@@ -118,32 +118,16 @@ jit_peek_at_self(jitstate_t *jit, ctx_t *ctx)
118
118
return jit -> ec -> cfp -> self ;
119
119
}
120
120
121
- // When we know a VALUE to be static, this returns an appropriate val_type_t
122
- static val_type_t
123
- jit_type_of_value (VALUE val )
124
- {
125
- if (SPECIAL_CONST_P (val )) {
126
- if (FIXNUM_P (val )) {
127
- return TYPE_FIXNUM ;
128
- } else if (NIL_P (val )) {
129
- return TYPE_NIL ;
130
- } else {
131
- // generic immediate
132
- return TYPE_IMM ;
133
- }
134
- } else {
135
- switch (BUILTIN_TYPE (val )) {
136
- case T_ARRAY :
137
- return TYPE_ARRAY ;
138
- case T_HASH :
139
- return TYPE_HASH ;
140
- case T_STRING :
141
- return TYPE_STRING ;
142
- default :
143
- // generic heap object
144
- return TYPE_HEAP ;
145
- }
146
- }
121
+ static VALUE
122
+ jit_peek_at_local (jitstate_t * jit , ctx_t * ctx , int n )
123
+ {
124
+ RUBY_ASSERT (jit_at_current_insn (jit ));
125
+
126
+ int32_t local_table_size = jit -> iseq -> body -> local_table_size ;
127
+ RUBY_ASSERT (n < (int )jit -> iseq -> body -> local_table_size );
128
+
129
+ const VALUE * ep = jit -> ec -> cfp -> ep ;
130
+ return ep [- VM_ENV_DATA_SIZE - local_table_size + n + 1 ];
147
131
}
148
132
149
133
// Save the incremented PC on the CFP
@@ -223,11 +207,70 @@ _add_comment(codeblock_t* cb, const char* comment_str)
223
207
#define ADD_COMMENT (cb , comment ) _add_comment((cb), (comment))
224
208
yjit_comment_array_t yjit_code_comments ;
225
209
210
+ // Verify the ctx's types and mappings against the compile-time stack, self,
211
+ // and locals.
212
+ static void
213
+ verify_ctx (jitstate_t * jit , ctx_t * ctx )
214
+ {
215
+ // Only able to check types when at current insn
216
+ RUBY_ASSERT (jit_at_current_insn (jit ));
217
+
218
+ VALUE self_val = jit_peek_at_self (jit , ctx );
219
+ if (type_diff (yjit_type_of_value (self_val ), ctx -> self_type ) == INT_MAX ) {
220
+ rb_bug ("verify_ctx: ctx type (%s) incompatible with actual value of self: %s" , yjit_type_name (ctx -> self_type ), rb_obj_info (self_val ));
221
+ }
222
+
223
+ for (int i = 0 ; i < ctx -> stack_size && i < MAX_TEMP_TYPES ; i ++ ) {
224
+ temp_type_mapping_t learned = ctx_get_opnd_mapping (ctx , OPND_STACK (i ));
225
+ VALUE val = jit_peek_at_stack (jit , ctx , i );
226
+ val_type_t detected = yjit_type_of_value (val );
227
+
228
+ if (learned .mapping .kind == TEMP_SELF ) {
229
+ if (self_val != val ) {
230
+ rb_bug ("verify_ctx: stack value was mapped to self, but values did not match\n"
231
+ " stack: %s\n"
232
+ " self: %s" ,
233
+ rb_obj_info (val ),
234
+ rb_obj_info (self_val ));
235
+ }
236
+ }
237
+
238
+ if (learned .mapping .kind == TEMP_LOCAL ) {
239
+ int local_idx = learned .mapping .idx ;
240
+ VALUE local_val = jit_peek_at_local (jit , ctx , local_idx );
241
+ if (local_val != val ) {
242
+ rb_bug ("verify_ctx: stack value was mapped to local, but values did not match\n"
243
+ " stack: %s\n"
244
+ " local %i: %s" ,
245
+ rb_obj_info (val ),
246
+ local_idx ,
247
+ rb_obj_info (local_val ));
248
+ }
249
+ }
250
+
251
+ if (type_diff (detected , learned .type ) == INT_MAX ) {
252
+ rb_bug ("verify_ctx: ctx type (%s) incompatible with actual value on stack: %s" , yjit_type_name (learned .type ), rb_obj_info (val ));
253
+ }
254
+ }
255
+
256
+ int32_t local_table_size = jit -> iseq -> body -> local_table_size ;
257
+ for (int i = 0 ; i < local_table_size && i < MAX_TEMP_TYPES ; i ++ ) {
258
+ val_type_t learned = ctx -> local_types [i ];
259
+ VALUE val = jit_peek_at_local (jit , ctx , i );
260
+ val_type_t detected = yjit_type_of_value (val );
261
+
262
+ if (type_diff (detected , learned ) == INT_MAX ) {
263
+ rb_bug ("verify_ctx: ctx type (%s) incompatible with actual value of local: %s" , yjit_type_name (learned ), rb_obj_info (val ));
264
+ }
265
+ }
266
+ }
267
+
226
268
#else
227
269
228
270
#define GEN_COUNTER_INC (cb , counter_name ) ((void)0)
229
271
#define COUNTED_EXIT (side_exit , counter_name ) side_exit
230
272
#define ADD_COMMENT (cb , comment ) ((void)0)
273
+ #define verify_ctx (jit , ctx ) ((void)0)
231
274
232
275
#endif // if RUBY_DEBUG
233
276
@@ -475,6 +518,11 @@ yjit_gen_block(block_t *block, rb_execution_context_t *ec)
475
518
jit .pc = pc ;
476
519
jit .opcode = opcode ;
477
520
521
+ // Verify our existing assumption (DEBUG)
522
+ if (jit_at_current_insn (& jit )) {
523
+ verify_ctx (& jit , ctx );
524
+ }
525
+
478
526
// Lookup the codegen function for this instruction
479
527
codegen_fn gen_fn = gen_fns [opcode ];
480
528
if (!gen_fn ) {
@@ -907,7 +955,7 @@ gen_putobject(jitstate_t* jit, ctx_t* ctx)
907
955
VALUE put_val = jit_get_arg (jit , 0 );
908
956
jit_mov_gc_ptr (jit , cb , REG0 , put_val );
909
957
910
- val_type_t val_type = jit_type_of_value (put_val );
958
+ val_type_t val_type = yjit_type_of_value (put_val );
911
959
912
960
// Write argument at SP
913
961
x86opnd_t stack_top = ctx_stack_push (ctx , val_type );
@@ -3546,7 +3594,7 @@ gen_opt_getinlinecache(jitstate_t *jit, ctx_t *ctx)
3546
3594
// FIXME: This leaks when st_insert raises NoMemoryError
3547
3595
assume_stable_global_constant_state (jit -> block );
3548
3596
3549
- val_type_t type = jit_type_of_value (ice -> value );
3597
+ val_type_t type = yjit_type_of_value (ice -> value );
3550
3598
x86opnd_t stack_top = ctx_stack_push (ctx , type );
3551
3599
jit_mov_gc_ptr (jit , cb , REG0 , ice -> value );
3552
3600
mov (cb , stack_top , REG0 );
0 commit comments