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
This commit is contained in:
Jeffrey Yasskin 2009-02-25 02:25:04 +00:00
parent 0a68b01d64
commit 9de7ec7868
9 changed files with 195 additions and 129 deletions

View file

@ -1295,7 +1295,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
SETLOCAL(oparg, v);
FAST_DISPATCH();
PREDICTED(POP_TOP);
TARGET(POP_TOP)
v = POP();
Py_DECREF(v);
@ -2204,8 +2203,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
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 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
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) {
STACKADJ(-1);
Py_DECREF(w);
}
else if (err == 0)
;
else
break;
DISPATCH();