@@ -1535,22 +1535,28 @@ impl Function {
15351535 // It allows you to use a faster ISEQ if possible.
15361536 cme = unsafe { rb_check_overloaded_cme ( cme, ci) } ;
15371537 let def_type = unsafe { get_cme_def_type ( cme) } ;
1538- if def_type ! = VM_METHOD_TYPE_ISEQ {
1538+ if def_type = = VM_METHOD_TYPE_ISEQ {
15391539 // TODO(max): Allow non-iseq; cache cme
1540+ // Only specialize positional-positional calls
1541+ // TODO(max): Handle other kinds of parameter passing
1542+ let iseq = unsafe { get_def_iseq_ptr ( ( * cme) . def ) } ;
1543+ if !can_direct_send ( iseq) {
1544+ self . push_insn_id ( block, insn_id) ; continue ;
1545+ }
1546+ self . push_insn ( block, Insn :: PatchPoint { invariant : Invariant :: MethodRedefined { klass, method : mid, cme } , state } ) ;
1547+ if let Some ( expected) = guard_equal_to {
1548+ self_val = self . push_insn ( block, Insn :: GuardBitEquals { val : self_val, expected, state } ) ;
1549+ }
1550+ let send_direct = self . push_insn ( block, Insn :: SendWithoutBlockDirect { self_val, call_info, cd, cme, iseq, args, state } ) ;
1551+ self . make_equal_to ( insn_id, send_direct) ;
1552+ } else if def_type == VM_METHOD_TYPE_IVAR && args. is_empty ( ) {
1553+ self . push_insn ( block, Insn :: PatchPoint { invariant : Invariant :: MethodRedefined { klass, method : mid, cme } , state } ) ;
1554+ let id = unsafe { get_cme_def_body_attr_id ( cme) } ;
1555+ let getivar = self . push_insn ( block, Insn :: GetIvar { self_val, id, state } ) ;
1556+ self . make_equal_to ( insn_id, getivar) ;
1557+ } else {
15401558 self . push_insn_id ( block, insn_id) ; continue ;
15411559 }
1542- // Only specialize positional-positional calls
1543- // TODO(max): Handle other kinds of parameter passing
1544- let iseq = unsafe { get_def_iseq_ptr ( ( * cme) . def ) } ;
1545- if !can_direct_send ( iseq) {
1546- self . push_insn_id ( block, insn_id) ; continue ;
1547- }
1548- self . push_insn ( block, Insn :: PatchPoint { invariant : Invariant :: MethodRedefined { klass, method : mid, cme } , state } ) ;
1549- if let Some ( expected) = guard_equal_to {
1550- self_val = self . push_insn ( block, Insn :: GuardBitEquals { val : self_val, expected, state } ) ;
1551- }
1552- let send_direct = self . push_insn ( block, Insn :: SendWithoutBlockDirect { self_val, call_info, cd, cme, iseq, args, state } ) ;
1553- self . make_equal_to ( insn_id, send_direct) ;
15541560 }
15551561 Insn :: GetConstantPath { ic, state, .. } => {
15561562 let idlist: * const ID = unsafe { ( * ic) . segments } ;
@@ -7371,4 +7377,60 @@ mod opt_tests {
73717377 Return v7
73727378 "# ] ] ) ;
73737379 }
7380+
7381+ #[ test]
7382+ fn test_inline_attr_reader ( ) {
7383+ eval ( "
7384+ class C
7385+ attr_reader :foo
7386+
7387+ def initialize
7388+ @foo = 4
7389+ end
7390+ end
7391+
7392+ O = C.new
7393+ def test = O.foo
7394+ test
7395+ test
7396+ " ) ;
7397+ assert_optimized_method_hir ( "test" , expect ! [ [ r#"
7398+ fn test@<compiled>:11:
7399+ bb0(v0:BasicObject):
7400+ PatchPoint SingleRactorMode
7401+ PatchPoint StableConstantNames(0x1000, O)
7402+ v9:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
7403+ PatchPoint MethodRedefined(C@0x1010, foo@0x1018, cme:0x1020)
7404+ v11:BasicObject = GetIvar v9, :@foo
7405+ Return v11
7406+ "# ] ] ) ;
7407+ }
7408+
7409+ #[ test]
7410+ fn test_inline_attr_accessor ( ) {
7411+ eval ( "
7412+ class C
7413+ attr_accessor :foo
7414+
7415+ def initialize
7416+ @foo = 4
7417+ end
7418+ end
7419+
7420+ O = C.new
7421+ def test = O.foo
7422+ test
7423+ test
7424+ " ) ;
7425+ assert_optimized_method_hir ( "test" , expect ! [ [ r#"
7426+ fn test@<compiled>:11:
7427+ bb0(v0:BasicObject):
7428+ PatchPoint SingleRactorMode
7429+ PatchPoint StableConstantNames(0x1000, O)
7430+ v9:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
7431+ PatchPoint MethodRedefined(C@0x1010, foo@0x1018, cme:0x1020)
7432+ v11:BasicObject = GetIvar v9, :@foo
7433+ Return v11
7434+ "# ] ] ) ;
7435+ }
73747436}
0 commit comments