Skip to content

Commit ce5d4f0

Browse files
committed
ZJIT: Support guarding *Exact types
ZJIT already can generate guard type instructions for *Exact types. For example: ``` def test(strings) strings.map do |string| string.bytesize end end test(["foo", "bar"]) ``` ``` HIR: fn block in test: bb0(v0:BasicObject, v1:BasicObject): PatchPoint MethodRedefined(String@0x1014be890, bytesize@0x19f1) v7:StringExact = GuardType v1, StringExact v8:Fixnum = CCall bytesize@0x16fa4cc18, v7 Return v8 ``` But zjit only supported guarding fixnums so this script would panic. This commit adds support for guarding *Exact types.
1 parent ad7d75c commit ce5d4f0

3 files changed

Lines changed: 95 additions & 0 deletions

File tree

test/ruby/test_zjit.rb

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,51 @@ def test_instruction_order
915915
end
916916
end
917917

918+
def test_module_name_with_guard_passes
919+
assert_compiles '"Integer"', %q{
920+
def test(mod)
921+
mod.name
922+
end
923+
924+
test(String)
925+
test(Integer)
926+
}, call_threshold: 2
927+
end
928+
929+
def test_string_bytesize_with_guard
930+
assert_compiles '5', %q{
931+
def test(str)
932+
str.bytesize
933+
end
934+
935+
test('hello')
936+
test('world')
937+
}, call_threshold: 2
938+
end
939+
940+
def test_guard_type_side_exit
941+
# This test demonstrates that the guard side exit works correctly
942+
# In this case, when we call with a non-Class object, it should fall back to interpreter
943+
assert_compiles '["String", "Integer", "Foo"]', %q{
944+
class Foo
945+
def name
946+
"Foo"
947+
end
948+
end
949+
950+
def test(mod)
951+
mod.name
952+
end
953+
954+
results = []
955+
results << test(String)
956+
results << test(Integer)
957+
results << test(Foo.new)
958+
959+
results
960+
}, call_threshold: 2
961+
end
962+
918963
private
919964

920965
# Assert that every method call in `test_script` can be compiled by ZJIT

zjit/src/codegen.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,16 @@ fn gen_guard_type(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, guard
979979
// Check if opnd is Fixnum
980980
asm.test(val, Opnd::UImm(RUBY_FIXNUM_FLAG as u64));
981981
asm.jz(side_exit(jit, state)?);
982+
} else if let Some(expected_class) = guard_type.runtime_exact_ruby_class() {
983+
// Guard for exact class types (e.g., ClassExact, ArrayExact, StringExact, etc.)
984+
asm_comment!(asm, "guard exact class");
985+
986+
// Get the class of the value
987+
let klass = asm.ccall(rb_yarv_class_of as *const u8, vec![val]);
988+
989+
// Compare with expected class
990+
asm.cmp(klass, Opnd::UImm(expected_class.into()));
991+
asm.jne(side_exit(jit, state)?);
982992
} else {
983993
unimplemented!("unsupported type: {guard_type}");
984994
}

zjit/src/hir.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6517,4 +6517,44 @@ mod opt_tests {
65176517
Return v5
65186518
"#]]);
65196519
}
6520+
6521+
#[test]
6522+
fn test_guard_class_for_module_name() {
6523+
eval("
6524+
def test(mod)
6525+
mod.name
6526+
end
6527+
# Profile with Class objects
6528+
test(String)
6529+
test(Integer)
6530+
");
6531+
assert_optimized_method_hir("test", expect![[r#"
6532+
fn test:
6533+
bb0(v0:BasicObject, v1:BasicObject):
6534+
PatchPoint MethodRedefined(Class@0x1000, name@0x1008)
6535+
v7:ClassExact = GuardType v1, ClassExact
6536+
v8:StringExact|NilClassExact = CCall name@0x1010, v7
6537+
Return v8
6538+
"#]]);
6539+
}
6540+
6541+
#[test]
6542+
fn test_guard_string_for_bytesize() {
6543+
eval("
6544+
def test(str)
6545+
str.bytesize
6546+
end
6547+
# Profile with String objects
6548+
test('hello')
6549+
test('world')
6550+
");
6551+
assert_optimized_method_hir("test", expect![[r#"
6552+
fn test:
6553+
bb0(v0:BasicObject, v1:BasicObject):
6554+
PatchPoint MethodRedefined(String@0x1000, bytesize@0x1008)
6555+
v7:StringExact = GuardType v1, StringExact
6556+
v8:Fixnum = CCall bytesize@0x1010, v7
6557+
Return v8
6558+
"#]]);
6559+
}
65206560
}

0 commit comments

Comments
 (0)