gh-148510: restore func_version check in _LOAD_ATTR_PROPERTY_FRAME#148528
Conversation
Fidget-Spinner
left a comment
There was a problem hiding this comment.
Just one thing that should be addressed. Thanks!
|
Seems like cpython/Python/optimizer_bytecodes.c Lines 143 to 145 in 21da9d7 |
Oops I think that was me. Can you please add a condition to that in another PR? |
|
Sure. |
|
@NekoAsakura sorry for the flip flop, but I think we can do this in this PR, I realised they're the same uop, just one is the other variant. |
|
NP! Wait me a second. |
Python/optimizer_bytecodes.c
Outdated
| sym_set_type_version(owner, type_version)) { | ||
| PyType_Watch(TYPE_WATCHER_ID, (PyObject *)probable_type); | ||
| _Py_BloomFilter_Add(dependencies, probable_type); |
There was a problem hiding this comment.
Instead of setting the type verison, promote the type. Use sym_set_type(owner, probable_type) inside the if branch. Please update _GUARD_TYPE_VERSION_LOCKED to do that as well (and fix the NULL check).
There was a problem hiding this comment.
Wait I'm wrong here, we can't do that. I forgot what sym_set_type_version does. Sorry for misleading!
There was a problem hiding this comment.
I think we can do both in sequence like:
sym_set_type(owner, probable_type);
sym_set_type_version(owner, type_version);
This promotes type while keeping the version.
There was a problem hiding this comment.
If we do sym_set_type(owner, probable_type);, we don't need to set the type version after, as sym_get_type_version just grabs tp_version_tag from the type. It's essentially a no-op.
Also type is strictly more information than type version in our framework https://github.com/python/cpython/blob/main/Python/optimizer_symbols.c#L37
There was a problem hiding this comment.
I'm afraid sym_get_type_version returns sym->cls.version for KNOWN_CLASS_TAG, not cls.type->tp_version_tag:
cpython/Python/optimizer_symbols.c
Lines 750 to 751 in 21da9d7
And sym_set_type sets cls.version = 0 when promoting from RECORDED_TYPE_TAG:
cpython/Python/optimizer_symbols.c
Lines 351 to 355 in 21da9d7
Without sym_set_type_version afterwards, the version stays 0 and guard elimination breaks.
There was a problem hiding this comment.
Ah ok. Thanks for digging into this!
There was a problem hiding this comment.
Is there a reason for it to return cls.version when class is known? It seems better to return the version from tp_version_tag.
Fidget-Spinner
left a comment
There was a problem hiding this comment.
Thanks, LGTM. Just one comment.
Python/optimizer_bytecodes.c
Outdated
| PyCodeObject *co = (PyCodeObject *)((PyFunctionObject *)fget)->func_code; | ||
| op(_LOAD_ATTR_PROPERTY_FRAME, (func_version/2, fget/4, owner -- new_frame)) { | ||
| if (sym_get_type_version(owner) == 0) { | ||
| ctx->done = true; |
There was a problem hiding this comment.
Why not ctx->contradiction to true as well? That would abandon the whole trace, which is what we dant. Done allows the trace to continue executing.
There was a problem hiding this comment.
Oops I accidentally deleted that. Thanks for catching it!
| # Check the optimizer traced through the property call. | ||
| self.assertIn("_CALL_BUILTIN_CLASS", uops) |
There was a problem hiding this comment.
No this doesn't check the optimizer actually ran inside the call. The easiest way is to check the global was promoted, ie the absence of _LOAD_GLOBAL_BUILTIN.
There was a problem hiding this comment.
Yes, was missing f->func = func on the abstract frame so globals couldn't be resolved. Sorted now, test asserts the absence of _LOAD_GLOBAL_BUILTINS.
Do not merge.Prerequisite: #148524 (Merged)
Mean +- std: [main] 12.8 ms +- 0.2 ms -> [branch] 12.3 ms +- 0.1 ms