xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ExecutionEngine/Orc/EPCIndirectionUtils.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1fe6060f1SDimitry Andric //===--- EPCIndirectionUtils.h - EPC based indirection utils ----*- C++ -*-===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric //
9fe6060f1SDimitry Andric // Indirection utilities (stubs, trampolines, lazy call-throughs) that use the
10fe6060f1SDimitry Andric // ExecutorProcessControl API to interact with the executor process.
11fe6060f1SDimitry Andric //
12fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
13fe6060f1SDimitry Andric 
14fe6060f1SDimitry Andric #ifndef LLVM_EXECUTIONENGINE_ORC_EPCINDIRECTIONUTILS_H
15fe6060f1SDimitry Andric #define LLVM_EXECUTIONENGINE_ORC_EPCINDIRECTIONUTILS_H
16fe6060f1SDimitry Andric 
17fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
18fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
19fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/Orc/LazyReexports.h"
20fe6060f1SDimitry Andric 
21fe6060f1SDimitry Andric #include <mutex>
22fe6060f1SDimitry Andric 
23fe6060f1SDimitry Andric namespace llvm {
24fe6060f1SDimitry Andric namespace orc {
25fe6060f1SDimitry Andric 
26fe6060f1SDimitry Andric class ExecutorProcessControl;
27fe6060f1SDimitry Andric 
28fe6060f1SDimitry Andric /// Provides ExecutorProcessControl based indirect stubs, trampoline pool and
29fe6060f1SDimitry Andric /// lazy call through manager.
30fe6060f1SDimitry Andric class EPCIndirectionUtils {
31fe6060f1SDimitry Andric   friend class EPCIndirectionUtilsAccess;
32fe6060f1SDimitry Andric 
33fe6060f1SDimitry Andric public:
34fe6060f1SDimitry Andric   /// ABI support base class. Used to write resolver, stub, and trampoline
35fe6060f1SDimitry Andric   /// blocks.
36fe6060f1SDimitry Andric   class ABISupport {
37fe6060f1SDimitry Andric   protected:
ABISupport(unsigned PointerSize,unsigned TrampolineSize,unsigned StubSize,unsigned StubToPointerMaxDisplacement,unsigned ResolverCodeSize)38fe6060f1SDimitry Andric     ABISupport(unsigned PointerSize, unsigned TrampolineSize, unsigned StubSize,
39fe6060f1SDimitry Andric                unsigned StubToPointerMaxDisplacement, unsigned ResolverCodeSize)
40fe6060f1SDimitry Andric         : PointerSize(PointerSize), TrampolineSize(TrampolineSize),
41fe6060f1SDimitry Andric           StubSize(StubSize),
42fe6060f1SDimitry Andric           StubToPointerMaxDisplacement(StubToPointerMaxDisplacement),
43fe6060f1SDimitry Andric           ResolverCodeSize(ResolverCodeSize) {}
44fe6060f1SDimitry Andric 
45fe6060f1SDimitry Andric   public:
46fe6060f1SDimitry Andric     virtual ~ABISupport();
47fe6060f1SDimitry Andric 
getPointerSize()48fe6060f1SDimitry Andric     unsigned getPointerSize() const { return PointerSize; }
getTrampolineSize()49fe6060f1SDimitry Andric     unsigned getTrampolineSize() const { return TrampolineSize; }
getStubSize()50fe6060f1SDimitry Andric     unsigned getStubSize() const { return StubSize; }
getStubToPointerMaxDisplacement()51fe6060f1SDimitry Andric     unsigned getStubToPointerMaxDisplacement() const {
52fe6060f1SDimitry Andric       return StubToPointerMaxDisplacement;
53fe6060f1SDimitry Andric     }
getResolverCodeSize()54fe6060f1SDimitry Andric     unsigned getResolverCodeSize() const { return ResolverCodeSize; }
55fe6060f1SDimitry Andric 
56fe6060f1SDimitry Andric     virtual void writeResolverCode(char *ResolverWorkingMem,
57*06c3fb27SDimitry Andric                                    ExecutorAddr ResolverTargetAddr,
58*06c3fb27SDimitry Andric                                    ExecutorAddr ReentryFnAddr,
59*06c3fb27SDimitry Andric                                    ExecutorAddr ReentryCtxAddr) const = 0;
60fe6060f1SDimitry Andric 
61fe6060f1SDimitry Andric     virtual void writeTrampolines(char *TrampolineBlockWorkingMem,
62*06c3fb27SDimitry Andric                                   ExecutorAddr TrampolineBlockTragetAddr,
63*06c3fb27SDimitry Andric                                   ExecutorAddr ResolverAddr,
64fe6060f1SDimitry Andric                                   unsigned NumTrampolines) const = 0;
65fe6060f1SDimitry Andric 
66*06c3fb27SDimitry Andric     virtual void writeIndirectStubsBlock(
67*06c3fb27SDimitry Andric         char *StubsBlockWorkingMem, ExecutorAddr StubsBlockTargetAddress,
68*06c3fb27SDimitry Andric         ExecutorAddr PointersBlockTargetAddress, unsigned NumStubs) const = 0;
69fe6060f1SDimitry Andric 
70fe6060f1SDimitry Andric   private:
71fe6060f1SDimitry Andric     unsigned PointerSize = 0;
72fe6060f1SDimitry Andric     unsigned TrampolineSize = 0;
73fe6060f1SDimitry Andric     unsigned StubSize = 0;
74fe6060f1SDimitry Andric     unsigned StubToPointerMaxDisplacement = 0;
75fe6060f1SDimitry Andric     unsigned ResolverCodeSize = 0;
76fe6060f1SDimitry Andric   };
77fe6060f1SDimitry Andric 
78fe6060f1SDimitry Andric   /// Create using the given ABI class.
79fe6060f1SDimitry Andric   template <typename ORCABI>
80fe6060f1SDimitry Andric   static std::unique_ptr<EPCIndirectionUtils>
81fe6060f1SDimitry Andric   CreateWithABI(ExecutorProcessControl &EPC);
82fe6060f1SDimitry Andric 
83fe6060f1SDimitry Andric   /// Create based on the ExecutorProcessControl triple.
84fe6060f1SDimitry Andric   static Expected<std::unique_ptr<EPCIndirectionUtils>>
85fe6060f1SDimitry Andric   Create(ExecutorProcessControl &EPC);
86fe6060f1SDimitry Andric 
87*06c3fb27SDimitry Andric   /// Create based on the ExecutorProcessControl triple.
88*06c3fb27SDimitry Andric   static Expected<std::unique_ptr<EPCIndirectionUtils>>
Create(ExecutionSession & ES)89*06c3fb27SDimitry Andric   Create(ExecutionSession &ES) {
90*06c3fb27SDimitry Andric     return Create(ES.getExecutorProcessControl());
91*06c3fb27SDimitry Andric   }
92*06c3fb27SDimitry Andric 
93fe6060f1SDimitry Andric   /// Return a reference to the ExecutorProcessControl object.
getExecutorProcessControl()94fe6060f1SDimitry Andric   ExecutorProcessControl &getExecutorProcessControl() const { return EPC; }
95fe6060f1SDimitry Andric 
96fe6060f1SDimitry Andric   /// Return a reference to the ABISupport object for this instance.
getABISupport()97fe6060f1SDimitry Andric   ABISupport &getABISupport() const { return *ABI; }
98fe6060f1SDimitry Andric 
99fe6060f1SDimitry Andric   /// Release memory for resources held by this instance. This *must* be called
100fe6060f1SDimitry Andric   /// prior to destruction of the class.
101fe6060f1SDimitry Andric   Error cleanup();
102fe6060f1SDimitry Andric 
103fe6060f1SDimitry Andric   /// Write resolver code to the executor process and return its address.
104fe6060f1SDimitry Andric   /// This must be called before any call to createTrampolinePool or
105fe6060f1SDimitry Andric   /// createLazyCallThroughManager.
106*06c3fb27SDimitry Andric   Expected<ExecutorAddr> writeResolverBlock(ExecutorAddr ReentryFnAddr,
107*06c3fb27SDimitry Andric                                             ExecutorAddr ReentryCtxAddr);
108fe6060f1SDimitry Andric 
109fe6060f1SDimitry Andric   /// Returns the address of the Resolver block. Returns zero if the
110fe6060f1SDimitry Andric   /// writeResolverBlock method has not previously been called.
getResolverBlockAddress()111*06c3fb27SDimitry Andric   ExecutorAddr getResolverBlockAddress() const { return ResolverBlockAddr; }
112fe6060f1SDimitry Andric 
113fe6060f1SDimitry Andric   /// Create an IndirectStubsManager for the executor process.
114fe6060f1SDimitry Andric   std::unique_ptr<IndirectStubsManager> createIndirectStubsManager();
115fe6060f1SDimitry Andric 
116fe6060f1SDimitry Andric   /// Create a TrampolinePool for the executor process.
117fe6060f1SDimitry Andric   TrampolinePool &getTrampolinePool();
118fe6060f1SDimitry Andric 
119fe6060f1SDimitry Andric   /// Create a LazyCallThroughManager.
120fe6060f1SDimitry Andric   /// This function should only be called once.
121fe6060f1SDimitry Andric   LazyCallThroughManager &
122fe6060f1SDimitry Andric   createLazyCallThroughManager(ExecutionSession &ES,
123*06c3fb27SDimitry Andric                                ExecutorAddr ErrorHandlerAddr);
124fe6060f1SDimitry Andric 
125fe6060f1SDimitry Andric   /// Create a LazyCallThroughManager for the executor process.
getLazyCallThroughManager()126fe6060f1SDimitry Andric   LazyCallThroughManager &getLazyCallThroughManager() {
127fe6060f1SDimitry Andric     assert(LCTM && "createLazyCallThroughManager must be called first");
128fe6060f1SDimitry Andric     return *LCTM;
129fe6060f1SDimitry Andric   }
130fe6060f1SDimitry Andric 
131fe6060f1SDimitry Andric private:
132349cc55cSDimitry Andric   using FinalizedAlloc = jitlink::JITLinkMemoryManager::FinalizedAlloc;
133fe6060f1SDimitry Andric 
134fe6060f1SDimitry Andric   struct IndirectStubInfo {
135fe6060f1SDimitry Andric     IndirectStubInfo() = default;
IndirectStubInfoIndirectStubInfo136*06c3fb27SDimitry Andric     IndirectStubInfo(ExecutorAddr StubAddress, ExecutorAddr PointerAddress)
137fe6060f1SDimitry Andric         : StubAddress(StubAddress), PointerAddress(PointerAddress) {}
138*06c3fb27SDimitry Andric     ExecutorAddr StubAddress;
139*06c3fb27SDimitry Andric     ExecutorAddr PointerAddress;
140fe6060f1SDimitry Andric   };
141fe6060f1SDimitry Andric 
142fe6060f1SDimitry Andric   using IndirectStubInfoVector = std::vector<IndirectStubInfo>;
143fe6060f1SDimitry Andric 
144fe6060f1SDimitry Andric   /// Create an EPCIndirectionUtils instance.
145fe6060f1SDimitry Andric   EPCIndirectionUtils(ExecutorProcessControl &EPC,
146fe6060f1SDimitry Andric                       std::unique_ptr<ABISupport> ABI);
147fe6060f1SDimitry Andric 
148fe6060f1SDimitry Andric   Expected<IndirectStubInfoVector> getIndirectStubs(unsigned NumStubs);
149fe6060f1SDimitry Andric 
150fe6060f1SDimitry Andric   std::mutex EPCUIMutex;
151fe6060f1SDimitry Andric   ExecutorProcessControl &EPC;
152fe6060f1SDimitry Andric   std::unique_ptr<ABISupport> ABI;
153*06c3fb27SDimitry Andric   ExecutorAddr ResolverBlockAddr;
154349cc55cSDimitry Andric   FinalizedAlloc ResolverBlock;
155fe6060f1SDimitry Andric   std::unique_ptr<TrampolinePool> TP;
156fe6060f1SDimitry Andric   std::unique_ptr<LazyCallThroughManager> LCTM;
157fe6060f1SDimitry Andric 
158fe6060f1SDimitry Andric   std::vector<IndirectStubInfo> AvailableIndirectStubs;
159349cc55cSDimitry Andric   std::vector<FinalizedAlloc> IndirectStubAllocs;
160fe6060f1SDimitry Andric };
161fe6060f1SDimitry Andric 
162fe6060f1SDimitry Andric /// This will call writeResolver on the given EPCIndirectionUtils instance
163fe6060f1SDimitry Andric /// to set up re-entry via a function that will directly return the trampoline
164fe6060f1SDimitry Andric /// landing address.
165fe6060f1SDimitry Andric ///
166fe6060f1SDimitry Andric /// The EPCIndirectionUtils' LazyCallThroughManager must have been previously
167fe6060f1SDimitry Andric /// created via EPCIndirectionUtils::createLazyCallThroughManager.
168fe6060f1SDimitry Andric ///
169fe6060f1SDimitry Andric /// The EPCIndirectionUtils' writeResolver method must not have been previously
170fe6060f1SDimitry Andric /// called.
171fe6060f1SDimitry Andric ///
172fe6060f1SDimitry Andric /// This function is experimental and likely subject to revision.
173fe6060f1SDimitry Andric Error setUpInProcessLCTMReentryViaEPCIU(EPCIndirectionUtils &EPCIU);
174fe6060f1SDimitry Andric 
175fe6060f1SDimitry Andric namespace detail {
176fe6060f1SDimitry Andric 
177fe6060f1SDimitry Andric template <typename ORCABI>
178fe6060f1SDimitry Andric class ABISupportImpl : public EPCIndirectionUtils::ABISupport {
179fe6060f1SDimitry Andric public:
ABISupportImpl()180fe6060f1SDimitry Andric   ABISupportImpl()
181fe6060f1SDimitry Andric       : ABISupport(ORCABI::PointerSize, ORCABI::TrampolineSize,
182fe6060f1SDimitry Andric                    ORCABI::StubSize, ORCABI::StubToPointerMaxDisplacement,
183fe6060f1SDimitry Andric                    ORCABI::ResolverCodeSize) {}
184fe6060f1SDimitry Andric 
writeResolverCode(char * ResolverWorkingMem,ExecutorAddr ResolverTargetAddr,ExecutorAddr ReentryFnAddr,ExecutorAddr ReentryCtxAddr)185fe6060f1SDimitry Andric   void writeResolverCode(char *ResolverWorkingMem,
186*06c3fb27SDimitry Andric                          ExecutorAddr ResolverTargetAddr,
187*06c3fb27SDimitry Andric                          ExecutorAddr ReentryFnAddr,
188*06c3fb27SDimitry Andric                          ExecutorAddr ReentryCtxAddr) const override {
189fe6060f1SDimitry Andric     ORCABI::writeResolverCode(ResolverWorkingMem, ResolverTargetAddr,
190fe6060f1SDimitry Andric                               ReentryFnAddr, ReentryCtxAddr);
191fe6060f1SDimitry Andric   }
192fe6060f1SDimitry Andric 
writeTrampolines(char * TrampolineBlockWorkingMem,ExecutorAddr TrampolineBlockTargetAddr,ExecutorAddr ResolverAddr,unsigned NumTrampolines)193fe6060f1SDimitry Andric   void writeTrampolines(char *TrampolineBlockWorkingMem,
194*06c3fb27SDimitry Andric                         ExecutorAddr TrampolineBlockTargetAddr,
195*06c3fb27SDimitry Andric                         ExecutorAddr ResolverAddr,
196fe6060f1SDimitry Andric                         unsigned NumTrampolines) const override {
197fe6060f1SDimitry Andric     ORCABI::writeTrampolines(TrampolineBlockWorkingMem,
198fe6060f1SDimitry Andric                              TrampolineBlockTargetAddr, ResolverAddr,
199fe6060f1SDimitry Andric                              NumTrampolines);
200fe6060f1SDimitry Andric   }
201fe6060f1SDimitry Andric 
writeIndirectStubsBlock(char * StubsBlockWorkingMem,ExecutorAddr StubsBlockTargetAddress,ExecutorAddr PointersBlockTargetAddress,unsigned NumStubs)202fe6060f1SDimitry Andric   void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
203*06c3fb27SDimitry Andric                                ExecutorAddr StubsBlockTargetAddress,
204*06c3fb27SDimitry Andric                                ExecutorAddr PointersBlockTargetAddress,
205fe6060f1SDimitry Andric                                unsigned NumStubs) const override {
206fe6060f1SDimitry Andric     ORCABI::writeIndirectStubsBlock(StubsBlockWorkingMem,
207fe6060f1SDimitry Andric                                     StubsBlockTargetAddress,
208fe6060f1SDimitry Andric                                     PointersBlockTargetAddress, NumStubs);
209fe6060f1SDimitry Andric   }
210fe6060f1SDimitry Andric };
211fe6060f1SDimitry Andric 
212fe6060f1SDimitry Andric } // end namespace detail
213fe6060f1SDimitry Andric 
214fe6060f1SDimitry Andric template <typename ORCABI>
215fe6060f1SDimitry Andric std::unique_ptr<EPCIndirectionUtils>
CreateWithABI(ExecutorProcessControl & EPC)216fe6060f1SDimitry Andric EPCIndirectionUtils::CreateWithABI(ExecutorProcessControl &EPC) {
217fe6060f1SDimitry Andric   return std::unique_ptr<EPCIndirectionUtils>(new EPCIndirectionUtils(
218fe6060f1SDimitry Andric       EPC, std::make_unique<detail::ABISupportImpl<ORCABI>>()));
219fe6060f1SDimitry Andric }
220fe6060f1SDimitry Andric 
221fe6060f1SDimitry Andric } // end namespace orc
222fe6060f1SDimitry Andric } // end namespace llvm
223fe6060f1SDimitry Andric 
224fe6060f1SDimitry Andric #endif // LLVM_EXECUTIONENGINE_ORC_EPCINDIRECTIONUTILS_H
225