Skip to content

Commit 0430dfa

Browse files
authored
bpo-40521: Always create the empty tuple singleton (GH-21116)
Py_InitializeFromConfig() now always creates the empty tuple singleton as soon as possible. Optimize PyTuple_New(0): it no longer has to check if the empty tuple was created or not, it is always creatd. * Add tuple_create_empty_tuple_singleton() function. * Add tuple_get_empty() function. * Remove state parameter of tuple_alloc().
1 parent 80526f6 commit 0430dfa

File tree

3 files changed

+105
-49
lines changed

3 files changed

+105
-49
lines changed

Include/internal/pycore_pylifecycle.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ PyAPI_FUNC(int) _Py_IsLocaleCoercionTarget(const char *ctype_loc);
3434
extern PyStatus _PyUnicode_Init(PyThreadState *tstate);
3535
extern int _PyStructSequence_Init(void);
3636
extern int _PyLong_Init(PyThreadState *tstate);
37+
extern PyStatus _PyTuple_Init(PyThreadState *tstate);
3738
extern PyStatus _PyFaulthandler_Init(int enable);
3839
extern int _PyTraceMalloc_Init(int enable);
3940
extern PyObject * _PyBuiltin_Init(PyThreadState *tstate);

Objects/tupleobject.c

Lines changed: 96 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
/* Tuple object implementation */
33

44
#include "Python.h"
5-
#include "pycore_abstract.h" // _PyIndex_Check()
6-
#include "pycore_accu.h"
7-
#include "pycore_gc.h" // _PyObject_GC_IS_TRACKED()
8-
#include "pycore_object.h"
5+
#include "pycore_abstract.h" // _PyIndex_Check()
6+
#include "pycore_gc.h" // _PyObject_GC_IS_TRACKED()
7+
#include "pycore_initconfig.h" // _PyStatus_OK()
8+
#include "pycore_object.h" // _PyObject_GC_TRACK()
99

1010
/*[clinic input]
1111
class tuple "PyTupleObject *" "&PyTuple_Type"
@@ -15,12 +15,14 @@ class tuple "PyTupleObject *" "&PyTuple_Type"
1515
#include "clinic/tupleobject.c.h"
1616

1717

18+
#if PyTuple_MAXSAVESIZE > 0
1819
static struct _Py_tuple_state *
1920
get_tuple_state(void)
2021
{
2122
PyInterpreterState *interp = _PyInterpreterState_GET();
2223
return &interp->tuple;
2324
}
25+
#endif
2426

2527

2628
static inline void
@@ -55,14 +57,21 @@ _PyTuple_DebugMallocStats(FILE *out)
5557
which wraps this function).
5658
*/
5759
static PyTupleObject *
58-
tuple_alloc(struct _Py_tuple_state *state, Py_ssize_t size)
60+
tuple_alloc(Py_ssize_t size)
5961
{
6062
PyTupleObject *op;
63+
#if PyTuple_MAXSAVESIZE > 0
64+
// If Python is built with the empty tuple singleton,
65+
// tuple_alloc(0) must not be called.
66+
assert(size != 0);
67+
#endif
6168
if (size < 0) {
6269
PyErr_BadInternalCall();
6370
return NULL;
6471
}
72+
6573
#if PyTuple_MAXSAVESIZE > 0
74+
struct _Py_tuple_state *state = get_tuple_state();
6675
#ifdef Py_DEBUG
6776
// tuple_alloc() must not be called after _PyTuple_Fini()
6877
assert(state->numfree[0] != -1);
@@ -93,36 +102,65 @@ tuple_alloc(struct _Py_tuple_state *state, Py_ssize_t size)
93102
return op;
94103
}
95104

