[ORC] Remove OrcRPCExecutorProcessControl ad OrcRPCTPCServer.
All in-tree tools have moved to SimpleRemoteEPC.
This commit is contained in:
@@ -1,436 +0,0 @@
|
||||
//===-- OrcRPCExecutorProcessControl.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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Executor control via ORC RPC.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCRPCEXECUTORPROCESSCONTROL_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_ORCRPCEXECUTORPROCESSCONTROL_H
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Core.h"
|
||||
#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/RPCUtils.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/RawByteChannel.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h"
|
||||
#include "llvm/Support/MSVCErrorWorkarounds.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
/// JITLinkMemoryManager implementation for a process connected via an ORC RPC
|
||||
/// endpoint.
|
||||
template <typename OrcRPCEPCImplT>
|
||||
class OrcRPCEPCJITLinkMemoryManager : 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(OrcRPCEPCJITLinkMemoryManager<OrcRPCEPCImplT> &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(), static_cast<size_t>(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({tpctypes::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 " << tpctypes::getWireProtectionFlagsStr(Prot)
|
||||
<< " segment: local " << (const 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({tpctypes::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:
|
||||
OrcRPCEPCJITLinkMemoryManager<OrcRPCEPCImplT> &Parent;
|
||||
HostAllocMap HostAllocs;
|
||||
TargetAllocMap TargetAllocs;
|
||||
};
|
||||
|
||||
OrcRPCEPCJITLinkMemoryManager(OrcRPCEPCImplT &Parent) : Parent(Parent) {}
|
||||
|
||||
Expected<std::unique_ptr<Allocation>>
|
||||
allocate(const jitlink::JITLinkDylib *JD,
|
||||
const SegmentsRequestMap &Request) override {
|
||||
orcrpctpc::ReserveMemRequest RMR;
|
||||
HostAllocMap HostAllocs;
|
||||
|
||||
for (auto &KV : Request) {
|
||||
assert(KV.second.getContentSize() <= std::numeric_limits<size_t>::max() &&
|
||||
"Content size is out-of-range for host");
|
||||
|
||||
RMR.push_back({tpctypes::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[tpctypes::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<OrcRPCEPCImplT>().getEndpoint()) getEndpoint() {
|
||||
return Parent.getEndpoint();
|
||||
}
|
||||
|
||||
OrcRPCEPCImplT &Parent;
|
||||
};
|
||||
|
||||
/// ExecutorProcessControl::MemoryAccess implementation for a process connected
|
||||
/// via an ORC RPC endpoint.
|
||||
template <typename OrcRPCEPCImplT>
|
||||
class OrcRPCEPCMemoryAccess : public ExecutorProcessControl::MemoryAccess {
|
||||
public:
|
||||
OrcRPCEPCMemoryAccess(OrcRPCEPCImplT &Parent) : Parent(Parent) {}
|
||||
|
||||
void writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws,
|
||||
WriteResultFn OnWriteComplete) override {
|
||||
writeViaRPC<orcrpctpc::WriteUInt8s>(Ws, std::move(OnWriteComplete));
|
||||
}
|
||||
|
||||
void writeUInt16sAsync(ArrayRef<tpctypes::UInt16Write> Ws,
|
||||
WriteResultFn OnWriteComplete) override {
|
||||
writeViaRPC<orcrpctpc::WriteUInt16s>(Ws, std::move(OnWriteComplete));
|
||||
}
|
||||
|
||||
void writeUInt32sAsync(ArrayRef<tpctypes::UInt32Write> Ws,
|
||||
WriteResultFn OnWriteComplete) override {
|
||||
writeViaRPC<orcrpctpc::WriteUInt32s>(Ws, std::move(OnWriteComplete));
|
||||
}
|
||||
|
||||
void writeUInt64sAsync(ArrayRef<tpctypes::UInt64Write> Ws,
|
||||
WriteResultFn OnWriteComplete) override {
|
||||
writeViaRPC<orcrpctpc::WriteUInt64s>(Ws, std::move(OnWriteComplete));
|
||||
}
|
||||
|
||||
void writeBuffersAsync(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();
|
||||
}
|
||||
}
|
||||
|
||||
OrcRPCEPCImplT &Parent;
|
||||
};
|
||||
|
||||
// ExecutorProcessControl for a process connected via an ORC RPC Endpoint.
|
||||
template <typename RPCEndpointT>
|
||||
class OrcRPCExecutorProcessControlBase : public ExecutorProcessControl {
|
||||
public:
|
||||
using ErrorReporter = unique_function<void(Error)>;
|
||||
|
||||
using OnCloseConnectionFunction = unique_function<Error(Error)>;
|
||||
|
||||
OrcRPCExecutorProcessControlBase(std::shared_ptr<SymbolStringPool> SSP,
|
||||
RPCEndpointT &EP, ErrorReporter ReportError)
|
||||
: ExecutorProcessControl(std::move(SSP)),
|
||||
ReportError(std::move(ReportError)), EP(EP) {
|
||||
using ThisT = OrcRPCExecutorProcessControlBase<RPCEndpointT>;
|
||||
EP.template addAsyncHandler<orcrpctpc::RunWrapper>(*this,
|
||||
&ThisT::runWrapperInJIT);
|
||||
}
|
||||
|
||||
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<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(ExecutorAddr MainFnAddr,
|
||||
ArrayRef<std::string> Args) override {
|
||||
DEBUG_WITH_TYPE("orc", {
|
||||
dbgs() << "Running as main: " << formatv("{0:x16}", MainFnAddr.getValue())
|
||||
<< ", args = [";
|
||||
for (unsigned I = 0; I != Args.size(); ++I)
|
||||
dbgs() << (I ? "," : "") << " \"" << Args[I] << "\"";
|
||||
dbgs() << "]\n";
|
||||
});
|
||||
auto Result =
|
||||
EP.template callB<orcrpctpc::RunMain>(MainFnAddr.getValue(), Args);
|
||||
DEBUG_WITH_TYPE("orc", {
|
||||
dbgs() << " call to " << formatv("{0:x16}", MainFnAddr.getValue());
|
||||
if (Result)
|
||||
dbgs() << " returned result " << *Result << "\n";
|
||||
else
|
||||
dbgs() << " failed\n";
|
||||
});
|
||||
return Result;
|
||||
}
|
||||
|
||||
void callWrapperAsync(SendResultFunction OnComplete,
|
||||
ExecutorAddr WrapperFnAddr,
|
||||
ArrayRef<char> ArgBuffer) override {
|
||||
DEBUG_WITH_TYPE("orc", {
|
||||
dbgs() << "Running as wrapper function "
|
||||
<< formatv("{0:x16}", WrapperFnAddr.getValue()) << " with "
|
||||
<< formatv("{0:x16}", ArgBuffer.size()) << " argument buffer\n";
|
||||
});
|
||||
auto Result = EP.template callB<orcrpctpc::RunWrapper>(
|
||||
WrapperFnAddr.getValue(),
|
||||
ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(ArgBuffer.data()),
|
||||
ArgBuffer.size()));
|
||||
|
||||
if (!Result)
|
||||
OnComplete(shared::WrapperFunctionResult::createOutOfBandError(
|
||||
toString(Result.takeError())));
|
||||
OnComplete(std::move(*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 initializeORCRPCEPCBase() {
|
||||
if (auto EPI = EP.template callB<orcrpctpc::GetExecutorProcessInfo>()) {
|
||||
this->TargetTriple = Triple(EPI->Triple);
|
||||
this->PageSize = EPI->PageSize;
|
||||
this->JDI = {ExecutorAddr(EPI->DispatchFuncAddr),
|
||||
ExecutorAddr(EPI->DispatchCtxAddr)};
|
||||
return Error::success();
|
||||
} else
|
||||
return EPI.takeError();
|
||||
}
|
||||
|
||||
private:
|
||||
Error runWrapperInJIT(
|
||||
std::function<Error(Expected<shared::WrapperFunctionResult>)> SendResult,
|
||||
JITTargetAddress FunctionTag, std::vector<uint8_t> ArgBuffer) {
|
||||
|
||||
getExecutionSession().runJITDispatchHandler(
|
||||
[this, SendResult = std::move(SendResult)](
|
||||
Expected<shared::WrapperFunctionResult> R) {
|
||||
if (auto Err = SendResult(std::move(R)))
|
||||
ReportError(std::move(Err));
|
||||
},
|
||||
FunctionTag,
|
||||
{reinterpret_cast<const char *>(ArgBuffer.data()), ArgBuffer.size()});
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
ErrorReporter ReportError;
|
||||
RPCEndpointT &EP;
|
||||
};
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_ORCRPCEXECUTORPROCESSCONTROL_H
|
||||
@@ -1,618 +0,0 @@
|
||||
//===-- 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/Shared/RPCUtils.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/RawByteChannel.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.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 {
|
||||
|
||||
struct ExecutorProcessInfo {
|
||||
std::string Triple;
|
||||
unsigned PageSize;
|
||||
JITTargetAddress DispatchFuncAddr;
|
||||
JITTargetAddress DispatchCtxAddr;
|
||||
};
|
||||
|
||||
struct ReserveMemRequestElement {
|
||||
tpctypes::WireProtectionFlags Prot = tpctypes::WPF_None;
|
||||
uint64_t Size = 0;
|
||||
uint64_t Alignment = 0;
|
||||
};
|
||||
|
||||
using ReserveMemRequest = std::vector<ReserveMemRequestElement>;
|
||||
|
||||
struct ReserveMemResultElement {
|
||||
tpctypes::WireProtectionFlags Prot = tpctypes::WPF_None;
|
||||
JITTargetAddress Address = 0;
|
||||
uint64_t AllocatedSize = 0;
|
||||
};
|
||||
|
||||
using ReserveMemResult = std::vector<ReserveMemResultElement>;
|
||||
|
||||
struct ReleaseOrFinalizeMemRequestElement {
|
||||
tpctypes::WireProtectionFlags Prot = tpctypes::WPF_None;
|
||||
JITTargetAddress Address = 0;
|
||||
uint64_t Size = 0;
|
||||
};
|
||||
|
||||
using ReleaseOrFinalizeMemRequest =
|
||||
std::vector<ReleaseOrFinalizeMemRequestElement>;
|
||||
|
||||
} // end namespace orcrpctpc
|
||||
|
||||
namespace shared {
|
||||
|
||||
template <> class SerializationTypeName<WrapperFunctionResult> {
|
||||
public:
|
||||
static const char *getName() { return "WrapperFunctionResult"; }
|
||||
};
|
||||
|
||||
template <typename ChannelT>
|
||||
class SerializationTraits<
|
||||
ChannelT, WrapperFunctionResult, WrapperFunctionResult,
|
||||
std::enable_if_t<std::is_base_of<RawByteChannel, ChannelT>::value>> {
|
||||
public:
|
||||
static Error serialize(ChannelT &C, const WrapperFunctionResult &E) {
|
||||
if (auto Err = serializeSeq(C, static_cast<uint64_t>(E.size())))
|
||||
return Err;
|
||||
if (E.size() == 0)
|
||||
return Error::success();
|
||||
return C.appendBytes(E.data(), E.size());
|
||||
}
|
||||
|
||||
static Error deserialize(ChannelT &C, WrapperFunctionResult &E) {
|
||||
uint64_t Size;
|
||||
if (auto Err = deserializeSeq(C, Size))
|
||||
return Err;
|
||||
|
||||
auto Tmp = WrapperFunctionResult::allocate(Size);
|
||||
|
||||
if (auto Err = C.readBytes(Tmp.data(), Tmp.size()))
|
||||
return Err;
|
||||
|
||||
E = std::move(Tmp);
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<tpctypes::UInt8Write> {
|
||||
public:
|
||||
static const char *getName() { return "UInt8Write"; }
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<tpctypes::UInt16Write> {
|
||||
public:
|
||||
static const char *getName() { return "UInt16Write"; }
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<tpctypes::UInt32Write> {
|
||||
public:
|
||||
static const char *getName() { return "UInt32Write"; }
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<tpctypes::UInt64Write> {
|
||||
public:
|
||||
static const char *getName() { return "UInt64Write"; }
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<tpctypes::BufferWrite> {
|
||||
public:
|
||||
static const char *getName() { return "BufferWrite"; }
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<orcrpctpc::ReserveMemRequestElement> {
|
||||
public:
|
||||
static const char *getName() { return "ReserveMemRequestElement"; }
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<orcrpctpc::ReserveMemResultElement> {
|
||||
public:
|
||||
static const char *getName() { return "ReserveMemResultElement"; }
|
||||
};
|
||||
|
||||
template <>
|
||||
class SerializationTypeName<orcrpctpc::ReleaseOrFinalizeMemRequestElement> {
|
||||
public:
|
||||
static const char *getName() { return "ReleaseOrFinalizeMemRequestElement"; }
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<orcrpctpc::ExecutorProcessInfo> {
|
||||
public:
|
||||
static const char *getName() { return "ExecutorProcessInfo"; }
|
||||
};
|
||||
|
||||
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, orcrpctpc::ExecutorProcessInfo> {
|
||||
public:
|
||||
static Error serialize(ChannelT &C,
|
||||
const orcrpctpc::ExecutorProcessInfo &EPI) {
|
||||
return serializeSeq(C, EPI.Triple, EPI.PageSize, EPI.DispatchFuncAddr,
|
||||
EPI.DispatchCtxAddr);
|
||||
}
|
||||
|
||||
static Error deserialize(ChannelT &C, orcrpctpc::ExecutorProcessInfo &EPI) {
|
||||
return deserializeSeq(C, EPI.Triple, EPI.PageSize, EPI.DispatchFuncAddr,
|
||||
EPI.DispatchCtxAddr);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace shared
|
||||
|
||||
namespace orcrpctpc {
|
||||
|
||||
using RemoteSymbolLookupSet = std::vector<std::pair<std::string, bool>>;
|
||||
using RemoteLookupRequest =
|
||||
std::pair<tpctypes::DylibHandle, RemoteSymbolLookupSet>;
|
||||
|
||||
class GetExecutorProcessInfo
|
||||
: public shared::RPCFunction<GetExecutorProcessInfo,
|
||||
orcrpctpc::ExecutorProcessInfo()> {
|
||||
public:
|
||||
static const char *getName() { return "GetJITDispatchInfo"; }
|
||||
};
|
||||
|
||||
class ReserveMem
|
||||
: public shared::RPCFunction<ReserveMem, Expected<ReserveMemResult>(
|
||||
ReserveMemRequest)> {
|
||||
public:
|
||||
static const char *getName() { return "ReserveMem"; }
|
||||
};
|
||||
|
||||
class FinalizeMem
|
||||
: public shared::RPCFunction<FinalizeMem,
|
||||
Error(ReleaseOrFinalizeMemRequest)> {
|
||||
public:
|
||||
static const char *getName() { return "FinalizeMem"; }
|
||||
};
|
||||
|
||||
class ReleaseMem
|
||||
: public shared::RPCFunction<ReleaseMem,
|
||||
Error(ReleaseOrFinalizeMemRequest)> {
|
||||
public:
|
||||
static const char *getName() { return "ReleaseMem"; }
|
||||
};
|
||||
|
||||
class WriteUInt8s
|
||||
: public shared::RPCFunction<WriteUInt8s,
|
||||
Error(std::vector<tpctypes::UInt8Write>)> {
|
||||
public:
|
||||
static const char *getName() { return "WriteUInt8s"; }
|
||||
};
|
||||
|
||||
class WriteUInt16s
|
||||
: public shared::RPCFunction<WriteUInt16s,
|
||||
Error(std::vector<tpctypes::UInt16Write>)> {
|
||||
public:
|
||||
static const char *getName() { return "WriteUInt16s"; }
|
||||
};
|
||||
|
||||
class WriteUInt32s
|
||||
: public shared::RPCFunction<WriteUInt32s,
|
||||
Error(std::vector<tpctypes::UInt32Write>)> {
|
||||
public:
|
||||
static const char *getName() { return "WriteUInt32s"; }
|
||||
};
|
||||
|
||||
class WriteUInt64s
|
||||
: public shared::RPCFunction<WriteUInt64s,
|
||||
Error(std::vector<tpctypes::UInt64Write>)> {
|
||||
public:
|
||||
static const char *getName() { return "WriteUInt64s"; }
|
||||
};
|
||||
|
||||
class WriteBuffers
|
||||
: public shared::RPCFunction<WriteBuffers,
|
||||
Error(std::vector<tpctypes::BufferWrite>)> {
|
||||
public:
|
||||
static const char *getName() { return "WriteBuffers"; }
|
||||
};
|
||||
|
||||
class LoadDylib
|
||||
: public shared::RPCFunction<LoadDylib, Expected<tpctypes::DylibHandle>(
|
||||
std::string DylibPath)> {
|
||||
public:
|
||||
static const char *getName() { return "LoadDylib"; }
|
||||
};
|
||||
|
||||
class LookupSymbols
|
||||
: public shared::RPCFunction<LookupSymbols,
|
||||
Expected<std::vector<tpctypes::LookupResult>>(
|
||||
std::vector<RemoteLookupRequest>)> {
|
||||
public:
|
||||
static const char *getName() { return "LookupSymbols"; }
|
||||
};
|
||||
|
||||
class RunMain
|
||||
: public shared::RPCFunction<RunMain,
|
||||
int64_t(JITTargetAddress MainAddr,
|
||||
std::vector<std::string> Args)> {
|
||||
public:
|
||||
static const char *getName() { return "RunMain"; }
|
||||
};
|
||||
|
||||
class RunWrapper
|
||||
: public shared::RPCFunction<RunWrapper,
|
||||
shared::WrapperFunctionResult(
|
||||
JITTargetAddress, std::vector<uint8_t>)> {
|
||||
public:
|
||||
static const char *getName() { return "RunWrapper"; }
|
||||
};
|
||||
|
||||
class CloseConnection : public shared::RPCFunction<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 {
|
||||
private:
|
||||
using ThisT = OrcRPCTPCServer<RPCEndpointT>;
|
||||
|
||||
public:
|
||||
/// Create an OrcRPCTPCServer from the given endpoint.
|
||||
OrcRPCTPCServer(RPCEndpointT &EP) : EP(EP) {
|
||||
|
||||
TripleStr = sys::getProcessTriple();
|
||||
PageSize = sys::Process::getPageSizeEstimate();
|
||||
|
||||
EP.template addHandler<orcrpctpc::GetExecutorProcessInfo>(
|
||||
*this, &ThisT::getExecutorProcessInfo);
|
||||
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();
|
||||
}
|
||||
|
||||
Expected<shared::WrapperFunctionResult>
|
||||
runWrapperInJIT(JITTargetAddress FunctionId, ArrayRef<char> ArgBuffer) {
|
||||
return EP.template callB<orcrpctpc::RunWrapper>(
|
||||
FunctionId,
|
||||
ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(ArgBuffer.data()),
|
||||
ArgBuffer.size()));
|
||||
}
|
||||
|
||||
private:
|
||||
static shared::detail::CWrapperFunctionResult
|
||||
jitDispatchViaOrcRPCTPCServer(void *Ctx, const void *FnTag, const char *Data,
|
||||
size_t Size) {
|
||||
assert(Ctx && "Attempt to dispatch with null context ptr");
|
||||
auto R = static_cast<ThisT *>(Ctx)->runWrapperInJIT(
|
||||
pointerToJITTargetAddress(FnTag), {Data, Size});
|
||||
if (!R) {
|
||||
auto ErrMsg = toString(R.takeError());
|
||||
return shared::WrapperFunctionResult::createOutOfBandError(ErrMsg.data())
|
||||
.release();
|
||||
}
|
||||
return R->release();
|
||||
}
|
||||
|
||||
orcrpctpc::ExecutorProcessInfo getExecutorProcessInfo() {
|
||||
return {TripleStr, static_cast<uint32_t>(PageSize),
|
||||
pointerToJITTargetAddress(jitDispatchViaOrcRPCTPCServer),
|
||||
pointerToJITTargetAddress(this)};
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 = tpctypes::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;
|
||||
}
|
||||
|
||||
int64_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);
|
||||
}
|
||||
|
||||
shared::WrapperFunctionResult
|
||||
runWrapper(JITTargetAddress WrapperFnAddr,
|
||||
const std::vector<uint8_t> &ArgBuffer) {
|
||||
using WrapperFnTy = shared::detail::CWrapperFunctionResult (*)(
|
||||
const char *Data, uint64_t Size);
|
||||
auto *WrapperFn = jitTargetAddressToFunction<WrapperFnTy>(WrapperFnAddr);
|
||||
return WrapperFn(reinterpret_cast<const char *>(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
|
||||
Reference in New Issue
Block a user