aboutsummaryrefslogtreecommitdiff
path: root/include/llvm/ExecutionEngine/Orc/OrcABISupport.h
blob: 6b748e58ea0222c909983a71a5341e67b35e19b5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
//===- OrcABISupport.h - ABI support code -----------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// ABI specific code for Orc, e.g. callback assembly.
//
// ABI classes should be part of the JIT *target* process, not the host
// process (except where you're doing hosted JITing and the two are one and the
// same).
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
#define LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H

#include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Memory.h"
#include <algorithm>
#include <cstdint>

namespace llvm {
namespace orc {

/// Generic ORC ABI support.
///
/// This class can be substituted as the target architecure support class for
/// ORC templates that require one (e.g. IndirectStubsManagers). It does not
/// support lazy JITing however, and any attempt to use that functionality
/// will result in execution of an llvm_unreachable.
class OrcGenericABI {
public:
  static const unsigned PointerSize = sizeof(uintptr_t);
  static const unsigned TrampolineSize = 1;
  static const unsigned ResolverCodeSize = 1;

  using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
                                            void *TrampolineId);

  static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
                                void *CallbackMgr) {
    llvm_unreachable("writeResolverCode is not supported by the generic host "
                     "support class");
  }

  static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
                               unsigned NumTrampolines) {
    llvm_unreachable("writeTrampolines is not supported by the generic host "
                     "support class");
  }

  class IndirectStubsInfo {
  public:
    const static unsigned StubSize = 1;

    unsigned getNumStubs() const { llvm_unreachable("Not supported"); }
    void *getStub(unsigned Idx) const { llvm_unreachable("Not supported"); }
    void **getPtr(unsigned Idx) const { llvm_unreachable("Not supported"); }
  };

  static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
                                      unsigned MinStubs, void *InitialPtrVal) {
    llvm_unreachable("emitIndirectStubsBlock is not supported by the generic "
                     "host support class");
  }
};

/// Provide information about stub blocks generated by the
///        makeIndirectStubsBlock function.
template <unsigned StubSizeVal> class GenericIndirectStubsInfo {
public:
  const static unsigned StubSize = StubSizeVal;

  GenericIndirectStubsInfo() = default;
  GenericIndirectStubsInfo(unsigned NumStubs, sys::OwningMemoryBlock StubsMem)
      : NumStubs(NumStubs), StubsMem(std::move(StubsMem)) {}
  GenericIndirectStubsInfo(GenericIndirectStubsInfo &&Other)
      : NumStubs(Other.NumStubs), StubsMem(std::move(Other.StubsMem)) {
    Other.NumStubs = 0;
  }

  GenericIndirectStubsInfo &operator=(GenericIndirectStubsInfo &&Other) {
    NumStubs = Other.NumStubs;
    Other.NumStubs = 0;
    StubsMem = std::move(Other.StubsMem);
    return *this;
  }

  /// Number of stubs in this block.
  unsigned getNumStubs() const { return NumStubs; }

  /// Get a pointer to the stub at the given index, which must be in
  ///        the range 0 .. getNumStubs() - 1.
  void *getStub(unsigned Idx) const {
    return static_cast<char *>(StubsMem.base()) + Idx * StubSize;
  }

  /// Get a pointer to the implementation-pointer at the given index,
  ///        which must be in the range 0 .. getNumStubs() - 1.
  void **getPtr(unsigned Idx) const {
    char *PtrsBase = static_cast<char *>(StubsMem.base()) + NumStubs * StubSize;
    return reinterpret_cast<void **>(PtrsBase) + Idx;
  }

private:
  unsigned NumStubs = 0;
  sys::OwningMemoryBlock StubsMem;
};

class OrcAArch64 {
public:
  static const unsigned PointerSize = 8;
  static const unsigned TrampolineSize = 12;
  static const unsigned ResolverCodeSize = 0x120;

  using IndirectStubsInfo = GenericIndirectStubsInfo<8>;

  using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
                                            void *TrampolineId);

  /// Write the resolver code into the given memory. The user is be
  ///        responsible for allocating the memory and setting permissions.
  static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
                                void *CallbackMgr);

  /// Write the requsted number of trampolines into the given memory,
  ///        which must be big enough to hold 1 pointer, plus NumTrampolines
  ///        trampolines.
  static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
                               unsigned NumTrampolines);

  /// Emit at least MinStubs worth of indirect call stubs, rounded out to
  ///        the nearest page size.
  ///
  ///   E.g. Asking for 4 stubs on x86-64, where stubs are 8-bytes, with 4k
  /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
  /// will return a block of 1024 (2-pages worth).
  static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
                                      unsigned MinStubs, void *InitialPtrVal);
};

/// X86_64 code that's common to all ABIs.
///
/// X86_64 supports lazy JITing.
class OrcX86_64_Base {
public:
  static const unsigned PointerSize = 8;
  static const unsigned TrampolineSize = 8;

  using IndirectStubsInfo = GenericIndirectStubsInfo<8>;

