Skip to content

Commit 321d13f

Browse files
authored
gh-111968: Split _Py_dictkeys_freelist out of _Py_dict_freelist (gh-115505)
1 parent 454d796 commit 321d13f

File tree

7 files changed

+77
-59
lines changed

7 files changed

+77
-59
lines changed

Include/internal/pycore_freelist.h

+15-8
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ extern "C" {
3535

3636
struct _Py_list_freelist {
3737
#ifdef WITH_FREELISTS
38-
PyListObject *free_list[PyList_MAXFREELIST];
38+
PyListObject *items[PyList_MAXFREELIST];
3939
int numfree;
4040
#endif
4141
};
@@ -50,7 +50,7 @@ struct _Py_tuple_freelist {
5050
object is used as the linked list node, with its first item
5151
(ob_item[0]) pointing to the next node (i.e. the previous head).
5252
Each linked list is initially NULL. */
53-
PyTupleObject *free_list[PyTuple_NFREELISTS];
53+
PyTupleObject *items[PyTuple_NFREELISTS];
5454
int numfree[PyTuple_NFREELISTS];
5555
#else
5656
char _unused; // Empty structs are not allowed.
@@ -63,17 +63,23 @@ struct _Py_float_freelist {
6363
free_list is a singly-linked list of available PyFloatObjects,
6464
linked via abuse of their ob_type members. */
6565
int numfree;
66-
PyFloatObject *free_list;
66+
PyFloatObject *items;
6767
#endif
6868
};
6969

7070
struct _Py_dict_freelist {
7171
#ifdef WITH_FREELISTS
7272
/* Dictionary reuse scheme to save calls to malloc and free */
73-
PyDictObject *free_list[PyDict_MAXFREELIST];
74-
PyDictKeysObject *keys_free_list[PyDict_MAXFREELIST];
73+
PyDictObject *items[PyDict_MAXFREELIST];
74+
int numfree;
75+
#endif
76+
};
77+
78+
struct _Py_dictkeys_freelist {
79+
#ifdef WITH_FREELISTS
80+
/* Dictionary keys reuse scheme to save calls to malloc and free */
81+
PyDictKeysObject *items[PyDict_MAXFREELIST];
7582
int numfree;
76-
int keys_numfree;
7783
#endif
7884
};
7985

@@ -88,7 +94,7 @@ struct _Py_slice_freelist {
8894
struct _Py_context_freelist {
8995
#ifdef WITH_FREELISTS
9096
// List of free PyContext objects
91-
PyContext *freelist;
97+
PyContext *items;
9298
int numfree;
9399
#endif
94100
};
@@ -110,7 +116,7 @@ struct _Py_async_gen_freelist {
110116
struct _PyObjectStackChunk;
111117

112118
struct _Py_object_stack_freelist {
113-
struct _PyObjectStackChunk *free_list;
119+
struct _PyObjectStackChunk *items;
114120
Py_ssize_t numfree;
115121
};
116122

@@ -119,6 +125,7 @@ struct _Py_object_freelists {
119125
struct _Py_tuple_freelist tuples;
120126
struct _Py_list_freelist lists;
121127
struct _Py_dict_freelist dicts;
128+
struct _Py_dictkeys_freelist dictkeys;
122129
struct _Py_slice_freelist slices;
123130
struct _Py_context_freelist contexts;
124131
struct _Py_async_gen_freelist async_gens;

Objects/dictobject.c

+31-20
Original file line numberDiff line numberDiff line change
@@ -276,25 +276,33 @@ get_dict_freelist(void)
276276
struct _Py_object_freelists *freelists = _Py_object_freelists_GET();
277277
return &freelists->dicts;
278278
}
279+
280+
static struct _Py_dictkeys_freelist *
281+
get_dictkeys_freelist(void)
282+
{
283+
struct _Py_object_freelists *freelists = _Py_object_freelists_GET();
284+
return &freelists->dictkeys;
285+
}
279286
#endif
280287

281288

282289
void
283290
_PyDict_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization)
284291
{
285292
#ifdef WITH_FREELISTS
286-
struct _Py_dict_freelist *state = &freelists->dicts;
287-
while (state->numfree > 0) {
288-
PyDictObject *op = state->free_list[--state->numfree];
293+
struct _Py_dict_freelist *freelist = &freelists->dicts;
294+
while (freelist->numfree > 0) {
295+
PyDictObject *op = freelist->items[--freelist->numfree];
289296
assert(PyDict_CheckExact(op));
290297
PyObject_GC_Del(op);
291298
}
292-
while (state->keys_numfree > 0) {
293-
PyMem_Free(state->keys_free_list[--state->keys_numfree]);
299+
struct _Py_dictkeys_freelist *keys_freelist = &freelists->dictkeys;
300+
while (keys_freelist->numfree > 0) {
301+
PyMem_Free(keys_freelist->items[--keys_freelist->numfree]);
294302
}
295303
if (is_finalization) {
296-
state->numfree = -1;
297-
state->keys_numfree = -1;
304+
freelist->numfree = -1;
305+
keys_freelist->numfree = -1;
298306
}
299307
#endif
300308
}
@@ -314,6 +322,9 @@ _PyDict_DebugMallocStats(FILE *out)
314322
struct _Py_dict_freelist *dict_freelist = get_dict_freelist();
315323
_PyDebugAllocatorStats(out, "free PyDictObject",
316324
dict_freelist->numfree, sizeof(PyDictObject));
325+
struct _Py_dictkeys_freelist *dictkeys_freelist = get_dictkeys_freelist();
326+
_PyDebugAllocatorStats(out, "free PyDictKeysObject",
327+
dictkeys_freelist->numfree, sizeof(PyDictKeysObject));
317328
#endif
318329
}
319330

@@ -663,9 +674,9 @@ new_keys_object(PyInterpreterState *interp, uint8_t log2_size, bool unicode)
663674
}
664675

665676
#ifdef WITH_FREELISTS
666-
struct _Py_dict_freelist *dict_freelist = get_dict_freelist();
667-
if (log2_size == PyDict_LOG_MINSIZE && unicode && dict_freelist->keys_numfree > 0) {
668-
dk = dict_freelist->keys_free_list[--dict_freelist->keys_numfree];
677+
struct _Py_dictkeys_freelist *freelist = get_dictkeys_freelist();
678+
if (log2_size == PyDict_LOG_MINSIZE && unicode && freelist->numfree > 0) {
679+
dk = freelist->items[--freelist->numfree];
669680
OBJECT_STAT_INC(from_freelist);
670681
}
671682
else
@@ -698,12 +709,12 @@ static void
698709
free_keys_object(PyDictKeysObject *keys)
699710
{
700711
#ifdef WITH_FREELISTS
701-
struct _Py_dict_freelist *dict_freelist = get_dict_freelist();
712+
struct _Py_dictkeys_freelist *freelist = get_dictkeys_freelist();
702713
if (DK_LOG_SIZE(keys) == PyDict_LOG_MINSIZE
703-
&& dict_freelist->keys_numfree < PyDict_MAXFREELIST
704-
&& dict_freelist->keys_numfree >= 0
714+
&& freelist->numfree < PyDict_MAXFREELIST
715+
&& freelist->numfree >= 0
705716
&& DK_IS_UNICODE(keys)) {
706-
dict_freelist->keys_free_list[dict_freelist->keys_numfree++] = keys;
717+
freelist->items[freelist->numfree++] = keys;
707718
OBJECT_STAT_INC(to_freelist);
708719
return;
709720
}
@@ -743,9 +754,9 @@ new_dict(PyInterpreterState *interp,
743754
PyDictObject *mp;
744755
assert(keys != NULL);
745756
#ifdef WITH_FREELISTS
746-
struct _Py_dict_freelist *dict_freelist = get_dict_freelist();
747-
if (dict_freelist->numfree > 0) {
748-
mp = dict_freelist->free_list[--dict_freelist->numfree];
757+
struct _Py_dict_freelist *freelist = get_dict_freelist();
758+
if (freelist->numfree > 0) {
759+
mp = freelist->items[--freelist->numfree];
749760
assert (mp != NULL);
750761
assert (Py_IS_TYPE(mp, &PyDict_Type));
751762
OBJECT_STAT_INC(from_freelist);
@@ -2593,10 +2604,10 @@ dict_dealloc(PyObject *self)
25932604
dictkeys_decref(interp, keys);
25942605
}
25952606
#ifdef WITH_FREELISTS
2596-
struct _Py_dict_freelist *dict_freelist = get_dict_freelist();
2597-
if (dict_freelist->numfree < PyDict_MAXFREELIST && dict_freelist->numfree >=0 &&
2607+
struct _Py_dict_freelist *freelist = get_dict_freelist();
2608+
if (freelist->numfree < PyDict_MAXFREELIST && freelist->numfree >=0 &&
25982609
Py_IS_TYPE(mp, &PyDict_Type)) {
2599-
dict_freelist->free_list[dict_freelist->numfree++] = mp;
2610+
freelist->items[freelist->numfree++] = mp;
26002611
OBJECT_STAT_INC(to_freelist);
26012612
}
26022613
else

Objects/floatobject.c

+6-6
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,9 @@ PyFloat_FromDouble(double fval)
130130
PyFloatObject *op;
131131
#ifdef WITH_FREELISTS
132132
struct _Py_float_freelist *float_freelist = get_float_freelist();
133-
op = float_freelist->free_list;
133+
op = float_freelist->items;
134134
if (op != NULL) {
135-
float_freelist->free_list = (PyFloatObject *) Py_TYPE(op);
135+
float_freelist->items = (PyFloatObject *) Py_TYPE(op);
136136
float_freelist->numfree--;
137137
OBJECT_STAT_INC(from_freelist);
138138
}
@@ -251,8 +251,8 @@ _PyFloat_ExactDealloc(PyObject *obj)
251251
return;
252252
}
253253
float_freelist->numfree++;
254-
Py_SET_TYPE(op, (PyTypeObject *)float_freelist->free_list);
255-
float_freelist->free_list = op;
254+
Py_SET_TYPE(op, (PyTypeObject *)float_freelist->items);
255+
float_freelist->items = op;
256256
OBJECT_STAT_INC(to_freelist);
257257
#else
258258
PyObject_Free(op);
@@ -1994,13 +1994,13 @@ _PyFloat_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalizati
19941994
{
19951995
#ifdef WITH_FREELISTS
19961996
struct _Py_float_freelist *state = &freelists->floats;
1997-
PyFloatObject *f = state->free_list;
1997+
PyFloatObject *f = state->items;
19981998
while (f != NULL) {
19991999
PyFloatObject *next = (PyFloatObject*) Py_TYPE(f);
20002000
PyObject_Free(f);
20012001
f = next;
20022002
}
2003-
state->free_list = NULL;
2003+
state->items = NULL;
20042004
if (is_finalization) {
20052005
state->numfree = -1;
20062006
}

Objects/listobject.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ _PyList_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalizatio
133133
#ifdef WITH_FREELISTS
134134
struct _Py_list_freelist *state = &freelists->lists;
135135
while (state->numfree > 0) {
136-
PyListObject *op = state->free_list[--state->numfree];
136+
PyListObject *op = state->items[--state->numfree];
137137
assert(PyList_CheckExact(op));
138138
PyObject_GC_Del(op);
139139
}
@@ -169,7 +169,7 @@ PyList_New(Py_ssize_t size)
169169
struct _Py_list_freelist *list_freelist = get_list_freelist();
170170
if (PyList_MAXFREELIST && list_freelist->numfree > 0) {
171171
list_freelist->numfree--;
172-
op = list_freelist->free_list[list_freelist->numfree];
172+
op = list_freelist->items[list_freelist->numfree];
173173
OBJECT_STAT_INC(from_freelist);
174174
_Py_NewReference((PyObject *)op);
175175
}
@@ -401,7 +401,7 @@ list_dealloc(PyObject *self)
401401
#ifdef WITH_FREELISTS
402402
struct _Py_list_freelist *list_freelist = get_list_freelist();
403403
if (list_freelist->numfree < PyList_MAXFREELIST && list_freelist->numfree >= 0 && PyList_CheckExact(op)) {
404-
list_freelist->free_list[list_freelist->numfree++] = op;
404+
list_freelist->items[list_freelist->numfree++] = op;
405405
OBJECT_STAT_INC(to_freelist);
406406
}
407407
else

Objects/tupleobject.c

+6-6
Original file line numberDiff line numberDiff line change
@@ -1134,11 +1134,11 @@ maybe_freelist_pop(Py_ssize_t size)
11341134
assert(size > 0);
11351135
if (size < PyTuple_MAXSAVESIZE) {
11361136
Py_ssize_t index = size - 1;
1137-
PyTupleObject *op = TUPLE_FREELIST.free_list[index];
1137+
PyTupleObject *op = TUPLE_FREELIST.items[index];
11381138
if (op != NULL) {
11391139
/* op is the head of a linked list, with the first item
11401140
pointing to the next node. Here we pop off the old head. */
1141-
TUPLE_FREELIST.free_list[index] = (PyTupleObject *) op->ob_item[0];
1141+
TUPLE_FREELIST.items[index] = (PyTupleObject *) op->ob_item[0];
11421142
TUPLE_FREELIST.numfree[index]--;
11431143
/* Inlined _PyObject_InitVar() without _PyType_HasFeature() test */
11441144
#ifdef Py_TRACE_REFS
@@ -1173,8 +1173,8 @@ maybe_freelist_push(PyTupleObject *op)
11731173
{
11741174
/* op is the head of a linked list, with the first item
11751175
pointing to the next node. Here we set op as the new head. */
1176-
op->ob_item[0] = (PyObject *) TUPLE_FREELIST.free_list[index];
1177-
TUPLE_FREELIST.free_list[index] = op;
1176+
op->ob_item[0] = (PyObject *) TUPLE_FREELIST.items[index];
1177+
TUPLE_FREELIST.items[index] = op;
11781178
TUPLE_FREELIST.numfree[index]++;
11791179
OBJECT_STAT_INC(to_freelist);
11801180
return 1;
@@ -1188,8 +1188,8 @@ maybe_freelist_clear(struct _Py_object_freelists *freelists, int fini)
11881188
{
11891189
#ifdef WITH_FREELISTS
11901190
for (Py_ssize_t i = 0; i < PyTuple_NFREELISTS; i++) {
1191-
PyTupleObject *p = TUPLE_FREELIST.free_list[i];
1192-
TUPLE_FREELIST.free_list[i] = NULL;
1191+
PyTupleObject *p = TUPLE_FREELIST.items[i];
1192+
TUPLE_FREELIST.items[i] = NULL;
11931193
TUPLE_FREELIST.numfree[i] = fini ? -1 : 0;
11941194
while (p) {
11951195
PyTupleObject *q = p;

Python/context.c

+6-6
Original file line numberDiff line numberDiff line change
@@ -344,8 +344,8 @@ _context_alloc(void)
344344
struct _Py_context_freelist *context_freelist = get_context_freelist();
345345
if (context_freelist->numfree > 0) {
346346
context_freelist->numfree--;
347-
ctx = context_freelist->freelist;
348-
context_freelist->freelist = (PyContext *)ctx->ctx_weakreflist;
347+
ctx = context_freelist->items;
348+
context_freelist->items = (PyContext *)ctx->ctx_weakreflist;
349349
OBJECT_STAT_INC(from_freelist);
350350
ctx->ctx_weakreflist = NULL;
351351
_Py_NewReference((PyObject *)ctx);
@@ -471,8 +471,8 @@ context_tp_dealloc(PyContext *self)
471471
struct _Py_context_freelist *context_freelist = get_context_freelist();
472472
if (context_freelist->numfree >= 0 && context_freelist->numfree < PyContext_MAXFREELIST) {
473473
context_freelist->numfree++;
474-
self->ctx_weakreflist = (PyObject *)context_freelist->freelist;
475-
context_freelist->freelist = self;
474+
self->ctx_weakreflist = (PyObject *)context_freelist->items;
475+
context_freelist->items = self;
476476
OBJECT_STAT_INC(to_freelist);
477477
}
478478
else
@@ -1272,8 +1272,8 @@ _PyContext_ClearFreeList(struct _Py_object_freelists *freelists, int is_finaliza
12721272
#ifdef WITH_FREELISTS
12731273
struct _Py_context_freelist *state = &freelists->contexts;
12741274
for (; state->numfree > 0; state->numfree--) {
1275-
PyContext *ctx = state->freelist;
1276-
state->freelist = (PyContext *)ctx->ctx_weakreflist;
1275+
PyContext *ctx = state->items;
1276+
state->items = (PyContext *)ctx->ctx_weakreflist;
12771277
ctx->ctx_weakreflist = NULL;
12781278
PyObject_GC_Del(ctx);
12791279
}

Python/object_stack.c

+10-10
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ _PyObjectStackChunk_New(void)
2121
_PyObjectStackChunk *buf;
2222
struct _Py_object_stack_freelist *obj_stack_freelist = get_object_stack_freelist();
2323
if (obj_stack_freelist->numfree > 0) {
24-
buf = obj_stack_freelist->free_list;
25-
obj_stack_freelist->free_list = buf->prev;
24+
buf = obj_stack_freelist->items;
25+
obj_stack_freelist->items = buf->prev;
2626
obj_stack_freelist->numfree--;
2727
}
2828
else {
@@ -47,8 +47,8 @@ _PyObjectStackChunk_Free(_PyObjectStackChunk *buf)
4747
if (obj_stack_freelist->numfree >= 0 &&
4848
obj_stack_freelist->numfree < _PyObjectStackChunk_MAXFREELIST)
4949
{
50-
buf->prev = obj_stack_freelist->free_list;
51-
obj_stack_freelist->free_list = buf;
50+
buf->prev = obj_stack_freelist->items;
51+
obj_stack_freelist->items = buf;
5252
obj_stack_freelist->numfree++;
5353
}
5454
else {
@@ -97,12 +97,12 @@ _PyObjectStackChunk_ClearFreeList(struct _Py_object_freelists *freelists, int is
9797
return;
9898
}
9999

100-
struct _Py_object_stack_freelist *state = &freelists->object_stacks;
101-
while (state->numfree > 0) {
102-
_PyObjectStackChunk *buf = state->free_list;
103-
state->free_list = buf->prev;
104-
state->numfree--;
100+
struct _Py_object_stack_freelist *freelist = &freelists->object_stacks;
101+
while (freelist->numfree > 0) {
102+
_PyObjectStackChunk *buf = freelist->items;
103+
freelist->items = buf->prev;
104+
freelist->numfree--;
105105
PyMem_RawFree(buf);
106106
}
107-
state->numfree = -1;
107+
freelist->numfree = -1;
108108
}

0 commit comments

Comments
 (0)