Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upExecution Context Stack. Violation of the LIFO order using Generator Function #1089
Comments
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
smellyshovel
Feb 2, 2018
Morover I couldn't have been able to find any mentions of this in the 25.3.3 section of the specification.
As I said earlier, I don't see any obvious LIFO order violations there.
For instance 4.c in the 25.3.3.1 just removes genContext from the stack, then 8 in the 25.3.3.3 pushes newly-created one onto the stack and the 10 of the 25.3.3.3 also just removes genContext from the stack (says that is already removed, to be precise).
I would be very grateful if you would honor me and explain what is happening in simple words. These are very basic things for you, but too complicated stuff for me. Anyway, thank you for your time.
smellyshovel
commented
Feb 2, 2018
•
As I said earlier, I don't see any obvious LIFO order violations there. I would be very grateful if you would honor me and explain what is happening in simple words. These are very basic things for you, but too complicated stuff for me. Anyway, thank you for your time. |
littledan
added
the
question
label
Feb 4, 2018
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
littledan
Feb 4, 2018
Member
When you yield from a generator, and call .next() to get back into a generator, the transfer of control flow is more like "swapping to a different stack" than the typical LIFO from ordinary function calls.
|
When you yield from a generator, and call |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
smellyshovel
Feb 4, 2018
@littledan sorry, don't understand what "swapping to a different stack" means.
When the control transfers to a generator first, the new EC is created. Then, when the control transfers back to the place where the generator was invoked (due to the yield statement), created EC is removed from the stack. Then the generator is invoked again (by the .next method), and the new EC is created again. And so on...
I don't quite understand what does LIFO violation means in terms of the specification. Is it like manipulating the ECs below the running EC, or does it mean that the running EC becomes not the top element of the stack? Maybe generator functions don't remove the running execution context from the stack after they done their work? Maybe they just kinda suspend it and the running EC after that is the EC that initiated the creation of the new one (in which the generator was invoked)?
smellyshovel
commented
Feb 4, 2018
|
@littledan sorry, don't understand what "swapping to a different stack" means. When the control transfers to a generator first, the new EC is created. Then, when the control transfers back to the place where the generator was invoked (due to the yield statement), created EC is removed from the stack. Then the generator is invoked again (by the I don't quite understand what does LIFO violation means in terms of the specification. Is it like manipulating the ECs below the running EC, or does it mean that the running EC becomes not the top element of the stack? Maybe generator functions don't remove the running execution context from the stack after they done their work? Maybe they just kinda suspend it and the running EC after that is the EC that initiated the creation of the new one (in which the generator was invoked)? |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
littledan
Feb 4, 2018
Member
Here's a good introduction I found to coroutines and how they work in terms of switching stacks: http://www.boost.org/doc/libs/1_53_0/libs/coroutine/doc/html/coroutine/intro.html . JavaScript generators are just like coroutines: yield switches to the caller, and next() switches back into the callee.
|
Here's a good introduction I found to coroutines and how they work in terms of switching stacks: http://www.boost.org/doc/libs/1_53_0/libs/coroutine/doc/html/coroutine/intro.html . JavaScript generators are just like coroutines: |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
smellyshovel
Feb 4, 2018
JavaScript generators are just like coroutines: yield switches to the caller, and next() switches back into the callee.
Do I understand correct that it means that the generator's EC doesn't get removed after the yield switches back to the caller context? Like
EC(global) - Running Execution Context (REC)
-> calling the generator
EC(gen1) - REC
EC(global)
-> yielding back to caller
EC(gen) - but why then the REC is not the top element in the stack?
EC(global) - *REC*
-> .next()
EC(gen2) - REC
EC(global)
-> completely terminating the generator
EC(global) - REC
Or does it mean that the generator's context gets saved somewhere else and not in the same Execution Context Stack? But, again, in this case I don't see any violation of the LIFO order of the real one stack. Damn, I feel dumb
smellyshovel
commented
Feb 4, 2018
Do I understand correct that it means that the generator's EC doesn't get removed after the
Or does it mean that the generator's context gets saved somewhere else and not in the same Execution Context Stack? But, again, in this case I don't see any violation of the LIFO order of the real one stack. Damn, I feel dumb |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
allenwb
Feb 4, 2018
Member
Let's just settle this . I originally wrote that sentence and this is what I meant:
In a conventional "call stack" the current activation records (aka "active Execution Contexts") is on the top of the stack. A new activation is pushed onto the stack when a call occurs, and the stack is popped when the procedure invocation represented by the current activation record returns or otherwise permanently terminates its execution. Popped activation records are discarded. This is behavior is what I meant by "stack-like last-in/first-out manner".
With generators, an operation (typically yield) causes an activation record to suspend execution and be removed from the call stack before before its associated procedure has terminated execution. The removed activation record is saved and execution continues using the activation record that was below it on the stack. At some latter point, an operation (typically the next method) causes a saved activation to be pushed again onto the call stack and its execution resumes at the point where it was suspended. This what I meant by a "non-LIFO" transition.
The call stack, by definition is a LIFO data-structure and usually the creation and destruction of activation record tracks that pushes and pops of the call stack. But generators require that in some cases activation records do not strictly track those LIFO stack operations.
|
Let's just settle this . I originally wrote that sentence and this is what I meant: In a conventional "call stack" the current activation records (aka "active Execution Contexts") is on the top of the stack. A new activation is pushed onto the stack when a call occurs, and the stack is popped when the procedure invocation represented by the current activation record returns or otherwise permanently terminates its execution. Popped activation records are discarded. This is behavior is what I meant by "stack-like last-in/first-out manner". With generators, an operation (typically yield) causes an activation record to suspend execution and be removed from the call stack before before its associated procedure has terminated execution. The removed activation record is saved and execution continues using the activation record that was below it on the stack. At some latter point, an operation (typically the next method) causes a saved activation to be pushed again onto the call stack and its execution resumes at the point where it was suspended. This what I meant by a "non-LIFO" transition. The call stack, by definition is a LIFO data-structure and usually the creation and destruction of activation record tracks that pushes and pops of the call stack. But generators require that in some cases activation records do not strictly track those LIFO stack operations. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
smellyshovel
Feb 4, 2018
@allenwb alright, now it seems like I completely got it. A huge thanks to all of you, guys!
smellyshovel
commented
Feb 4, 2018
|
@allenwb alright, now it seems like I completely got it. A huge thanks to all of you, guys! |
smellyshovel commentedFeb 2, 2018
The specifications says that the LIFO order of the Running Execution Context transitions in the Execution Context Stack may be violated by some ECMAScript featues:
However the specification doesn't explicitly tell by which exactly.
I've read that the violation may occure when using the Generator Functions. But I absolutely don't understand why. Morover I couldn't have been able to find any mentions of this in the 25.3.3 section of the specification.
As far as I understand the lifecycle of the Execution Context Stack in the exmple above may look as follows:
So I don't see any LIFO violations here.
Maybe Generator Functions don't even lead to such violation? Or, maybe, I misread the specification. Anyways, could you please explain what's going on with the Execution Context Stack when using generators? And how (and why) does LIFO order of the Running Execution Context transitions violates?