xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCIndirectionUtils.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
1*fe6060f1SDimitry Andric //===------- EPCIndirectionUtils.cpp -- EPC based indirection APIs --------===//
2*fe6060f1SDimitry Andric //
3*fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*fe6060f1SDimitry Andric //
7*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8*fe6060f1SDimitry Andric 
9*fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/Orc/EPCIndirectionUtils.h"
10*fe6060f1SDimitry Andric 
11*fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
12*fe6060f1SDimitry Andric #include "llvm/Support/MathExtras.h"
13*fe6060f1SDimitry Andric 
14*fe6060f1SDimitry Andric #include <future>
15*fe6060f1SDimitry Andric 
16*fe6060f1SDimitry Andric using namespace llvm;
17*fe6060f1SDimitry Andric using namespace llvm::orc;
18*fe6060f1SDimitry Andric 
19*fe6060f1SDimitry Andric namespace llvm {
20*fe6060f1SDimitry Andric namespace orc {
21*fe6060f1SDimitry Andric 
22*fe6060f1SDimitry Andric class EPCIndirectionUtilsAccess {
23*fe6060f1SDimitry Andric public:
24*fe6060f1SDimitry Andric   using IndirectStubInfo = EPCIndirectionUtils::IndirectStubInfo;
25*fe6060f1SDimitry Andric   using IndirectStubInfoVector = EPCIndirectionUtils::IndirectStubInfoVector;
26*fe6060f1SDimitry Andric 
27*fe6060f1SDimitry Andric   static Expected<IndirectStubInfoVector>
28*fe6060f1SDimitry Andric   getIndirectStubs(EPCIndirectionUtils &EPCIU, unsigned NumStubs) {
29*fe6060f1SDimitry Andric     return EPCIU.getIndirectStubs(NumStubs);
30*fe6060f1SDimitry Andric   };
31*fe6060f1SDimitry Andric };
32*fe6060f1SDimitry Andric 
33*fe6060f1SDimitry Andric } // end namespace orc
34*fe6060f1SDimitry Andric } // end namespace llvm
35*fe6060f1SDimitry Andric 
36*fe6060f1SDimitry Andric namespace {
37*fe6060f1SDimitry Andric 
38*fe6060f1SDimitry Andric class EPCTrampolinePool : public TrampolinePool {
39*fe6060f1SDimitry Andric public:
40*fe6060f1SDimitry Andric   EPCTrampolinePool(EPCIndirectionUtils &EPCIU);
41*fe6060f1SDimitry Andric   Error deallocatePool();
42*fe6060f1SDimitry Andric 
43*fe6060f1SDimitry Andric protected:
44*fe6060f1SDimitry Andric   Error grow() override;
45*fe6060f1SDimitry Andric 
46*fe6060f1SDimitry Andric   using Allocation = jitlink::JITLinkMemoryManager::Allocation;
47*fe6060f1SDimitry Andric 
48*fe6060f1SDimitry Andric   EPCIndirectionUtils &EPCIU;
49*fe6060f1SDimitry Andric   unsigned TrampolineSize = 0;
50*fe6060f1SDimitry Andric   unsigned TrampolinesPerPage = 0;
51*fe6060f1SDimitry Andric   std::vector<std::unique_ptr<Allocation>> TrampolineBlocks;
52*fe6060f1SDimitry Andric };
53*fe6060f1SDimitry Andric 
54*fe6060f1SDimitry Andric class EPCIndirectStubsManager : public IndirectStubsManager,
55*fe6060f1SDimitry Andric                                 private EPCIndirectionUtilsAccess {
56*fe6060f1SDimitry Andric public:
57*fe6060f1SDimitry Andric   EPCIndirectStubsManager(EPCIndirectionUtils &EPCIU) : EPCIU(EPCIU) {}
58*fe6060f1SDimitry Andric 
59*fe6060f1SDimitry Andric   Error deallocateStubs();
60*fe6060f1SDimitry Andric 
61*fe6060f1SDimitry Andric   Error createStub(StringRef StubName, JITTargetAddress StubAddr,
62*fe6060f1SDimitry Andric                    JITSymbolFlags StubFlags) override;
63*fe6060f1SDimitry Andric 
64*fe6060f1SDimitry Andric   Error createStubs(const StubInitsMap &StubInits) override;
65*fe6060f1SDimitry Andric 
66*fe6060f1SDimitry Andric   JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override;
67*fe6060f1SDimitry Andric 
68*fe6060f1SDimitry Andric   JITEvaluatedSymbol findPointer(StringRef Name) override;
69*fe6060f1SDimitry Andric 
70*fe6060f1SDimitry Andric   Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override;
71*fe6060f1SDimitry Andric 
72*fe6060f1SDimitry Andric private:
73*fe6060f1SDimitry Andric   using StubInfo = std::pair<IndirectStubInfo, JITSymbolFlags>;
74*fe6060f1SDimitry Andric 
75*fe6060f1SDimitry Andric   std::mutex ISMMutex;
76*fe6060f1SDimitry Andric   EPCIndirectionUtils &EPCIU;
77*fe6060f1SDimitry Andric   StringMap<StubInfo> StubInfos;
78*fe6060f1SDimitry Andric };
79*fe6060f1SDimitry Andric 
80*fe6060f1SDimitry Andric EPCTrampolinePool::EPCTrampolinePool(EPCIndirectionUtils &EPCIU)
81*fe6060f1SDimitry Andric     : EPCIU(EPCIU) {
82*fe6060f1SDimitry Andric   auto &EPC = EPCIU.getExecutorProcessControl();
83*fe6060f1SDimitry Andric   auto &ABI = EPCIU.getABISupport();
84*fe6060f1SDimitry Andric 
85*fe6060f1SDimitry Andric   TrampolineSize = ABI.getTrampolineSize();
86*fe6060f1SDimitry Andric   TrampolinesPerPage =
87*fe6060f1SDimitry Andric       (EPC.getPageSize() - ABI.getPointerSize()) / TrampolineSize;
88*fe6060f1SDimitry Andric }
89*fe6060f1SDimitry Andric 
90*fe6060f1SDimitry Andric Error EPCTrampolinePool::deallocatePool() {
91*fe6060f1SDimitry Andric   Error Err = Error::success();
92*fe6060f1SDimitry Andric   for (auto &Alloc : TrampolineBlocks)
93*fe6060f1SDimitry Andric     Err = joinErrors(std::move(Err), Alloc->deallocate());
94*fe6060f1SDimitry Andric   return Err;
95*fe6060f1SDimitry Andric }
96*fe6060f1SDimitry Andric 
97*fe6060f1SDimitry Andric Error EPCTrampolinePool::grow() {
98*fe6060f1SDimitry Andric   assert(AvailableTrampolines.empty() &&
99*fe6060f1SDimitry Andric          "Grow called with trampolines still available");
100*fe6060f1SDimitry Andric 
101*fe6060f1SDimitry Andric   auto ResolverAddress = EPCIU.getResolverBlockAddress();
102*fe6060f1SDimitry Andric   assert(ResolverAddress && "Resolver address can not be null");
103*fe6060f1SDimitry Andric 
104*fe6060f1SDimitry Andric   auto &EPC = EPCIU.getExecutorProcessControl();
105*fe6060f1SDimitry Andric   constexpr auto TrampolinePagePermissions =
106*fe6060f1SDimitry Andric       static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
107*fe6060f1SDimitry Andric                                                 sys::Memory::MF_EXEC);
108*fe6060f1SDimitry Andric   auto PageSize = EPC.getPageSize();
109*fe6060f1SDimitry Andric   jitlink::JITLinkMemoryManager::SegmentsRequestMap Request;
110*fe6060f1SDimitry Andric   Request[TrampolinePagePermissions] = {PageSize, static_cast<size_t>(PageSize),
111*fe6060f1SDimitry Andric                                         0};
112*fe6060f1SDimitry Andric   auto Alloc = EPC.getMemMgr().allocate(nullptr, Request);
113*fe6060f1SDimitry Andric 
114*fe6060f1SDimitry Andric   if (!Alloc)
115*fe6060f1SDimitry Andric     return Alloc.takeError();
116*fe6060f1SDimitry Andric 
117*fe6060f1SDimitry Andric   unsigned NumTrampolines = TrampolinesPerPage;
118*fe6060f1SDimitry Andric 
119*fe6060f1SDimitry Andric   auto WorkingMemory = (*Alloc)->getWorkingMemory(TrampolinePagePermissions);
120*fe6060f1SDimitry Andric   auto TargetAddress = (*Alloc)->getTargetMemory(TrampolinePagePermissions);
121*fe6060f1SDimitry Andric 
122*fe6060f1SDimitry Andric   EPCIU.getABISupport().writeTrampolines(WorkingMemory.data(), TargetAddress,
123*fe6060f1SDimitry Andric                                          ResolverAddress, NumTrampolines);
124*fe6060f1SDimitry Andric 
125*fe6060f1SDimitry Andric   auto TargetAddr = (*Alloc)->getTargetMemory(TrampolinePagePermissions);
126*fe6060f1SDimitry Andric   for (unsigned I = 0; I < NumTrampolines; ++I)
127*fe6060f1SDimitry Andric     AvailableTrampolines.push_back(TargetAddr + (I * TrampolineSize));
128*fe6060f1SDimitry Andric 
129*fe6060f1SDimitry Andric   if (auto Err = (*Alloc)->finalize())
130*fe6060f1SDimitry Andric     return Err;
131*fe6060f1SDimitry Andric 
132*fe6060f1SDimitry Andric   TrampolineBlocks.push_back(std::move(*Alloc));
133*fe6060f1SDimitry Andric 
134*fe6060f1SDimitry Andric   return Error::success();
135*fe6060f1SDimitry Andric }
136*fe6060f1SDimitry Andric 
137*fe6060f1SDimitry Andric Error EPCIndirectStubsManager::createStub(StringRef StubName,
138*fe6060f1SDimitry Andric                                           JITTargetAddress StubAddr,
139*fe6060f1SDimitry Andric                                           JITSymbolFlags StubFlags) {
140*fe6060f1SDimitry Andric   StubInitsMap SIM;
141*fe6060f1SDimitry Andric   SIM[StubName] = std::make_pair(StubAddr, StubFlags);
142*fe6060f1SDimitry Andric   return createStubs(SIM);
143*fe6060f1SDimitry Andric }
144*fe6060f1SDimitry Andric 
145*fe6060f1SDimitry Andric Error EPCIndirectStubsManager::createStubs(const StubInitsMap &StubInits) {
146*fe6060f1SDimitry Andric   auto AvailableStubInfos = getIndirectStubs(EPCIU, StubInits.size());
147*fe6060f1SDimitry Andric   if (!AvailableStubInfos)
148*fe6060f1SDimitry Andric     return AvailableStubInfos.takeError();
149*fe6060f1SDimitry Andric 
150*fe6060f1SDimitry Andric   {
151*fe6060f1SDimitry Andric     std::lock_guard<std::mutex> Lock(ISMMutex);
152*fe6060f1SDimitry Andric     unsigned ASIdx = 0;
153*fe6060f1SDimitry Andric     for (auto &SI : StubInits) {
154*fe6060f1SDimitry Andric       auto &A = (*AvailableStubInfos)[ASIdx++];
155*fe6060f1SDimitry Andric       StubInfos[SI.first()] = std::make_pair(A, SI.second.second);
156*fe6060f1SDimitry Andric     }
157*fe6060f1SDimitry Andric   }
158*fe6060f1SDimitry Andric 
159*fe6060f1SDimitry Andric   auto &MemAccess = EPCIU.getExecutorProcessControl().getMemoryAccess();
160*fe6060f1SDimitry Andric   switch (EPCIU.getABISupport().getPointerSize()) {
161*fe6060f1SDimitry Andric   case 4: {
162*fe6060f1SDimitry Andric     unsigned ASIdx = 0;
163*fe6060f1SDimitry Andric     std::vector<tpctypes::UInt32Write> PtrUpdates;
164*fe6060f1SDimitry Andric     for (auto &SI : StubInits)
165*fe6060f1SDimitry Andric       PtrUpdates.push_back({(*AvailableStubInfos)[ASIdx++].PointerAddress,
166*fe6060f1SDimitry Andric                             static_cast<uint32_t>(SI.second.first)});
167*fe6060f1SDimitry Andric     return MemAccess.writeUInt32s(PtrUpdates);
168*fe6060f1SDimitry Andric   }
169*fe6060f1SDimitry Andric   case 8: {
170*fe6060f1SDimitry Andric     unsigned ASIdx = 0;
171*fe6060f1SDimitry Andric     std::vector<tpctypes::UInt64Write> PtrUpdates;
172*fe6060f1SDimitry Andric     for (auto &SI : StubInits)
173*fe6060f1SDimitry Andric       PtrUpdates.push_back({(*AvailableStubInfos)[ASIdx++].PointerAddress,
174*fe6060f1SDimitry Andric                             static_cast<uint64_t>(SI.second.first)});
175*fe6060f1SDimitry Andric     return MemAccess.writeUInt64s(PtrUpdates);
176*fe6060f1SDimitry Andric   }
177*fe6060f1SDimitry Andric   default:
178*fe6060f1SDimitry Andric     return make_error<StringError>("Unsupported pointer size",
179*fe6060f1SDimitry Andric                                    inconvertibleErrorCode());
180*fe6060f1SDimitry Andric   }
181*fe6060f1SDimitry Andric }
182*fe6060f1SDimitry Andric 
183*fe6060f1SDimitry Andric JITEvaluatedSymbol EPCIndirectStubsManager::findStub(StringRef Name,
184*fe6060f1SDimitry Andric                                                      bool ExportedStubsOnly) {
185*fe6060f1SDimitry Andric   std::lock_guard<std::mutex> Lock(ISMMutex);
186*fe6060f1SDimitry Andric   auto I = StubInfos.find(Name);
187*fe6060f1SDimitry Andric   if (I == StubInfos.end())
188*fe6060f1SDimitry Andric     return nullptr;
189*fe6060f1SDimitry Andric   return {I->second.first.StubAddress, I->second.second};
190*fe6060f1SDimitry Andric }
191*fe6060f1SDimitry Andric 
192*fe6060f1SDimitry Andric JITEvaluatedSymbol EPCIndirectStubsManager::findPointer(StringRef Name) {
193*fe6060f1SDimitry Andric   std::lock_guard<std::mutex> Lock(ISMMutex);
194*fe6060f1SDimitry Andric   auto I = StubInfos.find(Name);
195*fe6060f1SDimitry Andric   if (I == StubInfos.end())
196*fe6060f1SDimitry Andric     return nullptr;
197*fe6060f1SDimitry Andric   return {I->second.first.PointerAddress, I->second.second};
198*fe6060f1SDimitry Andric }
199*fe6060f1SDimitry Andric 
200*fe6060f1SDimitry Andric Error EPCIndirectStubsManager::updatePointer(StringRef Name,
201*fe6060f1SDimitry Andric                                              JITTargetAddress NewAddr) {
202*fe6060f1SDimitry Andric 
203*fe6060f1SDimitry Andric   JITTargetAddress PtrAddr = 0;
204*fe6060f1SDimitry Andric   {
205*fe6060f1SDimitry Andric     std::lock_guard<std::mutex> Lock(ISMMutex);
206*fe6060f1SDimitry Andric     auto I = StubInfos.find(Name);
207*fe6060f1SDimitry Andric     if (I == StubInfos.end())
208*fe6060f1SDimitry Andric       return make_error<StringError>("Unknown stub name",
209*fe6060f1SDimitry Andric                                      inconvertibleErrorCode());
210*fe6060f1SDimitry Andric     PtrAddr = I->second.first.PointerAddress;
211*fe6060f1SDimitry Andric   }
212*fe6060f1SDimitry Andric 
213*fe6060f1SDimitry Andric   auto &MemAccess = EPCIU.getExecutorProcessControl().getMemoryAccess();
214*fe6060f1SDimitry Andric   switch (EPCIU.getABISupport().getPointerSize()) {
215*fe6060f1SDimitry Andric   case 4: {
216*fe6060f1SDimitry Andric     tpctypes::UInt32Write PUpdate(PtrAddr, NewAddr);
217*fe6060f1SDimitry Andric     return MemAccess.writeUInt32s(PUpdate);
218*fe6060f1SDimitry Andric   }
219*fe6060f1SDimitry Andric   case 8: {
220*fe6060f1SDimitry Andric     tpctypes::UInt64Write PUpdate(PtrAddr, NewAddr);
221*fe6060f1SDimitry Andric     return MemAccess.writeUInt64s(PUpdate);
222*fe6060f1SDimitry Andric   }
223*fe6060f1SDimitry Andric   default:
224*fe6060f1SDimitry Andric     return make_error<StringError>("Unsupported pointer size",
225*fe6060f1SDimitry Andric                                    inconvertibleErrorCode());
226*fe6060f1SDimitry Andric   }
227*fe6060f1SDimitry Andric }
228*fe6060f1SDimitry Andric 
229*fe6060f1SDimitry Andric } // end anonymous namespace.
230*fe6060f1SDimitry Andric 
231*fe6060f1SDimitry Andric namespace llvm {
232*fe6060f1SDimitry Andric namespace orc {
233*fe6060f1SDimitry Andric 
234*fe6060f1SDimitry Andric EPCIndirectionUtils::ABISupport::~ABISupport() {}
235*fe6060f1SDimitry Andric 
236*fe6060f1SDimitry Andric Expected<std::unique_ptr<EPCIndirectionUtils>>
237*fe6060f1SDimitry Andric EPCIndirectionUtils::Create(ExecutorProcessControl &EPC) {
238*fe6060f1SDimitry Andric   const auto &TT = EPC.getTargetTriple();
239*fe6060f1SDimitry Andric   switch (TT.getArch()) {
240*fe6060f1SDimitry Andric   default:
241*fe6060f1SDimitry Andric     return make_error<StringError>(
242*fe6060f1SDimitry Andric         std::string("No EPCIndirectionUtils available for ") + TT.str(),
243*fe6060f1SDimitry Andric         inconvertibleErrorCode());
244*fe6060f1SDimitry Andric   case Triple::aarch64:
245*fe6060f1SDimitry Andric   case Triple::aarch64_32:
246*fe6060f1SDimitry Andric     return CreateWithABI<OrcAArch64>(EPC);
247*fe6060f1SDimitry Andric 
248*fe6060f1SDimitry Andric   case Triple::x86:
249*fe6060f1SDimitry Andric     return CreateWithABI<OrcI386>(EPC);
250*fe6060f1SDimitry Andric 
251*fe6060f1SDimitry Andric   case Triple::mips:
252*fe6060f1SDimitry Andric     return CreateWithABI<OrcMips32Be>(EPC);
253*fe6060f1SDimitry Andric 
254*fe6060f1SDimitry Andric   case Triple::mipsel:
255*fe6060f1SDimitry Andric     return CreateWithABI<OrcMips32Le>(EPC);
256*fe6060f1SDimitry Andric 
257*fe6060f1SDimitry Andric   case Triple::mips64:
258*fe6060f1SDimitry Andric   case Triple::mips64el:
259*fe6060f1SDimitry Andric     return CreateWithABI<OrcMips64>(EPC);
260*fe6060f1SDimitry Andric 
261*fe6060f1SDimitry Andric   case Triple::x86_64:
262*fe6060f1SDimitry Andric     if (TT.getOS() == Triple::OSType::Win32)
263*fe6060f1SDimitry Andric       return CreateWithABI<OrcX86_64_Win32>(EPC);
264*fe6060f1SDimitry Andric     else
265*fe6060f1SDimitry Andric       return CreateWithABI<OrcX86_64_SysV>(EPC);
266*fe6060f1SDimitry Andric   }
267*fe6060f1SDimitry Andric }
268*fe6060f1SDimitry Andric 
269*fe6060f1SDimitry Andric Error EPCIndirectionUtils::cleanup() {
270*fe6060f1SDimitry Andric   Error Err = Error::success();
271*fe6060f1SDimitry Andric 
272*fe6060f1SDimitry Andric   for (auto &A : IndirectStubAllocs)
273*fe6060f1SDimitry Andric     Err = joinErrors(std::move(Err), A->deallocate());
274*fe6060f1SDimitry Andric 
275*fe6060f1SDimitry Andric   if (TP)
276*fe6060f1SDimitry Andric     Err = joinErrors(std::move(Err),
277*fe6060f1SDimitry Andric                      static_cast<EPCTrampolinePool &>(*TP).deallocatePool());
278*fe6060f1SDimitry Andric 
279*fe6060f1SDimitry Andric   if (ResolverBlock)
280*fe6060f1SDimitry Andric     Err = joinErrors(std::move(Err), ResolverBlock->deallocate());
281*fe6060f1SDimitry Andric 
282*fe6060f1SDimitry Andric   return Err;
283*fe6060f1SDimitry Andric }
284*fe6060f1SDimitry Andric 
285*fe6060f1SDimitry Andric Expected<JITTargetAddress>
286*fe6060f1SDimitry Andric EPCIndirectionUtils::writeResolverBlock(JITTargetAddress ReentryFnAddr,
287*fe6060f1SDimitry Andric                                         JITTargetAddress ReentryCtxAddr) {
288*fe6060f1SDimitry Andric   assert(ABI && "ABI can not be null");
289*fe6060f1SDimitry Andric   constexpr auto ResolverBlockPermissions =
290*fe6060f1SDimitry Andric       static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
291*fe6060f1SDimitry Andric                                                 sys::Memory::MF_EXEC);
292*fe6060f1SDimitry Andric   auto ResolverSize = ABI->getResolverCodeSize();
293*fe6060f1SDimitry Andric 
294*fe6060f1SDimitry Andric   jitlink::JITLinkMemoryManager::SegmentsRequestMap Request;
295*fe6060f1SDimitry Andric   Request[ResolverBlockPermissions] = {EPC.getPageSize(),
296*fe6060f1SDimitry Andric                                        static_cast<size_t>(ResolverSize), 0};
297*fe6060f1SDimitry Andric   auto Alloc = EPC.getMemMgr().allocate(nullptr, Request);
298*fe6060f1SDimitry Andric   if (!Alloc)
299*fe6060f1SDimitry Andric     return Alloc.takeError();
300*fe6060f1SDimitry Andric 
301*fe6060f1SDimitry Andric   auto WorkingMemory = (*Alloc)->getWorkingMemory(ResolverBlockPermissions);
302*fe6060f1SDimitry Andric   ResolverBlockAddr = (*Alloc)->getTargetMemory(ResolverBlockPermissions);
303*fe6060f1SDimitry Andric   ABI->writeResolverCode(WorkingMemory.data(), ResolverBlockAddr, ReentryFnAddr,
304*fe6060f1SDimitry Andric                          ReentryCtxAddr);
305*fe6060f1SDimitry Andric 
306*fe6060f1SDimitry Andric   if (auto Err = (*Alloc)->finalize())
307*fe6060f1SDimitry Andric     return std::move(Err);
308*fe6060f1SDimitry Andric 
309*fe6060f1SDimitry Andric   ResolverBlock = std::move(*Alloc);
310*fe6060f1SDimitry Andric   return ResolverBlockAddr;
311*fe6060f1SDimitry Andric }
312*fe6060f1SDimitry Andric 
313*fe6060f1SDimitry Andric std::unique_ptr<IndirectStubsManager>
314*fe6060f1SDimitry Andric EPCIndirectionUtils::createIndirectStubsManager() {
315*fe6060f1SDimitry Andric   return std::make_unique<EPCIndirectStubsManager>(*this);
316*fe6060f1SDimitry Andric }
317*fe6060f1SDimitry Andric 
318*fe6060f1SDimitry Andric TrampolinePool &EPCIndirectionUtils::getTrampolinePool() {
319*fe6060f1SDimitry Andric   if (!TP)
320*fe6060f1SDimitry Andric     TP = std::make_unique<EPCTrampolinePool>(*this);
321*fe6060f1SDimitry Andric   return *TP;
322*fe6060f1SDimitry Andric }
323*fe6060f1SDimitry Andric 
324*fe6060f1SDimitry Andric LazyCallThroughManager &EPCIndirectionUtils::createLazyCallThroughManager(
325*fe6060f1SDimitry Andric     ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr) {
326*fe6060f1SDimitry Andric   assert(!LCTM &&
327*fe6060f1SDimitry Andric          "createLazyCallThroughManager can not have been called before");
328*fe6060f1SDimitry Andric   LCTM = std::make_unique<LazyCallThroughManager>(ES, ErrorHandlerAddr,
329*fe6060f1SDimitry Andric                                                   &getTrampolinePool());
330*fe6060f1SDimitry Andric   return *LCTM;
331*fe6060f1SDimitry Andric }
332*fe6060f1SDimitry Andric 
333*fe6060f1SDimitry Andric EPCIndirectionUtils::EPCIndirectionUtils(ExecutorProcessControl &EPC,
334*fe6060f1SDimitry Andric                                          std::unique_ptr<ABISupport> ABI)
335*fe6060f1SDimitry Andric     : EPC(EPC), ABI(std::move(ABI)) {
336*fe6060f1SDimitry Andric   assert(this->ABI && "ABI can not be null");
337*fe6060f1SDimitry Andric 
338*fe6060f1SDimitry Andric   assert(EPC.getPageSize() > getABISupport().getStubSize() &&
339*fe6060f1SDimitry Andric          "Stubs larger than one page are not supported");
340*fe6060f1SDimitry Andric }
341*fe6060f1SDimitry Andric 
342*fe6060f1SDimitry Andric Expected<EPCIndirectionUtils::IndirectStubInfoVector>
343*fe6060f1SDimitry Andric EPCIndirectionUtils::getIndirectStubs(unsigned NumStubs) {
344*fe6060f1SDimitry Andric 
345*fe6060f1SDimitry Andric   std::lock_guard<std::mutex> Lock(EPCUIMutex);
346*fe6060f1SDimitry Andric 
347*fe6060f1SDimitry Andric   // If there aren't enough stubs available then allocate some more.
348*fe6060f1SDimitry Andric   if (NumStubs > AvailableIndirectStubs.size()) {
349*fe6060f1SDimitry Andric     auto NumStubsToAllocate = NumStubs;
350*fe6060f1SDimitry Andric     auto PageSize = EPC.getPageSize();
351*fe6060f1SDimitry Andric     auto StubBytes = alignTo(NumStubsToAllocate * ABI->getStubSize(), PageSize);
352*fe6060f1SDimitry Andric     NumStubsToAllocate = StubBytes / ABI->getStubSize();
353*fe6060f1SDimitry Andric     auto PointerBytes =
354*fe6060f1SDimitry Andric         alignTo(NumStubsToAllocate * ABI->getPointerSize(), PageSize);
355*fe6060f1SDimitry Andric 
356*fe6060f1SDimitry Andric     constexpr auto StubPagePermissions =
357*fe6060f1SDimitry Andric         static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
358*fe6060f1SDimitry Andric                                                   sys::Memory::MF_EXEC);
359*fe6060f1SDimitry Andric     constexpr auto PointerPagePermissions =
360*fe6060f1SDimitry Andric         static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
361*fe6060f1SDimitry Andric                                                   sys::Memory::MF_WRITE);
362*fe6060f1SDimitry Andric 
363*fe6060f1SDimitry Andric     jitlink::JITLinkMemoryManager::SegmentsRequestMap Request;
364*fe6060f1SDimitry Andric     Request[StubPagePermissions] = {PageSize, static_cast<size_t>(StubBytes),
365*fe6060f1SDimitry Andric                                     0};
366*fe6060f1SDimitry Andric     Request[PointerPagePermissions] = {PageSize, 0, PointerBytes};
367*fe6060f1SDimitry Andric     auto Alloc = EPC.getMemMgr().allocate(nullptr, Request);
368*fe6060f1SDimitry Andric     if (!Alloc)
369*fe6060f1SDimitry Andric       return Alloc.takeError();
370*fe6060f1SDimitry Andric 
371*fe6060f1SDimitry Andric     auto StubTargetAddr = (*Alloc)->getTargetMemory(StubPagePermissions);
372*fe6060f1SDimitry Andric     auto PointerTargetAddr = (*Alloc)->getTargetMemory(PointerPagePermissions);
373*fe6060f1SDimitry Andric 
374*fe6060f1SDimitry Andric     ABI->writeIndirectStubsBlock(
375*fe6060f1SDimitry Andric         (*Alloc)->getWorkingMemory(StubPagePermissions).data(), StubTargetAddr,
376*fe6060f1SDimitry Andric         PointerTargetAddr, NumStubsToAllocate);
377*fe6060f1SDimitry Andric 
378*fe6060f1SDimitry Andric     if (auto Err = (*Alloc)->finalize())
379*fe6060f1SDimitry Andric       return std::move(Err);
380*fe6060f1SDimitry Andric 
381*fe6060f1SDimitry Andric     for (unsigned I = 0; I != NumStubsToAllocate; ++I) {
382*fe6060f1SDimitry Andric       AvailableIndirectStubs.push_back(
383*fe6060f1SDimitry Andric           IndirectStubInfo(StubTargetAddr, PointerTargetAddr));
384*fe6060f1SDimitry Andric       StubTargetAddr += ABI->getStubSize();
385*fe6060f1SDimitry Andric       PointerTargetAddr += ABI->getPointerSize();
386*fe6060f1SDimitry Andric     }
387*fe6060f1SDimitry Andric 
388*fe6060f1SDimitry Andric     IndirectStubAllocs.push_back(std::move(*Alloc));
389*fe6060f1SDimitry Andric   }
390*fe6060f1SDimitry Andric 
391*fe6060f1SDimitry Andric   assert(NumStubs <= AvailableIndirectStubs.size() &&
392*fe6060f1SDimitry Andric          "Sufficient stubs should have been allocated above");
393*fe6060f1SDimitry Andric 
394*fe6060f1SDimitry Andric   IndirectStubInfoVector Result;
395*fe6060f1SDimitry Andric   while (NumStubs--) {
396*fe6060f1SDimitry Andric     Result.push_back(AvailableIndirectStubs.back());
397*fe6060f1SDimitry Andric     AvailableIndirectStubs.pop_back();
398*fe6060f1SDimitry Andric   }
399*fe6060f1SDimitry Andric 
400*fe6060f1SDimitry Andric   return std::move(Result);
401*fe6060f1SDimitry Andric }
402*fe6060f1SDimitry Andric 
403*fe6060f1SDimitry Andric static JITTargetAddress reentry(JITTargetAddress LCTMAddr,
404*fe6060f1SDimitry Andric                                 JITTargetAddress TrampolineAddr) {
405*fe6060f1SDimitry Andric   auto &LCTM = *jitTargetAddressToPointer<LazyCallThroughManager *>(LCTMAddr);
406*fe6060f1SDimitry Andric   std::promise<JITTargetAddress> LandingAddrP;
407*fe6060f1SDimitry Andric   auto LandingAddrF = LandingAddrP.get_future();
408*fe6060f1SDimitry Andric   LCTM.resolveTrampolineLandingAddress(
409*fe6060f1SDimitry Andric       TrampolineAddr,
410*fe6060f1SDimitry Andric       [&](JITTargetAddress Addr) { LandingAddrP.set_value(Addr); });
411*fe6060f1SDimitry Andric   return LandingAddrF.get();
412*fe6060f1SDimitry Andric }
413*fe6060f1SDimitry Andric 
414*fe6060f1SDimitry Andric Error setUpInProcessLCTMReentryViaEPCIU(EPCIndirectionUtils &EPCIU) {
415*fe6060f1SDimitry Andric   auto &LCTM = EPCIU.getLazyCallThroughManager();
416*fe6060f1SDimitry Andric   return EPCIU
417*fe6060f1SDimitry Andric       .writeResolverBlock(pointerToJITTargetAddress(&reentry),
418*fe6060f1SDimitry Andric                           pointerToJITTargetAddress(&LCTM))
419*fe6060f1SDimitry Andric       .takeError();
420*fe6060f1SDimitry Andric }
421*fe6060f1SDimitry Andric 
422*fe6060f1SDimitry Andric } // end namespace orc
423*fe6060f1SDimitry Andric } // end namespace llvm
424