Bug 1379525 - Part 1: Await on the value before yielding or returning inside async generator. r=shu
☠☠ backed out by c45e30f75acd ☠ ☠
authorTooru Fujisawa <arai_a@mac.com>
Fri, 04 Aug 2017 13:04:31 +0900
changeset 422423 fce216e62ff79f2f10d7c2e5b3fd5003e14c8fa8
parent 422422 db753f92f801db490906be89211f135acdd6f79a
child 422424 f21fd8353ea9fb7da7d159fccc8cd91859ed8abc
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshu
bugs1379525
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1379525 - Part 1: Await on the value before yielding or returning inside async generator. r=shu
js/src/builtin/Promise.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/vm/AsyncIteration.cpp
js/src/vm/AsyncIteration.h
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -31,28 +31,40 @@ MillisecondsSinceStartup()
 {
     auto now = mozilla::TimeStamp::Now();
     return (now - mozilla::TimeStamp::ProcessCreation()).ToMilliseconds();
 }
 
 enum PromiseHandler {
     PromiseHandlerIdentity = 0,
     PromiseHandlerThrower,
-    PromiseHandlerAsyncFunctionAwaitFulfilled,
-    PromiseHandlerAsyncFunctionAwaitRejected,
-    PromiseHandlerAsyncGeneratorAwaitFulfilled,
-    PromiseHandlerAsyncGeneratorAwaitRejected,
-
-    // Async Iteration proposal 6.1.1.2.1.
-    // Async iterator handlers take the resolved value and create new iterator
-    // objects.  To do so it needs to forward whether the iterator is done. In
-    // spec, this is achieved via the [[Done]] internal slot. We enumerate both
-    // true and false cases here.
-    PromiseHandlerAsyncIteratorValueUnwrapDone,
-    PromiseHandlerAsyncIteratorValueUnwrapNotDone,
+
+    // ES 2018 draft 25.5.5.4-5.
+    PromiseHandlerAsyncFunctionAwaitedFulfilled,
+    PromiseHandlerAsyncFunctionAwaitedRejected,
+
+    // Async Iteration proposal 4.1.
+    PromiseHandlerAsyncGeneratorAwaitedFulfilled,
+    PromiseHandlerAsyncGeneratorAwaitedRejected,
+
+    // Async Iteration proposal 11.4.3.5.1-2.
+    PromiseHandlerAsyncGeneratorResumeNextReturnFulfilled,
+    PromiseHandlerAsyncGeneratorResumeNextReturnRejected,
+
+    // Async Iteration proposal 11.4.3.7 steps 8.c-e.
+    PromiseHandlerAsyncGeneratorYieldReturnAwaitedFulfilled,
+    PromiseHandlerAsyncGeneratorYieldReturnAwaitedRejected,
+
+    // Async Iteration proposal 11.1.3.2.5.
+    // Async-from-Sync iterator handlers take the resolved value and create new
+    // iterator objects.  To do so it needs to forward whether the iterator is
+    // done. In spec, this is achieved via the [[Done]] internal slot. We
+    // enumerate both true and false cases here.
+    PromiseHandlerAsyncFromSyncIteratorValueUnwrapDone,
+    PromiseHandlerAsyncFromSyncIteratorValueUnwrapNotDone,
 };
 
 enum ResolutionMode {
     ResolveMode,
     RejectMode
 };
 
 enum ResolveFunctionSlots {
@@ -192,18 +204,18 @@ enum ReactionRecordSlots {
     ReactionRecordSlot_HandlerArg,
     ReactionRecordSlot_Generator,
     ReactionRecordSlots,
 };
 
 #define REACTION_FLAG_RESOLVED                  0x1
 #define REACTION_FLAG_FULFILLED                 0x2
 #define REACTION_FLAG_IGNORE_DEFAULT_RESOLUTION 0x4
-#define REACTION_FLAG_ASYNC_FUNCTION_AWAIT      0x8
-#define REACTION_FLAG_ASYNC_GENERATOR_AWAIT     0x10
+#define REACTION_FLAG_ASYNC_FUNCTION            0x8
+#define REACTION_FLAG_ASYNC_GENERATOR           0x10
 
 // ES2016, 25.4.1.2.
 class PromiseReactionRecord : public NativeObject
 {
   public:
     static const Class class_;
 
     JSObject* promise() { return getFixedSlot(ReactionRecordSlot_Promise).toObjectOrNull(); }
@@ -220,38 +232,38 @@ class PromiseReactionRecord : public Nat
         int32_t flags = this->flags();
         MOZ_ASSERT(!(flags & REACTION_FLAG_RESOLVED));
         MOZ_ASSERT(state != JS::PromiseState::Pending, "Can't revert a reaction to pending.");
         flags |= REACTION_FLAG_RESOLVED;
         if (state == JS::PromiseState::Fulfilled)
             flags |= REACTION_FLAG_FULFILLED;
         setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
     }
-    void setIsAsyncFunctionAwait() {
+    void setIsAsyncFunction() {
         int32_t flags = this->flags();
-        flags |= REACTION_FLAG_ASYNC_FUNCTION_AWAIT;
+        flags |= REACTION_FLAG_ASYNC_FUNCTION;
         setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
     }
-    bool isAsyncFunctionAwait() {
+    bool isAsyncFunction() {
         int32_t flags = this->flags();
-        return flags & REACTION_FLAG_ASYNC_FUNCTION_AWAIT;
+        return flags & REACTION_FLAG_ASYNC_FUNCTION;
     }
-    void setIsAsyncGeneratorAwait(Handle<AsyncGeneratorObject*> asyncGenObj) {
+    void setIsAsyncGenerator(Handle<AsyncGeneratorObject*> asyncGenObj) {
         int32_t flags = this->flags();
-        flags |= REACTION_FLAG_ASYNC_GENERATOR_AWAIT;
+        flags |= REACTION_FLAG_ASYNC_GENERATOR;
         setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
 
         setFixedSlot(ReactionRecordSlot_Generator, ObjectValue(*asyncGenObj));
     }
-    bool isAsyncGeneratorAwait() {
+    bool isAsyncGenerator() {
         int32_t flags = this->flags();
-        return flags & REACTION_FLAG_ASYNC_GENERATOR_AWAIT;
+        return flags & REACTION_FLAG_ASYNC_GENERATOR;
     }
     AsyncGeneratorObject* asyncGenerator() {
-        MOZ_ASSERT(isAsyncGeneratorAwait());
+        MOZ_ASSERT(isAsyncGenerator());
         return &getFixedSlot(ReactionRecordSlot_Generator).toObject()
                                                           .as<AsyncGeneratorObject>();
     }
     Value handler() {
         MOZ_ASSERT(targetState() != JS::PromiseState::Pending);
         uint32_t slot = targetState() == JS::PromiseState::Fulfilled
                         ? ReactionRecordSlot_OnFulfilled
                         : ReactionRecordSlot_OnRejected;
@@ -854,65 +866,85 @@ TriggerPromiseReactions(JSContext* cx, H
         if (!EnqueuePromiseReactionJob(cx, reaction, valueOrReason, state))
             return false;
     }
 
     return true;
 }
 
 static MOZ_MUST_USE bool
-AsyncFunctionAwaitPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction,
-                                     MutableHandleValue rval)
+AsyncFunctionPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction,
+                                MutableHandleValue rval)
 {
-    MOZ_ASSERT(reaction->isAsyncFunctionAwait());
+    MOZ_ASSERT(reaction->isAsyncFunction());
 
     RootedValue handlerVal(cx, reaction->handler());
     RootedValue argument(cx, reaction->handlerArg());
     Rooted<PromiseObject*> resultPromise(cx, &reaction->promise()->as<PromiseObject>());
     RootedValue generatorVal(cx, resultPromise->getFixedSlot(PromiseSlot_AwaitGenerator));
 
     int32_t handlerNum = int32_t(handlerVal.toNumber());
-    MOZ_ASSERT(handlerNum == PromiseHandlerAsyncFunctionAwaitFulfilled ||
-               handlerNum == PromiseHandlerAsyncFunctionAwaitRejected);
 
     // Await's handlers don't return a value, nor throw exception.
     // They fail only on OOM.
-    if (handlerNum == PromiseHandlerAsyncFunctionAwaitFulfilled) {
+    if (handlerNum == PromiseHandlerAsyncFunctionAwaitedFulfilled) {
         if (!AsyncFunctionAwaitedFulfilled(cx, resultPromise, generatorVal, argument))
             return false;
     } else {
+        MOZ_ASSERT(handlerNum == PromiseHandlerAsyncFunctionAwaitedRejected);
         if (!AsyncFunctionAwaitedRejected(cx, resultPromise, generatorVal, argument))
             return false;
     }
 
     rval.setUndefined();
     return true;
 }
 
 static MOZ_MUST_USE bool
-AsyncGeneratorAwaitPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction,
-                                      MutableHandleValue rval)
+AsyncGeneratorPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction,
+                                 MutableHandleValue rval)
 {
-    MOZ_ASSERT(reaction->isAsyncGeneratorAwait());
+    MOZ_ASSERT(reaction->isAsyncGenerator());
 
     RootedValue handlerVal(cx, reaction->handler());
     RootedValue argument(cx, reaction->handlerArg());
     Rooted<AsyncGeneratorObject*> asyncGenObj(cx, reaction->asyncGenerator());
 
     int32_t handlerNum = int32_t(handlerVal.toNumber());
-    MOZ_ASSERT(handlerNum == PromiseHandlerAsyncGeneratorAwaitFulfilled ||
-               handlerNum == PromiseHandlerAsyncGeneratorAwaitRejected);
 
     // Await's handlers don't return a value, nor throw exception.
     // They fail only on OOM.
-    if (handlerNum == PromiseHandlerAsyncGeneratorAwaitFulfilled) {
+    if (handlerNum == PromiseHandlerAsyncGeneratorAwaitedFulfilled) {
+        // 4.1.1.
         if (!AsyncGeneratorAwaitedFulfilled(cx, asyncGenObj, argument))
             return false;
+    } else if (handlerNum == PromiseHandlerAsyncGeneratorAwaitedRejected) {
+        // 4.1.2.
+        if (!AsyncGeneratorAwaitedRejected(cx, asyncGenObj, argument))
+            return false;
+    } else if (handlerNum == PromiseHandlerAsyncGeneratorResumeNextReturnFulfilled) {
+        asyncGenObj->setCompleted();
+        // 11.4.3.5.1 step 1.
+        if (!AsyncGeneratorResolve(cx, asyncGenObj, argument, true))
+            return false;
+    } else if (handlerNum == PromiseHandlerAsyncGeneratorResumeNextReturnRejected) {
+        asyncGenObj->setCompleted();
+        // 11.4.3.5.2 step 1.
+        if (!AsyncGeneratorReject(cx, asyncGenObj, argument))
+            return false;
+    } else if (handlerNum == PromiseHandlerAsyncGeneratorYieldReturnAwaitedFulfilled) {
+        asyncGenObj->setExecuting();
+        // 11.4.3.7 steps 8.d-e.
+        if (!AsyncGeneratorYieldReturnAwaitedFulfilled(cx, asyncGenObj, argument))
+            return false;
     } else {
-        if (!AsyncGeneratorAwaitedRejected(cx, asyncGenObj, argument))
+        MOZ_ASSERT(handlerNum == PromiseHandlerAsyncGeneratorYieldReturnAwaitedRejected);
+        asyncGenObj->setExecuting();
+        // 11.4.3.7 step 8.c.
+        if (!AsyncGeneratorYieldReturnAwaitedRejected(cx, asyncGenObj, argument))
             return false;
     }
 
     rval.setUndefined();
     return true;
 }
 
 // ES2016, 25.4.2.1.
@@ -953,20 +985,20 @@ PromiseReactionJob(JSContext* cx, unsign
             return false;
         }
         MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
         ac.emplace(cx, reactionObj);
     }
 
     // Steps 1-2.
     Rooted<PromiseReactionRecord*> reaction(cx, &reactionObj->as<PromiseReactionRecord>());
-    if (reaction->isAsyncFunctionAwait())
-        return AsyncFunctionAwaitPromiseReactionJob(cx, reaction, args.rval());
-    if (reaction->isAsyncGeneratorAwait())
-        return AsyncGeneratorAwaitPromiseReactionJob(cx, reaction, args.rval());
+    if (reaction->isAsyncFunction())
+        return AsyncFunctionPromiseReactionJob(cx, reaction, args.rval());
+    if (reaction->isAsyncGenerator())
+        return AsyncGeneratorPromiseReactionJob(cx, reaction, args.rval());
 
     // Step 3.
     RootedValue handlerVal(cx, reaction->handler());
 
     RootedValue argument(cx, reaction->handlerArg());
 
     RootedValue handlerResult(cx);
     ResolutionMode resolutionMode = ResolveMode;
@@ -978,21 +1010,21 @@ PromiseReactionJob(JSContext* cx, unsign
         // Step 4.
         if (handlerNum == PromiseHandlerIdentity) {
             handlerResult = argument;
         } else if (handlerNum == PromiseHandlerThrower) {
             // Step 5.
             resolutionMode = RejectMode;
             handlerResult = argument;
         } else {
-            MOZ_ASSERT(handlerNum == PromiseHandlerAsyncIteratorValueUnwrapDone ||
-                       handlerNum == PromiseHandlerAsyncIteratorValueUnwrapNotDone);
-
-            bool done = handlerNum == PromiseHandlerAsyncIteratorValueUnwrapDone;
-            // Async Iteration proposal 6.1.1.2.1 step 1.
+            MOZ_ASSERT(handlerNum == PromiseHandlerAsyncFromSyncIteratorValueUnwrapDone ||
+                       handlerNum == PromiseHandlerAsyncFromSyncIteratorValueUnwrapNotDone);
+
+            bool done = handlerNum == PromiseHandlerAsyncFromSyncIteratorValueUnwrapDone;
+            // Async Iteration proposal 11.1.3.2.5 step 1.
             RootedObject resultObj(cx, CreateIterResultObject(cx, argument, done));
             if (!resultObj)
                 return false;
 
             handlerResult = ObjectValue(*resultObj);
         }
     } else {
         // Step 6.
@@ -2213,134 +2245,127 @@ js::OriginalPromiseThen(JSContext* cx, H
 
 static MOZ_MUST_USE bool PerformPromiseThenWithReaction(JSContext* cx,
                                                         Handle<PromiseObject*> promise,
                                                         Handle<PromiseReactionRecord*> reaction);
 
 // Some async/await functions are implemented here instead of
 // js/src/builtin/AsyncFunction.cpp, to call Promise internal functions.
 
-// Async Functions proposal 1.1.8 and 1.2.14 step 1.
+// ES 2018 draft 14.6.11 and 14.7.14 step 1.
 MOZ_MUST_USE PromiseObject*
 js::CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal)
 {
     // Step 1.
     Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
     if (!promise)
         return nullptr;
 
     AddPromiseFlags(*promise, PROMISE_FLAG_ASYNC);
     promise->setFixedSlot(PromiseSlot_AwaitGenerator, generatorVal);
     return promise;
 }
 
-// Async Functions proposal 2.2 steps 3.f, 3.g.
+// ES 2018 draft 25.5.5.2 steps 3.f, 3.g.
 MOZ_MUST_USE bool
 js::AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise)
 {
     // Step 3.f.
     RootedValue exc(cx);
     if (!MaybeGetAndClearException(cx, &exc))
         return false;
 
     if (!RejectMaybeWrappedPromise(cx, resultPromise, exc))
         return false;
 
     // Step 3.g.
     return true;
 }
 
-// Async Functions proposal 2.2 steps 3.d-e, 3.g.
+// ES 2018 draft 25.5.5.2 steps 3.d-e, 3.g.
 MOZ_MUST_USE bool
 js::AsyncFunctionReturned(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value)
 {
     // Steps 3.d-e.
     if (!ResolvePromiseInternal(cx, resultPromise, value))
         return false;
 
     // Step 3.g.
     return true;
 }
 
-// Async Functions proposal 2.3 steps 2-8.
-MOZ_MUST_USE bool
-js::AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value)
+// Helper function that performs the equivalent steps as
+// Async Iteration proposal 4.1 Await steps 2-3, 6-9 or similar.
+template <typename T>
+static MOZ_MUST_USE bool
+InternalAwait(JSContext* cx, HandleValue value, HandleObject resultPromise,
+              HandleValue onFulfilled, HandleValue onRejected, T extraStep)
 {
     // Step 2.
     Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
     if (!promise)
         return false;
 
-    // Steps 3.
+    // Step 3.
     if (!ResolvePromiseInternal(cx, promise, value))
         return false;
 
-    // Steps 4-5.
-    RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncFunctionAwaitFulfilled));
-    RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncFunctionAwaitRejected));
-
     RootedObject incumbentGlobal(cx);
     if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
         return false;
 
-    // Steps 6-7.
+    // Step 7-8.
     Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise,
                                                                   onFulfilled, onRejected,
                                                                   nullptr, nullptr,
                                                                   incumbentGlobal));
     if (!reaction)
         return false;
 
-    reaction->setIsAsyncFunctionAwait();
-
-    // Step 8.
+    // Step 6.
+    extraStep(reaction);
+
+    // Step 9.
     return PerformPromiseThenWithReaction(cx, promise, reaction);
 }
 
-// Async Iteration proposal 5.1 steps 2-9.
+// ES 2018 draft 25.5.5.3 steps 2-10.
+MOZ_MUST_USE bool
+js::AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value)
+{
+    // Steps 4-5.
+    RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncFunctionAwaitedFulfilled));
+    RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncFunctionAwaitedRejected));
+
+    // Steps 2-3, 6-10.
+    auto extra = [](Handle<PromiseReactionRecord*> reaction) {
+        reaction->setIsAsyncFunction();
+    };
+    return InternalAwait(cx, value, resultPromise, onFulfilled, onRejected, extra);
+}
+
+// Async Iteration proposal 4.1 Await steps 2-9.
 MOZ_MUST_USE bool
 js::AsyncGeneratorAwait(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
                         HandleValue value)
 {
-    // Step 2.
-    Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
-    if (!promise)
-        return false;
-
-    // Steps 3.
-    if (!ResolvePromiseInternal(cx, promise, value))
-        return false;
-
     // Steps 4-5.
-    RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncGeneratorAwaitFulfilled));
-    RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncGeneratorAwaitRejected));
-
-    RootedObject incumbentGlobal(cx);
-    if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
-        return false;
-
-    // Step 6 (skipped).
-
-    // Steps 7-8.
-    Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, nullptr,
-                                                                  onFulfilled, onRejected,
-                                                                  nullptr, nullptr,
-                                                                  incumbentGlobal));
-    if (!reaction)
-        return false;
-
-    reaction->setIsAsyncGeneratorAwait(asyncGenObj);
-
-    // Step 9.
-    return PerformPromiseThenWithReaction(cx, promise, reaction);
+    RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncGeneratorAwaitedFulfilled));
+    RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncGeneratorAwaitedRejected));
+
+    // Steps 2-3, 6-9.
+    auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
+        reaction->setIsAsyncGenerator(asyncGenObj);
+    };
+    return InternalAwait(cx, value, nullptr, onFulfilled, onRejected, extra);
 }
 
