diff options
Diffstat (limited to 'Objects/typeobject.c')
-rw-r--r-- | Objects/typeobject.c | 149 |
1 files changed, 116 insertions, 33 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 1b51971..ced80ec 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -676,7 +676,7 @@ solid_base(PyTypeObject *type) staticforward void object_dealloc(PyObject *); staticforward int object_init(PyObject *, PyObject *, PyObject *); -staticforward int update_slot(PyTypeObject *, PyObject *, PyObject *); +staticforward int update_slot(PyTypeObject *, PyObject *); staticforward void fixup_slot_dispatchers(PyTypeObject *); static PyObject * @@ -1107,7 +1107,7 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) { if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0) return -1; - return update_slot(type, name, value); + return update_slot(type, name); } PyErr_SetString(PyExc_TypeError, "can't set static type attributes"); return -1; @@ -3679,6 +3679,7 @@ typedef struct { int offset; void *function; wrapperfunc wrapper; + PyObject *name_strobj; } slotdef; #undef TPSLOT @@ -3797,9 +3798,7 @@ static slotdef slotdefs[] = { slot_nb_inplace_true_divide, wrap_binaryfunc), TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc), - TPSLOT("__str__", tp_print, NULL, NULL), TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc), - TPSLOT("__repr__", tp_print, NULL, NULL), TPSLOT("__cmp__", tp_compare, _PyObject_SlotCompare, wrap_cmpfunc), TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc), TPSLOT("__call__", tp_call, slot_tp_call, wrap_call), @@ -3827,35 +3826,6 @@ static slotdef slotdefs[] = { {NULL} }; -static int -update_slot(PyTypeObject *type, PyObject *name, PyObject *value) -{ - char *s; - int n; - slotdef *p; - void **ptr; - - assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE); - if (value == NULL) - return 0; /* Can't unset a slot */ - s = PyString_AsString(name); - n = PyString_Size(name); - if (s == NULL || n < 0) { - /* Shouldn't happen, but can't be bothered */ - PyErr_Clear(); - return 0; - } - if (!(s[0] == '_' && s[1] == '_' && s[n-1] == '_' && s[n-2] == '_')) - return 0; - for (p = slotdefs; p->name; p++) { - if (!strcmp(p->name, s)) { - ptr = (void **) ((char *)type + p->offset); - *ptr = p->function; - } - } - return 0; -} - static void ** slotptr(PyTypeObject *type, int offset) { @@ -3883,6 +3853,119 @@ slotptr(PyTypeObject *type, int offset) return (void **)ptr; } +staticforward int recurse_down_subclasses(PyTypeObject *type, int offset); + +static int +update_one_slot(PyTypeObject *type, int offset) +{ + slotdef *p; + PyObject *descr; + PyWrapperDescrObject *d; + void *generic = NULL, *specific = NULL; + int use_generic = 0; + void **ptr; + + for (p = slotdefs; p->name; p++) { + if (p->offset != offset) + continue; + descr = _PyType_Lookup(type, p->name_strobj); + if (descr == NULL) + continue; + ptr = slotptr(type, p->offset); + if (ptr == NULL) + continue; + generic = p->function; + if (descr->ob_type == &PyWrapperDescr_Type) { + d = (PyWrapperDescrObject *)descr; + if (d->d_base->wrapper == p->wrapper && + PyType_IsSubtype(type, d->d_type)) { + if (specific == NULL || + specific == d->d_wrapped) + specific = d->d_wrapped; + else + use_generic = 1; + } + } + else + use_generic = 1; + if (specific && !use_generic) + *ptr = specific; + else + *ptr = generic; + } + if (recurse_down_subclasses(type, offset) < 0) + return -1; + return 0; +} + +static int +recurse_down_subclasses(PyTypeObject *type, int offset) +{ + PyTypeObject *subclass; + PyObject *ref, *subclasses; + int i, n; + + subclasses = type->tp_subclasses; + if (subclasses == NULL) + return 0; + assert(PyList_Check(subclasses)); + n = PyList_GET_SIZE(subclasses); + for (i = 0; i < n; i++) { + ref = PyList_GET_ITEM(subclasses, i); + assert(PyWeakref_CheckRef(ref)); + subclass = (PyTypeObject *)PyWeakref_GET_OBJECT(ref); + if (subclass == NULL) + continue; + assert(PyType_Check(subclass)); + if (update_one_slot(subclass, offset) < 0) + return -1; + } + return 0; +} + +static void +init_name_strobj(void) +{ + slotdef *p; + static int initialized = 0; + + if (initialized) + return; + for (p = slotdefs; p->name; p++) { + p->name_strobj = PyString_InternFromString(p->name); + if (!p->name_strobj) + Py_FatalError("XXX ouch"); + } + initialized = 1; +} + +static void +collect_offsets(PyObject *name, int offsets[]) +{ + slotdef *p; + + init_name_strobj(); + for (p = slotdefs; p->name; p++) { + if (name == p->name_strobj) + *offsets++ = p->offset; + } + *offsets = 0; +} + +static int +update_slot(PyTypeObject *type, PyObject *name) +{ + int offsets[10]; + int *ip; + + collect_offsets(name, offsets); + for (ip = offsets; *ip; ip++) { + if (update_one_slot(type, *ip) < 0) + return -1; + } + return 0; +} + static void fixup_slot_dispatchers(PyTypeObject *type) { |