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));
100 std::unique_lock<std::mutex> Lock(SimpleRemoteEPCMutex);
101 DisconnectCV.wait(Lock, [
this] {
return Disconnected; });
102 return std::move(DisconnectErr);
111 dbgs() <<
"SimpleRemoteEPC::handleMessage: opc = ";
115 assert(SeqNo == 0 &&
"Non-zero SeqNo for Setup?");
116 assert(!TagAddr &&
"Non-zero TagAddr for Setup?");
120 assert(SeqNo == 0 &&
"Non-zero SeqNo for Hangup?");
121 assert(!TagAddr &&
"Non-zero TagAddr for Hangup?");
125 assert(!TagAddr &&
"Non-zero TagAddr for Result?");
128 dbgs() <<
"CallWrapper";
131 dbgs() <<
", seqno = " << SeqNo <<
", tag-addr = " << TagAddr
132 <<
", arg-buffer = " <<
formatv(
"{0:x}", ArgBytes.
size())
136 using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
143 if (
auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))
144 return std::move(Err);
148 if (
auto Err = handleHangup(std::move(ArgBytes)))
149 return std::move(Err);
152 if (
auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
153 return std::move(Err);
156 handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
164 dbgs() <<
"SimpleRemoteEPC::handleDisconnect: "
165 << (Err ?
"failure" :
"success") <<
"\n";
168 PendingCallWrapperResultsMap TmpPending;
171 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
172 std::swap(TmpPending, PendingCallWrapperResults);
175 for (
auto &KV : TmpPending)
179 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
180 DisconnectErr =
joinErrors(std::move(DisconnectErr), std::move(Err));
182 DisconnectCV.notify_all();
189 {{SAs.Allocator, rt::SimpleExecutorMemoryManagerInstanceName},
190 {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
192 rt::SimpleExecutorMemoryManagerInitializeWrapperName},
193 {SAs.Release, rt::SimpleExecutorMemoryManagerReleaseWrapperName}}))
194 return std::move(Err);
196 return std::make_unique<EPCGenericJITLinkMemoryManager>(SREPC, SAs);
199Expected<std::unique_ptr<MemoryAccess>>
200SimpleRemoteEPC::createDefaultMemoryAccess(SimpleRemoteEPC &SREPC) {
201 EPCGenericMemoryAccess::FuncAddrs FAs;
202 if (
auto Err = SREPC.getBootstrapSymbols(
203 {{FAs.WriteUInt8s, rt::MemoryWriteUInt8sWrapperName},
204 {FAs.WriteUInt16s, rt::MemoryWriteUInt16sWrapperName},
205 {FAs.WriteUInt32s, rt::MemoryWriteUInt32sWrapperName},
206 {FAs.WriteUInt64s, rt::MemoryWriteUInt64sWrapperName},
207 {FAs.WriteBuffers, rt::MemoryWriteBuffersWrapperName},
208 {FAs.WritePointers, rt::MemoryWritePointersWrapperName},
209 {FAs.ReadUInt8s, rt::MemoryReadUInt8sWrapperName},
210 {FAs.ReadUInt16s, rt::MemoryReadUInt16sWrapperName},
211 {FAs.ReadUInt32s, rt::MemoryReadUInt32sWrapperName},
212 {FAs.ReadUInt64s, rt::MemoryReadUInt64sWrapperName},
213 {FAs.ReadBuffers, rt::MemoryReadBuffersWrapperName},
214 {FAs.ReadStrings, rt::MemoryReadStringsWrapperName}}))
215 return std::move(Err);
217 return std::make_unique<EPCGenericMemoryAccess>(SREPC, FAs);
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) {
259 return make_error<StringError>(
"Setup packet SeqNo not zero",
263 return make_error<StringError>(
"Setup packet TagAddr not zero",
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));
277 return Error::success();
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))
302 EIP.set_value(make_error<StringError>(
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();
355 if (!S.CreateMemoryAccess)
356 S.CreateMemoryAccess = createDefaultMemoryAccess;
358 if (
auto MemAccess = S.CreateMemoryAccess(*
this)) {
359 OwnedMemAccess = std::move(*MemAccess);
360 this->MemAccess = OwnedMemAccess.get();
362 return MemAccess.takeError();
364 return Error::success();
367Error SimpleRemoteEPC::handleResult(
uint64_t SeqNo, ExecutorAddr TagAddr,
368 shared::WrapperFunctionBuffer ArgBytes) {
369 IncomingWFRHandler SendResult;
372 return make_error<StringError>(
"Unexpected TagAddr in result message",
376 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
377 auto I = PendingCallWrapperResults.find(SeqNo);
378 if (
I == PendingCallWrapperResults.end())
379 return make_error<StringError>(
"No call for sequence number " +
382 SendResult = std::move(
I->second);
383 PendingCallWrapperResults.erase(
I);
388 shared::WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
389 SendResult(std::move(WFR));
390 return Error::success();
393void SimpleRemoteEPC::handleCallWrapper(
394 uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
395 shared::WrapperFunctionBuffer ArgBytes) {
396 assert(ES &&
"No ExecutionSession attached");
398 [
this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]()
mutable {
399 ES->runJITDispatchHandler(
400 [
this, RemoteSeqNo](shared::WrapperFunctionBuffer WFR) {
402 sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
403 ExecutorAddr(), {WFR.data(), WFR.size()}))
404 getExecutionSession().reportError(std::move(Err));
406 TagAddr, std::move(ArgBytes));
408 "callWrapper task"));
411Error SimpleRemoteEPC::handleHangup(shared::WrapperFunctionBuffer ArgBytes) {
414 if (
const char *ErrMsg = WFR.getOutOfBandError())
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.
Tagged union holding either a T or a Error.
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< 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.
A utility class for serializing to a blob from a variadic list.
C++ wrapper function buffer: Same as CWrapperFunctionBuffer but auto-releases memory.
static WrapperFunctionBuffer copyFrom(const char *Source, size_t Size)
Copy from the given char range.
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
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.
Helper type for serializing Errors.