Skip to content

Commit de180f8

Browse files
committed
Modify YARV Insns for setlocal to remove write barrier, add guards, and add side exits
1 parent ff93bc8 commit de180f8

2 files changed

Lines changed: 16 additions & 10 deletions

File tree

zjit/src/codegen.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
557557
&Insn::GetLocal { ep_offset, level, use_sp, .. } => gen_getlocal(asm, ep_offset, level, use_sp),
558558
&Insn::IsBlockParamModified { level } => gen_is_block_param_modified(asm, level),
559559
&Insn::GetBlockParam { ep_offset, level, state } => gen_getblockparam(jit, asm, ep_offset, level, &function.frame_state(state)),
560-
&Insn::SetLocal { val, ep_offset, level } => no_output!(gen_setlocal(jit, asm, opnd!(val), function.type_of(val), ep_offset, level )),
560+
&Insn::SetLocal { ep, val, ep_offset, level } => no_output!(gen_setlocal(asm, opnd!(ep), opnd!(val), ep_offset, level )),
561561
Insn::GetConstantPath { ic, state } => gen_get_constant_path(jit, asm, *ic, &function.frame_state(*state)),
562562
Insn::GetClassVar { id, ic, state } => gen_getclassvar(jit, asm, *id, *ic, &function.frame_state(*state)),
563563
Insn::SetClassVar { id, val, ic, state } => no_output!(gen_setclassvar(jit, asm, *id, opnd!(val), *ic, &function.frame_state(*state))),
@@ -730,13 +730,11 @@ fn gen_getlocal(asm: &mut Assembler, local_ep_offset: u32, level: u32, use_sp: b
730730
/// Set a local variable from a higher scope or the heap. `local_ep_offset` is in number of VALUEs.
731731
/// We generate this instruction with level=0 only when the local variable is on the heap, so we
732732
/// can't optimize the level=0 case using the SP register.
733-
// TODO(Jacob): remove superfluous arguments from function
734-
fn gen_setlocal(jit: &mut JITState, asm: &mut Assembler, val: Opnd, val_type: Type, local_ep_offset: u32, level: u32) {
735-
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"));
733+
fn gen_setlocal(asm: &mut Assembler, ep: Opnd, val: Opnd, local_ep_offset: u32, level: u32) {
736734
if level > 0 {
737735
gen_incr_counter(asm, Counter::vm_write_to_parent_iseq_local_count);
738736
}
739-
let ep = gen_get_ep(asm, level);
737+
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"));
740738
let offset = -(SIZEOF_VALUE_I32 * local_ep_offset);
741739
asm.mov(Opnd::mem(64, ep, offset), val);
742740
}

zjit/src/hir.rs

Lines changed: 13 additions & 5 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 },
853+
SetLocal { level: u32, ep_offset: u32, ep: InsnId, val: InsnId },
854854
GetSpecialSymbol { symbol_type: SpecialBackrefSymbol, state: InsnId },
855855
GetSpecialNumber { nth: u64, state: InsnId },
856856

@@ -2376,7 +2376,7 @@ impl Function {
23762376
&SetIvar { self_val, id, ic, val, state } => SetIvar { self_val: find!(self_val), id, ic, val: find!(val), state },
23772377
&GetClassVar { id, ic, state } => GetClassVar { id, ic, state },
23782378
&SetClassVar { id, val, ic, state } => SetClassVar { id, val: find!(val), ic, state },
2379-
&SetLocal { val, ep_offset, level } => SetLocal { val: find!(val), ep_offset, level },
2379+
&SetLocal { val, ep_offset, level, ep } => SetLocal { val: find!(val), ep_offset, level, ep },
23802380
&GetSpecialSymbol { symbol_type, state } => GetSpecialSymbol { symbol_type, state },
23812381
&GetSpecialNumber { nth, state } => GetSpecialNumber { nth, state },
23822382
&ToArray { val, state } => ToArray { val: find!(val), state },
@@ -6752,14 +6752,18 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
67526752
YARVINSN_setlocal_WC_0 => {
67536753
// TODO(Jacob): Modify this to use guards
67546754
let ep_offset = get_arg(pc, 0).as_u32();
6755+
const level: u32 = 0;
6756+
let ep = fun.push_insn(block, Insn::GetEP { level });
67556757
let val = state.stack_pop()?;
67566758
if ep_escaped || has_blockiseq { // TODO: figure out how to drop has_blockiseq here
67576759
// Write the local using EP
6758-
fun.push_insn(block, Insn::SetLocal { val, ep_offset, level: 0 });
6760+
fun.push_insn(block, Insn::SetLocal { val, ep, ep_offset, level });
67596761
} else if local_inval {
67606762
// If there has been any non-leaf call since JIT entry or the last patch point,
67616763
// add a patch point to make sure locals have not been escaped.
67626764
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state.without_locals() }); // skip spilling locals
6765+
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 });
6766+
fun.push_insn(block, Insn::GuardNoBitsSet { val: flags, mask: Const::CUInt64(VM_ENV_FLAG_WB_REQUIRED.into()), reason: SideExitReason::WriteBarrierRequired, state: exit_id });
67636767
fun.push_insn(block, Insn::PatchPoint { invariant: Invariant::NoEPEscape(iseq), state: exit_id });
67646768
local_inval = false;
67656769
}
@@ -6773,7 +6777,11 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
67736777
YARVINSN_setlocal_WC_1 => {
67746778
// TODO(Jacob): Modify this to use guards
67756779
let ep_offset = get_arg(pc, 0).as_u32();
6776-
fun.push_insn(block, Insn::SetLocal { val: state.stack_pop()?, ep_offset, level: 1 });
6780+
const level: u32 = 1;
6781+
let ep = fun.push_insn(block, Insn::GetEP { level });
6782+
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 });
6783+
fun.push_insn(block, Insn::GuardNoBitsSet { val: flags, mask: Const::CUInt64(VM_ENV_FLAG_WB_REQUIRED.into()), reason: SideExitReason::WriteBarrierRequired, state: exit_id });
6784+
fun.push_insn(block, Insn::SetLocal { val: state.stack_pop()?, ep, ep_offset, level });
67776785
}
67786786
YARVINSN_getlocal => {
67796787
let ep_offset = get_arg(pc, 0).as_u32();
@@ -6788,7 +6796,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
67886796
let ep = fun.push_insn(block, Insn::GetEP { level });
67896797
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 });
67906798
fun.push_insn(block, Insn::GuardNoBitsSet { val: flags, mask: Const::CUInt64(VM_ENV_FLAG_WB_REQUIRED.into()), reason: SideExitReason::WriteBarrierRequired, state: exit_id });
6791-
fun.push_insn(block, Insn::SetLocal { val: state.stack_pop()?, ep_offset, level });
6799+
fun.push_insn(block, Insn::SetLocal { val: state.stack_pop()?, ep, ep_offset, level });
67926800
}
67936801
YARVINSN_getblockparamproxy => {
67946802
let level = get_arg(pc, 1).as_u32();

0 commit comments

Comments
 (0)