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)
+
+ 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
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. */
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)
--- /dev/null
+Convert :c:func:`PyObject_IS_GC` macro to a function to hide
+implementation details.
{
_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
static int
visit_reachable(PyObject *op, PyGC_Head *reachable)
{
- if (!PyObject_IS_GC(op)) {
+ if (!_PyObject_IS_GC(op)) {
return 0;
}
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);
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)
{
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;
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;
}
}
+int
+PyObject_IS_GC(PyObject *obj)
+{
+ return _PyObject_IS_GC(obj);
+}
+
static PyObject *
_PyObject_GC_Alloc(int use_calloc, size_t basicsize)
{
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;
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;
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);
_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);
#include "frameobject.h"
#include "pycore_ceval.h" // _Py_RecursionLimitLowerWaterMark()
#include "pycore_initconfig.h"
+#include "pycore_object.h"
#include "pycore_pathconfig.h"
#include "pycore_pyerrors.h"
#include "pycore_pylifecycle.h"
}
/* 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;
}