Skip to content

Commit 75a1429

Browse files
author
antoine.pitrou
committed
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. ........ git-svn-id: http://svn.python.org/projects/python/branches/py3k@67839 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent 9d69913 commit 75a1429

8 files changed

Lines changed: 72 additions & 57 deletions

File tree

Doc/library/dis.rst

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -357,14 +357,25 @@ Miscellaneous opcodes.
357357
address to jump to (which should be a ``FOR_ITER`` instruction).
358358

359359

360-
.. opcode:: SET_ADD ()
360+
.. opcode:: SET_ADD (i)
361361

362-
Calls ``set.add(TOS1, TOS)``. Used to implement set comprehensions.
362+
Calls ``set.add(TOS1[-i], TOS)``. Used to implement set comprehensions.
363363

364364

365-
.. opcode:: LIST_APPEND ()
365+
.. opcode:: LIST_APPEND (i)
366366

367-
Calls ``list.append(TOS1, TOS)``. Used to implement list comprehensions.
367+
Calls ``list.append(TOS[-i], TOS)``. Used to implement list comprehensions.
368+
369+
370+
.. opcode:: MAP_ADD (i)
371+
372+
Calls ``dict.setitem(TOS1[-i], TOS, TOS1)``. Used to implement dict
373+
comprehensions.
374+
375+
376+
For all of the SET_ADD, LIST_APPEND and MAP_ADD instructions, while the
377+
added value or key/value pair is popped off, the container object remains on
378+
the stack so that it is available for further iterations of the loop.
368379

369380

370381
.. opcode:: LOAD_LOCALS ()

