16#define DEBUG_TYPE "orc"
23 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
24 assert(Disconnected &&
"Destroyed without disconnection");
32 RunAsMainAddr,
Result, MainFnAddr, Args))
33 return std::move(Err);
40 RunAsVoidFunctionAddr,
Result, VoidFnAddr))
41 return std::move(Err);
49 RunAsIntFunctionAddr,
Result, IntFnAddr, Arg))
50 return std::move(Err);
59 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
60 SeqNo = getNextSeqNo();
61 assert(!PendingCallWrapperResults.count(SeqNo) &&
"SeqNo already in use");
62 PendingCallWrapperResults[SeqNo] = std::move(OnComplete);
66 WrapperFnAddr, ArgBuffer)) {
75 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
76 auto I = PendingCallWrapperResults.find(SeqNo);
77 if (
I != PendingCallWrapperResults.end()) {
78 H = std::move(
I->second);
79 PendingCallWrapperResults.erase(
I);
94 return DM.takeError();
95 return std::make_unique<EPCGenericDylibManager>(std::move(*
DM));
114 return std::move(Err);
116 return std::make_unique<EPCGenericMemoryAccess>(*
this, FAs);
122 std::unique_lock<std::mutex> Lock(SimpleRemoteEPCMutex);
123 DisconnectCV.wait(Lock, [
this] {
return Disconnected; });
124 return std::move(DisconnectErr);
133 dbgs() <<
"SimpleRemoteEPC::handleMessage: opc = ";
137 assert(SeqNo == 0 &&
"Non-zero SeqNo for Setup?");
138 assert(!TagAddr &&
"Non-zero TagAddr for Setup?");
142 assert(SeqNo == 0 &&
"Non-zero SeqNo for Hangup?");
143 assert(!TagAddr &&
"Non-zero TagAddr for Hangup?");
147 assert(!TagAddr &&
"Non-zero TagAddr for Result?");
150 dbgs() <<
"CallWrapper";
153 dbgs() <<
", seqno = " << SeqNo <<
", tag-addr = " << TagAddr
154 <<
", arg-buffer = " <<
formatv(
"{0:x}", ArgBytes.
size())
158 using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
165 if (
auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))
166 return std::move(Err);
170 if (
auto Err = handleHangup(std::move(ArgBytes)))
171 return std::move(Err);
174 if (
auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
175 return std::move(Err);
178 handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
186 dbgs() <<
"SimpleRemoteEPC::handleDisconnect: "
187 << (Err ?
"failure" :
"success") <<
"\n";
190 PendingCallWrapperResultsMap TmpPending;
193 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
194 std::swap(TmpPending, PendingCallWrapperResults);
197 for (
auto &KV : TmpPending)
201 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
202 DisconnectErr =
joinErrors(std::move(DisconnectErr), std::move(Err));
204 DisconnectCV.notify_all();
211 {{SAs.Allocator, rt::SimpleExecutorMemoryManagerInstanceName},
212 {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
214 rt::SimpleExecutorMemoryManagerInitializeWrapperName},
215 {SAs.Release, rt::SimpleExecutorMemoryManagerReleaseWrapperName}}))
216 return std::move(Err);
218 return std::make_unique<EPCGenericJITLinkMemoryManager>(SREPC, SAs);
221Error SimpleRemoteEPC::sendMessage(SimpleRemoteEPCOpcode OpC,
uint64_t SeqNo,
222 ExecutorAddr TagAddr,
223 ArrayRef<char> ArgBytes) {
224 assert(OpC != SimpleRemoteEPCOpcode::Setup &&
225 "SimpleRemoteEPC sending Setup message? That's the wrong direction.");
228 dbgs() <<
"SimpleRemoteEPC::sendMessage: opc = ";
230 case SimpleRemoteEPCOpcode::Hangup:
232 assert(SeqNo == 0 &&
"Non-zero SeqNo for Hangup?");
233 assert(!TagAddr &&
"Non-zero TagAddr for Hangup?");
235 case SimpleRemoteEPCOpcode::Result:
237 assert(!TagAddr &&
"Non-zero TagAddr for Result?");
239 case SimpleRemoteEPCOpcode::CallWrapper:
240 dbgs() <<
"CallWrapper";
245 dbgs() <<
", seqno = " << SeqNo <<
", tag-addr = " << TagAddr
246 <<
", arg-buffer = " <<
formatv(
"{0:x}", ArgBytes.size())
249 auto Err =
T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes);
252 dbgs() <<
" \\--> SimpleRemoteEPC::sendMessage failed\n";
257Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddr TagAddr,
258 shared::WrapperFunctionBuffer ArgBytes) {
267 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
268 auto I = PendingCallWrapperResults.find(0);
269 assert(PendingCallWrapperResults.size() == 1 &&
270 I != PendingCallWrapperResults.end() &&
271 "Setup message handler not connectly set up");
272 auto SetupMsgHandler = std::move(
I->second);
273 PendingCallWrapperResults.erase(
I);
276 shared::WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
277 SetupMsgHandler(std::move(WFR));
281Error SimpleRemoteEPC::setup(Setup S) {
282 using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
284 std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> EIP;
285 auto EIF = EIP.get_future();
288 PendingCallWrapperResults[0] =
290 [&](shared::WrapperFunctionBuffer SetupMsgBytes) {
291 if (
const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
297 shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
298 shared::SPSInputBuffer
IB(SetupMsgBytes.data(), SetupMsgBytes.size());
299 SimpleRemoteEPCExecutorInfo EI;
300 if (SPSSerialize::deserialize(IB, EI))
308 if (
auto Err =
T->start())
315 return EI.takeError();
319 dbgs() <<
"SimpleRemoteEPC received setup message:\n"
320 <<
" Triple: " << EI->TargetTriple <<
"\n"
321 <<
" Page size: " << EI->PageSize <<
"\n"
322 <<
" Bootstrap map" << (EI->BootstrapMap.empty() ?
" empty" :
":")
324 for (
const auto &KV : EI->BootstrapMap)
325 dbgs() <<
" " << KV.first() <<
": " << KV.second.size()
326 <<
"-byte SPS encoded buffer\n";
327 dbgs() <<
" Bootstrap symbols"
328 << (EI->BootstrapSymbols.empty() ?
" empty" :
":") <<
"\n";
329 for (
const auto &KV : EI->BootstrapSymbols)
330 dbgs() <<
" " << KV.first() <<
": " << KV.second <<
"\n";
332 TargetTriple =
Triple(EI->TargetTriple);
334 BootstrapMap = std::move(EI->BootstrapMap);
335 BootstrapSymbols = std::move(EI->BootstrapSymbols);
337 if (
auto Err = getBootstrapSymbols(
340 {RunAsMainAddr, rt::RunAsMainWrapperName},
341 {RunAsVoidFunctionAddr, rt::RunAsVoidFunctionWrapperName},
342 {RunAsIntFunctionAddr, rt::RunAsIntFunctionWrapperName}}))
346 if (!S.CreateMemoryManager)
347 S.CreateMemoryManager = createDefaultMemoryManager;
349 if (
auto MemMgr = S.CreateMemoryManager(*
this)) {
350 OwnedMemMgr = std::move(*MemMgr);
351 this->MemMgr = OwnedMemMgr.get();
353 return MemMgr.takeError();
358Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddr TagAddr,
359 shared::WrapperFunctionBuffer ArgBytes) {
360 IncomingWFRHandler SendResult;
367 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
368 auto I = PendingCallWrapperResults.find(SeqNo);
369 if (
I == PendingCallWrapperResults.end())
373 SendResult = std::move(
I->second);
374 PendingCallWrapperResults.erase(
I);
379 shared::WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
380 SendResult(std::move(WFR));
384void SimpleRemoteEPC::handleCallWrapper(
385 uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
386 shared::WrapperFunctionBuffer ArgBytes) {
387 assert(ES &&
"No ExecutionSession attached");
389 [
this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]()
mutable {
390 ES->runJITDispatchHandler(
391 [
this, RemoteSeqNo](shared::WrapperFunctionBuffer WFR) {
393 sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
394 ExecutorAddr(), {WFR.data(), WFR.size()}))
395 getExecutionSession().reportError(std::move(Err));
397 TagAddr, std::move(ArgBytes));
399 "callWrapper task"));
402Error SimpleRemoteEPC::handleHangup(shared::WrapperFunctionBuffer ArgBytes) {
404 auto WFR = WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
405 if (
const char *ErrMsg = WFR.getOutOfBandError())
409 SPSInputBuffer
IB(WFR.data(), WFR.size());
410 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.