//===--- TBDGen.cpp - Swift TBD Generation --------------------------------===// // // 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 the entrypoints into TBD file generation. // //===----------------------------------------------------------------------===// #include "swift/TBDGen/TBDGen.h" #include "swift/AST/Availability.h" #include "swift/AST/ASTMangler.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/Basic/LLVM.h" #include "swift/IRGen/Linking.h" #include "swift/SIL/FormalLinkage.h" #include "swift/SIL/SILDeclRef.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILVTableVisitor.h" #include "swift/SIL/SILWitnessTable.h" #include "swift/SIL/TypeLowering.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Error.h" #include "llvm/Support/YAMLTraits.h" #include "TBDGenVisitor.h" #include "tapi/Architecture.h" #include "tapi/InterfaceFile.h" #include "tapi/Platform.h" #include "tapi/TextStub_v3.h" #include "tapi/YAMLReaderWriter.h" using namespace swift; using namespace swift::irgen; using namespace swift::tbdgen; using StringSet = llvm::StringSet<>; using SymbolKind = tapi::internal::SymbolKind; static bool isGlobalOrStaticVar(VarDecl *VD) { return VD->isStatic() || VD->getDeclContext()->isModuleScopeContext(); } void TBDGenVisitor::addSymbol(StringRef name, SymbolKind kind) { Symbols.addSymbol(kind, name, Archs); if (StringSymbols && kind == SymbolKind::GlobalSymbol) { auto isNewValue = StringSymbols->insert(name).second; (void)isNewValue; assert(isNewValue && "symbol appears twice"); } } void TBDGenVisitor::addSymbol(SILDeclRef declRef) { auto linkage = effectiveLinkageForClassMember( declRef.getLinkage(ForDefinition), declRef.getSubclassScope()); if (linkage == SILLinkage::Public) addSymbol(declRef.mangle()); } void TBDGenVisitor::addSymbol(LinkEntity entity) { auto linkage = LinkInfo::get(UniversalLinkInfo, SwiftModule, AvailCtx, entity, ForDefinition); auto externallyVisible = llvm::GlobalValue::isExternalLinkage(linkage.getLinkage()) && linkage.getVisibility() != llvm::GlobalValue::HiddenVisibility; if (externallyVisible) addSymbol(linkage.getName()); } void TBDGenVisitor::addDispatchThunk(SILDeclRef declRef) { auto entity = LinkEntity::forDispatchThunk(declRef); addSymbol(entity); } void TBDGenVisitor::addMethodDescriptor(SILDeclRef declRef) { auto entity = LinkEntity::forMethodDescriptor(declRef); addSymbol(entity); } void TBDGenVisitor::addProtocolRequirementsBaseDescriptor(ProtocolDecl *proto) { auto entity = LinkEntity::forProtocolRequirementsBaseDescriptor(proto); addSymbol(entity); } void TBDGenVisitor::addAssociatedTypeDescriptor(AssociatedTypeDecl *assocType) { auto entity = LinkEntity::forAssociatedTypeDescriptor(assocType); addSymbol(entity); } void TBDGenVisitor::addAssociatedConformanceDescriptor( AssociatedConformance conformance) { auto entity = LinkEntity::forAssociatedConformanceDescriptor(conformance); addSymbol(entity); } void TBDGenVisitor::addBaseConformanceDescriptor( BaseConformance conformance) { auto entity = LinkEntity::forBaseConformanceDescriptor(conformance); addSymbol(entity); } void TBDGenVisitor::addConformances(DeclContext *DC) { for (auto conformance : DC->getLocalConformances( ConformanceLookupKind::NonInherited)) { auto protocol = conformance->getProtocol(); auto needsWTable = Lowering::TypeConverter::protocolRequiresWitnessTable(protocol); if (!needsWTable) continue; // Only root conformances get symbols; the others get any public symbols // from their parent conformances. auto rootConformance = dyn_cast(conformance); if (!rootConformance) { continue; } addSymbol(LinkEntity::forProtocolWitnessTable(rootConformance)); addSymbol(LinkEntity::forProtocolConformanceDescriptor(rootConformance)); // FIXME: the logic around visibility in extensions is confusing, and // sometimes witness thunks need to be manually made public. auto conformanceIsFixed = SILWitnessTable::conformanceIsSerialized( rootConformance); auto addSymbolIfNecessary = [&](ValueDecl *requirementDecl, ValueDecl *witnessDecl) { auto witnessLinkage = SILDeclRef(witnessDecl).getLinkage(ForDefinition); if (conformanceIsFixed && (isa(rootConformance) || fixmeWitnessHasLinkageThatNeedsToBePublic(witnessLinkage))) { Mangle::ASTMangler Mangler; addSymbol( Mangler.mangleWitnessThunk(rootConformance, requirementDecl)); } }; rootConformance->forEachValueWitness( nullptr, [&](ValueDecl *valueReq, Witness witness) { auto witnessDecl = witness.getDecl(); if (isa(valueReq)) { addSymbolIfNecessary(valueReq, witnessDecl); } else if (auto *storage = dyn_cast(valueReq)) { auto witnessStorage = cast(witnessDecl); storage->visitOpaqueAccessors([&](AccessorDecl *reqtAccessor) { auto witnessAccessor = witnessStorage->getAccessor(reqtAccessor->getAccessorKind()); assert(witnessAccessor && "no corresponding witness accessor?"); addSymbolIfNecessary(reqtAccessor, witnessAccessor); }); } }); } } /// Determine whether dynamic replacement should be emitted for the allocator or /// the initializer given a decl. /// The rule is that structs and convenience init of classes emit a /// dynamic replacement for the allocator. /// Designated init of classes emit a dynamic replacement for the intializer. /// This is because the super class init call is emitted to the initializer and /// needs to be dynamic. static bool shouldUseAllocatorMangling(const AbstractFunctionDecl *afd) { auto constructor = dyn_cast(afd); if (!constructor) return false; return constructor->getParent()->getSelfClassDecl() == nullptr || constructor->isConvenienceInit(); } void TBDGenVisitor::visitAbstractFunctionDecl(AbstractFunctionDecl *AFD) { // A @_silgen_name("...") function without a body only exists // to forward-declare a symbol from another library. if (!AFD->hasBody() && AFD->getAttrs().hasAttribute()) { return; } addSymbol(SILDeclRef(AFD)); // Add the global function pointer for a dynamically replaceable function. if (AFD->isNativeDynamic()) { bool useAllocator = shouldUseAllocatorMangling(AFD); addSymbol(LinkEntity::forDynamicallyReplaceableFunctionVariable( AFD, useAllocator)); addSymbol( LinkEntity::forDynamicallyReplaceableFunctionImpl(AFD, useAllocator)); addSymbol( LinkEntity::forDynamicallyReplaceableFunctionKey(AFD, useAllocator)); } if (AFD->getAttrs().hasAttribute()) { bool useAllocator = shouldUseAllocatorMangling(AFD); addSymbol(LinkEntity::forDynamicallyReplaceableFunctionVariable( AFD, useAllocator)); addSymbol( LinkEntity::forDynamicallyReplaceableFunctionImpl(AFD, useAllocator)); } if (AFD->getAttrs().hasAttribute()) { // A @_cdecl("...") function has an extra symbol, with the name from the // attribute. addSymbol(SILDeclRef(AFD).asForeign()); } auto publicDefaultArgGenerators = SwiftModule->isTestingEnabled() || SwiftModule->arePrivateImportsEnabled(); if (!publicDefaultArgGenerators) return; // In Swift 3 (or under -enable-testing), default arguments (of public // functions) are public symbols, as the default values are computed at the // call site. auto index = 0; for (auto *param : *AFD->getParameters()) { if (param->isDefaultArgument()) addSymbol(SILDeclRef::getDefaultArgGenerator(AFD, index)); index++; } } void TBDGenVisitor::visitFuncDecl(FuncDecl *FD) { // If there's an opaque return type, its descriptor is exported. if (auto opaqueResult = FD->getOpaqueResultTypeDecl()) { addSymbol(LinkEntity::forOpaqueTypeDescriptor(opaqueResult)); assert(opaqueResult->getNamingDecl() == FD); if (FD->isNativeDynamic()) { addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessor(opaqueResult)); addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorImpl(opaqueResult)); addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorKey(opaqueResult)); addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorVar(opaqueResult)); } if (FD->getAttrs().hasAttribute()) { addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessor(opaqueResult)); addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorVar(opaqueResult)); } } visitAbstractFunctionDecl(FD); } void TBDGenVisitor::visitAccessorDecl(AccessorDecl *AD) { // Do nothing: accessors are always nested within the storage decl, but // sometimes appear outside it too. To avoid double-walking them, we // explicitly visit them as members of the storage and ignore them when we // visit them as part of the main walk, here. } void TBDGenVisitor::visitAbstractStorageDecl(AbstractStorageDecl *ASD) { // Add the property descriptor if the decl needs it. if (ASD->exportsPropertyDescriptor()) { addSymbol(LinkEntity::forPropertyDescriptor(ASD)); } // ...and the opaque result decl if it has one. if (auto opaqueResult = ASD->getOpaqueResultTypeDecl()) { addSymbol(LinkEntity::forOpaqueTypeDescriptor(opaqueResult)); assert(opaqueResult->getNamingDecl() == ASD); if (ASD->hasAnyNativeDynamicAccessors()) { addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessor(opaqueResult)); addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorImpl(opaqueResult)); addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorKey(opaqueResult)); addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorVar(opaqueResult)); } if (ASD->hasAnyDynamicReplacementAccessors()) { addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessor(opaqueResult)); addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorVar(opaqueResult)); } } // Explicitly look at each accessor here: see visitAccessorDecl. for (auto accessor : ASD->getAllAccessors()) { visitAbstractFunctionDecl(accessor); } } void TBDGenVisitor::visitVarDecl(VarDecl *VD) { // Variables inside non-resilient modules have some additional symbols. if (!VD->isResilient()) { // Non-global variables might have an explicit initializer symbol, in // non-resilient modules. if (VD->getAttrs().hasAttribute() && !isGlobalOrStaticVar(VD)) { auto declRef = SILDeclRef(VD, SILDeclRef::Kind::StoredPropertyInitializer); // Stored property initializers for public properties are currently // public. addSymbol(declRef); } // statically/globally stored variables have some special handling. if (VD->hasStorage() && isGlobalOrStaticVar(VD)) { if (getDeclLinkage(VD) == FormalLinkage::PublicUnique) { // The actual variable has a symbol. Mangle::ASTMangler mangler; addSymbol(mangler.mangleEntity(VD, false)); } if (VD->isLazilyInitializedGlobal()) addSymbol(SILDeclRef(VD, SILDeclRef::Kind::GlobalAccessor)); } } visitAbstractStorageDecl(VD); } void TBDGenVisitor::visitNominalTypeDecl(NominalTypeDecl *NTD) { auto declaredType = NTD->getDeclaredType()->getCanonicalType(); addSymbol(LinkEntity::forNominalTypeDescriptor(NTD)); // Generic types do not get metadata directly, only through the function. if (!NTD->isGenericContext()) { addSymbol(LinkEntity::forTypeMetadata(declaredType, TypeMetadataAddress::AddressPoint)); } addSymbol(LinkEntity::forTypeMetadataAccessFunction(declaredType)); // There are symbols associated with any protocols this type conforms to. addConformances(NTD); for (auto member : NTD->getMembers()) visit(member); } void TBDGenVisitor::visitClassDecl(ClassDecl *CD) { if (getDeclLinkage(CD) != FormalLinkage::PublicUnique) return; auto &ctxt = CD->getASTContext(); auto isGeneric = CD->isGenericContext(); auto objCCompatible = ctxt.LangOpts.EnableObjCInterop && !isGeneric; auto isObjC = objCCompatible && CD->isObjC(); // Metaclasses and ObjC class (duh) are a ObjC thing, and so are not needed in // build artifacts/for classes which can't touch ObjC. if (objCCompatible) { bool addObjCClass = false; if (isObjC) { addObjCClass = true; addSymbol(LinkEntity::forObjCClass(CD)); } if (CD->getMetaclassKind() == ClassDecl::MetaclassKind::ObjC) { addObjCClass = true; addSymbol(LinkEntity::forObjCMetaclass(CD)); } else addSymbol(LinkEntity::forSwiftMetaclassStub(CD)); if (addObjCClass) { SmallString<128> buffer; addSymbol(CD->getObjCRuntimeName(buffer), SymbolKind::ObjectiveCClass); } } // Some members of classes get extra handling, beyond members of struct/enums, // so let's walk over them manually. for (auto *member : CD->getMembers()) { auto value = dyn_cast(member); if (!value) continue; auto var = dyn_cast(value); auto hasFieldOffset = var && var->hasStorage() && !var->isStatic(); if (hasFieldOffset) addSymbol(LinkEntity::forFieldOffset(var)); } visitNominalTypeDecl(CD); bool resilientAncestry = CD->checkAncestry(AncestryFlags::ResilientOther); // Types with resilient superclasses have some extra symbols. if (resilientAncestry || CD->hasResilientMetadata()) { addSymbol(LinkEntity::forClassMetadataBaseOffset(CD)); } auto &Ctx = CD->getASTContext(); if (Ctx.LangOpts.EnableObjCInterop) { if (resilientAncestry) { addSymbol(LinkEntity::forObjCResilientClassStub( CD, TypeMetadataAddress::AddressPoint)); } } // Emit dispatch thunks for every new vtable entry. struct VTableVisitor : public SILVTableVisitor { TBDGenVisitor &TBD; ClassDecl *CD; bool FirstTime = true; public: VTableVisitor(TBDGenVisitor &TBD, ClassDecl *CD) : TBD(TBD), CD(CD) {} void addMethod(SILDeclRef method) { assert(method.getDecl()->getDeclContext() == CD); if (CD->hasResilientMetadata()) { if (FirstTime) { FirstTime = false; // If the class is itself resilient and has at least one vtable entry, // it has a method lookup function. TBD.addSymbol(LinkEntity::forMethodLookupFunction(CD)); } TBD.addDispatchThunk(method); } TBD.addMethodDescriptor(method); } void addMethodOverride(SILDeclRef baseRef, SILDeclRef derivedRef) {} void addPlaceholder(MissingMemberDecl *) {} void doIt() { addVTableEntries(CD); } }; VTableVisitor(*this, CD).doIt(); } void TBDGenVisitor::visitConstructorDecl(ConstructorDecl *CD) { if (CD->getParent()->getSelfClassDecl()) { // Class constructors come in two forms, allocating and non-allocating. The // default ValueDecl handling gives the allocating one, so we have to // manually include the non-allocating one. addSymbol(SILDeclRef(CD, SILDeclRef::Kind::Initializer)); } visitAbstractFunctionDecl(CD); } void TBDGenVisitor::visitDestructorDecl(DestructorDecl *DD) { // Class destructors come in two forms (deallocating and non-deallocating), // like constructors above. This is the deallocating one: visitAbstractFunctionDecl(DD); auto parentClass = DD->getParent()->getSelfClassDecl(); // But the non-deallocating one doesn't apply to some @objc classes. if (!Lowering::usesObjCAllocator(parentClass)) { addSymbol(SILDeclRef(DD, SILDeclRef::Kind::Destroyer)); } } void TBDGenVisitor::visitExtensionDecl(ExtensionDecl *ED) { if (!isa(ED->getExtendedNominal())) { addConformances(ED); } for (auto member : ED->getMembers()) visit(member); } /// Determine whether the protocol descriptor for the given protocol will /// contain any protocol requirements. static bool protocolDescriptorHasRequirements(ProtocolDecl *proto) { if (!proto->getRequirementSignature().empty()) return true; for (auto *member : proto->getMembers()) { if (auto func = dyn_cast(member)) { if (SILDeclRef::requiresNewWitnessTableEntry(func)) return true; } if (auto assocType = dyn_cast(member)) { if (assocType->getOverriddenDecls().empty()) { return true; } } } return false; } #ifndef NDEBUG static bool isValidProtocolMemberForTBDGen(const Decl *D) { switch (D->getKind()) { case DeclKind::TypeAlias: case DeclKind::AssociatedType: case DeclKind::Var: case DeclKind::Subscript: case DeclKind::PatternBinding: case DeclKind::Func: case DeclKind::Accessor: case DeclKind::Constructor: case DeclKind::Destructor: case DeclKind::IfConfig: case DeclKind::PoundDiagnostic: return true; case DeclKind::OpaqueType: case DeclKind::Enum: case DeclKind::Struct: case DeclKind::Class: case DeclKind::Protocol: case DeclKind::GenericTypeParam: case DeclKind::Module: case DeclKind::Param: case DeclKind::EnumElement: case DeclKind::Extension: case DeclKind::TopLevelCode: case DeclKind::Import: case DeclKind::PrecedenceGroup: case DeclKind::MissingMember: case DeclKind::EnumCase: case DeclKind::InfixOperator: case DeclKind::PrefixOperator: case DeclKind::PostfixOperator: return false; } } #endif void TBDGenVisitor::visitProtocolDecl(ProtocolDecl *PD) { if (!PD->isObjC()) { addSymbol(LinkEntity::forProtocolDescriptor(PD)); // If there are any requirements, emit a requirements base descriptor. if (protocolDescriptorHasRequirements(PD)) addProtocolRequirementsBaseDescriptor(PD); for (const auto &req : PD->getRequirementSignature()) { if (req.getKind() != RequirementKind::Conformance) continue; if (req.getFirstType()->isEqual(PD->getSelfInterfaceType())) { BaseConformance conformance( PD, req.getSecondType()->castTo()->getDecl()); addBaseConformanceDescriptor(conformance); } else { AssociatedConformance conformance( PD, req.getFirstType()->getCanonicalType(), req.getSecondType()->castTo()->getDecl()); addAssociatedConformanceDescriptor(conformance); } } for (auto *member : PD->getMembers()) { if (PD->isResilient()) { if (auto *funcDecl = dyn_cast(member)) { if (SILDeclRef::requiresNewWitnessTableEntry(funcDecl)) { addDispatchThunk(SILDeclRef(funcDecl)); addMethodDescriptor(SILDeclRef(funcDecl)); } } } // Always produce associated type descriptors, because they can // be referenced by generic signatures. if (auto *assocType = dyn_cast(member)) { if (assocType->getOverriddenDecls().empty()) addAssociatedTypeDescriptor(assocType); } } // Include the self-conformance. addConformances(PD); } #ifndef NDEBUG // There's no (currently) relevant information about members of a protocol at // individual protocols, each conforming type has to handle them individually // (NB. anything within an active IfConfigDecls also appears outside). Let's // assert this fact: for (auto *member : PD->getMembers()) { assert(isValidProtocolMemberForTBDGen(member) && "unexpected member of protocol during TBD generation"); } #endif } void TBDGenVisitor::visitEnumDecl(EnumDecl *ED) { visitNominalTypeDecl(ED); if (!ED->isResilient()) return; // Emit resilient tags. for (auto *elt : ED->getAllElements()) { auto entity = LinkEntity::forEnumCase(elt); addSymbol(entity); } } void TBDGenVisitor::addFirstFileSymbols() { if (!Opts.ModuleLinkName.empty()) { SmallString<32> buf; addSymbol(irgen::encodeForceLoadSymbolName(buf, Opts.ModuleLinkName)); } } /// Converts a version tuple into a packed version, ignoring components beyond /// major, minor, and subminor. static tapi::internal::PackedVersion convertToPacked(const version::Version &version) { // FIXME: Warn if version is greater than 3 components? unsigned major = 0, minor = 0, subminor = 0; if (version.size() > 0) major = version[0]; if (version.size() > 1) minor = version[1]; if (version.size() > 2) subminor = version[2]; return tapi::internal::PackedVersion(major, minor, subminor); } static bool isApplicationExtensionSafe(const LangOptions &LangOpts) { return LangOpts.EnableAppExtensionRestrictions; } static void enumeratePublicSymbolsAndWrite(ModuleDecl *M, FileUnit *singleFile, StringSet *symbols, llvm::raw_ostream *os, const TBDGenOptions &opts) { auto &ctx = M->getASTContext(); auto isWholeModule = singleFile == nullptr; const auto &target = ctx.LangOpts.Target; UniversalLinkageInfo linkInfo(target, opts.HasMultipleIGMs, false, isWholeModule); auto availCtx = AvailabilityContext::forDeploymentTarget(ctx); tapi::internal::InterfaceFile file; file.setFileType(tapi::internal::FileType::TBD_V3); file.setApplicationExtensionSafe( isApplicationExtensionSafe(M->getASTContext().LangOpts)); file.setInstallName(opts.InstallName); file.setCurrentVersion(convertToPacked(opts.CurrentVersion)); file.setCompatibilityVersion(convertToPacked(opts.CompatibilityVersion)); file.setTwoLevelNamespace(); file.setSwiftABIVersion(TAPI_SWIFT_ABI_VERSION); file.setPlatform(tapi::internal::mapToSinglePlatform(target)); auto arch = tapi::internal::getArchType(target.getArchName()); file.setArch(arch); file.setInstallAPI(); TBDGenVisitor visitor(file, arch, symbols, linkInfo, M, availCtx, opts); auto visitFile = [&](FileUnit *file) { if (file == M->getFiles()[0]) { visitor.addFirstFileSymbols(); } SmallVector decls; file->getTopLevelDecls(decls); visitor.addMainIfNecessary(file); for (auto d : decls) visitor.visit(d); }; if (singleFile) { assert(M == singleFile->getParentModule() && "mismatched file and module"); visitFile(singleFile); } else { for (auto *file : M->getFiles()) { visitFile(file); } } if (os) { tapi::internal::YAMLWriter writer; writer.add( llvm::make_unique()); assert(writer.canWrite(&file) && "YAML writer should be able to write TBD v3"); llvm::cantFail(writer.writeFile(*os, &file), "YAML writing should be error-free"); } } void swift::enumeratePublicSymbols(FileUnit *file, StringSet &symbols, const TBDGenOptions &opts) { enumeratePublicSymbolsAndWrite(file->getParentModule(), file, &symbols, nullptr, opts); } void swift::enumeratePublicSymbols(ModuleDecl *M, StringSet &symbols, const TBDGenOptions &opts) { enumeratePublicSymbolsAndWrite(M, nullptr, &symbols, nullptr, opts); } void swift::writeTBDFile(ModuleDecl *M, llvm::raw_ostream &os, const TBDGenOptions &opts) { enumeratePublicSymbolsAndWrite(M, nullptr, nullptr, &os, opts); }