summaryrefslogtreecommitdiffstats
path: root/Objects/frameobject.c
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2020-06-04 23:39:24 (GMT)
committerGitHub <noreply@github.com>2020-06-04 23:39:24 (GMT)
commit3744ed2c9c0b3905947602fc375de49533790cb9 (patch)
treef2086f04a9edd9875c6f0ec2eb1f2f0d6e85aa41 /Objects/frameobject.c
parent7daba6f221e713f7f60c613b246459b07d179f91 (diff)
downloadcpython-3744ed2c9c0b3905947602fc375de49533790cb9.zip
cpython-3744ed2c9c0b3905947602fc375de49533790cb9.tar.gz
cpython-3744ed2c9c0b3905947602fc375de49533790cb9.tar.bz2
bpo-40521: Make frame free list per-interpreter (GH-20638)
Each interpreter now has its own frame free list: * Move frame free list into PyInterpreterState. * Add _Py_frame_state structure. * Add tstate parameter to _PyFrame_ClearFreeList() and _PyFrame_Fini(). * Remove "#if PyFrame_MAXFREELIST > 0". * Remove "#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS".
Diffstat (limited to 'Objects/frameobject.c')
-rw-r--r--Objects/frameobject.c86
1 files changed, 37 insertions, 49 deletions
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index b6d073b..0fe9f2a 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -561,36 +561,25 @@ static PyGetSetDef frame_getsetlist[] = {
/* 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)
{
- PyObject **p, **valuestack;
- PyCodeObject *co;
-
- if (_PyObject_GC_IS_TRACKED(f))
+ if (_PyObject_GC_IS_TRACKED(f)) {
_PyObject_GC_UNTRACK(f);
+ }
Py_TRASHCAN_SAFE_BEGIN(f)
/* Kill all local variables */
- valuestack = f->f_valuestack;
- for (p = f->f_localsplus; p < valuestack; p++)
+ PyObject **valuestack = f->f_valuestack;
+ for (PyObject **p = f->f_localsplus; p < valuestack; p++) {
Py_CLEAR(*p);
+ }
/* Free stack */
if (f->f_stacktop != NULL) {
- for (p = valuestack; p < f->f_stacktop; p++)
+ for (PyObject **p = valuestack; p < f->f_stacktop; p++) {
Py_XDECREF(*p);
+ }
}
Py_XDECREF(f->f_back);
@@ -599,19 +588,21 @@ frame_dealloc(PyFrameObject *f)
Py_CLEAR(f->f_locals);
Py_CLEAR(f->f_trace);
- co = f->f_code;
+ PyCodeObject *co = f->f_code;
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;
- }
-#endif
else {
- PyObject_GC_Del(f);
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ struct _Py_frame_state *state = &interp->frame;
+ if (state->numfree < PyFrame_MAXFREELIST) {
+ ++state->numfree;
+ f->f_back = state->free_list;
+ state->free_list = f;
+ }
+ else {
+ PyObject_GC_Del(f);
+ }
}
Py_DECREF(co);
@@ -789,21 +780,20 @@ frame_alloc(PyCodeObject *code)
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
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ struct _Py_frame_state *state = &interp->frame;
+ if (state->free_list == NULL)
{
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;
+ assert(state->numfree > 0);
+ --state->numfree;
+ f = state->free_list;
+ state->free_list = state->free_list->f_back;
if (Py_SIZE(f) < extras) {
PyFrameObject *new_f = PyObject_GC_Resize(PyFrameObject, f, extras);
if (new_f == NULL) {
@@ -814,7 +804,6 @@ frame_alloc(PyCodeObject *code)
}
_Py_NewReference((PyObject *)f);
}
-#endif
f->f_code = code;
extras = code->co_nlocals + ncells + nfrees;
@@ -1183,34 +1172,33 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
/* Clear out the free list */
void
-_PyFrame_ClearFreeList(void)
+_PyFrame_ClearFreeList(PyThreadState *tstate)
{
-#if PyFrame_MAXFREELIST > 0
- while (free_list != NULL) {
- PyFrameObject *f = free_list;
- free_list = free_list->f_back;
+ struct _Py_frame_state *state = &tstate->interp->frame;
+ while (state->free_list != NULL) {
+ PyFrameObject *f = state->free_list;
+ state->free_list = state->free_list->f_back;
PyObject_GC_Del(f);
- --numfree;
+ --state->numfree;
}
- assert(numfree == 0);
-#endif
+ assert(state->numfree == 0);
}
void
-_PyFrame_Fini(void)
+_PyFrame_Fini(PyThreadState *tstate)
{
- _PyFrame_ClearFreeList();
+ _PyFrame_ClearFreeList(tstate);
}
/* Print summary info about the state of the optimized allocator */
void
_PyFrame_DebugMallocStats(FILE *out)
{
-#if PyFrame_MAXFREELIST > 0
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ struct _Py_frame_state *state = &interp->frame;
_PyDebugAllocatorStats(out,
"free PyFrameObject",
- numfree, sizeof(PyFrameObject));
-#endif
+ state->numfree, sizeof(PyFrameObject));
}