| //===--- GenDecl.cpp - IR Generation for Declarations ---------------------===// |
| // |
| // 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 for local and global |
| // declarations in Swift. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "swift/AST/ASTContext.h" |
| #include "swift/AST/Decl.h" |
| #include "swift/AST/DiagnosticEngine.h" |
| #include "swift/AST/GenericEnvironment.h" |
| #include "swift/AST/GenericSignature.h" |
| #include "swift/AST/IRGenOptions.h" |
| #include "swift/AST/Module.h" |
| #include "swift/AST/NameLookup.h" |
| #include "swift/AST/Pattern.h" |
| #include "swift/AST/ProtocolConformance.h" |
| #include "swift/AST/TypeMemberVisitor.h" |
| #include "swift/AST/Types.h" |
| #include "swift/ClangImporter/ClangModule.h" |
| #include "swift/Demangling/ManglingMacros.h" |
| #include "swift/IRGen/Linking.h" |
| #include "swift/Runtime/HeapObject.h" |
| #include "swift/SIL/FormalLinkage.h" |
| #include "swift/SIL/SILDebugScope.h" |
| #include "swift/SIL/SILModule.h" |
| #include "swift/Subsystems.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/DeclCXX.h" |
| #include "clang/AST/GlobalDecl.h" |
| #include "clang/CodeGen/CodeGenABITypes.h" |
| #include "clang/CodeGen/ModuleBuilder.h" |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/IR/DerivedTypes.h" |
| #include "llvm/IR/GlobalAlias.h" |
| #include "llvm/IR/InlineAsm.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/IR/Value.h" |
| #include "llvm/Support/Compiler.h" |
| #include "llvm/Support/ConvertUTF.h" |
| #include "llvm/Support/Path.h" |
| #include "llvm/Support/SaveAndRestore.h" |
| #include "llvm/Target/TargetMachine.h" |
| #include "llvm/Transforms/Utils/ModuleUtils.h" |
| |
| #include "Callee.h" |
| #include "ConformanceDescription.h" |
| #include "ConstantBuilder.h" |
| #include "Explosion.h" |
| #include "FixedTypeInfo.h" |
| #include "GenCall.h" |
| #include "GenClass.h" |
| #include "GenDecl.h" |
| #include "GenMeta.h" |
| #include "GenObjC.h" |
| #include "GenOpaque.h" |
| #include "GenPointerAuth.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" |
| #include "ProtocolInfo.h" |
| #include "Signature.h" |
| #include "StructLayout.h" |
| |
| using namespace swift; |
| using namespace irgen; |
| |
| llvm::cl::opt<bool> UseBasicDynamicReplacement( |
| "basic-dynamic-replacement", llvm::cl::init(false), |
| llvm::cl::desc("Basic implementation of dynamic replacement")); |
| |
| namespace { |
| |
| /// Add methods, properties, and protocol conformances from a JITed extension |
| /// to an ObjC class using the ObjC runtime. |
| /// |
| /// This must happen after ObjCProtocolInitializerVisitor if any @objc protocols |
| /// were defined in the TU. |
| class CategoryInitializerVisitor |
| : public ClassMemberVisitor<CategoryInitializerVisitor> |
| { |
| IRGenFunction &IGF; |
| IRGenModule &IGM = IGF.IGM; |
| IRBuilder &Builder = IGF.Builder; |
| |
| llvm::Constant *class_replaceMethod; |
| llvm::Constant *class_addProtocol; |
| |
| llvm::Value *classMetadata; |
| llvm::Constant *metaclassMetadata; |
| |
| public: |
| CategoryInitializerVisitor(IRGenFunction &IGF, ExtensionDecl *ext) |
| : IGF(IGF) |
| { |
| class_replaceMethod = IGM.getClassReplaceMethodFn(); |
| class_addProtocol = IGM.getClassAddProtocolFn(); |
| |
| CanType origTy = ext->getSelfNominalTypeDecl() |
| ->getDeclaredType()->getCanonicalType(); |
| classMetadata = emitClassHeapMetadataRef(IGF, origTy, |
| MetadataValueType::ObjCClass, |
| MetadataState::Complete, |
| /*allow uninitialized*/ false); |
| classMetadata = Builder.CreateBitCast(classMetadata, IGM.ObjCClassPtrTy); |
| metaclassMetadata = IGM.getAddrOfMetaclassObject( |
| origTy.getClassOrBoundGenericClass(), |
| NotForDefinition); |
| metaclassMetadata = llvm::ConstantExpr::getBitCast(metaclassMetadata, |
| IGM.ObjCClassPtrTy); |
| |
| // Register ObjC protocol conformances. |
| for (auto *p : ext->getLocalProtocols()) { |
| if (!p->isObjC()) |
| continue; |
| |
| llvm::Value *protoRef = IGM.getAddrOfObjCProtocolRef(p, NotForDefinition); |
| auto proto = Builder.CreateLoad(protoRef, IGM.getPointerAlignment()); |
| Builder.CreateCall(class_addProtocol, {classMetadata, proto}); |
| } |
| } |
| |
| void visitMembers(ExtensionDecl *ext) { |
| for (Decl *member : ext->getMembers()) |
| visit(member); |
| } |
| |
| void visitTypeDecl(TypeDecl *type) { |
| // We'll visit nested types separately if necessary. |
| } |
| |
| void visitMissingMemberDecl(MissingMemberDecl *placeholder) {} |
| |
| void visitFuncDecl(FuncDecl *method) { |
| if (!requiresObjCMethodDescriptor(method)) return; |
| |
| // Don't emit getters/setters for @NSManaged methods. |
| if (method->getAttrs().hasAttribute<NSManagedAttr>()) |
| return; |
| |
| auto descriptor = emitObjCMethodDescriptorParts(IGM, method, |
| /*concrete*/true); |
| |
| // When generating JIT'd code, we need to call sel_registerName() to force |
| // the runtime to unique the selector. |
| llvm::Value *sel = Builder.CreateCall(IGM.getObjCSelRegisterNameFn(), |
| descriptor.selectorRef); |
| |
| llvm::Value *args[] = { |
| method->isStatic() ? metaclassMetadata : classMetadata, |
| sel, |
| descriptor.impl, |
| descriptor.typeEncoding |
| }; |
| |
| Builder.CreateCall(class_replaceMethod, args); |
| } |
| |
| // Can't be added in an extension. |
| void visitDestructorDecl(DestructorDecl *dtor) {} |
| |
| void visitConstructorDecl(ConstructorDecl *constructor) { |
| if (!requiresObjCMethodDescriptor(constructor)) return; |
| auto descriptor = emitObjCMethodDescriptorParts(IGM, constructor, |
| /*concrete*/true); |
| |
| // When generating JIT'd code, we need to call sel_registerName() to force |
| // the runtime to unique the selector. |
| llvm::Value *sel = Builder.CreateCall(IGM.getObjCSelRegisterNameFn(), |
| descriptor.selectorRef); |
| |
| llvm::Value *args[] = { |
| classMetadata, |
| sel, |
| descriptor.impl, |
| descriptor.typeEncoding |
| }; |
| |
| Builder.CreateCall(class_replaceMethod, args); |
| } |
| |
| void visitPatternBindingDecl(PatternBindingDecl *binding) { |
| // Ignore the PBD and just handle the individual vars. |
| } |
| |
| void visitVarDecl(VarDecl *prop) { |
| if (!requiresObjCPropertyDescriptor(IGM, prop)) return; |
| |
| // FIXME: register property metadata in addition to the methods. |
| // ObjC doesn't have a notion of class properties, so we'd only do this |
| // for instance properties. |
| |
| // Don't emit getters/setters for @NSManaged properties. |
| if (prop->getAttrs().hasAttribute<NSManagedAttr>()) |
| return; |
| |
| auto descriptor = emitObjCGetterDescriptorParts(IGM, prop); |
| // When generating JIT'd code, we need to call sel_registerName() to force |
| // the runtime to unique the selector. |
| llvm::Value *sel = Builder.CreateCall(IGM.getObjCSelRegisterNameFn(), |
| descriptor.selectorRef); |
| auto theClass = prop->isStatic() ? metaclassMetadata : classMetadata; |
| llvm::Value *getterArgs[] = |
| {theClass, sel, descriptor.impl, descriptor.typeEncoding}; |
| Builder.CreateCall(class_replaceMethod, getterArgs); |
| |
| if (prop->isSettable(prop->getDeclContext())) { |
| auto descriptor = emitObjCSetterDescriptorParts(IGM, prop); |
| sel = Builder.CreateCall(IGM.getObjCSelRegisterNameFn(), |
| descriptor.selectorRef); |
| llvm::Value *setterArgs[] = |
| {theClass, sel, descriptor.impl, descriptor.typeEncoding}; |
| |
| Builder.CreateCall(class_replaceMethod, setterArgs); |
| } |
| } |
| |
| void visitSubscriptDecl(SubscriptDecl *subscript) { |
| assert(!subscript->isStatic() && "objc doesn't support class subscripts"); |
| if (!requiresObjCSubscriptDescriptor(IGM, subscript)) return; |
| |
| auto descriptor = emitObjCGetterDescriptorParts(IGM, subscript); |
| // When generating JIT'd code, we need to call sel_registerName() to force |
| // the runtime to unique the selector. |
| llvm::Value *sel = Builder.CreateCall(IGM.getObjCSelRegisterNameFn(), |
| descriptor.selectorRef); |
| llvm::Value *getterArgs[] = |
| {classMetadata, sel, descriptor.impl, descriptor.typeEncoding}; |
| Builder.CreateCall(class_replaceMethod, getterArgs); |
| |
| if (subscript->supportsMutation()) { |
| auto descriptor = emitObjCSetterDescriptorParts(IGM, subscript); |
| sel = Builder.CreateCall(IGM.getObjCSelRegisterNameFn(), |
| descriptor.selectorRef); |
| llvm::Value *setterArgs[] = |
| {classMetadata, sel, descriptor.impl, descriptor.typeEncoding}; |
| |
| Builder.CreateCall(class_replaceMethod, setterArgs); |
| } |
| } |
| }; |
| |
| /// Create a descriptor for JITed @objc protocol using the ObjC runtime. |
| class ObjCProtocolInitializerVisitor |
| : public ClassMemberVisitor<ObjCProtocolInitializerVisitor> |
| { |
| IRGenFunction &IGF; |
| IRGenModule &IGM = IGF.IGM; |
| IRBuilder &Builder = IGF.Builder; |
| |
| llvm::Constant *objc_getProtocol, |
| *objc_allocateProtocol, |
| *objc_registerProtocol, |
| *protocol_addMethodDescription, |
| *protocol_addProtocol; |
| |
| llvm::Value *NewProto = nullptr; |
| |
| public: |
| ObjCProtocolInitializerVisitor(IRGenFunction &IGF) |
| : IGF(IGF) |
| { |
| objc_getProtocol = IGM.getGetObjCProtocolFn(); |
| objc_allocateProtocol = IGM.getAllocateObjCProtocolFn(); |
| objc_registerProtocol = IGM.getRegisterObjCProtocolFn(); |
| protocol_addMethodDescription = IGM.getProtocolAddMethodDescriptionFn(); |
| protocol_addProtocol = IGM.getProtocolAddProtocolFn(); |
| } |
| |
| void visitMembers(ProtocolDecl *proto) { |
| // Check if the ObjC runtime already has a descriptor for this |
| // protocol. If so, use it. |
| SmallString<32> buf; |
| auto protocolName |
| = IGM.getAddrOfGlobalString(proto->getObjCRuntimeName(buf)); |
| |
| auto existing = Builder.CreateCall(objc_getProtocol, protocolName); |
| auto isNull = Builder.CreateICmpEQ(existing, |
| llvm::ConstantPointerNull::get(IGM.ProtocolDescriptorPtrTy)); |
| |
| auto existingBB = IGF.createBasicBlock("existing_protocol"); |
| auto newBB = IGF.createBasicBlock("new_protocol"); |
| auto contBB = IGF.createBasicBlock("cont"); |
| Builder.CreateCondBr(isNull, newBB, existingBB); |
| |
| // Nothing to do if there's already a descriptor. |
| Builder.emitBlock(existingBB); |
| Builder.CreateBr(contBB); |
| |
| Builder.emitBlock(newBB); |
| |
| // Allocate the protocol descriptor. |
| NewProto = Builder.CreateCall(objc_allocateProtocol, protocolName); |
| |
| // Add the parent protocols. |
| for (auto parentProto : proto->getInheritedProtocols()) { |
| if (!parentProto->isObjC()) |
| continue; |
| llvm::Value *parentRef = IGM.getAddrOfObjCProtocolRef(parentProto, |
| NotForDefinition); |
| parentRef = IGF.Builder.CreateBitCast(parentRef, |
| IGM.ProtocolDescriptorPtrTy |
| ->getPointerTo()); |
| auto parent = Builder.CreateLoad(parentRef, |
| IGM.getPointerAlignment()); |
| Builder.CreateCall(protocol_addProtocol, {NewProto, parent}); |
| } |
| |
| // Add the members. |
| for (Decl *member : proto->getMembers()) |
| visit(member); |
| |
| // Register it. |
| Builder.CreateCall(objc_registerProtocol, NewProto); |
| Builder.CreateBr(contBB); |
| |
| // Store the reference to the runtime's idea of the protocol descriptor. |
| Builder.emitBlock(contBB); |
| auto result = Builder.CreatePHI(IGM.ProtocolDescriptorPtrTy, 2); |
| result->addIncoming(existing, existingBB); |
| result->addIncoming(NewProto, newBB); |
| |
| llvm::Value *ref = IGM.getAddrOfObjCProtocolRef(proto, NotForDefinition); |
| ref = IGF.Builder.CreateBitCast(ref, |
| IGM.ProtocolDescriptorPtrTy->getPointerTo()); |
| |
| Builder.CreateStore(result, ref, IGM.getPointerAlignment()); |
| } |
| |
| void visitTypeDecl(TypeDecl *type) { |
| // We'll visit nested types separately if necessary. |
| } |
| |
| void visitMissingMemberDecl(MissingMemberDecl *placeholder) {} |
| |
| void visitAbstractFunctionDecl(AbstractFunctionDecl *method) { |
| if (isa<AccessorDecl>(method)) { |
| // Accessors are handled as part of their AbstractStorageDecls. |
| return; |
| } |
| |
| auto descriptor = emitObjCMethodDescriptorParts(IGM, method, |
| /*concrete*/false); |
| |
| // When generating JIT'd code, we need to call sel_registerName() to force |
| // the runtime to unique the selector. |
| llvm::Value *sel = Builder.CreateCall(IGM.getObjCSelRegisterNameFn(), |
| descriptor.selectorRef); |
| |
| llvm::Value *args[] = { |
| NewProto, sel, descriptor.typeEncoding, |
| // required? |
| llvm::ConstantInt::get(IGM.ObjCBoolTy, |
| !method->getAttrs().hasAttribute<OptionalAttr>()), |
| // instance? |
| llvm::ConstantInt::get(IGM.ObjCBoolTy, |
| isa<ConstructorDecl>(method) || method->isInstanceMember()), |
| }; |
| |
| Builder.CreateCall(protocol_addMethodDescription, args); |
| } |
| |
| void visitPatternBindingDecl(PatternBindingDecl *binding) { |
| // Ignore the PBD and just handle the individual vars. |
| } |
| |
| void visitAbstractStorageDecl(AbstractStorageDecl *prop) { |
| // TODO: Add properties to protocol. |
| |
| auto descriptor = emitObjCGetterDescriptorParts(IGM, prop); |
| // When generating JIT'd code, we need to call sel_registerName() to force |
| // the runtime to unique the selector. |
| llvm::Value *sel = Builder.CreateCall(IGM.getObjCSelRegisterNameFn(), |
| descriptor.selectorRef); |
| llvm::Value *getterArgs[] = { |
| NewProto, sel, descriptor.typeEncoding, |
| // required? |
| llvm::ConstantInt::get(IGM.ObjCBoolTy, |
| !prop->getAttrs().hasAttribute<OptionalAttr>()), |
| // instance? |
| llvm::ConstantInt::get(IGM.ObjCBoolTy, |
| prop->isInstanceMember()), |
| }; |
| Builder.CreateCall(protocol_addMethodDescription, getterArgs); |
| |
| if (prop->isSettable(nullptr)) { |
| auto descriptor = emitObjCSetterDescriptorParts(IGM, prop); |
| sel = Builder.CreateCall(IGM.getObjCSelRegisterNameFn(), |
| descriptor.selectorRef); |
| llvm::Value *setterArgs[] = { |
| NewProto, sel, descriptor.typeEncoding, |
| // required? |
| llvm::ConstantInt::get(IGM.ObjCBoolTy, |
| !prop->getAttrs().hasAttribute<OptionalAttr>()), |
| // instance? |
| llvm::ConstantInt::get(IGM.ObjCBoolTy, |
| prop->isInstanceMember()), |
| }; |
| Builder.CreateCall(protocol_addMethodDescription, setterArgs); |
| } |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| namespace { |
| |
| class PrettySourceFileEmission : public llvm::PrettyStackTraceEntry { |
| const SourceFile &SF; |
| public: |
| explicit PrettySourceFileEmission(const SourceFile &SF) : SF(SF) {} |
| |
| void print(raw_ostream &os) const override { |
| os << "While emitting IR for source file " << SF.getFilename() << '\n'; |
| } |
| }; |
| |
| class PrettySynthesizedFileUnitEmission : public llvm::PrettyStackTraceEntry { |
| const SynthesizedFileUnit &SFU; |
| |
| public: |
| explicit PrettySynthesizedFileUnitEmission(const SynthesizedFileUnit &SFU) |
| : SFU(SFU) {} |
| |
| void print(raw_ostream &os) const override { |
| os << "While emitting IR for synthesized file" << &SFU << "\n"; |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| /// Emit all the top-level code in the source file. |
| void IRGenModule::emitSourceFile(SourceFile &SF) { |
| // Type-check the file if we haven't already (this may be necessary for .sil |
| // files, which don't get fully type-checked by parsing). |
| performTypeChecking(SF); |
| |
| PrettySourceFileEmission StackEntry(SF); |
| |
| // Emit types and other global decls. |
| for (auto *decl : SF.getTopLevelDecls()) |
| emitGlobalDecl(decl); |
| for (auto *decl : SF.getHoistedDecls()) |
| emitGlobalDecl(decl); |
| for (auto *localDecl : SF.LocalTypeDecls) |
| emitGlobalDecl(localDecl); |
| for (auto *opaqueDecl : SF.getOpaqueReturnTypeDecls()) |
| maybeEmitOpaqueTypeDecl(opaqueDecl); |
| |
| SF.collectLinkLibraries([this](LinkLibrary linkLib) { |
| this->addLinkLibrary(linkLib); |
| }); |
| |
| if (ObjCInterop) |
| this->addLinkLibrary(LinkLibrary("objc", LibraryKind::Library)); |
| |
| // FIXME: It'd be better to have the driver invocation or build system that |
| // executes the linker introduce these compatibility libraries, since at |
| // that point we know whether we're building an executable, which is the only |
| // place where the compatibility libraries take effect. For the benefit of |
| // build systems that build Swift code, but don't use Swift to drive |
| // the linker, we can also use autolinking to pull in the compatibility |
| // libraries. This may however cause the library to get pulled in in |
| // situations where it isn't useful, such as for dylibs, though this is |
| // harmless aside from code size. |
| if (!IRGen.Opts.UseJIT) { |
| auto addBackDeployLib = [&](llvm::VersionTuple version, |
| StringRef libraryName) { |
| Optional<llvm::VersionTuple> compatibilityVersion; |
| if (libraryName == "swiftCompatibilityDynamicReplacements") { |
| compatibilityVersion = IRGen.Opts. |
| AutolinkRuntimeCompatibilityDynamicReplacementLibraryVersion; |
| } else { |
| compatibilityVersion = IRGen.Opts. |
| AutolinkRuntimeCompatibilityLibraryVersion; |
| } |
| |
| if (!compatibilityVersion) |
| return; |
| |
| if (*compatibilityVersion > version) |
| return; |
| |
| this->addLinkLibrary(LinkLibrary(libraryName, |
| LibraryKind::Library, |
| /*forceLoad*/ true)); |
| }; |
| |
| #define BACK_DEPLOYMENT_LIB(Version, Filter, LibraryName) \ |
| addBackDeployLib(llvm::VersionTuple Version, LibraryName); |
| #include "swift/Frontend/BackDeploymentLibs.def" |
| } |
| } |
| |
| /// Emit all the top-level code in the synthesized file unit. |
| void IRGenModule::emitSynthesizedFileUnit(SynthesizedFileUnit &SFU) { |
| PrettySynthesizedFileUnitEmission StackEntry(SFU); |
| for (auto *decl : SFU.getTopLevelDecls()) |
| emitGlobalDecl(decl); |
| } |
| |
| /// Collect elements of an already-existing global list with the given |
| /// \c name into \c list. |
| /// |
| /// We use this when Clang code generation might populate the list. |
| static void collectGlobalList(IRGenModule &IGM, |
| SmallVectorImpl<llvm::WeakTrackingVH> &list, |
| StringRef name) { |
| if (auto *existing = IGM.Module.getGlobalVariable(name)) { |
| auto *globals = cast<llvm::ConstantArray>(existing->getInitializer()); |
| for (auto &use : globals->operands()) { |
| auto *global = use.get(); |
| list.push_back(global); |
| } |
| existing->eraseFromParent(); |
| } |
| |
| std::for_each(list.begin(), list.end(), |
| [](const llvm::WeakTrackingVH &global) { |
| assert(!isa<llvm::GlobalValue>(global) || |
| !cast<llvm::GlobalValue>(global)->isDeclaration() && |
| "all globals in the 'used' list must be definitions"); |
| }); |
| } |
| |
| /// Emit a global list, i.e. a global constant array holding all of a |
| /// list of values. Generally these lists are for various LLVM |
| /// metadata or runtime purposes. |
| static llvm::GlobalVariable * |
| emitGlobalList(IRGenModule &IGM, ArrayRef<llvm::WeakTrackingVH> handles, |
| StringRef name, StringRef section, |
| llvm::GlobalValue::LinkageTypes linkage, |
| llvm::Type *eltTy, |
| bool isConstant) { |
| // Do nothing if the list is empty. |
| if (handles.empty()) return nullptr; |
| |
| // For global lists that actually get linked (as opposed to notional |
| // ones like @llvm.used), it's important to set an explicit alignment |
| // so that the linker doesn't accidentally put padding in the list. |
| Alignment alignment = IGM.getPointerAlignment(); |
| |
| // We have an array of value handles, but we need an array of constants. |
| SmallVector<llvm::Constant*, 8> elts; |
| elts.reserve(handles.size()); |
| for (auto &handle : handles) { |
| auto elt = cast<llvm::Constant>(&*handle); |
| if (elt->getType() != eltTy) |
| elt = llvm::ConstantExpr::getBitCast(elt, eltTy); |
| elts.push_back(elt); |
| } |
| |
| auto varTy = llvm::ArrayType::get(eltTy, elts.size()); |
| auto init = llvm::ConstantArray::get(varTy, elts); |
| auto var = new llvm::GlobalVariable(IGM.Module, varTy, isConstant, linkage, |
| init, name); |
| var->setSection(section); |
| var->setAlignment(llvm::MaybeAlign(alignment.getValue())); |
| disableAddressSanitizer(IGM, var); |
| |
| // Mark the variable as used if doesn't have external linkage. |
| // (Note that we'd specifically like to not put @llvm.used in itself.) |
| if (llvm::GlobalValue::isLocalLinkage(linkage)) |
| IGM.addUsedGlobal(var); |
| return var; |
| } |
| |
| void IRGenModule::emitRuntimeRegistration() { |
| // Duck out early if we have nothing to register. |
| if (SwiftProtocols.empty() && ProtocolConformances.empty() && |
| RuntimeResolvableTypes.empty() && |
| (!ObjCInterop || (ObjCProtocols.empty() && ObjCClasses.empty() && |
| ObjCCategoryDecls.empty())) && |
| FieldDescriptors.empty()) |
| return; |
| |
| // Find the entry point. |
| SILFunction *EntryPoint = |
| getSILModule().lookUpFunction(SWIFT_ENTRY_POINT_FUNCTION); |
| |
| // If we're debugging (and not in the REPL), we don't have a |
| // main. Find a function marked with the LLDBDebuggerFunction |
| // attribute instead. |
| if (!EntryPoint && Context.LangOpts.DebuggerSupport) { |
| for (SILFunction &SF : getSILModule()) { |
| if (SF.hasLocation()) { |
| if (Decl* D = SF.getLocation().getAsASTNode<Decl>()) { |
| if (auto *FD = dyn_cast<FuncDecl>(D)) { |
| if (FD->getAttrs().hasAttribute<LLDBDebuggerFunctionAttr>()) { |
| EntryPoint = &SF; |
| break; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| if (!EntryPoint) |
| return; |
| |
| llvm::Function *EntryFunction = Module.getFunction(EntryPoint->getName()); |
| if (!EntryFunction) |
| return; |
| |
| // Create a new function to contain our logic. |
| auto fnTy = llvm::FunctionType::get(VoidTy, /*varArg*/ false); |
| auto RegistrationFunction = llvm::Function::Create(fnTy, |
| llvm::GlobalValue::PrivateLinkage, |
| "runtime_registration", |
| getModule()); |
| RegistrationFunction->setAttributes(constructInitialAttributes()); |
| |
| // Insert a call into the entry function. |
| { |
| llvm::BasicBlock *EntryBB = &EntryFunction->getEntryBlock(); |
| llvm::BasicBlock::iterator IP = EntryBB->getFirstInsertionPt(); |
| IRBuilder Builder(getLLVMContext(), |
| DebugInfo && !Context.LangOpts.DebuggerSupport); |
| Builder.llvm::IRBuilderBase::SetInsertPoint(EntryBB, IP); |
| if (DebugInfo && !Context.LangOpts.DebuggerSupport) |
| DebugInfo->setEntryPointLoc(Builder); |
| Builder.CreateCall(RegistrationFunction, {}); |
| } |
| |
| IRGenFunction RegIGF(*this, RegistrationFunction); |
| if (DebugInfo && !Context.LangOpts.DebuggerSupport) |
| DebugInfo->emitArtificialFunction(RegIGF, RegistrationFunction); |
| |
| // Register ObjC protocols we added. |
| if (ObjCInterop) { |
| if (!ObjCProtocols.empty()) { |
| // We need to initialize ObjC protocols in inheritance order, parents |
| // first. |
| |
| llvm::DenseSet<ProtocolDecl*> protos; |
| for (auto &proto : ObjCProtocols) |
| protos.insert(proto.first); |
| |
| llvm::SmallVector<ProtocolDecl*, 4> protoInitOrder; |
| |
| std::function<void(ProtocolDecl*)> orderProtocol |
| = [&](ProtocolDecl *proto) { |
| // Recursively put parents first. |
| for (auto parent : proto->getInheritedProtocols()) |
| orderProtocol(parent); |
| |
| // Skip if we don't need to reify this protocol. |
| auto found = protos.find(proto); |
| if (found == protos.end()) |
| return; |
| protos.erase(found); |
| protoInitOrder.push_back(proto); |
| }; |
| |
| while (!protos.empty()) { |
| orderProtocol(*protos.begin()); |
| } |
| |
| // Visit the protocols in the order we established. |
| for (auto *proto : protoInitOrder) { |
| ObjCProtocolInitializerVisitor(RegIGF) |
| .visitMembers(proto); |
| } |
| } |
| } |
| |
| // Register Swift protocols if we added any. |
| if (!SwiftProtocols.empty()) { |
| llvm::Constant *protocols = emitSwiftProtocols(); |
| |
| llvm::Constant *beginIndices[] = { |
| llvm::ConstantInt::get(Int32Ty, 0), |
| llvm::ConstantInt::get(Int32Ty, 0), |
| }; |
| auto begin = llvm::ConstantExpr::getGetElementPtr( |
| /*Ty=*/nullptr, protocols, beginIndices); |
| llvm::Constant *endIndices[] = { |
| llvm::ConstantInt::get(Int32Ty, 0), |
| llvm::ConstantInt::get(Int32Ty, SwiftProtocols.size()), |
| }; |
| auto end = llvm::ConstantExpr::getGetElementPtr( |
| /*Ty=*/nullptr, protocols, endIndices); |
| |
| RegIGF.Builder.CreateCall(getRegisterProtocolsFn(), {begin, end}); |
| } |
| |
| // Register Swift protocol conformances if we added any. |
| if (llvm::Constant *conformances = emitProtocolConformances()) { |
| llvm::Constant *beginIndices[] = { |
| llvm::ConstantInt::get(Int32Ty, 0), |
| llvm::ConstantInt::get(Int32Ty, 0), |
| }; |
| auto begin = llvm::ConstantExpr::getGetElementPtr( |
| /*Ty=*/nullptr, conformances, beginIndices); |
| llvm::Constant *endIndices[] = { |
| llvm::ConstantInt::get(Int32Ty, 0), |
| llvm::ConstantInt::get(Int32Ty, ProtocolConformances.size()), |
| }; |
| auto end = llvm::ConstantExpr::getGetElementPtr( |
| /*Ty=*/nullptr, conformances, endIndices); |
| |
| RegIGF.Builder.CreateCall(getRegisterProtocolConformancesFn(), {begin, end}); |
| } |
| |
| if (!RuntimeResolvableTypes.empty()) { |
| llvm::Constant *records = emitTypeMetadataRecords(); |
| |
| llvm::Constant *beginIndices[] = { |
| llvm::ConstantInt::get(Int32Ty, 0), |
| llvm::ConstantInt::get(Int32Ty, 0), |
| }; |
| auto begin = llvm::ConstantExpr::getGetElementPtr( |
| /*Ty=*/nullptr, records, beginIndices); |
| llvm::Constant *endIndices[] = { |
| llvm::ConstantInt::get(Int32Ty, 0), |
| llvm::ConstantInt::get(Int32Ty, RuntimeResolvableTypes.size()), |
| }; |
| auto end = llvm::ConstantExpr::getGetElementPtr( |
| /*Ty=*/nullptr, records, endIndices); |
| |
| RegIGF.Builder.CreateCall(getRegisterTypeMetadataRecordsFn(), {begin, end}); |
| } |
| |
| // Register Objective-C classes and extensions we added. |
| if (ObjCInterop) { |
| for (llvm::WeakTrackingVH &ObjCClass : ObjCClasses) { |
| RegIGF.Builder.CreateCall(getInstantiateObjCClassFn(), {ObjCClass}); |
| } |
| |
| for (ExtensionDecl *ext : ObjCCategoryDecls) { |
| CategoryInitializerVisitor(RegIGF, ext).visitMembers(ext); |
| } |
| } |
| |
| if (!FieldDescriptors.empty()) { |
| emitFieldDescriptors(); |
| } |
| |
| RegIGF.Builder.CreateRetVoid(); |
| } |
| |
| /// Return the address of the context descriptor representing the given |
| /// decl context, used as a parent reference for another decl. |
| /// |
| /// For a nominal type context, this returns the address of the nominal type |
| /// descriptor. |
| /// For an extension context, this returns the address of the extension |
| /// context descriptor. |
| /// For a module or file unit context, this returns the address of the module |
| /// context descriptor. |
| /// For any other kind of context, this returns an anonymous context descriptor |
| /// for the context. |
| ConstantReference |
| IRGenModule::getAddrOfContextDescriptorForParent(DeclContext *parent, |
| DeclContext *ofChild, |
| bool fromAnonymousContext) { |
| switch (parent->getContextKind()) { |
| case DeclContextKind::AbstractClosureExpr: |
| case DeclContextKind::AbstractFunctionDecl: |
| case DeclContextKind::SubscriptDecl: |
| case DeclContextKind::EnumElementDecl: |
| case DeclContextKind::TopLevelCodeDecl: |
| case DeclContextKind::Initializer: |
| case DeclContextKind::SerializedLocal: |
| return {getAddrOfAnonymousContextDescriptor( |
| fromAnonymousContext ? parent : ofChild), |
| ConstantReference::Direct}; |
| |
| case DeclContextKind::GenericTypeDecl: |
| if (auto nomTy = dyn_cast<NominalTypeDecl>(parent)) { |
| return {getAddrOfTypeContextDescriptor(nomTy, DontRequireMetadata), |
| ConstantReference::Direct}; |
| } |
| return {getAddrOfAnonymousContextDescriptor( |
| fromAnonymousContext ? parent : ofChild), |
| ConstantReference::Direct}; |
| |
| case DeclContextKind::ExtensionDecl: { |
| auto ext = cast<ExtensionDecl>(parent); |
| // If the extension is equivalent to its extended context (that is, it's |
| // in the same module as the original non-protocol type and |
| // has no constraints), then we can use the original nominal type context |
| // (assuming there is one). |
| if (ext->isEquivalentToExtendedContext()) { |
| auto nominal = ext->getExtendedNominal(); |
| // If the extended type is an ObjC class, it won't have a nominal type |
| // descriptor, so we'll just emit an extension context. |
| auto clas = dyn_cast<ClassDecl>(nominal); |
| if (!clas || clas->isForeign() || hasKnownSwiftMetadata(*this, clas)) { |
| IRGen.noteUseOfTypeContextDescriptor(nominal, DontRequireMetadata); |
| return getAddrOfLLVMVariableOrGOTEquivalent( |
| LinkEntity::forNominalTypeDescriptor(nominal)); |
| } |
| } |
| return {getAddrOfExtensionContextDescriptor(ext), |
| ConstantReference::Direct}; |
| } |
| |
| case DeclContextKind::FileUnit: |
| parent = parent->getParentModule(); |
| LLVM_FALLTHROUGH; |
| |
| case DeclContextKind::Module: |
| if (auto *D = ofChild->getAsDecl()) { |
| // If the top-level decl has been marked as moved from another module, |
| // using @_originallyDefinedIn, we should emit the original module as |
| // the context because all run-time names of this decl are based on the |
| // original module name. |
| auto OriginalModule = D->getAlternateModuleName(); |
| if (!OriginalModule.empty()) { |
| return {getAddrOfOriginalModuleContextDescriptor(OriginalModule), |
| ConstantReference::Direct}; |
| } |
| } |
| return {getAddrOfModuleContextDescriptor(cast<ModuleDecl>(parent)), |
| ConstantReference::Direct}; |
| } |
| llvm_unreachable("unhandled kind"); |
| } |
| |
| /// Return the address of the context descriptor representing the parent of |
| /// the given decl context. |
| /// |
| /// For a nominal type context, this returns the address of the nominal type |
| /// descriptor. |
| /// For an extension context, this returns the address of the extension |
| /// context descriptor. |
| /// For a module or file unit context, this returns the address of the module |
| /// context descriptor. |
| /// For any other kind of context, this returns an anonymous context descriptor |
| /// for the context. |
| ConstantReference |
| IRGenModule::getAddrOfParentContextDescriptor(DeclContext *from, |
| bool fromAnonymousContext) { |
| // Some types get special treatment. |
| if (auto Type = dyn_cast<NominalTypeDecl>(from)) { |
| // Use a special module context if we have one. |
| if (auto context = |
| Mangle::ASTMangler::getSpecialManglingContext( |
| Type, /*UseObjCProtocolNames=*/false)) { |
| switch (*context) { |
| case Mangle::ASTMangler::ObjCContext: |
| return {getAddrOfObjCModuleContextDescriptor(), |
| ConstantReference::Direct}; |
| case Mangle::ASTMangler::ClangImporterContext: |
| return {getAddrOfClangImporterModuleContextDescriptor(), |
| ConstantReference::Direct}; |
| } |
| } |
| |
| // Wrap up private types in an anonymous context for the containing file |
| // unit so that the runtime knows they have unstable identity. |
| if (!fromAnonymousContext && Type->isOutermostPrivateOrFilePrivateScope() |
| && !Type->isUsableFromInline()) |
| return {getAddrOfAnonymousContextDescriptor(Type), |
| ConstantReference::Direct}; |
| } |
| |
| return getAddrOfContextDescriptorForParent(from->getParent(), from, |
| fromAnonymousContext); |
| } |
| |
| /// Add the given global value to @llvm.used. |
| /// |
| /// This value must have a definition by the time the module is finalized. |
| void IRGenModule::addUsedGlobal(llvm::GlobalValue *global) { |
| LLVMUsed.push_back(global); |
| } |
| |
| /// Add the given global value to @llvm.compiler.used. |
| /// |
| /// This value must have a definition by the time the module is finalized. |
| void IRGenModule::addCompilerUsedGlobal(llvm::GlobalValue *global) { |
| LLVMCompilerUsed.push_back(global); |
| } |
| |
| /// Add the given global value to the Objective-C class list. |
| void IRGenModule::addObjCClass(llvm::Constant *classPtr, bool nonlazy) { |
| ObjCClasses.push_back(classPtr); |
| if (nonlazy) |
| ObjCNonLazyClasses.push_back(classPtr); |
| } |
| |
| /// Add the given global value to the Objective-C resilient class stub list. |
| void IRGenModule::addObjCClassStub(llvm::Constant *classPtr) { |
| ObjCClassStubs.push_back(classPtr); |
| } |
| |
| void IRGenModule::addRuntimeResolvableType(GenericTypeDecl *type) { |
| // Collect the nominal type records we emit into a special section. |
| RuntimeResolvableTypes.push_back(type); |
| |
| if (auto nominal = dyn_cast<NominalTypeDecl>(type)) { |
| // As soon as the type metadata is available, all the type's conformances |
| // must be available, too. The reason is that a type (with the help of its |
| // metadata) can be checked at runtime if it conforms to a protocol. |
| addLazyConformances(nominal); |
| } |
| } |
| |
| ConstantReference |
| IRGenModule::getConstantReferenceForProtocolDescriptor(ProtocolDecl *proto) { |
| if (proto->isObjC()) { |
| // ObjC protocol descriptors don't have a unique address, but get uniqued |
| // by the Objective-C runtime at load time. |
| // Get the indirected address of the protocol descriptor reference variable |
| // that the ObjC runtime uniques. |
| auto refVar = getAddrOfObjCProtocolRef(proto, NotForDefinition); |
| return ConstantReference(refVar, ConstantReference::Indirect); |
| } |
| |
| // Try to form a direct reference to the nominal type descriptor if it's in |
| // the same binary, or use the GOT entry if it's from another binary. |
| return getAddrOfLLVMVariableOrGOTEquivalent( |
| LinkEntity::forProtocolDescriptor(proto)); |
| } |
| |
| void IRGenModule::addLazyConformances(const IterableDeclContext *idc) { |
| for (const ProtocolConformance *conf : |
| idc->getLocalConformances(ConformanceLookupKind::All)) { |
| IRGen.addLazyWitnessTable(conf); |
| } |
| } |
| |
| std::string IRGenModule::GetObjCSectionName(StringRef Section, |
| StringRef MachOAttributes) { |
| assert(Section.substr(0, 2) == "__" && "expected the name to begin with __"); |
| |
| switch (TargetInfo.OutputObjectFormat) { |
| case llvm::Triple::UnknownObjectFormat: |
| llvm_unreachable("must know the object file format"); |
| case llvm::Triple::MachO: |
| return MachOAttributes.empty() |
| ? ("__DATA," + Section).str() |
| : ("__DATA," + Section + "," + MachOAttributes).str(); |
| case llvm::Triple::ELF: |
| case llvm::Triple::Wasm: |
| return Section.substr(2).str(); |
| case llvm::Triple::XCOFF: |
| case llvm::Triple::COFF: |
| return ("." + Section.substr(2) + "$B").str(); |
| } |
| |
| llvm_unreachable("unexpected object file format"); |
| } |
| |
| void IRGenModule::SetCStringLiteralSection(llvm::GlobalVariable *GV, |
| ObjCLabelType Type) { |
| switch (TargetInfo.OutputObjectFormat) { |
| case llvm::Triple::UnknownObjectFormat: |
| llvm_unreachable("must know the object file format"); |
| case llvm::Triple::MachO: |
| switch (Type) { |
| case ObjCLabelType::ClassName: |
| GV->setSection("__TEXT,__objc_classname,cstring_literals"); |
| return; |
| case ObjCLabelType::MethodVarName: |
| GV->setSection("__TEXT,__objc_methname,cstring_literals"); |
| return; |
| case ObjCLabelType::MethodVarType: |
| GV->setSection("__TEXT,__objc_methtype,cstring_literals"); |
| return; |
| case ObjCLabelType::PropertyName: |
| GV->setSection("__TEXT,__cstring,cstring_literals"); |
| return; |
| } |
| case llvm::Triple::ELF: |
| case llvm::Triple::Wasm: |
| return; |
| case llvm::Triple::XCOFF: |
| case llvm::Triple::COFF: |
| return; |
| } |
| |
| llvm_unreachable("unexpected object file format"); |
| } |
| |
| void IRGenModule::emitGlobalLists() { |
| if (ObjCInterop) { |
| // Objective-C class references go in a variable with a meaningless |
| // name but a magic section. |
| emitGlobalList(*this, ObjCClasses, "objc_classes", |
| GetObjCSectionName("__objc_classlist", |
| "regular,no_dead_strip"), |
| llvm::GlobalValue::InternalLinkage, Int8PtrTy, false); |
| |
| // So do resilient class stubs. |
| emitGlobalList(*this, ObjCClassStubs, "objc_class_stubs", |
| GetObjCSectionName("__objc_stublist", |
| "regular,no_dead_strip"), |
| llvm::GlobalValue::InternalLinkage, Int8PtrTy, false); |
| |
| // So do categories. |
| emitGlobalList(*this, ObjCCategories, "objc_categories", |
| GetObjCSectionName("__objc_catlist", |
| "regular,no_dead_strip"), |
| llvm::GlobalValue::InternalLinkage, Int8PtrTy, false); |
| |
| // And categories on class stubs. |
| emitGlobalList(*this, ObjCCategoriesOnStubs, "objc_categories_stubs", |
| GetObjCSectionName("__objc_catlist2", |
| "regular,no_dead_strip"), |
| llvm::GlobalValue::InternalLinkage, Int8PtrTy, false); |
| |
| // Emit nonlazily realized class references in a second magic section to make |
| // sure they are realized by the Objective-C runtime before any instances |
| // are allocated. |
| emitGlobalList(*this, ObjCNonLazyClasses, "objc_non_lazy_classes", |
| GetObjCSectionName("__objc_nlclslist", |
| "regular,no_dead_strip"), |
| llvm::GlobalValue::InternalLinkage, Int8PtrTy, false); |
| } |
| |
| // @llvm.used |
| |
| // Collect llvm.used globals already in the module (coming from ClangCodeGen). |
| collectGlobalList(*this, LLVMUsed, "llvm.used"); |
| emitGlobalList(*this, LLVMUsed, "llvm.used", "llvm.metadata", |
| llvm::GlobalValue::AppendingLinkage, |
| Int8PtrTy, |
| false); |
| |
| // Collect llvm.compiler.used globals already in the module (coming |
| // from ClangCodeGen). |
| collectGlobalList(*this, LLVMCompilerUsed, "llvm.compiler.used"); |
| emitGlobalList(*this, LLVMCompilerUsed, "llvm.compiler.used", "llvm.metadata", |
| llvm::GlobalValue::AppendingLinkage, |
| Int8PtrTy, |
| false); |
| } |
| |
| static bool hasCodeCoverageInstrumentation(SILFunction &f, SILModule &m) { |
| return f.getProfiler() && m.getOptions().EmitProfileCoverageMapping; |
| } |
| |
| void IRGenerator::emitGlobalTopLevel( |
| const std::vector<std::string> &linkerDirectives) { |
| // Generate order numbers for the functions in the SIL module that |
| // correspond to definitions in the LLVM module. |
| unsigned nextOrderNumber = 0; |
| for (auto &silFn : PrimaryIGM->getSILModule().getFunctions()) { |
| // Don't bother adding external declarations to the function order. |
| if (!silFn.isDefinition()) continue; |
| FunctionOrder.insert(std::make_pair(&silFn, nextOrderNumber++)); |
| } |
| |
| // Ensure that relative symbols are collocated in the same LLVM module. |
| for (auto &wt : PrimaryIGM->getSILModule().getWitnessTableList()) { |
| CurrentIGMPtr IGM = getGenModule(wt.getDeclContext()); |
| ensureRelativeSymbolCollocation(wt); |
| } |
| |
| for (auto &wt : PrimaryIGM->getSILModule().getDefaultWitnessTableList()) { |
| CurrentIGMPtr IGM = getGenModule(wt.getProtocol()->getDeclContext()); |
| ensureRelativeSymbolCollocation(wt); |
| } |
| for (auto &directive: linkerDirectives) { |
| createLinkerDirectiveVariable(*PrimaryIGM, directive); |
| } |
| for (SILGlobalVariable &v : PrimaryIGM->getSILModule().getSILGlobals()) { |
| Decl *decl = v.getDecl(); |
| CurrentIGMPtr IGM = getGenModule(decl ? decl->getDeclContext() : nullptr); |
| IGM->emitSILGlobalVariable(&v); |
| } |
| |
| // Emit SIL functions. |
| for (SILFunction &f : PrimaryIGM->getSILModule()) { |
| // Eagerly emit functions that are externally visible. Functions with code |
| // coverage instrumentation must also be eagerly emitted. So must functions |
| // that are a dynamic replacement for another. |
| if (!f.isPossiblyUsedExternally() && |
| !f.getDynamicallyReplacedFunction() && |
| !hasCodeCoverageInstrumentation(f, PrimaryIGM->getSILModule())) |
| continue; |
| |
| CurrentIGMPtr IGM = getGenModule(&f); |
| IGM->emitSILFunction(&f); |
| } |
| |
| // Emit static initializers. |
| for (auto Iter : *this) { |
| IRGenModule *IGM = Iter.second; |
| IGM->emitSILStaticInitializers(); |
| } |
| |
| // Emit witness tables. |
| for (SILWitnessTable &wt : PrimaryIGM->getSILModule().getWitnessTableList()) { |
| CurrentIGMPtr IGM = getGenModule(wt.getDeclContext()); |
| if (!canEmitWitnessTableLazily(&wt)) { |
| IGM->emitSILWitnessTable(&wt); |
| } |
| } |
| |
| // Emit property descriptors. |
| for (auto &prop : PrimaryIGM->getSILModule().getPropertyList()) { |
| CurrentIGMPtr IGM = getGenModule(prop.getDecl()->getInnermostDeclContext()); |
| IGM->emitSILProperty(&prop); |
| } |
| |
| // Emit differentiability witnesses. |
| for (auto &dw : |
| PrimaryIGM->getSILModule().getDifferentiabilityWitnessList()) { |
| // Emit into same IRGenModule as the original function. |
| // NOTE(TF-894): Investigate whether `getGenModule(dw.getVJP())` is |
| // significant/desirable; `getGenModule` seems relevant for multi-threaded |
| // compilation. When the differentiation transform canonicalizes all |
| // differentiability witnesses to have JVP/VJP functions, we can assert |
| // that JVP/VJP functions exist and use `getGenModule(dw.getVJP())`. |
| CurrentIGMPtr IGM = getGenModule(dw.getOriginalFunction()); |
| |
| IGM->emitSILDifferentiabilityWitness(&dw); |
| } |
| |
| // Emit code coverage mapping data for all modules |
| for (auto Iter : *this) { |
| IRGenModule *IGM = Iter.second; |
| IGM->emitCoverageMapping(); |
| } |
| |
| for (auto Iter : *this) { |
| IRGenModule *IGM = Iter.second; |
| IGM->finishEmitAfterTopLevel(); |
| } |
| |
| emitEntryPointInfo(); |
| } |
| |
| void IRGenModule::finishEmitAfterTopLevel() { |
| // Emit the implicit import of the swift standard library. |
| // FIXME: We'd get the exact set of implicit imports if we went through the |
| // SourceFile's getImportedModules instead, but then we'd lose location info |
| // for the explicit imports. |
| if (DebugInfo) { |
| if (ModuleDecl *TheStdlib = Context.getStdlibModule()) { |
| if (TheStdlib != getSwiftModule()) { |
| Located<swift::Identifier> moduleName[] = { |
| { Context.StdlibModuleName, swift::SourceLoc() } |
| }; |
| |
| auto Imp = ImportDecl::create(Context, |
| getSwiftModule(), |
| SourceLoc(), |
| ImportKind::Module, SourceLoc(), |
| llvm::makeArrayRef(moduleName)); |
| Imp->setModule(TheStdlib); |
| DebugInfo->emitImport(Imp); |
| } |
| } |
| } |
| } |
| |
| void IRGenerator::emitSwiftProtocols() { |
| for (auto &m : *this) { |
| m.second->emitSwiftProtocols(); |
| } |
| } |
| |
| void IRGenerator::emitProtocolConformances() { |
| for (auto &m : *this) { |
| m.second->emitProtocolConformances(); |
| } |
| } |
| |
| void IRGenerator::emitTypeMetadataRecords() { |
| for (auto &m : *this) { |
| m.second->emitTypeMetadataRecords(); |
| } |
| } |
| |
| static void |
| deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords( |
| IRGenModule &IGM, CanType typeWithCanonicalMetadataPrespecialization, |
| NominalTypeDecl &decl) { |
| // The accessor depends on the existence of canonical metadata records |
| // because their presence determine which runtime function is called. |
| auto *accessor = IGM.getAddrOfTypeMetadataAccessFunction( |
| decl.getDeclaredType()->getCanonicalType(), NotForDefinition); |
| accessor->deleteBody(); |
| IGM.IRGen.noteUseOfMetadataAccessor(&decl); |
| |
| IGM.IRGen.noteLazyReemissionOfNominalTypeDescriptor(&decl); |
| // The type context descriptor depends on canonical metadata records because |
| // pointers to them are attached as trailing objects to it. |
| // |
| // Don't call |
| // |
| // noteUseOfTypeContextDescriptor |
| // |
| // here because we don't want to reemit metadata. |
| emitLazyTypeContextDescriptor(IGM, &decl, RequireMetadata); |
| } |
| |
| /// Emit any lazy definitions (of globals or functions or whatever |
| /// else) that we require. |
| void IRGenerator::emitLazyDefinitions() { |
| while (!LazyTypeMetadata.empty() || |
| !LazySpecializedTypeMetadataRecords.empty() || |
| !LazyTypeContextDescriptors.empty() || |
| !LazyOpaqueTypeDescriptors.empty() || !LazyFieldDescriptors.empty() || |
| !LazyFunctionDefinitions.empty() || !LazyWitnessTables.empty() || |
| !LazyCanonicalSpecializedMetadataAccessors.empty() || |
| !LazyMetadataAccessors.empty()) { |
| // Emit any lazy type metadata we require. |
| while (!LazyTypeMetadata.empty()) { |
| NominalTypeDecl *type = LazyTypeMetadata.pop_back_val(); |
| auto &entry = LazyTypeGlobals.find(type)->second; |
| assert(hasLazyMetadata(type)); |
| assert(entry.IsMetadataUsed && !entry.IsMetadataEmitted); |
| entry.IsMetadataEmitted = true; |
| CurrentIGMPtr IGM = getGenModule(type->getDeclContext()); |
| emitLazyTypeMetadata(*IGM.get(), type); |
| } |
| while (!LazySpecializedTypeMetadataRecords.empty()) { |
| CanType theType; |
| TypeMetadataCanonicality canonicality; |
| std::tie(theType, canonicality) = |
| LazySpecializedTypeMetadataRecords.pop_back_val(); |
| auto *nominal = theType->getNominalOrBoundGenericNominal(); |
| CurrentIGMPtr IGMPtr = getGenModule(nominal->getDeclContext()); |
| auto &IGM = *IGMPtr.get(); |
| // A new canonical prespecialized metadata changes both the type |
| // descriptor (adding a new entry to the trailing list of metadata) and |
| // the metadata accessor (calling the appropriate getGenericMetadata |
| // variant depending on whether there are any canonical prespecialized |
| // metadata records to add to the metadata cache). Consequently, it is |
| // necessary to force these to be reemitted. |
| if (canonicality == TypeMetadataCanonicality::Canonical) { |
| deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords( |
| IGM, theType, *nominal); |
| } |
| emitLazySpecializedGenericTypeMetadata(IGM, theType); |
| } |
| while (!LazyTypeContextDescriptors.empty()) { |
| NominalTypeDecl *type = LazyTypeContextDescriptors.pop_back_val(); |
| auto &entry = LazyTypeGlobals.find(type)->second; |
| assert(hasLazyMetadata(type)); |
| assert(entry.IsDescriptorUsed && !entry.IsDescriptorEmitted); |
| entry.IsDescriptorEmitted = true; |
| CurrentIGMPtr IGM = getGenModule(type->getDeclContext()); |
| emitLazyTypeContextDescriptor(*IGM.get(), type, |
| RequireMetadata_t(entry.IsMetadataUsed)); |
| } |
| while (!LazyOpaqueTypeDescriptors.empty()) { |
| OpaqueTypeDecl *type = LazyOpaqueTypeDescriptors.pop_back_val(); |
| auto &entry = LazyOpaqueTypes.find(type)->second; |
| assert(hasLazyMetadata(type)); |
| assert(entry.IsDescriptorUsed && !entry.IsDescriptorEmitted); |
| entry.IsDescriptorEmitted = true; |
| CurrentIGMPtr IGM = getGenModule(type->getDeclContext()); |
| IGM->emitOpaqueTypeDecl(type); |
| } |
| while (!LazyFieldDescriptors.empty()) { |
| NominalTypeDecl *type = LazyFieldDescriptors.pop_back_val(); |
| CurrentIGMPtr IGM = getGenModule(type->getDeclContext()); |
| IGM->emitFieldDescriptor(type); |
| } |
| while (!LazyWitnessTables.empty()) { |
| SILWitnessTable *wt = LazyWitnessTables.pop_back_val(); |
| CurrentIGMPtr IGM = getGenModule(wt->getDeclContext()); |
| IGM->emitSILWitnessTable(wt); |
| } |
| |
| // Emit any lazy function definitions we require. |
| while (!LazyFunctionDefinitions.empty()) { |
| SILFunction *f = LazyFunctionDefinitions.pop_back_val(); |
| CurrentIGMPtr IGM = getGenModule(f); |
| assert(!f->isPossiblyUsedExternally() |
| && "function with externally-visible linkage emitted lazily?"); |
| IGM->emitSILFunction(f); |
| } |
| |
| while (!LazyCanonicalSpecializedMetadataAccessors.empty()) { |
| CanType theType = |
| LazyCanonicalSpecializedMetadataAccessors.pop_back_val(); |
| auto *nominal = theType->getAnyNominal(); |
| assert(nominal); |
| CurrentIGMPtr IGMPtr = getGenModule(nominal->getDeclContext()); |
| auto &IGM = *IGMPtr.get(); |
| // TODO: Once non-canonical accessors are available, this variable should |
| // reflect the canonicality of the accessor rather than always being |
| // canonical. |
| auto canonicality = TypeMetadataCanonicality::Canonical; |
| if (canonicality == TypeMetadataCanonicality::Canonical) { |
| deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords( |
| IGM, theType, *nominal); |
| } |
| emitLazyCanonicalSpecializedMetadataAccessor(IGM, theType); |
| } |
| while (!LazyMetadataAccessors.empty()) { |
| NominalTypeDecl *nominal = LazyMetadataAccessors.pop_back_val(); |
| CurrentIGMPtr IGM = getGenModule(nominal->getDeclContext()); |
| emitLazyMetadataAccessor(*IGM.get(), nominal); |
| } |
| } |
| |
| FinishedEmittingLazyDefinitions = true; |
| } |
| |
| void IRGenerator::addLazyFunction(SILFunction *f) { |
| // Add it to the queue if it hasn't already been put there. |
| if (!LazilyEmittedFunctions.insert(f).second) |
| return; |
| |
| assert(!FinishedEmittingLazyDefinitions); |
| LazyFunctionDefinitions.push_back(f); |
| |
| if (const SILFunction *orig = f->getOriginOfSpecialization()) { |
| // f is a specialization. Try to emit all specializations of the same |
| // original function into the same IGM. This increases the chances that |
| // specializations are merged by LLVM's function merging. |
| auto iter = |
| IGMForSpecializations.insert(std::make_pair(orig, CurrentIGM)).first; |
| DefaultIGMForFunction.insert(std::make_pair(f, iter->second)); |
| return; |
| } |
| |
| if (auto *dc = f->getDeclContext()) |
| if (dc->getParentSourceFile()) |
| return; |
| |
| if (CurrentIGM == nullptr) |
| return; |
| |
| // Don't update the map if we already have an entry. |
| DefaultIGMForFunction.insert(std::make_pair(f, CurrentIGM)); |
| } |
| |
| bool IRGenerator::hasLazyMetadata(TypeDecl *type) { |
| assert(isa<NominalTypeDecl>(type) || |
| isa<OpaqueTypeDecl>(type)); |
| auto found = HasLazyMetadata.find(type); |
| if (found != HasLazyMetadata.end()) |
| return found->second; |
| |
| auto canBeLazy = [&]() -> bool { |
| auto *dc = type->getDeclContext(); |
| if (isa<ClangModuleUnit>(dc->getModuleScopeContext())) { |
| if (auto nominal = dyn_cast<NominalTypeDecl>(type)) { |
| return requiresForeignTypeMetadata(nominal); |
| } |
| } else if (dc->getParentModule() == SIL.getSwiftModule()) { |
| // When compiling with -Onone keep all metadata for the debugger. Even if |
| // it is not used by the program itself. |
| if (!Opts.shouldOptimize()) |
| return false; |
| if (Opts.UseJIT) |
| return false; |
| |
| if (isa<ClassDecl>(type) || isa<ProtocolDecl>(type)) |
| return false; |
| |
| switch (type->getEffectiveAccess()) { |
| case AccessLevel::Open: |
| case AccessLevel::Public: |
| // We can't remove metadata for externally visible types. |
| return false; |
| case AccessLevel::Internal: |
| // In non-whole-module mode, internal types are also visible externally. |
| return SIL.isWholeModule(); |
| case AccessLevel::FilePrivate: |
| case AccessLevel::Private: |
| return true; |
| } |
| } |
| |
| return false; |
| }; |
| |
| bool isLazy = canBeLazy(); |
| HasLazyMetadata[type] = isLazy; |
| |
| return isLazy; |
| } |
| |
| void IRGenerator::noteUseOfTypeGlobals(NominalTypeDecl *type, |
| bool isUseOfMetadata, |
| RequireMetadata_t requireMetadata) { |
| if (!type) |
| return; |
| |
| // Force emission of ObjC protocol descriptors used by type refs. |
| if (auto proto = dyn_cast<ProtocolDecl>(type)) { |
| if (proto->isObjC()) { |
| PrimaryIGM->getAddrOfObjCProtocolRecord(proto, NotForDefinition); |
| return; |
| } |
| } |
| |
| if (!hasLazyMetadata(type)) |
| return; |
| |
| // If the type can be generated in several TU with weak linkage we don't know |
| // which one will be picked up so we have to require the metadata. Otherwise, |
| // the situation can arise where one TU contains a type descriptor with a null |
| // metadata access function and the other TU which requires metadata has a |
| // type descriptor with a valid metadata access function but the linker picks |
| // the first one. |
| if (isAccessorLazilyGenerated(getTypeMetadataAccessStrategy( |
| type->getDeclaredType()->getCanonicalType()))) { |
| requireMetadata = RequireMetadata; |
| } |
| |
| // Try to create a new record of the fact that we used this type. |
| auto insertResult = LazyTypeGlobals.try_emplace(type); |
| auto &entry = insertResult.first->second; |
| |
| bool metadataWasUsed = entry.IsMetadataUsed; |
| bool descriptorWasUsed = entry.IsDescriptorUsed; |
| |
| bool isNovelUseOfMetadata = false; |
| bool isNovelUseOfDescriptor = false; |
| |
| // Flag that we have a use of the metadata if |
| // - the reference was directly to the metadata |
| // - the reference was to the descriptor, but it requested the emission |
| // of metadata |
| if (!metadataWasUsed && (isUseOfMetadata || requireMetadata)) { |
| if (metadataWasUsed) return; |
| entry.IsMetadataUsed = true; |
| isNovelUseOfMetadata = true; |
| } |
| |
| if (!descriptorWasUsed && !isUseOfMetadata) { |
| if (descriptorWasUsed) return; |
| entry.IsDescriptorUsed = true; |
| isNovelUseOfDescriptor = true; |
| } |
| |
| // Enqueue metadata emission if we have a novel use of it. |
| if (isNovelUseOfMetadata) { |
| assert(!FinishedEmittingLazyDefinitions); |
| LazyTypeMetadata.push_back(type); |
| } |
| |
| // Enqueue descriptor emission if we have a novel use of it or if we |
| // need to re-emit it because we're suddenly using metadata for it. |
| if (isNovelUseOfDescriptor || |
| (isNovelUseOfMetadata && entry.IsDescriptorEmitted)) { |
| entry.IsDescriptorEmitted = false; // clear this in case it was true |
| assert(!FinishedEmittingLazyDefinitions); |
| LazyTypeContextDescriptors.push_back(type); |
| } |
| } |
| |
| void IRGenerator::noteUseOfFieldDescriptor(NominalTypeDecl *type) { |
| if (!hasLazyMetadata(type)) |
| return; |
| |
| // Imported classes and protocols do not need field descriptors. |
| if (type->hasClangNode() && |
| (isa<ClassDecl>(type) || |
| isa<ProtocolDecl>(type))) |
| return; |
| |
| if (!LazilyEmittedFieldMetadata.insert(type).second) |
| return; |
| |
| assert(!FinishedEmittingLazyDefinitions); |
| LazyFieldDescriptors.push_back(type); |
| } |
| |
| void IRGenerator::noteUseOfCanonicalSpecializedMetadataAccessor( |
| CanType forType) { |
| auto key = forType->getAnyNominal(); |
| assert(key); |
| assert(key->isGenericContext()); |
| auto &enqueuedSpecializedAccessors = |
| CanonicalSpecializedAccessorsForGenericTypes[key]; |
| if (llvm::all_of(enqueuedSpecializedAccessors, |
| [&](CanType enqueued) { return enqueued != forType; })) { |
| assert(!FinishedEmittingLazyDefinitions); |
| LazyCanonicalSpecializedMetadataAccessors.insert(forType); |
| enqueuedSpecializedAccessors.push_back(forType); |
| } |
| } |
| |
| static bool typeKindCanBePrespecialized(TypeKind theKind) { |
| switch (theKind) { |
| case TypeKind::Struct: |
| case TypeKind::BoundGenericStruct: |
| case TypeKind::Enum: |
| case TypeKind::BoundGenericEnum: |
| case TypeKind::Class: |
| case TypeKind::BoundGenericClass: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| void IRGenerator::noteUseOfSpecializedGenericTypeMetadata( |
| IRGenModule &IGM, CanType theType, TypeMetadataCanonicality canonicality) { |
| assert(typeKindCanBePrespecialized(theType->getKind())); |
| auto key = theType->getAnyNominal(); |
| assert(key); |
| assert(key->isGenericContext()); |
| auto &enqueuedSpecializedTypes = |
| MetadataPrespecializationsForGenericTypes[key]; |
| if (llvm::all_of(enqueuedSpecializedTypes, |
| [&](auto enqueued) { return enqueued.first != theType; })) { |
| assert(!FinishedEmittingLazyDefinitions); |
| LazySpecializedTypeMetadataRecords.push_back({theType, canonicality}); |
| enqueuedSpecializedTypes.push_back({theType, canonicality}); |
| } |
| } |
| |
| void IRGenerator::noteUseOfOpaqueTypeDescriptor(OpaqueTypeDecl *opaque) { |
| if (!opaque) |
| return; |
| |
| if (!hasLazyMetadata(opaque)) |
| return; |
| |
| auto insertResult = LazyOpaqueTypes.try_emplace(opaque); |
| auto &entry = insertResult.first->second; |
| |
| bool isNovelUseOfDescriptor = !entry.IsDescriptorUsed; |
| entry.IsDescriptorUsed = true; |
| |
| if (isNovelUseOfDescriptor) { |
| LazyOpaqueTypeDescriptors.push_back(opaque); |
| } |
| } |
| |
| static std::string getDynamicReplacementSection(IRGenModule &IGM) { |
| std::string sectionName; |
| switch (IGM.TargetInfo.OutputObjectFormat) { |
| case llvm::Triple::UnknownObjectFormat: |
| llvm_unreachable("Don't know how to emit field records table for " |
| "the selected object format."); |
| case llvm::Triple::MachO: |
| sectionName = "__TEXT, __swift5_replace, regular, no_dead_strip"; |
| break; |
| case llvm::Triple::ELF: |
| case llvm::Triple::Wasm: |
| sectionName = "swift5_replace"; |
| break; |
| case llvm::Triple::XCOFF: |
| case llvm::Triple::COFF: |
| sectionName = ".sw5repl$B"; |
| break; |
| } |
| return sectionName; |
| } |
| |
| static std::string getDynamicReplacementSomeSection(IRGenModule &IGM) { |
| std::string sectionName; |
| switch (IGM.TargetInfo.OutputObjectFormat) { |
| case llvm::Triple::UnknownObjectFormat: |
| llvm_unreachable("Don't know how to emit field records table for " |
| "the selected object format."); |
| case llvm::Triple::MachO: |
| sectionName = "__TEXT, __swift5_replac2, regular, no_dead_strip"; |
| break; |
| case llvm::Triple::ELF: |
| case llvm::Triple::Wasm: |
| sectionName = "swift5_replac2"; |
| break; |
| case llvm::Triple::XCOFF: |
| case llvm::Triple::COFF: |
| sectionName = ".sw5reps$B"; |
| break; |
| } |
| return sectionName; |
| } |
| llvm::GlobalVariable *IRGenModule::getGlobalForDynamicallyReplaceableThunk( |
| LinkEntity &entity, llvm::Type *type, ForDefinition_t forDefinition) { |
| return cast<llvm::GlobalVariable>( |
| getAddrOfLLVMVariable(entity, forDefinition, DebugTypeInfo())); |
| } |
| |
| /// Creates a dynamic replacement chain entry for \p SILFn that contains either |
| /// the implementation function pointer \p or a nullptr, the next pointer of the |
| /// chain entry is set to nullptr. |
| /// struct ChainEntry { |
| /// void *funPtr; |
| /// struct ChainEntry *next; |
| /// } |
| static llvm::GlobalVariable *getChainEntryForDynamicReplacement( |
| IRGenModule &IGM, LinkEntity entity, llvm::Function *implFunction = nullptr, |
| ForDefinition_t forDefinition = ForDefinition) { |
| |
| auto linkEntry = IGM.getGlobalForDynamicallyReplaceableThunk( |
| entity, IGM.DynamicReplacementLinkEntryTy, forDefinition); |
| if (!forDefinition) |
| return linkEntry; |
| |
| auto *funPtr = |
| implFunction ? llvm::ConstantExpr::getBitCast(implFunction, IGM.Int8PtrTy) |
| : llvm::ConstantExpr::getNullValue(IGM.Int8PtrTy); |
| |
| if (implFunction) { |
| llvm::Constant *indices[] = {llvm::ConstantInt::get(IGM.Int32Ty, 0), |
| llvm::ConstantInt::get(IGM.Int32Ty, 0)}; |
| auto *storageAddr = llvm::ConstantExpr::getInBoundsGetElementPtr( |
| nullptr, linkEntry, indices); |
| |
| auto &schema = IGM.getOptions().PointerAuth.SwiftDynamicReplacements; |
| assert(entity.hasSILFunction() || entity.isOpaqueTypeDescriptorAccessor()); |
| auto authEntity = entity.hasSILFunction() |
| ? PointerAuthEntity(entity.getSILFunction()) |
| : PointerAuthEntity::Special::TypeDescriptor; |
| funPtr = |
| IGM.getConstantSignedPointer(funPtr, schema, authEntity, storageAddr); |
| } |
| |
| auto *nextEntry = |
| llvm::ConstantExpr::getNullValue(IGM.DynamicReplacementLinkEntryPtrTy); |
| llvm::Constant *fields[] = {funPtr, nextEntry}; |
| auto *entry = |
| llvm::ConstantStruct::get(IGM.DynamicReplacementLinkEntryTy, fields); |
| linkEntry->setInitializer(entry); |
| return linkEntry; |
| } |
| |
| void IRGenerator::emitDynamicReplacements() { |
| if (DynamicReplacements.empty()) |
| return; |
| |
| auto &IGM = *getPrimaryIGM(); |
| |
| // Collect all the type metadata accessor replacements. |
| SmallVector<OpaqueTypeArchetypeType *, 8> newFuncTypes; |
| SmallVector<OpaqueTypeArchetypeType *, 8> origFuncTypes; |
| llvm::SmallSet<OpaqueTypeArchetypeType *, 8> newUniqueOpaqueTypes; |
| llvm::SmallSet<OpaqueTypeArchetypeType *, 8> origUniqueOpaqueTypes; |
| for (auto *newFunc : DynamicReplacements) { |
| auto newResultTy = newFunc->getLoweredFunctionType() |
| ->getAllResultsInterfaceType() |
| .getASTType(); |
| if (!newResultTy->hasOpaqueArchetype()) |
| continue; |
| newResultTy.visit([&](CanType ty) { |
| if (auto opaque = ty->getAs<OpaqueTypeArchetypeType>()) |
| if (newUniqueOpaqueTypes.insert(opaque).second) |
| newFuncTypes.push_back(opaque); |
| }); |
| auto *origFunc = newFunc->getDynamicallyReplacedFunction(); |
| assert(origFunc); |
| auto origResultTy = origFunc->getLoweredFunctionType() |
| ->getAllResultsInterfaceType() |
| .getASTType(); |
| assert(origResultTy->hasOpaqueArchetype()); |
| origResultTy.visit([&](CanType ty) { |
| if (auto opaque = ty->getAs<OpaqueTypeArchetypeType>()) |
| if (origUniqueOpaqueTypes.insert(opaque).second) |
| origFuncTypes.push_back(opaque); |
| }); |
| |
| assert(origFuncTypes.size() == newFuncTypes.size()); |
| } |
| |
| // struct ReplacementScope { |
| // uint32t flags; // unused |
| // uint32t numReplacements; |
| // struct Entry { |
| // RelativeIndirectablePointer<KeyEntry, false> replacedFunctionKey; |
| // RelativeDirectPointer<void> newFunction; |
| // RelativeDirectPointer<LinkEntry> replacement; |
| // uint32_t flags; // shouldChain. |
| // }[0] |
| // }; |
| ConstantInitBuilder builder(IGM); |
| auto replacementScope = builder.beginStruct(); |
| replacementScope.addInt32(0); // unused flags. |
| replacementScope.addInt32(DynamicReplacements.size() + newFuncTypes.size()); |
| |
| auto replacementsArray = |
| replacementScope.beginArray(); |
| for (auto *newFunc : DynamicReplacements) { |
| LinkEntity entity = |
| LinkEntity::forDynamicallyReplaceableFunctionVariable(newFunc); |
| auto replacementLinkEntry = |
| getChainEntryForDynamicReplacement(IGM, entity); |
| // TODO: replacementLinkEntry->setZeroSection() |
| auto *origFunc = newFunc->getDynamicallyReplacedFunction(); |
| assert(origFunc); |
| auto keyRef = IGM.getAddrOfLLVMVariableOrGOTEquivalent( |
| LinkEntity::forDynamicallyReplaceableFunctionKey(origFunc)); |
| |
| llvm::Constant *newFnPtr = llvm::ConstantExpr::getBitCast( |
| IGM.getAddrOfSILFunction(newFunc, NotForDefinition), IGM.Int8PtrTy); |
| |
| auto replacement = replacementsArray.beginStruct(); |
| replacement.addRelativeAddress(keyRef); // tagged relative reference. |
| replacement.addRelativeAddress(newFnPtr); // direct relative reference. |
| replacement.addRelativeAddress( |
| replacementLinkEntry); // direct relative reference. |
| replacement.addInt32( |
| Opts.EnableDynamicReplacementChaining ? 1 : 0); |
| replacement.finishAndAddTo(replacementsArray); |
| } |
| // Emit replacements of the opaque type descriptor accessor. |
| for (auto i : indices(origFuncTypes)) { |
| LinkEntity entity = LinkEntity::forOpaqueTypeDescriptorAccessorVar( |
| newFuncTypes[i]->getDecl()); |
| auto replacementLinkEntry = getChainEntryForDynamicReplacement(IGM, entity); |
| auto keyRef = IGM.getAddrOfLLVMVariableOrGOTEquivalent( |
| LinkEntity::forOpaqueTypeDescriptorAccessorKey( |
| origFuncTypes[i]->getDecl())); |
| llvm::Constant *newFnPtr = llvm::ConstantExpr::getBitCast( |
| IGM.getAddrOfOpaqueTypeDescriptorAccessFunction( |
| newFuncTypes[i]->getDecl(), NotForDefinition, false), |
| IGM.Int8PtrTy); |
| auto replacement = replacementsArray.beginStruct(); |
| replacement.addRelativeAddress(keyRef); // tagged relative reference. |
| replacement.addRelativeAddress(newFnPtr); // direct relative reference. |
| replacement.addRelativeAddress( |
| replacementLinkEntry); // direct relative reference. |
| replacement.addInt32(0); |
| replacement.finishAndAddTo(replacementsArray); |
| } |
| replacementsArray.finishAndAddTo(replacementScope); |
| |
| auto var = replacementScope.finishAndCreateGlobal( |
| "\x01l_unnamed_dynamic_replacements", IGM.getPointerAlignment(), |
| /*isConstant*/ true, llvm::GlobalValue::PrivateLinkage); |
| IGM.setTrueConstGlobal(var); |
| IGM.addUsedGlobal(var); |
| |
| // Emit the data for automatic replacement to happen on load. |
| // struct AutomaticReplacements { |
| // uint32t flags; // unused |
| // uint32t numReplacements; |
| // struct Entry { |
| // RelativeDirectPointer<ReplacementScope> replacements; |
| // uint32_t flags; // unused. |
| // }[0] |
| // }; |
| auto autoReplacements = builder.beginStruct(); |
| autoReplacements.addInt32(0); // unused flags. |
| autoReplacements.addInt32(1); // number of replacement entries. |
| auto autoReplacementsArray = autoReplacements.beginArray(); |
| autoReplacementsArray.addRelativeAddress(var); |
| autoReplacementsArray.addInt32(0); // unused flags. |
| autoReplacementsArray.finishAndAddTo(autoReplacements); |
| auto autoReplVar = autoReplacements.finishAndCreateGlobal( |
| "\x01l_auto_dynamic_replacements", IGM.getPointerAlignment(), |
| /*isConstant*/ true, llvm::GlobalValue::PrivateLinkage); |
| autoReplVar->setSection(getDynamicReplacementSection(IGM)); |
| IGM.addUsedGlobal(autoReplVar); |
| |
| if (origFuncTypes.empty()) |
| return; |
| // Emit records for replacing opaque type descriptor for some types. |
| // struct AutomaticReplacementsSome { |
| // uint32t flags; // unused |
| // uint32t numReplacements; |
| // struct Entry { |
| // RelativeIndirectablePointer<OpaqueTypeDescriptor*> orig; |
| // RelativeDirectPointer<OpaqueTypeDescriptor*> replacement; |
| // uint32_t flags; // unused. |
| // }[numEntries] |
| // }; |
| auto autoReplacementsSome = builder.beginStruct(); |
| autoReplacementsSome.addInt32(0); // unused flags. |
| autoReplacementsSome.addInt32( |
| origFuncTypes.size()); // number of replacement entries. |
| auto someReplacementsArray = autoReplacementsSome.beginArray(); |
| for (auto i : indices(origFuncTypes)) { |
| auto origDesc = |
| LinkEntity::forOpaqueTypeDescriptor(origFuncTypes[i]->getDecl()); |
| auto replDesc = |
| LinkEntity::forOpaqueTypeDescriptor(newFuncTypes[i]->getDecl()); |
| auto replacement = someReplacementsArray.beginStruct(); |
| replacement.addRelativeAddress( |
| IGM.getAddrOfLLVMVariableOrGOTEquivalent(origDesc)); |
| replacement.addRelativeAddress( |
| IGM.getAddrOfLLVMVariableOrGOTEquivalent(replDesc)); |
| replacement.finishAndAddTo(someReplacementsArray); |
| } |
| someReplacementsArray.finishAndAddTo(autoReplacementsSome); |
| auto autoReplVar2 = autoReplacementsSome.finishAndCreateGlobal( |
| "\x01l_auto_dynamic_replacements_some", IGM.getPointerAlignment(), |
| /*isConstant*/ true, llvm::GlobalValue::PrivateLinkage); |
| autoReplVar2->setSection(getDynamicReplacementSomeSection(IGM)); |
| } |
| |
| void IRGenerator::emitEagerClassInitialization() { |
| if (ClassesForEagerInitialization.empty()) |
| return; |
| |
| // Emit the register function in the primary module. |
| IRGenModule *IGM = getPrimaryIGM(); |
| |
| llvm::Function *RegisterFn = llvm::Function::Create( |
| llvm::FunctionType::get(IGM->VoidTy, false), |
| llvm::GlobalValue::PrivateLinkage, |
| "_swift_eager_class_initialization"); |
| IGM->Module.getFunctionList().push_back(RegisterFn); |
| IRGenFunction RegisterIGF(*IGM, RegisterFn); |
| RegisterFn->setAttributes(IGM->constructInitialAttributes()); |
| RegisterFn->setCallingConv(IGM->DefaultCC); |
| |
| for (ClassDecl *CD : ClassesForEagerInitialization) { |
| auto Ty = CD->getDeclaredType()->getCanonicalType(); |
| llvm::Value *MetaData = RegisterIGF.emitTypeMetadataRef(Ty); |
| assert(CD->getAttrs().hasAttribute<StaticInitializeObjCMetadataAttr>()); |
| |
| // Get the metadata to make sure that the class is registered. We need to |
| // add a use (empty inline asm instruction) for the metadata. Otherwise |
| // llvm would optimize the metadata accessor call away because it's |
| // defined as "readnone". |
| llvm::FunctionType *asmFnTy = |
| llvm::FunctionType::get(IGM->VoidTy, {MetaData->getType()}, |
| false /* = isVarArg */); |
| llvm::InlineAsm *inlineAsm = |
| llvm::InlineAsm::get(asmFnTy, "", "r", true /* = SideEffects */); |
| RegisterIGF.Builder.CreateAsmCall(inlineAsm, MetaData); |
| } |
| RegisterIGF.Builder.CreateRetVoid(); |
| |
| // Add the registration function as a static initializer. We use a priority |
| // slightly lower than used for C++ global constructors, so that the code is |
| // executed before C++ global constructors (in case someone uses archives |
| // from a C++ global constructor). |
| llvm::appendToGlobalCtors(IGM->Module, RegisterFn, 60000, nullptr); |
| } |
| |
| /// Emit symbols for eliminated dead methods, which can still be referenced |
| /// from other modules. This happens e.g. if a public class contains a (dead) |
| /// private method. |
| void IRGenModule::emitVTableStubs() { |
| llvm::Function *stub = nullptr; |
| for (auto I = getSILModule().zombies_begin(); |
| I != getSILModule().zombies_end(); ++I) { |
| const SILFunction &F = *I; |
| if (! F.isExternallyUsedSymbol()) |
| continue; |
| |
| if (!stub) { |
| // Create a single stub function which calls swift_deletedMethodError(). |
| stub = llvm::Function::Create(llvm::FunctionType::get(VoidTy, false), |
| llvm::GlobalValue::InternalLinkage, |
| "_swift_dead_method_stub"); |
| stub->setAttributes(constructInitialAttributes()); |
| Module.getFunctionList().push_back(stub); |
| stub->setCallingConv(DefaultCC); |
| auto *entry = llvm::BasicBlock::Create(getLLVMContext(), "entry", stub); |
| auto *errorFunc = getDeletedMethodErrorFn(); |
| llvm::CallInst::Create(cast<llvm::FunctionType>( |
| errorFunc->getType()->getPointerElementType()), |
| errorFunc, ArrayRef<llvm::Value *>(), "", entry); |
| new llvm::UnreachableInst(getLLVMContext(), entry); |
| } |
| |
| // For each eliminated method symbol create an alias to the stub. |
| auto *alias = llvm::GlobalAlias::create(llvm::GlobalValue::ExternalLinkage, |
| F.getName(), stub); |
| |
| if (F.getEffectiveSymbolLinkage() == SILLinkage::Hidden) |
| alias->setVisibility(llvm::GlobalValue::HiddenVisibility); |
| else |
| ApplyIRLinkage(IRLinkage::ExternalExport).to(alias); |
| } |
| } |
| |
| static std::string getEntryPointSection(IRGenModule &IGM) { |
| std::string sectionName; |
| switch (IGM.TargetInfo.OutputObjectFormat) { |
| case llvm::Triple::UnknownObjectFormat: |
| llvm_unreachable("Don't know how to emit field records table for " |
| "the selected object format."); |
| case llvm::Triple::MachO: |
| sectionName = "__TEXT, __swift5_entry, regular, no_dead_strip"; |
| break; |
| case llvm::Triple::ELF: |
| case llvm::Triple::Wasm: |
| sectionName = "swift5_entry"; |
| break; |
| case llvm::Triple::XCOFF: |
| case llvm::Triple::COFF: |
| sectionName = ".sw5entr$B"; |
| break; |
| } |
| return sectionName; |
| } |
| |
| void IRGenerator::emitEntryPointInfo() { |
| SILFunction *entrypoint = nullptr; |
| if (!(entrypoint = SIL.lookUpFunction(SWIFT_ENTRY_POINT_FUNCTION))) { |
| return; |
| } |
| auto &IGM = *getGenModule(entrypoint); |
| ConstantInitBuilder builder(IGM); |
| auto entrypointInfo = builder.beginStruct(); |
| entrypointInfo.addRelativeAddress( |
| IGM.getAddrOfSILFunction(entrypoint, NotForDefinition)); |
| auto var = entrypointInfo.finishAndCreateGlobal( |
| "\x01l_entry_point", Alignment(4), |
| /*isConstant*/ true, llvm::GlobalValue::PrivateLinkage); |
| var->setSection(getEntryPointSection(IGM)); |
| IGM.addUsedGlobal(var); |
| } |
| |
| static IRLinkage |
| getIRLinkage(const UniversalLinkageInfo &info, SILLinkage linkage, |
| ForDefinition_t isDefinition, bool isWeakImported, |
| bool isKnownLocal = false) { |
| #define RESULT(LINKAGE, VISIBILITY, DLL_STORAGE) \ |
| IRLinkage{llvm::GlobalValue::LINKAGE##Linkage, \ |
| llvm::GlobalValue::VISIBILITY##Visibility, \ |
| llvm::GlobalValue::DLL_STORAGE##StorageClass} |
| |
| // Use protected visibility for public symbols we define on ELF. ld.so |
| // doesn't support relative relocations at load time, which interferes with |
| // our metadata formats. Default visibility should suffice for other object |
| // formats. |
| llvm::GlobalValue::VisibilityTypes PublicDefinitionVisibility = |
| info.IsELFObject ? llvm::GlobalValue::ProtectedVisibility |
| : llvm::GlobalValue::DefaultVisibility; |
| llvm::GlobalValue::DLLStorageClassTypes ExportedStorage = |
| info.UseDLLStorage ? llvm::GlobalValue::DLLExportStorageClass |
| : llvm::GlobalValue::DefaultStorageClass; |
| llvm::GlobalValue::DLLStorageClassTypes ImportedStorage = |
| info.UseDLLStorage ? llvm::GlobalValue::DLLImportStorageClass |
| : llvm::GlobalValue::DefaultStorageClass; |
| |
| switch (linkage) { |
| case SILLinkage::Public: |
| return {llvm::GlobalValue::ExternalLinkage, PublicDefinitionVisibility, |
| ExportedStorage}; |
| |
| case SILLinkage::PublicNonABI: |
| return isDefinition ? RESULT(WeakODR, Hidden, Default) |
| : RESULT(External, Hidden, Default); |
| |
| case SILLinkage::Shared: |
| case SILLinkage::SharedExternal: |
| return isDefinition ? RESULT(LinkOnceODR, Hidden, Default) |
| : RESULT(External, Hidden, Default); |
| |
| case SILLinkage::Hidden: |
| return RESULT(External, Hidden, Default); |
| |
| case SILLinkage::Private: { |
| if (info.forcePublicDecls() && !isDefinition) |
| return getIRLinkage(info, SILLinkage::PublicExternal, isDefinition, |
| isWeakImported, isKnownLocal); |
| |
| auto linkage = info.needLinkerToMergeDuplicateSymbols() |
| ? llvm::GlobalValue::LinkOnceODRLinkage |
| : llvm::GlobalValue::InternalLinkage; |
| auto visibility = info.shouldAllPrivateDeclsBeVisibleFromOtherFiles() |
| ? llvm::GlobalValue::HiddenVisibility |
| : llvm::GlobalValue::DefaultVisibility; |
| return {linkage, visibility, llvm::GlobalValue::DefaultStorageClass}; |
| } |
| |
| case SILLinkage::PublicExternal: { |
| if (isDefinition) |
| return RESULT(AvailableExternally, Default, Default); |
| |
| auto linkage = isWeakImported ? llvm::GlobalValue::ExternalWeakLinkage |
| : llvm::GlobalValue::ExternalLinkage; |
| return {linkage, llvm::GlobalValue::DefaultVisibility, |
| isKnownLocal |
| ? llvm::GlobalValue::DefaultStorageClass |
| : ImportedStorage}; |
| } |
| |
| case SILLinkage::HiddenExternal: |
| case SILLinkage::PrivateExternal: |
| if (isDefinition) |
| return RESULT(AvailableExternally, Hidden, Default); |
| |
| return {llvm::GlobalValue::ExternalLinkage, |
| llvm::GlobalValue::DefaultVisibility, |
| isKnownLocal |
| ? llvm::GlobalValue::DefaultStorageClass |
| : ImportedStorage}; |
| } |
| |
| llvm_unreachable("bad SIL linkage"); |
| } |
| |
| /// Given that we're going to define a global value but already have a |
| /// forward-declaration of it, update its linkage. |
| void irgen::updateLinkageForDefinition(IRGenModule &IGM, |
| llvm::GlobalValue *global, |
| const LinkEntity &entity) { |
| // TODO: there are probably cases where we can avoid redoing the |
| // entire linkage computation. |
| UniversalLinkageInfo linkInfo(IGM); |
| bool weakImported = entity.isWeakImported(IGM.getSwiftModule()); |
| |
| bool isKnownLocal = entity.isAlwaysSharedLinkage(); |
| if (const auto *DC = entity.getDeclContextForEmission()) |
| if (const auto *MD = DC->getParentModule()) |
| isKnownLocal = IGM.getSwiftModule() == MD; |
| |
| auto IRL = |
| getIRLinkage(linkInfo, entity.getLinkage(ForDefinition), |
| ForDefinition, weakImported, isKnownLocal); |
| ApplyIRLinkage(IRL).to(global); |
| |
| // Everything externally visible is considered used in Swift. |
| // That mostly means we need to be good at not marking things external. |
| if (LinkInfo::isUsed(IRL)) |
| IGM.addUsedGlobal(global); |
| } |
| |
| LinkInfo LinkInfo::get(IRGenModule &IGM, const LinkEntity &entity, |
| ForDefinition_t isDefinition) { |
| return LinkInfo::get(UniversalLinkageInfo(IGM), |
| IGM.getSwiftModule(), |
| entity, isDefinition); |
| } |
| |
| LinkInfo LinkInfo::get(const UniversalLinkageInfo &linkInfo, |
| ModuleDecl *swiftModule, |
| const LinkEntity &entity, |
| ForDefinition_t isDefinition) { |
| LinkInfo result; |
| |
| bool isKnownLocal = entity.isAlwaysSharedLinkage(); |
| if (const auto *DC = entity.getDeclContextForEmission()) |
| if (const auto *MD = DC->getParentModule()) |
| isKnownLocal = MD == swiftModule; |
| |
| entity.mangle(result.Name); |
| bool weakImported = entity.isWeakImported(swiftModule); |
| result.IRL = getIRLinkage(linkInfo, entity.getLinkage(isDefinition), |
| isDefinition, weakImported, isKnownLocal); |
| result.ForDefinition = isDefinition; |
| return result; |
| } |
| |
| LinkInfo LinkInfo::get(const UniversalLinkageInfo &linkInfo, StringRef name, |
| SILLinkage linkage, ForDefinition_t isDefinition, |
| bool isWeakImported) { |
| LinkInfo result; |
| |
| result.Name += name; |
| result.IRL = getIRLinkage(linkInfo, linkage, isDefinition, isWeakImported); |
| result.ForDefinition = isDefinition; |
| return result; |
| } |
| |
| static bool isPointerTo(llvm::Type *ptrTy, llvm::Type *objTy) { |
| return cast<llvm::PointerType>(ptrTy)->getElementType() == objTy; |
| } |
| |
| /// Get or create an LLVM function with these linkage rules. |
| llvm::Function *irgen::createFunction(IRGenModule &IGM, |
| LinkInfo &linkInfo, |
| const Signature &signature, |
| llvm::Function *insertBefore, |
| OptimizationMode FuncOptMode) { |
| auto name = linkInfo.getName(); |
| |
| llvm::Function *existing = IGM.Module.getFunction(name); |
| if (existing) { |
| if (isPointerTo(existing->getType(), signature.getType())) |
| return cast<llvm::Function>(existing); |
| |
| IGM.error(SourceLoc(), |
| "program too clever: function collides with existing symbol " + |
| name); |
| |
| // Note that this will implicitly unique if the .unique name is also taken. |
| existing->setName(name + ".unique"); |
| } |
| |
| llvm::Function *fn = |
| llvm::Function::Create(signature.getType(), linkInfo.getLinkage(), name); |
| fn->setCallingConv(signature.getCallingConv()); |
| |
| if (insertBefore) { |
| IGM.Module.getFunctionList().insert(insertBefore->getIterator(), fn); |
| } else { |
| IGM.Module.getFunctionList().push_back(fn); |
| } |
| |
| ApplyIRLinkage({linkInfo.getLinkage(), |
| linkInfo.getVisibility(), |
| linkInfo.getDLLStorage()}) |
| .to(fn, linkInfo.isForDefinition()); |
| |
| llvm::AttrBuilder initialAttrs; |
| IGM.constructInitialFnAttributes(initialAttrs, FuncOptMode); |
| // Merge initialAttrs with attrs. |
| auto updatedAttrs = |
| signature.getAttributes().addAttributes(IGM.getLLVMContext(), |
| llvm::AttributeList::FunctionIndex, |
| initialAttrs); |
| if (!updatedAttrs.isEmpty()) |
| fn->setAttributes(updatedAttrs); |
| |
| // Everything externally visible is considered used in Swift. |
| // That mostly means we need to be good at not marking things external. |
| if (linkInfo.isUsed()) { |
| IGM.addUsedGlobal(fn); |
| } |
| |
| return fn; |
| } |
| |
| bool LinkInfo::isUsed(IRLinkage IRL) { |
| // Everything externally visible is considered used in Swift. |
| // That mostly means we need to be good at not marking things external. |
| return IRL.Linkage == llvm::GlobalValue::ExternalLinkage && |
| (IRL.Visibility == llvm::GlobalValue::DefaultVisibility || |
| IRL.Visibility == llvm::GlobalValue::ProtectedVisibility) && |
| (IRL.DLLStorage == llvm::GlobalValue::DefaultStorageClass || |
| IRL.DLLStorage == llvm::GlobalValue::DLLExportStorageClass); |
| } |
| |
| /// Get or create an LLVM global variable with these linkage rules. |
| llvm::GlobalVariable *swift::irgen::createVariable( |
| IRGenModule &IGM, LinkInfo &linkInfo, llvm::Type *storageType, |
| Alignment alignment, DebugTypeInfo DbgTy, Optional<SILLocation> DebugLoc, |
| StringRef DebugName, bool inFixedBuffer) { |
| auto name = linkInfo.getName(); |
| llvm::GlobalValue *existingValue = IGM.Module.getNamedGlobal(name); |
| if (existingValue) { |
| auto existingVar = dyn_cast<llvm::GlobalVariable>(existingValue); |
| if (existingVar && isPointerTo(existingVar->getType(), storageType)) |
| return existingVar; |
| |
| IGM.error(SourceLoc(), |
| "program too clever: variable collides with existing symbol " + |
| name); |
| |
| // Note that this will implicitly unique if the .unique name is also taken. |
| existingValue->setName(name + ".unique"); |
| } |
| |
| auto var = new llvm::GlobalVariable(IGM.Module, storageType, |
| /*constant*/ false, linkInfo.getLinkage(), |
| /*initializer*/ nullptr, name); |
| ApplyIRLinkage({linkInfo.getLinkage(), |
| linkInfo.getVisibility(), |
| linkInfo.getDLLStorage()}) |
| .to(var, linkInfo.isForDefinition()); |
| var->setAlignment(llvm::MaybeAlign(alignment.getValue())); |
| |
| // Everything externally visible is considered used in Swift. |
| // That mostly means we need to be good at not marking things external. |
| if (linkInfo.isUsed()) { |
| IGM.addUsedGlobal(var); |
| } |
| |
| if (IGM.DebugInfo && !DbgTy.isNull() && linkInfo.isForDefinition()) |
| IGM.DebugInfo->emitGlobalVariableDeclaration( |
| var, DebugName.empty() ? name : DebugName, name, DbgTy, |
| var->hasInternalLinkage(), inFixedBuffer, DebugLoc); |
| |
| return var; |
| } |
| |
| llvm::GlobalVariable * |
| swift::irgen::createLinkerDirectiveVariable(IRGenModule &IGM, StringRef name) { |
| |
| // A prefix of \1 can avoid further mangling of the symbol (prefixing _). |
| llvm::SmallString<32> NameWithFlag; |
| NameWithFlag.push_back('\1'); |
| NameWithFlag.append(name); |
| name = NameWithFlag.str(); |
| static const uint8_t Size = 8; |
| static const uint8_t Alignment = 8; |
| |
| // Use a char type as the type for this linker directive. |
| auto ProperlySizedIntTy = SILType::getBuiltinIntegerType( |
| Size, IGM.getSwiftModule()->getASTContext()); |
| auto storageType = IGM.getStorageType(ProperlySizedIntTy); |
| |
| llvm::GlobalValue *existingValue = IGM.Module.getNamedGlobal(name); |
| if (existingValue) { |
| auto existingVar = dyn_cast<llvm::GlobalVariable>(existingValue); |
| if (existingVar && isPointerTo(existingVar->getType(), storageType)) |
| return existingVar; |
| |
| IGM.error(SourceLoc(), |
| "program too clever: variable collides with existing symbol " + |
| name); |
| |
| // Note that this will implicitly unique if the .unique name is also taken. |
| existingValue->setName(name + ".unique"); |
| } |
| |
| llvm::GlobalValue::LinkageTypes Linkage = |
| llvm::GlobalValue::LinkageTypes::ExternalLinkage; |
| auto var = new llvm::GlobalVariable(IGM.Module, storageType, /*constant*/true, |
| Linkage, /*Init to zero*/llvm::Constant::getNullValue(storageType), name); |
| ApplyIRLinkage({Linkage, |
| llvm::GlobalValue::VisibilityTypes::DefaultVisibility, |
| llvm::GlobalValue::DLLStorageClassTypes::DefaultStorageClass}).to(var); |
| var->setAlignment(llvm::MaybeAlign(Alignment)); |
| disableAddressSanitizer(IGM, var); |
| IGM.addUsedGlobal(var); |
| return var; |
| } |
| |
| void swift::irgen::disableAddressSanitizer(IRGenModule &IGM, llvm::GlobalVariable *var) { |
| // Add an operand to llvm.asan.globals denylisting this global variable. |
| llvm::Metadata *metadata[] = { |
| // The global variable to denylist. |
| llvm::ConstantAsMetadata::get(var), |
| |
| // Source location. Optional, unnecessary here. |
| nullptr, |
| |
| // Name. Optional, unnecessary here. |
| nullptr, |
| |
| // Whether the global is dynamically initialized. |
| llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( |
| llvm::Type::getInt1Ty(IGM.Module.getContext()), false)), |
| |
| // Whether the global is denylisted. |
| llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( |
| llvm::Type::getInt1Ty(IGM.Module.getContext()), true))}; |
| |
| auto *globalNode = llvm::MDNode::get(IGM.Module.getContext(), metadata); |
| auto *asanMetadata = IGM.Module.getOrInsertNamedMetadata("llvm.asan.globals"); |
| asanMetadata->addOperand(globalNode); |
| } |
| |
| /// Emit a global declaration. |
| void IRGenModule::emitGlobalDecl(Decl *D) { |
| switch (D->getKind()) { |
| case DeclKind::Extension: |
| return emitExtension(cast<ExtensionDecl>(D)); |
| |
| case DeclKind::Protocol: |
| return emitProtocolDecl(cast<ProtocolDecl>(D)); |
| |
| case DeclKind::PatternBinding: |
| // The global initializations are in SIL. |
| return; |
| |
| case DeclKind::Param: |
| llvm_unreachable("there are no global function parameters"); |
| |
| case DeclKind::Subscript: |
| llvm_unreachable("there are no global subscript operations"); |
| |
| case DeclKind::EnumCase: |
| case DeclKind::EnumElement: |
| llvm_unreachable("there are no global enum elements"); |
| |
| case DeclKind::Constructor: |
| llvm_unreachable("there are no global constructor"); |
| |
| case DeclKind::Destructor: |
| llvm_unreachable("there are no global destructor"); |
| |
| case DeclKind::MissingMember: |
| llvm_unreachable("there are no global member placeholders"); |
| |
| case DeclKind::TypeAlias: |
| case DeclKind::GenericTypeParam: |
| case DeclKind::AssociatedType: |
| case DeclKind::IfConfig: |
| case DeclKind::PoundDiagnostic: |
| return; |
| |
| case DeclKind::Enum: |
| return emitEnumDecl(cast<EnumDecl>(D)); |
| |
| case DeclKind::Struct: |
| return emitStructDecl(cast<StructDecl>(D)); |
| |
| case DeclKind::Class: |
| return emitClassDecl(cast<ClassDecl>(D)); |
| |
| // These declarations are only included in the debug info. |
| case DeclKind::Import: |
| if (DebugInfo) |
| DebugInfo->emitImport(cast<ImportDecl>(D)); |
| return; |
| |
| case DeclKind::Var: |
| case DeclKind::Accessor: |
| case DeclKind::Func: |
| // Handled in SIL. |
| return; |
| |
| case DeclKind::TopLevelCode: |
| // All the top-level code will be lowered separately. |
| return; |
| |
| // Operator decls aren't needed for IRGen. |
| case DeclKind::InfixOperator: |
| case DeclKind::PrefixOperator: |
| case DeclKind::PostfixOperator: |
| case DeclKind::PrecedenceGroup: |
| return; |
| |
| case DeclKind::Module: |
| return; |
| |
| case DeclKind::OpaqueType: |
| // TODO: Eventually we'll need to emit descriptors to access the opaque |
| // type's metadata. |
| return; |
| } |
| |
| llvm_unreachable("bad decl kind!"); |
| } |
| |
| Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var, |
| const TypeInfo &ti, |
| ForDefinition_t forDefinition) { |
| if (auto clangDecl = var->getClangDecl()) { |
| auto addr = getAddrOfClangGlobalDecl(cast<clang::VarDecl>(clangDecl), |
| forDefinition); |
| |
| // If we're not emitting this to define it, make sure we cast it to the |
| // right type. |
| if (!forDefinition) { |
| auto ptrTy = ti.getStorageType()->getPointerTo(); |
| addr = llvm::ConstantExpr::getBitCast(addr, ptrTy); |
| } |
| |
| auto alignment = |
| Alignment(getClangASTContext().getDeclAlign(clangDecl).getQuantity()); |
| return Address(addr, alignment); |
| } |
| |
| LinkEntity entity = LinkEntity::forSILGlobalVariable(var); |
| ResilienceExpansion expansion = getResilienceExpansionForLayout(var); |
| |
| llvm::Type *storageType; |
| llvm::Type *castStorageToType = nullptr; |
| Size fixedSize; |
| Alignment fixedAlignment; |
| bool inFixedBuffer = false; |
| |
| if (var->isInitializedObject()) { |
| assert(ti.isFixedSize(expansion)); |
| StructLayout *Layout = StaticObjectLayouts[var].get(); |
| if (!Layout) { |
| // Create the layout (includes the llvm type) for the statically |
| // initialized object and store it for later. |
| ObjectInst *OI = cast<ObjectInst>(var->getStaticInitializerValue()); |
| llvm::SmallVector<SILType, 16> TailTypes; |
| for (SILValue TailOp : OI->getTailElements()) { |
| TailTypes.push_back(TailOp->getType()); |
| } |
| Layout = getClassLayoutWithTailElems(*this, |
| var->getLoweredType(), TailTypes); |
| StaticObjectLayouts[var] = std::unique_ptr<StructLayout>(Layout); |
| } |
| storageType = Layout->getType(); |
| fixedSize = Layout->getSize(); |
| fixedAlignment = Layout->getAlignment(); |
| castStorageToType = cast<FixedTypeInfo>(ti).getStorageType(); |
| assert(fixedAlignment >= TargetInfo.HeapObjectAlignment); |
| } else if (ti.isFixedSize(expansion)) { |
| // Allocate static storage. |
| auto &fixedTI = cast<FixedTypeInfo>(ti); |
| storageType = fixedTI.getStorageType(); |
| fixedSize = fixedTI.getFixedSize(); |
| fixedAlignment = fixedTI.getFixedAlignment(); |
| } else { |
| // Allocate a fixed-size buffer and possibly heap-allocate a payload at |
| // runtime if the runtime size of the type does not fit in the buffer. |
| inFixedBuffer = true; |
| storageType = getFixedBufferTy(); |
| fixedSize = Size(DataLayout.getTypeAllocSize(storageType)); |
| fixedAlignment = getFixedBufferAlignment(*this); |
| } |
| |
| // Check whether we've created the global variable already. |
| // FIXME: We should integrate this into the LinkEntity cache more cleanly. |
| auto gvar = Module.getGlobalVariable(var->getName(), /*allowInternal*/ true); |
| if (gvar) { |
| if (forDefinition) |
| updateLinkageForDefinition(*this, gvar, entity); |
| } else { |
| LinkInfo link = LinkInfo::get(*this, entity, forDefinition); |
| llvm::Type *storageTypeWithContainer = storageType; |
| if (var->isInitializedObject()) { |
| // A statically initialized object must be placed into a container struct |
| // because the swift_initStaticObject needs a swift_once_t at offset -1: |
| // struct Container { |
| // swift_once_t token[fixedAlignment / sizeof(swift_once_t)]; |
| // HeapObject object; |
| // }; |
| std::string typeName = storageType->getStructName().str() + 'c'; |
| assert(fixedAlignment >= getPointerAlignment()); |
| unsigned numTokens = fixedAlignment.getValue() / |
| getPointerAlignment().getValue(); |
| storageTypeWithContainer = llvm::StructType::create(getLLVMContext(), |
| {llvm::ArrayType::get(OnceTy, numTokens), storageType}, typeName); |
| gvar = createVariable(*this, link, storageTypeWithContainer, |
| fixedAlignment); |
| } else { |
| StringRef name; |
| Optional<SILLocation> loc; |
| if (var->getDecl()) { |
| // Use the VarDecl for more accurate debugging information. |
| loc = var->getDecl(); |
| name = var->getDecl()->getName().str(); |
| } else { |
| if (var->hasLocation()) |
| loc = var->getLocation(); |
| name = var->getName(); |
| } |
| auto DbgTy = DebugTypeInfo::getGlobal(var, storageTypeWithContainer, |
| fixedSize, fixedAlignment); |
| gvar = createVariable(*this, link, storageTypeWithContainer, |
| fixedAlignment, DbgTy, loc, name, inFixedBuffer); |
| } |
| /// Add a zero initializer. |
| if (forDefinition) |
| gvar->setInitializer(llvm::Constant::getNullValue(storageTypeWithContainer)); |
| else |
| gvar->setComdat(nullptr); |
| } |
| llvm::Constant *addr = gvar; |
| if (var->isInitializedObject()) { |
| // Project out the object from the container. |
| llvm::Constant *Indices[2] = { |
| llvm::ConstantExpr::getIntegerValue(Int32Ty, APInt(32, 0)), |
| llvm::ConstantExpr::getIntegerValue(Int32Ty, APInt(32, 1)) |
| }; |
| // Return the address of the initialized object itself (and not the address |
| // to a reference to it). |
| addr = llvm::ConstantExpr::getGetElementPtr(nullptr, gvar, Indices); |
| } |
| addr = llvm::ConstantExpr::getBitCast( |
| addr, |
| castStorageToType ? castStorageToType : storageType->getPointerTo()); |
| return Address(addr, Alignment(gvar->getAlignment())); |
| } |
| |
| /// Return True if the function \p f is a 'readonly' function. Checking |
| /// for the SIL @_effects(readonly) attribute is not enough because this |
| /// definition does not match the definition of the LLVM readonly function |
| /// attribute. In this function we do the actual check. |
| static bool isReadOnlyFunction(SILFunction *f) { |
| // Check if the function has any 'owned' parameters. Owned parameters may |
| // call the destructor of the object which could violate the readonly-ness |
| // of the function. |
| if (f->hasOwnedParameters() || f->hasIndirectFormalResults()) |
| return false; |
| |
| auto Eff = f->getEffectsKind(); |
| |
| // Swift's readonly does not automatically match LLVM's readonly. |
| // Swift SIL optimizer relies on @_effects(readonly) to remove e.g. |
| // dead code remaining from initializers of strings or dictionaries |
| // of variables that are not used. But those initializers are often |
| // not really readonly in terms of LLVM IR. For example, the |
| // Dictionary.init() is marked as @_effects(readonly) in Swift, but |
| // it does invoke reference-counting operations. |
| if (Eff == EffectsKind::ReadOnly || Eff == EffectsKind::ReadNone) { |
| // TODO: Analyze the body of function f and return true if it is |
| // really readonly. |
| return false; |
| } |
| |
| return false; |
| } |
| |
| static clang::GlobalDecl getClangGlobalDeclForFunction(const clang::Decl *decl) { |
| if (auto ctor = dyn_cast<clang::CXXConstructorDecl>(decl)) |
| return clang::GlobalDecl(ctor, clang::Ctor_Complete); |
| if (auto dtor = dyn_cast<clang::CXXDestructorDecl>(decl)) |
| return clang::GlobalDecl(dtor, clang::Dtor_Complete); |
| return clang::GlobalDecl(cast<clang::FunctionDecl>(decl)); |
| } |
| |
| static void addLLVMFunctionAttributes(SILFunction *f, Signature &signature) { |
| auto &attrs = signature.getMutableAttributes(); |
| switch (f->getInlineStrategy()) { |
| case NoInline: |
| attrs = attrs.addAttribute(signature.getType()->getContext(), |
| llvm::AttributeList::FunctionIndex, |
| llvm::Attribute::NoInline); |
| break; |
| case AlwaysInline: |
| // FIXME: We do not currently transfer AlwaysInline since doing so results |
| // in test failures, which must be investigated first. |
| case InlineDefault: |
| break; |
| } |
| |
| if (isReadOnlyFunction(f)) { |
| attrs = attrs.addAttribute(signature.getType()->getContext(), |
| llvm::AttributeList::FunctionIndex, |
| llvm::Attribute::ReadOnly); |
| } |
| } |
| |
| /// Create a key entry for a dynamic function replacement. A key entry refers to |
| /// the link entry for the dynamic replaceable function. |
| /// struct KeyEntry { |
| /// RelativeDirectPointer<LinkEntry> linkEntry; |
| /// int32_t flags; |
| /// } |
| static llvm::GlobalVariable *createGlobalForDynamicReplacementFunctionKey( |
| IRGenModule &IGM, LinkEntity keyEntity, llvm::GlobalVariable *linkEntry) { |
| auto key = IGM.getGlobalForDynamicallyReplaceableThunk( |
| keyEntity, IGM.DynamicReplacementKeyTy, ForDefinition); |
| |
| ConstantInitBuilder builder(IGM); |
| auto B = builder.beginStruct(IGM.DynamicReplacementKeyTy); |
| B.addRelativeAddress(linkEntry); |
| auto schema = IGM.getOptions().PointerAuth.SwiftDynamicReplacements; |
| if (schema) { |
| assert(keyEntity.hasSILFunction() || |
| keyEntity.isOpaqueTypeDescriptorAccessor()); |
| auto authEntity = keyEntity.hasSILFunction() |
| ? PointerAuthEntity(keyEntity.getSILFunction()) |
| : PointerAuthEntity::Special::TypeDescriptor; |
| B.addInt32(PointerAuthInfo::getOtherDiscriminator(IGM, schema, authEntity) |
| ->getZExtValue()); |
| } else |
| B.addInt32(0); |
| B.finishAndSetAsInitializer(key); |
| key->setConstant(true); |
| IGM.setTrueConstGlobal(key); |
| return key; |
| } |
| |
| /// Creates the prolog for a dynamically replaceable function. |
| /// It checks if the replaced function or the original function should be called |
| /// (by calling the swift_getFunctionReplacement runtime function). In case of |
| /// the original function, it just jumps to the "real" code of the function, |
| /// otherwise it tail calls the replacement. |
| void IRGenModule::createReplaceableProlog(IRGenFunction &IGF, SILFunction *f) { |
| LinkEntity varEntity = |
| LinkEntity::forDynamicallyReplaceableFunctionVariable(f); |
| LinkEntity keyEntity = |
| LinkEntity::forDynamicallyReplaceableFunctionKey(f); |
| auto silFunctionType = f->getLoweredFunctionType(); |
| Signature signature = getSignature(silFunctionType); |
| |
| // Create and initialize the first link entry for the chain of replacements. |
| // The first implementation is initialized with 'implFn'. |
| auto linkEntry = getChainEntryForDynamicReplacement(*this, varEntity, IGF.CurFn); |
| |
| // Create the key data structure. This is used from other modules to refer to |
| // the chain of replacements. |
| createGlobalForDynamicReplacementFunctionKey(*this, keyEntity, linkEntry); |
| |
| llvm::Constant *indices[] = {llvm::ConstantInt::get(Int32Ty, 0), |
| llvm::ConstantInt::get(Int32Ty, 0)}; |
| |
| auto *fnPtrAddr = |
| llvm::ConstantExpr::getInBoundsGetElementPtr(nullptr, linkEntry, indices); |
| |
| auto *ReplAddr = |
| llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(fnPtrAddr, |
| FunctionPtrTy->getPointerTo()); |
| |
| auto *FnAddr = llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast( |
| IGF.CurFn, FunctionPtrTy); |
| |
| auto &schema = getOptions().PointerAuth.SwiftDynamicReplacements; |
| llvm::Value *ReplFn = nullptr, *hasReplFn = nullptr; |
| |
| if (UseBasicDynamicReplacement) { |
| ReplFn = IGF.Builder.CreateLoad(fnPtrAddr, getPointerAlignment()); |
| llvm::Value *lhs = ReplFn; |
| if (schema.isEnabled()) { |
| lhs = emitPointerAuthStrip(IGF, lhs, schema.getKey()); |
| } |
| hasReplFn = IGF.Builder.CreateICmpEQ(lhs, FnAddr); |
| } else { |
| // Call swift_getFunctionReplacement to check which function to call. |
| auto *callRTFunc = |
| IGF.Builder.CreateCall(getGetReplacementFn(), {ReplAddr, FnAddr}); |
| callRTFunc->setDoesNotThrow(); |
| ReplFn = callRTFunc; |
| hasReplFn = IGF.Builder.CreateICmpEQ(ReplFn, |
| llvm::ConstantExpr::getNullValue(ReplFn->getType())); |
| } |
| |
| auto *replacedBB = IGF.createBasicBlock("forward_to_replaced"); |
| auto *origEntryBB = IGF.createBasicBlock("original_entry"); |
| IGF.Builder.CreateCondBr(hasReplFn, origEntryBB, replacedBB); |
| |
| IGF.Builder.emitBlock(replacedBB); |
| |
| // Call the replacement function. |
| SmallVector<llvm::Value *, 16> forwardedArgs; |
| for (auto &arg : IGF.CurFn->args()) |
| forwardedArgs.push_back(&arg); |
| auto *fnType = signature.getType()->getPointerTo(); |
| auto *realReplFn = IGF.Builder.CreateBitCast(ReplFn, fnType); |
| |
| auto authEntity = PointerAuthEntity(f); |
| auto authInfo = PointerAuthInfo::emit(IGF, schema, fnPtrAddr, authEntity); |
| |
| auto *Res = IGF.Builder.CreateCall( |
| FunctionPointer(silFunctionType, realReplFn, authInfo, signature), |
| forwardedArgs); |
| Res->setTailCall(); |
| if (IGF.CurFn->getReturnType()->isVoidTy()) |
| IGF.Builder.CreateRetVoid(); |
| else |
| IGF.Builder.CreateRet(Res); |
| |
| IGF.Builder.emitBlock(origEntryBB); |
| |
| } |
| |
| /// Emit the thunk that dispatches to the dynamically replaceable function. |
| static void emitDynamicallyReplaceableThunk(IRGenModule &IGM, |
| LinkEntity varEntity, |
| LinkEntity keyEntity, |
| llvm::Function *dispatchFn, |
| llvm::Function *implFn, |
| Signature &signature) { |
| |
| // Create and initialize the first link entry for the chain of replacements. |
| // The first implementation is initialized with 'implFn'. |
| auto linkEntry = getChainEntryForDynamicReplacement(IGM, varEntity, implFn); |
| |
| // Create the key data structure. This is used from other modules to refer to |
| // the chain of replacements. |
| createGlobalForDynamicReplacementFunctionKey(IGM, keyEntity, linkEntry); |
| |
| // We should never inline the implementation function. |
| implFn->addFnAttr(llvm::Attribute::NoInline); |
| |
| // Load the function and dispatch to it forwarding our arguments. |
| IRGenFunction IGF(IGM, dispatchFn); |
| if (IGM.DebugInfo) |
| IGM.DebugInfo->emitArtificialFunction(IGF, dispatchFn); |
| llvm::Constant *indices[] = {llvm::ConstantInt::get(IGM.Int32Ty, 0), |
| llvm::ConstantInt::get(IGM.Int32Ty, 0)}; |
| |
| auto *fnPtrAddr = |
| llvm::ConstantExpr::getInBoundsGetElementPtr(nullptr, linkEntry, indices); |
| auto *fnPtr = IGF.Builder.CreateLoad(fnPtrAddr, IGM.getPointerAlignment()); |
| auto *typeFnPtr = IGF.Builder.CreateBitOrPointerCast(fnPtr, implFn->getType()); |
| |
| SmallVector<llvm::Value *, 16> forwardedArgs; |
| for (auto &arg : dispatchFn->args()) |
| forwardedArgs.push_back(&arg); |
| |
| auto &schema = IGM.getOptions().PointerAuth.SwiftDynamicReplacements; |
| assert(keyEntity.hasSILFunction() || |
| keyEntity.isOpaqueTypeDescriptorAccessor()); |
| auto authEntity = keyEntity.hasSILFunction() |
| ? PointerAuthEntity(keyEntity.getSILFunction()) |
| : PointerAuthEntity::Special::TypeDescriptor; |
| auto authInfo = PointerAuthInfo::emit(IGF, schema, fnPtrAddr, authEntity); |
| auto *Res = |
| IGF.Builder.CreateCall(FunctionPointer(FunctionPointer::KindTy::Function, |
| typeFnPtr, authInfo, signature), |
| forwardedArgs); |
| |
| Res->setTailCall(); |
| if (implFn->getReturnType()->isVoidTy()) |
| IGF.Builder.CreateRetVoid(); |
| else |
| IGF.Builder.CreateRet(Res); |
| } |
| |
| void IRGenModule::emitOpaqueTypeDescriptorAccessor(OpaqueTypeDecl *opaque) { |
| auto *namingDecl = opaque->getNamingDecl(); |
| auto *abstractStorage = dyn_cast<AbstractStorageDecl>(namingDecl); |
| |
| bool isNativeDynamic = false; |
| const bool isDynamicReplacement = namingDecl->getDynamicallyReplacedDecl(); |
| |
| // Don't emit accessors for abstract storage that is not dynamic or a dynamic |
| // replacement. |
| if (abstractStorage) { |
| isNativeDynamic = abstractStorage->hasAnyNativeDynamicAccessors(); |
| if (!isNativeDynamic && !isDynamicReplacement) |
| return; |
| } |
| |
| // Don't emit accessors for functions that are not dynamic or dynamic |
| // replacements. |
| if (!abstractStorage) { |
| isNativeDynamic = namingDecl->shouldUseNativeDynamicDispatch(); |
| if (!isNativeDynamic && !isDynamicReplacement) |
| return; |
| } |
| |
| auto accessor = |
| getAddrOfOpaqueTypeDescriptorAccessFunction(opaque, ForDefinition, false); |
| |
| if (isNativeDynamic) { |
| auto thunk = accessor; |
| auto impl = getAddrOfOpaqueTypeDescriptorAccessFunction( |
| opaque, ForDefinition, true); |
| auto varEntity = LinkEntity::forOpaqueTypeDescriptorAccessorVar(opaque); |
| auto keyEntity = LinkEntity::forOpaqueTypeDescriptorAccessorKey(opaque); |
| |
| auto fnType = llvm::FunctionType::get(OpaqueTypeDescriptorPtrTy, {}, false); |
| Signature signature(fnType, llvm::AttributeList(), SwiftCC); |
| emitDynamicallyReplaceableThunk(*this, varEntity, keyEntity, thunk, impl, |
| signature); |
| // We should never inline the thunk function. |
| thunk->addFnAttr(llvm::Attribute::NoInline); |
| accessor = impl; |
| } |
| |
| // The implementation just returns the opaque type descriptor. |
| llvm::BasicBlock *entryBB = |
| llvm::BasicBlock::Create(getLLVMContext(), "entry", accessor); |
| IRBuilder B(getLLVMContext(), false); |
| B.SetInsertPoint(entryBB); |
| if (DebugInfo) |
| DebugInfo->emitArtificialFunction(B, accessor); |
| auto *desc = getAddrOfOpaqueTypeDescriptor(opaque, ConstantInit()); |
| B.CreateRet(desc); |
| } |
| |
| /// Calls the previous implementation before this dynamic replacement became |
| /// active. |
| void IRGenModule::emitDynamicReplacementOriginalFunctionThunk(SILFunction *f) { |
| assert(f->getDynamicallyReplacedFunction()); |
| |
| if (UseBasicDynamicReplacement) |
| return; |
| |
| auto entity = LinkEntity::forSILFunction(f, true); |
| |
| auto fnType = f->getLoweredFunctionType(); |
| Signature signature = getSignature(fnType); |
| addLLVMFunctionAttributes(f, signature); |
| |
| LinkInfo implLink = LinkInfo::get(*this, entity, ForDefinition); |
| auto implFn = |
| createFunction(*this, implLink, signature, nullptr /*insertBefore*/, |
| f->getOptimizationMode()); |
| implFn->addFnAttr(llvm::Attribute::NoInline); |
| |
| IRGenFunction IGF(*this, implFn); |
| if (DebugInfo) |
| DebugInfo->emitArtificialFunction(IGF, implFn); |
| |
| LinkEntity varEntity = |
| LinkEntity::forDynamicallyReplaceableFunctionVariable(f); |
| auto linkEntry = getChainEntryForDynamicReplacement(*this, varEntity, nullptr, |
| NotForDefinition); |
| |
| // Load the function and dispatch to it forwarding our arguments. |
| llvm::Constant *indices[] = {llvm::ConstantInt::get(Int32Ty, 0), |
| llvm::ConstantInt::get(Int32Ty, 0)}; |
| |
| auto *fnPtrAddr = |
| llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast( |
| llvm::ConstantExpr::getInBoundsGetElementPtr(nullptr, linkEntry, indices), |
| FunctionPtrTy->getPointerTo()); |
| |
| auto *OrigFn = |
| IGF.Builder.CreateCall(getGetOrigOfReplaceableFn(), {fnPtrAddr}); |
| |
| OrigFn->setDoesNotThrow(); |
| |
| auto *typeFnPtr = |
| IGF.Builder.CreateBitOrPointerCast(OrigFn, implFn->getType()); |
| |
| SmallVector<llvm::Value *, 16> forwardedArgs; |
| for (auto &arg : implFn->args()) |
| forwardedArgs.push_back(&arg); |
| |
| auto &schema = getOptions().PointerAuth.SwiftDynamicReplacements; |
| auto authInfo = PointerAuthInfo::emit( |
| IGF, schema, fnPtrAddr, |
| PointerAuthEntity(f->getDynamicallyReplacedFunction())); |
| auto *Res = IGF.Builder.CreateCall( |
| FunctionPointer(fnType, typeFnPtr, authInfo, signature), forwardedArgs); |
| |
| if (implFn->getReturnType()->isVoidTy()) |
| IGF.Builder.CreateRetVoid(); |
| else |
| IGF.Builder.CreateRet(Res); |
| } |
| |
| /// If the calling convention for `ctor` doesn't match the calling convention |
| /// that we assumed for it when we imported it as `initializer`, emit and |
| /// return a thunk that conforms to the assumed calling convention. The thunk |
| /// is marked `alwaysinline`, so it doesn't generate any runtime overhead. |
| /// If the assumed calling convention was correct, just return `ctor`. |
| /// |
| /// See also comments in CXXMethodConventions in SIL/IR/SILFunctionType.cpp. |
| static llvm::Constant * |
| emitCXXConstructorThunkIfNeeded(IRGenModule &IGM, SILFunction *initializer, |
| const clang::CXXConstructorDecl *ctor, |
| const LinkEntity &entity, |
| llvm::Constant *ctorAddress) { |
| Signature signature = IGM.getSignature(initializer->getLoweredFunctionType()); |
| |
| llvm::FunctionType *assumedFnType = signature.getType(); |
| llvm::FunctionType *ctorFnType = |
| cast<llvm::FunctionType>(ctorAddress->getType()->getPointerElementType()); |
| |
| if (assumedFnType == ctorFnType) { |
| return ctorAddress; |
| } |
| |
| // The thunk has private linkage, so it doesn't need to have a predictable |
| // mangled name -- we just need to make sure the name is unique. |
| llvm::SmallString<32> name; |
| llvm::raw_svector_ostream stream(name); |
| stream << "__swift_cxx_ctor"; |
| entity.mangle(stream); |
| |
| llvm::Function *thunk = llvm::Function::Create( |
| assumedFnType, llvm::Function::PrivateLinkage, name, &IGM.Module); |
| |
| thunk->setCallingConv(llvm::CallingConv::C); |
| |
| llvm::AttrBuilder attrBuilder; |
| IGM.constructInitialFnAttributes(attrBuilder); |
| attrBuilder.addAttribute(llvm::Attribute::AlwaysInline); |
| llvm::AttributeList attr = signature.getAttributes().addAttributes( |
| IGM.getLLVMContext(), llvm::AttributeList::FunctionIndex, attrBuilder); |
| thunk->setAttributes(attr); |
| |
| IRGenFunction subIGF(IGM, thunk); |
| if (IGM.DebugInfo) |
| IGM.DebugInfo->emitArtificialFunction(subIGF, thunk); |
| |
| SmallVector<llvm::Value *, 8> Args; |
| for (auto i = thunk->arg_begin(), e = thunk->arg_end(); i != e; ++i) { |
| auto *argTy = i->getType(); |
| auto *paramTy = ctorFnType->getParamType(i - thunk->arg_begin()); |
| if (paramTy != argTy) |
| Args.push_back(subIGF.coerceValue(i, paramTy, IGM.DataLayout)); |
| else |
| Args.push_back(i); |
| } |
| |
| clang::CodeGen::ImplicitCXXConstructorArgs implicitArgs = |
| clang::CodeGen::getImplicitCXXConstructorArgs(IGM.ClangCodeGen->CGM(), |
| ctor); |
| for (size_t i = 0; i < implicitArgs.Prefix.size(); ++i) { |
| Args.insert(Args.begin() + 1 + i, implicitArgs.Prefix[i]); |
| } |
| for (const auto &arg : implicitArgs.Suffix) { |
| Args.push_back(arg); |
| } |
| |
| subIGF.Builder.CreateCall(ctorFnType, ctorAddress, Args); |
| subIGF.Builder.CreateRetVoid(); |
| |
| return thunk; |
| } |
| |
| /// Find the entry point for a SIL function. |
| llvm::Function *IRGenModule::getAddrOfSILFunction( |
| SILFunction *f, ForDefinition_t forDefinition, |
| bool isDynamicallyReplaceableImplementation, |
| bool shouldCallPreviousImplementation) { |
| assert(forDefinition || !isDynamicallyReplaceableImplementation); |
| assert(!forDefinition || !shouldCallPreviousImplementation); |
| |
| LinkEntity entity = |
| LinkEntity::forSILFunction(f, shouldCallPreviousImplementation); |
| |
| // Check whether we've created the function already. |
| // FIXME: We should integrate this into the LinkEntity cache more cleanly. |
| llvm::Function *fn = Module.getFunction(entity.mangleAsString()); |
| if (fn) { |
| if (forDefinition) { |
| updateLinkageForDefinition(*this, fn, entity); |
| } |
| return fn; |
| } |
| |
| // If it's a Clang declaration, ask Clang to generate the IR declaration. |
| // This might generate new functions, so we should do it before computing |
| // the insert-before point. |
| llvm::Constant *clangAddr = nullptr; |
| if (auto clangDecl = f->getClangDecl()) { |
| // If we have an Objective-C Clang declaration, it must be a direct |
| // method and we want to generate the IR declaration ourselves. |
| if (auto objcDecl = dyn_cast<clang::ObjCMethodDecl>(clangDecl)) { |
| assert(objcDecl->isDirectMethod()); |
| } else { |
| auto globalDecl = getClangGlobalDeclForFunction(clangDecl); |
| clangAddr = getAddrOfClangGlobalDecl(globalDecl, forDefinition); |
| |
| if (auto ctor = dyn_cast<clang::CXXConstructorDecl>(clangDecl)) { |
| clangAddr = |
| emitCXXConstructorThunkIfNeeded(*this, f, ctor, entity, clangAddr); |
| } |
| } |
| } |
| |
| bool isDefinition = f->isDefinition(); |
| bool hasOrderNumber = |
| isDefinition && !shouldCallPreviousImplementation; |
| unsigned orderNumber = ~0U; |
| llvm::Function *insertBefore = nullptr; |
| |
| // If the SIL function has a definition, we should have an order |
| // number for it; make sure to insert it in that position relative |
| // to other ordered functions. |
| if (hasOrderNumber) { |
| orderNumber = IRGen.getFunctionOrder(f); |
| if (auto emittedFunctionIterator |
| = EmittedFunctionsByOrder.findLeastUpperBound(orderNumber)) |
| insertBefore = *emittedFunctionIterator; |
| } |
| |
| // If it's a Clang declaration, check whether Clang gave us a declaration. |
| if (clangAddr) { |
| fn = dyn_cast<llvm::Function>(clangAddr->stripPointerCasts()); |
| |
| // If we have a function, move it to the appropriate position. |
| if (fn) { |
| if (hasOrderNumber) { |
| auto &fnList = Module.getFunctionList(); |
| fnList.remove(fn); |
| fnList.insert(llvm::Module::iterator(insertBefore), fn); |
| |
| EmittedFunctionsByOrder.insert(orderNumber, fn); |
| } |
| return fn; |
| } |
| |
| // Otherwise, if we have a lazy definition for it, be sure to queue that up. |
| } else if (isDefinition && !forDefinition && !f->isPossiblyUsedExternally() && |
| !hasCodeCoverageInstrumentation(*f, getSILModule())) { |
| IRGen.addLazyFunction(f); |
| } |
| |
| Signature signature = getSignature(f->getLoweredFunctionType()); |
| addLLVMFunctionAttributes(f, signature); |
| |
| LinkInfo link = LinkInfo::get(*this, entity, forDefinition); |
| |
| fn = createFunction(*this, link, signature, insertBefore, |
| f->getOptimizationMode()); |
| |
| // If `hasCReferences` is true, then the function is either marked with |
| // @_silgen_name OR @_cdecl. If it is the latter, it must have a definition |
| // associated with it. The combination of the two allows us to identify the |
| // @_silgen_name functions. These are locally defined function thunks used in |
| // the standard library. Do not give them DLLImport DLL Storage. |
| if (!forDefinition) { |
| fn->setComdat(nullptr); |
| if (f->hasCReferences()) |
| fn->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass); |
| } |
| |
| // If we have an order number for this function, set it up as appropriate. |
| if (hasOrderNumber) { |
| EmittedFunctionsByOrder.insert(orderNumber, fn); |
| } |
| return fn; |
| } |
| |
| static llvm::GlobalVariable *createGOTEquivalent(IRGenModule &IGM, |
| llvm::Constant *global, |
| LinkEntity entity) |
| { |
| // Determine the name of this entity. |
| llvm::SmallString<64> globalName; |
| entity.mangle(globalName); |
| |
| if (IGM.Triple.getObjectFormat() == llvm::Triple::COFF) { |
| if (cast<llvm::GlobalValue>(global)->hasDLLImportStorageClass()) { |
| // Add the user label prefix *prior* to the introduction of the linker |
| // synthetic marker `__imp_`. |
| // Failure to do so will re-decorate the generated symbol and miss the |
| // user label prefix, generating e.g. `___imp_$sBoW` instead of |
| // `__imp__$sBoW`. |
| if (auto prefix = IGM.DataLayout.getGlobalPrefix()) |
| globalName = (llvm::Twine(prefix) + globalName).str(); |
| // Indicate to LLVM that the symbol should not be re-decorated. |
| llvm::GlobalVariable *GV = |
| new llvm::GlobalVariable(IGM.Module, global->getType(), |
| /*Constant=*/true, |
| llvm::GlobalValue::ExternalLinkage, nullptr, |
| "\01__imp_" + globalName); |
| GV->setExternallyInitialized(true); |
| return GV; |
| } |
| } |
| |
| auto gotEquivalent = new llvm::GlobalVariable(IGM.Module, |
| global->getType(), |
| /*constant*/ true, |
| llvm::GlobalValue::PrivateLinkage, |
| global, |
| llvm::Twine("got.") + globalName); |
| |
| // rdar://problem/53836960: i386 ld64 also mis-links relative references |
| // to GOT entries. |
| // rdar://problem/59782487: issue with on-device JITd expressions. |
| // The JIT gets confused by private vars accessed accross object files. |
| if (!IGM.getOptions().UseJIT && |
| (!IGM.Triple.isOSDarwin() || IGM.Triple.getArch() != llvm::Triple::x86)) { |
| gotEquivalent->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); |
| } else { |
| ApplyIRLinkage(IRLinkage::InternalLinkOnceODR) |
| .to(gotEquivalent); |
| } |
| |
| // Context descriptor pointers need to be signed. |
| // TODO: We should really sign a pointer to *any* code entity or true-const |
| // metadata structure that may reference data structures with function |
| // pointers inside them. |
| if (entity.isContextDescriptor()) { |
| auto schema = IGM.getOptions().PointerAuth.TypeDescriptors; |
| if (schema) { |
| auto signedValue = IGM.getConstantSignedPointer( |
| global, schema, PointerAuthEntity::Special::TypeDescriptor, |
| /*storageAddress*/ gotEquivalent); |
| gotEquivalent->setInitializer(signedValue); |
| } |
| } else if (entity.isDynamicallyReplaceableKey()) { |
| auto schema = IGM.getOptions().PointerAuth.SwiftDynamicReplacementKeys; |
| if (schema) { |
| auto signedValue = IGM.getConstantSignedPointer( |
| global, schema, PointerAuthEntity::Special::DynamicReplacementKey, |
| /*storageAddress*/ gotEquivalent); |
| gotEquivalent->setInitializer(signedValue); |
| } |
| } |
| |
| return gotEquivalent; |
| } |
| |
| llvm::Constant *IRGenModule::getOrCreateGOTEquivalent(llvm::Constant *global, |
| LinkEntity entity) { |
| auto &gotEntry = GlobalGOTEquivalents[entity]; |
| if (gotEntry) { |
| return gotEntry; |
| } |
| |
| if (auto *Stats = Context.Stats) |
| ++Stats->getFrontendCounters().NumGOTEntries; |
| |
| // Use the global as the initializer for an anonymous constant. LLVM can treat |
| // this as equivalent to the global's GOT entry. |
| auto gotEquivalent = createGOTEquivalent(*this, global, entity); |
| gotEntry = gotEquivalent; |
| return gotEquivalent; |
| } |
| |
| static llvm::Constant *getElementBitCast(llvm::Constant *ptr, |
| llvm::Type *newEltType) { |
| auto ptrType = cast<llvm::PointerType>(ptr->getType()); |
| if (ptrType->getElementType() == newEltType) { |
| return ptr; |
| } else { |
| auto newPtrType = newEltType->getPointerTo(ptrType->getAddressSpace()); |
| return llvm::ConstantExpr::getBitCast(ptr, newPtrType); |
| } |
| } |
| |
| /// Return a reference to an object that's suitable for being used for |
| /// the given kind of reference. |
| /// |
| /// Note that, if the requested reference kind is a relative reference. |
| /// the returned constant will not actually be a relative reference. |
| /// To form the actual relative reference, you must pass the returned |
| /// result to emitRelativeReference, passing the correct base-address |
| /// information. |
| ConstantReference |
| IRGenModule::getAddrOfLLVMVariable(LinkEntity entity, |
| ConstantInit definition, |
| DebugTypeInfo debugType, |
| SymbolReferenceKind refKind, |
| llvm::Type *overrideDeclType) { |
| switch (refKind) { |
| case SymbolReferenceKind::Relative_Direct: |
| case SymbolReferenceKind::Far_Relative_Direct: |
| assert(!definition); |
| // FIXME: don't just fall through; force the creation of a weak |
| // definition so that we can emit a relative reference. |
| LLVM_FALLTHROUGH; |
| |
| case SymbolReferenceKind::Absolute: |
| return { getAddrOfLLVMVariable(entity, definition, debugType, |
| overrideDeclType), |
| ConstantReference::Direct }; |
| |
| |
| case SymbolReferenceKind::Relative_Indirectable: |
| case SymbolReferenceKind::Far_Relative_Indirectable: |
| assert(!definition); |
| return getAddrOfLLVMVariableOrGOTEquivalent(entity); |
| } |
| llvm_unreachable("bad reference kind"); |
| } |
| |
| /// A convenient wrapper around getAddrOfLLVMVariable which uses the |
| /// default type as the definition type. |
| llvm::Constant * |
| IRGenModule::getAddrOfLLVMVariable(LinkEntity entity, |
| ForDefinition_t forDefinition, |
| DebugTypeInfo debugType) { |
| auto definition = forDefinition |
| ? ConstantInit::getDelayed(entity.getDefaultDeclarationType(*this)) |
| : ConstantInit(); |
| return getAddrOfLLVMVariable(entity, definition, debugType); |
| } |
| |
| /// Get or create an llvm::GlobalVariable. |
| /// |
| /// If a definition type is given, the result will always be an |
| /// llvm::GlobalVariable of that type. Otherwise, the result will |
| /// have type pointerToDefaultType and may involve bitcasts. |
| llvm::Constant * |
| IRGenModule::getAddrOfLLVMVariable(LinkEntity entity, |
| ConstantInit definition, |
| DebugTypeInfo DbgTy, |
| llvm::Type *overrideDeclType) { |
| // This function assumes that 'globals' only contains GlobalValue |
| // values for the entities that it will look up. |
| |
| llvm::Type *definitionType = (definition ? definition.getType() : nullptr); |
| auto defaultType = overrideDeclType |
| ? overrideDeclType |
| : entity.getDefaultDeclarationType(*this); |
| |
| auto &entry = GlobalVars[entity]; |
| if (entry) { |
| auto existing = cast<llvm::GlobalValue>(entry); |
| |
| // If we're looking to define something, we may need to replace a |
| // forward declaration. |
| if (definitionType) { |
| assert(existing->isDeclaration() && "already defined"); |
| updateLinkageForDefinition(*this, existing, entity); |
| |
| // If the existing entry is a variable of the right type, |
| // set the initializer on it and return. |
| if (auto var = dyn_cast<llvm::GlobalVariable>(existing)) { |
| if (definitionType == var->getValueType()) { |
| if (definition.hasInit()) |
| definition.getInit().installInGlobal(var); |
| return var; |
| } |
| } |
| |
| // Fall out to the case below, clearing the name so that |
| // createVariable doesn't detect a collision. |
| entry->setName(""); |
| |
| // Otherwise, we have a previous declaration or definition which |
| // we need to ensure has the right type. |
| } else { |
| return getElementBitCast(entry, defaultType); |
| } |
| } |
| |
| ForDefinition_t forDefinition = (ForDefinition_t) (definitionType != nullptr); |
| LinkInfo link = LinkInfo::get(*this, entity, forDefinition); |
| |
| // Clang may have defined the variable already. |
| if (auto existing = Module.getNamedGlobal(link.getName())) |
| return getElementBitCast(existing, defaultType); |
| |
| // If we're not defining the object now, forward declare it with the default |
| // type. |
| if (!definitionType) definitionType = defaultType; |
| |
| // Create the variable. |
| auto var = createVariable(*this, link, definitionType, |
| entity.getAlignment(*this), DbgTy); |
| |
| // Install the concrete definition if we have one. |
| if (definition && definition.hasInit()) { |
| definition.getInit().installInGlobal(var); |
| } |
| |
| // If we have an existing entry, destroy it, replacing it with the |
| // new variable. |
| if (entry) { |
| auto existing = cast<llvm::GlobalValue>(entry); |
| auto castVar = llvm::ConstantExpr::getBitCast(var, entry->getType()); |
| existing->replaceAllUsesWith(castVar); |
| existing->eraseFromParent(); |
| } |
| |
| // If there's also an existing GOT-equivalent entry, rewrite it too, since |
| // LLVM won't recognize a global with bitcasts in its initializers as GOT- |
| // equivalent. rdar://problem/22388190 |
| auto foundGOTEntry = GlobalGOTEquivalents.find(entity); |
| if (foundGOTEntry != GlobalGOTEquivalents.end() && foundGOTEntry->second) { |
| auto existingGOTEquiv = cast<llvm::GlobalVariable>(foundGOTEntry->second); |
| |
| // Make a new GOT equivalent referring to the new variable with its |
| // definition type. |
| auto newGOTEquiv = createGOTEquivalent(*this, var, entity); |
| auto castGOTEquiv = llvm::ConstantExpr::getBitCast(newGOTEquiv, |
| existingGOTEquiv->getType()); |
| existingGOTEquiv->replaceAllUsesWith(castGOTEquiv); |
| existingGOTEquiv->eraseFromParent(); |
| GlobalGOTEquivalents[entity] = newGOTEquiv; |
| } |
| |
| // Cache and return. |
| entry = var; |
| return var; |
| } |
| |
| /// Get or create a "GOT equivalent" llvm::GlobalVariable, if applicable. |
| /// |
| /// Creates a private, unnamed constant containing the address of another |
| /// global variable. LLVM can replace relative references to this variable with |
| /// relative references to the GOT entry for the variable in the object file. |
| ConstantReference |
| IRGenModule::getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity) { |
| auto canDirectlyReferenceSILFunction = [&](SILFunction *silFn) { |
| return (silFn->isDefinition() && |
| !isAvailableExternally(silFn->getLinkage()) && |
| this == IRGen.getGenModule(silFn)); |
| }; |
| |
| // Handle SILFunctions specially, because unlike other entities they aren't |
| // variables and aren't kept in the GlobalVars table. |
| if (entity.isSILFunction()) { |
| auto *silFn = entity.getSILFunction(); |
| auto fn = getAddrOfSILFunction(silFn, NotForDefinition); |
| if (canDirectlyReferenceSILFunction(silFn)) { |
| return {fn, ConstantReference::Direct}; |
| } |
| |
| auto gotEquivalent = getOrCreateGOTEquivalent(fn, entity); |
| return {gotEquivalent, ConstantReference::Indirect}; |
| } |
| |
| // ObjC class references can always be directly referenced, even in |
| // the weird cases where we don't see a definition. |
| if (entity.isObjCClassRef()) { |
| auto value = getAddrOfObjCClassRef( |
| const_cast<ClassDecl *>(cast<ClassDecl>(entity.getDecl()))); |
| return { cast<llvm::Constant>(value.getAddress()), |
| ConstantReference::Direct }; |
| } |
| |
| // Ensure the variable is at least forward-declared. |
| getAddrOfLLVMVariable(entity, ConstantInit(), DebugTypeInfo()); |
| |
| auto entry = GlobalVars[entity]; |
| |
| /// Returns a direct reference. |
| auto direct = [&]() -> ConstantReference { |
| // FIXME: Relative references to aliases break MC on 32-bit Mach-O |
| // platforms (rdar://problem/22450593 ), so substitute an alias with its |
| // aliasee to work around that. |
| if (auto alias = dyn_cast<llvm::GlobalAlias>(entry)) |
| return {alias->getAliasee(), ConstantReference::Direct}; |
| return {entry, ConstantReference::Direct}; |
| }; |
| |
| /// Returns an indirect reference. |
| auto indirect = [&]() -> ConstantReference { |
| auto gotEquivalent = getOrCreateGOTEquivalent( |
| cast<llvm::GlobalValue>(entry), entity); |
| return {gotEquivalent, ConstantReference::Indirect}; |
| }; |
| |
| // Dynamically replaceable function keys are stored in the GlobalVars |
| // table, but they don't have an associated Decl, so they require |
| // special treatment here. |
| if (entity.isDynamicallyReplaceableFunctionKey()) { |
| auto *silFn = entity.getSILFunction(); |
| if (canDirectlyReferenceSILFunction(silFn)) |
| return direct(); |
| |
| return indirect(); |
| } |
| |
| if (auto *entityDC = entity.getDeclContextForEmission()) { |
| auto *entitySF = entityDC->getModuleScopeContext(); |
| bool clangImportedEntity = isa<ClangModuleUnit>(entitySF); |
| |
| auto &mod = getSILModule(); |
| |
| if (!mod.isWholeModule()) { |
| // In non-WMO builds, the associated context of the SILModule must |
| // be a source file. Every source file is its own translation unit. |
| auto *modDC = mod.getAssociatedContext(); |
| auto *modSF = modDC->getModuleScopeContext(); |
| assert(modSF != nullptr); |
| |
| // Imported entities are in a different Swift module, but are emitted |
| // on demand and can be referenced directly. Entities in the same |
| // source file can also be referenced directly. |
| if (clangImportedEntity || |
| modSF == entitySF) |
| return direct(); |
| |
| // Everything else must be referenced indirectly. |
| return indirect(); |
| } |
| |
| // We're performing a WMO build. |
| // |
| // The associated context of the SILModule is the entire AST ModuleDecl, |
| // but we might be doing a multi-threaded IRGen build, in which case |
| // there is one translation unit per source file. |
| |
| // Imported entities are in a different Swift module and are emitted |
| // on demand. In multi-threaded builds, they will be emitted into one |
| // translation unit only. |
| if (clangImportedEntity || |
| entitySF->getParentModule() == mod.getSwiftModule()) { |
| // If we're doing a single-threaded WMO build, or if the entity is |
| // scheduled to be emitted in the same translation unit, reference |
| // it directly. |
| if (this == IRGen.getGenModule(entitySF)) |
| return direct(); |
| } |
| } |
| |
| // Fall back to an indirect reference if we can't establish that a direct |
| // reference is OK. |
| return indirect(); |
| } |
| |
| static TypeEntityReference |
| getContextDescriptorEntityReference(IRGenModule &IGM, const LinkEntity &entity){ |
| // TODO: consider using a symbolic reference (i.e. a symbol string |
| // to be looked up dynamically) for types defined outside the module. |
| auto ref = IGM.getAddrOfLLVMVariableOrGOTEquivalent(entity); |
| auto kind = ref.isIndirect() |
| ? TypeReferenceKind::IndirectTypeDescriptor |
| : TypeReferenceKind::DirectTypeDescriptor; |
| return TypeEntityReference(kind, ref.getValue()); |
| } |
| |
| static TypeEntityReference |
| getTypeContextDescriptorEntityReference(IRGenModule &IGM, |
| NominalTypeDecl *decl) { |
| auto entity = LinkEntity::forNominalTypeDescriptor(decl); |
| IGM.IRGen.noteUseOfTypeContextDescriptor(decl, DontRequireMetadata); |
| return getContextDescriptorEntityReference(IGM, entity); |
| } |
| |
| static TypeEntityReference |
| getProtocolDescriptorEntityReference(IRGenModule &IGM, ProtocolDecl *protocol) { |
| assert(!protocol->isObjC() && |
| "objc protocols don't have swift protocol descriptors"); |
| auto entity = LinkEntity::forProtocolDescriptor(protocol); |
| return getContextDescriptorEntityReference(IGM, entity); |
| } |
| |
| static TypeEntityReference |
| getObjCClassByNameReference(IRGenModule &IGM, ClassDecl *cls) { |
| auto kind = TypeReferenceKind::DirectObjCClassName; |
| SmallString<64> objcRuntimeNameBuffer; |
| auto ref = IGM.getAddrOfGlobalString( |
| cls->getObjCRuntimeName(objcRuntimeNameBuffer), |
| /*willBeRelativelyAddressed=*/true); |
| |
| return TypeEntityReference(kind, ref); |
| } |
| |
| TypeEntityReference |
| IRGenModule::getTypeEntityReference(GenericTypeDecl *decl) { |
| if (auto protocol = dyn_cast<ProtocolDecl>(decl)) { |
| assert(!protocol->isObjC() && "imported protocols not handled here"); |
| return getProtocolDescriptorEntityReference(*this, protocol); |
| } |
| |
| if (auto opaque = dyn_cast<OpaqueTypeDecl>(decl)) { |
| auto entity = LinkEntity::forOpaqueTypeDescriptor(opaque); |
| IRGen.noteUseOfOpaqueTypeDescriptor(opaque); |
| return getContextDescriptorEntityReference(*this, entity); |
| } |
| |
| if (auto nominal = dyn_cast<NominalTypeDecl>(decl)) { |
| auto clas = dyn_cast<ClassDecl>(decl); |
| if (!clas) { |
| return getTypeContextDescriptorEntityReference(*this, nominal); |
| } |
| |
| switch (clas->getForeignClassKind()) { |
| case ClassDecl::ForeignKind::RuntimeOnly: |
| return getObjCClassByNameReference(*this, clas); |
| |
| case ClassDecl::ForeignKind::CFType: |
| return getTypeContextDescriptorEntityReference(*this, clas); |
| |
| case ClassDecl::ForeignKind::Normal: |
| if (hasKnownSwiftMetadata(*this, clas)) { |
| return getTypeContextDescriptorEntityReference(*this, clas); |
| } |
| |
| // Note: we would like to use an Objective-C class reference, but the |
| // Darwin linker currently has a bug where it will coalesce these symbols |
| // *after* computing a relative offset, causing incorrect relative |
| // offsets in the metadata. Therefore, reference Objective-C classes by |
| // their runtime names. |
| return getObjCClassByNameReference(*this, clas); |
| } |
| } |
| llvm_unreachable("bad foreign type kind"); |
| } |
| |
| /// Form an LLVM constant for the relative distance between a reference |
| /// (appearing at gep (0, indices) of `base`) and `target`. |
| llvm::Constant * |
| IRGenModule::emitRelativeReference(ConstantReference target, |
| llvm::Constant *base, |
| ArrayRef<unsigned> baseIndices) { |
| llvm::Constant *relativeAddr = |
| emitDirectRelativeReference(target.getValue(), base, baseIndices); |
| |
| // If the reference is indirect, flag it by setting the low bit. |
| // (All of the base, direct target, and GOT entry need to be pointer-aligned |
| // for this to be OK.) |
| if (target.isIndirect()) { |
| relativeAddr = llvm::ConstantExpr::getAdd(relativeAddr, |
| llvm::ConstantInt::get(RelativeAddressTy, 1)); |
| } |
| |
| return relativeAddr; |
| } |
| |
| /// Form an LLVM constant for the relative distance between a reference |
| /// (appearing at gep (0, indices...) of `base`) and `target`. For now, |
| /// for this to succeed portably, both need to be globals defined in the |
| /// current translation unit. |
| llvm::Constant * |
| IRGenModule::emitDirectRelativeReference(llvm::Constant *target, |
| llvm::Constant *base, |
| ArrayRef<unsigned> baseIndices) { |
| // Convert the target to an integer. |
| auto targetAddr = llvm::ConstantExpr::getPtrToInt(target, SizeTy); |
| |
| SmallVector<llvm::Constant*, 4> indices; |
| indices.push_back(llvm::ConstantInt::get(Int32Ty, 0)); |
| for (unsigned baseIndex : baseIndices) { |
| indices.push_back(llvm::ConstantInt::get(Int32Ty, baseIndex)); |
| }; |
| |
| // Drill down to the appropriate address in the base, then convert |
| // that to an integer. |
| auto baseElt = llvm::ConstantExpr::getInBoundsGetElementPtr( |
| base->getType()->getPointerElementType(), base, indices); |
| auto baseAddr = llvm::ConstantExpr::getPtrToInt(baseElt, SizeTy); |
| |
| // The relative address is the difference between those. |
| auto relativeAddr = llvm::ConstantExpr::getSub(targetAddr, baseAddr); |
| |
| // Relative addresses can be 32-bit even on 64-bit platforms. |
| if (SizeTy != RelativeAddressTy) |
| relativeAddr = llvm::ConstantExpr::getTrunc(relativeAddr, |
| RelativeAddressTy); |
| |
| return relativeAddr; |
| } |
| |
| /// Emit the protocol descriptors list and return it. |
| llvm::Constant *IRGenModule::emitSwiftProtocols() { |
| if (SwiftProtocols.empty()) |
| return nullptr; |
| |
| // Define the global variable for the protocol list. |
| ConstantInitBuilder builder(*this); |
| auto recordsArray = builder.beginArray(ProtocolRecordTy); |
| |
| for (auto *protocol : SwiftProtocols) { |
| auto record = recordsArray.beginStruct(ProtocolRecordTy); |
| |
| // Relative reference to the protocol descriptor. |
| auto descriptorRef = getAddrOfLLVMVariableOrGOTEquivalent( |
| LinkEntity::forProtocolDescriptor(protocol)); |
| record.addRelativeAddress(descriptorRef); |
| |
| record.finishAndAddTo(recordsArray); |
| } |
| |
| // FIXME: This needs to be a linker-local symbol in order for Darwin ld to |
| // resolve relocations relative to it. |
| |
| auto var = recordsArray.finishAndCreateGlobal( |
| "\x01l_protocols", |
| Alignment(4), |
| /*isConstant*/ true, |
| llvm::GlobalValue::PrivateLinkage); |
| |
| StringRef sectionName; |
| switch (TargetInfo.OutputObjectFormat) { |
| case llvm::Triple::UnknownObjectFormat: |
| llvm_unreachable("Don't know how to emit protocols for " |
| "the selected object format."); |
| case llvm::Triple::MachO: |
| sectionName = "__TEXT, __swift5_protos, regular, no_dead_strip"; |
| break; |
| case llvm::Triple::ELF: |
| case llvm::Triple::Wasm: |
| sectionName = "swift5_protocols"; |
| break; |
| case llvm::Triple::XCOFF: |
| case llvm::Triple::COFF: |
| sectionName = ".sw5prt$B"; |
| break; |
| } |
| |
| var->setSection(sectionName); |
| |
| disableAddressSanitizer(*this, var); |
| |
| addUsedGlobal(var); |
| return var; |
| } |
| |
| void IRGenModule::addProtocolConformance(ConformanceDescription &&record) { |
| |
| emitProtocolConformance(record); |
| |
| // Add this conformance to the conformance list. |
| ProtocolConformances.push_back(std::move(record)); |
| } |
| |
| /// Emit the protocol conformance list and return it. |
| llvm::Constant *IRGenModule::emitProtocolConformances() { |
| if (ProtocolConformances.empty()) |
| return nullptr; |
| |
| // Define the global variable for the conformance list. |
| ConstantInitBuilder builder(*this); |
| auto descriptorArray = builder.beginArray(RelativeAddressTy); |
| |
| for (const auto &record : ProtocolConformances) { |
| auto conformance = record.conformance; |
| auto entity = LinkEntity::forProtocolConformanceDescriptor(conformance); |
| auto descriptor = |
| getAddrOfLLVMVariable(entity, ConstantInit(), DebugTypeInfo()); |
| descriptorArray.addRelativeAddress(descriptor); |
| } |
| |
| // FIXME: This needs to be a linker-local symbol in order for Darwin ld to |
| // resolve relocations relative to it. |
| |
| auto var = descriptorArray.finishAndCreateGlobal( |
| "\x01l_protocol_conformances", |
| Alignment(4), |
| /*isConstant*/ true, |
| llvm::GlobalValue::PrivateLinkage); |
| |
| StringRef sectionName; |
| switch (TargetInfo.OutputObjectFormat) { |
| case llvm::Triple::UnknownObjectFormat: |
| llvm_unreachable("Don't know how to emit protocol conformances for " |
| "the selected object format."); |
| case llvm::Triple::MachO: |
| sectionName = "__TEXT, __swift5_proto, regular, no_dead_strip"; |
| break; |
| case llvm::Triple::ELF: |
| case llvm::Triple::Wasm: |
| sectionName = "swift5_protocol_conformances"; |
| break; |
| case llvm::Triple::XCOFF: |
| case llvm::Triple::COFF: |
| sectionName = ".sw5prtc$B"; |
| break; |
| } |
| |
| var->setSection(sectionName); |
| |
| disableAddressSanitizer(*this, var); |
| |
| addUsedGlobal(var); |
| return var; |
| } |
| |
| |
| /// Emit type metadata for types that might not have explicit protocol conformances. |
| llvm::Constant *IRGenModule::emitTypeMetadataRecords() { |
| std::string sectionName; |
| switch (TargetInfo.OutputObjectFormat) { |
| case llvm::Triple::MachO: |
| sectionName = "__TEXT, __swift5_types, regular, no_dead_strip"; |
| break; |
| case llvm::Triple::ELF: |
| case llvm::Triple::Wasm: |
| sectionName = "swift5_type_metadata"; |
| break; |
| case llvm::Triple::XCOFF: |
| case llvm::Triple::COFF: |
| sectionName = ".sw5tymd$B"; |
| break; |
| case llvm::Triple::UnknownObjectFormat: |
| llvm_unreachable("Don't know how to emit type metadata table for " |
| "the selected object format."); |
| } |
| |
| // Do nothing if the list is empty. |
| if (RuntimeResolvableTypes.empty()) |
| return nullptr; |
| |
| // Define the global variable for the conformance list. |
| // We have to do this before defining the initializer since the entries will |
| // contain offsets relative to themselves. |
| auto arrayTy = llvm::ArrayType::get(TypeMetadataRecordTy, |
| RuntimeResolvableTypes.size()); |
| |
| // FIXME: This needs to be a linker-local symbol in order for Darwin ld to |
| // resolve relocations relative to it. |
| auto var = new llvm::GlobalVariable(Module, arrayTy, |
| /*isConstant*/ true, |
| llvm::GlobalValue::PrivateLinkage, |
| /*initializer*/ nullptr, |
| "\x01l_type_metadata_table"); |
| |
| SmallVector<llvm::Constant *, 8> elts; |
| for (auto type : RuntimeResolvableTypes) { |
| auto ref = getTypeEntityReference(type); |
| |
| // Form the relative address, with the type reference kind in the low bits. |
| unsigned arrayIdx = elts.size(); |
| llvm::Constant *relativeAddr = |
| emitDirectRelativeReference(ref.getValue(), var, { arrayIdx, 0 }); |
| unsigned lowBits = static_cast<unsigned>(ref.getKind()); |
| if (lowBits != 0) { |
| relativeAddr = llvm::ConstantExpr::getAdd(relativeAddr, |
| llvm::ConstantInt::get(RelativeAddressTy, lowBits)); |
| } |
| |
| llvm::Constant *recordFields[] = { relativeAddr }; |
| auto record = llvm::ConstantStruct::get(TypeMetadataRecordTy, |
| recordFields); |
| elts.push_back(record); |
| } |
| |
| auto initializer = llvm::ConstantArray::get(arrayTy, elts); |
| |
| var->setInitializer(initializer); |
| var->setSection(sectionName); |
| var->setAlignment(llvm::MaybeAlign(4)); |
| |
| disableAddressSanitizer(*this, var); |
| |
| addUsedGlobal(var); |
| return var; |
| } |
| |
| llvm::Constant *IRGenModule::emitFieldDescriptors() { |
| std::string sectionName; |
| switch (TargetInfo.OutputObjectFormat) { |
| case llvm::Triple::MachO: |
| sectionName = "__TEXT, __swift5_fieldmd, regular, no_dead_strip"; |
| break; |
| case llvm::Triple::ELF: |
| case llvm::Triple::Wasm: |
| sectionName = "swift5_fieldmd"; |
| break; |
| case llvm::Triple::XCOFF: |
| case llvm::Triple::COFF: |
| sectionName = ".sw5flmd$B"; |
| break; |
| case llvm::Triple::UnknownObjectFormat: |
| llvm_unreachable("Don't know how to emit field records table for " |
| "the selected object format."); |
| } |
| |
| // Do nothing if the list is empty. |
| if (FieldDescriptors.empty()) |
| return nullptr; |
| |
| // Define the global variable for the field record list. |
| // We have to do this before defining the initializer since the entries will |
| // contain offsets relative to themselves. |
| auto arrayTy = |
| llvm::ArrayType::get(FieldDescriptorPtrTy, FieldDescriptors.size()); |
| |
| // FIXME: This needs to be a linker-local symbol in order for Darwin ld to |
| // resolve relocations relative to it. |
| auto var = new llvm::GlobalVariable( |
| Module, arrayTy, |
| /*isConstant*/ true, llvm::GlobalValue::PrivateLinkage, |
| /*initializer*/ nullptr, "\x01l_type_metadata_table"); |
| |
| SmallVector<llvm::Constant *, 8> elts; |
| for (auto *descriptor : FieldDescriptors) |
| elts.push_back( |
| llvm::ConstantExpr::getBitCast(descriptor, FieldDescriptorPtrTy)); |
| |
| var->setInitializer(llvm::ConstantArray::get(arrayTy, elts)); |
| var->setSection(sectionName); |
| var->setAlignment(llvm::MaybeAlign(4)); |
| |
| disableAddressSanitizer(*this, var); |
| |
| addUsedGlobal(var); |
| return var; |
| } |
| |
| /// Fetch a global reference to a reference to the given Objective-C class. |
| /// The result is of type ObjCClassPtrTy->getPointerTo(). |
| Address IRGenModule::getAddrOfObjCClassRef(ClassDecl *theClass) { |
| assert(ObjCInterop && "getting address of ObjC class ref in no-interop mode"); |
| |
| LinkEntity entity = LinkEntity::forObjCClassRef(theClass); |
| auto DbgTy = DebugTypeInfo::getObjCClass( |
| theClass, ObjCClassPtrTy, getPointerSize(), getPointerAlignment()); |
| auto addr = getAddrOfLLVMVariable(entity, ConstantInit(), DbgTy); |
| |
| // Define it lazily. |
| if (auto global = dyn_cast<llvm::GlobalVariable>(addr)) { |
| if (global->isDeclaration()) { |
| global->setSection(GetObjCSectionName("__objc_classrefs", |
| "regular,no_dead_strip")); |
| global->setLinkage(llvm::GlobalVariable::PrivateLinkage); |
| global->setExternallyInitialized(true); |
| global->setInitializer(getAddrOfObjCClass(theClass, NotForDefinition)); |
| addCompilerUsedGlobal(global); |
| } |
| } |
| |
| return Address(addr, entity.getAlignment(*this)); |
| } |
| |
| /// Fetch a global reference to the given Objective-C class. The |
| /// result is of type ObjCClassPtrTy. |
| llvm::Constant *IRGenModule::getAddrOfObjCClass(ClassDecl *theClass, |
| ForDefinition_t forDefinition) { |
| assert(ObjCInterop && "getting address of ObjC class in no-interop mode"); |
| assert(!theClass->isForeign()); |
| LinkEntity entity = LinkEntity::forObjCClass(theClass); |
| auto DbgTy = DebugTypeInfo::getObjCClass( |
| theClass, ObjCClassPtrTy, getPointerSize(), getPointerAlignment()); |
| auto addr = getAddrOfLLVMVariable(entity, forDefinition, DbgTy); |
| return addr; |
| } |
| |
| /// Fetch the declaration of a metaclass object. The result is always a |
| /// GlobalValue of ObjCClassPtrTy, and is either the Objective-C metaclass or |
| /// the Swift metaclass stub, depending on whether the class is published as an |
| /// ObjC class. |
| llvm::Constant * |
| IRGenModule::getAddrOfMetaclassObject(ClassDecl *decl, |
| ForDefinition_t forDefinition) { |
| assert((!decl->isGenericContext() || decl->hasClangNode()) && |
| "generic classes do not have a static metaclass object"); |
| |
| auto entity = decl->getMetaclassKind() == ClassDecl::MetaclassKind::ObjC |
| ? LinkEntity::forObjCMetaclass(decl) |
| : LinkEntity::forSwiftMetaclassStub(decl); |
| |
| auto DbgTy = DebugTypeInfo::getObjCClass( |
| decl, ObjCClassPtrTy, getPointerSize(), getPointerAlignment()); |
| auto addr = getAddrOfLLVMVariable(entity, forDefinition, DbgTy); |
| return addr; |
| } |
| |
| llvm::Constant * |
| IRGenModule::getAddrOfCanonicalSpecializedGenericMetaclassObject( |
| CanType concreteType, ForDefinition_t forDefinition) { |
| auto *theClass = concreteType->getClassOrBoundGenericClass(); |
| assert(theClass && "only classes have metaclasses"); |
| assert(concreteType->getClassOrBoundGenericClass()->isGenericContext()); |
| |
| auto entity = |
| LinkEntity::forSpecializedGenericSwiftMetaclassStub(concreteType); |
| |
| auto DbgTy = DebugTypeInfo::getObjCClass( |
| theClass, ObjCClassPtrTy, getPointerSize(), getPointerAlignment()); |
| auto addr = getAddrOfLLVMVariable(entity, forDefinition, DbgTy); |
| return addr; |
| } |
| |
| /// Fetch the declaration of an Objective-C metadata update callback. |
| llvm::Function * |
| IRGenModule::getAddrOfObjCMetadataUpdateFunction(ClassDecl *classDecl, |
| ForDefinition_t forDefinition) { |
| assert(ObjCInterop); |
| |
| LinkEntity entity = LinkEntity::forObjCMetadataUpdateFunction(classDecl); |
| llvm::Function *&entry = GlobalFuncs[entity]; |
| if (entry) { |
| if (forDefinition) updateLinkageForDefinition(*this, entry, entity); |
| return entry; |
| } |
| |
| // Class _Nullable callback(Class _Nonnull cls, void * _Nullable arg); |
| Signature signature(ObjCUpdateCallbackTy, llvm::AttributeList(), DefaultCC); |
| LinkInfo link = LinkInfo::get(*this, entity, forDefinition); |
| entry = createFunction(*this, link, signature); |
| return entry; |
| } |
| |
| /// Fetch the declaration of an Objective-C resilient class stub. |
| llvm::Constant * |
| IRGenModule::getAddrOfObjCResilientClassStub(ClassDecl *classDecl, |
| ForDefinition_t forDefinition, |
| TypeMetadataAddress addr) { |
| assert(ObjCInterop); |
| assert(getClassMetadataStrategy(classDecl) == |
| ClassMetadataStrategy::Resilient); |
| |
| LinkEntity entity = LinkEntity::forObjCResilientClassStub(classDecl, addr); |
| return getAddrOfLLVMVariable(entity, forDefinition, DebugTypeInfo()); |
| } |
| |
| /// Fetch the type metadata access function for a non-generic type. |
| llvm::Function * |
| IRGenModule::getAddrOfTypeMetadataAccessFunction(CanType type, |
| ForDefinition_t forDefinition) { |
| assert(!type->hasArchetype() && !type->hasTypeParameter()); |
| NominalTypeDecl *Nominal = type->getNominalOrBoundGenericNominal(); |
| IRGen.noteUseOfTypeMetadata(Nominal); |
| |
| LinkEntity entity = LinkEntity::forTypeMetadataAccessFunction(type); |
| llvm::Function *&entry = GlobalFuncs[entity]; |
| if (entry) { |
| if (forDefinition) updateLinkageForDefinition(*this, entry, entity); |
| return entry; |
| } |
| |
| llvm::Type *params[] = { SizeTy }; // MetadataRequest |
| auto fnType = llvm::FunctionType::get(TypeMetadataResponseTy, params, false); |
| Signature signature(fnType, llvm::AttributeList(), SwiftCC); |
| LinkInfo link = LinkInfo::get(*this, entity, forDefinition); |
| entry = createFunction(*this, link, signature); |
| return entry; |
| } |
| |
| /// Fetch the opaque type descriptor access function. |
| llvm::Function *IRGenModule::getAddrOfOpaqueTypeDescriptorAccessFunction( |
| OpaqueTypeDecl *decl, ForDefinition_t forDefinition, bool implementation) { |
| IRGen.noteUseOfOpaqueTypeDescriptor(decl); |
| |
| LinkEntity entity = |
| implementation ? LinkEntity::forOpaqueTypeDescriptorAccessorImpl(decl) |
| : LinkEntity::forOpaqueTypeDescriptorAccessor(decl); |
| llvm::Function *&entry = GlobalFuncs[entity]; |
| if (entry) { |
| if (forDefinition) |
| updateLinkageForDefinition(*this, entry, entity); |
| return entry; |
| } |
| |
| auto fnType = llvm::FunctionType::get(OpaqueTypeDescriptorPtrTy, {}, false); |
| Signature signature(fnType, llvm::AttributeList(), SwiftCC); |
| LinkInfo link = LinkInfo::get(*this, entity, forDefinition); |
| entry = createFunction(*this, link, signature); |
| return entry; |
| } |
| |
| /// Fetch the type metadata access function for the given generic type. |
| llvm::Function * |
| IRGenModule::getAddrOfGenericTypeMetadataAccessFunction( |
| NominalTypeDecl *nominal, |
| ArrayRef<llvm::Type *> genericArgs, |
| ForDefinition_t forDefinition) { |
| assert(nominal->isGenericContext()); |
| assert(!genericArgs.empty() || |
| nominal->getGenericSignature()->areAllParamsConcrete()); |
| IRGen.noteUseOfTypeMetadata(nominal); |
| |
| auto type = nominal->getDeclaredType()->getCanonicalType(); |
| assert(type->hasUnboundGenericType()); |
| LinkEntity entity = LinkEntity::forTypeMetadataAccessFunction(type); |
| llvm::Function *&entry = GlobalFuncs[entity]; |
| if (entry) { |
| if (forDefinition) updateLinkageForDefinition(*this, entry, entity); |
| return entry; |
| } |
| |
| // If we have more arguments than can be passed directly, all of the |
| // generic arguments are passed as an array. |
| llvm::Type *paramTypesArray[NumDirectGenericTypeMetadataAccessFunctionArgs+1]; |
| |
| paramTypesArray[0] = SizeTy; // MetadataRequest |
| size_t numParams = 1; |
| |
| size_t numGenericArgs = genericArgs.size(); |
| if (numGenericArgs > NumDirectGenericTypeMetadataAccessFunctionArgs) { |
| paramTypesArray[1] = Int8PtrPtrTy; |
| ++numParams; |
| } else { |
| for (size_t i : indices(genericArgs)) |
| paramTypesArray[i + 1] = genericArgs[i]; |
| numParams += numGenericArgs; |
| } |
| |
| auto paramTypes = llvm::makeArrayRef(paramTypesArray, numParams); |
| auto fnType = llvm::FunctionType::get(TypeMetadataResponseTy, |
| paramTypes, false); |
| Signature signature(fnType, llvm::AttributeList(), SwiftCC); |
| LinkInfo link = LinkInfo::get(*this, entity, forDefinition); |
| entry = createFunction(*this, link, signature); |
| return entry; |
| } |
| |
| llvm::Function * |
| IRGenModule::getAddrOfCanonicalSpecializedGenericTypeMetadataAccessFunction( |
| CanType theType, ForDefinition_t forDefinition) { |
| assert(shouldPrespecializeGenericMetadata()); |
| assert(!theType->hasUnboundGenericType()); |
| auto *nominal = theType->getAnyNominal(); |
| assert(nominal); |
| assert(nominal->isGenericContext()); |
| |
| IRGen.noteUseOfCanonicalSpecializedMetadataAccessor(theType); |
| |
| LinkEntity entity = |
| LinkEntity::forPrespecializedTypeMetadataAccessFunction(theType); |
| llvm::Function *&entry = GlobalFuncs[entity]; |
| if (entry) { |
| if (forDefinition) |
| updateLinkageForDefinition(*this, entry, entity); |
| return entry; |
| } |
| |
| llvm::Type *paramTypesArray[1]; |
| paramTypesArray[0] = SizeTy; // MetadataRequest |
| |
| auto paramTypes = llvm::makeArrayRef(paramTypesArray, 1); |
| auto functionType = |
| llvm::FunctionType::get(TypeMetadataResponseTy, paramTypes, false); |
| Signature signature(functionType, llvm::AttributeList(), SwiftCC); |
| LinkInfo link = LinkInfo::get(*this, entity, forDefinition); |
| entry = createFunction(*this, link, signature); |
| return entry; |
| } |
| |
| /// Get or create a type metadata cache variable. These are an |
| /// implementation detail of type metadata access functions. |
| llvm::Constant * |
| IRGenModule::getAddrOfTypeMetadataLazyCacheVariable(CanType type) { |
| assert(!type->hasArchetype() && !type->hasTypeParameter()); |
| LinkEntity entity = LinkEntity::forTypeMetadataLazyCacheVariable(type); |
| auto variable = |
| getAddrOfLLVMVariable(entity, ForDefinition, DebugTypeInfo()); |
| |
| // Zero-initialize if we're asking for a definition. |
| cast<llvm::GlobalVariable>(variable)->setInitializer( |
| llvm::ConstantPointerNull::get(TypeMetadataPtrTy)); |
| |
| return variable; |
| } |
| |
| llvm::Constant * |
| IRGenModule::getAddrOfCanonicalPrespecializedGenericTypeCachingOnceToken( |
| NominalTypeDecl *decl) { |
| assert(decl->isGenericContext()); |
| LinkEntity entity = |
| LinkEntity::forCanonicalPrespecializedGenericTypeCachingOnceToken(decl); |
| if (auto &entry = GlobalVars[entity]) { |
| return entry; |
| } |
| auto variable = getAddrOfLLVMVariable(entity, ForDefinition, DebugTypeInfo()); |
| |
| // Zero-initialize if we're asking for a definition. |
| cast<llvm::GlobalVariable>(variable)->setInitializer( |
| llvm::ConstantInt::get(OnceTy, 0)); |
| |
| return variable; |
| } |
| |
| llvm::Constant * |
| IRGenModule::getAddrOfNoncanonicalSpecializedGenericTypeMetadataCacheVariable(CanType type) { |
| assert(!type->hasArchetype() && !type->hasTypeParameter()); |
| LinkEntity entity = LinkEntity::forNoncanonicalSpecializedGenericTypeMetadataCacheVariable(type); |
| if (auto &entry = GlobalVars[entity]) { |
| return entry; |
| } |
| auto variable = |
| getAddrOfLLVMVariable(entity, ForDefinition, DebugTypeInfo()); |
| |
| cast<llvm::GlobalVariable>(variable)->setInitializer( |
| llvm::ConstantPointerNull::get(TypeMetadataPtrTy)); |
| |
| return variable; |
| } |
| |
| /// Get or create a type metadata cache variable. These are an |
| /// implementation detail of type metadata access functions. |
| llvm::Constant * |
| IRGenModule::getAddrOfTypeMetadataDemanglingCacheVariable(CanType type, |
| ConstantInit definition) { |
| assert(!type->hasArchetype() && !type->hasTypeParameter()); |
| LinkEntity entity = LinkEntity::forTypeMetadataDemanglingCacheVariable(type); |
| return getAddrOfLLVMVariable(entity, definition, DebugTypeInfo()); |
| } |
| |
| llvm::Constant * |
| IRGenModule::getAddrOfTypeMetadataSingletonInitializationCache( |
| NominalTypeDecl *D, |
| ForDefinition_t forDefinition) { |
| auto entity = LinkEntity::forTypeMetadataSingletonInitializationCache(D); |
| auto variable = |
| getAddrOfLLVMVariable(entity, forDefinition, DebugTypeInfo()); |
| |
| // Zero-initialize if we're asking for a definition. |
| if (forDefinition) { |
| cast<llvm::GlobalVariable>(variable)->setInitializer( |
| llvm::Constant::getNullValue(variable->getType()->getPointerElementType())); |
| } |
| |
| return variable; |
| } |
| |
| llvm::GlobalValue *IRGenModule::defineAlias(LinkEntity entity, |
| llvm::Constant *definition) { |
| // Check for an existing forward declaration of the alias. |
| auto &entry = GlobalVars[entity]; |
| llvm::GlobalValue *existingVal = nullptr; |
| if (entry) { |
| existingVal = cast<llvm::GlobalValue>(entry); |
| // Clear the existing value's name so we can steal it. |
| existingVal->setName(""); |
| } |
| |
| LinkInfo link = LinkInfo::get(*this, entity, ForDefinition); |
| auto *ptrTy = cast<llvm::PointerType>(definition->getType()); |
| auto *alias = llvm::GlobalAlias::create( |
| ptrTy->getElementType(), ptrTy->getAddressSpace(), link.getLinkage(), |
| link.getName(), definition, &Module); |
| ApplyIRLinkage({link.getLinkage(), link.getVisibility(), link.getDLLStorage()}) |
| .to(alias); |
| |
| if (link.isUsed()) { |
| addUsedGlobal(alias); |
| } |
| |
| // Replace an existing external declaration for the address point. |
| if (entry) { |
| auto existingVal = cast<llvm::GlobalValue>(entry); |
| |
| for (auto iterator = std::begin(LLVMUsed); iterator < std::end(LLVMUsed); ++iterator) { |
| llvm::Value *thisValue = *iterator; |
| if (thisValue == existingVal) { |
| LLVMUsed.erase(iterator); |
| } |
| } |
| for (auto iterator = std::begin(LLVMCompilerUsed); iterator < std::end(LLVMCompilerUsed); ++iterator) { |
| llvm::Value *thisValue = *iterator; |
| if (thisValue == existingVal) { |
| LLVMCompilerUsed.erase(iterator); |
| } |
| } |
| |
| // FIXME: MC breaks when emitting alias references on some platforms |
| // (rdar://problem/22450593 ). Work around this by referring to the aliasee |
| // instead. |
| llvm::Constant *aliasCast = alias->getAliasee(); |
| aliasCast = llvm::ConstantExpr::getBitCast(aliasCast, |
| entry->getType()); |
| existingVal->replaceAllUsesWith(aliasCast); |
| existingVal->eraseFromParent(); |
| } |
| entry = alias; |
| |
| return alias; |
| } |
| |
| /// Define the metadata for a type. |
| /// |
| /// Some type metadata has information before the address point that the |
| /// public symbol for the metadata references. This function will rewrite any |
| /// existing external declaration to the address point as an alias into the |
| /// full metadata object. |
| llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType, |
| bool isPattern, |
| bool isConstant, |
| ConstantInitFuture init, |
| llvm::StringRef section) { |
| assert(init); |
| |
| auto isPrespecialized = concreteType->getAnyGeneric() && |
| concreteType->getAnyGeneric()->isGenericContext(); |
| |
| if (isPattern) { |
| assert(isConstant && "Type metadata patterns must be constant"); |
| auto addr = getAddrOfTypeMetadataPattern(concreteType->getAnyNominal(), |
| init, section); |
| |
| return cast<llvm::GlobalValue>(addr); |
| } |
| |
| auto entity = |
| (isPrespecialized && |
| !irgen::isCanonicalInitializableTypeMetadataStaticallyAddressable( |
| *this, concreteType)) |
| ? LinkEntity::forNoncanonicalSpecializedGenericTypeMetadata( |
| concreteType) |
| : LinkEntity::forTypeMetadata(concreteType, |
| TypeMetadataAddress::FullMetadata); |
| |
| auto DbgTy = DebugTypeInfo::getMetadata(MetatypeType::get(concreteType), |
| entity.getDefaultDeclarationType(*this)->getPointerTo(), |
| Size(0), Alignment(1)); |
| |
| // Define the variable. |
| llvm::GlobalVariable *var = cast<llvm::GlobalVariable>( |
| getAddrOfLLVMVariable(entity, init, DbgTy)); |
| |
| var->setConstant(isConstant); |
| if (!section.empty()) |
| var->setSection(section); |
| |
| LinkInfo link = LinkInfo::get(*this, entity, ForDefinition); |
| if (link.isUsed()) |
| addUsedGlobal(var); |
| |
| /// For concrete metadata, we want to use the initializer on the |
| /// "full metadata", and define the "direct" address point as an alias. |
| unsigned adjustmentIndex = MetadataAdjustmentIndex::ValueType; |
| |
| if (auto nominal = concreteType->getAnyNominal()) { |
| // Keep type metadata around for all types. |
| addRuntimeResolvableType(nominal); |
| |
| // Don't define the alias for foreign type metadata or prespecialized |
| // generic metadata, since neither is ABI. |
| if (requiresForeignTypeMetadata(nominal) || isPrespecialized) |
| return var; |
| |
| // Native Swift class metadata has a destructor before the address point. |
| if (isa<ClassDecl>(nominal)) { |
| adjustmentIndex = MetadataAdjustmentIndex::Class; |
| } |
| } |
| |
| llvm::Constant *indices[] = { |
| llvm::ConstantInt::get(Int32Ty, 0), |
| llvm::ConstantInt::get(Int32Ty, adjustmentIndex)}; |
| auto addr = llvm::ConstantExpr::getInBoundsGetElementPtr(/*Ty=*/nullptr, var, |
| indices); |
| addr = llvm::ConstantExpr::getBitCast(addr, TypeMetadataPtrTy); |
| |
| // For concrete metadata, declare the alias to its address point. |
| auto directEntity = LinkEntity::forTypeMetadata( |
| concreteType, TypeMetadataAddress::AddressPoint); |
| return defineAlias(directEntity, addr); |
| } |
| |
| /// Fetch the declaration of the (possibly uninitialized) metadata for a type. |
| llvm::Constant * |
| IRGenModule::getAddrOfTypeMetadata(CanType concreteType, |
| TypeMetadataCanonicality canonicality) { |
| return getAddrOfTypeMetadata(concreteType, SymbolReferenceKind::Absolute, |
| canonicality) |
| .getDirectValue(); |
| } |
| |
| ConstantReference |
| IRGenModule::getAddrOfTypeMetadata(CanType concreteType, |
| SymbolReferenceKind refKind, |
| TypeMetadataCanonicality canonicality) { |
| assert(!isa<UnboundGenericType>(concreteType)); |
| |
| auto nominal = concreteType->getAnyNominal(); |
| |
| bool foreign = nominal && requiresForeignTypeMetadata(nominal); |
| |
| // Foreign classes and prespecialized generic types do not use an alias into |
| // the full metadata and therefore require a GEP. |
| bool fullMetadata = |
| foreign || (concreteType->getAnyGeneric() && |
| concreteType->getAnyGeneric()->isGenericContext()); |
| |
| llvm::Type *defaultVarTy; |
| unsigned adjustmentIndex; |
| |
| if (fullMetadata) { |
| defaultVarTy = FullTypeMetadataStructTy; |
| if (concreteType->getClassOrBoundGenericClass() && !foreign) { |
| adjustmentIndex = MetadataAdjustmentIndex::Class; |
| } else { |
| adjustmentIndex = MetadataAdjustmentIndex::ValueType; |
| } |
| } else if (nominal) { |
| // The symbol for native non-generic nominal type metadata is generated at |
| // the aliased address point (see defineTypeMetadata() above). |
| assert(!nominal->hasClangNode()); |
| |
| defaultVarTy = TypeMetadataStructTy; |
| adjustmentIndex = 0; |
| } else { |
| // FIXME: Non-nominal metadata provided by the C++ runtime is exported |
| // with the address of the start of the full metadata object, since |
| // Clang doesn't provide an easy way to emit symbols aliasing into the |
| // middle of an object. |
| defaultVarTy = FullTypeMetadataStructTy; |
| adjustmentIndex = MetadataAdjustmentIndex::ValueType; |
| } |
| |
| // If this is a use, and the type metadata is emitted lazily, |
| // trigger lazy emission of the metadata. |
| if (NominalTypeDecl *nominal = concreteType->getAnyNominal()) { |
| IRGen.noteUseOfTypeMetadata(nominal); |
| } |
| |
| if (shouldPrespecializeGenericMetadata()) { |
| if (auto nominal = concreteType->getAnyNominal()) { |
| if (nominal->isGenericContext()) { |
| IRGen.noteUseOfSpecializedGenericTypeMetadata(*this, concreteType, |
| canonicality); |
| } |
| } |
| } |
| |
| Optional<LinkEntity> entity; |
| DebugTypeInfo DbgTy; |
| |
| switch (canonicality) { |
| case TypeMetadataCanonicality::Canonical: |
| entity = LinkEntity::forTypeMetadata( |
| concreteType, fullMetadata ? TypeMetadataAddress::FullMetadata |
| : TypeMetadataAddress::AddressPoint); |
| break; |
| case TypeMetadataCanonicality::Noncanonical: |
| entity = |
| LinkEntity::forNoncanonicalSpecializedGenericTypeMetadata(concreteType); |
| break; |
| } |
| DbgTy = DebugTypeInfo::getMetadata(MetatypeType::get(concreteType), |
| defaultVarTy->getPointerTo(), Size(0), |
| Alignment(1)); |
| |
| ConstantReference addr; |
| |
| if (fullMetadata && !foreign) { |
| addr = getAddrOfLLVMVariable(*entity, ConstantInit(), DbgTy, refKind, |
| /*overrideDeclType=*/nullptr); |
| } else { |
| addr = getAddrOfLLVMVariable(*entity, ConstantInit(), DbgTy, refKind, |
| /*overrideDeclType=*/defaultVarTy); |
| } |
| |
| if (auto *GV = dyn_cast<llvm::GlobalVariable>(addr.getValue())) |
| GV->setComdat(nullptr); |
| |
| // FIXME: MC breaks when emitting alias references on some platforms |
| // (rdar://problem/22450593 ). Work around this by referring to the aliasee |
| // instead. |
| if (auto alias = dyn_cast<llvm::GlobalAlias>(addr.getValue())) |
| addr = ConstantReference(alias->getAliasee(), addr.isIndirect()); |
| |
| // Adjust if necessary. |
| if (adjustmentIndex) { |
| llvm::Constant *indices[] = { |
| llvm::ConstantInt::get(Int32Ty, 0), |
| llvm::ConstantInt::get(Int32Ty, adjustmentIndex) |
| }; |
| addr = ConstantReference( |
| llvm::ConstantExpr::getInBoundsGetElementPtr( |
| /*Ty=*/nullptr, addr.getValue(), indices), |
| addr.isIndirect()); |
| } |
| |
| return addr; |
| } |
| |
| llvm::Constant * |
| IRGenModule::getAddrOfTypeMetadataPattern(NominalTypeDecl *D) { |
| return getAddrOfTypeMetadataPattern(D, ConstantInit(), ""); |
| } |
| |
| llvm::Constant * |
| IRGenModule::getAddrOfTypeMetadataPattern(NominalTypeDecl *D, |
| ConstantInit init, |
| StringRef section) { |
| if (!init) |
| IRGen.noteUseOfTypeMetadata(D); |
| |
| LinkEntity entity = LinkEntity::forTypeMetadataPattern(D); |
| auto addr = getAddrOfLLVMVariable(entity, init, DebugTypeInfo()); |
| |
| if (init) { |
| auto var = cast<llvm::GlobalVariable>(addr); |
| var->setConstant(true); |
| if (!section.empty()) |
| var->setSection(section); |
| |
| // Keep type metadata around for all types. |
| addRuntimeResolvableType(D); |
| } |
| |
| return addr; |
| } |
| |
| /// Returns the address of a class metadata base offset. |
| llvm::Constant * |
| IRGenModule::getAddrOfClassMetadataBounds(ClassDecl *D, |
| ForDefinition_t forDefinition) { |
| LinkEntity entity = LinkEntity::forClassMetadataBaseOffset(D); |
| return getAddrOfLLVMVariable(entity, forDefinition, DebugTypeInfo()); |
| } |
| |
| /// Return the address of a generic type's metadata instantiation cache. |
| llvm::Constant * |
| IRGenModule::getAddrOfTypeMetadataInstantiationCache(NominalTypeDecl *D, |
| ForDefinition_t forDefinition) { |
| auto entity = LinkEntity::forTypeMetadataInstantiationCache(D); |
| return getAddrOfLLVMVariable(entity, forDefinition, DebugTypeInfo()); |
| } |
| |
| llvm::Function * |
| IRGenModule::getAddrOfTypeMetadataInstantiationFunction(NominalTypeDecl *D, |
| ForDefinition_t forDefinition) { |
| LinkEntity entity = LinkEntity::forTypeMetadataInstantiationFunction(D); |
| llvm::Function *&entry = GlobalFuncs[entity]; |
| if (entry) { |
| if (forDefinition) updateLinkageForDefinition(*this, entry, entity); |
| return entry; |
| } |
| |
| // This function is used in two cases -- allocating generic type metadata, |
| // and relocating non-generic resilient class metadata. |
| llvm::FunctionType *fnType; |
| |
| if (D->isGenericContext()) { |
| // MetadataInstantiator in ABI/Metadata.h |
| llvm::Type *argTys[] = { |
| /// Type descriptor. |
| TypeContextDescriptorPtrTy, |
| /// Generic arguments. |
| Int8PtrPtrTy, |
| /// Generic metadata pattern. |
| Int8PtrTy |
| }; |
| |
| fnType = llvm::FunctionType::get(TypeMetadataPtrTy, argTys, |
| /*isVarArg*/ false); |
| } else { |
| assert(isa<ClassDecl>(D)); |
| |
| // MetadataRelocator in ABI/Metadata.h |
| llvm::Type *argTys[] = { |
| /// Type descriptor. |
| TypeContextDescriptorPtrTy, |
| /// Resilient metadata pattern. |
| Int8PtrTy |
| }; |
| |
| fnType = llvm::FunctionType::get(TypeMetadataPtrTy, argTys, |
| /*isVarArg*/ false); |
| } |
| |
| Signature signature(fnType, llvm::AttributeList(), DefaultCC); |
| LinkInfo link = LinkInfo::get(*this, entity, forDefinition); |
| entry = createFunction(*this, link, signature); |
| return entry; |
| } |
| |
| llvm::Function * |
| IRGenModule::getAddrOfTypeMetadataCompletionFunction(NominalTypeDecl *D, |
| ForDefinition_t forDefinition) { |
| LinkEntity entity = LinkEntity::forTypeMetadataCompletionFunction(D); |
| llvm::Function *&entry = GlobalFuncs[entity]; |
| if (entry) { |
| if (forDefinition) updateLinkageForDefinition(*this, entry, entity); |
| return entry; |
| } |
| |
| llvm::Type *argTys[] = { |
| /// Type metadata. |
| TypeMetadataPtrTy, |
| /// Metadata completion context. |
| Int8PtrTy, |
| /// Generic metadata pattern. |
| Int8PtrPtrTy |
| }; |
| auto fnType = llvm::FunctionType::get(TypeMetadataResponseTy, |
| argTys, /*isVarArg*/ false); |
| Signature signature(fnType, llvm::AttributeList(), SwiftCC); |
| LinkInfo link = LinkInfo::get(*this, entity, forDefinition); |
| entry = createFunction(*this, link, signature); |
| return entry; |
| } |
| |
| /// Return the address of a nominal type descriptor. |
| llvm::Constant *IRGenModule::getAddrOfTypeContextDescriptor(NominalTypeDecl *D, |
| RequireMetadata_t requireMetadata, |
| ConstantInit definition) { |
| IRGen.noteUseOfTypeContextDescriptor(D, requireMetadata); |
| |
| auto entity = LinkEntity::forNominalTypeDescriptor(D); |
| return getAddrOfLLVMVariable(entity, |
| definition, |
| DebugTypeInfo()); |
| } |
| |
| llvm::Constant *IRGenModule::getAddrOfOpaqueTypeDescriptor( |
| OpaqueTypeDecl *opaqueType, |
| ConstantInit definition) { |
| IRGen.noteUseOfOpaqueTypeDescriptor(opaqueType); |
| auto entity = LinkEntity::forOpaqueTypeDescriptor(opaqueType); |
| return getAddrOfLLVMVariable(entity, |
| definition, |
| DebugTypeInfo()); |
| } |
| |
| llvm::Constant *IRGenModule:: |
| getAddrOfReflectionBuiltinDescriptor(CanType type, |
| ConstantInit definition) { |
| auto entity = LinkEntity::forReflectionBuiltinDescriptor(type); |
| return getAddrOfLLVMVariable(entity, |
| definition, |
| DebugTypeInfo()); |
| } |
| |
| llvm::Constant *IRGenModule:: |
| getAddrOfReflectionFieldDescriptor(CanType type, |
| ConstantInit definition) { |
| auto entity = LinkEntity::forReflectionFieldDescriptor(type); |
| return getAddrOfLLVMVariable(entity, |
| definition, |
| DebugTypeInfo()); |
| } |
| |
| llvm::Constant *IRGenModule:: |
| getAddrOfReflectionAssociatedTypeDescriptor(const ProtocolConformance *c, |
| ConstantInit definition) { |
| auto entity = LinkEntity::forReflectionAssociatedTypeDescriptor(c); |
| return getAddrOfLLVMVariable(entity, |
| definition, |
| DebugTypeInfo()); |
| } |
| |
| /// Return the address of a property descriptor. |
| llvm::Constant *IRGenModule::getAddrOfPropertyDescriptor(AbstractStorageDecl *D, |
| ConstantInit definition) { |
| auto entity = LinkEntity::forPropertyDescriptor(D); |
| return getAddrOfLLVMVariable(entity, |
| definition, |
| DebugTypeInfo()); |
| } |
| |
| llvm::Constant *IRGenModule::getAddrOfProtocolDescriptor(ProtocolDecl *D, |
| ConstantInit definition) { |
| if (D->isObjC()) { |
| assert(!definition && |
| "cannot define an @objc protocol descriptor this way"); |
| return getAddrOfObjCProtocolRecord(D, NotForDefinition); |
| } |
| |
| auto entity = LinkEntity::forProtocolDescriptor(D); |
| return getAddrOfLLVMVariable(entity, definition, |
| DebugTypeInfo()); |
| } |
| |
| llvm::Constant *IRGenModule::getAddrOfProtocolRequirementsBaseDescriptor( |
| ProtocolDecl *proto) { |
| auto entity = LinkEntity::forProtocolRequirementsBaseDescriptor(proto); |
| return getAddrOfLLVMVariable(entity, ConstantInit(), |
| DebugTypeInfo()); |
| } |
| |
| llvm::GlobalValue *IRGenModule::defineProtocolRequirementsBaseDescriptor( |
| ProtocolDecl *proto, |
| llvm::Constant *definition) { |
| auto entity = LinkEntity::forProtocolRequirementsBaseDescriptor(proto); |
| return defineAlias(entity, definition); |
| } |
| |
| llvm::Constant *IRGenModule::getAddrOfAssociatedTypeDescriptor( |
| AssociatedTypeDecl *assocType) { |
| auto entity = LinkEntity::forAssociatedTypeDescriptor(assocType); |
| return getAddrOfLLVMVariable(entity, ConstantInit(), |
| DebugTypeInfo()); |
| } |
| |
| llvm::GlobalValue *IRGenModule::defineAssociatedTypeDescriptor( |
| AssociatedTypeDecl *assocType, |
| llvm::Constant *definition) { |
| auto entity = LinkEntity::forAssociatedTypeDescriptor(assocType); |
| return defineAlias(entity, definition); |
| } |
| |
| llvm::Constant *IRGenModule::getAddrOfAssociatedConformanceDescriptor( |
| AssociatedConformance conformance) { |
| auto entity = LinkEntity::forAssociatedConformanceDescriptor(conformance); |
| return getAddrOfLLVMVariable(entity, ConstantInit(), DebugTypeInfo()); |
| } |
| |
| llvm::GlobalValue *IRGenModule::defineAssociatedConformanceDescriptor( |
| AssociatedConformance conformance, |
| llvm::Constant *definition) { |
| auto entity = LinkEntity::forAssociatedConformanceDescriptor(conformance); |
| return defineAlias(entity, definition); |
| } |
| |
| llvm::Constant *IRGenModule::getAddrOfBaseConformanceDescriptor( |
| BaseConformance conformance) { |
| auto entity = LinkEntity::forBaseConformanceDescriptor(conformance); |
| return getAddrOfLLVMVariable(entity, ConstantInit(), DebugTypeInfo()); |
| } |
| |
| llvm::GlobalValue *IRGenModule::defineBaseConformanceDescriptor( |
| BaseConformance conformance, |
| llvm::Constant *definition) { |
| auto entity = LinkEntity::forBaseConformanceDescriptor(conformance); |
| return defineAlias(entity, definition); |
| } |
| |
| llvm::Constant *IRGenModule::getAddrOfProtocolConformanceDescriptor( |
| const RootProtocolConformance *conformance, |
| ConstantInit definition) { |
| IRGen.addLazyWitnessTable(conformance); |
| |
| auto entity = LinkEntity::forProtocolConformanceDescriptor(conformance); |
| return getAddrOfLLVMVariable(entity, definition, |
| DebugTypeInfo()); |
| } |
| |
| /// Fetch the declaration of the ivar initializer for the given class. |
| Optional<llvm::Function*> IRGenModule::getAddrOfIVarInitDestroy( |
| ClassDecl *cd, |
| bool isDestroyer, |
| bool isForeign, |
| ForDefinition_t forDefinition) { |
| auto silRef = SILDeclRef(cd, |
| isDestroyer |
| ? SILDeclRef::Kind::IVarDestroyer |
| : SILDeclRef::Kind::IVarInitializer) |
| .asForeign(isForeign); |
| |
| // Find the SILFunction for the ivar initializer or destroyer. |
| if (auto silFn = getSILModule().lookUpFunction(silRef)) { |
| return getAddrOfSILFunction(silFn, forDefinition); |
| } |
| |
| return None; |
| } |
| |
| /// Returns the address of a value-witness function. |
| llvm::Function *IRGenModule::getAddrOfValueWitness(CanType abstractType, |
| ValueWitness index, |
| ForDefinition_t forDefinition) { |
| LinkEntity entity = LinkEntity::forValueWitness(abstractType, index); |
| |
| llvm::Function *&entry = GlobalFuncs[entity]; |
| if (entry) { |
| if (forDefinition) updateLinkageForDefinition(*this, entry, entity); |
| return entry; |
| } |
| |
| auto signature = getValueWitnessSignature(index); |
| LinkInfo link = LinkInfo::get(*this, entity, forDefinition); |
| entry = createFunction(*this, link, signature); |
| return entry; |
| } |
| |
| /// Returns the address of a value-witness table. If a definition |
| /// type is provided, the table is created with that type; the return |
| /// value will be an llvm::GlobalValue. Otherwise, the result will |
| /// have type WitnessTablePtrTy. |
| llvm::Constant * |
| IRGenModule::getAddrOfValueWitnessTable(CanType concreteType, |
| ConstantInit definition) { |
| LinkEntity entity = LinkEntity::forValueWitnessTable(concreteType); |
| return getAddrOfLLVMVariable(entity, definition, DebugTypeInfo()); |
| } |
| |
| static Address getAddrOfSimpleVariable(IRGenModule &IGM, |
| llvm::DenseMap<LinkEntity, llvm::Constant*> &cache, |
| LinkEntity entity, |
| ForDefinition_t forDefinition) { |
| auto alignment = entity.getAlignment(IGM); |
| auto type = entity.getDefaultDeclarationType(IGM); |
| |
| // Check whether it's already cached. |
| llvm::Constant *&entry = cache[entity]; |
| if (entry) { |
| auto existing = cast<llvm::GlobalVariable>(entry); |
| assert(alignment == Alignment(existing->getAlignment())); |
| if (forDefinition) updateLinkageForDefinition(IGM, existing, entity); |
| return Address(entry, alignment); |
| } |
| |
| // Otherwise, we need to create it. |
| LinkInfo link = LinkInfo::get(IGM, entity, forDefinition); |
| auto addr = createVariable(IGM, link, type, alignment); |
| |
| entry = addr; |
| return Address(addr, alignment); |
| } |
| |
| /// getAddrOfFieldOffset - Get the address of the global variable |
| /// which contains an offset to apply to either an object (if direct) |
| /// or a metadata object in order to find an offset to apply to an |
| /// object (if indirect). |
| /// |
| /// The result is always a GlobalValue. |
| Address IRGenModule::getAddrOfFieldOffset(VarDecl *var, |
| ForDefinition_t forDefinition) { |
| LinkEntity entity = LinkEntity::forFieldOffset(var); |
| return getAddrOfSimpleVariable(*this, GlobalVars, entity, |
| forDefinition); |
| } |
| |
| Address IRGenModule::getAddrOfEnumCase(EnumElementDecl *Case, |
| ForDefinition_t forDefinition) { |
| LinkEntity entity = LinkEntity::forEnumCase(Case); |
| auto addr = getAddrOfSimpleVariable(*this, GlobalVars, entity, forDefinition); |
| |
| auto *global = cast<llvm::GlobalVariable>(addr.getAddress()); |
| global->setConstant(true); |
| |
| return addr; |
| } |
| |
| void IRGenModule::emitNestedTypeDecls(DeclRange members) { |
| for (Decl *member : members) { |
| switch (member->getKind()) { |
| case DeclKind::Import: |
| case DeclKind::TopLevelCode: |
| case DeclKind::Protocol: |
| case DeclKind::Extension: |
| case DeclKind::InfixOperator: |
| case DeclKind::PrefixOperator: |
| case DeclKind::PostfixOperator: |
| case DeclKind::Param: |
| case DeclKind::Module: |
| case DeclKind::PrecedenceGroup: |
| llvm_unreachable("decl not allowed in type context"); |
| |
| case DeclKind::IfConfig: |
| case DeclKind::PoundDiagnostic: |
| continue; |
| |
| case DeclKind::Func: |
| case DeclKind::Var: |
| case DeclKind::Subscript: |
| // Handled in SIL. |
| continue; |
| |
| case DeclKind::PatternBinding: |
| case DeclKind::Accessor: |
| case DeclKind::Constructor: |
| case DeclKind::Destructor: |
| case DeclKind::EnumCase: |
| case DeclKind::EnumElement: |
| case DeclKind::MissingMember: |
| // Skip non-type members. |
| continue; |
| |
| case DeclKind::AssociatedType: |
| case DeclKind::GenericTypeParam: |
| // Do nothing. |
| continue; |
| |
| case DeclKind::TypeAlias: |
| case DeclKind::OpaqueType: |
| // Do nothing. |
| continue; |
| |
| case DeclKind::Enum: |
| emitEnumDecl(cast<EnumDecl>(member)); |
| continue; |
| case DeclKind::Struct: |
| emitStructDecl(cast<StructDecl>(member)); |
| continue; |
| case DeclKind::Class: |
| emitClassDecl(cast<ClassDecl>(member)); |
| continue; |
| } |
| } |
| } |
| |
| static bool shouldEmitCategory(IRGenModule &IGM, ExtensionDecl *ext) { |
| for (auto conformance : ext->getLocalConformances()) { |
| if (conformance->getProtocol()->isObjC()) |
| return true; |
| } |
| |
| for (auto member : ext->getMembers()) { |
| if (auto func = dyn_cast<FuncDecl>(member)) { |
| if (requiresObjCMethodDescriptor(func)) |
| return true; |
| } else if (auto constructor = dyn_cast<ConstructorDecl>(member)) { |
| if (requiresObjCMethodDescriptor(constructor)) |
| return true; |
| } else if (auto var = dyn_cast<VarDecl>(member)) { |
| if (requiresObjCPropertyDescriptor(IGM, var)) |
| return true; |
| } else if (auto subscript = dyn_cast<SubscriptDecl>(member)) { |
| if (requiresObjCSubscriptDescriptor(IGM, subscript)) |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| void IRGenModule::emitExtension(ExtensionDecl *ext) { |
| emitNestedTypeDecls(ext->getMembers()); |
| |
| addLazyConformances(ext); |
| |
| // Generate a category if the extension either introduces a |
| // conformance to an ObjC protocol or introduces a method |
| // that requires an Objective-C entry point. |
| ClassDecl *origClass = ext->getSelfClassDecl(); |
| if (!origClass) |
| return; |
| |
| if (shouldEmitCategory(*this, ext)) { |
| assert(origClass && !origClass->isForeign() && |
| "foreign types cannot have categories emitted"); |
| llvm::Constant *category = emitCategoryData(*this, ext); |
| category = llvm::ConstantExpr::getBitCast(category, Int8PtrTy); |
| |
| auto *theClass = ext->getSelfClassDecl(); |
| |
| // Categories on class stubs are added to a separate list. |
| if (theClass->checkAncestry(AncestryFlags::ResilientOther)) |
| ObjCCategoriesOnStubs.push_back(category); |
| else |
| ObjCCategories.push_back(category); |
| |
| ObjCCategoryDecls.push_back(ext); |
| } |
| } |
| |
| |
| /// Create an allocation on the stack. |
| Address IRGenFunction::createAlloca(llvm::Type *type, |
| Alignment alignment, |
| const llvm::Twine &name) { |
| llvm::AllocaInst *alloca = |
| new llvm::AllocaInst(type, IGM.DataLayout.getAllocaAddrSpace(), name, |
| AllocaIP); |
| alloca->setAlignment(llvm::MaybeAlign(alignment.getValue()).valueOrOne()); |
| return Address(alloca, alignment); |
| } |
| |
| /// Create an allocation of an array on the stack. |
| Address IRGenFunction::createAlloca(llvm::Type *type, |
| llvm::Value *ArraySize, |
| Alignment alignment, |
| const llvm::Twine &name) { |
| llvm::AllocaInst *alloca = new llvm::AllocaInst( |
| type, IGM.DataLayout.getAllocaAddrSpace(), ArraySize, |
| llvm::MaybeAlign(alignment.getValue()).valueOrOne(), name, AllocaIP); |
| return Address(alloca, alignment); |
| } |
| |
| /// Allocate a fixed-size buffer on the stack. |
| Address IRGenFunction::createFixedSizeBufferAlloca(const llvm::Twine &name) { |
| return createAlloca(IGM.getFixedBufferTy(), |
| getFixedBufferAlignment(IGM), |
| name); |
| } |
| |
| /// Get or create a global string constant. |
| /// |
| /// \returns an i8* with a null terminator; note that embedded nulls |
| /// are okay |
| /// |
| /// FIXME: willBeRelativelyAddressed is only needed to work around an ld64 bug |
| /// resolving relative references to coalesceable symbols. |
| /// It should be removed when fixed. rdar://problem/22674524 |
| llvm::Constant *IRGenModule::getAddrOfGlobalString(StringRef data, |
| bool willBeRelativelyAddressed) { |
| // Check whether this string already exists. |
| auto &entry = GlobalStrings[data]; |
| if (entry.second) { |
| // FIXME: Clear unnamed_addr if the global will be relative referenced |
| // to work around an ld64 bug. rdar://problem/22674524 |
| if (willBeRelativelyAddressed) |
| entry.first->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::None); |
| return entry.second; |
| } |
| |
| entry = createStringConstant(data, willBeRelativelyAddressed); |
| return entry.second; |
| } |
| |
| /// Get or create a global UTF-16 string constant. |
| /// |
| /// \returns an i16* with a null terminator; note that embedded nulls |
| /// are okay |
| llvm::Constant *IRGenModule::getAddrOfGlobalUTF16String(StringRef utf8) { |
| // Check whether this string already exists. |
| auto &entry = GlobalUTF16Strings[utf8]; |
| if (entry) return entry; |
| |
| // If not, first transcode it to UTF16. |
| SmallVector<llvm::UTF16, 128> buffer(utf8.size() + 1); // +1 for ending nulls. |
| const llvm::UTF8 *fromPtr = (const llvm::UTF8 *) utf8.data(); |
| llvm::UTF16 *toPtr = &buffer[0]; |
| (void) ConvertUTF8toUTF16(&fromPtr, fromPtr + utf8.size(), |
| &toPtr, toPtr + utf8.size(), |
| llvm::strictConversion); |
| |
| // The length of the transcoded string in UTF-8 code points. |
| size_t utf16Length = toPtr - &buffer[0]; |
| |
| // Null-terminate the UTF-16 string. |
| *toPtr = 0; |
| ArrayRef<llvm::UTF16> utf16(&buffer[0], utf16Length + 1); |
| |
| auto init = llvm::ConstantDataArray::get(getLLVMContext(), utf16); |
| auto global = new llvm::GlobalVariable(Module, init->getType(), true, |
| llvm::GlobalValue::PrivateLinkage, |
| init); |
| global->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); |
| |
| // Drill down to make an i16*. |
| auto zero = llvm::ConstantInt::get(SizeTy, 0); |
| llvm::Constant *indices[] = { zero, zero }; |
| auto address = llvm::ConstantExpr::getInBoundsGetElementPtr( |
| global->getValueType(), global, indices); |
| |
| // Cache and return. |
| entry = address; |
| return address; |
| } |
| |
| /// Do we have to use resilient access patterns when working with this |
| /// declaration? |
| /// |
| /// IRGen is primarily concerned with resilient handling of the following: |
| /// - For structs, a struct's size might change |
| /// - For enums, new cases can be added |
| /// - For classes, the superclass might change the size or number |
| /// of stored properties |
| bool IRGenModule::isResilient(NominalTypeDecl *D, ResilienceExpansion expansion) { |
| if (expansion == ResilienceExpansion::Maximal && |
| Types.getLoweringMode() == TypeConverter::Mode::CompletelyFragile) { |
| return false; |
| } |
| return D->isResilient(getSwiftModule(), expansion); |
| } |
| |
| /// Do we have to use resilient access patterns when working with this |
| /// class? |
| /// |
| /// For classes, this means that virtual method calls use dispatch thunks |
| /// rather than accessing metadata members directly. |
| bool IRGenModule::hasResilientMetadata(ClassDecl *D, |
| ResilienceExpansion expansion) { |
| if (expansion == ResilienceExpansion::Maximal && |
| Types.getLoweringMode() == TypeConverter::Mode::CompletelyFragile) { |
| return false; |
| } |
| return D->hasResilientMetadata(getSwiftModule(), expansion); |
| } |
| |
| // The most general resilience expansion where the given declaration is visible. |
| ResilienceExpansion |
| IRGenModule::getResilienceExpansionForAccess(NominalTypeDecl *decl) { |
| if (decl->getModuleContext() == getSwiftModule() && |
| decl->getEffectiveAccess() < AccessLevel::Public) |
| return ResilienceExpansion::Maximal; |
| return ResilienceExpansion::Minimal; |
| } |
| |
| // The most general resilience expansion which has knowledge of the declaration's |
| // layout. Calling isResilient() with this scope will always return false. |
| ResilienceExpansion |
| IRGenModule::getResilienceExpansionForLayout(NominalTypeDecl *decl) { |
| if (Types.getLoweringMode() == TypeConverter::Mode::CompletelyFragile) |
| return ResilienceExpansion::Minimal; |
| |
| if (isResilient(decl, ResilienceExpansion::Minimal)) |
| return ResilienceExpansion::Maximal; |
| |
| return getResilienceExpansionForAccess(decl); |
| } |
| |
| // The most general resilience expansion which has knowledge of the global |
| // variable's layout. |
| ResilienceExpansion |
| IRGenModule::getResilienceExpansionForLayout(SILGlobalVariable *global) { |
| if (hasPublicVisibility(global->getLinkage())) |
| return ResilienceExpansion::Minimal; |
| return ResilienceExpansion::Maximal; |
| } |
| |
| llvm::Function * |
| IRGenModule::getAddrOfGenericWitnessTableInstantiationFunction( |
| const NormalProtocolConformance *conf) { |
| auto forDefinition = ForDefinition; |
| |
| LinkEntity entity = |
| LinkEntity::forGenericProtocolWitnessTableInstantiationFunction(conf); |
| llvm::Function *&entry = GlobalFuncs[entity]; |
| if (entry) { |
| if (forDefinition) updateLinkageForDefinition(*this, entry, entity); |
| return entry; |
| } |
| |
| auto fnType = llvm::FunctionType::get( |
| VoidTy, {WitnessTablePtrTy, TypeMetadataPtrTy, Int8PtrPtrTy}, |
| /*varargs*/ false); |
| Signature signature(fnType, llvm::AttributeList(), DefaultCC); |
| LinkInfo link = LinkInfo::get(*this, entity, forDefinition); |
| entry = createFunction(*this, link, signature); |
| return entry; |
| } |
| |
| /// Fetch the lazy witness table access function for a protocol conformance. |
| llvm::Function * |
| IRGenModule::getAddrOfWitnessTableLazyAccessFunction( |
| const NormalProtocolConformance *conf, |
| CanType conformingType, |
| ForDefinition_t forDefinition) { |
| LinkEntity entity = |
| LinkEntity::forProtocolWitnessTableLazyAccessFunction(conf, conformingType); |
| llvm::Function *&entry = GlobalFuncs[entity]; |
| if (entry) { |
| if (forDefinition) updateLinkageForDefinition(*this, entry, entity); |
| return entry; |
| } |
| |
| llvm::FunctionType *fnType |
| = llvm::FunctionType::get(WitnessTablePtrTy, false); |
| |
| Signature signature(fnType, llvm::AttributeList(), DefaultCC); |
| LinkInfo link = LinkInfo::get(*this, entity, forDefinition); |
| entry = createFunction(*this, link, signature); |
| ApplyIRLinkage({link.getLinkage(), link.getVisibility(), link.getDLLStorage()}) |
| .to(entry, link.isForDefinition()); |
| return entry; |
| } |
| |
| /// Get or create a witness table cache variable. These are an |
| /// implementation detail of witness table lazy access functions. |
| llvm::Constant * |
| IRGenModule::getAddrOfWitnessTableLazyCacheVariable( |
| const NormalProtocolConformance *conf, |
| CanType conformingType, |
| ForDefinition_t forDefinition) { |
| assert(!conformingType->hasArchetype()); |
| LinkEntity entity = |
| LinkEntity::forProtocolWitnessTableLazyCacheVariable(conf, conformingType); |
| auto variable = getAddrOfLLVMVariable(entity, |
| forDefinition, |
| DebugTypeInfo()); |
| |
| // Zero-initialize if we're asking for a definition. |
| if (forDefinition) { |
| cast<llvm::GlobalVariable>(variable)->setInitializer( |
| llvm::ConstantPointerNull::get(WitnessTablePtrTy)); |
| } |
| |
| return variable; |
| } |
| |
| /// Look up the address of a witness table. |
| /// |
| /// This can only be used with non-dependent conformances. |
| llvm::Constant* |
| IRGenModule::getAddrOfWitnessTable(const RootProtocolConformance *conf, |
| ConstantInit definition) { |
| IRGen.addLazyWitnessTable(conf); |
| |
| auto entity = LinkEntity::forProtocolWitnessTable(conf); |
| return getAddrOfLLVMVariable(entity, definition, DebugTypeInfo()); |
| } |
| |
| /// Look up the address of a witness table pattern. |
| /// |
| /// This can only be used with dependent conformances from inside the |
| /// defining module. |
| llvm::Constant* |
| IRGenModule::getAddrOfWitnessTablePattern(const NormalProtocolConformance *conf, |
| ConstantInit definition) { |
| IRGen.addLazyWitnessTable(conf); |
| |
| auto entity = LinkEntity::forProtocolWitnessTablePattern(conf); |
| return getAddrOfLLVMVariable(entity, definition, DebugTypeInfo()); |
| } |
| |
| /// Look up the address of a differentiability witness. |
| llvm::Constant *IRGenModule::getAddrOfDifferentiabilityWitness( |
| const SILDifferentiabilityWitness *witness, ConstantInit definition) { |
| auto entity = LinkEntity::forDifferentiabilityWitness(witness); |
| return getAddrOfLLVMVariable(entity, definition, DebugTypeInfo()); |
| } |
| |
| llvm::Function * |
| IRGenModule::getAddrOfAssociatedTypeWitnessTableAccessFunction( |
| const NormalProtocolConformance *conformance, |
| const AssociatedConformance &association) { |
| auto forDefinition = ForDefinition; |
| |
| LinkEntity entity = |
| LinkEntity::forAssociatedTypeWitnessTableAccessFunction(conformance, |
| association); |
| llvm::Function *&entry = GlobalFuncs[entity]; |
| if (entry) { |
| if (forDefinition) updateLinkageForDefinition(*this, entry, entity); |
| return entry; |
| } |
| |
| auto signature = getAssociatedTypeWitnessTableAccessFunctionSignature(); |
| LinkInfo link = LinkInfo::get(*this, entity, forDefinition); |
| entry = createFunction(*this, link, signature); |
| return entry; |
| } |
| |
| llvm::Function * |
| IRGenModule::getAddrOfDefaultAssociatedConformanceAccessor( |
| AssociatedConformance requirement) { |
| auto forDefinition = ForDefinition; |
| |
| LinkEntity entity = |
| LinkEntity::forDefaultAssociatedConformanceAccessor(requirement); |
| llvm::Function *&entry = GlobalFuncs[entity]; |
| if (entry) { |
| if (forDefinition) updateLinkageForDefinition(*this, entry, entity); |
| return entry; |
| } |
| |
| auto signature = getAssociatedTypeWitnessTableAccessFunctionSignature(); |
| LinkInfo link = LinkInfo::get(*this, entity, forDefinition); |
| entry = createFunction(*this, link, signature); |
| return entry; |
| } |
| |
| llvm::Function * |
| IRGenModule::getAddrOfContinuationPrototype(CanSILFunctionType fnType) { |
| LinkEntity entity = LinkEntity::forCoroutineContinuationPrototype(fnType); |
| |
| llvm::Function *&entry = GlobalFuncs[entity]; |
| if (entry) return entry; |
| |
| auto signature = Signature::forCoroutineContinuation(*this, fnType); |
| LinkInfo link = LinkInfo::get(*this, entity, NotForDefinition); |
| entry = createFunction(*this, link, signature); |
| return entry; |
| } |
| |
| /// Should we be defining the given helper function? |
| static llvm::Function *shouldDefineHelper(IRGenModule &IGM, |
| llvm::Constant *fn, |
| bool setIsNoInline) { |
| auto *def = dyn_cast<llvm::Function>(fn); |
| if (!def) return nullptr; |
| if (!def->empty()) return nullptr; |
| |
| def->setAttributes(IGM.constructInitialAttributes()); |
| ApplyIRLinkage(IRLinkage::InternalLinkOnceODR).to(def); |
| def->setDoesNotThrow(); |
| def->setCallingConv(IGM.DefaultCC); |
| if (setIsNoInline) |
| def->addFnAttr(llvm::Attribute::NoInline); |
| return def; |
| } |
| |
| /// Get or create a helper function with the given name and type, lazily |
| /// using the given generation function to fill in its body. |
| /// |
| /// The helper function will be shared between translation units within the |
| /// current linkage unit, so choose the name carefully to ensure that it |
| /// does not collide with any other helper function. In general, it should |
| /// be a Swift-specific C reserved name; that is, it should start with |
| // "__swift". |
| llvm::Constant * |
| IRGenModule::getOrCreateHelperFunction(StringRef fnName, llvm::Type *resultTy, |
| ArrayRef<llvm::Type*> paramTys, |
| llvm::function_ref<void(IRGenFunction &IGF)> generate, |
| bool setIsNoInline) { |
| llvm::FunctionType *fnTy = |
| llvm::FunctionType::get(resultTy, paramTys, false); |
| |
| llvm::Constant *fn = |
| cast<llvm::Constant>( |
| Module.getOrInsertFunction(fnName, fnTy).getCallee()); |
| |
| if (llvm::Function *def = shouldDefineHelper(*this, fn, setIsNoInline)) { |
| IRGenFunction IGF(*this, def); |
| if (DebugInfo) |
| DebugInfo->emitArtificialFunction(IGF, def); |
| generate(IGF); |
| } |
| |
| return fn; |
| } |