Ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e0ba6b95ab71a441357ed5484e33498)
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
29enum 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
44typedef 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
56STATIC_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
77enum 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
87typedef 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
97STATIC_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
109typedef struct {
110 temp_mapping_t mapping;
113STATIC_ASSERT(temp_type_mapping_size, sizeof(temp_type_mapping_t) == 2);
114
115// Operand to a bytecode instruction
116typedef 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
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
133typedef 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;
158STATIC_ASSERT(yjit_ctx_size, sizeof(ctx_t) <= 32);
159
160// Tuple of (iseq, idx) used to identify basic blocks
161typedef 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
172static const blockid_t BLOCKID_NULL = { 0, 0 };
173
175typedef 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
183typedef void (*branchgen_fn)(codeblock_t* cb, uint8_t* target0, uint8_t* target1, uint8_t shape);
184
189typedef 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.
220typedef struct {
221 VALUE receiver_klass;
222 VALUE callee_cme;
224
225typedef rb_darray(cme_dependency_t) cme_dependency_array_t;
226
227typedef rb_darray(branch_t*) branch_array_t;
228
229typedef rb_darray(uint32_t) int32_array_t;
230
236typedef 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
272typedef 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
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
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:56
Basic block version Represents a portion of an iseq compiled with a given context Note: care must be ...
Definition: yjit_core.h:237
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
Code generation context Contains information we can use to optimize code.
Definition: yjit_core.h:134