Skip to content

Commit f103804

Browse files
Drop Py_IMMORTAL_CONST_REFCOUNTS and make immortal objects internal.
1 parent e6fc84f commit f103804

File tree

6 files changed

+54
-164
lines changed

6 files changed

+54
-164
lines changed

Doc/c-api/refcounting.rst

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -119,47 +119,3 @@ The following functions or macros are only for use within the interpreter core:
119119
:c:func:`_Py_Dealloc`, :c:func:`_Py_ForgetReference`, :c:func:`_Py_NewReference`,
120120
as well as the global variable :c:data:`_Py_RefTotal`.
121121
122-
.. _immortal-objects:
123-
124-
Immortal Objects
125-
================
126-
127-
"Immortal" objects are those that are expected to never be deallocated
128-
by the runtime (due to their reference count reaching 0). In the public
129-
C-API examples of such objects includes the singletons and many builtin
130-
types. For such objects the reference count is essentially irrelevant.
131-
Immortal objects are especially useful if otherwise immutable.
132-
133-
Note that for now the API for immortal objects is not available
134-
for general use, by default. Users of the public C-API (but not
135-
the limited API) may opt in by defining ``_Py_IMMORTAL_OBJECTS``.
136-
This API should not be considered stable yet.
137-
138-
.. c:function:: int _PyObject_IsImmortal(PyObject *o)
139-
140-
Return non-zero if the object is immortal.
141-
142-
.. versionadded:: 3.10
143-
144-
.. c:function:: void _PyObject_SetImmortal(PyObject *o)
145-
146-
Mark an object as immortal.
147-
148-
.. versionadded:: 3.10
149-
150-
Also see :c:macro:`_PyObject_HEAD_IMMORTAL_INIT` and
151-
:c:macro:`_PyVarObject_HEAD_IMMORTAL_INIT`.
152-
153-
.. _immutable-refcounts:
154-
155-
Immutable Refcounts
156-
-------------------
157-
158-
If ``Py_IMMORTAL_CONST_REFCOUNTS`` is defined then the following
159-
happens:
160-
161-
* the immortal objects API is enabled
162-
* the runtime never changes reference counts for immortal objects
163-
164-
This mode can help with copy-on-write semantics when forking.
165-

Doc/c-api/structures.rst

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@ the definition of all other Python objects.
9898
.. c:function:: void Py_SET_REFCNT(PyObject *o, Py_ssize_t refcnt)
9999
100100
Set the object *o* reference counter to *refcnt*.
101-
:ref:`immortal-objects` are not affected.
102101
103102
.. versionadded:: 3.9
104103
@@ -136,39 +135,6 @@ the definition of all other Python objects.
136135
1, type, size,
137136
138137
139-
.. c:macro:: _PyObject_HEAD_IMMORTAL_INIT(type)
140-
141-
This is a macro which expands to initialization values for a new
142-
:c:type:`PyObject` type. It makes the object
143-
:ref:`immortal <immortal-objects>`. This macro expands to::
144-
145-
_PyObject_EXTRA_INIT
146-
_PyObject_IMMORTAL_INIT_REFCNT, type,
147-
148-
For now you must opt in to use this by defining
149-
``_Py_IMMORTAL_OBJECTS``.
150-
151-
.. versionadded:: 3.10
152-
153-
154-
.. c:macro:: PyVarObject_HEAD_IMMORTAL_INIT(type, size)
155-
156-
This is a macro which expands to initialization values for a new
157-
:c:type:`PyVarObject` type, including the :attr:`ob_size` field.
158-
It makes the object :ref:`immortal <immortal-objects>`. This
159-
macro expands to::
160-
161-
_PyObject_EXTRA_INIT
162-
_PyObject_IMMORTAL_INIT_REFCNT, type, size,
163-
164-
This is especially useful for static types.
165-
166-
For now you must opt in to use this by defining
167-
``_Py_IMMORTAL_OBJECTS``.
168-
169-
.. versionadded:: 3.10
170-
171-
172138
Implementing functions and methods
173139
----------------------------------
174140

Include/cpython/object.h

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -376,60 +376,6 @@ PyAPI_FUNC(PyObject *) _PyObject_FunctionStr(PyObject *);
376376
} while (0)
377377

378378

