]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-126703: Add freelist for PyComplexObject's (gh-135233)
authorSergey B Kirpichev <skirpichev@gmail.com>
Fri, 13 Jun 2025 13:32:26 +0000 (16:32 +0300)
committerGitHub <noreply@github.com>
Fri, 13 Jun 2025 13:32:26 +0000 (22:32 +0900)
Include/internal/pycore_freelist_state.h
Objects/complexobject.c
Objects/object.c

index 4828dfd948f70ab2257d7acee52ac75b43c87a40..59beb92f3f7b9c6afb8fb4aae4b77d8fbc794833 100644 (file)
@@ -16,6 +16,7 @@ extern "C" {
 #  define Py_dicts_MAXFREELIST 80
 #  define Py_dictkeys_MAXFREELIST 80
 #  define Py_floats_MAXFREELIST 100
+#  define Py_complexes_MAXFREELIST 100
 #  define Py_ints_MAXFREELIST 100
 #  define Py_slices_MAXFREELIST 1
 #  define Py_ranges_MAXFREELIST 6
@@ -43,6 +44,7 @@ struct _Py_freelist {
 
 struct _Py_freelists {
     struct _Py_freelist floats;
+    struct _Py_freelist complexes;
     struct _Py_freelist ints;
     struct _Py_freelist tuples[PyTuple_MAXSAVESIZE];
     struct _Py_freelist lists;
index c2dd320ae73988f5681046fc84a16961a2609821..b66ebe131ae60522d1a4e7be793b4464f90fcd7c 100644 (file)
@@ -1,4 +1,3 @@
-
 /* Complex object implementation */
 
 /* Borrows heavily from floatobject.c */
@@ -9,6 +8,7 @@
 #include "pycore_call.h"          // _PyObject_CallNoArgs()
 #include "pycore_complexobject.h" // _PyComplex_FormatAdvancedWriter()
 #include "pycore_floatobject.h"   // _Py_convert_int_to_double()
+#include "pycore_freelist.h"      // _Py_FREELIST_FREE(), _Py_FREELIST_POP()
 #include "pycore_long.h"          // _PyLong_GetZero()
 #include "pycore_object.h"        // _PyObject_Init()
 #include "pycore_pymath.h"        // _Py_ADJUST_ERANGE2()
@@ -410,16 +410,32 @@ complex_subtype_from_c_complex(PyTypeObject *type, Py_complex cval)
 PyObject *
 PyComplex_FromCComplex(Py_complex cval)
 {
-    /* Inline PyObject_New */
-    PyComplexObject *op = PyObject_Malloc(sizeof(PyComplexObject));
+    PyComplexObject *op = _Py_FREELIST_POP(PyComplexObject, complexes);
+
     if (op == NULL) {
-        return PyErr_NoMemory();
+        /* Inline PyObject_New */
+        op = PyObject_Malloc(sizeof(PyComplexObject));
+        if (op == NULL) {
+            return PyErr_NoMemory();
+        }
+        _PyObject_Init((PyObject*)op, &PyComplex_Type);
     }
-    _PyObject_Init((PyObject*)op, &PyComplex_Type);
     op->cval = cval;
     return (PyObject *) op;
 }
 
+static void
+complex_dealloc(PyObject *op)
+{
+    assert(PyComplex_Check(op));
+    if (PyComplex_CheckExact(op)) {
+        _Py_FREELIST_FREE(complexes, op, PyObject_Free);
+    }
+    else {
+        Py_TYPE(op)->tp_free(op);
+    }
+}
+
 static PyObject *
 complex_subtype_from_doubles(PyTypeObject *type, double real, double imag)
 {
@@ -1383,7 +1399,7 @@ PyTypeObject PyComplex_Type = {
     "complex",
     sizeof(PyComplexObject),
     0,
-    0,                                          /* tp_dealloc */
+    complex_dealloc,                            /* tp_dealloc */
     0,                                          /* tp_vectorcall_offset */
     0,                                          /* tp_getattr */
     0,                                          /* tp_setattr */
index 9fe61ba7f1593aab65ab6726d5dec92653b42a98..eff3a9862129a2a3aadb4d2b77de4b7f4cd37c23 100644 (file)
@@ -925,6 +925,7 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization)
     // In the free-threaded build, freelists are per-PyThreadState and cleared in PyThreadState_Clear()
     // In the default build, freelists are per-interpreter and cleared in finalize_interp_types()
     clear_freelist(&freelists->floats, is_finalization, free_object);
+    clear_freelist(&freelists->complexes, is_finalization, free_object);
     for (Py_ssize_t i = 0; i < PyTuple_MAXSAVESIZE; i++) {
         clear_freelist(&freelists->tuples[i], is_finalization, free_object);
     }