@@ -193,7 +193,7 @@ jit_prepare_routine_call(jitstate_t *jit, ctx_t *ctx, x86opnd_t scratch_reg)
193
193
}
194
194
195
195
// Record the current codeblock write position for rewriting into a jump into
196
- // the outline block later. Used to implement global code invalidation.
196
+ // the outlined block later. Used to implement global code invalidation.
197
197
static void
198
198
record_global_inval_patch (const codeblock_t * cb , uint32_t outline_block_target_pos )
199
199
{
@@ -355,7 +355,7 @@ yjit_gen_exit(VALUE *exit_pc, ctx_t *ctx, codeblock_t *cb)
355
355
// Update the CFP on the EC
356
356
mov (cb , member_opnd (REG_EC , rb_execution_context_t , cfp ), REG_CFP );
357
357
358
- // Put PC into the return register, which the post call bytes dispatches to
358
+ // Update CFP->PC
359
359
mov (cb , RAX , const_ptr_opnd (exit_pc ));
360
360
mov (cb , member_opnd (REG_CFP , rb_control_frame_t , pc ), RAX );
361
361
@@ -398,12 +398,27 @@ yjit_gen_leave_exit(codeblock_t *cb)
398
398
return code_ptr ;
399
399
}
400
400
401
- // A shorthand for generating an exit in the outline block
401
+ // :side-exit:
402
+ // Get an exit for the current instruction in the outlined block. The code
403
+ // for each instruction often begins with several guards before proceeding
404
+ // to do work. When guards fail, an option we have is to exit to the
405
+ // interpreter at an instruction boundary. The piece of code that takes
406
+ // care of reconstructing interpreter state and exiting out of generated
407
+ // code is called the side exit.
408
+ //
409
+ // No guards change the logic for reconstructing interpreter state at the
410
+ // moment, so there is one unique side exit for each context. Note that
411
+ // it's incorrect to jump to the side exit after any ctx stack push/pop operations
412
+ // since they change the logic required for reconstructing interpreter state.
402
413
static uint8_t *
403
414
yjit_side_exit (jitstate_t * jit , ctx_t * ctx )
404
415
{
405
- uint32_t pos = yjit_gen_exit (jit -> pc , ctx , ocb );
406
- return cb_get_ptr (ocb , pos );
416
+ if (!jit -> side_exit_for_pc ) {
417
+ uint32_t pos = yjit_gen_exit (jit -> pc , ctx , ocb );
418
+ jit -> side_exit_for_pc = cb_get_ptr (ocb , pos );
419
+ }
420
+
421
+ return jit -> side_exit_for_pc ;
407
422
}
408
423
409
424
// Generate a runtime guard that ensures the PC is at the start of the iseq,
@@ -638,8 +653,9 @@ yjit_gen_block(block_t *block, rb_execution_context_t *ec)
638
653
639
654
// Set the current instruction
640
655
jit .insn_idx = insn_idx ;
641
- jit .pc = pc ;
642
656
jit .opcode = opcode ;
657
+ jit .pc = pc ;
658
+ jit .side_exit_for_pc = NULL ;
643
659
644
660
// If previous instruction requested to record the boundary
645
661
if (jit .record_boundary_patch_point ) {
0 commit comments