Skip to content

Commit 18281db

Browse files
authored
gh-144140: Optimize len for frozen dict/set constants in optimizer (#149969)
1 parent 6ee879f commit 18281db

4 files changed

Lines changed: 20 additions & 8 deletions

File tree

Lib/test/test_capi/test_opt.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3154,20 +3154,22 @@ def testfunc(n):
31543154
uops = get_opnames(ex)
31553155
self.assertNotIn("_CHECK_IS_NOT_PY_CALLABLE_KW", uops)
31563156

3157-
def test_call_len_string(self):
3157+
def test_call_len_string_frozen_set_dict(self):
31583158
def testfunc(n):
31593159
for _ in range(n):
31603160
_ = len("abc")
31613161
d = ''
31623162
_ = len(d)
31633163
_ = len(b"def")
31643164
_ = len(b"")
3165+
_ = len(FROZEN_SET_CONST)
3166+
_ = len(FROZEN_DICT_CONST)
31653167

31663168
_, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
31673169
self.assertIsNotNone(ex)
31683170
uops = get_opnames(ex)
31693171
self.assertNotIn("_CALL_LEN", uops)
3170-
self.assertGreaterEqual(count_ops(ex, "_LOAD_CONST_INLINE_BORROW"), 8)
3172+
self.assertGreaterEqual(count_ops(ex, "_LOAD_CONST_INLINE_BORROW"), 10)
31713173

31723174
def test_call_len_known_length_small_int(self):
31733175
# Make sure that len(t) is optimized for a tuple of length 5.

Python/optimizer_bytecodes.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2378,7 +2378,7 @@ dummy_func(void) {
23782378
res = sym_new_type(ctx, &PyLong_Type);
23792379
Py_ssize_t length = sym_tuple_length(arg);
23802380

2381-
// Not a tuple, check if it's a const string
2381+
// Not a tuple, check if it's another immutable const with known length
23822382
if (length < 0 && sym_is_const(ctx, arg)) {
23832383
PyObject *const_val = sym_get_const(ctx, arg);
23842384
if (const_val != NULL) {
@@ -2388,6 +2388,12 @@ dummy_func(void) {
23882388
else if (PyBytes_CheckExact(const_val)) {
23892389
length = PyBytes_GET_SIZE(const_val);
23902390
}
2391+
else if (PyFrozenDict_CheckExact(const_val)) {
2392+
length = PyDict_GET_SIZE(const_val);
2393+
}
2394+
else if (PyFrozenSet_CheckExact(const_val)) {
2395+
length = PySet_GET_SIZE(const_val);
2396+
}
23912397
}
23922398
}
23932399

Python/optimizer_cases.c.h

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

Tools/cases_generator/analyzer.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,9 @@ def has_error_without_pop(op: parser.CodeDef) -> bool:
616616
"PyStackRef_RefcountOnObject",
617617
"PyStackRef_TYPE",
618618
"PyStackRef_True",
619+
"PyBytes_GET_SIZE",
620+
"PyDict_GET_SIZE",
621+
"PySet_GET_SIZE",
619622
"PyTuple_GET_ITEM",
620623
"PyTuple_GET_SIZE",
621624
"PyType_HasFeature",

0 commit comments

Comments
 (0)