aboutsummaryrefslogtreecommitdiffstats
path: root/yjit/src
diff options
context:
space:
mode:
authorMaxime Chevalier-Boisvert <maxime.chevalierboisvert@shopify.com>2023-08-17 10:11:17 -0400
committerGitHub <noreply@github.com>2023-08-17 10:11:17 -0400
commit30a5b94517699589f6943163cd6b92f2f6c0023f (patch)
tree73760a4147e0c8be718f9cc6bb66894e2372e23f /yjit/src
parent7433c8f7dde9eb82b94d59c71c17b4173047e008 (diff)
downloadruby-30a5b94517699589f6943163cd6b92f2f6c0023f.tar.gz
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>
Diffstat (limited to 'yjit/src')
-rw-r--r--yjit/src/codegen.rs49
-rw-r--r--yjit/src/cruby_bindings.inc.rs1
2 files changed, 41 insertions, 9 deletions
diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs
index 919e1662b8..88c5677551 100644
--- a/yjit/src/codegen.rs
+++ b/yjit/src/codegen.rs
@@ -1546,8 +1546,7 @@ fn gen_expandarray(
let array_opnd = asm.stack_opnd(0);
- // num is the number of requested values. If there aren't enough in the
- // array then we're going to push on nils.
+ // If the array operand is nil, just push on nils
if asm.ctx.get_opnd_type(array_opnd.into()) == Type::Nil {
asm.stack_pop(1); // pop after using the type info
// special case for a, b = nil pattern
@@ -1762,6 +1761,7 @@ fn gen_getlocal_wc1(
fn gen_setlocal_generic(
jit: &mut JITState,
asm: &mut Assembler,
+ ocb: &mut OutlinedCb,
ep_offset: u32,
level: u32,
) -> Option<CodegenStatus> {
@@ -1770,6 +1770,29 @@ fn gen_setlocal_generic(
// Load environment pointer EP at 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
// only affect heap objects being written. If we know an immediate value is being written we
// can skip this check.
@@ -1783,7 +1806,15 @@ fn gen_setlocal_generic(
asm.test(flags_opnd, VM_ENV_FLAG_WB_REQUIRED.into());
// 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 {
@@ -1804,29 +1835,29 @@ fn gen_setlocal_generic(
fn gen_setlocal(
jit: &mut JITState,
asm: &mut Assembler,
- _ocb: &mut OutlinedCb,
+ ocb: &mut OutlinedCb,
) -> Option<CodegenStatus> {
let idx = jit.get_arg(0).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(
jit: &mut JITState,
asm: &mut Assembler,
- _ocb: &mut OutlinedCb,
+ ocb: &mut OutlinedCb,
) -> Option<CodegenStatus> {
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(
jit: &mut JITState,
asm: &mut Assembler,
- _ocb: &mut OutlinedCb,
+ ocb: &mut OutlinedCb,
) -> Option<CodegenStatus> {
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
diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs
index 1d0704073d..ccf5b530d6 100644
--- a/yjit/src/cruby_bindings.inc.rs
+++ b/yjit/src/cruby_bindings.inc.rs
@@ -1166,6 +1166,7 @@ extern "C" {
pub static mut rb_block_param_proxy: 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_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_frame_method_entry(
cfp: *const rb_control_frame_t,