Bug 1378808 - Add a new ParseNodeKind::Arguments node type for call argument lists. r=jorendorff

MozReview-Commit-ID: 7L4nNHjVoZo

--HG--
extra : rebase_source : 4140fd0df54bece716e4c5e0d68fbb3df16a6268
extra : source : e732697778c260c413047531e372a24286e0b667
This commit is contained in:
Logan F Smyth 2018-07-12 11:24:59 -07:00
parent 83c5c90bf7
commit ede9c30b6f
13 changed files with 313 additions and 244 deletions

View File

@ -2702,24 +2702,25 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
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);

View File

@ -3462,9 +3462,8 @@ BinASTParser<Tok>::parseInterfaceCallExpression(const size_t start, const BinKin
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;
}
@ -3742,7 +3741,7 @@ BinASTParser<Tok>::parseInterfaceComputedMemberAssignmentTarget(const size_t sta
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;
}
@ -3786,7 +3785,7 @@ BinASTParser<Tok>::parseInterfaceComputedMemberExpression(const size_t start, co
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;
}
@ -5677,10 +5676,7 @@ BinASTParser<Tok>::parseInterfaceNewExpression(const size_t start, const BinKind
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;
}
@ -6203,7 +6199,7 @@ BinASTParser<Tok>::parseInterfaceStaticMemberAssignmentTarget(const size_t start
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;
}
@ -6248,7 +6244,7 @@ BinASTParser<Tok>::parseInterfaceStaticMemberExpression(const size_t start, cons
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;
}
@ -7381,7 +7377,7 @@ BinASTParser<Tok>::parseArguments()
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());

View File

@ -207,7 +207,7 @@ hpp:
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, /* kid = */ item);
@ -428,9 +428,8 @@ CallExpression:
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);
@ -489,11 +488,11 @@ CompoundAssignmentExpression:
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: |
@ -831,10 +830,7 @@ LiteralStringExpression:
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:
@ -923,11 +919,11 @@ SwitchStatementWithDefault:
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: |

View File

@ -1260,6 +1260,14 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
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;
@ -4819,7 +4827,7 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, const EmitterScope* headLexical
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;
}
@ -6140,10 +6148,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;
}
@ -6154,8 +6164,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() == ParseNodeKind::Name &&
@ -6168,7 +6178,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;
@ -6197,7 +6207,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;
@ -6208,15 +6218,15 @@ BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn)
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;
@ -6248,24 +6258,26 @@ BytecodeEmitter::emitSelfHostedForceInterpreter()
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* pn_args = pn->pn_right;
ParseNode* funNode = pn->pn_head; // The _DefineDataProperty node.
// Only optimize when 3 arguments are passed.
MOZ_ASSERT(pn_args->pn_count == 3);
ParseNode* objNode = funNode->pn_next;
ParseNode* objNode = pn_args->pn_head;
if (!emitTree(objNode))
return false;
@ -6286,14 +6298,14 @@ BytecodeEmitter::emitSelfHostedDefineDataProperty(ParseNode* pn)
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;
@ -6307,14 +6319,14 @@ BytecodeEmitter::emitSelfHostedHasOwn(ParseNode* pn)
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;
@ -6343,11 +6355,11 @@ BytecodeEmitter::isRestParameter(ParseNode* pn)
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;
@ -6477,101 +6489,22 @@ BytecodeEmitter::emitPipeline(ParseNode* pn)
}
bool
BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */)
BytecodeEmitter::emitArguments(ParseNode* pn, bool callop, bool spread)
{
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;
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);
@ -6611,15 +6544,100 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUs
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;
}
}
@ -7204,7 +7222,7 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count)
if (emitterMode == BytecodeEmitter::SelfHosting &&
expr->isKind(ParseNodeKind::Call) &&
expr->pn_head->name() == cx->names().allowContentIter)
expr->pn_left->name() == cx->names().allowContentIter)
{
allowSelfHostedIter = true;
}

View File

@ -808,6 +808,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
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);

View File

