1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

YJIT: use a context-free landing pad to optimize leave

This allows gen_leave to always do an indirect to cfp->jit_return.
This commit is contained in:
Alan Wu 2021-04-19 18:23:07 -04:00
parent 9bd779cbf9
commit 1610dc0864

View file

@ -27,6 +27,9 @@ codeblock_t* cb = NULL;
static codeblock_t outline_block;
codeblock_t* ocb = NULL;
// Code for exiting back to the interpreter
static void *interp_exit;
// Print the current source location for debugging purposes
RBIMPL_ATTR_MAYBE_UNUSED()
static void
@ -137,7 +140,7 @@ yjit_load_regs(codeblock_t* cb)
static uint8_t *
yjit_gen_exit(jitstate_t *jit, ctx_t *ctx, codeblock_t *cb)
{
uint8_t *code_ptr = cb_get_ptr(ocb, ocb->write_pos);
uint8_t *code_ptr = cb_get_ptr(cb, cb->write_pos);
VALUE *exit_pc = jit->pc;
@ -184,6 +187,26 @@ yjit_gen_exit(jitstate_t *jit, ctx_t *ctx, codeblock_t *cb)
return code_ptr;
}
// Generate an interpreter to REG_CFP->pc.
static uint8_t *
yjit_gen_context_free_exit(codeblock_t *cb)
{
uint8_t *code_ptr = cb_get_ptr(cb, cb->write_pos);
// 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
mov(cb, RAX, member_opnd(REG_CFP, rb_control_frame_t, pc));
cb_write_post_call_bytes(cb);
// Note, not incrementing stats here since this exit is the natural end to
// executing output code.
return code_ptr;
}
// A shorthand for generating an exit in the outline block
static uint8_t *
@ -251,7 +274,7 @@ yjit_comment_array_t yjit_code_comments;
Compile an interpreter entry block to be inserted into an iseq
Returns `NULL` if compilation fails.
*/
uint8_t*
uint8_t *
yjit_entry_prologue(void)
{
RUBY_ASSERT(cb != NULL);
@ -271,6 +294,11 @@ yjit_entry_prologue(void)
// Load the current SP from the CFP into REG_SP
mov(cb, REG_SP, member_opnd(REG_CFP, rb_control_frame_t, sp));
// Setup cfp->jit_return
// TODO: this could use a IP relative LEA instead of an 8 byte immediate
mov(cb, REG0, const_ptr_opnd(interp_exit));
mov(cb, member_opnd(REG_CFP, rb_control_frame_t, jit_return), REG0);
return code_ptr;
}
@ -2076,21 +2104,9 @@ gen_leave(jitstate_t* jit, ctx_t* ctx)
mov(cb, REG_SP, member_opnd(REG_CFP, rb_control_frame_t, sp));
mov(cb, mem_opnd(64, REG_SP, -SIZEOF_VALUE), REG0);
// If the return address is NULL, fall back to the interpreter
ADD_COMMENT(cb, "check for jit return");
int FALLBACK_LABEL = cb_new_label(cb, "FALLBACK");
test(cb, REG1, REG1);
jz_label(cb, FALLBACK_LABEL);
// Jump to the JIT return address
jmp_rm(cb, REG1);
// Fall back to the interpreter
cb_write_label(cb, FALLBACK_LABEL);
cb_link_labels(cb);
GEN_COUNTER_INC(cb, leave_interp_return);
cb_write_post_call_bytes(cb);
return YJIT_END_BLOCK;
}
@ -2151,12 +2167,17 @@ yjit_init_codegen(void)
{
// Initialize the code blocks
uint32_t mem_size = 128 * 1024 * 1024;
uint8_t* mem_block = alloc_exec_mem(mem_size);
uint8_t *mem_block = alloc_exec_mem(mem_size);
cb = █
cb_init(cb, mem_block, mem_size/2);
ocb = &outline_block;
cb_init(ocb, mem_block + mem_size/2, mem_size/2);
// Generate interp_exit
interp_exit = yjit_gen_context_free_exit(cb);
// Map YARV opcodes to the corresponding codegen functions
yjit_reg_op(BIN(dup), gen_dup);
yjit_reg_op(BIN(nop), gen_nop);