You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[MERGE #6170@nhat-nguyen] Enable basic jitting without global optimizer for generators on x64
Merge pull request #6170 from nhat-nguyen:generator
- Cleaned up the bail-in code and the IR dumps with self-descriptive label names and added special opcodes just for generators; this made it easier to read the dumps in general and to perform some other logic using those opcodes
- Fixed epilogues in generators. We now have 2 epilogue labels in generators that can be jumped to. The first one nulls out the interpreter frame to signal generator completion and restores all callee-save registers - used for return statements. The other one only does the latter, used for jumps after bailing out. (the register restore part is shared between the 2 labels)
- We also already have the mechanism to deal with yield points that were optimized away (called `BailOutForElidedYield`), I also changed the logic a bit to work with these new epilogue labels
- The resume jump table must be placed close enough to the beginning of the jit'd function so that we don't accidentally re-run the code, but also further below enough so that we can reload "global" values such as constants / environment (right now, it is placed right after we load the environment). One thing to note is that objects like Environment are always loaded from the `ScriptFunction`, but some like the `FrameDisplay/LocalClosure` might be created on the heap and transferred over to the interpreter frame afterwards. So we want to place the jump table before anything that can created new objects on the heap
- also made sure that the bail-in code doesn't blindly overwrite any of the values we reload before the jump table
- Right now the bail-in code does the reverse of what the bail-out code does: grabbing all those special field members and putting them back, the rest of the bytecode symbols are simply loaded from the usual `localSlots` space
- Made for-in enumerators work with generators by always using the space allocated on the interpreter frame
- Previously, in some cases, we would not have an interpreter frame the first time we are in the jit'd code and only create the frame once we bail out for the first time. This is fine for normal generators because we would bail-out to return the generator object, so the next time the interpreter frame would have already been created. However, `async` functions don't have this first yield point, so we cannot use the interpreter frame space to store the enumerators.
- to fix this, we would always create an interpreter frame in the jit if the generator doesn't already have one
- Since the bail-in code relies on rax and rcx to do the reload, sometimes we would accidentally overwrite symbols reloaded before the jump table that might already be in those two registers. I made sure that we save/restore rax/rcx in the bail-in code if there are such symbols
// If the FunctionBody is a generator then this call is being made by one of the three
1510
-
// generator resuming methods: next(), throw(), or return(). They all pass the generator
1511
-
// object as the first of two arguments. The real user arguments are obtained from the
1512
-
// generator object. The second argument is the ResumeYieldData which is only needed
1513
-
// when resuming a generator and not needed when yielding from a generator, as is occurring
1514
-
// here.
1529
+
// generator resuming methods: next(), throw(), or return(). They all pass the generator
1530
+
// object as the first of two arguments. The real user arguments are obtained from the
1531
+
// generator object. The second argument is the ResumeYieldData which is only needed when
1532
+
// resuming a generator and not needed when yielding from a generator, as is occurring here.
1515
1533
AssertMsg(args.Info.Count == 2, "Generator ScriptFunctions should only be invoked by generator APIs with the pair of arguments they pass in -- the generator object and a ResumeYieldData pointer");
DWORD_PTR stackAddr = reinterpret_cast<DWORD_PTR>(&generator); // as mentioned above, use any stack address from this frame to ensure correct debugging functionality
0 commit comments