]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-102304: Consolidate Direct Usage of _Py_RefTotal (gh-102514)
authorEric Snow <ericsnowcurrently@gmail.com>
Wed, 8 Mar 2023 19:03:50 +0000 (12:03 -0700)
committerGitHub <noreply@github.com>
Wed, 8 Mar 2023 19:03:50 +0000 (12:03 -0700)
This simplifies further changes to _Py_RefTotal (e.g. make it atomic or move it to PyInterpreterState).

https://github.com/python/cpython/issues/102304

Include/cpython/object.h
Include/internal/pycore_object.h
Include/object.h
Modules/_testcapimodule.c
Objects/bytesobject.c
Objects/dictobject.c
Objects/object.c
Objects/structseq.c
Objects/tupleobject.c
Objects/unicodeobject.c

index 3f26f2487d70cc848c8b11e71774ffb7b7798f94..7b687d311359c38ce792b1663f884a47d296344e 100644 (file)
@@ -3,6 +3,7 @@
 #endif
 
 PyAPI_FUNC(void) _Py_NewReference(PyObject *op);
+PyAPI_FUNC(void) _Py_NewReferenceNoTotal(PyObject *op);
 
 #ifdef Py_TRACE_REFS
 /* Py_TRACE_REFS is such major surgery that we call external routines. */
index 8796dfe2f6b8cf65eea4c9cd720defff63ebbaab..e15685f174ebcfe8b2eb7923c0c4919a49c2339e 100644 (file)
@@ -37,11 +37,23 @@ PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalRefcountErrorFunc(
 #define _Py_FatalRefcountError(message) \
     _Py_FatalRefcountErrorFunc(__func__, (message))
 
+
+#ifdef Py_REF_DEBUG
+/* The symbol is only exposed in the API for the sake of extensions
+   built against the pre-3.12 stable ABI. */
+PyAPI_DATA(Py_ssize_t) _Py_RefTotal;
+
+extern void _Py_AddRefTotal(Py_ssize_t);
+extern void _Py_IncRefTotal(void);
+extern void _Py_DecRefTotal(void);
+#  define _Py_DEC_REFTOTAL() _Py_RefTotal--
+#endif
+
 // Increment reference count by n
 static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n)
 {
 #ifdef Py_REF_DEBUG
-    _Py_RefTotal += n;
+    _Py_AddRefTotal(n);
 #endif
     op->ob_refcnt += n;
 }
@@ -52,7 +64,7 @@ _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct)
 {
     _Py_DECREF_STAT_INC();
 #ifdef Py_REF_DEBUG
-    _Py_RefTotal--;
+    _Py_DEC_REFTOTAL();
 #endif
     if (--op->ob_refcnt != 0) {
         assert(op->ob_refcnt > 0);
@@ -70,7 +82,7 @@ _Py_DECREF_NO_DEALLOC(PyObject *op)
 {
     _Py_DECREF_STAT_INC();
 #ifdef Py_REF_DEBUG
-    _Py_RefTotal--;
+    _Py_DEC_REFTOTAL();
 #endif
     op->ob_refcnt--;
 #ifdef Py_DEBUG
@@ -80,6 +92,11 @@ _Py_DECREF_NO_DEALLOC(PyObject *op)
 #endif
 }
 
+#ifdef Py_REF_DEBUG
+#  undef _Py_DEC_REFTOTAL
+#endif
+
+
 PyAPI_FUNC(int) _PyType_CheckConsistency(PyTypeObject *type);
 PyAPI_FUNC(int) _PyDict_CheckConsistency(PyObject *mp, int check_content);
 
index 3774f126730005469a7c3dc48bca0fd9a898b33f..844b9c4a51c3e47019b14a2ac4402ff2733242e2 100644 (file)
@@ -490,7 +490,21 @@ you can count such references to the type object.)
 */
 
 #ifdef Py_REF_DEBUG
-PyAPI_DATA(Py_ssize_t) _Py_RefTotal;
+#  if defined(Py_LIMITED_API) && Py_LIMITED_API+0 < 0x030A0000
+extern Py_ssize_t _Py_RefTotal;
+#    define _Py_INC_REFTOTAL() _Py_RefTotal++
+#    define _Py_DEC_REFTOTAL() _Py_RefTotal--
+#  elif defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+extern void _Py_IncRefTotal(void);
+extern void _Py_DecRefTotal(void);
+#    define _Py_INC_REFTOTAL() _Py_IncRefTotal()
+#    define _Py_DEC_REFTOTAL() _Py_DecRefTotal()
+#  elif !defined(Py_LIMITED_API) || Py_LIMITED_API+0 > 0x030C0000
+extern void _Py_IncRefTotal_DO_NOT_USE_THIS(void);
+extern void _Py_DecRefTotal_DO_NOT_USE_THIS(void);
+#    define _Py_INC_REFTOTAL() _Py_IncRefTotal_DO_NOT_USE_THIS()
+#    define _Py_DEC_REFTOTAL() _Py_DecRefTotal_DO_NOT_USE_THIS()
+#  endif
 PyAPI_FUNC(void) _Py_NegativeRefcount(const char *filename, int lineno,
                                       PyObject *op);
 #endif /* Py_REF_DEBUG */
@@ -519,8 +533,8 @@ static inline void Py_INCREF(PyObject *op)
     // Non-limited C API and limited C API for Python 3.9 and older access
     // directly PyObject.ob_refcnt.
 #ifdef Py_REF_DEBUG
-    _Py_RefTotal++;
-#endif
+    _Py_INC_REFTOTAL();
+#endif  // Py_REF_DEBUG
     op->ob_refcnt++;
 #endif
 }
@@ -539,7 +553,7 @@ static inline void Py_DECREF(PyObject *op) {
 static inline void Py_DECREF(const char *filename, int lineno, PyObject *op)
 {
     _Py_DECREF_STAT_INC();
-    _Py_RefTotal--;
+    _Py_DEC_REFTOTAL();
     if (--op->ob_refcnt != 0) {
         if (op->ob_refcnt < 0) {
             _Py_NegativeRefcount(filename, lineno, op);
@@ -564,6 +578,9 @@ static inline void Py_DECREF(PyObject *op)
 #define Py_DECREF(op) Py_DECREF(_PyObject_CAST(op))
 #endif
 
+#undef _Py_INC_REFTOTAL
+#undef _Py_DEC_REFTOTAL
+
 
 /* Safely decref `op` and set `op` to NULL, especially useful in tp_clear
  * and tp_dealloc implementations.
index 10e507d6b481de04f6a3ab83ab642bbf800202b9..ea67017a1ba3b16c7925229c6f20702508a915d8 100644 (file)
@@ -1654,15 +1654,10 @@ slot_tp_del(PyObject *self)
      */
     {
         Py_ssize_t refcnt = Py_REFCNT(self);
-        _Py_NewReference(self);
+        _Py_NewReferenceNoTotal(self);
         Py_SET_REFCNT(self, refcnt);
     }
     assert(!PyType_IS_GC(Py_TYPE(self)) || PyObject_GC_IsTracked(self));
-    /* If Py_REF_DEBUG macro is defined, _Py_NewReference() increased
-       _Py_RefTotal, so we need to undo that. */
-#ifdef Py_REF_DEBUG
-    _Py_RefTotal--;
-#endif
 }
 
 static PyObject *
index 657443f31fa709bcea8b6b5011f1abdfe2a7985e..687a654bdae137cde3c260b138683db692baaa8a 100644 (file)
@@ -3060,21 +3060,20 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize)
         Py_DECREF(v);
         return 0;
     }
-    /* XXX UNREF/NEWREF interface should be more symmetrical */
-#ifdef Py_REF_DEBUG
-    _Py_RefTotal--;
-#endif
 #ifdef Py_TRACE_REFS
     _Py_ForgetReference(v);
 #endif
     *pv = (PyObject *)
         PyObject_Realloc(v, PyBytesObject_SIZE + newsize);
     if (*pv == NULL) {
+#ifdef Py_REF_DEBUG
+        _Py_DecRefTotal();
+#endif
         PyObject_Free(v);
         PyErr_NoMemory();
         return -1;
     }
-    _Py_NewReference(*pv);
+    _Py_NewReferenceNoTotal(*pv);
     sv = (PyBytesObject *) *pv;
     Py_SET_SIZE(sv, newsize);
     sv->ob_sval[newsize] = '\0';
index 75c92172a91778c07c5194ffa88a1fd295ac8feb..a60f275742a5341510787fdb566e891db51dd2f0 100644 (file)
@@ -303,7 +303,7 @@ static inline void
 dictkeys_incref(PyDictKeysObject *dk)
 {
 #ifdef Py_REF_DEBUG
-    _Py_RefTotal++;
+    _Py_IncRefTotal();
 #endif
     dk->dk_refcnt++;
 }
@@ -313,7 +313,7 @@ dictkeys_decref(PyDictKeysObject *dk)
 {
     assert(dk->dk_refcnt > 0);
 #ifdef Py_REF_DEBUG
-    _Py_RefTotal--;
+    _Py_DecRefTotal();
 #endif
     if (--dk->dk_refcnt == 0) {
         free_keys_object(dk);
@@ -633,7 +633,7 @@ new_keys_object(uint8_t log2_size, bool unicode)
         }
     }
 #ifdef Py_REF_DEBUG
-    _Py_RefTotal++;
+    _Py_IncRefTotal();
 #endif
     dk->dk_refcnt = 1;
     dk->dk_log2_size = log2_size;
@@ -821,7 +821,7 @@ clone_combined_dict_keys(PyDictObject *orig)
        we have it now; calling dictkeys_incref would be an error as
        keys->dk_refcnt is already set to 1 (after memcpy). */
 #ifdef Py_REF_DEBUG
-    _Py_RefTotal++;
+    _Py_IncRefTotal();
 #endif
     return keys;
 }
@@ -1520,7 +1520,7 @@ dictresize(PyDictObject *mp, uint8_t log2_newsize, int unicode)
         // We can not use free_keys_object here because key's reference
         // are moved already.
 #ifdef Py_REF_DEBUG
-        _Py_RefTotal--;
+        _Py_DecRefTotal();
 #endif
         if (oldkeys == Py_EMPTY_KEYS) {
             oldkeys->dk_refcnt--;
index 5db2b6af21ef135a1f5518e53ba95836023aff10..38da4d497a96e72311ee46e6d95074fa12a50559 100644 (file)
@@ -56,6 +56,24 @@ _PyObject_CheckConsistency(PyObject *op, int check_content)
 #ifdef Py_REF_DEBUG
 Py_ssize_t _Py_RefTotal;
 
+static inline void
+reftotal_increment(void)
+{
+    _Py_RefTotal++;
+}
+
+static inline void
+reftotal_decrement(void)
+{
+    _Py_RefTotal--;
+}
+
+void
+_Py_AddRefTotal(Py_ssize_t n)
+{
+    _Py_RefTotal += n;
+}
+
 Py_ssize_t
 _Py_GetRefTotal(void)
 {
@@ -121,6 +139,32 @@ _Py_NegativeRefcount(const char *filename, int lineno, PyObject *op)
                            filename, lineno, __func__);
 }
 
+/* This is exposed strictly for use in Py_INCREF(). */
+PyAPI_FUNC(void)
+_Py_IncRefTotal_DO_NOT_USE_THIS(void)
+{
+    reftotal_increment();
+}
+
+/* This is exposed strictly for use in Py_DECREF(). */
+PyAPI_FUNC(void)
+_Py_DecRefTotal_DO_NOT_USE_THIS(void)
+{
+    reftotal_decrement();
+}
+
+void
+_Py_IncRefTotal(void)
+{
+    reftotal_increment();
+}
+
+void
+_Py_DecRefTotal(void)
+{
+    reftotal_decrement();
+}
+
 #endif /* Py_REF_DEBUG */
 
 void
@@ -138,12 +182,18 @@ Py_DecRef(PyObject *o)
 void
 _Py_IncRef(PyObject *o)
 {
+#ifdef Py_REF_DEBUG
+    reftotal_increment();
+#endif
     Py_INCREF(o);
 }
 
 void
 _Py_DecRef(PyObject *o)
 {
+#ifdef Py_REF_DEBUG
+    reftotal_decrement();
+#endif
     Py_DECREF(o);
 }
 
@@ -238,17 +288,12 @@ PyObject_CallFinalizerFromDealloc(PyObject *self)
     /* tp_finalize resurrected it!  Make it look like the original Py_DECREF
      * never happened. */
     Py_ssize_t refcnt = Py_REFCNT(self);
-    _Py_NewReference(self);
+    _Py_NewReferenceNoTotal(self);
     Py_SET_REFCNT(self, refcnt);
 
     _PyObject_ASSERT(self,
                      (!_PyType_IS_GC(Py_TYPE(self))
                       || _PyObject_GC_IS_TRACKED(self)));
-    /* If Py_REF_DEBUG macro is defined, _Py_NewReference() increased
-       _Py_RefTotal, so we need to undo that. */
-#ifdef Py_REF_DEBUG
-    _Py_RefTotal--;
-#endif
     return -1;
 }
 
@@ -2010,21 +2055,33 @@ _PyTypes_FiniTypes(PyInterpreterState *interp)
 }
 
 
-void
-_Py_NewReference(PyObject *op)
+static inline void
+new_reference(PyObject *op)
 {
     if (_PyRuntime.tracemalloc.config.tracing) {
         _PyTraceMalloc_NewReference(op);
     }
-#ifdef Py_REF_DEBUG
-    _Py_RefTotal++;
-#endif
     Py_SET_REFCNT(op, 1);
 #ifdef Py_TRACE_REFS
     _Py_AddToAllObjects(op, 1);
 #endif
 }
 
+void
+_Py_NewReference(PyObject *op)
+{
+#ifdef Py_REF_DEBUG
+    reftotal_increment();
+#endif
+    new_reference(op);
+}
+
+void
+_Py_NewReferenceNoTotal(PyObject *op)
+{
+    new_reference(op);
+}
+
 
 #ifdef Py_TRACE_REFS
 void
index 100ccfef0a23c41613740f86937b57bdc332e45d..c20962ecd82563c1db3315531d26cda74dafdbf3 100644 (file)
@@ -592,7 +592,7 @@ _PyStructSequence_FiniType(PyTypeObject *type)
     // Don't use Py_DECREF(): static type must not be deallocated
     Py_SET_REFCNT(type, 0);
 #ifdef Py_REF_DEBUG
-    _Py_RefTotal--;
+    _Py_DecRefTotal();
 #endif
 
     // Make sure that _PyStructSequence_InitType() will initialize
index 6ee93ab5adc2816c522aab8138caa48a18637c87..59c0251639d3dda03c6fafda5fbac4ac93ce6722 100644 (file)
@@ -930,10 +930,6 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
         return *pv == NULL ? -1 : 0;
     }
 
-    /* XXX UNREF/NEWREF interface should be more symmetrical */
-#ifdef Py_REF_DEBUG
-    _Py_RefTotal--;
-#endif
     if (_PyObject_GC_IS_TRACKED(v)) {
         _PyObject_GC_UNTRACK(v);
     }
@@ -947,10 +943,13 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
     sv = PyObject_GC_Resize(PyTupleObject, v, newsize);
     if (sv == NULL) {
         *pv = NULL;
+#ifdef Py_REF_DEBUG
+        _Py_DecRefTotal();
+#endif
         PyObject_GC_Del(v);
         return -1;
     }
-    _Py_NewReference((PyObject *) sv);
+    _Py_NewReferenceNoTotal((PyObject *) sv);
     /* Zero out items added by growing */
     if (newsize > oldsize)
         memset(&sv->ob_item[oldsize], 0,
index 1ba30421c66dba45652519b67300ad4d1e987574..2d50f9c340f2f36eb500ce3f8cd572cafaa94ebe 100644 (file)
@@ -947,21 +947,18 @@ resize_compact(PyObject *unicode, Py_ssize_t length)
         _PyUnicode_UTF8(unicode) = NULL;
         _PyUnicode_UTF8_LENGTH(unicode) = 0;
     }
-#ifdef Py_REF_DEBUG
-    _Py_RefTotal--;
-#endif
 #ifdef Py_TRACE_REFS
     _Py_ForgetReference(unicode);
 #endif
 
     new_unicode = (PyObject *)PyObject_Realloc(unicode, new_size);
     if (new_unicode == NULL) {
-        _Py_NewReference(unicode);
+        _Py_NewReferenceNoTotal(unicode);
         PyErr_NoMemory();
         return NULL;
     }
     unicode = new_unicode;
-    _Py_NewReference(unicode);
+    _Py_NewReferenceNoTotal(unicode);
 
     _PyUnicode_LENGTH(unicode) = length;
 #ifdef Py_DEBUG