Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-40170: Convert PyObject_IS_GC() macro to a function #19464

Merged
merged 14 commits into from
Apr 14, 2020
9 changes: 9 additions & 0 deletions Doc/c-api/gcsupport.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
end of the constructor.


.. c:function:: int PyObject_IS_GC(PyObject *obj)
shihai1991 marked this conversation as resolved.
Show resolved Hide resolved

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)

Returns 1 if the object type of *op* implements the GC protocol and *op* is being
Expand Down
7 changes: 3 additions & 4 deletions Include/cpython/objimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,9 @@ PyAPI_FUNC(Py_ssize_t) _PyGC_CollectNoFail(void);
PyAPI_FUNC(Py_ssize_t) _PyGC_CollectIfEnabled(void);


/* Test if an object has a GC head */
#define PyObject_IS_GC(o) \
(PyType_IS_GC(Py_TYPE(o)) \
&& (Py_TYPE(o)->tp_is_gc == NULL || Py_TYPE(o)->tp_is_gc(o)))
/* Test if an object implements the garbage collector protocol */
PyAPI_FUNC(int) PyObject_IS_GC(PyObject *obj);


/* Code built with Py_BUILD_CORE must include pycore_gc.h instead which
defines a different _PyGC_FINALIZED() macro. */
Expand Down
9 changes: 9 additions & 0 deletions Include/internal/pycore_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,15 @@ _PyType_HasFeature(PyTypeObject *type, unsigned long feature) {
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()
#define _PyType_IS_GC(t) _PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Convert :c:func:`PyObject_IS_GC` macro to a function to hide
implementation details.
22 changes: 14 additions & 8 deletions Modules/gcmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ visit_decref(PyObject *op, void *parent)
{
_PyObject_ASSERT(_PyObject_CAST(parent), !_PyObject_IsFreed(op));

if (PyObject_IS_GC(op)) {
if (_PyObject_IS_GC(op)) {
PyGC_Head *gc = AS_GC(op);
/* We're only interested in gc_refs for objects in the
* generation being collected, which can be recognized
Expand Down Expand Up @@ -477,7 +477,7 @@ subtract_refs(PyGC_Head *containers)
static int
visit_reachable(PyObject *op, PyGC_Head *reachable)
{
if (!PyObject_IS_GC(op)) {
if (!_PyObject_IS_GC(op)) {
return 0;
}

Expand Down Expand Up @@ -704,7 +704,7 @@ clear_unreachable_mask(PyGC_Head *unreachable)
static int
visit_move(PyObject *op, PyGC_Head *tolist)
{
if (PyObject_IS_GC(op)) {
if (_PyObject_IS_GC(op)) {
PyGC_Head *gc = AS_GC(op);
if (gc_is_collecting(gc)) {
gc_list_move(gc, tolist);
Expand Down Expand Up @@ -1715,7 +1715,7 @@ gc_get_referents(PyObject *self, PyObject *args)
traverseproc traverse;
PyObject *obj = PyTuple_GET_ITEM(args, i);

if (! PyObject_IS_GC(obj))
if (!_PyObject_IS_GC(obj))
continue;
traverse = Py_TYPE(obj)->tp_traverse;
if (! traverse)
Expand Down Expand Up @@ -1855,7 +1855,7 @@ gc_is_tracked(PyObject *module, PyObject *obj)
{
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;
else
result = Py_False;
Expand All @@ -1876,7 +1876,7 @@ static PyObject *
gc_is_finalized(PyObject *module, PyObject *obj)
/*[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_FALSE;
Expand Down Expand Up @@ -2203,6 +2203,12 @@ PyObject_GC_UnTrack(void *op_raw)
}
}

int
PyObject_IS_GC(PyObject *obj)
{
return _PyObject_IS_GC(obj);
}

static PyObject *
_PyObject_GC_Alloc(int use_calloc, size_t basicsize)
{
Expand Down Expand Up @@ -2316,7 +2322,7 @@ PyObject_GC_Del(void *op)
int
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 0;
Expand All @@ -2325,7 +2331,7 @@ PyObject_GC_IsTracked(PyObject* obj)
int
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 0;
Expand Down
4 changes: 2 additions & 2 deletions Objects/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -2030,7 +2030,7 @@ _PyTrash_deposit_object(PyObject *op)
PyThreadState *tstate = _PyThreadState_GET();
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, Py_REFCNT(op) == 0);
_PyGCHead_SET_PREV(_Py_AS_GC(op), gcstate->trash_delete_later);
Expand All @@ -2042,7 +2042,7 @@ void
_PyTrash_thread_deposit_object(PyObject *op)
{
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, Py_REFCNT(op) == 0);
_PyGCHead_SET_PREV(_Py_AS_GC(op), tstate->trash_delete_later);
Expand Down
3 changes: 2 additions & 1 deletion Python/sysmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Data members:
#include "frameobject.h"
#include "pycore_ceval.h"
#include "pycore_initconfig.h"
#include "pycore_object.h"
#include "pycore_pathconfig.h"
#include "pycore_pyerrors.h"
#include "pycore_pylifecycle.h"
Expand Down Expand Up @@ -1678,7 +1679,7 @@ _PySys_GetSizeOf(PyObject *o)
}

/* 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;
}
Expand Down