| //===--- MetadataLookup.cpp - Swift Language Type Name Lookup -------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Implementations of runtime functions for looking up a type by name. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "swift/Basic/Lazy.h" |
| #include "swift/Demangling/Demangler.h" |
| #include "swift/Demangling/TypeDecoder.h" |
| #include "swift/Reflection/Records.h" |
| #include "swift/ABI/TypeIdentity.h" |
| #include "swift/Runtime/Casting.h" |
| #include "swift/Runtime/Concurrent.h" |
| #include "swift/Runtime/Debug.h" |
| #include "swift/Runtime/HeapObject.h" |
| #include "swift/Runtime/Metadata.h" |
| #include "swift/Runtime/Mutex.h" |
| #include "swift/Strings.h" |
| #include "llvm/ADT/DenseMap.h" |
| #include "llvm/ADT/DenseSet.h" |
| #include "llvm/ADT/Optional.h" |
| #include "llvm/ADT/PointerIntPair.h" |
| #include "llvm/ADT/PointerUnion.h" |
| #include "llvm/ADT/StringExtras.h" |
| #include "Private.h" |
| #include "CompatibilityOverride.h" |
| #include "ImageInspection.h" |
| #include <functional> |
| #include <vector> |
| #include <list> |
| |
| using namespace swift; |
| using namespace Demangle; |
| using namespace reflection; |
| |
| #if SWIFT_OBJC_INTEROP |
| #include <objc/runtime.h> |
| #include <objc/message.h> |
| #include <objc/objc.h> |
| #include <dlfcn.h> |
| #endif |
| |
| /// A Demangler suitable for resolving runtime type metadata strings. |
| template <class Base = Demangler> |
| class DemanglerForRuntimeTypeResolution : public Base { |
| public: |
| using Base::demangleSymbol; |
| using Base::demangleType; |
| |
| // Force callers to explicitly pass `nullptr` to demangleSymbol or |
| // demangleType if they don't want to demangle symbolic references. |
| NodePointer demangleSymbol(StringRef symbolName) = delete; |
| NodePointer demangleType(StringRef typeName) = delete; |
| |
| NodePointer demangleTypeRef(StringRef symbolName) { |
| // Resolve symbolic references to type contexts into the absolute address of |
| // the type context descriptor, so that if we see a symbolic reference in |
| // the mangled name we can immediately find the associated metadata. |
| return Base::demangleType(symbolName, |
| ResolveAsSymbolicReference(*this)); |
| } |
| }; |
| |
| /// Resolve the relative reference in a mangled symbolic reference. |
| static uintptr_t resolveSymbolicReferenceOffset(SymbolicReferenceKind kind, |
| Directness isIndirect, |
| int32_t offset, |
| const void *base) { |
| auto ptr = detail::applyRelativeOffset(base, offset); |
| |
| // Indirect references may be authenticated in a way appropriate for the |
| // referent. |
| if (isIndirect == Directness::Indirect) { |
| switch (kind) { |
| case SymbolicReferenceKind::Context: { |
| ContextDescriptor *contextPtr = |
| *(const TargetSignedContextPointer<InProcess> *)ptr; |
| return (uintptr_t)contextPtr; |
| } |
| case SymbolicReferenceKind::AccessorFunctionReference: { |
| swift_unreachable("should not be indirectly referenced"); |
| } |
| } |
| swift_unreachable("unknown symbolic reference kind"); |
| } else { |
| return ptr; |
| } |
| } |
| |
| NodePointer |
| ResolveAsSymbolicReference::operator()(SymbolicReferenceKind kind, |
| Directness isIndirect, |
| int32_t offset, |
| const void *base) { |
| // Resolve the absolute pointer to the entity being referenced. |
| auto ptr = resolveSymbolicReferenceOffset(kind, isIndirect, offset, base); |
| |
| // Figure out this symbolic reference's grammatical role. |
| Node::Kind nodeKind; |
| bool isType; |
| switch (kind) { |
| case Demangle::SymbolicReferenceKind::Context: { |
| auto descriptor = (const ContextDescriptor *)ptr; |
| switch (descriptor->getKind()) { |
| case ContextDescriptorKind::Protocol: |
| nodeKind = Node::Kind::ProtocolSymbolicReference; |
| isType = false; |
| break; |
| |
| case ContextDescriptorKind::OpaqueType: |
| nodeKind = Node::Kind::OpaqueTypeDescriptorSymbolicReference; |
| isType = false; |
| break; |
| |
| default: |
| if (auto typeContext = dyn_cast<TypeContextDescriptor>(descriptor)) { |
| nodeKind = Node::Kind::TypeSymbolicReference; |
| isType = true; |
| break; |
| } |
| |
| // References to other kinds of context aren't yet implemented. |
| return nullptr; |
| } |
| break; |
| } |
| case Demangle::SymbolicReferenceKind::AccessorFunctionReference: { |
| // Save the pointer to the accessor function. We can't demangle it any |
| // further as AST, but the consumer of the demangle tree may be able to |
| // invoke the function to resolve the thing they're trying to access. |
| nodeKind = Node::Kind::AccessorFunctionReference; |
| isType = false; |
| #if SWIFT_PTRAUTH |
| // The pointer refers to an accessor function, which we need to sign. |
| ptr = (uintptr_t)ptrauth_sign_unauthenticated((void*)ptr, |
| ptrauth_key_function_pointer, 0); |
| #endif |
| break; |
| } |
| } |
| |
| auto node = Dem.createNode(nodeKind, ptr); |
| if (isType) { |
| auto typeNode = Dem.createNode(Node::Kind::Type); |
| typeNode->addChild(node, Dem); |
| node = typeNode; |
| } |
| return node; |
| } |
| |
| static NodePointer |
| _buildDemanglingForSymbolicReference(SymbolicReferenceKind kind, |
| const void *resolvedReference, |
| Demangler &Dem) { |
| switch (kind) { |
| case SymbolicReferenceKind::Context: |
| return _buildDemanglingForContext( |
| (const ContextDescriptor *)resolvedReference, {}, Dem); |
| case SymbolicReferenceKind::AccessorFunctionReference: |
| #if SWIFT_PTRAUTH |
| // The pointer refers to an accessor function, which we need to sign. |
| resolvedReference = ptrauth_sign_unauthenticated(resolvedReference, |
| ptrauth_key_function_pointer, 0); |
| #endif |
| return Dem.createNode(Node::Kind::AccessorFunctionReference, |
| (uintptr_t)resolvedReference); |
| } |
| |
| swift_unreachable("invalid symbolic reference kind"); |
| } |
| |
| NodePointer |
| ResolveToDemanglingForContext::operator()(SymbolicReferenceKind kind, |
| Directness isIndirect, |
| int32_t offset, |
| const void *base) { |
| auto ptr = resolveSymbolicReferenceOffset(kind, isIndirect, offset, base); |
| |
| return _buildDemanglingForSymbolicReference(kind, (const void *)ptr, Dem); |
| } |
| |
| NodePointer |
| ExpandResolvedSymbolicReferences::operator()(SymbolicReferenceKind kind, |
| const void *ptr) { |
| return _buildDemanglingForSymbolicReference(kind, (const void *)ptr, Dem); |
| } |
| |
| #pragma mark Nominal type descriptor cache |
| // Type Metadata Cache. |
| |
| namespace { |
| struct TypeMetadataSection { |
| const TypeMetadataRecord *Begin, *End; |
| const TypeMetadataRecord *begin() const { |
| return Begin; |
| } |
| const TypeMetadataRecord *end() const { |
| return End; |
| } |
| }; |
| |
| struct NominalTypeDescriptorCacheEntry { |
| private: |
| const char *Name; |
| size_t NameLength; |
| const ContextDescriptor *Description; |
| |
| public: |
| NominalTypeDescriptorCacheEntry(const llvm::StringRef name, |
| const ContextDescriptor *description) |
| : Description(description) { |
| char *nameCopy = reinterpret_cast<char *>(malloc(name.size())); |
| memcpy(nameCopy, name.data(), name.size()); |
| Name = nameCopy; |
| NameLength = name.size(); |
| } |
| |
| const ContextDescriptor *getDescription() const { return Description; } |
| |
| bool matchesKey(llvm::StringRef aName) { |
| return aName == llvm::StringRef{Name, NameLength}; |
| } |
| |
| friend llvm::hash_code |
| hash_value(const NominalTypeDescriptorCacheEntry &value) { |
| return hash_value(llvm::StringRef{value.Name, value.NameLength}); |
| } |
| |
| template <class... T> |
| static size_t getExtraAllocationSize(T &&... ignored) { |
| return 0; |
| } |
| }; |
| } // end anonymous namespace |
| |
| struct TypeMetadataPrivateState { |
| ConcurrentReadableHashMap<NominalTypeDescriptorCacheEntry> NominalCache; |
| ConcurrentReadableArray<TypeMetadataSection> SectionsToScan; |
| |
| TypeMetadataPrivateState() { |
| initializeTypeMetadataRecordLookup(); |
| } |
| |
| }; |
| |
| static Lazy<TypeMetadataPrivateState> TypeMetadataRecords; |
| |
| static void |
| _registerTypeMetadataRecords(TypeMetadataPrivateState &T, |
| const TypeMetadataRecord *begin, |
| const TypeMetadataRecord *end) { |
| T.SectionsToScan.push_back(TypeMetadataSection{begin, end}); |
| } |
| |
| void swift::addImageTypeMetadataRecordBlockCallbackUnsafe( |
| const void *records, uintptr_t recordsSize) { |
| assert(recordsSize % sizeof(TypeMetadataRecord) == 0 |
| && "weird-sized type metadata section?!"); |
| |
| // If we have a section, enqueue the type metadata for lookup. |
| auto recordBytes = reinterpret_cast<const char *>(records); |
| auto recordsBegin |
| = reinterpret_cast<const TypeMetadataRecord*>(records); |
| auto recordsEnd |
| = reinterpret_cast<const TypeMetadataRecord*>(recordBytes + recordsSize); |
| |
| // Type metadata cache should always be sufficiently initialized by this |
| // point. Attempting to go through get() may also lead to an infinite loop, |
| // since we register records during the initialization of |
| // TypeMetadataRecords. |
| _registerTypeMetadataRecords(TypeMetadataRecords.unsafeGetAlreadyInitialized(), |
| recordsBegin, recordsEnd); |
| } |
| |
| void swift::addImageTypeMetadataRecordBlockCallback(const void *records, |
| uintptr_t recordsSize) { |
| TypeMetadataRecords.get(); |
| addImageTypeMetadataRecordBlockCallbackUnsafe(records, recordsSize); |
| } |
| |
| void |
| swift::swift_registerTypeMetadataRecords(const TypeMetadataRecord *begin, |
| const TypeMetadataRecord *end) { |
| auto &T = TypeMetadataRecords.get(); |
| _registerTypeMetadataRecords(T, begin, end); |
| } |
| |
| static const ContextDescriptor * |
| _findContextDescriptor(Demangle::NodePointer node, |
| Demangle::Demangler &Dem); |
| |
| /// Find the context descriptor for the type extended by the given extension. |
| /// |
| /// If \p maybeExtension isn't actually an extension context, returns nullptr. |
| static const ContextDescriptor * |
| _findExtendedTypeContextDescriptor(const ContextDescriptor *maybeExtension, |
| Demangler &demangler, |
| Demangle::NodePointer *demangledNode |
| = nullptr) { |
| auto extension = dyn_cast<ExtensionContextDescriptor>(maybeExtension); |
| if (!extension) |
| return nullptr; |
| |
| Demangle::NodePointer localNode; |
| Demangle::NodePointer &node = demangledNode ? *demangledNode : localNode; |
| |
| auto mangledName = extension->getMangledExtendedContext(); |
| node = demangler.demangleType(mangledName, |
| ResolveAsSymbolicReference(demangler)); |
| if (!node) |
| return nullptr; |
| if (node->getKind() == Node::Kind::Type) { |
| if (node->getNumChildren() < 1) |
| return nullptr; |
| node = node->getChild(0); |
| } |
| if (Demangle::isSpecialized(node)) { |
| node = Demangle::getUnspecialized(node, demangler); |
| } |
| |
| return _findContextDescriptor(node, demangler); |
| } |
| |
| /// Recognize imported tag types, which have a special mangling rule. |
| /// |
| /// This should be kept in sync with the AST mangler and with |
| /// buildContextDescriptorMangling in MetadataReader. |
| bool swift::_isCImportedTagType(const TypeContextDescriptor *type, |
| const ParsedTypeIdentity &identity) { |
| // Tag types are always imported as structs or enums. |
| if (type->getKind() != ContextDescriptorKind::Enum && |
| type->getKind() != ContextDescriptorKind::Struct) |
| return false; |
| |
| // Not a typedef imported as a nominal type. |
| if (identity.isCTypedef()) |
| return false; |
| |
| // Not a related entity. |
| if (identity.isAnyRelatedEntity()) |
| return false; |
| |
| // Imported from C. |
| return type->Parent->isCImportedContext(); |
| } |
| |
| ParsedTypeIdentity |
| ParsedTypeIdentity::parse(const TypeContextDescriptor *type) { |
| ParsedTypeIdentity result; |
| |
| // The first component is the user-facing name and (unless overridden) |
| // the ABI name. |
| StringRef component = type->Name.get(); |
| result.UserFacingName = component; |
| |
| // If we don't have import info, we're done. |
| if (!type->getTypeContextDescriptorFlags().hasImportInfo()) { |
| result.FullIdentity = result.UserFacingName; |
| return result; |
| } |
| |
| // Otherwise, start parsing the import information. |
| result.ImportInfo.emplace(); |
| |
| // The identity starts with the user-facing name. |
| const char *startOfIdentity = component.begin(); |
| const char *endOfIdentity = component.end(); |
| |
| #ifndef NDEBUG |
| enum { |
| AfterName, |
| AfterABIName, |
| AfterSymbolNamespace, |
| AfterRelatedEntityName, |
| AfterIdentity, |
| } stage = AfterName; |
| #endif |
| |
| while (true) { |
| // Parse the next component. If it's empty, we're done. |
| component = StringRef(component.end() + 1); |
| if (component.empty()) break; |
| |
| // Update the identity bounds and assert that the identity |
| // components are in the right order. |
| auto kind = TypeImportComponent(component[0]); |
| if (kind == TypeImportComponent::ABIName) { |
| #ifndef NDEBUG |
| assert(stage < AfterABIName); |
| stage = AfterABIName; |
| assert(result.UserFacingName != component.drop_front(1) && |
| "user-facing name was same as the ABI name"); |
| #endif |
| startOfIdentity = component.begin() + 1; |
| endOfIdentity = component.end(); |
| } else if (kind == TypeImportComponent::SymbolNamespace) { |
| #ifndef NDEBUG |
| assert(stage < AfterSymbolNamespace); |
| stage = AfterSymbolNamespace; |
| #endif |
| endOfIdentity = component.end(); |
| } else if (kind == TypeImportComponent::RelatedEntityName) { |
| #ifndef NDEBUG |
| assert(stage < AfterRelatedEntityName); |
| stage = AfterRelatedEntityName; |
| #endif |
| endOfIdentity = component.end(); |
| } else { |
| #ifndef NDEBUG |
| // Anything else is assumed to not be part of the identity. |
| stage = AfterIdentity; |
| #endif |
| } |
| |
| // Collect the component, whatever it is. |
| result.ImportInfo->collect</*asserting*/true>(component); |
| } |
| |
| assert(stage != AfterName && "no components?"); |
| |
| // Record the full identity. |
| result.FullIdentity = |
| StringRef(startOfIdentity, endOfIdentity - startOfIdentity); |
| |
| return result; |
| } |
| |
| #if SWIFT_OBJC_INTEROP |
| /// Determine whether the two demangle trees both refer to the same |
| /// Objective-C class or protocol referenced by name. |
| static bool sameObjCTypeManglings(Demangle::NodePointer node1, |
| Demangle::NodePointer node2) { |
| // Entities need to be of the same kind. |
| if (node1->getKind() != node2->getKind()) |
| return false; |
| |
| auto name1 = Demangle::getObjCClassOrProtocolName(node1); |
| if (!name1) return false; |
| |
| auto name2 = Demangle::getObjCClassOrProtocolName(node2); |
| if (!name2) return false; |
| |
| return *name1 == *name2; |
| } |
| #endif |
| |
| bool |
| swift::_contextDescriptorMatchesMangling(const ContextDescriptor *context, |
| Demangle::NodePointer node) { |
| while (context) { |
| if (node->getKind() == Demangle::Node::Kind::Type) |
| node = node->getChild(0); |
| |
| // We can directly match symbolic references to the current context. |
| if (node) { |
| if (node->getKind() == Demangle::Node::Kind::TypeSymbolicReference |
| || node->getKind() == Demangle::Node::Kind::ProtocolSymbolicReference){ |
| if (equalContexts(context, |
| reinterpret_cast<const ContextDescriptor *>(node->getIndex()))) { |
| return true; |
| } |
| } |
| } |
| |
| switch (context->getKind()) { |
| case ContextDescriptorKind::Module: { |
| auto module = cast<ModuleContextDescriptor>(context); |
| // Match to a mangled module name. |
| if (node->getKind() != Demangle::Node::Kind::Module) |
| return false; |
| if (!node->getText().equals(module->Name.get())) |
| return false; |
| |
| node = nullptr; |
| break; |
| } |
| |
| case ContextDescriptorKind::Extension: { |
| auto extension = cast<ExtensionContextDescriptor>(context); |
| |
| // Check whether the extension context matches the mangled context. |
| if (node->getKind() != Demangle::Node::Kind::Extension) |
| return false; |
| if (node->getNumChildren() < 2) |
| return false; |
| |
| // Check that the context being extended matches as well. |
| auto extendedContextNode = node->getChild(1); |
| DemanglerForRuntimeTypeResolution<> demangler; |
| |
| auto extendedDescriptorFromNode = |
| _findContextDescriptor(extendedContextNode, demangler); |
| |
| Demangle::NodePointer extendedContextDemangled; |
| auto extendedDescriptorFromDemangled = |
| _findExtendedTypeContextDescriptor(extension, demangler, |
| &extendedContextDemangled); |
| |
| // Determine whether the contexts match. |
| bool contextsMatch = |
| extendedDescriptorFromNode && extendedDescriptorFromDemangled && |
| equalContexts(extendedDescriptorFromNode, |
| extendedDescriptorFromDemangled); |
| |
| #if SWIFT_OBJC_INTEROP |
| // If we have manglings of the same Objective-C type, the contexts match. |
| if (!contextsMatch && |
| (!extendedDescriptorFromNode || !extendedDescriptorFromDemangled) && |
| sameObjCTypeManglings(extendedContextNode, |
| extendedContextDemangled)) { |
| contextsMatch = true; |
| } |
| #endif |
| |
| if (!contextsMatch) |
| return false; |
| |
| // Check whether the generic signature of the extension matches the |
| // mangled constraints, if any. |
| |
| if (node->getNumChildren() >= 3) { |
| // NB: If we ever support extensions with independent generic arguments |
| // like `extension <T> Array where Element == Optional<T>`, we'd need |
| // to look at the mangled context name to match up generic arguments. |
| // That would probably need a new extension mangling form, though. |
| |
| // TODO |
| } |
| |
| // The parent context of the extension should match in the mangling and |
| // context descriptor. |
| node = node->getChild(0); |
| break; |
| } |
| |
| case ContextDescriptorKind::Protocol: |
| // Match a protocol context. |
| if (node->getKind() == Demangle::Node::Kind::Protocol) { |
| auto proto = llvm::cast<ProtocolDescriptor>(context); |
| auto nameNode = node->getChild(1); |
| if (nameNode->getKind() != Demangle::Node::Kind::Identifier) |
| return false; |
| if (nameNode->getText() == proto->Name.get()) { |
| node = node->getChild(0); |
| break; |
| } |
| } |
| return false; |
| |
| default: |
| if (auto type = llvm::dyn_cast<TypeContextDescriptor>(context)) { |
| llvm::Optional<ParsedTypeIdentity> _identity; |
| auto getIdentity = [&]() -> const ParsedTypeIdentity & { |
| if (_identity) return *_identity; |
| _identity = ParsedTypeIdentity::parse(type); |
| return *_identity; |
| }; |
| |
| switch (node->getKind()) { |
| // If the mangled name doesn't indicate a type kind, accept anything. |
| // Otherwise, try to match them up. |
| case Demangle::Node::Kind::OtherNominalType: |
| break; |
| case Demangle::Node::Kind::Structure: |
| // We allow non-structs to match Kind::Structure if they are |
| // imported C tag types. This is necessary because we artificially |
| // make imported C tag types Kind::Structure. |
| if (type->getKind() != ContextDescriptorKind::Struct && |
| !_isCImportedTagType(type, getIdentity())) |
| return false; |
| break; |
| case Demangle::Node::Kind::Class: |
| if (type->getKind() != ContextDescriptorKind::Class) |
| return false; |
| break; |
| case Demangle::Node::Kind::Enum: |
| if (type->getKind() != ContextDescriptorKind::Enum) |
| return false; |
| break; |
| case Demangle::Node::Kind::TypeAlias: |
| if (!getIdentity().isCTypedef()) |
| return false; |
| break; |
| |
| default: |
| return false; |
| } |
| |
| auto nameNode = node->getChild(1); |
| |
| // Declarations synthesized by the Clang importer get a small tag |
| // string in addition to their name. |
| if (nameNode->getKind() == Demangle::Node::Kind::RelatedEntityDeclName){ |
| if (!getIdentity().isRelatedEntity( |
| nameNode->getFirstChild()->getText())) |
| return false; |
| |
| nameNode = nameNode->getChild(1); |
| } else if (getIdentity().isAnyRelatedEntity()) { |
| return false; |
| } |
| |
| // We should only match public or internal declarations with stable |
| // names. The runtime metadata for private declarations would be |
| // anonymized. |
| if (nameNode->getKind() == Demangle::Node::Kind::Identifier) { |
| if (nameNode->getText() != getIdentity().getABIName()) |
| return false; |
| |
| node = node->getChild(0); |
| break; |
| } |
| |
| return false; |
| |
| } |
| |
| // We don't know about this kind of context, or it doesn't have a stable |
| // name we can match to. |
| return false; |
| } |
| |
| context = context->Parent; |
| } |
| |
| // We should have reached the top of the node tree at the same time we reached |
| // the top of the context tree. |
| if (node) |
| return false; |
| |
| return true; |
| } |
| |
| // returns the nominal type descriptor for the type named by typeName |
| static const ContextDescriptor * |
| _searchTypeMetadataRecords(TypeMetadataPrivateState &T, |
| Demangle::NodePointer node) { |
| for (auto §ion : T.SectionsToScan.snapshot()) { |
| for (const auto &record : section) { |
| if (auto context = record.getContextDescriptor()) { |
| if (_contextDescriptorMatchesMangling(context, node)) { |
| return context; |
| } |
| } |
| } |
| } |
| |
| return nullptr; |
| } |
| |
| #define DESCRIPTOR_MANGLING_SUFFIX_Structure Mn |
| #define DESCRIPTOR_MANGLING_SUFFIX_Enum Mn |
| #define DESCRIPTOR_MANGLING_SUFFIX_Protocol Mp |
| |
| #define DESCRIPTOR_MANGLING_SUFFIX_(X) X |
| #define DESCRIPTOR_MANGLING_SUFFIX(KIND) \ |
| DESCRIPTOR_MANGLING_SUFFIX_(DESCRIPTOR_MANGLING_SUFFIX_ ## KIND) |
| |
| #define DESCRIPTOR_MANGLING_(CHAR, SUFFIX) \ |
| $sS ## CHAR ## SUFFIX |
| #define DESCRIPTOR_MANGLING(CHAR, SUFFIX) DESCRIPTOR_MANGLING_(CHAR, SUFFIX) |
| |
| #define STANDARD_TYPE(KIND, MANGLING, TYPENAME) \ |
| extern "C" const ContextDescriptor DESCRIPTOR_MANGLING(MANGLING, DESCRIPTOR_MANGLING_SUFFIX(KIND)); |
| |
| #if !SWIFT_OBJC_INTEROP |
| # define OBJC_INTEROP_STANDARD_TYPE(KIND, MANGLING, TYPENAME) |
| #endif |
| |
| #include "swift/Demangling/StandardTypesMangling.def" |
| |
| static const ContextDescriptor * |
| _findContextDescriptor(Demangle::NodePointer node, |
| Demangle::Demangler &Dem) { |
| NodePointer symbolicNode = node; |
| if (symbolicNode->getKind() == Node::Kind::Type) |
| symbolicNode = symbolicNode->getChild(0); |
| |
| // If we have a symbolic reference to a context, resolve it immediately. |
| if (symbolicNode->getKind() == Node::Kind::TypeSymbolicReference) { |
| return cast<TypeContextDescriptor>( |
| (const ContextDescriptor *)symbolicNode->getIndex()); |
| } |
| |
| // Fast-path lookup for standard library type references with short manglings. |
| if (symbolicNode->getNumChildren() >= 2 |
| && symbolicNode->getChild(0)->getKind() == Node::Kind::Module |
| && symbolicNode->getChild(0)->getText().equals("Swift") |
| && symbolicNode->getChild(1)->getKind() == Node::Kind::Identifier) { |
| auto name = symbolicNode->getChild(1)->getText(); |
| |
| #define STANDARD_TYPE(KIND, MANGLING, TYPENAME) \ |
| if (name.equals(#TYPENAME)) { \ |
| return &DESCRIPTOR_MANGLING(MANGLING, DESCRIPTOR_MANGLING_SUFFIX(KIND)); \ |
| } |
| #if !SWIFT_OBJC_INTEROP |
| # define OBJC_INTEROP_STANDARD_TYPE(KIND, MANGLING, TYPENAME) |
| #endif |
| |
| #include "swift/Demangling/StandardTypesMangling.def" |
| } |
| |
| const ContextDescriptor *foundContext = nullptr; |
| auto &T = TypeMetadataRecords.get(); |
| |
| // Nothing to resolve if have a generic parameter. |
| if (symbolicNode->getKind() == Node::Kind::DependentGenericParamType) |
| return nullptr; |
| |
| StringRef mangledName = |
| Demangle::mangleNode(node, ExpandResolvedSymbolicReferences(Dem), Dem); |
| |
| // Look for an existing entry. |
| // Find the bucket for the metadata entry. |
| { |
| auto snapshot = T.NominalCache.snapshot(); |
| if (auto Value = snapshot.find(mangledName)) |
| return Value->getDescription(); |
| } |
| |
| // Check type metadata records |
| // Scan any newly loaded images for context descriptors, then try the context |
| foundContext = _searchTypeMetadataRecords(T, node); |
| |
| // Check protocol conformances table. Note that this has no support for |
| // resolving generic types yet. |
| if (!foundContext) |
| foundContext = _searchConformancesByMangledTypeName(node); |
| |
| if (foundContext) |
| T.NominalCache.getOrInsert(mangledName, [&](NominalTypeDescriptorCacheEntry |
| *entry, |
| bool created) { |
| if (created) |
| new (entry) NominalTypeDescriptorCacheEntry{mangledName, foundContext}; |
| return true; |
| }); |
| |
| return foundContext; |
| } |
| |
| #pragma mark Protocol descriptor cache |
| namespace { |
| struct ProtocolSection { |
| const ProtocolRecord *Begin, *End; |
| |
| const ProtocolRecord *begin() const { |
| return Begin; |
| } |
| const ProtocolRecord *end() const { |
| return End; |
| } |
| }; |
| |
| struct ProtocolDescriptorCacheEntry { |
| private: |
| const char *Name; |
| size_t NameLength; |
| const ProtocolDescriptor *Description; |
| |
| public: |
| ProtocolDescriptorCacheEntry(const llvm::StringRef name, |
| const ProtocolDescriptor *description) |
| : Description(description) { |
| char *nameCopy = reinterpret_cast<char *>(malloc(name.size())); |
| memcpy(nameCopy, name.data(), name.size()); |
| Name = nameCopy; |
| NameLength = name.size(); |
| } |
| |
| const ProtocolDescriptor *getDescription() const { return Description; } |
| |
| bool matchesKey(llvm::StringRef aName) { |
| return aName == llvm::StringRef{Name, NameLength}; |
| } |
| |
| friend llvm::hash_code |
| hash_value(const ProtocolDescriptorCacheEntry &value) { |
| return hash_value(llvm::StringRef{value.Name, value.NameLength}); |
| } |
| |
| template <class... T> |
| static size_t getExtraAllocationSize(T &&... ignored) { |
| return 0; |
| } |
| }; |
| |
| struct ProtocolMetadataPrivateState { |
| ConcurrentReadableHashMap<ProtocolDescriptorCacheEntry> ProtocolCache; |
| ConcurrentReadableArray<ProtocolSection> SectionsToScan; |
| |
| ProtocolMetadataPrivateState() { |
| initializeProtocolLookup(); |
| } |
| }; |
| |
| static Lazy<ProtocolMetadataPrivateState> Protocols; |
| } |
| |
| static void |
| _registerProtocols(ProtocolMetadataPrivateState &C, |
| const ProtocolRecord *begin, |
| const ProtocolRecord *end) { |
| C.SectionsToScan.push_back(ProtocolSection{begin, end}); |
| } |
| |
| void swift::addImageProtocolsBlockCallbackUnsafe(const void *protocols, |
| uintptr_t protocolsSize) { |
| assert(protocolsSize % sizeof(ProtocolRecord) == 0 && |
| "protocols section not a multiple of ProtocolRecord"); |
| |
| // If we have a section, enqueue the protocols for lookup. |
| auto protocolsBytes = reinterpret_cast<const char *>(protocols); |
| auto recordsBegin |
| = reinterpret_cast<const ProtocolRecord *>(protocols); |
| auto recordsEnd |
| = reinterpret_cast<const ProtocolRecord *>(protocolsBytes + protocolsSize); |
| |
| // Conformance cache should always be sufficiently initialized by this point. |
| _registerProtocols(Protocols.unsafeGetAlreadyInitialized(), |
| recordsBegin, recordsEnd); |
| } |
| |
| void swift::addImageProtocolsBlockCallback(const void *protocols, |
| uintptr_t protocolsSize) { |
| Protocols.get(); |
| addImageProtocolsBlockCallbackUnsafe(protocols, protocolsSize); |
| } |
| |
| void swift::swift_registerProtocols(const ProtocolRecord *begin, |
| const ProtocolRecord *end) { |
| auto &C = Protocols.get(); |
| _registerProtocols(C, begin, end); |
| } |
| |
| static const ProtocolDescriptor * |
| _searchProtocolRecords(ProtocolMetadataPrivateState &C, |
| NodePointer node) { |
| for (auto §ion : C.SectionsToScan.snapshot()) { |
| for (const auto &record : section) { |
| if (auto protocol = record.Protocol.getPointer()) { |
| if (_contextDescriptorMatchesMangling(protocol, node)) |
| return protocol; |
| } |
| } |
| } |
| |
| return nullptr; |
| } |
| |
| static const ProtocolDescriptor * |
| _findProtocolDescriptor(NodePointer node, |
| Demangle::Demangler &Dem, |
| std::string &mangledName) { |
| const ProtocolDescriptor *foundProtocol = nullptr; |
| auto &T = Protocols.get(); |
| |
| // If we have a symbolic reference to a context, resolve it immediately. |
| NodePointer symbolicNode = node; |
| if (symbolicNode->getKind() == Node::Kind::Type) |
| symbolicNode = symbolicNode->getChild(0); |
| if (symbolicNode->getKind() == Node::Kind::ProtocolSymbolicReference) |
| return cast<ProtocolDescriptor>( |
| (const ContextDescriptor *)symbolicNode->getIndex()); |
| |
| mangledName = |
| Demangle::mangleNode(node, ExpandResolvedSymbolicReferences(Dem), Dem).str(); |
| |
| // Look for an existing entry. |
| // Find the bucket for the metadata entry. |
| { |
| auto snapshot = T.ProtocolCache.snapshot(); |
| if (auto Value = snapshot.find(mangledName)) |
| return Value->getDescription(); |
| } |
| |
| // Check type metadata records |
| foundProtocol = _searchProtocolRecords(T, node); |
| |
| if (foundProtocol) { |
| T.ProtocolCache.getOrInsert(mangledName, [&](ProtocolDescriptorCacheEntry |
| *entry, |
| bool created) { |
| if (created) |
| new (entry) ProtocolDescriptorCacheEntry{mangledName, foundProtocol}; |
| return true; |
| }); |
| } |
| |
| return foundProtocol; |
| } |
| |
| #pragma mark Type field descriptor cache |
| namespace { |
| struct FieldDescriptorCacheEntry { |
| private: |
| const Metadata *Type; |
| const FieldDescriptor *Description; |
| |
| public: |
| FieldDescriptorCacheEntry(const Metadata *type, |
| const FieldDescriptor *description) |
| : Type(type), Description(description) {} |
| |
| const FieldDescriptor *getDescription() { return Description; } |
| |
| int compareWithKey(const Metadata *other) const { |
| auto a = (uintptr_t)Type; |
| auto b = (uintptr_t)other; |
| return a == b ? 0 : (a < b ? -1 : 1); |
| } |
| |
| template <class... Args> |
| static size_t getExtraAllocationSize(Args &&... ignored) { |
| return 0; |
| } |
| }; |
| |
| } // namespace |
| |
| #pragma mark Metadata lookup via mangled name |
| |
| llvm::Optional<unsigned> |
| swift::_depthIndexToFlatIndex(unsigned depth, unsigned index, |
| llvm::ArrayRef<unsigned> paramCounts) { |
| // Out-of-bounds depth. |
| if (depth >= paramCounts.size()) return None; |
| |
| // Compute the flat index. |
| unsigned flatIndex = index + (depth == 0 ? 0 : paramCounts[depth - 1]); |
| |
| // Out-of-bounds index. |
| if (flatIndex >= paramCounts[depth]) return None; |
| |
| return flatIndex; |
| } |
| |
| /// Gather generic parameter counts from a context descriptor. |
| /// |
| /// \returns true if the innermost descriptor is generic. |
| bool swift::_gatherGenericParameterCounts( |
| const ContextDescriptor *descriptor, |
| llvm::SmallVectorImpl<unsigned> &genericParamCounts, |
| Demangler &BorrowFrom) { |
| DemanglerForRuntimeTypeResolution<> demangler; |
| demangler.providePreallocatedMemory(BorrowFrom); |
| |
| if (auto extension = _findExtendedTypeContextDescriptor(descriptor, |
| demangler)) { |
| // If we have a nominal type extension descriptor, extract the extended type |
| // and use that. If the extension is not nominal, then we can use the |
| // extension's own signature. |
| descriptor = extension; |
| } |
| |
| // Once we hit a non-generic descriptor, we're done. |
| if (!descriptor->isGeneric()) return false; |
| |
| // Recurse to record the parent context's generic parameters. |
| auto parent = descriptor->Parent.get(); |
| (void)_gatherGenericParameterCounts(parent, genericParamCounts, demangler); |
| |
| // Record a new level of generic parameters if the count exceeds the |
| // previous count. |
| unsigned parentCount = parent->getNumGenericParams(); |
| unsigned myCount = descriptor->getNumGenericParams(); |
| if (myCount > parentCount) { |
| genericParamCounts.push_back(myCount); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /// Retrieve the generic parameters introduced in this context. |
| static llvm::ArrayRef<GenericParamDescriptor> |
| getLocalGenericParams(const ContextDescriptor *context) { |
| if (!context->isGeneric()) |
| return { }; |
| |
| // Determine where to start looking at generic parameters. |
| unsigned startParamIndex; |
| if (auto parent = context->Parent.get()) |
| startParamIndex = parent->getNumGenericParams(); |
| else |
| startParamIndex = 0; |
| |
| auto genericContext = context->getGenericContext(); |
| return genericContext->getGenericParams().slice(startParamIndex); |
| } |
| |
| static llvm::Optional<TypeLookupError> |
| _gatherGenericParameters(const ContextDescriptor *context, |
| llvm::ArrayRef<const Metadata *> genericArgs, |
| const Metadata *parent, |
| llvm::SmallVectorImpl<unsigned> &genericParamCounts, |
| llvm::SmallVectorImpl<const void *> &allGenericArgsVec, |
| Demangler &demangler) { |
| auto makeCommonErrorStringGetter = [&] { |
| auto metadataVector = genericArgs.vec(); |
| return [=] { |
| std::string str; |
| |
| str += "_gatherGenericParameters: context: "; |
| |
| #if !defined(SWIFT_RUNTIME_MACHO_NO_DYLD) |
| SymbolInfo contextInfo; |
| if (lookupSymbol(context, &contextInfo)) { |
| str += contextInfo.symbolName.get(); |
| str += " "; |
| } |
| #endif |
| |
| char *contextStr; |
| swift_asprintf(&contextStr, "%p", context); |
| str += contextStr; |
| free(contextStr); |
| |
| str += " <"; |
| |
| bool first = true; |
| for (const Metadata *metadata : genericArgs) { |
| if (!first) |
| str += ", "; |
| first = false; |
| str += nameForMetadata(metadata); |
| } |
| |
| str += "> "; |
| |
| str += "parent: "; |
| if (parent) |
| str += nameForMetadata(parent); |
| else |
| str += "<null>"; |
| str += " - "; |
| |
| return str; |
| }; |
| }; |
| |
| // Figure out the various levels of generic parameters we have in |
| // this type. |
| (void)_gatherGenericParameterCounts(context, |
| genericParamCounts, demangler); |
| unsigned numTotalGenericParams = |
| genericParamCounts.empty() ? 0 : genericParamCounts.back(); |
| |
| // Check whether we have the right number of generic arguments. |
| if (genericArgs.size() == getLocalGenericParams(context).size()) { |
| // Okay: genericArgs is the innermost set of generic arguments. |
| } else if (genericArgs.size() == numTotalGenericParams && !parent) { |
| // Okay: genericArgs is the complete set of generic arguments. |
| } else { |
| auto commonString = makeCommonErrorStringGetter(); |
| auto genericArgsSize = genericArgs.size(); |
| return TypeLookupError([=] { |
| return commonString() + "incorrect number of generic args (" + |
| std::to_string(genericArgsSize) + "), " + |
| std::to_string(getLocalGenericParams(context).size()) + |
| " local params, " + std::to_string(numTotalGenericParams) + |
| " total params"; |
| }); |
| } |
| |
| // If there are generic parameters at any level, check the generic |
| // requirements and fill in the generic arguments vector. |
| if (!genericParamCounts.empty()) { |
| // Compute the set of generic arguments "as written". |
| llvm::SmallVector<const Metadata *, 8> allGenericArgs; |
| |
| // If we have a parent, gather it's generic arguments "as written". |
| if (parent) { |
| gatherWrittenGenericArgs(parent, parent->getTypeContextDescriptor(), |
| allGenericArgs, demangler); |
| } |
| |
| // Add the generic arguments we were given. |
| allGenericArgs.insert(allGenericArgs.end(), |
| genericArgs.begin(), genericArgs.end()); |
| |
| // Copy the generic arguments needed for metadata from the generic |
| // arguments "as written". |
| auto generics = context->getGenericContext(); |
| assert(generics); |
| { |
| auto genericParams = generics->getGenericParams(); |
| unsigned n = genericParams.size(); |
| if (allGenericArgs.size() != n) { |
| auto commonString = makeCommonErrorStringGetter(); |
| auto argsVecSize = allGenericArgsVec.size(); |
| return TypeLookupError([=] { |
| return commonString() + "have " + std::to_string(argsVecSize) + |
| "generic args, expected " + std::to_string(n); |
| }); |
| } |
| for (unsigned i = 0; i != n; ++i) { |
| const auto ¶m = genericParams[i]; |
| if (param.getKind() != GenericParamKind::Type) { |
| auto commonString = makeCommonErrorStringGetter(); |
| return TypeLookupError([=] { |
| return commonString() + "param " + std::to_string(i) + |
| " has unexpected kind " + |
| std::to_string(static_cast<uint8_t>(param.getKind())); |
| }); |
| } |
| if (param.hasExtraArgument()) { |
| auto commonString = makeCommonErrorStringGetter(); |
| return TypeLookupError([=] { |
| return commonString() + "param " + std::to_string(i) + |
| "has extra argument"; |
| }); |
| } |
| if (param.hasKeyArgument()) |
| allGenericArgsVec.push_back(allGenericArgs[i]); |
| } |
| } |
| |
| // If we have the wrong number of generic arguments, fail. |
| |
| // Check whether the generic requirements are satisfied, collecting |
| // any extra arguments we need for the instantiation function. |
| SubstGenericParametersFromWrittenArgs substitutions(allGenericArgs, |
| genericParamCounts); |
| auto error = _checkGenericRequirements( |
| generics->getGenericRequirements(), allGenericArgsVec, |
| [&substitutions](unsigned depth, unsigned index) { |
| return substitutions.getMetadata(depth, index); |
| }, |
| [&substitutions](const Metadata *type, unsigned index) { |
| return substitutions.getWitnessTable(type, index); |
| }); |
| if (error) |
| return *error; |
| |
| // If we still have the wrong number of generic arguments, this is |
| // some kind of metadata mismatch. |
| if (generics->getGenericContextHeader().getNumArguments() != |
| allGenericArgsVec.size()) { |
| auto commonString = makeCommonErrorStringGetter(); |
| auto argsVecSize = allGenericArgsVec.size(); |
| return TypeLookupError([=] { |
| return commonString() + "generic argument count mismatch, expected " + |
| std::to_string( |
| generics->getGenericContextHeader().getNumArguments()) + |
| ", have " + std::to_string(argsVecSize); |
| }); |
| } |
| } |
| |
| return llvm::None; |
| } |
| |
| namespace { |
| |
| /// Find the offset of the protocol requirement for an associated type with |
| /// the given name in the given protocol descriptor. |
| llvm::Optional<const ProtocolRequirement *> |
| findAssociatedTypeByName(const ProtocolDescriptor *protocol, StringRef name) { |
| // If we don't have associated type names, there's nothing to do. |
| const char *associatedTypeNamesPtr = protocol->AssociatedTypeNames.get(); |
| if (!associatedTypeNamesPtr) return None; |
| |
| // Look through the list of associated type names. |
| StringRef associatedTypeNames(associatedTypeNamesPtr); |
| unsigned matchingAssocTypeIdx = 0; |
| bool found = false; |
| while (!associatedTypeNames.empty()) { |
| // Avoid using StringRef::split because its definition is not |
| // provided in the header so that it requires linking with libSupport.a. |
| auto splitIdx = associatedTypeNames.find(' '); |
| if (associatedTypeNames.substr(0, splitIdx) == name) { |
| found = true; |
| break; |
| } |
| |
| ++matchingAssocTypeIdx; |
| associatedTypeNames = associatedTypeNames.substr(splitIdx).substr(1); |
| } |
| |
| if (!found) return None; |
| |
| // We have a match on the Nth associated type; go find the Nth associated |
| // type requirement. |
| unsigned currentAssocTypeIdx = 0; |
| unsigned numRequirements = protocol->NumRequirements; |
| auto requirements = protocol->getRequirements(); |
| for (unsigned reqIdx = 0; reqIdx != numRequirements; ++reqIdx) { |
| if (requirements[reqIdx].Flags.getKind() != |
| ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction) |
| continue; |
| |
| if (currentAssocTypeIdx == matchingAssocTypeIdx) |
| return requirements.begin() + reqIdx; |
| |
| ++currentAssocTypeIdx; |
| } |
| |
| swift_unreachable("associated type names don't line up"); |
| } |
| |
| namespace { |
| static Lazy<Mutex> DynamicReplacementLock; |
| } |
| |
| namespace { |
| struct OpaqueTypeMappings { |
| llvm::DenseMap<const OpaqueTypeDescriptor *, const OpaqueTypeDescriptor *> |
| descriptorMapping; |
| const OpaqueTypeDescriptor* find(const OpaqueTypeDescriptor *orig) { |
| const OpaqueTypeDescriptor *replacement = nullptr; |
| DynamicReplacementLock.get().withLock([&] { |
| auto entry = descriptorMapping.find(orig); |
| if (entry != descriptorMapping.end()) |
| replacement = entry->second; |
| }); |
| return replacement; |
| } |
| |
| // We take a mutex argument to make sure someone is holding the lock. |
| void insert(const OpaqueTypeDescriptor *orig, |
| const OpaqueTypeDescriptor *replacement, const Mutex &) { |
| descriptorMapping[orig] = replacement; |
| } |
| }; |
| } // end unnamed namespace |
| |
| static Lazy<OpaqueTypeMappings> opaqueTypeMappings; |
| |
| |
| static const OpaqueTypeDescriptor * |
| _findOpaqueTypeDescriptor(NodePointer demangleNode, |
| Demangler &dem) { |
| // Directly resolve a symbolic reference. |
| if (demangleNode->getKind() |
| == Node::Kind::OpaqueTypeDescriptorSymbolicReference) { |
| auto context = (const ContextDescriptor *)demangleNode->getIndex(); |
| auto *orig = cast<OpaqueTypeDescriptor>(context); |
| if (auto *entry = opaqueTypeMappings.get().find(orig)) { |
| return entry; |
| } |
| return orig; |
| } |
| |
| // TODO: Find non-symbolic-referenced opaque decls. |
| return nullptr; |
| } |
| |
| /// Constructs metadata by decoding a mangled type name, for use with |
| /// \c TypeDecoder. |
| class DecodedMetadataBuilder { |
| private: |
| /// The demangler we'll use when building new nodes. |
| Demangler &demangler; |
| |
| /// Substitute generic parameters. |
| SubstGenericParameterFn substGenericParameter; |
| |
| /// Substitute dependent witness tables. |
| SubstDependentWitnessTableFn substWitnessTable; |
| |
| /// Ownership information related to the metadata we are trying to lookup. |
| TypeReferenceOwnership ReferenceOwnership; |
| |
| public: |
| DecodedMetadataBuilder(Demangler &demangler, |
| SubstGenericParameterFn substGenericParameter, |
| SubstDependentWitnessTableFn substWitnessTable) |
| : demangler(demangler), |
| substGenericParameter(substGenericParameter), |
| substWitnessTable(substWitnessTable) { } |
| |
| using BuiltType = const Metadata *; |
| using BuiltTypeDecl = const ContextDescriptor *; |
| using BuiltProtocolDecl = ProtocolDescriptorRef; |
| |
| Demangle::NodeFactory &getNodeFactory() { return demangler; } |
| |
| TypeLookupErrorOr<BuiltType> |
| resolveOpaqueType(NodePointer opaqueDecl, |
| llvm::ArrayRef<llvm::ArrayRef<BuiltType>> genericArgs, |
| unsigned ordinal) { |
| auto descriptor = _findOpaqueTypeDescriptor(opaqueDecl, demangler); |
| if (!descriptor) |
| return BuiltType(); |
| auto outerContext = descriptor->Parent.get(); |
| |
| llvm::SmallVector<BuiltType, 8> allGenericArgs; |
| for (auto argSet : genericArgs) { |
| allGenericArgs.append(argSet.begin(), argSet.end()); |
| } |
| |
| // Gather the generic parameters we need to parameterize the opaque decl. |
| llvm::SmallVector<unsigned, 8> genericParamCounts; |
| llvm::SmallVector<const void *, 8> allGenericArgsVec; |
| |
| if (auto error = _gatherGenericParameters( |
| outerContext, allGenericArgs, BuiltType(), /* no parent */ |
| genericParamCounts, allGenericArgsVec, demangler)) |
| return *error; |
| |
| auto mangledName = descriptor->getUnderlyingTypeArgument(ordinal); |
| SubstGenericParametersFromMetadata substitutions(descriptor, |
| allGenericArgsVec.data()); |
| return swift_getTypeByMangledName(MetadataState::Complete, |
| mangledName, allGenericArgsVec.data(), |
| [&substitutions](unsigned depth, unsigned index) { |
| return substitutions.getMetadata(depth, index); |
| }, |
| [&substitutions](const Metadata *type, unsigned index) { |
| return substitutions.getWitnessTable(type, index); |
| }).getType().getMetadata(); |
| } |
| |
| BuiltTypeDecl createTypeDecl(NodePointer node, |
| bool &typeAlias) const { |
| // Look for a nominal type descriptor based on its mangled name. |
| return _findContextDescriptor(node, demangler); |
| } |
| |
| BuiltProtocolDecl createProtocolDecl(NodePointer node) const { |
| // Look for a protocol descriptor based on its mangled name. |
| std::string mangledName; |
| if (auto protocol = _findProtocolDescriptor(node, demangler, mangledName)) |
| return ProtocolDescriptorRef::forSwift(protocol);; |
| |
| #if SWIFT_OBJC_INTEROP |
| // Look for a Swift-defined @objc protocol with the Swift 3 mangling that |
| // is used for Objective-C entities. |
| const char *objcMangledName = mangleNodeAsObjcCString(node, demangler); |
| if (auto protocol = objc_getProtocol(objcMangledName)) |
| return ProtocolDescriptorRef::forObjC(protocol); |
| #endif |
| |
| return ProtocolDescriptorRef(); |
| } |
| |
| BuiltProtocolDecl createObjCProtocolDecl( |
| const std::string &mangledName) const { |
| #if SWIFT_OBJC_INTEROP |
| return ProtocolDescriptorRef::forObjC( |
| objc_getProtocol(mangledName.c_str())); |
| #else |
| return ProtocolDescriptorRef(); |
| #endif |
| } |
| |
| TypeLookupErrorOr<BuiltType> |
| createObjCClassType(const std::string &mangledName) const { |
| #if SWIFT_OBJC_INTEROP |
| auto objcClass = objc_getClass(mangledName.c_str()); |
| return swift_getObjCClassMetadata((const ClassMetadata *)objcClass); |
| #else |
| return BuiltType(); |
| #endif |
| } |
| |
| TypeLookupErrorOr<BuiltType> |
| createBoundGenericObjCClassType(const std::string &mangledName, |
| llvm::ArrayRef<BuiltType> args) const { |
| // Generic arguments of lightweight Objective-C generic classes are not |
| // reified in the metadata. |
| return createObjCClassType(mangledName); |
| } |
| |
| TypeLookupErrorOr<BuiltType> |
| createNominalType(BuiltTypeDecl metadataOrTypeDecl, BuiltType parent) const { |
| // Treat nominal type creation the same way as generic type creation, |
| // but with no generic arguments at this level. |
| return createBoundGenericType(metadataOrTypeDecl, { }, parent); |
| } |
| |
| TypeLookupErrorOr<BuiltType> createTypeAliasType(BuiltTypeDecl typeAliasDecl, |
| BuiltType parent) const { |
| // We can't support sugared types here since we have no way to |
| // resolve the underlying type of the type alias. However, some |
| // CF types are mangled as type aliases. |
| return createNominalType(typeAliasDecl, parent); |
| } |
| |
| TypeLookupErrorOr<BuiltType> |
| createBoundGenericType(BuiltTypeDecl anyTypeDecl, |
| llvm::ArrayRef<BuiltType> genericArgs, |
| BuiltType parent) const { |
| auto typeDecl = dyn_cast<TypeContextDescriptor>(anyTypeDecl); |
| if (!typeDecl) { |
| if (auto protocol = dyn_cast<ProtocolDescriptor>(anyTypeDecl)) |
| return _getSimpleProtocolTypeMetadata(protocol); |
| |
| return BuiltType(); |
| } |
| |
| // Figure out the various levels of generic parameters we have in |
| // this type. |
| llvm::SmallVector<unsigned, 8> genericParamCounts; |
| llvm::SmallVector<const void *, 8> allGenericArgsVec; |
| |
| if (auto error = _gatherGenericParameters(typeDecl, genericArgs, parent, |
| genericParamCounts, |
| allGenericArgsVec, demangler)) |
| return *error; |
| |
| // Call the access function. |
| auto accessFunction = typeDecl->getAccessFunction(); |
| if (!accessFunction) return BuiltType(); |
| |
| return accessFunction(MetadataState::Abstract, allGenericArgsVec).Value; |
| } |
| |
| TypeLookupErrorOr<BuiltType> createBuiltinType(StringRef builtinName, |
| StringRef mangledName) const { |
| #define BUILTIN_TYPE(Symbol, _) \ |
| if (mangledName.equals(#Symbol)) \ |
| return &METADATA_SYM(Symbol).base; |
| #include "swift/Runtime/BuiltinTypes.def" |
| return BuiltType(); |
| } |
| |
| TypeLookupErrorOr<BuiltType> createMetatypeType( |
| BuiltType instance, |
| llvm::Optional<Demangle::ImplMetatypeRepresentation> repr = None) const { |
| return swift_getMetatypeMetadata(instance); |
| } |
| |
| TypeLookupErrorOr<BuiltType> createExistentialMetatypeType( |
| BuiltType instance, |
| llvm::Optional<Demangle::ImplMetatypeRepresentation> repr = None) const { |
| return swift_getExistentialMetatypeMetadata(instance); |
| } |
| |
| TypeLookupErrorOr<BuiltType> |
| createProtocolCompositionType(llvm::ArrayRef<BuiltProtocolDecl> protocols, |
| BuiltType superclass, bool isClassBound) const { |
| // Determine whether we have a class bound. |
| ProtocolClassConstraint classConstraint = ProtocolClassConstraint::Any; |
| if (isClassBound || superclass) { |
| classConstraint = ProtocolClassConstraint::Class; |
| } else { |
| for (auto protocol : protocols) { |
| if (protocol.getClassConstraint() == ProtocolClassConstraint::Class) { |
| classConstraint = ProtocolClassConstraint::Class; |
| break; |
| } |
| } |
| } |
| |
| return swift_getExistentialTypeMetadata(classConstraint, superclass, |
| protocols.size(), protocols.data()); |
| } |
| |
| TypeLookupErrorOr<BuiltType> createDynamicSelfType(BuiltType selfType) const { |
| // Free-standing mangled type strings should not contain DynamicSelfType. |
| return BuiltType(); |
| } |
| |
| TypeLookupErrorOr<BuiltType> |
| createGenericTypeParameterType(unsigned depth, unsigned index) const { |
| // Use the callback, when provided. |
| if (substGenericParameter) |
| return substGenericParameter(depth, index); |
| |
| return BuiltType(); |
| } |
| |
| TypeLookupErrorOr<BuiltType> |
| createFunctionType(llvm::ArrayRef<Demangle::FunctionParam<BuiltType>> params, |
| BuiltType result, FunctionTypeFlags flags) const { |
| llvm::SmallVector<BuiltType, 8> paramTypes; |
| llvm::SmallVector<uint32_t, 8> paramFlags; |
| |
| // Fill in the parameters. |
| paramTypes.reserve(params.size()); |
| if (flags.hasParameterFlags()) |
| paramFlags.reserve(params.size()); |
| for (const auto ¶m : params) { |
| paramTypes.push_back(param.getType()); |
| if (flags.hasParameterFlags()) |
| paramFlags.push_back(param.getFlags().getIntValue()); |
| } |
| |
| return swift_getFunctionTypeMetadata(flags, paramTypes.data(), |
| flags.hasParameterFlags() |
| ? paramFlags.data() |
| : nullptr, |
| result); |
| } |
| |
| TypeLookupErrorOr<BuiltType> createImplFunctionType( |
| Demangle::ImplParameterConvention calleeConvention, |
| llvm::ArrayRef<Demangle::ImplFunctionParam<BuiltType>> params, |
| llvm::ArrayRef<Demangle::ImplFunctionResult<BuiltType>> results, |
| llvm::Optional<Demangle::ImplFunctionResult<BuiltType>> errorResult, |
| ImplFunctionTypeFlags flags) { |
| // We can't realize the metadata for a SILFunctionType. |
| return BuiltType(); |
| } |
| |
| TypeLookupErrorOr<BuiltType> |
| createTupleType(llvm::ArrayRef<BuiltType> elements, |
| std::string labels) const { |
| auto flags = TupleTypeFlags().withNumElements(elements.size()); |
| if (!labels.empty()) |
| flags = flags.withNonConstantLabels(true); |
| return MetadataResponse(swift_getTupleTypeMetadata( |
| MetadataState::Abstract, flags, elements.data(), |
| labels.empty() ? nullptr : labels.c_str(), |
| /*proposedWitnesses=*/nullptr)) |
| .Value; |
| } |
| |
| TypeLookupErrorOr<BuiltType> createDependentMemberType(StringRef name, |
| BuiltType base) const { |
| // Should not have unresolved dependent member types here. |
| return BuiltType(); |
| } |
| |
| TypeLookupErrorOr<BuiltType> |
| createDependentMemberType(StringRef name, BuiltType base, |
| BuiltProtocolDecl protocol) const { |
| #if SWIFT_OBJC_INTEROP |
| if (protocol.isObjC()) |
| return BuiltType(); |
| #endif |
| |
| auto swiftProtocol = protocol.getSwiftProtocol(); |
| auto witnessTable = swift_conformsToProtocol(base, swiftProtocol); |
| if (!witnessTable) |
| return BuiltType(); |
| |
| // Look for the named associated type within the protocol. |
| auto assocType = findAssociatedTypeByName(swiftProtocol, name); |
| if (!assocType) return nullptr; |
| |
| // Call the associated type access function. |
| return swift_getAssociatedTypeWitness( |
| MetadataState::Abstract, |
| const_cast<WitnessTable *>(witnessTable), |
| base, |
| swiftProtocol->getRequirementBaseDescriptor(), |
| *assocType).Value; |
| } |
| |
| #define REF_STORAGE(Name, ...) \ |
| TypeLookupErrorOr<BuiltType> create##Name##StorageType(BuiltType base) { \ |
| ReferenceOwnership.set##Name(); \ |
| return base; \ |
| } |
| #include "swift/AST/ReferenceStorage.def" |
| |
| TypeLookupErrorOr<BuiltType> createSILBoxType(BuiltType base) const { |
| // FIXME: Implement. |
| return BuiltType(); |
| } |
| |
| TypeReferenceOwnership getReferenceOwnership() const { |
| return ReferenceOwnership; |
| } |
| |
| TypeLookupErrorOr<BuiltType> createOptionalType(BuiltType base) { |
| // Mangled types for building metadata don't contain sugared types |
| return BuiltType(); |
| } |
| |
| TypeLookupErrorOr<BuiltType> createArrayType(BuiltType base) { |
| // Mangled types for building metadata don't contain sugared types |
| return BuiltType(); |
| } |
| |
| TypeLookupErrorOr<BuiltType> createDictionaryType(BuiltType key, |
| BuiltType value) { |
| // Mangled types for building metadata don't contain sugared types |
| return BuiltType(); |
| } |
| |
| TypeLookupErrorOr<BuiltType> createParenType(BuiltType base) { |
| // Mangled types for building metadata don't contain sugared types |
| return BuiltType(); |
| } |
| }; |
| |
| } |
| |
| SWIFT_CC(swift) |
| static TypeLookupErrorOr<TypeInfo> |
| swift_getTypeByMangledNodeImpl(MetadataRequest request, Demangler &demangler, |
| Demangle::NodePointer node, |
| const void *const *origArgumentVector, |
| SubstGenericParameterFn substGenericParam, |
| SubstDependentWitnessTableFn substWitnessTable) { |
| // Simply call an accessor function if that's all we got. |
| if (node->getKind() == Node::Kind::AccessorFunctionReference) { |
| // The accessor function is passed the pointer to the original argument |
| // buffer. It's assumed to match the generic context. |
| auto accessorFn = |
| (const Metadata *(*)(const void * const *))node->getIndex(); |
| auto type = accessorFn(origArgumentVector); |
| // We don't call checkMetadataState here since the result may not really |
| // *be* type metadata. If the accessor returns a type, it is responsible |
| // for completing the metadata. |
| return TypeInfo{MetadataResponse{type, MetadataState::Complete}, |
| TypeReferenceOwnership()}; |
| } |
| |
| // TODO: propagate the request down to the builder instead of calling |
| // swift_checkMetadataState after the fact. |
| DecodedMetadataBuilder builder(demangler, substGenericParam, |
| substWitnessTable); |
| auto type = Demangle::decodeMangledType(builder, node); |
| if (type.isError()) { |
| return *type.getError(); |
| } |
| if (!type.getType()) { |
| return TypeLookupError("NULL type but no error provided"); |
| } |
| |
| return TypeInfo{swift_checkMetadataState(request, type.getType()), |
| builder.getReferenceOwnership()}; |
| } |
| |
| SWIFT_CC(swift) |
| static TypeLookupErrorOr<TypeInfo> |
| swift_getTypeByMangledNameImpl(MetadataRequest request, StringRef typeName, |
| const void *const *origArgumentVector, |
| SubstGenericParameterFn substGenericParam, |
| SubstDependentWitnessTableFn substWitnessTable) { |
| DemanglerForRuntimeTypeResolution<StackAllocatedDemangler<2048>> demangler; |
| |
| NodePointer node; |
| |
| // Check whether this is the convenience syntax "ModuleName.ClassName". |
| auto getDotPosForConvenienceSyntax = [&]() -> size_t { |
| size_t dotPos = llvm::StringRef::npos; |
| for (unsigned i = 0; i < typeName.size(); ++i) { |
| // Should only contain one dot. |
| if (typeName[i] == '.') { |
| if (dotPos == llvm::StringRef::npos) { |
| dotPos = i; |
| continue; |
| } else { |
| return llvm::StringRef::npos; |
| } |
| } |
| |
| // Should not contain symbolic references. |
| if ((unsigned char)typeName[i] <= '\x1F') { |
| return llvm::StringRef::npos; |
| } |
| } |
| return dotPos; |
| }; |
| |
| auto dotPos = getDotPosForConvenienceSyntax(); |
| if (dotPos != llvm::StringRef::npos) { |
| // Form a demangle tree for this class. |
| NodePointer classNode = demangler.createNode(Node::Kind::Class); |
| NodePointer moduleNode = demangler.createNode(Node::Kind::Module, |
| typeName.substr(0, dotPos)); |
| NodePointer nameNode = demangler.createNode(Node::Kind::Identifier, |
| typeName.substr(dotPos + 1)); |
| classNode->addChild(moduleNode, demangler); |
| classNode->addChild(nameNode, demangler); |
| |
| node = classNode; |
| } else { |
| // Demangle the type name. |
| node = demangler.demangleTypeRef(typeName); |
| if (!node) { |
| return TypeInfo(); |
| } |
| } |
| |
| return swift_getTypeByMangledNode(request, demangler, node, |
| origArgumentVector, |
| substGenericParam, substWitnessTable); |
| } |
| |
| SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT |
| const Metadata * _Nullable |
| swift_getTypeByMangledNameInEnvironment( |
| const char *typeNameStart, |
| size_t typeNameLength, |
| const TargetGenericEnvironment<InProcess> *environment, |
| const void * const *genericArgs) { |
| llvm::StringRef typeName(typeNameStart, typeNameLength); |
| SubstGenericParametersFromMetadata substitutions(environment, genericArgs); |
| return swift_getTypeByMangledName(MetadataState::Complete, typeName, |
| genericArgs, |
| [&substitutions](unsigned depth, unsigned index) { |
| return substitutions.getMetadata(depth, index); |
| }, |
| [&substitutions](const Metadata *type, unsigned index) { |
| return substitutions.getWitnessTable(type, index); |
| }).getType().getMetadata(); |
| } |
| |
| SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT |
| const Metadata * _Nullable |
| swift_getTypeByMangledNameInEnvironmentInMetadataState( |
| size_t metadataState, |
| const char *typeNameStart, |
| size_t typeNameLength, |
| const TargetGenericEnvironment<InProcess> *environment, |
| const void * const *genericArgs) { |
| llvm::StringRef typeName(typeNameStart, typeNameLength); |
| SubstGenericParametersFromMetadata substitutions(environment, genericArgs); |
| return swift_getTypeByMangledName((MetadataState)metadataState, typeName, |
| genericArgs, |
| [&substitutions](unsigned depth, unsigned index) { |
| return substitutions.getMetadata(depth, index); |
| }, |
| [&substitutions](const Metadata *type, unsigned index) { |
| return substitutions.getWitnessTable(type, index); |
| }).getType().getMetadata(); |
| } |
| |
| SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT |
| const Metadata * _Nullable |
| swift_getTypeByMangledNameInContext( |
| const char *typeNameStart, |
| size_t typeNameLength, |
| const TargetContextDescriptor<InProcess> *context, |
| const void * const *genericArgs) { |
| llvm::StringRef typeName(typeNameStart, typeNameLength); |
| SubstGenericParametersFromMetadata substitutions(context, genericArgs); |
| return swift_getTypeByMangledName(MetadataState::Complete, typeName, |
| genericArgs, |
| [&substitutions](unsigned depth, unsigned index) { |
| return substitutions.getMetadata(depth, index); |
| }, |
| [&substitutions](const Metadata *type, unsigned index) { |
| return substitutions.getWitnessTable(type, index); |
| }).getType().getMetadata(); |
| } |
| |
| SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT |
| const Metadata * _Nullable |
| swift_getTypeByMangledNameInContextInMetadataState( |
| size_t metadataState, |
| const char *typeNameStart, |
| size_t typeNameLength, |
| const TargetContextDescriptor<InProcess> *context, |
| const void * const *genericArgs) { |
| llvm::StringRef typeName(typeNameStart, typeNameLength); |
| SubstGenericParametersFromMetadata substitutions(context, genericArgs); |
| return swift_getTypeByMangledName((MetadataState)metadataState, typeName, |
| genericArgs, |
| [&substitutions](unsigned depth, unsigned index) { |
| return substitutions.getMetadata(depth, index); |
| }, |
| [&substitutions](const Metadata *type, unsigned index) { |
| return substitutions.getWitnessTable(type, index); |
| }).getType().getMetadata(); |
| } |
| |
| /// Demangle a mangled name, but don't allow symbolic references. |
| SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL |
| const Metadata *_Nullable |
| swift_stdlib_getTypeByMangledNameUntrusted(const char *typeNameStart, |
| size_t typeNameLength) { |
| llvm::StringRef typeName(typeNameStart, typeNameLength); |
| for (char c : typeName) { |
| if (c >= '\x01' && c <= '\x1F') |
| return nullptr; |
| } |
| |
| return swift_getTypeByMangledName(MetadataState::Complete, typeName, nullptr, |
| {}, {}).getType().getMetadata(); |
| } |
| |
| SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT |
| MetadataResponse |
| swift_getOpaqueTypeMetadata(MetadataRequest request, |
| const void * const *arguments, |
| const OpaqueTypeDescriptor *descriptor, |
| unsigned index) { |
| auto mangledName = descriptor->getUnderlyingTypeArgument(index); |
| SubstGenericParametersFromMetadata substitutions(descriptor, arguments); |
| |
| return swift_getTypeByMangledName(request.getState(), |
| mangledName, arguments, |
| [&substitutions](unsigned depth, unsigned index) { |
| return substitutions.getMetadata(depth, index); |
| }, |
| [&substitutions](const Metadata *type, unsigned index) { |
| return substitutions.getWitnessTable(type, index); |
| }).getType().getResponse(); |
| } |
| |
| SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT |
| const WitnessTable * |
| swift_getOpaqueTypeConformance(const void * const *arguments, |
| const OpaqueTypeDescriptor *descriptor, |
| unsigned index) { |
| auto response = swift_getOpaqueTypeMetadata( |
| MetadataRequest(MetadataState::Complete), |
| arguments, descriptor, index); |
| return (const WitnessTable *)response.Value; |
| } |
| |
| #if SWIFT_OBJC_INTEROP |
| |
| // Return the ObjC class for the given type name. |
| // This gets installed as a callback from libobjc. |
| |
| // FIXME: delete this #if and dlsym once we don't |
| // need to build with older libobjc headers |
| #if !OBJC_GETCLASSHOOK_DEFINED |
| using objc_hook_getClass = BOOL(*)(const char * _Nonnull name, |
| Class _Nullable * _Nonnull outClass); |
| #endif |
| static objc_hook_getClass OldGetClassHook; |
| |
| static BOOL |
| getObjCClassByMangledName(const char * _Nonnull typeName, |
| Class _Nullable * _Nonnull outClass) { |
| // Demangle old-style class and protocol names, which are still used in the |
| // ObjC metadata. |
| StringRef typeStr(typeName); |
| const Metadata *metadata = nullptr; |
| if (typeStr.startswith("_Tt")) { |
| Demangler demangler; |
| auto node = demangler.demangleSymbol(typeName); |
| if (!node) |
| return NO; |
| |
| // If we successfully demangled but there is a suffix, then we did NOT use |
| // the entire name, and this is NOT a match. Reject it. |
| if (node->hasChildren() && |
| node->getLastChild()->getKind() == Node::Kind::Suffix) |
| return NO; |
| |
| metadata = swift_getTypeByMangledNode( |
| MetadataState::Complete, demangler, node, |
| nullptr, |
| /* no substitutions */ |
| [&](unsigned depth, unsigned index) { |
| return nullptr; |
| }, |
| [&](const Metadata *type, unsigned index) { |
| return nullptr; |
| }).getType().getMetadata(); |
| } else { |
| metadata = swift_stdlib_getTypeByMangledNameUntrusted(typeStr.data(), |
| typeStr.size()); |
| } |
| if (metadata) { |
| auto objcClass = |
| reinterpret_cast<Class>( |
| const_cast<ClassMetadata *>( |
| swift_getObjCClassFromMetadataConditional(metadata))); |
| |
| if (objcClass) { |
| *outClass = objcClass; |
| return YES; |
| } |
| } |
| |
| return OldGetClassHook(typeName, outClass); |
| } |
| |
| __attribute__((constructor)) |
| static void installGetClassHook() { |
| // FIXME: delete this #if and dlsym once we don't |
| // need to build with older libobjc headers |
| #if !OBJC_GETCLASSHOOK_DEFINED |
| using objc_hook_getClass = BOOL(*)(const char * _Nonnull name, |
| Class _Nullable * _Nonnull outClass); |
| auto objc_setHook_getClass = |
| (void(*)(objc_hook_getClass _Nonnull, |
| objc_hook_getClass _Nullable * _Nonnull)) |
| dlsym(RTLD_DEFAULT, "objc_setHook_getClass"); |
| #endif |
| |
| #pragma clang diagnostic push |
| #pragma clang diagnostic ignored "-Wunguarded-availability" |
| if (objc_setHook_getClass) { |
| objc_setHook_getClass(getObjCClassByMangledName, &OldGetClassHook); |
| } |
| #pragma clang diagnostic pop |
| } |
| |
| #endif |
| |
| unsigned SubstGenericParametersFromMetadata:: |
| buildDescriptorPath(const ContextDescriptor *context, |
| Demangler &borrowFrom) const { |
| assert(sourceIsMetadata); |
| |
| // Terminating condition: we don't have a context. |
| if (!context) |
| return 0; |
| |
| DemanglerForRuntimeTypeResolution<> demangler; |
| demangler.providePreallocatedMemory(borrowFrom); |
| |
| if (auto extension = _findExtendedTypeContextDescriptor(context, demangler)) { |
| // If we have a nominal type extension descriptor, extract the extended type |
| // and use that. If the extension is not nominal, then we can use the |
| // extension's own signature. |
| context = extension; |
| } |
| |
| // Add the parent's contribution to the descriptor path. |
| const ContextDescriptor *parent = context->Parent.get(); |
| unsigned numKeyGenericParamsInParent = buildDescriptorPath(parent, demangler); |
| |
| // If this context is non-generic, we're done. |
| if (!context->isGeneric()) |
| return numKeyGenericParamsInParent; |
| |
| // Count the number of key generic params at this level. |
| auto allGenericParams = baseContext->getGenericContext()->getGenericParams(); |
| unsigned parentCount = parent->getNumGenericParams(); |
| unsigned localCount = context->getNumGenericParams(); |
| auto localGenericParams = allGenericParams.slice(parentCount, |
| localCount - parentCount); |
| |
| unsigned numKeyGenericParamsHere = 0; |
| bool hasNonKeyGenericParams = false; |
| for (const auto &genericParam : localGenericParams) { |
| if (genericParam.hasKeyArgument()) |
| ++numKeyGenericParamsHere; |
| else |
| hasNonKeyGenericParams = true; |
| } |
| |
| // Form the path element if there are any new generic parameters. |
| if (localCount > parentCount) |
| descriptorPath.push_back(PathElement{localGenericParams, |
| context->getNumGenericParams(), |
| numKeyGenericParamsInParent, |
| numKeyGenericParamsHere, |
| hasNonKeyGenericParams}); |
| return numKeyGenericParamsInParent + numKeyGenericParamsHere; |
| } |
| |
| /// Builds a path from the generic environment. |
| unsigned SubstGenericParametersFromMetadata:: |
| buildEnvironmentPath( |
| const TargetGenericEnvironment<InProcess> *environment) const { |
| unsigned totalParamCount = 0; |
| unsigned totalKeyParamCount = 0; |
| auto genericParams = environment->getGenericParameters(); |
| for (unsigned numLocalParams : environment->getGenericParameterCounts()) { |
| // Adkjust totalParamCount so we have the # of local parameters. |
| numLocalParams -= totalParamCount; |
| |
| // Get the local generic parameters. |
| auto localGenericParams = genericParams.slice(0, numLocalParams); |
| genericParams = genericParams.slice(numLocalParams); |
| |
| // Count the parameters. |
| unsigned numKeyGenericParamsInParent = totalKeyParamCount; |
| unsigned numKeyGenericParamsHere = 0; |
| bool hasNonKeyGenericParams = false; |
| for (const auto &genericParam : localGenericParams) { |
| if (genericParam.hasKeyArgument()) |
| ++numKeyGenericParamsHere; |
| else |
| hasNonKeyGenericParams = true; |
| } |
| |
| // Update totals. |
| totalParamCount += numLocalParams; |
| totalKeyParamCount += numKeyGenericParamsHere; |
| |
| // Add to the descriptor path. |
| descriptorPath.push_back(PathElement{localGenericParams, |
| totalParamCount, |
| numKeyGenericParamsInParent, |
| numKeyGenericParamsHere, |
| hasNonKeyGenericParams}); |
| } |
| |
| return totalKeyParamCount; |
| } |
| |
| void SubstGenericParametersFromMetadata::setup() const { |
| if (!descriptorPath.empty()) |
| return; |
| |
| if (sourceIsMetadata && baseContext) { |
| DemanglerForRuntimeTypeResolution<StackAllocatedDemangler<2048>> demangler; |
| numKeyGenericParameters = buildDescriptorPath(baseContext, demangler); |
| return; |
| } |
| |
| if (!sourceIsMetadata && environment) { |
| numKeyGenericParameters = buildEnvironmentPath(environment); |
| return; |
| } |
| } |
| |
| const Metadata * |
| SubstGenericParametersFromMetadata::getMetadata( |
| unsigned depth, unsigned index) const { |
| // On first access, compute the descriptor path. |
| setup(); |
| |
| // If the depth is too great, there is nothing to do. |
| if (depth >= descriptorPath.size()) |
| return nullptr; |
| |
| /// Retrieve the descriptor path element at this depth. |
| auto &pathElement = descriptorPath[depth]; |
| |
| // Check whether the index is clearly out of bounds. |
| if (index >= pathElement.numTotalGenericParams) |
| return nullptr; |
| |
| // Compute the flat index. |
| unsigned flatIndex = pathElement.numKeyGenericParamsInParent; |
| if (pathElement.hasNonKeyGenericParams > 0) { |
| // We have non-key generic parameters at this level, so the index needs to |
| // be checked more carefully. |
| auto genericParams = pathElement.localGenericParams; |
| |
| // Make sure that the requested parameter itself has a key argument. |
| if (!genericParams[index].hasKeyArgument()) |
| return nullptr; |
| |
| // Increase the flat index for each parameter with a key argument, up to |
| // the given index. |
| for (const auto &genericParam : genericParams.slice(0, index)) { |
| if (genericParam.hasKeyArgument()) |
| ++flatIndex; |
| } |
| } else { |
| flatIndex += index; |
| } |
| |
| return (const Metadata *)genericArgs[flatIndex]; |
| } |
| |
| const WitnessTable * |
| SubstGenericParametersFromMetadata::getWitnessTable(const Metadata *type, |
| unsigned index) const { |
| // On first access, compute the descriptor path. |
| setup(); |
| |
| return (const WitnessTable *)genericArgs[index + numKeyGenericParameters]; |
| } |
| |
| const Metadata *SubstGenericParametersFromWrittenArgs::getMetadata( |
| unsigned depth, unsigned index) const { |
| if (auto flatIndex = |
| _depthIndexToFlatIndex(depth, index, genericParamCounts)) { |
| if (*flatIndex < allGenericArgs.size()) |
| return allGenericArgs[*flatIndex]; |
| } |
| |
| return nullptr; |
| } |
| |
| const WitnessTable * |
| SubstGenericParametersFromWrittenArgs::getWitnessTable(const Metadata *type, |
| unsigned index) const { |
| return nullptr; |
| } |
| |
| /// Demangle the given type name to a generic parameter reference, which |
| /// will be returned as (depth, index). |
| static llvm::Optional<std::pair<unsigned, unsigned>> |
| demangleToGenericParamRef(StringRef typeName) { |
| StackAllocatedDemangler<1024> demangler; |
| NodePointer node = demangler.demangleType(typeName); |
| if (!node) |
| return None; |
| |
| // Find the flat index that the right-hand side refers to. |
| if (node->getKind() == Demangle::Node::Kind::Type) |
| node = node->getChild(0); |
| if (node->getKind() != Demangle::Node::Kind::DependentGenericParamType) |
| return None; |
| |
| return std::pair<unsigned, unsigned>(node->getChild(0)->getIndex(), |
| node->getChild(1)->getIndex()); |
| } |
| |
| void swift::gatherWrittenGenericArgs( |
| const Metadata *metadata, const TypeContextDescriptor *description, |
| llvm::SmallVectorImpl<const Metadata *> &allGenericArgs, |
| Demangler &BorrowFrom) { |
| if (!description) |
| return; |
| auto generics = description->getGenericContext(); |
| if (!generics) |
| return; |
| |
| bool missingWrittenArguments = false; |
| auto genericArgs = description->getGenericArguments(metadata); |
| for (auto param : generics->getGenericParams()) { |
| switch (param.getKind()) { |
| case GenericParamKind::Type: |
| // The type should have a key argument unless it's been same-typed to |
| // another type. |
| if (param.hasKeyArgument()) { |
| auto genericArg = *genericArgs++; |
| allGenericArgs.push_back(genericArg); |
| } else { |
| // Leave a gap for us to fill in by looking at same type info. |
| allGenericArgs.push_back(nullptr); |
| missingWrittenArguments = true; |
| } |
| |
| // We don't know about type parameters with extra arguments. Leave |
| // a hole for it. |
| if (param.hasExtraArgument()) { |
| allGenericArgs.push_back(nullptr); |
| ++genericArgs; |
| } |
| break; |
| |
| default: |
| // We don't know about this kind of parameter. Create placeholders where |
| // needed. |
| if (param.hasKeyArgument()) { |
| allGenericArgs.push_back(nullptr); |
| ++genericArgs; |
| } |
| |
| if (param.hasExtraArgument()) { |
| allGenericArgs.push_back(nullptr); |
| ++genericArgs; |
| } |
| break; |
| } |
| } |
| |
| // If there is no follow-up work to do, we're done. |
| if (!missingWrittenArguments) |
| return; |
| |
| // We have generic arguments that would be written, but have been |
| // canonicalized away. Use same-type requirements to reconstitute them. |
| |
| // Retrieve the mapping information needed for depth/index -> flat index. |
| llvm::SmallVector<unsigned, 8> genericParamCounts; |
| (void)_gatherGenericParameterCounts(description, genericParamCounts, |
| BorrowFrom); |
| |
| // Walk through the generic requirements to evaluate same-type |
| // constraints that are needed to fill in missing generic arguments. |
| for (const auto &req : generics->getGenericRequirements()) { |
| // We only care about same-type constraints. |
| if (req.Flags.getKind() != GenericRequirementKind::SameType) |
| continue; |
| |
| auto lhsParam = demangleToGenericParamRef(req.getParam()); |
| if (!lhsParam) |
| continue; |
| |
| // If we don't yet have an argument for this parameter, it's a |
| // same-type-to-concrete constraint. |
| auto lhsFlatIndex = |
| _depthIndexToFlatIndex(lhsParam->first, lhsParam->second, |
| genericParamCounts); |
| if (!lhsFlatIndex || *lhsFlatIndex >= allGenericArgs.size()) |
| continue; |
| |
| if (!allGenericArgs[*lhsFlatIndex]) { |
| // Substitute into the right-hand side. |
| SubstGenericParametersFromWrittenArgs substitutions(allGenericArgs, |
| genericParamCounts); |
| allGenericArgs[*lhsFlatIndex] = |
| swift_getTypeByMangledName(MetadataState::Abstract, |
| req.getMangledTypeName(), |
| (const void * const *)allGenericArgs.data(), |
| [&substitutions](unsigned depth, unsigned index) { |
| return substitutions.getMetadata(depth, index); |
| }, |
| [&substitutions](const Metadata *type, unsigned index) { |
| return substitutions.getWitnessTable(type, index); |
| }).getType().getMetadata(); |
| continue; |
| } |
| |
| // If we do have an argument for this parameter, it might be that |
| // the right-hand side is itself a generic parameter, which means |
| // we have a same-type constraint A == B where A is already filled in. |
| auto rhsParam = demangleToGenericParamRef(req.getMangledTypeName()); |
| if (!rhsParam) |
| continue; |
| |
| auto rhsFlatIndex = |
| _depthIndexToFlatIndex(rhsParam->first, rhsParam->second, |
| genericParamCounts); |
| if (!rhsFlatIndex || *rhsFlatIndex >= allGenericArgs.size()) |
| continue; |
| |
| if (allGenericArgs[*rhsFlatIndex] || !allGenericArgs[*lhsFlatIndex]) |
| continue; |
| |
| allGenericArgs[*rhsFlatIndex] = allGenericArgs[*lhsFlatIndex]; |
| } |
| } |
| |
| struct InitializeDynamicReplacementLookup { |
| InitializeDynamicReplacementLookup() { |
| initializeDynamicReplacementLookup(); |
| } |
| }; |
| |
| SWIFT_ALLOWED_RUNTIME_GLOBAL_CTOR_BEGIN |
| static InitializeDynamicReplacementLookup initDynamicReplacements; |
| SWIFT_ALLOWED_RUNTIME_GLOBAL_CTOR_END |
| |
| void DynamicReplacementDescriptor::enableReplacement() const { |
| auto *chainRoot = const_cast<DynamicReplacementChainEntry *>( |
| replacedFunctionKey->root.get()); |
| |
| // Make sure this entry is not already enabled. |
| // This does not work until we make sure that when a dynamic library is |
| // unloaded all descriptors are removed. |
| #if 0 |
| for (auto *curr = chainRoot; curr != nullptr; curr = curr->next) { |
| if (curr == chainEntry.get()) { |
| swift::swift_abortDynamicReplacementEnabling(); |
| } |
| } |
| #endif |
| |
| // Unlink the previous entry if we are not chaining. |
| if (!shouldChain() && chainRoot->next) { |
| auto *previous = chainRoot->next; |
| chainRoot->next = previous->next; |
| //chainRoot->implementationFunction = previous->implementationFunction; |
| swift_ptrauth_copy( |
| reinterpret_cast<void **>(&chainRoot->implementationFunction), |
| reinterpret_cast<void *const *>(&previous->implementationFunction), |
| replacedFunctionKey->getExtraDiscriminator()); |
| } |
| |
| // First populate the current replacement's chain entry. |
| auto *currentEntry = |
| const_cast<DynamicReplacementChainEntry *>(chainEntry.get()); |
| // currentEntry->implementationFunction = chainRoot->implementationFunction; |
| swift_ptrauth_copy( |
| reinterpret_cast<void **>(¤tEntry->implementationFunction), |
| reinterpret_cast<void *const *>(&chainRoot->implementationFunction), |
| replacedFunctionKey->getExtraDiscriminator()); |
| |
| currentEntry->next = chainRoot->next; |
| |
| // Link the replacement entry. |
| chainRoot->next = chainEntry.get(); |
| // chainRoot->implementationFunction = replacementFunction.get(); |
| swift_ptrauth_init( |
| reinterpret_cast<void **>(&chainRoot->implementationFunction), |
| reinterpret_cast<void *>(replacementFunction.get()), |
| replacedFunctionKey->getExtraDiscriminator()); |
| } |
| |
| void DynamicReplacementDescriptor::disableReplacement() const { |
| const auto *chainRoot = replacedFunctionKey->root.get(); |
| auto *thisEntry = |
| const_cast<DynamicReplacementChainEntry *>(chainEntry.get()); |
| |
| // Find the entry previous to this one. |
| auto *prev = chainRoot; |
| while (prev && prev->next != thisEntry) |
| prev = prev->next; |
| if (!prev) { |
| swift::swift_abortDynamicReplacementDisabling(); |
| return; |
| } |
| |
| // Unlink this entry. |
| auto *previous = const_cast<DynamicReplacementChainEntry *>(prev); |
| previous->next = thisEntry->next; |
| // previous->implementationFunction = thisEntry->implementationFunction; |
| swift_ptrauth_copy( |
| reinterpret_cast<void **>(&previous->implementationFunction), |
| reinterpret_cast<void *const *>(&thisEntry->implementationFunction), |
| replacedFunctionKey->getExtraDiscriminator()); |
| } |
| |
| /// An automatic dymamic replacement entry. |
| namespace { |
| class AutomaticDynamicReplacementEntry { |
| RelativeDirectPointer<DynamicReplacementScope, false> replacementScope; |
| uint32_t flags; |
| |
| public: |
| void enable() const { replacementScope->enable(); } |
| |
| uint32_t getFlags() { return flags; } |
| }; |
| |
| /// A list of automatic dynamic replacement scopes. |
| class AutomaticDynamicReplacements |
| : private swift::ABI::TrailingObjects<AutomaticDynamicReplacements, |
| AutomaticDynamicReplacementEntry> { |
| uint32_t flags; |
| uint32_t numScopes; |
| |
| using TrailingObjects = |
| swift::ABI::TrailingObjects<AutomaticDynamicReplacements, |
| AutomaticDynamicReplacementEntry>; |
| friend TrailingObjects; |
| |
| llvm::ArrayRef<AutomaticDynamicReplacementEntry> |
| getReplacementEntries() const { |
| return { |
| this->template getTrailingObjects<AutomaticDynamicReplacementEntry>(), |
| numScopes}; |
| } |
| |
| public: |
| void enableReplacements() const { |
| for (auto &replacementEntry : getReplacementEntries()) |
| replacementEntry.enable(); |
| } |
| |
| uint32_t getNumScopes() const { return numScopes; } |
| }; |
| |
| /// A map from original to replaced opaque type descriptor of a some type. |
| class DynamicReplacementSomeDescriptor { |
| RelativeIndirectablePointer< |
| const OpaqueTypeDescriptor, false, int32_t, |
| TargetSignedPointer<InProcess, OpaqueTypeDescriptor * |
| __ptrauth_swift_type_descriptor>> |
| originalOpaqueTypeDesc; |
| RelativeDirectPointer<const OpaqueTypeDescriptor, false> |
| replacementOpaqueTypeDesc; |
| |
| public: |
| void enable(const Mutex &lock) const { |
| opaqueTypeMappings.get().insert(originalOpaqueTypeDesc.get(), |
| replacementOpaqueTypeDesc.get(), lock); |
| } |
| }; |
| |
| /// A list of dynamic replacements of some types. |
| class AutomaticDynamicReplacementsSome |
| : private swift::ABI::TrailingObjects<AutomaticDynamicReplacementsSome, |
| DynamicReplacementSomeDescriptor> { |
| uint32_t flags; |
| uint32_t numEntries; |
| using TrailingObjects = |
| swift::ABI::TrailingObjects<AutomaticDynamicReplacementsSome, |
| DynamicReplacementSomeDescriptor>; |
| friend TrailingObjects; |
| |
| llvm::ArrayRef<DynamicReplacementSomeDescriptor> |
| getReplacementEntries() const { |
| return { |
| this->template getTrailingObjects<DynamicReplacementSomeDescriptor>(), |
| numEntries}; |
| } |
| |
| public: |
| void enableReplacements(const Mutex &lock) const { |
| for (auto &replacementEntry : getReplacementEntries()) |
| replacementEntry.enable(lock); |
| } |
| uint32_t getNumEntries() const { return numEntries; } |
| }; |
| |
| } // anonymous namespace |
| |
| void swift::addImageDynamicReplacementBlockCallback( |
| const void *replacements, uintptr_t replacementsSize, |
| const void *replacementsSome, uintptr_t replacementsSomeSize) { |
| |
| auto *automaticReplacements = |
| reinterpret_cast<const AutomaticDynamicReplacements *>(replacements); |
| |
| const AutomaticDynamicReplacementsSome *someReplacements = nullptr; |
| if (replacementsSomeSize) { |
| someReplacements = |
| reinterpret_cast<const AutomaticDynamicReplacementsSome *>( |
| replacementsSome); |
| } |
| |
| auto sizeOfCurrentEntry = sizeof(AutomaticDynamicReplacements) + |
| (automaticReplacements->getNumScopes() * |
| sizeof(AutomaticDynamicReplacementEntry)); |
| auto sizeOfCurrentSomeEntry = |
| replacementsSomeSize == 0 |
| ? 0 |
| : sizeof(AutomaticDynamicReplacementsSome) + |
| (someReplacements->getNumEntries() * |
| sizeof(DynamicReplacementSomeDescriptor)); |
| |
| auto &lock = DynamicReplacementLock.get(); |
| lock.withLock([&] { |
| auto endOfAutomaticReplacements = |
| ((const char *)automaticReplacements) + replacementsSize; |
| while (((const char *)automaticReplacements) < endOfAutomaticReplacements) { |
| automaticReplacements->enableReplacements(); |
| automaticReplacements = |
| reinterpret_cast<const AutomaticDynamicReplacements *>( |
| ((const char *)automaticReplacements) + sizeOfCurrentEntry); |
| if ((const char*)automaticReplacements < endOfAutomaticReplacements) |
| sizeOfCurrentEntry = sizeof(AutomaticDynamicReplacements) + |
| (automaticReplacements->getNumScopes() * |
| sizeof(AutomaticDynamicReplacementEntry)); |
| } |
| if (!replacementsSomeSize) |
| return; |
| auto endOfSomeReplacements = |
| ((const char *)someReplacements) + replacementsSomeSize; |
| while (((const char *)someReplacements) < endOfSomeReplacements) { |
| someReplacements->enableReplacements(lock); |
| someReplacements = |
| reinterpret_cast<const AutomaticDynamicReplacementsSome *>( |
| ((const char *)someReplacements) + sizeOfCurrentSomeEntry); |
| if ((const char*) someReplacements < endOfSomeReplacements) |
| sizeOfCurrentSomeEntry = sizeof(AutomaticDynamicReplacementsSome) + |
| (someReplacements->getNumEntries() * |
| sizeof(DynamicReplacementSomeDescriptor)); |
| } |
| }); |
| } |
| |
| void swift::swift_enableDynamicReplacementScope( |
| const DynamicReplacementScope *scope) { |
| scope = swift_auth_data_non_address( |
| scope, SpecialPointerAuthDiscriminators::DynamicReplacementScope); |
| DynamicReplacementLock.get().withLock([=] { scope->enable(); }); |
| } |
| |
| void swift::swift_disableDynamicReplacementScope( |
| const DynamicReplacementScope *scope) { |
| scope = swift_auth_data_non_address( |
| scope, SpecialPointerAuthDiscriminators::DynamicReplacementScope); |
| DynamicReplacementLock.get().withLock([=] { scope->disable(); }); |
| } |
| #define OVERRIDE_METADATALOOKUP COMPATIBILITY_OVERRIDE |
| #include "CompatibilityOverride.def" |