• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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