@@ -31,6 +31,50 @@ get_list_freelist(void)
31
31
}
32
32
#endif
33
33
34
+ #ifdef Py_GIL_DISABLED
35
+ typedef struct {
36
+ Py_ssize_t allocated ;
37
+ PyObject * ob_item [];
38
+ } _PyListArray ;
39
+
40
+ static _PyListArray *
41
+ list_allocate_array (size_t capacity )
42
+ {
43
+ if (capacity > PY_SSIZE_T_MAX /sizeof (PyObject * ) - 1 ) {
44
+ return NULL ;
45
+ }
46
+ _PyListArray * array = PyMem_Malloc (sizeof (_PyListArray ) + capacity * sizeof (PyObject * ));
47
+ if (array == NULL ) {
48
+ return NULL ;
49
+ }
50
+ array -> allocated = capacity ;
51
+ return array ;
52
+ }
53
+
54
+ static Py_ssize_t
55
+ list_capacity (PyObject * * items )
56
+ {
57
+ _PyListArray * array = _Py_CONTAINER_OF (items , _PyListArray , ob_item );
58
+ return array -> allocated ;
59
+ }
60
+ #endif
61
+
62
+ static void
63
+ free_list_items (PyObject * * items , bool use_qsbr )
64
+ {
65
+ #ifdef Py_GIL_DISABLED
66
+ _PyListArray * array = _Py_CONTAINER_OF (items , _PyListArray , ob_item );
67
+ if (use_qsbr ) {
68
+ _PyMem_FreeDelayed (array );
69
+ }
70
+ else {
71
+ PyMem_Free (array );
72
+ }
73
+ #else
74
+ PyMem_Free (items );
75
+ #endif
76
+ }
77
+
34
78
/* Ensure ob_item has room for at least newsize elements, and set
35
79
* ob_size to newsize. If newsize > ob_size on entry, the content
36
80
* of the new slots at exit is undefined heap trash; it's the caller's
@@ -47,8 +91,7 @@ get_list_freelist(void)
47
91
static int
48
92
list_resize (PyListObject * self , Py_ssize_t newsize )
49
93
{
50
- PyObject * * items ;
51
- size_t new_allocated , num_allocated_bytes ;
94
+ size_t new_allocated , target_bytes ;
52
95
Py_ssize_t allocated = self -> allocated ;
53
96
54
97
/* Bypass realloc() when a previous overallocation is large enough
@@ -80,9 +123,34 @@ list_resize(PyListObject *self, Py_ssize_t newsize)
80
123
81
124
if (newsize == 0 )
82
125
new_allocated = 0 ;
126
+
127
+ #ifdef Py_GIL_DISABLED
128
+ _PyListArray * array = list_allocate_array (new_allocated );
129
+ if (array == NULL ) {
130
+ PyErr_NoMemory ();
131
+ return -1 ;
132
+ }
133
+ PyObject * * old_items = self -> ob_item ;
134
+ if (self -> ob_item ) {
135
+ if (new_allocated < (size_t )allocated ) {
136
+ target_bytes = new_allocated * sizeof (PyObject * );
137
+ }
138
+ else {
139
+ target_bytes = allocated * sizeof (PyObject * );
140
+ }
141
+ memcpy (array -> ob_item , self -> ob_item , target_bytes );
142
+ }
143
+ _Py_atomic_store_ptr_release (& self -> ob_item , & array -> ob_item );
144
+ self -> allocated = new_allocated ;
145
+ Py_SET_SIZE (self , newsize );
146
+ if (old_items != NULL ) {
147
+ free_list_items (old_items , _PyObject_GC_IS_SHARED (self ));
148
+ }
149
+ #else
150
+ PyObject * * items ;
83
151
if (new_allocated <= (size_t )PY_SSIZE_T_MAX / sizeof (PyObject * )) {
84
- num_allocated_bytes = new_allocated * sizeof (PyObject * );
85
- items = (PyObject * * )PyMem_Realloc (self -> ob_item , num_allocated_bytes );
152
+ target_bytes = new_allocated * sizeof (PyObject * );
153
+ items = (PyObject * * )PyMem_Realloc (self -> ob_item , target_bytes );
86
154
}
87
155
else {
88
156
// integer overflow
@@ -95,12 +163,14 @@ list_resize(PyListObject *self, Py_ssize_t newsize)
95
163
self -> ob_item = items ;
96
164
Py_SET_SIZE (self , newsize );
97
165
self -> allocated = new_allocated ;
166
+ #endif
98
167
return 0 ;
99
168
}
100
169
101
170
static int
102
171
list_preallocate_exact (PyListObject * self , Py_ssize_t size )
103
172
{
173
+ PyObject * * items ;
104
174
assert (self -> ob_item == NULL );
105
175
assert (size > 0 );
106
176
@@ -110,11 +180,20 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size)
110
180
* allocated size up to the nearest even number.
111
181
*/
112
182
size = (size + 1 ) & ~(size_t )1 ;
113
- PyObject * * items = PyMem_New (PyObject * , size );
183
+ #ifdef Py_GIL_DISABLED
184
+ _PyListArray * array = list_allocate_array (size );
185
+ if (array == NULL ) {
186
+ PyErr_NoMemory ();
187
+ return -1 ;
188
+ }
189
+ items = array -> ob_item ;
190
+ #else
191
+ items = PyMem_New (PyObject * , size );
114
192
if (items == NULL ) {
115
193
PyErr_NoMemory ();
116
194
return -1 ;
117
195
}
196
+ #endif
118
197
self -> ob_item = items ;
119
198
self -> allocated = size ;
120
199
return 0 ;
@@ -178,7 +257,17 @@ PyList_New(Py_ssize_t size)
178
257
op -> ob_item = NULL ;
179
258
}
180
259
else {
260
+ #ifdef Py_GIL_DISABLED
261
+ _PyListArray * array = list_allocate_array (size );
262
+ if (array == NULL ) {
263
+ Py_DECREF (op );
264
+ return PyErr_NoMemory ();
265
+ }
266
+ memset (& array -> ob_item , 0 , size * sizeof (PyObject * ));
267
+ op -> ob_item = array -> ob_item ;
268
+ #else
181
269
op -> ob_item = (PyObject * * ) PyMem_Calloc (size , sizeof (PyObject * ));
270
+ #endif
182
271
if (op -> ob_item == NULL ) {
183
272
Py_DECREF (op );
184
273
return PyErr_NoMemory ();
@@ -199,11 +288,20 @@ list_new_prealloc(Py_ssize_t size)
199
288
return NULL ;
200
289
}
201
290
assert (op -> ob_item == NULL );
291
+ #ifdef Py_GIL_DISABLED
292
+ _PyListArray * array = list_allocate_array (size );
293
+ if (array == NULL ) {
294
+ Py_DECREF (op );
295
+ return PyErr_NoMemory ();
296
+ }
297
+ op -> ob_item = array -> ob_item ;
298
+ #else
202
299
op -> ob_item = PyMem_New (PyObject * , size );
203
300
if (op -> ob_item == NULL ) {
204
301
Py_DECREF (op );
205
302
return PyErr_NoMemory ();
206
303
}
304
+ #endif
207
305
op -> allocated = size ;
208
306
return (PyObject * ) op ;
209
307
}
@@ -268,7 +366,7 @@ list_get_item_ref(PyListObject *op, Py_ssize_t i)
268
366
if (ob_item == NULL ) {
269
367
return NULL ;
270
368
}
271
- Py_ssize_t cap = _Py_atomic_load_ssize_relaxed ( & op -> allocated );
369
+ Py_ssize_t cap = list_capacity ( ob_item );
272
370
assert (cap != -1 && cap >= size );
273
371
if (!valid_index (i , cap )) {
274
372
return NULL ;
@@ -438,7 +536,7 @@ list_dealloc(PyObject *self)
438
536
while (-- i >= 0 ) {
439
537
Py_XDECREF (op -> ob_item [i ]);
440
538
}
441
- PyMem_Free (op -> ob_item );
539
+ free_list_items (op -> ob_item , false );
442
540
}
443
541
#ifdef WITH_FREELISTS
444
542
struct _Py_list_freelist * list_freelist = get_list_freelist ();
@@ -737,12 +835,7 @@ list_clear_impl(PyListObject *a, bool is_resize)
737
835
#else
738
836
bool use_qsbr = false;
739
837
#endif
740
- if (use_qsbr ) {
741
- _PyMem_FreeDelayed (items );
742
- }
743
- else {
744
- PyMem_Free (items );
745
- }
838
+ free_list_items (items , use_qsbr );
746
839
// Note that there is no guarantee that the list is actually empty
747
840
// at this point, because XDECREF may have populated it indirectly again!
748
841
}
@@ -2758,7 +2851,12 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse)
2758
2851
while (-- i >= 0 ) {
2759
2852
Py_XDECREF (final_ob_item [i ]);
2760
2853
}
2761
- PyMem_Free (final_ob_item );
2854
+ #ifdef Py_GIL_DISABLED
2855
+ bool use_qsbr = _PyObject_GC_IS_SHARED (self );
2856
+ #else
2857
+ bool use_qsbr = false;
2858
+ #endif
2859
+ free_list_items (final_ob_item , use_qsbr );
2762
2860
}
2763
2861
return Py_XNewRef (result );
2764
2862
}
0 commit comments