1 #ifndef Py_INTERNAL_STACKREF_H
2 #define Py_INTERNAL_STACKREF_H
3 #ifdef __cplusplus
4 extern "C" {
5 #endif
6
7 #ifndef Py_BUILD_CORE
8 # error "this header requires Py_BUILD_CORE define"
9 #endif
10
11 #include <stddef.h>
12
13 typedef union {
14 uintptr_t bits;
15 } _PyStackRef;
16
17 static const _PyStackRef Py_STACKREF_NULL = { .bits = 0 };
18
19 #define Py_TAG_DEFERRED (1)
20
21 // Gets a PyObject * from a _PyStackRef
22 #if defined(Py_GIL_DISABLED)
23 static inline PyObject *
PyStackRef_Get(_PyStackRef tagged)24 PyStackRef_Get(_PyStackRef tagged)
25 {
26 PyObject *cleared = ((PyObject *)((tagged).bits & (~Py_TAG_DEFERRED)));
27 return cleared;
28 }
29 #else
30 # define PyStackRef_Get(tagged) ((PyObject *)((tagged).bits))
31 #endif
32
33 // Converts a PyObject * to a PyStackRef, stealing the reference.
34 #if defined(Py_GIL_DISABLED)
35 static inline _PyStackRef
_PyStackRef_StealRef(PyObject * obj)36 _PyStackRef_StealRef(PyObject *obj)
37 {
38 // Make sure we don't take an already tagged value.
39 assert(((uintptr_t)obj & Py_TAG_DEFERRED) == 0);
40 return ((_PyStackRef){.bits = ((uintptr_t)(obj))});
41 }
42 # define PyStackRef_StealRef(obj) _PyStackRef_StealRef(_PyObject_CAST(obj))
43 #else
44 # define PyStackRef_StealRef(obj) ((_PyStackRef){.bits = ((uintptr_t)(obj))})
45 #endif
46
47 // Converts a PyObject * to a PyStackRef, with a new reference
48 #if defined(Py_GIL_DISABLED)
49 static inline _PyStackRef
_PyStackRef_NewRefDeferred(PyObject * obj)50 _PyStackRef_NewRefDeferred(PyObject *obj)
51 {
52 // Make sure we don't take an already tagged value.
53 assert(((uintptr_t)obj & Py_TAG_DEFERRED) == 0);
54 assert(obj != NULL);
55 if (_PyObject_HasDeferredRefcount(obj)) {
56 return (_PyStackRef){ .bits = (uintptr_t)obj | Py_TAG_DEFERRED };
57 }
58 else {
59 return (_PyStackRef){ .bits = (uintptr_t)Py_NewRef(obj) };
60 }
61 }
62 # define PyStackRef_NewRefDeferred(obj) _PyStackRef_NewRefDeferred(_PyObject_CAST(obj))
63 #else
64 # define PyStackRef_NewRefDeferred(obj) PyStackRef_NewRef(((_PyStackRef){.bits = ((uintptr_t)(obj))}))
65 #endif
66
67 #if defined(Py_GIL_DISABLED)
68 static inline _PyStackRef
_PyStackRef_XNewRefDeferred(PyObject * obj)69 _PyStackRef_XNewRefDeferred(PyObject *obj)
70 {
71 // Make sure we don't take an already tagged value.
72 assert(((uintptr_t)obj & Py_TAG_DEFERRED) == 0);
73 if (obj == NULL) {
74 return Py_STACKREF_NULL;
75 }
76 return _PyStackRef_NewRefDeferred(obj);
77 }
78 # define PyStackRef_XNewRefDeferred(obj) _PyStackRef_XNewRefDeferred(_PyObject_CAST(obj))
79 #else
80 # define PyStackRef_XNewRefDeferred(obj) PyStackRef_XNewRef(((_PyStackRef){.bits = ((uintptr_t)(obj))}))
81 #endif
82
83 // Converts a PyStackRef back to a PyObject *.
84 #if defined(Py_GIL_DISABLED)
85 static inline PyObject *
PyStackRef_StealObject(_PyStackRef tagged)86 PyStackRef_StealObject(_PyStackRef tagged)
87 {
88 if ((tagged.bits & Py_TAG_DEFERRED) == Py_TAG_DEFERRED) {
89 assert(_PyObject_HasDeferredRefcount(PyStackRef_Get(tagged)));
90 return Py_NewRef(PyStackRef_Get(tagged));
91 }
92 return PyStackRef_Get(tagged);
93 }
94 #else
95 # define PyStackRef_StealObject(tagged) PyStackRef_Get(tagged)
96 #endif
97
98 static inline void
_Py_untag_stack_borrowed(PyObject ** dst,const _PyStackRef * src,size_t length)99 _Py_untag_stack_borrowed(PyObject **dst, const _PyStackRef *src, size_t length)
100 {
101 for (size_t i = 0; i < length; i++) {
102 dst[i] = PyStackRef_Get(src[i]);
103 }
104 }
105
106 static inline void
_Py_untag_stack_steal(PyObject ** dst,const _PyStackRef * src,size_t length)107 _Py_untag_stack_steal(PyObject **dst, const _PyStackRef *src, size_t length)
108 {
109 for (size_t i = 0; i < length; i++) {
110 dst[i] = PyStackRef_StealObject(src[i]);
111 }
112 }
113
114
115 #define PyStackRef_XSETREF(dst, src) \
116 do { \
117 _PyStackRef *_tmp_dst_ptr = &(dst); \
118 _PyStackRef _tmp_old_dst = (*_tmp_dst_ptr); \
119 *_tmp_dst_ptr = (src); \
120 PyStackRef_XDECREF(_tmp_old_dst); \
121 } while (0)
122
123 #define PyStackRef_SETREF(dst, src) \
124 do { \
125 _PyStackRef *_tmp_dst_ptr = &(dst); \
126 _PyStackRef _tmp_old_dst = (*_tmp_dst_ptr); \
127 *_tmp_dst_ptr = (src); \
128 PyStackRef_DECREF(_tmp_old_dst); \
129 } while (0)
130
131 #define PyStackRef_CLEAR(op) \
132 do { \
133 _PyStackRef *_tmp_op_ptr = &(op); \
134 _PyStackRef _tmp_old_op = (*_tmp_op_ptr); \
135 if (_tmp_old_op.bits != Py_STACKREF_NULL.bits) { \
136 *_tmp_op_ptr = Py_STACKREF_NULL; \
137 PyStackRef_DECREF(_tmp_old_op); \
138 } \
139 } while (0)
140
141 #if defined(Py_GIL_DISABLED)
142 static inline void
PyStackRef_DECREF(_PyStackRef tagged)143 PyStackRef_DECREF(_PyStackRef tagged)
144 {
145 if ((tagged.bits & Py_TAG_DEFERRED) == Py_TAG_DEFERRED) {
146 return;
147 }
148 Py_DECREF(PyStackRef_Get(tagged));
149 }
150 #else
151 # define PyStackRef_DECREF(op) Py_DECREF(PyStackRef_Get(op))
152 #endif
153
154 #if defined(Py_GIL_DISABLED)
155 static inline void
PyStackRef_INCREF(_PyStackRef tagged)156 PyStackRef_INCREF(_PyStackRef tagged)
157 {
158 if ((tagged.bits & Py_TAG_DEFERRED) == Py_TAG_DEFERRED) {
159 assert(_PyObject_HasDeferredRefcount(PyStackRef_Get(tagged)));
160 return;
161 }
162 Py_INCREF(PyStackRef_Get(tagged));
163 }
164 #else
165 # define PyStackRef_INCREF(op) Py_INCREF(PyStackRef_Get(op))
166 #endif
167
168 static inline void
PyStackRef_XDECREF(_PyStackRef op)169 PyStackRef_XDECREF(_PyStackRef op)
170 {
171 if (op.bits != Py_STACKREF_NULL.bits) {
172 PyStackRef_DECREF(op);
173 }
174 }
175
176 static inline _PyStackRef
PyStackRef_NewRef(_PyStackRef obj)177 PyStackRef_NewRef(_PyStackRef obj)
178 {
179 PyStackRef_INCREF(obj);
180 return obj;
181 }
182
183 static inline _PyStackRef
PyStackRef_XNewRef(_PyStackRef obj)184 PyStackRef_XNewRef(_PyStackRef obj)
185 {
186 if (obj.bits == Py_STACKREF_NULL.bits) {
187 return obj;
188 }
189 return PyStackRef_NewRef(obj);
190 }
191
192 #ifdef __cplusplus
193 }
194 #endif
195 #endif /* !Py_INTERNAL_STACKREF_H */
196