@@ -8,144 +8,109 @@ extern "C" {
8
8
# error "this header requires Py_BUILD_CORE define"
9
9
#endif
10
10
11
- // PyTuple_MAXSAVESIZE - largest tuple to save on free list
12
- // PyTuple_MAXFREELIST - maximum number of tuples of each size to save
13
-
14
- #ifdef WITH_FREELISTS
15
- // with freelists
16
- # define PyTuple_MAXSAVESIZE 20
17
- # define PyTuple_NFREELISTS PyTuple_MAXSAVESIZE
18
- # define PyTuple_MAXFREELIST 2000
19
- # define PyList_MAXFREELIST 80
20
- # define PyDict_MAXFREELIST 80
21
- # define PyFloat_MAXFREELIST 100
22
- # define PyContext_MAXFREELIST 255
23
- # define _PyAsyncGen_MAXFREELIST 80
24
- # define _PyObjectStackChunk_MAXFREELIST 4
25
- #else
26
- # define PyTuple_NFREELISTS 0
27
- # define PyTuple_MAXFREELIST 0
28
- # define PyList_MAXFREELIST 0
29
- # define PyDict_MAXFREELIST 0
30
- # define PyFloat_MAXFREELIST 0
31
- # define PyContext_MAXFREELIST 0
32
- # define _PyAsyncGen_MAXFREELIST 0
33
- # define _PyObjectStackChunk_MAXFREELIST 0
34
- #endif
35
-
36
- struct _Py_list_freelist {
37
- #ifdef WITH_FREELISTS
38
- PyListObject * items [PyList_MAXFREELIST ];
39
- int numfree ;
11
+ #include "pycore_freelist_state.h" // struct _Py_freelists
12
+ #include "pycore_object.h" // _PyObject_IS_GC
13
+ #include "pycore_pystate.h" // _PyThreadState_GET
14
+ #include "pycore_code.h" // OBJECT_STAT_INC
15
+
16
+ static inline struct _Py_freelists *
17
+ _Py_freelists_GET (void )
18
+ {
19
+ PyThreadState * tstate = _PyThreadState_GET ();
20
+ #ifdef Py_DEBUG
21
+ _Py_EnsureTstateNotNULL (tstate );
40
22
#endif
41
- };
42
-
43
- struct _Py_tuple_freelist {
44
- #if WITH_FREELISTS
45
- /* There is one freelist for each size from 1 to PyTuple_MAXSAVESIZE.
46
- The empty tuple is handled separately.
47
23
48
- Each tuple stored in the array is the head of the linked list
49
- (and the next available tuple) for that size. The actual tuple
50
- object is used as the linked list node, with its first item
51
- (ob_item[0]) pointing to the next node (i.e. the previous head).
52
- Each linked list is initially NULL. */
53
- PyTupleObject * items [PyTuple_NFREELISTS ];
54
- int numfree [PyTuple_NFREELISTS ];
24
+ #ifdef Py_GIL_DISABLED
25
+ return & ((_PyThreadStateImpl * )tstate )-> freelists ;
55
26
#else
56
- char _unused ; // Empty structs are not allowed.
57
- #endif
58
- };
59
-
60
- struct _Py_float_freelist {
61
- #ifdef WITH_FREELISTS
62
- /* Special free list
63
- free_list is a singly-linked list of available PyFloatObjects,
64
- linked via abuse of their ob_type members. */
65
- int numfree ;
66
- PyFloatObject * items ;
67
- #endif
68
- };
69
-
70
- struct _Py_dict_freelist {
71
- #ifdef WITH_FREELISTS
72
- /* Dictionary reuse scheme to save calls to malloc and free */
73
- PyDictObject * items [PyDict_MAXFREELIST ];
74
- int numfree ;
27
+ return & tstate -> interp -> object_state .freelists ;
75
28
#endif
76
- };
29
+ }
77
30
78
- struct _Py_dictkeys_freelist {
79
- #ifdef WITH_FREELISTS
80
- /* Dictionary keys reuse scheme to save calls to malloc and free */
81
- PyDictKeysObject * items [PyDict_MAXFREELIST ];
82
- int numfree ;
83
- #endif
84
- };
31
+ #ifndef WITH_FREELISTS
32
+ #define _Py_FREELIST_FREE (NAME , op , freefunc ) freefunc(op)
33
+ #define _Py_FREELIST_PUSH (NAME , op , limit ) (0)
34
+ #define _Py_FREELIST_POP (TYPE , NAME ) (NULL)
35
+ #define _Py_FREELIST_POP_MEM (NAME ) (NULL)
36
+ #define _Py_FREELIST_SIZE (NAME ) (0)
37
+ #else
38
+ // Pushes `op` to the freelist, calls `freefunc` if the freelist is full
39
+ #define _Py_FREELIST_FREE (NAME , op , freefunc ) \
40
+ _PyFreeList_Free(&_Py_freelists_GET()->NAME, _PyObject_CAST(op), \
41
+ Py_ ## NAME ## _MAXFREELIST, freefunc)
42
+ // Pushes `op` to the freelist, returns 1 if successful, 0 if the freelist is full
43
+ #define _Py_FREELIST_PUSH (NAME , op , limit ) \
44
+ _PyFreeList_Push(&_Py_freelists_GET()->NAME, _PyObject_CAST(op), limit)
45
+
46
+ // Pops a PyObject from the freelist, returns NULL if the freelist is empty.
47
+ #define _Py_FREELIST_POP (TYPE , NAME ) \
48
+ _Py_CAST(TYPE*, _PyFreeList_Pop(&_Py_freelists_GET()->NAME))
49
+
50
+ // Pops a non-PyObject data structure from the freelist, returns NULL if the
51
+ // freelist is empty.
52
+ #define _Py_FREELIST_POP_MEM (NAME ) \
53
+ _PyFreeList_PopMem(&_Py_freelists_GET()->NAME)
54
+
55
+ #define _Py_FREELIST_SIZE (NAME ) (int)((_Py_freelists_GET()->NAME).size)
56
+
57
+ static inline int
58
+ _PyFreeList_Push (struct _Py_freelist * fl , void * obj , Py_ssize_t maxsize )
59
+ {
60
+ if (fl -> size < maxsize && fl -> size >= 0 ) {
61
+ * (void * * )obj = fl -> freelist ;
62
+ fl -> freelist = obj ;
63
+ fl -> size ++ ;
64
+ OBJECT_STAT_INC (to_freelist );
65
+ return 1 ;
66
+ }
67
+ return 0 ;
68
+ }
85
69
86
- struct _Py_slice_freelist {
87
- #ifdef WITH_FREELISTS
88
- /* Using a cache is very effective since typically only a single slice is
89
- created and then deleted again. */
90
- PySliceObject * slice_cache ;
91
- #endif
92
- };
70
+ static inline void
71
+ _PyFreeList_Free (struct _Py_freelist * fl , void * obj , Py_ssize_t maxsize ,
72
+ freefunc dofree )
73
+ {
74
+ if (!_PyFreeList_Push (fl , obj , maxsize )) {
75
+ dofree (obj );
76
+ }
77
+ }
93
78
94
- struct _Py_context_freelist {
95
- #ifdef WITH_FREELISTS
96
- // List of free PyContext objects
97
- PyContext * items ;
98
- int numfree ;
99
- #endif
100
- };
79
+ static inline void *
80
+ _PyFreeList_PopNoStats (struct _Py_freelist * fl )
81
+ {
82
+ void * obj = fl -> freelist ;
83
+ if (obj != NULL ) {
84
+ assert (fl -> size > 0 );
85
+ fl -> freelist = * (void * * )obj ;
86
+ fl -> size -- ;
87
+ }
88
+ return obj ;
89
+ }
101
90
102
- struct _Py_async_gen_freelist {
103
- #ifdef WITH_FREELISTS
104
- /* Freelists boost performance 6-10%; they also reduce memory
105
- fragmentation, as _PyAsyncGenWrappedValue and PyAsyncGenASend
106
- are short-living objects that are instantiated for every
107
- __anext__() call. */
108
- struct _PyAsyncGenWrappedValue * items [ _PyAsyncGen_MAXFREELIST ] ;
109
- int numfree ;
110
- #endif
111
- };
91
+ static inline PyObject *
92
+ _PyFreeList_Pop ( struct _Py_freelist * fl )
93
+ {
94
+ PyObject * op = _PyFreeList_PopNoStats ( fl );
95
+ if ( op != NULL ) {
96
+ OBJECT_STAT_INC ( from_freelist );
97
+ _Py_NewReference ( op ) ;
98
+ }
99
+ return op ;
100
+ }
112
101
113
- struct _Py_async_gen_asend_freelist {
114
- #ifdef WITH_FREELISTS
115
- struct PyAsyncGenASend * items [_PyAsyncGen_MAXFREELIST ];
116
- int numfree ;
102
+ static inline void *
103
+ _PyFreeList_PopMem (struct _Py_freelist * fl )
104
+ {
105
+ void * op = _PyFreeList_PopNoStats (fl );
106
+ if (op != NULL ) {
107
+ OBJECT_STAT_INC (from_freelist );
108
+ }
109
+ return op ;
110
+ }
117
111
#endif
118
- };
119
-
120
- struct _PyObjectStackChunk ;
121
-
122
- struct _Py_object_stack_freelist {
123
- struct _PyObjectStackChunk * items ;
124
- Py_ssize_t numfree ;
125
- };
126
-
127
- struct _Py_object_freelists {
128
- struct _Py_float_freelist floats ;
129
- struct _Py_tuple_freelist tuples ;
130
- struct _Py_list_freelist lists ;
131
- struct _Py_dict_freelist dicts ;
132
- struct _Py_dictkeys_freelist dictkeys ;
133
- struct _Py_slice_freelist slices ;
134
- struct _Py_context_freelist contexts ;
135
- struct _Py_async_gen_freelist async_gens ;
136
- struct _Py_async_gen_asend_freelist async_gen_asends ;
137
- struct _Py_object_stack_freelist object_stacks ;
138
- };
139
112
140
- extern void _PyObject_ClearFreeLists (struct _Py_object_freelists * freelists , int is_finalization );
141
- extern void _PyTuple_ClearFreeList (struct _Py_object_freelists * freelists , int is_finalization );
142
- extern void _PyFloat_ClearFreeList (struct _Py_object_freelists * freelists , int is_finalization );
143
- extern void _PyList_ClearFreeList (struct _Py_object_freelists * freelists , int is_finalization );
144
- extern void _PySlice_ClearFreeList (struct _Py_object_freelists * freelists , int is_finalization );
145
- extern void _PyDict_ClearFreeList (struct _Py_object_freelists * freelists , int is_finalization );
146
- extern void _PyAsyncGen_ClearFreeLists (struct _Py_object_freelists * freelists , int is_finalization );
147
- extern void _PyContext_ClearFreeList (struct _Py_object_freelists * freelists , int is_finalization );
148
- extern void _PyObjectStackChunk_ClearFreeList (struct _Py_object_freelists * freelists , int is_finalization );
113
+ extern void _PyObject_ClearFreeLists (struct _Py_freelists * freelists , int is_finalization );
149
114
150
115
#ifdef __cplusplus
151
116
}
0 commit comments