mirror of https://github.com/python/cpython
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:
parent
be63884d50
commit
9475a2310d
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -182,8 +182,12 @@ PyFloat_FromString(PyObject *v, char **pend)
|
||||||
static void
|
static void
|
||||||
float_dealloc(PyFloatObject *op)
|
float_dealloc(PyFloatObject *op)
|
||||||
{
|
{
|
||||||
|
if (PyFloat_CheckExact(op)) {
|
||||||
op->ob_type = (struct _typeobject *)free_list;
|
op->ob_type = (struct _typeobject *)free_list;
|
||||||
free_list = op;
|
free_list = op;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
op->ob_type->tp_free((PyObject *)op);
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
|
|
|
@ -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 *
|
||||||
|
|
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Reference in New Issue