diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index 48437a1f1d..a9c354fa7c 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -3025,24 +3025,25 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) case PNK_OPTCALL: case PNK_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(PNK_SUPERCALL)) { - MOZ_ASSERT(next->isKind(PNK_SUPERBASE)); - if (!builder.super(&next->pn_pos, &callee)) + MOZ_ASSERT(pn_callee->isKind(PNK_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); diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index d1c1082ad7..8c3e74155e 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -74,20 +74,6 @@ ParseNodeRequiresSpecialLineNumberNotes(ParseNode* pn) return pn->getKind() == PNK_WHILE || pn->getKind() == PNK_FOR; } -uint32_t -GetCallArgsAndCount(ParseNode* callNode, ParseNode** argumentNode) -{ - // XXX This helper function exists to make ports less error-prone. - // The current parse tree splits the information between callNode and callee. - // A later refactor has a ListNode instead, with slightly different storage. - // (See also the "what is stored where" table in ParseNode.h) - ParseNode* calleeNode = callNode->pn_head; - if (argumentNode && calleeNode) { - *argumentNode = calleeNode->pn_next; - } - return callNode->pn_count - 1; -} - // Class for emitting bytecode for optional expressions. class MOZ_RAII OptionalEmitter { @@ -1353,13 +1339,18 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) case PNK_OPTCALL: case PNK_TAGGED_TEMPLATE: case PNK_SUPERCALL: - MOZ_ASSERT(pn->isArity(PN_LIST)); + 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. + // the call being made will always trigger side-effects, it isn't needed. + case PNK_ARGUMENTS: + MOZ_ASSERT(pn->isArity(PN_LIST)); + *answer = true; + return true; + case PNK_OPTCHAIN: MOZ_ASSERT(pn->isArity(PN_UNARY)); *answer = true; @@ -1417,7 +1408,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) // Generator expressions have no side effects on their own. case PNK_GENEXP: - MOZ_ASSERT(pn->isArity(PN_LIST)); + MOZ_ASSERT(pn->isArity(PN_BINARY)); *answer = false; return true; @@ -4809,7 +4800,7 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte bool allowSelfHostedIter = false; if (emitterMode == BytecodeEmitter::SelfHosting && forHeadExpr->isKind(PNK_CALL) && - forHeadExpr->pn_head->name() == cx->names().allowContentIter) + forHeadExpr->pn_left->name() == cx->names().allowContentIter) { allowSelfHostedIter = true; } @@ -6989,10 +6980,12 @@ BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn) // // 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); + ParseNode* pn_callee = pn->pn_left; + ParseNode* pn_args = pn->pn_right; - if (pn->pn_count < 3) { + 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; } @@ -7003,8 +6996,8 @@ BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn) 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() == PNK_NAME && funNode->name() == cx->names().std_Function_apply) @@ -7015,7 +7008,7 @@ BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn) #ifdef DEBUG if (emitterMode == BytecodeEmitter::SelfHosting && - pn2->name() == cx->names().callFunction) + pn_callee->name() == cx->names().callFunction) { if (!emit1(JSOP_DEBUGCHECKSELFHOSTED)) return false; @@ -7044,7 +7037,7 @@ BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn) return false; } - uint32_t argc = pn->pn_count - 3; + uint32_t argc = pn_args->pn_count - 2; if (!emitCall(callOp, argc)) return false; @@ -7055,15 +7048,15 @@ BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn) bool BytecodeEmitter::emitSelfHostedResumeGenerator(ParseNode* pn) { + ParseNode* pn_args = pn->pn_right; + // Syntax: resumeGenerator(gen, value, 'next'|'throw'|'close') - 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; @@ -7095,13 +7088,15 @@ BytecodeEmitter::emitSelfHostedForceInterpreter(ParseNode* pn) 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 @@ -7117,9 +7112,10 @@ BytecodeEmitter::isRestParameter(ParseNode* pn) if (!pn->isKind(PNK_NAME)) { if (emitterMode == BytecodeEmitter::SelfHosting && pn->isKind(PNK_CALL)) { - ParseNode* pn2 = pn->pn_head; - if (pn2->getKind() == PNK_NAME && pn2->name() == cx->names().allowContentIter) - return isRestParameter(pn2->pn_next); + ParseNode* pn_callee = pn->pn_left; + if (pn_callee->getKind() == PNK_NAME && + pn_callee->name() == cx->names().allowContentIter) + return isRestParameter(pn->pn_right->pn_head); } return false; } @@ -7289,16 +7285,16 @@ BytecodeEmitter::emitOptionalCall( OptionalEmitter& oe, ValueUsage valueUsage) { - ParseNode* calleeNode = callNode->pn_head; + ParseNode* calleeNode = callNode->pn_left; + ParseNode* argsList = callNode->pn_right; bool isCall = true; bool isSpread = IsSpreadOp(callNode->getOp()); - ParseNode* firstArg = nullptr; - uint32_t argc = GetCallArgsAndCount(callNode, &firstArg); + uint32_t argc = argsList->pn_count; JSOp op = callNode->getOp(); CallOrNewEmitter cone(this, op, isSpread && (argc == 1) && - isRestParameter(firstArg->pn_kid) + isRestParameter(argsList->pn_head->pn_kid) ? CallOrNewEmitter::ArgumentsKind::SingleSpreadRest : CallOrNewEmitter::ArgumentsKind::Other, valueUsage); @@ -7315,12 +7311,12 @@ BytecodeEmitter::emitOptionalCall( } } - if (!emitArguments(firstArg, argc, /* isCall = */ true, isSpread, cone)) { + if (!emitArguments(argsList, /* isCall = */ true, isSpread, cone)) { // [stack] CALLEE THIS ARGS... return false; } - ParseNode* coordNode = getCoordNode(callNode, calleeNode, firstArg); + ParseNode* coordNode = getCoordNode(callNode, calleeNode, argsList); if (!cone.emitEnd(argc, Some(coordNode->pn_pos.begin))) { // [stack] RVAL return false; @@ -7331,17 +7327,14 @@ BytecodeEmitter::emitOptionalCall( ParseNode* BytecodeEmitter::getCoordNode(ParseNode* pn, ParseNode* calleeNode, - ParseNode* firstArg) { + ParseNode* argsList) { ParseNode* coordNode = pn; if (pn->isOp(JSOP_CALL) || pn->isOp(JSOP_SPREADCALL) || pn->isOp(JSOP_FUNCALL) || pn->isOp(JSOP_FUNAPPLY)) { // Default to using the location of the `(` itself. // obj[expr]() // expression // ^ // column coord - if (firstArg) { - // XXX In our version, firstArg points to the first argument and may be null if there are none - coordNode = firstArg; - } + coordNode = argsList; switch (calleeNode->getKind()) { case PNK_DOT: @@ -7369,9 +7362,11 @@ ParseNode* BytecodeEmitter::getCoordNode(ParseNode* pn, } bool -BytecodeEmitter::emitArguments(ParseNode* firstArgNode, uint32_t argc, bool isCall, bool isSpread, +BytecodeEmitter::emitArguments(ParseNode* pn, bool isCall, bool isSpread, CallOrNewEmitter& cone) { + uint32_t argc = pn->pn_count; + if (argc >= ARGC_LIMIT) { parser->tokenStream.reportError(isCall ? JSMSG_TOO_MANY_FUN_ARGS @@ -7382,21 +7377,21 @@ BytecodeEmitter::emitArguments(ParseNode* firstArgNode, uint32_t argc, bool isCa if (!cone.prepareForNonSpreadArguments()) { // CALLEE THIS return false; } - for (ParseNode* arg = firstArgNode; arg; arg = arg->pn_next) { + for (ParseNode* arg = pn->pn_head; arg; arg = arg->pn_next) { if (!emitTree(arg)) { return false; } } } else { if (cone.wantSpreadOperand()) { - if (!emitTree(firstArgNode->pn_kid)) { // CALLEE THIS ARG0 + if (!emitTree(pn->pn_head->pn_kid)) { // CALLEE THIS ARG0 return false; } } if (!cone.emitSpreadArgumentsTest()) { // CALLEE THIS return false; } - if (!emitArray(firstArgNode, argc, JSOP_SPREADCALLARRAY)) { // CALLEE THIS ARR + if (!emitArray(pn->pn_head, argc, JSOP_SPREADCALLARRAY)) { // CALLEE THIS ARR return false; } } @@ -7424,11 +7419,11 @@ BytecodeEmitter::emitCallOrNew( * value required for calls (which non-strict mode functions * will box into the global object). */ - ParseNode* calleeNode = callNode->pn_head; bool isCall = callNode->isKind(PNK_CALL) || callNode->isKind(PNK_TAGGED_TEMPLATE); + ParseNode* calleeNode = callNode->pn_left; + ParseNode* argsList = callNode->pn_right; + bool isSpread = IsSpreadOp(callNode->getOp()); - ParseNode* firstArg = nullptr; - uint32_t argc = GetCallArgsAndCount(callNode, &firstArg); if (calleeNode->isKind(PNK_NAME) && emitterMode == BytecodeEmitter::SelfHosting && @@ -7452,21 +7447,22 @@ BytecodeEmitter::emitCallOrNew( // Fall through. } + uint32_t argc = argsList->pn_count; JSOp op = callNode->getOp(); CallOrNewEmitter cone(this, op, isSpread && (argc == 1) && - isRestParameter(firstArg->pn_kid) + isRestParameter(argsList->pn_head->pn_kid) ? CallOrNewEmitter::ArgumentsKind::SingleSpreadRest : CallOrNewEmitter::ArgumentsKind::Other, valueUsage); if (!emitCalleeAndThis(callNode, calleeNode, cone)) { // CALLEE THIS return false; } - if (!emitArguments(firstArg, argc, isCall, isSpread, cone)) { + if (!emitArguments(argsList, isCall, isSpread, cone)) { return false; // CALLEE THIS ARGS... } - ParseNode* coordNode = getCoordNode(callNode, calleeNode, firstArg); + ParseNode* coordNode = getCoordNode(callNode, calleeNode, argsList); if (!cone.emitEnd(argc, Some(coordNode->pn_pos.begin))) { return false; // RVAL @@ -8091,7 +8087,7 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op) if (emitterMode == BytecodeEmitter::SelfHosting && expr->isKind(PNK_CALL) && - expr->pn_head->name() == cx->names().allowContentIter) + expr->pn_left->name() == cx->names().allowContentIter) { allowSelfHostedIter = true; } diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index d909c33084..70af327f38 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -751,8 +751,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE ParseNode* getCoordNode(ParseNode* callNode, ParseNode* calleeNode, ParseNode* firstArgNode); - MOZ_MUST_USE bool emitArguments(ParseNode* firstArgNode, uint32_t argc, - bool isCall, bool isSpread, + MOZ_MUST_USE bool emitArguments(ParseNode* argsList, bool isCall, bool isSpread, CallOrNewEmitter& cone); MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue); diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index c3354e44a4..abeebadddf 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -369,6 +369,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result) case PNK_OBJECT: case PNK_DOT: case PNK_ELEM: + case PNK_ARGUMENTS: case PNK_CALL: case PNK_OPTCHAIN: case PNK_OPTDOT: @@ -1549,8 +1550,9 @@ FoldCall(ExclusiveContext* cx, ParseNode* node, Parser& parser MOZ_ASSERT(node->isKind(PNK_CALL) || node->isKind(PNK_OPTCALL) || node->isKind(PNK_SUPERCALL) || + node->isKind(PNK_NEW) || node->isKind(PNK_TAGGED_TEMPLATE)); - 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: @@ -1563,9 +1565,27 @@ FoldCall(ExclusiveContext* cx, ParseNode* node, Parser& parser // assertEq(obj.f``, "obj"); // // See bug 537673 and bug 1182373. + ParseNode** pn_callee = &node->pn_left; + if (node->isKind(PNK_NEW) || !(*pn_callee)->isInParens()) { + if (!Fold(cx, pn_callee, parser, inGenexpLambda)) + return false; + } + + ParseNode** pn_args = &node->pn_right; + if (!Fold(cx, pn_args, parser, inGenexpLambda)) + return false; + + return true; +} + +static bool +FoldArguments(ExclusiveContext* cx, ParseNode* node, Parser& parser, + bool inGenexpLambda) +{ + MOZ_ASSERT(node->isKind(PNK_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, inGenexpLambda)) @@ -1739,6 +1759,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser& parser, bo return Fold(cx, &pn->pn_kid, parser, inGenexpLambda); case PNK_EXPORT_DEFAULT: + case PNK_GENEXP: MOZ_ASSERT(pn->isArity(PN_BINARY)); return Fold(cx, &pn->pn_left, parser, inGenexpLambda); @@ -1790,7 +1811,6 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser& parser, bo case PNK_INSTANCEOF: case PNK_IN: case PNK_COMMA: - case PNK_NEW: case PNK_ARRAY: case PNK_OBJECT: case PNK_ARRAYCOMP: @@ -1805,7 +1825,6 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser& parser, bo 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: @@ -1847,10 +1866,14 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser& parser, bo case PNK_CALL: case PNK_OPTCALL: + case PNK_NEW: case PNK_SUPERCALL: case PNK_TAGGED_TEMPLATE: return FoldCall(cx, pn, parser, inGenexpLambda); + case PNK_ARGUMENTS: + return FoldArguments(cx, pn, parser, inGenexpLambda); + case PNK_SWITCH: case PNK_COLON: case PNK_ASSIGN: diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index eeb4432e49..786a5c32dd 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -331,16 +331,28 @@ class FullParseHandler literal->append(element); } - ParseNode* newCall() { - return newList(PNK_CALL, JSOP_CALL); + ParseNode* newCall(ParseNode* callee, ParseNode* args) { + return new_(PNK_CALL, JSOP_CALL, callee, args); } - ParseNode* newOptionalCall() { - return newList(PNK_OPTCALL, JSOP_CALL); + ParseNode* newOptionalCall(ParseNode* callee, ParseNode* args) { + return new_(PNK_OPTCALL, JSOP_CALL, callee, args); } - ParseNode* newTaggedTemplate() { - return newList(PNK_TAGGED_TEMPLATE, JSOP_CALL); + ParseNode* newArguments(const TokenPos& pos) { + return new_(PNK_ARGUMENTS, JSOP_NOP, pos); + } + + ParseNode* newSuperCall(ParseNode* callee, ParseNode* args) { + return new_(PNK_SUPERCALL, JSOP_SUPERCALL, callee, args); + } + + ParseNode* newTaggedTemplate(ParseNode* tag, ParseNode* args) { + return new_(PNK_TAGGED_TEMPLATE, JSOP_CALL, tag, args); + } + + ParseNode* newGenExp(ParseNode* callee, ParseNode* args) { + return new_(PNK_GENEXP, JSOP_CALL, callee, args); } ParseNode* newObjectLiteral(uint32_t begin) { @@ -765,6 +777,10 @@ class FullParseHandler return new_(PNK_MODULE, JSOP_NOP, pos()); } + Node newNewExpression(uint32_t begin, ParseNode* ctor, ParseNode* args) { + return new_(PNK_NEW, JSOP_NEW, TokenPos(begin, args->pn_pos.end), ctor, args); + } + ParseNode* newLexicalScope(LexicalScope::Data* bindings, ParseNode* body) { return new_(bindings, body); } diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp index ebf83fb235..e82775b884 100644 --- a/js/src/frontend/NameFunctions.cpp +++ b/js/src/frontend/NameFunctions.cpp @@ -307,17 +307,17 @@ class NameResolver bool resolveTaggedTemplate(ParseNode* node, HandleAtom prefix) { MOZ_ASSERT(node->isKind(PNK_TAGGED_TEMPLATE)); - 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(PNK_CALLSITEOBJ)); @@ -689,10 +689,6 @@ class NameResolver case PNK_MOD: case PNK_POW: case PNK_COMMA: - case PNK_NEW: - case PNK_CALL: - case PNK_SUPERCALL: - case PNK_GENEXP: case PNK_ARRAY: case PNK_STATEMENTLIST: case PNK_PARAMSBODY: @@ -739,11 +735,33 @@ class NameResolver break; case PNK_TAGGED_TEMPLATE: - MOZ_ASSERT(cur->isArity(PN_LIST)); + MOZ_ASSERT(cur->isArity(PN_BINARY)); if (!resolveTaggedTemplate(cur, prefix)) return false; break; + case PNK_NEW: + case PNK_CALL: + case PNK_GENEXP: + case PNK_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 PNK_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. diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index 0b6278c7eb..71b57910c7 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -264,6 +264,12 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack) case PNK_DOWHILE: case PNK_WHILE: case PNK_SWITCH: + case PNK_NEW: + case PNK_OPTCALL: + case PNK_CALL: + case PNK_SUPERCALL: + case PNK_TAGGED_TEMPLATE: + case PNK_GENEXP: case PNK_CLASSMETHOD: case PNK_NEWTARGET: case PNK_SETTHIS: @@ -452,19 +458,14 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack) case PNK_MOD: case PNK_POW: case PNK_COMMA: - case PNK_NEW: - case PNK_OPTCALL: - case PNK_CALL: - case PNK_SUPERCALL: - case PNK_GENEXP: case PNK_ARRAY: case PNK_OBJECT: case PNK_TEMPLATE_STRING_LIST: - case PNK_TAGGED_TEMPLATE: case PNK_CALLSITEOBJ: case PNK_VAR: case PNK_CONST: case PNK_LET: + case PNK_ARGUMENTS: case PNK_CATCHLIST: case PNK_STATEMENTLIST: case PNK_IMPORT_SPEC_LIST: diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 2e5e29675e..68bdfdc200 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -44,6 +44,7 @@ class ObjectBox; F(LABEL) \ F(OBJECT) \ F(CALL) \ + F(ARGUMENTS) \ F(NAME) \ F(OBJECT_PROPERTY_NAME) \ F(COMPUTED_NAME) \ @@ -372,9 +373,8 @@ IsTypeofKind(ParseNodeKind kind) * PNK_POSTINCREMENT, * PNK_PREDECREMENT, * PNK_POSTDECREMENT - * PNK_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 + * PNK_NEW binary pn_left: ctor expression on the left of the ( + * pn_right: Arguments * PNK_DELETENAME unary pn_kid: PNK_NAME expr * PNK_DELETEPROP unary pn_kid: PNK_DOT expr * PNK_DELETEELEM unary pn_kid: PNK_ELEM expr @@ -410,10 +410,11 @@ IsTypeofKind(ParseNodeKind kind) * pn_atom: name to right of . * PNK_ELEM binary pn_left: MEMBER expr to left of [ * pn_right: expr between [ and ] - * PNK_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 - * PNK_GENEXP list Exactly like PNK_CALL, used for the implicit call + * PNK_CALL binary pn_left: callee expression on the left of the ( + * pn_right: Arguments + * PNK_ARGUMENTS list pn_head: list of arg1, arg2, ... argN + * pn_count: N (where N is number of args) + * PNK_GENEXP binary Exactly like PNK_CALL, used for the implicit call * in the desugaring of a generator-expression. * PNK_ARRAY list pn_head: list of pn_count array element exprs * [,,] holes are represented by PNK_ELISION nodes @@ -434,8 +435,8 @@ IsTypeofKind(ParseNodeKind kind) * list * PNK_TEMPLATE_STRING pn_atom: template string atom nullary pn_op: JSOP_NOP - * PNK_TAGGED_TEMPLATE pn_head: list of call, call site object, arg1, arg2, ... argN - * list pn_count: 2 + N (N is the number of substitutions) + * PNK_TAGGED_TEMPLATE pn_left: tag expression + * binary pn_right: Arguments, with the first being the call site object, then arg1, arg2, ... argN * PNK_CALLSITEOBJ list pn_head: a PNK_ARRAY node followed by * list of pn_count - 1 PNK_TEMPLATE_STRING nodes * PNK_REGEXP nullary pn_objbox: RegExp model object @@ -448,6 +449,8 @@ IsTypeofKind(ParseNodeKind kind) * PNK_THIS, unary pn_kid: '.this' Name if function `this`, else nullptr * PNK_SUPERBASE unary pn_kid: '.this' Name * + * PNK_SUPERCALL binary pn_left: SuperBase pn_right: Arguments + * * PNK_SETTHIS binary pn_left: '.this' Name, pn_right: SuperCall * * PNK_LEXICALSCOPE scope pn_u.scope.bindings: scope bindings @@ -744,7 +747,7 @@ class ParseNode ParseNode* generatorExpr() const { MOZ_ASSERT(isKind(PNK_GENEXP)); - ParseNode* callee = this->pn_head; + ParseNode* callee = this->pn_left; MOZ_ASSERT(callee->isKind(PNK_FUNCTION)); ParseNode* paramsBody = callee->pn_body; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 379455de7e..08812741af 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -3268,12 +3268,12 @@ Parser::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling template bool -Parser::taggedTemplate(YieldHandling yieldHandling, Node nodeList, TokenKind tt) +Parser::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)) @@ -3281,10 +3281,10 @@ Parser::taggedTemplate(YieldHandling yieldHandling, Node nodeList, if (tt != TOK_TEMPLATE_HEAD) break; - if (!addExprAndGetNextTemplStrToken(yieldHandling, nodeList, &tt)) + if (!addExprAndGetNextTemplStrToken(yieldHandling, tagArgsList, &tt)) return false; } - handler.setEndPosition(nodeList, callSiteObjNode); + handler.setEndPosition(tagArgsList, callSiteObjNode); return true; } @@ -9037,7 +9037,13 @@ Parser::generatorComprehension(uint32_t begin) if (!genfn) return null(); - Node result = handler.newList(PNK_GENEXP, genfn, JSOP_CALL); + // Create a dummy argsList so that PNK_GENEXP can be handled as a full PN_BINARY call node + Node argsList = handler.newArguments(pos()); + if (!argsList) + return null(); + handler.setBeginPosition(argsList, pos().end); + + Node result = handler.newGenExp(genfn, argsList); if (!result) return null(); handler.setBeginPosition(result, begin); @@ -9067,23 +9073,27 @@ Parser::assignExprWithoutYieldOrAwait(YieldHandling yieldHandling) } template -bool -Parser::argumentList(YieldHandling yieldHandling, Node listNode, bool* isSpread, +typename ParseHandler::Node +Parser::argumentList(YieldHandling yieldHandling, bool* isSpread, PossibleError* possibleError /* = nullptr */) { + Node argsList = handler.newArguments(pos()); + if (!argsList) + return null(); + bool matched; if (!tokenStream.matchToken(&matched, TOK_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, TOK_TRIPLEDOT, TokenStream::Operand)) - return false; + return null(); if (matched) { spread = true; begin = pos().begin; @@ -9092,18 +9102,18 @@ Parser::argumentList(YieldHandling yieldHandling, Node listNode, b Node argNode = assignExpr(InAllowed, yieldHandling, TripledotProhibited, possibleError); if (!argNode) - return false; + return null(); if (spread) { argNode = handler.newSpread(begin, argNode); if (!argNode) - return false; + return null(); } - handler.addList(listNode, argNode); + handler.addList(argsList, argNode); bool matched; if (!tokenStream.matchToken(&matched, TOK_COMMA)) - return false; + return null(); if (!matched) break; @@ -9118,8 +9128,8 @@ Parser::argumentList(YieldHandling yieldHandling, Node listNode, b MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_ARGS); - handler.setEndPosition(listNode, pos().end); - return true; + handler.setEndPosition(argsList, pos().end); + return argsList; } template @@ -9155,10 +9165,6 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling if (newTarget) { lhs = newTarget; } else { - lhs = handler.newList(PNK_NEW, newBegin, JSOP_NEW); - if (!lhs) - return null(); - // Gotten by tryNewTarget tt = tokenStream.currentToken().type; Node ctorExpr = memberExpr(yieldHandling, TripledotProhibited, tt, @@ -9167,8 +9173,6 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling if (!ctorExpr) return null(); - handler.addList(lhs, ctorExpr); - // If we have encountered an optional chain, in the form of `new // ClassName?.()` then we need to throw, as this is disallowed // by the spec. @@ -9184,13 +9188,24 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling bool matched; if (!tokenStream.matchToken(&matched, TOK_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 == TOK_SUPER) { Node thisName = newThisName(); @@ -9244,15 +9259,16 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling return null(); } - nextMember = handler.newList(PNK_SUPERCALL, lhs, JSOP_SUPERCALL); - 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) @@ -9368,17 +9384,6 @@ Parser::memberCall( tt == TOK_NO_SUBS_TEMPLATE, "Unexpected token kind for member call"); - Node nextMember; - if (tt == TOK_LP) { - if (optionalKind == OptionalKind::Optional) { - nextMember = handler.newOptionalCall(); - } else { - nextMember = handler.newCall(); - } - } else { - nextMember = handler.newTaggedTemplate(); - } - JSOp op = JSOP_CALL; bool maybeAsyncArrow = false; if (PropertyName* prop = handler.maybeDottedProperty(lhs)) { @@ -9422,16 +9427,15 @@ Parser::memberCall( } } - handler.setBeginPosition(nextMember, lhs); - handler.addList(nextMember, lhs); - + Node nextMember; if (tt == TOK_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(); } @@ -9444,14 +9448,30 @@ Parser::memberCall( op = JSOP_SPREADCALL; } } + + if (optionalKind == OptionalKind::Optional) { + nextMember = handler.newOptionalCall(lhs, args); + } else { + 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(); } if (optionalKind == OptionalKind::Optional) { error(JSMSG_BAD_OPTIONAL_TEMPLATE); return null(); } + + nextMember = handler.newTaggedTemplate(lhs, args); + if (!nextMember) + return null(); } handler.setOp(nextMember, op); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 4e5e18a265..ad5e079674 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1374,7 +1374,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter Node arrayComprehension(uint32_t begin); Node generatorComprehension(uint32_t begin); - 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); diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 85c8061162..2ada163938 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -289,9 +289,12 @@ class SyntaxParseHandler MOZ_MUST_USE bool addSpreadElement(Node literal, uint32_t begin, Node inner) { return true; } void addArrayElement(Node literal, Node element) { } - Node newCall() { return NodeFunctionCall; } - Node newOptionalCall() { return NodeOptionalFunctionCall; } - Node newTaggedTemplate() { return NodeGeneric; } + Node newCall(Node callee, Node args) { return NodeFunctionCall; } + Node newOptionalCall(Node callee, Node args) { return NodeOptionalFunctionCall; } + Node newArguments(const TokenPos& pos) { return NodeGeneric; } + Node newSuperCall(Node callee, Node args) { return NodeGeneric; } + Node newTaggedTemplate(Node callee, Node args) { return NodeGeneric; } + Node newGenExp(Node callee, Node args) { return NodeGeneric; } Node newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; } Node newClassMethodList(uint32_t begin) { return NodeGeneric; } @@ -491,6 +494,11 @@ class SyntaxParseHandler list == NodeOptionalFunctionCall); } + + Node newNewExpression(uint32_t begin, Node ctor, Node args) { + return NodeGeneric; + } + Node newAssignment(ParseNodeKind kind, Node lhs, Node rhs, JSOp op) { if (kind == PNK_ASSIGN) return NodeUnparenthesizedAssignment; diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index 0ecaee6d45..cf224d54ea 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -465,22 +465,21 @@ static inline ParseNode* CallCallee(ParseNode* pn) { MOZ_ASSERT(pn->isKind(PNK_CALL)); - return ListHead(pn); + return BinaryLeft(pn); } static inline unsigned CallArgListLength(ParseNode* pn) { MOZ_ASSERT(pn->isKind(PNK_CALL)); - MOZ_ASSERT(ListLength(pn) >= 1); - return ListLength(pn) - 1; + return ListLength(BinaryRight(pn)); } static inline ParseNode* CallArgList(ParseNode* pn) { MOZ_ASSERT(pn->isKind(PNK_CALL)); - return NextNode(ListHead(pn)); + return ListHead(BinaryRight(pn)); } static inline ParseNode* @@ -3433,9 +3432,11 @@ IsArrayViewCtorName(ModuleValidator& m, PropertyName* name, Scalar::Type* type) } static bool -CheckNewArrayViewArgs(ModuleValidator& m, ParseNode* ctorExpr, PropertyName* bufferName) +CheckNewArrayViewArgs(ModuleValidator& m, ParseNode* newExpr, PropertyName* bufferName) { - ParseNode* bufArg = NextNode(ctorExpr); + 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"); @@ -3456,7 +3457,7 @@ CheckNewArrayView(ModuleValidator& m, PropertyName* varName, ParseNode* newExpr) 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; @@ -3485,7 +3486,7 @@ CheckNewArrayView(ModuleValidator& m, PropertyName* varName, ParseNode* newExpr) type = global->viewType(); } - if (!CheckNewArrayViewArgs(m, ctorExpr, bufferName)) + if (!CheckNewArrayViewArgs(m, newExpr, bufferName)) return false; return m.addArrayView(varName, type, field);