http://bugs.python.org/issue4715
This patch by Antoine Pitrou optimizes the bytecode for conditional branches by
merging the following "POP_TOP" instruction into the conditional jump. For
example, the list comprehension "[x for x in l if not x]" produced the
following bytecode:
1 0 BUILD_LIST 0
3 LOAD_FAST 0 (.0)
>> 6 FOR_ITER 23 (to 32)
9 STORE_FAST 1 (x)
12 LOAD_FAST 1 (x)
15 JUMP_IF_TRUE 10 (to 28)
18 POP_TOP
19 LOAD_FAST 1 (x)
22 LIST_APPEND 2
25 JUMP_ABSOLUTE 6
>> 28 POP_TOP
29 JUMP_ABSOLUTE 6
>> 32 RETURN_VALUE
but after the patch it produces the following bytecode:
1 0 BUILD_LIST 0
3 LOAD_FAST 0 (.0)
>> 6 FOR_ITER 18 (to 27)
9 STORE_FAST 1 (x)
12 LOAD_FAST 1 (x)
15 POP_JUMP_IF_TRUE 6
18 LOAD_FAST 1 (x)
21 LIST_APPEND 2
24 JUMP_ABSOLUTE 6
>> 27 RETURN_VALUE
Notice that not only the code is shorter, but the conditional jump
(POP_JUMP_IF_TRUE) jumps right to the start of the loop instead of going through
the JUMP_ABSOLUTE at the end. "continue" statements are helped
similarly.
Furthermore, the old jump opcodes (JUMP_IF_FALSE, JUMP_IF_TRUE) have been
replaced by two new opcodes:
- JUMP_IF_TRUE_OR_POP, which jumps if true and pops otherwise
- JUMP_IF_FALSE_OR_POP, which jumps if false and pops otherwise
diff --git a/Python/ceval.c b/Python/ceval.c
index e0ce92e..d1d6d1d 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1295,7 +1295,6 @@
SETLOCAL(oparg, v);
FAST_DISPATCH();
- PREDICTED(POP_TOP);
TARGET(POP_TOP)
v = POP();
Py_DECREF(v);
@@ -2204,8 +2203,8 @@
Py_DECREF(w);
SET_TOP(x);
if (x == NULL) break;
- PREDICT(JUMP_IF_FALSE);
- PREDICT(JUMP_IF_TRUE);
+ PREDICT(POP_JUMP_IF_FALSE);
+ PREDICT(POP_JUMP_IF_TRUE);
DISPATCH();
TARGET(IMPORT_NAME)
@@ -2282,44 +2281,95 @@
JUMPBY(oparg);
FAST_DISPATCH();
- PREDICTED_WITH_ARG(JUMP_IF_FALSE);
- TARGET(JUMP_IF_FALSE)
- w = TOP();
+ PREDICTED_WITH_ARG(POP_JUMP_IF_FALSE);
+ TARGET(POP_JUMP_IF_FALSE)
+ w = POP();
if (w == Py_True) {
- PREDICT(POP_TOP);
+ Py_DECREF(w);
FAST_DISPATCH();
}
if (w == Py_False) {
- JUMPBY(oparg);
+ Py_DECREF(w);
+ JUMPTO(oparg);
FAST_DISPATCH();
}
err = PyObject_IsTrue(w);
+ Py_DECREF(w);
if (err > 0)
err = 0;
else if (err == 0)
- JUMPBY(oparg);
+ JUMPTO(oparg);
else
break;
DISPATCH();
- PREDICTED_WITH_ARG(JUMP_IF_TRUE);
- TARGET(JUMP_IF_TRUE)
- w = TOP();
+ PREDICTED_WITH_ARG(POP_JUMP_IF_TRUE);
+ TARGET(POP_JUMP_IF_TRUE)
+ w = POP();
if (w == Py_False) {
- PREDICT(POP_TOP);
+ Py_DECREF(w);
FAST_DISPATCH();
}
if (w == Py_True) {
- JUMPBY(oparg);
+ Py_DECREF(w);
+ JUMPTO(oparg);
+ FAST_DISPATCH();
+ }
+ err = PyObject_IsTrue(w);
+ Py_DECREF(w);
+ if (err > 0) {
+ err = 0;
+ JUMPTO(oparg);
+ }
+ else if (err == 0)
+ ;
+ else
+ break;
+ DISPATCH();
+
+ TARGET(JUMP_IF_FALSE_OR_POP)
+ w = TOP();
+ if (w == Py_True) {
+ STACKADJ(-1);
+ Py_DECREF(w);
+ FAST_DISPATCH();
+ }
+ if (w == Py_False) {
+ JUMPTO(oparg);
+ FAST_DISPATCH();
+ }
+ err = PyObject_IsTrue(w);
+ if (err > 0) {
+ STACKADJ(-1);
+ Py_DECREF(w);
+ err = 0;
+ }
+ else if (err == 0)
+ JUMPTO(oparg);
+ else
+ break;
+ DISPATCH();
+
+ TARGET(JUMP_IF_TRUE_OR_POP)
+ w = TOP();
+ if (w == Py_False) {
+ STACKADJ(-1);
+ Py_DECREF(w);
+ FAST_DISPATCH();
+ }
+ if (w == Py_True) {
+ JUMPTO(oparg);
FAST_DISPATCH();
}
err = PyObject_IsTrue(w);
if (err > 0) {
err = 0;
- JUMPBY(oparg);
+ JUMPTO(oparg);
}
- else if (err == 0)
- ;
+ else if (err == 0) {
+ STACKADJ(-1);
+ Py_DECREF(w);
+ }
else
break;
DISPATCH();