8000 Merge pull request #187 from Shopify/dedup-exits · github/ruby@76b9d72 · GitHub
[go: up one dir, main page]

Skip to content

Commit 76b9d72

Browse files
authored
Merge pull request #187 from Shopify/dedup-exits
Deduplicate side exits
2 parents aab2060 + f723c5f commit 76b9d72

File tree

2 files changed

+27
-8
lines changed

2 files changed

+27
-8
lines changed

yjit_codegen.c

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ jit_prepare_routine_call(jitstate_t *jit, ctx_t *ctx, x86opnd_t scratch_reg)
193193
}
194194

195195
// 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.
197197
static void
198198
record_global_inval_patch(const codeblock_t *cb, uint32_t outline_block_target_pos)
199199
{
@@ -355,7 +355,7 @@ yjit_gen_exit(VALUE *exit_pc, ctx_t *ctx, codeblock_t *cb)
355355
// Update the CFP on the EC
356356
mov(cb, member_opnd(REG_EC, rb_execution_context_t, cfp), REG_CFP);
357357

358-
// Put PC into the return register, which the post call bytes dispatches to
358+
// Update CFP->PC
359359
mov(cb, RAX, const_ptr_opnd(exit_pc));
360360
mov(cb, member_opnd(REG_CFP, rb_control_frame_t, pc), RAX);
361361

@@ -398,12 +398,27 @@ yjit_gen_leave_exit(codeblock_t *cb)
398398
return code_ptr;
399399
}
400400

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.
402413
static uint8_t *
403414
yjit_side_exit(jitstate_t *jit, ctx_t *ctx)
404415
{
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;
407422
}
408423

409424
// 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)
638653

639654
// Set the current instruction
640655
jit.insn_idx = insn_idx;
641-
jit.pc = pc;
642656
jit.opcode = opcode;
657+
jit.pc = pc;
658+
jit.side_exit_for_pc = NULL;
643659

644660
// If previous instruction requested to record the boundary
645661
if (jit.record_boundary_patch_point) {

yjit_codegen.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ extern uint32_t yjit_codepage_frozen_bytes;
1313
typedef struct JITState
1414
{
1515
// Block version being compiled
16-
block_t* block;
16+
block_t *block;
1717

1818
// Instruction sequence this is associated with
1919
const rb_iseq_t *iseq;
@@ -27,9 +27,12 @@ typedef struct JITState
2727
// PC of the instruction being compiled
2828
VALUE *pc;
2929

30+
// Side exit to the instruction being compiled. See :side-exit:.
31+
uint8_t *side_exit_for_pc;
32+
3033
// Execution context when compilation started
3134
// This allows us to peek at run-time values
32-
rb_execution_context_t* ec;
35+
rb_execution_context_t *ec;
3336

3437
// Whether we need to record the code address at
3538
// the end of this bytecode instruction for global invalidation

0 commit comments

Comments
 (0)
0