Skip to content

Commit 4484374

Browse files
committed
fixup! gh-157833: Fix specialized C calls with additional method flags
1 parent 5bc4896 commit 4484374

1 file changed

Lines changed: 49 additions & 31 deletions

File tree

‎Lib/test/test_capi/test_opt.py‎

Lines changed: 49 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@
1818

1919
from _testinternalcapi import _PY_NSMALLPOSINTS, TIER2_THRESHOLD, TIER2_RESUME_THRESHOLD
2020

21-
try:
22-
import _testcapi
23-
except ImportError:
24-
_testcapi = None
25-
2621
#For test of issue 136154
2722
GLOBAL_136154 = 42
2823

@@ -37,22 +32,6 @@ class _GenericKey:
3732

3833
_GENERIC_KEY = _GenericKey()
3934

40-
# Keep these callables in globals so the optimizer can resolve their values.
41-
# They have METH_CLASS, METH_STATIC, or METH_COEXIST flags.
42-
if _testcapi is not None:
43-
METH_CLASS_O = _testcapi.MethClass.meth_o
44-
METH_STATIC_O = _testcapi.MethStatic.meth_o
45-
METH_CLASS_FASTCALL = _testcapi.MethClass.meth_fastcall
46-
METH_STATIC_FASTCALL = _testcapi.MethStatic.meth_fastcall
47-
METH_CLASS_FASTCALL_KEYWORDS = _testcapi.MethClass.meth_fastcall_keywords
48-
METH_STATIC_FASTCALL_KEYWORDS = _testcapi.MethStatic.meth_fastcall_keywords
49-
METH_COEXIST_NOARGS_OBJECT = _testcapi.DocStringNoSignatureTest()
50-
METH_COEXIST_FAST_OBJECT = _testcapi.MethInstance()
51-
METH_COEXIST_FASTCALL = METH_COEXIST_FAST_OBJECT.meth_fastcall_coexist
52-
METH_COEXIST_FASTCALL_KEYWORDS = (
53-
METH_COEXIST_FAST_OBJECT.meth_fastcall_keywords_coexist)
54-
METH_COEXIST_O = {}.__contains__
55-
5635

5736
@contextlib.contextmanager
5837
def clear_executors(func):
@@ -3328,11 +3307,17 @@ def testfunc(n):
33283307
self.assertIn("_CALL_BUILTIN_FAST_WITH_KEYWORDS", uops)
33293308
self.assertNotIn("_GUARD_CALLABLE_BUILTIN_FAST_WITH_KEYWORDS", uops)
33303309

3331-
@unittest.skipIf(_testcapi is None, "requires _testcapi")
33323310
def test_call_builtin_o_extra_flags(self):
33333311
# Extra method flags must not prevent callable guard elimination.
3312+
_testcapi = import_helper.import_module("_testcapi")
33343313
self.addCleanup(_testinternalcapi.clear_executor_deletion_list)
33353314

3315+
namespace = {
3316+
"METH_CLASS_O": _testcapi.MethClass.meth_o,
3317+
"METH_STATIC_O": _testcapi.MethStatic.meth_o,
3318+
"METH_COEXIST_O": {}.__contains__,
3319+
}
3320+
33363321
@reset_code
33373322
def testfunc(n):
33383323
for _ in range(n):
@@ -3341,17 +3326,25 @@ def testfunc(n):
33413326
coexist_result = METH_COEXIST_O(1)
33423327
return class_result, static_result, coexist_result
33433328

3329+
testfunc = types.FunctionType(testfunc.__code__, namespace)
33443330
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
33453331
self.assertEqual(res, ((_testcapi.MethClass, 1), (None, 1), False))
33463332
self.assertIsNotNone(ex)
33473333
uops = get_opnames(ex)
33483334
self.assertEqual(uops.count("_CALL_BUILTIN_O"), 3)
33493335
self.assertNotIn("_GUARD_CALLABLE_BUILTIN_O", uops)
33503336

3351-
@unittest.skipIf(_testcapi is None, "requires _testcapi")
33523337
def test_call_builtin_fast_extra_flags(self):
3338+
_testcapi = import_helper.import_module("_testcapi")
33533339
self.addCleanup(_testinternalcapi.clear_executor_deletion_list)
33543340

3341+
obj = _testcapi.MethInstance()
3342+
namespace = {
3343+
"METH_CLASS_FASTCALL": _testcapi.MethClass.meth_fastcall,
3344+
"METH_STATIC_FASTCALL": _testcapi.MethStatic.meth_fastcall,
3345+
"METH_COEXIST_FASTCALL": obj.meth_fastcall_coexist,
3346+
}
3347+
33553348
@reset_code
33563349
def testfunc(n):
33573350
for _ in range(n):
@@ -3360,21 +3353,32 @@ def testfunc(n):
33603353
coexist_result = METH_COEXIST_FASTCALL(1, 2)
33613354
return class_result, static_result, coexist_result
33623355

3356+
testfunc = types.FunctionType(testfunc.__code__, namespace)
33633357
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
33643358
self.assertEqual(res, (
33653359
(_testcapi.MethClass, (1, 2)),
33663360
(None, (1, 2)),
3367-
(METH_COEXIST_FAST_OBJECT, (1, 2)),
3361+
(obj, (1, 2)),
33683362
))
33693363
self.assertIsNotNone(ex)
33703364
uops = get_opnames(ex)
33713365
self.assertEqual(uops.count("_CALL_BUILTIN_FAST"), 3)
33723366
self.assertNotIn("_GUARD_CALLABLE_BUILTIN_FAST", uops)
33733367

