|
32 | 32 | #include "llvm/ADT/PointerIntPair.h"
|
33 | 33 | #include "llvm/ADT/PointerUnion.h"
|
34 | 34 | #include "llvm/ADT/StringExtras.h"
|
| 35 | +#include "llvm/ADT/TinyPtrVector.h" |
35 | 36 | #include "Private.h"
|
36 | 37 | #include "CompatibilityOverride.h"
|
37 | 38 | #include "ImageInspection.h"
|
@@ -195,9 +196,19 @@ namespace {
|
195 | 196 | };
|
196 | 197 | } // end anonymous namespace
|
197 | 198 |
|
| 199 | +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::TinyPtrVector<const ContextDescriptor *>> |
| 209 | + ContextDescriptorCache; |
| 210 | + size_t ContextDescriptorLastSectionScanned = 0; |
| 211 | + Mutex ContextDescriptorCacheLock; |
201 | 212 |
|
202 | 213 | TypeMetadataPrivateState() {
|
203 | 214 | initializeTypeMetadataRecordLookup();
|
@@ -603,6 +614,60 @@ _searchTypeMetadataRecords(TypeMetadataPrivateState &T,
|
603 | 614 | return nullptr;
|
604 | 615 | }
|
605 | 616 |
|
| 617 | +// Read ContextDescriptors for any loaded images that haven't already been |
| 618 | +// scanned, if any. |
| 619 | +static void |
| 620 | +_scanAdditionalContextDescriptors(TypeMetadataPrivateState &T) { |
| 621 | + _forEachProtocolConformanceSectionAfter( |
| 622 | + &T.ContextDescriptorLastSectionScanned, |
| 623 | + [&T](const ProtocolConformanceRecord *Begin, |
| 624 | + const ProtocolConformanceRecord *End) { |
| 625 | + for (const auto *record = Begin; record != End; record++) { |
| 626 | + if (auto ntd = record[0]->getTypeDescriptor()) { |
| 627 | + if (auto type = llvm::dyn_cast<TypeContextDescriptor>(ntd)) { |
| 628 | + auto identity = ParsedTypeIdentity::parse(type); |
| 629 | + auto name = identity.getABIName(); |
| 630 | + T.ContextDescriptorCache[name].push_back(type); |
| 631 | + } |
| 632 | + } |
| 633 | + } |
| 634 | + }); |
| 635 | +} |
| 636 | + |
| 637 | +// Search for a ContextDescriptor in the context descriptor cache matching the |
| 638 | +// given demangle node. Returns the found node, or nullptr if no match was |
| 639 | +// found. |
| 640 | +static const ContextDescriptor * |
| 641 | +_findContextDescriptorInCache(TypeMetadataPrivateState &T, |
| 642 | + Demangle::NodePointer node) { |
| 643 | + if (node->getNumChildren() < 2) |
| 644 | + return nullptr; |
| 645 | + |
| 646 | + auto nameNode = node->getChild(1); |
| 647 | + |
| 648 | + // Declarations synthesized by the Clang importer get a small tag |
| 649 | + // string in addition to their name. |
| 650 | + if (nameNode->getKind() == Demangle::Node::Kind::RelatedEntityDeclName) |
| 651 | + nameNode = nameNode->getChild(1); |
| 652 | + |
| 653 | + if (nameNode->getKind() != Demangle::Node::Kind::Identifier) |
| 654 | + return nullptr; |
| 655 | + |
| 656 | + auto name = nameNode->getText(); |
| 657 | + |
| 658 | + auto iter = T.ContextDescriptorCache.find(name); |
| 659 | + if (iter == T.ContextDescriptorCache.end()) |
| 660 | + return nullptr; |
| 661 | + |
| 662 | + for (auto *contextDescriptor : iter->getSecond()) { |
| 663 | + if (_contextDescriptorMatchesMangling(contextDescriptor, node)) { |
| 664 | + return contextDescriptor; |
| 665 | + } |
| 666 | + } |
| 667 | + |
| 668 | + return nullptr; |
| 669 | +} |
| 670 | + |
606 | 671 | static const ContextDescriptor *
|
607 | 672 | _findContextDescriptor(Demangle::NodePointer node,
|
608 | 673 | Demangle::Demangler &Dem) {
|
@@ -630,8 +695,17 @@ _findContextDescriptor(Demangle::NodePointer node,
|
630 | 695 | if (auto Value = T.NominalCache.find(mangledName))
|
631 | 696 | return Value->getDescription();
|
632 | 697 |
|
| 698 | + // Scan any newly loaded images for context descriptors, then try the context |
| 699 | + // descriptor cache. This must be done with the cache's lock held. |
| 700 | + { |
| 701 | + ScopedLock guard(T.ContextDescriptorCacheLock); |
| 702 | + _scanAdditionalContextDescriptors(T); |
| 703 | + foundContext = _findContextDescriptorInCache(T, node); |
| 704 | + } |
| 705 | + |
633 | 706 | // Check type metadata records
|
634 |
| - foundContext = _searchTypeMetadataRecords(T, node); |
| 707 | + if (!foundContext) |
| 708 | + foundContext = _searchTypeMetadataRecords(T, node); |
635 | 709 |
|
636 | 710 | // Check protocol conformances table. Note that this has no support for
|
637 | 711 | // resolving generic types yet.
|
|
0 commit comments