29 return EPCIU.getIndirectStubs(NumStubs);
41 Error deallocatePool();
49 unsigned TrampolineSize = 0;
50 unsigned TrampolinesPerPage = 0;
51 std::vector<FinalizedAlloc> TrampolineBlocks;
59 Error deallocateStubs();
73 using StubInfo = std::pair<IndirectStubInfo, JITSymbolFlags>;
85 TrampolineSize =
ABI.getTrampolineSize();
87 (EPC.getPageSize() -
ABI.getPointerSize()) / TrampolineSize;
90Error EPCTrampolinePool::deallocatePool() {
91 std::promise<MSVCPError> DeallocResultP;
92 auto DeallocResultF = DeallocResultP.get_future();
95 std::move(TrampolineBlocks),
96 [&](
Error Err) { DeallocResultP.set_value(std::move(Err)); });
98 return DeallocResultF.get();
101Error 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;
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);
145Error 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),
168 return MemAccess.writeUInt32s(PtrUpdates);
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<OrcLoongArch64>(EPC);
257 return CreateWithABI<OrcMips32Be>(EPC);
260 return CreateWithABI<OrcMips32Le>(EPC);
264 return CreateWithABI<OrcMips64>(EPC);
267 return CreateWithABI<OrcRiscv64>(EPC);
270 if (TT.getOS() == Triple::OSType::Win32)
271 return CreateWithABI<OrcX86_64_Win32>(EPC);
273 return CreateWithABI<OrcX86_64_SysV>(EPC);
279 auto &MemMgr = EPC.getMemMgr();
280 auto Err = MemMgr.deallocate(std::move(IndirectStubAllocs));
284 static_cast<EPCTrampolinePool &
>(*TP).deallocatePool());
288 joinErrors(std::move(Err), MemMgr.deallocate(std::move(ResolverBlock)));
296 using namespace jitlink;
299 auto ResolverSize =
ABI->getResolverCodeSize();
302 SimpleSegmentAlloc::Create(EPC.getMemMgr(),
nullptr,
303 {{MemProt::Read | MemProt::Exec,
304 {ResolverSize, Align(EPC.getPageSize())}}});
307 return Alloc.takeError();
309 auto SegInfo = Alloc->getSegInfo(MemProt::Read | MemProt::Exec);
310 ResolverBlockAddr = SegInfo.Addr.getValue();
311 ABI->writeResolverCode(SegInfo.WorkingMem.data(), ResolverBlockAddr,
312 ReentryFnAddr, ReentryCtxAddr);
314 auto FA = Alloc->finalize();
316 return FA.takeError();
318 ResolverBlock = std::move(*FA);
319 return ResolverBlockAddr;
322std::unique_ptr<IndirectStubsManager>
324 return std::make_unique<EPCIndirectStubsManager>(*
this);
329 TP = std::make_unique<EPCTrampolinePool>(*
this);
336 "createLazyCallThroughManager can not have been called before");
337 LCTM = std::make_unique<LazyCallThroughManager>(ES, ErrorHandlerAddr,
338 &getTrampolinePool());
343 std::unique_ptr<ABISupport>
ABI)
345 assert(this->ABI &&
"ABI can not be null");
348 "Stubs larger than one page are not supported");
352EPCIndirectionUtils::getIndirectStubs(
unsigned NumStubs) {
353 using namespace jitlink;
355 std::lock_guard<std::mutex> Lock(EPCUIMutex);
358 if (NumStubs > AvailableIndirectStubs.size()) {
359 auto NumStubsToAllocate = NumStubs;
361 auto StubBytes =
alignTo(NumStubsToAllocate * ABI->getStubSize(),
PageSize);
362 NumStubsToAllocate = StubBytes / ABI->getStubSize();
369 auto Alloc = SimpleSegmentAlloc::Create(
371 {{StubProt, {static_cast<size_t>(StubBytes), Align(PageSize)}},
372 {PtrProt, {static_cast<size_t>(PtrBytes), Align(PageSize)}}});
375 return Alloc.takeError();
377 auto StubSeg =
Alloc->getSegInfo(StubProt);
378 auto PtrSeg =
Alloc->getSegInfo(PtrProt);
380 ABI->writeIndirectStubsBlock(StubSeg.WorkingMem.data(),
381 StubSeg.Addr.getValue(),
382 PtrSeg.Addr.getValue(), NumStubsToAllocate);
384 auto FA =
Alloc->finalize();
386 return FA.takeError();
388 IndirectStubAllocs.push_back(std::move(*FA));
390 auto StubExecutorAddr = StubSeg.Addr;
391 auto PtrExecutorAddr = PtrSeg.Addr;
392 for (
unsigned I = 0;
I != NumStubsToAllocate; ++
I) {
393 AvailableIndirectStubs.push_back(IndirectStubInfo(
394 StubExecutorAddr.getValue(), PtrExecutorAddr.getValue()));
395 StubExecutorAddr +=
ABI->getStubSize();
396 PtrExecutorAddr +=
ABI->getPointerSize();
400 assert(NumStubs <= AvailableIndirectStubs.size() &&
401 "Sufficient stubs should have been allocated above");
403 IndirectStubInfoVector
Result;
405 Result.push_back(AvailableIndirectStubs.back());
406 AvailableIndirectStubs.pop_back();
414 auto &LCTM = *jitTargetAddressToPointer<LazyCallThroughManager *>(LCTMAddr);
415 std::promise<JITTargetAddress> LandingAddrP;
416 auto LandingAddrF = LandingAddrP.get_future();
417 LCTM.resolveTrampolineLandingAddress(
420 return LandingAddrF.get();
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static cl::opt< int > PageSize("imp-null-check-page-size", cl::desc("The page size of the target in bytes"), cl::init(4096), cl::Hidden)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Represents a symbol that has been evaluated to an address already.
Flags for symbols in the JIT.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
StringRef - Represent a constant reference to a string, i.e.
Represents a finalized allocation.
virtual void deallocate(std::vector< FinalizedAlloc > Allocs, OnDeallocatedFunction OnDeallocated)=0
Deallocate a list of allocation objects.
EPCIndirectionUtils::IndirectStubInfo IndirectStubInfo
static Expected< IndirectStubInfoVector > getIndirectStubs(EPCIndirectionUtils &EPCIU, unsigned NumStubs)
EPCIndirectionUtils::IndirectStubInfoVector IndirectStubInfoVector
virtual void writeTrampolines(char *TrampolineBlockWorkingMem, JITTargetAddress TrampolineBlockTragetAddr, JITTargetAddress ResolverAddr, unsigned NumTrampolines) const =0
unsigned getPointerSize() const
Provides ExecutorProcessControl based indirect stubs, trampoline pool and lazy call through manager.
std::unique_ptr< IndirectStubsManager > createIndirectStubsManager()
Create an IndirectStubsManager for the executor process.
LazyCallThroughManager & getLazyCallThroughManager()
Create a LazyCallThroughManager for the executor process.
ExecutorProcessControl & getExecutorProcessControl() const
Return a reference to the ExecutorProcessControl object.
LazyCallThroughManager & createLazyCallThroughManager(ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr)
Create a LazyCallThroughManager.
Error cleanup()
Release memory for resources held by this instance.
Expected< JITTargetAddress > writeResolverBlock(JITTargetAddress ReentryFnAddr, JITTargetAddress ReentryCtxAddr)
Write resolver code to the executor process and return its address.
TrampolinePool & getTrampolinePool()
Create a TrampolinePool for the executor process.
static Expected< std::unique_ptr< EPCIndirectionUtils > > Create(ExecutorProcessControl &EPC)
Create based on the ExecutorProcessControl triple.
ABISupport & getABISupport() const
Return a reference to the ABISupport object for this instance.
JITTargetAddress getResolverBlockAddress() const
Returns the address of the Resolver block.
An ExecutionSession represents a running JIT program.
Represents an address in the executor process.
ExecutorProcessControl supports interaction with a JIT target process.
jitlink::JITLinkMemoryManager & getMemMgr() const
Return a JITLinkMemoryManager for the target process.
const Triple & getTargetTriple() const
Return the Triple for the target process.
unsigned getPageSize() const
Get the page size for the target process.
MemoryAccess & getMemoryAccess() const
Return a MemoryAccess object for the target process.
Base class for managing collections of named indirect stubs.
virtual Error updatePointer(StringRef Name, JITTargetAddress NewAddr)=0
Change the value of the implementation pointer for the stub.
virtual JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly)=0
Find the stub with the given name.
virtual JITEvaluatedSymbol findPointer(StringRef Name)=0
Find the implementation-pointer for the stub.
virtual Error createStub(StringRef StubName, JITTargetAddress StubAddr, JITSymbolFlags StubFlags)=0
Create a single stub with the given name, target address and flags.
virtual Error createStubs(const StubInitsMap &StubInits)=0
Create StubInits.size() stubs with the given names, target addresses, and flags.
Manages a set of 'lazy call-through' trampolines.
Base class for pools of compiler re-entry trampolines.
Error setUpInProcessLCTMReentryViaEPCIU(EPCIndirectionUtils &EPCIU)
This will call writeResolver on the given EPCIndirectionUtils instance to set up re-entry via a funct...
static JITTargetAddress reentry(JITTargetAddress LCTMAddr, JITTargetAddress TrampolineAddr)
This is an optimization pass for GlobalISel generic memory operations.
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
uint64_t JITTargetAddress
Represents an address in the target process's address space.
Error joinErrors(Error E1, Error E2)
Concatenate errors.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
JITTargetAddress pointerToJITTargetAddress(T *Ptr)
Convert a pointer to a JITTargetAddress.