summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2008-12-18 11:06:25 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2008-12-18 11:06:25 (GMT)
commitf289ae6f01683689dfd07785c9617175b40aea91 (patch)
treedd9a6f78817fcedbd95db286188507cf21a52bc0
parent621601a698a285a45231a6fd223db33566dcb842 (diff)
downloadcpython-f289ae6f01683689dfd07785c9617175b40aea91.zip
cpython-f289ae6f01683689dfd07785c9617175b40aea91.tar.gz
cpython-f289ae6f01683689dfd07785c9617175b40aea91.tar.bz2
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. ........
-rw-r--r--Doc/library/dis.rst19
-rw-r--r--Include/opcode.h6
-rw-r--r--Lib/opcode.py7
-rw-r--r--Lib/test/test_dis.py36
-rw-r--r--Misc/NEWS3
-rw-r--r--Python/ceval.c21
-rw-r--r--Python/compile.c33
-rw-r--r--Python/import.c4
8 files changed, 72 insertions, 57 deletions
diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst
index 500b83f..ab06542 100644
--- a/Doc/library/dis.rst
+++ b/Doc/library/dis.rst
@@ -357,14 +357,25 @@ Miscellaneous opcodes.
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 ()
diff --git a/Include/opcode.h b/Include/opcode.h
index 6da9877..063ab6c 100644
--- a/Include/opcode.h
+++ b/Include/opcode.h
@@ -21,8 +21,6 @@ extern "C" {
#define UNARY_INVERT 15
-#define SET_ADD 17
-#define LIST_APPEND 18
#define BINARY_POWER 19
#define BINARY_MULTIPLY 20
@@ -133,6 +131,10 @@ extern "C" {
/* Support for opargs more than 16 bits long */
#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
entering an except handler. It is not an opcode but we define it here
diff --git a/Lib/opcode.py b/Lib/opcode.py
index 5fd9c21..9484d1e 100644
--- a/Lib/opcode.py
+++ b/Lib/opcode.py
@@ -57,8 +57,6 @@ def_op('UNARY_NOT', 12)
def_op('UNARY_INVERT', 15)
-def_op('SET_ADD', 17)
-def_op('LIST_APPEND', 18)
def_op('BINARY_POWER', 19)
def_op('BINARY_MULTIPLY', 20)
@@ -169,4 +167,9 @@ def_op('CALL_FUNCTION_VAR_KW', 142) # #args + (#kwargs << 8)
def_op('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
diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py
index cf62ecf..d82dc5a 100644
--- a/Lib/test/test_dis.py
+++ b/Lib/test/test_dis.py
@@ -55,29 +55,25 @@ def bug1333982(x=[]):
dis_bug1333982 = """\
%-4d 0 LOAD_CONST 1 (0)
- 3 JUMP_IF_TRUE 41 (to 47)
+ 3 JUMP_IF_TRUE 33 (to 39)
6 POP_TOP
7 LOAD_GLOBAL 0 (AssertionError)
10 BUILD_LIST 0
- 13 DUP_TOP
- 14 STORE_FAST 1 (_[1])
- 17 LOAD_FAST 0 (x)
- 20 GET_ITER
- >> 21 FOR_ITER 13 (to 37)
- 24 STORE_FAST 2 (s)
- 27 LOAD_FAST 1 (_[1])
- 30 LOAD_FAST 2 (s)
- 33 LIST_APPEND
- 34 JUMP_ABSOLUTE 21
- >> 37 DELETE_FAST 1 (_[1])
-
- %-4d 40 LOAD_CONST 2 (1)
- 43 BINARY_ADD
- 44 RAISE_VARARGS 2
- >> 47 POP_TOP
-
- %-4d 48 LOAD_CONST 0 (None)
- 51 RETURN_VALUE
+ 13 LOAD_FAST 0 (x)
+ 16 GET_ITER
+ >> 17 FOR_ITER 12 (to 32)
+ 20 STORE_FAST 1 (s)
+ 23 LOAD_FAST 1 (s)
+ 26 LIST_APPEND 2
+ 29 JUMP_ABSOLUTE 17
+
+ %-4d >> 32 LOAD_CONST 2 (1)
+ 35 BINARY_ADD
+ 36 RAISE_VARARGS 2
+ >> 39 POP_TOP
+
+ %-4d 40 LOAD_CONST 0 (None)
+ 43 RETURN_VALUE
"""%(bug1333982.__code__.co_firstlineno + 1,
bug1333982.__code__.co_firstlineno + 2,
bug1333982.__code__.co_firstlineno + 3)
diff --git a/Misc/NEWS b/Misc/NEWS
index f812ce4..eb9a2bf 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,9 @@ What's New in Python 3.1 alpha 0
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
print elapsed times, not only when some objects are uncollectable /
unreachable. Original patch by Neil Schemenauer.
diff --git a/Python/ceval.c b/Python/ceval.c
index b17d3db..2ce3ec9 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1306,9 +1306,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
case LIST_APPEND:
w = POP();
- v = POP();
+ v = stack_pointer[-oparg];
err = PyList_Append(v, w);
- Py_DECREF(v);
Py_DECREF(w);
if (err == 0) {
PREDICT(JUMP_ABSOLUTE);
@@ -1318,9 +1317,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
case SET_ADD:
w = POP();
- v = POP();
+ v = stack_pointer[-oparg];
err = PySet_Add(v, w);
- Py_DECREF(v);
Py_DECREF(w);
if (err == 0) {
PREDICT(JUMP_ABSOLUTE);
@@ -1935,6 +1933,21 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
if (err == 0) continue;
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:
w = GETITEM(names, oparg);
v = TOP();
diff --git a/Python/compile.c b/Python/compile.c
index 50eb169..36f8c13 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -707,6 +707,8 @@ opcode_stack_effect(int opcode, int oparg)
case SET_ADD:
case LIST_APPEND:
+ return -1;
+ case MAP_ADD:
return -2;
case BINARY_POWER:
@@ -2823,7 +2825,7 @@ compiler_call_helper(struct compiler *c,
*/
static int
-compiler_comprehension_generator(struct compiler *c, PyObject *tmpname,
+compiler_comprehension_generator(struct compiler *c,
asdl_seq *generators, int gen_index,
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 (!compiler_comprehension_generator(c, tmpname,
+ if (!compiler_comprehension_generator(c,
generators, gen_index,
elt, val, type))
return 0;
@@ -2886,27 +2888,19 @@ compiler_comprehension_generator(struct compiler *c, PyObject *tmpname,
ADDOP(c, POP_TOP);
break;
case COMP_LISTCOMP:
- if (!compiler_nameop(c, tmpname, Load))
- return 0;
VISIT(c, expr, elt);
- ADDOP(c, LIST_APPEND);
+ ADDOP_I(c, LIST_APPEND, gen_index + 1);
break;
case COMP_SETCOMP:
- if (!compiler_nameop(c, tmpname, Load))
- return 0;
VISIT(c, expr, elt);
- ADDOP(c, SET_ADD);
+ ADDOP_I(c, SET_ADD, gen_index + 1);
break;
case COMP_DICTCOMP:
- if (!compiler_nameop(c, tmpname, Load))
- return 0;
/* With 'd[k] = v', v is evaluated before k, so we do
- the same. STORE_SUBSCR requires (item, map, key),
- so we still end up ROTing once. */
+ the same. */
VISIT(c, expr, val);
- ADDOP(c, ROT_TWO);
VISIT(c, expr, elt);
- ADDOP(c, STORE_SUBSCR);
+ ADDOP_I(c, MAP_ADD, gen_index + 1);
break;
default:
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)
{
PyCodeObject *co = NULL;
- identifier tmp = NULL;
expr_ty outermost_iter;
outermost_iter = ((comprehension_ty)
@@ -2943,9 +2936,6 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
if (type != COMP_GENEXP) {
int op;
- tmp = compiler_new_tmpname(c);
- if (!tmp)
- goto error_in_scope;
switch (type) {
case COMP_LISTCOMP:
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(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))
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))
goto error;
Py_DECREF(co);
- Py_XDECREF(tmp);
VISIT(c, expr, outermost_iter);
ADDOP(c, GET_ITER);
@@ -2994,7 +2980,6 @@ error_in_scope:
compiler_exit_scope(c);
error:
Py_XDECREF(co);
- Py_XDECREF(tmp);
return 0;
}
diff --git a/Python/import.c b/Python/import.c
index 2bad2e5..621284e 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -87,8 +87,10 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *);
3102 (__file__ points to source file)
Python 3.0a4: 3110 (WITH_CLEANUP optimization).
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
value of this global to accommodate for alterations of how the