[LLI] Replace the LLI remote-JIT support with the new ORC remote-JIT components.
authorLang Hames <lhames@gmail.com>
Mon, 11 Jan 2016 16:35:55 +0000 (16:35 +0000)
committerLang Hames <lhames@gmail.com>
Mon, 11 Jan 2016 16:35:55 +0000 (16:35 +0000)
The new ORC remote-JITing support provides a superset of the old code's
functionality, so we can replace the old stuff. As a bonus, a couple of
previously XFAILed tests have started passing.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@257343 91177308-0d34-0410-b5e6-96231b3b80d8

23 files changed:
include/llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h
lib/ExecutionEngine/Orc/OrcMCJITReplacement.h
test/ExecutionEngine/MCJIT/remote/stubs-remote.ll
test/ExecutionEngine/MCJIT/remote/test-global-init-nonzero-sm-pic.ll
test/ExecutionEngine/MCJIT/remote/test-ptr-reloc-sm-pic.ll
test/ExecutionEngine/OrcMCJIT/remote/stubs-remote.ll
test/ExecutionEngine/OrcMCJIT/remote/test-global-init-nonzero-sm-pic.ll
test/ExecutionEngine/OrcMCJIT/remote/test-ptr-reloc-sm-pic.ll
tools/lli/CMakeLists.txt
tools/lli/ChildTarget/CMakeLists.txt
tools/lli/ChildTarget/ChildTarget.cpp
tools/lli/RPCChannel.h [deleted file]
tools/lli/RemoteJITUtils.h [new file with mode: 0644]
tools/lli/RemoteMemoryManager.cpp [deleted file]
tools/lli/RemoteMemoryManager.h [deleted file]
tools/lli/RemoteTarget.cpp [deleted file]
tools/lli/RemoteTarget.h [deleted file]
tools/lli/RemoteTargetExternal.cpp [deleted file]
tools/lli/RemoteTargetExternal.h [deleted file]
tools/lli/RemoteTargetMessage.h [deleted file]
tools/lli/Unix/RPCChannel.inc [deleted file]
tools/lli/Windows/RPCChannel.inc [deleted file]
tools/lli/lli.cpp

index cd93421..1b0488b 100644 (file)
 namespace llvm {
 namespace orc {
 
+/// Generic ORC Architecture support.
+///
+/// This class can be substituted as the target architecure support class for
+/// ORC templates that require one (e.g. IndirectStubsManagers). It does not
+/// support lazy JITing however, and any attempt to use that functionality
+/// will result in execution of an llvm_unreachable.
+class OrcGenericArchitecture {
+public:
+  static const unsigned PointerSize = sizeof(uintptr_t);
+  static const unsigned TrampolineSize = 1;
+  static const unsigned ResolverCodeSize = 1;
+
+  typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, void *TrampolineId);
+
+  static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
+                                void *CallbackMgr) {
+    llvm_unreachable("writeResolverCode is not supported by the generic host "
+                     "support class");
+  }
+
+  static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
+                               unsigned NumTrampolines) {
+    llvm_unreachable("writeTrampolines is not supported by the generic host "
+                     "support class");
+  }
+
+  class IndirectStubsInfo {
+  public:
+    const static unsigned StubSize = 1;
+    unsigned getNumStubs() const { llvm_unreachable("Not supported"); }
+    void *getStub(unsigned Idx) const { llvm_unreachable("Not supported"); }
+    void **getPtr(unsigned Idx) const { llvm_unreachable("Not supported"); }
+  };
+
+  static std::error_code emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
+                                                unsigned MinStubs,
+                                                void *InitialPtrVal) {
+    llvm_unreachable("emitIndirectStubsBlock is not supported by the generic "
+                     "host support class");
+  }
+};
+
+/// @brief X86_64 support.
+///
+/// X86_64 supports lazy JITing.
 class OrcX86_64 {
 public:
   static const unsigned PointerSize = 8;
   static const unsigned TrampolineSize = 8;
   static const unsigned ResolverCodeSize = 0x78;
 
-  typedef TargetAddress (*JITReentryFn)(void *CallbackMgr,
-                                        void *TrampolineId);
+  typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, void *TrampolineId);
 
   /// @brief Write the resolver code into the given memory. The user is be
   ///        responsible for allocating the memory and setting permissions.
