diff --git a/zjit.c b/zjit.c index 9218395582..560e115f3c 100644 --- a/zjit.c +++ b/zjit.c @@ -32,6 +32,8 @@ #include +RUBY_EXTERN VALUE rb_cSet; // defined in set.c and it's not exposed yet + uint32_t rb_zjit_get_page_size(void) { diff --git a/zjit/bindgen/src/main.rs b/zjit/bindgen/src/main.rs index cf328fc68c..eb66da5617 100644 --- a/zjit/bindgen/src/main.rs +++ b/zjit/bindgen/src/main.rs @@ -186,6 +186,7 @@ fn main() { .allowlist_var("rb_cThread") .allowlist_var("rb_cArray") .allowlist_var("rb_cHash") + .allowlist_var("rb_cSet") .allowlist_var("rb_cClass") .allowlist_var("rb_cISeq") diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs index 1367c9381b..dd0eb82bda 100644 --- a/zjit/src/cruby_bindings.inc.rs +++ b/zjit/src/cruby_bindings.inc.rs @@ -900,6 +900,7 @@ unsafe extern "C" { lines: *mut ::std::os::raw::c_int, ) -> ::std::os::raw::c_int; pub fn rb_jit_cont_each_iseq(callback: rb_iseq_callback, data: *mut ::std::os::raw::c_void); + pub static mut rb_cSet: VALUE; pub fn rb_zjit_get_page_size() -> u32; pub fn rb_zjit_reserve_addr_space(mem_size: u32) -> *mut u8; pub fn rb_zjit_profile_disable(iseq: *const rb_iseq_t); diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 3cc38e9c83..b5ad8b48b1 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -6235,4 +6235,24 @@ mod opt_tests { Return v11 "#]]); } + + #[test] + fn test_set_type_from_constant() { + eval(" + MY_SET = Set.new + + def test = MY_SET + + test + test + "); + assert_optimized_method_hir("test", expect![[r#" + fn test: + bb0(v0:BasicObject): + PatchPoint SingleRactorMode + PatchPoint StableConstantNames(0x1000, MY_SET) + v7:SetExact[VALUE(0x1008)] = Const Value(VALUE(0x1008)) + Return v7 + "#]]); + } } diff --git a/zjit/src/hir_type/gen_hir_type.rb b/zjit/src/hir_type/gen_hir_type.rb index 92351aafa2..1166d8ebb8 100644 --- a/zjit/src/hir_type/gen_hir_type.rb +++ b/zjit/src/hir_type/gen_hir_type.rb @@ -72,6 +72,7 @@ base_type "String" base_type "Array" base_type "Hash" base_type "Range" +base_type "Set" (integer, integer_exact) = base_type "Integer" # CRuby partitions Integer into immediate and non-immediate variants. diff --git a/zjit/src/hir_type/hir_type.inc.rs b/zjit/src/hir_type/hir_type.inc.rs index 7d6f92a180..7557610463 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 = FalseClassExact | TrueClassExact; - pub const BuiltinExact: u64 = ArrayExact | BasicObjectExact | FalseClassExact | FloatExact | HashExact | IntegerExact | NilClassExact | ObjectExact | RangeExact | StringExact | SymbolExact | TrueClassExact; + pub const BuiltinExact: u64 = ArrayExact | BasicObjectExact | FalseClassExact | FloatExact | HashExact | IntegerExact | NilClassExact | ObjectExact | RangeExact | SetExact | StringExact | SymbolExact | TrueClassExact; pub const CBool: u64 = 1u64 << 5; pub const CDouble: u64 = 1u64 << 6; pub const CInt: u64 = CSigned | CUnsigned; @@ -48,26 +48,29 @@ mod bits { pub const NilClass: u64 = NilClassExact | NilClassSubclass; pub const NilClassExact: u64 = 1u64 << 28; pub const NilClassSubclass: u64 = 1u64 << 29; - pub const Object: u64 = Array | FalseClass | Float | Hash | Integer | NilClass | ObjectExact | ObjectSubclass | Range | String | Symbol | TrueClass; + pub const Object: u64 = Array | FalseClass | Float | Hash | Integer | NilClass | ObjectExact | ObjectSubclass | Range | Set | String | Symbol | TrueClass; pub const ObjectExact: u64 = 1u64 << 30; pub const ObjectSubclass: u64 = 1u64 << 31; pub const Range: u64 = RangeExact | RangeSubclass; pub const RangeExact: u64 = 1u64 << 32; pub const RangeSubclass: u64 = 1u64 << 33; pub const RubyValue: u64 = BasicObject | CallableMethodEntry | Undef; - pub const StaticSymbol: u64 = 1u64 << 34; + pub const Set: u64 = SetExact | SetSubclass; + pub const SetExact: u64 = 1u64 << 34; + pub const SetSubclass: u64 = 1u64 << 35; + pub const StaticSymbol: u64 = 1u64 << 36; pub const String: u64 = StringExact | StringSubclass; - pub const StringExact: u64 = 1u64 << 35; - pub const StringSubclass: u64 = 1u64 << 36; - pub const Subclass: u64 = ArraySubclass | BasicObjectSubclass | FalseClassSubclass | FloatSubclass | HashSubclass | IntegerSubclass | NilClassSubclass | ObjectSubclass | RangeSubclass | StringSubclass | SymbolSubclass | TrueClassSubclass; + pub const StringExact: u64 = 1u64 << 37; + pub const StringSubclass: u64 = 1u64 << 38; + pub const Subclass: u64 = ArraySubclass | BasicObjectSubclass | FalseClassSubclass | FloatSubclass | HashSubclass | IntegerSubclass | NilClassSubclass | ObjectSubclass | RangeSubclass | SetSubclass | StringSubclass | SymbolSubclass | TrueClassSubclass; pub const Symbol: u64 = SymbolExact | SymbolSubclass; pub const SymbolExact: u64 = DynamicSymbol | StaticSymbol; - pub const SymbolSubclass: u64 = 1u64 << 37; + pub const SymbolSubclass: u64 = 1u64 << 39; pub const TrueClass: u64 = TrueClassExact | TrueClassSubclass; - pub const TrueClassExact: u64 = 1u64 << 38; - pub const TrueClassSubclass: u64 = 1u64 << 39; - pub const Undef: u64 = 1u64 << 40; - pub const AllBitPatterns: [(&'static str, u64); 67] = [ + pub const TrueClassExact: u64 = 1u64 << 40; + pub const TrueClassSubclass: u64 = 1u64 << 41; + pub const Undef: u64 = 1u64 << 42; + pub const AllBitPatterns: [(&'static str, u64); 70] = [ ("Any", Any), ("RubyValue", RubyValue), ("Immediate", Immediate), @@ -87,6 +90,9 @@ mod bits { ("StringExact", StringExact), ("SymbolExact", SymbolExact), ("StaticSymbol", StaticSymbol), + ("Set", Set), + ("SetSubclass", SetSubclass), + ("SetExact", SetExact), ("Range", Range), ("RangeSubclass", RangeSubclass), ("RangeExact", RangeExact), @@ -136,7 +142,7 @@ mod bits { ("ArrayExact", ArrayExact), ("Empty", Empty), ]; - pub const NumTypeBits: u64 = 41; + pub const NumTypeBits: u64 = 43; } pub mod types { use super::*; @@ -195,6 +201,9 @@ pub mod types { pub const RangeExact: Type = Type::from_bits(bits::RangeExact); pub const RangeSubclass: Type = Type::from_bits(bits::RangeSubclass); pub const RubyValue: Type = Type::from_bits(bits::RubyValue); + pub const Set: Type = Type::from_bits(bits::Set); + pub const SetExact: Type = Type::from_bits(bits::SetExact); + pub const SetSubclass: Type = Type::from_bits(bits::SetSubclass); pub const StaticSymbol: Type = Type::from_bits(bits::StaticSymbol); pub const String: Type = Type::from_bits(bits::String); pub const StringExact: Type = Type::from_bits(bits::StringExact); diff --git a/zjit/src/hir_type/mod.rs b/zjit/src/hir_type/mod.rs index 784c2f324e..0ad26bdc33 100644 --- a/zjit/src/hir_type/mod.rs +++ b/zjit/src/hir_type/mod.rs @@ -1,6 +1,6 @@ #![allow(non_upper_case_globals)] use crate::cruby::{Qfalse, Qnil, Qtrue, VALUE, RUBY_T_ARRAY, RUBY_T_STRING, RUBY_T_HASH}; -use crate::cruby::{rb_cInteger, rb_cFloat, rb_cArray, rb_cHash, rb_cString, rb_cSymbol, rb_cObject, rb_cTrueClass, rb_cFalseClass, rb_cNilClass, rb_cRange}; +use crate::cruby::{rb_cInteger, rb_cFloat, rb_cArray, rb_cHash, rb_cString, rb_cSymbol, rb_cObject, rb_cTrueClass, rb_cFalseClass, rb_cNilClass, rb_cRange, rb_cSet}; use crate::cruby::ClassRelationship; use crate::cruby::get_class_name; use crate::cruby::rb_mRubyVMFrozenCore; @@ -195,6 +195,9 @@ impl Type { else if is_string_exact(val) { Type { bits: bits::StringExact, spec: Specialization::Object(val) } } + else if val.class_of() == unsafe { rb_cSet } { + Type { bits: bits::SetExact, spec: Specialization::Object(val) } + } else if val.class_of() == unsafe { rb_cObject } { Type { bits: bits::ObjectExact, spec: Specialization::Object(val) } } @@ -394,6 +397,7 @@ impl Type { if self.is_subtype(types::NilClassExact) { return Some(unsafe { rb_cNilClass }); } if self.is_subtype(types::ObjectExact) { return Some(unsafe { rb_cObject }); } if self.is_subtype(types::RangeExact) { return Some(unsafe { rb_cRange }); } + if self.is_subtype(types::SetExact) { return Some(unsafe { rb_cSet }); } if self.is_subtype(types::StringExact) { return Some(unsafe { rb_cString }); } if self.is_subtype(types::SymbolExact) { return Some(unsafe { rb_cSymbol }); } if self.is_subtype(types::TrueClassExact) { return Some(unsafe { rb_cTrueClass }); } @@ -585,6 +589,21 @@ mod tests { assert_eq!(types::Integer.inexact_ruby_class(), None); } + #[test] + fn set() { + assert_subtype(types::SetExact, types::Set); + assert_subtype(types::SetSubclass, types::Set); + } + + #[test] + fn set_has_ruby_class() { + crate::cruby::with_rubyvm(|| { + assert_eq!(types::SetExact.runtime_exact_ruby_class(), Some(unsafe { rb_cSet })); + assert_eq!(types::Set.runtime_exact_ruby_class(), None); + assert_eq!(types::SetSubclass.runtime_exact_ruby_class(), None); + }); + } + #[test] fn display_exact_bits_match() { assert_eq!(format!("{}", Type::fixnum(4)), "Fixnum[4]");