@@ -3349,6 +3349,186 @@ def testfunc(n):
33493349 self .assertIn ("_CALL_BUILTIN_FAST_WITH_KEYWORDS" , uops )
33503350 self .assertNotIn ("_GUARD_CALLABLE_BUILTIN_FAST_WITH_KEYWORDS" , uops )
33513351
3352+ def test_call_builtin_o_extra_flags (self ):
3353+ # Extra method flags must not prevent callable guard elimination.
3354+ _testcapi = import_helper .import_module ("_testcapi" )
3355+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3356+
3357+ namespace = {
3358+ "METH_CLASS_O" : _testcapi .MethClass .meth_o ,
3359+ "METH_STATIC_O" : _testcapi .MethStatic .meth_o ,
3360+ "METH_COEXIST_O" : {}.__contains__ ,
3361+ }
3362+
3363+ @reset_code
3364+ def testfunc (n ):
3365+ for _ in range (n ):
3366+ class_result = METH_CLASS_O (1 )
3367+ static_result = METH_STATIC_O (1 )
3368+ coexist_result = METH_COEXIST_O (1 )
3369+ return class_result , static_result , coexist_result
3370+
3371+ testfunc = types .FunctionType (testfunc .__code__ , namespace )
3372+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3373+ self .assertEqual (res , ((_testcapi .MethClass , 1 ), (None , 1 ), False ))
3374+ self .assertIsNotNone (ex )
3375+ uops = get_opnames (ex )
3376+ self .assertEqual (uops .count ("_CALL_BUILTIN_O" ), 3 )
3377+ self .assertNotIn ("_GUARD_CALLABLE_BUILTIN_O" , uops )
3378+
3379+ def test_call_builtin_fast_extra_flags (self ):
3380+ _testcapi = import_helper .import_module ("_testcapi" )
3381+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3382+
3383+ obj = _testcapi .MethInstance ()
3384+ namespace = {
3385+ "METH_CLASS_FASTCALL" : _testcapi .MethClass .meth_fastcall ,
3386+ "METH_STATIC_FASTCALL" : _testcapi .MethStatic .meth_fastcall ,
3387+ "METH_COEXIST_FASTCALL" : obj .meth_fastcall_coexist ,
3388+ }
3389+
3390+ @reset_code
3391+ def testfunc (n ):
3392+ for _ in range (n ):
3393+ class_result = METH_CLASS_FASTCALL (1 , 2 )
3394+ static_result = METH_STATIC_FASTCALL (1 , 2 )
3395+ coexist_result = METH_COEXIST_FASTCALL (1 , 2 )
3396+ return class_result , static_result , coexist_result
3397+
3398+ testfunc = types .FunctionType (testfunc .__code__ , namespace )
3399+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3400+ self .assertEqual (res , (
3401+ (_testcapi .MethClass , (1 , 2 )),
3402+ (None , (1 , 2 )),
3403+ (obj , (1 , 2 )),
3404+ ))
3405+ self .assertIsNotNone (ex )
3406+ uops = get_opnames (ex )
3407+ self .assertEqual (uops .count ("_CALL_BUILTIN_FAST" ), 3 )
3408+ self .assertNotIn ("_GUARD_CALLABLE_BUILTIN_FAST" , uops )
3409+
3410+ def test_call_builtin_fast_with_keywords_extra_flags (self ):
3411+ _testcapi = import_helper .import_module ("_testcapi" )
3412+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3413+
3414+ obj = _testcapi .MethInstance ()
3415+ namespace = {
3416+ "METH_CLASS_FASTCALL_KEYWORDS" : (
3417+ _testcapi .MethClass .meth_fastcall_keywords ),
3418+ "METH_STATIC_FASTCALL_KEYWORDS" : (
3419+ _testcapi .MethStatic .meth_fastcall_keywords ),
3420+ "METH_COEXIST_FASTCALL_KEYWORDS" : (
3421+ obj .meth_fastcall_keywords_coexist ),
3422+ }
3423+
3424+ @reset_code
3425+ def testfunc (n ):
3426+ # Use positional arguments to exercise CALL, not CALL_KW.
3427+ for _ in range (n ):
3428+ class_result = METH_CLASS_FASTCALL_KEYWORDS (1 , 2 )
3429+ static_result = METH_STATIC_FASTCALL_KEYWORDS (1 , 2 )
3430+ coexist_result = METH_COEXIST_FASTCALL_KEYWORDS (1 , 2 )
3431+ return class_result , static_result , coexist_result
3432+
3433+ testfunc = types .FunctionType (testfunc .__code__ , namespace )
3434+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3435+ self .assertEqual (res , (
3436+ (_testcapi .MethClass , (1 , 2 ), {}),
3437+ (None , (1 , 2 ), {}),
3438+ (obj , (1 , 2 ), {}),
3439+ ))
3440+ self .assertIsNotNone (ex )
3441+ uops = get_opnames (ex )
3442+ self .assertEqual (uops .count ("_CALL_BUILTIN_FAST_WITH_KEYWORDS" ), 3 )
3443+ self .assertNotIn ("_GUARD_CALLABLE_BUILTIN_FAST_WITH_KEYWORDS" , uops )
3444+
3445+ def test_call_method_descriptor_o_extra_flags (self ):
3446+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3447+
3448+ @reset_code
3449+ def testfunc (n ):
3450+ d = {1 : None }
3451+ for _ in range (n ):
3452+ result = d .__contains__ (1 )
3453+ return result
3454+
3455+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3456+ self .assertIs (res , True )
3457+ self .assertIsNotNone (ex )
3458+ uops = get_opnames (ex )
3459+ self .assertEqual (uops .count ("_CALL_METHOD_DESCRIPTOR_O_INLINE" ), 1 )
3460+ self .assertNotIn ("_GUARD_CALLABLE_METHOD_DESCRIPTOR_O" , uops )
3461+
3462+ def test_call_method_descriptor_noargs_extra_flags (self ):
3463+ _testcapi = import_helper .import_module ("_testcapi" )
3464+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3465+
3466+ namespace = {
3467+ "METH_COEXIST_NOARGS_OBJECT" : _testcapi .DocStringNoSignatureTest (),
3468+ }
3469+
3470+ @reset_code
3471+ def testfunc (n ):
3472+ for _ in range (n ):
3473+ result = METH_COEXIST_NOARGS_OBJECT .meth_noargs_coexist ()
3474+ return result
3475+
3476+ testfunc = types .FunctionType (testfunc .__code__ , namespace )
3477+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3478+ self .assertIsNone (res )
3479+ self .assertIsNotNone (ex )
3480+ uops = get_opnames (ex )
3481+ self .assertEqual (
3482+ uops .count ("_CALL_METHOD_DESCRIPTOR_NOARGS_INLINE" ), 1 )
3483+ self .assertNotIn ("_GUARD_CALLABLE_METHOD_DESCRIPTOR_NOARGS" , uops )
3484+
3485+ def test_call_method_descriptor_fast_extra_flags (self ):
3486+ _testcapi = import_helper .import_module ("_testcapi" )
3487+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3488+
3489+ obj = _testcapi .MethInstance ()
3490+ namespace = {"METH_COEXIST_FAST_OBJECT" : obj }
3491+
3492+ @reset_code
3493+ def testfunc (n ):
3494+ for _ in range (n ):
3495+ result = METH_COEXIST_FAST_OBJECT .meth_fastcall_coexist (1 , 2 )
3496+ return result
3497+
3498+ testfunc = types .FunctionType (testfunc .__code__ , namespace )
3499+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3500+ self .assertEqual (res , (obj , (1 , 2 )))
3501+ self .assertIsNotNone (ex )
3502+ uops = get_opnames (ex )
3503+ self .assertEqual (uops .count ("_CALL_METHOD_DESCRIPTOR_FAST_INLINE" ), 1 )
3504+ self .assertNotIn ("_GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST" , uops )
3505+
3506+ def test_call_method_descriptor_fast_with_keywords_extra_flags (self ):
3507+ _testcapi = import_helper .import_module ("_testcapi" )
3508+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3509+
3510+ obj = _testcapi .MethInstance ()
3511+ namespace = {"METH_COEXIST_FAST_OBJECT" : obj }
3512+
3513+ @reset_code
3514+ def testfunc (n ):
3515+ # Use positional arguments to exercise CALL, not CALL_KW.
3516+ for _ in range (n ):
3517+ result = (
3518+ METH_COEXIST_FAST_OBJECT .meth_fastcall_keywords_coexist (
3519+ 1 , 2 ))
3520+ return result
3521+
3522+ testfunc = types .FunctionType (testfunc .__code__ , namespace )
3523+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3524+ self .assertEqual (res , (obj , (1 , 2 ), {}))
3525+ self .assertIsNotNone (ex )
3526+ uops = get_opnames (ex )
3527+ self .assertEqual (
3528+ uops .count ("_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_INLINE" ), 1 )
3529+ self .assertNotIn (
3530+ "_GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS" , uops )
3531+
33523532 def test_call_method_descriptor_o (self ):
33533533 def testfunc (n ):
33543534 x = 0
0 commit comments