From 0c1ce03b8c8431d27bc45f88541929881edd4e3e Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Thu, 9 Apr 2026 18:40:17 -0400 Subject: ZJIT: Make `hir::types::Class` not final and have it include metaclasses Every class boots with a metaclass, and all metaclasses are subclasses of Class, so `types::Class` has no business in `ExactBitsAndClass`. In fact, we should never see an object whose RBasic::class is exactly rb_cClass because classes get a metaclass on boot. So there is no ClassExact type. This fixes the side exits on getivar-module.rb that were introduced in a8f3c34556bac709587ded4e0e4dad08932d5900 ("ZJIT: Add missing guard on ivar access on T_{DATA,CLASS,MODULE}"). The `GuardType v, Class` checked for exactly rb_cClass and never passed. --- zjit/src/hir_type/gen_hir_type.rb | 6 ++++-- zjit/src/hir_type/hir_type.inc.rs | 11 ++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/zjit/src/hir_type/gen_hir_type.rb b/zjit/src/hir_type/gen_hir_type.rb index 37919425ce..aca8e574d6 100644 --- a/zjit/src/hir_type/gen_hir_type.rb +++ b/zjit/src/hir_type/gen_hir_type.rb @@ -89,7 +89,7 @@ def base_type name, c_name: nil [type, exact] end -# Define a new type that cannot be subclassed. +# Define a new type that has no subclasses and cannot be subclassed. # If c_name is given, mark the rb_cXYZ object as equivalent to this type. def final_type name, base: $object, c_name: nil if c_name @@ -109,7 +109,9 @@ base_type "Range", c_name: "rb_cRange" base_type "Set", c_name: "rb_cSet" base_type "Regexp", c_name: "rb_cRegexp" module_class, _ = base_type "Module", c_name: "rb_cModule" -class_ = final_type "Class", base: module_class, c_name: "rb_cClass" +# Class cannot be subclassed by doing `class Sub < Class`, +# but every metaclass is a subclass of `Class`. It's not final. +module_class.subtype "Class" numeric, _ = base_type "Numeric", c_name: "rb_cNumeric" diff --git a/zjit/src/hir_type/hir_type.inc.rs b/zjit/src/hir_type/hir_type.inc.rs index f37cd57b31..46c45f17f3 100644 --- a/zjit/src/hir_type/hir_type.inc.rs +++ b/zjit/src/hir_type/hir_type.inc.rs @@ -9,7 +9,7 @@ mod bits { pub const BasicObjectSubclass: u64 = 1u64 << 3; pub const Bignum: u64 = 1u64 << 4; pub const BoolExact: u64 = FalseClass | TrueClass; - pub const BuiltinExact: u64 = ArrayExact | BasicObjectExact | Class | FalseClass | Float | HashExact | Integer | ModuleExact | NilClass | NumericExact | ObjectExact | RangeExact | RegexpExact | SetExact | StringExact | Symbol | TrueClass; + pub const BuiltinExact: u64 = ArrayExact | BasicObjectExact | FalseClass | Float | HashExact | Integer | ModuleExact | NilClass | NumericExact | ObjectExact | RangeExact | RegexpExact | SetExact | StringExact | Symbol | TrueClass; pub const CBool: u64 = 1u64 << 5; pub const CDouble: u64 = 1u64 << 6; pub const CInt: u64 = CSigned | CUnsigned; @@ -231,7 +231,7 @@ pub mod types { pub const Truthy: Type = Type::from_bits(bits::Truthy); pub const TypedTData: Type = Type::from_bits(bits::TypedTData); pub const Undef: Type = Type::from_bits(bits::Undef); - pub const ExactBitsAndClass: [(u64, *const VALUE); 17] = [ + pub const ExactBitsAndClass: [(u64, *const VALUE); 16] = [ (bits::ObjectExact, &raw const crate::cruby::rb_cObject), (bits::BasicObjectExact, &raw const crate::cruby::rb_cBasicObject), (bits::StringExact, &raw const crate::cruby::rb_cString), @@ -241,7 +241,6 @@ pub mod types { (bits::SetExact, &raw const crate::cruby::rb_cSet), (bits::RegexpExact, &raw const crate::cruby::rb_cRegexp), (bits::ModuleExact, &raw const crate::cruby::rb_cModule), - (bits::Class, &raw const crate::cruby::rb_cClass), (bits::NumericExact, &raw const crate::cruby::rb_cNumeric), (bits::Integer, &raw const crate::cruby::rb_cInteger), (bits::Float, &raw const crate::cruby::rb_cFloat), @@ -250,9 +249,8 @@ pub mod types { (bits::TrueClass, &raw const crate::cruby::rb_cTrueClass), (bits::FalseClass, &raw const crate::cruby::rb_cFalseClass), ]; - pub const SubclassBitsAndClass: [(u64, *const VALUE); 17] = [ + pub const SubclassBitsAndClass: [(u64, *const VALUE); 16] = [ (bits::ArraySubclass, &raw const crate::cruby::rb_cArray), - (bits::Class, &raw const crate::cruby::rb_cClass), (bits::FalseClass, &raw const crate::cruby::rb_cFalseClass), (bits::Integer, &raw const crate::cruby::rb_cInteger), (bits::HashSubclass, &raw const crate::cruby::rb_cHash), @@ -269,9 +267,8 @@ pub mod types { (bits::ObjectSubclass, &raw const crate::cruby::rb_cObject), (bits::BasicObjectSubclass, &raw const crate::cruby::rb_cBasicObject), ]; - pub const InexactBitsAndClass: [(u64, *const VALUE); 17] = [ + pub const InexactBitsAndClass: [(u64, *const VALUE); 16] = [ (bits::Array, &raw const crate::cruby::rb_cArray), - (bits::Class, &raw const crate::cruby::rb_cClass), (bits::FalseClass, &raw const crate::cruby::rb_cFalseClass), (bits::Integer, &raw const crate::cruby::rb_cInteger), (bits::Hash, &raw const crate::cruby::rb_cHash), -- cgit v1.2.3