-// Async Iteration proposal 6.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next
-// Async Iteration proposal 6.1.3.2.2 %AsyncFromSyncIteratorPrototype%.return
-// Async Iteration proposal 6.1.3.2.3 %AsyncFromSyncIteratorPrototype%.throw
+// Async Iteration proposal 11.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next
+// Async Iteration proposal 11.1.3.2.2 %AsyncFromSyncIteratorPrototype%.return
+// Async Iteration proposal 11.1.3.2.3 %AsyncFromSyncIteratorPrototype%.throw
 bool
 js::AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args, CompletionKind completionKind)
 {
     // Step 1.
     RootedValue thisVal(cx, args.thisv());
 
     // Step 2.
     RootedObject resultPromise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
@@ -2367,21 +2392,21 @@ js::AsyncFromSyncIteratorMethod(JSContex
         cx, &thisVal.toObject().as<AsyncFromSyncIteratorObject>());
 
     // Step 4.
     RootedObject iter(cx, asyncIter->iterator());
 
     RootedValue resultVal(cx);
     RootedValue func(cx);
     if (completionKind == CompletionKind::Normal) {
-        // 6.1.3.2.1 steps 5-6 (partially).
+        // 11.1.3.2.1 steps 5-6 (partially).
         if (!GetProperty(cx, iter, iter, cx->names().next, &func))
             return AbruptRejectPromise(cx, args, resultPromise, nullptr);
     } else if (completionKind == CompletionKind::Return) {
-        // 6.1.3.2.2 steps 5-6.
+        // 11.1.3.2.2 steps 5-6.
         if (!GetProperty(cx, iter, iter, cx->names().return_, &func))
             return AbruptRejectPromise(cx, args, resultPromise, nullptr);
 
         // Step 7.
         if (func.isNullOrUndefined()) {
             // Step 7.a.
             RootedObject resultObj(cx, CreateIterResultObject(cx, args.get(0), true));
             if (!resultObj)
@@ -2393,43 +2418,43 @@ js::AsyncFromSyncIteratorMethod(JSContex
             if (!ResolvePromiseInternal(cx, resultPromise, resultVal))
                 return AbruptRejectPromise(cx, args, resultPromise, nullptr);
 
             // Step 7.c.
             args.rval().setObject(*resultPromise);
             return true;
         }
     } else {
-        // 6.1.3.2.3 steps 5-6.
+        // 11.1.3.2.3 steps 5-6.
         MOZ_ASSERT(completionKind == CompletionKind::Throw);
         if (!GetProperty(cx, iter, iter, cx->names().throw_, &func))
             return AbruptRejectPromise(cx, args, resultPromise, nullptr);
 
         // Step 7.
         if (func.isNullOrUndefined()) {
             // Step 7.a.
             if (!RejectMaybeWrappedPromise(cx, resultPromise, args.get(0)))
                 return AbruptRejectPromise(cx, args, resultPromise, nullptr);
 
             // Step 7.b.
             args.rval().setObject(*resultPromise);
             return true;
         }
     }
 
-    // 6.1.3.2.1 steps 5-6 (partially).
-    // 6.1.3.2.2, 6.1.3.2.3 steps 8-9.
+    // 11.1.3.2.1 steps 5-6 (partially).
+    // 11.1.3.2.2, 11.1.3.2.3 steps 8-9.
     RootedValue iterVal(cx, ObjectValue(*iter));
     FixedInvokeArgs<1> args2(cx);
     args2[0].set(args.get(0));
     if (!js::Call(cx, func, iterVal, args2, &resultVal))
         return AbruptRejectPromise(cx, args, resultPromise, nullptr);
 
-    // 6.1.3.2.1 steps 5-6 (partially).
-    // 6.1.3.2.2, 6.1.3.2.3 steps 10.
+    // 11.1.3.2.1 steps 5-6 (partially).
+    // 11.1.3.2.2, 11.1.3.2.3 steps 10.
     if (!resultVal.isObject()) {
         CheckIsObjectKind kind;
         switch (completionKind) {
           case CompletionKind::Normal:
             kind = CheckIsObjectKind::IteratorNext;
             break;
           case CompletionKind::Throw:
             kind = CheckIsObjectKind::IteratorThrow;
@@ -2439,65 +2464,50 @@ js::AsyncFromSyncIteratorMethod(JSContex
             break;
         }
         MOZ_ALWAYS_FALSE(ThrowCheckIsObject(cx, kind));
         return AbruptRejectPromise(cx, args, resultPromise, nullptr);
     }
 
     RootedObject resultObj(cx, &resultVal.toObject());
 
-    // Following step numbers are for 6.1.3.2.1.
-    // For 6.1.3.2.2 and 6.1.3.2.3, steps 7-16 corresponds to steps 11-20.
+    // Following step numbers are for 11.1.3.2.1.
+    // For 11.1.3.2.2 and 11.1.3.2.3, steps 7-16 corresponds to steps 11-20.
 
     // Steps 7-8.
     RootedValue doneVal(cx);
     if (!GetProperty(cx, resultObj, resultObj, cx->names().done, &doneVal))
         return AbruptRejectPromise(cx, args, resultPromise, nullptr);
     bool done = ToBoolean(doneVal);
 
     // Steps 9-10.
     RootedValue value(cx);
     if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
         return AbruptRejectPromise(cx, args, resultPromise, nullptr);
 
-    // Step 11.
-    Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
-    if (!promise)
-        return false;
-
-    // Step 12.
-    if (!ResolvePromiseInternal(cx, promise, value))
-        return false;
-
     // Steps 13-14.
     RootedValue onFulfilled(cx, Int32Value(done
-                                           ? PromiseHandlerAsyncIteratorValueUnwrapDone
-                                           : PromiseHandlerAsyncIteratorValueUnwrapNotDone));
-
-    RootedObject incumbentGlobal(cx);
-    if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
-        return false;
-
-    // Step 15.
-    Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise, onFulfilled,
-                                                                  UndefinedHandleValue,
-                                                                  nullptr, nullptr,
-                                                                  incumbentGlobal));
-    if (!reaction)
-        return false;
-
-    if (!PerformPromiseThenWithReaction(cx, promise, reaction))
+                                           ? PromiseHandlerAsyncFromSyncIteratorValueUnwrapDone
+                                           : PromiseHandlerAsyncFromSyncIteratorValueUnwrapNotDone));
+
+    // Steps 11-12, 15.
+    auto extra = [](Handle<PromiseReactionRecord*> reaction) {
+    };
+    if (!InternalAwait(cx, value, resultPromise, onFulfilled, UndefinedHandleValue, extra))
         return false;
 
     // Step 16.
     args.rval().setObject(*resultPromise);
     return true;
 }
 
