28
28
#include " swift/Runtime/Mutex.h"
29
29
#include " swift/Strings.h"
30
30
#include " llvm/ADT/DenseMap.h"
31
+ #include " llvm/ADT/DenseSet.h"
31
32
#include " llvm/ADT/Optional.h"
32
33
#include " llvm/ADT/PointerIntPair.h"
33
34
#include " llvm/ADT/PointerUnion.h"
@@ -195,9 +196,20 @@ namespace {
195
196
};
196
197
} // end anonymous namespace
197
198
199
+ inline llvm::hash_code llvm::hash_value (StringRef S) {
200
+ return hash_combine_range (S.begin (), S.end ());
201
+ }
202
+
198
203
struct TypeMetadataPrivateState {
199
204
ConcurrentMap<NominalTypeDescriptorCacheEntry> NominalCache;
200
205
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;
201
213
202
214
TypeMetadataPrivateState () {
203
215
initializeTypeMetadataRecordLookup ();
@@ -214,6 +226,29 @@ _registerTypeMetadataRecords(TypeMetadataPrivateState &T,
214
226
T.SectionsToScan .push_back (TypeMetadataSection{begin, end});
215
227
}
216
228
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
+
217
252
void swift::addImageTypeMetadataRecordBlockCallback (const void *records,
218
253
uintptr_t recordsSize) {
219
254
assert (recordsSize % sizeof (TypeMetadataRecord) == 0
@@ -603,6 +638,70 @@ _searchTypeMetadataRecords(TypeMetadataPrivateState &T,
603
638
return nullptr ;
604
639
}
605
640
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
+
606
705
static const ContextDescriptor *
607
706
_findContextDescriptor (Demangle::NodePointer node,
608
707
Demangle::Demangler &Dem) {
@@ -630,16 +729,49 @@ _findContextDescriptor(Demangle::NodePointer node,
630
729
if (auto Value = T.NominalCache .find (mangledName))
631
730
return Value->getDescription ();
632
731
633
- // Check type metadata records
634
- foundContext = _searchTypeMetadataRecords (T, node);
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
+ }
635
740
636
- // Check protocol conformances table. Note that this has no support for
637
- // resolving generic types yet.
638
- if (!foundContext)
639
- foundContext = _searchConformancesByMangledTypeName (node);
741
+ bool foundInCache = false ;
742
+ for (auto cachedContext : cachedContexts) {
743
+ if (_contextDescriptorMatchesMangling (cachedContext, node)) {
744
+ foundContext = cachedContext;
745
+ foundInCache = true ;
746
+ break ;
747
+ }
748
+ }
749
+
750
+ if (!foundContext) {
751
+ // Slow path, as a fallback if the cache itself isn't capturing everything.
752
+ (void )foundInCache;
753
+
754
+ // Check type metadata records
755
+ foundContext = _searchTypeMetadataRecords (T, node);
756
+
757
+ // Check protocol conformances table. Note that this has no support for
758
+ // resolving generic types yet.
759
+ if (!foundContext)
760
+ foundContext = _searchConformancesByMangledTypeName (node);
761
+ }
640
762
641
763
if (foundContext) {
642
764
T.NominalCache .getOrInsert (mangledName, foundContext);
765
+
766
+ #ifndef NDEBUG
767
+ // If we found something in the slow path but not in the cache, it is a
768
+ // bug in the cache. Fail in assertions builds.
769
+ if (!foundInCache) {
770
+ fatalError (0 ,
771
+ " _findContextDescriptor cache miss for demangled tree:\n %s\n " ,
772
+ getNodeTreeAsString (node).c_str ());
773
+ }
774
+ #endif
643
775
}
644
776
645
777
return foundContext;
0 commit comments