diff options
| -rw-r--r-- | test/ruby/test_zjit.rb | 79 | ||||
| -rw-r--r-- | zjit/src/hir.rs | 56 |
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 |