-// Async Iteration proposal 6.4.3.3.
+static MOZ_MUST_USE bool
+AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj);
+
+// Async Iteration proposal 11.4.3.3.
 MOZ_MUST_USE bool
 js::AsyncGeneratorResolve(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
                           HandleValue value, bool done)
 {
     // Step 1 (implicit).
 
     // Steps 2-3.
     MOZ_ASSERT(!asyncGenObj->isQueueEmpty());
@@ -2507,53 +2517,35 @@ js::AsyncGeneratorResolve(JSContext* cx,
         cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj));
     if (!request)
         return false;
 
     // Step 5.
     RootedObject resultPromise(cx, request->promise());
 
     // Step 6.
-    Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
-    if (!promise)
+    RootedObject resultObj(cx, CreateIterResultObject(cx, value, done));
+    if (!resultObj)
         return false;
 
+    RootedValue resultValue(cx, ObjectValue(*resultObj));
+
     // Step 7.
-    if (!ResolvePromiseInternal(cx, promise, value))
-        return false;
-
-    // Steps 8-9.
-    RootedValue onFulfilled(cx, Int32Value(done
-                                           ? PromiseHandlerAsyncIteratorValueUnwrapDone
-                                           : PromiseHandlerAsyncIteratorValueUnwrapNotDone));
-
-    RootedObject incumbentGlobal(cx);
-    if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
+    if (!ResolvePromiseInternal(cx, resultPromise, resultValue))
         return false;
 
-    // Step 10.
-    Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise, onFulfilled,
-                                                                  UndefinedHandleValue,
-                                                                  nullptr, nullptr,
-                                                                  incumbentGlobal));
-    if (!reaction)
-        return false;
-
-    if (!PerformPromiseThenWithReaction(cx, promise, reaction))
-        return false;
-
-    // Step 11.
+    // Step 8.
     if (!AsyncGeneratorResumeNext(cx, asyncGenObj))
         return false;
 
-    // Step 12.
+    // Step 9.
     return true;
 }
 
