bpo-40170: Convert PyObject_IS_GC() macro to a function (GH-19464)
This commit is contained in:
parent
a5900ecf9f
commit
675d9a3d7a
|
@ -60,6 +60,15 @@ Constructors for container types must conform to two rules:
|
||||||
followed by the :c:member:`~PyTypeObject.tp_traverse` handler become valid, usually near the
|
followed by the :c:member:`~PyTypeObject.tp_traverse` handler become valid, usually near the
|
||||||
end of the constructor.
|
end of the constructor.
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: int PyObject_IS_GC(PyObject *obj)
|
||||||
|
|
||||||
|
Returns non-zero if the object implements the garbage collector protocol,
|
||||||
|
otherwise returns 0.
|
||||||
|
|
||||||
|
The object cannot be tracked by the garbage collector if this function returns 0.
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: int PyObject_GC_IsTracked(PyObject *op)
|
.. c:function:: int PyObject_GC_IsTracked(PyObject *op)
|
||||||
|
|
||||||
Returns 1 if the object type of *op* implements the GC protocol and *op* is being
|
Returns 1 if the object type of *op* implements the GC protocol and *op* is being
|
||||||
|
|
|
@ -120,10 +120,9 @@ PyAPI_FUNC(Py_ssize_t) _PyGC_CollectNoFail(void);
|
||||||
PyAPI_FUNC(Py_ssize_t) _PyGC_CollectIfEnabled(void);
|
PyAPI_FUNC(Py_ssize_t) _PyGC_CollectIfEnabled(void);
|
||||||
|
|
||||||
|
|
||||||
/* Test if an object has a GC head */
|
/* Test if an object implements the garbage collector protocol */
|
||||||
#define PyObject_IS_GC(o) \
|
PyAPI_FUNC(int) PyObject_IS_GC(PyObject *obj);
|
||||||
(PyType_IS_GC(Py_TYPE(o)) \
|
|
||||||
&& (Py_TYPE(o)->tp_is_gc == NULL || Py_TYPE(o)->tp_is_gc(o)))
|
|
||||||
|
|
||||||
/* Code built with Py_BUILD_CORE must include pycore_gc.h instead which
|
/* Code built with Py_BUILD_CORE must include pycore_gc.h instead which
|
||||||
defines a different _PyGC_FINALIZED() macro. */
|
defines a different _PyGC_FINALIZED() macro. */
|
||||||
|
|
|
@ -102,6 +102,15 @@ _PyType_HasFeature(PyTypeObject *type, unsigned long feature) {
|
||||||
return ((type->tp_flags & feature) != 0);
|
return ((type->tp_flags & feature) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fast inlined version of PyObject_IS_GC()
|
||||||
|
static inline int
|
||||||
|
_PyObject_IS_GC(PyObject *obj)
|
||||||
|
{
|
||||||
|
return (PyType_IS_GC(Py_TYPE(obj))
|
||||||
|
&& (Py_TYPE(obj)->tp_is_gc == NULL
|
||||||
|
|| Py_TYPE(obj)->tp_is_gc(obj)));
|
||||||
|
}
|
||||||
|
|
||||||
// Fast inlined version of PyType_IS_GC()
|
// Fast inlined version of PyType_IS_GC()
|
||||||
#define _PyType_IS_GC(t) _PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC)
|
#define _PyType_IS_GC(t) _PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Convert :c:func:`PyObject_IS_GC` macro to a function to hide
|
||||||
|
implementation details.
|
|
@ -442,7 +442,7 @@ visit_decref(PyObject *op, void *parent)
|
||||||
{
|
{
|
||||||
_PyObject_ASSERT(_PyObject_CAST(parent), !_PyObject_IsFreed(op));
|
_PyObject_ASSERT(_PyObject_CAST(parent), !_PyObject_IsFreed(op));
|
||||||
|
|
||||||
if (PyObject_IS_GC(op)) {
|
if (_PyObject_IS_GC(op)) {
|
||||||
PyGC_Head *gc = AS_GC(op);
|
PyGC_Head *gc = AS_GC(op);
|
||||||
/* We're only interested in gc_refs for objects in the
|
/* We're only interested in gc_refs for objects in the
|
||||||
* generation being collected, which can be recognized
|
* generation being collected, which can be recognized
|
||||||
|
@ -478,7 +478,7 @@ subtract_refs(PyGC_Head *containers)
|
||||||
static int
|
static int
|
||||||
visit_reachable(PyObject *op, PyGC_Head *reachable)
|
visit_reachable(PyObject *op, PyGC_Head *reachable)
|
||||||
{
|
{
|
||||||
if (!PyObject_IS_GC(op)) {
|
if (!_PyObject_IS_GC(op)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -705,7 +705,7 @@ clear_unreachable_mask(PyGC_Head *unreachable)
|
||||||
static int
|
static int
|
||||||
visit_move(PyObject *op, PyGC_Head *tolist)
|
visit_move(PyObject *op, PyGC_Head *tolist)
|
||||||
{
|
{
|
||||||
if (PyObject_IS_GC(op)) {
|
if (_PyObject_IS_GC(op)) {
|
||||||
PyGC_Head *gc = AS_GC(op);
|
PyGC_Head *gc = AS_GC(op);
|
||||||
if (gc_is_collecting(gc)) {
|
if (gc_is_collecting(gc)) {
|
||||||
gc_list_move(gc, tolist);
|
gc_list_move(gc, tolist);
|
||||||
|
@ -1716,7 +1716,7 @@ gc_get_referents(PyObject *self, PyObject *args)
|
||||||
traverseproc traverse;
|
traverseproc traverse;
|
||||||
PyObject *obj = PyTuple_GET_ITEM(args, i);
|
PyObject *obj = PyTuple_GET_ITEM(args, i);
|
||||||
|
|
||||||
if (! PyObject_IS_GC(obj))
|
if (!_PyObject_IS_GC(obj))
|
||||||
continue;
|
continue;
|
||||||
traverse = Py_TYPE(obj)->tp_traverse;
|
traverse = Py_TYPE(obj)->tp_traverse;
|
||||||
if (! traverse)
|
if (! traverse)
|
||||||
|
@ -1856,7 +1856,7 @@ gc_is_tracked(PyObject *module, PyObject *obj)
|
||||||
{
|
{
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
|
|
||||||
if (PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj))
|
if (_PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj))
|
||||||
result = Py_True;
|
result = Py_True;
|
||||||
else
|
else
|
||||||
result = Py_False;
|
result = Py_False;
|
||||||
|
@ -1877,7 +1877,7 @@ static PyObject *
|
||||||
gc_is_finalized(PyObject *module, PyObject *obj)
|
gc_is_finalized(PyObject *module, PyObject *obj)
|
||||||
/*[clinic end generated code: output=e1516ac119a918ed input=201d0c58f69ae390]*/
|
/*[clinic end generated code: output=e1516ac119a918ed input=201d0c58f69ae390]*/
|
||||||
{
|
{
|
||||||
if (PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(AS_GC(obj))) {
|
if (_PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(AS_GC(obj))) {
|
||||||
Py_RETURN_TRUE;
|
Py_RETURN_TRUE;
|
||||||
}
|
}
|
||||||
Py_RETURN_FALSE;
|
Py_RETURN_FALSE;
|
||||||
|
@ -2204,6 +2204,12 @@ PyObject_GC_UnTrack(void *op_raw)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PyObject_IS_GC(PyObject *obj)
|
||||||
|
{
|
||||||
|
return _PyObject_IS_GC(obj);
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_PyObject_GC_Alloc(int use_calloc, size_t basicsize)
|
_PyObject_GC_Alloc(int use_calloc, size_t basicsize)
|
||||||
{
|
{
|
||||||
|
@ -2317,7 +2323,7 @@ PyObject_GC_Del(void *op)
|
||||||
int
|
int
|
||||||
PyObject_GC_IsTracked(PyObject* obj)
|
PyObject_GC_IsTracked(PyObject* obj)
|
||||||
{
|
{
|
||||||
if (PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj)) {
|
if (_PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2326,7 +2332,7 @@ PyObject_GC_IsTracked(PyObject* obj)
|
||||||
int
|
int
|
||||||
PyObject_GC_IsFinalized(PyObject *obj)
|
PyObject_GC_IsFinalized(PyObject *obj)
|
||||||
{
|
{
|
||||||
if (PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(AS_GC(obj))) {
|
if (_PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(AS_GC(obj))) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -2031,7 +2031,7 @@ _PyTrash_deposit_object(PyObject *op)
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
struct _gc_runtime_state *gcstate = &tstate->interp->gc;
|
struct _gc_runtime_state *gcstate = &tstate->interp->gc;
|
||||||
|
|
||||||
_PyObject_ASSERT(op, PyObject_IS_GC(op));
|
_PyObject_ASSERT(op, _PyObject_IS_GC(op));
|
||||||
_PyObject_ASSERT(op, !_PyObject_GC_IS_TRACKED(op));
|
_PyObject_ASSERT(op, !_PyObject_GC_IS_TRACKED(op));
|
||||||
_PyObject_ASSERT(op, Py_REFCNT(op) == 0);
|
_PyObject_ASSERT(op, Py_REFCNT(op) == 0);
|
||||||
_PyGCHead_SET_PREV(_Py_AS_GC(op), gcstate->trash_delete_later);
|
_PyGCHead_SET_PREV(_Py_AS_GC(op), gcstate->trash_delete_later);
|
||||||
|
@ -2043,7 +2043,7 @@ void
|
||||||
_PyTrash_thread_deposit_object(PyObject *op)
|
_PyTrash_thread_deposit_object(PyObject *op)
|
||||||
{
|
{
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
_PyObject_ASSERT(op, PyObject_IS_GC(op));
|
_PyObject_ASSERT(op, _PyObject_IS_GC(op));
|
||||||
_PyObject_ASSERT(op, !_PyObject_GC_IS_TRACKED(op));
|
_PyObject_ASSERT(op, !_PyObject_GC_IS_TRACKED(op));
|
||||||
_PyObject_ASSERT(op, Py_REFCNT(op) == 0);
|
_PyObject_ASSERT(op, Py_REFCNT(op) == 0);
|
||||||
_PyGCHead_SET_PREV(_Py_AS_GC(op), tstate->trash_delete_later);
|
_PyGCHead_SET_PREV(_Py_AS_GC(op), tstate->trash_delete_later);
|
||||||
|
|
|
@ -19,6 +19,7 @@ Data members:
|
||||||
#include "frameobject.h"
|
#include "frameobject.h"
|
||||||
#include "pycore_ceval.h" // _Py_RecursionLimitLowerWaterMark()
|
#include "pycore_ceval.h" // _Py_RecursionLimitLowerWaterMark()
|
||||||
#include "pycore_initconfig.h"
|
#include "pycore_initconfig.h"
|
||||||
|
#include "pycore_object.h"
|
||||||
#include "pycore_pathconfig.h"
|
#include "pycore_pathconfig.h"
|
||||||
#include "pycore_pyerrors.h"
|
#include "pycore_pyerrors.h"
|
||||||
#include "pycore_pylifecycle.h"
|
#include "pycore_pylifecycle.h"
|
||||||
|
@ -1679,7 +1680,7 @@ _PySys_GetSizeOf(PyObject *o)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add gc_head size */
|
/* add gc_head size */
|
||||||
if (PyObject_IS_GC(o))
|
if (_PyObject_IS_GC(o))
|
||||||
return ((size_t)size) + sizeof(PyGC_Head);
|
return ((size_t)size) + sizeof(PyGC_Head);
|
||||||
return (size_t)size;
|
return (size_t)size;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue