diff options
author | Sam Gross <colesbury@gmail.com> | 2024-07-22 16:08:27 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-22 16:08:27 (GMT) |
commit | 5716cc352940a5f8557a8191e873837aa619498a (patch) | |
tree | a9b1526a46acfe002950b9ad0d046f03c7cab5e9 /Objects | |
parent | 2408a8a22bd13d8f15172a2ecf8bbbc4355dcb3b (diff) | |
download | cpython-5716cc352940a5f8557a8191e873837aa619498a.zip cpython-5716cc352940a5f8557a8191e873837aa619498a.tar.gz cpython-5716cc352940a5f8557a8191e873837aa619498a.tar.bz2 |
gh-100240: Use a consistent implementation for freelists (#121934)
This combines and updates our freelist handling to use a consistent
implementation. Objects in the freelist are linked together using the
first word of memory block.
If configured with freelists disabled, these operations are essentially
no-ops.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/dictobject.c | 103 | ||||
-rw-r--r-- | Objects/floatobject.c | 68 | ||||
-rw-r--r-- | Objects/genobject.c | 108 | ||||
-rw-r--r-- | Objects/listobject.c | 59 | ||||
-rw-r--r-- | Objects/object.c | 55 | ||||
-rw-r--r-- | Objects/sliceobject.c | 39 | ||||
-rw-r--r-- | Objects/tupleobject.c | 117 |
7 files changed, 113 insertions, 436 deletions
diff --git a/Objects/dictobject.c b/Objects/dictobject.c index ca91da7..7310c3c 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -395,44 +395,6 @@ static int _PyObject_InlineValuesConsistencyCheck(PyObject *obj); #include "clinic/dictobject.c.h" -#ifdef WITH_FREELISTS -static struct _Py_dict_freelist * -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 - - -void -_PyDict_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization) -{ -#ifdef WITH_FREELISTS - 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); - } - struct _Py_dictkeys_freelist *keys_freelist = &freelists->dictkeys; - while (keys_freelist->numfree > 0) { - PyMem_Free(keys_freelist->items[--keys_freelist->numfree]); - } - if (is_finalization) { - freelist->numfree = -1; - keys_freelist->numfree = -1; - } -#endif -} - static inline Py_hash_t unicode_get_hash(PyObject *o) { @@ -445,12 +407,12 @@ void _PyDict_DebugMallocStats(FILE *out) { #ifdef WITH_FREELISTS - 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(); + _Py_FREELIST_SIZE(dicts), + sizeof(PyDictObject)); _PyDebugAllocatorStats(out, "free PyDictKeysObject", - dictkeys_freelist->numfree, sizeof(PyDictKeysObject)); + _Py_FREELIST_SIZE(dictkeys), + sizeof(PyDictKeysObject)); #endif } @@ -785,7 +747,6 @@ _PyDict_CheckConsistency(PyObject *op, int check_content) static PyDictKeysObject* new_keys_object(PyInterpreterState *interp, uint8_t log2_size, bool unicode) { - PyDictKeysObject *dk; Py_ssize_t usable; int log2_bytes; size_t entry_size = unicode ? sizeof(PyDictUnicodeEntry) : sizeof(PyDictKeyEntry); @@ -808,15 +769,11 @@ new_keys_object(PyInterpreterState *interp, uint8_t log2_size, bool unicode) log2_bytes = log2_size + 2; } -#ifdef WITH_FREELISTS - 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); + PyDictKeysObject *dk = NULL; + if (log2_size == PyDict_LOG_MINSIZE && unicode) { + dk = _Py_FREELIST_POP_MEM(dictkeys); } - else -#endif - { + if (dk == NULL) { dk = PyMem_Malloc(sizeof(PyDictKeysObject) + ((size_t)1 << log2_bytes) + entry_size * usable); @@ -852,18 +809,12 @@ free_keys_object(PyDictKeysObject *keys, bool use_qsbr) return; } #endif -#ifdef WITH_FREELISTS - struct _Py_dictkeys_freelist *freelist = get_dictkeys_freelist(); - if (DK_LOG_SIZE(keys) == PyDict_LOG_MINSIZE - && freelist->numfree < PyDict_MAXFREELIST - && freelist->numfree >= 0 - && DK_IS_UNICODE(keys)) { - freelist->items[freelist->numfree++] = keys; - OBJECT_STAT_INC(to_freelist); - return; + if (DK_LOG_SIZE(keys) == PyDict_LOG_MINSIZE && keys->dk_kind == DICT_KEYS_UNICODE) { + _Py_FREELIST_FREE(dictkeys, keys, PyMem_Free); + } + else { + PyMem_Free(keys); } -#endif - PyMem_Free(keys); } static size_t @@ -912,20 +863,9 @@ new_dict(PyInterpreterState *interp, PyDictKeysObject *keys, PyDictValues *values, Py_ssize_t used, int free_values_on_failure) { - PyDictObject *mp; assert(keys != NULL); -#ifdef WITH_FREELISTS - 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); - _Py_NewReference((PyObject *)mp); - } - else -#endif - { + PyDictObject *mp = _Py_FREELIST_POP(PyDictObject, dicts); + if (mp == NULL) { mp = PyObject_GC_New(PyDictObject, &PyDict_Type); if (mp == NULL) { dictkeys_decref(interp, keys, false); @@ -935,6 +875,7 @@ new_dict(PyInterpreterState *interp, return NULL; } } + assert(Py_IS_TYPE(mp, &PyDict_Type)); mp->ma_keys = keys; mp->ma_values = values; mp->ma_used = used; @@ -3153,16 +3094,10 @@ dict_dealloc(PyObject *self) assert(keys->dk_refcnt == 1 || keys == Py_EMPTY_KEYS); dictkeys_decref(interp, keys, false); } -#ifdef WITH_FREELISTS - struct _Py_dict_freelist *freelist = get_dict_freelist(); - if (freelist->numfree < PyDict_MAXFREELIST && freelist->numfree >=0 && - Py_IS_TYPE(mp, &PyDict_Type)) { - freelist->items[freelist->numfree++] = mp; - OBJECT_STAT_INC(to_freelist); + if (Py_IS_TYPE(mp, &PyDict_Type)) { + _Py_FREELIST_FREE(dicts, mp, Py_TYPE(mp)->tp_free); } - else -#endif - { + else { Py_TYPE(mp)->tp_free((PyObject *)mp); } Py_TRASHCAN_END diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 08d8d85..82f39de 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -7,8 +7,8 @@ #include "pycore_abstract.h" // _PyNumber_Index() #include "pycore_dtoa.h" // _Py_dg_dtoa() #include "pycore_floatobject.h" // _PyFloat_FormatAdvancedWriter() +#include "pycore_freelist.h" // _Py_FREELIST_FREE(), _Py_FREELIST_POP() #include "pycore_initconfig.h" // _PyStatus_OK() -#include "pycore_interp.h" // _Py_float_freelist #include "pycore_long.h" // _PyLong_GetOne() #include "pycore_modsupport.h" // _PyArg_NoKwnames() #include "pycore_object.h" // _PyObject_Init(), _PyDebugAllocatorStats() @@ -26,16 +26,6 @@ class float "PyObject *" "&PyFloat_Type" #include "clinic/floatobject.c.h" -#ifdef WITH_FREELISTS -static struct _Py_float_freelist * -get_float_freelist(void) -{ - struct _Py_object_freelists *freelists = _Py_object_freelists_GET(); - assert(freelists != NULL); - return &freelists->floats; -} -#endif - double PyFloat_GetMax(void) @@ -132,24 +122,14 @@ PyFloat_GetInfo(void) PyObject * PyFloat_FromDouble(double fval) { - PyFloatObject *op; -#ifdef WITH_FREELISTS - struct _Py_float_freelist *float_freelist = get_float_freelist(); - op = float_freelist->items; - if (op != NULL) { - float_freelist->items = (PyFloatObject *) Py_TYPE(op); - float_freelist->numfree--; - OBJECT_STAT_INC(from_freelist); - } - else -#endif - { + PyFloatObject *op = _Py_FREELIST_POP(PyFloatObject, floats); + if (op == NULL) { op = PyObject_Malloc(sizeof(PyFloatObject)); if (!op) { return PyErr_NoMemory(); } + _PyObject_Init((PyObject*)op, &PyFloat_Type); } - _PyObject_Init((PyObject*)op, &PyFloat_Type); op->ob_fval = fval; return (PyObject *) op; } @@ -248,20 +228,7 @@ void _PyFloat_ExactDealloc(PyObject *obj) { assert(PyFloat_CheckExact(obj)); - PyFloatObject *op = (PyFloatObject *)obj; -#ifdef WITH_FREELISTS - struct _Py_float_freelist *float_freelist = get_float_freelist(); - if (float_freelist->numfree >= PyFloat_MAXFREELIST || float_freelist->numfree < 0) { - PyObject_Free(op); - return; - } - float_freelist->numfree++; - Py_SET_TYPE(op, (PyTypeObject *)float_freelist->items); - float_freelist->items = op; - OBJECT_STAT_INC(to_freelist); -#else - PyObject_Free(op); -#endif + _Py_FREELIST_FREE(floats, obj, PyObject_Free); } static void @@ -1995,27 +1962,6 @@ _PyFloat_InitTypes(PyInterpreterState *interp) } void -_PyFloat_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization) -{ -#ifdef WITH_FREELISTS - struct _Py_float_freelist *state = &freelists->floats; - PyFloatObject *f = state->items; - while (f != NULL) { - PyFloatObject *next = (PyFloatObject*) Py_TYPE(f); - PyObject_Free(f); - f = next; - } - state->items = NULL; - if (is_finalization) { - state->numfree = -1; - } - else { - state->numfree = 0; - } -#endif -} - -void _PyFloat_FiniType(PyInterpreterState *interp) { _PyStructSequence_FiniBuiltin(interp, &FloatInfoType); @@ -2026,10 +1972,10 @@ void _PyFloat_DebugMallocStats(FILE *out) { #ifdef WITH_FREELISTS - struct _Py_float_freelist *float_freelist = get_float_freelist(); _PyDebugAllocatorStats(out, "free PyFloatObject", - float_freelist->numfree, sizeof(PyFloatObject)); + _Py_FREELIST_SIZE(floats), + sizeof(PyFloatObject)); #endif } diff --git a/Objects/genobject.c b/Objects/genobject.c index 37b4053..c204ac0 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -6,7 +6,7 @@ #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_ceval.h" // _PyEval_EvalFrame() #include "pycore_frame.h" // _PyInterpreterFrame -#include "pycore_freelist.h" // struct _Py_async_gen_freelist +#include "pycore_freelist.h" // _Py_FREELIST_FREE(), _Py_FREELIST_POP() #include "pycore_gc.h" // _PyGC_CLEAR_FINALIZED() #include "pycore_modsupport.h" // _PyArg_CheckPositional() #include "pycore_object.h" // _PyObject_GC_UNTRACK() @@ -1629,23 +1629,6 @@ PyTypeObject PyAsyncGen_Type = { }; -#ifdef WITH_FREELISTS -static struct _Py_async_gen_freelist * -get_async_gen_freelist(void) -{ - struct _Py_object_freelists *freelists = _Py_object_freelists_GET(); - return &freelists->async_gens; -} - -static struct _Py_async_gen_asend_freelist * -get_async_gen_asend_freelist(void) -{ - struct _Py_object_freelists *freelists = _Py_object_freelists_GET(); - return &freelists->async_gen_asends; -} -#endif - - PyObject * PyAsyncGen_New(PyFrameObject *f, PyObject *name, PyObject *qualname) { @@ -1662,36 +1645,6 @@ PyAsyncGen_New(PyFrameObject *f, PyObject *name, PyObject *qualname) return (PyObject*)o; } - -void -_PyAsyncGen_ClearFreeLists(struct _Py_object_freelists *freelist_state, int is_finalization) -{ -#ifdef WITH_FREELISTS - struct _Py_async_gen_freelist *freelist = &freelist_state->async_gens; - - while (freelist->numfree > 0) { - _PyAsyncGenWrappedValue *o; - o = freelist->items[--freelist->numfree]; - assert(_PyAsyncGenWrappedValue_CheckExact(o)); - PyObject_GC_Del(o); - } - - struct _Py_async_gen_asend_freelist *asend_freelist = &freelist_state->async_gen_asends; - - while (asend_freelist->numfree > 0) { - PyAsyncGenASend *o; - o = asend_freelist->items[--asend_freelist->numfree]; - assert(Py_IS_TYPE(o, &_PyAsyncGenASend_Type)); - PyObject_GC_Del(o); - } - - if (is_finalization) { - freelist->numfree = -1; - asend_freelist->numfree = -1; - } -#endif -} - static PyObject * async_gen_unwrap_value(PyAsyncGenObject *gen, PyObject *result) { @@ -1735,18 +1688,11 @@ async_gen_asend_dealloc(PyAsyncGenASend *o) _PyObject_GC_UNTRACK((PyObject *)o); Py_CLEAR(o->ags_gen); Py_CLEAR(o->ags_sendval); -#ifdef WITH_FREELISTS - struct _Py_async_gen_asend_freelist *freelist = get_async_gen_asend_freelist(); - if (freelist->numfree >= 0 && freelist->numfree < _PyAsyncGen_MAXFREELIST) { - assert(PyAsyncGenASend_CheckExact(o)); - _PyGC_CLEAR_FINALIZED((PyObject *)o); - freelist->items[freelist->numfree++] = o; - } - else -#endif - { - PyObject_GC_Del(o); - } + + assert(PyAsyncGenASend_CheckExact(o)); + _PyGC_CLEAR_FINALIZED((PyObject *)o); + + _Py_FREELIST_FREE(async_gen_asends, o, PyObject_GC_Del); } static int @@ -1936,17 +1882,8 @@ PyTypeObject _PyAsyncGenASend_Type = { static PyObject * async_gen_asend_new(PyAsyncGenObject *gen, PyObject *sendval) { - PyAsyncGenASend *o; -#ifdef WITH_FREELISTS - struct _Py_async_gen_asend_freelist *freelist = get_async_gen_asend_freelist(); - if (freelist->numfree > 0) { - freelist->numfree--; - o = freelist->items[freelist->numfree]; - _Py_NewReference((PyObject *)o); - } - else -#endif - { + PyAsyncGenASend *o = _Py_FREELIST_POP(PyAsyncGenASend, async_gen_asends); + if (o == NULL) { o = PyObject_GC_New(PyAsyncGenASend, &_PyAsyncGenASend_Type); if (o == NULL) { return NULL; @@ -1972,18 +1909,7 @@ async_gen_wrapped_val_dealloc(_PyAsyncGenWrappedValue *o) { _PyObject_GC_UNTRACK((PyObject *)o); Py_CLEAR(o->agw_val); -#ifdef WITH_FREELISTS - struct _Py_async_gen_freelist *freelist = get_async_gen_freelist(); - if (freelist->numfree >= 0 && freelist->numfree < _PyAsyncGen_MAXFREELIST) { - assert(_PyAsyncGenWrappedValue_CheckExact(o)); - freelist->items[freelist->numfree++] = o; - OBJECT_STAT_INC(to_freelist); - } - else -#endif - { - PyObject_GC_Del(o); - } + _Py_FREELIST_FREE(async_gens, o, PyObject_GC_Del); } @@ -2042,27 +1968,17 @@ PyTypeObject _PyAsyncGenWrappedValue_Type = { PyObject * _PyAsyncGenValueWrapperNew(PyThreadState *tstate, PyObject *val) { - _PyAsyncGenWrappedValue *o; assert(val); -#ifdef WITH_FREELISTS - struct _Py_async_gen_freelist *freelist = get_async_gen_freelist(); - if (freelist->numfree > 0) { - freelist->numfree--; - o = freelist->items[freelist->numfree]; - OBJECT_STAT_INC(from_freelist); - assert(_PyAsyncGenWrappedValue_CheckExact(o)); - _Py_NewReference((PyObject*)o); - } - else -#endif - { + _PyAsyncGenWrappedValue *o = _Py_FREELIST_POP(_PyAsyncGenWrappedValue, async_gens); + if (o == NULL) { o = PyObject_GC_New(_PyAsyncGenWrappedValue, &_PyAsyncGenWrappedValue_Type); if (o == NULL) { return NULL; } } + assert(_PyAsyncGenWrappedValue_CheckExact(o)); o->agw_val = Py_NewRef(val); _PyObject_GC_TRACK((PyObject*)o); return (PyObject*)o; diff --git a/Objects/listobject.c b/Objects/listobject.c index f29f58d..4d654c2 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -4,6 +4,7 @@ #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_ceval.h" // _PyEval_GetBuiltin() #include "pycore_dict.h" // _PyDictViewObject +#include "pycore_freelist.h" // _Py_FREELIST_FREE(), _Py_FREELIST_POP() #include "pycore_pyatomic_ft_wrappers.h" #include "pycore_interp.h" // PyInterpreterState.list #include "pycore_list.h" // struct _Py_list_freelist, _PyListIterObject @@ -23,16 +24,6 @@ class list "PyListObject *" "&PyList_Type" _Py_DECLARE_STR(list_err, "list index out of range"); -#ifdef WITH_FREELISTS -static struct _Py_list_freelist * -get_list_freelist(void) -{ - struct _Py_object_freelists *freelists = _Py_object_freelists_GET(); - assert(freelists != NULL); - return &freelists->lists; -} -#endif - #ifdef Py_GIL_DISABLED typedef struct { Py_ssize_t allocated; @@ -205,55 +196,28 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size) return 0; } -void -_PyList_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization) -{ -#ifdef WITH_FREELISTS - struct _Py_list_freelist *state = &freelists->lists; - while (state->numfree > 0) { - PyListObject *op = state->items[--state->numfree]; - assert(PyList_CheckExact(op)); - PyObject_GC_Del(op); - } - if (is_finalization) { - state->numfree = -1; - } -#endif -} - /* Print summary info about the state of the optimized allocator */ void _PyList_DebugMallocStats(FILE *out) { #ifdef WITH_FREELISTS - struct _Py_list_freelist *list_freelist = get_list_freelist(); _PyDebugAllocatorStats(out, "free PyListObject", - list_freelist->numfree, sizeof(PyListObject)); + _Py_FREELIST_SIZE(lists), + sizeof(PyListObject)); #endif } PyObject * PyList_New(Py_ssize_t size) { - PyListObject *op; - if (size < 0) { PyErr_BadInternalCall(); return NULL; } -#ifdef WITH_FREELISTS - struct _Py_list_freelist *list_freelist = get_list_freelist(); - if (PyList_MAXFREELIST && list_freelist->numfree > 0) { - list_freelist->numfree--; - op = list_freelist->items[list_freelist->numfree]; - OBJECT_STAT_INC(from_freelist); - _Py_NewReference((PyObject *)op); - } - else -#endif - { + PyListObject *op = _Py_FREELIST_POP(PyListObject, lists); + if (op == NULL) { op = PyObject_GC_New(PyListObject, &PyList_Type); if (op == NULL) { return NULL; @@ -548,16 +512,11 @@ list_dealloc(PyObject *self) } free_list_items(op->ob_item, false); } -#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->items[list_freelist->numfree++] = op; - OBJECT_STAT_INC(to_freelist); + if (PyList_CheckExact(op)) { + _Py_FREELIST_FREE(lists, op, PyObject_GC_Del); } - else -#endif - { - Py_TYPE(op)->tp_free((PyObject *)op); + else { + PyObject_GC_Del(op); } Py_TRASHCAN_END } diff --git a/Objects/object.c b/Objects/object.c index e2f96af..6d6bb87 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -10,6 +10,7 @@ #include "pycore_descrobject.h" // _PyMethodWrapper_Type #include "pycore_dict.h" // _PyObject_MakeDictFromInstanceAttributes() #include "pycore_floatobject.h" // _PyFloat_DebugMallocStats() +#include "pycore_freelist.h" // _PyObject_ClearFreeLists() #include "pycore_initconfig.h" // _PyStatus_EXCEPTION() #include "pycore_instruction_sequence.h" // _PyInstructionSequence_Type #include "pycore_hashtable.h" // _Py_hashtable_new() @@ -808,20 +809,54 @@ PyObject_Bytes(PyObject *v) return PyBytes_FromObject(v); } +#ifdef WITH_FREELISTS +static void +clear_freelist(struct _Py_freelist *freelist, int is_finalization, + freefunc dofree) +{ + void *ptr; + while ((ptr = _PyFreeList_PopNoStats(freelist)) != NULL) { + dofree(ptr); + } + assert(freelist->size == 0 || freelist->size == -1); + assert(freelist->freelist == NULL); + if (is_finalization) { + freelist->size = -1; + } +} + +static void +free_object(void *obj) +{ + PyObject *op = (PyObject *)obj; + Py_TYPE(op)->tp_free(op); +} + +#endif + void -_PyObject_ClearFreeLists(struct _Py_object_freelists *freelists, int is_finalization) +_PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization) { +#ifdef WITH_FREELISTS // 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() - _PyFloat_ClearFreeList(freelists, is_finalization); - _PyTuple_ClearFreeList(freelists, is_finalization); - _PyList_ClearFreeList(freelists, is_finalization); - _PyDict_ClearFreeList(freelists, is_finalization); - _PyContext_ClearFreeList(freelists, is_finalization); - _PyAsyncGen_ClearFreeLists(freelists, is_finalization); - // Only be cleared if is_finalization is true. - _PyObjectStackChunk_ClearFreeList(freelists, is_finalization); - _PySlice_ClearFreeList(freelists, is_finalization); + clear_freelist(&freelists->floats, is_finalization, free_object); + for (Py_ssize_t i = 0; i < PyTuple_MAXSAVESIZE; i++) { + clear_freelist(&freelists->tuples[i], is_finalization, free_object); + } + clear_freelist(&freelists->lists, is_finalization, free_object); + clear_freelist(&freelists->dicts, is_finalization, free_object); + clear_freelist(&freelists->dictkeys, is_finalization, PyMem_Free); + clear_freelist(&freelists->slices, is_finalization, free_object); + clear_freelist(&freelists->contexts, is_finalization, free_object); + clear_freelist(&freelists->async_gens, is_finalization, free_object); + clear_freelist(&freelists->async_gen_asends, is_finalization, free_object); + if (is_finalization) { + // Only clear object stack chunks during finalization. We use object + // stacks during GC, so emptying the free-list is counterproductive. + clear_freelist(&freelists->object_stack_chunks, 1, PyMem_RawFree); + } +#endif } /* diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index 245bea9..1b6d359 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -15,6 +15,7 @@ this type and there is exactly one in existence. #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() +#include "pycore_freelist.h" // _Py_FREELIST_FREE(), _Py_FREELIST_POP() #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_modsupport.h" // _PyArg_NoKeywords() #include "pycore_object.h" // _PyObject_GC_TRACK() @@ -108,20 +109,6 @@ PyObject _Py_EllipsisObject = _PyObject_HEAD_INIT(&PyEllipsis_Type); /* Slice object implementation */ -void _PySlice_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization) -{ - if (!is_finalization) { - return; - } -#ifdef WITH_FREELISTS - PySliceObject *obj = freelists->slices.slice_cache; - if (obj != NULL) { - freelists->slices.slice_cache = NULL; - PyObject_GC_Del(obj); - } -#endif -} - /* start, stop, and step are python objects with None indicating no index is present. */ @@ -130,17 +117,8 @@ static PySliceObject * _PyBuildSlice_Consume2(PyObject *start, PyObject *stop, PyObject *step) { assert(start != NULL && stop != NULL && step != NULL); - PySliceObject *obj; -#ifdef WITH_FREELISTS - struct _Py_object_freelists *freelists = _Py_object_freelists_GET(); - if (freelists->slices.slice_cache != NULL) { - obj = freelists->slices.slice_cache; - freelists->slices.slice_cache = NULL; - _Py_NewReference((PyObject *)obj); - } - else -#endif - { + PySliceObject *obj = _Py_FREELIST_POP(PySliceObject, slices); + if (obj == NULL) { obj = PyObject_GC_New(PySliceObject, &PySlice_Type); if (obj == NULL) { goto error; @@ -369,16 +347,7 @@ slice_dealloc(PySliceObject *r) Py_DECREF(r->step); Py_DECREF(r->start); Py_DECREF(r->stop); -#ifdef WITH_FREELISTS - struct _Py_object_freelists *freelists = _Py_object_freelists_GET(); - if (freelists->slices.slice_cache == NULL) { - freelists->slices.slice_cache = r; - } - else -#endif - { - PyObject_GC_Del(r); - } + _Py_FREELIST_FREE(slices, r, PyObject_GC_Del); } static PyObject * diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 3704d09..bd6e568 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -4,6 +4,7 @@ #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_ceval.h" // _PyEval_GetBuiltin() +#include "pycore_freelist.h" // _Py_FREELIST_PUSH(), _Py_FREELIST_POP() #include "pycore_gc.h" // _PyObject_GC_IS_TRACKED() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_modsupport.h" // _PyArg_NoKwnames() @@ -17,7 +18,6 @@ class tuple "PyTupleObject *" "&PyTuple_Type" #include "clinic/tupleobject.c.h" -static inline PyTupleObject * maybe_freelist_pop(Py_ssize_t); static inline int maybe_freelist_push(PyTupleObject *); @@ -38,22 +38,20 @@ tuple_alloc(Py_ssize_t size) PyErr_BadInternalCall(); return NULL; } -#ifdef Py_DEBUG assert(size != 0); // The empty tuple is statically allocated. -#endif - - PyTupleObject *op = maybe_freelist_pop(size); - if (op == NULL) { - /* Check for overflow */ - if ((size_t)size > ((size_t)PY_SSIZE_T_MAX - (sizeof(PyTupleObject) - - sizeof(PyObject *))) / sizeof(PyObject *)) { - return (PyTupleObject *)PyErr_NoMemory(); + Py_ssize_t index = size - 1; + if (index < PyTuple_MAXSAVESIZE) { + PyTupleObject *op = _Py_FREELIST_POP(PyTupleObject, tuples[index]); + if (op != NULL) { + return op; } - op = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, size); - if (op == NULL) - return NULL; } - return op; + /* Check for overflow */ + if ((size_t)size > ((size_t)PY_SSIZE_T_MAX - (sizeof(PyTupleObject) - + sizeof(PyObject *))) / sizeof(PyObject *)) { + return (PyTupleObject *)PyErr_NoMemory(); + } + return PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, size); } // The empty tuple singleton is not tracked by the GC. @@ -982,16 +980,6 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize) return 0; } - -static void maybe_freelist_clear(struct _Py_object_freelists *, int); - - -void -_PyTuple_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization) -{ - maybe_freelist_clear(freelists, is_finalization); -} - /*********************** Tuple Iterator **************************/ @@ -1141,102 +1129,31 @@ tuple_iter(PyObject *seq) * freelists * *************/ -#define TUPLE_FREELIST (freelists->tuples) -#define FREELIST_FINALIZED (TUPLE_FREELIST.numfree[0] < 0) - -static inline PyTupleObject * -maybe_freelist_pop(Py_ssize_t size) -{ -#ifdef WITH_FREELISTS - struct _Py_object_freelists *freelists = _Py_object_freelists_GET(); - if (size == 0) { - return NULL; - } - assert(size > 0); - if (size <= PyTuple_MAXSAVESIZE) { - Py_ssize_t index = size - 1; - 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.items[index] = (PyTupleObject *) op->ob_item[0]; - TUPLE_FREELIST.numfree[index]--; - /* Inlined _PyObject_InitVar() without _PyType_HasFeature() test */ -#ifdef Py_TRACE_REFS - /* maybe_freelist_push() ensures these were already set. */ - // XXX Can we drop these? See commit 68055ce6fe01 (GvR, Dec 1998). - Py_SET_SIZE(op, size); - Py_SET_TYPE(op, &PyTuple_Type); -#endif - _Py_NewReference((PyObject *)op); - /* END inlined _PyObject_InitVar() */ - OBJECT_STAT_INC(from_freelist); - return op; - } - } -#endif - return NULL; -} - static inline int maybe_freelist_push(PyTupleObject *op) { -#ifdef WITH_FREELISTS - struct _Py_object_freelists *freelists = _Py_object_freelists_GET(); - if (Py_SIZE(op) == 0) { + if (!Py_IS_TYPE(op, &PyTuple_Type)) { return 0; } Py_ssize_t index = Py_SIZE(op) - 1; - if (index < PyTuple_NFREELISTS - && TUPLE_FREELIST.numfree[index] < PyTuple_MAXFREELIST - && TUPLE_FREELIST.numfree[index] >= 0 - && Py_IS_TYPE(op, &PyTuple_Type)) - { - /* 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.items[index]; - TUPLE_FREELIST.items[index] = op; - TUPLE_FREELIST.numfree[index]++; - OBJECT_STAT_INC(to_freelist); - return 1; + if (index < PyTuple_MAXSAVESIZE) { + return _Py_FREELIST_PUSH(tuples[index], op, Py_tuple_MAXFREELIST); } -#endif return 0; } -static void -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.items[i]; - TUPLE_FREELIST.items[i] = NULL; - TUPLE_FREELIST.numfree[i] = fini ? -1 : 0; - while (p) { - PyTupleObject *q = p; - p = (PyTupleObject *)(p->ob_item[0]); - PyObject_GC_Del(q); - } - } -#endif -} - /* Print summary info about the state of the optimized allocator */ void _PyTuple_DebugMallocStats(FILE *out) { #ifdef WITH_FREELISTS - struct _Py_object_freelists *freelists = _Py_object_freelists_GET(); - for (int i = 0; i < PyTuple_NFREELISTS; i++) { + for (int i = 0; i < PyTuple_MAXSAVESIZE; i++) { int len = i + 1; char buf[128]; PyOS_snprintf(buf, sizeof(buf), "free %d-sized PyTupleObject", len); - _PyDebugAllocatorStats(out, buf, TUPLE_FREELIST.numfree[i], + _PyDebugAllocatorStats(out, buf, _Py_FREELIST_SIZE(tuples[i]), _PyObject_VAR_SIZE(&PyTuple_Type, len)); } #endif } - -#undef STATE -#undef FREELIST_FINALIZED |