@@ -49,6 +93,7 @@ public:
   ///        makeIndirectStubsBlock function.
   class IndirectStubsInfo {
     friend class OrcX86_64;
+
   public:
     const static unsigned StubSize = 8;
 
@@ -57,7 +102,7 @@ public:
         : NumStubs(Other.NumStubs), StubsMem(std::move(Other.StubsMem)) {
       Other.NumStubs = 0;
     }
-    IndirectStubsInfooperator=(IndirectStubsInfo &&Other) {
+    IndirectStubsInfo &operator=(IndirectStubsInfo &&Other) {
       NumStubs = Other.NumStubs;
       Other.NumStubs = 0;
       StubsMem = std::move(Other.StubsMem);
@@ -69,17 +114,18 @@ public:
 
     /// @brief Get a pointer to the stub at the given index, which must be in
     ///        the range 0 .. getNumStubs() - 1.
-    voidgetStub(unsigned Idx) const {
-      return static_cast<uint64_t*>(StubsMem.base()) + Idx;
+    void *getStub(unsigned Idx) const {
+      return static_cast<uint64_t *>(StubsMem.base()) + Idx;
     }
 
     /// @brief Get a pointer to the implementation-pointer at the given index,
     ///        which must be in the range 0 .. getNumStubs() - 1.
-    void** getPtr(unsigned Idx) const {
+    void **getPtr(unsigned Idx) const {
       char *PtrsBase =
-        static_cast<char*>(StubsMem.base()) + NumStubs * StubSize;
-      return reinterpret_cast<void**>(PtrsBase) + Idx;
+          static_cast<char *>(StubsMem.base()) + NumStubs * StubSize;
+      return reinterpret_cast<void **>(PtrsBase) + Idx;
     }
+
   private:
     unsigned NumStubs;
     sys::OwningMemoryBlock StubsMem;
index 61d8ec9..2ab70a9 100644 (file)
@@ -77,6 +77,11 @@ class OrcMCJITReplacement : public ExecutionEngine {
       return ClientMM->deregisterEHFrames(Addr, LoadAddr, Size);
     }
 
+    void notifyObjectLoaded(RuntimeDyld &RTDyld,
+                            const object::ObjectFile &O) override {
+      return ClientMM->notifyObjectLoaded(RTDyld, O);
+    }
+
     void notifyObjectLoaded(ExecutionEngine *EE,
                             const object::ObjectFile &O) override {
       return ClientMM->notifyObjectLoaded(EE, O);
index a834ac5..0c4df7b 100644 (file)
@@ -1,5 +1,4 @@
 ; RUN: %lli -remote-mcjit -disable-lazy-compilation=false -mcjit-remote-process=lli-child-target%exeext %s
-; XFAIL: *
 ; This test should fail until remote symbol resolution is supported.
 
 define i32 @main() nounwind {
index e350b85..619c827 100644 (file)
@@ -1,4 +1,5 @@
-; RUN: %lli -remote-mcjit -relocation-model=pic -code-model=small %s > /dev/null
+; RUN: %lli -remote-mcjit -mcjit-remote-process=lli-child-target%exeext \
+; RUN:   -relocation-model=pic -code-model=small %s > /dev/null
 ; XFAIL: mips-, mipsel-, aarch64, arm, i686, i386
 
 @count = global i32 1, align 4
index 7162e92..31d8770 100644 (file)
@@ -1,4 +1,5 @@
-; RUN: %lli -remote-mcjit -O0 -relocation-model=pic -code-model=small %s
+; RUN: %lli -remote-mcjit -mcjit-remote-process=lli-child-target%exeext \
+; RUN:   -O0 -relocation-model=pic -code-model=small %s
 ; XFAIL: mips-, mipsel-, aarch64, arm, i686, i386
 
 @.str = private unnamed_addr constant [6 x i8] c"data1\00", align 1
index aeff011..523011c 100644 (file)
@@ -1,5 +1,4 @@
 ; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -disable-lazy-compilation=false -mcjit-remote-process=lli-child-target%exeext %s
-; XFAIL: *
 ; This test should fail until remote symbol resolution is supported.
 
 define i32 @main() nounwind {
index f1e9313..fc15fba 100644 (file)
@@ -1,4 +1,5 @@
-; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -relocation-model=pic -code-model=small %s > /dev/null
+; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -mcjit-remote-process=lli-child-target%exeext \
+; RUN:   -relocation-model=pic -code-model=small %s > /dev/null
 ; XFAIL: mips-, mipsel-, aarch64, arm, i686, i386
 
 @count = global i32 1, align 4
index cac800e..915dfa6 100644 (file)
@@ -1,4 +1,5 @@
-; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -O0 -relocation-model=pic -code-model=small %s
+; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -mcjit-remote-process=lli-child-target%exeext \
+; RUN:   -O0 -relocation-model=pic -code-model=small %s
 ; XFAIL: mips-, mipsel-, aarch64, arm, i686, i386
 
 @.str = private unnamed_addr constant [6 x i8] c"data1\00", align 1
index 4af0596..e317db6 100644 (file)
@@ -38,8 +38,5 @@ endif( LLVM_USE_INTEL_JITEVENTS )
 add_llvm_tool(lli
   lli.cpp
   OrcLazyJIT.cpp
-  RemoteMemoryManager.cpp
-  RemoteTarget.cpp
-  RemoteTargetExternal.cpp
   )
 export_executable_symbols(lli)
index 9f88b2c..abc1722 100644 (file)
@@ -1,8 +1,10 @@
-set(LLVM_LINK_COMPONENTS support)
+set(LLVM_LINK_COMPONENTS
+  OrcJIT
+  Support
+  )
 
 add_llvm_executable(lli-child-target
   ChildTarget.cpp
-  ../RemoteTarget.cpp
 )
 
 set_target_properties(lli-child-target PROPERTIES FOLDER "Misc")
index 6c537d4..0b75e20 100644 (file)
-#include "llvm/Config/config.h"
-#include "../RPCChannel.h"
-#include "../RemoteTarget.h"
-#include "../RemoteTargetMessage.h"
-#include "llvm/Support/Memory.h"
-#include <assert.h>
-#include <map>
-#include <stdint.h>
-#include <string>
-#include <vector>
+#include "llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h"
+#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Process.h"
+#include <sstream>
 
-using namespace llvm;
+#include "../RemoteJITUtils.h"
 
-class LLIChildTarget {
-public:
-  void initialize();
-  LLIMessageType waitForIncomingMessage();
-  void handleMessage(LLIMessageType messageType);
-  RemoteTarget *RT;
-  RPCChannel RPC;
+using namespace llvm;
+using namespace llvm::orc;
+using namespace llvm::sys;
 
-private:
-  // Incoming message handlers
-  void handleAllocateSpace();
-  void handleLoadSection(bool IsCode);
-  void handleExecute();
+#ifdef __x86_64__
+typedef OrcX86_64 HostOrcArch;
+#else
+typedef OrcGenericArchitecture HostOrcArch;
+#endif
 
-  // Outgoing message handlers
-  void sendChildActive();
-  void sendAllocationResult(uint64_t Addr);
-  void sendLoadStatus(uint32_t Status);
-  void sendExecutionComplete(int Result);
+int main(int argc, char *argv[]) {
 
-  // OS-specific functions
-  void initializeConnection();
-  int WriteBytes(const void *Data, size_t Size) {
-    return RPC.WriteBytes(Data, Size) ? Size : -1;
+  if (argc != 3) {
+    errs() << "Usage: " << argv[0] << " <input fd> <output fd>\n";
+    return 1;
   }
-  int ReadBytes(void *Data, size_t Size) {
-    return RPC.ReadBytes(Data, Size) ? Size : -1;
-  }
-
-  // Communication handles (OS-specific)
-  void *ConnectionData;
-};
-
-int main() {
-  LLIChildTarget  ThisChild;
-  ThisChild.RT = new RemoteTarget();
-  ThisChild.initialize();
-  LLIMessageType MsgType;
-  do {
-    MsgType = ThisChild.waitForIncomingMessage();
-    ThisChild.handleMessage(MsgType);
-  } while (MsgType != LLI_Terminate &&
-           MsgType != LLI_Error);
-  delete ThisChild.RT;
-  return 0;
-}
 
-// Public methods
-void LLIChildTarget::initialize() {
-  RPC.createClient();
-  sendChildActive();
-}
+  int InFD;
+  int OutFD;
+  {
+    std::istringstream InFDStream(argv[1]), OutFDStream(argv[2]);
+    InFDStream >> InFD;
+    OutFDStream >> OutFD;
+  }
 
-LLIMessageType LLIChildTarget::waitForIncomingMessage() {
-  int32_t MsgType = -1;
-  if (ReadBytes(&MsgType, 4) > 0)
-    return (LLIMessageType)MsgType;
-  return LLI_Error;
-}
+  if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr)) {
+    errs() << "Error loading program symbols.\n";
+    return 1;
+  }
 
-void LLIChildTarget::handleMessage(LLIMessageType messageType) {
-  switch (messageType) {
-    case LLI_AllocateSpace:
-      handleAllocateSpace();
-      break;
-    case LLI_LoadCodeSection:
-      handleLoadSection(true);
-      break;
-    case LLI_LoadDataSection:
-      handleLoadSection(false);
-      break;
-    case LLI_Execute:
-      handleExecute();
-      break;
-    case LLI_Terminate:
-      RT->stop();
-      break;
+  auto SymbolLookup = [](const std::string &Name) {
+    return RTDyldMemoryManager::getSymbolAddressInProcess(Name);
+  };
+
+  FDRPCChannel Channel(InFD, OutFD);
+  typedef remote::OrcRemoteTargetServer<FDRPCChannel, HostOrcArch> JITServer;
+  JITServer Server(Channel, SymbolLookup);
+
+  while (1) {
+    JITServer::JITProcId Id = JITServer::InvalidId;
+    if (auto EC = Server.getNextProcId(Id)) {
+      errs() << "Error: " << EC.message() << "\n";
+      return 1;
+    }
+    switch (Id) {
+    case JITServer::TerminateSessionId:
+      return 0;
     default:
-      // FIXME: Handle error!
-      break;
+      if (auto EC = Server.handleKnownProcedure(Id)) {
+        errs() << "Error: " << EC.message() << "\n";
+        return 1;
+      }
+    }
   }
-}
-
-// Incoming message handlers
-void LLIChildTarget::handleAllocateSpace() {
-  // Read and verify the message data size.
-  uint32_t DataSize = 0;
-  int rc = ReadBytes(&DataSize, 4);
-  (void)rc;
-  assert(rc == 4);
-  assert(DataSize == 8);
-
-  // Read the message arguments.
-  uint32_t Alignment = 0;
-  uint32_t AllocSize = 0;
-  rc = ReadBytes(&Alignment, 4);
-  assert(rc == 4);
-  rc = ReadBytes(&AllocSize, 4);
-  assert(rc == 4);
-
-  // Allocate the memory.
-  uint64_t Addr;
-  RT->allocateSpace(AllocSize, Alignment, Addr);
-
-  // Send AllocationResult message.
-  sendAllocationResult(Addr);
-}
-
-void LLIChildTarget::handleLoadSection(bool IsCode) {
-  // Read the message data size.
-  uint32_t DataSize = 0;
-  int rc = ReadBytes(&DataSize, 4);
-  (void)rc;
-  assert(rc == 4);
-
-  // Read the target load address.
-  uint64_t Addr = 0;
-  rc = ReadBytes(&Addr, 8);
-  assert(rc == 8);
-  size_t BufferSize = DataSize - 8;
-
-  if (!RT->isAllocatedMemory(Addr, BufferSize))
-    return sendLoadStatus(LLI_Status_NotAllocated);
-
-  // Read section data into previously allocated buffer
-  rc = ReadBytes((void*)Addr, BufferSize);
-  if (rc != (int)(BufferSize))
-    return sendLoadStatus(LLI_Status_IncompleteMsg);
-
-  // If IsCode, mark memory executable
-  if (IsCode)
-    sys::Memory::InvalidateInstructionCache((void *)Addr, BufferSize);
-
-  // Send MarkLoadComplete message.
-  sendLoadStatus(LLI_Status_Success);
-}
-
-void LLIChildTarget::handleExecute() {
-  // Read the message data size.
-  uint32_t DataSize = 0;
-  int rc = ReadBytes(&DataSize, 4);
-  (void)rc;
-  assert(rc == 4);
-  assert(DataSize == 8);
-
-  // Read the target address.
-  uint64_t Addr = 0;
-  rc = ReadBytes(&Addr, 8);
-  assert(rc == 8);
-
-  // Call function
-  int32_t Result = -1;
-  RT->executeCode(Addr, Result);
-
-  // Send ExecutionResult message.
-  sendExecutionComplete(Result);
-}
-
-// Outgoing message handlers
-void LLIChildTarget::sendChildActive() {
-  // Write the message type.
-  uint32_t MsgType = (uint32_t)LLI_ChildActive;
-  int rc = WriteBytes(&MsgType, 4);
-  (void)rc;
-  assert(rc == 4);
-
-  // Write the data size.
-  uint32_t DataSize = 0;
-  rc = WriteBytes(&DataSize, 4);
-  assert(rc == 4);
-}
-
-void LLIChildTarget::sendAllocationResult(uint64_t Addr) {
-  // Write the message type.
-  uint32_t MsgType = (uint32_t)LLI_AllocationResult;
-  int rc = WriteBytes(&MsgType, 4);
-  (void)rc;
-  assert(rc == 4);
-
-  // Write the data size.
-  uint32_t DataSize = 8;
-  rc = WriteBytes(&DataSize, 4);
-  assert(rc == 4);
-
-  // Write the allocated address.
-  rc = WriteBytes(&Addr, 8);
-  assert(rc == 8);
-}
-
-void LLIChildTarget::sendLoadStatus(uint32_t Status) {
-  // Write the message type.
-  uint32_t MsgType = (uint32_t)LLI_LoadResult;
-  int rc = WriteBytes(&MsgType, 4);
-  (void)rc;
-  assert(rc == 4);
-
-  // Write the data size.
-  uint32_t DataSize = 4;
-  rc = WriteBytes(&DataSize, 4);
-  assert(rc == 4);
-
-  // Write the result.
-  rc = WriteBytes(&Status, 4);
-  assert(rc == 4);
-}
-
-void LLIChildTarget::sendExecutionComplete(int Result) {
-  // Write the message type.
-  uint32_t MsgType = (uint32_t)LLI_ExecutionResult;
-  int rc = WriteBytes(&MsgType, 4);
-  (void)rc;
-  assert(rc == 4);
 
+  close(InFD);
+  close(OutFD);
 
-  // Write the data size.
-  uint32_t DataSize = 4;
-  rc = WriteBytes(&DataSize, 4);
-  assert(rc == 4);
-
-  // Write the result.
-  rc = WriteBytes(&Result, 4);
-  assert(rc == 4);
+  return 0;
 }
-
-#ifdef LLVM_ON_UNIX
-#include "../Unix/RPCChannel.inc"
-#endif
-
-#ifdef LLVM_ON_WIN32
-#include "../Windows/RPCChannel.inc"
-#endif
diff --git a/tools/lli/RPCChannel.h b/tools/lli/RPCChannel.h
deleted file mode 100644 (file)
index ebd3c65..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-//===---------- RPCChannel.h - LLVM out-of-process JIT execution ----------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Definition of the RemoteTargetExternal class which executes JITed code in a
-// separate process from where it was built.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLI_RPCCHANNEL_H
-#define LLVM_TOOLS_LLI_RPCCHANNEL_H
-
-#include <stdlib.h>
-#include <string>
-
-namespace llvm {
-
-class RPCChannel {
-public:
-  std::string ChildName;
-
-  RPCChannel() {}
-  ~RPCChannel();
-
-  /// Start the remote process.
-  ///
-  /// @returns True on success. On failure, ErrorMsg is updated with
-  ///          descriptive text of the encountered error.
-  bool createServer();
-
-  bool createClient();
-
-  // This will get filled in as a point to an OS-specific structure.
-  void *ConnectionData;
-
-  bool WriteBytes(const void *Data, size_t Size);
-  bool ReadBytes(void *Data, size_t Size);
-
-  void Wait();
-};
-
-} // end namespace llvm
-
-#endif
diff --git a/tools/lli/RemoteJITUtils.h b/tools/lli/RemoteJITUtils.h
new file mode 100644 (file)
index 0000000..792d8d0
--- /dev/null
@@ -0,0 +1,131 @@
+//===-- RemoteJITUtils.h - Utilities for remote-JITing with LLI -*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Utilities for remote-JITing with LLI.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLI_REMOTEJITUTILS_H
+#define LLVM_TOOLS_LLI_REMOTEJITUTILS_H
+
+#include "llvm/ExecutionEngine/Orc/RPCChannel.h"
+#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
+
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+/// RPC channel that reads from and writes from file descriptors.
+class FDRPCChannel : public llvm::orc::remote::RPCChannel {
+public:
+  FDRPCChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {}
+
+  std::error_code readBytes(char *Dst, unsigned Size) override {
+    assert(Dst && "Attempt to read into null.");
+    ssize_t ReadResult = ::read(InFD, Dst, Size);
+    if (ReadResult != Size)
+      return std::error_code(errno, std::generic_category());
+    return std::error_code();
+  }
+
+  std::error_code appendBytes(const char *Src, unsigned Size) override {
+    assert(Src && "Attempt to append from null.");
+    ssize_t WriteResult = ::write(OutFD, Src, Size);
+    if (WriteResult != Size)
+      std::error_code(errno, std::generic_category());
+    return std::error_code();
+  }
+
+  std::error_code send() override { return std::error_code(); }
+
+private:
+  int InFD, OutFD;
+};
+
+// launch the remote process (see lli.cpp) and return a channel to it.
+std::unique_ptr<FDRPCChannel> launchRemote();
+
+namespace llvm {
+
+// ForwardingMM - Adapter to connect MCJIT to Orc's Remote memory manager.
+class ForwardingMemoryManager : public llvm::RTDyldMemoryManager {
+public:
+  void setMemMgr(std::unique_ptr<RuntimeDyld::MemoryManager> MemMgr) {
+    this->MemMgr = std::move(MemMgr);
+  }
+
+  void setResolver(std::unique_ptr<RuntimeDyld::SymbolResolver> Resolver) {
+    this->Resolver = std::move(Resolver);
+  }
+
+  uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
+                               unsigned SectionID,
+                               StringRef SectionName) override {
+    return MemMgr->allocateCodeSection(Size, Alignment, SectionID, SectionName);
+  }
+
+  uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
+                               unsigned SectionID, StringRef SectionName,
+                               bool IsReadOnly) override {
+    return MemMgr->allocateDataSection(Size, Alignment, SectionID, SectionName,
+                                       IsReadOnly);
+  }
+
+  void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
+                              uintptr_t RODataSize, uint32_t RODataAlign,
+                              uintptr_t RWDataSize,
+                              uint32_t RWDataAlign) override {
+    MemMgr->reserveAllocationSpace(CodeSize, CodeAlign, RODataSize, RODataAlign,
+                                   RWDataSize, RWDataAlign);
+  }
+
+  bool needsToReserveAllocationSpace() override {
+    return MemMgr->needsToReserveAllocationSpace();
+  }
+
+  void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
+                        size_t Size) override {
+    MemMgr->registerEHFrames(Addr, LoadAddr, Size);
+  }
+
+  void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr,
+                          size_t Size) override {
+    MemMgr->deregisterEHFrames(Addr, LoadAddr, Size);
+  }
+
+  bool finalizeMemory(std::string *ErrMsg = nullptr) override {
+    return MemMgr->finalizeMemory(ErrMsg);
+  }
+
+  void notifyObjectLoaded(RuntimeDyld &RTDyld,
+                          const object::ObjectFile &Obj) override {
+    MemMgr->notifyObjectLoaded(RTDyld, Obj);
+  }
+
+  // Don't hide the sibling notifyObjectLoaded from RTDyldMemoryManager.
+  using RTDyldMemoryManager::notifyObjectLoaded;
+
+  RuntimeDyld::SymbolInfo findSymbol(const std::string &Name) override {
+    return Resolver->findSymbol(Name);
+  }
+
+  RuntimeDyld::SymbolInfo
+  findSymbolInLogicalDylib(const std::string &Name) override {
+    return Resolver->findSymbolInLogicalDylib(Name);
+  }
+
+private:
+  std::unique_ptr<RuntimeDyld::MemoryManager> MemMgr;
+  std::unique_ptr<RuntimeDyld::SymbolResolver> Resolver;
+};
+}
+
+#endif
diff --git a/tools/lli/RemoteMemoryManager.cpp b/tools/lli/RemoteMemoryManager.cpp
deleted file mode 100644 (file)
index 0a16210..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-//===---- RemoteMemoryManager.cpp - Recording memory manager --------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This memory manager allocates local storage and keeps a record of each
-// allocation. Iterators are provided for all data and code allocations.
-//
-//===----------------------------------------------------------------------===//
-
-#include "RemoteMemoryManager.h"
-#include "llvm/ExecutionEngine/ExecutionEngine.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace llvm;
-
-#define DEBUG_TYPE "lli"
-
-RemoteMemoryManager::~RemoteMemoryManager() {
-  for (SmallVector<Allocation, 2>::iterator
-         I = AllocatedSections.begin(), E = AllocatedSections.end();
-       I != E; ++I)
-    sys::Memory::releaseMappedMemory(I->MB);
-}
-
-uint8_t *RemoteMemoryManager::
-allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID,
-                    StringRef SectionName) {
-  // The recording memory manager is just a local copy of the remote target.
-  // The alignment requirement is just stored here for later use. Regular
-  // heap storage is sufficient here, but we're using mapped memory to work
-  // around a bug in MCJIT.
-  sys::MemoryBlock Block = allocateSection(Size);
-  // AllocatedSections will own this memory.
-  AllocatedSections.push_back( Allocation(Block, Alignment, true) );
-  // UnmappedSections has the same information but does not own the memory.
-  UnmappedSections.push_back( Allocation(Block, Alignment, true) );
-  return (uint8_t*)Block.base();
-}
-
-uint8_t *RemoteMemoryManager::
-allocateDataSection(uintptr_t Size, unsigned Alignment,
-                    unsigned SectionID, StringRef SectionName,
-                    bool IsReadOnly) {
-  // The recording memory manager is just a local copy of the remote target.
-  // The alignment requirement is just stored here for later use. Regular
-  // heap storage is sufficient here, but we're using mapped memory to work
-  // around a bug in MCJIT.
-  sys::MemoryBlock Block = allocateSection(Size);
-  // AllocatedSections will own this memory.
-  AllocatedSections.push_back( Allocation(Block, Alignment, false) );
-  // UnmappedSections has the same information but does not own the memory.
-  UnmappedSections.push_back( Allocation(Block, Alignment, false) );
-  return (uint8_t*)Block.base();
-}
-
-sys::MemoryBlock RemoteMemoryManager::allocateSection(uintptr_t Size) {
-  std::error_code ec;
-  sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(Size,
-                                                          &Near,
-                                                          sys::Memory::MF_READ |
-                                                          sys::Memory::MF_WRITE,
-                                                          ec);
-  assert(!ec && MB.base());
-
-  // FIXME: This is part of a work around to keep sections near one another
-  // when MCJIT performs relocations after code emission but before
-  // the generated code is moved to the remote target.
-  // Save this address as the basis for our next request
-  Near = MB;
-  return MB;
-}
-
-void RemoteMemoryManager::notifyObjectLoaded(ExecutionEngine *EE,
-                                             const object::ObjectFile &Obj) {
-  // The client should have called setRemoteTarget() before triggering any
-  // code generation.
-  assert(Target);
-  if (!Target)
-    return;
-
-  // FIXME: Make this function thread safe.
-
-  // Lay out our sections in order, with all the code sections first, then
-  // all the data sections.
-  uint64_t CurOffset = 0;
-  unsigned MaxAlign = Target->getPageAlignment();
-  SmallVector<std::pair<Allocation, uint64_t>, 16> Offsets;
-  unsigned NumSections = UnmappedSections.size();
-  // We're going to go through the list twice to separate code and data, but
-  // it's a very small list, so that's OK.
-  for (size_t i = 0, e = NumSections; i != e; ++i) {
-    Allocation &Section = UnmappedSections[i];
-    if (Section.IsCode) {
-      unsigned Size = Section.MB.size();
-      unsigned Align = Section.Alignment;
-      DEBUG(dbgs() << "code region: size " << Size
-                  << ", alignment " << Align << "\n");
-      // Align the current offset up to whatever is needed for the next
-      // section.
-      CurOffset = (CurOffset + Align - 1) / Align * Align;
-      // Save off the address of the new section and allocate its space.
-      Offsets.push_back(std::pair<Allocation,uint64_t>(Section, CurOffset));
-      CurOffset += Size;
-    }
-  }
-  // Adjust to keep code and data aligned on separate pages.
-  CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign;
-  for (size_t i = 0, e = NumSections; i != e; ++i) {
-    Allocation &Section = UnmappedSections[i];
-    if (!Section.IsCode) {
-      unsigned Size = Section.MB.size();
-      unsigned Align = Section.Alignment;
-      DEBUG(dbgs() << "data region: size " << Size
-                  << ", alignment " << Align << "\n");
-      // Align the current offset up to whatever is needed for the next
-      // section.
-      CurOffset = (CurOffset + Align - 1) / Align * Align;
-      // Save off the address of the new section and allocate its space.
-      Offsets.push_back(std::pair<Allocation,uint64_t>(Section, CurOffset));
-      CurOffset += Size;
-    }
-  }
-
-  // Allocate space in the remote target.
-  uint64_t RemoteAddr;
-  if (!Target->allocateSpace(CurOffset, MaxAlign, RemoteAddr))
-    report_fatal_error(Target->getErrorMsg());
-
-  // Map the section addresses so relocations will get updated in the local
-  // copies of the sections.
-  for (unsigned i = 0, e = Offsets.size(); i != e; ++i) {
-    uint64_t Addr = RemoteAddr + Offsets[i].second;
-    EE->mapSectionAddress(const_cast<void*>(Offsets[i].first.MB.base()), Addr);
-
-    DEBUG(dbgs() << "  Mapping local: " << Offsets[i].first.MB.base()
-                 << " to remote: 0x" << format("%llx", Addr) << "\n");
-
-    MappedSections[Addr] = Offsets[i].first;
-  }
-
-  UnmappedSections.clear();
-}
-
-bool RemoteMemoryManager::finalizeMemory(std::string *ErrMsg) {
-  // FIXME: Make this function thread safe.
-  for (DenseMap<uint64_t, Allocation>::iterator
-         I = MappedSections.begin(), E = MappedSections.end();
-       I != E; ++I) {
-    uint64_t RemoteAddr = I->first;
-    const Allocation &Section = I->second;
-    if (Section.IsCode) {
-      if (!Target->loadCode(RemoteAddr, Section.MB.base(), Section.MB.size()))
-        report_fatal_error(Target->getErrorMsg());
-      DEBUG(dbgs() << "  loading code: " << Section.MB.base()
-            << " to remote: 0x" << format("%llx", RemoteAddr) << "\n");
-    } else {
-      if (!Target->loadData(RemoteAddr, Section.MB.base(), Section.MB.size()))
-        report_fatal_error(Target->getErrorMsg());
-      DEBUG(dbgs() << "  loading data: " << Section.MB.base()
-            << " to remote: 0x" << format("%llx", RemoteAddr) << "\n");
-    }
-  }
-
-  MappedSections.clear();
-
-  return false;
-}
diff --git a/tools/lli/RemoteMemoryManager.h b/tools/lli/RemoteMemoryManager.h
deleted file mode 100644 (file)
index 5733fa5..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-//===- RemoteMemoryManager.h - LLI MCJIT recording memory manager ------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This memory manager allocates local storage and keeps a record of each
-// allocation. Iterators are provided for all data and code allocations.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLI_REMOTEMEMORYMANAGER_H
-#define LLVM_TOOLS_LLI_REMOTEMEMORYMANAGER_H
-
-#include "RemoteTarget.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/Memory.h"
-#include <utility>
-
-namespace llvm {
-
-class RemoteMemoryManager : public RTDyldMemoryManager {
-public:
-  // Notice that this structure takes ownership of the memory allocated.
-  struct Allocation {
-    Allocation() {}
-    Allocation(sys::MemoryBlock mb, unsigned a, bool code)
-      : MB(mb), Alignment(a), IsCode(code) {}
-
-    sys::MemoryBlock  MB;
-    unsigned          Alignment;
-    bool              IsCode;
-  };
-
-private:
-  // This vector contains Allocation objects for all sections which we have
-  // allocated.  This vector effectively owns the memory associated with the
-  // allocations.
-  SmallVector<Allocation, 2>  AllocatedSections;
-
-  // This vector contains pointers to Allocation objects for any sections we
-  // have allocated locally but have not yet remapped for the remote target.
-  // When we receive notification of a completed module load, we will map
-  // these sections into the remote target.
-  SmallVector<Allocation, 2>  UnmappedSections;
-
-  // This map tracks the sections we have remapped for the remote target
-  // but have not yet copied to the target.
-  DenseMap<uint64_t, Allocation>  MappedSections;
-
-  // FIXME: This is part of a work around to keep sections near one another
-  // when MCJIT performs relocations after code emission but before
-  // the generated code is moved to the remote target.
-  sys::MemoryBlock Near;
-  sys::MemoryBlock allocateSection(uintptr_t Size);
-
-  RemoteTarget *Target;
-
-public:
-  RemoteMemoryManager() : Target(nullptr) {}
-  ~RemoteMemoryManager() override;
-
-  uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
-                               unsigned SectionID,
-                               StringRef SectionName) override;
-
-  uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
-                               unsigned SectionID, StringRef SectionName,
-                               bool IsReadOnly) override;
-
-  // For now, remote symbol resolution is not support in lli.  The MCJIT
-  // interface does support this, but clients must provide their own
-  // mechanism for finding remote symbol addresses.  MCJIT will resolve
-  // symbols from Modules it contains.
-  uint64_t getSymbolAddress(const std::string &Name) override { return 0; }
-
-  void notifyObjectLoaded(ExecutionEngine *EE,
-                          const object::ObjectFile &Obj) override;
-
-  bool finalizeMemory(std::string *ErrMsg) override;
-
-  // For now, remote EH frame registration isn't supported.  Remote symbol
-  // resolution is a prerequisite to supporting remote EH frame registration.
-  void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
-                        size_t Size) override {}
-  void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr,
-                          size_t Size) override {}
-
-  // This is a non-interface function used by lli
-  void setRemoteTarget(RemoteTarget *T) { Target = T; }
-};
-
-} // end namespace llvm
-
-#endif
diff --git a/tools/lli/RemoteTarget.cpp b/tools/lli/RemoteTarget.cpp
deleted file mode 100644 (file)
index 95e1511..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-//===- RemoteTarget.cpp - LLVM Remote process JIT execution -----*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Implementation of the RemoteTarget class which executes JITed code in a
-// separate address range from where it was built.
-//
-//===----------------------------------------------------------------------===//
-
-#include "RemoteTarget.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/DataTypes.h"
-#include "llvm/Support/Memory.h"
-#include <stdlib.h>
-#include <string>
-
-using namespace llvm;
-
-////////////////////////////////////////////////////////////////////////////////
-// Simulated remote execution
-//
-// This implementation will simply move generated code and data to a new memory
-// location in the current executable and let it run from there.
-////////////////////////////////////////////////////////////////////////////////
-
-bool RemoteTarget::allocateSpace(size_t Size, unsigned Alignment,
-                                 uint64_t &Address) {
-  sys::MemoryBlock *Prev = Allocations.size() ? &Allocations.back() : nullptr;
-  sys::MemoryBlock Mem = sys::Memory::AllocateRWX(Size, Prev, &ErrorMsg);
-  if (Mem.base() == nullptr)
-    return false;
-  if ((uintptr_t)Mem.base() % Alignment) {
-    ErrorMsg = "unable to allocate sufficiently aligned memory";
-    return false;
-  }
-  Address = reinterpret_cast<uint64_t>(Mem.base());
-  Allocations.push_back(Mem);
-  return true;
-}
-
-bool RemoteTarget::loadData(uint64_t Address, const void *Data, size_t Size) {
-  memcpy ((void*)Address, Data, Size);
-  return true;
-}
-
-bool RemoteTarget::loadCode(uint64_t Address, const void *Data, size_t Size) {
-  memcpy ((void*)Address, Data, Size);
-  sys::MemoryBlock Mem((void*)Address, Size);
-  sys::Memory::setExecutable(Mem, &ErrorMsg);
-  return true;
-}
-
-bool RemoteTarget::executeCode(uint64_t Address, int &RetVal) {
-  int (*fn)() = (int(*)())Address;
-  RetVal = fn();
-  return true;
-}
-
-bool RemoteTarget::create() {
-  return true;
-}
-
-void RemoteTarget::stop() {
-  for (unsigned i = 0, e = Allocations.size(); i != e; ++i)
-    sys::Memory::ReleaseRWX(Allocations[i]);
-}
diff --git a/tools/lli/RemoteTarget.h b/tools/lli/RemoteTarget.h
deleted file mode 100644 (file)
index ee758a2..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-//===- RemoteTarget.h - LLVM Remote process JIT execution ----------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Definition of the RemoteTarget class which executes JITed code in a
-// separate address range from where it was built.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLI_REMOTETARGET_H
-#define LLVM_TOOLS_LLI_REMOTETARGET_H
-
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/DataTypes.h"
-#include "llvm/Support/Memory.h"
-#include <stdlib.h>
-#include <string>
-
-namespace llvm {
-
-class RemoteTarget {
-  bool IsRunning;
-
-  typedef SmallVector<sys::MemoryBlock, 16> AllocMapType;
-  AllocMapType Allocations;
-
-protected:
-  std::string ErrorMsg;
-
-public:
-  StringRef getErrorMsg() const { return ErrorMsg; }
-
-  /// Allocate space in the remote target address space.
-  ///
-  /// @param      Size      Amount of space, in bytes, to allocate.
-  /// @param      Alignment Required minimum alignment for allocated space.
-  /// @param[out] Address   Remote address of the allocated memory.
-  ///
-  /// @returns True on success. On failure, ErrorMsg is updated with
-  ///          descriptive text of the encountered error.
-  virtual bool allocateSpace(size_t Size,
-                             unsigned Alignment,
-                             uint64_t &Address);
-
-  bool isAllocatedMemory(uint64_t Address, uint32_t Size) {
-    uint64_t AddressEnd = Address + Size;
-    for (AllocMapType::const_iterator I = Allocations.begin(),
-                                      E = Allocations.end();
-         I != E; ++I) {
-      if (Address >= (uint64_t)I->base() &&
-          AddressEnd <= (uint64_t)I->base() + I->size())
-        return true;
-    }
-    return false;
-  }
-
-  /// Load data into the target address space.
-  ///
-  /// @param      Address   Destination address in the target process.
-  /// @param      Data      Source address in the host process.
-  /// @param      Size      Number of bytes to copy.
-  ///
-  /// @returns True on success. On failure, ErrorMsg is updated with
-  ///          descriptive text of the encountered error.
-  virtual bool loadData(uint64_t Address,
-                        const void *Data,
-                        size_t Size);
-
-  /// Load code into the target address space and prepare it for execution.
-  ///
-  /// @param      Address   Destination address in the target process.
-  /// @param      Data      Source address in the host process.
-  /// @param      Size      Number of bytes to copy.
-  ///
-  /// @returns True on success. On failure, ErrorMsg is updated with
-  ///          descriptive text of the encountered error.
-  virtual bool loadCode(uint64_t Address,
-                        const void *Data,
-                        size_t Size);
-
-  /// Execute code in the target process. The called function is required
-  /// to be of signature int "(*)(void)".
-  ///
-  /// @param      Address   Address of the loaded function in the target
-  ///                       process.
-  /// @param[out] RetVal    The integer return value of the called function.
-  ///
-  /// @returns True on success. On failure, ErrorMsg is updated with
-  ///          descriptive text of the encountered error.
-  virtual bool executeCode(uint64_t Address,
-                           int &RetVal);
-
-  /// Minimum alignment for memory permissions. Used to separate code and
-  /// data regions to make sure data doesn't get marked as code or vice
-  /// versa.
-  ///
-  /// @returns Page alignment return value. Default of 4k.
-  virtual unsigned getPageAlignment() { return 4096; }
-
-  /// Start the remote process.
-  virtual bool create();
-
-  /// Terminate the remote process.
-  virtual void stop();
-
-  RemoteTarget() : IsRunning(false), ErrorMsg("") {}
-  virtual ~RemoteTarget() { if (IsRunning) stop(); }
-private:
-  // Main processing function for the remote target process. Command messages
-  // are received on file descriptor CmdFD and responses come back on OutFD.
-  static void doRemoteTargeting(int CmdFD, int OutFD);
-};
-
-} // end namespace llvm
-
-#endif
diff --git a/tools/lli/RemoteTargetExternal.cpp b/tools/lli/RemoteTargetExternal.cpp
deleted file mode 100644 (file)
index fe46248..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-//===---- RemoteTargetExternal.cpp - LLVM out-of-process JIT execution ----===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Implementation of the RemoteTargetExternal class which executes JITed code
-// in a separate process from where it was built.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Config/config.h"
-#include "RemoteTarget.h"
-#include "RemoteTargetExternal.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/DataTypes.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/Memory.h"
-#include "llvm/Support/Program.h"
-#include "llvm/Support/raw_ostream.h"
-#include <string>
-
-using namespace llvm;
-
-#define DEBUG_TYPE "lli"
-
-bool RemoteTargetExternal::allocateSpace(size_t Size, unsigned Alignment,
-                                 uint64_t &Address) {
-  DEBUG(dbgs() << "Message [allocate space] size: " << Size <<
-                  ", align: " << Alignment << "\n");
-  if (!SendAllocateSpace(Alignment, Size)) {
-    ErrorMsg += ", (RemoteTargetExternal::allocateSpace)";
-    return false;
-  }
-  if (!Receive(LLI_AllocationResult, Address)) {
-    ErrorMsg += ", (RemoteTargetExternal::allocateSpace)";
-    return false;
-  }
-  if (Address == 0) {
-    ErrorMsg += "failed allocation, (RemoteTargetExternal::allocateSpace)";
-    return false;
-  }
-  DEBUG(dbgs() << "Message [allocate space] addr: 0x" <<
-                  format("%llx", Address) << "\n");
-  return true;
-}
-
-bool RemoteTargetExternal::loadData(uint64_t Address, const void *Data, size_t Size) {
-  DEBUG(dbgs() << "Message [load data] addr: 0x" << format("%llx", Address) <<
-                  ", size: " << Size << "\n");
-  if (!SendLoadSection(Address, Data, (uint32_t)Size, false)) {
-    ErrorMsg += ", (RemoteTargetExternal::loadData)";
-    return false;
-  }
-  int Status = LLI_Status_Success;
-  if (!Receive(LLI_LoadResult, Status)) {
-    ErrorMsg += ", (RemoteTargetExternal::loadData)";
-    return false;
-  }
-  if (Status == LLI_Status_IncompleteMsg) {
-    ErrorMsg += "incomplete load data, (RemoteTargetExternal::loadData)";
-    return false;
-  }
-  if (Status == LLI_Status_NotAllocated) {
-    ErrorMsg += "data memory not allocated, (RemoteTargetExternal::loadData)";
-    return false;
-  }
-  DEBUG(dbgs() << "Message [load data] complete\n");
-  return true;
-}
-
-bool RemoteTargetExternal::loadCode(uint64_t Address, const void *Data, size_t Size) {
-  DEBUG(dbgs() << "Message [load code] addr: 0x" << format("%llx", Address) <<
-                  ", size: " << Size << "\n");
-  if (!SendLoadSection(Address, Data, (uint32_t)Size, true)) {
-    ErrorMsg += ", (RemoteTargetExternal::loadCode)";
-    return false;
-  }
-  int Status = LLI_Status_Success;
-  if (!Receive(LLI_LoadResult, Status)) {
-    ErrorMsg += ", (RemoteTargetExternal::loadCode)";
-    return false;
-  }
-  if (Status == LLI_Status_IncompleteMsg) {
-    ErrorMsg += "incomplete load data, (RemoteTargetExternal::loadData)";
-    return false;
-  }
-  if (Status == LLI_Status_NotAllocated) {
-    ErrorMsg += "data memory not allocated, (RemoteTargetExternal::loadData)";
-    return false;
-  }
-  DEBUG(dbgs() << "Message [load code] complete\n");
-  return true;
-}
-
-bool RemoteTargetExternal::executeCode(uint64_t Address, int32_t &RetVal) {
-  DEBUG(dbgs() << "Message [exectue code] addr: " << Address << "\n");
-  if (!SendExecute(Address)) {
-    ErrorMsg += ", (RemoteTargetExternal::executeCode)";
-    return false;
-  }
-  if (!Receive(LLI_ExecutionResult, RetVal)) {
-    ErrorMsg += ", (RemoteTargetExternal::executeCode)";
-    return false;
-  }
-  DEBUG(dbgs() << "Message [exectue code] return: " << RetVal << "\n");
-  return true;
-}
-
-void RemoteTargetExternal::stop() {
-  SendTerminate();
-  RPC.Wait();
-}
-
-bool RemoteTargetExternal::SendAllocateSpace(uint32_t Alignment, uint32_t Size) {
-  if (!SendHeader(LLI_AllocateSpace)) {
-    ErrorMsg += ", (RemoteTargetExternal::SendAllocateSpace)";
-    return false;
-  }
-
-  AppendWrite((const void *)&Alignment, 4);
-  AppendWrite((const void *)&Size, 4);
-
-  if (!SendPayload()) {
-    ErrorMsg += ", (RemoteTargetExternal::SendAllocateSpace)";
-    return false;
-  }
-  return true;
-}
-
-bool RemoteTargetExternal::SendLoadSection(uint64_t Addr,
-                                       const void *Data,
-                                       uint32_t Size,
-                                       bool IsCode) {
-  LLIMessageType MsgType = IsCode ? LLI_LoadCodeSection : LLI_LoadDataSection;
-  if (!SendHeader(MsgType)) {
-    ErrorMsg += ", (RemoteTargetExternal::SendLoadSection)";
-    return false;
-  }
-
-  AppendWrite((const void *)&Addr, 8);
-  AppendWrite(Data, Size);
-
-  if (!SendPayload()) {
-    ErrorMsg += ", (RemoteTargetExternal::SendLoadSection)";
-    return false;
-  }
-  return true;
-}
-
-bool RemoteTargetExternal::SendExecute(uint64_t Addr) {
-  if (!SendHeader(LLI_Execute)) {
-    ErrorMsg += ", (RemoteTargetExternal::SendExecute)";
-    return false;
-  }
-
-  AppendWrite((const void *)&Addr, 8);
-
-  if (!SendPayload()) {
-    ErrorMsg += ", (RemoteTargetExternal::SendExecute)";
-    return false;
-  }
-  return true;
-}
-
-bool RemoteTargetExternal::SendTerminate() {
-  return SendHeader(LLI_Terminate);
-  // No data or data size is sent with Terminate
-}
-
-bool RemoteTargetExternal::Receive(LLIMessageType Msg) {
-  if (!ReceiveHeader(Msg))
-    return false;
-  int Unused;
-  AppendRead(&Unused, 0);
-  if (!ReceivePayload())
-    return false;
-  ReceiveData.clear();
-  Sizes.clear();
-  return true;
-}
-
-bool RemoteTargetExternal::Receive(LLIMessageType Msg, int32_t &Data) {
-  if (!ReceiveHeader(Msg))
-    return false;
-  AppendRead(&Data, 4);
-  if (!ReceivePayload())
-    return false;
-  ReceiveData.clear();
-  Sizes.clear();
-  return true;
-}
-
-bool RemoteTargetExternal::Receive(LLIMessageType Msg, uint64_t &Data) {
-  if (!ReceiveHeader(Msg))
-    return false;
-  AppendRead(&Data, 8);
-  if (!ReceivePayload())
-    return false;
-  ReceiveData.clear();
-  Sizes.clear();
-  return true;
-}
-
-bool RemoteTargetExternal::ReceiveHeader(LLIMessageType ExpectedMsgType) {
-  assert(ReceiveData.empty() && Sizes.empty() &&
-         "Payload vector not empty to receive header");
-
-  // Message header, with type to follow
-  uint32_t MsgType;
-  if (!ReadBytes(&MsgType, 4)) {
-    ErrorMsg += ", (RemoteTargetExternal::ReceiveHeader)";
-    return false;
-  }
-  if (MsgType != (uint32_t)ExpectedMsgType) {
-    ErrorMsg = "received unexpected message type";
-    ErrorMsg += ". Expecting: ";
-    ErrorMsg += ExpectedMsgType;
-    ErrorMsg += ", Got: ";
-    ErrorMsg += MsgType;
-    return false;
-  }
-  return true;
-}
-
-bool RemoteTargetExternal::ReceivePayload() {
-  assert(!ReceiveData.empty() &&
-         "Payload vector empty to receive");
-  assert(ReceiveData.size() == Sizes.size() &&
-         "Unexpected mismatch between data and size");
-
-  uint32_t TotalSize = 0;
-  for (int I=0, E=Sizes.size(); I < E; I++)
-    TotalSize += Sizes[I];
-
-  // Payload size header
-  uint32_t DataSize;
-  if (!ReadBytes(&DataSize, 4)) {
-    ErrorMsg += ", invalid data size";
-    return false;
-  }
-  if (DataSize != TotalSize) {
-    ErrorMsg = "unexpected data size";
-    ErrorMsg += ". Expecting: ";
-    ErrorMsg += TotalSize;
-    ErrorMsg += ", Got: ";
-    ErrorMsg += DataSize;
-    return false;
-  }
-  if (DataSize == 0)
-    return true;
-
-  // Payload itself
-  for (int I=0, E=Sizes.size(); I < E; I++) {
-    if (!ReadBytes(ReceiveData[I], Sizes[I])) {
-      ErrorMsg = "unexpected data while reading message";
-      return false;
-    }
-  }
-
-  return true;
-}
-
-bool RemoteTargetExternal::SendHeader(LLIMessageType MsgType) {
-  assert(SendData.empty() && Sizes.empty() &&
-         "Payload vector not empty to send header");
-
-  // Message header, with type to follow
-  if (!WriteBytes(&MsgType, 4)) {
-    ErrorMsg += ", (RemoteTargetExternal::SendHeader)";
-    return false;
-  }
-  return true;
-}
-
-bool RemoteTargetExternal::SendPayload() {
-  assert(!SendData.empty() && !Sizes.empty() &&
-         "Payload vector empty to send");
-  assert(SendData.size() == Sizes.size() &&
-         "Unexpected mismatch between data and size");
-
-  uint32_t TotalSize = 0;
-  for (int I=0, E=Sizes.size(); I < E; I++)
-    TotalSize += Sizes[I];
-
-  // Payload size header
-  if (!WriteBytes(&TotalSize, 4)) {
-    ErrorMsg += ", invalid data size";
-    return false;
-  }
-  if (TotalSize == 0)
-    return true;
-
-  // Payload itself
-  for (int I=0, E=Sizes.size(); I < E; I++) {
-    if (!WriteBytes(SendData[I], Sizes[I])) {
-      ErrorMsg = "unexpected data while writing message";
-      return false;
-    }
-  }
-
-  SendData.clear();
-  Sizes.clear();
-  return true;
-}
-
-void RemoteTargetExternal::AppendWrite(const void *Data, uint32_t Size) {
-  SendData.push_back(Data);
-  Sizes.push_back(Size);
-}
-
-void RemoteTargetExternal::AppendRead(void *Data, uint32_t Size) {
-  ReceiveData.push_back(Data);
-  Sizes.push_back(Size);
-}
-
-#ifdef LLVM_ON_UNIX
-#include "Unix/RPCChannel.inc"
-#endif
-
-#ifdef LLVM_ON_WIN32
-#include "Windows/RPCChannel.inc"
-#endif
diff --git a/tools/lli/RemoteTargetExternal.h b/tools/lli/RemoteTargetExternal.h
deleted file mode 100644 (file)
index afe8570..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-//===----- RemoteTargetExternal.h - LLVM out-of-process JIT execution -----===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Definition of the RemoteTargetExternal class which executes JITed code in a
-// separate process from where it was built.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLI_REMOTETARGETEXTERNAL_H
-#define LLVM_TOOLS_LLI_REMOTETARGETEXTERNAL_H
-
-#include "RPCChannel.h"
-#include "RemoteTarget.h"
-#include "RemoteTargetMessage.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Config/config.h"
-#include "llvm/Support/DataTypes.h"
-#include "llvm/Support/Memory.h"
-#include <stdlib.h>
-#include <string>
-
-namespace llvm {
-
-class RemoteTargetExternal : public RemoteTarget {
-  RPCChannel RPC;
-
-  bool WriteBytes(const void *Data, size_t Size) {
-    return RPC.WriteBytes(Data, Size);
-  }
-
-  bool ReadBytes(void *Data, size_t Size) { return RPC.ReadBytes(Data, Size); }
-
-public:
-  /// Allocate space in the remote target address space.
-  ///
-  /// @param      Size      Amount of space, in bytes, to allocate.
-  /// @param      Alignment Required minimum alignment for allocated space.
-  /// @param[out] Address   Remote address of the allocated memory.
-  ///
-  /// @returns True on success. On failure, ErrorMsg is updated with
-  ///          descriptive text of the encountered error.
-  bool allocateSpace(size_t Size, unsigned Alignment,
-                     uint64_t &Address) override;
-
-  /// Load data into the target address space.
-  ///
-  /// @param      Address   Destination address in the target process.
-  /// @param      Data      Source address in the host process.
-  /// @param      Size      Number of bytes to copy.
-  ///
-  /// @returns True on success. On failure, ErrorMsg is updated with
-  ///          descriptive text of the encountered error.
-  bool loadData(uint64_t Address, const void *Data, size_t Size) override;
-
-  /// Load code into the target address space and prepare it for execution.
-  ///
-  /// @param      Address   Destination address in the target process.
-  /// @param      Data      Source address in the host process.
-  /// @param      Size      Number of bytes to copy.
-  ///
-  /// @returns True on success. On failure, ErrorMsg is updated with
-  ///          descriptive text of the encountered error.
-  bool loadCode(uint64_t Address, const void *Data, size_t Size) override;
-
-  /// Execute code in the target process. The called function is required
-  /// to be of signature int "(*)(void)".
-  ///
-  /// @param      Address   Address of the loaded function in the target
-  ///                       process.
-  /// @param[out] RetVal    The integer return value of the called function.
-  ///
-  /// @returns True on success. On failure, ErrorMsg is updated with
-  ///          descriptive text of the encountered error.
-  bool executeCode(uint64_t Address, int &RetVal) override;
-
-  /// Minimum alignment for memory permissions. Used to separate code and
-  /// data regions to make sure data doesn't get marked as code or vice
-  /// versa.
-  ///
-  /// @returns Page alignment return value. Default of 4k.
-  unsigned getPageAlignment() override { return 4096; }
-
-  bool create() override {
-    RPC.ChildName = ChildName;
-    if (!RPC.createServer())
-      return true;
-
-    // We must get Ack from the client (blocking read)
-    if (!Receive(LLI_ChildActive)) {
-      ErrorMsg += ", (RPCChannel::create) - Stopping process!";
-      stop();
-      return false;
-    }
-
-    return true;
-  }
-
-  /// Terminate the remote process.
-  void stop() override;
-
-  RemoteTargetExternal(std::string &Name) : RemoteTarget(), ChildName(Name) {}
-  ~RemoteTargetExternal() override {}
-
-private:
-  std::string ChildName;
-
-  bool SendAllocateSpace(uint32_t Alignment, uint32_t Size);
-  bool SendLoadSection(uint64_t Addr,
-                       const void *Data,
-                       uint32_t Size,
-                       bool IsCode);
-  bool SendExecute(uint64_t Addr);
-  bool SendTerminate();
-
-  // High-level wrappers for receiving data
-  bool Receive(LLIMessageType Msg);
-  bool Receive(LLIMessageType Msg, int32_t &Data);
-  bool Receive(LLIMessageType Msg, uint64_t &Data);
-
-  // Lower level target-independent read/write to deal with errors
-  bool ReceiveHeader(LLIMessageType Msg);
-  bool ReceivePayload();
-  bool SendHeader(LLIMessageType Msg);
-  bool SendPayload();
-
-  // Functions to append/retrieve data from the payload
-  SmallVector<const void *, 2> SendData;
-  SmallVector<void *, 1> ReceiveData; // Future proof
-  SmallVector<int, 2> Sizes;
-  void AppendWrite(const void *Data, uint32_t Size);
-  void AppendRead(void *Data, uint32_t Size);
-};
-
-} // end namespace llvm
-
-#endif
diff --git a/tools/lli/RemoteTargetMessage.h b/tools/lli/RemoteTargetMessage.h
deleted file mode 100644 (file)
index c210e4b..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-//===---- RemoteTargetMessage.h - LLI out-of-process message protocol -----===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Definition of the LLIMessageType enum which is used for communication with a
-// child process for remote execution.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLI_REMOTETARGETMESSAGE_H
-#define LLVM_TOOLS_LLI_REMOTETARGETMESSAGE_H
-
-namespace llvm {
-
-// LLI messages from parent-to-child or vice versa follow an exceedingly simple
-// protocol where the first four bytes represent the message type, the next
-// four bytes represent the size of data for the command and following bytes
-// represent the actual data.
-//
-// The protocol is not intended to be robust, secure or fault-tolerant.  It is
-// only here for testing purposes and is therefore intended to be the simplest
-// implementation that will work.  It is assumed that the parent and child
-// share characteristics like endianness.
-//
-// Quick description of the protocol:
-//
-// { Header + Payload Size + Payload }
-//
-// The protocol message consist of a header, the payload size (which can be
-// zero), and the payload itself. The payload can contain any number of items,
-// and the size has to be the sum of them all. Each end is responsible for
-// reading/writing the correct number of items with the correct sizes.
-//
-// The current four known exchanges are:
-//
-//  * Allocate Space:
-//   Parent: { LLI_AllocateSpace, 8, Alignment, Size }
-//    Child: { LLI_AllocationResult, 8, Address }
-//
-//  * Load Data:
-//   Parent: { LLI_LoadDataSection, 8+Size, Address, Data }
-//    Child: { LLI_LoadComplete, 4, StatusCode }
-//
-//  * Load Code:
-//   Parent: { LLI_LoadCodeSection, 8+Size, Address, Code }
-//    Child: { LLI_LoadComplete, 4, StatusCode }
-//
-//  * Execute Code:
-//   Parent: { LLI_Execute, 8, Address }
-//    Child: { LLI_ExecutionResult, 4, Result }
-//
-// It is the responsibility of either side to check for correct headers,
-// sizes and payloads, since any inconsistency would misalign the pipe, and
-// result in data corruption.
-
-enum LLIMessageType {
-  LLI_Error = -1,
-  LLI_ChildActive = 0,        // Data = not used
-  LLI_AllocateSpace,          // Data = struct { uint32_t Align, uint_32t Size }
-  LLI_AllocationResult,       // Data = uint64_t Address (child memory space)
-
-  LLI_LoadCodeSection,        // Data = uint64_t Address, void * SectionData
-  LLI_LoadDataSection,        // Data = uint64_t Address, void * SectionData
-  LLI_LoadResult,             // Data = uint32_t LLIMessageStatus
-
-  LLI_Execute,                // Data = uint64_t Address
-  LLI_ExecutionResult,        // Data = uint32_t Result
-
-  LLI_Terminate               // Data = not used
-};
-
-enum LLIMessageStatus {
-  LLI_Status_Success = 0,     // Operation succeeded
-  LLI_Status_NotAllocated,    // Address+Size not allocated in child space
-  LLI_Status_IncompleteMsg    // Size received doesn't match request
-};
-
-} // end namespace llvm
-
-#endif
diff --git a/tools/lli/Unix/RPCChannel.inc b/tools/lli/Unix/RPCChannel.inc
deleted file mode 100644 (file)
index 6a9ae14..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-//=- RPCChannel.inc - LLVM out-of-process JIT execution for Unix --=//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Implementation of the Unix-specific parts of the RPCChannel class
-// which executes JITed code in a separate process from where it was built.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Support/Errno.h"
-#include "llvm/Support/raw_ostream.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-namespace {
-
-struct ConnectionData_t {
-  int InputPipe;
-  int OutputPipe;
-
-  ConnectionData_t(int in, int out) : InputPipe(in), OutputPipe(out) {}
-};
-
-} // namespace
-
-namespace llvm {
-
-bool RPCChannel::createServer() {
-  int PipeFD[2][2];
-  pid_t ChildPID;
-
-  // Create two pipes.
-  if (pipe(PipeFD[0]) != 0 || pipe(PipeFD[1]) != 0)
-    perror("Error creating pipe: ");
-
-  ChildPID = fork();
-
-  if (ChildPID == 0) {
-    // In the child...
-
-    // Close the parent ends of the pipes
-    close(PipeFD[0][1]);
-    close(PipeFD[1][0]);
-
-    // Use our pipes as stdin and stdout
-    if (PipeFD[0][0] != STDIN_FILENO) {
-      dup2(PipeFD[0][0], STDIN_FILENO);
-      close(PipeFD[0][0]);
-    }
-    if (PipeFD[1][1] != STDOUT_FILENO) {
-      dup2(PipeFD[1][1], STDOUT_FILENO);
-      close(PipeFD[1][1]);
-    }
-
-    // Execute the child process.
-    char *args[1] = { nullptr };
-    int rc = execv(ChildName.c_str(), args);
-    if (rc != 0)
-      perror("Error executing child process: ");
-  } else {
-    // In the parent...
-
-    // Close the child ends of the pipes
-    close(PipeFD[0][0]);
-    close(PipeFD[1][1]);
-
-    // Store the parent ends of the pipes
-    ConnectionData = (void *)new ConnectionData_t(PipeFD[1][0], PipeFD[0][1]);
-    return true;
-  }
-  return false;
-}
-
-bool RPCChannel::createClient() {
-  // Store the parent ends of the pipes
-  ConnectionData = (void *)new ConnectionData_t(STDIN_FILENO, STDOUT_FILENO);
-  return true;
-}
-
-void RPCChannel::Wait() { wait(nullptr); }
-
-static bool CheckError(int rc, size_t Size, const char *Desc) {
-  if (rc < 0) {
-    llvm::errs() << "IO Error: " << Desc << ": " << sys::StrError() << '\n';
-    return false;
-  } else if ((size_t)rc != Size) {
-    std::string ErrorMsg;
-    char Number[10] = { 0 };
-    ErrorMsg += "Expecting ";
-    sprintf(Number, "%d", (uint32_t)Size);
-    ErrorMsg += Number;
-    ErrorMsg += " bytes, Got ";
-    sprintf(Number, "%d", rc);
-    ErrorMsg += Number;
-    llvm::errs() << "RPC Error: " << Desc << ": " << ErrorMsg << '\n';
-    return false;
-  }
-  return true;
-}
-
-bool RPCChannel::WriteBytes(const void *Data, size_t Size) {
-  int rc = write(((ConnectionData_t *)ConnectionData)->OutputPipe, Data, Size);
-  return CheckError(rc, Size, "WriteBytes");
-}
-
-bool RPCChannel::ReadBytes(void *Data, size_t Size) {
-  int rc = read(((ConnectionData_t *)ConnectionData)->InputPipe, Data, Size);
-  return CheckError(rc, Size, "ReadBytes");
-}
-
-RPCChannel::~RPCChannel() {
-  delete static_cast<ConnectionData_t *>(ConnectionData);
-}
-
-} // namespace llvm
diff --git a/tools/lli/Windows/RPCChannel.inc b/tools/lli/Windows/RPCChannel.inc
deleted file mode 100644 (file)
index 82f2acb..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-//=- RPCChannel.inc - LLVM out-of-process JIT execution for Windows --=//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Implementation of the Windows-specific parts of the RPCChannel class
-// which executes JITed code in a separate process from where it was built.
-//
-//===----------------------------------------------------------------------===//
-
-namespace llvm {
-
-bool RPCChannel::createServer() { return false; }
-
-bool RPCChannel::createClient() { return false; }
-
-bool RPCChannel::WriteBytes(const void *Data, size_t Size) { return false; }
-
-bool RPCChannel::ReadBytes(void *Data, size_t Size) { return false; }
-
-void RPCChannel::Wait() {}
-
-RPCChannel::~RPCChannel() {}
-
-} // namespace llvm
index 9f71406..b83a1a8 100644 (file)
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/IR/LLVMContext.h"
 #include "OrcLazyJIT.h"
