# execution context suspension and resumption

**URL:** <https://es.discourse.group/t/execution-context-suspension-and-resumption/756>\
**Category:** Spec Reading\
**Created:** [April 28, 2021, 8:25pm UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756 "2021-04-28T20:25:07Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Adamk93](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/adamk93/32/795_2.png) [@Adamk93](https://es.discourse.group/u/Adamk93)\
**Post date:** [April 28, 2021, 8:25pm UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/1 "2021-04-28T20:25:07Z")

</div>

Hello and thanks in advance for your help.  
So, I am writing an executable semantics of ES2021. For a bit of context, this formalization aims to be a formal copy of the specification. We have decided to take almost no implementation choices. Exceptions are the data structures for the state, and all its components(Objects, ExecutionContexts, EnvironmentRecords, etc..). By the way, now I am working on function expressions and function calls.  
A practical example is:

```javascript
 let id = function (v) {return v;};
 id("ciao")

```

The example is trivial, but its interpretation is not.  
My problems start in FunctionDeclarationInstantiation and precisely in steps 24,25 and 26.

Let's start with step 24 and the [createListIteratorRecord](https://tc39.es/ecma262/2021/#sec-createlistiteratorRecord) method call with the list ["ciao"], corresponding  
to the arguments list. At this point, we are still in the callee execution context created by the ordinary function [[Call]]. Here basically we create a GeneratorObject and the return is an iterator record, with the generator object as iterator and %Generator.prototype.next% as next method.

_ **Question 1:** _  
_**After creating this object, we perform [GeneratorStart](https://tc39.es/ecma262/2021/#sec-generatorstart). Step 4 of GeneratorStart defines a closure to assign to the callee execution context. Does this imply that the execution context is suspended in that step?**_

However, once we return the iterator record and so the control flow to FunctionDeclarationInstantiation,  
it is time to bind the names in the context to a value. Indeed, steps 25 and 26 deal with this, depending on the presence of duplicated names.  
[IteratorBindingInitialization](https://tc39.es/ecma262/2021/#sec-runtime-semantics-iteratorbindinginitialization) deals with it. And here I have problems(We consider the syntactic production that matches with SingleNameBinding). This method takes a parse node, an iterator record, and - in the example case - an environment, and returns an updated state, in which the environment is updated with the bindings for each of the names that live within the context of the called function.

Morally, what makes things awkward is the IteratorStep call! At a certain point, through IteratorNext, we call [%Generator.prototype.next%](https://tc39.es/ecma262/2021/#sec-generator.prototype.next)using the Built-In Function [[Call]. At this point, a new context is created and pushed into the stack. The callee context was already suspended by GeneratorStart. Then, the algorithmic steps of _%Generator.prototype.next%_ are executed. This method calls GeneratorResume with this value(the generator object created in CreateListIteratorRecord, and a value, that happens to be the aforementioned object.  
This method, after some steps, suspends the running execution context(The new one created by the built-in function [[Call]]), pushes into the stack the callee context(We have a context duplication in the stack), and then it is resumed. Its resumption executes the closure defined in step 4 of GeneratorStart.  
In the first steps of the resumption closure, another closure is executed, The one defined in CreateListIteratorRecord. [Yield](https://tc39.es/ecma262/2021/#sec-yield) is executed for each of the arguments list.

_ **Question 2:** _  
_ **The definition of Suspension and resumption is not defined precisely. Indeed, here things break, and I am quite sure that it is not an implementation dependant error. As a reminder, we are visually close to the specification, so it is difficult to make mistakes. We have a doubt, that can maybe solve our dilemmas. Basically, the Yield loop is executed all at once, regardless of the context suspensions/resumptions.** _  
_ **We then return the result and the control to the abstract closure in GeneratorStart.** _

_**- Does a suspension imply implicitly a sort of continuation(CPS)?**_  
_ **- In case a closure is not given, does a resumption make the context resume in the same algorithmic step in which it was suspended? Or it simply changes its CodeEvaluationState?** _

Here things really break, because, at the top of the execution context stack, we get the wrong contexts at the top of the stack, and this makes the binding initialization break.

I think that a nice proposal is to detail more what happens in context switches.

Thanks in advance!

P.S. I tried to detail as much as possible, but a lot of things are left out. If not, the thread would have been really confusing.

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [April 28, 2021, 8:49pm UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/2 "2021-04-28T20:49:55Z")

</div>

did you mean `function* (v) {return v;}`, so it's a generator?

---

<div class="post-metadata">

**Author:** ![jmdyck](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jmdyck/32/796_2.png) [@jmdyck](https://es.discourse.group/u/jmdyck)\
**Post date:** [April 29, 2021, 3:10am UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/3 "2021-04-29T03:10:29Z")

</div>

@ljharb: I believe the `GeneratorStart` referred to is not the one in `EvaluateGeneratorBody`, but the one in `CreateIteratorFromClosure`, which is called from `CreateListIteratorRecord`, which is called from `FunctionDeclarationInstantiation`.

---

<div class="post-metadata">

**Author:** ![bakkot](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bakkot/32/22_2.png) [@bakkot](https://es.discourse.group/u/bakkot)\
**Post date:** [April 29, 2021, 5:16am UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/4 "2021-04-29T05:16:05Z")

</div>

Let me do my best to answer here. I'm not totally confident in this.

> _**After creating this object, we perform [GeneratorStart](https://tc39.es/ecma262/2021/#sec-generatorstart). Step 4 of GeneratorStart defines a closure to assign to the callee execution context. Does this imply that the execution context is suspended in that step?**_

I believe the idea is that execution contexts are suspended whenever they are removed from execution context stack. It would probably be best to be explicit about this.

I don't think GeneratorStart should be understood to suspend the execution of the running execution context. Rather, it is implicitly suspended when it is removed from the execution context stack. With a syntactic generator (as opposed to one created by CreateIteratorFromClosure), the execution context in question would be the one created in step 3 of [[[Call]] on ordinary function objects](https://tc39.es/ecma262/multipage/#sec-ecmascript-function-objects-call-thisargument-argumentslist), which is removed immediately after the call to GeneratorStart: step 7 of [[Call]]: OrdinaryCallEvaluateBody calls EvaluateBody calls EvaluateGeneratorBody, the last nontrivial step of which is GeneratorStart; step 8 of [[Call]] pops the execution context stack. So it should be understood to be suspended at that point.

That said, there are places where we explicitly suspend execution contexts before removing them from the stack. If my interpretation is correct, we should change the spec to be consistent here, and consistently suspend execution contexts before removing them.

> Morally, what makes things awkward is the IteratorStep call! At a certain point, through IteratorNext, we call [%Generator.prototype.next%](https://tc39.es/ecma262/2021/#sec-generator.prototype.next)using the Built-In Function [[Call]. At this point, a new context is created and pushed into the stack. The callee context was already suspended by GeneratorStart.

I believe this is a bug in CreateIteratorFromClosure, which was introduced in PR 2045. Specifically, I believe it needs to push a new execution context to the execution context stack before calling GeneratorStart, and pop it after.

I've submitted a [pull request](https://github.com/tc39/ecma262/pull/2398) implementing this fix.

> Basically, the Yield loop is executed all at once, regardless of the context suspensions/resumptions.

I'm not sure what this means.

> Does a suspension imply implicitly a sort of continuation(CPS)?

Yes.

> _ **In case a closure is not given, does a resumption make the context resume in the same algorithmic step in which it was suspended? Or it simply changes its CodeEvaluationState?** _

Do you have an example in mind where this comes up? My understanding is that it resumes at the point it says to resume: so when an algorithm step says "Resume _context_", and _context_ has not explicitly had its code evaluation state set, it means that execution proceeds at the "Resume _context_" step.

---

<div class="post-metadata">

**Author:** ![AlanSchmitt](https://avatars.discourse-cdn.com/v4/letter/a/9fc29f/32.png) [@AlanSchmitt](https://es.discourse.group/u/AlanSchmitt)\
**Post date:** [April 29, 2021, 6:56am UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/5 "2021-04-29T06:56:00Z")

</div>

I think one part of the confusion comes from the lack of distinction between code and meta-code. Code is typically the JavaScript that is being executed, while meta-code is an algorithmic description of how to execute it (i.e., the spec). Code can be manipulated, interrupted, and resumed, whereas meta-code cannot (at least I hope so, otherwise we’ll need meta-meda-code to handle it).

The part that is troubling in when code is written in spec style. For instance, the abstract closure created as part of step 1 of [CreateListIteratorRecord](https://tc39.es/ecma262/#sec-createlistiteratorRecord) should be code, as it uses `yield`, hence one should be able to interrupt its execution.

Things are less clear for the steps created in step 4 of [GeneratorStart](https://tc39.es/ecma262/#sec-generatorstart). As steps 4.a or 4.b can evaluate things that call `yield`, the whole series of steps may be suspended. Is this code or meta-code?

Finally, what is the status of built-in methods? For instance `%GeneratorFunction.prototype.prototype.next%` is defined to be `[[NextMethod]]` of the object returned by [CreateListIteratorRecord](https://tc39.es/ecma262/#sec-createlistiteratorRecord), which is called (as a code function) from [IteratorNext](https://tc39.es/ecma262/#sec-iteratornext). Can it be interrupted?

To sum up, as our formalization is purely functional, we need to distinguish between code (which is plain data for us) from meta-code (which we implement as an interpreter). Does this distinction makes sense at the spec level?

---

<div class="post-metadata">

**Author:** ![Adamk93](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/adamk93/32/795_2.png) [@Adamk93](https://es.discourse.group/u/Adamk93)\
**Post date:** [April 29, 2021, 9:22am UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/6 "2021-04-29T09:22:02Z")

</div>

Thanks for the answer!

> [@bakkot](#):
>
> I believe the idea is that execution contexts are suspended whenever they are removed from execution context stack. It would probably be best to be explicit about this.

So, what happens when a context is only explicitly suspended? It does stay at the top of the stack, right?  
i.e. Step 6 of GeneratorResume.

It's true that after step 6 we add GenContext to the stack and resume it. Indeed, after step 9, the execution context has changed again, because of what the abstract closure did, right. So basically, when MethodContext is resumed, the computation continues sequentially from the point in which it was resumed? Having no resumption abstract closure assigned to this context, the code just continues to execute in a new state in which MethodContext is resumed and it's at the top of the stack.

> [@bakkot](#):
>
> > Basically, the Yield loop is executed all at once, regardless of the context suspensions/resumptions.
> 
> I'm not sure what this means.

Oh yes, here I was not that clear. Indeed, when we call generatorBody() in step 4b of the closure defined in GeneratorStart, we execute the piece of code defined in step 1 of CreateListIteratorRecord.  
Imagine we have a non-trivial list, so one that has more than one element. What I meant for executed all at once is that, when we call Yield, there is a call to GeneratorYield. GeneratorYield manipulates the stack, and at the end, the MethodContext is again at the top of the stack. is there any manipulation of the control flow or we just get back to the loop that has called Yield, and do another iteration, if it is not finished?

This is the part in where Alan and I thought that a possible explanation for having a weird resulting context stack is that implicitly the code resumes somewhere else, and the loop is not executed sequentially.

> [@bakkot](#):
>
> My understanding is that it resumes at the point it says to resume: so when an algorithm step says "Resume _context_", and _context_ has not explicitly had its code evaluation state set, it means that execution proceeds at the "Resume _context_" step.

But I guess that your last answer satisfies my doubt, and in that case the is no continuation. The control flow just continues sequentially, right?

Another peculiar thing is that, before the step 4.d. of the GeneratorStart closure, the execution stack is:  
[MethodContext;GenContext; whatever..].  
After performing 4.d. the stack is [GenContext; ...]. and actually, that's is due to a repetition of GenContext in the stack, and a missing push/pop somewhere. Actually, after 4.d. I would have expected to have a stack with MethodContext at the top, ready to be removed once we return the control to the built-in function [[Call]].

@AlanSchmitt post integrates my original post

---

<div class="post-metadata">

**Author:** ![AlanSchmitt](https://avatars.discourse-cdn.com/v4/letter/a/9fc29f/32.png) [@AlanSchmitt](https://es.discourse.group/u/AlanSchmitt)\
**Post date:** [April 29, 2021, 12:56pm UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/7 "2021-04-29T12:56:51Z")

</div>

To make things more precise, I would like to propose a concrete example.

Assume we are running step 1.a.i of [CreateListIteratorRecord](https://tc39.es/ecma262/#sec-createlistiteratorRecord). It calls [Yield](https://tc39.es/ecma262/#sec-yield), which calls [GeneratorYield](https://tc39.es/ecma262/#sec-generatoryield) that removes in step 7 the current execution context. What I’m trying to understand is the point where we switch from interpreted code (which I assume to be the list of calls to `Yield`) to interpreter execution (which is not associated to any execution context and cannot be suspended).

One way to clarify this is to say that step 1 of `CreateListIteratorRecord` creates a _concrete representation_ of steps to be interpreted (and not an abstract closure). Then [CreateIteratorFromClosure](https://tc39.es/ecma262/#sec-createiteratorfromclosure) takes as argument such a concrete list of steps, and [GeneratorStart](https://tc39.es/ecma262/#sec-generatorstart) says to _interpret_ this list of steps in 4.b.ii. Interpreting means considering the first step, changing the state of the execution context to store the remaining steps, and calling the corresponding specification abstract algorithm.

---

<div class="post-metadata">

**Author:** ![jmdyck](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jmdyck/32/796_2.png) [@jmdyck](https://es.discourse.group/u/jmdyck)\
**Post date:** [April 29, 2021, 2:10pm UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/8 "2021-04-29T14:10:19Z")

</div>

> [AlanSchmitt] AlanSchmitt [https://es.discourse.group/u/alanschmitt](https://es.discourse.group/u/alanschmitt)  
> April 29
> 
> I think one part of the confusion comes from the lack of distinction between  
> code and meta-code. Code is typically the JavaScript that is being executed,  
> while meta-code is an algorithmic description of how to execute it (i.e.,  
> the spec).

I think there's a good distinction. Anything algorithmic in the spec that  
_isn't_ clearly an example of ECMAScript code (in monospace font) is  
'meta-code' (which we generally call 'pseudo-code'). The JavaScript that is  
being executed is represented as parse trees (resulting from invocations of  
ParseText).

You may wish to distinguish between abstract operations (or bits of  
pseudo-code) that can be suspended/resumed, and those that can't. Currently,  
the spec doesn't help you much with making that distinction, but it's  
conceivably a piece of metadata that could be attached to each abstract  
operation in the future. But note that that distinction is _not_ the  
distinction between JavaScript code and an algorithmic description of how to  
execute it. (At least, not in the spec's world.)

> Code can be manipulated, interrupted, and resumed, whereas  
> meta-code cannot (at least I hope so, otherwise we’ll need meta-meda-code to  
> handle it).

Meta-code can indeed be suspended and resumed.

> The part that is troubling in when code is written in spec style. For  
> instance, the abstract closure created as part of step 1 of  
> CreateListIteratorRecord  
> [https://tc39.es/ecma262/#sec-createlistiteratorRecord](https://tc39.es/ecma262/#sec-createlistiteratorRecord) should be code, as  
> it uses |yield|, hence one should be able to interrupt its execution.

It uses `Yield` (note the capital `Y`), which is an abstract operation, and  
not the ECMAScript `yield` keyword. And Abstract Closures are definitely  
'meta' structures.

> Things are less clear for the steps created in step 4 of GeneratorStart  
> [https://tc39.es/ecma262/#sec-generatorstart](https://tc39.es/ecma262/#sec-generatorstart). As steps 4.a or 4.b can  
> evaluate things that call |yield|, the whole series of steps may be  
> suspended. Is this code or meta-code?

It's meta-code. The fact that 4.a.i can (at some point) evaluate a  
YieldExpression doesn't change that.

> Finally, what is the status of built-in methods? For instance
> 
> > %GeneratorFunction.prototype.prototype.next%| is defined to be  
> > [[NextMethod]]| of the object

(Record, not object)

> returned by CreateListIteratorRecord, which is called (as  
> a code function) from IteratorNext.

`IteratorNext` invokes the `Call` abstract operation, passing it the value  
of some iterator record's `[[NextMethod]]` field. When that value is  
`%GeneratorFunction.prototype.prototype.next%`, that results in the  
invocation of that built-in function's `[[Call]]` internal method.

Implementations are allowed to implement the `next` function via ECMAScript  
code, but they're not obliged to. So there isn't necessarily something being  
called "as a code function" here.

> Can it be interrupted?

When you invoke the `next` function's `[[Call]]` internal method, it will  
invoke the `GeneratorResume` abstract op, which will typically cause a  
suspension of the current execution context and the resumption of another.  
(I would hesitate to call this "interrupted".)

> To sum up, as our formalization is purely functional, we need to distinguish  
> between code (which is plain data for us) from meta-code (which we implement  
> as an interpreter). Does this distinction makes sense at the spec level?

I'd say that distinction as stated makes sense to the spec. However, it  
sounds like you have additional ideas about that distinction that may not  
fit well with how the spec sees it.

-Michael

---

<div class="post-metadata">

**Author:** ![bakkot](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bakkot/32/22_2.png) [@bakkot](https://es.discourse.group/u/bakkot)\
**Post date:** [April 29, 2021, 5:22pm UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/9 "2021-04-29T17:22:20Z")

</div>

> [@Adamk93](#):
>
> So, what happens when a context is only explicitly suspended? It does stay at the top of the stack, right?

Yes, although I think this is a distinction without a difference: as far as I am aware, every time the spec suspends an execution context, it immediately thereafter causes said context to not be at the top of the stack, either by popping the newly suspended context or by pushing a new context on top of it.

> [@Adamk93](#):
>
> So basically, when MethodContext is resumed, the computation continues sequentially from the point in which it was resumed?

Right.

> [@Adamk93](#):
>
> This is the part in where Alan and I thought that a possible explanation for having a weird resulting context stack is that implicitly the code resumes somewhere else, and the loop is not executed sequentially.

Oh, yeah, like I said I think the weird execution context stack resulting from CreateIteratorFromClosure is just a bug. If you use the definition for CreateIteratorFromClosure given in [this PR](https://github.com/tc39/ecma262/pull/2398), does it make sense?

> [@Adamk93](#):
>
> Actually, after 4.d. I would have expected to have a stack with MethodContext at the top, ready to be removed once we return the control to the built-in function [[Call]].

Right, I think that's the same bug as above.

---

<div class="post-metadata">

**Author:** ![AlanSchmitt](https://avatars.discourse-cdn.com/v4/letter/a/9fc29f/32.png) [@AlanSchmitt](https://es.discourse.group/u/AlanSchmitt)\
**Post date:** [April 30, 2021, 7:45am UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/10 "2021-04-30T07:45:21Z")

</div>

Thank you Michael for these clarification. From an implementation point of view, it seems that abstract algorithms that can be suspended and abstract algorithms that cannot be suspended are quite different and need to be implemented differently.

For instance, I’m curious to see how [CreateListIteratorRecord](https://tc39.es/ecma262/#sec-createlistiteratorRecord) is implemented, as step 1.a.i can be suspended, but I suspect step 3 cannot.

---

<div class="post-metadata">

**Author:** ![jmdyck](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jmdyck/32/796_2.png) [@jmdyck](https://es.discourse.group/u/jmdyck)\
**Post date:** [April 30, 2021, 12:46pm UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/11 "2021-04-30T12:46:06Z")

</div>

> [AlanSchmitt] AlanSchmitt
> 
> From an implementation point of view, it seems that abstract algorithms  
> that can be suspended and abstract algorithms that cannot be suspended  
> are quite different and need to be implemented differently.

I imagine that would depend on the language of your implementation.

> For instance, I’m curious to see how CreateListIteratorRecord is  
> implemented,

Well, there's certainly no shortage of implementations whose source you can  
examine. But note that the specification of CreateListIteratorRecord (and a  
bunch of other operations) changed ~4 months ago when PR #2045 was merged,  
so most implementations (if they have an identifiable  
`CreateListIteratorRecord` chunk) will be based on the older form. For  
instance, that's the case with engine262, which follows the spec pretty closely:

> <https://github.com/engine262/engine262/blob/6094f3b3749fd608b899c7e3a1821e4d0b346bae/src/abstract-ops/iterator-operations.mjs#L190>

> as step 1.a.i can be suspended, but I suspect step 3 cannot.

Executing step 1.a.1 will lead to a suspension, yes, but note that step 1  
merely creates an Abstract Closure, doesn't execute it.

Step 3 doesn't invoke any other operations, so executing it can't involve a  
suspension.

So the execution of CreateListIteratorRecord itself will not be suspended,  
but it returns a Record that will likely be the cause of future suspensions.

-Michael

---

<div class="post-metadata">

**Author:** ![AlanSchmitt](https://avatars.discourse-cdn.com/v4/letter/a/9fc29f/32.png) [@AlanSchmitt](https://es.discourse.group/u/AlanSchmitt)\
**Post date:** [April 30, 2021, 1:23pm UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/12 "2021-04-30T13:23:50Z")

</div>

Thank you for the link to engine262, this will be most helpful. Unfortunately they implement code that can be suspended with asynchronous functions. Their [implementation of GeneratorStart](https://github.com/engine262/engine262/blob/6094f3b3749fd608b899c7e3a1821e4d0b346bae/src/abstract-ops/generator-operations.mjs#L20) is quite interesting, as it makes explicit the part of the code that is part of an execution context and the part that is not.

---

<div class="post-metadata">

**Author:** ![bakkot](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bakkot/32/22_2.png) [@bakkot](https://es.discourse.group/u/bakkot)\
**Post date:** [April 30, 2021, 7:53pm UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/13 "2021-04-30T19:53:07Z")

</div>

Thinking about this some more, I believe that every place the spec has a sequence of steps along the lines of

1. Let _oldCtx_ be the running execution context.
2. Let _ctx_ be a new execution context.
3. Push _ctx_ onto the execution context stack; _ctx_ is now the running execution context.
4. Do some stuff.
5. Remove _ctx_ from the execution context stack and restore _oldCtx_ as the running execution context.

you can think of it as being instead

1. Let _oldCtx_ be the running execution context.
2. Let _ctx_ be a new execution context.
3. Set the code evaluation state of _ctx_ such that when it becomes the running execution context the following steps will be performed:
  1. Do some stuff.
  2. Remove _ctx_ from the execution context stack and restore _oldCtx_ as the running execution context.

4. Push _ctx_ onto the execution context stack; _ctx_ is now the running execution context.
5. Assert: When we reach this step, _ctx_ has already been removed from the execution context stack and _oldCtx_ is the currently running execution context.

Generators differ from this only in that

- the push and corresponding pop of the execution context are not so closely linked as in the above (there is a push which happens in GeneratorResume and its corresponding pop is in GeneratorStart step 4.d or GeneratorYield step 7), and
- the code evaluation state is set some time previously to its becoming the running execution context (in particular, the code evaluation state of the relevant context is set in GeneratorStart or GeneratorYield, and it only becomes the running execution context when GeneratorResume is next called).

Edit: I guess there is another difference, which is that the execution contexts for generators can return values _to the thing which pushed them to the stack_. Specifically, step 9 of GeneratorResume has "Let result be the value returned by the resumed computation", which corresponds to the Returns in steps 4.i.ii and 4.j of GeneratorStart and step 9 of GeneratorYield. It would probably be best to rephrase these so they don't use "Return"; perhaps something like

"Remove genContext from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context **using NormalCompletion(iterNextObj) as the returned value**."

---

<div class="post-metadata">

**Author:** ![jmdyck](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jmdyck/32/796_2.png) [@jmdyck](https://es.discourse.group/u/jmdyck)\
**Post date:** [May 1, 2021, 3:51am UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/14 "2021-05-01T03:51:20Z")

</div>

> [bakkot]
> 
> 1. Set the code evaluation state of /ctx/ such that when it becomes the  
> running execution context the following steps will be performed:

The spec doesn't use that formulation though. It's always:  
... such that when evaluation is resumed [for that execution context] ...

I.e., simply pushing a context onto the stack doesn't trigger anything else; you have to explicitly "resume" such a context for it to start doing its stuff.

So I think this equivalence would be more in line with how the spec is currently written:

1. ...
2. ...
3. Set the code evaluation state of /ctx/ such that **when evaluation is resumed for that execution context** , the following steps will be performed:  
1. Do some stuff.  
2. Remove /ctx/ from the execution context stack and restore /oldCtx/ as the running execution context.
4. Push /ctx/ onto the execution context stack; /ctx/ is now the running execution context.
5. **Resume the evaluation of /ctx/**.
6. Assert: When we reach this step, /ctx/ has already been removed from the execution context stack and /oldCtx/ is the currently running execution context.

> Specifically, step 9 of GeneratorResume has "Let /result/ be the value returned by the resumed computation", which corresponds to the Returns in steps 4.i.ii and 4.j of GeneratorStart and step 9 of GeneratorYield. It would probably be best to rephrase these so they don't use "Return"; perhaps something like
> 
> "Remove genContext from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context _using NormalCompletion(iterNextObj) as the returned value_."

That would conflate a stack-pop with a transfer of control, which I don't think the spec currently does.

I can sort of see your point about not using the term "Return" in these steps, but I think just a different word would help.

---

<div class="post-metadata">

**Author:** ![bakkot](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bakkot/32/22_2.png) [@bakkot](https://es.discourse.group/u/bakkot)\
**Post date:** [May 1, 2021, 4:17am UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/15 "2021-05-01T04:17:03Z")

</div>

> That would conflate a stack-pop with a transfer of control, which I don't think the spec currently does.

It doesn't, but I think it would be clearer if it did; as far as I can tell there's no reason to separate the two.

Given that generators are implemented in a way which suggests that the execution context stack represents control, it is very strange that we manipulate what's on the execution context stack without transferring control. For example, I think without the NOTE which is step 10 of GeneratorYield it would not be at all clear what step 9 was supposed to do.

---

<div class="post-metadata">

**Author:** ![AlanSchmitt](https://avatars.discourse-cdn.com/v4/letter/a/9fc29f/32.png) [@AlanSchmitt](https://es.discourse.group/u/AlanSchmitt)\
**Post date:** [May 1, 2021, 8:49am UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/16 "2021-05-01T08:49:23Z")

</div>

> [@bakkot](#):
>
> Set the code evaluation state of _ctx_ such that when it becomes the running execution context the following steps will be performed:
> 
> 1. Do some stuff.
> 2. Remove _ctx_ from the execution context stack and restore _oldCtx_ as the running execution context.

I’m troubled by this because we would have an algorithmic step that is part of the code evaluation state of an execution context remove its own execution context.

---

<div class="post-metadata">

**Author:** ![bakkot](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bakkot/32/22_2.png) [@bakkot](https://es.discourse.group/u/bakkot)\
**Post date:** [May 1, 2021, 4:15pm UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/17 "2021-05-01T16:15:03Z")

</div>

As long as it's the last step, that seems fine to me. Necessary, even: there needs to be _some_ way of indicating that control should be transferred back to the previous execution context. It's just like `return` in any programming language: `return` is part of a function, and its effect is to complete execution of the function and remove it from the stack.

In any case, don't we already do this, for example in GeneratorYield step 7?

---

<div class="post-metadata">

**Author:** ![jmdyck](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jmdyck/32/796_2.png) [@jmdyck](https://es.discourse.group/u/jmdyck)\
**Post date:** [May 1, 2021, 8:03pm UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/18 "2021-05-01T20:03:39Z")

</div>

> [@bakkot](#):
>
> > That would conflate a stack-pop with a transfer of control, which I don't think the spec currently does.
> 
> It doesn't, but I think it would be clearer if it did; as far as I can tell there's no reason to separate the two.

So all the places in the spec where they **are** separated, those can be converted to the "conflated" model?

One possibility might be: in some cases, they have to be separated, but for others, we introduce an abstract operation that bundles them together. So for the most part, you can think of them as conflated.

> [@](#):
>
> Given that generators are implemented in a way which suggests that the execution context stack represents control, it is very strange that we manipulate what's on the execution context stack without transferring control.

If these two views are at odds, perhaps the strangeness goes the other way.

(Lately I've been wondering if having 'code evaluation state' as a component of execution contexts might be the problem.)

> [@](#):
>
> For example, I think without the NOTE which is step 10 of GeneratorYield it would not be at all clear what step 9 was supposed to do.

I agree that there's a problem with GeneratorYield; I've been working on an issue/PR about it.

---

<div class="post-metadata">

**Author:** ![bakkot](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bakkot/32/22_2.png) [@bakkot](https://es.discourse.group/u/bakkot)\
**Post date:** [May 1, 2021, 9:07pm UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/19 "2021-05-01T21:07:15Z")

</div>

> [@jmdyck](#):
>
> So all the places in the spec where they **are** separated, those can be converted to the "conflated" model?

Almost. I can't quite make it work for PrepareForTailCall, with the way things are wired up: you really want a tail call to _replace_ top of the execution context stack with the context of the new function, but the current logic is that a tail call does PrepareForTailCall which pops the stack, and then does F.[[Call]], and for ECMAScript functions and non-exotic built-in functions the implementation of [[Call]] pushes a new context as its first step.

(And it's not clear what to do with InitializeHostDefinedRealm, which is inherently weird.)

* * *

Sidebar:

There's an odd interaction with tail calls and Proxies: the [[Call]] slot for a Proxy will throw a TypeError if the Proxy has been revoked, and the above implies that if you tail-call a revoked Proxy the Realm for that TypeError should be that of the function which called the function which called the Proxy (since its execution context will be the top of the stack), which seems wrong.

Neither JSC nor engine262, the engines which implement tail calls I can most easily test, implements this behavior. [actually, turns out engine262 does not implement tail calls]

Edit: turns out there's tests for [a similar case](https://github.com/tc39/test262/blob/70bc32edab22b44db9d671ce505db8842ae200b6/test/language/expressions/call/tco-cross-realm-fun-call.js), though those tests recently [became incorrect](https://github.com/tc39/test262/issues/2978).

---

<div class="post-metadata">

**Author:** ![AlanSchmitt](https://avatars.discourse-cdn.com/v4/letter/a/9fc29f/32.png) [@AlanSchmitt](https://es.discourse.group/u/AlanSchmitt)\
**Post date:** [May 3, 2021, 7:37am UTC](https://es.discourse.group/t/execution-context-suspension-and-resumption/756/20 "2021-05-03T07:37:38Z")

</div>

> [@bakkot](#):
>
> In any case, don't we already do this, for example in GeneratorYield step 7?

I don’t think so, because this is interpreter code: I do not think these abstract steps would be associated to the code evaluation state of genContext.

(I’m sorry I’m struggling so much with terminology… I’m trying to find words that distinguish between steps associated to executions contexts and steps that are not.)

[Next page](https://es.discourse.group/t/execution-context-suspension-and-resumption/756.md?page=2)
