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