Skip to content

Commit d2e2e53

Browse files
gh-94673: Ensure Builtin Static Types are Readied Properly (gh-103940)
There were cases where we do unnecessary work for builtin static types. This also simplifies some work necessary for a per-interpreter GIL.
1 parent 56c7176 commit d2e2e53

21 files changed

+88
-168
lines changed

Diff for: Include/internal/pycore_bytesobject.h

-5
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ extern "C" {
99
#endif
1010

1111

12-
/* runtime lifecycle */
13-
14-
extern PyStatus _PyBytes_InitTypes(PyInterpreterState *);
15-
16-
1712
/* Substring Search.
1813
1914
Returns the index of the first occurrence of

Diff for: Include/internal/pycore_tuple.h

-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ extern "C" {
1414
/* runtime lifecycle */
1515

1616
extern PyStatus _PyTuple_InitGlobalObjects(PyInterpreterState *);
17-
extern PyStatus _PyTuple_InitTypes(PyInterpreterState *);
1817
extern void _PyTuple_Fini(PyInterpreterState *);
1918

2019

Diff for: Modules/_io/_iomodule.c

+4-6
Original file line numberDiff line numberDiff line change
@@ -671,13 +671,11 @@ static PyTypeObject* static_types[] = {
671671
PyStatus
672672
_PyIO_InitTypes(PyInterpreterState *interp)
673673
{
674-
if (!_Py_IsMainInterpreter(interp)) {
675-
return _PyStatus_OK();
676-
}
677-
678-
// Set type base classes
679674
#ifdef HAVE_WINDOWS_CONSOLE_IO
680-
PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type;
675+
if (_Py_IsMainInterpreter(interp)) {
676+
// Set type base classes
677+
PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type;
678+
}
681679
#endif
682680

683681
for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) {

Diff for: Modules/mathmodule.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -2096,7 +2096,7 @@ math_trunc(PyObject *module, PyObject *x)
20962096
return PyFloat_Type.tp_as_number->nb_int(x);
20972097
}
20982098

2099-
if (Py_TYPE(x)->tp_dict == NULL) {
2099+
if (_PyType_IsReady(Py_TYPE(x))) {
21002100
if (PyType_Ready(Py_TYPE(x)) < 0)
21012101
return NULL;
21022102
}

Diff for: Modules/symtablemodule.c

-7
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,6 @@ static PyMethodDef symtable_methods[] = {
6666
{NULL, NULL} /* sentinel */
6767
};
6868

69-
static int
70-
symtable_init_stentry_type(PyObject *m)
71-
{
72-
return PyType_Ready(&PySTEntry_Type);
73-
}
74-
7569
static int
7670
symtable_init_constants(PyObject *m)
7771
{
@@ -105,7 +99,6 @@ symtable_init_constants(PyObject *m)
10599
}
106100

107101
static PyModuleDef_Slot symtable_slots[] = {
108-
{Py_mod_exec, symtable_init_stentry_type},
109102
{Py_mod_exec, symtable_init_constants},
110103
{0, NULL}
111104
};

Diff for: Objects/bytesobject.c

-19
Original file line numberDiff line numberDiff line change
@@ -3090,25 +3090,6 @@ _Py_COMP_DIAG_POP
30903090
}
30913091

30923092

3093-
PyStatus
3094-
_PyBytes_InitTypes(PyInterpreterState *interp)
3095-
{
3096-
if (!_Py_IsMainInterpreter(interp)) {
3097-
return _PyStatus_OK();
3098-
}
3099-
3100-
if (PyType_Ready(&PyBytes_Type) < 0) {
3101-
return _PyStatus_ERR("Can't initialize bytes type");
3102-
}
3103-
3104-
if (PyType_Ready(&PyBytesIter_Type) < 0) {
3105-
return _PyStatus_ERR("Can't initialize bytes iterator type");
3106-
}
3107-
3108-
return _PyStatus_OK();
3109-
}
3110-
3111-
31123093
/*********************** Bytes Iterator ****************************/
31133094

31143095
typedef struct {

Diff for: Objects/classobject.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ method_getattro(PyObject *obj, PyObject *name)
181181
PyObject *descr = NULL;
182182

183183
{
184-
if (tp->tp_dict == NULL) {
184+
if (!_PyType_IsReady(tp)) {
185185
if (PyType_Ready(tp) < 0)
186186
return NULL;
187187
}
@@ -395,7 +395,7 @@ instancemethod_getattro(PyObject *self, PyObject *name)
395395
PyTypeObject *tp = Py_TYPE(self);
396396
PyObject *descr = NULL;
397397

398-
if (tp->tp_dict == NULL) {
398+
if (!_PyType_IsReady(tp)) {
399399
if (PyType_Ready(tp) < 0)
400400
return NULL;
401401
}

Diff for: Objects/exceptions.c

-4
Original file line numberDiff line numberDiff line change
@@ -3596,10 +3596,6 @@ static struct static_exception static_exceptions[] = {
35963596
int
35973597
_PyExc_InitTypes(PyInterpreterState *interp)
35983598
{
3599-
if (!_Py_IsMainInterpreter(interp)) {
3600-
return 0;
3601-
}
3602-
36033599
for (size_t i=0; i < Py_ARRAY_LENGTH(static_exceptions); i++) {
36043600
PyTypeObject *exc = static_exceptions[i].exc;
36053601
if (_PyStaticType_InitBuiltin(exc) < 0) {

Diff for: Objects/floatobject.c

+3-13
Original file line numberDiff line numberDiff line change
@@ -1990,20 +1990,10 @@ _PyFloat_InitState(PyInterpreterState *interp)
19901990
PyStatus
19911991
_PyFloat_InitTypes(PyInterpreterState *interp)
19921992
{
1993-
if (!_Py_IsMainInterpreter(interp)) {
1994-
return _PyStatus_OK();
1995-
}
1996-
1997-
if (PyType_Ready(&PyFloat_Type) < 0) {
1998-
return _PyStatus_ERR("Can't initialize float type");
1999-
}
2000-
20011993
/* Init float info */
2002-
if (FloatInfoType.tp_name == NULL) {
2003-
if (_PyStructSequence_InitBuiltin(&FloatInfoType,
2004-
&floatinfo_desc) < 0) {
2005-
return _PyStatus_ERR("can't init float info type");
2006-
}
1994+
if (_PyStructSequence_InitBuiltin(&FloatInfoType,
1995+
&floatinfo_desc) < 0) {
1996+
return _PyStatus_ERR("can't init float info type");
20071997
}
20081998

20091999
return _PyStatus_OK();

Diff for: Objects/longobject.c

+2-12
Original file line numberDiff line numberDiff line change
@@ -6351,19 +6351,9 @@ PyLong_GetInfo(void)
63516351
PyStatus
63526352
_PyLong_InitTypes(PyInterpreterState *interp)
63536353
{
6354-
if (!_Py_IsMainInterpreter(interp)) {
6355-
return _PyStatus_OK();
6356-
}
6357-
6358-
if (PyType_Ready(&PyLong_Type) < 0) {
6359-
return _PyStatus_ERR("Can't initialize int type");
6360-
}
6361-
63626354
/* initialize int_info */
6363-
if (Int_InfoType.tp_name == NULL) {
6364-
if (_PyStructSequence_InitBuiltin(&Int_InfoType, &int_info_desc) < 0) {
6365-
return _PyStatus_ERR("can't init int info type");
6366-
}
6355+
if (_PyStructSequence_InitBuiltin(&Int_InfoType, &int_info_desc) < 0) {
6356+
return _PyStatus_ERR("can't init int info type");
63676357
}
63686358

63696359
return _PyStatus_OK();

Diff for: Objects/object.c

+4-3
Original file line numberDiff line numberDiff line change
@@ -890,7 +890,7 @@ PyObject_Hash(PyObject *v)
890890
* an explicit call to PyType_Ready, we implicitly call
891891
* PyType_Ready here and then check the tp_hash slot again
892892
*/
893-
if (tp->tp_dict == NULL) {
893+
if (!_PyType_IsReady(tp)) {
894894
if (PyType_Ready(tp) < 0)
895895
return -1;
896896
if (tp->tp_hash != NULL)
@@ -1385,7 +1385,7 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
13851385
}
13861386
Py_INCREF(name);
13871387

1388-
if (tp->tp_dict == NULL) {
1388+
if (!_PyType_IsReady(tp)) {
13891389
if (PyType_Ready(tp) < 0)
13901390
goto done;
13911391
}
@@ -1507,8 +1507,9 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
15071507
return -1;
15081508
}
15091509

1510-
if (tp->tp_dict == NULL && PyType_Ready(tp) < 0)
1510+
if (!_PyType_IsReady(tp) && PyType_Ready(tp) < 0) {
15111511
return -1;
1512+
}
15121513

15131514
Py_INCREF(name);
15141515
Py_INCREF(tp);

Diff for: Objects/structseq.c

+19-5
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,13 @@ _PyStructSequence_InitBuiltinWithFlags(PyTypeObject *type,
509509
PyStructSequence_Desc *desc,
510510
unsigned long tp_flags)
511511
{
512+
if (type->tp_flags & Py_TPFLAGS_READY) {
513+
if (_PyStaticType_InitBuiltin(type) < 0) {
514+
goto failed_init_builtin;
515+
}
516+
return 0;
517+
}
518+
512519
PyMemberDef *members;
513520
Py_ssize_t n_members, n_unnamed_members;
514521

@@ -517,18 +524,25 @@ _PyStructSequence_InitBuiltinWithFlags(PyTypeObject *type,
517524
return -1;
518525
}
519526
initialize_static_fields(type, desc, members, tp_flags);
527+
528+
Py_INCREF(type); // XXX It should be immortal.
520529
if (_PyStaticType_InitBuiltin(type) < 0) {
521530
PyMem_Free(members);
522-
PyErr_Format(PyExc_RuntimeError,
523-
"Can't initialize builtin type %s",
524-
desc->name);
525-
return -1;
531+
goto failed_init_builtin;
526532
}
527-
if (initialize_static_type(type, desc, n_members, n_unnamed_members) < 0) {
533+
534+
if (initialize_structseq_dict(
535+
desc, type->tp_dict, n_members, n_unnamed_members) < 0) {
528536
PyMem_Free(members);
529537
return -1;
530538
}
531539
return 0;
540+
541+
failed_init_builtin:
542+
PyErr_Format(PyExc_RuntimeError,
543+
"Can't initialize builtin type %s",
544+
desc->name);
545+
return -1;
532546
}
533547

534548
int

Diff for: Objects/tupleobject.c

-18
Original file line numberDiff line numberDiff line change
@@ -960,24 +960,6 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
960960
}
961961

962962

963-
PyStatus
964-
_PyTuple_InitTypes(PyInterpreterState *interp)
965-
{
966-
if (!_Py_IsMainInterpreter(interp)) {
967-
return _PyStatus_OK();
968-
}
969-
970-
if (PyType_Ready(&PyTuple_Type) < 0) {
971-
return _PyStatus_ERR("Can't initialize tuple type");
972-
}
973-
974-
if (PyType_Ready(&PyTupleIter_Type) < 0) {
975-
return _PyStatus_ERR("Can't initialize tuple iterator type");
976-
}
977-
978-
return _PyStatus_OK();
979-
}
980-
981963
static void maybe_freelist_clear(PyInterpreterState *, int);
982964

983965
void

Diff for: Objects/typeobject.c

+37-27
Original file line numberDiff line numberDiff line change
@@ -6948,8 +6948,12 @@ type_ready_post_checks(PyTypeObject *type)
69486948
static int
69496949
type_ready(PyTypeObject *type)
69506950
{
6951+
_PyObject_ASSERT((PyObject *)type,
6952+
(type->tp_flags & Py_TPFLAGS_READYING) == 0);
6953+
type->tp_flags |= Py_TPFLAGS_READYING;
6954+
69516955
if (type_ready_pre_checks(type) < 0) {
6952-
return -1;
6956+
goto error;
69536957
}
69546958

69556959
#ifdef Py_TRACE_REFS
@@ -6963,41 +6967,49 @@ type_ready(PyTypeObject *type)
69636967

69646968
/* Initialize tp_dict: _PyType_IsReady() tests if tp_dict != NULL */
69656969
if (type_ready_set_dict(type) < 0) {
6966-
return -1;
6970+
goto error;
69676971
}
69686972
if (type_ready_set_bases(type) < 0) {
6969-
return -1;
6973+
goto error;
69706974
}
69716975
if (type_ready_mro(type) < 0) {
6972-
return -1;
6976+
goto error;
69736977
}
69746978
if (type_ready_set_new(type) < 0) {
6975-
return -1;
6979+
goto error;
69766980
}
69776981
if (type_ready_fill_dict(type) < 0) {
6978-
return -1;
6982+
goto error;
69796983
}
69806984
if (type_ready_inherit(type) < 0) {
6981-
return -1;
6985+
goto error;
69826986
}
69836987
if (type_ready_preheader(type) < 0) {
6984-
return -1;
6988+
goto error;
69856989
}
69866990
if (type_ready_set_hash(type) < 0) {
6987-
return -1;
6991+
goto error;
69886992
}
69896993
if (type_ready_add_subclasses(type) < 0) {
6990-
return -1;
6994+
goto error;
69916995
}
69926996
if (type_ready_managed_dict(type) < 0) {
6993-
return -1;
6997+
goto error;
69946998
}
69956999
if (type_ready_post_checks(type) < 0) {
6996-
return -1;
7000+
goto error;
69977001
}
7002+
7003+
/* All done -- set the ready flag */
7004+
type->tp_flags = (type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY;
7005+
7006+
assert(_PyType_CheckConsistency(type));
69987007
return 0;
6999-
}
70007008

7009+
error:
7010+
type->tp_flags &= ~Py_TPFLAGS_READYING;
7011+
return -1;
7012+
}
70017013

70027014
int
70037015
PyType_Ready(PyTypeObject *type)
@@ -7006,39 +7018,37 @@ PyType_Ready(PyTypeObject *type)
70067018
assert(_PyType_CheckConsistency(type));
70077019
return 0;
70087020
}
7009-
_PyObject_ASSERT((PyObject *)type,
7010-
(type->tp_flags & Py_TPFLAGS_READYING) == 0);
7011-
7012-
type->tp_flags |= Py_TPFLAGS_READYING;
7021+
assert(!(type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN));
70137022

70147023
/* Historically, all static types were immutable. See bpo-43908 */
70157024
if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
70167025
type->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE;
70177026
}
70187027

7019-
if (type_ready(type) < 0) {
7020-
type->tp_flags &= ~Py_TPFLAGS_READYING;
7021-
return -1;
7022-
}
7023-
7024-
/* All done -- set the ready flag */
7025-
type->tp_flags = (type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY;
7026-
assert(_PyType_CheckConsistency(type));
7027-
return 0;
7028+
return type_ready(type);
70287029
}
70297030

70307031
int
70317032
_PyStaticType_InitBuiltin(PyTypeObject *self)
70327033
{
7034+
assert(!(self->tp_flags & Py_TPFLAGS_HEAPTYPE));
7035+
7036+
if (self->tp_flags & Py_TPFLAGS_READY) {
7037+
assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN);
7038+
assert(_PyType_CheckConsistency(self));
7039+
return 0;
7040+
}
7041+
70337042
self->tp_flags |= _Py_TPFLAGS_STATIC_BUILTIN;
7043+
self->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE;
70347044

70357045
assert(NEXT_GLOBAL_VERSION_TAG <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG);
70367046
self->tp_version_tag = NEXT_GLOBAL_VERSION_TAG++;
70377047
self->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG;
70387048

70397049
static_builtin_state_init(self);
70407050

7041-
int res = PyType_Ready(self);
7051+
int res = type_ready(self);
70427052
if (res < 0) {
70437053
static_builtin_state_clear(self);
70447054
}

0 commit comments

Comments
 (0)