diff options
author | Victor Stinner <vstinner@python.org> | 2020-06-04 23:39:24 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-04 23:39:24 (GMT) |
commit | 3744ed2c9c0b3905947602fc375de49533790cb9 (patch) | |
tree | f2086f04a9edd9875c6f0ec2eb1f2f0d6e85aa41 /Objects/frameobject.c | |
parent | 7daba6f221e713f7f60c613b246459b07d179f91 (diff) | |
download | cpython-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.c | 86 |
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)); } |