xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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/Shared/ExecutorAddress.h"
19 #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
20 #include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
21 #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
22 #include "llvm/ExecutionEngine/Orc/TaskDispatch.h"
23 #include "llvm/Support/DynamicLibrary.h"
24 #include "llvm/Support/MSVCErrorWorkarounds.h"
25 #include "llvm/TargetParser/Triple.h"
26 
27 #include <future>
28 #include <mutex>
29 #include <vector>
30 
31 namespace llvm {
32 namespace orc {
33 
34 class ExecutionSession;
35 class SymbolLookupSet;
36 
37 /// ExecutorProcessControl supports interaction with a JIT target process.
38 class 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   /// APIs for manipulating memory in the target process.
101   class MemoryAccess {
102   public:
103     /// Callback function for asynchronous writes.
104     using WriteResultFn = unique_function<void(Error)>;
105 
106     virtual ~MemoryAccess();
107 
108     virtual void writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws,
109                                   WriteResultFn OnWriteComplete) = 0;
110 
111     virtual void writeUInt16sAsync(ArrayRef<tpctypes::UInt16Write> Ws,
112                                    WriteResultFn OnWriteComplete) = 0;
113 
114     virtual void writeUInt32sAsync(ArrayRef<tpctypes::UInt32Write> Ws,
115                                    WriteResultFn OnWriteComplete) = 0;
116 
117     virtual void writeUInt64sAsync(ArrayRef<tpctypes::UInt64Write> Ws,
118                                    WriteResultFn OnWriteComplete) = 0;
119 
120     virtual void writeBuffersAsync(ArrayRef<tpctypes::BufferWrite> Ws,
121                                    WriteResultFn OnWriteComplete) = 0;
122 
123     virtual void writePointersAsync(ArrayRef<tpctypes::PointerWrite> Ws,
124                                     WriteResultFn OnWriteComplete) = 0;
125 
writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws)126     Error writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws) {
127       std::promise<MSVCPError> ResultP;
128       auto ResultF = ResultP.get_future();
129       writeUInt8sAsync(Ws,
130                        [&](Error Err) { ResultP.set_value(std::move(Err)); });
131       return ResultF.get();
132     }
133 
writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws)134     Error writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws) {
135       std::promise<MSVCPError> ResultP;
136       auto ResultF = ResultP.get_future();
137       writeUInt16sAsync(Ws,
138                         [&](Error Err) { ResultP.set_value(std::move(Err)); });
139       return ResultF.get();
140     }
141 
writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws)142     Error writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws) {
143       std::promise<MSVCPError> ResultP;
144       auto ResultF = ResultP.get_future();
145       writeUInt32sAsync(Ws,
146                         [&](Error Err) { ResultP.set_value(std::move(Err)); });
147       return ResultF.get();
148     }
149 
writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws)150     Error writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws) {
151       std::promise<MSVCPError> ResultP;
152       auto ResultF = ResultP.get_future();
153       writeUInt64sAsync(Ws,
154                         [&](Error Err) { ResultP.set_value(std::move(Err)); });
155       return ResultF.get();
156     }
157 
writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws)158     Error writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws) {
159       std::promise<MSVCPError> ResultP;
160       auto ResultF = ResultP.get_future();
161       writeBuffersAsync(Ws,
162                         [&](Error Err) { ResultP.set_value(std::move(Err)); });
163       return ResultF.get();
164     }
165 
writePointers(ArrayRef<tpctypes::PointerWrite> Ws)166     Error writePointers(ArrayRef<tpctypes::PointerWrite> Ws) {
167       std::promise<MSVCPError> ResultP;
168       auto ResultF = ResultP.get_future();
169       writePointersAsync(Ws,
170                          [&](Error Err) { ResultP.set_value(std::move(Err)); });
171       return ResultF.get();
172     }
173   };
174 
175   /// A pair of a dylib and a set of symbols to be looked up.
176   struct LookupRequest {
LookupRequestLookupRequest177     LookupRequest(tpctypes::DylibHandle Handle, const SymbolLookupSet &Symbols)
178         : Handle(Handle), Symbols(Symbols) {}
179     tpctypes::DylibHandle Handle;
180     const SymbolLookupSet &Symbols;
181   };
182 
183   /// Contains the address of the dispatch function and context that the ORC
184   /// runtime can use to call functions in the JIT.
185   struct JITDispatchInfo {
186     ExecutorAddr JITDispatchFunction;
187     ExecutorAddr JITDispatchContext;
188   };
189 
ExecutorProcessControl(std::shared_ptr<SymbolStringPool> SSP,std::unique_ptr<TaskDispatcher> D)190   ExecutorProcessControl(std::shared_ptr<SymbolStringPool> SSP,
191                          std::unique_ptr<TaskDispatcher> D)
192     : SSP(std::move(SSP)), D(std::move(D)) {}
193 
194   virtual ~ExecutorProcessControl();
195 
196   /// Return the ExecutionSession associated with this instance.
197   /// Not callable until the ExecutionSession has been associated.
getExecutionSession()198   ExecutionSession &getExecutionSession() {
199     assert(ES && "No ExecutionSession associated yet");
200     return *ES;
201   }
202 
203   /// Intern a symbol name in the SymbolStringPool.
intern(StringRef SymName)204   SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); }
205 
206   /// Return a shared pointer to the SymbolStringPool for this instance.
getSymbolStringPool()207   std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; }
208 
getDispatcher()209   TaskDispatcher &getDispatcher() { return *D; }
210 
211   /// Return the Triple for the target process.
getTargetTriple()212   const Triple &getTargetTriple() const { return TargetTriple; }
213 
214   /// Get the page size for the target process.
getPageSize()215   unsigned getPageSize() const { return PageSize; }
216 
217   /// Get the JIT dispatch function and context address for the executor.
getJITDispatchInfo()218   const JITDispatchInfo &getJITDispatchInfo() const { return JDI; }
219 
220   /// Return a MemoryAccess object for the target process.
getMemoryAccess()221   MemoryAccess &getMemoryAccess() const {
222     assert(MemAccess && "No MemAccess object set.");
223     return *MemAccess;
224   }
225 
226   /// Return a JITLinkMemoryManager for the target process.
getMemMgr()227   jitlink::JITLinkMemoryManager &getMemMgr() const {
228     assert(MemMgr && "No MemMgr object set");
229     return *MemMgr;
230   }
231 
232   /// Returns the bootstrap map.
getBootstrapMap()233   const StringMap<std::vector<char>> &getBootstrapMap() const {
234     return BootstrapMap;
235   }
236 
237   /// Look up and SPS-deserialize a bootstrap map value.
238   ///
239   ///
240   template <typename T, typename SPSTagT>
getBootstrapMapValue(StringRef Key,std::optional<T> & Val)241   Error getBootstrapMapValue(StringRef Key, std::optional<T> &Val) const {
242     Val = std::nullopt;
243 
244     auto I = BootstrapMap.find(Key);
245     if (I == BootstrapMap.end())
246       return Error::success();
247 
248     T Tmp;
249     shared::SPSInputBuffer IB(I->second.data(), I->second.size());
250     if (!shared::SPSArgList<SPSTagT>::deserialize(IB, Tmp))
251       return make_error<StringError>("Could not deserialize value for key " +
252                                          Key,
253                                      inconvertibleErrorCode());
254 
255     Val = std::move(Tmp);
256     return Error::success();
257   }
258 
259   /// Returns the bootstrap symbol map.
getBootstrapSymbolsMap()260   const StringMap<ExecutorAddr> &getBootstrapSymbolsMap() const {
261     return BootstrapSymbols;
262   }
263 
264   /// For each (ExecutorAddr&, StringRef) pair, looks up the string in the
265   /// bootstrap symbols map and writes its address to the ExecutorAddr if
266   /// found. If any symbol is not found then the function returns an error.
getBootstrapSymbols(ArrayRef<std::pair<ExecutorAddr &,StringRef>> Pairs)267   Error getBootstrapSymbols(
268       ArrayRef<std::pair<ExecutorAddr &, StringRef>> Pairs) const {
269     for (const auto &KV : Pairs) {
270       auto I = BootstrapSymbols.find(KV.second);
271       if (I == BootstrapSymbols.end())
272         return make_error<StringError>("Symbol \"" + KV.second +
273                                            "\" not found "
274                                            "in bootstrap symbols map",
275                                        inconvertibleErrorCode());
276 
277       KV.first = I->second;
278     }
279     return Error::success();
280   }
281 
282   /// Load the dynamic library at the given path and return a handle to it.
283   /// If LibraryPath is null this function will return the global handle for
284   /// the target process.
285   virtual Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) = 0;
286 
287   /// Search for symbols in the target process.
288   ///
289   /// The result of the lookup is a 2-dimensional array of target addresses
290   /// that correspond to the lookup order. If a required symbol is not
291   /// found then this method will return an error. If a weakly referenced
292   /// symbol is not found then it be assigned a '0' value.
293   Expected<std::vector<tpctypes::LookupResult>>
lookupSymbols(ArrayRef<LookupRequest> Request)294   lookupSymbols(ArrayRef<LookupRequest> Request) {
295     std::promise<MSVCPExpected<std::vector<tpctypes::LookupResult>>> RP;
296     auto RF = RP.get_future();
297     lookupSymbolsAsync(Request,
298                        [&RP](auto Result) { RP.set_value(std::move(Result)); });
299     return RF.get();
300   }
301 
302   using SymbolLookupCompleteFn =
303       unique_function<void(Expected<std::vector<tpctypes::LookupResult>>)>;
304 
305   /// Search for symbols in the target process.
306   ///
307   /// The result of the lookup is a 2-dimensional array of target addresses
308   /// that correspond to the lookup order. If a required symbol is not
309   /// found then this method will return an error. If a weakly referenced
310   /// symbol is not found then it be assigned a '0' value.
311   virtual void lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
312                                   SymbolLookupCompleteFn F) = 0;
313 
314   /// Run function with a main-like signature.
315   virtual Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
316                                       ArrayRef<std::string> Args) = 0;
317 
318   // TODO: move this to ORC runtime.
319   /// Run function with a int (*)(void) signature.
320   virtual Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) = 0;
321 
322   // TODO: move this to ORC runtime.
323   /// Run function with a int (*)(int) signature.
324   virtual Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr,
325                                              int Arg) = 0;
326 
327   /// Run a wrapper function in the executor. The given WFRHandler will be
328   /// called on the result when it is returned.
329   ///
330   /// The wrapper function should be callable as:
331   ///
332   /// \code{.cpp}
333   ///   CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
334   /// \endcode{.cpp}
335   virtual void callWrapperAsync(ExecutorAddr WrapperFnAddr,
336                                 IncomingWFRHandler OnComplete,
337                                 ArrayRef<char> ArgBuffer) = 0;
338 
339   /// Run a wrapper function in the executor using the given Runner to dispatch
340   /// OnComplete when the result is ready.
341   template <typename RunPolicyT, typename FnT>
callWrapperAsync(RunPolicyT && Runner,ExecutorAddr WrapperFnAddr,FnT && OnComplete,ArrayRef<char> ArgBuffer)342   void callWrapperAsync(RunPolicyT &&Runner, ExecutorAddr WrapperFnAddr,
343                         FnT &&OnComplete, ArrayRef<char> ArgBuffer) {
344     callWrapperAsync(
345         WrapperFnAddr, Runner(std::forward<FnT>(OnComplete)), ArgBuffer);
346   }
347 
348   /// Run a wrapper function in the executor. OnComplete will be dispatched
349   /// as a GenericNamedTask using this instance's TaskDispatch object.
350   template <typename FnT>
callWrapperAsync(ExecutorAddr WrapperFnAddr,FnT && OnComplete,ArrayRef<char> ArgBuffer)351   void callWrapperAsync(ExecutorAddr WrapperFnAddr, FnT &&OnComplete,
352                         ArrayRef<char> ArgBuffer) {
353     callWrapperAsync(RunAsTask(*D), WrapperFnAddr,
354                      std::forward<FnT>(OnComplete), ArgBuffer);
355   }
356 
357   /// Run a wrapper function in the executor. The wrapper function should be
358   /// callable as:
359   ///
360   /// \code{.cpp}
361   ///   CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
362   /// \endcode{.cpp}
callWrapper(ExecutorAddr WrapperFnAddr,ArrayRef<char> ArgBuffer)363   shared::WrapperFunctionResult callWrapper(ExecutorAddr WrapperFnAddr,
364                                             ArrayRef<char> ArgBuffer) {
365     std::promise<shared::WrapperFunctionResult> RP;
366     auto RF = RP.get_future();
367     callWrapperAsync(
368         RunInPlace(), WrapperFnAddr,
369         [&](shared::WrapperFunctionResult R) {
370           RP.set_value(std::move(R));
371         }, ArgBuffer);
372     return RF.get();
373   }
374 
375   /// Run a wrapper function using SPS to serialize the arguments and
376   /// deserialize the results.
377   template <typename SPSSignature, typename RunPolicyT, typename SendResultT,
378             typename... ArgTs>
callSPSWrapperAsync(RunPolicyT && Runner,ExecutorAddr WrapperFnAddr,SendResultT && SendResult,const ArgTs &...Args)379   void callSPSWrapperAsync(RunPolicyT &&Runner, ExecutorAddr WrapperFnAddr,
380                            SendResultT &&SendResult, const ArgTs &...Args) {
381     shared::WrapperFunction<SPSSignature>::callAsync(
382         [this, WrapperFnAddr, Runner = std::move(Runner)]
383         (auto &&SendResult, const char *ArgData, size_t ArgSize) mutable {
384           this->callWrapperAsync(std::move(Runner), WrapperFnAddr,
385                                  std::move(SendResult),
386                                  ArrayRef<char>(ArgData, ArgSize));
387         },
388         std::forward<SendResultT>(SendResult), Args...);
389   }
390 
391   /// Run a wrapper function using SPS to serialize the arguments and
392   /// deserialize the results.
393   template <typename SPSSignature, typename SendResultT, typename... ArgTs>
callSPSWrapperAsync(ExecutorAddr WrapperFnAddr,SendResultT && SendResult,const ArgTs &...Args)394   void callSPSWrapperAsync(ExecutorAddr WrapperFnAddr, SendResultT &&SendResult,
395                            const ArgTs &...Args) {
396     callSPSWrapperAsync<SPSSignature>(RunAsTask(*D), WrapperFnAddr,
397                                       std::forward<SendResultT>(SendResult),
398                                       Args...);
399   }
400 
401   /// Run a wrapper function using SPS to serialize the arguments and
402   /// deserialize the results.
403   ///
404   /// If SPSSignature is a non-void function signature then the second argument
405   /// (the first in the Args list) should be a reference to a return value.
406   template <typename SPSSignature, typename... WrapperCallArgTs>
callSPSWrapper(ExecutorAddr WrapperFnAddr,WrapperCallArgTs &&...WrapperCallArgs)407   Error callSPSWrapper(ExecutorAddr WrapperFnAddr,
408                        WrapperCallArgTs &&...WrapperCallArgs) {
409     return shared::WrapperFunction<SPSSignature>::call(
410         [this, WrapperFnAddr](const char *ArgData, size_t ArgSize) {
411           return callWrapper(WrapperFnAddr, ArrayRef<char>(ArgData, ArgSize));
412         },
413         std::forward<WrapperCallArgTs>(WrapperCallArgs)...);
414   }
415 
416   /// Disconnect from the target process.
417   ///
418   /// This should be called after the JIT session is shut down.
419   virtual Error disconnect() = 0;
420 
421 protected:
422 
423   std::shared_ptr<SymbolStringPool> SSP;
424   std::unique_ptr<TaskDispatcher> D;
425   ExecutionSession *ES = nullptr;
426   Triple TargetTriple;
427   unsigned PageSize = 0;
428   JITDispatchInfo JDI;
429   MemoryAccess *MemAccess = nullptr;
430   jitlink::JITLinkMemoryManager *MemMgr = nullptr;
431   StringMap<std::vector<char>> BootstrapMap;
432   StringMap<ExecutorAddr> BootstrapSymbols;
433 };
434 
435 class InProcessMemoryAccess : public ExecutorProcessControl::MemoryAccess {
436 public:
InProcessMemoryAccess(bool IsArch64Bit)437   InProcessMemoryAccess(bool IsArch64Bit) : IsArch64Bit(IsArch64Bit) {}
438   void writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws,
439                         WriteResultFn OnWriteComplete) override;
440 
441   void writeUInt16sAsync(ArrayRef<tpctypes::UInt16Write> Ws,
442                          WriteResultFn OnWriteComplete) override;
443 
444   void writeUInt32sAsync(ArrayRef<tpctypes::UInt32Write> Ws,
445                          WriteResultFn OnWriteComplete) override;
446 
447   void writeUInt64sAsync(ArrayRef<tpctypes::UInt64Write> Ws,
448                          WriteResultFn OnWriteComplete) override;
449 
450   void writeBuffersAsync(ArrayRef<tpctypes::BufferWrite> Ws,
451                          WriteResultFn OnWriteComplete) override;
452 
453   void writePointersAsync(ArrayRef<tpctypes::PointerWrite> Ws,
454                           WriteResultFn OnWriteComplete) override;
455 
456 private:
457   bool IsArch64Bit;
458 };
459 
460 /// A ExecutorProcessControl instance that asserts if any of its methods are
461 /// used. Suitable for use is unit tests, and by ORC clients who haven't moved
462 /// to ExecutorProcessControl-based APIs yet.
463 class UnsupportedExecutorProcessControl : public ExecutorProcessControl,
464                                           private InProcessMemoryAccess {
465 public:
466   UnsupportedExecutorProcessControl(
467       std::shared_ptr<SymbolStringPool> SSP = nullptr,
468       std::unique_ptr<TaskDispatcher> D = nullptr, const std::string &TT = "",
469       unsigned PageSize = 0)
470       : ExecutorProcessControl(
471             SSP ? std::move(SSP) : std::make_shared<SymbolStringPool>(),
472             D ? std::move(D) : std::make_unique<InPlaceTaskDispatcher>()),
473         InProcessMemoryAccess(Triple(TT).isArch64Bit()) {
474     this->TargetTriple = Triple(TT);
475     this->PageSize = PageSize;
476     this->MemAccess = this;
477   }
478 
loadDylib(const char * DylibPath)479   Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override {
480     llvm_unreachable("Unsupported");
481   }
482 
lookupSymbolsAsync(ArrayRef<LookupRequest> Request,SymbolLookupCompleteFn F)483   void lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
484                           SymbolLookupCompleteFn F) override {
485     llvm_unreachable("Unsupported");
486   }
487 
runAsMain(ExecutorAddr MainFnAddr,ArrayRef<std::string> Args)488   Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
489                               ArrayRef<std::string> Args) override {
490     llvm_unreachable("Unsupported");
491   }
492 
runAsVoidFunction(ExecutorAddr VoidFnAddr)493   Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) override {
494     llvm_unreachable("Unsupported");
495   }
496 
runAsIntFunction(ExecutorAddr IntFnAddr,int Arg)497   Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override {
498     llvm_unreachable("Unsupported");
499   }
500 
callWrapperAsync(ExecutorAddr WrapperFnAddr,IncomingWFRHandler OnComplete,ArrayRef<char> ArgBuffer)501   void callWrapperAsync(ExecutorAddr WrapperFnAddr,
502                         IncomingWFRHandler OnComplete,
503                         ArrayRef<char> ArgBuffer) override {
504     llvm_unreachable("Unsupported");
505   }
506 
disconnect()507   Error disconnect() override { return Error::success(); }
508 };
509 
510 /// A ExecutorProcessControl implementation targeting the current process.
511 class SelfExecutorProcessControl : public ExecutorProcessControl,
512                                    private InProcessMemoryAccess {
513 public:
514   SelfExecutorProcessControl(
515       std::shared_ptr<SymbolStringPool> SSP, std::unique_ptr<TaskDispatcher> D,
516       Triple TargetTriple, unsigned PageSize,
517       std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr);
518 
519   /// Create a SelfExecutorProcessControl with the given symbol string pool and
520   /// memory manager.
521   /// If no symbol string pool is given then one will be created.
522   /// If no memory manager is given a jitlink::InProcessMemoryManager will
523   /// be created and used by default.
524   static Expected<std::unique_ptr<SelfExecutorProcessControl>>
525   Create(std::shared_ptr<SymbolStringPool> SSP = nullptr,
526          std::unique_ptr<TaskDispatcher> D = nullptr,
527          std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr = nullptr);
528 
529   Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override;
530 
531   void lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
532                           SymbolLookupCompleteFn F) override;
533 
534   Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
535                               ArrayRef<std::string> Args) override;
536 
537   Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) override;
538 
539   Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override;
540 
541   void callWrapperAsync(ExecutorAddr WrapperFnAddr,
542                         IncomingWFRHandler OnComplete,
543                         ArrayRef<char> ArgBuffer) override;
544 
545   Error disconnect() override;
546 
547 private:
548   static shared::CWrapperFunctionResult
549   jitDispatchViaWrapperFunctionManager(void *Ctx, const void *FnTag,
550                                        const char *Data, size_t Size);
551 
552   std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;
553   char GlobalManglingPrefix = 0;
554 };
555 
556 } // end namespace orc
557 } // end namespace llvm
558 
559 #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTORPROCESSCONTROL_H
560