| //===------ LazyReexports.h -- Utilities for lazy reexports -----*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Lazy re-exports are similar to normal re-exports, except that for callable |
| // symbols the definitions are replaced with trampolines that will look up and |
| // call through to the re-exported symbol at runtime. This can be used to |
| // enable lazy compilation. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_EXECUTIONENGINE_ORC_LAZYREEXPORTS_H |
| #define LLVM_EXECUTIONENGINE_ORC_LAZYREEXPORTS_H |
| |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/ExecutionEngine/Orc/Core.h" |
| #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" |
| #include "llvm/ExecutionEngine/Orc/Speculation.h" |
| |
| namespace llvm { |
| |
| class Triple; |
| |
| namespace orc { |
| |
| /// Manages a set of 'lazy call-through' trampolines. These are compiler |
| /// re-entry trampolines that are pre-bound to look up a given symbol in a given |
| /// JITDylib, then jump to that address. Since compilation of symbols is |
| /// triggered on first lookup, these call-through trampolines can be used to |
| /// implement lazy compilation. |
| /// |
| /// The easiest way to construct these call-throughs is using the lazyReexport |
| /// function. |
| class LazyCallThroughManager { |
| public: |
| using NotifyResolvedFunction = |
| unique_function<Error(JITTargetAddress ResolvedAddr)>; |
| |
| LazyCallThroughManager(ExecutionSession &ES, |
| JITTargetAddress ErrorHandlerAddr, TrampolinePool *TP); |
| |
| // Return a free call-through trampoline and bind it to look up and call |
| // through to the given symbol. |
| Expected<JITTargetAddress> |
| getCallThroughTrampoline(JITDylib &SourceJD, SymbolStringPtr SymbolName, |
| NotifyResolvedFunction NotifyResolved); |
| |
| void resolveTrampolineLandingAddress( |
| JITTargetAddress TrampolineAddr, |
| TrampolinePool::NotifyLandingResolvedFunction NotifyLandingResolved); |
| |
| virtual ~LazyCallThroughManager() = default; |
| |
| protected: |
| using NotifyLandingResolvedFunction = |
| TrampolinePool::NotifyLandingResolvedFunction; |
| |
| struct ReexportsEntry { |
| JITDylib *SourceJD; |
| SymbolStringPtr SymbolName; |
| }; |
| |
| JITTargetAddress reportCallThroughError(Error Err); |
| Expected<ReexportsEntry> findReexport(JITTargetAddress TrampolineAddr); |
| Error notifyResolved(JITTargetAddress TrampolineAddr, |
| JITTargetAddress ResolvedAddr); |
| void setTrampolinePool(TrampolinePool &TP) { this->TP = &TP; } |
| |
| private: |
| using ReexportsMap = std::map<JITTargetAddress, ReexportsEntry>; |
| |
| using NotifiersMap = std::map<JITTargetAddress, NotifyResolvedFunction>; |
| |
| std::mutex LCTMMutex; |
| ExecutionSession &ES; |
| JITTargetAddress ErrorHandlerAddr; |
| TrampolinePool *TP = nullptr; |
| ReexportsMap Reexports; |
| NotifiersMap Notifiers; |
| }; |
| |
| /// A lazy call-through manager that builds trampolines in the current process. |
| class LocalLazyCallThroughManager : public LazyCallThroughManager { |
| private: |
| using NotifyTargetResolved = unique_function<void(JITTargetAddress)>; |
| |
| LocalLazyCallThroughManager(ExecutionSession &ES, |
| JITTargetAddress ErrorHandlerAddr) |
| : LazyCallThroughManager(ES, ErrorHandlerAddr, nullptr) {} |
| |
| template <typename ORCABI> Error init() { |
| auto TP = LocalTrampolinePool<ORCABI>::Create( |
| [this](JITTargetAddress TrampolineAddr, |
| TrampolinePool::NotifyLandingResolvedFunction |
| NotifyLandingResolved) { |
| resolveTrampolineLandingAddress(TrampolineAddr, |
| std::move(NotifyLandingResolved)); |
| }); |
| |
| if (!TP) |
| return TP.takeError(); |
| |
| this->TP = std::move(*TP); |
| setTrampolinePool(*this->TP); |
| return Error::success(); |
| } |
| |
| std::unique_ptr<TrampolinePool> TP; |
| |
| public: |
| /// Create a LocalLazyCallThroughManager using the given ABI. See |
| /// createLocalLazyCallThroughManager. |
| template <typename ORCABI> |
| static Expected<std::unique_ptr<LocalLazyCallThroughManager>> |
| Create(ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr) { |
| auto LLCTM = std::unique_ptr<LocalLazyCallThroughManager>( |
| new LocalLazyCallThroughManager(ES, ErrorHandlerAddr)); |
| |
| if (auto Err = LLCTM->init<ORCABI>()) |
| return std::move(Err); |
| |
| return std::move(LLCTM); |
| } |
| }; |
| |
| /// Create a LocalLazyCallThroughManager from the given triple and execution |
| /// session. |
| Expected<std::unique_ptr<LazyCallThroughManager>> |
| createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES, |
| JITTargetAddress ErrorHandlerAddr); |
| |
| /// A materialization unit that builds lazy re-exports. These are callable |
| /// entry points that call through to the given symbols. |
| /// Unlike a 'true' re-export, the address of the lazy re-export will not |
| /// match the address of the re-exported symbol, but calling it will behave |
| /// the same as calling the re-exported symbol. |
| class LazyReexportsMaterializationUnit : public MaterializationUnit { |
| public: |
| LazyReexportsMaterializationUnit(LazyCallThroughManager &LCTManager, |
| IndirectStubsManager &ISManager, |
| JITDylib &SourceJD, |
| SymbolAliasMap CallableAliases, |
| ImplSymbolMap *SrcJDLoc); |
| |
| StringRef getName() const override; |
| |
| private: |
| void materialize(std::unique_ptr<MaterializationResponsibility> R) override; |
| void discard(const JITDylib &JD, const SymbolStringPtr &Name) override; |
| static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases); |
| |
| LazyCallThroughManager &LCTManager; |
| IndirectStubsManager &ISManager; |
| JITDylib &SourceJD; |
| SymbolAliasMap CallableAliases; |
| ImplSymbolMap *AliaseeTable; |
| }; |
| |
| /// Define lazy-reexports based on the given SymbolAliasMap. Each lazy re-export |
| /// is a callable symbol that will look up and dispatch to the given aliasee on |
| /// first call. All subsequent calls will go directly to the aliasee. |
| inline std::unique_ptr<LazyReexportsMaterializationUnit> |
| lazyReexports(LazyCallThroughManager &LCTManager, |
| IndirectStubsManager &ISManager, JITDylib &SourceJD, |
| SymbolAliasMap CallableAliases, |
| ImplSymbolMap *SrcJDLoc = nullptr) { |
| return std::make_unique<LazyReexportsMaterializationUnit>( |
| LCTManager, ISManager, SourceJD, std::move(CallableAliases), SrcJDLoc); |
| } |
| |
| } // End namespace orc |
| } // End namespace llvm |
| |
| #endif // LLVM_EXECUTIONENGINE_ORC_LAZYREEXPORTS_H |