YJIT: implement side chain fallback for setlocal to avoid exiting (#8227)
* YJIT: implement side chain fallback for setlocal to avoid exiting * Update yjit/src/codegen.rs Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com> --------- Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com>
This commit is contained in:
parent
7433c8f7dd
commit
30a5b94517
Notes:
git
2023-08-17 14:11:38 +00:00
Merged-By: maximecb <maximecb@ruby-lang.org>
@ -661,7 +661,7 @@ class TestYJIT < Test::Unit::TestCase
|
|||||||
|
|
||||||
def test_send_block
|
def test_send_block
|
||||||
# Setlocal_wc_0 sometimes side-exits on write barrier
|
# Setlocal_wc_0 sometimes side-exits on write barrier
|
||||||
assert_compiles(<<~'RUBY', result: "b:n/b:y/b:y/b:n", exits: { :setlocal_WC_0 => 0..1 })
|
assert_compiles(<<~'RUBY', result: "b:n/b:y/b:y/b:n")
|
||||||
def internal_method(&b)
|
def internal_method(&b)
|
||||||
"b:#{block_given? ? "y" : "n"}"
|
"b:#{block_given? ? "y" : "n"}"
|
||||||
end
|
end
|
||||||
|
@ -1758,6 +1758,7 @@ rb_thread_t * ruby_thread_from_native(void);
|
|||||||
int ruby_thread_set_native(rb_thread_t *th);
|
int ruby_thread_set_native(rb_thread_t *th);
|
||||||
int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, ID *called_idp, VALUE *klassp);
|
int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, ID *called_idp, VALUE *klassp);
|
||||||
void rb_vm_rewind_cfp(rb_execution_context_t *ec, rb_control_frame_t *cfp);
|
void rb_vm_rewind_cfp(rb_execution_context_t *ec, rb_control_frame_t *cfp);
|
||||||
|
void rb_vm_env_write(const VALUE *ep, int index, VALUE v);
|
||||||
VALUE rb_vm_bh_to_procval(const rb_execution_context_t *ec, VALUE block_handler);
|
VALUE rb_vm_bh_to_procval(const rb_execution_context_t *ec, VALUE block_handler);
|
||||||
|
|
||||||
void rb_vm_register_special_exception_str(enum ruby_special_exceptions sp, VALUE exception_class, VALUE mesg);
|
void rb_vm_register_special_exception_str(enum ruby_special_exceptions sp, VALUE exception_class, VALUE mesg);
|
||||||
|
@ -505,6 +505,12 @@ vm_env_write(const VALUE *ep, int index, VALUE v)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_vm_env_write(const VALUE *ep, int index, VALUE v)
|
||||||
|
{
|
||||||
|
vm_env_write(ep, index, v);
|
||||||
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_vm_bh_to_procval(const rb_execution_context_t *ec, VALUE block_handler)
|
rb_vm_bh_to_procval(const rb_execution_context_t *ec, VALUE block_handler)
|
||||||
{
|
{
|
||||||
|
@ -283,6 +283,7 @@ fn main() {
|
|||||||
.blocklist_type("rb_control_frame_struct")
|
.blocklist_type("rb_control_frame_struct")
|
||||||
.opaque_type("rb_control_frame_struct")
|
.opaque_type("rb_control_frame_struct")
|
||||||
.allowlist_function("rb_vm_bh_to_procval")
|
.allowlist_function("rb_vm_bh_to_procval")
|
||||||
|
.allowlist_function("rb_vm_env_write")
|
||||||
.allowlist_function("rb_vm_ep_local_ep")
|
.allowlist_function("rb_vm_ep_local_ep")
|
||||||
.allowlist_type("vm_special_object_type")
|
.allowlist_type("vm_special_object_type")
|
||||||
.allowlist_var("VM_ENV_DATA_INDEX_SPECVAL")
|
.allowlist_var("VM_ENV_DATA_INDEX_SPECVAL")
|
||||||
|
@ -1546,8 +1546,7 @@ fn gen_expandarray(
|
|||||||
|
|
||||||
let array_opnd = asm.stack_opnd(0);
|
let array_opnd = asm.stack_opnd(0);
|
||||||
|
|
||||||
// num is the number of requested values. If there aren't enough in the
|
// If the array operand is nil, just push on nils
|
||||||
// array then we're going to push on nils.
|
|
||||||
if asm.ctx.get_opnd_type(array_opnd.into()) == Type::Nil {
|
if asm.ctx.get_opnd_type(array_opnd.into()) == Type::Nil {
|
||||||
asm.stack_pop(1); // pop after using the type info
|
asm.stack_pop(1); // pop after using the type info
|
||||||
// special case for a, b = nil pattern
|
// special case for a, b = nil pattern
|
||||||
@ -1762,6 +1761,7 @@ fn gen_getlocal_wc1(
|
|||||||
fn gen_setlocal_generic(
|
fn gen_setlocal_generic(
|
||||||
jit: &mut JITState,
|
jit: &mut JITState,
|
||||||
asm: &mut Assembler,
|
asm: &mut Assembler,
|
||||||
|
ocb: &mut OutlinedCb,
|
||||||
ep_offset: u32,
|
ep_offset: u32,
|
||||||
level: u32,
|
level: u32,
|
||||||
) -> Option<CodegenStatus> {
|
) -> Option<CodegenStatus> {
|
||||||
@ -1770,6 +1770,29 @@ fn gen_setlocal_generic(
|
|||||||
// Load environment pointer EP at level
|
// Load environment pointer EP at level
|
||||||
let ep_opnd = gen_get_ep(asm, level);
|
let ep_opnd = gen_get_ep(asm, level);
|
||||||
|
|
||||||
|
// Fallback because of write barrier
|
||||||
|
if asm.ctx.get_chain_depth() > 0
|
||||||
|
{
|
||||||
|
// Save the PC and SP because it runs GC
|
||||||
|
jit_prepare_routine_call(jit, asm);
|
||||||
|
|
||||||
|
// Pop the value to write from the stack
|
||||||
|
let value_opnd = asm.stack_pop(1);
|
||||||
|
|
||||||
|
// void rb_vm_env_write(const VALUE *ep, int index, VALUE v)
|
||||||
|
let index = -(ep_offset as i64);
|
||||||
|
asm.ccall(
|
||||||
|
rb_vm_env_write as *const u8,
|
||||||
|
vec![
|
||||||
|
ep_opnd,
|
||||||
|
index.into(),
|
||||||
|
value_opnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
return Some(KeepCompiling);
|
||||||
|
}
|
||||||
|
|
||||||
// Write barriers may be required when VM_ENV_FLAG_WB_REQUIRED is set, however write barriers
|
// Write barriers may be required when VM_ENV_FLAG_WB_REQUIRED is set, however write barriers
|
||||||
// only affect heap objects being written. If we know an immediate value is being written we
|
// only affect heap objects being written. If we know an immediate value is being written we
|
||||||
// can skip this check.
|
// can skip this check.
|
||||||
@ -1783,7 +1806,15 @@ fn gen_setlocal_generic(
|
|||||||
asm.test(flags_opnd, VM_ENV_FLAG_WB_REQUIRED.into());
|
asm.test(flags_opnd, VM_ENV_FLAG_WB_REQUIRED.into());
|
||||||
|
|
||||||
// if (flags & VM_ENV_FLAG_WB_REQUIRED) != 0
|
// if (flags & VM_ENV_FLAG_WB_REQUIRED) != 0
|
||||||
asm.jnz(Target::side_exit(Counter::setlocal_wb_required));
|
assert!(asm.ctx.get_chain_depth() == 0);
|
||||||
|
jit_chain_guard(
|
||||||
|
JCC_JNZ,
|
||||||
|
jit,
|
||||||
|
asm,
|
||||||
|
ocb,
|
||||||
|
1,
|
||||||
|
Counter::setlocal_wb_required,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if level == 0 {
|
if level == 0 {
|
||||||
@ -1804,29 +1835,29 @@ fn gen_setlocal_generic(
|
|||||||
fn gen_setlocal(
|
fn gen_setlocal(
|
||||||
jit: &mut JITState,
|
jit: &mut JITState,
|
||||||
asm: &mut Assembler,
|
asm: &mut Assembler,
|
||||||
_ocb: &mut OutlinedCb,
|
ocb: &mut OutlinedCb,
|
||||||
) -> Option<CodegenStatus> {
|
) -> Option<CodegenStatus> {
|
||||||
let idx = jit.get_arg(0).as_u32();
|
let idx = jit.get_arg(0).as_u32();
|
||||||
let level = jit.get_arg(1).as_u32();
|
let level = jit.get_arg(1).as_u32();
|
||||||
gen_setlocal_generic(jit, asm, idx, level)
|
gen_setlocal_generic(jit, asm, ocb, idx, level)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_setlocal_wc0(
|
fn gen_setlocal_wc0(
|
||||||
jit: &mut JITState,
|
jit: &mut JITState,
|
||||||
asm: &mut Assembler,
|
asm: &mut Assembler,
|
||||||
_ocb: &mut OutlinedCb,
|
ocb: &mut OutlinedCb,
|
||||||
) -> Option<CodegenStatus> {
|
) -> Option<CodegenStatus> {
|
||||||
let idx = jit.get_arg(0).as_u32();
|
let idx = jit.get_arg(0).as_u32();
|
||||||
gen_setlocal_generic(jit, asm, idx, 0)
|
gen_setlocal_generic(jit, asm, ocb, idx, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_setlocal_wc1(
|
fn gen_setlocal_wc1(
|
||||||
jit: &mut JITState,
|
jit: &mut JITState,
|
||||||
asm: &mut Assembler,
|
asm: &mut Assembler,
|
||||||
_ocb: &mut OutlinedCb,
|
ocb: &mut OutlinedCb,
|
||||||
) -> Option<CodegenStatus> {
|
) -> Option<CodegenStatus> {
|
||||||
let idx = jit.get_arg(0).as_u32();
|
let idx = jit.get_arg(0).as_u32();
|
||||||
gen_setlocal_generic(jit, asm, idx, 1)
|
gen_setlocal_generic(jit, asm, ocb, idx, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// new hash initialized from top N values
|
// new hash initialized from top N values
|
||||||
|
@ -1166,6 +1166,7 @@ extern "C" {
|
|||||||
pub static mut rb_block_param_proxy: VALUE;
|
pub static mut rb_block_param_proxy: VALUE;
|
||||||
pub fn rb_vm_ep_local_ep(ep: *const VALUE) -> *const VALUE;
|
pub fn rb_vm_ep_local_ep(ep: *const VALUE) -> *const VALUE;
|
||||||
pub fn rb_iseq_path(iseq: *const rb_iseq_t) -> VALUE;
|
pub fn rb_iseq_path(iseq: *const rb_iseq_t) -> VALUE;
|
||||||
|
pub fn rb_vm_env_write(ep: *const VALUE, index: ::std::os::raw::c_int, v: VALUE);
|
||||||
pub fn rb_vm_bh_to_procval(ec: *const rb_execution_context_t, block_handler: VALUE) -> VALUE;
|
pub fn rb_vm_bh_to_procval(ec: *const rb_execution_context_t, block_handler: VALUE) -> VALUE;
|
||||||
pub fn rb_vm_frame_method_entry(
|
pub fn rb_vm_frame_method_entry(
|
||||||
cfp: *const rb_control_frame_t,
|
cfp: *const rb_control_frame_t,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user