https://github.com/python/cpython/commit/29772b0647519254b94bdf82df1666e98c3de3a2
commit: 29772b0647519254b94bdf82df1666e98c3de3a2
branch: main
author: Pieter Eendebak <[email protected]>
committer: Fidget-Spinner <[email protected]>
date: 2025-04-05T23:51:05+08:00
summary:
gh-126703: Add PyCFunction freelist (GH-128692)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2025-01-09-22-12-03.gh-issue-126703.6rAxZ7.rst
M Include/internal/pycore_freelist_state.h
M Objects/methodobject.c
M Objects/object.c
diff --git a/Include/internal/pycore_freelist_state.h
b/Include/internal/pycore_freelist_state.h
index 7c252f5b570c13..54415b22fd41ef 100644
--- a/Include/internal/pycore_freelist_state.h
+++ b/Include/internal/pycore_freelist_state.h
@@ -24,6 +24,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.
@@ -53,6 +55,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 457ff17b980e75..42ac3a1c2baa7b 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -942,6 +942,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);
}
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]