summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/ruby/test_zjit.rb79
-rw-r--r--zjit/src/hir.rs56
2 files changed, 120 insertions, 15 deletions
diff --git a/test/ruby/test_zjit.rb b/test/ruby/test_zjit.rb
index 52009d9d0a..692dfb486c 100644
--- a/test/ruby/test_zjit.rb
+++ b/test/ruby/test_zjit.rb
@@ -1919,6 +1919,85 @@ class TestZJIT < Test::Unit::TestCase
}
end
+ def test_ivar_attr_reader_optimization_with_multi_ractor_mode
+ assert_compiles '42', %q{
+ class Foo
+ class << self
+ attr_accessor :bar
+
+ def get_bar
+ bar
+ rescue Ractor::IsolationError
+ 42
+ end
+ end
+ end
+
+ Foo.bar = [] # needs to be a ractor unshareable object
+
+ def test
+ Foo.get_bar
+ end
+
+ test
+ test
+
+ Ractor.new { test }.value
+ }, call_threshold: 2
+ end
+
+ def test_ivar_get_with_multi_ractor_mode
+ assert_compiles '42', %q{
+ class Foo
+ def self.set_bar
+ @bar = [] # needs to be a ractor unshareable object
+ end
+
+ def self.bar
+ @bar
+ rescue Ractor::IsolationError
+ 42
+ end
+ end
+
+ Foo.set_bar
+
+ def test
+ Foo.bar
+ end
+
+ test
+ test
+
+ Ractor.new { test }.value
+ }
+ end
+
+ def test_ivar_set_with_multi_ractor_mode
+ assert_compiles '42', %q{
+ class Foo
+ def self.bar
+ _foo = 1
+ _bar = 2
+ begin
+ @bar = _foo + _bar
+ rescue Ractor::IsolationError
+ 42
+ end
+ end
+ end
+
+ def test
+ Foo.bar
+ end
+
+ test
+ test
+
+ Ractor.new { test }.value
+ }
+ end
+
private
# Assert that every method call in `test_script` can be compiled by ZJIT
diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs
index d1f5a3af84..ee90032ee8 100644
--- a/zjit/src/hir.rs
+++ b/zjit/src/hir.rs
@@ -1671,6 +1671,15 @@ impl Function {
self_val = self.push_insn(block, Insn::GuardType { val: self_val, guard_type: Type::from_profiled_type(profiled_type), state });
}
let id = unsafe { get_cme_def_body_attr_id(cme) };
+
+ // Check if we're accessing ivars of a Class or Module object as they require single-ractor mode.
+ // We omit gen_prepare_non_leaf_call on gen_getivar, so it's unsafe to raise for multi-ractor mode.
+ if unsafe { rb_zjit_singleton_class_p(klass) } {
+ let attached = unsafe { rb_class_attached_object(klass) };
+ if unsafe { RB_TYPE_P(attached, RUBY_T_CLASS) || RB_TYPE_P(attached, RUBY_T_MODULE) } {
+ self.push_insn(block, Insn::PatchPoint { invariant: Invariant::SingleRactorMode, state });
+ }
+ }
let getivar = self.push_insn(block, Insn::GetIvar { self_val, id, state });
self.make_equal_to(insn_id, getivar);
} else {
@@ -3332,6 +3341,9 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let id = ID(get_arg(pc, 0).as_u64());
// ic is in arg 1
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
+ // Assume single-Ractor mode to omit gen_prepare_non_leaf_call on gen_getivar
+ // TODO: We only really need this if self_val is a class/module
+ fun.push_insn(block, Insn::PatchPoint { invariant: Invariant::SingleRactorMode, state: exit_id });
let result = fun.push_insn(block, Insn::GetIvar { self_val: self_param, id, state: exit_id });
state.stack_push(result);
}
@@ -3339,6 +3351,9 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let id = ID(get_arg(pc, 0).as_u64());
// ic is in arg 1
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
+ // Assume single-Ractor mode to omit gen_prepare_non_leaf_call on gen_setivar
+ // TODO: We only really need this if self_val is a class/module
+ fun.push_insn(block, Insn::PatchPoint { invariant: Invariant::SingleRactorMode, state: exit_id });
let val = state.stack_pop()?;
fun.push_insn(block, Insn::SetIvar { self_val: self_param, id, val, state: exit_id });
}
@@ -5053,9 +5068,10 @@ mod tests {
assert_snapshot!(hir_string("test"), @r"
fn test@<compiled>:2:
bb0(v0:BasicObject):
- v3:BasicObject = GetIvar v0, :@foo
+ PatchPoint SingleRactorMode
+ v4:BasicObject = GetIvar v0, :@foo
CheckInterrupts
- Return v3
+ Return v4
");
}
@@ -5070,6 +5086,7 @@ mod tests {
fn test@<compiled>:2:
bb0(v0:BasicObject):
v2:Fixnum[1] = Const Value(1)
+ PatchPoint SingleRactorMode
SetIvar v0, :@foo, v2
CheckInterrupts
Return v2
@@ -5345,12 +5362,15 @@ mod tests {
v1:NilClass = Const Value(nil)
v2:NilClass = Const Value(nil)
v3:NilClass = Const Value(nil)
- v6:BasicObject = GetIvar v0, :@a
- v8:BasicObject = GetIvar v0, :@b
- v10:BasicObject = GetIvar v0, :@c
- v12:ArrayExact = NewArray v6, v8, v10
+ PatchPoint SingleRactorMode
+ v7:BasicObject = GetIvar v0, :@a
+ PatchPoint SingleRactorMode
+ v10:BasicObject = GetIvar v0, :@b
+ PatchPoint SingleRactorMode
+ v13:BasicObject = GetIvar v0, :@c
+ v15:ArrayExact = NewArray v7, v10, v13
CheckInterrupts
- Return v12
+ Return v15
");
assert_contains_opcode("reverse_even", YARVINSN_opt_reverse);
assert_snapshot!(hir_string("reverse_even"), @r"
@@ -5360,13 +5380,17 @@ mod tests {
v2:NilClass = Const Value(nil)
v3:NilClass = Const Value(nil)
v4:NilClass = Const Value(nil)
- v7:BasicObject = GetIvar v0, :@a
- v9:BasicObject = GetIvar v0, :@b
- v11:BasicObject = GetIvar v0, :@c
- v13:BasicObject = GetIvar v0, :@d
- v15:ArrayExact = NewArray v7, v9, v11, v13
+ PatchPoint SingleRactorMode
+ v8:BasicObject = GetIvar v0, :@a
+ PatchPoint SingleRactorMode
+ v11:BasicObject = GetIvar v0, :@b
+ PatchPoint SingleRactorMode
+ v14:BasicObject = GetIvar v0, :@c
+ PatchPoint SingleRactorMode
+ v17:BasicObject = GetIvar v0, :@d
+ v19:ArrayExact = NewArray v8, v11, v14, v17
CheckInterrupts
- Return v15
+ Return v19
");
}
@@ -7454,9 +7478,10 @@ mod opt_tests {
assert_snapshot!(hir_string("test"), @r"
fn test@<compiled>:2:
bb0(v0:BasicObject):
- v3:BasicObject = GetIvar v0, :@foo
+ PatchPoint SingleRactorMode
+ v4:BasicObject = GetIvar v0, :@foo
CheckInterrupts
- Return v3
+ Return v4
");
}
@@ -7469,6 +7494,7 @@ mod opt_tests {
fn test@<compiled>:2:
bb0(v0:BasicObject):
v2:Fixnum[1] = Const Value(1)
+ PatchPoint SingleRactorMode
SetIvar v0, :@foo, v2
CheckInterrupts
Return v2