https://github.com/python/cpython/commit/891c1e36f4e08da107443772a4eb50c72a83836d
commit: 891c1e36f4e08da107443772a4eb50c72a83836d
branch: main
author: Victor Stinner <vstin...@python.org>
committer: vstinner <vstin...@python.org>
date: 2024-05-31T16:49:26+02:00
summary:

gh-119853: Add Include/refcount.h file  (#119854)

files:
A Include/refcount.h
M Include/Python.h
M Include/object.h

diff --git a/Include/Python.h b/Include/Python.h
index e05901b9e52b5a..502c5ec5aeaa3c 100644
--- a/Include/Python.h
+++ b/Include/Python.h
@@ -61,6 +61,7 @@
 #include "pystats.h"
 #include "pyatomic.h"
 #include "object.h"
+#include "refcount.h"
 #include "objimpl.h"
 #include "typeslots.h"
 #include "pyhash.h"
diff --git a/Include/object.h b/Include/object.h
index 9132784628a501..c8c63b9b2b1450 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -59,59 +59,6 @@ whose size is determined when the object is allocated.
 /* PyObject_HEAD defines the initial segment of every PyObject. */
 #define PyObject_HEAD                   PyObject ob_base;
 
-/*
-Immortalization:
-
-The following indicates the immortalization strategy depending on the amount
-of available bits in the reference count field. All strategies are backwards
-compatible but the specific reference count value or immortalization check
-might change depending on the specializations for the underlying system.
-
-Proper deallocation of immortal instances requires distinguishing between
-statically allocated immortal instances vs those promoted by the runtime to be
-immortal. The latter should be the only instances that require
-cleanup during runtime finalization.
-*/
-
-#if SIZEOF_VOID_P > 4
-/*
-In 64+ bit systems, an object will be marked as immortal by setting all of the
-lower 32 bits of the reference count field, which is equal to: 0xFFFFFFFF
-
-Using the lower 32 bits makes the value backwards compatible by allowing
-C-Extensions without the updated checks in Py_INCREF and Py_DECREF to safely
-increase and decrease the objects reference count. The object would lose its
-immortality, but the execution would still be correct.
-
-Reference count increases will use saturated arithmetic, taking advantage of
-having all the lower 32 bits set, which will avoid the reference count to go
-beyond the refcount limit. Immortality checks for reference count decreases 
will
-be done by checking the bit sign flag in the lower 32 bits.
-*/
-#define _Py_IMMORTAL_REFCNT _Py_CAST(Py_ssize_t, UINT_MAX)
-
-#else
-/*
-In 32 bit systems, an object will be marked as immortal by setting all of the
-lower 30 bits of the reference count field, which is equal to: 0x3FFFFFFF
-
-Using the lower 30 bits makes the value backwards compatible by allowing
-C-Extensions without the updated checks in Py_INCREF and Py_DECREF to safely
-increase and decrease the objects reference count. The object would lose its
-immortality, but the execution would still be correct.
-
-Reference count increases and decreases will first go through an immortality
-check by comparing the reference count field to the immortality reference 
count.
-*/
-#define _Py_IMMORTAL_REFCNT _Py_CAST(Py_ssize_t, UINT_MAX >> 2)
-#endif
-
-// Py_GIL_DISABLED builds indicate immortal objects using `ob_ref_local`, 
which is
-// always 32-bits.
-#ifdef Py_GIL_DISABLED
-#define _Py_IMMORTAL_REFCNT_LOCAL UINT32_MAX
-#endif
-
 // Kept for backward compatibility. It was needed by Py_TRACE_REFS build.
 #define _PyObject_EXTRA_INIT
 
@@ -190,20 +137,6 @@ struct _object {
 // fields have been merged.
 #define _Py_UNOWNED_TID             0
 
-// The shared reference count uses the two least-significant bits to store
-// flags. The remaining bits are used to store the reference count.
-#define _Py_REF_SHARED_SHIFT        2
-#define _Py_REF_SHARED_FLAG_MASK    0x3
-
-// The shared flags are initialized to zero.
-#define _Py_REF_SHARED_INIT         0x0
-#define _Py_REF_MAYBE_WEAKREF       0x1
-#define _Py_REF_QUEUED              0x2
-#define _Py_REF_MERGED              0x3
-
-// Create a shared field from a refcnt and desired flags
-#define _Py_REF_SHARED(refcnt, flags) (((refcnt) << _Py_REF_SHARED_SHIFT) + 
(flags))
-
 // NOTE: In non-free-threaded builds, `struct _PyMutex` is defined in
 // pycore_lock.h. See pycore_lock.h for more details.
 struct _PyMutex { uint8_t v; };
@@ -311,24 +244,6 @@ _Py_IsOwnedByCurrentThread(PyObject *ob)
 }
 #endif
 
