Bug 1539132 - Part 5: Add assertions and comments for async-generator states. r=arai
authorAndré Bargull <andre.bargull@gmail.com>
Wed, 03 Apr 2019 20:02:50 +0000
changeset 467945 201c7691d719efc9b544018197c7b43b3a49ca1f
parent 467944 ef5b0d01d900190f3fcad092cba34c7d1e0dda5b
child 467946 e1d21ee0fa85adcacf0497e8e9b4122631241cd8
push id35813
push useraiakab@mozilla.com
push dateThu, 04 Apr 2019 16:07:30 +0000
treeherdermozilla-central@aa623df2ae8f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarai
bugs1539132
milestone68.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 1539132 - Part 5: Add assertions and comments for async-generator states. r=arai Differential Revision: https://phabricator.services.mozilla.com/D25573
js/src/builtin/Promise.cpp
js/src/vm/AsyncIteration.cpp
js/src/vm/AsyncIteration.h
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -1505,58 +1505,88 @@ static MOZ_MUST_USE bool AsyncGeneratorP
 
   // Await's handlers don't return a value, nor throw any exceptions.
   // They fail only on OOM.
 
   switch (handler) {
     // ES2020 draft rev a09fc232c137800dbf51b6204f37fdede4ba1646
     // 6.2.3.1.1 Await Fulfilled Functions
     case PromiseHandlerAsyncGeneratorAwaitedFulfilled: {
+      MOZ_ASSERT(asyncGenObj->isExecuting(),
+                 "Await fulfilled when not in 'Executing' state");
+
       return AsyncGeneratorAwaitedFulfilled(cx, asyncGenObj, argument);
     }
 
     // ES2020 draft rev a09fc232c137800dbf51b6204f37fdede4ba1646
     // 6.2.3.1.2 Await Rejected Functions
     case PromiseHandlerAsyncGeneratorAwaitedRejected: {
+      MOZ_ASSERT(asyncGenObj->isExecuting(),
+                 "Await rejected when not in 'Executing' state");
+
       return AsyncGeneratorAwaitedRejected(cx, asyncGenObj, argument);
     }
 
     // ES2020 draft rev a09fc232c137800dbf51b6204f37fdede4ba1646
     // 25.5.3.5.1 AsyncGeneratorResumeNext Return Processor Fulfilled Functions
     case PromiseHandlerAsyncGeneratorResumeNextReturnFulfilled: {
+      MOZ_ASSERT(asyncGenObj->isAwaitingReturn(),
+                 "AsyncGeneratorResumeNext-Return fulfilled when not in "
+                 "'AwaitingReturn' state");
+
       // Steps 1-2.
       asyncGenObj->setCompleted();
 
       // Step 3.
       return AsyncGeneratorResolve(cx, asyncGenObj, argument, true);
     }
 
     // ES2020 draft rev a09fc232c137800dbf51b6204f37fdede4ba1646
     // 25.5.3.5.2 AsyncGeneratorResumeNext Return Processor Rejected Functions
     case PromiseHandlerAsyncGeneratorResumeNextReturnRejected: {
+      MOZ_ASSERT(asyncGenObj->isAwaitingReturn(),
+                 "AsyncGeneratorResumeNext-Return rejected when not in "
+                 "'AwaitingReturn' state");
+
       // Steps 1-2.
       asyncGenObj->setCompleted();
 
       // Step 3.
       return AsyncGeneratorReject(cx, asyncGenObj, argument);
     }
 
     // ES2020 draft rev a09fc232c137800dbf51b6204f37fdede4ba1646
     // 25.5.3.7 AsyncGeneratorYield
     case PromiseHandlerAsyncGeneratorYieldReturnAwaitedFulfilled: {
+      MOZ_ASSERT(asyncGenObj->isAwaitingYieldReturn(),
+                 "YieldReturn-Await fulfilled when not in "
+                 "'AwaitingYieldReturn' state");
+
+      // We're using a separate 'AwaitingYieldReturn' state when awaiting a
+      // return completion in yield expressions, whereas the spec uses the
+      // 'Executing' state all along. So we now need to transition into the
+      // 'Executing' state.
       asyncGenObj->setExecuting();
 
       // Steps 8.d-e.
       return AsyncGeneratorYieldReturnAwaitedFulfilled(cx, asyncGenObj,
                                                        argument);
     }
 
     // ES2020 draft rev a09fc232c137800dbf51b6204f37fdede4ba1646
     // 25.5.3.7 AsyncGeneratorYield
     case PromiseHandlerAsyncGeneratorYieldReturnAwaitedRejected: {
+      MOZ_ASSERT(
+          asyncGenObj->isAwaitingYieldReturn(),
+          "YieldReturn-Await rejected when not in 'AwaitingYieldReturn' state");
+
+      // We're using a separate 'AwaitingYieldReturn' state when awaiting a
+      // return completion in yield expressions, whereas the spec uses the
+      // 'Executing' state all along. So we now need to transition into the
+      // 'Executing' state.
       asyncGenObj->setExecuting();
 
       // Step 8.c.
       return AsyncGeneratorYieldReturnAwaitedRejected(cx, asyncGenObj,
                                                       argument);
     }
 
     default:
@@ -3955,19 +3985,20 @@ static MOZ_MUST_USE bool AsyncGeneratorR
       }
     }
 
     // 25.5.3.5 AsyncGeneratorResumeNext ( generator )
     // Step 1: Assert: generator is an AsyncGenerator instance (implicit).
     // Step 2: Let state be generator.[[AsyncGeneratorState]] (implicit).
     // Step 3: Assert: state is not "executing".
     MOZ_ASSERT(!generator->isExecuting());
+    MOZ_ASSERT(!generator->isAwaitingYieldReturn());
 
     // Step 4: If state is "awaiting-return", return undefined.
-    if (generator->isAwaitingYieldReturn() || generator->isAwaitingReturn()) {
+    if (generator->isAwaitingReturn()) {
       return true;
     }
 
     // Step 5: Let queue be generator.[[AsyncGeneratorQueue]].
     // Step 6: If queue is an empty List, return undefined.
     if (generator->isQueueEmpty()) {
       return true;
     }
@@ -4056,20 +4087,16 @@ static MOZ_MUST_USE bool AsyncGeneratorR
       valueOrException.setUndefined();
       done = true;
       continue;
     }
 
     // Step 12: Assert: state is either "suspendedStart" or "suspendedYield".
     MOZ_ASSERT(generator->isSuspendedStart() || generator->isSuspendedYield());
 
-    // Step 16 (reordered): Set generator.[[AsyncGeneratorState]] to
-    //                      "executing".
-    generator->setExecuting();
-
     RootedValue argument(cx, request->completionValue());
 
     if (completionKind == CompletionKind::Return) {
       // 25.5.3.7 AsyncGeneratorYield steps 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.
       generator->setAwaitingYieldReturn();
@@ -4084,16 +4111,20 @@ static MOZ_MUST_USE bool AsyncGeneratorR
 
       auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
         reaction->setIsAsyncGenerator(generator);
       };
       return InternalAwait(cx, argument, nullptr, onFulfilled, onRejected,
                            extra);
     }
 
+    // Step 16 (reordered): Set generator.[[AsyncGeneratorState]] to
+    //                      "executing".
+    generator->setExecuting();
+
     // Steps 13-15, 17-21.
     return AsyncGeneratorResume(cx, generator, completionKind, argument);
   }
 }
 
 // 25.5.3.6 AsyncGeneratorEnqueue ( generator, completion )
 MOZ_MUST_USE bool js::AsyncGeneratorEnqueue(JSContext* cx,
                                             HandleValue asyncGenVal,
@@ -4140,17 +4171,17 @@ MOZ_MUST_USE bool js::AsyncGeneratorEnqu
   }
 
   // Steps 4, 6.
   if (!AsyncGeneratorObject::enqueueRequest(cx, asyncGenObj, request)) {
     return false;
   }
 
   // Step 7.
-  if (!asyncGenObj->isExecuting()) {
+  if (!asyncGenObj->isExecuting() && !asyncGenObj->isAwaitingYieldReturn()) {
     // Step 8.
     if (!AsyncGeneratorResumeNext(cx, asyncGenObj, ResumeNextKind::Enqueue)) {
       return false;
     }
   }
 
   // Step 9.
   result.setObject(*resultPromise);
--- a/js/src/vm/AsyncIteration.cpp
+++ b/js/src/vm/AsyncIteration.cpp
@@ -353,16 +353,18 @@ static MOZ_MUST_USE bool AsyncGeneratorY
 // Note: Execution context switching is handled in generator.
 MOZ_MUST_USE bool js::AsyncGeneratorResume(
     JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
     CompletionKind completionKind, HandleValue argument) {
   MOZ_ASSERT(!asyncGenObj->isClosed(),
              "closed generator when resuming async generator");
   MOZ_ASSERT(asyncGenObj->isSuspended(),
              "non-suspended generator when resuming async generator");
+  MOZ_ASSERT(asyncGenObj->isExecuting(),
+             "async generator not set into 'executing' state");
 
   // 25.5.3.5, steps 12-14, 16-20.
   HandlePropertyName funName = completionKind == CompletionKind::Normal
                                    ? cx->names().AsyncGeneratorNext
                                    : completionKind == CompletionKind::Throw
                                          ? cx->names().AsyncGeneratorThrow
                                          : cx->names().AsyncGeneratorReturn;
   FixedInvokeArgs<1> args(cx);
--- a/js/src/vm/AsyncIteration.h
+++ b/js/src/vm/AsyncIteration.h
@@ -130,17 +130,17 @@ class AsyncGeneratorObject : public Abst
     // or awaiting for `await` expression.
     State_Executing,
 
     // Part of "executing" in the spec.
     // Awaiting on the value passed by AsyncGenerator#return which is called
     // while executing.
     State_AwaitingYieldReturn,
 
-    // Part of "executing" in the spec.
+    // "awaiting-return" in the spec.
     // Awaiting on the value passed by AsyncGenerator#return which is called
     // after completed.
     State_AwaitingReturn,
 
     // "completed" in the spec.
     // The generator is completed.
     State_Completed
   };