Files
swift-mirror/lib/IRGen/GenReflection.cpp
Slava Pestov 95bc009e3e Reflection: Multi-payload enum layout
The approach here is to split this into two cases:

- If all case payloads have a fixed size, spare bits may be
  potentially used to differentiate between cases, and the
  remote reflection library does not have enough information to
  compute the layout itself.

  However, the total size must be fixed, so IRGen just emits a
  builtin type descriptor (which I need to rename to 'fixed type
  descriptor' since these are also used for imported value types,
  and now, certain enums).

- If at least one case has a size that depends on a generic
  parameter or is a resilient type, IRGen does not know the size,
  but this means fancy tricks with spare bits cannot be used either.
  The remote reflection library uses the same approach as the
  runtime, basically taking the maximum of the payload size and
  alignment, and adding a tag byte.

As with single-payload enums, we produce a new kind of
RecordTypeInfo, this time with a field for every enum case.
All cases start at offset zero (but of course this might change,
if for example we put the enum tag before the address point).

Also, just as with single-payload enums, there is no remote
'project case index' operation on ReflectionContext yet.

So the the main benefit from this change is that we don't entirely
give up when doing layout of class instances containing enums;
however, tools still cannot look inside the enum values themselves,
except in the simplest cases involving optionals.

Notably, the remote reflection library finally understands all
of the standard library's collection types -- Array, Character,
Dictionary, Set, and String.
2016-07-01 01:31:25 -07:00

