summaryrefslogtreecommitdiff
path: root/Python/peephole.c
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2010-01-16 18:37:38 +0000
committerAntoine Pitrou <solipsis@pitrou.net>2010-01-16 18:37:38 +0000
commit21626fd023758b13af68da0aaf036123fd60b6a7 (patch)
treec90148d446844b5e91245c2e1232213bafcb3e48 /Python/peephole.c
parentcd1f31f5b0a391f99c7d2e935d9bcde63d99b096 (diff)
downloadcpython-21626fd023758b13af68da0aaf036123fd60b6a7.tar.gz
Issue #6690: Optimize the bytecode for expressions such as `x in {1, 2, 3}`,
where the right hand operand is a set of constants, by turning the set into a frozenset and pre-building it as a constant. The comparison operation is made against the constant instead of building a new set each time it is executed (a similar optimization already existed which turned a list of constants into a pre-built tuple). Patch and additional tests by Dave Malcolm.
Diffstat (limited to 'Python/peephole.c')
-rw-r--r--Python/peephole.c20
1 files changed, 16 insertions, 4 deletions
diff --git a/Python/peephole.c b/Python/peephole.c
index 104db8cb97..eeb31d54bd 100644
--- a/Python/peephole.c
+++ b/Python/peephole.c
@@ -31,7 +31,8 @@
new constant (c1, c2, ... cn) can be appended.
Called with codestr pointing to the first LOAD_CONST.
Bails out with no change if one or more of the LOAD_CONSTs is missing.
- Also works for BUILD_LIST when followed by an "in" or "not in" test.
+ Also works for BUILD_LIST and BUILT_SET when followed by an "in" or "not in"
+ test; for BUILD_SET it assembles a frozenset rather than a tuple.
*/
static int
tuple_of_constants(unsigned char *codestr, Py_ssize_t n, PyObject *consts)
@@ -41,7 +42,7 @@ tuple_of_constants(unsigned char *codestr, Py_ssize_t n, PyObject *consts)
/* Pre-conditions */
assert(PyList_CheckExact(consts));
- assert(codestr[n*3] == BUILD_TUPLE || codestr[n*3] == BUILD_LIST);
+ assert(codestr[n*3] == BUILD_TUPLE || codestr[n*3] == BUILD_LIST || codestr[n*3] == BUILD_SET);
assert(GETARG(codestr, (n*3)) == n);
for (i=0 ; i<n ; i++)
assert(codestr[i*3] == LOAD_CONST);
@@ -59,6 +60,16 @@ tuple_of_constants(unsigned char *codestr, Py_ssize_t n, PyObject *consts)
PyTuple_SET_ITEM(newconst, i, constant);
}
+ /* If it's a BUILD_SET, use the PyTuple we just built to create a
+ PyFrozenSet, and use that as the constant instead: */
+ if (codestr[n*3] == BUILD_SET) {
+ PyObject *tuple = newconst;
+ newconst = PyFrozenSet_New(tuple);
+ Py_DECREF(tuple);
+ if (newconst == NULL)
+ return 0;
+ }
+
/* Append folded constant onto consts */
if (PyList_Append(consts, newconst)) {
Py_DECREF(newconst);
@@ -436,20 +447,21 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
cumlc = 0;
break;
- /* Try to fold tuples of constants (includes a case for lists
+ /* Try to fold tuples of constants (includes a case for lists and sets
which are only used for "in" and "not in" tests).
Skip over BUILD_SEQN 1 UNPACK_SEQN 1.
Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2.
Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */
case BUILD_TUPLE:
case BUILD_LIST:
+ case BUILD_SET:
j = GETARG(codestr, i);
h = i - 3 * j;
if (h >= 0 &&
j <= lastlc &&
((opcode == BUILD_TUPLE &&
ISBASICBLOCK(blocks, h, 3*(j+1))) ||
- (opcode == BUILD_LIST &&
+ ((opcode == BUILD_LIST || opcode == BUILD_SET) &&
codestr[i+3]==COMPARE_OP &&
ISBASICBLOCK(blocks, h, 3*(j+2)) &&
(GETARG(codestr,i+3)==6 ||