-#include "RemoteMemoryManager.h"
-#include "RemoteTarget.h"
-#include "RemoteTargetExternal.h"
+#include "RemoteJITUtils.h"
+#include "llvm/IR/LLVMContext.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/Bitcode/ReaderWriter.h"
 #include "llvm/CodeGen/LinkAllCodegenComponents.h"
@@ -28,6 +26,7 @@
 #include "llvm/ExecutionEngine/ObjectCache.h"
 #include "llvm/ExecutionEngine/OrcMCJITReplacement.h"
 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
+#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/Module.h"
 #include "llvm/IR/Type.h"
@@ -449,7 +448,7 @@ int main(int argc, char **argv, char * const *envp) {
   RTDyldMemoryManager *RTDyldMM = nullptr;
   if (!ForceInterpreter) {
     if (RemoteMCJIT)
-      RTDyldMM = new RemoteMemoryManager();
+      RTDyldMM = new ForwardingMemoryManager();
     else
       RTDyldMM = new SectionMemoryManager();
 
@@ -582,6 +581,27 @@ int main(int argc, char **argv, char * const *envp) {
 
   int Result;
 
+  // Sanity check use of remote-jit: LLI currently only supports use of the
+  // remote JIT on Unix platforms.
+  // FIXME: Remove this pointless fallback mode which causes tests to "pass"
+  // on platforms where they should XFAIL.
+  if (RemoteMCJIT) {
+#ifndef LLVM_ON_UNIX
+    errs() << "Warning: host does not support external remote targets.\n"
+           << "  Defaulting to local execution execution\n";
+    RemoteMCJIT = false;
+#else
+    if (ChildExecPath.empty()) {
+      errs() << "-remote-mcjit requires -mcjit-remote-process.\n";
+      exit(1);
+    } else if (!sys::fs::can_execute(ChildExecPath)) {
+      errs() << "Unable to find usable child executable: '" << ChildExecPath
+             << "'\n";
+      return -1;
+    }
+#endif
+  }
+
   if (!RemoteMCJIT) {
     // If the program doesn't explicitly call exit, we will need the Exit
     // function later on to make an explicit call, so get the function now.
@@ -629,66 +649,123 @@ int main(int argc, char **argv, char * const *envp) {
     // Remote target MCJIT doesn't (yet) support static constructors. No reason
     // it couldn't. This is a limitation of the LLI implemantation, not the
     // MCJIT itself. FIXME.
-    //
-    RemoteMemoryManager *MM = static_cast<RemoteMemoryManager*>(RTDyldMM);
-    // Everything is prepared now, so lay out our program for the target
-    // address space, assign the section addresses to resolve any relocations,
-    // and send it to the target.
-
-    std::unique_ptr<RemoteTarget> Target;
-    if (!ChildExecPath.empty()) { // Remote execution on a child process
-#ifndef LLVM_ON_UNIX
-      // FIXME: Remove this pointless fallback mode which causes tests to "pass"
-      // on platforms where they should XFAIL.
-      errs() << "Warning: host does not support external remote targets.\n"
-             << "  Defaulting to simulated remote execution\n";
-      Target.reset(new RemoteTarget);
-#else
-      if (!sys::fs::can_execute(ChildExecPath)) {
-        errs() << "Unable to find usable child executable: '" << ChildExecPath
-               << "'\n";
-        return -1;
-      }
-      Target.reset(new RemoteTargetExternal(ChildExecPath));
-#endif
-    } else {
-      // No child process name provided, use simulated remote execution.
-      Target.reset(new RemoteTarget);
+
+    // Lanch the remote process and get a channel to it.
+    std::unique_ptr<FDRPCChannel> C = launchRemote();
+    if (!C) {
+      errs() << "Failed to launch remote JIT.\n";
+      exit(1);
     }
 
-    // Give the memory manager a pointer to our remote target interface object.
-    MM->setRemoteTarget(Target.get());
+    // Create a remote target client running over the channel.
+    typedef orc::remote::OrcRemoteTargetClient<orc::remote::RPCChannel> MyRemote;
+    ErrorOr<MyRemote> R = MyRemote::Create(*C);
+    if (!R) {
+      errs() << "Could not create remote: " << R.getError().message() << "\n";
+      exit(1);
+    }
 
-    // Create the remote target.
-    if (!Target->create()) {
-      errs() << "ERROR: " << Target->getErrorMsg() << "\n";
-      return EXIT_FAILURE;
+    // Create a remote memory manager.
+    std::unique_ptr<MyRemote::RCMemoryManager> RemoteMM;
+    if (auto EC = R->createRemoteMemoryManager(RemoteMM)) {
+      errs() << "Could not create remote memory manager: " << EC.message() << "\n";
+      exit(1);
     }
 
-    // Since we're executing in a (at least simulated) remote address space,
-    // we can't use the ExecutionEngine::runFunctionAsMain(). We have to
-    // grab the function address directly here and tell the remote target
-    // to execute the function.
-    //
-    // Our memory manager will map generated code into the remote address
-    // space as it is loaded and copy the bits over during the finalizeMemory
-    // operation.
-    //
+    // Forward MCJIT's memory manager calls to the remote memory manager.
+    static_cast<ForwardingMemoryManager*>(RTDyldMM)->setMemMgr(
+      std::move(RemoteMM));
+
+    // Forward MCJIT's symbol resolution calls to the remote.
+    static_cast<ForwardingMemoryManager*>(RTDyldMM)->setResolver(
+      orc::createLambdaResolver(
+        [&](const std::string &Name) {
+          orc::TargetAddress Addr = 0;
+          if (auto EC = R->getSymbolAddress(Addr, Name)) {
+            errs() << "Failure during symbol lookup: " << EC.message() << "\n";
+            exit(1);
+          }
+          return RuntimeDyld::SymbolInfo(Addr, JITSymbolFlags::Exported);
+        },
+        [](const std::string &Name) { return nullptr; }
+      ));
+
+    // Grab the target address of the JIT'd main function on the remote and call
+    // it.
     // FIXME: argv and envp handling.
-    uint64_t Entry = EE->getFunctionAddress(EntryFn->getName().str());
-
+    orc::TargetAddress Entry = EE->getFunctionAddress(EntryFn->getName().str());
+    EE->finalizeObject();
     DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at 0x"
                  << format("%llx", Entry) << "\n");
-
-    if (!Target->executeCode(Entry, Result))
-      errs() << "ERROR: " << Target->getErrorMsg() << "\n";
+    if (auto EC = R->callIntVoid(Result, Entry))
+      errs() << "ERROR: " << EC.message() << "\n";
 
     // Like static constructors, the remote target MCJIT support doesn't handle
     // this yet. It could. FIXME.
 
-    // Stop the remote target
-    Target->stop();
+    // Delete the EE - we need to tear it down *before* we terminate the session
+    // with the remote, otherwise it'll crash when it tries to release resources
+    // on a remote that has already been disconnected.
+    delete EE;
+    EE = nullptr;
+
+    // Signal the remote target that we're done JITing.
+    R->terminateSession();
   }
 
   return Result;
 }
+
+std::unique_ptr<FDRPCChannel> launchRemote() {
+#ifndef LLVM_ON_UNIX
+  llvm_unreachable("launchRemote not supported on non-Unix platforms");
+#else
+  int PipeFD[2][2];
+  pid_t ChildPID;
+
+  // Create two pipes.
+  if (pipe(PipeFD[0]) != 0 || pipe(PipeFD[1]) != 0)
+    perror("Error creating pipe: ");
+
+  ChildPID = fork();
+
+  if (ChildPID == 0) {
+    // In the child...
+
+    // Close the parent ends of the pipes
+    close(PipeFD[0][1]);
+    close(PipeFD[1][0]);
+
+
+    // Execute the child process.
+    std::unique_ptr<char[]> ChildPath, ChildIn, ChildOut;
+    {
+      ChildPath.reset(new char[ChildExecPath.size() + 1]);
+      std::copy(ChildExecPath.begin(), ChildExecPath.end(), &ChildPath[0]);
+      ChildPath[ChildExecPath.size()] = '\0';
+      std::string ChildInStr = std::to_string(PipeFD[0][0]);
+      ChildIn.reset(new char[ChildInStr.size() + 1]);
+      std::copy(ChildInStr.begin(), ChildInStr.end(), &ChildIn[0]);
+      ChildIn[ChildInStr.size()] = '\0';
+      std::string ChildOutStr = std::to_string(PipeFD[1][1]);
+      ChildOut.reset(new char[ChildOutStr.size() + 1]);
+      std::copy(ChildOutStr.begin(), ChildOutStr.end(), &ChildOut[0]);
+      ChildOut[ChildOutStr.size()] = '\0';
+    }
+
+    char * const args[] = { &ChildPath[0], &ChildIn[0], &ChildOut[0], nullptr };
+    int rc = execv(ChildExecPath.c_str(), args);
+    if (rc != 0)
+      perror("Error executing child process: ");
+    llvm_unreachable("Error executing child process");
+  }
+  // else we're the parent...
+
+  // Close the child ends of the pipes
+  close(PipeFD[0][0]);
+  close(PipeFD[1][1]);
+
+  // Return an RPC channel connected to our end of the pipes.
+  return llvm::make_unique<FDRPCChannel>(PipeFD[1][0], PipeFD[0][1]);
+#endif
+}