[3.7] bpo-28866: No type cache for types with specialized mro, invalidation is hard. (GH-13157) (GH-13589)
* No type cache for types with specialized mro, invalidation is hard.
* FIX: Don't disable method cache custom types that do not implement mro().
* fixing implem.
* Avoid storing error flags, also decref.
* news entry
* Clear as soon as we're getting an error.
* FIX: Reference leak.
(cherry picked from commit 180dc1b0f4
)
Co-authored-by: Julien Palard <julien@palard.fr>
https://bugs.python.org/issue28866
This commit is contained in:
parent
f3d909428c
commit
bfd0b77201
|
@ -0,0 +1,2 @@
|
||||||
|
Avoid caching attributes of classes which type defines mro() to avoid a hard
|
||||||
|
cache invalidation problem.
|
|
@ -77,6 +77,9 @@ slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
|
||||||
static void
|
static void
|
||||||
clear_slotdefs(void);
|
clear_slotdefs(void);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
lookup_maybe_method(PyObject *self, _Py_Identifier *attrid, int *unbound);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* finds the beginning of the docstring's introspection signature.
|
* finds the beginning of the docstring's introspection signature.
|
||||||
* if present, returns a pointer pointing to the first '('.
|
* if present, returns a pointer pointing to the first '('.
|
||||||
|
@ -281,17 +284,35 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
|
||||||
|
|
||||||
Unset HAVE_VERSION_TAG and VALID_VERSION_TAG if the type
|
Unset HAVE_VERSION_TAG and VALID_VERSION_TAG if the type
|
||||||
has a custom MRO that includes a type which is not officially
|
has a custom MRO that includes a type which is not officially
|
||||||
super type.
|
super type, or if the type implements its own mro() method.
|
||||||
|
|
||||||
Called from mro_internal, which will subsequently be called on
|
Called from mro_internal, which will subsequently be called on
|
||||||
each subclass when their mro is recursively updated.
|
each subclass when their mro is recursively updated.
|
||||||
*/
|
*/
|
||||||
Py_ssize_t i, n;
|
Py_ssize_t i, n;
|
||||||
int clear = 0;
|
int custom = (Py_TYPE(type) != &PyType_Type);
|
||||||
|
int unbound;
|
||||||
|
PyObject *mro_meth = NULL;
|
||||||
|
PyObject *type_mro_meth = NULL;
|
||||||
|
|
||||||
if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_VERSION_TAG))
|
if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_VERSION_TAG))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (custom) {
|
||||||
|
_Py_IDENTIFIER(mro);
|
||||||
|
mro_meth = lookup_maybe_method(
|
||||||
|
(PyObject *)type, &PyId_mro, &unbound);
|
||||||
|
if (mro_meth == NULL)
|
||||||
|
goto clear;
|
||||||
|
type_mro_meth = lookup_maybe_method(
|
||||||
|
(PyObject *)&PyType_Type, &PyId_mro, &unbound);
|
||||||
|
if (type_mro_meth == NULL)
|
||||||
|
goto clear;
|
||||||
|
if (mro_meth != type_mro_meth)
|
||||||
|
goto clear;
|
||||||
|
Py_XDECREF(mro_meth);
|
||||||
|
Py_XDECREF(type_mro_meth);
|
||||||
|
}
|
||||||
n = PyTuple_GET_SIZE(bases);
|
n = PyTuple_GET_SIZE(bases);
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
PyObject *b = PyTuple_GET_ITEM(bases, i);
|
PyObject *b = PyTuple_GET_ITEM(bases, i);
|
||||||
|
@ -302,12 +323,13 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
|
||||||
|
|
||||||
if (!PyType_HasFeature(cls, Py_TPFLAGS_HAVE_VERSION_TAG) ||
|
if (!PyType_HasFeature(cls, Py_TPFLAGS_HAVE_VERSION_TAG) ||
|
||||||
!PyType_IsSubtype(type, cls)) {
|
!PyType_IsSubtype(type, cls)) {
|
||||||
clear = 1;
|
goto clear;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
if (clear)
|
clear:
|
||||||
|
Py_XDECREF(mro_meth);
|
||||||
|
Py_XDECREF(type_mro_meth);
|
||||||
type->tp_flags &= ~(Py_TPFLAGS_HAVE_VERSION_TAG|
|
type->tp_flags &= ~(Py_TPFLAGS_HAVE_VERSION_TAG|
|
||||||
Py_TPFLAGS_VALID_VERSION_TAG);
|
Py_TPFLAGS_VALID_VERSION_TAG);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue