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

@ -285,6 +285,7 @@ typedef struct _typeobject {
allocfunc tp_alloc; allocfunc tp_alloc;
newfunc tp_new; newfunc tp_new;
destructor tp_free; /* Low-level free-memory routine */ destructor tp_free; /* Low-level free-memory routine */
inquiry tp_is_gc; /* For PyObject_IS_GC */
PyObject *tp_bases; PyObject *tp_bases;
PyObject *tp_mro; /* method resolution order */ PyObject *tp_mro; /* method resolution order */
PyObject *tp_defined; PyObject *tp_defined;

View File

@ -217,13 +217,18 @@ extern DL_IMPORT(void) _PyObject_Del(PyObject *);
/* /*
* Garbage Collection Support * Garbage Collection Support
* ========================== * ==========================
*
* Some of the functions and macros below are always defined; when
* WITH_CYCLE_GC is undefined, they simply don't do anything different
* than their non-GC counterparts.
*/ */
/* Test if a type has a GC head */ /* Test if a type has a GC head */
#define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC) #define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC)
/* Test if an object has a GC head */ /* Test if an object has a GC head */
#define PyObject_IS_GC(o) PyType_IS_GC((o)->ob_type) #define PyObject_IS_GC(o) (PyType_IS_GC((o)->ob_type) && \
((o)->ob_type->tp_is_gc == NULL || (o)->ob_type->tp_is_gc(o)))
extern DL_IMPORT(PyObject *) _PyObject_GC_Malloc(PyTypeObject *, int); extern DL_IMPORT(PyObject *) _PyObject_GC_Malloc(PyTypeObject *, int);
extern DL_IMPORT(PyVarObject *) _PyObject_GC_Resize(PyVarObject *, int); extern DL_IMPORT(PyVarObject *) _PyObject_GC_Resize(PyVarObject *, int);
@ -231,14 +236,14 @@ extern DL_IMPORT(PyVarObject *) _PyObject_GC_Resize(PyVarObject *, int);
#define PyObject_GC_Resize(type, op, n) \ #define PyObject_GC_Resize(type, op, n) \
( (type *) _PyObject_GC_Resize((PyVarObject *)(op), (n)) ) ( (type *) _PyObject_GC_Resize((PyVarObject *)(op), (n)) )
#ifdef WITH_CYCLE_GC
extern DL_IMPORT(PyObject *) _PyObject_GC_New(PyTypeObject *); extern DL_IMPORT(PyObject *) _PyObject_GC_New(PyTypeObject *);
extern DL_IMPORT(PyVarObject *) _PyObject_GC_NewVar(PyTypeObject *, int); extern DL_IMPORT(PyVarObject *) _PyObject_GC_NewVar(PyTypeObject *, int);
extern DL_IMPORT(void) _PyObject_GC_Del(PyObject *); extern DL_IMPORT(void) _PyObject_GC_Del(PyObject *);
extern DL_IMPORT(void) _PyObject_GC_Track(PyObject *); extern DL_IMPORT(void) _PyObject_GC_Track(PyObject *);
extern DL_IMPORT(void) _PyObject_GC_UnTrack(PyObject *); extern DL_IMPORT(void) _PyObject_GC_UnTrack(PyObject *);
#ifdef WITH_CYCLE_GC
/* GC information is stored BEFORE the object structure */ /* GC information is stored BEFORE the object structure */
typedef struct _gc_head { typedef struct _gc_head {
struct _gc_head *gc_next; /* not NULL if object is tracked */ struct _gc_head *gc_next; /* not NULL if object is tracked */

View File

@ -7,9 +7,9 @@ def expect(actual, expected, name):
raise TestFailed, "test_%s: actual %d, expected %d" % ( raise TestFailed, "test_%s: actual %d, expected %d" % (
name, actual, expected) name, actual, expected)
def expect_not(actual, expected, name): def expect_nonzero(actual, name):
if actual == expected: if actual == 0:
raise TestFailed, "test_%s: actual %d unexpected" % (name, actual) raise TestFailed, "test_%s: unexpected zero" % name
def run_test(name, thunk): def run_test(name, thunk):
if verbose: if verbose:
@ -48,7 +48,21 @@ def test_class():
A.a = A A.a = A
gc.collect() gc.collect()
del A del A
expect_not(gc.collect(), 0, "class") expect_nonzero(gc.collect(), "class")
def test_staticclass():
class A(object):
__dynamic__ = 0
gc.collect()
del A
expect_nonzero(gc.collect(), "staticclass")
def test_dynamicclass():
class A(object):
__dynamic__ = 1
gc.collect()
del A
expect_nonzero(gc.collect(), "dynamicclass")
def test_instance(): def test_instance():
class A: class A:
@ -57,7 +71,7 @@ def test_instance():
a.a = a a.a = a
gc.collect() gc.collect()
del a del a
expect_not(gc.collect(), 0, "instance") expect_nonzero(gc.collect(), "instance")
def test_method(): def test_method():
# Tricky: self.__init__ is a bound method, it references the instance. # Tricky: self.__init__ is a bound method, it references the instance.
@ -67,7 +81,7 @@ def test_method():
a = A() a = A()
gc.collect() gc.collect()
del a del a
expect_not(gc.collect(), 0, "method") expect_nonzero(gc.collect(), "method")
def test_finalizer(): def test_finalizer():
# A() is uncollectable if it is part of a cycle, make sure it shows up # A() is uncollectable if it is part of a cycle, make sure it shows up
@ -84,7 +98,7 @@ def test_finalizer():
gc.collect() gc.collect()
del a del a
del b del b
expect_not(gc.collect(), 0, "finalizer") expect_nonzero(gc.collect(), "finalizer")
for obj in gc.garbage: for obj in gc.garbage:
if id(obj) == id_a: if id(obj) == id_a:
del obj.a del obj.a
@ -153,6 +167,8 @@ def test_all():
run_test("dicts", test_dict) run_test("dicts", test_dict)
run_test("tuples", test_tuple) run_test("tuples", test_tuple)
run_test("classes", test_class) run_test("classes", test_class)
run_test("static classes", test_staticclass)
run_test("dynamic classes", test_dynamicclass)
run_test("instances", test_instance) run_test("instances", test_instance)
run_test("methods", test_method) run_test("methods", test_method)
run_test("functions", test_function) run_test("functions", test_function)

View File

@ -38,9 +38,10 @@ typedef struct {
static void static void
descr_dealloc(PyDescrObject *descr) descr_dealloc(PyDescrObject *descr)
{ {
_PyObject_GC_UNTRACK(descr);
Py_XDECREF(descr->d_type); Py_XDECREF(descr->d_type);
Py_XDECREF(descr->d_name); Py_XDECREF(descr->d_name);
PyObject_DEL(descr); PyObject_GC_Del(descr);
} }
static char * static char *
@ -352,6 +353,20 @@ static PyGetSetDef wrapper_getset[] = {
{0} {0}
}; };
static int
descr_traverse(PyObject *self, visitproc visit, void *arg)
{
PyDescrObject *descr = (PyDescrObject *)self;
int err;
if (descr->d_type) {
err = visit((PyObject *)(descr->d_type), arg);
if (err)
return err;
}
return 0;
}
static PyTypeObject PyMethodDescr_Type = { static PyTypeObject PyMethodDescr_Type = {
PyObject_HEAD_INIT(&PyType_Type) PyObject_HEAD_INIT(&PyType_Type)
0, 0,
@ -373,9 +388,9 @@ static PyTypeObject PyMethodDescr_Type = {
PyObject_GenericGetAttr, /* tp_getattro */ PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */ 0, /* tp_doc */
0, /* tp_traverse */ descr_traverse, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
0, /* tp_richcompare */ 0, /* tp_richcompare */
0, /* tp_weaklistoffset */ 0, /* tp_weaklistoffset */
@ -411,9 +426,9 @@ static PyTypeObject PyMemberDescr_Type = {
PyObject_GenericGetAttr, /* tp_getattro */ PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */ 0, /* tp_doc */
0, /* tp_traverse */ descr_traverse, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
0, /* tp_richcompare */ 0, /* tp_richcompare */
0, /* tp_weaklistoffset */ 0, /* tp_weaklistoffset */
@ -449,9 +464,9 @@ static PyTypeObject PyGetSetDescr_Type = {
PyObject_GenericGetAttr, /* tp_getattro */ PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */ 0, /* tp_doc */
0, /* tp_traverse */ descr_traverse, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
0, /* tp_richcompare */ 0, /* tp_richcompare */
0, /* tp_weaklistoffset */ 0, /* tp_weaklistoffset */
@ -487,9 +502,9 @@ static PyTypeObject PyWrapperDescr_Type = {
PyObject_GenericGetAttr, /* tp_getattro */ PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */ 0, /* tp_doc */
0, /* tp_traverse */ descr_traverse, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
0, /* tp_richcompare */ 0, /* tp_richcompare */
0, /* tp_weaklistoffset */ 0, /* tp_weaklistoffset */
@ -679,8 +694,9 @@ static PyMethodDef proxy_methods[] = {
static void static void
proxy_dealloc(proxyobject *pp) proxy_dealloc(proxyobject *pp)
{ {
_PyObject_GC_UNTRACK(pp);
Py_DECREF(pp->dict); Py_DECREF(pp->dict);
PyObject_DEL(pp); PyObject_GC_Del(pp);
} }
static PyObject * static PyObject *
@ -695,6 +711,20 @@ proxy_str(proxyobject *pp)
return PyObject_Str(pp->dict); return PyObject_Str(pp->dict);
} }
static int
proxy_traverse(PyObject *self, visitproc visit, void *arg)
{
proxyobject *pp = (proxyobject *)self;
int err;
if (pp->dict) {
err = visit(pp->dict, arg);
if (err)
return err;
}
return 0;
}
PyTypeObject proxytype = { PyTypeObject proxytype = {
PyObject_HEAD_INIT(&PyType_Type) PyObject_HEAD_INIT(&PyType_Type)
0, /* ob_size */ 0, /* ob_size */
@ -717,9 +747,9 @@ PyTypeObject proxytype = {
PyObject_GenericGetAttr, /* tp_getattro */ PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */ 0, /* tp_doc */
0, /* tp_traverse */ proxy_traverse, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
0, /* tp_richcompare */ 0, /* tp_richcompare */
0, /* tp_weaklistoffset */ 0, /* tp_weaklistoffset */
@ -739,10 +769,11 @@ PyDictProxy_New(PyObject *dict)
{ {
proxyobject *pp; proxyobject *pp;
pp = PyObject_NEW(proxyobject, &proxytype); pp = PyObject_GC_New(proxyobject, &proxytype);
if (pp != NULL) { if (pp != NULL) {
Py_INCREF(dict); Py_INCREF(dict);
pp->dict = dict; pp->dict = dict;
_PyObject_GC_TRACK(pp);
} }
return (PyObject *)pp; return (PyObject *)pp;
} }
@ -762,9 +793,10 @@ typedef struct {
static void static void
wrapper_dealloc(wrapperobject *wp) wrapper_dealloc(wrapperobject *wp)
{ {
_PyObject_GC_UNTRACK(wp);
Py_XDECREF(wp->descr); Py_XDECREF(wp->descr);
Py_XDECREF(wp->self); Py_XDECREF(wp->self);
PyObject_DEL(wp); PyObject_GC_Del(wp);
} }
static PyMethodDef wrapper_methods[] = { static PyMethodDef wrapper_methods[] = {
@ -808,6 +840,25 @@ wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds)
return (*wrapper)(self, args, wp->descr->d_wrapped); return (*wrapper)(self, args, wp->descr->d_wrapped);
} }
static int
wrapper_traverse(PyObject *self, visitproc visit, void *arg)
{
wrapperobject *wp = (wrapperobject *)self;
int err;
if (wp->descr) {
err = visit((PyObject *)(wp->descr), arg);
if (err)
return err;
}
if (wp->self) {
err = visit(wp->self, arg);
if (err)
return err;
}
return 0;
}
PyTypeObject wrappertype = { PyTypeObject wrappertype = {
PyObject_HEAD_INIT(&PyType_Type) PyObject_HEAD_INIT(&PyType_Type)
0, /* ob_size */ 0, /* ob_size */
@ -830,9 +881,9 @@ PyTypeObject wrappertype = {
PyObject_GenericGetAttr, /* tp_getattro */ PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */ 0, /* tp_doc */
0, /* tp_traverse */ wrapper_traverse, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
0, /* tp_richcompare */ 0, /* tp_richcompare */
0, /* tp_weaklistoffset */ 0, /* tp_weaklistoffset */
@ -857,12 +908,13 @@ PyWrapper_New(PyObject *d, PyObject *self)
descr = (PyWrapperDescrObject *)d; descr = (PyWrapperDescrObject *)d;
assert(PyObject_IsInstance(self, (PyObject *)(descr->d_type))); assert(PyObject_IsInstance(self, (PyObject *)(descr->d_type)));
wp = PyObject_NEW(wrapperobject, &wrappertype); wp = PyObject_GC_New(wrapperobject, &wrappertype);
if (wp != NULL) { if (wp != NULL) {
Py_INCREF(descr); Py_INCREF(descr);
wp->descr = descr; wp->descr = descr;
Py_INCREF(self); Py_INCREF(self);
wp->self = self; wp->self = self;
_PyObject_GC_TRACK(wp);
} }
return (PyObject *)wp; return (PyObject *)wp;
} }
@ -919,6 +971,7 @@ property_dealloc(PyObject *self)
{ {
propertyobject *gs = (propertyobject *)self; propertyobject *gs = (propertyobject *)self;
_PyObject_GC_UNTRACK(self);
Py_XDECREF(gs->prop_get); Py_XDECREF(gs->prop_get);
Py_XDECREF(gs->prop_set); Py_XDECREF(gs->prop_set);
Py_XDECREF(gs->prop_del); Py_XDECREF(gs->prop_del);
@ -1012,6 +1065,26 @@ static char property_doc[] =
" def delx(self): del self.__x\n" " def delx(self): del self.__x\n"
" x = property(getx, setx, delx, \"I'm the 'x' property.\")"; " x = property(getx, setx, delx, \"I'm the 'x' property.\")";
static int
property_traverse(PyObject *self, visitproc visit, void *arg)
{
propertyobject *pp = (propertyobject *)self;
int err;
#define VISIT(SLOT) \
if (pp->SLOT) { \
err = visit((PyObject *)(pp->SLOT), arg); \
if (err) \
return err; \
}
VISIT(prop_get);
VISIT(prop_set);
VISIT(prop_del);
return 0;
}
PyTypeObject PyProperty_Type = { PyTypeObject PyProperty_Type = {
PyObject_HEAD_INIT(&PyType_Type) PyObject_HEAD_INIT(&PyType_Type)
0, /* ob_size */ 0, /* ob_size */
@ -1034,9 +1107,10 @@ PyTypeObject PyProperty_Type = {
PyObject_GenericGetAttr, /* tp_getattro */ PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_BASETYPE, /* tp_flags */
property_doc, /* tp_doc */ property_doc, /* tp_doc */
0, /* tp_traverse */ property_traverse, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
0, /* tp_richcompare */ 0, /* tp_richcompare */
0, /* tp_weaklistoffset */ 0, /* tp_weaklistoffset */
@ -1053,5 +1127,5 @@ PyTypeObject PyProperty_Type = {
property_init, /* tp_init */ property_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */ PyType_GenericAlloc, /* tp_alloc */
PyType_GenericNew, /* tp_new */ PyType_GenericNew, /* tp_new */
_PyObject_Del, /* tp_free */ _PyObject_GC_Del, /* tp_free */
}; };

View File

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