Index: Python/peephole.c =================================================================== --- Python/peephole.c (revision 72970) +++ Python/peephole.c (working copy) @@ -30,7 +30,7 @@ The consts table must still be in list form so that the new constant (c1, c2, ... cn) can be appended. Called with codestr pointing to the first LOAD_CONST. - Bails out with no change if one or more of the LOAD_CONSTs is missing. + Bails out with no change if one or more of the LOAD_CONSTs is missing. Also works for BUILD_LIST when followed by an "in" or "not in" test. */ static int @@ -78,8 +78,8 @@ with LOAD_CONST binop(c1,c2) The consts table must still be in list form so that the new constant can be appended. - Called with codestr pointing to the first LOAD_CONST. - Abandons the transformation if the folding fails (i.e. 1+'a'). + Called with codestr pointing to the first LOAD_CONST. + Abandons the transformation if the folding fails (i.e. 1+'a'). If the new constant is a sequence, only folds when the size is below a threshold value. That keeps pyc files from becoming large in the presence of code like: (None,)*1000. @@ -180,11 +180,12 @@ } static int -fold_unaryops_on_constants(unsigned char *codestr, PyObject *consts) +fold_unaryops_on_constants(unsigned char *codestr, PyObject *consts, + PyObject *names) { PyObject *newconst=NULL, *v; Py_ssize_t len_consts; - int opcode; + int opcode, i = 1, j; /* Pre-conditions */ assert(PyList_CheckExact(consts)); @@ -205,6 +206,11 @@ case UNARY_INVERT: newconst = PyNumber_Invert(v); break; + case LOAD_ATTR: + i = 3; + newconst = PyObject_GetAttr(v, + PyTuple_GET_ITEM(names, GETARG(codestr, 3))); + break; default: /* Called with an unknown opcode */ PyErr_Format(PyExc_SystemError, @@ -226,9 +232,11 @@ Py_DECREF(newconst); /* Write NOP LOAD_CONST newconst */ - codestr[0] = NOP; - codestr[1] = LOAD_CONST; - SETARG(codestr, 1, len_consts); + for (j = 0; j < i; j++) { + codestr[j] = NOP; + } + codestr[i] = LOAD_CONST; + SETARG(codestr, i, len_consts); return 1; } @@ -274,18 +282,18 @@ } /* Perform basic peephole optimizations to components of a code object. - The consts object should still be in list form to allow new constants + The consts object should still be in list form to allow new constants to be appended. To keep the optimizer simple, it bails out (does nothing) for code - containing extended arguments or that has a length over 32,700. That + containing extended arguments or that has a length over 32,700. That allows us to avoid overflow and sign issues. Likewise, it bails when the lineno table has complex encoding for gaps >= 255. Optimizations are restricted to simple transformations occuring within a - single basic block. All transformations keep the code size the same or - smaller. For those that reduce size, the gaps are initially filled with - NOPs. Later those NOPs are removed and the jump addresses retargeted in + single basic block. All transformations keep the code size the same or + smaller. For those that reduce size, the gaps are initially filled with + NOPs. Later those NOPs are removed and the jump addresses retargeted in a single pass. Line numbering is adjusted accordingly. */ PyObject * @@ -324,7 +332,7 @@ codestr = (unsigned char *)PyMem_Malloc(codelen); if (codestr == NULL) goto exitUnchanged; - codestr = (unsigned char *)memcpy(codestr, + codestr = (unsigned char *)memcpy(codestr, PyString_AS_STRING(code), codelen); /* Verify that RETURN_VALUE terminates the codestring. This allows @@ -353,7 +361,7 @@ cumlc = 0; switch (opcode) { - /* Replace UNARY_NOT POP_JUMP_IF_FALSE + /* Replace UNARY_NOT POP_JUMP_IF_FALSE with POP_JUMP_IF_TRUE */ case UNARY_NOT: if (codestr[i+1] != POP_JUMP_IF_FALSE @@ -373,7 +381,7 @@ case COMPARE_OP: j = GETARG(codestr, i); if (j < 6 || j > 9 || - codestr[i+3] != UNARY_NOT || + codestr[i+3] != UNARY_NOT || !ISBASICBLOCK(blocks,i,4)) continue; SETARG(codestr, i, (j^1)); @@ -394,7 +402,7 @@ } if (j == PyList_GET_SIZE(consts)) { if (PyList_Append(consts, Py_None) == -1) - goto exitUnchanged; + goto exitUnchanged; } assert(PyList_GET_ITEM(consts, j) == Py_None); codestr[i] = LOAD_CONST; @@ -427,10 +435,10 @@ h = i - 3 * j; if (h >= 0 && j <= lastlc && - ((opcode == BUILD_TUPLE && + ((opcode == BUILD_TUPLE && ISBASICBLOCK(blocks, h, 3*(j+1))) || - (opcode == BUILD_LIST && - codestr[i+3]==COMPARE_OP && + (opcode == BUILD_LIST && + codestr[i+3]==COMPARE_OP && ISBASICBLOCK(blocks, h, 3*(j+2)) && (GETARG(codestr,i+3)==6 || GETARG(codestr,i+3)==7))) && @@ -484,10 +492,13 @@ case UNARY_NEGATIVE: case UNARY_CONVERT: case UNARY_INVERT: + case LOAD_ATTR: if (lastlc >= 1 && ISBASICBLOCK(blocks, i-3, 4) && - fold_unaryops_on_constants(&codestr[i-3], consts)) { - i -= 2; + fold_unaryops_on_constants(&codestr[i-3], consts, names)) { + if (opcode != LOAD_ATTR) { + i -= 2; + } assert(codestr[i] == LOAD_CONST); cumlc = 1; }