xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===- ExecutorProcessControl.h - Executor process control APIs -*- C++ -*-===//
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 // Utilities for interacting with the executor processes.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_EXECUTIONENGINE_ORC_EXECUTORPROCESSCONTROL_H
14 #define LLVM_EXECUTIONENGINE_ORC_EXECUTORPROCESSCONTROL_H
15 
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
18 #include "llvm/ExecutionEngine/Orc/DylibManager.h"
19 #include "llvm/ExecutionEngine/Orc/MemoryAccess.h"
20 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
21 #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
22 #include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
23 #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
24 #include "llvm/ExecutionEngine/Orc/TargetProcess/UnwindInfoManager.h"
25 #include "llvm/ExecutionEngine/Orc/TaskDispatch.h"
26 #include "llvm/Support/Compiler.h"
27 #include "llvm/TargetParser/Triple.h"
28 
29 #include <future>
30 #include <mutex>
31 #include <vector>
32 
33 namespace llvm::orc {
34 
35 class ExecutionSession;
36 
37 /// ExecutorProcessControl supports interaction with a JIT target process.
38 class LLVM_ABI ExecutorProcessControl {
39   friend class ExecutionSession;
40 public:
41 
42   /// A handler or incoming WrapperFunctionResults -- either return values from
43   /// callWrapper* calls, or incoming JIT-dispatch requests.
44   ///
45   /// IncomingWFRHandlers are constructible from
46   /// unique_function<void(shared::WrapperFunctionResult)>s using the
47   /// runInPlace function or a RunWithDispatch object.
48   class IncomingWFRHandler {
49     friend class ExecutorProcessControl;
50   public:
51     IncomingWFRHandler() = default;
52     explicit operator bool() const { return !!H; }
operator()53     void operator()(shared::WrapperFunctionResult WFR) { H(std::move(WFR)); }
54   private:
IncomingWFRHandler(FnT && Fn)55     template <typename FnT> IncomingWFRHandler(FnT &&Fn)
56       : H(std::forward<FnT>(Fn)) {}
57 
58     unique_function<void(shared::WrapperFunctionResult)> H;
59   };
60 
61   /// Constructs an IncomingWFRHandler from a function object that is callable
62   /// as void(shared::WrapperFunctionResult). The function object will be called
63   /// directly. This should be used with care as it may block listener threads
64   /// in remote EPCs. It is only suitable for simple tasks (e.g. setting a
65   /// future), or for performing some quick analysis before dispatching "real"
66   /// work as a Task.
67   class RunInPlace {
68   public:
69     template <typename FnT>
operator()70     IncomingWFRHandler operator()(FnT &&Fn) {
71       return IncomingWFRHandler(std::forward<FnT>(Fn));
72     }
73   };
74 
75   /// Constructs an IncomingWFRHandler from a function object by creating a new
76   /// function object that dispatches the original using a TaskDispatcher,
77   /// wrapping the original as a GenericNamedTask.
78   ///
79   /// This is the default approach for running WFR handlers.
80   class RunAsTask {
81   public:
RunAsTask(TaskDispatcher & D)82     RunAsTask(TaskDispatcher &D) : D(D) {}
83 
84     template <typename FnT>
operator()85     IncomingWFRHandler operator()(FnT &&Fn) {
86       return IncomingWFRHandler(
87           [&D = this->D, Fn = std::move(Fn)]
88           (shared::WrapperFunctionResult WFR) mutable {
89               D.dispatch(
90                 makeGenericNamedTask(
91                     [Fn = std::move(Fn), WFR = std::move(WFR)]() mutable {
92                       Fn(std::move(WFR));
93                     }, "WFR handler task"));
94           });
95     }
96   private:
97     TaskDispatcher &D;
98   };
99 
100   /// Contains the address of the dispatch function and context that the ORC
101   /// runtime can use to call functions in the JIT.
102   struct JITDispatchInfo {
103     ExecutorAddr JITDispatchFunction;
104     ExecutorAddr JITDispatchContext;
105   };
106 
ExecutorProcessControl(std::shared_ptr<SymbolStringPool> SSP,std::unique_ptr<TaskDispatcher> D)107   ExecutorProcessControl(std::shared_ptr<SymbolStringPool> SSP,
108                          std::unique_ptr<TaskDispatcher> D)
109       : SSP(std::move(SSP)), D(std::move(D)) {}
110 
111   virtual ~ExecutorProcessControl();
112 
113   /// Return the ExecutionSession associated with this instance.
114   /// Not callable until the ExecutionSession has been associated.
getExecutionSession()115   ExecutionSession &getExecutionSession() {
116     assert(ES && "No ExecutionSession associated yet");
117     return *ES;
118   }
119 
120   /// Intern a symbol name in the SymbolStringPool.
intern(StringRef SymName)121   SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); }
122 
123   /// Return a shared pointer to the SymbolStringPool for this instance.
getSymbolStringPool()124   std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; }
125 
getDispatcher()126   TaskDispatcher &getDispatcher() { return *D; }
127 
128   /// Return the Triple for the target process.
getTargetTriple()129   const Triple &getTargetTriple() const { return TargetTriple; }
130 
131   /// Get the page size for the target process.
getPageSize()132   unsigned getPageSize() const { return PageSize; }
133 
134   /// Get the JIT dispatch function and context address for the executor.
getJITDispatchInfo()135   const JITDispatchInfo &getJITDispatchInfo() const { return JDI; }
136 
137   /// Return a MemoryAccess object for the target process.
getMemoryAccess()138   MemoryAccess &getMemoryAccess() const {
139     assert(MemAccess && "No MemAccess object set.");
140     return *MemAccess;
141   }
142 
143   /// Return a JITLinkMemoryManager for the target process.
getMemMgr()144   jitlink::JITLinkMemoryManager &getMemMgr() const {
145     assert(MemMgr && "No MemMgr object set");
146     return *MemMgr;
147   }
148 
149   /// Return the DylibManager for the target process.
getDylibMgr()150   DylibManager &getDylibMgr() const {
151     assert(DylibMgr && "No DylibMgr object set");
152     return *DylibMgr;
153   }
154 
155   /// Returns the bootstrap map.
getBootstrapMap()156   const StringMap<std::vector<char>> &getBootstrapMap() const {
157     return BootstrapMap;
158   }
159 
160   /// Look up and SPS-deserialize a bootstrap map value.
161   template <typename T, typename SPSTagT>
getBootstrapMapValue(StringRef Key,std::optional<T> & Val)162   Error getBootstrapMapValue(StringRef Key, std::optional<T> &Val) const {
163     Val = std::nullopt;
164 
165     auto I = BootstrapMap.find(Key);
166     if (I == BootstrapMap.end())
167       return Error::success();
168 
169     T Tmp;
170     shared::SPSInputBuffer IB(I->second.data(), I->second.size());
171     if (!shared::SPSArgList<SPSTagT>::deserialize(IB, Tmp))
172       return make_error<StringError>("Could not deserialize value for key " +
173                                          Key,
174                                      inconvertibleErrorCode());
175 
176     Val = std::move(Tmp);
177     return Error::success();
178   }
179 
180   /// Returns the bootstrap symbol map.
getBootstrapSymbolsMap()181   const StringMap<ExecutorAddr> &getBootstrapSymbolsMap() const {
182     return BootstrapSymbols;
183   }
184 
185   /// For each (ExecutorAddr&, StringRef) pair, looks up the string in the
186   /// bootstrap symbols map and writes its address to the ExecutorAddr if
187   /// found. If any symbol is not found then the function returns an error.
getBootstrapSymbols(ArrayRef<std::pair<ExecutorAddr &,StringRef>> Pairs)188   Error getBootstrapSymbols(
189       ArrayRef<std::pair<ExecutorAddr &, StringRef>> Pairs) const {
190     for (const auto &KV : Pairs) {
191       auto I = BootstrapSymbols.find(KV.second);
192       if (I == BootstrapSymbols.end())
193         return make_error<StringError>("Symbol \"" + KV.second +
194                                            "\" not found "
195                                            "in bootstrap symbols map",
196                                        inconvertibleErrorCode());
197 
198       KV.first = I->second;
199     }
200     return Error::success();
201   }
202 
203   /// Run function with a main-like signature.
204   virtual Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
205                                       ArrayRef<std::string> Args) = 0;
206 
207   // TODO: move this to ORC runtime.
208   /// Run function with a int (*)(void) signature.
209   virtual Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) = 0;
210 
211   // TODO: move this to ORC runtime.
212   /// Run function with a int (*)(int) signature.
213   virtual Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr,
214                                              int Arg) = 0;
215 
216   /// Run a wrapper function in the executor. The given WFRHandler will be
217   /// called on the result when it is returned.
218   ///
219   /// The wrapper function should be callable as:
220   ///
221   /// \code{.cpp}
222   ///   CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
223   /// \endcode{.cpp}
224   virtual void callWrapperAsync(ExecutorAddr WrapperFnAddr,
225                                 IncomingWFRHandler OnComplete,
226                                 ArrayRef<char> ArgBuffer) = 0;
227 
228   /// Run a wrapper function in the executor using the given Runner to dispatch
229   /// OnComplete when the result is ready.
230   template <typename RunPolicyT, typename FnT>
callWrapperAsync(RunPolicyT && Runner,ExecutorAddr WrapperFnAddr,FnT && OnComplete,ArrayRef<char> ArgBuffer)231   void callWrapperAsync(RunPolicyT &&Runner, ExecutorAddr WrapperFnAddr,
232                         FnT &&OnComplete, ArrayRef<char> ArgBuffer) {
233     callWrapperAsync(
234         WrapperFnAddr, Runner(std::forward<FnT>(OnComplete)), ArgBuffer);
235   }
236 
237   /// Run a wrapper function in the executor. OnComplete will be dispatched
238   /// as a GenericNamedTask using this instance's TaskDispatch object.
239   template <typename FnT>
callWrapperAsync(ExecutorAddr WrapperFnAddr,FnT && OnComplete,ArrayRef<char> ArgBuffer)240   void callWrapperAsync(ExecutorAddr WrapperFnAddr, FnT &&OnComplete,
241                         ArrayRef<char> ArgBuffer) {
242     callWrapperAsync(RunAsTask(*D), WrapperFnAddr,
243                      std::forward<FnT>(OnComplete), ArgBuffer);
244   }
245 
246   /// Run a wrapper function in the executor. The wrapper function should be
247   /// callable as:
248   ///
249   /// \code{.cpp}
250   ///   CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
251   /// \endcode{.cpp}
callWrapper(ExecutorAddr WrapperFnAddr,ArrayRef<char> ArgBuffer)252   shared::WrapperFunctionResult callWrapper(ExecutorAddr WrapperFnAddr,
253                                             ArrayRef<char> ArgBuffer) {
254     std::promise<shared::WrapperFunctionResult> RP;
255     auto RF = RP.get_future();
256     callWrapperAsync(
257         RunInPlace(), WrapperFnAddr,
258         [&](shared::WrapperFunctionResult R) {
259           RP.set_value(std::move(R));
260         }, ArgBuffer);
261     return RF.get();
262   }
263 
264   /// Run a wrapper function using SPS to serialize the arguments and
265   /// deserialize the results.
266   template <typename SPSSignature, typename RunPolicyT, typename SendResultT,
267             typename... ArgTs>
callSPSWrapperAsync(RunPolicyT && Runner,ExecutorAddr WrapperFnAddr,SendResultT && SendResult,const ArgTs &...Args)268   void callSPSWrapperAsync(RunPolicyT &&Runner, ExecutorAddr WrapperFnAddr,
269                            SendResultT &&SendResult, const ArgTs &...Args) {
270     shared::WrapperFunction<SPSSignature>::callAsync(
271         [this, WrapperFnAddr, Runner = std::move(Runner)]
272         (auto &&SendResult, const char *ArgData, size_t ArgSize) mutable {
273           this->callWrapperAsync(std::move(Runner), WrapperFnAddr,
274                                  std::move(SendResult),
275                                  ArrayRef<char>(ArgData, ArgSize));
276         },
277         std::forward<SendResultT>(SendResult), Args...);
278   }
279 
280   /// Run a wrapper function using SPS to serialize the arguments and
281   /// deserialize the results.
282   template <typename SPSSignature, typename SendResultT, typename... ArgTs>
callSPSWrapperAsync(ExecutorAddr WrapperFnAddr,SendResultT && SendResult,const ArgTs &...Args)283   void callSPSWrapperAsync(ExecutorAddr WrapperFnAddr, SendResultT &&SendResult,
284                            const ArgTs &...Args) {
285     callSPSWrapperAsync<SPSSignature>(RunAsTask(*D), WrapperFnAddr,
286                                       std::forward<SendResultT>(SendResult),
287                                       Args...);
288   }
289 
290   /// Run a wrapper function using SPS to serialize the arguments and
291   /// deserialize the results.
292   ///
293   /// If SPSSignature is a non-void function signature then the second argument
294   /// (the first in the Args list) should be a reference to a return value.
295   template <typename SPSSignature, typename... WrapperCallArgTs>
callSPSWrapper(ExecutorAddr WrapperFnAddr,WrapperCallArgTs &&...WrapperCallArgs)296   Error callSPSWrapper(ExecutorAddr WrapperFnAddr,
297                        WrapperCallArgTs &&...WrapperCallArgs) {
298     return shared::WrapperFunction<SPSSignature>::call(
299         [this, WrapperFnAddr](const char *ArgData, size_t ArgSize) {
300           return callWrapper(WrapperFnAddr, ArrayRef<char>(ArgData, ArgSize));
301         },
302         std::forward<WrapperCallArgTs>(WrapperCallArgs)...);
303   }
304 
305   /// Disconnect from the target process.
306   ///
307   /// This should be called after the JIT session is shut down.
308   virtual Error disconnect() = 0;
309 
310 protected:
311 
312   std::shared_ptr<SymbolStringPool> SSP;
313   std::unique_ptr<TaskDispatcher> D;
314   ExecutionSession *ES = nullptr;
315   Triple TargetTriple;
316   unsigned PageSize = 0;
317   JITDispatchInfo JDI;
318   MemoryAccess *MemAccess = nullptr;
319   jitlink::JITLinkMemoryManager *MemMgr = nullptr;
320   DylibManager *DylibMgr = nullptr;
321   StringMap<std::vector<char>> BootstrapMap;
322   StringMap<ExecutorAddr> BootstrapSymbols;
323 };
324 
325 } // namespace llvm::orc
326 
327 #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTORPROCESSCONTROL_H
328