933 lines
29 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 - 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
//
//===----------------------------------------------------------------------===//
//
// This file implements IR generation of type metadata for struct/class
// stored properties and enum cases for use with reflection.
//===----------------------------------------------------------------------===//
#include "swift/AST/ArchetypeBuilder.h"
#include "swift/AST/Decl.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/Reflection/MetadataSourceBuilder.h"
#include "swift/Reflection/Records.h"
#include "swift/SIL/SILModule.h"
#include "ConstantBuilder.h"
#include "GenClass.h"
#include "GenEnum.h"
#include "GenHeap.h"
#include "GenProto.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 visitParentMetadataSource(const ParentMetadataSource *P) {
OS << 'P';
visit(P->getChild());
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
visitParentMetadataSource(const ParentMetadataSource *P) {
printHeader("parent-of");
printRec(P->getChild());
closeForm();
}
void
visitSelfMetadataSource(const SelfMetadataSource *S) {
printHeader("self");
closeForm();
}
void
visitSelfWitnessTableMetadataSource(const SelfWitnessTableMetadataSource *S) {
printHeader("self-witness-table");
closeForm();
}
};
class ReflectionMetadataBuilder : public ConstantBuilder<> {
protected:
// Collect any builtin types referenced from this type.
void addBuiltinTypeRefs(CanType type) {
type.visit([&](Type t) {
if (t->is<BuiltinType>())
IGM.BuiltinTypes.insert(CanType(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(Module *ModuleContext, CanType type) {
assert(type);
// Generic parameters should be written in terms of interface types
// for the purposes of reflection metadata
assert(!type->hasArchetype() && "Forgot to map typeref out of context");
Mangle::Mangler mangler(/*DWARFMangling*/false,
/*usePunyCode*/ true,
/*OptimizeProtocolNames*/ false);
mangler.setModuleContext(ModuleContext);
mangler.mangleType(type, 0);
auto mangledName = IGM.getAddrOfStringForTypeRef(mangler.finalize());
addRelativeAddress(mangledName);
}
public:
ReflectionMetadataBuilder(IRGenModule &IGM)
: ConstantBuilder(IGM) {}
};
class AssociatedTypeMetadataBuilder : public ReflectionMetadataBuilder {
static const uint32_t AssociatedTypeRecordSize = 8;
const ProtocolConformance *Conformance;
ArrayRef<std::pair<StringRef, CanType>> AssociatedTypes;
void layout() {
// If the conforming type is generic, we just want to emit the
// unbound generic type here.
auto *Nominal = Conformance->getInterfaceType()->getAnyNominal();
assert(Nominal && "Structural conformance?");
PrettyStackTraceDecl DebugStack("emitting associated type metadata",
Nominal);
auto *M = IGM.getSILModule().getSwiftModule();
addTypeRef(M, Nominal->getDeclaredType()->getCanonicalType());
auto ProtoTy = Conformance->getProtocol()->getDeclaredType();
addTypeRef(M, ProtoTy->getCanonicalType());
addConstantInt32(AssociatedTypes.size());
addConstantInt32(AssociatedTypeRecordSize);
for (auto AssocTy : AssociatedTypes) {
auto NameGlobal = IGM.getAddrOfStringForTypeRef(AssocTy.first);
addRelativeAddress(NameGlobal);
addBuiltinTypeRefs(AssocTy.second);
addTypeRef(M, 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 tempBase = std::unique_ptr<llvm::GlobalVariable>(
new llvm::GlobalVariable(IGM.Int8Ty, /*isConstant*/ true,
llvm::GlobalValue::PrivateLinkage));
setRelativeAddressBase(tempBase.get());
layout();
auto init = getInit();
if (!init)
return nullptr;
auto var = new llvm::GlobalVariable(*IGM.getModule(), init->getType(),
/*isConstant*/ true,
llvm::GlobalValue::PrivateLinkage,
init,
"\x01l__swift3_assocty_metadata");
var->setSection(IGM.getAssociatedTypeMetadataSectionName());
var->setAlignment(4);
auto replacer = llvm::ConstantExpr::getBitCast(var, IGM.Int8PtrTy);
tempBase->replaceAllUsesWith(replacer);
return var;
}
};
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);
addConstantInt32(flags.getRawValue());
if (!type) {
addConstantInt32(0);
} else {
addTypeRef(value->getModuleContext(), type);
addBuiltinTypeRefs(type);
}
if (IGM.IRGen.Opts.EnableReflectionNames) {
auto fieldName = IGM.getAddrOfFieldName(value->getNameStr());
addRelativeAddress(fieldName);
} else {
addConstantInt32(0);
}
}
void layoutRecord() {
auto kind = FieldDescriptorKind::Struct;
if (auto CD = dyn_cast<ClassDecl>(NTD)) {
auto RC = getReferenceCountingForClass(IGM, const_cast<ClassDecl *>(CD));
if (RC == ReferenceCounting::ObjC)
kind = FieldDescriptorKind::ObjCClass;
else
kind = FieldDescriptorKind::Class;
}
addConstantInt16(uint16_t(kind));
addConstantInt16(fieldRecordSize);
// Imported classes don't need field descriptors
if (NTD->hasClangNode()) {
assert(isa<ClassDecl>(NTD));
addConstantInt32(0);
return;
}
auto properties = NTD->getStoredProperties();
addConstantInt32(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);
}
addConstantInt16(uint16_t(kind));
addConstantInt16(fieldRecordSize);
addConstantInt32(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;
addConstantInt16(uint16_t(Kind));
addConstantInt16(fieldRecordSize);
addConstantInt32(0);
}
void layout() {
PrettyStackTraceDecl DebugStack("emitting field type metadata", NTD);
auto type = NTD->getDeclaredType()->getCanonicalType();
addTypeRef(NTD->getModuleContext(), type);
if (NTD->hasClangNode() &&
!isa<ClassDecl>(NTD) &&
!isa<ProtocolDecl>(NTD))
return;
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 tempBase = std::unique_ptr<llvm::GlobalVariable>(
new llvm::GlobalVariable(IGM.Int8Ty, /*isConstant*/ true,
llvm::GlobalValue::PrivateLinkage));
setRelativeAddressBase(tempBase.get());
layout();
auto init = getInit();
if (!init)
return nullptr;
auto var = new llvm::GlobalVariable(*IGM.getModule(), init->getType(),
/*isConstant*/ true,
llvm::GlobalValue::PrivateLinkage,
init,
"\x01l__swift3_reflection_metadata");
var->setSection(IGM.getFieldTypeMetadataSectionName());
var->setAlignment(4);
auto replacer = llvm::ConstantExpr::getBitCast(var, IGM.Int8PtrTy);
tempBase->replaceAllUsesWith(replacer);
return var;
}
};
class FixedTypeMetadataBuilder : public ReflectionMetadataBuilder {
void addFixedType(Module *module, CanType type,
const FixedTypeInfo &ti) {
addTypeRef(module, type);
addConstantInt32(ti.getFixedSize().getValue());
addConstantInt32(ti.getFixedAlignment().getValue());
addConstantInt32(ti.getFixedStride().getValue());
addConstantInt32(ti.getFixedExtraInhabitantCount(IGM));
}
void addBuiltinType(CanType builtinType) {
auto &ti = cast<FixedTypeInfo>(IGM.getTypeInfoForUnlowered(builtinType));
addFixedType(builtinType->getASTContext().TheBuiltinModule, builtinType, ti);
}
void addOpaqueType(const NominalTypeDecl *nominalDecl) {
auto &ti = cast<FixedTypeInfo>(IGM.getTypeInfoForUnlowered(
nominalDecl->getDeclaredTypeInContext()->getCanonicalType()));
addFixedType(nominalDecl->getParentModule(),
nominalDecl->getDeclaredType()->getCanonicalType(), ti);
}
void layout() {
for (auto builtinType : IGM.BuiltinTypes)
addBuiltinType(builtinType);
for (auto nominalDecl : IGM.OpaqueTypes)
addOpaqueType(nominalDecl);
}
public:
FixedTypeMetadataBuilder(IRGenModule &IGM)
: ReflectionMetadataBuilder(IGM) {}
llvm::GlobalVariable *emit() {
auto tempBase = std::unique_ptr<llvm::GlobalVariable>(
new llvm::GlobalVariable(IGM.Int8Ty, /*isConstant*/ true,
llvm::GlobalValue::PrivateLinkage));
setRelativeAddressBase(tempBase.get());
layout();
auto init = getInit();
if (!init)
return nullptr;
auto var = new llvm::GlobalVariable(*IGM.getModule(), init->getType(),
/*isConstant*/ true,
llvm::GlobalValue::PrivateLinkage,
init,
"\x01l__swift3_builtin_metadata");
var->setSection(IGM.getBuiltinTypeMetadataSectionName());
var->setAlignment(4);
auto replacer = llvm::ConstantExpr::getBitCast(var, IGM.Int8PtrTy);
tempBase->replaceAllUsesWith(replacer);
return var;
}
};
/// 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() {
addConstantInt32(1);
addConstantInt32(0); // Number of sources
addConstantInt32(0); // Number of generic bindings
addTypeRef(IGM.getSILModule().getSwiftModule(), BoxedType);
addBuiltinTypeRefs(BoxedType);
}
llvm::GlobalVariable *emit() {
auto tempBase = std::unique_ptr<llvm::GlobalVariable>(
new llvm::GlobalVariable(IGM.Int8Ty, /*isConstant*/ true,
llvm::GlobalValue::PrivateLinkage));
setRelativeAddressBase(tempBase.get());
layout();
auto init = getInit();
if (!init)
return nullptr;
auto var = new llvm::GlobalVariable(*IGM.getModule(), init->getType(),
/*isConstant*/ true,
llvm::GlobalValue::PrivateLinkage,
init,
"\x01l__swift3_box_descriptor");
var->setSection(IGM.getCaptureDescriptorMetadataSectionName());
var->setAlignment(4);
auto replacer = llvm::ConstantExpr::getBitCast(var, IGM.Int8PtrTy);
tempBase->replaceAllUsesWith(replacer);
return var;
}
};
/// 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;
SILFunction &Caller;
CanSILFunctionType OrigCalleeType;
CanSILFunctionType SubstCalleeType;
ArrayRef<Substitution> Subs;
const HeapLayout &Layout;
public:
CaptureDescriptorBuilder(IRGenModule &IGM,
SILFunction &Caller,
CanSILFunctionType OrigCalleeType,
CanSILFunctionType SubstCalleeType,
ArrayRef<Substitution> Subs,
const HeapLayout &Layout)
: ReflectionMetadataBuilder(IGM),
Caller(Caller), 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) {
addConstantInt32(0);
} else {
SmallString<16> EncodeBuffer;
llvm::raw_svector_ostream OS(EncodeBuffer);
MetadataSourceEncoder Encoder(OS);
Encoder.visit(Source);
auto EncodedSource = IGM.getAddrOfStringForTypeRef(OS.str());
addRelativeAddress(EncodedSource);
}
}
/// 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;
if (!OrigCalleeType->isPolymorphic())
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 = Caller.mapTypeOutOfContext(Bindings[i].TypeParameter);
SourceMap.push_back({BindingType->getCanonicalType(), Source});
}
// Check if any requirements were fulfilled by metadata stored inside a
// captured value.
auto SubstMap =
OrigCalleeType->getGenericSignature()->getSubstitutionMap(Subs);
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 =
Caller.mapTypeOutOfContext(SubstMap[GenericParam.getPointer()]);
SourceMap.push_back({SubstType->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.getSwiftRValueType();
auto InterfaceType = Caller.mapTypeOutOfContext(SwiftType);
CaptureTypes.push_back(InterfaceType->getCanonicalType());
}
return CaptureTypes;
}
void layout() {
auto CaptureTypes = getCaptureTypes();
auto MetadataSources = getMetadataSourceMap();
addConstantInt32(CaptureTypes.size());
addConstantInt32(MetadataSources.size());
addConstantInt32(Layout.getBindings().size());
// Now add typerefs of all of the captures.
for (auto CaptureType : CaptureTypes) {
addTypeRef(IGM.getSILModule().getSwiftModule(), 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(nullptr, GenericParam);
addMetadataSource(Source);
}
}
llvm::GlobalVariable *emit() {
auto tempBase = std::unique_ptr<llvm::GlobalVariable>(
new llvm::GlobalVariable(IGM.Int8Ty, /*isConstant*/ true,
llvm::GlobalValue::PrivateLinkage));
setRelativeAddressBase(tempBase.get());
layout();
auto init = getInit();
if (!init)
return nullptr;
auto var = new llvm::GlobalVariable(*IGM.getModule(), init->getType(),
/*isConstant*/ true,
llvm::GlobalValue::PrivateLinkage,
init,
"\x01l__swift3_capture_descriptor");
var->setSection(IGM.getCaptureDescriptorMetadataSectionName());
var->setAlignment(4);
auto replacer = llvm::ConstantExpr::getBitCast(var, IGM.Int8PtrTy);
tempBase->replaceAllUsesWith(replacer);
return var;
}
};
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 << ".sw3" << FourCC;
break;
case llvm::Triple::ELF:
OS << ".swift3_" << LongName;
break;
case llvm::Triple::MachO:
assert(LongName.size() <= 7 &&
"Mach-O section name length must be <= 16 characters");
OS << "__TEXT,__swift3_" << LongName << ", regular, no_dead_strip";
break;
}
return OS.str();
}
std::string IRGenModule::getFieldTypeMetadataSectionName() {
return getReflectionSectionName(*this, "fieldmd", "flmd");
}
std::string IRGenModule::getBuiltinTypeMetadataSectionName() {
return getReflectionSectionName(*this, "builtin", "bltn");
}
std::string IRGenModule::getAssociatedTypeMetadataSectionName() {
return getReflectionSectionName(*this, "assocty", "asty");
}
std::string IRGenModule::getCaptureDescriptorMetadataSectionName() {
return getReflectionSectionName(*this, "capture", "cptr");
}
std::string IRGenModule::getReflectionStringsSectionName() {
return getReflectionSectionName(*this, "reflstr", "rfst");
}
std::string IRGenModule::getReflectionTypeRefSectionName() {
return getReflectionSectionName(*this, "typeref", "tyrf");
}
llvm::Constant *IRGenModule::getAddrOfFieldName(StringRef Name) {
auto &entry = FieldNames[Name];
if (entry.second)
return entry.second;
entry = createStringConstant(Name, /*willBeRelativelyAddressed*/ true,
getReflectionStringsSectionName());
return entry.second;
}
llvm::Constant *IRGenModule::getAddrOfStringForTypeRef(StringRef Str) {
auto &entry = StringsForTypeRef[Str];
if (entry.second)
return entry.second;
entry = createStringConstant(Str, /*willBeRelativelyAddressed*/ true,
getReflectionTypeRefSectionName());
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();
if (var)
addUsedGlobal(var);
return llvm::ConstantExpr::getBitCast(var, CaptureDescriptorPtrTy);
}
llvm::Constant *
IRGenModule::getAddrOfCaptureDescriptor(SILFunction &Caller,
CanSILFunctionType OrigCalleeType,
CanSILFunctionType SubstCalleeType,
ArrayRef<Substitution> Subs,
const HeapLayout &Layout) {
if (!IRGen.Opts.EnableReflectionMetadata)
return llvm::Constant::getNullValue(CaptureDescriptorPtrTy);
CaptureDescriptorBuilder builder(*this, Caller,
OrigCalleeType, SubstCalleeType, Subs,
Layout);
auto var = builder.emit();
if (var)
addUsedGlobal(var);
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,
const Substitution &Sub,
const TypeDecl *TD) -> bool {
auto Subst = ArchetypeBuilder::mapTypeOutOfContext(
Conformance->getDeclContext(), Sub.getReplacement());
AssociatedTypes.push_back({
AssocTy->getNameStr(),
Subst->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);
auto var = builder.emit();
if (var)
addUsedGlobal(var);
}
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(
TupleType::getEmpty(Context),
TupleType::getEmpty(Context),
AnyFunctionType::ExtInfo().withRepresentation(
FunctionTypeRepresentation::Thin));
BuiltinTypes.insert(thinFunction);
CanType anyMetatype = CanExistentialMetatypeType::get(
ProtocolCompositionType::get(Context, {})->getCanonicalType());
BuiltinTypes.insert(anyMetatype);
}
for (auto CD : ImportedClasses)
emitFieldMetadataRecord(CD);
for (auto PD : ImportedProtocols)
emitFieldMetadataRecord(PD);
FixedTypeMetadataBuilder builder(*this);
auto var = builder.emit();
if (var)
addUsedGlobal(var);
}
void IRGenModule::emitFieldMetadataRecord(const NominalTypeDecl *Decl) {
if (!IRGen.Opts.EnableReflectionMetadata)
return;
FieldTypeMetadataBuilder builder(*this, Decl);
auto var = builder.emit();
if (var)
addUsedGlobal(var);
}