//===---------- LazyReexports.cpp - Utilities for lazy reexports ----------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/Orc/LazyReexports.h" #include "llvm/ADT/Triple.h" #include "llvm/ExecutionEngine/Orc/OrcABISupport.h" #define DEBUG_TYPE "orc" namespace llvm { namespace orc { void LazyCallThroughManager::NotifyResolvedFunction::anchor() {} LazyCallThroughManager::LazyCallThroughManager( ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr, std::unique_ptr TP) : ES(ES), ErrorHandlerAddr(ErrorHandlerAddr), TP(std::move(TP)) {} Expected LazyCallThroughManager::getCallThroughTrampoline( JITDylib &SourceJD, SymbolStringPtr SymbolName, std::shared_ptr NotifyResolved) { std::lock_guard Lock(LCTMMutex); auto Trampoline = TP->getTrampoline(); if (!Trampoline) return Trampoline.takeError(); Reexports[*Trampoline] = std::make_pair(&SourceJD, std::move(SymbolName)); Notifiers[*Trampoline] = std::move(NotifyResolved); return *Trampoline; } JITTargetAddress LazyCallThroughManager::callThroughToSymbol(JITTargetAddress TrampolineAddr) { JITDylib *SourceJD = nullptr; SymbolStringPtr SymbolName; { std::lock_guard Lock(LCTMMutex); auto I = Reexports.find(TrampolineAddr); if (I == Reexports.end()) return ErrorHandlerAddr; SourceJD = I->second.first; SymbolName = I->second.second; } auto LookupResult = ES.lookup(JITDylibSearchList({{SourceJD, true}}), {SymbolName}, NoDependenciesToRegister, true); if (!LookupResult) { ES.reportError(LookupResult.takeError()); return ErrorHandlerAddr; } assert(LookupResult->size() == 1 && "Unexpected number of results"); assert(LookupResult->count(SymbolName) && "Unexpected result"); auto ResolvedAddr = LookupResult->begin()->second.getAddress(); std::shared_ptr NotifyResolved = nullptr; { std::lock_guard Lock(LCTMMutex); auto I = Notifiers.find(TrampolineAddr); if (I != Notifiers.end()) { NotifyResolved = I->second; Notifiers.erase(I); } } if (NotifyResolved) { if (auto Err = (*NotifyResolved)(*SourceJD, SymbolName, ResolvedAddr)) { ES.reportError(std::move(Err)); return ErrorHandlerAddr; } } return ResolvedAddr; } Expected> createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr) { switch (T.getArch()) { default: return make_error( std::string("No callback manager available for ") + T.str(), inconvertibleErrorCode()); case Triple::aarch64: return LocalLazyCallThroughManager::Create(ES, ErrorHandlerAddr); case Triple::x86: return LocalLazyCallThroughManager::Create(ES, ErrorHandlerAddr); case Triple::mips: return LocalLazyCallThroughManager::Create(ES, ErrorHandlerAddr); case Triple::mipsel: return LocalLazyCallThroughManager::Create(ES, ErrorHandlerAddr); case Triple::mips64: case Triple::mips64el: return LocalLazyCallThroughManager::Create(ES, ErrorHandlerAddr); case Triple::x86_64: if (T.getOS() == Triple::OSType::Win32) return LocalLazyCallThroughManager::Create( ES, ErrorHandlerAddr); else return LocalLazyCallThroughManager::Create( ES, ErrorHandlerAddr); } } LazyReexportsMaterializationUnit::LazyReexportsMaterializationUnit( LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager, JITDylib &SourceJD, SymbolAliasMap CallableAliases, VModuleKey K) : MaterializationUnit(extractFlags(CallableAliases), std::move(K)), LCTManager(LCTManager), ISManager(ISManager), SourceJD(SourceJD), CallableAliases(std::move(CallableAliases)), NotifyResolved(LazyCallThroughManager::createNotifyResolvedFunction( [&ISManager](JITDylib &JD, const SymbolStringPtr &SymbolName, JITTargetAddress ResolvedAddr) { return ISManager.updatePointer(*SymbolName, ResolvedAddr); })) {} StringRef LazyReexportsMaterializationUnit::getName() const { return ""; } void LazyReexportsMaterializationUnit::materialize( MaterializationResponsibility R) { auto RequestedSymbols = R.getRequestedSymbols(); SymbolAliasMap RequestedAliases; for (auto &RequestedSymbol : RequestedSymbols) { auto I = CallableAliases.find(RequestedSymbol); assert(I != CallableAliases.end() && "Symbol not found in alias map?"); RequestedAliases[I->first] = std::move(I->second); CallableAliases.erase(I); } if (!CallableAliases.empty()) R.replace(lazyReexports(LCTManager, ISManager, SourceJD, std::move(CallableAliases))); IndirectStubsManager::StubInitsMap StubInits; for (auto &Alias : RequestedAliases) { auto CallThroughTrampoline = LCTManager.getCallThroughTrampoline( SourceJD, Alias.second.Aliasee, NotifyResolved); if (!CallThroughTrampoline) { SourceJD.getExecutionSession().reportError( CallThroughTrampoline.takeError()); R.failMaterialization(); return; } StubInits[*Alias.first] = std::make_pair(*CallThroughTrampoline, Alias.second.AliasFlags); } if (auto Err = ISManager.createStubs(StubInits)) { SourceJD.getExecutionSession().reportError(std::move(Err)); R.failMaterialization(); return; } SymbolMap Stubs; for (auto &Alias : RequestedAliases) Stubs[Alias.first] = ISManager.findStub(*Alias.first, false); R.resolve(Stubs); R.emit(); } void LazyReexportsMaterializationUnit::discard(const JITDylib &JD, const SymbolStringPtr &Name) { assert(CallableAliases.count(Name) && "Symbol not covered by this MaterializationUnit"); CallableAliases.erase(Name); } SymbolFlagsMap LazyReexportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) { SymbolFlagsMap SymbolFlags; for (auto &KV : Aliases) { assert(KV.second.AliasFlags.isCallable() && "Lazy re-exports must be callable symbols"); SymbolFlags[KV.first] = KV.second.AliasFlags; } return SymbolFlags; } } // End namespace orc. } // End namespace llvm.