]> granicus.if.org Git - python/commitdiff
Merged revisions 67818 via svnmerge from
authorAntoine Pitrou <solipsis@pitrou.net>
Thu, 18 Dec 2008 11:06:25 +0000 (11:06 +0000)
committerAntoine Pitrou <solipsis@pitrou.net>
Thu, 18 Dec 2008 11:06:25 +0000 (11:06 +0000)
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.
........

Doc/library/dis.rst
Include/opcode.h
Lib/opcode.py
Lib/test/test_dis.py
Misc/NEWS
Python/ceval.c
Python/compile.c
Python/import.c

index 500b83faa93f2eb2b484e96b6105ea8d856254d8..ab06542b88d9eff2788bffc58ecf7efa535f2949 100644 (file)
@@ -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 ()
index 6da9877098b2c14daaa5988963f6521ed42d6d00..063ab6c515dbf8f7d6e98796aad2d9bf35426484 100644 (file)
@@ -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
index 5fd9c218c57cb8279b2f977e0eb5762b0b618b41..9484d1ef859eca9f01781813b576c2d7f96a6276 100644 (file)
@@ -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
index cf62ecfdfef0b8632ba9d55ae9b8e880f3d70ecc..d82dc5a1e2fb0cdce77e40aaf61c09ef7ff8d480 100644 (file)
@@ -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)
index f812ce488a3f152e36594725170aa5f92ae99e82..eb9a2bfffbc6e4906232105191e91d41f1053105 100644 (file)
--- 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.
index b17d3dbc76943114185c59e6f09818c8f7195c3f..2ce3ec9c10858aa47cd2d1501a2b5f34adeb059d 100644 (file)
@@ -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();
index 50eb1693debfbe04227f58343d2aba81bde50394..36f8c13d527fc2076a39e254bb9f7c4f0ee12847 100644 (file)
@@ -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;
 }
 
index 2bad2e524821fa40ed4ba844b63596be9bafb5fe..621284ecb45992435dd7832f28be877ae7f543f7 100644 (file)
@@ -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