diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h index a1a94c1f2dc880..5b95485a1ae63c 100644 --- a/Include/internal/pycore_freelist_state.h +++ b/Include/internal/pycore_freelist_state.h @@ -16,6 +16,12 @@ extern "C" { # define Py_floats_MAXFREELIST 100 # define Py_ints_MAXFREELIST 100 # define Py_slices_MAXFREELIST 1 +# define Py_pycfunctionobject_MAXFREELIST 40 +# define Py_pycmethodobject_MAXFREELIST 40 +# define Py_ranges_MAXFREELIST 10 +# define Py_range_iters_MAXFREELIST 10 +# define Py_shared_iters_MAXFREELIST 24 +# define Py_class_method_MAXFREELIST 10 # define Py_contexts_MAXFREELIST 255 # define Py_async_gens_MAXFREELIST 80 # define Py_async_gen_asends_MAXFREELIST 80 @@ -42,6 +48,12 @@ struct _Py_freelists { struct _Py_freelist dicts; struct _Py_freelist dictkeys; struct _Py_freelist slices; + struct _Py_freelist pycfunctionobject; + struct _Py_freelist pycmethodobject; + struct _Py_freelist ranges; + struct _Py_freelist range_iters; + struct _Py_freelist shared_iters; + struct _Py_freelist class_method; struct _Py_freelist contexts; struct _Py_freelist async_gens; struct _Py_freelist async_gen_asends; diff --git a/Objects/classobject.c b/Objects/classobject.c index 775894ad5a7166..408fcdab9e25b5 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -3,6 +3,7 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_VectorcallTstate() #include "pycore_ceval.h" // _PyEval_GetBuiltin() +#include "pycore_freelist.h" #include "pycore_object.h" #include "pycore_pyerrors.h" #include "pycore_pystate.h" // _PyThreadState_GET() @@ -112,9 +113,13 @@ PyMethod_New(PyObject *func, PyObject *self) PyErr_BadInternalCall(); return NULL; } - PyMethodObject *im = PyObject_GC_New(PyMethodObject, &PyMethod_Type); + + PyMethodObject *im = _Py_FREELIST_POP(PyMethodObject, class_method); if (im == NULL) { - return NULL; + im = PyObject_GC_New(PyMethodObject, &PyMethod_Type); + if (im == NULL) { + return NULL; + } } im->im_weakreflist = NULL; im->im_func = Py_NewRef(func); @@ -245,7 +250,7 @@ method_dealloc(PyObject *self) PyObject_ClearWeakRefs((PyObject *)im); Py_DECREF(im->im_func); Py_XDECREF(im->im_self); - PyObject_GC_Del(im); + _Py_FREELIST_FREE(class_method, (PyObject *)im, PyObject_GC_Del); } static PyObject * diff --git a/Objects/iterobject.c b/Objects/iterobject.c index 135ced9ea1f268..3bd3a26968df5f 100644 --- a/Objects/iterobject.c +++ b/Objects/iterobject.c @@ -4,6 +4,7 @@ #include "pycore_abstract.h" // _PyObject_HasLen() #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_ceval.h" // _PyEval_GetBuiltin() +#include "pycore_freelist.h" // _Py_FREELIST_PUSH(), _Py_FREELIST_POP() #include "pycore_object.h" // _PyObject_GC_TRACK() typedef struct { @@ -21,9 +22,16 @@ PySeqIter_New(PyObject *seq) PyErr_BadInternalCall(); return NULL; } - it = PyObject_GC_New(seqiterobject, &PySeqIter_Type); - if (it == NULL) - return NULL; + + it = _Py_FREELIST_POP(seqiterobject, shared_iters); + if (it == NULL) { + it = PyObject_GC_New(seqiterobject, &PySeqIter_Type); + if (it == NULL) + return NULL; + } + else { + Py_SET_TYPE(it, &PySeqIter_Type); + } it->it_index = 0; it->it_seq = Py_NewRef(seq); _PyObject_GC_TRACK(it); @@ -35,7 +43,8 @@ iter_dealloc(seqiterobject *it) { _PyObject_GC_UNTRACK(it); Py_XDECREF(it->it_seq); - PyObject_GC_Del(it); + assert(sizeof(seqiterobject)==sizeof(_PyListIterObject)); + _Py_FREELIST_FREE(shared_iters, (PyObject *)it, PyObject_GC_Del); } static int diff --git a/Objects/listobject.c b/Objects/listobject.c index bbd53e7de94a31..2db0e4bfc436b5 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -3906,15 +3906,19 @@ PyTypeObject PyListIter_Type = { static PyObject * list_iter(PyObject *seq) { - _PyListIterObject *it; - if (!PyList_Check(seq)) { PyErr_BadInternalCall(); return NULL; } - it = PyObject_GC_New(_PyListIterObject, &PyListIter_Type); - if (it == NULL) - return NULL; + _PyListIterObject *it = _Py_FREELIST_POP(_PyListIterObject, shared_iters); + if (it == NULL) { + it = PyObject_GC_New(_PyListIterObject, &PyListIter_Type); + if (it == NULL) { + return NULL; + } + } else { + Py_SET_TYPE(it, &PyListIter_Type); + } it->it_index = 0; it->it_seq = (PyListObject *)Py_NewRef(seq); _PyObject_GC_TRACK(it); @@ -3927,7 +3931,7 @@ listiter_dealloc(PyObject *self) _PyListIterObject *it = (_PyListIterObject *)self; _PyObject_GC_UNTRACK(it); Py_XDECREF(it->it_seq); - PyObject_GC_Del(it); + _Py_FREELIST_FREE(shared_iters, it, PyObject_GC_Del); } static int diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 345da4607423cf..362b46c9b66b75 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -4,6 +4,7 @@ #include "Python.h" #include "pycore_call.h" // _Py_CheckFunctionResult() #include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate() +#include "pycore_freelist.h" #include "pycore_object.h" #include "pycore_pyerrors.h" #include "pycore_pystate.h" // _PyThreadState_GET() @@ -85,10 +86,13 @@ PyCMethod_New(PyMethodDef *ml, PyObject *self, PyObject *module, PyTypeObject *c "flag but no class"); return NULL; } - PyCMethodObject *om = PyObject_GC_New(PyCMethodObject, &PyCMethod_Type); - if (om == NULL) { - return NULL; - } + PyCMethodObject *om = _Py_FREELIST_POP(PyCMethodObject, pycmethodobject); + if (om == NULL) { + om = PyObject_GC_New(PyCMethodObject, &PyCMethod_Type); + if (om == NULL) { + return NULL; + } + } om->mm_class = (PyTypeObject*)Py_NewRef(cls); op = (PyCFunctionObject *)om; } else { @@ -98,9 +102,12 @@ PyCMethod_New(PyMethodDef *ml, PyObject *self, PyObject *module, PyTypeObject *c "but no METH_METHOD flag"); return NULL; } - op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type); + op = _Py_FREELIST_POP(PyCFunctionObject, pycfunctionobject); if (op == NULL) { - return NULL; + op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type); + if (op == NULL) { + return NULL; + } } } @@ -171,7 +178,12 @@ meth_dealloc(PyObject *self) Py_XDECREF(PyCFunction_GET_CLASS(m)); Py_XDECREF(m->m_self); Py_XDECREF(m->m_module); - PyObject_GC_Del(m); + if (m->m_ml->ml_flags & METH_METHOD) { + _Py_FREELIST_FREE(pycmethodobject, m, PyObject_GC_Del); + } + else { + _Py_FREELIST_FREE(pycfunctionobject, m, PyObject_GC_Del); + } Py_TRASHCAN_END; } diff --git a/Objects/object.c b/Objects/object.c index 4c30257ca26938..27088503ba3cd8 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -937,6 +937,12 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization) } clear_freelist(&freelists->unicode_writers, is_finalization, PyMem_Free); clear_freelist(&freelists->ints, is_finalization, free_object); + clear_freelist(&freelists->shared_iters, is_finalization, free_object); + clear_freelist(&freelists->pycfunctionobject, is_finalization, PyObject_GC_Del); + clear_freelist(&freelists->pycmethodobject, is_finalization, PyObject_GC_Del); + clear_freelist(&freelists->ranges, is_finalization, free_object); + clear_freelist(&freelists->range_iters, is_finalization, free_object); + clear_freelist(&freelists->class_method, is_finalization, free_object); } /* diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index 2942ab624edf72..a64522d19b7ded 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -3,6 +3,7 @@ #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_ceval.h" // _PyEval_GetBuiltin() +#include "pycore_freelist.h" // _Py_FREELIST_FREE(), _Py_FREELIST_POP() #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_modsupport.h" // _PyArg_NoKwnames() #include "pycore_range.h" @@ -51,16 +52,18 @@ static rangeobject * make_range_object(PyTypeObject *type, PyObject *start, PyObject *stop, PyObject *step) { - rangeobject *obj = NULL; PyObject *length; length = compute_range_length(start, stop, step); if (length == NULL) { return NULL; } - obj = PyObject_New(rangeobject, type); + rangeobject *obj = _Py_FREELIST_POP(rangeobject, ranges); if (obj == NULL) { - Py_DECREF(length); - return NULL; + obj = PyObject_New(rangeobject, type); + if (obj == NULL) { + Py_DECREF(length); + return NULL; + } } obj->start = start; obj->stop = stop; @@ -170,7 +173,7 @@ range_dealloc(rangeobject *r) Py_DECREF(r->stop); Py_DECREF(r->step); Py_DECREF(r->length); - PyObject_Free(r); + _Py_FREELIST_FREE(ranges, r, PyObject_Free); } static unsigned long @@ -880,6 +883,12 @@ rangeiter_setstate(_PyRangeIterObject *r, PyObject *state) Py_RETURN_NONE; } +static void +rangeiter_dealloc(_PyRangeIterObject *r) +{ + _Py_FREELIST_FREE(range_iters, r, PyObject_Free); +} + PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); PyDoc_STRVAR(setstate_doc, "Set state information for unpickling."); @@ -899,7 +908,7 @@ PyTypeObject PyRangeIter_Type = { sizeof(_PyRangeIterObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ - (destructor)PyObject_Free, /* tp_dealloc */ + (destructor)rangeiter_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -960,9 +969,15 @@ get_len_of_range(long lo, long hi, long step) static PyObject * fast_range_iter(long start, long stop, long step, long len) { - _PyRangeIterObject *it = PyObject_New(_PyRangeIterObject, &PyRangeIter_Type); - if (it == NULL) - return NULL; + _PyRangeIterObject *it = _Py_FREELIST_POP(_PyRangeIterObject, range_iters); + if (it == NULL) { + it = PyObject_New(_PyRangeIterObject, &PyRangeIter_Type); + if (it == NULL) + return NULL; + } + else { + Py_SET_TYPE(it, &PyRangeIter_Type); + } it->start = start; it->step = step; it->len = len; diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 49977726eadca9..d2a18f8f7ac11b 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -994,7 +994,8 @@ tupleiter_dealloc(_PyTupleIterObject *it) { _PyObject_GC_UNTRACK(it); Py_XDECREF(it->it_seq); - PyObject_GC_Del(it); + assert(sizeof(_PyTupleIterObject)==sizeof(_PyListIterObject)); + _Py_FREELIST_FREE(shared_iters, it, PyObject_GC_Del); } static int @@ -1122,9 +1123,15 @@ tuple_iter(PyObject *seq) PyErr_BadInternalCall(); return NULL; } - it = PyObject_GC_New(_PyTupleIterObject, &PyTupleIter_Type); - if (it == NULL) - return NULL; + it = _Py_FREELIST_POP(_PyTupleIterObject, shared_iters); + + if (it == NULL) { + it = PyObject_GC_New(_PyTupleIterObject, &PyTupleIter_Type); + if (it == NULL) + return NULL; + } else { + Py_SET_TYPE(it, &PyTupleIter_Type); + } it->it_index = 0; it->it_seq = (PyTupleObject *)Py_NewRef(seq); _PyObject_GC_TRACK(it);