@@ -3483,6 +3483,39 @@ mod hir_opt_tests {
34833483 " ) ;
34843484 }
34853485
3486+ #[ test]
3487+ fn test_dont_specialize_complex_shape_definedivar ( ) {
3488+ eval ( r#"
3489+ class C
3490+ def test = defined?(@a)
3491+ end
3492+ obj = C.new
3493+ (0..1000).each do |i|
3494+ obj.instance_variable_set(:"@v#{i}", i)
3495+ end
3496+ (0..1000).each do |i|
3497+ obj.remove_instance_variable(:"@v#{i}")
3498+ end
3499+ obj.test
3500+ TEST = C.instance_method(:test)
3501+ "# ) ;
3502+ assert_snapshot ! ( hir_string_proc( "TEST" ) , @r"
3503+ fn test@<compiled>:3:
3504+ bb0():
3505+ EntryPoint interpreter
3506+ v1:BasicObject = LoadSelf
3507+ Jump bb2(v1)
3508+ bb1(v4:BasicObject):
3509+ EntryPoint JIT(0)
3510+ Jump bb2(v4)
3511+ bb2(v6:BasicObject):
3512+ IncrCounter definedivar_fallback_too_complex
3513+ v10:StringExact|NilClass = DefinedIvar v6, :@a
3514+ CheckInterrupts
3515+ Return v10
3516+ " ) ;
3517+ }
3518+
34863519 #[ test]
34873520 fn test_specialize_monomorphic_setivar_already_in_shape ( ) {
34883521 eval ( "
@@ -3512,7 +3545,7 @@ mod hir_opt_tests {
35123545 }
35133546
35143547 #[ test]
3515- fn test_dont_specialize_monomorphic_setivar_with_shape_transition ( ) {
3548+ fn test_specialize_monomorphic_setivar_with_shape_transition ( ) {
35163549 eval ( "
35173550 def test = @foo = 5
35183551 test
@@ -3529,13 +3562,57 @@ mod hir_opt_tests {
35293562 bb2(v6:BasicObject):
35303563 v10:Fixnum[5] = Const Value(5)
35313564 PatchPoint SingleRactorMode
3532- IncrCounter setivar_fallback_shape_transition
3533- SetIvar v6, :@foo, v10
3565+ v19:HeapBasicObject = GuardType v6, HeapBasicObject
3566+ v20:HeapBasicObject = GuardShape v19, 0x1000
3567+ StoreField v20, :@foo@0x1001, v10
3568+ WriteBarrier v20, v10
3569+ v23:CUInt32[4194311] = Const CUInt32(4194311)
3570+ StoreField v20, :_shape_id@0x1002, v23
35343571 CheckInterrupts
35353572 Return v10
35363573 " ) ;
35373574 }
35383575
3576+ #[ test]
3577+ fn test_specialize_multiple_monomorphic_setivar_with_shape_transition ( ) {
3578+ eval ( "
3579+ def test
3580+ @foo = 1
3581+ @bar = 2
3582+ end
3583+ test
3584+ " ) ;
3585+ assert_snapshot ! ( hir_string( "test" ) , @r"
3586+ fn test@<compiled>:3:
3587+ bb0():
3588+ EntryPoint interpreter
3589+ v1:BasicObject = LoadSelf
3590+ Jump bb2(v1)
3591+ bb1(v4:BasicObject):
3592+ EntryPoint JIT(0)
3593+ Jump bb2(v4)
3594+ bb2(v6:BasicObject):
3595+ v10:Fixnum[1] = Const Value(1)
3596+ PatchPoint SingleRactorMode
3597+ v25:HeapBasicObject = GuardType v6, HeapBasicObject
3598+ v26:HeapBasicObject = GuardShape v25, 0x1000
3599+ StoreField v26, :@foo@0x1001, v10
3600+ WriteBarrier v26, v10
3601+ v29:CUInt32[4194311] = Const CUInt32(4194311)
3602+ StoreField v26, :_shape_id@0x1002, v29
3603+ v16:Fixnum[2] = Const Value(2)
3604+ PatchPoint SingleRactorMode
3605+ v31:HeapBasicObject = GuardType v6, HeapBasicObject
3606+ v32:HeapBasicObject = GuardShape v31, 0x1003
3607+ StoreField v32, :@bar@0x1004, v16
3608+ WriteBarrier v32, v16
3609+ v35:CUInt32[4194312] = Const CUInt32(4194312)
3610+ StoreField v32, :_shape_id@0x1002, v35
3611+ CheckInterrupts
3612+ Return v16
3613+ " ) ;
3614+ }
3615+
35393616 #[ test]
35403617 fn test_dont_specialize_setivar_with_t_data ( ) {
35413618 eval ( "
@@ -3610,6 +3687,9 @@ mod hir_opt_tests {
36103687 (0..1000).each do |i|
36113688 obj.instance_variable_set(:"@v#{i}", i)
36123689 end
3690+ (0..1000).each do |i|
3691+ obj.remove_instance_variable(:"@v#{i}")
3692+ end
36133693 obj.test
36143694 TEST = C.instance_method(:test)
36153695 "# ) ;
@@ -3625,7 +3705,7 @@ mod hir_opt_tests {
36253705 bb2(v6:BasicObject):
36263706 v10:Fixnum[5] = Const Value(5)
36273707 PatchPoint SingleRactorMode
3628- IncrCounter setivar_fallback_shape_transition
3708+ IncrCounter setivar_fallback_too_complex
36293709 SetIvar v6, :@a, v10
36303710 CheckInterrupts
36313711 Return v10
@@ -5416,6 +5496,43 @@ mod hir_opt_tests {
54165496 " ) ;
54175497 }
54185498
5499+ #[ test]
5500+ fn test_dont_optimize_getivar_with_too_complex_shape ( ) {
5501+ eval ( r#"
5502+ class C
5503+ attr_accessor :foo
5504+ end
5505+ obj = C.new
5506+ (0..1000).each do |i|
5507+ obj.instance_variable_set(:"@v#{i}", i)
5508+ end
5509+ (0..1000).each do |i|
5510+ obj.remove_instance_variable(:"@v#{i}")
5511+ end
5512+ def test(o) = o.foo
5513+ test obj
5514+ "# ) ;
5515+ assert_snapshot ! ( hir_string( "test" ) , @r"
5516+ fn test@<compiled>:12:
5517+ bb0():
5518+ EntryPoint interpreter
5519+ v1:BasicObject = LoadSelf
5520+ v2:BasicObject = GetLocal l0, SP@4
5521+ Jump bb2(v1, v2)
5522+ bb1(v5:BasicObject, v6:BasicObject):
5523+ EntryPoint JIT(0)
5524+ Jump bb2(v5, v6)
5525+ bb2(v8:BasicObject, v9:BasicObject):
5526+ PatchPoint MethodRedefined(C@0x1000, foo@0x1008, cme:0x1010)
5527+ PatchPoint NoSingletonClass(C@0x1000)
5528+ v21:HeapObject[class_exact:C] = GuardType v9, HeapObject[class_exact:C]
5529+ IncrCounter getivar_fallback_too_complex
5530+ v22:BasicObject = GetIvar v21, :@foo
5531+ CheckInterrupts
5532+ Return v22
5533+ " ) ;
5534+ }
5535+
54195536 #[ test]
54205537 fn test_optimize_send_with_block ( ) {
54215538 eval ( r#"
@@ -5696,8 +5813,11 @@ mod hir_opt_tests {
56965813 v16:Fixnum[5] = Const Value(5)
56975814 PatchPoint MethodRedefined(C@0x1000, foo=@0x1008, cme:0x1010)
56985815 v26:HeapObject[class_exact:C] = GuardType v9, HeapObject[class_exact:C]
5699- IncrCounter setivar_fallback_shape_transition
5700- SetIvar v26, :@foo, v16
5816+ v29:HeapObject[class_exact:C] = GuardShape v26, 0x1038
5817+ StoreField v29, :@foo@0x1039, v16
5818+ WriteBarrier v29, v16
5819+ v32:CUInt32[4194311] = Const CUInt32(4194311)
5820+ StoreField v29, :_shape_id@0x103a, v32
57015821 CheckInterrupts
57025822 Return v16
57035823 " ) ;
@@ -5728,8 +5848,11 @@ mod hir_opt_tests {
57285848 v16:Fixnum[5] = Const Value(5)
57295849 PatchPoint MethodRedefined(C@0x1000, foo=@0x1008, cme:0x1010)
57305850 v26:HeapObject[class_exact:C] = GuardType v9, HeapObject[class_exact:C]
5731- IncrCounter setivar_fallback_shape_transition
5732- SetIvar v26, :@foo, v16
5851+ v29:HeapObject[class_exact:C] = GuardShape v26, 0x1038
5852+ StoreField v29, :@foo@0x1039, v16
5853+ WriteBarrier v29, v16
5854+ v32:CUInt32[4194311] = Const CUInt32(4194311)
5855+ StoreField v29, :_shape_id@0x103a, v32
57335856 CheckInterrupts
57345857 Return v16
57355858 " ) ;
@@ -9026,18 +9149,22 @@ mod hir_opt_tests {
90269149 SetLocal l0, EP@3, v27
90279150 v39:BasicObject = GetLocal l0, EP@3
90289151 PatchPoint SingleRactorMode
9029- IncrCounter setivar_fallback_shape_transition
9030- SetIvar v14, :@formatted, v39
9031- v45:Class[VMFrozenCore] = Const Value(VALUE(0x1000))
9032- PatchPoint MethodRedefined(Class@0x1008, lambda@0x1010, cme:0x1018)
9033- PatchPoint NoSingletonClass(Class@0x1008)
9034- v60:BasicObject = CCallWithFrame v45, :RubyVM::FrozenCore.lambda@0x1040, block=0x1048
9152+ v56:HeapBasicObject = GuardType v14, HeapBasicObject
9153+ v57:HeapBasicObject = GuardShape v56, 0x1000
9154+ StoreField v57, :@formatted@0x1001, v39
9155+ WriteBarrier v57, v39
9156+ v60:CUInt32[4194311] = Const CUInt32(4194311)
9157+ StoreField v57, :_shape_id@0x1002, v60
9158+ v45:Class[VMFrozenCore] = Const Value(VALUE(0x1008))
9159+ PatchPoint MethodRedefined(Class@0x1010, lambda@0x1018, cme:0x1020)
9160+ PatchPoint NoSingletonClass(Class@0x1010)
9161+ v65:BasicObject = CCallWithFrame v45, :RubyVM::FrozenCore.lambda@0x1048, block=0x1050
90359162 v48:BasicObject = GetLocal l0, EP@6
90369163 v49:BasicObject = GetLocal l0, EP@5
90379164 v50:BasicObject = GetLocal l0, EP@4
90389165 v51:BasicObject = GetLocal l0, EP@3
90399166 CheckInterrupts
9040- Return v60
9167+ Return v65
90419168 " ) ;
90429169 }
90439170}
0 commit comments