13 // Scratch registers used by YJIT
20 // Maximum number of temp value types we keep track of
21 #define MAX_TEMP_TYPES 8
23 // Maximum number of local variable types we keep track of
24 #define MAX_LOCAL_TYPES 8
26 // Default versioning context (no type information)
27 #define DEFAULT_CTX ( (ctx_t){ 0 } )
43 // Represent the type of a value (local/stack/self) in YJIT
44 typedef struct yjit_type_struct
46 // Value is definitely a heap object
49 // Value is definitely an immediate
52 // Specific value type, if known
56 STATIC_ASSERT(val_type_size
, sizeof(val_type_t
) == 1);
58 // Unknown type, could be anything, all zeroes
59 #define TYPE_UNKNOWN ( (val_type_t){ 0 } )
61 // Could be any heap object
62 #define TYPE_HEAP ( (val_type_t){ .is_heap = 1 } )
64 // Could be any immediate
65 #define TYPE_IMM ( (val_type_t){ .is_imm = 1 } )
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 } )
81 TEMP_LOCAL
, // Local with index
82 //TEMP_CONST, // Small constant (0, 1, 2, Qnil, Qfalse, Qtrue)
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
89 // Where/how is the value stored?
92 // Index of the local variale,
93 // or small non-negative constant in [0, 63]
97 STATIC_ASSERT(temp_mapping_size
, sizeof(temp_mapping_t
) == 1);
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.
103 #define MAP_STACK ( (temp_mapping_t) { 0 } )
105 // Temp value is actually self
106 #define MAP_SELF ( (temp_mapping_t) { .kind = TEMP_SELF } )
108 // Represents both the type and mapping
110 temp_mapping_t mapping
;
112 } temp_type_mapping_t
;
113 STATIC_ASSERT(temp_type_mapping_size
, sizeof(temp_type_mapping_t
) == 2);
115 // Operand to a bytecode instruction
116 typedef struct yjit_insn_opnd
118 // Indicates if the value is self
121 // Index on the temporary stack (for stack operands only)
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 } )
130 Code generation context
131 Contains information we can use to optimize code
133 typedef struct yjit_context
135 // Number of values currently on the temporary stack
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
142 // Depth of this block in the sidechain (eg: inline-cache chain)
145 // Local variable types we keepp track of
146 val_type_t local_types
[MAX_LOCAL_TYPES
];
148 // Temporary variable types we keep track of
149 val_type_t temp_types
[MAX_TEMP_TYPES
];
151 // Type we track for self
152 val_type_t self_type
;
154 // Mapping of temp stack entries to types we track
155 temp_mapping_t temp_mapping
[MAX_TEMP_TYPES
];
158 STATIC_ASSERT(yjit_ctx_size
, sizeof(ctx_t
) <= 32);
160 // Tuple of (iseq, idx) used to identify basic blocks
161 typedef struct BlockId
163 // Instruction sequence
164 const rb_iseq_t
*iseq
;
166 // Index in the iseq where the block starts
171 // Null block id constant
172 static const blockid_t BLOCKID_NULL
= { 0, 0 };
174 /// Branch code shape enumeration
175 typedef enum branch_shape
177 SHAPE_NEXT0
, // Target 0 is next
178 SHAPE_NEXT1
, // Target 1 is next
179 SHAPE_DEFAULT
// Neither target is next
182 // Branch code generation function signature
183 typedef void (*branchgen_fn
)(codeblock_t
* cb
, uint8_t* target0
, uint8_t* target1
, uint8_t shape
);
186 Store info about an outgoing branch in a code segment
187 Note: care must be taken to minimize the size of branch_t objects
189 typedef struct yjit_branch_entry
191 // Block this is attached to
192 struct yjit_block_version
*block
;
194 // Positions where the generated code starts and ends
198 // Context right after the branch instruction
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];
207 // Jump target addresses
208 uint8_t *dst_addrs
[2];
210 // Branch code generation function
213 // Shape of the branch
214 branch_shape_t shape
: 2;
218 // In case this block is invalidated, these two pieces of info
219 // help to remove all pointers to this block in the system.
221 VALUE receiver_klass
;
225 typedef rb_darray(cme_dependency_t
) cme_dependency_array_t
;
227 typedef rb_darray(branch_t
*) branch_array_t
;
229 typedef rb_darray(uint32_t) int32_array_t
;
233 Represents a portion of an iseq compiled with a given context
234 Note: care must be taken to minimize the size of block_t objects
236 typedef struct yjit_block_version
238 // Bytecode sequence (iseq, idx) this is a version of
241 // Context at the start of the block
244 // Positions where the generated code starts and ends
248 // List of incoming branches (from predecessors)
249 branch_array_t incoming
;
251 // List of outgoing branches (to successors)
252 // Note: these are owned by this block version
253 branch_array_t outgoing
;
255 // Offsets for GC managed objects in the mainline code block
256 int32_array_t gc_object_offsets
;
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
;
262 // Code address of an exit for `ctx` and `blockid`. Used for block
266 // Index one past the last instruction in the iseq
271 // Code generation state
272 typedef struct JITState
274 // Inline and outlined code blocks we are
275 // currently generating code into
279 // Block version being compiled
282 // Instruction sequence this is associated with
283 const rb_iseq_t
*iseq
;
285 // Index of the current instruction being compiled
288 // Opcode for the instruction being compiled
291 // PC of the instruction being compiled
294 // Side exit to the instruction being compiled. See :side-exit:.
295 uint8_t *side_exit_for_pc
;
297 // Execution context when compilation started
298 // This allows us to peek at run-time values
299 rb_execution_context_t
*ec
;
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
;
307 #endif // #ifndef YJIT_CORE_H