diff -r 314eeb71b161 Include/code.h --- a/Include/code.h Mon Dec 14 00:22:10 2015 +0100 +++ b/Include/code.h Mon Dec 14 18:30:22 2015 +0100 @@ -114,6 +114,8 @@ typedef struct _addr_pair { #ifndef Py_LIMITED_API PyAPI_FUNC(int) _PyCode_CheckLineNumber(PyCodeObject* co, int lasti, PyAddrPair *bounds); + +PyAPI_FUNC(PyObject*) _PyCode_ConstantKey(PyObject *o); #endif PyAPI_FUNC(PyObject*) PyCode_Optimize(PyObject *code, PyObject* consts, diff -r 314eeb71b161 Objects/codeobject.c --- a/Objects/codeobject.c Mon Dec 14 00:22:10 2015 +0100 +++ b/Objects/codeobject.c Mon Dec 14 18:30:22 2015 +0100 @@ -409,11 +409,114 @@ code_repr(PyCodeObject *co) } } +PyObject* +_PyCode_ConstantKey(PyObject *o) +{ + PyObject *key; + + /* necessary to make sure types aren't coerced (e.g., float and complex) */ + /* _and_ to distinguish 0.0 from -0.0 e.g. on IEEE platforms */ + if (PyFloat_Check(o)) { + double d = PyFloat_AS_DOUBLE(o); + /* all we need is to make the tuple different in either the 0.0 + * or -0.0 case from all others, just to avoid the "coercion". + */ + if (d == 0.0 && copysign(1.0, d) < 0.0) + key = PyTuple_Pack(3, o, o->ob_type, Py_None); + else + key = PyTuple_Pack(2, o, o->ob_type); + } + else if (PyComplex_Check(o)) { + Py_complex z; + int real_negzero, imag_negzero; + /* For the complex case we must make complex(x, 0.) + different from complex(x, -0.) and complex(0., y) + different from complex(-0., y), for any x and y. + All four complex zeros must be distinguished.*/ + z = PyComplex_AsCComplex(o); + real_negzero = z.real == 0.0 && copysign(1.0, z.real) < 0.0; + imag_negzero = z.imag == 0.0 && copysign(1.0, z.imag) < 0.0; + if (real_negzero && imag_negzero) { + key = PyTuple_Pack(5, o, o->ob_type, + Py_None, Py_None, Py_None); + } + else if (imag_negzero) { + key = PyTuple_Pack(4, o, o->ob_type, Py_None, Py_None); + } + else if (real_negzero) { + key = PyTuple_Pack(3, o, o->ob_type, Py_None); + } + else { + key = PyTuple_Pack(2, o, o->ob_type); + } + } + else if (PyTuple_Check(o)) { + Py_ssize_t i, len; + PyObject *keys; + + len = PyTuple_GET_SIZE(o); + keys = PyTuple_New(len); + if (keys == NULL) + return NULL; + + for (i=0; i < len; i++) { + PyObject *item, *item_key; + + item = PyTuple_GET_ITEM(o, i); + item_key = _PyCode_ConstantKey(item); + if (item_key == NULL) { + Py_DECREF(keys); + return NULL; + } + + PyTuple_SET_ITEM(keys, i, item_key); + } + + key = PyTuple_Pack(2, o, keys); + } + else if (PyAnySet_CheckExact(o)) { + Py_ssize_t pos = 0; + PyObject *item; + Py_hash_t hash; + Py_ssize_t i, len; + PyObject *keys; + + len = PySet_GET_SIZE(o); + keys = PyTuple_New(len); + if (keys == NULL) + return NULL; + + i = 0; + while (_PySet_NextEntry(o, &pos, &item, &hash)) { + PyObject *item_key; + + item_key = _PyCode_ConstantKey(item); + if (item_key == NULL) { + Py_DECREF(keys); + return NULL; + } + + PyTuple_SET_ITEM(keys, i, item_key); + i++; + if (i >= len) { + /* set size changed during iteration, ignore */ + break; + } + } + return keys; + } + else { + key = PyTuple_Pack(2, o, o->ob_type); + } + return key; +} + static PyObject * code_richcompare(PyObject *self, PyObject *other, int op) { PyCodeObject *co, *cp; int eq; + PyObject *consts1, *consts2; PyObject *res; if ((op != Py_EQ && op != Py_NE) || @@ -439,8 +542,21 @@ code_richcompare(PyObject *self, PyObjec if (!eq) goto unequal; eq = PyObject_RichCompareBool(co->co_code, cp->co_code, Py_EQ); if (eq <= 0) goto unequal; - eq = PyObject_RichCompareBool(co->co_consts, cp->co_consts, Py_EQ); + + /* compare constants */ + consts1 = _PyCode_ConstantKey(co->co_consts); + if (!consts1) + return NULL; + consts2 = _PyCode_ConstantKey(cp->co_consts); + if (!consts2) { + Py_DECREF(consts1); + return NULL; + } + eq = PyObject_RichCompareBool(consts1, consts2, Py_EQ); + Py_DECREF(consts1); + Py_DECREF(consts2); if (eq <= 0) goto unequal; + eq = PyObject_RichCompareBool(co->co_names, cp->co_names, Py_EQ); if (eq <= 0) goto unequal; eq = PyObject_RichCompareBool(co->co_varnames, cp->co_varnames, Py_EQ); diff -r 314eeb71b161 Python/compile.c --- a/Python/compile.c Mon Dec 14 00:22:10 2015 +0100 +++ b/Python/compile.c Mon Dec 14 18:30:22 2015 +0100 @@ -1105,47 +1105,8 @@ compiler_add_o(struct compiler *c, PyObj { PyObject *t, *v; Py_ssize_t arg; - double d; - - /* necessary to make sure types aren't coerced (e.g., float and complex) */ - /* _and_ to distinguish 0.0 from -0.0 e.g. on IEEE platforms */ - if (PyFloat_Check(o)) { - d = PyFloat_AS_DOUBLE(o); - /* all we need is to make the tuple different in either the 0.0 - * or -0.0 case from all others, just to avoid the "coercion". - */ - if (d == 0.0 && copysign(1.0, d) < 0.0) - t = PyTuple_Pack(3, o, o->ob_type, Py_None); - else - t = PyTuple_Pack(2, o, o->ob_type); - } - else if (PyComplex_Check(o)) { - Py_complex z; - int real_negzero, imag_negzero; - /* For the complex case we must make complex(x, 0.) - different from complex(x, -0.) and complex(0., y) - different from complex(-0., y), for any x and y. - All four complex zeros must be distinguished.*/ - z = PyComplex_AsCComplex(o); - real_negzero = z.real == 0.0 && copysign(1.0, z.real) < 0.0; - imag_negzero = z.imag == 0.0 && copysign(1.0, z.imag) < 0.0; - if (real_negzero && imag_negzero) { - t = PyTuple_Pack(5, o, o->ob_type, - Py_None, Py_None, Py_None); - } - else if (imag_negzero) { - t = PyTuple_Pack(4, o, o->ob_type, Py_None, Py_None); - } - else if (real_negzero) { - t = PyTuple_Pack(3, o, o->ob_type, Py_None); - } - else { - t = PyTuple_Pack(2, o, o->ob_type); - } - } - else { - t = PyTuple_Pack(2, o, o->ob_type); - } + + t = _PyCode_ConstantKey(o); if (t == NULL) return -1;