379-
/* Immortal Objects
380-
*
381-
* An "immortal" object is one for which Py_DECREF() will never try
382-
* to deallocate it. */
383-
384-
#if defined(Py_IMMORTAL_CONST_REFCOUNTS) || defined(Py_BUILD_CORE)
385-
#define _Py_IMMORTAL_OBJECTS 1
386-
#endif
387-
388-
#ifdef _Py_IMMORTAL_OBJECTS
389-
390-
/* The implementation-independent API is only the following functions: */
391-
PyAPI_FUNC(int) _PyObject_IsImmortal(PyObject *);
392-
PyAPI_FUNC(void) _PyObject_SetImmortal(PyObject *);
393-
394-
/* In the actual implementation we set the refcount to some positive
395-
* value that we would never expect to be reachable through use of
396-
* Py_INCREF() in a program.
397-
*
398-
* The only parts that should be used directly are the two
399-
* _Py*Object_HEAD_IMMORTAL_INIT() macros.
400-
*/
401-
402-
/* _PyObject_IMMORTAL_BIT is the bit in the refcount value (Py_ssize_t)
403-
* that we use to mark an object as immortal. It shouldn't ever be
404-
* part of the public API.
405-
*
406-
* The GC bit-shifts refcounts left by two, and after that shift we still
407-
* need this to be >> 0, so leave three high zero bits (the sign bit and
408-
* room for a shift of two.) */
409-
#define _PyObject_IMMORTAL_BIT (1LL << (8 * sizeof(Py_ssize_t) - 4))
410-
411-
/* _PyObject_IMMORTAL_INIT_REFCNT is the initial value we use for
412-
* immortal objects. It shouldn't ever be part of the public API. */
413-
#ifdef Py_IMMORTAL_CONST_REFCOUNTS
414-
#define _PyObject_IMMORTAL_INIT_REFCNT \
415-
_PyObject_IMMORTAL_BIT
416-
#else
417-
// We leave plenty of room to preserve _PyObject_IMMORTAL_BIT.
418-
#define _PyObject_IMMORTAL_INIT_REFCNT \
419-
(_PyObject_IMMORTAL_BIT + (_PyObject_IMMORTAL_BIT / 2))
420-
#endif
421-
422-
/* These macros are drop-in replacements for the corresponding
423-
* Py*Object_HEAD_INIT() macros. They will probably become
424-
* part of the public API. */
425-
#define _PyObject_HEAD_IMMORTAL_INIT(type) \
426-
{ _PyObject_EXTRA_INIT _PyObject_IMMORTAL_INIT_REFCNT, type },
427-
#define _PyVarObject_HEAD_IMMORTAL_INIT(type, size) \
428-
{ PyObject_HEAD_IMMORTAL_INIT(type) size },
429-
430-
#endif /* defined(_Py_IMMORTAL_OBJECTS) */
431-
432-
433379
PyAPI_DATA(PyTypeObject) _PyNone_Type;
434380
PyAPI_DATA(PyTypeObject) _PyNotImplemented_Type;
435381

Include/internal/pycore_object.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,55 @@ _PyType_HasFeature(PyTypeObject *type, unsigned long feature) {
3030
extern void _PyType_InitCache(PyInterpreterState *interp);
3131

3232

33+
/* Immortal Objects
34+
*
35+
* An "immortal" object is one for which Py_DECREF() will never try
36+
* to deallocate it.
37+
*
38+
* At the moment this API is strictly internal. However, if it proves
39+
* helpful for extension authors we may move it to the public API. */
40+
41+
#define _Py_IMMORTAL_OBJECTS 1
42+
43+
/* The implementation-independent API is only the following functions: */
44+
PyAPI_FUNC(int) _PyObject_IsImmortal(PyObject *);
45+
PyAPI_FUNC(void) _PyObject_SetImmortal(PyObject *);
46+
47+
/* In the actual implementation we set the refcount to some positive
48+
* value that we would never expect to be reachable through use of
49+
* Py_INCREF() in a program.
50+
*
51+
* The only parts that should be used directly are the two
52+
* _Py*Object_HEAD_IMMORTAL_INIT() macros.
53+
*/
54+
55+
/* _PyObject_IMMORTAL_BIT is the bit in the refcount value (Py_ssize_t)
56+
* that we use to mark an object as immortal. It shouldn't ever be
57+
* part of the public API.
58+
*
59+
* The GC bit-shifts refcounts left by two, and after that shift we still
60+
* need this to be >> 0, so leave three high zero bits (the sign bit and
61+
* room for a shift of two.) */
62+
#define _PyObject_IMMORTAL_BIT (1LL << (8 * sizeof(Py_ssize_t) - 4))
63+
64+
/* _PyObject_IMMORTAL_INIT_REFCNT is the initial value we use for
65+
* immortal objects. It shouldn't ever be part of the public API.
66+
*
67+
* We leave plenty of room to preserve _PyObject_IMMORTAL_BIT. */
68+
#define _PyObject_IMMORTAL_INIT_REFCNT \
69+
(_PyObject_IMMORTAL_BIT + (_PyObject_IMMORTAL_BIT / 2))
70+
71+
/* These macros are drop-in replacements for the corresponding
72+
* Py*Object_HEAD_INIT() macros. They will probably become
73+
* part of the public API. */
74+
#define _PyObject_HEAD_IMMORTAL_INIT(type) \
75+
{ _PyObject_EXTRA_INIT _PyObject_IMMORTAL_INIT_REFCNT, type },
76+
#define _PyVarObject_HEAD_IMMORTAL_INIT(type, size) \
77+
{ PyObject_HEAD_IMMORTAL_INIT(type) size },
78+
79+
/* end Immortal Objects */
80+
81+
3382
/* Inline functions trading binary compatibility for speed:
3483
_PyObject_Init() is the fast version of PyObject_Init(), and
3584
_PyObject_InitVar() is the fast version of PyObject_InitVar().

Include/object.h

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -433,11 +433,6 @@ static inline void _Py_INCREF(PyObject *op)
433433
{
434434
#ifdef Py_REF_DEBUG
435435
_Py_RefTotal++;
436-
#endif
437-
#ifdef Py_IMMORTAL_CONST_REFCOUNTS
438-
if (_py_is_immortal(op)) {
439-
return;
440-
}
441436
#endif
442437
op->ob_refcnt++;
443438
}
@@ -451,11 +446,6 @@ static inline void _Py_DECREF(
451446
{
452447
#ifdef Py_REF_DEBUG
453448
_Py_RefTotal--;
454-
#endif
455-
#ifdef Py_IMMORTAL_CONST_REFCOUNTS
456-
if (_py_is_immortal(op)) {
457-
return;
458-
}
459449
#endif
460450
if (--op->ob_refcnt != 0) {
461451
#ifdef Py_REF_DEBUG
@@ -688,22 +678,6 @@ times.
688678
#endif
689679

690680

691-
#if defined(Py_LIMITED_API) && \
692-
(defined(_Py_IMMORTAL_OBJECTS) || defined(Py_IMMORTAL_CONST_REFCOUNTS))
693-
#error "the immortal objects API is not available in the limited API"
694-
#endif
695-
696-
#ifdef Py_IMMORTAL_CONST_REFCOUNTS
697-
// We need this function since _PyObject_IMMORTAL_BIT is defined
698-
// in cpython/object.h and not available for use above. Otherwise
699-
// we wouldn't need this function.
700-
static inline int _py_is_immortal(PyObject *op)
701-
{
702-
return (op->ob_refcnt & _PyObject_IMMORTAL_BIT) != 0;
703-
}
704-
#endif
705-
706-
707681
static inline int
708682
PyType_HasFeature(PyTypeObject *type, unsigned long feature)
709683
{
Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
There is now internal support for "immortal" objects. Those are objects
2-
that will never be deleted, like the singletons and static types. This has
3-
benefits for the C-API and subinterpreters, as well as allowing for better
4-
copy-on-write behavior for forking (if Py_IMMORTAL_CONST_REFCOUNTS is used).
5-
The feature is currently intended for internal use, though you can try it
6-
out by building with _Py_IMMORTAL_OBJECTS defined.
1+
There is now internal support for "immortal" objects (with a "private"
2+
C-API). Those are objects that will never be deleted, like the
3+
singletons and static types. This will benefit the C-API and
4+
subinterpreters. For now the API is currently intended only
5+
for internal use.

0 commit comments

Comments
 (0)