1use crate::pyport::Py_ssize_t;
2use crate::PyObject;
3#[cfg(all(not(Py_LIMITED_API), py_sys_config = "Py_REF_DEBUG"))]
4use std::ffi::c_char;
5#[cfg(any(Py_3_12, all(py_sys_config = "Py_REF_DEBUG", not(Py_LIMITED_API))))]
6use std::ffi::c_int;
7#[cfg(all(Py_3_14, any(not(Py_GIL_DISABLED), target_pointer_width = "32")))]
8use std::ffi::c_long;
9#[cfg(any(Py_GIL_DISABLED, all(Py_3_12, not(Py_3_14))))]
10use std::ffi::c_uint;
11#[cfg(all(Py_3_14, not(Py_GIL_DISABLED)))]
12use std::ffi::c_ulong;
13use std::ptr;
14#[cfg(Py_GIL_DISABLED)]
15use std::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)))]
109 {
110 (*ob).ob_refcnt
111 }
112}
113
114#[cfg(Py_3_12)]
115#[inline(always)]
116unsafe fn _Py_IsImmortal(op: *mut PyObject) -> c_int {
117 #[cfg(all(target_pointer_width = "64", not(Py_GIL_DISABLED)))]
118 {
119 (((*op).ob_refcnt.ob_refcnt as crate::PY_INT32_T) < 0) as c_int
120 }
121
122 #[cfg(all(target_pointer_width = "32", not(Py_GIL_DISABLED)))]
123 {
124 #[cfg(not(Py_3_14))]
125 {
126 ((*op).ob_refcnt.ob_refcnt == _Py_IMMORTAL_REFCNT) as c_int
127 }
128
129 #[cfg(Py_3_14)]
130 {
131 ((*op).ob_refcnt.ob_refcnt >= _Py_IMMORTAL_MINIMUM_REFCNT) as c_int
132 }
133 }
134
135 #[cfg(Py_GIL_DISABLED)]
136 {
137 ((*op).ob_ref_local.load(Relaxed) == _Py_IMMORTAL_REFCNT_LOCAL) as c_int
138 }
139}
140
141extern_libpython! {
146 #[cfg(all(py_sys_config = "Py_REF_DEBUG", not(Py_LIMITED_API)))]
147 fn _Py_NegativeRefcount(filename: *const c_char, lineno: c_int, op: *mut PyObject);
148 #[cfg(all(Py_3_12, py_sys_config = "Py_REF_DEBUG", not(Py_LIMITED_API)))]
149 fn _Py_INCREF_IncRefTotal();
150 #[cfg(all(Py_3_12, py_sys_config = "Py_REF_DEBUG", not(Py_LIMITED_API)))]
151 fn _Py_DECREF_DecRefTotal();
152
153 fn _Py_Dealloc(arg1: *mut PyObject);
154
155 pub fn Py_IncRef(o: *mut PyObject);
156 pub fn Py_DecRef(o: *mut PyObject);
157
158 #[cfg(Py_3_10)]
159 fn _Py_IncRef(o: *mut PyObject);
160 #[cfg(Py_3_10)]
161 fn _Py_DecRef(o: *mut PyObject);
162}
163
164#[inline(always)]
165pub unsafe fn Py_INCREF(op: *mut PyObject) {
166 #[cfg(any(
169 Py_GIL_DISABLED,
170 Py_LIMITED_API,
171 py_sys_config = "Py_REF_DEBUG",
172 ))]
173 {
174 #[cfg(Py_3_10)]
176 {
177 _Py_IncRef(op);
178 }
179
180 #[cfg(not(Py_3_10))]
181 {
182 Py_IncRef(op);
183 }
184 }
185
186 #[cfg(not(any(
188 Py_GIL_DISABLED,
189 Py_LIMITED_API,
190 py_sys_config = "Py_REF_DEBUG",
191 )))]
192 {
193 #[cfg(all(Py_3_14, target_pointer_width = "64"))]
194 {
195 let cur_refcnt = (*op).ob_refcnt.ob_refcnt;
196 if (cur_refcnt as i32) < 0 {
197 return;
198 }
199 (*op).ob_refcnt.ob_refcnt = cur_refcnt.wrapping_add(1);
200 }
201
202 #[cfg(all(Py_3_12, not(Py_3_14), target_pointer_width = "64"))]
203 {
204 let cur_refcnt = (*op).ob_refcnt.ob_refcnt_split[crate::PY_BIG_ENDIAN];
205 let new_refcnt = cur_refcnt.wrapping_add(1);
206 if new_refcnt == 0 {
207 return;
208 }
209 (*op).ob_refcnt.ob_refcnt_split[crate::PY_BIG_ENDIAN] = new_refcnt;
210 }
211
212 #[cfg(all(Py_3_12, target_pointer_width = "32"))]
213 {
214 if _Py_IsImmortal(op) != 0 {
215 return;
216 }
217 (*op).ob_refcnt.ob_refcnt += 1
218 }
219
220 #[cfg(not(Py_3_12))]
221 {
222 (*op).ob_refcnt += 1
223 }
224
225 }
228}
229
230#[inline(always)]
235#[cfg_attr(
236 all(py_sys_config = "Py_REF_DEBUG", Py_3_12, not(Py_LIMITED_API)),
237 track_caller
238)]
239pub unsafe fn Py_DECREF(op: *mut PyObject) {
240 #[cfg(any(
244 Py_GIL_DISABLED,
245 Py_LIMITED_API,
246 all(py_sys_config = "Py_REF_DEBUG", not(Py_3_12)),
247 ))]
248 {
249 #[cfg(Py_3_10)]
251 {
252 _Py_DecRef(op);
253 }
254
255 #[cfg(not(Py_3_10))]
256 {
257 Py_DecRef(op);
258 }
259 }
260
261 #[cfg(not(any(
262 Py_GIL_DISABLED,
263 Py_LIMITED_API,
264 all(py_sys_config = "Py_REF_DEBUG", not(Py_3_12)),
265 )))]
266 {
267 #[cfg(Py_3_12)]
268 if _Py_IsImmortal(op) != 0 {
269 return;
270 }
271
272 #[cfg(py_sys_config = "Py_REF_DEBUG")]
276 _Py_DECREF_DecRefTotal();
277
278 #[cfg(Py_3_12)]
279 {
280 (*op).ob_refcnt.ob_refcnt -= 1;
281
282 #[cfg(py_sys_config = "Py_REF_DEBUG")]
283 if (*op).ob_refcnt.ob_refcnt < 0 {
284 let location = std::panic::Location::caller();
285 let filename = std::ffi::CString::new(location.file()).unwrap();
286 _Py_NegativeRefcount(filename.as_ptr(), location.line() as i32, op);
287 }
288
289 if (*op).ob_refcnt.ob_refcnt == 0 {
290 _Py_Dealloc(op);
291 }
292 }
293
294 #[cfg(not(Py_3_12))]
295 {
296 (*op).ob_refcnt -= 1;
297
298 if (*op).ob_refcnt == 0 {
299 _Py_Dealloc(op);
300 }
301 }
302 }
303}
304
305#[inline]
306pub unsafe fn Py_CLEAR(op: *mut *mut PyObject) {
307 let tmp = *op;
308 if !tmp.is_null() {
309 *op = ptr::null_mut();
310 Py_DECREF(tmp);
311 }
312}
313
314#[inline]
315pub unsafe fn Py_XINCREF(op: *mut PyObject) {
316 if !op.is_null() {
317 Py_INCREF(op)
318 }
319}
320
321#[inline]
322pub unsafe fn Py_XDECREF(op: *mut PyObject) {
323 if !op.is_null() {
324 Py_DECREF(op)
325 }
326}
327
328extern_libpython! {
329 #[cfg(all(Py_3_10, Py_LIMITED_API))]
330 #[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
331 pub fn Py_NewRef(obj: *mut PyObject) -> *mut PyObject;
332 #[cfg(all(Py_3_10, Py_LIMITED_API))]
333 #[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
334 pub fn Py_XNewRef(obj: *mut PyObject) -> *mut PyObject;
335}
336
337#[cfg(all(Py_3_10, not(Py_LIMITED_API)))]
341#[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
342#[inline]
343pub unsafe fn Py_NewRef(obj: *mut PyObject) -> *mut PyObject {
344 Py_INCREF(obj);
345 obj
346}
347
348#[cfg(all(Py_3_10, not(Py_LIMITED_API)))]
349#[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
350#[inline]
351pub unsafe fn Py_XNewRef(obj: *mut PyObject) -> *mut PyObject {
352 Py_XINCREF(obj);
353 obj
354}