Skip to content

Commit d4e4427

Browse files
cmaloneyclaude
andcommitted
gh-160858: Use the list freelist in list()
list() allocated its result with PyType_GenericAlloc(), bypassing the freelist that PyList_New() and the [] display use. For an exact list, allocate with PyList_New(0) instead. The object handed to list.__init__() is in the same state either way: empty, with no item array, and tracked by the GC. Subclasses still use PyType_GenericAlloc(). pyperf, PGO+LTO, base 19270d3, two interleaved rounds per side (a third round, disturbed by machine load, was dropped): | Benchmark | main | branch | |----------------|:-------:|:---------------------:| | list() | 21.2 ns | 15.3 ns: 1.38x faster | | list(d) | 36.1 ns | 27.4 ns: 1.32x faster | | list(t) | 30.3 ns | 23.9 ns: 1.27x faster | | list(l) | 32.0 ns | 25.7 ns: 1.24x faster | | list(r) | 43.6 ns | 36.0 ns: 1.21x faster | | x + 1 | 10.4 ns | 9.70 ns: 1.07x faster | | len(l) | 9.87 ns | 9.53 ns: 1.03x faster | | l[0] | 8.24 ns | 8.00 ns: 1.03x faster | | L(t) | 48.2 ns | 47.4 ns: 1.02x faster | | tuple(l) | 15.4 ns | 16.0 ns: 1.04x slower | | Geometric mean | (ref) | 1.13x faster | Not significant: []. x + 1, len(l), l[0], L(t) and tuple(l) don't run the changed code; their movement is layout noise, within the up-to-1.07x spread between two runs of the same main build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 19270d3 commit d4e4427

2 files changed

Lines changed: 7 additions & 2 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Speed up :class:`list` construction by reusing list objects from the free
2+
list, as ``[]`` already does.

‎Objects/listobject.c‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3600,7 +3600,7 @@ static int
36003600
list___init___impl(PyListObject *self, PyObject *iterable)
36013601
/*[clinic end generated code: output=0f3c21379d01de48 input=b3f3fe7206af8f6b]*/
36023602
{
3603-
/* Verify list invariants established by PyType_GenericAlloc() */
3603+
/* Verify list invariants */
36043604
assert(0 <= Py_SIZE(self));
36053605
assert(Py_SIZE(self) <= self->allocated || self->allocated == -1);
36063606
assert(self->ob_item != NULL ||
@@ -3632,7 +3632,10 @@ list_vectorcall(PyObject *type, PyObject * const*args,
36323632
return NULL;
36333633
}
36343634

3635-
PyObject *list = PyType_GenericAlloc(_PyType_CAST(type), 0);
3635+
/* use PyList_New() to make exact lists from the freelist. */
3636+
PyObject *list = (type == (PyObject *)&PyList_Type
3637+
? PyList_New(0)
3638+
: PyType_GenericAlloc(_PyType_CAST(type), 0));
36363639
if (list == NULL) {
36373640
return NULL;
36383641
}

0 commit comments

Comments
 (0)