gh-127773: Disable attribute cache on incompatible MRO entries#127924
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This brings back the functionality of
Py_TPFLAGS_HAVE_VERSION_TAG, which should have been named “use version tag”, as the field itself is always present -- see #27260 where I mistakenly removed it.The type attribute cache relies on a class being able to invalidate caches of all of its subclasses. If a type's MRO contains an entry that's not that type's base, the cache needs to be disabled.
This requires a single bit, which was in
tp_flagsin 3.9 and below.I'd like to avoid using
tp_flagsfor an internal flag (even one that's currently reserved for ABI compatibility).We already have a mechanism for disabling the cache: it's disabled after 1000 modifications to a single type, using
tp_versions_usedas a counter. It would be possible to set this to 1000 (MAX_VERSIONS_PER_CLASS) when an incompatible MRO is found. To make the code & logic more understandable, this PR uses a new bigger constant,_Py_ATTR_CACHE_UNUSED. The existingtp_versions_usedcheck is reused.If the
tp_versions_usedmechanism is dropped in the future,_Py_ATTR_CACHE_UNUSEDcan become a single bit stored elsewhere inPyTypeObject. Ideally in a private (underscore-prefixed) field; not intp_flags.@markshannon@colesbury Does this sound right? I'm not much of an attribute cache expert and I don't know about future plans in this area.