Include/opcode.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ extern "C" {
2121

2222
#define UNARY_INVERT 15
2323

24-
#define SET_ADD 17
25-
#define LIST_APPEND 18
2624
#define BINARY_POWER 19
2725

2826
#define BINARY_MULTIPLY 20
@@ -133,6 +131,10 @@ extern "C" {
133131
/* Support for opargs more than 16 bits long */
134132
#define EXTENDED_ARG 143
135133

134+
#define LIST_APPEND 145
135+
#define SET_ADD 146
136+
#define MAP_ADD 147
137+
136138

137139
/* EXCEPT_HANDLER is a special, implicit block type which is created when
138140
entering an except handler. It is not an opcode but we define it here

Lib/opcode.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ def jabs_op(name, op):
5757

5858
def_op('UNARY_INVERT', 15)
5959

60-
def_op('SET_ADD', 17)
61-
def_op('LIST_APPEND', 18)
6260
def_op('BINARY_POWER', 19)
6361
def_op('BINARY_MULTIPLY', 20)
6462

@@ -169,4 +167,9 @@ def jabs_op(name, op):
169167
def_op('EXTENDED_ARG', 143)
170168
EXTENDED_ARG = 143
171169

170+
def_op('LIST_APPEND', 145)
171+
def_op('SET_ADD', 146)
172+
def_op('MAP_ADD', 147)
173+
174+
172175
del def_op, name_op, jrel_op, jabs_op

Lib/test/test_dis.py

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -55,29 +55,25 @@ def bug1333982(x=[]):
5555

5656
dis_bug1333982 = """\
5757
%-4d 0 LOAD_CONST 1 (0)
58-
3 JUMP_IF_TRUE 41 (to 47)
58+
3 JUMP_IF_TRUE 33 (to 39)
5959
6 POP_TOP
6060
7 LOAD_GLOBAL 0 (AssertionError)
6161
10 BUILD_LIST 0
62-
13 DUP_TOP
63-
14 STORE_FAST 1 (_[1])
64-
17 LOAD_FAST 0 (x)
65-
20 GET_ITER
66-
>> 21 FOR_ITER 13 (to 37)
67-
24 STORE_FAST 2 (s)
68-
27 LOAD_FAST 1 (_[1])
69-
30 LOAD_FAST 2 (s)
70-
33 LIST_APPEND
71-
34 JUMP_ABSOLUTE 21
72-
>> 37 DELETE_FAST 1 (_[1])
73-
74-
%-4d 40 LOAD_CONST 2 (1)
75-
43 BINARY_ADD
76-
44 RAISE_VARARGS 2
77-
>> 47 POP_TOP
78-
79-
%-4d 48 LOAD_CONST 0 (None)
80-
51 RETURN_VALUE
62+
13 LOAD_FAST 0 (x)
63+
16 GET_ITER
64+
>> 17 FOR_ITER 12 (to 32)
65+
20 STORE_FAST 1 (s)
66+
23 LOAD_FAST 1 (s)
67+
26 LIST_APPEND 2
68+
29 JUMP_ABSOLUTE 17
69+
70+
%-4d >> 32 LOAD_CONST 2 (1)
71+
35 BINARY_ADD
72+
36 RAISE_VARARGS 2
73+
>> 39 POP_TOP
74+
75+
%-4d 40 LOAD_CONST 0 (None)
76+
43 RETURN_VALUE
8177
"""%(bug1333982.__code__.co_firstlineno + 1,
8278
bug1333982.__code__.co_firstlineno + 2,
8379
bug1333982.__code__.co_firstlineno + 3)

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ What's New in Python 3.1 alpha 0
1212
Core and Builtins
1313
-----------------
1414

15+
- Issue #2183: Simplify and optimize bytecode for list, dict and set
16+
comprehensions. Original patch for list comprehensions by Neal Norwitz.
17+
1518
- Issue #2467: gc.DEBUG_STATS reported invalid elapsed times. Also, always
1619
print elapsed times, not only when some objects are uncollectable /
1720
unreachable. Original patch by Neil Schemenauer.

Python/ceval.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,9 +1306,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
13061306

13071307
case LIST_APPEND:
13081308
w = POP();
1309-
v = POP();
1309+
v = stack_pointer[-oparg];
13101310
err = PyList_Append(v, w);
1311-
Py_DECREF(v);
13121311
Py_DECREF(w);
13131312
if (err == 0) {
13141313
PREDICT(JUMP_ABSOLUTE);
@@ -1318,9 +1317,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
13181317

13191318
case SET_ADD:
13201319
w = POP();
1321-
v = POP();
1320+
v = stack_pointer[-oparg];
13221321
err = PySet_Add(v, w);
1323-
Py_DECREF(v);
13241322
Py_DECREF(w);
13251323
if (err == 0) {
13261324
PREDICT(JUMP_ABSOLUTE);
@@ -1935,6 +1933,21 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
19351933
if (err == 0) continue;
19361934
break;
19371935

1936+
case MAP_ADD:
1937+
w = TOP(); /* key */
1938+
u = SECOND(); /* value */
1939+
STACKADJ(-2);
1940+
v = stack_pointer[-oparg]; /* dict */
1941+
assert (PyDict_CheckExact(v));
1942+
err = PyDict_SetItem(v, w, u); /* v[w] = u */
1943+
Py_DECREF(u);
1944+
Py_DECREF(w);
1945+
if (err == 0) {
1946+
PREDICT(JUMP_ABSOLUTE);
1947+
continue;
1948+
}
1949+
break;
1950+
19381951
case LOAD_ATTR:
19391952
w = GETITEM(names, oparg);
19401953
v = TOP();

Python/compile.c

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,8 @@ opcode_stack_effect(int opcode, int oparg)
707707

708708
case SET_ADD:
709709
case LIST_APPEND:
710+
return -1;
711+
case MAP_ADD:
710712
return -2;
711713

712714
case BINARY_POWER:
@@ -2823,7 +2825,7 @@ compiler_call_helper(struct compiler *c,
28232825
*/
28242826

28252827
static int
2826-
compiler_comprehension_generator(struct compiler *c, PyObject *tmpname,
2828+
compiler_comprehension_generator(struct compiler *c,
28272829
asdl_seq *generators, int gen_index,
28282830
expr_ty elt, expr_ty val, int type)
28292831
{
@@ -2871,7 +2873,7 @@ compiler_comprehension_generator(struct compiler *c, PyObject *tmpname,
28712873
}
28722874

28732875
if (++gen_index < asdl_seq_LEN(generators))
2874-
if (!compiler_comprehension_generator(c, tmpname,
2876+
if (!compiler_comprehension_generator(c,
28752877
generators, gen_index,
28762878
elt, val, type))
28772879
return 0;
@@ -2886,27 +2888,19 @@ compiler_comprehension_generator(struct compiler *c, PyObject *tmpname,
28862888
ADDOP(c, POP_TOP);
28872889
break;
28882890
case COMP_LISTCOMP:
2889-
if (!compiler_nameop(c, tmpname, Load))
2890-
return 0;
28912891
VISIT(c, expr, elt);
2892-
ADDOP(c, LIST_APPEND);
2892+
ADDOP_I(c, LIST_APPEND, gen_index + 1);
28932893
break;
28942894
case COMP_SETCOMP:
2895-
if (!compiler_nameop(c, tmpname, Load))
2896-
return 0;
28972895
VISIT(c, expr, elt);
2898-
ADDOP(c, SET_ADD);
2896+
ADDOP_I(c, SET_ADD, gen_index + 1);
28992897
break;
29002898
case COMP_DICTCOMP:
2901-
if (!compiler_nameop(c, tmpname, Load))
2902-
return 0;
29032899
/* With 'd[k] = v', v is evaluated before k, so we do
2904-
the same. STORE_SUBSCR requires (item, map, key),
2905-
so we still end up ROTing once. */
2900+
the same. */
29062901
VISIT(c, expr, val);
2907-
ADDOP(c, ROT_TWO);
29082902
VISIT(c, expr, elt);
2909-
ADDOP(c, STORE_SUBSCR);
2903+
ADDOP_I(c, MAP_ADD, gen_index + 1);
29102904
break;
29112905
default:
29122906
return 0;
@@ -2932,7 +2926,6 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
29322926
asdl_seq *generators, expr_ty elt, expr_ty val)
29332927
{
29342928
PyCodeObject *co = NULL;
2935-
identifier tmp = NULL;
29362929
expr_ty outermost_iter;
29372930

29382931
outermost_iter = ((comprehension_ty)
@@ -2943,9 +2936,6 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
29432936

29442937
if (type != COMP_GENEXP) {
29452938
int op;
2946-
tmp = compiler_new_tmpname(c);
2947-
if (!tmp)
2948-
goto error_in_scope;
29492939
switch (type) {
29502940
case COMP_LISTCOMP:
29512941
op = BUILD_LIST;
@@ -2963,12 +2953,9 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
29632953
}
29642954

29652955
ADDOP_I(c, op, 0);
2966-
ADDOP(c, DUP_TOP);
2967-
if (!compiler_nameop(c, tmp, Store))
2968-
goto error_in_scope;
29692956
}
29702957

2971-
if (!compiler_comprehension_generator(c, tmp, generators, 0, elt,
2958+
if (!compiler_comprehension_generator(c, generators, 0, elt,
29722959
val, type))
29732960
goto error_in_scope;
29742961

@@ -2984,7 +2971,6 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
29842971
if (!compiler_make_closure(c, co, 0))
29852972
goto error;
29862973
Py_DECREF(co);
2987-
Py_XDECREF(tmp);
29882974

29892975
VISIT(c, expr, outermost_iter);
29902976
ADDOP(c, GET_ITER);
@@ -2994,7 +2980,6 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
29942980
compiler_exit_scope(c);
29952981
error:
29962982
Py_XDECREF(co);
2997-
Py_XDECREF(tmp);
29982983
return 0;
29992984
}
30002985

Python/import.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,10 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *);
8787
3102 (__file__ points to source file)
8888
Python 3.0a4: 3110 (WITH_CLEANUP optimization).
8989
Python 3.0a5: 3130 (lexical exception stacking, including POP_EXCEPT)
90+
Python 3.1a0: 3140 (optimize list, set and dict comprehensions:
91+
change LIST_APPEND and SET_ADD, add MAP_ADD)
9092
*/
91-
#define MAGIC (3130 | ((long)'\r'<<16) | ((long)'\n'<<24))
93+
#define MAGIC (3140 | ((long)'\r'<<16) | ((long)'\n'<<24))
9294

9395
/* Magic word as global; note that _PyImport_Init() can change the
9496
value of this global to accommodate for alterations of how the

0 commit comments

Comments
 (0)