bpo-40521: Disable free lists in subinterpreters (GH-19937)

When Python is built with experimental isolated interpreters, disable
tuple, dict and free free lists.

Temporary workaround until these caches are made per-interpreter.

Add frame_alloc() and frame_get_builtins() subfunctions to simplify
_PyFrame_New_NoTrack().
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 9c35f3c..fa35d16 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -250,16 +250,26 @@
 #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)
 {
+#if PyDict_MAXFREELIST > 0
     while (numfree) {
         PyDictObject *op = free_list[--numfree];
         assert(PyDict_CheckExact(op));
@@ -268,14 +278,17 @@
     while (numfreekeys) {
         PyObject_FREE(keys_free_list[--numfreekeys]);
     }
+#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
 }
 
 
@@ -553,10 +566,13 @@
         es = sizeof(Py_ssize_t);
     }
 
+#if PyDict_MAXFREELIST > 0
     if (size == PyDict_MINSIZE && numfreekeys > 0) {
         dk = keys_free_list[--numfreekeys];
     }
-    else {
+    else
+#endif
+    {
         dk = PyObject_MALLOC(sizeof(PyDictKeysObject)
                              + es * size
                              + sizeof(PyDictKeyEntry) * usable);
@@ -587,10 +603,12 @@
         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;
         return;
     }
+#endif
     PyObject_FREE(keys);
 }
 
@@ -603,13 +621,16 @@
 {
     PyDictObject *mp;
     assert(keys != NULL);
+#if PyDict_MAXFREELIST > 0
     if (numfree) {
         mp = free_list[--numfree];
         assert (mp != NULL);
         assert (Py_IS_TYPE(mp, &PyDict_Type));
         _Py_NewReference((PyObject *)mp);
     }
-    else {
+    else
+#endif
+    {
         mp = PyObject_GC_New(PyDictObject, &PyDict_Type);
         if (mp == NULL) {
             dictkeys_decref(keys);
@@ -1258,12 +1279,15 @@
 #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 {
+        else
+#endif
+        {
             PyObject_FREE(oldkeys);
         }
     }
@@ -2005,10 +2029,15 @@
         assert(keys->dk_refcnt == 1);
         dictkeys_decref(keys);
     }
-    if (numfree < PyDict_MAXFREELIST && Py_IS_TYPE(mp, &PyDict_Type))
+#if PyDict_MAXFREELIST > 0
+    if (numfree < PyDict_MAXFREELIST && Py_IS_TYPE(mp, &PyDict_Type)) {
         free_list[numfree++] = mp;
+    }
     else
+#endif
+    {
         Py_TYPE(mp)->tp_free((PyObject *)mp);
+    }
     Py_TRASHCAN_END
 }
 
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 4f5054d..af32276 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -556,12 +556,20 @@
    free_list.  Else programs creating lots of cyclic trash involving
    frames could provoke free_list into growing without bound.
 */
-
-static PyFrameObject *free_list = NULL;
-static int numfree = 0;         /* number of frames currently in free_list */
 /* max value for numfree */
 #define PyFrame_MAXFREELIST 200
 
+/* bpo-40521: frame free lists are shared by all interpreters. */
+#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
+#  undef PyFrame_MAXFREELIST
+#  define PyFrame_MAXFREELIST 0
+#endif
+
+#if PyFrame_MAXFREELIST > 0
+static PyFrameObject *free_list = NULL;
+static int numfree = 0;         /* number of frames currently in free_list */
+#endif
+
 static void _Py_HOT_FUNCTION
 frame_dealloc(PyFrameObject *f)
 {
@@ -590,15 +598,19 @@
     Py_CLEAR(f->f_trace);
 
     co = f->f_code;
-    if (co->co_zombieframe == NULL)
+    if (co->co_zombieframe == NULL) {
         co->co_zombieframe = f;
+    }
+#if PyFrame_MAXFREELIST > 0
     else if (numfree < PyFrame_MAXFREELIST) {
         ++numfree;
         f->f_back = free_list;
         free_list = f;
     }
-    else
+#endif
+    else {
         PyObject_GC_Del(f);
+    }
 
     Py_DECREF(co);
     Py_TRASHCAN_SAFE_END(f)
@@ -759,15 +771,107 @@
 
 _Py_IDENTIFIER(__builtins__);
 
+static inline PyFrameObject*
+frame_alloc(PyCodeObject *code)
+{
+    PyFrameObject *f;
+
+    f = code->co_zombieframe;
+    if (f != NULL) {
+        code->co_zombieframe = NULL;
+        _Py_NewReference((PyObject *)f);
+        assert(f->f_code == code);
+        return f;
+    }
+
+    Py_ssize_t ncells = PyTuple_GET_SIZE(code->co_cellvars);
+    Py_ssize_t nfrees = PyTuple_GET_SIZE(code->co_freevars);
+    Py_ssize_t extras = code->co_stacksize + code->co_nlocals + ncells + nfrees;
+#if PyFrame_MAXFREELIST > 0
+    if (free_list == NULL)
+#endif
+    {
+        f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type, extras);
+        if (f == NULL) {
+            return NULL;
+        }
+    }
+#if PyFrame_MAXFREELIST > 0
+    else {
+        assert(numfree > 0);
+        --numfree;
+        f = free_list;
+        free_list = free_list->f_back;
+        if (Py_SIZE(f) < extras) {
+            PyFrameObject *new_f = PyObject_GC_Resize(PyFrameObject, f, extras);
+            if (new_f == NULL) {
+                PyObject_GC_Del(f);
+                return NULL;
+            }
+            f = new_f;
+        }
+        _Py_NewReference((PyObject *)f);
+    }
+#endif
+
+    f->f_code = code;
+    extras = code->co_nlocals + ncells + nfrees;
+    f->f_valuestack = f->f_localsplus + extras;
+    for (Py_ssize_t i=0; i<extras; i++) {
+        f->f_localsplus[i] = NULL;
+    }
+    f->f_locals = NULL;
+    f->f_trace = NULL;
+    return f;
+}
+
+
+static inline PyObject *
+frame_get_builtins(PyFrameObject *back, PyObject *globals)
+{
+    PyObject *builtins;
+
+    if (back != NULL && back->f_globals == globals) {
+        /* If we share the globals, we share the builtins.
+           Save a lookup and a call. */
+        builtins = back->f_builtins;
+        assert(builtins != NULL);
+        Py_INCREF(builtins);
+        return builtins;
+    }
+
+    builtins = _PyDict_GetItemIdWithError(globals, &PyId___builtins__);
+    if (builtins != NULL && PyModule_Check(builtins)) {
+        builtins = PyModule_GetDict(builtins);
+        assert(builtins != NULL);
+    }
+    if (builtins != NULL) {
+        Py_INCREF(builtins);
+        return builtins;
+    }
+
+    if (PyErr_Occurred()) {
+        return NULL;
+    }
+
+    /* No builtins! Make up a minimal one.
+       Give them 'None', at least. */
+    builtins = PyDict_New();
+    if (builtins == NULL) {
+        return NULL;
+    }
+    if (PyDict_SetItemString(builtins, "None", Py_None) < 0) {
+        Py_DECREF(builtins);
+        return NULL;
+    }
+    return builtins;
+}
+
+
 PyFrameObject* _Py_HOT_FUNCTION
 _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
                      PyObject *globals, PyObject *locals)
 {
-    PyFrameObject *back = tstate->frame;
-    PyFrameObject *f;
-    PyObject *builtins;
-    Py_ssize_t i;
-
 #ifdef Py_DEBUG
     if (code == NULL || globals == NULL || !PyDict_Check(globals) ||
         (locals != NULL && !PyMapping_Check(locals))) {
@@ -775,82 +879,19 @@
         return NULL;
     }
 #endif
-    if (back == NULL || back->f_globals != globals) {
-        builtins = _PyDict_GetItemIdWithError(globals, &PyId___builtins__);
-        if (builtins) {
-            if (PyModule_Check(builtins)) {
-                builtins = PyModule_GetDict(builtins);
-                assert(builtins != NULL);
-            }
-        }
-        if (builtins == NULL) {
-            if (PyErr_Occurred()) {
-                return NULL;
-            }
-            /* No builtins!              Make up a minimal one
-               Give them 'None', at least. */
-            builtins = PyDict_New();
-            if (builtins == NULL ||
-                PyDict_SetItemString(
-                    builtins, "None", Py_None) < 0)
-                return NULL;
-        }
-        else
-            Py_INCREF(builtins);
 
+    PyFrameObject *back = tstate->frame;
+    PyObject *builtins = frame_get_builtins(back, globals);
+    if (builtins == NULL) {
+        return NULL;
     }
-    else {
-        /* If we share the globals, we share the builtins.
-           Save a lookup and a call. */
-        builtins = back->f_builtins;
-        assert(builtins != NULL);
-        Py_INCREF(builtins);
-    }
-    if (code->co_zombieframe != NULL) {
-        f = code->co_zombieframe;
-        code->co_zombieframe = NULL;
-        _Py_NewReference((PyObject *)f);
-        assert(f->f_code == code);
-    }
-    else {
-        Py_ssize_t extras, ncells, nfrees;
-        ncells = PyTuple_GET_SIZE(code->co_cellvars);
-        nfrees = PyTuple_GET_SIZE(code->co_freevars);
-        extras = code->co_stacksize + code->co_nlocals + ncells +
-            nfrees;
-        if (free_list == NULL) {
-            f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type,
-            extras);
-            if (f == NULL) {
-                Py_DECREF(builtins);
-                return NULL;
-            }
-        }
-        else {
-            assert(numfree > 0);
-            --numfree;
-            f = free_list;
-            free_list = free_list->f_back;
-            if (Py_SIZE(f) < extras) {
-                PyFrameObject *new_f = PyObject_GC_Resize(PyFrameObject, f, extras);
-                if (new_f == NULL) {
-                    PyObject_GC_Del(f);
-                    Py_DECREF(builtins);
-                    return NULL;
-                }
-                f = new_f;
-            }
-            _Py_NewReference((PyObject *)f);
-        }
 
-        f->f_code = code;
-        extras = code->co_nlocals + ncells + nfrees;
-        f->f_valuestack = f->f_localsplus + extras;
-        for (i=0; i<extras; i++)
-            f->f_localsplus[i] = NULL;
-        f->f_locals = NULL;
-        f->f_trace = NULL;
+    PyFrameObject *f = frame_alloc(code);
+    if (f == NULL) {
+        Py_DECREF(builtins);
+        return NULL;
     }
+
     f->f_stacktop = f->f_valuestack;
     f->f_builtins = builtins;
     Py_XINCREF(back);
@@ -1142,6 +1183,7 @@
 void
 _PyFrame_ClearFreeList(void)
 {
+#if PyFrame_MAXFREELIST > 0
     while (free_list != NULL) {
         PyFrameObject *f = free_list;
         free_list = free_list->f_back;
@@ -1149,6 +1191,7 @@
         --numfree;
     }
     assert(numfree == 0);
+#endif
 }
 
 void
@@ -1161,9 +1204,11 @@
 void
 _PyFrame_DebugMallocStats(FILE *out)
 {
+#if PyFrame_MAXFREELIST > 0
     _PyDebugAllocatorStats(out,
                            "free PyFrameObject",
                            numfree, sizeof(PyFrameObject));
+#endif
 }
 
 
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index f8648d2..c0b59c0 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -22,6 +22,12 @@
 #define PyTuple_MAXFREELIST  2000  /* Maximum number of tuples of each size to save */
 #endif
 
+/* bpo-40521: tuple free lists are shared by all interpreters. */
+#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
+#  undef PyTuple_MAXSAVESIZE
+#  define PyTuple_MAXSAVESIZE 0
+#endif
+
 #if PyTuple_MAXSAVESIZE > 0
 /* Entries 1 up to PyTuple_MAXSAVESIZE are free lists, entry 0 is the empty
    tuple () of which at most one instance will be allocated.
@@ -248,7 +254,9 @@
 #endif
     }
     Py_TYPE(op)->tp_free((PyObject *)op);
+#if PyTuple_MAXSAVESIZE > 0
 done:
+#endif
     Py_TRASHCAN_END
 }