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() {
92 std::promise<MSVCPError> DeallocResultP;
93 auto DeallocResultF = DeallocResultP.get_future();
99 return DeallocResultF.get();
102 Error EPCTrampolinePool::grow() {
103 using namespace jitlink;
105 assert(AvailableTrampolines.empty() &&
106 "Grow called with trampolines still available");
109 assert(ResolverAddress &&
"Resolver address can not be null");
113 auto Alloc = SimpleSegmentAlloc::Create(
114 EPC.getMemMgr(),
nullptr,
115 {{MemProt::Read | MemProt::Exec, {PageSize, Align(PageSize)}}});
117 return Alloc.takeError();
119 unsigned NumTrampolines = TrampolinesPerPage;
121 auto SegInfo = Alloc->getSegInfo(MemProt::Read | MemProt::Exec);
123 SegInfo.Addr.getValue(),
124 ResolverAddress, NumTrampolines);
125 for (
unsigned I = 0;
I < NumTrampolines; ++
I)
126 AvailableTrampolines.push_back(SegInfo.Addr.getValue() +
127 (
I * TrampolineSize));
129 auto FA = Alloc->finalize();
131 return FA.takeError();
133 TrampolineBlocks.push_back(
std::move(*FA));
142 SIM[StubName] = std::make_pair(StubAddr, StubFlags);
143 return createStubs(SIM);
146 Error EPCIndirectStubsManager::createStubs(
const StubInitsMap &StubInits) {
147 auto AvailableStubInfos = getIndirectStubs(EPCIU, StubInits.size());
148 if (!AvailableStubInfos)
149 return AvailableStubInfos.takeError();
152 std::lock_guard<std::mutex>
Lock(ISMMutex);
154 for (
auto &
SI : StubInits) {
155 auto &
A = (*AvailableStubInfos)[ASIdx++];
156 StubInfos[
SI.first()] = std::make_pair(A,
SI.second.second);
164 std::vector<tpctypes::UInt32Write> PtrUpdates;
165 for (
auto &
SI : StubInits)
166 PtrUpdates.push_back(
167 {
ExecutorAddr((*AvailableStubInfos)[ASIdx++].PointerAddress),
173 std::vector<tpctypes::UInt64Write> PtrUpdates;
174 for (
auto &
SI : StubInits)
175 PtrUpdates.push_back(
176 {
ExecutorAddr((*AvailableStubInfos)[ASIdx++].PointerAddress),
178 return MemAccess.writeUInt64s(PtrUpdates);
181 return make_error<StringError>(
"Unsupported pointer size",
187 bool ExportedStubsOnly) {
188 std::lock_guard<std::mutex>
Lock(ISMMutex);
189 auto I = StubInfos.find(
Name);
190 if (
I == StubInfos.end())
192 return {
I->second.first.StubAddress,
I->second.second};
196 std::lock_guard<std::mutex>
Lock(ISMMutex);
197 auto I = StubInfos.find(
Name);
198 if (
I == StubInfos.end())
200 return {
I->second.first.PointerAddress,
I->second.second};
208 std::lock_guard<std::mutex>
Lock(ISMMutex);
209 auto I = StubInfos.find(
Name);
210 if (
I == StubInfos.end())
211 return make_error<StringError>(
"Unknown stub name",
213 PtrAddr =
I->second.first.PointerAddress;
220 return MemAccess.writeUInt32s(PUpdate);
224 return MemAccess.writeUInt64s(PUpdate);
227 return make_error<StringError>(
"Unsupported pointer size",
242 switch (TT.getArch()) {
244 return make_error<StringError>(
245 std::string(
"No EPCIndirectionUtils available for ") + TT.str(),
249 return CreateWithABI<OrcAArch64>(EPC);
252 return CreateWithABI<OrcI386>(EPC);
255 return CreateWithABI<OrcMips32Be>(EPC);
258 return CreateWithABI<OrcMips32Le>(EPC);
262 return CreateWithABI<OrcMips64>(EPC);
265 return CreateWithABI<OrcRiscv64>(EPC);
268 if (TT.getOS() == Triple::OSType::Win32)
269 return CreateWithABI<OrcX86_64_Win32>(EPC);
271 return CreateWithABI<OrcX86_64_SysV>(EPC);
277 auto &MemMgr = EPC.getMemMgr();
278 auto Err = MemMgr.deallocate(
std::move(IndirectStubAllocs));
282 static_cast<EPCTrampolinePool &
>(*TP).deallocatePool());
294 using namespace jitlink;
297 auto ResolverSize =
ABI->getResolverCodeSize();
300 SimpleSegmentAlloc::Create(EPC.getMemMgr(),
nullptr,
301 {{MemProt::Read | MemProt::Exec,
302 {ResolverSize, Align(EPC.getPageSize())}}});
305 return Alloc.takeError();
307 auto SegInfo = Alloc->getSegInfo(MemProt::Read | MemProt::Exec);
308 ResolverBlockAddr = SegInfo.Addr.getValue();
309 ABI->writeResolverCode(SegInfo.WorkingMem.data(), ResolverBlockAddr,
310 ReentryFnAddr, ReentryCtxAddr);
312 auto FA = Alloc->finalize();
314 return FA.takeError();
317 return ResolverBlockAddr;
320 std::unique_ptr<IndirectStubsManager>
322 return std::make_unique<EPCIndirectStubsManager>(*
this);
327 TP = std::make_unique<EPCTrampolinePool>(*
this);
334 "createLazyCallThroughManager can not have been called before");
335 LCTM = std::make_unique<LazyCallThroughManager>(ES, ErrorHandlerAddr,
336 &getTrampolinePool());
341 std::unique_ptr<ABISupport>
ABI)
343 assert(this->ABI &&
"ABI can not be null");
346 "Stubs larger than one page are not supported");
350 EPCIndirectionUtils::getIndirectStubs(
unsigned NumStubs) {
351 using namespace jitlink;
353 std::lock_guard<std::mutex>
Lock(EPCUIMutex);
356 if (NumStubs > AvailableIndirectStubs.size()) {
357 auto NumStubsToAllocate = NumStubs;
359 auto StubBytes =
alignTo(NumStubsToAllocate * ABI->getStubSize(),
PageSize);
360 NumStubsToAllocate = StubBytes / ABI->getStubSize();
364 auto StubProt = MemProt::Read | MemProt::Exec;
365 auto PtrProt = MemProt::Read | MemProt::Write;
367 auto Alloc = SimpleSegmentAlloc::Create(
369 {{StubProt, {static_cast<size_t>(StubBytes), Align(PageSize)}},
370 {PtrProt, {static_cast<size_t>(PtrBytes), Align(PageSize)}}});
373 return Alloc.takeError();
375 auto StubSeg = Alloc->getSegInfo(StubProt);
376 auto PtrSeg = Alloc->getSegInfo(PtrProt);
378 ABI->writeIndirectStubsBlock(StubSeg.WorkingMem.data(),
379 StubSeg.Addr.getValue(),
380 PtrSeg.Addr.getValue(), NumStubsToAllocate);
382 auto FA = Alloc->finalize();
384 return FA.takeError();
386 IndirectStubAllocs.push_back(
std::move(*FA));
388 auto StubExecutorAddr = StubSeg.Addr;
389 auto PtrExecutorAddr = PtrSeg.Addr;
390 for (
unsigned I = 0;
I != NumStubsToAllocate; ++
I) {
391 AvailableIndirectStubs.push_back(IndirectStubInfo(
392 StubExecutorAddr.getValue(), PtrExecutorAddr.getValue()));
393 StubExecutorAddr +=
ABI->getStubSize();
394 PtrExecutorAddr +=
ABI->getPointerSize();
398 assert(NumStubs <= AvailableIndirectStubs.size() &&
399 "Sufficient stubs should have been allocated above");
401 IndirectStubInfoVector
Result;
403 Result.push_back(AvailableIndirectStubs.back());
404 AvailableIndirectStubs.pop_back();
412 auto &LCTM = *jitTargetAddressToPointer<LazyCallThroughManager *>(LCTMAddr);
413 std::promise<JITTargetAddress> LandingAddrP;
414 auto LandingAddrF = LandingAddrP.get_future();
415 LCTM.resolveTrampolineLandingAddress(
418 return LandingAddrF.get();