105+
static int
106+
tuple_create_empty_tuple_singleton(struct _Py_tuple_state *state)
107+
{
108+
#if PyTuple_MAXSAVESIZE > 0
109+
assert(state->free_list[0] == NULL);
110+
111+
PyTupleObject *op = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, 0);
112+
if (op == NULL) {
113+
return -1;
114+
}
115+
// The empty tuple singleton is not tracked by the GC.
116+
// It does not contain any Python object.
117+
118+
state->free_list[0] = op;
119+
state->numfree[0]++;
120+
121+
assert(state->numfree[0] == 1);
122+
#endif
123+
return 0;
124+
}
125+
126+
127+
static PyObject *
128+
tuple_get_empty(void)
129+
{
130+
#if PyTuple_MAXSAVESIZE > 0
131+
struct _Py_tuple_state *state = get_tuple_state();
132+
PyTupleObject *op = state->free_list[0];
133+
// tuple_get_empty() must not be called before _PyTuple_Init()
134+
// or after _PyTuple_Fini()
135+
assert(op != NULL);
136+
#ifdef Py_DEBUG
137+
assert(state->numfree[0] != -1);
138+
#endif
139+
140+
Py_INCREF(op);
141+
return (PyObject *) op;
142+
#else
143+
return PyTuple_New(0);
144+
#endif
145+
}
146+
147+
96148
PyObject *
97149
PyTuple_New(Py_ssize_t size)
98150
{
99151
PyTupleObject *op;
100152
#if PyTuple_MAXSAVESIZE > 0
101-
struct _Py_tuple_state *state = get_tuple_state();
102-
if (size == 0 && state->free_list[0]) {
103-
op = state->free_list[0];
104-
Py_INCREF(op);
105-
return (PyObject *) op;
153+
if (size == 0) {
154+
return tuple_get_empty();
106155
}
107156
#endif
108-
op = tuple_alloc(state, size);
157+
op = tuple_alloc(size);
109158
if (op == NULL) {
110159
return NULL;
111160
}
112161
for (Py_ssize_t i = 0; i < size; i++) {
113162
op->ob_item[i] = NULL;
114163
}
115-
#if PyTuple_MAXSAVESIZE > 0
116-
if (size == 0) {
117-
#ifdef Py_DEBUG
118-
// PyTuple_New() must not be called after _PyTuple_Fini()
119-
assert(state->numfree[0] != -1);
120-
#endif
121-
state->free_list[0] = op;
122-
++state->numfree[0];
123-
Py_INCREF(op); /* extra INCREF so that this is never freed */
124-
}
125-
#endif
126164
tuple_gc_track(op);
127165
return (PyObject *) op;
128166
}
@@ -203,13 +241,11 @@ PyTuple_Pack(Py_ssize_t n, ...)
203241
va_list vargs;
204242

205243
if (n == 0) {
206-
return PyTuple_New(0);
244+
return tuple_get_empty();
207245
}
208246

209-
struct _Py_tuple_state *state = get_tuple_state();
210-
211247
va_start(vargs, n);
212-
PyTupleObject *result = tuple_alloc(state, n);
248+
PyTupleObject *result = tuple_alloc(n);
213249
if (result == NULL) {
214250
va_end(vargs);
215251
return NULL;
@@ -245,9 +281,9 @@ tupledealloc(PyTupleObject *op)
245281
// tupledealloc() must not be called after _PyTuple_Fini()
246282
assert(state->numfree[0] != -1);
247283
#endif
248-
if (len < PyTuple_MAXSAVESIZE &&
249-
state->numfree[len] < PyTuple_MAXFREELIST &&
250-
Py_IS_TYPE(op, &PyTuple_Type))
284+
if (len < PyTuple_MAXSAVESIZE
285+
&& state->numfree[len] < PyTuple_MAXFREELIST
286+
&& Py_IS_TYPE(op, &PyTuple_Type))
251287
{
252288
op->ob_item[0] = (PyObject *) state->free_list[len];
253289
state->numfree[len]++;
@@ -257,6 +293,7 @@ tupledealloc(PyTupleObject *op)
257293
#endif
258294
}
259295
Py_TYPE(op)->tp_free((PyObject *)op);
296+
260297
#if PyTuple_MAXSAVESIZE > 0
261298
done:
262299
#endif
@@ -423,11 +460,10 @@ PyObject *
423460
_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n)
424461
{
425462
if (n == 0) {
426-
return PyTuple_New(0);
463+
return tuple_get_empty();
427464
}
428465

429-
struct _Py_tuple_state *state = get_tuple_state();
430-
PyTupleObject *tuple = tuple_alloc(state, n);
466+
PyTupleObject *tuple = tuple_alloc(n);
431467
if (tuple == NULL) {
432468
return NULL;
433469
}
@@ -494,11 +530,10 @@ tupleconcat(PyTupleObject *a, PyObject *bb)
494530
assert((size_t)Py_SIZE(a) + (size_t)Py_SIZE(b) < PY_SSIZE_T_MAX);
495531
size = Py_SIZE(a) + Py_SIZE(b);
496532
if (size == 0) {
497-
return PyTuple_New(0);
533+
return tuple_get_empty();
498534
}
499535

500-
struct _Py_tuple_state *state = get_tuple_state();
501-
np = tuple_alloc(state, size);
536+
np = tuple_alloc(size);
502537
if (np == NULL) {
503538
return NULL;
504539
}
@@ -536,13 +571,12 @@ tuplerepeat(PyTupleObject *a, Py_ssize_t n)
536571
}
537572
}
538573
if (Py_SIZE(a) == 0 || n <= 0) {
539-
return PyTuple_New(0);
574+
return tuple_get_empty();
540575
}
541576
if (n > PY_SSIZE_T_MAX / Py_SIZE(a))
542577
return PyErr_NoMemory();
543578
size = Py_SIZE(a) * n;
544-
struct _Py_tuple_state *state = get_tuple_state();
545-
np = tuple_alloc(state, size);
579+
np = tuple_alloc(size);
546580
if (np == NULL)
547581
return NULL;
548582
p = np->ob_item;
@@ -713,10 +747,12 @@ tuple_new_impl(PyTypeObject *type, PyObject *iterable)
713747
if (type != &PyTuple_Type)
714748
return tuple_subtype_new(type, iterable);
715749

716-
if (iterable == NULL)
717-
return PyTuple_New(0);
718-
else
750+
if (iterable == NULL) {
751+
return tuple_get_empty();
752+
}
753+
else {
719754
return PySequence_Tuple(iterable);
755+
}
720756
}
721757

722758
static PyObject *
@@ -735,7 +771,9 @@ tuple_vectorcall(PyObject *type, PyObject * const*args,
735771
if (nargs) {
736772
return tuple_new_impl((PyTypeObject *)type, args[0]);
737773
}
738-
return PyTuple_New(0);
774+
else {
775+
return tuple_get_empty();
776+
}
739777
}
740778

741779
static PyObject *
@@ -798,7 +836,7 @@ tuplesubscript(PyTupleObject* self, PyObject* item)
798836
&stop, step);
799837

800838
if (slicelength <= 0) {
801-
return PyTuple_New(0);
839+
return tuple_get_empty();
802840
}
803841
else if (start == 0 && step == 1 &&
804842
slicelength == PyTuple_GET_SIZE(self) &&
@@ -807,8 +845,7 @@ tuplesubscript(PyTupleObject* self, PyObject* item)
807845
return (PyObject *)self;
808846
}
809847
else {
810-
struct _Py_tuple_state *state = get_tuple_state();
811-
PyTupleObject* result = tuple_alloc(state, slicelength);
848+
PyTupleObject* result = tuple_alloc(slicelength);
812849
if (!result) return NULL;
813850

814851
src = self->ob_item;
@@ -988,15 +1025,26 @@ _PyTuple_ClearFreeList(PyThreadState *tstate)
9881025
#endif
9891026
}
9901027

1028+
1029+
PyStatus
1030+
_PyTuple_Init(PyThreadState *tstate)
1031+
{
1032+
struct _Py_tuple_state *state = &tstate->interp->tuple;
1033+
if (tuple_create_empty_tuple_singleton(state) < 0) {
1034+
return _PyStatus_NO_MEMORY();
1035+
}
1036+
return _PyStatus_OK();
1037+
}
1038+
1039+
9911040
void
9921041
_PyTuple_Fini(PyThreadState *tstate)
9931042
{
9941043
#if PyTuple_MAXSAVESIZE > 0
9951044
struct _Py_tuple_state *state = &tstate->interp->tuple;
996-
/* empty tuples are used all over the place and applications may
997-
* rely on the fact that an empty tuple is a singleton. */
1045+
// The empty tuple singleton must not be tracked by the GC
1046+
assert(!_PyObject_GC_IS_TRACKED(state->free_list[0]));
9981047
Py_CLEAR(state->free_list[0]);
999-
10001048
_PyTuple_ClearFreeList(tstate);
10011049
#ifdef Py_DEBUG
10021050
state->numfree[0] = -1;

Python/pylifecycle.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,14 +583,21 @@ pycore_init_types(PyThreadState *tstate)
583583
return status;
584584
}
585585

586+
// Create the empty tuple singleton. It must be created before the first
587+
// PyType_Ready() call since PyType_Ready() creates tuples, for tp_bases
588+
// for example.
589+
status = _PyTuple_Init(tstate);
590+
if (_PyStatus_EXCEPTION(status)) {
591+
return status;
592+
}
593+
586594
if (is_main_interp) {
587595
status = _PyTypes_Init();
588596
if (_PyStatus_EXCEPTION(status)) {
589597
return status;
590598
}
591599
}
592600

593-
594601
if (!_PyLong_Init(tstate)) {
595602
return _PyStatus_ERR("can't init longs");
596603
}

0 commit comments

Comments
 (0)