LCOV - code coverage report
Current view: top level - include/llvm/ExecutionEngine/Orc - IndirectionUtils.h (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 89 105 84.8 %
Date: 2017-09-14 15:23:50 Functions: 17 61 27.9 %
Legend: Lines: hit not hit

          Line data    Source code
       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"
      20             : #include "llvm/ExecutionEngine/JITSymbol.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             : /// @brief Target-independent base class for compile callback management.
      50             : class JITCompileCallbackManager {
      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.
      57             :   class CompileCallbackInfo {
      58             :   public:
      59             :     CompileCallbackInfo(JITTargetAddress Addr, CompileFtor &Compile)
      60             :         : Addr(Addr), Compile(Compile) {}
      61             : 
      62             :     JITTargetAddress getAddress() const { return Addr; }
      63             :     void setCompileAction(CompileFtor Compile) {
      64          18 :       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.
      75             :   JITCompileCallbackManager(JITTargetAddress ErrorHandlerAddress)
      76          33 :       : ErrorHandlerAddress(ErrorHandlerAddress) {}
      77             : 
      78          33 :   virtual ~JITCompileCallbackManager() = default;
      79             : 
      80             :   /// @brief Execute the callback for the given trampoline id. Called by the JIT
      81             :   ///        to compile functions on demand.
      82          17 :   JITTargetAddress executeCompileCallback(JITTargetAddress TrampolineAddr) {
      83          34 :     auto I = ActiveTrampolines.find(TrampolineAddr);
      84             :     // FIXME: Also raise an error in the Orc error-handler when we finally have
      85             :     //        one.
      86          34 :     if (I == ActiveTrampolines.end())
      87           0 :       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          34 :     auto Compile = std::move(I->second);
      98          34 :     ActiveTrampolines.erase(I);
      99          17 :     AvailableTrampolines.push_back(TrampolineAddr);
     100             : 
     101          17 :     if (auto Addr = Compile())
     102             :       return Addr;
     103             : 
     104           0 :     return ErrorHandlerAddress;
     105             :   }
     106             : 
     107             :   /// @brief Reserve a compile callback.
     108          18 :   Expected<CompileCallbackInfo> getCompileCallback() {
     109          54 :     if (auto TrampolineAddrOrErr = getAvailableTrampolineAddr()) {
     110          18 :       const auto &TrampolineAddr = *TrampolineAddrOrErr;
     111          18 :       auto &Compile = this->ActiveTrampolines[TrampolineAddr];
     112          36 :       return CompileCallbackInfo(TrampolineAddr, Compile);
     113             :     } else
     114           0 :       return TrampolineAddrOrErr.takeError();
     115             :   }
     116             : 
     117             :   /// @brief Get a CompileCallbackInfo for an existing callback.
     118             :   CompileCallbackInfo getCompileCallbackInfo(JITTargetAddress TrampolineAddr) {
     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.
     129             :   void releaseCompileCallback(JITTargetAddress TrampolineAddr) {
     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:
     137             :   JITTargetAddress ErrorHandlerAddress;
     138             : 
     139             :   using TrampolineMapT = std::map<JITTargetAddress, CompileFtor>;
     140             :   TrampolineMapT ActiveTrampolines;
     141             :   std::vector<JITTargetAddress> AvailableTrampolines;
     142             : 
     143             : private:
     144          18 :   Expected<JITTargetAddress> getAvailableTrampolineAddr() {
     145          36 :     if (this->AvailableTrampolines.empty())
     146          27 :       if (auto Err = grow())
     147           0 :         return std::move(Err);
     148             :     assert(!this->AvailableTrampolines.empty() &&
     149             :            "Failed to grow available trampolines.");
     150          36 :     JITTargetAddress TrampolineAddr = this->AvailableTrampolines.back();
     151          36 :     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>
     163          30 : class LocalJITCompileCallbackManager : public JITCompileCallbackManager {
     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.
     168          10 :   LocalJITCompileCallbackManager(JITTargetAddress ErrorHandlerAddress)
     169          40 :       : JITCompileCallbackManager(ErrorHandlerAddress) {
     170             :     /// Set up the resolver block.
     171          10 :     std::error_code EC;
     172          40 :     ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
     173             :         TargetT::ResolverCodeSize, nullptr,
     174             :         sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
     175             :     assert(!EC && "Failed to allocate resolver block");
     176             : 
     177          20 :     TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()),
     178             :                                &reenter, this);
     179             : 
     180          20 :     EC = sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(),
     181             :                                           sys::Memory::MF_READ |
     182             :                                               sys::Memory::MF_EXEC);
     183             :     assert(!EC && "Failed to mprotect resolver block");
     184          10 :   }
     185             : 
     186             : private:
     187          17 :   static JITTargetAddress reenter(void *CCMgr, void *TrampolineId) {
     188          17 :     JITCompileCallbackManager *Mgr =
     189             :         static_cast<JITCompileCallbackManager *>(CCMgr);
     190          17 :     return Mgr->executeCompileCallback(
     191             :         static_cast<JITTargetAddress>(
     192          17 :             reinterpret_cast<uintptr_t>(TrampolineId)));
     193             :   }
     194             : 
     195           9 :   Error grow() override {
     196             :     assert(this->AvailableTrampolines.empty() && "Growing prematurely?");
     197             : 
     198           9 :     std::error_code EC;
     199          27 :     auto TrampolineBlock =
     200             :         sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
     201           9 :             sys::Process::getPageSize(), nullptr,
     202             :             sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
     203           9 :     if (EC)
     204           0 :       return errorCodeToError(EC);
     205             : 
     206           9 :     unsigned NumTrampolines =
     207           9 :         (sys::Process::getPageSize() - TargetT::PointerSize) /
     208             :         TargetT::TrampolineSize;
     209             : 
     210           9 :     uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base());
     211          18 :     TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
     212             :                               NumTrampolines);
     213             : 
     214        4608 :     for (unsigned I = 0; I < NumTrampolines; ++I)
     215       13797 :       this->AvailableTrampolines.push_back(
     216             :           static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(
     217        4599 :               TrampolineMem + (I * TargetT::TrampolineSize))));
     218             : 
     219          18 :     if (auto EC = sys::Memory::protectMappedMemory(
     220          18 :                     TrampolineBlock.getMemoryBlock(),
     221             :                     sys::Memory::MF_READ | sys::Memory::MF_EXEC))
     222           0 :       return errorCodeToError(EC);
     223             : 
     224          18 :     TrampolineBlocks.push_back(std::move(TrampolineBlock));
     225          27 :     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.
     233             : class IndirectStubsManager {
     234             : public:
     235             :   /// @brief Map type for initializing the manager. See init.
     236             :   using StubInitsMap = StringMap<std::pair<JITTargetAddress, JITSymbolFlags>>;
     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>
     266          77 : class LocalIndirectStubsManager : public IndirectStubsManager {
     267             : public:
     268           1 :   Error createStub(StringRef StubName, JITTargetAddress StubAddr,
     269             :                    JITSymbolFlags StubFlags) override {
     270           3 :     if (auto Err = reserveStubs(1))
     271           0 :       return Err;
     272             : 
     273           1 :     createStubInternal(StubName, StubAddr, StubFlags);
     274             : 
     275           3 :     return Error::success();
     276             :   }
     277             : 
     278           9 :   Error createStubs(const StubInitsMap &StubInits) override {
     279          27 :     if (auto Err = reserveStubs(StubInits.size()))
     280           0 :       return Err;
     281             : 
     282          70 :     for (auto &Entry : StubInits)
     283          34 :       createStubInternal(Entry.first(), Entry.second.first,
     284             :                          Entry.second.second);
     285             : 
     286          27 :     return Error::success();
     287             :   }
     288             : 
     289          56 :   JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
     290          56 :     auto I = StubIndexes.find(Name);
     291         112 :     if (I == StubIndexes.end())
     292             :       return nullptr;
     293          22 :     auto Key = I->second.first;
     294          66 :     void *StubAddr = IndirectStubsInfos[Key.first].getStub(Key.second);
     295             :     assert(StubAddr && "Missing stub address");
     296          22 :     auto StubTargetAddr =
     297             :         static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(StubAddr));
     298          66 :     auto StubSymbol = JITSymbol(StubTargetAddr, I->second.second);
     299          22 :     if (ExportedStubsOnly && !StubSymbol.getFlags().isExported())
     300             :       return nullptr;
     301          22 :     return StubSymbol;
     302             :   }
     303             : 
     304           0 :   JITSymbol findPointer(StringRef Name) override {
     305           0 :     auto I = StubIndexes.find(Name);
     306           0 :     if (I == StubIndexes.end())
     307             :       return nullptr;
     308           0 :     auto Key = I->second.first;
     309           0 :     void *PtrAddr = IndirectStubsInfos[Key.first].getPtr(Key.second);
     310             :     assert(PtrAddr && "Missing pointer address");
     311           0 :     auto PtrTargetAddr =
     312             :         static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(PtrAddr));
     313           0 :     return JITSymbol(PtrTargetAddr, I->second.second);
     314             :   }
     315             : 
     316          17 :   Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override {
     317          17 :     auto I = StubIndexes.find(Name);
     318             :     assert(I != StubIndexes.end() && "No stub pointer for symbol");
     319          17 :     auto Key = I->second.first;
     320          51 :     *IndirectStubsInfos[Key.first].getPtr(Key.second) =
     321             :         reinterpret_cast<void *>(static_cast<uintptr_t>(NewAddr));
     322          51 :     return Error::success();
     323             :   }
     324             : 
     325             : private:
     326          10 :   Error reserveStubs(unsigned NumStubs) {
     327          20 :     if (NumStubs <= FreeStubs.size())
     328           3 :       return Error::success();
     329             : 
     330           9 :     unsigned NewStubsRequired = NumStubs - FreeStubs.size();
     331          18 :     unsigned NewBlockId = IndirectStubsInfos.size();
     332           9 :     typename TargetT::IndirectStubsInfo ISI;
     333          27 :     if (auto Err =
     334             :             TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired, nullptr))
     335           0 :       return Err;
     336        4617 :     for (unsigned I = 0; I < ISI.getNumStubs(); ++I)
     337       18432 :       FreeStubs.push_back(std::make_pair(NewBlockId, I));
     338          18 :     IndirectStubsInfos.push_back(std::move(ISI));
     339          27 :     return Error::success();
     340             :   }
     341             : 
     342          18 :   void createStubInternal(StringRef StubName, JITTargetAddress InitAddr,
     343             :                           JITSymbolFlags StubFlags) {
     344          36 :     auto Key = FreeStubs.back();
     345          18 :     FreeStubs.pop_back();
     346          54 :     *IndirectStubsInfos[Key.first].getPtr(Key.second) =
     347             :         reinterpret_cast<void *>(static_cast<uintptr_t>(InitAddr));
     348          54 :     StubIndexes[StubName] = std::make_pair(Key, StubFlags);
     349          18 :   }
     350             : 
     351             :   std::vector<typename TargetT::IndirectStubsInfo> IndirectStubsInfos;
     352             :   using StubKey = std::pair<uint16_t, uint16_t>;
     353             :   std::vector<StubKey> FreeStubs;
     354             :   StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
     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>
     363             : createLocalCompileCallbackManager(const Triple &T,
     364             :                                   JITTargetAddress ErrorHandlerAddress);
     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>()>
     370             : createLocalIndirectStubsManagerBuilder(const Triple &T);
     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.
     377             : Constant *createIRTypedAddress(FunctionType &FT, JITTargetAddress Addr);
     378             : 
     379             : /// @brief Create a function pointer with the given type, name, and initializer
     380             : ///        in the given Module.
     381             : GlobalVariable *createImplPointer(PointerType &PT, Module &M, const Twine &Name,
     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.
     393             : void makeAllSymbolsExternallyAccessible(Module &M);
     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.
     423             : GlobalVariable *cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV,
     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.
     434             : void moveGlobalVariableInitializer(GlobalVariable &OrigGV,
     435             :                                    ValueToValueMapTy &VMap,
     436             :                                    ValueMaterializer *Materializer = nullptr,
     437             :                                    GlobalVariable *NewGV = nullptr);
     438             : 
     439             : /// @brief Clone a global alias declaration into a new module.
     440             : GlobalAlias *cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA,
     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

Generated by: LCOV version 1.13