I wanted to understand the internal mechanisms of a JavaScript engine for asynchronous functions, so I checked the Spec. For the rest of this question, I will refer to the linked version of the specification.
Section 6.2.3.1 describes this. Basically, a promise is created which is resolved to the expression that is awaited. The promise is then added resolving handlers via .then; The fulfillment handler is a function object created from an abstract closure which captures asyncContext which is the execution context associated to the asynchronous function. This abstract closure suspends the running execution context and restores asyncContext as the running execution context.
The thing I don't understand is: when this abstract closure gets called, isn't the execution context associated with itself the running execution context? Wouldn't this abstract closure suspend itself then? I believe so because .then [27.2.5.4.1 PerformPromiseThen] creates jobs via 27.2.2.1 NewPromiseReactionJob which creates an abstract closure that uses 9.5.3 HostCallJobCallback to call the handler which in turn must perform 7.3.14 Call on it, leading to an invocation of the [[Call]] internal method of the function object (10.2.1). This pushes a new execution context on the stack.
What am I misunderstanding? What does prevContext actually refer to in 6.2.3.1?
Your problem might be the idea that there's an execution context "associated with" the abstract closure. The spec is a bit cagey on this point, but I think it's easier to understand examples like yours if you imagine spec algorithms (including abstract closures) as running "outside" any execution context. This then allows spec algorithms to suspend/resume/push/pop execution contexts without any effect on the running of those algorithms.