10b57cec5SDimitry Andric //===---------- LazyReexports.cpp - Utilities for lazy reexports ----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "llvm/ExecutionEngine/Orc/LazyReexports.h"
100b57cec5SDimitry Andric
110b57cec5SDimitry Andric #include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
1206c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #define DEBUG_TYPE "orc"
150b57cec5SDimitry Andric
160b57cec5SDimitry Andric namespace llvm {
170b57cec5SDimitry Andric namespace orc {
180b57cec5SDimitry Andric
LazyCallThroughManager(ExecutionSession & ES,ExecutorAddr ErrorHandlerAddr,TrampolinePool * TP)1906c3fb27SDimitry Andric LazyCallThroughManager::LazyCallThroughManager(ExecutionSession &ES,
2006c3fb27SDimitry Andric ExecutorAddr ErrorHandlerAddr,
2106c3fb27SDimitry Andric TrampolinePool *TP)
225ffd83dbSDimitry Andric : ES(ES), ErrorHandlerAddr(ErrorHandlerAddr), TP(TP) {}
230b57cec5SDimitry Andric
getCallThroughTrampoline(JITDylib & SourceJD,SymbolStringPtr SymbolName,NotifyResolvedFunction NotifyResolved)2406c3fb27SDimitry Andric Expected<ExecutorAddr> LazyCallThroughManager::getCallThroughTrampoline(
250b57cec5SDimitry Andric JITDylib &SourceJD, SymbolStringPtr SymbolName,
265ffd83dbSDimitry Andric NotifyResolvedFunction NotifyResolved) {
275ffd83dbSDimitry Andric assert(TP && "TrampolinePool not set");
285ffd83dbSDimitry Andric
290b57cec5SDimitry Andric std::lock_guard<std::mutex> Lock(LCTMMutex);
300b57cec5SDimitry Andric auto Trampoline = TP->getTrampoline();
310b57cec5SDimitry Andric
320b57cec5SDimitry Andric if (!Trampoline)
330b57cec5SDimitry Andric return Trampoline.takeError();
340b57cec5SDimitry Andric
355ffd83dbSDimitry Andric Reexports[*Trampoline] = ReexportsEntry{&SourceJD, std::move(SymbolName)};
360b57cec5SDimitry Andric Notifiers[*Trampoline] = std::move(NotifyResolved);
370b57cec5SDimitry Andric return *Trampoline;
380b57cec5SDimitry Andric }
390b57cec5SDimitry Andric
reportCallThroughError(Error Err)4006c3fb27SDimitry Andric ExecutorAddr LazyCallThroughManager::reportCallThroughError(Error Err) {
415ffd83dbSDimitry Andric ES.reportError(std::move(Err));
425ffd83dbSDimitry Andric return ErrorHandlerAddr;
435ffd83dbSDimitry Andric }
440b57cec5SDimitry Andric
455ffd83dbSDimitry Andric Expected<LazyCallThroughManager::ReexportsEntry>
findReexport(ExecutorAddr TrampolineAddr)4606c3fb27SDimitry Andric LazyCallThroughManager::findReexport(ExecutorAddr TrampolineAddr) {
470b57cec5SDimitry Andric std::lock_guard<std::mutex> Lock(LCTMMutex);
480b57cec5SDimitry Andric auto I = Reexports.find(TrampolineAddr);
490b57cec5SDimitry Andric if (I == Reexports.end())
505ffd83dbSDimitry Andric return createStringError(inconvertibleErrorCode(),
5106c3fb27SDimitry Andric "Missing reexport for trampoline address %p" +
5206c3fb27SDimitry Andric formatv("{0:x}", TrampolineAddr));
535ffd83dbSDimitry Andric return I->second;
540b57cec5SDimitry Andric }
55480093f4SDimitry Andric
notifyResolved(ExecutorAddr TrampolineAddr,ExecutorAddr ResolvedAddr)5606c3fb27SDimitry Andric Error LazyCallThroughManager::notifyResolved(ExecutorAddr TrampolineAddr,
5706c3fb27SDimitry Andric ExecutorAddr ResolvedAddr) {
585ffd83dbSDimitry Andric NotifyResolvedFunction NotifyResolved;
590b57cec5SDimitry Andric {
600b57cec5SDimitry Andric std::lock_guard<std::mutex> Lock(LCTMMutex);
610b57cec5SDimitry Andric auto I = Notifiers.find(TrampolineAddr);
620b57cec5SDimitry Andric if (I != Notifiers.end()) {
635ffd83dbSDimitry Andric NotifyResolved = std::move(I->second);
640b57cec5SDimitry Andric Notifiers.erase(I);
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric
685ffd83dbSDimitry Andric return NotifyResolved ? NotifyResolved(ResolvedAddr) : Error::success();
690b57cec5SDimitry Andric }
700b57cec5SDimitry Andric
resolveTrampolineLandingAddress(ExecutorAddr TrampolineAddr,NotifyLandingResolvedFunction NotifyLandingResolved)715ffd83dbSDimitry Andric void LazyCallThroughManager::resolveTrampolineLandingAddress(
7206c3fb27SDimitry Andric ExecutorAddr TrampolineAddr,
735ffd83dbSDimitry Andric NotifyLandingResolvedFunction NotifyLandingResolved) {
745ffd83dbSDimitry Andric
755ffd83dbSDimitry Andric auto Entry = findReexport(TrampolineAddr);
765ffd83dbSDimitry Andric if (!Entry)
775ffd83dbSDimitry Andric return NotifyLandingResolved(reportCallThroughError(Entry.takeError()));
785ffd83dbSDimitry Andric
79e8d8bef9SDimitry Andric // Declaring SLS and the callback outside of the call to ES.lookup is a
80e8d8bef9SDimitry Andric // workaround to fix build failures on AIX and on z/OS platforms.
81e8d8bef9SDimitry Andric SymbolLookupSet SLS({Entry->SymbolName});
82e8d8bef9SDimitry Andric auto Callback = [this, TrampolineAddr, SymbolName = Entry->SymbolName,
835ffd83dbSDimitry Andric NotifyLandingResolved = std::move(NotifyLandingResolved)](
845ffd83dbSDimitry Andric Expected<SymbolMap> Result) mutable {
855ffd83dbSDimitry Andric if (Result) {
865ffd83dbSDimitry Andric assert(Result->size() == 1 && "Unexpected result size");
875ffd83dbSDimitry Andric assert(Result->count(SymbolName) && "Unexpected result value");
8806c3fb27SDimitry Andric ExecutorAddr LandingAddr = (*Result)[SymbolName].getAddress();
895ffd83dbSDimitry Andric
905ffd83dbSDimitry Andric if (auto Err = notifyResolved(TrampolineAddr, LandingAddr))
915ffd83dbSDimitry Andric NotifyLandingResolved(reportCallThroughError(std::move(Err)));
925ffd83dbSDimitry Andric else
935ffd83dbSDimitry Andric NotifyLandingResolved(LandingAddr);
94e8d8bef9SDimitry Andric } else {
955ffd83dbSDimitry Andric NotifyLandingResolved(reportCallThroughError(Result.takeError()));
96e8d8bef9SDimitry Andric }
97e8d8bef9SDimitry Andric };
98e8d8bef9SDimitry Andric
99e8d8bef9SDimitry Andric ES.lookup(LookupKind::Static,
100e8d8bef9SDimitry Andric makeJITDylibSearchOrder(Entry->SourceJD,
101e8d8bef9SDimitry Andric JITDylibLookupFlags::MatchAllSymbols),
102e8d8bef9SDimitry Andric std::move(SLS), SymbolState::Ready, std::move(Callback),
1035ffd83dbSDimitry Andric NoDependenciesToRegister);
1040b57cec5SDimitry Andric }
1050b57cec5SDimitry Andric
1060b57cec5SDimitry Andric Expected<std::unique_ptr<LazyCallThroughManager>>
createLocalLazyCallThroughManager(const Triple & T,ExecutionSession & ES,ExecutorAddr ErrorHandlerAddr)1070b57cec5SDimitry Andric createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES,
10806c3fb27SDimitry Andric ExecutorAddr ErrorHandlerAddr) {
1090b57cec5SDimitry Andric switch (T.getArch()) {
1100b57cec5SDimitry Andric default:
1110b57cec5SDimitry Andric return make_error<StringError>(
1120b57cec5SDimitry Andric std::string("No callback manager available for ") + T.str(),
1130b57cec5SDimitry Andric inconvertibleErrorCode());
1140b57cec5SDimitry Andric
1150b57cec5SDimitry Andric case Triple::aarch64:
1168bcb0991SDimitry Andric case Triple::aarch64_32:
1170b57cec5SDimitry Andric return LocalLazyCallThroughManager::Create<OrcAArch64>(ES,
1180b57cec5SDimitry Andric ErrorHandlerAddr);
1190b57cec5SDimitry Andric
1200b57cec5SDimitry Andric case Triple::x86:
1210b57cec5SDimitry Andric return LocalLazyCallThroughManager::Create<OrcI386>(ES, ErrorHandlerAddr);
1220b57cec5SDimitry Andric
123bdd1243dSDimitry Andric case Triple::loongarch64:
124bdd1243dSDimitry Andric return LocalLazyCallThroughManager::Create<OrcLoongArch64>(
125bdd1243dSDimitry Andric ES, ErrorHandlerAddr);
126bdd1243dSDimitry Andric
1270b57cec5SDimitry Andric case Triple::mips:
1280b57cec5SDimitry Andric return LocalLazyCallThroughManager::Create<OrcMips32Be>(ES,
1290b57cec5SDimitry Andric ErrorHandlerAddr);
1300b57cec5SDimitry Andric
1310b57cec5SDimitry Andric case Triple::mipsel:
1320b57cec5SDimitry Andric return LocalLazyCallThroughManager::Create<OrcMips32Le>(ES,
1330b57cec5SDimitry Andric ErrorHandlerAddr);
1340b57cec5SDimitry Andric
1350b57cec5SDimitry Andric case Triple::mips64:
1360b57cec5SDimitry Andric case Triple::mips64el:
1370b57cec5SDimitry Andric return LocalLazyCallThroughManager::Create<OrcMips64>(ES, ErrorHandlerAddr);
1380b57cec5SDimitry Andric
13981ad6265SDimitry Andric case Triple::riscv64:
14081ad6265SDimitry Andric return LocalLazyCallThroughManager::Create<OrcRiscv64>(ES,
14181ad6265SDimitry Andric ErrorHandlerAddr);
14281ad6265SDimitry Andric
1430b57cec5SDimitry Andric case Triple::x86_64:
1440b57cec5SDimitry Andric if (T.getOS() == Triple::OSType::Win32)
1450b57cec5SDimitry Andric return LocalLazyCallThroughManager::Create<OrcX86_64_Win32>(
1460b57cec5SDimitry Andric ES, ErrorHandlerAddr);
1470b57cec5SDimitry Andric else
1480b57cec5SDimitry Andric return LocalLazyCallThroughManager::Create<OrcX86_64_SysV>(
1490b57cec5SDimitry Andric ES, ErrorHandlerAddr);
1500b57cec5SDimitry Andric }
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric
LazyReexportsMaterializationUnit(LazyCallThroughManager & LCTManager,IndirectStubsManager & ISManager,JITDylib & SourceJD,SymbolAliasMap CallableAliases,ImplSymbolMap * SrcJDLoc)1530b57cec5SDimitry Andric LazyReexportsMaterializationUnit::LazyReexportsMaterializationUnit(
1540b57cec5SDimitry Andric LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager,
155e8d8bef9SDimitry Andric JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc)
1560eae32dcSDimitry Andric : MaterializationUnit(extractFlags(CallableAliases)),
1570b57cec5SDimitry Andric LCTManager(LCTManager), ISManager(ISManager), SourceJD(SourceJD),
1585ffd83dbSDimitry Andric CallableAliases(std::move(CallableAliases)), AliaseeTable(SrcJDLoc) {}
1590b57cec5SDimitry Andric
getName() const1600b57cec5SDimitry Andric StringRef LazyReexportsMaterializationUnit::getName() const {
1610b57cec5SDimitry Andric return "<Lazy Reexports>";
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric
materialize(std::unique_ptr<MaterializationResponsibility> R)1640b57cec5SDimitry Andric void LazyReexportsMaterializationUnit::materialize(
165e8d8bef9SDimitry Andric std::unique_ptr<MaterializationResponsibility> R) {
166e8d8bef9SDimitry Andric auto RequestedSymbols = R->getRequestedSymbols();
1670b57cec5SDimitry Andric
1680b57cec5SDimitry Andric SymbolAliasMap RequestedAliases;
1690b57cec5SDimitry Andric for (auto &RequestedSymbol : RequestedSymbols) {
1700b57cec5SDimitry Andric auto I = CallableAliases.find(RequestedSymbol);
1710b57cec5SDimitry Andric assert(I != CallableAliases.end() && "Symbol not found in alias map?");
1720b57cec5SDimitry Andric RequestedAliases[I->first] = std::move(I->second);
1730b57cec5SDimitry Andric CallableAliases.erase(I);
1740b57cec5SDimitry Andric }
1750b57cec5SDimitry Andric
1760b57cec5SDimitry Andric if (!CallableAliases.empty())
177e8d8bef9SDimitry Andric if (auto Err = R->replace(lazyReexports(LCTManager, ISManager, SourceJD,
178e8d8bef9SDimitry Andric std::move(CallableAliases),
179e8d8bef9SDimitry Andric AliaseeTable))) {
180e8d8bef9SDimitry Andric R->getExecutionSession().reportError(std::move(Err));
181e8d8bef9SDimitry Andric R->failMaterialization();
182e8d8bef9SDimitry Andric return;
183e8d8bef9SDimitry Andric }
1840b57cec5SDimitry Andric
1850b57cec5SDimitry Andric IndirectStubsManager::StubInitsMap StubInits;
1860b57cec5SDimitry Andric for (auto &Alias : RequestedAliases) {
1870b57cec5SDimitry Andric
1880b57cec5SDimitry Andric auto CallThroughTrampoline = LCTManager.getCallThroughTrampoline(
1895ffd83dbSDimitry Andric SourceJD, Alias.second.Aliasee,
1905ffd83dbSDimitry Andric [&ISManager = this->ISManager,
19106c3fb27SDimitry Andric StubSym = Alias.first](ExecutorAddr ResolvedAddr) -> Error {
1925ffd83dbSDimitry Andric return ISManager.updatePointer(*StubSym, ResolvedAddr);
1935ffd83dbSDimitry Andric });
1940b57cec5SDimitry Andric
1950b57cec5SDimitry Andric if (!CallThroughTrampoline) {
1960b57cec5SDimitry Andric SourceJD.getExecutionSession().reportError(
1970b57cec5SDimitry Andric CallThroughTrampoline.takeError());
198e8d8bef9SDimitry Andric R->failMaterialization();
1990b57cec5SDimitry Andric return;
2000b57cec5SDimitry Andric }
2010b57cec5SDimitry Andric
2020b57cec5SDimitry Andric StubInits[*Alias.first] =
2030b57cec5SDimitry Andric std::make_pair(*CallThroughTrampoline, Alias.second.AliasFlags);
2040b57cec5SDimitry Andric }
2050b57cec5SDimitry Andric
2068bcb0991SDimitry Andric if (AliaseeTable != nullptr && !RequestedAliases.empty())
2078bcb0991SDimitry Andric AliaseeTable->trackImpls(RequestedAliases, &SourceJD);
2088bcb0991SDimitry Andric
2090b57cec5SDimitry Andric if (auto Err = ISManager.createStubs(StubInits)) {
2100b57cec5SDimitry Andric SourceJD.getExecutionSession().reportError(std::move(Err));
211e8d8bef9SDimitry Andric R->failMaterialization();
2120b57cec5SDimitry Andric return;
2130b57cec5SDimitry Andric }
2140b57cec5SDimitry Andric
2150b57cec5SDimitry Andric SymbolMap Stubs;
2160b57cec5SDimitry Andric for (auto &Alias : RequestedAliases)
2170b57cec5SDimitry Andric Stubs[Alias.first] = ISManager.findStub(*Alias.first, false);
2180b57cec5SDimitry Andric
2198bcb0991SDimitry Andric // No registered dependencies, so these calls cannot fail.
220e8d8bef9SDimitry Andric cantFail(R->notifyResolved(Stubs));
221*0fca6ea1SDimitry Andric cantFail(R->notifyEmitted({}));
2220b57cec5SDimitry Andric }
2230b57cec5SDimitry Andric
discard(const JITDylib & JD,const SymbolStringPtr & Name)2240b57cec5SDimitry Andric void LazyReexportsMaterializationUnit::discard(const JITDylib &JD,
2250b57cec5SDimitry Andric const SymbolStringPtr &Name) {
2260b57cec5SDimitry Andric assert(CallableAliases.count(Name) &&
2270b57cec5SDimitry Andric "Symbol not covered by this MaterializationUnit");
2280b57cec5SDimitry Andric CallableAliases.erase(Name);
2290b57cec5SDimitry Andric }
2300b57cec5SDimitry Andric
2310eae32dcSDimitry Andric MaterializationUnit::Interface
extractFlags(const SymbolAliasMap & Aliases)2320b57cec5SDimitry Andric LazyReexportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) {
2330b57cec5SDimitry Andric SymbolFlagsMap SymbolFlags;
2340b57cec5SDimitry Andric for (auto &KV : Aliases) {
2350b57cec5SDimitry Andric assert(KV.second.AliasFlags.isCallable() &&
2360b57cec5SDimitry Andric "Lazy re-exports must be callable symbols");
2370b57cec5SDimitry Andric SymbolFlags[KV.first] = KV.second.AliasFlags;
2380b57cec5SDimitry Andric }
2390eae32dcSDimitry Andric return MaterializationUnit::Interface(std::move(SymbolFlags), nullptr);
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric
2420b57cec5SDimitry Andric } // End namespace orc.
2430b57cec5SDimitry Andric } // End namespace llvm.
244