@@ -3315,6 +3315,186 @@ def testfunc(n):
33153315 self .assertIn ("_CALL_BUILTIN_FAST_WITH_KEYWORDS" , uops )
33163316 self .assertNotIn ("_GUARD_CALLABLE_BUILTIN_FAST_WITH_KEYWORDS" , uops )
33173317
3318+ def test_call_builtin_o_extra_flags (self ):
3319+ # Extra method flags must not prevent callable guard elimination.
3320+ _testcapi = import_helper .import_module ("_testcapi" )
3321+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3322+
3323+ namespace = {
3324+ "METH_CLASS_O" : _testcapi .MethClass .meth_o ,
3325+ "METH_STATIC_O" : _testcapi .MethStatic .meth_o ,
3326+ "METH_COEXIST_O" : {}.__contains__ ,
3327+ }
3328+
3329+ @reset_code
3330+ def testfunc (n ):
3331+ for _ in range (n ):
3332+ class_result = METH_CLASS_O (1 )
3333+ static_result = METH_STATIC_O (1 )
3334+ coexist_result = METH_COEXIST_O (1 )
3335+ return class_result , static_result , coexist_result
3336+
3337+ testfunc = types .FunctionType (testfunc .__code__ , namespace )
3338+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3339+ self .assertEqual (res , ((_testcapi .MethClass , 1 ), (None , 1 ), False ))
3340+ self .assertIsNotNone (ex )
3341+ uops = get_opnames (ex )
3342+ self .assertEqual (uops .count ("_CALL_BUILTIN_O" ), 3 )
3343+ self .assertNotIn ("_GUARD_CALLABLE_BUILTIN_O" , uops )
3344+
3345+ def test_call_builtin_fast_extra_flags (self ):
3346+ _testcapi = import_helper .import_module ("_testcapi" )
3347+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3348+
3349+ obj = _testcapi .MethInstance ()
3350+ namespace = {
3351+ "METH_CLASS_FASTCALL" : _testcapi .MethClass .meth_fastcall ,
3352+ "METH_STATIC_FASTCALL" : _testcapi .MethStatic .meth_fastcall ,
3353+ "METH_COEXIST_FASTCALL" : obj .meth_fastcall_coexist ,
3354+ }
3355+
3356+ @reset_code
3357+ def testfunc (n ):
3358+ for _ in range (n ):
3359+ class_result = METH_CLASS_FASTCALL (1 , 2 )
3360+ static_result = METH_STATIC_FASTCALL (1 , 2 )
3361+ coexist_result = METH_COEXIST_FASTCALL (1 , 2 )
3362+ return class_result , static_result , coexist_result
3363+
3364+ testfunc = types .FunctionType (testfunc .__code__ , namespace )
3365+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3366+ self .assertEqual (res , (
3367+ (_testcapi .MethClass , (1 , 2 )),
3368+ (None , (1 , 2 )),
3369+ (obj , (1 , 2 )),
3370+ ))
3371+ self .assertIsNotNone (ex )
3372+ uops = get_opnames (ex )
3373+ self .assertEqual (uops .count ("_CALL_BUILTIN_FAST" ), 3 )
3374+ self .assertNotIn ("_GUARD_CALLABLE_BUILTIN_FAST" , uops )
3375+
3376+ def test_call_builtin_fast_with_keywords_extra_flags (self ):
3377+ _testcapi = import_helper .import_module ("_testcapi" )
3378+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3379+
3380+ obj = _testcapi .MethInstance ()
3381+ namespace = {
3382+ "METH_CLASS_FASTCALL_KEYWORDS" : (
3383+ _testcapi .MethClass .meth_fastcall_keywords ),
3384+ "METH_STATIC_FASTCALL_KEYWORDS" : (
3385+ _testcapi .MethStatic .meth_fastcall_keywords ),
3386+ "METH_COEXIST_FASTCALL_KEYWORDS" : (
3387+ obj .meth_fastcall_keywords_coexist ),
3388+ }
3389+
3390+ @reset_code
3391+ def testfunc (n ):
3392+ # Use positional arguments to exercise CALL, not CALL_KW.
3393+ for _ in range (n ):
3394+ class_result = METH_CLASS_FASTCALL_KEYWORDS (1 , 2 )
3395+ static_result = METH_STATIC_FASTCALL_KEYWORDS (1 , 2 )
3396+ coexist_result = METH_COEXIST_FASTCALL_KEYWORDS (1 , 2 )
3397+ return class_result , static_result , coexist_result
3398+
3399+ testfunc = types .FunctionType (testfunc .__code__ , namespace )
3400+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3401+ self .assertEqual (res , (
3402+ (_testcapi .MethClass , (1 , 2 ), {}),
3403+ (None , (1 , 2 ), {}),
3404+ (obj , (1 , 2 ), {}),
3405+ ))
3406+ self .assertIsNotNone (ex )
3407+ uops = get_opnames (ex )
3408+ self .assertEqual (uops .count ("_CALL_BUILTIN_FAST_WITH_KEYWORDS" ), 3 )
3409+ self .assertNotIn ("_GUARD_CALLABLE_BUILTIN_FAST_WITH_KEYWORDS" , uops )
3410+
3411+ def test_call_method_descriptor_o_extra_flags (self ):
3412+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3413+
3414+ @reset_code
3415+ def testfunc (n ):
3416+ d = {1 : None }
3417+ for _ in range (n ):
3418+ result = d .__contains__ (1 )
3419+ return result
3420+
3421+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3422+ self .assertIs (res , True )
3423+ self .assertIsNotNone (ex )
3424+ uops = get_opnames (ex )
3425+ self .assertEqual (uops .count ("_CALL_METHOD_DESCRIPTOR_O_INLINE" ), 1 )
3426+ self .assertNotIn ("_GUARD_CALLABLE_METHOD_DESCRIPTOR_O" , uops )
3427+
3428+ def test_call_method_descriptor_noargs_extra_flags (self ):
3429+ _testcapi = import_helper .import_module ("_testcapi" )
3430+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3431+
3432+ namespace = {
3433+ "METH_COEXIST_NOARGS_OBJECT" : _testcapi .DocStringNoSignatureTest (),
3434+ }
3435+
3436+ @reset_code
3437+ def testfunc (n ):
3438+ for _ in range (n ):
3439+ result = METH_COEXIST_NOARGS_OBJECT .meth_noargs_coexist ()
3440+ return result
3441+
3442+ testfunc = types .FunctionType (testfunc .__code__ , namespace )
3443+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3444+ self .assertIsNone (res )
3445+ self .assertIsNotNone (ex )
3446+ uops = get_opnames (ex )
3447+ self .assertEqual (
3448+ uops .count ("_CALL_METHOD_DESCRIPTOR_NOARGS_INLINE" ), 1 )
3449+ self .assertNotIn ("_GUARD_CALLABLE_METHOD_DESCRIPTOR_NOARGS" , uops )
3450+
3451+ def test_call_method_descriptor_fast_extra_flags (self ):
3452+ _testcapi = import_helper .import_module ("_testcapi" )
3453+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3454+
3455+ obj = _testcapi .MethInstance ()
3456+ namespace = {"METH_COEXIST_FAST_OBJECT" : obj }
3457+
3458+ @reset_code
3459+ def testfunc (n ):
3460+ for _ in range (n ):
3461+ result = METH_COEXIST_FAST_OBJECT .meth_fastcall_coexist (1 , 2 )
3462+ return result
3463+
3464+ testfunc = types .FunctionType (testfunc .__code__ , namespace )
3465+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3466+ self .assertEqual (res , (obj , (1 , 2 )))
3467+ self .assertIsNotNone (ex )
3468+ uops = get_opnames (ex )
3469+ self .assertEqual (uops .count ("_CALL_METHOD_DESCRIPTOR_FAST_INLINE" ), 1 )
3470+ self .assertNotIn ("_GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST" , uops )
3471+
3472+ def test_call_method_descriptor_fast_with_keywords_extra_flags (self ):
3473+ _testcapi = import_helper .import_module ("_testcapi" )
3474+ self .addCleanup (_testinternalcapi .clear_executor_deletion_list )
3475+
3476+ obj = _testcapi .MethInstance ()
3477+ namespace = {"METH_COEXIST_FAST_OBJECT" : obj }
3478+
3479+ @reset_code
3480+ def testfunc (n ):
3481+ # Use positional arguments to exercise CALL, not CALL_KW.
3482+ for _ in range (n ):
3483+ result = (
3484+ METH_COEXIST_FAST_OBJECT .meth_fastcall_keywords_coexist (
3485+ 1 , 2 ))
3486+ return result
3487+
3488+ testfunc = types .FunctionType (testfunc .__code__ , namespace )
3489+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3490+ self .assertEqual (res , (obj , (1 , 2 ), {}))
3491+ self .assertIsNotNone (ex )
3492+ uops = get_opnames (ex )
3493+ self .assertEqual (
3494+ uops .count ("_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_INLINE" ), 1 )
3495+ self .assertNotIn (
3496+ "_GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS" , uops )
3497+
33183498 def test_call_method_descriptor_o (self ):
33193499 def testfunc (n ):
33203500 x = 0
0 commit comments