mirror of https://github.com/python/cpython
gh-94673: More Per-Interpreter Fields for Builtin Static Types (gh-103912)
his involves moving tp_dict, tp_bases, and tp_mro to PyInterpreterState, in the same way we did for tp_subclasses. Those three fields are effectively const for builtin static types (unlike tp_subclasses). In theory we only need to make their values immortal, along with their contents. However, that isn't such a simple proposition. (See gh-103823.) In the meantime the simplest solution is to move the fields into the interpreter. One alternative is to statically allocate the values, but that's its own can of worms.
This commit is contained in:
parent
872cbc6132
commit
de64e75616
|
@ -44,6 +44,13 @@ struct type_cache {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyTypeObject *type;
|
PyTypeObject *type;
|
||||||
|
int readying;
|
||||||
|
int ready;
|
||||||
|
// XXX tp_dict, tp_bases, and tp_mro can probably be statically
|
||||||
|
// allocated, instead of dynamically and stored on the interpreter.
|
||||||
|
PyObject *tp_dict;
|
||||||
|
PyObject *tp_bases;
|
||||||
|
PyObject *tp_mro;
|
||||||
PyObject *tp_subclasses;
|
PyObject *tp_subclasses;
|
||||||
/* We never clean up weakrefs for static builtin types since
|
/* We never clean up weakrefs for static builtin types since
|
||||||
they will effectively never get triggered. However, there
|
they will effectively never get triggered. However, there
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "pycore_moduleobject.h" // _PyModule_GetState()
|
#include "pycore_moduleobject.h" // _PyModule_GetState()
|
||||||
#include "pycore_object.h" // _PyType_GetSubclasses()
|
#include "pycore_object.h" // _PyType_GetSubclasses()
|
||||||
#include "pycore_runtime.h" // _Py_ID()
|
#include "pycore_runtime.h" // _Py_ID()
|
||||||
|
#include "pycore_typeobject.h" // _PyType_GetMRO()
|
||||||
#include "clinic/_abc.c.h"
|
#include "clinic/_abc.c.h"
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
|
|
@ -2174,23 +2174,6 @@ _PyGC_DumpShutdownStats(PyInterpreterState *interp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
gc_fini_untrack(PyGC_Head *list)
|
|
||||||
{
|
|
||||||
PyGC_Head *gc;
|
|
||||||
for (gc = GC_NEXT(list); gc != list; gc = GC_NEXT(list)) {
|
|
||||||
PyObject *op = FROM_GC(gc);
|
|
||||||
_PyObject_GC_UNTRACK(op);
|
|
||||||
// gh-92036: If a deallocator function expect the object to be tracked
|
|
||||||
// by the GC (ex: func_dealloc()), it can crash if called on an object
|
|
||||||
// which is no longer tracked by the GC. Leak one strong reference on
|
|
||||||
// purpose so the object is never deleted and its deallocator is not
|
|
||||||
// called.
|
|
||||||
Py_INCREF(op);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
_PyGC_Fini(PyInterpreterState *interp)
|
_PyGC_Fini(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
|
@ -2198,17 +2181,9 @@ _PyGC_Fini(PyInterpreterState *interp)
|
||||||
Py_CLEAR(gcstate->garbage);
|
Py_CLEAR(gcstate->garbage);
|
||||||
Py_CLEAR(gcstate->callbacks);
|
Py_CLEAR(gcstate->callbacks);
|
||||||
|
|
||||||
if (!_Py_IsMainInterpreter(interp)) {
|
/* We expect that none of this interpreters objects are shared
|
||||||
// bpo-46070: Explicitly untrack all objects currently tracked by the
|
with other interpreters.
|
||||||
// GC. Otherwise, if an object is used later by another interpreter,
|
See https://github.com/python/cpython/issues/90228. */
|
||||||
// calling PyObject_GC_UnTrack() on the object crashs if the previous
|
|
||||||
// or the next object of the PyGC_Head structure became a dangling
|
|
||||||
// pointer.
|
|
||||||
for (int i = 0; i < NUM_GENERATIONS; i++) {
|
|
||||||
PyGC_Head *gen = GEN_HEAD(gcstate, i);
|
|
||||||
gc_fini_untrack(gen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* for debugging */
|
/* for debugging */
|
||||||
|
|
|
@ -511,7 +511,6 @@ _PyStructSequence_InitBuiltinWithFlags(PyInterpreterState *interp,
|
||||||
Py_ssize_t n_members = count_members(desc, &n_unnamed_members);
|
Py_ssize_t n_members = count_members(desc, &n_unnamed_members);
|
||||||
PyMemberDef *members = NULL;
|
PyMemberDef *members = NULL;
|
||||||
|
|
||||||
int initialized = 1;
|
|
||||||
if ((type->tp_flags & Py_TPFLAGS_READY) == 0) {
|
if ((type->tp_flags & Py_TPFLAGS_READY) == 0) {
|
||||||
assert(type->tp_name == NULL);
|
assert(type->tp_name == NULL);
|
||||||
assert(type->tp_members == NULL);
|
assert(type->tp_members == NULL);
|
||||||
|
@ -524,7 +523,6 @@ _PyStructSequence_InitBuiltinWithFlags(PyInterpreterState *interp,
|
||||||
initialize_static_fields(type, desc, members, tp_flags);
|
initialize_static_fields(type, desc, members, tp_flags);
|
||||||
|
|
||||||
_Py_SetImmortal(type);
|
_Py_SetImmortal(type);
|
||||||
initialized = 0;
|
|
||||||
}
|
}
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
else {
|
else {
|
||||||
|
@ -543,13 +541,10 @@ _PyStructSequence_InitBuiltinWithFlags(PyInterpreterState *interp,
|
||||||
desc->name);
|
desc->name);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
// This should be dropped if tp_dict is made per-interpreter.
|
|
||||||
if (initialized) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (initialize_structseq_dict(
|
if (initialize_structseq_dict(
|
||||||
desc, _PyType_GetDict(type), n_members, n_unnamed_members) < 0) {
|
desc, _PyType_GetDict(type), n_members, n_unnamed_members) < 0)
|
||||||
|
{
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -167,29 +167,93 @@ static_builtin_state_clear(PyInterpreterState *interp, PyTypeObject *self)
|
||||||
/* end static builtin helpers */
|
/* 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 */
|
/* accessors for objects stored on PyTypeObject */
|
||||||
|
|
||||||
static inline PyObject *
|
static inline PyObject *
|
||||||
lookup_tp_dict(PyTypeObject *self)
|
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;
|
return self->tp_dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_PyType_GetDict(PyTypeObject *self)
|
_PyType_GetDict(PyTypeObject *self)
|
||||||
{
|
{
|
||||||
|
/* It returns a borrowed reference. */
|
||||||
return lookup_tp_dict(self);
|
return lookup_tp_dict(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
set_tp_dict(PyTypeObject *self, PyObject *dict)
|
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;
|
self->tp_dict = dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
clear_tp_dict(PyTypeObject *self)
|
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);
|
Py_CLEAR(self->tp_dict);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,24 +261,45 @@ clear_tp_dict(PyTypeObject *self)
|
||||||
static inline PyObject *
|
static inline PyObject *
|
||||||
lookup_tp_bases(PyTypeObject *self)
|
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;
|
return self->tp_bases;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_PyType_GetBases(PyTypeObject *self)
|
_PyType_GetBases(PyTypeObject *self)
|
||||||
{
|
{
|
||||||
|
/* It returns a borrowed reference. */
|
||||||
return lookup_tp_bases(self);
|
return lookup_tp_bases(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
set_tp_bases(PyTypeObject *self, PyObject *bases)
|
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;
|
self->tp_bases = bases;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
clear_tp_bases(PyTypeObject *self)
|
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);
|
Py_CLEAR(self->tp_bases);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,24 +307,45 @@ clear_tp_bases(PyTypeObject *self)
|
||||||
static inline PyObject *
|
static inline PyObject *
|
||||||
lookup_tp_mro(PyTypeObject *self)
|
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;
|
return self->tp_mro;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_PyType_GetMRO(PyTypeObject *self)
|
_PyType_GetMRO(PyTypeObject *self)
|
||||||
{
|
{
|
||||||
|
/* It returns a borrowed reference. */
|
||||||
return lookup_tp_mro(self);
|
return lookup_tp_mro(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
set_tp_mro(PyTypeObject *self, PyObject *mro)
|
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;
|
self->tp_mro = mro;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
clear_tp_mro(PyTypeObject *self)
|
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);
|
Py_CLEAR(self->tp_mro);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,7 +514,7 @@ _PyType_CheckConsistency(PyTypeObject *type)
|
||||||
CHECK(Py_REFCNT(type) >= 1);
|
CHECK(Py_REFCNT(type) >= 1);
|
||||||
CHECK(PyType_Check(type));
|
CHECK(PyType_Check(type));
|
||||||
|
|
||||||
CHECK(!(type->tp_flags & Py_TPFLAGS_READYING));
|
CHECK(!is_readying(type));
|
||||||
CHECK(lookup_tp_dict(type) != NULL);
|
CHECK(lookup_tp_dict(type) != NULL);
|
||||||
|
|
||||||
if (type->tp_flags & Py_TPFLAGS_HAVE_GC) {
|
if (type->tp_flags & Py_TPFLAGS_HAVE_GC) {
|
||||||
|
@ -809,7 +915,6 @@ static PyMemberDef type_members[] = {
|
||||||
{"__base__", T_OBJECT, offsetof(PyTypeObject, tp_base), READONLY},
|
{"__base__", T_OBJECT, offsetof(PyTypeObject, tp_base), READONLY},
|
||||||
{"__dictoffset__", T_PYSSIZET,
|
{"__dictoffset__", T_PYSSIZET,
|
||||||
offsetof(PyTypeObject, tp_dictoffset), READONLY},
|
offsetof(PyTypeObject, tp_dictoffset), READONLY},
|
||||||
{"__mro__", T_OBJECT, offsetof(PyTypeObject, tp_mro), READONLY},
|
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1023,7 +1128,21 @@ type_set_abstractmethods(PyTypeObject *type, PyObject *value, void *context)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
type_get_bases(PyTypeObject *type, void *context)
|
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 *);
|
static PyTypeObject *best_base(PyObject *);
|
||||||
|
@ -1402,6 +1521,7 @@ static PyGetSetDef type_getsets[] = {
|
||||||
{"__name__", (getter)type_name, (setter)type_set_name, NULL},
|
{"__name__", (getter)type_name, (setter)type_set_name, NULL},
|
||||||
{"__qualname__", (getter)type_qualname, (setter)type_set_qualname, NULL},
|
{"__qualname__", (getter)type_qualname, (setter)type_set_qualname, NULL},
|
||||||
{"__bases__", (getter)type_get_bases, (setter)type_set_bases, 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},
|
{"__module__", (getter)type_module, (setter)type_set_module, NULL},
|
||||||
{"__abstractmethods__", (getter)type_abstractmethods,
|
{"__abstractmethods__", (getter)type_abstractmethods,
|
||||||
(setter)type_set_abstractmethods, NULL},
|
(setter)type_set_abstractmethods, NULL},
|
||||||
|
@ -4342,7 +4462,7 @@ find_name_in_mro(PyTypeObject *type, PyObject *name, int *error)
|
||||||
/* Look in tp_dict of types in MRO */
|
/* Look in tp_dict of types in MRO */
|
||||||
PyObject *mro = lookup_tp_mro(type);
|
PyObject *mro = lookup_tp_mro(type);
|
||||||
if (mro == NULL) {
|
if (mro == NULL) {
|
||||||
if ((type->tp_flags & Py_TPFLAGS_READYING) == 0) {
|
if (!is_readying(type)) {
|
||||||
if (PyType_Ready(type) < 0) {
|
if (PyType_Ready(type) < 0) {
|
||||||
*error = -1;
|
*error = -1;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -4692,11 +4812,11 @@ static void
|
||||||
clear_static_type_objects(PyInterpreterState *interp, PyTypeObject *type)
|
clear_static_type_objects(PyInterpreterState *interp, PyTypeObject *type)
|
||||||
{
|
{
|
||||||
if (_Py_IsMainInterpreter(interp)) {
|
if (_Py_IsMainInterpreter(interp)) {
|
||||||
clear_tp_dict(type);
|
|
||||||
clear_tp_bases(type);
|
|
||||||
clear_tp_mro(type);
|
|
||||||
Py_CLEAR(type->tp_cache);
|
Py_CLEAR(type->tp_cache);
|
||||||
}
|
}
|
||||||
|
clear_tp_dict(type);
|
||||||
|
clear_tp_bases(type);
|
||||||
|
clear_tp_mro(type);
|
||||||
clear_static_tp_subclasses(type);
|
clear_static_tp_subclasses(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6684,6 +6804,10 @@ type_ready_pre_checks(PyTypeObject *type)
|
||||||
static int
|
static int
|
||||||
type_ready_set_bases(PyTypeObject *type)
|
type_ready_set_bases(PyTypeObject *type)
|
||||||
{
|
{
|
||||||
|
if (lookup_tp_bases(type) != NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize tp_base (defaults to BaseObject unless that's us) */
|
/* Initialize tp_base (defaults to BaseObject unless that's us) */
|
||||||
PyTypeObject *base = type->tp_base;
|
PyTypeObject *base = type->tp_base;
|
||||||
if (base == NULL && type != &PyBaseObject_Type) {
|
if (base == NULL && type != &PyBaseObject_Type) {
|
||||||
|
@ -6997,7 +7121,7 @@ type_ready_add_subclasses(PyTypeObject *type)
|
||||||
// Set tp_new and the "__new__" key in the type dictionary.
|
// Set tp_new and the "__new__" key in the type dictionary.
|
||||||
// Use the Py_TPFLAGS_DISALLOW_INSTANTIATION flag.
|
// Use the Py_TPFLAGS_DISALLOW_INSTANTIATION flag.
|
||||||
static int
|
static int
|
||||||
type_ready_set_new(PyTypeObject *type)
|
type_ready_set_new(PyTypeObject *type, int rerunbuiltin)
|
||||||
{
|
{
|
||||||
PyTypeObject *base = type->tp_base;
|
PyTypeObject *base = type->tp_base;
|
||||||
/* The condition below could use some explanation.
|
/* The condition below could use some explanation.
|
||||||
|
@ -7019,10 +7143,12 @@ type_ready_set_new(PyTypeObject *type)
|
||||||
|
|
||||||
if (!(type->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION)) {
|
if (!(type->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION)) {
|
||||||
if (type->tp_new != NULL) {
|
if (type->tp_new != NULL) {
|
||||||
// If "__new__" key does not exists in the type dictionary,
|
if (!rerunbuiltin || base == NULL || type->tp_new != base->tp_new) {
|
||||||
// set it to tp_new_wrapper().
|
// If "__new__" key does not exists in the type dictionary,
|
||||||
if (add_tp_new_wrapper(type) < 0) {
|
// set it to tp_new_wrapper().
|
||||||
return -1;
|
if (add_tp_new_wrapper(type) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -7096,11 +7222,10 @@ type_ready_post_checks(PyTypeObject *type)
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
type_ready(PyTypeObject *type)
|
type_ready(PyTypeObject *type, int rerunbuiltin)
|
||||||
{
|
{
|
||||||
_PyObject_ASSERT((PyObject *)type,
|
_PyObject_ASSERT((PyObject *)type, !is_readying(type));
|
||||||
(type->tp_flags & Py_TPFLAGS_READYING) == 0);
|
start_readying(type);
|
||||||
type->tp_flags |= Py_TPFLAGS_READYING;
|
|
||||||
|
|
||||||
if (type_ready_pre_checks(type) < 0) {
|
if (type_ready_pre_checks(type) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -7125,17 +7250,19 @@ type_ready(PyTypeObject *type)
|
||||||
if (type_ready_mro(type) < 0) {
|
if (type_ready_mro(type) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (type_ready_set_new(type) < 0) {
|
if (type_ready_set_new(type, rerunbuiltin) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (type_ready_fill_dict(type) < 0) {
|
if (type_ready_fill_dict(type) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (type_ready_inherit(type) < 0) {
|
if (!rerunbuiltin) {
|
||||||
goto error;
|
if (type_ready_inherit(type) < 0) {
|
||||||
}
|
goto error;
|
||||||
if (type_ready_preheader(type) < 0) {
|
}
|
||||||
goto error;
|
if (type_ready_preheader(type) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (type_ready_set_hash(type) < 0) {
|
if (type_ready_set_hash(type) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -7143,21 +7270,24 @@ type_ready(PyTypeObject *type)
|
||||||
if (type_ready_add_subclasses(type) < 0) {
|
if (type_ready_add_subclasses(type) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (type_ready_managed_dict(type) < 0) {
|
if (!rerunbuiltin) {
|
||||||
goto error;
|
if (type_ready_managed_dict(type) < 0) {
|
||||||
}
|
goto error;
|
||||||
if (type_ready_post_checks(type) < 0) {
|
}
|
||||||
goto error;
|
if (type_ready_post_checks(type) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* All done -- set the ready flag */
|
/* 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));
|
assert(_PyType_CheckConsistency(type));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
type->tp_flags &= ~Py_TPFLAGS_READYING;
|
stop_readying(type);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7175,7 +7305,7 @@ PyType_Ready(PyTypeObject *type)
|
||||||
type->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE;
|
type->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type_ready(type);
|
return type_ready(type, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -7186,35 +7316,26 @@ _PyStaticType_InitBuiltin(PyInterpreterState *interp, PyTypeObject *self)
|
||||||
assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_DICT));
|
assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_DICT));
|
||||||
assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_WEAKREF));
|
assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_WEAKREF));
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
int ismain = _Py_IsMainInterpreter(interp);
|
int ismain = _Py_IsMainInterpreter(interp);
|
||||||
#endif
|
if ((self->tp_flags & Py_TPFLAGS_READY) == 0) {
|
||||||
if (self->tp_flags & Py_TPFLAGS_READY) {
|
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(!ismain);
|
||||||
assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN);
|
assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN);
|
||||||
assert(self->tp_flags & Py_TPFLAGS_VALID_VERSION_TAG);
|
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);
|
static_builtin_state_init(interp, self);
|
||||||
|
|
||||||
int res = type_ready(self);
|
int res = type_ready(self, !ismain);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
static_builtin_state_clear(interp, self);
|
static_builtin_state_clear(interp, self);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue