Skip to content

Commit 43c54d4

Browse files
committed
refactor tests
1 parent 5d3090a commit 43c54d4

1 file changed

Lines changed: 60 additions & 183 deletions

File tree

Lib/test/test_capi/test_opt.py

Lines changed: 60 additions & 183 deletions
Original file line numberDiff line numberDiff line change
@@ -4885,155 +4885,83 @@ class A:
48854885
uops = get_opnames(ex)
48864886
self.assertNotIn("_REPLACE_WITH_TRUE", uops)
48874887

4888-
def test_to_bool_kwargs_dict(self):
4889-
"""**kwargs is known to be dict, so TO_BOOL specializes to _TO_BOOL_SIZED."""
4890-
def inner(**kwargs):
4888+
def test_to_bool_static_type(self):
4889+
# *args is tuple and **kwargs is dict in tier2, so TO_BOOL on those
4890+
# locals specializes to _TO_BOOL_SIZED without a runtime guard.
4891+
# `va_kw_regular` also covers the non-zero slot-offset case.
4892+
def kw(**kwargs):
48914893
cnt = 0
4892-
for i in range(TIER2_THRESHOLD):
4894+
for _ in range(TIER2_THRESHOLD):
48934895
if kwargs:
48944896
cnt += 1
48954897
return cnt
48964898

4897-
def f(n):
4898-
return inner(a=1, b=2)
4899-
4900-
res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
4901-
self.assertEqual(res, TIER2_THRESHOLD)
4902-
ex_inner = get_first_executor(inner)
4903-
self.assertIsNotNone(ex_inner)
4904-
uops = get_opnames(ex_inner)
4905-
self.assertIn("_TO_BOOL_SIZED", uops)
4906-
self.assertNotIn("_TO_BOOL", uops)
4907-
4908-
def test_to_bool_kwargs_empty_dict(self):
4909-
"""**kwargs is known to be dict even when empty."""
4910-
def inner(**kwargs):
4899+
def va(*args):
49114900
cnt = 0
4912-
for i in range(TIER2_THRESHOLD):
4913-
if not kwargs:
4914-
cnt += 1
4915-
return cnt
4916-
4917-
def f(n):
4918-
return inner()
4919-
4920-
res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
4921-
self.assertEqual(res, TIER2_THRESHOLD)
4922-
ex_inner = get_first_executor(inner)
4923-
self.assertIsNotNone(ex_inner)
4924-
uops = get_opnames(ex_inner)
4925-
self.assertIn("_TO_BOOL_SIZED", uops)
4926-
self.assertNotIn("_TO_BOOL", uops)
4927-
4928-
def test_to_bool_varargs_tuple(self):
4929-
"""*args is known to be tuple, so TO_BOOL specializes to _TO_BOOL_SIZED."""
4930-
def inner(*args):
4931-
cnt = 0
4932-
for i in range(TIER2_THRESHOLD):
4901+
for _ in range(TIER2_THRESHOLD):
49334902
if args:
49344903
cnt += 1
49354904
return cnt
49364905

