Skip to content

Commit f469a12

Browse files
committed
ZJIT: Support inference of ModuleExact type
1 parent 350df4f commit f469a12

5 files changed

Lines changed: 70 additions & 31 deletions

File tree

zjit/src/cruby.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ unsafe extern "C" {
158158
pub fn rb_vm_ic_hit_p(ic: IC, reg_ep: *const VALUE) -> bool;
159159
pub fn rb_vm_stack_canary() -> VALUE;
160160
pub fn rb_vm_push_cfunc_frame(cme: *const rb_callable_method_entry_t, recv_idx: c_int);
161+
pub fn rb_obj_class(klass: VALUE) -> VALUE;
161162
}
162163

163164
// Renames

zjit/src/hir.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5797,7 +5797,7 @@ mod opt_tests {
57975797
}
57985798

57995799
#[test]
5800-
fn module_instances_not_class_exact() {
5800+
fn module_instances_are_module_exact() {
58015801
eval("
58025802
def test = [Enumerable, Kernel]
58035803
test # Warm the constant cache
@@ -5807,15 +5807,33 @@ mod opt_tests {
58075807
bb0(v0:BasicObject):
58085808
PatchPoint SingleRactorMode
58095809
PatchPoint StableConstantNames(0x1000, Enumerable)
5810-
v11:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
5810+
v11:ModuleExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
58115811
PatchPoint SingleRactorMode
58125812
PatchPoint StableConstantNames(0x1010, Kernel)
5813-
v14:BasicObject[VALUE(0x1018)] = Const Value(VALUE(0x1018))
5813+
v14:ModuleExact[VALUE(0x1018)] = Const Value(VALUE(0x1018))
58145814
v7:ArrayExact = NewArray v11, v14
58155815
Return v7
58165816
"#]]);
58175817
}
58185818

5819+
#[test]
5820+
fn module_subclasses_are_not_module_exact() {
5821+
eval("
5822+
class ModuleSubclass < Module; end
5823+
MY_MODULE = ModuleSubclass.new
5824+
def test = MY_MODULE
5825+
test # Warm the constant cache
5826+
");
5827+
assert_optimized_method_hir("test", expect![[r#"
5828+
fn test:
5829+
bb0(v0:BasicObject):
5830+
PatchPoint SingleRactorMode
5831+
PatchPoint StableConstantNames(0x1000, MY_MODULE)
5832+
v7:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
5833+
Return v7
5834+
"#]]);
5835+
}
5836+
58195837
#[test]
58205838
fn eliminate_array_size() {
58215839
eval("
@@ -5943,7 +5961,7 @@ mod opt_tests {
59435961
bb0(v0:BasicObject):
59445962
PatchPoint SingleRactorMode
59455963
PatchPoint StableConstantNames(0x1000, Kernel)
5946-
v7:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
5964+
v7:ModuleExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
59475965
Return v7
59485966
"#]]);
59495967
}

zjit/src/hir_type/gen_hir_type.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ def base_type name
7575
base_type "Set"
7676
base_type "Regexp"
7777
base_type "Class"
78+
base_type "Module"
7879

7980
(integer, integer_exact) = base_type "Integer"
8081
# CRuby partitions Integer into immediate and non-immediate variants.

zjit/src/hir_type/hir_type.inc.rs

Lines changed: 31 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

zjit/src/hir_type/mod.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
#![allow(non_upper_case_globals)]
2-
use crate::cruby::{Qfalse, Qnil, Qtrue, VALUE, RUBY_T_ARRAY, RUBY_T_STRING, RUBY_T_HASH, RUBY_T_CLASS};
2+
use crate::cruby::{Qfalse, Qnil, Qtrue, VALUE, RUBY_T_ARRAY, RUBY_T_STRING, RUBY_T_HASH, RUBY_T_CLASS, RUBY_T_MODULE};
33
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, rb_cRegexp, rb_cClass, rb_cModule};
44
use crate::cruby::ClassRelationship;
55
use crate::cruby::get_class_name;
66
use crate::cruby::ruby_sym_to_rust_string;
77
use crate::cruby::rb_mRubyVMFrozenCore;
8+
use crate::cruby::rb_obj_class;
89
use crate::hir::PtrPrintMap;
910

1011
#[derive(Copy, Clone, Debug, PartialEq)]
@@ -145,9 +146,13 @@ fn is_range_exact(val: VALUE) -> bool {
145146
val.class_of() == unsafe { rb_cRange }
146147
}
147148

148-
fn is_class_exact(val: VALUE) -> bool {
149-
// Objects with RUBY_T_CLASS type and not instances of Module
150-
val.builtin_type() == RUBY_T_CLASS && val.class_of() != unsafe { rb_cModule }
149+
fn is_module_exact(val: VALUE) -> bool {
150+
if val.builtin_type() != RUBY_T_MODULE {
151+
return false;
152+
}
153+
154+
let klass = unsafe { rb_obj_class(val) };
155+
klass == unsafe { rb_cModule }
151156
}
152157

153158
impl Type {
@@ -202,7 +207,10 @@ impl Type {
202207
else if is_string_exact(val) {
203208
Type { bits: bits::StringExact, spec: Specialization::Object(val) }
204209
}
205-
else if is_class_exact(val) {
210+
else if is_module_exact(val) {
211+
Type { bits: bits::ModuleExact, spec: Specialization::Object(val) }
212+
}
213+
else if val.builtin_type() == RUBY_T_CLASS {
206214
Type { bits: bits::ClassExact, spec: Specialization::Object(val) }
207215
}
208216
else if val.class_of() == unsafe { rb_cRegexp } {
@@ -301,6 +309,7 @@ impl Type {
301309
if class == unsafe { rb_cFloat } { return true; }
302310
if class == unsafe { rb_cHash } { return true; }
303311
if class == unsafe { rb_cInteger } { return true; }
312+
if class == unsafe { rb_cModule } { return true; }
304313
if class == unsafe { rb_cNilClass } { return true; }
305314
if class == unsafe { rb_cObject } { return true; }
306315
if class == unsafe { rb_cRange } { return true; }
@@ -410,6 +419,7 @@ impl Type {
410419
if self.is_subtype(types::FloatExact) { return Some(unsafe { rb_cFloat }); }
411420
if self.is_subtype(types::HashExact) { return Some(unsafe { rb_cHash }); }
412421
if self.is_subtype(types::IntegerExact) { return Some(unsafe { rb_cInteger }); }
422+
if self.is_subtype(types::ModuleExact) { return Some(unsafe { rb_cModule }); }
413423
if self.is_subtype(types::NilClassExact) { return Some(unsafe { rb_cNilClass }); }
414424
if self.is_subtype(types::ObjectExact) { return Some(unsafe { rb_cObject }); }
415425
if self.is_subtype(types::RangeExact) { return Some(unsafe { rb_cRange }); }

0 commit comments

Comments
 (0)