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