ZJIT: Don't make GuardNotFrozen consider immediates

This commit is contained in:
Max Bernstein 2025-11-21 13:43:52 -05:00 committed by Max Bernstein
parent e31c256907
commit 6e2906f60d
Notes: git 2025-11-21 19:16:59 +00:00
3 changed files with 9 additions and 11 deletions

View File

@ -654,20 +654,12 @@ fn gen_guard_block_param_proxy(jit: &JITState, asm: &mut Assembler, level: u32,
}
fn gen_guard_not_frozen(jit: &JITState, asm: &mut Assembler, recv: Opnd, state: &FrameState) -> Opnd {
let side_exit = side_exit(jit, state, GuardNotFrozen);
let recv = asm.load(recv);
// Side-exit if recv is false
assert_eq!(Qfalse.as_i64(), 0);
asm.test(recv, recv);
asm.jz(side_exit.clone());
// Side-exit if recv is immediate
asm.test(recv, (RUBY_IMMEDIATE_MASK as u64).into());
asm.jnz(side_exit.clone());
// It's a heap object, so check the frozen flag
let flags = asm.load(Opnd::mem(64, recv, RUBY_OFFSET_RBASIC_FLAGS));
asm.test(flags, (RUBY_FL_FREEZE as u64).into());
// Side-exit if frozen
asm.jnz(side_exit.clone());
asm.jnz(side_exit(jit, state, GuardNotFrozen));
recv
}

View File

@ -330,6 +330,7 @@ fn inline_array_push(fun: &mut hir::Function, block: hir::BlockId, recv: hir::In
fn inline_array_pop(fun: &mut hir::Function, block: hir::BlockId, recv: hir::InsnId, args: &[hir::InsnId], state: hir::InsnId) -> Option<hir::InsnId> {
// Only inline the case of no arguments.
let &[] = args else { return None; };
// We know that all Array are HeapObject, so no need to insert a GuardType(HeapObject).
let arr = fun.push_insn(block, hir::Insn::GuardNotFrozen { recv, state });
Some(fun.push_insn(block, hir::Insn::ArrayPop { array: arr, state }))
}
@ -391,6 +392,7 @@ fn inline_string_setbyte(fun: &mut hir::Function, block: hir::BlockId, recv: hir
let unboxed_index = fun.push_insn(block, hir::Insn::GuardLess { left: unboxed_index, right: len, state });
let zero = fun.push_insn(block, hir::Insn::Const { val: hir::Const::CInt64(0) });
let _ = fun.push_insn(block, hir::Insn::GuardGreaterEq { left: unboxed_index, right: zero, state });
// We know that all String are HeapObject, so no need to insert a GuardType(HeapObject).
let recv = fun.push_insn(block, hir::Insn::GuardNotFrozen { recv, state });
let _ = fun.push_insn(block, hir::Insn::StringSetbyteFixnum { string: recv, index, value });
// String#setbyte returns the fixnum provided as its `value` argument back to the caller.

View File

@ -903,7 +903,8 @@ pub enum Insn {
/// Side-exit if the block param has been modified or the block handler for the frame
/// is neither ISEQ nor ifunc, which makes it incompatible with rb_block_param_proxy.
GuardBlockParamProxy { level: u32, state: InsnId },
/// Side-exit if val is frozen.
/// Side-exit if val is frozen. Does *not* check if the val is an immediate; assumes that it is
/// a heap object.
GuardNotFrozen { recv: InsnId, state: InsnId },
/// Side-exit if left is not greater than or equal to right (both operands are C long).
GuardGreaterEq { left: InsnId, right: InsnId, state: InsnId },
@ -2553,6 +2554,7 @@ impl Function {
//
// No need for a GuardShape.
if let OptimizedMethodType::StructAset = opt_type {
// We know that all Struct are HeapObject, so no need to insert a GuardType(HeapObject).
recv = self.push_insn(block, Insn::GuardNotFrozen { recv, state });
}
@ -4150,7 +4152,6 @@ impl Function {
| Insn::IsNil { val }
| Insn::IsMethodCfunc { val, .. }
| Insn::GuardShape { val, .. }
| Insn::GuardNotFrozen { recv: val, .. }
| Insn::SetGlobal { val, .. }
| Insn::SetLocal { val, .. }
| Insn::SetClassVar { val, .. }
@ -4169,6 +4170,9 @@ impl Function {
| Insn::DefinedIvar { self_val: val, .. } => {
self.assert_subtype(insn_id, val, types::BasicObject)
}
Insn::GuardNotFrozen { recv, .. } => {
self.assert_subtype(insn_id, recv, types::HeapBasicObject)
}
// Instructions with 2 Ruby object operands
Insn::SetIvar { self_val: left, val: right, .. }
| Insn::NewRange { low: left, high: right, .. }