LLVM  3.7.0
IndirectionUtils.h
Go to the documentation of this file.
1 //===-- IndirectionUtils.h - Utilities for adding indirections --*- 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 // Contains utilities for adding indirections and breaking up modules.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
15 #define LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
16 
17 #include "JITSymbol.h"
18 #include "LambdaResolver.h"
19 #include "llvm/ADT/DenseSet.h"
21 #include "llvm/IR/IRBuilder.h"
22 #include "llvm/IR/Mangler.h"
23 #include "llvm/IR/Module.h"
25 #include <sstream>
26 
27 namespace llvm {
28 namespace orc {
29 
30 /// @brief Base class for JITLayer independent aspects of
31 /// JITCompileCallbackManager.
33 public:
34 
35  typedef std::function<TargetAddress()> CompileFtor;
36 
37  /// @brief Handle to a newly created compile callback. Can be used to get an
38  /// IR constant representing the address of the trampoline, and to set
39  /// the compile action for the callback.
41  public:
43  : Addr(Addr), Compile(Compile) {}
44 
45  TargetAddress getAddress() const { return Addr; }
46  void setCompileAction(CompileFtor Compile) {
47  this->Compile = std::move(Compile);
48  }
49  private:
50  TargetAddress Addr;
51  CompileFtor &Compile;
52  };
53 
54  /// @brief Construct a JITCompileCallbackManagerBase.
55  /// @param ErrorHandlerAddress The address of an error handler in the target
56  /// process to be used if a compile callback fails.
57  /// @param NumTrampolinesPerBlock Number of trampolines to emit if there is no
58  /// available trampoline when getCompileCallback is
59  /// called.
61  unsigned NumTrampolinesPerBlock)
62  : ErrorHandlerAddress(ErrorHandlerAddress),
63  NumTrampolinesPerBlock(NumTrampolinesPerBlock) {}
64 
66 
67  /// @brief Execute the callback for the given trampoline id. Called by the JIT
68  /// to compile functions on demand.
70  auto I = ActiveTrampolines.find(TrampolineAddr);
71  // FIXME: Also raise an error in the Orc error-handler when we finally have
72  // one.
73  if (I == ActiveTrampolines.end())
74  return ErrorHandlerAddress;
75 
76  // Found a callback handler. Yank this trampoline out of the active list and
77  // put it back in the available trampolines list, then try to run the
78  // handler's compile and update actions.
79  // Moving the trampoline ID back to the available list first means there's at
80  // least one available trampoline if the compile action triggers a request for
81  // a new one.
82  auto Compile = std::move(I->second);
83  ActiveTrampolines.erase(I);
84  AvailableTrampolines.push_back(TrampolineAddr);
85 
86  if (auto Addr = Compile())
87  return Addr;
88 
89  return ErrorHandlerAddress;
90  }
91 
92  /// @brief Reserve a compile callback.
93  virtual CompileCallbackInfo getCompileCallback(LLVMContext &Context) = 0;
94 
95  /// @brief Get a CompileCallbackInfo for an existing callback.
97  auto I = ActiveTrampolines.find(TrampolineAddr);
98  assert(I != ActiveTrampolines.end() && "Not an active trampoline.");
99  return CompileCallbackInfo(I->first, I->second);
100  }
101 
102  /// @brief Release a compile callback.
103  ///
104  /// Note: Callbacks are auto-released after they execute. This method should
105  /// only be called to manually release a callback that is not going to
106  /// execute.
107  void releaseCompileCallback(TargetAddress TrampolineAddr) {
108  auto I = ActiveTrampolines.find(TrampolineAddr);
109  assert(I != ActiveTrampolines.end() && "Not an active trampoline.");
110  ActiveTrampolines.erase(I);
111  AvailableTrampolines.push_back(TrampolineAddr);
112  }
113 
114 protected:
117 
118  typedef std::map<TargetAddress, CompileFtor> TrampolineMapT;
120  std::vector<TargetAddress> AvailableTrampolines;
121 };
122 
123 /// @brief Manage compile callbacks.
124 template <typename JITLayerT, typename TargetT>
126 public:
127 
128  /// @brief Construct a JITCompileCallbackManager.
129  /// @param JIT JIT layer to emit callback trampolines, etc. into.
130  /// @param Context LLVMContext to use for trampoline & resolve block modules.
131  /// @param ErrorHandlerAddress The address of an error handler in the target
132  /// process to be used if a compile callback fails.
133  /// @param NumTrampolinesPerBlock Number of trampolines to allocate whenever
134  /// there is no existing callback trampoline.
135  /// (Trampolines are allocated in blocks for
136  /// efficiency.)
138  LLVMContext &Context,
140  unsigned NumTrampolinesPerBlock)
141  : JITCompileCallbackManagerBase(ErrorHandlerAddress,
142  NumTrampolinesPerBlock),
143  JIT(JIT), MemMgr(MemMgr) {
144  emitResolverBlock(Context);
145  }
146 
147  /// @brief Get/create a compile callback with the given signature.
149  TargetAddress TrampolineAddr = getAvailableTrampolineAddr(Context);
150  auto &Compile = this->ActiveTrampolines[TrampolineAddr];
151  return CompileCallbackInfo(TrampolineAddr, Compile);
152  }
153 
154 private:
155 
156  std::vector<std::unique_ptr<Module>>
157  SingletonSet(std::unique_ptr<Module> M) {
158  std::vector<std::unique_ptr<Module>> Ms;
159  Ms.push_back(std::move(M));
160  return Ms;
161  }
162 
163  void emitResolverBlock(LLVMContext &Context) {
164  std::unique_ptr<Module> M(new Module("resolver_block_module",
165  Context));
166  TargetT::insertResolverBlock(*M, *this);
167  auto NonResolver =
169  [](const std::string &Name) -> RuntimeDyld::SymbolInfo {
170  llvm_unreachable("External symbols in resolver block?");
171  },
172  [](const std::string &Name) -> RuntimeDyld::SymbolInfo {
173  llvm_unreachable("Dylib symbols in resolver block?");
174  });
175  auto H = JIT.addModuleSet(SingletonSet(std::move(M)), &MemMgr,
176  std::move(NonResolver));
177  JIT.emitAndFinalize(H);
178  auto ResolverBlockSymbol =
179  JIT.findSymbolIn(H, TargetT::ResolverBlockName, false);
180  assert(ResolverBlockSymbol && "Failed to insert resolver block");
181  ResolverBlockAddr = ResolverBlockSymbol.getAddress();
182  }
183 
184  TargetAddress getAvailableTrampolineAddr(LLVMContext &Context) {
185  if (this->AvailableTrampolines.empty())
186  grow(Context);
187  assert(!this->AvailableTrampolines.empty() &&
188  "Failed to grow available trampolines.");
189  TargetAddress TrampolineAddr = this->AvailableTrampolines.back();
190  this->AvailableTrampolines.pop_back();
191  return TrampolineAddr;
192  }
193 
194  void grow(LLVMContext &Context) {
195  assert(this->AvailableTrampolines.empty() && "Growing prematurely?");
196  std::unique_ptr<Module> M(new Module("trampoline_block", Context));
197  auto GetLabelName =
198  TargetT::insertCompileCallbackTrampolines(*M, ResolverBlockAddr,
200  this->ActiveTrampolines.size());
201  auto NonResolver =
203  [](const std::string &Name) -> RuntimeDyld::SymbolInfo {
204  llvm_unreachable("External symbols in trampoline block?");
205  },
206  [](const std::string &Name) -> RuntimeDyld::SymbolInfo {
207  llvm_unreachable("Dylib symbols in trampoline block?");
208  });
209  auto H = JIT.addModuleSet(SingletonSet(std::move(M)), &MemMgr,
210  std::move(NonResolver));
211  JIT.emitAndFinalize(H);
212  for (unsigned I = 0; I < this->NumTrampolinesPerBlock; ++I) {
213  std::string Name = GetLabelName(I);
214  auto TrampolineSymbol = JIT.findSymbolIn(H, Name, false);
215  assert(TrampolineSymbol && "Failed to emit trampoline.");
216  this->AvailableTrampolines.push_back(TrampolineSymbol.getAddress());
217  }
218  }
219 
220  JITLayerT &JIT;
221  RuntimeDyld::MemoryManager &MemMgr;
222  TargetAddress ResolverBlockAddr;
223 };
224 
225 /// @brief Build a function pointer of FunctionType with the given constant
226 /// address.
227 ///
228 /// Usage example: Turn a trampoline address into a function pointer constant
229 /// for use in a stub.
230 Constant* createIRTypedAddress(FunctionType &FT, TargetAddress Addr);
231 
232 /// @brief Create a function pointer with the given type, name, and initializer
233 /// in the given Module.
234 GlobalVariable* createImplPointer(PointerType &PT, Module &M,
235  const Twine &Name, Constant *Initializer);
236 
237 /// @brief Turn a function declaration into a stub function that makes an
238 /// indirect call using the given function pointer.
239 void makeStub(Function &F, GlobalVariable &ImplPointer);
240 
241 /// @brief Raise linkage types and rename as necessary to ensure that all
242 /// symbols are accessible for other modules.
243 ///
244 /// This should be called before partitioning a module to ensure that the
245 /// partitions retain access to each other's symbols.
246 void makeAllSymbolsExternallyAccessible(Module &M);
247 
248 /// @brief Clone a function declaration into a new module.
249 ///
250 /// This function can be used as the first step towards creating a callback
251 /// stub (see makeStub), or moving a function body (see moveFunctionBody).
252 ///
253 /// If the VMap argument is non-null, a mapping will be added between F and
254 /// the new declaration, and between each of F's arguments and the new
255 /// declaration's arguments. This map can then be passed in to moveFunction to
256 /// move the function body if required. Note: When moving functions between
257 /// modules with these utilities, all decls should be cloned (and added to a
258 /// single VMap) before any bodies are moved. This will ensure that references
259 /// between functions all refer to the versions in the new module.
260 Function* cloneFunctionDecl(Module &Dst, const Function &F,
261  ValueToValueMapTy *VMap = nullptr);
262 
263 /// @brief Move the body of function 'F' to a cloned function declaration in a
264 /// different module (See related cloneFunctionDecl).
265 ///
266 /// If the target function declaration is not supplied via the NewF parameter
267 /// then it will be looked up via the VMap.
268 ///
269 /// This will delete the body of function 'F' from its original parent module,
270 /// but leave its declaration.
271 void moveFunctionBody(Function &OrigF, ValueToValueMapTy &VMap,
272  ValueMaterializer *Materializer = nullptr,
273  Function *NewF = nullptr);
274 
275 /// @brief Clone a global variable declaration into a new module.
276 GlobalVariable* cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV,
277  ValueToValueMapTy *VMap = nullptr);
278 
279 /// @brief Move global variable GV from its parent module to cloned global
280 /// declaration in a different module.
281 ///
282 /// If the target global declaration is not supplied via the NewGV parameter
283 /// then it will be looked up via the VMap.
284 ///
285 /// This will delete the initializer of GV from its original parent module,
286 /// but leave its declaration.
287 void moveGlobalVariableInitializer(GlobalVariable &OrigGV,
288  ValueToValueMapTy &VMap,
289  ValueMaterializer *Materializer = nullptr,
290  GlobalVariable *NewGV = nullptr);
291 
292 } // End namespace orc.
293 } // End namespace llvm.
294 
295 #endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
std::function< TargetAddress()> CompileFtor
std::vector< TargetAddress > AvailableTrampolines
A Module instance is used to store all the information related to an LLVM module. ...
Definition: Module.h:114
F(f)
GlobalVariable * createImplPointer(PointerType &PT, Module &M, const Twine &Name, Constant *Initializer)
Create a function pointer with the given type, name, and initializer in the given Module...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:98
Constant * createIRTypedAddress(FunctionType &FT, TargetAddress Addr)
Build a function pointer of FunctionType with the given constant address.
void moveGlobalVariableInitializer(GlobalVariable &OrigGV, ValueToValueMapTy &VMap, ValueMaterializer *Materializer=nullptr, GlobalVariable *NewGV=nullptr)
Move global variable GV from its parent module to cloned global declaration in a different module...
CompileCallbackInfo(TargetAddress Addr, CompileFtor &Compile)
GlobalVariable * cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV, ValueToValueMapTy *VMap=nullptr)
Clone a global variable declaration into a new module.
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:41
CompileCallbackInfo getCompileCallback(LLVMContext &Context) final
Get/create a compile callback with the given signature.
void releaseCompileCallback(TargetAddress TrampolineAddr)
Release a compile callback.
Base class for JITLayer independent aspects of JITCompileCallbackManager.
#define H(x, y, z)
Definition: MD5.cpp:53
TargetAddress executeCompileCallback(TargetAddress TrampolineAddr)
Execute the callback for the given trampoline id.
std::map< TargetAddress, CompileFtor > TrampolineMapT
ValueMap< const Value *, WeakVH > ValueToValueMapTy
Definition: ValueMapper.h:22
Handle to a newly created compile callback.
virtual CompileCallbackInfo getCompileCallback(LLVMContext &Context)=0
Reserve a compile callback.
Function * cloneFunctionDecl(Module &Dst, const Function &F, ValueToValueMapTy *VMap=nullptr)
Clone a function declaration into a new module.
Module.h This file contains the declarations for the Module class.
uint64_t TargetAddress
Represents an address in the target process's address space.
Definition: JITSymbol.h:26
std::unique_ptr< LambdaResolver< ExternalLookupFtorT, DylibLookupFtorT > > createLambdaResolver(ExternalLookupFtorT ExternalLookupFtor, DylibLookupFtorT DylibLookupFtor)
void makeAllSymbolsExternallyAccessible(Module &M)
Raise linkage types and rename as necessary to ensure that all symbols are accessible for other modul...
JITCompileCallbackManagerBase(TargetAddress ErrorHandlerAddress, unsigned NumTrampolinesPerBlock)
Construct a JITCompileCallbackManagerBase.
#define I(x, y, z)
Definition: MD5.cpp:54
void makeStub(Function &F, GlobalVariable &ImplPointer)
Turn a function declaration into a stub function that makes an indirect call using the given function...
Information about a named symbol.
Definition: RuntimeDyld.h:47
JITCompileCallbackManager(JITLayerT &JIT, RuntimeDyld::MemoryManager &MemMgr, LLVMContext &Context, TargetAddress ErrorHandlerAddress, unsigned NumTrampolinesPerBlock)
Construct a JITCompileCallbackManager.
CompileCallbackInfo getCompileCallbackInfo(TargetAddress TrampolineAddr)
Get a CompileCallbackInfo for an existing callback.
void moveFunctionBody(Function &OrigF, ValueToValueMapTy &VMap, ValueMaterializer *Materializer=nullptr, Function *NewF=nullptr)
Move the body of function 'F' to a cloned function declaration in a different module (See related clo...