From cea401e58a5887201de799c8d78ef50713d87b98 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Fri, 20 Jul 2018 18:31:50 +0000 Subject: [PATCH] [ORC] Replace SymbolResolvers in the new ORC layers with search orders on VSOs. A search order is a list of VSOs to be searched linearly to find symbols. Each VSO now has a search order that will be used when fixing up definitions in that VSO. Each VSO's search order defaults to just that VSO itself. This is a first step towards removing symbol resolvers from ORC altogether. In practice symbol resolvers tended to be used to implement a search order anyway, sometimes with additional programatic generation of symbols. Now that VSOs support programmatic generation of definitions via fallback generators, search orders provide a cleaner way to achieve the desired effect (while removing a lot of boilerplate). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@337593 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Orc/CompileOnDemandLayer.h | 16 +-- include/llvm/ExecutionEngine/Orc/Core.h | 115 +++++++----------- include/llvm/ExecutionEngine/Orc/LLJIT.h | 12 +- include/llvm/ExecutionEngine/Orc/Legacy.h | 68 +++++++++++ .../llvm/ExecutionEngine/Orc/NullResolver.h | 2 +- .../Orc/RTDyldObjectLinkingLayer.h | 12 +- .../Orc/CompileOnDemandLayer.cpp | 63 +++------- lib/ExecutionEngine/Orc/Core.cpp | 48 +++++++- lib/ExecutionEngine/Orc/LLJIT.cpp | 47 +------ lib/ExecutionEngine/Orc/Legacy.cpp | 2 + .../Orc/RTDyldObjectLinkingLayer.cpp | 85 +++++++++++-- .../ExecutionEngine/Orc/CoreAPIsTest.cpp | 101 +-------------- .../Orc/LegacyAPIInteropTest.cpp | 61 ++++++++++ .../ExecutionEngine/Orc/OrcTestCommon.cpp | 5 + unittests/ExecutionEngine/Orc/OrcTestCommon.h | 42 ++++++- 15 files changed, 376 insertions(+), 303 deletions(-) diff --git a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h index 0b5bddf8da9..3a720952df7 100644 --- a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h +++ b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h @@ -23,6 +23,7 @@ #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" #include "llvm/ExecutionEngine/Orc/LambdaResolver.h" #include "llvm/ExecutionEngine/Orc/Layer.h" +#include "llvm/ExecutionEngine/Orc/Legacy.h" #include "llvm/ExecutionEngine/Orc/OrcError.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/IR/Attributes.h" @@ -67,21 +68,11 @@ public: using IndirectStubsManagerBuilder = std::function()>; - /// Retrieve symbol resolver for the given VModuleKey. - using GetSymbolResolverFunction = - std::function(VModuleKey K)>; - - /// Set the symbol resolver for the given VModuleKey. - using SetSymbolResolverFunction = - std::function R)>; - using GetAvailableContextFunction = std::function; CompileOnDemandLayer2(ExecutionSession &ES, IRLayer &BaseLayer, JITCompileCallbackManager &CCMgr, IndirectStubsManagerBuilder BuildIndirectStubsManager, - GetSymbolResolverFunction GetSymbolResolver, - SetSymbolResolverFunction SetSymbolResolver, GetAvailableContextFunction GetAvailableContext); Error add(VSO &V, VModuleKey K, std::unique_ptr M) override; @@ -96,8 +87,7 @@ private: IndirectStubsManager &getStubsManager(const VSO &V); void emitExtractedFunctionsModule(MaterializationResponsibility R, - std::unique_ptr M, - std::shared_ptr Resolver); + std::unique_ptr M); mutable std::mutex CODLayerMutex; @@ -105,8 +95,6 @@ private: JITCompileCallbackManager &CCMgr; IndirectStubsManagerBuilder BuildIndirectStubsManager; StubManagersMap StubsMgrs; - GetSymbolResolverFunction GetSymbolResolver; - SetSymbolResolverFunction SetSymbolResolver; GetAvailableContextFunction GetAvailableContext; }; diff --git a/include/llvm/ExecutionEngine/Orc/Core.h b/include/llvm/ExecutionEngine/Orc/Core.h index 7df59641f8e..5894525e0eb 100644 --- a/include/llvm/ExecutionEngine/Orc/Core.h +++ b/include/llvm/ExecutionEngine/Orc/Core.h @@ -66,6 +66,11 @@ using SymbolDependenceMap = std::map; /// Render a SymbolDependendeMap. raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps); +/// A list of VSO pointers. +using VSOList = std::vector; + +raw_ostream &operator<<(raw_ostream &OS, const VSOList &VSOs); + /// Used to notify a VSO that the given set of symbols failed to materialize. class FailedToMaterialize : public ErrorInfo { public: @@ -471,74 +476,6 @@ private: size_t NotYetReadyCount; }; -/// SymbolResolver is a composable interface for looking up symbol flags -/// and addresses using the AsynchronousSymbolQuery type. It will -/// eventually replace the LegacyJITSymbolResolver interface as the -/// stardard ORC symbol resolver type. -/// -/// FIXME: SymbolResolvers should go away and be replaced with VSOs with -/// defenition generators. -class SymbolResolver { -public: - virtual ~SymbolResolver() = default; - - /// Returns the flags for each symbol in Symbols that can be found, - /// along with the set of symbol that could not be found. - virtual SymbolNameSet lookupFlags(SymbolFlagsMap &Flags, - const SymbolNameSet &Symbols) = 0; - - /// For each symbol in Symbols that can be found, assigns that symbols - /// value in Query. Returns the set of symbols that could not be found. - virtual SymbolNameSet lookup(std::shared_ptr Query, - SymbolNameSet Symbols) = 0; - -private: - virtual void anchor(); -}; - -/// Implements SymbolResolver with a pair of supplied function objects -/// for convenience. See createSymbolResolver. -template -class LambdaSymbolResolver final : public SymbolResolver { -public: - template - LambdaSymbolResolver(LookupFlagsFnRef &&LookupFlags, LookupFnRef &&Lookup) - : LookupFlags(std::forward(LookupFlags)), - Lookup(std::forward(Lookup)) {} - - SymbolNameSet lookupFlags(SymbolFlagsMap &Flags, - const SymbolNameSet &Symbols) final { - return LookupFlags(Flags, Symbols); - } - - SymbolNameSet lookup(std::shared_ptr Query, - SymbolNameSet Symbols) final { - return Lookup(std::move(Query), std::move(Symbols)); - } - -private: - LookupFlagsFn LookupFlags; - LookupFn Lookup; -}; - -/// Creates a SymbolResolver implementation from the pair of supplied -/// function objects. -template -std::unique_ptr::type>::type, - typename std::remove_cv< - typename std::remove_reference::type>::type>> -createSymbolResolver(LookupFlagsFn &&LookupFlags, LookupFn &&Lookup) { - using LambdaSymbolResolverImpl = LambdaSymbolResolver< - typename std::remove_cv< - typename std::remove_reference::type>::type, - typename std::remove_cv< - typename std::remove_reference::type>::type>; - return llvm::make_unique( - std::forward(LookupFlags), std::forward(Lookup)); -} - /// A symbol table that supports asynchoronous symbol queries. /// /// Represents a virtual shared object. Instances can not be copied or moved, so @@ -578,6 +515,42 @@ public: this->FallbackDefinitionGenerator = std::move(FallbackDefinitionGenerator); } + /// Set the search order to be used when fixing up definitions in VSO. + /// This will replace the previous search order, and apply to any symbol + /// resolutions made for definitions in this VSO after the call to + /// setSearchOrder (even if the definition itself was added before the + /// call). + /// + /// If SearchThisVSOFirst is set, which by default it is, then this VSO will + /// add itself to the beginning of the SearchOrder (Clients should *not* + /// put this VSO in the list in this case, to avoid redundant lookups). + /// + /// If SearchThisVSOFirst is false then the search order will be used as + /// given. The main motivation for this feature is to support deliberate + /// shadowing of symbols in this VSO by a facade VSO. For example, the + /// facade may resolve function names to stubs, and the stubs may compile + /// lazily by looking up symbols in this dylib. Adding the facade dylib + /// as the first in the search order (instead of this dylib) ensures that + /// definitions within this dylib resolve to the lazy-compiling stubs, + /// rather than immediately materializing the definitions in this dylib. + void setSearchOrder(VSOList NewSearchOrder, bool SearchThisVSOFirst = true); + + /// Add the given VSO to the search order for definitions in this VSO. + void addToSearchOrder(VSO &V); + + /// Replace OldV with NewV in the search order if OldV is present. Otherwise + /// this operation is a no-op. + void replaceInSearchOrder(VSO &OldV, VSO &NewV); + + /// Remove the given VSO from the search order for this VSO if it is + /// present. Otherwise this operation is a no-op. + void removeFromSearchOrder(VSO &V); + + /// Do something with the search order (run under the session lock). + template void withSearchOrderDo(Func F) { + ES.runSessionLocked([&]() { F(SearchOrder); }); + } + /// Define all symbols provided by the materialization unit to be part /// of the given VSO. template @@ -649,8 +622,7 @@ private: LLVM_MARK_AS_BITMASK_ENUM(NotifyFullyReady) }; - VSO(ExecutionSessionBase &ES, std::string Name) - : ES(ES), VSOName(std::move(Name)) {} + VSO(ExecutionSessionBase &ES, std::string Name); Error defineImpl(MaterializationUnit &MU); @@ -692,6 +664,7 @@ private: UnmaterializedInfosMap UnmaterializedInfos; MaterializingInfosMap MaterializingInfos; FallbackDefinitionGeneratorFunction FallbackDefinitionGenerator; + VSOList SearchOrder; // FIXME: Remove this (and runOutstandingMUs) once the linking layer works // with callbacks from asynchronous queries. @@ -729,8 +702,6 @@ Expected blockingLookup(ExecutionSessionBase &ES, SymbolNameSet Names, bool WaiUntilReady, MaterializationResponsibility *MR = nullptr); -using VSOList = std::vector; - /// Look up the given names in the given VSOs. /// VSOs will be searched in order and no VSO pointer may be null. /// All symbols must be found within the given VSOs or an error diff --git a/include/llvm/ExecutionEngine/Orc/LLJIT.h b/include/llvm/ExecutionEngine/Orc/LLJIT.h index 8d764c3eab1..df655bd8200 100644 --- a/include/llvm/ExecutionEngine/Orc/LLJIT.h +++ b/include/llvm/ExecutionEngine/Orc/LLJIT.h @@ -81,13 +81,10 @@ protected: LLJIT(std::unique_ptr ES, std::unique_ptr TM, DataLayout DL); - std::shared_ptr takeSymbolResolver(VModuleKey K); - RTDyldObjectLinkingLayer2::Resources getRTDyldResources(VModuleKey K); + std::shared_ptr getMemoryManager(VModuleKey K); std::string mangle(StringRef UnmangledName); - std::unique_ptr createResolverFor(VSO &V); - Error applyDataLayout(Module &M); void recordCtorDtors(Module &M); @@ -98,12 +95,9 @@ protected: std::unique_ptr TM; DataLayout DL; - std::map VSOLookupOrder; - RTDyldObjectLinkingLayer2 ObjLinkingLayer; IRCompileLayer2 CompileLayer; - std::map> Resolvers; CtorDtorRunner2 CtorRunner, DtorRunner; }; @@ -136,10 +130,6 @@ private: std::unique_ptr CCMgr, std::function()> ISMBuilder); - std::shared_ptr getSymbolResolver(VModuleKey K); - - void setSymbolResolver(VModuleKey K, std::shared_ptr R); - std::unique_ptr CCMgr; std::function()> ISMBuilder; diff --git a/include/llvm/ExecutionEngine/Orc/Legacy.h b/include/llvm/ExecutionEngine/Orc/Legacy.h index 343daa48432..d5ece3e5a7f 100644 --- a/include/llvm/ExecutionEngine/Orc/Legacy.h +++ b/include/llvm/ExecutionEngine/Orc/Legacy.h @@ -20,6 +20,74 @@ namespace llvm { namespace orc { +/// SymbolResolver is a composable interface for looking up symbol flags +/// and addresses using the AsynchronousSymbolQuery type. It will +/// eventually replace the LegacyJITSymbolResolver interface as the +/// stardard ORC symbol resolver type. +/// +/// FIXME: SymbolResolvers should go away and be replaced with VSOs with +/// defenition generators. +class SymbolResolver { +public: + virtual ~SymbolResolver() = default; + + /// Returns the flags for each symbol in Symbols that can be found, + /// along with the set of symbol that could not be found. + virtual SymbolNameSet lookupFlags(SymbolFlagsMap &Flags, + const SymbolNameSet &Symbols) = 0; + + /// For each symbol in Symbols that can be found, assigns that symbols + /// value in Query. Returns the set of symbols that could not be found. + virtual SymbolNameSet lookup(std::shared_ptr Query, + SymbolNameSet Symbols) = 0; + +private: + virtual void anchor(); +}; + +/// Implements SymbolResolver with a pair of supplied function objects +/// for convenience. See createSymbolResolver. +template +class LambdaSymbolResolver final : public SymbolResolver { +public: + template + LambdaSymbolResolver(LookupFlagsFnRef &&LookupFlags, LookupFnRef &&Lookup) + : LookupFlags(std::forward(LookupFlags)), + Lookup(std::forward(Lookup)) {} + + SymbolNameSet lookupFlags(SymbolFlagsMap &Flags, + const SymbolNameSet &Symbols) final { + return LookupFlags(Flags, Symbols); + } + + SymbolNameSet lookup(std::shared_ptr Query, + SymbolNameSet Symbols) final { + return Lookup(std::move(Query), std::move(Symbols)); + } + +private: + LookupFlagsFn LookupFlags; + LookupFn Lookup; +}; + +/// Creates a SymbolResolver implementation from the pair of supplied +/// function objects. +template +std::unique_ptr::type>::type, + typename std::remove_cv< + typename std::remove_reference::type>::type>> +createSymbolResolver(LookupFlagsFn &&LookupFlags, LookupFn &&Lookup) { + using LambdaSymbolResolverImpl = LambdaSymbolResolver< + typename std::remove_cv< + typename std::remove_reference::type>::type, + typename std::remove_cv< + typename std::remove_reference::type>::type>; + return llvm::make_unique( + std::forward(LookupFlags), std::forward(Lookup)); +} + class JITSymbolResolverAdapter : public JITSymbolResolver { public: JITSymbolResolverAdapter(ExecutionSession &ES, SymbolResolver &R, diff --git a/include/llvm/ExecutionEngine/Orc/NullResolver.h b/include/llvm/ExecutionEngine/Orc/NullResolver.h index eba9b95952a..bfb9931df14 100644 --- a/include/llvm/ExecutionEngine/Orc/NullResolver.h +++ b/include/llvm/ExecutionEngine/Orc/NullResolver.h @@ -15,7 +15,7 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_NULLRESOLVER_H #define LLVM_EXECUTIONENGINE_ORC_NULLRESOLVER_H -#include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/ExecutionEngine/Orc/Legacy.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" namespace llvm { diff --git a/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h b/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h index 84ceea40be0..48b3f7a58ed 100644 --- a/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h +++ b/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h @@ -46,17 +46,13 @@ public: /// Functor for receiving finalization notifications. using NotifyFinalizedFunction = std::function; - struct Resources { - std::shared_ptr MemMgr; - std::shared_ptr Resolver; - }; - - using ResourcesGetterFunction = std::function; + using GetMemoryManagerFunction = + std::function(VModuleKey)>; /// Construct an ObjectLinkingLayer with the given NotifyLoaded, /// and NotifyFinalized functors. RTDyldObjectLinkingLayer2( - ExecutionSession &ES, ResourcesGetterFunction GetResources, + ExecutionSession &ES, GetMemoryManagerFunction GetMemoryManager, NotifyLoadedFunction NotifyLoaded = NotifyLoadedFunction(), NotifyFinalizedFunction NotifyFinalized = NotifyFinalizedFunction()); @@ -81,7 +77,7 @@ public: private: mutable std::mutex RTDyldLayerMutex; - ResourcesGetterFunction GetResources; + GetMemoryManagerFunction GetMemoryManager; NotifyLoadedFunction NotifyLoaded; NotifyFinalizedFunction NotifyFinalized; bool ProcessAllSections; diff --git a/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp b/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp index ebd8d43e710..d42e7b05ba6 100644 --- a/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp +++ b/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp @@ -130,21 +130,18 @@ namespace orc { class ExtractingIRMaterializationUnit : public IRMaterializationUnit { public: - ExtractingIRMaterializationUnit( - ExecutionSession &ES, CompileOnDemandLayer2 &Parent, - std::unique_ptr M, - std::shared_ptr BackingResolver) - : IRMaterializationUnit(ES, std::move(M)), Parent(Parent), - BackingResolver(std::move(BackingResolver)) {} - - ExtractingIRMaterializationUnit( - std::unique_ptr M, SymbolFlagsMap SymbolFlags, - SymbolNameToDefinitionMap SymbolToDefinition, - CompileOnDemandLayer2 &Parent, - std::shared_ptr BackingResolver) + ExtractingIRMaterializationUnit(ExecutionSession &ES, + CompileOnDemandLayer2 &Parent, + std::unique_ptr M) + : IRMaterializationUnit(ES, std::move(M)), Parent(Parent) {} + + ExtractingIRMaterializationUnit(std::unique_ptr M, + SymbolFlagsMap SymbolFlags, + SymbolNameToDefinitionMap SymbolToDefinition, + CompileOnDemandLayer2 &Parent) : IRMaterializationUnit(std::move(M), std::move(SymbolFlags), std::move(SymbolToDefinition)), - Parent(Parent), BackingResolver(std::move(BackingResolver)) {} + Parent(Parent) {} private: void materialize(MaterializationResponsibility R) override { @@ -153,10 +150,6 @@ private: // together. This could be used, for example, to provide a specific // memory manager instance to the linking layer. - // FIXME: The derived constructor should *only* look for the names of - // original function definitions in the target VSO. All other - // symbols should be looked up in the backing resolver. - auto RequestedSymbols = R.getRequestedSymbols(); // Extract the requested functions into a new module. @@ -201,12 +194,12 @@ private: "of entries"); R.replace(llvm::make_unique( std::move(M), std::move(DelegatedSymbolFlags), - std::move(DelegatedSymbolToDefinition), Parent, BackingResolver)); + std::move(DelegatedSymbolToDefinition), Parent)); } if (ExtractedFunctionsModule) - Parent.emitExtractedFunctionsModule( - std::move(R), std::move(ExtractedFunctionsModule), BackingResolver); + Parent.emitExtractedFunctionsModule(std::move(R), + std::move(ExtractedFunctionsModule)); } void discard(const VSO &V, SymbolStringPtr Name) override { @@ -218,19 +211,14 @@ private: mutable std::mutex SourceModuleMutex; CompileOnDemandLayer2 &Parent; - std::shared_ptr BackingResolver; }; CompileOnDemandLayer2::CompileOnDemandLayer2( ExecutionSession &ES, IRLayer &BaseLayer, JITCompileCallbackManager &CCMgr, IndirectStubsManagerBuilder BuildIndirectStubsManager, - GetSymbolResolverFunction GetSymbolResolver, - SetSymbolResolverFunction SetSymbolResolver, GetAvailableContextFunction GetAvailableContext) : IRLayer(ES), BaseLayer(BaseLayer), CCMgr(CCMgr), BuildIndirectStubsManager(std::move(BuildIndirectStubsManager)), - GetSymbolResolver(std::move(GetSymbolResolver)), - SetSymbolResolver(std::move(SetSymbolResolver)), GetAvailableContext(std::move(GetAvailableContext)) {} Error CompileOnDemandLayer2::add(VSO &V, VModuleKey K, @@ -306,19 +294,14 @@ void CompileOnDemandLayer2::emit(MaterializationResponsibility R, VModuleKey K, StubInits[*KV.first] = KV.second; // Build the function-body-extracting materialization unit. - auto SR = GetSymbolResolver(K); if (auto Err = R.getTargetVSO().define( - llvm::make_unique( - ES, *this, std::move(M), SR))) { + llvm::make_unique(ES, *this, + std::move(M)))) { ES.reportError(std::move(Err)); R.failMaterialization(); return; } - // Replace the fallback symbol resolver: We will re-use M's VModuleKey for - // the GlobalsModule. - SetSymbolResolver(K, SR); - // Build the stubs. // FIXME: Remove function bodies materialization unit if stub creation fails. auto &StubsMgr = getStubsManager(TargetVSO); @@ -351,22 +334,8 @@ IndirectStubsManager &CompileOnDemandLayer2::getStubsManager(const VSO &V) { } void CompileOnDemandLayer2::emitExtractedFunctionsModule( - MaterializationResponsibility R, std::unique_ptr M, - std::shared_ptr Resolver) { - auto &TargetVSO = R.getTargetVSO(); + MaterializationResponsibility R, std::unique_ptr M) { auto K = getExecutionSession().allocateVModule(); - - auto ExtractedFunctionsResolver = createSymbolResolver( - [=](SymbolFlagsMap &Flags, const SymbolNameSet &Symbols) { - return Resolver->lookupFlags(Flags, Symbols); - }, - [=, &TargetVSO](std::shared_ptr Query, - SymbolNameSet Symbols) { - auto RemainingSymbols = TargetVSO.lookup(Query, std::move(Symbols)); - return Resolver->lookup(std::move(Query), std::move(RemainingSymbols)); - }); - - SetSymbolResolver(K, std::move(ExtractedFunctionsResolver)); BaseLayer.emit(std::move(R), std::move(K), std::move(M)); } diff --git a/lib/ExecutionEngine/Orc/Core.cpp b/lib/ExecutionEngine/Orc/Core.cpp index 38f2213a85f..9275bb84d01 100644 --- a/lib/ExecutionEngine/Orc/Core.cpp +++ b/lib/ExecutionEngine/Orc/Core.cpp @@ -24,7 +24,6 @@ char FailedToMaterialize::ID = 0; char SymbolsNotFound::ID = 0; void MaterializationUnit::anchor() {} -void SymbolResolver::anchor() {} raw_ostream &operator<<(raw_ostream &OS, const JITSymbolFlags &Flags) { if (Flags.isWeak()) @@ -99,6 +98,20 @@ raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps) { return OS; } +raw_ostream &operator<<(raw_ostream &OS, const VSOList &VSOs) { + OS << "["; + if (!VSOs.empty()) { + assert(VSOs.front() && "VSOList entries must not be null"); + OS << " " << VSOs.front()->getName(); + for (auto *V : make_range(std::next(VSOs.begin()), VSOs.end())) { + assert(V && "VSOList entries must not be null"); + OS << ", " << V->getName(); + } + } + OS << " ]"; + return OS; +} + FailedToMaterialize::FailedToMaterialize(SymbolNameSet Symbols) : Symbols(std::move(Symbols)) { assert(!this->Symbols.empty() && "Can not fail to resolve an empty set"); @@ -859,6 +872,34 @@ void VSO::runOutstandingMUs() { } } +void VSO::setSearchOrder(VSOList NewSearchOrder, bool SearchThisVSOFirst) { + if (SearchThisVSOFirst && NewSearchOrder.front() != this) + NewSearchOrder.insert(NewSearchOrder.begin(), this); + + ES.runSessionLocked([&]() { SearchOrder = std::move(NewSearchOrder); }); +} + +void VSO::addToSearchOrder(VSO &V) { + ES.runSessionLocked([&]() { SearchOrder.push_back(&V); }); +} + +void VSO::replaceInSearchOrder(VSO &OldV, VSO &NewV) { + ES.runSessionLocked([&]() { + auto I = std::find(SearchOrder.begin(), SearchOrder.end(), &OldV); + + if (I != SearchOrder.end()) + *I = &NewV; + }); +} + +void VSO::removeFromSearchOrder(VSO &V) { + ES.runSessionLocked([&]() { + auto I = std::find(SearchOrder.begin(), SearchOrder.end(), &V); + if (I != SearchOrder.end()) + SearchOrder.erase(I); + }); +} + SymbolNameSet VSO::lookupFlags(SymbolFlagsMap &Flags, const SymbolNameSet &Names) { return ES.runSessionLocked([&, this]() { @@ -1066,6 +1107,11 @@ void VSO::dump(raw_ostream &OS) { }); } +VSO::VSO(ExecutionSessionBase &ES, std::string Name) + : ES(ES), VSOName(std::move(Name)) { + SearchOrder.push_back(this); +} + Error VSO::defineImpl(MaterializationUnit &MU) { SymbolNameSet Duplicates; SymbolNameSet MUDefsOverridden; diff --git a/lib/ExecutionEngine/Orc/LLJIT.cpp b/lib/ExecutionEngine/Orc/LLJIT.cpp index 059fba23d57..52ff4efe56b 100644 --- a/lib/ExecutionEngine/Orc/LLJIT.cpp +++ b/lib/ExecutionEngine/Orc/LLJIT.cpp @@ -35,7 +35,6 @@ Error LLJIT::addIRModule(VSO &V, std::unique_ptr M) { return Err; auto K = ES->allocateVModule(); - Resolvers[K] = createResolverFor(V); return CompileLayer.add(V, K, std::move(M)); } @@ -49,23 +48,13 @@ LLJIT::LLJIT(std::unique_ptr ES, : ES(std::move(ES)), Main(this->ES->createVSO("main")), TM(std::move(TM)), DL(std::move(DL)), ObjLinkingLayer(*this->ES, - [this](VModuleKey K) { return getRTDyldResources(K); }), + [this](VModuleKey K) { return getMemoryManager(K); }), CompileLayer(*this->ES, ObjLinkingLayer, SimpleCompiler(*this->TM)), - CtorRunner(Main), DtorRunner(Main) { - VSOLookupOrder[&Main] = VSOList({&Main}); -} - -std::shared_ptr LLJIT::takeSymbolResolver(VModuleKey K) { - auto ResolverI = Resolvers.find(K); - assert(ResolverI != Resolvers.end() && "Missing resolver"); - auto Resolver = std::move(ResolverI->second); - Resolvers.erase(ResolverI); - return Resolver; -} + CtorRunner(Main), DtorRunner(Main) {} -RTDyldObjectLinkingLayer2::Resources LLJIT::getRTDyldResources(VModuleKey K) { - return orc::RTDyldObjectLinkingLayer2::Resources( - {llvm::make_unique(), takeSymbolResolver(K)}); +std::shared_ptr +LLJIT::getMemoryManager(VModuleKey K) { + return llvm::make_unique(); } std::string LLJIT::mangle(StringRef UnmangledName) { @@ -77,21 +66,6 @@ std::string LLJIT::mangle(StringRef UnmangledName) { return MangledName; } -std::unique_ptr LLJIT::createResolverFor(VSO &V) { - return createSymbolResolver( - [&](SymbolFlagsMap &Flags, const SymbolNameSet &Symbols) { - return V.lookupFlags(Flags, Symbols); - }, - [&, this](std::shared_ptr Q, - SymbolNameSet Symbols) { - assert(VSOLookupOrder.count(&V) && "No VSO lookup order for V"); - SymbolNameSet Unresolved = std::move(Symbols); - for (auto *LV : VSOLookupOrder[&V]) - Unresolved = LV->lookup(Q, std::move(Unresolved)); - return Unresolved; - }); -} - Error LLJIT::applyDataLayout(Module &M) { if (M.getDataLayout().isDefault()) M.setDataLayout(DL); @@ -143,7 +117,6 @@ Error LLLazyJIT::addLazyIRModule(VSO &V, std::unique_ptr M) { recordCtorDtors(*M); auto K = ES->allocateVModule(); - setSymbolResolver(K, createResolverFor(V)); return CODLayer.add(V, K, std::move(M)); } @@ -155,17 +128,7 @@ LLLazyJIT::LLLazyJIT( : LLJIT(std::move(ES), std::move(TM), std::move(DL)), CCMgr(std::move(CCMgr)), TransformLayer(*this->ES, CompileLayer), CODLayer(*this->ES, TransformLayer, *this->CCMgr, std::move(ISMBuilder), - [this](VModuleKey K) { return takeSymbolResolver(K); }, - [this](VModuleKey K, std::shared_ptr R) { - setSymbolResolver(K, std::move(R)); - }, [&]() -> LLVMContext & { return Ctx; }) {} -void LLLazyJIT::setSymbolResolver(VModuleKey K, - std::shared_ptr R) { - assert(!Resolvers.count(K) && "Resolver already present for VModule K"); - Resolvers[K] = std::move(R); -} - } // End namespace orc. } // End namespace llvm. diff --git a/lib/ExecutionEngine/Orc/Legacy.cpp b/lib/ExecutionEngine/Orc/Legacy.cpp index 795ddd582d8..79525baf92e 100644 --- a/lib/ExecutionEngine/Orc/Legacy.cpp +++ b/lib/ExecutionEngine/Orc/Legacy.cpp @@ -12,6 +12,8 @@ namespace llvm { namespace orc { +void SymbolResolver::anchor() {} + JITSymbolResolverAdapter::JITSymbolResolverAdapter( ExecutionSession &ES, SymbolResolver &R, MaterializationResponsibility *MR) : ES(ES), R(R), MR(MR) {} diff --git a/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp b/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp index 61e8ee8ff1a..8c53b4f58de 100644 --- a/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp +++ b/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp @@ -9,13 +9,85 @@ #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" +namespace { + +using namespace llvm; +using namespace llvm::orc; + +class VSOSearchOrderResolver : public JITSymbolResolver { +public: + VSOSearchOrderResolver(ExecutionSession &ES, + MaterializationResponsibility &MR) + : ES(ES), MR(MR) {} + + Expected lookup(const LookupSet &Symbols) { + SymbolNameSet InternedSymbols; + + for (auto &S : Symbols) + InternedSymbols.insert(ES.getSymbolStringPool().intern(S)); + + auto AsyncLookup = [&](std::shared_ptr Q, + SymbolNameSet Names) { + SymbolNameSet Unresolved = std::move(Names); + MR.getTargetVSO().withSearchOrderDo([&](const VSOList &SearchOrder) { + for (auto *V : SearchOrder) { + assert(V && "VSOList entry can not be null"); + Unresolved = V->lookup(Q, std::move(Unresolved)); + } + }); + return Unresolved; + }; + + auto InternedResult = blockingLookup( + ES, std::move(AsyncLookup), std::move(InternedSymbols), false, &MR); + + if (!InternedResult) + return InternedResult.takeError(); + + LookupResult Result; + for (auto &KV : *InternedResult) + Result[*KV.first] = std::move(KV.second); + + return Result; + } + + Expected lookupFlags(const LookupSet &Symbols) { + SymbolNameSet InternedSymbols; + + for (auto &S : Symbols) + InternedSymbols.insert(ES.getSymbolStringPool().intern(S)); + + SymbolFlagsMap InternedResult; + MR.getTargetVSO().withSearchOrderDo([&](const VSOList &VSOs) { + // An empty search order is pathalogical, but allowed. + if (VSOs.empty()) + return; + + assert(VSOs.front() && "VSOList entry can not be null"); + VSOs.front()->lookupFlags(InternedResult, InternedSymbols); + }); + + LookupFlagsResult Result; + for (auto &KV : InternedResult) + Result[*KV.first] = std::move(KV.second); + + return Result; + } + +private: + ExecutionSession &ES; + MaterializationResponsibility &MR; +}; + +} // end anonymous namespace + namespace llvm { namespace orc { RTDyldObjectLinkingLayer2::RTDyldObjectLinkingLayer2( - ExecutionSession &ES, ResourcesGetterFunction GetResources, + ExecutionSession &ES, GetMemoryManagerFunction GetMemoryManager, NotifyLoadedFunction NotifyLoaded, NotifyFinalizedFunction NotifyFinalized) - : ObjectLayer(ES), GetResources(std::move(GetResources)), + : ObjectLayer(ES), GetMemoryManager(GetMemoryManager), NotifyLoaded(std::move(NotifyLoaded)), NotifyFinalized(std::move(NotifyFinalized)), ProcessAllSections(false) {} @@ -32,11 +104,10 @@ void RTDyldObjectLinkingLayer2::emit(MaterializationResponsibility R, R.failMaterialization(); } - auto Resources = GetResources(K); + auto MemoryManager = GetMemoryManager(K); - JITSymbolResolverAdapter ResolverAdapter(ES, *Resources.Resolver, &R); - auto RTDyld = - llvm::make_unique(*Resources.MemMgr, ResolverAdapter); + VSOSearchOrderResolver Resolver(ES, R); + auto RTDyld = llvm::make_unique(*MemoryManager, Resolver); RTDyld->setProcessAllSections(ProcessAllSections); { @@ -48,7 +119,7 @@ void RTDyldObjectLinkingLayer2::emit(MaterializationResponsibility R, assert(!MemMgrs.count(K) && "A memory manager already exists for this key?"); - MemMgrs[K] = Resources.MemMgr; + MemMgrs[K] = std::move(MemoryManager); } auto Info = RTDyld->loadObject(**ObjFile); diff --git a/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp b/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp index 68911d75877..9d4f9463372 100644 --- a/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp +++ b/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp @@ -11,7 +11,6 @@ #include "llvm/Config/llvm-config.h" #include "llvm/ExecutionEngine/Orc/Core.h" #include "llvm/ExecutionEngine/Orc/OrcError.h" -#include "gtest/gtest.h" #include #include @@ -19,6 +18,8 @@ using namespace llvm; using namespace llvm::orc; +class CoreAPIsStandardTest : public CoreAPIsBasedStandardTest {}; + namespace { class SimpleMaterializationUnit : public MaterializationUnit { @@ -58,45 +59,6 @@ private: DestructorFunction Destructor; }; -// CoreAPIsStandardTest that saves a bunch of boilerplate by providing the -// following: -// -// (1) ES -- An ExecutionSession -// (2) Foo, Bar, Baz, Qux -- SymbolStringPtrs for strings "foo", "bar", "baz", -// and "qux" respectively. -// (3) FooAddr, BarAddr, BazAddr, QuxAddr -- Dummy addresses. Guaranteed -// distinct and non-null. -// (4) FooSym, BarSym, BazSym, QuxSym -- JITEvaluatedSymbols with FooAddr, -// BarAddr, BazAddr, and QuxAddr respectively. All with default strong, -// linkage and non-hidden visibility. -// (5) V -- A VSO associated with ES. -class CoreAPIsStandardTest : public testing::Test { -public: -protected: - ExecutionSession ES; - VSO &V = ES.createVSO("V"); - SymbolStringPtr Foo = ES.getSymbolStringPool().intern("foo"); - SymbolStringPtr Bar = ES.getSymbolStringPool().intern("bar"); - SymbolStringPtr Baz = ES.getSymbolStringPool().intern("baz"); - SymbolStringPtr Qux = ES.getSymbolStringPool().intern("qux"); - static const JITTargetAddress FooAddr = 1U; - static const JITTargetAddress BarAddr = 2U; - static const JITTargetAddress BazAddr = 3U; - static const JITTargetAddress QuxAddr = 4U; - JITEvaluatedSymbol FooSym = - JITEvaluatedSymbol(FooAddr, JITSymbolFlags::Exported); - JITEvaluatedSymbol BarSym = - JITEvaluatedSymbol(BarAddr, JITSymbolFlags::Exported); - JITEvaluatedSymbol BazSym = - JITEvaluatedSymbol(BazAddr, JITSymbolFlags::Exported); - JITEvaluatedSymbol QuxSym = - JITEvaluatedSymbol(QuxAddr, JITSymbolFlags::Exported); -}; - -const JITTargetAddress CoreAPIsStandardTest::FooAddr; -const JITTargetAddress CoreAPIsStandardTest::BarAddr; -const JITTargetAddress CoreAPIsStandardTest::BazAddr; -const JITTargetAddress CoreAPIsStandardTest::QuxAddr; TEST_F(CoreAPIsStandardTest, AsynchronousSymbolQuerySuccessfulResolutionOnly) { bool OnResolutionRun = false; @@ -623,65 +585,6 @@ TEST_F(CoreAPIsStandardTest, FailResolution) { } } -TEST_F(CoreAPIsStandardTest, TestLambdaSymbolResolver) { - cantFail(V.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}}))); - - auto Resolver = createSymbolResolver( - [&](SymbolFlagsMap &SymbolFlags, const SymbolNameSet &Symbols) { - return V.lookupFlags(SymbolFlags, Symbols); - }, - [&](std::shared_ptr Q, SymbolNameSet Symbols) { - return V.lookup(std::move(Q), Symbols); - }); - - SymbolNameSet Symbols({Foo, Bar, Baz}); - - SymbolFlagsMap SymbolFlags; - SymbolNameSet SymbolsNotFound = Resolver->lookupFlags(SymbolFlags, Symbols); - - EXPECT_EQ(SymbolFlags.size(), 2U) - << "lookupFlags returned the wrong number of results"; - EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for foo"; - EXPECT_EQ(SymbolFlags.count(Bar), 1U) << "Missing lookupFlags result for bar"; - EXPECT_EQ(SymbolFlags[Foo], FooSym.getFlags()) - << "Incorrect lookupFlags result for Foo"; - EXPECT_EQ(SymbolFlags[Bar], BarSym.getFlags()) - << "Incorrect lookupFlags result for Bar"; - EXPECT_EQ(SymbolsNotFound.size(), 1U) - << "Expected one symbol not found in lookupFlags"; - EXPECT_EQ(SymbolsNotFound.count(Baz), 1U) - << "Expected baz not to be found in lookupFlags"; - - bool OnResolvedRun = false; - - auto OnResolved = - [&](Expected Result) { - OnResolvedRun = true; - EXPECT_TRUE(!!Result) << "Unexpected error"; - EXPECT_EQ(Result->Symbols.size(), 2U) - << "Unexpected number of resolved symbols"; - EXPECT_EQ(Result->Symbols.count(Foo), 1U) - << "Missing lookup result for foo"; - EXPECT_EQ(Result->Symbols.count(Bar), 1U) - << "Missing lookup result for bar"; - EXPECT_EQ(Result->Symbols[Foo].getAddress(), FooSym.getAddress()) - << "Incorrect address for foo"; - EXPECT_EQ(Result->Symbols[Bar].getAddress(), BarSym.getAddress()) - << "Incorrect address for bar"; - }; - auto OnReady = [&](Error Err) { - EXPECT_FALSE(!!Err) << "Finalization should never fail in this test"; - }; - - auto Q = std::make_shared(SymbolNameSet({Foo, Bar}), - OnResolved, OnReady); - auto Unresolved = Resolver->lookup(std::move(Q), Symbols); - - EXPECT_EQ(Unresolved.size(), 1U) << "Expected one unresolved symbol"; - EXPECT_EQ(Unresolved.count(Baz), 1U) << "Expected baz to not be resolved"; - EXPECT_TRUE(OnResolvedRun) << "OnResolved was never run"; -} - TEST_F(CoreAPIsStandardTest, TestLookupWithUnthreadedMaterialization) { auto MU = llvm::make_unique( SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), diff --git a/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp b/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp index ade5aa26470..51f86eacfd9 100644 --- a/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp +++ b/unittests/ExecutionEngine/Orc/LegacyAPIInteropTest.cpp @@ -14,8 +14,69 @@ using namespace llvm; using namespace llvm::orc; +class LegacyAPIsStandardTest : public CoreAPIsBasedStandardTest {}; + namespace { +TEST_F(LegacyAPIsStandardTest, TestLambdaSymbolResolver) { + cantFail(V.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}}))); + + auto Resolver = createSymbolResolver( + [&](SymbolFlagsMap &SymbolFlags, const SymbolNameSet &Symbols) { + return V.lookupFlags(SymbolFlags, Symbols); + }, + [&](std::shared_ptr Q, SymbolNameSet Symbols) { + return V.lookup(std::move(Q), Symbols); + }); + + SymbolNameSet Symbols({Foo, Bar, Baz}); + + SymbolFlagsMap SymbolFlags; + SymbolNameSet SymbolsNotFound = Resolver->lookupFlags(SymbolFlags, Symbols); + + EXPECT_EQ(SymbolFlags.size(), 2U) + << "lookupFlags returned the wrong number of results"; + EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for foo"; + EXPECT_EQ(SymbolFlags.count(Bar), 1U) << "Missing lookupFlags result for bar"; + EXPECT_EQ(SymbolFlags[Foo], FooSym.getFlags()) + << "Incorrect lookupFlags result for Foo"; + EXPECT_EQ(SymbolFlags[Bar], BarSym.getFlags()) + << "Incorrect lookupFlags result for Bar"; + EXPECT_EQ(SymbolsNotFound.size(), 1U) + << "Expected one symbol not found in lookupFlags"; + EXPECT_EQ(SymbolsNotFound.count(Baz), 1U) + << "Expected baz not to be found in lookupFlags"; + + bool OnResolvedRun = false; + + auto OnResolved = + [&](Expected Result) { + OnResolvedRun = true; + EXPECT_TRUE(!!Result) << "Unexpected error"; + EXPECT_EQ(Result->Symbols.size(), 2U) + << "Unexpected number of resolved symbols"; + EXPECT_EQ(Result->Symbols.count(Foo), 1U) + << "Missing lookup result for foo"; + EXPECT_EQ(Result->Symbols.count(Bar), 1U) + << "Missing lookup result for bar"; + EXPECT_EQ(Result->Symbols[Foo].getAddress(), FooSym.getAddress()) + << "Incorrect address for foo"; + EXPECT_EQ(Result->Symbols[Bar].getAddress(), BarSym.getAddress()) + << "Incorrect address for bar"; + }; + auto OnReady = [&](Error Err) { + EXPECT_FALSE(!!Err) << "Finalization should never fail in this test"; + }; + + auto Q = std::make_shared(SymbolNameSet({Foo, Bar}), + OnResolved, OnReady); + auto Unresolved = Resolver->lookup(std::move(Q), Symbols); + + EXPECT_EQ(Unresolved.size(), 1U) << "Expected one unresolved symbol"; + EXPECT_EQ(Unresolved.count(Baz), 1U) << "Expected baz to not be resolved"; + EXPECT_TRUE(OnResolvedRun) << "OnResolved was never run"; +} + TEST(LegacyAPIInteropTest, QueryAgainstVSO) { ExecutionSession ES(std::make_shared()); diff --git a/unittests/ExecutionEngine/Orc/OrcTestCommon.cpp b/unittests/ExecutionEngine/Orc/OrcTestCommon.cpp index ccd2fc0fb18..a12b1876e29 100644 --- a/unittests/ExecutionEngine/Orc/OrcTestCommon.cpp +++ b/unittests/ExecutionEngine/Orc/OrcTestCommon.cpp @@ -15,6 +15,11 @@ using namespace llvm; +const JITTargetAddress llvm::orc::CoreAPIsBasedStandardTest::FooAddr; +const JITTargetAddress llvm::orc::CoreAPIsBasedStandardTest::BarAddr; +const JITTargetAddress llvm::orc::CoreAPIsBasedStandardTest::BazAddr; +const JITTargetAddress llvm::orc::CoreAPIsBasedStandardTest::QuxAddr; + bool OrcNativeTarget::NativeTargetInitialized = false; ModuleBuilder::ModuleBuilder(LLVMContext &Context, StringRef Triple, diff --git a/unittests/ExecutionEngine/Orc/OrcTestCommon.h b/unittests/ExecutionEngine/Orc/OrcTestCommon.h index c4424e009b4..c6caaf07db0 100644 --- a/unittests/ExecutionEngine/Orc/OrcTestCommon.h +++ b/unittests/ExecutionEngine/Orc/OrcTestCommon.h @@ -24,12 +24,52 @@ #include "llvm/IR/Module.h" #include "llvm/IR/TypeBuilder.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/Support/TargetSelect.h" #include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "gtest/gtest.h" + #include namespace llvm { +namespace orc { +// CoreAPIsStandardTest that saves a bunch of boilerplate by providing the +// following: +// +// (1) ES -- An ExecutionSession +// (2) Foo, Bar, Baz, Qux -- SymbolStringPtrs for strings "foo", "bar", "baz", +// and "qux" respectively. +// (3) FooAddr, BarAddr, BazAddr, QuxAddr -- Dummy addresses. Guaranteed +// distinct and non-null. +// (4) FooSym, BarSym, BazSym, QuxSym -- JITEvaluatedSymbols with FooAddr, +// BarAddr, BazAddr, and QuxAddr respectively. All with default strong, +// linkage and non-hidden visibility. +// (5) V -- A VSO associated with ES. +class CoreAPIsBasedStandardTest : public testing::Test { +public: +protected: + ExecutionSession ES; + VSO &V = ES.createVSO("V"); + SymbolStringPtr Foo = ES.getSymbolStringPool().intern("foo"); + SymbolStringPtr Bar = ES.getSymbolStringPool().intern("bar"); + SymbolStringPtr Baz = ES.getSymbolStringPool().intern("baz"); + SymbolStringPtr Qux = ES.getSymbolStringPool().intern("qux"); + static const JITTargetAddress FooAddr = 1U; + static const JITTargetAddress BarAddr = 2U; + static const JITTargetAddress BazAddr = 3U; + static const JITTargetAddress QuxAddr = 4U; + JITEvaluatedSymbol FooSym = + JITEvaluatedSymbol(FooAddr, JITSymbolFlags::Exported); + JITEvaluatedSymbol BarSym = + JITEvaluatedSymbol(BarAddr, JITSymbolFlags::Exported); + JITEvaluatedSymbol BazSym = + JITEvaluatedSymbol(BazAddr, JITSymbolFlags::Exported); + JITEvaluatedSymbol QuxSym = + JITEvaluatedSymbol(QuxAddr, JITSymbolFlags::Exported); +}; + +} // end namespace orc + class OrcNativeTarget { public: static void initialize() { -- 2.50.1