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