gh-127773: Disable attribute cache on incompatible MRO entries #127924
+49
−2
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_flags
in 3.9 and below.I'd like to avoid using
tp_flags
for 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_used
as 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_used
check is reused.If the
tp_versions_used
mechanism is dropped in the future,_Py_ATTR_CACHE_UNUSED
can 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.