Mercurial > cpython-lru_cache-weakref
diff Objects/typeobject.c @ 23687:c4d2d305fd98 2.2
Backport to 2.2.x:
Address SF bug 519621: slots weren't traversed by GC.
While I was at it, I added a tp_clear handler and changed the
tp_dealloc handler to use the clear_slots helper for the tp_clear
handler.
Also set mp->flags = READONLY for the __weakref__ pseudo-slot.
[Note that I am *not* backporting the part of that patch that
tightened the __slot__ rules.]
| author | Guido van Rossum <guido@python.org> |
|---|---|
| date | Tue, 04 Jun 2002 21:19:55 +0000 |
| parents | a34523121cf4 |
| children | 2c8ea7f9a3ce |
line wrap: on
line diff
--- a/Objects/typeobject.c Tue Jun 04 16:29:24 2002 +0000 +++ b/Objects/typeobject.c Tue Jun 04 21:19:55 2002 +0000 @@ -4,6 +4,20 @@ #include "Python.h" #include "structmember.h" +#include <ctype.h> + +/* The *real* layout of a type object when allocated on the heap */ +/* XXX Should we publish this in a header file? */ +typedef struct { + PyTypeObject type; + PyNumberMethods as_number; + PySequenceMethods as_sequence; + PyMappingMethods as_mapping; + PyBufferProcs as_buffer; + PyObject *name, *slots; + PyMemberDef members[1]; +} etype; + static PyMemberDef type_members[] = { {"__basicsize__", T_INT, offsetof(PyTypeObject,tp_basicsize),READONLY}, {"__itemsize__", T_INT, offsetof(PyTypeObject, tp_itemsize), READONLY}, @@ -223,16 +237,43 @@ /* Helpers for subtyping */ static int +traverse_slots(PyTypeObject *type, PyObject *self, visitproc visit, void *arg) +{ + int i, n; + PyMemberDef *mp; + + n = type->ob_size; + mp = ((etype *)type)->members; + for (i = 0; i < n; i++, mp++) { + if (mp->type == T_OBJECT_EX) { + char *addr = (char *)self + mp->offset; + PyObject *obj = *(PyObject **)addr; + if (obj != NULL) { + int err = visit(obj, arg); + if (err) + return err; + } + } + } + return 0; +} + +static int subtype_traverse(PyObject *self, visitproc visit, void *arg) { PyTypeObject *type, *base; - traverseproc f; - int err; - - /* Find the nearest base with a different tp_traverse */ + traverseproc basetraverse; + + /* Find the nearest base with a different tp_traverse, + and traverse slots while we're at it */ type = self->ob_type; - base = type->tp_base; - while ((f = base->tp_traverse) == subtype_traverse) { + base = type; + while ((basetraverse = base->tp_traverse) == subtype_traverse) { + if (base->ob_size) { + int err = traverse_slots(base, self, visit, arg); + if (err) + return err; + } base = base->tp_base; assert(base); } @@ -240,14 +281,63 @@ if (type->tp_dictoffset != base->tp_dictoffset) { PyObject **dictptr = _PyObject_GetDictPtr(self); if (dictptr && *dictptr) { - err = visit(*dictptr, arg); + int err = visit(*dictptr, arg); if (err) return err; } } - if (f) - return f(self, visit, arg); + if (basetraverse) + return basetraverse(self, visit, arg); + return 0; +} + +static void +clear_slots(PyTypeObject *type, PyObject *self) +{ + int i, n; + PyMemberDef *mp; + + n = type->ob_size; + mp = ((etype *)type)->members; + for (i = 0; i < n; i++, mp++) { + if (mp->type == T_OBJECT_EX && !(mp->flags & READONLY)) { + char *addr = (char *)self + mp->offset; + PyObject *obj = *(PyObject **)addr; + if (obj != NULL) { + Py_DECREF(obj); + *(PyObject **)addr = NULL; + } + } + } +} + +static int +subtype_clear(PyObject *self) +{ + PyTypeObject *type, *base; + inquiry baseclear; + + /* Find the nearest base with a different tp_clear + and clear slots while we're at it */ + type = self->ob_type; + base = type; + while ((baseclear = base->tp_clear) == subtype_clear) { + if (base->ob_size) + clear_slots(base, self); + base = base->tp_base; + assert(base); + } + + if (type->tp_dictoffset != base->tp_dictoffset) { + PyObject **dictptr = _PyObject_GetDictPtr(self); + if (dictptr && *dictptr) { + PyDict_Clear(*dictptr); + } + } + + if (baseclear) + return baseclear(self); return 0; } @@ -326,41 +416,24 @@ subtype_dealloc(PyObject *self) { PyTypeObject *type, *base; - destructor f; + destructor basedealloc; /* This exists so we can DECREF self->ob_type */ if (call_finalizer(self) < 0) return; - /* Find the nearest base with a different tp_dealloc */ + /* Find the nearest base with a different tp_dealloc + and clear slots while we're at it */ type = self->ob_type; - base = type->tp_base; - while ((f = base->tp_dealloc) == subtype_dealloc) { + base = type; + while ((basedealloc = base->tp_dealloc) == subtype_dealloc) { + if (base->ob_size) + clear_slots(base, self); base = base->tp_base; assert(base); } - /* Clear __slots__ variables */ - if (type->tp_basicsize != base->tp_basicsize && - type->tp_itemsize == 0) - { - char *addr = ((char *)self); - char *p = addr + base->tp_basicsize; - char *q = addr + type->tp_basicsize; - for (; p < q; p += sizeof(PyObject *)) { - PyObject **pp; - if (p == addr + type->tp_dictoffset || - p == addr + type->tp_weaklistoffset) - continue; - pp = (PyObject **)p; - if (*pp != NULL) { - Py_DECREF(*pp); - *pp = NULL; - } - } - } - /* If we added a dict, DECREF it */ if (type->tp_dictoffset && !base->tp_dictoffset) { PyObject **dictptr = _PyObject_GetDictPtr(self); @@ -382,8 +455,8 @@ _PyObject_GC_UNTRACK(self); /* Call the base tp_dealloc() */ - assert(f); - f(self); + assert(basedealloc); + basedealloc(self); /* Can't reference self beyond this point */ if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) { @@ -393,16 +466,6 @@ staticforward PyTypeObject *solid_base(PyTypeObject *type); -typedef struct { - PyTypeObject type; - PyNumberMethods as_number; - PySequenceMethods as_sequence; - PyMappingMethods as_mapping; - PyBufferProcs as_buffer; - PyObject *name, *slots; - PyMemberDef members[1]; -} etype; - /* type test with subclassing support */ int @@ -1142,6 +1205,7 @@ if (base->tp_weaklistoffset == 0 && strcmp(mp->name, "__weakref__") == 0) { mp->type = T_OBJECT; + mp->flags = READONLY; type->tp_weaklistoffset = slotoffset; } slotoffset += sizeof(PyObject *); @@ -1191,7 +1255,7 @@ if (type->tp_flags & Py_TPFLAGS_HAVE_GC) { type->tp_free = _PyObject_GC_Del; type->tp_traverse = subtype_traverse; - type->tp_clear = base->tp_clear; + type->tp_clear = subtype_clear; } else type->tp_free = _PyObject_Del;
