diff options
| author | Max Bernstein <rubybugs@bernsteinbear.com> | 2025-08-07 12:11:55 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-07 15:11:55 -0400 |
| commit | 363ad0ad17c8ce36035c64ee3267ec680423bc68 (patch) | |
| tree | 68e5917ea647567053895b3904be76e6fa1decaa | |
| parent | 1aabd2cb365ff0a236609fe1c4ab193d16027757 (diff) | |
ZJIT: Create HeapObject Type (#14140)
This is a counterpoint to the Immediate type and it represents all BasicObject subclasses except for the several immediate objects.
If we know something is a HeapObject, we know we can treat it as an RBasic pointer.
| -rw-r--r-- | zjit/src/hir.rs | 20 | ||||
| -rw-r--r-- | zjit/src/hir_type/gen_hir_type.rb | 2 | ||||
| -rw-r--r-- | zjit/src/hir_type/hir_type.inc.rs | 5 | ||||
| -rw-r--r-- | zjit/src/hir_type/mod.rs | 29 |
4 files changed, 44 insertions, 12 deletions
diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index f4dae3f0ec..f98aa846cd 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -5566,7 +5566,7 @@ mod opt_tests { fn test@<compiled>:5: bb0(v0:BasicObject): PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010) - v6:BasicObject[class_exact*:Object@VALUE(0x1000)] = GuardType v0, BasicObject[class_exact*:Object@VALUE(0x1000)] + v6:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v0, HeapObject[class_exact*:Object@VALUE(0x1000)] v7:BasicObject = SendWithoutBlockDirect v6, :foo (0x1038) Return v7 "#]]); @@ -5606,7 +5606,7 @@ mod opt_tests { fn test@<compiled>:6: bb0(v0:BasicObject): PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010) - v6:BasicObject[class_exact*:Object@VALUE(0x1000)] = GuardType v0, BasicObject[class_exact*:Object@VALUE(0x1000)] + v6:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v0, HeapObject[class_exact*:Object@VALUE(0x1000)] v7:BasicObject = SendWithoutBlockDirect v6, :foo (0x1038) Return v7 "#]]); @@ -5625,7 +5625,7 @@ mod opt_tests { bb0(v0:BasicObject): v2:Fixnum[3] = Const Value(3) PatchPoint MethodRedefined(Object@0x1000, Integer@0x1008, cme:0x1010) - v7:BasicObject[class_exact*:Object@VALUE(0x1000)] = GuardType v0, BasicObject[class_exact*:Object@VALUE(0x1000)] + v7:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v0, HeapObject[class_exact*:Object@VALUE(0x1000)] v8:BasicObject = SendWithoutBlockDirect v7, :Integer (0x1038), v2 Return v8 "#]]); @@ -5647,7 +5647,7 @@ mod opt_tests { v2:Fixnum[1] = Const Value(1) v3:Fixnum[2] = Const Value(2) PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010) - v8:BasicObject[class_exact*:Object@VALUE(0x1000)] = GuardType v0, BasicObject[class_exact*:Object@VALUE(0x1000)] + v8:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v0, HeapObject[class_exact*:Object@VALUE(0x1000)] v9:BasicObject = SendWithoutBlockDirect v8, :foo (0x1038), v2, v3 Return v9 "#]]); @@ -5670,10 +5670,10 @@ mod opt_tests { fn test@<compiled>:7: bb0(v0:BasicObject): PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010) - v8:BasicObject[class_exact*:Object@VALUE(0x1000)] = GuardType v0, BasicObject[class_exact*:Object@VALUE(0x1000)] + v8:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v0, HeapObject[class_exact*:Object@VALUE(0x1000)] v9:BasicObject = SendWithoutBlockDirect v8, :foo (0x1038) PatchPoint MethodRedefined(Object@0x1000, bar@0x1040, cme:0x1048) - v11:BasicObject[class_exact*:Object@VALUE(0x1000)] = GuardType v0, BasicObject[class_exact*:Object@VALUE(0x1000)] + v11:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v0, HeapObject[class_exact*:Object@VALUE(0x1000)] v12:BasicObject = SendWithoutBlockDirect v11, :bar (0x1038) Return v12 "#]]); @@ -6475,7 +6475,7 @@ mod opt_tests { fn test@<compiled>:8: bb0(v0:BasicObject, v1:BasicObject): PatchPoint MethodRedefined(C@0x1000, foo@0x1008, cme:0x1010) - v7:BasicObject[class_exact:C] = GuardType v1, BasicObject[class_exact:C] + v7:HeapObject[class_exact:C] = GuardType v1, HeapObject[class_exact:C] v8:BasicObject = SendWithoutBlockDirect v7, :foo (0x1038) Return v8 "#]]); @@ -7428,7 +7428,7 @@ mod opt_tests { fn test@<compiled>:3: bb0(v0:BasicObject): PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010) - v6:BasicObject[class_exact*:Object@VALUE(0x1000)] = GuardType v0, BasicObject[class_exact*:Object@VALUE(0x1000)] + v6:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v0, HeapObject[class_exact*:Object@VALUE(0x1000)] v7:BasicObject = SendWithoutBlockDirect v6, :foo (0x1038) Return v7 "#]]); @@ -7497,7 +7497,7 @@ mod opt_tests { fn test@<compiled>:6: bb0(v0:BasicObject, v1:BasicObject): PatchPoint MethodRedefined(C@0x1000, foo@0x1008, cme:0x1010) - v7:BasicObject[class_exact:C] = GuardType v1, BasicObject[class_exact:C] + v7:HeapObject[class_exact:C] = GuardType v1, HeapObject[class_exact:C] v8:BasicObject = GetIvar v7, :@foo Return v8 "#]]); @@ -7518,7 +7518,7 @@ mod opt_tests { fn test@<compiled>:6: bb0(v0:BasicObject, v1:BasicObject): PatchPoint MethodRedefined(C@0x1000, foo@0x1008, cme:0x1010) - v7:BasicObject[class_exact:C] = GuardType v1, BasicObject[class_exact:C] + v7:HeapObject[class_exact:C] = GuardType v1, HeapObject[class_exact:C] v8:BasicObject = GetIvar v7, :@foo Return v8 "#]]); diff --git a/zjit/src/hir_type/gen_hir_type.rb b/zjit/src/hir_type/gen_hir_type.rb index 6857678982..15aa68a600 100644 --- a/zjit/src/hir_type/gen_hir_type.rb +++ b/zjit/src/hir_type/gen_hir_type.rb @@ -156,6 +156,8 @@ add_union "BuiltinExact", $builtin_exact add_union "Subclass", $subclass add_union "BoolExact", [true_exact.name, false_exact.name] add_union "Immediate", [fixnum.name, flonum.name, static_sym.name, nil_exact.name, true_exact.name, false_exact.name, undef_.name] +$bits["HeapObject"] = ["BasicObject & !Immediate"] +$numeric_bits["HeapObject"] = $numeric_bits["BasicObject"] & ~$numeric_bits["Immediate"] # ===== Finished generating the DAG; write Rust code ===== diff --git a/zjit/src/hir_type/hir_type.inc.rs b/zjit/src/hir_type/hir_type.inc.rs index 68039c7f53..5850874080 100644 --- a/zjit/src/hir_type/hir_type.inc.rs +++ b/zjit/src/hir_type/hir_type.inc.rs @@ -38,6 +38,7 @@ mod bits { pub const HashExact: u64 = 1u64 << 23; pub const HashSubclass: u64 = 1u64 << 24; pub const HeapFloat: u64 = 1u64 << 25; + pub const HeapObject: u64 = BasicObject & !Immediate; pub const Immediate: u64 = FalseClass | Fixnum | Flonum | NilClass | StaticSymbol | TrueClass | Undef; pub const Integer: u64 = Bignum | Fixnum; pub const Module: u64 = Class | ModuleExact | ModuleSubclass; @@ -65,7 +66,7 @@ mod bits { pub const Symbol: u64 = DynamicSymbol | StaticSymbol; pub const TrueClass: u64 = 1u64 << 40; pub const Undef: u64 = 1u64 << 41; - pub const AllBitPatterns: [(&'static str, u64); 65] = [ + pub const AllBitPatterns: [(&'static str, u64); 66] = [ ("Any", Any), ("RubyValue", RubyValue), ("Immediate", Immediate), @@ -75,6 +76,7 @@ mod bits { ("BuiltinExact", BuiltinExact), ("BoolExact", BoolExact), ("TrueClass", TrueClass), + ("HeapObject", HeapObject), ("String", String), ("Subclass", Subclass), ("StringSubclass", StringSubclass), @@ -174,6 +176,7 @@ pub mod types { pub const HashExact: Type = Type::from_bits(bits::HashExact); pub const HashSubclass: Type = Type::from_bits(bits::HashSubclass); pub const HeapFloat: Type = Type::from_bits(bits::HeapFloat); + pub const HeapObject: Type = Type::from_bits(bits::HeapObject); pub const Immediate: Type = Type::from_bits(bits::Immediate); pub const Integer: Type = Type::from_bits(bits::Integer); pub const Module: Type = Type::from_bits(bits::Module); diff --git a/zjit/src/hir_type/mod.rs b/zjit/src/hir_type/mod.rs index 84679c419d..c5e7aa87c6 100644 --- a/zjit/src/hir_type/mod.rs +++ b/zjit/src/hir_type/mod.rs @@ -248,7 +248,7 @@ impl Type { else if val.class() == unsafe { rb_cString } { types::StringExact } else { // TODO(max): Add more cases for inferring type bits from built-in types - Type { bits: bits::BasicObject, spec: Specialization::TypeExact(val.class()) } + Type { bits: bits::HeapObject, spec: Specialization::TypeExact(val.class()) } } } @@ -583,6 +583,7 @@ mod tests { assert_subtype(Type::fixnum(123), types::Immediate); assert_subtype(types::Fixnum, types::Immediate); assert_not_subtype(types::Bignum, types::Immediate); + assert_not_subtype(types::Integer, types::Immediate); assert_subtype(types::NilClass, types::Immediate); assert_subtype(types::TrueClass, types::Immediate); assert_subtype(types::FalseClass, types::Immediate); @@ -593,6 +594,32 @@ mod tests { } #[test] + fn heap_object() { + assert_not_subtype(Type::fixnum(123), types::HeapObject); + assert_not_subtype(types::Fixnum, types::HeapObject); + assert_subtype(types::Bignum, types::HeapObject); + assert_not_subtype(types::Integer, types::HeapObject); + assert_not_subtype(types::NilClass, types::HeapObject); + assert_not_subtype(types::TrueClass, types::HeapObject); + assert_not_subtype(types::FalseClass, types::HeapObject); + assert_not_subtype(types::StaticSymbol, types::HeapObject); + assert_subtype(types::DynamicSymbol, types::HeapObject); + assert_not_subtype(types::Flonum, types::HeapObject); + assert_subtype(types::HeapFloat, types::HeapObject); + assert_not_subtype(types::BasicObject, types::HeapObject); + assert_not_subtype(types::Object, types::HeapObject); + assert_not_subtype(types::Immediate, types::HeapObject); + assert_not_subtype(types::HeapObject, types::Immediate); + crate::cruby::with_rubyvm(|| { + let left = Type::from_value(rust_str_to_ruby("hello")); + let right = Type::from_value(rust_str_to_ruby("world")); + assert_subtype(left, types::HeapObject); + assert_subtype(right, types::HeapObject); + assert_subtype(left.union(right), types::HeapObject); + }); + } + + #[test] fn fixnum_has_ruby_object() { assert_eq!(Type::fixnum(3).ruby_object(), Some(VALUE::fixnum_from_usize(3))); assert_eq!(types::Fixnum.ruby_object(), None); |
