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