4937-
def f(n):
4938-
return inner(1, 2, 3)
4939-
4940-
res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
4941-
self.assertEqual(res, TIER2_THRESHOLD)
4942-
ex_inner = get_first_executor(inner)
4943-
self.assertIsNotNone(ex_inner)
4944-
uops = get_opnames(ex_inner)
4945-
self.assertIn("_TO_BOOL_SIZED", uops)
4946-
self.assertNotIn("_TO_BOOL", uops)
4947-
4948-
def test_to_bool_varargs_empty_tuple(self):
4949-
"""*args is known to be tuple even when empty."""
4950-
def inner(*args):
4906+
def va_kw_regular(x, y, *args, key=None, **kwargs):
49514907
cnt = 0
4952-
for i in range(TIER2_THRESHOLD):
4953-
if not args:
4954-
cnt += 1
4955-
return cnt
4956-
4957-
def f(n):
4958-
return inner()
4959-
4960-
res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
4961-
self.assertEqual(res, TIER2_THRESHOLD)
4962-
ex_inner = get_first_executor(inner)
4963-
self.assertIsNotNone(ex_inner)
4964-
uops = get_opnames(ex_inner)
4965-
self.assertIn("_TO_BOOL_SIZED", uops)
4966-
self.assertNotIn("_TO_BOOL", uops)
4967-
4968-
def test_to_bool_args_and_kwargs(self):
4969-
"""Combined *args and **kwargs both get correct types."""
4970-
def inner(*args, **kwargs):
4971-
cnt = 0
4972-
for i in range(TIER2_THRESHOLD):
4973-
if args and kwargs:
4974-
cnt += 1
4975-
return cnt
4976-
4977-
def f(n):
4978-
return inner(1, 2, a=3)
4979-
4980-
res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
4981-
self.assertEqual(res, TIER2_THRESHOLD)
4982-
ex_inner = get_first_executor(inner)
4983-
self.assertIsNotNone(ex_inner)
4984-
uops = get_opnames(ex_inner)
4985-
# Both the tuple (args) and dict (kwargs) TO_BOOLs specialize to _TO_BOOL_SIZED.
4986-
self.assertGreaterEqual(count_ops(ex_inner, "_TO_BOOL_SIZED"), 2)
4987-
self.assertNotIn("_TO_BOOL", uops)
4988-
4989-
def test_to_bool_args_kwargs_with_regular_params(self):
4990-
"""*args/**kwargs slot calculation is correct with regular params."""
4991-
def inner(x, y, *args, key=None, **kwargs):
4992-
cnt = 0
4993-
for i in range(TIER2_THRESHOLD):
4908+
for _ in range(TIER2_THRESHOLD):
49944909
if args and kwargs:
49954910
cnt += 1
49964911
return cnt
49974912

4998-
def f(n):
4999-
return inner(1, 2, 3, 4, key="v", extra=5)
5000-
5001-
res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
5002-
self.assertEqual(res, TIER2_THRESHOLD)
5003-
ex_inner = get_first_executor(inner)
5004-
self.assertIsNotNone(ex_inner)
5005-
uops = get_opnames(ex_inner)
5006-
self.assertGreaterEqual(count_ops(ex_inner, "_TO_BOOL_SIZED"), 2)
5007-
self.assertNotIn("_TO_BOOL", uops)
5008-
5009-
def test_to_bool_kwargs_only_no_varargs(self):
5010-
"""**kwargs without *args gets correct dict type."""
5011-
def inner(x, **kwargs):
5012-
cnt = 0
5013-
for i in range(TIER2_THRESHOLD):
5014-
if kwargs:
5015-
cnt += 1
5016-
return cnt
5017-
5018-
def f(n):
5019-
return inner(1, a=2)
5020-
5021-
res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
5022-
self.assertEqual(res, TIER2_THRESHOLD)
5023-
ex_inner = get_first_executor(inner)
5024-
self.assertIsNotNone(ex_inner)
5025-
uops = get_opnames(ex_inner)
5026-
self.assertIn("_TO_BOOL_SIZED", uops)
5027-
self.assertNotIn("_TO_BOOL", uops)
4913+
# (inner, args, kwargs, min _TO_BOOL_SIZED count)
4914+
cases = [
4915+
(kw, (), {"a": 1, "b": 2}, 1),
4916+
(va, (1, 2, 3), {}, 1),
4917+
(va_kw_regular, (1, 2, 3, 4), {"key": "v", "extra": 5}, 2),
4918+
]
4919+
for inner, args, kwargs, expected in cases:
4920+
with self.subTest(case=inner.__name__):
4921+
inner(*args, **kwargs)
4922+
ex_inner = get_first_executor(inner)
4923+
self.assertIsNotNone(ex_inner)
4924+
uops = get_opnames(ex_inner)
4925+
self.assertGreaterEqual(
4926+
count_ops(ex_inner, "_TO_BOOL_SIZED"), expected)
4927+
self.assertNotIn("_TO_BOOL", uops)
4928+
4929+
def test_to_bool_recorded_type(self):
4930+
# A value whose static type is unknown but whose runtime type is
4931+
# recorded gets a `_GUARD_TOS_<TYPE>` followed by _TO_BOOL_SIZED.
4932+
# A fresh `inner` is compiled per case so each gets its own executor.
4933+
src = (
4934+
"def inner(v):\n"
4935+
" cnt = 0\n"
4936+
" for _ in range(T):\n"
4937+
" if v:\n"
4938+
" cnt += 1\n"
4939+
" return cnt\n"
4940+
)
4941+
cases = [
4942+
(b"hello", "_GUARD_TOS_BYTES"),
4943+
(bytearray(b"hello"), "_GUARD_TOS_BYTEARRAY"),
4944+
(frozenset({1, 2, 3}), "_GUARD_TOS_FROZENSET"),
4945+
(frozendict({1: 1, 2: 2}), "_GUARD_TOS_FROZENDICT"),
4946+
]
4947+
for value, guard_op in cases:
4948+
with self.subTest(case=type(value).__name__):
4949+
ns = {"T": TIER2_THRESHOLD}
4950+
exec(src, ns)
4951+
inner = ns["inner"]
4952+
self.assertEqual(inner(value), TIER2_THRESHOLD)
4953+
ex_inner = get_first_executor(inner)
4954+
self.assertIsNotNone(ex_inner)
4955+
uops = get_opnames(ex_inner)
4956+
self.assertIn(guard_op, uops)
4957+
self.assertIn("_TO_BOOL_SIZED", uops)
4958+
self.assertNotIn("_TO_BOOL", uops)
50284959

50294960
def test_to_bool_set_with_dummy_entries(self):
5030-
"""Sets with dummy entries (after discard) must evaluate as falsy.
5031-
5032-
PySetObject does not use PyObject_VAR_HEAD; reading ob_size at that
5033-
offset accidentally reads `fill`, which counts both live *and* dummy
5034-
(deleted) entries. A set whose items have all been discarded must
5035-
still be falsy even after the JIT specialises TO_BOOL.
5036-
"""
4961+
# PySetObject does not use PyObject_VAR_HEAD; reading ob_size at that
4962+
# offset accidentally reads `fill`, which counts both live *and* dummy
4963+
# (deleted) entries. A set whose items have all been discarded must
4964+
# still be falsy even after the JIT specialises TO_BOOL.
50374965
def f(n):
50384966
result = []
50394967
for _ in range(n):
@@ -5043,59 +4971,8 @@ def f(n):
50434971
return result
50444972

50454973
res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
5046-
# Every element must be False: the set is empty after discard()
50474974
self.assertTrue(all(r is False for r in res))
50484975

5049-
def _check_to_bool_recorded_type(self, inner, value, guard_op):
5050-
"""Recorded-type path: a value whose static type is unknown but whose
5051-
runtime type is recorded should emit `guard_op` + _TO_BOOL_SIZED."""
5052-
self.assertEqual(inner(value), TIER2_THRESHOLD)
5053-
ex_inner = get_first_executor(inner)
5054-
self.assertIsNotNone(ex_inner)
5055-
uops = get_opnames(ex_inner)
5056-
self.assertIn(guard_op, uops)
5057-
self.assertIn("_TO_BOOL_SIZED", uops)
5058-
self.assertNotIn("_TO_BOOL", uops)
5059-
5060-
def test_to_bool_bytes(self):
5061-
def inner(v):
5062-
cnt = 0
5063-
for _ in range(TIER2_THRESHOLD):
5064-
if v:
5065-
cnt += 1
5066-
return cnt
5067-
self._check_to_bool_recorded_type(inner, b"hello", "_GUARD_TOS_BYTES")
5068-
5069-
def test_to_bool_bytearray(self):
5070-
def inner(v):
5071-
cnt = 0
5072-
for _ in range(TIER2_THRESHOLD):
5073-
if v:
5074-
cnt += 1
5075-
return cnt
5076-
self._check_to_bool_recorded_type(
5077-
inner, bytearray(b"hello"), "_GUARD_TOS_BYTEARRAY")
5078-
5079-
def test_to_bool_frozenset(self):
5080-
def inner(v):
5081-
cnt = 0
5082-
for _ in range(TIER2_THRESHOLD):
5083-
if v:
5084-
cnt += 1
5085-
return cnt
5086-
self._check_to_bool_recorded_type(
5087-
inner, frozenset({1, 2, 3}), "_GUARD_TOS_FROZENSET")
5088-
5089-
def test_to_bool_frozendict(self):
5090-
def inner(v):
5091-
cnt = 0
5092-
for _ in range(TIER2_THRESHOLD):
5093-
if v:
5094-
cnt += 1
5095-
return cnt
5096-
self._check_to_bool_recorded_type(
5097-
inner, frozendict({1: 1, 2: 2}), "_GUARD_TOS_FROZENDICT")
5098-
50994976
def test_attr_promotion_failure(self):
51004977
# We're not testing for any specific uops here, just
51014978
# testing it doesn't crash.

0 commit comments

Comments
 (0)