LLVM  7.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"
22 #include "llvm/Support/Error.h"
23 #include "llvm/Support/Memory.h"
24 #include "llvm/Support/Process.h"
26 #include <algorithm>
27 #include <cassert>
28 #include <cstdint>
29 #include <functional>
30 #include <map>
31 #include <memory>
32 #include <system_error>
33 #include <utility>
34 #include <vector>
35 
36 namespace llvm {
37 
38 class Constant;
39 class Function;
40 class FunctionType;
41 class GlobalAlias;
42 class GlobalVariable;
43 class Module;
44 class PointerType;
45 class Triple;
46 class Value;
47 
48 namespace orc {
49 
50 /// Target-independent base class for compile callback management.
52 public:
53  using CompileFunction = std::function<JITTargetAddress()>;
54 
55  /// Construct a JITCompileCallbackManager.
56  /// @param ErrorHandlerAddress The address of an error handler in the target
57  /// process to be used if a compile callback fails.
59  JITTargetAddress ErrorHandlerAddress)
60  : ES(ES), CallbacksVSO(ES.createVSO("<Callbacks>")),
61  ErrorHandlerAddress(ErrorHandlerAddress) {}
62 
63  virtual ~JITCompileCallbackManager() = default;
64 
65  /// Reserve a compile callback.
67 
68  /// Execute the callback for the given trampoline id. Called by the JIT
69  /// to compile functions on demand.
71 
72 protected:
73  std::vector<JITTargetAddress> AvailableTrampolines;
74 
75 private:
76  Expected<JITTargetAddress> getAvailableTrampolineAddr() {
77  if (this->AvailableTrampolines.empty())
78  if (auto Err = grow())
79  return std::move(Err);
80  assert(!this->AvailableTrampolines.empty() &&
81  "Failed to grow available trampolines.");
82  JITTargetAddress TrampolineAddr = this->AvailableTrampolines.back();
83  this->AvailableTrampolines.pop_back();
84  return TrampolineAddr;
85  }
86 
87  // Create new trampolines - to be implemented in subclasses.
88  virtual Error grow() = 0;
89 
90  virtual void anchor();
91 
92  std::mutex CCMgrMutex;
93  ExecutionSession &ES;
94  VSO &CallbacksVSO;
95  JITTargetAddress ErrorHandlerAddress;
96  std::map<JITTargetAddress, SymbolStringPtr> AddrToSymbol;
97  size_t NextCallbackId = 0;
98 };
99 
100 /// Manage compile callbacks for in-process JITs.
101 template <typename TargetT>
103 public:
104  /// Construct a InProcessJITCompileCallbackManager.
105  /// @param ErrorHandlerAddress The address of an error handler in the target
106  /// process to be used if a compile callback fails.
108  JITTargetAddress ErrorHandlerAddress)
109  : JITCompileCallbackManager(ES, ErrorHandlerAddress) {
110  /// Set up the resolver block.
111  std::error_code EC;
113  TargetT::ResolverCodeSize, nullptr,
115  assert(!EC && "Failed to allocate resolver block");
116 
117  TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()),
118  &reenter, this);
119 
120  EC = sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(),
123  assert(!EC && "Failed to mprotect resolver block");
124  }
125 
126 private:
127  static JITTargetAddress reenter(void *CCMgr, void *TrampolineId) {
129  static_cast<JITCompileCallbackManager *>(CCMgr);
130  return Mgr->executeCompileCallback(
131  static_cast<JITTargetAddress>(
132  reinterpret_cast<uintptr_t>(TrampolineId)));
133  }
134 
135  Error grow() override {
136  assert(this->AvailableTrampolines.empty() && "Growing prematurely?");
137 
138  std::error_code EC;
139  auto TrampolineBlock =
141  sys::Process::getPageSize(), nullptr,
143  if (EC)
144  return errorCodeToError(EC);
145 
146  unsigned NumTrampolines =
147  (sys::Process::getPageSize() - TargetT::PointerSize) /
148  TargetT::TrampolineSize;
149 
150  uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base());
151  TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
152  NumTrampolines);
153 
154  for (unsigned I = 0; I < NumTrampolines; ++I)
155  this->AvailableTrampolines.push_back(
156  static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(
157  TrampolineMem + (I * TargetT::TrampolineSize))));
158 
159  if (auto EC = sys::Memory::protectMappedMemory(
160  TrampolineBlock.getMemoryBlock(),
162  return errorCodeToError(EC);
163 
164  TrampolineBlocks.push_back(std::move(TrampolineBlock));
165  return Error::success();
166  }
167 
168  sys::OwningMemoryBlock ResolverBlock;
169  std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
170 };
171 
172 /// Base class for managing collections of named indirect stubs.
174 public:
175  /// Map type for initializing the manager. See init.
177 
178  virtual ~IndirectStubsManager() = default;
179 
180  /// Create a single stub with the given name, target address and flags.
181  virtual Error createStub(StringRef StubName, JITTargetAddress StubAddr,
182  JITSymbolFlags StubFlags) = 0;
183 
184  /// Create StubInits.size() stubs with the given names, target
185  /// addresses, and flags.
186  virtual Error createStubs(const StubInitsMap &StubInits) = 0;
187 
188  /// Find the stub with the given name. If ExportedStubsOnly is true,
189  /// this will only return a result if the stub's flags indicate that it
190  /// is exported.
191  virtual JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) = 0;
192 
193  /// Find the implementation-pointer for the stub.
194  virtual JITEvaluatedSymbol findPointer(StringRef Name) = 0;
195 
196  /// Change the value of the implementation pointer for the stub.
197  virtual Error updatePointer(StringRef Name, JITTargetAddress NewAddr) = 0;
198 
199 private:
200  virtual void anchor();
201 };
202 
203 /// IndirectStubsManager implementation for the host architecture, e.g.
204 /// OrcX86_64. (See OrcArchitectureSupport.h).
205 template <typename TargetT>
207 public:
209  JITSymbolFlags StubFlags) override {
210  if (auto Err = reserveStubs(1))
211  return Err;
212 
213  createStubInternal(StubName, StubAddr, StubFlags);
214 
215  return Error::success();
216  }
217 
218  Error createStubs(const StubInitsMap &StubInits) override {
219  if (auto Err = reserveStubs(StubInits.size()))
220  return Err;
221 
222  for (auto &Entry : StubInits)
223  createStubInternal(Entry.first(), Entry.second.first,
224  Entry.second.second);
225 
226  return Error::success();
227  }
228 
229  JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
230  auto I = StubIndexes.find(Name);
231  if (I == StubIndexes.end())
232  return nullptr;
233  auto Key = I->second.first;
234  void *StubAddr = IndirectStubsInfos[Key.first].getStub(Key.second);
235  assert(StubAddr && "Missing stub address");
236  auto StubTargetAddr =
237  static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(StubAddr));
238  auto StubSymbol = JITEvaluatedSymbol(StubTargetAddr, I->second.second);
239  if (ExportedStubsOnly && !StubSymbol.getFlags().isExported())
240  return nullptr;
241  return StubSymbol;
242  }
243 
245  auto I = StubIndexes.find(Name);
246  if (I == StubIndexes.end())
247  return nullptr;
248  auto Key = I->second.first;
249  void *PtrAddr = IndirectStubsInfos[Key.first].getPtr(Key.second);
250  assert(PtrAddr && "Missing pointer address");
251  auto PtrTargetAddr =
252  static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(PtrAddr));
253  return JITEvaluatedSymbol(PtrTargetAddr, I->second.second);
254  }
255 
257  auto I = StubIndexes.find(Name);
258  assert(I != StubIndexes.end() && "No stub pointer for symbol");
259  auto Key = I->second.first;
260  *IndirectStubsInfos[Key.first].getPtr(Key.second) =
261  reinterpret_cast<void *>(static_cast<uintptr_t>(NewAddr));
262  return Error::success();
263  }
264 
265 private:
266  Error reserveStubs(unsigned NumStubs) {
267  if (NumStubs <= FreeStubs.size())
268  return Error::success();
269 
270  unsigned NewStubsRequired = NumStubs - FreeStubs.size();
271  unsigned NewBlockId = IndirectStubsInfos.size();
272  typename TargetT::IndirectStubsInfo ISI;
273  if (auto Err =
274  TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired, nullptr))
275  return Err;
276  for (unsigned I = 0; I < ISI.getNumStubs(); ++I)
277  FreeStubs.push_back(std::make_pair(NewBlockId, I));
278  IndirectStubsInfos.push_back(std::move(ISI));
279  return Error::success();
280  }
281 
282  void createStubInternal(StringRef StubName, JITTargetAddress InitAddr,
283  JITSymbolFlags StubFlags) {
284  auto Key = FreeStubs.back();
285  FreeStubs.pop_back();
286  *IndirectStubsInfos[Key.first].getPtr(Key.second) =
287  reinterpret_cast<void *>(static_cast<uintptr_t>(InitAddr));
288  StubIndexes[StubName] = std::make_pair(Key, StubFlags);
289  }
290 
291  std::vector<typename TargetT::IndirectStubsInfo> IndirectStubsInfos;
292  using StubKey = std::pair<uint16_t, uint16_t>;
293  std::vector<StubKey> FreeStubs;
295 };
296 
297 /// Create a local compile callback manager.
298 ///
299 /// The given target triple will determine the ABI, and the given
300 /// ErrorHandlerAddress will be used by the resulting compile callback
301 /// manager if a compile callback fails.
302 std::unique_ptr<JITCompileCallbackManager>
304  JITTargetAddress ErrorHandlerAddress);
305 
306 /// Create a local indriect stubs manager builder.
307 ///
308 /// The given target triple will determine the ABI.
309 std::function<std::unique_ptr<IndirectStubsManager>()>
311 
312 /// Build a function pointer of FunctionType with the given constant
313 /// address.
314 ///
315 /// Usage example: Turn a trampoline address into a function pointer constant
316 /// for use in a stub.
318 
319 /// Create a function pointer with the given type, name, and initializer
320 /// in the given Module.
322  Constant *Initializer);
323 
324 /// Turn a function declaration into a stub function that makes an
325 /// indirect call using the given function pointer.
326 void makeStub(Function &F, Value &ImplPointer);
327 
328 /// Raise linkage types and rename as necessary to ensure that all
329 /// symbols are accessible for other modules.
330 ///
331 /// This should be called before partitioning a module to ensure that the
332 /// partitions retain access to each other's symbols.
334 
335 /// Clone a function declaration into a new module.
336 ///
337 /// This function can be used as the first step towards creating a callback
338 /// stub (see makeStub), or moving a function body (see moveFunctionBody).
339 ///
340 /// If the VMap argument is non-null, a mapping will be added between F and
341 /// the new declaration, and between each of F's arguments and the new
342 /// declaration's arguments. This map can then be passed in to moveFunction to
343 /// move the function body if required. Note: When moving functions between
344 /// modules with these utilities, all decls should be cloned (and added to a
345 /// single VMap) before any bodies are moved. This will ensure that references
346 /// between functions all refer to the versions in the new module.
347 Function *cloneFunctionDecl(Module &Dst, const Function &F,
348  ValueToValueMapTy *VMap = nullptr);
349 
350 /// Move the body of function 'F' to a cloned function declaration in a
351 /// different module (See related cloneFunctionDecl).
352 ///
353 /// If the target function declaration is not supplied via the NewF parameter
354 /// then it will be looked up via the VMap.
355 ///
356 /// This will delete the body of function 'F' from its original parent module,
357 /// but leave its declaration.
358 void moveFunctionBody(Function &OrigF, ValueToValueMapTy &VMap,
359  ValueMaterializer *Materializer = nullptr,
360  Function *NewF = nullptr);
361 
362 /// Clone a global variable declaration into a new module.
364  ValueToValueMapTy *VMap = nullptr);
365 
366 /// Move global variable GV from its parent module to cloned global
367 /// declaration in a different module.
368 ///
369 /// If the target global declaration is not supplied via the NewGV parameter
370 /// then it will be looked up via the VMap.
371 ///
372 /// This will delete the initializer of GV from its original parent module,
373 /// but leave its declaration.
375  ValueToValueMapTy &VMap,
376  ValueMaterializer *Materializer = nullptr,
377  GlobalVariable *NewGV = nullptr);
378 
379 /// Clone a global alias declaration into a new module.
381  ValueToValueMapTy &VMap);
382 
383 /// Clone module flags metadata into the destination module.
384 void cloneModuleFlagsMetadata(Module &Dst, const Module &Src,
385  ValueToValueMapTy &VMap);
386 
387 } // end namespace orc
388 
389 } // end namespace llvm
390 
391 #endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
IndirectStubsManager implementation for the host architecture, e.g.
Base class for managing collections of named indirect stubs.
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
A symbol table that supports asynchoronous symbol queries.
Definition: Core.h:548
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...
Target-independent base class for compile callback management.
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...
JITCompileCallbackManager(ExecutionSession &ES, JITTargetAddress ErrorHandlerAddress)
Construct a JITCompileCallbackManager.
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
JITEvaluatedSymbol findPointer(StringRef Name) override
Find the implementation-pointer for the stub.
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:40
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
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:43
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.
std::function< JITTargetAddress()> CompileFunction
static ErrorSuccess success()
Create a success value.
Definition: Error.h:321
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
Expected< JITTargetAddress > getCompileCallback(CompileFunction Compile)
Reserve a compile callback.
An ExecutionSession represents a running JIT program.
Definition: Core.h:703
StringMap - This is an unconventional map that is specialized for handling keys that are "strings"...
Definition: StringMap.h:220
Represents a symbol that has been evaluated to an address already.
Definition: JITSymbol.h:157
void makeAllSymbolsExternallyAccessible(Module &M)
Raise linkage types and rename as necessary to ensure that all symbols are accessible for other modul...
LocalJITCompileCallbackManager(ExecutionSession &ES, JITTargetAddress ErrorHandlerAddress)
Construct a InProcessJITCompileCallbackManager.
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
Error createStubs(const StubInitsMap &StubInits) override
Create StubInits.size() stubs with the given names, target addresses, and flags.
std::unique_ptr< JITCompileCallbackManager > createLocalCompileCallbackManager(const Triple &T, ExecutionSession &ES, JITTargetAddress ErrorHandlerAddress)
Create a local compile callback manager.
virtual ~JITCompileCallbackManager()=default
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override
Find the stub with the given name.
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...
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...