LCOV - code coverage report
Current view: top level - include/llvm/ExecutionEngine/Orc - IndirectionUtils.h (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 65 73 89.0 %
Date: 2018-07-13 00:08:38 Functions: 16 67 23.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/ExecutionEngine/Orc/Core.h"
      22             : #include "llvm/Support/Error.h"
      23             : #include "llvm/Support/Memory.h"
      24             : #include "llvm/Support/Process.h"
      25             : #include "llvm/Transforms/Utils/ValueMapper.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.
      51             : class JITCompileCallbackManager {
      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.
      58          19 :   JITCompileCallbackManager(ExecutionSession &ES,
      59             :                             JITTargetAddress ErrorHandlerAddress)
      60          57 :       : ES(ES), CallbacksVSO(ES.createVSO("<Callbacks>")),
      61          95 :         ErrorHandlerAddress(ErrorHandlerAddress) {}
      62             : 
      63          38 :   virtual ~JITCompileCallbackManager() = default;
      64             : 
      65             :   /// Reserve a compile callback.
      66             :   Expected<JITTargetAddress> getCompileCallback(CompileFunction Compile);
      67             : 
      68             :   /// Execute the callback for the given trampoline id. Called by the JIT
      69             :   ///        to compile functions on demand.
      70             :   JITTargetAddress executeCompileCallback(JITTargetAddress TrampolineAddr);
      71             : 
      72             : protected:
      73             :   std::vector<JITTargetAddress> AvailableTrampolines;
      74             : 
      75             : private:
      76          18 :   Expected<JITTargetAddress> getAvailableTrampolineAddr() {
      77          18 :     if (this->AvailableTrampolines.empty())
      78          18 :       if (auto Err = grow())
      79             :         return std::move(Err);
      80             :     assert(!this->AvailableTrampolines.empty() &&
      81             :            "Failed to grow available trampolines.");
      82          18 :     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>
     102          54 : class LocalJITCompileCallbackManager : public JITCompileCallbackManager {
     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.
     107          18 :   LocalJITCompileCallbackManager(ExecutionSession &ES,
     108             :                                  JITTargetAddress ErrorHandlerAddress)
     109          18 :       : JITCompileCallbackManager(ES, ErrorHandlerAddress) {
     110             :     /// Set up the resolver block.
     111             :     std::error_code EC;
     112          36 :     ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
     113             :         TargetT::ResolverCodeSize, nullptr,
     114             :         sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
     115             :     assert(!EC && "Failed to allocate resolver block");
     116             : 
     117          18 :     TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()),
     118             :                                &reenter, this);
     119             : 
     120          18 :     EC = sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(),
     121             :                                           sys::Memory::MF_READ |
     122             :                                               sys::Memory::MF_EXEC);
     123             :     assert(!EC && "Failed to mprotect resolver block");
     124          18 :   }
     125             : 
     126             : private:
     127          17 :   static JITTargetAddress reenter(void *CCMgr, void *TrampolineId) {
     128             :     JITCompileCallbackManager *Mgr =
     129             :         static_cast<JITCompileCallbackManager *>(CCMgr);
     130          17 :     return Mgr->executeCompileCallback(
     131             :         static_cast<JITTargetAddress>(
     132          17 :             reinterpret_cast<uintptr_t>(TrampolineId)));
     133             :   }
     134             : 
     135           9 :   Error grow() override {
     136             :     assert(this->AvailableTrampolines.empty() && "Growing prematurely?");
     137             : 
     138             :     std::error_code EC;
     139           9 :     auto TrampolineBlock =
     140             :         sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
     141           9 :             sys::Process::getPageSize(), nullptr,
     142             :             sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
     143           9 :     if (EC)
     144           0 :       return errorCodeToError(EC);
     145             : 
     146           9 :     unsigned NumTrampolines =
     147           9 :         (sys::Process::getPageSize() - TargetT::PointerSize) /
     148             :         TargetT::TrampolineSize;
     149             : 
     150             :     uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base());
     151           9 :     TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
     152             :                               NumTrampolines);
     153             : 
     154        9207 :     for (unsigned I = 0; I < NumTrampolines; ++I)
     155       13797 :       this->AvailableTrampolines.push_back(
     156             :           static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(
     157        4599 :               TrampolineMem + (I * TargetT::TrampolineSize))));
     158             : 
     159          18 :     if (auto EC = sys::Memory::protectMappedMemory(
     160          18 :                     TrampolineBlock.getMemoryBlock(),
     161             :                     sys::Memory::MF_READ | sys::Memory::MF_EXEC))
     162           0 :       return errorCodeToError(EC);
     163             : 
     164           9 :     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.
     173             : class IndirectStubsManager {
     174             : public:
     175             :   /// Map type for initializing the manager. See init.
     176             :   using StubInitsMap = StringMap<std::pair<JITTargetAddress, JITSymbolFlags>>;
     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>
     206          48 : class LocalIndirectStubsManager : public IndirectStubsManager {
     207             : public:
     208           1 :   Error createStub(StringRef StubName, JITTargetAddress StubAddr,
     209             :                    JITSymbolFlags StubFlags) override {
     210           2 :     if (auto Err = reserveStubs(1))
     211             :       return Err;
     212             : 
     213           1 :     createStubInternal(StubName, StubAddr, StubFlags);
     214             : 
     215             :     return Error::success();
     216             :   }
     217             : 
     218           9 :   Error createStubs(const StubInitsMap &StubInits) override {
     219          18 :     if (auto Err = reserveStubs(StubInits.size()))
     220             :       return Err;
     221             : 
     222          35 :     for (auto &Entry : StubInits)
     223          34 :       createStubInternal(Entry.first(), Entry.second.first,
     224             :                          Entry.second.second);
     225             : 
     226             :     return Error::success();
     227             :   }
     228             : 
     229          25 :   JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
     230          25 :     auto I = StubIndexes.find(Name);
     231          50 :     if (I == StubIndexes.end())
     232             :       return nullptr;
     233          18 :     auto Key = I->second.first;
     234          36 :     void *StubAddr = IndirectStubsInfos[Key.first].getStub(Key.second);
     235             :     assert(StubAddr && "Missing stub address");
     236          18 :     auto StubTargetAddr =
     237             :         static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(StubAddr));
     238             :     auto StubSymbol = JITEvaluatedSymbol(StubTargetAddr, I->second.second);
     239          18 :     if (ExportedStubsOnly && !StubSymbol.getFlags().isExported())
     240             :       return nullptr;
     241          18 :     return StubSymbol;
     242             :   }
     243             : 
     244           0 :   JITEvaluatedSymbol findPointer(StringRef Name) override {
     245           0 :     auto I = StubIndexes.find(Name);
     246           0 :     if (I == StubIndexes.end())
     247             :       return nullptr;
     248           0 :     auto Key = I->second.first;
     249           0 :     void *PtrAddr = IndirectStubsInfos[Key.first].getPtr(Key.second);
     250             :     assert(PtrAddr && "Missing pointer address");
     251           0 :     auto PtrTargetAddr =
     252             :         static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(PtrAddr));
     253             :     return JITEvaluatedSymbol(PtrTargetAddr, I->second.second);
     254             :   }
     255             : 
     256           2 :   Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override {
     257           2 :     auto I = StubIndexes.find(Name);
     258             :     assert(I != StubIndexes.end() && "No stub pointer for symbol");
     259           2 :     auto Key = I->second.first;
     260           4 :     *IndirectStubsInfos[Key.first].getPtr(Key.second) =
     261             :         reinterpret_cast<void *>(static_cast<uintptr_t>(NewAddr));
     262           2 :     return Error::success();
     263             :   }
     264             : 
     265             : private:
     266          10 :   Error reserveStubs(unsigned NumStubs) {
     267          20 :     if (NumStubs <= FreeStubs.size())
     268             :       return Error::success();
     269             : 
     270           9 :     unsigned NewStubsRequired = NumStubs - FreeStubs.size();
     271          18 :     unsigned NewBlockId = IndirectStubsInfos.size();
     272             :     typename TargetT::IndirectStubsInfo ISI;
     273          18 :     if (auto Err =
     274             :             TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired, nullptr))
     275             :       return Err;
     276        9225 :     for (unsigned I = 0; I < ISI.getNumStubs(); ++I)
     277        9216 :       FreeStubs.push_back(std::make_pair(NewBlockId, I));
     278           9 :     IndirectStubsInfos.push_back(std::move(ISI));
     279             :     return Error::success();
     280             :   }
     281             : 
     282          18 :   void createStubInternal(StringRef StubName, JITTargetAddress InitAddr,
     283             :                           JITSymbolFlags StubFlags) {
     284          18 :     auto Key = FreeStubs.back();
     285             :     FreeStubs.pop_back();
     286          36 :     *IndirectStubsInfos[Key.first].getPtr(Key.second) =
     287             :         reinterpret_cast<void *>(static_cast<uintptr_t>(InitAddr));
     288          18 :     StubIndexes[StubName] = std::make_pair(Key, StubFlags);
     289          18 :   }
     290             : 
     291             :   std::vector<typename TargetT::IndirectStubsInfo> IndirectStubsInfos;
     292             :   using StubKey = std::pair<uint16_t, uint16_t>;
     293             :   std::vector<StubKey> FreeStubs;
     294             :   StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
     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>
     303             : createLocalCompileCallbackManager(const Triple &T, ExecutionSession &ES,
     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>()>
     310             : createLocalIndirectStubsManagerBuilder(const Triple &T);
     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.
     317             : Constant *createIRTypedAddress(FunctionType &FT, JITTargetAddress Addr);
     318             : 
     319             : /// Create a function pointer with the given type, name, and initializer
     320             : ///        in the given Module.
     321             : GlobalVariable *createImplPointer(PointerType &PT, Module &M, const Twine &Name,
     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.
     333             : void makeAllSymbolsExternallyAccessible(Module &M);
     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.
     363             : GlobalVariable *cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV,
     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.
     374             : void moveGlobalVariableInitializer(GlobalVariable &OrigGV,
     375             :                                    ValueToValueMapTy &VMap,
     376             :                                    ValueMaterializer *Materializer = nullptr,
     377             :                                    GlobalVariable *NewGV = nullptr);
     378             : 
     379             : /// Clone a global alias declaration into a new module.
     380             : GlobalAlias *cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA,
     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

Generated by: LCOV version 1.13