1use crate::pyport::Py_ssize_t;
2use crate::PyObject;
3#[cfg(py_sys_config = "Py_REF_DEBUG")]
4use std::ffi::c_char;
5#[cfg(Py_3_12)]
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 "C" {
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(Py_3_12)]
120#[inline(always)]
121unsafe fn _Py_IsImmortal(op: *mut PyObject) -> c_int {
122 #[cfg(all(target_pointer_width = "64", not(Py_GIL_DISABLED)))]
123 {
124 (((*op).ob_refcnt.ob_refcnt as crate::PY_INT32_T) < 0) as c_int
125 }
126
127 #[cfg(all(target_pointer_width = "32", not(Py_GIL_DISABLED)))]
128 {
129 #[cfg(not(Py_3_14))]
130 {
131 ((*op).ob_refcnt.ob_refcnt == _Py_IMMORTAL_REFCNT) as c_int
132 }
133
134 #[cfg(Py_3_14)]
135 {
136 ((*op).ob_refcnt.ob_refcnt >= _Py_IMMORTAL_MINIMUM_REFCNT) as c_int
137 }
138 }
139
140 #[cfg(Py_GIL_DISABLED)]
141 {
142 ((*op).ob_ref_local.load(Relaxed) == _Py_IMMORTAL_REFCNT_LOCAL) as c_int
143 }
144}
145
146extern "C" {
151 #[cfg(all(py_sys_config = "Py_REF_DEBUG", not(Py_LIMITED_API)))]
152 fn _Py_NegativeRefcount(filename: *const c_char, lineno: c_int, op: *mut PyObject);
153 #[cfg(all(Py_3_12, py_sys_config = "Py_REF_DEBUG", not(Py_LIMITED_API)))]
154 fn _Py_INCREF_IncRefTotal();
155 #[cfg(all(Py_3_12, py_sys_config = "Py_REF_DEBUG", not(Py_LIMITED_API)))]
156 fn _Py_DECREF_DecRefTotal();
157
158 #[cfg_attr(PyPy, link_name = "_PyPy_Dealloc")]
159 fn _Py_Dealloc(arg1: *mut PyObject);
160
161 #[cfg_attr(PyPy, link_name = "PyPy_IncRef")]
162 #[cfg_attr(GraalPy, link_name = "_Py_IncRef")]
163 pub fn Py_IncRef(o: *mut PyObject);
164 #[cfg_attr(PyPy, link_name = "PyPy_DecRef")]
165 #[cfg_attr(GraalPy, link_name = "_Py_DecRef")]
166 pub fn Py_DecRef(o: *mut PyObject);
167
168 #[cfg(all(Py_3_10, not(PyPy)))]
169 fn _Py_IncRef(o: *mut PyObject);
170 #[cfg(all(Py_3_10, not(PyPy)))]
171 fn _Py_DecRef(o: *mut PyObject);
172
173 #[cfg(GraalPy)]
174 fn _Py_REFCNT(arg1: *const PyObject) -> Py_ssize_t;
175}
176
177#[inline(always)]
178pub unsafe fn Py_INCREF(op: *mut PyObject) {
179 #[cfg(any(
182 Py_GIL_DISABLED,
183 Py_LIMITED_API,
184 py_sys_config = "Py_REF_DEBUG",
185 GraalPy
186 ))]
187 {
188 #[cfg(all(Py_3_10, not(PyPy)))]
190 {
191 _Py_IncRef(op);
192 }
193
194 #[cfg(any(not(Py_3_10), PyPy))]
195 {
196 Py_IncRef(op);
197 }
198 }
199
200 #[cfg(not(any(
202 Py_GIL_DISABLED,
203 Py_LIMITED_API,
204 py_sys_config = "Py_REF_DEBUG",
205 GraalPy
206 )))]
207 {
208 #[cfg(all(Py_3_14, target_pointer_width = "64"))]
209 {
210 let cur_refcnt = (*op).ob_refcnt.ob_refcnt;
211 if (cur_refcnt as i32) < 0 {
212 return;
213 }
214 (*op).ob_refcnt.ob_refcnt = cur_refcnt.wrapping_add(1);
215 }
216
217 #[cfg(all(Py_3_12, not(Py_3_14), target_pointer_width = "64"))]
218 {
219 let cur_refcnt = (*op).ob_refcnt.ob_refcnt_split[crate::PY_BIG_ENDIAN];
220 let new_refcnt = cur_refcnt.wrapping_add(1);
221 if new_refcnt == 0 {
222 return;
223 }
224 (*op).ob_refcnt.ob_refcnt_split[crate::PY_BIG_ENDIAN] = new_refcnt;
225 }
226
227 #[cfg(all(Py_3_12, target_pointer_width = "32"))]
228 {
229 if _Py_IsImmortal(op) != 0 {
230 return;
231 }
232 (*op).ob_refcnt.ob_refcnt += 1
233 }
234
235 #[cfg(not(Py_3_12))]
236 {
237 (*op).ob_refcnt += 1
238 }
239
240 }
243}
244
245#[inline(always)]
250#[cfg_attr(
251 all(py_sys_config = "Py_REF_DEBUG", Py_3_12, not(Py_LIMITED_API)),
252 track_caller
253)]
254pub unsafe fn Py_DECREF(op: *mut PyObject) {
255 #[cfg(any(
259 Py_GIL_DISABLED,
260 Py_LIMITED_API,
261 all(py_sys_config = "Py_REF_DEBUG", not(Py_3_12)),
262 GraalPy
263 ))]
264 {
265 #[cfg(all(Py_3_10, not(PyPy)))]
267 {
268 _Py_DecRef(op);
269 }
270
271 #[cfg(any(not(Py_3_10), PyPy))]
272 {
273 Py_DecRef(op);
274 }
275 }
276
277 #[cfg(not(any(
278 Py_GIL_DISABLED,
279 Py_LIMITED_API,
280 all(py_sys_config = "Py_REF_DEBUG", not(Py_3_12)),
281 GraalPy
282 )))]
283 {
284 #[cfg(Py_3_12)]
285 if _Py_IsImmortal(op) != 0 {
286 return;
287 }
288
289 #[cfg(py_sys_config = "Py_REF_DEBUG")]
293 _Py_DECREF_DecRefTotal();
294
295 #[cfg(Py_3_12)]
296 {
297 (*op).ob_refcnt.ob_refcnt -= 1;
298
299 #[cfg(py_sys_config = "Py_REF_DEBUG")]
300 if (*op).ob_refcnt.ob_refcnt < 0 {
301 let location = std::panic::Location::caller();
302 let filename = std::ffi::CString::new(location.file()).unwrap();
303 _Py_NegativeRefcount(filename.as_ptr(), location.line() as i32, op);
304 }
305
306 if (*op).ob_refcnt.ob_refcnt == 0 {
307 _Py_Dealloc(op);
308 }
309 }
310
311 #[cfg(not(Py_3_12))]
312 {
313 (*op).ob_refcnt -= 1;
314
315 if (*op).ob_refcnt == 0 {
316 _Py_Dealloc(op);
317 }
318 }
319 }
320}
321
322#[inline]
323pub unsafe fn Py_CLEAR(op: *mut *mut PyObject) {
324 let tmp = *op;
325 if !tmp.is_null() {
326 *op = ptr::null_mut();
327 Py_DECREF(tmp);
328 }
329}
330
331#[inline]
332pub unsafe fn Py_XINCREF(op: *mut PyObject) {
333 if !op.is_null() {
334 Py_INCREF(op)
335 }
336}
337
338#[inline]
339pub unsafe fn Py_XDECREF(op: *mut PyObject) {
340 if !op.is_null() {
341 Py_DECREF(op)
342 }
343}
344
345extern "C" {
346 #[cfg(all(Py_3_10, Py_LIMITED_API, not(PyPy)))]
347 #[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
348 pub fn Py_NewRef(obj: *mut PyObject) -> *mut PyObject;
349 #[cfg(all(Py_3_10, Py_LIMITED_API, not(PyPy)))]
350 #[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
351 pub fn Py_XNewRef(obj: *mut PyObject) -> *mut PyObject;
352}
353
354#[cfg(all(Py_3_10, any(not(Py_LIMITED_API), PyPy)))]
358#[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
359#[inline]
360pub unsafe fn Py_NewRef(obj: *mut PyObject) -> *mut PyObject {
361 Py_INCREF(obj);
362 obj
363}
364
365#[cfg(all(Py_3_10, any(not(Py_LIMITED_API), PyPy)))]
366#[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
367#[inline]
368pub unsafe fn Py_XNewRef(obj: *mut PyObject) -> *mut PyObject {
369 Py_XINCREF(obj);
370 obj
371}