Skip to content

Commit bbfcb49

Browse files
committed
Add guard to YARVINSN_setlocal even though it breaks a test
1 parent 9242fc7 commit bbfcb49

2 files changed

Lines changed: 17 additions & 29 deletions

File tree

zjit/src/codegen.rs

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
561561
&Insn::GetLocal { ep_offset, level, use_sp, .. } => gen_getlocal(asm, ep_offset, level, use_sp),
562562
&Insn::IsBlockParamModified { level } => gen_is_block_param_modified(asm, level),
563563
&Insn::GetBlockParam { ep_offset, level, state } => gen_getblockparam(jit, asm, ep_offset, level, &function.frame_state(state)),
564-
&Insn::SetLocal { val, ep_offset, level, state } => no_output!(gen_setlocal(asm, opnd!(val), function.type_of(val), ep_offset, level, &function.frame_state(state))),
564+
&Insn::SetLocal { val, ep_offset, level } => no_output!(gen_setlocal(jit, asm, opnd!(val), function.type_of(val), ep_offset, level )),
565565
Insn::GetConstantPath { ic, state } => gen_get_constant_path(jit, asm, *ic, &function.frame_state(*state)),
566566
Insn::GetClassVar { id, ic, state } => gen_getclassvar(jit, asm, *id, *ic, &function.frame_state(*state)),
567567
Insn::SetClassVar { id, val, ic, state } => no_output!(gen_setclassvar(jit, asm, *id, opnd!(val), *ic, &function.frame_state(*state))),
@@ -735,32 +735,15 @@ fn gen_getlocal(asm: &mut Assembler, local_ep_offset: u32, level: u32, use_sp: b
735735
/// Set a local variable from a higher scope or the heap. `local_ep_offset` is in number of VALUEs.
736736
/// We generate this instruction with level=0 only when the local variable is on the heap, so we
737737
/// can't optimize the level=0 case using the SP register.
738-
fn gen_setlocal(asm: &mut Assembler, val: Opnd, val_type: Type, local_ep_offset: u32, level: u32, state: &FrameState) {
738+
// TODO(Jacob): remove superfluous arguments from function
739+
fn gen_setlocal(jit: &mut JITState, asm: &mut Assembler, val: Opnd, val_type: Type, local_ep_offset: u32, level: u32) {
739740
let local_ep_offset = c_int::try_from(local_ep_offset).unwrap_or_else(|_| panic!("Could not convert local_ep_offset {local_ep_offset} to i32"));
740741
if level > 0 {
741742
gen_incr_counter(asm, Counter::vm_write_to_parent_iseq_local_count);
742743
}
743744
let ep = gen_get_ep(asm, level);
744-
745-
// When we've proved that we're writing an immediate,
746-
// we can skip the write barrier.
747-
if val_type.is_immediate() {
748-
let offset = -(SIZEOF_VALUE_I32 * local_ep_offset);
749-
asm.mov(Opnd::mem(64, ep, offset), val);
750-
} else {
751-
// Side exit if the write barrier is required.
752-
// TODO(Jacob): Convert to guard, and maybe fix up other getblock case that uses this
753-
// TODO(Jacob): Figure out what modified `VM_ENV_FLAG_WB_REQUIRED`
754-
let ep = gen_get_ep(asm, level);
755-
let flags = Opnd::mem(VALUE_BITS, ep, SIZEOF_VALUE_I32 * (VM_ENV_DATA_INDEX_FLAGS as i32));
756-
// asm.test(flags, VM_ENV_FLAG_WB_REQUIRED.into());
757-
// asm.jnz(side_exit(jit, state, SideExitReason::WriteBarrierRequired));
758-
// TODO(Jacob): Remove the write barrier check that is somehow buried in these next few lines
759-
// We're potentially writing a reference to an IMEMO/env object,
760-
// so take care of the write barrier with a function.
761-
let local_index = -local_ep_offset;
762-
asm_ccall!(asm, rb_vm_env_write, ep, local_index.into(), val);
763-
}
745+
let offset = -(SIZEOF_VALUE_I32 * local_ep_offset);
746+
asm.mov(Opnd::mem(64, ep, offset), val);
764747
}
765748

766749
/// Returns 1 (as CBool) when VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM is set; returns 0 otherwise.

zjit/src/hir.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -850,7 +850,7 @@ pub enum Insn {
850850
/// Get the block parameter as a Proc.
851851
GetBlockParam { level: u32, ep_offset: u32, state: InsnId },
852852
/// Set a local variable in a higher scope or the heap
853-
SetLocal { level: u32, ep_offset: u32, val: InsnId, state: InsnId },
853+
SetLocal { level: u32, ep_offset: u32, val: InsnId },
854854
GetSpecialSymbol { symbol_type: SpecialBackrefSymbol, state: InsnId },
855855
GetSpecialNumber { nth: u64, state: InsnId },
856856

@@ -2404,7 +2404,7 @@ impl Function {
24042404
&SetIvar { self_val, id, ic, val, state } => SetIvar { self_val: find!(self_val), id, ic, val: find!(val), state },
24052405
&GetClassVar { id, ic, state } => GetClassVar { id, ic, state },
24062406
&SetClassVar { id, val, ic, state } => SetClassVar { id, val: find!(val), ic, state },
2407-
&SetLocal { val, ep_offset, level, state } => SetLocal { val: find!(val), ep_offset, level, state },
2407+
&SetLocal { val, ep_offset, level } => SetLocal { val: find!(val), ep_offset, level },
24082408
&GetSpecialSymbol { symbol_type, state } => GetSpecialSymbol { symbol_type, state },
24092409
&GetSpecialNumber { nth, state } => GetSpecialNumber { nth, state },
24102410
&ToArray { val, state } => ToArray { val: find!(val), state },
@@ -6723,11 +6723,12 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
67236723
}
67246724
}
67256725
YARVINSN_setlocal_WC_0 => {
6726+
// TODO(Jacob): Modify this to use guards
67266727
let ep_offset = get_arg(pc, 0).as_u32();
67276728
let val = state.stack_pop()?;
67286729
if ep_escaped || has_blockiseq { // TODO: figure out how to drop has_blockiseq here
67296730
// Write the local using EP
6730-
fun.push_insn(block, Insn::SetLocal { val, ep_offset, level: 0, state: exit_id });
6731+
fun.push_insn(block, Insn::SetLocal { val, ep_offset, level: 0 });
67316732
} else if local_inval {
67326733
// If there has been any non-leaf call since JIT entry or the last patch point,
67336734
// add a patch point to make sure locals have not been escaped.
@@ -6743,20 +6744,24 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
67436744
state.stack_push(fun.push_insn(block, Insn::GetLocal { ep_offset, level: 1, use_sp: false, rest_param: false }));
67446745
}
67456746
YARVINSN_setlocal_WC_1 => {
6747+
// TODO(Jacob): Modify this to use guards
67466748
let ep_offset = get_arg(pc, 0).as_u32();
6747-
fun.push_insn(block, Insn::SetLocal { val: state.stack_pop()?, ep_offset, level: 1, state: exit_id });
6749+
fun.push_insn(block, Insn::SetLocal { val: state.stack_pop()?, ep_offset, level: 1 });
67486750
}
67496751
YARVINSN_getlocal => {
67506752
let ep_offset = get_arg(pc, 0).as_u32();
67516753
let level = get_arg(pc, 1).as_u32();
67526754
state.stack_push(fun.push_insn(block, Insn::GetLocal { ep_offset, level, use_sp: false, rest_param: false }));
67536755
}
67546756
YARVINSN_setlocal => {
6757+
// TODO(Jacob): Make sure this works
6758+
// TODO(Jacob): Clean up the offset, levels, ep chasing, etc
67556759
let ep_offset = get_arg(pc, 0).as_u32();
67566760
let level = get_arg(pc, 1).as_u32();
6757-
// TODO(Jacob): Add guard here
6758-
// TODO(Jacob): Figure out if we should change ALL of the setlocals and what the differences are
6759-
fun.push_insn(block, Insn::SetLocal { val: state.stack_pop()?, ep_offset, level, state: exit_id });
6761+
let ep = fun.push_insn(block, Insn::GetEP { level });
6762+
let flags = fun.push_insn(block, Insn::LoadField { recv: ep, id: ID!(_env_data_index_flags), offset: SIZEOF_VALUE_I32 * (VM_ENV_DATA_INDEX_FLAGS as i32), return_type: types::CInt64 });
6763+
fun.push_insn(block, Insn::GuardNoBitsSet { val: flags, mask: Const::CUInt64(VM_ENV_FLAG_WB_REQUIRED.into()), reason: SideExitReason::WriteBarrierRequired, state: exit_id });
6764+
fun.push_insn(block, Insn::SetLocal { val: state.stack_pop()?, ep_offset, level });
67606765
}
67616766
YARVINSN_getblockparamproxy => {
67626767
let level = get_arg(pc, 1).as_u32();

0 commit comments

Comments
 (0)