mirror of https://github.com/python/cpython
gh-107073: Make PyObject_VisitManagedDict() public (#108763)
Make PyObject_VisitManagedDict() and PyObject_ClearManagedDict() functions public in Python 3.13 C API. * Rename _PyObject_VisitManagedDict() to PyObject_VisitManagedDict(). * Rename _PyObject_ClearManagedDict() to PyObject_ClearManagedDict(). * Document these functions.
This commit is contained in:
parent
6387b5313c
commit
fc2cb86d21
|
@ -489,3 +489,21 @@ Object Protocol
|
||||||
:c:macro:`Py_TPFLAGS_ITEMS_AT_END` set.
|
:c:macro:`Py_TPFLAGS_ITEMS_AT_END` set.
|
||||||
|
|
||||||
.. versionadded:: 3.12
|
.. versionadded:: 3.12
|
||||||
|
|
||||||
|
.. c:function:: int PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
|
||||||
|
|
||||||
|
Visit the managed dictionary of *obj*.
|
||||||
|
|
||||||
|
This function must only be called in a traverse function of the type which
|
||||||
|
has the :c:macro:`Py_TPFLAGS_MANAGED_DICT` flag set.
|
||||||
|
|
||||||
|
.. versionadded:: 3.13
|
||||||
|
|
||||||
|
.. c:function:: void PyObject_ClearManagedDict(PyObject *obj)
|
||||||
|
|
||||||
|
Clear the managed dictionary of *obj*.
|
||||||
|
|
||||||
|
This function must only be called in a traverse function of the type which
|
||||||
|
has the :c:macro:`Py_TPFLAGS_MANAGED_DICT` flag set.
|
||||||
|
|
||||||
|
.. versionadded:: 3.13
|
||||||
|
|
|
@ -1131,6 +1131,9 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
||||||
|
|
||||||
If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` should also be set.
|
If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` should also be set.
|
||||||
|
|
||||||
|
The type traverse function must call :c:func:`PyObject_VisitManagedDict`
|
||||||
|
and its clear function must call :c:func:`PyObject_ClearManagedDict`.
|
||||||
|
|
||||||
.. versionadded:: 3.12
|
.. versionadded:: 3.12
|
||||||
|
|
||||||
**Inheritance:**
|
**Inheritance:**
|
||||||
|
@ -1368,6 +1371,23 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
||||||
debugging aid you may want to visit it anyway just so the :mod:`gc` module's
|
debugging aid you may want to visit it anyway just so the :mod:`gc` module's
|
||||||
:func:`~gc.get_referents` function will include it.
|
:func:`~gc.get_referents` function will include it.
|
||||||
|
|
||||||
|
Heap types (:c:macro:`Py_TPFLAGS_HEAPTYPE`) must visit their type with::
|
||||||
|
|
||||||
|
Py_VISIT(Py_TYPE(self));
|
||||||
|
|
||||||
|
It is only needed since Python 3.9. To support Python 3.8 and older, this
|
||||||
|
line must be conditionnal::
|
||||||
|
|
||||||
|
#if PY_VERSION_HEX >= 0x03090000
|
||||||
|
Py_VISIT(Py_TYPE(self));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` bit is set in the
|
||||||
|
:c:member:`~PyTypeObject.tp_flags` field, the traverse function must call
|
||||||
|
:c:func:`PyObject_VisitManagedDict` like this::
|
||||||
|
|
||||||
|
PyObject_VisitManagedDict((PyObject*)self, visit, arg);
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
When implementing :c:member:`~PyTypeObject.tp_traverse`, only the
|
When implementing :c:member:`~PyTypeObject.tp_traverse`, only the
|
||||||
members that the instance *owns* (by having :term:`strong references
|
members that the instance *owns* (by having :term:`strong references
|
||||||
|
@ -1451,6 +1471,12 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
||||||
so that *self* knows the contained object can no longer be used. The
|
so that *self* knows the contained object can no longer be used. The
|
||||||
:c:func:`Py_CLEAR` macro performs the operations in a safe order.
|
:c:func:`Py_CLEAR` macro performs the operations in a safe order.
|
||||||
|
|
||||||
|
If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` bit is set in the
|
||||||
|
:c:member:`~PyTypeObject.tp_flags` field, the traverse function must call
|
||||||
|
:c:func:`PyObject_ClearManagedDict` like this::
|
||||||
|
|
||||||
|
PyObject_ClearManagedDict((PyObject*)self);
|
||||||
|
|
||||||
Note that :c:member:`~PyTypeObject.tp_clear` is not *always* called
|
Note that :c:member:`~PyTypeObject.tp_clear` is not *always* called
|
||||||
before an instance is deallocated. For example, when reference counting
|
before an instance is deallocated. For example, when reference counting
|
||||||
is enough to determine that an object is no longer used, the cyclic garbage
|
is enough to determine that an object is no longer used, the cyclic garbage
|
||||||
|
@ -1801,7 +1827,7 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
||||||
field is ``NULL`` then no :attr:`~object.__dict__` gets created for instances.
|
field is ``NULL`` then no :attr:`~object.__dict__` gets created for instances.
|
||||||
|
|
||||||
If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` bit is set in the
|
If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` bit is set in the
|
||||||
:c:member:`~PyTypeObject.tp_dict` field, then
|
:c:member:`~PyTypeObject.tp_flags` field, then
|
||||||
:c:member:`~PyTypeObject.tp_dictoffset` will be set to ``-1``, to indicate
|
:c:member:`~PyTypeObject.tp_dictoffset` will be set to ``-1``, to indicate
|
||||||
that it is unsafe to use this field.
|
that it is unsafe to use this field.
|
||||||
|
|
||||||
|
|
|
@ -2123,7 +2123,7 @@ Porting to Python 3.12
|
||||||
The use of ``tp_dictoffset`` and ``tp_weaklistoffset`` is still
|
The use of ``tp_dictoffset`` and ``tp_weaklistoffset`` is still
|
||||||
supported, but does not fully support multiple inheritance
|
supported, but does not fully support multiple inheritance
|
||||||
(:gh:`95589`), and performance may be worse.
|
(:gh:`95589`), and performance may be worse.
|
||||||
Classes declaring :c:macro:`Py_TPFLAGS_MANAGED_DICT` should call
|
Classes declaring :c:macro:`Py_TPFLAGS_MANAGED_DICT` must call
|
||||||
:c:func:`!_PyObject_VisitManagedDict` and :c:func:`!_PyObject_ClearManagedDict`
|
:c:func:`!_PyObject_VisitManagedDict` and :c:func:`!_PyObject_ClearManagedDict`
|
||||||
to traverse and clear their instance's dictionaries.
|
to traverse and clear their instance's dictionaries.
|
||||||
To clear weakrefs, call :c:func:`PyObject_ClearWeakRefs`, as before.
|
To clear weakrefs, call :c:func:`PyObject_ClearWeakRefs`, as before.
|
||||||
|
|
|
@ -995,6 +995,12 @@ New Features
|
||||||
references) now supports the :ref:`Limited API <limited-c-api>`.
|
references) now supports the :ref:`Limited API <limited-c-api>`.
|
||||||
(Contributed by Victor Stinner in :gh:`108634`.)
|
(Contributed by Victor Stinner in :gh:`108634`.)
|
||||||
|
|
||||||
|
* Add :c:func:`PyObject_VisitManagedDict` and
|
||||||
|
:c:func:`PyObject_ClearManagedDict` functions which must be called by the
|
||||||
|
traverse and clear functions of a type using
|
||||||
|
:c:macro:`Py_TPFLAGS_MANAGED_DICT` flag.
|
||||||
|
(Contributed by Victor Stinner in :gh:`107073`.)
|
||||||
|
|
||||||
Porting to Python 3.13
|
Porting to Python 3.13
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|
|
@ -444,8 +444,8 @@ PyAPI_FUNC(int) _PyTrash_cond(PyObject *op, destructor dealloc);
|
||||||
|
|
||||||
PyAPI_FUNC(void *) PyObject_GetItemData(PyObject *obj);
|
PyAPI_FUNC(void *) PyObject_GetItemData(PyObject *obj);
|
||||||
|
|
||||||
PyAPI_FUNC(int) _PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg);
|
PyAPI_FUNC(int) PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg);
|
||||||
PyAPI_FUNC(void) _PyObject_ClearManagedDict(PyObject *obj);
|
PyAPI_FUNC(void) PyObject_ClearManagedDict(PyObject *obj);
|
||||||
|
|
||||||
#define TYPE_MAX_WATCHERS 8
|
#define TYPE_MAX_WATCHERS 8
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Add :c:func:`PyObject_VisitManagedDict` and :c:func:`PyObject_ClearManagedDict`
|
||||||
|
functions which must be called by the traverse and clear functions of a type
|
||||||
|
using :c:macro:`Py_TPFLAGS_MANAGED_DICT` flag. Patch by Victor Stinner.
|
|
@ -816,7 +816,7 @@ FutureObj_clear(FutureObj *fut)
|
||||||
Py_CLEAR(fut->fut_source_tb);
|
Py_CLEAR(fut->fut_source_tb);
|
||||||
Py_CLEAR(fut->fut_cancel_msg);
|
Py_CLEAR(fut->fut_cancel_msg);
|
||||||
Py_CLEAR(fut->fut_cancelled_exc);
|
Py_CLEAR(fut->fut_cancelled_exc);
|
||||||
_PyObject_ClearManagedDict((PyObject *)fut);
|
PyObject_ClearManagedDict((PyObject *)fut);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -834,7 +834,7 @@ FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg)
|
||||||
Py_VISIT(fut->fut_source_tb);
|
Py_VISIT(fut->fut_source_tb);
|
||||||
Py_VISIT(fut->fut_cancel_msg);
|
Py_VISIT(fut->fut_cancel_msg);
|
||||||
Py_VISIT(fut->fut_cancelled_exc);
|
Py_VISIT(fut->fut_cancelled_exc);
|
||||||
_PyObject_VisitManagedDict((PyObject *)fut, visit, arg);
|
PyObject_VisitManagedDict((PyObject *)fut, visit, arg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2181,7 +2181,7 @@ TaskObj_traverse(TaskObj *task, visitproc visit, void *arg)
|
||||||
Py_VISIT(fut->fut_source_tb);
|
Py_VISIT(fut->fut_source_tb);
|
||||||
Py_VISIT(fut->fut_cancel_msg);
|
Py_VISIT(fut->fut_cancel_msg);
|
||||||
Py_VISIT(fut->fut_cancelled_exc);
|
Py_VISIT(fut->fut_cancelled_exc);
|
||||||
_PyObject_VisitManagedDict((PyObject *)fut, visit, arg);
|
PyObject_VisitManagedDict((PyObject *)fut, visit, arg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -805,13 +805,13 @@ static int
|
||||||
heapmanaged_traverse(HeapCTypeObject *self, visitproc visit, void *arg)
|
heapmanaged_traverse(HeapCTypeObject *self, visitproc visit, void *arg)
|
||||||
{
|
{
|
||||||
Py_VISIT(Py_TYPE(self));
|
Py_VISIT(Py_TYPE(self));
|
||||||
return _PyObject_VisitManagedDict((PyObject *)self, visit, arg);
|
return PyObject_VisitManagedDict((PyObject *)self, visit, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
heapmanaged_clear(HeapCTypeObject *self)
|
heapmanaged_clear(HeapCTypeObject *self)
|
||||||
{
|
{
|
||||||
_PyObject_ClearManagedDict((PyObject *)self);
|
PyObject_ClearManagedDict((PyObject *)self);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -819,7 +819,7 @@ static void
|
||||||
heapmanaged_dealloc(HeapCTypeObject *self)
|
heapmanaged_dealloc(HeapCTypeObject *self)
|
||||||
{
|
{
|
||||||
PyTypeObject *tp = Py_TYPE(self);
|
PyTypeObject *tp = Py_TYPE(self);
|
||||||
_PyObject_ClearManagedDict((PyObject *)self);
|
PyObject_ClearManagedDict((PyObject *)self);
|
||||||
PyObject_GC_UnTrack(self);
|
PyObject_GC_UnTrack(self);
|
||||||
PyObject_GC_Del(self);
|
PyObject_GC_Del(self);
|
||||||
Py_DECREF(tp);
|
Py_DECREF(tp);
|
||||||
|
|
|
@ -2923,7 +2923,7 @@ settrace_to_error(PyObject *self, PyObject *list)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
clear_managed_dict(PyObject *self, PyObject *obj)
|
clear_managed_dict(PyObject *self, PyObject *obj)
|
||||||
{
|
{
|
||||||
_PyObject_ClearManagedDict(obj);
|
PyObject_ClearManagedDict(obj);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5649,7 +5649,7 @@ _PyObject_FreeInstanceAttributes(PyObject *self)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
|
PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
|
||||||
{
|
{
|
||||||
PyTypeObject *tp = Py_TYPE(obj);
|
PyTypeObject *tp = Py_TYPE(obj);
|
||||||
if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
|
if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
|
||||||
|
@ -5672,7 +5672,7 @@ _PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_PyObject_ClearManagedDict(PyObject *obj)
|
PyObject_ClearManagedDict(PyObject *obj)
|
||||||
{
|
{
|
||||||
PyTypeObject *tp = Py_TYPE(obj);
|
PyTypeObject *tp = Py_TYPE(obj);
|
||||||
if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
|
if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
|
||||||
|
|
|
@ -1835,7 +1835,7 @@ subtype_traverse(PyObject *self, visitproc visit, void *arg)
|
||||||
assert(base->tp_dictoffset == 0);
|
assert(base->tp_dictoffset == 0);
|
||||||
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
|
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
|
||||||
assert(type->tp_dictoffset == -1);
|
assert(type->tp_dictoffset == -1);
|
||||||
int err = _PyObject_VisitManagedDict(self, visit, arg);
|
int err = PyObject_VisitManagedDict(self, visit, arg);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -1905,7 +1905,7 @@ subtype_clear(PyObject *self)
|
||||||
__dict__ slots (as in the case 'self.__dict__ is self'). */
|
__dict__ slots (as in the case 'self.__dict__ is self'). */
|
||||||
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
|
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
|
||||||
if ((base->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
|
if ((base->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
|
||||||
_PyObject_ClearManagedDict(self);
|
PyObject_ClearManagedDict(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (type->tp_dictoffset != base->tp_dictoffset) {
|
else if (type->tp_dictoffset != base->tp_dictoffset) {
|
||||||
|
|
|
@ -200,7 +200,7 @@ typevar_dealloc(PyObject *self)
|
||||||
Py_XDECREF(tv->evaluate_bound);
|
Py_XDECREF(tv->evaluate_bound);
|
||||||
Py_XDECREF(tv->constraints);
|
Py_XDECREF(tv->constraints);
|
||||||
Py_XDECREF(tv->evaluate_constraints);
|
Py_XDECREF(tv->evaluate_constraints);
|
||||||
_PyObject_ClearManagedDict(self);
|
PyObject_ClearManagedDict(self);
|
||||||
PyObject_ClearWeakRefs(self);
|
PyObject_ClearWeakRefs(self);
|
||||||
|
|
||||||
Py_TYPE(self)->tp_free(self);
|
Py_TYPE(self)->tp_free(self);
|
||||||
|
@ -216,7 +216,7 @@ typevar_traverse(PyObject *self, visitproc visit, void *arg)
|
||||||
Py_VISIT(tv->evaluate_bound);
|
Py_VISIT(tv->evaluate_bound);
|
||||||
Py_VISIT(tv->constraints);
|
Py_VISIT(tv->constraints);
|
||||||
Py_VISIT(tv->evaluate_constraints);
|
Py_VISIT(tv->evaluate_constraints);
|
||||||
_PyObject_VisitManagedDict(self, visit, arg);
|
PyObject_VisitManagedDict(self, visit, arg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +227,7 @@ typevar_clear(typevarobject *self)
|
||||||
Py_CLEAR(self->evaluate_bound);
|
Py_CLEAR(self->evaluate_bound);
|
||||||
Py_CLEAR(self->constraints);
|
Py_CLEAR(self->constraints);
|
||||||
Py_CLEAR(self->evaluate_constraints);
|
Py_CLEAR(self->evaluate_constraints);
|
||||||
_PyObject_ClearManagedDict((PyObject *)self);
|
PyObject_ClearManagedDict((PyObject *)self);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -744,7 +744,7 @@ paramspec_dealloc(PyObject *self)
|
||||||
|
|
||||||
Py_DECREF(ps->name);
|
Py_DECREF(ps->name);
|
||||||
Py_XDECREF(ps->bound);
|
Py_XDECREF(ps->bound);
|
||||||
_PyObject_ClearManagedDict(self);
|
PyObject_ClearManagedDict(self);
|
||||||
PyObject_ClearWeakRefs(self);
|
PyObject_ClearWeakRefs(self);
|
||||||
|
|
||||||
Py_TYPE(self)->tp_free(self);
|
Py_TYPE(self)->tp_free(self);
|
||||||
|
@ -757,7 +757,7 @@ paramspec_traverse(PyObject *self, visitproc visit, void *arg)
|
||||||
Py_VISIT(Py_TYPE(self));
|
Py_VISIT(Py_TYPE(self));
|
||||||
paramspecobject *ps = (paramspecobject *)self;
|
paramspecobject *ps = (paramspecobject *)self;
|
||||||
Py_VISIT(ps->bound);
|
Py_VISIT(ps->bound);
|
||||||
_PyObject_VisitManagedDict(self, visit, arg);
|
PyObject_VisitManagedDict(self, visit, arg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -765,7 +765,7 @@ static int
|
||||||
paramspec_clear(paramspecobject *self)
|
paramspec_clear(paramspecobject *self)
|
||||||
{
|
{
|
||||||
Py_CLEAR(self->bound);
|
Py_CLEAR(self->bound);
|
||||||
_PyObject_ClearManagedDict((PyObject *)self);
|
PyObject_ClearManagedDict((PyObject *)self);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1026,7 +1026,7 @@ typevartuple_dealloc(PyObject *self)
|
||||||
typevartupleobject *tvt = (typevartupleobject *)self;
|
typevartupleobject *tvt = (typevartupleobject *)self;
|
||||||
|
|
||||||
Py_DECREF(tvt->name);
|
Py_DECREF(tvt->name);
|
||||||
_PyObject_ClearManagedDict(self);
|
PyObject_ClearManagedDict(self);
|
||||||
PyObject_ClearWeakRefs(self);
|
PyObject_ClearWeakRefs(self);
|
||||||
|
|
||||||
Py_TYPE(self)->tp_free(self);
|
Py_TYPE(self)->tp_free(self);
|
||||||
|
@ -1165,14 +1165,14 @@ static int
|
||||||
typevartuple_traverse(PyObject *self, visitproc visit, void *arg)
|
typevartuple_traverse(PyObject *self, visitproc visit, void *arg)
|
||||||
{
|
{
|
||||||
Py_VISIT(Py_TYPE(self));
|
Py_VISIT(Py_TYPE(self));
|
||||||
_PyObject_VisitManagedDict(self, visit, arg);
|
PyObject_VisitManagedDict(self, visit, arg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
typevartuple_clear(PyObject *self)
|
typevartuple_clear(PyObject *self)
|
||||||
{
|
{
|
||||||
_PyObject_ClearManagedDict(self);
|
PyObject_ClearManagedDict(self);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue