Skip to content

Commit a657e6b

Browse files
committed
Add write barrier to gen_setlocal, add new side exit reason, and modify setlocal struct to include state
1 parent 8d41e57 commit a657e6b

File tree

3 files changed

+19
-8
lines changed

3 files changed

+19
-8
lines changed

zjit/src/codegen.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
553553
&Insn::GetLocal { ep_offset, level, use_sp, .. } => gen_getlocal(asm, ep_offset, level, use_sp),
554554
&Insn::IsBlockParamModified { level } => gen_is_block_param_modified(asm, level),
555555
&Insn::GetBlockParam { ep_offset, level, state } => gen_getblockparam(jit, asm, ep_offset, level, &function.frame_state(state)),
556-
&Insn::SetLocal { val, ep_offset, level } => no_output!(gen_setlocal(asm, opnd!(val), function.type_of(val), ep_offset, level)),
556+
&Insn::SetLocal { val, ep_offset, level, state } => no_output!(gen_setlocal(jit, asm, opnd!(val), function.type_of(val), ep_offset, level, &function.frame_state(state))),
557557
Insn::GetConstantPath { ic, state } => gen_get_constant_path(jit, asm, *ic, &function.frame_state(*state)),
558558
Insn::GetClassVar { id, ic, state } => gen_getclassvar(jit, asm, *id, *ic, &function.frame_state(*state)),
559559
Insn::SetClassVar { id, val, ic, state } => no_output!(gen_setclassvar(jit, asm, *id, opnd!(val), *ic, &function.frame_state(*state))),
@@ -726,7 +726,7 @@ fn gen_getlocal(asm: &mut Assembler, local_ep_offset: u32, level: u32, use_sp: b
726726
/// Set a local variable from a higher scope or the heap. `local_ep_offset` is in number of VALUEs.
727727
/// We generate this instruction with level=0 only when the local variable is on the heap, so we
728728
/// can't optimize the level=0 case using the SP register.
729-
fn gen_setlocal(asm: &mut Assembler, val: Opnd, val_type: Type, local_ep_offset: u32, level: u32) {
729+
fn gen_setlocal(jit: &mut JITState, asm: &mut Assembler, val: Opnd, val_type: Type, local_ep_offset: u32, level: u32, state: &FrameState) {
730730
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"));
731731
if level > 0 {
732732
gen_incr_counter(asm, Counter::vm_write_to_parent_iseq_local_count);
@@ -739,6 +739,14 @@ fn gen_setlocal(asm: &mut Assembler, val: Opnd, val_type: Type, local_ep_offset:
739739
let offset = -(SIZEOF_VALUE_I32 * local_ep_offset);
740740
asm.mov(Opnd::mem(64, ep, offset), val);
741741
} else {
742+
// Side exit if the write barrier is required.
743+
// TODO(Jacob): Convert to guard, and maybe fix up other getblock case that uses this
744+
// TODO(Jacob): Figure out what modified `VM_ENV_FLAG_WB_REQUIRED`
745+
let ep = gen_get_ep(asm, level);
746+
let flags = Opnd::mem(VALUE_BITS, ep, SIZEOF_VALUE_I32 * (VM_ENV_DATA_INDEX_FLAGS as i32));
747+
asm.test(flags, VM_ENV_FLAG_WB_REQUIRED.into());
748+
asm.jnz(side_exit(jit, state, SideExitReason::WriteBarrierRequired));
749+
// TODO(Jacob): Remove the write barrier check that is somehow buried in these next few lines
742750
// We're potentially writing a reference to an IMEMO/env object,
743751
// so take care of the write barrier with a function.
744752
let local_index = -local_ep_offset;

zjit/src/hir.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,7 @@ pub enum SideExitReason {
511511
FixnumModByZero,
512512
FixnumDivByZero,
513513
BoxFixnumOverflow,
514+
WriteBarrierRequired,
514515
}
515516

516517
#[derive(Debug, Clone, Copy)]
@@ -846,7 +847,7 @@ pub enum Insn {
846847
/// Get the block parameter as a Proc.
847848
GetBlockParam { level: u32, ep_offset: u32, state: InsnId },
848849
/// Set a local variable in a higher scope or the heap
849-
SetLocal { level: u32, ep_offset: u32, val: InsnId },
850+
SetLocal { level: u32, ep_offset: u32, val: InsnId, state: InsnId },
850851
GetSpecialSymbol { symbol_type: SpecialBackrefSymbol, state: InsnId },
851852
GetSpecialNumber { nth: u64, state: InsnId },
852853

@@ -1622,7 +1623,7 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
16221623
&Insn::IsBlockParamModified { level } => {
16231624
write!(f, "IsBlockParamModified l{level}")
16241625
},
1625-
&Insn::SetLocal { val, level, ep_offset } => {
1626+
&Insn::SetLocal { val, level, ep_offset, .. } => {
16261627
let name = get_local_var_name_for_printer(self.iseq, level, ep_offset).map_or(String::new(), |x| format!("{x}, "));
16271628
write!(f, "SetLocal {name}l{level}, EP@{ep_offset}, {val}")
16281629
},
@@ -2360,7 +2361,7 @@ impl Function {
23602361
&SetIvar { self_val, id, ic, val, state } => SetIvar { self_val: find!(self_val), id, ic, val: find!(val), state },
23612362
&GetClassVar { id, ic, state } => GetClassVar { id, ic, state },
23622363
&SetClassVar { id, val, ic, state } => SetClassVar { id, val: find!(val), ic, state },
2363-
&SetLocal { val, ep_offset, level } => SetLocal { val: find!(val), ep_offset, level },
2364+
&SetLocal { val, ep_offset, level, state } => SetLocal { val: find!(val), ep_offset, level, state },
23642365
&GetSpecialSymbol { symbol_type, state } => GetSpecialSymbol { symbol_type, state },
23652366
&GetSpecialNumber { nth, state } => GetSpecialNumber { nth, state },
23662367
&ToArray { val, state } => ToArray { val: find!(val), state },
@@ -6478,7 +6479,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
64786479
let val = state.stack_pop()?;
64796480
if ep_escaped || has_blockiseq { // TODO: figure out how to drop has_blockiseq here
64806481
// Write the local using EP
6481-
fun.push_insn(block, Insn::SetLocal { val, ep_offset, level: 0 });
6482+
fun.push_insn(block, Insn::SetLocal { val, ep_offset, level: 0, state: exit_id });
64826483
} else if local_inval {
64836484
// If there has been any non-leaf call since JIT entry or the last patch point,
64846485
// add a patch point to make sure locals have not been escaped.
@@ -6495,7 +6496,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
64956496
}
64966497
YARVINSN_setlocal_WC_1 => {
64976498
let ep_offset = get_arg(pc, 0).as_u32();
6498-
fun.push_insn(block, Insn::SetLocal { val: state.stack_pop()?, ep_offset, level: 1 });
6499+
fun.push_insn(block, Insn::SetLocal { val: state.stack_pop()?, ep_offset, level: 1, state: exit_id });
64996500
}
65006501
YARVINSN_getlocal => {
65016502
let ep_offset = get_arg(pc, 0).as_u32();
@@ -6505,7 +6506,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
65056506
YARVINSN_setlocal => {
65066507
let ep_offset = get_arg(pc, 0).as_u32();
65076508
let level = get_arg(pc, 1).as_u32();
6508-
fun.push_insn(block, Insn::SetLocal { val: state.stack_pop()?, ep_offset, level });
6509+
fun.push_insn(block, Insn::SetLocal { val: state.stack_pop()?, ep_offset, level, state: exit_id });
65096510
}
65106511
YARVINSN_getblockparamproxy => {
65116512
let level = get_arg(pc, 1).as_u32();

zjit/src/stats.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ make_counters! {
212212
exit_block_param_proxy_not_iseq_or_ifunc,
213213
exit_block_param_wb_required,
214214
exit_too_many_keyword_parameters,
215+
exit_write_barrier_required,
215216
}
216217

217218
// Send fallback counters that are summed as dynamic_send_count
@@ -560,6 +561,7 @@ pub fn side_exit_counter(reason: crate::hir::SideExitReason) -> Counter {
560561
BlockParamProxyNotIseqOrIfunc => exit_block_param_proxy_not_iseq_or_ifunc,
561562
BlockParamWbRequired => exit_block_param_wb_required,
562563
TooManyKeywordParameters => exit_too_many_keyword_parameters,
564+
WriteBarrierRequired => exit_write_barrier_required,
563565
PatchPoint(Invariant::BOPRedefined { .. })
564566
=> exit_patchpoint_bop_redefined,
565567
PatchPoint(Invariant::MethodRedefined { .. })

0 commit comments

Comments
 (0)