Index: Lib/opcode.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/opcode.py,v retrieving revision 1.6 diff -u -r1.6 opcode.py --- Lib/opcode.py 21 Jun 2004 16:31:13 -0000 1.6 +++ Lib/opcode.py 20 Feb 2005 15:27:12 -0000 @@ -130,6 +130,7 @@ name_op('DELETE_NAME', 91) # "" def_op('UNPACK_SEQUENCE', 92) # Number of tuple items jrel_op('FOR_ITER', 93) +name_op('DUP_STORE_NAME', 94) # Index in name list name_op('STORE_ATTR', 95) # Index in name list name_op('DELETE_ATTR', 96) # "" @@ -166,6 +167,8 @@ haslocal.append(125) def_op('DELETE_FAST', 126) # Local variable number haslocal.append(126) +def_op('DUP_STORE_FAST', 127) # Local variable number +haslocal.append(127) def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3) def_op('CALL_FUNCTION', 131) # #args + (#kwargs << 8) Index: Include/opcode.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/opcode.h,v retrieving revision 2.45 diff -u -r2.45 opcode.h --- Include/opcode.h 21 Jun 2004 16:31:15 -0000 2.45 +++ Include/opcode.h 20 Feb 2005 15:27:12 -0000 @@ -89,6 +89,7 @@ #define DELETE_NAME 91 /* "" */ #define UNPACK_SEQUENCE 92 /* Number of sequence items */ #define FOR_ITER 93 +#define DUP_STORE_NAME 94 /* Index in name list */ #define STORE_ATTR 95 /* Index in name list */ #define DELETE_ATTR 96 /* "" */ @@ -120,6 +121,7 @@ #define LOAD_FAST 124 /* Local variable number */ #define STORE_FAST 125 /* Local variable number */ #define DELETE_FAST 126 /* Local variable number */ +#define DUP_STORE_FAST 127 /* Local variable number */ #define RAISE_VARARGS 130 /* Number of raise arguments (1, 2 or 3) */ /* CALL_FUNCTION_XXX opcodes defined below depend on this definition */ Index: Python/ceval.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/ceval.c,v retrieving revision 2.421 diff -u -r2.421 ceval.c --- Python/ceval.c 18 Jan 2005 15:56:11 -0000 2.421 +++ Python/ceval.c 20 Feb 2005 15:27:14 -0000 @@ -926,6 +926,12 @@ Py_DECREF(v); goto fast_next_opcode; + case DUP_STORE_FAST: + v = TOP(); + Py_INCREF(v); + SETLOCAL(oparg, v); + goto fast_next_opcode; + case ROT_TWO: v = TOP(); w = SECOND(); @@ -1712,6 +1718,23 @@ PyObject_REPR(w)); break; + case DUP_STORE_NAME: + w = GETITEM(names, oparg); + v = TOP(); + if ((x = f->f_locals) != NULL) { + if (PyDict_CheckExact(x)) + err = PyDict_SetItem(x, w, v); + else + err = PyObject_SetItem(x, w, v); + if (err == 0) continue; + break; + } + STACKADJ(-1); + PyErr_Format(PyExc_SystemError, + "no locals found when storing %s", + PyObject_REPR(w)); + break; + case DELETE_NAME: w = GETITEM(names, oparg); if ((x = f->f_locals) != NULL) { Index: Python/compile.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/compile.c,v retrieving revision 2.345 diff -u -r2.345 compile.c --- Python/compile.c 20 Feb 2005 12:41:32 -0000 2.345 +++ Python/compile.c 20 Feb 2005 15:27:17 -0000 @@ -744,6 +744,42 @@ } break; + /* Replace STORE_FAST x LOAD_FAST x with DUP_STORE_FAST x */ + case STORE_FAST: + j = GETARG(codestr, i); + if (codestr[i+3] == LOAD_FAST && + GETARG(codestr, i+3) == j && + ISBASICBLOCK(blocks,i,6)) { + codestr[i] = DUP_STORE_FAST; + memset(codestr+i+3, NOP, 3); + } + break; + + /* Replace STORE_NAME x LOAD_NAME x with DUP_STORE_NAME x */ + case STORE_NAME: + j = GETARG(codestr, i); + if (codestr[i+3] == LOAD_NAME && + GETARG(codestr, i+3) == j && + ISBASICBLOCK(blocks,i,6)) { + codestr[i] = DUP_STORE_NAME; + memset(codestr+i+3, NOP, 3); + } + break; + + /* Replace DUP_TOP STORE_NAME/FAST with DUP_STORE_NAME/FAST. + This arises in chained assignments like: x = y = f(). */ + case DUP_TOP: + if (codestr[i+1] == STORE_FAST && + ISBASICBLOCK(blocks,i,4)) { + codestr[i] = NOP; + codestr[i+1] = DUP_STORE_FAST; + } else if (codestr[i+1] == STORE_NAME && + ISBASICBLOCK(blocks,i,4)) { + codestr[i] = NOP; + codestr[i+1] = DUP_STORE_NAME; + } + break; + /* Skip over LOAD_CONST trueconst JUMP_IF_FALSE xx POP_TOP */ case LOAD_CONST: cumlc = lastlc + 1; Index: Python/import.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/import.c,v retrieving revision 2.240 diff -u -r2.240 import.c --- Python/import.c 7 Oct 2004 06:46:25 -0000 2.240 +++ Python/import.c 20 Feb 2005 15:27:18 -0000 @@ -50,8 +50,9 @@ Python 2.4a0: 62041 Python 2.4a3: 62051 Python 2.4b1: 62061 + Python 2.5a0 62071 */ -#define MAGIC (62061 | ((long)'\r'<<16) | ((long)'\n'<<24)) +#define MAGIC (62071 | ((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 Index: Lib/test/test_peepholer.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_peepholer.py,v retrieving revision 1.12 diff -u -r1.12 test_peepholer.py --- Lib/test/test_peepholer.py 20 Feb 2005 12:46:54 -0000 1.12 +++ Lib/test/test_peepholer.py 20 Feb 2005 15:27:18 -0000 @@ -161,7 +161,23 @@ self.assert_('(None)' not in asm) self.assertEqual(asm.split().count('RETURN_VALUE'), 1) + def test_dup_store(self): + def f(): + x = 3 + y = x + asm = disassemble(f) + self.assert_('DUP_STORE_FAST' in asm) + asm = dis_single('x=3; y=x') + self.assert_('DUP_STORE_NAME' in asm) + + def f(): + x = y = 1 + asm = disassemble(f) + self.assert_('DUP_STORE_FAST' in asm) + + asm = dis_single('x = y = 1') + self.assert_('DUP_STORE_NAME' in asm) def test_main(verbose=None): import sys