Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 33.9k
gh-105387: Limited C API implements Py_INCREF() as func#105388
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Conversation
vstinner commented Jun 6, 2023 • edited by bedevere-bot
Loading Uh oh!
There was an error while loading. Please reload this page.
edited by bedevere-bot
Uh oh!
There was an error while loading. Please reload this page.
vstinner commented Jun 6, 2023
In the limited C API version 3.12, Py_INCREF() and Py_DECREF() functions are now implemented as opaque function calls to hide implementation details.
cbde052 to bdd5865Comparevstinner commented Jun 9, 2023
The PR is now ready for a review. I rebased the PR on the main branch. I fixed the compatibility with Python 3.9 and older in main (commit 7ba0fd9). |
vstinner commented Jun 9, 2023
In Python 3.12, Py_INCREF() and Py_DECREF() implementation become more complicated than There are C compiler issues with the current implementation: issue #105059. |
vstinner commented Jun 9, 2023
This change was written to be backported to Python 3.12: see the issue for the discussion on the version number. |
zooba commented Jun 13, 2023
What happens if I build with 3.12 but set Py_LIMITED_API to 3.11? or to just This means that, in practice, it's only safe to set If you can't set |
vstinner commented Jun 13, 2023
Limited C API: Python 3.11 (inline)You can look at xxlimited ( Preprocessor output ( staticinline __attribute__((always_inline)) voidPy_INCREF(PyObject*op){uint32_tcur_refcnt=op->ob_refcnt_split[0]; uint32_tnew_refcnt=cur_refcnt+1; if (new_refcnt==0){return} op->ob_refcnt_split[0] =new_refcnt; ((void)0)}Extract of Xxo_getattro() x86-64 assembly code: => with the limited C API version 3.11, Py_INCREF() is inlined code (refcnt+1 and test for immutable refcnt) at the ABI level. Limited C API: Python 3.12 (function call)I modified xxlimited ( Preprocessor output ( staticinline __attribute__((always_inline)) voidPy_INCREF(PyObject*op){_Py_IncRef(op)}Extract of Xxo_getattro() x86-64 assembly code: => with the limited C API version 3.12, Py_INCREF() becomes a function call to _Py_IncRef() at the ABI level. Py_LIMITED_API=1 (inline)I modified Preprocessor output ( staticinline __attribute__((always_inline)) voidPy_INCREF(PyObject*op){uint32_tcur_refcnt=op->ob_refcnt_split[0]; uint32_tnew_refcnt=cur_refcnt+1; if (new_refcnt==0){return} op->ob_refcnt_split[0] =new_refcnt; ((void)0)}=> With
The trick is to convert It's a common pattern in the limited C API: look for |
vstinner commented Jun 13, 2023
If you build a C extension with Python 3.12 and target the limited C API 3.11, you get Python 3.12 Py_INCREF() inlined code (refcnt+1, test for immutable refcnt) which is backward compatible: the binary built with new Python 3.12 header files can be run on old Python 3.11 and older, see PEP 683: Stable ABI. If you consider that it's wrong, please revisit the whole PEP 683, but I don't see how this question is related to my change. Your question is about the code path unaffected by this PR.
You can set Py_LIMITED_API to an earlier version and the built binary works on old Python versions (it remains ABI compatible). Would you mind to elaborate why do you think that it does not work? |
vstinner commented Jun 13, 2023 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
If I understood correctly @zooba rationale, he wants to build a C extension with (the limited C API of) the new Python 3.(N+1), run it with an old Python 3.N and have the exact same behavioras if the C extension was built with an old Python 3.N. The current implementation of the limited C API DOES NOT provide such ABI warranty. There are many corner cases like the function being discussed here: Py_INCREF(). There are around 315 functions in Python 3.12 which are either implemented as a macro or a static inline function and so is likely to access structure members or relying on another implementation details: https://pythoncapi.readthedocs.io/stats.html#functions-defined-as-macros-and-static-inline-functions The intent of moving the limited C API towards "opaque function calls" is to build a C extension with Python 3.N and have exactly the Python 3.x behavior on Python 3.x since the executed code is no longer hardcoded in the extension binary, but instead we call call in the Python executable (libpython). For example, if this change lands in Python 3.12 beta3, a C extension is built with Python 3.12 beta3, but Python 3.12 beta4 changes again the Py_INCREF() implementation: the C extension will execute the exact new beta4 implementation, rather than using the copy of old beta3 implementation. Without opaque function calls, the promise of a "stable ABI" is weak. This change moves the limited C API / stable ABI one step towards a better (more stable) stable ABI. @zooba rationale is that the implementation of the limited C API and the stable ABI is broken is should be abandoned. I disagree here. IMO not only the current half-baken implementation is useful to many people, but also it is fixable in an increment way. Moreover, my long term goal is to bend the whole (regular) Python C API towards to limited C API / stable ABI. |
miss-islington commented Jun 14, 2023
Thanks @vstinner for the PR 🌮🎉.. I'm working now to backport this PR to: 3.12. |
…GH-105388) In the limited C API version 3.12, Py_INCREF() and Py_DECREF() functions are now implemented as opaque function calls to hide implementation details. (cherry picked from commit b542972) Co-authored-by: Victor Stinner <vstinner@python.org>
bedevere-bot commented Jun 14, 2023
GH-105763 is a backport of this pull request to the 3.12 branch. |
…5388) (#105763) gh-105387: Limited C API implements Py_INCREF() as func (GH-105388) In the limited C API version 3.12, Py_INCREF() and Py_DECREF() functions are now implemented as opaque function calls to hide implementation details. (cherry picked from commit b542972) Co-authored-by: Victor Stinner <vstinner@python.org>
In the limited C API version 3.12 and newer, Py_INCREF() and Py_DECREF() functions are now implemented as opaque function calls in the stable ABI to hide implementation details.