bpo-40521: Make the empty frozenset per interpreter (GH-21068)
Each interpreter now has its own empty frozenset singleton.
This commit is contained in:
parent
b4e85cadfb
commit
261cfedf76
|
@ -238,6 +238,8 @@ struct _is {
|
||||||
/* Using a cache is very effective since typically only a single slice is
|
/* Using a cache is very effective since typically only a single slice is
|
||||||
created and then deleted again. */
|
created and then deleted again. */
|
||||||
PySliceObject *slice_cache;
|
PySliceObject *slice_cache;
|
||||||
|
// The empty frozenset is a singleton.
|
||||||
|
PyObject *empty_frozenset;
|
||||||
|
|
||||||
struct _Py_tuple_state tuple;
|
struct _Py_tuple_state tuple;
|
||||||
struct _Py_list_state list;
|
struct _Py_list_state list;
|
||||||
|
|
|
@ -62,7 +62,7 @@ extern void _PyFrame_Fini(PyThreadState *tstate);
|
||||||
extern void _PyDict_Fini(PyThreadState *tstate);
|
extern void _PyDict_Fini(PyThreadState *tstate);
|
||||||
extern void _PyTuple_Fini(PyThreadState *tstate);
|
extern void _PyTuple_Fini(PyThreadState *tstate);
|
||||||
extern void _PyList_Fini(PyThreadState *tstate);
|
extern void _PyList_Fini(PyThreadState *tstate);
|
||||||
extern void _PySet_Fini(void);
|
extern void _PySet_Fini(PyThreadState *tstate);
|
||||||
extern void _PyBytes_Fini(void);
|
extern void _PyBytes_Fini(void);
|
||||||
extern void _PyFloat_Fini(PyThreadState *tstate);
|
extern void _PyFloat_Fini(PyThreadState *tstate);
|
||||||
extern void _PySlice_Fini(PyThreadState *tstate);
|
extern void _PySlice_Fini(PyThreadState *tstate);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
The tuple free lists, the empty tuple singleton, the list free list, the float
|
The tuple free lists, the empty tuple singleton, the list free list, the empty
|
||||||
free list, the slice cache, the dict free lists, the frame free list, the
|
frozenset singleton, the float free list, the slice cache, the dict free lists,
|
||||||
asynchronous generator free lists, and the context free list are no longer
|
the frame free list, the asynchronous generator free lists, and the context
|
||||||
shared by all interpreters: each interpreter now its has own free lists and
|
free list are no longer shared by all interpreters: each interpreter now its
|
||||||
caches.
|
has own free lists and caches.
|
||||||
|
|
|
@ -975,12 +975,11 @@ make_new_set_basetype(PyTypeObject *type, PyObject *iterable)
|
||||||
return make_new_set(type, iterable);
|
return make_new_set(type, iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The empty frozenset is a singleton */
|
|
||||||
static PyObject *emptyfrozenset = NULL;
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
make_new_frozenset(PyTypeObject *type, PyObject *iterable)
|
make_new_frozenset(PyTypeObject *type, PyObject *iterable)
|
||||||
{
|
{
|
||||||
|
PyObject *res;
|
||||||
|
|
||||||
if (type != &PyFrozenSet_Type) {
|
if (type != &PyFrozenSet_Type) {
|
||||||
return make_new_set(type, iterable);
|
return make_new_set(type, iterable);
|
||||||
}
|
}
|
||||||
|
@ -991,7 +990,7 @@ make_new_frozenset(PyTypeObject *type, PyObject *iterable)
|
||||||
Py_INCREF(iterable);
|
Py_INCREF(iterable);
|
||||||
return iterable;
|
return iterable;
|
||||||
}
|
}
|
||||||
PyObject *res = make_new_set((PyTypeObject *)type, iterable);
|
res = make_new_set((PyTypeObject *)type, iterable);
|
||||||
if (res == NULL || PySet_GET_SIZE(res) != 0) {
|
if (res == NULL || PySet_GET_SIZE(res) != 0) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -1000,11 +999,17 @@ make_new_frozenset(PyTypeObject *type, PyObject *iterable)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The empty frozenset is a singleton
|
// The empty frozenset is a singleton
|
||||||
if (emptyfrozenset == NULL) {
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
emptyfrozenset = make_new_set((PyTypeObject *)type, NULL);
|
res = interp->empty_frozenset;
|
||||||
|
if (res == NULL) {
|
||||||
|
interp->empty_frozenset = make_new_set((PyTypeObject *)type, NULL);
|
||||||
|
res = interp->empty_frozenset;
|
||||||
|
if (res == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Py_XINCREF(emptyfrozenset);
|
Py_INCREF(res);
|
||||||
return emptyfrozenset;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -2300,9 +2305,9 @@ PySet_Add(PyObject *anyset, PyObject *key)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_PySet_Fini(void)
|
_PySet_Fini(PyThreadState *tstate)
|
||||||
{
|
{
|
||||||
Py_CLEAR(emptyfrozenset);
|
Py_CLEAR(tstate->interp->empty_frozenset);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -1255,9 +1255,7 @@ finalize_interp_types(PyThreadState *tstate, int is_main_interp)
|
||||||
_PyAsyncGen_Fini(tstate);
|
_PyAsyncGen_Fini(tstate);
|
||||||
_PyContext_Fini(tstate);
|
_PyContext_Fini(tstate);
|
||||||
|
|
||||||
if (is_main_interp) {
|
_PySet_Fini(tstate);
|
||||||
_PySet_Fini();
|
|
||||||
}
|
|
||||||
_PyDict_Fini(tstate);
|
_PyDict_Fini(tstate);
|
||||||
_PyList_Fini(tstate);
|
_PyList_Fini(tstate);
|
||||||
_PyTuple_Fini(tstate);
|
_PyTuple_Fini(tstate);
|
||||||
|
|
Loading…
Reference in New Issue