[Python-checkins] bpo-40170: Convert PyObject_IS_GC() macro to a function (GH-19464)

Hai Shi webhook-mailer at python.org
Tue Apr 14 14:11:25 EDT 2020


https://github.com/python/cpython/commit/675d9a3d7afc767a2818c84da7ba4bf4181dcf26
commit: 675d9a3d7afc767a2818c84da7ba4bf4181dcf26
branch: master
author: Hai Shi <shihai1992 at gmail.com>
committer: GitHub <noreply at github.com>
date: 2020-04-14T20:11:20+02:00
summary:

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

files:
A Misc/NEWS.d/next/C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst
M Doc/c-api/gcsupport.rst
M Include/cpython/objimpl.h
M Include/internal/pycore_object.h
M Modules/gcmodule.c
M Objects/object.c
M Python/sysmodule.c

diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst
index 4cab0f544ed81..eee114c19d590 100644
--- a/Doc/c-api/gcsupport.rst
+++ b/Doc/c-api/gcsupport.rst
@@ -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)
+
+   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
diff --git a/Include/cpython/objimpl.h b/Include/cpython/objimpl.h
index 6634f29c8c873..b835936db7011 100644
--- a/Include/cpython/objimpl.h
+++ b/Include/cpython/objimpl.h
@@ -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. */
diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h
index 7c0f24ac07d7f..32e86d06db5b4 100644
--- a/Include/internal/pycore_object.h
+++ b/Include/internal/pycore_object.h
@@ -102,6 +102,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)
 
diff --git a/Misc/NEWS.d/next/C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst b/Misc/NEWS.d/next/C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst
new file mode 100644
index 0000000000000..832b7f6e081d5
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2020-04-11-06-12-44.bpo-40170.cmM9oK.rst	
@@ -0,0 +1,2 @@
+Convert :c:func:`PyObject_IS_GC` macro to a function to hide
+implementation details.
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c
index 281ab33e06523..d2cd2c9296616 100644
--- a/Modules/gcmodule.c
+++ b/Modules/gcmodule.c
@@ -442,7 +442,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
@@ -478,7 +478,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;
     }
 
@@ -705,7 +705,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);
@@ -1716,7 +1716,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)
@@ -1856,7 +1856,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;
@@ -1877,7 +1877,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;
@@ -2204,6 +2204,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)
 {
@@ -2317,7 +2323,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;
@@ -2326,7 +2332,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;
diff --git a/Objects/object.c b/Objects/object.c
index c759ccc568472..75ea92ad9005c 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -2031,7 +2031,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);
@@ -2043,7 +2043,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);
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index 79e5df06d3037..741979a09acc0 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -19,6 +19,7 @@ Data members:
 #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"
@@ -1679,7 +1680,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;
 }



More information about the Python-checkins mailing list