-// Async Iteration proposal 6.4.3.4.
+// Async Iteration proposal 11.4.3.4.
 MOZ_MUST_USE bool
 js::AsyncGeneratorReject(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
                          HandleValue exception)
 {
     // Step 1 (implicit).
 
     // Steps 2-3.
     MOZ_ASSERT(!asyncGenObj->isQueueEmpty());
@@ -2574,17 +2566,108 @@ js::AsyncGeneratorReject(JSContext* cx, 
     // Step 7.
     if (!AsyncGeneratorResumeNext(cx, asyncGenObj))
         return false;
 
     // Step 8.
     return true;
 }
 
-// Async Iteration proposal 6.4.3.6.
+// Async Iteration proposal 11.4.3.5.
+static MOZ_MUST_USE bool
+AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
+{
+    // Step 1 (implicit).
+
+    // Steps 2-3.
+    MOZ_ASSERT(!asyncGenObj->isExecuting());
+
+    // Step 4.
+    if (asyncGenObj->isAwaitingYieldReturn() || asyncGenObj->isAwaitingReturn())
+        return true;
+
+    // Steps 5-6.
+    if (asyncGenObj->isQueueEmpty())
+        return true;
+
+    // Steps 7-8.
+    Rooted<AsyncGeneratorRequest*> request(
+        cx, AsyncGeneratorObject::peekRequest(cx, asyncGenObj));
+    if (!request)
+        return false;
+
+    // Step 9.
+    CompletionKind completionKind = request->completionKind();
+
+    // Step 10.
+    if (completionKind != CompletionKind::Normal) {
+        // Step 10.a.
+        if (asyncGenObj->isSuspendedStart())
+            asyncGenObj->setCompleted();
+
+        // Step 10.b.
+        if (asyncGenObj->isCompleted()) {
+            RootedValue value(cx, request->completionValue());
+
+            // Step 10.b.i.
+            if (completionKind == CompletionKind::Return) {
+                // Steps 10.b.i.1.
+                asyncGenObj->setAwaitingReturn();
+
+                // Steps 10.b.i.4-6 (reordered).
+                RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncGeneratorResumeNextReturnFulfilled));
+                RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncGeneratorResumeNextReturnRejected));
+
+                // Steps 10.b.i.2-3, 7-10.
+                auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
+                    reaction->setIsAsyncGenerator(asyncGenObj);
+                };
+                return InternalAwait(cx, value, nullptr, onFulfilled, onRejected, extra);
+            }
+
+            // Step 10.b.ii.1.
+            MOZ_ASSERT(completionKind == CompletionKind::Throw);
+
+            // Steps 10.b.ii.2-3.
+            return AsyncGeneratorReject(cx, asyncGenObj, value);
+        }
+    } else if (asyncGenObj->isCompleted()) {
+        // Step 11.
+        return AsyncGeneratorResolve(cx, asyncGenObj, UndefinedHandleValue, true);
+    }
+
+    // Step 12.
+    MOZ_ASSERT(asyncGenObj->isSuspendedStart() || asyncGenObj->isSuspendedYield());
+
+    // Step 16 (reordered).
+    asyncGenObj->setExecuting();
+
+    RootedValue argument(cx, request->completionValue());
+
+    if (completionKind == CompletionKind::Return) {
+        // 11.4.3.7 AsyncGeneratorYield step 8.b-e.
+        // Since we don't have the place that handles return from yield
+        // inside the generator, handle the case here, with extra state
+        // State_AwaitingYieldReturn.
+        asyncGenObj->setAwaitingYieldReturn();
+
+        RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncGeneratorYieldReturnAwaitedFulfilled));
+        RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncGeneratorYieldReturnAwaitedRejected));
+
+        auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
+            reaction->setIsAsyncGenerator(asyncGenObj);
+        };
+        return InternalAwait(cx, argument, nullptr, onFulfilled, onRejected, extra);
+    }
+
+    // Steps 13-15, 17-21.
+    return AsyncGeneratorResume(cx, asyncGenObj, completionKind, argument);
+}
+
+// Async Iteration proposal 11.4.3.6.
 MOZ_MUST_USE bool
 js::AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal,
                           CompletionKind completionKind, HandleValue completionValue,
                           MutableHandleValue result)
 {
     // Step 1 (implicit).
 
     // Step 2.
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -8607,16 +8607,22 @@ BytecodeEmitter::emitReturn(ParseNode* p
         if (!emitPrepareIteratorResult())
             return false;
     }
 
     /* Push a return value */
     if (ParseNode* pn2 = pn->pn_kid) {
         if (!emitTree(pn2))
             return false;
+
+        bool isAsyncGenerator = sc->asFunctionBox()->isAsync();
+        if (isAsyncGenerator) {
+            if (!emitAwait())
+                return false;
+        }
     } else {
         /* No explicit return value provided */
         if (!emit1(JSOP_UNDEFINED))
             return false;
     }
 
     if (needsIteratorResult) {
         if (!emitFinishIteratorResult(true))
@@ -8719,16 +8725,24 @@ BytecodeEmitter::emitYield(ParseNode* pn
     }
     if (pn->pn_kid) {
         if (!emitTree(pn->pn_kid))
             return false;
     } else {
         if (!emit1(JSOP_UNDEFINED))
             return false;
     }
+
+    // 11.4.3.7 AsyncGeneratorYield step 5.
+    bool isAsyncGenerator = sc->asFunctionBox()->isAsync();
+    if (isAsyncGenerator) {
+        if (!emitAwait())                                 // RESULT
+            return false;
+    }
+
     if (needsIteratorResult) {
         if (!emitFinishIteratorResult(false))
             return false;
     }
 
     if (!emitGetDotGenerator())
         return false;
 
@@ -8791,16 +8805,22 @@ BytecodeEmitter::emitYieldStar(ParseNode
         return false;
 
     JumpTarget tryStart{ offset() };
     if (!tryCatch.emitTry())                              // ITER RESULT
         return false;
 
     MOZ_ASSERT(this->stackDepth == startDepth);
 
+    // 11.4.3.7 AsyncGeneratorYield step 5.
+    if (isAsyncGenerator) {
+        if (!emitAwait())                                 // ITER RESULT
+            return false;
+    }
+
     // Load the generator object.
     if (!emitGetDotGenerator())                           // ITER RESULT GENOBJ
         return false;
 
     // Yield RESULT as-is, without re-boxing.
     if (!emitYieldOp(JSOP_YIELD))                         // ITER RECEIVED
         return false;
 
@@ -8940,21 +8960,16 @@ BytecodeEmitter::emitYieldStar(ParseNode
         return false;
     if (!emitAtomOp(cx->names().done, JSOP_GETPROP))      // ITER OLDRESULT FTYPE FVALUE RESULT DONE
         return false;
     if (!ifReturnDone.emitIfElse())                       // ITER OLDRESULT FTYPE FVALUE RESULT
         return false;
     if (!emitAtomOp(cx->names().value, JSOP_GETPROP))     // ITER OLDRESULT FTYPE FVALUE VALUE
         return false;
 
-    if (isAsyncGenerator) {
-        if (!emitAwait())                                 // ITER OLDRESULT FTYPE FVALUE VALUE
-            return false;
-    }
-
     if (!emitPrepareIteratorResult())                     // ITER OLDRESULT FTYPE FVALUE VALUE RESULT
         return false;
     if (!emit1(JSOP_SWAP))                                // ITER OLDRESULT FTYPE FVALUE RESULT VALUE
         return false;
     if (!emitFinishIteratorResult(true))                  // ITER OLDRESULT FTYPE FVALUE RESULT
         return false;
     if (!emit1(JSOP_SETRVAL))                             // ITER OLDRESULT FTYPE FVALUE
         return false;
@@ -9035,21 +9050,16 @@ BytecodeEmitter::emitYieldStar(ParseNode
     // result.value
     if (!emit1(JSOP_SWAP))                                       // RESULT ITER
         return false;
     if (!emit1(JSOP_POP))                                        // RESULT
         return false;
     if (!emitAtomOp(cx->names().value, JSOP_GETPROP))            // VALUE
         return false;
 
-    if (isAsyncGenerator) {
-        if (!emitAwait())                                        // VALUE
-            return false;
-    }
-
     MOZ_ASSERT(this->stackDepth == startDepth - 1);
 
     return true;
 }
 
 bool
 BytecodeEmitter::emitStatementList(ParseNode* pn)
 {
--- a/js/src/vm/AsyncIteration.cpp
+++ b/js/src/vm/AsyncIteration.cpp
@@ -21,17 +21,17 @@
 #include "vm/NativeObject-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
 #define UNWRAPPED_ASYNC_WRAPPED_SLOT 1
 #define WRAPPED_ASYNC_UNWRAPPED_SLOT 0
 
-// Async Iteration proposal 2.3.10 Runtime Semantics: EvaluateBody.
+// Async Iteration proposal 8.3.10 Runtime Semantics: EvaluateBody.
 static bool
 WrappedAsyncGenerator(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     RootedFunction wrapped(cx, &args.callee().as<JSFunction>());
     RootedValue unwrappedVal(cx, wrapped->getExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT));
     RootedFunction unwrapped(cx, &unwrappedVal.toObject().as<JSFunction>());
@@ -123,53 +123,67 @@ js::GetUnwrappedAsyncGenerator(JSFunctio
 {
     MOZ_ASSERT(IsWrappedAsyncGenerator(wrapped));
     JSFunction* unwrapped = &wrapped->getExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT)
                             .toObject().as<JSFunction>();
     MOZ_ASSERT(unwrapped->isAsync());
     return unwrapped;
 }
 
-static MOZ_MUST_USE bool
-AsyncGeneratorResume(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
-                     CompletionKind completionKind, HandleValue argument);
-
-// Async Iteration proposal 5.1.1 Await Fulfilled Functions.
+// Async Iteration proposal 4.1.1 Await Fulfilled Functions.
 MOZ_MUST_USE bool
 js::AsyncGeneratorAwaitedFulfilled(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
                                    HandleValue value)
 {
     return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Normal, value);
 }
 
-// Async Iteration proposal 5.1.2 Await Rejected Functions.
+// Async Iteration proposal 4.1.2 Await Rejected Functions.
 MOZ_MUST_USE bool
 js::AsyncGeneratorAwaitedRejected(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
                                   HandleValue reason)
 {
     return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Throw, reason);
 }
 
+// Async Iteration proposal 11.4.3.7 step 8.d-e.
+MOZ_MUST_USE bool
+js::AsyncGeneratorYieldReturnAwaitedFulfilled(JSContext* cx,
+                                              Handle<AsyncGeneratorObject*> asyncGenObj,
+                                              HandleValue value)
+{
+    return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Return, value);
+}
+
+// Async Iteration proposal 11.4.3.7 step 8.d-e.
+MOZ_MUST_USE bool
+js::AsyncGeneratorYieldReturnAwaitedRejected(JSContext* cx,
+                                             Handle<AsyncGeneratorObject*> asyncGenObj,
+                                             HandleValue reason)
+{
+    return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Throw, reason);
+}
+
 const Class AsyncFromSyncIteratorObject::class_ = {
     "AsyncFromSyncIteratorObject",
     JSCLASS_HAS_RESERVED_SLOTS(AsyncFromSyncIteratorObject::Slots)
 };
 
-// Async Iteration proposal 6.1.3.1.
+// Async Iteration proposal 11.1.3.1.
 JSObject*
 js::CreateAsyncFromSyncIterator(JSContext* cx, HandleObject iter)
 {
     // Step 1 (implicit).
     // Done in bytecode emitted by emitAsyncIterator.
 
     // Steps 2-4.
     return AsyncFromSyncIteratorObject::create(cx, iter);
 }
 
-// Async Iteration proposal 6.1.3.1 steps 2-4.
+// Async Iteration proposal 11.1.3.1 steps 2-4.
 /* static */ JSObject*
 AsyncFromSyncIteratorObject::create(JSContext* cx, HandleObject iter)
 {
     // Step 2.
     RootedObject proto(cx, GlobalObject::getOrCreateAsyncFromSyncIteratorPrototype(cx,
                                                                                    cx->global()));
     if (!proto)
         return nullptr;
@@ -182,63 +196,63 @@ AsyncFromSyncIteratorObject::create(JSCo
 
     // Step 3.
     asyncIter->setIterator(iter);
 
     // Step 4.
     return asyncIter;
 }
 
-// Async Iteration proposal 6.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next.
+// Async Iteration proposal 11.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next.
 static bool
 AsyncFromSyncIteratorNext(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Normal);
 }
 
-// Async Iteration proposal 6.1.3.2.2 %AsyncFromSyncIteratorPrototype%.return.
+// Async Iteration proposal 11.1.3.2.2 %AsyncFromSyncIteratorPrototype%.return.
 static bool
 AsyncFromSyncIteratorReturn(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Return);
 }
 
