# error "this header requires Py_BUILD_CORE define"
#endif
-#include "pycore_freelist.h" // _PyFreeListState
#include "pycore_hamt.h" // PyHamtObject
# error "this header requires Py_BUILD_CORE define"
#endif
-#include "pycore_freelist.h" // _PyFreeListState
#include "pycore_object.h" // PyManagedDictPointer
#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_SSIZE_ACQUIRE
# error "this header requires Py_BUILD_CORE define"
#endif
-#include "pycore_freelist.h" // _PyFreeListState
#include "pycore_unicodeobject.h" // _PyUnicodeWriter
/* runtime lifecycle */
# error "this header requires Py_BUILD_CORE define"
#endif
-// PyTuple_MAXSAVESIZE - largest tuple to save on free list
-// PyTuple_MAXFREELIST - maximum number of tuples of each size to save
-
-#ifdef WITH_FREELISTS
-// with freelists
-# define PyTuple_MAXSAVESIZE 20
-# define PyTuple_NFREELISTS PyTuple_MAXSAVESIZE
-# define PyTuple_MAXFREELIST 2000
-# define PyList_MAXFREELIST 80
-# define PyDict_MAXFREELIST 80
-# define PyFloat_MAXFREELIST 100
-# define PyContext_MAXFREELIST 255
-# define _PyAsyncGen_MAXFREELIST 80
-# define _PyObjectStackChunk_MAXFREELIST 4
-#else
-# define PyTuple_NFREELISTS 0
-# define PyTuple_MAXFREELIST 0
-# define PyList_MAXFREELIST 0
-# define PyDict_MAXFREELIST 0
-# define PyFloat_MAXFREELIST 0
-# define PyContext_MAXFREELIST 0
-# define _PyAsyncGen_MAXFREELIST 0
-# define _PyObjectStackChunk_MAXFREELIST 0
-#endif
-
-struct _Py_list_freelist {
-#ifdef WITH_FREELISTS
- PyListObject *items[PyList_MAXFREELIST];
- int numfree;
+#include "pycore_freelist_state.h" // struct _Py_freelists
+#include "pycore_object.h" // _PyObject_IS_GC
+#include "pycore_pystate.h" // _PyThreadState_GET
+#include "pycore_code.h" // OBJECT_STAT_INC
+
+static inline struct _Py_freelists *
+_Py_freelists_GET(void)
+{
+ PyThreadState *tstate = _PyThreadState_GET();
+#ifdef Py_DEBUG
+ _Py_EnsureTstateNotNULL(tstate);
#endif
-};
-
-struct _Py_tuple_freelist {
-#if WITH_FREELISTS
- /* There is one freelist for each size from 1 to PyTuple_MAXSAVESIZE.
- The empty tuple is handled separately.
- Each tuple stored in the array is the head of the linked list
- (and the next available tuple) for that size. The actual tuple
- 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 *items[PyTuple_NFREELISTS];
- int numfree[PyTuple_NFREELISTS];
+#ifdef Py_GIL_DISABLED
+ return &((_PyThreadStateImpl*)tstate)->freelists;
#else
- char _unused; // Empty structs are not allowed.
-#endif
-};
-
-struct _Py_float_freelist {
-#ifdef WITH_FREELISTS
- /* Special free list
- free_list is a singly-linked list of available PyFloatObjects,
- linked via abuse of their ob_type members. */
- int numfree;
- PyFloatObject *items;
-#endif
-};
-
-struct _Py_dict_freelist {
-#ifdef WITH_FREELISTS
- /* Dictionary reuse scheme to save calls to malloc and free */
- PyDictObject *items[PyDict_MAXFREELIST];
- int numfree;
+ return &tstate->interp->object_state.freelists;
#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;
-#endif
-};
+#ifndef WITH_FREELISTS
+#define _Py_FREELIST_FREE(NAME, op, freefunc) freefunc(op)
+#define _Py_FREELIST_PUSH(NAME, op, limit) (0)
+#define _Py_FREELIST_POP(TYPE, NAME) (NULL)
+#define _Py_FREELIST_POP_MEM(NAME) (NULL)
+#define _Py_FREELIST_SIZE(NAME) (0)
+#else
+// Pushes `op` to the freelist, calls `freefunc` if the freelist is full
+#define _Py_FREELIST_FREE(NAME, op, freefunc) \
+ _PyFreeList_Free(&_Py_freelists_GET()->NAME, _PyObject_CAST(op), \
+ Py_ ## NAME ## _MAXFREELIST, freefunc)
+// Pushes `op` to the freelist, returns 1 if successful, 0 if the freelist is full
+#define _Py_FREELIST_PUSH(NAME, op, limit) \
+ _PyFreeList_Push(&_Py_freelists_GET()->NAME, _PyObject_CAST(op), limit)
+
+// Pops a PyObject from the freelist, returns NULL if the freelist is empty.
+#define _Py_FREELIST_POP(TYPE, NAME) \
+ _Py_CAST(TYPE*, _PyFreeList_Pop(&_Py_freelists_GET()->NAME))
+
+// Pops a non-PyObject data structure from the freelist, returns NULL if the
+// freelist is empty.
+#define _Py_FREELIST_POP_MEM(NAME) \
+ _PyFreeList_PopMem(&_Py_freelists_GET()->NAME)
+
+#define _Py_FREELIST_SIZE(NAME) (int)((_Py_freelists_GET()->NAME).size)
+
+static inline int
+_PyFreeList_Push(struct _Py_freelist *fl, void *obj, Py_ssize_t maxsize)
+{
+ if (fl->size < maxsize && fl->size >= 0) {
+ *(void **)obj = fl->freelist;
+ fl->freelist = obj;
+ fl->size++;
+ OBJECT_STAT_INC(to_freelist);
+ return 1;
+ }
+ return 0;
+}
-struct _Py_slice_freelist {
-#ifdef WITH_FREELISTS
- /* Using a cache is very effective since typically only a single slice is
- created and then deleted again. */
- PySliceObject *slice_cache;
-#endif
-};
+static inline void
+_PyFreeList_Free(struct _Py_freelist *fl, void *obj, Py_ssize_t maxsize,
+ freefunc dofree)
+{
+ if (!_PyFreeList_Push(fl, obj, maxsize)) {
+ dofree(obj);
+ }
+}
-struct _Py_context_freelist {
-#ifdef WITH_FREELISTS
- // List of free PyContext objects
- PyContext *items;
- int numfree;
-#endif
-};
+static inline void *
+_PyFreeList_PopNoStats(struct _Py_freelist *fl)
+{
+ void *obj = fl->freelist;
+ if (obj != NULL) {
+ assert(fl->size > 0);
+ fl->freelist = *(void **)obj;
+ fl->size--;
+ }
+ return obj;
+}
-struct _Py_async_gen_freelist {
-#ifdef WITH_FREELISTS
- /* Freelists boost performance 6-10%; they also reduce memory
- fragmentation, as _PyAsyncGenWrappedValue and PyAsyncGenASend
- are short-living objects that are instantiated for every
- __anext__() call. */
- struct _PyAsyncGenWrappedValue* items[_PyAsyncGen_MAXFREELIST];
- int numfree;
-#endif
-};
+static inline PyObject *
+_PyFreeList_Pop(struct _Py_freelist *fl)
+{
+ PyObject *op = _PyFreeList_PopNoStats(fl);
+ if (op != NULL) {
+ OBJECT_STAT_INC(from_freelist);
+ _Py_NewReference(op);
+ }
+ return op;
+}
-struct _Py_async_gen_asend_freelist {
-#ifdef WITH_FREELISTS
- struct PyAsyncGenASend* items[_PyAsyncGen_MAXFREELIST];
- int numfree;
+static inline void *
+_PyFreeList_PopMem(struct _Py_freelist *fl)
+{
+ void *op = _PyFreeList_PopNoStats(fl);
+ if (op != NULL) {
+ OBJECT_STAT_INC(from_freelist);
+ }
+ return op;
+}
#endif
-};
-
-struct _PyObjectStackChunk;
-
-struct _Py_object_stack_freelist {
- struct _PyObjectStackChunk *items;
- Py_ssize_t numfree;
-};
-
-struct _Py_object_freelists {
- struct _Py_float_freelist floats;
- 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;
- struct _Py_async_gen_asend_freelist async_gen_asends;
- struct _Py_object_stack_freelist object_stacks;
-};
-extern void _PyObject_ClearFreeLists(struct _Py_object_freelists *freelists, int is_finalization);
-extern void _PyTuple_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization);
-extern void _PyFloat_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization);
-extern void _PyList_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization);
-extern void _PySlice_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization);
-extern void _PyDict_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization);
-extern void _PyAsyncGen_ClearFreeLists(struct _Py_object_freelists *freelists, int is_finalization);
-extern void _PyContext_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization);
-extern void _PyObjectStackChunk_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization);
+extern void _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization);
#ifdef __cplusplus
}
--- /dev/null
+#ifndef Py_INTERNAL_FREELIST_STATE_H
+#define Py_INTERNAL_FREELIST_STATE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef Py_BUILD_CORE
+# error "this header requires Py_BUILD_CORE define"
+#endif
+
+#ifdef WITH_FREELISTS
+// with freelists
+# define PyTuple_MAXSAVESIZE 20 // Largest tuple to save on freelist
+# define Py_tuple_MAXFREELIST 2000 // Maximum number of tuples of each size to save
+# define Py_lists_MAXFREELIST 80
+# define Py_dicts_MAXFREELIST 80
+# define Py_dictkeys_MAXFREELIST 80
+# define Py_floats_MAXFREELIST 100
+# define Py_slices_MAXFREELIST 1
+# define Py_contexts_MAXFREELIST 255
+# define Py_async_gens_MAXFREELIST 80
+# define Py_async_gen_asends_MAXFREELIST 80
+# define Py_object_stack_chunks_MAXFREELIST 4
+#else
+# define PyTuple_MAXSAVESIZE 0
+#endif
+
+// A generic freelist of either PyObjects or other data structures.
+struct _Py_freelist {
+ // Entries are linked together using the first word of the the object.
+ // For PyObjects, this overlaps with the `ob_refcnt` field or the `ob_tid`
+ // field.
+ void *freelist;
+
+ // The number of items in the free list or -1 if the free list is disabled
+ Py_ssize_t size;
+};
+
+struct _Py_freelists {
+#ifdef WITH_FREELISTS
+ struct _Py_freelist floats;
+ struct _Py_freelist tuples[PyTuple_MAXSAVESIZE];
+ struct _Py_freelist lists;
+ struct _Py_freelist dicts;
+ struct _Py_freelist dictkeys;
+ struct _Py_freelist slices;
+ struct _Py_freelist contexts;
+ struct _Py_freelist async_gens;
+ struct _Py_freelist async_gen_asends;
+ struct _Py_freelist object_stack_chunks;
+#else
+ char _unused; // Empty structs are not allowed.
+#endif
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_INTERNAL_FREELIST_STATE_H */
# error "this header requires Py_BUILD_CORE define"
#endif
-#include "pycore_freelist.h" // _PyFreeListState
-
/* GC information is stored BEFORE the object structure. */
typedef struct {
// Pointer to next object in the list.
# error "this header requires Py_BUILD_CORE define"
#endif
-#include "pycore_freelist.h" // _PyFreeListState
-
PyAPI_FUNC(PyObject*) _PyList_Extend(PyListObject *, PyObject *);
extern void _PyList_DebugMallocStats(FILE *out);
#ifndef Py_INTERNAL_OBJECT_STACK_H
#define Py_INTERNAL_OBJECT_STACK_H
-#include "pycore_freelist.h" // _PyFreeListState
-
#ifdef __cplusplus
extern "C" {
#endif
# error "this header requires Py_BUILD_CORE define"
#endif
-#include "pycore_freelist.h" // _PyObject_freelists
-#include "pycore_hashtable.h" // _Py_hashtable_t
+#include "pycore_freelist_state.h" // _Py_freelists
+#include "pycore_hashtable.h" // _Py_hashtable_t
struct _py_object_runtime_state {
#ifdef Py_REF_DEBUG
struct _py_object_state {
#if !defined(Py_GIL_DISABLED)
- struct _Py_object_freelists freelists;
+ struct _Py_freelists freelists;
#endif
#ifdef Py_REF_DEBUG
Py_ssize_t reftotal;
# error "this header requires Py_BUILD_CORE define"
#endif
-#include "pycore_freelist.h" // _PyFreeListState
#include "pycore_runtime.h" // _PyRuntime
#include "pycore_tstate.h" // _PyThreadStateImpl
-
// Values for PyThreadState.state. A thread must be in the "attached" state
// before calling most Python APIs. If the GIL is enabled, then "attached"
// implies that the thread holds the GIL and "detached" implies that the
// See also PyInterpreterState_Get() and _PyInterpreterState_GET().
extern PyInterpreterState* _PyGILState_GetInterpreterStateUnsafe(void);
-static inline struct _Py_object_freelists* _Py_object_freelists_GET(void)
-{
- PyThreadState *tstate = _PyThreadState_GET();
-#ifdef Py_DEBUG
- _Py_EnsureTstateNotNULL(tstate);
-#endif
-
-#ifdef Py_GIL_DISABLED
- return &((_PyThreadStateImpl*)tstate)->freelists;
-#else
- return &tstate->interp->object_state.freelists;
-#endif
-}
-
#ifdef __cplusplus
}
#endif
# error "this header requires Py_BUILD_CORE define"
#endif
-#include "pycore_brc.h" // struct _brc_thread_state
-#include "pycore_freelist.h" // struct _Py_freelist_state
-#include "pycore_mimalloc.h" // struct _mimalloc_thread_state
-#include "pycore_qsbr.h" // struct qsbr
+#include "pycore_brc.h" // struct _brc_thread_state
+#include "pycore_freelist_state.h" // struct _Py_freelists
+#include "pycore_mimalloc.h" // struct _mimalloc_thread_state
+#include "pycore_qsbr.h" // struct qsbr
// Every PyThreadState is actually allocated as a _PyThreadStateImpl. The
#ifdef Py_GIL_DISABLED
struct _gc_thread_state gc;
struct _mimalloc_thread_state mimalloc;
- struct _Py_object_freelists freelists;
+ struct _Py_freelists freelists;
struct _brc_thread_state brc;
#endif
$(srcdir)/Include/internal/pycore_format.h \
$(srcdir)/Include/internal/pycore_frame.h \
$(srcdir)/Include/internal/pycore_freelist.h \
+ $(srcdir)/Include/internal/pycore_freelist_state.h \
$(srcdir)/Include/internal/pycore_function.h \
$(srcdir)/Include/internal/pycore_gc.h \
$(srcdir)/Include/internal/pycore_genobject.h \
#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)
{
_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
}
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);
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);
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
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);
return NULL;
}
}
+ assert(Py_IS_TYPE(mp, &PyDict_Type));
mp->ma_keys = keys;
mp->ma_values = values;
mp->ma_used = used;
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
#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()
#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)
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;
}
_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
return _PyStatus_OK();
}
-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)
{
_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
}
#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()
};
-#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)
{
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)
{
_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
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;
{
_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);
}
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;
#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
_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;
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;
}
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
}
#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()
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
}
/*
#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()
/* 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.
*/
_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;
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 *
#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()
#include "clinic/tupleobject.c.h"
-static inline PyTupleObject * maybe_freelist_pop(Py_ssize_t);
static inline int maybe_freelist_push(PyTupleObject *);
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.
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 **************************/
* 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
<ClInclude Include="..\Include\internal\pycore_format.h" />
<ClInclude Include="..\Include\internal\pycore_frame.h" />
<ClInclude Include="..\Include\internal\pycore_freelist.h" />
+ <ClInclude Include="..\Include\internal\pycore_freelist_state.h" />
<ClInclude Include="..\Include\internal\pycore_function.h" />
<ClInclude Include="..\Include\internal\pycore_gc.h" />
<ClInclude Include="..\Include\internal\pycore_genobject.h" />
<ClInclude Include="..\Include\internal\pycore_freelist.h">
<Filter>Include\internal</Filter>
</ClInclude>
+ <ClInclude Include="..\Include\internal\pycore_freelist_state.h">
+ <Filter>Include\internal</Filter>
+ </ClInclude>
<ClInclude Include="..\Include\internal\pycore_function.h">
<Filter>Include\internal</Filter>
</ClInclude>
#include "Python.h"
#include "pycore_call.h" // _PyObject_VectorcallTstate()
#include "pycore_context.h"
+#include "pycore_freelist.h" // _Py_FREELIST_FREE(), _Py_FREELIST_POP()
#include "pycore_gc.h" // _PyObject_GC_MAY_BE_TRACKED()
#include "pycore_hamt.h"
#include "pycore_initconfig.h" // _PyStatus_OK()
contextvar_del(PyContextVar *var);
-#ifdef WITH_FREELISTS
-static struct _Py_context_freelist *
-get_context_freelist(void)
-{
- struct _Py_object_freelists *freelists = _Py_object_freelists_GET();
- return &freelists->contexts;
-}
-#endif
-
-
PyObject *
_PyContext_NewHamtForTests(void)
{
static inline PyContext *
_context_alloc(void)
{
- PyContext *ctx;
-#ifdef WITH_FREELISTS
- struct _Py_context_freelist *context_freelist = get_context_freelist();
- if (context_freelist->numfree > 0) {
- context_freelist->numfree--;
- ctx = context_freelist->items;
- context_freelist->items = (PyContext *)ctx->ctx_weakreflist;
- OBJECT_STAT_INC(from_freelist);
- ctx->ctx_weakreflist = NULL;
- _Py_NewReference((PyObject *)ctx);
- }
- else
-#endif
- {
+ PyContext *ctx = _Py_FREELIST_POP(PyContext, contexts);
+ if (ctx == NULL) {
ctx = PyObject_GC_New(PyContext, &PyContext_Type);
if (ctx == NULL) {
return NULL;
}
(void)context_tp_clear(self);
-#ifdef WITH_FREELISTS
- 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->items;
- context_freelist->items = self;
- OBJECT_STAT_INC(to_freelist);
- }
- else
-#endif
- {
- Py_TYPE(self)->tp_free(self);
- }
+ _Py_FREELIST_FREE(contexts, self, Py_TYPE(self)->tp_free);
}
static PyObject *
///////////////////////////
-void
-_PyContext_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization)
-{
-#ifdef WITH_FREELISTS
- struct _Py_context_freelist *state = &freelists->contexts;
- for (; state->numfree > 0; state->numfree--) {
- PyContext *ctx = state->items;
- state->items = (PyContext *)ctx->ctx_weakreflist;
- ctx->ctx_weakreflist = NULL;
- PyObject_GC_Del(ctx);
- }
- if (is_finalization) {
- state->numfree = -1;
- }
-#endif
-}
-
-
PyStatus
_PyContext_Init(PyInterpreterState *interp)
{
#include "pycore_ceval.h" // _Py_set_eval_breaker_bit()
#include "pycore_context.h"
#include "pycore_dict.h" // _PyDict_MaybeUntrack()
+#include "pycore_freelist.h" // _PyObject_ClearFreeLists()
#include "pycore_initconfig.h"
#include "pycore_interp.h" // PyInterpreterState.gc
#include "pycore_object.h"
#include "Python.h"
-#include "pycore_pystate.h" // _Py_ClearFreeLists()
+#include "pycore_freelist.h" // _PyObject_ClearFreeLists()
#ifndef Py_GIL_DISABLED
extern _PyObjectStackChunk *_PyObjectStackChunk_New(void);
extern void _PyObjectStackChunk_Free(_PyObjectStackChunk *);
-static struct _Py_object_stack_freelist *
-get_object_stack_freelist(void)
-{
- struct _Py_object_freelists *freelists = _Py_object_freelists_GET();
- return &freelists->object_stacks;
-}
-
_PyObjectStackChunk *
_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->items;
- obj_stack_freelist->items = buf->prev;
- obj_stack_freelist->numfree--;
- }
- else {
+ _PyObjectStackChunk *buf = _Py_FREELIST_POP_MEM(object_stack_chunks);
+ if (buf == NULL) {
// NOTE: we use PyMem_RawMalloc() here because this is used by the GC
// during mimalloc heap traversal. In that context, it is not safe to
// allocate mimalloc memory, such as via PyMem_Malloc().
_PyObjectStackChunk_Free(_PyObjectStackChunk *buf)
{
assert(buf->n == 0);
- struct _Py_object_stack_freelist *obj_stack_freelist = get_object_stack_freelist();
- if (obj_stack_freelist->numfree >= 0 &&
- obj_stack_freelist->numfree < _PyObjectStackChunk_MAXFREELIST)
- {
- buf->prev = obj_stack_freelist->items;
- obj_stack_freelist->items = buf;
- obj_stack_freelist->numfree++;
- }
- else {
- PyMem_RawFree(buf);
- }
+ _Py_FREELIST_FREE(object_stack_chunks, buf, PyMem_RawFree);
}
void
dst->head = src->head;
src->head = NULL;
}
-
-void
-_PyObjectStackChunk_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization)
-{
- if (!is_finalization) {
- // Ignore requests to clear the free list during GC. We use object
- // stacks during GC, so emptying the free-list is counterproductive.
- return;
- }
-
- 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);
- }
- freelist->numfree = -1;
-}
#include "pycore_dict.h" // _PyDict_Fini()
#include "pycore_exceptions.h" // _PyExc_InitTypes()
#include "pycore_fileutils.h" // _Py_ResetForceASCII()
+#include "pycore_freelist.h" // _PyObject_ClearFreeLists()
#include "pycore_floatobject.h" // _PyFloat_InitTypes()
#include "pycore_global_objects_fini_generated.h" // "_PyStaticObjects_CheckRefcnt()
#include "pycore_import.h" // _PyImport_BootstrapImp()
#ifndef Py_GIL_DISABLED
// With Py_GIL_DISABLED:
// the freelists for the current thread state have already been cleared.
- struct _Py_object_freelists *freelists = _Py_object_freelists_GET();
+ struct _Py_freelists *freelists = _Py_freelists_GET();
_PyObject_ClearFreeLists(freelists, 1);
#endif
#include "pycore_dtoa.h" // _dtoa_state_INIT()
#include "pycore_emscripten_trampoline.h" // _Py_EmscriptenTrampoline_Init()
#include "pycore_frame.h"
+#include "pycore_freelist.h" // _PyObject_ClearFreeLists()
#include "pycore_initconfig.h" // _PyStatus_OK()
#include "pycore_object.h" // _PyType_InitCache()
-#include "pycore_object_stack.h" // _PyObjectStackChunk_ClearFreeList()
#include "pycore_parking_lot.h" // _PyParkingLot_AfterFork()
#include "pycore_pyerrors.h" // _PyErr_Clear()
#include "pycore_pylifecycle.h" // _PyAST_Fini()
#ifdef Py_GIL_DISABLED
// Each thread should clear own freelists in free-threading builds.
- struct _Py_object_freelists *freelists = _Py_object_freelists_GET();
+ struct _Py_freelists *freelists = _Py_freelists_GET();
_PyObject_ClearFreeLists(freelists, 1);
// Remove ourself from the biased reference counting table of threads.