244 changes: 91 additions & 153 deletions llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h

Large diffs are not rendered by default.

171 changes: 88 additions & 83 deletions llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,48 @@ namespace llvm {
namespace orc {
namespace remote {

class DirectBufferWriter {
public:
DirectBufferWriter() = default;
DirectBufferWriter(const char *Src, TargetAddress Dst, uint64_t Size)
: Src(Src), Dst(Dst), Size(Size) {}

const char *getSrc() const { return Src; }
TargetAddress getDst() const { return Dst; }
uint64_t getSize() const { return Size; }
private:
const char *Src;
TargetAddress Dst;
uint64_t Size;
};

inline std::error_code serialize(RPCChannel &C,
const DirectBufferWriter &DBW) {
if (auto EC = serialize(C, DBW.getDst()))
return EC;
if (auto EC = serialize(C, DBW.getSize()))
return EC;
return C.appendBytes(DBW.getSrc(), DBW.getSize());
}

inline std::error_code deserialize(RPCChannel &C,
DirectBufferWriter &DBW) {
TargetAddress Dst;
if (auto EC = deserialize(C, Dst))
return EC;
uint64_t Size;
if (auto EC = deserialize(C, Size))
return EC;
char *Addr = reinterpret_cast<char*>(static_cast<uintptr_t>(Dst));

DBW = DirectBufferWriter(0, Dst, Size);

return C.readBytes(Addr, Size);
}

class OrcRemoteTargetRPCAPI : public RPC<RPCChannel> {
protected:

class ResourceIdMgr {
public:
typedef uint64_t ResourceId;
Expand All @@ -45,146 +85,111 @@ class OrcRemoteTargetRPCAPI : public RPC<RPCChannel> {
};

public:
enum JITProcId : uint32_t {
InvalidId = 0,
CallIntVoidId,
CallIntVoidResponseId,
enum JITFuncId : uint32_t {
InvalidId = RPCFunctionIdTraits<JITFuncId>::InvalidId,
CallIntVoidId = RPCFunctionIdTraits<JITFuncId>::FirstValidId,
CallMainId,
CallMainResponseId,
CallVoidVoidId,
CallVoidVoidResponseId,
CreateRemoteAllocatorId,
CreateIndirectStubsOwnerId,
DeregisterEHFramesId,
DestroyRemoteAllocatorId,
DestroyIndirectStubsOwnerId,
EmitIndirectStubsId,
EmitIndirectStubsResponseId,
EmitResolverBlockId,
EmitTrampolineBlockId,
EmitTrampolineBlockResponseId,
GetSymbolAddressId,
GetSymbolAddressResponseId,
GetRemoteInfoId,
GetRemoteInfoResponseId,
ReadMemId,
ReadMemResponseId,
RegisterEHFramesId,
ReserveMemId,
ReserveMemResponseId,
RequestCompileId,
RequestCompileResponseId,
SetProtectionsId,
TerminateSessionId,
WriteMemId,
WritePtrId
};

static const char *getJITProcIdName(JITProcId Id);

typedef Procedure<CallIntVoidId, void(TargetAddress Addr)> CallIntVoid;
static const char *getJITFuncIdName(JITFuncId Id);

typedef Procedure<CallIntVoidResponseId, void(int Result)>
CallIntVoidResponse;
typedef Function<CallIntVoidId, int32_t(TargetAddress Addr)> CallIntVoid;

typedef Procedure<CallMainId, void(TargetAddress Addr,
std::vector<std::string> Args)>
typedef Function<CallMainId, int32_t(TargetAddress Addr,
std::vector<std::string> Args)>
CallMain;

typedef Procedure<CallMainResponseId, void(int Result)> CallMainResponse;

typedef Procedure<CallVoidVoidId, void(TargetAddress FnAddr)> CallVoidVoid;

typedef Procedure<CallVoidVoidResponseId, void()> CallVoidVoidResponse;
typedef Function<CallVoidVoidId, void(TargetAddress FnAddr)> CallVoidVoid;

typedef Procedure<CreateRemoteAllocatorId,
void(ResourceIdMgr::ResourceId AllocatorID)>
typedef Function<CreateRemoteAllocatorId,
void(ResourceIdMgr::ResourceId AllocatorID)>
CreateRemoteAllocator;

typedef Procedure<CreateIndirectStubsOwnerId,
void(ResourceIdMgr::ResourceId StubOwnerID)>
typedef Function<CreateIndirectStubsOwnerId,
void(ResourceIdMgr::ResourceId StubOwnerID)>
CreateIndirectStubsOwner;

typedef Procedure<DeregisterEHFramesId,
void(TargetAddress Addr, uint32_t Size)>
typedef Function<DeregisterEHFramesId,
void(TargetAddress Addr, uint32_t Size)>
DeregisterEHFrames;

typedef Procedure<DestroyRemoteAllocatorId,
void(ResourceIdMgr::ResourceId AllocatorID)>
typedef Function<DestroyRemoteAllocatorId,
void(ResourceIdMgr::ResourceId AllocatorID)>
DestroyRemoteAllocator;

typedef Procedure<DestroyIndirectStubsOwnerId,
void(ResourceIdMgr::ResourceId StubsOwnerID)>
typedef Function<DestroyIndirectStubsOwnerId,
void(ResourceIdMgr::ResourceId StubsOwnerID)>
DestroyIndirectStubsOwner;

typedef Procedure<EmitIndirectStubsId,
void(ResourceIdMgr::ResourceId StubsOwnerID,
uint32_t NumStubsRequired)>
/// EmitIndirectStubs result is (StubsBase, PtrsBase, NumStubsEmitted).
typedef Function<EmitIndirectStubsId,
std::tuple<TargetAddress, TargetAddress, uint32_t>(
ResourceIdMgr::ResourceId StubsOwnerID,
uint32_t NumStubsRequired)>
EmitIndirectStubs;

typedef Procedure<EmitIndirectStubsResponseId,
void(TargetAddress StubsBaseAddr,
TargetAddress PtrsBaseAddr,
uint32_t NumStubsEmitted)>
EmitIndirectStubsResponse;
typedef Function<EmitResolverBlockId, void()> EmitResolverBlock;

typedef Procedure<EmitResolverBlockId, void()> EmitResolverBlock;
/// EmitTrampolineBlock result is (BlockAddr, NumTrampolines).
typedef Function<EmitTrampolineBlockId,
std::tuple<TargetAddress, uint32_t>()> EmitTrampolineBlock;

typedef Procedure<EmitTrampolineBlockId, void()> EmitTrampolineBlock;

typedef Procedure<EmitTrampolineBlockResponseId,
void(TargetAddress BlockAddr, uint32_t NumTrampolines)>
EmitTrampolineBlockResponse;

typedef Procedure<GetSymbolAddressId, void(std::string SymbolName)>
typedef Function<GetSymbolAddressId, TargetAddress(std::string SymbolName)>
GetSymbolAddress;

typedef Procedure<GetSymbolAddressResponseId, void(uint64_t SymbolAddr)>
GetSymbolAddressResponse;

typedef Procedure<GetRemoteInfoId, void()> GetRemoteInfo;

typedef Procedure<GetRemoteInfoResponseId,
void(std::string Triple, uint32_t PointerSize,
uint32_t PageSize, uint32_t TrampolineSize,
uint32_t IndirectStubSize)>
GetRemoteInfoResponse;
/// GetRemoteInfo result is (Triple, PointerSize, PageSize, TrampolineSize,
/// IndirectStubsSize).
typedef Function<GetRemoteInfoId,
std::tuple<std::string, uint32_t, uint32_t, uint32_t,
uint32_t>()> GetRemoteInfo;

typedef Procedure<ReadMemId, void(TargetAddress Src, uint64_t Size)>
typedef Function<ReadMemId,
std::vector<char>(TargetAddress Src, uint64_t Size)>
ReadMem;

typedef Procedure<ReadMemResponseId, void()> ReadMemResponse;

typedef Procedure<RegisterEHFramesId,
void(TargetAddress Addr, uint32_t Size)>
typedef Function<RegisterEHFramesId,
void(TargetAddress Addr, uint32_t Size)>
RegisterEHFrames;

typedef Procedure<ReserveMemId,
void(ResourceIdMgr::ResourceId AllocID, uint64_t Size,
uint32_t Align)>
typedef Function<ReserveMemId,
TargetAddress(ResourceIdMgr::ResourceId AllocID,
uint64_t Size, uint32_t Align)>
ReserveMem;

typedef Procedure<ReserveMemResponseId, void(TargetAddress Addr)>
ReserveMemResponse;

typedef Procedure<RequestCompileId, void(TargetAddress TrampolineAddr)>
typedef Function<RequestCompileId,
TargetAddress(TargetAddress TrampolineAddr)>
RequestCompile;

typedef Procedure<RequestCompileResponseId, void(TargetAddress ImplAddr)>
RequestCompileResponse;

typedef Procedure<SetProtectionsId,
void(ResourceIdMgr::ResourceId AllocID, TargetAddress Dst,
uint32_t ProtFlags)>
typedef Function<SetProtectionsId,
void(ResourceIdMgr::ResourceId AllocID, TargetAddress Dst,
uint32_t ProtFlags)>
SetProtections;

typedef Procedure<TerminateSessionId, void()> TerminateSession;
typedef Function<TerminateSessionId, void()> TerminateSession;

typedef Procedure<WriteMemId,
void(TargetAddress Dst, uint64_t Size /* Data to follow */)>
typedef Function<WriteMemId, void(DirectBufferWriter DB)>
WriteMem;

typedef Procedure<WritePtrId, void(TargetAddress Dst, TargetAddress Val)>
typedef Function<WritePtrId, void(TargetAddress Dst, TargetAddress Val)>
WritePtr;
};

Expand Down
123 changes: 56 additions & 67 deletions llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
EHFramesRegister(std::move(EHFramesRegister)),
EHFramesDeregister(std::move(EHFramesDeregister)) {}

std::error_code getNextProcId(JITProcId &Id) {
std::error_code getNextFuncId(JITFuncId &Id) {
return deserialize(Channel, Id);
}

std::error_code handleKnownProcedure(JITProcId Id) {
std::error_code handleKnownFunction(JITFuncId Id) {
typedef OrcRemoteTargetServer ThisT;

DEBUG(dbgs() << "Handling known proc: " << getJITProcIdName(Id) << "\n");
DEBUG(dbgs() << "Handling known proc: " << getJITFuncIdName(Id) << "\n");

switch (Id) {
case CallIntVoidId:
Expand Down Expand Up @@ -111,27 +111,17 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
llvm_unreachable("Unhandled JIT RPC procedure Id.");
}

std::error_code requestCompile(TargetAddress &CompiledFnAddr,
TargetAddress TrampolineAddr) {
if (auto EC = call<RequestCompile>(Channel, TrampolineAddr))
return EC;

while (1) {
JITProcId Id = InvalidId;
if (auto EC = getNextProcId(Id))
return EC;
ErrorOr<TargetAddress> requestCompile(TargetAddress TrampolineAddr) {
auto Listen =
[&](RPCChannel &C, uint32_t Id) {
return handleKnownFunction(static_cast<JITFuncId>(Id));
};

switch (Id) {
case RequestCompileResponseId:
return handle<RequestCompileResponse>(Channel,
readArgs(CompiledFnAddr));
default:
if (auto EC = handleKnownProcedure(Id))
return EC;
}
}
return callSTHandling<RequestCompile>(Channel, Listen, TrampolineAddr);
}

llvm_unreachable("Fell through request-compile command loop.");
void handleTerminateSession() {
handle<TerminateSession>(Channel, [](){ return std::error_code(); });
}

private:
Expand Down Expand Up @@ -175,18 +165,16 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
static std::error_code doNothing() { return std::error_code(); }

static TargetAddress reenter(void *JITTargetAddr, void *TrampolineAddr) {
TargetAddress CompiledFnAddr = 0;

auto T = static_cast<OrcRemoteTargetServer *>(JITTargetAddr);
auto EC = T->requestCompile(
CompiledFnAddr, static_cast<TargetAddress>(
reinterpret_cast<uintptr_t>(TrampolineAddr)));
assert(!EC && "Compile request failed");
(void)EC;
return CompiledFnAddr;
auto AddrOrErr = T->requestCompile(
static_cast<TargetAddress>(
reinterpret_cast<uintptr_t>(TrampolineAddr)));
// FIXME: Allow customizable failure substitution functions.
assert(AddrOrErr && "Compile request failed");
return *AddrOrErr;
}

std::error_code handleCallIntVoid(TargetAddress Addr) {
ErrorOr<int32_t> handleCallIntVoid(TargetAddress Addr) {
typedef int (*IntVoidFnTy)();
IntVoidFnTy Fn =
reinterpret_cast<IntVoidFnTy>(static_cast<uintptr_t>(Addr));
Expand All @@ -195,11 +183,11 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
int Result = Fn();
DEBUG(dbgs() << " Result = " << Result << "\n");

return call<CallIntVoidResponse>(Channel, Result);
return Result;
}

std::error_code handleCallMain(TargetAddress Addr,
std::vector<std::string> Args) {
ErrorOr<int32_t> handleCallMain(TargetAddress Addr,
std::vector<std::string> Args) {
typedef int (*MainFnTy)(int, const char *[]);

MainFnTy Fn = reinterpret_cast<MainFnTy>(static_cast<uintptr_t>(Addr));
Expand All @@ -214,7 +202,7 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
int Result = Fn(ArgC, ArgV.get());
DEBUG(dbgs() << " Result = " << Result << "\n");

return call<CallMainResponse>(Channel, Result);
return Result;
}

std::error_code handleCallVoidVoid(TargetAddress Addr) {
Expand All @@ -226,7 +214,7 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
Fn();
DEBUG(dbgs() << " Complete.\n");

return call<CallVoidVoidResponse>(Channel);
return std::error_code();
}

std::error_code handleCreateRemoteAllocator(ResourceIdMgr::ResourceId Id) {
Expand Down Expand Up @@ -273,8 +261,9 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
return std::error_code();
}

std::error_code handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id,
uint32_t NumStubsRequired) {
ErrorOr<std::tuple<TargetAddress, TargetAddress, uint32_t>>
handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id,
uint32_t NumStubsRequired) {
DEBUG(dbgs() << " ISMgr " << Id << " request " << NumStubsRequired
<< " stubs.\n");

Expand All @@ -296,8 +285,7 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
auto &BlockList = StubOwnerItr->second;
BlockList.push_back(std::move(IS));

return call<EmitIndirectStubsResponse>(Channel, StubsBase, PtrsBase,
NumStubsEmitted);
return std::make_tuple(StubsBase, PtrsBase, NumStubsEmitted);
}

std::error_code handleEmitResolverBlock() {
Expand All @@ -316,7 +304,8 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
sys::Memory::MF_EXEC);
}

std::error_code handleEmitTrampolineBlock() {
ErrorOr<std::tuple<TargetAddress, uint32_t>>
handleEmitTrampolineBlock() {
std::error_code EC;
auto TrampolineBlock =
sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
Expand All @@ -325,7 +314,7 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
if (EC)
return EC;

unsigned NumTrampolines =
uint32_t NumTrampolines =
(sys::Process::getPageSize() - TargetT::PointerSize) /
TargetT::TrampolineSize;

Expand All @@ -339,20 +328,21 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {

TrampolineBlocks.push_back(std::move(TrampolineBlock));

return call<EmitTrampolineBlockResponse>(
Channel,
static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(TrampolineMem)),
NumTrampolines);
auto TrampolineBaseAddr =
static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(TrampolineMem));

return std::make_tuple(TrampolineBaseAddr, NumTrampolines);
}

std::error_code handleGetSymbolAddress(const std::string &Name) {
ErrorOr<TargetAddress> handleGetSymbolAddress(const std::string &Name) {
TargetAddress Addr = SymbolLookup(Name);
DEBUG(dbgs() << " Symbol '" << Name << "' = " << format("0x%016x", Addr)
<< "\n");
return call<GetSymbolAddressResponse>(Channel, Addr);
return Addr;
}

std::error_code handleGetRemoteInfo() {
ErrorOr<std::tuple<std::string, uint32_t, uint32_t, uint32_t, uint32_t>>
handleGetRemoteInfo() {
std::string ProcessTriple = sys::getProcessTriple();
uint32_t PointerSize = TargetT::PointerSize;
uint32_t PageSize = sys::Process::getPageSize();
Expand All @@ -364,24 +354,23 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
<< " page size = " << PageSize << "\n"
<< " trampoline size = " << TrampolineSize << "\n"
<< " indirect stub size = " << IndirectStubSize << "\n");
return call<GetRemoteInfoResponse>(Channel, ProcessTriple, PointerSize,
PageSize, TrampolineSize,
IndirectStubSize);
return std::make_tuple(ProcessTriple, PointerSize, PageSize ,TrampolineSize,
IndirectStubSize);
}

std::error_code handleReadMem(TargetAddress RSrc, uint64_t Size) {
ErrorOr<std::vector<char>>
handleReadMem(TargetAddress RSrc, uint64_t Size) {
char *Src = reinterpret_cast<char *>(static_cast<uintptr_t>(RSrc));

DEBUG(dbgs() << " Reading " << Size << " bytes from "
<< format("0x%016x", RSrc) << "\n");

if (auto EC = call<ReadMemResponse>(Channel))
return EC;

if (auto EC = Channel.appendBytes(Src, Size))
return EC;
std::vector<char> Buffer;
Buffer.resize(Size);
for (char *P = Src; Size != 0; --Size)
Buffer.push_back(*P++);

return Channel.send();
return Buffer;
}

std::error_code handleRegisterEHFrames(TargetAddress TAddr, uint32_t Size) {
Expand All @@ -392,8 +381,9 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
return std::error_code();
}

std::error_code handleReserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size,
uint32_t Align) {
ErrorOr<TargetAddress>
handleReserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size,
uint32_t Align) {
auto I = Allocators.find(Id);
if (I == Allocators.end())
return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
Expand All @@ -408,7 +398,7 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
TargetAddress AllocAddr =
static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(LocalAllocAddr));

return call<ReserveMemResponse>(Channel, AllocAddr);
return AllocAddr;
}

std::error_code handleSetProtections(ResourceIdMgr::ResourceId Id,
Expand All @@ -425,11 +415,10 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
return Allocator.setProtections(LocalAddr, Flags);
}

std::error_code handleWriteMem(TargetAddress RDst, uint64_t Size) {
char *Dst = reinterpret_cast<char *>(static_cast<uintptr_t>(RDst));
DEBUG(dbgs() << " Writing " << Size << " bytes to "
<< format("0x%016x", RDst) << "\n");
return Channel.readBytes(Dst, Size);
std::error_code handleWriteMem(DirectBufferWriter DBW) {
DEBUG(dbgs() << " Writing " << DBW.getSize() << " bytes to "
<< format("0x%016x", DBW.getDst()) << "\n");
return std::error_code();
}

std::error_code handleWritePtr(TargetAddress Addr, TargetAddress PtrVal) {
Expand Down
79 changes: 73 additions & 6 deletions llvm/include/llvm/ExecutionEngine/Orc/RPCChannel.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@

#include "OrcError.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Endian.h"

#include <mutex>
#include <system_error>

namespace llvm {
Expand All @@ -26,31 +28,68 @@ class RPCChannel {

/// Flush the stream if possible.
virtual std::error_code send() = 0;

/// Get the lock for stream reading.
std::mutex& getReadLock() { return readLock; }

/// Get the lock for stream writing.
std::mutex& getWriteLock() { return writeLock; }

private:
std::mutex readLock, writeLock;
};

/// Notify the channel that we're starting a message send.
/// Locks the channel for writing.
inline std::error_code startSendMessage(RPCChannel &C) {
C.getWriteLock().lock();
return std::error_code();
}

/// Notify the channel that we're ending a message send.
/// Unlocks the channel for writing.
inline std::error_code endSendMessage(RPCChannel &C) {
C.getWriteLock().unlock();
return std::error_code();
}

/// Notify the channel that we're starting a message receive.
/// Locks the channel for reading.
inline std::error_code startReceiveMessage(RPCChannel &C) {
C.getReadLock().lock();
return std::error_code();
}

/// Notify the channel that we're ending a message receive.
/// Unlocks the channel for reading.
inline std::error_code endReceiveMessage(RPCChannel &C) {
C.getReadLock().unlock();
return std::error_code();
}

/// RPC channel serialization for a variadic list of arguments.
template <typename T, typename... Ts>
std::error_code serialize_seq(RPCChannel &C, const T &Arg, const Ts &... Args) {
std::error_code serializeSeq(RPCChannel &C, const T &Arg, const Ts &... Args) {
if (auto EC = serialize(C, Arg))
return EC;
return serialize_seq(C, Args...);
return serializeSeq(C, Args...);
}

/// RPC channel serialization for an (empty) variadic list of arguments.
inline std::error_code serialize_seq(RPCChannel &C) {
inline std::error_code serializeSeq(RPCChannel &C) {
return std::error_code();
}

/// RPC channel deserialization for a variadic list of arguments.
template <typename T, typename... Ts>
std::error_code deserialize_seq(RPCChannel &C, T &Arg, Ts &... Args) {
std::error_code deserializeSeq(RPCChannel &C, T &Arg, Ts &... Args) {
if (auto EC = deserialize(C, Arg))
return EC;
return deserialize_seq(C, Args...);
return deserializeSeq(C, Args...);
}

/// RPC channel serialization for an (empty) variadic list of arguments.
inline std::error_code deserialize_seq(RPCChannel &C) {
inline std::error_code deserializeSeq(RPCChannel &C) {
return std::error_code();
}

Expand Down Expand Up @@ -138,6 +177,34 @@ inline std::error_code deserialize(RPCChannel &C, std::string &S) {
return C.readBytes(&S[0], Count);
}

// Serialization helper for std::tuple.
template <typename TupleT, size_t... Is>
inline std::error_code serializeTupleHelper(RPCChannel &C,
const TupleT &V,
llvm::index_sequence<Is...> _) {
return serializeSeq(C, std::get<Is>(V)...);
}

/// RPC channel serialization for std::tuple.
template <typename... ArgTs>
inline std::error_code serialize(RPCChannel &C, const std::tuple<ArgTs...> &V) {
return serializeTupleHelper(C, V, llvm::index_sequence_for<ArgTs...>());
}

// Serialization helper for std::tuple.
template <typename TupleT, size_t... Is>
inline std::error_code deserializeTupleHelper(RPCChannel &C,
TupleT &V,
llvm::index_sequence<Is...> _) {
return deserializeSeq(C, std::get<Is>(V)...);
}

/// RPC channel deserialization for std::tuple.
template <typename... ArgTs>
inline std::error_code deserialize(RPCChannel &C, std::tuple<ArgTs...> &V) {
return deserializeTupleHelper(C, V, llvm::index_sequence_for<ArgTs...>());
}

/// RPC channel serialization for ArrayRef<T>.
template <typename T>
std::error_code serialize(RPCChannel &C, const ArrayRef<T> &A) {
Expand Down
524 changes: 448 additions & 76 deletions llvm/include/llvm/ExecutionEngine/Orc/RPCUtils.h

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions llvm/lib/ExecutionEngine/Orc/OrcError.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class OrcErrorCategory : public std::error_category {
return "Remote indirect stubs owner Id already in use";
case OrcErrorCode::UnexpectedRPCCall:
return "Unexpected RPC call";
case OrcErrorCode::UnexpectedRPCResponse:
return "Unexpected RPC response";
}
llvm_unreachable("Unhandled error code");
}
Expand Down
60 changes: 25 additions & 35 deletions llvm/lib/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,50 +13,40 @@ namespace llvm {
namespace orc {
namespace remote {

#define PROCNAME(X) \
#define FUNCNAME(X) \
case X ## Id: \
return #X

const char *OrcRemoteTargetRPCAPI::getJITProcIdName(JITProcId Id) {
const char *OrcRemoteTargetRPCAPI::getJITFuncIdName(JITFuncId Id) {
switch (Id) {
case InvalidId:
return "*** Invalid JITProcId ***";
PROCNAME(CallIntVoid);
PROCNAME(CallIntVoidResponse);
PROCNAME(CallMain);
PROCNAME(CallMainResponse);
PROCNAME(CallVoidVoid);
PROCNAME(CallVoidVoidResponse);
PROCNAME(CreateRemoteAllocator);
PROCNAME(CreateIndirectStubsOwner);
PROCNAME(DeregisterEHFrames);
PROCNAME(DestroyRemoteAllocator);
PROCNAME(DestroyIndirectStubsOwner);
PROCNAME(EmitIndirectStubs);
PROCNAME(EmitIndirectStubsResponse);
PROCNAME(EmitResolverBlock);
PROCNAME(EmitTrampolineBlock);
PROCNAME(EmitTrampolineBlockResponse);
PROCNAME(GetSymbolAddress);
PROCNAME(GetSymbolAddressResponse);
PROCNAME(GetRemoteInfo);
PROCNAME(GetRemoteInfoResponse);
PROCNAME(ReadMem);
PROCNAME(ReadMemResponse);
PROCNAME(RegisterEHFrames);
PROCNAME(ReserveMem);
PROCNAME(ReserveMemResponse);
PROCNAME(RequestCompile);
PROCNAME(RequestCompileResponse);
PROCNAME(SetProtections);
PROCNAME(TerminateSession);
PROCNAME(WriteMem);
PROCNAME(WritePtr);
return "*** Invalid JITFuncId ***";
FUNCNAME(CallIntVoid);
FUNCNAME(CallMain);
FUNCNAME(CallVoidVoid);
FUNCNAME(CreateRemoteAllocator);
FUNCNAME(CreateIndirectStubsOwner);
FUNCNAME(DeregisterEHFrames);
FUNCNAME(DestroyRemoteAllocator);
FUNCNAME(DestroyIndirectStubsOwner);
FUNCNAME(EmitIndirectStubs);
FUNCNAME(EmitResolverBlock);
FUNCNAME(EmitTrampolineBlock);
FUNCNAME(GetSymbolAddress);
FUNCNAME(GetRemoteInfo);
FUNCNAME(ReadMem);
FUNCNAME(RegisterEHFrames);
FUNCNAME(ReserveMem);
FUNCNAME(RequestCompile);
FUNCNAME(SetProtections);
FUNCNAME(TerminateSession);
FUNCNAME(WriteMem);
FUNCNAME(WritePtr);
};
return nullptr;
}

#undef PROCNAME
#undef FUNCNAME

} // end namespace remote
} // end namespace orc
Expand Down
6 changes: 3 additions & 3 deletions llvm/tools/lli/ChildTarget/ChildTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,16 @@ int main(int argc, char *argv[]) {
JITServer Server(Channel, SymbolLookup, RegisterEHFrames, DeregisterEHFrames);

while (1) {
JITServer::JITProcId Id = JITServer::InvalidId;
if (auto EC = Server.getNextProcId(Id)) {
JITServer::JITFuncId Id = JITServer::InvalidId;
if (auto EC = Server.getNextFuncId(Id)) {
errs() << "Error: " << EC.message() << "\n";
return 1;
}
switch (Id) {
case JITServer::TerminateSessionId:
return 0;
default:
if (auto EC = Server.handleKnownProcedure(Id)) {
if (auto EC = Server.handleKnownFunction(Id)) {
errs() << "Error: " << EC.message() << "\n";
return 1;
}
Expand Down
1 change: 1 addition & 0 deletions llvm/tools/lli/RemoteJITUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include "llvm/ExecutionEngine/Orc/RPCChannel.h"
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
#include <mutex>

#if !defined(_MSC_VER) && !defined(__MINGW32__)
#include <unistd.h>
Expand Down
21 changes: 12 additions & 9 deletions llvm/tools/lli/lli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ int main(int argc, char **argv, char * const *envp) {
// Reset errno to zero on entry to main.
errno = 0;

int Result;
int Result = -1;

// Sanity check use of remote-jit: LLI currently only supports use of the
// remote JIT on Unix platforms.
Expand Down Expand Up @@ -681,12 +681,13 @@ int main(int argc, char **argv, char * const *envp) {
static_cast<ForwardingMemoryManager*>(RTDyldMM)->setResolver(
orc::createLambdaResolver(
[&](const std::string &Name) {
orc::TargetAddress Addr = 0;
if (auto EC = R->getSymbolAddress(Addr, Name)) {
errs() << "Failure during symbol lookup: " << EC.message() << "\n";
exit(1);
}
return RuntimeDyld::SymbolInfo(Addr, JITSymbolFlags::Exported);
if (auto AddrOrErr = R->getSymbolAddress(Name))
return RuntimeDyld::SymbolInfo(*AddrOrErr, JITSymbolFlags::Exported);
else {
errs() << "Failure during symbol lookup: "
<< AddrOrErr.getError().message() << "\n";
exit(1);
}
},
[](const std::string &Name) { return nullptr; }
));
Expand All @@ -698,8 +699,10 @@ int main(int argc, char **argv, char * const *envp) {
EE->finalizeObject();
DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at 0x"
<< format("%llx", Entry) << "\n");
if (auto EC = R->callIntVoid(Result, Entry))
errs() << "ERROR: " << EC.message() << "\n";
if (auto ResultOrErr = R->callIntVoid(Entry))
Result = *ResultOrErr;
else
errs() << "ERROR: " << ResultOrErr.getError().message() << "\n";

// Like static constructors, the remote target MCJIT support doesn't handle
// this yet. It could. FIXME.
Expand Down
103 changes: 76 additions & 27 deletions llvm/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,57 +44,96 @@ class QueueChannel : public RPCChannel {
class DummyRPC : public testing::Test,
public RPC<QueueChannel> {
public:
typedef Procedure<1, void(bool)> Proc1;
typedef Procedure<2, void(int8_t, uint8_t, int16_t, uint16_t,
int32_t, uint32_t, int64_t, uint64_t,
bool, std::string, std::vector<int>)> AllTheTypes;
typedef Function<2, void(bool)> BasicVoid;
typedef Function<3, int32_t(bool)> BasicInt;
typedef Function<4, void(int8_t, uint8_t, int16_t, uint16_t,
int32_t, uint32_t, int64_t, uint64_t,
bool, std::string, std::vector<int>)> AllTheTypes;
};


TEST_F(DummyRPC, TestBasic) {
TEST_F(DummyRPC, TestAsyncBasicVoid) {
std::queue<char> Queue;
QueueChannel C(Queue);

{
// Make a call to Proc1.
auto EC = call<Proc1>(C, true);
EXPECT_FALSE(EC) << "Simple call over queue failed";
}
// Make an async call.
auto ResOrErr = callAsync<BasicVoid>(C, true);
EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed";

{
// Expect a call to Proc1.
auto EC = expect<Proc1>(C,
auto EC = expect<BasicVoid>(C,
[&](bool &B) {
EXPECT_EQ(B, true)
<< "Bool serialization broken";
return std::error_code();
});
EXPECT_FALSE(EC) << "Simple expect over queue failed";
}

{
// Wait for the result.
auto EC = waitForResult(C, ResOrErr->second, handleNone);
EXPECT_FALSE(EC) << "Could not read result.";
}

// Verify that the function returned ok.
auto Val = ResOrErr->first.get();
EXPECT_TRUE(Val) << "Remote void function failed to execute.";
}

TEST_F(DummyRPC, TestSerialization) {
TEST_F(DummyRPC, TestAsyncBasicInt) {
std::queue<char> Queue;
QueueChannel C(Queue);

// Make an async call.
auto ResOrErr = callAsync<BasicInt>(C, false);
EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed";

{
// Make a call to Proc1.
std::vector<int> v({42, 7});
auto EC = call<AllTheTypes>(C,
-101,
250,
-10000,
10000,
-1000000000,
1000000000,
-10000000000,
10000000000,
true,
"foo",
v);
EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed";
// Expect a call to Proc1.
auto EC = expect<BasicInt>(C,
[&](bool &B) {
EXPECT_EQ(B, false)
<< "Bool serialization broken";
return 42;
});
EXPECT_FALSE(EC) << "Simple expect over queue failed";
}

{
// Wait for the result.
auto EC = waitForResult(C, ResOrErr->second, handleNone);
EXPECT_FALSE(EC) << "Could not read result.";
}

// Verify that the function returned ok.
auto Val = ResOrErr->first.get();
EXPECT_TRUE(!!Val) << "Remote int function failed to execute.";
EXPECT_EQ(*Val, 42) << "Remote int function return wrong value.";
}

TEST_F(DummyRPC, TestSerialization) {
std::queue<char> Queue;
QueueChannel C(Queue);

// Make a call to Proc1.
std::vector<int> v({42, 7});
auto ResOrErr = callAsync<AllTheTypes>(C,
-101,
250,
-10000,
10000,
-1000000000,
1000000000,
-10000000000,
10000000000,
true,
"foo",
v);
EXPECT_TRUE(!!ResOrErr)
<< "Big (serialization test) call over queue failed";

{
// Expect a call to Proc1.
auto EC = expect<AllTheTypes>(C,
Expand Down Expand Up @@ -136,4 +175,14 @@ TEST_F(DummyRPC, TestSerialization) {
});
EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed";
}

{
// Wait for the result.
auto EC = waitForResult(C, ResOrErr->second, handleNone);
EXPECT_FALSE(EC) << "Could not read result.";
}

// Verify that the function returned ok.
auto Val = ResOrErr->first.get();
EXPECT_TRUE(Val) << "Remote void function failed to execute.";
}