Ruby
3.1.4p223 (2023-03-30 revision HEAD)
yjit_core.h
1
#ifndef YJIT_CORE_H
2
#define YJIT_CORE_H 1
3
4
#include <stddef.h>
5
#include <stdint.h>
6
#include "yjit_asm.h"
7
8
// Callee-saved regs
9
#define REG_CFP R13
10
#define REG_EC R12
11
#define REG_SP RBX
12
13
// Scratch registers used by YJIT
14
#define REG0 RAX
15
#define REG0_32 EAX
16
#define REG0_8 AL
17
#define REG1 RCX
18
#define REG1_32 ECX
19
20
// Maximum number of temp value types we keep track of
21
#define MAX_TEMP_TYPES 8
22
23
// Maximum number of local variable types we keep track of
24
#define MAX_LOCAL_TYPES 8
25
26
// Default versioning context (no type information)
27
#define DEFAULT_CTX ( (ctx_t){ 0 } )
28
29
enum
yjit_type_enum
30
{
31
ETYPE_UNKNOWN = 0,
32
ETYPE_NIL,
33
ETYPE_TRUE,
34
ETYPE_FALSE,
35
ETYPE_FIXNUM,
36
ETYPE_FLONUM,
37
ETYPE_ARRAY,
38
ETYPE_HASH,
39
ETYPE_SYMBOL,
40
ETYPE_STRING
41
};
42
43
// Represent the type of a value (local/stack/self) in YJIT
44
typedef
struct
yjit_type_struct
45
{
46
// Value is definitely a heap object
47
uint8_t is_heap : 1;
48
49
// Value is definitely an immediate
50
uint8_t is_imm : 1;
51
52
// Specific value type, if known
53
uint8_t type : 4;
54
55
}
val_type_t
;
56
STATIC_ASSERT(val_type_size,
sizeof
(
val_type_t
) == 1);
57
58
// Unknown type, could be anything, all zeroes
59
#define TYPE_UNKNOWN ( (val_type_t){ 0 } )
60
61
// Could be any heap object
62
#define TYPE_HEAP ( (val_type_t){ .is_heap = 1 } )
63
64
// Could be any immediate
65
#define TYPE_IMM ( (val_type_t){ .is_imm = 1 } )
66
67
#define TYPE_NIL ( (val_type_t){ .is_imm = 1, .type = ETYPE_NIL } )
68
#define TYPE_TRUE ( (val_type_t){ .is_imm = 1, .type = ETYPE_TRUE } )
69
#define TYPE_FALSE ( (val_type_t){ .is_imm = 1, .type = ETYPE_FALSE } )
70
#define TYPE_FIXNUM ( (val_type_t){ .is_imm = 1, .type = ETYPE_FIXNUM } )
71
#define TYPE_FLONUM ( (val_type_t){ .is_imm = 1, .type = ETYPE_FLONUM } )
72
#define TYPE_STATIC_SYMBOL ( (val_type_t){ .is_imm = 1, .type = ETYPE_SYMBOL } )
73
#define TYPE_ARRAY ( (val_type_t){ .is_heap = 1, .type = ETYPE_ARRAY } )
74
#define TYPE_HASH ( (val_type_t){ .is_heap = 1, .type = ETYPE_HASH } )
75
#define TYPE_STRING ( (val_type_t){ .is_heap = 1, .type = ETYPE_STRING } )
76
77
enum
yjit_temp_loc
78
{
79
TEMP_STACK = 0,
80
TEMP_SELF,
81
TEMP_LOCAL,
// Local with index
82
//TEMP_CONST, // Small constant (0, 1, 2, Qnil, Qfalse, Qtrue)
83
};
84
85
// Potential mapping of a value on the temporary stack to
86
// self, a local variable or constant so that we can track its type
87
typedef
struct
yjit_temp_mapping
88
{
89
// Where/how is the value stored?
90
uint8_t kind: 2;
91
92
// Index of the local variale,
93
// or small non-negative constant in [0, 63]
94
uint8_t idx : 6;
95
96
}
temp_mapping_t
;
97
STATIC_ASSERT(temp_mapping_size,
sizeof
(
temp_mapping_t
) == 1);
98
99
// By default, temps are just temps on the stack.
100
// Name conflict with an mmap flag. This is a struct instance,
101
// so the compiler will check for wrong usage.
102
#undef MAP_STACK
103
#define MAP_STACK ( (temp_mapping_t) { 0 } )
104
105
// Temp value is actually self
106
#define MAP_SELF ( (temp_mapping_t) { .kind = TEMP_SELF } )
107
108
// Represents both the type and mapping
109
typedef
struct
{
110
temp_mapping_t
mapping;
111
val_type_t
type;
112
}
temp_type_mapping_t
;
113
STATIC_ASSERT(temp_type_mapping_size,
sizeof
(
temp_type_mapping_t
) == 2);
114
115
// Operand to a bytecode instruction
116
typedef
struct
yjit_insn_opnd
117
{
118
// Indicates if the value is self
119
bool
is_self;
120
121
// Index on the temporary stack (for stack operands only)
122
uint16_t idx;
123
124
}
insn_opnd_t
;
125
126
#define OPND_SELF ( (insn_opnd_t){ .is_self = true } )
127
#define OPND_STACK(stack_idx) ( (insn_opnd_t){ .is_self = false, .idx = stack_idx } )
128
133
typedef
struct
yjit_context
134
{
135
// Number of values currently on the temporary stack
136
uint16_t stack_size;
137
138
// Offset of the JIT SP relative to the interpreter SP
139
// This represents how far the JIT's SP is from the "real" SP
140
int16_t sp_offset;
141
142
// Depth of this block in the sidechain (eg: inline-cache chain)
143
uint8_t chain_depth;
144
145
// Local variable types we keepp track of
146
val_type_t
local_types[MAX_LOCAL_TYPES];
147
148
// Temporary variable types we keep track of
149
val_type_t
temp_types[MAX_TEMP_TYPES];
150
151
// Type we track for self
152
val_type_t
self_type;
153
154
// Mapping of temp stack entries to types we track
155
temp_mapping_t
temp_mapping[MAX_TEMP_TYPES];
156
157
}
ctx_t
;
158
STATIC_ASSERT(yjit_ctx_size,
sizeof
(
ctx_t
) <= 32);
159
160
// Tuple of (iseq, idx) used to identify basic blocks
161
typedef
struct
BlockId
162
{
163
// Instruction sequence
164
const
rb_iseq_t
*iseq;
165
166
// Index in the iseq where the block starts
167
uint32_t idx;
168
169
}
blockid_t
;
170
171
// Null block id constant
172
static
const
blockid_t
BLOCKID_NULL = { 0, 0 };
173
175
typedef
enum
branch_shape
176
{
177
SHAPE_NEXT0,
// Target 0 is next
178
SHAPE_NEXT1,
// Target 1 is next
179
SHAPE_DEFAULT
// Neither target is next
180
} branch_shape_t;
181
182
// Branch code generation function signature
183
typedef
void (*branchgen_fn)(
codeblock_t
* cb, uint8_t* target0, uint8_t* target1, uint8_t shape);
184
189
typedef
struct
yjit_branch_entry
190
{
191
// Block this is attached to
192
struct
yjit_block_version
*block;
193
194
// Positions where the generated code starts and ends
195
uint8_t *start_addr;
196
uint8_t *end_addr;
197
198
// Context right after the branch instruction
199
// Unused for now.
200
// ctx_t src_ctx;
201
202
// Branch target blocks and their contexts
203
blockid_t
targets[2];
204
ctx_t
target_ctxs[2];
205
struct
yjit_block_version
*blocks[2];
206
207
// Jump target addresses
208
uint8_t *dst_addrs[2];
209
210
// Branch code generation function
211
branchgen_fn gen_fn;
212
213
// Shape of the branch
214
branch_shape_t shape : 2;
215
216
}
branch_t
;
217
218
// In case this block is invalidated, these two pieces of info
219
// help to remove all pointers to this block in the system.
220
typedef
struct
{
221
VALUE
receiver_klass;
222
VALUE
callee_cme;
223
}
cme_dependency_t
;
224
225
typedef
rb_darray(
cme_dependency_t
) cme_dependency_array_t;
226
227
typedef
rb_darray(
branch_t
*) branch_array_t;
228
229
typedef
rb_darray(uint32_t) int32_array_t;
230
236
typedef
struct
yjit_block_version
237
{
238
// Bytecode sequence (iseq, idx) this is a version of
239
blockid_t
blockid;
240
241
// Context at the start of the block
242
ctx_t
ctx;
243
244
// Positions where the generated code starts and ends
245
uint8_t *start_addr;
246
uint8_t *end_addr;
247
248
// List of incoming branches (from predecessors)
249
branch_array_t incoming;
250
251
// List of outgoing branches (to successors)
252
// Note: these are owned by this block version
253
branch_array_t outgoing;
254
255
// Offsets for GC managed objects in the mainline code block
256
int32_array_t gc_object_offsets;
257
258
// CME dependencies of this block, to help to remove all pointers to this
259
// block in the system.
260
cme_dependency_array_t cme_dependencies;
261
262
// Code address of an exit for `ctx` and `blockid`. Used for block
263
// invalidation.
264
uint8_t *entry_exit;
265
266
// Index one past the last instruction in the iseq
267
uint32_t end_idx;
268
269
}
block_t
;
270
271
// Code generation state
272
typedef
struct
JITState
273
{
274
// Inline and outlined code blocks we are
275
// currently generating code into
276
codeblock_t
* cb;
277
codeblock_t
* ocb;
278
279
// Block version being compiled
280
block_t
*block;
281
282
// Instruction sequence this is associated with
283
const
rb_iseq_t
*iseq;
284
285
// Index of the current instruction being compiled
286
uint32_t insn_idx;
287
288
// Opcode for the instruction being compiled
289
int
opcode;
290
291
// PC of the instruction being compiled
292
VALUE
*pc;
293
294
// Side exit to the instruction being compiled. See :side-exit:.
295
uint8_t *side_exit_for_pc;
296
297
// Execution context when compilation started
298
// This allows us to peek at run-time values
299
rb_execution_context_t
*ec;
300
301
// Whether we need to record the code address at
302
// the end of this bytecode instruction for global invalidation
303
bool
record_boundary_patch_point;
304
305
}
jitstate_t
;
306
307
#endif
// #ifndef YJIT_CORE_H
BlockId
Definition
yjit_core.h:162
CodeBlock
Definition
yjit_asm.h:27
JITState
Definition
yjit_core.h:273
cme_dependency_t
Definition
yjit_core.h:220
rb_execution_context_struct
Definition
vm_core.h:919
rb_iseq_struct
Definition
vm_core.h:500
temp_type_mapping_t
Definition
yjit_core.h:109
yjit_block_version
Basic block version Represents a portion of an iseq compiled with a given context Note: care must be ...
Definition
yjit_core.h:237
yjit_branch_entry
Store info about an outgoing branch in a code segment Note: care must be taken to minimize the size o...
Definition
yjit_core.h:190
yjit_context
Code generation context Contains information we can use to optimize code.
Definition
yjit_core.h:134
yjit_insn_opnd
Definition
yjit_core.h:117
yjit_temp_mapping
Definition
yjit_core.h:88
yjit_type_struct
Definition
yjit_core.h:45
VALUE
uintptr_t VALUE
Type that represents a Ruby object.
Definition
value.h:40
Generated by
1.10.0