diff options
author | shadchin <[email protected]> | 2022-04-18 12:39:32 +0300 |
---|---|---|
committer | shadchin <[email protected]> | 2022-04-18 12:39:32 +0300 |
commit | d4be68e361f4258cf0848fc70018dfe37a2acc24 (patch) | |
tree | 153e294cd97ac8b5d7a989612704a0c1f58e8ad4 /contrib/tools/python3/src/Objects/tupleobject.c | |
parent | 260c02f5ccf242d9d9b8a873afaf6588c00237d6 (diff) |
IGNIETFERRO-1816 Update Python 3 from 3.9.12 to 3.10.4
ref:9f96be6d02ee8044fdd6f124b799b270c20ce641
Diffstat (limited to 'contrib/tools/python3/src/Objects/tupleobject.c')
-rw-r--r-- | contrib/tools/python3/src/Objects/tupleobject.c | 210 |
1 files changed, 138 insertions, 72 deletions
diff --git a/contrib/tools/python3/src/Objects/tupleobject.c b/contrib/tools/python3/src/Objects/tupleobject.c index 9092c9f8bee..6b1ab740121 100644 --- a/contrib/tools/python3/src/Objects/tupleobject.c +++ b/contrib/tools/python3/src/Objects/tupleobject.c @@ -2,10 +2,10 @@ /* Tuple object implementation */ #include "Python.h" -#include "pycore_abstract.h" // _PyIndex_Check() -#include "pycore_accu.h" -#include "pycore_gc.h" // _PyObject_GC_IS_TRACKED() -#include "pycore_object.h" +#include "pycore_abstract.h" // _PyIndex_Check() +#include "pycore_gc.h" // _PyObject_GC_IS_TRACKED() +#include "pycore_initconfig.h" // _PyStatus_OK() +#include "pycore_object.h" // _PyObject_GC_TRACK() /*[clinic input] class tuple "PyTupleObject *" "&PyTuple_Type" @@ -14,41 +14,36 @@ class tuple "PyTupleObject *" "&PyTuple_Type" #include "clinic/tupleobject.c.h" -/* Speed optimization to avoid frequent malloc/free of small tuples */ -#ifndef PyTuple_MAXSAVESIZE -#define PyTuple_MAXSAVESIZE 20 /* Largest tuple to save on free list */ -#endif -#ifndef PyTuple_MAXFREELIST -#define PyTuple_MAXFREELIST 2000 /* Maximum number of tuples of each size to save */ -#endif #if PyTuple_MAXSAVESIZE > 0 -/* Entries 1 up to PyTuple_MAXSAVESIZE are free lists, entry 0 is the empty - tuple () of which at most one instance will be allocated. -*/ -static PyTupleObject *free_list[PyTuple_MAXSAVESIZE]; -static int numfree[PyTuple_MAXSAVESIZE]; +static struct _Py_tuple_state * +get_tuple_state(void) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + return &interp->tuple; +} #endif + static inline void tuple_gc_track(PyTupleObject *op) { _PyObject_GC_TRACK(op); } + /* Print summary info about the state of the optimized allocator */ void _PyTuple_DebugMallocStats(FILE *out) { #if PyTuple_MAXSAVESIZE > 0 - int i; - char buf[128]; - for (i = 1; i < PyTuple_MAXSAVESIZE; i++) { + struct _Py_tuple_state *state = get_tuple_state(); + for (int i = 1; i < PyTuple_MAXSAVESIZE; i++) { + char buf[128]; PyOS_snprintf(buf, sizeof(buf), "free %d-sized PyTupleObject", i); - _PyDebugAllocatorStats(out, - buf, - numfree[i], _PyObject_VAR_SIZE(&PyTuple_Type, i)); + _PyDebugAllocatorStats(out, buf, state->numfree[i], + _PyObject_VAR_SIZE(&PyTuple_Type, i)); } #endif } @@ -65,19 +60,30 @@ static PyTupleObject * tuple_alloc(Py_ssize_t size) { PyTupleObject *op; +#if PyTuple_MAXSAVESIZE > 0 + // If Python is built with the empty tuple singleton, + // tuple_alloc(0) must not be called. + assert(size != 0); +#endif if (size < 0) { PyErr_BadInternalCall(); return NULL; } + #if PyTuple_MAXSAVESIZE > 0 - if (size < PyTuple_MAXSAVESIZE && (op = free_list[size]) != NULL) { + struct _Py_tuple_state *state = get_tuple_state(); +#ifdef Py_DEBUG + // tuple_alloc() must not be called after _PyTuple_Fini() + assert(state->numfree[0] != -1); +#endif + if (size < PyTuple_MAXSAVESIZE && (op = state->free_list[size]) != NULL) { assert(size != 0); - free_list[size] = (PyTupleObject *) op->ob_item[0]; - numfree[size]--; - /* Inline PyObject_InitVar */ + state->free_list[size] = (PyTupleObject *) op->ob_item[0]; + state->numfree[size]--; + /* Inlined _PyObject_InitVar() without _PyType_HasFeature() test */ #ifdef Py_TRACE_REFS - Py_SIZE(op) = size; - Py_TYPE(op) = &PyTuple_Type; + Py_SET_SIZE(op, size); + Py_SET_TYPE(op, &PyTuple_Type); #endif _Py_NewReference((PyObject *)op); } @@ -96,15 +102,56 @@ tuple_alloc(Py_ssize_t size) return op; } +static int +tuple_create_empty_tuple_singleton(struct _Py_tuple_state *state) +{ +#if PyTuple_MAXSAVESIZE > 0 + assert(state->free_list[0] == NULL); + + PyTupleObject *op = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, 0); + if (op == NULL) { + return -1; + } + // The empty tuple singleton is not tracked by the GC. + // It does not contain any Python object. + + state->free_list[0] = op; + state->numfree[0]++; + + assert(state->numfree[0] == 1); +#endif + return 0; +} + + +static PyObject * +tuple_get_empty(void) +{ +#if PyTuple_MAXSAVESIZE > 0 + struct _Py_tuple_state *state = get_tuple_state(); + PyTupleObject *op = state->free_list[0]; + // tuple_get_empty() must not be called before _PyTuple_Init() + // or after _PyTuple_Fini() + assert(op != NULL); +#ifdef Py_DEBUG + assert(state->numfree[0] != -1); +#endif + + Py_INCREF(op); + return (PyObject *) op; +#else + return PyTuple_New(0); +#endif +} + + PyObject * PyTuple_New(Py_ssize_t size) { PyTupleObject *op; #if PyTuple_MAXSAVESIZE > 0 - if (size == 0 && free_list[0]) { - op = free_list[0]; - Py_INCREF(op); - return (PyObject *) op; + if (size == 0) { + return tuple_get_empty(); } #endif op = tuple_alloc(size); @@ -114,13 +161,6 @@ PyTuple_New(Py_ssize_t size) for (Py_ssize_t i = 0; i < size; i++) { op->ob_item[i] = NULL; } -#if PyTuple_MAXSAVESIZE > 0 - if (size == 0) { - free_list[0] = op; - ++numfree[0]; - Py_INCREF(op); /* extra INCREF so that this is never freed */ - } -#endif tuple_gc_track(op); return (PyObject *) op; } @@ -201,7 +241,7 @@ PyTuple_Pack(Py_ssize_t n, ...) va_list vargs; if (n == 0) { - return PyTuple_New(0); + return tuple_get_empty(); } va_start(vargs, n); @@ -227,27 +267,33 @@ PyTuple_Pack(Py_ssize_t n, ...) static void tupledealloc(PyTupleObject *op) { - Py_ssize_t i; Py_ssize_t len = Py_SIZE(op); PyObject_GC_UnTrack(op); Py_TRASHCAN_BEGIN(op, tupledealloc) if (len > 0) { - i = len; - while (--i >= 0) + Py_ssize_t i = len; + while (--i >= 0) { Py_XDECREF(op->ob_item[i]); + } #if PyTuple_MAXSAVESIZE > 0 - if (len < PyTuple_MAXSAVESIZE && - numfree[len] < PyTuple_MAXFREELIST && - Py_IS_TYPE(op, &PyTuple_Type)) + struct _Py_tuple_state *state = get_tuple_state(); +#ifdef Py_DEBUG + // tupledealloc() must not be called after _PyTuple_Fini() + assert(state->numfree[0] != -1); +#endif + if (len < PyTuple_MAXSAVESIZE + && state->numfree[len] < PyTuple_MAXFREELIST + && Py_IS_TYPE(op, &PyTuple_Type)) { - op->ob_item[0] = (PyObject *) free_list[len]; - numfree[len]++; - free_list[len] = op; + op->ob_item[0] = (PyObject *) state->free_list[len]; + state->numfree[len]++; + state->free_list[len] = op; goto done; /* return */ } #endif } Py_TYPE(op)->tp_free((PyObject *)op); + #if PyTuple_MAXSAVESIZE > 0 done: #endif @@ -414,7 +460,7 @@ PyObject * _PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) { if (n == 0) { - return PyTuple_New(0); + return tuple_get_empty(); } PyTupleObject *tuple = tuple_alloc(n); @@ -475,16 +521,16 @@ tupleconcat(PyTupleObject *a, PyObject *bb) Py_TYPE(bb)->tp_name); return NULL; } -#define b ((PyTupleObject *)bb) + PyTupleObject *b = (PyTupleObject *)bb; + if (Py_SIZE(b) == 0 && PyTuple_CheckExact(a)) { Py_INCREF(a); return (PyObject *)a; } - if (Py_SIZE(a) > PY_SSIZE_T_MAX - Py_SIZE(b)) - return PyErr_NoMemory(); + assert((size_t)Py_SIZE(a) + (size_t)Py_SIZE(b) < PY_SSIZE_T_MAX); size = Py_SIZE(a) + Py_SIZE(b); if (size == 0) { - return PyTuple_New(0); + return tuple_get_empty(); } np = tuple_alloc(size); @@ -507,7 +553,6 @@ tupleconcat(PyTupleObject *a, PyObject *bb) } tuple_gc_track(np); return (PyObject *)np; -#undef b } static PyObject * @@ -526,7 +571,7 @@ tuplerepeat(PyTupleObject *a, Py_ssize_t n) } } if (Py_SIZE(a) == 0 || n <= 0) { - return PyTuple_New(0); + return tuple_get_empty(); } if (n > PY_SSIZE_T_MAX / Py_SIZE(a)) return PyErr_NoMemory(); @@ -702,10 +747,12 @@ tuple_new_impl(PyTypeObject *type, PyObject *iterable) if (type != &PyTuple_Type) return tuple_subtype_new(type, iterable); - if (iterable == NULL) - return PyTuple_New(0); - else + if (iterable == NULL) { + return tuple_get_empty(); + } + else { return PySequence_Tuple(iterable); + } } static PyObject * @@ -724,7 +771,9 @@ tuple_vectorcall(PyObject *type, PyObject * const*args, if (nargs) { return tuple_new_impl((PyTypeObject *)type, args[0]); } - return PyTuple_New(0); + else { + return tuple_get_empty(); + } } static PyObject * @@ -787,7 +836,7 @@ tuplesubscript(PyTupleObject* self, PyObject* item) &stop, step); if (slicelength <= 0) { - return PyTuple_New(0); + return tuple_get_empty(); } else if (start == 0 && step == 1 && slicelength == PyTuple_GET_SIZE(self) && @@ -868,7 +917,8 @@ PyTypeObject PyTuple_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TUPLE_SUBCLASS, /* tp_flags */ + Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TUPLE_SUBCLASS | + _Py_TPFLAGS_MATCH_SELF | Py_TPFLAGS_SEQUENCE, /* tp_flags */ tuple_new__doc__, /* tp_doc */ (traverseproc)tupletraverse, /* tp_traverse */ 0, /* tp_clear */ @@ -958,13 +1008,14 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize) } void -_PyTuple_ClearFreeList(void) +_PyTuple_ClearFreeList(PyInterpreterState *interp) { #if PyTuple_MAXSAVESIZE > 0 + struct _Py_tuple_state *state = &interp->tuple; for (Py_ssize_t i = 1; i < PyTuple_MAXSAVESIZE; i++) { - PyTupleObject *p = free_list[i]; - free_list[i] = NULL; - numfree[i] = 0; + PyTupleObject *p = state->free_list[i]; + state->free_list[i] = NULL; + state->numfree[i] = 0; while (p) { PyTupleObject *q = p; p = (PyTupleObject *)(p->ob_item[0]); @@ -975,15 +1026,30 @@ _PyTuple_ClearFreeList(void) #endif } + +PyStatus +_PyTuple_Init(PyInterpreterState *interp) +{ + struct _Py_tuple_state *state = &interp->tuple; + if (tuple_create_empty_tuple_singleton(state) < 0) { + return _PyStatus_NO_MEMORY(); + } + return _PyStatus_OK(); +} + + void -_PyTuple_Fini(void) +_PyTuple_Fini(PyInterpreterState *interp) { #if PyTuple_MAXSAVESIZE > 0 - /* empty tuples are used all over the place and applications may - * rely on the fact that an empty tuple is a singleton. */ - Py_CLEAR(free_list[0]); - - _PyTuple_ClearFreeList(); + struct _Py_tuple_state *state = &interp->tuple; + // The empty tuple singleton must not be tracked by the GC + assert(!_PyObject_GC_IS_TRACKED(state->free_list[0])); + Py_CLEAR(state->free_list[0]); + _PyTuple_ClearFreeList(interp); +#ifdef Py_DEBUG + state->numfree[0] = -1; +#endif #endif } |