File indexing completed on 2026-05-10 08:43:53
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
0014 #define LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
0015
0016 #include "llvm/ADT/StringMap.h"
0017 #include "llvm/ADT/StringRef.h"
0018 #include "llvm/ExecutionEngine/JITSymbol.h"
0019 #include "llvm/ExecutionEngine/Orc/Core.h"
0020 #include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
0021 #include "llvm/ExecutionEngine/Orc/RedirectionManager.h"
0022 #include "llvm/Support/Error.h"
0023 #include "llvm/Support/Memory.h"
0024 #include "llvm/Support/Process.h"
0025 #include "llvm/Transforms/Utils/ValueMapper.h"
0026 #include <algorithm>
0027 #include <cassert>
0028 #include <cstdint>
0029 #include <functional>
0030 #include <future>
0031 #include <map>
0032 #include <memory>
0033 #include <system_error>
0034 #include <utility>
0035 #include <vector>
0036
0037 namespace llvm {
0038
0039 class Constant;
0040 class Function;
0041 class FunctionType;
0042 class GlobalAlias;
0043 class GlobalVariable;
0044 class Module;
0045 class PointerType;
0046 class Triple;
0047 class Twine;
0048 class Value;
0049 class MCDisassembler;
0050 class MCInstrAnalysis;
0051
0052 namespace jitlink {
0053 class LinkGraph;
0054 class Symbol;
0055 }
0056
0057 namespace orc {
0058
0059
0060
0061
0062
0063
0064 class TrampolinePool {
0065 public:
0066 using NotifyLandingResolvedFunction =
0067 unique_function<void(ExecutorAddr) const>;
0068
0069 using ResolveLandingFunction = unique_function<void(
0070 ExecutorAddr TrampolineAddr,
0071 NotifyLandingResolvedFunction OnLandingResolved) const>;
0072
0073 virtual ~TrampolinePool();
0074
0075
0076
0077 Expected<ExecutorAddr> getTrampoline() {
0078 std::lock_guard<std::mutex> Lock(TPMutex);
0079 if (AvailableTrampolines.empty()) {
0080 if (auto Err = grow())
0081 return std::move(Err);
0082 }
0083 assert(!AvailableTrampolines.empty() && "Failed to grow trampoline pool");
0084 auto TrampolineAddr = AvailableTrampolines.back();
0085 AvailableTrampolines.pop_back();
0086 return TrampolineAddr;
0087 }
0088
0089
0090 void releaseTrampoline(ExecutorAddr TrampolineAddr) {
0091 std::lock_guard<std::mutex> Lock(TPMutex);
0092 AvailableTrampolines.push_back(TrampolineAddr);
0093 }
0094
0095 protected:
0096 virtual Error grow() = 0;
0097
0098 std::mutex TPMutex;
0099 std::vector<ExecutorAddr> AvailableTrampolines;
0100 };
0101
0102
0103 template <typename ORCABI> class LocalTrampolinePool : public TrampolinePool {
0104 public:
0105
0106
0107
0108 static Expected<std::unique_ptr<LocalTrampolinePool>>
0109 Create(ResolveLandingFunction ResolveLanding) {
0110 Error Err = Error::success();
0111
0112 auto LTP = std::unique_ptr<LocalTrampolinePool>(
0113 new LocalTrampolinePool(std::move(ResolveLanding), Err));
0114
0115 if (Err)
0116 return std::move(Err);
0117 return std::move(LTP);
0118 }
0119
0120 private:
0121 static JITTargetAddress reenter(void *TrampolinePoolPtr, void *TrampolineId) {
0122 LocalTrampolinePool<ORCABI> *TrampolinePool =
0123 static_cast<LocalTrampolinePool *>(TrampolinePoolPtr);
0124
0125 std::promise<ExecutorAddr> LandingAddressP;
0126 auto LandingAddressF = LandingAddressP.get_future();
0127
0128 TrampolinePool->ResolveLanding(ExecutorAddr::fromPtr(TrampolineId),
0129 [&](ExecutorAddr LandingAddress) {
0130 LandingAddressP.set_value(LandingAddress);
0131 });
0132 return LandingAddressF.get().getValue();
0133 }
0134
0135 LocalTrampolinePool(ResolveLandingFunction ResolveLanding, Error &Err)
0136 : ResolveLanding(std::move(ResolveLanding)) {
0137
0138 ErrorAsOutParameter _(Err);
0139
0140
0141 std::error_code EC;
0142 ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
0143 ORCABI::ResolverCodeSize, nullptr,
0144 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
0145 if (EC) {
0146 Err = errorCodeToError(EC);
0147 return;
0148 }
0149
0150 ORCABI::writeResolverCode(static_cast<char *>(ResolverBlock.base()),
0151 ExecutorAddr::fromPtr(ResolverBlock.base()),
0152 ExecutorAddr::fromPtr(&reenter),
0153 ExecutorAddr::fromPtr(this));
0154
0155 EC = sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(),
0156 sys::Memory::MF_READ |
0157 sys::Memory::MF_EXEC);
0158 if (EC) {
0159 Err = errorCodeToError(EC);
0160 return;
0161 }
0162 }
0163
0164 Error grow() override {
0165 assert(AvailableTrampolines.empty() && "Growing prematurely?");
0166
0167 std::error_code EC;
0168 auto TrampolineBlock =
0169 sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
0170 sys::Process::getPageSizeEstimate(), nullptr,
0171 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
0172 if (EC)
0173 return errorCodeToError(EC);
0174
0175 unsigned NumTrampolines =
0176 (sys::Process::getPageSizeEstimate() - ORCABI::PointerSize) /
0177 ORCABI::TrampolineSize;
0178
0179 char *TrampolineMem = static_cast<char *>(TrampolineBlock.base());
0180 ORCABI::writeTrampolines(
0181 TrampolineMem, ExecutorAddr::fromPtr(TrampolineMem),
0182 ExecutorAddr::fromPtr(ResolverBlock.base()), NumTrampolines);
0183
0184 for (unsigned I = 0; I < NumTrampolines; ++I)
0185 AvailableTrampolines.push_back(
0186 ExecutorAddr::fromPtr(TrampolineMem + (I * ORCABI::TrampolineSize)));
0187
0188 if (auto EC = sys::Memory::protectMappedMemory(
0189 TrampolineBlock.getMemoryBlock(),
0190 sys::Memory::MF_READ | sys::Memory::MF_EXEC))
0191 return errorCodeToError(EC);
0192
0193 TrampolineBlocks.push_back(std::move(TrampolineBlock));
0194 return Error::success();
0195 }
0196
0197 ResolveLandingFunction ResolveLanding;
0198
0199 sys::OwningMemoryBlock ResolverBlock;
0200 std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
0201 };
0202
0203
0204 class JITCompileCallbackManager {
0205 public:
0206 using CompileFunction = std::function<ExecutorAddr()>;
0207
0208 virtual ~JITCompileCallbackManager() = default;
0209
0210
0211 Expected<ExecutorAddr> getCompileCallback(CompileFunction Compile);
0212
0213
0214
0215 ExecutorAddr executeCompileCallback(ExecutorAddr TrampolineAddr);
0216
0217 protected:
0218
0219 JITCompileCallbackManager(std::unique_ptr<TrampolinePool> TP,
0220 ExecutionSession &ES,
0221 ExecutorAddr ErrorHandlerAddress)
0222 : TP(std::move(TP)), ES(ES),
0223 CallbacksJD(ES.createBareJITDylib("<Callbacks>")),
0224 ErrorHandlerAddress(ErrorHandlerAddress) {}
0225
0226 void setTrampolinePool(std::unique_ptr<TrampolinePool> TP) {
0227 this->TP = std::move(TP);
0228 }
0229
0230 private:
0231 std::mutex CCMgrMutex;
0232 std::unique_ptr<TrampolinePool> TP;
0233 ExecutionSession &ES;
0234 JITDylib &CallbacksJD;
0235 ExecutorAddr ErrorHandlerAddress;
0236 std::map<ExecutorAddr, SymbolStringPtr> AddrToSymbol;
0237 size_t NextCallbackId = 0;
0238 };
0239
0240
0241 template <typename ORCABI>
0242 class LocalJITCompileCallbackManager : public JITCompileCallbackManager {
0243 public:
0244
0245 static Expected<std::unique_ptr<LocalJITCompileCallbackManager>>
0246 Create(ExecutionSession &ES, ExecutorAddr ErrorHandlerAddress) {
0247 Error Err = Error::success();
0248 auto CCMgr = std::unique_ptr<LocalJITCompileCallbackManager>(
0249 new LocalJITCompileCallbackManager(ES, ErrorHandlerAddress, Err));
0250 if (Err)
0251 return std::move(Err);
0252 return std::move(CCMgr);
0253 }
0254
0255 private:
0256
0257
0258
0259 LocalJITCompileCallbackManager(ExecutionSession &ES,
0260 ExecutorAddr ErrorHandlerAddress, Error &Err)
0261 : JITCompileCallbackManager(nullptr, ES, ErrorHandlerAddress) {
0262 using NotifyLandingResolvedFunction =
0263 TrampolinePool::NotifyLandingResolvedFunction;
0264
0265 ErrorAsOutParameter _(Err);
0266 auto TP = LocalTrampolinePool<ORCABI>::Create(
0267 [this](ExecutorAddr TrampolineAddr,
0268 NotifyLandingResolvedFunction NotifyLandingResolved) {
0269 NotifyLandingResolved(executeCompileCallback(TrampolineAddr));
0270 });
0271
0272 if (!TP) {
0273 Err = TP.takeError();
0274 return;
0275 }
0276
0277 setTrampolinePool(std::move(*TP));
0278 }
0279 };
0280
0281
0282 class IndirectStubsManager : public RedirectableSymbolManager {
0283 public:
0284
0285 using StubInitsMap = StringMap<std::pair<ExecutorAddr, JITSymbolFlags>>;
0286
0287 virtual ~IndirectStubsManager() = default;
0288
0289
0290 virtual Error createStub(StringRef StubName, ExecutorAddr StubAddr,
0291 JITSymbolFlags StubFlags) = 0;
0292
0293
0294
0295 virtual Error createStubs(const StubInitsMap &StubInits) = 0;
0296
0297
0298
0299
0300 virtual ExecutorSymbolDef findStub(StringRef Name,
0301 bool ExportedStubsOnly) = 0;
0302
0303
0304 virtual ExecutorSymbolDef findPointer(StringRef Name) = 0;
0305
0306
0307 virtual Error updatePointer(StringRef Name, ExecutorAddr NewAddr) = 0;
0308
0309
0310 Error redirect(JITDylib &JD, const SymbolMap &NewDests) override;
0311
0312 void
0313 emitRedirectableSymbols(std::unique_ptr<MaterializationResponsibility> MR,
0314 SymbolMap InitialDests) override;
0315
0316 private:
0317 void anchor() override;
0318 };
0319
0320 template <typename ORCABI> class LocalIndirectStubsInfo {
0321 public:
0322 LocalIndirectStubsInfo(unsigned NumStubs, sys::OwningMemoryBlock StubsMem)
0323 : NumStubs(NumStubs), StubsMem(std::move(StubsMem)) {}
0324
0325 static Expected<LocalIndirectStubsInfo> create(unsigned MinStubs,
0326 unsigned PageSize) {
0327 auto ISAS = getIndirectStubsBlockSizes<ORCABI>(MinStubs, PageSize);
0328
0329 assert((ISAS.StubBytes % PageSize == 0) &&
0330 "StubBytes is not a page size multiple");
0331 uint64_t PointerAlloc = alignTo(ISAS.PointerBytes, PageSize);
0332
0333
0334 std::error_code EC;
0335 auto StubsAndPtrsMem =
0336 sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
0337 ISAS.StubBytes + PointerAlloc, nullptr,
0338 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
0339 if (EC)
0340 return errorCodeToError(EC);
0341
0342 sys::MemoryBlock StubsBlock(StubsAndPtrsMem.base(), ISAS.StubBytes);
0343 auto StubsBlockMem = static_cast<char *>(StubsAndPtrsMem.base());
0344 auto PtrBlockAddress =
0345 ExecutorAddr::fromPtr(StubsBlockMem) + ISAS.StubBytes;
0346
0347 ORCABI::writeIndirectStubsBlock(StubsBlockMem,
0348 ExecutorAddr::fromPtr(StubsBlockMem),
0349 PtrBlockAddress, ISAS.NumStubs);
0350
0351 if (auto EC = sys::Memory::protectMappedMemory(
0352 StubsBlock, sys::Memory::MF_READ | sys::Memory::MF_EXEC))
0353 return errorCodeToError(EC);
0354
0355 return LocalIndirectStubsInfo(ISAS.NumStubs, std::move(StubsAndPtrsMem));
0356 }
0357
0358 unsigned getNumStubs() const { return NumStubs; }
0359
0360 void *getStub(unsigned Idx) const {
0361 return static_cast<char *>(StubsMem.base()) + Idx * ORCABI::StubSize;
0362 }
0363
0364 void **getPtr(unsigned Idx) const {
0365 char *PtrsBase =
0366 static_cast<char *>(StubsMem.base()) + NumStubs * ORCABI::StubSize;
0367 return reinterpret_cast<void **>(PtrsBase) + Idx;
0368 }
0369
0370 private:
0371 unsigned NumStubs = 0;
0372 sys::OwningMemoryBlock StubsMem;
0373 };
0374
0375
0376
0377 template <typename TargetT>
0378 class LocalIndirectStubsManager : public IndirectStubsManager {
0379 public:
0380 Error createStub(StringRef StubName, ExecutorAddr StubAddr,
0381 JITSymbolFlags StubFlags) override {
0382 std::lock_guard<std::mutex> Lock(StubsMutex);
0383 if (auto Err = reserveStubs(1))
0384 return Err;
0385
0386 createStubInternal(StubName, StubAddr, StubFlags);
0387
0388 return Error::success();
0389 }
0390
0391 Error createStubs(const StubInitsMap &StubInits) override {
0392 std::lock_guard<std::mutex> Lock(StubsMutex);
0393 if (auto Err = reserveStubs(StubInits.size()))
0394 return Err;
0395
0396 for (const auto &Entry : StubInits)
0397 createStubInternal(Entry.first(), Entry.second.first,
0398 Entry.second.second);
0399
0400 return Error::success();
0401 }
0402
0403 ExecutorSymbolDef findStub(StringRef Name, bool ExportedStubsOnly) override {
0404 std::lock_guard<std::mutex> Lock(StubsMutex);
0405 auto I = StubIndexes.find(Name);
0406 if (I == StubIndexes.end())
0407 return ExecutorSymbolDef();
0408 auto Key = I->second.first;
0409 void *StubPtr = IndirectStubsInfos[Key.first].getStub(Key.second);
0410 assert(StubPtr && "Missing stub address");
0411 auto StubAddr = ExecutorAddr::fromPtr(StubPtr);
0412 auto StubSymbol = ExecutorSymbolDef(StubAddr, I->second.second);
0413 if (ExportedStubsOnly && !StubSymbol.getFlags().isExported())
0414 return ExecutorSymbolDef();
0415 return StubSymbol;
0416 }
0417
0418 ExecutorSymbolDef findPointer(StringRef Name) override {
0419 std::lock_guard<std::mutex> Lock(StubsMutex);
0420 auto I = StubIndexes.find(Name);
0421 if (I == StubIndexes.end())
0422 return ExecutorSymbolDef();
0423 auto Key = I->second.first;
0424 void *PtrPtr = IndirectStubsInfos[Key.first].getPtr(Key.second);
0425 assert(PtrPtr && "Missing pointer address");
0426 auto PtrAddr = ExecutorAddr::fromPtr(PtrPtr);
0427 return ExecutorSymbolDef(PtrAddr, I->second.second);
0428 }
0429
0430 Error updatePointer(StringRef Name, ExecutorAddr NewAddr) override {
0431 using AtomicIntPtr = std::atomic<uintptr_t>;
0432
0433 std::lock_guard<std::mutex> Lock(StubsMutex);
0434 auto I = StubIndexes.find(Name);
0435 assert(I != StubIndexes.end() && "No stub pointer for symbol");
0436 auto Key = I->second.first;
0437 AtomicIntPtr *AtomicStubPtr = reinterpret_cast<AtomicIntPtr *>(
0438 IndirectStubsInfos[Key.first].getPtr(Key.second));
0439 *AtomicStubPtr = static_cast<uintptr_t>(NewAddr.getValue());
0440 return Error::success();
0441 }
0442
0443 private:
0444 Error reserveStubs(unsigned NumStubs) {
0445 if (NumStubs <= FreeStubs.size())
0446 return Error::success();
0447
0448 unsigned NewStubsRequired = NumStubs - FreeStubs.size();
0449 unsigned NewBlockId = IndirectStubsInfos.size();
0450 auto ISI =
0451 LocalIndirectStubsInfo<TargetT>::create(NewStubsRequired, PageSize);
0452 if (!ISI)
0453 return ISI.takeError();
0454 for (unsigned I = 0; I < ISI->getNumStubs(); ++I)
0455 FreeStubs.push_back(std::make_pair(NewBlockId, I));
0456 IndirectStubsInfos.push_back(std::move(*ISI));
0457 return Error::success();
0458 }
0459
0460 void createStubInternal(StringRef StubName, ExecutorAddr InitAddr,
0461 JITSymbolFlags StubFlags) {
0462 auto Key = FreeStubs.back();
0463 FreeStubs.pop_back();
0464 *IndirectStubsInfos[Key.first].getPtr(Key.second) =
0465 InitAddr.toPtr<void *>();
0466 StubIndexes[StubName] = std::make_pair(Key, StubFlags);
0467 }
0468
0469 unsigned PageSize = sys::Process::getPageSizeEstimate();
0470 std::mutex StubsMutex;
0471 std::vector<LocalIndirectStubsInfo<TargetT>> IndirectStubsInfos;
0472 using StubKey = std::pair<uint16_t, uint16_t>;
0473 std::vector<StubKey> FreeStubs;
0474 StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
0475 };
0476
0477
0478
0479
0480
0481
0482 Expected<std::unique_ptr<JITCompileCallbackManager>>
0483 createLocalCompileCallbackManager(const Triple &T, ExecutionSession &ES,
0484 ExecutorAddr ErrorHandlerAddress);
0485
0486
0487
0488
0489 std::function<std::unique_ptr<IndirectStubsManager>()>
0490 createLocalIndirectStubsManagerBuilder(const Triple &T);
0491
0492
0493
0494
0495
0496
0497 Constant *createIRTypedAddress(FunctionType &FT, ExecutorAddr Addr);
0498
0499
0500
0501 GlobalVariable *createImplPointer(PointerType &PT, Module &M, const Twine &Name,
0502 Constant *Initializer);
0503
0504
0505
0506 void makeStub(Function &F, Value &ImplPointer);
0507
0508
0509
0510
0511 class SymbolLinkagePromoter {
0512 public:
0513
0514
0515 std::vector<GlobalValue *> operator()(Module &M);
0516
0517 private:
0518 unsigned NextId = 0;
0519 };
0520
0521
0522
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532
0533 Function *cloneFunctionDecl(Module &Dst, const Function &F,
0534 ValueToValueMapTy *VMap = nullptr);
0535
0536
0537 GlobalVariable *cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV,
0538 ValueToValueMapTy *VMap = nullptr);
0539
0540
0541 GlobalAlias *cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA,
0542 ValueToValueMapTy &VMap);
0543
0544
0545
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566 Error addFunctionPointerRelocationsToCurrentSymbol(jitlink::Symbol &Sym,
0567 jitlink::LinkGraph &G,
0568 MCDisassembler &Disassembler,
0569 MCInstrAnalysis &MIA);
0570
0571 }
0572
0573 }
0574
0575 #endif