Enable GC for new-style instances. This touches lots of files, since

many types were subclassable but had a xxx_dealloc function that
called PyObject_DEL(self) directly instead of deferring to
self->ob_type->tp_free(self).  It is permissible to set tp_free in the
type object directly to _PyObject_Del, for non-GC types, or to
_PyObject_GC_Del, for GC types.  Still, PyObject_DEL was a tad faster,
so I'm fearing that our pystone rating is going down again.  I'm not
sure if doing something like

void xxx_dealloc(PyObject *self)
{
	if (PyXxxCheckExact(self))
		PyObject_DEL(self);
	else
		self->ob_type->tp_free(self);
}

is any faster than always calling the else branch, so I haven't
attempted that -- however those types whose own dealloc is fancier
(int, float, unicode) do use this pattern.
This commit is contained in:
Guido van Rossum 2001-10-05 20:51:39 +00:00
parent be63884d50
commit 9475a2310d
13 changed files with 90 additions and 26 deletions

View File

@ -73,6 +73,24 @@ def test_instance():
del a del a
expect_nonzero(gc.collect(), "instance") expect_nonzero(gc.collect(), "instance")
def test_newinstance():
class A(object):
pass
a = A()
a.a = a
gc.collect()
del a
expect_nonzero(gc.collect(), "newinstance")
class B(list):
pass
class C(B, A):
pass
a = C()
a.a = a
gc.collect()
del a
expect_nonzero(gc.collect(), "newinstance(2)")
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.
class A: class A:
@ -170,6 +188,7 @@ def test_all():
run_test("static classes", test_staticclass) run_test("static classes", test_staticclass)
run_test("dynamic classes", test_dynamicclass) run_test("dynamic classes", test_dynamicclass)
run_test("instances", test_instance) run_test("instances", test_instance)
run_test("new instances", test_newinstance)
run_test("methods", test_method) run_test("methods", test_method)
run_test("functions", test_function) run_test("functions", test_function)
run_test("frames", test_frame) run_test("frames", test_frame)

View File

@ -265,7 +265,7 @@ PyComplex_AsCComplex(PyObject *op)
static void static void
complex_dealloc(PyObject *op) complex_dealloc(PyObject *op)
{ {
PyObject_DEL(op); op->ob_type->tp_free(op);
} }
@ -970,6 +970,7 @@ PyTypeObject PyComplex_Type = {
0, /* tp_init */ 0, /* tp_init */
0, /* tp_alloc */ 0, /* tp_alloc */
complex_new, /* tp_new */ complex_new, /* tp_new */
_PyObject_Del, /* tp_free */
}; };
#endif #endif

View File

@ -705,7 +705,7 @@ dict_dealloc(register dictobject *mp)
} }
if (mp->ma_table != mp->ma_smalltable) if (mp->ma_table != mp->ma_smalltable)
PyMem_DEL(mp->ma_table); PyMem_DEL(mp->ma_table);
PyObject_GC_Del(mp); mp->ob_type->tp_free((PyObject *)mp);
Py_TRASHCAN_SAFE_END(mp) Py_TRASHCAN_SAFE_END(mp)
} }
@ -1769,6 +1769,7 @@ PyTypeObject PyDict_Type = {
(initproc)dict_init, /* tp_init */ (initproc)dict_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */ PyType_GenericAlloc, /* tp_alloc */
dict_new, /* tp_new */ dict_new, /* tp_new */
_PyObject_GC_Del, /* tp_free */
}; };
/* For backward compatibility with old dictionary interface */ /* For backward compatibility with old dictionary interface */

View File

@ -208,7 +208,7 @@ file_dealloc(PyFileObject *f)
} }
Py_XDECREF(f->f_name); Py_XDECREF(f->f_name);
Py_XDECREF(f->f_mode); Py_XDECREF(f->f_mode);
PyObject_DEL(f); f->ob_type->tp_free((PyObject *)f);
} }
static PyObject * static PyObject *
@ -1508,8 +1508,7 @@ PyTypeObject PyFile_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_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
Py_TPFLAGS_BASETYPE, /* tp_flags */
file_doc, /* tp_doc */ file_doc, /* tp_doc */
0, /* tp_traverse */ 0, /* tp_traverse */
0, /* tp_clear */ 0, /* tp_clear */
@ -1528,6 +1527,7 @@ PyTypeObject PyFile_Type = {
(initproc)file_init, /* tp_init */ (initproc)file_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */ PyType_GenericAlloc, /* tp_alloc */
file_new, /* tp_new */ file_new, /* tp_new */
_PyObject_Del, /* tp_free */
}; };
/* Interface for the 'soft space' between print items. */ /* Interface for the 'soft space' between print items. */

View File

@ -182,8 +182,12 @@ PyFloat_FromString(PyObject *v, char **pend)
static void static void
float_dealloc(PyFloatObject *op) float_dealloc(PyFloatObject *op)
{ {
op->ob_type = (struct _typeobject *)free_list; if (PyFloat_CheckExact(op)) {
free_list = op; op->ob_type = (struct _typeobject *)free_list;
free_list = op;
}
else
op->ob_type->tp_free((PyObject *)op);
} }
double double

View File

@ -461,7 +461,7 @@ static void
cm_dealloc(classmethod *cm) cm_dealloc(classmethod *cm)
{ {
Py_XDECREF(cm->cm_callable); Py_XDECREF(cm->cm_callable);
PyObject_DEL(cm); cm->ob_type->tp_free((PyObject *)cm);
} }
static PyObject * static PyObject *
@ -531,6 +531,7 @@ PyTypeObject PyClassMethod_Type = {
cm_init, /* tp_init */ cm_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */ PyType_GenericAlloc, /* tp_alloc */
PyType_GenericNew, /* tp_new */ PyType_GenericNew, /* tp_new */
_PyObject_Del, /* tp_free */
}; };
PyObject * PyObject *
@ -571,7 +572,7 @@ static void
sm_dealloc(staticmethod *sm) sm_dealloc(staticmethod *sm)
{ {
Py_XDECREF(sm->sm_callable); Py_XDECREF(sm->sm_callable);
PyObject_DEL(sm); sm->ob_type->tp_free((PyObject *)sm);
} }
static PyObject * static PyObject *
@ -641,6 +642,7 @@ PyTypeObject PyStaticMethod_Type = {
sm_init, /* tp_init */ sm_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */ PyType_GenericAlloc, /* tp_alloc */
PyType_GenericNew, /* tp_new */ PyType_GenericNew, /* tp_new */
_PyObject_Del, /* tp_free */
}; };
PyObject * PyObject *

View File

@ -208,7 +208,7 @@ list_dealloc(PyListObject *op)
} }
PyMem_FREE(op->ob_item); PyMem_FREE(op->ob_item);
} }
PyObject_GC_Del(op); op->ob_type->tp_free((PyObject *)op);
Py_TRASHCAN_SAFE_END(op) Py_TRASHCAN_SAFE_END(op)
} }
@ -1707,6 +1707,7 @@ PyTypeObject PyList_Type = {
(initproc)list_init, /* tp_init */ (initproc)list_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */ PyType_GenericAlloc, /* tp_alloc */
PyType_GenericNew, /* tp_new */ PyType_GenericNew, /* tp_new */
_PyObject_GC_Del, /* tp_free */
}; };

View File

@ -1227,7 +1227,7 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem)
static void static void
long_dealloc(PyObject *v) long_dealloc(PyObject *v)
{ {
PyObject_DEL(v); v->ob_type->tp_free(v);
} }
static PyObject * static PyObject *
@ -2341,4 +2341,5 @@ PyTypeObject PyLong_Type = {
0, /* tp_init */ 0, /* tp_init */
0, /* tp_alloc */ 0, /* tp_alloc */
long_new, /* tp_new */ long_new, /* tp_new */
_PyObject_Del, /* tp_free */
}; };

View File

@ -151,7 +151,7 @@ module_dealloc(PyModuleObject *m)
_PyModule_Clear((PyObject *)m); _PyModule_Clear((PyObject *)m);
Py_DECREF(m->md_dict); Py_DECREF(m->md_dict);
} }
PyObject_GC_Del(m); m->ob_type->tp_free((PyObject *)m);
} }
static PyObject * static PyObject *
@ -225,4 +225,5 @@ PyTypeObject PyModule_Type = {
(initproc)module_init, /* tp_init */ (initproc)module_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */ PyType_GenericAlloc, /* tp_alloc */
PyType_GenericNew, /* tp_new */ PyType_GenericNew, /* tp_new */
_PyObject_GC_Del, /* tp_free */
}; };

View File

@ -481,7 +481,7 @@ PyObject *PyString_AsEncodedString(PyObject *str,
static void static void
string_dealloc(PyObject *op) string_dealloc(PyObject *op)
{ {
PyObject_DEL(op); op->ob_type->tp_free(op);
} }
static int static int
@ -2746,6 +2746,7 @@ PyTypeObject PyString_Type = {
0, /* tp_init */ 0, /* tp_init */
0, /* tp_alloc */ 0, /* tp_alloc */
string_new, /* tp_new */ string_new, /* tp_new */
_PyObject_Del, /* tp_free */
}; };
void void

View File

@ -157,7 +157,7 @@ tupledealloc(register PyTupleObject *op)
} }
#endif #endif
} }
PyObject_GC_Del(op); op->ob_type->tp_free((PyObject *)op);
done: done:
Py_TRASHCAN_SAFE_END(op) Py_TRASHCAN_SAFE_END(op)
} }
@ -582,6 +582,7 @@ PyTypeObject PyTuple_Type = {
0, /* tp_init */ 0, /* tp_init */
0, /* tp_alloc */ 0, /* tp_alloc */
tuple_new, /* tp_new */ tuple_new, /* tp_new */
_PyObject_GC_Del, /* tp_free */
}; };
/* The following function breaks the notion that tuples are immutable: /* The following function breaks the notion that tuples are immutable:

View File

@ -229,7 +229,36 @@ PyType_GenericNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
return type->tp_alloc(type, 0); return type->tp_alloc(type, 0);
} }
/* Helper for subtyping */ /* Helpers for subtyping */
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 */
type = self->ob_type;
base = type->tp_base;
while ((f = base->tp_traverse) == subtype_traverse) {
base = base->tp_base;
assert(base);
}
if (type->tp_dictoffset != base->tp_dictoffset) {
PyObject **dictptr = _PyObject_GetDictPtr(self);
if (dictptr && *dictptr) {
err = visit(*dictptr, arg);
if (err)
return err;
}
}
if (f)
return f(self, visit, arg);
return 0;
}
static void static void
subtype_dealloc(PyObject *self) subtype_dealloc(PyObject *self)
@ -968,11 +997,16 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
} }
type->tp_dealloc = subtype_dealloc; type->tp_dealloc = subtype_dealloc;
/* Enable GC unless there are really no instance variables possible */
if (!(type->tp_basicsize == sizeof(PyObject) &&
type->tp_itemsize == 0))
type->tp_flags |= Py_TPFLAGS_HAVE_GC;
/* 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) { if (type->tp_flags & Py_TPFLAGS_HAVE_GC) {
type->tp_free = _PyObject_GC_Del; type->tp_free = _PyObject_GC_Del;
type->tp_traverse = base->tp_traverse; type->tp_traverse = subtype_traverse;
type->tp_clear = base->tp_clear; type->tp_clear = base->tp_clear;
} }
else else
@ -1097,7 +1131,6 @@ type_dealloc(PyTypeObject *type)
Py_XDECREF(type->tp_bases); Py_XDECREF(type->tp_bases);
Py_XDECREF(type->tp_mro); Py_XDECREF(type->tp_mro);
Py_XDECREF(type->tp_defined); Py_XDECREF(type->tp_defined);
/* XXX more? */
Py_XDECREF(et->name); Py_XDECREF(et->name);
Py_XDECREF(et->slots); Py_XDECREF(et->slots);
type->ob_type->tp_free((PyObject *)type); type->ob_type->tp_free((PyObject *)type);
@ -1291,12 +1324,6 @@ object_hash(PyObject *self)
return _Py_HashPointer(self); return _Py_HashPointer(self);
} }
static void
object_free(PyObject *self)
{
PyObject_Del(self);
}
static PyObject * static PyObject *
object_get_class(PyObject *self, void *closure) object_get_class(PyObject *self, void *closure)
{ {
@ -1446,7 +1473,7 @@ PyTypeObject PyBaseObject_Type = {
object_init, /* tp_init */ object_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */ PyType_GenericAlloc, /* tp_alloc */
PyType_GenericNew, /* tp_new */ PyType_GenericNew, /* tp_new */
object_free, /* tp_free */ _PyObject_Del, /* tp_free */
}; };

View File

@ -224,8 +224,12 @@ PyUnicodeObject *_PyUnicode_New(int length)
} }
static static
void _PyUnicode_Free(register PyUnicodeObject *unicode) void unicode_dealloc(register PyUnicodeObject *unicode)
{ {
if (!PyUnicode_CheckExact(unicode)) {
unicode->ob_type->tp_free((PyObject *)unicode);
return;
}
if (unicode_freelist_size < MAX_UNICODE_FREELIST_SIZE) { if (unicode_freelist_size < MAX_UNICODE_FREELIST_SIZE) {
/* Keep-Alive optimization */ /* Keep-Alive optimization */
if (unicode->length >= KEEPALIVE_SIZE_LIMIT) { if (unicode->length >= KEEPALIVE_SIZE_LIMIT) {
@ -5693,7 +5697,7 @@ PyTypeObject PyUnicode_Type = {
sizeof(PyUnicodeObject), /* tp_size */ sizeof(PyUnicodeObject), /* tp_size */
0, /* tp_itemsize */ 0, /* tp_itemsize */
/* Slots */ /* Slots */
(destructor)_PyUnicode_Free, /* tp_dealloc */ (destructor)unicode_dealloc, /* tp_dealloc */
0, /* tp_print */ 0, /* tp_print */
0, /* tp_getattr */ 0, /* tp_getattr */
0, /* tp_setattr */ 0, /* tp_setattr */
@ -5727,6 +5731,7 @@ PyTypeObject PyUnicode_Type = {
0, /* tp_init */ 0, /* tp_init */
0, /* tp_alloc */ 0, /* tp_alloc */
unicode_new, /* tp_new */ unicode_new, /* tp_new */
_PyObject_Del, /* tp_free */
}; };
/* Initialize the Unicode implementation */ /* Initialize the Unicode implementation */