@@ -247,58 +247,47 @@ static uint64_t pydict_global_version = 0;
247
247
248
248
#define DICT_NEXT_VERSION () (++pydict_global_version)
249
249
250
- /* Dictionary reuse scheme to save calls to malloc and free */
251
- #ifndef PyDict_MAXFREELIST
252
- #define PyDict_MAXFREELIST 80
253
- #endif
254
-
255
- /* bpo-40521: dict free lists are shared by all interpreters. */
256
- #ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
257
- # undef PyDict_MAXFREELIST
258
- # define PyDict_MAXFREELIST 0
259
- #endif
260
-
261
- #if PyDict_MAXFREELIST > 0
262
- static PyDictObject * free_list [PyDict_MAXFREELIST ];
263
- static int numfree = 0 ;
264
- static PyDictKeysObject * keys_free_list [PyDict_MAXFREELIST ];
265
- static int numfreekeys = 0 ;
266
- #endif
267
-
268
250
#include "clinic/dictobject.c.h"
269
251
270
252
void
271
- _PyDict_ClearFreeList (void )
253
+ _PyDict_ClearFreeList (PyThreadState * tstate )
272
254
{
273
- #if PyDict_MAXFREELIST > 0
274
- while (numfree ) {
275
- PyDictObject * op = free_list [-- numfree ];
255
+ struct _Py_dict_state * state = & tstate -> interp -> dict_state ;
256
+ while (state -> numfree ) {
257
+ PyDictObject * op = state -> free_list [-- state -> numfree ];
276
258
assert (PyDict_CheckExact (op ));
277
259
PyObject_GC_Del (op );
278
260
}
279
- while (numfreekeys ) {
280
- PyObject_FREE (keys_free_list [-- numfreekeys ]);
261
+ while (state -> keys_numfree ) {
262
+ PyObject_FREE (state -> keys_free_list [-- state -> keys_numfree ]);
281
263
}
282
- #endif
283
264
}
284
265
285
- /* Print summary info about the state of the optimized allocator */
266
+
286
267
void
287
- _PyDict_DebugMallocStats ( FILE * out )
268
+ _PyDict_Fini ( PyThreadState * tstate )
288
269
{
289
- #if PyDict_MAXFREELIST > 0
290
- _PyDebugAllocatorStats (out ,
291
- "free PyDictObject" , numfree , sizeof (PyDictObject ));
270
+ _PyDict_ClearFreeList (tstate );
271
+ #ifdef Py_DEBUG
272
+ PyInterpreterState * interp = _PyInterpreterState_GET ();
273
+ struct _Py_dict_state * state = & interp -> dict_state ;
274
+ state -> numfree = -1 ;
275
+ state -> keys_numfree = -1 ;
292
276
#endif
293
277
}
294
278
295
279
280
+ /* Print summary info about the state of the optimized allocator */
296
281
void
297
- _PyDict_Fini ( void )
282
+ _PyDict_DebugMallocStats ( FILE * out )
298
283
{
299
- _PyDict_ClearFreeList ();
284
+ PyInterpreterState * interp = _PyInterpreterState_GET ();
285
+ struct _Py_dict_state * state = & interp -> dict_state ;
286
+ _PyDebugAllocatorStats (out , "free PyDictObject" ,
287
+ state -> numfree , sizeof (PyDictObject ));
300
288
}
301
289
290
+
302
291
#define DK_SIZE (dk ) ((dk)->dk_size)
303
292
#if SIZEOF_VOID_P > 4
304
293
#define DK_IXSIZE (dk ) \
@@ -543,7 +532,8 @@ _PyDict_CheckConsistency(PyObject *op, int check_content)
543
532
}
544
533
545
534
546
- static PyDictKeysObject * new_keys_object (Py_ssize_t size )
535
+ static PyDictKeysObject *
536
+ new_keys_object (Py_ssize_t size )
547
537
{
548
538
PyDictKeysObject * dk ;
549
539
Py_ssize_t es , usable ;
@@ -567,12 +557,16 @@ static PyDictKeysObject *new_keys_object(Py_ssize_t size)
567
557
es = sizeof (Py_ssize_t );
568
558
}
569
559
570
- #if PyDict_MAXFREELIST > 0
571
- if (size == PyDict_MINSIZE && numfreekeys > 0 ) {
572
- dk = keys_free_list [-- numfreekeys ];
560
+ PyInterpreterState * interp = _PyInterpreterState_GET ();
561
+ struct _Py_dict_state * state = & interp -> dict_state ;
562
+ #ifdef Py_DEBUG
563
+ // new_keys_object() must not be called after _PyDict_Fini()
564
+ assert (state -> keys_numfree != -1 );
565
+ #endif
566
+ if (size == PyDict_MINSIZE && state -> keys_numfree > 0 ) {
567
+ dk = state -> keys_free_list [-- state -> keys_numfree ];
573
568
}
574
569
else
575
- #endif
576
570
{
577
571
dk = PyObject_MALLOC (sizeof (PyDictKeysObject )
578
572
+ es * size
@@ -604,12 +598,16 @@ free_keys_object(PyDictKeysObject *keys)
604
598
Py_XDECREF (entries [i ].me_key );
605
599
Py_XDECREF (entries [i ].me_value );
606
600
}
607
- #if PyDict_MAXFREELIST > 0
608
- if (keys -> dk_size == PyDict_MINSIZE && numfreekeys < PyDict_MAXFREELIST ) {
609
- keys_free_list [numfreekeys ++ ] = keys ;
601
+ PyInterpreterState * interp = _PyInterpreterState_GET ();
602
+ struct _Py_dict_state * state = & interp -> dict_state ;
603
+ #ifdef Py_DEBUG
604
+ // free_keys_object() must not be called after _PyDict_Fini()
605
+ assert (state -> keys_numfree != -1 );
606
+ #endif
607
+ if (keys -> dk_size == PyDict_MINSIZE && state -> keys_numfree < PyDict_MAXFREELIST ) {
608
+ state -> keys_free_list [state -> keys_numfree ++ ] = keys ;
610
609
return ;
611
610
}
612
- #endif
613
611
PyObject_FREE (keys );
614
612
}
615
613
@@ -622,16 +620,19 @@ new_dict(PyDictKeysObject *keys, PyObject **values)
622
620
{
623
621
PyDictObject * mp ;
624
622
assert (keys != NULL );
625
- #if PyDict_MAXFREELIST > 0
626
- if (numfree ) {
627
- mp = free_list [-- numfree ];
623
+ PyInterpreterState * interp = _PyInterpreterState_GET ();
624
+ struct _Py_dict_state * state = & interp -> dict_state ;
625
+ #ifdef Py_DEBUG
626
+ // new_dict() must not be called after _PyDict_Fini()
627
+ assert (state -> numfree != -1 );
628
+ #endif
629
+ if (state -> numfree ) {
630
+ mp = state -> free_list [-- state -> numfree ];
628
631
assert (mp != NULL );
629
632
assert (Py_IS_TYPE (mp , & PyDict_Type ));
630
633
_Py_NewReference ((PyObject * )mp );
631
634
}
632
- else
633
- #endif
634
- {
635
+ else {
635
636
mp = PyObject_GC_New (PyDictObject , & PyDict_Type );
636
637
if (mp == NULL ) {
637
638
dictkeys_decref (keys );
@@ -1280,15 +1281,18 @@ dictresize(PyDictObject *mp, Py_ssize_t minsize)
1280
1281
#ifdef Py_REF_DEBUG
1281
1282
_Py_RefTotal -- ;
1282
1283
#endif
1283
- #if PyDict_MAXFREELIST > 0
1284
+ PyInterpreterState * interp = _PyInterpreterState_GET ();
1285
+ struct _Py_dict_state * state = & interp -> dict_state ;
1286
+ #ifdef Py_DEBUG
1287
+ // dictresize() must not be called after _PyDict_Fini()
1288
+ assert (state -> keys_numfree != -1 );
1289
+ #endif
1284
1290
if (oldkeys -> dk_size == PyDict_MINSIZE &&
1285
- numfreekeys < PyDict_MAXFREELIST )
1291
+ state -> keys_numfree < PyDict_MAXFREELIST )
1286
1292
{
1287
- keys_free_list [numfreekeys ++ ] = oldkeys ;
1293
+ state -> keys_free_list [state -> keys_numfree ++ ] = oldkeys ;
1288
1294
}
1289
- else
1290
- #endif
1291
- {
1295
+ else {
1292
1296
PyObject_FREE (oldkeys );
1293
1297
}
1294
1298
}
@@ -2028,13 +2032,16 @@ dict_dealloc(PyDictObject *mp)
2028
2032
assert (keys -> dk_refcnt == 1 );
2029
2033
dictkeys_decref (keys );
2030
2034
}
2031
- #if PyDict_MAXFREELIST > 0
2032
- if ( numfree < PyDict_MAXFREELIST && Py_IS_TYPE ( mp , & PyDict_Type )) {
2033
- free_list [ numfree ++ ] = mp ;
2034
- }
2035
- else
2035
+ PyInterpreterState * interp = _PyInterpreterState_GET ();
2036
+ struct _Py_dict_state * state = & interp -> dict_state ;
2037
+ #ifdef Py_DEBUG
2038
+ // new_dict() must not be called after _PyDict_Fini()
2039
+ assert ( state -> numfree != -1 );
2036
2040
#endif
2037
- {
2041
+ if (state -> numfree < PyDict_MAXFREELIST && Py_IS_TYPE (mp , & PyDict_Type )) {
2042
+ state -> free_list [state -> numfree ++ ] = mp ;
2043
+ }
2044
+ else {
2038
2045
Py_TYPE (mp )-> tp_free ((PyObject * )mp );
2039
2046
}
2040
2047
Py_TRASHCAN_END
0 commit comments