[Python-checkins] bpo-40241: Add pycore_gc.h header file (GH-19494)

Victor Stinner webhook-mailer at python.org
Mon Apr 13 05:38:47 EDT 2020


https://github.com/python/cpython/commit/0135598d729d01f35ce08d47160adaa095a6149f
commit: 0135598d729d01f35ce08d47160adaa095a6149f
branch: master
author: Victor Stinner <vstinner at python.org>
committer: GitHub <noreply at github.com>
date: 2020-04-13T11:38:42+02:00
summary:

bpo-40241: Add pycore_gc.h header file (GH-19494)

Move the PyGC_Head structure and the following private macros to the
internal C API:

* _PyGCHead_FINALIZED()
* _PyGCHead_NEXT()
* _PyGCHead_PREV()
* _PyGCHead_SET_FINALIZED()
* _PyGCHead_SET_NEXT()
* _PyGCHead_SET_PREV()
* _PyGC_FINALIZED()
* _PyGC_PREV_MASK
* _PyGC_PREV_MASK_COLLECTING
* _PyGC_PREV_MASK_FINALIZED
* _PyGC_PREV_SHIFT
* _PyGC_SET_FINALIZED()
* _PyObject_GC_IS_TRACKED()
* _PyObject_GC_MAY_BE_TRACKED()
* _Py_AS_GC(o)

Keep the private _PyGC_FINALIZED() macro in the public C API for
backward compatibility with Python 3.8: make it an alias to the new
PyObject_GC_IsFinalized() function.

Move the SIZEOF_PYGC_HEAD constant from _testcapi module to
_testinternalcapi module.

files:
A Include/internal/pycore_gc.h
A Misc/NEWS.d/next/C API/2020-04-13-02-56-24.bpo-40241._FOf7E.rst
M Include/cpython/objimpl.h
M Include/internal/pycore_pymem.h
M Lib/test/support/__init__.py
M Lib/test/test_sys.py
M Modules/_testcapimodule.c
M Modules/_testinternalcapi.c

diff --git a/Include/cpython/objimpl.h b/Include/cpython/objimpl.h
index 832622cb61921..6634f29c8c873 100644
--- a/Include/cpython/objimpl.h
+++ b/Include/cpython/objimpl.h
@@ -125,61 +125,12 @@ PyAPI_FUNC(Py_ssize_t) _PyGC_CollectIfEnabled(void);
     (PyType_IS_GC(Py_TYPE(o)) \
      && (Py_TYPE(o)->tp_is_gc == NULL || Py_TYPE(o)->tp_is_gc(o)))
 
-/* GC information is stored BEFORE the object structure. */
-typedef struct {
-    // Pointer to next object in the list.
-    // 0 means the object is not tracked
-    uintptr_t _gc_next;
-
-    // Pointer to previous object in the list.
-    // Lowest two bits are used for flags documented later.
-    uintptr_t _gc_prev;
-} PyGC_Head;
-
-#define _Py_AS_GC(o) ((PyGC_Head *)(o)-1)
-
-/* True if the object is currently tracked by the GC. */
-#define _PyObject_GC_IS_TRACKED(o) (_Py_AS_GC(o)->_gc_next != 0)
-
-/* True if the object may be tracked by the GC in the future, or already is.
-   This can be useful to implement some optimizations. */
-#define _PyObject_GC_MAY_BE_TRACKED(obj) \
-    (PyObject_IS_GC(obj) && \
-        (!PyTuple_CheckExact(obj) || _PyObject_GC_IS_TRACKED(obj)))
-
-
-/* Bit flags for _gc_prev */
-/* Bit 0 is set when tp_finalize is called */
-#define _PyGC_PREV_MASK_FINALIZED  (1)
-/* Bit 1 is set when the object is in generation which is GCed currently. */
-#define _PyGC_PREV_MASK_COLLECTING (2)
-/* The (N-2) most significant bits contain the real address. */
-#define _PyGC_PREV_SHIFT           (2)
-#define _PyGC_PREV_MASK            (((uintptr_t) -1) << _PyGC_PREV_SHIFT)
-
-// Lowest bit of _gc_next is used for flags only in GC.
-// But it is always 0 for normal code.
-#define _PyGCHead_NEXT(g)        ((PyGC_Head*)(g)->_gc_next)
-#define _PyGCHead_SET_NEXT(g, p) ((g)->_gc_next = (uintptr_t)(p))
-
-// Lowest two bits of _gc_prev is used for _PyGC_PREV_MASK_* flags.
-#define _PyGCHead_PREV(g) ((PyGC_Head*)((g)->_gc_prev & _PyGC_PREV_MASK))
-#define _PyGCHead_SET_PREV(g, p) do { \
-    assert(((uintptr_t)p & ~_PyGC_PREV_MASK) == 0); \
-    (g)->_gc_prev = ((g)->_gc_prev & ~_PyGC_PREV_MASK) \
-        | ((uintptr_t)(p)); \
-    } while (0)
-
-#define _PyGCHead_FINALIZED(g) \
-    (((g)->_gc_prev & _PyGC_PREV_MASK_FINALIZED) != 0)
-#define _PyGCHead_SET_FINALIZED(g) \
-    ((g)->_gc_prev |= _PyGC_PREV_MASK_FINALIZED)
-
-#define _PyGC_FINALIZED(o) \
-    _PyGCHead_FINALIZED(_Py_AS_GC(o))
-#define _PyGC_SET_FINALIZED(o) \
-    _PyGCHead_SET_FINALIZED(_Py_AS_GC(o))
-
+/* Code built with Py_BUILD_CORE must include pycore_gc.h instead which
+   defines a different _PyGC_FINALIZED() macro. */
+#ifndef Py_BUILD_CORE
+   // Kept for backward compatibility with Python 3.8
+#  define _PyGC_FINALIZED(o) PyObject_GC_IsFinalized(o)
+#endif
 
 PyAPI_FUNC(PyObject *) _PyObject_GC_Malloc(size_t size);
 PyAPI_FUNC(PyObject *) _PyObject_GC_Calloc(size_t size);
diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h
new file mode 100644
index 0000000000000..7309205ed1229
--- /dev/null
+++ b/Include/internal/pycore_gc.h
@@ -0,0 +1,69 @@
+#ifndef Py_INTERNAL_GC_H
+#define Py_INTERNAL_GC_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef Py_BUILD_CORE
+#  error "this header requires Py_BUILD_CORE define"
+#endif
+
+/* GC information is stored BEFORE the object structure. */
+typedef struct {
+    // Pointer to next object in the list.
+    // 0 means the object is not tracked
+    uintptr_t _gc_next;
+
+    // Pointer to previous object in the list.
+    // Lowest two bits are used for flags documented later.
+    uintptr_t _gc_prev;
+} PyGC_Head;
+
+#define _Py_AS_GC(o) ((PyGC_Head *)(o)-1)
+
+/* True if the object is currently tracked by the GC. */
+#define _PyObject_GC_IS_TRACKED(o) (_Py_AS_GC(o)->_gc_next != 0)
+
+/* True if the object may be tracked by the GC in the future, or already is.
+   This can be useful to implement some optimizations. */
+#define _PyObject_GC_MAY_BE_TRACKED(obj) \
+    (PyObject_IS_GC(obj) && \
+        (!PyTuple_CheckExact(obj) || _PyObject_GC_IS_TRACKED(obj)))
+
+
+/* Bit flags for _gc_prev */
+/* Bit 0 is set when tp_finalize is called */
+#define _PyGC_PREV_MASK_FINALIZED  (1)
+/* Bit 1 is set when the object is in generation which is GCed currently. */
+#define _PyGC_PREV_MASK_COLLECTING (2)
+/* The (N-2) most significant bits contain the real address. */
+#define _PyGC_PREV_SHIFT           (2)
+#define _PyGC_PREV_MASK            (((uintptr_t) -1) << _PyGC_PREV_SHIFT)
+
+// Lowest bit of _gc_next is used for flags only in GC.
+// But it is always 0 for normal code.
+#define _PyGCHead_NEXT(g)        ((PyGC_Head*)(g)->_gc_next)
+#define _PyGCHead_SET_NEXT(g, p) ((g)->_gc_next = (uintptr_t)(p))
+
+// Lowest two bits of _gc_prev is used for _PyGC_PREV_MASK_* flags.
+#define _PyGCHead_PREV(g) ((PyGC_Head*)((g)->_gc_prev & _PyGC_PREV_MASK))
+#define _PyGCHead_SET_PREV(g, p) do { \
+    assert(((uintptr_t)p & ~_PyGC_PREV_MASK) == 0); \
+    (g)->_gc_prev = ((g)->_gc_prev & ~_PyGC_PREV_MASK) \
+        | ((uintptr_t)(p)); \
+    } while (0)
+
+#define _PyGCHead_FINALIZED(g) \
+    (((g)->_gc_prev & _PyGC_PREV_MASK_FINALIZED) != 0)
+#define _PyGCHead_SET_FINALIZED(g) \
+    ((g)->_gc_prev |= _PyGC_PREV_MASK_FINALIZED)
+
+#define _PyGC_FINALIZED(o) \
+    _PyGCHead_FINALIZED(_Py_AS_GC(o))
+#define _PyGC_SET_FINALIZED(o) \
+    _PyGCHead_SET_FINALIZED(_Py_AS_GC(o))
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_INTERNAL_GC_H */
diff --git a/Include/internal/pycore_pymem.h b/Include/internal/pycore_pymem.h
index db153e0bd2d71..34a17d5ae0979 100644
--- a/Include/internal/pycore_pymem.h
+++ b/Include/internal/pycore_pymem.h
@@ -8,7 +8,8 @@ extern "C" {
 #  error "this header requires Py_BUILD_CORE define"
 #endif
 
-#include "pymem.h"   /* PyMemAllocatorName */
+#include "pymem.h"      // PyMemAllocatorName
+#include "pycore_gc.h"  // PyGC_Head
 
 
 /* GC runtime state */
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 1f792d8514da0..9f43b4071c044 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -1764,12 +1764,12 @@ def calcvobjsize(fmt):
 _TPFLAGS_HEAPTYPE = 1<<9
 
 def check_sizeof(test, o, size):
-    import _testcapi
+    import _testinternalcapi
     result = sys.getsizeof(o)
     # add GC header size
     if ((type(o) == type) and (o.__flags__ & _TPFLAGS_HEAPTYPE) or\
         ((type(o) != type) and (type(o).__flags__ & _TPFLAGS_HAVE_GC))):
-        size += _testcapi.SIZEOF_PYGC_HEAD
+        size += _testinternalcapi.SIZEOF_PYGC_HEAD
     msg = 'wrong size for %s: got %d, expected %d' \
             % (type(o), result, size)
     test.assertEqual(result, size, msg)
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index 395725857b7c0..329f7ddeb2c57 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -1056,8 +1056,8 @@ class SizeofTest(unittest.TestCase):
     def setUp(self):
         self.P = struct.calcsize('P')
         self.longdigit = sys.int_info.sizeof_digit
-        import _testcapi
-        self.gc_headsize = _testcapi.SIZEOF_PYGC_HEAD
+        import _testinternalcapi
+        self.gc_headsize = _testinternalcapi.SIZEOF_PYGC_HEAD
 
     check_sizeof = test.support.check_sizeof
 
diff --git a/Misc/NEWS.d/next/C API/2020-04-13-02-56-24.bpo-40241._FOf7E.rst b/Misc/NEWS.d/next/C API/2020-04-13-02-56-24.bpo-40241._FOf7E.rst
new file mode 100644
index 0000000000000..b3e4aafe992df
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2020-04-13-02-56-24.bpo-40241._FOf7E.rst	
@@ -0,0 +1 @@
+Move the :c:type:`PyGC_Head` structure to the internal C API.
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 0a30fea9e8747..c97cbe8355197 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -6716,7 +6716,6 @@ PyInit__testcapi(void)
     PyModule_AddObject(m, "ULLONG_MAX", PyLong_FromUnsignedLongLong(ULLONG_MAX));
     PyModule_AddObject(m, "PY_SSIZE_T_MAX", PyLong_FromSsize_t(PY_SSIZE_T_MAX));
     PyModule_AddObject(m, "PY_SSIZE_T_MIN", PyLong_FromSsize_t(PY_SSIZE_T_MIN));
-    PyModule_AddObject(m, "SIZEOF_PYGC_HEAD", PyLong_FromSsize_t(sizeof(PyGC_Head)));
     PyModule_AddObject(m, "SIZEOF_TIME_T", PyLong_FromSsize_t(sizeof(time_t)));
     Py_INCREF(&PyInstanceMethod_Type);
     PyModule_AddObject(m, "instancemethod", (PyObject *)&PyInstanceMethod_Type);
diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c
index 394b870e90780..8352f6e2590c5 100644
--- a/Modules/_testinternalcapi.c
+++ b/Modules/_testinternalcapi.c
@@ -10,6 +10,7 @@
 
 #include "Python.h"
 #include "pycore_initconfig.h"   // _Py_GetConfigsAsDict()
+#include "pycore_gc.h"           // PyGC_Head
 
 
 static PyObject *
@@ -52,5 +53,19 @@ static struct PyModuleDef _testcapimodule = {
 PyMODINIT_FUNC
 PyInit__testinternalcapi(void)
 {
-    return PyModule_Create(&_testcapimodule);
+    PyObject *module = PyModule_Create(&_testcapimodule);
+    if (module == NULL) {
+        return NULL;
+    }
+
+    if (PyModule_AddObject(module, "SIZEOF_PYGC_HEAD",
+                           PyLong_FromSsize_t(sizeof(PyGC_Head))) < 0) {
+        goto error;
+    }
+
+    return module;
+
+error:
+    Py_DECREF(module);
+    return NULL;
 }



More information about the Python-checkins mailing list