Skip to content

Commit 21952b5

Browse files
committed
gh-145497: Compute static builtin type count at compile time
1 parent 785b6dc commit 21952b5

8 files changed

Lines changed: 316 additions & 243 deletions

File tree

Include/internal/pycore_interp_structs.h

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -529,17 +529,10 @@ struct _py_func_state {
529529

530530
/****** type state *********/
531531

532-
/* For now we hard-code this to a value for which we are confident
533-
all the static builtin types will fit (for all builds).
534-
If you add a new static type to the standard library, you may have to
535-
update one of these numbers.
536-
*/
537-
#define _Py_NUM_MANAGED_PREINITIALIZED_TYPES 120
538-
#define _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES \
539-
(_Py_NUM_MANAGED_PREINITIALIZED_TYPES + 83)
540-
#define _Py_MAX_MANAGED_STATIC_EXT_TYPES 10
541-
#define _Py_MAX_MANAGED_STATIC_TYPES \
542-
(_Py_MAX_MANAGED_STATIC_BUILTIN_TYPES + _Py_MAX_MANAGED_STATIC_EXT_TYPES)
532+
/* All _Py_MAX_MANAGED_STATIC_* sizing macros are derived at compile
533+
time from the X-macro lists in pycore_static_builtin_types.h, the
534+
single source of truth for every static builtin registration. */
535+
#include "pycore_static_builtin_types.h"
543536

544537
struct _types_runtime_state {
545538
/* Used to set PyTypeObject.tp_version_tag for core static types. */
Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
#ifndef Py_INTERNAL_STATIC_BUILTIN_TYPES_H
2+
#define Py_INTERNAL_STATIC_BUILTIN_TYPES_H
3+
#ifdef __cplusplus
4+
extern "C" {
5+
#endif
6+
7+
#ifndef Py_BUILD_CORE
8+
# error "this header requires Py_BUILD_CORE define"
9+
#endif
10+
11+
/* Single source of truth for every static builtin type registered at
12+
startup, partitioned by where it is registered. Adding a
13+
registration anywhere in the tree requires adding an entry to the
14+
matching list; _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES then adjusts at
15+
compile time (gh-145497). */
16+
17+
18+
#ifdef _Py_TIER2
19+
# define _Py_FOREACH_TIER2_PREINIT_TYPE(TYPE) TYPE(_PyUOpExecutor_Type)
20+
#else
21+
# define _Py_FOREACH_TIER2_PREINIT_TYPE(TYPE)
22+
#endif
23+
24+
/* Registered via static_types[] in Objects/object.c.
25+
Order matters: base types first; trailing subclasses last so
26+
_PyTypes_FiniTypes() tears them down before their base. */
27+
#define _Py_FOREACH_STATIC_PREINIT_TYPE(TYPE) \
28+
TYPE(PyBaseObject_Type) \
29+
TYPE(PyType_Type) \
30+
TYPE(PyStaticMethod_Type) \
31+
TYPE(PyCFunction_Type) \
32+
\
33+
TYPE(PyAsyncGen_Type) \
34+
TYPE(PyByteArrayIter_Type) \
35+
TYPE(PyByteArray_Type) \
36+
TYPE(PyBytesIter_Type) \
37+
TYPE(PyBytes_Type) \
38+
TYPE(PyCallIter_Type) \
39+
TYPE(PyCapsule_Type) \
40+
TYPE(PyCell_Type) \
41+
TYPE(PyClassMethodDescr_Type) \
42+
TYPE(PyClassMethod_Type) \
43+
TYPE(PyCode_Type) \
44+
TYPE(PyComplex_Type) \
45+
TYPE(PyContextToken_Type) \
46+
TYPE(PyContextVar_Type) \
47+
TYPE(PyContext_Type) \
48+
TYPE(PyCoro_Type) \
49+
TYPE(PyDictItems_Type) \
50+
TYPE(PyDictIterItem_Type) \
51+
TYPE(PyDictIterKey_Type) \
52+
TYPE(PyDictIterValue_Type) \
53+
TYPE(PyDictKeys_Type) \
54+
TYPE(PyDictProxy_Type) \
55+
TYPE(PyDictRevIterItem_Type) \
56+
TYPE(PyDictRevIterKey_Type) \
57+
TYPE(PyDictRevIterValue_Type) \
58+
TYPE(PyDictValues_Type) \
59+
TYPE(PyDict_Type) \
60+
TYPE(PyEllipsis_Type) \
61+
TYPE(PyEnum_Type) \
62+
TYPE(PyFilter_Type) \
63+
TYPE(PyFloat_Type) \
64+
TYPE(PyFrameLocalsProxy_Type) \
65+
TYPE(PyFrame_Type) \
66+
TYPE(PyFrozenDict_Type) \
67+
TYPE(PyFrozenSet_Type) \
68+
TYPE(PyFunction_Type) \
69+
TYPE(PyGen_Type) \
70+
TYPE(PyGetSetDescr_Type) \
71+
TYPE(PyInstanceMethod_Type) \
72+
TYPE(PyLazyImport_Type) \
73+
TYPE(PyListIter_Type) \
74+
TYPE(PyListRevIter_Type) \
75+
TYPE(PyList_Type) \
76+
TYPE(PyLongRangeIter_Type) \
77+
TYPE(PyLong_Type) \
78+
TYPE(PyMap_Type) \
79+
TYPE(PyMemberDescr_Type) \
80+
TYPE(PyMemoryView_Type) \
81+
TYPE(PyMethodDescr_Type) \
82+
TYPE(PyMethod_Type) \
83+
TYPE(PyModuleDef_Type) \
84+
TYPE(PyModule_Type) \
85+
TYPE(PyODictIter_Type) \
86+
TYPE(PyPickleBuffer_Type) \
87+
TYPE(PyProperty_Type) \
88+
TYPE(PyRangeIter_Type) \
89+
TYPE(PyRange_Type) \
90+
TYPE(PyReversed_Type) \
91+
TYPE(PySTEntry_Type) \
92+
TYPE(PySentinel_Type) \
93+
TYPE(PySeqIter_Type) \
94+
TYPE(PySetIter_Type) \
95+
TYPE(PySet_Type) \
96+
TYPE(PySlice_Type) \
97+
TYPE(PyStdPrinter_Type) \
98+
TYPE(PySuper_Type) \
99+
TYPE(PyTraceBack_Type) \
100+
TYPE(PyTupleIter_Type) \
101+
TYPE(PyTuple_Type) \
102+
TYPE(PyUnicodeIter_Type) \
103+
TYPE(PyUnicode_Type) \
104+
TYPE(PyWrapperDescr_Type) \
105+
TYPE(PyZip_Type) \
106+
TYPE(Py_GenericAliasType) \
107+
TYPE(_PyAnextAwaitable_Type) \
108+
TYPE(_PyAsyncGenASend_Type) \
109+
TYPE(_PyAsyncGenAThrow_Type) \
110+
TYPE(_PyAsyncGenWrappedValue_Type) \
111+
TYPE(_PyBufferWrapper_Type) \
112+
TYPE(_PyContextTokenMissing_Type) \
113+
TYPE(_PyCoroWrapper_Type) \
114+
TYPE(_Py_GenericAliasIterType) \
115+
TYPE(_PyHamtItems_Type) \
116+
TYPE(_PyHamtKeys_Type) \
117+
TYPE(_PyHamtValues_Type) \
118+
TYPE(_PyHamt_ArrayNode_Type) \
119+
TYPE(_PyHamt_BitmapNode_Type) \
120+
TYPE(_PyHamt_CollisionNode_Type) \
121+
TYPE(_PyHamt_Type) \
122+
TYPE(_PyInstructionSequence_Type) \
123+
TYPE(_PyInterpolation_Type) \
124+
TYPE(_PyLegacyEventHandler_Type) \
125+
TYPE(_PyLineIterator) \
126+
TYPE(_PyManagedBuffer_Type) \
127+
TYPE(_PyMemoryIter_Type) \
128+
TYPE(_PyMethodWrapper_Type) \
129+
TYPE(_PyNamespace_Type) \
130+
TYPE(_PyNone_Type) \
131+
TYPE(_PyNotImplemented_Type) \
132+
TYPE(_PyPositionsIterator) \
133+
TYPE(_PyTemplate_Type) \
134+
TYPE(_PyTemplateIter_Type) \
135+
TYPE(_PyUnicodeASCIIIter_Type) \
136+
TYPE(_PyUnion_Type) \
137+
_Py_FOREACH_TIER2_PREINIT_TYPE(TYPE) \
138+
TYPE(_PyWeakref_CallableProxyType) \
139+
TYPE(_PyWeakref_ProxyType) \
140+
TYPE(_PyWeakref_RefType) \
141+
TYPE(_PyTypeAlias_Type) \
142+
TYPE(_PyNoDefault_Type) \
143+
\
144+
TYPE(PyBool_Type) \
145+
TYPE(PyCMethod_Type) \
146+
TYPE(PyODictItems_Type) \
147+
TYPE(PyODictKeys_Type) \
148+
TYPE(PyODictValues_Type) \
149+
TYPE(PyODict_Type)
150+
151+
152+
/* Registered via static_exceptions[] in Objects/exceptions.c.
153+
NAME is the suffix; the real type is &_PyExc_<NAME>. */
154+
#define _Py_FOREACH_STATIC_EXCEPTION_TYPE(EXC) \
155+
EXC(BaseException) \
156+
\
157+
EXC(BaseExceptionGroup) \
158+
EXC(Exception) \
159+
EXC(GeneratorExit) \
160+
EXC(KeyboardInterrupt) \
161+
EXC(SystemExit) \
162+
\
163+
EXC(ArithmeticError) \
164+
EXC(AssertionError) \
165+
EXC(AttributeError) \
166+
EXC(BufferError) \
167+
EXC(EOFError) \
168+
EXC(ImportError) \
169+
EXC(LookupError) \
170+
EXC(MemoryError) \
171+
EXC(NameError) \
172+
EXC(OSError) \
173+
EXC(ReferenceError) \
174+
EXC(RuntimeError) \
175+
EXC(StopAsyncIteration) \
176+
EXC(StopIteration) \
177+
EXC(SyntaxError) \
178+
EXC(SystemError) \
179+
EXC(TypeError) \
180+
EXC(ValueError) \
181+
EXC(Warning) \
182+
\
183+
EXC(FloatingPointError) \
184+
EXC(OverflowError) \
185+
EXC(ZeroDivisionError) \
186+
\
187+
EXC(BytesWarning) \
188+
EXC(DeprecationWarning) \
189+
EXC(EncodingWarning) \
190+
EXC(FutureWarning) \
191+
EXC(ImportWarning) \
192+
EXC(PendingDeprecationWarning) \
193+
EXC(ResourceWarning) \
194+
EXC(RuntimeWarning) \
195+
EXC(SyntaxWarning) \
196+
EXC(UnicodeWarning) \
197+
EXC(UserWarning) \
198+
\
199+
EXC(BlockingIOError) \
200+
EXC(ChildProcessError) \
201+
EXC(ConnectionError) \
202+
EXC(FileExistsError) \
203+
EXC(FileNotFoundError) \
204+
EXC(InterruptedError) \
205+
EXC(IsADirectoryError) \
206+
EXC(NotADirectoryError) \
207+
EXC(PermissionError) \
208+
EXC(ProcessLookupError) \
209+
EXC(TimeoutError) \
210+
\
211+
EXC(IndentationError) \
212+
EXC(IndexError) \
213+
EXC(KeyError) \
214+
EXC(ImportCycleError) \
215+
EXC(ModuleNotFoundError) \
216+
EXC(NotImplementedError) \
217+
EXC(PythonFinalizationError) \
218+
EXC(RecursionError) \
219+
EXC(UnboundLocalError) \
220+
EXC(UnicodeError) \
221+
\
222+
EXC(BrokenPipeError) \
223+
EXC(ConnectionAbortedError) \
224+
EXC(ConnectionRefusedError) \
225+
EXC(ConnectionResetError) \
226+
\
227+
EXC(TabError) \
228+
\
229+
EXC(UnicodeDecodeError) \
230+
EXC(UnicodeEncodeError) \
231+
EXC(UnicodeTranslateError)
232+
233+
234+
/* Static exceptions whose exposed name differs from the symbol's
235+
suffix after `_PyExc_`. Each entry is (NAME, "exposed name"). */
236+
#define _Py_FOREACH_RENAMED_EXCEPTION_TYPE(EXC) \
237+
EXC(IncompleteInputError, "_IncompleteInputError")
238+
239+
240+
/* One TYPE(name) per textual _PyStaticType_InitBuiltin /
241+
_PyStructSequence_InitBuiltin{,WithFlags} call site outside the two
242+
arrays above. Count-only -- the calls themselves stay at their
243+
existing locations. Forgetting an entry trips the
244+
`index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES` assertion in
245+
Objects/typeobject.c on interpreter start. */
246+
#define _Py_FOREACH_STATIC_EXTRA_TYPE(TYPE) \
247+
/* Python/crossinterp_exceptions.h */ \
248+
TYPE(_PyExc_InterpreterError) \
249+
TYPE(_PyExc_InterpreterNotFoundError) \
250+
/* Objects/unicodeobject.c */ \
251+
TYPE(EncodingMapType) \
252+
TYPE(PyFieldNameIter_Type) \
253+
TYPE(PyFormatterIter_Type) \
254+
/* Python/thread.c */ \
255+
TYPE(ThreadInfoType) \
256+
/* Python/sysmodule.c */ \
257+
TYPE(Hash_InfoType) \
258+
TYPE(AsyncGenHooksType) \
259+
TYPE(VersionInfoType) \
260+
TYPE(FlagsType) \
261+
TYPE(WindowsVersionType) \
262+
/* Python/errors.c */ \
263+
TYPE(UnraisableHookArgsType) \
264+
/* Objects/longobject.c */ \
265+
TYPE(Int_InfoType) \
266+
/* Objects/floatobject.c */ \
267+
TYPE(FloatInfoType)
268+
269+
270+
/* Variadic so it accepts both single-arg X(name) and two-arg X(name, str). */
271+
#define _PY_COUNT_STATIC_TYPE_(...) + 1
272+
273+
#define _Py_NUM_MANAGED_PREINITIALIZED_TYPES \
274+
(0 _Py_FOREACH_STATIC_PREINIT_TYPE(_PY_COUNT_STATIC_TYPE_))
275+
276+
#define _Py_NUM_MANAGED_STATIC_EXCEPTION_TYPES \
277+
(0 _Py_FOREACH_STATIC_EXCEPTION_TYPE(_PY_COUNT_STATIC_TYPE_) \
278+
_Py_FOREACH_RENAMED_EXCEPTION_TYPE(_PY_COUNT_STATIC_TYPE_))
279+
280+
#define _Py_NUM_MANAGED_STATIC_EXTRA_TYPES \
281+
(0 _Py_FOREACH_STATIC_EXTRA_TYPE(_PY_COUNT_STATIC_TYPE_))
282+
283+
#define _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES \
284+
(_Py_NUM_MANAGED_PREINITIALIZED_TYPES + \
285+
_Py_NUM_MANAGED_STATIC_EXCEPTION_TYPES + \
286+
_Py_NUM_MANAGED_STATIC_EXTRA_TYPES)
287+
288+
#define _Py_MAX_MANAGED_STATIC_EXT_TYPES 10
289+
290+
#define _Py_MAX_MANAGED_STATIC_TYPES \
291+
(_Py_MAX_MANAGED_STATIC_BUILTIN_TYPES + _Py_MAX_MANAGED_STATIC_EXT_TYPES)
292+
293+
294+
#ifdef __cplusplus
295+
}
296+
#endif
297+
#endif /* !Py_INTERNAL_STATIC_BUILTIN_TYPES_H */

Makefile.pre.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,6 +1399,7 @@ PYTHON_HEADERS= \
13991399
$(srcdir)/Include/internal/pycore_sliceobject.h \
14001400
$(srcdir)/Include/internal/pycore_slots.h \
14011401
$(srcdir)/Include/internal/pycore_slots_generated.h \
1402+
$(srcdir)/Include/internal/pycore_static_builtin_types.h \
14021403
$(srcdir)/Include/internal/pycore_stats.h \
14031404
$(srcdir)/Include/internal/pycore_strhex.h \
14041405
$(srcdir)/Include/internal/pycore_stackref.h \
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Compute static builtin type count at compile time. Patch by Donghee Na.

0 commit comments

Comments
 (0)