1 //===------- SimpleRemoteEPC.cpp -- Simple remote executor control --------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h"
10 #include "llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h"
11 #include "llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h"
12 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
13 #include "llvm/Support/FormatVariadic.h"
14 
15 #define DEBUG_TYPE "orc"
16 
17 namespace llvm {
18 namespace orc {
19 
20 SimpleRemoteEPC::~SimpleRemoteEPC() {
21 #ifndef NDEBUG
22   std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
23   assert(Disconnected && "Destroyed without disconnection");
24 #endif // NDEBUG
25 }
26 
27 Expected<tpctypes::DylibHandle>
28 SimpleRemoteEPC::loadDylib(const char *DylibPath) {
29   return DylibMgr->open(DylibPath, 0);
30 }
31 
32 Expected<std::vector<tpctypes::LookupResult>>
33 SimpleRemoteEPC::lookupSymbols(ArrayRef<LookupRequest> Request) {
34   std::vector<tpctypes::LookupResult> Result;
35 
36   for (auto &Element : Request) {
37     if (auto R = DylibMgr->lookup(Element.Handle, Element.Symbols)) {
38       Result.push_back({});
39       Result.back().reserve(R->size());
40       for (auto Addr : *R)
41         Result.back().push_back(Addr);
42     } else
43       return R.takeError();
44   }
45   return std::move(Result);
46 }
47 
48 Expected<int32_t> SimpleRemoteEPC::runAsMain(ExecutorAddr MainFnAddr,
49                                              ArrayRef<std::string> Args) {
50   int64_t Result = 0;
51   if (auto Err = callSPSWrapper<rt::SPSRunAsMainSignature>(
52           RunAsMainAddr, Result, MainFnAddr, Args))
53     return std::move(Err);
54   return Result;
55 }
56 
57 Expected<int32_t> SimpleRemoteEPC::runAsVoidFunction(ExecutorAddr VoidFnAddr) {
58   int32_t Result = 0;
59   if (auto Err = callSPSWrapper<rt::SPSRunAsVoidFunctionSignature>(
60           RunAsVoidFunctionAddr, Result, VoidFnAddr))
61     return std::move(Err);
62   return Result;
63 }
64 
65 Expected<int32_t> SimpleRemoteEPC::runAsIntFunction(ExecutorAddr IntFnAddr,
66                                                     int Arg) {
67   int32_t Result = 0;
68   if (auto Err = callSPSWrapper<rt::SPSRunAsIntFunctionSignature>(
69           RunAsIntFunctionAddr, Result, IntFnAddr, Arg))
70     return std::move(Err);
71   return Result;
72 }
73 
74 void SimpleRemoteEPC::callWrapperAsync(ExecutorAddr WrapperFnAddr,
75                                        IncomingWFRHandler OnComplete,
76                                        ArrayRef<char> ArgBuffer) {
77   uint64_t SeqNo;
78   {
79     std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
80     SeqNo = getNextSeqNo();
81     assert(!PendingCallWrapperResults.count(SeqNo) && "SeqNo already in use");
82     PendingCallWrapperResults[SeqNo] = std::move(OnComplete);
83   }
84 
85   if (auto Err = sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,
86                              WrapperFnAddr, ArgBuffer)) {
87     IncomingWFRHandler H;
88 
89     // We just registered OnComplete, but there may be a race between this
90     // thread returning from sendMessage and handleDisconnect being called from
91     // the transport's listener thread. If handleDisconnect gets there first
92     // then it will have failed 'H' for us. If we get there first (or if
93     // handleDisconnect already ran) then we need to take care of it.
94     {
95       std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
96       auto I = PendingCallWrapperResults.find(SeqNo);
97       if (I != PendingCallWrapperResults.end()) {
98         H = std::move(I->second);
99         PendingCallWrapperResults.erase(I);
100       }
101     }
102 
103     if (H)
104       H(shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
105 
106     getExecutionSession().reportError(std::move(Err));
107   }
108 }
109 
110 Error SimpleRemoteEPC::disconnect() {
111   T->disconnect();
112   D->shutdown();
113   std::unique_lock<std::mutex> Lock(SimpleRemoteEPCMutex);
114   DisconnectCV.wait(Lock, [this] { return Disconnected; });
115   return std::move(DisconnectErr);
116 }
117 
118 Expected<SimpleRemoteEPCTransportClient::HandleMessageAction>
119 SimpleRemoteEPC::handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
120                                ExecutorAddr TagAddr,
121                                SimpleRemoteEPCArgBytesVector ArgBytes) {
122 
123   LLVM_DEBUG({
124     dbgs() << "SimpleRemoteEPC::handleMessage: opc = ";
125     switch (OpC) {
126     case SimpleRemoteEPCOpcode::Setup:
127       dbgs() << "Setup";
128       assert(SeqNo == 0 && "Non-zero SeqNo for Setup?");
129       assert(!TagAddr && "Non-zero TagAddr for Setup?");
130       break;
131     case SimpleRemoteEPCOpcode::Hangup:
132       dbgs() << "Hangup";
133       assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
134       assert(!TagAddr && "Non-zero TagAddr for Hangup?");
135       break;
136     case SimpleRemoteEPCOpcode::Result:
137       dbgs() << "Result";
138       assert(!TagAddr && "Non-zero TagAddr for Result?");
139       break;
140     case SimpleRemoteEPCOpcode::CallWrapper:
141       dbgs() << "CallWrapper";
142       break;
143     }
144     dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr
145            << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
146            << " bytes\n";
147   });
148 
149   using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
150   if (static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC))
151     return make_error<StringError>("Unexpected opcode",
152                                    inconvertibleErrorCode());
153 
154   switch (OpC) {
155   case SimpleRemoteEPCOpcode::Setup:
156     if (auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))
157       return std::move(Err);
158     break;
159   case SimpleRemoteEPCOpcode::Hangup:
160     T->disconnect();
161     if (auto Err = handleHangup(std::move(ArgBytes)))
162       return std::move(Err);
163     return EndSession;
164   case SimpleRemoteEPCOpcode::Result:
165     if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
166       return std::move(Err);
167     break;
168   case SimpleRemoteEPCOpcode::CallWrapper:
169     handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
170     break;
171   }
172   return ContinueSession;
173 }
174 
175 void SimpleRemoteEPC::handleDisconnect(Error Err) {
176   LLVM_DEBUG({
177     dbgs() << "SimpleRemoteEPC::handleDisconnect: "
178            << (Err ? "failure" : "success") << "\n";
179   });
180 
181   PendingCallWrapperResultsMap TmpPending;
182 
183   {
184     std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
185     std::swap(TmpPending, PendingCallWrapperResults);
186   }
187 
188   for (auto &KV : TmpPending)
189     KV.second(
190         shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
191 
192   std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
193   DisconnectErr = joinErrors(std::move(DisconnectErr), std::move(Err));
194   Disconnected = true;
195   DisconnectCV.notify_all();
196 }
197 
198 Expected<std::unique_ptr<jitlink::JITLinkMemoryManager>>
199 SimpleRemoteEPC::createDefaultMemoryManager(SimpleRemoteEPC &SREPC) {
200   EPCGenericJITLinkMemoryManager::SymbolAddrs SAs;
201   if (auto Err = SREPC.getBootstrapSymbols(
202           {{SAs.Allocator, rt::SimpleExecutorMemoryManagerInstanceName},
203            {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
204            {SAs.Finalize, rt::SimpleExecutorMemoryManagerFinalizeWrapperName},
205            {SAs.Deallocate,
206             rt::SimpleExecutorMemoryManagerDeallocateWrapperName}}))
207     return std::move(Err);
208 
209   return std::make_unique<EPCGenericJITLinkMemoryManager>(SREPC, SAs);
210 }
211 
212 Expected<std::unique_ptr<ExecutorProcessControl::MemoryAccess>>
213 SimpleRemoteEPC::createDefaultMemoryAccess(SimpleRemoteEPC &SREPC) {
214   return nullptr;
215 }
216 
217 Error SimpleRemoteEPC::sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
218                                    ExecutorAddr TagAddr,
219                                    ArrayRef<char> ArgBytes) {
220   assert(OpC != SimpleRemoteEPCOpcode::Setup &&
221          "SimpleRemoteEPC sending Setup message? That's the wrong direction.");
222 
223   LLVM_DEBUG({
224     dbgs() << "SimpleRemoteEPC::sendMessage: opc = ";
225     switch (OpC) {
226     case SimpleRemoteEPCOpcode::Hangup:
227       dbgs() << "Hangup";
228       assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
229       assert(!TagAddr && "Non-zero TagAddr for Hangup?");
230       break;
231     case SimpleRemoteEPCOpcode::Result:
232       dbgs() << "Result";
233       assert(!TagAddr && "Non-zero TagAddr for Result?");
234       break;
235     case SimpleRemoteEPCOpcode::CallWrapper:
236       dbgs() << "CallWrapper";
237       break;
238     default:
239       llvm_unreachable("Invalid opcode");
240     }
241     dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr
242            << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
243            << " bytes\n";
244   });
245   auto Err = T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes);
246   LLVM_DEBUG({
247     if (Err)
248       dbgs() << "  \\--> SimpleRemoteEPC::sendMessage failed\n";
249   });
250   return Err;
251 }
252 
253 Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddr TagAddr,
254                                    SimpleRemoteEPCArgBytesVector ArgBytes) {
255   if (SeqNo != 0)
256     return make_error<StringError>("Setup packet SeqNo not zero",
257                                    inconvertibleErrorCode());
258 
259   if (TagAddr)
260     return make_error<StringError>("Setup packet TagAddr not zero",
261                                    inconvertibleErrorCode());
262 
263   std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
264   auto I = PendingCallWrapperResults.find(0);
265   assert(PendingCallWrapperResults.size() == 1 &&
266          I != PendingCallWrapperResults.end() &&
267          "Setup message handler not connectly set up");
268   auto SetupMsgHandler = std::move(I->second);
269   PendingCallWrapperResults.erase(I);
270 
271   auto WFR =
272       shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
273   SetupMsgHandler(std::move(WFR));
274   return Error::success();
275 }
276 
277 Error SimpleRemoteEPC::setup(Setup S) {
278   using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
279 
280   std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> EIP;
281   auto EIF = EIP.get_future();
282 
283   // Prepare a handler for the setup packet.
284   PendingCallWrapperResults[0] =
285     RunInPlace()(
286       [&](shared::WrapperFunctionResult SetupMsgBytes) {
287         if (const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
288           EIP.set_value(
289               make_error<StringError>(ErrMsg, inconvertibleErrorCode()));
290           return;
291         }
292         using SPSSerialize =
293             shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
294         shared::SPSInputBuffer IB(SetupMsgBytes.data(), SetupMsgBytes.size());
295         SimpleRemoteEPCExecutorInfo EI;
296         if (SPSSerialize::deserialize(IB, EI))
297           EIP.set_value(EI);
298         else
299           EIP.set_value(make_error<StringError>(
300               "Could not deserialize setup message", inconvertibleErrorCode()));
301       });
302 
303   // Start the transport.
304   if (auto Err = T->start())
305     return Err;
306 
307   // Wait for setup packet to arrive.
308   auto EI = EIF.get();
309   if (!EI) {
310     T->disconnect();
311     return EI.takeError();
312   }
313 
314   LLVM_DEBUG({
315     dbgs() << "SimpleRemoteEPC received setup message:\n"
316            << "  Triple: " << EI->TargetTriple << "\n"
317            << "  Page size: " << EI->PageSize << "\n"
318            << "  Bootstrap map" << (EI->BootstrapMap.empty() ? " empty" : ":")
319            << "\n";
320     for (const auto &KV : EI->BootstrapMap)
321       dbgs() << "    " << KV.first() << ": " << KV.second.size()
322              << "-byte SPS encoded buffer\n";
323     dbgs() << "  Bootstrap symbols"
324            << (EI->BootstrapSymbols.empty() ? " empty" : ":") << "\n";
325     for (const auto &KV : EI->BootstrapSymbols)
326       dbgs() << "    " << KV.first() << ": " << KV.second << "\n";
327   });
328   TargetTriple = Triple(EI->TargetTriple);
329   PageSize = EI->PageSize;
330   BootstrapMap = std::move(EI->BootstrapMap);
331   BootstrapSymbols = std::move(EI->BootstrapSymbols);
332 
333   if (auto Err = getBootstrapSymbols(
334           {{JDI.JITDispatchContext, ExecutorSessionObjectName},
335            {JDI.JITDispatchFunction, DispatchFnName},
336            {RunAsMainAddr, rt::RunAsMainWrapperName},
337            {RunAsVoidFunctionAddr, rt::RunAsVoidFunctionWrapperName},
338            {RunAsIntFunctionAddr, rt::RunAsIntFunctionWrapperName}}))
339     return Err;
340 
341   if (auto DM =
342           EPCGenericDylibManager::CreateWithDefaultBootstrapSymbols(*this))
343     DylibMgr = std::make_unique<EPCGenericDylibManager>(std::move(*DM));
344   else
345     return DM.takeError();
346 
347   // Set a default CreateMemoryManager if none is specified.
348   if (!S.CreateMemoryManager)
349     S.CreateMemoryManager = createDefaultMemoryManager;
350 
351   if (auto MemMgr = S.CreateMemoryManager(*this)) {
352     OwnedMemMgr = std::move(*MemMgr);
353     this->MemMgr = OwnedMemMgr.get();
354   } else
355     return MemMgr.takeError();
356 
357   // Set a default CreateMemoryAccess if none is specified.
358   if (!S.CreateMemoryAccess)
359     S.CreateMemoryAccess = createDefaultMemoryAccess;
360 
361   if (auto MemAccess = S.CreateMemoryAccess(*this)) {
362     OwnedMemAccess = std::move(*MemAccess);
363     this->MemAccess = OwnedMemAccess.get();
364   } else
365     return MemAccess.takeError();
366 
367   return Error::success();
368 }
369 
370 Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddr TagAddr,
371                                     SimpleRemoteEPCArgBytesVector ArgBytes) {
372   IncomingWFRHandler SendResult;
373 
374   if (TagAddr)
375     return make_error<StringError>("Unexpected TagAddr in result message",
376                                    inconvertibleErrorCode());
377 
378   {
379     std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
380     auto I = PendingCallWrapperResults.find(SeqNo);
381     if (I == PendingCallWrapperResults.end())
382       return make_error<StringError>("No call for sequence number " +
383                                          Twine(SeqNo),
384                                      inconvertibleErrorCode());
385     SendResult = std::move(I->second);
386     PendingCallWrapperResults.erase(I);
387     releaseSeqNo(SeqNo);
388   }
389 
390   auto WFR =
391       shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
392   SendResult(std::move(WFR));
393   return Error::success();
394 }
395 
396 void SimpleRemoteEPC::handleCallWrapper(
397     uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
398     SimpleRemoteEPCArgBytesVector ArgBytes) {
399   assert(ES && "No ExecutionSession attached");
400   D->dispatch(makeGenericNamedTask(
401       [this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() {
402         ES->runJITDispatchHandler(
403             [this, RemoteSeqNo](shared::WrapperFunctionResult WFR) {
404               if (auto Err =
405                       sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
406                                   ExecutorAddr(), {WFR.data(), WFR.size()}))
407                 getExecutionSession().reportError(std::move(Err));
408             },
409             TagAddr, ArgBytes);
410       },
411       "callWrapper task"));
412 }
413 
414 Error SimpleRemoteEPC::handleHangup(SimpleRemoteEPCArgBytesVector ArgBytes) {
415   using namespace llvm::orc::shared;
416   auto WFR = WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
417   if (const char *ErrMsg = WFR.getOutOfBandError())
418     return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
419 
420   detail::SPSSerializableError Info;
421   SPSInputBuffer IB(WFR.data(), WFR.size());
422   if (!SPSArgList<SPSError>::deserialize(IB, Info))
423     return make_error<StringError>("Could not deserialize hangup info",
424                                    inconvertibleErrorCode());
425   return fromSPSSerializable(std::move(Info));
426 }
427 
428 } // end namespace orc
429 } // end namespace llvm
430