ZJIT: Replace GuardShape with LoadField+GuardBitEquals (#15821)

GuardShape is just load+guard, so use the existing HIR instructions for load+guard. Probably makes future analysis slightly easier.
This commit is contained in:
Max Bernstein 2026-01-08 14:57:55 -05:00 committed by GitHub
parent 16863f2ec1
commit 523857bfcb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
Notes: git 2026-01-08 19:58:24 +00:00
Merged-By: tekknolagi <donotemailthisaddress@bernsteinbear.com>
4 changed files with 170 additions and 119 deletions

View File

@ -449,7 +449,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
Insn::Test { val } => gen_test(asm, opnd!(val)),
Insn::GuardType { val, guard_type, state } => gen_guard_type(jit, asm, opnd!(val), *guard_type, &function.frame_state(*state)),
Insn::GuardTypeNot { val, guard_type, state } => gen_guard_type_not(jit, asm, opnd!(val), *guard_type, &function.frame_state(*state)),
Insn::GuardBitEquals { val, expected, state } => gen_guard_bit_equals(jit, asm, opnd!(val), *expected, &function.frame_state(*state)),
&Insn::GuardBitEquals { val, expected, reason, state } => gen_guard_bit_equals(jit, asm, opnd!(val), expected, reason, &function.frame_state(state)),
&Insn::GuardBlockParamProxy { level, state } => no_output!(gen_guard_block_param_proxy(jit, asm, level, &function.frame_state(state))),
Insn::GuardNotFrozen { recv, state } => gen_guard_not_frozen(jit, asm, opnd!(recv), &function.frame_state(*state)),
Insn::GuardNotShared { recv, state } => gen_guard_not_shared(jit, asm, opnd!(recv), &function.frame_state(*state)),
@ -498,7 +498,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
Insn::LoadPC => gen_load_pc(asm),
Insn::LoadEC => gen_load_ec(),
Insn::LoadSelf => gen_load_self(),
&Insn::LoadField { recv, id, offset, return_type: _ } => gen_load_field(asm, opnd!(recv), id, offset),
&Insn::LoadField { recv, id, offset, return_type } => gen_load_field(asm, opnd!(recv), id, offset, return_type),
&Insn::StoreField { recv, id, offset, val } => no_output!(gen_store_field(asm, opnd!(recv), id, offset, opnd!(val), function.type_of(val))),
&Insn::WriteBarrier { recv, val } => no_output!(gen_write_barrier(asm, opnd!(recv), opnd!(val), function.type_of(val))),
&Insn::IsBlockGiven => gen_is_block_given(jit, asm),
@ -1130,10 +1130,10 @@ fn gen_load_self() -> Opnd {
Opnd::mem(64, CFP, RUBY_OFFSET_CFP_SELF)
}
fn gen_load_field(asm: &mut Assembler, recv: Opnd, id: ID, offset: i32) -> Opnd {
fn gen_load_field(asm: &mut Assembler, recv: Opnd, id: ID, offset: i32, return_type: Type) -> Opnd {
asm_comment!(asm, "Load field id={} offset={}", id.contents_lossy(), offset);
let recv = asm.load(recv);
asm.load(Opnd::mem(64, recv, offset))
asm.load(Opnd::mem(return_type.num_bits(), recv, offset))
}
fn gen_store_field(asm: &mut Assembler, recv: Opnd, id: ID, offset: i32, val: Opnd, val_type: Type) {
@ -2083,14 +2083,15 @@ fn gen_guard_type_not(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, g
}
/// Compile an identity check with a side exit
fn gen_guard_bit_equals(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, expected: crate::hir::Const, state: &FrameState) -> lir::Opnd {
fn gen_guard_bit_equals(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, expected: crate::hir::Const, reason: SideExitReason, state: &FrameState) -> lir::Opnd {
let expected_opnd: Opnd = match expected {
crate::hir::Const::Value(v) => { Opnd::Value(v) }
crate::hir::Const::CInt64(v) => { v.into() }
crate::hir::Const::CShape(v) => { Opnd::UImm(v.0 as u64) }
_ => panic!("gen_guard_bit_equals: unexpected hir::Const {expected:?}"),
};
asm.cmp(val, expected_opnd);
asm.jnz(side_exit(jit, state, GuardBitEquals(expected)));
asm.jnz(side_exit(jit, state, reason));
val
}

View File

@ -491,7 +491,7 @@ pub enum SideExitReason {
GuardType(Type),
GuardTypeNot(Type),
GuardShape(ShapeId),
GuardBitEquals(Const),
ExpandArray,
GuardNotFrozen,
GuardNotShared,
GuardLess,
@ -580,7 +580,6 @@ impl std::fmt::Display for SideExitReason {
SideExitReason::UnhandledDuparraySend(method_id) => write!(f, "UnhandledDuparraySend({method_id})"),
SideExitReason::GuardType(guard_type) => write!(f, "GuardType({guard_type})"),
SideExitReason::GuardTypeNot(guard_type) => write!(f, "GuardTypeNot({guard_type})"),
SideExitReason::GuardBitEquals(value) => write!(f, "GuardBitEquals({})", value.print(&PtrPrintMap::identity())),
SideExitReason::GuardNotShared => write!(f, "GuardNotShared"),
SideExitReason::PatchPoint(invariant) => write!(f, "PatchPoint({invariant})"),
_ => write!(f, "{self:?}"),
@ -954,7 +953,7 @@ pub enum Insn {
GuardType { val: InsnId, guard_type: Type, state: InsnId },
GuardTypeNot { val: InsnId, guard_type: Type, state: InsnId },
/// Side-exit if val is not the expected Const.
GuardBitEquals { val: InsnId, expected: Const, state: InsnId },
GuardBitEquals { val: InsnId, expected: Const, reason: SideExitReason, state: InsnId },
/// Side-exit if val doesn't have the expected shape.
GuardShape { val: InsnId, shape: ShapeId, state: InsnId },
/// Side-exit if the block param has been modified or the block handler for the frame
@ -1975,7 +1974,7 @@ impl Function {
&IfFalse { val, ref target } => IfFalse { val: find!(val), target: find_branch_edge!(target) },
&GuardType { val, guard_type, state } => GuardType { val: find!(val), guard_type, state },
&GuardTypeNot { val, guard_type, state } => GuardTypeNot { val: find!(val), guard_type, state },
&GuardBitEquals { val, expected, state } => GuardBitEquals { val: find!(val), expected, state },
&GuardBitEquals { val, expected, reason, state } => GuardBitEquals { val: find!(val), expected, reason, state },
&GuardShape { val, shape, state } => GuardShape { val: find!(val), shape, state },
&GuardBlockParamProxy { level, state } => GuardBlockParamProxy { level, state: find!(state) },
&GuardNotFrozen { recv, state } => GuardNotFrozen { recv: find!(recv), state },
@ -3069,6 +3068,24 @@ impl Function {
self.infer_types();
}
fn load_shape(&mut self, block: BlockId, recv: InsnId) -> InsnId {
self.push_insn(block, Insn::LoadField {
recv,
id: ID!(_shape_id),
offset: unsafe { rb_shape_id_offset() } as i32,
return_type: types::CShape
})
}
fn guard_shape(&mut self, block: BlockId, val: InsnId, expected: ShapeId, state: InsnId) -> InsnId {
self.push_insn(block, Insn::GuardBitEquals {
val,
expected: Const::CShape(expected),
reason: SideExitReason::GuardShape(expected),
state
})
}
fn optimize_getivar(&mut self) {
for block in self.rpo() {
let old_insns = std::mem::take(&mut self.blocks[block.0].insns);
@ -3094,7 +3111,8 @@ impl Function {
self.push_insn_id(block, insn_id); continue;
}
let self_val = self.push_insn(block, Insn::GuardType { val: self_val, guard_type: types::HeapBasicObject, state });
let self_val = self.push_insn(block, Insn::GuardShape { val: self_val, shape: recv_type.shape(), state });
let shape = self.load_shape(block, self_val);
self.guard_shape(block, shape, recv_type.shape(), state);
let mut ivar_index: u16 = 0;
let replacement = if ! unsafe { rb_shape_get_iv_index(recv_type.shape().0, id, &mut ivar_index) } {
// If there is no IVAR index, then the ivar was undefined when we
@ -3148,7 +3166,8 @@ impl Function {
self.push_insn_id(block, insn_id); continue;
}
let self_val = self.push_insn(block, Insn::GuardType { val: self_val, guard_type: types::HeapBasicObject, state });
let _ = self.push_insn(block, Insn::GuardShape { val: self_val, shape: recv_type.shape(), state });
let shape = self.load_shape(block, self_val);
self.guard_shape(block, shape, recv_type.shape(), state);
let mut ivar_index: u16 = 0;
let replacement = if unsafe { rb_shape_get_iv_index(recv_type.shape().0, id, &mut ivar_index) } {
self.push_insn(block, Insn::Const { val: Const::Value(pushval) })
@ -3219,7 +3238,8 @@ impl Function {
// Fall through to emitting the ivar write
}
let self_val = self.push_insn(block, Insn::GuardType { val: self_val, guard_type: types::HeapBasicObject, state });
let self_val = self.push_insn(block, Insn::GuardShape { val: self_val, shape: recv_type.shape(), state });
let shape = self.load_shape(block, self_val);
self.guard_shape(block, shape, recv_type.shape(), state);
// Current shape contains this ivar
let (ivar_storage, offset) = if recv_type.flags().is_embedded() {
// See ROBJECT_FIELDS() from include/ruby/internal/core/robject.h
@ -6261,7 +6281,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let val = state.stack_pop()?;
let array = fun.push_insn(block, Insn::GuardType { val, guard_type: types::ArrayExact, state: exit_id, });
let length = fun.push_insn(block, Insn::ArrayLength { array });
fun.push_insn(block, Insn::GuardBitEquals { val: length, expected: Const::CInt64(num as i64), state: exit_id });
fun.push_insn(block, Insn::GuardBitEquals { val: length, expected: Const::CInt64(num as i64), reason: SideExitReason::ExpandArray, state: exit_id });
for i in (0..num).rev() {
// TODO(max): Add a short-cut path for long indices into an array where the
// index is known to be in-bounds

View File

@ -3677,10 +3677,11 @@ mod hir_opt_tests {
Jump bb2(v4)
bb2(v6:BasicObject):
v15:HeapBasicObject = GuardType v6, HeapBasicObject
v16:HeapBasicObject = GuardShape v15, 0x1000
v17:StringExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
v16:CShape = LoadField v15, :_shape_id@0x1000
v17:CShape[0x1001] = GuardBitEquals v16, CShape(0x1001)
v18:StringExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
CheckInterrupts
Return v17
Return v18
");
}
@ -3701,10 +3702,11 @@ mod hir_opt_tests {
Jump bb2(v4)
bb2(v6:BasicObject):
v15:HeapBasicObject = GuardType v6, HeapBasicObject
v16:HeapBasicObject = GuardShape v15, 0x1000
v17:NilClass = Const Value(nil)
v16:CShape = LoadField v15, :_shape_id@0x1000
v17:CShape[0x1001] = GuardBitEquals v16, CShape(0x1001)
v18:NilClass = Const Value(nil)
CheckInterrupts
Return v17
Return v18
");
}
@ -3821,9 +3823,10 @@ mod hir_opt_tests {
v10:Fixnum[5] = Const Value(5)
PatchPoint SingleRactorMode
v19:HeapBasicObject = GuardType v6, HeapBasicObject
v20:HeapBasicObject = GuardShape v19, 0x1000
StoreField v20, :@foo@0x1001, v10
WriteBarrier v20, v10
v20:CShape = LoadField v19, :_shape_id@0x1000
v21:CShape[0x1001] = GuardBitEquals v20, CShape(0x1001)
StoreField v19, :@foo@0x1002, v10
WriteBarrier v19, v10
CheckInterrupts
Return v10
");
@ -3848,11 +3851,12 @@ mod hir_opt_tests {
v10:Fixnum[5] = Const Value(5)
PatchPoint SingleRactorMode
v19:HeapBasicObject = GuardType v6, HeapBasicObject
v20:HeapBasicObject = GuardShape v19, 0x1000
StoreField v20, :@foo@0x1001, v10
WriteBarrier v20, v10
v23:CShape[0x1002] = Const CShape(0x1002)
StoreField v20, :_shape_id@0x1003, v23
v20:CShape = LoadField v19, :_shape_id@0x1000
v21:CShape[0x1001] = GuardBitEquals v20, CShape(0x1001)
StoreField v19, :@foo@0x1002, v10
WriteBarrier v19, v10
v24:CShape[0x1003] = Const CShape(0x1003)
StoreField v19, :_shape_id@0x1000, v24
CheckInterrupts
Return v10
");
@ -3880,19 +3884,21 @@ mod hir_opt_tests {
v10:Fixnum[1] = Const Value(1)
PatchPoint SingleRactorMode
v25:HeapBasicObject = GuardType v6, HeapBasicObject
v26:HeapBasicObject = GuardShape v25, 0x1000
StoreField v26, :@foo@0x1001, v10
WriteBarrier v26, v10
v29:CShape[0x1002] = Const CShape(0x1002)
StoreField v26, :_shape_id@0x1003, v29
v26:CShape = LoadField v25, :_shape_id@0x1000
v27:CShape[0x1001] = GuardBitEquals v26, CShape(0x1001)
StoreField v25, :@foo@0x1002, v10
WriteBarrier v25, v10
v30:CShape[0x1003] = Const CShape(0x1003)
StoreField v25, :_shape_id@0x1000, v30
v16:Fixnum[2] = Const Value(2)
PatchPoint SingleRactorMode
v31:HeapBasicObject = GuardType v6, HeapBasicObject
v32:HeapBasicObject = GuardShape v31, 0x1002
v32:HeapBasicObject = GuardType v6, HeapBasicObject
v33:CShape = LoadField v32, :_shape_id@0x1000
v34:CShape[0x1003] = GuardBitEquals v33, CShape(0x1003)
StoreField v32, :@bar@0x1004, v16
WriteBarrier v32, v16
v35:CShape[0x1005] = Const CShape(0x1005)
StoreField v32, :_shape_id@0x1003, v35
v37:CShape[0x1005] = Const CShape(0x1005)
StoreField v32, :_shape_id@0x1000, v37
CheckInterrupts
Return v16
");
@ -5611,10 +5617,11 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(C@0x1000, foo@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(C@0x1000)
v21:HeapObject[class_exact:C] = GuardType v9, HeapObject[class_exact:C]
v24:HeapObject[class_exact:C] = GuardShape v21, 0x1038
v25:BasicObject = LoadField v24, :@foo@0x1039
v24:CShape = LoadField v21, :_shape_id@0x1038
v25:CShape[0x1039] = GuardBitEquals v24, CShape(0x1039)
v26:BasicObject = LoadField v21, :@foo@0x103a
CheckInterrupts
Return v25
Return v26
");
}
@ -5650,11 +5657,12 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(C@0x1000, foo@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(C@0x1000)
v21:HeapObject[class_exact:C] = GuardType v9, HeapObject[class_exact:C]
v24:HeapObject[class_exact:C] = GuardShape v21, 0x1038
v25:CPtr = LoadField v24, :_as_heap@0x1039
v26:BasicObject = LoadField v25, :@foo@0x103a
v24:CShape = LoadField v21, :_shape_id@0x1038
v25:CShape[0x1039] = GuardBitEquals v24, CShape(0x1039)
v26:CPtr = LoadField v21, :_as_heap@0x103a
v27:BasicObject = LoadField v26, :@foo@0x103b
CheckInterrupts
Return v26
Return v27
");
}
@ -5679,11 +5687,12 @@ mod hir_opt_tests {
bb2(v6:BasicObject):
PatchPoint SingleRactorMode
v16:HeapBasicObject = GuardType v6, HeapBasicObject
v17:HeapBasicObject = GuardShape v16, 0x1000
v18:CUInt16[0] = Const CUInt16(0)
v19:BasicObject = CCall v17, :rb_ivar_get_at_no_ractor_check@0x1008, v18
v17:CShape = LoadField v16, :_shape_id@0x1000
v18:CShape[0x1001] = GuardBitEquals v17, CShape(0x1001)
v19:CUInt16[0] = Const CUInt16(0)
v20:BasicObject = CCall v16, :rb_ivar_get_at_no_ractor_check@0x1008, v19
CheckInterrupts
Return v19
Return v20
");
}
@ -5708,11 +5717,12 @@ mod hir_opt_tests {
bb2(v6:BasicObject):
PatchPoint SingleRactorMode
v16:HeapBasicObject = GuardType v6, HeapBasicObject
v17:HeapBasicObject = GuardShape v16, 0x1000
v18:CUInt16[0] = Const CUInt16(0)
v19:BasicObject = CCall v17, :rb_ivar_get_at_no_ractor_check@0x1008, v18
v17:CShape = LoadField v16, :_shape_id@0x1000
v18:CShape[0x1001] = GuardBitEquals v17, CShape(0x1001)
v19:CUInt16[0] = Const CUInt16(0)
v20:BasicObject = CCall v16, :rb_ivar_get_at_no_ractor_check@0x1008, v19
CheckInterrupts
Return v19
Return v20
");
}
@ -5739,11 +5749,12 @@ mod hir_opt_tests {
bb2(v6:BasicObject):
PatchPoint SingleRactorMode
v16:HeapBasicObject = GuardType v6, HeapBasicObject
v17:HeapBasicObject = GuardShape v16, 0x1000
v18:CUInt16[0] = Const CUInt16(0)
v19:BasicObject = CCall v17, :rb_ivar_get_at_no_ractor_check@0x1008, v18
v17:CShape = LoadField v16, :_shape_id@0x1000
v18:CShape[0x1001] = GuardBitEquals v17, CShape(0x1001)
v19:CUInt16[0] = Const CUInt16(0)
v20:BasicObject = CCall v16, :rb_ivar_get_at_no_ractor_check@0x1008, v19
CheckInterrupts
Return v19
Return v20
");
}
@ -6030,10 +6041,11 @@ mod hir_opt_tests {
v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(C@0x1010, foo@0x1018, cme:0x1020)
PatchPoint NoSingletonClass(C@0x1010)
v25:HeapObject[VALUE(0x1008)] = GuardShape v20, 0x1048
v26:NilClass = Const Value(nil)
v25:CShape = LoadField v20, :_shape_id@0x1048
v26:CShape[0x1049] = GuardBitEquals v25, CShape(0x1049)
v27:NilClass = Const Value(nil)
CheckInterrupts
Return v26
Return v27
");
}
@ -6064,10 +6076,11 @@ mod hir_opt_tests {
v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(C@0x1010, foo@0x1018, cme:0x1020)
PatchPoint NoSingletonClass(C@0x1010)
v25:HeapObject[VALUE(0x1008)] = GuardShape v20, 0x1048
v26:NilClass = Const Value(nil)
v25:CShape = LoadField v20, :_shape_id@0x1048
v26:CShape[0x1049] = GuardBitEquals v25, CShape(0x1049)
v27:NilClass = Const Value(nil)
CheckInterrupts
Return v26
Return v27
");
}
@ -6096,10 +6109,11 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(C@0x1000, foo@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(C@0x1000)
v21:HeapObject[class_exact:C] = GuardType v9, HeapObject[class_exact:C]
v24:HeapObject[class_exact:C] = GuardShape v21, 0x1038
v25:NilClass = Const Value(nil)
v24:CShape = LoadField v21, :_shape_id@0x1038
v25:CShape[0x1039] = GuardBitEquals v24, CShape(0x1039)
v26:NilClass = Const Value(nil)
CheckInterrupts
Return v25
Return v26
");
}
@ -6128,10 +6142,11 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(C@0x1000, foo@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(C@0x1000)
v21:HeapObject[class_exact:C] = GuardType v9, HeapObject[class_exact:C]
v24:HeapObject[class_exact:C] = GuardShape v21, 0x1038
v25:NilClass = Const Value(nil)
v24:CShape = LoadField v21, :_shape_id@0x1038
v25:CShape[0x1039] = GuardBitEquals v24, CShape(0x1039)
v26:NilClass = Const Value(nil)
CheckInterrupts
Return v25
Return v26
");
}
@ -6160,11 +6175,12 @@ mod hir_opt_tests {
v16:Fixnum[5] = Const Value(5)
PatchPoint MethodRedefined(C@0x1000, foo=@0x1008, cme:0x1010)
v26:HeapObject[class_exact:C] = GuardType v9, HeapObject[class_exact:C]
v29:HeapObject[class_exact:C] = GuardShape v26, 0x1038
StoreField v29, :@foo@0x1039, v16
WriteBarrier v29, v16
v32:CShape[0x103a] = Const CShape(0x103a)
StoreField v29, :_shape_id@0x103b, v32
v29:CShape = LoadField v26, :_shape_id@0x1038
v30:CShape[0x1039] = GuardBitEquals v29, CShape(0x1039)
StoreField v26, :@foo@0x103a, v16
WriteBarrier v26, v16
v33:CShape[0x103b] = Const CShape(0x103b)
StoreField v26, :_shape_id@0x1038, v33
CheckInterrupts
Return v16
");
@ -6195,11 +6211,12 @@ mod hir_opt_tests {
v16:Fixnum[5] = Const Value(5)
PatchPoint MethodRedefined(C@0x1000, foo=@0x1008, cme:0x1010)
v26:HeapObject[class_exact:C] = GuardType v9, HeapObject[class_exact:C]
v29:HeapObject[class_exact:C] = GuardShape v26, 0x1038
StoreField v29, :@foo@0x1039, v16
WriteBarrier v29, v16
v32:CShape[0x103a] = Const CShape(0x103a)
StoreField v29, :_shape_id@0x103b, v32
v29:CShape = LoadField v26, :_shape_id@0x1038
v30:CShape[0x1039] = GuardBitEquals v29, CShape(0x1039)
StoreField v26, :@foo@0x103a, v16
WriteBarrier v26, v16
v33:CShape[0x103b] = Const CShape(0x103b)
StoreField v26, :_shape_id@0x1038, v33
CheckInterrupts
Return v16
");
@ -9752,21 +9769,22 @@ mod hir_opt_tests {
SetLocal :formatted, l0, EP@3, v15
PatchPoint SingleRactorMode
v54:HeapBasicObject = GuardType v14, HeapBasicObject
v55:HeapBasicObject = GuardShape v54, 0x1000
StoreField v55, :@formatted@0x1001, v15
WriteBarrier v55, v15
v58:CShape[0x1002] = Const CShape(0x1002)
StoreField v55, :_shape_id@0x1003, v58
v55:CShape = LoadField v54, :_shape_id@0x1000
v56:CShape[0x1001] = GuardBitEquals v55, CShape(0x1001)
StoreField v54, :@formatted@0x1002, v15
WriteBarrier v54, v15
v59:CShape[0x1003] = Const CShape(0x1003)
StoreField v54, :_shape_id@0x1000, v59
v43:Class[VMFrozenCore] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(Class@0x1010, lambda@0x1018, cme:0x1020)
PatchPoint NoSingletonClass(Class@0x1010)
v63:BasicObject = CCallWithFrame v43, :RubyVM::FrozenCore.lambda@0x1048, block=0x1050
v64:BasicObject = CCallWithFrame v43, :RubyVM::FrozenCore.lambda@0x1048, block=0x1050
v46:BasicObject = GetLocal :a, l0, EP@6
v47:BasicObject = GetLocal :_b, l0, EP@5
v48:BasicObject = GetLocal :_c, l0, EP@4
v49:BasicObject = GetLocal :formatted, l0, EP@3
CheckInterrupts
Return v63
Return v64
");
}
@ -9802,10 +9820,11 @@ mod hir_opt_tests {
v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(TestFrozen@0x1010, a@0x1018, cme:0x1020)
PatchPoint NoSingletonClass(TestFrozen@0x1010)
v25:HeapObject[VALUE(0x1008)] = GuardShape v20, 0x1048
v27:Fixnum[1] = Const Value(1)
v25:CShape = LoadField v20, :_shape_id@0x1048
v26:CShape[0x1049] = GuardBitEquals v25, CShape(0x1049)
v28:Fixnum[1] = Const Value(1)
CheckInterrupts
Return v27
Return v28
");
}
@ -9843,10 +9862,11 @@ mod hir_opt_tests {
v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(TestMultiIvars@0x1010, b@0x1018, cme:0x1020)
PatchPoint NoSingletonClass(TestMultiIvars@0x1010)
v25:HeapObject[VALUE(0x1008)] = GuardShape v20, 0x1048
v27:Fixnum[20] = Const Value(20)
v25:CShape = LoadField v20, :_shape_id@0x1048
v26:CShape[0x1049] = GuardBitEquals v25, CShape(0x1049)
v28:Fixnum[20] = Const Value(20)
CheckInterrupts
Return v27
Return v28
");
}
@ -9882,10 +9902,11 @@ mod hir_opt_tests {
v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(TestFrozenStr@0x1010, name@0x1018, cme:0x1020)
PatchPoint NoSingletonClass(TestFrozenStr@0x1010)
v25:HeapObject[VALUE(0x1008)] = GuardShape v20, 0x1048
v27:StringExact[VALUE(0x1050)] = Const Value(VALUE(0x1050))
v25:CShape = LoadField v20, :_shape_id@0x1048
v26:CShape[0x1049] = GuardBitEquals v25, CShape(0x1049)
v28:StringExact[VALUE(0x1050)] = Const Value(VALUE(0x1050))
CheckInterrupts
Return v27
Return v28
");
}
@ -9921,10 +9942,11 @@ mod hir_opt_tests {
v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(TestFrozenNil@0x1010, value@0x1018, cme:0x1020)
PatchPoint NoSingletonClass(TestFrozenNil@0x1010)
v25:HeapObject[VALUE(0x1008)] = GuardShape v20, 0x1048
v27:NilClass = Const Value(nil)
v25:CShape = LoadField v20, :_shape_id@0x1048
v26:CShape[0x1049] = GuardBitEquals v25, CShape(0x1049)
v28:NilClass = Const Value(nil)
CheckInterrupts
Return v27
Return v28
");
}
@ -9960,10 +9982,11 @@ mod hir_opt_tests {
v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(TestUnfrozen@0x1010, a@0x1018, cme:0x1020)
PatchPoint NoSingletonClass(TestUnfrozen@0x1010)
v25:HeapObject[VALUE(0x1008)] = GuardShape v20, 0x1048
v26:BasicObject = LoadField v25, :@a@0x1049
v25:CShape = LoadField v20, :_shape_id@0x1048
v26:CShape[0x1049] = GuardBitEquals v25, CShape(0x1049)
v27:BasicObject = LoadField v20, :@a@0x104a
CheckInterrupts
Return v26
Return v27
");
}
@ -9999,10 +10022,11 @@ mod hir_opt_tests {
v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(TestAttrReader@0x1010, value@0x1018, cme:0x1020)
PatchPoint NoSingletonClass(TestAttrReader@0x1010)
v25:HeapObject[VALUE(0x1008)] = GuardShape v20, 0x1048
v27:Fixnum[42] = Const Value(42)
v25:CShape = LoadField v20, :_shape_id@0x1048
v26:CShape[0x1049] = GuardBitEquals v25, CShape(0x1049)
v28:Fixnum[42] = Const Value(42)
CheckInterrupts
Return v27
Return v28
");
}
@ -10038,10 +10062,11 @@ mod hir_opt_tests {
v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(TestFrozenSym@0x1010, sym@0x1018, cme:0x1020)
PatchPoint NoSingletonClass(TestFrozenSym@0x1010)
v25:HeapObject[VALUE(0x1008)] = GuardShape v20, 0x1048
v27:StaticSymbol[:hello] = Const Value(VALUE(0x1050))
v25:CShape = LoadField v20, :_shape_id@0x1048
v26:CShape[0x1049] = GuardBitEquals v25, CShape(0x1049)
v28:StaticSymbol[:hello] = Const Value(VALUE(0x1050))
CheckInterrupts
Return v27
Return v28
");
}
@ -10077,10 +10102,11 @@ mod hir_opt_tests {
v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(TestFrozenBool@0x1010, flag@0x1018, cme:0x1020)
PatchPoint NoSingletonClass(TestFrozenBool@0x1010)
v25:HeapObject[VALUE(0x1008)] = GuardShape v20, 0x1048
v27:TrueClass = Const Value(true)
v25:CShape = LoadField v20, :_shape_id@0x1048
v26:CShape[0x1049] = GuardBitEquals v25, CShape(0x1049)
v28:TrueClass = Const Value(true)
CheckInterrupts
Return v27
Return v28
");
}
@ -10114,10 +10140,11 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(TestDynamic@0x1000, val@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(TestDynamic@0x1000)
v21:HeapObject[class_exact:TestDynamic] = GuardType v9, HeapObject[class_exact:TestDynamic]
v24:HeapObject[class_exact:TestDynamic] = GuardShape v21, 0x1038
v25:BasicObject = LoadField v24, :@val@0x1039
v24:CShape = LoadField v21, :_shape_id@0x1038
v25:CShape[0x1039] = GuardBitEquals v24, CShape(0x1039)
v26:BasicObject = LoadField v21, :@val@0x103a
CheckInterrupts
Return v25
Return v26
");
}
@ -10154,20 +10181,22 @@ mod hir_opt_tests {
v28:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(TestNestedAccess@0x1010, x@0x1018, cme:0x1020)
PatchPoint NoSingletonClass(TestNestedAccess@0x1010)
v39:HeapObject[VALUE(0x1008)] = GuardShape v28, 0x1048
v50:Fixnum[100] = Const Value(100)
v39:CShape = LoadField v28, :_shape_id@0x1048
v40:CShape[0x1049] = GuardBitEquals v39, CShape(0x1049)
v52:Fixnum[100] = Const Value(100)
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1050, NESTED_FROZEN)
v34:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(TestNestedAccess@0x1010, y@0x1058, cme:0x1060)
PatchPoint NoSingletonClass(TestNestedAccess@0x1010)
v42:HeapObject[VALUE(0x1008)] = GuardShape v34, 0x1048
v51:Fixnum[200] = Const Value(200)
v43:CShape = LoadField v34, :_shape_id@0x1048
v44:CShape[0x1049] = GuardBitEquals v43, CShape(0x1049)
v53:Fixnum[200] = Const Value(200)
PatchPoint MethodRedefined(Integer@0x1088, +@0x1090, cme:0x1098)
v52:Fixnum[300] = Const Value(300)
v54:Fixnum[300] = Const Value(300)
IncrCounter inline_cfunc_optimized_send_count
CheckInterrupts
Return v52
Return v54
");
}

View File

@ -190,6 +190,7 @@ make_counters! {
exit_guard_bit_equals_failure,
exit_guard_int_equals_failure,
exit_guard_shape_failure,
exit_expandarray_failure,
exit_guard_not_frozen_failure,
exit_guard_not_shared_failure,
exit_guard_less_failure,
@ -509,8 +510,8 @@ pub fn side_exit_counter(reason: crate::hir::SideExitReason) -> Counter {
BoxFixnumOverflow => exit_box_fixnum_overflow,
GuardType(_) => exit_guard_type_failure,
GuardTypeNot(_) => exit_guard_type_not_failure,
GuardBitEquals(_) => exit_guard_bit_equals_failure,
GuardShape(_) => exit_guard_shape_failure,
ExpandArray => exit_expandarray_failure,
GuardNotFrozen => exit_guard_not_frozen_failure,
GuardNotShared => exit_guard_not_shared_failure,
GuardLess => exit_guard_less_failure,