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