• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
writeResolverCode(uint8_t * ResolveMem,JITReentryFn Reentry,void * CallbackMgr)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 
writeTrampolines(uint8_t * TrampolineMem,void * ResolverAddr,unsigned NumTrampolines)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;
getNumStubs()57     unsigned getNumStubs() const { llvm_unreachable("Not supported"); }
getStub(unsigned Idx)58     void *getStub(unsigned Idx) const { llvm_unreachable("Not supported"); }
getPtr(unsigned Idx)59     void **getPtr(unsigned Idx) const { llvm_unreachable("Not supported"); }
60   };
61 
emitIndirectStubsBlock(IndirectStubsInfo & StubsInfo,unsigned MinStubs,void * InitialPtrVal)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 
GenericIndirectStubsInfo()75   GenericIndirectStubsInfo() : NumStubs(0) {}
GenericIndirectStubsInfo(unsigned NumStubs,sys::OwningMemoryBlock StubsMem)76   GenericIndirectStubsInfo(unsigned NumStubs, sys::OwningMemoryBlock StubsMem)
77       : NumStubs(NumStubs), StubsMem(std::move(StubsMem)) {}
GenericIndirectStubsInfo(GenericIndirectStubsInfo && Other)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.
getNumStubs()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.
getStub(unsigned Idx)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.
getPtr(unsigned Idx)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