diff -r c25b54be90ee Python/peephole.c --- a/Python/peephole.c Wed Mar 09 18:22:33 2011 -0500 +++ b/Python/peephole.c Thu Mar 10 20:00:02 2011 -0500 @@ -23,6 +23,49 @@ #define ISBASICBLOCK(blocks, start, bytes) \ (blocks[start]==blocks[start+bytes-1]) +static int +number_as_complex(PyObject *num, Py_complex *z) +{ + if (PyFloat_Check(num)) { + z->real = PyFloat_AS_DOUBLE(num); + z->imag = 0; + return 1; + } + if (PyComplex_Check(num)) { + *z = PyComplex_AsCComplex(num); + return 1; + } + return 0; +} + +/* Helper to add a constant to constants list. + Reuses existing constant if possible, otherwise appends a new one. */ +static Py_ssize_t +add_const(PyObject *consts, PyObject *newconst) +{ + Py_ssize_t i, size; + PyObject *item; + Py_complex z1, z2; + + size = PyList_GET_SIZE(consts); + for (i = 0; i < size; i++) { + item = PyList_GET_ITEM(consts, i); + if (Py_TYPE(item) == Py_TYPE(newconst) && + PyObject_RichCompareBool(item, newconst, Py_EQ) == 1) { + /* Special handling for -0.0 in float in complex. */ + if (number_as_complex(item, &z1) && + number_as_complex(newconst, &z2) && + (copysign(1.0, z1.real) != copysign(1.0, z2.real) || + copysign(1.0, z1.imag) != copysign(1.0, z2.imag))) + continue; + return i; + } + } + if (PyList_Append(consts, newconst)) + return -1; + return size; +} + /* Replace LOAD_CONST c1. LOAD_CONST c2 ... LOAD_CONST cn BUILD_TUPLE n with LOAD_CONST (c1, c2, ... cn). The consts table must still be in list form so that the @@ -36,7 +79,7 @@ tuple_of_constants(unsigned char *codestr, Py_ssize_t n, PyObject *consts) { PyObject *newconst, *constant; - Py_ssize_t i, arg, len_consts; + Py_ssize_t i, arg, len_consts, newidx; /* Pre-conditions */ assert(PyList_CheckExact(consts)); @@ -69,7 +112,8 @@ } /* Append folded constant onto consts */ - if (PyList_Append(consts, newconst)) { + newidx = add_const(consts, newconst); + if (newidx < 0) { Py_DECREF(newconst); return 0; } @@ -79,7 +123,7 @@ add a new LOAD_CONST newconst on top of the BUILD_TUPLE n */ memset(codestr, NOP, n*3); codestr[n*3] = LOAD_CONST; - SETARG(codestr, (n*3), len_consts); + SETARG(codestr, (n*3), newidx); return 1; } @@ -97,7 +141,7 @@ fold_binops_on_constants(unsigned char *codestr, PyObject *consts) { PyObject *newconst, *v, *w; - Py_ssize_t len_consts, size; + Py_ssize_t newidx, size; int opcode; /* Pre-conditions */ @@ -172,8 +216,8 @@ } /* Append folded constant into consts table */ - len_consts = PyList_GET_SIZE(consts); - if (PyList_Append(consts, newconst)) { + newidx = add_const(consts, newconst); + if (newidx < 0) { Py_DECREF(newconst); return 0; } @@ -182,7 +226,7 @@ /* Write NOP NOP NOP NOP LOAD_CONST newconst */ memset(codestr, NOP, 4); codestr[4] = LOAD_CONST; - SETARG(codestr, 4, len_consts); + SETARG(codestr, 4, newidx); return 1; } @@ -190,7 +234,7 @@ fold_unaryops_on_constants(unsigned char *codestr, PyObject *consts) { PyObject *newconst=NULL, *v; - Py_ssize_t len_consts; + Py_ssize_t newidx; int opcode; /* Pre-conditions */ @@ -226,8 +270,8 @@ } /* Append folded constant into consts table */ - len_consts = PyList_GET_SIZE(consts); - if (PyList_Append(consts, newconst)) { + newidx = add_const(consts, newconst); + if (newidx < 0) { Py_DECREF(newconst); return 0; } @@ -236,7 +280,7 @@ /* Write NOP LOAD_CONST newconst */ codestr[0] = NOP; codestr[1] = LOAD_CONST; - SETARG(codestr, 1, len_consts); + SETARG(codestr, 1, newidx); return 1; } @@ -284,9 +328,9 @@ /* Helper to replace LOAD_NAME None/True/False with LOAD_CONST Returns: 0 if no change, 1 if change, -1 if error */ static int -load_global(unsigned char *codestr, Py_ssize_t i, char *name, PyObject *consts) +load_global(unsigned char *codestr, char *name, PyObject *consts) { - Py_ssize_t j; + Py_ssize_t newidx; PyObject *obj; if (name == NULL) return 0; @@ -298,17 +342,11 @@ obj = Py_False; else return 0; - for (j = 0; j < PyList_GET_SIZE(consts); j++) { - if (PyList_GET_ITEM(consts, j) == obj) - break; - } - if (j == PyList_GET_SIZE(consts)) { - if (PyList_Append(consts, obj) < 0) - return -1; - } - assert(PyList_GET_ITEM(consts, j) == obj); - codestr[i] = LOAD_CONST; - SETARG(codestr, i, j); + newidx = add_const(consts, obj); + if (newidx < 0) + return -1; + codestr[0] = LOAD_CONST; + SETARG(codestr, 0, newidx); return 1; } @@ -427,7 +465,7 @@ case LOAD_GLOBAL: j = GETARG(codestr, i); name = _PyUnicode_AsString(PyTuple_GET_ITEM(names, j)); - h = load_global(codestr, i, name, consts); + h = load_global(&codestr[i], name, consts); if (h < 0) goto exitError; else if (h == 0) @@ -520,7 +558,7 @@ case UNARY_POSITIVE: if (lastlc >= 1 && ISBASICBLOCK(blocks, i-3, 4) && - fold_unaryops_on_constants(&codestr[i-3], consts)) { + fold_unaryops_on_constants(&codestr[i-3], consts)) { i -= 2; assert(codestr[i] == LOAD_CONST); cumlc = 1;