summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Objects/tupleobject.c
diff options
context:
space:
mode:
authorshadchin <[email protected]>2022-04-18 12:39:32 +0300
committershadchin <[email protected]>2022-04-18 12:39:32 +0300
commitd4be68e361f4258cf0848fc70018dfe37a2acc24 (patch)
tree153e294cd97ac8b5d7a989612704a0c1f58e8ad4 /contrib/tools/python3/src/Objects/tupleobject.c
parent260c02f5ccf242d9d9b8a873afaf6588c00237d6 (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.c210
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
}