From b20e09ca99580deb207856d00877c115719b2464 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Mon, 11 Jan 2016 16:35:55 +0000 Subject: [PATCH] [LLI] Replace the LLI remote-JIT support with the new ORC remote-JIT components. 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 --- .../Orc/OrcArchitectureSupport.h | 62 +++- lib/ExecutionEngine/Orc/OrcMCJITReplacement.h | 5 + .../MCJIT/remote/stubs-remote.ll | 1 - .../remote/test-global-init-nonzero-sm-pic.ll | 3 +- .../MCJIT/remote/test-ptr-reloc-sm-pic.ll | 3 +- .../OrcMCJIT/remote/stubs-remote.ll | 1 - .../remote/test-global-init-nonzero-sm-pic.ll | 3 +- .../OrcMCJIT/remote/test-ptr-reloc-sm-pic.ll | 3 +- tools/lli/CMakeLists.txt | 3 - tools/lli/ChildTarget/CMakeLists.txt | 6 +- tools/lli/ChildTarget/ChildTarget.cpp | 285 +++------------ tools/lli/RPCChannel.h | 49 --- tools/lli/RemoteJITUtils.h | 131 +++++++ tools/lli/RemoteMemoryManager.cpp | 174 ---------- tools/lli/RemoteMemoryManager.h | 101 ------ tools/lli/RemoteTarget.cpp | 71 ---- tools/lli/RemoteTarget.h | 122 ------- tools/lli/RemoteTargetExternal.cpp | 327 ------------------ tools/lli/RemoteTargetExternal.h | 143 -------- tools/lli/RemoteTargetMessage.h | 85 ----- tools/lli/Unix/RPCChannel.inc | 122 ------- tools/lli/Windows/RPCChannel.inc | 29 -- tools/lli/lli.cpp | 181 +++++++--- 23 files changed, 386 insertions(+), 1524 deletions(-) delete mode 100644 tools/lli/RPCChannel.h create mode 100644 tools/lli/RemoteJITUtils.h delete mode 100644 tools/lli/RemoteMemoryManager.cpp delete mode 100644 tools/lli/RemoteMemoryManager.h delete mode 100644 tools/lli/RemoteTarget.cpp delete mode 100644 tools/lli/RemoteTarget.h delete mode 100644 tools/lli/RemoteTargetExternal.cpp delete mode 100644 tools/lli/RemoteTargetExternal.h delete mode 100644 tools/lli/RemoteTargetMessage.h delete mode 100644 tools/lli/Unix/RPCChannel.inc delete mode 100644 tools/lli/Windows/RPCChannel.inc diff --git a/include/llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h b/include/llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h index cd934216c93..1b0488bcf00 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h +++ b/include/llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h @@ -25,14 +25,58 @@ 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; } - IndirectStubsInfo& operator=(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. - void* getStub(unsigned Idx) const { - return static_cast(StubsMem.base()) + Idx; + void *getStub(unsigned Idx) const { + return static_cast(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(StubsMem.base()) + NumStubs * StubSize; - return reinterpret_cast(PtrsBase) + Idx; + static_cast(StubsMem.base()) + NumStubs * StubSize; + return reinterpret_cast(PtrsBase) + Idx; } + private: unsigned NumStubs; sys::OwningMemoryBlock StubsMem; diff --git a/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h b/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h index 61d8ec99451..2ab70a9fee8 100644 --- a/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h +++ b/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h @@ -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); diff --git a/test/ExecutionEngine/MCJIT/remote/stubs-remote.ll b/test/ExecutionEngine/MCJIT/remote/stubs-remote.ll index a834ac5c985..0c4df7bcb15 100644 --- a/test/ExecutionEngine/MCJIT/remote/stubs-remote.ll +++ b/test/ExecutionEngine/MCJIT/remote/stubs-remote.ll @@ -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 { diff --git a/test/ExecutionEngine/MCJIT/remote/test-global-init-nonzero-sm-pic.ll b/test/ExecutionEngine/MCJIT/remote/test-global-init-nonzero-sm-pic.ll index e350b85a8bc..619c827cd82 100644 --- a/test/ExecutionEngine/MCJIT/remote/test-global-init-nonzero-sm-pic.ll +++ b/test/ExecutionEngine/MCJIT/remote/test-global-init-nonzero-sm-pic.ll @@ -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 diff --git a/test/ExecutionEngine/MCJIT/remote/test-ptr-reloc-sm-pic.ll b/test/ExecutionEngine/MCJIT/remote/test-ptr-reloc-sm-pic.ll index 7162e927de0..31d87708f37 100644 --- a/test/ExecutionEngine/MCJIT/remote/test-ptr-reloc-sm-pic.ll +++ b/test/ExecutionEngine/MCJIT/remote/test-ptr-reloc-sm-pic.ll @@ -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 diff --git a/test/ExecutionEngine/OrcMCJIT/remote/stubs-remote.ll b/test/ExecutionEngine/OrcMCJIT/remote/stubs-remote.ll index aeff011d5ed..523011ccdf1 100644 --- a/test/ExecutionEngine/OrcMCJIT/remote/stubs-remote.ll +++ b/test/ExecutionEngine/OrcMCJIT/remote/stubs-remote.ll @@ -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 { diff --git a/test/ExecutionEngine/OrcMCJIT/remote/test-global-init-nonzero-sm-pic.ll b/test/ExecutionEngine/OrcMCJIT/remote/test-global-init-nonzero-sm-pic.ll index f1e93133b22..fc15fba91a0 100644 --- a/test/ExecutionEngine/OrcMCJIT/remote/test-global-init-nonzero-sm-pic.ll +++ b/test/ExecutionEngine/OrcMCJIT/remote/test-global-init-nonzero-sm-pic.ll @@ -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 diff --git a/test/ExecutionEngine/OrcMCJIT/remote/test-ptr-reloc-sm-pic.ll b/test/ExecutionEngine/OrcMCJIT/remote/test-ptr-reloc-sm-pic.ll index cac800ef5e7..915dfa6507c 100644 --- a/test/ExecutionEngine/OrcMCJIT/remote/test-ptr-reloc-sm-pic.ll +++ b/test/ExecutionEngine/OrcMCJIT/remote/test-ptr-reloc-sm-pic.ll @@ -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 diff --git a/tools/lli/CMakeLists.txt b/tools/lli/CMakeLists.txt index 4af05969af1..e317db6b713 100644 --- a/tools/lli/CMakeLists.txt +++ b/tools/lli/CMakeLists.txt @@ -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) diff --git a/tools/lli/ChildTarget/CMakeLists.txt b/tools/lli/ChildTarget/CMakeLists.txt index 9f88b2cde3f..abc1722b076 100644 --- a/tools/lli/ChildTarget/CMakeLists.txt +++ b/tools/lli/ChildTarget/CMakeLists.txt @@ -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") diff --git a/tools/lli/ChildTarget/ChildTarget.cpp b/tools/lli/ChildTarget/ChildTarget.cpp index 6c537d47df3..0b75e20f83e 100644 --- a/tools/lli/ChildTarget/ChildTarget.cpp +++ b/tools/lli/ChildTarget/ChildTarget.cpp @@ -1,244 +1,69 @@ -#include "llvm/Config/config.h" -#include "../RPCChannel.h" -#include "../RemoteTarget.h" -#include "../RemoteTargetMessage.h" -#include "llvm/Support/Memory.h" -#include -#include -#include -#include -#include +#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 -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] << " \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 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 index ebd3c65640b..00000000000 --- a/tools/lli/RPCChannel.h +++ /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 -#include - -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 index 00000000000..792d8d0dedf --- /dev/null +++ b/tools/lli/RemoteJITUtils.h @@ -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 +#else +#include +#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 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 MemMgr) { + this->MemMgr = std::move(MemMgr); + } + + void setResolver(std::unique_ptr 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 MemMgr; + std::unique_ptr Resolver; +}; +} + +#endif diff --git a/tools/lli/RemoteMemoryManager.cpp b/tools/lli/RemoteMemoryManager.cpp deleted file mode 100644 index 0a16210d2ea..00000000000 --- a/tools/lli/RemoteMemoryManager.cpp +++ /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::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, 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(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(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(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::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 index 5733fa53f3e..00000000000 --- a/tools/lli/RemoteMemoryManager.h +++ /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 - -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 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 UnmappedSections; - - // This map tracks the sections we have remapped for the remote target - // but have not yet copied to the target. - DenseMap 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 index 95e1511eaaf..00000000000 --- a/tools/lli/RemoteTarget.cpp +++ /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 -#include - -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(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 index ee758a2747a..00000000000 --- a/tools/lli/RemoteTarget.h +++ /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 -#include - -namespace llvm { - -class RemoteTarget { - bool IsRunning; - - typedef SmallVector 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 index fe46248822c..00000000000 --- a/tools/lli/RemoteTargetExternal.cpp +++ /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 - -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 index afe8570ff49..00000000000 --- a/tools/lli/RemoteTargetExternal.h +++ /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 -#include - -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 SendData; - SmallVector ReceiveData; // Future proof - SmallVector 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 index c210e4b3d6b..00000000000 --- a/tools/lli/RemoteTargetMessage.h +++ /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 index 6a9ae14b599..00000000000 --- a/tools/lli/Unix/RPCChannel.inc +++ /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 -#include -#include -#include - -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); -} - -} // namespace llvm diff --git a/tools/lli/Windows/RPCChannel.inc b/tools/lli/Windows/RPCChannel.inc deleted file mode 100644 index 82f2acbf14a..00000000000 --- a/tools/lli/Windows/RPCChannel.inc +++ /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 diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index 9f714060c17..b83a1a86e0d 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -13,11 +13,9 @@ // //===----------------------------------------------------------------------===// -#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(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 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 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 MyRemote; + ErrorOr 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 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(RTDyldMM)->setMemMgr( + std::move(RemoteMM)); + + // Forward MCJIT's symbol resolution calls to the remote. + static_cast(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 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 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(PipeFD[1][0], PipeFD[0][1]); +#endif +} -- 2.34.1