Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 14 | pmbaty | 1 | //===------ LazyReexports.h -- Utilities for lazy reexports -----*- C++ -*-===// |
| 2 | // |
||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
||
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
||
| 6 | // |
||
| 7 | //===----------------------------------------------------------------------===// |
||
| 8 | // |
||
| 9 | // Lazy re-exports are similar to normal re-exports, except that for callable |
||
| 10 | // symbols the definitions are replaced with trampolines that will look up and |
||
| 11 | // call through to the re-exported symbol at runtime. This can be used to |
||
| 12 | // enable lazy compilation. |
||
| 13 | // |
||
| 14 | //===----------------------------------------------------------------------===// |
||
| 15 | |||
| 16 | #ifndef LLVM_EXECUTIONENGINE_ORC_LAZYREEXPORTS_H |
||
| 17 | #define LLVM_EXECUTIONENGINE_ORC_LAZYREEXPORTS_H |
||
| 18 | |||
| 19 | #include "llvm/ADT/STLExtras.h" |
||
| 20 | #include "llvm/ExecutionEngine/Orc/Core.h" |
||
| 21 | #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" |
||
| 22 | #include "llvm/ExecutionEngine/Orc/Speculation.h" |
||
| 23 | |||
| 24 | namespace llvm { |
||
| 25 | |||
| 26 | class Triple; |
||
| 27 | |||
| 28 | namespace orc { |
||
| 29 | |||
| 30 | /// Manages a set of 'lazy call-through' trampolines. These are compiler |
||
| 31 | /// re-entry trampolines that are pre-bound to look up a given symbol in a given |
||
| 32 | /// JITDylib, then jump to that address. Since compilation of symbols is |
||
| 33 | /// triggered on first lookup, these call-through trampolines can be used to |
||
| 34 | /// implement lazy compilation. |
||
| 35 | /// |
||
| 36 | /// The easiest way to construct these call-throughs is using the lazyReexport |
||
| 37 | /// function. |
||
| 38 | class LazyCallThroughManager { |
||
| 39 | public: |
||
| 40 | using NotifyResolvedFunction = |
||
| 41 | unique_function<Error(JITTargetAddress ResolvedAddr)>; |
||
| 42 | |||
| 43 | LazyCallThroughManager(ExecutionSession &ES, |
||
| 44 | JITTargetAddress ErrorHandlerAddr, TrampolinePool *TP); |
||
| 45 | |||
| 46 | // Return a free call-through trampoline and bind it to look up and call |
||
| 47 | // through to the given symbol. |
||
| 48 | Expected<JITTargetAddress> |
||
| 49 | getCallThroughTrampoline(JITDylib &SourceJD, SymbolStringPtr SymbolName, |
||
| 50 | NotifyResolvedFunction NotifyResolved); |
||
| 51 | |||
| 52 | void resolveTrampolineLandingAddress( |
||
| 53 | JITTargetAddress TrampolineAddr, |
||
| 54 | TrampolinePool::NotifyLandingResolvedFunction NotifyLandingResolved); |
||
| 55 | |||
| 56 | virtual ~LazyCallThroughManager() = default; |
||
| 57 | |||
| 58 | protected: |
||
| 59 | using NotifyLandingResolvedFunction = |
||
| 60 | TrampolinePool::NotifyLandingResolvedFunction; |
||
| 61 | |||
| 62 | struct ReexportsEntry { |
||
| 63 | JITDylib *SourceJD; |
||
| 64 | SymbolStringPtr SymbolName; |
||
| 65 | }; |
||
| 66 | |||
| 67 | JITTargetAddress reportCallThroughError(Error Err); |
||
| 68 | Expected<ReexportsEntry> findReexport(JITTargetAddress TrampolineAddr); |
||
| 69 | Error notifyResolved(JITTargetAddress TrampolineAddr, |
||
| 70 | JITTargetAddress ResolvedAddr); |
||
| 71 | void setTrampolinePool(TrampolinePool &TP) { this->TP = &TP; } |
||
| 72 | |||
| 73 | private: |
||
| 74 | using ReexportsMap = std::map<JITTargetAddress, ReexportsEntry>; |
||
| 75 | |||
| 76 | using NotifiersMap = std::map<JITTargetAddress, NotifyResolvedFunction>; |
||
| 77 | |||
| 78 | std::mutex LCTMMutex; |
||
| 79 | ExecutionSession &ES; |
||
| 80 | JITTargetAddress ErrorHandlerAddr; |
||
| 81 | TrampolinePool *TP = nullptr; |
||
| 82 | ReexportsMap Reexports; |
||
| 83 | NotifiersMap Notifiers; |
||
| 84 | }; |
||
| 85 | |||
| 86 | /// A lazy call-through manager that builds trampolines in the current process. |
||
| 87 | class LocalLazyCallThroughManager : public LazyCallThroughManager { |
||
| 88 | private: |
||
| 89 | using NotifyTargetResolved = unique_function<void(JITTargetAddress)>; |
||
| 90 | |||
| 91 | LocalLazyCallThroughManager(ExecutionSession &ES, |
||
| 92 | JITTargetAddress ErrorHandlerAddr) |
||
| 93 | : LazyCallThroughManager(ES, ErrorHandlerAddr, nullptr) {} |
||
| 94 | |||
| 95 | template <typename ORCABI> Error init() { |
||
| 96 | auto TP = LocalTrampolinePool<ORCABI>::Create( |
||
| 97 | [this](JITTargetAddress TrampolineAddr, |
||
| 98 | TrampolinePool::NotifyLandingResolvedFunction |
||
| 99 | NotifyLandingResolved) { |
||
| 100 | resolveTrampolineLandingAddress(TrampolineAddr, |
||
| 101 | std::move(NotifyLandingResolved)); |
||
| 102 | }); |
||
| 103 | |||
| 104 | if (!TP) |
||
| 105 | return TP.takeError(); |
||
| 106 | |||
| 107 | this->TP = std::move(*TP); |
||
| 108 | setTrampolinePool(*this->TP); |
||
| 109 | return Error::success(); |
||
| 110 | } |
||
| 111 | |||
| 112 | std::unique_ptr<TrampolinePool> TP; |
||
| 113 | |||
| 114 | public: |
||
| 115 | /// Create a LocalLazyCallThroughManager using the given ABI. See |
||
| 116 | /// createLocalLazyCallThroughManager. |
||
| 117 | template <typename ORCABI> |
||
| 118 | static Expected<std::unique_ptr<LocalLazyCallThroughManager>> |
||
| 119 | Create(ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr) { |
||
| 120 | auto LLCTM = std::unique_ptr<LocalLazyCallThroughManager>( |
||
| 121 | new LocalLazyCallThroughManager(ES, ErrorHandlerAddr)); |
||
| 122 | |||
| 123 | if (auto Err = LLCTM->init<ORCABI>()) |
||
| 124 | return std::move(Err); |
||
| 125 | |||
| 126 | return std::move(LLCTM); |
||
| 127 | } |
||
| 128 | }; |
||
| 129 | |||
| 130 | /// Create a LocalLazyCallThroughManager from the given triple and execution |
||
| 131 | /// session. |
||
| 132 | Expected<std::unique_ptr<LazyCallThroughManager>> |
||
| 133 | createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES, |
||
| 134 | JITTargetAddress ErrorHandlerAddr); |
||
| 135 | |||
| 136 | /// A materialization unit that builds lazy re-exports. These are callable |
||
| 137 | /// entry points that call through to the given symbols. |
||
| 138 | /// Unlike a 'true' re-export, the address of the lazy re-export will not |
||
| 139 | /// match the address of the re-exported symbol, but calling it will behave |
||
| 140 | /// the same as calling the re-exported symbol. |
||
| 141 | class LazyReexportsMaterializationUnit : public MaterializationUnit { |
||
| 142 | public: |
||
| 143 | LazyReexportsMaterializationUnit(LazyCallThroughManager &LCTManager, |
||
| 144 | IndirectStubsManager &ISManager, |
||
| 145 | JITDylib &SourceJD, |
||
| 146 | SymbolAliasMap CallableAliases, |
||
| 147 | ImplSymbolMap *SrcJDLoc); |
||
| 148 | |||
| 149 | StringRef getName() const override; |
||
| 150 | |||
| 151 | private: |
||
| 152 | void materialize(std::unique_ptr<MaterializationResponsibility> R) override; |
||
| 153 | void discard(const JITDylib &JD, const SymbolStringPtr &Name) override; |
||
| 154 | static MaterializationUnit::Interface |
||
| 155 | extractFlags(const SymbolAliasMap &Aliases); |
||
| 156 | |||
| 157 | LazyCallThroughManager &LCTManager; |
||
| 158 | IndirectStubsManager &ISManager; |
||
| 159 | JITDylib &SourceJD; |
||
| 160 | SymbolAliasMap CallableAliases; |
||
| 161 | ImplSymbolMap *AliaseeTable; |
||
| 162 | }; |
||
| 163 | |||
| 164 | /// Define lazy-reexports based on the given SymbolAliasMap. Each lazy re-export |
||
| 165 | /// is a callable symbol that will look up and dispatch to the given aliasee on |
||
| 166 | /// first call. All subsequent calls will go directly to the aliasee. |
||
| 167 | inline std::unique_ptr<LazyReexportsMaterializationUnit> |
||
| 168 | lazyReexports(LazyCallThroughManager &LCTManager, |
||
| 169 | IndirectStubsManager &ISManager, JITDylib &SourceJD, |
||
| 170 | SymbolAliasMap CallableAliases, |
||
| 171 | ImplSymbolMap *SrcJDLoc = nullptr) { |
||
| 172 | return std::make_unique<LazyReexportsMaterializationUnit>( |
||
| 173 | LCTManager, ISManager, SourceJD, std::move(CallableAliases), SrcJDLoc); |
||
| 174 | } |
||
| 175 | |||
| 176 | } // End namespace orc |
||
| 177 | } // End namespace llvm |
||
| 178 | |||
| 179 | #endif // LLVM_EXECUTIONENGINE_ORC_LAZYREEXPORTS_H |