diff --git a/include/swift/SIL/SILModule.h b/include/swift/SIL/SILModule.h index 1525fbd1c86..5d6d93a3141 100644 --- a/include/swift/SIL/SILModule.h +++ b/include/swift/SIL/SILModule.h @@ -294,6 +294,12 @@ public: bool linkFunction(SILFunction *Fun, LinkingMode LinkAll=LinkingMode::LinkNormal); + /// Link in all Witness Tables in the module. + void linkAllWitnessTables(); + + /// Link in all VTables in the module. + void linkAllVTables(); + /// \brief Return the declaration of a utility function that can, /// but needn't, be shared between modules. SILFunction *getOrCreateSharedFunction(SILLocation loc, diff --git a/lib/SIL/SILModule.cpp b/lib/SIL/SILModule.cpp index db3e7565e1a..2bc74963172 100644 --- a/lib/SIL/SILModule.cpp +++ b/lib/SIL/SILModule.cpp @@ -340,12 +340,14 @@ public: if (Mode == LinkingMode::LinkNone) return false; - auto NewFn = Loader->lookupSILFunction(F); + // If F is a declaration, first deserialize it. + auto NewFn = F->isExternalDeclaration() ? Loader->lookupSILFunction(F) : F; if (!NewFn || NewFn->empty()) return false; ++NumFuncLinked; + // Transitively deserialize everything referenced by NewFn. Worklist.push_back(NewFn); while (!Worklist.empty()) { auto Fn = Worklist.pop_back_val(); @@ -448,3 +450,11 @@ private: bool SILModule::linkFunction(SILFunction *Fun, SILModule::LinkingMode Mode) { return SILLinkerVisitor(SILLoader, Mode, ExternalSource).process(Fun); } + +void SILModule::linkAllWitnessTables() { + SILLoader->getAllWitnessTables(); +} + +void SILModule::linkAllVTables() { + SILLoader->getAllVTables(); +} diff --git a/lib/SILPasses/Link.cpp b/lib/SILPasses/Link.cpp index 28d66fa2536..7719e353074 100644 --- a/lib/SILPasses/Link.cpp +++ b/lib/SILPasses/Link.cpp @@ -21,126 +21,21 @@ using namespace swift; -STATISTIC(NumFuncLinked, "Number of SIL functions linked"); - -namespace { - class Callback : public SerializedSILLoader::Callback { - void didDeserialize(Module *M, SILFunction *fn) override { - updateLinkage(fn); - } - - void didDeserialize(Module *M, SILGlobalVariable *var) override { - updateLinkage(var); - } - - void didDeserialize(Module *M, SILVTable *vtable) override { - // TODO: should vtables get linkage? - //updateLinkage(vtable); - } - - template void updateLinkage(T *decl) { - switch (decl->getLinkage()) { - case SILLinkage::Public: - decl->setLinkage(SILLinkage::PublicExternal); - return; - case SILLinkage::Hidden: - decl->setLinkage(SILLinkage::HiddenExternal); - return; - case SILLinkage::Shared: - decl->setLinkage(SILLinkage::Shared); - return; - case SILLinkage::Private: // ? - case SILLinkage::PublicExternal: - case SILLinkage::HiddenExternal: - return; - } - } - }; -} - //===----------------------------------------------------------------------===// // Top Level Driver //===----------------------------------------------------------------------===// void swift::performSILLinking(SILModule *M, bool LinkAll) { - Callback callback; - SerializedSILLoader *SILLoader = SerializedSILLoader::create( - M->getASTContext(), M, &callback); - - SILExternalSource *ExternalSource = M->getExternalSource(); - - SmallVector Worklist; + auto LinkMode = LinkAll? SILModule::LinkingMode::LinkAll : + SILModule::LinkingMode::LinkNormal; for (auto &Fn : *M) - Worklist.push_back(&Fn); + M->linkFunction(&Fn, LinkMode); - while (!Worklist.empty()) { - auto Fn = Worklist.pop_back_val(); + if (!LinkAll) + return; - for (auto &BB : *Fn) { - for (auto I = BB.begin(), E = BB.end(); I != E; I++) { - SILFunction *CalleeFunction = nullptr; - bool TryLinking = false; - if (ApplyInst *AI = dyn_cast(I)) { - SILValue Callee = AI->getCallee(); - // Handles FunctionRefInst only. - if (FunctionRefInst *FRI = dyn_cast(Callee.getDef())) { - CalleeFunction = FRI->getReferencedFunction(); - // When EnableLinkAll is true, we always link the Callee. - TryLinking = LinkAll || AI->isTransparent() || - CalleeFunction->getLinkage() == SILLinkage::Shared; - } - } - else if (PartialApplyInst *PAI = dyn_cast(I)) { - SILValue Callee = PAI->getCallee(); - // Handles FunctionRefInst only. - if (FunctionRefInst *FRI = dyn_cast(Callee.getDef())) { - CalleeFunction = FRI->getReferencedFunction(); - // When EnableLinkAll is true, we always link the Callee. - TryLinking = LinkAll || CalleeFunction->isTransparent() || - CalleeFunction->getLinkage() == SILLinkage::Shared; - } else { - continue; - } - } - else if (FunctionRefInst *FRI = dyn_cast(I)) { - // When EnableLinkAll is true, we link the function referenced by - // FunctionRefInst. - CalleeFunction = LinkAll ? FRI->getReferencedFunction() : - nullptr; - TryLinking = LinkAll; - } - - if (!CalleeFunction) - continue; - - // The ExternalSource may wish to rewrite non-empty bodies. - if (ExternalSource) { - if (auto NewFn = ExternalSource->lookupSILFunction(CalleeFunction)) { - Worklist.push_back(NewFn); - ++NumFuncLinked; - continue; - } - } - - CalleeFunction->setBare(IsBare); - - if (CalleeFunction->empty()) { - // Try to find the definition in a serialized module when callee is - // currently empty. - if (TryLinking) { - if (auto NewFn = SILLoader->lookupSILFunction(CalleeFunction)) { - Worklist.push_back(NewFn); - ++NumFuncLinked; - continue; - } - } - } - } - } - } - - if (LinkAll) { - SILLoader->getAllVTables(); - SILLoader->getAllWitnessTables(); - } + M->linkAllWitnessTables(); + M->linkAllVTables(); } + + diff --git a/test/Serialization/Inputs/def_basic.sil b/test/Serialization/Inputs/def_basic.sil index bd677f7289a..25c1c225cea 100644 --- a/test/Serialization/Inputs/def_basic.sil +++ b/test/Serialization/Inputs/def_basic.sil @@ -1024,7 +1024,7 @@ bb0(%0 : $*ConformingAssoc): return %3 : $() } -// CHECK-LABEL: sil_witness_table ConformingAssoc: AssocReqt module +// CHECK-LABEL: sil_witness_table public_external ConformingAssoc: AssocReqt module // CHECK: #AssocReqt.requiredMethod!1: @_TTWV14witness_tables15ConformingAssocS_9AssocReqtS_FS1_14requiredMethodU_fRQPS1_FT_T_ // CHECK: } sil_witness_table ConformingAssoc: AssocReqt module def_basic { @@ -1050,14 +1050,14 @@ struct InheritedConformance : InheritedProtocol1 { func inheritedMethod() } -// CHECK-LABEL: sil_witness_table InheritedConformance: InheritedProtocol1 module +// CHECK-LABEL: sil_witness_table public_external InheritedConformance: InheritedProtocol1 module // CHECK: base_protocol AnyProtocol: InheritedConformance: AnyProtocol module // CHECK: } sil_witness_table InheritedConformance: InheritedProtocol1 module witness_tables { base_protocol AnyProtocol: InheritedConformance: AnyProtocol module witness_tables } -// CHECK-LABEL: sil_witness_table InheritedConformance: AnyProtocol module +// CHECK-LABEL: sil_witness_table public_external InheritedConformance: AnyProtocol module // CHECK: associated_type AssocType: SomeAssoc // CHECK: associated_type_protocol (AssocWithReqt: AssocReqt): ConformingAssoc: AssocReqt module // CHECK: }