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