29 return EPCIU.getIndirectStubs(NumStubs);
41 Error deallocatePool();
44 Error grow()
override;
49 unsigned TrampolineSize = 0;
50 unsigned TrampolinesPerPage = 0;
51 std::vector<FinalizedAlloc> TrampolineBlocks;
59 Error deallocateStubs();
64 Error createStubs(
const StubInitsMap &StubInits)
override;
73 using StubInfo = std::pair<IndirectStubInfo, JITSymbolFlags>;
85 TrampolineSize =
ABI.getTrampolineSize();
87 (EPC.getPageSize() -
ABI.getPointerSize()) / TrampolineSize;
90 Error EPCTrampolinePool::deallocatePool() {
91 std::promise<MSVCPError> DeallocResultP;
92 auto DeallocResultF = DeallocResultP.get_future();
98 return DeallocResultF.get();
101 Error EPCTrampolinePool::grow() {
102 using namespace jitlink;
104 assert(AvailableTrampolines.empty() &&
105 "Grow called with trampolines still available");
108 assert(ResolverAddress &&
"Resolver address can not be null");
112 auto Alloc = SimpleSegmentAlloc::Create(
113 EPC.getMemMgr(),
nullptr,
114 {{MemProt::Read | MemProt::Exec, {PageSize, Align(PageSize)}}});
116 return Alloc.takeError();
118 unsigned NumTrampolines = TrampolinesPerPage;
120 auto SegInfo =
Alloc->getSegInfo(MemProt::Read | MemProt::Exec);
122 SegInfo.Addr.getValue(),
123 ResolverAddress, NumTrampolines);
124 for (
unsigned I = 0;
I < NumTrampolines; ++
I)
125 AvailableTrampolines.push_back(SegInfo.Addr.getValue() +
126 (
I * TrampolineSize));
128 auto FA =
Alloc->finalize();
130 return FA.takeError();
132 TrampolineBlocks.push_back(
std::move(*FA));
141 SIM[StubName] = std::make_pair(StubAddr, StubFlags);
142 return createStubs(SIM);
145 Error EPCIndirectStubsManager::createStubs(
const StubInitsMap &StubInits) {
146 auto AvailableStubInfos = getIndirectStubs(EPCIU, StubInits.size());
147 if (!AvailableStubInfos)
148 return AvailableStubInfos.takeError();
151 std::lock_guard<std::mutex> Lock(ISMMutex);
153 for (
auto &
SI : StubInits) {
154 auto &
A = (*AvailableStubInfos)[ASIdx++];
155 StubInfos[
SI.first()] = std::make_pair(A,
SI.second.second);
163 std::vector<tpctypes::UInt32Write> PtrUpdates;
164 for (
auto &
SI : StubInits)
165 PtrUpdates.push_back(
166 {
ExecutorAddr((*AvailableStubInfos)[ASIdx++].PointerAddress),
172 std::vector<tpctypes::UInt64Write> PtrUpdates;
173 for (
auto &
SI : StubInits)
174 PtrUpdates.push_back(
175 {
ExecutorAddr((*AvailableStubInfos)[ASIdx++].PointerAddress),
177 return MemAccess.writeUInt64s(PtrUpdates);
180 return make_error<StringError>(
"Unsupported pointer size",
186 bool ExportedStubsOnly) {
187 std::lock_guard<std::mutex> Lock(ISMMutex);
188 auto I = StubInfos.find(
Name);
189 if (
I == StubInfos.end())
191 return {
I->second.first.StubAddress,
I->second.second};
195 std::lock_guard<std::mutex> Lock(ISMMutex);
196 auto I = StubInfos.find(
Name);
197 if (
I == StubInfos.end())
199 return {
I->second.first.PointerAddress,
I->second.second};
207 std::lock_guard<std::mutex> Lock(ISMMutex);
208 auto I = StubInfos.find(
Name);
209 if (
I == StubInfos.end())
210 return make_error<StringError>(
"Unknown stub name",
212 PtrAddr =
I->second.first.PointerAddress;
219 return MemAccess.writeUInt32s(PUpdate);
223 return MemAccess.writeUInt64s(PUpdate);
226 return make_error<StringError>(
"Unsupported pointer size",
241 switch (TT.getArch()) {
243 return make_error<StringError>(
244 std::string(
"No EPCIndirectionUtils available for ") + TT.str(),
248 return CreateWithABI<OrcAArch64>(EPC);
251 return CreateWithABI<OrcI386>(EPC);
254 return CreateWithABI<OrcMips32Be>(EPC);
257 return CreateWithABI<OrcMips32Le>(EPC);
261 return CreateWithABI<OrcMips64>(EPC);
264 return CreateWithABI<OrcRiscv64>(EPC);
267 if (TT.getOS() == Triple::OSType::Win32)
268 return CreateWithABI<OrcX86_64_Win32>(EPC);
270 return CreateWithABI<OrcX86_64_SysV>(EPC);
276 auto &MemMgr = EPC.getMemMgr();
277 auto Err = MemMgr.deallocate(
std::move(IndirectStubAllocs));
281 static_cast<EPCTrampolinePool &
>(*TP).deallocatePool());
293 using namespace jitlink;
296 auto ResolverSize =
ABI->getResolverCodeSize();
299 SimpleSegmentAlloc::Create(EPC.getMemMgr(),
nullptr,
300 {{MemProt::Read | MemProt::Exec,
301 {ResolverSize, Align(EPC.getPageSize())}}});
304 return Alloc.takeError();
306 auto SegInfo =
Alloc->getSegInfo(MemProt::Read | MemProt::Exec);
307 ResolverBlockAddr = SegInfo.Addr.getValue();
308 ABI->writeResolverCode(SegInfo.WorkingMem.data(), ResolverBlockAddr,
309 ReentryFnAddr, ReentryCtxAddr);
311 auto FA =
Alloc->finalize();
313 return FA.takeError();
316 return ResolverBlockAddr;
319 std::unique_ptr<IndirectStubsManager>
321 return std::make_unique<EPCIndirectStubsManager>(*
this);
326 TP = std::make_unique<EPCTrampolinePool>(*
this);
333 "createLazyCallThroughManager can not have been called before");
334 LCTM = std::make_unique<LazyCallThroughManager>(ES, ErrorHandlerAddr,
335 &getTrampolinePool());
340 std::unique_ptr<ABISupport>
ABI)
342 assert(this->ABI &&
"ABI can not be null");
345 "Stubs larger than one page are not supported");
349 EPCIndirectionUtils::getIndirectStubs(
unsigned NumStubs) {
350 using namespace jitlink;
352 std::lock_guard<std::mutex> Lock(EPCUIMutex);
355 if (NumStubs > AvailableIndirectStubs.size()) {
356 auto NumStubsToAllocate = NumStubs;
358 auto StubBytes =
alignTo(NumStubsToAllocate * ABI->getStubSize(),
PageSize);
359 NumStubsToAllocate = StubBytes / ABI->getStubSize();
363 auto StubProt = MemProt::Read | MemProt::Exec;
364 auto PtrProt = MemProt::Read | MemProt::Write;
366 auto Alloc = SimpleSegmentAlloc::Create(
368 {{StubProt, {static_cast<size_t>(StubBytes), Align(PageSize)}},
369 {PtrProt, {static_cast<size_t>(PtrBytes), Align(PageSize)}}});
372 return Alloc.takeError();
374 auto StubSeg =
Alloc->getSegInfo(StubProt);
375 auto PtrSeg =
Alloc->getSegInfo(PtrProt);
377 ABI->writeIndirectStubsBlock(StubSeg.WorkingMem.data(),
378 StubSeg.Addr.getValue(),
379 PtrSeg.Addr.getValue(), NumStubsToAllocate);
381 auto FA =
Alloc->finalize();
383 return FA.takeError();
385 IndirectStubAllocs.push_back(
std::move(*FA));
387 auto StubExecutorAddr = StubSeg.Addr;
388 auto PtrExecutorAddr = PtrSeg.Addr;
389 for (
unsigned I = 0;
I != NumStubsToAllocate; ++
I) {
390 AvailableIndirectStubs.push_back(IndirectStubInfo(
391 StubExecutorAddr.getValue(), PtrExecutorAddr.getValue()));
392 StubExecutorAddr +=
ABI->getStubSize();
393 PtrExecutorAddr +=
ABI->getPointerSize();
397 assert(NumStubs <= AvailableIndirectStubs.size() &&
398 "Sufficient stubs should have been allocated above");
400 IndirectStubInfoVector
Result;
402 Result.push_back(AvailableIndirectStubs.back());
403 AvailableIndirectStubs.pop_back();
411 auto &LCTM = *jitTargetAddressToPointer<LazyCallThroughManager *>(LCTMAddr);
412 std::promise<JITTargetAddress> LandingAddrP;
413 auto LandingAddrF = LandingAddrP.get_future();
414 LCTM.resolveTrampolineLandingAddress(
417 return LandingAddrF.get();