1 //===-- IndirectionUtils.h - Utilities for adding indirections --*- 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 // Contains utilities for adding indirections and breaking up modules.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
15 #define LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
17 #include "JITSymbol.h"
18 #include "llvm/IR/Mangler.h"
19 #include "llvm/IR/Module.h"
24 /// @brief Persistent name mangling.
26 /// This class provides name mangling that can outlive a Module (and its
28 class PersistentMangler {
30 PersistentMangler(DataLayout DL) : DL(std::move(DL)), M(&this->DL) {}
32 std::string getMangledName(StringRef Name) const {
33 std::string MangledName;
35 raw_string_ostream MangledNameStream(MangledName);
36 M.getNameWithPrefix(MangledNameStream, Name);
46 /// @brief Handle callbacks from the JIT process requesting the definitions of
49 /// This utility is intended to be used to support compile-on-demand for
51 class JITResolveCallbackHandler {
53 typedef std::vector<std::string> FuncNameList;
56 typedef FuncNameList::size_type StubIndex;
59 /// @brief Create a JITResolveCallbackHandler with the given functors for
60 /// looking up symbols and updating their use-sites.
62 /// @return A JITResolveCallbackHandler instance that will invoke the
63 /// Lookup and Update functors as needed to resolve missing symbol
65 template <typename LookupFtor, typename UpdateFtor>
66 static std::unique_ptr<JITResolveCallbackHandler> create(LookupFtor Lookup,
69 /// @brief Destroy instance. Does not modify existing emitted symbols.
71 /// Not-yet-emitted symbols will need to be resolved some other way after
72 /// this class is destroyed.
73 virtual ~JITResolveCallbackHandler() {}
75 /// @brief Add a function to be resolved on demand.
76 void addFuncName(std::string Name) { FuncNames.push_back(std::move(Name)); }
78 /// @brief Get the name associated with the given index.
79 const std::string &getFuncName(StubIndex Idx) const { return FuncNames[Idx]; }
81 /// @brief Returns the number of symbols being managed by this instance.
82 StubIndex getNumFuncs() const { return FuncNames.size(); }
84 /// @brief Get the address for the symbol associated with the given index.
86 /// This is expected to be called by code in the JIT process itself, in
87 /// order to resolve a function.
88 virtual TargetAddress resolve(StubIndex StubIdx) = 0;
91 FuncNameList FuncNames;
94 // Implementation class for JITResolveCallbackHandler.
95 template <typename LookupFtor, typename UpdateFtor>
96 class JITResolveCallbackHandlerImpl : public JITResolveCallbackHandler {
98 JITResolveCallbackHandlerImpl(LookupFtor Lookup, UpdateFtor Update)
99 : Lookup(std::move(Lookup)), Update(std::move(Update)) {}
101 TargetAddress resolve(StubIndex StubIdx) override {
102 const std::string &FuncName = getFuncName(StubIdx);
103 TargetAddress Addr = Lookup(FuncName);
104 Update(FuncName, Addr);
113 template <typename LookupFtor, typename UpdateFtor>
114 std::unique_ptr<JITResolveCallbackHandler>
115 JITResolveCallbackHandler::create(LookupFtor Lookup, UpdateFtor Update) {
116 typedef JITResolveCallbackHandlerImpl<LookupFtor, UpdateFtor> Impl;
117 return make_unique<Impl>(std::move(Lookup), std::move(Update));
120 /// @brief Holds a list of the function names that were indirected, plus
121 /// mappings from each of these names to (a) the name of function
122 /// providing the implementation for that name (GetImplNames), and
123 /// (b) the name of the global variable holding the address of the
126 /// This data structure can be used with a JITCallbackHandler to look up and
127 /// update function implementations when lazily compiling.
128 class JITIndirections {
130 JITIndirections(std::vector<std::string> IndirectedNames,
131 std::function<std::string(StringRef)> GetImplName,
132 std::function<std::string(StringRef)> GetAddrName)
133 : IndirectedNames(std::move(IndirectedNames)),
134 GetImplName(std::move(GetImplName)),
135 GetAddrName(std::move(GetAddrName)) {}
137 std::vector<std::string> IndirectedNames;
138 std::function<std::string(StringRef Name)> GetImplName;
139 std::function<std::string(StringRef Name)> GetAddrName;
142 /// @brief Indirect all calls to functions matching the predicate
143 /// ShouldIndirect through a global variable containing the address
144 /// of the implementation.
146 /// @return An indirection structure containing the functions that had their
147 /// call-sites re-written.
149 /// For each function 'F' that meets the ShouldIndirect predicate, and that
150 /// is called in this Module, add a common-linkage global variable to the
151 /// module that will hold the address of the implementation of that function.
152 /// Rewrite all call-sites of 'F' to be indirect calls (via the global).
153 /// This allows clients, either directly or via a JITCallbackHandler, to
154 /// change the address of the implementation of 'F' at runtime.
158 /// Single indirection does not preserve pointer equality for 'F'. If the
159 /// program was already calling 'F' indirectly through function pointers, or
160 /// if it was taking the address of 'F' for the purpose of pointer comparisons
161 /// or arithmetic double indirection should be used instead.
163 /// This method does *not* initialize the function implementation addresses.
164 /// The client must do this prior to running any call-sites that have been
166 JITIndirections makeCallsSingleIndirect(
168 const std::function<bool(const Function &)> &ShouldIndirect,
169 const char *JITImplSuffix, const char *JITAddrSuffix);
171 /// @brief Replace the body of functions matching the predicate ShouldIndirect
172 /// with indirect calls to the implementation.
174 /// @return An indirections structure containing the functions that had their
175 /// implementations re-written.
177 /// For each function 'F' that meets the ShouldIndirect predicate, add a
178 /// common-linkage global variable to the module that will hold the address of
179 /// the implementation of that function and rewrite the implementation of 'F'
180 /// to call through to the implementation indirectly (via the global).
181 /// This allows clients, either directly or via a JITCallbackHandler, to
182 /// change the address of the implementation of 'F' at runtime.
186 /// Double indirection is slower than single indirection, but preserves
187 /// function pointer relation tests and correct behavior for function pointers
188 /// (all calls to 'F', direct or indirect) go the address stored in the global
189 /// variable at the time of the call.
191 /// This method does *not* initialize the function implementation addresses.
192 /// The client must do this prior to running any call-sites that have been
194 JITIndirections makeCallsDoubleIndirect(
196 const std::function<bool(const Function &)> &ShouldIndirect,
197 const char *JITImplSuffix, const char *JITAddrSuffix);
199 /// @brief Given a set of indirections and a symbol lookup functor, create a
200 /// JITResolveCallbackHandler instance that will resolve the
201 /// implementations for the indirected symbols on demand.
202 template <typename SymbolLookupFtor>
203 std::unique_ptr<JITResolveCallbackHandler>
204 createCallbackHandlerFromJITIndirections(const JITIndirections &Indirs,
205 const PersistentMangler &NM,
206 SymbolLookupFtor Lookup) {
207 auto GetImplName = Indirs.GetImplName;
208 auto GetAddrName = Indirs.GetAddrName;
210 std::unique_ptr<JITResolveCallbackHandler> J =
211 JITResolveCallbackHandler::create(
212 [=](const std::string &S) {
213 return Lookup(NM.getMangledName(GetImplName(S)));
215 [=](const std::string &S, TargetAddress Addr) {
216 void *ImplPtr = reinterpret_cast<void *>(
217 Lookup(NM.getMangledName(GetAddrName(S))));
218 memcpy(ImplPtr, &Addr, sizeof(TargetAddress));
221 for (const auto &FuncName : Indirs.IndirectedNames)
222 J->addFuncName(FuncName);
227 /// @brief Insert callback asm into module M for the symbols managed by
228 /// JITResolveCallbackHandler J.
229 void insertX86CallbackAsm(Module &M, JITResolveCallbackHandler &J);
231 /// @brief Initialize global indirects to point into the callback asm.
232 template <typename LookupFtor>
233 void initializeFuncAddrs(JITResolveCallbackHandler &J,
234 const JITIndirections &Indirs,
235 const PersistentMangler &NM, LookupFtor Lookup) {
236 // Forward declare so that we can access this, even though it's an
237 // implementation detail.
238 std::string getJITResolveCallbackIndexLabel(unsigned I);
240 if (J.getNumFuncs() == 0)
243 // Force a look up one of the global addresses for a function that has been
244 // indirected. We need to do this to trigger the emission of the module
245 // holding the callback asm. We can't rely on that emission happening
246 // automatically when we look up the callback asm symbols, since lazy-emitting
247 // layers can't see those.
248 Lookup(NM.getMangledName(Indirs.GetAddrName(J.getFuncName(0))));
250 // Now update indirects to point to the JIT resolve callback asm.
251 for (JITResolveCallbackHandler::StubIndex I = 0; I < J.getNumFuncs(); ++I) {
252 TargetAddress ResolveCallbackIdxAddr =
253 Lookup(getJITResolveCallbackIndexLabel(I));
254 void *AddrPtr = reinterpret_cast<void *>(
255 Lookup(NM.getMangledName(Indirs.GetAddrName(J.getFuncName(I)))));
256 assert(AddrPtr && "Can't find stub addr global to initialize.");
257 memcpy(AddrPtr, &ResolveCallbackIdxAddr, sizeof(TargetAddress));
261 /// @brief Extract all functions matching the predicate ShouldExtract in to
262 /// their own modules. (Does not modify the original module.)
264 /// @return A set of modules, the first containing all symbols (including
265 /// globals and aliases) that did not pass ShouldExtract, and each
266 /// subsequent module containing one of the functions that did meet
269 /// By adding the resulting modules separately (not as a set) to a
270 /// LazyEmittingLayer instance, compilation can be deferred until symbols are
272 std::vector<std::unique_ptr<llvm::Module>>
273 explode(const llvm::Module &OrigMod,
274 const std::function<bool(const Function &)> &ShouldExtract);
276 /// @brief Given a module that has been indirectified, break each function
277 /// that has been indirected out into its own module. (Does not modify
278 /// the original module).
280 /// @returns A set of modules covering the symbols provided by OrigMod.
281 std::vector<std::unique_ptr<llvm::Module>>
282 explode(const llvm::Module &OrigMod, const JITIndirections &Indirections);
285 #endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H