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