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));
95 std::unique_lock<std::mutex> Lock(SimpleRemoteEPCMutex);
96 DisconnectCV.wait(Lock, [
this] {
return Disconnected; });
97 return std::move(DisconnectErr);
106 dbgs() <<
"SimpleRemoteEPC::handleMessage: opc = ";
110 assert(SeqNo == 0 &&
"Non-zero SeqNo for Setup?");
111 assert(!TagAddr &&
"Non-zero TagAddr for Setup?");
115 assert(SeqNo == 0 &&
"Non-zero SeqNo for Hangup?");
116 assert(!TagAddr &&
"Non-zero TagAddr for Hangup?");
120 assert(!TagAddr &&
"Non-zero TagAddr for Result?");
123 dbgs() <<
"CallWrapper";
126 dbgs() <<
", seqno = " << SeqNo <<
", tag-addr = " << TagAddr
127 <<
", arg-buffer = " <<
formatv(
"{0:x}", ArgBytes.
size())
131 using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
138 if (
auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))
139 return std::move(Err);
143 if (
auto Err = handleHangup(std::move(ArgBytes)))
144 return std::move(Err);
147 if (
auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
148 return std::move(Err);
151 handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
159 dbgs() <<
"SimpleRemoteEPC::handleDisconnect: "
160 << (Err ?
"failure" :
"success") <<
"\n";
163 PendingCallWrapperResultsMap TmpPending;
166 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
167 std::swap(TmpPending, PendingCallWrapperResults);
170 for (
auto &KV : TmpPending)
174 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
175 DisconnectErr =
joinErrors(std::move(DisconnectErr), std::move(Err));
177 DisconnectCV.notify_all();
184 {{SAs.Allocator, rt::SimpleExecutorMemoryManagerInstanceName},
185 {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
187 rt::SimpleExecutorMemoryManagerInitializeWrapperName},
188 {SAs.Release, rt::SimpleExecutorMemoryManagerReleaseWrapperName}}))
189 return std::move(Err);
191 return std::make_unique<EPCGenericJITLinkMemoryManager>(SREPC, SAs);
194Error SimpleRemoteEPC::sendMessage(SimpleRemoteEPCOpcode OpC,
uint64_t SeqNo,
195 ExecutorAddr TagAddr,
196 ArrayRef<char> ArgBytes) {
197 assert(OpC != SimpleRemoteEPCOpcode::Setup &&
198 "SimpleRemoteEPC sending Setup message? That's the wrong direction.");
201 dbgs() <<
"SimpleRemoteEPC::sendMessage: opc = ";
203 case SimpleRemoteEPCOpcode::Hangup:
205 assert(SeqNo == 0 &&
"Non-zero SeqNo for Hangup?");
206 assert(!TagAddr &&
"Non-zero TagAddr for Hangup?");
208 case SimpleRemoteEPCOpcode::Result:
210 assert(!TagAddr &&
"Non-zero TagAddr for Result?");
212 case SimpleRemoteEPCOpcode::CallWrapper:
213 dbgs() <<
"CallWrapper";
218 dbgs() <<
", seqno = " << SeqNo <<
", tag-addr = " << TagAddr
219 <<
", arg-buffer = " <<
formatv(
"{0:x}", ArgBytes.size())
222 auto Err =
T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes);
225 dbgs() <<
" \\--> SimpleRemoteEPC::sendMessage failed\n";
230Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddr TagAddr,
231 shared::WrapperFunctionBuffer ArgBytes) {
240 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
241 auto I = PendingCallWrapperResults.find(0);
242 assert(PendingCallWrapperResults.size() == 1 &&
243 I != PendingCallWrapperResults.end() &&
244 "Setup message handler not connectly set up");
245 auto SetupMsgHandler = std::move(
I->second);
246 PendingCallWrapperResults.erase(
I);
249 shared::WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
250 SetupMsgHandler(std::move(WFR));
254Error SimpleRemoteEPC::setup() {
255 using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
257 std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> EIP;
258 auto EIF = EIP.get_future();
261 PendingCallWrapperResults[0] =
263 [&](shared::WrapperFunctionBuffer SetupMsgBytes) {
264 if (
const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
270 shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
271 shared::SPSInputBuffer
IB(SetupMsgBytes.data(), SetupMsgBytes.size());
272 SimpleRemoteEPCExecutorInfo EI;
273 if (SPSSerialize::deserialize(IB, EI))
281 if (
auto Err =
T->start())
288 return EI.takeError();
292 dbgs() <<
"SimpleRemoteEPC received setup message:\n"
293 <<
" Triple: " << EI->TargetTriple <<
"\n"
294 <<
" Page size: " << EI->PageSize <<
"\n"
295 <<
" Bootstrap map" << (EI->BootstrapMap.empty() ?
" empty" :
":")
297 for (
const auto &KV : EI->BootstrapMap)
298 dbgs() <<
" " << KV.first() <<
": " << KV.second.size()
299 <<
"-byte SPS encoded buffer\n";
300 dbgs() <<
" Bootstrap symbols"
301 << (EI->BootstrapSymbols.empty() ?
" empty" :
":") <<
"\n";
302 for (
const auto &KV : EI->BootstrapSymbols)
303 dbgs() <<
" " << KV.first() <<
": " << KV.second <<
"\n";
305 TargetTriple =
Triple(EI->TargetTriple);
307 BootstrapMap = std::move(EI->BootstrapMap);
308 BootstrapSymbols = std::move(EI->BootstrapSymbols);
310 BootstrapSymbols[rt::DispatchName] = BootstrapSymbols[
DispatchFnName];
311 BootstrapSymbols[rt::DispatchCtxName] =
315 getBootstrapSymbols({{RunAsMainAddr, rt::sps::CallMainCIName}}))
321Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddr TagAddr,
322 shared::WrapperFunctionBuffer ArgBytes) {
323 IncomingWFRHandler SendResult;
330 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
331 auto I = PendingCallWrapperResults.find(SeqNo);
332 if (
I == PendingCallWrapperResults.end())
336 SendResult = std::move(
I->second);
337 PendingCallWrapperResults.erase(
I);
342 shared::WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
343 SendResult(std::move(WFR));
347void SimpleRemoteEPC::handleCallWrapper(
348 uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
349 shared::WrapperFunctionBuffer ArgBytes) {
350 assert(ES &&
"No ExecutionSession attached");
352 [
this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]()
mutable {
353 ES->runJITDispatchHandler(
354 [
this, RemoteSeqNo](shared::WrapperFunctionBuffer WFR) {
356 sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
357 ExecutorAddr(), {WFR.data(), WFR.size()}))
358 getExecutionSession().reportError(std::move(Err));
360 TagAddr, std::move(ArgBytes));
362 "callWrapper task"));
365Error SimpleRemoteEPC::handleHangup(shared::WrapperFunctionBuffer ArgBytes) {
367 auto WFR = WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
368 if (
const char *ErrMsg = WFR.getOutOfBandError())
372 SPSInputBuffer
IB(WFR.data(), WFR.size());
373 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 > Create(JITDylib &JD)
Create an EPCGenericDylibManager for the ORC runtime's NativeDylibManager interface,...
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.
static Expected< std::unique_ptr< MemoryAccess > > Create(ExecutionSession &ES)
Create an EPCGenericMemoryAccess instance that reaches the memory-access wrappers in ES's bootstrap J...
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
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.