Skip to content

Commit 4839739

Browse files
committed
ZJIT: Support inference of ModuleExact type
1 parent f5acefc commit 4839739

5 files changed

Lines changed: 73 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
@@ -5921,7 +5921,7 @@ mod opt_tests {
59215921
}
59225922

59235923
#[test]
5924-
fn module_instances_not_class_exact() {
5924+
fn module_instances_are_module_exact() {
59255925
eval("
59265926
def test = [Enumerable, Kernel]
59275927
test # Warm the constant cache
@@ -5931,15 +5931,33 @@ mod opt_tests {
59315931
bb0(v0:BasicObject):
59325932
PatchPoint SingleRactorMode
59335933
PatchPoint StableConstantNames(0x1000, Enumerable)
5934-
v11:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
5934+
v11:ModuleExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
59355935
PatchPoint SingleRactorMode
59365936
PatchPoint StableConstantNames(0x1010, Kernel)
5937-
v14:BasicObject[VALUE(0x1018)] = Const Value(VALUE(0x1018))
5937+
v14:ModuleExact[VALUE(0x1018)] = Const Value(VALUE(0x1018))
59385938
v7:ArrayExact = NewArray v11, v14
59395939
Return v7
59405940
"#]]);
59415941
}
59425942

5943+
#[test]
5944+
fn module_subclasses_are_not_module_exact() {
5945+
eval("
5946+
class ModuleSubclass < Module; end
5947+
MY_MODULE = ModuleSubclass.new
5948+
def test = MY_MODULE
5949+
test # Warm the constant cache
5950+
");
5951+
assert_optimized_method_hir("test", expect![[r#"
5952+
fn test:
5953+
bb0(v0:BasicObject):
5954+
PatchPoint SingleRactorMode
5955+
PatchPoint StableConstantNames(0x1000, MY_MODULE)
5956+
v7:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
5957+
Return v7
5958+
"#]]);
5959+
}
5960+
59435961
#[test]
59445962
fn eliminate_array_size() {
59455963
eval("
@@ -6067,7 +6085,7 @@ mod opt_tests {
60676085
bb0(v0:BasicObject):
60686086
PatchPoint SingleRactorMode
60696087
PatchPoint StableConstantNames(0x1000, Kernel)
6070-
v7:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
6088+
v7:ModuleExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
60716089
Return v7
60726090
"#]]);
60736091
}

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: 18 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,16 @@ 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+
// For Class and Module instances, `class_of` will return the singleton class of the object.
155+
// Using `rb_obj_class` will give us the actual class of the module so we can check if the
156+
// object is an instance of Module, or an instance of Module subclass.
157+
let klass = unsafe { rb_obj_class(val) };
158+
klass == unsafe { rb_cModule }
151159
}
152160

153161
impl Type {
@@ -202,7 +210,10 @@ impl Type {
202210
else if is_string_exact(val) {
203211
Type { bits: bits::StringExact, spec: Specialization::Object(val) }
204212
}
205-
else if is_class_exact(val) {
213+
else if is_module_exact(val) {
214+
Type { bits: bits::ModuleExact, spec: Specialization::Object(val) }
215+
}
216+
else if val.builtin_type() == RUBY_T_CLASS {
206217
Type { bits: bits::ClassExact, spec: Specialization::Object(val) }
207218
}
208219
else if val.class_of() == unsafe { rb_cRegexp } {
@@ -301,6 +312,7 @@ impl Type {
301312
if class == unsafe { rb_cFloat } { return true; }
302313
if class == unsafe { rb_cHash } { return true; }
303314
if class == unsafe { rb_cInteger } { return true; }
315+
if class == unsafe { rb_cModule } { return true; }
304316
if class == unsafe { rb_cNilClass } { return true; }
305317
if class == unsafe { rb_cObject } { return true; }
306318
if class == unsafe { rb_cRange } { return true; }
@@ -410,6 +422,7 @@ impl Type {
410422
if self.is_subtype(types::FloatExact) { return Some(unsafe { rb_cFloat }); }
411423
if self.is_subtype(types::HashExact) { return Some(unsafe { rb_cHash }); }
412424
if self.is_subtype(types::IntegerExact) { return Some(unsafe { rb_cInteger }); }
425+
if self.is_subtype(types::ModuleExact) { return Some(unsafe { rb_cModule }); }
413426
if self.is_subtype(types::NilClassExact) { return Some(unsafe { rb_cNilClass }); }
414427
if self.is_subtype(types::ObjectExact) { return Some(unsafe { rb_cObject }); }
415428
if self.is_subtype(types::RangeExact) { return Some(unsafe { rb_cRange }); }

0 commit comments

Comments
 (0)