blob: d527cbd38c01703e0038edc50ae56fc4b3b36c32 [file] [log] [blame]
//===--- 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);
}