LLVM  4.0.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 "llvm/ADT/StringMap.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/ADT/Twine.h"
21 #include "llvm/IR/IRBuilder.h"
22 #include "llvm/IR/Mangler.h"
23 #include "llvm/IR/Module.h"
24 #include "llvm/Support/Error.h"
25 #include "llvm/Support/Memory.h"
26 #include "llvm/Support/Process.h"
28 #include <algorithm>
29 #include <cassert>
30 #include <cstdint>
31 #include <functional>
32 #include <map>
33 #include <memory>
34 #include <system_error>
35 #include <utility>
36 #include <vector>
37 
38 namespace llvm {
39 namespace orc {
40 
41 /// @brief Target-independent base class for compile callback management.
43 public:
44  typedef std::function<JITTargetAddress()> CompileFtor;
45 
46  /// @brief Handle to a newly created compile callback. Can be used to get an
47  /// IR constant representing the address of the trampoline, and to set
48  /// the compile action for the callback.
50  public:
52  : Addr(Addr), Compile(Compile) {}
53 
54  JITTargetAddress getAddress() const { return Addr; }
55  void setCompileAction(CompileFtor Compile) {
56  this->Compile = std::move(Compile);
57  }
58 
59  private:
60  JITTargetAddress Addr;
61  CompileFtor &Compile;
62  };
63 
64  /// @brief Construct a JITCompileCallbackManager.
65  /// @param ErrorHandlerAddress The address of an error handler in the target
66  /// process to be used if a compile callback fails.
68  : ErrorHandlerAddress(ErrorHandlerAddress) {}
69 
70  virtual ~JITCompileCallbackManager() = default;
71 
72  /// @brief Execute the callback for the given trampoline id. Called by the JIT
73  /// to compile functions on demand.
75  auto I = ActiveTrampolines.find(TrampolineAddr);
76  // FIXME: Also raise an error in the Orc error-handler when we finally have
77  // one.
78  if (I == ActiveTrampolines.end())
79  return ErrorHandlerAddress;
80 
81  // Found a callback handler. Yank this trampoline out of the active list and
82  // put it back in the available trampolines list, then try to run the
83  // handler's compile and update actions.
84  // Moving the trampoline ID back to the available list first means there's
85  // at
86  // least one available trampoline if the compile action triggers a request
87  // for
88  // a new one.
89  auto Compile = std::move(I->second);
90  ActiveTrampolines.erase(I);
91  AvailableTrampolines.push_back(TrampolineAddr);
92 
93  if (auto Addr = Compile())
94  return Addr;
95 
96  return ErrorHandlerAddress;
97  }
98 
99  /// @brief Reserve a compile callback.
101  JITTargetAddress TrampolineAddr = getAvailableTrampolineAddr();
102  auto &Compile = this->ActiveTrampolines[TrampolineAddr];
103  return CompileCallbackInfo(TrampolineAddr, Compile);
104  }
105 
106  /// @brief Get a CompileCallbackInfo for an existing callback.
108  auto I = ActiveTrampolines.find(TrampolineAddr);
109  assert(I != ActiveTrampolines.end() && "Not an active trampoline.");
110  return CompileCallbackInfo(I->first, I->second);
111  }
112 
113  /// @brief Release a compile callback.
114  ///
115  /// Note: Callbacks are auto-released after they execute. This method should
116  /// only be called to manually release a callback that is not going to
117  /// execute.
119  auto I = ActiveTrampolines.find(TrampolineAddr);
120  assert(I != ActiveTrampolines.end() && "Not an active trampoline.");
121  ActiveTrampolines.erase(I);
122  AvailableTrampolines.push_back(TrampolineAddr);
123  }
124 
125 protected:
127 
128  typedef std::map<JITTargetAddress, CompileFtor> TrampolineMapT;
130  std::vector<JITTargetAddress> AvailableTrampolines;
131 
132 private:
133  JITTargetAddress getAvailableTrampolineAddr() {
134  if (this->AvailableTrampolines.empty())
135  grow();
136  assert(!this->AvailableTrampolines.empty() &&
137  "Failed to grow available trampolines.");
138  JITTargetAddress TrampolineAddr = this->AvailableTrampolines.back();
139  this->AvailableTrampolines.pop_back();
140  return TrampolineAddr;
141  }
142 
143  // Create new trampolines - to be implemented in subclasses.
144  virtual void grow() = 0;
145 
146  virtual void anchor();
147 };
148 
149 /// @brief Manage compile callbacks for in-process JITs.
150 template <typename TargetT>
152 public:
153  /// @brief Construct a InProcessJITCompileCallbackManager.
154  /// @param ErrorHandlerAddress The address of an error handler in the target
155  /// process to be used if a compile callback fails.
157  : JITCompileCallbackManager(ErrorHandlerAddress) {
158 
159  /// Set up the resolver block.
160  std::error_code EC;
162  TargetT::ResolverCodeSize, nullptr,
164  assert(!EC && "Failed to allocate resolver block");
165 
166  TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()),
167  &reenter, this);
168 
172  assert(!EC && "Failed to mprotect resolver block");
173  }
174 
175 private:
176  static JITTargetAddress reenter(void *CCMgr, void *TrampolineId) {
178  static_cast<JITCompileCallbackManager *>(CCMgr);
179  return Mgr->executeCompileCallback(
180  static_cast<JITTargetAddress>(
181  reinterpret_cast<uintptr_t>(TrampolineId)));
182  }
183 
184  void grow() override {
185  assert(this->AvailableTrampolines.empty() && "Growing prematurely?");
186 
187  std::error_code EC;
188  auto TrampolineBlock =
190  sys::Process::getPageSize(), nullptr,
192  assert(!EC && "Failed to allocate trampoline block");
193 
194  unsigned NumTrampolines =
195  (sys::Process::getPageSize() - TargetT::PointerSize) /
196  TargetT::TrampolineSize;
197 
198  uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base());
199  TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
200  NumTrampolines);
201 
202  for (unsigned I = 0; I < NumTrampolines; ++I)
203  this->AvailableTrampolines.push_back(
204  static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(
205  TrampolineMem + (I * TargetT::TrampolineSize))));
206 
207  EC = sys::Memory::protectMappedMemory(TrampolineBlock.getMemoryBlock(),
210  assert(!EC && "Failed to mprotect trampoline block");
211 
212  TrampolineBlocks.push_back(std::move(TrampolineBlock));
213  }
214 
215  sys::OwningMemoryBlock ResolverBlock;
216  std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
217 };
218 
219 /// @brief Base class for managing collections of named indirect stubs.
221 public:
222  /// @brief Map type for initializing the manager. See init.
224 
225  virtual ~IndirectStubsManager() = default;
226 
227  /// @brief Create a single stub with the given name, target address and flags.
228  virtual Error createStub(StringRef StubName, JITTargetAddress StubAddr,
229  JITSymbolFlags StubFlags) = 0;
230 
231  /// @brief Create StubInits.size() stubs with the given names, target
232  /// addresses, and flags.
233  virtual Error createStubs(const StubInitsMap &StubInits) = 0;
234 
235  /// @brief Find the stub with the given name. If ExportedStubsOnly is true,
236  /// this will only return a result if the stub's flags indicate that it
237  /// is exported.
238  virtual JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) = 0;
239 
240  /// @brief Find the implementation-pointer for the stub.
241  virtual JITSymbol findPointer(StringRef Name) = 0;
242 
243  /// @brief Change the value of the implementation pointer for the stub.
244  virtual Error updatePointer(StringRef Name, JITTargetAddress NewAddr) = 0;
245 
246 private:
247  virtual void anchor();
248 };
249 
250 /// @brief IndirectStubsManager implementation for the host architecture, e.g.
251 /// OrcX86_64. (See OrcArchitectureSupport.h).
252 template <typename TargetT>
254 public:
256  JITSymbolFlags StubFlags) override {
257  if (auto Err = reserveStubs(1))
258  return Err;
259 
260  createStubInternal(StubName, StubAddr, StubFlags);
261 
262  return Error::success();
263  }
264 
265  Error createStubs(const StubInitsMap &StubInits) override {
266  if (auto Err = reserveStubs(StubInits.size()))
267  return Err;
268 
269  for (auto &Entry : StubInits)
270  createStubInternal(Entry.first(), Entry.second.first,
271  Entry.second.second);
272 
273  return Error::success();
274  }
275 
276  JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
277  auto I = StubIndexes.find(Name);
278  if (I == StubIndexes.end())
279  return nullptr;
280  auto Key = I->second.first;
281  void *StubAddr = IndirectStubsInfos[Key.first].getStub(Key.second);
282  assert(StubAddr && "Missing stub address");
283  auto StubTargetAddr =
284  static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(StubAddr));
285  auto StubSymbol = JITSymbol(StubTargetAddr, I->second.second);
286  if (ExportedStubsOnly && !StubSymbol.getFlags().isExported())
287  return nullptr;
288  return StubSymbol;
289  }
290 
292  auto I = StubIndexes.find(Name);
293  if (I == StubIndexes.end())
294  return nullptr;
295  auto Key = I->second.first;
296  void *PtrAddr = IndirectStubsInfos[Key.first].getPtr(Key.second);
297  assert(PtrAddr && "Missing pointer address");
298  auto PtrTargetAddr =
299  static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(PtrAddr));
300  return JITSymbol(PtrTargetAddr, I->second.second);
301  }
302 
304  auto I = StubIndexes.find(Name);
305  assert(I != StubIndexes.end() && "No stub pointer for symbol");
306  auto Key = I->second.first;
307  *IndirectStubsInfos[Key.first].getPtr(Key.second) =
308  reinterpret_cast<void *>(static_cast<uintptr_t>(NewAddr));
309  return Error::success();
310  }
311 
312 private:
313  Error reserveStubs(unsigned NumStubs) {
314  if (NumStubs <= FreeStubs.size())
315  return Error::success();
316 
317  unsigned NewStubsRequired = NumStubs - FreeStubs.size();
318  unsigned NewBlockId = IndirectStubsInfos.size();
319  typename TargetT::IndirectStubsInfo ISI;
320  if (auto Err =
321  TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired, nullptr))
322  return Err;
323  for (unsigned I = 0; I < ISI.getNumStubs(); ++I)
324  FreeStubs.push_back(std::make_pair(NewBlockId, I));
325  IndirectStubsInfos.push_back(std::move(ISI));
326  return Error::success();
327  }
328 
329  void createStubInternal(StringRef StubName, JITTargetAddress InitAddr,
330  JITSymbolFlags StubFlags) {
331  auto Key = FreeStubs.back();
332  FreeStubs.pop_back();
333  *IndirectStubsInfos[Key.first].getPtr(Key.second) =
334  reinterpret_cast<void *>(static_cast<uintptr_t>(InitAddr));
335  StubIndexes[StubName] = std::make_pair(Key, StubFlags);
336  }
337 
338  std::vector<typename TargetT::IndirectStubsInfo> IndirectStubsInfos;
339  typedef std::pair<uint16_t, uint16_t> StubKey;
340  std::vector<StubKey> FreeStubs;
341  StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
342 };
343 
344 /// @brief Create a local compile callback manager.
345 ///
346 /// The given target triple will determine the ABI, and the given
347 /// ErrorHandlerAddress will be used by the resulting compile callback
348 /// manager if a compile callback fails.
349 std::unique_ptr<JITCompileCallbackManager>
351  JITTargetAddress ErrorHandlerAddress);
352 
353 /// @brief Create a local indriect stubs manager builder.
354 ///
355 /// The given target triple will determine the ABI.
356 std::function<std::unique_ptr<IndirectStubsManager>()>
358 
359 /// @brief Build a function pointer of FunctionType with the given constant
360 /// address.
361 ///
362 /// Usage example: Turn a trampoline address into a function pointer constant
363 /// for use in a stub.
364 Constant *createIRTypedAddress(FunctionType &FT, JITTargetAddress Addr);
365 
366 /// @brief Create a function pointer with the given type, name, and initializer
367 /// in the given Module.
368 GlobalVariable *createImplPointer(PointerType &PT, Module &M, const Twine &Name,
369  Constant *Initializer);
370 
371 /// @brief Turn a function declaration into a stub function that makes an
372 /// indirect call using the given function pointer.
373 void makeStub(Function &F, Value &ImplPointer);
374 
375 /// @brief Raise linkage types and rename as necessary to ensure that all
376 /// symbols are accessible for other modules.
377 ///
378 /// This should be called before partitioning a module to ensure that the
379 /// partitions retain access to each other's symbols.
380 void makeAllSymbolsExternallyAccessible(Module &M);
381 
382 /// @brief Clone a function declaration into a new module.
383 ///
384 /// This function can be used as the first step towards creating a callback
385 /// stub (see makeStub), or moving a function body (see moveFunctionBody).
386 ///
387 /// If the VMap argument is non-null, a mapping will be added between F and
388 /// the new declaration, and between each of F's arguments and the new
389 /// declaration's arguments. This map can then be passed in to moveFunction to
390 /// move the function body if required. Note: When moving functions between
391 /// modules with these utilities, all decls should be cloned (and added to a
392 /// single VMap) before any bodies are moved. This will ensure that references
393 /// between functions all refer to the versions in the new module.
394 Function *cloneFunctionDecl(Module &Dst, const Function &F,
395  ValueToValueMapTy *VMap = nullptr);
396 
397 /// @brief Move the body of function 'F' to a cloned function declaration in a
398 /// different module (See related cloneFunctionDecl).
399 ///
400 /// If the target function declaration is not supplied via the NewF parameter
401 /// then it will be looked up via the VMap.
402 ///
403 /// This will delete the body of function 'F' from its original parent module,
404 /// but leave its declaration.
405 void moveFunctionBody(Function &OrigF, ValueToValueMapTy &VMap,
406  ValueMaterializer *Materializer = nullptr,
407  Function *NewF = nullptr);
408 
409 /// @brief Clone a global variable declaration into a new module.
410 GlobalVariable *cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV,
411  ValueToValueMapTy *VMap = nullptr);
412 
413 /// @brief Move global variable GV from its parent module to cloned global
414 /// declaration in a different module.
415 ///
416 /// If the target global declaration is not supplied via the NewGV parameter
417 /// then it will be looked up via the VMap.
418 ///
419 /// This will delete the initializer of GV from its original parent module,
420 /// but leave its declaration.
421 void moveGlobalVariableInitializer(GlobalVariable &OrigGV,
422  ValueToValueMapTy &VMap,
423  ValueMaterializer *Materializer = nullptr,
424  GlobalVariable *NewGV = nullptr);
425 
426 /// @brief Clone a global alias declaration into a new module.
427 GlobalAlias *cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA,
428  ValueToValueMapTy &VMap);
429 
430 /// @brief Clone module flags metadata into the destination module.
431 void cloneModuleFlagsMetadata(Module &Dst, const Module &Src,
432  ValueToValueMapTy &VMap);
433 
434 } // end namespace orc
435 } // end namespace llvm
436 
437 #endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
IndirectStubsManager implementation for the host architecture, e.g.
Base class for managing collections of named indirect stubs.
Represents a symbol in the JIT.
Definition: JITSymbol.h:113
std::function< std::unique_ptr< IndirectStubsManager >)> createLocalIndirectStubsManagerBuilder(const Triple &T)
Create a local indriect stubs manager builder.
GlobalAlias * cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA, ValueToValueMapTy &VMap)
Clone a global alias declaration into a new module.
std::map< JITTargetAddress, CompileFtor > TrampolineMapT
void cloneModuleFlagsMetadata(Module &Dst, const Module &Src, ValueToValueMapTy &VMap)
Clone module flags metadata into the destination module.
virtual JITSymbol findStub(StringRef Name, bool ExportedStubsOnly)=0
Find the stub with the given name.
std::function< JITTargetAddress()> CompileFtor
Manage compile callbacks for in-process JITs.
static MemoryBlock allocateMappedMemory(size_t NumBytes, const MemoryBlock *const NearBlock, unsigned Flags, std::error_code &EC)
This method allocates a block of memory that is suitable for loading dynamically generated code (e...
Target-independent base class for compile callback management.
Handle to a newly created compile callback.
Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override
Change the value of the implementation pointer for the stub.
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...
std::unique_ptr< JITCompileCallbackManager > createLocalCompileCallbackManager(const Triple &T, JITTargetAddress ErrorHandlerAddress)
Create a local compile callback manager.
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...
virtual Error createStub(StringRef StubName, JITTargetAddress StubAddr, JITSymbolFlags StubFlags)=0
Create a single stub with the given name, target address and flags.
void makeStub(Function &F, Value &ImplPointer)
Turn a function declaration into a stub function that makes an indirect call using the given function...
#define F(x, y, z)
Definition: MD5.cpp:51
CompileCallbackInfo getCompileCallback()
Reserve a compile callback.
StringMap< std::pair< JITTargetAddress, JITSymbolFlags > > StubInitsMap
Map type for initializing the manager. See init.
std::vector< JITTargetAddress > AvailableTrampolines
GlobalVariable * cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV, ValueToValueMapTy *VMap=nullptr)
Clone a global variable declaration into a new module.
MemoryBlock getMemoryBlock() const
Definition: Memory.h:178
CompileCallbackInfo(JITTargetAddress Addr, CompileFtor &Compile)
CompileCallbackInfo getCompileCallbackInfo(JITTargetAddress TrampolineAddr)
Get a CompileCallbackInfo for an existing callback.
unsigned size() const
Definition: StringMap.h:114
Flags for symbols in the JIT.
Definition: JITSymbol.h:36
uint64_t JITTargetAddress
Represents an address in the target process's address space.
Definition: JITSymbol.h:33
ValueMap< const Value *, WeakVH > ValueToValueMapTy
Definition: ValueMapper.h:23
void releaseCompileCallback(JITTargetAddress TrampolineAddr)
Release a compile callback.
static unsigned getPageSize()
Constant * createIRTypedAddress(FunctionType &FT, JITTargetAddress Addr)
Build a function pointer of FunctionType with the given constant address.
static ErrorSuccess success()
Create a success value.
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.
Error createStub(StringRef StubName, JITTargetAddress StubAddr, JITSymbolFlags StubFlags) override
Create a single stub with the given name, target address and flags.
virtual ~IndirectStubsManager()=default
Owning version of MemoryBlock.
Definition: Memory.h:160
JITSymbol findPointer(StringRef Name) override
Find the implementation-pointer for the stub.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings"...
Definition: StringMap.h:223
void makeAllSymbolsExternallyAccessible(Module &M)
Raise linkage types and rename as necessary to ensure that all symbols are accessible for other modul...
virtual JITSymbol findPointer(StringRef Name)=0
Find the implementation-pointer for the stub.
JITTargetAddress executeCompileCallback(JITTargetAddress TrampolineAddr)
Execute the callback for the given trampoline id.
Provides a library for accessing information about this process and other processes on the operating ...
virtual Error updatePointer(StringRef Name, JITTargetAddress NewAddr)=0
Change the value of the implementation pointer for the stub.
void * base() const
Definition: Memory.h:176
#define I(x, y, z)
Definition: MD5.cpp:54
LocalJITCompileCallbackManager(JITTargetAddress ErrorHandlerAddress)
Construct a InProcessJITCompileCallbackManager.
JITCompileCallbackManager(JITTargetAddress ErrorHandlerAddress)
Construct a JITCompileCallbackManager.
Error createStubs(const StubInitsMap &StubInits) override
Create StubInits.size() stubs with the given names, target addresses, and flags.
virtual ~JITCompileCallbackManager()=default
virtual Error createStubs(const StubInitsMap &StubInits)=0
Create StubInits.size() stubs with the given names, target addresses, and flags.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Lightweight error class with error context and mandatory checking.
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:47
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...
JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override
Find the stub with the given name.
static std::error_code protectMappedMemory(const MemoryBlock &Block, unsigned Flags)
This method sets the protection flags for a block of memory to the state specified by /p Flags...