-// Async Iteration proposal 6.1.3.2.3 %AsyncFromSyncIteratorPrototype%.throw.
+// Async Iteration proposal 11.1.3.2.3 %AsyncFromSyncIteratorPrototype%.throw.
 static bool
 AsyncFromSyncIteratorThrow(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Throw);
 }
 
-// Async Iteration proposal 6.4.1.2 AsyncGenerator.prototype.next.
+// Async Iteration proposal 11.4.1.2 AsyncGenerator.prototype.next.
 static bool
 AsyncGeneratorNext(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Steps 1-3.
     return AsyncGeneratorEnqueue(cx, args.thisv(), CompletionKind::Normal, args.get(0),
                                  args.rval());
 }
 
-// Async Iteration proposal 6.4.1.3 AsyncGenerator.prototype.return.
+// Async Iteration proposal 11.4.1.3 AsyncGenerator.prototype.return.
 static bool
 AsyncGeneratorReturn(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Steps 1-3.
     return AsyncGeneratorEnqueue(cx, args.thisv(), CompletionKind::Return, args.get(0),
                                  args.rval());
 }
 
-// Async Iteration proposal 6.4.1.4 AsyncGenerator.prototype.throw.
+// Async Iteration proposal 11.4.1.4 AsyncGenerator.prototype.throw.
 static bool
 AsyncGeneratorThrow(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Steps 1-3.
     return AsyncGeneratorEnqueue(cx, args.thisv(), CompletionKind::Throw, args.get(0),
                                  args.rval());
@@ -366,48 +380,48 @@ AsyncGeneratorObject::peekRequest(JSCont
     return &requestVal.toObject().as<AsyncGeneratorRequest>();
 }
 
 const Class AsyncGeneratorRequest::class_ = {
     "AsyncGeneratorRequest",
     JSCLASS_HAS_RESERVED_SLOTS(AsyncGeneratorRequest::Slots)
 };
 
-// Async Iteration proposal 6.4.3.1.
+// Async Iteration proposal 11.4.3.1.
 /* static */ AsyncGeneratorRequest*
 AsyncGeneratorRequest::create(JSContext* cx, CompletionKind completionKind_,
                               HandleValue completionValue_, HandleObject promise_)
 {
     RootedObject obj(cx, NewNativeObjectWithGivenProto(cx, &class_, nullptr));
     if (!obj)
         return nullptr;
 
     Handle<AsyncGeneratorRequest*> request = obj.as<AsyncGeneratorRequest>();
     request->setCompletionKind(completionKind_);
     request->setCompletionValue(completionValue_);
     request->setPromise(promise_);
     return request;
 }
 
-// Async Iteration proposal 6.4.3.2 steps 5.d-g.
+// Async Iteration proposal 11.4.3.2 AsyncGeneratorStart steps 5.d-g.
 static MOZ_MUST_USE bool
 AsyncGeneratorReturned(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
                        HandleValue value)
 {
     // Step 5.d.
     asyncGenObj->setCompleted();
 
     // Step 5.e (done in bytecode).
     // Step 5.f.i (implicit).
 
     // Step 5.g.
     return AsyncGeneratorResolve(cx, asyncGenObj, value, true);
 }
 
-// Async Iteration proposal 6.4.3.2 steps 5.d, f.
+// Async Iteration proposal 11.4.3.2 AsyncGeneratorStart steps 5.d, f.
 static MOZ_MUST_USE bool
 AsyncGeneratorThrown(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
 {
     // Step 5.d.
     asyncGenObj->setCompleted();
 
     // Not much we can do about uncatchable exceptions, so just bail.
     if (!cx->isExceptionPending())
@@ -417,130 +431,81 @@ AsyncGeneratorThrown(JSContext* cx, Hand
     RootedValue value(cx);
     if (!GetAndClearException(cx, &value))
         return false;
 
     // Step 5.f.ii.
     return AsyncGeneratorReject(cx, asyncGenObj, value);
 }
 
-// Async Iteration proposal 6.4.3.5.
-MOZ_MUST_USE bool
-js::AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
+// Async Iteration proposal 11.4.3.7 (partially).
+// Most steps are done in generator.
+static MOZ_MUST_USE bool
+AsyncGeneratorYield(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj, HandleValue value)
 {
-    // Step 1 (implicit).
-
-    // Steps 2-3.
-    MOZ_ASSERT(!asyncGenObj->isExecuting());
+    // Step 5 is done in bytecode.
 
-    // Steps 4-5.
-    if (asyncGenObj->isQueueEmpty())
-        return true;
-
-    // Steps 6-7.
-    Rooted<AsyncGeneratorRequest*> request(
-        cx, AsyncGeneratorObject::peekRequest(cx, asyncGenObj));
-    if (!request)
-        return false;
-
-    // Step 8.
-    CompletionKind completionKind = request->completionKind();
+    // Step 6.
+    asyncGenObj->setSuspendedYield();
 
     // Step 9.
-    if (completionKind != CompletionKind::Normal) {
-        // Step 9.a.
-        if (asyncGenObj->isSuspendedStart())
-            asyncGenObj->setCompleted();
-
-        // Step 9.b.
-        if (asyncGenObj->isCompleted()) {
-            // Step 9.b.i.
-            RootedValue value(cx, request->completionValue());
-            if (completionKind == CompletionKind::Return)
-                return AsyncGeneratorResolve(cx, asyncGenObj, value, true);
-            // Step 9.b.ii.
-            return AsyncGeneratorReject(cx, asyncGenObj, value);
-        }
-    } else if (asyncGenObj->isCompleted()) {
-        // Step 10.
-        return AsyncGeneratorResolve(cx, asyncGenObj, UndefinedHandleValue, true);
-    }
-
-    // Step 11.
-    MOZ_ASSERT(asyncGenObj->isSuspendedStart() || asyncGenObj->isSuspendedYield());
-
-    // Step 15 (reordered).
-    asyncGenObj->setExecuting();
-
-    RootedValue argument(cx, request->completionValue());
-
-    // Steps 12-14, 16-20.
-    return AsyncGeneratorResume(cx, asyncGenObj, completionKind, argument);
-}
-
-// Async Iteration proposal 6.2.1.3 (partially).
-// Most steps are done in generator.
-static MOZ_MUST_USE bool
-AsyncGeneratorYield(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
-                    HandleValue value)
-{
-    // Step 5.
-    asyncGenObj->setSuspendedYield();
-
-    // Step 8.
     return AsyncGeneratorResolve(cx, asyncGenObj, value, false);
 }
 
-// Async Iteration proposal 6.4.3.5 steps 12-14, 16-20.
-// Async Iteration proposal 6.2.1.2 step 10.
-// Async Iteration proposal 6.4.3.2 step 5.f-g.
-// Async Iteration proposal 5.1 steps 2-9.
+// Async Iteration proposal 4.1 Await steps 2-9.
+// Async Iteration proposal 8.2.1 yield* steps 6.a.vii, 6.b.ii.7, 6.c.ix.
+// Async Iteration proposal 11.4.3.2 AsyncGeneratorStart step 5.f-g.
+// Async Iteration proposal 11.4.3.5 AsyncGeneratorResumeNext
+//   steps 12-14, 16-20.
 // Execution context switching is handled in generator.
-static MOZ_MUST_USE bool
-AsyncGeneratorResume(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
-                     CompletionKind completionKind, HandleValue argument)
+MOZ_MUST_USE bool
+js::AsyncGeneratorResume(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+                         CompletionKind completionKind, HandleValue argument)
 {
     RootedValue generatorVal(cx, asyncGenObj->generatorVal());
 
-    // 6.4.3.5 steps 12-14, 16-20.
+    // 11.4.3.5 steps 12-14, 16-20.
     HandlePropertyName funName = completionKind == CompletionKind::Normal
                                  ? cx->names().StarGeneratorNext
                                  : completionKind == CompletionKind::Throw
                                  ? cx->names().StarGeneratorThrow
                                  : cx->names().StarGeneratorReturn;
     FixedInvokeArgs<1> args(cx);
     args[0].set(argument);
     RootedValue result(cx);
     if (!CallSelfHostedFunction(cx, funName, generatorVal, args, &result)) {
-        // 6.4.3.2 step 5.d, f.
+        // 11.4.3.2 step 5.d, f.
         return AsyncGeneratorThrown(cx, asyncGenObj);
     }
 
+    // 4.1 steps 2-9.
     if (asyncGenObj->generatorObj()->isAfterAwait())
         return AsyncGeneratorAwait(cx, asyncGenObj, result);
 
     // The following code corresponds to the following 3 cases:
     //   * yield
     //   * yield*
     //   * return
     // For yield and return, property access is done on an internal result
     // object and it's not observable.
     // For yield*, it's done on a possibly user-provided result object, and
     // it's observable.
+    //
+    // Note that IteratorComplete steps in 8.2.1 are done in bytecode.
 
-    // 2.2.1 yield* steps 6.a.vii, 6.b.ii.7, 6.c.ix.
+    // 8.2.1 yield* steps 6.a.vii, 6.b.ii.7, 6.c.ix.
     RootedObject resultObj(cx, &result.toObject());
     RootedValue value(cx);
     if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
         return false;
 
     if (asyncGenObj->generatorObj()->isAfterYield())
         return AsyncGeneratorYield(cx, asyncGenObj, value);
 
-    // 6.4.3.2 step 5.d-g.
+    // 11.4.3.2 step 5.d-g.
     return AsyncGeneratorReturned(cx, asyncGenObj, value);
 }
 
 static const JSFunctionSpec async_iterator_proto_methods[] = {
     JS_SELF_HOSTED_SYM_FN(asyncIterator, "AsyncIteratorIdentity", 0, 0),
     JS_FS_END
 };
 
@@ -559,49 +524,49 @@ static const JSFunctionSpec async_genera
 };
 
 /* static */ MOZ_MUST_USE bool
 GlobalObject::initAsyncGenerators(JSContext* cx, Handle<GlobalObject*> global)
 {
     if (global->getReservedSlot(ASYNC_ITERATOR_PROTO).isObject())
         return true;
 
-    // Async Iteration proposal 6.1.2 %AsyncIteratorPrototype%.
+    // Async Iteration proposal 11.1.2 %AsyncIteratorPrototype%.
     RootedObject asyncIterProto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
     if (!asyncIterProto)
         return false;
     if (!DefinePropertiesAndFunctions(cx, asyncIterProto, nullptr, async_iterator_proto_methods))
         return false;
 
-    // Async Iteration proposal 6.1.3.2 %AsyncFromSyncIteratorPrototype%.
+    // Async Iteration proposal 11.1.3.2 %AsyncFromSyncIteratorPrototype%.
     RootedObject asyncFromSyncIterProto(
         cx, GlobalObject::createBlankPrototypeInheriting(cx, global, &PlainObject::class_,
                                                          asyncIterProto));
     if (!asyncFromSyncIterProto)
         return false;
     if (!DefinePropertiesAndFunctions(cx, asyncFromSyncIterProto, nullptr,
                                       async_from_sync_iter_methods) ||
         !DefineToStringTag(cx, asyncFromSyncIterProto, cx->names().AsyncFromSyncIterator))
     {
         return false;
     }
 
-    // Async Iteration proposal 6.4.1 %AsyncGeneratorPrototype%.
+    // Async Iteration proposal 11.4.1 %AsyncGeneratorPrototype%.
     RootedObject asyncGenProto(
         cx, GlobalObject::createBlankPrototypeInheriting(cx, global, &PlainObject::class_,
                                                          asyncIterProto));
     if (!asyncGenProto)
         return false;
     if (!DefinePropertiesAndFunctions(cx, asyncGenProto, nullptr, async_generator_methods) ||
         !DefineToStringTag(cx, asyncGenProto, cx->names().AsyncGenerator))
     {
         return false;
     }
 
-    // Async Iteration proposal 6.3.3 %AsyncGenerator%.
+    // Async Iteration proposal 11.3.3 %AsyncGenerator%.
     RootedObject asyncGenerator(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
     if (!asyncGenerator)
         return false;
     if (!JSObject::setDelegate(cx, asyncGenerator))
         return false;
     if (!LinkConstructorAndPrototype(cx, asyncGenerator, asyncGenProto, JSPROP_READONLY,
                                      JSPROP_READONLY) ||
         !DefineToStringTag(cx, asyncGenerator, cx->names().AsyncGeneratorFunction))
@@ -610,17 +575,17 @@ GlobalObject::initAsyncGenerators(JSCont
     }
 
     RootedValue function(cx, global->getConstructor(JSProto_Function));
     if (!function.toObjectOrNull())
         return false;
     RootedObject proto(cx, &function.toObject());
     RootedAtom name(cx, cx->names().AsyncGeneratorFunction);
 
-    // Async Iteration proposal 6.3.2 %AsyncGeneratorFunction%.
+    // Async Iteration proposal 11.3.2 %AsyncGeneratorFunction%.
     RootedObject asyncGenFunction(
         cx, NewFunctionWithProto(cx, AsyncGeneratorConstructor, 1, JSFunction::NATIVE_CTOR,
                                  nullptr, name, proto, gc::AllocKind::FUNCTION, SingletonObject));
     if (!asyncGenFunction)
         return false;
     if (!LinkConstructorAndPrototype(cx, asyncGenFunction, asyncGenerator,
                                      JSPROP_PERMANENT | JSPROP_READONLY, JSPROP_READONLY))
     {
--- a/js/src/vm/AsyncIteration.h
+++ b/js/src/vm/AsyncIteration.h
@@ -33,21 +33,28 @@ IsWrappedAsyncGenerator(JSFunction* fun)
 JSFunction*
 GetWrappedAsyncGenerator(JSFunction* unwrapped);
 
 JSFunction*
 GetUnwrappedAsyncGenerator(JSFunction* wrapped);
 
 MOZ_MUST_USE bool
 AsyncGeneratorAwaitedFulfilled(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
-                              HandleValue value);
-
+                               HandleValue value);
 MOZ_MUST_USE bool
 AsyncGeneratorAwaitedRejected(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
-                             HandleValue reason);
+                              HandleValue reason);
+MOZ_MUST_USE bool
+AsyncGeneratorYieldReturnAwaitedFulfilled(JSContext* cx,
+                                          Handle<AsyncGeneratorObject*> asyncGenObj,
+                                          HandleValue value);
+MOZ_MUST_USE bool
+AsyncGeneratorYieldReturnAwaitedRejected(JSContext* cx,
+                                         Handle<AsyncGeneratorObject*> asyncGenObj,
+                                         HandleValue reason);
 
 class AsyncGeneratorRequest : public NativeObject
 {
   private:
     enum AsyncGeneratorRequestSlots {
         Slot_CompletionKind = 0,
         Slot_CompletionValue,
         Slot_Promise,
@@ -92,16 +99,22 @@ class AsyncGeneratorObject : public Nati
         Slot_QueueOrRequest,
         Slots
     };
 
     enum State {
         State_SuspendedStart,
         State_SuspendedYield,
         State_Executing,
+        // State_AwaitingYieldReturn corresponds to the case that
+        // AsyncGenerator#return is called while State_Executing,
+        // just like the case that AsyncGenerator#return is called
+        // while State_Completed.
+        State_AwaitingYieldReturn,
+        State_AwaitingReturn,
         State_Completed
     };
 
     State state() const {
         return static_cast<State>(getFixedSlot(Slot_State).toInt32());
     }
     void setState(State state_) {
         setFixedSlot(Slot_State, Int32Value(state_));
@@ -150,29 +163,41 @@ class AsyncGeneratorObject : public Nati
         return state() == State_SuspendedStart;
     }
     bool isSuspendedYield() const {
         return state() == State_SuspendedYield;
     }
     bool isExecuting() const {
         return state() == State_Executing;
     }
+    bool isAwaitingYieldReturn() const {
+        return state() == State_AwaitingYieldReturn;
+    }
+    bool isAwaitingReturn() const {
+        return state() == State_AwaitingReturn;
+    }
     bool isCompleted() const {
         return state() == State_Completed;
     }
 
     void setSuspendedStart() {
         setState(State_SuspendedStart);
     }
     void setSuspendedYield() {
         setState(State_SuspendedYield);
     }
     void setExecuting() {
         setState(State_Executing);
     }
+    void setAwaitingYieldReturn() {
+        setState(State_AwaitingYieldReturn);
+    }
+    void setAwaitingReturn() {
+        setState(State_AwaitingReturn);
+    }
     void setCompleted() {
         setState(State_Completed);
     }
 
     JS::Value generatorVal() const {
         return getFixedSlot(Slot_Generator);
     }
     GeneratorObject* generatorObj() const {
@@ -218,13 +243,14 @@ class AsyncFromSyncIteratorObject : publ
     create(JSContext* cx, HandleObject iter);
 
     JSObject* iterator() const {
         return &getFixedSlot(Slot_Iterator).toObject();
     }
 };
 
 MOZ_MUST_USE bool
-AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj);
+AsyncGeneratorResume(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+                     CompletionKind completionKind, HandleValue argument);
 
 } // namespace js
 
 #endif /* vm_AsyncIteration_h */