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.getValue());
42     } else
43       return R.takeError();
44   }
45   return std::move(Result);
46 }
47 
48 Expected<int32_t> SimpleRemoteEPC::runAsMain(JITTargetAddress MainFnAddr,
49                                              ArrayRef<std::string> Args) {
50   int64_t Result = 0;
51   if (auto Err = callSPSWrapper<rt::SPSRunAsMainSignature>(
52           RunAsMainAddr.getValue(), Result, ExecutorAddr(MainFnAddr), Args))
53     return std::move(Err);
54   return Result;
55 }
56 
57 void SimpleRemoteEPC::callWrapperAsync(SendResultFunction OnComplete,
58                                        JITTargetAddress WrapperFnAddr,
59                                        ArrayRef<char> ArgBuffer) {
60   uint64_t SeqNo;
61   {
62     std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
63     SeqNo = getNextSeqNo();
64     assert(!PendingCallWrapperResults.count(SeqNo) && "SeqNo already in use");
65     PendingCallWrapperResults[SeqNo] = std::move(OnComplete);
66   }
67 
68   if (auto Err = T->sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,
69                                 ExecutorAddr(WrapperFnAddr), ArgBuffer)) {
70     getExecutionSession().reportError(std::move(Err));
71   }
72 }
73 
74 Error SimpleRemoteEPC::disconnect() {
75   T->disconnect();
76   std::unique_lock<std::mutex> Lock(SimpleRemoteEPCMutex);
77   DisconnectCV.wait(Lock, [this] { return Disconnected; });
78   return std::move(DisconnectErr);
79 }
80 
81 Expected<SimpleRemoteEPCTransportClient::HandleMessageAction>
82 SimpleRemoteEPC::handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
83                                ExecutorAddr TagAddr,
84                                SimpleRemoteEPCArgBytesVector ArgBytes) {
85   using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
86   if (static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC))
87     return make_error<StringError>("Unexpected opcode",
88                                    inconvertibleErrorCode());
89 
90   switch (OpC) {
91   case SimpleRemoteEPCOpcode::Setup:
92     if (auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))
93       return std::move(Err);
94     break;
95   case SimpleRemoteEPCOpcode::Hangup:
96     // FIXME: Put EPC into 'detached' state.
97     return SimpleRemoteEPCTransportClient::EndSession;
98   case SimpleRemoteEPCOpcode::Result:
99     if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
100       return std::move(Err);
101     break;
102   case SimpleRemoteEPCOpcode::CallWrapper:
103     handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
104     break;
105   }
106   return ContinueSession;
107 }
108 
109 void SimpleRemoteEPC::handleDisconnect(Error Err) {
110   PendingCallWrapperResultsMap TmpPending;
111 
112   {
113     std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
114     std::swap(TmpPending, PendingCallWrapperResults);
115   }
116 
117   for (auto &KV : TmpPending)
118     KV.second(
119         shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
120 
121   std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
122   DisconnectErr = joinErrors(std::move(DisconnectErr), std::move(Err));
123   Disconnected = true;
124   DisconnectCV.notify_all();
125 }
126 
127 Expected<std::unique_ptr<jitlink::JITLinkMemoryManager>>
128 SimpleRemoteEPC::createMemoryManager() {
129   EPCGenericJITLinkMemoryManager::SymbolAddrs SAs;
130   if (auto Err = getBootstrapSymbols(
131           {{SAs.Allocator, rt::SimpleExecutorMemoryManagerInstanceName},
132            {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
133            {SAs.Finalize, rt::SimpleExecutorMemoryManagerFinalizeWrapperName},
134            {SAs.Deallocate,
135             rt::SimpleExecutorMemoryManagerDeallocateWrapperName}}))
136     return std::move(Err);
137 
138   return std::make_unique<EPCGenericJITLinkMemoryManager>(*this, SAs);
139 }
140 
141 Expected<std::unique_ptr<ExecutorProcessControl::MemoryAccess>>
142 SimpleRemoteEPC::createMemoryAccess() {
143 
144   return nullptr;
145 }
146 
147 Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddr TagAddr,
148                                    SimpleRemoteEPCArgBytesVector ArgBytes) {
149   if (SeqNo != 0)
150     return make_error<StringError>("Setup packet SeqNo not zero",
151                                    inconvertibleErrorCode());
152 
153   if (TagAddr)
154     return make_error<StringError>("Setup packet TagAddr not zero",
155                                    inconvertibleErrorCode());
156 
157   std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
158   auto I = PendingCallWrapperResults.find(0);
159   assert(PendingCallWrapperResults.size() == 1 &&
160          I != PendingCallWrapperResults.end() &&
161          "Setup message handler not connectly set up");
162   auto SetupMsgHandler = std::move(I->second);
163   PendingCallWrapperResults.erase(I);
164 
165   auto WFR =
166       shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
167   SetupMsgHandler(std::move(WFR));
168   return Error::success();
169 }
170 
171 void SimpleRemoteEPC::prepareToReceiveSetupMessage(
172     std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> &ExecInfoP) {
173   PendingCallWrapperResults[0] =
174       [&](shared::WrapperFunctionResult SetupMsgBytes) {
175         if (const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
176           ExecInfoP.set_value(
177               make_error<StringError>(ErrMsg, inconvertibleErrorCode()));
178           return;
179         }
180         using SPSSerialize =
181             shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
182         shared::SPSInputBuffer IB(SetupMsgBytes.data(), SetupMsgBytes.size());
183         SimpleRemoteEPCExecutorInfo EI;
184         if (SPSSerialize::deserialize(IB, EI))
185           ExecInfoP.set_value(EI);
186         else
187           ExecInfoP.set_value(make_error<StringError>(
188               "Could not deserialize setup message", inconvertibleErrorCode()));
189       };
190 }
191 
192 Error SimpleRemoteEPC::setup(std::unique_ptr<SimpleRemoteEPCTransport> T,
193                              SimpleRemoteEPCExecutorInfo EI) {
194   using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
195   LLVM_DEBUG({
196     dbgs() << "SimpleRemoteEPC received setup message:\n"
197            << "  Triple: " << EI.TargetTriple << "\n"
198            << "  Page size: " << EI.PageSize << "\n"
199            << "  Bootstrap symbols:\n";
200     for (const auto &KV : EI.BootstrapSymbols)
201       dbgs() << "    " << KV.first() << ": "
202              << formatv("{0:x16}", KV.second.getValue()) << "\n";
203   });
204   this->T = std::move(T);
205   TargetTriple = Triple(EI.TargetTriple);
206   PageSize = EI.PageSize;
207   BootstrapSymbols = std::move(EI.BootstrapSymbols);
208 
209   if (auto Err = getBootstrapSymbols(
210           {{JDI.JITDispatchContext, ExecutorSessionObjectName},
211            {JDI.JITDispatchFunction, DispatchFnName},
212            {RunAsMainAddr, rt::RunAsMainWrapperName}}))
213     return Err;
214 
215   if (auto DM =
216           EPCGenericDylibManager::CreateWithDefaultBootstrapSymbols(*this))
217     DylibMgr = std::make_unique<EPCGenericDylibManager>(std::move(*DM));
218   else
219     return DM.takeError();
220 
221   if (auto MemMgr = createMemoryManager()) {
222     OwnedMemMgr = std::move(*MemMgr);
223     this->MemMgr = OwnedMemMgr.get();
224   } else
225     return MemMgr.takeError();
226 
227   if (auto MemAccess = createMemoryAccess()) {
228     OwnedMemAccess = std::move(*MemAccess);
229     this->MemAccess = OwnedMemAccess.get();
230   } else
231     return MemAccess.takeError();
232 
233   return Error::success();
234 }
235 
236 Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddr TagAddr,
237                                     SimpleRemoteEPCArgBytesVector ArgBytes) {
238   SendResultFunction SendResult;
239 
240   if (TagAddr)
241     return make_error<StringError>("Unexpected TagAddr in result message",
242                                    inconvertibleErrorCode());
243 
244   {
245     std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
246     auto I = PendingCallWrapperResults.find(SeqNo);
247     if (I == PendingCallWrapperResults.end())
248       return make_error<StringError>("No call for sequence number " +
249                                          Twine(SeqNo),
250                                      inconvertibleErrorCode());
251     SendResult = std::move(I->second);
252     PendingCallWrapperResults.erase(I);
253     releaseSeqNo(SeqNo);
254   }
255 
256   auto WFR =
257       shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
258   SendResult(std::move(WFR));
259   return Error::success();
260 }
261 
262 void SimpleRemoteEPC::handleCallWrapper(
263     uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
264     SimpleRemoteEPCArgBytesVector ArgBytes) {
265   assert(ES && "No ExecutionSession attached");
266   ES->runJITDispatchHandler(
267       [this, RemoteSeqNo](shared::WrapperFunctionResult WFR) {
268         if (auto Err =
269                 T->sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
270                                ExecutorAddr(), {WFR.data(), WFR.size()}))
271           getExecutionSession().reportError(std::move(Err));
272       },
273       TagAddr.getValue(), ArgBytes);
274 }
275 
276 } // end namespace orc
277 } // end namespace llvm
278