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> 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: 57fe6060f1SDimitry Andric EPCIndirectStubsManager(EPCIndirectionUtils &EPCIU) : EPCIU(EPCIU) {} 58fe6060f1SDimitry Andric 59fe6060f1SDimitry Andric Error deallocateStubs(); 60fe6060f1SDimitry Andric 61fe6060f1SDimitry Andric Error createStub(StringRef StubName, JITTargetAddress StubAddr, 62fe6060f1SDimitry Andric JITSymbolFlags StubFlags) override; 63fe6060f1SDimitry Andric 64fe6060f1SDimitry Andric Error createStubs(const StubInitsMap &StubInits) override; 65fe6060f1SDimitry Andric 66fe6060f1SDimitry Andric JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override; 67fe6060f1SDimitry Andric 68fe6060f1SDimitry Andric JITEvaluatedSymbol findPointer(StringRef Name) override; 69fe6060f1SDimitry Andric 70fe6060f1SDimitry Andric Error updatePointer(StringRef Name, JITTargetAddress 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 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 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 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); 12104eeddc0SDimitry Andric EPCIU.getABISupport().writeTrampolines(SegInfo.WorkingMem.data(), 12204eeddc0SDimitry Andric SegInfo.Addr.getValue(), 12304eeddc0SDimitry Andric ResolverAddress, NumTrampolines); 124fe6060f1SDimitry Andric for (unsigned I = 0; I < NumTrampolines; ++I) 12504eeddc0SDimitry Andric AvailableTrampolines.push_back(SegInfo.Addr.getValue() + 12604eeddc0SDimitry Andric (I * TrampolineSize)); 127fe6060f1SDimitry Andric 128349cc55cSDimitry Andric auto FA = Alloc->finalize(); 129349cc55cSDimitry Andric if (!FA) 130349cc55cSDimitry Andric return FA.takeError(); 131fe6060f1SDimitry Andric 132349cc55cSDimitry Andric TrampolineBlocks.push_back(std::move(*FA)); 133fe6060f1SDimitry Andric 134fe6060f1SDimitry Andric return Error::success(); 135fe6060f1SDimitry Andric } 136fe6060f1SDimitry Andric 137fe6060f1SDimitry Andric Error EPCIndirectStubsManager::createStub(StringRef StubName, 138fe6060f1SDimitry Andric JITTargetAddress StubAddr, 139fe6060f1SDimitry Andric JITSymbolFlags StubFlags) { 140fe6060f1SDimitry Andric StubInitsMap SIM; 141fe6060f1SDimitry Andric SIM[StubName] = std::make_pair(StubAddr, StubFlags); 142fe6060f1SDimitry Andric return createStubs(SIM); 143fe6060f1SDimitry Andric } 144fe6060f1SDimitry Andric 145fe6060f1SDimitry Andric Error EPCIndirectStubsManager::createStubs(const StubInitsMap &StubInits) { 146fe6060f1SDimitry Andric auto AvailableStubInfos = getIndirectStubs(EPCIU, StubInits.size()); 147fe6060f1SDimitry Andric if (!AvailableStubInfos) 148fe6060f1SDimitry Andric return AvailableStubInfos.takeError(); 149fe6060f1SDimitry Andric 150fe6060f1SDimitry Andric { 151fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(ISMMutex); 152fe6060f1SDimitry Andric unsigned ASIdx = 0; 153fe6060f1SDimitry Andric for (auto &SI : StubInits) { 154fe6060f1SDimitry Andric auto &A = (*AvailableStubInfos)[ASIdx++]; 155fe6060f1SDimitry Andric StubInfos[SI.first()] = std::make_pair(A, SI.second.second); 156fe6060f1SDimitry Andric } 157fe6060f1SDimitry Andric } 158fe6060f1SDimitry Andric 159fe6060f1SDimitry Andric auto &MemAccess = EPCIU.getExecutorProcessControl().getMemoryAccess(); 160fe6060f1SDimitry Andric switch (EPCIU.getABISupport().getPointerSize()) { 161fe6060f1SDimitry Andric case 4: { 162fe6060f1SDimitry Andric unsigned ASIdx = 0; 163fe6060f1SDimitry Andric std::vector<tpctypes::UInt32Write> PtrUpdates; 164fe6060f1SDimitry Andric for (auto &SI : StubInits) 165349cc55cSDimitry Andric PtrUpdates.push_back( 166349cc55cSDimitry Andric {ExecutorAddr((*AvailableStubInfos)[ASIdx++].PointerAddress), 167fe6060f1SDimitry Andric static_cast<uint32_t>(SI.second.first)}); 168fe6060f1SDimitry Andric return MemAccess.writeUInt32s(PtrUpdates); 169fe6060f1SDimitry Andric } 170fe6060f1SDimitry Andric case 8: { 171fe6060f1SDimitry Andric unsigned ASIdx = 0; 172fe6060f1SDimitry Andric std::vector<tpctypes::UInt64Write> PtrUpdates; 173fe6060f1SDimitry Andric for (auto &SI : StubInits) 174349cc55cSDimitry Andric PtrUpdates.push_back( 175349cc55cSDimitry Andric {ExecutorAddr((*AvailableStubInfos)[ASIdx++].PointerAddress), 176fe6060f1SDimitry Andric static_cast<uint64_t>(SI.second.first)}); 177fe6060f1SDimitry Andric return MemAccess.writeUInt64s(PtrUpdates); 178fe6060f1SDimitry Andric } 179fe6060f1SDimitry Andric default: 180fe6060f1SDimitry Andric return make_error<StringError>("Unsupported pointer size", 181fe6060f1SDimitry Andric inconvertibleErrorCode()); 182fe6060f1SDimitry Andric } 183fe6060f1SDimitry Andric } 184fe6060f1SDimitry Andric 185fe6060f1SDimitry Andric JITEvaluatedSymbol EPCIndirectStubsManager::findStub(StringRef Name, 186fe6060f1SDimitry Andric bool ExportedStubsOnly) { 187fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(ISMMutex); 188fe6060f1SDimitry Andric auto I = StubInfos.find(Name); 189fe6060f1SDimitry Andric if (I == StubInfos.end()) 190fe6060f1SDimitry Andric return nullptr; 191fe6060f1SDimitry Andric return {I->second.first.StubAddress, I->second.second}; 192fe6060f1SDimitry Andric } 193fe6060f1SDimitry Andric 194fe6060f1SDimitry Andric JITEvaluatedSymbol EPCIndirectStubsManager::findPointer(StringRef Name) { 195fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(ISMMutex); 196fe6060f1SDimitry Andric auto I = StubInfos.find(Name); 197fe6060f1SDimitry Andric if (I == StubInfos.end()) 198fe6060f1SDimitry Andric return nullptr; 199fe6060f1SDimitry Andric return {I->second.first.PointerAddress, I->second.second}; 200fe6060f1SDimitry Andric } 201fe6060f1SDimitry Andric 202fe6060f1SDimitry Andric Error EPCIndirectStubsManager::updatePointer(StringRef Name, 203fe6060f1SDimitry Andric JITTargetAddress NewAddr) { 204fe6060f1SDimitry Andric 205fe6060f1SDimitry Andric JITTargetAddress PtrAddr = 0; 206fe6060f1SDimitry Andric { 207fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(ISMMutex); 208fe6060f1SDimitry Andric auto I = StubInfos.find(Name); 209fe6060f1SDimitry Andric if (I == StubInfos.end()) 210fe6060f1SDimitry Andric return make_error<StringError>("Unknown stub name", 211fe6060f1SDimitry Andric inconvertibleErrorCode()); 212fe6060f1SDimitry Andric PtrAddr = I->second.first.PointerAddress; 213fe6060f1SDimitry Andric } 214fe6060f1SDimitry Andric 215fe6060f1SDimitry Andric auto &MemAccess = EPCIU.getExecutorProcessControl().getMemoryAccess(); 216fe6060f1SDimitry Andric switch (EPCIU.getABISupport().getPointerSize()) { 217fe6060f1SDimitry Andric case 4: { 218349cc55cSDimitry Andric tpctypes::UInt32Write PUpdate(ExecutorAddr(PtrAddr), NewAddr); 219fe6060f1SDimitry Andric return MemAccess.writeUInt32s(PUpdate); 220fe6060f1SDimitry Andric } 221fe6060f1SDimitry Andric case 8: { 222349cc55cSDimitry Andric tpctypes::UInt64Write PUpdate(ExecutorAddr(PtrAddr), NewAddr); 223fe6060f1SDimitry Andric return MemAccess.writeUInt64s(PUpdate); 224fe6060f1SDimitry Andric } 225fe6060f1SDimitry Andric default: 226fe6060f1SDimitry Andric return make_error<StringError>("Unsupported pointer size", 227fe6060f1SDimitry Andric inconvertibleErrorCode()); 228fe6060f1SDimitry Andric } 229fe6060f1SDimitry Andric } 230fe6060f1SDimitry Andric 231fe6060f1SDimitry Andric } // end anonymous namespace. 232fe6060f1SDimitry Andric 233fe6060f1SDimitry Andric namespace llvm { 234fe6060f1SDimitry Andric namespace orc { 235fe6060f1SDimitry Andric 23681ad6265SDimitry Andric EPCIndirectionUtils::ABISupport::~ABISupport() = default; 237fe6060f1SDimitry Andric 238fe6060f1SDimitry Andric Expected<std::unique_ptr<EPCIndirectionUtils>> 239fe6060f1SDimitry Andric EPCIndirectionUtils::Create(ExecutorProcessControl &EPC) { 240fe6060f1SDimitry Andric const auto &TT = EPC.getTargetTriple(); 241fe6060f1SDimitry Andric switch (TT.getArch()) { 242fe6060f1SDimitry Andric default: 243fe6060f1SDimitry Andric return make_error<StringError>( 244fe6060f1SDimitry Andric std::string("No EPCIndirectionUtils available for ") + TT.str(), 245fe6060f1SDimitry Andric inconvertibleErrorCode()); 246fe6060f1SDimitry Andric case Triple::aarch64: 247fe6060f1SDimitry Andric case Triple::aarch64_32: 248fe6060f1SDimitry Andric return CreateWithABI<OrcAArch64>(EPC); 249fe6060f1SDimitry Andric 250fe6060f1SDimitry Andric case Triple::x86: 251fe6060f1SDimitry Andric return CreateWithABI<OrcI386>(EPC); 252fe6060f1SDimitry Andric 253*bdd1243dSDimitry Andric case Triple::loongarch64: 254*bdd1243dSDimitry Andric return CreateWithABI<OrcLoongArch64>(EPC); 255*bdd1243dSDimitry Andric 256fe6060f1SDimitry Andric case Triple::mips: 257fe6060f1SDimitry Andric return CreateWithABI<OrcMips32Be>(EPC); 258fe6060f1SDimitry Andric 259fe6060f1SDimitry Andric case Triple::mipsel: 260fe6060f1SDimitry Andric return CreateWithABI<OrcMips32Le>(EPC); 261fe6060f1SDimitry Andric 262fe6060f1SDimitry Andric case Triple::mips64: 263fe6060f1SDimitry Andric case Triple::mips64el: 264fe6060f1SDimitry Andric return CreateWithABI<OrcMips64>(EPC); 265fe6060f1SDimitry Andric 26681ad6265SDimitry Andric case Triple::riscv64: 26781ad6265SDimitry Andric return CreateWithABI<OrcRiscv64>(EPC); 26881ad6265SDimitry Andric 269fe6060f1SDimitry Andric case Triple::x86_64: 270fe6060f1SDimitry Andric if (TT.getOS() == Triple::OSType::Win32) 271fe6060f1SDimitry Andric return CreateWithABI<OrcX86_64_Win32>(EPC); 272fe6060f1SDimitry Andric else 273fe6060f1SDimitry Andric return CreateWithABI<OrcX86_64_SysV>(EPC); 274fe6060f1SDimitry Andric } 275fe6060f1SDimitry Andric } 276fe6060f1SDimitry Andric 277fe6060f1SDimitry Andric Error EPCIndirectionUtils::cleanup() { 278fe6060f1SDimitry Andric 279349cc55cSDimitry Andric auto &MemMgr = EPC.getMemMgr(); 280349cc55cSDimitry Andric auto Err = MemMgr.deallocate(std::move(IndirectStubAllocs)); 281fe6060f1SDimitry Andric 282fe6060f1SDimitry Andric if (TP) 283fe6060f1SDimitry Andric Err = joinErrors(std::move(Err), 284fe6060f1SDimitry Andric static_cast<EPCTrampolinePool &>(*TP).deallocatePool()); 285fe6060f1SDimitry Andric 286fe6060f1SDimitry Andric if (ResolverBlock) 287349cc55cSDimitry Andric Err = 288349cc55cSDimitry Andric joinErrors(std::move(Err), MemMgr.deallocate(std::move(ResolverBlock))); 289fe6060f1SDimitry Andric 290fe6060f1SDimitry Andric return Err; 291fe6060f1SDimitry Andric } 292fe6060f1SDimitry Andric 293fe6060f1SDimitry Andric Expected<JITTargetAddress> 294fe6060f1SDimitry Andric EPCIndirectionUtils::writeResolverBlock(JITTargetAddress ReentryFnAddr, 295fe6060f1SDimitry Andric JITTargetAddress ReentryCtxAddr) { 296349cc55cSDimitry Andric using namespace jitlink; 297349cc55cSDimitry Andric 298fe6060f1SDimitry Andric assert(ABI && "ABI can not be null"); 299fe6060f1SDimitry Andric auto ResolverSize = ABI->getResolverCodeSize(); 300fe6060f1SDimitry Andric 301349cc55cSDimitry Andric auto Alloc = 302349cc55cSDimitry Andric SimpleSegmentAlloc::Create(EPC.getMemMgr(), nullptr, 303349cc55cSDimitry Andric {{MemProt::Read | MemProt::Exec, 304349cc55cSDimitry Andric {ResolverSize, Align(EPC.getPageSize())}}}); 305349cc55cSDimitry Andric 306fe6060f1SDimitry Andric if (!Alloc) 307fe6060f1SDimitry Andric return Alloc.takeError(); 308fe6060f1SDimitry Andric 309349cc55cSDimitry Andric auto SegInfo = Alloc->getSegInfo(MemProt::Read | MemProt::Exec); 310d781ede6SDimitry Andric ResolverBlockAddr = SegInfo.Addr.getValue(); 311d781ede6SDimitry Andric ABI->writeResolverCode(SegInfo.WorkingMem.data(), ResolverBlockAddr, 31204eeddc0SDimitry Andric ReentryFnAddr, ReentryCtxAddr); 313fe6060f1SDimitry Andric 314349cc55cSDimitry Andric auto FA = Alloc->finalize(); 315349cc55cSDimitry Andric if (!FA) 316349cc55cSDimitry Andric return FA.takeError(); 317fe6060f1SDimitry Andric 318349cc55cSDimitry Andric ResolverBlock = std::move(*FA); 319d781ede6SDimitry Andric return ResolverBlockAddr; 320fe6060f1SDimitry Andric } 321fe6060f1SDimitry Andric 322fe6060f1SDimitry Andric std::unique_ptr<IndirectStubsManager> 323fe6060f1SDimitry Andric EPCIndirectionUtils::createIndirectStubsManager() { 324fe6060f1SDimitry Andric return std::make_unique<EPCIndirectStubsManager>(*this); 325fe6060f1SDimitry Andric } 326fe6060f1SDimitry Andric 327fe6060f1SDimitry Andric TrampolinePool &EPCIndirectionUtils::getTrampolinePool() { 328fe6060f1SDimitry Andric if (!TP) 329fe6060f1SDimitry Andric TP = std::make_unique<EPCTrampolinePool>(*this); 330fe6060f1SDimitry Andric return *TP; 331fe6060f1SDimitry Andric } 332fe6060f1SDimitry Andric 333fe6060f1SDimitry Andric LazyCallThroughManager &EPCIndirectionUtils::createLazyCallThroughManager( 334fe6060f1SDimitry Andric ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr) { 335fe6060f1SDimitry Andric assert(!LCTM && 336fe6060f1SDimitry Andric "createLazyCallThroughManager can not have been called before"); 337fe6060f1SDimitry Andric LCTM = std::make_unique<LazyCallThroughManager>(ES, ErrorHandlerAddr, 338fe6060f1SDimitry Andric &getTrampolinePool()); 339fe6060f1SDimitry Andric return *LCTM; 340fe6060f1SDimitry Andric } 341fe6060f1SDimitry Andric 342fe6060f1SDimitry Andric EPCIndirectionUtils::EPCIndirectionUtils(ExecutorProcessControl &EPC, 343fe6060f1SDimitry Andric std::unique_ptr<ABISupport> ABI) 344fe6060f1SDimitry Andric : EPC(EPC), ABI(std::move(ABI)) { 345fe6060f1SDimitry Andric assert(this->ABI && "ABI can not be null"); 346fe6060f1SDimitry Andric 347fe6060f1SDimitry Andric assert(EPC.getPageSize() > getABISupport().getStubSize() && 348fe6060f1SDimitry Andric "Stubs larger than one page are not supported"); 349fe6060f1SDimitry Andric } 350fe6060f1SDimitry Andric 351fe6060f1SDimitry Andric Expected<EPCIndirectionUtils::IndirectStubInfoVector> 352fe6060f1SDimitry Andric EPCIndirectionUtils::getIndirectStubs(unsigned NumStubs) { 353349cc55cSDimitry Andric using namespace jitlink; 354fe6060f1SDimitry Andric 355fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(EPCUIMutex); 356fe6060f1SDimitry Andric 357fe6060f1SDimitry Andric // If there aren't enough stubs available then allocate some more. 358fe6060f1SDimitry Andric if (NumStubs > AvailableIndirectStubs.size()) { 359fe6060f1SDimitry Andric auto NumStubsToAllocate = NumStubs; 360fe6060f1SDimitry Andric auto PageSize = EPC.getPageSize(); 361fe6060f1SDimitry Andric auto StubBytes = alignTo(NumStubsToAllocate * ABI->getStubSize(), PageSize); 362fe6060f1SDimitry Andric NumStubsToAllocate = StubBytes / ABI->getStubSize(); 363349cc55cSDimitry Andric auto PtrBytes = 364fe6060f1SDimitry Andric alignTo(NumStubsToAllocate * ABI->getPointerSize(), PageSize); 365fe6060f1SDimitry Andric 366349cc55cSDimitry Andric auto StubProt = MemProt::Read | MemProt::Exec; 367349cc55cSDimitry Andric auto PtrProt = MemProt::Read | MemProt::Write; 368fe6060f1SDimitry Andric 369349cc55cSDimitry Andric auto Alloc = SimpleSegmentAlloc::Create( 370349cc55cSDimitry Andric EPC.getMemMgr(), nullptr, 371349cc55cSDimitry Andric {{StubProt, {static_cast<size_t>(StubBytes), Align(PageSize)}}, 372349cc55cSDimitry Andric {PtrProt, {static_cast<size_t>(PtrBytes), Align(PageSize)}}}); 373349cc55cSDimitry Andric 374fe6060f1SDimitry Andric if (!Alloc) 375fe6060f1SDimitry Andric return Alloc.takeError(); 376fe6060f1SDimitry Andric 377349cc55cSDimitry Andric auto StubSeg = Alloc->getSegInfo(StubProt); 378349cc55cSDimitry Andric auto PtrSeg = Alloc->getSegInfo(PtrProt); 379fe6060f1SDimitry Andric 38004eeddc0SDimitry Andric ABI->writeIndirectStubsBlock(StubSeg.WorkingMem.data(), 38104eeddc0SDimitry Andric StubSeg.Addr.getValue(), 38204eeddc0SDimitry Andric PtrSeg.Addr.getValue(), NumStubsToAllocate); 383fe6060f1SDimitry Andric 384349cc55cSDimitry Andric auto FA = Alloc->finalize(); 385349cc55cSDimitry Andric if (!FA) 386349cc55cSDimitry Andric return FA.takeError(); 387fe6060f1SDimitry Andric 388349cc55cSDimitry Andric IndirectStubAllocs.push_back(std::move(*FA)); 389349cc55cSDimitry Andric 390349cc55cSDimitry Andric auto StubExecutorAddr = StubSeg.Addr; 391349cc55cSDimitry Andric auto PtrExecutorAddr = PtrSeg.Addr; 392fe6060f1SDimitry Andric for (unsigned I = 0; I != NumStubsToAllocate; ++I) { 39304eeddc0SDimitry Andric AvailableIndirectStubs.push_back(IndirectStubInfo( 39404eeddc0SDimitry Andric StubExecutorAddr.getValue(), PtrExecutorAddr.getValue())); 395349cc55cSDimitry Andric StubExecutorAddr += ABI->getStubSize(); 396349cc55cSDimitry Andric PtrExecutorAddr += ABI->getPointerSize(); 397fe6060f1SDimitry Andric } 398fe6060f1SDimitry Andric } 399fe6060f1SDimitry Andric 400fe6060f1SDimitry Andric assert(NumStubs <= AvailableIndirectStubs.size() && 401fe6060f1SDimitry Andric "Sufficient stubs should have been allocated above"); 402fe6060f1SDimitry Andric 403fe6060f1SDimitry Andric IndirectStubInfoVector Result; 404fe6060f1SDimitry Andric while (NumStubs--) { 405fe6060f1SDimitry Andric Result.push_back(AvailableIndirectStubs.back()); 406fe6060f1SDimitry Andric AvailableIndirectStubs.pop_back(); 407fe6060f1SDimitry Andric } 408fe6060f1SDimitry Andric 409fe6060f1SDimitry Andric return std::move(Result); 410fe6060f1SDimitry Andric } 411fe6060f1SDimitry Andric 412fe6060f1SDimitry Andric static JITTargetAddress reentry(JITTargetAddress LCTMAddr, 413fe6060f1SDimitry Andric JITTargetAddress TrampolineAddr) { 414fe6060f1SDimitry Andric auto &LCTM = *jitTargetAddressToPointer<LazyCallThroughManager *>(LCTMAddr); 415fe6060f1SDimitry Andric std::promise<JITTargetAddress> LandingAddrP; 416fe6060f1SDimitry Andric auto LandingAddrF = LandingAddrP.get_future(); 417fe6060f1SDimitry Andric LCTM.resolveTrampolineLandingAddress( 418fe6060f1SDimitry Andric TrampolineAddr, 419fe6060f1SDimitry Andric [&](JITTargetAddress Addr) { LandingAddrP.set_value(Addr); }); 420fe6060f1SDimitry Andric return LandingAddrF.get(); 421fe6060f1SDimitry Andric } 422fe6060f1SDimitry Andric 423fe6060f1SDimitry Andric Error setUpInProcessLCTMReentryViaEPCIU(EPCIndirectionUtils &EPCIU) { 424fe6060f1SDimitry Andric auto &LCTM = EPCIU.getLazyCallThroughManager(); 425fe6060f1SDimitry Andric return EPCIU 426fe6060f1SDimitry Andric .writeResolverBlock(pointerToJITTargetAddress(&reentry), 427fe6060f1SDimitry Andric pointerToJITTargetAddress(&LCTM)) 428fe6060f1SDimitry Andric .takeError(); 429fe6060f1SDimitry Andric } 430fe6060f1SDimitry Andric 431fe6060f1SDimitry Andric } // end namespace orc 432fe6060f1SDimitry Andric } // end namespace llvm 433