Back to home page

EIC code displayed by LXR

 
 

    


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

0001 //===--- EPCIndirectionUtils.h - EPC based indirection utils ----*- 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 // Indirection utilities (stubs, trampolines, lazy call-throughs) that use the
0010 // ExecutorProcessControl API to interact with the executor process.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_EXECUTIONENGINE_ORC_EPCINDIRECTIONUTILS_H
0015 #define LLVM_EXECUTIONENGINE_ORC_EPCINDIRECTIONUTILS_H
0016 
0017 #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
0018 #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
0019 #include "llvm/ExecutionEngine/Orc/LazyReexports.h"
0020 
0021 #include <mutex>
0022 
0023 namespace llvm {
0024 namespace orc {
0025 
0026 class ExecutorProcessControl;
0027 
0028 /// Provides ExecutorProcessControl based indirect stubs, trampoline pool and
0029 /// lazy call through manager.
0030 class EPCIndirectionUtils {
0031   friend class EPCIndirectionUtilsAccess;
0032 
0033 public:
0034   /// ABI support base class. Used to write resolver, stub, and trampoline
0035   /// blocks.
0036   class ABISupport {
0037   protected:
0038     ABISupport(unsigned PointerSize, unsigned TrampolineSize, unsigned StubSize,
0039                unsigned StubToPointerMaxDisplacement, unsigned ResolverCodeSize)
0040         : PointerSize(PointerSize), TrampolineSize(TrampolineSize),
0041           StubSize(StubSize),
0042           StubToPointerMaxDisplacement(StubToPointerMaxDisplacement),
0043           ResolverCodeSize(ResolverCodeSize) {}
0044 
0045   public:
0046     virtual ~ABISupport();
0047 
0048     unsigned getPointerSize() const { return PointerSize; }
0049     unsigned getTrampolineSize() const { return TrampolineSize; }
0050     unsigned getStubSize() const { return StubSize; }
0051     unsigned getStubToPointerMaxDisplacement() const {
0052       return StubToPointerMaxDisplacement;
0053     }
0054     unsigned getResolverCodeSize() const { return ResolverCodeSize; }
0055 
0056     virtual void writeResolverCode(char *ResolverWorkingMem,
0057                                    ExecutorAddr ResolverTargetAddr,
0058                                    ExecutorAddr ReentryFnAddr,
0059                                    ExecutorAddr ReentryCtxAddr) const = 0;
0060 
0061     virtual void writeTrampolines(char *TrampolineBlockWorkingMem,
0062                                   ExecutorAddr TrampolineBlockTragetAddr,
0063                                   ExecutorAddr ResolverAddr,
0064                                   unsigned NumTrampolines) const = 0;
0065 
0066     virtual void writeIndirectStubsBlock(
0067         char *StubsBlockWorkingMem, ExecutorAddr StubsBlockTargetAddress,
0068         ExecutorAddr PointersBlockTargetAddress, unsigned NumStubs) const = 0;
0069 
0070   private:
0071     unsigned PointerSize = 0;
0072     unsigned TrampolineSize = 0;
0073     unsigned StubSize = 0;
0074     unsigned StubToPointerMaxDisplacement = 0;
0075     unsigned ResolverCodeSize = 0;
0076   };
0077 
0078   /// Create using the given ABI class.
0079   template <typename ORCABI>
0080   static std::unique_ptr<EPCIndirectionUtils>
0081   CreateWithABI(ExecutorProcessControl &EPC);
0082 
0083   /// Create based on the ExecutorProcessControl triple.
0084   static Expected<std::unique_ptr<EPCIndirectionUtils>>
0085   Create(ExecutorProcessControl &EPC);
0086 
0087   /// Create based on the ExecutorProcessControl triple.
0088   static Expected<std::unique_ptr<EPCIndirectionUtils>>
0089   Create(ExecutionSession &ES) {
0090     return Create(ES.getExecutorProcessControl());
0091   }
0092 
0093   /// Return a reference to the ExecutorProcessControl object.
0094   ExecutorProcessControl &getExecutorProcessControl() const { return EPC; }
0095 
0096   /// Return a reference to the ABISupport object for this instance.
0097   ABISupport &getABISupport() const { return *ABI; }
0098 
0099   /// Release memory for resources held by this instance. This *must* be called
0100   /// prior to destruction of the class.
0101   Error cleanup();
0102 
0103   /// Write resolver code to the executor process and return its address.
0104   /// This must be called before any call to createTrampolinePool or
0105   /// createLazyCallThroughManager.
0106   Expected<ExecutorAddr> writeResolverBlock(ExecutorAddr ReentryFnAddr,
0107                                             ExecutorAddr ReentryCtxAddr);
0108 
0109   /// Returns the address of the Resolver block. Returns zero if the
0110   /// writeResolverBlock method has not previously been called.
0111   ExecutorAddr getResolverBlockAddress() const { return ResolverBlockAddr; }
0112 
0113   /// Create an IndirectStubsManager for the executor process.
0114   std::unique_ptr<IndirectStubsManager> createIndirectStubsManager();
0115 
0116   /// Create a TrampolinePool for the executor process.
0117   TrampolinePool &getTrampolinePool();
0118 
0119   /// Create a LazyCallThroughManager.
0120   /// This function should only be called once.
0121   LazyCallThroughManager &
0122   createLazyCallThroughManager(ExecutionSession &ES,
0123                                ExecutorAddr ErrorHandlerAddr);
0124 
0125   /// Create a LazyCallThroughManager for the executor process.
0126   LazyCallThroughManager &getLazyCallThroughManager() {
0127     assert(LCTM && "createLazyCallThroughManager must be called first");
0128     return *LCTM;
0129   }
0130 
0131 private:
0132   using FinalizedAlloc = jitlink::JITLinkMemoryManager::FinalizedAlloc;
0133 
0134   struct IndirectStubInfo {
0135     IndirectStubInfo() = default;
0136     IndirectStubInfo(ExecutorAddr StubAddress, ExecutorAddr PointerAddress)
0137         : StubAddress(StubAddress), PointerAddress(PointerAddress) {}
0138     ExecutorAddr StubAddress;
0139     ExecutorAddr PointerAddress;
0140   };
0141 
0142   using IndirectStubInfoVector = std::vector<IndirectStubInfo>;
0143 
0144   /// Create an EPCIndirectionUtils instance.
0145   EPCIndirectionUtils(ExecutorProcessControl &EPC,
0146                       std::unique_ptr<ABISupport> ABI);
0147 
0148   Expected<IndirectStubInfoVector> getIndirectStubs(unsigned NumStubs);
0149 
0150   std::mutex EPCUIMutex;
0151   ExecutorProcessControl &EPC;
0152   std::unique_ptr<ABISupport> ABI;
0153   ExecutorAddr ResolverBlockAddr;
0154   FinalizedAlloc ResolverBlock;
0155   std::unique_ptr<TrampolinePool> TP;
0156   std::unique_ptr<LazyCallThroughManager> LCTM;
0157 
0158   std::vector<IndirectStubInfo> AvailableIndirectStubs;
0159   std::vector<FinalizedAlloc> IndirectStubAllocs;
0160 };
0161 
0162 /// This will call writeResolver on the given EPCIndirectionUtils instance
0163 /// to set up re-entry via a function that will directly return the trampoline
0164 /// landing address.
0165 ///
0166 /// The EPCIndirectionUtils' LazyCallThroughManager must have been previously
0167 /// created via EPCIndirectionUtils::createLazyCallThroughManager.
0168 ///
0169 /// The EPCIndirectionUtils' writeResolver method must not have been previously
0170 /// called.
0171 ///
0172 /// This function is experimental and likely subject to revision.
0173 Error setUpInProcessLCTMReentryViaEPCIU(EPCIndirectionUtils &EPCIU);
0174 
0175 namespace detail {
0176 
0177 template <typename ORCABI>
0178 class ABISupportImpl : public EPCIndirectionUtils::ABISupport {
0179 public:
0180   ABISupportImpl()
0181       : ABISupport(ORCABI::PointerSize, ORCABI::TrampolineSize,
0182                    ORCABI::StubSize, ORCABI::StubToPointerMaxDisplacement,
0183                    ORCABI::ResolverCodeSize) {}
0184 
0185   void writeResolverCode(char *ResolverWorkingMem,
0186                          ExecutorAddr ResolverTargetAddr,
0187                          ExecutorAddr ReentryFnAddr,
0188                          ExecutorAddr ReentryCtxAddr) const override {
0189     ORCABI::writeResolverCode(ResolverWorkingMem, ResolverTargetAddr,
0190                               ReentryFnAddr, ReentryCtxAddr);
0191   }
0192 
0193   void writeTrampolines(char *TrampolineBlockWorkingMem,
0194                         ExecutorAddr TrampolineBlockTargetAddr,
0195                         ExecutorAddr ResolverAddr,
0196                         unsigned NumTrampolines) const override {
0197     ORCABI::writeTrampolines(TrampolineBlockWorkingMem,
0198                              TrampolineBlockTargetAddr, ResolverAddr,
0199                              NumTrampolines);
0200   }
0201 
0202   void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
0203                                ExecutorAddr StubsBlockTargetAddress,
0204                                ExecutorAddr PointersBlockTargetAddress,
0205                                unsigned NumStubs) const override {
0206     ORCABI::writeIndirectStubsBlock(StubsBlockWorkingMem,
0207                                     StubsBlockTargetAddress,
0208                                     PointersBlockTargetAddress, NumStubs);
0209   }
0210 };
0211 
0212 } // end namespace detail
0213 
0214 template <typename ORCABI>
0215 std::unique_ptr<EPCIndirectionUtils>
0216 EPCIndirectionUtils::CreateWithABI(ExecutorProcessControl &EPC) {
0217   return std::unique_ptr<EPCIndirectionUtils>(new EPCIndirectionUtils(
0218       EPC, std::make_unique<detail::ABISupportImpl<ORCABI>>()));
0219 }
0220 
0221 } // end namespace orc
0222 } // end namespace llvm
0223 
0224 #endif // LLVM_EXECUTIONENGINE_ORC_EPCINDIRECTIONUTILS_H