-
-
Notifications
You must be signed in to change notification settings - Fork 3k
[mypyc] Call generator helper method directly in await expression #19376
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
Conversation
Also use generator class as the return type of generators.
# Give a more precise type for generators, so that we can optimize | ||
# code that uses them. They return a generator object, which has a | ||
# specific class. Without this, the type would have to be 'object'. | ||
ret: RType = RInstance(self.fdef_to_generator[fdef]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the first part of the optimization.
and val.type.class_ir.has_method(helper_method) | ||
): | ||
# This is a generated generator class, and we can use a fast path. | ||
iter_val: Value = val |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes in this function implemented the bulk of the optimization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a bit more detailed comment (essentially summarizing the PR description) so we will not forget the motivation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LG, just one suggestion.
and val.type.class_ir.has_method(helper_method) | ||
): | ||
# This is a generated generator class, and we can use a fast path. | ||
iter_val: Value = val |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a bit more detailed comment (essentially summarizing the PR description) so we will not forget the motivation.
Previously calls like
await foo()
were compiled to code that included code like this (in Python-like pseudocode):In the above code,
get_coro(a)
just returnsa
iffoo
is a native async function, so we now optimize this call away. Alsonext(b)
callsb.__next__()
, which calls the generated generator helper method__mypyc_generator_helper__
. Now we call the helper method directly, which saves some unnecessary calls.More importantly, in a follow-up PR I can easily change the way
__mypyc_generator_helper__
is called, since we now call it directly. This makes it possible to avoid raising aStopIteration
exception in many await expressions. The goal of this PR is to prepare for the latter optimization. This PR doesn't help performance significantly by itself.In order to call the helper method directly, I had to generate the declaration of this method and the generated generator class before the main irbuild pass, since otherwise a call site could be processed before we have processed the called generator.
I also improved test coverage of related functionality. We don't have an IR test for async calls, since the IR is very verbose. I manually inspected the generated IR to verify that the new code path works both when calling a top-level function and when calling a method. I'll later add a mypyc benchmark to ensure that we will notice if the performance of async calls is degraded.