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);
99 return DM.takeError();
100 return std::make_unique<EPCGenericDylibManager>(std::move(*
DM));
119 return std::move(Err);
121 return std::make_unique<EPCGenericMemoryAccess>(*
this, FAs);
127 std::unique_lock<std::mutex> Lock(SimpleRemoteEPCMutex);
128 DisconnectCV.wait(Lock, [
this] {
return Disconnected; });
129 return std::move(DisconnectErr);
138 dbgs() <<
"SimpleRemoteEPC::handleMessage: opc = ";
142 assert(SeqNo == 0 &&
"Non-zero SeqNo for Setup?");
143 assert(!TagAddr &&
"Non-zero TagAddr for Setup?");
147 assert(SeqNo == 0 &&
"Non-zero SeqNo for Hangup?");
148 assert(!TagAddr &&
"Non-zero TagAddr for Hangup?");
152 assert(!TagAddr &&
"Non-zero TagAddr for Result?");
155 dbgs() <<
"CallWrapper";
158 dbgs() <<
", seqno = " << SeqNo <<
", tag-addr = " << TagAddr
159 <<
", arg-buffer = " <<
formatv(
"{0:x}", ArgBytes.
size())
163 using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
170 if (
auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))
171 return std::move(Err);
175 if (
auto Err = handleHangup(std::move(ArgBytes)))
176 return std::move(Err);
179 if (
auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
180 return std::move(Err);
183 handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
191 dbgs() <<
"SimpleRemoteEPC::handleDisconnect: "
192 << (Err ?
"failure" :
"success") <<
"\n";
195 PendingCallWrapperResultsMap TmpPending;
198 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
199 std::swap(TmpPending, PendingCallWrapperResults);
202 for (
auto &KV : TmpPending)
206 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
207 DisconnectErr =
joinErrors(std::move(DisconnectErr), std::move(Err));
209 DisconnectCV.notify_all();
216 {{SAs.Allocator, rt::SimpleExecutorMemoryManagerInstanceName},
217 {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
219 rt::SimpleExecutorMemoryManagerInitializeWrapperName},
220 {SAs.Release, rt::SimpleExecutorMemoryManagerReleaseWrapperName}}))
221 return std::move(Err);
223 return std::make_unique<EPCGenericJITLinkMemoryManager>(SREPC, SAs);
226Error SimpleRemoteEPC::sendMessage(SimpleRemoteEPCOpcode OpC,
uint64_t SeqNo,
227 ExecutorAddr TagAddr,
228 ArrayRef<char> ArgBytes) {
229 assert(OpC != SimpleRemoteEPCOpcode::Setup &&
230 "SimpleRemoteEPC sending Setup message? That's the wrong direction.");
233 dbgs() <<
"SimpleRemoteEPC::sendMessage: opc = ";
235 case SimpleRemoteEPCOpcode::Hangup:
237 assert(SeqNo == 0 &&
"Non-zero SeqNo for Hangup?");
238 assert(!TagAddr &&
"Non-zero TagAddr for Hangup?");
240 case SimpleRemoteEPCOpcode::Result:
242 assert(!TagAddr &&
"Non-zero TagAddr for Result?");
244 case SimpleRemoteEPCOpcode::CallWrapper:
245 dbgs() <<
"CallWrapper";
250 dbgs() <<
", seqno = " << SeqNo <<
", tag-addr = " << TagAddr
251 <<
", arg-buffer = " <<
formatv(
"{0:x}", ArgBytes.size())
254 auto Err =
T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes);
257 dbgs() <<
" \\--> SimpleRemoteEPC::sendMessage failed\n";
262Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddr TagAddr,
263 shared::WrapperFunctionBuffer ArgBytes) {
272 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
273 auto I = PendingCallWrapperResults.find(0);
274 assert(PendingCallWrapperResults.size() == 1 &&
275 I != PendingCallWrapperResults.end() &&
276 "Setup message handler not connectly set up");
277 auto SetupMsgHandler = std::move(
I->second);
278 PendingCallWrapperResults.erase(
I);
281 shared::WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
282 SetupMsgHandler(std::move(WFR));
286Error SimpleRemoteEPC::setup() {
287 using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
289 std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> EIP;
290 auto EIF = EIP.get_future();
293 PendingCallWrapperResults[0] =
295 [&](shared::WrapperFunctionBuffer SetupMsgBytes) {
296 if (
const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
302 shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
303 shared::SPSInputBuffer
IB(SetupMsgBytes.data(), SetupMsgBytes.size());
304 SimpleRemoteEPCExecutorInfo EI;
305 if (SPSSerialize::deserialize(IB, EI))
313 if (
auto Err =
T->start())
320 return EI.takeError();
324 dbgs() <<
"SimpleRemoteEPC received setup message:\n"
325 <<
" Triple: " << EI->TargetTriple <<
"\n"
326 <<
" Page size: " << EI->PageSize <<
"\n"
327 <<
" Bootstrap map" << (EI->BootstrapMap.empty() ?
" empty" :
":")
329 for (
const auto &KV : EI->BootstrapMap)
330 dbgs() <<
" " << KV.first() <<
": " << KV.second.size()
331 <<
"-byte SPS encoded buffer\n";
332 dbgs() <<
" Bootstrap symbols"
333 << (EI->BootstrapSymbols.empty() ?
" empty" :
":") <<
"\n";
334 for (
const auto &KV : EI->BootstrapSymbols)
335 dbgs() <<
" " << KV.first() <<
": " << KV.second <<
"\n";
337 TargetTriple =
Triple(EI->TargetTriple);
339 BootstrapMap = std::move(EI->BootstrapMap);
340 BootstrapSymbols = std::move(EI->BootstrapSymbols);
342 if (
auto Err = getBootstrapSymbols(
345 {RunAsMainAddr, rt::RunAsMainWrapperName},
346 {RunAsVoidFunctionAddr, rt::RunAsVoidFunctionWrapperName},
347 {RunAsIntFunctionAddr, rt::RunAsIntFunctionWrapperName}}))
353Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddr TagAddr,
354 shared::WrapperFunctionBuffer ArgBytes) {
355 IncomingWFRHandler SendResult;
362 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
363 auto I = PendingCallWrapperResults.find(SeqNo);
364 if (
I == PendingCallWrapperResults.end())
368 SendResult = std::move(
I->second);
369 PendingCallWrapperResults.erase(
I);
374 shared::WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
375 SendResult(std::move(WFR));
379void SimpleRemoteEPC::handleCallWrapper(
380 uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
381 shared::WrapperFunctionBuffer ArgBytes) {
382 assert(ES &&
"No ExecutionSession attached");
384 [
this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]()
mutable {
385 ES->runJITDispatchHandler(
386 [
this, RemoteSeqNo](shared::WrapperFunctionBuffer WFR) {
388 sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
389 ExecutorAddr(), {WFR.data(), WFR.size()}))
390 getExecutionSession().reportError(std::move(Err));
392 TagAddr, std::move(ArgBytes));
394 "callWrapper task"));
397Error SimpleRemoteEPC::handleHangup(shared::WrapperFunctionBuffer ArgBytes) {
399 auto WFR = WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
400 if (
const char *ErrMsg = WFR.getOutOfBandError())
404 SPSInputBuffer
IB(WFR.data(), WFR.size());
405 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.
static Expected< std::unique_ptr< EPCGenericJITLinkMemoryManager > > Create(JITDylib &JD, rt::SimpleExecutorMemoryManagerSymbolNames SNs=rt::orc_rt_SimpleNativeMemoryMapSPSSymbols)
Create an EPCGenericJITLinkMemoryManager using the given implementation symbol names.
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< std::unique_ptr< jitlink::JITLinkMemoryManager > > createDefaultMemoryManager() override
Create a default JITLinkMemoryManager for the target process.
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.