@@ -1986,6 +1986,24 @@ impl Function {
19861986 }
19871987 let getivar = self . push_insn ( block, Insn :: GetIvar { self_val : recv, id, state } ) ;
19881988 self . make_equal_to ( insn_id, getivar) ;
1989+ } else if def_type == VM_METHOD_TYPE_ATTRSET && args. len ( ) == 1 {
1990+ self . push_insn ( block, Insn :: PatchPoint { invariant : Invariant :: MethodRedefined { klass, method : mid, cme } , state } ) ;
1991+ if let Some ( profiled_type) = profiled_type {
1992+ recv = self . push_insn ( block, Insn :: GuardType { val : recv, guard_type : Type :: from_profiled_type ( profiled_type) , state } ) ;
1993+ }
1994+ let id = unsafe { get_cme_def_body_attr_id ( cme) } ;
1995+
1996+ // Check if we're accessing ivars of a Class or Module object as they require single-ractor mode.
1997+ // We omit gen_prepare_non_leaf_call on gen_setivar, so it's unsafe to raise for multi-ractor mode.
1998+ if unsafe { rb_zjit_singleton_class_p ( klass) } {
1999+ let attached = unsafe { rb_class_attached_object ( klass) } ;
2000+ if unsafe { RB_TYPE_P ( attached, RUBY_T_CLASS ) || RB_TYPE_P ( attached, RUBY_T_MODULE ) } {
2001+ self . push_insn ( block, Insn :: PatchPoint { invariant : Invariant :: SingleRactorMode , state } ) ;
2002+ }
2003+ }
2004+ let val = args[ 0 ] ;
2005+ let setivar = self . push_insn ( block, Insn :: SetIvar { self_val : recv, id, val, state } ) ;
2006+ self . make_equal_to ( insn_id, setivar) ;
19892007 } else {
19902008 if let Insn :: SendWithoutBlock { def_type : insn_def_type, .. } = & mut self . insns [ insn_id. 0 ] {
19912009 * insn_def_type = Some ( MethodType :: from ( def_type) ) ;
@@ -12133,4 +12151,50 @@ mod opt_tests {
1213312151 Return v25
1213412152 " ) ;
1213512153 }
12154+
12155+ #[ test]
12156+ fn test_inline_attr_accessor_set ( ) {
12157+ eval ( "
12158+ class C
12159+ attr_accessor :foo
12160+ end
12161+
12162+ def test(o) = o.foo = 5
12163+ test C.new
12164+ test C.new
12165+ " ) ;
12166+ assert_snapshot ! ( hir_string( "test" ) , @r"
12167+ fn test@<compiled>:6:
12168+ bb0(v0:BasicObject, v1:BasicObject):
12169+ v6:Fixnum[5] = Const Value(5)
12170+ PatchPoint MethodRedefined(C@0x1000, foo=@0x1008, cme:0x1010)
12171+ v15:HeapObject[class_exact:C] = GuardType v1, HeapObject[class_exact:C]
12172+ SetIvar v15, :@foo, v6
12173+ CheckInterrupts
12174+ Return v6
12175+ " ) ;
12176+ }
12177+
12178+ #[ test]
12179+ fn test_inline_attr_writer_set ( ) {
12180+ eval ( "
12181+ class C
12182+ attr_writer :foo
12183+ end
12184+
12185+ def test(o) = o.foo = 5
12186+ test C.new
12187+ test C.new
12188+ " ) ;
12189+ assert_snapshot ! ( hir_string( "test" ) , @r"
12190+ fn test@<compiled>:6:
12191+ bb0(v0:BasicObject, v1:BasicObject):
12192+ v6:Fixnum[5] = Const Value(5)
12193+ PatchPoint MethodRedefined(C@0x1000, foo=@0x1008, cme:0x1010)
12194+ v15:HeapObject[class_exact:C] = GuardType v1, HeapObject[class_exact:C]
12195+ SetIvar v15, :@foo, v6
12196+ CheckInterrupts
12197+ Return v6
12198+ " ) ;
12199+ }
1213612200}
0 commit comments