Skip to content

Commit 425a146

Browse files
authored
Merge pull request #26581 from DougGregor/runtime-find-context-descriptor-cache-5.1
[5.1] [Runtime] Add caching based on ABI name to _findContextDescriptor.
2 parents 252a072 + f2f2c6e commit 425a146

File tree

3 files changed

+152
-2
lines changed

3 files changed

+152
-2
lines changed

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 123 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "swift/Runtime/Mutex.h"
2929
#include "swift/Strings.h"
3030
#include "llvm/ADT/DenseMap.h"
31+
#include "llvm/ADT/DenseSet.h"
3132
#include "llvm/ADT/Optional.h"
3233
#include "llvm/ADT/PointerIntPair.h"
3334
#include "llvm/ADT/PointerUnion.h"
@@ -195,9 +196,20 @@ namespace {
195196
};
196197
} // end anonymous namespace
197198

199+
inline llvm::hash_code llvm::hash_value(StringRef S) {
200+
return hash_combine_range(S.begin(), S.end());
201+
}
202+
198203
struct TypeMetadataPrivateState {
199204
ConcurrentMap<NominalTypeDescriptorCacheEntry> NominalCache;
200205
ConcurrentReadableArray<TypeMetadataSection> SectionsToScan;
206+
207+
llvm::DenseMap<llvm::StringRef,
208+
llvm::SmallDenseSet<const ContextDescriptor *, 1>>
209+
ContextDescriptorCache;
210+
size_t ConformanceDescriptorLastSectionScanned = 0;
211+
size_t TypeContextDescriptorLastSectionScanned = 0;
212+
Mutex ContextDescriptorCacheLock;
201213

202214
TypeMetadataPrivateState() {
203215
initializeTypeMetadataRecordLookup();
@@ -214,6 +226,29 @@ _registerTypeMetadataRecords(TypeMetadataPrivateState &T,
214226
T.SectionsToScan.push_back(TypeMetadataSection{begin, end});
215227
}
216228

229+
/// Iterate over type metadata sections starting from the given index.
230+
/// The index is updated to the current number of sections. Passing
231+
/// the same index to the next call will iterate over any sections that were
232+
/// added after the previous call.
233+
///
234+
/// Takes a function to call for each section found. The two parameters are
235+
/// the start and end of the section.
236+
static void _forEachTypeMetadataSectionAfter(
237+
TypeMetadataPrivateState &T,
238+
size_t *start,
239+
const std::function<void(const TypeMetadataRecord *,
240+
const TypeMetadataRecord *)> &f) {
241+
auto snapshot = T.SectionsToScan.snapshot();
242+
if (snapshot.Count > *start) {
243+
auto *begin = snapshot.begin() + *start;
244+
auto *end = snapshot.end();
245+
for (auto *section = begin; section != end; section++) {
246+
f(section->Begin, section->End);
247+
}
248+
*start = snapshot.Count;
249+
}
250+
}
251+
217252
void swift::addImageTypeMetadataRecordBlockCallback(const void *records,
218253
uintptr_t recordsSize) {
219254
assert(recordsSize % sizeof(TypeMetadataRecord) == 0
@@ -603,6 +638,70 @@ _searchTypeMetadataRecords(TypeMetadataPrivateState &T,
603638
return nullptr;
604639
}
605640

641+
// Read ContextDescriptors for any loaded images that haven't already been
642+
// scanned, if any.
643+
static void
644+
_scanAdditionalContextDescriptors(TypeMetadataPrivateState &T) {
645+
_forEachTypeMetadataSectionAfter(
646+
T,
647+
&T.TypeContextDescriptorLastSectionScanned,
648+
[&T](const TypeMetadataRecord *Begin,
649+
const TypeMetadataRecord *End) {
650+
for (const auto *record = Begin; record != End; record++) {
651+
if (auto ntd = record->getContextDescriptor()) {
652+
if (auto type = llvm::dyn_cast<TypeContextDescriptor>(ntd)) {
653+
auto identity = ParsedTypeIdentity::parse(type);
654+
auto name = identity.getABIName();
655+
T.ContextDescriptorCache[name].insert(type);
656+
}
657+
}
658+
}
659+
});
660+
661+
_forEachProtocolConformanceSectionAfter(
662+
&T.ConformanceDescriptorLastSectionScanned,
663+
[&T](const ProtocolConformanceRecord *Begin,
664+
const ProtocolConformanceRecord *End) {
665+
for (const auto *record = Begin; record != End; record++) {
666+
if (auto ntd = record[0]->getTypeDescriptor()) {
667+
if (auto type = llvm::dyn_cast<TypeContextDescriptor>(ntd)) {
668+
auto identity = ParsedTypeIdentity::parse(type);
669+
auto name = identity.getABIName();
670+
T.ContextDescriptorCache[name].insert(type);
671+
}
672+
}
673+
}
674+
});
675+
}
676+
677+
// Search for a ContextDescriptor in the context descriptor cache matching the
678+
// given demangle node. Returns the found node, or nullptr if no match was
679+
// found.
680+
static llvm::SmallDenseSet<const ContextDescriptor *, 1>
681+
_findContextDescriptorInCache(TypeMetadataPrivateState &T,
682+
Demangle::NodePointer node) {
683+
if (node->getNumChildren() < 2)
684+
return { };
685+
686+
auto nameNode = node->getChild(1);
687+
688+
// Declarations synthesized by the Clang importer get a small tag
689+
// string in addition to their name.
690+
if (nameNode->getKind() == Demangle::Node::Kind::RelatedEntityDeclName)
691+
nameNode = nameNode->getChild(1);
692+
693+
if (nameNode->getKind() != Demangle::Node::Kind::Identifier)
694+
return { };
695+
696+
auto name = nameNode->getText();
697+
698+
auto iter = T.ContextDescriptorCache.find(name);
699+
if (iter == T.ContextDescriptorCache.end())
700+
return { };
701+
702+
return iter->getSecond();
703+
}
704+
606705
static const ContextDescriptor *
607706
_findContextDescriptor(Demangle::NodePointer node,
608707
Demangle::Demangler &Dem) {
@@ -613,9 +712,14 @@ _findContextDescriptor(Demangle::NodePointer node,
613712
NodePointer symbolicNode = node;
614713
if (symbolicNode->getKind() == Node::Kind::Type)
615714
symbolicNode = symbolicNode->getChild(0);
616-
if (symbolicNode->getKind() == Node::Kind::TypeSymbolicReference)
715+
if (symbolicNode->getKind() == Node::Kind::TypeSymbolicReference) {
617716
return cast<TypeContextDescriptor>(
618717
(const ContextDescriptor *)symbolicNode->getIndex());
718+
}
719+
720+
// Nothing to resolve if have a generic parameter.
721+
if (symbolicNode->getKind() == Node::Kind::DependentGenericParamType)
722+
return nullptr;
619723

620724
StringRef mangledName =
621725
Demangle::mangleNode(node, ExpandResolvedSymbolicReferences(Dem), Dem);
@@ -625,8 +729,25 @@ _findContextDescriptor(Demangle::NodePointer node,
625729
if (auto Value = T.NominalCache.find(mangledName))
626730
return Value->getDescription();
627731

732+
// Scan any newly loaded images for context descriptors, then try the context
733+
// descriptor cache. This must be done with the cache's lock held.
734+
llvm::SmallDenseSet<const ContextDescriptor *, 1> cachedContexts;
735+
{
736+
ScopedLock guard(T.ContextDescriptorCacheLock);
737+
_scanAdditionalContextDescriptors(T);
738+
cachedContexts = _findContextDescriptorInCache(T, node);
739+
}
740+
741+
for (auto cachedContext : cachedContexts) {
742+
if (_contextDescriptorMatchesMangling(cachedContext, node)) {
743+
foundContext = cachedContext;
744+
break;
745+
}
746+
}
747+
628748
// Check type metadata records
629-
foundContext = _searchTypeMetadataRecords(T, node);
749+
if (!foundContext)
750+
foundContext = _searchTypeMetadataRecords(T, node);
630751

631752
// Check protocol conformances table. Note that this has no support for
632753
// resolving generic types yet.

stdlib/public/runtime/Private.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,19 @@ class TypeInfo {
249249
const ContextDescriptor *
250250
_searchConformancesByMangledTypeName(Demangle::NodePointer node);
251251

252+
/// Iterate over protocol conformance sections starting from the given index.
253+
/// The index is updated to the current number of protocol sections. Passing
254+
/// the same index to the next call will iterate over any sections that were
255+
/// added after the previous call.
256+
///
257+
/// Takes a function to call for each section found. The two parameters are
258+
/// the start and end of the section.
259+
void
260+
_forEachProtocolConformanceSectionAfter(
261+
size_t *start,
262+
const std::function<void(const ProtocolConformanceRecord *,
263+
const ProtocolConformanceRecord *)> &f);
264+
252265
Demangle::NodePointer _swift_buildDemanglingForMetadata(const Metadata *type,
253266
Demangle::Demangler &Dem);
254267

stdlib/public/runtime/ProtocolConformance.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,22 @@ swift::_searchConformancesByMangledTypeName(Demangle::NodePointer node) {
634634
return nullptr;
635635
}
636636

637+
void
638+
swift::_forEachProtocolConformanceSectionAfter(
639+
size_t *start,
640+
const std::function<void(const ProtocolConformanceRecord *,
641+
const ProtocolConformanceRecord *)> &f) {
642+
auto snapshot = Conformances.get().SectionsToScan.snapshot();
643+
if (snapshot.Count > *start) {
644+
auto *begin = snapshot.begin() + *start;
645+
auto *end = snapshot.end();
646+
for (auto *section = begin; section != end; section++) {
647+
f(section->Begin, section->End);
648+
}
649+
*start = snapshot.Count;
650+
}
651+
}
652+
637653
bool swift::_checkGenericRequirements(
638654
llvm::ArrayRef<GenericRequirementDescriptor> requirements,
639655
SmallVectorImpl<const void *> &extraArguments,

0 commit comments

Comments
 (0)