Implement async functions using generators (#2821)
This should hopefully fix more async/futures issues related to resuming execution in the future, since we can leverage generator logic to handle this for us.
It changes the following:
- Refactors `GeneratorContext` to handle context preparation.
- Reuses the functionality of `GeneratorContext` in `Await`.
- Removes `EarlyReturnType` in favour of a single `r#await` bool flag in `CallFrame`.
// 7. Resume the suspended evaluation of genContext using completion as the result of the operation that suspended it. Let result be the Completion Record returned by the resumed computation.
// 7. Resume the suspended evaluation of genContext using completion as the result of the operation that suspended it. Let result be the Completion Record returned by the resumed computation.
generator_context.call_frame=context.vm.pop_frame().expect("generator frame must exist");
std::mem::swap(
&mutcontext.vm.active_function,
&mutgenerator_context.active_function,
);
context.enter_realm(old_realm);
generator
generator
.borrow_mut()
.borrow_mut()
@ -543,7 +516,8 @@ impl AsyncGenerator {
// 8. Assert: result is never an abrupt completion.
// 8. Assert: result is never an abrupt completion.
assert!(!result.is_throw_completion());
assert!(!result.is_throw_completion());
// 9. Assert: When we return here, genContext has already been removed from the execution context stack and callerContext is the currently running execution context.
// 9. Assert: When we return here, genContext has already been removed from the execution context stack and
// callerContext is the currently running execution context.
// 8. Push genContext onto the execution context stack; genContext is now the running execution context.
// 8. Push genContext onto the execution context stack; genContext is now the running execution context.
// 9. Resume the suspended evaluation of genContext using NormalCompletion(value) as the result of the operation that suspended it. Let result be the value returned by the resumed computation.
// 9. Resume the suspended evaluation of genContext using NormalCompletion(value) as the result of the operation that suspended it. Let result be the value returned by the resumed computation.
// 10. Assert: When we return here, genContext has already been removed from the execution context stack and methodContext is the currently running execution context.
// 10. Assert: When we return here, genContext has already been removed from the execution context stack and methodContext is the currently running execution context.
// a. Let prevContext be the running execution context.
// a. Let prevContext be the running execution context.
// b. Suspend prevContext.
// b. Suspend prevContext.
// c. Push asyncContext onto the execution context stack; asyncContext is now the running execution context.
// c. Push asyncContext onto the execution context stack; asyncContext is now the running execution context.
// d. Resume the suspended evaluation of asyncContext using NormalCompletion(value) as the result of the operation that suspended it.
// d. Resume the suspended evaluation of asyncContext using NormalCompletion(value) as the result of the operation that suspended it.
// e. Assert: When we reach this step, asyncContext has already been removed from the execution context stack and prevContext is the currently running execution context.
letmutgen=captures.borrow_mut().take().expect("should only run once");
// e. Assert: When we reach this step, asyncContext has already been removed from the execution context stack and prevContext is the currently running execution context.
// a. Let prevContext be the running execution context.
// a. Let prevContext be the running execution context.
// b. Suspend prevContext.
// b. Suspend prevContext.
// c. Push asyncContext onto the execution context stack; asyncContext is now the running execution context.
// c. Push asyncContext onto the execution context stack; asyncContext is now the running execution context.
@ -111,40 +74,17 @@ impl Operation for Await {
// e. Assert: When we reach this step, asyncContext has already been removed from the execution context stack and prevContext is the currently running execution context.
// e. Assert: When we reach this step, asyncContext has already been removed from the execution context stack and prevContext is the currently running execution context.
// f. Return undefined.
// f. Return undefined.
std::mem::swap(
letmutgen=captures.borrow_mut().take().expect("should only run once");