Merged revisions 67818 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r67818 | antoine.pitrou | 2008-12-17 01:38:28 +0100 (mer., 17 déc. 2008) | 3 lines

  Issue #2183: Simplify and optimize bytecode for list comprehensions.
........
This commit is contained in:
Antoine Pitrou 2008-12-18 11:06:25 +00:00
parent 621601a698
commit f289ae6f01
8 changed files with 70 additions and 55 deletions

View file

@ -357,14 +357,25 @@ Miscellaneous opcodes.
address to jump to (which should be a ``FOR_ITER`` instruction). address to jump to (which should be a ``FOR_ITER`` instruction).
.. opcode:: SET_ADD () .. opcode:: SET_ADD (i)
Calls ``set.add(TOS1, TOS)``. Used to implement set comprehensions. Calls ``set.add(TOS1[-i], TOS)``. Used to implement set comprehensions.
.. opcode:: LIST_APPEND () .. opcode:: LIST_APPEND (i)
Calls ``list.append(TOS1, TOS)``. Used to implement list comprehensions. Calls ``list.append(TOS[-i], TOS)``. Used to implement list comprehensions.
.. opcode:: MAP_ADD (i)
Calls ``dict.setitem(TOS1[-i], TOS, TOS1)``. Used to implement dict
comprehensions.
For all of the SET_ADD, LIST_APPEND and MAP_ADD instructions, while the
added value or key/value pair is popped off, the container object remains on
the stack so that it is available for further iterations of the loop.
.. opcode:: LOAD_LOCALS () .. opcode:: LOAD_LOCALS ()

View file

@ -21,8 +21,6 @@ extern "C" {
#define UNARY_INVERT 15 #define UNARY_INVERT 15
#define SET_ADD 17
#define LIST_APPEND 18
#define BINARY_POWER 19 #define BINARY_POWER 19
#define BINARY_MULTIPLY 20 #define BINARY_MULTIPLY 20
@ -133,6 +131,10 @@ extern "C" {
/* Support for opargs more than 16 bits long */ /* Support for opargs more than 16 bits long */
#define EXTENDED_ARG 143 #define EXTENDED_ARG 143
#define LIST_APPEND 145
#define SET_ADD 146
#define MAP_ADD 147
/* EXCEPT_HANDLER is a special, implicit block type which is created when /* EXCEPT_HANDLER is a special, implicit block type which is created when
entering an except handler. It is not an opcode but we define it here entering an except handler. It is not an opcode but we define it here

View file

@ -57,8 +57,6 @@ def_op('UNARY_NOT', 12)
def_op('UNARY_INVERT', 15) def_op('UNARY_INVERT', 15)
def_op('SET_ADD', 17)
def_op('LIST_APPEND', 18)
def_op('BINARY_POWER', 19) def_op('BINARY_POWER', 19)
def_op('BINARY_MULTIPLY', 20) def_op('BINARY_MULTIPLY', 20)
@ -169,4 +167,9 @@ def_op('CALL_FUNCTION_VAR_KW', 142) # #args + (#kwargs << 8)
def_op('EXTENDED_ARG', 143) def_op('EXTENDED_ARG', 143)
EXTENDED_ARG = 143 EXTENDED_ARG = 143
def_op('LIST_APPEND', 145)
def_op('SET_ADD', 146)
def_op('MAP_ADD', 147)
del def_op, name_op, jrel_op, jabs_op del def_op, name_op, jrel_op, jabs_op

View file

@ -55,29 +55,25 @@ def bug1333982(x=[]):
dis_bug1333982 = """\ dis_bug1333982 = """\
%-4d 0 LOAD_CONST 1 (0) %-4d 0 LOAD_CONST 1 (0)
3 JUMP_IF_TRUE 41 (to 47) 3 JUMP_IF_TRUE 33 (to 39)
6 POP_TOP 6 POP_TOP
7 LOAD_GLOBAL 0 (AssertionError) 7 LOAD_GLOBAL 0 (AssertionError)
10 BUILD_LIST 0 10 BUILD_LIST 0
13 DUP_TOP 13 LOAD_FAST 0 (x)
14 STORE_FAST 1 (_[1]) 16 GET_ITER
17 LOAD_FAST 0 (x) >> 17 FOR_ITER 12 (to 32)
20 GET_ITER 20 STORE_FAST 1 (s)
>> 21 FOR_ITER 13 (to 37) 23 LOAD_FAST 1 (s)
24 STORE_FAST 2 (s) 26 LIST_APPEND 2
27 LOAD_FAST 1 (_[1]) 29 JUMP_ABSOLUTE 17
30 LOAD_FAST 2 (s)
33 LIST_APPEND
34 JUMP_ABSOLUTE 21
>> 37 DELETE_FAST 1 (_[1])
%-4d 40 LOAD_CONST 2 (1) %-4d >> 32 LOAD_CONST 2 (1)
43 BINARY_ADD 35 BINARY_ADD
44 RAISE_VARARGS 2 36 RAISE_VARARGS 2
>> 47 POP_TOP >> 39 POP_TOP
%-4d 48 LOAD_CONST 0 (None) %-4d 40 LOAD_CONST 0 (None)
51 RETURN_VALUE 43 RETURN_VALUE
"""%(bug1333982.__code__.co_firstlineno + 1, """%(bug1333982.__code__.co_firstlineno + 1,
bug1333982.__code__.co_firstlineno + 2, bug1333982.__code__.co_firstlineno + 2,
bug1333982.__code__.co_firstlineno + 3) bug1333982.__code__.co_firstlineno + 3)

View file

@ -12,6 +12,9 @@ What's New in Python 3.1 alpha 0
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #2183: Simplify and optimize bytecode for list, dict and set
comprehensions. Original patch for list comprehensions by Neal Norwitz.
- Issue #2467: gc.DEBUG_STATS reported invalid elapsed times. Also, always - Issue #2467: gc.DEBUG_STATS reported invalid elapsed times. Also, always
print elapsed times, not only when some objects are uncollectable / print elapsed times, not only when some objects are uncollectable /
unreachable. Original patch by Neil Schemenauer. unreachable. Original patch by Neil Schemenauer.

View file

@ -1306,9 +1306,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
case LIST_APPEND: case LIST_APPEND:
w = POP(); w = POP();
v = POP(); v = stack_pointer[-oparg];
err = PyList_Append(v, w); err = PyList_Append(v, w);
Py_DECREF(v);
Py_DECREF(w); Py_DECREF(w);
if (err == 0) { if (err == 0) {
PREDICT(JUMP_ABSOLUTE); PREDICT(JUMP_ABSOLUTE);
@ -1318,9 +1317,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
case SET_ADD: case SET_ADD:
w = POP(); w = POP();
v = POP(); v = stack_pointer[-oparg];
err = PySet_Add(v, w); err = PySet_Add(v, w);
Py_DECREF(v);
Py_DECREF(w); Py_DECREF(w);
if (err == 0) { if (err == 0) {
PREDICT(JUMP_ABSOLUTE); PREDICT(JUMP_ABSOLUTE);
@ -1935,6 +1933,21 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
if (err == 0) continue; if (err == 0) continue;
break; break;
case MAP_ADD:
w = TOP(); /* key */
u = SECOND(); /* value */
STACKADJ(-2);
v = stack_pointer[-oparg]; /* dict */
assert (PyDict_CheckExact(v));
err = PyDict_SetItem(v, w, u); /* v[w] = u */
Py_DECREF(u);
Py_DECREF(w);
if (err == 0) {
PREDICT(JUMP_ABSOLUTE);
continue;
}
break;
case LOAD_ATTR: case LOAD_ATTR:
w = GETITEM(names, oparg); w = GETITEM(names, oparg);
v = TOP(); v = TOP();

View file

@ -707,6 +707,8 @@ opcode_stack_effect(int opcode, int oparg)
case SET_ADD: case SET_ADD:
case LIST_APPEND: case LIST_APPEND:
return -1;
case MAP_ADD:
return -2; return -2;
case BINARY_POWER: case BINARY_POWER:
@ -2823,7 +2825,7 @@ compiler_call_helper(struct compiler *c,
*/ */
static int static int
compiler_comprehension_generator(struct compiler *c, PyObject *tmpname, compiler_comprehension_generator(struct compiler *c,
asdl_seq *generators, int gen_index, asdl_seq *generators, int gen_index,
expr_ty elt, expr_ty val, int type) expr_ty elt, expr_ty val, int type)
{ {
@ -2871,7 +2873,7 @@ compiler_comprehension_generator(struct compiler *c, PyObject *tmpname,
} }
if (++gen_index < asdl_seq_LEN(generators)) if (++gen_index < asdl_seq_LEN(generators))
if (!compiler_comprehension_generator(c, tmpname, if (!compiler_comprehension_generator(c,
generators, gen_index, generators, gen_index,
elt, val, type)) elt, val, type))
return 0; return 0;
@ -2886,27 +2888,19 @@ compiler_comprehension_generator(struct compiler *c, PyObject *tmpname,
ADDOP(c, POP_TOP); ADDOP(c, POP_TOP);
break; break;
case COMP_LISTCOMP: case COMP_LISTCOMP:
if (!compiler_nameop(c, tmpname, Load))
return 0;
VISIT(c, expr, elt); VISIT(c, expr, elt);
ADDOP(c, LIST_APPEND); ADDOP_I(c, LIST_APPEND, gen_index + 1);
break; break;
case COMP_SETCOMP: case COMP_SETCOMP:
if (!compiler_nameop(c, tmpname, Load))
return 0;
VISIT(c, expr, elt); VISIT(c, expr, elt);
ADDOP(c, SET_ADD); ADDOP_I(c, SET_ADD, gen_index + 1);
break; break;
case COMP_DICTCOMP: case COMP_DICTCOMP:
if (!compiler_nameop(c, tmpname, Load))
return 0;
/* With 'd[k] = v', v is evaluated before k, so we do /* With 'd[k] = v', v is evaluated before k, so we do
the same. STORE_SUBSCR requires (item, map, key), the same. */
so we still end up ROTing once. */
VISIT(c, expr, val); VISIT(c, expr, val);
ADDOP(c, ROT_TWO);
VISIT(c, expr, elt); VISIT(c, expr, elt);
ADDOP(c, STORE_SUBSCR); ADDOP_I(c, MAP_ADD, gen_index + 1);
break; break;
default: default:
return 0; return 0;
@ -2932,7 +2926,6 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
asdl_seq *generators, expr_ty elt, expr_ty val) asdl_seq *generators, expr_ty elt, expr_ty val)
{ {
PyCodeObject *co = NULL; PyCodeObject *co = NULL;
identifier tmp = NULL;
expr_ty outermost_iter; expr_ty outermost_iter;
outermost_iter = ((comprehension_ty) outermost_iter = ((comprehension_ty)
@ -2943,9 +2936,6 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
if (type != COMP_GENEXP) { if (type != COMP_GENEXP) {
int op; int op;
tmp = compiler_new_tmpname(c);
if (!tmp)
goto error_in_scope;
switch (type) { switch (type) {
case COMP_LISTCOMP: case COMP_LISTCOMP:
op = BUILD_LIST; op = BUILD_LIST;
@ -2963,12 +2953,9 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
} }
ADDOP_I(c, op, 0); ADDOP_I(c, op, 0);
ADDOP(c, DUP_TOP);
if (!compiler_nameop(c, tmp, Store))
goto error_in_scope;
} }
if (!compiler_comprehension_generator(c, tmp, generators, 0, elt, if (!compiler_comprehension_generator(c, generators, 0, elt,
val, type)) val, type))
goto error_in_scope; goto error_in_scope;
@ -2984,7 +2971,6 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
if (!compiler_make_closure(c, co, 0)) if (!compiler_make_closure(c, co, 0))
goto error; goto error;
Py_DECREF(co); Py_DECREF(co);
Py_XDECREF(tmp);
VISIT(c, expr, outermost_iter); VISIT(c, expr, outermost_iter);
ADDOP(c, GET_ITER); ADDOP(c, GET_ITER);
@ -2994,7 +2980,6 @@ error_in_scope:
compiler_exit_scope(c); compiler_exit_scope(c);
error: error:
Py_XDECREF(co); Py_XDECREF(co);
Py_XDECREF(tmp);
return 0; return 0;
} }

View file

@ -87,8 +87,10 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *);
3102 (__file__ points to source file) 3102 (__file__ points to source file)
Python 3.0a4: 3110 (WITH_CLEANUP optimization). Python 3.0a4: 3110 (WITH_CLEANUP optimization).
Python 3.0a5: 3130 (lexical exception stacking, including POP_EXCEPT) Python 3.0a5: 3130 (lexical exception stacking, including POP_EXCEPT)
Python 3.1a0: 3140 (optimize list, set and dict comprehensions:
change LIST_APPEND and SET_ADD, add MAP_ADD)
*/ */
#define MAGIC (3130 | ((long)'\r'<<16) | ((long)'\n'<<24)) #define MAGIC (3140 | ((long)'\r'<<16) | ((long)'\n'<<24))
/* Magic word as global; note that _PyImport_Init() can change the /* Magic word as global; note that _PyImport_Init() can change the
value of this global to accommodate for alterations of how the value of this global to accommodate for alterations of how the