Commit f289ae6f authored by Antoine Pitrou's avatar Antoine Pitrou

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.
........
parent 621601a6
...@@ -357,14 +357,25 @@ Miscellaneous opcodes. ...@@ -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 ()
......
...@@ -21,8 +21,6 @@ extern "C" { ...@@ -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" { ...@@ -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
......
...@@ -57,8 +57,6 @@ def_op('UNARY_NOT', 12) ...@@ -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) ...@@ -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
...@@ -55,29 +55,25 @@ def bug1333982(x=[]): ...@@ -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 %-4d >> 32 LOAD_CONST 2 (1)
34 JUMP_ABSOLUTE 21 35 BINARY_ADD
>> 37 DELETE_FAST 1 (_[1]) 36 RAISE_VARARGS 2
>> 39 POP_TOP
%-4d 40 LOAD_CONST 2 (1)
43 BINARY_ADD %-4d 40 LOAD_CONST 0 (None)
44 RAISE_VARARGS 2 43 RETURN_VALUE
>> 47 POP_TOP
%-4d 48 LOAD_CONST 0 (None)
51 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)
......
...@@ -12,6 +12,9 @@ What's New in Python 3.1 alpha 0 ...@@ -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.
......
...@@ -1306,9 +1306,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -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) ...@@ -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) ...@@ -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();
......
...@@ -707,6 +707,8 @@ opcode_stack_effect(int opcode, int oparg) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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: ...@@ -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;
} }
......
...@@ -87,8 +87,10 @@ extern time_t PyOS_GetLastModificationTime(char *, 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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment