summaryrefslogtreecommitdiff
path: root/Python/compile.c
diff options
context:
space:
mode:
authorINADA Naoki <methane@users.noreply.github.com>2018-11-29 00:58:46 +0900
committerVictor Stinner <vstinner@redhat.com>2018-11-28 16:58:46 +0100
commitf7e4d3642fbb88f4e6243c952a0e223fb5df1c65 (patch)
tree1a6c12cbe54e48774c7723e6d54136d78a168742 /Python/compile.c
parent1cdfcfc9843d35ab2cb87387d3a79b2c8a585a38 (diff)
downloadcpython-git-f7e4d3642fbb88f4e6243c952a0e223fb5df1c65.tar.gz
bpo-34100: compile: Re-enable frozenset merging (GH-10760)
This reverts commit 1005c84535191a72ebb7587d8c5636a065b7ed79.
Diffstat (limited to 'Python/compile.c')
-rw-r--r--Python/compile.c59
1 files changed, 57 insertions, 2 deletions
diff --git a/Python/compile.c b/Python/compile.c
index 7d51819e00..45e78cb22c 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -1208,14 +1208,18 @@ merge_consts_recursive(struct compiler *c, PyObject *o)
// t is borrowed reference
PyObject *t = PyDict_SetDefault(c->c_const_cache, key, key);
if (t != key) {
+ // o is registered in c_const_cache. Just use it.
Py_INCREF(t);
Py_DECREF(key);
return t;
}
+ // We registered o in c_const_cache.
+ // When o is a tuple or frozenset, we want to merge it's
+ // items too.
if (PyTuple_CheckExact(o)) {
- Py_ssize_t i, len = PyTuple_GET_SIZE(o);
- for (i = 0; i < len; i++) {
+ Py_ssize_t len = PyTuple_GET_SIZE(o);
+ for (Py_ssize_t i = 0; i < len; i++) {
PyObject *item = PyTuple_GET_ITEM(o, i);
PyObject *u = merge_consts_recursive(c, item);
if (u == NULL) {
@@ -1240,6 +1244,57 @@ merge_consts_recursive(struct compiler *c, PyObject *o)
Py_DECREF(u);
}
}
+ else if (PyFrozenSet_CheckExact(o)) {
+ // *key* is tuple. And it's first item is frozenset of
+ // constant keys.
+ // See _PyCode_ConstantKey() for detail.
+ assert(PyTuple_CheckExact(key));
+ assert(PyTuple_GET_SIZE(key) == 2);
+
+ Py_ssize_t len = PySet_GET_SIZE(o);
+ if (len == 0) { // empty frozenset should not be re-created.
+ return key;
+ }
+ PyObject *tuple = PyTuple_New(len);
+ if (tuple == NULL) {
+ Py_DECREF(key);
+ return NULL;
+ }
+ Py_ssize_t i = 0, pos = 0;
+ PyObject *item;
+ Py_hash_t hash;
+ while (_PySet_NextEntry(o, &pos, &item, &hash)) {
+ PyObject *k = merge_consts_recursive(c, item);
+ if (k == NULL) {
+ Py_DECREF(tuple);
+ Py_DECREF(key);
+ return NULL;
+ }
+ PyObject *u;
+ if (PyTuple_CheckExact(k)) {
+ u = PyTuple_GET_ITEM(k, 1);
+ Py_INCREF(u);
+ Py_DECREF(k);
+ }
+ else {
+ u = k;
+ }
+ PyTuple_SET_ITEM(tuple, i, u); // Steals reference of u.
+ i++;
+ }
+
+ // Instead of rewriting o, we create new frozenset and embed in the
+ // key tuple. Caller should get merged frozenset from the key tuple.
+ PyObject *new = PyFrozenSet_New(tuple);
+ Py_DECREF(tuple);
+ if (new == NULL) {
+ Py_DECREF(key);
+ return NULL;
+ }
+ assert(PyTuple_GET_ITEM(key, 1) == o);
+ Py_DECREF(o);
+ PyTuple_SET_ITEM(key, 1, new);
+ }
return key;
}