bpo-40521: Make dict free lists per-interpreter (GH-20645)

Each interpreter now has its own dict free list:

* Move dict free lists into PyInterpreterState.
* Move PyDict_MAXFREELIST define to pycore_interp.h
* Add _Py_dict_state structure.
* Add tstate parameter to _PyDict_ClearFreeList() and _PyDict_Fini().
* In debug mode, ensure that the dict free lists are not used after
  _PyDict_Fini() is called.
* Remove "#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS".
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 55bf4ae..f3b1157 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -247,58 +247,47 @@
 
 #define DICT_NEXT_VERSION() (++pydict_global_version)
 
-/* Dictionary reuse scheme to save calls to malloc and free */
-#ifndef PyDict_MAXFREELIST
-#define PyDict_MAXFREELIST 80
-#endif
-
-/* bpo-40521: dict free lists are shared by all interpreters. */
-#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
-#  undef PyDict_MAXFREELIST
-#  define PyDict_MAXFREELIST 0
-#endif
-
-#if PyDict_MAXFREELIST > 0
-static PyDictObject *free_list[PyDict_MAXFREELIST];
-static int numfree = 0;
-static PyDictKeysObject *keys_free_list[PyDict_MAXFREELIST];
-static int numfreekeys = 0;
-#endif
-
 #include "clinic/dictobject.c.h"
 
 void
-_PyDict_ClearFreeList(void)
+_PyDict_ClearFreeList(PyThreadState *tstate)
 {
-#if PyDict_MAXFREELIST > 0
-    while (numfree) {
-        PyDictObject *op = free_list[--numfree];
+    struct _Py_dict_state *state = &tstate->interp->dict_state;
+    while (state->numfree) {
+        PyDictObject *op = state->free_list[--state->numfree];
         assert(PyDict_CheckExact(op));
         PyObject_GC_Del(op);
     }
-    while (numfreekeys) {
-        PyObject_FREE(keys_free_list[--numfreekeys]);
+    while (state->keys_numfree) {
+        PyObject_FREE(state->keys_free_list[--state->keys_numfree]);
     }
+}
+
+
+void
+_PyDict_Fini(PyThreadState *tstate)
+{
+    _PyDict_ClearFreeList(tstate);
+#ifdef Py_DEBUG
+    PyInterpreterState *interp = _PyInterpreterState_GET();
+    struct _Py_dict_state *state = &interp->dict_state;
+    state->numfree = -1;
+    state->keys_numfree = -1;
 #endif
 }
 
+
 /* Print summary info about the state of the optimized allocator */
 void
 _PyDict_DebugMallocStats(FILE *out)
 {
-#if PyDict_MAXFREELIST > 0
-    _PyDebugAllocatorStats(out,
-                           "free PyDictObject", numfree, sizeof(PyDictObject));
-#endif
+    PyInterpreterState *interp = _PyInterpreterState_GET();
+    struct _Py_dict_state *state = &interp->dict_state;
+    _PyDebugAllocatorStats(out, "free PyDictObject",
+                           state->numfree, sizeof(PyDictObject));
 }
 
 
-void
-_PyDict_Fini(void)
-{
-    _PyDict_ClearFreeList();
-}
-
 #define DK_SIZE(dk) ((dk)->dk_size)
 #if SIZEOF_VOID_P > 4
 #define DK_IXSIZE(dk)                          \
@@ -543,7 +532,8 @@
 }
 
 
-static PyDictKeysObject *new_keys_object(Py_ssize_t size)
+static PyDictKeysObject*
+new_keys_object(Py_ssize_t size)
 {
     PyDictKeysObject *dk;
     Py_ssize_t es, usable;
@@ -567,12 +557,16 @@
         es = sizeof(Py_ssize_t);
     }
 
-#if PyDict_MAXFREELIST > 0
-    if (size == PyDict_MINSIZE && numfreekeys > 0) {
-        dk = keys_free_list[--numfreekeys];
+    PyInterpreterState *interp = _PyInterpreterState_GET();
+    struct _Py_dict_state *state = &interp->dict_state;
+#ifdef Py_DEBUG
+    // new_keys_object() must not be called after _PyDict_Fini()
+    assert(state->keys_numfree != -1);
+#endif
+    if (size == PyDict_MINSIZE && state->keys_numfree > 0) {
+        dk = state->keys_free_list[--state->keys_numfree];
     }
     else
-#endif
     {
         dk = PyObject_MALLOC(sizeof(PyDictKeysObject)
                              + es * size
@@ -604,12 +598,16 @@
         Py_XDECREF(entries[i].me_key);
         Py_XDECREF(entries[i].me_value);
     }
-#if PyDict_MAXFREELIST > 0
-    if (keys->dk_size == PyDict_MINSIZE && numfreekeys < PyDict_MAXFREELIST) {
-        keys_free_list[numfreekeys++] = keys;
+    PyInterpreterState *interp = _PyInterpreterState_GET();
+    struct _Py_dict_state *state = &interp->dict_state;
+#ifdef Py_DEBUG
+    // free_keys_object() must not be called after _PyDict_Fini()
+    assert(state->keys_numfree != -1);
+#endif
+    if (keys->dk_size == PyDict_MINSIZE && state->keys_numfree < PyDict_MAXFREELIST) {
+        state->keys_free_list[state->keys_numfree++] = keys;
         return;
     }
-#endif
     PyObject_FREE(keys);
 }
 
@@ -622,16 +620,19 @@
 {
     PyDictObject *mp;
     assert(keys != NULL);
-#if PyDict_MAXFREELIST > 0
-    if (numfree) {
-        mp = free_list[--numfree];
+    PyInterpreterState *interp = _PyInterpreterState_GET();
+    struct _Py_dict_state *state = &interp->dict_state;
+#ifdef Py_DEBUG
+    // new_dict() must not be called after _PyDict_Fini()
+    assert(state->numfree != -1);
+#endif
+    if (state->numfree) {
+        mp = state->free_list[--state->numfree];
         assert (mp != NULL);
         assert (Py_IS_TYPE(mp, &PyDict_Type));
         _Py_NewReference((PyObject *)mp);
     }
-    else
-#endif
-    {
+    else {
         mp = PyObject_GC_New(PyDictObject, &PyDict_Type);
         if (mp == NULL) {
             dictkeys_decref(keys);
@@ -1280,15 +1281,18 @@
 #ifdef Py_REF_DEBUG
         _Py_RefTotal--;
 #endif
-#if PyDict_MAXFREELIST > 0
-        if (oldkeys->dk_size == PyDict_MINSIZE &&
-            numfreekeys < PyDict_MAXFREELIST)
-        {
-            keys_free_list[numfreekeys++] = oldkeys;
-        }
-        else
+        PyInterpreterState *interp = _PyInterpreterState_GET();
+        struct _Py_dict_state *state = &interp->dict_state;
+#ifdef Py_DEBUG
+        // dictresize() must not be called after _PyDict_Fini()
+        assert(state->keys_numfree != -1);
 #endif
+        if (oldkeys->dk_size == PyDict_MINSIZE &&
+            state->keys_numfree < PyDict_MAXFREELIST)
         {
+            state->keys_free_list[state->keys_numfree++] = oldkeys;
+        }
+        else {
             PyObject_FREE(oldkeys);
         }
     }
@@ -2028,13 +2032,16 @@
         assert(keys->dk_refcnt == 1);
         dictkeys_decref(keys);
     }
-#if PyDict_MAXFREELIST > 0
-    if (numfree < PyDict_MAXFREELIST && Py_IS_TYPE(mp, &PyDict_Type)) {
-        free_list[numfree++] = mp;
-    }
-    else
+    PyInterpreterState *interp = _PyInterpreterState_GET();
+    struct _Py_dict_state *state = &interp->dict_state;
+#ifdef Py_DEBUG
+    // new_dict() must not be called after _PyDict_Fini()
+    assert(state->numfree != -1);
 #endif
-    {
+    if (state->numfree < PyDict_MAXFREELIST && Py_IS_TYPE(mp, &PyDict_Type)) {
+        state->free_list[state->numfree++] = mp;
+    }
+    else {
         Py_TYPE(mp)->tp_free((PyObject *)mp);
     }
     Py_TRASHCAN_END