diff options
-rw-r--r-- | Include/internal/pycore_gc.h | 2 | ||||
-rw-r--r-- | Include/internal/pycore_interp.h | 7 | ||||
-rw-r--r-- | Include/internal/pycore_pylifecycle.h | 2 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst | 6 | ||||
-rw-r--r-- | Modules/gcmodule.c | 2 | ||||
-rw-r--r-- | Objects/frameobject.c | 86 | ||||
-rw-r--r-- | Python/pylifecycle.c | 5 |
7 files changed, 51 insertions, 59 deletions
diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index f90d80b..01265d3 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -165,7 +165,7 @@ PyAPI_FUNC(void) _PyGC_InitState(struct _gc_runtime_state *); // Functions to clear types free lists -extern void _PyFrame_ClearFreeList(void); +extern void _PyFrame_ClearFreeList(PyThreadState *tstate); extern void _PyTuple_ClearFreeList(PyThreadState *tstate); extern void _PyFloat_ClearFreeList(PyThreadState *tstate); extern void _PyList_ClearFreeList(void); diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 70054ef..9b805f0 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -92,6 +92,12 @@ struct _Py_float_state { PyFloatObject *free_list; }; +struct _Py_frame_state { + PyFrameObject *free_list; + /* number of frames currently in free_list */ + int numfree; +}; + /* interpreter state */ @@ -187,6 +193,7 @@ struct _is { #endif struct _Py_tuple_state tuple; struct _Py_float_state float_state; + struct _Py_frame_state frame; /* Using a cache is very effective since typically only a single slice is created and then deleted again. */ diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index bba9bd9..06d2ac1 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -58,7 +58,7 @@ extern PyStatus _PyGC_Init(PyThreadState *tstate); /* Various internal finalizers */ -extern void _PyFrame_Fini(void); +extern void _PyFrame_Fini(PyThreadState *tstate); extern void _PyDict_Fini(void); extern void _PyTuple_Fini(PyThreadState *tstate); extern void _PyList_Fini(void); diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst b/Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst index 74c7a49..71a1064 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst @@ -1,3 +1,3 @@ -The tuple free lists, the empty tuple singleton, the float free list, and the -slice cache are no longer shared by all interpreters: each interpreter now has -its own free lists and caches. +The tuple free lists, the empty tuple singleton, the float free list, the slice +cache, and the frame free list are no longer shared by all interpreters: each +interpreter now its has own free lists and caches. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 0bad0f8..45dc89d 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1026,7 +1026,7 @@ static void clear_freelists(void) { PyThreadState *tstate = _PyThreadState_GET(); - _PyFrame_ClearFreeList(); + _PyFrame_ClearFreeList(tstate); _PyTuple_ClearFreeList(tstate); _PyFloat_ClearFreeList(tstate); _PyList_ClearFreeList(); 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)); } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index ee9d698..1dbdbfd 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1249,10 +1249,7 @@ flush_std_files(void) static void finalize_interp_types(PyThreadState *tstate, int is_main_interp) { - if (is_main_interp) { - /* Sundry finalizers */ - _PyFrame_Fini(); - } + _PyFrame_Fini(tstate); _PyTuple_Fini(tstate); if (is_main_interp) { _PyList_Fini(); |