1 //===------ LazyReexports.h -- Utilities for lazy reexports -----*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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.
15 //===----------------------------------------------------------------------===//
17 #ifndef LLVM_EXECUTIONENGINE_ORC_LAZYREEXPORTS_H
18 #define LLVM_EXECUTIONENGINE_ORC_LAZYREEXPORTS_H
20 #include "llvm/ExecutionEngine/Orc/Core.h"
21 #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
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.
35 /// The easiest way to construct these call-throughs is using the lazyReexport
37 class LazyCallThroughManager {
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 {
43 virtual ~NotifyResolvedFunction() {}
45 /// Called the first time a lazy call through is executed and the target
47 virtual Error operator()(JITDylib &SourceJD,
48 const SymbolStringPtr &SymbolName,
49 JITTargetAddress ResolvedAddr) = 0;
52 virtual void anchor();
55 template <typename NotifyResolvedImpl>
56 class NotifyResolvedFunctionImpl : public NotifyResolvedFunction {
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);
66 NotifyResolvedImpl NotifyResolved;
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));
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);
85 LazyCallThroughManager(ExecutionSession &ES,
86 JITTargetAddress ErrorHandlerAddr,
87 std::unique_ptr<TrampolinePool> TP);
89 JITTargetAddress callThroughToSymbol(JITTargetAddress TrampolineAddr);
91 void setTrampolinePool(std::unique_ptr<TrampolinePool> TP) {
92 this->TP = std::move(TP);
97 std::map<JITTargetAddress, std::pair<JITDylib *, SymbolStringPtr>>;
100 std::map<JITTargetAddress, std::shared_ptr<NotifyResolvedFunction>>;
102 std::mutex LCTMMutex;
103 ExecutionSession &ES;
104 JITTargetAddress ErrorHandlerAddr;
105 std::unique_ptr<TrampolinePool> TP;
106 ReexportsMap Reexports;
107 NotifiersMap Notifiers;
110 /// A lazy call-through manager that builds trampolines in the current process.
111 class LocalLazyCallThroughManager : public LazyCallThroughManager {
113 LocalLazyCallThroughManager(ExecutionSession &ES,
114 JITTargetAddress ErrorHandlerAddr)
115 : LazyCallThroughManager(ES, ErrorHandlerAddr, nullptr) {}
117 template <typename ORCABI> Error init() {
118 auto TP = LocalTrampolinePool<ORCABI>::Create(
119 [this](JITTargetAddress TrampolineAddr) {
120 return callThroughToSymbol(TrampolineAddr);
124 return TP.takeError();
126 setTrampolinePool(std::move(*TP));
127 return Error::success();
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));
139 if (auto Err = LLCTM->init<ORCABI>())
140 return std::move(Err);
142 return std::move(LLCTM);
146 /// Create a LocalLazyCallThroughManager from the given triple and execution
148 Expected<std::unique_ptr<LazyCallThroughManager>>
149 createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES,
150 JITTargetAddress ErrorHandlerAddr);
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 {
159 LazyReexportsMaterializationUnit(LazyCallThroughManager &LCTManager,
160 IndirectStubsManager &ISManager,
162 SymbolAliasMap CallableAliases,
165 StringRef getName() const override;
168 void materialize(MaterializationResponsibility R) override;
169 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
170 static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases);
172 LazyCallThroughManager &LCTManager;
173 IndirectStubsManager &ISManager;
175 SymbolAliasMap CallableAliases;
176 std::shared_ptr<LazyCallThroughManager::NotifyResolvedFunction>
180 /// Define lazy-reexports based on the given SymbolAliasMap. Each lazy re-export
181 /// is a callable symbol that will look up and dispatch to the given aliasee on
182 /// first call. All subsequent calls will go directly to the aliasee.
183 inline std::unique_ptr<LazyReexportsMaterializationUnit>
184 lazyReexports(LazyCallThroughManager &LCTManager,
185 IndirectStubsManager &ISManager, JITDylib &SourceJD,
186 SymbolAliasMap CallableAliases, VModuleKey K = VModuleKey()) {
187 return llvm::make_unique<LazyReexportsMaterializationUnit>(
188 LCTManager, ISManager, SourceJD, std::move(CallableAliases),
192 } // End namespace orc
193 } // End namespace llvm
195 #endif // LLVM_EXECUTIONENGINE_ORC_LAZYREEXPORTS_H