mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Deduplicate side exits
Send instructions currently generate the exact same side exit twice. Cache the exit the first time we generate it. Also add a comment explaining what side exits do. Closes GH-117.
This commit is contained in:
parent
6e1f2519cc
commit
cbb0271dd6
2 changed files with 27 additions and 8 deletions
|
@ -193,7 +193,7 @@ jit_prepare_routine_call(jitstate_t *jit, ctx_t *ctx, x86opnd_t scratch_reg)
|
|||
}
|
||||
|
||||
// Record the current codeblock write position for rewriting into a jump into
|
||||
// the outline block later. Used to implement global code invalidation.
|
||||
// the outlined block later. Used to implement global code invalidation.
|
||||
static void
|
||||
record_global_inval_patch(const codeblock_t *cb, uint32_t outline_block_target_pos)
|
||||
{
|
||||
|
@ -355,7 +355,7 @@ yjit_gen_exit(VALUE *exit_pc, ctx_t *ctx, codeblock_t *cb)
|
|||
// Update the CFP on the EC
|
||||
mov(cb, member_opnd(REG_EC, rb_execution_context_t, cfp), REG_CFP);
|
||||
|
||||
// Put PC into the return register, which the post call bytes dispatches to
|
||||
// Update CFP->PC
|
||||
mov(cb, RAX, const_ptr_opnd(exit_pc));
|
||||
mov(cb, member_opnd(REG_CFP, rb_control_frame_t, pc), RAX);
|
||||
|
||||
|
@ -398,12 +398,27 @@ yjit_gen_leave_exit(codeblock_t *cb)
|
|||
return code_ptr;
|
||||
}
|
||||
|
||||
// A shorthand for generating an exit in the outline block
|
||||
// :side-exit:
|
||||
// Get an exit for the current instruction in the outlined block. The code
|
||||
// for each instruction often begins with several guards before proceeding
|
||||
// to do work. When guards fail, an option we have is to exit to the
|
||||
// interpreter at an instruction boundary. The piece of code that takes
|
||||
// care of reconstructing interpreter state and exiting out of generated
|
||||
// code is called the side exit.
|
||||
//
|
||||
// No guards change the logic for reconstructing interpreter state at the
|
||||
// moment, so there is one unique side exit for each context. Note that
|
||||
// it's incorrect to jump to the side exit after any ctx stack push/pop operations
|
||||
// since they change the logic required for reconstructing interpreter state.
|
||||
static uint8_t *
|
||||
yjit_side_exit(jitstate_t *jit, ctx_t *ctx)
|
||||
{
|
||||
uint32_t pos = yjit_gen_exit(jit->pc, ctx, ocb);
|
||||
return cb_get_ptr(ocb, pos);
|
||||
if (!jit->side_exit_for_pc) {
|
||||
uint32_t pos = yjit_gen_exit(jit->pc, ctx, ocb);
|
||||
jit->side_exit_for_pc = cb_get_ptr(ocb, pos);
|
||||
}
|
||||
|
||||
return jit->side_exit_for_pc;
|
||||
}
|
||||
|
||||
// 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)
|
|||
|
||||
// Set the current instruction
|
||||
jit.insn_idx = insn_idx;
|
||||
jit.pc = pc;
|
||||
jit.opcode = opcode;
|
||||
jit.pc = pc;
|
||||
jit.side_exit_for_pc = NULL;
|
||||
|
||||
// If previous instruction requested to record the boundary
|
||||
if (jit.record_boundary_patch_point) {
|
||||
|
|
|
@ -13,7 +13,7 @@ extern uint32_t yjit_codepage_frozen_bytes;
|
|||
typedef struct JITState
|
||||
{
|
||||
// Block version being compiled
|
||||
block_t* block;
|
||||
block_t *block;
|
||||
|
||||
// Instruction sequence this is associated with
|
||||
const rb_iseq_t *iseq;
|
||||
|
@ -27,9 +27,12 @@ typedef struct JITState
|
|||
// PC of the instruction being compiled
|
||||
VALUE *pc;
|
||||
|
||||
// Side exit to the instruction being compiled. See :side-exit:.
|
||||
uint8_t *side_exit_for_pc;
|
||||
|
||||
// Execution context when compilation started
|
||||
// This allows us to peek at run-time values
|
||||
rb_execution_context_t* ec;
|
||||
rb_execution_context_t *ec;
|
||||
|
||||
// Whether we need to record the code address at
|
||||
// the end of this bytecode instruction for global invalidation
|
||||
|
|
Loading…
Add table
Reference in a new issue