@@ -2043,6 +2043,23 @@ impl Function {
20432043 }
20442044 let getivar = self . push_insn ( block, Insn :: GetIvar { self_val : recv, id, state } ) ;
20452045 self . make_equal_to ( insn_id, getivar) ;
2046+ } else if let ( VM_METHOD_TYPE_ATTRSET , & [ val] ) = ( def_type, args. as_slice ( ) ) {
2047+ self . push_insn ( block, Insn :: PatchPoint { invariant : Invariant :: MethodRedefined { klass, method : mid, cme } , state } ) ;
2048+ if let Some ( profiled_type) = profiled_type {
2049+ recv = self . push_insn ( block, Insn :: GuardType { val : recv, guard_type : Type :: from_profiled_type ( profiled_type) , state } ) ;
2050+ }
2051+ let id = unsafe { get_cme_def_body_attr_id ( cme) } ;
2052+
2053+ // Check if we're accessing ivars of a Class or Module object as they require single-ractor mode.
2054+ // We omit gen_prepare_non_leaf_call on gen_setivar, so it's unsafe to raise for multi-ractor mode.
2055+ if unsafe { rb_zjit_singleton_class_p ( klass) } {
2056+ let attached = unsafe { rb_class_attached_object ( klass) } ;
2057+ if unsafe { RB_TYPE_P ( attached, RUBY_T_CLASS ) || RB_TYPE_P ( attached, RUBY_T_MODULE ) } {
2058+ self . push_insn ( block, Insn :: PatchPoint { invariant : Invariant :: SingleRactorMode , state } ) ;
2059+ }
2060+ }
2061+ self . push_insn ( block, Insn :: SetIvar { self_val : recv, id, val, state } ) ;
2062+ self . make_equal_to ( insn_id, val) ;
20462063 } else {
20472064 self . set_dynamic_send_reason ( insn_id, SendWithoutBlockNotOptimizedMethodType ( MethodType :: from ( def_type) ) ) ;
20482065 self . push_insn_id ( block, insn_id) ; continue ;
@@ -12190,4 +12207,66 @@ mod opt_tests {
1219012207 Return v25
1219112208 " ) ;
1219212209 }
12210+
12211+ #[ test]
12212+ fn test_inline_attr_accessor_set ( ) {
12213+ eval ( "
12214+ class C
12215+ attr_accessor :foo
12216+ end
12217+
12218+ def test(o) = o.foo = 5
12219+ test C.new
12220+ test C.new
12221+ " ) ;
12222+ assert_snapshot ! ( hir_string( "test" ) , @r"
12223+ fn test@<compiled>:6:
12224+ bb0():
12225+ EntryPoint interpreter
12226+ v1:BasicObject = LoadSelf
12227+ v2:BasicObject = GetLocal l0, SP@4
12228+ Jump bb2(v1, v2)
12229+ bb1(v5:BasicObject, v6:BasicObject):
12230+ EntryPoint JIT(0)
12231+ Jump bb2(v5, v6)
12232+ bb2(v8:BasicObject, v9:BasicObject):
12233+ v14:Fixnum[5] = Const Value(5)
12234+ PatchPoint MethodRedefined(C@0x1000, foo=@0x1008, cme:0x1010)
12235+ v23:HeapObject[class_exact:C] = GuardType v9, HeapObject[class_exact:C]
12236+ SetIvar v23, :@foo, v14
12237+ CheckInterrupts
12238+ Return v14
12239+ " ) ;
12240+ }
12241+
12242+ #[ test]
12243+ fn test_inline_attr_writer_set ( ) {
12244+ eval ( "
12245+ class C
12246+ attr_writer :foo
12247+ end
12248+
12249+ def test(o) = o.foo = 5
12250+ test C.new
12251+ test C.new
12252+ " ) ;
12253+ assert_snapshot ! ( hir_string( "test" ) , @r"
12254+ fn test@<compiled>:6:
12255+ bb0():
12256+ EntryPoint interpreter
12257+ v1:BasicObject = LoadSelf
12258+ v2:BasicObject = GetLocal l0, SP@4
12259+ Jump bb2(v1, v2)
12260+ bb1(v5:BasicObject, v6:BasicObject):
12261+ EntryPoint JIT(0)
12262+ Jump bb2(v5, v6)
12263+ bb2(v8:BasicObject, v9:BasicObject):
12264+ v14:Fixnum[5] = Const Value(5)
12265+ PatchPoint MethodRedefined(C@0x1000, foo=@0x1008, cme:0x1010)
12266+ v23:HeapObject[class_exact:C] = GuardType v9, HeapObject[class_exact:C]
12267+ SetIvar v23, :@foo, v14
12268+ CheckInterrupts
12269+ Return v14
12270+ " ) ;
12271+ }
1219312272}
0 commit comments