Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 35.2k
gh-133164: Add PyUnstable_Object_IsUniqueReferencedTemporary C API#133170
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.
Changes from all commits
32b6cd0479f1854a53a98fdc438ab6508df07ba54099e32650e0e67407f3b23bba589ff23de336efe2fbf30ccf4File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -89,6 +89,10 @@ If you encounter :exc:`NameError`\s or pickling errors coming out of | ||
| :mod:`multiprocessing` or :mod:`concurrent.futures`, see the | ||
| :ref:`forkserver restrictions <multiprocessing-programming-forkserver>`. | ||
| The interpreter avoids some reference count modifications internally when | ||
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👌 | ||
| it's safe to do so. This can lead to different values returned from | ||
| :func:`sys.getrefcount` and :c:func:`Py_REFCNT` compared to previous versions | ||
| of Python. See :ref:`below <whatsnew314-refcount>` for details. | ||
| New features | ||
| ============ | ||
| @@ -2215,6 +2219,11 @@ New features | ||
| take a C integer and produce a Python :class:`bool` object. (Contributed by | ||
| Pablo Galindo in :issue:`45325`.) | ||
| * Add :c:func:`PyUnstable_Object_IsUniqueReferencedTemporary` to determine if an object | ||
| is a unique temporary object on the interpreter's operand stack. This can | ||
| be used in some cases as a replacement for checking if :c:func:`Py_REFCNT` | ||
| is ``1`` for Python objects passed as arguments to C API functions. | ||
| Limited C API changes | ||
| --------------------- | ||
| @@ -2249,6 +2258,17 @@ Porting to Python 3.14 | ||
| a :exc:`UnicodeError` object. | ||
| (Contributed by Bénédikt Tran in :gh:`127691`.) | ||
| .. _whatsnew314-refcount: | ||
| * The interpreter internally avoids some reference count modifications when | ||
| loading objects onto the operands stack by :term:`borrowing <borrowed reference>` | ||
| references when possible. This can lead to smaller reference count values | ||
| compared to previous Python versions. C API extensions that checked | ||
| :c:func:`Py_REFCNT` of ``1`` to determine if an function argument is not | ||
| referenced by any other code should instead use | ||
| :c:func:`PyUnstable_Object_IsUniqueReferencedTemporary` as a safer replacement. | ||
| * Private functions promoted to public C APIs: | ||
| * ``_PyBytes_Join()``: :c:func:`PyBytes_Join`. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| import enum | ||
| import sys | ||
| import textwrap | ||
| import unittest | ||
| from test import support | ||
| @@ -223,5 +224,17 @@ def __del__(self): | ||
| obj = MyObj() | ||
| _testinternalcapi.incref_decref_delayed(obj) | ||
| def test_is_unique_temporary(self): | ||
| self.assertTrue(_testcapi.pyobject_is_unique_temporary(object())) | ||
| obj = object() | ||
| self.assertFalse(_testcapi.pyobject_is_unique_temporary(obj)) | ||
| def func(x): | ||
| # This relies on the LOAD_FAST_BORROW optimization (gh-130704) | ||
| self.assertEqual(sys.getrefcount(x), 1) | ||
colesbury marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| self.assertFalse(_testcapi.pyobject_is_unique_temporary(x)) | ||
| func(object()) | ||
| if __name__ == "__main__": | ||
| unittest.main() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| Add :c:func:`PyUnstable_Object_IsUniqueReferencedTemporary` function for | ||
| determining if an object exists as a unique temporary variable on the | ||
| interpreter's stack. This is a replacement for some cases where checking | ||
| that :c:func:`Py_REFCNT` is one is no longer sufficient to determine if it's | ||
| safe to modify a Python object in-place with no visible side effects. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -15,6 +15,7 @@ | ||
| #include "pycore_hamt.h" // _PyHamtItems_Type | ||
| #include "pycore_initconfig.h" // _PyStatus_OK() | ||
| #include "pycore_instruction_sequence.h" // _PyInstructionSequence_Type | ||
| #include "pycore_interpframe.h" // _PyFrame_Stackbase() | ||
| #include "pycore_interpolation.h" // _PyInterpolation_Type | ||
| #include "pycore_list.h" // _PyList_DebugMallocStats() | ||
| #include "pycore_long.h" // _PyLong_GetZero() | ||
| @@ -2621,6 +2622,29 @@ PyUnstable_Object_EnableDeferredRefcount(PyObject *op) | ||
| #endif | ||
| } | ||
| int | ||
| PyUnstable_Object_IsUniqueReferencedTemporary(PyObject *op) | ||
| { | ||
| if (!_PyObject_IsUniquelyReferenced(op)) { | ||
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this just demonstrates that We need to check that the following are true:
I think ContributorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's discuss the name for | ||
| return 0; | ||
| } | ||
| _PyInterpreterFrame *frame = _PyEval_GetFrame(); | ||
| if (frame == NULL) { | ||
| return 0; | ||
| } | ||
| _PyStackRef *base = _PyFrame_Stackbase(frame); | ||
| _PyStackRef *stackpointer = frame->stackpointer; | ||
| while (stackpointer > base) { | ||
| stackpointer--; | ||
| if (op == PyStackRef_AsPyObjectBorrow(*stackpointer)) { | ||
| return PyStackRef_IsHeapSafe(*stackpointer); | ||
| } | ||
| } | ||
| return 0; | ||
| } | ||
| int | ||
| PyUnstable_TryIncRef(PyObject *op) | ||
| { | ||
Uh oh!
There was an error while loading. Please reload this page.