mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
964 lines
30 KiB
C++
964 lines
30 KiB
C++
//===--- GenReflection.cpp - IR generation for nominal type reflection ----===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements IR generation of type metadata for struct/class
|
|
// stored properties and enum cases for use with reflection.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/AST/IRGenOptions.h"
|
|
#include "swift/AST/PrettyStackTrace.h"
|
|
#include "swift/AST/ProtocolConformance.h"
|
|
#include "swift/AST/SubstitutionMap.h"
|
|
#include "swift/IRGen/Linking.h"
|
|
#include "swift/Reflection/MetadataSourceBuilder.h"
|
|
#include "swift/Reflection/Records.h"
|
|
#include "swift/SIL/SILModule.h"
|
|
|
|
#include "ConstantBuilder.h"
|
|
#include "GenClass.h"
|
|
#include "GenDecl.h"
|
|
#include "GenEnum.h"
|
|
#include "GenHeap.h"
|
|
#include "GenProto.h"
|
|
#include "GenType.h"
|
|
#include "IRGenMangler.h"
|
|
#include "IRGenModule.h"
|
|
#include "LoadableTypeInfo.h"
|
|
|
|
using namespace swift;
|
|
using namespace irgen;
|
|
using namespace reflection;
|
|
|
|
class MetadataSourceEncoder
|
|
: public MetadataSourceVisitor<MetadataSourceEncoder> {
|
|
llvm::raw_ostream &OS;
|
|
public:
|
|
MetadataSourceEncoder(llvm::raw_ostream &OS) : OS(OS) {}
|
|
|
|
void
|
|
visitClosureBindingMetadataSource(const ClosureBindingMetadataSource *CB) {
|
|
OS << 'B';
|
|
OS << CB->getIndex();
|
|
}
|
|
|
|
void
|
|
visitReferenceCaptureMetadataSource(const ReferenceCaptureMetadataSource *RC){
|
|
OS << 'R';
|
|
OS << RC->getIndex();
|
|
}
|
|
|
|
void
|
|
visitMetadataCaptureMetadataSource(const MetadataCaptureMetadataSource *MC) {
|
|
OS << 'M';
|
|
OS << MC->getIndex();
|
|
}
|
|
|
|
void
|
|
visitGenericArgumentMetadataSource(const GenericArgumentMetadataSource *GA) {
|
|
OS << 'G';
|
|
OS << GA->getIndex();
|
|
visit(GA->getSource());
|
|
OS << '_';
|
|
}
|
|
|
|
void visitSelfMetadataSource(const SelfMetadataSource *S) {
|
|
OS << 'S';
|
|
}
|
|
|
|
void
|
|
visitSelfWitnessTableMetadataSource(const SelfWitnessTableMetadataSource *S) {
|
|
OS << 'W';
|
|
}
|
|
};
|
|
|
|
class PrintMetadataSource
|
|
: public MetadataSourceVisitor<PrintMetadataSource, void> {
|
|
llvm::raw_ostream &OS;
|
|
unsigned Indent;
|
|
|
|
llvm::raw_ostream &indent(unsigned Amount) {
|
|
for (unsigned i = 0; i < Amount; ++i)
|
|
OS << ' ';
|
|
return OS;
|
|
}
|
|
|
|
llvm::raw_ostream &printHeader(std::string Name) {
|
|
indent(Indent) << '(' << Name;
|
|
return OS;
|
|
}
|
|
|
|
template<typename T>
|
|
llvm::raw_ostream &printField(std::string name, const T &value) {
|
|
if (!name.empty())
|
|
OS << " " << name << "=" << value;
|
|
else
|
|
OS << " " << value;
|
|
return OS;
|
|
}
|
|
|
|
void printRec(const reflection::MetadataSource *MS) {
|
|
OS << "\n";
|
|
|
|
Indent += 2;
|
|
visit(MS);
|
|
Indent -= 2;
|
|
}
|
|
|
|
void closeForm() {
|
|
OS << ')';
|
|
}
|
|
|
|
public:
|
|
PrintMetadataSource(llvm::raw_ostream &OS, unsigned Indent)
|
|
: OS(OS), Indent(Indent) {}
|
|
|
|
void
|
|
visitClosureBindingMetadataSource(const ClosureBindingMetadataSource *CB) {
|
|
printHeader("closure-binding");
|
|
printField("index", CB->getIndex());
|
|
closeForm();
|
|
}
|
|
|
|
void
|
|
visitReferenceCaptureMetadataSource(const ReferenceCaptureMetadataSource *RC){
|
|
printHeader("reference-capture");
|
|
printField("index", RC->getIndex());
|
|
closeForm();
|
|
}
|
|
|
|
void
|
|
visitMetadataCaptureMetadataSource(const MetadataCaptureMetadataSource *MC){
|
|
printHeader("metadata-capture");
|
|
printField("index", MC->getIndex());
|
|
closeForm();
|
|
}
|
|
|
|
void
|
|
visitGenericArgumentMetadataSource(const GenericArgumentMetadataSource *GA) {
|
|
printHeader("generic-argument");
|
|
printField("index", GA->getIndex());
|
|
printRec(GA->getSource());
|
|
closeForm();
|
|
}
|
|
|
|
void
|
|
visitSelfMetadataSource(const SelfMetadataSource *S) {
|
|
printHeader("self");
|
|
closeForm();
|
|
}
|
|
|
|
void
|
|
visitSelfWitnessTableMetadataSource(const SelfWitnessTableMetadataSource *S) {
|
|
printHeader("self-witness-table");
|
|
closeForm();
|
|
}
|
|
};
|
|
|
|
llvm::Constant *IRGenModule::getTypeRef(CanType type) {
|
|
IRGenMangler Mangler;
|
|
auto SymbolicName = Mangler.mangleTypeForReflection(*this, type);
|
|
return getAddrOfStringForTypeRef(SymbolicName);
|
|
}
|
|
|
|
class ReflectionMetadataBuilder {
|
|
protected:
|
|
IRGenModule &IGM;
|
|
ConstantInitBuilder InitBuilder;
|
|
ConstantStructBuilder B;
|
|
|
|
ReflectionMetadataBuilder(IRGenModule &IGM)
|
|
: IGM(IGM), InitBuilder(IGM), B(InitBuilder.beginStruct()) {}
|
|
|
|
virtual ~ReflectionMetadataBuilder() {}
|
|
|
|
// Collect any builtin types referenced from this type.
|
|
void addBuiltinTypeRefs(CanType type) {
|
|
type.visit([&](CanType t) {
|
|
if (IGM.getSwiftModule()->isStdlibModule() && isa<BuiltinType>(t))
|
|
IGM.BuiltinTypes.insert(t);
|
|
|
|
// We need size/alignment information for imported value types,
|
|
// so emit builtin descriptors for them.
|
|
//
|
|
// In effect they're treated like an opaque blob, which is OK
|
|
// for now, at least until we want to import C++ types or
|
|
// something like that.
|
|
//
|
|
// Classes and protocols go down a different path.
|
|
if (auto Nominal = t->getAnyNominal())
|
|
if (Nominal->hasClangNode()) {
|
|
if (auto CD = dyn_cast<ClassDecl>(Nominal))
|
|
IGM.ImportedClasses.insert(CD);
|
|
else if (auto PD = dyn_cast<ProtocolDecl>(Nominal))
|
|
IGM.ImportedProtocols.insert(PD);
|
|
else
|
|
IGM.OpaqueTypes.insert(Nominal);
|
|
}
|
|
});
|
|
}
|
|
|
|
/// Add a 32-bit relative offset to a mangled typeref string
|
|
/// in the typeref reflection section.
|
|
void addTypeRef(CanType type) {
|
|
B.addRelativeAddress(IGM.getTypeRef(type));
|
|
}
|
|
|
|
/// Add a 32-bit relative offset to a mangled nominal type string
|
|
/// in the typeref reflection section.
|
|
void addNominalRef(const NominalTypeDecl *nominal) {
|
|
if (auto proto = dyn_cast<ProtocolDecl>(nominal)) {
|
|
IRGenMangler mangler;
|
|
SymbolicMangling mangledStr;
|
|
mangledStr.String = mangler.mangleBareProtocol(proto);
|
|
auto mangledName = IGM.getAddrOfStringForTypeRef(mangledStr);
|
|
B.addRelativeAddress(mangledName);
|
|
} else {
|
|
CanType type = nominal->getDeclaredType()->getCanonicalType();
|
|
B.addRelativeAddress(IGM.getTypeRef(type));
|
|
}
|
|
}
|
|
|
|
llvm::GlobalVariable *emit(Optional<LinkEntity> entity,
|
|
const char *section) {
|
|
layout();
|
|
|
|
llvm::GlobalVariable *var;
|
|
|
|
// Some reflection records have a mangled symbol name, for uniquing
|
|
// imported type metadata.
|
|
if (entity) {
|
|
auto info = LinkInfo::get(IGM, *entity, ForDefinition);
|
|
|
|
auto init = B.finishAndCreateFuture();
|
|
|
|
var = createVariable(IGM, info, init.getType(), Alignment(4));
|
|
var->setConstant(true);
|
|
init.installInGlobal(var);
|
|
|
|
// Others, such as capture descriptors, do not have a name.
|
|
} else {
|
|
var = B.finishAndCreateGlobal("\x01l__swift5_reflection_descriptor",
|
|
Alignment(4), /*isConstant*/ true,
|
|
llvm::GlobalValue::PrivateLinkage);
|
|
}
|
|
|
|
var->setSection(section);
|
|
|
|
IGM.addUsedGlobal(var);
|
|
|
|
disableAddressSanitizer(IGM, var);
|
|
|
|
return var;
|
|
}
|
|
|
|
virtual void layout() = 0;
|
|
};
|
|
|
|
class AssociatedTypeMetadataBuilder : public ReflectionMetadataBuilder {
|
|
static const uint32_t AssociatedTypeRecordSize = 8;
|
|
|
|
const ProtocolConformance *Conformance;
|
|
ArrayRef<std::pair<StringRef, CanType>> AssociatedTypes;
|
|
|
|
void layout() override {
|
|
// If the conforming type is generic, we just want to emit the
|
|
// unbound generic type here.
|
|
auto *Nominal = Conformance->getType()->getAnyNominal();
|
|
assert(Nominal && "Structural conformance?");
|
|
|
|
PrettyStackTraceDecl DebugStack("emitting associated type metadata",
|
|
Nominal);
|
|
|
|
addTypeRef(Nominal->getDeclaredType()->getCanonicalType());
|
|
addNominalRef(Conformance->getProtocol());
|
|
|
|
B.addInt32(AssociatedTypes.size());
|
|
B.addInt32(AssociatedTypeRecordSize);
|
|
|
|
for (auto AssocTy : AssociatedTypes) {
|
|
auto NameGlobal = IGM.getAddrOfFieldName(AssocTy.first);
|
|
B.addRelativeAddress(NameGlobal);
|
|
addBuiltinTypeRefs(AssocTy.second);
|
|
addTypeRef(AssocTy.second);
|
|
}
|
|
}
|
|
|
|
public:
|
|
AssociatedTypeMetadataBuilder(IRGenModule &IGM,
|
|
const ProtocolConformance *Conformance,
|
|
ArrayRef<std::pair<StringRef, CanType>> AssociatedTypes)
|
|
: ReflectionMetadataBuilder(IGM), Conformance(Conformance),
|
|
AssociatedTypes(AssociatedTypes) {}
|
|
|
|
llvm::GlobalVariable *emit() {
|
|
auto entity = LinkEntity::forReflectionAssociatedTypeDescriptor(Conformance);
|
|
auto section = IGM.getAssociatedTypeMetadataSectionName();
|
|
return ReflectionMetadataBuilder::emit(entity, section);
|
|
}
|
|
};
|
|
|
|
class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
|
|
const uint32_t fieldRecordSize = 12;
|
|
const NominalTypeDecl *NTD;
|
|
|
|
void addFieldDecl(const ValueDecl *value, CanType type,
|
|
bool indirect=false) {
|
|
reflection::FieldRecordFlags flags;
|
|
flags.setIsIndirectCase(indirect);
|
|
if (auto var = dyn_cast<VarDecl>(value))
|
|
flags.setIsVar(!var->isLet());
|
|
|
|
B.addInt32(flags.getRawValue());
|
|
|
|
if (!type) {
|
|
B.addInt32(0);
|
|
} else {
|
|
addTypeRef(type);
|
|
addBuiltinTypeRefs(type);
|
|
}
|
|
|
|
if (IGM.IRGen.Opts.EnableReflectionNames) {
|
|
auto name = value->getBaseName().getIdentifier().str();
|
|
auto fieldName = IGM.getAddrOfFieldName(name);
|
|
B.addRelativeAddress(fieldName);
|
|
} else {
|
|
B.addInt32(0);
|
|
}
|
|
}
|
|
|
|
void layoutRecord() {
|
|
auto kind = FieldDescriptorKind::Struct;
|
|
|
|
if (auto CD = dyn_cast<ClassDecl>(NTD)) {
|
|
auto type = CD->getDeclaredType()->getCanonicalType();
|
|
auto RC = getReferenceCountingForType(IGM, type);
|
|
if (RC == ReferenceCounting::ObjC)
|
|
kind = FieldDescriptorKind::ObjCClass;
|
|
else
|
|
kind = FieldDescriptorKind::Class;
|
|
}
|
|
|
|
B.addInt16(uint16_t(kind));
|
|
B.addInt16(fieldRecordSize);
|
|
|
|
// Imported classes don't need field descriptors
|
|
if (NTD->hasClangNode() && isa<ClassDecl>(NTD)) {
|
|
B.addInt32(0);
|
|
return;
|
|
}
|
|
|
|
assert(!NTD->hasClangNode() || isa<StructDecl>(NTD));
|
|
|
|
auto properties = NTD->getStoredProperties();
|
|
B.addInt32(std::distance(properties.begin(), properties.end()));
|
|
for (auto property : properties)
|
|
addFieldDecl(property,
|
|
property->getInterfaceType()
|
|
->getCanonicalType());
|
|
}
|
|
|
|
void layoutEnum() {
|
|
auto enumDecl = cast<EnumDecl>(NTD);
|
|
auto &strategy = irgen::getEnumImplStrategy(
|
|
IGM, enumDecl->getDeclaredTypeInContext()
|
|
->getCanonicalType());
|
|
|
|
auto kind = FieldDescriptorKind::Enum;
|
|
|
|
// If this is a fixed-size multi-payload enum, we have to emit a descriptor
|
|
// with the size and alignment of the type, because the reflection library
|
|
// cannot derive this information at runtime.
|
|
if (strategy.getElementsWithPayload().size() > 1 &&
|
|
!strategy.needsPayloadSizeInMetadata()) {
|
|
kind = FieldDescriptorKind::MultiPayloadEnum;
|
|
IGM.OpaqueTypes.insert(enumDecl);
|
|
}
|
|
|
|
B.addInt16(uint16_t(kind));
|
|
B.addInt16(fieldRecordSize);
|
|
B.addInt32(strategy.getElementsWithPayload().size()
|
|
+ strategy.getElementsWithNoPayload().size());
|
|
|
|
for (auto enumCase : strategy.getElementsWithPayload()) {
|
|
bool indirect = (enumCase.decl->isIndirect() ||
|
|
enumDecl->isIndirect());
|
|
addFieldDecl(enumCase.decl,
|
|
enumCase.decl->getArgumentInterfaceType()
|
|
->getCanonicalType(),
|
|
indirect);
|
|
}
|
|
|
|
for (auto enumCase : strategy.getElementsWithNoPayload()) {
|
|
addFieldDecl(enumCase.decl, CanType());
|
|
}
|
|
}
|
|
|
|
void layoutProtocol() {
|
|
auto protocolDecl = cast<ProtocolDecl>(NTD);
|
|
FieldDescriptorKind Kind;
|
|
if (protocolDecl->isObjC())
|
|
Kind = FieldDescriptorKind::ObjCProtocol;
|
|
else if (protocolDecl->requiresClass())
|
|
Kind = FieldDescriptorKind::ClassProtocol;
|
|
else
|
|
Kind = FieldDescriptorKind::Protocol;
|
|
B.addInt16(uint16_t(Kind));
|
|
B.addInt16(fieldRecordSize);
|
|
B.addInt32(0);
|
|
}
|
|
|
|
void layout() override {
|
|
if (NTD->hasClangNode() &&
|
|
!isa<ClassDecl>(NTD) &&
|
|
!isa<StructDecl>(NTD) &&
|
|
!isa<ProtocolDecl>(NTD))
|
|
return;
|
|
|
|
PrettyStackTraceDecl DebugStack("emitting field type metadata", NTD);
|
|
addNominalRef(NTD);
|
|
|
|
auto *CD = dyn_cast<ClassDecl>(NTD);
|
|
if (CD && CD->getSuperclass()) {
|
|
addTypeRef(CD->getSuperclass()->getCanonicalType());
|
|
} else {
|
|
B.addInt32(0);
|
|
}
|
|
|
|
switch (NTD->getKind()) {
|
|
case DeclKind::Class:
|
|
case DeclKind::Struct:
|
|
layoutRecord();
|
|
break;
|
|
|
|
case DeclKind::Enum:
|
|
layoutEnum();
|
|
break;
|
|
|
|
case DeclKind::Protocol:
|
|
layoutProtocol();
|
|
break;
|
|
|
|
default:
|
|
llvm_unreachable("Not a nominal type");
|
|
break;
|
|
}
|
|
}
|
|
|
|
public:
|
|
FieldTypeMetadataBuilder(IRGenModule &IGM,
|
|
const NominalTypeDecl * NTD)
|
|
: ReflectionMetadataBuilder(IGM), NTD(NTD) {}
|
|
|
|
llvm::GlobalVariable *emit() {
|
|
auto entity = LinkEntity::forReflectionFieldDescriptor(
|
|
NTD->getDeclaredType()->getCanonicalType());
|
|
auto section = IGM.getFieldTypeMetadataSectionName();
|
|
return ReflectionMetadataBuilder::emit(entity, section);
|
|
}
|
|
};
|
|
|
|
class FixedTypeMetadataBuilder : public ReflectionMetadataBuilder {
|
|
ModuleDecl *module;
|
|
CanType type;
|
|
const FixedTypeInfo *ti;
|
|
|
|
public:
|
|
FixedTypeMetadataBuilder(IRGenModule &IGM,
|
|
CanType builtinType)
|
|
: ReflectionMetadataBuilder(IGM) {
|
|
module = builtinType->getASTContext().TheBuiltinModule;
|
|
type = builtinType;
|
|
ti = &cast<FixedTypeInfo>(IGM.getTypeInfoForUnlowered(builtinType));
|
|
}
|
|
|
|
FixedTypeMetadataBuilder(IRGenModule &IGM,
|
|
const NominalTypeDecl *nominalDecl)
|
|
: ReflectionMetadataBuilder(IGM) {
|
|
module = nominalDecl->getParentModule();
|
|
type = nominalDecl->getDeclaredType()->getCanonicalType();
|
|
ti = &cast<FixedTypeInfo>(IGM.getTypeInfoForUnlowered(
|
|
nominalDecl->getDeclaredTypeInContext()->getCanonicalType()));
|
|
}
|
|
|
|
void layout() override {
|
|
addTypeRef(type);
|
|
|
|
B.addInt32(ti->getFixedSize().getValue());
|
|
B.addInt32(ti->getFixedAlignment().getValue());
|
|
B.addInt32(ti->getFixedStride().getValue());
|
|
B.addInt32(ti->getFixedExtraInhabitantCount(IGM));
|
|
}
|
|
|
|
llvm::GlobalVariable *emit() {
|
|
auto entity = LinkEntity::forReflectionBuiltinDescriptor(type);
|
|
auto section = IGM.getBuiltinTypeMetadataSectionName();
|
|
return ReflectionMetadataBuilder::emit(entity, section);
|
|
}
|
|
};
|
|
|
|
void IRGenModule::emitBuiltinTypeMetadataRecord(CanType builtinType) {
|
|
FixedTypeMetadataBuilder builder(*this, builtinType);
|
|
builder.emit();
|
|
}
|
|
|
|
void IRGenModule::emitOpaqueTypeMetadataRecord(const NominalTypeDecl *nominalDecl) {
|
|
FixedTypeMetadataBuilder builder(*this, nominalDecl);
|
|
builder.emit();
|
|
}
|
|
|
|
bool IRGenModule::shouldEmitOpaqueTypeMetadataRecord(
|
|
const NominalTypeDecl *nominalDecl) {
|
|
if (nominalDecl->getAttrs().hasAttribute<AlignmentAttr>()) {
|
|
auto &ti = getTypeInfoForUnlowered(nominalDecl->getDeclaredTypeInContext());
|
|
if (isa<FixedTypeInfo>(ti))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// Builds a constant LLVM struct describing the layout of a fixed-size
|
|
/// SIL @box. These look like closure contexts, but without any necessary
|
|
/// bindings or metadata sources, and only a single captured value.
|
|
class BoxDescriptorBuilder : public ReflectionMetadataBuilder {
|
|
CanType BoxedType;
|
|
public:
|
|
BoxDescriptorBuilder(IRGenModule &IGM, CanType BoxedType)
|
|
: ReflectionMetadataBuilder(IGM), BoxedType(BoxedType) {}
|
|
|
|
void layout() override {
|
|
B.addInt32(1);
|
|
B.addInt32(0); // Number of sources
|
|
B.addInt32(0); // Number of generic bindings
|
|
|
|
addTypeRef(BoxedType);
|
|
addBuiltinTypeRefs(BoxedType);
|
|
}
|
|
|
|
llvm::GlobalVariable *emit() {
|
|
auto section = IGM.getCaptureDescriptorMetadataSectionName();
|
|
return ReflectionMetadataBuilder::emit(None, section);
|
|
}
|
|
};
|
|
|
|
/// Builds a constant LLVM struct describing the layout of a heap closure,
|
|
/// the types of its captures, and the sources of metadata if any of the
|
|
/// captures are generic.
|
|
class CaptureDescriptorBuilder : public ReflectionMetadataBuilder {
|
|
swift::reflection::MetadataSourceBuilder SourceBuilder;
|
|
CanSILFunctionType OrigCalleeType;
|
|
CanSILFunctionType SubstCalleeType;
|
|
SubstitutionMap Subs;
|
|
const HeapLayout &Layout;
|
|
|
|
public:
|
|
CaptureDescriptorBuilder(IRGenModule &IGM,
|
|
CanSILFunctionType OrigCalleeType,
|
|
CanSILFunctionType SubstCalleeType,
|
|
SubstitutionMap Subs,
|
|
const HeapLayout &Layout)
|
|
: ReflectionMetadataBuilder(IGM),
|
|
OrigCalleeType(OrigCalleeType),
|
|
SubstCalleeType(SubstCalleeType), Subs(Subs),
|
|
Layout(Layout) {}
|
|
|
|
using MetadataSourceMap
|
|
= std::vector<std::pair<CanType, const reflection::MetadataSource*>>;
|
|
|
|
void addMetadataSource(const reflection::MetadataSource *Source) {
|
|
if (Source == nullptr) {
|
|
B.addInt32(0);
|
|
} else {
|
|
SmallString<16> EncodeBuffer;
|
|
llvm::raw_svector_ostream OS(EncodeBuffer);
|
|
MetadataSourceEncoder Encoder(OS);
|
|
Encoder.visit(Source);
|
|
|
|
auto EncodedSource = IGM.getAddrOfStringForTypeRef(OS.str());
|
|
B.addRelativeAddress(EncodedSource);
|
|
}
|
|
}
|
|
|
|
/// Give up if we captured an opened existential type. Eventually we
|
|
/// should figure out how to represent this.
|
|
static bool hasOpenedExistential(CanSILFunctionType OrigCalleeType,
|
|
const HeapLayout &Layout) {
|
|
if (!OrigCalleeType->isPolymorphic() ||
|
|
OrigCalleeType->isPseudogeneric())
|
|
return false;
|
|
|
|
auto &Bindings = Layout.getBindings();
|
|
for (unsigned i = 0; i < Bindings.size(); ++i) {
|
|
// Skip protocol requirements (FIXME: for now?)
|
|
if (Bindings[i].Protocol != nullptr)
|
|
continue;
|
|
|
|
if (Bindings[i].TypeParameter->hasOpenedExistential())
|
|
return true;
|
|
}
|
|
|
|
auto ElementTypes = Layout.getElementTypes().slice(
|
|
Layout.hasBindings() ? 1 : 0);
|
|
for (auto ElementType : ElementTypes) {
|
|
auto SwiftType = ElementType.getASTType();
|
|
if (SwiftType->hasOpenedExistential())
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// Slice off the NecessaryBindings struct at the beginning, if it's there.
|
|
/// We'll keep track of how many things are in the bindings struct with its
|
|
/// own count in the capture descriptor.
|
|
ArrayRef<SILType> getElementTypes() {
|
|
return Layout.getElementTypes().slice(Layout.hasBindings() ? 1 : 0);
|
|
}
|
|
|
|
/// Build a map from generic parameter -> source of its metadata at runtime.
|
|
///
|
|
/// If the callee that we are partially applying to create a box/closure
|
|
/// isn't generic, then the map is empty.
|
|
MetadataSourceMap getMetadataSourceMap() {
|
|
MetadataSourceMap SourceMap;
|
|
|
|
// Generic parameters of pseudogeneric functions do not have
|
|
// runtime metadata.
|
|
if (!OrigCalleeType->isPolymorphic() ||
|
|
OrigCalleeType->isPseudogeneric())
|
|
return SourceMap;
|
|
|
|
// Any generic parameters that are not fulfilled are passed in via the
|
|
// bindings. Structural types are decomposed, so emit the contents of
|
|
// the bindings structure directly.
|
|
auto &Bindings = Layout.getBindings();
|
|
for (unsigned i = 0; i < Bindings.size(); ++i) {
|
|
// Skip protocol requirements (FIXME: for now?)
|
|
if (Bindings[i].Protocol != nullptr)
|
|
continue;
|
|
|
|
auto Source = SourceBuilder.createClosureBinding(i);
|
|
auto BindingType = Bindings[i].TypeParameter;
|
|
auto InterfaceType = BindingType->mapTypeOutOfContext();
|
|
SourceMap.push_back({InterfaceType->getCanonicalType(), Source});
|
|
}
|
|
|
|
// Check if any requirements were fulfilled by metadata stored inside a
|
|
// captured value.
|
|
|
|
enumerateGenericParamFulfillments(IGM, OrigCalleeType,
|
|
[&](CanType GenericParam,
|
|
const irgen::MetadataSource &Source,
|
|
const MetadataPath &Path) {
|
|
|
|
const reflection::MetadataSource *Root;
|
|
switch (Source.getKind()) {
|
|
case irgen::MetadataSource::Kind::SelfMetadata:
|
|
case irgen::MetadataSource::Kind::SelfWitnessTable:
|
|
// Handled as part of bindings
|
|
return;
|
|
|
|
case irgen::MetadataSource::Kind::GenericLValueMetadata:
|
|
// FIXME?
|
|
return;
|
|
|
|
case irgen::MetadataSource::Kind::ClassPointer:
|
|
Root = SourceBuilder.createReferenceCapture(Source.getParamIndex());
|
|
break;
|
|
|
|
case irgen::MetadataSource::Kind::Metadata:
|
|
Root = SourceBuilder.createMetadataCapture(Source.getParamIndex());
|
|
break;
|
|
}
|
|
|
|
// The metadata might be reached via a non-trivial path (eg,
|
|
// dereferencing an isa pointer or a generic argument). Record
|
|
// the path. We assume captured values map 1-1 with function
|
|
// parameters.
|
|
auto Src = Path.getMetadataSource(SourceBuilder, Root);
|
|
|
|
auto SubstType = GenericParam.subst(Subs);
|
|
auto InterfaceType = SubstType->mapTypeOutOfContext();
|
|
SourceMap.push_back({InterfaceType->getCanonicalType(), Src});
|
|
});
|
|
|
|
return SourceMap;
|
|
}
|
|
|
|
/// Get the interface types of all of the captured values, mapped out of the
|
|
/// context of the callee we're partially applying.
|
|
std::vector<CanType> getCaptureTypes() {
|
|
std::vector<CanType> CaptureTypes;
|
|
|
|
for (auto ElementType : getElementTypes()) {
|
|
auto SwiftType = ElementType.getASTType();
|
|
|
|
// Erase pseudogeneric captures down to AnyObject.
|
|
if (OrigCalleeType->isPseudogeneric()) {
|
|
SwiftType = SwiftType.transform([&](Type t) -> Type {
|
|
if (auto *archetype = t->getAs<ArchetypeType>()) {
|
|
assert(archetype->requiresClass() && "don't know what to do");
|
|
return IGM.Context.getAnyObjectType();
|
|
}
|
|
return t;
|
|
})->getCanonicalType();
|
|
}
|
|
|
|
auto InterfaceType = SwiftType->mapTypeOutOfContext();
|
|
CaptureTypes.push_back(InterfaceType->getCanonicalType());
|
|
}
|
|
|
|
return CaptureTypes;
|
|
}
|
|
|
|
void layout() override {
|
|
auto CaptureTypes = getCaptureTypes();
|
|
auto MetadataSources = getMetadataSourceMap();
|
|
|
|
B.addInt32(CaptureTypes.size());
|
|
B.addInt32(MetadataSources.size());
|
|
B.addInt32(Layout.getBindings().size());
|
|
|
|
// Now add typerefs of all of the captures.
|
|
for (auto CaptureType : CaptureTypes) {
|
|
addTypeRef(CaptureType);
|
|
addBuiltinTypeRefs(CaptureType);
|
|
}
|
|
|
|
// Add the pairs that make up the generic param -> metadata source map
|
|
// to the struct.
|
|
for (auto GenericAndSource : MetadataSources) {
|
|
auto GenericParam = GenericAndSource.first->getCanonicalType();
|
|
auto Source = GenericAndSource.second;
|
|
|
|
addTypeRef(GenericParam);
|
|
addMetadataSource(Source);
|
|
}
|
|
}
|
|
|
|
llvm::GlobalVariable *emit() {
|
|
auto section = IGM.getCaptureDescriptorMetadataSectionName();
|
|
return ReflectionMetadataBuilder::emit(None, section);
|
|
}
|
|
};
|
|
|
|
static std::string getReflectionSectionName(IRGenModule &IGM,
|
|
StringRef LongName,
|
|
StringRef FourCC) {
|
|
SmallString<50> SectionName;
|
|
llvm::raw_svector_ostream OS(SectionName);
|
|
switch (IGM.TargetInfo.OutputObjectFormat) {
|
|
case llvm::Triple::UnknownObjectFormat:
|
|
llvm_unreachable("unknown object format");
|
|
case llvm::Triple::COFF:
|
|
assert(FourCC.size() <= 4 &&
|
|
"COFF section name length must be <= 8 characters");
|
|
OS << ".sw5" << FourCC << "$B";
|
|
break;
|
|
case llvm::Triple::ELF:
|
|
OS << "swift5_" << LongName;
|
|
break;
|
|
case llvm::Triple::MachO:
|
|
assert(LongName.size() <= 7 &&
|
|
"Mach-O section name length must be <= 16 characters");
|
|
OS << "__TEXT,__swift5_" << LongName << ", regular, no_dead_strip";
|
|
break;
|
|
case llvm::Triple::Wasm:
|
|
llvm_unreachable("web assembly object format is not supported.");
|
|
break;
|
|
}
|
|
return OS.str();
|
|
}
|
|
|
|
const char *IRGenModule::getFieldTypeMetadataSectionName() {
|
|
if (FieldTypeSection.empty())
|
|
FieldTypeSection = getReflectionSectionName(*this, "fieldmd", "flmd");
|
|
return FieldTypeSection.c_str();
|
|
}
|
|
|
|
const char *IRGenModule::getBuiltinTypeMetadataSectionName() {
|
|
if (BuiltinTypeSection.empty())
|
|
BuiltinTypeSection = getReflectionSectionName(*this, "builtin", "bltn");
|
|
return BuiltinTypeSection.c_str();
|
|
}
|
|
|
|
const char *IRGenModule::getAssociatedTypeMetadataSectionName() {
|
|
if (AssociatedTypeSection.empty())
|
|
AssociatedTypeSection = getReflectionSectionName(*this, "assocty", "asty");
|
|
return AssociatedTypeSection.c_str();
|
|
}
|
|
|
|
const char *IRGenModule::getCaptureDescriptorMetadataSectionName() {
|
|
if (CaptureDescriptorSection.empty())
|
|
CaptureDescriptorSection = getReflectionSectionName(*this, "capture", "cptr");
|
|
return CaptureDescriptorSection.c_str();
|
|
}
|
|
|
|
const char *IRGenModule::getReflectionStringsSectionName() {
|
|
if (ReflectionStringsSection.empty())
|
|
ReflectionStringsSection = getReflectionSectionName(*this, "reflstr", "rfst");
|
|
return ReflectionStringsSection.c_str();
|
|
}
|
|
|
|
const char *IRGenModule::getReflectionTypeRefSectionName() {
|
|
if (ReflectionTypeRefSection.empty())
|
|
ReflectionTypeRefSection = getReflectionSectionName(*this, "typeref", "tyrf");
|
|
return ReflectionTypeRefSection.c_str();
|
|
}
|
|
|
|
llvm::Constant *IRGenModule::getAddrOfFieldName(StringRef Name) {
|
|
auto &entry = FieldNames[Name];
|
|
if (entry.second)
|
|
return entry.second;
|
|
|
|
entry = createStringConstant(Name, /*willBeRelativelyAddressed*/ true,
|
|
getReflectionStringsSectionName());
|
|
disableAddressSanitizer(*this, entry.first);
|
|
return entry.second;
|
|
}
|
|
|
|
llvm::Constant *
|
|
IRGenModule::getAddrOfBoxDescriptor(CanType BoxedType) {
|
|
if (!IRGen.Opts.EnableReflectionMetadata)
|
|
return llvm::Constant::getNullValue(CaptureDescriptorPtrTy);
|
|
|
|
BoxDescriptorBuilder builder(*this, BoxedType);
|
|
auto var = builder.emit();
|
|
|
|
return llvm::ConstantExpr::getBitCast(var, CaptureDescriptorPtrTy);
|
|
}
|
|
|
|
llvm::Constant *
|
|
IRGenModule::getAddrOfCaptureDescriptor(SILFunction &Caller,
|
|
CanSILFunctionType OrigCalleeType,
|
|
CanSILFunctionType SubstCalleeType,
|
|
SubstitutionMap Subs,
|
|
const HeapLayout &Layout) {
|
|
if (!IRGen.Opts.EnableReflectionMetadata)
|
|
return llvm::Constant::getNullValue(CaptureDescriptorPtrTy);
|
|
|
|
if (CaptureDescriptorBuilder::hasOpenedExistential(OrigCalleeType, Layout))
|
|
return llvm::Constant::getNullValue(CaptureDescriptorPtrTy);
|
|
|
|
CaptureDescriptorBuilder builder(*this,
|
|
OrigCalleeType, SubstCalleeType, Subs,
|
|
Layout);
|
|
auto var = builder.emit();
|
|
return llvm::ConstantExpr::getBitCast(var, CaptureDescriptorPtrTy);
|
|
}
|
|
|
|
void IRGenModule::
|
|
emitAssociatedTypeMetadataRecord(const ProtocolConformance *Conformance) {
|
|
if (!IRGen.Opts.EnableReflectionMetadata)
|
|
return;
|
|
|
|
SmallVector<std::pair<StringRef, CanType>, 2> AssociatedTypes;
|
|
|
|
auto collectTypeWitness = [&](const AssociatedTypeDecl *AssocTy,
|
|
Type Replacement,
|
|
const TypeDecl *TD) -> bool {
|
|
AssociatedTypes.push_back({
|
|
AssocTy->getNameStr(),
|
|
Replacement->getCanonicalType()
|
|
});
|
|
return false;
|
|
};
|
|
|
|
Conformance->forEachTypeWitness(/*resolver*/ nullptr, collectTypeWitness);
|
|
|
|
// If there are no associated types, don't bother emitting any
|
|
// metadata.
|
|
if (AssociatedTypes.empty())
|
|
return;
|
|
|
|
AssociatedTypeMetadataBuilder builder(*this, Conformance, AssociatedTypes);
|
|
builder.emit();
|
|
}
|
|
|
|
void IRGenModule::emitBuiltinReflectionMetadata() {
|
|
if (getSwiftModule()->isStdlibModule()) {
|
|
BuiltinTypes.insert(Context.TheNativeObjectType);
|
|
BuiltinTypes.insert(Context.TheUnknownObjectType);
|
|
BuiltinTypes.insert(Context.TheBridgeObjectType);
|
|
BuiltinTypes.insert(Context.TheRawPointerType);
|
|
BuiltinTypes.insert(Context.TheUnsafeValueBufferType);
|
|
|
|
// This would not be necessary if RawPointer had the same set of
|
|
// extra inhabitants as these. But maybe it's best not to codify
|
|
// that in the ABI anyway.
|
|
CanType thinFunction = CanFunctionType::get(
|
|
AnyFunctionType::CanParamArrayRef(), Context.TheEmptyTupleType,
|
|
AnyFunctionType::ExtInfo().withRepresentation(
|
|
FunctionTypeRepresentation::Thin));
|
|
BuiltinTypes.insert(thinFunction);
|
|
|
|
CanType anyMetatype = CanExistentialMetatypeType::get(
|
|
Context.TheAnyType);
|
|
BuiltinTypes.insert(anyMetatype);
|
|
}
|
|
|
|
for (auto CD : ImportedClasses)
|
|
emitFieldMetadataRecord(CD);
|
|
|
|
for (auto PD : ImportedProtocols)
|
|
emitFieldMetadataRecord(PD);
|
|
|
|
for (auto SD : ImportedStructs)
|
|
emitFieldMetadataRecord(SD);
|
|
|
|
for (auto builtinType : BuiltinTypes)
|
|
emitBuiltinTypeMetadataRecord(builtinType);
|
|
|
|
for (auto nominalDecl : OpaqueTypes)
|
|
emitOpaqueTypeMetadataRecord(nominalDecl);
|
|
}
|
|
|
|
void IRGenerator::emitBuiltinReflectionMetadata() {
|
|
for (auto &m : *this) {
|
|
m.second->emitBuiltinReflectionMetadata();
|
|
}
|
|
}
|
|
|
|
void IRGenModule::emitFieldMetadataRecord(const NominalTypeDecl *Decl) {
|
|
if (!IRGen.Opts.EnableReflectionMetadata)
|
|
return;
|
|
|
|
// @objc enums never have generic parameters or payloads,
|
|
// and lower as their raw type.
|
|
if (auto *ED = dyn_cast<EnumDecl>(Decl))
|
|
if (ED->isObjC()) {
|
|
emitOpaqueTypeMetadataRecord(ED);
|
|
return;
|
|
}
|
|
|
|
FieldTypeMetadataBuilder builder(*this, Decl);
|
|
FieldDescriptors.push_back(builder.emit());
|
|
}
|
|
|
|
void IRGenModule::emitReflectionMetadataVersion() {
|
|
auto Init =
|
|
llvm::ConstantInt::get(Int16Ty, SWIFT_REFLECTION_METADATA_VERSION);
|
|
auto Version = new llvm::GlobalVariable(Module, Int16Ty, /*constant*/ true,
|
|
llvm::GlobalValue::LinkOnceODRLinkage,
|
|
Init,
|
|
"__swift_reflection_version");
|
|
Version->setVisibility(llvm::GlobalValue::HiddenVisibility);
|
|
addUsedGlobal(Version);
|
|
}
|
|
|
|
void IRGenerator::emitReflectionMetadataVersion() {
|
|
for (auto &m : *this) {
|
|
m.second->emitReflectionMetadataVersion();
|
|
}
|
|
}
|