Home | History | Annotate | Download | only in Orc
      1 //===- OrcABISupport.h - ABI support code -----------------------*- 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 // ABI specific code for Orc, e.g. callback assembly.
     11 //
     12 // ABI classes should be part of the JIT *target* process, not the host
     13 // process (except where you're doing hosted JITing and the two are one and the
     14 // same).
     15 //
     16 //===----------------------------------------------------------------------===//
     17 
     18 #ifndef LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
     19 #define LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
     20 
     21 #include "llvm/ExecutionEngine/JITSymbol.h"
     22 #include "llvm/Support/Error.h"
     23 #include "llvm/Support/ErrorHandling.h"
     24 #include "llvm/Support/Memory.h"
     25 #include <algorithm>
     26 #include <cstdint>
     27 
     28 namespace llvm {
     29 namespace orc {
     30 
     31 /// Generic ORC ABI support.
     32 ///
     33 /// This class can be substituted as the target architecure support class for
     34 /// ORC templates that require one (e.g. IndirectStubsManagers). It does not
     35 /// support lazy JITing however, and any attempt to use that functionality
     36 /// will result in execution of an llvm_unreachable.
     37 class OrcGenericABI {
     38 public:
     39   static const unsigned PointerSize = sizeof(uintptr_t);
     40   static const unsigned TrampolineSize = 1;
     41   static const unsigned ResolverCodeSize = 1;
     42 
     43   using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
     44                                             void *TrampolineId);
     45 
     46   static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
     47                                 void *CallbackMgr) {
     48     llvm_unreachable("writeResolverCode is not supported by the generic host "
     49                      "support class");
     50   }
     51 
     52   static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
     53                                unsigned NumTrampolines) {
     54     llvm_unreachable("writeTrampolines is not supported by the generic host "
     55                      "support class");
     56   }
     57 
     58   class IndirectStubsInfo {
     59   public:
     60     const static unsigned StubSize = 1;
     61 
     62     unsigned getNumStubs() const { llvm_unreachable("Not supported"); }
     63     void *getStub(unsigned Idx) const { llvm_unreachable("Not supported"); }
     64     void **getPtr(unsigned Idx) const { llvm_unreachable("Not supported"); }
     65   };
     66 
     67   static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
     68                                       unsigned MinStubs, void *InitialPtrVal) {
     69     llvm_unreachable("emitIndirectStubsBlock is not supported by the generic "
     70                      "host support class");
     71   }
     72 };
     73 
     74 /// @brief Provide information about stub blocks generated by the
     75 ///        makeIndirectStubsBlock function.
     76 template <unsigned StubSizeVal> class GenericIndirectStubsInfo {
     77 public:
     78   const static unsigned StubSize = StubSizeVal;
     79 
     80   GenericIndirectStubsInfo() = default;
     81   GenericIndirectStubsInfo(unsigned NumStubs, sys::OwningMemoryBlock StubsMem)
     82       : NumStubs(NumStubs), StubsMem(std::move(StubsMem)) {}
     83   GenericIndirectStubsInfo(GenericIndirectStubsInfo &&Other)
     84       : NumStubs(Other.NumStubs), StubsMem(std::move(Other.StubsMem)) {
     85     Other.NumStubs = 0;
     86   }
     87 
     88   GenericIndirectStubsInfo &operator=(GenericIndirectStubsInfo &&Other) {
     89     NumStubs = Other.NumStubs;
     90     Other.NumStubs = 0;
     91     StubsMem = std::move(Other.StubsMem);
     92     return *this;
     93   }
     94 
     95   /// @brief Number of stubs in this block.
     96   unsigned getNumStubs() const { return NumStubs; }
     97 
     98   /// @brief Get a pointer to the stub at the given index, which must be in
     99   ///        the range 0 .. getNumStubs() - 1.
    100   void *getStub(unsigned Idx) const {
    101     return static_cast<char *>(StubsMem.base()) + Idx * StubSize;
    102   }
    103 
    104   /// @brief Get a pointer to the implementation-pointer at the given index,
    105   ///        which must be in the range 0 .. getNumStubs() - 1.
    106   void **getPtr(unsigned Idx) const {
    107     char *PtrsBase = static_cast<char *>(StubsMem.base()) + NumStubs * StubSize;
    108     return reinterpret_cast<void **>(PtrsBase) + Idx;
    109   }
    110 
    111 private:
    112   unsigned NumStubs = 0;
    113   sys::OwningMemoryBlock StubsMem;
    114 };
    115 
    116 class OrcAArch64 {
    117 public:
    118   static const unsigned PointerSize = 8;
    119   static const unsigned TrampolineSize = 12;
    120   static const unsigned ResolverCodeSize = 0x120;
    121 
    122   using IndirectStubsInfo = GenericIndirectStubsInfo<8>;
    123 
    124   using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
    125                                             void *TrampolineId);
    126 
    127   /// @brief Write the resolver code into the given memory. The user is be
    128   ///        responsible for allocating the memory and setting permissions.
    129   static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
    130                                 void *CallbackMgr);
    131 
    132   /// @brief Write the requsted number of trampolines into the given memory,
    133   ///        which must be big enough to hold 1 pointer, plus NumTrampolines
    134   ///        trampolines.
    135   static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
    136                                unsigned NumTrampolines);
    137 
    138   /// @brief Emit at least MinStubs worth of indirect call stubs, rounded out to
    139   ///        the nearest page size.
    140   ///
    141   ///   E.g. Asking for 4 stubs on x86-64, where stubs are 8-bytes, with 4k
    142   /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
    143   /// will return a block of 1024 (2-pages worth).
    144   static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
    145                                       unsigned MinStubs, void *InitialPtrVal);
    146 };
    147 
    148 /// @brief X86_64 code that's common to all ABIs.
    149 ///
    150 /// X86_64 supports lazy JITing.
    151 class OrcX86_64_Base {
    152 public:
    153   static const unsigned PointerSize = 8;
    154   static const unsigned TrampolineSize = 8;
    155 
    156   using IndirectStubsInfo = GenericIndirectStubsInfo<8>;
    157 
    158   /// @brief Write the requsted number of trampolines into the given memory,
    159   ///        which must be big enough to hold 1 pointer, plus NumTrampolines
    160   ///        trampolines.
    161   static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
    162                                unsigned NumTrampolines);
    163 
    164   /// @brief Emit at least MinStubs worth of indirect call stubs, rounded out to
    165   ///        the nearest page size.
    166   ///
    167   ///   E.g. Asking for 4 stubs on x86-64, where stubs are 8-bytes, with 4k
    168   /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
    169   /// will return a block of 1024 (2-pages worth).
    170   static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
    171                                       unsigned MinStubs, void *InitialPtrVal);
    172 };
    173 
    174 /// @brief X86_64 support for SysV ABI (Linux, MacOSX).
    175 ///
    176 /// X86_64_SysV supports lazy JITing.
    177 class OrcX86_64_SysV : public OrcX86_64_Base {
    178 public:
    179   static const unsigned ResolverCodeSize = 0x6C;
    180 
    181   using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
    182                                             void *TrampolineId);
    183 
    184   /// @brief Write the resolver code into the given memory. The user is be
    185   ///        responsible for allocating the memory and setting permissions.
    186   static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
    187                                 void *CallbackMgr);
    188 };
    189 
    190 /// @brief X86_64 support for Win32.
    191 ///
    192 /// X86_64_Win32 supports lazy JITing.
    193 class OrcX86_64_Win32 : public OrcX86_64_Base {
    194 public:
    195   static const unsigned ResolverCodeSize = 0x74;
    196 
    197   using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
    198                                             void *TrampolineId);
    199 
    200   /// @brief Write the resolver code into the given memory. The user is be
    201   ///        responsible for allocating the memory and setting permissions.
    202   static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
    203                                 void *CallbackMgr);
    204 };
    205 
    206 /// @brief I386 support.
    207 ///
    208 /// I386 supports lazy JITing.
    209 class OrcI386 {
    210 public:
    211   static const unsigned PointerSize = 4;
    212   static const unsigned TrampolineSize = 8;
    213   static const unsigned ResolverCodeSize = 0x4a;
    214 
    215   using IndirectStubsInfo = GenericIndirectStubsInfo<8>;
    216 
    217   using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
    218                                             void *TrampolineId);
    219 
    220   /// @brief Write the resolver code into the given memory. The user is be
    221   ///        responsible for allocating the memory and setting permissions.
    222   static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
    223                                 void *CallbackMgr);
    224 
    225   /// @brief Write the requsted number of trampolines into the given memory,
    226   ///        which must be big enough to hold 1 pointer, plus NumTrampolines
    227   ///        trampolines.
    228   static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
    229                                unsigned NumTrampolines);
    230 
    231   /// @brief Emit at least MinStubs worth of indirect call stubs, rounded out to
    232   ///        the nearest page size.
    233   ///
    234   ///   E.g. Asking for 4 stubs on i386, where stubs are 8-bytes, with 4k
    235   /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
    236   /// will return a block of 1024 (2-pages worth).
    237   static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
    238                                       unsigned MinStubs, void *InitialPtrVal);
    239 };
    240 
    241 } // end namespace orc
    242 } // end namespace llvm
    243 
    244 #endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
    245