  /// Write the requsted number of trampolines into the given memory,
  ///        which must be big enough to hold 1 pointer, plus NumTrampolines
  ///        trampolines.
  static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
                               unsigned NumTrampolines);

  /// Emit at least MinStubs worth of indirect call stubs, rounded out to
  ///        the nearest page size.
  ///
  ///   E.g. Asking for 4 stubs on x86-64, where stubs are 8-bytes, with 4k
  /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
  /// will return a block of 1024 (2-pages worth).
  static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
                                      unsigned MinStubs, void *InitialPtrVal);
};

/// X86_64 support for SysV ABI (Linux, MacOSX).
///
/// X86_64_SysV supports lazy JITing.
class OrcX86_64_SysV : public OrcX86_64_Base {
public:
  static const unsigned ResolverCodeSize = 0x6C;

  using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
                                            void *TrampolineId);

  /// Write the resolver code into the given memory. The user is be
  ///        responsible for allocating the memory and setting permissions.
  static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
                                void *CallbackMgr);
};

/// X86_64 support for Win32.
///
/// X86_64_Win32 supports lazy JITing.
class OrcX86_64_Win32 : public OrcX86_64_Base {
public:
  static const unsigned ResolverCodeSize = 0x74;

  using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
                                            void *TrampolineId);

  /// Write the resolver code into the given memory. The user is be
  ///        responsible for allocating the memory and setting permissions.
  static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
                                void *CallbackMgr);
};

/// I386 support.
///
/// I386 supports lazy JITing.
class OrcI386 {
public:
  static const unsigned PointerSize = 4;
  static const unsigned TrampolineSize = 8;
  static const unsigned ResolverCodeSize = 0x4a;

  using IndirectStubsInfo = GenericIndirectStubsInfo<8>;

  using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
                                            void *TrampolineId);

  /// Write the resolver code into the given memory. The user is be
  ///        responsible for allocating the memory and setting permissions.
  static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
                                void *CallbackMgr);

  /// Write the requsted number of trampolines into the given memory,
  ///        which must be big enough to hold 1 pointer, plus NumTrampolines
  ///        trampolines.
  static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
                               unsigned NumTrampolines);

  /// Emit at least MinStubs worth of indirect call stubs, rounded out to
  ///        the nearest page size.
  ///
  ///   E.g. Asking for 4 stubs on i386, where stubs are 8-bytes, with 4k
  /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
  /// will return a block of 1024 (2-pages worth).
  static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
                                      unsigned MinStubs, void *InitialPtrVal);
};

// @brief Mips32 support.
//
// Mips32 supports lazy JITing.
class OrcMips32_Base {
public:
  static const unsigned PointerSize = 4;
  static const unsigned TrampolineSize = 20;
  static const unsigned ResolverCodeSize = 0xf8;
  using IndirectStubsInfo = GenericIndirectStubsInfo<16>;

  using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
                                            void *TrampolineId);
  /// @brief Write the requsted number of trampolines into the given memory,
  ///        which must be big enough to hold 1 pointer, plus NumTrampolines
  ///        trampolines.
  static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,unsigned NumTrampolines);

  /// @brief Write the resolver code into the given memory. The user is be
  ///        responsible for allocating the memory and setting permissions.
  static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,void *CallbackMgr, bool isBigEndian);
  /// @brief Emit at least MinStubs worth of indirect call stubs, rounded out to
  ///        the nearest page size.
  ///
  ///   E.g. Asking for 4 stubs on Mips32, where stubs are 8-bytes, with 4k
  /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
  /// will return a block of 1024 (2-pages worth).
  static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,unsigned MinStubs, void *InitialPtrVal);
};


class OrcMips32Le : public OrcMips32_Base {
public:
  static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,void *CallbackMgr)
  { OrcMips32_Base::writeResolverCode(ResolveMem, Reentry, CallbackMgr, false); }
};

class OrcMips32Be : public OrcMips32_Base {
public:
  static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,void *CallbackMgr)
  { OrcMips32_Base::writeResolverCode(ResolveMem, Reentry, CallbackMgr, true); }
};

// @brief Mips64 support.
//
// Mips64 supports lazy JITing.
class OrcMips64 {
public:
  static const unsigned PointerSize = 8;
  static const unsigned TrampolineSize = 40;
  static const unsigned ResolverCodeSize = 0x11C;

  using IndirectStubsInfo = GenericIndirectStubsInfo<32>;
  using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
                                            void *TrampolineId);
  /// @brief Write the resolver code into the given memory. The user is be
  ///        responsible for allocating the memory and setting permissions.
  static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,void *CallbackMgr);

  /// @brief Write the requsted number of trampolines into the given memory,
  ///        which must be big enough to hold 1 pointer, plus NumTrampolines
  ///        trampolines.
  static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,unsigned NumTrampolines);

  /// @brief Emit at least MinStubs worth of indirect call stubs, rounded out to
  ///        the nearest page size.
  ///
  ///   E.g. Asking for 4 stubs on Mips64, where stubs are 8-bytes, with 4k
  /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
  /// will return a block of 1024 (2-pages worth).
  static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,unsigned MinStubs, void *InitialPtrVal);
};

 } // end namespace orc
 } // end namespace llvm
#endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H