Skip to content

Commit c163aca

Browse files
Re-apply the global singleton part.
1 parent 460ae61 commit c163aca

File tree

8 files changed

+51
-102
lines changed

8 files changed

+51
-102
lines changed

Include/internal/pycore_gc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ typedef struct {
2020
} PyGC_Head;
2121

2222
#define _Py_AS_GC(o) ((PyGC_Head *)(o)-1)
23+
#define _PyGC_Head_UNUSED PyGC_Head
2324

2425
/* True if the object is currently tracked by the GC. */
2526
#define _PyObject_GC_IS_TRACKED(o) (_Py_AS_GC(o)->_gc_next != 0)

Include/internal/pycore_global_objects.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ extern "C" {
88
# error "this header requires Py_BUILD_CORE define"
99
#endif
1010

11+
#include "pycore_gc.h" // PyGC_Head
1112
#include "pycore_global_strings.h" // struct _Py_global_strings
1213

1314

@@ -40,6 +41,9 @@ struct _Py_global_objects {
4041
} bytes_characters[256];
4142

4243
struct _Py_global_strings strings;
44+
45+
_PyGC_Head_UNUSED _tuple_empty_gc_not_used;
46+
PyTupleObject tuple_empty;
4347
} singletons;
4448
};
4549

Include/internal/pycore_runtime_init.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,10 @@ extern "C" {
964964
INIT_ID(zipimporter), \
965965
}, \
966966
}, \
967+
\
968+
.tuple_empty = { \
969+
.ob_base = _PyVarObject_IMMORTAL_INIT(&PyTuple_Type, 0) \
970+
}, \
967971
}, \
968972
}
969973
/* End auto-generated code */

Include/internal/pycore_tuple.h

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,13 @@ extern void _PyTuple_Fini(PyInterpreterState *);
2929
# undef PyTuple_MAXSAVESIZE
3030

3131
#elif !defined(WITH_FREELISTS)
32-
// Only store the empty tuple singleton.
33-
# define PyTuple_NFREELISTS 1
34-
# ifndef PyTuple_MAXSAVESIZE
35-
# define PyTuple_MAXSAVESIZE 0
36-
# endif
37-
# ifndef PyTuple_MAXFREELIST
38-
# define PyTuple_MAXFREELIST 1
39-
# endif
32+
# define PyTuple_NFREELISTS 0
4033

4134
#else
4235
# ifndef PyTuple_MAXSAVESIZE
4336
# define PyTuple_MAXSAVESIZE 20
4437
# endif
45-
# define PyTuple_NFREELISTS (PyTuple_MAXSAVESIZE + 1)
38+
# define PyTuple_NFREELISTS PyTuple_MAXSAVESIZE
4639
# ifndef PyTuple_MAXFREELIST
4740
# define PyTuple_MAXFREELIST 2000
4841
# endif
@@ -51,8 +44,7 @@ extern void _PyTuple_Fini(PyInterpreterState *);
5144
struct _Py_tuple_state {
5245
#if PyTuple_NFREELISTS > 0
5346
/* There is one freelist for each size from 1 to PyTuple_MAXSAVESIZE.
54-
Entry 0 is the empty tuple () of which at most one instance
55-
will be allocated.
47+
The empty tuple is handled separately.
5648
5749
Each tuple stored in the array is the head of the linked list
5850
(and the next available tuple) for that size. The actual tuple

Objects/tupleobject.c

Lines changed: 34 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ tuple_alloc(Py_ssize_t size)
3737
PyErr_BadInternalCall();
3838
return NULL;
3939
}
40+
#ifdef Py_DEBUG
41+
assert(size != 0); // The empty tuple is statically allocated.
42+
#endif
4043

4144
PyTupleObject *op = maybe_freelist_pop(size);
4245
if (op == NULL) {
@@ -52,24 +55,17 @@ tuple_alloc(Py_ssize_t size)
5255
return op;
5356
}
5457

55-
static inline PyTupleObject *maybe_freelist_get_empty_singleton(void);
58+
// The empty tuple singleton is not tracked by the GC.
59+
// It does not contain any Python object.
60+
// Note that tuple subclasses have their own empty instances.
5661

5762
static inline PyObject *
5863
tuple_get_empty(void)
5964
{
60-
PyTupleObject *op = maybe_freelist_get_empty_singleton();
61-
if (op != NULL) {
62-
Py_INCREF(op);
63-
}
64-
else {
65-
op = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, 0);
66-
_PyObject_GC_TRACK(op);
67-
}
68-
return (PyObject *)op;
65+
Py_INCREF(&_Py_SINGLETON(tuple_empty));
66+
return (PyObject *)&_Py_SINGLETON(tuple_empty);
6967
}
7068

71-
// Note that tuple subclasses have their own empty instances.
72-
7369
PyObject *
7470
PyTuple_New(Py_ssize_t size)
7571
{
@@ -190,6 +186,21 @@ PyTuple_Pack(Py_ssize_t n, ...)
190186
static void
191187
tupledealloc(PyTupleObject *op)
192188
{
189+
if (Py_SIZE(op) == 0) {
190+
/* The empty tuple is statically allocated. */
191+
if (op == &_Py_SINGLETON(tuple_empty)) {
192+
#ifdef Py_DEBUG
193+
_Py_FatalRefcountError("deallocating the empty tuple singleton");
194+
#else
195+
return;
196+
#endif
197+
}
198+
#ifdef Py_DEBUG
199+
/* tuple subclasses have their own empty instances. */
200+
assert(!PyTuple_CheckExact(op));
201+
#endif
202+
}
203+
193204
PyObject_GC_UnTrack(op);
194205
Py_TRASHCAN_BEGIN(op, tupledealloc)
195206

