[llvm] 1d0676b - [ORC] Break up OrcJIT library, add Orc-RPC based remote TargetProcessControl
Arthur Eubanks via llvm-commits
llvm-commits at lists.llvm.org
Fri Nov 13 11:35:01 PST 2020
This causes a warning on Windows:
[326/1881] CXX
obj/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.llvm-jitlink-executor.obj
../../llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp(77,1):
warning: non-void function does not return a value [-Wreturn-type]
}
On Thu, Nov 12, 2020 at 10:06 PM Lang Hames via llvm-commits <
llvm-commits at lists.llvm.org> wrote:
>
> Author: Lang Hames
> Date: 2020-11-13T17:05:13+11:00
> New Revision: 1d0676b54c4e3a517719220def96dfdbc26d8048
>
> URL:
> https://github.com/llvm/llvm-project/commit/1d0676b54c4e3a517719220def96dfdbc26d8048
> DIFF:
> https://github.com/llvm/llvm-project/commit/1d0676b54c4e3a517719220def96dfdbc26d8048.diff
>
> LOG: [ORC] Break up OrcJIT library, add Orc-RPC based remote
> TargetProcessControl
> implementation.
>
> This patch aims to improve support for out-of-process JITing using OrcV2.
> It
> introduces two new class templates, OrcRPCTargetProcessControlBase and
> OrcRPCTPCServer, which together implement the TargetProcessControl API by
> forwarding operations to an execution process via an Orc-RPC Endpoint.
> These
> utilities are used to implement out-of-process JITing from llvm-jitlink to
> a new llvm-jitlink-executor tool.
>
> This patch also breaks the OrcJIT library into three parts:
> -- OrcTargetProcess: Contains code needed by the JIT execution process.
> -- OrcShared: Contains code needed by the JIT execution and compiler
> processes
> -- OrcJIT: Everything else.
>
> This break-up allows JIT executor processes to link against
> OrcTargetProcess
> and OrcShared only, without having to link in all of OrcJIT. Clients
> executing
> JIT'd code in-process should start linking against OrcTargetProcess as
> well as
> OrcJIT.
>
> In the near future these changes will enable:
> -- Removal of the OrcRemoteTargetClient/OrcRemoteTargetServer class
> templates
> which provided similar functionality in OrcV1.
> -- Restoration of Chapter 5 of the Building-A-JIT tutorial series, which
> will
> serve as a simple usage example for these APIs.
> -- Implementation of lazy, cross-target compilation in lli's
> -jit-kind=orc-lazy
> mode.
>
> Added:
> llvm/include/llvm/ExecutionEngine/Orc/OrcRPCTargetProcessControl.h
>
> llvm/include/llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h
> llvm/include/llvm/ExecutionEngine/Orc/TPCEHFrameRegistrar.h
> llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h
> llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h
>
> llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h
> llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
> llvm/lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt
> llvm/lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt.rej
> llvm/lib/ExecutionEngine/Orc/Shared/OrcError.cpp
> llvm/lib/ExecutionEngine/Orc/Shared/RPCError.cpp
> llvm/lib/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.cpp
> llvm/lib/ExecutionEngine/Orc/TPCEHFrameRegistrar.cpp
> llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
> llvm/lib/ExecutionEngine/Orc/TargetProcess/LLVMBuild.txt
> llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp
> llvm/lib/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.cpp
> llvm/tools/llvm-jitlink/llvm-jitlink-executor/CMakeLists.txt
> llvm/tools/llvm-jitlink/llvm-jitlink-executor/LLVMBuild.txt
> llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
>
> Modified:
>
> llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp
> llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h
> llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
> llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h
> llvm/include/llvm/ExecutionEngine/Orc/RPC/FDRawByteChannel.h
> llvm/include/llvm/ExecutionEngine/Orc/RPC/RPCSerialization.h
>
> llvm/include/llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h
> llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h
> llvm/lib/ExecutionEngine/CMakeLists.txt
> llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
> llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
> llvm/lib/ExecutionEngine/JITLink/LLVMBuild.txt
> llvm/lib/ExecutionEngine/LLVMBuild.txt
> llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
> llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
> llvm/lib/ExecutionEngine/Orc/LLVMBuild.txt
> llvm/lib/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.cpp
> llvm/lib/ExecutionEngine/Orc/TPCIndirectionUtils.cpp
> llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp
> llvm/tools/lli/CMakeLists.txt
> llvm/tools/lli/ChildTarget/CMakeLists.txt
> llvm/tools/lli/LLVMBuild.txt
> llvm/tools/lli/lli.cpp
> llvm/tools/llvm-jitlink/CMakeLists.txt
> llvm/tools/llvm-jitlink/LLVMBuild.txt
> llvm/tools/llvm-jitlink/llvm-jitlink.cpp
> llvm/tools/llvm-jitlink/llvm-jitlink.h
> llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
> llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
>
> Removed:
> llvm/lib/ExecutionEngine/OrcError/CMakeLists.txt
> llvm/lib/ExecutionEngine/OrcError/LLVMBuild.txt
> llvm/lib/ExecutionEngine/OrcError/OrcError.cpp
> llvm/lib/ExecutionEngine/OrcError/RPCError.cpp
>
>
>
> ################################################################################
> diff --git
> a/llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp
> b/llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp
> index d2ce26bddd72..4e36631ef97d 100644
> ---
> a/llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp
> +++
> b/llvm/examples/OrcV2Examples/LLJITWithTargetProcessControl/LLJITWithTargetProcessControl.cpp
> @@ -134,7 +134,8 @@ int main(int argc, char *argv[]) {
> ExitOnErr.setBanner(std::string(argv[0]) + ": ");
>
> // (1) Create LLJIT instance.
> - auto TPC = ExitOnErr(SelfTargetProcessControl::Create());
> + auto SSP = std::make_shared<SymbolStringPool>();
> + auto TPC = ExitOnErr(SelfTargetProcessControl::Create(std::move(SSP)));
> auto J =
> ExitOnErr(LLJITBuilder().setTargetProcessControl(*TPC).create());
>
> // (2) Install transform to print modules as they are compiled:
>
> diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h
> b/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h
> index 72394d7c9985..ec78d9db40b6 100644
> --- a/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h
> +++ b/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h
> @@ -21,14 +21,6 @@
> namespace llvm {
> namespace jitlink {
>
> -/// Registers all FDEs in the given eh-frame section with the current
> process.
> -Error registerEHFrameSection(const void *EHFrameSectionAddr,
> - size_t EHFrameSectionSize);
> -
> -/// Deregisters all FDEs in the given eh-frame section with the current
> process.
> -Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
> - size_t EHFrameSectionSize);
> -
> /// Supports registration/deregistration of EH-frames in a target process.
> class EHFrameRegistrar {
> public:
>
> diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
> b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
> index 5e22837fa930..f0b4d9bcd49c 100644
> --- a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
> +++ b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
> @@ -801,6 +801,17 @@ class LinkGraph {
> /// Returns the endianness of content in this graph.
> support::endianness getEndianness() const { return Endianness; }
>
> + /// Allocate a copy of the given String using the LinkGraph's allocator.
> + /// This can be useful when renaming symbols or adding new content to
> the
> + /// graph.
> + StringRef allocateString(Twine Source) {
> + SmallString<256> TmpBuffer;
> + auto SourceStr = Source.toStringRef(TmpBuffer);
> + auto *AllocatedBuffer = Allocator.Allocate<char>(SourceStr.size());
> + llvm::copy(SourceStr, AllocatedBuffer);
> + return StringRef(AllocatedBuffer, SourceStr.size());
> + }
> +
> /// Create a section with the given name, protection flags, and
> alignment.
> Section &createSection(StringRef Name, sys::Memory::ProtectionFlags
> Prot) {
> std::unique_ptr<Section> Sec(new Section(Name, Prot,
> Sections.size()));
>
> diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h
> b/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h
> index 0270f8f7d68d..1dc2af49b78e 100644
> --- a/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h
> +++ b/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h
> @@ -41,17 +41,6 @@ namespace orc {
>
> class ObjectLayer;
>
> -/// Run a main function, returning the result.
> -///
> -/// If the optional ProgramName argument is given then it will be inserted
> -/// before the strings in Args as the first argument to the called
> function.
> -///
> -/// It is legal to have an empty argument list and no program name,
> however
> -/// many main functions will expect a name argument at least, and will
> fail
> -/// if none is provided.
> -int runAsMain(int (*Main)(int, char *[]), ArrayRef<std::string> Args,
> - Optional<StringRef> ProgramName = None);
> -
> /// This iterator provides a convenient way to iterate over the elements
> /// of an llvm.global_ctors/llvm.global_dtors instance.
> ///
>
> diff --git
> a/llvm/include/llvm/ExecutionEngine/Orc/OrcRPCTargetProcessControl.h
> b/llvm/include/llvm/ExecutionEngine/Orc/OrcRPCTargetProcessControl.h
> new file mode 100644
> index 000000000000..f63dcd0f3471
> --- /dev/null
> +++ b/llvm/include/llvm/ExecutionEngine/Orc/OrcRPCTargetProcessControl.h
> @@ -0,0 +1,411 @@
> +//===--- OrcRPCTargetProcessControl.h - Remote target control ---*- C++
> -*-===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// Utilities for interacting with target processes.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_EXECUTIONENGINE_ORC_ORCRPCTARGETPROCESSCONTROL_H
> +#define LLVM_EXECUTIONENGINE_ORC_ORCRPCTARGETPROCESSCONTROL_H
> +
> +#include "llvm/ExecutionEngine/Orc/RPC/RPCUtils.h"
> +#include "llvm/ExecutionEngine/Orc/RPC/RawByteChannel.h"
> +#include "llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h"
> +#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
> +#include "llvm/Support/MSVCErrorWorkarounds.h"
> +
> +namespace llvm {
> +namespace orc {
> +
> +/// JITLinkMemoryManager implementation for a process connected via an
> ORC RPC
> +/// endpoint.
> +template <typename OrcRPCTPCImplT>
> +class OrcRPCTPCJITLinkMemoryManager : public
> jitlink::JITLinkMemoryManager {
> +private:
> + struct HostAlloc {
> + std::unique_ptr<char[]> Mem;
> + uint64_t Size;
> + };
> +
> + struct TargetAlloc {
> + JITTargetAddress Address = 0;
> + uint64_t AllocatedSize = 0;
> + };
> +
> + using HostAllocMap = DenseMap<int, HostAlloc>;
> + using TargetAllocMap = DenseMap<int, TargetAlloc>;
> +
> +public:
> + class OrcRPCAllocation : public Allocation {
> + public:
> + OrcRPCAllocation(OrcRPCTPCJITLinkMemoryManager<OrcRPCTPCImplT>
> &Parent,
> + HostAllocMap HostAllocs, TargetAllocMap TargetAllocs)
> + : Parent(Parent), HostAllocs(std::move(HostAllocs)),
> + TargetAllocs(std::move(TargetAllocs)) {
> + assert(HostAllocs.size() == TargetAllocs.size() &&
> + "HostAllocs size should match TargetAllocs");
> + }
> +
> + ~OrcRPCAllocation() override {
> + assert(TargetAllocs.empty() && "failed to deallocate");
> + }
> +
> + MutableArrayRef<char> getWorkingMemory(ProtectionFlags Seg) override {
> + auto I = HostAllocs.find(Seg);
> + assert(I != HostAllocs.end() && "No host allocation for segment");
> + auto &HA = I->second;
> + return {HA.Mem.get(), HA.Size};
> + }
> +
> + JITTargetAddress getTargetMemory(ProtectionFlags Seg) override {
> + auto I = TargetAllocs.find(Seg);
> + assert(I != TargetAllocs.end() && "No target allocation for
> segment");
> + return I->second.Address;
> + }
> +
> + void finalizeAsync(FinalizeContinuation OnFinalize) override {
> +
> + std::vector<tpctypes::BufferWrite> BufferWrites;
> + orcrpctpc::ReleaseOrFinalizeMemRequest FMR;
> +
> + for (auto &KV : HostAllocs) {
> + assert(TargetAllocs.count(KV.first) &&
> + "No target allocation for buffer");
> + auto &HA = KV.second;
> + auto &TA = TargetAllocs[KV.first];
> + BufferWrites.push_back({TA.Address, StringRef(HA.Mem.get(),
> HA.Size)});
> + FMR.push_back({orcrpctpc::toWireProtectionFlags(
> +
> static_cast<sys::Memory::ProtectionFlags>(KV.first)),
> + TA.Address, TA.AllocatedSize});
> + }
> +
> + DEBUG_WITH_TYPE("orc", {
> + dbgs() << "finalizeAsync " << (void *)this << ":\n";
> + auto FMRI = FMR.begin();
> + for (auto &B : BufferWrites) {
> + auto Prot = FMRI->Prot;
> + ++FMRI;
> + dbgs() << " Writing " << formatv("{0:x16}", B.Buffer.size())
> + << " bytes to " << ((Prot & orcrpctpc::WPF_Read) ? 'R' :
> '-')
> + << ((Prot & orcrpctpc::WPF_Write) ? 'W' : '-')
> + << ((Prot & orcrpctpc::WPF_Exec) ? 'X' : '-')
> + << " segment: local " << (void *)B.Buffer.data()
> + << " -> target " << formatv("{0:x16}", B.Address) <<
> "\n";
> + }
> + });
> + if (auto Err =
> + Parent.Parent.getMemoryAccess().writeBuffers(BufferWrites))
> {
> + OnFinalize(std::move(Err));
> + return;
> + }
> +
> + DEBUG_WITH_TYPE("orc", dbgs() << " Applying permissions...\n");
> + if (auto Err =
> + Parent.getEndpoint().template
> callAsync<orcrpctpc::FinalizeMem>(
> + [OF = std::move(OnFinalize)](Error Err2) {
> + // FIXME: Dispatch to work queue.
> + std::thread([OF = std::move(OF),
> + Err3 = std::move(Err2)]() mutable {
> + DEBUG_WITH_TYPE(
> + "orc", { dbgs() << " finalizeAsync
> complete\n"; });
> + OF(std::move(Err3));
> + }).detach();
> + return Error::success();
> + },
> + FMR)) {
> + DEBUG_WITH_TYPE("orc", dbgs() << " failed.\n");
> + Parent.getEndpoint().abandonPendingResponses();
> + Parent.reportError(std::move(Err));
> + }
> + DEBUG_WITH_TYPE("orc", {
> + dbgs() << "Leaving finalizeAsync (finalization may continue in "
> + "background)\n";
> + });
> + }
> +
> + Error deallocate() override {
> + orcrpctpc::ReleaseOrFinalizeMemRequest RMR;
> + for (auto &KV : TargetAllocs)
> + RMR.push_back({orcrpctpc::toWireProtectionFlags(
> +
> static_cast<sys::Memory::ProtectionFlags>(KV.first)),
> + KV.second.Address, KV.second.AllocatedSize});
> + TargetAllocs.clear();
> +
> + return Parent.getEndpoint().template
> callB<orcrpctpc::ReleaseMem>(RMR);
> + }
> +
> + private:
> + OrcRPCTPCJITLinkMemoryManager<OrcRPCTPCImplT> &Parent;
> + HostAllocMap HostAllocs;
> + TargetAllocMap TargetAllocs;
> + };
> +
> + OrcRPCTPCJITLinkMemoryManager(OrcRPCTPCImplT &Parent) : Parent(Parent)
> {}
> +
> + Expected<std::unique_ptr<Allocation>>
> + allocate(const SegmentsRequestMap &Request) override {
> + orcrpctpc::ReserveMemRequest RMR;
> + HostAllocMap HostAllocs;
> +
> + for (auto &KV : Request) {
> + RMR.push_back({orcrpctpc::toWireProtectionFlags(
> +
> static_cast<sys::Memory::ProtectionFlags>(KV.first)),
> + KV.second.getContentSize() +
> KV.second.getZeroFillSize(),
> + KV.second.getAlignment()});
> + HostAllocs[KV.first] = {
> + std::make_unique<char[]>(KV.second.getContentSize()),
> + KV.second.getContentSize()};
> + }
> +
> + DEBUG_WITH_TYPE("orc", {
> + dbgs() << "Orc remote memmgr got request:\n";
> + for (auto &KV : Request)
> + dbgs() << " permissions: "
> + << ((KV.first & sys::Memory::MF_READ) ? 'R' : '-')
> + << ((KV.first & sys::Memory::MF_WRITE) ? 'W' : '-')
> + << ((KV.first & sys::Memory::MF_EXEC) ? 'X' : '-')
> + << ", content size: "
> + << formatv("{0:x16}", KV.second.getContentSize())
> + << " + zero-fill-size: "
> + << formatv("{0:x16}", KV.second.getZeroFillSize())
> + << ", align: " << KV.second.getAlignment() << "\n";
> + });
> +
> + // FIXME: LLVM RPC needs to be fixed to support alt
> + // serialization/deserialization on return types. For now just
> + // translate from std::map to DenseMap manually.
> + auto TmpTargetAllocs =
> + Parent.getEndpoint().template callB<orcrpctpc::ReserveMem>(RMR);
> + if (!TmpTargetAllocs)
> + return TmpTargetAllocs.takeError();
> +
> + if (TmpTargetAllocs->size() != RMR.size())
> + return make_error<StringError>(
> + "Number of target allocations does not match request",
> + inconvertibleErrorCode());
> +
> + TargetAllocMap TargetAllocs;
> + for (auto &E : *TmpTargetAllocs)
> + TargetAllocs[orcrpctpc::fromWireProtectionFlags(E.Prot)] = {
> + E.Address, E.AllocatedSize};
> +
> + DEBUG_WITH_TYPE("orc", {
> + auto HAI = HostAllocs.begin();
> + for (auto &KV : TargetAllocs)
> + dbgs() << " permissions: "
> + << ((KV.first & sys::Memory::MF_READ) ? 'R' : '-')
> + << ((KV.first & sys::Memory::MF_WRITE) ? 'W' : '-')
> + << ((KV.first & sys::Memory::MF_EXEC) ? 'X' : '-')
> + << " assigned local " << (void *)HAI->second.Mem.get()
> + << ", target " << formatv("{0:x16}", KV.second.Address) <<
> "\n";
> + });
> +
> + return std::make_unique<OrcRPCAllocation>(*this,
> std::move(HostAllocs),
> + std::move(TargetAllocs));
> + }
> +
> +private:
> + void reportError(Error Err) { Parent.reportError(std::move(Err)); }
> +
> + decltype(std::declval<OrcRPCTPCImplT>().getEndpoint()) getEndpoint() {
> + return Parent.getEndpoint();
> + }
> +
> + OrcRPCTPCImplT &Parent;
> +};
> +
> +/// TargetProcessControl::MemoryAccess implementation for a process
> connected
> +/// via an ORC RPC endpoint.
> +template <typename OrcRPCTPCImplT>
> +class OrcRPCTPCMemoryAccess : public TargetProcessControl::MemoryAccess {
> +public:
> + OrcRPCTPCMemoryAccess(OrcRPCTPCImplT &Parent) : Parent(Parent) {}
> +
> + void writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws,
> + WriteResultFn OnWriteComplete) override {
> + writeViaRPC<orcrpctpc::WriteUInt8s>(Ws, std::move(OnWriteComplete));
> + }
> +
> + void writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws,
> + WriteResultFn OnWriteComplete) override {
> + writeViaRPC<orcrpctpc::WriteUInt16s>(Ws, std::move(OnWriteComplete));
> + }
> +
> + void writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws,
> + WriteResultFn OnWriteComplete) override {
> + writeViaRPC<orcrpctpc::WriteUInt32s>(Ws, std::move(OnWriteComplete));
> + }
> +
> + void writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws,
> + WriteResultFn OnWriteComplete) override {
> + writeViaRPC<orcrpctpc::WriteUInt64s>(Ws, std::move(OnWriteComplete));
> + }
> +
> + void writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws,
> + WriteResultFn OnWriteComplete) override {
> + writeViaRPC<orcrpctpc::WriteBuffers>(Ws, std::move(OnWriteComplete));
> + }
> +
> +private:
> + template <typename WriteRPCFunction, typename WriteElementT>
> + void writeViaRPC(ArrayRef<WriteElementT> Ws, WriteResultFn
> OnWriteComplete) {
> + if (auto Err = Parent.getEndpoint().template
> callAsync<WriteRPCFunction>(
> + [OWC = std::move(OnWriteComplete)](Error Err2) mutable ->
> Error {
> + OWC(std::move(Err2));
> + return Error::success();
> + },
> + Ws)) {
> + Parent.reportError(std::move(Err));
> + Parent.getEndpoint().abandonPendingResponses();
> + }
> + }
> +
> + OrcRPCTPCImplT &Parent;
> +};
> +
> +// TargetProcessControl for a process connected via an ORC RPC Endpoint.
> +template <typename RPCEndpointT>
> +class OrcRPCTargetProcessControlBase : public TargetProcessControl {
> +public:
> + using ErrorReporter = unique_function<void(Error)>;
> +
> + using OnCloseConnectionFunction = unique_function<Error(Error)>;
> +
> + OrcRPCTargetProcessControlBase(std::shared_ptr<SymbolStringPool> SSP,
> + RPCEndpointT &EP, ErrorReporter
> ReportError)
> + : TargetProcessControl(std::move(SSP)),
> + ReportError(std::move(ReportError)), EP(EP) {}
> +
> + void reportError(Error Err) { ReportError(std::move(Err)); }
> +
> + RPCEndpointT &getEndpoint() { return EP; }
> +
> + Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath)
> override {
> + DEBUG_WITH_TYPE("orc", {
> + dbgs() << "Loading dylib \"" << (DylibPath ? DylibPath : "") << "\"
> ";
> + if (!DylibPath)
> + dbgs() << "(process symbols)";
> + dbgs() << "\n";
> + });
> + if (!DylibPath)
> + DylibPath = "";
> + auto H = EP.template callB<orcrpctpc::LoadDylib>(DylibPath);
> + DEBUG_WITH_TYPE("orc", {
> + if (H)
> + dbgs() << " got handle " << formatv("{0:x16}", *H) << "\n";
> + else
> + dbgs() << " error, unable to load\n";
> + });
> + return H;
> + }
> +
> + Expected<std::vector<tpctypes::LookupResult>>
> + lookupSymbols(ArrayRef<tpctypes::LookupRequest> Request) override {
> + std::vector<orcrpctpc::RemoteLookupRequest> RR;
> + for (auto &E : Request) {
> + RR.push_back({});
> + RR.back().first = E.Handle;
> + for (auto &KV : E.Symbols)
> + RR.back().second.push_back(
> + {(*KV.first).str(),
> + KV.second == SymbolLookupFlags::WeaklyReferencedSymbol});
> + }
> + DEBUG_WITH_TYPE("orc", {
> + dbgs() << "Compound lookup:\n";
> + for (auto &R : Request) {
> + dbgs() << " In " << formatv("{0:x16}", R.Handle) << ": {";
> + bool First = true;
> + for (auto &KV : R.Symbols) {
> + dbgs() << (First ? "" : ",") << " " << *KV.first;
> + First = false;
> + }
> + dbgs() << " }\n";
> + }
> + });
> + return EP.template callB<orcrpctpc::LookupSymbols>(RR);
> + }
> +
> + Expected<int32_t> runAsMain(JITTargetAddress MainFnAddr,
> + ArrayRef<std::string> Args) override {
> + DEBUG_WITH_TYPE("orc", {
> + dbgs() << "Running as main: " << formatv("{0:x16}", MainFnAddr)
> + << ", args = [";
> + for (unsigned I = 0; I != Args.size(); ++I)
> + dbgs() << (I ? "," : "") << " \"" << Args[I] << "\"";
> + dbgs() << "]\n";
> + });
> + auto Result = EP.template callB<orcrpctpc::RunMain>(MainFnAddr, Args);
> + DEBUG_WITH_TYPE("orc", {
> + dbgs() << " call to " << formatv("{0:x16}", MainFnAddr);
> + if (Result)
> + dbgs() << " returned result " << *Result << "\n";
> + else
> + dbgs() << " failed\n";
> + });
> + return Result;
> + }
> +
> + Expected<tpctypes::WrapperFunctionResult>
> + runWrapper(JITTargetAddress WrapperFnAddr,
> + ArrayRef<uint8_t> ArgBuffer) override {
> + DEBUG_WITH_TYPE("orc", {
> + dbgs() << "Running as wrapper function "
> + << formatv("{0:x16}", WrapperFnAddr) << " with "
> + << formatv("{0:x16}", ArgBuffer.size()) << " argument
> buffer\n";
> + });
> + auto Result =
> + EP.template callB<orcrpctpc::RunWrapper>(WrapperFnAddr,
> ArgBuffer);
> + // dbgs() << "Returned from runWrapper...\n";
> + return Result;
> + }
> +
> + Error closeConnection(OnCloseConnectionFunction OnCloseConnection) {
> + DEBUG_WITH_TYPE("orc", dbgs() << "Closing connection to remote\n");
> + return EP.template callAsync<orcrpctpc::CloseConnection>(
> + std::move(OnCloseConnection));
> + }
> +
> + Error closeConnectionAndWait() {
> + std::promise<MSVCPError> P;
> + auto F = P.get_future();
> + if (auto Err = closeConnection([&](Error Err2) -> Error {
> + P.set_value(std::move(Err2));
> + return Error::success();
> + })) {
> + EP.abandonAllPendingResponses();
> + return joinErrors(std::move(Err), F.get());
> + }
> + return F.get();
> + }
> +
> +protected:
> + /// Subclasses must call this during construction to initialize the
> + /// TargetTriple and PageSize members.
> + Error initializeORCRPCTPCBase() {
> + if (auto TripleOrErr = EP.template
> callB<orcrpctpc::GetTargetTriple>())
> + TargetTriple = Triple(*TripleOrErr);
> + else
> + return TripleOrErr.takeError();
> +
> + if (auto PageSizeOrErr = EP.template callB<orcrpctpc::GetPageSize>())
> + PageSize = *PageSizeOrErr;
> + else
> + return PageSizeOrErr.takeError();
> +
> + return Error::success();
> + }
> +
> +private:
> + ErrorReporter ReportError;
> + RPCEndpointT &EP;
> +};
> +
> +} // end namespace orc
> +} // end namespace llvm
> +
> +#endif // LLVM_EXECUTIONENGINE_ORC_ORCRPCTARGETPROCESSCONTROL_H
>
> diff --git a/llvm/include/llvm/ExecutionEngine/Orc/RPC/FDRawByteChannel.h
> b/llvm/include/llvm/ExecutionEngine/Orc/RPC/FDRawByteChannel.h
> index 25edb289a5f9..9faa1afe546c 100644
> --- a/llvm/include/llvm/ExecutionEngine/Orc/RPC/FDRawByteChannel.h
> +++ b/llvm/include/llvm/ExecutionEngine/Orc/RPC/FDRawByteChannel.h
> @@ -15,6 +15,9 @@
>
> #include "llvm/ExecutionEngine/Orc/RPC/RawByteChannel.h"
>
> +#include "llvm/Support/FormatVariadic.h"
> +#include "llvm/Support/raw_ostream.h"
> +
> #if !defined(_MSC_VER) && !defined(__MINGW32__)
> #include <unistd.h>
> #else
> @@ -31,11 +34,13 @@ class FDRawByteChannel final : public RawByteChannel {
> FDRawByteChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {}
>
> llvm::Error readBytes(char *Dst, unsigned Size) override {
> + // dbgs() << "Reading " << Size << " bytes: [";
> assert(Dst && "Attempt to read into null.");
> ssize_t Completed = 0;
> while (Completed < static_cast<ssize_t>(Size)) {
> ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed);
> if (Read <= 0) {
> + // dbgs() << " <<<\n";
> auto ErrNo = errno;
> if (ErrNo == EAGAIN || ErrNo == EINTR)
> continue;
> @@ -43,17 +48,22 @@ class FDRawByteChannel final : public RawByteChannel {
> return llvm::errorCodeToError(
> std::error_code(errno, std::generic_category()));
> }
> + // for (size_t I = 0; I != Read; ++I)
> + // dbgs() << " " << formatv("{0:x2}", Dst[Completed + I]);
> Completed += Read;
> }
> + // dbgs() << " ]\n";
> return llvm::Error::success();
> }
>
> llvm::Error appendBytes(const char *Src, unsigned Size) override {
> + // dbgs() << "Appending " << Size << " bytes: [";
> assert(Src && "Attempt to append from null.");
> ssize_t Completed = 0;
> while (Completed < static_cast<ssize_t>(Size)) {
> ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed);
> if (Written < 0) {
> + // dbgs() << " <<<\n";
> auto ErrNo = errno;
> if (ErrNo == EAGAIN || ErrNo == EINTR)
> continue;
> @@ -61,8 +71,11 @@ class FDRawByteChannel final : public RawByteChannel {
> return llvm::errorCodeToError(
> std::error_code(errno, std::generic_category()));
> }
> + // for (size_t I = 0; I != Written; ++I)
> + // dbgs() << " " << formatv("{0:x2}", Src[Completed + I]);
> Completed += Written;
> }
> + // dbgs() << " ]\n";
> return llvm::Error::success();
> }
>
>
> diff --git a/llvm/include/llvm/ExecutionEngine/Orc/RPC/RPCSerialization.h
> b/llvm/include/llvm/ExecutionEngine/Orc/RPC/RPCSerialization.h
> index 948a1b061e3b..0dc05f4d1c17 100644
> --- a/llvm/include/llvm/ExecutionEngine/Orc/RPC/RPCSerialization.h
> +++ b/llvm/include/llvm/ExecutionEngine/Orc/RPC/RPCSerialization.h
> @@ -9,6 +9,8 @@
> #ifndef LLVM_EXECUTIONENGINE_ORC_RPC_RPCSERIALIZATION_H
> #define LLVM_EXECUTIONENGINE_ORC_RPC_RPCSERIALIZATION_H
>
> +#include "llvm/ADT/ArrayRef.h"
> +#include "llvm/ADT/DenseMap.h"
> #include "llvm/ExecutionEngine/Orc/OrcError.h"
> #include "llvm/Support/thread.h"
> #include <map>
> @@ -166,6 +168,19 @@ class RPCTypeName<std::tuple<ArgTs...>> {
> }
> };
>
> +template <typename T> class RPCTypeName<Optional<T>> {
> +public:
> + static const char *getName() {
> + static std::string Name = [] {
> + std::string Name;
> + raw_string_ostream(Name)
> + << "Optional<" << RPCTypeName<T>::getName() << ">";
> + return Name;
> + }();
> + return Name.data();
> + }
> +};
> +
> template <typename T>
> class RPCTypeName<std::vector<T>> {
> public:
> @@ -574,6 +589,31 @@ class SerializationTraits<ChannelT,
> std::tuple<ArgTs...>> {
> }
> };
>
> +template <typename ChannelT, typename T>
> +class SerializationTraits<ChannelT, Optional<T>> {
> +public:
> + /// Serialize an Optional<T>.
> + static Error serialize(ChannelT &C, const Optional<T> &O) {
> + if (auto Err = serializeSeq(C, O != None))
> + return Err;
> + if (O)
> + if (auto Err = serializeSeq(C, *O))
> + return Err;
> + return Error::success();
> + }
> +
> + /// Deserialize an Optional<T>.
> + static Error deserialize(ChannelT &C, Optional<T> &O) {
> + bool HasValue = false;
> + if (auto Err = deserializeSeq(C, HasValue))
> + return Err;
> + if (HasValue)
> + if (auto Err = deserializeSeq(C, *O))
> + return Err;
> + return Error::success();
> + };
> +};
> +
> /// SerializationTraits default specialization for std::vector.
> template <typename ChannelT, typename T>
> class SerializationTraits<ChannelT, std::vector<T>> {
> @@ -609,6 +649,22 @@ class SerializationTraits<ChannelT, std::vector<T>> {
> }
> };
>
> +/// Enable vector serialization from an ArrayRef.
> +template <typename ChannelT, typename T>
> +class SerializationTraits<ChannelT, std::vector<T>, ArrayRef<T>> {
> +public:
> + static Error serialize(ChannelT &C, ArrayRef<T> V) {
> + if (auto Err = serializeSeq(C, static_cast<uint64_t>(V.size())))
> + return Err;
> +
> + for (const auto &E : V)
> + if (auto Err = serializeSeq(C, E))
> + return Err;
> +
> + return Error::success();
> + }
> +};
> +
> template <typename ChannelT, typename T, typename T2>
> class SerializationTraits<ChannelT, std::set<T>, std::set<T2>> {
> public:
> @@ -695,6 +751,55 @@ class SerializationTraits<ChannelT, std::map<K, V>,
> std::map<K2, V2>> {
> }
> };
>
> +template <typename ChannelT, typename K, typename V, typename K2,
> typename V2>
> +class SerializationTraits<ChannelT, std::map<K, V>, DenseMap<K2, V2>> {
> +public:
> + /// Serialize a std::map<K, V> from DenseMap<K2, V2>.
> + static Error serialize(ChannelT &C, const DenseMap<K2, V2> &M) {
> + if (auto Err = serializeSeq(C, static_cast<uint64_t>(M.size())))
> + return Err;
> +
> + for (auto &E : M) {
> + if (auto Err =
> + SerializationTraits<ChannelT, K, K2>::serialize(C, E.first))
> + return Err;
> +
> + if (auto Err =
> + SerializationTraits<ChannelT, V, V2>::serialize(C,
> E.second))
> + return Err;
> + }
> +
> + return Error::success();
> + }
> +
> + /// Serialize a std::map<K, V> from DenseMap<K2, V2>.
> + static Error deserialize(ChannelT &C, DenseMap<K2, V2> &M) {
> + assert(M.empty() && "Expected default-constructed map to deserialize
> into");
> +
> + uint64_t Count = 0;
> + if (auto Err = deserializeSeq(C, Count))
> + return Err;
> +
> + while (Count-- != 0) {
> + std::pair<K2, V2> Val;
> + if (auto Err =
> + SerializationTraits<ChannelT, K, K2>::deserialize(C,
> Val.first))
> + return Err;
> +
> + if (auto Err =
> + SerializationTraits<ChannelT, V, V2>::deserialize(C,
> Val.second))
> + return Err;
> +
> + auto Added = M.insert(Val).second;
> + if (!Added)
> + return make_error<StringError>("Duplicate element in deserialized
> map",
> +
> orcError(OrcErrorCode::UnknownORCError));
> + }
> +
> + return Error::success();
> + }
> +};
> +
> } // end namespace rpc
> } // end namespace orc
> } // end namespace llvm
>
> diff --git
> a/llvm/include/llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h
> b/llvm/include/llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h
> new file mode 100644
> index 000000000000..9f958989f46d
> --- /dev/null
> +++
> b/llvm/include/llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h
> @@ -0,0 +1,174 @@
> +//===--- TargetProcessControlTypes.h -- Shared Core/TPC types ---*- C++
> -*-===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// TargetProcessControl types that are used by both the Orc and
> +// OrcTargetProcess libraries.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_TARGETPROCESSCONTROLTYPES_H
> +#define LLVM_EXECUTIONENGINE_ORC_SHARED_TARGETPROCESSCONTROLTYPES_H
> +
> +#include "llvm/ADT/ArrayRef.h"
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/ExecutionEngine/JITSymbol.h"
> +#include "llvm/ExecutionEngine/Orc/Core.h"
> +
> +#include <vector>
> +
> +namespace llvm {
> +namespace orc {
> +namespace tpctypes {
> +
> +template <typename T> struct UIntWrite {
> + UIntWrite() = default;
> + UIntWrite(JITTargetAddress Address, T Value)
> + : Address(Address), Value(Value) {}
> +
> + JITTargetAddress Address = 0;
> + T Value = 0;
> +};
> +
> +/// Describes a write to a uint8_t.
> +using UInt8Write = UIntWrite<uint8_t>;
> +
> +/// Describes a write to a uint16_t.
> +using UInt16Write = UIntWrite<uint16_t>;
> +
> +/// Describes a write to a uint32_t.
> +using UInt32Write = UIntWrite<uint32_t>;
> +
> +/// Describes a write to a uint64_t.
> +using UInt64Write = UIntWrite<uint64_t>;
> +
> +/// Describes a write to a buffer.
> +/// For use with TargetProcessControl::MemoryAccess objects.
> +struct BufferWrite {
> + BufferWrite() = default;
> + BufferWrite(JITTargetAddress Address, StringRef Buffer)
> + : Address(Address), Buffer(Buffer) {}
> +
> + JITTargetAddress Address = 0;
> + StringRef Buffer;
> +};
> +
> +/// A handle used to represent a loaded dylib in the target process.
> +using DylibHandle = JITTargetAddress;
> +
> +/// A pair of a dylib and a set of symbols to be looked up.
> +struct LookupRequest {
> + LookupRequest(DylibHandle Handle, const SymbolLookupSet &Symbols)
> + : Handle(Handle), Symbols(Symbols) {}
> + DylibHandle Handle;
> + const SymbolLookupSet &Symbols;
> +};
> +
> +using LookupResult = std::vector<JITTargetAddress>;
> +
> +/// Either a uint8_t array or a uint8_t*.
> +union CWrapperFunctionResultData {
> + uint8_t Value[8];
> + uint8_t *ValuePtr;
> +};
> +
> +/// C ABI compatible wrapper function result.
> +///
> +/// This can be safely returned from extern "C" functions, but should be
> used
> +/// to construct a WrapperFunctionResult for safety.
> +struct CWrapperFunctionResult {
> + uint64_t Size;
> + CWrapperFunctionResultData Data;
> + void (*Destroy)(CWrapperFunctionResultData Data, uint64_t Size);
> +};
> +
> +/// C++ wrapper function result: Same as CWrapperFunctionResult but
> +/// auto-releases memory.
> +class WrapperFunctionResult {
> +public:
> + /// Create a default WrapperFunctionResult.
> + WrapperFunctionResult() { zeroInit(R); }
> +
> + /// Create a WrapperFunctionResult from a CWrapperFunctionResult. This
> + /// instance takes ownership of the result object and will automatically
> + /// call the Destroy member upon destruction.
> + WrapperFunctionResult(CWrapperFunctionResult R) : R(R) {}
> +
> + WrapperFunctionResult(const WrapperFunctionResult &) = delete;
> + WrapperFunctionResult &operator=(const WrapperFunctionResult &) =
> delete;
> +
> + WrapperFunctionResult(WrapperFunctionResult &&Other) {
> + zeroInit(R);
> + std::swap(R, Other.R);
> + }
> +
> + WrapperFunctionResult &operator=(WrapperFunctionResult &&Other) {
> + CWrapperFunctionResult Tmp;
> + zeroInit(Tmp);
> + std::swap(Tmp, Other.R);
> + std::swap(R, Tmp);
> + return *this;
> + }
> +
> + ~WrapperFunctionResult() {
> + if (R.Destroy)
> + R.Destroy(R.Data, R.Size);
> + }
> +
> + /// Relinquish ownership of and return the CWrapperFunctionResult.
> + CWrapperFunctionResult release() {
> + CWrapperFunctionResult Tmp;
> + zeroInit(Tmp);
> + std::swap(R, Tmp);
> + return Tmp;
> + }
> +
> + /// Get an ArrayRef covering the data in the result.
> + ArrayRef<uint8_t> getData() const {
> + if (R.Size <= 8)
> + return ArrayRef<uint8_t>(R.Data.Value, R.Size);
> + return ArrayRef<uint8_t>(R.Data.ValuePtr, R.Size);
> + }
> +
> + /// Create a WrapperFunctionResult from the given integer, provided its
> + /// size is no greater than 64 bits.
> + template <typename T,
> + typename _ = std::enable_if_t<std::is_integral<T>::value &&
> + sizeof(T) <= sizeof(uint64_t)>>
> + static WrapperFunctionResult from(T Value) {
> + CWrapperFunctionResult R;
> + R.Size = sizeof(T);
> + memcpy(&R.Data.Value, Value, R.Size);
> + R.Destroy = nullptr;
> + return R;
> + }
> +
> + /// Create a WrapperFunctionResult from the given string.
> + static WrapperFunctionResult from(StringRef S);
> +
> + /// Always free Data.ValuePtr by calling free on it.
> + static void destroyWithFree(CWrapperFunctionResultData Data, uint64_t
> Size);
> +
> + /// Always free Data.ValuePtr by calling delete[] on it.
> + static void destroyWithDeleteArray(CWrapperFunctionResultData Data,
> + uint64_t Size);
> +
> +private:
> + void zeroInit(CWrapperFunctionResult &R) {
> + R.Size = 0;
> + R.Data.ValuePtr = nullptr;
> + R.Destroy = nullptr;
> + }
> +
> + CWrapperFunctionResult R;
> +};
> +
> +} // end namespace tpctypes
> +} // end namespace orc
> +} // end namespace llvm
> +
> +#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_TARGETPROCESSCONTROLTYPES_H
>
> diff --git
> a/llvm/include/llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h
> b/llvm/include/llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h
> index 3b5c4b9cf8cd..07720f5c0f33 100644
> ---
> a/llvm/include/llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h
> +++
> b/llvm/include/llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h
> @@ -31,7 +31,7 @@ class TPCDynamicLibrarySearchGenerator : public
> DefinitionGenerator {
> /// will be searched for. If the predicate is not given then all
> symbols will
> /// be searched for.
> TPCDynamicLibrarySearchGenerator(TargetProcessControl &TPC,
> - TargetProcessControl::DylibHandle H,
> + tpctypes::DylibHandle H,
> SymbolPredicate Allow =
> SymbolPredicate())
> : TPC(TPC), H(H), Allow(std::move(Allow)) {}
>
> @@ -56,7 +56,7 @@ class TPCDynamicLibrarySearchGenerator : public
> DefinitionGenerator {
>
> private:
> TargetProcessControl &TPC;
> - TargetProcessControl::DylibHandle H;
> + tpctypes::DylibHandle H;
> SymbolPredicate Allow;
> };
>
>
> diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TPCEHFrameRegistrar.h
> b/llvm/include/llvm/ExecutionEngine/Orc/TPCEHFrameRegistrar.h
> new file mode 100644
> index 000000000000..519f818907f9
> --- /dev/null
> +++ b/llvm/include/llvm/ExecutionEngine/Orc/TPCEHFrameRegistrar.h
> @@ -0,0 +1,54 @@
> +//===-- TPCEHFrameRegistrar.h - TPC based eh-frame registration -*- C++
> -*-===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// TargetProcessControl based eh-frame registration.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_EXECUTIONENGINE_ORC_TPCEHFRAMEREGISTRAR_H
> +#define LLVM_EXECUTIONENGINE_ORC_TPCEHFRAMEREGISTRAR_H
> +
> +#include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
> +#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
> +
> +namespace llvm {
> +namespace orc {
> +
> +/// Register/Deregisters EH frames in a remote process via a
> +/// TargetProcessControl instance.
> +class TPCEHFrameRegistrar : public jitlink::EHFrameRegistrar {
> +public:
> + /// Create from a TargetProcessControl instance alone. This will use
> + /// the TPC's lookupSymbols method to find the
> registration/deregistration
> + /// funciton addresses by name.
> + static Expected<std::unique_ptr<TPCEHFrameRegistrar>>
> + Create(TargetProcessControl &TPC);
> +
> + /// Create a TPCEHFrameRegistrar with the given TargetProcessControl
> + /// object and registration/deregistration function addresses.
> + TPCEHFrameRegistrar(TargetProcessControl &TPC,
> + JITTargetAddress RegisterEHFrameWrapperFnAddr,
> + JITTargetAddress DeregisterEHFRameWrapperFnAddr)
> + : TPC(TPC),
> RegisterEHFrameWrapperFnAddr(RegisterEHFrameWrapperFnAddr),
> + DeregisterEHFrameWrapperFnAddr(DeregisterEHFRameWrapperFnAddr) {}
> +
> + Error registerEHFrames(JITTargetAddress EHFrameSectionAddr,
> + size_t EHFrameSectionSize) override;
> + Error deregisterEHFrames(JITTargetAddress EHFrameSectionAddr,
> + size_t EHFrameSectionSize) override;
> +
> +private:
> + TargetProcessControl &TPC;
> + JITTargetAddress RegisterEHFrameWrapperFnAddr;
> + JITTargetAddress DeregisterEHFrameWrapperFnAddr;
> +};
> +
> +} // end namespace orc
> +} // end namespace llvm
> +
> +#endif // LLVM_EXECUTIONENGINE_ORC_TPCEHFRAMEREGISTRAR_H
>
> diff --git
> a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h
> b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h
> new file mode 100644
> index 000000000000..2b759dea6333
> --- /dev/null
> +++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h
> @@ -0,0 +1,614 @@
> +//===-- OrcRPCTPCServer.h -- OrcRPCTargetProcessControl Server --*- C++
> -*-===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// OrcRPCTargetProcessControl server class.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_ORCRPCTPCSERVER_H
> +#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_ORCRPCTPCSERVER_H
> +
> +#include "llvm/ADT/BitmaskEnum.h"
> +#include "llvm/ExecutionEngine/Orc/RPC/RPCUtils.h"
> +#include "llvm/ExecutionEngine/Orc/RPC/RawByteChannel.h"
> +#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
> +#include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h"
> +#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
> +#include "llvm/Support/DynamicLibrary.h"
> +#include "llvm/Support/FormatVariadic.h"
> +#include "llvm/Support/Host.h"
> +#include "llvm/Support/MathExtras.h"
> +#include "llvm/Support/Memory.h"
> +#include "llvm/Support/Process.h"
> +
> +#include <atomic>
> +
> +namespace llvm {
> +namespace orc {
> +
> +namespace orcrpctpc {
> +
> +enum WireProtectionFlags : uint8_t {
> + WPF_None = 0,
> + WPF_Read = 1U << 0,
> + WPF_Write = 1U << 1,
> + WPF_Exec = 1U << 2,
> + LLVM_MARK_AS_BITMASK_ENUM(WPF_Exec)
> +};
> +
> +/// Convert from sys::Memory::ProtectionFlags
> +inline WireProtectionFlags
> +toWireProtectionFlags(sys::Memory::ProtectionFlags PF) {
> + WireProtectionFlags WPF = WPF_None;
> + if (PF & sys::Memory::MF_READ)
> + WPF |= WPF_Read;
> + if (PF & sys::Memory::MF_WRITE)
> + WPF |= WPF_Write;
> + if (PF & sys::Memory::MF_EXEC)
> + WPF |= WPF_Exec;
> + return WPF;
> +}
> +
> +inline sys::Memory::ProtectionFlags
> +fromWireProtectionFlags(WireProtectionFlags WPF) {
> + int PF = 0;
> + if (WPF & WPF_Read)
> + PF |= sys::Memory::MF_READ;
> + if (WPF & WPF_Write)
> + PF |= sys::Memory::MF_WRITE;
> + if (WPF & WPF_Exec)
> + PF |= sys::Memory::MF_EXEC;
> + return static_cast<sys::Memory::ProtectionFlags>(PF);
> +}
> +
> +struct ReserveMemRequestElement {
> + WireProtectionFlags Prot = WPF_None;
> + uint64_t Size = 0;
> + uint64_t Alignment = 0;
> +};
> +
> +using ReserveMemRequest = std::vector<ReserveMemRequestElement>;
> +
> +struct ReserveMemResultElement {
> + WireProtectionFlags Prot = WPF_None;
> + JITTargetAddress Address = 0;
> + uint64_t AllocatedSize = 0;
> +};
> +
> +using ReserveMemResult = std::vector<ReserveMemResultElement>;
> +
> +struct ReleaseOrFinalizeMemRequestElement {
> + WireProtectionFlags Prot = WPF_None;
> + JITTargetAddress Address = 0;
> + uint64_t Size = 0;
> +};
> +
> +using ReleaseOrFinalizeMemRequest =
> + std::vector<ReleaseOrFinalizeMemRequestElement>;
> +
> +} // end namespace orcrpctpc
> +
> +namespace rpc {
> +
> +template <> class RPCTypeName<tpctypes::UInt8Write> {
> +public:
> + static const char *getName() { return "UInt8Write"; }
> +};
> +
> +template <> class RPCTypeName<tpctypes::UInt16Write> {
> +public:
> + static const char *getName() { return "UInt16Write"; }
> +};
> +
> +template <> class RPCTypeName<tpctypes::UInt32Write> {
> +public:
> + static const char *getName() { return "UInt32Write"; }
> +};
> +
> +template <> class RPCTypeName<tpctypes::UInt64Write> {
> +public:
> + static const char *getName() { return "UInt64Write"; }
> +};
> +
> +template <> class RPCTypeName<tpctypes::BufferWrite> {
> +public:
> + static const char *getName() { return "BufferWrite"; }
> +};
> +
> +template <> class RPCTypeName<orcrpctpc::ReserveMemRequestElement> {
> +public:
> + static const char *getName() { return "ReserveMemRequestElement"; }
> +};
> +
> +template <> class RPCTypeName<orcrpctpc::ReserveMemResultElement> {
> +public:
> + static const char *getName() { return "ReserveMemResultElement"; }
> +};
> +
> +template <> class
> RPCTypeName<orcrpctpc::ReleaseOrFinalizeMemRequestElement> {
> +public:
> + static const char *getName() { return
> "ReleaseOrFinalizeMemRequestElement"; }
> +};
> +
> +template <> class RPCTypeName<tpctypes::WrapperFunctionResult> {
> +public:
> + static const char *getName() { return "WrapperFunctionResult"; }
> +};
> +
> +template <typename ChannelT, typename WriteT>
> +class SerializationTraits<
> + ChannelT, WriteT, WriteT,
> + std::enable_if_t<std::is_same<WriteT, tpctypes::UInt8Write>::value ||
> + std::is_same<WriteT, tpctypes::UInt16Write>::value ||
> + std::is_same<WriteT, tpctypes::UInt32Write>::value ||
> + std::is_same<WriteT, tpctypes::UInt64Write>::value>>
> {
> +public:
> + static Error serialize(ChannelT &C, const WriteT &W) {
> + return serializeSeq(C, W.Address, W.Value);
> + }
> + static Error deserialize(ChannelT &C, WriteT &W) {
> + return deserializeSeq(C, W.Address, W.Value);
> + }
> +};
> +
> +template <typename ChannelT>
> +class SerializationTraits<
> + ChannelT, tpctypes::BufferWrite, tpctypes::BufferWrite,
> + std::enable_if_t<std::is_base_of<RawByteChannel, ChannelT>::value>> {
> +public:
> + static Error serialize(ChannelT &C, const tpctypes::BufferWrite &W) {
> + uint64_t Size = W.Buffer.size();
> + if (auto Err = serializeSeq(C, W.Address, Size))
> + return Err;
> +
> + return C.appendBytes(W.Buffer.data(), Size);
> + }
> + static Error deserialize(ChannelT &C, tpctypes::BufferWrite &W) {
> + JITTargetAddress Address;
> + uint64_t Size;
> +
> + if (auto Err = deserializeSeq(C, Address, Size))
> + return Err;
> +
> + char *Buffer = jitTargetAddressToPointer<char *>(Address);
> +
> + if (auto Err = C.readBytes(Buffer, Size))
> + return Err;
> +
> + W = {Address, StringRef(Buffer, Size)};
> + return Error::success();
> + }
> +};
> +
> +template <typename ChannelT>
> +class SerializationTraits<ChannelT, orcrpctpc::ReserveMemRequestElement> {
> +public:
> + static Error serialize(ChannelT &C,
> + const orcrpctpc::ReserveMemRequestElement &E) {
> + return serializeSeq(C, static_cast<uint8_t>(E.Prot), E.Size,
> E.Alignment);
> + }
> +
> + static Error deserialize(ChannelT &C,
> + orcrpctpc::ReserveMemRequestElement &E) {
> + return deserializeSeq(C, *reinterpret_cast<uint8_t *>(&E.Prot),
> E.Size,
> + E.Alignment);
> + }
> +};
> +
> +template <typename ChannelT>
> +class SerializationTraits<ChannelT, orcrpctpc::ReserveMemResultElement> {
> +public:
> + static Error serialize(ChannelT &C,
> + const orcrpctpc::ReserveMemResultElement &E) {
> + return serializeSeq(C, static_cast<uint8_t>(E.Prot), E.Address,
> + E.AllocatedSize);
> + }
> +
> + static Error deserialize(ChannelT &C,
> orcrpctpc::ReserveMemResultElement &E) {
> + return deserializeSeq(C, *reinterpret_cast<uint8_t *>(&E.Prot),
> E.Address,
> + E.AllocatedSize);
> + }
> +};
> +
> +template <typename ChannelT>
> +class SerializationTraits<ChannelT,
> + orcrpctpc::ReleaseOrFinalizeMemRequestElement> {
> +public:
> + static Error
> + serialize(ChannelT &C,
> + const orcrpctpc::ReleaseOrFinalizeMemRequestElement &E) {
> + return serializeSeq(C, static_cast<uint8_t>(E.Prot), E.Address,
> E.Size);
> + }
> +
> + static Error deserialize(ChannelT &C,
> + orcrpctpc::ReleaseOrFinalizeMemRequestElement
> &E) {
> + return deserializeSeq(C, *reinterpret_cast<uint8_t *>(&E.Prot),
> E.Address,
> + E.Size);
> + }
> +};
> +
> +template <typename ChannelT>
> +class SerializationTraits<
> + ChannelT, tpctypes::WrapperFunctionResult,
> tpctypes::WrapperFunctionResult,
> + std::enable_if_t<std::is_base_of<RawByteChannel, ChannelT>::value>> {
> +public:
> + static Error serialize(ChannelT &C,
> + const tpctypes::WrapperFunctionResult &E) {
> + auto Data = E.getData();
> + if (auto Err = serializeSeq(C, static_cast<uint64_t>(Data.size())))
> + return Err;
> + if (Data.size() == 0)
> + return Error::success();
> + return C.appendBytes(reinterpret_cast<const char *>(Data.data()),
> + Data.size());
> + }
> +
> + static Error deserialize(ChannelT &C, tpctypes::WrapperFunctionResult
> &E) {
> + tpctypes::CWrapperFunctionResult R;
> +
> + R.Size = 0;
> + R.Data.ValuePtr = nullptr;
> + R.Destroy = nullptr;
> +
> + if (auto Err = deserializeSeq(C, R.Size))
> + return Err;
> + if (R.Size == 0)
> + return Error::success();
> + R.Data.ValuePtr = new uint8_t[R.Size];
> + if (auto Err =
> + C.readBytes(reinterpret_cast<char *>(R.Data.ValuePtr),
> R.Size)) {
> + R.Destroy = tpctypes::WrapperFunctionResult::destroyWithDeleteArray;
> + return Err;
> + }
> +
> + E = tpctypes::WrapperFunctionResult(R);
> + return Error::success();
> + }
> +};
> +
> +} // end namespace rpc
> +
> +namespace orcrpctpc {
> +
> +using RemoteSymbolLookupSet = std::vector<std::pair<std::string, bool>>;
> +using RemoteLookupRequest =
> + std::pair<tpctypes::DylibHandle, RemoteSymbolLookupSet>;
> +
> +class GetTargetTriple : public rpc::Function<GetTargetTriple,
> std::string()> {
> +public:
> + static const char *getName() { return "GetTargetTriple"; }
> +};
> +
> +class GetPageSize : public rpc::Function<GetPageSize, uint64_t()> {
> +public:
> + static const char *getName() { return "GetPageSize"; }
> +};
> +
> +class ReserveMem : public rpc::Function<ReserveMem,
> Expected<ReserveMemResult>(
> +
> ReserveMemRequest)> {
> +public:
> + static const char *getName() { return "ReserveMem"; }
> +};
> +
> +class FinalizeMem
> + : public rpc::Function<FinalizeMem,
> Error(ReleaseOrFinalizeMemRequest)> {
> +public:
> + static const char *getName() { return "FinalizeMem"; }
> +};
> +
> +class ReleaseMem
> + : public rpc::Function<ReleaseMem,
> Error(ReleaseOrFinalizeMemRequest)> {
> +public:
> + static const char *getName() { return "ReleaseMem"; }
> +};
> +
> +class WriteUInt8s
> + : public rpc::Function<WriteUInt8s,
> + Error(std::vector<tpctypes::UInt8Write>)> {
> +public:
> + static const char *getName() { return "WriteUInt8s"; }
> +};
> +
> +class WriteUInt16s
> + : public rpc::Function<WriteUInt16s,
> + Error(std::vector<tpctypes::UInt16Write>)> {
> +public:
> + static const char *getName() { return "WriteUInt16s"; }
> +};
> +
> +class WriteUInt32s
> + : public rpc::Function<WriteUInt32s,
> + Error(std::vector<tpctypes::UInt32Write>)> {
> +public:
> + static const char *getName() { return "WriteUInt32s"; }
> +};
> +
> +class WriteUInt64s
> + : public rpc::Function<WriteUInt64s,
> + Error(std::vector<tpctypes::UInt64Write>)> {
> +public:
> + static const char *getName() { return "WriteUInt64s"; }
> +};
> +
> +class WriteBuffers
> + : public rpc::Function<WriteBuffers,
> + Error(std::vector<tpctypes::BufferWrite>)> {
> +public:
> + static const char *getName() { return "WriteBuffers"; }
> +};
> +
> +class LoadDylib
> + : public rpc::Function<LoadDylib, Expected<tpctypes::DylibHandle>(
> + std::string DylibPath)> {
> +public:
> + static const char *getName() { return "LoadDylib"; }
> +};
> +
> +class LookupSymbols
> + : public rpc::Function<LookupSymbols,
> + Expected<std::vector<tpctypes::LookupResult>>(
> + std::vector<RemoteLookupRequest>)> {
> +public:
> + static const char *getName() { return "LookupSymbols"; }
> +};
> +
> +class RunMain
> + : public rpc::Function<RunMain, int32_t(JITTargetAddress MainAddr,
> + std::vector<std::string>
> Args)> {
> +public:
> + static const char *getName() { return "RunMain"; }
> +};
> +
> +class RunWrapper
> + : public rpc::Function<RunWrapper,
> + tpctypes::WrapperFunctionResult(
> + JITTargetAddress, std::vector<uint8_t>)> {
> +public:
> + static const char *getName() { return "RunWrapper"; }
> +};
> +
> +class CloseConnection : public rpc::Function<CloseConnection, void()> {
> +public:
> + static const char *getName() { return "CloseConnection"; }
> +};
> +
> +} // end namespace orcrpctpc
> +
> +/// TargetProcessControl for a process connected via an ORC RPC Endpoint.
> +template <typename RPCEndpointT> class OrcRPCTPCServer {
> +public:
> + /// Create an OrcRPCTPCServer from the given endpoint.
> + OrcRPCTPCServer(RPCEndpointT &EP) : EP(EP) {
> + using ThisT = OrcRPCTPCServer<RPCEndpointT>;
> +
> + TripleStr = sys::getProcessTriple();
> + PageSize = sys::Process::getPageSizeEstimate();
> +
> + EP.template addHandler<orcrpctpc::GetTargetTriple>(*this,
> +
> &ThisT::getTargetTriple);
> + EP.template addHandler<orcrpctpc::GetPageSize>(*this,
> &ThisT::getPageSize);
> +
> + EP.template addHandler<orcrpctpc::ReserveMem>(*this,
> &ThisT::reserveMemory);
> + EP.template addHandler<orcrpctpc::FinalizeMem>(*this,
> +
> &ThisT::finalizeMemory);
> + EP.template addHandler<orcrpctpc::ReleaseMem>(*this,
> &ThisT::releaseMemory);
> +
> + EP.template addHandler<orcrpctpc::WriteUInt8s>(
> + handleWriteUInt<tpctypes::UInt8Write>);
> + EP.template addHandler<orcrpctpc::WriteUInt16s>(
> + handleWriteUInt<tpctypes::UInt16Write>);
> + EP.template addHandler<orcrpctpc::WriteUInt32s>(
> + handleWriteUInt<tpctypes::UInt32Write>);
> + EP.template addHandler<orcrpctpc::WriteUInt64s>(
> + handleWriteUInt<tpctypes::UInt64Write>);
> + EP.template addHandler<orcrpctpc::WriteBuffers>(handleWriteBuffer);
> +
> + EP.template addHandler<orcrpctpc::LoadDylib>(*this,
> &ThisT::loadDylib);
> + EP.template addHandler<orcrpctpc::LookupSymbols>(*this,
> +
> &ThisT::lookupSymbols);
> +
> + EP.template addHandler<orcrpctpc::RunMain>(*this, &ThisT::runMain);
> + EP.template addHandler<orcrpctpc::RunWrapper>(*this,
> &ThisT::runWrapper);
> +
> + EP.template addHandler<orcrpctpc::CloseConnection>(*this,
> +
> &ThisT::closeConnection);
> + }
> +
> + /// Set the ProgramName to be used as the first argv element when
> running
> + /// functions via runAsMain.
> + void setProgramName(Optional<std::string> ProgramName = None) {
> + this->ProgramName = std::move(ProgramName);
> + }
> +
> + /// Get the RPC endpoint for this server.
> + RPCEndpointT &getEndpoint() { return EP; }
> +
> + /// Run the server loop.
> + Error run() {
> + while (!Finished) {
> + if (auto Err = EP.handleOne())
> + return Err;
> + }
> + return Error::success();
> + }
> +
> +private:
> + std::string getTargetTriple() { return TripleStr; }
> + uint64_t getPageSize() { return PageSize; }
> +
> + template <typename WriteT>
> + static void handleWriteUInt(const std::vector<WriteT> &Ws) {
> + using ValueT = decltype(std::declval<WriteT>().Value);
> + for (auto &W : Ws)
> + *jitTargetAddressToPointer<ValueT *>(W.Address) = W.Value;
> + }
> +
> + std::string getProtStr(orcrpctpc::WireProtectionFlags WPF) {
> + std::string Result;
> + Result += (WPF & orcrpctpc::WPF_Read) ? 'R' : '-';
> + Result += (WPF & orcrpctpc::WPF_Write) ? 'W' : '-';
> + Result += (WPF & orcrpctpc::WPF_Exec) ? 'X' : '-';
> + return Result;
> + }
> +
> + static void handleWriteBuffer(const std::vector<tpctypes::BufferWrite>
> &Ws) {
> + for (auto &W : Ws) {
> + memcpy(jitTargetAddressToPointer<char *>(W.Address),
> W.Buffer.data(),
> + W.Buffer.size());
> + }
> + }
> +
> + Expected<orcrpctpc::ReserveMemResult>
> + reserveMemory(const orcrpctpc::ReserveMemRequest &Request) {
> + orcrpctpc::ReserveMemResult Allocs;
> + auto PF = sys::Memory::MF_READ | sys::Memory::MF_WRITE;
> +
> + uint64_t TotalSize = 0;
> +
> + for (const auto &E : Request) {
> + uint64_t Size = alignTo(E.Size, PageSize);
> + uint16_t Align = E.Alignment;
> +
> + if ((Align > PageSize) || (PageSize % Align))
> + return make_error<StringError>(
> + "Page alignmen does not satisfy requested alignment",
> + inconvertibleErrorCode());
> +
> + TotalSize += Size;
> + }
> +
> + // Allocate memory slab.
> + std::error_code EC;
> + auto MB = sys::Memory::allocateMappedMemory(TotalSize, nullptr, PF,
> EC);
> + if (EC)
> + return make_error<StringError>("Unable to allocate memory: " +
> + EC.message(),
> + inconvertibleErrorCode());
> +
> + // Zero-fill the whole thing.
> + memset(MB.base(), 0, MB.allocatedSize());
> +
> + // Carve up sections to return.
> + uint64_t SectionBase = 0;
> + for (const auto &E : Request) {
> + uint64_t SectionSize = alignTo(E.Size, PageSize);
> + Allocs.push_back({E.Prot,
> + pointerToJITTargetAddress(MB.base()) +
> SectionBase,
> + SectionSize});
> + SectionBase += SectionSize;
> + }
> +
> + return Allocs;
> + }
> +
> + Error finalizeMemory(const orcrpctpc::ReleaseOrFinalizeMemRequest &FMR)
> {
> + for (const auto &E : FMR) {
> + sys::MemoryBlock MB(jitTargetAddressToPointer<void *>(E.Address),
> E.Size);
> +
> + auto PF = orcrpctpc::fromWireProtectionFlags(E.Prot);
> + if (auto EC =
> + sys::Memory::protectMappedMemory(MB,
> static_cast<unsigned>(PF)))
> + return make_error<StringError>("error protecting memory: " +
> + EC.message(),
> + inconvertibleErrorCode());
> + }
> + return Error::success();
> + }
> +
> + Error releaseMemory(const orcrpctpc::ReleaseOrFinalizeMemRequest &RMR) {
> + for (const auto &E : RMR) {
> + sys::MemoryBlock MB(jitTargetAddressToPointer<void *>(E.Address),
> E.Size);
> +
> + if (auto EC = sys::Memory::releaseMappedMemory(MB))
> + return make_error<StringError>("error release memory: " +
> EC.message(),
> + inconvertibleErrorCode());
> + }
> + return Error::success();
> + }
> +
> + Expected<tpctypes::DylibHandle> loadDylib(const std::string &Path) {
> + std::string ErrMsg;
> + const char *DLPath = !Path.empty() ? Path.c_str() : nullptr;
> + auto DL = sys::DynamicLibrary::getPermanentLibrary(DLPath, &ErrMsg);
> + if (!DL.isValid())
> + return make_error<StringError>(std::move(ErrMsg),
> + inconvertibleErrorCode());
> +
> + tpctypes::DylibHandle H = Dylibs.size();
> + Dylibs[H] = std::move(DL);
> + return H;
> + }
> +
> + Expected<std::vector<tpctypes::LookupResult>>
> + lookupSymbols(const std::vector<orcrpctpc::RemoteLookupRequest>
> &Request) {
> + std::vector<tpctypes::LookupResult> Result;
> +
> + for (const auto &E : Request) {
> + auto I = Dylibs.find(E.first);
> + if (I == Dylibs.end())
> + return make_error<StringError>("Unrecognized handle",
> + inconvertibleErrorCode());
> + auto &DL = I->second;
> + Result.push_back({});
> +
> + for (const auto &KV : E.second) {
> + auto &SymString = KV.first;
> + bool WeakReference = KV.second;
> +
> + const char *Sym = SymString.c_str();
> +#ifdef __APPLE__
> + if (*Sym == '_')
> + ++Sym;
> +#endif
> +
> + void *Addr = DL.getAddressOfSymbol(Sym);
> + if (!Addr && !WeakReference)
> + return make_error<StringError>(Twine("Missing definition for ")
> + Sym,
> + inconvertibleErrorCode());
> +
> + Result.back().push_back(pointerToJITTargetAddress(Addr));
> + }
> + }
> +
> + return Result;
> + }
> +
> + int32_t runMain(JITTargetAddress MainFnAddr,
> + const std::vector<std::string> &Args) {
> + Optional<StringRef> ProgramNameOverride;
> + if (ProgramName)
> + ProgramNameOverride = *ProgramName;
> +
> + return runAsMain(
> + jitTargetAddressToFunction<int (*)(int, char *[])>(MainFnAddr),
> Args,
> + ProgramNameOverride);
> + }
> +
> + tpctypes::WrapperFunctionResult
> + runWrapper(JITTargetAddress WrapperFnAddr,
> + const std::vector<uint8_t> &ArgBuffer) {
> + using WrapperFnTy = tpctypes::CWrapperFunctionResult (*)(
> + const uint8_t *Data, uint64_t Size);
> + auto *WrapperFn =
> jitTargetAddressToFunction<WrapperFnTy>(WrapperFnAddr);
> + return WrapperFn(ArgBuffer.data(), ArgBuffer.size());
> + }
> +
> + void closeConnection() { Finished = true; }
> +
> + std::string TripleStr;
> + uint64_t PageSize = 0;
> + Optional<std::string> ProgramName;
> + RPCEndpointT &EP;
> + std::atomic<bool> Finished{false};
> + DenseMap<tpctypes::DylibHandle, sys::DynamicLibrary> Dylibs;
> +};
> +
> +} // end namespace orc
> +} // end namespace llvm
> +
> +#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_ORCRPCTPCSERVER_H
>
> diff --git
> a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h
> b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h
> new file mode 100644
> index 000000000000..811c50e3ce4d
> --- /dev/null
> +++
> b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h
> @@ -0,0 +1,41 @@
> +//===----- RegisterEHFrames.h -- Register EH frame sections -----*- C++
> -*-===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// Support for dynamically registering and deregistering eh-frame sections
> +// in-process via libunwind.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_REGISTEREHFRAMES_H
> +#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_REGISTEREHFRAMES_H
> +
> +#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
> +#include "llvm/Support/Error.h"
> +#include <vector>
> +
> +namespace llvm {
> +namespace orc {
> +
> +/// Register frames in the given eh-frame section with libunwind.
> +Error registerEHFrameSection(const void *EHFrameSectionAddr,
> + size_t EHFrameSectionSize);
> +
> +/// Unregister frames in the given eh-frame section with libunwind.
> +Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
> + size_t EHFrameSectionSize);
> +
> +} // end namespace orc
> +} // end namespace llvm
> +
> +extern "C" llvm::orc::tpctypes::CWrapperFunctionResult
> +llvm_orc_registerEHFrameSectionWrapper(uint8_t *Data, uint64_t Size);
> +
> +extern "C" llvm::orc::tpctypes::CWrapperFunctionResult
> +llvm_orc_deregisterEHFrameSectionWrapper(uint8_t *Data, uint64_t Size);
> +
> +#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_REGISTEREHFRAMES_H
>
> diff --git
> a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h
> b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h
> new file mode 100644
> index 000000000000..1d2f6d2be089
> --- /dev/null
> +++
> b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h
> @@ -0,0 +1,38 @@
> +//===-- TargetExecutionUtils.h - Utils for execution in target --*- C++
> -*-===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// Utilities for execution in the target process.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_TARGETEXECUTIONUTILS_H
> +#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_TARGETEXECUTIONUTILS_H
> +
> +#include "llvm/ADT/ArrayRef.h"
> +#include "llvm/ADT/Optional.h"
> +#include "llvm/ADT/StringRef.h"
> +#include <string>
> +
> +namespace llvm {
> +namespace orc {
> +
> +/// Run a main function, returning the result.
> +///
> +/// If the optional ProgramName argument is given then it will be inserted
> +/// before the strings in Args as the first argument to the called
> function.
> +///
> +/// It is legal to have an empty argument list and no program name,
> however
> +/// many main functions will expect a name argument at least, and will
> fail
> +/// if none is provided.
> +int runAsMain(int (*Main)(int, char *[]), ArrayRef<std::string> Args,
> + Optional<StringRef> ProgramName = None);
> +
> +} // end namespace orc
> +} // end namespace llvm
> +
> +#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_TARGETEXECUTIONUTILS_H
>
> diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h
> b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h
> index d3349753284e..504a5ea0f9e9 100644
> --- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h
> +++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcessControl.h
> @@ -18,6 +18,7 @@
> #include "llvm/ADT/Triple.h"
> #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
> #include "llvm/ExecutionEngine/Orc/Core.h"
> +#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
> #include "llvm/Support/DynamicLibrary.h"
> #include "llvm/Support/MSVCErrorWorkarounds.h"
>
> @@ -33,76 +34,55 @@ class TargetProcessControl {
> /// APIs for manipulating memory in the target process.
> class MemoryAccess {
> public:
> - template <typename T> struct UIntWrite {
> - UIntWrite() = default;
> - UIntWrite(JITTargetAddress Address, T Value)
> - : Address(Address), Value(Value) {}
> -
> - JITTargetAddress Address = 0;
> - T Value = 0;
> - };
> -
> - using UInt8Write = UIntWrite<uint8_t>;
> - using UInt16Write = UIntWrite<uint16_t>;
> - using UInt32Write = UIntWrite<uint32_t>;
> - using UInt64Write = UIntWrite<uint64_t>;
> -
> - struct BufferWrite {
> - BufferWrite(JITTargetAddress Address, StringRef Buffer)
> - : Address(Address), Buffer(Buffer) {}
> -
> - JITTargetAddress Address = 0;
> - StringRef Buffer;
> - };
> -
> + /// Callback function for asynchronous writes.
> using WriteResultFn = unique_function<void(Error)>;
>
> virtual ~MemoryAccess();
>
> - virtual void writeUInt8s(ArrayRef<UInt8Write> Ws,
> + virtual void writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws,
> WriteResultFn OnWriteComplete) = 0;
>
> - virtual void writeUInt16s(ArrayRef<UInt16Write> Ws,
> + virtual void writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws,
> WriteResultFn OnWriteComplete) = 0;
>
> - virtual void writeUInt32s(ArrayRef<UInt32Write> Ws,
> + virtual void writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws,
> WriteResultFn OnWriteComplete) = 0;
>
> - virtual void writeUInt64s(ArrayRef<UInt64Write> Ws,
> + virtual void writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws,
> WriteResultFn OnWriteComplete) = 0;
>
> - virtual void writeBuffers(ArrayRef<BufferWrite> Ws,
> + virtual void writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws,
> WriteResultFn OnWriteComplete) = 0;
>
> - Error writeUInt8s(ArrayRef<UInt8Write> Ws) {
> + Error writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws) {
> std::promise<MSVCPError> ResultP;
> auto ResultF = ResultP.get_future();
> writeUInt8s(Ws, [&](Error Err) { ResultP.set_value(std::move(Err));
> });
> return ResultF.get();
> }
>
> - Error writeUInt16s(ArrayRef<UInt16Write> Ws) {
> + Error writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws) {
> std::promise<MSVCPError> ResultP;
> auto ResultF = ResultP.get_future();
> writeUInt16s(Ws, [&](Error Err) {
> ResultP.set_value(std::move(Err)); });
> return ResultF.get();
> }
>
> - Error writeUInt32s(ArrayRef<UInt32Write> Ws) {
> + Error writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws) {
> std::promise<MSVCPError> ResultP;
> auto ResultF = ResultP.get_future();
> writeUInt32s(Ws, [&](Error Err) {
> ResultP.set_value(std::move(Err)); });
> return ResultF.get();
> }
>
> - Error writeUInt64s(ArrayRef<UInt64Write> Ws) {
> + Error writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws) {
> std::promise<MSVCPError> ResultP;
> auto ResultF = ResultP.get_future();
> writeUInt64s(Ws, [&](Error Err) {
> ResultP.set_value(std::move(Err)); });
> return ResultF.get();
> }
>
> - Error writeBuffers(ArrayRef<BufferWrite> Ws) {
> + Error writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws) {
> std::promise<MSVCPError> ResultP;
> auto ResultF = ResultP.get_future();
> writeBuffers(Ws, [&](Error Err) {
> ResultP.set_value(std::move(Err)); });
> @@ -110,43 +90,30 @@ class TargetProcessControl {
> }
> };
>
> - /// A handle for a library opened via loadDylib.
> - ///
> - /// Note that this handle does not necessarily represent a JITDylib: it
> may
> - /// be a regular dynamic library or shared object (e.g. one opened via a
> - /// dlopen in the target process).
> - using DylibHandle = JITTargetAddress;
> -
> - /// Request lookup within the given DylibHandle.
> - struct LookupRequestElement {
> - LookupRequestElement(DylibHandle Handle, const SymbolLookupSet
> &Symbols)
> - : Handle(Handle), Symbols(Symbols) {}
> - DylibHandle Handle;
> - const SymbolLookupSet &Symbols;
> - };
> -
> - using LookupRequest = ArrayRef<LookupRequestElement>;
> + virtual ~TargetProcessControl();
>
> - using LookupResult = std::vector<std::vector<JITTargetAddress>>;
> + /// Intern a symbol name in the SymbolStringPool.
> + SymbolStringPtr intern(StringRef SymName) { return
> SSP->intern(SymName); }
>
> - virtual ~TargetProcessControl();
> + /// Return a shared pointer to the SymbolStringPool for this instance.
> + std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return
> SSP; }
>
> /// Return the Triple for the target process.
> - const Triple &getTargetTriple() const { return TT; }
> + const Triple &getTargetTriple() const { return TargetTriple; }
>
> /// Get the page size for the target process.
> unsigned getPageSize() const { return PageSize; }
>
> - /// Return a JITLinkMemoryManager for the target process.
> - jitlink::JITLinkMemoryManager &getMemMgr() const { return *MemMgr; }
> -
> /// Return a MemoryAccess object for the target process.
> MemoryAccess &getMemoryAccess() const { return *MemAccess; }
>
> + /// Return a JITLinkMemoryManager for the target process.
> + jitlink::JITLinkMemoryManager &getMemMgr() const { return *MemMgr; }
> +
> /// Load the dynamic library at the given path and return a handle to
> it.
> /// If LibraryPath is null this function will return the global handle
> for
> /// the target process.
> - virtual Expected<DylibHandle> loadDylib(const char *DylibPath) = 0;
> + virtual Expected<tpctypes::DylibHandle> loadDylib(const char
> *DylibPath) = 0;
>
> /// Search for symbols in the target process.
> ///
> @@ -154,14 +121,37 @@ class TargetProcessControl {
> /// that correspond to the lookup order. If a required symbol is not
> /// found then this method will return an error. If a weakly referenced
> /// symbol is not found then it be assigned a '0' value in the result.
> - virtual Expected<LookupResult> lookupSymbols(LookupRequest Request) = 0;
> + /// that correspond to the lookup order.
> + virtual Expected<std::vector<tpctypes::LookupResult>>
> + lookupSymbols(ArrayRef<tpctypes::LookupRequest> Request) = 0;
> +
> + /// Run function with a main-like signature.
> + virtual Expected<int32_t> runAsMain(JITTargetAddress MainFnAddr,
> + ArrayRef<std::string> Args) = 0;
> +
> + /// Run a wrapper function with signature:
> + ///
> + /// \code{.cpp}
> + /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
> + /// \endcode{.cpp}
> + ///
> + virtual Expected<tpctypes::WrapperFunctionResult>
> + runWrapper(JITTargetAddress WrapperFnAddr, ArrayRef<uint8_t> ArgBuffer)
> = 0;
> +
> + /// Disconnect from the target process.
> + ///
> + /// This should be called after the JIT session is shut down.
> + virtual Error disconnect() = 0;
>
> protected:
> + TargetProcessControl(std::shared_ptr<SymbolStringPool> SSP)
> + : SSP(std::move(SSP)) {}
>
> - Triple TT;
> + std::shared_ptr<SymbolStringPool> SSP;
> + Triple TargetTriple;
> unsigned PageSize = 0;
> - jitlink::JITLinkMemoryManager *MemMgr = nullptr;
> MemoryAccess *MemAccess = nullptr;
> + jitlink::JITLinkMemoryManager *MemMgr = nullptr;
> };
>
> /// A TargetProcessControl implementation targeting the current process.
> @@ -169,33 +159,44 @@ class SelfTargetProcessControl : public
> TargetProcessControl,
> private
> TargetProcessControl::MemoryAccess {
> public:
> SelfTargetProcessControl(
> - Triple TT, unsigned PageSize,
> - std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr);
> + std::shared_ptr<SymbolStringPool> SSP, Triple TargetTriple,
> + unsigned PageSize, std::unique_ptr<jitlink::JITLinkMemoryManager>
> MemMgr);
>
> /// Create a SelfTargetProcessControl with the given memory manager.
> /// If no memory manager is given a jitlink::InProcessMemoryManager will
> /// be used by default.
> static Expected<std::unique_ptr<SelfTargetProcessControl>>
> - Create(std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr = nullptr);
> + Create(std::shared_ptr<SymbolStringPool> SSP,
> + std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr = nullptr);
> +
> + Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath)
> override;
> +
> + Expected<std::vector<tpctypes::LookupResult>>
> + lookupSymbols(ArrayRef<tpctypes::LookupRequest> Request) override;
> +
> + Expected<int32_t> runAsMain(JITTargetAddress MainFnAddr,
> + ArrayRef<std::string> Args) override;
>
> - Expected<DylibHandle> loadDylib(const char *DylibPath) override;
> + Expected<tpctypes::WrapperFunctionResult>
> + runWrapper(JITTargetAddress WrapperFnAddr,
> + ArrayRef<uint8_t> ArgBuffer) override;
>
> - Expected<LookupResult> lookupSymbols(LookupRequest Request) override;
> + Error disconnect() override;
>
> private:
> - void writeUInt8s(ArrayRef<UInt8Write> Ws,
> + void writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws,
> WriteResultFn OnWriteComplete) override;
>
> - void writeUInt16s(ArrayRef<UInt16Write> Ws,
> + void writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws,
> WriteResultFn OnWriteComplete) override;
>
> - void writeUInt32s(ArrayRef<UInt32Write> Ws,
> + void writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws,
> WriteResultFn OnWriteComplete) override;
>
> - void writeUInt64s(ArrayRef<UInt64Write> Ws,
> + void writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws,
> WriteResultFn OnWriteComplete) override;
>
> - void writeBuffers(ArrayRef<BufferWrite> Ws,
> + void writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws,
> WriteResultFn OnWriteComplete) override;
>
> std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;
>
> diff --git a/llvm/lib/ExecutionEngine/CMakeLists.txt
> b/llvm/lib/ExecutionEngine/CMakeLists.txt
> index 9b5dd44e079e..a13fcc784e4b 100644
> --- a/llvm/lib/ExecutionEngine/CMakeLists.txt
> +++ b/llvm/lib/ExecutionEngine/CMakeLists.txt
> @@ -21,7 +21,6 @@ endif()
> add_subdirectory(Interpreter)
> add_subdirectory(JITLink)
> add_subdirectory(MCJIT)
> -add_subdirectory(OrcError)
> add_subdirectory(Orc)
> add_subdirectory(RuntimeDyld)
>
>
> diff --git a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
> b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
> index 86836e54f20e..20c53980b512 100644
> --- a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
> +++ b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
> @@ -22,4 +22,6 @@ add_llvm_component_library(LLVMJITLink
> target_link_libraries(LLVMJITLink
> PRIVATE
> LLVMObject
> + LLVMOrcTargetProcess
> + LLVMSupport
> )
>
> diff --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
> b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
> index b94a2b36b5f1..7a89476687d2 100644
> --- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
> +++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
> @@ -11,6 +11,7 @@
>
> #include "llvm/BinaryFormat/Dwarf.h"
> #include "llvm/Config/config.h"
> +#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
> #include "llvm/Support/DynamicLibrary.h"
>
> #define DEBUG_TYPE "jitlink"
> @@ -630,142 +631,18 @@ Expected<Symbol &>
> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
> return PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false,
> false);
> }
>
> -#if defined(HAVE_REGISTER_FRAME) && defined(HAVE_DEREGISTER_FRAME) &&
> \
> - !defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
> -extern "C" void __register_frame(const void *);
> -extern "C" void __deregister_frame(const void *);
> -
> -Error registerFrameWrapper(const void *P) {
> - __register_frame(P);
> - return Error::success();
> -}
> -
> -Error deregisterFrameWrapper(const void *P) {
> - __deregister_frame(P);
> - return Error::success();
> -}
> -
> -#else
> -
> -// The building compiler does not have __(de)register_frame but
> -// it may be found at runtime in a dynamically-loaded library.
> -// For example, this happens when building LLVM with Visual C++
> -// but using the MingW runtime.
> -static Error registerFrameWrapper(const void *P) {
> - static void((*RegisterFrame)(const void *)) = 0;
> -
> - if (!RegisterFrame)
> - *(void **)&RegisterFrame =
> -
> llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame");
> -
> - if (RegisterFrame) {
> - RegisterFrame(P);
> - return Error::success();
> - }
> -
> - return make_error<JITLinkError>("could not register eh-frame: "
> - "__register_frame function not found");
> -}
> -
> -static Error deregisterFrameWrapper(const void *P) {
> - static void((*DeregisterFrame)(const void *)) = 0;
> -
> - if (!DeregisterFrame)
> - *(void **)&DeregisterFrame =
> - llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
> - "__deregister_frame");
> -
> - if (DeregisterFrame) {
> - DeregisterFrame(P);
> - return Error::success();
> - }
> -
> - return make_error<JITLinkError>("could not deregister eh-frame: "
> - "__deregister_frame function not
> found");
> -}
> -#endif
> -
> -#ifdef __APPLE__
> -
> -template <typename HandleFDEFn>
> -Error walkAppleEHFrameSection(const char *const SectionStart,
> - size_t SectionSize,
> - HandleFDEFn HandleFDE) {
> - const char *CurCFIRecord = SectionStart;
> - const char *End = SectionStart + SectionSize;
> - uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
> -
> - while (CurCFIRecord != End && Size != 0) {
> - const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 :
> 4);
> - if (Size == 0xffffffff)
> - Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
> - else
> - Size += 4;
> - uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
> -
> - LLVM_DEBUG({
> - dbgs() << "Registering eh-frame section:\n";
> - dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @"
> - << (void *)CurCFIRecord << ": [";
> - for (unsigned I = 0; I < Size; ++I)
> - dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I));
> - dbgs() << " ]\n";
> - });
> -
> - if (Offset != 0)
> - if (auto Err = HandleFDE(CurCFIRecord))
> - return Err;
> -
> - CurCFIRecord += Size;
> -
> - Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
> - }
> -
> - return Error::success();
> -}
> -
> -#endif // __APPLE__
> -
> -Error registerEHFrameSection(const void *EHFrameSectionAddr,
> - size_t EHFrameSectionSize) {
> -#ifdef __APPLE__
> - // On Darwin __register_frame has to be called for each FDE entry.
> - return walkAppleEHFrameSection(static_cast<const char
> *>(EHFrameSectionAddr),
> - EHFrameSectionSize,
> - registerFrameWrapper);
> -#else
> - // On Linux __register_frame takes a single argument:
> - // a pointer to the start of the .eh_frame section.
> -
> - // How can it find the end? Because crtendS.o is linked
> - // in and it has an .eh_frame section with four zero chars.
> - return registerFrameWrapper(EHFrameSectionAddr);
> -#endif
> -}
> -
> -Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
> - size_t EHFrameSectionSize) {
> -#ifdef __APPLE__
> - return walkAppleEHFrameSection(static_cast<const char
> *>(EHFrameSectionAddr),
> - EHFrameSectionSize,
> - deregisterFrameWrapper);
> -#else
> - return deregisterFrameWrapper(EHFrameSectionAddr);
> -#endif
> -}
> -
> EHFrameRegistrar::~EHFrameRegistrar() {}
>
> Error InProcessEHFrameRegistrar::registerEHFrames(
> JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) {
> - return registerEHFrameSection(
> + return orc::registerEHFrameSection(
> jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
> EHFrameSectionSize);
> }
>
> Error InProcessEHFrameRegistrar::deregisterEHFrames(
> JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) {
> - return deregisterEHFrameSection(
> + return orc::deregisterEHFrameSection(
> jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
> EHFrameSectionSize);
> }
>
> diff --git a/llvm/lib/ExecutionEngine/JITLink/LLVMBuild.txt
> b/llvm/lib/ExecutionEngine/JITLink/LLVMBuild.txt
> index e7721a184b98..f73246beb224 100644
> --- a/llvm/lib/ExecutionEngine/JITLink/LLVMBuild.txt
> +++ b/llvm/lib/ExecutionEngine/JITLink/LLVMBuild.txt
> @@ -18,4 +18,4 @@
> type = Library
> name = JITLink
> parent = ExecutionEngine
> -required_libraries = BinaryFormat Object Support
> +required_libraries = BinaryFormat Object OrcTargetProcess Support
>
> diff --git a/llvm/lib/ExecutionEngine/LLVMBuild.txt
> b/llvm/lib/ExecutionEngine/LLVMBuild.txt
> index 9bc6775f78a0..13872da4a564 100644
> --- a/llvm/lib/ExecutionEngine/LLVMBuild.txt
> +++ b/llvm/lib/ExecutionEngine/LLVMBuild.txt
> @@ -16,7 +16,7 @@
>
> [common]
> subdirectories = Interpreter MCJIT JITLink RuntimeDyld IntelJITEvents
> - OProfileJIT Orc OrcError PerfJITEvents
> + OProfileJIT Orc PerfJITEvents
>
> [component_0]
> type = Library
>
> diff --git a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
> b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
> index 6396fb5d1187..2ab410dbf578 100644
> --- a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
> +++ b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
> @@ -23,6 +23,7 @@ add_llvm_component_library(LLVMOrcJIT
> TargetProcessControl.cpp
> ThreadSafeModule.cpp
> TPCDynamicLibrarySearchGenerator.cpp
> + TPCEHFrameRegistrar.cpp
> TPCIndirectionUtils.cpp
> ADDITIONAL_HEADER_DIRS
> ${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
> @@ -31,6 +32,9 @@ add_llvm_component_library(LLVMOrcJIT
> intrinsics_gen
> )
>
> +add_subdirectory(Shared)
> +add_subdirectory(TargetProcess)
> +
> target_link_libraries(LLVMOrcJIT
> PRIVATE
> LLVMAnalysis
>
> diff --git a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
> b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
> index 5f9faf693c82..6a1a41a13a1b 100644
> --- a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
> +++ b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp
> @@ -21,32 +21,6 @@
> namespace llvm {
> namespace orc {
>
> -int runAsMain(int (*Main)(int, char *[]), ArrayRef<std::string> Args,
> - Optional<StringRef> ProgramName) {
> - std::vector<std::unique_ptr<char[]>> ArgVStorage;
> - std::vector<char *> ArgV;
> -
> - ArgVStorage.reserve(Args.size() + (ProgramName ? 1 : 0));
> - ArgV.reserve(Args.size() + 1 + (ProgramName ? 1 : 0));
> -
> - if (ProgramName) {
> - ArgVStorage.push_back(std::make_unique<char[]>(ProgramName->size() +
> 1));
> - llvm::copy(*ProgramName, &ArgVStorage.back()[0]);
> - ArgVStorage.back()[ProgramName->size()] = '\0';
> - ArgV.push_back(ArgVStorage.back().get());
> - }
> -
> - for (auto &Arg : Args) {
> - ArgVStorage.push_back(std::make_unique<char[]>(Arg.size() + 1));
> - llvm::copy(Arg, &ArgVStorage.back()[0]);
> - ArgVStorage.back()[Arg.size()] = '\0';
> - ArgV.push_back(ArgVStorage.back().get());
> - }
> - ArgV.push_back(nullptr);
> -
> - return Main(Args.size() + !!ProgramName, ArgV.data());
> -}
> -
> CtorDtorIterator::CtorDtorIterator(const GlobalVariable *GV, bool End)
> : InitList(
> GV ? dyn_cast_or_null<ConstantArray>(GV->getInitializer()) :
> nullptr),
>
> diff --git a/llvm/lib/ExecutionEngine/Orc/LLVMBuild.txt
> b/llvm/lib/ExecutionEngine/Orc/LLVMBuild.txt
> index 4a78243551ca..5d580d8fb40d 100644
> --- a/llvm/lib/ExecutionEngine/Orc/LLVMBuild.txt
> +++ b/llvm/lib/ExecutionEngine/Orc/LLVMBuild.txt
> @@ -14,9 +14,12 @@
> ;
>
> ;===------------------------------------------------------------------------===;
>
> +[common]
> +subdirectories = Shared TargetProcess
> +
> [component_0]
> type = Library
> name = OrcJIT
> parent = ExecutionEngine
> -required_libraries = Core ExecutionEngine JITLink Object OrcError MC
> Passes
> +required_libraries = Core ExecutionEngine JITLink Object OrcShared MC
> Passes
> RuntimeDyld Support Target TransformUtils
>
> diff --git a/llvm/lib/ExecutionEngine/OrcError/CMakeLists.txt
> b/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
> similarity index 60%
> rename from llvm/lib/ExecutionEngine/OrcError/CMakeLists.txt
> rename to llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
> index bd968d55e670..57c06d739ec7 100644
> --- a/llvm/lib/ExecutionEngine/OrcError/CMakeLists.txt
> +++ b/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
> @@ -1,6 +1,7 @@
> -add_llvm_component_library(LLVMOrcError
> +add_llvm_component_library(LLVMOrcShared
> OrcError.cpp
> RPCError.cpp
> + TargetProcessControlTypes.cpp
> ADDITIONAL_HEADER_DIRS
> ${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
> )
>
> diff --git a/llvm/lib/ExecutionEngine/OrcError/LLVMBuild.txt
> b/llvm/lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt
> similarity index 83%
> rename from llvm/lib/ExecutionEngine/OrcError/LLVMBuild.txt
> rename to llvm/lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt
> index 65e7916916f3..68f2ab08c9ca 100644
> --- a/llvm/lib/ExecutionEngine/OrcError/LLVMBuild.txt
> +++ b/llvm/lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt
> @@ -1,4 +1,4 @@
> -;===- ./lib/ExecutionEngine/OrcError/LLVMBuild.txt -------------*- Conf
> -*--===;
> +;===- ./lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt ------------*- Conf
> -*--===;
> ;
> ; Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> ; See https://llvm.org/LICENSE.txt for license information.
> @@ -16,6 +16,6 @@
>
> [component_0]
> type = Library
> -name = OrcError
> -parent = ExecutionEngine
> +name = OrcShared
> +parent = OrcJIT
> required_libraries = Support
>
> diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt.rej
> b/llvm/lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt.rej
> new file mode 100644
> index 000000000000..49d4038c2bf5
> --- /dev/null
> +++ b/llvm/lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt.rej
> @@ -0,0 +1,27 @@
> +***************
> +*** 1,4 ****
> +- ;===- ./lib/ExecutionEngine/OrcError/LLVMBuild.txt -------------*- Conf
> -*--===;
> + ;
> + ; Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> + ; See https://llvm.org/LICENSE.txt for license information.
> +--- 1,4 ----
> ++ ;===- ./tools/llvm-jitlink/llvm-jitlink-executor/LLVMBuild.txt -*- Conf
> -*--===;
> + ;
> + ; Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> + ; See https://llvm.org/LICENSE.txt for license information.
> +***************
> +*** 15,21 ****
> +
> ;===------------------------------------------------------------------------===;
> +
> + [component_0]
> +- type = Library
> +- name = OrcError
> +- parent = ExecutionEngine
> +- required_libraries = Support
> +--- 15,20 ----
> +
> ;===------------------------------------------------------------------------===;
> +
> + [component_0]
> ++ type = Tool
> ++ name = llvm-jitlink-executor
> ++ parent = llvm-jitlink
>
> diff --git a/llvm/lib/ExecutionEngine/OrcError/OrcError.cpp
> b/llvm/lib/ExecutionEngine/Orc/Shared/OrcError.cpp
> similarity index 96%
> rename from llvm/lib/ExecutionEngine/OrcError/OrcError.cpp
> rename to llvm/lib/ExecutionEngine/Orc/Shared/OrcError.cpp
> index cc99e154fbec..9b1c028d7047 100644
> --- a/llvm/lib/ExecutionEngine/OrcError/OrcError.cpp
> +++ b/llvm/lib/ExecutionEngine/Orc/Shared/OrcError.cpp
> @@ -71,7 +71,7 @@ class OrcErrorCategory : public std::error_category {
> };
>
> static ManagedStatic<OrcErrorCategory> OrcErrCat;
> -}
> +} // namespace
>
> namespace llvm {
> namespace orc {
> @@ -84,9 +84,8 @@ std::error_code orcError(OrcErrorCode ErrCode) {
> return std::error_code(static_cast<UT>(ErrCode), *OrcErrCat);
> }
>
> -
> DuplicateDefinition::DuplicateDefinition(std::string SymbolName)
> - : SymbolName(std::move(SymbolName)) {}
> + : SymbolName(std::move(SymbolName)) {}
>
> std::error_code DuplicateDefinition::convertToErrorCode() const {
> return orcError(OrcErrorCode::DuplicateDefinition);
> @@ -101,7 +100,7 @@ const std::string
> &DuplicateDefinition::getSymbolName() const {
> }
>
> JITSymbolNotFound::JITSymbolNotFound(std::string SymbolName)
> - : SymbolName(std::move(SymbolName)) {}
> + : SymbolName(std::move(SymbolName)) {}
>
> std::error_code JITSymbolNotFound::convertToErrorCode() const {
> typedef std::underlying_type<OrcErrorCode>::type UT;
> @@ -117,5 +116,5 @@ const std::string &JITSymbolNotFound::getSymbolName()
> const {
> return SymbolName;
> }
>
> -}
> -}
> +} // namespace orc
> +} // namespace llvm
>
> diff --git a/llvm/lib/ExecutionEngine/OrcError/RPCError.cpp
> b/llvm/lib/ExecutionEngine/Orc/Shared/RPCError.cpp
> similarity index 99%
> rename from llvm/lib/ExecutionEngine/OrcError/RPCError.cpp
> rename to llvm/lib/ExecutionEngine/Orc/Shared/RPCError.cpp
> index 3cf78fd9f7ba..a13db4863953 100644
> --- a/llvm/lib/ExecutionEngine/OrcError/RPCError.cpp
> +++ b/llvm/lib/ExecutionEngine/Orc/Shared/RPCError.cpp
> @@ -14,8 +14,8 @@
> #include "llvm/Support/Error.h"
> #include "llvm/Support/raw_ostream.h"
>
> -#include <system_error>
> #include <string>
> +#include <system_error>
>
> char llvm::orc::rpc::RPCFatalError::ID = 0;
> char llvm::orc::rpc::ConnectionClosed::ID = 0;
> @@ -53,7 +53,6 @@ void CouldNotNegotiate::log(raw_ostream &OS) const {
> OS << "Could not negotiate RPC function " << Signature;
> }
>
> -
> } // end namespace rpc
> } // end namespace orc
> } // end namespace llvm
>
> diff --git
> a/llvm/lib/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.cpp
> b/llvm/lib/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.cpp
> new file mode 100644
> index 000000000000..0b77eac8b4a6
> --- /dev/null
> +++ b/llvm/lib/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.cpp
> @@ -0,0 +1,43 @@
> +//===---------- TargetProcessControlTypes.cpp - Shared TPC types
> ----------===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// TargetProcessControl types.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
> +
> +namespace llvm {
> +namespace orc {
> +namespace tpctypes {
> +
> +WrapperFunctionResult WrapperFunctionResult::from(StringRef S) {
> + CWrapperFunctionResult R = {0, {.ValuePtr = nullptr}, nullptr};
> + R.Size = S.size();
> + if (R.Size > sizeof(uint64_t)) {
> + R.Data.ValuePtr = new uint8_t[R.Size];
> + memcpy(R.Data.ValuePtr, S.data(), R.Size);
> + R.Destroy = destroyWithDeleteArray;
> + } else
> + memcpy(R.Data.Value, S.data(), R.Size);
> + return R;
> +}
> +
> +void WrapperFunctionResult::destroyWithFree(CWrapperFunctionResultData
> Data,
> + uint64_t Size) {
> + free(Data.ValuePtr);
> +}
> +
> +void WrapperFunctionResult::destroyWithDeleteArray(
> + CWrapperFunctionResultData Data, uint64_t Size) {
> + delete[] Data.ValuePtr;
> +}
> +
> +} // end namespace tpctypes
> +} // end namespace orc
> +} // end namespace llvm
>
> diff --git
> a/llvm/lib/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.cpp
> b/llvm/lib/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.cpp
> index ab58641b3478..f275c634a6d5 100644
> --- a/llvm/lib/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.cpp
> +++ b/llvm/lib/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.cpp
> @@ -41,7 +41,7 @@ Error TPCDynamicLibrarySearchGenerator::tryToGenerate(
>
> SymbolMap NewSymbols;
>
> - TargetProcessControl::LookupRequestElement Request(H, LookupSymbols);
> + tpctypes::LookupRequest Request(H, LookupSymbols);
> auto Result = TPC.lookupSymbols(Request);
> if (!Result)
> return Result.takeError();
>
> diff --git a/llvm/lib/ExecutionEngine/Orc/TPCEHFrameRegistrar.cpp
> b/llvm/lib/ExecutionEngine/Orc/TPCEHFrameRegistrar.cpp
> new file mode 100644
> index 000000000000..4f901ce6d445
> --- /dev/null
> +++ b/llvm/lib/ExecutionEngine/Orc/TPCEHFrameRegistrar.cpp
> @@ -0,0 +1,80 @@
> +//===------ TPCEHFrameRegistrar.cpp - TPC-based eh-frame registration
> -----===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/ExecutionEngine/Orc/TPCEHFrameRegistrar.h"
> +#include "llvm/Support/BinaryStreamWriter.h"
> +
> +namespace llvm {
> +namespace orc {
> +
> +Expected<std::unique_ptr<TPCEHFrameRegistrar>>
> +TPCEHFrameRegistrar::Create(TargetProcessControl &TPC) {
> + // FIXME: Proper mangling here -- we really need to decouple linker
> mangling
> + // from DataLayout.
> +
> + // Find the addresses of the registration/deregistration functions in
> the
> + // target process.
> + auto ProcessHandle = TPC.loadDylib(nullptr);
> + if (!ProcessHandle)
> + return ProcessHandle.takeError();
> +
> + std::string RegisterWrapperName, DeregisterWrapperName;
> + if (TPC.getTargetTriple().isOSBinFormatMachO()) {
> + RegisterWrapperName += '_';
> + DeregisterWrapperName += '_';
> + }
> + RegisterWrapperName += "llvm_orc_registerEHFrameSectionWrapper";
> + DeregisterWrapperName += "llvm_orc_deregisterEHFrameSectionWrapper";
> +
> + SymbolLookupSet RegistrationSymbols;
> + RegistrationSymbols.add(TPC.intern(RegisterWrapperName));
> + RegistrationSymbols.add(TPC.intern(DeregisterWrapperName));
> +
> + auto Result = TPC.lookupSymbols({{*ProcessHandle,
> RegistrationSymbols}});
> + if (!Result)
> + return Result.takeError();
> +
> + assert(Result->size() == 1 && "Unexpected number of dylibs in result");
> + assert((*Result)[0].size() == 2 &&
> + "Unexpected number of addresses in result");
> +
> + auto RegisterEHFrameWrapperFnAddr = (*Result)[0][0];
> + auto DeregisterEHFrameWrapperFnAddr = (*Result)[0][1];
> +
> + return std::make_unique<TPCEHFrameRegistrar>(
> + TPC, RegisterEHFrameWrapperFnAddr, DeregisterEHFrameWrapperFnAddr);
> +}
> +
> +Error TPCEHFrameRegistrar::registerEHFrames(JITTargetAddress
> EHFrameSectionAddr,
> + size_t EHFrameSectionSize) {
> + constexpr size_t ArgBufferSize = sizeof(uint64_t) + sizeof(uint64_t);
> + uint8_t ArgBuffer[ArgBufferSize];
> + BinaryStreamWriter ArgWriter(
> + MutableArrayRef<uint8_t>(ArgBuffer, ArgBufferSize),
> + support::endianness::big);
> +
> cantFail(ArgWriter.writeInteger(static_cast<uint64_t>(EHFrameSectionAddr)));
> +
> cantFail(ArgWriter.writeInteger(static_cast<uint64_t>(EHFrameSectionSize)));
> +
> + return TPC.runWrapper(RegisterEHFrameWrapperFnAddr,
> ArgBuffer).takeError();
> +}
> +
> +Error TPCEHFrameRegistrar::deregisterEHFrames(
> + JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) {
> + constexpr size_t ArgBufferSize = sizeof(uint64_t) + sizeof(uint64_t);
> + uint8_t ArgBuffer[ArgBufferSize];
> + BinaryStreamWriter ArgWriter(
> + MutableArrayRef<uint8_t>(ArgBuffer, ArgBufferSize),
> + support::endianness::big);
> +
> cantFail(ArgWriter.writeInteger(static_cast<uint64_t>(EHFrameSectionAddr)));
> +
> cantFail(ArgWriter.writeInteger(static_cast<uint64_t>(EHFrameSectionSize)));
> +
> + return TPC.runWrapper(DeregisterEHFrameWrapperFnAddr,
> ArgBuffer).takeError();
> +}
> +
> +} // end namespace orc
> +} // end namespace llvm
>
> diff --git a/llvm/lib/ExecutionEngine/Orc/TPCIndirectionUtils.cpp
> b/llvm/lib/ExecutionEngine/Orc/TPCIndirectionUtils.cpp
> index de13f064189a..d827cf7b273b 100644
> --- a/llvm/lib/ExecutionEngine/Orc/TPCIndirectionUtils.cpp
> +++ b/llvm/lib/ExecutionEngine/Orc/TPCIndirectionUtils.cpp
> @@ -160,7 +160,7 @@ Error TPCIndirectStubsManager::createStubs(const
> StubInitsMap &StubInits) {
> switch (TPCIU.getABISupport().getPointerSize()) {
> case 4: {
> unsigned ASIdx = 0;
> - std::vector<TargetProcessControl::MemoryAccess::UInt32Write>
> PtrUpdates;
> + std::vector<tpctypes::UInt32Write> PtrUpdates;
> for (auto &SI : StubInits)
> PtrUpdates.push_back({(*AvailableStubInfos)[ASIdx++].PointerAddress,
> static_cast<uint32_t>(SI.second.first)});
> @@ -168,7 +168,7 @@ Error TPCIndirectStubsManager::createStubs(const
> StubInitsMap &StubInits) {
> }
> case 8: {
> unsigned ASIdx = 0;
> - std::vector<TargetProcessControl::MemoryAccess::UInt64Write>
> PtrUpdates;
> + std::vector<tpctypes::UInt64Write> PtrUpdates;
> for (auto &SI : StubInits)
> PtrUpdates.push_back({(*AvailableStubInfos)[ASIdx++].PointerAddress,
> static_cast<uint64_t>(SI.second.first)});
> @@ -213,11 +213,11 @@ Error
> TPCIndirectStubsManager::updatePointer(StringRef Name,
> auto &MemAccess = TPCIU.getTargetProcessControl().getMemoryAccess();
> switch (TPCIU.getABISupport().getPointerSize()) {
> case 4: {
> - TargetProcessControl::MemoryAccess::UInt32Write PUpdate(PtrAddr,
> NewAddr);
> + tpctypes::UInt32Write PUpdate(PtrAddr, NewAddr);
> return MemAccess.writeUInt32s(PUpdate);
> }
> case 8: {
> - TargetProcessControl::MemoryAccess::UInt64Write PUpdate(PtrAddr,
> NewAddr);
> + tpctypes::UInt64Write PUpdate(PtrAddr, NewAddr);
> return MemAccess.writeUInt64s(PUpdate);
> }
> default:
>
> diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
> b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
> new file mode 100644
> index 000000000000..b561ce232ce4
> --- /dev/null
> +++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
> @@ -0,0 +1,6 @@
> +add_llvm_component_library(LLVMOrcTargetProcess
> + RegisterEHFrames.cpp
> + TargetExecutionUtils.cpp
> + ADDITIONAL_HEADER_DIRS
> + ${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
> + )
>
> diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LLVMBuild.txt
> b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LLVMBuild.txt
> new file mode 100644
> index 000000000000..781e6188a702
> --- /dev/null
> +++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LLVMBuild.txt
> @@ -0,0 +1,21 @@
> +;===- ./lib/ExecutionEngine/OrcTargetProcess/LLVMBuild.txt -----*- Conf
> -*--===;
> +;
> +; Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> +; See https://llvm.org/LICENSE.txt for license information.
> +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +;
>
> +;===------------------------------------------------------------------------===;
> +;
> +; This is an LLVMBuild description file for the components in this
> subdirectory.
> +;
> +; For more information on the LLVMBuild system, please see:
> +;
> +; http://llvm.org/docs/LLVMBuild.html
> +;
>
> +;===------------------------------------------------------------------------===;
> +
> +[component_0]
> +type = Library
> +name = OrcTargetProcess
> +parent = OrcJIT
> +required_libraries = OrcShared Support
>
> diff --git
> a/llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp
> b/llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp
> new file mode 100644
> index 000000000000..e32916dfcd96
> --- /dev/null
> +++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp
> @@ -0,0 +1,207 @@
> +//===--------- RegisterEHFrames.cpp - Register EH frame sections
> ----------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
> +
> +#include "llvm/ExecutionEngine/JITSymbol.h"
> +#include "llvm/Support/BinaryStreamReader.h"
> +#include "llvm/Support/Compiler.h"
> +#include "llvm/Support/Debug.h"
> +#include "llvm/Support/DynamicLibrary.h"
> +#include "llvm/Support/raw_ostream.h"
> +
> +#include "llvm/Support/FormatVariadic.h"
> +
> +#define DEBUG_TYPE "orc"
> +
> +using namespace llvm;
> +using namespace llvm::orc;
> +using namespace llvm::orc::tpctypes;
> +
> +namespace llvm {
> +namespace orc {
> +
> +#if defined(HAVE_REGISTER_FRAME) && defined(HAVE_DEREGISTER_FRAME) &&
> \
> + !defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
> +
> +extern "C" void __register_frame(const void *);
> +extern "C" void __deregister_frame(const void *);
> +
> +Error registerFrameWrapper(const void *P) {
> + __register_frame(P);
> + return Error::success();
> +}
> +
> +Error deregisterFrameWrapper(const void *P) {
> + __deregister_frame(P);
> + return Error::success();
> +}
> +
> +#else
> +
> +// The building compiler does not have __(de)register_frame but
> +// it may be found at runtime in a dynamically-loaded library.
> +// For example, this happens when building LLVM with Visual C++
> +// but using the MingW runtime.
> +static Error registerFrameWrapper(const void *P) {
> + static void((*RegisterFrame)(const void *)) = 0;
> +
> + if (!RegisterFrame)
> + *(void **)&RegisterFrame =
> +
> llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame");
> +
> + if (RegisterFrame) {
> + RegisterFrame(P);
> + return Error::success();
> + }
> +
> + return make_error<StringError>("could not register eh-frame: "
> + "__register_frame function not found",
> + inconvertibleErrorCode());
> +}
> +
> +static Error deregisterFrameWrapper(const void *P) {
> + static void((*DeregisterFrame)(const void *)) = 0;
> +
> + if (!DeregisterFrame)
> + *(void **)&DeregisterFrame =
> + llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
> + "__deregister_frame");
> +
> + if (DeregisterFrame) {
> + DeregisterFrame(P);
> + return Error::success();
> + }
> +
> + return make_error<StringError>("could not deregister eh-frame: "
> + "__deregister_frame function not found",
> + inconvertibleErrorCode());
> +}
> +#endif
> +
> +#ifdef __APPLE__
> +
> +template <typename HandleFDEFn>
> +Error walkAppleEHFrameSection(const char *const SectionStart,
> + size_t SectionSize, HandleFDEFn HandleFDE) {
> + const char *CurCFIRecord = SectionStart;
> + const char *End = SectionStart + SectionSize;
> + uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
> +
> + while (CurCFIRecord != End && Size != 0) {
> + const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 :
> 4);
> + if (Size == 0xffffffff)
> + Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
> + else
> + Size += 4;
> + uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
> +
> + LLVM_DEBUG({
> + dbgs() << "Registering eh-frame section:\n";
> + dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @"
> + << (void *)CurCFIRecord << ": [";
> + for (unsigned I = 0; I < Size; ++I)
> + dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I));
> + dbgs() << " ]\n";
> + });
> +
> + if (Offset != 0)
> + if (auto Err = HandleFDE(CurCFIRecord))
> + return Err;
> +
> + CurCFIRecord += Size;
> +
> + Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
> + }
> +
> + return Error::success();
> +}
> +
> +#endif // __APPLE__
> +
> +Error registerEHFrameSection(const void *EHFrameSectionAddr,
> + size_t EHFrameSectionSize) {
> +#ifdef __APPLE__
> + // On Darwin __register_frame has to be called for each FDE entry.
> + return walkAppleEHFrameSection(static_cast<const char
> *>(EHFrameSectionAddr),
> + EHFrameSectionSize,
> registerFrameWrapper);
> +#else
> + // On Linux __register_frame takes a single argument:
> + // a pointer to the start of the .eh_frame section.
> +
> + // How can it find the end? Because crtendS.o is linked
> + // in and it has an .eh_frame section with four zero chars.
> + return registerFrameWrapper(EHFrameSectionAddr);
> +#endif
> +}
> +
> +Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
> + size_t EHFrameSectionSize) {
> +#ifdef __APPLE__
> + return walkAppleEHFrameSection(static_cast<const char
> *>(EHFrameSectionAddr),
> + EHFrameSectionSize,
> deregisterFrameWrapper);
> +#else
> + return deregisterFrameWrapper(EHFrameSectionAddr);
> +#endif
> +}
> +
> +} // end namespace orc
> +} // end namespace llvm
> +
> +extern "C" CWrapperFunctionResult
> +llvm_orc_registerEHFrameSectionWrapper(uint8_t *Data, uint64_t Size) {
> + if (Size != sizeof(uint64_t) + sizeof(uint64_t))
> + return WrapperFunctionResult::from(
> + "Invalid arguments to
> llvm_orc_registerEHFrameSectionWrapper")
> + .release();
> +
> + uint64_t EHFrameSectionAddr;
> + uint64_t EHFrameSectionSize;
> +
> + {
> + BinaryStreamReader ArgReader(ArrayRef<uint8_t>(Data, Size),
> + support::endianness::big);
> + cantFail(ArgReader.readInteger(EHFrameSectionAddr));
> + cantFail(ArgReader.readInteger(EHFrameSectionSize));
> + }
> +
> + if (auto Err = registerEHFrameSection(
> + jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
> + EHFrameSectionSize)) {
> + auto ErrMsg = toString(std::move(Err));
> + return WrapperFunctionResult::from(ErrMsg).release();
> + }
> + return WrapperFunctionResult().release();
> +}
> +
> +extern "C" CWrapperFunctionResult
> +llvm_orc_deregisterEHFrameSectionWrapper(uint8_t *Data, uint64_t Size) {
> + if (Size != sizeof(uint64_t) + sizeof(uint64_t))
> + return WrapperFunctionResult::from(
> + "Invalid arguments to
> llvm_orc_registerEHFrameSectionWrapper")
> + .release();
> +
> + uint64_t EHFrameSectionAddr;
> + uint64_t EHFrameSectionSize;
> +
> + {
> + BinaryStreamReader ArgReader(ArrayRef<uint8_t>(Data, Size),
> + support::endianness::big);
> + cantFail(ArgReader.readInteger(EHFrameSectionAddr));
> + cantFail(ArgReader.readInteger(EHFrameSectionSize));
> + }
> +
> + if (auto Err = deregisterEHFrameSection(
> + jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
> + EHFrameSectionSize)) {
> + auto ErrMsg = toString(std::move(Err));
> + return WrapperFunctionResult::from(ErrMsg).release();
> + }
> + return WrapperFunctionResult().release();
> +}
>
> diff --git
> a/llvm/lib/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.cpp
> b/llvm/lib/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.cpp
> new file mode 100644
> index 000000000000..a8e6c049cf4b
> --- /dev/null
> +++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.cpp
> @@ -0,0 +1,43 @@
> +//===--- TargetExecutionUtils.cpp - Execution utils for target processes
> --===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h"
> +
> +#include <vector>
> +
> +namespace llvm {
> +namespace orc {
> +
> +int runAsMain(int (*Main)(int, char *[]), ArrayRef<std::string> Args,
> + Optional<StringRef> ProgramName) {
> + std::vector<std::unique_ptr<char[]>> ArgVStorage;
> + std::vector<char *> ArgV;
> +
> + ArgVStorage.reserve(Args.size() + (ProgramName ? 1 : 0));
> + ArgV.reserve(Args.size() + 1 + (ProgramName ? 1 : 0));
> +
> + if (ProgramName) {
> + ArgVStorage.push_back(std::make_unique<char[]>(ProgramName->size() +
> 1));
> + llvm::copy(*ProgramName, &ArgVStorage.back()[0]);
> + ArgVStorage.back()[ProgramName->size()] = '\0';
> + ArgV.push_back(ArgVStorage.back().get());
> + }
> +
> + for (const auto &Arg : Args) {
> + ArgVStorage.push_back(std::make_unique<char[]>(Arg.size() + 1));
> + llvm::copy(Arg, &ArgVStorage.back()[0]);
> + ArgVStorage.back()[Arg.size()] = '\0';
> + ArgV.push_back(ArgVStorage.back().get());
> + }
> + ArgV.push_back(nullptr);
> +
> + return Main(Args.size() + !!ProgramName, ArgV.data());
> +}
> +
> +} // End namespace orc.
> +} // End namespace llvm.
>
> diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp
> b/llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp
> index 1e7736d1f40d..bbbc2d60d936 100644
> --- a/llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp
> +++ b/llvm/lib/ExecutionEngine/Orc/TargetProcessControl.cpp
> @@ -9,6 +9,7 @@
> #include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
>
> #include "llvm/ExecutionEngine/Orc/Core.h"
> +#include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h"
> #include "llvm/Support/Host.h"
> #include "llvm/Support/Process.h"
>
> @@ -22,23 +23,25 @@ TargetProcessControl::MemoryAccess::~MemoryAccess() {}
> TargetProcessControl::~TargetProcessControl() {}
>
> SelfTargetProcessControl::SelfTargetProcessControl(
> - Triple TT, unsigned PageSize,
> - std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) {
> + std::shared_ptr<SymbolStringPool> SSP, Triple TargetTriple,
> + unsigned PageSize, std::unique_ptr<jitlink::JITLinkMemoryManager>
> MemMgr)
> + : TargetProcessControl(std::move(SSP)) {
>
> OwnedMemMgr = std::move(MemMgr);
> if (!OwnedMemMgr)
> OwnedMemMgr = std::make_unique<jitlink::InProcessMemoryManager>();
>
> - this->TT = std::move(TT);
> + this->TargetTriple = std::move(TargetTriple);
> this->PageSize = PageSize;
> this->MemMgr = OwnedMemMgr.get();
> this->MemAccess = this;
> - if (this->TT.isOSBinFormatMachO())
> + if (this->TargetTriple.isOSBinFormatMachO())
> GlobalManglingPrefix = '_';
> }
>
> Expected<std::unique_ptr<SelfTargetProcessControl>>
> SelfTargetProcessControl::Create(
> + std::shared_ptr<SymbolStringPool> SSP,
> std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) {
> auto PageSize = sys::Process::getPageSize();
> if (!PageSize)
> @@ -46,11 +49,11 @@ SelfTargetProcessControl::Create(
>
> Triple TT(sys::getProcessTriple());
>
> - return std::make_unique<SelfTargetProcessControl>(std::move(TT),
> *PageSize,
> - std::move(MemMgr));
> + return std::make_unique<SelfTargetProcessControl>(
> + std::move(SSP), std::move(TT), *PageSize, std::move(MemMgr));
> }
>
> -Expected<TargetProcessControl::DylibHandle>
> +Expected<tpctypes::DylibHandle>
> SelfTargetProcessControl::loadDylib(const char *DylibPath) {
> std::string ErrMsg;
> auto Dylib = std::make_unique<sys::DynamicLibrary>(
> @@ -61,9 +64,10 @@ SelfTargetProcessControl::loadDylib(const char
> *DylibPath) {
> return pointerToJITTargetAddress(DynamicLibraries.back().get());
> }
>
> -Expected<TargetProcessControl::LookupResult>
> -SelfTargetProcessControl::lookupSymbols(LookupRequest Request) {
> - LookupResult R;
> +Expected<std::vector<tpctypes::LookupResult>>
> +SelfTargetProcessControl::lookupSymbols(
> + ArrayRef<tpctypes::LookupRequest> Request) {
> + std::vector<tpctypes::LookupResult> R;
>
> for (auto &Elem : Request) {
> auto *Dylib = jitTargetAddressToPointer<sys::DynamicLibrary
> *>(Elem.Handle);
> @@ -92,35 +96,53 @@ SelfTargetProcessControl::lookupSymbols(LookupRequest
> Request) {
> return R;
> }
>
> -void SelfTargetProcessControl::writeUInt8s(ArrayRef<UInt8Write> Ws,
> +Expected<int32_t>
> +SelfTargetProcessControl::runAsMain(JITTargetAddress MainFnAddr,
> + ArrayRef<std::string> Args) {
> + using MainTy = int (*)(int, char *[]);
> + return orc::runAsMain(jitTargetAddressToFunction<MainTy>(MainFnAddr),
> Args);
> +}
> +
> +Expected<tpctypes::WrapperFunctionResult>
> +SelfTargetProcessControl::runWrapper(JITTargetAddress WrapperFnAddr,
> + ArrayRef<uint8_t> ArgBuffer) {
> + using WrapperFnTy =
> + tpctypes::CWrapperFunctionResult (*)(const uint8_t *Data, uint64_t
> Size);
> + auto *WrapperFn =
> jitTargetAddressToFunction<WrapperFnTy>(WrapperFnAddr);
> + return WrapperFn(ArgBuffer.data(), ArgBuffer.size());
> +};
> +
> +Error SelfTargetProcessControl::disconnect() { return Error::success(); }
> +
> +void SelfTargetProcessControl::writeUInt8s(ArrayRef<tpctypes::UInt8Write>
> Ws,
> WriteResultFn OnWriteComplete)
> {
> for (auto &W : Ws)
> *jitTargetAddressToPointer<uint8_t *>(W.Address) = W.Value;
> OnWriteComplete(Error::success());
> }
>
> -void SelfTargetProcessControl::writeUInt16s(ArrayRef<UInt16Write> Ws,
> +void
> SelfTargetProcessControl::writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws,
> WriteResultFn
> OnWriteComplete) {
> for (auto &W : Ws)
> *jitTargetAddressToPointer<uint16_t *>(W.Address) = W.Value;
> OnWriteComplete(Error::success());
> }
>
> -void SelfTargetProcessControl::writeUInt32s(ArrayRef<UInt32Write> Ws,
> +void
> SelfTargetProcessControl::writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws,
> WriteResultFn
> OnWriteComplete) {
> for (auto &W : Ws)
> *jitTargetAddressToPointer<uint32_t *>(W.Address) = W.Value;
> OnWriteComplete(Error::success());
> }
>
> -void SelfTargetProcessControl::writeUInt64s(ArrayRef<UInt64Write> Ws,
> +void
> SelfTargetProcessControl::writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws,
> WriteResultFn
> OnWriteComplete) {
> for (auto &W : Ws)
> *jitTargetAddressToPointer<uint64_t *>(W.Address) = W.Value;
> OnWriteComplete(Error::success());
> }
>
> -void SelfTargetProcessControl::writeBuffers(ArrayRef<BufferWrite> Ws,
> +void
> SelfTargetProcessControl::writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws,
> WriteResultFn
> OnWriteComplete) {
> for (auto &W : Ws)
> memcpy(jitTargetAddressToPointer<char *>(W.Address), W.Buffer.data(),
>
> diff --git a/llvm/tools/lli/CMakeLists.txt b/llvm/tools/lli/CMakeLists.txt
> index bc6ef213b8fd..098e9dd3e743 100644
> --- a/llvm/tools/lli/CMakeLists.txt
> +++ b/llvm/tools/lli/CMakeLists.txt
> @@ -11,8 +11,9 @@ set(LLVM_LINK_COMPONENTS
> MC
> MCJIT
> Object
> - OrcError
> + OrcShared
> OrcJIT
> + OrcTargetProcess
> Passes
> RuntimeDyld
> SelectionDAG
>
> diff --git a/llvm/tools/lli/ChildTarget/CMakeLists.txt
> b/llvm/tools/lli/ChildTarget/CMakeLists.txt
> index d3d15bef6c5b..c5795eebd71a 100644
> --- a/llvm/tools/lli/ChildTarget/CMakeLists.txt
> +++ b/llvm/tools/lli/ChildTarget/CMakeLists.txt
> @@ -1,5 +1,5 @@
> set(LLVM_LINK_COMPONENTS
> - OrcError
> + OrcShared
> OrcJIT
> RuntimeDyld
> Support
>
> diff --git a/llvm/tools/lli/LLVMBuild.txt b/llvm/tools/lli/LLVMBuild.txt
> index 133543a26fce..0d473cbe9238 100644
> --- a/llvm/tools/lli/LLVMBuild.txt
> +++ b/llvm/tools/lli/LLVMBuild.txt
> @@ -28,6 +28,9 @@ required_libraries =
> Instrumentation
> Interpreter
> MCJIT
> + OrcJIT
> + OrcShared
> + OrcTargetProcess
> Native
> NativeCodeGen
> SelectionDAG
>
> diff --git a/llvm/tools/lli/lli.cpp b/llvm/tools/lli/lli.cpp
> index 1ebd1435f2f3..e9b48a8542ec 100644
> --- a/llvm/tools/lli/lli.cpp
> +++ b/llvm/tools/lli/lli.cpp
> @@ -31,6 +31,7 @@
> #include "llvm/ExecutionEngine/Orc/MachOPlatform.h"
> #include "llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h"
> #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
> +#include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h"
> #include "llvm/ExecutionEngine/SectionMemoryManager.h"
> #include "llvm/IR/IRBuilder.h"
> #include "llvm/IR/LLVMContext.h"
>
> diff --git a/llvm/tools/llvm-jitlink/CMakeLists.txt
> b/llvm/tools/llvm-jitlink/CMakeLists.txt
> index bfe691d976ba..8d511b17fca2 100644
> --- a/llvm/tools/llvm-jitlink/CMakeLists.txt
> +++ b/llvm/tools/llvm-jitlink/CMakeLists.txt
> @@ -1,3 +1,7 @@
> +if ( LLVM_INCLUDE_UTILS )
> + add_subdirectory(llvm-jitlink-executor)
> +endif()
> +
> set(LLVM_LINK_COMPONENTS
> AllTargetsDescs
> AllTargetsDisassemblers
> @@ -8,6 +12,8 @@ set(LLVM_LINK_COMPONENTS
> MC
> Object
> OrcJIT
> + OrcShared
> + OrcTargetProcess
> RuntimeDyld
> Support
> )
>
> diff --git a/llvm/tools/llvm-jitlink/LLVMBuild.txt
> b/llvm/tools/llvm-jitlink/LLVMBuild.txt
> index 224bab58c215..8aa0ef8161e6 100644
> --- a/llvm/tools/llvm-jitlink/LLVMBuild.txt
> +++ b/llvm/tools/llvm-jitlink/LLVMBuild.txt
> @@ -18,5 +18,5 @@
> type = Tool
> name = llvm-jitlink
> parent = Tools
> -required_libraries = JITLink BinaryFormat MC Object RuntimeDyld Support
> - all-targets
> +required_libraries = JITLink BinaryFormat MC Object OrcJIT
> OrcTargetProcess
> + Support all-targets
>
> diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink-executor/CMakeLists.txt
> b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/CMakeLists.txt
> new file mode 100644
> index 000000000000..f6d882d1a8f0
> --- /dev/null
> +++ b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/CMakeLists.txt
> @@ -0,0 +1,14 @@
> +set(LLVM_LINK_COMPONENTS
> + OrcShared
> + OrcTargetProcess
> + Support
> + )
> +
> +add_llvm_utility(llvm-jitlink-executor
> + llvm-jitlink-executor.cpp
> +
> + DEPENDS
> + intrinsics_gen
> +)
> +
> +export_executable_symbols(llvm-jitlink-executor)
>
> diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink-executor/LLVMBuild.txt
> b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/LLVMBuild.txt
> new file mode 100644
> index 000000000000..0d96143673dd
> --- /dev/null
> +++ b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/LLVMBuild.txt
> @@ -0,0 +1,21 @@
> +;===- ./tools/llvm-jitlink/llvm-jitlink-executor/LLVMBuild.txt -*- Conf
> -*--===;
> +;
> +; Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> +; See https://llvm.org/LICENSE.txt for license information.
> +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +;
>
> +;===------------------------------------------------------------------------===;
> +;
> +; This is an LLVMBuild description file for the components in this
> subdirectory.
> +;
> +; For more information on the LLVMBuild system, please see:
> +;
> +; http://llvm.org/docs/LLVMBuild.html
> +;
>
> +;===------------------------------------------------------------------------===;
> +
> +[component_0]
> +type = Tool
> +name = llvm-jitlink-executor
> +parent = llvm-jitlink
> +required_libraries = OrcTargetProcess Support
>
> diff --git
> a/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
> b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
> new file mode 100644
> index 000000000000..78227f3f423b
> --- /dev/null
> +++
> b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
> @@ -0,0 +1,127 @@
> +//===- llvm-jitlink-executor.cpp - Out-of-proc executor for llvm-jitlink
> -===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// Simple out-of-process executor for llvm-jitlink.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/ExecutionEngine/Orc/RPC/FDRawByteChannel.h"
> +#include "llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h"
> +#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
> +#include "llvm/Support/DynamicLibrary.h"
> +#include "llvm/Support/Error.h"
> +#include "llvm/Support/raw_ostream.h"
> +#include <sstream>
> +
> +#ifdef LLVM_ON_UNIX
> +
> +#include <netinet/in.h>
> +#include <sys/socket.h>
> +
> +#endif
> +
> +using namespace llvm;
> +using namespace llvm::orc;
> +
> +ExitOnError ExitOnErr;
> +
> +LLVM_ATTRIBUTE_USED void linkComponents() {
> + errs() << (void *)&llvm_orc_registerEHFrameSectionWrapper
> + << (void *)&llvm_orc_deregisterEHFrameSectionWrapper;
> +}
> +
> +void printErrorAndExit(Twine ErrMsg) {
> + errs() << "error: " << ErrMsg.str() << "\n\n"
> + << "Usage:\n"
> + << " llvm-jitlink-executor filedescs=<infd>,<outfd> [args...]\n"
> + << " llvm-jitlink-executor listen=<host>:<port> [args...]\n";
> + exit(1);
> +}
> +
> +int openListener(std::string Host, int Port) {
> +#ifndef LLVM_ON_UNIX
> + // FIXME: Add TCP support for Windows.
> + printErrorAndExit("listen option not supported");
> +#else
> + int SockFD = socket(PF_INET, SOCK_STREAM, 0);
> + struct sockaddr_in ServerAddr, ClientAddr;
> + socklen_t ClientAddrLen = sizeof(ClientAddr);
> + memset(&ServerAddr, 0, sizeof(ServerAddr));
> + ServerAddr.sin_family = PF_INET;
> + ServerAddr.sin_family = INADDR_ANY;
> + ServerAddr.sin_port = htons(Port);
> +
> + {
> + // lose the "Address already in use" error message
> + int Yes = 1;
> + if (setsockopt(SockFD, SOL_SOCKET, SO_REUSEADDR, &Yes, sizeof(int))
> == -1) {
> + errs() << "Error calling setsockopt.\n";
> + exit(1);
> + }
> + }
> +
> + if (bind(SockFD, (struct sockaddr *)&ServerAddr, sizeof(ServerAddr)) <
> 0) {
> + errs() << "Error on binding.\n";
> + exit(1);
> + }
> +
> + listen(SockFD, 1);
> + return accept(SockFD, (struct sockaddr *)&ClientAddr, &ClientAddrLen);
> +#endif
> +}
> +
> +int main(int argc, char *argv[]) {
> +
> + ExitOnErr.setBanner(std::string(argv[0]) + ": ");
> +
> + int InFD = 0;
> + int OutFD = 0;
> +
> + if (argc < 2)
> + printErrorAndExit("insufficient arguments");
> + else {
> + StringRef Arg1 = argv[1];
> + StringRef SpecifierType, Specifier;
> + std::tie(SpecifierType, Specifier) = Arg1.split('=');
> + if (SpecifierType == "filedescs") {
> + StringRef FD1Str, FD2Str;
> + std::tie(FD1Str, FD2Str) = Specifier.split(',');
> + if (FD1Str.getAsInteger(10, InFD))
> + printErrorAndExit(FD1Str + " is not a valid file descriptor");
> + if (FD2Str.getAsInteger(10, OutFD))
> + printErrorAndExit(FD2Str + " is not a valid file descriptor");
> + } else if (SpecifierType == "listen") {
> + StringRef Host, PortStr;
> + std::tie(Host, PortStr) = Specifier.split(':');
> +
> + int Port = 0;
> + if (PortStr.getAsInteger(10, Port))
> + printErrorAndExit("port" + PortStr + " is not a valid integer");
> +
> + InFD = OutFD = openListener(Host.str(), Port);
> + } else
> + printErrorAndExit("invalid specifier type \"" + SpecifierType +
> "\"");
> + }
> +
> + ExitOnErr.setBanner(std::string(argv[0]) + ":");
> +
> + using JITLinkExecutorEndpoint =
> + rpc::MultiThreadedRPCEndpoint<rpc::FDRawByteChannel>;
> +
> + rpc::registerStringError<rpc::FDRawByteChannel>();
> +
> + rpc::FDRawByteChannel C(InFD, OutFD);
> + JITLinkExecutorEndpoint EP(C, true);
> + OrcRPCTPCServer<JITLinkExecutorEndpoint> Server(EP);
> + Server.setProgramName(std::string("llvm-jitlink-executor"));
> +
> + ExitOnErr(Server.run());
> +
> + return 0;
> +}
>
> diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
> b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
> index 8c3b99824fe3..4e899cf2d156 100644
> --- a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
> +++ b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
> @@ -15,9 +15,9 @@
> #include "llvm-jitlink.h"
>
> #include "llvm/BinaryFormat/Magic.h"
> -#include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
> #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
> #include "llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h"
> +#include "llvm/ExecutionEngine/Orc/TPCEHFrameRegistrar.h"
> #include "llvm/MC/MCAsmInfo.h"
> #include "llvm/MC/MCContext.h"
> #include "llvm/MC/MCDisassembler/MCDisassembler.h"
> @@ -41,6 +41,13 @@
> #include <list>
> #include <string>
>
> +#ifdef LLVM_ON_UNIX
> +#include <netdb.h>
> +#include <netinet/in.h>
> +#include <sys/socket.h>
> +#include <unistd.h>
> +#endif // LLVM_ON_UNIX
> +
> #define DEBUG_TYPE "llvm_jitlink"
>
> using namespace llvm;
> @@ -138,6 +145,14 @@ static cl::opt<bool> PhonyExternals(
> cl::desc("resolve all otherwise unresolved externals to null"),
> cl::init(false));
>
> +static cl::opt<std::string> OutOfProcessExecutor(
> + "oop-executor", cl::desc("Launch an out-of-process executor to run
> code"),
> + cl::ValueOptional);
> +
> +static cl::opt<std::string> OutOfProcessExecutorConnect(
> + "oop-executor-connect",
> + cl::desc("Connect to an out-of-process executor via TCP"));
> +
> ExitOnError ExitOnErr;
>
> namespace llvm {
> @@ -561,6 +576,165 @@ Error
> LLVMJITLinkObjectLinkingLayer::add(ResourceTrackerSP RT,
> return JD.define(std::move(MU), std::move(RT));
> }
>
> +Expected<std::unique_ptr<TargetProcessControl>>
> +LLVMJITLinkRemoteTargetProcessControl::LaunchExecutor() {
> +#ifndef LLVM_ON_UNIX
> + // FIXME: Add support for Windows.
> + return make_error<StringError>("-" + OutOfProcessExecutor.ArgStr +
> + " not supported on non-unix
> platforms",
> + inconvertibleErrorCode());
> +#else
> +
> + rpc::registerStringError<LLVMJITLinkChannel>();
> +
> + constexpr int ReadEnd = 0;
> + constexpr int WriteEnd = 1;
> +
> + // Pipe FDs.
> + int ToExecutor[2];
> + int FromExecutor[2];
> +
> + pid_t ChildPID;
> +
> + // Create pipes to/from the executor..
> + if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0)
> + return make_error<StringError>("Unable to create pipe for executor",
> + inconvertibleErrorCode());
> +
> + ChildPID = fork();
> +
> + if (ChildPID == 0) {
> + // In the child...
> +
> + // Close the parent ends of the pipes
> + close(ToExecutor[WriteEnd]);
> + close(FromExecutor[ReadEnd]);
> +
> + // Execute the child process.
> + std::unique_ptr<char[]> ExecutorPath, FDSpecifier;
> + {
> + ExecutorPath = std::make_unique<char[]>(OutOfProcessExecutor.size()
> + 1);
> + strcpy(ExecutorPath.get(), OutOfProcessExecutor.data());
> +
> + std::string FDSpecifierStr("filedescs=");
> + FDSpecifierStr += utostr(ToExecutor[ReadEnd]);
> + FDSpecifierStr += ',';
> + FDSpecifierStr += utostr(FromExecutor[WriteEnd]);
> + FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1);
> + strcpy(FDSpecifier.get(), FDSpecifierStr.c_str());
> + }
> +
> + char *const Args[] = {ExecutorPath.get(), FDSpecifier.get(), nullptr};
> + int RC = execvp(ExecutorPath.get(), Args);
> + if (RC != 0) {
> + errs() << "unable to launch out-of-process executor \""
> + << ExecutorPath.get() << "\"\n";
> + exit(1);
> + }
> + }
> + // else we're the parent...
> +
> + // Close the child ends of the pipes
> + close(ToExecutor[ReadEnd]);
> + close(FromExecutor[WriteEnd]);
> +
> + // Return an RPC channel connected to our end of the pipes.
> + auto SSP = std::make_shared<SymbolStringPool>();
> + auto Channel =
> std::make_unique<rpc::FDRawByteChannel>(FromExecutor[ReadEnd],
> +
> ToExecutor[WriteEnd]);
> + auto Endpoint = std::make_unique<LLVMJITLinkRPCEndpoint>(*Channel,
> true);
> +
> + auto ReportError = [](Error Err) {
> + logAllUnhandledErrors(std::move(Err), errs(), "");
> + };
> +
> + Error Err = Error::success();
> + std::unique_ptr<LLVMJITLinkRemoteTargetProcessControl> RTPC(
> + new LLVMJITLinkRemoteTargetProcessControl(
> + std::move(SSP), std::move(Channel), std::move(Endpoint),
> + std::move(ReportError), Err));
> + if (Err)
> + return std::move(Err);
> + return std::move(RTPC);
> +#endif
> +}
> +
> +Expected<std::unique_ptr<TargetProcessControl>>
> +LLVMJITLinkRemoteTargetProcessControl::ConnectToExecutor() {
> +#ifndef LLVM_ON_UNIX
> + // FIXME: Add TCP support for Windows.
> + return make_error<StringError>("-" + OutOfProcessExecutorConnect.ArgStr
> +
> + " not supported on non-unix
> platforms",
> + inconvertibleErrorCode());
> +#else
> +
> + rpc::registerStringError<LLVMJITLinkChannel>();
> +
> + StringRef HostNameStr, PortStr;
> + std::tie(HostNameStr, PortStr) =
> + StringRef(OutOfProcessExecutorConnect).split(':');
> +
> + if (HostNameStr.empty())
> + return make_error<StringError>("host name for -" +
> + OutOfProcessExecutorConnect.ArgStr
> +
> + " can not be empty",
> + inconvertibleErrorCode());
> + if (PortStr.empty())
> + return make_error<StringError>(
> + "port for -" + OutOfProcessExecutorConnect.ArgStr + " can not be
> empty",
> + inconvertibleErrorCode());
> +
> + std::string HostName = HostNameStr.str();
> + int Port = 0;
> + if (PortStr.getAsInteger(10, Port))
> + return make_error<StringError>("port number " + PortStr +
> + " is not a valid integer",
> + inconvertibleErrorCode());
> +
> + int SockFD = socket(PF_INET, SOCK_STREAM, 0);
> + hostent *Server = gethostbyname(HostName.c_str());
> + sockaddr_in ServAddr;
> + memset(&ServAddr, 0, sizeof(ServAddr));
> + ServAddr.sin_family = PF_INET;
> + memmove(&Server->h_addr, &ServAddr.sin_addr.s_addr, Server->h_length);
> + ServAddr.sin_port = htons(Port);
> + if (connect(SockFD, reinterpret_cast<sockaddr *>(&ServAddr),
> + sizeof(ServAddr)) < 0)
> + return make_error<StringError>("Failed to connect to " + HostName +
> ":" +
> + Twine(Port),
> + inconvertibleErrorCode());
> +
> + auto SSP = std::make_shared<SymbolStringPool>();
> + auto Channel = std::make_unique<rpc::FDRawByteChannel>(SockFD, SockFD);
> + auto Endpoint = std::make_unique<LLVMJITLinkRPCEndpoint>(*Channel,
> true);
> +
> + auto ReportError = [](Error Err) {
> + logAllUnhandledErrors(std::move(Err), errs(), "");
> + };
> +
> + Error Err = Error::success();
> + std::unique_ptr<LLVMJITLinkRemoteTargetProcessControl> RTPC(
> + new LLVMJITLinkRemoteTargetProcessControl(
> + std::move(SSP), std::move(Channel), std::move(Endpoint),
> + std::move(ReportError), Err));
> + if (Err)
> + return std::move(Err);
> + return std::move(RTPC);
> +#endif
> +}
> +
> +Error LLVMJITLinkRemoteTargetProcessControl::disconnect() {
> + std::promise<MSVCPError> P;
> + auto F = P.get_future();
> + auto Err = closeConnection([&](Error Err) -> Error {
> + P.set_value(std::move(Err));
> + Finished = true;
> + return Error::success();
> + });
> + ListenerThread.join();
> + return joinErrors(std::move(Err), F.get());
> +};
> +
> class PhonyExternalsGenerator : public DefinitionGenerator {
> public:
> Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
> @@ -574,13 +748,30 @@ class PhonyExternalsGenerator : public
> DefinitionGenerator {
> };
>
> Expected<std::unique_ptr<Session>> Session::Create(Triple TT) {
> - Error Err = Error::success();
>
> auto PageSize = sys::Process::getPageSize();
> if (!PageSize)
> return PageSize.takeError();
>
> - std::unique_ptr<Session> S(new Session(std::move(TT), *PageSize, Err));
> + /// If -oop-executor is passed then launch the executor.
> + std::unique_ptr<TargetProcessControl> TPC;
> + if (OutOfProcessExecutor.getNumOccurrences()) {
> + if (auto RTPC =
> LLVMJITLinkRemoteTargetProcessControl::LaunchExecutor())
> + TPC = std::move(*RTPC);
> + else
> + return RTPC.takeError();
> + } else if (OutOfProcessExecutorConnect.getNumOccurrences()) {
> + if (auto RTPC =
> LLVMJITLinkRemoteTargetProcessControl::ConnectToExecutor())
> + TPC = std::move(*RTPC);
> + else
> + return RTPC.takeError();
> + } else
> + TPC = std::make_unique<SelfTargetProcessControl>(
> + std::make_shared<SymbolStringPool>(), std::move(TT), *PageSize,
> + createMemoryManager());
> +
> + Error Err = Error::success();
> + std::unique_ptr<Session> S(new Session(std::move(TPC), Err));
> if (Err)
> return std::move(Err);
> return std::move(S);
> @@ -593,10 +784,8 @@ Session::~Session() {
>
> // FIXME: Move to createJITDylib if/when we start using Platform support
> in
> // llvm-jitlink.
> -Session::Session(Triple TT, uint64_t PageSize, Error &Err)
> - : TPC(std::make_unique<SelfTargetProcessControl>(std::move(TT),
> PageSize,
> -
> createMemoryManager())),
> - ObjLayer(*this, TPC->getMemMgr()) {
> +Session::Session(std::unique_ptr<TargetProcessControl> TPC, Error &Err)
> + : TPC(std::move(TPC)), ObjLayer(*this, this->TPC->getMemMgr()) {
>
> /// Local ObjectLinkingLayer::Plugin class to forward modifyPassConfig
> to the
> /// Session.
> @@ -630,9 +819,9 @@ Session::Session(Triple TT, uint64_t PageSize, Error
> &Err)
> return;
> }
>
> - if (!NoExec && !TT.isOSWindows())
> + if (!NoExec && !this->TPC->getTargetTriple().isOSWindows())
> ObjLayer.addPlugin(std::make_unique<EHFrameRegistrationPlugin>(
> - ES, std::make_unique<InProcessEHFrameRegistrar>()));
> + ES, ExitOnErr(TPCEHFrameRegistrar::Create(*this->TPC))));
>
> ObjLayer.addPlugin(std::make_unique<JITLinkSessionPlugin>(*this));
>
> @@ -785,22 +974,28 @@ Session::findSymbolInfo(StringRef SymbolName, Twine
> ErrorMsgStem) {
> } // end namespace llvm
>
> static Triple getFirstFileTriple() {
> - assert(!InputFiles.empty() && "InputFiles can not be empty");
> - auto ObjBuffer =
> -
> ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFiles.front())));
> - auto Obj = ExitOnErr(
> - object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()));
> - return Obj->makeTriple();
> + static Triple FirstTT = []() {
> + assert(!InputFiles.empty() && "InputFiles can not be empty");
> + auto ObjBuffer =
> +
> ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFiles.front())));
> + auto Obj = ExitOnErr(
> +
> object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()));
> + return Obj->makeTriple();
> + }();
> +
> + return FirstTT;
> }
>
> -static Error sanitizeArguments(const Session &S) {
> +static Error sanitizeArguments(const Triple &TT, const char *ArgV0) {
> + // Set the entry point name if not specified.
> if (EntryPointName.empty()) {
> - if (S.TPC->getTargetTriple().getObjectFormat() == Triple::MachO)
> + if (TT.getObjectFormat() == Triple::MachO)
> EntryPointName = "_main";
> else
> EntryPointName = "main";
> }
>
> + // -noexec and --args should not be used together.
> if (NoExec && !InputArgv.empty())
> outs() << "Warning: --args passed to -noexec run will be ignored.\n";
>
> @@ -812,14 +1007,35 @@ static Error sanitizeArguments(const Session &S) {
> inconvertibleErrorCode());
> }
>
> + // Only one of -oop-executor and -oop-executor-connect can be used.
> + if (!!OutOfProcessExecutor.getNumOccurrences() &&
> + !!OutOfProcessExecutorConnect.getNumOccurrences())
> + return make_error<StringError>(
> + "Only one of -" + OutOfProcessExecutor.ArgStr + " and -" +
> + OutOfProcessExecutorConnect.ArgStr + " can be specified",
> + inconvertibleErrorCode());
> +
> + // If -oop-executor was used but no value was specified then use a
> sensible
> + // default.
> + if (!!OutOfProcessExecutor.getNumOccurrences() &&
> + OutOfProcessExecutor.empty()) {
> + SmallString<256> OOPExecutorPath(sys::fs::getMainExecutable(
> + ArgV0, reinterpret_cast<void *>(&sanitizeArguments)));
> + sys::path::remove_filename(OOPExecutorPath);
> + if (OOPExecutorPath.back() != '/')
> + OOPExecutorPath += '/';
> + OOPExecutorPath += "llvm-jitlink-executor";
> + OutOfProcessExecutor = OOPExecutorPath.str().str();
> + }
> +
> return Error::success();
> }
>
> static Error loadProcessSymbols(Session &S) {
> - auto InternedEntryPointName = S.ES.intern(EntryPointName);
> - auto FilterMainEntryPoint = [InternedEntryPointName](SymbolStringPtr
> Name) {
> - return Name != InternedEntryPointName;
> - };
> + auto FilterMainEntryPoint =
> + [EPName = S.ES.intern(EntryPointName)](SymbolStringPtr Name) {
> + return Name != EPName;
> + };
> S.MainJD->addGenerator(
>
> ExitOnErr(orc::TPCDynamicLibrarySearchGenerator::GetForTargetProcess(
> *S.TPC, std::move(FilterMainEntryPoint))));
> @@ -827,15 +1043,12 @@ static Error loadProcessSymbols(Session &S) {
> return Error::success();
> }
>
> -static Error loadDylibs() {
> - // FIXME: This should all be handled inside DynamicLibrary.
> +static Error loadDylibs(Session &S) {
> for (const auto &Dylib : Dylibs) {
> - if (!sys::fs::is_regular_file(Dylib))
> - return make_error<StringError>("\"" + Dylib + "\" is not a regular
> file",
> - inconvertibleErrorCode());
> - std::string ErrMsg;
> - if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib.c_str(),
> &ErrMsg))
> - return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
> + auto G = orc::TPCDynamicLibrarySearchGenerator::Load(*S.TPC,
> Dylib.c_str());
> + if (!G)
> + return G.takeError();
> + S.MainJD->addGenerator(std::move(*G));
> }
>
> return Error::success();
> @@ -1072,9 +1285,9 @@ int main(int argc, char *argv[]) {
> std::unique_ptr<JITLinkTimers> Timers =
> ShowTimes ? std::make_unique<JITLinkTimers>() : nullptr;
>
> - auto S = ExitOnErr(Session::Create(getFirstFileTriple()));
> + ExitOnErr(sanitizeArguments(getFirstFileTriple(), argv[0]));
>
> - ExitOnErr(sanitizeArguments(*S));
> + auto S = ExitOnErr(Session::Create(getFirstFileTriple()));
>
> {
> TimeRegion TR(Timers ? &Timers->LoadObjectsTimer : nullptr);
> @@ -1083,7 +1296,7 @@ int main(int argc, char *argv[]) {
>
> if (!NoProcessSymbols)
> ExitOnErr(loadProcessSymbols(*S));
> - ExitOnErr(loadDylibs());
> + ExitOnErr(loadDylibs(*S));
>
> if (PhonyExternals)
> addPhonyExternalsGenerator(*S);
> @@ -1110,11 +1323,12 @@ int main(int argc, char *argv[]) {
>
> int Result = 0;
> {
> - using MainTy = int (*)(int, char *[]);
> - auto EntryFn =
> jitTargetAddressToFunction<MainTy>(EntryPoint.getAddress());
> TimeRegion TR(Timers ? &Timers->RunTimer : nullptr);
> - Result = runAsMain(EntryFn, InputArgv, StringRef(InputFiles.front()));
> + Result = ExitOnErr(S->TPC->runAsMain(EntryPoint.getAddress(),
> InputArgv));
> }
>
> + ExitOnErr(S->ES.endSession());
> + ExitOnErr(S->TPC->disconnect());
> +
> return Result;
> }
>
> diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink.h
> b/llvm/tools/llvm-jitlink/llvm-jitlink.h
> index f0ede14050fd..5132eb204be1 100644
> --- a/llvm/tools/llvm-jitlink/llvm-jitlink.h
> +++ b/llvm/tools/llvm-jitlink/llvm-jitlink.h
> @@ -18,6 +18,9 @@
> #include "llvm/ADT/Triple.h"
> #include "llvm/ExecutionEngine/Orc/Core.h"
> #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
> +#include "llvm/ExecutionEngine/Orc/OrcRPCTargetProcessControl.h"
> +#include "llvm/ExecutionEngine/Orc/RPC/FDRawByteChannel.h"
> +#include "llvm/ExecutionEngine/Orc/RPC/RPCUtils.h"
> #include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
> #include "llvm/ExecutionEngine/RuntimeDyldChecker.h"
> #include "llvm/Support/Error.h"
> @@ -45,9 +48,71 @@ class LLVMJITLinkObjectLinkingLayer : public
> orc::ObjectLinkingLayer {
> Session &S;
> };
>
> +using LLVMJITLinkChannel = orc::rpc::FDRawByteChannel;
> +using LLVMJITLinkRPCEndpoint =
> + orc::rpc::MultiThreadedRPCEndpoint<LLVMJITLinkChannel>;
> +using LLVMJITLinkRemoteMemoryManager =
> + orc::OrcRPCTPCJITLinkMemoryManager<LLVMJITLinkRPCEndpoint>;
> +using LLVMJITLinkRemoteMemoryAccess =
> + orc::OrcRPCTPCMemoryAccess<LLVMJITLinkRPCEndpoint>;
> +
> +class LLVMJITLinkRemoteTargetProcessControl
> + : public orc::OrcRPCTargetProcessControlBase<LLVMJITLinkRPCEndpoint> {
> +public:
> + using BaseT =
> orc::OrcRPCTargetProcessControlBase<LLVMJITLinkRPCEndpoint>;
> + static Expected<std::unique_ptr<TargetProcessControl>> LaunchExecutor();
> +
> + static Expected<std::unique_ptr<TargetProcessControl>>
> ConnectToExecutor();
> +
> + Error disconnect() override;
> +
> +private:
> + using LLVMJITLinkRemoteMemoryAccess =
> + orc::OrcRPCTPCMemoryAccess<LLVMJITLinkRemoteTargetProcessControl>;
> +
> + using LLVMJITLinkRemoteMemoryManager =
> +
> orc::OrcRPCTPCJITLinkMemoryManager<LLVMJITLinkRemoteTargetProcessControl>;
> +
> + LLVMJITLinkRemoteTargetProcessControl(
> + std::shared_ptr<orc::SymbolStringPool> SSP,
> + std::unique_ptr<LLVMJITLinkChannel> Channel,
> + std::unique_ptr<LLVMJITLinkRPCEndpoint> Endpoint,
> + ErrorReporter ReportError, Error &Err)
> + : BaseT(std::move(SSP), *Endpoint, std::move(ReportError)),
> + Channel(std::move(Channel)), Endpoint(std::move(Endpoint)) {
> + ErrorAsOutParameter _(&Err);
> +
> + ListenerThread = std::thread([&]() {
> + while (!Finished) {
> + if (auto Err = this->Endpoint->handleOne()) {
> + reportError(std::move(Err));
> + return;
> + }
> + }
> + });
> +
> + if (auto Err2 = initializeORCRPCTPCBase()) {
> + Err = joinErrors(std::move(Err2), disconnect());
> + return;
> + }
> +
> + OwnedMemAccess =
> std::make_unique<LLVMJITLinkRemoteMemoryAccess>(*this);
> + MemAccess = OwnedMemAccess.get();
> + OwnedMemMgr = std::make_unique<LLVMJITLinkRemoteMemoryManager>(*this);
> + MemMgr = OwnedMemMgr.get();
> + }
> +
> + std::unique_ptr<LLVMJITLinkChannel> Channel;
> + std::unique_ptr<LLVMJITLinkRPCEndpoint> Endpoint;
> + std::unique_ptr<TargetProcessControl::MemoryAccess> OwnedMemAccess;
> + std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;
> + std::atomic<bool> Finished{false};
> + std::thread ListenerThread;
> +};
> +
> struct Session {
> - orc::ExecutionSession ES;
> std::unique_ptr<orc::TargetProcessControl> TPC;
> + orc::ExecutionSession ES;
> orc::JITDylib *MainJD;
> LLVMJITLinkObjectLinkingLayer ObjLayer;
> std::vector<orc::JITDylib *> JDSearchOrder;
> @@ -93,7 +158,7 @@ struct Session {
> DenseMap<StringRef, StringRef> CanonicalWeakDefs;
>
> private:
> - Session(Triple TT, uint64_t PageSize, Error &Err);
> + Session(std::unique_ptr<orc::TargetProcessControl> TPC, Error &Err);
> };
>
> /// Record symbols, GOT entries, stubs, and sections for ELF file.
>
> diff --git a/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
> b/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
> index 28eb128ac55d..58aacfc25bf3 100644
> --- a/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
> +++ b/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
> @@ -2,6 +2,8 @@ set(LLVM_LINK_COMPONENTS
> ${LLVM_TARGETS_TO_BUILD}
> JITLink
> Object
> + OrcShared
> + OrcTargetProcess
> RuntimeDyld
> Support
> )
>
> diff --git a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
> b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
> index b382e4c4d731..48d6888fad11 100644
> --- a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
> +++ b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
> @@ -3,8 +3,8 @@ set(LLVM_LINK_COMPONENTS
> Core
> ExecutionEngine
> Object
> - OrcError
> OrcJIT
> + OrcShared
> Passes
> RuntimeDyld
> Support
>
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20201113/f7d36a49/attachment-0001.html>
More information about the llvm-commits
mailing list