//===--- 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 { 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 { 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 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()) 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(Nominal)) IGM.ImportedClasses.insert(CD); else if (auto PD = dyn_cast(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> 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> AssociatedTypes) : ReflectionMetadataBuilder(IGM), Conformance(Conformance), AssociatedTypes(AssociatedTypes) {} llvm::GlobalVariable *emit() { auto tempBase = std::unique_ptr( 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(NTD)) { auto RC = getReferenceCountingForClass(IGM, const_cast(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(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(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(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(NTD) && !isa(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( 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(IGM.getTypeInfoForUnlowered(builtinType)); addFixedType(builtinType->getASTContext().TheBuiltinModule, builtinType, ti); } void addOpaqueType(const NominalTypeDecl *nominalDecl) { auto &ti = cast(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( 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( 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 Subs; const HeapLayout &Layout; public: CaptureDescriptorBuilder(IRGenModule &IGM, SILFunction &Caller, CanSILFunctionType OrigCalleeType, CanSILFunctionType SubstCalleeType, ArrayRef Subs, const HeapLayout &Layout) : ReflectionMetadataBuilder(IGM), Caller(Caller), OrigCalleeType(OrigCalleeType), SubstCalleeType(SubstCalleeType), Subs(Subs), Layout(Layout) {} using MetadataSourceMap = std::vector>; 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 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 getCaptureTypes() { std::vector 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( 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 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, 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); } 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); }