/* end static builtin helpers */
+static inline void
+start_readying(PyTypeObject *type)
+{
+ if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ static_builtin_state *state = static_builtin_state_get(interp, type);
+ assert(state != NULL);
+ assert(!state->readying);
+ state->readying = 1;
+ return;
+ }
+ assert((type->tp_flags & Py_TPFLAGS_READYING) == 0);
+ type->tp_flags |= Py_TPFLAGS_READYING;
+}
+
+static inline void
+stop_readying(PyTypeObject *type)
+{
+ if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ static_builtin_state *state = static_builtin_state_get(interp, type);
+ assert(state != NULL);
+ assert(state->readying);
+ state->readying = 0;
+ return;
+ }
+ assert(type->tp_flags & Py_TPFLAGS_READYING);
+ type->tp_flags &= ~Py_TPFLAGS_READYING;
+}
+
+static inline int
+is_readying(PyTypeObject *type)
+{
+ if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ static_builtin_state *state = static_builtin_state_get(interp, type);
+ assert(state != NULL);
+ return state->readying;
+ }
+ return (type->tp_flags & Py_TPFLAGS_READYING) != 0;
+}
+
+
/* accessors for objects stored on PyTypeObject */
static inline PyObject *
lookup_tp_dict(PyTypeObject *self)
{
+ if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ static_builtin_state *state = _PyStaticType_GetState(interp, self);
+ assert(state != NULL);
+ return state->tp_dict;
+ }
return self->tp_dict;
}
PyObject *
_PyType_GetDict(PyTypeObject *self)
{
+ /* It returns a borrowed reference. */
return lookup_tp_dict(self);
}
static inline void
set_tp_dict(PyTypeObject *self, PyObject *dict)
{
+ if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ static_builtin_state *state = _PyStaticType_GetState(interp, self);
+ assert(state != NULL);
+ state->tp_dict = dict;
+ return;
+ }
self->tp_dict = dict;
}
static inline void
clear_tp_dict(PyTypeObject *self)
{
+ if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ static_builtin_state *state = _PyStaticType_GetState(interp, self);
+ assert(state != NULL);
+ Py_CLEAR(state->tp_dict);
+ return;
+ }
Py_CLEAR(self->tp_dict);
}
static inline PyObject *
lookup_tp_bases(PyTypeObject *self)
{
+ if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ static_builtin_state *state = _PyStaticType_GetState(interp, self);
+ assert(state != NULL);
+ return state->tp_bases;
+ }
return self->tp_bases;
}
PyObject *
_PyType_GetBases(PyTypeObject *self)
{
+ /* It returns a borrowed reference. */
return lookup_tp_bases(self);
}
static inline void
set_tp_bases(PyTypeObject *self, PyObject *bases)
{
+ if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ static_builtin_state *state = _PyStaticType_GetState(interp, self);
+ assert(state != NULL);
+ state->tp_bases = bases;
+ return;
+ }
self->tp_bases = bases;
}
static inline void
clear_tp_bases(PyTypeObject *self)
{
+ if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ static_builtin_state *state = _PyStaticType_GetState(interp, self);
+ assert(state != NULL);
+ Py_CLEAR(state->tp_bases);
+ return;
+ }
Py_CLEAR(self->tp_bases);
}
static inline PyObject *
lookup_tp_mro(PyTypeObject *self)
{
+ if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ static_builtin_state *state = _PyStaticType_GetState(interp, self);
+ assert(state != NULL);
+ return state->tp_mro;
+ }
return self->tp_mro;
}
PyObject *
_PyType_GetMRO(PyTypeObject *self)
{
+ /* It returns a borrowed reference. */
return lookup_tp_mro(self);
}
static inline void
set_tp_mro(PyTypeObject *self, PyObject *mro)
{
+ if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ static_builtin_state *state = _PyStaticType_GetState(interp, self);
+ assert(state != NULL);
+ state->tp_mro = mro;
+ return;
+ }
self->tp_mro = mro;
}
static inline void
clear_tp_mro(PyTypeObject *self)
{
+ if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ static_builtin_state *state = _PyStaticType_GetState(interp, self);
+ assert(state != NULL);
+ Py_CLEAR(state->tp_mro);
+ return;
+ }
Py_CLEAR(self->tp_mro);
}
CHECK(Py_REFCNT(type) >= 1);
CHECK(PyType_Check(type));
- CHECK(!(type->tp_flags & Py_TPFLAGS_READYING));
+ CHECK(!is_readying(type));
CHECK(lookup_tp_dict(type) != NULL);
if (type->tp_flags & Py_TPFLAGS_HAVE_GC) {
{"__base__", T_OBJECT, offsetof(PyTypeObject, tp_base), READONLY},
{"__dictoffset__", T_PYSSIZET,
offsetof(PyTypeObject, tp_dictoffset), READONLY},
- {"__mro__", T_OBJECT, offsetof(PyTypeObject, tp_mro), READONLY},
{0}
};
static PyObject *
type_get_bases(PyTypeObject *type, void *context)
{
- return Py_NewRef(lookup_tp_bases(type));
+ PyObject *bases = lookup_tp_bases(type);
+ if (bases == NULL) {
+ Py_RETURN_NONE;
+ }
+ return Py_NewRef(bases);
+}
+
+static PyObject *
+type_get_mro(PyTypeObject *type, void *context)
+{
+ PyObject *mro = lookup_tp_mro(type);
+ if (mro == NULL) {
+ Py_RETURN_NONE;
+ }
+ return Py_NewRef(mro);
}
static PyTypeObject *best_base(PyObject *);
{"__name__", (getter)type_name, (setter)type_set_name, NULL},
{"__qualname__", (getter)type_qualname, (setter)type_set_qualname, NULL},
{"__bases__", (getter)type_get_bases, (setter)type_set_bases, NULL},
+ {"__mro__", (getter)type_get_mro, NULL, NULL},
{"__module__", (getter)type_module, (setter)type_set_module, NULL},
{"__abstractmethods__", (getter)type_abstractmethods,
(setter)type_set_abstractmethods, NULL},
/* Look in tp_dict of types in MRO */
PyObject *mro = lookup_tp_mro(type);
if (mro == NULL) {
- if ((type->tp_flags & Py_TPFLAGS_READYING) == 0) {
+ if (!is_readying(type)) {
if (PyType_Ready(type) < 0) {
*error = -1;
return NULL;
clear_static_type_objects(PyInterpreterState *interp, PyTypeObject *type)
{
if (_Py_IsMainInterpreter(interp)) {
- clear_tp_dict(type);
- clear_tp_bases(type);
- clear_tp_mro(type);
Py_CLEAR(type->tp_cache);
}
+ clear_tp_dict(type);
+ clear_tp_bases(type);
+ clear_tp_mro(type);
clear_static_tp_subclasses(type);
}
static int
type_ready_set_bases(PyTypeObject *type)
{
+ if (lookup_tp_bases(type) != NULL) {
+ return 0;
+ }
+
/* Initialize tp_base (defaults to BaseObject unless that's us) */
PyTypeObject *base = type->tp_base;
if (base == NULL && type != &PyBaseObject_Type) {
// Set tp_new and the "__new__" key in the type dictionary.
// Use the Py_TPFLAGS_DISALLOW_INSTANTIATION flag.
static int
-type_ready_set_new(PyTypeObject *type)
+type_ready_set_new(PyTypeObject *type, int rerunbuiltin)
{
PyTypeObject *base = type->tp_base;
/* The condition below could use some explanation.
if (!(type->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION)) {
if (type->tp_new != NULL) {
- // If "__new__" key does not exists in the type dictionary,
- // set it to tp_new_wrapper().
- if (add_tp_new_wrapper(type) < 0) {
- return -1;
+ if (!rerunbuiltin || base == NULL || type->tp_new != base->tp_new) {
+ // If "__new__" key does not exists in the type dictionary,
+ // set it to tp_new_wrapper().
+ if (add_tp_new_wrapper(type) < 0) {
+ return -1;
+ }
}
}
else {
static int
-type_ready(PyTypeObject *type)
+type_ready(PyTypeObject *type, int rerunbuiltin)
{
- _PyObject_ASSERT((PyObject *)type,
- (type->tp_flags & Py_TPFLAGS_READYING) == 0);
- type->tp_flags |= Py_TPFLAGS_READYING;
+ _PyObject_ASSERT((PyObject *)type, !is_readying(type));
+ start_readying(type);
if (type_ready_pre_checks(type) < 0) {
goto error;
if (type_ready_mro(type) < 0) {
goto error;
}
- if (type_ready_set_new(type) < 0) {
+ if (type_ready_set_new(type, rerunbuiltin) < 0) {
goto error;
}
if (type_ready_fill_dict(type) < 0) {
goto error;
}
- if (type_ready_inherit(type) < 0) {
- goto error;
- }
- if (type_ready_preheader(type) < 0) {
- goto error;
+ if (!rerunbuiltin) {
+ if (type_ready_inherit(type) < 0) {
+ goto error;
+ }
+ if (type_ready_preheader(type) < 0) {
+ goto error;
+ }
}
if (type_ready_set_hash(type) < 0) {
goto error;
if (type_ready_add_subclasses(type) < 0) {
goto error;
}
- if (type_ready_managed_dict(type) < 0) {
- goto error;
- }
- if (type_ready_post_checks(type) < 0) {
- goto error;
+ if (!rerunbuiltin) {
+ if (type_ready_managed_dict(type) < 0) {
+ goto error;
+ }
+ if (type_ready_post_checks(type) < 0) {
+ goto error;
+ }
}
/* All done -- set the ready flag */
- type->tp_flags = (type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY;
+ type->tp_flags = type->tp_flags | Py_TPFLAGS_READY;
+ stop_readying(type);
assert(_PyType_CheckConsistency(type));
return 0;
error:
- type->tp_flags &= ~Py_TPFLAGS_READYING;
+ stop_readying(type);
return -1;
}
type->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE;
}
- return type_ready(type);
+ return type_ready(type, 0);
}
int
assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_DICT));
assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_WEAKREF));
-#ifndef NDEBUG
int ismain = _Py_IsMainInterpreter(interp);
-#endif
- if (self->tp_flags & Py_TPFLAGS_READY) {
+ if ((self->tp_flags & Py_TPFLAGS_READY) == 0) {
+ assert(ismain);
+
+ 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;
+ }
+ else {
assert(!ismain);
assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN);
assert(self->tp_flags & Py_TPFLAGS_VALID_VERSION_TAG);
-
- static_builtin_state_init(interp, self);
-
- /* Per-interpreter tp_subclasses is done lazily.
- Otherwise we would initialize it here. */
-
- assert(_PyType_CheckConsistency(self));
- return 0;
}
- assert(ismain);
-
- 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(interp, self);
- int res = type_ready(self);
+ int res = type_ready(self, !ismain);
if (res < 0) {
static_builtin_state_clear(interp, self);
}