[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
|
||||
clear_slotdefs(void);
|
||||
|
||||
static PyObject *
|
||||
lookup_maybe_method(PyObject *self, _Py_Identifier *attrid, int *unbound);
|
||||
|
||||
/*
|
||||
* finds the beginning of the docstring's introspection signature.
|
||||
* 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
|
||||
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
|
||||
each subclass when their mro is recursively updated.
|
||||
*/
|
||||
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))
|
||||
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);
|
||||
for (i = 0; i < n; 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) ||
|
||||
!PyType_IsSubtype(type, cls)) {
|
||||
clear = 1;
|
||||
break;
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
|
||||
if (clear)
|
||||
return;
|
||||
clear:
|
||||
Py_XDECREF(mro_meth);
|
||||
Py_XDECREF(type_mro_meth);
|
||||
type->tp_flags &= ~(Py_TPFLAGS_HAVE_VERSION_TAG|
|
||||
Py_TPFLAGS_VALID_VERSION_TAG);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue