Bug 1343481 - Part 7: Add BytecodeEmitter::emitDotGenerator and make yield/await nodes unary. r=shu
authorTooru Fujisawa <arai_a@mac.com>
Wed, 01 Mar 2017 20:40:05 +0900
changeset 374323 bf3219269a11aff5b64a61b6c782aa97bb4594c1
parent 374322 b623bf54b41f1ba8a406851e19e74340417540b9
child 374324 fb5e539b6624112a60be8ac65058d2a2116e2c04
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshu
bugs1343481
milestone54.0a1
Bug 1343481 - Part 7: Add BytecodeEmitter::emitDotGenerator and make yield/await nodes unary. r=shu
js/src/builtin/ReflectParse.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/FoldConstants.cpp
js/src/frontend/FullParseHandler.h
js/src/frontend/NameFunctions.cpp
js/src/frontend/ParseNode.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/SyntaxParseHandler.h
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -2797,21 +2797,21 @@ ASTSerializer::generatorExpression(Parse
             next = next->pn_kid2;
         } else {
             break;
         }
     }
 
     LOCAL_ASSERT(next->isKind(PNK_SEMI) &&
                  next->pn_kid->isKind(PNK_YIELD) &&
-                 next->pn_kid->pn_left);
+                 next->pn_kid->pn_kid);
 
     RootedValue body(cx);
 
-    return expression(next->pn_kid->pn_left, &body) &&
+    return expression(next->pn_kid->pn_kid, &body) &&
            builder.generatorExpression(body, blocks, filter, isLegacy, &pn->pn_pos, dst);
 }
 
 bool
 ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
 {
     if (!CheckRecursionLimit(cx))
         return false;
@@ -3145,29 +3145,29 @@ ASTSerializer::expression(ParseNode* pn,
       case PNK_TRUE:
       case PNK_FALSE:
       case PNK_NULL:
       case PNK_RAW_UNDEFINED:
         return literal(pn, dst);
 
       case PNK_YIELD_STAR:
       {
-        MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
+        MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
 
         RootedValue arg(cx);
-        return expression(pn->pn_left, &arg) &&
+        return expression(pn->pn_kid, &arg) &&
                builder.yieldExpression(arg, Delegating, &pn->pn_pos, dst);
       }
 
       case PNK_YIELD:
       {
-        MOZ_ASSERT_IF(pn->pn_left, pn->pn_pos.encloses(pn->pn_left->pn_pos));
+        MOZ_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos));
 
         RootedValue arg(cx);
-        return optExpression(pn->pn_left, &arg) &&
+        return optExpression(pn->pn_kid, &arg) &&
                builder.yieldExpression(arg, NotDelegating, &pn->pn_pos, dst);
       }
 
       case PNK_ARRAYCOMP:
         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_head->pn_pos));
 
         /* NB: it's no longer the case that pn_count could be 2. */
         LOCAL_ASSERT(pn->pn_count == 1);
@@ -3469,17 +3469,17 @@ ASTSerializer::functionArgsAndBody(Parse
         return functionArgs(pn, pnargs, args, defaults, rest) &&
                expression(pnbody->pn_kid, body);
 
       case PNK_STATEMENTLIST:     /* statement closure */
       {
         ParseNode* pnstart = pnbody->pn_head;
 
         // Skip over initial yield in generator.
-        if (pnstart && pnstart->isKind(PNK_YIELD)) {
+        if (pnstart && pnstart->isKind(PNK_INITIALYIELD)) {
             MOZ_ASSERT(pnstart->getOp() == JSOP_INITIALYIELD);
             pnstart = pnstart->pn_next;
         }
 
         // Async arrow with expression body is converted into STATEMENTLIST
         // to insert initial yield.
         if (isAsync && isExpression) {
             MOZ_ASSERT(pnstart->getKind() == PNK_RETURN);
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -3158,20 +3158,21 @@ BytecodeEmitter::checkSideEffects(ParseN
         return true;
 
       // This invokes the (user-controllable) iterator protocol.
       case PNK_SPREAD:
         MOZ_ASSERT(pn->isArity(PN_UNARY));
         *answer = true;
         return true;
 
+      case PNK_INITIALYIELD:
       case PNK_YIELD_STAR:
       case PNK_YIELD:
       case PNK_AWAIT:
-        MOZ_ASSERT(pn->isArity(PN_BINARY));
+        MOZ_ASSERT(pn->isArity(PN_UNARY));
         *answer = true;
         return true;
 
       // Deletion generally has side effects, even if isolated cases have none.
       case PNK_DELETENAME:
       case PNK_DELETEPROP:
       case PNK_DELETEELEM:
         MOZ_ASSERT(pn->isArity(PN_UNARY));
@@ -8324,55 +8325,71 @@ BytecodeEmitter::emitReturn(ParseNode* p
         if (!emit1(JSOP_RETRVAL))
             return false;
     }
 
     return true;
 }
 
 bool
+BytecodeEmitter::emitGetDotGenerator()
+{
+    NameLocation loc = *locationOfNameBoundInFunctionScope(cx->names().dotGenerator);
+    return emitGetNameAtLocation(cx->names().dotGenerator, loc);
+}
+
+bool
+BytecodeEmitter::emitInitialYield(ParseNode* pn)
+{
+    if (!emitTree(pn->pn_kid))
+        return false;
+
+    if (!emitYieldOp(JSOP_INITIALYIELD))
+        return false;
+
+    if (!emit1(JSOP_POP))
+        return false;
+
+    return true;
+}
+
+bool
 BytecodeEmitter::emitYield(ParseNode* pn)
 {
     MOZ_ASSERT(sc->isFunctionBox());
-
-    if (pn->getOp() == JSOP_YIELD || pn->getOp() == JSOP_AWAIT) {
-        bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
-        if (needsIteratorResult) {
-            if (!emitPrepareIteratorResult())
-                return false;
-        }
-        if (pn->pn_left) {
-            if (!emitTree(pn->pn_left))
-                return false;
-        } else {
-            if (!emit1(JSOP_UNDEFINED))
-                return false;
-        }
-        if (needsIteratorResult) {
-            if (!emitFinishIteratorResult(false))
-                return false;
-        }
+    MOZ_ASSERT(pn->getOp() == JSOP_YIELD || pn->getOp() == JSOP_AWAIT);
+
+    bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
+    if (needsIteratorResult) {
+        if (!emitPrepareIteratorResult())
+            return false;
+    }
+    if (pn->pn_kid) {
+        if (!emitTree(pn->pn_kid))
+            return false;
     } else {
-        MOZ_ASSERT(pn->getOp() == JSOP_INITIALYIELD);
-    }
-
-    if (!emitTree(pn->pn_right))
+        if (!emit1(JSOP_UNDEFINED))
+            return false;
+    }
+    if (needsIteratorResult) {
+        if (!emitFinishIteratorResult(false))
+            return false;
+    }
+
+    if (!emitGetDotGenerator())
         return false;
 
     if (!emitYieldOp(pn->getOp()))
         return false;
 
-    if (pn->getOp() == JSOP_INITIALYIELD && !emit1(JSOP_POP))
-        return false;
-
-    return true;
-}
-
-bool
-BytecodeEmitter::emitYieldStar(ParseNode* iter, ParseNode* gen)
+    return true;
+}
+
+bool
+BytecodeEmitter::emitYieldStar(ParseNode* iter)
 {
     MOZ_ASSERT(sc->isFunctionBox());
     MOZ_ASSERT(sc->asFunctionBox()->isStarGenerator());
 
     if (!emitTree(iter))                                  // ITERABLE
         return false;
     if (!emitIterator())                                  // ITER
         return false;
@@ -8392,17 +8409,17 @@ BytecodeEmitter::emitYieldStar(ParseNode
 
     JumpTarget tryStart{ offset() };
     if (!tryCatch.emitTry())                              // ITER RESULT
         return false;
 
     MOZ_ASSERT(this->stackDepth == startDepth);
 
     // Load the generator object.
-    if (!emitTree(gen))                                   // ITER RESULT GENOBJ
+    if (!emitGetDotGenerator())                           // ITER RESULT GENOBJ
         return false;
 
     // Yield RESULT as-is, without re-boxing.
     if (!emitYieldOp(JSOP_YIELD))                         // ITER RECEIVED
         return false;
 
     if (!tryCatch.emitCatch())                            // ITER RESULT
         return false;
@@ -10111,18 +10128,17 @@ BytecodeEmitter::emitFunctionBody(ParseN
         if (needsIteratorResult) {
             if (!emitFinishIteratorResult(true))
                 return false;
         }
 
         if (!emit1(JSOP_SETRVAL))
             return false;
 
-        NameLocation loc = *locationOfNameBoundInFunctionScope(cx->names().dotGenerator);
-        if (!emitGetNameAtLocation(cx->names().dotGenerator, loc))
+        if (!emitGetDotGenerator())
             return false;
 
         // No need to check for finally blocks, etc as in EmitReturn.
         if (!emitYieldOp(JSOP_FINALYIELDRVAL))
             return false;
     } else {
         // Non-generator functions just return |undefined|. The
         // JSOP_RETRVAL emitted below will do that, except if the
@@ -10365,25 +10381,30 @@ BytecodeEmitter::emitTree(ParseNode* pn,
         break;
 
       case PNK_RETURN:
         if (!emitReturn(pn))
             return false;
         break;
 
       case PNK_YIELD_STAR:
-        if (!emitYieldStar(pn->pn_left, pn->pn_right))
+        if (!emitYieldStar(pn->pn_kid))
             return false;
         break;
 
       case PNK_GENERATOR:
         if (!emit1(JSOP_GENERATOR))
             return false;
         break;
 
+      case PNK_INITIALYIELD:
+        if (!emitInitialYield(pn))
+            return false;
+        break;
+
       case PNK_YIELD:
       case PNK_AWAIT:
         if (!emitYield(pn))
             return false;
         break;
 
       case PNK_STATEMENTLIST:
         if (!emitStatementList(pn))
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -593,19 +593,22 @@ struct MOZ_STACK_CLASS BytecodeEmitter
 
     MOZ_MUST_USE bool emitNewInit(JSProtoKey key);
     MOZ_MUST_USE bool emitSingletonInitialiser(ParseNode* pn);
 
     MOZ_MUST_USE bool emitPrepareIteratorResult();
     MOZ_MUST_USE bool emitFinishIteratorResult(bool done);
     MOZ_MUST_USE bool iteratorResultShape(unsigned* shape);
 
+    MOZ_MUST_USE bool emitGetDotGenerator();
+
+    MOZ_MUST_USE bool emitInitialYield(ParseNode* pn);
     MOZ_MUST_USE bool emitYield(ParseNode* pn);
     MOZ_MUST_USE bool emitYieldOp(JSOp op);
-    MOZ_MUST_USE bool emitYieldStar(ParseNode* iter, ParseNode* gen);
+    MOZ_MUST_USE bool emitYieldStar(ParseNode* iter);
 
     MOZ_MUST_USE bool emitPropLHS(ParseNode* pn);
     MOZ_MUST_USE bool emitPropOp(ParseNode* pn, JSOp op);
     MOZ_MUST_USE bool emitPropIncDec(ParseNode* pn);
 
     MOZ_MUST_USE bool emitAsyncWrapperLambda(unsigned index, bool isArrow);
     MOZ_MUST_USE bool emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow);
 
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -113,19 +113,20 @@ ContainsHoistedDeclaration(JSContext* cx
       case PNK_THROW:
       case PNK_RETURN:
         MOZ_ASSERT(node->isArity(PN_UNARY));
         *result = false;
         return true;
 
       // These two aren't statements in the spec, but we sometimes insert them
       // in statement lists anyway.
+      case PNK_INITIALYIELD:
       case PNK_YIELD_STAR:
       case PNK_YIELD:
-        MOZ_ASSERT(node->isArity(PN_BINARY));
+        MOZ_ASSERT(node->isArity(PN_UNARY));
         *result = false;
         return true;
 
       // Other statements with no sub-statement components.
       case PNK_BREAK:
       case PNK_CONTINUE:
       case PNK_IMPORT:
       case PNK_IMPORT_SPEC_LIST:
@@ -1779,31 +1780,33 @@ Fold(JSContext* cx, ParseNode** pnp, Par
       case PNK_LET:
       case PNK_PARAMSBODY:
       case PNK_CALLSITEOBJ:
       case PNK_EXPORT_SPEC_LIST:
       case PNK_IMPORT_SPEC_LIST:
       case PNK_GENEXP:
         return FoldList(cx, pn, parser, inGenexpLambda);
 
+      case PNK_INITIALYIELD:
+        MOZ_ASSERT(pn->isArity(PN_UNARY));
+        MOZ_ASSERT(pn->pn_kid->isKind(PNK_ASSIGN) &&
+                   pn->pn_kid->pn_left->isKind(PNK_NAME) &&
+                   pn->pn_kid->pn_right->isKind(PNK_GENERATOR));
+        return true;
+
       case PNK_YIELD_STAR:
-        MOZ_ASSERT(pn->isArity(PN_BINARY));
-        MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME));
-        return Fold(cx, &pn->pn_left, parser, inGenexpLambda);
+        MOZ_ASSERT(pn->isArity(PN_UNARY));
+        return Fold(cx, &pn->pn_kid, parser, inGenexpLambda);
 
       case PNK_YIELD:
       case PNK_AWAIT:
-        MOZ_ASSERT(pn->isArity(PN_BINARY));
-        MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME) ||
-                   (pn->pn_right->isKind(PNK_ASSIGN) &&
-                    pn->pn_right->pn_left->isKind(PNK_NAME) &&
-                    pn->pn_right->pn_right->isKind(PNK_GENERATOR)));
-        if (!pn->pn_left)
+        MOZ_ASSERT(pn->isArity(PN_UNARY));
+        if (!pn->pn_kid)
             return true;
-        return Fold(cx, &pn->pn_left, parser, inGenexpLambda);
+        return Fold(cx, &pn->pn_kid, parser, inGenexpLambda);
 
       case PNK_RETURN:
         return FoldReturn(cx, pn, parser, inGenexpLambda);
 
       case PNK_TRY:
         return FoldTry(cx, pn, parser, inGenexpLambda);
 
       case PNK_CATCH:
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -422,30 +422,34 @@ class FullParseHandler
 
         ParseNode* classMethod = new_<ClassMethod>(key, fn, op, isStatic);
         if (!classMethod)
             return false;
         methodList->append(classMethod);
         return true;
     }
 
-    ParseNode* newYieldExpression(uint32_t begin, ParseNode* value, ParseNode* gen,
-                                  JSOp op = JSOP_YIELD) {
-        TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
-        return new_<BinaryNode>(PNK_YIELD, op, pos, value, gen);
+    ParseNode* newInitialYieldExpression(uint32_t begin, ParseNode* gen) {
+        TokenPos pos(begin, begin + 1);
+        return new_<UnaryNode>(PNK_INITIALYIELD, JSOP_INITIALYIELD, pos, gen);
     }
 
-    ParseNode* newYieldStarExpression(uint32_t begin, ParseNode* value, ParseNode* gen) {
-        TokenPos pos(begin, value->pn_pos.end);
-        return new_<BinaryNode>(PNK_YIELD_STAR, JSOP_NOP, pos, value, gen);
+    ParseNode* newYieldExpression(uint32_t begin, ParseNode* value) {
+        TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
+        return new_<UnaryNode>(PNK_YIELD, JSOP_YIELD, pos, value);
     }
 
-    ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value, ParseNode* gen) {
+    ParseNode* newYieldStarExpression(uint32_t begin, ParseNode* value) {
+        TokenPos pos(begin, value->pn_pos.end);
+        return new_<UnaryNode>(PNK_YIELD_STAR, JSOP_NOP, pos, value);
+    }
+
+    ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value) {
         TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
-        return new_<BinaryNode>(PNK_AWAIT, JSOP_AWAIT, pos, value, gen);
+        return new_<UnaryNode>(PNK_AWAIT, JSOP_AWAIT, pos, value);
     }
 
     // Statements
 
     ParseNode* newStatementList(const TokenPos& pos) {
         return new_<ListNode>(PNK_STATEMENTLIST, pos);
     }
 
@@ -488,18 +492,17 @@ class FullParseHandler
             return false;
 
         MOZ_ASSERT(genName->getOp() == JSOP_GETNAME);
         genName->setOp(JSOP_SETNAME);
         ParseNode* genInit = newBinary(PNK_ASSIGN, genName, makeGen);
         if (!genInit)
             return false;
 
-        ParseNode* initialYield = newYieldExpression(yieldPos.begin, nullptr, genInit,
-                                                     JSOP_INITIALYIELD);
+        ParseNode* initialYield = newInitialYieldExpression(yieldPos.begin, genInit);
         if (!initialYield)
             return false;
 
         stmtList->prepend(initialYield);
         return true;
     }
 
     ParseNode* newSetThis(ParseNode* thisName, ParseNode* val) {
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -496,34 +496,35 @@ class NameResolver
             if (ParseNode* caseExpr = cur->pn_left) {
                 if (!resolve(caseExpr, prefix))
                     return false;
             }
             if (!resolve(cur->pn_right, prefix))
                 return false;
             break;
 
+          case PNK_INITIALYIELD:
+            MOZ_ASSERT(cur->pn_kid->isKind(PNK_ASSIGN) &&
+                       cur->pn_kid->pn_left->isKind(PNK_NAME) &&
+                       cur->pn_kid->pn_right->isKind(PNK_GENERATOR));
+            break;
+
           case PNK_YIELD_STAR:
-            MOZ_ASSERT(cur->isArity(PN_BINARY));
-            MOZ_ASSERT(cur->pn_right->isKind(PNK_NAME));
-            if (!resolve(cur->pn_left, prefix))
+            MOZ_ASSERT(cur->isArity(PN_UNARY));
+            if (!resolve(cur->pn_kid, prefix))
                 return false;
             break;
 
           case PNK_YIELD:
           case PNK_AWAIT:
-            MOZ_ASSERT(cur->isArity(PN_BINARY));
-            if (cur->pn_left) {
-                if (!resolve(cur->pn_left, prefix))
+            MOZ_ASSERT(cur->isArity(PN_UNARY));
+            if (cur->pn_kid) {
+                if (!resolve(cur->pn_kid, prefix))
                     return false;
             }
-            MOZ_ASSERT(cur->pn_right->isKind(PNK_NAME) ||
-                       (cur->pn_right->isKind(PNK_ASSIGN) &&
-                        cur->pn_right->pn_left->isKind(PNK_NAME) &&
-                        cur->pn_right->pn_right->isKind(PNK_GENERATOR)));
             break;
 
           case PNK_RETURN:
             MOZ_ASSERT(cur->isArity(PN_UNARY));
             if (ParseNode* returnValue = cur->pn_kid) {
                 if (!resolve(returnValue, prefix))
                     return false;
             }
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -281,32 +281,34 @@ PushNodeChildren(ParseNode* pn, NodeStac
       case PNK_CLASSNAMES: {
         MOZ_ASSERT(pn->isArity(PN_BINARY));
         if (pn->pn_left)
             stack->push(pn->pn_left);
         stack->push(pn->pn_right);
         return PushResult::Recyclable;
       }
 
-      // The left half is the expression being yielded.  The right half is
-      // internal goop: a name reference to the invisible '.generator' local
-      // variable, or an assignment of a PNK_GENERATOR node to the '.generator'
-      // local, for a synthesized, prepended initial yield.  Yum!
+      // The child is an assignment of a PNK_GENERATOR node to the
+      // '.generator' local, for a synthesized, prepended initial yield.
+      case PNK_INITIALYIELD: {
+        MOZ_ASSERT(pn->isArity(PN_UNARY));
+        MOZ_ASSERT(pn->pn_kid->isKind(PNK_ASSIGN) &&
+                   pn->pn_kid->pn_left->isKind(PNK_NAME) &&
+                   pn->pn_kid->pn_right->isKind(PNK_GENERATOR));
+        stack->push(pn->pn_kid);
+        return PushResult::Recyclable;
+      }
+
+      // The child is the expression being yielded.
       case PNK_YIELD_STAR:
       case PNK_YIELD:
       case PNK_AWAIT: {
-        MOZ_ASSERT(pn->isArity(PN_BINARY));
-        MOZ_ASSERT(pn->pn_right);
-        MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME) ||
-                   (pn->pn_right->isKind(PNK_ASSIGN) &&
-                    pn->pn_right->pn_left->isKind(PNK_NAME) &&
-                    pn->pn_right->pn_right->isKind(PNK_GENERATOR)));
-        if (pn->pn_left)
-            stack->push(pn->pn_left);
-        stack->push(pn->pn_right);
+        MOZ_ASSERT(pn->isArity(PN_UNARY));
+        if (pn->pn_kid)
+            stack->push(pn->pn_kid);
         return PushResult::Recyclable;
       }
 
       // A return node's child is what you'd expect: the return expression,
       // if any.
       case PNK_RETURN: {
         MOZ_ASSERT(pn->isArity(PN_UNARY));
         if (pn->pn_kid)
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -78,16 +78,17 @@ class ObjectBox;
     F(DELETEELEM) \
     F(DELETEEXPR) \
     F(TRY) \
     F(CATCH) \
     F(CATCHLIST) \
     F(THROW) \
     F(DEBUGGER) \
     F(GENERATOR) \
+    F(INITIALYIELD) \
     F(YIELD) \
     F(YIELD_STAR) \
     F(GENEXP) \
     F(ARRAYCOMP) \
     F(ARRAYPUSH) \
     F(LEXICALSCOPE) \
     F(LET) \
     F(IMPORT) \
@@ -412,18 +413,19 @@ IsTypeofKind(ParseNodeKind kind)
  * PNK_THIS,        unary   pn_kid: '.this' Name if function `this`, else nullptr
  * PNK_SUPERBASE    unary   pn_kid: '.this' Name
  *
  * PNK_SETTHIS      binary  pn_left: '.this' Name, pn_right: SuperCall
  *
  * PNK_LEXICALSCOPE scope   pn_u.scope.bindings: scope bindings
  *                          pn_u.scope.body: scope body
  * PNK_GENERATOR    nullary
- * PNK_YIELD,       binary  pn_left: expr or null
- * PNK_YIELD_STAR,          pn_right: generator object
+ * PNK_INITIALYIELD unary   pn_kid: generator object
+ * PNK_YIELD,       unary   pn_kid: expr or null
+ * PNK_YIELD_STAR,
  * PNK_AWAIT
  * PNK_ARRAYCOMP    list    pn_count: 1
  *                          pn_head: list of 1 element, which is block
  *                          enclosing for loop(s) and optionally
  *                          if-guarded PNK_ARRAYPUSH
  * PNK_ARRAYPUSH    unary   pn_op: JSOP_ARRAYCOMP
  *                          pn_kid: array comprehension expression
  * PNK_NOP          nullary
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -6366,39 +6366,16 @@ Parser<ParseHandler>::returnStatement(Yi
         return null();
     }
 
     return pn;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::newYieldExpression(uint32_t begin, typename ParseHandler::Node expr,
-                                         bool isYieldStar)
-{
-    Node generator = newDotGeneratorName();
-    if (!generator)
-        return null();
-    if (isYieldStar)
-        return handler.newYieldStarExpression(begin, expr, generator);
-    return handler.newYieldExpression(begin, expr, generator);
-}
-
-template <typename ParseHandler>
-typename ParseHandler::Node
-Parser<ParseHandler>::newAwaitExpression(uint32_t begin, typename ParseHandler::Node expr)
-{
-    Node generator = newDotGeneratorName();
-    if (!generator)
-        return null();
-    return handler.newAwaitExpression(begin, expr, generator);
-}
-
-template <typename ParseHandler>
-typename ParseHandler::Node
 Parser<ParseHandler>::yieldExpression(InHandling inHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_YIELD));
     uint32_t begin = pos().begin;
 
     switch (pc->generatorKind()) {
       case StarGenerator:
       {
@@ -6435,17 +6412,19 @@ Parser<ParseHandler>::yieldExpression(In
             kind = PNK_YIELD_STAR;
             tokenStream.consumeKnownToken(TOK_MUL, TokenStream::Operand);
             MOZ_FALLTHROUGH;
           default:
             exprNode = assignExpr(inHandling, YieldIsKeyword, TripledotProhibited);
             if (!exprNode)
                 return null();
         }
-        return newYieldExpression(begin, exprNode, kind == PNK_YIELD_STAR);
+        if (kind == PNK_YIELD_STAR)
+            return handler.newYieldStarExpression(begin, exprNode);
+        return handler.newYieldExpression(begin, exprNode);
       }
 
       case NotGenerator:
         // We are in code that has not seen a yield, but we are in JS 1.7 or
         // later.  Try to transition to being a legacy generator.
         MOZ_ASSERT(tokenStream.versionNumber() >= JSVERSION_1_7);
         MOZ_ASSERT(pc->lastYieldOffset == ParseContext::NoYieldOffset);
 
@@ -6513,17 +6492,17 @@ Parser<ParseHandler>::yieldExpression(In
             tokenStream.addModifierException(TokenStream::NoneIsOperand);
             break;
           default:
             exprNode = assignExpr(inHandling, YieldIsKeyword, TripledotProhibited);
             if (!exprNode)
                 return null();
         }
 
-        return newYieldExpression(begin, exprNode);
+        return handler.newYieldExpression(begin, exprNode);
       }
     }
 
     MOZ_CRASH("yieldExpr");
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
@@ -8260,17 +8239,17 @@ Parser<ParseHandler>::unaryExpr(YieldHan
       }
 
       case TOK_AWAIT: {
         if (pc->isAsync()) {
             Node kid = unaryExpr(yieldHandling, tripledotHandling, possibleError, invoked);
             if (!kid)
                 return null();
             pc->lastAwaitOffset = begin;
-            return newAwaitExpression(begin, kid);
+            return handler.newAwaitExpression(begin, kid);
         }
       }
 
         MOZ_FALLTHROUGH;
 
       default: {
         Node expr = memberExpr(yieldHandling, tripledotHandling, tt, /* allowCallSyntax = */ true,
                                possibleError, invoked);
@@ -8517,17 +8496,17 @@ Parser<ParseHandler>::comprehensionTail(
     Node bodyExpr = assignExpr(InAllowed, YieldIsKeyword, TripledotProhibited);
     if (!bodyExpr)
         return null();
 
     if (comprehensionKind == NotGenerator)
         return handler.newArrayPush(begin, bodyExpr);
 
     MOZ_ASSERT(comprehensionKind == StarGenerator);
-    Node yieldExpr = newYieldExpression(begin, bodyExpr);
+    Node yieldExpr = handler.newYieldExpression(begin, bodyExpr);
     if (!yieldExpr)
         return null();
     yieldExpr = handler.parenthesize(yieldExpr);
 
     return handler.newExprStatement(yieldExpr, pos().end);
 }
 
 // Parse an ES6-era generator or array comprehension, starting at the first
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -1083,18 +1083,16 @@ class Parser final : public ParserBase, 
     bool taggedTemplate(YieldHandling yieldHandling, Node nodeList, TokenKind tt);
     bool appendToCallSiteObj(Node callSiteObj);
     bool addExprAndGetNextTemplStrToken(YieldHandling yieldHandling, Node nodeList,
                                         TokenKind* ttp);
     bool checkStatementsEOF();
 
     inline Node newName(PropertyName* name);
     inline Node newName(PropertyName* name, TokenPos pos);
-    inline Node newYieldExpression(uint32_t begin, Node expr, bool isYieldStar = false);
-    inline Node newAwaitExpression(uint32_t begin, Node expr);
 
     inline bool abortIfSyntaxParser();
 
   public:
     /* Public entry points for parsing. */
     Node statement(YieldHandling yieldHandling);
     Node statementListItem(YieldHandling yieldHandling, bool canHaveDirectives = false);
 
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -295,19 +295,19 @@ class SyntaxParseHandler
     Node newPosHolder(const TokenPos& pos) { return NodeGeneric; }
     Node newSuperBase(Node thisName, const TokenPos& pos) { return NodeSuperBase; }
 
     MOZ_MUST_USE bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; }
     MOZ_MUST_USE bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; }
     MOZ_MUST_USE bool addShorthand(Node literal, Node name, Node expr) { return true; }
     MOZ_MUST_USE bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; }
     MOZ_MUST_USE bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; }
-    Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
-    Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
-    Node newAwaitExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
+    Node newYieldExpression(uint32_t begin, Node value) { return NodeGeneric; }
+    Node newYieldStarExpression(uint32_t begin, Node value) { return NodeGeneric; }
+    Node newAwaitExpression(uint32_t begin, Node value) { return NodeGeneric; }
 
     // Statements
 
     Node newStatementList(const TokenPos& pos) { return NodeGeneric; }
     void addStatementToList(Node list, Node stmt) {}
     void addCaseStatementToList(Node list, Node stmt) {}
     MOZ_MUST_USE bool prependInitialYield(Node stmtList, Node gen) { return true; }
     Node newEmptyStatement(const TokenPos& pos) { return NodeEmptyStatement; }