diff --git a/Include/object.h b/Include/object.h index f6ceba5cbf2..e18e0e80fd2 100644 --- a/Include/object.h +++ b/Include/object.h @@ -145,6 +145,8 @@ typedef int (*getwritebufferproc) Py_PROTO((PyObject *, int, void **)); typedef int (*getsegcountproc) Py_PROTO((PyObject *, int *)); typedef int (*getcharbufferproc) Py_PROTO((PyObject *, int, const char **)); typedef int (*objobjproc) Py_PROTO((PyObject *, PyObject *)); +typedef int (*visitproc) Py_PROTO((PyObject *, void *)); +typedef int (*traverseproc) Py_PROTO((PyObject *, visitproc, void *)); typedef struct { binaryfunc nb_add; @@ -243,9 +245,13 @@ typedef struct _typeobject { char *tp_doc; /* Documentation string */ + /* call function for all accessible objects */ + traverseproc tp_traverse; + + /* delete references to contained objects */ + inquiry tp_clear; + /* More spares */ - long tp_xxx5; - long tp_xxx6; long tp_xxx7; long tp_xxx8; diff --git a/Objects/classobject.c b/Objects/classobject.c index bd95bc039fa..18908f3acef 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -387,6 +387,43 @@ class_str(op) return res; } +static int +class_traverse(PyClassObject *o, visitproc visit, void *arg) +{ + int err; + if (o->cl_bases) { + err = visit(o->cl_bases, arg); + if (err) + return err; + } + if (o->cl_dict) { + err = visit(o->cl_dict, arg); + if (err) + return err; + } + if (o->cl_name) { + err = visit(o->cl_name, arg); + if (err) + return err; + } + if (o->cl_getattr) { + err = visit(o->cl_getattr, arg); + if (err) + return err; + } + if (o->cl_setattr) { + err = visit(o->cl_setattr, arg); + if (err) + return err; + } + if (o->cl_delattr) { + err = visit(o->cl_delattr, arg); + if (err) + return err; + } + return 0; +} + PyTypeObject PyClass_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, @@ -407,6 +444,10 @@ PyTypeObject PyClass_Type = { (reprfunc)class_str, /*tp_str*/ (getattrofunc)class_getattr, /*tp_getattro*/ (setattrofunc)class_setattr, /*tp_setattro*/ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /* tp_doc */ + (traverseproc)class_traverse, /* tp_traverse */ }; int @@ -849,6 +890,23 @@ instance_hash(inst) return outcome; } +static int +instance_traverse(PyInstanceObject *o, visitproc visit, void *arg) +{ + int err; + if (o->in_class) { + err = visit((PyObject *)(o->in_class), arg); + if (err) + return err; + } + if (o->in_dict) { + err = visit(o->in_dict, arg); + if (err) + return err; + } + return 1; +} + static PyObject *getitemstr, *setitemstr, *delitemstr, *lenstr; static int @@ -1472,7 +1530,9 @@ PyTypeObject PyInstance_Type = { (getattrofunc)instance_getattr, /*tp_getattro*/ (setattrofunc)instance_setattr, /*tp_setattro*/ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /*tp_flags */ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /* tp_doc */ + (traverseproc)instance_traverse, /* tp_traverse */ }; @@ -1662,6 +1722,28 @@ instancemethod_hash(a) return x ^ y; } +static int +instancemethod_traverse(PyMethodObject *im, visitproc visit, void *arg) +{ + int err; + if (im->im_func) { + err = visit(im->im_func, arg); + if (err) + return err; + } + if (im->im_self) { + err = visit(im->im_self, arg); + if (err) + return err; + } + if (im->im_class) { + err = visit(im->im_class, arg); + if (err) + return err; + } + return 1; +} + PyTypeObject PyMethod_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, @@ -1682,6 +1764,10 @@ PyTypeObject PyMethod_Type = { 0, /*tp_str*/ (getattrofunc)instancemethod_getattr, /*tp_getattro*/ 0, /*tp_setattro*/ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /* tp_doc */ + (traverseproc)instancemethod_traverse, /* tp_traverse */ }; /* Clear out the free list */ diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 6e7fa3d0ef6..2d33b927da9 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1038,6 +1038,31 @@ dict_clear(mp, args) return Py_None; } +static int +dict_traverse(PyObject *op, visitproc visit, void *arg) +{ + int i = 0, err; + PyObject *pk; + PyObject *pv; + + while (PyDict_Next(op, &i, &pk, &pv)) { + err = visit(pk, arg); + if (err) + return err; + err = visit(pv, arg); + if (err) + return err; + } + return 0; +} + +static int +dict_tp_clear(PyObject *op) +{ + PyDict_Clear(op); + return 0; +} + static PyMethodDef mapp_methods[] = { {"has_key", (PyCFunction)dict_has_key, METH_VARARGS}, {"keys", (PyCFunction)dict_keys}, @@ -1073,6 +1098,16 @@ PyTypeObject PyDict_Type = { 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ &dict_as_mapping, /*tp_as_mapping*/ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /* tp_doc */ + (traverseproc)dict_traverse, /* tp_traverse */ + (inquiry)dict_tp_clear, /* tp_clear */ }; /* For backward compatibility with old dictionary interface */ diff --git a/Objects/funcobject.c b/Objects/funcobject.c index a5e15cc9057..142c7e7df9c 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -239,6 +239,38 @@ func_hash(f) return h; } +static int +func_traverse(PyFunctionObject *f, visitproc visit, void *arg) +{ + int err; + if (f->func_code) { + err = visit(f->func_code, arg); + if (err) + return err; + } + if (f->func_globals) { + err = visit(f->func_globals, arg); + if (err) + return err; + } + if (f->func_defaults) { + err = visit(f->func_defaults, arg); + if (err) + return err; + } + if (f->func_doc) { + err = visit(f->func_doc, arg); + if (err) + return err; + } + if (f->func_name) { + err = visit(f->func_name, arg); + if (err) + return err; + } + return 0; +} + PyTypeObject PyFunction_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, @@ -255,4 +287,12 @@ PyTypeObject PyFunction_Type = { 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ (hashfunc)func_hash, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /* tp_doc */ + (traverseproc)func_traverse, /* tp_traverse */ }; diff --git a/Objects/listobject.c b/Objects/listobject.c index 163ba2a8194..65dfb18f7bb 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1418,6 +1418,30 @@ listremove(self, args) return NULL; } +static int +list_traverse(PyListObject *o, visitproc visit, void *arg) +{ + int i, err; + PyObject *x; + + for (i = o->ob_size; --i >= 0; ) { + x = o->ob_item[i]; + if (x != NULL) { + err = visit(x, arg); + if (err) + return err; + } + } + return 0; +} + +static int +list_clear(PyListObject *lp) +{ + (void) PyList_SetSlice((PyObject *)lp, 0, lp->ob_size, 0); + return 0; +} + static char append_doc[] = "L.append(object) -- append object to end"; static char extend_doc[] = @@ -1491,6 +1515,9 @@ PyTypeObject PyList_Type = { 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /* tp_doc */ + (traverseproc)list_traverse, /* tp_traverse */ + (inquiry)list_clear, /* tp_clear */ }; @@ -1567,5 +1594,7 @@ static PyTypeObject immutable_list_type = { 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /* tp_doc */ + (traverseproc)list_traverse, /* tp_traverse */ }; diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index f89fa365a90..bbb56b1adc4 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -420,6 +420,23 @@ tuplerepeat(a, n) return (PyObject *) np; } +static int +tupletraverse(PyTupleObject *o, visitproc visit, void *arg) +{ + int i, err; + PyObject *x; + + for (i = o->ob_size; --i >= 0; ) { + x = o->ob_item[i]; + if (x != NULL) { + err = visit(x, arg); + if (err) + return err; + } + } + return 0; +} + static PySequenceMethods tuple_as_sequence = { (inquiry)tuplelength, /*sq_length*/ (binaryfunc)tupleconcat, /*sq_concat*/ @@ -453,6 +470,8 @@ PyTypeObject PyTuple_Type = { 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + (traverseproc)tupletraverse, /* tp_traverse */ }; /* The following function breaks the notion that tuples are immutable: