Skip to content

Commit 4a1dd73

Browse files
gh-94673: Add _PyStaticType_InitBuiltin() (#95152)
This is the first of several precursors to storing tp_subclasses (and tp_weaklist) on the interpreter state for static builtin types. We do the following: * add `_PyStaticType_InitBuiltin()` * add `_Py_TPFLAGS_STATIC_BUILTIN` * set it on all static builtin types in `_PyStaticType_InitBuiltin()` * shuffle some code around to be able to use _PyStaticType_InitBuiltin() * rename `_PyStructSequence_InitType()` to `_PyStructSequence_InitBuiltinWithFlags()` * add `_PyStructSequence_InitBuiltin()`.
1 parent c514094 commit 4a1dd73

File tree

13 files changed

+133
-76
lines changed

13 files changed

+133
-76
lines changed

Include/internal/pycore_structseq.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,18 @@ PyAPI_FUNC(PyTypeObject *) _PyStructSequence_NewType(
1515
PyStructSequence_Desc *desc,
1616
unsigned long tp_flags);
1717

18-
PyAPI_FUNC(int) _PyStructSequence_InitType(
18+
PyAPI_FUNC(int) _PyStructSequence_InitBuiltinWithFlags(
1919
PyTypeObject *type,
2020
PyStructSequence_Desc *desc,
2121
unsigned long tp_flags);
2222

23+
static inline int
24+
_PyStructSequence_InitBuiltin(PyTypeObject *type,
25+
PyStructSequence_Desc *desc)
26+
{
27+
return _PyStructSequence_InitBuiltinWithFlags(type, desc, 0);
28+
}
29+
2330
extern void _PyStructSequence_FiniType(PyTypeObject *type);
2431

2532
#ifdef __cplusplus

Include/internal/pycore_typeobject.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ struct type_cache {
4141

4242
extern PyStatus _PyTypes_InitSlotDefs(void);
4343

44+
extern int _PyStaticType_InitBuiltin(PyTypeObject *type);
4445
extern void _PyStaticType_Dealloc(PyTypeObject *type);
4546

4647

Include/object.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,9 @@ given type object has a specified feature.
352352

353353
#ifndef Py_LIMITED_API
354354

355+
/* Track types initialized using _PyStaticType_InitBuiltin(). */
356+
#define _Py_TPFLAGS_STATIC_BUILTIN (1 << 1)
357+
355358
/* Placement of dict (and values) pointers are managed by the VM, not by the type.
356359
* The VM will automatically set tp_dictoffset. Should not be used for variable sized
357360
* classes, such as classes that extend tuple.

Objects/exceptions.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3556,8 +3556,7 @@ _PyExc_InitTypes(PyInterpreterState *interp)
35563556

35573557
for (size_t i=0; i < Py_ARRAY_LENGTH(static_exceptions); i++) {
35583558
PyTypeObject *exc = static_exceptions[i].exc;
3559-
3560-
if (PyType_Ready(exc) < 0) {
3559+
if (_PyStaticType_InitBuiltin(exc) < 0) {
35613560
return -1;
35623561
}
35633562
}

Objects/floatobject.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1992,7 +1992,8 @@ _PyFloat_InitTypes(PyInterpreterState *interp)
19921992

19931993
/* Init float info */
19941994
if (FloatInfoType.tp_name == NULL) {
1995-
if (PyStructSequence_InitType2(&FloatInfoType, &floatinfo_desc) < 0) {
1995+
if (_PyStructSequence_InitBuiltin(&FloatInfoType,
1996+
&floatinfo_desc) < 0) {
19961997
return _PyStatus_ERR("can't init float info type");
19971998
}
19981999
}

Objects/longobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6135,7 +6135,7 @@ _PyLong_InitTypes(PyInterpreterState *interp)
61356135

61366136
/* initialize int_info */
61376137
if (Int_InfoType.tp_name == NULL) {
6138-
if (PyStructSequence_InitType2(&Int_InfoType, &int_info_desc) < 0) {
6138+
if (_PyStructSequence_InitBuiltin(&Int_InfoType, &int_info_desc) < 0) {
61396139
return _PyStatus_ERR("can't init int info type");
61406140
}
61416141
}

Objects/object.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1975,8 +1975,8 @@ _PyTypes_InitTypes(PyInterpreterState *interp)
19751975
// All other static types (unless initialized elsewhere)
19761976
for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) {
19771977
PyTypeObject *type = static_types[i];
1978-
if (PyType_Ready(type) < 0) {
1979-
return _PyStatus_ERR("Can't initialize types");
1978+
if (_PyStaticType_InitBuiltin(type) < 0) {
1979+
return _PyStatus_ERR("Can't initialize builtin type");
19801980
}
19811981
if (type == &PyType_Type) {
19821982
// Sanitify checks of the two most important types

Objects/structseq.c

Lines changed: 82 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -432,11 +432,21 @@ initialize_structseq_dict(PyStructSequence_Desc *desc, PyObject* dict,
432432
return -1;
433433
}
434434

435-
static void
436-
initialize_members(PyStructSequence_Desc *desc, PyMemberDef* members,
437-
Py_ssize_t n_members) {
438-
Py_ssize_t i, k;
435+
static PyMemberDef *
436+
initialize_members(PyStructSequence_Desc *desc,
437+
Py_ssize_t *pn_members, Py_ssize_t *pn_unnamed_members)
438+
{
439+
PyMemberDef *members;
440+
Py_ssize_t n_members, n_unnamed_members;
441+
442+
n_members = count_members(desc, &n_unnamed_members);
443+
members = PyMem_NEW(PyMemberDef, n_members - n_unnamed_members + 1);
444+
if (members == NULL) {
445+
PyErr_NoMemory();
446+
return NULL;
447+
}
439448

449+
Py_ssize_t i, k;
440450
for (i = k = 0; i < n_members; ++i) {
441451
if (desc->fields[i].name == PyStructSequence_UnnamedField) {
442452
continue;
@@ -453,30 +463,17 @@ initialize_members(PyStructSequence_Desc *desc, PyMemberDef* members,
453463
k++;
454464
}
455465
members[k].name = NULL;
466+
467+
*pn_members = n_members;
468+
*pn_unnamed_members = n_unnamed_members;
469+
return members;
456470
}
457471

458472

459-
int
460-
_PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc,
461-
unsigned long tp_flags)
473+
static void
474+
initialize_static_fields(PyTypeObject *type, PyStructSequence_Desc *desc,
475+
PyMemberDef *tp_members, unsigned long tp_flags)
462476
{
463-
PyMemberDef *members;
464-
Py_ssize_t n_members, n_unnamed_members;
465-
466-
#ifdef Py_TRACE_REFS
467-
/* if the type object was chained, unchain it first
468-
before overwriting its storage */
469-
if (type->ob_base.ob_base._ob_next) {
470-
_Py_ForgetReference((PyObject *)type);
471-
}
472-
#endif
473-
474-
/* PyTypeObject has already been initialized */
475-
if (Py_REFCNT(type) != 0) {
476-
PyErr_BadInternalCall();
477-
return -1;
478-
}
479-
480477
type->tp_name = desc->name;
481478
type->tp_basicsize = sizeof(PyStructSequence) - sizeof(PyObject *);
482479
type->tp_itemsize = sizeof(PyObject *);
@@ -488,36 +485,84 @@ _PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc,
488485
type->tp_new = structseq_new;
489486
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | tp_flags;
490487
type->tp_traverse = (traverseproc) structseq_traverse;
488+
type->tp_members = tp_members;
489+
}
491490

492-
n_members = count_members(desc, &n_unnamed_members);
493-
members = PyMem_NEW(PyMemberDef, n_members - n_unnamed_members + 1);
494-
if (members == NULL) {
495-
PyErr_NoMemory();
496-
return -1;
497-
}
498-
initialize_members(desc, members, n_members);
499-
type->tp_members = members;
500-
491+
static int
492+
initialize_static_type(PyTypeObject *type, PyStructSequence_Desc *desc,
493+
Py_ssize_t n_members, Py_ssize_t n_unnamed_members) {
494+
/* initialize_static_fields() should have been called already. */
501495
if (PyType_Ready(type) < 0) {
502-
PyMem_Free(members);
503496
return -1;
504497
}
505498
Py_INCREF(type);
506499

507500
if (initialize_structseq_dict(
508501
desc, type->tp_dict, n_members, n_unnamed_members) < 0) {
509-
PyMem_Free(members);
510502
Py_DECREF(type);
511503
return -1;
512504
}
513505

514506
return 0;
515507
}
516508

509+
int
510+
_PyStructSequence_InitBuiltinWithFlags(PyTypeObject *type,
511+
PyStructSequence_Desc *desc,
512+
unsigned long tp_flags)
513+
{
514+
PyMemberDef *members;
515+
Py_ssize_t n_members, n_unnamed_members;
516+
517+
members = initialize_members(desc, &n_members, &n_unnamed_members);
518+
if (members == NULL) {
519+
return -1;
520+
}
521+
initialize_static_fields(type, desc, members, tp_flags);
522+
if (_PyStaticType_InitBuiltin(type) < 0) {
523+
PyMem_Free(members);
524+
PyErr_Format(PyExc_RuntimeError,
525+
"Can't initialize builtin type %s",
526+
desc->name);
527+
return -1;
528+
}
529+
if (initialize_static_type(type, desc, n_members, n_unnamed_members) < 0) {
530+
PyMem_Free(members);
531+
return -1;
532+
}
533+
return 0;
534+
}
535+
517536
int
518537
PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
519538
{
520-
return _PyStructSequence_InitType(type, desc, 0);
539+
PyMemberDef *members;
540+
Py_ssize_t n_members, n_unnamed_members;
541+
542+
#ifdef Py_TRACE_REFS
543+
/* if the type object was chained, unchain it first
544+
before overwriting its storage */
545+
if (type->ob_base.ob_base._ob_next) {
546+
_Py_ForgetReference((PyObject *)type);
547+
}
548+
#endif
549+
550+
/* PyTypeObject has already been initialized */
551+
if (Py_REFCNT(type) != 0) {
552+
PyErr_BadInternalCall();
553+
return -1;
554+
}
555+
556+
members = initialize_members(desc, &n_members, &n_unnamed_members);
557+
if (members == NULL) {
558+
return -1;
559+
}
560+
initialize_static_fields(type, desc, members, 0);
561+
if (initialize_static_type(type, desc, n_members, n_unnamed_members) < 0) {
562+
PyMem_Free(members);
563+
return -1;
564+
}
565+
return 0;
521566
}
522567

523568
void
@@ -569,13 +614,10 @@ _PyStructSequence_NewType(PyStructSequence_Desc *desc, unsigned long tp_flags)
569614
Py_ssize_t n_members, n_unnamed_members;
570615

571616
/* Initialize MemberDefs */
572-
n_members = count_members(desc, &n_unnamed_members);
573-
members = PyMem_NEW(PyMemberDef, n_members - n_unnamed_members + 1);
617+
members = initialize_members(desc, &n_members, &n_unnamed_members);
574618
if (members == NULL) {
575-
PyErr_NoMemory();
576619
return NULL;
577620
}
578-
initialize_members(desc, members, n_members);
579621

580622
/* Initialize Slots */
581623
slots[0] = (PyType_Slot){Py_tp_dealloc, (destructor)structseq_dealloc};

Objects/typeobject.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6650,6 +6650,14 @@ PyType_Ready(PyTypeObject *type)
66506650
return 0;
66516651
}
66526652

6653+
int
6654+
_PyStaticType_InitBuiltin(PyTypeObject *self)
6655+
{
6656+
self->tp_flags = self->tp_flags | _Py_TPFLAGS_STATIC_BUILTIN;
6657+
6658+
return PyType_Ready(self);
6659+
}
6660+
66536661

66546662
static int
66556663
add_subclass(PyTypeObject *base, PyTypeObject *type)

Objects/unicodeobject.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14604,13 +14604,13 @@ _PyUnicode_InitTypes(PyInterpreterState *interp)
1460414604
return _PyStatus_OK();
1460514605
}
1460614606

14607-
if (PyType_Ready(&EncodingMapType) < 0) {
14607+
if (_PyStaticType_InitBuiltin(&EncodingMapType) < 0) {
1460814608
goto error;
1460914609
}
14610-
if (PyType_Ready(&PyFieldNameIter_Type) < 0) {
14610+
if (_PyStaticType_InitBuiltin(&PyFieldNameIter_Type) < 0) {
1461114611
goto error;
1461214612
}
14613-
if (PyType_Ready(&PyFormatterIter_Type) < 0) {
14613+
if (_PyStaticType_InitBuiltin(&PyFormatterIter_Type) < 0) {
1461414614
goto error;
1461514615
}
1461614616
return _PyStatus_OK();

Python/errors.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,8 +1229,8 @@ _PyErr_InitTypes(PyInterpreterState *interp)
12291229
}
12301230

12311231
if (UnraisableHookArgsType.tp_name == NULL) {
1232-
if (PyStructSequence_InitType2(&UnraisableHookArgsType,
1233-
&UnraisableHookArgs_desc) < 0) {
1232+
if (_PyStructSequence_InitBuiltin(&UnraisableHookArgsType,
1233+
&UnraisableHookArgs_desc) < 0) {
12341234
return _PyStatus_ERR("failed to initialize UnraisableHookArgs type");
12351235
}
12361236
}

Python/sysmodule.c

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Data members:
2828
#include "pycore_pymath.h" // _PY_SHORT_FLOAT_REPR
2929
#include "pycore_pymem.h" // _PyMem_SetDefaultAllocator()
3030
#include "pycore_pystate.h" // _PyThreadState_GET()
31-
#include "pycore_structseq.h" // _PyStructSequence_InitType()
31+
#include "pycore_structseq.h" // _PyStructSequence_InitBuiltinWithFlags()
3232
#include "pycore_tuple.h" // _PyTuple_FromArray()
3333

3434
#include "frameobject.h" // PyFrame_FastToLocalsWithError()
@@ -2921,7 +2921,7 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict)
29212921
SET_SYS("int_info", PyLong_GetInfo());
29222922
/* initialize hash_info */
29232923
if (Hash_InfoType.tp_name == NULL) {
2924-
if (PyStructSequence_InitType2(&Hash_InfoType, &hash_info_desc) < 0) {
2924+
if (_PyStructSequence_InitBuiltin(&Hash_InfoType, &hash_info_desc) < 0) {
29252925
goto type_init_failed;
29262926
}
29272927
}
@@ -2943,42 +2943,37 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict)
29432943
SET_SYS_FROM_STRING("abiflags", ABIFLAGS);
29442944
#endif
29452945

2946+
#define ENSURE_INFO_TYPE(TYPE, DESC) \
2947+
do { \
2948+
if (TYPE.tp_name == NULL) { \
2949+
if (_PyStructSequence_InitBuiltinWithFlags( \
2950+
&TYPE, &DESC, Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) { \
2951+
goto type_init_failed; \
2952+
} \
2953+
} \
2954+
} while (0)
2955+
29462956
/* version_info */
2947-
if (VersionInfoType.tp_name == NULL) {
2948-
if (_PyStructSequence_InitType(&VersionInfoType,
2949-
&version_info_desc,
2950-
Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) {
2951-
goto type_init_failed;
2952-
}
2953-
}
2957+
ENSURE_INFO_TYPE(VersionInfoType, version_info_desc);
29542958
version_info = make_version_info(tstate);
29552959
SET_SYS("version_info", version_info);
29562960

29572961
/* implementation */
29582962
SET_SYS("implementation", make_impl_info(version_info));
29592963

29602964
// sys.flags: updated in-place later by _PySys_UpdateConfig()
2961-
if (FlagsType.tp_name == 0) {
2962-
if (_PyStructSequence_InitType(&FlagsType, &flags_desc,
2963-
Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) {
2964-
goto type_init_failed;
2965-
}
2966-
}
2965+
ENSURE_INFO_TYPE(FlagsType, flags_desc);
29672966
SET_SYS("flags", make_flags(tstate->interp));
29682967

29692968
#if defined(MS_WINDOWS)
29702969
/* getwindowsversion */
2971-
if (WindowsVersionType.tp_name == 0) {
2972-
if (_PyStructSequence_InitType(&WindowsVersionType,
2973-
&windows_version_desc,
2974-
Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) {
2975-
goto type_init_failed;
2976-
}
2977-
}
2970+
ENSURE_INFO_TYPE(WindowsVersionType, windows_version_desc);
29782971

29792972
SET_SYS_FROM_STRING("_vpath", VPATH);
29802973
#endif
29812974

2975+
#undef ENSURE_INFO_TYPE
2976+
29822977
/* float repr style: 0.03 (short) vs 0.029999999999999999 (legacy) */
29832978
#if _PY_SHORT_FLOAT_REPR == 1
29842979
SET_SYS_FROM_STRING("float_repr_style", "short");
@@ -2990,7 +2985,7 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict)
29902985

29912986
/* initialize asyncgen_hooks */
29922987
if (AsyncGenHooksType.tp_name == NULL) {
2993-
if (PyStructSequence_InitType2(
2988+
if (_PyStructSequence_InitBuiltin(
29942989
&AsyncGenHooksType, &asyncgen_hooks_desc) < 0) {
29952990
goto type_init_failed;
29962991
}

Python/thread.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,8 @@ PyThread_GetInfo(void)
155155
#endif
156156

157157
if (ThreadInfoType.tp_name == 0) {
158-
if (PyStructSequence_InitType2(&ThreadInfoType, &threadinfo_desc) < 0)
158+
if (_PyStructSequence_InitBuiltin(&ThreadInfoType,
159+
&threadinfo_desc) < 0)
159160
return NULL;
160161
}
161162

0 commit comments

Comments
 (0)