-static inline Py_ssize_t Py_REFCNT(PyObject *ob) {
-#if !defined(Py_GIL_DISABLED)
-    return ob->ob_refcnt;
-#else
-    uint32_t local = _Py_atomic_load_uint32_relaxed(&ob->ob_ref_local);
-    if (local == _Py_IMMORTAL_REFCNT_LOCAL) {
-        return _Py_IMMORTAL_REFCNT;
-    }
-    Py_ssize_t shared = _Py_atomic_load_ssize_relaxed(&ob->ob_ref_shared);
-    return _Py_STATIC_CAST(Py_ssize_t, local) +
-           Py_ARITHMETIC_RIGHT_SHIFT(Py_ssize_t, shared, _Py_REF_SHARED_SHIFT);
-#endif
-}
-#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
-#  define Py_REFCNT(ob) Py_REFCNT(_PyObject_CAST(ob))
-#endif
-
-
 // bpo-39573: The Py_SET_TYPE() function must be used to set an object type.
 static inline PyTypeObject* Py_TYPE(PyObject *ob) {
     return ob->ob_type;
@@ -350,19 +265,6 @@ static inline Py_ssize_t Py_SIZE(PyObject *ob) {
 #  define Py_SIZE(ob) Py_SIZE(_PyObject_CAST(ob))
 #endif
 
-static inline Py_ALWAYS_INLINE int _Py_IsImmortal(PyObject *op)
-{
-#if defined(Py_GIL_DISABLED)
-    return (_Py_atomic_load_uint32_relaxed(&op->ob_ref_local) ==
-            _Py_IMMORTAL_REFCNT_LOCAL);
-#elif SIZEOF_VOID_P > 4
-    return (_Py_CAST(PY_INT32_T, op->ob_refcnt) < 0);
-#else
-    return (op->ob_refcnt == _Py_IMMORTAL_REFCNT);
-#endif
-}
-#define _Py_IsImmortal(op) _Py_IsImmortal(_PyObject_CAST(op))
-
 static inline int Py_IS_TYPE(PyObject *ob, PyTypeObject *type) {
     return Py_TYPE(ob) == type;
 }
@@ -371,55 +273,6 @@ static inline int Py_IS_TYPE(PyObject *ob, PyTypeObject 
*type) {
 #endif
 
 
-// Py_SET_REFCNT() implementation for stable ABI
-PyAPI_FUNC(void) _Py_SetRefcnt(PyObject *ob, Py_ssize_t refcnt);
-
-static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) {
-#if defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030d0000
-    // Stable ABI implements Py_SET_REFCNT() as a function call
-    // on limited C API version 3.13 and newer.
-    _Py_SetRefcnt(ob, refcnt);
-#else
-    // This immortal check is for code that is unaware of immortal objects.
-    // The runtime tracks these objects and we should avoid as much
-    // as possible having extensions inadvertently change the refcnt
-    // of an immortalized object.
-    if (_Py_IsImmortal(ob)) {
-        return;
-    }
-
-#ifndef Py_GIL_DISABLED
-    ob->ob_refcnt = refcnt;
-#else
-    if (_Py_IsOwnedByCurrentThread(ob)) {
-        if ((size_t)refcnt > (size_t)UINT32_MAX) {
-            // On overflow, make the object immortal
-            ob->ob_tid = _Py_UNOWNED_TID;
-            ob->ob_ref_local = _Py_IMMORTAL_REFCNT_LOCAL;
-            ob->ob_ref_shared = 0;
-        }
-        else {
-            // Set local refcount to desired refcount and shared refcount
-            // to zero, but preserve the shared refcount flags.
-            ob->ob_ref_local = _Py_STATIC_CAST(uint32_t, refcnt);
-            ob->ob_ref_shared &= _Py_REF_SHARED_FLAG_MASK;
-        }
-    }
-    else {
-        // Set local refcount to zero and shared refcount to desired refcount.
-        // Mark the object as merged.
-        ob->ob_tid = _Py_UNOWNED_TID;
-        ob->ob_ref_local = 0;
-        ob->ob_ref_shared = _Py_REF_SHARED(refcnt, _Py_REF_MERGED);
-    }
-#endif  // Py_GIL_DISABLED
-#endif  // Py_LIMITED_API+0 < 0x030d0000
-}
-#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
-#  define Py_SET_REFCNT(ob, refcnt) Py_SET_REFCNT(_PyObject_CAST(ob), (refcnt))
-#endif
-
-
 static inline void Py_SET_TYPE(PyObject *ob, PyTypeObject *type) {
     ob->ob_type = type;
 }
@@ -740,341 +593,6 @@ given type object has a specified feature.
 #define Py_TPFLAGS_HAVE_VERSION_TAG   (1UL << 18)
 
 
-/*
-The macros Py_INCREF(op) and Py_DECREF(op) are used to increment or decrement
-reference counts.  Py_DECREF calls the object's deallocator function when
-the refcount falls to 0; for
-objects that don't contain references to other objects or heap memory
-this can be the standard function free().  Both macros can be used
-wherever a void expression is allowed.  The argument must not be a
-NULL pointer.  If it may be NULL, use Py_XINCREF/Py_XDECREF instead.
-The macro _Py_NewReference(op) initialize reference counts to 1, and
-in special builds (Py_REF_DEBUG, Py_TRACE_REFS) performs additional
-bookkeeping appropriate to the special build.
-
-We assume that the reference count field can never overflow; this can
-be proven when the size of the field is the same as the pointer size, so
-we ignore the possibility.  Provided a C int is at least 32 bits (which
-is implicitly assumed in many parts of this code), that's enough for
-about 2**31 references to an object.
-
-XXX The following became out of date in Python 2.2, but I'm not sure
-XXX what the full truth is now.  Certainly, heap-allocated type objects
-XXX can and should be deallocated.
-Type objects should never be deallocated; the type pointer in an object
-is not considered to be a reference to the type object, to save
-complications in the deallocation function.  (This is actually a
-decision that's up to the implementer of each new type so if you want,
-you can count such references to the type object.)
-*/
-
-#if defined(Py_REF_DEBUG) && !defined(Py_LIMITED_API)
-PyAPI_FUNC(void) _Py_NegativeRefcount(const char *filename, int lineno,
-                                      PyObject *op);
-PyAPI_FUNC(void) _Py_INCREF_IncRefTotal(void);
-PyAPI_FUNC(void) _Py_DECREF_DecRefTotal(void);
-#endif  // Py_REF_DEBUG && !Py_LIMITED_API
-
-PyAPI_FUNC(void) _Py_Dealloc(PyObject *);
-
-/*
-These are provided as conveniences to Python runtime embedders, so that
-they can have object code that is not dependent on Python compilation flags.
-*/
-PyAPI_FUNC(void) Py_IncRef(PyObject *);
-PyAPI_FUNC(void) Py_DecRef(PyObject *);
-
-// Similar to Py_IncRef() and Py_DecRef() but the argument must be non-NULL.
-// Private functions used by Py_INCREF() and Py_DECREF().
-PyAPI_FUNC(void) _Py_IncRef(PyObject *);
-PyAPI_FUNC(void) _Py_DecRef(PyObject *);
-
-static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op)
-{
-#if defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || 
defined(Py_REF_DEBUG))
-    // Stable ABI implements Py_INCREF() as a function call on limited C API
-    // version 3.12 and newer, and on Python built in debug mode. _Py_IncRef()
-    // was added to Python 3.10.0a7, use Py_IncRef() on older Python versions.
-    // Py_IncRef() accepts NULL whereas _Py_IncRef() doesn't.
-#  if Py_LIMITED_API+0 >= 0x030a00A7
-    _Py_IncRef(op);
-#  else
-    Py_IncRef(op);
-#  endif
-#else
-    // Non-limited C API and limited C API for Python 3.9 and older access
-    // directly PyObject.ob_refcnt.
-#if defined(Py_GIL_DISABLED)
-    uint32_t local = _Py_atomic_load_uint32_relaxed(&op->ob_ref_local);
-    uint32_t new_local = local + 1;
-    if (new_local == 0) {
-        // local is equal to _Py_IMMORTAL_REFCNT: do nothing
-        return;
-    }
-    if (_Py_IsOwnedByCurrentThread(op)) {
-        _Py_atomic_store_uint32_relaxed(&op->ob_ref_local, new_local);
-    }
-    else {
-        _Py_atomic_add_ssize(&op->ob_ref_shared, (1 << _Py_REF_SHARED_SHIFT));
-    }
-#elif SIZEOF_VOID_P > 4
-    // Portable saturated add, branching on the carry flag and set low bits
-    PY_UINT32_T cur_refcnt = op->ob_refcnt_split[PY_BIG_ENDIAN];
-    PY_UINT32_T new_refcnt = cur_refcnt + 1;
-    if (new_refcnt == 0) {
-        // cur_refcnt is equal to _Py_IMMORTAL_REFCNT: the object is immortal,
-        // do nothing
-        return;
-    }
-    op->ob_refcnt_split[PY_BIG_ENDIAN] = new_refcnt;
-#else
-    // Explicitly check immortality against the immortal value
-    if (_Py_IsImmortal(op)) {
-        return;
-    }
-    op->ob_refcnt++;
-#endif
-    _Py_INCREF_STAT_INC();
-#ifdef Py_REF_DEBUG
-    _Py_INCREF_IncRefTotal();
-#endif
-#endif
-}
-#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
-#  define Py_INCREF(op) Py_INCREF(_PyObject_CAST(op))
-#endif
-
-
-#if !defined(Py_LIMITED_API) && defined(Py_GIL_DISABLED)
-// Implements Py_DECREF on objects not owned by the current thread.
-PyAPI_FUNC(void) _Py_DecRefShared(PyObject *);
-PyAPI_FUNC(void) _Py_DecRefSharedDebug(PyObject *, const char *, int);
-
-// Called from Py_DECREF by the owning thread when the local refcount reaches
-// zero. The call will deallocate the object if the shared refcount is also
-// zero. Otherwise, the thread gives up ownership and merges the reference
-// count fields.
-PyAPI_FUNC(void) _Py_MergeZeroLocalRefcount(PyObject *);
-#endif
-
-#if defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || 
defined(Py_REF_DEBUG))
-// Stable ABI implements Py_DECREF() as a function call on limited C API
-// version 3.12 and newer, and on Python built in debug mode. _Py_DecRef() was
-// added to Python 3.10.0a7, use Py_DecRef() on older Python versions.
-// Py_DecRef() accepts NULL whereas _Py_IncRef() doesn't.
-static inline void Py_DECREF(PyObject *op) {
-#  if Py_LIMITED_API+0 >= 0x030a00A7
-    _Py_DecRef(op);
-#  else
-    Py_DecRef(op);
-#  endif
-}
-#define Py_DECREF(op) Py_DECREF(_PyObject_CAST(op))
-
-#elif defined(Py_GIL_DISABLED) && defined(Py_REF_DEBUG)
-static inline void Py_DECREF(const char *filename, int lineno, PyObject *op)
-{
-    uint32_t local = _Py_atomic_load_uint32_relaxed(&op->ob_ref_local);
-    if (local == _Py_IMMORTAL_REFCNT_LOCAL) {
-        return;
-    }
-    _Py_DECREF_STAT_INC();
-    _Py_DECREF_DecRefTotal();
-    if (_Py_IsOwnedByCurrentThread(op)) {
-        if (local == 0) {
-            _Py_NegativeRefcount(filename, lineno, op);
-        }
-        local--;
-        _Py_atomic_store_uint32_relaxed(&op->ob_ref_local, local);
-        if (local == 0) {
-            _Py_MergeZeroLocalRefcount(op);
-        }
-    }
-    else {
-        _Py_DecRefSharedDebug(op, filename, lineno);
-    }
-}
-#define Py_DECREF(op) Py_DECREF(__FILE__, __LINE__, _PyObject_CAST(op))
-
-#elif defined(Py_GIL_DISABLED)
-static inline void Py_DECREF(PyObject *op)
-{
-    uint32_t local = _Py_atomic_load_uint32_relaxed(&op->ob_ref_local);
-    if (local == _Py_IMMORTAL_REFCNT_LOCAL) {
-        return;
-    }
-    _Py_DECREF_STAT_INC();
-    if (_Py_IsOwnedByCurrentThread(op)) {
-        local--;
-        _Py_atomic_store_uint32_relaxed(&op->ob_ref_local, local);
-        if (local == 0) {
-            _Py_MergeZeroLocalRefcount(op);
-        }
-    }
-    else {
-        _Py_DecRefShared(op);
-    }
-}
-#define Py_DECREF(op) Py_DECREF(_PyObject_CAST(op))
-
-#elif defined(Py_REF_DEBUG)
-static inline void Py_DECREF(const char *filename, int lineno, PyObject *op)
-{
-    if (op->ob_refcnt <= 0) {
-        _Py_NegativeRefcount(filename, lineno, op);
-    }
-    if (_Py_IsImmortal(op)) {
-        return;
-    }
-    _Py_DECREF_STAT_INC();
-    _Py_DECREF_DecRefTotal();
-    if (--op->ob_refcnt == 0) {
-        _Py_Dealloc(op);
-    }
-}
-#define Py_DECREF(op) Py_DECREF(__FILE__, __LINE__, _PyObject_CAST(op))
-
-#else
-static inline Py_ALWAYS_INLINE void Py_DECREF(PyObject *op)
-{
-    // Non-limited C API and limited C API for Python 3.9 and older access
-    // directly PyObject.ob_refcnt.
-    if (_Py_IsImmortal(op)) {
-        return;
-    }
-    _Py_DECREF_STAT_INC();
-    if (--op->ob_refcnt == 0) {
-        _Py_Dealloc(op);
-    }
-}
-#define Py_DECREF(op) Py_DECREF(_PyObject_CAST(op))
-#endif
-
-
-/* Safely decref `op` and set `op` to NULL, especially useful in tp_clear
- * and tp_dealloc implementations.
- *
- * Note that "the obvious" code can be deadly:
- *
- *     Py_XDECREF(op);
- *     op = NULL;
- *
- * Typically, `op` is something like self->containee, and `self` is done
- * using its `containee` member.  In the code sequence above, suppose
- * `containee` is non-NULL with a refcount of 1.  Its refcount falls to
- * 0 on the first line, which can trigger an arbitrary amount of code,
- * possibly including finalizers (like __del__ methods or weakref callbacks)
- * coded in Python, which in turn can release the GIL and allow other threads
- * to run, etc.  Such code may even invoke methods of `self` again, or cause
- * cyclic gc to trigger, but-- oops! --self->containee still points to the
- * object being torn down, and it may be in an insane state while being torn
- * down.  This has in fact been a rich historic source of miserable (rare &
- * hard-to-diagnose) segfaulting (and other) bugs.
- *
- * The safe way is:
- *
- *      Py_CLEAR(op);
- *
- * That arranges to set `op` to NULL _before_ decref'ing, so that any code
- * triggered as a side-effect of `op` getting torn down no longer believes
- * `op` points to a valid object.
- *
- * There are cases where it's safe to use the naive code, but they're brittle.
- * For example, if `op` points to a Python integer, you know that destroying
- * one of those can't cause problems -- but in part that relies on that
- * Python integers aren't currently weakly referencable.  Best practice is
- * to use Py_CLEAR() even if you can't think of a reason for why you need to.
- *
- * gh-98724: Use a temporary variable to only evaluate the macro argument once,
- * to avoid the duplication of side effects if the argument has side effects.
- *
- * gh-99701: If the PyObject* type is used with casting arguments to PyObject*,
- * the code can be miscompiled with strict aliasing because of type punning.
- * With strict aliasing, a compiler considers that two pointers of different
- * types cannot read or write the same memory which enables optimization
- * opportunities.
- *
- * If available, use _Py_TYPEOF() to use the 'op' type for temporary variables,
- * and so avoid type punning. Otherwise, use memcpy() which causes type erasure
- * and so prevents the compiler to reuse an old cached 'op' value after
- * Py_CLEAR().
- */
-#ifdef _Py_TYPEOF
-#define Py_CLEAR(op) \
-    do { \
-        _Py_TYPEOF(op)* _tmp_op_ptr = &(op); \
-        _Py_TYPEOF(op) _tmp_old_op = (*_tmp_op_ptr); \
-        if (_tmp_old_op != NULL) { \
-            *_tmp_op_ptr = _Py_NULL; \
-            Py_DECREF(_tmp_old_op); \
-        } \
-    } while (0)
-#else
-#define Py_CLEAR(op) \
-    do { \
-        PyObject **_tmp_op_ptr = _Py_CAST(PyObject**, &(op)); \
-        PyObject *_tmp_old_op = (*_tmp_op_ptr); \
-        if (_tmp_old_op != NULL) { \
-            PyObject *_null_ptr = _Py_NULL; \
-            memcpy(_tmp_op_ptr, &_null_ptr, sizeof(PyObject*)); \
-            Py_DECREF(_tmp_old_op); \
-        } \
-    } while (0)
-#endif
-
-
-/* Function to use in case the object pointer can be NULL: */
-static inline void Py_XINCREF(PyObject *op)
-{
-    if (op != _Py_NULL) {
-        Py_INCREF(op);
-    }
-}
-#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
-#  define Py_XINCREF(op) Py_XINCREF(_PyObject_CAST(op))
-#endif
-
-static inline void Py_XDECREF(PyObject *op)
-{
-    if (op != _Py_NULL) {
-        Py_DECREF(op);
-    }
-}
-#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
-#  define Py_XDECREF(op) Py_XDECREF(_PyObject_CAST(op))
-#endif
-
-// Create a new strong reference to an object:
-// increment the reference count of the object and return the object.
-PyAPI_FUNC(PyObject*) Py_NewRef(PyObject *obj);
-
-// Similar to Py_NewRef(), but the object can be NULL.
-PyAPI_FUNC(PyObject*) Py_XNewRef(PyObject *obj);
-
-static inline PyObject* _Py_NewRef(PyObject *obj)
-{
-    Py_INCREF(obj);
-    return obj;
-}
-
-static inline PyObject* _Py_XNewRef(PyObject *obj)
-{
-    Py_XINCREF(obj);
-    return obj;
-}
-
-// Py_NewRef() and Py_XNewRef() are exported as functions for the stable ABI.
-// Names overridden with macros by static inline functions for best
-// performances.
-#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
-#  define Py_NewRef(obj) _Py_NewRef(_PyObject_CAST(obj))
-#  define Py_XNewRef(obj) _Py_XNewRef(_PyObject_CAST(obj))
-#else
-#  define Py_NewRef(obj) _Py_NewRef(obj)
-#  define Py_XNewRef(obj) _Py_XNewRef(obj)
-#endif
-
-
 #define Py_CONSTANT_NONE 0
 #define Py_CONSTANT_FALSE 1
 #define Py_CONSTANT_TRUE 2
