Add Garbage Collection support to new-style classes (not yet to their

instances).

Also added GC support to various auxiliary types: super, property,
descriptors, wrappers, dictproxy.  (Only type objects have a tp_clear
field; the other types are.)

One change was necessary to the GC infrastructure.  We have statically
allocated type objects that don't have a GC header (and can't easily
be given one) and heap-allocated type objects that do have a GC
header.  Giving these different metatypes would be really ugly: I
tried, and I had to modify pickle.py, cPickle.c, copy.py, add a new
invent a new name for the new metatype and make it a built-in, change
affected tests...  In short, a mess.  So instead, we add a new type
slot tp_is_gc, which is a simple Boolean function that determines
whether a particular instance has GC headers or not.  This slot is
only relevant for types that have the (new) GC flag bit set.  If the
tp_is_gc slot is NULL (by far the most common case), all instances of
the type are deemed to have GC headers.  This slot is called by the
PyObject_IS_GC() macro (which is only used twice, both times in
gcmodule.c).

I also changed the extern declarations for a bunch of GC-related
functions (_PyObject_GC_Del etc.): these always exist but objimpl.h
only declared them when WITH_CYCLE_GC was defined, but I needed to be
able to reference them without #ifdefs.  (When WITH_CYCLE_GC is not
defined, they do the same as their non-GC counterparts anyway.)
This commit is contained in:
Guido van Rossum 2001-10-02 21:24:57 +00:00
parent 0481d24dd5
commit 048eb75c2d
5 changed files with 237 additions and 39 deletions

View file

@ -265,7 +265,7 @@ subtype_dealloc(PyObject *self)
/* Finalize GC if the base doesn't do GC and we do */
if (PyType_IS_GC(type) && !PyType_IS_GC(base))
PyObject_GC_Fini(self);
_PyObject_GC_UNTRACK(self);
/* Call the base tp_dealloc() */
assert(f);
@ -864,6 +864,8 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
Py_TPFLAGS_BASETYPE;
if (dynamic)
type->tp_flags |= Py_TPFLAGS_DYNAMICTYPE;
if (base->tp_flags & Py_TPFLAGS_HAVE_GC)
type->tp_flags |= Py_TPFLAGS_HAVE_GC;
/* It's a new-style number unless it specifically inherits any
old-style numeric behavior */
@ -934,7 +936,8 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
else {
if (add_dict) {
if (base->tp_itemsize)
type->tp_dictoffset = -(long)sizeof(PyObject *);
type->tp_dictoffset =
-(long)sizeof(PyObject *);
else
type->tp_dictoffset = slotoffset;
slotoffset += sizeof(PyObject *);
@ -966,7 +969,13 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
/* Always override allocation strategy to use regular heap */
type->tp_alloc = PyType_GenericAlloc;
type->tp_free = _PyObject_Del;
if (type->tp_flags & Py_TPFLAGS_HAVE_GC) {
type->tp_free = _PyObject_GC_Del;
type->tp_traverse = base->tp_traverse;
type->tp_clear = base->tp_clear;
}
else
type->tp_free = _PyObject_Del;
/* Initialize the rest */
if (PyType_Ready(type) < 0) {
@ -1080,6 +1089,7 @@ type_dealloc(PyTypeObject *type)
/* Assert this is a heap-allocated type object */
assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE);
_PyObject_GC_UNTRACK(type);
et = (etype *)type;
Py_XDECREF(type->tp_base);
Py_XDECREF(type->tp_dict);
@ -1102,6 +1112,72 @@ static char type_doc[] =
"type(object) -> the object's type\n"
"type(name, bases, dict) -> a new type";
static int
type_traverse(PyTypeObject *type, visitproc visit, void *arg)
{
etype *et;
int err;
if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE))
return 0;
et = (etype *)type;
#define VISIT(SLOT) \
if (SLOT) { \
err = visit((PyObject *)(SLOT), arg); \
if (err) \
return err; \
}
VISIT(type->tp_dict);
VISIT(type->tp_defined);
VISIT(type->tp_mro);
VISIT(type->tp_bases);
VISIT(type->tp_base);
VISIT(et->slots);
#undef VISIT
return 0;
}
static int
type_clear(PyTypeObject *type)
{
etype *et;
PyObject *tmp;
if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE))
return 0;
et = (etype *)type;
#define CLEAR(SLOT) \
if (SLOT) { \
tmp = (PyObject *)(SLOT); \
SLOT = NULL; \
Py_DECREF(tmp); \
}
CLEAR(type->tp_dict);
CLEAR(type->tp_defined);
CLEAR(type->tp_mro);
CLEAR(type->tp_bases);
CLEAR(type->tp_base);
CLEAR(et->slots);
#undef CLEAR
return 0;
}
static int
type_is_gc(PyTypeObject *type)
{
return type->tp_flags & Py_TPFLAGS_HEAPTYPE;
}
PyTypeObject PyType_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /* ob_size */
@ -1123,10 +1199,11 @@ PyTypeObject PyType_Type = {
(getattrofunc)type_getattro, /* tp_getattro */
(setattrofunc)type_setattro, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_BASETYPE, /* tp_flags */
type_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
(traverseproc)type_traverse, /* tp_traverse */
(inquiry)type_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
@ -1142,6 +1219,8 @@ PyTypeObject PyType_Type = {
0, /* tp_init */
0, /* tp_alloc */
type_new, /* tp_new */
_PyObject_GC_Del, /* tp_free */
(inquiry)type_is_gc, /* tp_is_gc */
};
@ -3531,6 +3610,7 @@ super_dealloc(PyObject *self)
{
superobject *su = (superobject *)self;
_PyObject_GC_UNTRACK(self);
Py_XDECREF(su->obj);
Py_XDECREF(su->type);
self->ob_type->tp_free(self);
@ -3666,6 +3746,27 @@ static char super_doc[] =
" def meth(self, arg):\n"
" super(C, self).meth(arg)";
static int
super_traverse(PyObject *self, visitproc visit, void *arg)
{
superobject *su = (superobject *)self;
int err;
#define VISIT(SLOT) \
if (SLOT) { \
err = visit((PyObject *)(SLOT), arg); \
if (err) \
return err; \
}
VISIT(su->obj);
VISIT(su->type);
#undef VISIT
return 0;
}
PyTypeObject PySuper_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /* ob_size */
@ -3688,9 +3789,10 @@ PyTypeObject PySuper_Type = {
super_getattro, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_BASETYPE, /* tp_flags */
super_doc, /* tp_doc */
0, /* tp_traverse */
super_traverse, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
@ -3707,5 +3809,5 @@ PyTypeObject PySuper_Type = {
super_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
PyType_GenericNew, /* tp_new */
_PyObject_Del, /* tp_free */
_PyObject_GC_Del, /* tp_free */
};