@@ -50,27 +50,58 @@ extern "C" {
5050 CPython refcounting operations on it!
5151*/
5252
53+ #define Py_INT_TAG 3
54+ #define Py_TAG_INVALID 2
55+ #define Py_TAG_REFCNT 1
56+ #define Py_TAG_BITS 3
5357
54- #if !defined( Py_GIL_DISABLED ) && defined( Py_STACKREF_DEBUG )
58+ #define Py_TAGGED_SHIFT 2
5559
56- #define Py_TAG_BITS 0
60+ #if !defined( Py_GIL_DISABLED ) && defined( Py_STACKREF_DEBUG )
5761
5862PyAPI_FUNC (PyObject * ) _Py_stackref_get_object (_PyStackRef ref );
5963PyAPI_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 );
64+ PyAPI_FUNC (_PyStackRef ) _Py_stackref_create (PyObject * obj , uint16_t flags , const char * filename , int linenumber );
6165PyAPI_FUNC (void ) _Py_stackref_record_borrow (_PyStackRef ref , const char * filename , int linenumber );
6266extern void _Py_stackref_associate (PyInterpreterState * interp , PyObject * obj , _PyStackRef ref );
6367
6468static const _PyStackRef PyStackRef_NULL = { .index = 0 };
65- static const _PyStackRef PyStackRef_ERROR = { .index = 2 };
69+ static const _PyStackRef PyStackRef_ERROR = { .index = ( 1 << Py_TAGGED_SHIFT ) };
6670
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 })
71+ #define PyStackRef_None ((_PyStackRef){ .index = (2 << Py_TAGGED_SHIFT) } )
72+ #define PyStackRef_False ((_PyStackRef){ .index = (3 << Py_TAGGED_SHIFT) })
73+ #define PyStackRef_True ((_PyStackRef){ .index = (4 << Py_TAGGED_SHIFT) })
74+
75+ #define INITIAL_STACKREF_INDEX (5 << Py_TAGGED_SHIFT)
76+
77+ static inline _PyStackRef
78+ PyStackRef_Wrap (void * ptr )
79+ {
80+ assert (ptr != NULL );
81+ #ifdef Py_DEBUG
82+ assert (((uint64_t )ptr & Py_TAG_BITS ) == 0 );
83+ return (_PyStackRef ){ .index = ((uint64_t )ptr ) | Py_TAG_INVALID };
84+ #else
85+ return (_PyStackRef ){ .index = (uint64_t )ptr };
86+ #endif
87+ }
88+
89+ static inline void *
90+ PyStackRef_Unwrap (_PyStackRef ref )
91+ {
92+ #ifdef Py_DEBUG
93+ assert ((ref .index & Py_TAG_BITS ) == Py_TAG_INVALID );
94+ return (void * )(ref .index & ~Py_TAG_BITS );
95+ #else
96+ return (void * )(ref .index );
97+ #endif
98+ }
7299
73- #define INITIAL_STACKREF_INDEX 10
100+ static inline int
101+ PyStackRef_RefcountOnObject (_PyStackRef ref )
102+ {
103+ return (ref .index & Py_TAG_REFCNT ) == 0 ;
104+ }
74105
75106static inline int
76107PyStackRef_IsNull (_PyStackRef ref )
@@ -81,7 +112,13 @@ PyStackRef_IsNull(_PyStackRef ref)
81112static inline bool
82113PyStackRef_IsError (_PyStackRef ref )
83114{
84- return ref .index == 2 ;
115+ return ref .index == (1 << Py_TAGGED_SHIFT );
116+ }
117+
118+ static inline bool
119+ PyStackRef_IsMalformed (_PyStackRef ref )
120+ {
121+ return (ref .index & Py_TAG_BITS ) == Py_TAG_INVALID ;
85122}
86123
87124static inline bool
@@ -112,7 +149,7 @@ PyStackRef_IsNone(_PyStackRef ref)
112149static inline bool
113150PyStackRef_IsTaggedInt (_PyStackRef ref )
114151{
115- return (ref .index & 1 ) == 1 ;
152+ return (ref .index & Py_TAG_BITS ) == Py_INT_TAG ;
116153}
117154
118155static inline PyObject *
@@ -123,50 +160,68 @@ _PyStackRef_AsPyObjectBorrow(_PyStackRef ref, const char *filename, int linenumb
123160 _Py_stackref_record_borrow (ref , filename , linenumber );
124161 return _Py_stackref_get_object (ref );
125162}
126-
127163#define PyStackRef_AsPyObjectBorrow (REF ) _PyStackRef_AsPyObjectBorrow((REF), __FILE__, __LINE__)
128164
129165static inline PyObject *
130166_PyStackRef_AsPyObjectSteal (_PyStackRef ref , const char * filename , int linenumber )
131167{
132- return _Py_stackref_close (ref , filename , linenumber );
168+ PyObject * obj = _Py_stackref_close (ref , filename , linenumber );
169+ if (PyStackRef_RefcountOnObject (ref )) {
170+ return obj ;
171+ }
172+ return Py_NewRef (obj );
133173}
134174#define PyStackRef_AsPyObjectSteal (REF ) _PyStackRef_AsPyObjectSteal((REF), __FILE__, __LINE__)
135175
136176static inline _PyStackRef
137177_PyStackRef_FromPyObjectNew (PyObject * obj , const char * filename , int linenumber )
138178{
139- Py_INCREF (obj );
140- return _Py_stackref_create (obj , filename , linenumber );
179+ assert (obj != NULL );
180+ uint16_t flags = 0 ;
181+ if (!_Py_IsImmortal (obj )) {
182+ _Py_INCREF_MORTAL (obj );
183+ } else {
184+ flags = Py_TAG_REFCNT ;
185+ }
186+ return _Py_stackref_create (obj , flags , filename , linenumber );
141187}
142188#define PyStackRef_FromPyObjectNew (obj ) _PyStackRef_FromPyObjectNew(_PyObject_CAST(obj), __FILE__, __LINE__)
143189
144190static inline _PyStackRef
145191_PyStackRef_FromPyObjectSteal (PyObject * obj , const char * filename , int linenumber )
146192{
147- return _Py_stackref_create (obj , filename , linenumber );
193+ assert (obj != NULL );
194+ uint16_t flags = 0 ;
195+ if (_Py_IsImmortal (obj )) {
196+ flags = Py_TAG_REFCNT ;
197+ }
198+ return _Py_stackref_create (obj , flags , filename , linenumber );
148199}
149200#define PyStackRef_FromPyObjectSteal (obj ) _PyStackRef_FromPyObjectSteal(_PyObject_CAST(obj), __FILE__, __LINE__)
150201
151202static inline _PyStackRef
152203_PyStackRef_FromPyObjectBorrow (PyObject * obj , const char * filename , int linenumber )
153204{
154- return _Py_stackref_create (obj , filename , linenumber );
205+ return _Py_stackref_create (obj , Py_TAG_REFCNT , filename , linenumber );
155206}
156207#define PyStackRef_FromPyObjectBorrow (obj ) _PyStackRef_FromPyObjectBorrow(_PyObject_CAST(obj), __FILE__, __LINE__)
157208
158209static inline void
159210_PyStackRef_CLOSE (_PyStackRef ref , const char * filename , int linenumber )
160211{
212+ assert (!PyStackRef_IsError (ref ));
213+ assert (!PyStackRef_IsNull (ref ));
161214 if (PyStackRef_IsTaggedInt (ref )) {
162215 return ;
163216 }
164217 PyObject * obj = _Py_stackref_close (ref , filename , linenumber );
165- Py_DECREF (obj );
218+ assert (Py_REFCNT (obj ) > 0 );
219+ if (PyStackRef_RefcountOnObject (ref )) {
220+ Py_DECREF (obj );
221+ }
166222}
167223#define PyStackRef_CLOSE (REF ) _PyStackRef_CLOSE((REF), __FILE__, __LINE__)
168224
169-
170225static inline void
171226_PyStackRef_XCLOSE (_PyStackRef ref , const char * filename , int linenumber )
172227{
@@ -182,31 +237,46 @@ static inline _PyStackRef
182237_PyStackRef_DUP (_PyStackRef ref , const char * filename , int linenumber )
183238{
184239 assert (!PyStackRef_IsError (ref ));
240+ assert (!PyStackRef_IsNull (ref ));
185241 if (PyStackRef_IsTaggedInt (ref )) {
186242 return ref ;
187243 }
188- else {
189- PyObject * obj = _Py_stackref_get_object (ref );
244+ PyObject * obj = _Py_stackref_get_object (ref );
245+ uint16_t flags = 0 ;
246+ if (PyStackRef_RefcountOnObject (ref )) {
190247 Py_INCREF (obj );
191- return _Py_stackref_create (obj , filename , linenumber );
248+ } else {
249+ flags = Py_TAG_REFCNT ;
192250 }
251+ return _Py_stackref_create (obj , flags , filename , linenumber );
193252}
194253#define PyStackRef_DUP (REF ) _PyStackRef_DUP(REF, __FILE__, __LINE__)
195254
196- extern void _PyStackRef_CLOSE_SPECIALIZED (_PyStackRef ref , destructor destruct , const char * filename , int linenumber );
197- #define PyStackRef_CLOSE_SPECIALIZED (REF , DESTRUCT ) _PyStackRef_CLOSE_SPECIALIZED(REF, DESTRUCT, __FILE__, __LINE__)
198-
199- static inline _PyStackRef
200- PyStackRef_MakeHeapSafe (_PyStackRef ref )
255+ static inline void
256+ _PyStackRef_CLOSE_SPECIALIZED (_PyStackRef ref , destructor destruct , const char * filename , int linenumber )
201257{
202- return ref ;
258+ assert (!PyStackRef_IsError (ref ));
259+ assert (!PyStackRef_IsNull (ref ));
260+ assert (!PyStackRef_IsTaggedInt (ref ));
261+ PyObject * obj = _Py_stackref_close (ref , filename , linenumber );
262+ if (PyStackRef_RefcountOnObject (ref )) {
263+ _Py_DECREF_SPECIALIZED (obj , destruct );
264+ }
203265}
266+ #define PyStackRef_CLOSE_SPECIALIZED (REF , DESTRUCT ) _PyStackRef_CLOSE_SPECIALIZED(REF, DESTRUCT, __FILE__, __LINE__)
204267
205268static inline _PyStackRef
206- PyStackRef_Borrow (_PyStackRef ref )
269+ _PyStackRef_Borrow (_PyStackRef ref , const char * filename , int linenumber )
207270{
208- return PyStackRef_DUP (ref );
271+ assert (!PyStackRef_IsError (ref ));
272+ assert (!PyStackRef_IsNull (ref ));
273+ if (PyStackRef_IsTaggedInt (ref )) {
274+ return ref ;
275+ }
276+ PyObject * obj = _Py_stackref_get_object (ref );
277+ return _Py_stackref_create (obj , Py_TAG_REFCNT , filename , linenumber );
209278}
279+ #define PyStackRef_Borrow (REF ) _PyStackRef_Borrow((REF), __FILE__, __LINE__)
210280
211281#define PyStackRef_CLEAR (REF ) \
212282 do { \
@@ -219,28 +289,47 @@ PyStackRef_Borrow(_PyStackRef ref)
219289static inline _PyStackRef
220290_PyStackRef_FromPyObjectStealMortal (PyObject * obj , const char * filename , int linenumber )
221291{
292+ assert (obj != NULL );
222293 assert (!_Py_IsImmortal (obj ));
223- return _Py_stackref_create (obj , filename , linenumber );
294+ return _Py_stackref_create (obj , 0 , filename , linenumber );
224295}
225296#define PyStackRef_FromPyObjectStealMortal (obj ) _PyStackRef_FromPyObjectStealMortal(_PyObject_CAST(obj), __FILE__, __LINE__)
226297
227298static inline bool
228299PyStackRef_IsHeapSafe (_PyStackRef ref )
229300{
230- return true;
301+ if ((ref .index & Py_TAG_BITS ) != Py_TAG_REFCNT || PyStackRef_IsNull (ref )) {
302+ // Tagged ints and ERROR are included.
303+ return true;
304+ }
305+
306+ PyObject * obj = _Py_stackref_get_object (ref );
307+ return _Py_IsImmortal (obj );
231308}
232309
310+ static inline _PyStackRef
311+ _PyStackRef_MakeHeapSafe (_PyStackRef ref , const char * filename , int linenumber )
312+ {
313+ if (PyStackRef_IsHeapSafe (ref )) {
314+ return ref ;
315+ }
316+
317+ PyObject * obj = _Py_stackref_close (ref , filename , linenumber );
318+ Py_INCREF (obj );
319+ return _Py_stackref_create (obj , 0 , filename , linenumber );
320+ }
321+ #define PyStackRef_MakeHeapSafe (REF ) _PyStackRef_MakeHeapSafe(REF, __FILE__, __LINE__)
322+
233323static inline _PyStackRef
234324_PyStackRef_FromPyObjectNewMortal (PyObject * obj , const char * filename , int linenumber )
235325{
326+ assert (obj != NULL );
236327 assert (!_Py_IsStaticImmortal (obj ));
237328 Py_INCREF (obj );
238- return _Py_stackref_create (obj , filename , linenumber );
329+ return _Py_stackref_create (obj , 0 , filename , linenumber );
239330}
240331#define PyStackRef_FromPyObjectNewMortal (obj ) _PyStackRef_FromPyObjectNewMortal(_PyObject_CAST(obj), __FILE__, __LINE__)
241332
242- #define PyStackRef_RefcountOnObject (REF ) 1
243-
244333extern int PyStackRef_Is (_PyStackRef a , _PyStackRef b );
245334
246335extern bool PyStackRef_IsTaggedInt (_PyStackRef ref );
@@ -257,11 +346,6 @@ PyStackRef_IsNullOrInt(_PyStackRef ref);
257346
258347#else
259348
260- #define Py_INT_TAG 3
261- #define Py_TAG_INVALID 2
262- #define Py_TAG_REFCNT 1
263- #define Py_TAG_BITS 3
264-
265349static const _PyStackRef PyStackRef_ERROR = { .bits = Py_TAG_INVALID };
266350
267351/* Wrap a pointer in a stack ref.
@@ -273,6 +357,7 @@ PyStackRef_Wrap(void *ptr)
273357{
274358 assert (ptr != NULL );
275359#ifdef Py_DEBUG
360+ assert (((uintptr_t )ptr & Py_TAG_BITS ) == 0 );
276361 return (_PyStackRef ){ .bits = ((uintptr_t )ptr ) | Py_TAG_INVALID };
277362#else
278363 return (_PyStackRef ){ .bits = (uintptr_t )ptr };
@@ -318,25 +403,25 @@ PyStackRef_IsTaggedInt(_PyStackRef i)
318403static inline _PyStackRef
319404PyStackRef_TagInt (intptr_t i )
320405{
321- assert (Py_ARITHMETIC_RIGHT_SHIFT (intptr_t , (i << 2 ), 2 ) == i );
322- return (_PyStackRef ){ .bits = ((((uintptr_t )i ) << 2 ) | Py_INT_TAG ) };
406+ assert (Py_ARITHMETIC_RIGHT_SHIFT (intptr_t , (i << Py_TAGGED_SHIFT ), Py_TAGGED_SHIFT ) == i );
407+ return (_PyStackRef ){ .bits = ((((uintptr_t )i ) << Py_TAGGED_SHIFT ) | Py_INT_TAG ) };
323408}
324409
325410static inline intptr_t
326411PyStackRef_UntagInt (_PyStackRef i )
327412{
328413 assert (PyStackRef_IsTaggedInt (i ));
329414 intptr_t val = (intptr_t )i .bits ;
330- return Py_ARITHMETIC_RIGHT_SHIFT (intptr_t , val , 2 );
415+ return Py_ARITHMETIC_RIGHT_SHIFT (intptr_t , val , Py_TAGGED_SHIFT );
331416}
332417
333418
334419static inline _PyStackRef
335420PyStackRef_IncrementTaggedIntNoOverflow (_PyStackRef ref )
336421{
337422 assert ((ref .bits & Py_TAG_BITS ) == Py_INT_TAG ); // Is tagged int
338- assert ((ref .bits & (~Py_TAG_BITS )) != (INT_MAX & (~Py_TAG_BITS ))); // Isn't about to overflow
339- return (_PyStackRef ){ .bits = ref .bits + 4 };
423+ assert ((ref .bits & (~Py_TAG_BITS )) != (INTPTR_MAX & (~Py_TAG_BITS ))); // Isn't about to overflow
424+ return (_PyStackRef ){ .bits = ref .bits + ( 1 << Py_TAGGED_SHIFT ) };
340425}
341426
342427#define PyStackRef_IsDeferredOrTaggedInt (ref ) (((ref).bits & Py_TAG_REFCNT) != 0)
0 commit comments