diff --git a/Include/refcount.h b/Include/refcount.h
new file mode 100644
index 00000000000000..a0bd2087fb1b57
--- /dev/null
+++ b/Include/refcount.h
@@ -0,0 +1,500 @@
+#ifndef Py_REFCOUNT_H
+#define Py_REFCOUNT_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+Immortalization:
+
+The following indicates the immortalization strategy depending on the amount
+of available bits in the reference count field. All strategies are backwards
+compatible but the specific reference count value or immortalization check
+might change depending on the specializations for the underlying system.
+
+Proper deallocation of immortal instances requires distinguishing between
+statically allocated immortal instances vs those promoted by the runtime to be
+immortal. The latter should be the only instances that require
+cleanup during runtime finalization.
+*/
+
+#if SIZEOF_VOID_P > 4
+/*
+In 64+ bit systems, an object will be marked as immortal by setting all of the
+lower 32 bits of the reference count field, which is equal to: 0xFFFFFFFF
+
+Using the lower 32 bits makes the value backwards compatible by allowing
+C-Extensions without the updated checks in Py_INCREF and Py_DECREF to safely
+increase and decrease the objects reference count. The object would lose its
+immortality, but the execution would still be correct.
+
+Reference count increases will use saturated arithmetic, taking advantage of
+having all the lower 32 bits set, which will avoid the reference count to go
+beyond the refcount limit. Immortality checks for reference count decreases 
will
+be done by checking the bit sign flag in the lower 32 bits.
+*/
+#define _Py_IMMORTAL_REFCNT _Py_CAST(Py_ssize_t, UINT_MAX)
+
+#else
+/*
+In 32 bit systems, an object will be marked as immortal by setting all of the
+lower 30 bits of the reference count field, which is equal to: 0x3FFFFFFF
+
+Using the lower 30 bits makes the value backwards compatible by allowing
+C-Extensions without the updated checks in Py_INCREF and Py_DECREF to safely
+increase and decrease the objects reference count. The object would lose its
+immortality, but the execution would still be correct.
+
+Reference count increases and decreases will first go through an immortality
+check by comparing the reference count field to the immortality reference 
count.
+*/
+#define _Py_IMMORTAL_REFCNT _Py_CAST(Py_ssize_t, UINT_MAX >> 2)
+#endif
+
+// Py_GIL_DISABLED builds indicate immortal objects using `ob_ref_local`, 
which is
+// always 32-bits.
+#ifdef Py_GIL_DISABLED
+#define _Py_IMMORTAL_REFCNT_LOCAL UINT32_MAX
+#endif
+
+
+#ifdef Py_GIL_DISABLED
+   // The shared reference count uses the two least-significant bits to store
+   // flags. The remaining bits are used to store the reference count.
+#  define _Py_REF_SHARED_SHIFT        2
+#  define _Py_REF_SHARED_FLAG_MASK    0x3
+
+   // The shared flags are initialized to zero.
+#  define _Py_REF_SHARED_INIT         0x0
+#  define _Py_REF_MAYBE_WEAKREF       0x1
+#  define _Py_REF_QUEUED              0x2
+#  define _Py_REF_MERGED              0x3
+
+   // Create a shared field from a refcnt and desired flags
+#  define _Py_REF_SHARED(refcnt, flags) \
+              (((refcnt) << _Py_REF_SHARED_SHIFT) + (flags))
+#endif  // Py_GIL_DISABLED
+
+
+static inline Py_ssize_t Py_REFCNT(PyObject *ob) {
+#if !defined(Py_GIL_DISABLED)
+    return ob->ob_refcnt;
+#else
+    uint32_t local = _Py_atomic_load_uint32_relaxed(&ob->ob_ref_local);
+    if (local == _Py_IMMORTAL_REFCNT_LOCAL) {
+        return _Py_IMMORTAL_REFCNT;
+    }
+    Py_ssize_t shared = _Py_atomic_load_ssize_relaxed(&ob->ob_ref_shared);
+    return _Py_STATIC_CAST(Py_ssize_t, local) +
+           Py_ARITHMETIC_RIGHT_SHIFT(Py_ssize_t, shared, _Py_REF_SHARED_SHIFT);
+#endif
+}
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
+#  define Py_REFCNT(ob) Py_REFCNT(_PyObject_CAST(ob))
+#endif
+
+
+static inline Py_ALWAYS_INLINE int _Py_IsImmortal(PyObject *op)
+{
+#if defined(Py_GIL_DISABLED)
+    return (_Py_atomic_load_uint32_relaxed(&op->ob_ref_local) ==
+            _Py_IMMORTAL_REFCNT_LOCAL);
+#elif SIZEOF_VOID_P > 4
+    return (_Py_CAST(PY_INT32_T, op->ob_refcnt) < 0);
+#else
+    return (op->ob_refcnt == _Py_IMMORTAL_REFCNT);
+#endif
+}
+#define _Py_IsImmortal(op) _Py_IsImmortal(_PyObject_CAST(op))
+
+
+// Py_SET_REFCNT() implementation for stable ABI
+PyAPI_FUNC(void) _Py_SetRefcnt(PyObject *ob, Py_ssize_t refcnt);
+
+static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) {
+#if defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030d0000
+    // Stable ABI implements Py_SET_REFCNT() as a function call
+    // on limited C API version 3.13 and newer.
+    _Py_SetRefcnt(ob, refcnt);
+#else
+    // This immortal check is for code that is unaware of immortal objects.
+    // The runtime tracks these objects and we should avoid as much
+    // as possible having extensions inadvertently change the refcnt
+    // of an immortalized object.
+    if (_Py_IsImmortal(ob)) {
+        return;
+    }
+
+#ifndef Py_GIL_DISABLED
+    ob->ob_refcnt = refcnt;
+#else
+    if (_Py_IsOwnedByCurrentThread(ob)) {
+        if ((size_t)refcnt > (size_t)UINT32_MAX) {
+            // On overflow, make the object immortal
+            ob->ob_tid = _Py_UNOWNED_TID;
+            ob->ob_ref_local = _Py_IMMORTAL_REFCNT_LOCAL;
+            ob->ob_ref_shared = 0;
+        }
+        else {
+            // Set local refcount to desired refcount and shared refcount
+            // to zero, but preserve the shared refcount flags.
+            ob->ob_ref_local = _Py_STATIC_CAST(uint32_t, refcnt);
+            ob->ob_ref_shared &= _Py_REF_SHARED_FLAG_MASK;
+        }
+    }
+    else {
+        // Set local refcount to zero and shared refcount to desired refcount.
+        // Mark the object as merged.
+        ob->ob_tid = _Py_UNOWNED_TID;
+        ob->ob_ref_local = 0;
+        ob->ob_ref_shared = _Py_REF_SHARED(refcnt, _Py_REF_MERGED);
+    }
+#endif  // Py_GIL_DISABLED
+#endif  // Py_LIMITED_API+0 < 0x030d0000
+}
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
+#  define Py_SET_REFCNT(ob, refcnt) Py_SET_REFCNT(_PyObject_CAST(ob), (refcnt))
+#endif
+
+
+/*
+The macros Py_INCREF(op) and Py_DECREF(op) are used to increment or decrement
+reference counts.  Py_DECREF calls the object's deallocator function when
+the refcount falls to 0; for
+objects that don't contain references to other objects or heap memory
+this can be the standard function free().  Both macros can be used
+wherever a void expression is allowed.  The argument must not be a
+NULL pointer.  If it may be NULL, use Py_XINCREF/Py_XDECREF instead.
+The macro _Py_NewReference(op) initialize reference counts to 1, and
+in special builds (Py_REF_DEBUG, Py_TRACE_REFS) performs additional
+bookkeeping appropriate to the special build.
+
+We assume that the reference count field can never overflow; this can
+be proven when the size of the field is the same as the pointer size, so
+we ignore the possibility.  Provided a C int is at least 32 bits (which
+is implicitly assumed in many parts of this code), that's enough for
+about 2**31 references to an object.
+
+XXX The following became out of date in Python 2.2, but I'm not sure
+XXX what the full truth is now.  Certainly, heap-allocated type objects
+XXX can and should be deallocated.
+Type objects should never be deallocated; the type pointer in an object
+is not considered to be a reference to the type object, to save
+complications in the deallocation function.  (This is actually a
+decision that's up to the implementer of each new type so if you want,
+you can count such references to the type object.)
+*/
+
+#if defined(Py_REF_DEBUG) && !defined(Py_LIMITED_API)
+PyAPI_FUNC(void) _Py_NegativeRefcount(const char *filename, int lineno,
+                                      PyObject *op);
+PyAPI_FUNC(void) _Py_INCREF_IncRefTotal(void);
+PyAPI_FUNC(void) _Py_DECREF_DecRefTotal(void);
+#endif  // Py_REF_DEBUG && !Py_LIMITED_API
+
+PyAPI_FUNC(void) _Py_Dealloc(PyObject *);
+
+
+/*
+These are provided as conveniences to Python runtime embedders, so that
+they can have object code that is not dependent on Python compilation flags.
+*/
+PyAPI_FUNC(void) Py_IncRef(PyObject *);
+PyAPI_FUNC(void) Py_DecRef(PyObject *);
+
+// Similar to Py_IncRef() and Py_DecRef() but the argument must be non-NULL.
+// Private functions used by Py_INCREF() and Py_DECREF().
+PyAPI_FUNC(void) _Py_IncRef(PyObject *);
+PyAPI_FUNC(void) _Py_DecRef(PyObject *);
+
+static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op)
+{
+#if defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || 
defined(Py_REF_DEBUG))
+    // Stable ABI implements Py_INCREF() as a function call on limited C API
+    // version 3.12 and newer, and on Python built in debug mode. _Py_IncRef()
+    // was added to Python 3.10.0a7, use Py_IncRef() on older Python versions.
+    // Py_IncRef() accepts NULL whereas _Py_IncRef() doesn't.
+#  if Py_LIMITED_API+0 >= 0x030a00A7
+    _Py_IncRef(op);
+#  else
+    Py_IncRef(op);
+#  endif
+#else
+    // Non-limited C API and limited C API for Python 3.9 and older access
+    // directly PyObject.ob_refcnt.
+#if defined(Py_GIL_DISABLED)
+    uint32_t local = _Py_atomic_load_uint32_relaxed(&op->ob_ref_local);
+    uint32_t new_local = local + 1;
+    if (new_local == 0) {
+        // local is equal to _Py_IMMORTAL_REFCNT: do nothing
+        return;
+    }
+    if (_Py_IsOwnedByCurrentThread(op)) {
+        _Py_atomic_store_uint32_relaxed(&op->ob_ref_local, new_local);
+    }
+    else {
+        _Py_atomic_add_ssize(&op->ob_ref_shared, (1 << _Py_REF_SHARED_SHIFT));
+    }
+#elif SIZEOF_VOID_P > 4
+    // Portable saturated add, branching on the carry flag and set low bits
+    PY_UINT32_T cur_refcnt = op->ob_refcnt_split[PY_BIG_ENDIAN];
+    PY_UINT32_T new_refcnt = cur_refcnt + 1;
+    if (new_refcnt == 0) {
+        // cur_refcnt is equal to _Py_IMMORTAL_REFCNT: the object is immortal,
+        // do nothing
+        return;
+    }
+    op->ob_refcnt_split[PY_BIG_ENDIAN] = new_refcnt;
+#else
+    // Explicitly check immortality against the immortal value
+    if (_Py_IsImmortal(op)) {
+        return;
+    }
+    op->ob_refcnt++;
+#endif
+    _Py_INCREF_STAT_INC();
+#ifdef Py_REF_DEBUG
+    _Py_INCREF_IncRefTotal();
+#endif
+#endif
+}
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
+#  define Py_INCREF(op) Py_INCREF(_PyObject_CAST(op))
+#endif
+
+
+#if !defined(Py_LIMITED_API) && defined(Py_GIL_DISABLED)
+// Implements Py_DECREF on objects not owned by the current thread.
+PyAPI_FUNC(void) _Py_DecRefShared(PyObject *);
+PyAPI_FUNC(void) _Py_DecRefSharedDebug(PyObject *, const char *, int);
+
+// Called from Py_DECREF by the owning thread when the local refcount reaches
+// zero. The call will deallocate the object if the shared refcount is also
+// zero. Otherwise, the thread gives up ownership and merges the reference
+// count fields.
+PyAPI_FUNC(void) _Py_MergeZeroLocalRefcount(PyObject *);
+#endif
+
+#if defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || 
defined(Py_REF_DEBUG))
+// Stable ABI implements Py_DECREF() as a function call on limited C API
+// version 3.12 and newer, and on Python built in debug mode. _Py_DecRef() was
+// added to Python 3.10.0a7, use Py_DecRef() on older Python versions.
+// Py_DecRef() accepts NULL whereas _Py_IncRef() doesn't.
+static inline void Py_DECREF(PyObject *op) {
+#  if Py_LIMITED_API+0 >= 0x030a00A7
+    _Py_DecRef(op);
+#  else
+    Py_DecRef(op);
+#  endif
+}
+#define Py_DECREF(op) Py_DECREF(_PyObject_CAST(op))
+
+#elif defined(Py_GIL_DISABLED) && defined(Py_REF_DEBUG)
+static inline void Py_DECREF(const char *filename, int lineno, PyObject *op)
+{
+    uint32_t local = _Py_atomic_load_uint32_relaxed(&op->ob_ref_local);
+    if (local == _Py_IMMORTAL_REFCNT_LOCAL) {
+        return;
+    }
+    _Py_DECREF_STAT_INC();
+    _Py_DECREF_DecRefTotal();
+    if (_Py_IsOwnedByCurrentThread(op)) {
+        if (local == 0) {
+            _Py_NegativeRefcount(filename, lineno, op);
+        }
+        local--;
+        _Py_atomic_store_uint32_relaxed(&op->ob_ref_local, local);
+        if (local == 0) {
+            _Py_MergeZeroLocalRefcount(op);
+        }
+    }
+    else {
+        _Py_DecRefSharedDebug(op, filename, lineno);
+    }
+}
+#define Py_DECREF(op) Py_DECREF(__FILE__, __LINE__, _PyObject_CAST(op))
+
+#elif defined(Py_GIL_DISABLED)
+static inline void Py_DECREF(PyObject *op)
+{
+    uint32_t local = _Py_atomic_load_uint32_relaxed(&op->ob_ref_local);
+    if (local == _Py_IMMORTAL_REFCNT_LOCAL) {
+        return;
+    }
+    _Py_DECREF_STAT_INC();
+    if (_Py_IsOwnedByCurrentThread(op)) {
+        local--;
+        _Py_atomic_store_uint32_relaxed(&op->ob_ref_local, local);
+        if (local == 0) {
+            _Py_MergeZeroLocalRefcount(op);
+        }
+    }
+    else {
+        _Py_DecRefShared(op);
+    }
+}
+#define Py_DECREF(op) Py_DECREF(_PyObject_CAST(op))
+
+#elif defined(Py_REF_DEBUG)
+static inline void Py_DECREF(const char *filename, int lineno, PyObject *op)
+{
+    if (op->ob_refcnt <= 0) {
+        _Py_NegativeRefcount(filename, lineno, op);
+    }
+    if (_Py_IsImmortal(op)) {
+        return;
+    }
+    _Py_DECREF_STAT_INC();
+    _Py_DECREF_DecRefTotal();
+    if (--op->ob_refcnt == 0) {
+        _Py_Dealloc(op);
+    }
+}
+#define Py_DECREF(op) Py_DECREF(__FILE__, __LINE__, _PyObject_CAST(op))
+
+#else
+static inline Py_ALWAYS_INLINE void Py_DECREF(PyObject *op)
+{
+    // Non-limited C API and limited C API for Python 3.9 and older access
+    // directly PyObject.ob_refcnt.
+    if (_Py_IsImmortal(op)) {
+        return;
+    }
+    _Py_DECREF_STAT_INC();
+    if (--op->ob_refcnt == 0) {
+        _Py_Dealloc(op);
+    }
+}
+#define Py_DECREF(op) Py_DECREF(_PyObject_CAST(op))
+#endif
+
+
+/* Safely decref `op` and set `op` to NULL, especially useful in tp_clear
+ * and tp_dealloc implementations.
+ *
+ * Note that "the obvious" code can be deadly:
+ *
+ *     Py_XDECREF(op);
+ *     op = NULL;
+ *
+ * Typically, `op` is something like self->containee, and `self` is done
+ * using its `containee` member.  In the code sequence above, suppose
+ * `containee` is non-NULL with a refcount of 1.  Its refcount falls to
+ * 0 on the first line, which can trigger an arbitrary amount of code,
+ * possibly including finalizers (like __del__ methods or weakref callbacks)
+ * coded in Python, which in turn can release the GIL and allow other threads
+ * to run, etc.  Such code may even invoke methods of `self` again, or cause
+ * cyclic gc to trigger, but-- oops! --self->containee still points to the
+ * object being torn down, and it may be in an insane state while being torn
+ * down.  This has in fact been a rich historic source of miserable (rare &
+ * hard-to-diagnose) segfaulting (and other) bugs.
+ *
+ * The safe way is:
+ *
+ *      Py_CLEAR(op);
+ *
+ * That arranges to set `op` to NULL _before_ decref'ing, so that any code
+ * triggered as a side-effect of `op` getting torn down no longer believes
+ * `op` points to a valid object.
+ *
+ * There are cases where it's safe to use the naive code, but they're brittle.
+ * For example, if `op` points to a Python integer, you know that destroying
+ * one of those can't cause problems -- but in part that relies on that
+ * Python integers aren't currently weakly referencable.  Best practice is
+ * to use Py_CLEAR() even if you can't think of a reason for why you need to.
+ *
+ * gh-98724: Use a temporary variable to only evaluate the macro argument once,
+ * to avoid the duplication of side effects if the argument has side effects.
+ *
+ * gh-99701: If the PyObject* type is used with casting arguments to PyObject*,
+ * the code can be miscompiled with strict aliasing because of type punning.
+ * With strict aliasing, a compiler considers that two pointers of different
+ * types cannot read or write the same memory which enables optimization
+ * opportunities.
+ *
+ * If available, use _Py_TYPEOF() to use the 'op' type for temporary variables,
+ * and so avoid type punning. Otherwise, use memcpy() which causes type erasure
+ * and so prevents the compiler to reuse an old cached 'op' value after
+ * Py_CLEAR().
+ */
+#ifdef _Py_TYPEOF
+#define Py_CLEAR(op) \
+    do { \
+        _Py_TYPEOF(op)* _tmp_op_ptr = &(op); \
+        _Py_TYPEOF(op) _tmp_old_op = (*_tmp_op_ptr); \
+        if (_tmp_old_op != NULL) { \
+            *_tmp_op_ptr = _Py_NULL; \
+            Py_DECREF(_tmp_old_op); \
+        } \
+    } while (0)
+#else
+#define Py_CLEAR(op) \
+    do { \
+        PyObject **_tmp_op_ptr = _Py_CAST(PyObject**, &(op)); \
+        PyObject *_tmp_old_op = (*_tmp_op_ptr); \
+        if (_tmp_old_op != NULL) { \
+            PyObject *_null_ptr = _Py_NULL; \
+            memcpy(_tmp_op_ptr, &_null_ptr, sizeof(PyObject*)); \
+            Py_DECREF(_tmp_old_op); \
+        } \
+    } while (0)
+#endif
+
+
+/* Function to use in case the object pointer can be NULL: */
+static inline void Py_XINCREF(PyObject *op)
+{
+    if (op != _Py_NULL) {
+        Py_INCREF(op);
+    }
+}
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
+#  define Py_XINCREF(op) Py_XINCREF(_PyObject_CAST(op))
+#endif
+
+static inline void Py_XDECREF(PyObject *op)
+{
+    if (op != _Py_NULL) {
+        Py_DECREF(op);
+    }
+}
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
+#  define Py_XDECREF(op) Py_XDECREF(_PyObject_CAST(op))
+#endif
+
+// Create a new strong reference to an object:
+// increment the reference count of the object and return the object.
+PyAPI_FUNC(PyObject*) Py_NewRef(PyObject *obj);
+
+// Similar to Py_NewRef(), but the object can be NULL.
+PyAPI_FUNC(PyObject*) Py_XNewRef(PyObject *obj);
+
+static inline PyObject* _Py_NewRef(PyObject *obj)
+{
+    Py_INCREF(obj);
+    return obj;
+}
+
+static inline PyObject* _Py_XNewRef(PyObject *obj)
+{
+    Py_XINCREF(obj);
+    return obj;
+}
+
+// Py_NewRef() and Py_XNewRef() are exported as functions for the stable ABI.
+// Names overridden with macros by static inline functions for best
+// performances.
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
+#  define Py_NewRef(obj) _Py_NewRef(_PyObject_CAST(obj))
+#  define Py_XNewRef(obj) _Py_XNewRef(_PyObject_CAST(obj))
+#else
+#  define Py_NewRef(obj) _Py_NewRef(obj)
+#  define Py_XNewRef(obj) _Py_XNewRef(obj)
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif   // !Py_REFCOUNT_H

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to