diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 7c4b56d1dd6..19dc71a345b 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -881,6 +881,7 @@ func,Py_Main,3.2,, func,Py_MakePendingCalls,3.2,, func,Py_NewInterpreter,3.2,, func,Py_NewRef,3.10,, +func,Py_REFCNT,3.14,, func,Py_ReprEnter,3.2,, func,Py_ReprLeave,3.2,, func,Py_SetProgramName,3.2,, diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 04f1a195bca..5acb9bfe18b 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -650,9 +650,10 @@ New Features Porting to Python 3.14 ---------------------- -* In the limited C API 3.14 and newer, :c:func:`Py_TYPE` is now implemented as - an opaque function call to hide implementation details. - (Contributed by Victor Stinner in :gh:`120600`.) +* In the limited C API 3.14 and newer, :c:func:`Py_TYPE` and + :c:func:`Py_REFCNT` are now implemented as an opaque function call to hide + implementation details. + (Contributed by Victor Stinner in :gh:`120600` and :gh:`124127`.) Deprecated diff --git a/Include/refcount.h b/Include/refcount.h index 1d736b194dc..9a4e15065ec 100644 --- a/Include/refcount.h +++ b/Include/refcount.h @@ -77,21 +77,29 @@ check by comparing the reference count field to the immortality reference count. #endif // Py_GIL_DISABLED -static inline Py_ssize_t Py_REFCNT(PyObject *ob) { -#if !defined(Py_GIL_DISABLED) - return ob->ob_refcnt; +// Py_REFCNT() implementation for the stable ABI +PyAPI_FUNC(Py_ssize_t) Py_REFCNT(PyObject *ob); + +#if defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030e0000 + // Stable ABI implements Py_REFCNT() as a function call + // on limited C API version 3.14 and newer. #else - uint32_t local = _Py_atomic_load_uint32_relaxed(&ob->ob_ref_local); - if (local == _Py_IMMORTAL_REFCNT_LOCAL) { - return _Py_IMMORTAL_REFCNT; + 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 } - 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)) + #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 + # define Py_REFCNT(ob) _Py_REFCNT(_PyObject_CAST(ob)) + #endif #endif diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 4e509e30bee..d16ad7ef5d4 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -899,6 +899,7 @@ SYMBOL_NAMES = ( "Py_MakePendingCalls", "Py_NewInterpreter", "Py_NewRef", + "Py_REFCNT", "Py_ReprEnter", "Py_ReprLeave", "Py_SetPath", diff --git a/Misc/NEWS.d/next/C_API/2024-09-16-16-21-39.gh-issue-124127.LB8DBU.rst b/Misc/NEWS.d/next/C_API/2024-09-16-16-21-39.gh-issue-124127.LB8DBU.rst new file mode 100644 index 00000000000..883f173f8fb --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2024-09-16-16-21-39.gh-issue-124127.LB8DBU.rst @@ -0,0 +1,3 @@ +In the limited C API 3.14 and newer, :c:func:`Py_REFCNT` is now implemented +as an opaque function call to hide implementation details. Patch by Victor +Stinner. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index d8a9d1f3335..fe0a5e44f8f 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2508,6 +2508,8 @@ [function.Py_TYPE] added = '3.14' +[function.Py_REFCNT] + added = '3.14' [function.PyIter_NextItem] added = '3.14' [function.PyLong_FromInt32] diff --git a/Objects/object.c b/Objects/object.c index bc63b8120a5..8a819dd336e 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -3039,7 +3039,17 @@ Py_GetConstantBorrowed(unsigned int constant_id) // Py_TYPE() implementation for the stable ABI #undef Py_TYPE -PyTypeObject* Py_TYPE(PyObject *ob) +PyTypeObject* +Py_TYPE(PyObject *ob) { return _Py_TYPE(ob); } + + +// Py_REFCNT() implementation for the stable ABI +#undef Py_REFCNT +Py_ssize_t +Py_REFCNT(PyObject *ob) +{ + return _Py_REFCNT(ob); +} diff --git a/PC/python3dll.c b/PC/python3dll.c index 7bd04cb483b..6b8208ab90b 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -81,6 +81,7 @@ EXPORT_FUNC(Py_Main) EXPORT_FUNC(Py_MakePendingCalls) EXPORT_FUNC(Py_NewInterpreter) EXPORT_FUNC(Py_NewRef) +EXPORT_FUNC(Py_REFCNT) EXPORT_FUNC(Py_ReprEnter) EXPORT_FUNC(Py_ReprLeave) EXPORT_FUNC(Py_SetPath)