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

skip type check of method receivers where unnecessary #4026

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

davidhewitt
Copy link
Member

Attempt to fix #3843

The idea is that the Python interpreter already type-checks the self passed for many methods and slots, so we don't need to do this for receivers where we know the interpreter does the check.

There is precedent in CPython for this assumption to be used, for example tuple.__hash__() assumes it gets a tuple object: https://github.com/python/cpython/blob/bfc57d43d8766120ba0c8f3f6d7b2ac681a81d8a/Objects/tupleobject.c#L321

Similarly for tuple methods such as tuple.index(): https://github.com/python/cpython/blob/bfc57d43d8766120ba0c8f3f6d7b2ac681a81d8a/Objects/clinic/tupleobject.c.h#L23

The only case where this seemed to be problematic was in the binary operators, where they can be called in reverse and that breaks the assumption that the type is correct. This might be our fault inside the implementation, so possibly something to check.

I thought that first I'd see how this implementation affects benchmarks...

@davidhewitt
Copy link
Member Author

According to codspeed, this is a 5% improvement in the method call benchmarks:
image

Is it worth the complexity / lack of check? Maybe.

U: TryFrom<BoundRef<'a, 'py, T>>,
U::Error: Into<PyErr>,
{
U::try_from(BoundRef::ref_from_ptr(py, obj).downcast::<T>()?).map_err(Into::into)
Copy link
Member

Choose a reason for hiding this comment

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

The extra let obj binding would be worth the readability improvement here as well IMHO.

pub unsafe fn receive_pyclass<'a, 'py: 'a, T: PyClass>(
py: Python<'py>,
obj: &'a *mut ffi::PyObject,
holder: &'a mut Option<PyRef<'py, T>>,
Copy link
Member

Choose a reason for hiding this comment

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

Doesn't this already imply 'py: 'a or is what requires you to add the bound?

Copy link
Member

@adamreichold adamreichold left a comment

Choose a reason for hiding this comment

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

I quite like the controlled approach using AssumeCorrectReceiverType which also carries documentation nicely targeted and think this would be worth it. I would be grateful for a test case or two involving the binary-operator-based type confusion though.

We should be prepared for bug reports though as I expect us to get it wrong at least in some place or there being version- or implementation-dependent behaviour for which we have yet to account.

@davidhewitt
Copy link
Member Author

davidhewitt commented Mar 31, 2024

I quite like the controlled approach using AssumeCorrectReceiverType which also carries documentation nicely targeted

Agreed, I wondered whether to even make it unsafe inside the macro to apply the assumption (given that can cause runtime unsafety) but figured that was overkill given that basically everything the macros do is related to building unsafe code.

We should be prepared for bug reports though as I expect us to get it wrong at least in some place or there being version- or implementation-dependent behaviour for which we have yet to account.

I think so too; as well as more thorough testing I'd like to dig deeper into the binary operators further. Also given the risk to introduce bugs I'm feeling like I'll leave this for 0.22 where this sort of adjustment seems more reasonable than a 0.21.1 patch release.

I'll try to get back to this in the coming days, will leave in draft for now...

@davidhewitt davidhewitt added this to the 0.22 milestone Mar 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Avoiding struct method call overhead of extract_pyclass_ref_mut
2 participants