@@ -928,6 +939,9 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
928939
return 0;
929940
}
930941
if (oldsize == 0) {
942+
#ifdef Py_DEBUG
943+
assert(v == &_Py_SINGLETON(tuple_empty));
944+
#endif
931945
/* The empty tuple is statically allocated so we never
932946
resize it in-place. */
933947
Py_DECREF(v);
@@ -984,17 +998,6 @@ _PyTuple_InitTypes(PyInterpreterState *interp)
984998
return _PyStatus_OK();
985999
}
9861000

987-
static int maybe_freelist_init_empty_tuple(PyInterpreterState *);
988-
989-
PyStatus
990-
_PyTuple_InitGlobalObjects(PyInterpreterState *interp)
991-
{
992-
if (maybe_freelist_init_empty_tuple(interp) < 0) {
993-
return _PyStatus_NO_MEMORY();
994-
}
995-
return _PyStatus_OK();
996-
}
997-
9981001
static void maybe_freelist_clear(PyInterpreterState *, int);
9991002

10001003
void
@@ -1163,44 +1166,6 @@ tuple_iter(PyObject *seq)
11631166
#define STATE (interp->tuple)
11641167
#define FREELIST_FINALIZED (STATE.numfree[0] < 0)
11651168

1166-
static int
1167-
maybe_freelist_init_empty_tuple(PyInterpreterState *interp)
1168-
{
1169-
#if PyTuple_NFREELISTS > 0
1170-
assert(STATE.free_list[0] == NULL);
1171-
1172-
PyTupleObject *op = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, 0);
1173-
if (op == NULL) {
1174-
return -1;
1175-
}
1176-
// The empty tuple singleton is not tracked by the GC.
1177-
// It does not contain any Python object.
1178-
1179-
STATE.free_list[0] = op;
1180-
assert(STATE.numfree[0] == 0);
1181-
STATE.numfree[0] = 1;
1182-
#endif
1183-
return 0;
1184-
}
1185-
1186-
static inline PyTupleObject *
1187-
maybe_freelist_get_empty_singleton(void)
1188-
{
1189-
#if PyTuple_NFREELISTS > 0
1190-
PyTupleObject *op = STATE.free_list[0];
1191-
// maybe_freelist_get_empty_singleton() must not be called
1192-
// before maybe_freelist_init_empty_tuple()
1193-
// or after maybe_freelist_clear(fini=1).
1194-
assert(op != NULL);
1195-
#ifdef Py_DEBUG
1196-
assert(STATE.numfree[0] == 1);
1197-
#endif
1198-
return (PyObject *) op;
1199-
#else
1200-
return NULL;
1201-
#endif
1202-
}
1203-
12041169
static inline PyTupleObject *
12051170
maybe_freelist_pop(Py_ssize_t size)
12061171
{
@@ -1210,9 +1175,12 @@ maybe_freelist_pop(Py_ssize_t size)
12101175
/* maybe_freelist_pop() must not be called after maybe_freelist_fini(). */
12111176
assert(!FREELIST_FINALIZED);
12121177
#endif
1178+
if (size == 0) {
1179+
return NULL;
1180+
}
12131181
assert(size > 0);
12141182
if (size < PyTuple_MAXSAVESIZE) {
1215-
Py_ssize_t index = size;
1183+
Py_ssize_t index = size - 1;
12161184
PyTupleObject *op = STATE.free_list[index];
12171185
if (op != NULL) {
12181186
/* op is the head of a linked list, with the first item
@@ -1245,16 +1213,9 @@ maybe_freelist_push(PyTupleObject *op)
12451213
assert(!FREELIST_FINALIZED);
12461214
#endif
12471215
if (Py_SIZE(op) == 0) {
1248-
#ifdef Py_DEBUG
1249-
// The empty tuple singleton must only be deallocated by
1250-
// maybe_freelist_fini(): not before, not after.
1251-
if (op == STATE.free_list[0] && STATE.numfree[0] < 0) {
1252-
_Py_FatalRefcountError("deallocating the empty tuple singleton");
1253-
}
1254-
#endif
1255-
return 1;
1216+
return 0;
12561217
}
1257-
Py_ssize_t index = Py_SIZE(op);
1218+
Py_ssize_t index = Py_SIZE(op) - 1;
12581219
if (index < PyTuple_NFREELISTS
12591220
&& STATE.numfree[index] < PyTuple_MAXFREELIST
12601221
&& Py_IS_TYPE(op, &PyTuple_Type))
@@ -1274,20 +1235,7 @@ static void
12741235
maybe_freelist_clear(PyInterpreterState *interp, int fini)
12751236
{
12761237
#if PyTuple_NFREELISTS > 0
1277-
// The empty tuple singleton is only cleared during finalization.
1278-
if (fini) {
1279-
assert(!_PyObject_GC_IS_TRACKED(STATE.free_list[0]));
1280-
// XXX Is this right?
1281-
assert(STATE.free_list[0].ob_item[0] == NULL);
1282-
#ifdef Py_DEBUG
1283-
STATE.numfree[0] = 0;
1284-
#endif
1285-
Py_CLEAR(STATE.free_list[0]);
1286-
#ifdef Py_DEBUG
1287-
STATE.numfree[0] = -1;
1288-
#endif
1289-
}
1290-
for (Py_ssize_t i = 1; i < PyTuple_NFREELISTS; i++) {
1238+
for (Py_ssize_t i = 0; i < PyTuple_NFREELISTS; i++) {
12911239
PyTupleObject *p = STATE.free_list[i];
12921240
STATE.free_list[i] = NULL;
12931241
STATE.numfree[i] = fini ? -1 : 0;
@@ -1307,7 +1255,7 @@ _PyTuple_DebugMallocStats(FILE *out)
13071255
#if PyTuple_NFREELISTS > 0
13081256
PyInterpreterState *interp = _PyInterpreterState_GET();
13091257
for (int i = 0; i < PyTuple_NFREELISTS; i++) {
1310-
int len = i;
1258+
int len = i + 1;
13111259
char buf[128];
13121260
PyOS_snprintf(buf, sizeof(buf),
13131261
"free %d-sized PyTupleObject", len);

Python/pylifecycle.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -682,11 +682,6 @@ pycore_init_global_objects(PyInterpreterState *interp)
682682

683683
_PyUnicode_InitState(interp);
684684

685-
status = _PyTuple_InitGlobalObjects(interp);
686-
if (_PyStatus_EXCEPTION(status)) {
687-
return status;
688-
}
689-
690685
return _PyStatus_OK();
691686
}
692687

Tools/scripts/deepfreeze.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,8 @@ def generate_code(self, name: str, code: types.CodeType) -> str:
284284
return f"& {name}.ob_base"
285285

286286
def generate_tuple(self, name: str, t: Tuple[object, ...]) -> str:
287+
if len(t) == 0:
288+
return f"(PyObject *)& _Py_SINGLETON(tuple_empty)"
287289
items = [self.generate(f"{name}_{i}", it) for i, it in enumerate(t)]
288290
self.write("static")
289291
with self.indent():

Tools/scripts/generate_global_objects.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,9 @@ def generate_runtime_init(identifiers, strings):
252252
for name in sorted(identifiers):
253253
assert name.isidentifier(), name
254254
printer.write(f'INIT_ID({name}),')
255+
printer.write('')
256+
with printer.block('.tuple_empty =', ','):
257+
printer.write('.ob_base = _PyVarObject_IMMORTAL_INIT(&PyTuple_Type, 0)')
255258
printer.write(END)
256259
printer.write(after)
257260

0 commit comments

Comments
 (0)