• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- IndirectionUtils.h - Utilities for adding indirections ---*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Contains utilities for adding indirections and breaking up modules.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
14 #define LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
15 
16 #include "llvm/ADT/StringMap.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/ADT/Twine.h"
19 #include "llvm/ExecutionEngine/JITSymbol.h"
20 #include "llvm/ExecutionEngine/Orc/Core.h"
21 #include "llvm/Support/Error.h"
22 #include "llvm/Support/Memory.h"
23 #include "llvm/Support/Process.h"
24 #include "llvm/Transforms/Utils/ValueMapper.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 /// Base class for pools of compiler re-entry trampolines.
50 /// These trampolines are callable addresses that save all register state
51 /// before calling a supplied function to return the trampoline landing
52 /// address, then restore all state before jumping to that address. They
53 /// are used by various ORC APIs to support lazy compilation
54 class TrampolinePool {
55 public:
~TrampolinePool()56   virtual ~TrampolinePool() {}
57 
58   /// Get an available trampoline address.
59   /// Returns an error if no trampoline can be created.
60   virtual Expected<JITTargetAddress> getTrampoline() = 0;
61 
62 private:
63   virtual void anchor();
64 };
65 
66 /// A trampoline pool for trampolines within the current process.
67 template <typename ORCABI> class LocalTrampolinePool : public TrampolinePool {
68 public:
69   using GetTrampolineLandingFunction =
70       std::function<JITTargetAddress(JITTargetAddress TrampolineAddr)>;
71 
72   /// Creates a LocalTrampolinePool with the given RunCallback function.
73   /// Returns an error if this function is unable to correctly allocate, write
74   /// and protect the resolver code block.
75   static Expected<std::unique_ptr<LocalTrampolinePool>>
Create(GetTrampolineLandingFunction GetTrampolineLanding)76   Create(GetTrampolineLandingFunction GetTrampolineLanding) {
77     Error Err = Error::success();
78 
79     auto LTP = std::unique_ptr<LocalTrampolinePool>(
80         new LocalTrampolinePool(std::move(GetTrampolineLanding), Err));
81 
82     if (Err)
83       return std::move(Err);
84     return std::move(LTP);
85   }
86 
87   /// Get a free trampoline. Returns an error if one can not be provided (e.g.
88   /// because the pool is empty and can not be grown).
getTrampoline()89   Expected<JITTargetAddress> getTrampoline() override {
90     std::lock_guard<std::mutex> Lock(LTPMutex);
91     if (AvailableTrampolines.empty()) {
92       if (auto Err = grow())
93         return std::move(Err);
94     }
95     assert(!AvailableTrampolines.empty() && "Failed to grow trampoline pool");
96     auto TrampolineAddr = AvailableTrampolines.back();
97     AvailableTrampolines.pop_back();
98     return TrampolineAddr;
99   }
100 
101   /// Returns the given trampoline to the pool for re-use.
releaseTrampoline(JITTargetAddress TrampolineAddr)102   void releaseTrampoline(JITTargetAddress TrampolineAddr) {
103     std::lock_guard<std::mutex> Lock(LTPMutex);
104     AvailableTrampolines.push_back(TrampolineAddr);
105   }
106 
107 private:
reenter(void * TrampolinePoolPtr,void * TrampolineId)108   static JITTargetAddress reenter(void *TrampolinePoolPtr, void *TrampolineId) {
109     LocalTrampolinePool<ORCABI> *TrampolinePool =
110         static_cast<LocalTrampolinePool *>(TrampolinePoolPtr);
111     return TrampolinePool->GetTrampolineLanding(static_cast<JITTargetAddress>(
112         reinterpret_cast<uintptr_t>(TrampolineId)));
113   }
114 
LocalTrampolinePool(GetTrampolineLandingFunction GetTrampolineLanding,Error & Err)115   LocalTrampolinePool(GetTrampolineLandingFunction GetTrampolineLanding,
116                       Error &Err)
117       : GetTrampolineLanding(std::move(GetTrampolineLanding)) {
118 
119     ErrorAsOutParameter _(&Err);
120 
121     /// Try to set up the resolver block.
122     std::error_code EC;
123     ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
124         ORCABI::ResolverCodeSize, nullptr,
125         sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
126     if (EC) {
127       Err = errorCodeToError(EC);
128       return;
129     }
130 
131     ORCABI::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()),
132                               &reenter, this);
133 
134     EC = sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(),
135                                           sys::Memory::MF_READ |
136                                               sys::Memory::MF_EXEC);
137     if (EC) {
138       Err = errorCodeToError(EC);
139       return;
140     }
141   }
142 
grow()143   Error grow() {
144     assert(this->AvailableTrampolines.empty() && "Growing prematurely?");
145 
146     std::error_code EC;
147     auto TrampolineBlock =
148         sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
149             sys::Process::getPageSizeEstimate(), nullptr,
150             sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
151     if (EC)
152       return errorCodeToError(EC);
153 
154     unsigned NumTrampolines =
155         (sys::Process::getPageSizeEstimate() - ORCABI::PointerSize) /
156         ORCABI::TrampolineSize;
157 
158     uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base());
159     ORCABI::writeTrampolines(TrampolineMem, ResolverBlock.base(),
160                              NumTrampolines);
161 
162     for (unsigned I = 0; I < NumTrampolines; ++I)
163       this->AvailableTrampolines.push_back(
164           static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(
165               TrampolineMem + (I * ORCABI::TrampolineSize))));
166 
167     if (auto EC = sys::Memory::protectMappedMemory(
168                     TrampolineBlock.getMemoryBlock(),
169                     sys::Memory::MF_READ | sys::Memory::MF_EXEC))
170       return errorCodeToError(EC);
171 
172     TrampolineBlocks.push_back(std::move(TrampolineBlock));
173     return Error::success();
174   }
175 
176   GetTrampolineLandingFunction GetTrampolineLanding;
177 
178   std::mutex LTPMutex;
179   sys::OwningMemoryBlock ResolverBlock;
180   std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
181   std::vector<JITTargetAddress> AvailableTrampolines;
182 };
183 
184 /// Target-independent base class for compile callback management.
185 class JITCompileCallbackManager {
186 public:
187   using CompileFunction = std::function<JITTargetAddress()>;
188 
189   virtual ~JITCompileCallbackManager() = default;
190 
191   /// Reserve a compile callback.
192   Expected<JITTargetAddress> getCompileCallback(CompileFunction Compile);
193 
194   /// Execute the callback for the given trampoline id. Called by the JIT
195   ///        to compile functions on demand.
196   JITTargetAddress executeCompileCallback(JITTargetAddress TrampolineAddr);
197 
198 protected:
199   /// Construct a JITCompileCallbackManager.
JITCompileCallbackManager(std::unique_ptr<TrampolinePool> TP,ExecutionSession & ES,JITTargetAddress ErrorHandlerAddress)200   JITCompileCallbackManager(std::unique_ptr<TrampolinePool> TP,
201                             ExecutionSession &ES,
202                             JITTargetAddress ErrorHandlerAddress)
203       : TP(std::move(TP)), ES(ES),
204         CallbacksJD(ES.createJITDylib("<Callbacks>")),
205         ErrorHandlerAddress(ErrorHandlerAddress) {}
206 
setTrampolinePool(std::unique_ptr<TrampolinePool> TP)207   void setTrampolinePool(std::unique_ptr<TrampolinePool> TP) {
208     this->TP = std::move(TP);
209   }
210 
211 private:
212   std::mutex CCMgrMutex;
213   std::unique_ptr<TrampolinePool> TP;
214   ExecutionSession &ES;
215   JITDylib &CallbacksJD;
216   JITTargetAddress ErrorHandlerAddress;
217   std::map<JITTargetAddress, SymbolStringPtr> AddrToSymbol;
218   size_t NextCallbackId = 0;
219 };
220 
221 /// Manage compile callbacks for in-process JITs.
222 template <typename ORCABI>
223 class LocalJITCompileCallbackManager : public JITCompileCallbackManager {
224 public:
225   /// Create a new LocalJITCompileCallbackManager.
226   static Expected<std::unique_ptr<LocalJITCompileCallbackManager>>
Create(ExecutionSession & ES,JITTargetAddress ErrorHandlerAddress)227   Create(ExecutionSession &ES, JITTargetAddress ErrorHandlerAddress) {
228     Error Err = Error::success();
229     auto CCMgr = std::unique_ptr<LocalJITCompileCallbackManager>(
230         new LocalJITCompileCallbackManager(ES, ErrorHandlerAddress, Err));
231     if (Err)
232       return std::move(Err);
233     return std::move(CCMgr);
234   }
235 
236 private:
237   /// Construct a InProcessJITCompileCallbackManager.
238   /// @param ErrorHandlerAddress The address of an error handler in the target
239   ///                            process to be used if a compile callback fails.
LocalJITCompileCallbackManager(ExecutionSession & ES,JITTargetAddress ErrorHandlerAddress,Error & Err)240   LocalJITCompileCallbackManager(ExecutionSession &ES,
241                                  JITTargetAddress ErrorHandlerAddress,
242                                  Error &Err)
243       : JITCompileCallbackManager(nullptr, ES, ErrorHandlerAddress) {
244     ErrorAsOutParameter _(&Err);
245     auto TP = LocalTrampolinePool<ORCABI>::Create(
246         [this](JITTargetAddress TrampolineAddr) {
247           return executeCompileCallback(TrampolineAddr);
248         });
249 
250     if (!TP) {
251       Err = TP.takeError();
252       return;
253     }
254 
255     setTrampolinePool(std::move(*TP));
256   }
257 };
258 
259 /// Base class for managing collections of named indirect stubs.
260 class IndirectStubsManager {
261 public:
262   /// Map type for initializing the manager. See init.
263   using StubInitsMap = StringMap<std::pair<JITTargetAddress, JITSymbolFlags>>;
264 
265   virtual ~IndirectStubsManager() = default;
266 
267   /// Create a single stub with the given name, target address and flags.
268   virtual Error createStub(StringRef StubName, JITTargetAddress StubAddr,
269                            JITSymbolFlags StubFlags) = 0;
270 
271   /// Create StubInits.size() stubs with the given names, target
272   ///        addresses, and flags.
273   virtual Error createStubs(const StubInitsMap &StubInits) = 0;
274 
275   /// Find the stub with the given name. If ExportedStubsOnly is true,
276   ///        this will only return a result if the stub's flags indicate that it
277   ///        is exported.
278   virtual JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) = 0;
279 
280   /// Find the implementation-pointer for the stub.
281   virtual JITEvaluatedSymbol findPointer(StringRef Name) = 0;
282 
283   /// Change the value of the implementation pointer for the stub.
284   virtual Error updatePointer(StringRef Name, JITTargetAddress NewAddr) = 0;
285 
286 private:
287   virtual void anchor();
288 };
289 
290 /// IndirectStubsManager implementation for the host architecture, e.g.
291 ///        OrcX86_64. (See OrcArchitectureSupport.h).
292 template <typename TargetT>
293 class LocalIndirectStubsManager : public IndirectStubsManager {
294 public:
createStub(StringRef StubName,JITTargetAddress StubAddr,JITSymbolFlags StubFlags)295   Error createStub(StringRef StubName, JITTargetAddress StubAddr,
296                    JITSymbolFlags StubFlags) override {
297     std::lock_guard<std::mutex> Lock(StubsMutex);
298     if (auto Err = reserveStubs(1))
299       return Err;
300 
301     createStubInternal(StubName, StubAddr, StubFlags);
302 
303     return Error::success();
304   }
305 
createStubs(const StubInitsMap & StubInits)306   Error createStubs(const StubInitsMap &StubInits) override {
307     std::lock_guard<std::mutex> Lock(StubsMutex);
308     if (auto Err = reserveStubs(StubInits.size()))
309       return Err;
310 
311     for (auto &Entry : StubInits)
312       createStubInternal(Entry.first(), Entry.second.first,
313                          Entry.second.second);
314 
315     return Error::success();
316   }
317 
findStub(StringRef Name,bool ExportedStubsOnly)318   JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
319     std::lock_guard<std::mutex> Lock(StubsMutex);
320     auto I = StubIndexes.find(Name);
321     if (I == StubIndexes.end())
322       return nullptr;
323     auto Key = I->second.first;
324     void *StubAddr = IndirectStubsInfos[Key.first].getStub(Key.second);
325     assert(StubAddr && "Missing stub address");
326     auto StubTargetAddr =
327         static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(StubAddr));
328     auto StubSymbol = JITEvaluatedSymbol(StubTargetAddr, I->second.second);
329     if (ExportedStubsOnly && !StubSymbol.getFlags().isExported())
330       return nullptr;
331     return StubSymbol;
332   }
333 
findPointer(StringRef Name)334   JITEvaluatedSymbol findPointer(StringRef Name) override {
335     std::lock_guard<std::mutex> Lock(StubsMutex);
336     auto I = StubIndexes.find(Name);
337     if (I == StubIndexes.end())
338       return nullptr;
339     auto Key = I->second.first;
340     void *PtrAddr = IndirectStubsInfos[Key.first].getPtr(Key.second);
341     assert(PtrAddr && "Missing pointer address");
342     auto PtrTargetAddr =
343         static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(PtrAddr));
344     return JITEvaluatedSymbol(PtrTargetAddr, I->second.second);
345   }
346 
updatePointer(StringRef Name,JITTargetAddress NewAddr)347   Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override {
348     using AtomicIntPtr = std::atomic<uintptr_t>;
349 
350     std::lock_guard<std::mutex> Lock(StubsMutex);
351     auto I = StubIndexes.find(Name);
352     assert(I != StubIndexes.end() && "No stub pointer for symbol");
353     auto Key = I->second.first;
354     AtomicIntPtr *AtomicStubPtr = reinterpret_cast<AtomicIntPtr *>(
355         IndirectStubsInfos[Key.first].getPtr(Key.second));
356     *AtomicStubPtr = static_cast<uintptr_t>(NewAddr);
357     return Error::success();
358   }
359 
360 private:
reserveStubs(unsigned NumStubs)361   Error reserveStubs(unsigned NumStubs) {
362     if (NumStubs <= FreeStubs.size())
363       return Error::success();
364 
365     unsigned NewStubsRequired = NumStubs - FreeStubs.size();
366     unsigned NewBlockId = IndirectStubsInfos.size();
367     typename TargetT::IndirectStubsInfo ISI;
368     if (auto Err =
369             TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired, nullptr))
370       return Err;
371     for (unsigned I = 0; I < ISI.getNumStubs(); ++I)
372       FreeStubs.push_back(std::make_pair(NewBlockId, I));
373     IndirectStubsInfos.push_back(std::move(ISI));
374     return Error::success();
375   }
376 
createStubInternal(StringRef StubName,JITTargetAddress InitAddr,JITSymbolFlags StubFlags)377   void createStubInternal(StringRef StubName, JITTargetAddress InitAddr,
378                           JITSymbolFlags StubFlags) {
379     auto Key = FreeStubs.back();
380     FreeStubs.pop_back();
381     *IndirectStubsInfos[Key.first].getPtr(Key.second) =
382         reinterpret_cast<void *>(static_cast<uintptr_t>(InitAddr));
383     StubIndexes[StubName] = std::make_pair(Key, StubFlags);
384   }
385 
386   std::mutex StubsMutex;
387   std::vector<typename TargetT::IndirectStubsInfo> IndirectStubsInfos;
388   using StubKey = std::pair<uint16_t, uint16_t>;
389   std::vector<StubKey> FreeStubs;
390   StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
391 };
392 
393 /// Create a local compile callback manager.
394 ///
395 /// The given target triple will determine the ABI, and the given
396 /// ErrorHandlerAddress will be used by the resulting compile callback
397 /// manager if a compile callback fails.
398 Expected<std::unique_ptr<JITCompileCallbackManager>>
399 createLocalCompileCallbackManager(const Triple &T, ExecutionSession &ES,
400                                   JITTargetAddress ErrorHandlerAddress);
401 
402 /// Create a local indriect stubs manager builder.
403 ///
404 /// The given target triple will determine the ABI.
405 std::function<std::unique_ptr<IndirectStubsManager>()>
406 createLocalIndirectStubsManagerBuilder(const Triple &T);
407 
408 /// Build a function pointer of FunctionType with the given constant
409 ///        address.
410 ///
411 ///   Usage example: Turn a trampoline address into a function pointer constant
412 /// for use in a stub.
413 Constant *createIRTypedAddress(FunctionType &FT, JITTargetAddress Addr);
414 
415 /// Create a function pointer with the given type, name, and initializer
416 ///        in the given Module.
417 GlobalVariable *createImplPointer(PointerType &PT, Module &M, const Twine &Name,
418                                   Constant *Initializer);
419 
420 /// Turn a function declaration into a stub function that makes an
421 ///        indirect call using the given function pointer.
422 void makeStub(Function &F, Value &ImplPointer);
423 
424 /// Promotes private symbols to global hidden, and renames to prevent clashes
425 /// with other promoted symbols. The same SymbolPromoter instance should be
426 /// used for all symbols to be added to a single JITDylib.
427 class SymbolLinkagePromoter {
428 public:
429   /// Promote symbols in the given module. Returns the set of global values
430   /// that have been renamed/promoted.
431   std::vector<GlobalValue *> operator()(Module &M);
432 
433 private:
434   unsigned NextId = 0;
435 };
436 
437 /// Clone a function declaration into a new module.
438 ///
439 ///   This function can be used as the first step towards creating a callback
440 /// stub (see makeStub), or moving a function body (see moveFunctionBody).
441 ///
442 ///   If the VMap argument is non-null, a mapping will be added between F and
443 /// the new declaration, and between each of F's arguments and the new
444 /// declaration's arguments. This map can then be passed in to moveFunction to
445 /// move the function body if required. Note: When moving functions between
446 /// modules with these utilities, all decls should be cloned (and added to a
447 /// single VMap) before any bodies are moved. This will ensure that references
448 /// between functions all refer to the versions in the new module.
449 Function *cloneFunctionDecl(Module &Dst, const Function &F,
450                             ValueToValueMapTy *VMap = nullptr);
451 
452 /// Move the body of function 'F' to a cloned function declaration in a
453 ///        different module (See related cloneFunctionDecl).
454 ///
455 ///   If the target function declaration is not supplied via the NewF parameter
456 /// then it will be looked up via the VMap.
457 ///
458 ///   This will delete the body of function 'F' from its original parent module,
459 /// but leave its declaration.
460 void moveFunctionBody(Function &OrigF, ValueToValueMapTy &VMap,
461                       ValueMaterializer *Materializer = nullptr,
462                       Function *NewF = nullptr);
463 
464 /// Clone a global variable declaration into a new module.
465 GlobalVariable *cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV,
466                                         ValueToValueMapTy *VMap = nullptr);
467 
468 /// Move global variable GV from its parent module to cloned global
469 ///        declaration in a different module.
470 ///
471 ///   If the target global declaration is not supplied via the NewGV parameter
472 /// then it will be looked up via the VMap.
473 ///
474 ///   This will delete the initializer of GV from its original parent module,
475 /// but leave its declaration.
476 void moveGlobalVariableInitializer(GlobalVariable &OrigGV,
477                                    ValueToValueMapTy &VMap,
478                                    ValueMaterializer *Materializer = nullptr,
479                                    GlobalVariable *NewGV = nullptr);
480 
481 /// Clone a global alias declaration into a new module.
482 GlobalAlias *cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA,
483                                   ValueToValueMapTy &VMap);
484 
485 /// Clone module flags metadata into the destination module.
486 void cloneModuleFlagsMetadata(Module &Dst, const Module &Src,
487                               ValueToValueMapTy &VMap);
488 
489 } // end namespace orc
490 
491 } // end namespace llvm
492 
493 #endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
494