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>
getIndirectStubs(EPCIndirectionUtils & EPCIU,unsigned NumStubs)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:
EPCIndirectStubsManager(EPCIndirectionUtils & EPCIU)57fe6060f1SDimitry Andric EPCIndirectStubsManager(EPCIndirectionUtils &EPCIU) : EPCIU(EPCIU) {}
58fe6060f1SDimitry Andric
59fe6060f1SDimitry Andric Error deallocateStubs();
60fe6060f1SDimitry Andric
61*06c3fb27SDimitry Andric Error createStub(StringRef StubName, ExecutorAddr StubAddr,
62fe6060f1SDimitry Andric JITSymbolFlags StubFlags) override;
63fe6060f1SDimitry Andric
64fe6060f1SDimitry Andric Error createStubs(const StubInitsMap &StubInits) override;
65fe6060f1SDimitry Andric
66*06c3fb27SDimitry Andric ExecutorSymbolDef findStub(StringRef Name, bool ExportedStubsOnly) override;
67fe6060f1SDimitry Andric
68*06c3fb27SDimitry Andric ExecutorSymbolDef findPointer(StringRef Name) override;
69fe6060f1SDimitry Andric
70*06c3fb27SDimitry Andric Error updatePointer(StringRef Name, ExecutorAddr 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
EPCTrampolinePool(EPCIndirectionUtils & EPCIU)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
deallocatePool()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
grow()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);
121*06c3fb27SDimitry Andric EPCIU.getABISupport().writeTrampolines(
122*06c3fb27SDimitry Andric SegInfo.WorkingMem.data(), SegInfo.Addr, ResolverAddress, NumTrampolines);
123fe6060f1SDimitry Andric for (unsigned I = 0; I < NumTrampolines; ++I)
124*06c3fb27SDimitry Andric AvailableTrampolines.push_back(SegInfo.Addr + (I * TrampolineSize));
125fe6060f1SDimitry Andric
126349cc55cSDimitry Andric auto FA = Alloc->finalize();
127349cc55cSDimitry Andric if (!FA)
128349cc55cSDimitry Andric return FA.takeError();
129fe6060f1SDimitry Andric
130349cc55cSDimitry Andric TrampolineBlocks.push_back(std::move(*FA));
131fe6060f1SDimitry Andric
132fe6060f1SDimitry Andric return Error::success();
133fe6060f1SDimitry Andric }
134fe6060f1SDimitry Andric
createStub(StringRef StubName,ExecutorAddr StubAddr,JITSymbolFlags StubFlags)135fe6060f1SDimitry Andric Error EPCIndirectStubsManager::createStub(StringRef StubName,
136*06c3fb27SDimitry Andric ExecutorAddr StubAddr,
137fe6060f1SDimitry Andric JITSymbolFlags StubFlags) {
138fe6060f1SDimitry Andric StubInitsMap SIM;
139fe6060f1SDimitry Andric SIM[StubName] = std::make_pair(StubAddr, StubFlags);
140fe6060f1SDimitry Andric return createStubs(SIM);
141fe6060f1SDimitry Andric }
142fe6060f1SDimitry Andric
createStubs(const StubInitsMap & StubInits)143fe6060f1SDimitry Andric Error EPCIndirectStubsManager::createStubs(const StubInitsMap &StubInits) {
144fe6060f1SDimitry Andric auto AvailableStubInfos = getIndirectStubs(EPCIU, StubInits.size());
145fe6060f1SDimitry Andric if (!AvailableStubInfos)
146fe6060f1SDimitry Andric return AvailableStubInfos.takeError();
147fe6060f1SDimitry Andric
148fe6060f1SDimitry Andric {
149fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(ISMMutex);
150fe6060f1SDimitry Andric unsigned ASIdx = 0;
151fe6060f1SDimitry Andric for (auto &SI : StubInits) {
152fe6060f1SDimitry Andric auto &A = (*AvailableStubInfos)[ASIdx++];
153fe6060f1SDimitry Andric StubInfos[SI.first()] = std::make_pair(A, SI.second.second);
154fe6060f1SDimitry Andric }
155fe6060f1SDimitry Andric }
156fe6060f1SDimitry Andric
157fe6060f1SDimitry Andric auto &MemAccess = EPCIU.getExecutorProcessControl().getMemoryAccess();
158fe6060f1SDimitry Andric switch (EPCIU.getABISupport().getPointerSize()) {
159fe6060f1SDimitry Andric case 4: {
160fe6060f1SDimitry Andric unsigned ASIdx = 0;
161fe6060f1SDimitry Andric std::vector<tpctypes::UInt32Write> PtrUpdates;
162fe6060f1SDimitry Andric for (auto &SI : StubInits)
163*06c3fb27SDimitry Andric PtrUpdates.push_back({(*AvailableStubInfos)[ASIdx++].PointerAddress,
164*06c3fb27SDimitry Andric static_cast<uint32_t>(SI.second.first.getValue())});
165fe6060f1SDimitry Andric return MemAccess.writeUInt32s(PtrUpdates);
166fe6060f1SDimitry Andric }
167fe6060f1SDimitry Andric case 8: {
168fe6060f1SDimitry Andric unsigned ASIdx = 0;
169fe6060f1SDimitry Andric std::vector<tpctypes::UInt64Write> PtrUpdates;
170fe6060f1SDimitry Andric for (auto &SI : StubInits)
171*06c3fb27SDimitry Andric PtrUpdates.push_back({(*AvailableStubInfos)[ASIdx++].PointerAddress,
172*06c3fb27SDimitry Andric static_cast<uint64_t>(SI.second.first.getValue())});
173fe6060f1SDimitry Andric return MemAccess.writeUInt64s(PtrUpdates);
174fe6060f1SDimitry Andric }
175fe6060f1SDimitry Andric default:
176fe6060f1SDimitry Andric return make_error<StringError>("Unsupported pointer size",
177fe6060f1SDimitry Andric inconvertibleErrorCode());
178fe6060f1SDimitry Andric }
179fe6060f1SDimitry Andric }
180fe6060f1SDimitry Andric
findStub(StringRef Name,bool ExportedStubsOnly)181*06c3fb27SDimitry Andric ExecutorSymbolDef EPCIndirectStubsManager::findStub(StringRef Name,
182fe6060f1SDimitry Andric bool ExportedStubsOnly) {
183fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(ISMMutex);
184fe6060f1SDimitry Andric auto I = StubInfos.find(Name);
185fe6060f1SDimitry Andric if (I == StubInfos.end())
186*06c3fb27SDimitry Andric return ExecutorSymbolDef();
187fe6060f1SDimitry Andric return {I->second.first.StubAddress, I->second.second};
188fe6060f1SDimitry Andric }
189fe6060f1SDimitry Andric
findPointer(StringRef Name)190*06c3fb27SDimitry Andric ExecutorSymbolDef EPCIndirectStubsManager::findPointer(StringRef Name) {
191fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(ISMMutex);
192fe6060f1SDimitry Andric auto I = StubInfos.find(Name);
193fe6060f1SDimitry Andric if (I == StubInfos.end())
194*06c3fb27SDimitry Andric return ExecutorSymbolDef();
195fe6060f1SDimitry Andric return {I->second.first.PointerAddress, I->second.second};
196fe6060f1SDimitry Andric }
197fe6060f1SDimitry Andric
updatePointer(StringRef Name,ExecutorAddr NewAddr)198fe6060f1SDimitry Andric Error EPCIndirectStubsManager::updatePointer(StringRef Name,
199*06c3fb27SDimitry Andric ExecutorAddr NewAddr) {
200fe6060f1SDimitry Andric
201*06c3fb27SDimitry Andric ExecutorAddr PtrAddr;
202fe6060f1SDimitry Andric {
203fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(ISMMutex);
204fe6060f1SDimitry Andric auto I = StubInfos.find(Name);
205fe6060f1SDimitry Andric if (I == StubInfos.end())
206fe6060f1SDimitry Andric return make_error<StringError>("Unknown stub name",
207fe6060f1SDimitry Andric inconvertibleErrorCode());
208fe6060f1SDimitry Andric PtrAddr = I->second.first.PointerAddress;
209fe6060f1SDimitry Andric }
210fe6060f1SDimitry Andric
211fe6060f1SDimitry Andric auto &MemAccess = EPCIU.getExecutorProcessControl().getMemoryAccess();
212fe6060f1SDimitry Andric switch (EPCIU.getABISupport().getPointerSize()) {
213fe6060f1SDimitry Andric case 4: {
214*06c3fb27SDimitry Andric tpctypes::UInt32Write PUpdate(PtrAddr, NewAddr.getValue());
215fe6060f1SDimitry Andric return MemAccess.writeUInt32s(PUpdate);
216fe6060f1SDimitry Andric }
217fe6060f1SDimitry Andric case 8: {
218*06c3fb27SDimitry Andric tpctypes::UInt64Write PUpdate(PtrAddr, NewAddr.getValue());
219fe6060f1SDimitry Andric return MemAccess.writeUInt64s(PUpdate);
220fe6060f1SDimitry Andric }
221fe6060f1SDimitry Andric default:
222fe6060f1SDimitry Andric return make_error<StringError>("Unsupported pointer size",
223fe6060f1SDimitry Andric inconvertibleErrorCode());
224fe6060f1SDimitry Andric }
225fe6060f1SDimitry Andric }
226fe6060f1SDimitry Andric
227fe6060f1SDimitry Andric } // end anonymous namespace.
228fe6060f1SDimitry Andric
229fe6060f1SDimitry Andric namespace llvm {
230fe6060f1SDimitry Andric namespace orc {
231fe6060f1SDimitry Andric
23281ad6265SDimitry Andric EPCIndirectionUtils::ABISupport::~ABISupport() = default;
233fe6060f1SDimitry Andric
234fe6060f1SDimitry Andric Expected<std::unique_ptr<EPCIndirectionUtils>>
Create(ExecutorProcessControl & EPC)235fe6060f1SDimitry Andric EPCIndirectionUtils::Create(ExecutorProcessControl &EPC) {
236fe6060f1SDimitry Andric const auto &TT = EPC.getTargetTriple();
237fe6060f1SDimitry Andric switch (TT.getArch()) {
238fe6060f1SDimitry Andric default:
239fe6060f1SDimitry Andric return make_error<StringError>(
240fe6060f1SDimitry Andric std::string("No EPCIndirectionUtils available for ") + TT.str(),
241fe6060f1SDimitry Andric inconvertibleErrorCode());
242fe6060f1SDimitry Andric case Triple::aarch64:
243fe6060f1SDimitry Andric case Triple::aarch64_32:
244fe6060f1SDimitry Andric return CreateWithABI<OrcAArch64>(EPC);
245fe6060f1SDimitry Andric
246fe6060f1SDimitry Andric case Triple::x86:
247fe6060f1SDimitry Andric return CreateWithABI<OrcI386>(EPC);
248fe6060f1SDimitry Andric
249bdd1243dSDimitry Andric case Triple::loongarch64:
250bdd1243dSDimitry Andric return CreateWithABI<OrcLoongArch64>(EPC);
251bdd1243dSDimitry Andric
252fe6060f1SDimitry Andric case Triple::mips:
253fe6060f1SDimitry Andric return CreateWithABI<OrcMips32Be>(EPC);
254fe6060f1SDimitry Andric
255fe6060f1SDimitry Andric case Triple::mipsel:
256fe6060f1SDimitry Andric return CreateWithABI<OrcMips32Le>(EPC);
257fe6060f1SDimitry Andric
258fe6060f1SDimitry Andric case Triple::mips64:
259fe6060f1SDimitry Andric case Triple::mips64el:
260fe6060f1SDimitry Andric return CreateWithABI<OrcMips64>(EPC);
261fe6060f1SDimitry Andric
26281ad6265SDimitry Andric case Triple::riscv64:
26381ad6265SDimitry Andric return CreateWithABI<OrcRiscv64>(EPC);
26481ad6265SDimitry Andric
265fe6060f1SDimitry Andric case Triple::x86_64:
266fe6060f1SDimitry Andric if (TT.getOS() == Triple::OSType::Win32)
267fe6060f1SDimitry Andric return CreateWithABI<OrcX86_64_Win32>(EPC);
268fe6060f1SDimitry Andric else
269fe6060f1SDimitry Andric return CreateWithABI<OrcX86_64_SysV>(EPC);
270fe6060f1SDimitry Andric }
271fe6060f1SDimitry Andric }
272fe6060f1SDimitry Andric
cleanup()273fe6060f1SDimitry Andric Error EPCIndirectionUtils::cleanup() {
274fe6060f1SDimitry Andric
275349cc55cSDimitry Andric auto &MemMgr = EPC.getMemMgr();
276349cc55cSDimitry Andric auto Err = MemMgr.deallocate(std::move(IndirectStubAllocs));
277fe6060f1SDimitry Andric
278fe6060f1SDimitry Andric if (TP)
279fe6060f1SDimitry Andric Err = joinErrors(std::move(Err),
280fe6060f1SDimitry Andric static_cast<EPCTrampolinePool &>(*TP).deallocatePool());
281fe6060f1SDimitry Andric
282fe6060f1SDimitry Andric if (ResolverBlock)
283349cc55cSDimitry Andric Err =
284349cc55cSDimitry Andric joinErrors(std::move(Err), MemMgr.deallocate(std::move(ResolverBlock)));
285fe6060f1SDimitry Andric
286fe6060f1SDimitry Andric return Err;
287fe6060f1SDimitry Andric }
288fe6060f1SDimitry Andric
289*06c3fb27SDimitry Andric Expected<ExecutorAddr>
writeResolverBlock(ExecutorAddr ReentryFnAddr,ExecutorAddr ReentryCtxAddr)290*06c3fb27SDimitry Andric EPCIndirectionUtils::writeResolverBlock(ExecutorAddr ReentryFnAddr,
291*06c3fb27SDimitry Andric ExecutorAddr ReentryCtxAddr) {
292349cc55cSDimitry Andric using namespace jitlink;
293349cc55cSDimitry Andric
294fe6060f1SDimitry Andric assert(ABI && "ABI can not be null");
295fe6060f1SDimitry Andric auto ResolverSize = ABI->getResolverCodeSize();
296fe6060f1SDimitry Andric
297349cc55cSDimitry Andric auto Alloc =
298349cc55cSDimitry Andric SimpleSegmentAlloc::Create(EPC.getMemMgr(), nullptr,
299349cc55cSDimitry Andric {{MemProt::Read | MemProt::Exec,
300349cc55cSDimitry Andric {ResolverSize, Align(EPC.getPageSize())}}});
301349cc55cSDimitry Andric
302fe6060f1SDimitry Andric if (!Alloc)
303fe6060f1SDimitry Andric return Alloc.takeError();
304fe6060f1SDimitry Andric
305349cc55cSDimitry Andric auto SegInfo = Alloc->getSegInfo(MemProt::Read | MemProt::Exec);
306*06c3fb27SDimitry Andric ResolverBlockAddr = SegInfo.Addr;
307d781ede6SDimitry Andric ABI->writeResolverCode(SegInfo.WorkingMem.data(), ResolverBlockAddr,
30804eeddc0SDimitry Andric ReentryFnAddr, ReentryCtxAddr);
309fe6060f1SDimitry Andric
310349cc55cSDimitry Andric auto FA = Alloc->finalize();
311349cc55cSDimitry Andric if (!FA)
312349cc55cSDimitry Andric return FA.takeError();
313fe6060f1SDimitry Andric
314349cc55cSDimitry Andric ResolverBlock = std::move(*FA);
315d781ede6SDimitry Andric return ResolverBlockAddr;
316fe6060f1SDimitry Andric }
317fe6060f1SDimitry Andric
318fe6060f1SDimitry Andric std::unique_ptr<IndirectStubsManager>
createIndirectStubsManager()319fe6060f1SDimitry Andric EPCIndirectionUtils::createIndirectStubsManager() {
320fe6060f1SDimitry Andric return std::make_unique<EPCIndirectStubsManager>(*this);
321fe6060f1SDimitry Andric }
322fe6060f1SDimitry Andric
getTrampolinePool()323fe6060f1SDimitry Andric TrampolinePool &EPCIndirectionUtils::getTrampolinePool() {
324fe6060f1SDimitry Andric if (!TP)
325fe6060f1SDimitry Andric TP = std::make_unique<EPCTrampolinePool>(*this);
326fe6060f1SDimitry Andric return *TP;
327fe6060f1SDimitry Andric }
328fe6060f1SDimitry Andric
createLazyCallThroughManager(ExecutionSession & ES,ExecutorAddr ErrorHandlerAddr)329fe6060f1SDimitry Andric LazyCallThroughManager &EPCIndirectionUtils::createLazyCallThroughManager(
330*06c3fb27SDimitry Andric ExecutionSession &ES, ExecutorAddr ErrorHandlerAddr) {
331fe6060f1SDimitry Andric assert(!LCTM &&
332fe6060f1SDimitry Andric "createLazyCallThroughManager can not have been called before");
333fe6060f1SDimitry Andric LCTM = std::make_unique<LazyCallThroughManager>(ES, ErrorHandlerAddr,
334fe6060f1SDimitry Andric &getTrampolinePool());
335fe6060f1SDimitry Andric return *LCTM;
336fe6060f1SDimitry Andric }
337fe6060f1SDimitry Andric
EPCIndirectionUtils(ExecutorProcessControl & EPC,std::unique_ptr<ABISupport> ABI)338fe6060f1SDimitry Andric EPCIndirectionUtils::EPCIndirectionUtils(ExecutorProcessControl &EPC,
339fe6060f1SDimitry Andric std::unique_ptr<ABISupport> ABI)
340fe6060f1SDimitry Andric : EPC(EPC), ABI(std::move(ABI)) {
341fe6060f1SDimitry Andric assert(this->ABI && "ABI can not be null");
342fe6060f1SDimitry Andric
343fe6060f1SDimitry Andric assert(EPC.getPageSize() > getABISupport().getStubSize() &&
344fe6060f1SDimitry Andric "Stubs larger than one page are not supported");
345fe6060f1SDimitry Andric }
346fe6060f1SDimitry Andric
347fe6060f1SDimitry Andric Expected<EPCIndirectionUtils::IndirectStubInfoVector>
getIndirectStubs(unsigned NumStubs)348fe6060f1SDimitry Andric EPCIndirectionUtils::getIndirectStubs(unsigned NumStubs) {
349349cc55cSDimitry Andric using namespace jitlink;
350fe6060f1SDimitry Andric
351fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(EPCUIMutex);
352fe6060f1SDimitry Andric
353fe6060f1SDimitry Andric // If there aren't enough stubs available then allocate some more.
354fe6060f1SDimitry Andric if (NumStubs > AvailableIndirectStubs.size()) {
355fe6060f1SDimitry Andric auto NumStubsToAllocate = NumStubs;
356fe6060f1SDimitry Andric auto PageSize = EPC.getPageSize();
357fe6060f1SDimitry Andric auto StubBytes = alignTo(NumStubsToAllocate * ABI->getStubSize(), PageSize);
358fe6060f1SDimitry Andric NumStubsToAllocate = StubBytes / ABI->getStubSize();
359349cc55cSDimitry Andric auto PtrBytes =
360fe6060f1SDimitry Andric alignTo(NumStubsToAllocate * ABI->getPointerSize(), PageSize);
361fe6060f1SDimitry Andric
362349cc55cSDimitry Andric auto StubProt = MemProt::Read | MemProt::Exec;
363349cc55cSDimitry Andric auto PtrProt = MemProt::Read | MemProt::Write;
364fe6060f1SDimitry Andric
365349cc55cSDimitry Andric auto Alloc = SimpleSegmentAlloc::Create(
366349cc55cSDimitry Andric EPC.getMemMgr(), nullptr,
367349cc55cSDimitry Andric {{StubProt, {static_cast<size_t>(StubBytes), Align(PageSize)}},
368349cc55cSDimitry Andric {PtrProt, {static_cast<size_t>(PtrBytes), Align(PageSize)}}});
369349cc55cSDimitry Andric
370fe6060f1SDimitry Andric if (!Alloc)
371fe6060f1SDimitry Andric return Alloc.takeError();
372fe6060f1SDimitry Andric
373349cc55cSDimitry Andric auto StubSeg = Alloc->getSegInfo(StubProt);
374349cc55cSDimitry Andric auto PtrSeg = Alloc->getSegInfo(PtrProt);
375fe6060f1SDimitry Andric
376*06c3fb27SDimitry Andric ABI->writeIndirectStubsBlock(StubSeg.WorkingMem.data(), StubSeg.Addr,
377*06c3fb27SDimitry Andric PtrSeg.Addr, NumStubsToAllocate);
378fe6060f1SDimitry Andric
379349cc55cSDimitry Andric auto FA = Alloc->finalize();
380349cc55cSDimitry Andric if (!FA)
381349cc55cSDimitry Andric return FA.takeError();
382fe6060f1SDimitry Andric
383349cc55cSDimitry Andric IndirectStubAllocs.push_back(std::move(*FA));
384349cc55cSDimitry Andric
385349cc55cSDimitry Andric auto StubExecutorAddr = StubSeg.Addr;
386349cc55cSDimitry Andric auto PtrExecutorAddr = PtrSeg.Addr;
387fe6060f1SDimitry Andric for (unsigned I = 0; I != NumStubsToAllocate; ++I) {
388*06c3fb27SDimitry Andric AvailableIndirectStubs.push_back(
389*06c3fb27SDimitry Andric IndirectStubInfo(StubExecutorAddr, PtrExecutorAddr));
390349cc55cSDimitry Andric StubExecutorAddr += ABI->getStubSize();
391349cc55cSDimitry Andric PtrExecutorAddr += ABI->getPointerSize();
392fe6060f1SDimitry Andric }
393fe6060f1SDimitry Andric }
394fe6060f1SDimitry Andric
395fe6060f1SDimitry Andric assert(NumStubs <= AvailableIndirectStubs.size() &&
396fe6060f1SDimitry Andric "Sufficient stubs should have been allocated above");
397fe6060f1SDimitry Andric
398fe6060f1SDimitry Andric IndirectStubInfoVector Result;
399fe6060f1SDimitry Andric while (NumStubs--) {
400fe6060f1SDimitry Andric Result.push_back(AvailableIndirectStubs.back());
401fe6060f1SDimitry Andric AvailableIndirectStubs.pop_back();
402fe6060f1SDimitry Andric }
403fe6060f1SDimitry Andric
404fe6060f1SDimitry Andric return std::move(Result);
405fe6060f1SDimitry Andric }
406fe6060f1SDimitry Andric
reentry(JITTargetAddress LCTMAddr,JITTargetAddress TrampolineAddr)407fe6060f1SDimitry Andric static JITTargetAddress reentry(JITTargetAddress LCTMAddr,
408fe6060f1SDimitry Andric JITTargetAddress TrampolineAddr) {
409fe6060f1SDimitry Andric auto &LCTM = *jitTargetAddressToPointer<LazyCallThroughManager *>(LCTMAddr);
410*06c3fb27SDimitry Andric std::promise<ExecutorAddr> LandingAddrP;
411fe6060f1SDimitry Andric auto LandingAddrF = LandingAddrP.get_future();
412fe6060f1SDimitry Andric LCTM.resolveTrampolineLandingAddress(
413*06c3fb27SDimitry Andric ExecutorAddr(TrampolineAddr),
414*06c3fb27SDimitry Andric [&](ExecutorAddr Addr) { LandingAddrP.set_value(Addr); });
415*06c3fb27SDimitry Andric return LandingAddrF.get().getValue();
416fe6060f1SDimitry Andric }
417fe6060f1SDimitry Andric
setUpInProcessLCTMReentryViaEPCIU(EPCIndirectionUtils & EPCIU)418fe6060f1SDimitry Andric Error setUpInProcessLCTMReentryViaEPCIU(EPCIndirectionUtils &EPCIU) {
419fe6060f1SDimitry Andric auto &LCTM = EPCIU.getLazyCallThroughManager();
420fe6060f1SDimitry Andric return EPCIU
421*06c3fb27SDimitry Andric .writeResolverBlock(ExecutorAddr::fromPtr(&reentry),
422*06c3fb27SDimitry Andric ExecutorAddr::fromPtr(&LCTM))
423fe6060f1SDimitry Andric .takeError();
424fe6060f1SDimitry Andric }
425fe6060f1SDimitry Andric
426fe6060f1SDimitry Andric } // end namespace orc
427fe6060f1SDimitry Andric } // end namespace llvm
428