[ORC] Thread Error/Expected through the RPC library.

This replaces use of std::error_code and ErrorOr in the ORC RPC support library
with Error and Expected. This required updating the OrcRemoteTarget API, Client,
and server code, as well as updating the Orc C API.

This patch also fixes several instances where Errors were dropped.

llvm-svn: 267457
This commit is contained in:
Lang Hames 2016-04-25 19:56:45 +00:00
parent 074ea2851c
commit ef5a0ee2c3
18 changed files with 621 additions and 533 deletions

View File

@ -37,6 +37,11 @@ typedef uint64_t (*LLVMOrcSymbolResolverFn)(const char *Name,
typedef uint64_t (*LLVMOrcLazyCompileCallbackFn)(LLVMOrcJITStackRef JITStack,
void *CallbackCtx);
typedef enum {
LLVMOrcErrSuccess = 0,
LLVMOrcErrGeneric
} LLVMOrcErrorCode;
/**
* Create an ORC JIT stack.
*
@ -48,6 +53,14 @@ typedef uint64_t (*LLVMOrcLazyCompileCallbackFn)(LLVMOrcJITStackRef JITStack,
*/
LLVMOrcJITStackRef LLVMOrcCreateInstance(LLVMTargetMachineRef TM);
/**
* Get the error message for the most recent error (if any).
*
* This message is owned by the ORC JIT Stack and will be freed when the stack
* is disposed of by LLVMOrcDisposeInstance.
*/
const char *LLVMOrcGetErrorMsg(LLVMOrcJITStackRef JITStack);
/**
* Mangle the given symbol.
* Memory will be allocated for MangledSymbol to hold the result. The client
@ -58,7 +71,6 @@ void LLVMOrcGetMangledSymbol(LLVMOrcJITStackRef JITStack, char **MangledSymbol,
/**
* Dispose of a mangled symbol.
*/
void LLVMOrcDisposeMangledSymbol(char *MangledSymbol);
/**
@ -72,16 +84,16 @@ LLVMOrcCreateLazyCompileCallback(LLVMOrcJITStackRef JITStack,
/**
* Create a named indirect call stub.
*/
void LLVMOrcCreateIndirectStub(LLVMOrcJITStackRef JITStack,
const char *StubName,
LLVMOrcTargetAddress InitAddr);
LLVMOrcErrorCode LLVMOrcCreateIndirectStub(LLVMOrcJITStackRef JITStack,
const char *StubName,
LLVMOrcTargetAddress InitAddr);
/**
* Set the pointer for the given indirect stub.
*/
void LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack,
const char *StubName,
LLVMOrcTargetAddress NewAddr);
LLVMOrcErrorCode LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack,
const char *StubName,
LLVMOrcTargetAddress NewAddr);
/**
* Add module to be eagerly compiled.

View File

@ -219,12 +219,12 @@ public:
virtual ~IndirectStubsManager() {}
/// @brief Create a single stub with the given name, target address and flags.
virtual std::error_code createStub(StringRef StubName, TargetAddress StubAddr,
JITSymbolFlags StubFlags) = 0;
virtual Error createStub(StringRef StubName, TargetAddress StubAddr,
JITSymbolFlags StubFlags) = 0;
/// @brief Create StubInits.size() stubs with the given names, target
/// addresses, and flags.
virtual std::error_code createStubs(const StubInitsMap &StubInits) = 0;
virtual Error createStubs(const StubInitsMap &StubInits) = 0;
/// @brief Find the stub with the given name. If ExportedStubsOnly is true,
/// this will only return a result if the stub's flags indicate that it
@ -235,7 +235,7 @@ public:
virtual JITSymbol findPointer(StringRef Name) = 0;
/// @brief Change the value of the implementation pointer for the stub.
virtual std::error_code updatePointer(StringRef Name, TargetAddress NewAddr) = 0;
virtual Error updatePointer(StringRef Name, TargetAddress NewAddr) = 0;
private:
virtual void anchor();
};
@ -246,25 +246,25 @@ template <typename TargetT>
class LocalIndirectStubsManager : public IndirectStubsManager {
public:
std::error_code createStub(StringRef StubName, TargetAddress StubAddr,
Error createStub(StringRef StubName, TargetAddress StubAddr,
JITSymbolFlags StubFlags) override {
if (auto EC = reserveStubs(1))
return EC;
if (auto Err = reserveStubs(1))
return Err;
createStubInternal(StubName, StubAddr, StubFlags);
return std::error_code();
return Error::success();
}
std::error_code createStubs(const StubInitsMap &StubInits) override {
if (auto EC = reserveStubs(StubInits.size()))
return EC;
Error createStubs(const StubInitsMap &StubInits) override {
if (auto Err = reserveStubs(StubInits.size()))
return Err;
for (auto &Entry : StubInits)
createStubInternal(Entry.first(), Entry.second.first,
Entry.second.second);
return std::error_code();
return Error::success();
}
JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
@ -294,31 +294,31 @@ public:
return JITSymbol(PtrTargetAddr, I->second.second);
}
std::error_code updatePointer(StringRef Name, TargetAddress NewAddr) override {
Error updatePointer(StringRef Name, TargetAddress NewAddr) override {
auto I = StubIndexes.find(Name);
assert(I != StubIndexes.end() && "No stub pointer for symbol");
auto Key = I->second.first;
*IndirectStubsInfos[Key.first].getPtr(Key.second) =
reinterpret_cast<void*>(static_cast<uintptr_t>(NewAddr));
return std::error_code();
return Error::success();
}
private:
std::error_code reserveStubs(unsigned NumStubs) {
Error reserveStubs(unsigned NumStubs) {
if (NumStubs <= FreeStubs.size())
return std::error_code();
return Error::success();
unsigned NewStubsRequired = NumStubs - FreeStubs.size();
unsigned NewBlockId = IndirectStubsInfos.size();
typename TargetT::IndirectStubsInfo ISI;
if (auto EC = TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired,
if (auto Err = TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired,
nullptr))
return EC;
return Err;
for (unsigned I = 0; I < ISI.getNumStubs(); ++I)
FreeStubs.push_back(std::make_pair(NewBlockId, I));
IndirectStubsInfos.push_back(std::move(ISI));
return std::error_code();
return Error::success();
}
void createStubInternal(StringRef StubName, TargetAddress InitAddr,

View File

@ -59,9 +59,8 @@ public:
void **getPtr(unsigned Idx) const { llvm_unreachable("Not supported"); }
};
static std::error_code emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
unsigned MinStubs,
void *InitialPtrVal) {
static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
unsigned MinStubs, void *InitialPtrVal) {
llvm_unreachable("emitIndirectStubsBlock is not supported by the generic "
"host support class");
}
@ -69,8 +68,7 @@ public:
/// @brief Provide information about stub blocks generated by the
/// makeIndirectStubsBlock function.
template <unsigned StubSizeVal>
class GenericIndirectStubsInfo {
template <unsigned StubSizeVal> class GenericIndirectStubsInfo {
public:
const static unsigned StubSize = StubSizeVal;
@ -100,8 +98,7 @@ public:
/// @brief Get a pointer to the implementation-pointer at the given index,
/// which must be in the range 0 .. getNumStubs() - 1.
void **getPtr(unsigned Idx) const {
char *PtrsBase =
static_cast<char *>(StubsMem.base()) + NumStubs * StubSize;
char *PtrsBase = static_cast<char *>(StubsMem.base()) + NumStubs * StubSize;
return reinterpret_cast<void **>(PtrsBase) + Idx;
}
@ -140,9 +137,8 @@ public:
/// E.g. Asking for 4 stubs on x86-64, where stubs are 8-bytes, with 4k
/// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
/// will return a block of 1024 (2-pages worth).
static std::error_code emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
unsigned MinStubs,
void *InitialPtrVal);
static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
unsigned MinStubs, void *InitialPtrVal);
};
/// @brief I386 support.
@ -175,12 +171,10 @@ public:
/// E.g. Asking for 4 stubs on i386, where stubs are 8-bytes, with 4k
/// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
/// will return a block of 1024 (2-pages worth).
static std::error_code emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
unsigned MinStubs,
void *InitialPtrVal);
static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
unsigned MinStubs, void *InitialPtrVal);
};
} // End namespace orc.
} // End namespace llvm.

View File

@ -14,6 +14,7 @@
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCERROR_H
#define LLVM_EXECUTIONENGINE_ORC_ORCERROR_H
#include "llvm/Support/Error.h"
#include <system_error>
namespace llvm {
@ -30,7 +31,7 @@ enum class OrcErrorCode : int {
UnexpectedRPCResponse,
};
std::error_code orcError(OrcErrorCode ErrCode);
Error orcError(OrcErrorCode ErrCode);
} // End namespace orc.
} // End namespace llvm.

View File

@ -36,25 +36,22 @@ namespace remote {
template <typename ChannelT>
class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI {
public:
// FIXME: Remove move/copy ops once MSVC supports synthesizing move ops.
OrcRemoteTargetClient(const OrcRemoteTargetClient&) = delete;
OrcRemoteTargetClient& operator=(const OrcRemoteTargetClient&) = delete;
OrcRemoteTargetClient(const OrcRemoteTargetClient &) = delete;
OrcRemoteTargetClient &operator=(const OrcRemoteTargetClient &) = delete;
OrcRemoteTargetClient(OrcRemoteTargetClient &&Other)
: Channel(Other.Channel),
ExistingError(std::move(Other.ExistingError)),
RemoteTargetTriple(std::move(Other.RemoteTargetTriple)),
RemotePointerSize(std::move(Other.RemotePointerSize)),
RemotePageSize(std::move(Other.RemotePageSize)),
RemoteTrampolineSize(std::move(Other.RemoteTrampolineSize)),
RemoteIndirectStubSize(std::move(Other.RemoteIndirectStubSize)),
AllocatorIds(std::move(Other.AllocatorIds)),
IndirectStubOwnerIds(std::move(Other.IndirectStubOwnerIds)),
CompileCallback(std::move(Other.CompileCallback)) {}
: Channel(Other.Channel), ExistingError(std::move(Other.ExistingError)),
RemoteTargetTriple(std::move(Other.RemoteTargetTriple)),
RemotePointerSize(std::move(Other.RemotePointerSize)),
RemotePageSize(std::move(Other.RemotePageSize)),
RemoteTrampolineSize(std::move(Other.RemoteTrampolineSize)),
RemoteIndirectStubSize(std::move(Other.RemoteIndirectStubSize)),
AllocatorIds(std::move(Other.AllocatorIds)),
IndirectStubOwnerIds(std::move(Other.IndirectStubOwnerIds)) {}
OrcRemoteTargetClient& operator=(OrcRemoteTargetClient&&) = delete;
OrcRemoteTargetClient &operator=(OrcRemoteTargetClient &&) = delete;
/// Remote memory manager.
class RCMemoryManager : public RuntimeDyld::MemoryManager {
@ -125,12 +122,12 @@ public:
DEBUG(dbgs() << "Allocator " << Id << " reserved:\n");
if (CodeSize != 0) {
if (auto AddrOrErr = Client.reserveMem(Id, CodeSize, CodeAlign))
Unmapped.back().RemoteCodeAddr = *AddrOrErr;
else {
// FIXME; Add error to poll.
assert(!AddrOrErr.getError() && "Failed reserving remote memory.");
}
if (auto AddrOrErr = Client.reserveMem(Id, CodeSize, CodeAlign))
Unmapped.back().RemoteCodeAddr = *AddrOrErr;
else {
// FIXME; Add error to poll.
assert(!AddrOrErr.takeError() && "Failed reserving remote memory.");
}
DEBUG(dbgs() << " code: "
<< format("0x%016x", Unmapped.back().RemoteCodeAddr)
@ -140,11 +137,11 @@ public:
if (RODataSize != 0) {
if (auto AddrOrErr = Client.reserveMem(Id, RODataSize, RODataAlign))
Unmapped.back().RemoteRODataAddr = *AddrOrErr;
else {
// FIXME; Add error to poll.
assert(!AddrOrErr.getError() && "Failed reserving remote memory.");
}
Unmapped.back().RemoteRODataAddr = *AddrOrErr;
else {
// FIXME; Add error to poll.
assert(!AddrOrErr.takeError() && "Failed reserving remote memory.");
}
DEBUG(dbgs() << " ro-data: "
<< format("0x%016x", Unmapped.back().RemoteRODataAddr)
@ -154,10 +151,10 @@ public:
if (RWDataSize != 0) {
if (auto AddrOrErr = Client.reserveMem(Id, RWDataSize, RWDataAlign))
Unmapped.back().RemoteRWDataAddr = *AddrOrErr;
else {
// FIXME; Add error to poll.
assert(!AddrOrErr.getError() && "Failed reserving remote memory.");
Unmapped.back().RemoteRWDataAddr = *AddrOrErr;
else {
// FIXME; Add error to poll.
assert(!AddrOrErr.takeError() && "Failed reserving remote memory.");
}
DEBUG(dbgs() << " rw-data: "
@ -177,10 +174,10 @@ public:
void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr,
size_t Size) override {
auto EC = Client.deregisterEHFrames(LoadAddr, Size);
auto Err = Client.deregisterEHFrames(LoadAddr, Size);
// FIXME: Add error poll.
assert(!EC && "Failed to register remote EH frames.");
(void)EC;
assert(!Err && "Failed to register remote EH frames.");
(void)Err;
}
void notifyObjectLoaded(RuntimeDyld &Dyld,
@ -240,15 +237,35 @@ public:
<< static_cast<void *>(Alloc.getLocalAddress()) << " -> "
<< format("0x%016x", Alloc.getRemoteAddress()) << " ("
<< Alloc.getSize() << " bytes)\n");
Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
Alloc.getSize());
if (auto Err =
Client.writeMem(Alloc.getRemoteAddress(),
Alloc.getLocalAddress(), Alloc.getSize())) {
// FIXME: Replace this once finalizeMemory can return an Error.
handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
if (ErrMsg) {
raw_string_ostream ErrOut(*ErrMsg);
EIB.log(ErrOut);
}
});
return true;
}
}
if (ObjAllocs.RemoteCodeAddr) {
DEBUG(dbgs() << " setting R-X permissions on code block: "
<< format("0x%016x", ObjAllocs.RemoteCodeAddr) << "\n");
Client.setProtections(Id, ObjAllocs.RemoteCodeAddr,
sys::Memory::MF_READ | sys::Memory::MF_EXEC);
if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteCodeAddr,
sys::Memory::MF_READ |
sys::Memory::MF_EXEC)) {
// FIXME: Replace this once finalizeMemory can return an Error.
handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
if (ErrMsg) {
raw_string_ostream ErrOut(*ErrMsg);
EIB.log(ErrOut);
}
});
return true;
}
}
for (auto &Alloc : ObjAllocs.RODataAllocs) {
@ -256,16 +273,35 @@ public:
<< static_cast<void *>(Alloc.getLocalAddress()) << " -> "
<< format("0x%016x", Alloc.getRemoteAddress()) << " ("
<< Alloc.getSize() << " bytes)\n");
Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
Alloc.getSize());
if (auto Err =
Client.writeMem(Alloc.getRemoteAddress(),
Alloc.getLocalAddress(), Alloc.getSize())) {
// FIXME: Replace this once finalizeMemory can return an Error.
handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
if (ErrMsg) {
raw_string_ostream ErrOut(*ErrMsg);
EIB.log(ErrOut);
}
});
return true;
}
}
if (ObjAllocs.RemoteRODataAddr) {
DEBUG(dbgs() << " setting R-- permissions on ro-data block: "
<< format("0x%016x", ObjAllocs.RemoteRODataAddr)
<< "\n");
Client.setProtections(Id, ObjAllocs.RemoteRODataAddr,
sys::Memory::MF_READ);
if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteRODataAddr,
sys::Memory::MF_READ)) {
// FIXME: Replace this once finalizeMemory can return an Error.
handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
if (ErrMsg) {
raw_string_ostream ErrOut(*ErrMsg);
EIB.log(ErrOut);
}
});
return false;
}
}
for (auto &Alloc : ObjAllocs.RWDataAllocs) {
@ -273,25 +309,51 @@ public:
<< static_cast<void *>(Alloc.getLocalAddress()) << " -> "
<< format("0x%016x", Alloc.getRemoteAddress()) << " ("
<< Alloc.getSize() << " bytes)\n");
Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
Alloc.getSize());
if (auto Err =
Client.writeMem(Alloc.getRemoteAddress(),
Alloc.getLocalAddress(), Alloc.getSize())) {
// FIXME: Replace this once finalizeMemory can return an Error.
handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
if (ErrMsg) {
raw_string_ostream ErrOut(*ErrMsg);
EIB.log(ErrOut);
}
});
return false;
}
}
if (ObjAllocs.RemoteRWDataAddr) {
DEBUG(dbgs() << " setting RW- permissions on rw-data block: "
<< format("0x%016x", ObjAllocs.RemoteRWDataAddr)
<< "\n");
Client.setProtections(Id, ObjAllocs.RemoteRWDataAddr,
sys::Memory::MF_READ | sys::Memory::MF_WRITE);
if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteRWDataAddr,
sys::Memory::MF_READ |
sys::Memory::MF_WRITE)) {
// FIXME: Replace this once finalizeMemory can return an Error.
handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
if (ErrMsg) {
raw_string_ostream ErrOut(*ErrMsg);
EIB.log(ErrOut);
}
});
return false;
}
}
}
Unfinalized.clear();
for (auto &EHFrame : UnfinalizedEHFrames) {
auto EC = Client.registerEHFrames(EHFrame.first, EHFrame.second);
// FIXME: Add error poll.
assert(!EC && "Failed to register remote EH frames.");
(void)EC;
if (auto Err = Client.registerEHFrames(EHFrame.first, EHFrame.second)) {
// FIXME: Replace this once finalizeMemory can return an Error.
handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
if (ErrMsg) {
raw_string_ostream ErrOut(*ErrMsg);
EIB.log(ErrOut);
}
});
return false;
}
}
UnfinalizedEHFrames.clear();
@ -382,27 +444,30 @@ public:
: Remote(Remote), Id(Id) {}
~RCIndirectStubsManager() override {
Remote.destroyIndirectStubsManager(Id);
if (auto Err = Remote.destroyIndirectStubsManager(Id)) {
// FIXME: Thread this error back to clients.
consumeError(std::move(Err));
}
}
std::error_code createStub(StringRef StubName, TargetAddress StubAddr,
JITSymbolFlags StubFlags) override {
if (auto EC = reserveStubs(1))
return EC;
Error createStub(StringRef StubName, TargetAddress StubAddr,
JITSymbolFlags StubFlags) override {
if (auto Err = reserveStubs(1))
return Err;
return createStubInternal(StubName, StubAddr, StubFlags);
}
std::error_code createStubs(const StubInitsMap &StubInits) override {
if (auto EC = reserveStubs(StubInits.size()))
return EC;
Error createStubs(const StubInitsMap &StubInits) override {
if (auto Err = reserveStubs(StubInits.size()))
return Err;
for (auto &Entry : StubInits)
if (auto EC = createStubInternal(Entry.first(), Entry.second.first,
Entry.second.second))
return EC;
if (auto Err = createStubInternal(Entry.first(), Entry.second.first,
Entry.second.second))
return Err;
return std::error_code();
return Error::success();
}
JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
@ -426,8 +491,7 @@ public:
return JITSymbol(getPtrAddr(Key), Flags);
}
std::error_code updatePointer(StringRef Name,
TargetAddress NewAddr) override {
Error updatePointer(StringRef Name, TargetAddress NewAddr) override {
auto I = StubIndexes.find(Name);
assert(I != StubIndexes.end() && "No stub pointer for symbol");
auto Key = I->second.first;
@ -448,9 +512,9 @@ public:
std::vector<StubKey> FreeStubs;
StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
std::error_code reserveStubs(unsigned NumStubs) {
Error reserveStubs(unsigned NumStubs) {
if (NumStubs <= FreeStubs.size())
return std::error_code();
return Error::success();
unsigned NewStubsRequired = NumStubs - FreeStubs.size();
TargetAddress StubBase;
@ -458,9 +522,9 @@ public:
unsigned NumStubsEmitted;
if (auto StubInfoOrErr = Remote.emitIndirectStubs(Id, NewStubsRequired))
std::tie(StubBase, PtrBase, NumStubsEmitted) = *StubInfoOrErr;
std::tie(StubBase, PtrBase, NumStubsEmitted) = *StubInfoOrErr;
else
return StubInfoOrErr.getError();
return StubInfoOrErr.takeError();
unsigned NewBlockId = RemoteIndirectStubsInfos.size();
RemoteIndirectStubsInfos.push_back({StubBase, PtrBase, NumStubsEmitted});
@ -468,12 +532,11 @@ public:
for (unsigned I = 0; I < NumStubsEmitted; ++I)
FreeStubs.push_back(std::make_pair(NewBlockId, I));
return std::error_code();
return Error::success();
}
std::error_code createStubInternal(StringRef StubName,
TargetAddress InitAddr,
JITSymbolFlags StubFlags) {
Error createStubInternal(StringRef StubName, TargetAddress InitAddr,
JITSymbolFlags StubFlags) {
auto Key = FreeStubs.back();
FreeStubs.pop_back();
StubIndexes[StubName] = std::make_pair(Key, StubFlags);
@ -500,23 +563,17 @@ public:
public:
RCCompileCallbackManager(TargetAddress ErrorHandlerAddress,
OrcRemoteTargetClient &Remote)
: JITCompileCallbackManager(ErrorHandlerAddress), Remote(Remote) {
assert(!Remote.CompileCallback && "Compile callback already set");
Remote.CompileCallback = [this](TargetAddress TrampolineAddr) {
return executeCompileCallback(TrampolineAddr);
};
Remote.emitResolverBlock();
}
: JITCompileCallbackManager(ErrorHandlerAddress), Remote(Remote) {}
private:
void grow() override {
TargetAddress BlockAddr = 0;
uint32_t NumTrampolines = 0;
if (auto TrampolineInfoOrErr = Remote.emitTrampolineBlock())
std::tie(BlockAddr, NumTrampolines) = *TrampolineInfoOrErr;
std::tie(BlockAddr, NumTrampolines) = *TrampolineInfoOrErr;
else {
// FIXME: Return error.
llvm_unreachable("Failed to create trampolines");
// FIXME: Return error.
llvm_unreachable("Failed to create trampolines");
}
uint32_t TrampolineSize = Remote.getTrampolineSize();
@ -530,85 +587,96 @@ public:
/// Create an OrcRemoteTargetClient.
/// Channel is the ChannelT instance to communicate on. It is assumed that
/// the channel is ready to be read from and written to.
static ErrorOr<OrcRemoteTargetClient> Create(ChannelT &Channel) {
std::error_code EC;
OrcRemoteTargetClient H(Channel, EC);
if (EC)
return EC;
return ErrorOr<OrcRemoteTargetClient>(std::move(H));
static Expected<OrcRemoteTargetClient> Create(ChannelT &Channel) {
Error Err;
OrcRemoteTargetClient H(Channel, Err);
if (Err)
return std::move(Err);
return Expected<OrcRemoteTargetClient>(std::move(H));
}
/// Call the int(void) function at the given address in the target and return
/// its result.
ErrorOr<int> callIntVoid(TargetAddress Addr) {
Expected<int> callIntVoid(TargetAddress Addr) {
DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n");
auto Listen =
[&](RPCChannel &C, uint32_t Id) {
return listenForCompileRequests(C, Id);
};
auto Listen = [&](RPCChannel &C, uint32_t Id) {
return listenForCompileRequests(C, Id);
};
return callSTHandling<CallIntVoid>(Channel, Listen, Addr);
}
/// Call the int(int, char*[]) function at the given address in the target and
/// return its result.
ErrorOr<int> callMain(TargetAddress Addr,
const std::vector<std::string> &Args) {
Expected<int> callMain(TargetAddress Addr,
const std::vector<std::string> &Args) {
DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr)
<< "\n");
auto Listen =
[&](RPCChannel &C, uint32_t Id) {
return listenForCompileRequests(C, Id);
};
auto Listen = [&](RPCChannel &C, uint32_t Id) {
return listenForCompileRequests(C, Id);
};
return callSTHandling<CallMain>(Channel, Listen, Addr, Args);
}
/// Call the void() function at the given address in the target and wait for
/// it to finish.
std::error_code callVoidVoid(TargetAddress Addr) {
Error callVoidVoid(TargetAddress Addr) {
DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr)
<< "\n");
auto Listen =
[&](RPCChannel &C, JITFuncId Id) {
return listenForCompileRequests(C, Id);
};
auto Listen = [&](RPCChannel &C, JITFuncId Id) {
return listenForCompileRequests(C, Id);
};
return callSTHandling<CallVoidVoid>(Channel, Listen, Addr);
}
/// Create an RCMemoryManager which will allocate its memory on the remote
/// target.
std::error_code
createRemoteMemoryManager(std::unique_ptr<RCMemoryManager> &MM) {
Error createRemoteMemoryManager(std::unique_ptr<RCMemoryManager> &MM) {
assert(!MM && "MemoryManager should be null before creation.");
auto Id = AllocatorIds.getNext();
if (auto EC = callST<CreateRemoteAllocator>(Channel, Id))
return EC;
if (auto Err = callST<CreateRemoteAllocator>(Channel, Id))
return Err;
MM = llvm::make_unique<RCMemoryManager>(*this, Id);
return std::error_code();
return Error::success();
}
/// Create an RCIndirectStubsManager that will allocate stubs on the remote
/// target.
std::error_code
createIndirectStubsManager(std::unique_ptr<RCIndirectStubsManager> &I) {
Error createIndirectStubsManager(std::unique_ptr<RCIndirectStubsManager> &I) {
assert(!I && "Indirect stubs manager should be null before creation.");
auto Id = IndirectStubOwnerIds.getNext();
if (auto EC = callST<CreateIndirectStubsOwner>(Channel, Id))
return EC;
if (auto Err = callST<CreateIndirectStubsOwner>(Channel, Id))
return Err;
I = llvm::make_unique<RCIndirectStubsManager>(*this, Id);
return std::error_code();
return Error::success();
}
Expected<RCCompileCallbackManager &>
enableCompileCallbacks(TargetAddress ErrorHandlerAddress) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return std::move(ExistingError);
// Emit the resolver block on the JIT server.
if (auto Err = callST<EmitResolverBlock>(Channel))
return std::move(Err);
// Create the callback manager.
CallbackManager.emplace(ErrorHandlerAddress, *this);
RCCompileCallbackManager &Mgr = *CallbackManager;
return Mgr;
}
/// Search for symbols in the remote process. Note: This should be used by
/// symbol resolvers *after* they've searched the local symbol table in the
/// JIT stack.
ErrorOr<TargetAddress> getSymbolAddress(StringRef Name) {
Expected<TargetAddress> getSymbolAddress(StringRef Name) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return ExistingError;
return std::move(ExistingError);
return callST<GetSymbolAddress>(Channel, Name);
}
@ -616,28 +684,25 @@ public:
/// Get the triple for the remote target.
const std::string &getTargetTriple() const { return RemoteTargetTriple; }
std::error_code terminateSession() {
return callST<TerminateSession>(Channel);
}
Error terminateSession() { return callST<TerminateSession>(Channel); }
private:
OrcRemoteTargetClient(ChannelT &Channel, std::error_code &EC)
: Channel(Channel) {
OrcRemoteTargetClient(ChannelT &Channel, Error &Err) : Channel(Channel) {
ErrorAsOutParameter EAO(Err);
if (auto RIOrErr = callST<GetRemoteInfo>(Channel)) {
std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
RemoteTrampolineSize, RemoteIndirectStubSize) =
*RIOrErr;
EC = std::error_code();
RemoteTrampolineSize, RemoteIndirectStubSize) = *RIOrErr;
Err = Error::success();
} else
EC = RIOrErr.getError();
Err = RIOrErr.takeError();
}
std::error_code deregisterEHFrames(TargetAddress Addr, uint32_t Size) {
Error deregisterEHFrames(TargetAddress Addr, uint32_t Size) {
return callST<RegisterEHFrames>(Channel, Addr, Size);
}
void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
if (auto EC = callST<DestroyRemoteAllocator>(Channel, Id)) {
if (auto Err = callST<DestroyRemoteAllocator>(Channel, Id)) {
// FIXME: This will be triggered by a removeModuleSet call: Propagate
// error return up through that.
llvm_unreachable("Failed to destroy remote allocator.");
@ -645,30 +710,20 @@ private:
}
}
std::error_code destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
Error destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
IndirectStubOwnerIds.release(Id);
return callST<DestroyIndirectStubsOwner>(Channel, Id);
}
ErrorOr<std::tuple<TargetAddress, TargetAddress, uint32_t>>
emitIndirectStubs(ResourceIdMgr::ResourceId Id,
uint32_t NumStubsRequired) {
Expected<std::tuple<TargetAddress, TargetAddress, uint32_t>>
emitIndirectStubs(ResourceIdMgr::ResourceId Id, uint32_t NumStubsRequired) {
return callST<EmitIndirectStubs>(Channel, Id, NumStubsRequired);
}
std::error_code emitResolverBlock() {
Expected<std::tuple<TargetAddress, uint32_t>> emitTrampolineBlock() {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return ExistingError;
return callST<EmitResolverBlock>(Channel);
}
ErrorOr<std::tuple<TargetAddress, uint32_t>>
emitTrampolineBlock() {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return ExistingError;
return std::move(ExistingError);
return callST<EmitTrampolineBlock>(Channel);
}
@ -679,75 +734,81 @@ private:
uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }
std::error_code listenForCompileRequests(RPCChannel &C, uint32_t &Id) {
Error listenForCompileRequests(RPCChannel &C, uint32_t &Id) {
assert(CallbackManager &&
"No calback manager. enableCompileCallbacks must be called first");
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return ExistingError;
return std::move(ExistingError);
if (Id == RequestCompileId) {
if (auto EC = handle<RequestCompile>(C, CompileCallback))
return EC;
return std::error_code();
if (auto Err = handle<RequestCompile>(
C, [&](TargetAddress Addr) -> Expected<TargetAddress> {
return CallbackManager->executeCompileCallback(Addr);
}))
return Err;
return Error::success();
}
// else
return orcError(OrcErrorCode::UnexpectedRPCCall);
}
ErrorOr<std::vector<char>> readMem(char *Dst, TargetAddress Src, uint64_t Size) {
Expected<std::vector<char>> readMem(char *Dst, TargetAddress Src,
uint64_t Size) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return ExistingError;
return std::move(ExistingError);
return callST<ReadMem>(Channel, Src, Size);
}
std::error_code registerEHFrames(TargetAddress &RAddr, uint32_t Size) {
Error registerEHFrames(TargetAddress &RAddr, uint32_t Size) {
return callST<RegisterEHFrames>(Channel, RAddr, Size);
}
ErrorOr<TargetAddress> reserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size,
uint32_t Align) {
Expected<TargetAddress> reserveMem(ResourceIdMgr::ResourceId Id,
uint64_t Size, uint32_t Align) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return ExistingError;
return std::move(ExistingError);
return callST<ReserveMem>(Channel, Id, Size, Align);
}
std::error_code setProtections(ResourceIdMgr::ResourceId Id,
TargetAddress RemoteSegAddr,
unsigned ProtFlags) {
Error setProtections(ResourceIdMgr::ResourceId Id,
TargetAddress RemoteSegAddr, unsigned ProtFlags) {
return callST<SetProtections>(Channel, Id, RemoteSegAddr, ProtFlags);
}
std::error_code writeMem(TargetAddress Addr, const char *Src, uint64_t Size) {
Error writeMem(TargetAddress Addr, const char *Src, uint64_t Size) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return ExistingError;
return std::move(ExistingError);
return callST<WriteMem>(Channel, DirectBufferWriter(Src, Addr, Size));
}
std::error_code writePointer(TargetAddress Addr, TargetAddress PtrVal) {
Error writePointer(TargetAddress Addr, TargetAddress PtrVal) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return ExistingError;
return std::move(ExistingError);
return callST<WritePtr>(Channel, Addr, PtrVal);
}
static std::error_code doNothing() { return std::error_code(); }
static Error doNothing() { return Error::success(); }
ChannelT &Channel;
std::error_code ExistingError;
Error ExistingError;
std::string RemoteTargetTriple;
uint32_t RemotePointerSize = 0;
uint32_t RemotePageSize = 0;
uint32_t RemoteTrampolineSize = 0;
uint32_t RemoteIndirectStubSize = 0;
ResourceIdMgr AllocatorIds, IndirectStubOwnerIds;
std::function<TargetAddress(TargetAddress)> CompileCallback;
Optional<RCCompileCallbackManager> CallbackManager;
};
} // end namespace remote

View File

@ -39,8 +39,8 @@ private:
uint64_t Size;
};
inline std::error_code serialize(RPCChannel &C,
const DirectBufferWriter &DBW) {
inline Error serialize(RPCChannel &C,
const DirectBufferWriter &DBW) {
if (auto EC = serialize(C, DBW.getDst()))
return EC;
if (auto EC = serialize(C, DBW.getSize()))
@ -48,8 +48,8 @@ inline std::error_code serialize(RPCChannel &C,
return C.appendBytes(DBW.getSrc(), DBW.getSize());
}
inline std::error_code deserialize(RPCChannel &C,
DirectBufferWriter &DBW) {
inline Error deserialize(RPCChannel &C,
DirectBufferWriter &DBW) {
TargetAddress Dst;
if (auto EC = deserialize(C, Dst))
return EC;
@ -69,6 +69,8 @@ protected:
class ResourceIdMgr {
public:
typedef uint64_t ResourceId;
static const ResourceId InvalidId = ~0U;
ResourceId getNext() {
if (!FreeIds.empty()) {
ResourceId I = FreeIds.back();

View File

@ -46,18 +46,17 @@ public:
EHFramesDeregister(std::move(EHFramesDeregister)) {}
// FIXME: Remove move/copy ops once MSVC supports synthesizing move ops.
OrcRemoteTargetServer(const OrcRemoteTargetServer&) = delete;
OrcRemoteTargetServer& operator=(const OrcRemoteTargetServer&) = delete;
OrcRemoteTargetServer(const OrcRemoteTargetServer &) = delete;
OrcRemoteTargetServer &operator=(const OrcRemoteTargetServer &) = delete;
OrcRemoteTargetServer(OrcRemoteTargetServer &&Other)
: Channel(Other.Channel),
SymbolLookup(std::move(Other.SymbolLookup)),
EHFramesRegister(std::move(Other.EHFramesRegister)),
EHFramesDeregister(std::move(Other.EHFramesDeregister)) {}
: Channel(Other.Channel), SymbolLookup(std::move(Other.SymbolLookup)),
EHFramesRegister(std::move(Other.EHFramesRegister)),
EHFramesDeregister(std::move(Other.EHFramesDeregister)) {}
OrcRemoteTargetServer& operator=(OrcRemoteTargetServer&&) = delete;
OrcRemoteTargetServer &operator=(OrcRemoteTargetServer &&) = delete;
std::error_code handleKnownFunction(JITFuncId Id) {
Error handleKnownFunction(JITFuncId Id) {
typedef OrcRemoteTargetServer ThisT;
DEBUG(dbgs() << "Handling known proc: " << getJITFuncIdName(Id) << "\n");
@ -119,17 +118,16 @@ public:
llvm_unreachable("Unhandled JIT RPC procedure Id.");
}
ErrorOr<TargetAddress> requestCompile(TargetAddress TrampolineAddr) {
auto Listen =
[&](RPCChannel &C, uint32_t Id) {
return handleKnownFunction(static_cast<JITFuncId>(Id));
};
Expected<TargetAddress> requestCompile(TargetAddress TrampolineAddr) {
auto Listen = [&](RPCChannel &C, uint32_t Id) {
return handleKnownFunction(static_cast<JITFuncId>(Id));
};
return callSTHandling<RequestCompile>(Channel, Listen, TrampolineAddr);
}
void handleTerminateSession() {
handle<TerminateSession>(Channel, [](){ return std::error_code(); });
Error handleTerminateSession() {
return handle<TerminateSession>(Channel, []() { return Error::success(); });
}
private:
@ -146,43 +144,43 @@ private:
sys::Memory::releaseMappedMemory(Alloc.second);
}
std::error_code allocate(void *&Addr, size_t Size, uint32_t Align) {
Error allocate(void *&Addr, size_t Size, uint32_t Align) {
std::error_code EC;
sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(
Size, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
if (EC)
return EC;
return errorCodeToError(EC);
Addr = MB.base();
assert(Allocs.find(MB.base()) == Allocs.end() && "Duplicate alloc");
Allocs[MB.base()] = std::move(MB);
return std::error_code();
return Error::success();
}
std::error_code setProtections(void *block, unsigned Flags) {
Error setProtections(void *block, unsigned Flags) {
auto I = Allocs.find(block);
if (I == Allocs.end())
return orcError(OrcErrorCode::RemoteMProtectAddrUnrecognized);
return sys::Memory::protectMappedMemory(I->second, Flags);
return errorCodeToError(
sys::Memory::protectMappedMemory(I->second, Flags));
}
private:
std::map<void *, sys::MemoryBlock> Allocs;
};
static std::error_code doNothing() { return std::error_code(); }
static Error doNothing() { return Error::success(); }
static TargetAddress reenter(void *JITTargetAddr, void *TrampolineAddr) {
auto T = static_cast<OrcRemoteTargetServer *>(JITTargetAddr);
auto AddrOrErr = T->requestCompile(
static_cast<TargetAddress>(
reinterpret_cast<uintptr_t>(TrampolineAddr)));
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;
}
ErrorOr<int32_t> handleCallIntVoid(TargetAddress Addr) {
Expected<int32_t> handleCallIntVoid(TargetAddress Addr) {
typedef int (*IntVoidFnTy)();
IntVoidFnTy Fn =
reinterpret_cast<IntVoidFnTy>(static_cast<uintptr_t>(Addr));
@ -194,8 +192,8 @@ private:
return Result;
}
ErrorOr<int32_t> handleCallMain(TargetAddress Addr,
std::vector<std::string> Args) {
Expected<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));
@ -213,7 +211,7 @@ private:
return Result;
}
std::error_code handleCallVoidVoid(TargetAddress Addr) {
Error handleCallVoidVoid(TargetAddress Addr) {
typedef void (*VoidVoidFnTy)();
VoidVoidFnTy Fn =
reinterpret_cast<VoidVoidFnTy>(static_cast<uintptr_t>(Addr));
@ -222,56 +220,55 @@ private:
Fn();
DEBUG(dbgs() << " Complete.\n");
return std::error_code();
return Error::success();
}
std::error_code handleCreateRemoteAllocator(ResourceIdMgr::ResourceId Id) {
Error handleCreateRemoteAllocator(ResourceIdMgr::ResourceId Id) {
auto I = Allocators.find(Id);
if (I != Allocators.end())
return orcError(OrcErrorCode::RemoteAllocatorIdAlreadyInUse);
DEBUG(dbgs() << " Created allocator " << Id << "\n");
Allocators[Id] = Allocator();
return std::error_code();
return Error::success();
}
std::error_code handleCreateIndirectStubsOwner(ResourceIdMgr::ResourceId Id) {
Error handleCreateIndirectStubsOwner(ResourceIdMgr::ResourceId Id) {
auto I = IndirectStubsOwners.find(Id);
if (I != IndirectStubsOwners.end())
return orcError(OrcErrorCode::RemoteIndirectStubsOwnerIdAlreadyInUse);
DEBUG(dbgs() << " Create indirect stubs owner " << Id << "\n");
IndirectStubsOwners[Id] = ISBlockOwnerList();
return std::error_code();
return Error::success();
}
std::error_code handleDeregisterEHFrames(TargetAddress TAddr, uint32_t Size) {
Error handleDeregisterEHFrames(TargetAddress TAddr, uint32_t Size) {
uint8_t *Addr = reinterpret_cast<uint8_t *>(static_cast<uintptr_t>(TAddr));
DEBUG(dbgs() << " Registering EH frames at " << format("0x%016x", TAddr)
<< ", Size = " << Size << " bytes\n");
EHFramesDeregister(Addr, Size);
return std::error_code();
return Error::success();
}
std::error_code handleDestroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
Error handleDestroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
auto I = Allocators.find(Id);
if (I == Allocators.end())
return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
Allocators.erase(I);
DEBUG(dbgs() << " Destroyed allocator " << Id << "\n");
return std::error_code();
return Error::success();
}
std::error_code
handleDestroyIndirectStubsOwner(ResourceIdMgr::ResourceId Id) {
Error handleDestroyIndirectStubsOwner(ResourceIdMgr::ResourceId Id) {
auto I = IndirectStubsOwners.find(Id);
if (I == IndirectStubsOwners.end())
return orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist);
IndirectStubsOwners.erase(I);
return std::error_code();
return Error::success();
}
ErrorOr<std::tuple<TargetAddress, TargetAddress, uint32_t>>
Expected<std::tuple<TargetAddress, TargetAddress, uint32_t>>
handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id,
uint32_t NumStubsRequired) {
uint32_t NumStubsRequired) {
DEBUG(dbgs() << " ISMgr " << Id << " request " << NumStubsRequired
<< " stubs.\n");
@ -280,9 +277,9 @@ private:
return orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist);
typename TargetT::IndirectStubsInfo IS;
if (auto EC =
if (auto Err =
TargetT::emitIndirectStubsBlock(IS, NumStubsRequired, nullptr))
return EC;
return std::move(Err);
TargetAddress StubsBase =
static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(IS.getStub(0)));
@ -296,31 +293,30 @@ private:
return std::make_tuple(StubsBase, PtrsBase, NumStubsEmitted);
}
std::error_code handleEmitResolverBlock() {
Error handleEmitResolverBlock() {
std::error_code EC;
ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
TargetT::ResolverCodeSize, nullptr,
sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
if (EC)
return EC;
return errorCodeToError(EC);
TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()),
&reenter, this);
return sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(),
sys::Memory::MF_READ |
sys::Memory::MF_EXEC);
return errorCodeToError(sys::Memory::protectMappedMemory(
ResolverBlock.getMemoryBlock(),
sys::Memory::MF_READ | sys::Memory::MF_EXEC));
}
ErrorOr<std::tuple<TargetAddress, uint32_t>>
handleEmitTrampolineBlock() {
Expected<std::tuple<TargetAddress, uint32_t>> handleEmitTrampolineBlock() {
std::error_code EC;
auto TrampolineBlock =
sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
sys::Process::getPageSize(), nullptr,
sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
if (EC)
return EC;
return errorCodeToError(EC);
uint32_t NumTrampolines =
(sys::Process::getPageSize() - TargetT::PointerSize) /
@ -337,19 +333,19 @@ private:
TrampolineBlocks.push_back(std::move(TrampolineBlock));
auto TrampolineBaseAddr =
static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(TrampolineMem));
static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(TrampolineMem));
return std::make_tuple(TrampolineBaseAddr, NumTrampolines);
}
ErrorOr<TargetAddress> handleGetSymbolAddress(const std::string &Name) {
Expected<TargetAddress> handleGetSymbolAddress(const std::string &Name) {
TargetAddress Addr = SymbolLookup(Name);
DEBUG(dbgs() << " Symbol '" << Name << "' = " << format("0x%016x", Addr)
<< "\n");
return Addr;
}
ErrorOr<std::tuple<std::string, uint32_t, uint32_t, uint32_t, uint32_t>>
Expected<std::tuple<std::string, uint32_t, uint32_t, uint32_t, uint32_t>>
handleGetRemoteInfo() {
std::string ProcessTriple = sys::getProcessTriple();
uint32_t PointerSize = TargetT::PointerSize;
@ -362,12 +358,11 @@ private:
<< " page size = " << PageSize << "\n"
<< " trampoline size = " << TrampolineSize << "\n"
<< " indirect stub size = " << IndirectStubSize << "\n");
return std::make_tuple(ProcessTriple, PointerSize, PageSize ,TrampolineSize,
IndirectStubSize);
return std::make_tuple(ProcessTriple, PointerSize, PageSize, TrampolineSize,
IndirectStubSize);
}
ErrorOr<std::vector<char>>
handleReadMem(TargetAddress RSrc, uint64_t Size) {
Expected<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 "
@ -381,24 +376,23 @@ private:
return Buffer;
}
std::error_code handleRegisterEHFrames(TargetAddress TAddr, uint32_t Size) {
Error handleRegisterEHFrames(TargetAddress TAddr, uint32_t Size) {
uint8_t *Addr = reinterpret_cast<uint8_t *>(static_cast<uintptr_t>(TAddr));
DEBUG(dbgs() << " Registering EH frames at " << format("0x%016x", TAddr)
<< ", Size = " << Size << " bytes\n");
EHFramesRegister(Addr, Size);
return std::error_code();
return Error::success();
}
ErrorOr<TargetAddress>
handleReserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size,
uint32_t Align) {
Expected<TargetAddress> handleReserveMem(ResourceIdMgr::ResourceId Id,
uint64_t Size, uint32_t Align) {
auto I = Allocators.find(Id);
if (I == Allocators.end())
return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
auto &Allocator = I->second;
void *LocalAllocAddr = nullptr;
if (auto EC = Allocator.allocate(LocalAllocAddr, Size, Align))
return EC;
if (auto Err = Allocator.allocate(LocalAllocAddr, Size, Align))
return std::move(Err);
DEBUG(dbgs() << " Allocator " << Id << " reserved " << LocalAllocAddr
<< " (" << Size << " bytes, alignment " << Align << ")\n");
@ -409,8 +403,8 @@ private:
return AllocAddr;
}
std::error_code handleSetProtections(ResourceIdMgr::ResourceId Id,
TargetAddress Addr, uint32_t Flags) {
Error handleSetProtections(ResourceIdMgr::ResourceId Id, TargetAddress Addr,
uint32_t Flags) {
auto I = Allocators.find(Id);
if (I == Allocators.end())
return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
@ -423,19 +417,19 @@ private:
return Allocator.setProtections(LocalAddr, Flags);
}
std::error_code handleWriteMem(DirectBufferWriter DBW) {
Error handleWriteMem(DirectBufferWriter DBW) {
DEBUG(dbgs() << " Writing " << DBW.getSize() << " bytes to "
<< format("0x%016x", DBW.getDst()) << "\n");
return std::error_code();
<< format("0x%016x", DBW.getDst()) << "\n");
return Error::success();
}
std::error_code handleWritePtr(TargetAddress Addr, TargetAddress PtrVal) {
Error handleWritePtr(TargetAddress Addr, TargetAddress PtrVal) {
DEBUG(dbgs() << " Writing pointer *" << format("0x%016x", Addr) << " = "
<< format("0x%016x", PtrVal) << "\n");
uintptr_t *Ptr =
reinterpret_cast<uintptr_t *>(static_cast<uintptr_t>(Addr));
*Ptr = static_cast<uintptr_t>(PtrVal);
return std::error_code();
return Error::success();
}
ChannelT &Channel;

View File

@ -21,19 +21,19 @@ public:
virtual ~RPCChannel() {}
/// Read Size bytes from the stream into *Dst.
virtual std::error_code readBytes(char *Dst, unsigned Size) = 0;
virtual Error readBytes(char *Dst, unsigned Size) = 0;
/// Read size bytes from *Src and append them to the stream.
virtual std::error_code appendBytes(const char *Src, unsigned Size) = 0;
virtual Error appendBytes(const char *Src, unsigned Size) = 0;
/// Flush the stream if possible.
virtual std::error_code send() = 0;
virtual Error send() = 0;
/// Get the lock for stream reading.
std::mutex& getReadLock() { return readLock; }
std::mutex &getReadLock() { return readLock; }
/// Get the lock for stream writing.
std::mutex& getWriteLock() { return writeLock; }
std::mutex &getWriteLock() { return writeLock; }
private:
std::mutex readLock, writeLock;
@ -41,57 +41,53 @@ private:
/// Notify the channel that we're starting a message send.
/// Locks the channel for writing.
inline std::error_code startSendMessage(RPCChannel &C) {
inline Error startSendMessage(RPCChannel &C) {
C.getWriteLock().lock();
return std::error_code();
return Error::success();
}
/// Notify the channel that we're ending a message send.
/// Unlocks the channel for writing.
inline std::error_code endSendMessage(RPCChannel &C) {
inline Error endSendMessage(RPCChannel &C) {
C.getWriteLock().unlock();
return std::error_code();
return Error::success();
}
/// Notify the channel that we're starting a message receive.
/// Locks the channel for reading.
inline std::error_code startReceiveMessage(RPCChannel &C) {
inline Error startReceiveMessage(RPCChannel &C) {
C.getReadLock().lock();
return std::error_code();
return Error::success();
}
/// Notify the channel that we're ending a message receive.
/// Unlocks the channel for reading.
inline std::error_code endReceiveMessage(RPCChannel &C) {
inline Error endReceiveMessage(RPCChannel &C) {
C.getReadLock().unlock();
return std::error_code();
return Error::success();
}
/// RPC channel serialization for a variadic list of arguments.
template <typename T, typename... Ts>
std::error_code serializeSeq(RPCChannel &C, const T &Arg, const Ts &... Args) {
if (auto EC = serialize(C, Arg))
return EC;
Error serializeSeq(RPCChannel &C, const T &Arg, const Ts &... Args) {
if (auto Err = serialize(C, Arg))
return Err;
return serializeSeq(C, Args...);
}
/// RPC channel serialization for an (empty) variadic list of arguments.
inline std::error_code serializeSeq(RPCChannel &C) {
return std::error_code();
}
inline Error serializeSeq(RPCChannel &C) { return Error::success(); }
/// RPC channel deserialization for a variadic list of arguments.
template <typename T, typename... Ts>
std::error_code deserializeSeq(RPCChannel &C, T &Arg, Ts &... Args) {
if (auto EC = deserialize(C, Arg))
return EC;
Error deserializeSeq(RPCChannel &C, T &Arg, Ts &... Args) {
if (auto Err = deserialize(C, Arg))
return Err;
return deserializeSeq(C, Args...);
}
/// RPC channel serialization for an (empty) variadic list of arguments.
inline std::error_code deserializeSeq(RPCChannel &C) {
return std::error_code();
}
inline Error deserializeSeq(RPCChannel &C) { return Error::success(); }
/// RPC channel serialization for integer primitives.
template <typename T>
@ -100,7 +96,7 @@ typename std::enable_if<
std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value ||
std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value,
std::error_code>::type
Error>::type
serialize(RPCChannel &C, T V) {
support::endian::byte_swap<T, support::big>(V);
return C.appendBytes(reinterpret_cast<const char *>(&V), sizeof(T));
@ -113,130 +109,125 @@ typename std::enable_if<
std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value ||
std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value,
std::error_code>::type
Error>::type
deserialize(RPCChannel &C, T &V) {
if (auto EC = C.readBytes(reinterpret_cast<char *>(&V), sizeof(T)))
return EC;
if (auto Err = C.readBytes(reinterpret_cast<char *>(&V), sizeof(T)))
return Err;
support::endian::byte_swap<T, support::big>(V);
return std::error_code();
return Error::success();
}
/// RPC channel serialization for enums.
template <typename T>
typename std::enable_if<std::is_enum<T>::value, std::error_code>::type
typename std::enable_if<std::is_enum<T>::value, Error>::type
serialize(RPCChannel &C, T V) {
return serialize(C, static_cast<typename std::underlying_type<T>::type>(V));
}
/// RPC channel deserialization for enums.
template <typename T>
typename std::enable_if<std::is_enum<T>::value, std::error_code>::type
typename std::enable_if<std::is_enum<T>::value, Error>::type
deserialize(RPCChannel &C, T &V) {
typename std::underlying_type<T>::type Tmp;
std::error_code EC = deserialize(C, Tmp);
Error Err = deserialize(C, Tmp);
V = static_cast<T>(Tmp);
return EC;
return Err;
}
/// RPC channel serialization for bools.
inline std::error_code serialize(RPCChannel &C, bool V) {
inline Error serialize(RPCChannel &C, bool V) {
uint8_t VN = V ? 1 : 0;
return C.appendBytes(reinterpret_cast<const char *>(&VN), 1);
}
/// RPC channel deserialization for bools.
inline std::error_code deserialize(RPCChannel &C, bool &V) {
inline Error deserialize(RPCChannel &C, bool &V) {
uint8_t VN = 0;
if (auto EC = C.readBytes(reinterpret_cast<char *>(&VN), 1))
return EC;
if (auto Err = C.readBytes(reinterpret_cast<char *>(&VN), 1))
return Err;
V = (VN != 0) ? true : false;
return std::error_code();
return Error::success();
}
/// RPC channel serialization for StringRefs.
/// Note: There is no corresponding deseralization for this, as StringRef
/// doesn't own its memory and so can't hold the deserialized data.
inline std::error_code serialize(RPCChannel &C, StringRef S) {
if (auto EC = serialize(C, static_cast<uint64_t>(S.size())))
return EC;
inline Error serialize(RPCChannel &C, StringRef S) {
if (auto Err = serialize(C, static_cast<uint64_t>(S.size())))
return Err;
return C.appendBytes((const char *)S.bytes_begin(), S.size());
}
/// RPC channel serialization for std::strings.
inline std::error_code serialize(RPCChannel &C, const std::string &S) {
inline Error serialize(RPCChannel &C, const std::string &S) {
return serialize(C, StringRef(S));
}
/// RPC channel deserialization for std::strings.
inline std::error_code deserialize(RPCChannel &C, std::string &S) {
inline Error deserialize(RPCChannel &C, std::string &S) {
uint64_t Count;
if (auto EC = deserialize(C, Count))
return EC;
if (auto Err = deserialize(C, Count))
return Err;
S.resize(Count);
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...> _) {
inline Error 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) {
inline Error 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...> _) {
inline Error 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) {
inline Error 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) {
if (auto EC = serialize(C, static_cast<uint64_t>(A.size())))
return EC;
template <typename T> Error serialize(RPCChannel &C, const ArrayRef<T> &A) {
if (auto Err = serialize(C, static_cast<uint64_t>(A.size())))
return Err;
for (const auto &E : A)
if (auto EC = serialize(C, E))
return EC;
if (auto Err = serialize(C, E))
return Err;
return std::error_code();
return Error::success();
}
/// RPC channel serialization for std::array<T>.
template <typename T>
std::error_code serialize(RPCChannel &C, const std::vector<T> &V) {
template <typename T> Error serialize(RPCChannel &C, const std::vector<T> &V) {
return serialize(C, ArrayRef<T>(V));
}
/// RPC channel deserialization for std::array<T>.
template <typename T>
std::error_code deserialize(RPCChannel &C, std::vector<T> &V) {
template <typename T> Error deserialize(RPCChannel &C, std::vector<T> &V) {
uint64_t Count = 0;
if (auto EC = deserialize(C, Count))
return EC;
if (auto Err = deserialize(C, Count))
return Err;
V.resize(Count);
for (auto &E : V)
if (auto EC = deserialize(C, E))
return EC;
if (auto Err = deserialize(C, E))
return Err;
return std::error_code();
return Error::success();
}
} // end namespace remote

View File

@ -20,7 +20,6 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ExecutionEngine/Orc/OrcError.h"
#include "llvm/Support/ErrorOr.h"
#ifdef _MSC_VER
// concrt.h depends on eh.h for __uncaught_exception declaration
@ -94,7 +93,7 @@ protected:
typedef Optional<RetT> OptionalReturn;
typedef ErrorOr<RetT> ErrorReturn;
typedef Expected<RetT> ErrorReturn;
static ErrorReturn optionalToErrorReturn(OptionalReturn &&V) {
assert(V && "Return value not available");
@ -102,21 +101,18 @@ protected:
}
template <typename ChannelT>
static std::error_code readResult(ChannelT &C,
std::promise<OptionalReturn> &P) {
static Error readResult(ChannelT &C, std::promise<OptionalReturn> &P) {
RetT Val;
auto EC = deserialize(C, Val);
// FIXME: Join error EC2 from endReceiveMessage with the deserialize
// error once we switch to using Error.
auto EC2 = endReceiveMessage(C);
(void)EC2;
auto Err = deserialize(C, Val);
auto Err2 = endReceiveMessage(C);
Err = joinErrors(std::move(Err), std::move(Err2));
if (EC) {
if (Err) {
P.set_value(OptionalReturn());
return EC;
return Err;
}
P.set_value(std::move(Val));
return std::error_code();
return Error::success();
}
static void abandon(std::promise<OptionalReturn> &P) {
@ -124,19 +120,19 @@ protected:
}
template <typename ChannelT, typename SequenceNumberT>
static std::error_code respond(ChannelT &C, SequenceNumberT SeqNo,
const ErrorReturn &Result) {
static Error respond(ChannelT &C, SequenceNumberT SeqNo,
ErrorReturn &Result) {
FunctionIdT ResponseId = RPCFunctionIdTraits<FunctionIdT>::ResponseId;
// If the handler returned an error then bail out with that.
if (!Result)
return Result.getError();
return Result.takeError();
// Otherwise open a new message on the channel and send the result.
if (auto EC = startSendMessage(C))
return EC;
if (auto EC = serializeSeq(C, ResponseId, SeqNo, *Result))
return EC;
if (auto Err = startSendMessage(C))
return Err;
if (auto Err = serializeSeq(C, ResponseId, SeqNo, *Result))
return Err;
return endSendMessage(C);
}
};
@ -153,16 +149,15 @@ protected:
static const FunctionIdT Id = FuncId;
typedef bool OptionalReturn;
typedef std::error_code ErrorReturn;
typedef Error ErrorReturn;
static ErrorReturn optionalToErrorReturn(OptionalReturn &&V) {
assert(V && "Return value not available");
return std::error_code();
return Error::success();
}
template <typename ChannelT>
static std::error_code readResult(ChannelT &C,
std::promise<OptionalReturn> &P) {
static Error readResult(ChannelT &C, std::promise<OptionalReturn> &P) {
// Void functions don't have anything to deserialize, so we're good.
P.set_value(true);
return endReceiveMessage(C);
@ -171,20 +166,20 @@ protected:
static void abandon(std::promise<OptionalReturn> &P) { P.set_value(false); }
template <typename ChannelT, typename SequenceNumberT>
static std::error_code respond(ChannelT &C, SequenceNumberT SeqNo,
const ErrorReturn &Result) {
static Error respond(ChannelT &C, SequenceNumberT SeqNo,
ErrorReturn &Result) {
const FunctionIdT ResponseId =
RPCFunctionIdTraits<FunctionIdT>::ResponseId;
// If the handler returned an error then bail out with that.
if (Result)
return Result;
return std::move(Result);
// Otherwise open a new message on the channel and send the result.
if (auto EC = startSendMessage(C))
return EC;
if (auto EC = serializeSeq(C, ResponseId, SeqNo))
return EC;
if (auto Err = startSendMessage(C))
return Err;
if (auto Err = serializeSeq(C, ResponseId, SeqNo))
return Err;
return endSendMessage(C);
}
};
@ -198,12 +193,12 @@ protected:
class CallHelper<ChannelT, SequenceNumberT,
FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)>> {
public:
static std::error_code call(ChannelT &C, SequenceNumberT SeqNo,
const ArgTs &... Args) {
if (auto EC = startSendMessage(C))
return EC;
if (auto EC = serializeSeq(C, FuncId, SeqNo, Args...))
return EC;
static Error call(ChannelT &C, SequenceNumberT SeqNo,
const ArgTs &... Args) {
if (auto Err = startSendMessage(C))
return Err;
if (auto Err = serializeSeq(C, FuncId, SeqNo, Args...))
return Err;
return endSendMessage(C);
}
};
@ -218,7 +213,7 @@ protected:
FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)>> {
public:
template <typename HandlerT>
static std::error_code handle(ChannelT &C, HandlerT Handler) {
static Error handle(ChannelT &C, HandlerT Handler) {
return readAndHandle(C, Handler, llvm::index_sequence_for<ArgTs...>());
}
@ -226,24 +221,28 @@ protected:
typedef FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)> Func;
template <typename HandlerT, size_t... Is>
static std::error_code readAndHandle(ChannelT &C, HandlerT Handler,
llvm::index_sequence<Is...> _) {
static Error readAndHandle(ChannelT &C, HandlerT Handler,
llvm::index_sequence<Is...> _) {
std::tuple<ArgTs...> RPCArgs;
SequenceNumberT SeqNo;
// GCC 4.7 and 4.8 incorrectly issue a -Wunused-but-set-variable warning
// for RPCArgs. Void cast RPCArgs to work around this for now.
// FIXME: Remove this workaround once we can assume a working GCC version.
(void)RPCArgs;
if (auto EC = deserializeSeq(C, SeqNo, std::get<Is>(RPCArgs)...))
return EC;
if (auto Err = deserializeSeq(C, SeqNo, std::get<Is>(RPCArgs)...))
return Err;
// We've deserialized the arguments, so unlock the channel for reading
// before we call the handler. This allows recursive RPC calls.
if (auto EC = endReceiveMessage(C))
return EC;
if (auto Err = endReceiveMessage(C))
return Err;
return Func::template respond<ChannelT, SequenceNumberT>(
C, SeqNo, Handler(std::get<Is>(RPCArgs)...));
// Run the handler and get the result.
auto Result = Handler(std::get<Is>(RPCArgs)...);
// Return the result to the client.
return Func::template respond<ChannelT, SequenceNumberT>(C, SeqNo,
Result);
}
};
@ -264,7 +263,7 @@ protected:
// Helper that provides a Functor for deserializing arguments.
template <typename... ArgTs> class ReadArgs {
public:
std::error_code operator()() { return std::error_code(); }
Error operator()() { return Error::success(); }
};
template <typename ArgT, typename... ArgTs>
@ -273,7 +272,7 @@ protected:
ReadArgs(ArgT &Arg, ArgTs &... Args)
: ReadArgs<ArgTs...>(Args...), Arg(Arg) {}
std::error_code operator()(ArgT &ArgVal, ArgTs &... ArgVals) {
Error operator()(ArgT &ArgVal, ArgTs &... ArgVals) {
this->Arg = std::move(ArgVal);
return ReadArgs<ArgTs...>::operator()(ArgVals...);
}
@ -313,13 +312,13 @@ protected:
/// arguments and sending the resulting bytes to 'Channel'.
///
///
/// handle<Func>(Channel, <functor matching std::error_code(Args...)> :
/// handle<Func>(Channel, <functor matching Error(Args...)> :
///
/// Handles a call to 'Func' by deserializing its arguments and calling the
/// given functor. This assumes that the id for 'Func' has already been
/// deserialized.
///
/// expect<Func>(Channel, <functor matching std::error_code(Args...)> :
/// expect<Func>(Channel, <functor matching Error(Args...)> :
///
/// The same as 'handle', except that the procedure id should not have been
/// read yet. Expect will deserialize the id and assert that it matches Func's
@ -367,15 +366,15 @@ public:
/// typedef Function<0, bool> Func1;
/// typedef Function<1, std::string, std::vector<int>> Func2;
///
/// if (auto EC = call<Func1>(Channel, true))
/// /* handle EC */;
/// if (auto Err = call<Func1>(Channel, true))
/// /* handle Err */;
///
/// if (auto EC = expect<Func2>(Channel,
/// if (auto Err = expect<Func2>(Channel,
/// [](std::string &S, std::vector<int> &V) {
/// // Stuff.
/// return std::error_code();
/// return Error::success();
/// })
/// /* handle EC */;
/// /* handle Err */;
///
template <FunctionIdT FuncId, typename FnT>
using Function = FunctionHelper<FunctionIdT, FuncId, FnT>;
@ -400,18 +399,18 @@ public:
/// result. In multi-threaded mode the appendCallAsync method, which does not
/// return the sequence numeber, should be preferred.
template <typename Func, typename... ArgTs>
ErrorOr<AsyncCallWithSeqResult<Func>>
Expected<AsyncCallWithSeqResult<Func>>
appendCallAsyncWithSeq(ChannelT &C, const ArgTs &... Args) {
auto SeqNo = SequenceNumberMgr.getSequenceNumber();
std::promise<typename Func::OptionalReturn> Promise;
auto Result = Promise.get_future();
OutstandingResults[SeqNo] =
createOutstandingResult<Func>(std::move(Promise));
createOutstandingResult<Func>(std::move(Promise));
if (auto EC = CallHelper<ChannelT, SequenceNumberT, Func>::call(C, SeqNo,
if (auto Err = CallHelper<ChannelT, SequenceNumberT, Func>::call(C, SeqNo,
Args...)) {
abandonOutstandingResults();
return EC;
return std::move(Err);
} else
return AsyncCallWithSeqResult<Func>(std::move(Result), SeqNo);
}
@ -419,14 +418,14 @@ public:
/// The same as appendCallAsyncWithSeq, except that it calls C.send() to
/// flush the channel after serializing the call.
template <typename Func, typename... ArgTs>
ErrorOr<AsyncCallWithSeqResult<Func>>
Expected<AsyncCallWithSeqResult<Func>>
callAsyncWithSeq(ChannelT &C, const ArgTs &... Args) {
auto Result = appendCallAsyncWithSeq<Func>(C, Args...);
if (!Result)
return Result;
if (auto EC = C.send()) {
if (auto Err = C.send()) {
abandonOutstandingResults();
return EC;
return std::move(Err);
}
return Result;
}
@ -435,8 +434,8 @@ public:
/// Returns an error if serialization fails, otherwise returns a
/// std::future<Optional<T>> (or a future<bool> for void functions).
template <typename Func, typename... ArgTs>
ErrorOr<AsyncCallResult<Func>>
appendCallAsync(ChannelT &C, const ArgTs &... Args) {
Expected<AsyncCallResult<Func>> appendCallAsync(ChannelT &C,
const ArgTs &... Args) {
auto ResAndSeqOrErr = appendCallAsyncWithSeq<Func>(C, Args...);
if (ResAndSeqOrErr)
return std::move(ResAndSeqOrErr->first);
@ -446,8 +445,7 @@ public:
/// The same as appendCallAsync, except that it calls C.send to flush the
/// channel after serializing the call.
template <typename Func, typename... ArgTs>
ErrorOr<AsyncCallResult<Func>>
callAsync(ChannelT &C, const ArgTs &... Args) {
Expected<AsyncCallResult<Func>> callAsync(ChannelT &C, const ArgTs &... Args) {
auto ResAndSeqOrErr = callAsyncWithSeq<Func>(C, Args...);
if (ResAndSeqOrErr)
return std::move(ResAndSeqOrErr->first);
@ -460,11 +458,11 @@ public:
callSTHandling(ChannelT &C, HandleFtor &HandleOther, const ArgTs &... Args) {
if (auto ResultAndSeqNoOrErr = callAsyncWithSeq<Func>(C, Args...)) {
auto &ResultAndSeqNo = *ResultAndSeqNoOrErr;
if (auto EC = waitForResult(C, ResultAndSeqNo.second, HandleOther))
return EC;
if (auto Err = waitForResult(C, ResultAndSeqNo.second, HandleOther))
return std::move(Err);
return Func::optionalToErrorReturn(ResultAndSeqNo.first.get());
} else
return ResultAndSeqNoOrErr.getError();
return ResultAndSeqNoOrErr.takeError();
}
// This can be used in single-threaded mode.
@ -477,25 +475,25 @@ public:
///
/// Calls startReceiveMessage on the channel, then deserializes a FunctionId
/// into Id.
std::error_code startReceivingFunction(ChannelT &C, FunctionIdT &Id) {
if (auto EC = startReceiveMessage(C))
return EC;
Error startReceivingFunction(ChannelT &C, FunctionIdT &Id) {
if (auto Err = startReceiveMessage(C))
return Err;
return deserialize(C, Id);
}
/// Deserialize args for Func from C and call Handler. The signature of
/// handler must conform to 'std::error_code(Args...)' where Args... matches
/// handler must conform to 'Error(Args...)' where Args... matches
/// the arguments used in the Func typedef.
template <typename Func, typename HandlerT>
static std::error_code handle(ChannelT &C, HandlerT Handler) {
static Error handle(ChannelT &C, HandlerT Handler) {
return HandlerHelper<ChannelT, SequenceNumberT, Func>::handle(C, Handler);
}
/// Helper version of 'handle' for calling member functions.
template <typename Func, typename ClassT, typename RetT, typename... ArgTs>
static std::error_code handle(ChannelT &C, ClassT &Instance,
RetT (ClassT::*HandlerMethod)(ArgTs...)) {
static Error handle(ChannelT &C, ClassT &Instance,
RetT (ClassT::*HandlerMethod)(ArgTs...)) {
return handle<Func>(
C, MemberFnWrapper<ClassT, RetT, ArgTs...>(Instance, HandlerMethod));
}
@ -506,10 +504,10 @@ public:
/// If the id does not match, return an unexpect RPC call error and do not
/// deserialize any further bytes.
template <typename Func, typename HandlerT>
std::error_code expect(ChannelT &C, HandlerT Handler) {
Error expect(ChannelT &C, HandlerT Handler) {
FunctionIdT FuncId;
if (auto EC = startReceivingFunction(C, FuncId))
return std::move(EC);
if (auto Err = startReceivingFunction(C, FuncId))
return std::move(Err);
if (FuncId != Func::Id)
return orcError(OrcErrorCode::UnexpectedRPCCall);
return handle<Func>(C, Handler);
@ -517,9 +515,8 @@ public:
/// Helper version of expect for calling member functions.
template <typename Func, typename ClassT, typename... ArgTs>
static std::error_code
expect(ChannelT &C, ClassT &Instance,
std::error_code (ClassT::*HandlerMethod)(ArgTs...)) {
static Error expect(ChannelT &C, ClassT &Instance,
Error (ClassT::*HandlerMethod)(ArgTs...)) {
return expect<Func>(
C, MemberFnWrapper<ClassT, ArgTs...>(Instance, HandlerMethod));
}
@ -534,7 +531,7 @@ public:
/// ...
/// bool B;
/// int I;
/// if (auto EC = expect<Func1>(Channel, readArgs(B, I)))
/// if (auto Err = expect<Func1>(Channel, readArgs(B, I)))
/// /* Handle Args */ ;
///
template <typename... ArgTs>
@ -544,12 +541,11 @@ public:
/// Read a response from Channel.
/// This should be called from the receive loop to retrieve results.
std::error_code handleResponse(ChannelT &C,
SequenceNumberT *SeqNoRet = nullptr) {
Error handleResponse(ChannelT &C, SequenceNumberT *SeqNoRet = nullptr) {
SequenceNumberT SeqNo;
if (auto EC = deserialize(C, SeqNo)) {
if (auto Err = deserialize(C, SeqNo)) {
abandonOutstandingResults();
return EC;
return Err;
}
if (SeqNoRet)
@ -561,44 +557,44 @@ public:
return orcError(OrcErrorCode::UnexpectedRPCResponse);
}
if (auto EC = I->second->readResult(C)) {
if (auto Err = I->second->readResult(C)) {
abandonOutstandingResults();
// FIXME: Release sequence numbers?
return EC;
return Err;
}
OutstandingResults.erase(I);
SequenceNumberMgr.releaseSequenceNumber(SeqNo);
return std::error_code();
return Error::success();
}
// Loop waiting for a result with the given sequence number.
// This can be used as a receive loop if the user doesn't have a default.
template <typename HandleOtherFtor>
std::error_code waitForResult(ChannelT &C, SequenceNumberT TgtSeqNo,
HandleOtherFtor &HandleOther = handleNone) {
Error waitForResult(ChannelT &C, SequenceNumberT TgtSeqNo,
HandleOtherFtor &HandleOther = handleNone) {
bool GotTgtResult = false;
while (!GotTgtResult) {
FunctionIdT Id = RPCFunctionIdTraits<FunctionIdT>::InvalidId;
if (auto EC = startReceivingFunction(C, Id))
return EC;
if (auto Err = startReceivingFunction(C, Id))
return Err;
if (Id == RPCFunctionIdTraits<FunctionIdT>::ResponseId) {
SequenceNumberT SeqNo;
if (auto EC = handleResponse(C, &SeqNo))
return EC;
if (auto Err = handleResponse(C, &SeqNo))
return Err;
GotTgtResult = (SeqNo == TgtSeqNo);
} else if (auto EC = HandleOther(C, Id))
return EC;
} else if (auto Err = HandleOther(C, Id))
return Err;
}
return std::error_code();
return Error::success();
}
// Default handler for 'other' (non-response) functions when waiting for a
// result from the channel.
static std::error_code handleNone(ChannelT &, FunctionIdT) {
static Error handleNone(ChannelT &, FunctionIdT) {
return orcError(OrcErrorCode::UnexpectedRPCCall);
};
@ -608,8 +604,8 @@ private:
public:
SequenceNumberManager() = default;
SequenceNumberManager(const SequenceNumberManager&) = delete;
SequenceNumberManager& operator=(const SequenceNumberManager&) = delete;
SequenceNumberManager(const SequenceNumberManager &) = delete;
SequenceNumberManager &operator=(const SequenceNumberManager &) = delete;
SequenceNumberManager(SequenceNumberManager &&Other)
: NextSequenceNumber(std::move(Other.NextSequenceNumber)),
@ -651,7 +647,7 @@ private:
class OutstandingResult {
public:
virtual ~OutstandingResult() {}
virtual std::error_code readResult(ChannelT &C) = 0;
virtual Error readResult(ChannelT &C) = 0;
virtual void abandon() = 0;
};
@ -663,9 +659,7 @@ private:
OutstandingResultImpl(std::promise<typename Func::OptionalReturn> &&P)
: P(std::move(P)) {}
std::error_code readResult(ChannelT &C) override {
return Func::readResult(C, P);
}
Error readResult(ChannelT &C) override { return Func::readResult(C, P); }
void abandon() override { Func::abandon(P); }

View File

@ -94,9 +94,9 @@ void OrcX86_64::writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
Trampolines[I] = CallIndirPCRel | ((OffsetToPtr - 6) << 16);
}
std::error_code OrcX86_64::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
unsigned MinStubs,
void *InitialPtrVal) {
Error OrcX86_64::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
unsigned MinStubs,
void *InitialPtrVal) {
// Stub format is:
//
// .section __orc_stubs
@ -134,7 +134,7 @@ std::error_code OrcX86_64::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
EC));
if (EC)
return EC;
return errorCodeToError(EC);
// Create separate MemoryBlocks representing the stubs and pointers.
sys::MemoryBlock StubsBlock(StubsMem.base(), NumPages * PageSize);
@ -152,7 +152,7 @@ std::error_code OrcX86_64::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
if (auto EC = sys::Memory::protectMappedMemory(StubsBlock,
sys::Memory::MF_READ |
sys::Memory::MF_EXEC))
return EC;
return errorCodeToError(EC);
// Initialize all pointers to point at FailureAddress.
void **Ptr = reinterpret_cast<void**>(PtrsBlock.base());
@ -161,7 +161,7 @@ std::error_code OrcX86_64::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
StubsInfo = IndirectStubsInfo(NumStubs, std::move(StubsMem));
return std::error_code();
return Error::success();
}
void OrcI386::writeResolverCode(uint8_t *ResolverMem, JITReentryFn ReentryFn,
@ -223,9 +223,9 @@ void OrcI386::writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
Trampolines[I] = CallRelImm | (ResolverRel << 8);
}
std::error_code OrcI386::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
unsigned MinStubs,
void *InitialPtrVal) {
Error OrcI386::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
unsigned MinStubs,
void *InitialPtrVal) {
// Stub format is:
//
// .section __orc_stubs
@ -263,7 +263,7 @@ std::error_code OrcI386::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
EC));
if (EC)
return EC;
return errorCodeToError(EC);
// Create separate MemoryBlocks representing the stubs and pointers.
sys::MemoryBlock StubsBlock(StubsMem.base(), NumPages * PageSize);
@ -280,7 +280,7 @@ std::error_code OrcI386::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
if (auto EC = sys::Memory::protectMappedMemory(StubsBlock,
sys::Memory::MF_READ |
sys::Memory::MF_EXEC))
return EC;
return errorCodeToError(EC);
// Initialize all pointers to point at FailureAddress.
void **Ptr = reinterpret_cast<void**>(PtrsBlock.base());
@ -289,7 +289,7 @@ std::error_code OrcI386::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
StubsInfo = IndirectStubsInfo(NumStubs, std::move(StubsMem));
return std::error_code();
return Error::success();
}
} // End namespace orc.

View File

@ -28,6 +28,11 @@ LLVMOrcJITStackRef LLVMOrcCreateInstance(LLVMTargetMachineRef TM) {
return wrap(JITStack);
}
const char *LLVMOrcGetErrorMsg(LLVMOrcJITStackRef JITStack) {
OrcCBindingsStack &J = *unwrap(JITStack);
return J.getErrorMessage().c_str();
}
void LLVMOrcGetMangledSymbol(LLVMOrcJITStackRef JITStack, char **MangledName,
const char *SymbolName) {
OrcCBindingsStack &J = *unwrap(JITStack);
@ -48,18 +53,18 @@ LLVMOrcCreateLazyCompileCallback(LLVMOrcJITStackRef JITStack,
return J.createLazyCompileCallback(Callback, CallbackCtx);
}
void LLVMOrcCreateIndirectStub(LLVMOrcJITStackRef JITStack,
const char *StubName,
LLVMOrcTargetAddress InitAddr) {
LLVMOrcErrorCode LLVMOrcCreateIndirectStub(LLVMOrcJITStackRef JITStack,
const char *StubName,
LLVMOrcTargetAddress InitAddr) {
OrcCBindingsStack &J = *unwrap(JITStack);
J.createIndirectStub(StubName, InitAddr);
return J.createIndirectStub(StubName, InitAddr);
}
void LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack,
const char *StubName,
LLVMOrcTargetAddress NewAddr) {
LLVMOrcErrorCode LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack,
const char *StubName,
LLVMOrcTargetAddress NewAddr) {
OrcCBindingsStack &J = *unwrap(JITStack);
J.setIndirectStubPointer(StubName, NewAddr);
return J.setIndirectStubPointer(StubName, NewAddr);
}
LLVMOrcModuleHandle

View File

@ -17,6 +17,7 @@
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/Error.h"
#include "llvm-c/OrcBindings.h"
namespace llvm {
@ -131,12 +132,16 @@ public:
return CCInfo.getAddress();
}
void createIndirectStub(StringRef StubName, orc::TargetAddress Addr) {
IndirectStubsMgr->createStub(StubName, Addr, JITSymbolFlags::Exported);
LLVMOrcErrorCode
createIndirectStub(StringRef StubName, orc::TargetAddress Addr) {
return mapError(
IndirectStubsMgr->createStub(StubName, Addr,
JITSymbolFlags::Exported));
}
void setIndirectStubPointer(StringRef Name, orc::TargetAddress Addr) {
IndirectStubsMgr->updatePointer(Name, Addr);
LLVMOrcErrorCode
setIndirectStubPointer(StringRef Name, orc::TargetAddress Addr) {
return mapError(IndirectStubsMgr->updatePointer(Name, Addr));
}
std::shared_ptr<RuntimeDyld::SymbolResolver>
@ -243,6 +248,10 @@ public:
return GenericHandles[H]->findSymbolIn(Name, ExportedSymbolsOnly);
}
const std::string& getErrorMessage() const {
return ErrMsg;
}
private:
template <typename LayerT>
@ -261,6 +270,19 @@ private:
return NewHandle;
}
LLVMOrcErrorCode mapError(Error Err) {
LLVMOrcErrorCode Result = LLVMOrcErrSuccess;
handleAllErrors(std::move(Err),
[&](ErrorInfoBase &EIB) {
// Handler of last resort.
Result = LLVMOrcErrGeneric;
ErrMsg = "";
raw_string_ostream ErrStream(ErrMsg);
EIB.log(ErrStream);
});
return Result;
}
DataLayout DL;
SectionMemoryManager CCMgrMemMgr;
@ -276,6 +298,7 @@ private:
orc::LocalCXXRuntimeOverrides CXXRuntimeOverrides;
std::vector<orc::CtorDtorRunner<OrcCBindingsStack>> IRStaticDestructorRunners;
std::string ErrMsg;
};
} // end namespace llvm

View File

@ -51,9 +51,10 @@ static ManagedStatic<OrcErrorCategory> OrcErrCat;
namespace llvm {
namespace orc {
std::error_code orcError(OrcErrorCode ErrCode) {
Error orcError(OrcErrorCode ErrCode) {
typedef std::underlying_type<OrcErrorCode>::type UT;
return std::error_code(static_cast<UT>(ErrCode), *OrcErrCat);
return errorCodeToError(std::error_code(static_cast<UT>(ErrCode),
*OrcErrCat));
}
}
}

View File

@ -17,6 +17,8 @@ typedef OrcX86_64 HostOrcArch;
typedef OrcGenericArchitecture HostOrcArch;
#endif
ExitOnError ExitOnErr;
int main(int argc, char *argv[]) {
if (argc != 3) {
@ -24,6 +26,8 @@ int main(int argc, char *argv[]) {
return 1;
}
ExitOnErr.setBanner(std::string(argv[0]) + ":");
int InFD;
int OutFD;
{
@ -55,20 +59,15 @@ int main(int argc, char *argv[]) {
while (1) {
uint32_t RawId;
if (auto EC = Server.startReceivingFunction(Channel, RawId)) {
errs() << "Error: " << EC.message() << "\n";
return 1;
}
ExitOnErr(Server.startReceivingFunction(Channel, RawId));
auto Id = static_cast<JITServer::JITFuncId>(RawId);
switch (Id) {
case JITServer::TerminateSessionId:
Server.handleTerminateSession();
ExitOnErr(Server.handleTerminateSession());
return 0;
default:
if (auto EC = Server.handleKnownFunction(Id)) {
errs() << "Error: " << EC.message() << "\n";
return 1;
}
ExitOnErr(Server.handleKnownFunction(Id));
break;
}
}

View File

@ -29,23 +29,43 @@ class FDRPCChannel final : public llvm::orc::remote::RPCChannel {
public:
FDRPCChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {}
std::error_code readBytes(char *Dst, unsigned Size) override {
llvm::Error readBytes(char *Dst, unsigned Size) override {
assert(Dst && "Attempt to read into null.");
ssize_t ReadResult = ::read(InFD, Dst, Size);
if (ReadResult != (ssize_t)Size)
return std::error_code(errno, std::generic_category());
return std::error_code();
ssize_t Completed = 0;
while (Completed < Size) {
ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed);
if (Read <= 0) {
auto ErrNo = errno;
if (ErrNo == EAGAIN || ErrNo == EINTR)
continue;
else
return llvm::errorCodeToError(
std::error_code(errno, std::generic_category()));
}
Completed += Read;
}
return llvm::Error::success();
}
std::error_code appendBytes(const char *Src, unsigned Size) override {
llvm::Error appendBytes(const char *Src, unsigned Size) override {
assert(Src && "Attempt to append from null.");
ssize_t WriteResult = ::write(OutFD, Src, Size);
if (WriteResult != (ssize_t)Size)
std::error_code(errno, std::generic_category());
return std::error_code();
ssize_t Completed = 0;
while (Completed < Size) {
ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed);
if (Written < 0) {
auto ErrNo = errno;
if (ErrNo == EAGAIN || ErrNo == EINTR)
continue;
else
return llvm::errorCodeToError(
std::error_code(errno, std::generic_category()));
}
Completed += Written;
}
return llvm::Error::success();
}
std::error_code send() override { return std::error_code(); }
llvm::Error send() override { return llvm::Error::success(); }
private:
int InFD, OutFD;

View File

@ -235,6 +235,8 @@ namespace {
clEnumValN(FloatABI::Hard, "hard",
"Hard float ABI (uses FP registers)"),
clEnumValEnd));
ExitOnError ExitOnErr;
}
//===----------------------------------------------------------------------===//
@ -373,6 +375,9 @@ int main(int argc, char **argv, char * const *envp) {
atexit(llvm_shutdown); // Call llvm_shutdown() on exit.
if (argc > 1)
ExitOnErr.setBanner(std::string(argv[0]) + ": ");
// If we have a native target, initialize it to ensure it is linked in and
// usable by the JIT.
InitializeNativeTarget();
@ -648,18 +653,11 @@ int main(int argc, char **argv, char * const *envp) {
// Create a remote target client running over the channel.
typedef orc::remote::OrcRemoteTargetClient<orc::remote::RPCChannel> MyRemote;
ErrorOr<MyRemote> R = MyRemote::Create(*C);
if (!R) {
errs() << "Could not create remote: " << R.getError().message() << "\n";
exit(1);
}
MyRemote R = ExitOnErr(MyRemote::Create(*C));
// Create a remote memory manager.
std::unique_ptr<MyRemote::RCMemoryManager> RemoteMM;
if (auto EC = R->createRemoteMemoryManager(RemoteMM)) {
errs() << "Could not create remote memory manager: " << EC.message() << "\n";
exit(1);
}
ExitOnErr(R.createRemoteMemoryManager(RemoteMM));
// Forward MCJIT's memory manager calls to the remote memory manager.
static_cast<ForwardingMemoryManager*>(RTDyldMM)->setMemMgr(
@ -669,13 +667,9 @@ int main(int argc, char **argv, char * const *envp) {
static_cast<ForwardingMemoryManager*>(RTDyldMM)->setResolver(
orc::createLambdaResolver(
[&](const std::string &Name) {
if (auto AddrOrErr = R->getSymbolAddress(Name))
return RuntimeDyld::SymbolInfo(*AddrOrErr, JITSymbolFlags::Exported);
else {
errs() << "Failure during symbol lookup: "
<< AddrOrErr.getError().message() << "\n";
exit(1);
}
if (auto Addr = ExitOnErr(R.getSymbolAddress(Name)))
return RuntimeDyld::SymbolInfo(Addr, JITSymbolFlags::Exported);
return RuntimeDyld::SymbolInfo(nullptr);
},
[](const std::string &Name) { return nullptr; }
));
@ -687,10 +681,7 @@ int main(int argc, char **argv, char * const *envp) {
EE->finalizeObject();
DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at 0x"
<< format("%llx", Entry) << "\n");
if (auto ResultOrErr = R->callIntVoid(Entry))
Result = *ResultOrErr;
else
errs() << "ERROR: " << ResultOrErr.getError().message() << "\n";
Result = ExitOnErr(R.callIntVoid(Entry));
// Like static constructors, the remote target MCJIT support doesn't handle
// this yet. It could. FIXME.
@ -701,7 +692,7 @@ int main(int argc, char **argv, char * const *envp) {
EE.reset();
// Signal the remote target that we're done JITing.
R->terminateSession();
ExitOnErr(R.terminateSession());
}
return Result;

View File

@ -25,12 +25,12 @@ public:
class DummyStubsManager : public orc::IndirectStubsManager {
public:
std::error_code createStub(StringRef StubName, TargetAddress InitAddr,
Error createStub(StringRef StubName, TargetAddress InitAddr,
JITSymbolFlags Flags) override {
llvm_unreachable("Not implemented");
}
std::error_code createStubs(const StubInitsMap &StubInits) override {
Error createStubs(const StubInitsMap &StubInits) override {
llvm_unreachable("Not implemented");
}
@ -42,7 +42,7 @@ public:
llvm_unreachable("Not implemented");
}
std::error_code updatePointer(StringRef Name,
Error updatePointer(StringRef Name,
TargetAddress NewAddr) override {
llvm_unreachable("Not implemented");
}

View File

@ -29,7 +29,7 @@ public:
QueueChannel(Queue &InQueue, Queue &OutQueue)
: InQueue(InQueue), OutQueue(OutQueue) {}
std::error_code readBytes(char *Dst, unsigned Size) override {
Error readBytes(char *Dst, unsigned Size) override {
while (Size != 0) {
// If there's nothing to read then yield.
while (InQueue.empty())
@ -43,17 +43,17 @@ public:
InQueue.pop();
}
}
return std::error_code();
return Error::success();
}
std::error_code appendBytes(const char *Src, unsigned Size) override {
Error appendBytes(const char *Src, unsigned Size) override {
std::lock_guard<std::mutex> Lock(OutQueue.getLock());
while (Size--)
OutQueue.push(*Src++);
return std::error_code();
return Error::success();
}
std::error_code send() override { return std::error_code(); }
Error send() override { return Error::success(); }
private:
Queue &InQueue;
@ -95,7 +95,7 @@ TEST_F(DummyRPC, TestAsyncVoidBool) {
[&](bool &B) {
EXPECT_EQ(B, true)
<< "Bool serialization broken";
return std::error_code();
return Error::success();
});
EXPECT_FALSE(EC) << "Simple expect over queue failed";
}
@ -123,7 +123,7 @@ TEST_F(DummyRPC, TestAsyncIntInt) {
{
// Expect a call to Proc1.
auto EC = expect<IntInt>(C2,
[&](int32_t I) {
[&](int32_t I) -> Expected<int32_t> {
EXPECT_EQ(I, 21)
<< "Bool serialization broken";
return 2 * I;
@ -202,7 +202,7 @@ TEST_F(DummyRPC, TestSerialization) {
<< "std::string serialization broken";
EXPECT_EQ(v, std::vector<int>({42, 7}))
<< "std::vector serialization broken";
return std::error_code();
return Error::success();
});
EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed";
}