@@ -54,16 +54,24 @@ PyAPI_FUNC(int) _PyObject_IsFreed(PyObject *);
5454 Furthermore, we can't use designated initializers in Extensions since these
5555 are not supported pre-C++20. Thus, keeping an internal copy here is the most
5656 backwards compatible solution */
57+ #if defined(Py_NOGIL )
58+ #define _PyObject_HEAD_INIT (type ) \
59+ { \
60+ .ob_ref_local = _Py_IMMORTAL_REFCNT_LOCAL, \
61+ .ob_type = (type) \
62+ }
63+ #else
5764#define _PyObject_HEAD_INIT (type ) \
5865 { \
5966 .ob_refcnt = _Py_IMMORTAL_REFCNT, \
6067 .ob_type = (type) \
61- },
68+ }
69+ #endif
6270#define _PyVarObject_HEAD_INIT (type , size ) \
6371 { \
64- .ob_base = _PyObject_HEAD_INIT(type) \
72+ .ob_base = _PyObject_HEAD_INIT(type), \
6573 .ob_size = size \
66- },
74+ }
6775
6876extern void _Py_NO_RETURN _Py_FatalRefcountErrorFunc (
6977 const char * func ,
@@ -95,24 +103,63 @@ static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n)
95103#ifdef Py_REF_DEBUG
96104 _Py_AddRefTotal (_PyInterpreterState_GET (), n );
97105#endif
106+ #if !defined(Py_NOGIL )
98107 op -> ob_refcnt += n ;
108+ #else
109+ if (_Py_IsOwnedByCurrentThread (op )) {
110+ uint32_t local = op -> ob_ref_local ;
111+ Py_ssize_t refcnt = (Py_ssize_t )local + n ;
112+ # if PY_SSIZE_T_MAX > UINT32_MAX
113+ if (refcnt > (Py_ssize_t )UINT32_MAX ) {
114+ // Make the object immortal if the 32-bit local reference count
115+ // would overflow.
116+ refcnt = _Py_IMMORTAL_REFCNT_LOCAL ;
117+ }
118+ # endif
119+ _Py_atomic_store_uint32_relaxed (& op -> ob_ref_local , (uint32_t )refcnt );
120+ }
121+ else {
122+ _Py_atomic_add_ssize (& op -> ob_ref_shared , (n << _Py_REF_SHARED_SHIFT ));
123+ }
124+ #endif
99125}
100126#define _Py_RefcntAdd (op , n ) _Py_RefcntAdd(_PyObject_CAST(op), n)
101127
102128static inline void _Py_SetImmortal (PyObject * op )
103129{
104130 if (op ) {
131+ #ifdef Py_NOGIL
132+ op -> ob_tid = _Py_UNOWNED_TID ;
133+ op -> ob_ref_local = _Py_IMMORTAL_REFCNT_LOCAL ;
134+ op -> ob_ref_shared = 0 ;
135+ #else
105136 op -> ob_refcnt = _Py_IMMORTAL_REFCNT ;
137+ #endif
106138 }
107139}
108140#define _Py_SetImmortal (op ) _Py_SetImmortal(_PyObject_CAST(op))
109141
142+ // Makes an immortal object mortal again with the specified refcnt. Should only
143+ // be used during runtime finalization.
144+ static inline void _Py_SetMortal (PyObject * op , Py_ssize_t refcnt )
145+ {
146+ if (op ) {
147+ assert (_Py_IsImmortal (op ));
148+ #ifdef Py_NOGIL
149+ op -> ob_tid = _Py_UNOWNED_TID ;
150+ op -> ob_ref_local = 0 ;
151+ op -> ob_ref_shared = _Py_REF_SHARED (refcnt , _Py_REF_MERGED );
152+ #else
153+ op -> ob_refcnt = refcnt ;
154+ #endif
155+ }
156+ }
157+
110158/* _Py_ClearImmortal() should only be used during runtime finalization. */
111159static inline void _Py_ClearImmortal (PyObject * op )
112160{
113161 if (op ) {
114- assert (op -> ob_refcnt == _Py_IMMORTAL_REFCNT );
115- op -> ob_refcnt = 1 ;
162+ _Py_SetMortal (op , 1 );
116163 Py_DECREF (op );
117164 }
118165}
@@ -122,6 +169,7 @@ static inline void _Py_ClearImmortal(PyObject *op)
122169 op = NULL; \
123170 } while (0)
124171
172+ #if !defined(Py_NOGIL )
125173static inline void
126174_Py_DECREF_SPECIALIZED (PyObject * op , const destructor destruct )
127175{
@@ -161,6 +209,37 @@ _Py_DECREF_NO_DEALLOC(PyObject *op)
161209#endif
162210}
163211
212+ #else
213+ // TODO: implement Py_DECREF specializations for Py_NOGIL build
214+ static inline void
215+ _Py_DECREF_SPECIALIZED (PyObject * op , const destructor destruct )
216+ {
217+ Py_DECREF (op );
218+ }
219+
220+ static inline void
221+ _Py_DECREF_NO_DEALLOC (PyObject * op )
222+ {
223+ Py_DECREF (op );
224+ }
225+
226+ static inline int
227+ _Py_REF_IS_MERGED (Py_ssize_t ob_ref_shared )
228+ {
229+ return (ob_ref_shared & _Py_REF_SHARED_FLAG_MASK ) == _Py_REF_MERGED ;
230+ }
231+
232+ static inline int
233+ _Py_REF_IS_QUEUED (Py_ssize_t ob_ref_shared )
234+ {
235+ return (ob_ref_shared & _Py_REF_SHARED_FLAG_MASK ) == _Py_REF_QUEUED ;
236+ }
237+
238+ // Merge the local and shared reference count fields and add `extra` to the
239+ // refcount when merging.
240+ Py_ssize_t _Py_ExplicitMergeRefcount (PyObject * op , Py_ssize_t extra );
241+ #endif // !defined(Py_NOGIL)
242+
164243#ifdef Py_REF_DEBUG
165244# undef _Py_DEC_REFTOTAL
166245#endif
0 commit comments