summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mjit.h18
-rw-r--r--yjit.h2
-rw-r--r--yjit_codegen.c48
-rw-r--r--yjit_iface.c13
-rw-r--r--yjit_iface.h1
5 files changed, 43 insertions, 39 deletions
diff --git a/mjit.h b/mjit.h
index e6bf6be8dc..1694fcba88 100644
--- a/mjit.h
+++ b/mjit.h
@@ -150,17 +150,27 @@ mjit_exec(rb_execution_context_t *ec)
#ifndef MJIT_HEADER
if (rb_yjit_enabled_p() && !mjit_call_p && body->total_calls == rb_yjit_call_threshold()) {
- rb_yjit_compile_iseq(iseq, ec);
- return Qundef;
+ // If we couldn't generate any code for this iseq, then return
+ // Qundef so the interpreter will handle the call.
+ if (!rb_yjit_compile_iseq(iseq, ec)) {
+ return Qundef;
+ }
}
#endif
- if (!mjit_call_p)
+ if (!(mjit_call_p || rb_yjit_enabled_p()))
return Qundef;
RB_DEBUG_COUNTER_INC(mjit_exec);
mjit_func_t func = body->jit_func;
+
+ // YJIT tried compiling this function once before and couldn't do
+ // it, so return Qundef so the interpreter handles it.
+ if (rb_yjit_enabled_p() && func == 0) {
+ return Qundef;
+ }
+
if (UNLIKELY((uintptr_t)func <= LAST_JIT_ISEQ_FUNC)) {
# ifdef MJIT_HEADER
RB_DEBUG_COUNTER_INC(mjit_frame_JT2VM);
@@ -176,6 +186,8 @@ mjit_exec(rb_execution_context_t *ec)
RB_DEBUG_COUNTER_INC(mjit_frame_VM2JT);
# endif
RB_DEBUG_COUNTER_INC(mjit_exec_call_func);
+ // ec -> RDI
+ // cfp -> RSI
return func(ec, ec->cfp);
}
diff --git a/yjit.h b/yjit.h
index cb41e76ecf..0e7a7b6c9b 100644
--- a/yjit.h
+++ b/yjit.h
@@ -62,7 +62,7 @@ void rb_yjit_cme_invalidate(VALUE cme);
void rb_yjit_collect_vm_usage_insn(int insn);
void rb_yjit_collect_binding_alloc(void);
void rb_yjit_collect_binding_set(void);
-void rb_yjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec);
+bool rb_yjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec);
void rb_yjit_init(struct rb_yjit_options *options);
void rb_yjit_bop_redefined(VALUE klass, const rb_method_entry_t *me, enum ruby_basic_operators bop);
void rb_yjit_constant_state_changed(void);
diff --git a/yjit_codegen.c b/yjit_codegen.c
index f126407dc8..25d265432d 100644
--- a/yjit_codegen.c
+++ b/yjit_codegen.c
@@ -261,21 +261,6 @@ yjit_gen_exit(jitstate_t *jit, ctx_t *ctx, codeblock_t *cb)
VALUE *exit_pc = jit->pc;
- // YJIT only ever patches the first instruction in an iseq
- if (jit->insn_idx == 0) {
- // Table mapping opcodes to interpreter handlers
- const void *const *handler_table = rb_vm_get_insns_address_table();
-
- // Write back the old instruction at the exit PC
- // Otherwise the interpreter may jump right back to the
- // JITted code we're trying to exit
- int exit_opcode = yjit_opcode_at_pc(jit->iseq, exit_pc);
- void* handler_addr = (void*)handler_table[exit_opcode];
- mov(cb, REG0, const_ptr_opnd(exit_pc));
- mov(cb, REG1, const_ptr_opnd(handler_addr));
- mov(cb, mem_opnd(64, REG0, 0), REG1);
- }
-
// Generate the code to exit to the interpreters
// Write the adjusted SP back into the CFP
if (ctx->sp_offset != 0) {
@@ -299,7 +284,8 @@ yjit_gen_exit(jitstate_t *jit, ctx_t *ctx, codeblock_t *cb)
}
#endif
- cb_write_post_call_bytes(cb);
+ mov(cb, RAX, imm_opnd(Qundef));
+ ret(cb);
return code_ptr;
}
@@ -316,10 +302,13 @@ yjit_gen_leave_exit(codeblock_t *cb)
// Every exit to the interpreter should be counted
GEN_COUNTER_INC(cb, leave_interp_return);
- // 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));
+ // GEN_COUNTER_INC clobbers RAX, so put the top of the stack
+ // in to RAX and return.
+ mov(cb, RAX, mem_opnd(64, REG_SP, -SIZEOF_VALUE));
+ sub(cb, member_opnd(REG_CFP, rb_control_frame_t, sp), imm_opnd(SIZEOF_VALUE));
+ mov(cb, REG_SP, member_opnd(REG_CFP, rb_control_frame_t, sp));
- cb_write_post_call_bytes(cb);
+ ret(cb);
return code_ptr;
}
@@ -348,9 +337,14 @@ yjit_entry_prologue(void)
cb_align_pos(cb, 64);
uint8_t *code_ptr = cb_get_ptr(cb, cb->write_pos);
+ ADD_COMMENT(cb, "yjit prolog");
- // Write the interpreter entry prologue
- cb_write_pre_call_bytes(cb);
+ // Fix registers for YJIT. The MJIT callback puts the ec in RDI
+ // and the CFP in RSI, but REG_CFP == RDI and REG_EC == RSI
+ mov(cb, REG0, RDI); // EC
+ mov(cb, REG1, RSI); // CFP
+ mov(cb, REG_EC, REG0);
+ mov(cb, REG_CFP, REG1);
// Load the current SP from the CFP into REG_SP
mov(cb, REG_SP, member_opnd(REG_CFP, rb_control_frame_t, sp));
@@ -363,7 +357,8 @@ yjit_entry_prologue(void)
return code_ptr;
}
-// Generate code to check for interrupts and take a side-exit
+// Generate code to check for interrupts and take a side-exit.
+// Warning: this function clobbers REG0
static void
yjit_check_ints(codeblock_t* cb, uint8_t* side_exit)
{
@@ -3374,15 +3369,10 @@ gen_leave(jitstate_t* jit, ctx_t* ctx)
uint8_t* side_exit = yjit_side_exit(jit, ctx);
// Load environment pointer EP from CFP
- mov(cb, REG0, member_opnd(REG_CFP, rb_control_frame_t, ep));
-
- // if (flags & VM_FRAME_FLAG_FINISH) != 0
- ADD_COMMENT(cb, "check for finish frame");
- x86opnd_t flags_opnd = mem_opnd(64, REG0, sizeof(VALUE) * VM_ENV_DATA_INDEX_FLAGS);
- test(cb, flags_opnd, imm_opnd(VM_FRAME_FLAG_FINISH));
- jnz_ptr(cb, COUNTED_EXIT(side_exit, leave_se_finish_frame));
+ mov(cb, REG1, member_opnd(REG_CFP, rb_control_frame_t, ep));
// Check for interrupts
+ ADD_COMMENT(cb, "check for interrupts");
yjit_check_ints(cb, COUNTED_EXIT(side_exit, leave_se_interrupt));
// Load the return value
diff --git a/yjit_iface.c b/yjit_iface.c
index d347cbd5ef..c6fdb7124e 100644
--- a/yjit_iface.c
+++ b/yjit_iface.c
@@ -465,9 +465,10 @@ yjit_block_assumptions_free(block_t *block)
}
}
-void
+bool
rb_yjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec)
{
+ bool success = true;
#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
RB_VM_LOCK_ENTER();
// TODO: I think we need to stop all other ractors here
@@ -478,14 +479,16 @@ rb_yjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec)
if (code_ptr)
{
- // Map the code address to the corresponding opcode
- int first_opcode = yjit_opcode_at_pc(iseq, &encoded[0]);
- map_addr2insn(code_ptr, first_opcode);
- encoded[0] = (VALUE)code_ptr;
+ iseq->body->jit_func = code_ptr;
+ }
+ else {
+ iseq->body->jit_func = 0;
+ success = false;
}
RB_VM_LOCK_LEAVE();
#endif
+ return success;
}
struct yjit_block_itr {
diff --git a/yjit_iface.h b/yjit_iface.h
index 30bee18ed1..4f63cdb974 100644
--- a/yjit_iface.h
+++ b/yjit_iface.h
@@ -46,7 +46,6 @@ YJIT_DECLARE_COUNTERS(
send_se_cf_overflow,
send_se_protected_check_failed,
- leave_se_finish_frame,
leave_se_interrupt,
leave_interp_return,