Skip to content

Commit

Permalink
pythongh-94673: Ensure Builtin Static Types are Readied Properly (pyt…
Browse files Browse the repository at this point in the history
…hongh-103940)

There were cases where we do unnecessary work for builtin static types. This also simplifies some work necessary for a per-interpreter GIL.
  • Loading branch information
ericsnowcurrently committed Apr 27, 2023
1 parent 56c7176 commit d2e2e53
Show file tree
Hide file tree
Showing 21 changed files with 88 additions and 168 deletions.
5 changes: 0 additions & 5 deletions Include/internal/pycore_bytesobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ extern "C" {
#endif


/* runtime lifecycle */

extern PyStatus _PyBytes_InitTypes(PyInterpreterState *);


/* Substring Search.
Returns the index of the first occurrence of
Expand Down
1 change: 0 additions & 1 deletion Include/internal/pycore_tuple.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ extern "C" {
/* runtime lifecycle */

extern PyStatus _PyTuple_InitGlobalObjects(PyInterpreterState *);
extern PyStatus _PyTuple_InitTypes(PyInterpreterState *);
extern void _PyTuple_Fini(PyInterpreterState *);


Expand Down
10 changes: 4 additions & 6 deletions Modules/_io/_iomodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -671,13 +671,11 @@ static PyTypeObject* static_types[] = {
PyStatus
_PyIO_InitTypes(PyInterpreterState *interp)
{
if (!_Py_IsMainInterpreter(interp)) {
return _PyStatus_OK();
}

// Set type base classes
#ifdef HAVE_WINDOWS_CONSOLE_IO
PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type;
if (_Py_IsMainInterpreter(interp)) {
// Set type base classes
PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type;
}
#endif

for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) {
Expand Down
2 changes: 1 addition & 1 deletion Modules/mathmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2096,7 +2096,7 @@ math_trunc(PyObject *module, PyObject *x)
return PyFloat_Type.tp_as_number->nb_int(x);
}

if (Py_TYPE(x)->tp_dict == NULL) {
if (_PyType_IsReady(Py_TYPE(x))) {
if (PyType_Ready(Py_TYPE(x)) < 0)
return NULL;
}
Expand Down
7 changes: 0 additions & 7 deletions Modules/symtablemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,6 @@ static PyMethodDef symtable_methods[] = {
{NULL, NULL} /* sentinel */
};

static int
symtable_init_stentry_type(PyObject *m)
{
return PyType_Ready(&PySTEntry_Type);
}

static int
symtable_init_constants(PyObject *m)
{
Expand Down Expand Up @@ -105,7 +99,6 @@ symtable_init_constants(PyObject *m)
}

static PyModuleDef_Slot symtable_slots[] = {
{Py_mod_exec, symtable_init_stentry_type},
{Py_mod_exec, symtable_init_constants},
{0, NULL}
};
Expand Down
19 changes: 0 additions & 19 deletions Objects/bytesobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -3090,25 +3090,6 @@ _Py_COMP_DIAG_POP
}


PyStatus
_PyBytes_InitTypes(PyInterpreterState *interp)
{
if (!_Py_IsMainInterpreter(interp)) {
return _PyStatus_OK();
}

if (PyType_Ready(&PyBytes_Type) < 0) {
return _PyStatus_ERR("Can't initialize bytes type");
}

if (PyType_Ready(&PyBytesIter_Type) < 0) {
return _PyStatus_ERR("Can't initialize bytes iterator type");
}

return _PyStatus_OK();
}


/*********************** Bytes Iterator ****************************/

typedef struct {
Expand Down
4 changes: 2 additions & 2 deletions Objects/classobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ method_getattro(PyObject *obj, PyObject *name)
PyObject *descr = NULL;

{
if (tp->tp_dict == NULL) {
if (!_PyType_IsReady(tp)) {
if (PyType_Ready(tp) < 0)
return NULL;
}
Expand Down Expand Up @@ -395,7 +395,7 @@ instancemethod_getattro(PyObject *self, PyObject *name)
PyTypeObject *tp = Py_TYPE(self);
PyObject *descr = NULL;

if (tp->tp_dict == NULL) {
if (!_PyType_IsReady(tp)) {
if (PyType_Ready(tp) < 0)
return NULL;
}
Expand Down
4 changes: 0 additions & 4 deletions Objects/exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -3596,10 +3596,6 @@ static struct static_exception static_exceptions[] = {
int
_PyExc_InitTypes(PyInterpreterState *interp)
{
if (!_Py_IsMainInterpreter(interp)) {
return 0;
}

for (size_t i=0; i < Py_ARRAY_LENGTH(static_exceptions); i++) {
PyTypeObject *exc = static_exceptions[i].exc;
if (_PyStaticType_InitBuiltin(exc) < 0) {
Expand Down
16 changes: 3 additions & 13 deletions Objects/floatobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1990,20 +1990,10 @@ _PyFloat_InitState(PyInterpreterState *interp)
PyStatus
_PyFloat_InitTypes(PyInterpreterState *interp)
{
if (!_Py_IsMainInterpreter(interp)) {
return _PyStatus_OK();
}

if (PyType_Ready(&PyFloat_Type) < 0) {
return _PyStatus_ERR("Can't initialize float type");
}

/* Init float info */
if (FloatInfoType.tp_name == NULL) {
if (_PyStructSequence_InitBuiltin(&FloatInfoType,
&floatinfo_desc) < 0) {
return _PyStatus_ERR("can't init float info type");
}
if (_PyStructSequence_InitBuiltin(&FloatInfoType,
&floatinfo_desc) < 0) {
return _PyStatus_ERR("can't init float info type");
}

return _PyStatus_OK();
Expand Down
14 changes: 2 additions & 12 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -6351,19 +6351,9 @@ PyLong_GetInfo(void)
PyStatus
_PyLong_InitTypes(PyInterpreterState *interp)
{
if (!_Py_IsMainInterpreter(interp)) {
return _PyStatus_OK();
}

if (PyType_Ready(&PyLong_Type) < 0) {
return _PyStatus_ERR("Can't initialize int type");
}

/* initialize int_info */
if (Int_InfoType.tp_name == NULL) {
if (_PyStructSequence_InitBuiltin(&Int_InfoType, &int_info_desc) < 0) {
return _PyStatus_ERR("can't init int info type");
}
if (_PyStructSequence_InitBuiltin(&Int_InfoType, &int_info_desc) < 0) {
return _PyStatus_ERR("can't init int info type");
}

return _PyStatus_OK();
Expand Down
7 changes: 4 additions & 3 deletions Objects/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -890,7 +890,7 @@ PyObject_Hash(PyObject *v)
* an explicit call to PyType_Ready, we implicitly call
* PyType_Ready here and then check the tp_hash slot again
*/
if (tp->tp_dict == NULL) {
if (!_PyType_IsReady(tp)) {
if (PyType_Ready(tp) < 0)
return -1;
if (tp->tp_hash != NULL)
Expand Down Expand Up @@ -1385,7 +1385,7 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
}
Py_INCREF(name);

if (tp->tp_dict == NULL) {
if (!_PyType_IsReady(tp)) {
if (PyType_Ready(tp) < 0)
goto done;
}
Expand Down Expand Up @@ -1507,8 +1507,9 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
return -1;
}

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

Py_INCREF(name);
Py_INCREF(tp);
Expand Down
24 changes: 19 additions & 5 deletions Objects/structseq.c
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,13 @@ _PyStructSequence_InitBuiltinWithFlags(PyTypeObject *type,
PyStructSequence_Desc *desc,
unsigned long tp_flags)
{
if (type->tp_flags & Py_TPFLAGS_READY) {
if (_PyStaticType_InitBuiltin(type) < 0) {
goto failed_init_builtin;
}
return 0;
}

PyMemberDef *members;
Py_ssize_t n_members, n_unnamed_members;

Expand All @@ -517,18 +524,25 @@ _PyStructSequence_InitBuiltinWithFlags(PyTypeObject *type,
return -1;
}
initialize_static_fields(type, desc, members, tp_flags);

Py_INCREF(type); // XXX It should be immortal.
if (_PyStaticType_InitBuiltin(type) < 0) {
PyMem_Free(members);
PyErr_Format(PyExc_RuntimeError,
"Can't initialize builtin type %s",
desc->name);
return -1;
goto failed_init_builtin;
}
if (initialize_static_type(type, desc, n_members, n_unnamed_members) < 0) {

if (initialize_structseq_dict(
desc, type->tp_dict, n_members, n_unnamed_members) < 0) {
PyMem_Free(members);
return -1;
}
return 0;

failed_init_builtin:
PyErr_Format(PyExc_RuntimeError,
"Can't initialize builtin type %s",
desc->name);
return -1;
}

int
Expand Down
18 changes: 0 additions & 18 deletions Objects/tupleobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -960,24 +960,6 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
}


PyStatus
_PyTuple_InitTypes(PyInterpreterState *interp)
{
if (!_Py_IsMainInterpreter(interp)) {
return _PyStatus_OK();
}

if (PyType_Ready(&PyTuple_Type) < 0) {
return _PyStatus_ERR("Can't initialize tuple type");
}

if (PyType_Ready(&PyTupleIter_Type) < 0) {
return _PyStatus_ERR("Can't initialize tuple iterator type");
}

return _PyStatus_OK();
}

static void maybe_freelist_clear(PyInterpreterState *, int);

void
Expand Down
64 changes: 37 additions & 27 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -6948,8 +6948,12 @@ type_ready_post_checks(PyTypeObject *type)
static int
type_ready(PyTypeObject *type)
{
_PyObject_ASSERT((PyObject *)type,
(type->tp_flags & Py_TPFLAGS_READYING) == 0);
type->tp_flags |= Py_TPFLAGS_READYING;

if (type_ready_pre_checks(type) < 0) {
return -1;
goto error;
}

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

/* Initialize tp_dict: _PyType_IsReady() tests if tp_dict != NULL */
if (type_ready_set_dict(type) < 0) {
return -1;
goto error;
}
if (type_ready_set_bases(type) < 0) {
return -1;
goto error;
}
if (type_ready_mro(type) < 0) {
return -1;
goto error;
}
if (type_ready_set_new(type) < 0) {
return -1;
goto error;
}
if (type_ready_fill_dict(type) < 0) {
return -1;
goto error;
}
if (type_ready_inherit(type) < 0) {
return -1;
goto error;
}
if (type_ready_preheader(type) < 0) {
return -1;
goto error;
}
if (type_ready_set_hash(type) < 0) {
return -1;
goto error;
}
if (type_ready_add_subclasses(type) < 0) {
return -1;
goto error;
}
if (type_ready_managed_dict(type) < 0) {
return -1;
goto error;
}
if (type_ready_post_checks(type) < 0) {
return -1;
goto error;
}

/* All done -- set the ready flag */
type->tp_flags = (type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY;

assert(_PyType_CheckConsistency(type));
return 0;
}

error:
type->tp_flags &= ~Py_TPFLAGS_READYING;
return -1;
}

int
PyType_Ready(PyTypeObject *type)
Expand All @@ -7006,39 +7018,37 @@ PyType_Ready(PyTypeObject *type)
assert(_PyType_CheckConsistency(type));
return 0;
}
_PyObject_ASSERT((PyObject *)type,
(type->tp_flags & Py_TPFLAGS_READYING) == 0);

type->tp_flags |= Py_TPFLAGS_READYING;
assert(!(type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN));

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

if (type_ready(type) < 0) {
type->tp_flags &= ~Py_TPFLAGS_READYING;
return -1;
}

/* All done -- set the ready flag */
type->tp_flags = (type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY;
assert(_PyType_CheckConsistency(type));
return 0;
return type_ready(type);
}

int
_PyStaticType_InitBuiltin(PyTypeObject *self)
{
assert(!(self->tp_flags & Py_TPFLAGS_HEAPTYPE));

if (self->tp_flags & Py_TPFLAGS_READY) {
assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN);
assert(_PyType_CheckConsistency(self));
return 0;
}

self->tp_flags |= _Py_TPFLAGS_STATIC_BUILTIN;
self->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE;

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

static_builtin_state_init(self);

int res = PyType_Ready(self);
int res = type_ready(self);
if (res < 0) {
static_builtin_state_clear(self);
}
Expand Down
Loading

0 comments on commit d2e2e53

Please sign in to comment.