Issue #2173 - Add a new PNK_ARGUMENTS node type for call argument lists

Also change PNK_GENEXP (not supported by upstream) to a PN_BINARY node

Based-on: m-c 1378808/1
This commit is contained in:
Martok 2023-03-23 02:03:26 +01:00 committed by roytam1
commit 924140d400
12 changed files with 249 additions and 163 deletions

View file

@ -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);

View file

@ -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;
}

View file

@ -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);

View file

@ -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<FullParseHandler>& 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<FullParseHandler>& 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<FullParseHandler>& 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<FullParseHandler>& 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<FullParseHandler>& 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<FullParseHandler>& 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<FullParseHandler>& 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:

View file

@ -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_<BinaryNode>(PNK_CALL, JSOP_CALL, callee, args);
}
ParseNode* newOptionalCall() {
return newList(PNK_OPTCALL, JSOP_CALL);
ParseNode* newOptionalCall(ParseNode* callee, ParseNode* args) {
return new_<BinaryNode>(PNK_OPTCALL, JSOP_CALL, callee, args);
}
ParseNode* newTaggedTemplate() {
return newList(PNK_TAGGED_TEMPLATE, JSOP_CALL);
ParseNode* newArguments(const TokenPos& pos) {
return new_<ListNode>(PNK_ARGUMENTS, JSOP_NOP, pos);
}
ParseNode* newSuperCall(ParseNode* callee, ParseNode* args) {
return new_<BinaryNode>(PNK_SUPERCALL, JSOP_SUPERCALL, callee, args);
}
ParseNode* newTaggedTemplate(ParseNode* tag, ParseNode* args) {
return new_<BinaryNode>(PNK_TAGGED_TEMPLATE, JSOP_CALL, tag, args);
}
ParseNode* newGenExp(ParseNode* callee, ParseNode* args) {
return new_<BinaryNode>(PNK_GENEXP, JSOP_CALL, callee, args);
}
ParseNode* newObjectLiteral(uint32_t begin) {
@ -765,6 +777,10 @@ class FullParseHandler
return new_<CodeNode>(PNK_MODULE, JSOP_NOP, pos());
}
Node newNewExpression(uint32_t begin, ParseNode* ctor, ParseNode* args) {
return new_<BinaryNode>(PNK_NEW, JSOP_NEW, TokenPos(begin, args->pn_pos.end), ctor, args);
}
ParseNode* newLexicalScope(LexicalScope::Data* bindings, ParseNode* body) {
return new_<LexicalScopeNode>(bindings, body);
}

View file

@ -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.

View file

@ -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:

View file

@ -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;

View file

@ -3268,12 +3268,12 @@ Parser<ParseHandler>::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling
template <typename ParseHandler>
bool
Parser<ParseHandler>::taggedTemplate(YieldHandling yieldHandling, Node nodeList, TokenKind tt)
Parser<ParseHandler>::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<ParseHandler>::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<ParseHandler>::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<ParseHandler>::assignExprWithoutYieldOrAwait(YieldHandling yieldHandling)
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::argumentList(YieldHandling yieldHandling, Node listNode, bool* isSpread,
typename ParseHandler::Node
Parser<ParseHandler>::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<ParseHandler>::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<ParseHandler>::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 <typename ParseHandler>
@ -9155,10 +9165,6 @@ Parser<ParseHandler>::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<ParseHandler>::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<ParseHandler>::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<ParseHandler>::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<ParseHandler>::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<ParseHandler>::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<ParseHandler>::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);

View file

@ -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);

View file

@ -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;

View file

@ -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);