]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-111968: Split _Py_dictkeys_freelist out of _Py_dict_freelist (gh-115505)
authorDonghee Na <donghee.na@python.org>
Fri, 16 Feb 2024 01:01:36 +0000 (10:01 +0900)
committerGitHub <noreply@github.com>
Fri, 16 Feb 2024 01:01:36 +0000 (01:01 +0000)
Include/internal/pycore_freelist.h
Objects/dictobject.c
Objects/floatobject.c
Objects/listobject.c
Objects/tupleobject.c
Python/context.c
Python/object_stack.c

index b365ca337eabc87b0170ddb8b3c505813d539d3d..9900ce98037060db6b0acdf966e2a6049426fdb4 100644 (file)
@@ -35,7 +35,7 @@ extern "C" {
 
 struct _Py_list_freelist {
 #ifdef WITH_FREELISTS
-    PyListObject *free_list[PyList_MAXFREELIST];
+    PyListObject *items[PyList_MAXFREELIST];
     int numfree;
 #endif
 };
@@ -50,7 +50,7 @@ struct _Py_tuple_freelist {
        object is used as the linked list node, with its first item
        (ob_item[0]) pointing to the next node (i.e. the previous head).
        Each linked list is initially NULL. */
-    PyTupleObject *free_list[PyTuple_NFREELISTS];
+    PyTupleObject *items[PyTuple_NFREELISTS];
     int numfree[PyTuple_NFREELISTS];
 #else
     char _unused;  // Empty structs are not allowed.
@@ -63,17 +63,23 @@ struct _Py_float_freelist {
        free_list is a singly-linked list of available PyFloatObjects,
        linked via abuse of their ob_type members. */
     int numfree;
-    PyFloatObject *free_list;
+    PyFloatObject *items;
 #endif
 };
 
 struct _Py_dict_freelist {
 #ifdef WITH_FREELISTS
     /* Dictionary reuse scheme to save calls to malloc and free */
-    PyDictObject *free_list[PyDict_MAXFREELIST];
-    PyDictKeysObject *keys_free_list[PyDict_MAXFREELIST];
+    PyDictObject *items[PyDict_MAXFREELIST];
+    int numfree;
+#endif
+};
+
+struct _Py_dictkeys_freelist {
+#ifdef WITH_FREELISTS
+    /* Dictionary keys reuse scheme to save calls to malloc and free */
+    PyDictKeysObject *items[PyDict_MAXFREELIST];
     int numfree;
-    int keys_numfree;
 #endif
 };
 
@@ -88,7 +94,7 @@ struct _Py_slice_freelist {
 struct _Py_context_freelist {
 #ifdef WITH_FREELISTS
     // List of free PyContext objects
-    PyContext *freelist;
+    PyContext *items;
     int numfree;
 #endif
 };
@@ -110,7 +116,7 @@ struct _Py_async_gen_freelist {
 struct _PyObjectStackChunk;
 
 struct _Py_object_stack_freelist {
-    struct _PyObjectStackChunk *free_list;
+    struct _PyObjectStackChunk *items;
     Py_ssize_t numfree;
 };
 
@@ -119,6 +125,7 @@ struct _Py_object_freelists {
     struct _Py_tuple_freelist tuples;
     struct _Py_list_freelist lists;
     struct _Py_dict_freelist dicts;
+    struct _Py_dictkeys_freelist dictkeys;
     struct _Py_slice_freelist slices;
     struct _Py_context_freelist contexts;
     struct _Py_async_gen_freelist async_gens;
index 11667b07ecfb4bded39e12e09fbd591903a1c7a8..25ab21881f8f746dc6933ea2fd13b1e589702cab 100644 (file)
@@ -276,6 +276,13 @@ get_dict_freelist(void)
     struct _Py_object_freelists *freelists = _Py_object_freelists_GET();
     return &freelists->dicts;
 }
+
+static struct _Py_dictkeys_freelist *
+get_dictkeys_freelist(void)
+{
+    struct _Py_object_freelists *freelists = _Py_object_freelists_GET();
+    return &freelists->dictkeys;
+}
 #endif
 
 
@@ -283,18 +290,19 @@ void
 _PyDict_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization)
 {
 #ifdef WITH_FREELISTS
-    struct _Py_dict_freelist *state = &freelists->dicts;
-    while (state->numfree > 0) {
-        PyDictObject *op = state->free_list[--state->numfree];
+    struct _Py_dict_freelist *freelist = &freelists->dicts;
+    while (freelist->numfree > 0) {
+        PyDictObject *op = freelist->items[--freelist->numfree];
         assert(PyDict_CheckExact(op));
         PyObject_GC_Del(op);
     }
-    while (state->keys_numfree > 0) {
-        PyMem_Free(state->keys_free_list[--state->keys_numfree]);
+    struct _Py_dictkeys_freelist *keys_freelist = &freelists->dictkeys;
+    while (keys_freelist->numfree > 0) {
+        PyMem_Free(keys_freelist->items[--keys_freelist->numfree]);
     }
     if (is_finalization) {
-        state->numfree = -1;
-        state->keys_numfree = -1;
+        freelist->numfree = -1;
+        keys_freelist->numfree = -1;
     }
 #endif
 }
@@ -314,6 +322,9 @@ _PyDict_DebugMallocStats(FILE *out)
     struct _Py_dict_freelist *dict_freelist = get_dict_freelist();
     _PyDebugAllocatorStats(out, "free PyDictObject",
                            dict_freelist->numfree, sizeof(PyDictObject));
+    struct _Py_dictkeys_freelist *dictkeys_freelist = get_dictkeys_freelist();
+    _PyDebugAllocatorStats(out, "free PyDictKeysObject",
+                           dictkeys_freelist->numfree, sizeof(PyDictKeysObject));
 #endif
 }
 
@@ -663,9 +674,9 @@ new_keys_object(PyInterpreterState *interp, uint8_t log2_size, bool unicode)
     }
 
 #ifdef WITH_FREELISTS
-    struct _Py_dict_freelist *dict_freelist = get_dict_freelist();
-    if (log2_size == PyDict_LOG_MINSIZE && unicode && dict_freelist->keys_numfree > 0) {
-        dk = dict_freelist->keys_free_list[--dict_freelist->keys_numfree];
+    struct _Py_dictkeys_freelist *freelist = get_dictkeys_freelist();
+    if (log2_size == PyDict_LOG_MINSIZE && unicode && freelist->numfree > 0) {
+        dk = freelist->items[--freelist->numfree];
         OBJECT_STAT_INC(from_freelist);
     }
     else
@@ -698,12 +709,12 @@ static void
 free_keys_object(PyDictKeysObject *keys)
 {
 #ifdef WITH_FREELISTS
-    struct _Py_dict_freelist *dict_freelist = get_dict_freelist();
+    struct _Py_dictkeys_freelist *freelist = get_dictkeys_freelist();
     if (DK_LOG_SIZE(keys) == PyDict_LOG_MINSIZE
-            && dict_freelist->keys_numfree < PyDict_MAXFREELIST
-            && dict_freelist->keys_numfree >= 0
+            && freelist->numfree < PyDict_MAXFREELIST
+            && freelist->numfree >= 0
             && DK_IS_UNICODE(keys)) {
-        dict_freelist->keys_free_list[dict_freelist->keys_numfree++] = keys;
+        freelist->items[freelist->numfree++] = keys;
         OBJECT_STAT_INC(to_freelist);
         return;
     }
@@ -743,9 +754,9 @@ new_dict(PyInterpreterState *interp,
     PyDictObject *mp;
     assert(keys != NULL);
 #ifdef WITH_FREELISTS
-    struct _Py_dict_freelist *dict_freelist = get_dict_freelist();
-    if (dict_freelist->numfree > 0) {
-        mp = dict_freelist->free_list[--dict_freelist->numfree];
+    struct _Py_dict_freelist *freelist = get_dict_freelist();
+    if (freelist->numfree > 0) {
+        mp = freelist->items[--freelist->numfree];
         assert (mp != NULL);
         assert (Py_IS_TYPE(mp, &PyDict_Type));
         OBJECT_STAT_INC(from_freelist);
@@ -2593,10 +2604,10 @@ dict_dealloc(PyObject *self)
         dictkeys_decref(interp, keys);
     }
 #ifdef WITH_FREELISTS
-    struct _Py_dict_freelist *dict_freelist = get_dict_freelist();
-    if (dict_freelist->numfree < PyDict_MAXFREELIST && dict_freelist->numfree >=0 &&
+    struct _Py_dict_freelist *freelist = get_dict_freelist();
+    if (freelist->numfree < PyDict_MAXFREELIST && freelist->numfree >=0 &&
         Py_IS_TYPE(mp, &PyDict_Type)) {
-        dict_freelist->free_list[dict_freelist->numfree++] = mp;
+        freelist->items[freelist->numfree++] = mp;
         OBJECT_STAT_INC(to_freelist);
     }
     else
index 7dac8292c7232bdeba56ace02177bb581e86a4a8..37d2d312a6a0b78591c56f6c72525f13d3d25653 100644 (file)
@@ -130,9 +130,9 @@ PyFloat_FromDouble(double fval)
     PyFloatObject *op;
 #ifdef WITH_FREELISTS
     struct _Py_float_freelist *float_freelist = get_float_freelist();
-    op = float_freelist->free_list;
+    op = float_freelist->items;
     if (op != NULL) {
-        float_freelist->free_list = (PyFloatObject *) Py_TYPE(op);
+        float_freelist->items = (PyFloatObject *) Py_TYPE(op);
         float_freelist->numfree--;
         OBJECT_STAT_INC(from_freelist);
     }
@@ -251,8 +251,8 @@ _PyFloat_ExactDealloc(PyObject *obj)
         return;
     }
     float_freelist->numfree++;
-    Py_SET_TYPE(op, (PyTypeObject *)float_freelist->free_list);
-    float_freelist->free_list = op;
+    Py_SET_TYPE(op, (PyTypeObject *)float_freelist->items);
+    float_freelist->items = op;
     OBJECT_STAT_INC(to_freelist);
 #else
     PyObject_Free(op);
@@ -1994,13 +1994,13 @@ _PyFloat_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalizati
 {
 #ifdef WITH_FREELISTS
     struct _Py_float_freelist *state = &freelists->floats;
-    PyFloatObject *f = state->free_list;
+    PyFloatObject *f = state->items;
     while (f != NULL) {
         PyFloatObject *next = (PyFloatObject*) Py_TYPE(f);
         PyObject_Free(f);
         f = next;
     }
-    state->free_list = NULL;
+    state->items = NULL;
     if (is_finalization) {
         state->numfree = -1;
     }
index 96182a42306d95766f46c21500109e759788b4d6..eb466260318ec16942bdbe72885505f361402324 100644 (file)
@@ -133,7 +133,7 @@ _PyList_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalizatio
 #ifdef WITH_FREELISTS
     struct _Py_list_freelist *state = &freelists->lists;
     while (state->numfree > 0) {
-        PyListObject *op = state->free_list[--state->numfree];
+        PyListObject *op = state->items[--state->numfree];
         assert(PyList_CheckExact(op));
         PyObject_GC_Del(op);
     }
@@ -169,7 +169,7 @@ PyList_New(Py_ssize_t size)
     struct _Py_list_freelist *list_freelist = get_list_freelist();
     if (PyList_MAXFREELIST && list_freelist->numfree > 0) {
         list_freelist->numfree--;
-        op = list_freelist->free_list[list_freelist->numfree];
+        op = list_freelist->items[list_freelist->numfree];
         OBJECT_STAT_INC(from_freelist);
         _Py_NewReference((PyObject *)op);
     }
@@ -401,7 +401,7 @@ list_dealloc(PyObject *self)
 #ifdef WITH_FREELISTS
     struct _Py_list_freelist *list_freelist = get_list_freelist();
     if (list_freelist->numfree < PyList_MAXFREELIST && list_freelist->numfree >= 0 && PyList_CheckExact(op)) {
-        list_freelist->free_list[list_freelist->numfree++] = op;
+        list_freelist->items[list_freelist->numfree++] = op;
         OBJECT_STAT_INC(to_freelist);
     }
     else
index 1cdf79d95ae352dd12bb9b2fb1bf072036c99e1b..d9dc00da368a84c82eda6b105977a128b3652e6b 100644 (file)
@@ -1134,11 +1134,11 @@ maybe_freelist_pop(Py_ssize_t size)
     assert(size > 0);
     if (size < PyTuple_MAXSAVESIZE) {
         Py_ssize_t index = size - 1;
-        PyTupleObject *op = TUPLE_FREELIST.free_list[index];
+        PyTupleObject *op = TUPLE_FREELIST.items[index];
         if (op != NULL) {
             /* op is the head of a linked list, with the first item
                pointing to the next node.  Here we pop off the old head. */
-            TUPLE_FREELIST.free_list[index] = (PyTupleObject *) op->ob_item[0];
+            TUPLE_FREELIST.items[index] = (PyTupleObject *) op->ob_item[0];
             TUPLE_FREELIST.numfree[index]--;
             /* Inlined _PyObject_InitVar() without _PyType_HasFeature() test */
 #ifdef Py_TRACE_REFS
@@ -1173,8 +1173,8 @@ maybe_freelist_push(PyTupleObject *op)
     {
         /* op is the head of a linked list, with the first item
            pointing to the next node.  Here we set op as the new head. */
-        op->ob_item[0] = (PyObject *) TUPLE_FREELIST.free_list[index];
-        TUPLE_FREELIST.free_list[index] = op;
+        op->ob_item[0] = (PyObject *) TUPLE_FREELIST.items[index];
+        TUPLE_FREELIST.items[index] = op;
         TUPLE_FREELIST.numfree[index]++;
         OBJECT_STAT_INC(to_freelist);
         return 1;
@@ -1188,8 +1188,8 @@ maybe_freelist_clear(struct _Py_object_freelists *freelists, int fini)
 {
 #ifdef WITH_FREELISTS
     for (Py_ssize_t i = 0; i < PyTuple_NFREELISTS; i++) {
-        PyTupleObject *p = TUPLE_FREELIST.free_list[i];
-        TUPLE_FREELIST.free_list[i] = NULL;
+        PyTupleObject *p = TUPLE_FREELIST.items[i];
+        TUPLE_FREELIST.items[i] = NULL;
         TUPLE_FREELIST.numfree[i] = fini ? -1 : 0;
         while (p) {
             PyTupleObject *q = p;
index 01a21b47da5452bed3772b672bf3c9d7fe972918..3937819b3c386cb33436858d49f94a37ac0a749d 100644 (file)
@@ -344,8 +344,8 @@ _context_alloc(void)
     struct _Py_context_freelist *context_freelist = get_context_freelist();
     if (context_freelist->numfree > 0) {
         context_freelist->numfree--;
-        ctx = context_freelist->freelist;
-        context_freelist->freelist = (PyContext *)ctx->ctx_weakreflist;
+        ctx = context_freelist->items;
+        context_freelist->items = (PyContext *)ctx->ctx_weakreflist;
         OBJECT_STAT_INC(from_freelist);
         ctx->ctx_weakreflist = NULL;
         _Py_NewReference((PyObject *)ctx);
@@ -471,8 +471,8 @@ context_tp_dealloc(PyContext *self)
     struct _Py_context_freelist *context_freelist = get_context_freelist();
     if (context_freelist->numfree >= 0 && context_freelist->numfree < PyContext_MAXFREELIST) {
         context_freelist->numfree++;
-        self->ctx_weakreflist = (PyObject *)context_freelist->freelist;
-        context_freelist->freelist = self;
+        self->ctx_weakreflist = (PyObject *)context_freelist->items;
+        context_freelist->items = self;
         OBJECT_STAT_INC(to_freelist);
     }
     else
@@ -1272,8 +1272,8 @@ _PyContext_ClearFreeList(struct _Py_object_freelists *freelists, int is_finaliza
 #ifdef WITH_FREELISTS
     struct _Py_context_freelist *state = &freelists->contexts;
     for (; state->numfree > 0; state->numfree--) {
-        PyContext *ctx = state->freelist;
-        state->freelist = (PyContext *)ctx->ctx_weakreflist;
+        PyContext *ctx = state->items;
+        state->items = (PyContext *)ctx->ctx_weakreflist;
         ctx->ctx_weakreflist = NULL;
         PyObject_GC_Del(ctx);
     }
index ff2901cdacceb824cc16030ee8cb84fa52d969bd..bd9696822c8a9d416a96c9e1ea25145e8f1a9e1a 100644 (file)
@@ -21,8 +21,8 @@ _PyObjectStackChunk_New(void)
     _PyObjectStackChunk *buf;
     struct _Py_object_stack_freelist *obj_stack_freelist = get_object_stack_freelist();
     if (obj_stack_freelist->numfree > 0) {
-        buf = obj_stack_freelist->free_list;
-        obj_stack_freelist->free_list = buf->prev;
+        buf = obj_stack_freelist->items;
+        obj_stack_freelist->items = buf->prev;
         obj_stack_freelist->numfree--;
     }
     else {
@@ -47,8 +47,8 @@ _PyObjectStackChunk_Free(_PyObjectStackChunk *buf)
     if (obj_stack_freelist->numfree >= 0 &&
         obj_stack_freelist->numfree < _PyObjectStackChunk_MAXFREELIST)
     {
-        buf->prev = obj_stack_freelist->free_list;
-        obj_stack_freelist->free_list = buf;
+        buf->prev = obj_stack_freelist->items;
+        obj_stack_freelist->items = buf;
         obj_stack_freelist->numfree++;
     }
     else {
@@ -97,12 +97,12 @@ _PyObjectStackChunk_ClearFreeList(struct _Py_object_freelists *freelists, int is
         return;
     }
 
-    struct _Py_object_stack_freelist *state = &freelists->object_stacks;
-    while (state->numfree > 0) {
-        _PyObjectStackChunk *buf = state->free_list;
-        state->free_list = buf->prev;
-        state->numfree--;
+    struct _Py_object_stack_freelist *freelist = &freelists->object_stacks;
+    while (freelist->numfree > 0) {
+        _PyObjectStackChunk *buf = freelist->items;
+        freelist->items = buf->prev;
+        freelist->numfree--;
         PyMem_RawFree(buf);
     }
-    state->numfree = -1;
+    freelist->numfree = -1;
 }