diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h index 783c352cf057ca..18a4c111a5275e 100644 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h +++ b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h @@ -32,7 +32,6 @@ namespace orc { class KaleidoscopeJIT { private: - std::unique_ptr EPC; std::unique_ptr ES; DataLayout DL; @@ -44,11 +43,9 @@ class KaleidoscopeJIT { JITDylib &MainJD; public: - KaleidoscopeJIT(std::unique_ptr EPC, - std::unique_ptr ES, + KaleidoscopeJIT(std::unique_ptr ES, JITTargetMachineBuilder JTMB, DataLayout DL) - : EPC(std::move(EPC)), ES(std::move(ES)), DL(std::move(DL)), - Mangle(*this->ES, this->DL), + : ES(std::move(ES)), DL(std::move(DL)), Mangle(*this->ES, this->DL), ObjectLayer(*this->ES, []() { return std::make_unique(); }), CompileLayer(*this->ES, ObjectLayer, @@ -65,21 +62,21 @@ class KaleidoscopeJIT { } static Expected> Create() { - auto SSP = std::make_shared(); - auto EPC = SelfExecutorProcessControl::Create(SSP); + auto EPC = SelfExecutorProcessControl::Create(); if (!EPC) return EPC.takeError(); - auto ES = std::make_unique(std::move(SSP)); + auto ES = std::make_unique(std::move(*EPC)); - JITTargetMachineBuilder JTMB((*EPC)->getTargetTriple()); + JITTargetMachineBuilder JTMB( + ES->getExecutorProcessControl().getTargetTriple()); auto DL = JTMB.getDefaultDataLayoutForTarget(); if (!DL) return DL.takeError(); - return std::make_unique(std::move(*EPC), std::move(ES), - std::move(JTMB), std::move(*DL)); + return std::make_unique(std::move(ES), std::move(JTMB), + std::move(*DL)); } const DataLayout &getDataLayout() const { return DL; } diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h index 363c74882b8f17..23a6fd806f5abf 100644 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h +++ b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h @@ -37,7 +37,6 @@ namespace orc { class KaleidoscopeJIT { private: - std::unique_ptr EPC; std::unique_ptr ES; DataLayout DL; @@ -50,11 +49,9 @@ class KaleidoscopeJIT { JITDylib &MainJD; public: - KaleidoscopeJIT(std::unique_ptr EPC, - std::unique_ptr ES, + KaleidoscopeJIT(std::unique_ptr ES, JITTargetMachineBuilder JTMB, DataLayout DL) - : EPC(std::move(EPC)), ES(std::move(ES)), DL(std::move(DL)), - Mangle(*this->ES, this->DL), + : ES(std::move(ES)), DL(std::move(DL)), Mangle(*this->ES, this->DL), ObjectLayer(*this->ES, []() { return std::make_unique(); }), CompileLayer(*this->ES, ObjectLayer, @@ -72,21 +69,21 @@ class KaleidoscopeJIT { } static Expected> Create() { - auto SSP = std::make_shared(); - auto EPC = SelfExecutorProcessControl::Create(SSP); + auto EPC = SelfExecutorProcessControl::Create(); if (!EPC) return EPC.takeError(); - auto ES = std::make_unique(std::move(SSP)); + auto ES = std::make_unique(std::move(*EPC)); - JITTargetMachineBuilder JTMB((*EPC)->getTargetTriple()); + JITTargetMachineBuilder JTMB( + ES->getExecutorProcessControl().getTargetTriple()); auto DL = JTMB.getDefaultDataLayoutForTarget(); if (!DL) return DL.takeError(); - return std::make_unique(std::move(*EPC), std::move(ES), - std::move(JTMB), std::move(*DL)); + return std::make_unique(std::move(ES), std::move(JTMB), + std::move(*DL)); } const DataLayout &getDataLayout() const { return DL; } diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h index 0aba5666995aaf..130310da92748e 100644 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h +++ b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h @@ -39,7 +39,6 @@ namespace orc { class KaleidoscopeJIT { private: - std::unique_ptr EPC; std::unique_ptr ES; std::unique_ptr EPCIU; @@ -59,12 +58,11 @@ class KaleidoscopeJIT { } public: - KaleidoscopeJIT(std::unique_ptr EPC, - std::unique_ptr ES, + KaleidoscopeJIT(std::unique_ptr ES, std::unique_ptr EPCIU, JITTargetMachineBuilder JTMB, DataLayout DL) - : EPC(std::move(EPC)), ES(std::move(ES)), EPCIU(std::move(EPCIU)), - DL(std::move(DL)), Mangle(*this->ES, this->DL), + : ES(std::move(ES)), EPCIU(std::move(EPCIU)), DL(std::move(DL)), + Mangle(*this->ES, this->DL), ObjectLayer(*this->ES, []() { return std::make_unique(); }), CompileLayer(*this->ES, ObjectLayer, @@ -87,14 +85,13 @@ class KaleidoscopeJIT { } static Expected> Create() { - auto SSP = std::make_shared(); - auto EPC = SelfExecutorProcessControl::Create(SSP); + auto EPC = SelfExecutorProcessControl::Create(); if (!EPC) return EPC.takeError(); - auto ES = std::make_unique(std::move(SSP)); + auto ES = std::make_unique(std::move(*EPC)); - auto EPCIU = EPCIndirectionUtils::Create(**EPC); + auto EPCIU = EPCIndirectionUtils::Create(ES->getExecutorProcessControl()); if (!EPCIU) return EPCIU.takeError(); @@ -104,15 +101,15 @@ class KaleidoscopeJIT { if (auto Err = setUpInProcessLCTMReentryViaEPCIU(**EPCIU)) return std::move(Err); - JITTargetMachineBuilder JTMB((*EPC)->getTargetTriple()); + JITTargetMachineBuilder JTMB( + ES->getExecutorProcessControl().getTargetTriple()); auto DL = JTMB.getDefaultDataLayoutForTarget(); if (!DL) return DL.takeError(); - return std::make_unique(std::move(*EPC), std::move(ES), - std::move(*EPCIU), std::move(JTMB), - std::move(*DL)); + return std::make_unique(std::move(ES), std::move(*EPCIU), + std::move(JTMB), std::move(*DL)); } const DataLayout &getDataLayout() const { return DL; } diff --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h index 6b2f6a543bbf86..863304b02113ec 100644 --- a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h +++ b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h @@ -126,7 +126,6 @@ void KaleidoscopeASTMaterializationUnit::materialize( class KaleidoscopeJIT { private: - std::unique_ptr EPC; std::unique_ptr ES; std::unique_ptr EPCIU; @@ -146,12 +145,11 @@ class KaleidoscopeJIT { } public: - KaleidoscopeJIT(std::unique_ptr EPC, - std::unique_ptr ES, + KaleidoscopeJIT(std::unique_ptr ES, std::unique_ptr EPCIU, JITTargetMachineBuilder JTMB, DataLayout DL) - : EPC(std::move(EPC)), ES(std::move(ES)), EPCIU(std::move(EPCIU)), - DL(std::move(DL)), Mangle(*this->ES, this->DL), + : ES(std::move(ES)), EPCIU(std::move(EPCIU)), DL(std::move(DL)), + Mangle(*this->ES, this->DL), ObjectLayer(*this->ES, []() { return std::make_unique(); }), CompileLayer(*this->ES, ObjectLayer, @@ -172,14 +170,13 @@ class KaleidoscopeJIT { } static Expected> Create() { - auto SSP = std::make_shared(); - auto EPC = SelfExecutorProcessControl::Create(SSP); + auto EPC = SelfExecutorProcessControl::Create(); if (!EPC) return EPC.takeError(); - auto ES = std::make_unique(std::move(SSP)); + auto ES = std::make_unique(std::move(*EPC)); - auto EPCIU = EPCIndirectionUtils::Create(**EPC); + auto EPCIU = EPCIndirectionUtils::Create(ES->getExecutorProcessControl()); if (!EPCIU) return EPCIU.takeError(); @@ -195,9 +192,8 @@ class KaleidoscopeJIT { if (!DL) return DL.takeError(); - return std::make_unique(std::move(*EPC), std::move(ES), - std::move(*EPCIU), std::move(JTMB), - std::move(*DL)); + return std::make_unique(std::move(ES), std::move(*EPCIU), + std::move(JTMB), std::move(*DL)); } const DataLayout &getDataLayout() const { return DL; } diff --git a/llvm/examples/Kaleidoscope/include/KaleidoscopeJIT.h b/llvm/examples/Kaleidoscope/include/KaleidoscopeJIT.h index 783c352cf057ca..18a4c111a5275e 100644 --- a/llvm/examples/Kaleidoscope/include/KaleidoscopeJIT.h +++ b/llvm/examples/Kaleidoscope/include/KaleidoscopeJIT.h @@ -32,7 +32,6 @@ namespace orc { class KaleidoscopeJIT { private: - std::unique_ptr EPC; std::unique_ptr ES; DataLayout DL; @@ -44,11 +43,9 @@ class KaleidoscopeJIT { JITDylib &MainJD; public: - KaleidoscopeJIT(std::unique_ptr EPC, - std::unique_ptr ES, + KaleidoscopeJIT(std::unique_ptr ES, JITTargetMachineBuilder JTMB, DataLayout DL) - : EPC(std::move(EPC)), ES(std::move(ES)), DL(std::move(DL)), - Mangle(*this->ES, this->DL), + : ES(std::move(ES)), DL(std::move(DL)), Mangle(*this->ES, this->DL), ObjectLayer(*this->ES, []() { return std::make_unique(); }), CompileLayer(*this->ES, ObjectLayer, @@ -65,21 +62,21 @@ class KaleidoscopeJIT { } static Expected> Create() { - auto SSP = std::make_shared(); - auto EPC = SelfExecutorProcessControl::Create(SSP); + auto EPC = SelfExecutorProcessControl::Create(); if (!EPC) return EPC.takeError(); - auto ES = std::make_unique(std::move(SSP)); + auto ES = std::make_unique(std::move(*EPC)); - JITTargetMachineBuilder JTMB((*EPC)->getTargetTriple()); + JITTargetMachineBuilder JTMB( + ES->getExecutorProcessControl().getTargetTriple()); auto DL = JTMB.getDefaultDataLayoutForTarget(); if (!DL) return DL.takeError(); - return std::make_unique(std::move(*EPC), std::move(ES), - std::move(JTMB), std::move(*DL)); + return std::make_unique(std::move(ES), std::move(JTMB), + std::move(*DL)); } const DataLayout &getDataLayout() const { return DL; } diff --git a/llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp b/llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp index 953d90e4c06ef3..ac5ea5643b03b3 100644 --- a/llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp +++ b/llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp @@ -134,9 +134,9 @@ int main(int argc, char *argv[]) { ExitOnErr.setBanner(std::string(argv[0]) + ": "); // (1) Create LLJIT instance. - auto SSP = std::make_shared(); - auto EPC = ExitOnErr(SelfExecutorProcessControl::Create(std::move(SSP))); - auto J = ExitOnErr(LLJITBuilder().setExecutorProcessControl(*EPC).create()); + auto EPC = ExitOnErr(SelfExecutorProcessControl::Create()); + auto J = ExitOnErr( + LLJITBuilder().setExecutorProcessControl(std::move(EPC)).create()); // (2) Install transform to print modules as they are compiled: J->getIRTransformLayer().setTransform( @@ -154,7 +154,8 @@ int main(int argc, char *argv[]) { J->getExecutionSession(), pointerToJITTargetAddress(&reportErrorAndExit)); auto ISM = EPCIU->createIndirectStubsManager(); J->getMainJITDylib().addGenerator( - ExitOnErr(EPCDynamicLibrarySearchGenerator::GetForTargetProcess(*EPC))); + ExitOnErr(EPCDynamicLibrarySearchGenerator::GetForTargetProcess( + J->getExecutionSession()))); // (4) Add modules. ExitOnErr(J->addIRModule(ExitOnErr(parseExampleModule(FooMod, "foo-mod")))); diff --git a/llvm/examples/SpeculativeJIT/SpeculativeJIT.cpp b/llvm/examples/SpeculativeJIT/SpeculativeJIT.cpp index 0ca5d62e7b67cb..9f5677437f38dc 100644 --- a/llvm/examples/SpeculativeJIT/SpeculativeJIT.cpp +++ b/llvm/examples/SpeculativeJIT/SpeculativeJIT.cpp @@ -49,7 +49,11 @@ class SpeculativeJIT { if (!DL) return DL.takeError(); - auto ES = std::make_unique(); + auto EPC = SelfExecutorProcessControl::Create(); + if (!EPC) + return EPC.takeError(); + + auto ES = std::make_unique(std::move(*EPC)); auto LCTMgr = createLocalLazyCallThroughManager( JTMB->getTargetTriple(), *ES, diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Core.h b/llvm/include/llvm/ExecutionEngine/Orc/Core.h index 159553b5559f48..e832d8d57dfa37 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/Core.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/Core.h @@ -19,12 +19,14 @@ #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ExecutionEngine/JITLink/JITLinkDylib.h" #include "llvm/ExecutionEngine/JITSymbol.h" -#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h" +#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" +#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h" #include "llvm/ExecutionEngine/OrcV1Deprecation.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ExtensibleRTTI.h" #include +#include #include #include @@ -1286,19 +1288,30 @@ class ExecutionSession { /// For dispatching ORC tasks (typically materialization tasks). using DispatchTaskFunction = unique_function T)>; - /// Construct an ExecutionSession. - /// - /// SymbolStringPools may be shared between ExecutionSessions. - ExecutionSession(std::shared_ptr SSP = nullptr); + /// An asynchronous wrapper-function callable from the executor via + /// jit-dispatch. + using JITDispatchHandlerFunction = unique_function; + + /// A map associating tag names with asynchronous wrapper function + /// implementations in the JIT. + using JITDispatchHandlerAssociationMap = + DenseMap; + + /// Construct an ExecutionSession with the given ExecutorProcessControl + /// object. + ExecutionSession(std::unique_ptr EPC); /// End the session. Closes all JITDylibs. Error endSession(); - /// Add a symbol name to the SymbolStringPool and return a pointer to it. - SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); } + /// Get the ExecutorProcessControl object associated with this + /// ExecutionSession. + ExecutorProcessControl &getExecutorProcessControl() { return *EPC; } - /// Returns a shared_ptr to the SymbolStringPool for this ExecutionSession. - std::shared_ptr getSymbolStringPool() const { return SSP; } + /// Add a symbol name to the SymbolStringPool and return a pointer to it. + SymbolStringPtr intern(StringRef SymName) { return EPC->intern(SymName); } /// Set the Platform for this ExecutionSession. void setPlatform(std::unique_ptr P) { this->P = std::move(P); } @@ -1440,6 +1453,121 @@ class ExecutionSession { DispatchTask(std::move(T)); } + /// Run a wrapper function in the executor. + /// + /// The wrapper function should be callable as: + /// + /// \code{.cpp} + /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size); + /// \endcode{.cpp} + /// + /// The given OnComplete function will be called to return the result. + void callWrapperAsync(ExecutorProcessControl::SendResultFunction OnComplete, + JITTargetAddress WrapperFnAddr, + ArrayRef ArgBuffer) { + EPC->callWrapperAsync(std::move(OnComplete), WrapperFnAddr, ArgBuffer); + } + + /// Run a wrapper function in the executor. The wrapper function should be + /// callable as: + /// + /// \code{.cpp} + /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size); + /// \endcode{.cpp} + shared::WrapperFunctionResult callWrapper(JITTargetAddress WrapperFnAddr, + ArrayRef ArgBuffer) { + std::promise RP; + auto RF = RP.get_future(); + callWrapperAsync( + [&](shared::WrapperFunctionResult R) { RP.set_value(std::move(R)); }, + WrapperFnAddr, ArgBuffer); + return RF.get(); + } + + /// Run a wrapper function using SPS to serialize the arguments and + /// deserialize the results. + template + void callSPSWrapperAsync(SendResultT &&SendResult, + JITTargetAddress WrapperFnAddr, + const ArgTs &...Args) { + shared::WrapperFunction::callAsync( + [this, + WrapperFnAddr](ExecutorProcessControl::SendResultFunction SendResult, + const char *ArgData, size_t ArgSize) { + callWrapperAsync(std::move(SendResult), WrapperFnAddr, + ArrayRef(ArgData, ArgSize)); + }, + std::move(SendResult), Args...); + } + + /// Run a wrapper function using SPS to serialize the arguments and + /// deserialize the results. + /// + /// If SPSSignature is a non-void function signature then the second argument + /// (the first in the Args list) should be a reference to a return value. + template + Error callSPSWrapper(JITTargetAddress WrapperFnAddr, + WrapperCallArgTs &&...WrapperCallArgs) { + return shared::WrapperFunction::call( + [this, WrapperFnAddr](const char *ArgData, size_t ArgSize) { + return callWrapper(WrapperFnAddr, ArrayRef(ArgData, ArgSize)); + }, + std::forward(WrapperCallArgs)...); + } + + /// Wrap a handler that takes concrete argument types (and a sender for a + /// concrete return type) to produce an AsyncHandlerWrapperFunction. Uses SPS + /// to unpack the arguments and pack the result. + /// + /// This function is intended to support easy construction of + /// AsyncHandlerWrapperFunctions that can be associated with a tag + /// (using registerJITDispatchHandler) and called from the executor. + template + static JITDispatchHandlerFunction wrapAsyncWithSPS(HandlerT &&H) { + return [H = std::forward(H)]( + ExecutorProcessControl::SendResultFunction SendResult, + const char *ArgData, size_t ArgSize) mutable { + shared::WrapperFunction::handleAsync(ArgData, ArgSize, H, + std::move(SendResult)); + }; + } + + /// Wrap a class method that takes concrete argument types (and a sender for + /// a concrete return type) to produce an AsyncHandlerWrapperFunction. Uses + /// SPS to unpack teh arguments and pack the result. + /// + /// This function is intended to support easy construction of + /// AsyncHandlerWrapperFunctions that can be associated with a tag + /// (using registerJITDispatchHandler) and called from the executor. + template + static JITDispatchHandlerFunction + wrapAsyncWithSPS(ClassT *Instance, void (ClassT::*Method)(MethodArgTs...)) { + return wrapAsyncWithSPS( + [Instance, Method](MethodArgTs &&...MethodArgs) { + (Instance->*Method)(std::forward(MethodArgs)...); + }); + } + + /// For each tag symbol name, associate the corresponding + /// AsyncHandlerWrapperFunction with the address of that symbol. The + /// handler becomes callable from the executor using the ORC runtime + /// __orc_rt_jit_dispatch function and the given tag. + /// + /// Tag symbols will be looked up in JD using LookupKind::Static, + /// JITDylibLookupFlags::MatchAllSymbols (hidden tags will be found), and + /// LookupFlags::WeaklyReferencedSymbol. Missing tag definitions will not + /// cause an error, the handler will simply be dropped. + Error registerJITDispatchHandlers(JITDylib &JD, + JITDispatchHandlerAssociationMap WFs); + + /// Run a registered jit-side wrapper function. + /// This should be called by the ExecutorProcessControl instance in response + /// to incoming jit-dispatch requests from the executor. + void + runJITDispatchHandler(ExecutorProcessControl::SendResultFunction SendResult, + JITTargetAddress HandlerFnTagAddr, + ArrayRef ArgBuffer); + /// Dump the state of all the JITDylibs in this session. void dump(raw_ostream &OS); @@ -1523,7 +1651,7 @@ class ExecutionSession { mutable std::recursive_mutex SessionMutex; bool SessionOpen = true; - std::shared_ptr SSP; + std::unique_ptr EPC; std::unique_ptr P; ErrorReporter ReportError = logErrorsToStdErr; DispatchTaskFunction DispatchTask = runOnCurrentThread; @@ -1538,6 +1666,10 @@ class ExecutionSession { std::vector, std::unique_ptr>> OutstandingMUs; + + mutable std::mutex JITDispatchHandlersMutex; + DenseMap> + JITDispatchHandlers; }; inline ExecutionSession &MaterializationResponsibility::getExecutionSession() { diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h index db5c18b4b4911d..410a202b329641 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h @@ -14,7 +14,7 @@ #define LLVM_EXECUTIONENGINE_ORC_EPCDEBUGOBJECTREGISTRAR_H #include "llvm/ExecutionEngine/JITSymbol.h" -#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" +#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h" #include "llvm/Support/Error.h" #include "llvm/Support/Memory.h" @@ -27,6 +27,8 @@ using namespace llvm::orc::shared; namespace llvm { namespace orc { +class ExecutionSession; + /// Abstract interface for registering debug objects in the executor process. class DebugObjectRegistrar { public: @@ -38,25 +40,20 @@ class DebugObjectRegistrar { /// executor process. class EPCDebugObjectRegistrar : public DebugObjectRegistrar { public: - EPCDebugObjectRegistrar(ExecutorProcessControl &EPC, - JITTargetAddress RegisterFn) - : EPC(EPC), RegisterFn(RegisterFn) {} + EPCDebugObjectRegistrar(ExecutionSession &ES, JITTargetAddress RegisterFn) + : ES(ES), RegisterFn(RegisterFn) {} - Error registerDebugObject(sys::MemoryBlock TargetMem) override { - return WrapperFunction::call( - EPCCaller(EPC, RegisterFn), pointerToJITTargetAddress(TargetMem.base()), - static_cast(TargetMem.allocatedSize())); - } + Error registerDebugObject(sys::MemoryBlock TargetMem) override; private: - ExecutorProcessControl &EPC; + ExecutionSession &ES; JITTargetAddress RegisterFn; }; /// Create a ExecutorProcessControl-based DebugObjectRegistrar that emits debug /// objects to the GDB JIT interface. Expected> -createJITLoaderGDBRegistrar(ExecutorProcessControl &EPC); +createJITLoaderGDBRegistrar(ExecutionSession &ES); } // end namespace orc } // end namespace llvm diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h index 08b5ab05ba761e..63797edec89e61 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h @@ -15,11 +15,13 @@ #define LLVM_EXECUTIONENGINE_ORC_EPCDYNAMICLIBRARYSEARCHGENERATOR_H #include "llvm/ADT/FunctionExtras.h" -#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" +#include "llvm/ExecutionEngine/Orc/Core.h" namespace llvm { namespace orc { +class ExecutorProcessControl; + class EPCDynamicLibrarySearchGenerator : public DefinitionGenerator { public: using SymbolPredicate = unique_function; @@ -30,24 +32,24 @@ class EPCDynamicLibrarySearchGenerator : public DefinitionGenerator { /// If the Allow predicate is given then only symbols matching the predicate /// will be searched for. If the predicate is not given then all symbols will /// be searched for. - EPCDynamicLibrarySearchGenerator(ExecutorProcessControl &EPC, + EPCDynamicLibrarySearchGenerator(ExecutionSession &ES, tpctypes::DylibHandle H, SymbolPredicate Allow = SymbolPredicate()) - : EPC(EPC), H(H), Allow(std::move(Allow)) {} + : EPC(ES.getExecutorProcessControl()), H(H), Allow(std::move(Allow)) {} /// Permanently loads the library at the given path and, on success, returns /// a DynamicLibrarySearchGenerator that will search it for symbol definitions /// in the library. On failure returns the reason the library failed to load. static Expected> - Load(ExecutorProcessControl &EPC, const char *LibraryPath, + Load(ExecutionSession &ES, const char *LibraryPath, SymbolPredicate Allow = SymbolPredicate()); /// Creates a EPCDynamicLibrarySearchGenerator that searches for symbols in /// the target process. static Expected> - GetForTargetProcess(ExecutorProcessControl &EPC, + GetForTargetProcess(ExecutionSession &ES, SymbolPredicate Allow = SymbolPredicate()) { - return Load(EPC, nullptr, std::move(Allow)); + return Load(ES, nullptr, std::move(Allow)); } Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCEHFrameRegistrar.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCEHFrameRegistrar.h index f230cfcac41675..8cd6e9319a287b 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/EPCEHFrameRegistrar.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCEHFrameRegistrar.h @@ -14,11 +14,12 @@ #define LLVM_EXECUTIONENGINE_ORC_EPCEHFRAMEREGISTRAR_H #include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h" -#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" namespace llvm { namespace orc { +class ExecutionSession; + /// Register/Deregisters EH frames in a remote process via a /// ExecutorProcessControl instance. class EPCEHFrameRegistrar : public jitlink::EHFrameRegistrar { @@ -27,14 +28,14 @@ class EPCEHFrameRegistrar : public jitlink::EHFrameRegistrar { /// the EPC's lookupSymbols method to find the registration/deregistration /// funciton addresses by name. static Expected> - Create(ExecutorProcessControl &EPC); + Create(ExecutionSession &ES); /// Create a EPCEHFrameRegistrar with the given ExecutorProcessControl /// object and registration/deregistration function addresses. - EPCEHFrameRegistrar(ExecutorProcessControl &EPC, + EPCEHFrameRegistrar(ExecutionSession &ES, JITTargetAddress RegisterEHFrameWrapperFnAddr, JITTargetAddress DeregisterEHFRameWrapperFnAddr) - : EPC(EPC), RegisterEHFrameWrapperFnAddr(RegisterEHFrameWrapperFnAddr), + : ES(ES), RegisterEHFrameWrapperFnAddr(RegisterEHFrameWrapperFnAddr), DeregisterEHFrameWrapperFnAddr(DeregisterEHFRameWrapperFnAddr) {} Error registerEHFrames(JITTargetAddress EHFrameSectionAddr, @@ -43,7 +44,7 @@ class EPCEHFrameRegistrar : public jitlink::EHFrameRegistrar { size_t EHFrameSectionSize) override; private: - ExecutorProcessControl &EPC; + ExecutionSession &ES; JITTargetAddress RegisterEHFrameWrapperFnAddr; JITTargetAddress DeregisterEHFrameWrapperFnAddr; }; diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h b/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h index f8d6192706a1d6..d540d0cd0608c6 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h @@ -17,10 +17,10 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" -#include "llvm/ExecutionEngine/Orc/Core.h" #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h" #include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h" +#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/MSVCErrorWorkarounds.h" @@ -31,22 +31,18 @@ namespace llvm { namespace orc { +class ExecutionSession; +class SymbolLookupSet; + /// ExecutorProcessControl supports interaction with a JIT target process. class ExecutorProcessControl { + friend class ExecutionSession; + public: /// Sender to return the result of a WrapperFunction executed in the JIT. using SendResultFunction = unique_function; - /// An asynchronous wrapper-function. - using AsyncWrapperFunction = unique_function; - - /// A map associating tag names with asynchronous wrapper function - /// implementations in the JIT. - using WrapperFunctionAssociationMap = - DenseMap; - /// APIs for manipulating memory in the target process. class MemoryAccess { public: @@ -123,6 +119,13 @@ class ExecutorProcessControl { virtual ~ExecutorProcessControl(); + /// Return the ExecutionSession associated with this instance. + /// Not callable until the ExecutionSession has been associated. + ExecutionSession &getExecutionSession() { + assert(ES && "No ExecutionSession associated yet"); + return *ES; + } + /// Intern a symbol name in the SymbolStringPool. SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); } @@ -139,10 +142,16 @@ class ExecutorProcessControl { const JITDispatchInfo &getJITDispatchInfo() const { return JDI; } /// Return a MemoryAccess object for the target process. - MemoryAccess &getMemoryAccess() const { return *MemAccess; } + MemoryAccess &getMemoryAccess() const { + assert(MemAccess && "No MemAccess object set."); + return *MemAccess; + } /// Return a JITLinkMemoryManager for the target process. - jitlink::JITLinkMemoryManager &getMemMgr() const { return *MemMgr; } + jitlink::JITLinkMemoryManager &getMemMgr() const { + assert(MemMgr && "No MemMgr object set"); + return *MemMgr; + } /// Load the dynamic library at the given path and return a handle to it. /// If LibraryPath is null this function will return the global handle for @@ -163,7 +172,7 @@ class ExecutorProcessControl { virtual Expected runAsMain(JITTargetAddress MainFnAddr, ArrayRef Args) = 0; - /// Run a wrapper function in the executor (async version). + /// Run a wrapper function in the executor. /// /// The wrapper function should be callable as: /// @@ -172,94 +181,9 @@ class ExecutorProcessControl { /// \endcode{.cpp} /// /// The given OnComplete function will be called to return the result. - virtual void runWrapperAsync(SendResultFunction OnComplete, - JITTargetAddress WrapperFnAddr, - ArrayRef ArgBuffer) = 0; - - /// Run a wrapper function in the executor. The wrapper function should be - /// callable as: - /// - /// \code{.cpp} - /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size); - /// \endcode{.cpp} - shared::WrapperFunctionResult runWrapper(JITTargetAddress WrapperFnAddr, - ArrayRef ArgBuffer) { - std::promise RP; - auto RF = RP.get_future(); - runWrapperAsync( - [&](shared::WrapperFunctionResult R) { RP.set_value(std::move(R)); }, - WrapperFnAddr, ArgBuffer); - return RF.get(); - } - - /// Run a wrapper function using SPS to serialize the arguments and - /// deserialize the results. - template - void runSPSWrapperAsync(SendResultT &&SendResult, - JITTargetAddress WrapperFnAddr, - const ArgTs &...Args) { - shared::WrapperFunction::callAsync( - [this, WrapperFnAddr](SendResultFunction SendResult, - const char *ArgData, size_t ArgSize) { - runWrapperAsync(std::move(SendResult), WrapperFnAddr, - ArrayRef(ArgData, ArgSize)); - }, - std::move(SendResult), Args...); - } - - /// Run a wrapper function using SPS to serialize the arguments and - /// deserialize the results. - /// - /// If SPSSignature is a non-void function signature then the second argument - /// (the first in the Args list) should be a reference to a return value. - template - Error runSPSWrapper(JITTargetAddress WrapperFnAddr, - WrapperCallArgTs &&...WrapperCallArgs) { - return shared::WrapperFunction::call( - [this, WrapperFnAddr](const char *ArgData, size_t ArgSize) { - return runWrapper(WrapperFnAddr, ArrayRef(ArgData, ArgSize)); - }, - std::forward(WrapperCallArgs)...); - } - - /// Wrap a handler that takes concrete argument types (and a sender for a - /// concrete return type) to produce an AsyncWrapperFunction. Uses SPS to - /// unpack the arguments and pack the result. - /// - /// This function is usually used when building association maps. - template - static AsyncWrapperFunction wrapAsyncWithSPS(HandlerT &&H) { - return [H = std::forward(H)](SendResultFunction SendResult, - const char *ArgData, - size_t ArgSize) mutable { - shared::WrapperFunction::handleAsync(ArgData, ArgSize, H, - std::move(SendResult)); - }; - } - - template - static AsyncWrapperFunction - wrapAsyncWithSPS(ClassT *Instance, void (ClassT::*Method)(MethodArgTs...)) { - return wrapAsyncWithSPS( - [Instance, Method](MethodArgTs &&...MethodArgs) { - (Instance->*Method)(std::forward(MethodArgs)...); - }); - } - - /// For each symbol name, associate the AsyncWrapperFunction implementation - /// value with the address of that symbol. - /// - /// Symbols will be looked up using LookupKind::Static, - /// JITDylibLookupFlags::MatchAllSymbols (hidden tags will be found), and - /// LookupFlags::WeaklyReferencedSymbol (missing tags will not cause an - /// error, the implementations will simply be dropped). - Error associateJITSideWrapperFunctions(JITDylib &JD, - WrapperFunctionAssociationMap WFs); - - /// Run a registered jit-side wrapper function. - void runJITSideWrapperFunction(SendResultFunction SendResult, - JITTargetAddress TagAddr, - ArrayRef ArgBuffer); + virtual void callWrapperAsync(SendResultFunction OnComplete, + JITTargetAddress WrapperFnAddr, + ArrayRef ArgBuffer) = 0; /// Disconnect from the target process. /// @@ -271,29 +195,49 @@ class ExecutorProcessControl { : SSP(std::move(SSP)) {} std::shared_ptr SSP; + ExecutionSession *ES = nullptr; Triple TargetTriple; unsigned PageSize = 0; JITDispatchInfo JDI; MemoryAccess *MemAccess = nullptr; jitlink::JITLinkMemoryManager *MemMgr = nullptr; - - std::mutex TagToFuncMapMutex; - DenseMap> TagToFunc; }; -/// Call a wrapper function via ExecutorProcessControl::runWrapper. -class EPCCaller { +/// A ExecutorProcessControl instance that asserts if any of its methods are +/// used. Suitable for use is unit tests, and by ORC clients who haven't moved +/// to ExecutorProcessControl-based APIs yet. +class UnsupportedExecutorProcessControl : public ExecutorProcessControl { public: - EPCCaller(ExecutorProcessControl &EPC, JITTargetAddress WrapperFnAddr) - : EPC(EPC), WrapperFnAddr(WrapperFnAddr) {} - shared::WrapperFunctionResult operator()(const char *ArgData, - size_t ArgSize) const { - return EPC.runWrapper(WrapperFnAddr, ArrayRef(ArgData, ArgSize)); + UnsupportedExecutorProcessControl( + std::shared_ptr SSP = nullptr, + const std::string &TT = "", unsigned PageSize = 0) + : ExecutorProcessControl(SSP ? std::move(SSP) + : std::make_shared()) { + this->TargetTriple = Triple(TT); + this->PageSize = PageSize; } -private: - ExecutorProcessControl &EPC; - JITTargetAddress WrapperFnAddr; + Expected loadDylib(const char *DylibPath) override { + llvm_unreachable("Unsupported"); + } + + Expected> + lookupSymbols(ArrayRef Request) override { + llvm_unreachable("Unsupported"); + } + + Expected runAsMain(JITTargetAddress MainFnAddr, + ArrayRef Args) override { + llvm_unreachable("Unsupported"); + } + + void callWrapperAsync(SendResultFunction OnComplete, + JITTargetAddress WrapperFnAddr, + ArrayRef ArgBuffer) override { + llvm_unreachable("Unsupported"); + } + + Error disconnect() override { return Error::success(); } }; /// A ExecutorProcessControl implementation targeting the current process. @@ -305,11 +249,13 @@ class SelfExecutorProcessControl std::shared_ptr SSP, Triple TargetTriple, unsigned PageSize, std::unique_ptr MemMgr); - /// Create a SelfExecutorProcessControl with the given memory manager. + /// Create a SelfExecutorProcessControl with the given symbol string pool and + /// memory manager. + /// If no symbol string pool is given then one will be created. /// If no memory manager is given a jitlink::InProcessMemoryManager will - /// be used by default. + /// be created and used by default. static Expected> - Create(std::shared_ptr SSP, + Create(std::shared_ptr SSP = nullptr, std::unique_ptr MemMgr = nullptr); Expected loadDylib(const char *DylibPath) override; @@ -320,9 +266,9 @@ class SelfExecutorProcessControl Expected runAsMain(JITTargetAddress MainFnAddr, ArrayRef Args) override; - void runWrapperAsync(SendResultFunction OnComplete, - JITTargetAddress WrapperFnAddr, - ArrayRef ArgBuffer) override; + void callWrapperAsync(SendResultFunction OnComplete, + JITTargetAddress WrapperFnAddr, + ArrayRef ArgBuffer) override; Error disconnect() override; diff --git a/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h b/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h index cc23147aac388a..d76e6a21a9bb69 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h @@ -260,6 +260,7 @@ class LLJITBuilderState { using PlatformSetupFunction = std::function; + std::unique_ptr EPC; std::unique_ptr ES; Optional JTMB; Optional DL; @@ -267,7 +268,6 @@ class LLJITBuilderState { CompileFunctionCreator CreateCompileFunction; PlatformSetupFunction SetUpPlatform; unsigned NumCompileThreads = 0; - ExecutorProcessControl *EPC = nullptr; /// Called prior to JIT class construcion to fix up defaults. Error prepareForConstruction(); @@ -276,6 +276,17 @@ class LLJITBuilderState { template class LLJITBuilderSetters { public: + /// Set a ExecutorProcessControl for this instance. + /// This should not be called if ExecutionSession has already been set. + SetterImpl & + setExecutorProcessControl(std::unique_ptr EPC) { + assert( + !impl().ES && + "setExecutorProcessControl should not be called if an ExecutionSession " + "has already been set"); + impl().EPC = std::move(EPC); + return impl(); + } /// Set an ExecutionSession for this instance. SetterImpl &setExecutionSession(std::unique_ptr ES) { diff --git a/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h b/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h index 8b228a52244d1b..f77dfd208413ca 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h @@ -97,13 +97,11 @@ class MachOPlatform : public Platform { /// setting up all aliases (including the required ones). static Expected> Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, - ExecutorProcessControl &EPC, JITDylib &PlatformJD, - const char *OrcRuntimePath, + JITDylib &PlatformJD, const char *OrcRuntimePath, Optional RuntimeAliases = None); ExecutionSession &getExecutionSession() const { return ES; } ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; } - ExecutorProcessControl &getExecutorProcessControl() const { return EPC; } Error setupJITDylib(JITDylib &JD) override; Error notifyAdding(ResourceTracker &RT, @@ -193,7 +191,7 @@ class MachOPlatform : public Platform { static bool supportedTarget(const Triple &TT); MachOPlatform(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, - ExecutorProcessControl &EPC, JITDylib &PlatformJD, + JITDylib &PlatformJD, std::unique_ptr OrcRuntimeGenerator, Error &Err); @@ -228,7 +226,6 @@ class MachOPlatform : public Platform { ExecutionSession &ES; ObjectLinkingLayer &ObjLinkingLayer; - ExecutorProcessControl &EPC; SymbolStringPtr MachOHeaderStartSymbol; std::atomic RuntimeBootstrapped{false}; diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h index 4737fe80ba3ea8..5632118eee4e44 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h @@ -101,7 +101,11 @@ class ObjectLinkingLayer : public RTTIExtends, using ReturnObjectBufferFunction = std::function)>; - /// Construct an ObjectLinkingLayer. + /// Construct an ObjectLinkingLayer using the ExecutorProcessControl + /// instance's memory manager. + ObjectLinkingLayer(ExecutionSession &ES); + + /// Construct an ObjectLinkingLayer using a custom memory manager. ObjectLinkingLayer(ExecutionSession &ES, jitlink::JITLinkMemoryManager &MemMgr); diff --git a/llvm/include/llvm/ExecutionEngine/Orc/OrcRPCExecutorProcessControl.h b/llvm/include/llvm/ExecutionEngine/Orc/OrcRPCExecutorProcessControl.h index fedd79c93146ee..4310ba9ce9e0e7 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/OrcRPCExecutorProcessControl.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/OrcRPCExecutorProcessControl.h @@ -358,9 +358,9 @@ class OrcRPCExecutorProcessControlBase : public ExecutorProcessControl { return Result; } - void runWrapperAsync(SendResultFunction OnComplete, - JITTargetAddress WrapperFnAddr, - ArrayRef ArgBuffer) override { + void callWrapperAsync(SendResultFunction OnComplete, + JITTargetAddress WrapperFnAddr, + ArrayRef ArgBuffer) override { DEBUG_WITH_TYPE("orc", { dbgs() << "Running as wrapper function " << formatv("{0:x16}", WrapperFnAddr) << " with " @@ -415,7 +415,7 @@ class OrcRPCExecutorProcessControlBase : public ExecutorProcessControl { std::function)> SendResult, JITTargetAddress FunctionTag, std::vector ArgBuffer) { - runJITSideWrapperFunction( + getExecutionSession().runJITDispatchHandler( [this, SendResult = std::move(SendResult)]( Expected R) { if (auto Err = SendResult(std::move(R))) diff --git a/llvm/lib/ExecutionEngine/Orc/Core.cpp b/llvm/lib/ExecutionEngine/Orc/Core.cpp index c613c57c15f87f..12a501f7f98c6f 100644 --- a/llvm/lib/ExecutionEngine/Orc/Core.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Core.cpp @@ -1802,8 +1802,11 @@ void MaterializationTask::printDescription(raw_ostream &OS) { void MaterializationTask::run() { MU->materialize(std::move(MR)); } -ExecutionSession::ExecutionSession(std::shared_ptr SSP) - : SSP(SSP ? std::move(SSP) : std::make_shared()) {} +ExecutionSession::ExecutionSession(std::unique_ptr EPC) + : EPC(std::move(EPC)) { + // Associated EPC and this. + this->EPC->ES = this; +} Error ExecutionSession::endSession() { LLVM_DEBUG(dbgs() << "Ending ExecutionSession " << this << "\n"); @@ -1818,6 +1821,9 @@ Error ExecutionSession::endSession() { Error Err = Error::success(); for (auto &JD : JITDylibsToClose) Err = joinErrors(std::move(Err), JD->clear()); + + Err = joinErrors(std::move(Err), EPC->disconnect()); + return Err; } @@ -2048,6 +2054,58 @@ ExecutionSession::lookup(ArrayRef SearchOrder, StringRef Name, return lookup(SearchOrder, intern(Name), RequiredState); } +Error ExecutionSession::registerJITDispatchHandlers( + JITDylib &JD, JITDispatchHandlerAssociationMap WFs) { + + auto TagAddrs = lookup({{&JD, JITDylibLookupFlags::MatchAllSymbols}}, + SymbolLookupSet::fromMapKeys( + WFs, SymbolLookupFlags::WeaklyReferencedSymbol)); + if (!TagAddrs) + return TagAddrs.takeError(); + + // Associate tag addresses with implementations. + std::lock_guard Lock(JITDispatchHandlersMutex); + for (auto &KV : *TagAddrs) { + auto TagAddr = KV.second.getAddress(); + if (JITDispatchHandlers.count(TagAddr)) + return make_error("Tag " + formatv("{0:x16}", TagAddr) + + " (for " + *KV.first + + ") already registered", + inconvertibleErrorCode()); + auto I = WFs.find(KV.first); + assert(I != WFs.end() && I->second && + "JITDispatchHandler implementation missing"); + JITDispatchHandlers[KV.second.getAddress()] = + std::make_shared(std::move(I->second)); + LLVM_DEBUG({ + dbgs() << "Associated function tag \"" << *KV.first << "\" (" + << formatv("{0:x}", KV.second.getAddress()) << ") with handler\n"; + }); + } + return Error::success(); +} + +void ExecutionSession::runJITDispatchHandler( + ExecutorProcessControl::SendResultFunction SendResult, + JITTargetAddress HandlerFnTagAddr, ArrayRef ArgBuffer) { + + std::shared_ptr F; + { + std::lock_guard Lock(JITDispatchHandlersMutex); + auto I = JITDispatchHandlers.find(HandlerFnTagAddr); + if (I != JITDispatchHandlers.end()) + F = I->second; + } + + if (F) + (*F)(std::move(SendResult), ArgBuffer.data(), ArgBuffer.size()); + else + SendResult(shared::WrapperFunctionResult::createOutOfBandError( + ("No function registered for tag " + + formatv("{0:x16}", HandlerFnTagAddr)) + .str())); +} + void ExecutionSession::dump(raw_ostream &OS) { runSessionLocked([this, &OS]() { for (auto &JD : JDs) diff --git a/llvm/lib/ExecutionEngine/Orc/EPCDebugObjectRegistrar.cpp b/llvm/lib/ExecutionEngine/Orc/EPCDebugObjectRegistrar.cpp index 803cf96f5bddf3..5715eda71eee23 100644 --- a/llvm/lib/ExecutionEngine/Orc/EPCDebugObjectRegistrar.cpp +++ b/llvm/lib/ExecutionEngine/Orc/EPCDebugObjectRegistrar.cpp @@ -9,6 +9,7 @@ #include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h" #include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h" #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h" #include "llvm/Support/BinaryStreamWriter.h" @@ -16,7 +17,8 @@ namespace llvm { namespace orc { Expected> -createJITLoaderGDBRegistrar(ExecutorProcessControl &EPC) { +createJITLoaderGDBRegistrar(ExecutionSession &ES) { + auto &EPC = ES.getExecutorProcessControl(); auto ProcessHandle = EPC.loadDylib(nullptr); if (!ProcessHandle) return ProcessHandle.takeError(); @@ -37,7 +39,13 @@ createJITLoaderGDBRegistrar(ExecutorProcessControl &EPC) { assert((*Result)[0].size() == 1 && "Unexpected number of addresses in result"); - return std::make_unique(EPC, (*Result)[0][0]); + return std::make_unique(ES, (*Result)[0][0]); +} + +Error EPCDebugObjectRegistrar::registerDebugObject(sys::MemoryBlock TargetMem) { + return ES.callSPSWrapper( + RegisterFn, ExecutorAddress::fromPtr(TargetMem.base()), + static_cast(TargetMem.allocatedSize())); } } // namespace orc diff --git a/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp b/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp index 9958a52f0e44cc..ba154aaecd1aab 100644 --- a/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp +++ b/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp @@ -12,14 +12,14 @@ namespace llvm { namespace orc { Expected> -EPCDynamicLibrarySearchGenerator::Load(ExecutorProcessControl &EPC, +EPCDynamicLibrarySearchGenerator::Load(ExecutionSession &ES, const char *LibraryPath, SymbolPredicate Allow) { - auto Handle = EPC.loadDylib(LibraryPath); + auto Handle = ES.getExecutorProcessControl().loadDylib(LibraryPath); if (!Handle) return Handle.takeError(); - return std::make_unique(EPC, *Handle, + return std::make_unique(ES, *Handle, std::move(Allow)); } diff --git a/llvm/lib/ExecutionEngine/Orc/EPCEHFrameRegistrar.cpp b/llvm/lib/ExecutionEngine/Orc/EPCEHFrameRegistrar.cpp index 4bfcf132c8f7ee..8cdda9ab5a15fe 100644 --- a/llvm/lib/ExecutionEngine/Orc/EPCEHFrameRegistrar.cpp +++ b/llvm/lib/ExecutionEngine/Orc/EPCEHFrameRegistrar.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/Orc/EPCEHFrameRegistrar.h" + +#include "llvm/ExecutionEngine/Orc/Core.h" #include "llvm/Support/BinaryStreamWriter.h" using namespace llvm::orc::shared; @@ -15,12 +17,13 @@ namespace llvm { namespace orc { Expected> -EPCEHFrameRegistrar::Create(ExecutorProcessControl &EPC) { +EPCEHFrameRegistrar::Create(ExecutionSession &ES) { // FIXME: Proper mangling here -- we really need to decouple linker mangling // from DataLayout. // Find the addresses of the registration/deregistration functions in the // executor process. + auto &EPC = ES.getExecutorProcessControl(); auto ProcessHandle = EPC.loadDylib(nullptr); if (!ProcessHandle) return ProcessHandle.takeError(); @@ -48,22 +51,21 @@ EPCEHFrameRegistrar::Create(ExecutorProcessControl &EPC) { auto RegisterEHFrameWrapperFnAddr = (*Result)[0][0]; auto DeregisterEHFrameWrapperFnAddr = (*Result)[0][1]; - return std::make_unique( - EPC, RegisterEHFrameWrapperFnAddr, DeregisterEHFrameWrapperFnAddr); + return std::make_unique(ES, RegisterEHFrameWrapperFnAddr, + DeregisterEHFrameWrapperFnAddr); } Error EPCEHFrameRegistrar::registerEHFrames(JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) { - - return WrapperFunction::call( - EPCCaller(EPC, RegisterEHFrameWrapperFnAddr), EHFrameSectionAddr, + return ES.callSPSWrapper( + RegisterEHFrameWrapperFnAddr, EHFrameSectionAddr, static_cast(EHFrameSectionSize)); } Error EPCEHFrameRegistrar::deregisterEHFrames( JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) { - return WrapperFunction::call( - EPCCaller(EPC, DeregisterEHFrameWrapperFnAddr), EHFrameSectionAddr, + return ES.callSPSWrapper( + DeregisterEHFrameWrapperFnAddr, EHFrameSectionAddr, static_cast(EHFrameSectionSize)); } diff --git a/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp b/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp index 9442eab2997088..7d86d125d1db28 100644 --- a/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp @@ -23,60 +23,6 @@ ExecutorProcessControl::MemoryAccess::~MemoryAccess() {} ExecutorProcessControl::~ExecutorProcessControl() {} -Error ExecutorProcessControl::associateJITSideWrapperFunctions( - JITDylib &JD, WrapperFunctionAssociationMap WFs) { - - // Look up tag addresses. - auto &ES = JD.getExecutionSession(); - auto TagAddrs = - ES.lookup({{&JD, JITDylibLookupFlags::MatchAllSymbols}}, - SymbolLookupSet::fromMapKeys( - WFs, SymbolLookupFlags::WeaklyReferencedSymbol)); - if (!TagAddrs) - return TagAddrs.takeError(); - - // Associate tag addresses with implementations. - std::lock_guard Lock(TagToFuncMapMutex); - for (auto &KV : *TagAddrs) { - auto TagAddr = KV.second.getAddress(); - if (TagToFunc.count(TagAddr)) - return make_error("Tag " + formatv("{0:x16}", TagAddr) + - " (for " + *KV.first + - ") already registered", - inconvertibleErrorCode()); - auto I = WFs.find(KV.first); - assert(I != WFs.end() && I->second && - "AsyncWrapperFunction implementation missing"); - TagToFunc[KV.second.getAddress()] = - std::make_shared(std::move(I->second)); - LLVM_DEBUG({ - dbgs() << "Associated function tag \"" << *KV.first << "\" (" - << formatv("{0:x}", KV.second.getAddress()) << ") with handler\n"; - }); - } - return Error::success(); -} - -void ExecutorProcessControl::runJITSideWrapperFunction( - SendResultFunction SendResult, JITTargetAddress TagAddr, - ArrayRef ArgBuffer) { - - std::shared_ptr F; - { - std::lock_guard Lock(TagToFuncMapMutex); - auto I = TagToFunc.find(TagAddr); - if (I != TagToFunc.end()) - F = I->second; - } - - if (F) - (*F)(std::move(SendResult), ArgBuffer.data(), ArgBuffer.size()); - else - SendResult(shared::WrapperFunctionResult::createOutOfBandError( - ("No function registered for tag " + formatv("{0:x16}", TagAddr)) - .str())); -} - SelfExecutorProcessControl::SelfExecutorProcessControl( std::shared_ptr SSP, Triple TargetTriple, unsigned PageSize, std::unique_ptr MemMgr) @@ -100,6 +46,10 @@ Expected> SelfExecutorProcessControl::Create( std::shared_ptr SSP, std::unique_ptr MemMgr) { + + if (!SSP) + SSP = std::make_shared(); + auto PageSize = sys::Process::getPageSize(); if (!PageSize) return PageSize.takeError(); @@ -159,9 +109,9 @@ SelfExecutorProcessControl::runAsMain(JITTargetAddress MainFnAddr, return orc::runAsMain(jitTargetAddressToFunction(MainFnAddr), Args); } -void SelfExecutorProcessControl::runWrapperAsync(SendResultFunction SendResult, - JITTargetAddress WrapperFnAddr, - ArrayRef ArgBuffer) { +void SelfExecutorProcessControl::callWrapperAsync( + SendResultFunction SendResult, JITTargetAddress WrapperFnAddr, + ArrayRef ArgBuffer) { using WrapperFnTy = shared::detail::CWrapperFunctionResult (*)(const char *Data, size_t Size); auto *WrapperFn = jitTargetAddressToFunction(WrapperFnAddr); @@ -217,12 +167,14 @@ SelfExecutorProcessControl::jitDispatchViaWrapperFunctionManager( std::promise ResultP; auto ResultF = ResultP.get_future(); - static_cast(Ctx)->runJITSideWrapperFunction( - [ResultP = - std::move(ResultP)](shared::WrapperFunctionResult Result) mutable { - ResultP.set_value(std::move(Result)); - }, - pointerToJITTargetAddress(FnTag), {Data, Size}); + static_cast(Ctx) + ->getExecutionSession() + .runJITDispatchHandler( + [ResultP = std::move(ResultP)]( + shared::WrapperFunctionResult Result) mutable { + ResultP.set_value(std::move(Result)); + }, + pointerToJITTargetAddress(FnTag), {Data, Size}); return ResultF.get().release(); } diff --git a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp index 2d1f394a5fb97a..2ac32293e4dba4 100644 --- a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp +++ b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp @@ -575,6 +575,22 @@ Error LLJITBuilderState::prepareForConstruction() { dbgs() << "\n"; }); + // If neither ES nor EPC has been set then create an EPC instance. + if (!ES && !EPC) { + LLVM_DEBUG({ + dbgs() << "ExecutorProcessControl not specified, " + "Creating SelfExecutorProcessControl instance\n"; + }); + if (auto EPCOrErr = SelfExecutorProcessControl::Create()) + EPC = std::move(*EPCOrErr); + else + return EPCOrErr.takeError(); + } else + LLVM_DEBUG({ + dbgs() << "Using explicitly specified ExecutorProcessControl instance " + << EPC.get() << "\n"; + }); + // If the client didn't configure any linker options then auto-configure the // JIT linker. if (!CreateObjectLinkingLayer) { @@ -585,16 +601,9 @@ Error LLJITBuilderState::prepareForConstruction() { JTMB->setRelocationModel(Reloc::PIC_); JTMB->setCodeModel(CodeModel::Small); CreateObjectLinkingLayer = - [EPC = this->EPC]( - ExecutionSession &ES, - const Triple &) -> Expected> { - std::unique_ptr ObjLinkingLayer; - if (EPC) - ObjLinkingLayer = - std::make_unique(ES, EPC->getMemMgr()); - else - ObjLinkingLayer = std::make_unique( - ES, std::make_unique()); + [](ExecutionSession &ES, + const Triple &) -> Expected> { + auto ObjLinkingLayer = std::make_unique(ES); ObjLinkingLayer->addPlugin(std::make_unique( ES, std::make_unique())); return std::move(ObjLinkingLayer); @@ -688,11 +697,25 @@ LLJIT::createCompileFunction(LLJITBuilderState &S, } LLJIT::LLJIT(LLJITBuilderState &S, Error &Err) - : ES(S.ES ? std::move(S.ES) : std::make_unique()), Main(), - DL(""), TT(S.JTMB->getTargetTriple()) { + : DL(""), TT(S.JTMB->getTargetTriple()) { ErrorAsOutParameter _(&Err); + assert(!(S.EPC && S.ES) && "EPC and ES should not both be set"); + + if (S.EPC) { + ES = std::make_unique(std::move(S.EPC)); + } else if (S.ES) + ES = std::move(S.ES); + else { + if (auto EPC = SelfExecutorProcessControl::Create()) { + ES = std::make_unique(std::move(*EPC)); + } else { + Err = EPC.takeError(); + return; + } + } + if (auto MainOrErr = this->ES->createJITDylib("main")) Main = &*MainOrErr; else { diff --git a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp index 986f39a8832801..66ef835dc34da3 100644 --- a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp +++ b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp @@ -36,8 +36,10 @@ class MachOHeaderMaterializationUnit : public MaterializationUnit { void materialize(std::unique_ptr R) override { unsigned PointerSize; support::endianness Endianness; + const auto &TT = + MOP.getExecutionSession().getExecutorProcessControl().getTargetTriple(); - switch (MOP.getExecutorProcessControl().getTargetTriple().getArch()) { + switch (TT.getArch()) { case Triple::aarch64: case Triple::x86_64: PointerSize = 8; @@ -48,8 +50,8 @@ class MachOHeaderMaterializationUnit : public MaterializationUnit { } auto G = std::make_unique( - "", MOP.getExecutorProcessControl().getTargetTriple(), - PointerSize, Endianness, jitlink::getGenericEdgeKindName); + "", TT, PointerSize, Endianness, + jitlink::getGenericEdgeKindName); auto &HeaderSection = G->createSection("__header", sys::Memory::MF_READ); auto &HeaderBlock = createHeaderBlock(*G, HeaderSection); @@ -148,10 +150,11 @@ namespace orc { Expected> MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, - ExecutorProcessControl &EPC, JITDylib &PlatformJD, - const char *OrcRuntimePath, + JITDylib &PlatformJD, const char *OrcRuntimePath, Optional RuntimeAliases) { + auto &EPC = ES.getExecutorProcessControl(); + // If the target is not supported then bail out immediately. if (!supportedTarget(EPC.getTargetTriple())) return make_error("Unsupported MachOPlatform triple: " + @@ -185,7 +188,7 @@ MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, // Create the instance. Error Err = Error::success(); auto P = std::unique_ptr( - new MachOPlatform(ES, ObjLinkingLayer, EPC, PlatformJD, + new MachOPlatform(ES, ObjLinkingLayer, PlatformJD, std::move(*OrcRuntimeArchiveGenerator), Err)); if (Err) return std::move(Err); @@ -273,9 +276,9 @@ bool MachOPlatform::supportedTarget(const Triple &TT) { MachOPlatform::MachOPlatform( ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, - ExecutorProcessControl &EPC, JITDylib &PlatformJD, + JITDylib &PlatformJD, std::unique_ptr OrcRuntimeGenerator, Error &Err) - : ES(ES), ObjLinkingLayer(ObjLinkingLayer), EPC(EPC), + : ES(ES), ObjLinkingLayer(ObjLinkingLayer), MachOHeaderStartSymbol(ES.intern("___dso_handle")) { ErrorAsOutParameter _(&Err); @@ -309,27 +312,27 @@ MachOPlatform::MachOPlatform( } Error MachOPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) { - ExecutorProcessControl::WrapperFunctionAssociationMap WFs; + ExecutionSession::JITDispatchHandlerAssociationMap WFs; using GetInitializersSPSSig = SPSExpected(SPSString); WFs[ES.intern("___orc_rt_macho_get_initializers_tag")] = - EPC.wrapAsyncWithSPS( + ES.wrapAsyncWithSPS( this, &MachOPlatform::rt_getInitializers); using GetDeinitializersSPSSig = SPSExpected(SPSExecutorAddress); WFs[ES.intern("___orc_rt_macho_get_deinitializers_tag")] = - EPC.wrapAsyncWithSPS( + ES.wrapAsyncWithSPS( this, &MachOPlatform::rt_getDeinitializers); using LookupSymbolSPSSig = SPSExpected(SPSExecutorAddress, SPSString); WFs[ES.intern("___orc_rt_macho_symbol_lookup_tag")] = - EPC.wrapAsyncWithSPS(this, - &MachOPlatform::rt_lookupSymbol); + ES.wrapAsyncWithSPS(this, + &MachOPlatform::rt_lookupSymbol); - return EPC.associateJITSideWrapperFunctions(PlatformJD, std::move(WFs)); + return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs)); } void MachOPlatform::getInitializersBuildSequencePhase( @@ -520,7 +523,7 @@ Error MachOPlatform::bootstrapMachORuntime(JITDylib &PlatformJD) { } if (auto Err = - EPC.runSPSWrapper(orc_rt_macho_platform_bootstrap.getValue())) + ES.callSPSWrapper(orc_rt_macho_platform_bootstrap.getValue())) return Err; // FIXME: Ordering is fuzzy here. We're probably best off saying @@ -589,7 +592,7 @@ Error MachOPlatform::registerPerObjectSections( inconvertibleErrorCode()); Error ErrResult = Error::success(); - if (auto Err = EPC.runSPSWrapper( orc_rt_macho_register_object_sections.getValue(), ErrResult, POSR)) return Err; @@ -604,7 +607,7 @@ Expected MachOPlatform::createPThreadKey() { inconvertibleErrorCode()); Expected Result(0); - if (auto Err = EPC.runSPSWrapper(void)>( + if (auto Err = ES.callSPSWrapper(void)>( orc_rt_macho_create_pthread_key.getValue(), Result)) return std::move(Err); return Result; diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp index 41769170ca7163..fd260089c04ba9 100644 --- a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp @@ -607,6 +607,11 @@ char ObjectLinkingLayer::ID; using BaseT = RTTIExtends; +ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession &ES) + : BaseT(ES), MemMgr(ES.getExecutorProcessControl().getMemMgr()) { + ES.registerResourceManager(*this); +} + ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession &ES, JITLinkMemoryManager &MemMgr) : BaseT(ES), MemMgr(MemMgr) { diff --git a/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp b/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp index e6fdd065b9958e..d6f73a8b0864ca 100644 --- a/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp +++ b/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp @@ -293,7 +293,8 @@ void LLVMOrcExecutionSessionSetErrorReporter( LLVMOrcSymbolStringPoolRef LLVMOrcExecutionSessionGetSymbolStringPool(LLVMOrcExecutionSessionRef ES) { - return wrap(unwrap(ES)->getSymbolStringPool().get()); + return wrap( + unwrap(ES)->getExecutorProcessControl().getSymbolStringPool().get()); } void LLVMOrcSymbolStringPoolClearDeadEntries(LLVMOrcSymbolStringPoolRef SSP) { diff --git a/llvm/tools/lli/lli.cpp b/llvm/tools/lli/lli.cpp index 50917a92b3be4a..af614c01b9a881 100644 --- a/llvm/tools/lli/lli.cpp +++ b/llvm/tools/lli/lli.cpp @@ -717,7 +717,8 @@ int main(int argc, char **argv, char * const *envp) { } // Create a remote target client running over the channel. - llvm::orc::ExecutionSession ES; + llvm::orc::ExecutionSession ES( + std::make_unique()); ES.setErrorReporter([&](Error Err) { ExitOnErr(std::move(Err)); }); typedef orc::remote::OrcRemoteTargetClient MyRemote; auto R = ExitOnErr(MyRemote::Create(*C, ES)); @@ -874,7 +875,8 @@ int runOrcJIT(const char *ProgName) { // JIT builder to instantiate a default (which would fail with an error for // unsupported architectures). if (UseJITKind != JITKind::OrcLazy) { - auto ES = std::make_unique(); + auto ES = std::make_unique( + ExitOnErr(orc::SelfExecutorProcessControl::Create())); Builder.setLazyCallthroughManager( std::make_unique(*ES, 0, nullptr)); Builder.setExecutionSession(std::move(ES)); @@ -934,9 +936,9 @@ int runOrcJIT(const char *ProgName) { const Triple &) { auto L = std::make_unique(ES, EPC->getMemMgr()); L->addPlugin(std::make_unique( - ES, ExitOnErr(orc::EPCEHFrameRegistrar::Create(*EPC)))); + ES, ExitOnErr(orc::EPCEHFrameRegistrar::Create(ES)))); L->addPlugin(std::make_unique( - ES, ExitOnErr(orc::createJITLoaderGDBRegistrar(*EPC)))); + ES, ExitOnErr(orc::createJITLoaderGDBRegistrar(ES)))); return L; }); } diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp index 6e03d63cbf7507..8bd384ec746fc8 100644 --- a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp +++ b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp @@ -621,7 +621,7 @@ static Error loadProcessSymbols(Session &S) { }; S.MainJD->addGenerator( ExitOnErr(orc::EPCDynamicLibrarySearchGenerator::GetForTargetProcess( - *S.EPC, std::move(FilterMainEntryPoint)))); + S.ES, std::move(FilterMainEntryPoint)))); return Error::success(); } @@ -630,7 +630,7 @@ static Error loadDylibs(Session &S) { LLVM_DEBUG(dbgs() << "Loading dylibs...\n"); for (const auto &Dylib : Dylibs) { LLVM_DEBUG(dbgs() << " " << Dylib << "\n"); - auto G = orc::EPCDynamicLibrarySearchGenerator::Load(*S.EPC, Dylib.c_str()); + auto G = orc::EPCDynamicLibrarySearchGenerator::Load(S.ES, Dylib.c_str()); if (!G) return G.takeError(); S.MainJD->addGenerator(std::move(*G)); @@ -880,13 +880,11 @@ Expected> Session::Create(Triple TT) { Session::~Session() { if (auto Err = ES.endSession()) ES.reportError(std::move(Err)); - if (auto Err = EPC->disconnect()) - ES.reportError(std::move(Err)); } Session::Session(std::unique_ptr EPC, Error &Err) - : EPC(std::move(EPC)), ES(this->EPC->getSymbolStringPool()), - ObjLayer(*this, this->EPC->getMemMgr()) { + : ES(std::move(EPC)), + ObjLayer(*this, ES.getExecutorProcessControl().getMemMgr()) { /// Local ObjectLinkingLayer::Plugin class to forward modifyPassConfig to the /// Session. @@ -925,20 +923,20 @@ Session::Session(std::unique_ptr EPC, Error &Err) ExitOnErr(loadDylibs(*this)); // Set up the platform. - if (this->EPC->getTargetTriple().isOSBinFormatMachO() && UseOrcRuntime) { - if (auto P = MachOPlatform::Create(ES, ObjLayer, *this->EPC, *MainJD, + auto &TT = ES.getExecutorProcessControl().getTargetTriple(); + if (TT.isOSBinFormatMachO() && UseOrcRuntime) { + if (auto P = MachOPlatform::Create(ES, ObjLayer, *MainJD, OrcRuntimePath.c_str())) ES.setPlatform(std::move(*P)); else { Err = P.takeError(); return; } - } else if (!NoExec && !this->EPC->getTargetTriple().isOSWindows() && - !this->EPC->getTargetTriple().isOSBinFormatMachO()) { + } else if (!NoExec && !TT.isOSWindows() && !TT.isOSBinFormatMachO()) { ObjLayer.addPlugin(std::make_unique( - ES, ExitOnErr(EPCEHFrameRegistrar::Create(*this->EPC)))); + ES, ExitOnErr(EPCEHFrameRegistrar::Create(this->ES)))); ObjLayer.addPlugin(std::make_unique( - ES, ExitOnErr(createJITLoaderGDBRegistrar(*this->EPC)))); + ES, ExitOnErr(createJITLoaderGDBRegistrar(this->ES)))); } ObjLayer.addPlugin(std::make_unique(*this)); @@ -985,10 +983,11 @@ void Session::modifyPassConfig(const Triple &TT, PassConfiguration &PassConfig) { if (!CheckFiles.empty()) PassConfig.PostFixupPasses.push_back([this](LinkGraph &G) { - if (EPC->getTargetTriple().getObjectFormat() == Triple::ELF) + auto &EPC = ES.getExecutorProcessControl(); + if (EPC.getTargetTriple().getObjectFormat() == Triple::ELF) return registerELFGraphInfo(*this, G); - if (EPC->getTargetTriple().getObjectFormat() == Triple::MachO) + if (EPC.getTargetTriple().getObjectFormat() == Triple::MachO) return registerMachOGraphInfo(*this, G); return make_error("Unsupported object format for GOT/stub " @@ -1269,7 +1268,8 @@ static Error loadObjects(Session &S) { if (Magic == file_magic::archive || Magic == file_magic::macho_universal_binary) JD.addGenerator(ExitOnErr(StaticLibraryDefinitionGenerator::Load( - S.ObjLayer, InputFile.c_str(), S.EPC->getTargetTriple()))); + S.ObjLayer, InputFile.c_str(), + S.ES.getExecutorProcessControl().getTargetTriple()))); else ExitOnErr(S.ObjLayer.add(JD, std::move(ObjBuffer))); } @@ -1316,13 +1316,14 @@ static Error loadObjects(Session &S) { } static Error runChecks(Session &S) { + const auto &TT = S.ES.getExecutorProcessControl().getTargetTriple(); if (CheckFiles.empty()) return Error::success(); LLVM_DEBUG(dbgs() << "Running checks...\n"); - auto TripleName = S.EPC->getTargetTriple().str(); + auto TripleName = TT.str(); std::string ErrorStr; const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, ErrorStr); if (!TheTarget) @@ -1388,9 +1389,8 @@ static Error runChecks(Session &S) { RuntimeDyldChecker Checker( IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo, - S.EPC->getTargetTriple().isLittleEndian() ? support::little - : support::big, - Disassembler.get(), InstPrinter.get(), dbgs()); + TT.isLittleEndian() ? support::little : support::big, Disassembler.get(), + InstPrinter.get(), dbgs()); std::string CheckLineStart = "# " + CheckName + ":"; for (auto &CheckFile : CheckFiles) { @@ -1423,7 +1423,8 @@ static Expected getMainEntryPoint(Session &S) { static Expected getOrcRuntimeEntryPoint(Session &S) { std::string RuntimeEntryPoint = "__orc_rt_run_program_wrapper"; - if (S.EPC->getTargetTriple().getObjectFormat() == Triple::MachO) + const auto &TT = S.ES.getExecutorProcessControl().getTargetTriple(); + if (TT.getObjectFormat() == Triple::MachO) RuntimeEntryPoint = '_' + RuntimeEntryPoint; return S.ES.lookup(S.JDSearchOrder, RuntimeEntryPoint); } @@ -1431,13 +1432,14 @@ static Expected getOrcRuntimeEntryPoint(Session &S) { static Expected runWithRuntime(Session &S, JITTargetAddress EntryPointAddress) { StringRef DemangledEntryPoint = EntryPointName; - if (S.EPC->getTargetTriple().getObjectFormat() == Triple::MachO && + const auto &TT = S.ES.getExecutorProcessControl().getTargetTriple(); + if (TT.getObjectFormat() == Triple::MachO && DemangledEntryPoint.front() == '_') DemangledEntryPoint = DemangledEntryPoint.drop_front(); using SPSRunProgramSig = int64_t(SPSString, SPSString, SPSSequence); int64_t Result; - if (auto Err = S.EPC->runSPSWrapper( + if (auto Err = S.ES.callSPSWrapper( EntryPointAddress, Result, S.MainJD->getName(), DemangledEntryPoint, static_cast &>(InputArgv))) return std::move(Err); @@ -1446,7 +1448,8 @@ static Expected runWithRuntime(Session &S, static Expected runWithoutRuntime(Session &S, JITTargetAddress EntryPointAddress) { - return S.EPC->runAsMain(EntryPointAddress, InputArgv); + return S.ES.getExecutorProcessControl().runAsMain(EntryPointAddress, + InputArgv); } namespace { diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink.h b/llvm/tools/llvm-jitlink/llvm-jitlink.h index 5050b2fef7570f..acb64a9a39ca38 100644 --- a/llvm/tools/llvm-jitlink/llvm-jitlink.h +++ b/llvm/tools/llvm-jitlink/llvm-jitlink.h @@ -109,7 +109,6 @@ class LLVMJITLinkRemoteExecutorProcessControl }; struct Session { - std::unique_ptr EPC; orc::ExecutionSession ES; orc::JITDylib *MainJD = nullptr; LLVMJITLinkObjectLinkingLayer ObjLayer; diff --git a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt index b544cfa1864e8b..5c2a7879dcd3f6 100644 --- a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt +++ b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt @@ -16,7 +16,7 @@ set(LLVM_LINK_COMPONENTS add_llvm_unittest(OrcJITTests CoreAPIsTest.cpp - ExecutorProcessControlTest.cpp + ExecutionSessionWrapperFunctionCallsTest.cpp IndirectionUtilsTest.cpp JITTargetMachineBuilderTest.cpp LazyCallThroughAndReexportsTest.cpp diff --git a/llvm/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp b/llvm/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp index 717987daa2ab68..020a261ac23865 100644 --- a/llvm/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp +++ b/llvm/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp @@ -1409,7 +1409,7 @@ TEST(JITDylibTest, GetDFSLinkOrderTree) { // Test that DFS ordering behaves as expected when the linkage relationships // form a tree. - ExecutionSession ES; + ExecutionSession ES{std::make_unique()}; auto &LibA = ES.createBareJITDylib("A"); auto &LibB = ES.createBareJITDylib("B"); @@ -1450,7 +1450,7 @@ TEST(JITDylibTest, GetDFSLinkOrderDiamond) { // Test that DFS ordering behaves as expected when the linkage relationships // contain a diamond. - ExecutionSession ES; + ExecutionSession ES{std::make_unique()}; auto &LibA = ES.createBareJITDylib("A"); auto &LibB = ES.createBareJITDylib("B"); auto &LibC = ES.createBareJITDylib("C"); @@ -1472,7 +1472,7 @@ TEST(JITDylibTest, GetDFSLinkOrderCycle) { // Test that DFS ordering behaves as expected when the linkage relationships // contain a cycle. - ExecutionSession ES; + ExecutionSession ES{std::make_unique()}; auto &LibA = ES.createBareJITDylib("A"); auto &LibB = ES.createBareJITDylib("B"); auto &LibC = ES.createBareJITDylib("C"); diff --git a/llvm/unittests/ExecutionEngine/Orc/ExecutorProcessControlTest.cpp b/llvm/unittests/ExecutionEngine/Orc/ExecutionSessionWrapperFunctionCallsTest.cpp similarity index 73% rename from llvm/unittests/ExecutionEngine/Orc/ExecutorProcessControlTest.cpp rename to llvm/unittests/ExecutionEngine/Orc/ExecutionSessionWrapperFunctionCallsTest.cpp index 23096c86f4d33c..9044ead6318261 100644 --- a/llvm/unittests/ExecutionEngine/Orc/ExecutorProcessControlTest.cpp +++ b/llvm/unittests/ExecutionEngine/Orc/ExecutionSessionWrapperFunctionCallsTest.cpp @@ -1,4 +1,4 @@ -//===- ExecutorProcessControlTest.cpp - Test ExecutorProcessControl utils -===// +//===- ExecutionSessionWrapperFunctionCallsTest.cpp -- Test wrapper calls -===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" #include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" #include "llvm/Support/MSVCErrorWorkarounds.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" @@ -30,24 +30,22 @@ static void addAsyncWrapper(unique_function SendResult, SendResult(X + Y); } -TEST(ExecutorProcessControl, RunWrapperTemplate) { - auto EPC = cantFail( - SelfExecutorProcessControl::Create(std::make_shared())); +TEST(ExecutionSessionWrapperFunctionCalls, RunWrapperTemplate) { + ExecutionSession ES(cantFail(SelfExecutorProcessControl::Create())); int32_t Result; - EXPECT_THAT_ERROR(EPC->runSPSWrapper( + EXPECT_THAT_ERROR(ES.callSPSWrapper( pointerToJITTargetAddress(addWrapper), Result, 2, 3), Succeeded()); EXPECT_EQ(Result, 5); } -TEST(ExecutorProcessControl, RunWrapperAsyncTemplate) { - auto EPC = cantFail( - SelfExecutorProcessControl::Create(std::make_shared())); +TEST(ExecutionSessionWrapperFunctionCalls, RunWrapperAsyncTemplate) { + ExecutionSession ES(cantFail(SelfExecutorProcessControl::Create())); std::promise> RP; using Sig = int32_t(int32_t, int32_t); - EPC->runSPSWrapperAsync( + ES.callSPSWrapperAsync( [&](Error SerializationErr, int32_t R) { if (SerializationErr) RP.set_value(std::move(SerializationErr)); @@ -58,13 +56,11 @@ TEST(ExecutorProcessControl, RunWrapperAsyncTemplate) { EXPECT_THAT_EXPECTED(Result, HasValue(5)); } -TEST(ExecutorProcessControl, RegisterAsyncHandlerAndRun) { +TEST(ExecutionSessionWrapperFunctionCalls, RegisterAsyncHandlerAndRun) { constexpr JITTargetAddress AddAsyncTagAddr = 0x01; - auto EPC = cantFail( - SelfExecutorProcessControl::Create(std::make_shared())); - ExecutionSession ES(EPC->getSymbolStringPool()); + ExecutionSession ES(cantFail(SelfExecutorProcessControl::Create())); auto &JD = ES.createBareJITDylib("JD"); auto AddAsyncTag = ES.intern("addAsync_tag"); @@ -72,12 +68,12 @@ TEST(ExecutorProcessControl, RegisterAsyncHandlerAndRun) { {{AddAsyncTag, JITEvaluatedSymbol(AddAsyncTagAddr, JITSymbolFlags::Exported)}}))); - ExecutorProcessControl::WrapperFunctionAssociationMap Associations; + ExecutionSession::JITDispatchHandlerAssociationMap Associations; Associations[AddAsyncTag] = - EPC->wrapAsyncWithSPS(addAsyncWrapper); + ES.wrapAsyncWithSPS(addAsyncWrapper); - cantFail(EPC->associateJITSideWrapperFunctions(JD, std::move(Associations))); + cantFail(ES.registerJITDispatchHandlers(JD, std::move(Associations))); std::promise RP; auto RF = RP.get_future(); @@ -90,7 +86,7 @@ TEST(ExecutorProcessControl, RegisterAsyncHandlerAndRun) { SPSOutputBuffer OB(ArgBufferData, ArgBufferSize); EXPECT_TRUE(ArgSerialization::serialize(OB, 1, 2)); - EPC->runJITSideWrapperFunction( + ES.runJITDispatchHandler( [&](WrapperFunctionResult ResultBuffer) { int32_t Result; SPSInputBuffer IB(ResultBuffer.data(), ResultBuffer.size()); diff --git a/llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp index a628b86b9c5b41..f6413316b692df 100644 --- a/llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp +++ b/llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp @@ -35,7 +35,7 @@ class ObjectLinkingLayerTest : public testing::Test { } protected: - ExecutionSession ES; + ExecutionSession ES{std::make_unique()}; JITDylib &JD = ES.createBareJITDylib("main"); ObjectLinkingLayer ObjLinkingLayer{ ES, std::make_unique()}; diff --git a/llvm/unittests/ExecutionEngine/Orc/OrcTestCommon.h b/llvm/unittests/ExecutionEngine/Orc/OrcTestCommon.h index d279235639527c..a4581394a6e34f 100644 --- a/llvm/unittests/ExecutionEngine/Orc/OrcTestCommon.h +++ b/llvm/unittests/ExecutionEngine/Orc/OrcTestCommon.h @@ -14,8 +14,9 @@ #ifndef LLVM_UNITTESTS_EXECUTIONENGINE_ORC_ORCTESTCOMMON_H #define LLVM_UNITTESTS_EXECUTIONENGINE_ORC_ORCTESTCOMMON_H -#include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" @@ -52,7 +53,7 @@ class CoreAPIsBasedStandardTest : public testing::Test { protected: std::shared_ptr SSP = std::make_shared(); - ExecutionSession ES{SSP}; + ExecutionSession ES{std::make_unique(SSP)}; JITDylib &JD = ES.createBareJITDylib("JD"); SymbolStringPtr Foo = ES.intern("foo"); SymbolStringPtr Bar = ES.intern("bar"); diff --git a/llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp index d00b900c97f6b6..bff096915af6af 100644 --- a/llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp +++ b/llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp @@ -46,7 +46,7 @@ static bool testSetProcessAllSections(std::unique_ptr Obj, bool NonAllocSectionSeen = false; - ExecutionSession ES; + ExecutionSession ES(std::make_unique()); auto &JD = ES.createBareJITDylib("main"); auto Foo = ES.intern("foo"); @@ -153,7 +153,7 @@ TEST(RTDyldObjectLinkingLayerTest, TestOverrideObjectFlags) { } // Create a simple stack and set the override flags option. - ExecutionSession ES; + ExecutionSession ES{std::make_unique()}; auto &JD = ES.createBareJITDylib("main"); auto Foo = ES.intern("foo"); RTDyldObjectLinkingLayer ObjLayer( @@ -223,7 +223,7 @@ TEST(RTDyldObjectLinkingLayerTest, TestAutoClaimResponsibilityForSymbols) { } // Create a simple stack and set the override flags option. - ExecutionSession ES; + ExecutionSession ES{std::make_unique()}; auto &JD = ES.createBareJITDylib("main"); auto Foo = ES.intern("foo"); RTDyldObjectLinkingLayer ObjLayer(