diff --git a/include/swift/IRGen/IRSymbolVisitor.h b/include/swift/IRGen/IRSymbolVisitor.h new file mode 100644 index 0000000000000..7bf71484effc6 --- /dev/null +++ b/include/swift/IRGen/IRSymbolVisitor.h @@ -0,0 +1,79 @@ +//===--- IRSymbolVisitor.h - Symbol Visitor for IR --------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2022 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 +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_IRGEN_IRSYMBOLVISITOR_H +#define SWIFT_IRGEN_IRSYMBOLVISITOR_H + +#include "swift/IRGen/Linking.h" + +namespace swift { + +class SILSymbolVisitorContext; + +namespace irgen { + +/// Context for symbol enumeration using `IRSymbolVisitor`. +class IRSymbolVisitorContext { + const UniversalLinkageInfo &LinkInfo; + const SILSymbolVisitorContext &SILCtx; + +public: + IRSymbolVisitorContext(const UniversalLinkageInfo &LinkInfo, + const SILSymbolVisitorContext &SILCtx) + : LinkInfo{LinkInfo}, SILCtx{SILCtx} {} + + const UniversalLinkageInfo &getLinkInfo() const { return LinkInfo; } + const SILSymbolVisitorContext &getSILCtx() const { return SILCtx; } +}; + +/// A visitor class which may be used to enumerate the entities representing +/// linker symbols associated with a Swift declaration, file, or module. This +/// class is a refinement of `SILSymbolVisitor` for the IRGen layer. Most of the +/// enumerated linker symbols can be represented as either a `SILDeclRef` or a +/// `LinkEntity`, but a few aren't supported by those abstractions and are +/// handled ad-hoc. Additionally, there are some Obj-C entities (like methods) +/// that don't actually have associated linker symbols but are enumerated for +/// the convenience of clients using this utility for API surface discovery. +class IRSymbolVisitor { +public: + virtual ~IRSymbolVisitor() {} + + /// Enumerate the symbols associated with the given decl. + void visit(Decl *D, const IRSymbolVisitorContext &ctx); + + /// Enumerate the symbols associated with the given file. + void visitFile(FileUnit *file, const IRSymbolVisitorContext &ctx); + + /// Enumerate the symbols associated with the given modules. + void visitModules(llvm::SmallVector &modules, + const IRSymbolVisitorContext &ctx); + + /// Override to prepare for enumeration of the symbols for a specific decl. + virtual void willVisitDecl(Decl *D) {} + + /// Override to clean up after enumeration of the symbols for a specific decl. + virtual void didVisitDecl(Decl *D) {} + + virtual void addFunction(SILDeclRef declRef) {} + virtual void addFunction(StringRef name, SILDeclRef declRef) {} + virtual void addGlobalVar(VarDecl *VD) {} + virtual void addLinkEntity(LinkEntity entity) {} + virtual void addObjCInterface(ClassDecl *CD) {} + virtual void addObjCMethod(AbstractFunctionDecl *AFD) {} + virtual void addProtocolWitnessThunk(RootProtocolConformance *C, + ValueDecl *requirementDecl) {} +}; + +} // end namespace irgen +} // end namespace swift + +#endif diff --git a/include/swift/SIL/SILSymbolVisitor.h b/include/swift/SIL/SILSymbolVisitor.h new file mode 100644 index 0000000000000..b0d448834812b --- /dev/null +++ b/include/swift/SIL/SILSymbolVisitor.h @@ -0,0 +1,131 @@ +//===--- SILSymbolVisitor.h - Symbol Visitor for SIL ------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2022 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 +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SIL_SILSYMBOLVISITOR_H +#define SWIFT_SIL_SILSYMBOLVISITOR_H + +#include "swift/AST/Decl.h" +#include "swift/AST/ProtocolAssociations.h" +#include "swift/AST/ProtocolConformance.h" +#include "swift/SIL/SILDeclRef.h" + +namespace swift { + +/// Options dictating which symbols are enumerated by `SILSymbolVisitor`. +struct SILSymbolVisitorOptions { + /// Whether to visit the members of declarations like structs, classes, and + /// protocols. + bool VisitMembers = true; + + /// Whether to only visit declarations for which linker directive symbols + /// are needed (e.g. decls with `@_originallyDefinedIn`. + bool LinkerDirectivesOnly = false; + + /// Whether to only visit symbols with public linkage. + bool PublicSymbolsOnly = true; + + /// Whether LLVM IR Virtual Function Elimination is enabled. + bool VirtualFunctionElimination = false; + + /// Whether LLVM IR Witness Method Elimination is enabled. + bool WitnessMethodElimination = false; +}; + +/// Context for `SILSymbolVisitor` symbol enumeration. +class SILSymbolVisitorContext { + ModuleDecl *Module; + const SILSymbolVisitorOptions Opts; + +public: + SILSymbolVisitorContext(ModuleDecl *M, const SILSymbolVisitorOptions Opts) + : Module{M}, Opts{Opts} { + assert(M); + }; + + ModuleDecl *getModule() const { return Module; } + const SILSymbolVisitorOptions &getOpts() const { return Opts; } +}; + +/// A visitor class which may be used to enumerate the entities representing +/// linker symbols associated with a Swift declaration, file, or module. Some +/// enumerated linker symbols can be represented as a `SILDeclRef`. The rest are +/// enumerated ad-hoc. Additionally, there a some Obj-C entities (like methods) +/// that don't actually have associated linker symbols but are enumerated for +/// the convenience of clients using this utility for API surface discovery. +class SILSymbolVisitor { +public: + virtual ~SILSymbolVisitor() {} + + /// Enumerate the symbols associated with the given decl. + void visitDecl(Decl *D, const SILSymbolVisitorContext &ctx); + + /// Enumerate the symbols associated with the given file. + void visitFile(FileUnit *file, const SILSymbolVisitorContext &ctx); + + /// Enumerate the symbols associated with the given modules. + void visitModules(llvm::SmallVector &modules, + const SILSymbolVisitorContext &ctx); + + /// Override to prepare for enumeration of the symbols for a specific decl. + virtual void willVisitDecl(Decl *D) {} + + /// Override to clean up after enumeration of the symbols for a specific decl. + virtual void didVisitDecl(Decl *D) {} + + /// A classification for the dynamic dispatch metadata of a decl. + enum class DynamicKind { + /// May be replaced at runtime (e.g.`dynamic`). + Replaceable, + + /// May replace another decl at runtime (e.g. `@_dynamicReplacement(for:)`). + Replacement, + }; + + virtual void addAssociatedConformanceDescriptor(AssociatedConformance AC) {} + virtual void addAssociatedTypeDescriptor(AssociatedTypeDecl *ATD) {} + virtual void addAsyncFunctionPointer(SILDeclRef declRef) {} + virtual void addBaseConformanceDescriptor(BaseConformance BC) {} + virtual void addClassMetadataBaseOffset(ClassDecl *CD) {} + virtual void addDispatchThunk(SILDeclRef declRef) {} + virtual void addDynamicFunction(AbstractFunctionDecl *AFD, + DynamicKind dynKind) {} + virtual void addEnumCase(EnumElementDecl *EED) {} + virtual void addFieldOffset(VarDecl *VD) {} + virtual void addFunction(SILDeclRef declRef) {} + virtual void addFunction(StringRef name, SILDeclRef declRef) {} + virtual void addGlobalVar(VarDecl *VD) {} + virtual void addMethodDescriptor(SILDeclRef declRef) {} + virtual void addMethodLookupFunction(ClassDecl *CD) {} + virtual void addNominalTypeDescriptor(NominalTypeDecl *NTD) {} + virtual void addObjCClass(ClassDecl *CD) {} + virtual void addObjCInterface(ClassDecl *CD) {} + virtual void addObjCMetaclass(ClassDecl *CD) {} + virtual void addObjCMethod(AbstractFunctionDecl *AFD) {} + virtual void addObjCResilientClassStub(ClassDecl *CD) {} + virtual void addOpaqueTypeDescriptor(OpaqueTypeDecl *OTD) {} + virtual void addOpaqueTypeDescriptorAccessor(OpaqueTypeDecl *OTD, + DynamicKind dynKind) {} + virtual void addPropertyDescriptor(AbstractStorageDecl *ASD) {} + virtual void addProtocolConformanceDescriptor(RootProtocolConformance *C) {} + virtual void addProtocolDescriptor(ProtocolDecl *PD) {} + virtual void addProtocolRequirementsBaseDescriptor(ProtocolDecl *PD) {} + virtual void addProtocolWitnessTable(RootProtocolConformance *C) {} + virtual void addProtocolWitnessThunk(RootProtocolConformance *C, + ValueDecl *requirementDecl) {} + virtual void addSwiftMetaclassStub(ClassDecl *CD) {} + virtual void addTypeMetadataAccessFunction(CanType T) {} + virtual void addTypeMetadataAddress(CanType T) {} +}; + +} // end namespace swift + +#endif diff --git a/lib/IRGen/CMakeLists.txt b/lib/IRGen/CMakeLists.txt index 154db6ef32d8f..6367c306aec04 100644 --- a/lib/IRGen/CMakeLists.txt +++ b/lib/IRGen/CMakeLists.txt @@ -50,6 +50,7 @@ add_swift_host_library(swiftIRGen STATIC IRGenSILPasses.cpp IRGenRequests.cpp IRGenSIL.cpp + IRSymbolVisitor.cpp Linking.cpp LoadableByAddress.cpp LocalTypeData.cpp diff --git a/lib/IRGen/IRSymbolVisitor.cpp b/lib/IRGen/IRSymbolVisitor.cpp new file mode 100644 index 0000000000000..3feb9c553c6be --- /dev/null +++ b/lib/IRGen/IRSymbolVisitor.cpp @@ -0,0 +1,253 @@ +//===--- IRSymbolVisitor.cpp - IR Linker Symbol Visitor ------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2022 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 liker symbol enumeration for IRSymbolVisitor. +// +//===----------------------------------------------------------------------===// + +#include "swift/IRGen/IRSymbolVisitor.h" + +#include "swift/SIL/SILSymbolVisitor.h" + +using namespace swift; +using namespace irgen; + +/// 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. A designated init +/// of a class emits 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(AFD); + if (!constructor) + return false; + return constructor->getParent()->getSelfClassDecl() == nullptr || + constructor->isConvenienceInit(); +} + +/// The underlying implementation of the IR symbol visitor logic. This class is +/// responsible for overriding the abstract methods of `SILSymbolVisitor` and +/// emitting `LinkEntity` instances to the downstream visitor in addition to +/// passing through `SILDeclRef`s produced by the SIL symbol visitor. +class IRSymbolVisitorImpl : public SILSymbolVisitor { + IRSymbolVisitor &Visitor; + const IRSymbolVisitorContext &Ctx; + bool PublicSymbolsOnly; + + /// Emits the given `LinkEntity` to the downstream visitor as long as the + /// entity has the required linkage. + /// + /// FIXME: The need for an ignoreVisibility flag here possibly indicates that + /// there is something broken about the linkage computation below. + void addLinkEntity(LinkEntity entity, bool ignoreVisibility = false) { + if (!ignoreVisibility) { + auto linkage = + LinkInfo::get(Ctx.getLinkInfo(), Ctx.getSILCtx().getModule(), entity, + ForDefinition); + + auto externallyVisible = + llvm::GlobalValue::isExternalLinkage(linkage.getLinkage()) && + linkage.getVisibility() != llvm::GlobalValue::HiddenVisibility; + + if (PublicSymbolsOnly && !externallyVisible) + return; + } + + Visitor.addLinkEntity(entity); + } + +public: + IRSymbolVisitorImpl(IRSymbolVisitor &Visitor, + const IRSymbolVisitorContext &Ctx) + : Visitor{Visitor}, Ctx{Ctx}, + PublicSymbolsOnly{Ctx.getSILCtx().getOpts().PublicSymbolsOnly} {} + + void willVisitDecl(Decl *D) override { + Visitor.willVisitDecl(D); + } + + void didVisitDecl(Decl *D) override { + Visitor.didVisitDecl(D); + } + + void addAssociatedConformanceDescriptor(AssociatedConformance AC) override { + addLinkEntity(LinkEntity::forAssociatedConformanceDescriptor(AC)); + } + + void addAssociatedTypeDescriptor(AssociatedTypeDecl *ATD) override { + addLinkEntity(LinkEntity::forAssociatedTypeDescriptor(ATD)); + } + + void addAsyncFunctionPointer(SILDeclRef declRef) override { + addLinkEntity(LinkEntity::forAsyncFunctionPointer(declRef), + /*ignoreVisibility=*/true); + } + + void addBaseConformanceDescriptor(BaseConformance BC) override { + addLinkEntity(LinkEntity::forBaseConformanceDescriptor(BC)); + } + + void addClassMetadataBaseOffset(ClassDecl *CD) override { + addLinkEntity(LinkEntity::forClassMetadataBaseOffset(CD)); + } + + void addDispatchThunk(SILDeclRef declRef) override { + auto entity = LinkEntity::forDispatchThunk(declRef); + addLinkEntity(entity); + + if (declRef.getAbstractFunctionDecl()->hasAsync()) + addLinkEntity(LinkEntity::forAsyncFunctionPointer(entity)); + } + + void addDynamicFunction(AbstractFunctionDecl *AFD, + DynamicKind dynKind) override { + bool useAllocator = shouldUseAllocatorMangling(AFD); + addLinkEntity(LinkEntity::forDynamicallyReplaceableFunctionVariable( + AFD, useAllocator)); + switch (dynKind) { + case DynamicKind::Replaceable: + addLinkEntity( + LinkEntity::forDynamicallyReplaceableFunctionKey(AFD, useAllocator)); + break; + case DynamicKind::Replacement: + addLinkEntity( + LinkEntity::forDynamicallyReplaceableFunctionImpl(AFD, useAllocator)); + break; + } + } + + void addEnumCase(EnumElementDecl *EED) override { + addLinkEntity(LinkEntity::forEnumCase(EED)); + } + + void addFieldOffset(VarDecl *VD) override { + addLinkEntity(LinkEntity::forFieldOffset(VD)); + } + + void addFunction(SILDeclRef declRef) override { + Visitor.addFunction(declRef); + } + + void addFunction(StringRef name, SILDeclRef declRef) override { + Visitor.addFunction(name, declRef); + } + + void addGlobalVar(VarDecl *VD) override { + Visitor.addGlobalVar(VD); + } + + void addMethodDescriptor(SILDeclRef declRef) override { + addLinkEntity(LinkEntity::forMethodDescriptor(declRef)); + } + + void addMethodLookupFunction(ClassDecl *CD) override { + addLinkEntity(LinkEntity::forMethodLookupFunction(CD)); + } + + void addNominalTypeDescriptor(NominalTypeDecl *NTD) override { + addLinkEntity(LinkEntity::forNominalTypeDescriptor(NTD)); + } + + void addObjCClass(ClassDecl *CD) override { + addLinkEntity(LinkEntity::forObjCClass(CD)); + } + + void addObjCInterface(ClassDecl *CD) override { + // Pass through; Obj-C interfaces don't have linkable symbols. + Visitor.addObjCInterface(CD); + } + + void addObjCMetaclass(ClassDecl *CD) override { + addLinkEntity(LinkEntity::forObjCMetaclass(CD)); + } + + void addObjCMethod(AbstractFunctionDecl *AFD) override { + // Pass through; Obj-C methods don't have linkable symbols. + Visitor.addObjCMethod(AFD); + } + + void addObjCResilientClassStub(ClassDecl *CD) override { + addLinkEntity(LinkEntity::forObjCResilientClassStub( + CD, TypeMetadataAddress::AddressPoint)); + } + + void addOpaqueTypeDescriptor(OpaqueTypeDecl *OTD) override { + addLinkEntity(LinkEntity::forOpaqueTypeDescriptor(OTD)); + } + + void addOpaqueTypeDescriptorAccessor(OpaqueTypeDecl *OTD, + DynamicKind dynKind) override { + addLinkEntity(LinkEntity::forOpaqueTypeDescriptorAccessor(OTD)); + switch (dynKind) { + case DynamicKind::Replaceable: + addLinkEntity(LinkEntity::forOpaqueTypeDescriptorAccessorImpl(OTD)); + addLinkEntity(LinkEntity::forOpaqueTypeDescriptorAccessorKey(OTD)); + break; + case DynamicKind::Replacement: + break; + } + addLinkEntity(LinkEntity::forOpaqueTypeDescriptorAccessorVar(OTD)); + } + + void addPropertyDescriptor(AbstractStorageDecl *ASD) override { + addLinkEntity(LinkEntity::forPropertyDescriptor(ASD)); + } + + void addProtocolConformanceDescriptor(RootProtocolConformance *C) override { + addLinkEntity(LinkEntity::forProtocolConformanceDescriptor(C)); + } + + void addProtocolDescriptor(ProtocolDecl *PD) override { + addLinkEntity(LinkEntity::forProtocolDescriptor(PD)); + } + + void addProtocolRequirementsBaseDescriptor(ProtocolDecl *PD) override { + addLinkEntity(LinkEntity::forProtocolRequirementsBaseDescriptor(PD)); + } + + void addProtocolWitnessTable(RootProtocolConformance *C) override { + addLinkEntity(LinkEntity::forProtocolWitnessTable(C)); + } + + void addProtocolWitnessThunk(RootProtocolConformance *C, + ValueDecl *requirementDecl) override { + Visitor.addProtocolWitnessThunk(C, requirementDecl); + } + + void addSwiftMetaclassStub(ClassDecl *CD) override { + addLinkEntity(LinkEntity::forSwiftMetaclassStub(CD)); + } + + void addTypeMetadataAccessFunction(CanType T) override { + addLinkEntity(LinkEntity::forTypeMetadataAccessFunction(T)); + } + + void addTypeMetadataAddress(CanType T) override { + addLinkEntity( + LinkEntity::forTypeMetadata(T, TypeMetadataAddress::AddressPoint)); + } +}; + +void IRSymbolVisitor::visit(Decl *D, const IRSymbolVisitorContext &Ctx) { + IRSymbolVisitorImpl(*this, Ctx).visitDecl(D, Ctx.getSILCtx()); +} + +void IRSymbolVisitor::visitFile(FileUnit *file, + const IRSymbolVisitorContext &Ctx) { + IRSymbolVisitorImpl(*this, Ctx).visitFile(file, Ctx.getSILCtx()); +} + +void IRSymbolVisitor::visitModules(llvm::SmallVector &modules, + const IRSymbolVisitorContext &Ctx) { + IRSymbolVisitorImpl(*this, Ctx).visitModules(modules, Ctx.getSILCtx()); +} diff --git a/lib/IRGen/TBDGen.cpp b/lib/IRGen/TBDGen.cpp index d9fbfd27c88c4..9375244193ab6 100644 --- a/lib/IRGen/TBDGen.cpp +++ b/lib/IRGen/TBDGen.cpp @@ -16,9 +16,9 @@ #include "swift/IRGen/TBDGen.h" -#include "swift/AST/Availability.h" #include "swift/AST/ASTMangler.h" #include "swift/AST/ASTVisitor.h" +#include "swift/AST/Availability.h" #include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" @@ -35,6 +35,7 @@ #include "swift/SIL/FormalLinkage.h" #include "swift/SIL/SILDeclRef.h" #include "swift/SIL/SILModule.h" +#include "swift/SIL/SILSymbolVisitor.h" #include "swift/SIL/SILVTableVisitor.h" #include "swift/SIL/SILWitnessTable.h" #include "swift/SIL/SILWitnessVisitor.h" @@ -45,8 +46,8 @@ #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/Support/YAMLTraits.h" #include "llvm/TextAPI/InterfaceFile.h" #include "llvm/TextAPI/Symbol.h" #include "llvm/TextAPI/TextAPIReader.h" @@ -62,10 +63,6 @@ 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, APIRecorder &recorder) : TBDGenVisitor(desc.getTarget(), desc.getDataLayoutString(), @@ -403,755 +400,58 @@ void TBDGenVisitor::addSymbol(StringRef name, SymbolSource source, } } -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::addAsyncFunctionPointerSymbol(SILDeclRef declRef) { - auto silLinkage = effectiveLinkageForClassMember( - declRef.getLinkage(ForDefinition), - declRef.getSubclassScope()); - if (Opts.PublicSymbolsOnly && silLinkage != SILLinkage::Public) - return; - - auto entity = LinkEntity::forAsyncFunctionPointer(declRef); - auto linkage = - LinkInfo::get(UniversalLinkInfo, SwiftModule, entity, ForDefinition); - addSymbol(linkage.getName(), 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); - - if (declRef.getAbstractFunctionDecl()->hasAsync()) - addSymbol(LinkEntity::forAsyncFunctionPointer(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::willVisitDecl(Decl *D) { + DeclStack.push_back(D); } -void TBDGenVisitor::addBaseConformanceDescriptor( - BaseConformance conformance) { - auto entity = LinkEntity::forBaseConformanceDescriptor(conformance); - addSymbol(entity); +void TBDGenVisitor::didVisitDecl(Decl *D) { + assert(DeclStack.back() == D); + DeclStack.pop_back(); } -void TBDGenVisitor::addConformances(const IterableDeclContext *IDC) { - for (auto conformance : IDC->getLocalConformances( - ConformanceLookupKind::NonInherited)) { - auto protocol = conformance->getProtocol(); - if (Opts.PublicSymbolsOnly && - getDeclLinkage(protocol) != FormalLinkage::PublicUnique) - continue; - - 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; - } - // 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(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(valueReq)) { - addSymbolIfNecessary(valueReq, witnessDecl); - } else if (auto *storage = dyn_cast(valueReq)) { - if (auto witnessStorage = dyn_cast(witnessDecl)) { - storage->visitOpaqueAccessors([&](AccessorDecl *reqtAccessor) { - auto witnessAccessor = witnessStorage->getSynthesizedAccessor( - reqtAccessor->getAccessorKind()); - addSymbolIfNecessary(reqtAccessor, witnessAccessor); - }); - } else if (isa(witnessDecl)) { - auto getter = storage->getSynthesizedAccessor(AccessorKind::Get); - addSymbolIfNecessary(getter, witnessDecl); - } - } - }); - } -} - -void TBDGenVisitor::addAutoDiffLinearMapFunction(AbstractFunctionDecl *original, - const 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.hasFeature(Feature::ForwardModeDifferentiation)) - return; - auto *loweredParamIndices = autodiff::getLoweredParameterIndices( - config.parameterIndices, - original->getInterfaceType()->castTo()); - Mangle::ASTMangler mangler; - AutoDiffConfig silConfig{ - loweredParamIndices, config.resultIndices, - autodiff::getDifferentiabilityWitnessGenericSignature( - original->getGenericSignature(), config.derivativeGenericSignature)}; - std::string linearMapName = - mangler.mangleAutoDiffLinearMap(original, kind, silConfig); - addSymbol(linearMapName, SymbolSource::forSILDeclRef(declRef)); +void TBDGenVisitor::addFunction(SILDeclRef declRef) { + addSymbol(declRef.mangle(), 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::addFunction(StringRef name, SILDeclRef declRef) { + addSymbol(name, SymbolSource::forSILDeclRef(declRef)); } -void TBDGenVisitor::addDifferentiabilityWitness( - AbstractFunctionDecl *original, DifferentiabilityKind kind, - 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()); - - auto originalMangledName = declRef.mangle(); - AutoDiffConfig config{ - silParamIndices, resultIndices, - autodiff::getDifferentiabilityWitnessGenericSignature( - original->getGenericSignature(), derivativeGenericSignature)}; - +void TBDGenVisitor::addGlobalVar(VarDecl *VD) { + // FIXME: We ought to have a symbol source for this. Mangle::ASTMangler mangler; - auto mangledName = mangler.mangleSILDifferentiabilityWitness( - originalMangledName, kind, config); - addSymbol(mangledName, SymbolSource::forSILDeclRef(declRef)); + addSymbol(mangler.mangleEntity(VD), SymbolSource::forUnknown()); } -void TBDGenVisitor::addDerivativeConfiguration(DifferentiabilityKind diffKind, - AbstractFunctionDecl *original, - const 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, diffKind, config.parameterIndices, - config.resultIndices, - config.derivativeGenericSignature); -} +void TBDGenVisitor::addLinkEntity(LinkEntity entity) { + auto linkage = + LinkInfo::get(UniversalLinkInfo, SwiftModule, entity, ForDefinition); -/// 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(afd); - if (!constructor) - return false; - return constructor->getParent()->getSelfClassDecl() == nullptr || - constructor->isConvenienceInit(); + addSymbol(linkage.getName(), SymbolSource::forIRLinkEntity(entity)); } -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::addObjCInterface(ClassDecl *CD) { + // FIXME: We ought to have a symbol source for this. + SmallString<128> buffer; + addSymbol(CD->getObjCRuntimeName(buffer), SymbolSource::forUnknown(), + SymbolKind::ObjectiveCClass); + recorder.addObjCInterface(CD); } -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; - } - - // Add exported prespecialized symbols. - for (auto *attr : AFD->getAttrs().getAttributes()) { - if (!attr->isExported()) - continue; - - auto erasedSignature = attr->getSpecializedSignature() - .typeErased(attr->getTypeErasedParams()); - - if (auto *targetFun = attr->getTargetFunctionDecl(AFD)) { - auto declRef = SILDeclRef(targetFun, erasedSignature); - addSymbol(declRef.mangle(), SymbolSource::forSILDeclRef(declRef)); - } else { - auto declRef = SILDeclRef(AFD, erasedSignature); - 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()) { - // A @_cdecl("...") function has an extra symbol, with the name from the - // attribute. - addSymbol(SILDeclRef(AFD).asForeign()); - } - - if (auto distributedThunk = AFD->getDistributedThunk()) { - auto thunk = SILDeclRef(distributedThunk).asDistributed(); - addSymbol(thunk); - addAsyncFunctionPointerSymbol(thunk); - } - - // Add derivative function symbols. - for (const auto *differentiableAttr : - AFD->getAttrs().getAttributes()) - addDerivativeConfiguration( - differentiableAttr->getDifferentiabilityKind(), - AFD, - AutoDiffConfig(differentiableAttr->getParameterIndices(), - IndexSubset::get(AFD->getASTContext(), 1, {0}), - differentiableAttr->getDerivativeGenericSignature())); - for (const auto *derivativeAttr : - AFD->getAttrs().getAttributes()) - addDerivativeConfiguration( - DifferentiabilityKind::Reverse, - derivativeAttr->getOriginalFunction(AFD->getASTContext()), - AutoDiffConfig(derivativeAttr->getParameterIndices(), - IndexSubset::get(AFD->getASTContext(), 1, {0}), - AFD->getGenericSignature())); - - visitDefaultArguments(AFD, AFD->getParameters()); - - if (AFD->hasAsync()) { - addAsyncFunctionPointerSymbol(SILDeclRef(AFD)); - } - - // Skip non objc compatible methods or non-public methods. - if (isa(AFD) || !AFD->isObjC() || - AFD->getFormalAccess() != AccessLevel::Public) - return; +void TBDGenVisitor::addObjCMethod(AbstractFunctionDecl *AFD) { if (auto *CD = dyn_cast(AFD->getDeclContext())) recorder.addObjCMethod(CD, SILDeclRef(AFD)); else if (auto *ED = dyn_cast(AFD->getDeclContext())) recorder.addObjCMethod(ED, SILDeclRef(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()) - addDerivativeConfiguration( - differentiableAttr->getDifferentiabilityKind(), - 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() && - !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. - auto initInfo = VD->getPropertyWrapperInitializerInfo(); - if (initInfo.hasInitFromWrappedValue() && !VD->isStatic()) { - addSymbol( - SILDeclRef(VD, SILDeclRef::Kind::PropertyWrapperBackingInitializer)); - } - } +void TBDGenVisitor::addProtocolWitnessThunk(RootProtocolConformance *C, + ValueDecl *requirementDecl) { + Mangle::ASTMangler Mangler; - visitAbstractStorageDecl(VD); -} - -void TBDGenVisitor::visitSubscriptDecl(SubscriptDecl *SD) { - visitDefaultArguments(SD, SD->getIndices()); - visitAbstractStorageDecl(SD); -} - -void TBDGenVisitor::visitNominalTypeDecl(NominalTypeDecl *NTD) { - auto declaredType = NTD->getDeclaredType()->getCanonicalType(); - - if (!NTD->getObjCImplementationDecl()) { - 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); -} - -bool TBDGenVisitor::addClassMetadata(ClassDecl *CD) { - if (Opts.PublicSymbolsOnly && - getDeclLinkage(CD) != FormalLinkage::PublicUnique) - return false; - - 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); - recorder.addObjCInterface(CD); - } - } - - // 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)); - } - } - - return true; -} - -void TBDGenVisitor::visitClassDecl(ClassDecl *CD) { - if (!addClassMetadata(CD)) - return; - - // Emit dispatch thunks for every new vtable entry. - struct VTableVisitor : public SILVTableVisitor { - TBDGenVisitor &TBD; - ClassDecl *CD; - bool FirstTime = true; - APIRecorder &recorder; - - public: - VTableVisitor(TBDGenVisitor &TBD, ClassDecl *CD, APIRecorder &recorder) - : TBD(TBD), CD(CD), recorder(recorder) {} - - void addMethod(SILDeclRef method) { - assert(method.getDecl()->getDeclContext() == CD); - - if (TBD.Opts.VirtualFunctionElimination || 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, recorder).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)); - if (CD->hasAsync()) { - addAsyncFunctionPointerSymbol( - SILDeclRef(CD, SILDeclRef::Kind::Initializer)); - } - } - - visitAbstractFunctionDecl(CD); -} - -void TBDGenVisitor::visitDestructorDecl(DestructorDecl *DD) { - // Destructors come in two forms (deallocating and non-deallocating), like - // constructors above. Classes use both but move only non-class nominal types - // only use the deallocating one. This is the deallocating one: - visitAbstractFunctionDecl(DD); - - if (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 (auto CD = dyn_cast_or_null(ED->getImplementedObjCDecl())) { - // @_objcImplementation extensions generate the class metadata symbols. - (void)addClassMetadata(CD); - } - - if (!isa(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: - case DeclKind::MacroExpansion: - return false; - case DeclKind::BuiltinTuple: - llvm_unreachable("BuiltinTupleDecl should not show up here"); - } - llvm_unreachable("covered switch"); -} -#endif - -void TBDGenVisitor::visitProtocolDecl(ProtocolDecl *PD) { - if (!PD->isObjC() && !PD->isMarkerProtocol()) { - addSymbol(LinkEntity::forProtocolDescriptor(PD)); - - struct WitnessVisitor : public SILWitnessVisitor { - 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.Opts.WitnessMethodElimination) { - 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); + // FIXME: We should have a SILDeclRef SymbolSource for this. + addSymbol(Mangler.mangleWitnessThunk(C, requirementDecl), + SymbolSource::forUnknown()); } void TBDGenVisitor::addFirstFileSymbols() { @@ -1163,64 +463,24 @@ void TBDGenVisitor::addFirstFileSymbols() { } } -void TBDGenVisitor::addMainIfNecessary(FileUnit *file) { - // HACK: 'main' is a special symbol that's always emitted in SILGen if - // the file has an entry point. Since it doesn't show up in the - // module until SILGen, we need to explicitly add it here. - // - // Make sure to only add the main symbol for the module that we're emitting - // TBD for, and not for any statically linked libraries. - if (!file->hasEntryPoint() || file->getParentModule() != SwiftModule) - return; - - auto entryPointSymbol = - SwiftModule->getASTContext().getEntryPointFunctionName(); - - if (auto *decl = file->getMainDecl()) { - auto ref = SILDeclRef::getMainDeclEntryPoint(decl); - addSymbol(entryPointSymbol, SymbolSource::forSILDeclRef(ref)); - return; - } - - auto ref = SILDeclRef::getMainFileEntryPoint(file); - addSymbol(entryPointSymbol, SymbolSource::forSILDeclRef(ref)); -} - -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) { - SmallVector decls; - file->getTopLevelDecls(decls); - - addMainIfNecessary(file); +void TBDGenVisitor::visit(const TBDGenDescriptor &desc) { + SILSymbolVisitorOptions opts; + opts.VisitMembers = true; + opts.LinkerDirectivesOnly = Opts.LinkerDirectivesOnly; + opts.PublicSymbolsOnly = Opts.PublicSymbolsOnly; + opts.WitnessMethodElimination = Opts.WitnessMethodElimination; + opts.VirtualFunctionElimination = Opts.VirtualFunctionElimination; - for (auto d : decls) { - if (Opts.LinkerDirectivesOnly && !hasLinkerDirective(d)) - continue; - visit(d); - } -} + auto silVisitorCtx = SILSymbolVisitorContext(SwiftModule, opts); + auto visitorCtx = IRSymbolVisitorContext{UniversalLinkInfo, silVisitorCtx}; -void TBDGenVisitor::visit(const TBDGenDescriptor &desc) { // Add any autolinking force_load symbols. addFirstFileSymbols(); if (auto *singleFile = desc.getSingleFile()) { assert(SwiftModule == singleFile->getParentModule() && "mismatched file and module"); - visitFile(singleFile); - - // Visit synthesized file, if it exists. - if (auto *synthesizedFile = singleFile->getSynthesizedFile()) - visitFile(synthesizedFile); + visitFile(singleFile, visitorCtx); return; } @@ -1241,15 +501,7 @@ void TBDGenVisitor::visit(const TBDGenDescriptor &desc) { } // Collect symbols in each module. - llvm::for_each(Modules, [&](ModuleDecl *M) { - for (auto *file : M->getFiles()) { - visitFile(file); - - // Visit synthesized file, if it exists. - if (auto *synthesizedFile = file->getSynthesizedFile()) - visitFile(synthesizedFile); - } - }); + visitModules(Modules, visitorCtx); } /// The kind of version being parsed, used for diagnostics. @@ -1566,6 +818,8 @@ void swift::writeAPIJSONFile(ModuleDecl *M, llvm::raw_ostream &os, api.writeAPIJSONFile(os, PrettyPrint); } +/// NOTE: This is part of an incomplete experimental feature. There are +/// currently no clients that depend on its output. SymbolSourceMap SymbolSourceMapRequest::evaluate(Evaluator &evaluator, TBDGenDescriptor desc) const { using Map = SymbolSourceMap::Storage; diff --git a/lib/IRGen/TBDGenVisitor.h b/lib/IRGen/TBDGenVisitor.h index ef1e625706dbb..592edb0c043c8 100644 --- a/lib/IRGen/TBDGenVisitor.h +++ b/lib/IRGen/TBDGenVisitor.h @@ -17,16 +17,12 @@ #define SWIFT_TBDGEN_TBDGENVISITOR_H #include "swift/AST/ASTMangler.h" -#include "swift/AST/ASTVisitor.h" #include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" -#include "swift/AST/ParameterList.h" #include "swift/Basic/LLVM.h" +#include "swift/IRGen/IRSymbolVisitor.h" #include "swift/IRGen/Linking.h" -#include "swift/SIL/FormalLinkage.h" #include "swift/SIL/SILDeclRef.h" -#include "swift/SIL/SILWitnessTable.h" -#include "swift/SIL/TypeLowering.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/Triple.h" #include "llvm/TextAPI/InterfaceFile.h" @@ -87,7 +83,7 @@ class SimpleAPIRecorder final : public APIRecorder { SymbolCallbackFn func; }; -class TBDGenVisitor : public ASTVisitor { +class TBDGenVisitor : public IRSymbolVisitor { #ifndef NDEBUG /// Tracks the symbols emitted to ensure we don't emit any duplicates. llvm::StringSet<> DuplicateSymbolChecker; @@ -103,14 +99,6 @@ class TBDGenVisitor : public ASTVisitor { using SymbolKind = llvm::MachO::SymbolKind; - /// A set of original function and derivative configuration pairs for which - /// derivative symbols have been emitted. - /// - /// Used to deduplicate derivative symbol emission for `@differentiable` and - /// `@derivative` attributes. - llvm::DenseSet> - AddedDerivatives; - std::vector DeclStack; std::unique_ptr> previousInstallNameMap; @@ -123,54 +111,10 @@ class TBDGenVisitor : public ASTVisitor { void addSymbol(StringRef name, SymbolSource source, SymbolKind kind = SymbolKind::GlobalSymbol); - void addSymbol(SILDeclRef declRef); - void addAsyncFunctionPointerSymbol(SILDeclRef declRef); - void addSymbol(LinkEntity entity); bool addClassMetadata(ClassDecl *CD); - void addConformances(const IterableDeclContext *IDC); - - void addDispatchThunk(SILDeclRef declRef); - - void addMethodDescriptor(SILDeclRef declRef); - - void addProtocolRequirementsBaseDescriptor(ProtocolDecl *proto); - void addAssociatedTypeDescriptor(AssociatedTypeDecl *assocType); - void addAssociatedConformanceDescriptor(AssociatedConformance conformance); - void addBaseConformanceDescriptor(BaseConformance conformance); - - /// Adds the symbol for the linear map function of the given kind associated - /// with the given original function and derivative function configuration. - void addAutoDiffLinearMapFunction(AbstractFunctionDecl *original, - const AutoDiffConfig &config, - AutoDiffLinearMapKind kind); - - /// Adds the symbol for the autodiff function of the given kind associated - /// with the given original function, parameter indices, and derivative - /// generic signature. - void - addAutoDiffDerivativeFunction(AbstractFunctionDecl *original, - IndexSubset *parameterIndices, - GenericSignature derivativeGenericSignature, - AutoDiffDerivativeFunctionKind kind); - - /// Adds the symbol for the differentiability witness associated with the - /// given original function, AST parameter indices, result indices, and - /// derivative generic signature. - void addDifferentiabilityWitness(AbstractFunctionDecl *original, - DifferentiabilityKind kind, - IndexSubset *astParameterIndices, - IndexSubset *resultIndices, - GenericSignature derivativeGenericSignature); - - /// Adds symbols associated with the given original function and - /// derivative function configuration. - void addDerivativeConfiguration(DifferentiabilityKind diffKind, - AbstractFunctionDecl *original, - const AutoDiffConfig &config); - public: TBDGenVisitor(const llvm::Triple &target, const StringRef dataLayoutString, ModuleDecl *swiftModule, const TBDGenOptions &opts, @@ -187,51 +131,25 @@ class TBDGenVisitor : public ASTVisitor { ~TBDGenVisitor() { assert(DeclStack.empty()); } - /// Add the main symbol. - void addMainIfNecessary(FileUnit *file); - /// Adds the global symbols associated with the first file. void addFirstFileSymbols(); - void visitDefaultArguments(ValueDecl *VD, ParameterList *PL); - - void visitAbstractFunctionDecl(AbstractFunctionDecl *AFD); - - void visitAccessorDecl(AccessorDecl *AD); - - void visitNominalTypeDecl(NominalTypeDecl *NTD); - - void visitClassDecl(ClassDecl *CD); - - void visitConstructorDecl(ConstructorDecl *CD); - - void visitDestructorDecl(DestructorDecl *DD); - - void visitExtensionDecl(ExtensionDecl *ED); - - void visitFuncDecl(FuncDecl *FD); - - void visitProtocolDecl(ProtocolDecl *PD); - - void visitAbstractStorageDecl(AbstractStorageDecl *ASD); - - void visitVarDecl(VarDecl *VD); - - void visitSubscriptDecl(SubscriptDecl *SD); - - void visitEnumDecl(EnumDecl *ED); - - void visitEnumElementDecl(EnumElementDecl *EED); - - void visitDecl(Decl *D) {} + /// Visit the files specified by a given TBDGenDescriptor. + void visit(const TBDGenDescriptor &desc); - void visit(Decl *D); + // --- IRSymbolVisitor --- - /// Visit the symbols in a given file unit. - void visitFile(FileUnit *file); + void willVisitDecl(Decl *D) override; + void didVisitDecl(Decl *D) override; - /// Visit the files specified by a given TBDGenDescriptor. - void visit(const TBDGenDescriptor &desc); + void addFunction(SILDeclRef declRef) override; + void addFunction(StringRef name, SILDeclRef declRef) override; + void addGlobalVar(VarDecl *VD) override; + void addLinkEntity(LinkEntity entity) override; + void addObjCInterface(ClassDecl *CD) override; + void addObjCMethod(AbstractFunctionDecl *AFD) override; + void addProtocolWitnessThunk(RootProtocolConformance *C, + ValueDecl *requirementDecl) override; }; } // end namespace tbdgen } // end namespace swift diff --git a/lib/SIL/IR/CMakeLists.txt b/lib/SIL/IR/CMakeLists.txt index 6f8c9e8685661..00b599bcbe050 100644 --- a/lib/SIL/IR/CMakeLists.txt +++ b/lib/SIL/IR/CMakeLists.txt @@ -28,6 +28,7 @@ target_sources(swiftSIL PRIVATE SILPrinter.cpp SILProfiler.cpp SILSuccessor.cpp + SILSymbolVisitor.cpp SILType.cpp SILUndef.cpp SILVTable.cpp diff --git a/lib/SIL/IR/SILSymbolVisitor.cpp b/lib/SIL/IR/SILSymbolVisitor.cpp new file mode 100644 index 0000000000000..f5c7377451e2f --- /dev/null +++ b/lib/SIL/IR/SILSymbolVisitor.cpp @@ -0,0 +1,823 @@ +//===--- SILSymbolVisitor.cpp ---------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 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 liker symbol enumeration for SILSymbolVisitor. +// +//===----------------------------------------------------------------------===// + +#include "swift/SIL/SILSymbolVisitor.h" + +#include "swift/AST/ASTContext.h" +#include "swift/AST/ASTMangler.h" +#include "swift/AST/Decl.h" +#include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" +#include "swift/AST/ParameterList.h" +#include "swift/AST/PropertyWrappers.h" +#include "swift/AST/SynthesizedFileUnit.h" +#include "swift/SIL/FormalLinkage.h" +#include "swift/SIL/SILLinkage.h" +#include "swift/SIL/SILModule.h" +#include "swift/SIL/SILVTableVisitor.h" +#include "swift/SIL/SILWitnessTable.h" +#include "swift/SIL/SILWitnessVisitor.h" + +using namespace swift; + +static bool requiresLinkerDirective(Decl *D) { + for (auto *attr : D->getAttrs()) { + if (auto *ODA = dyn_cast(attr)) { + auto Active = ODA->isActivePlatform(D->getASTContext()); + if (Active.hasValue()) + return true; + } + } + return false; +} + +static bool isGlobalOrStaticVar(VarDecl *VD) { + return VD->isStatic() || VD->getDeclContext()->isModuleScopeContext(); +} + +using DynamicKind = SILSymbolVisitor::DynamicKind; + +static Optional getDynamicKind(ValueDecl *VD) { + if (VD->shouldUseNativeMethodReplacement()) + return DynamicKind::Replaceable; + + if (VD->getDynamicallyReplacedDecl()) + return DynamicKind::Replacement; + + return None; +} + +class SILSymbolVisitorImpl : public ASTVisitor { + SILSymbolVisitor &Visitor; + const SILSymbolVisitorContext &Ctx; + + /// A set of original function and derivative configuration pairs for which + /// derivative symbols have been emitted. + /// + /// Used to deduplicate derivative symbol emission for `@differentiable` and + /// `@derivative` attributes. + llvm::DenseSet> + AddedDerivatives; + + void addMainIfNecessary(FileUnit *file) { + // Make sure to only add the main symbol for the module that we're emitting + // TBD for, and not for any statically linked libraries. + if (!file->hasEntryPoint() || file->getParentModule() != Ctx.getModule()) + return; + + auto entryPointSymbol = + file->getParentModule()->getASTContext().getEntryPointFunctionName(); + + if (auto *decl = file->getMainDecl()) { + addFunction(SILDeclRef::getMainDeclEntryPoint(decl), + /*ignoreLinkage=*/true); + return; + } + + auto declRef = SILDeclRef::getMainFileEntryPoint(file); + Visitor.addFunction(entryPointSymbol, declRef); + } + + /// Emits the given `SILDeclRef` to the downstream visitor as long as the + /// entity has the required linkage. + /// + /// FIXME: The need for an ignoreLinkage flag here possibly indicates that + /// there is something broken about the linkage computation below. + void addFunction(SILDeclRef declRef, bool ignoreLinkage = false) { + if (!ignoreLinkage) { + auto linkage = effectiveLinkageForClassMember( + declRef.getLinkage(ForDefinition), declRef.getSubclassScope()); + if (Ctx.getOpts().PublicSymbolsOnly && linkage != SILLinkage::Public) + return; + } + + Visitor.addFunction(declRef); + } + + void addAsyncFunctionPointer(SILDeclRef declRef) { + auto silLinkage = effectiveLinkageForClassMember( + declRef.getLinkage(ForDefinition), declRef.getSubclassScope()); + if (Ctx.getOpts().PublicSymbolsOnly && silLinkage != SILLinkage::Public) + return; + + Visitor.addAsyncFunctionPointer(declRef); + } + + void addAutoDiffLinearMapFunction(AbstractFunctionDecl *original, + const 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 (Ctx.getOpts().PublicSymbolsOnly && !declRef.isSerialized()) + return; + + // Differential functions are emitted only when forward-mode is enabled. + if (kind == AutoDiffLinearMapKind::Differential && + !ctx.LangOpts.hasFeature(Feature::ForwardModeDifferentiation)) + return; + + auto *loweredParamIndices = autodiff::getLoweredParameterIndices( + config.parameterIndices, + original->getInterfaceType()->castTo()); + Mangle::ASTMangler mangler; + AutoDiffConfig silConfig{ + loweredParamIndices, config.resultIndices, + autodiff::getDifferentiabilityWitnessGenericSignature( + original->getGenericSignature(), + config.derivativeGenericSignature)}; + std::string linearMapName = + mangler.mangleAutoDiffLinearMap(original, kind, silConfig); + + // TODO: Can we encode a linear map function in a SILDeclRef instead of + // doing a bespoke mangling here? + Visitor.addFunction(linearMapName, declRef); + } + + void + 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)); + addFunction(declRef.asAutoDiffDerivativeFunction(assocFnId)); + } + + void addDifferentiabilityWitness( + AbstractFunctionDecl *original, DifferentiabilityKind kind, + 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 (Ctx.getOpts().PublicSymbolsOnly && + originalLinkage != SILLinkage::Public) + return; + + auto *silParamIndices = autodiff::getLoweredParameterIndices( + astParameterIndices, + original->getInterfaceType()->castTo()); + + auto originalMangledName = declRef.mangle(); + AutoDiffConfig config{ + silParamIndices, resultIndices, + autodiff::getDifferentiabilityWitnessGenericSignature( + original->getGenericSignature(), derivativeGenericSignature)}; + + Mangle::ASTMangler mangler; + auto mangledName = mangler.mangleSILDifferentiabilityWitness( + originalMangledName, kind, config); + + // TODO: Can we encode a differentiability witness function in a SILDeclRef + // instead of doing a bespoke mangling here? + Visitor.addFunction(mangledName, declRef); + } + + void addDerivativeConfiguration(DifferentiabilityKind diffKind, + AbstractFunctionDecl *original, + const 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, diffKind, config.parameterIndices, + config.resultIndices, + config.derivativeGenericSignature); + } + + void addOpaqueResultIfNecessary(ValueDecl *VD) { + if (auto opaqueResult = VD->getOpaqueResultTypeDecl()) { + Visitor.addOpaqueTypeDescriptor(opaqueResult); + assert(opaqueResult->getNamingDecl() == VD); + if (auto dynKind = getDynamicKind(VD)) { + Visitor.addOpaqueTypeDescriptorAccessor(opaqueResult, *dynKind); + } + } + } + + void addConformances(const IterableDeclContext *IDC) { + for (auto conformance : + IDC->getLocalConformances(ConformanceLookupKind::NonInherited)) { + auto protocol = conformance->getProtocol(); + if (Ctx.getOpts().PublicSymbolsOnly && + getDeclLinkage(protocol) != FormalLinkage::PublicUnique) + continue; + + 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; + } + + // 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)) + Visitor.addProtocolWitnessTable(rootConformance); + Visitor.addProtocolConformanceDescriptor(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 (Ctx.getOpts().PublicSymbolsOnly) { + if (!conformanceIsFixed) + return; + + if (!isa(rootConformance) && + !fixmeWitnessHasLinkageThatNeedsToBePublic(witnessRef)) { + return; + } + } + + Visitor.addProtocolWitnessThunk(rootConformance, requirementDecl); + }; + + rootConformance->forEachValueWitness([&](ValueDecl *valueReq, + Witness witness) { + auto witnessDecl = witness.getDecl(); + if (isa(valueReq)) { + addSymbolIfNecessary(valueReq, witnessDecl); + } else if (auto *storage = dyn_cast(valueReq)) { + if (auto witnessStorage = + dyn_cast(witnessDecl)) { + storage->visitOpaqueAccessors([&](AccessorDecl *reqtAccessor) { + auto witnessAccessor = witnessStorage->getSynthesizedAccessor( + reqtAccessor->getAccessorKind()); + addSymbolIfNecessary(reqtAccessor, witnessAccessor); + }); + } else if (isa(witnessDecl)) { + auto getter = storage->getSynthesizedAccessor(AccessorKind::Get); + addSymbolIfNecessary(getter, witnessDecl); + } + } + }); + } + } + + bool addClassMetadata(ClassDecl *CD) { + if (Ctx.getOpts().PublicSymbolsOnly && + getDeclLinkage(CD) != FormalLinkage::PublicUnique) + return false; + + auto &ctxt = CD->getASTContext(); + auto isGeneric = CD->isGenericContext(); + auto objCCompatible = ctxt.LangOpts.EnableObjCInterop && !isGeneric; + auto isObjC = objCCompatible && CD->isObjC(); + + // Metaclasses and ObjC classes (duh) are an 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; + Visitor.addObjCClass(CD); + } + + if (CD->getMetaclassKind() == ClassDecl::MetaclassKind::ObjC) { + addObjCClass = true; + Visitor.addObjCMetaclass(CD); + } else + Visitor.addSwiftMetaclassStub(CD); + + if (addObjCClass) { + Visitor.addObjCInterface(CD); + } + } + + // Some members of classes get extra handling, beyond members of + // struct/enums, so let's walk over them manually. + if (Ctx.getOpts().VisitMembers) + for (auto *var : CD->getStoredProperties()) + Visitor.addFieldOffset(var); + + visitNominalTypeDecl(CD); + + bool resilientAncestry = CD->checkAncestry(AncestryFlags::ResilientOther); + + // Types with resilient superclasses have some extra symbols. + if (resilientAncestry || CD->hasResilientMetadata()) + Visitor.addClassMetadataBaseOffset(CD); + + auto &Ctx = CD->getASTContext(); + if (Ctx.LangOpts.EnableObjCInterop && resilientAncestry) + Visitor.addObjCResilientClassStub(CD); + + return true; + } + +public: + SILSymbolVisitorImpl(SILSymbolVisitor &Visitor, + const SILSymbolVisitorContext &Ctx) + : Visitor{Visitor}, Ctx{Ctx} {} + + void visit(Decl *D) { + Visitor.willVisitDecl(D); + ASTVisitor::visit(D); + Visitor.didVisitDecl(D); + } + + void visit(FileUnit *file) { + auto visitFile = [this](FileUnit *file) { + SmallVector decls; + file->getTopLevelDecls(decls); + + addMainIfNecessary(file); + + for (auto D : decls) { + if (Ctx.getOpts().LinkerDirectivesOnly && !requiresLinkerDirective(D)) + continue; + + visit(D); + } + }; + + visitFile(file); + + // Visit synthesized file, if it exists. + if (auto *synthesizedFile = file->getSynthesizedFile()) + visitFile(synthesizedFile); + } + + void visitDefaultArguments(ValueDecl *VD, ParameterList *PL) { + auto moduleDecl = VD->getModuleContext(); + auto publicDefaultArgGenerators = moduleDecl->isTestingEnabled() || + moduleDecl->arePrivateImportsEnabled(); + if (Ctx.getOpts().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()) + addFunction(SILDeclRef::getDefaultArgGenerator(VD, index)); + ++index; + } + } + + void 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; + } + + // Add exported prespecialized symbols. + for (auto *attr : AFD->getAttrs().getAttributes()) { + if (!attr->isExported()) + continue; + + auto erasedSignature = attr->getSpecializedSignature().typeErased( + attr->getTypeErasedParams()); + + if (auto *targetFun = attr->getTargetFunctionDecl(AFD)) { + addFunction(SILDeclRef(targetFun, erasedSignature), + /*ignoreLinkage=*/true); + } else { + addFunction(SILDeclRef(AFD, erasedSignature), /*ignoreLinkage=*/true); + } + } + + addFunction(SILDeclRef(AFD)); + + if (auto dynKind = getDynamicKind(AFD)) { + // Add the global function pointer for a dynamically replaceable function. + Visitor.addDynamicFunction(AFD, *dynKind); + } + + if (AFD->getAttrs().hasAttribute()) { + // A @_cdecl("...") function has an extra symbol, with the name from the + // attribute. + addFunction(SILDeclRef(AFD).asForeign()); + } + + if (auto distributedThunk = AFD->getDistributedThunk()) { + auto thunk = SILDeclRef(distributedThunk).asDistributed(); + addFunction(thunk); + addAsyncFunctionPointer(thunk); + } + + // Add derivative function symbols. + for (const auto *differentiableAttr : + AFD->getAttrs().getAttributes()) + addDerivativeConfiguration( + differentiableAttr->getDifferentiabilityKind(), AFD, + AutoDiffConfig(differentiableAttr->getParameterIndices(), + IndexSubset::get(AFD->getASTContext(), 1, {0}), + differentiableAttr->getDerivativeGenericSignature())); + for (const auto *derivativeAttr : + AFD->getAttrs().getAttributes()) + addDerivativeConfiguration( + DifferentiabilityKind::Reverse, + derivativeAttr->getOriginalFunction(AFD->getASTContext()), + AutoDiffConfig(derivativeAttr->getParameterIndices(), + IndexSubset::get(AFD->getASTContext(), 1, {0}), + AFD->getGenericSignature())); + + visitDefaultArguments(AFD, AFD->getParameters()); + + if (AFD->hasAsync()) { + addAsyncFunctionPointer(SILDeclRef(AFD)); + } + + // Skip non objc compatible methods or non-public methods. + if (isa(AFD) || !AFD->isObjC() || + AFD->getFormalAccess() != AccessLevel::Public) + return; + Visitor.addObjCMethod(AFD); + } + + void visitFuncDecl(FuncDecl *FD) { + // If there's an opaque return type, its descriptor is exported. + addOpaqueResultIfNecessary(FD); + visitAbstractFunctionDecl(FD); + } + + void visitAccessorDecl(AccessorDecl *AD) { + llvm_unreachable("should not see an accessor here"); + } + + void visitAbstractStorageDecl(AbstractStorageDecl *ASD) { + // Add the property descriptor if the decl needs it. + if (ASD->exportsPropertyDescriptor()) { + Visitor.addPropertyDescriptor(ASD); + } + + // ...and the opaque result decl if it has one. + addOpaqueResultIfNecessary(ASD); + + // 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()) + addDerivativeConfiguration( + differentiableAttr->getDifferentiabilityKind(), + ASD->getOpaqueAccessor(AccessorKind::Get), + AutoDiffConfig(differentiableAttr->getParameterIndices(), + IndexSubset::get(ASD->getASTContext(), 1, {0}), + differentiableAttr->getDerivativeGenericSignature())); + } + + void 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 public. + addFunction(declRef); + } + + // Statically/globally stored variables have some special handling. + if (VD->hasStorage() && isGlobalOrStaticVar(VD)) { + if (!Ctx.getOpts().PublicSymbolsOnly || + getDeclLinkage(VD) == FormalLinkage::PublicUnique) { + Visitor.addGlobalVar(VD); + } + + if (VD->isLazilyInitializedGlobal()) + addFunction(SILDeclRef(VD, SILDeclRef::Kind::GlobalAccessor)); + } + + // Wrapped non-static member properties may have a backing initializer. + auto initInfo = VD->getPropertyWrapperInitializerInfo(); + if (initInfo.hasInitFromWrappedValue() && !VD->isStatic()) { + addFunction(SILDeclRef( + VD, SILDeclRef::Kind::PropertyWrapperBackingInitializer)); + } + } + + visitAbstractStorageDecl(VD); + } + + void visitSubscriptDecl(SubscriptDecl *SD) { + visitDefaultArguments(SD, SD->getIndices()); + visitAbstractStorageDecl(SD); + } + + void visitNominalTypeDecl(NominalTypeDecl *NTD) { + auto declaredType = NTD->getDeclaredType()->getCanonicalType(); + + if (!NTD->getObjCImplementationDecl()) { + Visitor.addNominalTypeDescriptor(NTD); + + // Generic types do not get metadata directly, only through the function. + if (!NTD->isGenericContext()) { + Visitor.addTypeMetadataAddress(declaredType); + } + } + Visitor.addTypeMetadataAccessFunction(declaredType); + + // There are symbols associated with any protocols this type conforms to. + addConformances(NTD); + + if (Ctx.getOpts().VisitMembers) + for (auto member : NTD->getMembers()) + visit(member); + } + + void visitClassDecl(ClassDecl *CD) { + if (!addClassMetadata(CD)) + return; + + // Emit dispatch thunks for every new vtable entry. + struct VTableVisitor : public SILVTableVisitor { + SILSymbolVisitor &Visitor; + ClassDecl *CD; + bool FirstTime = true; + bool VirtualFunctionElimination; + + public: + VTableVisitor(SILSymbolVisitorImpl &V, ClassDecl *CD) + : Visitor{V.Visitor}, CD{CD}, + VirtualFunctionElimination{ + V.Ctx.getOpts().VirtualFunctionElimination} {} + + void addMethod(SILDeclRef method) { + assert(method.getDecl()->getDeclContext() == CD); + + if (VirtualFunctionElimination || 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. + Visitor.addMethodLookupFunction(CD); + } + + Visitor.addDispatchThunk(method); + } + + Visitor.addMethodDescriptor(method); + } + + void addMethodOverride(SILDeclRef baseRef, SILDeclRef derivedRef) {} + + void addPlaceholder(MissingMemberDecl *) {} + + void doIt() { + addVTableEntries(CD); + } + }; + + if (Ctx.getOpts().VisitMembers) + VTableVisitor(*this, CD).doIt(); + } + + void 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. + addFunction(SILDeclRef(CD, SILDeclRef::Kind::Initializer)); + if (CD->hasAsync()) { + addAsyncFunctionPointer(SILDeclRef(CD, SILDeclRef::Kind::Initializer)); + } + } + + visitAbstractFunctionDecl(CD); + } + + void visitDestructorDecl(DestructorDecl *DD) { + // Destructors come in two forms (deallocating and non-deallocating), like + // constructors above. Classes use both but move only non-class nominal + // types only use the deallocating one. This is the deallocating one: + visitAbstractFunctionDecl(DD); + + if (auto parentClass = DD->getParent()->getSelfClassDecl()) { + // But the non-deallocating one doesn't apply to some @objc classes. + if (!Lowering::usesObjCAllocator(parentClass)) { + addFunction(SILDeclRef(DD, SILDeclRef::Kind::Destroyer)); + } + } + } + + void visitExtensionDecl(ExtensionDecl *ED) { + if (auto CD = dyn_cast_or_null(ED->getImplementedObjCDecl())) { + // @_objcImplementation extensions generate the class metadata symbols. + (void)addClassMetadata(CD); + } + + if (!isa(ED->getExtendedNominal())) { + addConformances(ED); + } + + if (Ctx.getOpts().VisitMembers) + for (auto member : ED->getMembers()) + visit(member); + } + +#ifndef NDEBUG + static bool isExpectedProtocolMember(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: + case DeclKind::MacroExpansion: + return false; + case DeclKind::BuiltinTuple: + llvm_unreachable("BuiltinTupleDecl should not show up here"); + } + llvm_unreachable("covered switch"); + } +#endif + + void visitProtocolDecl(ProtocolDecl *PD) { + if (!PD->isObjC() && !PD->isMarkerProtocol()) { + Visitor.addProtocolDescriptor(PD); + + struct WitnessVisitor : public SILWitnessVisitor { + SILSymbolVisitor &Visitor; + ProtocolDecl *PD; + bool Resilient; + bool WitnessMethodElimination; + + public: + WitnessVisitor(SILSymbolVisitorImpl &V, ProtocolDecl *PD) + : Visitor{V.Visitor}, PD{PD}, + Resilient{PD->getParentModule()->isResilient()}, + WitnessMethodElimination{ + V.Ctx.getOpts().WitnessMethodElimination} {} + + void addMethod(SILDeclRef declRef) { + if (Resilient || WitnessMethodElimination) { + Visitor.addDispatchThunk(declRef); + Visitor.addMethodDescriptor(declRef); + } + } + + void addAssociatedType(AssociatedType associatedType) { + Visitor.addAssociatedTypeDescriptor(associatedType.getAssociation()); + } + + void addProtocolConformanceDescriptor() { + Visitor.addProtocolRequirementsBaseDescriptor(PD); + } + + void addOutOfLineBaseProtocol(ProtocolDecl *proto) { + Visitor.addBaseConformanceDescriptor(BaseConformance(PD, proto)); + } + + void addAssociatedConformance(AssociatedConformance associatedConf) { + Visitor.addAssociatedConformanceDescriptor(associatedConf); + } + + void addPlaceholder(MissingMemberDecl *decl) {} + + void doIt() { + visitProtocolDecl(PD); + } + }; + + WitnessVisitor(*this, PD).doIt(); + + // Include the self-conformance. + addConformances(PD); + } + +#ifndef NDEBUG + // There are currently no symbols associated with the members of a protocol; + // 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(isExpectedProtocolMember(member) && + "unexpected member of protocol during TBD generation"); + } +#endif + } + + void visitEnumDecl(EnumDecl *ED) { + visitNominalTypeDecl(ED); + } + + void visitEnumElementDecl(EnumElementDecl *EED) { + if (EED->getParentEnum()->isResilient()) + Visitor.addEnumCase(EED); + + if (auto *PL = EED->getParameterList()) + visitDefaultArguments(EED, PL); + } + +#define UNINTERESTING_DECL(CLASS) \ + void visit##CLASS##Decl(CLASS##Decl *) {} + + UNINTERESTING_DECL(EnumCase) + UNINTERESTING_DECL(IfConfig) + UNINTERESTING_DECL(Import) + UNINTERESTING_DECL(MacroExpansion) + UNINTERESTING_DECL(MissingMember) + UNINTERESTING_DECL(Operator) + UNINTERESTING_DECL(PatternBinding) + UNINTERESTING_DECL(PoundDiagnostic) + UNINTERESTING_DECL(PrecedenceGroup) + UNINTERESTING_DECL(TopLevelCode) + UNINTERESTING_DECL(Value) + +#undef UNINTERESTING_DECL +}; + +void SILSymbolVisitor::visitDecl(Decl *D, const SILSymbolVisitorContext &ctx) { + SILSymbolVisitorImpl(*this, ctx).visit(D); +} + +void SILSymbolVisitor::visitFile(FileUnit *file, + const SILSymbolVisitorContext &ctx) { + SILSymbolVisitorImpl(*this, ctx).visit(file); +} + +void SILSymbolVisitor::visitModules(llvm::SmallVector &modules, + const SILSymbolVisitorContext &ctx) { + auto impl = SILSymbolVisitorImpl(*this, ctx); + for (auto *M : modules) { + for (auto *file : M->getFiles()) { + impl.visit(file); + } + } +} diff --git a/test/Serialization/load-file-permissions.swift b/test/Serialization/load-file-permissions.swift index d8643080b36d0..a7e25aa52054f 100644 --- a/test/Serialization/load-file-permissions.swift +++ b/test/Serialization/load-file-permissions.swift @@ -1,3 +1,4 @@ +// RUN: chmod a+rx %t/bad 2>/dev/null || true // RUN: %empty-directory(%t) // RUN: %empty-directory(%t/good) // RUN: %empty-directory(%t/bad)