Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:53

0001 //===- ExecutorProcessControl.h - Executor process control APIs -*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // Utilities for interacting with the executor processes.
0010 //
0011 //===----------------------------------------------------------------------===//
0012 
0013 #ifndef LLVM_EXECUTIONENGINE_ORC_EXECUTORPROCESSCONTROL_H
0014 #define LLVM_EXECUTIONENGINE_ORC_EXECUTORPROCESSCONTROL_H
0015 
0016 #include "llvm/ADT/StringRef.h"
0017 #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
0018 #include "llvm/ExecutionEngine/Orc/DylibManager.h"
0019 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
0020 #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
0021 #include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
0022 #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
0023 #include "llvm/ExecutionEngine/Orc/TargetProcess/UnwindInfoManager.h"
0024 #include "llvm/ExecutionEngine/Orc/TaskDispatch.h"
0025 #include "llvm/Support/DynamicLibrary.h"
0026 #include "llvm/Support/MSVCErrorWorkarounds.h"
0027 #include "llvm/TargetParser/Triple.h"
0028 
0029 #include <future>
0030 #include <mutex>
0031 #include <vector>
0032 
0033 namespace llvm {
0034 namespace orc {
0035 
0036 class ExecutionSession;
0037 
0038 /// ExecutorProcessControl supports interaction with a JIT target process.
0039 class ExecutorProcessControl {
0040   friend class ExecutionSession;
0041 public:
0042 
0043   /// A handler or incoming WrapperFunctionResults -- either return values from
0044   /// callWrapper* calls, or incoming JIT-dispatch requests.
0045   ///
0046   /// IncomingWFRHandlers are constructible from
0047   /// unique_function<void(shared::WrapperFunctionResult)>s using the
0048   /// runInPlace function or a RunWithDispatch object.
0049   class IncomingWFRHandler {
0050     friend class ExecutorProcessControl;
0051   public:
0052     IncomingWFRHandler() = default;
0053     explicit operator bool() const { return !!H; }
0054     void operator()(shared::WrapperFunctionResult WFR) { H(std::move(WFR)); }
0055   private:
0056     template <typename FnT> IncomingWFRHandler(FnT &&Fn)
0057       : H(std::forward<FnT>(Fn)) {}
0058 
0059     unique_function<void(shared::WrapperFunctionResult)> H;
0060   };
0061 
0062   /// Constructs an IncomingWFRHandler from a function object that is callable
0063   /// as void(shared::WrapperFunctionResult). The function object will be called
0064   /// directly. This should be used with care as it may block listener threads
0065   /// in remote EPCs. It is only suitable for simple tasks (e.g. setting a
0066   /// future), or for performing some quick analysis before dispatching "real"
0067   /// work as a Task.
0068   class RunInPlace {
0069   public:
0070     template <typename FnT>
0071     IncomingWFRHandler operator()(FnT &&Fn) {
0072       return IncomingWFRHandler(std::forward<FnT>(Fn));
0073     }
0074   };
0075 
0076   /// Constructs an IncomingWFRHandler from a function object by creating a new
0077   /// function object that dispatches the original using a TaskDispatcher,
0078   /// wrapping the original as a GenericNamedTask.
0079   ///
0080   /// This is the default approach for running WFR handlers.
0081   class RunAsTask {
0082   public:
0083     RunAsTask(TaskDispatcher &D) : D(D) {}
0084 
0085     template <typename FnT>
0086     IncomingWFRHandler operator()(FnT &&Fn) {
0087       return IncomingWFRHandler(
0088           [&D = this->D, Fn = std::move(Fn)]
0089           (shared::WrapperFunctionResult WFR) mutable {
0090               D.dispatch(
0091                 makeGenericNamedTask(
0092                     [Fn = std::move(Fn), WFR = std::move(WFR)]() mutable {
0093                       Fn(std::move(WFR));
0094                     }, "WFR handler task"));
0095           });
0096     }
0097   private:
0098     TaskDispatcher &D;
0099   };
0100 
0101   /// APIs for manipulating memory in the target process.
0102   class MemoryAccess {
0103   public:
0104     /// Callback function for asynchronous writes.
0105     using WriteResultFn = unique_function<void(Error)>;
0106 
0107     virtual ~MemoryAccess();
0108 
0109     virtual void writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws,
0110                                   WriteResultFn OnWriteComplete) = 0;
0111 
0112     virtual void writeUInt16sAsync(ArrayRef<tpctypes::UInt16Write> Ws,
0113                                    WriteResultFn OnWriteComplete) = 0;
0114 
0115     virtual void writeUInt32sAsync(ArrayRef<tpctypes::UInt32Write> Ws,
0116                                    WriteResultFn OnWriteComplete) = 0;
0117 
0118     virtual void writeUInt64sAsync(ArrayRef<tpctypes::UInt64Write> Ws,
0119                                    WriteResultFn OnWriteComplete) = 0;
0120 
0121     virtual void writeBuffersAsync(ArrayRef<tpctypes::BufferWrite> Ws,
0122                                    WriteResultFn OnWriteComplete) = 0;
0123 
0124     virtual void writePointersAsync(ArrayRef<tpctypes::PointerWrite> Ws,
0125                                     WriteResultFn OnWriteComplete) = 0;
0126 
0127     Error writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws) {
0128       std::promise<MSVCPError> ResultP;
0129       auto ResultF = ResultP.get_future();
0130       writeUInt8sAsync(Ws,
0131                        [&](Error Err) { ResultP.set_value(std::move(Err)); });
0132       return ResultF.get();
0133     }
0134 
0135     Error writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws) {
0136       std::promise<MSVCPError> ResultP;
0137       auto ResultF = ResultP.get_future();
0138       writeUInt16sAsync(Ws,
0139                         [&](Error Err) { ResultP.set_value(std::move(Err)); });
0140       return ResultF.get();
0141     }
0142 
0143     Error writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws) {
0144       std::promise<MSVCPError> ResultP;
0145       auto ResultF = ResultP.get_future();
0146       writeUInt32sAsync(Ws,
0147                         [&](Error Err) { ResultP.set_value(std::move(Err)); });
0148       return ResultF.get();
0149     }
0150 
0151     Error writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws) {
0152       std::promise<MSVCPError> ResultP;
0153       auto ResultF = ResultP.get_future();
0154       writeUInt64sAsync(Ws,
0155                         [&](Error Err) { ResultP.set_value(std::move(Err)); });
0156       return ResultF.get();
0157     }
0158 
0159     Error writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws) {
0160       std::promise<MSVCPError> ResultP;
0161       auto ResultF = ResultP.get_future();
0162       writeBuffersAsync(Ws,
0163                         [&](Error Err) { ResultP.set_value(std::move(Err)); });
0164       return ResultF.get();
0165     }
0166 
0167     Error writePointers(ArrayRef<tpctypes::PointerWrite> Ws) {
0168       std::promise<MSVCPError> ResultP;
0169       auto ResultF = ResultP.get_future();
0170       writePointersAsync(Ws,
0171                          [&](Error Err) { ResultP.set_value(std::move(Err)); });
0172       return ResultF.get();
0173     }
0174   };
0175 
0176   /// Contains the address of the dispatch function and context that the ORC
0177   /// runtime can use to call functions in the JIT.
0178   struct JITDispatchInfo {
0179     ExecutorAddr JITDispatchFunction;
0180     ExecutorAddr JITDispatchContext;
0181   };
0182 
0183   ExecutorProcessControl(std::shared_ptr<SymbolStringPool> SSP,
0184                          std::unique_ptr<TaskDispatcher> D)
0185       : SSP(std::move(SSP)), D(std::move(D)) {}
0186 
0187   virtual ~ExecutorProcessControl();
0188 
0189   /// Return the ExecutionSession associated with this instance.
0190   /// Not callable until the ExecutionSession has been associated.
0191   ExecutionSession &getExecutionSession() {
0192     assert(ES && "No ExecutionSession associated yet");
0193     return *ES;
0194   }
0195 
0196   /// Intern a symbol name in the SymbolStringPool.
0197   SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); }
0198 
0199   /// Return a shared pointer to the SymbolStringPool for this instance.
0200   std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; }
0201 
0202   TaskDispatcher &getDispatcher() { return *D; }
0203 
0204   /// Return the Triple for the target process.
0205   const Triple &getTargetTriple() const { return TargetTriple; }
0206 
0207   /// Get the page size for the target process.
0208   unsigned getPageSize() const { return PageSize; }
0209 
0210   /// Get the JIT dispatch function and context address for the executor.
0211   const JITDispatchInfo &getJITDispatchInfo() const { return JDI; }
0212 
0213   /// Return a MemoryAccess object for the target process.
0214   MemoryAccess &getMemoryAccess() const {
0215     assert(MemAccess && "No MemAccess object set.");
0216     return *MemAccess;
0217   }
0218 
0219   /// Return a JITLinkMemoryManager for the target process.
0220   jitlink::JITLinkMemoryManager &getMemMgr() const {
0221     assert(MemMgr && "No MemMgr object set");
0222     return *MemMgr;
0223   }
0224 
0225   /// Return the DylibManager for the target process.
0226   DylibManager &getDylibMgr() const {
0227     assert(DylibMgr && "No DylibMgr object set");
0228     return *DylibMgr;
0229   }
0230 
0231   /// Returns the bootstrap map.
0232   const StringMap<std::vector<char>> &getBootstrapMap() const {
0233     return BootstrapMap;
0234   }
0235 
0236   /// Look up and SPS-deserialize a bootstrap map value.
0237   template <typename T, typename SPSTagT>
0238   Error getBootstrapMapValue(StringRef Key, std::optional<T> &Val) const {
0239     Val = std::nullopt;
0240 
0241     auto I = BootstrapMap.find(Key);
0242     if (I == BootstrapMap.end())
0243       return Error::success();
0244 
0245     T Tmp;
0246     shared::SPSInputBuffer IB(I->second.data(), I->second.size());
0247     if (!shared::SPSArgList<SPSTagT>::deserialize(IB, Tmp))
0248       return make_error<StringError>("Could not deserialize value for key " +
0249                                          Key,
0250                                      inconvertibleErrorCode());
0251 
0252     Val = std::move(Tmp);
0253     return Error::success();
0254   }
0255 
0256   /// Returns the bootstrap symbol map.
0257   const StringMap<ExecutorAddr> &getBootstrapSymbolsMap() const {
0258     return BootstrapSymbols;
0259   }
0260 
0261   /// For each (ExecutorAddr&, StringRef) pair, looks up the string in the
0262   /// bootstrap symbols map and writes its address to the ExecutorAddr if
0263   /// found. If any symbol is not found then the function returns an error.
0264   Error getBootstrapSymbols(
0265       ArrayRef<std::pair<ExecutorAddr &, StringRef>> Pairs) const {
0266     for (const auto &KV : Pairs) {
0267       auto I = BootstrapSymbols.find(KV.second);
0268       if (I == BootstrapSymbols.end())
0269         return make_error<StringError>("Symbol \"" + KV.second +
0270                                            "\" not found "
0271                                            "in bootstrap symbols map",
0272                                        inconvertibleErrorCode());
0273 
0274       KV.first = I->second;
0275     }
0276     return Error::success();
0277   }
0278 
0279   /// Run function with a main-like signature.
0280   virtual Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
0281                                       ArrayRef<std::string> Args) = 0;
0282 
0283   // TODO: move this to ORC runtime.
0284   /// Run function with a int (*)(void) signature.
0285   virtual Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) = 0;
0286 
0287   // TODO: move this to ORC runtime.
0288   /// Run function with a int (*)(int) signature.
0289   virtual Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr,
0290                                              int Arg) = 0;
0291 
0292   /// Run a wrapper function in the executor. The given WFRHandler will be
0293   /// called on the result when it is returned.
0294   ///
0295   /// The wrapper function should be callable as:
0296   ///
0297   /// \code{.cpp}
0298   ///   CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
0299   /// \endcode{.cpp}
0300   virtual void callWrapperAsync(ExecutorAddr WrapperFnAddr,
0301                                 IncomingWFRHandler OnComplete,
0302                                 ArrayRef<char> ArgBuffer) = 0;
0303 
0304   /// Run a wrapper function in the executor using the given Runner to dispatch
0305   /// OnComplete when the result is ready.
0306   template <typename RunPolicyT, typename FnT>
0307   void callWrapperAsync(RunPolicyT &&Runner, ExecutorAddr WrapperFnAddr,
0308                         FnT &&OnComplete, ArrayRef<char> ArgBuffer) {
0309     callWrapperAsync(
0310         WrapperFnAddr, Runner(std::forward<FnT>(OnComplete)), ArgBuffer);
0311   }
0312 
0313   /// Run a wrapper function in the executor. OnComplete will be dispatched
0314   /// as a GenericNamedTask using this instance's TaskDispatch object.
0315   template <typename FnT>
0316   void callWrapperAsync(ExecutorAddr WrapperFnAddr, FnT &&OnComplete,
0317                         ArrayRef<char> ArgBuffer) {
0318     callWrapperAsync(RunAsTask(*D), WrapperFnAddr,
0319                      std::forward<FnT>(OnComplete), ArgBuffer);
0320   }
0321 
0322   /// Run a wrapper function in the executor. The wrapper function should be
0323   /// callable as:
0324   ///
0325   /// \code{.cpp}
0326   ///   CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
0327   /// \endcode{.cpp}
0328   shared::WrapperFunctionResult callWrapper(ExecutorAddr WrapperFnAddr,
0329                                             ArrayRef<char> ArgBuffer) {
0330     std::promise<shared::WrapperFunctionResult> RP;
0331     auto RF = RP.get_future();
0332     callWrapperAsync(
0333         RunInPlace(), WrapperFnAddr,
0334         [&](shared::WrapperFunctionResult R) {
0335           RP.set_value(std::move(R));
0336         }, ArgBuffer);
0337     return RF.get();
0338   }
0339 
0340   /// Run a wrapper function using SPS to serialize the arguments and
0341   /// deserialize the results.
0342   template <typename SPSSignature, typename RunPolicyT, typename SendResultT,
0343             typename... ArgTs>
0344   void callSPSWrapperAsync(RunPolicyT &&Runner, ExecutorAddr WrapperFnAddr,
0345                            SendResultT &&SendResult, const ArgTs &...Args) {
0346     shared::WrapperFunction<SPSSignature>::callAsync(
0347         [this, WrapperFnAddr, Runner = std::move(Runner)]
0348         (auto &&SendResult, const char *ArgData, size_t ArgSize) mutable {
0349           this->callWrapperAsync(std::move(Runner), WrapperFnAddr,
0350                                  std::move(SendResult),
0351                                  ArrayRef<char>(ArgData, ArgSize));
0352         },
0353         std::forward<SendResultT>(SendResult), Args...);
0354   }
0355 
0356   /// Run a wrapper function using SPS to serialize the arguments and
0357   /// deserialize the results.
0358   template <typename SPSSignature, typename SendResultT, typename... ArgTs>
0359   void callSPSWrapperAsync(ExecutorAddr WrapperFnAddr, SendResultT &&SendResult,
0360                            const ArgTs &...Args) {
0361     callSPSWrapperAsync<SPSSignature>(RunAsTask(*D), WrapperFnAddr,
0362                                       std::forward<SendResultT>(SendResult),
0363                                       Args...);
0364   }
0365 
0366   /// Run a wrapper function using SPS to serialize the arguments and
0367   /// deserialize the results.
0368   ///
0369   /// If SPSSignature is a non-void function signature then the second argument
0370   /// (the first in the Args list) should be a reference to a return value.
0371   template <typename SPSSignature, typename... WrapperCallArgTs>
0372   Error callSPSWrapper(ExecutorAddr WrapperFnAddr,
0373                        WrapperCallArgTs &&...WrapperCallArgs) {
0374     return shared::WrapperFunction<SPSSignature>::call(
0375         [this, WrapperFnAddr](const char *ArgData, size_t ArgSize) {
0376           return callWrapper(WrapperFnAddr, ArrayRef<char>(ArgData, ArgSize));
0377         },
0378         std::forward<WrapperCallArgTs>(WrapperCallArgs)...);
0379   }
0380 
0381   /// Disconnect from the target process.
0382   ///
0383   /// This should be called after the JIT session is shut down.
0384   virtual Error disconnect() = 0;
0385 
0386 protected:
0387 
0388   std::shared_ptr<SymbolStringPool> SSP;
0389   std::unique_ptr<TaskDispatcher> D;
0390   ExecutionSession *ES = nullptr;
0391   Triple TargetTriple;
0392   unsigned PageSize = 0;
0393   JITDispatchInfo JDI;
0394   MemoryAccess *MemAccess = nullptr;
0395   jitlink::JITLinkMemoryManager *MemMgr = nullptr;
0396   DylibManager *DylibMgr = nullptr;
0397   StringMap<std::vector<char>> BootstrapMap;
0398   StringMap<ExecutorAddr> BootstrapSymbols;
0399 };
0400 
0401 class InProcessMemoryAccess : public ExecutorProcessControl::MemoryAccess {
0402 public:
0403   InProcessMemoryAccess(bool IsArch64Bit) : IsArch64Bit(IsArch64Bit) {}
0404   void writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws,
0405                         WriteResultFn OnWriteComplete) override;
0406 
0407   void writeUInt16sAsync(ArrayRef<tpctypes::UInt16Write> Ws,
0408                          WriteResultFn OnWriteComplete) override;
0409 
0410   void writeUInt32sAsync(ArrayRef<tpctypes::UInt32Write> Ws,
0411                          WriteResultFn OnWriteComplete) override;
0412 
0413   void writeUInt64sAsync(ArrayRef<tpctypes::UInt64Write> Ws,
0414                          WriteResultFn OnWriteComplete) override;
0415 
0416   void writeBuffersAsync(ArrayRef<tpctypes::BufferWrite> Ws,
0417                          WriteResultFn OnWriteComplete) override;
0418 
0419   void writePointersAsync(ArrayRef<tpctypes::PointerWrite> Ws,
0420                           WriteResultFn OnWriteComplete) override;
0421 
0422 private:
0423   bool IsArch64Bit;
0424 };
0425 
0426 /// A ExecutorProcessControl instance that asserts if any of its methods are
0427 /// used. Suitable for use is unit tests, and by ORC clients who haven't moved
0428 /// to ExecutorProcessControl-based APIs yet.
0429 class UnsupportedExecutorProcessControl : public ExecutorProcessControl,
0430                                           private InProcessMemoryAccess {
0431 public:
0432   UnsupportedExecutorProcessControl(
0433       std::shared_ptr<SymbolStringPool> SSP = nullptr,
0434       std::unique_ptr<TaskDispatcher> D = nullptr, const std::string &TT = "",
0435       unsigned PageSize = 0)
0436       : ExecutorProcessControl(
0437             SSP ? std::move(SSP) : std::make_shared<SymbolStringPool>(),
0438             D ? std::move(D) : std::make_unique<InPlaceTaskDispatcher>()),
0439         InProcessMemoryAccess(Triple(TT).isArch64Bit()) {
0440     this->TargetTriple = Triple(TT);
0441     this->PageSize = PageSize;
0442     this->MemAccess = this;
0443   }
0444 
0445   Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
0446                               ArrayRef<std::string> Args) override {
0447     llvm_unreachable("Unsupported");
0448   }
0449 
0450   Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) override {
0451     llvm_unreachable("Unsupported");
0452   }
0453 
0454   Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override {
0455     llvm_unreachable("Unsupported");
0456   }
0457 
0458   void callWrapperAsync(ExecutorAddr WrapperFnAddr,
0459                         IncomingWFRHandler OnComplete,
0460                         ArrayRef<char> ArgBuffer) override {
0461     llvm_unreachable("Unsupported");
0462   }
0463 
0464   Error disconnect() override { return Error::success(); }
0465 };
0466 
0467 /// A ExecutorProcessControl implementation targeting the current process.
0468 class SelfExecutorProcessControl : public ExecutorProcessControl,
0469                                    private InProcessMemoryAccess,
0470                                    private DylibManager {
0471 public:
0472   SelfExecutorProcessControl(
0473       std::shared_ptr<SymbolStringPool> SSP, std::unique_ptr<TaskDispatcher> D,
0474       Triple TargetTriple, unsigned PageSize,
0475       std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr);
0476 
0477   /// Create a SelfExecutorProcessControl with the given symbol string pool and
0478   /// memory manager.
0479   /// If no symbol string pool is given then one will be created.
0480   /// If no memory manager is given a jitlink::InProcessMemoryManager will
0481   /// be created and used by default.
0482   static Expected<std::unique_ptr<SelfExecutorProcessControl>>
0483   Create(std::shared_ptr<SymbolStringPool> SSP = nullptr,
0484          std::unique_ptr<TaskDispatcher> D = nullptr,
0485          std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr = nullptr);
0486 
0487   Expected<int32_t> runAsMain(ExecutorAddr MainFnAddr,
0488                               ArrayRef<std::string> Args) override;
0489 
0490   Expected<int32_t> runAsVoidFunction(ExecutorAddr VoidFnAddr) override;
0491 
0492   Expected<int32_t> runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override;
0493 
0494   void callWrapperAsync(ExecutorAddr WrapperFnAddr,
0495                         IncomingWFRHandler OnComplete,
0496                         ArrayRef<char> ArgBuffer) override;
0497 
0498   Error disconnect() override;
0499 
0500 private:
0501   static shared::CWrapperFunctionResult
0502   jitDispatchViaWrapperFunctionManager(void *Ctx, const void *FnTag,
0503                                        const char *Data, size_t Size);
0504 
0505   Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override;
0506 
0507   void lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
0508                           SymbolLookupCompleteFn F) override;
0509 
0510   std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;
0511 #ifdef __APPLE__
0512   std::unique_ptr<UnwindInfoManager> UnwindInfoMgr;
0513 #endif // __APPLE__
0514   char GlobalManglingPrefix = 0;
0515 };
0516 
0517 } // end namespace orc
0518 } // end namespace llvm
0519 
0520 #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTORPROCESSCONTROL_H