| //===--- 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/GenericEnvironment.h" |
| #include "swift/AST/IRGenOptions.h" |
| #include "swift/AST/PrettyStackTrace.h" |
| #include "swift/AST/ProtocolConformance.h" |
| #include "swift/AST/SubstitutionMap.h" |
| #include "swift/Basic/Platform.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 "Explosion.h" |
| #include "GenClass.h" |
| #include "GenDecl.h" |
| #include "GenEnum.h" |
| #include "GenHeap.h" |
| #include "GenProto.h" |
| #include "GenType.h" |
| #include "IRGenDebugInfo.h" |
| #include "IRGenFunction.h" |
| #include "IRGenMangler.h" |
| #include "IRGenModule.h" |
| #include "LoadableTypeInfo.h" |
| #include "MetadataRequest.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(); |
| } |
| }; |
| |
| // Return the minimum Swift runtime version that supports demangling a given |
| // type. |
| static llvm::VersionTuple |
| getRuntimeVersionThatSupportsDemanglingType(IRGenModule &IGM, |
| CanType type) { |
| // Associated types of opaque types weren't mangled in a usable form by the |
| // Swift 5.1 runtime, so we needed to add a new mangling in 5.2. |
| if (type->hasOpaqueArchetype()) { |
| auto hasOpaqueAssocType = type.findIf([](CanType t) -> bool { |
| if (auto a = dyn_cast<NestedArchetypeType>(t)) { |
| return isa<OpaqueTypeArchetypeType>(a->getRoot()); |
| } |
| return false; |
| }); |
| |
| if (hasOpaqueAssocType) |
| return llvm::VersionTuple(5, 2); |
| // Although opaque types in general were only added in Swift 5.1, |
| // declarations that use them are already covered by availability |
| // guards, so we don't need to limit availability of mangled names |
| // involving them. |
| } |
| |
| return llvm::VersionTuple(5, 0); |
| } |
| |
| // Produce a fallback mangled type name that uses an open-coded callback |
| // to form the metadata. This is useful for working around bugs in older |
| // runtimes, or supporting new type system features when deploying back. |
| // |
| // Note that this functionality is limited, because the demangler callback |
| // mechanism can only produce complete metadata. It can't be used in situations |
| // where completing the metadata during demangling might cause cyclic |
| // dependencies. |
| static std::pair<llvm::Constant *, unsigned> |
| getTypeRefByFunction(IRGenModule &IGM, |
| CanGenericSignature sig, |
| CanType t) { |
| IRGenMangler mangler; |
| std::string symbolName = |
| mangler.mangleSymbolNameForMangledMetadataAccessorString( |
| "get_type_metadata", sig, t); |
| auto constant = IGM.getAddrOfStringForMetadataRef(symbolName, /*align*/2, |
| /*low bit*/false, |
| [&](ConstantInitBuilder &B) { |
| llvm::Function *accessor; |
| |
| // Otherwise, we need to emit a helper function to bind the arguments |
| // out of the demangler's argument buffer. |
| auto fnTy = llvm::FunctionType::get(IGM.TypeMetadataPtrTy, |
| {IGM.Int8PtrTy}, /*vararg*/ false); |
| accessor = |
| llvm::Function::Create(fnTy, llvm::GlobalValue::PrivateLinkage, |
| symbolName, IGM.getModule()); |
| accessor->setAttributes(IGM.constructInitialAttributes()); |
| |
| SmallVector<GenericRequirement, 4> requirements; |
| GenericEnvironment *genericEnv = nullptr; |
| if (sig) { |
| enumerateGenericSignatureRequirements(sig, |
| [&](GenericRequirement reqt) { requirements.push_back(reqt); }); |
| genericEnv = sig->getGenericEnvironment(); |
| } |
| |
| { |
| IRGenFunction IGF(IGM, accessor); |
| if (IGM.DebugInfo) |
| IGM.DebugInfo->emitArtificialFunction(IGF, accessor); |
| |
| auto bindingsBufPtr = IGF.collectParameters().claimNext(); |
| |
| auto substT = genericEnv |
| ? genericEnv->mapTypeIntoContext(t)->getCanonicalType() |
| : t; |
| |
| bindFromGenericRequirementsBuffer(IGF, requirements, |
| Address(bindingsBufPtr, IGM.getPointerAlignment()), |
| MetadataState::Complete, |
| [&](CanType t) { |
| return genericEnv |
| ? genericEnv->mapTypeIntoContext(t)->getCanonicalType() |
| : t; |
| }); |
| |
| auto ret = IGF.emitTypeMetadataRef(substT); |
| IGF.Builder.CreateRet(ret); |
| } |
| // Form the mangled name with its relative reference. |
| auto S = B.beginStruct(); |
| S.setPacked(true); |
| S.add(llvm::ConstantInt::get(IGM.Int8Ty, 255)); |
| S.add(llvm::ConstantInt::get(IGM.Int8Ty, 9)); |
| S.addRelativeAddress(accessor); |
| |
| // And a null terminator! |
| S.addInt(IGM.Int8Ty, 0); |
| |
| return S.finishAndCreateFuture(); |
| }); |
| return {constant, 6}; |
| } |
| |
| static std::pair<llvm::Constant *, unsigned> |
| getTypeRefImpl(IRGenModule &IGM, |
| CanType type, |
| CanGenericSignature sig, |
| MangledTypeRefRole role) { |
| switch (role) { |
| case MangledTypeRefRole::DefaultAssociatedTypeWitness: |
| case MangledTypeRefRole::Metadata: |
| // Note that we're using all of the nominal types referenced by this type, |
| // ensuring that we can always reconstruct type metadata from a mangled name |
| // in-process. |
| IGM.IRGen.noteUseOfTypeMetadata(type); |
| |
| // If the minimum deployment target's runtime demangler wouldn't understand |
| // this mangled name, then fall back to generating a "mangled name" with a |
| // symbolic reference with a callback function. |
| if (auto runtimeCompatVersion = getSwiftRuntimeCompatibilityVersionForTarget |
| (IGM.Context.LangOpts.Target)) { |
| if (*runtimeCompatVersion < |
| getRuntimeVersionThatSupportsDemanglingType(IGM, type)) { |
| return getTypeRefByFunction(IGM, sig, type); |
| } |
| } |
| |
| break; |
| |
| case MangledTypeRefRole::Reflection: |
| // For reflection records only used for out-of-process reflection, we do not |
| // need to force emission of runtime type metadata. |
| IGM.IRGen.noteUseOfFieldDescriptors(type); |
| break; |
| } |
| |
| IRGenMangler Mangler; |
| auto SymbolicName = Mangler.mangleTypeForReflection(IGM, type); |
| return {IGM.getAddrOfStringForTypeRef(SymbolicName, role), |
| SymbolicName.runtimeSizeInBytes()}; |
| } |
| |
| std::pair<llvm::Constant *, unsigned> |
| IRGenModule::getTypeRef(CanType type, CanGenericSignature sig, |
| MangledTypeRefRole role) { |
| type = substOpaqueTypesWithUnderlyingTypes(type); |
| return getTypeRefImpl(*this, type, sig, role); |
| } |
| |
| std::pair<llvm::Constant *, unsigned> |
| IRGenModule::getTypeRef(Type type, GenericSignature genericSig, |
| MangledTypeRefRole role) { |
| return getTypeRef(type->getCanonicalType(genericSig), |
| genericSig ? genericSig->getCanonicalSignature() : CanGenericSignature(), |
| role); |
| } |
| |
| std::pair<llvm::Constant *, unsigned> |
| IRGenModule::getLoweredTypeRef(SILType loweredType, |
| CanGenericSignature genericSig, |
| MangledTypeRefRole role) { |
| auto substTy = |
| substOpaqueTypesWithUnderlyingTypes(loweredType, genericSig); |
| auto type = substTy.getASTType(); |
| if (substTy.hasArchetype()) |
| type = type->mapTypeOutOfContext()->getCanonicalType(); |
| |
| return getTypeRefImpl(*this, type, genericSig, role); |
| } |
| |
| /// Emit a mangled string referencing a specific protocol conformance, so that |
| /// the runtime can fetch its witness table. |
| /// |
| /// TODO: Currently this uses a stub mangling that just refers to an accessor |
| /// function. We need to fully develop the mangling with the ability to refer |
| /// to dependent conformances to be able to use mangled strings. |
| llvm::Constant * |
| IRGenModule::emitWitnessTableRefString(CanType type, |
| ProtocolConformanceRef conformance, |
| GenericSignature origGenericSig, |
| bool shouldSetLowBit) { |
| std::tie(type, conformance) |
| = substOpaqueTypesWithUnderlyingTypes(type, conformance); |
| |
| auto origType = type; |
| CanGenericSignature genericSig; |
| SmallVector<GenericRequirement, 4> requirements; |
| GenericEnvironment *genericEnv = nullptr; |
| |
| if (origGenericSig) { |
| genericSig = origGenericSig->getCanonicalSignature(); |
| enumerateGenericSignatureRequirements(genericSig, |
| [&](GenericRequirement reqt) { requirements.push_back(reqt); }); |
| genericEnv = genericSig->getGenericEnvironment(); |
| } |
| |
| IRGenMangler mangler; |
| std::string symbolName = |
| mangler.mangleSymbolNameForMangledConformanceAccessorString( |
| "get_witness_table", genericSig, type, conformance); |
| |
| return getAddrOfStringForMetadataRef(symbolName, /*alignment=*/2, |
| shouldSetLowBit, |
| [&](ConstantInitBuilder &B) { |
| // Build a stub that loads the necessary bindings from the key path's |
| // argument buffer then fetches the metadata. |
| auto fnTy = llvm::FunctionType::get(WitnessTablePtrTy, |
| {Int8PtrTy}, /*vararg*/ false); |
| auto accessorThunk = |
| llvm::Function::Create(fnTy, llvm::GlobalValue::PrivateLinkage, |
| symbolName, getModule()); |
| accessorThunk->setAttributes(constructInitialAttributes()); |
| |
| { |
| IRGenFunction IGF(*this, accessorThunk); |
| if (DebugInfo) |
| DebugInfo->emitArtificialFunction(IGF, accessorThunk); |
| |
| if (type->hasTypeParameter()) { |
| auto bindingsBufPtr = IGF.collectParameters().claimNext(); |
| |
| bindFromGenericRequirementsBuffer(IGF, requirements, |
| Address(bindingsBufPtr, getPointerAlignment()), |
| MetadataState::Complete, |
| [&](CanType t) { |
| return genericEnv->mapTypeIntoContext(t)->getCanonicalType(); |
| }); |
| |
| type = genericEnv->mapTypeIntoContext(type)->getCanonicalType(); |
| } |
| if (origType->hasTypeParameter()) { |
| auto origSig = genericEnv->getGenericSignature(); |
| conformance = conformance.subst(origType, |
| QueryInterfaceTypeSubstitutions(genericEnv), |
| LookUpConformanceInSignature(origSig.getPointer())); |
| } |
| auto ret = emitWitnessTableRef(IGF, type, conformance); |
| IGF.Builder.CreateRet(ret); |
| } |
| |
| // Form the mangled name with its relative reference. |
| auto S = B.beginStruct(); |
| S.setPacked(true); |
| S.add(llvm::ConstantInt::get(Int8Ty, 255)); |
| S.add(llvm::ConstantInt::get(Int8Ty, 9)); |
| S.addRelativeAddress(accessorThunk); |
| |
| // And a null terminator! |
| S.addInt(Int8Ty, 0); |
| |
| return S.finishAndCreateFuture(); |
| }); |
| } |
| |
| |
| llvm::Constant *IRGenModule::getMangledAssociatedConformance( |
| const NormalProtocolConformance *conformance, |
| const AssociatedConformance &requirement) { |
| // Figure out the name of the symbol to be used for the conformance. |
| IRGenMangler mangler; |
| auto symbolName = |
| mangler.mangleSymbolNameForAssociatedConformanceWitness( |
| conformance, requirement.getAssociation(), |
| requirement.getAssociatedRequirement()); |
| |
| // See if we emitted the constant already. |
| auto &entry = StringsForTypeRef[symbolName]; |
| if (entry.second) { |
| return entry.second; |
| } |
| |
| // Get the accessor for this associated conformance. |
| llvm::Function *accessor; |
| unsigned char kind; |
| if (conformance) { |
| kind = 7; |
| accessor = getAddrOfAssociatedTypeWitnessTableAccessFunction(conformance, |
| requirement); |
| } else { |
| kind = 8; |
| accessor = getAddrOfDefaultAssociatedConformanceAccessor(requirement); |
| } |
| |
| // Form the mangled name with its relative reference. |
| ConstantInitBuilder B(*this); |
| auto S = B.beginStruct(); |
| S.setPacked(true); |
| S.add(llvm::ConstantInt::get(Int8Ty, 255)); |
| S.add(llvm::ConstantInt::get(Int8Ty, kind)); |
| S.addRelativeAddress(accessor); |
| |
| // And a null terminator! |
| S.addInt(Int8Ty, 0); |
| |
| auto finished = S.finishAndCreateFuture(); |
| auto var = new llvm::GlobalVariable(Module, finished.getType(), |
| /*constant*/ true, |
| llvm::GlobalValue::LinkOnceODRLinkage, |
| nullptr, |
| symbolName); |
| ApplyIRLinkage(IRLinkage::InternalLinkOnceODR).to(var); |
| var->setAlignment(2); |
| setTrueConstGlobal(var); |
| var->setSection(getReflectionTypeRefSectionName()); |
| |
| finished.installInGlobal(var); |
| |
| // Drill down to the i8* at the beginning of the constant. |
| auto addr = llvm::ConstantExpr::getBitCast(var, Int8PtrTy); |
| |
| // Set the low bit. |
| unsigned bit = ProtocolRequirementFlags::AssociatedTypeMangledNameBit; |
| auto bitConstant = llvm::ConstantInt::get(IntPtrTy, bit); |
| addr = llvm::ConstantExpr::getGetElementPtr(nullptr, addr, bitConstant); |
| |
| // Update the entry. |
| entry = {var, addr}; |
| |
| return addr; |
| } |
| |
| 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) { |
| if (IGM.getSwiftModule()->isStdlibModule()) { |
| type.visit([&](CanType t) { |
| if (isa<BuiltinType>(t)) |
| IGM.BuiltinTypes.insert(t); |
| }); |
| } |
| } |
| |
| /// Add a 32-bit relative offset to a mangled typeref string |
| /// in the typeref reflection section. |
| /// |
| /// By default, we use MangledTypeRefRole::Reflection, which does not |
| /// force emission of any type metadata referenced from the typeref. |
| /// |
| /// For reflection records which are demangled to produce type metadata |
| /// in-process, pass MangledTypeRefRole::Metadata instead. |
| void addTypeRef(Type type, GenericSignature genericSig, |
| MangledTypeRefRole role = |
| MangledTypeRefRole::Reflection) { |
| addTypeRef(type->getCanonicalType(genericSig), |
| genericSig ? genericSig->getCanonicalSignature() |
| : CanGenericSignature(), |
| role); |
| } |
| |
| /// Add a 32-bit relative offset to a mangled typeref string |
| /// in the typeref reflection section. |
| /// |
| /// By default, we use MangledTypeRefRole::Reflection, which does not |
| /// force emission of any type metadata referenced from the typeref. |
| /// |
| /// For reflection records which are demangled to produce type metadata |
| /// in-process, pass MangledTypeRefRole::Metadata instead. |
| void addTypeRef(CanType type, |
| CanGenericSignature sig, |
| MangledTypeRefRole role = |
| MangledTypeRefRole::Reflection) { |
| B.addRelativeAddress(IGM.getTypeRef(type, sig, role).first); |
| addBuiltinTypeRefs(type); |
| } |
| |
| void |
| addLoweredTypeRef(SILType loweredType, |
| CanGenericSignature genericSig, |
| MangledTypeRefRole role = MangledTypeRefRole::Reflection) { |
| B.addRelativeAddress( |
| IGM.getLoweredTypeRef(loweredType, genericSig, role).first); |
| addBuiltinTypeRefs(loweredType.getASTType()); |
| } |
| |
| /// Add a 32-bit relative offset to a mangled nominal type string |
| /// in the typeref reflection section. |
| /// |
| /// See above comment about 'role'. |
| void addNominalRef(const NominalTypeDecl *nominal, |
| MangledTypeRefRole role = |
| MangledTypeRefRole::Reflection) { |
| if (auto proto = dyn_cast<ProtocolDecl>(nominal)) { |
| IRGenMangler mangler; |
| SymbolicMangling mangledStr; |
| mangledStr.String = mangler.mangleBareProtocol(proto); |
| auto mangledName = |
| IGM.getAddrOfStringForTypeRef(mangledStr, role); |
| B.addRelativeAddress(mangledName); |
| } else { |
| addTypeRef(nominal->getDeclaredType(), GenericSignature(), role); |
| } |
| } |
| |
| // A function signature for a lambda wrapping an IRGenModule::getAddrOf* |
| // method. |
| using GetAddrOfEntityFn = llvm::Constant* (IRGenModule &, ConstantInit); |
| |
| llvm::GlobalVariable *emit( |
| Optional<llvm::function_ref<GetAddrOfEntityFn>> getAddr, |
| const char *section) { |
| layout(); |
| |
| llvm::GlobalVariable *var; |
| |
| // Some reflection records have a mangled symbol name, for uniquing |
| // imported type metadata. |
| if (getAddr) { |
| auto init = B.finishAndCreateFuture(); |
| |
| var = cast<llvm::GlobalVariable>((*getAddr)(IGM, init)); |
| var->setConstant(true); |
| // 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; |
| } |
| |
| // Helpers to guide the C++ type system into converting lambda arguments |
| // to Optional<function_ref> |
| llvm::GlobalVariable *emit(llvm::function_ref<GetAddrOfEntityFn> getAddr, |
| const char *section) { |
| return emit(Optional<llvm::function_ref<GetAddrOfEntityFn>>(getAddr), |
| section); |
| } |
| llvm::GlobalVariable *emit(NoneType none, |
| const char *section) { |
| return emit(Optional<llvm::function_ref<GetAddrOfEntityFn>>(), |
| section); |
| } |
| |
| 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); |
| |
| addNominalRef(Nominal); |
| addNominalRef(Conformance->getProtocol()); |
| |
| B.addInt32(AssociatedTypes.size()); |
| B.addInt32(AssociatedTypeRecordSize); |
| |
| for (auto AssocTy : AssociatedTypes) { |
| auto NameGlobal = IGM.getAddrOfFieldName(AssocTy.first); |
| B.addRelativeAddress(NameGlobal); |
| addTypeRef(AssocTy.second, |
| Nominal->getGenericSignature() |
| ? Nominal->getGenericSignature()->getCanonicalSignature() |
| : CanGenericSignature()); |
| } |
| } |
| |
| public: |
| AssociatedTypeMetadataBuilder(IRGenModule &IGM, |
| const ProtocolConformance *Conformance, |
| ArrayRef<std::pair<StringRef, CanType>> AssociatedTypes) |
| : ReflectionMetadataBuilder(IGM), Conformance(Conformance), |
| AssociatedTypes(AssociatedTypes) {} |
| |
| llvm::GlobalVariable *emit() { |
| auto section = IGM.getAssociatedTypeMetadataSectionName(); |
| return ReflectionMetadataBuilder::emit( |
| [&](IRGenModule &IGM, ConstantInit init) -> llvm::Constant* { |
| return IGM.getAddrOfReflectionAssociatedTypeDescriptor(Conformance,init); |
| }, |
| section); |
| } |
| }; |
| |
| class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder { |
| const uint32_t fieldRecordSize = 12; |
| const NominalTypeDecl *NTD; |
| |
| void addFieldDecl(const ValueDecl *value, Type type, |
| GenericSignature genericSig, 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 { |
| // The standard library's Mirror demangles metadata from field |
| // descriptors, so use MangledTypeRefRole::Metadata to ensure |
| // runtime metadata is available. |
| addTypeRef(type, genericSig, MangledTypeRefRole::Metadata); |
| } |
| |
| 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 = type->getReferenceCounting(); |
| if (RC == ReferenceCounting::ObjC) |
| kind = FieldDescriptorKind::ObjCClass; |
| else |
| kind = FieldDescriptorKind::Class; |
| } |
| |
| B.addInt16(uint16_t(kind)); |
| B.addInt16(fieldRecordSize); |
| |
| auto properties = NTD->getStoredProperties(); |
| B.addInt32(properties.size()); |
| for (auto property : properties) |
| addFieldDecl(property, property->getInterfaceType(), |
| NTD->getGenericSignature()); |
| } |
| |
| void layoutEnum() { |
| auto enumDecl = cast<EnumDecl>(NTD); |
| auto &strategy = irgen::getEnumImplStrategy( |
| IGM, enumDecl->getDeclaredTypeInContext() |
| ->getCanonicalType()); |
| |
| auto kind = FieldDescriptorKind::Enum; |
| |
| if (strategy.getElementsWithPayload().size() > 1 && |
| !strategy.needsPayloadSizeInMetadata()) { |
| kind = FieldDescriptorKind::MultiPayloadEnum; |
| } |
| |
| 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(), |
| enumDecl->getGenericSignature(), |
| indirect); |
| } |
| |
| for (auto enumCase : strategy.getElementsWithNoPayload()) { |
| addFieldDecl(enumCase.decl, CanType(), nullptr); |
| } |
| } |
| |
| void layoutProtocol() { |
| auto PD = cast<ProtocolDecl>(NTD); |
| FieldDescriptorKind Kind; |
| if (PD->isObjC()) |
| Kind = FieldDescriptorKind::ObjCProtocol; |
| else if (PD->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()) { |
| auto *enumDecl = dyn_cast<EnumDecl>(NTD); |
| // Structs and namespace-like enums are ok. |
| assert(isa<StructDecl>(NTD) || (enumDecl && !enumDecl->hasCases())); |
| } |
| |
| PrettyStackTraceDecl DebugStack("emitting field type metadata", NTD); |
| addNominalRef(NTD); |
| |
| auto *CD = dyn_cast<ClassDecl>(NTD); |
| auto *PD = dyn_cast<ProtocolDecl>(NTD); |
| if (CD && CD->getSuperclass()) { |
| addTypeRef(CD->getSuperclass(), CD->getGenericSignature()); |
| } else if (PD && PD->getDeclaredType()->getSuperclass()) { |
| addTypeRef(PD->getDeclaredType()->getSuperclass(), |
| PD->getGenericSignature()); |
| } 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 section = IGM.getFieldTypeMetadataSectionName(); |
| return ReflectionMetadataBuilder::emit( |
| [&](IRGenModule &IGM, ConstantInit definition) -> llvm::Constant* { |
| return IGM.getAddrOfReflectionFieldDescriptor( |
| NTD->getDeclaredType()->getCanonicalType(), definition); |
| }, |
| 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 { |
| if (type->isAnyObject()) { |
| // AnyObject isn't actually a builtin type; we're emitting it as the old |
| // Builtin.UnknownObject type for ABI compatibility. |
| B.addRelativeAddress( |
| IGM.getAddrOfStringForTypeRef("BO", MangledTypeRefRole::Reflection)); |
| } else { |
| addTypeRef(type, CanGenericSignature()); |
| } |
| |
| B.addInt32(ti->getFixedSize().getValue()); |
| |
| auto alignment = ti->getFixedAlignment().getValue(); |
| unsigned bitwiseTakable = |
| (ti->isBitwiseTakable(ResilienceExpansion::Minimal) == IsBitwiseTakable |
| ? 1 : 0); |
| B.addInt32(alignment | (bitwiseTakable << 16)); |
| |
| B.addInt32(ti->getFixedStride().getValue()); |
| B.addInt32(ti->getFixedExtraInhabitantCount(IGM)); |
| } |
| |
| llvm::GlobalVariable *emit() { |
| auto section = IGM.getBuiltinTypeMetadataSectionName(); |
| return ReflectionMetadataBuilder::emit( |
| [&](IRGenModule &IGM, ConstantInit definition) -> llvm::Constant * { |
| return IGM.getAddrOfReflectionBuiltinDescriptor(type, definition); |
| }, |
| section); |
| } |
| }; |
| |
| void IRGenModule::emitBuiltinTypeMetadataRecord(CanType builtinType) { |
| FixedTypeMetadataBuilder builder(*this, builtinType); |
| builder.emit(); |
| } |
| |
| /// 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 { |
| SILType BoxedType; |
| CanGenericSignature genericSig; |
| public: |
| BoxDescriptorBuilder(IRGenModule &IGM, SILType BoxedType, |
| CanGenericSignature genericSig) |
| : ReflectionMetadataBuilder(IGM), BoxedType(BoxedType), |
| genericSig(genericSig) {} |
| |
| void layout() override { |
| B.addInt32(1); |
| B.addInt32(0); // Number of sources |
| B.addInt32(0); // Number of generic bindings |
| |
| addLoweredTypeRef(BoxedType, genericSig); |
| } |
| |
| 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. |
| /// |
| /// For now capture descriptors are only used by out-of-process reflection. |
| /// |
| /// If the standard library's Mirror type ever gains the ability to reflect |
| /// closure contexts, we should use MangledTypeRefRole::Metadata below. |
| 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(), MangledTypeRefRole::Reflection); |
| 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<SILType> getCaptureTypes() { |
| std::vector<SILType> 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(); |
| } |
| |
| CaptureTypes.push_back( |
| SILType::getPrimitiveObjectType(SwiftType->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()); |
| |
| auto sig = OrigCalleeType->getGenericSignature() |
| ? OrigCalleeType->getGenericSignature()->getCanonicalSignature() |
| : CanGenericSignature(); |
| |
| // Now add typerefs of all of the captures. |
| for (auto CaptureType : CaptureTypes) { |
| addLoweredTypeRef(CaptureType, sig); |
| } |
| |
| // 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, sig); |
| 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::XCOFF: |
| 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: |
| case llvm::Triple::Wasm: |
| 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; |
| } |
| 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(SILType BoxedType, |
| CanGenericSignature genericSig) { |
| if (!IRGen.Opts.EnableReflectionMetadata) |
| return llvm::Constant::getNullValue(CaptureDescriptorPtrTy); |
| |
| BoxDescriptorBuilder builder(*this, BoxedType, genericSig); |
| 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 RootProtocolConformance *conformance) { |
| auto normalConf = dyn_cast<NormalProtocolConformance>(conformance); |
| if (!normalConf) |
| return; |
| |
| 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; |
| }; |
| |
| normalConf->forEachTypeWitness(collectTypeWitness); |
| |
| // If there are no associated types, don't bother emitting any |
| // metadata. |
| if (AssociatedTypes.empty()) |
| return; |
| |
| AssociatedTypeMetadataBuilder builder(*this, normalConf, AssociatedTypes); |
| builder.emit(); |
| } |
| |
| void IRGenModule::emitBuiltinReflectionMetadata() { |
| if (getSwiftModule()->isStdlibModule()) { |
| BuiltinTypes.insert(Context.TheNativeObjectType); |
| BuiltinTypes.insert(Context.getAnyObjectType()); |
| 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( |
| {}, Context.TheEmptyTupleType, |
| AnyFunctionType::ExtInfo().withRepresentation( |
| FunctionTypeRepresentation::Thin)); |
| BuiltinTypes.insert(thinFunction); |
| |
| CanType anyMetatype = CanExistentialMetatypeType::get( |
| Context.TheAnyType); |
| BuiltinTypes.insert(anyMetatype); |
| } |
| |
| for (auto builtinType : BuiltinTypes) |
| emitBuiltinTypeMetadataRecord(builtinType); |
| } |
| |
| void IRGenerator::emitBuiltinReflectionMetadata() { |
| for (auto &m : *this) { |
| m.second->emitBuiltinReflectionMetadata(); |
| } |
| } |
| |
| void IRGenModule::emitFieldDescriptor(const NominalTypeDecl *D) { |
| if (!IRGen.Opts.EnableReflectionMetadata) |
| return; |
| |
| auto T = D->getDeclaredTypeInContext()->getCanonicalType(); |
| |
| bool needsOpaqueDescriptor = false; |
| bool needsFieldDescriptor = true; |
| |
| if (auto *ED = dyn_cast<EnumDecl>(D)) { |
| auto &strategy = getEnumImplStrategy(*this, T); |
| |
| // @objc enums never have generic parameters or payloads, |
| // and lower as their raw type. |
| if (!strategy.isReflectable()) { |
| needsOpaqueDescriptor = true; |
| needsFieldDescriptor = false; |
| } |
| |
| // 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()) { |
| needsOpaqueDescriptor = true; |
| } |
| } |
| |
| if (auto *SD = dyn_cast<StructDecl>(D)) { |
| if (SD->hasClangNode()) |
| needsOpaqueDescriptor = true; |
| } |
| |
| // If the type has custom @_alignment, emit a fixed record with the |
| // alignment since remote mirrors will need to treat the type as opaque. |
| // |
| // Note that we go on to also emit a field descriptor in this case, |
| // since in-process reflection only cares about the types of the fields |
| // and does not independently re-derive the layout. |
| if (D->getAttrs().hasAttribute<AlignmentAttr>()) { |
| auto &TI = getTypeInfoForUnlowered(T); |
| if (isa<FixedTypeInfo>(TI)) { |
| needsOpaqueDescriptor = true; |
| } |
| } |
| |
| if (needsOpaqueDescriptor) { |
| FixedTypeMetadataBuilder builder(*this, D); |
| builder.emit(); |
| } |
| |
| if (needsFieldDescriptor) { |
| FieldTypeMetadataBuilder builder(*this, D); |
| 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"); |
| ApplyIRLinkage(IRLinkage::InternalLinkOnceODR).to(Version); |
| addUsedGlobal(Version); |
| } |
| |
| void IRGenerator::emitReflectionMetadataVersion() { |
| for (auto &m : *this) { |
| m.second->emitReflectionMetadataVersion(); |
| } |
| } |