1use crate::pyport::Py_ssize_t;
2use crate::PyObject;
3#[cfg(all(not(Py_LIMITED_API), py_sys_config = "Py_REF_DEBUG"))]
4use core::ffi::c_char;
5#[cfg(any(Py_3_12, all(py_sys_config = "Py_REF_DEBUG", not(Py_LIMITED_API))))]
6use core::ffi::c_int;
7#[cfg(all(Py_3_14, any(not(Py_GIL_DISABLED), target_pointer_width = "32")))]
8use core::ffi::c_long;
9#[cfg(any(Py_GIL_DISABLED, all(Py_3_12, not(Py_3_14))))]
10use core::ffi::c_uint;
11#[cfg(all(Py_3_14, not(Py_GIL_DISABLED)))]
12use core::ffi::c_ulong;
13use core::ptr;
14#[cfg(all(Py_GIL_DISABLED, not(Py_LIMITED_API)))]
15use core::sync::atomic::Ordering::Relaxed;
16
17#[cfg(all(Py_3_14, not(Py_3_15)))]
18const _Py_STATICALLY_ALLOCATED_FLAG: c_int = 1 << 7;
19#[cfg(Py_3_15)]
20pub(crate) const _Py_STATICALLY_ALLOCATED_FLAG: c_int = 1 << 2;
21
22#[cfg(all(Py_3_12, not(Py_3_14)))]
23const _Py_IMMORTAL_REFCNT: Py_ssize_t = {
24 if cfg!(target_pointer_width = "64") {
25 c_uint::MAX as Py_ssize_t
26 } else {
27 (c_uint::MAX >> 2) as Py_ssize_t
29 }
30};
31
32#[cfg(all(Py_3_14, not(Py_GIL_DISABLED)))]
35const _Py_IMMORTAL_INITIAL_REFCNT: Py_ssize_t = {
36 if cfg!(target_pointer_width = "64") {
37 ((3 as c_ulong) << (30 as c_ulong)) as Py_ssize_t
38 } else {
39 ((5 as c_long) << (28 as c_long)) as Py_ssize_t
40 }
41};
42
43#[cfg(all(Py_3_14, not(Py_GIL_DISABLED)))]
44const _Py_STATIC_IMMORTAL_INITIAL_REFCNT: Py_ssize_t = {
45 if cfg!(target_pointer_width = "64") {
46 _Py_IMMORTAL_INITIAL_REFCNT
47 | ((_Py_STATICALLY_ALLOCATED_FLAG as Py_ssize_t) << (32 as Py_ssize_t))
48 } else {
49 ((7 as c_long) << (28 as c_long)) as Py_ssize_t
50 }
51};
52
53#[cfg(all(Py_3_14, target_pointer_width = "32"))]
54const _Py_IMMORTAL_MINIMUM_REFCNT: Py_ssize_t = ((1 as c_long) << (30 as c_long)) as Py_ssize_t;
55
56#[cfg(all(Py_3_14, target_pointer_width = "32"))]
57const _Py_STATIC_IMMORTAL_MINIMUM_REFCNT: Py_ssize_t =
58 ((6 as c_long) << (28 as c_long)) as Py_ssize_t;
59
60#[cfg(all(Py_3_14, Py_GIL_DISABLED))]
61const _Py_IMMORTAL_INITIAL_REFCNT: Py_ssize_t = c_uint::MAX as Py_ssize_t;
62
63#[cfg(Py_GIL_DISABLED)]
64pub(crate) const _Py_IMMORTAL_REFCNT_LOCAL: u32 = u32::MAX;
65
66#[cfg(Py_GIL_DISABLED)]
67const _Py_REF_SHARED_SHIFT: isize = 2;
68extern_libpython! {
78 #[cfg(all(Py_3_14, Py_LIMITED_API))]
79 pub fn Py_REFCNT(ob: *mut PyObject) -> Py_ssize_t;
80}
81
82#[cfg(not(all(Py_3_14, Py_LIMITED_API)))]
83#[inline]
84pub unsafe fn Py_REFCNT(ob: *mut PyObject) -> Py_ssize_t {
85 #[cfg(Py_GIL_DISABLED)]
86 {
87 let local = (*ob).ob_ref_local.load(Relaxed);
88 if local == _Py_IMMORTAL_REFCNT_LOCAL {
89 #[cfg(not(Py_3_14))]
90 return _Py_IMMORTAL_REFCNT;
91 #[cfg(Py_3_14)]
92 return _Py_IMMORTAL_INITIAL_REFCNT;
93 }
94 let shared = (*ob).ob_ref_shared.load(Relaxed);
95 local as Py_ssize_t + Py_ssize_t::from(shared >> _Py_REF_SHARED_SHIFT)
96 }
97
98 #[cfg(all(Py_LIMITED_API, Py_3_14))]
99 {
100 Py_REFCNT(ob)
101 }
102
103 #[cfg(all(not(Py_GIL_DISABLED), not(all(Py_LIMITED_API, Py_3_14)), Py_3_12))]
104 {
105 (*ob).ob_refcnt.ob_refcnt
106 }
107
108 #[cfg(all(not(Py_GIL_DISABLED), not(Py_3_12), not(GraalPy)))]
109 {
110 (*ob).ob_refcnt
111 }
112
113 #[cfg(all(not(Py_GIL_DISABLED), not(Py_3_12), GraalPy))]
114 {
115 _Py_REFCNT(ob)
116 }
117}
118
119#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
120#[cfg(Py_3_12)]
121#[inline(always)]
122unsafe fn _Py_IsImmortal(op: *mut PyObject) -> c_int {
123 #[cfg(all(target_pointer_width = "64", not(Py_GIL_DISABLED)))]
124 {
125 (((*op).ob_refcnt.ob_refcnt as crate::PY_INT32_T) < 0) as c_int
126 }
127
128 #[cfg(all(target_pointer_width = "32", not(Py_GIL_DISABLED)))]
129 {
130 #[cfg(not(Py_3_14))]
131 {
132 ((*op).ob_refcnt.ob_refcnt == _Py_IMMORTAL_REFCNT) as c_int
133 }
134
135 #[cfg(Py_3_14)]
136 {
137 ((*op).ob_refcnt.ob_refcnt >= _Py_IMMORTAL_MINIMUM_REFCNT) as c_int
138 }
139 }
140
141 #[cfg(Py_GIL_DISABLED)]
142 {
143 ((*op).ob_ref_local.load(Relaxed) == _Py_IMMORTAL_REFCNT_LOCAL) as c_int
144 }
145}
146
147extern_libpython! {
152 #[cfg(all(py_sys_config = "Py_REF_DEBUG", not(Py_LIMITED_API)))]
153 fn _Py_NegativeRefcount(filename: *const c_char, lineno: c_int, op: *mut PyObject);
154 #[cfg(all(Py_3_12, py_sys_config = "Py_REF_DEBUG", not(Py_LIMITED_API)))]
155 fn _Py_INCREF_IncRefTotal();
156 #[cfg(all(Py_3_12, py_sys_config = "Py_REF_DEBUG", not(Py_LIMITED_API)))]
157 fn _Py_DECREF_DecRefTotal();
158
159 #[cfg_attr(PyPy, link_name = "_PyPy_Dealloc")]
160 fn _Py_Dealloc(arg1: *mut PyObject);
161
162 #[cfg_attr(PyPy, link_name = "PyPy_IncRef")]
163 #[cfg_attr(GraalPy, link_name = "_Py_IncRef")]
164 pub fn Py_IncRef(o: *mut PyObject);
165 #[cfg_attr(PyPy, link_name = "PyPy_DecRef")]
166 #[cfg_attr(GraalPy, link_name = "_Py_DecRef")]
167 pub fn Py_DecRef(o: *mut PyObject);
168
169 #[cfg(all(Py_3_10, not(PyPy)))]
170 fn _Py_IncRef(o: *mut PyObject);
171 #[cfg(all(Py_3_10, not(PyPy)))]
172 fn _Py_DecRef(o: *mut PyObject);
173
174 #[cfg(GraalPy)]
175 fn _Py_REFCNT(arg1: *const PyObject) -> Py_ssize_t;
176}
177
178#[inline(always)]
179pub unsafe fn Py_INCREF(op: *mut PyObject) {
180 #[cfg(any(
183 Py_GIL_DISABLED,
184 Py_LIMITED_API,
185 py_sys_config = "Py_REF_DEBUG",
186 GraalPy
187 ))]
188 {
189 #[cfg(all(Py_3_10, not(PyPy)))]
191 {
192 _Py_IncRef(op);
193 }
194
195 #[cfg(any(not(Py_3_10), PyPy))]
196 {
197 Py_IncRef(op);
198 }
199 }
200
201 #[cfg(not(any(
203 Py_GIL_DISABLED,
204 Py_LIMITED_API,
205 py_sys_config = "Py_REF_DEBUG",
206 GraalPy
207 )))]
208 {
209 #[cfg(all(Py_3_14, target_pointer_width = "64"))]
210 {
211 let cur_refcnt = (*op).ob_refcnt.ob_refcnt;
212 if (cur_refcnt as i32) < 0 {
213 return;
214 }
215 (*op).ob_refcnt.ob_refcnt = cur_refcnt.wrapping_add(1);
216 }
217
218 #[cfg(all(Py_3_12, not(Py_3_14), target_pointer_width = "64"))]
219 {
220 let cur_refcnt = (*op).ob_refcnt.ob_refcnt_split[crate::PY_BIG_ENDIAN];
221 let new_refcnt = cur_refcnt.wrapping_add(1);
222 if new_refcnt == 0 {
223 return;
224 }
225 (*op).ob_refcnt.ob_refcnt_split[crate::PY_BIG_ENDIAN] = new_refcnt;
226 }
227
228 #[cfg(all(Py_3_12, target_pointer_width = "32"))]
229 {
230 if _Py_IsImmortal(op) != 0 {
231 return;
232 }
233 (*op).ob_refcnt.ob_refcnt += 1
234 }
235
236 #[cfg(not(Py_3_12))]
237 {
238 (*op).ob_refcnt += 1
239 }
240
241 }
244}
245
246#[inline(always)]
251#[cfg_attr(
252 all(py_sys_config = "Py_REF_DEBUG", Py_3_12, not(Py_LIMITED_API)),
253 track_caller
254)]
255pub unsafe fn Py_DECREF(op: *mut PyObject) {
256 #[cfg(any(
260 Py_GIL_DISABLED,
261 Py_LIMITED_API,
262 all(py_sys_config = "Py_REF_DEBUG", not(Py_3_12)),
263 GraalPy
264 ))]
265 {
266 #[cfg(all(Py_3_10, not(PyPy)))]
268 {
269 _Py_DecRef(op);
270 }
271
272 #[cfg(any(not(Py_3_10), PyPy))]
273 {
274 Py_DecRef(op);
275 }
276 }
277
278 #[cfg(not(any(
279 Py_GIL_DISABLED,
280 Py_LIMITED_API,
281 all(py_sys_config = "Py_REF_DEBUG", not(Py_3_12)),
282 GraalPy
283 )))]
284 {
285 #[cfg(Py_3_12)]
286 if _Py_IsImmortal(op) != 0 {
287 return;
288 }
289
290 #[cfg(py_sys_config = "Py_REF_DEBUG")]
294 _Py_DECREF_DecRefTotal();
295
296 #[cfg(Py_3_12)]
297 {
298 (*op).ob_refcnt.ob_refcnt -= 1;
299
300 #[cfg(py_sys_config = "Py_REF_DEBUG")]
301 if (*op).ob_refcnt.ob_refcnt < 0 {
302 let location = core::panic::Location::caller();
303 let filename = alloc::ffi::CString::new(location.file()).unwrap();
304 _Py_NegativeRefcount(filename.as_ptr(), location.line() as i32, op);
305 }
306
307 if (*op).ob_refcnt.ob_refcnt == 0 {
308 _Py_Dealloc(op);
309 }
310 }
311
312 #[cfg(not(Py_3_12))]
313 {
314 (*op).ob_refcnt -= 1;
315
316 if (*op).ob_refcnt == 0 {
317 _Py_Dealloc(op);
318 }
319 }
320 }
321}
322
323#[inline]
324pub unsafe fn Py_CLEAR(op: *mut *mut PyObject) {
325 let tmp = *op;
326 if !tmp.is_null() {
327 *op = ptr::null_mut();
328 Py_DECREF(tmp);
329 }
330}
331
332#[inline]
333pub unsafe fn Py_XINCREF(op: *mut PyObject) {
334 if !op.is_null() {
335 Py_INCREF(op)
336 }
337}
338
339#[inline]
340pub unsafe fn Py_XDECREF(op: *mut PyObject) {
341 if !op.is_null() {
342 Py_DECREF(op)
343 }
344}
345
346extern_libpython! {
347 #[cfg(all(Py_3_10, Py_LIMITED_API, not(PyPy)))]
348 #[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
349 pub fn Py_NewRef(obj: *mut PyObject) -> *mut PyObject;
350 #[cfg(all(Py_3_10, Py_LIMITED_API, not(PyPy)))]
351 #[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
352 pub fn Py_XNewRef(obj: *mut PyObject) -> *mut PyObject;
353}
354
355#[cfg(all(Py_3_10, any(not(Py_LIMITED_API), PyPy)))]
359#[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
360#[inline]
361pub unsafe fn Py_NewRef(obj: *mut PyObject) -> *mut PyObject {
362 Py_INCREF(obj);
363 obj
364}
365
366#[cfg(all(Py_3_10, any(not(Py_LIMITED_API), PyPy)))]
367#[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
368#[inline]
369pub unsafe fn Py_XNewRef(obj: *mut PyObject) -> *mut PyObject {
370 Py_XINCREF(obj);
371 obj
372}