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