@@ -63,11 +63,13 @@ extern void _Py_stackref_associate(PyInterpreterState *interp, PyObject *obj, _P
6363
6464static const _PyStackRef PyStackRef_NULL = { .index = 0 };
6565
66- #define PyStackRef_None ((_PyStackRef){ .index = 1 } )
67- #define PyStackRef_False ((_PyStackRef){ .index = 2 })
68- #define PyStackRef_True ((_PyStackRef){ .index = 3 })
66+ // Use the first 3 even numbers for None, True and False.
67+ // Odd numbers are reserved for (tagged) integers
68+ #define PyStackRef_None ((_PyStackRef){ .index = 2 } )
69+ #define PyStackRef_False ((_PyStackRef){ .index = 4 })
70+ #define PyStackRef_True ((_PyStackRef){ .index = 6 })
6971
70- #define LAST_PREDEFINED_STACKREF_INDEX 3
72+ #define INITIAL_STACKREF_INDEX 8
7173
7274static inline int
7375PyStackRef_IsNull (_PyStackRef ref )
@@ -96,6 +98,7 @@ PyStackRef_IsNone(_PyStackRef ref)
9698static inline PyObject *
9799_PyStackRef_AsPyObjectBorrow (_PyStackRef ref , const char * filename , int linenumber )
98100{
101+ assert ((ref .index & 1 ) == 0 );
99102 _Py_stackref_record_borrow (ref , filename , linenumber );
100103 return _Py_stackref_get_object (ref );
101104}
@@ -132,31 +135,45 @@ _PyStackRef_FromPyObjectImmortal(PyObject *obj, const char *filename, int linenu
132135}
133136#define PyStackRef_FromPyObjectImmortal (obj ) _PyStackRef_FromPyObjectImmortal(_PyObject_CAST(obj), __FILE__, __LINE__)
134137
138+ static inline bool
139+ PyStackRef_IsTaggedInt (_PyStackRef ref )
140+ {
141+ return (ref .index & 1 ) == 1 ;
142+ }
143+
135144static inline void
136145_PyStackRef_CLOSE (_PyStackRef ref , const char * filename , int linenumber )
137146{
147+ if (PyStackRef_IsTaggedInt (ref )) {
148+ return ;
149+ }
138150 PyObject * obj = _Py_stackref_close (ref , filename , linenumber );
139151 Py_DECREF (obj );
140152}
141153#define PyStackRef_CLOSE (REF ) _PyStackRef_CLOSE((REF), __FILE__, __LINE__)
142154
155+
143156static inline void
144157_PyStackRef_XCLOSE (_PyStackRef ref , const char * filename , int linenumber )
145158{
146159 if (PyStackRef_IsNull (ref )) {
147160 return ;
148161 }
149- PyObject * obj = _Py_stackref_close (ref , filename , linenumber );
150- Py_DECREF (obj );
162+ _PyStackRef_CLOSE (ref , filename , linenumber );
151163}
152164#define PyStackRef_XCLOSE (REF ) _PyStackRef_XCLOSE((REF), __FILE__, __LINE__)
153165
154166static inline _PyStackRef
155167_PyStackRef_DUP (_PyStackRef ref , const char * filename , int linenumber )
156168{
157- PyObject * obj = _Py_stackref_get_object (ref );
158- Py_INCREF (obj );
159- return _Py_stackref_create (obj , filename , linenumber );
169+ if (PyStackRef_IsTaggedInt (ref )) {
170+ return ref ;
171+ }
172+ else {
173+ PyObject * obj = _Py_stackref_get_object (ref );
174+ Py_INCREF (obj );
175+ return _Py_stackref_create (obj , filename , linenumber );
176+ }
160177}
161178#define PyStackRef_DUP (REF ) _PyStackRef_DUP(REF, __FILE__, __LINE__)
162179
@@ -210,8 +227,40 @@ _PyStackRef_FromPyObjectNewMortal(PyObject *obj, const char *filename, int linen
210227
211228extern int PyStackRef_Is (_PyStackRef a , _PyStackRef b );
212229
230+ extern bool PyStackRef_IsTaggedInt (_PyStackRef ref );
231+
232+ extern intptr_t PyStackRef_UntagInt (_PyStackRef ref );
233+
234+ extern _PyStackRef PyStackRef_TagInt (intptr_t i );
235+
236+ extern bool
237+ PyStackRef_IsNullOrInt (_PyStackRef ref );
238+
213239#else
214240
241+ #define Py_INT_TAG 3
242+
243+ static inline bool
244+ PyStackRef_IsTaggedInt (_PyStackRef i )
245+ {
246+ return (i .bits & Py_INT_TAG ) == Py_INT_TAG ;
247+ }
248+
249+ static inline _PyStackRef
250+ PyStackRef_TagInt (intptr_t i )
251+ {
252+ assert (Py_ARITHMETIC_RIGHT_SHIFT (intptr_t , (i << 2 ), 2 ) == i );
253+ return (_PyStackRef ){ .bits = ((((uintptr_t )i ) << 2 ) | Py_INT_TAG ) };
254+ }
255+
256+ static inline intptr_t
257+ PyStackRef_UntagInt (_PyStackRef i )
258+ {
259+ assert ((i .bits & Py_INT_TAG ) == Py_INT_TAG );
260+ intptr_t val = (intptr_t )i .bits ;
261+ return Py_ARITHMETIC_RIGHT_SHIFT (intptr_t , val , 2 );
262+ }
263+
215264
216265#ifdef Py_GIL_DISABLED
217266
@@ -232,6 +281,8 @@ static const _PyStackRef PyStackRef_NULL = { .bits = Py_TAG_DEFERRED};
232281#define PyStackRef_IsTrue (ref ) (PyStackRef_AsPyObjectBorrow(ref) == Py_True)
233282#define PyStackRef_IsFalse (ref ) (PyStackRef_AsPyObjectBorrow(ref) == Py_False)
234283
284+ #define PyStackRef_IsNullOrInt (stackref ) (PyStackRef_IsNull(stackref) || PyStackRef_IsTaggedInt(stackref))
285+
235286static inline PyObject *
236287PyStackRef_AsPyObjectBorrow (_PyStackRef stackref )
237288{
@@ -451,6 +502,7 @@ PyStackRef_RefcountOnObject(_PyStackRef ref)
451502static inline PyObject *
452503PyStackRef_AsPyObjectBorrow (_PyStackRef ref )
453504{
505+ assert (!PyStackRef_IsTaggedInt (ref ));
454506 return BITS_TO_PTR_MASKED (ref );
455507}
456508
@@ -587,6 +639,12 @@ PyStackRef_CLOSE(_PyStackRef ref)
587639}
588640#endif
589641
642+ static inline bool
643+ PyStackRef_IsNullOrInt (_PyStackRef ref )
644+ {
645+ return PyStackRef_IsNull (ref ) || PyStackRef_IsTaggedInt (ref );
646+ }
647+
590648static inline void
591649PyStackRef_CLOSE_SPECIALIZED (_PyStackRef ref , destructor destruct )
592650{
@@ -726,7 +784,7 @@ _Py_TryXGetStackRef(PyObject **src, _PyStackRef *out)
726784// Like Py_VISIT but for _PyStackRef fields
727785#define _Py_VISIT_STACKREF (ref ) \
728786 do { \
729- if (!PyStackRef_IsNull (ref)) { \
787+ if (!PyStackRef_IsNullOrInt (ref)) { \
730788 int vret = _PyGC_VisitStackRef(&(ref), visit, arg); \
731789 if (vret) \
732790 return vret; \
0 commit comments