blob: d8344b7e68531990eac4dbd9decf34ab2529740f [file] [log] [blame]
//===--- 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/LLVM.h"
#include "swift/Basic/Lazy.h"
#include "swift/Demangling/Demangler.h"
#include "swift/Demangling/TypeDecoder.h"
#include "swift/Reflection/Records.h"
#include "swift/Runtime/Casting.h"
#include "swift/Runtime/Concurrent.h"
#include "swift/Runtime/HeapObject.h"
#include "swift/Runtime/Metadata.h"
#include "swift/Strings.h"
#include "llvm/ADT/DenseMap.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>
#endif
/// Produce a Demangler value suitable for resolving runtime type metadata
/// strings.
static Demangler getDemanglerForRuntimeTypeResolution() {
Demangler dem;
// 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.
dem.setSymbolicReferenceResolver([&](int32_t offset,
const void *base) -> NodePointer {
auto absolute_addr = (uintptr_t)detail::applyRelativeOffset(base, offset);
auto reference = dem.createNode(Node::Kind::SymbolicReference, absolute_addr);
auto type = dem.createNode(Node::Kind::Type);
type->addChild(reference, dem);
return type;
});
return 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:
std::string Name;
const TypeContextDescriptor *Description;
public:
NominalTypeDescriptorCacheEntry(const llvm::StringRef name,
const TypeContextDescriptor *description)
: Name(name.str()), Description(description) {}
const TypeContextDescriptor *getDescription() {
return Description;
}
int compareWithKey(llvm::StringRef aName) const {
return aName.compare(Name);
}
template <class... T>
static size_t getExtraAllocationSize(T &&... ignored) {
return 0;
}
};
} // end anonymous namespace
struct TypeMetadataPrivateState {
ConcurrentMap<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::addImageTypeMetadataRecordBlockCallback(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::swift_registerTypeMetadataRecords(const TypeMetadataRecord *begin,
const TypeMetadataRecord *end) {
auto &T = TypeMetadataRecords.get();
_registerTypeMetadataRecords(T, begin, end);
}
static const TypeContextDescriptor *
_findNominalTypeDescriptor(Demangle::NodePointer node,
Demangle::Demangler &Dem);
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 && node->getKind() == Demangle::Node::Kind::SymbolicReference) {
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);
auto extendedContextMangledName = extension->getMangledExtendedContext();
auto demangler = getDemanglerForRuntimeTypeResolution();
auto extendedContextDemangled =
demangler.demangleType(extendedContextMangledName);
if (!extendedContextDemangled)
return false;
if (extendedContextDemangled->getKind() == Node::Kind::Type) {
if (extendedContextDemangled->getNumChildren() < 1)
return false;
extendedContextDemangled = extendedContextDemangled->getChild(0);
}
extendedContextDemangled =
stripGenericArgsFromContextNode(extendedContextDemangled, demangler);
auto extendedDescriptorFromNode =
_findNominalTypeDescriptor(extendedContextNode, demangler);
auto extendedDescriptorFromDemangled =
_findNominalTypeDescriptor(extendedContextDemangled, demangler);
if (!extendedDescriptorFromNode || !extendedDescriptorFromDemangled ||
!equalContexts(extendedDescriptorFromNode,
extendedDescriptorFromDemangled))
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;
}
default:
if (auto type = llvm::dyn_cast<TypeContextDescriptor>(context)) {
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:
if (type->getKind() != ContextDescriptorKind::Struct
&& !type->getTypeContextDescriptorFlags().isCTag())
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 (!type->getTypeContextDescriptorFlags().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 (nameNode->getText() != type->getSynthesizedDeclRelatedEntityTag())
return false;
nameNode = nameNode->getChild(0);
} else if (type->isSynthesizedRelatedEntity()) {
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() != type->Name.get())
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 TypeContextDescriptor *
_searchTypeMetadataRecords(TypeMetadataPrivateState &T,
Demangle::NodePointer node) {
for (auto &section : T.SectionsToScan.snapshot()) {
for (const auto &record : section) {
if (auto ntd = record.getTypeContextDescriptor()) {
if (_contextDescriptorMatchesMangling(ntd, node)) {
return ntd;
}
}
}
}
return nullptr;
}
static const TypeContextDescriptor *
_findNominalTypeDescriptor(Demangle::NodePointer node,
Demangle::Demangler &Dem) {
const TypeContextDescriptor *foundNominal = nullptr;
auto &T = TypeMetadataRecords.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::SymbolicReference)
return cast<TypeContextDescriptor>(
(const ContextDescriptor *)symbolicNode->getIndex());
auto mangledName =
Demangle::mangleNode(node,
[&](const void *context) -> NodePointer {
return _buildDemanglingForContext(
(const ContextDescriptor *) context,
{}, false, Dem);
});
// Look for an existing entry.
// Find the bucket for the metadata entry.
if (auto Value = T.NominalCache.find(mangledName))
return Value->getDescription();
// Check type metadata records
foundNominal = _searchTypeMetadataRecords(T, node);
// Check protocol conformances table. Note that this has no support for
// resolving generic types yet.
if (!foundNominal)
foundNominal = _searchConformancesByMangledTypeName(node);
if (foundNominal) {
T.NominalCache.getOrInsert(mangledName, foundNominal);
}
return foundNominal;
}
#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:
std::string Name;
const ProtocolDescriptor *Description;
public:
ProtocolDescriptorCacheEntry(const llvm::StringRef name,
const ProtocolDescriptor *description)
: Name(name.str()), Description(description) {}
const ProtocolDescriptor *getDescription() { return Description; }
int compareWithKey(llvm::StringRef aName) const {
return aName.compare(Name);
}
template <class... T>
static size_t getExtraAllocationSize(T &&... ignored) {
return 0;
}
};
struct ProtocolMetadataPrivateState {
ConcurrentMap<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::addImageProtocolsBlockCallback(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::swift_registerProtocols(const ProtocolRecord *begin,
const ProtocolRecord *end) {
auto &C = Protocols.get();
_registerProtocols(C, begin, end);
}
static const ProtocolDescriptor *
_searchProtocolRecords(ProtocolMetadataPrivateState &C,
const llvm::StringRef protocolName){
for (auto &section : C.SectionsToScan.snapshot()) {
for (const auto &record : section) {
if (auto protocol = record.Protocol.getPointer()) {
// Drop the "S$" prefix from the protocol record. It's not used in
// the type itself.
StringRef foundProtocolName = protocol->Name;
assert(foundProtocolName.startswith("$S"));
foundProtocolName = foundProtocolName.drop_front(2);
if (foundProtocolName == protocolName)
return protocol;
}
}
}
return nullptr;
}
static const ProtocolDescriptor *
_findProtocolDescriptor(llvm::StringRef mangledName) {
const ProtocolDescriptor *foundProtocol = nullptr;
auto &T = Protocols.get();
// Look for an existing entry.
// Find the bucket for the metadata entry.
if (auto Value = T.ProtocolCache.find(mangledName))
return Value->getDescription();
// Check type metadata records
foundProtocol = _searchProtocolRecords(T, mangledName);
if (foundProtocol) {
T.ProtocolCache.getOrInsert(mangledName, foundProtocol);
}
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;
}
};
class StaticFieldSection {
const void *Begin;
const void *End;
public:
StaticFieldSection(const void *begin, const void *end)
: Begin(begin), End(end) {}
FieldDescriptorIterator begin() const {
return FieldDescriptorIterator(Begin, End);
}
FieldDescriptorIterator end() const {
return FieldDescriptorIterator(End, End);
}
};
class DynamicFieldSection {
const FieldDescriptor **Begin;
const FieldDescriptor **End;
public:
DynamicFieldSection(const FieldDescriptor **fields, size_t size)
: Begin(fields), End(fields + size) {}
const FieldDescriptor **begin() const { return Begin; }
const FieldDescriptor **end() const { return End; }
};
struct FieldCacheState {
ConcurrentMap<FieldDescriptorCacheEntry> FieldCache;
ConcurrentReadableArray<StaticFieldSection> StaticSections;
ConcurrentReadableArray<DynamicFieldSection> DynamicSections;
FieldCacheState() {
initializeTypeFieldLookup();
}
};
static Lazy<FieldCacheState> FieldCache;
} // namespace
void swift::swift_registerFieldDescriptors(const FieldDescriptor **records,
size_t size) {
auto &cache = FieldCache.get();
cache.DynamicSections.push_back({records, size});
}
void swift::addImageTypeFieldDescriptorBlockCallback(const void *recordsBegin,
uintptr_t size) {
auto sectionBytes = reinterpret_cast<const char *>(recordsBegin);
auto recordsEnd = reinterpret_cast<const void *>(sectionBytes + size);
// Field cache should always be sufficiently initialized by this point.
auto &cache = FieldCache.unsafeGetAlreadyInitialized();
cache.StaticSections.push_back({recordsBegin, recordsEnd});
}
#pragma mark Metadata lookup via mangled name
#if SWIFT_OBJC_INTEROP
/// For a mangled node that refers to an Objective-C class or protocol,
/// return the class or protocol name.
static Optional<StringRef> getObjCClassOrProtocolName(
const Demangle::NodePointer &node) {
if (node->getKind() != Demangle::Node::Kind::Class &&
node->getKind() != Demangle::Node::Kind::Protocol)
return None;
if (node->getNumChildren() != 2)
return None;
// Check whether we have the __ObjC module.
auto moduleNode = node->getChild(0);
if (moduleNode->getKind() != Demangle::Node::Kind::Module ||
moduleNode->getText() != MANGLING_MODULE_OBJC)
return None;
// Check whether we have an identifier.
auto nameNode = node->getChild(1);
if (nameNode->getKind() != Demangle::Node::Kind::Identifier)
return None;
return nameNode->getText();
}
#endif
Optional<unsigned> swift::_depthIndexToFlatIndex(
unsigned depth, unsigned index,
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,
std::vector<unsigned> &genericParamCounts) {
// Once we hit a non-generic descriptor, we're done.
if (!descriptor->isGeneric()) return false;
// Recurse to record the parent context's generic parameters.
if (auto parent = descriptor->Parent.get())
(void)_gatherGenericParameterCounts(parent, genericParamCounts);
// Record a new level of generic parameters if the count exceeds the
// previous count.
auto myCount =
descriptor->getGenericContext()->getGenericContextHeader().NumParams;
if (genericParamCounts.empty() || myCount > genericParamCounts.back()) {
genericParamCounts.push_back(myCount);
return true;
}
return false;
}
namespace {
/// Find the offset of the protocol requirement for an associated type with
/// the given name in the given protocol descriptor.
Optional<unsigned> findAssociatedTypeByName(const ProtocolDescriptor *protocol,
StringRef name) {
// Only Swift protocols have associated types.
if (!protocol->Flags.isSwift()) return None;
// 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()) {
auto split = associatedTypeNames.split(' ');
if (split.first == name) {
found = true;
break;
}
++matchingAssocTypeIdx;
associatedTypeNames = split.second;
}
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;
const ProtocolRequirement *requirements = protocol->Requirements.get();
for (unsigned reqIdx = 0; reqIdx != numRequirements; ++reqIdx) {
if (requirements[reqIdx].Flags.getKind() !=
ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction)
continue;
if (currentAssocTypeIdx == matchingAssocTypeIdx)
return reqIdx + WitnessTableFirstRequirementOffset;
++currentAssocTypeIdx;
}
swift_runtime_unreachable("associated type names don't line up");
}
/// Constructs metadata by decoding a mangled type name, for use with
/// \c TypeDecoder.
class DecodedMetadataBuilder {
public:
/// Callback used to handle the substitution of a generic parameter for
/// its metadata.
using SubstGenericParameterFn =
std::function<const Metadata *(unsigned depth, unsigned index)>;
/// Callback used to handle the lookup of dependent member types.
using LookupDependentMemberFn =
std::function<const Metadata *(const Metadata *base, StringRef assocType,
const ProtocolDescriptor *protocol)>;
private:
/// The demangler we'll use when building new nodes.
Demangler &demangler;
/// Substitute generic parameters.
SubstGenericParameterFn substGenericParameter;
/// Lookup dependent member types.
LookupDependentMemberFn lookupDependentMember;
/// Ownership information related to the metadata we are trying to lookup.
TypeReferenceOwnership ReferenceOwnership;
public:
DecodedMetadataBuilder(Demangler &demangler,
SubstGenericParameterFn substGenericParameter
= nullptr,
LookupDependentMemberFn lookupDependentMember
= nullptr)
: demangler(demangler),
substGenericParameter(substGenericParameter),
lookupDependentMember(lookupDependentMember) { }
using BuiltType = const Metadata *;
struct BuiltNominalTypeDecl :
llvm::PointerUnion<const TypeContextDescriptor *, const Metadata *>
{
using PointerUnion::PointerUnion;
explicit operator bool() const { return !isNull(); }
};
using BuiltProtocolDecl = const ProtocolDescriptor *;
Demangle::NodeFactory &getNodeFactory() { return demangler; }
BuiltNominalTypeDecl createNominalTypeDecl(
const Demangle::NodePointer &node) const {
#if SWIFT_OBJC_INTEROP
// If we have an Objective-C class name, call into the Objective-C
// runtime to find them.
if (auto objcClassName = getObjCClassOrProtocolName(node)) {
auto objcClass = objc_getClass(objcClassName->str().c_str());
return swift_getObjCClassMetadata((const ClassMetadata *)objcClass);
}
#endif
// Look for a nominal type descriptor based on its mangled name.
return _findNominalTypeDescriptor(node, demangler);
}
BuiltProtocolDecl createProtocolDecl(
const Demangle::NodePointer &node) const {
#if SWIFT_OBJC_INTEROP
// If we have an Objective-C class name, call into the Objective-C
// runtime to find them.
if (auto objcProtocolName = getObjCClassOrProtocolName(node)) {
return (ProtocolDescriptor *)objc_getProtocol(
objcProtocolName->str().c_str());
}
#endif
auto mangledName = Demangle::mangleNode(node);
// Look for a Swift protocol with this mangled name.
if (auto protocol = _findProtocolDescriptor(mangledName))
return protocol;
#if SWIFT_OBJC_INTEROP
// Look for a Swift-defined @objc protocol with the Swift 3 mangling that
// is used for Objective-C entities.
std::string objcMangledName =
"_TtP" + mangledName.substr(0, mangledName.size()-1) + "_";
if (auto protocol = objc_getProtocol(objcMangledName.c_str()))
return (ProtocolDescriptor *)protocol;
#endif
return nullptr;
}
BuiltType createNominalType(BuiltNominalTypeDecl 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);
}
BuiltType createBoundGenericType(BuiltNominalTypeDecl metadataOrTypeDecl,
const ArrayRef<BuiltType> genericArgs,
const BuiltType parent) const {
// If we already have metadata, return it.
if (auto metadata = metadataOrTypeDecl.dyn_cast<const Metadata *>())
return metadata;
auto typeDecl = metadataOrTypeDecl.get<const TypeContextDescriptor *>();
// Figure out the various levels of generic parameters we have in
// this type.
std::vector<unsigned> genericParamCounts;
bool innermostIsGeneric;
// If we have no parent given, try to form the whole type in one go.
if (!parent) {
innermostIsGeneric = !genericArgs.empty();
if (innermostIsGeneric) {
genericParamCounts.push_back(genericArgs.size());
}
// Otherwise, we'll need to steal the generic arguments from the parent
// type to build a nested type.
} else {
innermostIsGeneric = _gatherGenericParameterCounts(typeDecl,
genericParamCounts);
}
bool isGeneric = !genericParamCounts.empty();
// Gather the generic arguments.
std::vector<const void *> allGenericArgsVec;
ArrayRef<const void *> allGenericArgs;
// If the innermost type is generic, we need to gather arguments and
// check requirements.
if (innermostIsGeneric) {
// If no generic arguments were provided at this level, fail.
if (genericArgs.empty()) return BuiltType();
unsigned startParamIndex;
if (genericParamCounts.size() > 1) {
// When there is more than one level of generic parameters, copy all of
// the key type parameters from the parent (but not any of the other
// requirements, e.g., witness tables are excluded).
auto parentGenericArgs = parent->getGenericArgs();
auto parentGenericParams =
typeDecl->Parent->getGenericContext()->getGenericParams();
unsigned parentArgIndex = 0;
for (const auto &parentGenericParam : parentGenericParams) {
if (parentGenericParam.hasKeyArgument())
allGenericArgsVec.push_back(parentGenericArgs[parentArgIndex++]);
}
startParamIndex = parentGenericParams.size();
} else {
startParamIndex = 0;
}
// If we have the wrong number of generic arguments, fail.
auto genericContext = typeDecl->getGenericContext();
auto genericParams = genericContext->getGenericParams();
if (genericArgs.size() != genericParamCounts.back() - startParamIndex)
return BuiltType();
// Add generic arguments for the key parameters at this level.
unsigned genericArgIndex = 0;
for (const auto &genericParam : genericParams.slice(startParamIndex)) {
if (genericParam.hasKeyArgument())
allGenericArgsVec.push_back(genericArgs[genericArgIndex++]);
}
// Check whether the generic requirements are satisfied, collecting
// any extra arguments we need for the instantiation function.
bool failed =
_checkGenericRequirements(genericContext->getGenericRequirements(),
allGenericArgsVec,
[&](unsigned flatIndex) -> BuiltType {
// FIXME: Wrong for same-type-to-concrete
// constraints.
if (flatIndex < allGenericArgsVec.size())
return static_cast<BuiltType>(allGenericArgsVec[flatIndex]);
return BuiltType();
},
[&](unsigned depth, unsigned index) -> BuiltType {
auto flatIndex = _depthIndexToFlatIndex(depth, index,
genericParamCounts);
// FIXME: Wrong for same-type-to-concrete
// constraints.
if (flatIndex && *flatIndex < allGenericArgsVec.size())
return static_cast<BuiltType>(allGenericArgsVec[*flatIndex]);
return BuiltType();
});
if (failed)
return BuiltType();
// If we still have the wrong number of generic arguments, this is
// some kind of metadata mismatch.
// FIXME: Fail silently? Complain loudly?
assert(typeDecl->getGenericContextHeader().getNumArguments() ==
allGenericArgsVec.size());
allGenericArgs = allGenericArgsVec;
} else {
// If generic arguments were provided at this level, fail.
if (!genericArgs.empty()) return BuiltType();
// If this is a generic context, get all of the arguments from our
// parent.
if (isGeneric) {
if (!parent) return BuiltType();
auto numGenericArgs =
typeDecl->getGenericContextHeader().getNumArguments();
auto parentGenericArgs =
reinterpret_cast<const void * const *>(parent->getGenericArgs());
allGenericArgs =
llvm::makeArrayRef(parentGenericArgs, numGenericArgs);
}
}
// Call the access function.
auto accessFunction = typeDecl->getAccessFunction();
if (!accessFunction) return BuiltType();
return accessFunction(MetadataState::Complete, allGenericArgs).Value;
}
BuiltType createBuiltinType(StringRef mangledName) const {
#define BUILTIN_TYPE(Symbol, _) \
if (mangledName.equals(#Symbol)) \
return &METADATA_SYM(Symbol).base;
#include "swift/Runtime/BuiltinTypes.def"
return BuiltType();
}
BuiltType createMetatypeType(BuiltType instance, bool wasAbstract) const {
return swift_getMetatypeMetadata(instance);
}
BuiltType createExistentialMetatypeType(BuiltType instance) const {
return swift_getExistentialMetatypeMetadata(instance);
}
BuiltType createProtocolCompositionType(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->Flags.getClassConstraint()
== ProtocolClassConstraint::Class) {
classConstraint = ProtocolClassConstraint::Class;
break;
}
}
}
return swift_getExistentialTypeMetadata(classConstraint, superclass,
protocols.size(), protocols.data());
}
BuiltType createGenericTypeParameterType(unsigned depth,
unsigned index) const {
// Use the callback, when provided.
if (substGenericParameter)
return substGenericParameter(depth, index);
return BuiltType();
}
BuiltType createFunctionType(
ArrayRef<Demangle::FunctionParam<BuiltType>> params,
BuiltType result, FunctionTypeFlags flags) const {
std::vector<BuiltType> paramTypes;
std::vector<uint32_t> paramFlags;
// Fill in the parameters.
paramTypes.reserve(params.size());
if (flags.hasParameterFlags())
paramFlags.reserve(params.size());
for (const auto &param : 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);
}
BuiltType createTupleType(ArrayRef<BuiltType> elements,
std::string labels,
bool variadic) const {
// TODO: 'variadic' should no longer exist
auto flags = TupleTypeFlags().withNumElements(elements.size());
if (!labels.empty())
flags = flags.withNonConstantLabels(true);
return swift_getTupleTypeMetadata(MetadataState::Complete,
flags, elements.data(),
labels.empty() ? nullptr : labels.c_str(),
/*proposedWitnesses=*/nullptr).Value;
}
BuiltType createDependentMemberType(StringRef name, BuiltType base,
BuiltProtocolDecl protocol) const {
if (lookupDependentMember)
return lookupDependentMember(base, name, protocol);
return BuiltType();
}
BuiltType createUnownedStorageType(BuiltType base) {
ReferenceOwnership.setUnowned();
return base;
}
BuiltType createUnmanagedStorageType(BuiltType base) {
ReferenceOwnership.setUnmanaged();
return base;
}
BuiltType createWeakStorageType(BuiltType base) {
ReferenceOwnership.setWeak();
return base;
}
BuiltType createSILBoxType(BuiltType base) const {
// FIXME: Implement.
return BuiltType();
}
TypeReferenceOwnership getReferenceOwnership() const {
return ReferenceOwnership;
}
};
}
TypeInfo
swift::_getTypeByMangledName(StringRef typeName,
SubstGenericParameterFn substGenericParam) {
auto demangler = getDemanglerForRuntimeTypeResolution();
NodePointer node;
// Check whether this is the convenience syntax "ModuleName.ClassName".
auto getDotPosForConvenienceSyntax = [&]() -> size_t {
size_t dotPos = typeName.find('.');
if (dotPos == llvm::StringRef::npos)
return llvm::StringRef::npos;
if (typeName.find('.', dotPos + 1) != llvm::StringRef::npos)
return llvm::StringRef::npos;
if (typeName.find('\1') != llvm::StringRef::npos)
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.demangleType(typeName);
if (!node)
return TypeInfo();
}
DecodedMetadataBuilder builder(demangler, substGenericParam,
[](const Metadata *base, StringRef assocType,
const ProtocolDescriptor *protocol) -> const Metadata * {
// Look for a conformance of the base type to the protocol.
auto witnessTable = swift_conformsToProtocol(base, protocol);
if (!witnessTable) return nullptr;
// Look for the named associated type within the protocol.
auto assocTypeReqIndex = findAssociatedTypeByName(protocol, assocType);
if (!assocTypeReqIndex) return nullptr;
// Call the associated type access function.
// TODO: can we just request abstract metadata? If so, do we have
// a responsibility to try to finish it later?
return ((AssociatedTypeAccessFunction * const *)witnessTable)[*assocTypeReqIndex]
(MetadataState::Complete, base, witnessTable).Value;
});
auto type = Demangle::decodeMangledType(builder, node);
return {type, builder.getReferenceOwnership()};
}
static const Metadata * _Nullable
swift_getTypeByMangledNameImpl(const char *typeNameStart, size_t typeNameLength,
size_t numberOfLevels,
size_t *parametersPerLevel,
const Metadata * const *flatSubstitutions) {
llvm::StringRef typeName(typeNameStart, typeNameLength);
return _getTypeByMangledName(typeName,
[&](unsigned depth, unsigned index) -> const Metadata * {
if (depth >= numberOfLevels)
return nullptr;
if (index >= parametersPerLevel[depth])
return nullptr;
unsigned flatIndex = index;
for (unsigned i = 0; i < depth; ++i)
flatIndex += parametersPerLevel[i];
return flatSubstitutions[flatIndex];
});
}
struct swift_closure {
void *fptr;
HeapObject *context;
};
SWIFT_RUNTIME_STDLIB_API SWIFT_CC(swift) swift_closure
MANGLE_SYM(s20_playgroundPrintHookySScSgvg)();
static bool _shouldReportMissingReflectionMetadataWarnings() {
// Missing metadata warnings noise up playground sessions and aren't really
// actionable in playground contexts. If we're running in a playground,
// suppress warnings.
//
// Guesstimate whether we're in a playground by looking at the
// _playgroundPrintHook variable in the standard library, which is set during
// playground execution.
auto hook = MANGLE_SYM(s20_playgroundPrintHookySScSgvg)();
if (hook.fptr) {
swift_release(hook.context);
return false;
} else {
return true;
}
}
/// Raise a warning about reflection metadata that could not be found
/// at runtime. This is usually mostly harmless, but it's good to alert
/// users that it happens.
static void
missing_reflection_metadata_warning(const char *fmt, ...) {
bool shouldWarn =
SWIFT_LAZY_CONSTANT(_shouldReportMissingReflectionMetadataWarnings());
if (!shouldWarn)
return;
va_list args;
va_start(args, fmt);
warningv(0, fmt, args);
}
void swift::swift_getFieldAt(
const Metadata *base, unsigned index,
void (*callback)(const char *name, const Metadata *type, void *ctx), void *callbackCtx) {
swift::_swift_getFieldAt(base, index, [&] (llvm::StringRef name, FieldType fieldInfo) { callback(name.data(), fieldInfo.getType(), callbackCtx); });
}
void swift::_swift_getFieldAt(
const Metadata *base, unsigned index,
std::function<void(llvm::StringRef name, FieldType fieldInfo)>
callback) {
auto *baseDesc = base->getTypeContextDescriptor();
if (!baseDesc)
return;
auto getFieldAt = [&](const FieldDescriptor &descriptor) {
auto &field = descriptor.getFields()[index];
auto name = field.getFieldName(0);
// Enum cases don't always have types.
if (!field.hasMangledTypeName()) {
callback(name, FieldType().withIndirect(field.isIndirectCase()));
return;
}
std::vector<const ContextDescriptor *> descriptorPath;
{
const auto *parent = reinterpret_cast<
const ContextDescriptor *>(baseDesc);
while (parent) {
if (parent->isGeneric())
descriptorPath.push_back(parent);
parent = parent->Parent.get();
}
}
auto typeName = field.getMangledTypeName(0);
auto typeInfo = _getTypeByMangledName(
typeName,
[&](unsigned depth, unsigned index) -> const Metadata * {
if (depth >= descriptorPath.size())
return nullptr;
unsigned currentDepth = 0;
unsigned flatIndex = index;
const ContextDescriptor *currentContext = descriptorPath.back();
for (const auto *context : llvm::reverse(descriptorPath)) {
if (currentDepth >= depth)
break;
flatIndex += context->getNumGenericParams();
currentContext = context;
++currentDepth;
}
if (index >= currentContext->getNumGenericParams())
return nullptr;
return base->getGenericArgs()[flatIndex];
});
// If demangling the type failed, pretend it's an empty type instead with
// a log message.
if (typeInfo == nullptr) {
typeInfo = TypeInfo(&METADATA_SYM(EMPTY_TUPLE_MANGLING), {});
missing_reflection_metadata_warning(
"warning: the Swift runtime was unable to demangle the type "
"of field '%*s'. the mangled type name is '%*s'. this field will "
"show up as an empty tuple in Mirrors\n",
(int)name.size(), name.data(),
(int)typeName.size(), typeName.data());
}
callback(name, FieldType()
.withType(typeInfo)
.withIndirect(field.isIndirectCase())
.withWeak(typeInfo.isWeak()));
};
auto dem = getDemanglerForRuntimeTypeResolution();
auto &cache = FieldCache.get();
auto isRequestedDescriptor = [&](const FieldDescriptor &descriptor) {
assert(descriptor.hasMangledTypeName());
auto mangledName = descriptor.getMangledTypeName(0);
if (!_contextDescriptorMatchesMangling(baseDesc,
dem.demangleType(mangledName)))
return false;
cache.FieldCache.getOrInsert(base, &descriptor);
getFieldAt(descriptor);
return true;
};
// Fast path: If we already have field descriptor cached.
if (auto Value = cache.FieldCache.find(base)) {
getFieldAt(*Value->getDescription());
return;
}
// Otherwise let's try to find it in one of the sections.
for (auto &section : cache.DynamicSections.snapshot()) {
for (const auto *descriptor : section) {
if (isRequestedDescriptor(*descriptor))
return;
}
}
for (const auto &section : cache.StaticSections.snapshot()) {
for (auto &descriptor : section) {
if (isRequestedDescriptor(descriptor))
return;
}
}
// If we failed to find the field descriptor metadata for the type, fall
// back to returning an empty tuple as a standin.
auto typeName = swift_getTypeName(base, /*qualified*/ true);
missing_reflection_metadata_warning(
"warning: the Swift runtime found no field metadata for "
"type '%*s' that claims to be reflectable. Its fields will show up as "
"'unknown' in Mirrors\n",
(int)typeName.length, typeName.data);
callback("unknown",
FieldType()
.withType(TypeInfo(&METADATA_SYM(EMPTY_TUPLE_MANGLING), {}))
.withIndirect(false)
.withWeak(false));
}
#define OVERRIDE_METADATALOOKUP COMPATIBILITY_OVERRIDE
#include "CompatibilityOverride.def"