summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorChristian Heimes <christian@python.org>2021-10-21 13:12:20 (GMT)
committerGitHub <noreply@github.com>2021-10-21 13:12:20 (GMT)
commit9942f42a93ccda047fd3558c47b822e99afe10c0 (patch)
tree5a28ecf799a90b9225530c12acd7c38c1935f156 /Objects
parent5a14f71fe869d4a62dcdeb9a8fbbb5884c75060c (diff)
downloadcpython-9942f42a93ccda047fd3558c47b822e99afe10c0.zip
cpython-9942f42a93ccda047fd3558c47b822e99afe10c0.tar.gz
cpython-9942f42a93ccda047fd3558c47b822e99afe10c0.tar.bz2
bpo-45522: Allow to disable freelists on build time (GH-29056)
Freelists for object structs can now be disabled. A new ``configure`` option ``--without-freelists`` can be used to disable all freelists except empty tuple singleton. Internal Py*_MAXFREELIST macros can now be defined as 0 without causing compiler warnings and segfaults. Signed-off-by: Christian Heimes <christian@python.org>
Diffstat (limited to 'Objects')
-rw-r--r--Objects/dictobject.c27
-rw-r--r--Objects/floatobject.c21
-rw-r--r--Objects/frameobject.c23
-rw-r--r--Objects/genobject.c26
-rw-r--r--Objects/listobject.c24
-rw-r--r--Objects/tupleobject.c3
6 files changed, 98 insertions, 26 deletions
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 3d6e4c1..6dcd5a1 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -240,17 +240,20 @@ uint64_t _pydict_global_version = 0;
#include "clinic/dictobject.c.h"
+#if PyDict_MAXFREELIST > 0
static struct _Py_dict_state *
get_dict_state(void)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
return &interp->dict_state;
}
+#endif
void
_PyDict_ClearFreeList(PyInterpreterState *interp)
{
+#if PyDict_MAXFREELIST > 0
struct _Py_dict_state *state = &interp->dict_state;
while (state->numfree) {
PyDictObject *op = state->free_list[--state->numfree];
@@ -260,6 +263,7 @@ _PyDict_ClearFreeList(PyInterpreterState *interp)
while (state->keys_numfree) {
PyObject_Free(state->keys_free_list[--state->keys_numfree]);
}
+#endif
}
@@ -267,7 +271,7 @@ void
_PyDict_Fini(PyInterpreterState *interp)
{
_PyDict_ClearFreeList(interp);
-#ifdef Py_DEBUG
+#if defined(Py_DEBUG) && PyDict_MAXFREELIST > 0
struct _Py_dict_state *state = &interp->dict_state;
state->numfree = -1;
state->keys_numfree = -1;
@@ -279,9 +283,11 @@ _PyDict_Fini(PyInterpreterState *interp)
void
_PyDict_DebugMallocStats(FILE *out)
{
+#if PyDict_MAXFREELIST > 0
struct _Py_dict_state *state = get_dict_state();
_PyDebugAllocatorStats(out, "free PyDictObject",
state->numfree, sizeof(PyDictObject));
+#endif
}
#define DK_MASK(dk) (DK_SIZE(dk)-1)
@@ -570,6 +576,7 @@ new_keys_object(uint8_t log2_size)
es = sizeof(Py_ssize_t);
}
+#if PyDict_MAXFREELIST > 0
struct _Py_dict_state *state = get_dict_state();
#ifdef Py_DEBUG
// new_keys_object() must not be called after _PyDict_Fini()
@@ -579,6 +586,7 @@ new_keys_object(uint8_t log2_size)
dk = state->keys_free_list[--state->keys_numfree];
}
else
+#endif
{
dk = PyObject_Malloc(sizeof(PyDictKeysObject)
+ (es<<log2_size)
@@ -611,6 +619,7 @@ free_keys_object(PyDictKeysObject *keys)
Py_XDECREF(entries[i].me_key);
Py_XDECREF(entries[i].me_value);
}
+#if PyDict_MAXFREELIST > 0
struct _Py_dict_state *state = get_dict_state();
#ifdef Py_DEBUG
// free_keys_object() must not be called after _PyDict_Fini()
@@ -620,6 +629,7 @@ free_keys_object(PyDictKeysObject *keys)
state->keys_free_list[state->keys_numfree++] = keys;
return;
}
+#endif
PyObject_Free(keys);
}
@@ -638,6 +648,7 @@ new_dict(PyDictKeysObject *keys, PyDictValues *values, Py_ssize_t used, int free
{
PyDictObject *mp;
assert(keys != NULL);
+#if PyDict_MAXFREELIST > 0
struct _Py_dict_state *state = get_dict_state();
#ifdef Py_DEBUG
// new_dict() must not be called after _PyDict_Fini()
@@ -649,7 +660,9 @@ new_dict(PyDictKeysObject *keys, PyDictValues *values, Py_ssize_t used, int free
assert (Py_IS_TYPE(mp, &PyDict_Type));
_Py_NewReference((PyObject *)mp);
}
- else {
+ else
+#endif
+ {
mp = PyObject_GC_New(PyDictObject, &PyDict_Type);
if (mp == NULL) {
dictkeys_decref(keys);
@@ -1259,6 +1272,7 @@ dictresize(PyDictObject *mp, uint8_t log2_newsize)
#ifdef Py_REF_DEBUG
_Py_RefTotal--;
#endif
+#if PyDict_MAXFREELIST > 0
struct _Py_dict_state *state = get_dict_state();
#ifdef Py_DEBUG
// dictresize() must not be called after _PyDict_Fini()
@@ -1269,7 +1283,9 @@ dictresize(PyDictObject *mp, uint8_t log2_newsize)
{
state->keys_free_list[state->keys_numfree++] = oldkeys;
}
- else {
+ else
+#endif
+ {
PyObject_Free(oldkeys);
}
}
@@ -1987,6 +2003,7 @@ dict_dealloc(PyDictObject *mp)
assert(keys->dk_refcnt == 1);
dictkeys_decref(keys);
}
+#if PyDict_MAXFREELIST > 0
struct _Py_dict_state *state = get_dict_state();
#ifdef Py_DEBUG
// new_dict() must not be called after _PyDict_Fini()
@@ -1995,7 +2012,9 @@ dict_dealloc(PyDictObject *mp)
if (state->numfree < PyDict_MAXFREELIST && Py_IS_TYPE(mp, &PyDict_Type)) {
state->free_list[state->numfree++] = mp;
}
- else {
+ else
+#endif
+ {
Py_TYPE(mp)->tp_free((PyObject *)mp);
}
Py_TRASHCAN_END
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index 1be31e3..7fc192e 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -28,12 +28,14 @@ class float "PyObject *" "&PyFloat_Type"
#endif
+#if PyFloat_MAXFREELIST > 0
static struct _Py_float_state *
get_float_state(void)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
return &interp->float_state;
}
+#endif
double
@@ -126,8 +128,10 @@ PyFloat_GetInfo(void)
PyObject *
PyFloat_FromDouble(double fval)
{
+ PyFloatObject *op;
+#if PyFloat_MAXFREELIST > 0
struct _Py_float_state *state = get_float_state();
- PyFloatObject *op = state->free_list;
+ op = state->free_list;
if (op != NULL) {
#ifdef Py_DEBUG
// PyFloat_FromDouble() must not be called after _PyFloat_Fini()
@@ -136,7 +140,9 @@ PyFloat_FromDouble(double fval)
state->free_list = (PyFloatObject *) Py_TYPE(op);
state->numfree--;
}
- else {
+ else
+#endif
+ {
op = PyObject_Malloc(sizeof(PyFloatObject));
if (!op) {
return PyErr_NoMemory();
@@ -233,6 +239,7 @@ PyFloat_FromString(PyObject *v)
static void
float_dealloc(PyFloatObject *op)
{
+#if PyFloat_MAXFREELIST > 0
if (PyFloat_CheckExact(op)) {
struct _Py_float_state *state = get_float_state();
#ifdef Py_DEBUG
@@ -247,7 +254,9 @@ float_dealloc(PyFloatObject *op)
Py_SET_TYPE(op, (PyTypeObject *)state->free_list);
state->free_list = op;
}
- else {
+ else
+#endif
+ {
Py_TYPE(op)->tp_free((PyObject *)op);
}
}
@@ -2036,6 +2045,7 @@ _PyFloat_InitTypes(void)
void
_PyFloat_ClearFreeList(PyInterpreterState *interp)
{
+#if PyFloat_MAXFREELIST > 0
struct _Py_float_state *state = &interp->float_state;
PyFloatObject *f = state->free_list;
while (f != NULL) {
@@ -2045,13 +2055,14 @@ _PyFloat_ClearFreeList(PyInterpreterState *interp)
}
state->free_list = NULL;
state->numfree = 0;
+#endif
}
void
_PyFloat_Fini(PyInterpreterState *interp)
{
_PyFloat_ClearFreeList(interp);
-#ifdef Py_DEBUG
+#if defined(Py_DEBUG) && PyFloat_MAXFREELIST > 0
struct _Py_float_state *state = &interp->float_state;
state->numfree = -1;
#endif
@@ -2061,10 +2072,12 @@ _PyFloat_Fini(PyInterpreterState *interp)
void
_PyFloat_DebugMallocStats(FILE *out)
{
+#if PyFloat_MAXFREELIST > 0
struct _Py_float_state *state = get_float_state();
_PyDebugAllocatorStats(out,
"free PyFloatObject",
state->numfree, sizeof(PyFloatObject));
+#endif
}
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 5271790..ffe19b3 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -19,12 +19,14 @@ static PyMemberDef frame_memberlist[] = {
{NULL} /* Sentinel */
};
+#if PyFrame_MAXFREELIST > 0
static struct _Py_frame_state *
get_frame_state(void)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
return &interp->frame;
}
+#endif
static PyObject *
@@ -607,9 +609,6 @@ static PyGetSetDef frame_getsetlist[] = {
f_back next item on free list, or NULL
*/
-/* max value for numfree */
-#define PyFrame_MAXFREELIST 200
-
static void _Py_HOT_FUNCTION
frame_dealloc(PyFrameObject *f)
{
@@ -638,6 +637,7 @@ frame_dealloc(PyFrameObject *f)
}
Py_CLEAR(f->f_back);
Py_CLEAR(f->f_trace);
+#if PyFrame_MAXFREELIST > 0
struct _Py_frame_state *state = get_frame_state();
#ifdef Py_DEBUG
// frame_dealloc() must not be called after _PyFrame_Fini()
@@ -648,7 +648,9 @@ frame_dealloc(PyFrameObject *f)
f->f_back = state->free_list;
state->free_list = f;
}
- else {
+ else
+#endif
+ {
PyObject_GC_Del(f);
}
@@ -801,8 +803,10 @@ static inline PyFrameObject*
frame_alloc(InterpreterFrame *frame, int owns)
{
PyFrameObject *f;
+#if PyFrame_MAXFREELIST > 0
struct _Py_frame_state *state = get_frame_state();
if (state->free_list == NULL)
+#endif
{
f = PyObject_GC_New(PyFrameObject, &PyFrame_Type);
if (f == NULL) {
@@ -816,7 +820,9 @@ frame_alloc(InterpreterFrame *frame, int owns)
return NULL;
}
}
- else {
+#if PyFrame_MAXFREELIST > 0
+ else
+ {
#ifdef Py_DEBUG
// frame_alloc() must not be called after _PyFrame_Fini()
assert(state->numfree != -1);
@@ -827,6 +833,7 @@ frame_alloc(InterpreterFrame *frame, int owns)
state->free_list = state->free_list->f_back;
_Py_NewReference((PyObject *)f);
}
+#endif
f->f_frame = frame;
f->f_own_locals_memory = owns;
return f;
@@ -1069,6 +1076,7 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
void
_PyFrame_ClearFreeList(PyInterpreterState *interp)
{
+#if PyFrame_MAXFREELIST > 0
struct _Py_frame_state *state = &interp->frame;
while (state->free_list != NULL) {
PyFrameObject *f = state->free_list;
@@ -1077,13 +1085,14 @@ _PyFrame_ClearFreeList(PyInterpreterState *interp)
--state->numfree;
}
assert(state->numfree == 0);
+#endif
}
void
_PyFrame_Fini(PyInterpreterState *interp)
{
_PyFrame_ClearFreeList(interp);
-#ifdef Py_DEBUG
+#if defined(Py_DEBUG) && PyFrame_MAXFREELIST > 0
struct _Py_frame_state *state = &interp->frame;
state->numfree = -1;
#endif
@@ -1093,10 +1102,12 @@ _PyFrame_Fini(PyInterpreterState *interp)
void
_PyFrame_DebugMallocStats(FILE *out)
{
+#if PyFrame_MAXFREELIST > 0
struct _Py_frame_state *state = get_frame_state();
_PyDebugAllocatorStats(out,
"free PyFrameObject",
state->numfree, sizeof(PyFrameObject));
+#endif
}
diff --git a/Objects/genobject.c b/Objects/genobject.c
index f91f367..8bf5515 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -1567,12 +1567,14 @@ PyTypeObject PyAsyncGen_Type = {
};
+#if _PyAsyncGen_MAXFREELIST > 0
static struct _Py_async_gen_state *
get_async_gen_state(void)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
return &interp->async_gen;
}
+#endif
PyObject *
@@ -1595,6 +1597,7 @@ PyAsyncGen_New(PyFrameObject *f, PyObject *name, PyObject *qualname)
void
_PyAsyncGen_ClearFreeLists(PyInterpreterState *interp)
{
+#if _PyAsyncGen_MAXFREELIST > 0
struct _Py_async_gen_state *state = &interp->async_gen;
while (state->value_numfree) {
@@ -1610,13 +1613,14 @@ _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp)
assert(Py_IS_TYPE(o, &_PyAsyncGenASend_Type));
PyObject_GC_Del(o);
}
+#endif
}
void
_PyAsyncGen_Fini(PyInterpreterState *interp)
{
_PyAsyncGen_ClearFreeLists(interp);
-#ifdef Py_DEBUG
+#if defined(Py_DEBUG) && _PyAsyncGen_MAXFREELIST > 0
struct _Py_async_gen_state *state = &interp->async_gen;
state->value_numfree = -1;
state->asend_numfree = -1;
@@ -1663,6 +1667,7 @@ async_gen_asend_dealloc(PyAsyncGenASend *o)
_PyObject_GC_UNTRACK((PyObject *)o);
Py_CLEAR(o->ags_gen);
Py_CLEAR(o->ags_sendval);
+#if _PyAsyncGen_MAXFREELIST > 0
struct _Py_async_gen_state *state = get_async_gen_state();
#ifdef Py_DEBUG
// async_gen_asend_dealloc() must not be called after _PyAsyncGen_Fini()
@@ -1672,7 +1677,9 @@ async_gen_asend_dealloc(PyAsyncGenASend *o)
assert(PyAsyncGenASend_CheckExact(o));
state->asend_freelist[state->asend_numfree++] = o;
}
- else {
+ else
+#endif
+ {
PyObject_GC_Del(o);
}
}
@@ -1825,6 +1832,7 @@ static PyObject *
async_gen_asend_new(PyAsyncGenObject *gen, PyObject *sendval)
{
PyAsyncGenASend *o;
+#if _PyAsyncGen_MAXFREELIST > 0
struct _Py_async_gen_state *state = get_async_gen_state();
#ifdef Py_DEBUG
// async_gen_asend_new() must not be called after _PyAsyncGen_Fini()
@@ -1835,7 +1843,9 @@ async_gen_asend_new(PyAsyncGenObject *gen, PyObject *sendval)
o = state->asend_freelist[state->asend_numfree];
_Py_NewReference((PyObject *)o);
}
- else {
+ else
+#endif
+ {
o = PyObject_GC_New(PyAsyncGenASend, &_PyAsyncGenASend_Type);
if (o == NULL) {
return NULL;
@@ -1863,6 +1873,7 @@ async_gen_wrapped_val_dealloc(_PyAsyncGenWrappedValue *o)
{
_PyObject_GC_UNTRACK((PyObject *)o);
Py_CLEAR(o->agw_val);
+#if _PyAsyncGen_MAXFREELIST > 0
struct _Py_async_gen_state *state = get_async_gen_state();
#ifdef Py_DEBUG
// async_gen_wrapped_val_dealloc() must not be called after _PyAsyncGen_Fini()
@@ -1872,7 +1883,9 @@ async_gen_wrapped_val_dealloc(_PyAsyncGenWrappedValue *o)
assert(_PyAsyncGenWrappedValue_CheckExact(o));
state->value_freelist[state->value_numfree++] = o;
}
- else {
+ else
+#endif
+ {
PyObject_GC_Del(o);
}
}
@@ -1936,6 +1949,7 @@ _PyAsyncGenValueWrapperNew(PyObject *val)
_PyAsyncGenWrappedValue *o;
assert(val);
+#if _PyAsyncGen_MAXFREELIST > 0
struct _Py_async_gen_state *state = get_async_gen_state();
#ifdef Py_DEBUG
// _PyAsyncGenValueWrapperNew() must not be called after _PyAsyncGen_Fini()
@@ -1947,7 +1961,9 @@ _PyAsyncGenValueWrapperNew(PyObject *val)
assert(_PyAsyncGenWrappedValue_CheckExact(o));
_Py_NewReference((PyObject*)o);
}
- else {
+ else
+#endif
+ {
o = PyObject_GC_New(_PyAsyncGenWrappedValue,
&_PyAsyncGenWrappedValue_Type);
if (o == NULL) {
diff --git a/Objects/listobject.c b/Objects/listobject.c
index ed53241..e0cae87 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -19,13 +19,14 @@ class list "PyListObject *" "&PyList_Type"
#include "clinic/listobject.c.h"
-
+#if PyList_MAXFREELIST > 0
static struct _Py_list_state *
get_list_state(void)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
return &interp->list;
}
+#endif
/* Ensure ob_item has room for at least newsize elements, and set
@@ -108,19 +109,21 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size)
void
_PyList_ClearFreeList(PyInterpreterState *interp)
{
+#if PyList_MAXFREELIST > 0
struct _Py_list_state *state = &interp->list;
while (state->numfree) {
PyListObject *op = state->free_list[--state->numfree];
assert(PyList_CheckExact(op));
PyObject_GC_Del(op);
}
+#endif
}
void
_PyList_Fini(PyInterpreterState *interp)
{
_PyList_ClearFreeList(interp);
-#ifdef Py_DEBUG
+#if defined(Py_DEBUG) && PyList_MAXFREELIST > 0
struct _Py_list_state *state = &interp->list;
state->numfree = -1;
#endif
@@ -130,32 +133,38 @@ _PyList_Fini(PyInterpreterState *interp)
void
_PyList_DebugMallocStats(FILE *out)
{
+#if PyList_MAXFREELIST > 0
struct _Py_list_state *state = get_list_state();
_PyDebugAllocatorStats(out,
"free PyListObject",
state->numfree, sizeof(PyListObject));
+#endif
}
PyObject *
PyList_New(Py_ssize_t size)
{
+ PyListObject *op;
+
if (size < 0) {
PyErr_BadInternalCall();
return NULL;
}
+#if PyList_MAXFREELIST > 0
struct _Py_list_state *state = get_list_state();
- PyListObject *op;
#ifdef Py_DEBUG
// PyList_New() must not be called after _PyList_Fini()
assert(state->numfree != -1);
#endif
- if (state->numfree) {
+ if (PyList_MAXFREELIST && state->numfree) {
state->numfree--;
op = state->free_list[state->numfree];
_Py_NewReference((PyObject *)op);
}
- else {
+ else
+#endif
+ {
op = PyObject_GC_New(PyListObject, &PyList_Type);
if (op == NULL) {
return NULL;
@@ -344,6 +353,7 @@ list_dealloc(PyListObject *op)
}
PyMem_Free(op->ob_item);
}
+#if PyList_MAXFREELIST > 0
struct _Py_list_state *state = get_list_state();
#ifdef Py_DEBUG
// list_dealloc() must not be called after _PyList_Fini()
@@ -352,7 +362,9 @@ list_dealloc(PyListObject *op)
if (state->numfree < PyList_MAXFREELIST && PyList_CheckExact(op)) {
state->free_list[state->numfree++] = op;
}
- else {
+ else
+#endif
+ {
Py_TYPE(op)->tp_free((PyObject *)op);
}
Py_TRASHCAN_END
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index 0516830..e9d1b59 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -66,7 +66,8 @@ tuple_alloc(Py_ssize_t size)
return NULL;
}
-#if PyTuple_MAXSAVESIZE > 0
+// Check for max save size > 1. Empty tuple singleton is special case.
+#if PyTuple_MAXSAVESIZE > 1
struct _Py_tuple_state *state = get_tuple_state();
#ifdef Py_DEBUG
// tuple_alloc() must not be called after _PyTuple_Fini()