-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Clarify Running Execution context and the impact of push/pop and suspend/resume #2409
Comments
The running execution context (REC) is just whatever context is top-of-stack. "Suspend" isn't defined, but it's pretty clear that it doesn't manipulate the stack (since that always has to be done separately). So I'd say theoretically yes, if you Suspend the top-of-stack, it's still the REC. However, 'in practice', it only stays that way for a step or two before it's no longer top-of-stack, during which time there aren't any references to the REC, so the answer currently doesn't make a difference normatively.
Nope. Stack manipulation always happens explicitly (I think). "Suspend" (whatever it means) is separate, though it typically precedes a Push or Pop. (The cases where it doesn't might be bugs, it's hard to say.) My guess is that the intent was that a Suspend would only affect a context's 'code evaluation state', but it's a grey area.
I don't think there actually are any "non-LIFO transitions", i.e. cases where the last context to become REC isn't the first one to stop being REC. Generators and Async do interesting things with contexts, but I don't think any of them violate the LIFO-ness of REC transitions. (I.e., the execution context stack really is a stack.)
See also issue #2400, which gets into Suspend+Resume and Push+Pop. @bakkot certainly has ideas in this area. |
See also the discussion on esdiscuss which prompted #2400. For posterity I should also link logs from IRC where jmdyck and I were talking this over: May 3, May 4, and May 5.
I'd like to do this, but it requires working through a bit of confusion: there are a couple of places (in particular AsyncGeneratorYield and PrepareForTailCall) where an execution context is popped but the now-topmost context is not immediately resumed. (This can lead to some very weird behavior.) Getting in to the weeds a bit: I suspect AsyncGeneratorYield can be rewritten to avoid this, but it would have normative implications for the realm of the iterator result object. However, engines are wildly inconsistent about those anyway, so we can almost certainly get away with normative changes of that sort if the rewrite otherwise makes sense. (Edit: I did this in #2413. I managed to keep it editorial by more explicitly managing the realm for creating the iterator result object.) |
In preparing top level await, something I thought was resolved kept nagging me and I have been trying to get further input.
Specifically, in the top level await specification, we are suspending the running context for both the sync and async modules. In the case of async, that suspended module is still at the top of the stack:
Module suspension: https://github.com/tc39/proposal-top-level-await/blob/main/spec.html#L1208
Reference to running context in the asyncBlockStart: https://github.com/tc39/proposal-top-level-await/blob/main/spec.html#L52
The question is, if the top module on the stack is suspended is it still the running context? If it is still the running context, we should clarify this here: https://tc39.es/ecma262/#running-execution-context -- my expectation that, when we suspend, that the running context will be the next one on the stack, but what does suspend really mean? according to this: https://tc39.es/ecma262/#sec-execution-contexts, running context is always at the top of the stack. I am also wondering if we really need this step, or if pushing a new context for the module is enough in the sync case.
On the other hand, if a suspended module is not the running context (that is, suspending somehow removes it) then we have a bug in the spec code, as we will end up asserting that we are pointing to the wrong one here: https://github.com/tc39/proposal-top-level-await/blob/main/spec.html#L67
In any case, a clarification of push/pop and suspend/resume would help, especially if suspending/resuming is in terms of push/pop. Does suspending mean, save the context, remove it from the stack, and return it when resuming? This seems to be hinted at by:
The confusion is brought back by the "non-LIFO" part -- is suspend/resume explicitly for non-lifo contexts? If so, what happens when it participates in a LIFO situation like the one above? If a context is suspended, a new context is pushed then popped, is the prior context that is suspended immediately resume?
Or, perhaps better, to update and no longer use suspend/resume -- rather only say that we are pushing or popping.
The text was updated successfully, but these errors were encountered: