diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h index 2ccd1ac055b747..7f575e0fc17a54 100644 --- a/Include/internal/pycore_freelist_state.h +++ b/Include/internal/pycore_freelist_state.h @@ -22,6 +22,8 @@ extern "C" { # define Py_futureiters_MAXFREELIST 255 # define Py_object_stack_chunks_MAXFREELIST 4 # define Py_unicode_writers_MAXFREELIST 1 +# define Py_pycfunctionobject_MAXFREELIST 16 +# define Py_pycmethodobject_MAXFREELIST 16 # define Py_pymethodobjects_MAXFREELIST 20 // A generic freelist of either PyObjects or other data structures. @@ -49,6 +51,8 @@ struct _Py_freelists { struct _Py_freelist futureiters; struct _Py_freelist object_stack_chunks; struct _Py_freelist unicode_writers; + struct _Py_freelist pycfunctionobject; + struct _Py_freelist pycmethodobject; struct _Py_freelist pymethodobjects; }; diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-01-09-22-12-03.gh-issue-126703.6rAxZ7.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-09-22-12-03.gh-issue-126703.6rAxZ7.rst new file mode 100644 index 00000000000000..6dc04135c7879e --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-09-22-12-03.gh-issue-126703.6rAxZ7.rst @@ -0,0 +1 @@ +Improve performance of builtin methods by using a freelist. diff --git a/Objects/methodobject.c b/Objects/methodobject.c index ecec0f7205a11d..1f459dea44192c 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,9 +86,12 @@ PyCMethod_New(PyMethodDef *ml, PyObject *self, PyObject *module, PyTypeObject *c "flag but no class"); return NULL; } - PyCMethodObject *om = PyObject_GC_New(PyCMethodObject, &PyCMethod_Type); + PyCMethodObject *om = _Py_FREELIST_POP(PyCMethodObject, pycmethodobject); if (om == NULL) { - return NULL; + om = PyObject_GC_New(PyCMethodObject, &PyCMethod_Type); + if (om == NULL) { + return NULL; + } } om->mm_class = (PyTypeObject*)Py_NewRef(cls); op = (PyCFunctionObject *)om; @@ -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,14 @@ 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) { + assert(Py_IS_TYPE(self, &PyCMethod_Type)); + _Py_FREELIST_FREE(pycmethodobject, m, PyObject_GC_Del); + } + else { + assert(Py_IS_TYPE(self, &PyCFunction_Type)); + _Py_FREELIST_FREE(pycfunctionobject, m, PyObject_GC_Del); + } Py_TRASHCAN_END; } diff --git a/Objects/object.c b/Objects/object.c index 51b6016b9c191c..8fe1c69aeaec01 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -937,6 +937,8 @@ _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->pycfunctionobject, is_finalization, PyObject_GC_Del); + clear_freelist(&freelists->pycmethodobject, is_finalization, PyObject_GC_Del); clear_freelist(&freelists->pymethodobjects, is_finalization, free_object); }
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: