| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -70,6 +70,11 @@ Python 3.15 | |||
| 70 | 70 | ||
| 71 | 71 | On PyPy, always returns ``-1``. | |
| 72 | 72 | ||
| 73 | + .. c:function:: int PyUnstable_SetImmortal(PyObject *op) | ||
| 74 | + | ||
| 75 | + See `PyUnstable_SetImmortal() documentation <https://docs.python.org/dev/c-api/object.html#c.PyUnstable_SetImmortal>`__. | ||
| 76 | + | ||
| 77 | + Availability: Python 3.13 and newer, not available on PyPy. | ||
| 73 | 78 | ||
| 74 | 79 | Python 3.14 | |
| 75 | 80 | ----------- | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,6 +1,10 @@ | |||
| 1 | 1 | Changelog | |
| 2 | 2 | ========= | |
| 3 | 3 | ||
| 4 | + * 2026-02-12: Add functions: | ||
| 5 | + | ||
| 6 | + * ``PyUnstable_SetImmortal()`` | ||
| 7 | + | ||
| 4 | 8 | * 2025-10-14: Add functions: | |
| 5 | 9 | ||
| 6 | 10 | * ``PyTuple_FromArray()`` | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2659,6 +2659,37 @@ PyUnstable_Unicode_GET_CACHED_HASH(PyObject *op) | |||
| 2659 | 2659 | } | |
| 2660 | 2660 | #endif | |
| 2661 | 2661 | ||
| 2662 | + #if 0x030D0000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030F00A7 && !defined(PYPY_VERSION) | ||
| 2663 | + // Immortal objects were implemented in Python 3.12, however there is no easy API | ||
| 2664 | + // to make objects immortal until 3.14 which has _Py_SetImmortal(). Since | ||
| 2665 | + // immortal objects are primarily needed for free-threading, this API is implemented | ||
| 2666 | + // for 3.14 using _Py_SetImmortal() and uses private macros on 3.13. | ||
| 2667 | + static inline int | ||
| 2668 | + PyUnstable_SetImmortal(PyObject *op) | ||
| 2669 | + { | ||
| 2670 | + assert(op != NULL); | ||
| 2671 | + if (!PyUnstable_Object_IsUniquelyReferenced(op) || PyUnicode_Check(op)) { | ||
| 2672 | + return 0; | ||
| 2673 | + } | ||
| 2674 | + #if 0x030E0000 <= PY_VERSION_HEX | ||
| 2675 | + PyAPI_FUNC(void) _Py_SetImmortal(PyObject *op); | ||
| 2676 | + _Py_SetImmortal(op); | ||
| 2677 | + #else | ||
| 2678 | + // Python 3.13 doesn't export _Py_SetImmortal() function | ||
| 2679 | + if (PyObject_GC_IsTracked(op)) { | ||
| 2680 | + PyObject_GC_UnTrack(op); | ||
| 2681 | + } | ||
| 2682 | + #ifdef Py_GIL_DISABLED | ||
| 2683 | + op->ob_tid = _Py_UNOWNED_TID; | ||
| 2684 | + op->ob_ref_local = _Py_IMMORTAL_REFCNT_LOCAL; | ||
| 2685 | + op->ob_ref_shared = 0; | ||
| 2686 | + #else | ||
| 2687 | + op->ob_refcnt = _Py_IMMORTAL_REFCNT; | ||
| 2688 | + #endif | ||
| 2689 | + #endif | ||
| 2690 | + return 1; | ||
| 2691 | + } | ||
| 2692 | + #endif | ||
| 2662 | 2693 | ||
| 2663 | 2694 | #ifdef __cplusplus | |
| 2664 | 2695 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2489,6 +2489,39 @@ test_try_incref(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) | |||
| 2489 | 2489 | Py_RETURN_NONE; | |
| 2490 | 2490 | } | |
| 2491 | 2491 | ||
| 2492 | + #if 0x030D0000 <= PY_VERSION_HEX && !defined(PYPY_VERSION) | ||
| 2493 | + static PyObject * | ||
| 2494 | + test_set_immortal(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) | ||
| 2495 | + { | ||
| 2496 | + PyObject object; | ||
| 2497 | + memset(&object, 0, sizeof(PyObject)); | ||
| 2498 | + #ifdef Py_GIL_DISABLED | ||
| 2499 | + object.ob_tid = _Py_ThreadId(); | ||
| 2500 | + object.ob_gc_bits = 0; | ||
| 2501 | + object.ob_ref_local = 1; | ||
| 2502 | + object.ob_ref_shared = 0; | ||
| 2503 | + #else | ||
| 2504 | + object.ob_refcnt = 1; | ||
| 2505 | + #endif | ||
| 2506 | + object.ob_type = &PyBaseObject_Type; | ||
| 2507 | + | ||
| 2508 | + int rc = PyUnstable_SetImmortal(&object); | ||
| 2509 | + assert(rc == 1); | ||
| 2510 | + Py_DECREF(&object); // should not dealloc | ||
| 2511 | + | ||
| 2512 | + // Check already immortal object | ||
| 2513 | + rc = PyUnstable_SetImmortal(&object); | ||
| 2514 | + assert(rc == 0); | ||
| 2515 | + | ||
| 2516 | + // Check unicode objects | ||
| 2517 | + PyObject *unicode = PyUnicode_FromString("test"); | ||
| 2518 | + rc = PyUnstable_SetImmortal(unicode); | ||
| 2519 | + assert(rc == 0); | ||
| 2520 | + Py_DECREF(unicode); | ||
| 2521 | + Py_RETURN_NONE; | ||
| 2522 | + } | ||
| 2523 | + #endif | ||
| 2524 | + | ||
| 2492 | 2525 | ||
| 2493 | 2526 | static struct PyMethodDef methods[] = { | |
| 2494 | 2527 | {"test_object", test_object, METH_NOARGS, _Py_NULL}, | |
@@ -2546,6 +2579,9 @@ static struct PyMethodDef methods[] = { | |||
| 2546 | 2579 | {"test_byteswriter", test_byteswriter, METH_NOARGS, _Py_NULL}, | |
| 2547 | 2580 | {"test_tuple", test_tuple, METH_NOARGS, _Py_NULL}, | |
| 2548 | 2581 | {"test_try_incref", test_try_incref, METH_NOARGS, _Py_NULL}, | |
| 2582 | + #if 0x030D0000 <= PY_VERSION_HEX && !defined(PYPY_VERSION) | ||
| 2583 | + {"test_set_immortal", test_set_immortal, METH_NOARGS, _Py_NULL}, | ||
| 2584 | + #endif | ||
| 2549 | 2585 | {_Py_NULL, _Py_NULL, 0, _Py_NULL} | |
| 2550 | 2586 | }; | |
| 2551 | 2587 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments