diff --git a/Include/object.h b/Include/object.h index 1c7d7f407fe23e..bdc07d9e8d7f83 100644 --- a/Include/object.h +++ b/Include/object.h @@ -327,7 +327,15 @@ 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 @@ -335,7 +343,7 @@ static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) { if (_Py_IsImmortal(ob)) { return; } -#if !defined(Py_NOGIL) +#ifndef Py_NOGIL ob->ob_refcnt = refcnt; #else if (_Py_IsOwnedByCurrentThread(ob)) { @@ -352,7 +360,8 @@ static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) { ob->ob_ref_local = 0; ob->ob_ref_shared = _Py_REF_SHARED(refcnt, _Py_REF_MERGED); } -#endif +#endif // Py_NOGIL +#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)) diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 88bc0fd4025a17..85a63c44b49431 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -907,6 +907,7 @@ def test_windows_feature_macros(self): "_Py_IncRef", "_Py_NoneStruct", "_Py_NotImplementedStruct", + "_Py_SetRefcnt", "_Py_SwappedOp", "_Py_TrueStruct", "_Py_VaBuildValue_SizeT", diff --git a/Misc/NEWS.d/next/C API/2023-10-30-18-13-01.gh-issue-111506.EUdO22.rst b/Misc/NEWS.d/next/C API/2023-10-30-18-13-01.gh-issue-111506.EUdO22.rst new file mode 100644 index 00000000000000..f4d71fd008241a --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-10-30-18-13-01.gh-issue-111506.EUdO22.rst @@ -0,0 +1,2 @@ +In the limited C API version 3.13, :c:func:`Py_SET_REFCNT` function is now +implemented as an opaque function call. Patch by Victor Stinner. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 0601de20fe0f46..b55bb599d71dcc 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2480,3 +2480,6 @@ added = '3.13' [function.PyUnicode_AsUTF8] added = '3.13' +[function._Py_SetRefcnt] + added = '3.13' + abi_only = true diff --git a/Objects/object.c b/Objects/object.c index 35c7e7bf33b135..1cc3f914646709 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2931,3 +2931,11 @@ int Py_IsFalse(PyObject *x) { return Py_Is(x, Py_False); } + + +// Py_SET_REFCNT() implementation for stable ABI +void +_Py_SetRefcnt(PyObject *ob, Py_ssize_t refcnt) +{ + Py_SET_REFCNT(ob, refcnt); +} diff --git a/PC/python3dll.c b/PC/python3dll.c index 7f5d97ae4dc83f..fa6bf1f0282b0a 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -19,6 +19,7 @@ EXPORT_FUNC(_Py_Dealloc) EXPORT_FUNC(_Py_DecRef) EXPORT_FUNC(_Py_IncRef) EXPORT_FUNC(_Py_NegativeRefcount) +EXPORT_FUNC(_Py_SetRefcnt) EXPORT_FUNC(_Py_VaBuildValue_SizeT) EXPORT_FUNC(_PyArg_Parse_SizeT) EXPORT_FUNC(_PyArg_ParseTuple_SizeT)