Skip to content

Commit 979d92f

Browse files
authored
gh-144140: Optimize len for string constants in optimizer (GH-144142)
1 parent 27246c3 commit 979d92f

File tree

3 files changed

+53
-10
lines changed

3 files changed

+53
-10
lines changed

Lib/test/test_capi/test_opt.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2419,6 +2419,21 @@ def testfunc(n):
24192419
self.assertNotIn("_GUARD_TOS_INT", uops)
24202420
self.assertIn("_POP_TOP_NOP", uops)
24212421

2422+
def test_call_len_string(self):
2423+
def testfunc(n):
2424+
for _ in range(n):
2425+
_ = len("abc")
2426+
d = ''
2427+
_ = len(d)
2428+
_ = len(b"def")
2429+
_ = len(b"")
2430+
2431+
_, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
2432+
self.assertIsNotNone(ex)
2433+
uops = get_opnames(ex)
2434+
self.assertNotIn("_CALL_LEN", uops)
2435+
self.assertEqual(count_ops(ex, "_SHUFFLE_3_LOAD_CONST_INLINE_BORROW"), 4)
2436+
24222437
def test_call_len_known_length_small_int(self):
24232438
# Make sure that len(t) is optimized for a tuple of length 5.
24242439
# See https://github.com/python/cpython/issues/139393.

Python/optimizer_bytecodes.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,15 +1455,28 @@ dummy_func(void) {
14551455

14561456
op(_CALL_LEN, (callable, null, arg -- res, a, c)) {
14571457
res = sym_new_type(ctx, &PyLong_Type);
1458-
Py_ssize_t tuple_length = sym_tuple_length(arg);
1459-
if (tuple_length >= 0) {
1460-
PyObject *temp = PyLong_FromSsize_t(tuple_length);
1458+
Py_ssize_t length = sym_tuple_length(arg);
1459+
1460+
// Not a tuple, check if it's a const string
1461+
if (length < 0 && sym_is_const(ctx, arg)) {
1462+
PyObject *const_val = sym_get_const(ctx, arg);
1463+
if (const_val != NULL) {
1464+
if (PyUnicode_CheckExact(const_val)) {
1465+
length = PyUnicode_GET_LENGTH(const_val);
1466+
}
1467+
else if (PyBytes_CheckExact(const_val)) {
1468+
length = PyBytes_GET_SIZE(const_val);
1469+
}
1470+
}
1471+
}
1472+
1473+
if (length >= 0) {
1474+
PyObject *temp = PyLong_FromSsize_t(length);
14611475
if (temp == NULL) {
14621476
goto error;
14631477
}
14641478
if (_Py_IsImmortal(temp)) {
1465-
ADD_OP(_SHUFFLE_3_LOAD_CONST_INLINE_BORROW,
1466-
0, (uintptr_t)temp);
1479+
ADD_OP(_SHUFFLE_3_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)temp);
14671480
}
14681481
res = sym_new_const(ctx, temp);
14691482
Py_DECREF(temp);

Python/optimizer_cases.c.h

Lines changed: 20 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)