-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Runtime improvements for generators #6251
Conversation
nhat-nguyen
commented
Aug 16, 2019
- Cache generator type
- Remove redundant prototype creation
- Remove extra dummy yield at the beginning of generator functions (used to evaluate default arguments, disabled by default, currently breaks async functions)
Generator functions with non-simple parameter list (e.g: arguments with default values that have some complex expressions) will need to evaluate those expressions when the generator object is created. This result in us emitting a first dummy yield to evaluate those. For jitted generator functions, this would mean every function would have a bailout at the beginning which is fairly expensive for small functions. So to mitigate this, only emit dummy yields when we really need to do so.
As the consistent test failure relates to AsyncGenerators I took a quick look. Unfortunately I found 2 separate bugs neither of which I currently have a fix for. 1. Error causing the current crash: async function* agf () {
await (function() {})();
}
agf().next(); Run with: This results in: I would be surprised if this result cannot be reproduced without the Dummy Yield as I assume there are other ways to hit a BailOnNoProfile before an OP_Await (Or OP_AwaitYield which has the same problem) 2. Other error async function* agf () {
await 5;
}
agf().next(); Run with: This appears to be an error introduced by removing the Dummy Yield and is not related to Jitting the code.
I'd like to look into this further particularly point 2 where I can see what's happening: |
} | ||
else | ||
{ | ||
this->Writer()->Reg1(Js::OpCode::LdUndef, funcInfo->yieldRegister); |
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.
In AsyncGenerators this results in writing undefined to what should be the location of the ResumeYieldData - unfortunately removing it just leaves it as a nullptr which isn't right either - in any event I don't think this instruction is useful.
Within the EmitDummyYield undefined is loaded into the yieldRegister then yielded (as you need to yield something) - the Resume that follows results in ResumeYieldData then being set here.
@rhuanjl Yes you are right. This improvement is a work-in-progress, and unfortunately I didn't have time to fix this before my last day. Essentially the problem is that async generator assumes that the Following is what I have tried to address this problem, but I wasn't sure if it was the best way. So there is code that handles setting this ResumeYieldData if the interpreter frame already exists ( The above fix would expose us to another problem in the jit where the symbol defined by the yield register doesn't exist before uses by So with the 2 fixes, I think we are back to having the first case that you describe where the |
I think I've solved the BailOut issue, took ages to track it down but very simple in the end - posted in the other PR as relevant there. I've hit all sorts of weird errors I don't understand trying to solve the RemoveDummyYield, I will continue digging a little with it. |