Skip to content

Commit 7daba6f

Browse files
authored
bpo-40521: Make slice cache per-interpreter (GH-20637)
Each interpreter now has its own slice cache: * Move slice cache into PyInterpreterState. * Add tstate parameter to _PySlice_Fini().
1 parent 2ba5937 commit 7daba6f

File tree

5 files changed

+24
-18
lines changed

5 files changed

+24
-18
lines changed

Include/internal/pycore_interp.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,10 @@ struct _is {
187187
#endif
188188
struct _Py_tuple_state tuple;
189189
struct _Py_float_state float_state;
190+
191+
/* Using a cache is very effective since typically only a single slice is
192+
created and then deleted again. */
193+
PySliceObject *slice_cache;
190194
};
191195

192196
/* Used by _PyImport_Cleanup() */

Include/internal/pycore_pylifecycle.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ extern void _PyList_Fini(void);
6565
extern void _PySet_Fini(void);
6666
extern void _PyBytes_Fini(void);
6767
extern void _PyFloat_Fini(PyThreadState *tstate);
68-
extern void _PySlice_Fini(void);
68+
extern void _PySlice_Fini(PyThreadState *tstate);
6969
extern void _PyAsyncGen_Fini(void);
7070

7171
extern void PyOS_FiniInterrupts(void);
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
Tuple free lists, empty tuple singleton, and float free list are no longer
2-
shared by all interpreters: each interpreter now its own free lists.
1+
The tuple free lists, the empty tuple singleton, the float free list, and the
2+
slice cache are no longer shared by all interpreters: each interpreter now has
3+
its own free lists and caches.

Objects/sliceobject.c

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ this type and there is exactly one in existence.
1515

1616
#include "Python.h"
1717
#include "pycore_abstract.h" // _PyIndex_Check()
18-
#include "pycore_object.h"
18+
#include "pycore_object.h" // _PyObject_GC_TRACK()
1919
#include "structmember.h" // PyMemberDef
2020

2121
static PyObject *
@@ -95,16 +95,13 @@ PyObject _Py_EllipsisObject = {
9595

9696
/* Slice object implementation */
9797

98-
/* Using a cache is very effective since typically only a single slice is
99-
* created and then deleted again
100-
*/
101-
static PySliceObject *slice_cache = NULL;
10298

103-
void _PySlice_Fini(void)
99+
void _PySlice_Fini(PyThreadState *tstate)
104100
{
105-
PySliceObject *obj = slice_cache;
101+
PyInterpreterState *interp = tstate->interp;
102+
PySliceObject *obj = interp->slice_cache;
106103
if (obj != NULL) {
107-
slice_cache = NULL;
104+
interp->slice_cache = NULL;
108105
PyObject_GC_Del(obj);
109106
}
110107
}
@@ -116,10 +113,11 @@ void _PySlice_Fini(void)
116113
PyObject *
117114
PySlice_New(PyObject *start, PyObject *stop, PyObject *step)
118115
{
116+
PyInterpreterState *interp = _PyInterpreterState_GET();
119117
PySliceObject *obj;
120-
if (slice_cache != NULL) {
121-
obj = slice_cache;
122-
slice_cache = NULL;
118+
if (interp->slice_cache != NULL) {
119+
obj = interp->slice_cache;
120+
interp->slice_cache = NULL;
123121
_Py_NewReference((PyObject *)obj);
124122
} else {
125123
obj = PyObject_GC_New(PySliceObject, &PySlice_Type);
@@ -324,14 +322,17 @@ Create a slice object. This is used for extended slicing (e.g. a[0:10:2]).");
324322
static void
325323
slice_dealloc(PySliceObject *r)
326324
{
325+
PyInterpreterState *interp = _PyInterpreterState_GET();
327326
_PyObject_GC_UNTRACK(r);
328327
Py_DECREF(r->step);
329328
Py_DECREF(r->start);
330329
Py_DECREF(r->stop);
331-
if (slice_cache == NULL)
332-
slice_cache = r;
333-
else
330+
if (interp->slice_cache == NULL) {
331+
interp->slice_cache = r;
332+
}
333+
else {
334334
PyObject_GC_Del(r);
335+
}
335336
}
336337

337338
static PyObject *

Python/pylifecycle.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1265,9 +1265,9 @@ finalize_interp_types(PyThreadState *tstate, int is_main_interp)
12651265

12661266
if (is_main_interp) {
12671267
_PyDict_Fini();
1268-
_PySlice_Fini();
12691268
}
12701269

1270+
_PySlice_Fini(tstate);
12711271
_PyWarnings_Fini(tstate->interp);
12721272

12731273
if (is_main_interp) {

0 commit comments

Comments
 (0)