Bug 1378808 - Add a new ParseNodeKind::Arguments node type for call argument lists. r=jorendorff draft
authorLogan F Smyth <loganfsmyth@gmail.com>
Thu, 12 Jul 2018 11:24:59 -0700
changeset 823736 4c8496ef42fee75992a449c257d7861ed1a23fec
parent 817312 fe17acc6e291e54463db3ea82697c714ae5a4b27
child 823737 3b4f4db5d3d78170faf00bdf9fe2a562ad155fd5
push id117772
push userbmo:loganfsmyth@gmail.com
push dateFri, 27 Jul 2018 23:49:53 +0000
reviewersjorendorff
bugs1378808
milestone63.0a1
Bug 1378808 - Add a new ParseNodeKind::Arguments node type for call argument lists. r=jorendorff MozReview-Commit-ID: 7L4nNHjVoZo
js/src/builtin/ReflectParse.cpp
js/src/frontend/BinSource-auto.cpp
js/src/frontend/BinSource.yaml
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.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/SyntaxParseHandler.h
js/src/wasm/AsmJS.cpp
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -2697,34 +2697,35 @@ ASTSerializer::expression(ParseNode* pn,
                builder.unaryExpression(op, expr, &pn->pn_pos, dst);
       }
 
       case ParseNodeKind::New:
       case ParseNodeKind::TaggedTemplate:
       case ParseNodeKind::Call:
       case ParseNodeKind::SuperCall:
       {
-        ParseNode* next = pn->pn_head;
-        MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
+        ParseNode* pn_callee = pn->pn_left;
+        ParseNode* pn_args = pn->pn_right;
+        MOZ_ASSERT(pn->pn_pos.encloses(pn_callee->pn_pos));
 
         RootedValue callee(cx);
         if (pn->isKind(ParseNodeKind::SuperCall)) {
-            MOZ_ASSERT(next->isKind(ParseNodeKind::SuperBase));
-            if (!builder.super(&next->pn_pos, &callee))
+            MOZ_ASSERT(pn_callee->isKind(ParseNodeKind::SuperBase));
+            if (!builder.super(&pn_callee->pn_pos, &callee))
                 return false;
         } else {
-            if (!expression(next, &callee))
+            if (!expression(pn_callee, &callee))
                 return false;
         }
 
         NodeVector args(cx);
-        if (!args.reserve(pn->pn_count - 1))
+        if (!args.reserve(pn_args->pn_count))
             return false;
 
-        for (next = next->pn_next; next; next = next->pn_next) {
+        for (ParseNode* next = pn_args->pn_head; next; next = next->pn_next) {
             MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
 
             RootedValue arg(cx);
             if (!expression(next, &arg))
                 return false;
             args.infallibleAppend(arg);
         }
 
--- a/js/src/frontend/BinSource-auto.cpp
+++ b/js/src/frontend/BinSource-auto.cpp
@@ -3457,19 +3457,18 @@ BinASTParser<Tok>::parseInterfaceCallExp
          && !parseContext_->innermostScope()->lookupDeclaredNameForAdd(callee->name())) {
             // This is a direct call to `eval`.
             if (!parseContext_->sc()->hasDirectEval())
                 return raiseMissingDirectEvalInAssertedScope();
 
             op = parseContext_->sc()->strict() ? JSOP_STRICTEVAL : JSOP_EVAL;
         }
     }
-    auto result = arguments;
-    result->setKind(ParseNodeKind::Call);
-    result->prepend(callee);
+
+    BINJS_TRY_DECL(result, factory_.newCall(callee, arguments));
     result->setOp(op);
     return result;
 }
 
 
 /*
  interface CatchClause : Node {
     AssertedParameterScope? bindingScope;
@@ -3737,17 +3736,17 @@ BinASTParser<Tok>::parseInterfaceCompute
     const BinField expected_fields[2] = { BinField::Object, BinField::Expression };
     MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif // defined(DEBUG)
 
     BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
 
     BINJS_MOZ_TRY_DECL(expression, parseExpression());
 
-    BINJS_TRY_DECL(result, factory_.newPropertyByValue(object, expression, start));
+    BINJS_TRY_DECL(result, factory_.newPropertyByValue(object, expression, tokenizer_->offset()));
     return result;
 }
 
 
 /*
  interface ComputedMemberExpression : Node {
     (Expression or Super) object;
     Expression expression;
@@ -3781,17 +3780,17 @@ BinASTParser<Tok>::parseInterfaceCompute
     const BinField expected_fields[2] = { BinField::Object, BinField::Expression };
     MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif // defined(DEBUG)
 
     BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
 
     BINJS_MOZ_TRY_DECL(expression, parseExpression());
 
-    BINJS_TRY_DECL(result, factory_.newPropertyByValue(object, expression, start));
+    BINJS_TRY_DECL(result, factory_.newPropertyByValue(object, expression, tokenizer_->offset()));
     return result;
 }
 
 
 /*
  interface ComputedPropertyName : Node {
     Expression expression;
  }
@@ -5672,20 +5671,17 @@ BinASTParser<Tok>::parseInterfaceNewExpr
     const BinField expected_fields[2] = { BinField::Callee, BinField::Arguments };
     MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif // defined(DEBUG)
 
     BINJS_MOZ_TRY_DECL(callee, parseExpression());
 
     BINJS_MOZ_TRY_DECL(arguments, parseArguments());
 
-    auto result = arguments;
-    result->setKind(ParseNodeKind::New);
-    result->prepend(callee);
-    result->setOp(JSOP_NEW);
+    BINJS_TRY_DECL(result, factory_.newNewExpression(tokenizer_->pos(start).begin, callee, arguments));
     return result;
 }
 
 
 /*
  interface NewTargetExpression : Node {
  }
 */
@@ -6198,17 +6194,17 @@ BinASTParser<Tok>::parseInterfaceStaticM
     MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif // defined(DEBUG)
 
     BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
 
     RootedAtom property(cx_);
     MOZ_TRY_VAR(property, tokenizer_->readAtom());
 
-    BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), start));
+    BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), tokenizer_->offset()));
     return result;
 }
 
 
 /*
  interface StaticMemberExpression : Node {
     (Expression or Super) object;
     IdentifierName property;
@@ -6243,17 +6239,17 @@ BinASTParser<Tok>::parseInterfaceStaticM
     MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif // defined(DEBUG)
 
     BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
 
     RootedAtom property(cx_);
     MOZ_TRY_VAR(property, tokenizer_->readAtom());
 
-    BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), start));
+    BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), tokenizer_->offset()));
     return result;
 }
 
 
 /*
  interface Super : Node {
  }
 */
@@ -7376,17 +7372,17 @@ BinASTParser<Tok>::parseVariableDeclarat
 template<typename Tok> JS::Result<ParseNode*>
 BinASTParser<Tok>::parseArguments()
 {
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
     MOZ_TRY(tokenizer_->enterList(length, guard));
-    BINJS_TRY_DECL(result, factory_.newList(ParseNodeKind::ParamsBody, tokenizer_->pos(start)));
+    BINJS_TRY_DECL(result, factory_.newList(ParseNodeKind::Arguments, tokenizer_->pos(start)));
 
     for (uint32_t i = 0; i < length; ++i) {
         BINJS_MOZ_TRY_DECL(item, parseSpreadElementOrExpression());
         factory_.addList(/* list = */ result, /* child = */ item);
     }
 
     MOZ_TRY(guard.done());
     return result;
--- a/js/src/frontend/BinSource.yaml
+++ b/js/src/frontend/BinSource.yaml
@@ -189,17 +189,17 @@ hpp:
 
             } // namespace frontend
             } // namespace js
 
             #endif // frontend_BinToken_h
 
 Arguments:
     init:
-        BINJS_TRY_DECL(result, factory_.newList(ParseNodeKind::ParamsBody, tokenizer_->pos(start)));
+        BINJS_TRY_DECL(result, factory_.newList(ParseNodeKind::Arguments, tokenizer_->pos(start)));
     append:
         factory_.addList(/* list = */ result, /* child = */ item);
 
 ArrayExpression:
     build:
         auto result = elements;
 
 AssertedBlockScope:
@@ -410,19 +410,18 @@ CallExpression:
              && !parseContext_->innermostScope()->lookupDeclaredNameForAdd(callee->name())) {
                 // This is a direct call to `eval`.
                 if (!parseContext_->sc()->hasDirectEval())
                     return raiseMissingDirectEvalInAssertedScope();
 
                 op = parseContext_->sc()->strict() ? JSOP_STRICTEVAL : JSOP_EVAL;
             }
         }
-        auto result = arguments;
-        result->setKind(ParseNodeKind::Call);
-        result->prepend(callee);
+
+        BINJS_TRY_DECL(result, factory_.newCall(callee, arguments));
         result->setOp(op);
 
 
 CatchClause:
     init: |
         ParseContext::Statement stmt(parseContext_, StatementKind::Catch);
         ParseContext::Scope currentScope(cx_, parseContext_, usedNames_);
         BINJS_TRY(currentScope.init(parseContext_));
@@ -471,21 +470,21 @@ CompoundAssignmentExpression:
           case CompoundAssignmentOperator::BitAndAssign:
             pnk = ParseNodeKind::BitAndAssign;
             break;
         }
         BINJS_TRY_DECL(result, factory_.newAssignment(pnk, binding, expression));
 
 ComputedMemberAssignmentTarget:
     build: |
-        BINJS_TRY_DECL(result, factory_.newPropertyByValue(object, expression, start));
+        BINJS_TRY_DECL(result, factory_.newPropertyByValue(object, expression, tokenizer_->offset()));
 
 ComputedMemberExpression:
     build: |
-        BINJS_TRY_DECL(result, factory_.newPropertyByValue(object, expression, start));
+        BINJS_TRY_DECL(result, factory_.newPropertyByValue(object, expression, tokenizer_->offset()));
 
 ConditionalExpression:
     build: |
         BINJS_TRY_DECL(result, factory_.newConditional(test, consequent, alternate));
 
 ContinueStatement:
     fields:
         label:
@@ -813,20 +812,17 @@ LiteralRegExpExpression:
         BINJS_TRY_DECL(result, factory_.newRegExp(reobj, tokenizer_->pos(start), *this));
 
 LiteralStringExpression:
     build:
         BINJS_TRY_DECL(result, factory_.newStringLiteral(value, tokenizer_->pos(start)));
 
 NewExpression:
     build: |
-        auto result = arguments;
-        result->setKind(ParseNodeKind::New);
-        result->prepend(callee);
-        result->setOp(JSOP_NEW);
+        BINJS_TRY_DECL(result, factory_.newNewExpression(tokenizer_->pos(start).begin, callee, arguments));
 
 ObjectExpression:
     build:
         auto result = properties;
 
 OptionalAssertedBlockScope:
     type-ok:
         Ok
@@ -905,21 +901,21 @@ SwitchStatementWithDefault:
             factory_.addList(cases, iter);
             iter = next;
         }
         BINJS_TRY_DECL(scope, factory_.newLexicalScope(nullptr, cases));
         BINJS_TRY_DECL(result, factory_.newSwitchStatement(start, discriminant, scope));
 
 StaticMemberAssignmentTarget:
     build: |
-        BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), start));
+        BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), tokenizer_->offset()));
 
 StaticMemberExpression:
     build: |
-        BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), start));
+        BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), tokenizer_->offset()));
 
 ThisExpression:
     build: |
         if (parseContext_->isFunctionBox())
             parseContext_->functionBox()->usesThis = true;
 
         TokenPos pos = tokenizer_->pos(start);
         ParseNode* thisName(nullptr);
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -3718,16 +3718,24 @@ BytecodeEmitter::checkSideEffects(ParseN
             goto restart;
         return true;
 
       // Function calls can invoke non-local code.
       case ParseNodeKind::New:
       case ParseNodeKind::Call:
       case ParseNodeKind::TaggedTemplate:
       case ParseNodeKind::SuperCall:
+        MOZ_ASSERT(pn->isArity(PN_BINARY));
+        *answer = true;
+        return true;
+
+      // Function arg lists can contain arbitrary expressions. Technically
+      // this only causes side-effects if one of the arguments does, but since
+      // the call being made will always trigger side-effects, it isn't needed.
+      case ParseNodeKind::Arguments:
         MOZ_ASSERT(pn->isArity(PN_LIST));
         *answer = true;
         return true;
 
       case ParseNodeKind::Pipeline:
         MOZ_ASSERT(pn->isArity(PN_LIST));
         MOZ_ASSERT(pn->pn_count >= 2);
         *answer = true;
@@ -7486,17 +7494,17 @@ BytecodeEmitter::emitForOf(ParseNode* fo
 
     ParseNode* forHeadExpr = forOfHead->pn_kid3;
 
     // Certain builtins (e.g. Array.from) are implemented in self-hosting
     // as for-of loops.
     bool allowSelfHostedIter = false;
     if (emitterMode == BytecodeEmitter::SelfHosting &&
         forHeadExpr->isKind(ParseNodeKind::Call) &&
-        forHeadExpr->pn_head->name() == cx->names().allowContentIter)
+        forHeadExpr->pn_left->name() == cx->names().allowContentIter)
     {
         allowSelfHostedIter = true;
     }
 
     // Evaluate the expression being iterated. The forHeadExpr should use a
     // distinct TDZCheckCache to evaluate since (abstractly) it runs in its own
     // LexicalEnvironment.
     if (!emitTreeInBranch(forHeadExpr))                   // ITERABLE
@@ -9188,45 +9196,47 @@ BytecodeEmitter::emitSelfHostedCallFunct
     // invokes the callee with the correct |this| object and arguments.
     // callFunction(fun, thisArg, arg0, arg1) thus becomes:
     // - emit lookup for fun
     // - emit lookup for thisArg
     // - emit lookups for arg0, arg1
     //
     // argc is set to the amount of actually emitted args and the
     // emitting of args below is disabled by setting emitArgs to false.
-    ParseNode* pn2 = pn->pn_head;
-    const char* errorName = SelfHostedCallFunctionName(pn2->name(), cx);
-
-    if (pn->pn_count < 3) {
+    ParseNode* pn_callee = pn->pn_left;
+    ParseNode* pn_args = pn->pn_right;
+
+    const char* errorName = SelfHostedCallFunctionName(pn_callee->name(), cx);
+
+    if (pn_args->pn_count < 2) {
         reportError(pn, JSMSG_MORE_ARGS_NEEDED, errorName, "2", "s");
         return false;
     }
 
     JSOp callOp = pn->getOp();
     if (callOp != JSOP_CALL) {
         reportError(pn, JSMSG_NOT_CONSTRUCTOR, errorName);
         return false;
     }
 
-    bool constructing = pn2->name() == cx->names().constructContentFunction;
-    ParseNode* funNode = pn2->pn_next;
+    bool constructing = pn_callee->name() == cx->names().constructContentFunction;
+    ParseNode* funNode = pn_args->pn_head;
     if (constructing) {
         callOp = JSOP_NEW;
     } else if (funNode->getKind() == ParseNodeKind::Name &&
                funNode->name() == cx->names().std_Function_apply) {
         callOp = JSOP_FUNAPPLY;
     }
 
     if (!emitTree(funNode))
         return false;
 
 #ifdef DEBUG
     if (emitterMode == BytecodeEmitter::SelfHosting &&
-        pn2->name() == cx->names().callFunction)
+        pn_callee->name() == cx->names().callFunction)
     {
         if (!emit1(JSOP_DEBUGCHECKSELFHOSTED))
             return false;
     }
 #endif
 
     ParseNode* thisOrNewTarget = funNode->pn_next;
     if (constructing) {
@@ -9245,36 +9255,36 @@ BytecodeEmitter::emitSelfHostedCallFunct
             return false;
     }
 
     if (constructing) {
         if (!emitTree(thisOrNewTarget))
             return false;
     }
 
-    uint32_t argc = pn->pn_count - 3;
+    uint32_t argc = pn_args->pn_count - 2;
     if (!emitCall(callOp, argc))
         return false;
 
     checkTypeSet(callOp);
     return true;
 }
 
 bool
 BytecodeEmitter::emitSelfHostedResumeGenerator(ParseNode* pn)
 {
+    ParseNode* pn_args = pn->pn_right;
+
     // Syntax: resumeGenerator(gen, value, 'next'|'throw'|'return')
-    if (pn->pn_count != 4) {
+    if (pn_args->pn_count != 3) {
         reportError(pn, JSMSG_MORE_ARGS_NEEDED, "resumeGenerator", "1", "s");
         return false;
     }
 
-    ParseNode* funNode = pn->pn_head;  // The resumeGenerator node.
-
-    ParseNode* genNode = funNode->pn_next;
+    ParseNode* genNode = pn_args->pn_head;
     if (!emitTree(genNode))
         return false;
 
     ParseNode* valNode = genNode->pn_next;
     if (!emitTree(valNode))
         return false;
 
     ParseNode* kindNode = valNode->pn_next;
@@ -9296,34 +9306,36 @@ BytecodeEmitter::emitSelfHostedForceInte
     if (!emit1(JSOP_UNDEFINED))
         return false;
     return true;
 }
 
 bool
 BytecodeEmitter::emitSelfHostedAllowContentIter(ParseNode* pn)
 {
-    if (pn->pn_count != 2) {
+    ParseNode* pn_args = pn->pn_right;
+
+    if (pn_args->pn_count != 1) {
         reportError(pn, JSMSG_MORE_ARGS_NEEDED, "allowContentIter", "1", "");
         return false;
     }
 
     // We're just here as a sentinel. Pass the value through directly.
-    return emitTree(pn->pn_head->pn_next);
+    return emitTree(pn_args->pn_head);
 }
 
 bool
 BytecodeEmitter::emitSelfHostedDefineDataProperty(ParseNode* pn)
 {
-    // Only optimize when 3 arguments are passed (we use 4 to include |this|).
-    MOZ_ASSERT(pn->pn_count == 4);
-
-    ParseNode* funNode = pn->pn_head;  // The _DefineDataProperty node.
-
-    ParseNode* objNode = funNode->pn_next;
+    ParseNode* pn_args = pn->pn_right;
+
+    // Only optimize when 3 arguments are passed.
+    MOZ_ASSERT(pn_args->pn_count == 3);
+
+    ParseNode* objNode = pn_args->pn_head;
     if (!emitTree(objNode))
         return false;
 
     ParseNode* idNode = objNode->pn_next;
     if (!emitTree(idNode))
         return false;
 
     ParseNode* valNode = idNode->pn_next;
@@ -9334,45 +9346,45 @@ BytecodeEmitter::emitSelfHostedDefineDat
     // but that's fine because the self-hosted code doesn't use the return
     // value.
     return emit1(JSOP_INITELEM);
 }
 
 bool
 BytecodeEmitter::emitSelfHostedHasOwn(ParseNode* pn)
 {
-    if (pn->pn_count != 3) {
+    ParseNode* pn_args = pn->pn_right;
+
+    if (pn_args->pn_count != 2) {
         reportError(pn, JSMSG_MORE_ARGS_NEEDED, "hasOwn", "2", "");
         return false;
     }
 
-    ParseNode* funNode = pn->pn_head;  // The hasOwn node.
-
-    ParseNode* idNode = funNode->pn_next;
+    ParseNode* idNode = pn_args->pn_head;
     if (!emitTree(idNode))
         return false;
 
     ParseNode* objNode = idNode->pn_next;
     if (!emitTree(objNode))
         return false;
 
     return emit1(JSOP_HASOWN);
 }
 
 bool
 BytecodeEmitter::emitSelfHostedGetPropertySuper(ParseNode* pn)
 {
-    if (pn->pn_count != 4) {
+    ParseNode* pn_args = pn->pn_right;
+
+    if (pn_args->pn_count != 3) {
         reportError(pn, JSMSG_MORE_ARGS_NEEDED, "getPropertySuper", "3", "");
         return false;
     }
 
-    ParseNode* funNode = pn->pn_head;  // The getPropertySuper node.
-
-    ParseNode* objNode = funNode->pn_next;
+    ParseNode* objNode = pn_args->pn_head;
     ParseNode* idNode = objNode->pn_next;
     ParseNode* receiverNode = idNode->pn_next;
 
     if (!emitTree(idNode))
         return false;
 
     if (!emitTree(receiverNode))
         return false;
@@ -9391,21 +9403,21 @@ BytecodeEmitter::isRestParameter(ParseNo
 
     FunctionBox* funbox = sc->asFunctionBox();
     RootedFunction fun(cx, funbox->function());
     if (!funbox->hasRest())
         return false;
 
     if (!pn->isKind(ParseNodeKind::Name)) {
         if (emitterMode == BytecodeEmitter::SelfHosting && pn->isKind(ParseNodeKind::Call)) {
-            ParseNode* pn2 = pn->pn_head;
-            if (pn2->getKind() == ParseNodeKind::Name &&
-                pn2->name() == cx->names().allowContentIter)
+            ParseNode* pn_callee = pn->pn_left;
+            if (pn_callee->getKind() == ParseNodeKind::Name &&
+                pn_callee->name() == cx->names().allowContentIter)
             {
-                return isRestParameter(pn2->pn_next);
+                return isRestParameter(pn->pn_right->pn_head);
             }
         }
         return false;
     }
 
     JSAtom* name = pn->name();
     Maybe<NameLocation> paramLoc = locationOfNameBoundInFunctionScope(name);
     if (paramLoc && lookupName(name) == *paramLoc) {
@@ -9525,111 +9537,32 @@ BytecodeEmitter::emitPipeline(ParseNode*
 
         checkTypeSet(JSOP_CALL);
     } while ((callee = callee->pn_next));
 
     return true;
 }
 
 bool
-BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */)
-{
-    bool callop =
-        pn->isKind(ParseNodeKind::Call) || pn->isKind(ParseNodeKind::TaggedTemplate);
-    /*
-     * Emit callable invocation or operator new (constructor call) code.
-     * First, emit code for the left operand to evaluate the callable or
-     * constructable object expression.
-     *
-     * For operator new, we emit JSOP_GETPROP instead of JSOP_CALLPROP, etc.
-     * This is necessary to interpose the lambda-initialized method read
-     * barrier -- see the code in jsinterp.cpp for JSOP_LAMBDA followed by
-     * JSOP_{SET,INIT}PROP.
-     *
-     * Then (or in a call case that has no explicit reference-base
-     * object) we emit JSOP_UNDEFINED to produce the undefined |this|
-     * value required for calls (which non-strict mode functions
-     * will box into the global object).
-     */
-    uint32_t argc = pn->pn_count - 1;
+BytecodeEmitter::emitArguments(ParseNode* pn, bool callop, bool spread)
+{
+    uint32_t argc = pn->pn_count;
 
     if (argc >= ARGC_LIMIT) {
         reportError(pn, callop ? JSMSG_TOO_MANY_FUN_ARGS : JSMSG_TOO_MANY_CON_ARGS);
         return false;
     }
 
-    ParseNode* pn2 = pn->pn_head;
-    bool spread = JOF_OPTYPE(pn->getOp()) == JOF_BYTE;
-
-    if (pn2->isKind(ParseNodeKind::Name) && emitterMode == BytecodeEmitter::SelfHosting && !spread) {
-        // Calls to "forceInterpreter", "callFunction",
-        // "callContentFunction", or "resumeGenerator" in self-hosted
-        // code generate inline bytecode.
-        if (pn2->name() == cx->names().callFunction ||
-            pn2->name() == cx->names().callContentFunction ||
-            pn2->name() == cx->names().constructContentFunction)
-        {
-            return emitSelfHostedCallFunction(pn);
-        }
-        if (pn2->name() == cx->names().resumeGenerator)
-            return emitSelfHostedResumeGenerator(pn);
-        if (pn2->name() == cx->names().forceInterpreter)
-            return emitSelfHostedForceInterpreter();
-        if (pn2->name() == cx->names().allowContentIter)
-            return emitSelfHostedAllowContentIter(pn);
-        if (pn2->name() == cx->names().defineDataPropertyIntrinsic && pn->pn_count == 4)
-            return emitSelfHostedDefineDataProperty(pn);
-        if (pn2->name() == cx->names().hasOwn)
-            return emitSelfHostedHasOwn(pn);
-        if (pn2->name() == cx->names().getPropertySuper)
-            return emitSelfHostedGetPropertySuper(pn);
-        // Fall through
-    }
-
-    if (!emitCallee(pn2, pn, &callop))
-        return false;
-
-    bool isNewOp = pn->getOp() == JSOP_NEW || pn->getOp() == JSOP_SPREADNEW ||
-                   pn->getOp() == JSOP_SUPERCALL || pn->getOp() == JSOP_SPREADSUPERCALL;
-
-
-    // Emit room for |this|.
-    if (!callop) {
-        if (isNewOp) {
-            if (!emit1(JSOP_IS_CONSTRUCTING))
-                return false;
-        } else {
-            if (!emit1(JSOP_UNDEFINED))
-                return false;
-        }
-    }
-
-    /*
-     * Emit code for each argument in order, then emit the JSOP_*CALL or
-     * JSOP_NEW bytecode with a two-byte immediate telling how many args
-     * were pushed on the operand stack.
-     */
     if (!spread) {
-        for (ParseNode* pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {
+        for (ParseNode* pn3 = pn->pn_head; pn3; pn3 = pn3->pn_next) {
             if (!emitTree(pn3))
                 return false;
         }
-
-        if (isNewOp) {
-            if (pn->isKind(ParseNodeKind::SuperCall)) {
-                if (!emit1(JSOP_NEWTARGET))
-                    return false;
-            } else {
-                // Repush the callee as new.target
-                if (!emitDupAt(argc + 1))
-                    return false;
-            }
-        }
     } else {
-        ParseNode* args = pn2->pn_next;
+        ParseNode* args = pn->pn_head;
         bool emitOptCode = (argc == 1) && isRestParameter(args->pn_kid);
         InternalIfEmitter ifNotOptimizable(this);
 
         if (emitOptCode) {
             // Emit a preparation code to optimize the spread call with a rest
             // parameter:
             //
             //   function f(...args) {
@@ -9659,25 +9592,110 @@ BytecodeEmitter::emitCallOrNew(ParseNode
 
         if (!emitArray(args, argc))
             return false;
 
         if (emitOptCode) {
             if (!ifNotOptimizable.emitEnd())
                 return false;
         }
-
+    }
+
+    return true;
+}
+
+bool
+BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */)
+{
+    bool callop =
+        pn->isKind(ParseNodeKind::Call) || pn->isKind(ParseNodeKind::TaggedTemplate);
+
+    /*
+     * Emit callable invocation or operator new (constructor call) code.
+     * First, emit code for the left operand to evaluate the callable or
+     * constructable object expression.
+     *
+     * For operator new, we emit JSOP_GETPROP instead of JSOP_CALLPROP, etc.
+     * This is necessary to interpose the lambda-initialized method read
+     * barrier -- see the code in jsinterp.cpp for JSOP_LAMBDA followed by
+     * JSOP_{SET,INIT}PROP.
+     *
+     * Then (or in a call case that has no explicit reference-base
+     * object) we emit JSOP_UNDEFINED to produce the undefined |this|
+     * value required for calls (which non-strict mode functions
+     * will box into the global object).
+     */
+    ParseNode* pn_callee = pn->pn_left;
+    ParseNode* pn_args = pn->pn_right;
+
+    bool spread = JOF_OPTYPE(pn->getOp()) == JOF_BYTE;
+
+    if (pn_callee->isKind(ParseNodeKind::Name) && emitterMode == BytecodeEmitter::SelfHosting && !spread) {
+        // Calls to "forceInterpreter", "callFunction",
+        // "callContentFunction", or "resumeGenerator" in self-hosted
+        // code generate inline bytecode.
+        if (pn_callee->name() == cx->names().callFunction ||
+            pn_callee->name() == cx->names().callContentFunction ||
+            pn_callee->name() == cx->names().constructContentFunction)
+        {
+            return emitSelfHostedCallFunction(pn);
+        }
+        if (pn_callee->name() == cx->names().resumeGenerator)
+            return emitSelfHostedResumeGenerator(pn);
+        if (pn_callee->name() == cx->names().forceInterpreter)
+            return emitSelfHostedForceInterpreter();
+        if (pn_callee->name() == cx->names().allowContentIter)
+            return emitSelfHostedAllowContentIter(pn);
+        if (pn_callee->name() == cx->names().defineDataPropertyIntrinsic && pn_args->pn_count == 3)
+            return emitSelfHostedDefineDataProperty(pn);
+        if (pn_callee->name() == cx->names().hasOwn)
+            return emitSelfHostedHasOwn(pn);
+        if (pn_callee->name() == cx->names().getPropertySuper)
+            return emitSelfHostedGetPropertySuper(pn);
+        // Fall through
+    }
+
+    if (!emitCallee(pn_callee, pn, &callop))
+        return false;
+
+    bool isNewOp = pn->getOp() == JSOP_NEW || pn->getOp() == JSOP_SPREADNEW ||
+                   pn->getOp() == JSOP_SUPERCALL || pn->getOp() == JSOP_SPREADSUPERCALL;
+
+    // Emit room for |this|.
+    if (!callop) {
         if (isNewOp) {
-            if (pn->isKind(ParseNodeKind::SuperCall)) {
-                if (!emit1(JSOP_NEWTARGET))
-                    return false;
-            } else {
-                if (!emitDupAt(2))
-                    return false;
-            }
+            if (!emit1(JSOP_IS_CONSTRUCTING))
+                return false;
+        } else {
+            if (!emit1(JSOP_UNDEFINED))
+                return false;
+        }
+    }
+
+    if (!emitArguments(pn_args, callop, spread))
+        return false;
+
+    uint32_t argc = pn_args->pn_count;
+
+    /*
+     * Emit code for each argument in order, then emit the JSOP_*CALL or
+     * JSOP_NEW bytecode with a two-byte immediate telling how many args
+     * were pushed on the operand stack.
+     */
+    if (isNewOp) {
+        if (pn->isKind(ParseNodeKind::SuperCall)) {
+            if (!emit1(JSOP_NEWTARGET))
+                return false;
+        } else if (!spread) {
+            // Repush the callee as new.target
+            if (!emitDupAt(argc + 1))
+                return false;
+        } else {
+            if (!emitDupAt(2))
+                return false;
         }
     }
 
     if (!spread) {
         if (pn->getOp() == JSOP_CALL && valueUsage == ValueUsage::IgnoreValue) {
             if (!emitCall(JSOP_CALL_IGNORES_RV, argc, pn))
                 return false;
             checkTypeSet(JSOP_CALL_IGNORES_RV);
@@ -10250,17 +10268,17 @@ BytecodeEmitter::emitArray(ParseNode* pn
                 return false;
         } else {
             ParseNode* expr;
             if (pn2->isKind(ParseNodeKind::Spread)) {
                 expr = pn2->pn_kid;
 
                 if (emitterMode == BytecodeEmitter::SelfHosting &&
                     expr->isKind(ParseNodeKind::Call) &&
-                    expr->pn_head->name() == cx->names().allowContentIter)
+                    expr->pn_left->name() == cx->names().allowContentIter)
                 {
                     allowSelfHostedIter = true;
                 }
             } else {
                 expr = pn2;
             }
             if (!emitTree(expr))                                         // ARRAY INDEX? VALUE
                 return false;
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -846,16 +846,17 @@ struct MOZ_STACK_CLASS BytecodeEmitter
 
     MOZ_NEVER_INLINE MOZ_MUST_USE bool emitIncOrDec(ParseNode* pn);
 
     MOZ_MUST_USE bool emitConditionalExpression(ConditionalExpression& conditional,
                                                 ValueUsage valueUsage = ValueUsage::WantValue);
 
     bool isRestParameter(ParseNode* pn);
 
+    MOZ_MUST_USE bool emitArguments(ParseNode* pn, bool callop, bool spread);
     MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue);
     MOZ_MUST_USE bool emitSelfHostedCallFunction(ParseNode* pn);
     MOZ_MUST_USE bool emitSelfHostedResumeGenerator(ParseNode* pn);
     MOZ_MUST_USE bool emitSelfHostedForceInterpreter();
     MOZ_MUST_USE bool emitSelfHostedAllowContentIter(ParseNode* pn);
     MOZ_MUST_USE bool emitSelfHostedDefineDataProperty(ParseNode* pn);
     MOZ_MUST_USE bool emitSelfHostedGetPropertySuper(ParseNode* pn);
     MOZ_MUST_USE bool emitSelfHostedHasOwn(ParseNode* pn);
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -344,16 +344,17 @@ ContainsHoistedDeclaration(JSContext* cx
       case ParseNodeKind::DivAssign:
       case ParseNodeKind::ModAssign:
       case ParseNodeKind::PowAssign:
       case ParseNodeKind::Comma:
       case ParseNodeKind::Array:
       case ParseNodeKind::Object:
       case ParseNodeKind::Dot:
       case ParseNodeKind::Elem:
+      case ParseNodeKind::Arguments:
       case ParseNodeKind::Call:
       case ParseNodeKind::Name:
       case ParseNodeKind::TemplateString:
       case ParseNodeKind::TemplateStringList:
       case ParseNodeKind::TaggedTemplate:
       case ParseNodeKind::CallSiteObj:
       case ParseNodeKind::String:
       case ParseNodeKind::RegExp:
@@ -1404,34 +1405,51 @@ FoldAdd(JSContext* cx, ParseNode** nodeP
     return true;
 }
 
 static bool
 FoldCall(JSContext* cx, ParseNode* node, PerHandlerParser<FullParseHandler>& parser)
 {
     MOZ_ASSERT(node->isKind(ParseNodeKind::Call) ||
                node->isKind(ParseNodeKind::SuperCall) ||
+               node->isKind(ParseNodeKind::New) ||
                node->isKind(ParseNodeKind::TaggedTemplate));
-    MOZ_ASSERT(node->isArity(PN_LIST));
+    MOZ_ASSERT(node->isArity(PN_BINARY));
 
     // Don't fold a parenthesized callable component in an invocation, as this
     // might cause a different |this| value to be used, changing semantics:
     //
     //   var prop = "global";
     //   var obj = { prop: "obj", f: function() { return this.prop; } };
     //   assertEq((true ? obj.f : null)(), "global");
     //   assertEq(obj.f(), "obj");
     //   assertEq((true ? obj.f : null)``, "global");
     //   assertEq(obj.f``, "obj");
     //
     // See bug 537673 and bug 1182373.
+    ParseNode** pn_callee = &node->pn_left;
+    if (node->isKind(ParseNodeKind::New) || !(*pn_callee)->isInParens()) {
+        if (!Fold(cx, pn_callee, parser))
+            return false;
+    }
+
+    ParseNode** pn_args = &node->pn_right;
+    if (!Fold(cx, pn_args, parser))
+        return false;
+
+    return true;
+}
+
+static bool
+FoldArguments(JSContext* cx, ParseNode* node, PerHandlerParser<FullParseHandler>& parser)
+{
+    MOZ_ASSERT(node->isKind(ParseNodeKind::Arguments));
+    MOZ_ASSERT(node->isArity(PN_LIST));
+
     ParseNode** listp = &node->pn_head;
-    if ((*listp)->isInParens())
-        listp = &(*listp)->pn_next;
-
     for (; *listp; listp = &(*listp)->pn_next) {
         if (!Fold(cx, listp, parser))
             return false;
     }
 
     // If the last node in the list was replaced, pn_tail points into the wrong node.
     node->pn_tail = listp;
 
@@ -1637,17 +1655,16 @@ Fold(JSContext* cx, ParseNode** pnp, Per
       case ParseNodeKind::Ne:
       case ParseNodeKind::Lt:
       case ParseNodeKind::Le:
       case ParseNodeKind::Gt:
       case ParseNodeKind::Ge:
       case ParseNodeKind::InstanceOf:
       case ParseNodeKind::In:
       case ParseNodeKind::Comma:
-      case ParseNodeKind::New:
       case ParseNodeKind::Array:
       case ParseNodeKind::Object:
       case ParseNodeKind::StatementList:
       case ParseNodeKind::ClassMethodList:
       case ParseNodeKind::TemplateStringList:
       case ParseNodeKind::Var:
       case ParseNodeKind::Const:
       case ParseNodeKind::Let:
@@ -1689,20 +1706,24 @@ Fold(JSContext* cx, ParseNode** pnp, Per
 
       case ParseNodeKind::Elem:
         return FoldElement(cx, pnp, parser);
 
       case ParseNodeKind::Add:
         return FoldAdd(cx, pnp, parser);
 
       case ParseNodeKind::Call:
+      case ParseNodeKind::New:
       case ParseNodeKind::SuperCall:
       case ParseNodeKind::TaggedTemplate:
         return FoldCall(cx, pn, parser);
 
+      case ParseNodeKind::Arguments:
+        return FoldArguments(cx, pn, parser);
+
       case ParseNodeKind::Switch:
       case ParseNodeKind::Colon:
       case ParseNodeKind::Assign:
       case ParseNodeKind::AddAssign:
       case ParseNodeKind::SubAssign:
       case ParseNodeKind::BitOrAssign:
       case ParseNodeKind::BitAndAssign:
       case ParseNodeKind::BitXorAssign:
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -270,26 +270,30 @@ class FullParseHandler
     void addArrayElement(ParseNode* literal, ParseNode* element) {
         MOZ_ASSERT(literal->isArity(PN_LIST));
 
         if (!element->isConstant())
             literal->pn_xflags |= PNX_NONCONST;
         addList(/* list = */ literal, /* child = */ element);
     }
 
-    ParseNode* newCall(const TokenPos& pos) {
-        return new_<ListNode>(ParseNodeKind::Call, JSOP_CALL, pos);
+    ParseNode* newCall(ParseNode* callee, ParseNode* args) {
+        return new_<BinaryNode>(ParseNodeKind::Call, JSOP_CALL, callee, args);
     }
 
-    ParseNode* newSuperCall(ParseNode* callee) {
-        return new_<ListNode>(ParseNodeKind::SuperCall, JSOP_SUPERCALL, callee);
+    ParseNode* newArguments(const TokenPos& pos) {
+        return new_<ListNode>(ParseNodeKind::Arguments, JSOP_NOP, pos);
     }
 
-    ParseNode* newTaggedTemplate(const TokenPos& pos) {
-        return new_<ListNode>(ParseNodeKind::TaggedTemplate, JSOP_CALL, pos);
+    ParseNode* newSuperCall(ParseNode* callee, ParseNode* args) {
+        return new_<BinaryNode>(ParseNodeKind::SuperCall, JSOP_SUPERCALL, callee, args);
+    }
+
+    ParseNode* newTaggedTemplate(ParseNode* tag, ParseNode* args) {
+        return new_<BinaryNode>(ParseNodeKind::TaggedTemplate, JSOP_CALL, tag, args);
     }
 
     ParseNode* newObjectLiteral(uint32_t begin) {
         return new_<ListNode>(ParseNodeKind::Object, TokenPos(begin, begin + 1));
     }
 
     ParseNode* newClass(ParseNode* name, ParseNode* heritage, ParseNode* methodBlock,
                         const TokenPos& pos)
@@ -729,23 +733,18 @@ class FullParseHandler
     ParseNode* newModule(const TokenPos& pos) {
         return new_<CodeNode>(ParseNodeKind::Module, JSOP_NOP, pos);
     }
 
     ParseNode* newLexicalScope(LexicalScope::Data* bindings, ParseNode* body) {
         return new_<LexicalScopeNode>(bindings, body);
     }
 
-    Node newNewExpression(uint32_t begin, ParseNode* ctor) {
-        ParseNode* newExpr = new_<ListNode>(ParseNodeKind::New, JSOP_NEW, TokenPos(begin, begin + 1));
-        if (!newExpr)
-            return nullptr;
-
-        addList(/* list = */ newExpr, /* child = */ ctor);
-        return newExpr;
+    Node newNewExpression(uint32_t begin, ParseNode* ctor, ParseNode* args) {
+        return new_<BinaryNode>(ParseNodeKind::New, JSOP_NEW, TokenPos(begin, args->pn_pos.end), ctor, args);
     }
 
     ParseNode* newAssignment(ParseNodeKind kind, ParseNode* lhs, ParseNode* rhs) {
         if (kind == ParseNodeKind::Assign && lhs->isKind(ParseNodeKind::Name) &&
             !lhs->isInParens())
         {
             checkAndSetIsDirectRHSAnonFunction(rhs);
         }
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -310,27 +310,27 @@ class NameResolver
 
             element = element->pn_next;
         }
     }
 
     bool resolveTaggedTemplate(ParseNode* node, HandleAtom prefix) {
         MOZ_ASSERT(node->isKind(ParseNodeKind::TaggedTemplate));
 
-        ParseNode* element = node->pn_head;
+        ParseNode* tag = node->pn_left;
 
-        // The list head is a leading expression, e.g. |tag| in |tag`foo`|,
+        // The leading expression, e.g. |tag| in |tag`foo`|,
         // that might contain functions.
-        if (!resolve(element, prefix))
+        if (!resolve(tag, prefix))
             return false;
 
-        // Next is the callsite object node.  This node only contains
+        // The callsite object node is first.  This node only contains
         // internal strings or undefined and an array -- no user-controlled
         // expressions.
-        element = element->pn_next;
+        ParseNode* element = node->pn_right->pn_head;
 #ifdef DEBUG
         {
             MOZ_ASSERT(element->isKind(ParseNodeKind::CallSiteObj));
             ParseNode* array = element->pn_head;
             MOZ_ASSERT(array->isKind(ParseNodeKind::Array));
             for (ParseNode* kid = array->pn_head; kid; kid = kid->pn_next)
                 MOZ_ASSERT(kid->isKind(ParseNodeKind::TemplateString));
             for (ParseNode* next = array->pn_next; next; next = next->pn_next) {
@@ -692,19 +692,16 @@ class NameResolver
           case ParseNodeKind::Add:
           case ParseNodeKind::Sub:
           case ParseNodeKind::Star:
           case ParseNodeKind::Div:
           case ParseNodeKind::Mod:
           case ParseNodeKind::Pow:
           case ParseNodeKind::Pipeline:
           case ParseNodeKind::Comma:
-          case ParseNodeKind::New:
-          case ParseNodeKind::Call:
-          case ParseNodeKind::SuperCall:
           case ParseNodeKind::Array:
           case ParseNodeKind::StatementList:
           case ParseNodeKind::ParamsBody:
           // Initializers for individual variables, and computed property names
           // within destructuring patterns, may contain unnamed functions.
           case ParseNodeKind::Var:
           case ParseNodeKind::Const:
           case ParseNodeKind::Let:
@@ -728,21 +725,42 @@ class NameResolver
           // contents with expressions interpolated into the overall literal.
           case ParseNodeKind::TemplateStringList:
             MOZ_ASSERT(cur->isArity(PN_LIST));
             if (!resolveTemplateLiteral(cur, prefix))
                 return false;
             break;
 
           case ParseNodeKind::TaggedTemplate:
-            MOZ_ASSERT(cur->isArity(PN_LIST));
+            MOZ_ASSERT(cur->isArity(PN_BINARY));
             if (!resolveTaggedTemplate(cur, prefix))
                 return false;
             break;
 
+          case ParseNodeKind::New:
+          case ParseNodeKind::Call:
+          case ParseNodeKind::SuperCall:
+            MOZ_ASSERT(cur->isArity(PN_BINARY));
+            if (!resolve(cur->pn_left, prefix))
+                return false;
+            if (!resolve(cur->pn_right, prefix))
+                return false;
+            break;
+
+          // Handles the arguments for new/call/supercall, but does _not_ handle
+          // the Arguments node used by tagged template literals, since that is
+          // special-cased inside of resolveTaggedTemplate.
+          case ParseNodeKind::Arguments:
+            MOZ_ASSERT(cur->isArity(PN_LIST));
+            for (ParseNode* element = cur->pn_head; element; element = element->pn_next) {
+                if (!resolve(element, prefix))
+                    return false;
+            }
+            break;
+
           // Import/export spec lists contain import/export specs containing
           // only pairs of names. Alternatively, an export spec lists may
           // contain a single export batch specifier.
           case ParseNodeKind::ExportSpecList:
           case ParseNodeKind::ImportSpecList: {
             MOZ_ASSERT(cur->isArity(PN_LIST));
 #ifdef DEBUG
             bool isImport = cur->isKind(ParseNodeKind::ImportSpecList);
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -58,16 +58,17 @@ class ObjectBox;
     F(Dot) \
     F(Elem) \
     F(Array) \
     F(Elision) \
     F(StatementList) \
     F(Label) \
     F(Object) \
     F(Call) \
+    F(Arguments) \
     F(Name) \
     F(ObjectPropertyName) \
     F(ComputedName) \
     F(Number) \
     F(String) \
     F(TemplateStringList) \
     F(TemplateString) \
     F(TaggedTemplate) \
@@ -368,34 +369,34 @@ IsTypeofKind(ParseNodeKind kind)
  * Not,
  * BitNot
  * TypeOfName, unary    pn_kid: UNARY expr
  * TypeOfExpr
  * PreIncrement, unary  pn_kid: MEMBER expr
  * PostIncrement,
  * PreDecrement,
  * PostDecrement
- * New      list        pn_head: list of ctor, arg1, arg2, ... argN
- *                          pn_count: 1 + N (where N is number of args)
- *                          ctor is a MEMBER expr
+ * New      binary      pn_left: ctor expression on the left of the (
+ *                          pn_right: Arguments
  * DeleteName unary     pn_kid: Name expr
  * DeleteProp unary     pn_kid: Dot expr
  * DeleteElem unary     pn_kid: Elem expr
  * DeleteExpr unary     pn_kid: MEMBER expr that's evaluated, then the
  *                          overall delete evaluates to true; can't be a kind
  *                          for a more-specific PNK_DELETE* unless constant
  *                          folding (or a similar parse tree manipulation) has
  *                          occurred
  * Dot      name        pn_expr: MEMBER expr to left of .
  *                          pn_atom: name to right of .
  * Elem     binary      pn_left: MEMBER expr to left of [
  *                          pn_right: expr between [ and ]
- * Call     list        pn_head: list of call, arg1, arg2, ... argN
- *                          pn_count: 1 + N (where N is number of args)
- *                          call is a MEMBER expr naming a callable object
+ * Call     binary      pn_left: callee expression on the left of the (
+ *                          pn_right: Arguments
+ * Arguments list       pn_head: list of arg1, arg2, ... argN
+ *                          pn_count: N (where N is number of args)
  * Array    list        pn_head: list of pn_count array element exprs
  *                          [,,] holes are represented by Elision nodes
  *                          pn_xflags: PN_ENDCOMMA if extra comma at end
  * Object   list        pn_head: list of pn_count binary Colon nodes
  * Colon    binary      key-value pair in object initializer or
  *                          destructuring lhs
  *                          pn_left: property id, pn_right: value
  * Shorthand binary     Same fields as Colon. This is used for object
@@ -405,30 +406,31 @@ IsTypeofKind(ParseNodeKind kind)
  * Name,    name        pn_atom: name, string, or object atom
  * String               pn_op: JSOP_GETNAME, JSOP_STRING, or JSOP_OBJECT
  *                          If JSOP_GETNAME, pn_op may be JSOP_*ARG or JSOP_*VAR
  *                          telling const-ness and static analysis results
  * TemplateStringList pn_head: list of alternating expr and template strings
  *              list
  * TemplateString      pn_atom: template string atom
                 nullary     pn_op: JSOP_NOP
- * TaggedTemplate      pn_head: list of call, call site object, arg1, arg2, ... argN
- *              list        pn_count: 2 + N (N is the number of substitutions)
+ * TaggedTemplate      pn_left: tag expression
+ *              binary       pn_right: Arguments, with the first being the
+ *                           call site object, then arg1, arg2, ... argN
  * CallSiteObj list     pn_head: a Array node followed by
  *                          list of pn_count - 1 TemplateString nodes
  * RegExp   nullary     pn_objbox: RegExp model object
  * Number   dval        pn_dval: double value of numeric literal
  * True,    nullary     pn_op: JSOp bytecode
  * False,
  * Null,
  * RawUndefined
  *
  * This,        unary   pn_kid: '.this' Name if function `this`, else nullptr
  * SuperBase    unary   pn_kid: '.this' Name
- *
+ * SuperCall    binary  pn_left: SuperBase pn_right: Arguments
  * SetThis      binary  pn_left: '.this' Name, pn_right: SuperCall
  *
  * LexicalScope scope   pn_u.scope.bindings: scope bindings
  *                          pn_u.scope.body: scope body
  * Generator    nullary
  * InitialYield unary   pn_kid: generator object
  * Yield,       unary   pn_kid: expr or null
  * YieldStar,
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -3364,34 +3364,34 @@ GeneralParser<ParseHandler, CharT>::addE
         return false;
     }
 
     return tokenStream.getToken(ttp, TokenStream::TemplateTail);
 }
 
 template <class ParseHandler, typename CharT>
 bool
-GeneralParser<ParseHandler, CharT>::taggedTemplate(YieldHandling yieldHandling, Node nodeList,
+GeneralParser<ParseHandler, CharT>::taggedTemplate(YieldHandling yieldHandling, Node tagArgsList,
                                                    TokenKind tt)
 {
     Node callSiteObjNode = handler.newCallSiteObject(pos().begin);
     if (!callSiteObjNode)
         return false;
-    handler.addList(nodeList, callSiteObjNode);
+    handler.addList(tagArgsList, callSiteObjNode);
 
     while (true) {
         if (!appendToCallSiteObj(callSiteObjNode))
             return false;
         if (tt != TokenKind::TemplateHead)
             break;
 
-        if (!addExprAndGetNextTemplStrToken(yieldHandling, nodeList, &tt))
+        if (!addExprAndGetNextTemplStrToken(yieldHandling, tagArgsList, &tt))
             return false;
     }
-    handler.setEndPosition(nodeList, callSiteObjNode);
+    handler.setEndPosition(tagArgsList, callSiteObjNode);
     return true;
 }
 
 template <class ParseHandler, typename CharT>
 typename ParseHandler::Node
 GeneralParser<ParseHandler, CharT>::templateLiteral(YieldHandling yieldHandling)
 {
     Node pn = noSubstitutionUntaggedTemplate();
@@ -8600,68 +8600,69 @@ GeneralParser<ParseHandler, CharT>::assi
             errorAt(pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT);
             return null();
         }
     }
     return res;
 }
 
 template <class ParseHandler, typename CharT>
-bool
-GeneralParser<ParseHandler, CharT>::argumentList(YieldHandling yieldHandling, Node listNode,
-                                                 bool* isSpread,
+typename ParseHandler::Node
+GeneralParser<ParseHandler, CharT>::argumentList(YieldHandling yieldHandling, bool* isSpread,
                                                  PossibleError* possibleError /* = nullptr */)
 {
+    Node argsList = handler.newArguments(pos());
+
     bool matched;
     if (!tokenStream.matchToken(&matched, TokenKind::Rp, TokenStream::Operand))
-        return false;
+        return null();
     if (matched) {
-        handler.setEndPosition(listNode, pos().end);
-        return true;
+        handler.setEndPosition(argsList, pos().end);
+        return argsList;
     }
 
     while (true) {
         bool spread = false;
         uint32_t begin = 0;
         if (!tokenStream.matchToken(&matched, TokenKind::TripleDot, TokenStream::Operand))
-            return false;
+            return null();
         if (matched) {
             spread = true;
             begin = pos().begin;
             *isSpread = true;
         }
 
         Node argNode = assignExpr(InAllowed, yieldHandling, TripledotProhibited, possibleError);
         if (!argNode)
-            return false;
+            return null();
         if (spread) {
             argNode = handler.newSpread(begin, argNode);
             if (!argNode)
-                return false;
-        }
-
-        handler.addList(listNode, argNode);
+                return null();
+        }
+
+        handler.addList(argsList, argNode);
 
         bool matched;
         if (!tokenStream.matchToken(&matched, TokenKind::Comma, TokenStream::Operand))
-            return false;
+            return null();
         if (!matched)
             break;
 
         TokenKind tt;
         if (!tokenStream.peekToken(&tt, TokenStream::Operand))
             return null();
         if (tt == TokenKind::Rp)
             break;
     }
 
     MUST_MATCH_TOKEN_MOD(TokenKind::Rp, TokenStream::Operand, JSMSG_PAREN_AFTER_ARGS);
 
-    handler.setEndPosition(listNode, pos().end);
-    return true;
+    handler.setEndPosition(argsList, pos().end);
+    return argsList;
 }
 
 bool
 ParserBase::checkAndMarkSuperScope()
 {
     if (!pc->sc()->allowSuperProperty())
         return false;
 
@@ -8697,30 +8698,37 @@ GeneralParser<ParseHandler, CharT>::memb
             // Gotten by tryNewTarget
             tt = anyChars.currentToken().type;
             Node ctorExpr = memberExpr(yieldHandling, TripledotProhibited, tt,
                                        /* allowCallSyntax = */ false,
                                        /* possibleError = */ nullptr, PredictInvoked);
             if (!ctorExpr)
                 return null();
 
-            lhs = handler.newNewExpression(newBegin, ctorExpr);
-            if (!lhs)
-                return null();
-
             bool matched;
             if (!tokenStream.matchToken(&matched, TokenKind::Lp))
                 return null();
+
+            bool isSpread = false;
+            Node args;
             if (matched) {
-                bool isSpread = false;
-                if (!argumentList(yieldHandling, lhs, &isSpread))
-                    return null();
-                if (isSpread)
-                    handler.setOp(lhs, JSOP_SPREADNEW);
+                args = argumentList(yieldHandling, &isSpread);
+            } else {
+                args = handler.newArguments(pos());
             }
+
+            if (!args)
+                return null();
+
+            lhs = handler.newNewExpression(newBegin, ctorExpr, args);
+            if (!lhs)
+                return null();
+
+            if (isSpread)
+                handler.setOp(lhs, JSOP_SPREADNEW);
         }
     } else if (tt == TokenKind::Super) {
         Node thisName = newThisName();
         if (!thisName)
             return null();
         lhs = handler.newSuperBase(thisName, pos());
         if (!lhs)
             return null();
@@ -8783,25 +8791,26 @@ GeneralParser<ParseHandler, CharT>::memb
                     return null();
                 }
 
                 if (tt != TokenKind::Lp) {
                     error(JSMSG_BAD_SUPER);
                     return null();
                 }
 
-                nextMember = handler.newSuperCall(lhs);
-                if (!nextMember)
-                    return null();
-
                 // Despite the fact that it's impossible to have |super()| in a
                 // generator, we still inherit the yieldHandling of the
                 // memberExpression, per spec. Curious.
                 bool isSpread = false;
-                if (!argumentList(yieldHandling, nextMember, &isSpread))
+                Node args = argumentList(yieldHandling, &isSpread);
+                if (!args)
+                    return null();
+
+                nextMember = handler.newSuperCall(lhs, args);
+                if (!nextMember)
                     return null();
 
                 if (isSpread)
                     handler.setOp(nextMember, JSOP_SPREADSUPERCALL);
 
                 Node thisName = newThisName();
                 if (!thisName)
                     return null();
@@ -8810,23 +8819,16 @@ GeneralParser<ParseHandler, CharT>::memb
                 if (!nextMember)
                     return null();
             } else {
                 if (options().selfHostingMode && handler.isPropertyAccess(lhs)) {
                     error(JSMSG_SELFHOSTED_METHOD_CALL);
                     return null();
                 }
 
-                TokenPos nextMemberPos = pos();
-                nextMember = tt == TokenKind::Lp
-                             ? handler.newCall(nextMemberPos)
-                             : handler.newTaggedTemplate(nextMemberPos);
-                if (!nextMember)
-                    return null();
-
                 JSOp op = JSOP_CALL;
                 bool maybeAsyncArrow = false;
                 if (PropertyName* prop = handler.maybeDottedProperty(lhs)) {
                     // Use the JSOP_FUN{APPLY,CALL} optimizations given the
                     // right syntax.
                     if (prop == context->names().apply) {
                         op = JSOP_FUNAPPLY;
                         if (pc->isFunctionBox())
@@ -8858,34 +8860,44 @@ GeneralParser<ParseHandler, CharT>::memb
                         // If we're in a method, mark the method as requiring
                         // support for 'super', since direct eval code can use
                         // it. (If we're not in a method, that's fine, so
                         // ignore the return value.)
                         checkAndMarkSuperScope();
                     }
                 }
 
-                handler.setBeginPosition(nextMember, lhs);
-                handler.addList(nextMember, lhs);
-
                 if (tt == TokenKind::Lp) {
                     bool isSpread = false;
                     PossibleError* asyncPossibleError = maybeAsyncArrow ? possibleError : nullptr;
-                    if (!argumentList(yieldHandling, nextMember, &isSpread, asyncPossibleError))
+                    Node args = argumentList(yieldHandling, &isSpread, asyncPossibleError);
+                    if (!args)
                         return null();
                     if (isSpread) {
                         if (op == JSOP_EVAL)
                             op = JSOP_SPREADEVAL;
                         else if (op == JSOP_STRICTEVAL)
                             op = JSOP_STRICTSPREADEVAL;
                         else
                             op = JSOP_SPREADCALL;
                     }
+
+                    nextMember = handler.newCall(lhs, args);
+                    if (!nextMember)
+                        return null();
                 } else {
-                    if (!taggedTemplate(yieldHandling, nextMember, tt))
+                    Node args = handler.newArguments(pos());
+                    if (!args)
+                        return null();
+
+                    if (!taggedTemplate(yieldHandling, args, tt))
+                        return null();
+
+                    nextMember = handler.newTaggedTemplate(lhs, args);
+                    if (!nextMember)
                         return null();
                 }
                 handler.setOp(nextMember, op);
             }
         } else {
             anyChars.ungetToken();
             if (handler.isSuperBase(lhs))
                 break;
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -1150,17 +1150,17 @@ class MOZ_STACK_CLASS GeneralParser
     enum FunctionBodyType { StatementListBody, ExpressionBody };
     Node functionBody(InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind,
                       FunctionBodyType type);
 
     Node unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind, uint32_t begin);
 
     Node condition(InHandling inHandling, YieldHandling yieldHandling);
 
-    bool argumentList(YieldHandling yieldHandling, Node listNode, bool* isSpread,
+    Node argumentList(YieldHandling yieldHandling, bool* isSpread,
                       PossibleError* possibleError = nullptr);
     Node destructuringDeclaration(DeclarationKind kind, YieldHandling yieldHandling,
                                   TokenKind tt);
     Node destructuringDeclarationWithoutYieldOrAwait(DeclarationKind kind, YieldHandling yieldHandling,
                                                      TokenKind tt);
 
     inline bool checkExportedName(JSAtom* exportName);
     inline bool checkExportedNamesForArrayBinding(Node node);
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -243,19 +243,21 @@ class SyntaxParseHandler
 
     // Expressions
 
     Node newArrayLiteral(uint32_t begin) { return NodeUnparenthesizedArray; }
     MOZ_MUST_USE bool addElision(Node literal, const TokenPos& pos) { return true; }
     MOZ_MUST_USE bool addSpreadElement(Node literal, uint32_t begin, Node inner) { return true; }
     void addArrayElement(Node literal, Node element) { }
 
-    Node newCall(const TokenPos& pos) { return NodeFunctionCall; }
-    Node newSuperCall(Node callee) { return NodeGeneric; }
-    Node newTaggedTemplate(const TokenPos& pos) { return NodeGeneric; }
+    Node newArguments(const TokenPos& pos) { return NodeGeneric; }
+    Node newCall(Node callee, Node args) { return NodeFunctionCall; }
+
+    Node newSuperCall(Node callee, Node args) { return NodeGeneric; }
+    Node newTaggedTemplate(Node callee, Node args) { return NodeGeneric; }
 
     Node newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; }
     Node newClassMethodList(uint32_t begin) { return NodeGeneric; }
     Node newClassNames(Node outer, Node inner, const TokenPos& pos) { return NodeGeneric; }
     Node newClass(Node name, Node heritage, Node methodBlock, const TokenPos& pos) { return NodeGeneric; }
 
     Node newNewTarget(Node newHolder, Node targetHolder) { return NodeGeneric; }
     Node newPosHolder(const TokenPos& pos) { return NodeGeneric; }
@@ -419,17 +421,17 @@ class SyntaxParseHandler
         MOZ_ASSERT(list == NodeGeneric ||
                    list == NodeUnparenthesizedArray ||
                    list == NodeUnparenthesizedObject ||
                    list == NodeVarDeclaration ||
                    list == NodeLexicalDeclaration ||
                    list == NodeFunctionCall);
     }
 
-    Node newNewExpression(uint32_t begin, Node ctor) {
+    Node newNewExpression(uint32_t begin, Node ctor, Node args) {
         return NodeGeneric;
     }
 
     Node newAssignment(ParseNodeKind kind, Node lhs, Node rhs) {
         return kind == ParseNodeKind::Assign ? NodeUnparenthesizedAssignment : NodeGeneric;
     }
 
     bool isUnparenthesizedAssignment(Node node) {
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -452,32 +452,31 @@ ListLength(ParseNode* pn)
     MOZ_ASSERT(pn->isArity(PN_LIST));
     return pn->pn_count;
 }
 
 static inline ParseNode*
 CallCallee(ParseNode* pn)
 {
     MOZ_ASSERT(pn->isKind(ParseNodeKind::Call));
-    return ListHead(pn);
+    return BinaryLeft(pn);
 }
 
 static inline unsigned
 CallArgListLength(ParseNode* pn)
 {
     MOZ_ASSERT(pn->isKind(ParseNodeKind::Call));
-    MOZ_ASSERT(ListLength(pn) >= 1);
-    return ListLength(pn) - 1;
+    return ListLength(BinaryRight(pn));
 }
 
 static inline ParseNode*
 CallArgList(ParseNode* pn)
 {
     MOZ_ASSERT(pn->isKind(ParseNodeKind::Call));
-    return NextNode(ListHead(pn));
+    return ListHead(BinaryRight(pn));
 }
 
 static inline ParseNode*
 VarListHead(ParseNode* pn)
 {
     MOZ_ASSERT(pn->isKind(ParseNodeKind::Var) || pn->isKind(ParseNodeKind::Const));
     return ListHead(pn);
 }
@@ -3557,19 +3556,21 @@ IsArrayViewCtorName(ModuleValidator& m, 
         *type = Scalar::Float64;
     } else {
         return false;
     }
     return true;
 }
 
 static bool
-CheckNewArrayViewArgs(ModuleValidator& m, ParseNode* ctorExpr, PropertyName* bufferName)
-{
-    ParseNode* bufArg = NextNode(ctorExpr);
+CheckNewArrayViewArgs(ModuleValidator& m, ParseNode* newExpr, PropertyName* bufferName)
+{
+    ParseNode* ctorExpr = BinaryLeft(newExpr);
+    ParseNode* ctorArgs = BinaryRight(newExpr);
+    ParseNode* bufArg = ListHead(ctorArgs);
     if (!bufArg || NextNode(bufArg) != nullptr)
         return m.fail(ctorExpr, "array view constructor takes exactly one argument");
 
     if (!IsUseOfName(bufArg, bufferName))
         return m.failName(bufArg, "argument to array view constructor must be '%s'", bufferName);
 
     return true;
 }
@@ -3580,17 +3581,17 @@ CheckNewArrayView(ModuleValidator& m, Pr
     PropertyName* globalName = m.globalArgumentName();
     if (!globalName)
         return m.fail(newExpr, "cannot create array view without an asm.js global parameter");
 
     PropertyName* bufferName = m.bufferArgumentName();
     if (!bufferName)
         return m.fail(newExpr, "cannot create array view without an asm.js heap parameter");
 
-    ParseNode* ctorExpr = ListHead(newExpr);
+    ParseNode* ctorExpr = BinaryLeft(newExpr);
 
     PropertyName* field;
     Scalar::Type type;
     if (ctorExpr->isKind(ParseNodeKind::Dot)) {
         ParseNode* base = DotBase(ctorExpr);
 
         if (!IsUseOfName(base, globalName))
             return m.failName(base, "expecting '%s.*Array", globalName);
@@ -3609,17 +3610,17 @@ CheckNewArrayView(ModuleValidator& m, Pr
 
         if (global->which() != ModuleValidator::Global::ArrayViewCtor)
             return m.failName(ctorExpr, "%s must be an imported array view constructor", globalName);
 
         field = nullptr;
         type = global->viewType();
     }
 
-    if (!CheckNewArrayViewArgs(m, ctorExpr, bufferName))
+    if (!CheckNewArrayViewArgs(m, newExpr, bufferName))
         return false;
 
     return m.addArrayView(varName, type, field);
 }
 
 static bool
 IsSimdValidOperationType(SimdType type, SimdOperation op)
 {