summaryrefslogtreecommitdiff
path: root/Objects/codeobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/codeobject.c')
-rw-r--r--Objects/codeobject.c211
1 files changed, 193 insertions, 18 deletions
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index 353f414a38..9df87b04f8 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -11,21 +11,21 @@ static int
all_name_chars(PyObject *o)
{
static char ok_name_char[256];
- static unsigned char *name_chars = (unsigned char *)NAME_CHARS;
- PyUnicodeObject *u = (PyUnicodeObject *)o;
- const unsigned char *s;
+ static const unsigned char *name_chars = (unsigned char *)NAME_CHARS;
+ const unsigned char *s, *e;
- if (!PyUnicode_Check(o) || PyUnicode_READY(u) == -1 ||
- PyUnicode_MAX_CHAR_VALUE(u) >= 128)
+ if (!PyUnicode_Check(o) || PyUnicode_READY(o) == -1 ||
+ !PyUnicode_IS_ASCII(o))
return 0;
if (ok_name_char[*name_chars] == 0) {
- unsigned char *p;
+ const unsigned char *p;
for (p = name_chars; *p; p++)
ok_name_char[*p] = 1;
}
- s = PyUnicode_1BYTE_DATA(u);
- while (*s) {
+ s = PyUnicode_1BYTE_DATA(o);
+ e = s + PyUnicode_GET_LENGTH(o);
+ while (s != e) {
if (ok_name_char[*s++] == 0)
return 0;
}
@@ -46,6 +46,50 @@ intern_strings(PyObject *tuple)
}
}
+/* Intern selected string constants */
+static int
+intern_string_constants(PyObject *tuple)
+{
+ int modified = 0;
+ Py_ssize_t i;
+
+ for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) {
+ PyObject *v = PyTuple_GET_ITEM(tuple, i);
+ if (PyUnicode_CheckExact(v)) {
+ if (all_name_chars(v)) {
+ PyObject *w = v;
+ PyUnicode_InternInPlace(&v);
+ if (w != v) {
+ PyTuple_SET_ITEM(tuple, i, v);
+ modified = 1;
+ }
+ }
+ }
+ else if (PyTuple_CheckExact(v)) {
+ intern_string_constants(v);
+ }
+ else if (PyFrozenSet_CheckExact(v)) {
+ PyObject *tmp = PySequence_Tuple(v);
+ if (tmp == NULL) {
+ PyErr_Clear();
+ continue;
+ }
+ if (intern_string_constants(tmp)) {
+ v = PyFrozenSet_New(tmp);
+ if (v == NULL) {
+ PyErr_Clear();
+ }
+ else {
+ PyTuple_SET_ITEM(tuple, i, v);
+ modified = 1;
+ }
+ }
+ Py_DECREF(tmp);
+ }
+ }
+ return modified;
+}
+
PyCodeObject *
PyCode_New(int argcount, int kwonlyargcount,
@@ -84,13 +128,7 @@ PyCode_New(int argcount, int kwonlyargcount,
intern_strings(varnames);
intern_strings(freevars);
intern_strings(cellvars);
- /* Intern selected string constants */
- for (i = PyTuple_GET_SIZE(consts); --i >= 0; ) {
- PyObject *v = PyTuple_GetItem(consts, i);
- if (!all_name_chars(v))
- continue;
- PyUnicode_InternInPlace(&PyTuple_GET_ITEM(consts, i));
- }
+ intern_string_constants(consts);
/* Create mapping between cells and arguments if needed. */
if (n_cellvars) {
Py_ssize_t total_args = argcount + kwonlyargcount +
@@ -384,7 +422,7 @@ code_sizeof(PyCodeObject *co, void *unused)
{
Py_ssize_t res;
- res = sizeof(PyCodeObject);
+ res = _PyObject_SIZE(Py_TYPE(co));
if (co->co_cell2arg != NULL && co->co_cellvars != NULL)
res += PyTuple_GET_SIZE(co->co_cellvars) * sizeof(unsigned char);
return PyLong_FromSsize_t(res);
@@ -409,11 +447,135 @@ code_repr(PyCodeObject *co)
}
}
+PyObject*
+_PyCode_ConstantKey(PyObject *op)
+{
+ PyObject *key;
+
+ /* Py_None and Py_Ellipsis are singleton */
+ if (op == Py_None || op == Py_Ellipsis
+ || PyLong_CheckExact(op)
+ || PyBool_Check(op)
+ || PyBytes_CheckExact(op)
+ || PyUnicode_CheckExact(op)
+ /* code_richcompare() uses _PyCode_ConstantKey() internally */
+ || PyCode_Check(op)) {
+ key = PyTuple_Pack(2, Py_TYPE(op), op);
+ }
+ else if (PyFloat_CheckExact(op)) {
+ double d = PyFloat_AS_DOUBLE(op);
+ /* 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, Py_TYPE(op), op, Py_None);
+ else
+ key = PyTuple_Pack(2, Py_TYPE(op), op);
+ }
+ else if (PyComplex_CheckExact(op)) {
+ 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(op);
+ 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;
+ /* use True, False and None singleton as tags for the real and imag
+ * sign, to make tuples different */
+ if (real_negzero && imag_negzero) {
+ key = PyTuple_Pack(3, Py_TYPE(op), op, Py_True);
+ }
+ else if (imag_negzero) {
+ key = PyTuple_Pack(3, Py_TYPE(op), op, Py_False);
+ }
+ else if (real_negzero) {
+ key = PyTuple_Pack(3, Py_TYPE(op), op, Py_None);
+ }
+ else {
+ key = PyTuple_Pack(2, Py_TYPE(op), op);
+ }
+ }
+ else if (PyTuple_CheckExact(op)) {
+ Py_ssize_t i, len;
+ PyObject *tuple;
+
+ len = PyTuple_GET_SIZE(op);
+ tuple = PyTuple_New(len);
+ if (tuple == NULL)
+ return NULL;
+
+ for (i=0; i < len; i++) {
+ PyObject *item, *item_key;
+
+ item = PyTuple_GET_ITEM(op, i);
+ item_key = _PyCode_ConstantKey(item);
+ if (item_key == NULL) {
+ Py_DECREF(tuple);
+ return NULL;
+ }
+
+ PyTuple_SET_ITEM(tuple, i, item_key);
+ }
+
+ key = PyTuple_Pack(3, Py_TYPE(op), op, tuple);
+ Py_DECREF(tuple);
+ }
+ else if (PyFrozenSet_CheckExact(op)) {
+ Py_ssize_t pos = 0;
+ PyObject *item;
+ Py_hash_t hash;
+ Py_ssize_t i, len;
+ PyObject *tuple, *set;
+
+ len = PySet_GET_SIZE(op);
+ tuple = PyTuple_New(len);
+ if (tuple == NULL)
+ return NULL;
+
+ i = 0;
+ while (_PySet_NextEntry(op, &pos, &item, &hash)) {
+ PyObject *item_key;
+
+ item_key = _PyCode_ConstantKey(item);
+ if (item_key == NULL) {
+ Py_DECREF(tuple);
+ return NULL;
+ }
+
+ assert(i < len);
+ PyTuple_SET_ITEM(tuple, i, item_key);
+ i++;
+ }
+ set = PyFrozenSet_New(tuple);
+ Py_DECREF(tuple);
+ if (set == NULL)
+ return NULL;
+
+ key = PyTuple_Pack(3, Py_TYPE(op), op, set);
+ Py_DECREF(set);
+ return key;
+ }
+ else {
+ /* for other types, use the object identifier as a unique identifier
+ * to ensure that they are seen as unequal. */
+ PyObject *obj_id = PyLong_FromVoidPtr(op);
+ if (obj_id == NULL)
+ return NULL;
+
+ key = PyTuple_Pack(3, Py_TYPE(op), op, obj_id);
+ Py_DECREF(obj_id);
+ }
+ 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 +601,21 @@ code_richcompare(PyObject *self, PyObject *other, int op)
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);
@@ -581,7 +756,7 @@ _PyCode_CheckLineNumber(PyCodeObject* co, int lasti, PyAddrPair *bounds)
/* possible optimization: if f->f_lasti == instr_ub
(likely to be a common case) then we already know
instr_lb -- if we stored the matching value of p
- somwhere we could skip the first while loop. */
+ somewhere we could skip the first while loop. */
/* See lnotab_notes.txt for the description of
co_lnotab. A point to remember: increments to p