@@ -16,25 +16,10 @@ class tuple "PyTupleObject *" "&PyTuple_Type"
16
16
#include "clinic/tupleobject.c.h"
17
17
18
18
19
- #define STATE (interp->tuple)
19
+ static inline PyTupleObject * maybe_freelist_pop (Py_ssize_t );
20
+ static inline int maybe_freelist_push (PyTupleObject * );
20
21
21
22
22
- /* Print summary info about the state of the optimized allocator */
23
- void
24
- _PyTuple_DebugMallocStats (FILE * out )
25
- {
26
- #if PyTuple_MAXSAVESIZE > 0
27
- PyInterpreterState * interp = _PyInterpreterState_GET ();
28
- for (int i = 1 ; i < PyTuple_MAXSAVESIZE ; i ++ ) {
29
- char buf [128 ];
30
- PyOS_snprintf (buf , sizeof (buf ),
31
- "free %d-sized PyTupleObject" , i );
32
- _PyDebugAllocatorStats (out , buf , STATE .numfree [i - 1 ],
33
- _PyObject_VAR_SIZE (& PyTuple_Type , i ));
34
- }
35
- #endif
36
- }
37
-
38
23
/* Allocate an uninitialized tuple object. Before making it public, following
39
24
steps must be done:
40
25
@@ -48,33 +33,14 @@ _PyTuple_DebugMallocStats(FILE *out)
48
33
static PyTupleObject *
49
34
tuple_alloc (Py_ssize_t size )
50
35
{
51
- PyTupleObject * op ;
52
- /* The empty tuple is statically allocated. */
53
- if (size <= 0 ) {
36
+ assert (size != 0 ); // The empty tuple is statically allocated.
37
+ if (size < 0 ) {
54
38
PyErr_BadInternalCall ();
55
39
return NULL ;
56
40
}
57
41
58
- // Check for max save size > 1.
59
- #if PyTuple_MAXSAVESIZE > 1
60
- PyInterpreterState * interp = _PyInterpreterState_GET ();
61
- #ifdef Py_DEBUG
62
- // tuple_alloc() must not be called after _PyTuple_Fini()
63
- assert (STATE .numfree [0 ] >= 0 );
64
- #endif
65
- if (size < PyTuple_MAXSAVESIZE && (op = STATE .free_list [size - 1 ]) != NULL ) {
66
- STATE .free_list [size - 1 ] = (PyTupleObject * ) op -> ob_item [0 ];
67
- STATE .numfree [size - 1 ]-- ;
68
- /* Inlined _PyObject_InitVar() without _PyType_HasFeature() test */
69
- #ifdef Py_TRACE_REFS
70
- Py_SET_SIZE (op , size );
71
- Py_SET_TYPE (op , & PyTuple_Type );
72
- #endif
73
- _Py_NewReference ((PyObject * )op );
74
- }
75
- else
76
- #endif
77
- {
42
+ PyTupleObject * op = maybe_freelist_pop (size );
43
+ if (op == NULL ) {
78
44
/* Check for overflow */
79
45
if ((size_t )size > ((size_t )PY_SSIZE_T_MAX - (sizeof (PyTupleObject ) -
80
46
sizeof (PyObject * ))) / sizeof (PyObject * )) {
@@ -226,32 +192,14 @@ tupledealloc(PyTupleObject *op)
226
192
PyObject_GC_UnTrack (op );
227
193
Py_TRASHCAN_BEGIN (op , tupledealloc )
228
194
229
- Py_ssize_t len = Py_SIZE (op );
230
- Py_ssize_t i = len ;
195
+ Py_ssize_t i = Py_SIZE (op );
231
196
while (-- i >= 0 ) {
232
197
Py_XDECREF (op -> ob_item [i ]);
233
198
}
234
- #if PyTuple_MAXSAVESIZE > 0
235
- PyInterpreterState * interp = _PyInterpreterState_GET ();
236
- #ifdef Py_DEBUG
237
- // tupledealloc() must not be called after _PyTuple_Fini()
238
- assert (STATE .numfree [0 ] >= 0 );
239
- #endif
240
- if (len < (PyTuple_MAXSAVESIZE - 1 )
241
- && STATE .numfree [len - 1 ] < PyTuple_MAXFREELIST
242
- && Py_IS_TYPE (op , & PyTuple_Type ))
243
- {
244
- op -> ob_item [0 ] = (PyObject * ) STATE .free_list [len - 1 ];
245
- STATE .numfree [len - 1 ]++ ;
246
- STATE .free_list [len - 1 ] = op ;
247
- goto done ; /* return */
199
+ if (!maybe_freelist_push (op )) {
200
+ Py_TYPE (op )-> tp_free ((PyObject * )op );
248
201
}
249
- #endif
250
- Py_TYPE (op )-> tp_free ((PyObject * )op );
251
202
252
- #if PyTuple_MAXSAVESIZE > 0
253
- done :
254
- #endif
255
203
Py_TRASHCAN_END
256
204
}
257
205
@@ -1014,23 +962,6 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
1014
962
return 0 ;
1015
963
}
1016
964
1017
- void
1018
- _PyTuple_ClearFreeList (PyInterpreterState * interp )
1019
- {
1020
- #if PyTuple_MAXSAVESIZE > 0
1021
- for (Py_ssize_t i = 1 ; i < PyTuple_MAXSAVESIZE ; i ++ ) {
1022
- PyTupleObject * p = STATE .free_list [i - 1 ];
1023
- STATE .free_list [i - 1 ] = NULL ;
1024
- STATE .numfree [i - 1 ] = 0 ;
1025
- while (p ) {
1026
- PyTupleObject * q = p ;
1027
- p = (PyTupleObject * )(p -> ob_item [0 ]);
1028
- PyObject_GC_Del (q );
1029
- }
1030
- }
1031
- #endif
1032
- }
1033
-
1034
965
1035
966
PyStatus
1036
967
_PyTuple_InitTypes (PyInterpreterState * interp )
@@ -1050,15 +981,20 @@ _PyTuple_InitTypes(PyInterpreterState *interp)
1050
981
return _PyStatus_OK ();
1051
982
}
1052
983
984
+ static void maybe_freelist_clear (PyInterpreterState * );
985
+ static void maybe_freelist_fini (PyInterpreterState * );
986
+
1053
987
void
1054
988
_PyTuple_Fini (PyInterpreterState * interp )
1055
989
{
1056
- #if PyTuple_MAXSAVESIZE > 0
1057
- _PyTuple_ClearFreeList (interp );
1058
- for (Py_ssize_t i = 1 ; i < PyTuple_MAXSAVESIZE ; i ++ ) {
1059
- interp -> tuple .numfree [i - 1 ] = -1 ;
1060
- }
1061
- #endif
990
+ maybe_freelist_clear (interp );
991
+ maybe_freelist_fini (interp );
992
+ }
993
+
994
+ void
995
+ _PyTuple_ClearFreeList (PyInterpreterState * interp )
996
+ {
997
+ maybe_freelist_clear (interp );
1062
998
}
1063
999
1064
1000
/*********************** Tuple Iterator **************************/
@@ -1206,3 +1142,116 @@ tuple_iter(PyObject *seq)
1206
1142
_PyObject_GC_TRACK (it );
1207
1143
return (PyObject * )it ;
1208
1144
}
1145
+
1146
+
1147
+ /*************
1148
+ * freelists *
1149
+ *************/
1150
+
1151
+ #define STATE (interp->tuple)
1152
+ #define FREELIST_FINALIZED (STATE.numfree[0] < 0)
1153
+
1154
+ static inline PyTupleObject *
1155
+ maybe_freelist_pop (Py_ssize_t size )
1156
+ {
1157
+ #if PyTuple_MAXSAVESIZE > 0
1158
+ PyInterpreterState * interp = _PyInterpreterState_GET ();
1159
+ #ifdef Py_DEBUG
1160
+ /* maybe_freelist_pop() must not be called after maybe_freelist_fini(). */
1161
+ assert (!FREELIST_FINALIZED );
1162
+ #endif
1163
+ Py_ssize_t index = size - 1 ;
1164
+ if (index < PyTuple_MAXSAVESIZE ) {
1165
+ PyTupleObject * op = STATE .free_list [index ];
1166
+ if (op != NULL ) {
1167
+ /* op is the head of a linked list, with the first item
1168
+ pointing to the next node. Here we pop off the old head. */
1169
+ STATE .free_list [index ] = (PyTupleObject * ) op -> ob_item [0 ];
1170
+ STATE .numfree [index ]-- ;
1171
+ /* Inlined _PyObject_InitVar() without _PyType_HasFeature() test */
1172
+ #ifdef Py_TRACE_REFS
1173
+ /* maybe_freelist_push() ensures these were already set. */
1174
+ // XXX Can we drop these? See commit 68055ce6fe01 (GvR, Dec 1998).
1175
+ Py_SET_SIZE (op , size );
1176
+ Py_SET_TYPE (op , & PyTuple_Type );
1177
+ #endif
1178
+ _Py_NewReference ((PyObject * )op );
1179
+ /* END inlined _PyObject_InitVar() */
1180
+ return op ;
1181
+ }
1182
+ }
1183
+ #endif
1184
+ return NULL ;
1185
+ }
1186
+
1187
+ static inline int
1188
+ maybe_freelist_push (PyTupleObject * op )
1189
+ {
1190
+ #if PyTuple_MAXSAVESIZE > 0
1191
+ PyInterpreterState * interp = _PyInterpreterState_GET ();
1192
+ #ifdef Py_DEBUG
1193
+ /* maybe_freelist_push() must not be called after maybe_freelist_fini(). */
1194
+ assert (!FREELIST_FINALIZED );
1195
+ #endif
1196
+ Py_ssize_t index = Py_SIZE (op ) - 1 ;
1197
+ if (index < PyTuple_MAXSAVESIZE
1198
+ && STATE .numfree [index ] < PyTuple_MAXFREELIST
1199
+ && Py_IS_TYPE (op , & PyTuple_Type ))
1200
+ {
1201
+ /* op is the head of a linked list, with the first item
1202
+ pointing to the next node. Here we set op as the new head. */
1203
+ op -> ob_item [0 ] = (PyObject * ) STATE .free_list [index ];
1204
+ STATE .free_list [index ] = op ;
1205
+ STATE .numfree [index ]++ ;
1206
+ return 1 ;
1207
+ }
1208
+ #endif
1209
+ return 0 ;
1210
+ }
1211
+
1212
+ static void
1213
+ maybe_freelist_clear (PyInterpreterState * interp )
1214
+ {
1215
+ #if PyTuple_MAXSAVESIZE > 0
1216
+ for (Py_ssize_t i = 0 ; i < PyTuple_MAXSAVESIZE ; i ++ ) {
1217
+ PyTupleObject * p = STATE .free_list [i ];
1218
+ STATE .free_list [i ] = NULL ;
1219
+ STATE .numfree [i ] = 0 ;
1220
+ while (p ) {
1221
+ PyTupleObject * q = p ;
1222
+ p = (PyTupleObject * )(p -> ob_item [0 ]);
1223
+ PyObject_GC_Del (q );
1224
+ }
1225
+ }
1226
+ #endif
1227
+ }
1228
+
1229
+ static void
1230
+ maybe_freelist_fini (PyInterpreterState * interp )
1231
+ {
1232
+ #if PyTuple_MAXSAVESIZE > 0
1233
+ for (Py_ssize_t i = 0 ; i < PyTuple_MAXSAVESIZE ; i ++ ) {
1234
+ STATE .numfree [i ] = -1 ;
1235
+ }
1236
+ #endif
1237
+ }
1238
+
1239
+ /* Print summary info about the state of the optimized allocator */
1240
+ void
1241
+ _PyTuple_DebugMallocStats (FILE * out )
1242
+ {
1243
+ #if PyTuple_MAXSAVESIZE > 0
1244
+ PyInterpreterState * interp = _PyInterpreterState_GET ();
1245
+ for (int i = 0 ; i < PyTuple_MAXSAVESIZE ; i ++ ) {
1246
+ int len = i + 1 ;
1247
+ char buf [128 ];
1248
+ PyOS_snprintf (buf , sizeof (buf ),
1249
+ "free %d-sized PyTupleObject" , len );
1250
+ _PyDebugAllocatorStats (out , buf , STATE .numfree [i ],
1251
+ _PyObject_VAR_SIZE (& PyTuple_Type , len ));
1252
+ }
1253
+ #endif
1254
+ }
1255
+
1256
+ #undef STATE
1257
+ #undef FREELIST_FINALIZED
0 commit comments