[llvm] 2487db1 - [ORC] Require ExecutorProcessControl when constructing an ExecutionSession.

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 26 23:54:05 PDT 2021


Author: Lang Hames
Date: 2021-07-27T16:53:49+10:00
New Revision: 2487db1f286222e2501c2fa8e8244eda13f6afc3

URL: https://github.com/llvm/llvm-project/commit/2487db1f286222e2501c2fa8e8244eda13f6afc3
DIFF: https://github.com/llvm/llvm-project/commit/2487db1f286222e2501c2fa8e8244eda13f6afc3.diff

LOG: [ORC] Require ExecutorProcessControl when constructing an ExecutionSession.

Wrapper function call and dispatch handler helpers are moved to
ExecutionSession, and existing EPC-based tools are re-written to take an
ExecutionSession argument instead.

Requiring an ExecutorProcessControl instance simplifies existing EPC based
utilities (which only need to take an ES now), and should encourage more
utilities to use the EPC interface. It also simplifies process termination,
since the session can automatically call ExecutorProcessControl::disconnect
(previously this had to be done manually, and carefully ordered with the
rest of JIT tear-down to work correctly).

Added: 
    llvm/unittests/ExecutionEngine/Orc/ExecutionSessionWrapperFunctionCallsTest.cpp

Modified: 
    llvm/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h
    llvm/examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h
    llvm/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h
    llvm/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h
    llvm/examples/Kaleidoscope/include/KaleidoscopeJIT.h
    llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp
    llvm/examples/SpeculativeJIT/SpeculativeJIT.cpp
    llvm/include/llvm/ExecutionEngine/Orc/Core.h
    llvm/include/llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h
    llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h
    llvm/include/llvm/ExecutionEngine/Orc/EPCEHFrameRegistrar.h
    llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
    llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h
    llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h
    llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h
    llvm/include/llvm/ExecutionEngine/Orc/OrcRPCExecutorProcessControl.h
    llvm/lib/ExecutionEngine/Orc/Core.cpp
    llvm/lib/ExecutionEngine/Orc/EPCDebugObjectRegistrar.cpp
    llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
    llvm/lib/ExecutionEngine/Orc/EPCEHFrameRegistrar.cpp
    llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp
    llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
    llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
    llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
    llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp
    llvm/tools/lli/lli.cpp
    llvm/tools/llvm-jitlink/llvm-jitlink.cpp
    llvm/tools/llvm-jitlink/llvm-jitlink.h
    llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
    llvm/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp
    llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp
    llvm/unittests/ExecutionEngine/Orc/OrcTestCommon.h
    llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp

Removed: 
    llvm/unittests/ExecutionEngine/Orc/ExecutorProcessControlTest.cpp


################################################################################
diff  --git a/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h b/llvm/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h
index 783c352cf057c..18a4c111a5275 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<ExecutorProcessControl> EPC;
   std::unique_ptr<ExecutionSession> ES;
 
   DataLayout DL;
