summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2022-01-22 15:53:30 (GMT)
committerGitHub <noreply@github.com>2022-01-22 15:53:30 (GMT)
commit2d03b73cc9c0dada3243eab1373a46dbd98d24a0 (patch)
treea5540d769b1f1c8e2f05007df3903736b04932a9 /Objects
parentf1c6ae3270913e095d24ae13ecf96f5a32c8c503 (diff)
downloadcpython-2d03b73cc9c0dada3243eab1373a46dbd98d24a0.zip
cpython-2d03b73cc9c0dada3243eab1373a46dbd98d24a0.tar.gz
cpython-2d03b73cc9c0dada3243eab1373a46dbd98d24a0.tar.bz2
bpo-46417: remove_subclass() clears tp_subclasses (GH-30793)
The remove_subclass() function now deletes the dictionary when removing the last subclass (if the dictionary becomes empty) to save memory: set PyTypeObject.tp_subclasses to NULL. remove_subclass() is called when a type is deallocated. _PyType_GetSubclasses() no longer holds a reference to tp_subclasses: its loop cannot modify tp_subclasses.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/typeobject.c24
1 files changed, 15 insertions, 9 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 2b47afe..b3c305e 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -4137,16 +4137,17 @@ _PyType_GetSubclasses(PyTypeObject *self)
return NULL;
}
- // Hold a strong reference to tp_subclasses while iterating on it
- PyObject *dict = Py_XNewRef(self->tp_subclasses);
- if (dict == NULL) {
+ PyObject *subclasses = self->tp_subclasses; // borrowed ref
+ if (subclasses == NULL) {
return list;
}
- assert(PyDict_CheckExact(dict));
+ assert(PyDict_CheckExact(subclasses));
+ // The loop cannot modify tp_subclasses, there is no need
+ // to hold a strong reference (use a borrowed reference).
Py_ssize_t i = 0;
PyObject *ref; // borrowed ref
- while (PyDict_Next(dict, &i, NULL, &ref)) {
+ while (PyDict_Next(subclasses, &i, NULL, &ref)) {
assert(PyWeakref_CheckRef(ref));
PyObject *obj = PyWeakref_GET_OBJECT(ref); // borrowed ref
if (obj == Py_None) {
@@ -4154,12 +4155,10 @@ _PyType_GetSubclasses(PyTypeObject *self)
}
assert(PyType_Check(obj));
if (PyList_Append(list, obj) < 0) {
- Py_CLEAR(list);
- goto done;
+ Py_DECREF(list);
+ return NULL;
}
}
-done:
- Py_DECREF(dict);
return list;
}
@@ -6568,6 +6567,13 @@ remove_subclass(PyTypeObject *base, PyTypeObject *type)
PyErr_Clear();
}
Py_XDECREF(key);
+
+ if (PyDict_Size(dict) == 0) {
+ // Delete the dictionary to save memory. _PyStaticType_Dealloc()
+ // callers also test if tp_subclasses is NULL to check if a static type
+ // has no subclass.
+ Py_CLEAR(base->tp_subclasses);
+ }
}
static void