@@ -54,16 +54,24 @@ PyAPI_FUNC(int) _PyObject_IsFreed(PyObject *);
54
54
Furthermore, we can't use designated initializers in Extensions since these
55
55
are not supported pre-C++20. Thus, keeping an internal copy here is the most
56
56
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
57
64
#define _PyObject_HEAD_INIT (type ) \
58
65
{ \
59
66
.ob_refcnt = _Py_IMMORTAL_REFCNT, \
60
67
.ob_type = (type) \
61
- },
68
+ }
69
+ #endif
62
70
#define _PyVarObject_HEAD_INIT (type , size ) \
63
71
{ \
64
- .ob_base = _PyObject_HEAD_INIT(type) \
72
+ .ob_base = _PyObject_HEAD_INIT(type), \
65
73
.ob_size = size \
66
- },
74
+ }
67
75
68
76
extern void _Py_NO_RETURN _Py_FatalRefcountErrorFunc (
69
77
const char * func ,
@@ -95,24 +103,63 @@ static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n)
95
103
#ifdef Py_REF_DEBUG
96
104
_Py_AddRefTotal (_PyInterpreterState_GET (), n );
97
105
#endif
106
+ #if !defined(Py_NOGIL )
98
107
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
99
125
}
100
126
#define _Py_RefcntAdd (op , n ) _Py_RefcntAdd(_PyObject_CAST(op), n)
101
127
102
128
static inline void _Py_SetImmortal (PyObject * op )
103
129
{
104
130
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
105
136
op -> ob_refcnt = _Py_IMMORTAL_REFCNT ;
137
+ #endif
106
138
}
107
139
}
108
140
#define _Py_SetImmortal (op ) _Py_SetImmortal(_PyObject_CAST(op))
109
141
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
+
110
158
/* _Py_ClearImmortal() should only be used during runtime finalization. */
111
159
static inline void _Py_ClearImmortal (PyObject * op )
112
160
{
113
161
if (op ) {
114
- assert (op -> ob_refcnt == _Py_IMMORTAL_REFCNT );
115
- op -> ob_refcnt = 1 ;
162
+ _Py_SetMortal (op , 1 );
116
163
Py_DECREF (op );
117
164
}
118
165
}
@@ -122,6 +169,7 @@ static inline void _Py_ClearImmortal(PyObject *op)
122
169
op = NULL; \
123
170
} while (0)
124
171
172
+ #if !defined(Py_NOGIL )
125
173
static inline void
126
174
_Py_DECREF_SPECIALIZED (PyObject * op , const destructor destruct )
127
175
{
@@ -161,6 +209,37 @@ _Py_DECREF_NO_DEALLOC(PyObject *op)
161
209
#endif
162
210
}
163
211
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
+
164
243
#ifdef Py_REF_DEBUG
165
244
# undef _Py_DEC_REFTOTAL
166
245
#endif
0 commit comments