3374-
@unittest.skipIf(_testcapi is None, "requires _testcapi")
33753368
def test_call_builtin_fast_with_keywords_extra_flags(self):
3369+
_testcapi = import_helper.import_module("_testcapi")
33763370
self.addCleanup(_testinternalcapi.clear_executor_deletion_list)
33773371

3372+
obj = _testcapi.MethInstance()
3373+
namespace = {
3374+
"METH_CLASS_FASTCALL_KEYWORDS": (
3375+
_testcapi.MethClass.meth_fastcall_keywords),
3376+
"METH_STATIC_FASTCALL_KEYWORDS": (
3377+
_testcapi.MethStatic.meth_fastcall_keywords),
3378+
"METH_COEXIST_FASTCALL_KEYWORDS": (
3379+
obj.meth_fastcall_keywords_coexist),
3380+
}
3381+
33783382
@reset_code
33793383
def testfunc(n):
33803384
# Use positional arguments to exercise CALL, not CALL_KW.
@@ -3384,11 +3388,12 @@ def testfunc(n):
33843388
coexist_result = METH_COEXIST_FASTCALL_KEYWORDS(1, 2)
33853389
return class_result, static_result, coexist_result
33863390

3391+
testfunc = types.FunctionType(testfunc.__code__, namespace)
33873392
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
33883393
self.assertEqual(res, (
33893394
(_testcapi.MethClass, (1, 2), {}),
33903395
(None, (1, 2), {}),
3391-
(METH_COEXIST_FAST_OBJECT, (1, 2), {}),
3396+
(obj, (1, 2), {}),
33923397
))
33933398
self.assertIsNotNone(ex)
33943399
uops = get_opnames(ex)
@@ -3412,16 +3417,21 @@ def testfunc(n):
34123417
self.assertEqual(uops.count("_CALL_METHOD_DESCRIPTOR_O_INLINE"), 1)
34133418
self.assertNotIn("_GUARD_CALLABLE_METHOD_DESCRIPTOR_O", uops)
34143419

3415-
@unittest.skipIf(_testcapi is None, "requires _testcapi")
34163420
def test_call_method_descriptor_noargs_extra_flags(self):
3421+
_testcapi = import_helper.import_module("_testcapi")
34173422
self.addCleanup(_testinternalcapi.clear_executor_deletion_list)
34183423

3424+
namespace = {
3425+
"METH_COEXIST_NOARGS_OBJECT": _testcapi.DocStringNoSignatureTest(),
3426+
}
3427+
34193428
@reset_code
34203429
def testfunc(n):
34213430
for _ in range(n):
34223431
result = METH_COEXIST_NOARGS_OBJECT.meth_noargs_coexist()
34233432
return result
34243433

3434+
testfunc = types.FunctionType(testfunc.__code__, namespace)
34253435
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
34263436
self.assertIsNone(res)
34273437
self.assertIsNotNone(ex)
@@ -3430,27 +3440,34 @@ def testfunc(n):
34303440
uops.count("_CALL_METHOD_DESCRIPTOR_NOARGS_INLINE"), 1)
34313441
self.assertNotIn("_GUARD_CALLABLE_METHOD_DESCRIPTOR_NOARGS", uops)
34323442

3433-
@unittest.skipIf(_testcapi is None, "requires _testcapi")
34343443
def test_call_method_descriptor_fast_extra_flags(self):
3444+
_testcapi = import_helper.import_module("_testcapi")
34353445
self.addCleanup(_testinternalcapi.clear_executor_deletion_list)
34363446

3447+
obj = _testcapi.MethInstance()
3448+
namespace = {"METH_COEXIST_FAST_OBJECT": obj}
3449+
34373450
@reset_code
34383451
def testfunc(n):
34393452
for _ in range(n):
34403453
result = METH_COEXIST_FAST_OBJECT.meth_fastcall_coexist(1, 2)
34413454
return result
34423455

3456+
testfunc = types.FunctionType(testfunc.__code__, namespace)
34433457
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
3444-
self.assertEqual(res, (METH_COEXIST_FAST_OBJECT, (1, 2)))
3458+
self.assertEqual(res, (obj, (1, 2)))
34453459
self.assertIsNotNone(ex)
34463460
uops = get_opnames(ex)
34473461
self.assertEqual(uops.count("_CALL_METHOD_DESCRIPTOR_FAST_INLINE"), 1)
34483462
self.assertNotIn("_GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST", uops)
34493463

3450-
@unittest.skipIf(_testcapi is None, "requires _testcapi")
34513464
def test_call_method_descriptor_fast_with_keywords_extra_flags(self):
3465+
_testcapi = import_helper.import_module("_testcapi")
34523466
self.addCleanup(_testinternalcapi.clear_executor_deletion_list)
34533467

3468+
obj = _testcapi.MethInstance()
3469+
namespace = {"METH_COEXIST_FAST_OBJECT": obj}
3470+
34543471
@reset_code
34553472
def testfunc(n):
34563473
# Use positional arguments to exercise CALL, not CALL_KW.
@@ -3460,8 +3477,9 @@ def testfunc(n):
34603477
1, 2))
34613478
return result
34623479

3480+
testfunc = types.FunctionType(testfunc.__code__, namespace)
34633481
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
3464-
self.assertEqual(res, (METH_COEXIST_FAST_OBJECT, (1, 2), {}))
3482+
self.assertEqual(res, (obj, (1, 2), {}))
34653483
self.assertIsNotNone(ex)
34663484
uops = get_opnames(ex)
34673485
self.assertEqual(

0 commit comments

Comments
 (0)