8000 bpo-34100: compile: Re-enable frozenset merging (GH-10760) · python/cpython@f7e4d36 · GitHub
[go: up one dir, main page]

Skip to content

Commit f7e4d36

Browse files
methanevstinner
authored andcommitted
bpo-34100: compile: Re-enable frozenset merging (GH-10760)
This reverts commit 1005c84.
1 parent 1cdfcfc commit f7e4d36

File tree

2 files changed

+65
-2
lines changed

2 files changed

+65
-2
lines changed

Lib/test/test_compile.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,14 @@ def check_same_constant(const):
615615
self.check_constant(f1, Ellipsis)
616616
self.assertEqual(repr(f1()), repr(Ellipsis))
617617

618+
# Merge constants in tuple or frozenset
619+
f1, f2 = lambda: "not a name", lambda: ("not a name",)
620+
f3 = lambda x: x in {("not a name",)}
621+
self.assertIs(f1.__code__.co_consts[1],
622+
f2.__code__.co_consts[1][0])
623+
self.assertIs(next(iter(f3.__code__.co_consts[1])),
624+
f2.__code__.co_consts[1])
625+
618626
# {0} is converted to a constant frozenset({0}) by the peephole
619627
# optimizer
620628
f1, f2 = lambda x: x in {0}, lambda x: x in {0}

Python/compile.c

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,14 +1208,18 @@ merge_consts_recursive(struct compiler *c, PyObject *o)
12081208
// t is borrowed reference
12091209
PyObject *t = PyDict_SetDefault(c->c_const_cache, key, key);
12101210
if (t != key) {
1211+
// o is registered in c_const_cache. Just use it.
12111212
Py_INCREF(t);
12121213
Py_DECREF(key);
12131214
return t;
12141215
}
12151216

1217+
// We registered o in c_const_cache.
1218+
// When o is a tuple or frozenset, we want to merge it's
1219+
// items too.
12161220
if (PyTuple_CheckExact(o)) {
1217-
Py_ssize_t i, len = PyTuple_GET_SIZE(o);
1218-
for (i = 0; i < len; i++) {
1221+
Py_ssize_t len = PyTuple_GET_SIZE(o);
1222+
for (Py_ssize_t i = 0; i < len; i++) {
12191223
PyObject *item = PyTuple_GET_ITEM(o, i);
12201224
PyObject *u = merge_consts_recursive(c, item);
12211225
if (u == NULL) {
@@ -1240,6 +1244,57 @@ merge_consts_recursive(struct compiler *c, PyObject *o)
12401244
Py_DECREF(u);
12411245
}
12421246
}
1247+
else if (PyFrozenSet_CheckExact(o)) {
1248+
// *key* is tuple. And it's first item is frozenset of
1249+
// constant keys.
1250+
// See _PyCode_ConstantKey() for detail.
1251+
assert(PyTuple_CheckExact(key));
1252+
assert(PyTuple_GET_SIZE(key) == 2);
1253+
1254+
Py_ssize_t len = PySet_GET_SIZE(o);
1255+
if (len == 0) { // empty frozenset should not be re-created.
1256+
return key;
1257+
}
1258+
PyObject *tuple = PyTuple_New(len);
1259+
if (tuple == NULL) {
1260+
Py_DECREF(key);
1261+
return NULL;
1262+
}
1263+
Py_ssize_t i = 0, pos = 0;
1264+
PyObject *item;
1265+
Py_hash_t hash;
1266+
while (_PySet_NextEntry(o, &pos, &item, &hash)) {
1267+
PyObject *k = merge_consts_recursive(c, item);
1268+
if (k == NULL) {
1269+
Py_DECREF(tuple);
1270+
Py_DECREF(key);
1271+
return NULL;
1272+
}
1273+
PyObject *u;
1274+
if (PyTuple_CheckExact(k)) {
1275+
u = PyTuple_GET_ITEM(k, 1);
1276+
Py_INCREF(u);
1277+
Py_DECREF(k);
1278+
}
1279+
else {
1280+
u = k;
1281+
}
1282+
PyTuple_SET_ITEM(tuple, i, u); // Steals reference of u.
1283+
i++;
1284+
}
1285+
1286+
// Instead of rewriting o, we create new frozenset and embed in the
1287+
// key tuple. Caller should get merged frozenset from the key tuple.
1288+
PyObject *new = PyFrozenSet_New(tuple);
1289+
Py_DECREF(tuple);
1290+
if (new == NULL) {
1291+
Py_DECREF(key);
1292+
return NULL;
1293+
}
1294+
assert(PyTuple_GET_ITEM(key, 1) == o);
1295+
Py_DECREF(o);
1296+
PyTuple_SET_ITEM(key, 1, new);
1297+
}
12431298

12441299
return key;
12451300
}

0 commit comments

Comments
 (0)
0