15#define DEBUG_TYPE "orc"
22 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
23 assert(Disconnected &&
"Destroyed without disconnection");
31 RunAsMainAddr,
Result, MainFnAddr, Args))
32 return std::move(Err);
39 RunAsVoidFunctionAddr,
Result, VoidFnAddr))
40 return std::move(Err);
48 RunAsIntFunctionAddr,
Result, IntFnAddr, Arg))
49 return std::move(Err);
58 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
59 SeqNo = getNextSeqNo();
60 assert(!PendingCallWrapperResults.count(SeqNo) &&
"SeqNo already in use");
61 PendingCallWrapperResults[SeqNo] = std::move(OnComplete);
65 WrapperFnAddr, ArgBuffer)) {
74 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
75 auto I = PendingCallWrapperResults.find(SeqNo);
76 if (
I != PendingCallWrapperResults.end()) {
77 H = std::move(
I->second);
78 PendingCallWrapperResults.erase(
I);
93 return DM.takeError();
94 return std::make_unique<EPCGenericDylibManager>(std::move(*
DM));
113 return std::move(Err);
115 return std::make_unique<EPCGenericMemoryAccess>(*
this, FAs);
121 std::unique_lock<std::mutex> Lock(SimpleRemoteEPCMutex);
122 DisconnectCV.wait(Lock, [
this] {
return Disconnected; });
123 return std::move(DisconnectErr);
132 dbgs() <<
"SimpleRemoteEPC::handleMessage: opc = ";
136 assert(SeqNo == 0 &&
"Non-zero SeqNo for Setup?");
137 assert(!TagAddr &&
"Non-zero TagAddr for Setup?");
141 assert(SeqNo == 0 &&
"Non-zero SeqNo for Hangup?");
142 assert(!TagAddr &&
"Non-zero TagAddr for Hangup?");
146 assert(!TagAddr &&
"Non-zero TagAddr for Result?");
149 dbgs() <<
"CallWrapper";
152 dbgs() <<
", seqno = " << SeqNo <<
", tag-addr = " << TagAddr
153 <<
", arg-buffer = " <<
formatv(
"{0:x}", ArgBytes.
size())
157 using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
164 if (
auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))
165 return std::move(Err);
169 if (
auto Err = handleHangup(std::move(ArgBytes)))
170 return std::move(Err);
173 if (
auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
174 return std::move(Err);
177 handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
185 dbgs() <<
"SimpleRemoteEPC::handleDisconnect: "
186 << (Err ?
"failure" :
"success") <<
"\n";
189 PendingCallWrapperResultsMap TmpPending;
192 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
193 std::swap(TmpPending, PendingCallWrapperResults);
196 for (
auto &KV : TmpPending)
200 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
201 DisconnectErr =
joinErrors(std::move(DisconnectErr), std::move(Err));
203 DisconnectCV.notify_all();
210 {{SAs.Allocator, rt::SimpleExecutorMemoryManagerInstanceName},
211 {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
213 rt::SimpleExecutorMemoryManagerInitializeWrapperName},
214 {SAs.Release, rt::SimpleExecutorMemoryManagerReleaseWrapperName}}))
215 return std::move(Err);
217 return std::make_unique<EPCGenericJITLinkMemoryManager>(SREPC, SAs);
220Error SimpleRemoteEPC::sendMessage(SimpleRemoteEPCOpcode OpC,
uint64_t SeqNo,
221 ExecutorAddr TagAddr,
222 ArrayRef<char> ArgBytes) {
223 assert(OpC != SimpleRemoteEPCOpcode::Setup &&
224 "SimpleRemoteEPC sending Setup message? That's the wrong direction.");
227 dbgs() <<
"SimpleRemoteEPC::sendMessage: opc = ";
229 case SimpleRemoteEPCOpcode::Hangup:
231 assert(SeqNo == 0 &&
"Non-zero SeqNo for Hangup?");
232 assert(!TagAddr &&
"Non-zero TagAddr for Hangup?");
234 case SimpleRemoteEPCOpcode::Result:
236 assert(!TagAddr &&
"Non-zero TagAddr for Result?");
238 case SimpleRemoteEPCOpcode::CallWrapper:
239 dbgs() <<
"CallWrapper";
244 dbgs() <<
", seqno = " << SeqNo <<
", tag-addr = " << TagAddr
245 <<
", arg-buffer = " <<
formatv(
"{0:x}", ArgBytes.size())
248 auto Err =
T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes);
251 dbgs() <<
" \\--> SimpleRemoteEPC::sendMessage failed\n";
256Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddr TagAddr,
257 shared::WrapperFunctionBuffer ArgBytes) {
266 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
267 auto I = PendingCallWrapperResults.find(0);
268 assert(PendingCallWrapperResults.size() == 1 &&
269 I != PendingCallWrapperResults.end() &&
270 "Setup message handler not connectly set up");
271 auto SetupMsgHandler = std::move(
I->second);
272 PendingCallWrapperResults.erase(
I);
275 shared::WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
276 SetupMsgHandler(std::move(WFR));
280Error SimpleRemoteEPC::setup(Setup S) {
281 using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
283 std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> EIP;
284 auto EIF = EIP.get_future();
287 PendingCallWrapperResults[0] =
289 [&](shared::WrapperFunctionBuffer SetupMsgBytes) {
290 if (
const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
296 shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
297 shared::SPSInputBuffer
IB(SetupMsgBytes.data(), SetupMsgBytes.size());
298 SimpleRemoteEPCExecutorInfo EI;
299 if (SPSSerialize::deserialize(IB, EI))
307 if (
auto Err =
T->start())
314 return EI.takeError();
318 dbgs() <<
"SimpleRemoteEPC received setup message:\n"
319 <<
" Triple: " << EI->TargetTriple <<
"\n"
320 <<
" Page size: " << EI->PageSize <<
"\n"
321 <<
" Bootstrap map" << (EI->BootstrapMap.empty() ?
" empty" :
":")
323 for (
const auto &KV : EI->BootstrapMap)
324 dbgs() <<
" " << KV.first() <<
": " << KV.second.size()
325 <<
"-byte SPS encoded buffer\n";
326 dbgs() <<
" Bootstrap symbols"
327 << (EI->BootstrapSymbols.empty() ?
" empty" :
":") <<
"\n";
328 for (
const auto &KV : EI->BootstrapSymbols)
329 dbgs() <<
" " << KV.first() <<
": " << KV.second <<
"\n";
331 TargetTriple =
Triple(EI->TargetTriple);
333 BootstrapMap = std::move(EI->BootstrapMap);
334 BootstrapSymbols = std::move(EI->BootstrapSymbols);
336 if (
auto Err = getBootstrapSymbols(
339 {RunAsMainAddr, rt::RunAsMainWrapperName},
340 {RunAsVoidFunctionAddr, rt::RunAsVoidFunctionWrapperName},
341 {RunAsIntFunctionAddr, rt::RunAsIntFunctionWrapperName}}))
345 if (!S.CreateMemoryManager)
346 S.CreateMemoryManager = createDefaultMemoryManager;
348 if (
auto MemMgr = S.CreateMemoryManager(*
this)) {
349 OwnedMemMgr = std::move(*MemMgr);
350 this->MemMgr = OwnedMemMgr.get();
352 return MemMgr.takeError();
357Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddr TagAddr,
358 shared::WrapperFunctionBuffer ArgBytes) {
359 IncomingWFRHandler SendResult;
366 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
367 auto I = PendingCallWrapperResults.find(SeqNo);
368 if (
I == PendingCallWrapperResults.end())
372 SendResult = std::move(
I->second);
373 PendingCallWrapperResults.erase(
I);
378 shared::WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
379 SendResult(std::move(WFR));
383void SimpleRemoteEPC::handleCallWrapper(
384 uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
385 shared::WrapperFunctionBuffer ArgBytes) {
386 assert(ES &&
"No ExecutionSession attached");
388 [
this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]()
mutable {
389 ES->runJITDispatchHandler(
390 [
this, RemoteSeqNo](shared::WrapperFunctionBuffer WFR) {
392 sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
393 ExecutorAddr(), {WFR.data(), WFR.size()}))
394 getExecutionSession().reportError(std::move(Err));
396 TagAddr, std::move(ArgBytes));
398 "callWrapper task"));
401Error SimpleRemoteEPC::handleHangup(shared::WrapperFunctionBuffer ArgBytes) {
403 auto WFR = WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
404 if (
const char *ErrMsg = WFR.getOutOfBandError())
408 SPSInputBuffer
IB(WFR.data(), WFR.size());
409 if (!SPSArgList<SPSError>::deserialize(IB, Info))
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static RegisterPass< DebugifyModulePass > DM("debugify", "Attach debug info to everything")
static cl::opt< int > PageSize("imp-null-check-page-size", cl::desc("The page size of the target in bytes"), cl::init(4096), cl::Hidden)
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Triple - Helper class for working with autoconf configuration names.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
static LLVM_ABI Expected< EPCGenericDylibManager > CreateWithDefaultBootstrapSymbols(ExecutorProcessControl &EPC)
Create an EPCGenericMemoryAccess instance from a given set of function addrs.
void reportError(Error Err)
Report a error for this execution session.
Represents an address in the executor process.
A handler or incoming WrapperFunctionBuffers – either return values from callWrapper* calls,...
std::unique_ptr< TaskDispatcher > D
Error callSPSWrapper(ExecutorAddr WrapperFnAddr, WrapperCallArgTs &&...WrapperCallArgs)
Run a wrapper function using SPS to serialize the arguments and deserialize the results.
Error getBootstrapSymbols(ArrayRef< std::pair< ExecutorAddr &, StringRef > > Pairs) const
For each (ExecutorAddr&, StringRef) pair, looks up the string in the bootstrap symbols map and writes...
ExecutionSession & getExecutionSession()
Return the ExecutionSession associated with this instance.
void handleDisconnect(Error Err) override
Handle a disconnection from the underlying transport.
Expected< std::unique_ptr< MemoryAccess > > createDefaultMemoryAccess() override
Create a default MemoryAccess for the target process.
Expected< int32_t > runAsMain(ExecutorAddr MainFnAddr, ArrayRef< std::string > Args) override
Run function with a main-like signature.
Expected< HandleMessageAction > handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, ExecutorAddr TagAddr, shared::WrapperFunctionBuffer ArgBytes) override
Handle receipt of a message.
~SimpleRemoteEPC() override
Expected< std::unique_ptr< DylibManager > > createDefaultDylibMgr() override
Create a default DylibManager for the target process.
Error disconnect() override
Disconnect from the target process.
Expected< int32_t > runAsVoidFunction(ExecutorAddr VoidFnAddr) override
Run function with a int (*)(void) signature.
void callWrapperAsync(ExecutorAddr WrapperFnAddr, IncomingWFRHandler OnComplete, ArrayRef< char > ArgBuffer) override
Run a wrapper function in the executor.
Expected< int32_t > runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override
Run function with a int (*)(int) signature.
C++ wrapper function buffer: Same as CWrapperFunctionBuffer but auto-releases memory.
size_t size() const
Returns the size of the data contained in this instance.
static WrapperFunctionBuffer createOutOfBandError(const char *Msg)
Create an out-of-band error by copying the given string.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LLVM_ABI const char * DispatchFnName
LLVM_ABI const char * ExecutorSessionObjectName
LLVM_ABI const char * MemoryReadUInt64sWrapperName
LLVM_ABI const char * MemoryWriteUInt16sWrapperName
LLVM_ABI const char * MemoryReadStringsWrapperName
LLVM_ABI const char * MemoryReadUInt16sWrapperName
LLVM_ABI const char * MemoryReadUInt32sWrapperName
LLVM_ABI const char * MemoryWriteUInt64sWrapperName
LLVM_ABI const char * MemoryWriteUInt8sWrapperName
LLVM_ABI const char * MemoryWritePointersWrapperName
LLVM_ABI const char * MemoryWriteUInt32sWrapperName
LLVM_ABI const char * MemoryWriteBuffersWrapperName
LLVM_ABI const char * MemoryReadBuffersWrapperName
LLVM_ABI const char * MemoryReadUInt8sWrapperName
Error fromSPSSerializable(SPSSerializableError BSE)
std::unique_ptr< GenericNamedTask > makeGenericNamedTask(FnT &&Fn, std::string Desc)
Create a generic named task from a std::string description.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
Error joinErrors(Error E1, Error E2)
Concatenate errors.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Symbol addresses for memory management implementation.
Function addresses for memory access.
ExecutorAddr WritePointers
ExecutorAddr WriteUInt64s
ExecutorAddr WriteUInt16s
ExecutorAddr WriteUInt32s
ExecutorAddr WriteBuffers
Helper type for serializing Errors.