| //===--- 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/DiagnosticsFrontend.h" |
| #include "swift/AST/Module.h" |
| #include "swift/AST/ParameterList.h" |
| #include "swift/AST/PropertyWrappers.h" |
| #include "swift/AST/SynthesizedFileUnit.h" |
| #include "swift/AST/TBDGenRequests.h" |
| #include "swift/Basic/LLVM.h" |
| #include "swift/ClangImporter/ClangImporter.h" |
| #include "swift/IRGen/IRGenPublic.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/SILWitnessVisitor.h" |
| #include "swift/SIL/TypeLowering.h" |
| #include "clang/Basic/TargetInfo.h" |
| #include "llvm/ADT/StringSet.h" |
| #include "llvm/ADT/StringSwitch.h" |
| #include "llvm/IR/Mangler.h" |
| #include "llvm/Support/Error.h" |
| #include "llvm/Support/Process.h" |
| #include "llvm/Support/YAMLTraits.h" |
| #include "llvm/Support/YAMLParser.h" |
| #include "llvm/TextAPI/MachO/InterfaceFile.h" |
| #include "llvm/TextAPI/MachO/TextAPIReader.h" |
| #include "llvm/TextAPI/MachO/TextAPIWriter.h" |
| |
| #include "TBDGenVisitor.h" |
| |
| using namespace swift; |
| using namespace swift::irgen; |
| using namespace swift::tbdgen; |
| using namespace llvm::yaml; |
| using StringSet = llvm::StringSet<>; |
| using SymbolKind = llvm::MachO::SymbolKind; |
| |
| static bool isGlobalOrStaticVar(VarDecl *VD) { |
| return VD->isStatic() || VD->getDeclContext()->isModuleScopeContext(); |
| } |
| |
| TBDGenVisitor::TBDGenVisitor(const TBDGenDescriptor &desc, |
| SymbolCallbackFn symbolCallback) |
| : TBDGenVisitor(desc.getTarget(), desc.getDataLayout(), |
| desc.getParentModule(), desc.getOptions(), |
| symbolCallback) {} |
| |
| void TBDGenVisitor::addSymbolInternal(StringRef name, SymbolKind kind, |
| SymbolSource source) { |
| if (!source.isLinkerDirective() && Opts.LinkerDirectivesOnly) |
| return; |
| |
| #ifndef NDEBUG |
| if (kind == SymbolKind::GlobalSymbol) { |
| if (!DuplicateSymbolChecker.insert(name).second) { |
| llvm::dbgs() << "TBDGen duplicate symbol: " << name << '\n'; |
| assert(false && "TBDGen symbol appears twice"); |
| } |
| } |
| #endif |
| SymbolCallback(name, kind, source); |
| } |
| |
| static std::vector<OriginallyDefinedInAttr::ActiveVersion> |
| getAllMovedPlatformVersions(Decl *D) { |
| std::vector<OriginallyDefinedInAttr::ActiveVersion> Results; |
| for (auto *attr: D->getAttrs()) { |
| if (auto *ODA = dyn_cast<OriginallyDefinedInAttr>(attr)) { |
| auto Active = ODA->isActivePlatform(D->getASTContext()); |
| if (Active.hasValue()) { |
| Results.push_back(*Active); |
| } |
| } |
| } |
| return Results; |
| } |
| |
| static StringRef getLinkerPlatformName(uint8_t Id) { |
| switch (Id) { |
| #define LD_PLATFORM(Name, Id) case Id: return #Name; |
| #include "ldPlatformKinds.def" |
| default: |
| llvm_unreachable("unrecognized platform id"); |
| } |
| } |
| |
| static Optional<uint8_t> getLinkerPlatformId(StringRef Platform) { |
| return llvm::StringSwitch<Optional<uint8_t>>(Platform) |
| #define LD_PLATFORM(Name, Id) .Case(#Name, Id) |
| #include "ldPlatformKinds.def" |
| .Default(None); |
| } |
| |
| StringRef InstallNameStore::getInstallName(LinkerPlatformId Id) const { |
| auto It = PlatformInstallName.find((uint8_t)Id); |
| if (It == PlatformInstallName.end()) |
| return InstallName; |
| else |
| return It->second; |
| } |
| |
| void InstallNameStore::remark(ASTContext &Ctx, StringRef ModuleName) const { |
| Ctx.Diags.diagnose(SourceLoc(), diag::default_previous_install_name, |
| ModuleName, InstallName); |
| for (auto Pair: PlatformInstallName) { |
| Ctx.Diags.diagnose(SourceLoc(), diag::platform_previous_install_name, |
| ModuleName, getLinkerPlatformName(Pair.first), |
| Pair.second); |
| } |
| } |
| |
| static std::string getScalaNodeText(Node *N) { |
| SmallString<32> Buffer; |
| return cast<ScalarNode>(N)->getValue(Buffer).str(); |
| } |
| |
| static std::set<int8_t> getSequenceNodePlatformList(ASTContext &Ctx, Node *N) { |
| std::set<int8_t> Results; |
| for (auto &E: *cast<SequenceNode>(N)) { |
| auto Platform = getScalaNodeText(&E); |
| auto Id = getLinkerPlatformId(Platform); |
| if (Id.hasValue()) { |
| Results.insert(*Id); |
| } else { |
| // Diagnose unrecognized platform name. |
| Ctx.Diags.diagnose(SourceLoc(), diag::unknown_platform_name, Platform); |
| } |
| } |
| return Results; |
| } |
| |
| /// Parse an entry like this, where the "platforms" key-value pair is optional: |
| /// { |
| /// "module": "Foo", |
| /// "platforms": ["macOS"], |
| /// "install_name": "/System/MacOS" |
| /// }, |
| static int |
| parseEntry(ASTContext &Ctx, |
| Node *Node, std::map<std::string, InstallNameStore> &Stores) { |
| if (auto *SN = cast<SequenceNode>(Node)) { |
| for (auto It = SN->begin(); It != SN->end(); ++It) { |
| auto *MN = cast<MappingNode>(&*It); |
| std::string ModuleName; |
| std::string InstallName; |
| Optional<std::set<int8_t>> Platforms; |
| for (auto &Pair: *MN) { |
| auto Key = getScalaNodeText(Pair.getKey()); |
| auto* Value = Pair.getValue(); |
| if (Key == "module") { |
| ModuleName = getScalaNodeText(Value); |
| } else if (Key == "platforms") { |
| Platforms = getSequenceNodePlatformList(Ctx, Value); |
| } else if (Key == "install_name") { |
| InstallName = getScalaNodeText(Value); |
| } else { |
| return 1; |
| } |
| } |
| if (ModuleName.empty() || InstallName.empty()) |
| return 1; |
| auto &Store = Stores.insert(std::make_pair(ModuleName, |
| InstallNameStore())).first->second; |
| if (Platforms.hasValue()) { |
| // This install name is platform-specific. |
| for (auto Id: Platforms.getValue()) { |
| Store.PlatformInstallName[Id] = InstallName; |
| } |
| } else { |
| // The install name is the default one. |
| Store.InstallName = InstallName; |
| } |
| } |
| } else { |
| return 1; |
| } |
| return 0; |
| } |
| |
| std::unique_ptr<std::map<std::string, InstallNameStore>> |
| TBDGenVisitor::parsePreviousModuleInstallNameMap() { |
| StringRef FileName = Opts.ModuleInstallNameMapPath; |
| // Nothing to parse. |
| if (FileName.empty()) |
| return nullptr; |
| namespace yaml = llvm::yaml; |
| ASTContext &Ctx = SwiftModule->getASTContext(); |
| std::unique_ptr<std::map<std::string, InstallNameStore>> pResult( |
| new std::map<std::string, InstallNameStore>()); |
| auto &AllInstallNames = *pResult; |
| SWIFT_DEFER { |
| for (auto Pair: AllInstallNames) { |
| Pair.second.remark(Ctx, Pair.first); |
| } |
| }; |
| |
| // Load the input file. |
| llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr = |
| llvm::MemoryBuffer::getFile(FileName); |
| if (!FileBufOrErr) { |
| Ctx.Diags.diagnose(SourceLoc(), diag::previous_installname_map_missing, |
| FileName); |
| return nullptr; |
| } |
| StringRef Buffer = FileBufOrErr->get()->getBuffer(); |
| |
| // Use a new source manager instead of the one from ASTContext because we |
| // don't want the Json file to be persistent. |
| SourceManager SM; |
| yaml::Stream Stream(llvm::MemoryBufferRef(Buffer, FileName), |
| SM.getLLVMSourceMgr()); |
| for (auto DI = Stream.begin(); DI != Stream.end(); ++ DI) { |
| assert(DI != Stream.end() && "Failed to read a document"); |
| yaml::Node *N = DI->getRoot(); |
| assert(N && "Failed to find a root"); |
| if (parseEntry(Ctx, N, AllInstallNames)) { |
| Ctx.Diags.diagnose(SourceLoc(), diag::previous_installname_map_corrupted, |
| FileName); |
| return nullptr; |
| } |
| } |
| return pResult; |
| } |
| |
| static LinkerPlatformId |
| getLinkerPlatformId(OriginallyDefinedInAttr::ActiveVersion Ver) { |
| switch(Ver.Platform) { |
| case swift::PlatformKind::none: |
| llvm_unreachable("cannot find platform kind"); |
| case swift::PlatformKind::OpenBSD: |
| llvm_unreachable("not used for this platform"); |
| case swift::PlatformKind::Windows: |
| llvm_unreachable("not used for this platform"); |
| case swift::PlatformKind::iOS: |
| case swift::PlatformKind::iOSApplicationExtension: |
| return Ver.IsSimulator ? LinkerPlatformId::iOS_sim: |
| LinkerPlatformId::iOS; |
| case swift::PlatformKind::tvOS: |
| case swift::PlatformKind::tvOSApplicationExtension: |
| return Ver.IsSimulator ? LinkerPlatformId::tvOS_sim: |
| LinkerPlatformId::tvOS; |
| case swift::PlatformKind::watchOS: |
| case swift::PlatformKind::watchOSApplicationExtension: |
| return Ver.IsSimulator ? LinkerPlatformId::watchOS_sim: |
| LinkerPlatformId::watchOS; |
| case swift::PlatformKind::macOS: |
| case swift::PlatformKind::macOSApplicationExtension: |
| return LinkerPlatformId::macOS; |
| case swift::PlatformKind::macCatalyst: |
| case swift::PlatformKind::macCatalystApplicationExtension: |
| return LinkerPlatformId::macCatalyst; |
| } |
| llvm_unreachable("invalid platform kind"); |
| } |
| |
| static StringRef |
| getLinkerPlatformName(OriginallyDefinedInAttr::ActiveVersion Ver) { |
| return getLinkerPlatformName((uint8_t)getLinkerPlatformId(Ver)); |
| } |
| |
| /// Find the most relevant introducing version of the decl stack we have visted |
| /// so far. |
| static Optional<llvm::VersionTuple> |
| getInnermostIntroVersion(ArrayRef<Decl*> DeclStack, PlatformKind Platform) { |
| for (auto It = DeclStack.rbegin(); It != DeclStack.rend(); ++ It) { |
| if (auto Result = (*It)->getIntroducedOSVersion(Platform)) |
| return Result; |
| } |
| return None; |
| } |
| |
| void TBDGenVisitor::addLinkerDirectiveSymbolsLdPrevious(StringRef name, |
| llvm::MachO::SymbolKind kind) { |
| if (kind != llvm::MachO::SymbolKind::GlobalSymbol) |
| return; |
| if(DeclStack.empty()) |
| return; |
| auto TopLevelDecl = DeclStack.front(); |
| auto MovedVers = getAllMovedPlatformVersions(TopLevelDecl); |
| if (MovedVers.empty()) |
| return; |
| assert(!MovedVers.empty()); |
| assert(previousInstallNameMap); |
| auto &Ctx = TopLevelDecl->getASTContext(); |
| for (auto &Ver: MovedVers) { |
| auto IntroVer = getInnermostIntroVersion(DeclStack, Ver.Platform); |
| assert(IntroVer && "cannot find OS intro version"); |
| if (!IntroVer.hasValue()) |
| continue; |
| // This decl is available after the top-level symbol has been moved here, |
| // so we don't need the linker directives. |
| if (*IntroVer >= Ver.Version) |
| continue; |
| auto PlatformNumber = getLinkerPlatformId(Ver); |
| auto It = previousInstallNameMap->find(Ver.ModuleName.str()); |
| if (It == previousInstallNameMap->end()) { |
| Ctx.Diags.diagnose(SourceLoc(), diag::cannot_find_install_name, |
| Ver.ModuleName, getLinkerPlatformName(Ver)); |
| continue; |
| } |
| auto InstallName = It->second.getInstallName(PlatformNumber); |
| if (InstallName.empty()) { |
| Ctx.Diags.diagnose(SourceLoc(), diag::cannot_find_install_name, |
| Ver.ModuleName, getLinkerPlatformName(Ver)); |
| continue; |
| } |
| llvm::SmallString<64> Buffer; |
| llvm::raw_svector_ostream OS(Buffer); |
| // Empty compatible version indicates using the current compatible version. |
| StringRef ComptibleVersion = ""; |
| OS << "$ld$previous$"; |
| OS << InstallName << "$"; |
| OS << ComptibleVersion << "$"; |
| OS << std::to_string((uint8_t)PlatformNumber) << "$"; |
| static auto getMinor = [](Optional<unsigned> Minor) { |
| return Minor.hasValue() ? *Minor : 0; |
| }; |
| OS << IntroVer->getMajor() << "." << getMinor(IntroVer->getMinor()) << "$"; |
| OS << Ver.Version.getMajor() << "." << getMinor(Ver.Version.getMinor()) << "$"; |
| OS << name << "$"; |
| addSymbolInternal(OS.str(), SymbolKind::GlobalSymbol, |
| SymbolSource::forLinkerDirective()); |
| } |
| } |
| |
| void TBDGenVisitor::addLinkerDirectiveSymbolsLdHide(StringRef name, |
| llvm::MachO::SymbolKind kind) { |
| if (kind != llvm::MachO::SymbolKind::GlobalSymbol) |
| return; |
| if (DeclStack.empty()) |
| return; |
| auto TopLevelDecl = DeclStack.front(); |
| auto MovedVers = getAllMovedPlatformVersions(TopLevelDecl); |
| if (MovedVers.empty()) |
| return; |
| assert(!MovedVers.empty()); |
| |
| // Using $ld$add and $ld$hide cannot encode platform name in the version number, |
| // so we can only handle one version. |
| // FIXME: use $ld$previous instead |
| auto MovedVer = MovedVers.front().Version; |
| auto Platform = MovedVers.front().Platform; |
| unsigned Major[2]; |
| unsigned Minor[2]; |
| Major[1] = MovedVer.getMajor(); |
| Minor[1] = MovedVer.getMinor().hasValue() ? *MovedVer.getMinor(): 0; |
| auto IntroVer = getInnermostIntroVersion(DeclStack, Platform); |
| assert(IntroVer && "cannot find the start point of availability"); |
| if (!IntroVer.hasValue()) |
| return; |
| // This decl is available after the top-level symbol has been moved here, |
| // so we don't need the linker directives. |
| if (*IntroVer >= MovedVer) |
| return; |
| Major[0] = IntroVer->getMajor(); |
| Minor[0] = IntroVer->getMinor().hasValue() ? IntroVer->getMinor().getValue() : 0; |
| for (auto CurMaj = Major[0]; CurMaj <= Major[1]; ++ CurMaj) { |
| unsigned MinRange[2] = {0, 31}; |
| if (CurMaj == Major[0]) |
| MinRange[0] = Minor[0]; |
| if (CurMaj == Major[1]) |
| MinRange[1] = Minor[1]; |
| for (auto CurMin = MinRange[0]; CurMin != MinRange[1]; ++ CurMin) { |
| llvm::SmallString<64> Buffer; |
| llvm::raw_svector_ostream OS(Buffer); |
| OS << "$ld$hide$os" << CurMaj << "." << CurMin << "$" << name; |
| addSymbolInternal(OS.str(), SymbolKind::GlobalSymbol, |
| SymbolSource::forLinkerDirective()); |
| } |
| } |
| } |
| |
| void TBDGenVisitor::addSymbol(StringRef name, SymbolSource source, |
| SymbolKind kind) { |
| // The linker expects to see mangled symbol names in TBD files, so make sure |
| // to mangle before inserting the symbol. |
| SmallString<32> mangled; |
| llvm::Mangler::getNameWithPrefix(mangled, name, DataLayout); |
| addSymbolInternal(mangled, kind, source); |
| if (previousInstallNameMap) { |
| addLinkerDirectiveSymbolsLdPrevious(mangled, kind); |
| } else { |
| addLinkerDirectiveSymbolsLdHide(mangled, kind); |
| } |
| } |
| |
| void TBDGenVisitor::addSymbol(SILDeclRef declRef) { |
| auto linkage = effectiveLinkageForClassMember( |
| declRef.getLinkage(ForDefinition), |
| declRef.getSubclassScope()); |
| if (Opts.PublicSymbolsOnly && linkage != SILLinkage::Public) |
| return; |
| |
| addSymbol(declRef.mangle(), SymbolSource::forSILDeclRef(declRef)); |
| } |
| |
| void TBDGenVisitor::addSymbol(LinkEntity entity) { |
| auto linkage = |
| LinkInfo::get(UniversalLinkInfo, SwiftModule, entity, ForDefinition); |
| |
| auto externallyVisible = |
| llvm::GlobalValue::isExternalLinkage(linkage.getLinkage()) && |
| linkage.getVisibility() != llvm::GlobalValue::HiddenVisibility; |
| |
| if (Opts.PublicSymbolsOnly && !externallyVisible) |
| return; |
| |
| addSymbol(linkage.getName(), SymbolSource::forIRLinkEntity(entity)); |
| } |
| |
| 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(const IterableDeclContext *IDC) { |
| for (auto conformance : IDC->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<RootProtocolConformance>(conformance); |
| if (!rootConformance) { |
| continue; |
| } |
| // We cannot emit the witness table symbol if the protocol is imported from |
| // another module and it's resilient, because initialization of that protocol |
| // is necessary in this case |
| if (!rootConformance->getProtocol()->isResilient( |
| IDC->getAsGenericContext()->getParentModule(), |
| ResilienceExpansion::Maximal)) |
| 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 witnessRef = SILDeclRef(witnessDecl); |
| if (Opts.PublicSymbolsOnly) { |
| if (!conformanceIsFixed) |
| return; |
| |
| if (!isa<SelfProtocolConformance>(rootConformance) && |
| !fixmeWitnessHasLinkageThatNeedsToBePublic(witnessRef)) { |
| return; |
| } |
| } |
| |
| Mangle::ASTMangler Mangler; |
| |
| // FIXME: We should have a SILDeclRef SymbolSource for this. |
| addSymbol(Mangler.mangleWitnessThunk(rootConformance, requirementDecl), |
| SymbolSource::forUnknown()); |
| }; |
| |
| rootConformance->forEachValueWitness([&](ValueDecl *valueReq, |
| Witness witness) { |
| auto witnessDecl = witness.getDecl(); |
| if (isa<AbstractFunctionDecl>(valueReq)) { |
| addSymbolIfNecessary(valueReq, witnessDecl); |
| } else if (auto *storage = dyn_cast<AbstractStorageDecl>(valueReq)) { |
| if (auto witnessStorage = dyn_cast<AbstractStorageDecl>(witnessDecl)) { |
| storage->visitOpaqueAccessors([&](AccessorDecl *reqtAccessor) { |
| auto witnessAccessor = witnessStorage->getSynthesizedAccessor( |
| reqtAccessor->getAccessorKind()); |
| addSymbolIfNecessary(reqtAccessor, witnessAccessor); |
| }); |
| } else if (isa<EnumElementDecl>(witnessDecl)) { |
| auto getter = storage->getSynthesizedAccessor(AccessorKind::Get); |
| addSymbolIfNecessary(getter, witnessDecl); |
| } |
| } |
| }); |
| } |
| } |
| |
| void TBDGenVisitor::addAutoDiffLinearMapFunction(AbstractFunctionDecl *original, |
| AutoDiffConfig config, |
| AutoDiffLinearMapKind kind) { |
| auto &ctx = original->getASTContext(); |
| auto declRef = |
| SILDeclRef(original).asForeign(requiresForeignEntryPoint(original)); |
| |
| // Linear maps are public only when the original function is serialized. So |
| // if we're only including public symbols and it's not serialized, bail. |
| if (Opts.PublicSymbolsOnly && !declRef.isSerialized()) |
| return; |
| |
| // Differential functions are emitted only when forward-mode is enabled. |
| if (kind == AutoDiffLinearMapKind::Differential && |
| !ctx.LangOpts.EnableExperimentalForwardModeDifferentiation) |
| return; |
| auto *loweredParamIndices = autodiff::getLoweredParameterIndices( |
| config.parameterIndices, |
| original->getInterfaceType()->castTo<AnyFunctionType>()); |
| Mangle::ASTMangler mangler; |
| AutoDiffConfig silConfig{ |
| loweredParamIndices, config.resultIndices, |
| autodiff::getDifferentiabilityWitnessGenericSignature( |
| original->getGenericSignature(), config.derivativeGenericSignature)}; |
| std::string linearMapName = |
| mangler.mangleAutoDiffLinearMapHelper(declRef.mangle(), kind, silConfig); |
| addSymbol(linearMapName, SymbolSource::forSILDeclRef(declRef)); |
| } |
| |
| void TBDGenVisitor::addAutoDiffDerivativeFunction( |
| AbstractFunctionDecl *original, IndexSubset *parameterIndices, |
| GenericSignature derivativeGenericSignature, |
| AutoDiffDerivativeFunctionKind kind) { |
| auto *assocFnId = AutoDiffDerivativeFunctionIdentifier::get( |
| kind, parameterIndices, |
| autodiff::getDifferentiabilityWitnessGenericSignature( |
| original->getGenericSignature(), derivativeGenericSignature), |
| original->getASTContext()); |
| auto declRef = |
| SILDeclRef(original).asForeign(requiresForeignEntryPoint(original)); |
| addSymbol(declRef.asAutoDiffDerivativeFunction(assocFnId)); |
| } |
| |
| void TBDGenVisitor::addDifferentiabilityWitness( |
| AbstractFunctionDecl *original, IndexSubset *astParameterIndices, |
| IndexSubset *resultIndices, GenericSignature derivativeGenericSignature) { |
| bool foreign = requiresForeignEntryPoint(original); |
| auto declRef = SILDeclRef(original).asForeign(foreign); |
| |
| // Skip symbol emission for original functions that do not have public |
| // linkage. Exclude original functions that require a foreign entry point with |
| // `public_external` linkage. |
| auto originalLinkage = declRef.getLinkage(ForDefinition); |
| if (foreign) |
| originalLinkage = stripExternalFromLinkage(originalLinkage); |
| if (Opts.PublicSymbolsOnly && originalLinkage != SILLinkage::Public) |
| return; |
| |
| auto *silParamIndices = autodiff::getLoweredParameterIndices( |
| astParameterIndices, |
| original->getInterfaceType()->castTo<AnyFunctionType>()); |
| |
| auto originalMangledName = declRef.mangle(); |
| AutoDiffConfig config{ |
| silParamIndices, resultIndices, |
| autodiff::getDifferentiabilityWitnessGenericSignature( |
| original->getGenericSignature(), derivativeGenericSignature)}; |
| SILDifferentiabilityWitnessKey key(originalMangledName, config); |
| |
| Mangle::ASTMangler mangler; |
| auto mangledName = mangler.mangleSILDifferentiabilityWitnessKey(key); |
| addSymbol(mangledName, SymbolSource::forSILDeclRef(declRef)); |
| } |
| |
| void TBDGenVisitor::addDerivativeConfiguration(AbstractFunctionDecl *original, |
| AutoDiffConfig config) { |
| auto inserted = AddedDerivatives.insert({original, config}); |
| if (!inserted.second) |
| return; |
| |
| addAutoDiffLinearMapFunction(original, config, |
| AutoDiffLinearMapKind::Differential); |
| addAutoDiffLinearMapFunction(original, config, |
| AutoDiffLinearMapKind::Pullback); |
| addAutoDiffDerivativeFunction(original, config.parameterIndices, |
| config.derivativeGenericSignature, |
| AutoDiffDerivativeFunctionKind::JVP); |
| addAutoDiffDerivativeFunction(original, config.parameterIndices, |
| config.derivativeGenericSignature, |
| AutoDiffDerivativeFunctionKind::VJP); |
| addDifferentiabilityWitness(original, config.parameterIndices, |
| config.resultIndices, |
| config.derivativeGenericSignature); |
| } |
| |
| /// 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 initializer. |
| /// 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<ConstructorDecl>(afd); |
| if (!constructor) |
| return false; |
| return constructor->getParent()->getSelfClassDecl() == nullptr || |
| constructor->isConvenienceInit(); |
| } |
| |
| void TBDGenVisitor::visitDefaultArguments(ValueDecl *VD, ParameterList *PL) { |
| auto publicDefaultArgGenerators = SwiftModule->isTestingEnabled() || |
| SwiftModule->arePrivateImportsEnabled(); |
| if (Opts.PublicSymbolsOnly && !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 : *PL) { |
| if (param->isDefaultArgument()) |
| addSymbol(SILDeclRef::getDefaultArgGenerator(VD, index)); |
| ++index; |
| } |
| } |
| |
| 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<SILGenNameAttr>()) { |
| return; |
| } |
| |
| // Add exported prespecialized symbols. |
| for (auto *attr : AFD->getAttrs().getAttributes<SpecializeAttr>()) { |
| if (!attr->isExported()) |
| continue; |
| if (auto *targetFun = attr->getTargetFunctionDecl(AFD)) { |
| auto declRef = SILDeclRef(targetFun, attr->getSpecializedSignature()); |
| addSymbol(declRef.mangle(), SymbolSource::forSILDeclRef(declRef)); |
| } else { |
| auto declRef = SILDeclRef(AFD, attr->getSpecializedSignature()); |
| addSymbol(declRef.mangle(), SymbolSource::forSILDeclRef(declRef)); |
| } |
| } |
| |
| addSymbol(SILDeclRef(AFD)); |
| |
| // Add the global function pointer for a dynamically replaceable function. |
| if (AFD->shouldUseNativeMethodReplacement()) { |
| bool useAllocator = shouldUseAllocatorMangling(AFD); |
| addSymbol(LinkEntity::forDynamicallyReplaceableFunctionVariable( |
| AFD, useAllocator)); |
| addSymbol( |
| LinkEntity::forDynamicallyReplaceableFunctionKey(AFD, useAllocator)); |
| } |
| if (AFD->getDynamicallyReplacedDecl()) { |
| bool useAllocator = shouldUseAllocatorMangling(AFD); |
| addSymbol(LinkEntity::forDynamicallyReplaceableFunctionVariable( |
| AFD, useAllocator)); |
| addSymbol( |
| LinkEntity::forDynamicallyReplaceableFunctionImpl(AFD, useAllocator)); |
| } |
| |
| if (AFD->getAttrs().hasAttribute<CDeclAttr>()) { |
| // A @_cdecl("...") function has an extra symbol, with the name from the |
| // attribute. |
| addSymbol(SILDeclRef(AFD).asForeign()); |
| } |
| |
| // Add derivative function symbols. |
| for (const auto *differentiableAttr : |
| AFD->getAttrs().getAttributes<DifferentiableAttr>()) |
| addDerivativeConfiguration( |
| AFD, |
| AutoDiffConfig(differentiableAttr->getParameterIndices(), |
| IndexSubset::get(AFD->getASTContext(), 1, {0}), |
| differentiableAttr->getDerivativeGenericSignature())); |
| for (const auto *derivativeAttr : |
| AFD->getAttrs().getAttributes<DerivativeAttr>()) |
| addDerivativeConfiguration( |
| derivativeAttr->getOriginalFunction(AFD->getASTContext()), |
| AutoDiffConfig(derivativeAttr->getParameterIndices(), |
| IndexSubset::get(AFD->getASTContext(), 1, {0}), |
| AFD->getGenericSignature())); |
| |
| visitDefaultArguments(AFD, AFD->getParameters()); |
| |
| if (AFD->hasAsync()) { |
| addSymbol(LinkEntity::forAsyncFunctionPointer(AFD)); |
| } |
| } |
| |
| 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->shouldUseNativeDynamicDispatch()) { |
| addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessor(opaqueResult)); |
| addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorImpl(opaqueResult)); |
| addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorKey(opaqueResult)); |
| addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorVar(opaqueResult)); |
| } |
| if (FD->getDynamicallyReplacedDecl()) { |
| addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessor(opaqueResult)); |
| addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorVar(opaqueResult)); |
| } |
| } |
| visitAbstractFunctionDecl(FD); |
| } |
| |
| void TBDGenVisitor::visitAccessorDecl(AccessorDecl *AD) { |
| llvm_unreachable("should not see an accessor 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->getDynamicallyReplacedDecl()) { |
| addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessor(opaqueResult)); |
| addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorVar(opaqueResult)); |
| } |
| } |
| |
| // Explicitly look at each accessor here: see visitAccessorDecl. |
| ASD->visitEmittedAccessors([&](AccessorDecl *accessor) { |
| visitFuncDecl(accessor); |
| }); |
| |
| // Add derivative function symbols. |
| for (const auto *differentiableAttr : |
| ASD->getAttrs().getAttributes<DifferentiableAttr>()) |
| addDerivativeConfiguration( |
| ASD->getOpaqueAccessor(AccessorKind::Get), |
| AutoDiffConfig(differentiableAttr->getParameterIndices(), |
| IndexSubset::get(ASD->getASTContext(), 1, {0}), |
| differentiableAttr->getDerivativeGenericSignature())); |
| } |
| |
| 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<HasInitialValueAttr>() && |
| !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 (!Opts.PublicSymbolsOnly || |
| getDeclLinkage(VD) == FormalLinkage::PublicUnique) { |
| // The actual variable has a symbol. |
| // FIXME: We ought to have a symbol source for this. |
| Mangle::ASTMangler mangler; |
| addSymbol(mangler.mangleEntity(VD), SymbolSource::forUnknown()); |
| } |
| |
| if (VD->isLazilyInitializedGlobal()) |
| addSymbol(SILDeclRef(VD, SILDeclRef::Kind::GlobalAccessor)); |
| } |
| |
| // Wrapped non-static member properties may have a backing initializer. |
| if (auto wrapperInfo = VD->getPropertyWrapperBackingPropertyInfo()) { |
| if (wrapperInfo.initializeFromOriginal && !VD->isStatic()) { |
| addSymbol( |
| SILDeclRef(VD, SILDeclRef::Kind::PropertyWrapperBackingInitializer)); |
| } |
| } |
| } |
| |
| 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 (Opts.PublicSymbolsOnly && |
| 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) { |
| // FIXME: We ought to have a symbol source for this. |
| SmallString<128> buffer; |
| addSymbol(CD->getObjCRuntimeName(buffer), SymbolSource::forUnknown(), |
| SymbolKind::ObjectiveCClass); |
| } |
| } |
| |
| // Some members of classes get extra handling, beyond members of struct/enums, |
| // so let's walk over them manually. |
| for (auto *var : CD->getStoredProperties()) |
| 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<VTableVisitor> { |
| 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<ProtocolDecl>(ED->getExtendedNominal())) { |
| addConformances(ED); |
| } |
| |
| for (auto member : ED->getMembers()) |
| visit(member); |
| } |
| |
| #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; |
| } |
| llvm_unreachable("covered switch"); |
| } |
| #endif |
| |
| void TBDGenVisitor::visitProtocolDecl(ProtocolDecl *PD) { |
| if (!PD->isObjC()) { |
| addSymbol(LinkEntity::forProtocolDescriptor(PD)); |
| |
| struct WitnessVisitor : public SILWitnessVisitor<WitnessVisitor> { |
| TBDGenVisitor &TBD; |
| ProtocolDecl *PD; |
| bool Resilient; |
| |
| public: |
| WitnessVisitor(TBDGenVisitor &TBD, ProtocolDecl *PD) |
| : TBD(TBD), PD(PD), Resilient(PD->getParentModule()->isResilient()) {} |
| |
| void addMethod(SILDeclRef declRef) { |
| if (Resilient) { |
| TBD.addDispatchThunk(declRef); |
| TBD.addMethodDescriptor(declRef); |
| } |
| } |
| |
| void addAssociatedType(AssociatedType associatedType) { |
| TBD.addAssociatedTypeDescriptor(associatedType.getAssociation()); |
| } |
| |
| void addProtocolConformanceDescriptor() { |
| TBD.addProtocolRequirementsBaseDescriptor(PD); |
| } |
| |
| void addOutOfLineBaseProtocol(ProtocolDecl *proto) { |
| TBD.addBaseConformanceDescriptor(BaseConformance(PD, proto)); |
| } |
| |
| void addAssociatedConformance(AssociatedConformance associatedConf) { |
| TBD.addAssociatedConformanceDescriptor(associatedConf); |
| } |
| |
| void addPlaceholder(MissingMemberDecl *decl) {} |
| |
| void doIt() { |
| visitProtocolDecl(PD); |
| } |
| }; |
| |
| WitnessVisitor(*this, PD).doIt(); |
| |
| // 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); |
| } |
| |
| void TBDGenVisitor::visitEnumElementDecl(EnumElementDecl *EED) { |
| if (EED->getParentEnum()->isResilient()) |
| addSymbol(LinkEntity::forEnumCase(EED)); |
| |
| if (auto *PL = EED->getParameterList()) |
| visitDefaultArguments(EED, PL); |
| } |
| |
| void TBDGenVisitor::addFirstFileSymbols() { |
| if (!Opts.ModuleLinkName.empty()) { |
| // FIXME: We ought to have a symbol source for this. |
| SmallString<32> buf; |
| addSymbol(irgen::encodeForceLoadSymbolName(buf, Opts.ModuleLinkName), |
| SymbolSource::forUnknown()); |
| } |
| } |
| |
| void TBDGenVisitor::visit(Decl *D) { |
| DeclStack.push_back(D); |
| SWIFT_DEFER { DeclStack.pop_back(); }; |
| ASTVisitor::visit(D); |
| } |
| |
| static bool hasLinkerDirective(Decl *D) { |
| return !getAllMovedPlatformVersions(D).empty(); |
| } |
| |
| void TBDGenVisitor::visitFile(FileUnit *file) { |
| if (file == SwiftModule->getFiles()[0]) |
| addFirstFileSymbols(); |
| |
| SmallVector<Decl *, 16> decls; |
| file->getTopLevelDecls(decls); |
| |
| addMainIfNecessary(file); |
| |
| for (auto d : decls) { |
| if (Opts.LinkerDirectivesOnly && !hasLinkerDirective(d)) |
| continue; |
| visit(d); |
| } |
| } |
| |
| void TBDGenVisitor::visit(const TBDGenDescriptor &desc) { |
| if (auto *singleFile = desc.getSingleFile()) { |
| assert(SwiftModule == singleFile->getParentModule() && |
| "mismatched file and module"); |
| visitFile(singleFile); |
| |
| // Visit synthesized file, if it exists. |
| if (auto *SF = dyn_cast<SourceFile>(singleFile)) { |
| if (auto *synthesizedFile = SF->getSynthesizedFile()) |
| visitFile(synthesizedFile); |
| } |
| return; |
| } |
| |
| llvm::SmallVector<ModuleDecl*, 4> Modules; |
| Modules.push_back(SwiftModule); |
| |
| auto &ctx = SwiftModule->getASTContext(); |
| for (auto Name: Opts.embedSymbolsFromModules) { |
| if (auto *MD = ctx.getModuleByName(Name)) { |
| // If it is a clang module, the symbols should be collected by TAPI. |
| if (!MD->isNonSwiftModule()) { |
| Modules.push_back(MD); |
| continue; |
| } |
| } |
| // Diagnose module name that cannot be found |
| ctx.Diags.diagnose(SourceLoc(), diag::unknown_swift_module_name, Name); |
| } |
| // Collect symbols in each module. |
| llvm::for_each(Modules, [&](ModuleDecl *M) { |
| for (auto *file : M->getFiles()) { |
| visitFile(file); |
| } |
| }); |
| } |
| |
| /// The kind of version being parsed, used for diagnostics. |
| /// Note: Must match the order in DiagnosticsFrontend.def |
| enum DylibVersionKind_t: unsigned { |
| CurrentVersion, |
| CompatibilityVersion |
| }; |
| |
| /// Converts a version string into a packed version, truncating each component |
| /// if necessary to fit all 3 into a 32-bit packed structure. |
| /// |
| /// For example, the version '1219.37.11' will be packed as |
| /// |
| /// Major (1,219) Minor (37) Patch (11) |
| /// ┌───────────────────┬──────────┬──────────┐ |
| /// │ 00001100 11000011 │ 00100101 │ 00001011 │ |
| /// └───────────────────┴──────────┴──────────┘ |
| /// |
| /// If an individual component is greater than the highest number that can be |
| /// represented in its alloted space, it will be truncated to the maximum value |
| /// that fits in the alloted space, which matches the behavior of the linker. |
| static Optional<llvm::MachO::PackedVersion> |
| parsePackedVersion(DylibVersionKind_t kind, StringRef versionString, |
| ASTContext &ctx) { |
| if (versionString.empty()) |
| return None; |
| |
| llvm::MachO::PackedVersion version; |
| auto result = version.parse64(versionString); |
| if (!result.first) { |
| ctx.Diags.diagnose(SourceLoc(), diag::tbd_err_invalid_version, |
| (unsigned)kind, versionString); |
| return None; |
| } |
| if (result.second) { |
| ctx.Diags.diagnose(SourceLoc(), diag::tbd_warn_truncating_version, |
| (unsigned)kind, versionString); |
| } |
| return version; |
| } |
| |
| static bool isApplicationExtensionSafe(const LangOptions &LangOpts) { |
| // Existing linkers respect these flags to determine app extension safety. |
| return LangOpts.EnableAppExtensionRestrictions || |
| llvm::sys::Process::GetEnv("LD_NO_ENCRYPT") || |
| llvm::sys::Process::GetEnv("LD_APPLICATION_EXTENSION_SAFE"); |
| } |
| |
| TBDFile GenerateTBDRequest::evaluate(Evaluator &evaluator, |
| TBDGenDescriptor desc) const { |
| auto *M = desc.getParentModule(); |
| auto &opts = desc.getOptions(); |
| auto &ctx = M->getASTContext(); |
| |
| llvm::MachO::InterfaceFile file; |
| file.setFileType(llvm::MachO::FileType::TBD_V4); |
| file.setApplicationExtensionSafe(isApplicationExtensionSafe(ctx.LangOpts)); |
| file.setInstallName(opts.InstallName); |
| file.setTwoLevelNamespace(); |
| file.setSwiftABIVersion(irgen::getSwiftABIVersion()); |
| file.setInstallAPI(opts.IsInstallAPI); |
| |
| if (auto packed = parsePackedVersion(CurrentVersion, |
| opts.CurrentVersion, ctx)) { |
| file.setCurrentVersion(*packed); |
| } |
| |
| if (auto packed = parsePackedVersion(CompatibilityVersion, |
| opts.CompatibilityVersion, ctx)) { |
| file.setCompatibilityVersion(*packed); |
| } |
| |
| llvm::MachO::Target target(ctx.LangOpts.Target); |
| file.addTarget(target); |
| // Add target variant |
| if (ctx.LangOpts.TargetVariant.hasValue()) { |
| llvm::MachO::Target targetVar(*ctx.LangOpts.TargetVariant); |
| file.addTarget(targetVar); |
| } |
| |
| llvm::MachO::TargetList targets{target}; |
| auto addSymbol = [&](StringRef symbol, SymbolKind kind, SymbolSource source) { |
| file.addSymbol(kind, symbol, targets); |
| }; |
| |
| TBDGenVisitor visitor(desc, addSymbol); |
| visitor.visit(desc); |
| return file; |
| } |
| |
| std::vector<std::string> |
| PublicSymbolsRequest::evaluate(Evaluator &evaluator, |
| TBDGenDescriptor desc) const { |
| std::vector<std::string> symbols; |
| auto addSymbol = [&](StringRef symbol, SymbolKind kind, SymbolSource source) { |
| if (kind == SymbolKind::GlobalSymbol) |
| symbols.push_back(symbol.str()); |
| }; |
| |
| TBDGenVisitor visitor(desc, addSymbol); |
| visitor.visit(desc); |
| return symbols; |
| } |
| |
| std::vector<std::string> swift::getPublicSymbols(TBDGenDescriptor desc) { |
| auto &evaluator = desc.getParentModule()->getASTContext().evaluator; |
| return llvm::cantFail(evaluator(PublicSymbolsRequest{desc})); |
| } |
| void swift::writeTBDFile(ModuleDecl *M, llvm::raw_ostream &os, |
| const TBDGenOptions &opts) { |
| auto &evaluator = M->getASTContext().evaluator; |
| auto desc = TBDGenDescriptor::forModule(M, opts); |
| auto file = llvm::cantFail(evaluator(GenerateTBDRequest{desc})); |
| llvm::cantFail(llvm::MachO::TextAPIWriter::writeToStream(os, file), |
| "YAML writing should be error-free"); |
| } |
| |
| SymbolSourceMap SymbolSourceMapRequest::evaluate(Evaluator &evaluator, |
| TBDGenDescriptor desc) const { |
| using Map = SymbolSourceMap::Storage; |
| Map symbolSources; |
| |
| auto addSymbol = [&](StringRef symbol, SymbolKind kind, SymbolSource source) { |
| symbolSources.insert({symbol, source}); |
| }; |
| |
| TBDGenVisitor visitor(desc, addSymbol); |
| visitor.visit(desc); |
| |
| // FIXME: Once the evaluator supports returning a reference to a cached value |
| // in storage, this won't be necessary. |
| auto &ctx = desc.getParentModule()->getASTContext(); |
| auto *memory = ctx.Allocate<Map>(); |
| *memory = std::move(symbolSources); |
| ctx.addCleanup([memory](){ memory->~Map(); }); |
| return SymbolSourceMap(memory); |
| } |