From dd80f762650f42f5f9ae820d9f55b21ed6f33bc0 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sun, 7 Mar 2004 07:31:06 +0000 Subject: SF patch #910929: Optimize list comprehensions Add a new opcode, LIST_APPEND, and apply it to the code generation for list comprehensions. Reduces the per-loop overhead by about a third. --- Doc/whatsnew/whatsnew24.tex | 4 ++++ Include/opcode.h | 1 + Lib/opcode.py | 1 + Misc/NEWS | 4 ++++ Python/ceval.c | 9 +++++++++ Python/compile.c | 4 +--- 6 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Doc/whatsnew/whatsnew24.tex b/Doc/whatsnew/whatsnew24.tex index 24650fa..2a323ff 100644 --- a/Doc/whatsnew/whatsnew24.tex +++ b/Doc/whatsnew/whatsnew24.tex @@ -288,6 +288,10 @@ yellow 5 use as arguments to functionals: \samp{map(mydict.__getitem__, keylist)}. +\item Added an newcode opcode, \code{LIST_APPEND}, that simplifies + the generated bytecode for list comprehensions and speeds them up + by about a third. + \end{itemize} The net result of the 2.4 optimizations is that Python 2.4 runs the diff --git a/Include/opcode.h b/Include/opcode.h index 2f3dd04..8df96b4 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -21,6 +21,7 @@ extern "C" { #define UNARY_INVERT 15 +#define LIST_APPEND 18 #define BINARY_POWER 19 #define BINARY_MULTIPLY 20 diff --git a/Lib/opcode.py b/Lib/opcode.py index 39d4bd2..ae9f6cc 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -56,6 +56,7 @@ def_op('UNARY_CONVERT', 13) def_op('UNARY_INVERT', 15) +def_op('LIST_APPEND', 18) def_op('BINARY_POWER', 19) def_op('BINARY_MULTIPLY', 20) diff --git a/Misc/NEWS b/Misc/NEWS index 72232c8..f3554c3 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,10 @@ What's New in Python 2.4 alpha 1? Core and builtins ----------------- +- Implemented a newcode opcode, LIST_APPEND, that simplifies + the generated bytecode for list comprehensions and further + improves their performance (about 35%). + - Implemented rich comparisons for floats, which seems to make comparisons involving NaNs somewhat less surprising when the underlying C compiler actually implements C99 semantics. diff --git a/Python/ceval.c b/Python/ceval.c index 3371844..b20934c 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1225,6 +1225,15 @@ eval_frame(PyFrameObject *f) if (x != NULL) continue; break; + case LIST_APPEND: + w = POP(); + v = POP(); + err = PyList_Append(v, w); + Py_DECREF(v); + Py_DECREF(w); + if (err == 0) continue; + break; + case INPLACE_POWER: w = POP(); v = TOP(); diff --git a/Python/compile.c b/Python/compile.c index 04d8b65..f58fb83 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1552,8 +1552,7 @@ com_list_iter(struct compiling *c, com_addop_varname(c, VAR_LOAD, t); com_push(c, 1); com_node(c, e); - com_addoparg(c, CALL_FUNCTION, 1); - com_addbyte(c, POP_TOP); + com_addbyte(c, LIST_APPEND); com_pop(c, 2); } } @@ -1569,7 +1568,6 @@ com_list_comprehension(struct compiling *c, node *n) com_addoparg(c, BUILD_LIST, 0); com_addbyte(c, DUP_TOP); /* leave the result on the stack */ com_push(c, 2); - com_addop_name(c, LOAD_ATTR, "append"); com_addop_varname(c, VAR_STORE, tmpname); com_pop(c, 1); com_list_for(c, CHILD(n, 1), CHILD(n, 0), tmpname); -- cgit v0.12