xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCIndirectionUtils.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1fe6060f1SDimitry Andric //===------- EPCIndirectionUtils.cpp -- EPC based indirection APIs --------===//
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 #include "llvm/ExecutionEngine/Orc/EPCIndirectionUtils.h"
10fe6060f1SDimitry Andric 
11fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
12fe6060f1SDimitry Andric #include "llvm/Support/MathExtras.h"
13fe6060f1SDimitry Andric 
14fe6060f1SDimitry Andric #include <future>
15fe6060f1SDimitry Andric 
16fe6060f1SDimitry Andric using namespace llvm;
17fe6060f1SDimitry Andric using namespace llvm::orc;
18fe6060f1SDimitry Andric 
19fe6060f1SDimitry Andric namespace llvm {
20fe6060f1SDimitry Andric namespace orc {
21fe6060f1SDimitry Andric 
22fe6060f1SDimitry Andric class EPCIndirectionUtilsAccess {
23fe6060f1SDimitry Andric public:
24fe6060f1SDimitry Andric   using IndirectStubInfo = EPCIndirectionUtils::IndirectStubInfo;
25fe6060f1SDimitry Andric   using IndirectStubInfoVector = EPCIndirectionUtils::IndirectStubInfoVector;
26fe6060f1SDimitry Andric 
27fe6060f1SDimitry Andric   static Expected<IndirectStubInfoVector>
28fe6060f1SDimitry Andric   getIndirectStubs(EPCIndirectionUtils &EPCIU, unsigned NumStubs) {
29fe6060f1SDimitry Andric     return EPCIU.getIndirectStubs(NumStubs);
30fe6060f1SDimitry Andric   };
31fe6060f1SDimitry Andric };
32fe6060f1SDimitry Andric 
33fe6060f1SDimitry Andric } // end namespace orc
34fe6060f1SDimitry Andric } // end namespace llvm
35fe6060f1SDimitry Andric 
36fe6060f1SDimitry Andric namespace {
37fe6060f1SDimitry Andric 
38fe6060f1SDimitry Andric class EPCTrampolinePool : public TrampolinePool {
39fe6060f1SDimitry Andric public:
40fe6060f1SDimitry Andric   EPCTrampolinePool(EPCIndirectionUtils &EPCIU);
41fe6060f1SDimitry Andric   Error deallocatePool();
42fe6060f1SDimitry Andric 
43fe6060f1SDimitry Andric protected:
44fe6060f1SDimitry Andric   Error grow() override;
45fe6060f1SDimitry Andric 
46349cc55cSDimitry Andric   using FinalizedAlloc = jitlink::JITLinkMemoryManager::FinalizedAlloc;
47fe6060f1SDimitry Andric 
48fe6060f1SDimitry Andric   EPCIndirectionUtils &EPCIU;
49fe6060f1SDimitry Andric   unsigned TrampolineSize = 0;
50fe6060f1SDimitry Andric   unsigned TrampolinesPerPage = 0;
51349cc55cSDimitry Andric   std::vector<FinalizedAlloc> TrampolineBlocks;
52fe6060f1SDimitry Andric };
53fe6060f1SDimitry Andric 
54fe6060f1SDimitry Andric class EPCIndirectStubsManager : public IndirectStubsManager,
55fe6060f1SDimitry Andric                                 private EPCIndirectionUtilsAccess {
56fe6060f1SDimitry Andric public:
57fe6060f1SDimitry Andric   EPCIndirectStubsManager(EPCIndirectionUtils &EPCIU) : EPCIU(EPCIU) {}
58fe6060f1SDimitry Andric 
59fe6060f1SDimitry Andric   Error deallocateStubs();
60fe6060f1SDimitry Andric 
61fe6060f1SDimitry Andric   Error createStub(StringRef StubName, JITTargetAddress StubAddr,
62fe6060f1SDimitry Andric                    JITSymbolFlags StubFlags) override;
63fe6060f1SDimitry Andric 
64fe6060f1SDimitry Andric   Error createStubs(const StubInitsMap &StubInits) override;
65fe6060f1SDimitry Andric 
66fe6060f1SDimitry Andric   JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override;
67fe6060f1SDimitry Andric 
68fe6060f1SDimitry Andric   JITEvaluatedSymbol findPointer(StringRef Name) override;
69fe6060f1SDimitry Andric 
70fe6060f1SDimitry Andric   Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override;
71fe6060f1SDimitry Andric 
72fe6060f1SDimitry Andric private:
73fe6060f1SDimitry Andric   using StubInfo = std::pair<IndirectStubInfo, JITSymbolFlags>;
74fe6060f1SDimitry Andric 
75fe6060f1SDimitry Andric   std::mutex ISMMutex;
76fe6060f1SDimitry Andric   EPCIndirectionUtils &EPCIU;
77fe6060f1SDimitry Andric   StringMap<StubInfo> StubInfos;
78fe6060f1SDimitry Andric };
79fe6060f1SDimitry Andric 
80fe6060f1SDimitry Andric EPCTrampolinePool::EPCTrampolinePool(EPCIndirectionUtils &EPCIU)
81fe6060f1SDimitry Andric     : EPCIU(EPCIU) {
82fe6060f1SDimitry Andric   auto &EPC = EPCIU.getExecutorProcessControl();
83fe6060f1SDimitry Andric   auto &ABI = EPCIU.getABISupport();
84fe6060f1SDimitry Andric 
85fe6060f1SDimitry Andric   TrampolineSize = ABI.getTrampolineSize();
86fe6060f1SDimitry Andric   TrampolinesPerPage =
87fe6060f1SDimitry Andric       (EPC.getPageSize() - ABI.getPointerSize()) / TrampolineSize;
88fe6060f1SDimitry Andric }
89fe6060f1SDimitry Andric 
90fe6060f1SDimitry Andric Error EPCTrampolinePool::deallocatePool() {
91349cc55cSDimitry Andric   std::promise<MSVCPError> DeallocResultP;
92349cc55cSDimitry Andric   auto DeallocResultF = DeallocResultP.get_future();
93349cc55cSDimitry Andric 
94349cc55cSDimitry Andric   EPCIU.getExecutorProcessControl().getMemMgr().deallocate(
95349cc55cSDimitry Andric       std::move(TrampolineBlocks),
96349cc55cSDimitry Andric       [&](Error Err) { DeallocResultP.set_value(std::move(Err)); });
97349cc55cSDimitry Andric 
98349cc55cSDimitry Andric   return DeallocResultF.get();
99fe6060f1SDimitry Andric }
100fe6060f1SDimitry Andric 
101fe6060f1SDimitry Andric Error EPCTrampolinePool::grow() {
102349cc55cSDimitry Andric   using namespace jitlink;
103349cc55cSDimitry Andric 
104fe6060f1SDimitry Andric   assert(AvailableTrampolines.empty() &&
105fe6060f1SDimitry Andric          "Grow called with trampolines still available");
106fe6060f1SDimitry Andric 
107fe6060f1SDimitry Andric   auto ResolverAddress = EPCIU.getResolverBlockAddress();
108fe6060f1SDimitry Andric   assert(ResolverAddress && "Resolver address can not be null");
109fe6060f1SDimitry Andric 
110fe6060f1SDimitry Andric   auto &EPC = EPCIU.getExecutorProcessControl();
111fe6060f1SDimitry Andric   auto PageSize = EPC.getPageSize();
112349cc55cSDimitry Andric   auto Alloc = SimpleSegmentAlloc::Create(
113349cc55cSDimitry Andric       EPC.getMemMgr(), nullptr,
114349cc55cSDimitry Andric       {{MemProt::Read | MemProt::Exec, {PageSize, Align(PageSize)}}});
115fe6060f1SDimitry Andric   if (!Alloc)
116fe6060f1SDimitry Andric     return Alloc.takeError();
117fe6060f1SDimitry Andric 
118fe6060f1SDimitry Andric   unsigned NumTrampolines = TrampolinesPerPage;
119fe6060f1SDimitry Andric 
120349cc55cSDimitry Andric   auto SegInfo = Alloc->getSegInfo(MemProt::Read | MemProt::Exec);
12104eeddc0SDimitry Andric   EPCIU.getABISupport().writeTrampolines(SegInfo.WorkingMem.data(),
12204eeddc0SDimitry Andric                                          SegInfo.Addr.getValue(),
12304eeddc0SDimitry Andric                                          ResolverAddress, NumTrampolines);
124fe6060f1SDimitry Andric   for (unsigned I = 0; I < NumTrampolines; ++I)
12504eeddc0SDimitry Andric     AvailableTrampolines.push_back(SegInfo.Addr.getValue() +
12604eeddc0SDimitry Andric                                    (I * TrampolineSize));
127fe6060f1SDimitry Andric 
128349cc55cSDimitry Andric   auto FA = Alloc->finalize();
129349cc55cSDimitry Andric   if (!FA)
130349cc55cSDimitry Andric     return FA.takeError();
131fe6060f1SDimitry Andric 
132349cc55cSDimitry Andric   TrampolineBlocks.push_back(std::move(*FA));
133fe6060f1SDimitry Andric 
134fe6060f1SDimitry Andric   return Error::success();
135fe6060f1SDimitry Andric }
136fe6060f1SDimitry Andric 
137fe6060f1SDimitry Andric Error EPCIndirectStubsManager::createStub(StringRef StubName,
138fe6060f1SDimitry Andric                                           JITTargetAddress StubAddr,
139fe6060f1SDimitry Andric                                           JITSymbolFlags StubFlags) {
140fe6060f1SDimitry Andric   StubInitsMap SIM;
141fe6060f1SDimitry Andric   SIM[StubName] = std::make_pair(StubAddr, StubFlags);
142fe6060f1SDimitry Andric   return createStubs(SIM);
143fe6060f1SDimitry Andric }
144fe6060f1SDimitry Andric 
145fe6060f1SDimitry Andric Error EPCIndirectStubsManager::createStubs(const StubInitsMap &StubInits) {
146fe6060f1SDimitry Andric   auto AvailableStubInfos = getIndirectStubs(EPCIU, StubInits.size());
147fe6060f1SDimitry Andric   if (!AvailableStubInfos)
148fe6060f1SDimitry Andric     return AvailableStubInfos.takeError();
149fe6060f1SDimitry Andric 
150fe6060f1SDimitry Andric   {
151fe6060f1SDimitry Andric     std::lock_guard<std::mutex> Lock(ISMMutex);
152fe6060f1SDimitry Andric     unsigned ASIdx = 0;
153fe6060f1SDimitry Andric     for (auto &SI : StubInits) {
154fe6060f1SDimitry Andric       auto &A = (*AvailableStubInfos)[ASIdx++];
155fe6060f1SDimitry Andric       StubInfos[SI.first()] = std::make_pair(A, SI.second.second);
156fe6060f1SDimitry Andric     }
157fe6060f1SDimitry Andric   }
158fe6060f1SDimitry Andric 
159fe6060f1SDimitry Andric   auto &MemAccess = EPCIU.getExecutorProcessControl().getMemoryAccess();
160fe6060f1SDimitry Andric   switch (EPCIU.getABISupport().getPointerSize()) {
161fe6060f1SDimitry Andric   case 4: {
162fe6060f1SDimitry Andric     unsigned ASIdx = 0;
163fe6060f1SDimitry Andric     std::vector<tpctypes::UInt32Write> PtrUpdates;
164fe6060f1SDimitry Andric     for (auto &SI : StubInits)
165349cc55cSDimitry Andric       PtrUpdates.push_back(
166349cc55cSDimitry Andric           {ExecutorAddr((*AvailableStubInfos)[ASIdx++].PointerAddress),
167fe6060f1SDimitry Andric            static_cast<uint32_t>(SI.second.first)});
168fe6060f1SDimitry Andric     return MemAccess.writeUInt32s(PtrUpdates);
169fe6060f1SDimitry Andric   }
170fe6060f1SDimitry Andric   case 8: {
171fe6060f1SDimitry Andric     unsigned ASIdx = 0;
172fe6060f1SDimitry Andric     std::vector<tpctypes::UInt64Write> PtrUpdates;
173fe6060f1SDimitry Andric     for (auto &SI : StubInits)
174349cc55cSDimitry Andric       PtrUpdates.push_back(
175349cc55cSDimitry Andric           {ExecutorAddr((*AvailableStubInfos)[ASIdx++].PointerAddress),
176fe6060f1SDimitry Andric            static_cast<uint64_t>(SI.second.first)});
177fe6060f1SDimitry Andric     return MemAccess.writeUInt64s(PtrUpdates);
178fe6060f1SDimitry Andric   }
179fe6060f1SDimitry Andric   default:
180fe6060f1SDimitry Andric     return make_error<StringError>("Unsupported pointer size",
181fe6060f1SDimitry Andric                                    inconvertibleErrorCode());
182fe6060f1SDimitry Andric   }
183fe6060f1SDimitry Andric }
184fe6060f1SDimitry Andric 
185fe6060f1SDimitry Andric JITEvaluatedSymbol EPCIndirectStubsManager::findStub(StringRef Name,
186fe6060f1SDimitry Andric                                                      bool ExportedStubsOnly) {
187fe6060f1SDimitry Andric   std::lock_guard<std::mutex> Lock(ISMMutex);
188fe6060f1SDimitry Andric   auto I = StubInfos.find(Name);
189fe6060f1SDimitry Andric   if (I == StubInfos.end())
190fe6060f1SDimitry Andric     return nullptr;
191fe6060f1SDimitry Andric   return {I->second.first.StubAddress, I->second.second};
192fe6060f1SDimitry Andric }
193fe6060f1SDimitry Andric 
194fe6060f1SDimitry Andric JITEvaluatedSymbol EPCIndirectStubsManager::findPointer(StringRef Name) {
195fe6060f1SDimitry Andric   std::lock_guard<std::mutex> Lock(ISMMutex);
196fe6060f1SDimitry Andric   auto I = StubInfos.find(Name);
197fe6060f1SDimitry Andric   if (I == StubInfos.end())
198fe6060f1SDimitry Andric     return nullptr;
199fe6060f1SDimitry Andric   return {I->second.first.PointerAddress, I->second.second};
200fe6060f1SDimitry Andric }
201fe6060f1SDimitry Andric 
202fe6060f1SDimitry Andric Error EPCIndirectStubsManager::updatePointer(StringRef Name,
203fe6060f1SDimitry Andric                                              JITTargetAddress NewAddr) {
204fe6060f1SDimitry Andric 
205fe6060f1SDimitry Andric   JITTargetAddress PtrAddr = 0;
206fe6060f1SDimitry Andric   {
207fe6060f1SDimitry Andric     std::lock_guard<std::mutex> Lock(ISMMutex);
208fe6060f1SDimitry Andric     auto I = StubInfos.find(Name);
209fe6060f1SDimitry Andric     if (I == StubInfos.end())
210fe6060f1SDimitry Andric       return make_error<StringError>("Unknown stub name",
211fe6060f1SDimitry Andric                                      inconvertibleErrorCode());
212fe6060f1SDimitry Andric     PtrAddr = I->second.first.PointerAddress;
213fe6060f1SDimitry Andric   }
214fe6060f1SDimitry Andric 
215fe6060f1SDimitry Andric   auto &MemAccess = EPCIU.getExecutorProcessControl().getMemoryAccess();
216fe6060f1SDimitry Andric   switch (EPCIU.getABISupport().getPointerSize()) {
217fe6060f1SDimitry Andric   case 4: {
218349cc55cSDimitry Andric     tpctypes::UInt32Write PUpdate(ExecutorAddr(PtrAddr), NewAddr);
219fe6060f1SDimitry Andric     return MemAccess.writeUInt32s(PUpdate);
220fe6060f1SDimitry Andric   }
221fe6060f1SDimitry Andric   case 8: {
222349cc55cSDimitry Andric     tpctypes::UInt64Write PUpdate(ExecutorAddr(PtrAddr), NewAddr);
223fe6060f1SDimitry Andric     return MemAccess.writeUInt64s(PUpdate);
224fe6060f1SDimitry Andric   }
225fe6060f1SDimitry Andric   default:
226fe6060f1SDimitry Andric     return make_error<StringError>("Unsupported pointer size",
227fe6060f1SDimitry Andric                                    inconvertibleErrorCode());
228fe6060f1SDimitry Andric   }
229fe6060f1SDimitry Andric }
230fe6060f1SDimitry Andric 
231fe6060f1SDimitry Andric } // end anonymous namespace.
232fe6060f1SDimitry Andric 
233fe6060f1SDimitry Andric namespace llvm {
234fe6060f1SDimitry Andric namespace orc {
235fe6060f1SDimitry Andric 
23681ad6265SDimitry Andric EPCIndirectionUtils::ABISupport::~ABISupport() = default;
237fe6060f1SDimitry Andric 
238fe6060f1SDimitry Andric Expected<std::unique_ptr<EPCIndirectionUtils>>
239fe6060f1SDimitry Andric EPCIndirectionUtils::Create(ExecutorProcessControl &EPC) {
240fe6060f1SDimitry Andric   const auto &TT = EPC.getTargetTriple();
241fe6060f1SDimitry Andric   switch (TT.getArch()) {
242fe6060f1SDimitry Andric   default:
243fe6060f1SDimitry Andric     return make_error<StringError>(
244fe6060f1SDimitry Andric         std::string("No EPCIndirectionUtils available for ") + TT.str(),
245fe6060f1SDimitry Andric         inconvertibleErrorCode());
246fe6060f1SDimitry Andric   case Triple::aarch64:
247fe6060f1SDimitry Andric   case Triple::aarch64_32:
248fe6060f1SDimitry Andric     return CreateWithABI<OrcAArch64>(EPC);
249fe6060f1SDimitry Andric 
250fe6060f1SDimitry Andric   case Triple::x86:
251fe6060f1SDimitry Andric     return CreateWithABI<OrcI386>(EPC);
252fe6060f1SDimitry Andric 
253*bdd1243dSDimitry Andric   case Triple::loongarch64:
254*bdd1243dSDimitry Andric     return CreateWithABI<OrcLoongArch64>(EPC);
255*bdd1243dSDimitry Andric 
256fe6060f1SDimitry Andric   case Triple::mips:
257fe6060f1SDimitry Andric     return CreateWithABI<OrcMips32Be>(EPC);
258fe6060f1SDimitry Andric 
259fe6060f1SDimitry Andric   case Triple::mipsel:
260fe6060f1SDimitry Andric     return CreateWithABI<OrcMips32Le>(EPC);
261fe6060f1SDimitry Andric 
262fe6060f1SDimitry Andric   case Triple::mips64:
263fe6060f1SDimitry Andric   case Triple::mips64el:
264fe6060f1SDimitry Andric     return CreateWithABI<OrcMips64>(EPC);
265fe6060f1SDimitry Andric 
26681ad6265SDimitry Andric   case Triple::riscv64:
26781ad6265SDimitry Andric     return CreateWithABI<OrcRiscv64>(EPC);
26881ad6265SDimitry Andric 
269fe6060f1SDimitry Andric   case Triple::x86_64:
270fe6060f1SDimitry Andric     if (TT.getOS() == Triple::OSType::Win32)
271fe6060f1SDimitry Andric       return CreateWithABI<OrcX86_64_Win32>(EPC);
272fe6060f1SDimitry Andric     else
273fe6060f1SDimitry Andric       return CreateWithABI<OrcX86_64_SysV>(EPC);
274fe6060f1SDimitry Andric   }
275fe6060f1SDimitry Andric }
276fe6060f1SDimitry Andric 
277fe6060f1SDimitry Andric Error EPCIndirectionUtils::cleanup() {
278fe6060f1SDimitry Andric 
279349cc55cSDimitry Andric   auto &MemMgr = EPC.getMemMgr();
280349cc55cSDimitry Andric   auto Err = MemMgr.deallocate(std::move(IndirectStubAllocs));
281fe6060f1SDimitry Andric 
282fe6060f1SDimitry Andric   if (TP)
283fe6060f1SDimitry Andric     Err = joinErrors(std::move(Err),
284fe6060f1SDimitry Andric                      static_cast<EPCTrampolinePool &>(*TP).deallocatePool());
285fe6060f1SDimitry Andric 
286fe6060f1SDimitry Andric   if (ResolverBlock)
287349cc55cSDimitry Andric     Err =
288349cc55cSDimitry Andric         joinErrors(std::move(Err), MemMgr.deallocate(std::move(ResolverBlock)));
289fe6060f1SDimitry Andric 
290fe6060f1SDimitry Andric   return Err;
291fe6060f1SDimitry Andric }
292fe6060f1SDimitry Andric 
293fe6060f1SDimitry Andric Expected<JITTargetAddress>
294fe6060f1SDimitry Andric EPCIndirectionUtils::writeResolverBlock(JITTargetAddress ReentryFnAddr,
295fe6060f1SDimitry Andric                                         JITTargetAddress ReentryCtxAddr) {
296349cc55cSDimitry Andric   using namespace jitlink;
297349cc55cSDimitry Andric 
298fe6060f1SDimitry Andric   assert(ABI && "ABI can not be null");
299fe6060f1SDimitry Andric   auto ResolverSize = ABI->getResolverCodeSize();
300fe6060f1SDimitry Andric 
301349cc55cSDimitry Andric   auto Alloc =
302349cc55cSDimitry Andric       SimpleSegmentAlloc::Create(EPC.getMemMgr(), nullptr,
303349cc55cSDimitry Andric                                  {{MemProt::Read | MemProt::Exec,
304349cc55cSDimitry Andric                                    {ResolverSize, Align(EPC.getPageSize())}}});
305349cc55cSDimitry Andric 
306fe6060f1SDimitry Andric   if (!Alloc)
307fe6060f1SDimitry Andric     return Alloc.takeError();
308fe6060f1SDimitry Andric 
309349cc55cSDimitry Andric   auto SegInfo = Alloc->getSegInfo(MemProt::Read | MemProt::Exec);
310d781ede6SDimitry Andric   ResolverBlockAddr = SegInfo.Addr.getValue();
311d781ede6SDimitry Andric   ABI->writeResolverCode(SegInfo.WorkingMem.data(), ResolverBlockAddr,
31204eeddc0SDimitry Andric                          ReentryFnAddr, ReentryCtxAddr);
313fe6060f1SDimitry Andric 
314349cc55cSDimitry Andric   auto FA = Alloc->finalize();
315349cc55cSDimitry Andric   if (!FA)
316349cc55cSDimitry Andric     return FA.takeError();
317fe6060f1SDimitry Andric 
318349cc55cSDimitry Andric   ResolverBlock = std::move(*FA);
319d781ede6SDimitry Andric   return ResolverBlockAddr;
320fe6060f1SDimitry Andric }
321fe6060f1SDimitry Andric 
322fe6060f1SDimitry Andric std::unique_ptr<IndirectStubsManager>
323fe6060f1SDimitry Andric EPCIndirectionUtils::createIndirectStubsManager() {
324fe6060f1SDimitry Andric   return std::make_unique<EPCIndirectStubsManager>(*this);
325fe6060f1SDimitry Andric }
326fe6060f1SDimitry Andric 
327fe6060f1SDimitry Andric TrampolinePool &EPCIndirectionUtils::getTrampolinePool() {
328fe6060f1SDimitry Andric   if (!TP)
329fe6060f1SDimitry Andric     TP = std::make_unique<EPCTrampolinePool>(*this);
330fe6060f1SDimitry Andric   return *TP;
331fe6060f1SDimitry Andric }
332fe6060f1SDimitry Andric 
333fe6060f1SDimitry Andric LazyCallThroughManager &EPCIndirectionUtils::createLazyCallThroughManager(
334fe6060f1SDimitry Andric     ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr) {
335fe6060f1SDimitry Andric   assert(!LCTM &&
336fe6060f1SDimitry Andric          "createLazyCallThroughManager can not have been called before");
337fe6060f1SDimitry Andric   LCTM = std::make_unique<LazyCallThroughManager>(ES, ErrorHandlerAddr,
338fe6060f1SDimitry Andric                                                   &getTrampolinePool());
339fe6060f1SDimitry Andric   return *LCTM;
340fe6060f1SDimitry Andric }
341fe6060f1SDimitry Andric 
342fe6060f1SDimitry Andric EPCIndirectionUtils::EPCIndirectionUtils(ExecutorProcessControl &EPC,
343fe6060f1SDimitry Andric                                          std::unique_ptr<ABISupport> ABI)
344fe6060f1SDimitry Andric     : EPC(EPC), ABI(std::move(ABI)) {
345fe6060f1SDimitry Andric   assert(this->ABI && "ABI can not be null");
346fe6060f1SDimitry Andric 
347fe6060f1SDimitry Andric   assert(EPC.getPageSize() > getABISupport().getStubSize() &&
348fe6060f1SDimitry Andric          "Stubs larger than one page are not supported");
349fe6060f1SDimitry Andric }
350fe6060f1SDimitry Andric 
351fe6060f1SDimitry Andric Expected<EPCIndirectionUtils::IndirectStubInfoVector>
352fe6060f1SDimitry Andric EPCIndirectionUtils::getIndirectStubs(unsigned NumStubs) {
353349cc55cSDimitry Andric   using namespace jitlink;
354fe6060f1SDimitry Andric 
355fe6060f1SDimitry Andric   std::lock_guard<std::mutex> Lock(EPCUIMutex);
356fe6060f1SDimitry Andric 
357fe6060f1SDimitry Andric   // If there aren't enough stubs available then allocate some more.
358fe6060f1SDimitry Andric   if (NumStubs > AvailableIndirectStubs.size()) {
359fe6060f1SDimitry Andric     auto NumStubsToAllocate = NumStubs;
360fe6060f1SDimitry Andric     auto PageSize = EPC.getPageSize();
361fe6060f1SDimitry Andric     auto StubBytes = alignTo(NumStubsToAllocate * ABI->getStubSize(), PageSize);
362fe6060f1SDimitry Andric     NumStubsToAllocate = StubBytes / ABI->getStubSize();
363349cc55cSDimitry Andric     auto PtrBytes =
364fe6060f1SDimitry Andric         alignTo(NumStubsToAllocate * ABI->getPointerSize(), PageSize);
365fe6060f1SDimitry Andric 
366349cc55cSDimitry Andric     auto StubProt = MemProt::Read | MemProt::Exec;
367349cc55cSDimitry Andric     auto PtrProt = MemProt::Read | MemProt::Write;
368fe6060f1SDimitry Andric 
369349cc55cSDimitry Andric     auto Alloc = SimpleSegmentAlloc::Create(
370349cc55cSDimitry Andric         EPC.getMemMgr(), nullptr,
371349cc55cSDimitry Andric         {{StubProt, {static_cast<size_t>(StubBytes), Align(PageSize)}},
372349cc55cSDimitry Andric          {PtrProt, {static_cast<size_t>(PtrBytes), Align(PageSize)}}});
373349cc55cSDimitry Andric 
374fe6060f1SDimitry Andric     if (!Alloc)
375fe6060f1SDimitry Andric       return Alloc.takeError();
376fe6060f1SDimitry Andric 
377349cc55cSDimitry Andric     auto StubSeg = Alloc->getSegInfo(StubProt);
378349cc55cSDimitry Andric     auto PtrSeg = Alloc->getSegInfo(PtrProt);
379fe6060f1SDimitry Andric 
38004eeddc0SDimitry Andric     ABI->writeIndirectStubsBlock(StubSeg.WorkingMem.data(),
38104eeddc0SDimitry Andric                                  StubSeg.Addr.getValue(),
38204eeddc0SDimitry Andric                                  PtrSeg.Addr.getValue(), NumStubsToAllocate);
383fe6060f1SDimitry Andric 
384349cc55cSDimitry Andric     auto FA = Alloc->finalize();
385349cc55cSDimitry Andric     if (!FA)
386349cc55cSDimitry Andric       return FA.takeError();
387fe6060f1SDimitry Andric 
388349cc55cSDimitry Andric     IndirectStubAllocs.push_back(std::move(*FA));
389349cc55cSDimitry Andric 
390349cc55cSDimitry Andric     auto StubExecutorAddr = StubSeg.Addr;
391349cc55cSDimitry Andric     auto PtrExecutorAddr = PtrSeg.Addr;
392fe6060f1SDimitry Andric     for (unsigned I = 0; I != NumStubsToAllocate; ++I) {
39304eeddc0SDimitry Andric       AvailableIndirectStubs.push_back(IndirectStubInfo(
39404eeddc0SDimitry Andric           StubExecutorAddr.getValue(), PtrExecutorAddr.getValue()));
395349cc55cSDimitry Andric       StubExecutorAddr += ABI->getStubSize();
396349cc55cSDimitry Andric       PtrExecutorAddr += ABI->getPointerSize();
397fe6060f1SDimitry Andric     }
398fe6060f1SDimitry Andric   }
399fe6060f1SDimitry Andric 
400fe6060f1SDimitry Andric   assert(NumStubs <= AvailableIndirectStubs.size() &&
401fe6060f1SDimitry Andric          "Sufficient stubs should have been allocated above");
402fe6060f1SDimitry Andric 
403fe6060f1SDimitry Andric   IndirectStubInfoVector Result;
404fe6060f1SDimitry Andric   while (NumStubs--) {
405fe6060f1SDimitry Andric     Result.push_back(AvailableIndirectStubs.back());
406fe6060f1SDimitry Andric     AvailableIndirectStubs.pop_back();
407fe6060f1SDimitry Andric   }
408fe6060f1SDimitry Andric 
409fe6060f1SDimitry Andric   return std::move(Result);
410fe6060f1SDimitry Andric }
411fe6060f1SDimitry Andric 
412fe6060f1SDimitry Andric static JITTargetAddress reentry(JITTargetAddress LCTMAddr,
413fe6060f1SDimitry Andric                                 JITTargetAddress TrampolineAddr) {
414fe6060f1SDimitry Andric   auto &LCTM = *jitTargetAddressToPointer<LazyCallThroughManager *>(LCTMAddr);
415fe6060f1SDimitry Andric   std::promise<JITTargetAddress> LandingAddrP;
416fe6060f1SDimitry Andric   auto LandingAddrF = LandingAddrP.get_future();
417fe6060f1SDimitry Andric   LCTM.resolveTrampolineLandingAddress(
418fe6060f1SDimitry Andric       TrampolineAddr,
419fe6060f1SDimitry Andric       [&](JITTargetAddress Addr) { LandingAddrP.set_value(Addr); });
420fe6060f1SDimitry Andric   return LandingAddrF.get();
421fe6060f1SDimitry Andric }
422fe6060f1SDimitry Andric 
423fe6060f1SDimitry Andric Error setUpInProcessLCTMReentryViaEPCIU(EPCIndirectionUtils &EPCIU) {
424fe6060f1SDimitry Andric   auto &LCTM = EPCIU.getLazyCallThroughManager();
425fe6060f1SDimitry Andric   return EPCIU
426fe6060f1SDimitry Andric       .writeResolverBlock(pointerToJITTargetAddress(&reentry),
427fe6060f1SDimitry Andric                           pointerToJITTargetAddress(&LCTM))
428fe6060f1SDimitry Andric       .takeError();
429fe6060f1SDimitry Andric }
430fe6060f1SDimitry Andric 
431fe6060f1SDimitry Andric } // end namespace orc
432fe6060f1SDimitry Andric } // end namespace llvm
433