#
# Manuall backport of Mozilla's bug 1378808 and others, mostly
# to prepare code for backporting of optional chaining support.
#
# bug 1378808 (part 1-3)
# bug 1518661 part 3 only (and without all the tests)
#
diff -Nrup mozilla-OLD/js/src/builtin/ReflectParse.cpp mozilla/js/src/builtin/ReflectParse.cpp
--- mozilla-OLD/js/src/builtin/ReflectParse.cpp 2021-12-29 03:47:40.631227104 +0300
+++ mozilla/js/src/builtin/ReflectParse.cpp 2021-12-29 03:37:16.052713992 +0300
@@ -2945,24 +2945,25 @@ ASTSerializer::expression(ParseNode* pn,
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);
@@ -2983,17 +2984,17 @@ ASTSerializer::expression(ParseNode* pn,
case ParseNodeKind::Dot:
{
- MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_expr->pn_pos));
+ MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
RootedValue expr(cx);
RootedValue propname(cx);
- RootedAtom pnAtom(cx, pn->pn_atom);
+ RootedAtom pnAtom(cx, pn->pn_right->pn_atom);
if (pn->as<PropertyAccess>().isSuper()) {
- if (!builder.super(&pn->pn_expr->pn_pos, &expr))
+ if (!builder.super(&pn->pn_left->pn_pos, &expr))
return false;
} else {
- if (!expression(pn->pn_expr, &expr))
+ if (!expression(pn->pn_left, &expr))
return false;
}
diff -Nrup mozilla-OLD/js/src/frontend/BytecodeEmitter.cpp mozilla/js/src/frontend/BytecodeEmitter.cpp
--- mozilla-OLD/js/src/frontend/BytecodeEmitter.cpp 2021-12-29 03:47:40.635227075 +0300
+++ mozilla/js/src/frontend/BytecodeEmitter.cpp 2021-12-29 03:47:09.644450104 +0300
@@ -3143,7 +3143,7 @@ BytecodeEmitter::checkSideEffects(ParseN
// Watch out for getters!
case ParseNodeKind::Dot:
- MOZ_ASSERT(pn->isArity(PN_NAME));
+ MOZ_ASSERT(pn->isArity(PN_BINARY));
*answer = true;
return true;
@@ -3388,6 +3388,14 @@ BytecodeEmitter::checkSideEffects(ParseN
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;
@@ -3533,6 +3541,7 @@ BytecodeEmitter::checkSideEffects(ParseN
case ParseNodeKind::CallSiteObj: // byParseNodeKind::TaggedTemplate
case ParseNodeKind::PosHolder: // byParseNodeKind::NewTarget
case ParseNodeKind::SuperBase: // byParseNodeKind::Elem and others
+ case ParseNodeKind::PropertyName: // by ParseNodeKind::Dot
MOZ_CRASH("handled by parent nodes");
case ParseNodeKind::Limit: // invalid sentinel value
@@ -4026,11 +4035,11 @@ BytecodeEmitter::emitPropLHS(ParseNode*
MOZ_ASSERT(pn->isKind(ParseNodeKind::Dot));
MOZ_ASSERT(!pn->as<PropertyAccess>().isSuper());
- ParseNode* pn2 = pn->pn_expr;
+ ParseNode* pn2 = pn->pn_left;
/*
* If the object operand is also a dotted property reference, reverse the
- * list linked via pn_expr temporarily so we can iterate over it from the
+ * list linked via pn_left temporarily so we can iterate over it from the
* bottom up (reversing again as we go), to avoid excessive recursion.
*/
if (pn2->isKind(ParseNodeKind::Dot) && !pn2->as<PropertyAccess>().isSuper()) {
@@ -4038,9 +4047,9 @@ BytecodeEmitter::emitPropLHS(ParseNode*
ParseNode* pnup = nullptr;
ParseNode* pndown;
for (;;) {
- /* Reverse pndot->pn_expr to point up, not down. */
- pndown = pndot->pn_expr;
- pndot->pn_expr = pnup;
+ /* Reverse pndot->pn_left to point up, not down. */
+ pndown = pndot->pn_left;
+ pndot->pn_left = pnup;
if (!pndown->isKind(ParseNodeKind::Dot) || pndown->as<PropertyAccess>().isSuper())
break;
pnup = pndot;
@@ -4053,12 +4062,12 @@ BytecodeEmitter::emitPropLHS(ParseNode*
do {
/* Walk back up the list, emitting annotated name ops. */
- if (!emitAtomOp(pndot, JSOP_GETPROP))
+ if (!emitAtomOp(pndot->pn_right, JSOP_GETPROP))
return false;
- /* Reverse the pn_expr link again. */
- pnup = pndot->pn_expr;
- pndot->pn_expr = pndown;
+ /* Reverse the pn_left link again. */
+ pnup = pndot->pn_left;
+ pndot->pn_left = pndown;
pndown = pndot;
} while ((pndot = pnup) != nullptr);
return true;
@@ -4083,7 +4092,7 @@ BytecodeEmitter::emitSuperPropLHS(ParseN
bool
BytecodeEmitter::emitPropOp(ParseNode* pn, JSOp op)
{
- MOZ_ASSERT(pn->isArity(PN_NAME));
+ MOZ_ASSERT(pn->isArity(PN_BINARY));
if (!emitPropLHS(pn))
return false;
@@ -4091,7 +4100,7 @@ BytecodeEmitter::emitPropOp(ParseNode* p
if (op == JSOP_CALLPROP && !emit1(JSOP_DUP))
return false;
- if (!emitAtomOp(pn, op))
+ if (!emitAtomOp(pn->pn_right, op))
return false;
if (op == JSOP_CALLPROP && !emit1(JSOP_SWAP))
@@ -4107,7 +4116,7 @@ BytecodeEmitter::emitSuperPropOp(ParseNo
if (!emitSuperPropLHS(base, isCall))
return false;
- if (!emitAtomOp(pn, op))
+ if (!emitAtomOp(pn->pn_right, op))
return false;
if (isCall && !emit1(JSOP_SWAP))
@@ -4137,7 +4146,7 @@ BytecodeEmitter::emitPropIncDec(ParseNod
if (!emit1(JSOP_DUP)) // OBJ OBJ
return false;
}
- if (!emitAtomOp(pn->pn_kid, isSuper? JSOP_GETPROP_SUPER : JSOP_GETPROP)) // OBJ V
+ if (!emitAtomOp(pn->pn_kid->pn_right, isSuper ? JSOP_GETPROP_SUPER : JSOP_GETPROP)) // OBJ V
return false;
if (!emit1(JSOP_POS)) // OBJ N
return false;
@@ -4163,7 +4172,7 @@ BytecodeEmitter::emitPropIncDec(ParseNod
JSOp setOp = isSuper ? sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER
: sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
- if (!emitAtomOp(pn->pn_kid, setOp)) // N? N+1
+ if (!emitAtomOp(pn->pn_kid->pn_right, setOp)) // N? N+1
return false;
if (post && !emit1(JSOP_POP)) // RESULT
return false;
@@ -5140,7 +5149,7 @@ BytecodeEmitter::emitDestructuringLHSRef
return false;
*emitted = 2;
} else {
- if (!emitTree(target->pn_expr))
+ if (!emitTree(target->pn_left))
return false;
*emitted = 1;
}
@@ -5258,7 +5267,7 @@ BytecodeEmitter::emitSetOrInitializeDest
setOp = sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER;
else
setOp = sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
- if (!emitAtomOp(target, setOp))
+ if (!emitAtomOp(target->pn_right, setOp))
return false;
break;
}
@@ -6333,11 +6342,11 @@ BytecodeEmitter::emitAssignment(ParseNod
return false;
offset += 2;
} else {
- if (!emitTree(lhs->expr()))
+ if (!emitTree(lhs->pn_left))
return false;
offset += 1;
}
- if (!makeAtomIndex(lhs->pn_atom, &atomIndex))
+ if (!makeAtomIndex(lhs->pn_right->pn_atom, &atomIndex))
return false;
break;
case ParseNodeKind::Elem: {
@@ -6386,7 +6395,7 @@ BytecodeEmitter::emitAssignment(ParseNod
} else {
if (!emit1(JSOP_DUP))
return false;
- bool isLength = (lhs->pn_atom == cx->names().length);
+ bool isLength = (lhs->pn_right->pn_atom == cx->names().length);
getOp = isLength ? JSOP_LENGTH : JSOP_GETPROP;
}
if (!emitIndex32(getOp, atomIndex))
@@ -7211,7 +7220,7 @@ BytecodeEmitter::emitForOf(ParseNode* fo
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;
}
@@ -9251,10 +9260,12 @@ BytecodeEmitter::emitSelfHostedCallFunct
//
// 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;
+
+ const char* errorName = SelfHostedCallFunctionName(pn_callee->name(), cx);
- if (pn->pn_count < 3) {
+ if (pn_args->pn_count < 2) {
reportError(pn, JSMSG_MORE_ARGS_NEEDED, errorName, "2", "s");
return false;
}
@@ -9265,8 +9276,8 @@ BytecodeEmitter::emitSelfHostedCallFunct
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 &&
@@ -9279,7 +9290,7 @@ BytecodeEmitter::emitSelfHostedCallFunct
#ifdef DEBUG
if (emitterMode == BytecodeEmitter::SelfHosting &&
- pn2->name() == cx->names().callFunction)
+ pn_callee->name() == cx->names().callFunction)
{
if (!emit1(JSOP_DEBUGCHECKSELFHOSTED))
return false;
@@ -9308,7 +9319,7 @@ BytecodeEmitter::emitSelfHostedCallFunct
return false;
}
- uint32_t argc = pn->pn_count - 3;
+ uint32_t argc = pn_args->pn_count - 2;
if (!emitCall(callOp, argc))
return false;
@@ -9319,15 +9330,15 @@ BytecodeEmitter::emitSelfHostedCallFunct
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;
@@ -9359,24 +9370,26 @@ BytecodeEmitter::emitSelfHostedForceInte
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;
@@ -9397,14 +9410,14 @@ BytecodeEmitter::emitSelfHostedDefineDat
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;
@@ -9428,11 +9441,11 @@ BytecodeEmitter::isRestParameter(ParseNo
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;
@@ -9561,10 +9574,72 @@ BytecodeEmitter::emitPipeline(ParseNode*
}
bool
+BytecodeEmitter::emitArguments(ParseNode* pn, bool callop, bool spread)
+{
+ uint32_t argc = pn->pn_count;
+
+ if (argc >= ARGC_LIMIT) {
+ parser.reportError(callop ? JSMSG_TOO_MANY_FUN_ARGS : JSMSG_TOO_MANY_CON_ARGS);
+ return false;
+ }
+
+ if (!spread) {
+ for (ParseNode* pn3 = pn->pn_head; pn3; pn3 = pn3->pn_next) {
+ if (!emitTree(pn3))
+ return false;
+ }
+ } else {
+ ParseNode* args = pn->pn_head;
+ bool emitOptCode = (argc == 1) && isRestParameter(args->pn_kid);
+ IfThenElseEmitter ifNotOptimizable(this);
+
+ if (emitOptCode) {
+ // Emit a preparation code to optimize the spread call with a rest
+ // parameter:
+ //
+ // function f(...args) {
+ // g(...args);
+ // }
+ //
+ // If the spread operand is a rest parameter and it's optimizable
+ // array, skip spread operation and pass it directly to spread call
+ // operation. See the comment in OptimizeSpreadCall in
+ // Interpreter.cpp for the optimizable conditons.
+
+ if (!emitTree(args->pn_kid))
+ return false;
+
+ if (!emit1(JSOP_OPTIMIZE_SPREADCALL))
+ return false;
+
+ if (!emit1(JSOP_NOT))
+ return false;
+
+ if (!ifNotOptimizable.emitIf())
+ return false;
+
+ if (!emit1(JSOP_POP))
+ return false;
+ }
+
+ 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
@@ -9580,46 +9655,40 @@ BytecodeEmitter::emitCallOrNew(ParseNode
* value required for calls (which non-strict mode functions
* will box into the global object).
*/
- uint32_t argc = pn->pn_count - 1;
+ ParseNode* pn_callee = pn->pn_left;
+ ParseNode* pn_args = pn->pn_right;
- if (argc >= ARGC_LIMIT) {
- parser.reportError(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) {
+ 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 (pn2->name() == cx->names().callFunction ||
- pn2->name() == cx->names().callContentFunction ||
- pn2->name() == cx->names().constructContentFunction)
+ if (pn_callee->name() == cx->names().callFunction ||
+ pn_callee->name() == cx->names().callContentFunction ||
+ pn_callee->name() == cx->names().constructContentFunction)
{
return emitSelfHostedCallFunction(pn);
}
- if (pn2->name() == cx->names().resumeGenerator)
+ if (pn_callee->name() == cx->names().resumeGenerator)
return emitSelfHostedResumeGenerator(pn);
- if (pn2->name() == cx->names().forceInterpreter)
+ if (pn_callee->name() == cx->names().forceInterpreter)
return emitSelfHostedForceInterpreter(pn);
- if (pn2->name() == cx->names().allowContentIter)
+ if (pn_callee->name() == cx->names().allowContentIter)
return emitSelfHostedAllowContentIter(pn);
- if (pn2->name() == cx->names().defineDataPropertyIntrinsic && pn->pn_count == 4)
+ if (pn_callee->name() == cx->names().defineDataPropertyIntrinsic && pn_args->pn_count == 3)
return emitSelfHostedDefineDataProperty(pn);
- if (pn2->name() == cx->names().hasOwn)
+ if (pn_callee->name() == cx->names().hasOwn)
return emitSelfHostedHasOwn(pn);
// Fall through
}
- if (!emitCallee(pn2, pn, spread, &callop))
+ if (!emitCallee(pn_callee, pn, false, &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) {
@@ -9631,91 +9700,77 @@ BytecodeEmitter::emitCallOrNew(ParseNode
}
}
+ 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 (!spread) {
- for (ParseNode* pn3 = pn2->pn_next; 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;
- bool emitOptCode = (argc == 1) && isRestParameter(args->pn_kid);
- IfThenElseEmitter ifNotOptimizable(this);
-
- if (emitOptCode) {
- // Emit a preparation code to optimize the spread call with a rest
- // parameter:
- //
- // function f(...args) {
- // g(...args);
- // }
- //
- // If the spread operand is a rest parameter and it's optimizable
- // array, skip spread operation and pass it directly to spread call
- // operation. See the comment in OptimizeSpreadCall in
- // Interpreter.cpp for the optimizable conditons.
-
- if (!emitTree(args->pn_kid))
- return false;
-
- if (!emit1(JSOP_OPTIMIZE_SPREADCALL))
- return false;
-
- if (!emit1(JSOP_NOT))
+ if (isNewOp) {
+ if (pn->isKind(ParseNodeKind::SuperCall)) {
+ if (!emit1(JSOP_NEWTARGET))
return false;
-
- if (!ifNotOptimizable.emitIf())
+ } else if (!spread) {
+ // Repush the callee as new.target
+ if (!emitDupAt(argc + 1))
return false;
-
- if (!emit1(JSOP_POP))
+ } else {
+ if (!emitDupAt(2))
return false;
}
+ }
- if (!emitArray(args, argc))
- return false;
-
- if (emitOptCode) {
- if (!ifNotOptimizable.emitEnd())
- return false;
- }
+ 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
+ coordNode = pn_args;
- if (isNewOp) {
- if (pn->isKind(ParseNodeKind::SuperCall)) {
- if (!emit1(JSOP_NEWTARGET))
- return false;
- } else {
- if (!emitDupAt(2))
- return false;
- }
+ switch (pn_callee->getKind()) {
+ case ParseNodeKind::Dot:
+ // Use the position of a property access identifier.
+ //
+ // obj().aprop() // expression
+ // ^ // column coord
+ //
+ // Note: Because of the constant folding logic in FoldElement,
+ // this case also applies for constant string properties.
+ //
+ // obj()['aprop']() // expression
+ // ^ // column coord
+ coordNode = pn_callee->pn_right;
+ break;
+ case ParseNodeKind::Name:
+ // Use the start of callee names.
+ coordNode = pn_callee;
+ break;
+ default:
+ break;
}
}
if (!spread) {
if (pn->getOp() == JSOP_CALL && valueUsage == ValueUsage::IgnoreValue) {
- if (!emitCall(JSOP_CALL_IGNORES_RV, argc, pn))
+ if (!emitCall(JSOP_CALL_IGNORES_RV, argc, coordNode))
return false;
checkTypeSet(JSOP_CALL_IGNORES_RV);
} else {
- if (!emitCall(pn->getOp(), argc, pn))
+ if (!emitCall(pn->getOp(), argc, coordNode))
return false;
checkTypeSet(pn->getOp());
}
} else {
+ if (coordNode) {
+ if (!updateSourceCoordNotes(coordNode->pn_pos.begin))
+ return false;
+ }
+
if (!emit1(pn->getOp()))
return false;
checkTypeSet(pn->getOp());
@@ -10331,7 +10386,7 @@ BytecodeEmitter::emitArray(ParseNode* pn
if (emitterMode == BytecodeEmitter::SelfHosting &&
expr->isKind(ParseNodeKind::Call) &&
- expr->pn_head->name() == cx->names().allowContentIter)
+ expr->pn_left->name() == cx->names().allowContentIter)
{
allowSelfHostedIter = true;
}
@@ -11394,8 +11449,9 @@ BytecodeEmitter::emitTree(ParseNode* pn,
return false;
break;
+ case ParseNodeKind::PropertyName:
case ParseNodeKind::PosHolder:
- MOZ_FALLTHROUGH_ASSERT("Should never try to emitParseNodeKind::PosHolder");
+ MOZ_FALLTHROUGH_ASSERT("Should never try to emit ParseNodeKind::PosHolder or ::Property");
default:
MOZ_ASSERT(0);
diff -Nrup mozilla-OLD/js/src/frontend/BytecodeEmitter.h mozilla/js/src/frontend/BytecodeEmitter.h
--- mozilla-OLD/js/src/frontend/BytecodeEmitter.h 2021-12-29 03:47:40.636227068 +0300
+++ mozilla/js/src/frontend/BytecodeEmitter.h 2021-12-29 03:47:09.645450097 +0300
@@ -815,6 +815,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);
diff -Nrup mozilla-OLD/js/src/frontend/FoldConstants.cpp mozilla/js/src/frontend/FoldConstants.cpp
--- mozilla-OLD/js/src/frontend/FoldConstants.cpp 2021-12-29 03:47:40.636227068 +0300
+++ mozilla/js/src/frontend/FoldConstants.cpp 2021-12-29 03:37:16.058713948 +0300
@@ -363,8 +363,10 @@ ContainsHoistedDeclaration(JSContext* cx
case ParseNodeKind::Comma:
case ParseNodeKind::Array:
case ParseNodeKind::Object:
+ case ParseNodeKind::PropertyName:
case ParseNodeKind::Dot:
case ParseNodeKind::Elem:
+ case ParseNodeKind::Arguments:
case ParseNodeKind::Call:
case ParseNodeKind::Name:
case ParseNodeKind::TemplateString:
@@ -1316,7 +1318,10 @@ FoldElement(JSContext* cx, ParseNode** n
// Optimization 3: We have expr["foo"] where foo is not an index. Convert
// to a property access (like expr.foo) that optimizes better downstream.
- ParseNode* dottedAccess = parser.handler.newPropertyAccess(expr, name, node->pn_pos.end);
+ ParseNode* nameNode = parser.handler.newPropertyName(name, key->pn_pos);
+ if (!nameNode)
+ return false;
+ ParseNode* dottedAccess = parser.handler.newPropertyAccess(expr, nameNode);
if (!dottedAccess)
return false;
dottedAccess->setInParens(node->isInParens());
@@ -1474,8 +1479,9 @@ FoldCall(JSContext* cx, ParseNode* node,
{
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:
@@ -1488,10 +1494,27 @@ FoldCall(JSContext* cx, ParseNode* node,
// 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, inGenexpLambda))
+ return false;
+ }
+ ParseNode** pn_args = &node->pn_right;
+ if (!Fold(cx, pn_args, parser, inGenexpLambda))
+ return false;
+
+ return true;
+}
+
+static bool
+FoldArguments(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
+ bool inGenexpLambda)
+{
+ 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, inGenexpLambda))
return false;
@@ -1550,14 +1573,14 @@ FoldDottedProperty(JSContext* cx, ParseN
bool inGenexpLambda)
{
MOZ_ASSERT(node->isKind(ParseNodeKind::Dot));
- MOZ_ASSERT(node->isArity(PN_NAME));
+ MOZ_ASSERT(node->isArity(PN_BINARY));
// Iterate through a long chain of dotted property accesses to find the
// most-nested non-dotted property node, then fold that.
- ParseNode** nested = &node->pn_expr;
+ ParseNode** nested = &node->pn_left;
while ((*nested)->isKind(ParseNodeKind::Dot)) {
- MOZ_ASSERT((*nested)->isArity(PN_NAME));
- nested = &(*nested)->pn_expr;
+ MOZ_ASSERT((*nested)->isArity(PN_BINARY));
+ nested = &(*nested)->pn_left;
}
return Fold(cx, nested, parser, inGenexpLambda);
@@ -1714,7 +1737,6 @@ Fold(JSContext* cx, ParseNode** pnp, Par
case ParseNodeKind::InstanceOf:
case ParseNodeKind::In:
case ParseNodeKind::Comma:
- case ParseNodeKind::New:
case ParseNodeKind::Array:
case ParseNodeKind::Object:
case ParseNodeKind::ArrayComp:
@@ -1768,10 +1790,14 @@ Fold(JSContext* cx, ParseNode** pnp, Par
return FoldAdd(cx, pnp, parser, inGenexpLambda);
case ParseNodeKind::Call:
+ case ParseNodeKind::New:
case ParseNodeKind::SuperCall:
case ParseNodeKind::TaggedTemplate:
return FoldCall(cx, pn, parser, inGenexpLambda);
+ case ParseNodeKind::Arguments:
+ return FoldArguments(cx, pn, parser, inGenexpLambda);
+
case ParseNodeKind::Switch:
case ParseNodeKind::Colon:
case ParseNodeKind::Assign:
@@ -1851,6 +1877,9 @@ Fold(JSContext* cx, ParseNode** pnp, Par
MOZ_ASSERT(pn->isArity(PN_NAME));
return Fold(cx, &pn->pn_expr, parser, inGenexpLambda);
+ case ParseNodeKind::PropertyName:
+ MOZ_CRASH("unreachable, handled by ::Dot");
+
case ParseNodeKind::Dot:
return FoldDottedProperty(cx, pn, parser, inGenexpLambda);
diff -Nrup mozilla-OLD/js/src/frontend/FullParseHandler.h mozilla/js/src/frontend/FullParseHandler.h
--- mozilla-OLD/js/src/frontend/FullParseHandler.h 2021-12-29 03:47:40.637227061 +0300
+++ mozilla/js/src/frontend/FullParseHandler.h 2021-12-29 03:37:16.058713948 +0300
@@ -285,16 +285,20 @@ class FullParseHandler
literal->append(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) {
@@ -669,8 +673,12 @@ class FullParseHandler
return new_<DebuggerStatement>(pos);
}
- ParseNode* newPropertyAccess(ParseNode* pn, PropertyName* name, uint32_t end) {
- return new_<PropertyAccess>(pn, name, pn->pn_pos.begin, end);
+ ParseNode* newPropertyName(PropertyName* name, const TokenPos& pos) {
+ return new_<NameNode>(ParseNodeKind::PropertyName, JSOP_NOP, name, pos);
+ }
+
+ ParseNode* newPropertyAccess(ParseNode* expr, ParseNode* key) {
+ return new_<PropertyAccess>(expr, key, expr->pn_pos.begin, key->pn_pos.end);
}
ParseNode* newPropertyByValue(ParseNode* lhs, ParseNode* index, uint32_t end) {
@@ -744,13 +752,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(newExpr, 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) {
diff -Nrup mozilla-OLD/js/src/frontend/NameFunctions.cpp mozilla/js/src/frontend/NameFunctions.cpp
--- mozilla-OLD/js/src/frontend/NameFunctions.cpp 2021-12-29 03:47:40.638227054 +0300
+++ mozilla/js/src/frontend/NameFunctions.cpp 2021-12-29 03:37:16.059713941 +0300
@@ -77,11 +77,11 @@ class NameResolver
bool nameExpression(ParseNode* n, bool* foundName) {
switch (n->getKind()) {
case ParseNodeKind::Dot:
- if (!nameExpression(n->expr(), foundName))
+ if (!nameExpression(n->pn_left, foundName))
return false;
if (!*foundName)
return true;
- return appendPropertyReference(n->pn_atom);
+ return appendPropertyReference(n->pn_right->pn_atom);
case ParseNodeKind::Name:
*foundName = true;
@@ -313,17 +313,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));
@@ -701,9 +701,6 @@ class NameResolver
case ParseNodeKind::Pow:
case ParseNodeKind::Pipeline:
case ParseNodeKind::Comma:
- case ParseNodeKind::New:
- case ParseNodeKind::Call:
- case ParseNodeKind::SuperCall:
case ParseNodeKind::GenExp:
case ParseNodeKind::Array:
case ParseNodeKind::StatementList:
@@ -751,11 +748,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.
@@ -784,12 +802,12 @@ class NameResolver
}
case ParseNodeKind::Dot:
- MOZ_ASSERT(cur->isArity(PN_NAME));
+ MOZ_ASSERT(cur->isArity(PN_BINARY));
// Super prop nodes do not have a meaningful LHS
if (cur->as<PropertyAccess>().isSuper())
break;
- if (!resolve(cur->expr(), prefix))
+ if (!resolve(cur->pn_left, prefix))
return false;
break;
@@ -824,6 +842,7 @@ class NameResolver
case ParseNodeKind::ExportSpec: // by ParseNodeKind::ExportSpecList
case ParseNodeKind::CallSiteObj: // by ParseNodeKind::TaggedTemplate
case ParseNodeKind::ClassNames: // by ParseNodeKind::Class
+ case ParseNodeKind::PropertyName: // by ParseNodeKind::Dot
MOZ_CRASH("should have been handled by a parent node");
case ParseNodeKind::Limit: // invalid sentinel value
diff -Nrup mozilla-OLD/js/src/frontend/ParseNode.cpp mozilla/js/src/frontend/ParseNode.cpp
--- mozilla-OLD/js/src/frontend/ParseNode.cpp 2021-12-29 03:47:40.638227054 +0300
+++ mozilla/js/src/frontend/ParseNode.cpp 2021-12-29 03:37:16.060713934 +0300
@@ -214,6 +214,21 @@ UnaryNode::dump(GenericPrinter& out, int
void
BinaryNode::dump(GenericPrinter& out, int indent)
{
+ if (isKind(ParseNodeKind::Dot)) {
+ out.put("(.");
+
+ DumpParseTree(pn_right, out, indent + 2);
+
+ out.putChar(' ');
+ if (as<PropertyAccess>().isSuper())
+ out.put("super");
+ else
+ DumpParseTree(pn_left, out, indent + 2);
+
+ out.printf(")");
+ return;
+ }
+
const char* name = parseNodeNames[size_t(getKind())];
out.printf("(%s ", name);
indent += strlen(name) + 2;
@@ -286,10 +301,7 @@ DumpName(GenericPrinter& out, const Char
void
NameNode::dump(GenericPrinter& out, int indent)
{
- if (isKind(ParseNodeKind::Name) || isKind(ParseNodeKind::Dot)) {
- if (isKind(ParseNodeKind::Dot))
- out.put("(.");
-
+ if (isKind(ParseNodeKind::Name) || isKind(ParseNodeKind::PropertyName)) {
if (!pn_atom) {
out.put("#<null name>");
} else if (getOp() == JSOP_GETARG && pn_atom->length() == 0) {
@@ -304,15 +316,6 @@ NameNode::dump(GenericPrinter& out, int
else
DumpName(out, pn_atom->twoByteChars(nogc), pn_atom->length());
}
-
- if (isKind(ParseNodeKind::Dot)) {
- out.putChar(' ');
- if (as<PropertyAccess>().isSuper())
- out.put("super");
- else
- DumpParseTree(expr(), out, indent + 2);
- out.printf(")");
- }
return;
}
diff -Nrup mozilla-OLD/js/src/frontend/ParseNode.h mozilla/js/src/frontend/ParseNode.h
--- mozilla-OLD/js/src/frontend/ParseNode.h 2021-12-29 03:47:40.639227047 +0300
+++ mozilla/js/src/frontend/ParseNode.h 2021-12-29 03:37:16.060713934 +0300
@@ -34,6 +34,7 @@ class ObjectBox;
F(PostIncrement) \
F(PreDecrement) \
F(PostDecrement) \
+ F(PropertyName) \
F(Dot) \
F(Elem) \
F(Array) \
@@ -42,6 +43,7 @@ class ObjectBox;
F(Label) \
F(Object) \
F(Call) \
+ F(Arguments) \
F(Name) \
F(ObjectPropertyName) \
F(ComputedName) \
@@ -366,9 +368,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
@@ -377,13 +378,15 @@ IsTypeofKind(ParseNodeKind 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 .
+ * PropertyName name pn_atom: property name being accessed
+ * Dot binary pn_left: MEMBER expr to left of .
+ * pn_right: PropertyName 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)
* GenExp list Exactly like Call, used for the implicit call
* in the desugaring of a generator-expression.
* Array list pn_head: list of pn_count array element exprs
@@ -405,8 +408,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
@@ -418,7 +422,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
@@ -573,8 +577,7 @@ class ParseNode
FunctionBox* funbox; /* function object */
};
ParseNode* expr; /* module or function body, var
- initializer, argument default, or
- base object of ParseNodeKind::Dot */
+ initializer, or argument default */
} name;
struct {
LexicalScope::Data* bindings;
@@ -1194,30 +1197,33 @@ class RegExpLiteral : public NullaryNode
}
};
-class PropertyAccess : public ParseNode
+class PropertyAccess : public BinaryNode
{
public:
- PropertyAccess(ParseNode* lhs, PropertyName* name, uint32_t begin, uint32_t end)
- : ParseNode(ParseNodeKind::Dot, JSOP_NOP, PN_NAME, TokenPos(begin, end))
+ /*
+ * PropertyAccess nodes can have any expression/'super' as left-hand
+ * side, but the name must be a ParseNodeKind::PropertyName node.
+ */
+ PropertyAccess(ParseNode* lhs, ParseNode* name, uint32_t begin, uint32_t end)
+ : BinaryNode(ParseNodeKind::Dot, JSOP_NOP, TokenPos(begin, end), lhs, name)
{
MOZ_ASSERT(lhs != nullptr);
MOZ_ASSERT(name != nullptr);
- pn_u.name.expr = lhs;
- pn_u.name.atom = name;
}
static bool test(const ParseNode& node) {
bool match = node.isKind(ParseNodeKind::Dot);
- MOZ_ASSERT_IF(match, node.isArity(PN_NAME));
+ MOZ_ASSERT_IF(match, node.isArity(PN_BINARY));
+ MOZ_ASSERT_IF(match, node.pn_right->isKind(ParseNodeKind::PropertyName));
return match;
}
ParseNode& expression() const {
- return *pn_u.name.expr;
+ return *pn_u.binary.left;
}
PropertyName& name() const {
- return *pn_u.name.atom->asPropertyName();
+ return *pn_u.binary.right->pn_atom->asPropertyName();
}
bool isSuper() const {
diff -Nrup mozilla-OLD/js/src/frontend/Parser.cpp mozilla/js/src/frontend/Parser.cpp
--- mozilla-OLD/js/src/frontend/Parser.cpp 2021-12-29 03:47:40.641227032 +0300
+++ mozilla/js/src/frontend/Parser.cpp 2021-12-29 03:37:16.063713912 +0300
@@ -3348,13 +3348,13 @@ Parser<ParseHandler, CharT>::addExprAndG
template <class ParseHandler, typename CharT>
bool
-Parser<ParseHandler, CharT>::taggedTemplate(YieldHandling yieldHandling, Node nodeList,
+Parser<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))
@@ -3362,10 +3362,10 @@ Parser<ParseHandler, CharT>::taggedTempl
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;
}
@@ -8855,24 +8855,27 @@ Parser<ParseHandler, CharT>::assignExprW
}
template <class ParseHandler, typename CharT>
-bool
-Parser<ParseHandler, CharT>::argumentList(YieldHandling yieldHandling, Node listNode,
- bool* isSpread,
+typename ParseHandler::Node
+Parser<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, 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;
@@ -8881,18 +8884,18 @@ Parser<ParseHandler, CharT>::argumentLis
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, TokenStream::Operand))
- return false;
+ return null();
if (!matched)
break;
@@ -8905,8 +8908,8 @@ Parser<ParseHandler, CharT>::argumentLis
MUST_MATCH_TOKEN_MOD(TOK_RP, TokenStream::Operand, JSMSG_PAREN_AFTER_ARGS);
- handler.setEndPosition(listNode, pos().end);
- return true;
+ handler.setEndPosition(argsList, pos().end);
+ return argsList;
}
template <class ParseHandler, typename CharT>
@@ -8952,20 +8955,27 @@ Parser<ParseHandler, CharT>::memberExpr(
if (!ctorExpr)
return null();
- lhs = handler.newNewExpression(newBegin, ctorExpr);
- if (!lhs)
- return null();
-
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();
@@ -8998,7 +9008,12 @@ Parser<ParseHandler, CharT>::memberExpr(
error(JSMSG_BAD_SUPERPROP, "property");
return null();
}
- nextMember = handler.newPropertyAccess(lhs, field, pos().end);
+
+ Node name = handler.newPropertyName(field, pos());
+ if (!name)
+ return null();
+
+ nextMember = handler.newPropertyAccess(lhs, name);
if (!nextMember)
return null();
} else {
@@ -9034,15 +9049,16 @@ Parser<ParseHandler, CharT>::memberExpr(
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)
@@ -9061,13 +9077,6 @@ Parser<ParseHandler, CharT>::memberExpr(
return null();
}
- TokenPos nextMemberPos = pos();
- nextMember = tt == TOK_LP
- ? handler.newCall(nextMemberPos)
- : handler.newTaggedTemplate(nextMemberPos);
- if (!nextMember)
- return null();
-
JSOp op = JSOP_CALL;
bool maybeAsyncArrow = false;
if (PropertyName* prop = handler.maybeDottedProperty(lhs)) {
@@ -9109,13 +9118,11 @@ Parser<ParseHandler, CharT>::memberExpr(
}
}
- handler.setBeginPosition(nextMember, lhs);
- handler.addList(nextMember, lhs);
-
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();
if (isSpread) {
if (op == JSOP_EVAL)
@@ -9125,8 +9132,20 @@ Parser<ParseHandler, CharT>::memberExpr(
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);
diff -Nrup mozilla-OLD/js/src/frontend/Parser.h mozilla/js/src/frontend/Parser.h
--- mozilla-OLD/js/src/frontend/Parser.h 2021-12-29 03:47:40.642227025 +0300
+++ mozilla/js/src/frontend/Parser.h 2021-12-29 03:37:16.064713905 +0300
@@ -799,7 +799,7 @@ class Parser final
Node arrayComprehension(uint32_t begin);
Node generatorComprehension(uint32_t begin);
- bool argumentList(YieldHandling yieldHandling, Node listNode, bool* isSpread,
+ Node argumentList(YieldHandling yieldHandling, bool* isSpread,
PossibleError* possibleError = nullptr);
Node destructuringDeclaration(DeclarationKind kind, YieldHandling yieldHandling,
TokenKind tt);
diff -Nrup mozilla-OLD/js/src/frontend/SyntaxParseHandler.h mozilla/js/src/frontend/SyntaxParseHandler.h
--- mozilla-OLD/js/src/frontend/SyntaxParseHandler.h 2021-12-29 03:47:40.643227018 +0300
+++ mozilla/js/src/frontend/SyntaxParseHandler.h 2021-12-29 03:37:16.064713905 +0300
@@ -241,9 +241,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; }
@@ -316,8 +318,12 @@ class SyntaxParseHandler
}
Node newDebuggerStatement(const TokenPos& pos) { return NodeGeneric; }
- Node newPropertyAccess(Node pn, PropertyName* name, uint32_t end) {
+ Node newPropertyName(PropertyName* name, const TokenPos& pos) {
lastAtom = name;
+ return NodeGeneric;
+ }
+
+ Node newPropertyAccess(Node expr, Node key) {
return NodeDottedProperty;
}
@@ -438,7 +444,7 @@ class SyntaxParseHandler
list == NodeFunctionCall);
}
- Node newNewExpression(uint32_t begin, Node ctor) {
+ Node newNewExpression(uint32_t begin, Node ctor, Node args) {
return NodeGeneric;
}
diff -Nrup mozilla-OLD/js/src/wasm/AsmJS.cpp mozilla/js/src/wasm/AsmJS.cpp
--- mozilla-OLD/js/src/wasm/AsmJS.cpp 2021-12-29 03:47:40.645227003 +0300
+++ mozilla/js/src/wasm/AsmJS.cpp 2021-12-29 03:37:16.066713891 +0300
@@ -456,22 +456,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*
@@ -634,16 +633,16 @@ static ParseNode*
DotBase(ParseNode* pn)
{
MOZ_ASSERT(pn->isKind(ParseNodeKind::Dot));
- MOZ_ASSERT(pn->isArity(PN_NAME));
- return pn->expr();
+ MOZ_ASSERT(pn->isArity(PN_BINARY));
+ return pn->pn_left;
}
static PropertyName*
DotMember(ParseNode* pn)
{
MOZ_ASSERT(pn->isKind(ParseNodeKind::Dot));
- MOZ_ASSERT(pn->isArity(PN_NAME));
- return pn->pn_atom->asPropertyName();
+ MOZ_ASSERT(pn->isArity(PN_BINARY));
+ return pn->pn_right->pn_atom->asPropertyName();
}
static ParseNode*
@@ -3429,9 +3428,11 @@ IsArrayViewCtorName(ModuleValidator& m,
}
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");
@@ -3452,7 +3453,7 @@ CheckNewArrayView(ModuleValidator& m, Pr
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;
@@ -3481,7 +3482,7 @@ CheckNewArrayView(ModuleValidator& m, Pr
type = global->viewType();
}
- if (!CheckNewArrayViewArgs(m, ctorExpr, bufferName))
+ if (!CheckNewArrayViewArgs(m, newExpr, bufferName))
return false;
return m.addArrayView(varName, type, field);