diff options
author | Lang Hames <lhames@gmail.com> | 2018-09-26 04:18:30 +0000 |
---|---|---|
committer | Lang Hames <lhames@gmail.com> | 2018-09-26 04:18:30 +0000 |
commit | c1275e72cb47b7a9ef5a6a2ffe1961f3e0025528 (patch) | |
tree | ee4cec8e7dd8a4ce68e2948d094aaf23a6a4ebbb /llvm/lib/ExecutionEngine | |
parent | ea0b7bb548befa8539ce3a9b02584fa001fd89f3 (diff) | |
download | bcm5719-llvm-c1275e72cb47b7a9ef5a6a2ffe1961f3e0025528.tar.gz bcm5719-llvm-c1275e72cb47b7a9ef5a6a2ffe1961f3e0025528.zip |
[ORC] Add a "lazy call-through" utility based on the same underlying trampoline
implementation as lazy compile callbacks, and a "lazy re-exports" utility that
builds lazy call-throughs.
Lazy call-throughs are similar to lazy compile callbacks (and are based on the
same underlying state saving/restoring trampolines) but resolve their targets
by performing a standard ORC lookup rather than invoking a user supplied
compiler callback. This allows them to inherit the thread-safety of ORC lookups
while blocking only the calling thread (whereas compile callbacks also block one
compile thread).
Lazy re-exports provide a simple way of building lazy call-throughs. Unlike a
regular re-export, a lazy re-export generates a new address (a stub entry point)
that will act like the re-exported symbol when called. The first call via a
lazy re-export will trigger compilation of the re-exported symbol before calling
through to it.
llvm-svn: 343061
Diffstat (limited to 'llvm/lib/ExecutionEngine')
-rw-r--r-- | llvm/lib/ExecutionEngine/Orc/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp | 204 |
2 files changed, 205 insertions, 0 deletions
diff --git a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt index 59c9ee7364e..680ede23568 100644 --- a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt +++ b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt @@ -5,6 +5,7 @@ add_llvm_library(LLVMOrcJIT IndirectionUtils.cpp IRCompileLayer.cpp IRTransformLayer.cpp + LazyReexports.cpp Legacy.cpp Layer.cpp LLJIT.cpp diff --git a/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp b/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp new file mode 100644 index 00000000000..c3270053d2d --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp @@ -0,0 +1,204 @@ +//===---------- 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<TrampolinePool> TP) + : ES(ES), ErrorHandlerAddr(ErrorHandlerAddr), TP(std::move(TP)) {} + +Expected<JITTargetAddress> LazyCallThroughManager::getCallThroughTrampoline( + JITDylib &SourceJD, SymbolStringPtr SymbolName, + std::shared_ptr<NotifyResolvedFunction> NotifyResolved) { + std::lock_guard<std::mutex> 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<std::mutex> 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({SourceJD}, {SymbolName}, NoDependenciesToRegister); + + 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<NotifyResolvedFunction> NotifyResolved = nullptr; + { + std::lock_guard<std::mutex> 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<std::unique_ptr<LazyCallThroughManager>> +createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES, + JITTargetAddress ErrorHandlerAddr) { + switch (T.getArch()) { + default: + return make_error<StringError>( + std::string("No callback manager available for ") + T.str(), + inconvertibleErrorCode()); + + case Triple::aarch64: + return LocalLazyCallThroughManager::Create<OrcAArch64>(ES, + ErrorHandlerAddr); + + case Triple::x86: + return LocalLazyCallThroughManager::Create<OrcI386>(ES, ErrorHandlerAddr); + + case Triple::mips: + return LocalLazyCallThroughManager::Create<OrcMips32Be>(ES, + ErrorHandlerAddr); + + case Triple::mipsel: + return LocalLazyCallThroughManager::Create<OrcMips32Le>(ES, + ErrorHandlerAddr); + + case Triple::mips64: + case Triple::mips64el: + return LocalLazyCallThroughManager::Create<OrcMips64>(ES, ErrorHandlerAddr); + + case Triple::x86_64: + if (T.getOS() == Triple::OSType::Win32) + return LocalLazyCallThroughManager::Create<OrcX86_64_Win32>( + ES, ErrorHandlerAddr); + else + return LocalLazyCallThroughManager::Create<OrcX86_64_SysV>( + ES, ErrorHandlerAddr); + } +} + +LazyReexportsMaterializationUnit::LazyReexportsMaterializationUnit( + LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager, + JITDylib &SourceJD, SymbolAliasMap CallableAliases) + : MaterializationUnit(extractFlags(CallableAliases)), + 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); + })) {} + +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, + 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. |