17#define DEBUG_TYPE "orc"
24 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
25 assert(Disconnected &&
"Destroyed without disconnection");
33 RunAsMainAddr,
Result, MainFnAddr, Args))
34 return std::move(Err);
43 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
44 SeqNo = getNextSeqNo();
45 assert(!PendingCallWrapperResults.count(SeqNo) &&
"SeqNo already in use");
46 PendingCallWrapperResults[SeqNo] = std::move(OnComplete);
50 WrapperFnAddr, ArgBuffer)) {
59 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
60 auto I = PendingCallWrapperResults.find(SeqNo);
61 if (
I != PendingCallWrapperResults.end()) {
62 H = std::move(
I->second);
63 PendingCallWrapperResults.erase(
I);
83 return DM.takeError();
84 return std::make_unique<EPCGenericDylibManager>(std::move(*
DM));
103 return std::move(Err);
105 return std::make_unique<EPCGenericMemoryAccess>(*
this, FAs);
111 std::unique_lock<std::mutex> Lock(SimpleRemoteEPCMutex);
112 DisconnectCV.wait(Lock, [
this] {
return Disconnected; });
113 return std::move(DisconnectErr);
122 dbgs() <<
"SimpleRemoteEPC::handleMessage: opc = ";
126 assert(SeqNo == 0 &&
"Non-zero SeqNo for Setup?");
127 assert(!TagAddr &&
"Non-zero TagAddr for Setup?");
131 assert(SeqNo == 0 &&
"Non-zero SeqNo for Hangup?");
132 assert(!TagAddr &&
"Non-zero TagAddr for Hangup?");
136 assert(!TagAddr &&
"Non-zero TagAddr for Result?");
139 dbgs() <<
"CallWrapper";
142 dbgs() <<
", seqno = " << SeqNo <<
", tag-addr = " << TagAddr
143 <<
", arg-buffer = " <<
formatv(
"{0:x}", ArgBytes.
size())
147 using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
154 if (
auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))
155 return std::move(Err);
159 if (
auto Err = handleHangup(std::move(ArgBytes)))
160 return std::move(Err);
163 if (
auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
164 return std::move(Err);
167 handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
175 dbgs() <<
"SimpleRemoteEPC::handleDisconnect: "
176 << (Err ?
"failure" :
"success") <<
"\n";
179 PendingCallWrapperResultsMap TmpPending;
182 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
183 std::swap(TmpPending, PendingCallWrapperResults);
186 for (
auto &KV : TmpPending)
190 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
191 DisconnectErr =
joinErrors(std::move(DisconnectErr), std::move(Err));
193 DisconnectCV.notify_all();
200 {{SAs.Allocator, rt::SimpleExecutorMemoryManagerInstanceName},
201 {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
203 rt::SimpleExecutorMemoryManagerInitializeWrapperName},
204 {SAs.Release, rt::SimpleExecutorMemoryManagerReleaseWrapperName}}))
205 return std::move(Err);
207 return std::make_unique<EPCGenericJITLinkMemoryManager>(SREPC, SAs);
210Error SimpleRemoteEPC::sendMessage(SimpleRemoteEPCOpcode OpC,
uint64_t SeqNo,
211 ExecutorAddr TagAddr,
212 ArrayRef<char> ArgBytes) {
213 assert(OpC != SimpleRemoteEPCOpcode::Setup &&
214 "SimpleRemoteEPC sending Setup message? That's the wrong direction.");
217 dbgs() <<
"SimpleRemoteEPC::sendMessage: opc = ";
219 case SimpleRemoteEPCOpcode::Hangup:
221 assert(SeqNo == 0 &&
"Non-zero SeqNo for Hangup?");
222 assert(!TagAddr &&
"Non-zero TagAddr for Hangup?");
224 case SimpleRemoteEPCOpcode::Result:
226 assert(!TagAddr &&
"Non-zero TagAddr for Result?");
228 case SimpleRemoteEPCOpcode::CallWrapper:
229 dbgs() <<
"CallWrapper";
234 dbgs() <<
", seqno = " << SeqNo <<
", tag-addr = " << TagAddr
235 <<
", arg-buffer = " <<
formatv(
"{0:x}", ArgBytes.size())
238 auto Err =
T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes);
241 dbgs() <<
" \\--> SimpleRemoteEPC::sendMessage failed\n";
246Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddr TagAddr,
247 shared::WrapperFunctionBuffer ArgBytes) {
256 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
257 auto I = PendingCallWrapperResults.find(0);
258 assert(PendingCallWrapperResults.size() == 1 &&
259 I != PendingCallWrapperResults.end() &&
260 "Setup message handler not connectly set up");
261 auto SetupMsgHandler = std::move(
I->second);
262 PendingCallWrapperResults.erase(
I);
265 shared::WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
266 SetupMsgHandler(std::move(WFR));
270Error SimpleRemoteEPC::setup() {
271 using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
273 std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> EIP;
274 auto EIF = EIP.get_future();
277 PendingCallWrapperResults[0] =
279 [&](shared::WrapperFunctionBuffer SetupMsgBytes) {
280 if (
const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
286 shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
287 shared::SPSInputBuffer
IB(SetupMsgBytes.data(), SetupMsgBytes.size());
288 SimpleRemoteEPCExecutorInfo EI;
289 if (SPSSerialize::deserialize(IB, EI))
297 if (
auto Err =
T->start())
304 return EI.takeError();
308 dbgs() <<
"SimpleRemoteEPC received setup message:\n"
309 <<
" Triple: " << EI->TargetTriple <<
"\n"
310 <<
" Page size: " << EI->PageSize <<
"\n"
311 <<
" Bootstrap map" << (EI->BootstrapMap.empty() ?
" empty" :
":")
313 for (
const auto &KV : EI->BootstrapMap)
314 dbgs() <<
" " << KV.first() <<
": " << KV.second.size()
315 <<
"-byte SPS encoded buffer\n";
316 dbgs() <<
" Bootstrap symbols"
317 << (EI->BootstrapSymbols.empty() ?
" empty" :
":") <<
"\n";
318 for (
const auto &KV : EI->BootstrapSymbols)
319 dbgs() <<
" " << KV.first() <<
": " << KV.second <<
"\n";
321 TargetTriple =
Triple(EI->TargetTriple);
323 BootstrapMap = std::move(EI->BootstrapMap);
324 BootstrapSymbols = std::move(EI->BootstrapSymbols);
326 BootstrapSymbols[rt::DispatchName] = BootstrapSymbols[
DispatchFnName];
327 BootstrapSymbols[rt::DispatchCtxName] =
331 getBootstrapSymbols({{RunAsMainAddr, rt::sps::CallMainCIName}}))
337Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddr TagAddr,
338 shared::WrapperFunctionBuffer ArgBytes) {
339 IncomingWFRHandler SendResult;
346 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
347 auto I = PendingCallWrapperResults.find(SeqNo);
348 if (
I == PendingCallWrapperResults.end())
352 SendResult = std::move(
I->second);
353 PendingCallWrapperResults.erase(
I);
358 shared::WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
359 SendResult(std::move(WFR));
363void SimpleRemoteEPC::handleCallWrapper(
364 uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
365 shared::WrapperFunctionBuffer ArgBytes) {
366 assert(ES &&
"No ExecutionSession attached");
368 [
this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]()
mutable {
369 ES->runJITDispatchHandler(
370 [
this, RemoteSeqNo](shared::WrapperFunctionBuffer WFR) {
372 sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
373 ExecutorAddr(), {WFR.data(), WFR.size()}))
374 getExecutionSession().reportError(std::move(Err));
376 TagAddr, std::move(ArgBytes));
378 "callWrapper task"));
381Error SimpleRemoteEPC::handleHangup(shared::WrapperFunctionBuffer ArgBytes) {
383 auto WFR = WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
384 if (
const char *ErrMsg = WFR.getOutOfBandError())
388 SPSInputBuffer
IB(WFR.data(), WFR.size());
389 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)
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 Expected< EPCGenericDylibManager > CreateWithDefaultBootstrapSymbols(ExecutorProcessControl &EPC)
Create an EPCGenericDylibManager instance by looking up the LLVM-style SimpleExecutorDylibManager sym...
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.
void callWrapperAsync(ExecutorAddr WrapperFnAddr, IncomingWFRHandler OnComplete, ArrayRef< char > ArgBuffer) override
Run a wrapper function in the executor.
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.