//===--- MetadataLookup.cpp - Swift Language Type Name Lookup -------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://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/LLVM.h" #include "swift/Basic/Lazy.h" #include "swift/Runtime/Concurrent.h" #include "swift/Runtime/HeapObject.h" #include "swift/Runtime/Metadata.h" #include "swift/Runtime/Mutex.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/StringExtras.h" #include "Private.h" #if defined(__APPLE__) && defined(__MACH__) #include #include #elif defined(__ELF__) || defined(__ANDROID__) #include #include #endif using namespace swift; using namespace Demangle; #if SWIFT_OBJC_INTEROP #include #include #include #endif #if defined(__APPLE__) && defined(__MACH__) #define SWIFT_TYPE_METADATA_SECTION "__swift2_types" #elif defined(__ELF__) #define SWIFT_TYPE_METADATA_SECTION ".swift2_type_metadata_start" #elif defined(__CYGWIN__) || defined(_MSC_VER) #define SWIFT_TYPE_METADATA_SECTION ".sw2tymd" #endif // Type Metadata Cache. namespace { struct TypeMetadataSection { const TypeMetadataRecord *Begin, *End; const TypeMetadataRecord *begin() const { return Begin; } const TypeMetadataRecord *end() const { return End; } }; struct TypeMetadataCacheEntry { private: std::string Name; const Metadata *Metadata; public: TypeMetadataCacheEntry(const llvm::StringRef name, const ::Metadata *metadata) : Name(name.str()), Metadata(metadata) {} const ::Metadata *getMetadata(void) { return Metadata; } int compareWithKey(llvm::StringRef aName) const { return aName.compare(Name); } template static size_t getExtraAllocationSize(T &&... ignored) { return 0; } }; } #if defined(__APPLE__) && defined(__MACH__) static void _initializeCallbacksToInspectDylib(); #else namespace swift { void _swift_initializeCallbacksToInspectDylib( void (*fnAddImageBlock)(const uint8_t *, size_t), const char *sectionName); } static void _addImageTypeMetadataRecordsBlock(const uint8_t *records, size_t recordsSize); #endif struct TypeMetadataState { ConcurrentMap Cache; std::vector SectionsToScan; Mutex SectionsToScanLock; TypeMetadataState() { SectionsToScan.reserve(16); #if defined(__APPLE__) && defined(__MACH__) _initializeCallbacksToInspectDylib(); #else _swift_initializeCallbacksToInspectDylib( _addImageTypeMetadataRecordsBlock, SWIFT_TYPE_METADATA_SECTION); #endif } }; static Lazy TypeMetadataRecords; static void _registerTypeMetadataRecords(TypeMetadataState &T, const TypeMetadataRecord *begin, const TypeMetadataRecord *end) { ScopedLock guard(T.SectionsToScanLock); T.SectionsToScan.push_back(TypeMetadataSection{begin, end}); } static void _addImageTypeMetadataRecordsBlock(const uint8_t *records, size_t recordsSize) { assert(recordsSize % sizeof(TypeMetadataRecord) == 0 && "weird-sized type metadata section?!"); // If we have a section, enqueue the type metadata for lookup. auto recordsBegin = reinterpret_cast(records); auto recordsEnd = reinterpret_cast (records + recordsSize); // type metadata cache should always be sufficiently initialized by this point. _registerTypeMetadataRecords(TypeMetadataRecords.unsafeGetAlreadyInitialized(), recordsBegin, recordsEnd); } #if defined(__APPLE__) && defined(__MACH__) static void _addImageTypeMetadataRecords(const mach_header *mh, intptr_t vmaddr_slide) { #ifdef __LP64__ using mach_header_platform = mach_header_64; assert(mh->magic == MH_MAGIC_64 && "loaded non-64-bit image?!"); #else using mach_header_platform = mach_header; #endif // Look for a __swift2_types section. unsigned long recordsSize; const uint8_t *records = getsectiondata(reinterpret_cast(mh), SEG_TEXT, SWIFT_TYPE_METADATA_SECTION, &recordsSize); if (!records) return; _addImageTypeMetadataRecordsBlock(records, recordsSize); } static void _initializeCallbacksToInspectDylib() { // Install our dyld callback. // Dyld will invoke this on our behalf for all images that have already // been loaded. _dyld_register_func_for_add_image(_addImageTypeMetadataRecords); } #endif void swift::swift_registerTypeMetadataRecords(const TypeMetadataRecord *begin, const TypeMetadataRecord *end) { auto &T = TypeMetadataRecords.get(); _registerTypeMetadataRecords(T, begin, end); } // copied from ProtocolConformanceRecord::getCanonicalTypeMetadata() template<> const Metadata *TypeMetadataRecord::getCanonicalTypeMetadata() const { switch (getTypeKind()) { case TypeMetadataRecordKind::UniqueDirectType: return getDirectType(); case TypeMetadataRecordKind::NonuniqueDirectType: return swift_getForeignTypeMetadata((ForeignTypeMetadata *)getDirectType()); case TypeMetadataRecordKind::UniqueDirectClass: if (auto *ClassMetadata = static_cast(getDirectType())) return swift_getObjCClassMetadata(ClassMetadata); else return nullptr; default: return nullptr; } } // returns the type metadata for the type named by typeNode const Metadata * swift::_matchMetadataByMangledTypeName(const llvm::StringRef typeName, const Metadata *metadata, const NominalTypeDescriptor *ntd) { if (metadata != nullptr) { assert(ntd == nullptr); ntd = metadata->getNominalTypeDescriptor(); } if (ntd == nullptr || ntd->Name.get() != typeName) return nullptr; // Call the accessor if there is one. if (metadata == nullptr && !ntd->GenericParams.isGeneric()) { if (auto accessFn = ntd->getAccessFunction()) metadata = accessFn(); } return metadata; } // returns the type metadata for the type named by typeName static const Metadata * _searchTypeMetadataRecords(const TypeMetadataState &T, const llvm::StringRef typeName) { unsigned sectionIdx = 0; unsigned endSectionIdx = T.SectionsToScan.size(); const Metadata *foundMetadata = nullptr; for (; sectionIdx < endSectionIdx; ++sectionIdx) { auto §ion = T.SectionsToScan[sectionIdx]; for (const auto &record : section) { if (auto metadata = record.getCanonicalTypeMetadata()) foundMetadata = _matchMetadataByMangledTypeName(typeName, metadata, nullptr); else if (auto ntd = record.getNominalTypeDescriptor()) foundMetadata = _matchMetadataByMangledTypeName(typeName, nullptr, ntd); if (foundMetadata != nullptr) return foundMetadata; } } return nullptr; } static const Metadata * _typeByMangledName(const llvm::StringRef typeName) { const Metadata *foundMetadata = nullptr; auto &T = TypeMetadataRecords.get(); // Look for an existing entry. // Find the bucket for the metadata entry. if (auto Value = T.Cache.find(typeName)) return Value->getMetadata(); // Check type metadata records T.SectionsToScanLock.withLock([&] { foundMetadata = _searchTypeMetadataRecords(T, typeName); }); // Check protocol conformances table. Note that this has no support for // resolving generic types yet. if (!foundMetadata) foundMetadata = _searchConformancesByMangledTypeName(typeName); if (foundMetadata) { T.Cache.getOrInsert(typeName, foundMetadata); } #if SWIFT_OBJC_INTEROP // Check for ObjC class // FIXME does this have any value? any ObjC class with a Swift name // should already be registered as a Swift type. if (foundMetadata == nullptr) { std::string prefixedName("_Tt" + typeName.str()); foundMetadata = reinterpret_cast (objc_lookUpClass(prefixedName.c_str())); } #endif return foundMetadata; } /// Return the type metadata for a given mangled name, used in the /// implementation of _typeByName(). The human readable name returned /// by swift_getTypeName() is non-unique, so we used mangled names /// internally. SWIFT_RUNTIME_EXPORT extern "C" const Metadata * swift_getTypeByMangledName(const char *typeName, size_t typeNameLength) { llvm::StringRef name(typeName, typeNameLength); return _typeByMangledName(name); }