@ -349,6 +349,7 @@ ContainsHoistedDeclaration(JSContext* cx, ParseNode* node, bool* result)
case ParseNodeKind::Object:
case ParseNodeKind::Dot:
case ParseNodeKind::Elem:
case ParseNodeKind::Arguments:
case ParseNodeKind::Call:
case ParseNodeKind::Name:
case ParseNodeKind::TemplateString:
@ -1409,8 +1410,9 @@ FoldCall(JSContext* cx, ParseNode* node, PerHandlerParser<FullParseHandler>& par
{
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:
@ -1423,10 +1425,26 @@ FoldCall(JSContext* cx, ParseNode* node, PerHandlerParser<FullParseHandler>& par
// assertEq(obj.f``, "obj");
//
// See bug 537673 and bug 1182373.
ParseNode** listp = &node->pn_head;
if ((*listp)->isInParens())
listp = &(*listp)->pn_next;
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;
for (; *listp; listp = &(*listp)->pn_next) {
if (!Fold(cx, listp, parser))
return false;
@ -1642,7 +1660,6 @@ Fold(JSContext* cx, ParseNode** pnp, PerHandlerParser<FullParseHandler>& parser)
case ParseNodeKind::InstanceOf:
case ParseNodeKind::In:
case ParseNodeKind::Comma:
case ParseNodeKind::New:
case ParseNodeKind::Array:
case ParseNodeKind::Object:
case ParseNodeKind::StatementList:
@ -1694,10 +1711,14 @@ Fold(JSContext* cx, ParseNode** pnp, PerHandlerParser<FullParseHandler>& parser)
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:

View File

@ -275,16 +275,20 @@ class FullParseHandler
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) {
@ -735,13 +739,8 @@ class FullParseHandler
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) {

View File

@ -315,17 +315,17 @@ class NameResolver
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));
@ -697,9 +697,6 @@ class NameResolver
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:
@ -733,11 +730,32 @@ class NameResolver
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.

View File

@ -63,6 +63,7 @@ class ObjectBox;
F(Label) \
F(Object) \
F(Call) \
F(Arguments) \
F(Name) \
F(ObjectPropertyName) \
F(ComputedName) \
@ -371,9 +372,8 @@ IsTypeofKind(ParseNodeKind kind)
* 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
@ -386,9 +386,10 @@ IsTypeofKind(ParseNodeKind kind)
* 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
@ -408,8 +409,9 @@ IsTypeofKind(ParseNodeKind kind)
* 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
@ -421,7 +423,7 @@ IsTypeofKind(ParseNodeKind kind)
*
* 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

View File

@ -3397,13 +3397,13 @@ GeneralParser<ParseHandler, CharT>::addExprAndGetNextTemplStrToken(YieldHandling
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))
@ -3411,10 +3411,10 @@ GeneralParser<ParseHandler, CharT>::taggedTemplate(YieldHandling yieldHandling,
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;
}
@ -8643,24 +8643,27 @@ GeneralParser<ParseHandler, CharT>::assignExprWithoutYieldOrAwait(YieldHandling
}
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());
if (!argsList)
return null();
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;
@ -8669,18 +8672,18 @@ GeneralParser<ParseHandler, CharT>::argumentList(YieldHandling yieldHandling, No
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, TokenKind::Comma, TokenStream::Operand))
return false;
return null();
if (!matched)
break;
@ -8693,8 +8696,8 @@ GeneralParser<ParseHandler, CharT>::argumentList(YieldHandling yieldHandling, No
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
@ -8740,20 +8743,27 @@ GeneralParser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
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();
@ -8826,15 +8836,16 @@ GeneralParser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
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)
@ -8853,13 +8864,6 @@ GeneralParser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
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)) {
@ -8901,13 +8905,11 @@ GeneralParser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
}
}
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)
@ -8917,8 +8919,20 @@ GeneralParser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
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);

View File

@ -1155,7 +1155,7 @@ class MOZ_STACK_CLASS GeneralParser
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);

View File

@ -248,9 +248,11 @@ class SyntaxParseHandler
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; }
@ -428,7 +430,7 @@ class SyntaxParseHandler
list == NodeFunctionCall);
}
Node newNewExpression(uint32_t begin, Node ctor) {
Node newNewExpression(uint32_t begin, Node ctor, Node args) {
return NodeGeneric;
}

View File

@ -416,22 +416,21 @@ 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*
@ -2800,9 +2799,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");
@ -2823,7 +2824,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;
@ -2852,7 +2853,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);