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