Skip to content

Commit 2d3a76e

Browse files
committed
gh-110481: Move non-limited Py_INCREF() to cpython/object.h
Move the non-limited implementation of Py_INCREF() and Py_DECREF() from Include/object.h to Include/cpython/object.h. Move static inline functions using Py_INCREF/DECREF() after the cpython/object.h include: Py_XINCREF(), Py_XDECREF(), Py_NewRef() and Py_XNewRef().
1 parent 8eaa206 commit 2d3a76e

File tree

2 files changed

+202
-169
lines changed

2 files changed

+202
-169
lines changed

Include/cpython/object.h

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,146 @@
22
# error "this header file must not be included directly"
33
#endif
44

5+
#if defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || defined(Py_REF_DEBUG))
6+
// Implemented in ../object.h
7+
#else
8+
static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op)
9+
{
10+
// Non-limited C API and limited C API for Python 3.9 and older access
11+
// directly PyObject.ob_refcnt.
12+
#if defined(Py_NOGIL)
13+
uint32_t local = _Py_atomic_load_uint32_relaxed(&op->ob_ref_local);
14+
uint32_t new_local = local + 1;
15+
if (new_local == 0) {
16+
return;
17+
}
18+
if (_Py_IsOwnedByCurrentThread(op)) {
19+
_Py_atomic_store_uint32_relaxed(&op->ob_ref_local, new_local);
20+
}
21+
else {
22+
_Py_atomic_add_ssize(&op->ob_ref_shared, (1 << _Py_REF_SHARED_SHIFT));
23+
}
24+
#elif SIZEOF_VOID_P > 4
25+
// Portable saturated add, branching on the carry flag and set low bits
26+
PY_UINT32_T cur_refcnt = op->ob_refcnt_split[PY_BIG_ENDIAN];
27+
PY_UINT32_T new_refcnt = cur_refcnt + 1;
28+
if (new_refcnt == 0) {
29+
return;
30+
}
31+
op->ob_refcnt_split[PY_BIG_ENDIAN] = new_refcnt;
32+
#else
33+
// Explicitly check immortality against the immortal value
34+
if (_Py_IsImmortal(op)) {
35+
return;
36+
}
37+
op->ob_refcnt++;
38+
#endif
39+
_Py_INCREF_STAT_INC();
40+
#ifdef Py_REF_DEBUG
41+
_Py_INCREF_IncRefTotal();
42+
#endif
43+
}
44+
45+
# if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
46+
# define Py_INCREF(op) Py_INCREF(_PyObject_CAST(op))
47+
# endif
48+
#endif
49+
50+
51+
#ifdef Py_NOGIL
52+
// Implements Py_DECREF on objects not owned by the current thread.
53+
PyAPI_FUNC(void) _Py_DecRefShared(PyObject *);
54+
PyAPI_FUNC(void) _Py_DecRefSharedDebug(PyObject *, const char *, int);
55+
56+
// Called from Py_DECREF by the owning thread when the local refcount reaches
57+
// zero. The call will deallocate the object if the shared refcount is also
58+
// zero. Otherwise, the thread gives up ownership and merges the reference
59+
// count fields.
60+
PyAPI_FUNC(void) _Py_MergeZeroLocalRefcount(PyObject *);
61+
#endif
62+
63+
#if defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || defined(Py_REF_DEBUG))
64+
// Implemented in ../object.h
65+
#elif defined(Py_NOGIL) && defined(Py_REF_DEBUG)
66+
static inline void Py_DECREF(const char *filename, int lineno, PyObject *op)
67+
{
68+
uint32_t local = _Py_atomic_load_uint32_relaxed(&op->ob_ref_local);
69+
if (local == _Py_IMMORTAL_REFCNT_LOCAL) {
70+
return;
71+
}
72+
_Py_DECREF_STAT_INC();
73+
_Py_DECREF_DecRefTotal();
74+
if (_Py_IsOwnedByCurrentThread(op)) {
75+
if (local == 0) {
76+
_Py_NegativeRefcount(filename, lineno, op);
77+
}
78+
local--;
79+
_Py_atomic_store_uint32_relaxed(&op->ob_ref_local, local);
80+
if (local == 0) {
81+
_Py_MergeZeroLocalRefcount(op);
82+
}
83+
}
84+
else {
85+
_Py_DecRefSharedDebug(op, filename, lineno);
86+
}
87+
}
88+
#define Py_DECREF(op) Py_DECREF(__FILE__, __LINE__, _PyObject_CAST(op))
89+
90+
#elif defined(Py_NOGIL)
91+
static inline void Py_DECREF(PyObject *op)
92+
{
93+
uint32_t local = _Py_atomic_load_uint32_relaxed(&op->ob_ref_local);
94+
if (local == _Py_IMMORTAL_REFCNT_LOCAL) {
95+
return;
96+
}
97+
_Py_DECREF_STAT_INC();
98+
if (_Py_IsOwnedByCurrentThread(op)) {
99+
local--;
100+
_Py_atomic_store_uint32_relaxed(&op->ob_ref_local, local);
101+
if (local == 0) {
102+
_Py_MergeZeroLocalRefcount(op);
103+
}
104+
}
105+
else {
106+
_Py_DecRefShared(op);
107+
}
108+
}
109+
#define Py_DECREF(op) Py_DECREF(_PyObject_CAST(op))
110+
111+
#elif defined(Py_REF_DEBUG)
112+
static inline void Py_DECREF(const char *filename, int lineno, PyObject *op)
113+
{
114+
if (op->ob_refcnt <= 0) {
115+
_Py_NegativeRefcount(filename, lineno, op);
116+
}
117+
if (_Py_IsImmortal(op)) {
118+
return;
119+
}
120+
_Py_DECREF_STAT_INC();
121+
_Py_DECREF_DecRefTotal();
122+
if (--op->ob_refcnt == 0) {
123+
_Py_Dealloc(op);
124+
}
125+
}
126+
#define Py_DECREF(op) Py_DECREF(__FILE__, __LINE__, _PyObject_CAST(op))
127+
128+
#else
129+
static inline Py_ALWAYS_INLINE void Py_DECREF(PyObject *op)
130+
{
131+
// Non-limited C API and limited C API for Python 3.9 and older access
132+
// directly PyObject.ob_refcnt.
133+
if (_Py_IsImmortal(op)) {
134+
return;
135+
}
136+
_Py_DECREF_STAT_INC();
137+
if (--op->ob_refcnt == 0) {
138+
_Py_Dealloc(op);
139+
}
140+
}
141+
#define Py_DECREF(op) Py_DECREF(_PyObject_CAST(op))
142+
#endif
143+
144+
5145
PyAPI_FUNC(void) _Py_NewReference(PyObject *op);
6146
PyAPI_FUNC(void) _Py_NewReferenceNoTotal(PyObject *op);
7147

0 commit comments

Comments
 (0)