Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-127773: Disable attribute cache on incompatible MRO entries #127924

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

encukou
Copy link
Member

@encukou encukou commented Dec 13, 2024

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 existing tp_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 in PyTypeObject. Ideally in a private (underscore-prefixed) field; not in tp_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.

Copy link
Contributor

@colesbury colesbury left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense to me, but @markshannon is probably more familiar with the MRO cache and tp_versions_used.

@@ -1208,6 +1214,8 @@ _PyType_GetVersionForCurrentState(PyTypeObject *tp)


#define MAX_VERSIONS_PER_CLASS 1000
_Static_assert(MAX_VERSIONS_PER_CLASS < _Py_ATTR_CACHE_UNUSED,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think _freeze_module in the Windows build is not compiling this as C11.

@@ -0,0 +1 @@
Do not use the type attribute cache for types with incompatible MRO.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Do not use the type attribute cache for types with incompatible MRO.
Do not use the type attribute cache for types with incompatible :term:`MRO`.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants