mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
initialization in-place on demand. Initialize parent metadata references correctly on struct and enum metadata. Also includes several minor improvements related to relative pointers that I was using before deciding to simply switch the parent reference to an absolute reference to get better access patterns. Includes a fix since the earlier commit to make enum metadata writable if they have an unfilled payload size. This didn't show up on Darwin because "constant" is currently unenforced there in global data containing relocations. This patch requires an associated LLDB change which is being submitted in parallel.
305 lines
9.3 KiB
C++
305 lines
9.3 KiB
C++
//===--- 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 "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 <mach-o/dyld.h>
|
|
#include <mach-o/getsect.h>
|
|
#elif defined(__ELF__)
|
|
#include <elf.h>
|
|
#include <link.h>
|
|
#endif
|
|
|
|
#include <dlfcn.h>
|
|
#include <mutex>
|
|
|
|
using namespace swift;
|
|
using namespace Demangle;
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
#include <objc/runtime.h>
|
|
#include <objc/message.h>
|
|
#include <objc/objc.h>
|
|
#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__)
|
|
#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 <class... T>
|
|
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<TypeMetadataCacheEntry> Cache;
|
|
std::vector<TypeMetadataSection> SectionsToScan;
|
|
pthread_mutex_t SectionsToScanLock;
|
|
|
|
TypeMetadataState() {
|
|
SectionsToScan.reserve(16);
|
|
pthread_mutex_init(&SectionsToScanLock, nullptr);
|
|
#if defined(__APPLE__) && defined(__MACH__)
|
|
_initializeCallbacksToInspectDylib();
|
|
#else
|
|
_swift_initializeCallbacksToInspectDylib(
|
|
_addImageTypeMetadataRecordsBlock,
|
|
SWIFT_TYPE_METADATA_SECTION);
|
|
#endif
|
|
}
|
|
};
|
|
|
|
static Lazy<TypeMetadataState> TypeMetadataRecords;
|
|
|
|
static void
|
|
_registerTypeMetadataRecords(TypeMetadataState &T,
|
|
const TypeMetadataRecord *begin,
|
|
const TypeMetadataRecord *end) {
|
|
pthread_mutex_lock(&T.SectionsToScanLock);
|
|
T.SectionsToScan.push_back(TypeMetadataSection{begin, end});
|
|
pthread_mutex_unlock(&T.SectionsToScanLock);
|
|
}
|
|
|
|
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<const TypeMetadataRecord*>(records);
|
|
auto recordsEnd
|
|
= reinterpret_cast<const TypeMetadataRecord*>
|
|
(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<const mach_header_platform *>(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<const ::ClassMetadata *>(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())
|
|
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
|
|
pthread_mutex_lock(&T.SectionsToScanLock);
|
|
foundMetadata = _searchTypeMetadataRecords(T, typeName);
|
|
pthread_mutex_unlock(&T.SectionsToScanLock);
|
|
|
|
// 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<ClassMetadata *>
|
|
(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);
|
|
}
|