@@ -53,36 +53,53 @@ extern "C" {
5353
5454#if !defined(Py_GIL_DISABLED ) && defined(Py_STACKREF_DEBUG )
5555
56- #define Py_TAG_BITS 0
56+ #define Py_INT_TAG 3
57+ #define Py_TAG_INVALID 2
58+ #define Py_TAG_REFCNT 1
59+ #define Py_TAG_BITS 3
5760
5861PyAPI_FUNC (PyObject * ) _Py_stackref_get_object (_PyStackRef ref );
5962PyAPI_FUNC (PyObject * ) _Py_stackref_close (_PyStackRef ref , const char * filename , int linenumber );
60- PyAPI_FUNC (_PyStackRef ) _Py_stackref_create (PyObject * obj , const char * filename , int linenumber );
63+ PyAPI_FUNC (_PyStackRef ) _Py_stackref_create (PyObject * obj , uint16_t flags , const char * filename , int linenumber );
6164PyAPI_FUNC (void ) _Py_stackref_record_borrow (_PyStackRef ref , const char * filename , int linenumber );
6265extern void _Py_stackref_associate (PyInterpreterState * interp , PyObject * obj , _PyStackRef ref );
6366
6467static const _PyStackRef PyStackRef_NULL = { .index = 0 };
65- static const _PyStackRef PyStackRef_ERROR = { .index = 2 };
68+ static const _PyStackRef PyStackRef_ERROR = { .index = 4 };
6669
67- // Use the first 3 even numbers for None, True and False.
68- // Odd numbers are reserved for (tagged) integers
69- #define PyStackRef_None ((_PyStackRef){ .index = 4 } )
70- #define PyStackRef_False ((_PyStackRef){ .index = 6 })
71- #define PyStackRef_True ((_PyStackRef){ .index = 8 })
70+ #define PyStackRef_None ((_PyStackRef){ .index = 8 } )
71+ #define PyStackRef_False ((_PyStackRef){ .index = 12 })
72+ #define PyStackRef_True ((_PyStackRef){ .index = 16 })
7273
73- #define INITIAL_STACKREF_INDEX 10
74+ #define INITIAL_STACKREF_INDEX 20
7475
7576static inline _PyStackRef
7677PyStackRef_Wrap (void * ptr )
7778{
7879 assert (ptr != NULL );
80+ #ifdef Py_DEBUG
81+ assert (((uint64_t )ptr & Py_TAG_BITS ) == 0 );
82+ return (_PyStackRef ){ .index = ((uint64_t )ptr ) | Py_TAG_INVALID };
83+ #else
7984 return (_PyStackRef ){ .index = (uint64_t )ptr };
85+ #endif
8086}
8187
8288static inline void *
8389PyStackRef_Unwrap (_PyStackRef ref )
8490{
91+ #ifdef Py_DEBUG
92+ assert ((ref .index & Py_TAG_BITS ) == Py_TAG_INVALID );
93+ return (void * )(ref .index & ~Py_TAG_BITS );
94+ #else
8595 return (void * )(ref .index );
96+ #endif
97+ }
98+
99+ static inline int
100+ PyStackRef_RefcountOnObject (_PyStackRef ref )
101+ {
102+ return (ref .index & Py_TAG_REFCNT ) == 0 ;
86103}
87104
88105static inline int
@@ -94,7 +111,7 @@ PyStackRef_IsNull(_PyStackRef ref)
94111static inline bool
95112PyStackRef_IsError (_PyStackRef ref )
96113{
97- return ref .index == 2 ;
114+ return ref .index == 4 ;
98115}
99116
100117static inline bool
@@ -125,7 +142,7 @@ PyStackRef_IsNone(_PyStackRef ref)
125142static inline bool
126143PyStackRef_IsTaggedInt (_PyStackRef ref )
127144{
128- return (ref .index & 1 ) == 1 ;
145+ return (ref .index & Py_TAG_BITS ) == Py_INT_TAG ;
129146}
130147
131148static inline PyObject *
@@ -136,51 +153,68 @@ _PyStackRef_AsPyObjectBorrow(_PyStackRef ref, const char *filename, int linenumb
136153 _Py_stackref_record_borrow (ref , filename , linenumber );
137154 return _Py_stackref_get_object (ref );
138155}
139-
140156#define PyStackRef_AsPyObjectBorrow (REF ) _PyStackRef_AsPyObjectBorrow((REF), __FILE__, __LINE__)
141157
142158static inline PyObject *
143159_PyStackRef_AsPyObjectSteal (_PyStackRef ref , const char * filename , int linenumber )
144160{
145- return _Py_stackref_close (ref , filename , linenumber );
161+ PyObject * obj = _Py_stackref_close (ref , filename , linenumber );
162+ if (PyStackRef_RefcountOnObject (ref )) {
163+ return obj ;
164+ }
165+ return Py_NewRef (obj );
146166}
147167#define PyStackRef_AsPyObjectSteal (REF ) _PyStackRef_AsPyObjectSteal((REF), __FILE__, __LINE__)
148168
149169static inline _PyStackRef
150170_PyStackRef_FromPyObjectNew (PyObject * obj , const char * filename , int linenumber )
151171{
152- Py_INCREF (obj );
153- return _Py_stackref_create (obj , filename , linenumber );
172+ assert (obj != NULL );
173+ uint16_t flags = 0 ;
174+ if (!_Py_IsImmortal (obj )) {
175+ _Py_INCREF_MORTAL (obj );
176+ } else {
177+ flags = Py_TAG_REFCNT ;
178+ }
179+ return _Py_stackref_create (obj , flags , filename , linenumber );
154180}
155181#define PyStackRef_FromPyObjectNew (obj ) _PyStackRef_FromPyObjectNew(_PyObject_CAST(obj), __FILE__, __LINE__)
156182
157183static inline _PyStackRef
158184_PyStackRef_FromPyObjectSteal (PyObject * obj , const char * filename , int linenumber )
159185{
160- return _Py_stackref_create (obj , filename , linenumber );
186+ assert (obj != NULL );
187+ uint16_t flags = 0 ;
188+ if (_Py_IsImmortal (obj )) {
189+ flags = Py_TAG_REFCNT ;
190+ }
191+ return _Py_stackref_create (obj , flags , filename , linenumber );
161192}
162193#define PyStackRef_FromPyObjectSteal (obj ) _PyStackRef_FromPyObjectSteal(_PyObject_CAST(obj), __FILE__, __LINE__)
163194
164195static inline _PyStackRef
165196_PyStackRef_FromPyObjectBorrow (PyObject * obj , const char * filename , int linenumber )
166197{
167- Py_INCREF (obj );
168- return _Py_stackref_create (obj , filename , linenumber );
198+ return _Py_stackref_create (obj , Py_TAG_REFCNT , filename , linenumber );
169199}
170200#define PyStackRef_FromPyObjectBorrow (obj ) _PyStackRef_FromPyObjectBorrow(_PyObject_CAST(obj), __FILE__, __LINE__)
171201
172202static inline void
173203_PyStackRef_CLOSE (_PyStackRef ref , const char * filename , int linenumber )
174204{
205+ assert (!PyStackRef_IsError (ref ));
206+ assert (!PyStackRef_IsNull (ref ));
175207 if (PyStackRef_IsTaggedInt (ref )) {
176208 return ;
177209 }
178210 PyObject * obj = _Py_stackref_close (ref , filename , linenumber );
179- Py_DECREF (obj );
211+ assert (Py_REFCNT (obj ) > 0 );
212+ if (PyStackRef_RefcountOnObject (ref )) {
213+ Py_DECREF (obj );
214+ }
180215}
181216#define PyStackRef_CLOSE (REF ) _PyStackRef_CLOSE((REF), __FILE__, __LINE__)
182217
183-
184218static inline void
185219_PyStackRef_XCLOSE (_PyStackRef ref , const char * filename , int linenumber )
186220{
@@ -196,31 +230,46 @@ static inline _PyStackRef
196230_PyStackRef_DUP (_PyStackRef ref , const char * filename , int linenumber )
197231{
198232 assert (!PyStackRef_IsError (ref ));
233+ assert (!PyStackRef_IsNull (ref ));
199234 if (PyStackRef_IsTaggedInt (ref )) {
200235 return ref ;
201236 }
202- else {
203- PyObject * obj = _Py_stackref_get_object (ref );
237+ PyObject * obj = _Py_stackref_get_object (ref );
238+ uint16_t flags = 0 ;
239+ if (PyStackRef_RefcountOnObject (ref )) {
204240 Py_INCREF (obj );
205- return _Py_stackref_create (obj , filename , linenumber );
241+ } else {
242+ flags = Py_TAG_REFCNT ;
206243 }
244+ return _Py_stackref_create (obj , flags , filename , linenumber );
207245}
208246#define PyStackRef_DUP (REF ) _PyStackRef_DUP(REF, __FILE__, __LINE__)
209247
210- extern void _PyStackRef_CLOSE_SPECIALIZED (_PyStackRef ref , destructor destruct , const char * filename , int linenumber );
211- #define PyStackRef_CLOSE_SPECIALIZED (REF , DESTRUCT ) _PyStackRef_CLOSE_SPECIALIZED(REF, DESTRUCT, __FILE__, __LINE__)
212-
213- static inline _PyStackRef
214- PyStackRef_MakeHeapSafe (_PyStackRef ref )
248+ static inline void
249+ _PyStackRef_CLOSE_SPECIALIZED (_PyStackRef ref , destructor destruct , const char * filename , int linenumber )
215250{
216- return ref ;
251+ assert (!PyStackRef_IsError (ref ));
252+ assert (!PyStackRef_IsNull (ref ));
253+ assert (!PyStackRef_IsTaggedInt (ref ));
254+ PyObject * obj = _Py_stackref_close (ref , filename , linenumber );
255+ if (PyStackRef_RefcountOnObject (ref )) {
256+ _Py_DECREF_SPECIALIZED (obj , destruct );
257+ }
217258}
259+ #define PyStackRef_CLOSE_SPECIALIZED (REF , DESTRUCT ) _PyStackRef_CLOSE_SPECIALIZED(REF, DESTRUCT, __FILE__, __LINE__)
218260
219261static inline _PyStackRef
220- PyStackRef_Borrow (_PyStackRef ref )
262+ _PyStackRef_Borrow (_PyStackRef ref , const char * filename , int linenumber )
221263{
222- return PyStackRef_DUP (ref );
264+ assert (!PyStackRef_IsError (ref ));
265+ assert (!PyStackRef_IsNull (ref ));
266+ if (PyStackRef_IsTaggedInt (ref )) {
267+ return ref ;
268+ }
269+ PyObject * obj = _Py_stackref_get_object (ref );
270+ return _Py_stackref_create (obj , Py_TAG_REFCNT , filename , linenumber );
223271}
272+ #define PyStackRef_Borrow (REF ) _PyStackRef_Borrow((REF), __FILE__, __LINE__)
224273
225274#define PyStackRef_CLEAR (REF ) \
226275 do { \
@@ -234,27 +283,44 @@ static inline _PyStackRef
234283_PyStackRef_FromPyObjectStealMortal (PyObject * obj , const char * filename , int linenumber )
235284{
236285 assert (!_Py_IsImmortal (obj ));
237- return _Py_stackref_create (obj , filename , linenumber );
286+ return _Py_stackref_create (obj , 0 , filename , linenumber );
238287}
239288#define PyStackRef_FromPyObjectStealMortal (obj ) _PyStackRef_FromPyObjectStealMortal(_PyObject_CAST(obj), __FILE__, __LINE__)
240289
241290static inline bool
242291PyStackRef_IsHeapSafe (_PyStackRef ref )
243292{
244- return true;
293+ if ((ref .index & Py_TAG_BITS ) != Py_TAG_REFCNT || PyStackRef_IsNull (ref )) {
294+ // Tagged ints and ERROR are included.
295+ return true;
296+ }
297+
298+ PyObject * obj = _Py_stackref_get_object (ref );
299+ return _Py_IsImmortal (obj );
245300}
246301
302+ static inline _PyStackRef
303+ _PyStackRef_MakeHeapSafe (_PyStackRef ref , const char * filename , int linenumber )
304+ {
305+ if (PyStackRef_IsHeapSafe (ref )) {
306+ return ref ;
307+ }
308+
309+ PyObject * obj = _Py_stackref_close (ref , filename , linenumber );
310+ Py_INCREF (obj );
311+ return _Py_stackref_create (obj , 0 , filename , linenumber );
312+ }
313+ #define PyStackRef_MakeHeapSafe (REF ) _PyStackRef_MakeHeapSafe(REF, __FILE__, __LINE__)
314+
247315static inline _PyStackRef
248316_PyStackRef_FromPyObjectNewMortal (PyObject * obj , const char * filename , int linenumber )
249317{
250318 assert (!_Py_IsStaticImmortal (obj ));
251- Py_INCREF (obj );
252- return _Py_stackref_create (obj , filename , linenumber );
319+ Py_XINCREF (obj );
320+ return _Py_stackref_create (obj , 0 , filename , linenumber );
253321}
254322#define PyStackRef_FromPyObjectNewMortal (obj ) _PyStackRef_FromPyObjectNewMortal(_PyObject_CAST(obj), __FILE__, __LINE__)
255323
256- #define PyStackRef_RefcountOnObject (REF ) 1
257-
258324extern int PyStackRef_Is (_PyStackRef a , _PyStackRef b );
259325
260326extern bool PyStackRef_IsTaggedInt (_PyStackRef ref );
@@ -287,6 +353,7 @@ PyStackRef_Wrap(void *ptr)
287353{
288354 assert (ptr != NULL );
289355#ifdef Py_DEBUG
356+ assert (((uintptr_t )ptr & Py_TAG_BITS ) == 0 );
290357 return (_PyStackRef ){ .bits = ((uintptr_t )ptr ) | Py_TAG_INVALID };
291358#else
292359 return (_PyStackRef ){ .bits = (uintptr_t )ptr };
0 commit comments