1 //===------ LazyReexports.h -- Utilities for lazy reexports -----*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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.
14 //===----------------------------------------------------------------------===//
16 #ifndef LLVM_EXECUTIONENGINE_ORC_LAZYREEXPORTS_H
17 #define LLVM_EXECUTIONENGINE_ORC_LAZYREEXPORTS_H
19 #include "llvm/ExecutionEngine/Orc/Core.h"
20 #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
21 #include "llvm/ExecutionEngine/Orc/Speculation.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 std::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
,
163 ImplSymbolMap
*SrcJDLoc
, VModuleKey K
);
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
>
178 ImplSymbolMap
*AliaseeTable
;
181 /// Define lazy-reexports based on the given SymbolAliasMap. Each lazy re-export
182 /// is a callable symbol that will look up and dispatch to the given aliasee on
183 /// first call. All subsequent calls will go directly to the aliasee.
184 inline std::unique_ptr
<LazyReexportsMaterializationUnit
>
185 lazyReexports(LazyCallThroughManager
&LCTManager
,
186 IndirectStubsManager
&ISManager
, JITDylib
&SourceJD
,
187 SymbolAliasMap CallableAliases
, ImplSymbolMap
*SrcJDLoc
= nullptr,
188 VModuleKey K
= VModuleKey()) {
189 return std::make_unique
<LazyReexportsMaterializationUnit
>(
190 LCTManager
, ISManager
, SourceJD
, std::move(CallableAliases
), SrcJDLoc
,
194 } // End namespace orc
195 } // End namespace llvm
197 #endif // LLVM_EXECUTIONENGINE_ORC_LAZYREEXPORTS_H