@@ -44,11 +43,9 @@ class KaleidoscopeJIT {
   JITDylib &MainJD;
 
 public:
-  KaleidoscopeJIT(std::unique_ptr<ExecutorProcessControl> EPC,
-                  std::unique_ptr<ExecutionSession> ES,
+  KaleidoscopeJIT(std::unique_ptr<ExecutionSession> 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<SectionMemoryManager>(); }),
         CompileLayer(*this->ES, ObjectLayer,
@@ -65,21 +62,21 @@ class KaleidoscopeJIT {
   }
 
   static Expected<std::unique_ptr<KaleidoscopeJIT>> Create() {
-    auto SSP = std::make_shared<SymbolStringPool>();
-    auto EPC = SelfExecutorProcessControl::Create(SSP);
+    auto EPC = SelfExecutorProcessControl::Create();
     if (!EPC)
       return EPC.takeError();
 
-    auto ES = std::make_unique<ExecutionSession>(std::move(SSP));
+    auto ES = std::make_unique<ExecutionSession>(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<KaleidoscopeJIT>(std::move(*EPC), std::move(ES),
-                                             std::move(JTMB), std::move(*DL));
+    return std::make_unique<KaleidoscopeJIT>(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 363c74882b8f1..23a6fd806f5ab 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<ExecutorProcessControl> EPC;
   std::unique_ptr<ExecutionSession> ES;
 
   DataLayout DL;
@@ -50,11 +49,9 @@ class KaleidoscopeJIT {
   JITDylib &MainJD;
 
 public:
-  KaleidoscopeJIT(std::unique_ptr<ExecutorProcessControl> EPC,
-                  std::unique_ptr<ExecutionSession> ES,
+  KaleidoscopeJIT(std::unique_ptr<ExecutionSession> 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<SectionMemoryManager>(); }),
         CompileLayer(*this->ES, ObjectLayer,
@@ -72,21 +69,21 @@ class KaleidoscopeJIT {
   }
 
   static Expected<std::unique_ptr<KaleidoscopeJIT>> Create() {
-    auto SSP = std::make_shared<SymbolStringPool>();
-    auto EPC = SelfExecutorProcessControl::Create(SSP);
+    auto EPC = SelfExecutorProcessControl::Create();
     if (!EPC)
       return EPC.takeError();
 
-    auto ES = std::make_unique<ExecutionSession>(std::move(SSP));
+    auto ES = std::make_unique<ExecutionSession>(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<KaleidoscopeJIT>(std::move(*EPC), std::move(ES),
-                                             std::move(JTMB), std::move(*DL));
+    return std::make_unique<KaleidoscopeJIT>(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 0aba5666995aa..130310da92748 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<ExecutorProcessControl> EPC;
   std::unique_ptr<ExecutionSession> ES;
   std::unique_ptr<EPCIndirectionUtils> EPCIU;
 
@@ -59,12 +58,11 @@ class KaleidoscopeJIT {
   }
 
 public:
-  KaleidoscopeJIT(std::unique_ptr<ExecutorProcessControl> EPC,
-                  std::unique_ptr<ExecutionSession> ES,
+  KaleidoscopeJIT(std::unique_ptr<ExecutionSession> ES,
                   std::unique_ptr<EPCIndirectionUtils> 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<SectionMemoryManager>(); }),
         CompileLayer(*this->ES, ObjectLayer,
@@ -87,14 +85,13 @@ class KaleidoscopeJIT {
   }
 
   static Expected<std::unique_ptr<KaleidoscopeJIT>> Create() {
-    auto SSP = std::make_shared<SymbolStringPool>();
-    auto EPC = SelfExecutorProcessControl::Create(SSP);
+    auto EPC = SelfExecutorProcessControl::Create();
     if (!EPC)
       return EPC.takeError();
 
-    auto ES = std::make_unique<ExecutionSession>(std::move(SSP));
+    auto ES = std::make_unique<ExecutionSession>(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<KaleidoscopeJIT>(std::move(*EPC), std::move(ES),
-                                             std::move(*EPCIU), std::move(JTMB),
-                                             std::move(*DL));
+    return std::make_unique<KaleidoscopeJIT>(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 6b2f6a543bbf8..863304b02113e 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<ExecutorProcessControl> EPC;
   std::unique_ptr<ExecutionSession> ES;
   std::unique_ptr<EPCIndirectionUtils> EPCIU;
 
@@ -146,12 +145,11 @@ class KaleidoscopeJIT {
   }
 
 public:
-  KaleidoscopeJIT(std::unique_ptr<ExecutorProcessControl> EPC,
-                  std::unique_ptr<ExecutionSession> ES,
+  KaleidoscopeJIT(std::unique_ptr<ExecutionSession> ES,
                   std::unique_ptr<EPCIndirectionUtils> 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<SectionMemoryManager>(); }),
         CompileLayer(*this->ES, ObjectLayer,
@@ -172,14 +170,13 @@ class KaleidoscopeJIT {
   }
 
   static Expected<std::unique_ptr<KaleidoscopeJIT>> Create() {
-    auto SSP = std::make_shared<SymbolStringPool>();
-    auto EPC = SelfExecutorProcessControl::Create(SSP);
+    auto EPC = SelfExecutorProcessControl::Create();
     if (!EPC)
       return EPC.takeError();
 
-    auto ES = std::make_unique<ExecutionSession>(std::move(SSP));
+    auto ES = std::make_unique<ExecutionSession>(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<KaleidoscopeJIT>(std::move(*EPC), std::move(ES),
-                                             std::move(*EPCIU), std::move(JTMB),
-                                             std::move(*DL));
+    return std::make_unique<KaleidoscopeJIT>(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 783c352cf057c..18a4c111a5275 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<ExecutorProcessControl> EPC;
   std::unique_ptr<ExecutionSession> ES;
 
   DataLayout DL;
@@ -44,11 +43,9 @@ class KaleidoscopeJIT {
   JITDylib &MainJD;
 
 public:
-  KaleidoscopeJIT(std::unique_ptr<ExecutorProcessControl> EPC,
-                  std::unique_ptr<ExecutionSession> ES,
+  KaleidoscopeJIT(std::unique_ptr<ExecutionSession> 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<SectionMemoryManager>(); }),
         CompileLayer(*this->ES, ObjectLayer,
@@ -65,21 +62,21 @@ class KaleidoscopeJIT {
   }
 
   static Expected<std::unique_ptr<KaleidoscopeJIT>> Create() {
-    auto SSP = std::make_shared<SymbolStringPool>();
-    auto EPC = SelfExecutorProcessControl::Create(SSP);
+    auto EPC = SelfExecutorProcessControl::Create();
     if (!EPC)
       return EPC.takeError();
 
-    auto ES = std::make_unique<ExecutionSession>(std::move(SSP));
+    auto ES = std::make_unique<ExecutionSession>(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<KaleidoscopeJIT>(std::move(*EPC), std::move(ES),
-                                             std::move(JTMB), std::move(*DL));
+    return std::make_unique<KaleidoscopeJIT>(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 953d90e4c06ef..ac5ea5643b03b 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<SymbolStringPool>();
-  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 0ca5d62e7b67c..9f5677437f38d 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<ExecutionSession>();
+    auto EPC = SelfExecutorProcessControl::Create();
+    if (!EPC)
+      return EPC.takeError();
+
+    auto ES = std::make_unique<ExecutionSession>(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 159553b5559f4..e832d8d57dfa3 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 <atomic>
+#include <future>
 #include <memory>
 #include <vector>
 
@@ -1286,19 +1288,30 @@ class ExecutionSession {
   /// For dispatching ORC tasks (typically materialization tasks).
   using DispatchTaskFunction = unique_function<void(std::unique_ptr<Task> T)>;
 
-  /// Construct an ExecutionSession.
-  ///
-  /// SymbolStringPools may be shared between ExecutionSessions.
-  ExecutionSession(std::shared_ptr<SymbolStringPool> SSP = nullptr);
+  /// An asynchronous wrapper-function callable from the executor via
+  /// jit-dispatch.
+  using JITDispatchHandlerFunction = unique_function<void(
+      ExecutorProcessControl::SendResultFunction SendResult,
+      const char *ArgData, size_t ArgSize)>;
+
+  /// A map associating tag names with asynchronous wrapper function
+  /// implementations in the JIT.
+  using JITDispatchHandlerAssociationMap =
+      DenseMap<SymbolStringPtr, JITDispatchHandlerFunction>;
+
+  /// Construct an ExecutionSession with the given ExecutorProcessControl
+  /// object.
+  ExecutionSession(std::unique_ptr<ExecutorProcessControl> 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<SymbolStringPool> 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<Platform> 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<char> 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<char> ArgBuffer) {
+    std::promise<shared::WrapperFunctionResult> 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 <typename SPSSignature, typename SendResultT, typename... ArgTs>
+  void callSPSWrapperAsync(SendResultT &&SendResult,
+                           JITTargetAddress WrapperFnAddr,
+                           const ArgTs &...Args) {
+    shared::WrapperFunction<SPSSignature>::callAsync(
+        [this,
+         WrapperFnAddr](ExecutorProcessControl::SendResultFunction SendResult,
+                        const char *ArgData, size_t ArgSize) {
+          callWrapperAsync(std::move(SendResult), WrapperFnAddr,
+                           ArrayRef<char>(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 <typename SPSSignature, typename... WrapperCallArgTs>
+  Error callSPSWrapper(JITTargetAddress WrapperFnAddr,
+                       WrapperCallArgTs &&...WrapperCallArgs) {
+    return shared::WrapperFunction<SPSSignature>::call(
+        [this, WrapperFnAddr](const char *ArgData, size_t ArgSize) {
+          return callWrapper(WrapperFnAddr, ArrayRef<char>(ArgData, ArgSize));
+        },
+        std::forward<WrapperCallArgTs>(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 <typename SPSSignature, typename HandlerT>
+  static JITDispatchHandlerFunction wrapAsyncWithSPS(HandlerT &&H) {
+    return [H = std::forward<HandlerT>(H)](
+               ExecutorProcessControl::SendResultFunction SendResult,
+               const char *ArgData, size_t ArgSize) mutable {
+      shared::WrapperFunction<SPSSignature>::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 <typename SPSSignature, typename ClassT, typename... MethodArgTs>
+  static JITDispatchHandlerFunction
+  wrapAsyncWithSPS(ClassT *Instance, void (ClassT::*Method)(MethodArgTs...)) {
+    return wrapAsyncWithSPS<SPSSignature>(
+        [Instance, Method](MethodArgTs &&...MethodArgs) {
+          (Instance->*Method)(std::forward<MethodArgTs>(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<char> 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<SymbolStringPool> SSP;
+  std::unique_ptr<ExecutorProcessControl> EPC;
   std::unique_ptr<Platform> P;
   ErrorReporter ReportError = logErrorsToStdErr;
   DispatchTaskFunction DispatchTask = runOnCurrentThread;
@@ -1538,6 +1666,10 @@ class ExecutionSession {
   std::vector<std::pair<std::unique_ptr<MaterializationUnit>,
                         std::unique_ptr<MaterializationResponsibility>>>
       OutstandingMUs;
+
+  mutable std::mutex JITDispatchHandlersMutex;
+  DenseMap<JITTargetAddress, std::shared_ptr<JITDispatchHandlerFunction>>
+      JITDispatchHandlers;
 };
 
 inline ExecutionSession &MaterializationResponsibility::getExecutionSession() {

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h
index db5c18b4b4911..410a202b32964 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<void(SPSExecutorAddress, uint64_t)>::call(
-        EPCCaller(EPC, RegisterFn), pointerToJITTargetAddress(TargetMem.base()),
-        static_cast<uint64_t>(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<std::unique_ptr<EPCDebugObjectRegistrar>>
-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 08b5ab05ba761..63797edec89e6 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<bool(const SymbolStringPtr &)>;
@@ -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<std::unique_ptr<EPCDynamicLibrarySearchGenerator>>
-  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<std::unique_ptr<EPCDynamicLibrarySearchGenerator>>
-  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 f230cfcac4167..8cd6e9319a287 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<std::unique_ptr<EPCEHFrameRegistrar>>
-  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 f8d6192706a1d..d540d0cd0608c 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<void(shared::WrapperFunctionResult)>;
 
-  /// An asynchronous wrapper-function.
-  using AsyncWrapperFunction = unique_function<void(
-      SendResultFunction SendResult, const char *ArgData, size_t ArgSize)>;
-
-  /// A map associating tag names with asynchronous wrapper function
-  /// implementations in the JIT.
-  using WrapperFunctionAssociationMap =
-      DenseMap<SymbolStringPtr, AsyncWrapperFunction>;
-
   /// 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<int32_t> runAsMain(JITTargetAddress MainFnAddr,
                                       ArrayRef<std::string> 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<char> 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<char> ArgBuffer) {
-    std::promise<shared::WrapperFunctionResult> 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 <typename SPSSignature, typename SendResultT, typename... ArgTs>
-  void runSPSWrapperAsync(SendResultT &&SendResult,
-                          JITTargetAddress WrapperFnAddr,
-                          const ArgTs &...Args) {
-    shared::WrapperFunction<SPSSignature>::callAsync(
-        [this, WrapperFnAddr](SendResultFunction SendResult,
-                              const char *ArgData, size_t ArgSize) {
-          runWrapperAsync(std::move(SendResult), WrapperFnAddr,
-                          ArrayRef<char>(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 <typename SPSSignature, typename... WrapperCallArgTs>
-  Error runSPSWrapper(JITTargetAddress WrapperFnAddr,
-                      WrapperCallArgTs &&...WrapperCallArgs) {
-    return shared::WrapperFunction<SPSSignature>::call(
-        [this, WrapperFnAddr](const char *ArgData, size_t ArgSize) {
-          return runWrapper(WrapperFnAddr, ArrayRef<char>(ArgData, ArgSize));
-        },
-        std::forward<WrapperCallArgTs>(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 <typename SPSSignature, typename HandlerT>
-  static AsyncWrapperFunction wrapAsyncWithSPS(HandlerT &&H) {
-    return [H = std::forward<HandlerT>(H)](SendResultFunction SendResult,
-                                           const char *ArgData,
-                                           size_t ArgSize) mutable {
-      shared::WrapperFunction<SPSSignature>::handleAsync(ArgData, ArgSize, H,
-                                                         std::move(SendResult));
-    };
-  }
-
-  template <typename SPSSignature, typename ClassT, typename... MethodArgTs>
-  static AsyncWrapperFunction
-  wrapAsyncWithSPS(ClassT *Instance, void (ClassT::*Method)(MethodArgTs...)) {
-    return wrapAsyncWithSPS<SPSSignature>(
-        [Instance, Method](MethodArgTs &&...MethodArgs) {
-          (Instance->*Method)(std::forward<MethodArgTs>(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<char> ArgBuffer);
+  virtual void callWrapperAsync(SendResultFunction OnComplete,
+                                JITTargetAddress WrapperFnAddr,
+                                ArrayRef<char> ArgBuffer) = 0;
 
   /// Disconnect from the target process.
   ///
@@ -271,29 +195,49 @@ class ExecutorProcessControl {
       : SSP(std::move(SSP)) {}
 
   std::shared_ptr<SymbolStringPool> SSP;
+  ExecutionSession *ES = nullptr;
   Triple TargetTriple;
   unsigned PageSize = 0;
   JITDispatchInfo JDI;
   MemoryAccess *MemAccess = nullptr;
   jitlink::JITLinkMemoryManager *MemMgr = nullptr;
-
-  std::mutex TagToFuncMapMutex;
-  DenseMap<JITTargetAddress, std::shared_ptr<AsyncWrapperFunction>> 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<char>(ArgData, ArgSize));
+  UnsupportedExecutorProcessControl(
+      std::shared_ptr<SymbolStringPool> SSP = nullptr,
+      const std::string &TT = "", unsigned PageSize = 0)
+      : ExecutorProcessControl(SSP ? std::move(SSP)
+                                   : std::make_shared<SymbolStringPool>()) {
+    this->TargetTriple = Triple(TT);
+    this->PageSize = PageSize;
   }
 
-private:
-  ExecutorProcessControl &EPC;
-  JITTargetAddress WrapperFnAddr;
+  Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override {
+    llvm_unreachable("Unsupported");
+  }
+
+  Expected<std::vector<tpctypes::LookupResult>>
+  lookupSymbols(ArrayRef<LookupRequest> Request) override {
+    llvm_unreachable("Unsupported");
+  }
+
+  Expected<int32_t> runAsMain(JITTargetAddress MainFnAddr,
+                              ArrayRef<std::string> Args) override {
+    llvm_unreachable("Unsupported");
+  }
+
+  void callWrapperAsync(SendResultFunction OnComplete,
+                        JITTargetAddress WrapperFnAddr,
+                        ArrayRef<char> 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<SymbolStringPool> SSP, Triple TargetTriple,
       unsigned PageSize, std::unique_ptr<jitlink::JITLinkMemoryManager> 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<std::unique_ptr<SelfExecutorProcessControl>>
-  Create(std::shared_ptr<SymbolStringPool> SSP,
+  Create(std::shared_ptr<SymbolStringPool> SSP = nullptr,
          std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr = nullptr);
 
   Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override;
@@ -320,9 +266,9 @@ class SelfExecutorProcessControl
   Expected<int32_t> runAsMain(JITTargetAddress MainFnAddr,
                               ArrayRef<std::string> Args) override;
 
-  void runWrapperAsync(SendResultFunction OnComplete,
-                       JITTargetAddress WrapperFnAddr,
-                       ArrayRef<char> ArgBuffer) override;
+  void callWrapperAsync(SendResultFunction OnComplete,
+                        JITTargetAddress WrapperFnAddr,
+                        ArrayRef<char> ArgBuffer) override;
 
   Error disconnect() override;
 

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h b/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h
index cc23147aac388..d76e6a21a9bb6 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<Error(LLJIT &J)>;
 
+  std::unique_ptr<ExecutorProcessControl> EPC;
   std::unique_ptr<ExecutionSession> ES;
   Optional<JITTargetMachineBuilder> JTMB;
   Optional<DataLayout> 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 <typename JITType, typename SetterImpl, typename State>
 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<ExecutorProcessControl> 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<ExecutionSession> ES) {

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h b/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h
index 8b228a52244d1..f77dfd208413c 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<std::unique_ptr<MachOPlatform>>
   Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
-         ExecutorProcessControl &EPC, JITDylib &PlatformJD,
-         const char *OrcRuntimePath,
+         JITDylib &PlatformJD, const char *OrcRuntimePath,
          Optional<SymbolAliasMap> 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<DefinitionGenerator> OrcRuntimeGenerator,
                 Error &Err);
 
@@ -228,7 +226,6 @@ class MachOPlatform : public Platform {
 
   ExecutionSession &ES;
   ObjectLinkingLayer &ObjLinkingLayer;
-  ExecutorProcessControl &EPC;
 
   SymbolStringPtr MachOHeaderStartSymbol;
   std::atomic<bool> RuntimeBootstrapped{false};

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h
index 4737fe80ba3ea..5632118eee4e4 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<ObjectLinkingLayer, ObjectLayer>,
   using ReturnObjectBufferFunction =
       std::function<void(std::unique_ptr<MemoryBuffer>)>;
 
-  /// 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 fedd79c93146e..4310ba9ce9e0e 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<char> ArgBuffer) override {
+  void callWrapperAsync(SendResultFunction OnComplete,
+                        JITTargetAddress WrapperFnAddr,
+                        ArrayRef<char> 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<Error(Expected<shared::WrapperFunctionResult>)> SendResult,
       JITTargetAddress FunctionTag, std::vector<uint8_t> ArgBuffer) {
 
-    runJITSideWrapperFunction(
+    getExecutionSession().runJITDispatchHandler(
         [this, SendResult = std::move(SendResult)](
             Expected<shared::WrapperFunctionResult> 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 c613c57c15f87..12a501f7f98c6 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<SymbolStringPool> SSP)
-    : SSP(SSP ? std::move(SSP) : std::make_shared<SymbolStringPool>()) {}
+ExecutionSession::ExecutionSession(std::unique_ptr<ExecutorProcessControl> 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<JITDylib *> 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<std::mutex> Lock(JITDispatchHandlersMutex);
+  for (auto &KV : *TagAddrs) {
+    auto TagAddr = KV.second.getAddress();
+    if (JITDispatchHandlers.count(TagAddr))
+      return make_error<StringError>("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<JITDispatchHandlerFunction>(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<char> ArgBuffer) {
+
+  std::shared_ptr<JITDispatchHandlerFunction> F;
+  {
+    std::lock_guard<std::mutex> 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 803cf96f5bddf..5715eda71eee2 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<std::unique_ptr<EPCDebugObjectRegistrar>>
-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<EPCDebugObjectRegistrar>(EPC, (*Result)[0][0]);
+  return std::make_unique<EPCDebugObjectRegistrar>(ES, (*Result)[0][0]);
+}
+
+Error EPCDebugObjectRegistrar::registerDebugObject(sys::MemoryBlock TargetMem) {
+  return ES.callSPSWrapper<void(SPSExecutorAddress, uint64_t)>(
+      RegisterFn, ExecutorAddress::fromPtr(TargetMem.base()),
+      static_cast<uint64_t>(TargetMem.allocatedSize()));
 }
 
 } // namespace orc

diff  --git a/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp b/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
index 9958a52f0e44c..ba154aaecd1aa 100644
--- a/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
@@ -12,14 +12,14 @@ namespace llvm {
 namespace orc {
 
 Expected<std::unique_ptr<EPCDynamicLibrarySearchGenerator>>
-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<EPCDynamicLibrarySearchGenerator>(EPC, *Handle,
+  return std::make_unique<EPCDynamicLibrarySearchGenerator>(ES, *Handle,
                                                             std::move(Allow));
 }
 

diff  --git a/llvm/lib/ExecutionEngine/Orc/EPCEHFrameRegistrar.cpp b/llvm/lib/ExecutionEngine/Orc/EPCEHFrameRegistrar.cpp
index 4bfcf132c8f7e..8cdda9ab5a15f 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<std::unique_ptr<EPCEHFrameRegistrar>>
-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<EPCEHFrameRegistrar>(
-      EPC, RegisterEHFrameWrapperFnAddr, DeregisterEHFrameWrapperFnAddr);
+  return std::make_unique<EPCEHFrameRegistrar>(ES, RegisterEHFrameWrapperFnAddr,
+                                               DeregisterEHFrameWrapperFnAddr);
 }
 
 Error EPCEHFrameRegistrar::registerEHFrames(JITTargetAddress EHFrameSectionAddr,
                                             size_t EHFrameSectionSize) {
-
-  return WrapperFunction<void(SPSExecutorAddress, uint64_t)>::call(
-      EPCCaller(EPC, RegisterEHFrameWrapperFnAddr), EHFrameSectionAddr,
+  return ES.callSPSWrapper<void(SPSExecutorAddress, uint64_t)>(
+      RegisterEHFrameWrapperFnAddr, EHFrameSectionAddr,
       static_cast<uint64_t>(EHFrameSectionSize));
 }
 
 Error EPCEHFrameRegistrar::deregisterEHFrames(
     JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) {
-  return WrapperFunction<void(SPSExecutorAddress, uint64_t)>::call(
-      EPCCaller(EPC, DeregisterEHFrameWrapperFnAddr), EHFrameSectionAddr,
+  return ES.callSPSWrapper<void(SPSExecutorAddress, uint64_t)>(
+      DeregisterEHFrameWrapperFnAddr, EHFrameSectionAddr,
       static_cast<uint64_t>(EHFrameSectionSize));
 }
 

diff  --git a/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp b/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp
index 9442eab299708..7d86d125d1db2 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<std::mutex> Lock(TagToFuncMapMutex);
-  for (auto &KV : *TagAddrs) {
-    auto TagAddr = KV.second.getAddress();
-    if (TagToFunc.count(TagAddr))
-      return make_error<StringError>("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<AsyncWrapperFunction>(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<char> ArgBuffer) {
-
-  std::shared_ptr<AsyncWrapperFunction> F;
-  {
-    std::lock_guard<std::mutex> 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<SymbolStringPool> SSP, Triple TargetTriple,
     unsigned PageSize, std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr)
@@ -100,6 +46,10 @@ Expected<std::unique_ptr<SelfExecutorProcessControl>>
 SelfExecutorProcessControl::Create(
     std::shared_ptr<SymbolStringPool> SSP,
     std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) {
+
+  if (!SSP)
+    SSP = std::make_shared<SymbolStringPool>();
+
   auto PageSize = sys::Process::getPageSize();
   if (!PageSize)
     return PageSize.takeError();
@@ -159,9 +109,9 @@ SelfExecutorProcessControl::runAsMain(JITTargetAddress MainFnAddr,
   return orc::runAsMain(jitTargetAddressToFunction<MainTy>(MainFnAddr), Args);
 }
 
-void SelfExecutorProcessControl::runWrapperAsync(SendResultFunction SendResult,
-                                                 JITTargetAddress WrapperFnAddr,
-                                                 ArrayRef<char> ArgBuffer) {
+void SelfExecutorProcessControl::callWrapperAsync(
+    SendResultFunction SendResult, JITTargetAddress WrapperFnAddr,
+    ArrayRef<char> ArgBuffer) {
   using WrapperFnTy =
       shared::detail::CWrapperFunctionResult (*)(const char *Data, size_t Size);
   auto *WrapperFn = jitTargetAddressToFunction<WrapperFnTy>(WrapperFnAddr);
@@ -217,12 +167,14 @@ SelfExecutorProcessControl::jitDispatchViaWrapperFunctionManager(
 
   std::promise<shared::WrapperFunctionResult> ResultP;
   auto ResultF = ResultP.get_future();
-  static_cast<SelfExecutorProcessControl *>(Ctx)->runJITSideWrapperFunction(
-      [ResultP =
-           std::move(ResultP)](shared::WrapperFunctionResult Result) mutable {
-        ResultP.set_value(std::move(Result));
-      },
-      pointerToJITTargetAddress(FnTag), {Data, Size});
+  static_cast<SelfExecutorProcessControl *>(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 2d1f394a5fb97..2ac32293e4dba 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<ObjectLayer>> {
-        std::unique_ptr<ObjectLinkingLayer> ObjLinkingLayer;
-        if (EPC)
-          ObjLinkingLayer =
-              std::make_unique<ObjectLinkingLayer>(ES, EPC->getMemMgr());
-        else
-          ObjLinkingLayer = std::make_unique<ObjectLinkingLayer>(
-              ES, std::make_unique<jitlink::InProcessMemoryManager>());
+          [](ExecutionSession &ES,
+             const Triple &) -> Expected<std::unique_ptr<ObjectLayer>> {
+        auto ObjLinkingLayer = std::make_unique<ObjectLinkingLayer>(ES);
         ObjLinkingLayer->addPlugin(std::make_unique<EHFrameRegistrationPlugin>(
             ES, std::make_unique<jitlink::InProcessEHFrameRegistrar>()));
         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<ExecutionSession>()), 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<ExecutionSession>(std::move(S.EPC));
+  } else if (S.ES)
+    ES = std::move(S.ES);
+  else {
+    if (auto EPC = SelfExecutorProcessControl::Create()) {
+      ES = std::make_unique<ExecutionSession>(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 986f39a883280..66ef835dc34da 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<MaterializationResponsibility> 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<jitlink::LinkGraph>(
-        "<MachOHeaderMU>", MOP.getExecutorProcessControl().getTargetTriple(),
-        PointerSize, Endianness, jitlink::getGenericEdgeKindName);
+        "<MachOHeaderMU>", 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<std::unique_ptr<MachOPlatform>>
 MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
-                      ExecutorProcessControl &EPC, JITDylib &PlatformJD,
-                      const char *OrcRuntimePath,
+                      JITDylib &PlatformJD, const char *OrcRuntimePath,
                       Optional<SymbolAliasMap> RuntimeAliases) {
 
+  auto &EPC = ES.getExecutorProcessControl();
+
   // If the target is not supported then bail out immediately.
   if (!supportedTarget(EPC.getTargetTriple()))
     return make_error<StringError>("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<MachOPlatform>(
-      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<DefinitionGenerator> 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<SPSMachOJITDylibInitializerSequence>(SPSString);
   WFs[ES.intern("___orc_rt_macho_get_initializers_tag")] =
-      EPC.wrapAsyncWithSPS<GetInitializersSPSSig>(
+      ES.wrapAsyncWithSPS<GetInitializersSPSSig>(
           this, &MachOPlatform::rt_getInitializers);
 
   using GetDeinitializersSPSSig =
       SPSExpected<SPSMachOJITDylibDeinitializerSequence>(SPSExecutorAddress);
   WFs[ES.intern("___orc_rt_macho_get_deinitializers_tag")] =
-      EPC.wrapAsyncWithSPS<GetDeinitializersSPSSig>(
+      ES.wrapAsyncWithSPS<GetDeinitializersSPSSig>(
           this, &MachOPlatform::rt_getDeinitializers);
 
   using LookupSymbolSPSSig =
       SPSExpected<SPSExecutorAddress>(SPSExecutorAddress, SPSString);
   WFs[ES.intern("___orc_rt_macho_symbol_lookup_tag")] =
-      EPC.wrapAsyncWithSPS<LookupSymbolSPSSig>(this,
-                                               &MachOPlatform::rt_lookupSymbol);
+      ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(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<void()>(orc_rt_macho_platform_bootstrap.getValue()))
+          ES.callSPSWrapper<void()>(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<shared::SPSError(
+  if (auto Err = ES.callSPSWrapper<shared::SPSError(
                      SPSMachOPerObjectSectionsToRegister)>(
           orc_rt_macho_register_object_sections.getValue(), ErrResult, POSR))
     return Err;
@@ -604,7 +607,7 @@ Expected<uint64_t> MachOPlatform::createPThreadKey() {
         inconvertibleErrorCode());
 
   Expected<uint64_t> Result(0);
-  if (auto Err = EPC.runSPSWrapper<SPSExpected<uint64_t>(void)>(
+  if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(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 41769170ca716..fd260089c04ba 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, ObjectLayer>;
 
+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 e6fdd065b9958..d6f73a8b0864c 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 50917a92b3be4..af614c01b9a88 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<orc::UnsupportedExecutorProcessControl>());
     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<orc::ExecutionSession>();
+    auto ES = std::make_unique<orc::ExecutionSession>(
+        ExitOnErr(orc::SelfExecutorProcessControl::Create()));
     Builder.setLazyCallthroughManager(
         std::make_unique<orc::LazyCallThroughManager>(*ES, 0, nullptr));
     Builder.setExecutionSession(std::move(ES));
@@ -934,9 +936,9 @@ int runOrcJIT(const char *ProgName) {
                                                 const Triple &) {
       auto L = std::make_unique<orc::ObjectLinkingLayer>(ES, EPC->getMemMgr());
       L->addPlugin(std::make_unique<orc::EHFrameRegistrationPlugin>(
-          ES, ExitOnErr(orc::EPCEHFrameRegistrar::Create(*EPC))));
+          ES, ExitOnErr(orc::EPCEHFrameRegistrar::Create(ES))));
       L->addPlugin(std::make_unique<orc::DebugObjectManagerPlugin>(
-          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 6e03d63cbf750..8bd384ec746fc 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<std::unique_ptr<Session>> 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<ExecutorProcessControl> 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<ExecutorProcessControl> 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<EHFrameRegistrationPlugin>(
-        ES, ExitOnErr(EPCEHFrameRegistrar::Create(*this->EPC))));
+        ES, ExitOnErr(EPCEHFrameRegistrar::Create(this->ES))));
     ObjLayer.addPlugin(std::make_unique<DebugObjectManagerPlugin>(
-        ES, ExitOnErr(createJITLoaderGDBRegistrar(*this->EPC))));
+        ES, ExitOnErr(createJITLoaderGDBRegistrar(this->ES))));
   }
 
   ObjLayer.addPlugin(std::make_unique<JITLinkSessionPlugin>(*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<StringError>("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<JITEvaluatedSymbol> getMainEntryPoint(Session &S) {
 
 static Expected<JITEvaluatedSymbol> 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<JITEvaluatedSymbol> getOrcRuntimeEntryPoint(Session &S) {
 static Expected<int> 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<SPSString>);
   int64_t Result;
-  if (auto Err = S.EPC->runSPSWrapper<SPSRunProgramSig>(
+  if (auto Err = S.ES.callSPSWrapper<SPSRunProgramSig>(
           EntryPointAddress, Result, S.MainJD->getName(), DemangledEntryPoint,
           static_cast<std::vector<std::string> &>(InputArgv)))
     return std::move(Err);
@@ -1446,7 +1448,8 @@ static Expected<int> runWithRuntime(Session &S,
 
 static Expected<int> 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 5050b2fef7570..acb64a9a39ca3 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<orc::ExecutorProcessControl> 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 b544cfa1864e8..5c2a7879dcd3f 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 717987daa2ab6..020a261ac2386 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<UnsupportedExecutorProcessControl>()};
 
   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<UnsupportedExecutorProcessControl>()};
   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<UnsupportedExecutorProcessControl>()};
   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 23096c86f4d33..9044ead631826 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<void(int32_t)> SendResult,
   SendResult(X + Y);
 }
 
-TEST(ExecutorProcessControl, RunWrapperTemplate) {
-  auto EPC = cantFail(
-      SelfExecutorProcessControl::Create(std::make_shared<SymbolStringPool>()));
+TEST(ExecutionSessionWrapperFunctionCalls, RunWrapperTemplate) {
+  ExecutionSession ES(cantFail(SelfExecutorProcessControl::Create()));
 
   int32_t Result;
-  EXPECT_THAT_ERROR(EPC->runSPSWrapper<int32_t(int32_t, int32_t)>(
+  EXPECT_THAT_ERROR(ES.callSPSWrapper<int32_t(int32_t, int32_t)>(
                         pointerToJITTargetAddress(addWrapper), Result, 2, 3),
                     Succeeded());
   EXPECT_EQ(Result, 5);
 }
 
-TEST(ExecutorProcessControl, RunWrapperAsyncTemplate) {
-  auto EPC = cantFail(
-      SelfExecutorProcessControl::Create(std::make_shared<SymbolStringPool>()));
+TEST(ExecutionSessionWrapperFunctionCalls, RunWrapperAsyncTemplate) {
+  ExecutionSession ES(cantFail(SelfExecutorProcessControl::Create()));
 
   std::promise<MSVCPExpected<int32_t>> RP;
   using Sig = int32_t(int32_t, int32_t);
-  EPC->runSPSWrapperAsync<Sig>(
+  ES.callSPSWrapperAsync<Sig>(
       [&](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<SymbolStringPool>()));
-  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<int32_t(int32_t, int32_t)>(addAsyncWrapper);
+      ES.wrapAsyncWithSPS<int32_t(int32_t, int32_t)>(addAsyncWrapper);
 
-  cantFail(EPC->associateJITSideWrapperFunctions(JD, std::move(Associations)));
+  cantFail(ES.registerJITDispatchHandlers(JD, std::move(Associations)));
 
   std::promise<int32_t> 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 a628b86b9c5b4..f6413316b692d 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<UnsupportedExecutorProcessControl>()};
   JITDylib &JD = ES.createBareJITDylib("main");
   ObjectLinkingLayer ObjLinkingLayer{
       ES, std::make_unique<InProcessMemoryManager>()};

diff  --git a/llvm/unittests/ExecutionEngine/Orc/OrcTestCommon.h b/llvm/unittests/ExecutionEngine/Orc/OrcTestCommon.h
index d279235639527..a4581394a6e34 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<SymbolStringPool> SSP = std::make_shared<SymbolStringPool>();
-  ExecutionSession ES{SSP};
+  ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>(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 d00b900c97f6b..bff096915af6a 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<MemoryBuffer> Obj,
 
   bool NonAllocSectionSeen = false;
 
-  ExecutionSession ES;
+  ExecutionSession ES(std::make_unique<UnsupportedExecutorProcessControl>());
   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<UnsupportedExecutorProcessControl>()};
   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<UnsupportedExecutorProcessControl>()};
   auto &JD = ES.createBareJITDylib("main");
   auto Foo = ES.intern("foo");
   RTDyldObjectLinkingLayer ObjLayer(


        


More information about the llvm-commits mailing list