diff --git a/Include/internal/pycore_freelist.h b/Include/internal/pycore_freelist.h index 34009435910d99..faa0c11a49e798 100644 --- a/Include/internal/pycore_freelist.h +++ b/Include/internal/pycore_freelist.h @@ -59,10 +59,19 @@ struct _Py_float_state { #endif }; +struct _Py_slice_state { +#ifdef WITH_FREELISTS + /* Using a cache is very effective since typically only a single slice is + created and then deleted again. */ + PySliceObject *slice_cache; +#endif +}; + typedef struct _Py_freelist_state { struct _Py_float_state float_state; struct _Py_tuple_state tuple_state; struct _Py_list_state list_state; + struct _Py_slice_state slice_state; } _PyFreeListState; #ifdef __cplusplus diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index c029b239306648..f8e86a22d0fa58 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -249,6 +249,7 @@ extern void _Py_ClearFreeLists(_PyFreeListState *state, int is_finalization); extern void _PyTuple_ClearFreeList(_PyFreeListState *state, int is_finalization); extern void _PyFloat_ClearFreeList(_PyFreeListState *state, int is_finalization); extern void _PyList_ClearFreeList(_PyFreeListState *state, int is_finalization); +extern void _PySlice_ClearCache(_PyFreeListState *state); extern void _PyDict_ClearFreeList(PyInterpreterState *interp); extern void _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp); extern void _PyContext_ClearFreeList(PyInterpreterState *interp); diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index dadc8e3b91a75d..134a882695bbd7 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -187,9 +187,6 @@ struct _is { struct _Py_long_state long_state; struct _dtoa_state dtoa; struct _py_func_state func_state; - /* Using a cache is very effective since typically only a single slice is - created and then deleted again. */ - PySliceObject *slice_cache; struct _Py_tuple_state tuple; struct _Py_dict_state dict_state; diff --git a/Include/internal/pycore_sliceobject.h b/Include/internal/pycore_sliceobject.h index 98665c3859d574..0c72d3ee6225c5 100644 --- a/Include/internal/pycore_sliceobject.h +++ b/Include/internal/pycore_sliceobject.h @@ -11,7 +11,7 @@ extern "C" { /* runtime lifecycle */ -extern void _PySlice_Fini(PyInterpreterState *); +extern void _PySlice_Fini(_PyFreeListState *); extern PyObject * _PyBuildSlice_ConsumeRefs(PyObject *start, PyObject *stop); diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index a3ed0c096d84ed..9ec8ea8e1b307f 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -103,16 +103,20 @@ PyObject _Py_EllipsisObject = _PyObject_HEAD_INIT(&PyEllipsis_Type); /* Slice object implementation */ - -void _PySlice_Fini(PyInterpreterState *interp) +void _PySlice_ClearCache(_PyFreeListState *state) { - PySliceObject *obj = interp->slice_cache; + PySliceObject *obj = state->slice_state.slice_cache; if (obj != NULL) { - interp->slice_cache = NULL; + state->slice_state.slice_cache = NULL; PyObject_GC_Del(obj); } } +void _PySlice_Fini(_PyFreeListState *state) +{ + _PySlice_ClearCache(state); +} + /* start, stop, and step are python objects with None indicating no index is present. */ @@ -122,11 +126,11 @@ _PyBuildSlice_Consume2(PyObject *start, PyObject *stop, PyObject *step) { assert(start != NULL && stop != NULL && step != NULL); - PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyFreeListState *state = _PyFreeListState_GET(); PySliceObject *obj; - if (interp->slice_cache != NULL) { - obj = interp->slice_cache; - interp->slice_cache = NULL; + if (state->slice_state.slice_cache != NULL) { + obj = state->slice_state.slice_cache; + state->slice_state.slice_cache = NULL; _Py_NewReference((PyObject *)obj); } else { @@ -354,13 +358,13 @@ Create a slice object. This is used for extended slicing (e.g. a[0:10:2])."); static void slice_dealloc(PySliceObject *r) { - PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyFreeListState *state = _PyFreeListState_GET(); _PyObject_GC_UNTRACK(r); Py_DECREF(r->step); Py_DECREF(r->start); Py_DECREF(r->stop); - if (interp->slice_cache == NULL) { - interp->slice_cache = r; + if (state->slice_state.slice_cache == NULL) { + state->slice_state.slice_cache = r; } else { PyObject_GC_Del(r); diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 4198f6a38f0e56..c33892af1c91da 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1752,15 +1752,13 @@ finalize_interp_types(PyInterpreterState *interp) _PyUnicode_ClearInterned(interp); _PyDict_Fini(interp); - - _PySlice_Fini(interp); - _PyUnicode_Fini(interp); _PyFreeListState *state = _PyFreeListState_GET(); _PyTuple_Fini(state); _PyList_Fini(state); _PyFloat_Fini(state); + _PySlice_Fini(state); #ifdef Py_DEBUG _PyStaticObjects_CheckRefcnt(interp); diff --git a/Python/pystate.c b/Python/pystate.c index eaf77b0da62a84..01dc86feabfb2f 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1549,6 +1549,7 @@ PyThreadState_Clear(PyThreadState *tstate) // Each thread should clear own freelists in free-threading builds. _PyFreeListState *freelist_state = &((_PyThreadStateImpl*)tstate)->freelist_state; _Py_ClearFreeLists(freelist_state, 0); + _PySlice_ClearCache(freelist_state); #endif _PyThreadState_ClearMimallocHeaps(tstate);