@@ -3283,6 +3283,186 @@ def testfunc(n):
32833283 self .assertIn ("_CALL_BUILTIN_FAST_WITH_KEYWORDS" , uops )
32843284 self .assertNotIn ("_GUARD_CALLABLE_BUILTIN_FAST_WITH_KEYWORDS" , uops )
32853285
3286+ def test_call_builtin_o_extra_flags (self ):
3287+ # Extra method flags must not prevent callable guard elimination.
3288+ _testcapi = import_helper .import_module ("_testcapi" )
3289+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3290+
3291+ namespace = {
3292+ "METH_CLASS_O" : _testcapi .MethClass .meth_o ,
3293+ "METH_STATIC_O" : _testcapi .MethStatic .meth_o ,
3294+ "METH_COEXIST_O" : {}.__contains__ ,
3295+ }
3296+
3297+ @reset_code
3298+ def testfunc (n ):
3299+ for _ in range (n ):
3300+ class_result = METH_CLASS_O (1 )
3301+ static_result = METH_STATIC_O (1 )
3302+ coexist_result = METH_COEXIST_O (1 )
3303+ return class_result , static_result , coexist_result
3304+
3305+ testfunc = types .FunctionType (testfunc .__code__ , namespace )
3306+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3307+ self .assertEqual (res , ((_testcapi .MethClass , 1 ), (None , 1 ), False ))
3308+ self .assertIsNotNone (ex )
3309+ uops = get_opnames (ex )
3310+ self .assertEqual (uops .count ("_CALL_BUILTIN_O" ), 3 )
3311+ self .assertNotIn ("_GUARD_CALLABLE_BUILTIN_O" , uops )
3312+
3313+ def test_call_builtin_fast_extra_flags (self ):
3314+ _testcapi = import_helper .import_module ("_testcapi" )
3315+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3316+
3317+ obj = _testcapi .MethInstance ()
3318+ namespace = {
3319+ "METH_CLASS_FASTCALL" : _testcapi .MethClass .meth_fastcall ,
3320+ "METH_STATIC_FASTCALL" : _testcapi .MethStatic .meth_fastcall ,
3321+ "METH_COEXIST_FASTCALL" : obj .meth_fastcall_coexist ,
3322+ }
3323+
3324+ @reset_code
3325+ def testfunc (n ):
3326+ for _ in range (n ):
3327+ class_result = METH_CLASS_FASTCALL (1 , 2 )
3328+ static_result = METH_STATIC_FASTCALL (1 , 2 )
3329+ coexist_result = METH_COEXIST_FASTCALL (1 , 2 )
3330+ return class_result , static_result , coexist_result
3331+
3332+ testfunc = types .FunctionType (testfunc .__code__ , namespace )
3333+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3334+ self .assertEqual (res , (
3335+ (_testcapi .MethClass , (1 , 2 )),
3336+ (None , (1 , 2 )),
3337+ (obj , (1 , 2 )),
3338+ ))
3339+ self .assertIsNotNone (ex )
3340+ uops = get_opnames (ex )
3341+ self .assertEqual (uops .count ("_CALL_BUILTIN_FAST" ), 3 )
3342+ self .assertNotIn ("_GUARD_CALLABLE_BUILTIN_FAST" , uops )
3343+
3344+ def test_call_builtin_fast_with_keywords_extra_flags (self ):
3345+ _testcapi = import_helper .import_module ("_testcapi" )
3346+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3347+
3348+ obj = _testcapi .MethInstance ()
3349+ namespace = {
3350+ "METH_CLASS_FASTCALL_KEYWORDS" : (
3351+ _testcapi .MethClass .meth_fastcall_keywords ),
3352+ "METH_STATIC_FASTCALL_KEYWORDS" : (
3353+ _testcapi .MethStatic .meth_fastcall_keywords ),
3354+ "METH_COEXIST_FASTCALL_KEYWORDS" : (
3355+ obj .meth_fastcall_keywords_coexist ),
3356+ }
3357+
3358+ @reset_code
3359+ def testfunc (n ):
3360+ # Use positional arguments to exercise CALL, not CALL_KW.
3361+ for _ in range (n ):
3362+ class_result = METH_CLASS_FASTCALL_KEYWORDS (1 , 2 )
3363+ static_result = METH_STATIC_FASTCALL_KEYWORDS (1 , 2 )
3364+ coexist_result = METH_COEXIST_FASTCALL_KEYWORDS (1 , 2 )
3365+ return class_result , static_result , coexist_result
3366+
3367+ testfunc = types .FunctionType (testfunc .__code__ , namespace )
3368+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3369+ self .assertEqual (res , (
3370+ (_testcapi .MethClass , (1 , 2 ), {}),
3371+ (None , (1 , 2 ), {}),
3372+ (obj , (1 , 2 ), {}),
3373+ ))
3374+ self .assertIsNotNone (ex )
3375+ uops = get_opnames (ex )
3376+ self .assertEqual (uops .count ("_CALL_BUILTIN_FAST_WITH_KEYWORDS" ), 3 )
3377+ self .assertNotIn ("_GUARD_CALLABLE_BUILTIN_FAST_WITH_KEYWORDS" , uops )
3378+
3379+ def test_call_method_descriptor_o_extra_flags (self ):
3380+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3381+
3382+ @reset_code
3383+ def testfunc (n ):
3384+ d = {1 : None }
3385+ for _ in range (n ):
3386+ result = d .__contains__ (1 )
3387+ return result
3388+
3389+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3390+ self .assertIs (res , True )
3391+ self .assertIsNotNone (ex )
3392+ uops = get_opnames (ex )
3393+ self .assertEqual (uops .count ("_CALL_METHOD_DESCRIPTOR_O_INLINE" ), 1 )
3394+ self .assertNotIn ("_GUARD_CALLABLE_METHOD_DESCRIPTOR_O" , uops )
3395+
3396+ def test_call_method_descriptor_noargs_extra_flags (self ):
3397+ _testcapi = import_helper .import_module ("_testcapi" )
3398+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3399+
3400+ namespace = {
3401+ "METH_COEXIST_NOARGS_OBJECT" : _testcapi .DocStringNoSignatureTest (),
3402+ }
3403+
3404+ @reset_code
3405+ def testfunc (n ):
3406+ for _ in range (n ):
3407+ result = METH_COEXIST_NOARGS_OBJECT .meth_noargs_coexist ()
3408+ return result
3409+
3410+ testfunc = types .FunctionType (testfunc .__code__ , namespace )
3411+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3412+ self .assertIsNone (res )
3413+ self .assertIsNotNone (ex )
3414+ uops = get_opnames (ex )
3415+ self .assertEqual (
3416+ uops .count ("_CALL_METHOD_DESCRIPTOR_NOARGS_INLINE" ), 1 )
3417+ self .assertNotIn ("_GUARD_CALLABLE_METHOD_DESCRIPTOR_NOARGS" , uops )
3418+
3419+ def test_call_method_descriptor_fast_extra_flags (self ):
3420+ _testcapi = import_helper .import_module ("_testcapi" )
3421+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3422+
3423+ obj = _testcapi .MethInstance ()
3424+ namespace = {"METH_COEXIST_FAST_OBJECT" : obj }
3425+
3426+ @reset_code
3427+ def testfunc (n ):
3428+ for _ in range (n ):
3429+ result = METH_COEXIST_FAST_OBJECT .meth_fastcall_coexist (1 , 2 )
3430+ return result
3431+
3432+ testfunc = types .FunctionType (testfunc .__code__ , namespace )
3433+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3434+ self .assertEqual (res , (obj , (1 , 2 )))
3435+ self .assertIsNotNone (ex )
3436+ uops = get_opnames (ex )
3437+ self .assertEqual (uops .count ("_CALL_METHOD_DESCRIPTOR_FAST_INLINE" ), 1 )
3438+ self .assertNotIn ("_GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST" , uops )
3439+
3440+ def test_call_method_descriptor_fast_with_keywords_extra_flags (self ):
3441+ _testcapi = import_helper .import_module ("_testcapi" )
3442+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3443+
3444+ obj = _testcapi .MethInstance ()
3445+ namespace = {"METH_COEXIST_FAST_OBJECT" : obj }
3446+
3447+ @reset_code
3448+ def testfunc (n ):
3449+ # Use positional arguments to exercise CALL, not CALL_KW.
3450+ for _ in range (n ):
3451+ result = (
3452+ METH_COEXIST_FAST_OBJECT .meth_fastcall_keywords_coexist (
3453+ 1 , 2 ))
3454+ return result
3455+
3456+ testfunc = types .FunctionType (testfunc .__code__ , namespace )
3457+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3458+ self .assertEqual (res , (obj , (1 , 2 ), {}))
3459+ self .assertIsNotNone (ex )
3460+ uops = get_opnames (ex )
3461+ self .assertEqual (
3462+ uops .count ("_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_INLINE" ), 1 )
3463+ self .assertNotIn (
3464+ "_GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS" , uops )
3465+
32863466 def test_call_method_descriptor_o (self ):
32873467 def testfunc (n ):
32883468 x = 0
0 commit comments