зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 3 changesets (bug 1378808) for failing spidermonkey builds on a CLOSED TREE
Backed out changeset 8658a25ee96b (bug 1378808) Backed out changeset e761b8eef0aa (bug 1378808) Backed out changeset b14186c3f895 (bug 1378808)
This commit is contained in:
Родитель
806241e4f4
Коммит
1ea5273b59
|
@ -2702,25 +2702,24 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
|||
case ParseNodeKind::Call:
|
||||
case ParseNodeKind::SuperCall:
|
||||
{
|
||||
ParseNode* pn_callee = pn->pn_left;
|
||||
ParseNode* pn_args = pn->pn_right;
|
||||
MOZ_ASSERT(pn->pn_pos.encloses(pn_callee->pn_pos));
|
||||
ParseNode* next = pn->pn_head;
|
||||
MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
|
||||
|
||||
RootedValue callee(cx);
|
||||
if (pn->isKind(ParseNodeKind::SuperCall)) {
|
||||
MOZ_ASSERT(pn_callee->isKind(ParseNodeKind::SuperBase));
|
||||
if (!builder.super(&pn_callee->pn_pos, &callee))
|
||||
MOZ_ASSERT(next->isKind(ParseNodeKind::SuperBase));
|
||||
if (!builder.super(&next->pn_pos, &callee))
|
||||
return false;
|
||||
} else {
|
||||
if (!expression(pn_callee, &callee))
|
||||
if (!expression(next, &callee))
|
||||
return false;
|
||||
}
|
||||
|
||||
NodeVector args(cx);
|
||||
if (!args.reserve(pn_args->pn_count))
|
||||
if (!args.reserve(pn->pn_count - 1))
|
||||
return false;
|
||||
|
||||
for (ParseNode* next = pn_args->pn_head; next; next = next->pn_next) {
|
||||
for (next = next->pn_next; next; next = next->pn_next) {
|
||||
MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
|
||||
|
||||
RootedValue arg(cx);
|
||||
|
@ -2741,17 +2740,17 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
|||
|
||||
case ParseNodeKind::Dot:
|
||||
{
|
||||
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
|
||||
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_expr->pn_pos));
|
||||
|
||||
RootedValue expr(cx);
|
||||
RootedValue propname(cx);
|
||||
RootedAtom pnAtom(cx, pn->pn_right->pn_atom);
|
||||
RootedAtom pnAtom(cx, pn->pn_atom);
|
||||
|
||||
if (pn->as<PropertyAccess>().isSuper()) {
|
||||
if (!builder.super(&pn->pn_left->pn_pos, &expr))
|
||||
if (!builder.super(&pn->pn_expr->pn_pos, &expr))
|
||||
return false;
|
||||
} else {
|
||||
if (!expression(pn->pn_left, &expr))
|
||||
if (!expression(pn->pn_expr, &expr))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -3462,8 +3462,9 @@ BinASTParser<Tok>::parseInterfaceCallExpression(const size_t start, const BinKin
|
|||
op = parseContext_->sc()->strict() ? JSOP_STRICTEVAL : JSOP_EVAL;
|
||||
}
|
||||
}
|
||||
|
||||
BINJS_TRY_DECL(result, factory_.newCall(callee, arguments));
|
||||
auto result = arguments;
|
||||
result->setKind(ParseNodeKind::Call);
|
||||
result->prepend(callee);
|
||||
result->setOp(op);
|
||||
return result;
|
||||
}
|
||||
|
@ -5676,7 +5677,10 @@ BinASTParser<Tok>::parseInterfaceNewExpression(const size_t start, const BinKind
|
|||
|
||||
BINJS_MOZ_TRY_DECL(arguments, parseArguments());
|
||||
|
||||
BINJS_TRY_DECL(result, factory_.newNewExpression(tokenizer_->pos(start).begin, callee, arguments));
|
||||
auto result = arguments;
|
||||
result->setKind(ParseNodeKind::New);
|
||||
result->prepend(callee);
|
||||
result->setOp(JSOP_NEW);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -6193,18 +6197,13 @@ BinASTParser<Tok>::parseInterfaceStaticMemberAssignmentTarget(const size_t start
|
|||
const BinField expected_fields[2] = { BinField::Object, BinField::Property };
|
||||
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
|
||||
#endif // defined(DEBUG)
|
||||
TokenPos namePos;
|
||||
|
||||
BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
|
||||
|
||||
RootedAtom property(cx_);
|
||||
{
|
||||
namePos = tokenizer_->pos();
|
||||
MOZ_TRY_VAR(property, tokenizer_->readAtom());
|
||||
MOZ_TRY_VAR(property, tokenizer_->readAtom());
|
||||
|
||||
}
|
||||
|
||||
BINJS_TRY_DECL(name, factory_.newPropertyName(property->asPropertyName(), namePos));
|
||||
BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, name));
|
||||
BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), start));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -6243,18 +6242,13 @@ BinASTParser<Tok>::parseInterfaceStaticMemberExpression(const size_t start, cons
|
|||
const BinField expected_fields[2] = { BinField::Object, BinField::Property };
|
||||
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
|
||||
#endif // defined(DEBUG)
|
||||
TokenPos namePos;
|
||||
|
||||
BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
|
||||
|
||||
RootedAtom property(cx_);
|
||||
{
|
||||
namePos = tokenizer_->pos();
|
||||
MOZ_TRY_VAR(property, tokenizer_->readAtom());
|
||||
MOZ_TRY_VAR(property, tokenizer_->readAtom());
|
||||
|
||||
}
|
||||
|
||||
BINJS_TRY_DECL(name, factory_.newPropertyName(property->asPropertyName(), namePos));
|
||||
BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, name));
|
||||
BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), start));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -428,8 +428,9 @@ CallExpression:
|
|||
op = parseContext_->sc()->strict() ? JSOP_STRICTEVAL : JSOP_EVAL;
|
||||
}
|
||||
}
|
||||
|
||||
BINJS_TRY_DECL(result, factory_.newCall(callee, arguments));
|
||||
auto result = arguments;
|
||||
result->setKind(ParseNodeKind::Call);
|
||||
result->prepend(callee);
|
||||
result->setOp(op);
|
||||
|
||||
|
||||
|
@ -830,7 +831,10 @@ LiteralStringExpression:
|
|||
|
||||
NewExpression:
|
||||
build: |
|
||||
BINJS_TRY_DECL(result, factory_.newNewExpression(tokenizer_->pos(start).begin, callee, arguments));
|
||||
auto result = arguments;
|
||||
result->setKind(ParseNodeKind::New);
|
||||
result->prepend(callee);
|
||||
result->setOp(JSOP_NEW);
|
||||
|
||||
ObjectExpression:
|
||||
build:
|
||||
|
@ -918,28 +922,12 @@ SwitchStatementWithDefault:
|
|||
BINJS_TRY_DECL(result, factory_.newSwitchStatement(start, discriminant, scope));
|
||||
|
||||
StaticMemberAssignmentTarget:
|
||||
init:
|
||||
TokenPos namePos;
|
||||
fields:
|
||||
property:
|
||||
block:
|
||||
before: |
|
||||
namePos = tokenizer_->pos();
|
||||
build: |
|
||||
BINJS_TRY_DECL(name, factory_.newPropertyName(property->asPropertyName(), namePos));
|
||||
BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, name));
|
||||
BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), start));
|
||||
|
||||
StaticMemberExpression:
|
||||
init:
|
||||
TokenPos namePos;
|
||||
fields:
|
||||
property:
|
||||
block:
|
||||
before: |
|
||||
namePos = tokenizer_->pos();
|
||||
build: |
|
||||
BINJS_TRY_DECL(name, factory_.newPropertyName(property->asPropertyName(), namePos));
|
||||
BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, name));
|
||||
BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), start));
|
||||
|
||||
ThisExpression:
|
||||
build: |
|
||||
|
|
|
@ -1038,7 +1038,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
|||
|
||||
// Watch out for getters!
|
||||
case ParseNodeKind::Dot:
|
||||
MOZ_ASSERT(pn->isArity(PN_BINARY));
|
||||
MOZ_ASSERT(pn->isArity(PN_NAME));
|
||||
*answer = true;
|
||||
return true;
|
||||
|
||||
|
@ -1276,14 +1276,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
|||
case ParseNodeKind::Call:
|
||||
case ParseNodeKind::TaggedTemplate:
|
||||
case ParseNodeKind::SuperCall:
|
||||
MOZ_ASSERT(pn->isArity(PN_BINARY));
|
||||
*answer = true;
|
||||
return true;
|
||||
|
||||
// Function arg lists can contain arbitrary expressions. Technically
|
||||
// this only causes side-effects if one of the arguments does, but since
|
||||
// the call being made will always trigger side-effects, it isn't needed.
|
||||
case ParseNodeKind::Arguments:
|
||||
MOZ_ASSERT(pn->isArity(PN_LIST));
|
||||
*answer = true;
|
||||
return true;
|
||||
|
@ -1418,7 +1410,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
|||
case ParseNodeKind::CallSiteObj: // by ParseNodeKind::TaggedTemplate
|
||||
case ParseNodeKind::PosHolder: // by ParseNodeKind::NewTarget
|
||||
case ParseNodeKind::SuperBase: // by ParseNodeKind::Elem and others
|
||||
case ParseNodeKind::PropertyName: // by ParseNodeKind::Dot
|
||||
MOZ_CRASH("handled by parent nodes");
|
||||
|
||||
case ParseNodeKind::Limit: // invalid sentinel value
|
||||
|
@ -1890,11 +1881,11 @@ BytecodeEmitter::emitPropLHS(ParseNode* pn)
|
|||
MOZ_ASSERT(pn->isKind(ParseNodeKind::Dot));
|
||||
MOZ_ASSERT(!pn->as<PropertyAccess>().isSuper());
|
||||
|
||||
ParseNode* pn2 = pn->pn_left;
|
||||
ParseNode* pn2 = pn->pn_expr;
|
||||
|
||||
/*
|
||||
* If the object operand is also a dotted property reference, reverse the
|
||||
* list linked via pn_left temporarily so we can iterate over it from the
|
||||
* list linked via pn_expr 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()) {
|
||||
|
@ -1902,9 +1893,9 @@ BytecodeEmitter::emitPropLHS(ParseNode* pn)
|
|||
ParseNode* pnup = nullptr;
|
||||
ParseNode* pndown;
|
||||
for (;;) {
|
||||
/* Reverse pndot->pn_left to point up, not down. */
|
||||
pndown = pndot->pn_left;
|
||||
pndot->pn_left = pnup;
|
||||
/* Reverse pndot->pn_expr to point up, not down. */
|
||||
pndown = pndot->pn_expr;
|
||||
pndot->pn_expr = pnup;
|
||||
if (!pndown->isKind(ParseNodeKind::Dot) || pndown->as<PropertyAccess>().isSuper())
|
||||
break;
|
||||
pnup = pndot;
|
||||
|
@ -1917,12 +1908,12 @@ BytecodeEmitter::emitPropLHS(ParseNode* pn)
|
|||
|
||||
do {
|
||||
/* Walk back up the list, emitting annotated name ops. */
|
||||
if (!emitAtomOp(pndot->pn_right, JSOP_GETPROP))
|
||||
if (!emitAtomOp(pndot, JSOP_GETPROP))
|
||||
return false;
|
||||
|
||||
/* Reverse the pn_left link again. */
|
||||
pnup = pndot->pn_left;
|
||||
pndot->pn_left = pndown;
|
||||
/* Reverse the pn_expr link again. */
|
||||
pnup = pndot->pn_expr;
|
||||
pndot->pn_expr = pndown;
|
||||
pndown = pndot;
|
||||
} while ((pndot = pnup) != nullptr);
|
||||
return true;
|
||||
|
@ -1947,7 +1938,7 @@ BytecodeEmitter::emitSuperPropLHS(ParseNode* superBase, bool isCall)
|
|||
bool
|
||||
BytecodeEmitter::emitPropOp(ParseNode* pn, JSOp op)
|
||||
{
|
||||
MOZ_ASSERT(pn->isArity(PN_BINARY));
|
||||
MOZ_ASSERT(pn->isArity(PN_NAME));
|
||||
|
||||
if (!emitPropLHS(pn))
|
||||
return false;
|
||||
|
@ -1955,7 +1946,7 @@ BytecodeEmitter::emitPropOp(ParseNode* pn, JSOp op)
|
|||
if (op == JSOP_CALLPROP && !emit1(JSOP_DUP))
|
||||
return false;
|
||||
|
||||
if (!emitAtomOp(pn->pn_right, op))
|
||||
if (!emitAtomOp(pn, op))
|
||||
return false;
|
||||
|
||||
if (op == JSOP_CALLPROP && !emit1(JSOP_SWAP))
|
||||
|
@ -1971,7 +1962,7 @@ BytecodeEmitter::emitSuperPropOp(ParseNode* pn, JSOp op, bool isCall)
|
|||
if (!emitSuperPropLHS(base, isCall))
|
||||
return false;
|
||||
|
||||
if (!emitAtomOp(pn->pn_right, op))
|
||||
if (!emitAtomOp(pn, op))
|
||||
return false;
|
||||
|
||||
if (isCall && !emit1(JSOP_SWAP))
|
||||
|
@ -2001,7 +1992,7 @@ BytecodeEmitter::emitPropIncDec(ParseNode* pn)
|
|||
if (!emit1(JSOP_DUP)) // OBJ OBJ
|
||||
return false;
|
||||
}
|
||||
if (!emitAtomOp(pn->pn_kid->pn_right, isSuper ? JSOP_GETPROP_SUPER : JSOP_GETPROP)) // OBJ V
|
||||
if (!emitAtomOp(pn->pn_kid, isSuper? JSOP_GETPROP_SUPER : JSOP_GETPROP)) // OBJ V
|
||||
return false;
|
||||
if (!emit1(JSOP_POS)) // OBJ N
|
||||
return false;
|
||||
|
@ -2027,7 +2018,7 @@ BytecodeEmitter::emitPropIncDec(ParseNode* pn)
|
|||
|
||||
JSOp setOp = isSuper ? sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER
|
||||
: sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
|
||||
if (!emitAtomOp(pn->pn_kid->pn_right, setOp)) // N? N+1
|
||||
if (!emitAtomOp(pn->pn_kid, setOp)) // N? N+1
|
||||
return false;
|
||||
if (post && !emit1(JSOP_POP)) // RESULT
|
||||
return false;
|
||||
|
@ -2752,7 +2743,7 @@ BytecodeEmitter::emitDestructuringLHSRef(ParseNode* target, size_t* emitted)
|
|||
return false;
|
||||
*emitted = 2;
|
||||
} else {
|
||||
if (!emitTree(target->pn_left))
|
||||
if (!emitTree(target->pn_expr))
|
||||
return false;
|
||||
*emitted = 1;
|
||||
}
|
||||
|
@ -2870,7 +2861,7 @@ BytecodeEmitter::emitSetOrInitializeDestructuring(ParseNode* target, Destructuri
|
|||
setOp = sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER;
|
||||
else
|
||||
setOp = sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
|
||||
if (!emitAtomOp(target->pn_right, setOp))
|
||||
if (!emitAtomOp(target, setOp))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
@ -3982,11 +3973,11 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, ParseNodeKind pnk, ParseNode* rh
|
|||
return false;
|
||||
offset += 2;
|
||||
} else {
|
||||
if (!emitTree(lhs->pn_left))
|
||||
if (!emitTree(lhs->expr()))
|
||||
return false;
|
||||
offset += 1;
|
||||
}
|
||||
if (!makeAtomIndex(lhs->pn_right->pn_atom, &atomIndex))
|
||||
if (!makeAtomIndex(lhs->pn_atom, &atomIndex))
|
||||
return false;
|
||||
break;
|
||||
case ParseNodeKind::Elem: {
|
||||
|
@ -4035,7 +4026,7 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, ParseNodeKind pnk, ParseNode* rh
|
|||
} else {
|
||||
if (!emit1(JSOP_DUP))
|
||||
return false;
|
||||
bool isLength = (lhs->pn_right->pn_atom == cx->names().length);
|
||||
bool isLength = (lhs->pn_atom == cx->names().length);
|
||||
getOp = isLength ? JSOP_LENGTH : JSOP_GETPROP;
|
||||
}
|
||||
if (!emitIndex32(getOp, atomIndex))
|
||||
|
@ -4882,7 +4873,7 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
|
|||
bool allowSelfHostedIter = false;
|
||||
if (emitterMode == BytecodeEmitter::SelfHosting &&
|
||||
forHeadExpr->isKind(ParseNodeKind::Call) &&
|
||||
forHeadExpr->pn_left->name() == cx->names().allowContentIter)
|
||||
forHeadExpr->pn_head->name() == cx->names().allowContentIter)
|
||||
{
|
||||
allowSelfHostedIter = true;
|
||||
}
|
||||
|
@ -6577,12 +6568,10 @@ BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn)
|
|||
//
|
||||
// argc is set to the amount of actually emitted args and the
|
||||
// emitting of args below is disabled by setting emitArgs to false.
|
||||
ParseNode* pn_callee = pn->pn_left;
|
||||
ParseNode* pn_args = pn->pn_right;
|
||||
ParseNode* pn2 = pn->pn_head;
|
||||
const char* errorName = SelfHostedCallFunctionName(pn2->name(), cx);
|
||||
|
||||
const char* errorName = SelfHostedCallFunctionName(pn_callee->name(), cx);
|
||||
|
||||
if (pn_args->pn_count < 2) {
|
||||
if (pn->pn_count < 3) {
|
||||
reportError(pn, JSMSG_MORE_ARGS_NEEDED, errorName, "2", "s");
|
||||
return false;
|
||||
}
|
||||
|
@ -6593,8 +6582,8 @@ BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool constructing = pn_callee->name() == cx->names().constructContentFunction;
|
||||
ParseNode* funNode = pn_args->pn_head;
|
||||
bool constructing = pn2->name() == cx->names().constructContentFunction;
|
||||
ParseNode* funNode = pn2->pn_next;
|
||||
if (constructing) {
|
||||
callOp = JSOP_NEW;
|
||||
} else if (funNode->getKind() == ParseNodeKind::Name &&
|
||||
|
@ -6607,7 +6596,7 @@ BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn)
|
|||
|
||||
#ifdef DEBUG
|
||||
if (emitterMode == BytecodeEmitter::SelfHosting &&
|
||||
pn_callee->name() == cx->names().callFunction)
|
||||
pn2->name() == cx->names().callFunction)
|
||||
{
|
||||
if (!emit1(JSOP_DEBUGCHECKSELFHOSTED))
|
||||
return false;
|
||||
|
@ -6636,7 +6625,7 @@ BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn)
|
|||
return false;
|
||||
}
|
||||
|
||||
uint32_t argc = pn_args->pn_count - 2;
|
||||
uint32_t argc = pn->pn_count - 3;
|
||||
if (!emitCall(callOp, argc))
|
||||
return false;
|
||||
|
||||
|
@ -6647,15 +6636,15 @@ BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn)
|
|||
bool
|
||||
BytecodeEmitter::emitSelfHostedResumeGenerator(ParseNode* pn)
|
||||
{
|
||||
ParseNode* pn_args = pn->pn_right;
|
||||
|
||||
// Syntax: resumeGenerator(gen, value, 'next'|'throw'|'return')
|
||||
if (pn_args->pn_count != 3) {
|
||||
if (pn->pn_count != 4) {
|
||||
reportError(pn, JSMSG_MORE_ARGS_NEEDED, "resumeGenerator", "1", "s");
|
||||
return false;
|
||||
}
|
||||
|
||||
ParseNode* genNode = pn_args->pn_head;
|
||||
ParseNode* funNode = pn->pn_head; // The resumeGenerator node.
|
||||
|
||||
ParseNode* genNode = funNode->pn_next;
|
||||
if (!emitTree(genNode))
|
||||
return false;
|
||||
|
||||
|
@ -6687,26 +6676,24 @@ BytecodeEmitter::emitSelfHostedForceInterpreter()
|
|||
bool
|
||||
BytecodeEmitter::emitSelfHostedAllowContentIter(ParseNode* pn)
|
||||
{
|
||||
ParseNode* pn_args = pn->pn_right;
|
||||
|
||||
if (pn_args->pn_count != 1) {
|
||||
if (pn->pn_count != 2) {
|
||||
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_args->pn_head);
|
||||
return emitTree(pn->pn_head->pn_next);
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitSelfHostedDefineDataProperty(ParseNode* pn)
|
||||
{
|
||||
ParseNode* pn_args = pn->pn_right;
|
||||
// Only optimize when 3 arguments are passed (we use 4 to include |this|).
|
||||
MOZ_ASSERT(pn->pn_count == 4);
|
||||
|
||||
// Only optimize when 3 arguments are passed.
|
||||
MOZ_ASSERT(pn_args->pn_count == 3);
|
||||
ParseNode* funNode = pn->pn_head; // The _DefineDataProperty node.
|
||||
|
||||
ParseNode* objNode = pn_args->pn_head;
|
||||
ParseNode* objNode = funNode->pn_next;
|
||||
if (!emitTree(objNode))
|
||||
return false;
|
||||
|
||||
|
@ -6727,14 +6714,14 @@ BytecodeEmitter::emitSelfHostedDefineDataProperty(ParseNode* pn)
|
|||
bool
|
||||
BytecodeEmitter::emitSelfHostedHasOwn(ParseNode* pn)
|
||||
{
|
||||
ParseNode* pn_args = pn->pn_right;
|
||||
|
||||
if (pn_args->pn_count != 2) {
|
||||
if (pn->pn_count != 3) {
|
||||
reportError(pn, JSMSG_MORE_ARGS_NEEDED, "hasOwn", "2", "");
|
||||
return false;
|
||||
}
|
||||
|
||||
ParseNode* idNode = pn_args->pn_head;
|
||||
ParseNode* funNode = pn->pn_head; // The hasOwn node.
|
||||
|
||||
ParseNode* idNode = funNode->pn_next;
|
||||
if (!emitTree(idNode))
|
||||
return false;
|
||||
|
||||
|
@ -6748,14 +6735,14 @@ BytecodeEmitter::emitSelfHostedHasOwn(ParseNode* pn)
|
|||
bool
|
||||
BytecodeEmitter::emitSelfHostedGetPropertySuper(ParseNode* pn)
|
||||
{
|
||||
ParseNode* pn_args = pn->pn_right;
|
||||
|
||||
if (pn_args->pn_count != 3) {
|
||||
if (pn->pn_count != 4) {
|
||||
reportError(pn, JSMSG_MORE_ARGS_NEEDED, "getPropertySuper", "3", "");
|
||||
return false;
|
||||
}
|
||||
|
||||
ParseNode* objNode = pn_args->pn_head;
|
||||
ParseNode* funNode = pn->pn_head; // The getPropertySuper node.
|
||||
|
||||
ParseNode* objNode = funNode->pn_next;
|
||||
ParseNode* idNode = objNode->pn_next;
|
||||
ParseNode* receiverNode = idNode->pn_next;
|
||||
|
||||
|
@ -6784,11 +6771,11 @@ BytecodeEmitter::isRestParameter(ParseNode* pn)
|
|||
|
||||
if (!pn->isKind(ParseNodeKind::Name)) {
|
||||
if (emitterMode == BytecodeEmitter::SelfHosting && pn->isKind(ParseNodeKind::Call)) {
|
||||
ParseNode* pn_callee = pn->pn_left;
|
||||
if (pn_callee->getKind() == ParseNodeKind::Name &&
|
||||
pn_callee->name() == cx->names().allowContentIter)
|
||||
ParseNode* pn2 = pn->pn_head;
|
||||
if (pn2->getKind() == ParseNodeKind::Name &&
|
||||
pn2->name() == cx->names().allowContentIter)
|
||||
{
|
||||
return isRestParameter(pn->pn_right->pn_head);
|
||||
return isRestParameter(pn2->pn_next);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -6918,22 +6905,101 @@ BytecodeEmitter::emitPipeline(ParseNode* pn)
|
|||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitArguments(ParseNode* pn, bool callop, bool spread)
|
||||
BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */)
|
||||
{
|
||||
uint32_t argc = pn->pn_count;
|
||||
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;
|
||||
|
||||
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 = pn->pn_head; pn3; pn3 = pn3->pn_next) {
|
||||
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 = pn->pn_head;
|
||||
ParseNode* args = pn2->pn_next;
|
||||
bool emitOptCode = (argc == 1) && isRestParameter(args->pn_kid);
|
||||
InternalIfEmitter ifNotOptimizable(this);
|
||||
|
||||
|
@ -6973,159 +7039,29 @@ BytecodeEmitter::emitArguments(ParseNode* pn, bool callop, bool spread)
|
|||
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 (!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;
|
||||
}
|
||||
}
|
||||
|
||||
ParseNode* coordNode = pn;
|
||||
if (pn->isOp(JSOP_CALL) || pn->isOp(JSOP_SPREADCALL)) {
|
||||
switch (pn_callee->getKind()) {
|
||||
case ParseNodeKind::Dot: {
|
||||
|
||||
// Check if this member is a simple chain of simple chain of
|
||||
// property accesses, e.g. x.y.z, this.x.y, super.x.y
|
||||
bool simpleDotChain = false;
|
||||
for (ParseNode* cur = pn_callee; cur->isKind(ParseNodeKind::Dot); cur = cur->pn_left) {
|
||||
ParseNode* left = cur->pn_left;
|
||||
if (left->isKind(ParseNodeKind::Name) || left->isKind(ParseNodeKind::This) ||
|
||||
left->isKind(ParseNodeKind::SuperBase))
|
||||
{
|
||||
simpleDotChain = true;
|
||||
}
|
||||
if (pn->isKind(ParseNodeKind::SuperCall)) {
|
||||
if (!emit1(JSOP_NEWTARGET))
|
||||
return false;
|
||||
} else {
|
||||
if (!emitDupAt(2))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!simpleDotChain) {
|
||||
// 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::Elem:
|
||||
// obj[expr]() // expression
|
||||
// ^ // column coord
|
||||
coordNode = pn_args;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!spread) {
|
||||
if (pn->getOp() == JSOP_CALL && valueUsage == ValueUsage::IgnoreValue) {
|
||||
if (!emitCall(JSOP_CALL_IGNORES_RV, argc, coordNode))
|
||||
if (!emitCall(JSOP_CALL_IGNORES_RV, argc, pn))
|
||||
return false;
|
||||
checkTypeSet(JSOP_CALL_IGNORES_RV);
|
||||
} else {
|
||||
if (!emitCall(pn->getOp(), argc, coordNode))
|
||||
if (!emitCall(pn->getOp(), argc, pn))
|
||||
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());
|
||||
|
@ -7694,7 +7630,7 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count)
|
|||
|
||||
if (emitterMode == BytecodeEmitter::SelfHosting &&
|
||||
expr->isKind(ParseNodeKind::Call) &&
|
||||
expr->pn_left->name() == cx->names().allowContentIter)
|
||||
expr->pn_head->name() == cx->names().allowContentIter)
|
||||
{
|
||||
allowSelfHostedIter = true;
|
||||
}
|
||||
|
@ -8742,9 +8678,8 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
|
|||
return false;
|
||||
break;
|
||||
|
||||
case ParseNodeKind::PropertyName:
|
||||
case ParseNodeKind::PosHolder:
|
||||
MOZ_FALLTHROUGH_ASSERT("Should never try to emit ParseNodeKind::PosHolder or ::Property");
|
||||
MOZ_FALLTHROUGH_ASSERT("Should never try to emit ParseNodeKind::PosHolder");
|
||||
|
||||
default:
|
||||
MOZ_ASSERT(0);
|
||||
|
|
|
@ -806,7 +806,6 @@ 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);
|
||||
|
|
|
@ -347,10 +347,8 @@ ContainsHoistedDeclaration(JSContext* cx, ParseNode* node, bool* result)
|
|||
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:
|
||||
|
@ -1255,8 +1253,7 @@ FoldElement(JSContext* cx, ParseNode** nodePtr, PerHandlerParser<FullParseHandle
|
|||
|
||||
// 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* nameNode = parser.newPropertyName(name, key->pn_pos);
|
||||
ParseNode* dottedAccess = parser.newPropertyAccess(expr, nameNode);
|
||||
ParseNode* dottedAccess = parser.newPropertyAccess(expr, name, node->pn_pos.end);
|
||||
if (!dottedAccess)
|
||||
return false;
|
||||
dottedAccess->setInParens(node->isInParens());
|
||||
|
@ -1412,9 +1409,8 @@ FoldCall(JSContext* cx, ParseNode* node, PerHandlerParser<FullParseHandler>& par
|
|||
{
|
||||
MOZ_ASSERT(node->isKind(ParseNodeKind::Call) ||
|
||||
node->isKind(ParseNodeKind::SuperCall) ||
|
||||
node->isKind(ParseNodeKind::New) ||
|
||||
node->isKind(ParseNodeKind::TaggedTemplate));
|
||||
MOZ_ASSERT(node->isArity(PN_BINARY));
|
||||
MOZ_ASSERT(node->isArity(PN_LIST));
|
||||
|
||||
// Don't fold a parenthesized callable component in an invocation, as this
|
||||
// might cause a different |this| value to be used, changing semantics:
|
||||
|
@ -1427,26 +1423,10 @@ FoldCall(JSContext* cx, ParseNode* node, PerHandlerParser<FullParseHandler>& par
|
|||
// 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;
|
||||
|
@ -1502,14 +1482,14 @@ static bool
|
|||
FoldDottedProperty(JSContext* cx, ParseNode* node, PerHandlerParser<FullParseHandler>& parser)
|
||||
{
|
||||
MOZ_ASSERT(node->isKind(ParseNodeKind::Dot));
|
||||
MOZ_ASSERT(node->isArity(PN_BINARY));
|
||||
MOZ_ASSERT(node->isArity(PN_NAME));
|
||||
|
||||
// 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_left;
|
||||
ParseNode** nested = &node->pn_expr;
|
||||
while ((*nested)->isKind(ParseNodeKind::Dot)) {
|
||||
MOZ_ASSERT((*nested)->isArity(PN_BINARY));
|
||||
nested = &(*nested)->pn_left;
|
||||
MOZ_ASSERT((*nested)->isArity(PN_NAME));
|
||||
nested = &(*nested)->pn_expr;
|
||||
}
|
||||
|
||||
return Fold(cx, nested, parser);
|
||||
|
@ -1662,6 +1642,7 @@ Fold(JSContext* cx, ParseNode** pnp, PerHandlerParser<FullParseHandler>& parser)
|
|||
case ParseNodeKind::InstanceOf:
|
||||
case ParseNodeKind::In:
|
||||
case ParseNodeKind::Comma:
|
||||
case ParseNodeKind::New:
|
||||
case ParseNodeKind::Array:
|
||||
case ParseNodeKind::Object:
|
||||
case ParseNodeKind::StatementList:
|
||||
|
@ -1713,14 +1694,10 @@ Fold(JSContext* cx, ParseNode** pnp, PerHandlerParser<FullParseHandler>& parser)
|
|||
return FoldAdd(cx, pnp, parser);
|
||||
|
||||
case ParseNodeKind::Call:
|
||||
case ParseNodeKind::New:
|
||||
case ParseNodeKind::SuperCall:
|
||||
case ParseNodeKind::TaggedTemplate:
|
||||
return FoldCall(cx, pn, parser);
|
||||
|
||||
case ParseNodeKind::Arguments:
|
||||
return FoldArguments(cx, pn, parser);
|
||||
|
||||
case ParseNodeKind::Switch:
|
||||
case ParseNodeKind::Colon:
|
||||
case ParseNodeKind::Assign:
|
||||
|
@ -1800,9 +1777,6 @@ Fold(JSContext* cx, ParseNode** pnp, PerHandlerParser<FullParseHandler>& parser)
|
|||
MOZ_ASSERT(pn->isArity(PN_NAME));
|
||||
return Fold(cx, &pn->pn_expr, parser);
|
||||
|
||||
case ParseNodeKind::PropertyName:
|
||||
MOZ_CRASH("unreachable, handled by ::Dot");
|
||||
|
||||
case ParseNodeKind::Dot:
|
||||
return FoldDottedProperty(cx, pn, parser);
|
||||
|
||||
|
|
|
@ -275,20 +275,16 @@ class FullParseHandler
|
|||
addList(/* list = */ literal, /* child = */ element);
|
||||
}
|
||||
|
||||
ParseNode* newCall(ParseNode* callee, ParseNode* args) {
|
||||
return new_<BinaryNode>(ParseNodeKind::Call, JSOP_CALL, callee, args);
|
||||
ParseNode* newCall(const TokenPos& pos) {
|
||||
return new_<ListNode>(ParseNodeKind::Call, JSOP_CALL, pos);
|
||||
}
|
||||
|
||||
ParseNode* newArguments(const TokenPos& pos) {
|
||||
return new_<ListNode>(ParseNodeKind::Arguments, JSOP_NOP, pos);
|
||||
ParseNode* newSuperCall(ParseNode* callee) {
|
||||
return new_<ListNode>(ParseNodeKind::SuperCall, JSOP_SUPERCALL, callee);
|
||||
}
|
||||
|
||||
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* newTaggedTemplate(const TokenPos& pos) {
|
||||
return new_<ListNode>(ParseNodeKind::TaggedTemplate, JSOP_CALL, pos);
|
||||
}
|
||||
|
||||
ParseNode* newObjectLiteral(uint32_t begin) {
|
||||
|
@ -663,12 +659,8 @@ class FullParseHandler
|
|||
return new_<DebuggerStatement>(pos);
|
||||
}
|
||||
|
||||
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* newPropertyAccess(ParseNode* expr, PropertyName* key, uint32_t end) {
|
||||
return new_<PropertyAccess>(expr, key, expr->pn_pos.begin, end);
|
||||
}
|
||||
|
||||
ParseNode* newPropertyByValue(ParseNode* lhs, ParseNode* index, uint32_t end) {
|
||||
|
@ -742,8 +734,13 @@ class FullParseHandler
|
|||
return new_<LexicalScopeNode>(bindings, body);
|
||||
}
|
||||
|
||||
Node newNewExpression(uint32_t begin, ParseNode* ctor, ParseNode* args) {
|
||||
return new_<BinaryNode>(ParseNodeKind::New, JSOP_NEW, TokenPos(begin, args->pn_pos.end), ctor, args);
|
||||
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;
|
||||
}
|
||||
|
||||
ParseNode* newAssignment(ParseNodeKind kind, ParseNode* lhs, ParseNode* rhs) {
|
||||
|
|
|
@ -75,11 +75,11 @@ class NameResolver
|
|||
bool nameExpression(ParseNode* n, bool* foundName) {
|
||||
switch (n->getKind()) {
|
||||
case ParseNodeKind::Dot:
|
||||
if (!nameExpression(n->pn_left, foundName))
|
||||
if (!nameExpression(n->expr(), foundName))
|
||||
return false;
|
||||
if (!*foundName)
|
||||
return true;
|
||||
return appendPropertyReference(n->pn_right->pn_atom);
|
||||
return appendPropertyReference(n->pn_atom);
|
||||
|
||||
case ParseNodeKind::Name:
|
||||
*foundName = true;
|
||||
|
@ -315,17 +315,17 @@ class NameResolver
|
|||
bool resolveTaggedTemplate(ParseNode* node, HandleAtom prefix) {
|
||||
MOZ_ASSERT(node->isKind(ParseNodeKind::TaggedTemplate));
|
||||
|
||||
ParseNode* tag = node->pn_left;
|
||||
ParseNode* element = node->pn_head;
|
||||
|
||||
// The leading expression, e.g. |tag| in |tag`foo`|,
|
||||
// The list head is a leading expression, e.g. |tag| in |tag`foo`|,
|
||||
// that might contain functions.
|
||||
if (!resolve(tag, prefix))
|
||||
if (!resolve(element, prefix))
|
||||
return false;
|
||||
|
||||
// The callsite object node is first. This node only contains
|
||||
// Next is the callsite object node. This node only contains
|
||||
// internal strings or undefined and an array -- no user-controlled
|
||||
// expressions.
|
||||
ParseNode* element = node->pn_right->pn_head;
|
||||
element = element->pn_next;
|
||||
#ifdef DEBUG
|
||||
{
|
||||
MOZ_ASSERT(element->isKind(ParseNodeKind::CallSiteObj));
|
||||
|
@ -697,6 +697,9 @@ class NameResolver
|
|||
case ParseNodeKind::Pow:
|
||||
case ParseNodeKind::Pipeline:
|
||||
case ParseNodeKind::Comma:
|
||||
case ParseNodeKind::New:
|
||||
case ParseNodeKind::Call:
|
||||
case ParseNodeKind::SuperCall:
|
||||
case ParseNodeKind::Array:
|
||||
case ParseNodeKind::StatementList:
|
||||
case ParseNodeKind::ParamsBody:
|
||||
|
@ -730,32 +733,11 @@ class NameResolver
|
|||
break;
|
||||
|
||||
case ParseNodeKind::TaggedTemplate:
|
||||
MOZ_ASSERT(cur->isArity(PN_BINARY));
|
||||
MOZ_ASSERT(cur->isArity(PN_LIST));
|
||||
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 +766,12 @@ class NameResolver
|
|||
}
|
||||
|
||||
case ParseNodeKind::Dot:
|
||||
MOZ_ASSERT(cur->isArity(PN_BINARY));
|
||||
MOZ_ASSERT(cur->isArity(PN_NAME));
|
||||
|
||||
// Super prop nodes do not have a meaningful LHS
|
||||
if (cur->as<PropertyAccess>().isSuper())
|
||||
break;
|
||||
if (!resolve(cur->pn_left, prefix))
|
||||
if (!resolve(cur->expr(), prefix))
|
||||
return false;
|
||||
break;
|
||||
|
||||
|
@ -828,7 +810,6 @@ 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
|
||||
|
|
|
@ -216,21 +216,6 @@ UnaryNode::dump(GenericPrinter& out, int indent)
|
|||
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;
|
||||
|
@ -303,7 +288,10 @@ DumpName(GenericPrinter& out, const CharT* s, size_t len)
|
|||
void
|
||||
NameNode::dump(GenericPrinter& out, int indent)
|
||||
{
|
||||
if (isKind(ParseNodeKind::Name) || isKind(ParseNodeKind::PropertyName)) {
|
||||
if (isKind(ParseNodeKind::Name) || isKind(ParseNodeKind::Dot)) {
|
||||
if (isKind(ParseNodeKind::Dot))
|
||||
out.put("(.");
|
||||
|
||||
if (!pn_atom) {
|
||||
out.put("#<null name>");
|
||||
} else if (getOp() == JSOP_GETARG && pn_atom->length() == 0) {
|
||||
|
@ -318,6 +306,15 @@ NameNode::dump(GenericPrinter& out, int indent)
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,6 @@ class ObjectBox;
|
|||
F(PostIncrement) \
|
||||
F(PreDecrement) \
|
||||
F(PostDecrement) \
|
||||
F(PropertyName) \
|
||||
F(Dot) \
|
||||
F(Elem) \
|
||||
F(Array) \
|
||||
|
@ -64,7 +63,6 @@ class ObjectBox;
|
|||
F(Label) \
|
||||
F(Object) \
|
||||
F(Call) \
|
||||
F(Arguments) \
|
||||
F(Name) \
|
||||
F(ObjectPropertyName) \
|
||||
F(ComputedName) \
|
||||
|
@ -372,8 +370,9 @@ IsTypeofKind(ParseNodeKind kind)
|
|||
* PostIncrement,
|
||||
* PreDecrement,
|
||||
* PostDecrement
|
||||
* New binary pn_left: ctor expression on the left of the (
|
||||
* pn_right: Arguments
|
||||
* 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
|
||||
* DeleteName unary pn_kid: Name expr
|
||||
* DeleteProp unary pn_kid: Dot expr
|
||||
* DeleteElem unary pn_kid: Elem expr
|
||||
|
@ -382,15 +381,13 @@ IsTypeofKind(ParseNodeKind kind)
|
|||
* for a more-specific PNK_DELETE* unless constant
|
||||
* folding (or a similar parse tree manipulation) has
|
||||
* occurred
|
||||
* PropertyName name pn_atom: property name being accessed
|
||||
* Dot binary pn_left: MEMBER expr to left of .
|
||||
* pn_right: PropertyName to right of .
|
||||
* 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 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)
|
||||
* 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
|
||||
* 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
|
||||
|
@ -410,9 +407,8 @@ IsTypeofKind(ParseNodeKind kind)
|
|||
* list
|
||||
* TemplateString pn_atom: template string atom
|
||||
nullary pn_op: JSOP_NOP
|
||||
* TaggedTemplate pn_left: tag expression
|
||||
* binary pn_right: Arguments, with the first being the
|
||||
* call site object, then arg1, arg2, ... argN
|
||||
* TaggedTemplate pn_head: list of call, call site object, arg1, arg2, ... argN
|
||||
* list pn_count: 2 + N (N is the number of substitutions)
|
||||
* CallSiteObj list pn_head: a Array node followed by
|
||||
* list of pn_count - 1 TemplateString nodes
|
||||
* RegExp nullary pn_objbox: RegExp model object
|
||||
|
@ -424,7 +420,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,7 +569,8 @@ class ParseNode
|
|||
FunctionBox* funbox; /* function object */
|
||||
};
|
||||
ParseNode* expr; /* module or function body, var
|
||||
initializer, or argument default */
|
||||
initializer, argument default, or
|
||||
base object of ParseNodeKind::Dot */
|
||||
} name;
|
||||
struct {
|
||||
LexicalScope::Data* bindings;
|
||||
|
@ -1177,33 +1174,30 @@ class RegExpLiteral : public NullaryNode
|
|||
}
|
||||
};
|
||||
|
||||
class PropertyAccess : public BinaryNode
|
||||
class PropertyAccess : public ParseNode
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* 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)
|
||||
PropertyAccess(ParseNode* lhs, PropertyName* name, uint32_t begin, uint32_t end)
|
||||
: ParseNode(ParseNodeKind::Dot, JSOP_NOP, PN_NAME, TokenPos(begin, end))
|
||||
{
|
||||
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_BINARY));
|
||||
MOZ_ASSERT_IF(match, node.pn_right->isKind(ParseNodeKind::PropertyName));
|
||||
MOZ_ASSERT_IF(match, node.isArity(PN_NAME));
|
||||
return match;
|
||||
}
|
||||
|
||||
ParseNode& expression() const {
|
||||
return *pn_u.binary.left;
|
||||
return *pn_u.name.expr;
|
||||
}
|
||||
|
||||
PropertyName& name() const {
|
||||
return *pn_u.binary.right->pn_atom->asPropertyName();
|
||||
return *pn_u.name.atom->asPropertyName();
|
||||
}
|
||||
|
||||
bool isSuper() const {
|
||||
|
|
|
@ -3395,13 +3395,13 @@ GeneralParser<ParseHandler, CharT>::addExprAndGetNextTemplStrToken(YieldHandling
|
|||
|
||||
template <class ParseHandler, typename CharT>
|
||||
bool
|
||||
GeneralParser<ParseHandler, CharT>::taggedTemplate(YieldHandling yieldHandling, Node tagArgsList,
|
||||
GeneralParser<ParseHandler, CharT>::taggedTemplate(YieldHandling yieldHandling, Node nodeList,
|
||||
TokenKind tt)
|
||||
{
|
||||
Node callSiteObjNode = handler.newCallSiteObject(pos().begin);
|
||||
if (!callSiteObjNode)
|
||||
return false;
|
||||
handler.addList(tagArgsList, callSiteObjNode);
|
||||
handler.addList(nodeList, callSiteObjNode);
|
||||
|
||||
while (true) {
|
||||
if (!appendToCallSiteObj(callSiteObjNode))
|
||||
|
@ -3409,10 +3409,10 @@ GeneralParser<ParseHandler, CharT>::taggedTemplate(YieldHandling yieldHandling,
|
|||
if (tt != TokenKind::TemplateHead)
|
||||
break;
|
||||
|
||||
if (!addExprAndGetNextTemplStrToken(yieldHandling, tagArgsList, &tt))
|
||||
if (!addExprAndGetNextTemplStrToken(yieldHandling, nodeList, &tt))
|
||||
return false;
|
||||
}
|
||||
handler.setEndPosition(tagArgsList, callSiteObjNode);
|
||||
handler.setEndPosition(nodeList, callSiteObjNode);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -8631,25 +8631,24 @@ GeneralParser<ParseHandler, CharT>::assignExprWithoutYieldOrAwait(YieldHandling
|
|||
}
|
||||
|
||||
template <class ParseHandler, typename CharT>
|
||||
typename ParseHandler::Node
|
||||
GeneralParser<ParseHandler, CharT>::argumentList(YieldHandling yieldHandling, bool* isSpread,
|
||||
bool
|
||||
GeneralParser<ParseHandler, CharT>::argumentList(YieldHandling yieldHandling, Node listNode,
|
||||
bool* isSpread,
|
||||
PossibleError* possibleError /* = nullptr */)
|
||||
{
|
||||
Node argsList = handler.newArguments(pos());
|
||||
|
||||
bool matched;
|
||||
if (!tokenStream.matchToken(&matched, TokenKind::Rp, TokenStream::Operand))
|
||||
return null();
|
||||
return false;
|
||||
if (matched) {
|
||||
handler.setEndPosition(argsList, pos().end);
|
||||
return argsList;
|
||||
handler.setEndPosition(listNode, pos().end);
|
||||
return true;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
bool spread = false;
|
||||
uint32_t begin = 0;
|
||||
if (!tokenStream.matchToken(&matched, TokenKind::TripleDot, TokenStream::Operand))
|
||||
return null();
|
||||
return false;
|
||||
if (matched) {
|
||||
spread = true;
|
||||
begin = pos().begin;
|
||||
|
@ -8658,18 +8657,18 @@ GeneralParser<ParseHandler, CharT>::argumentList(YieldHandling yieldHandling, bo
|
|||
|
||||
Node argNode = assignExpr(InAllowed, yieldHandling, TripledotProhibited, possibleError);
|
||||
if (!argNode)
|
||||
return null();
|
||||
return false;
|
||||
if (spread) {
|
||||
argNode = handler.newSpread(begin, argNode);
|
||||
if (!argNode)
|
||||
return null();
|
||||
return false;
|
||||
}
|
||||
|
||||
handler.addList(argsList, argNode);
|
||||
handler.addList(listNode, argNode);
|
||||
|
||||
bool matched;
|
||||
if (!tokenStream.matchToken(&matched, TokenKind::Comma, TokenStream::Operand))
|
||||
return null();
|
||||
return false;
|
||||
if (!matched)
|
||||
break;
|
||||
|
||||
|
@ -8682,8 +8681,8 @@ GeneralParser<ParseHandler, CharT>::argumentList(YieldHandling yieldHandling, bo
|
|||
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::Rp, TokenStream::Operand, JSMSG_PAREN_AFTER_ARGS);
|
||||
|
||||
handler.setEndPosition(argsList, pos().end);
|
||||
return argsList;
|
||||
handler.setEndPosition(listNode, pos().end);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -8729,27 +8728,20 @@ GeneralParser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
|
|||
if (!ctorExpr)
|
||||
return null();
|
||||
|
||||
bool matched;
|
||||
if (!tokenStream.matchToken(&matched, TokenKind::Lp))
|
||||
return null();
|
||||
|
||||
bool isSpread = false;
|
||||
Node args;
|
||||
if (matched) {
|
||||
args = argumentList(yieldHandling, &isSpread);
|
||||
} else {
|
||||
args = handler.newArguments(pos());
|
||||
}
|
||||
|
||||
if (!args)
|
||||
return null();
|
||||
|
||||
lhs = handler.newNewExpression(newBegin, ctorExpr, args);
|
||||
lhs = handler.newNewExpression(newBegin, ctorExpr);
|
||||
if (!lhs)
|
||||
return null();
|
||||
|
||||
if (isSpread)
|
||||
handler.setOp(lhs, JSOP_SPREADNEW);
|
||||
bool matched;
|
||||
if (!tokenStream.matchToken(&matched, TokenKind::Lp))
|
||||
return null();
|
||||
if (matched) {
|
||||
bool isSpread = false;
|
||||
if (!argumentList(yieldHandling, lhs, &isSpread))
|
||||
return null();
|
||||
if (isSpread)
|
||||
handler.setOp(lhs, JSOP_SPREADNEW);
|
||||
}
|
||||
}
|
||||
} else if (tt == TokenKind::Super) {
|
||||
Node thisName = newThisName();
|
||||
|
@ -8786,12 +8778,7 @@ GeneralParser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
|
|||
error(JSMSG_BAD_SUPERPROP, "property");
|
||||
return null();
|
||||
}
|
||||
|
||||
Node name = handler.newPropertyName(field, pos());
|
||||
if (!name)
|
||||
return null();
|
||||
|
||||
nextMember = handler.newPropertyAccess(lhs, name);
|
||||
nextMember = handler.newPropertyAccess(lhs, field, pos().end);
|
||||
if (!nextMember)
|
||||
return null();
|
||||
} else {
|
||||
|
@ -8827,16 +8814,15 @@ GeneralParser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
|
|||
return null();
|
||||
}
|
||||
|
||||
nextMember = handler.newSuperCall(lhs);
|
||||
if (!nextMember)
|
||||
return null();
|
||||
|
||||
// Despite the fact that it's impossible to have |super()| in a
|
||||
// generator, we still inherit the yieldHandling of the
|
||||
// memberExpression, per spec. Curious.
|
||||
bool isSpread = false;
|
||||
Node args = argumentList(yieldHandling, &isSpread);
|
||||
if (!args)
|
||||
return null();
|
||||
|
||||
nextMember = handler.newSuperCall(lhs, args);
|
||||
if (!nextMember)
|
||||
if (!argumentList(yieldHandling, nextMember, &isSpread))
|
||||
return null();
|
||||
|
||||
if (isSpread)
|
||||
|
@ -8855,6 +8841,13 @@ GeneralParser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
|
|||
return null();
|
||||
}
|
||||
|
||||
TokenPos nextMemberPos = pos();
|
||||
nextMember = tt == TokenKind::Lp
|
||||
? handler.newCall(nextMemberPos)
|
||||
: handler.newTaggedTemplate(nextMemberPos);
|
||||
if (!nextMember)
|
||||
return null();
|
||||
|
||||
JSOp op = JSOP_CALL;
|
||||
bool maybeAsyncArrow = false;
|
||||
if (PropertyName* prop = handler.maybeDottedProperty(lhs)) {
|
||||
|
@ -8896,11 +8889,13 @@ GeneralParser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
|
|||
}
|
||||
}
|
||||
|
||||
handler.setBeginPosition(nextMember, lhs);
|
||||
handler.addList(nextMember, lhs);
|
||||
|
||||
if (tt == TokenKind::Lp) {
|
||||
bool isSpread = false;
|
||||
PossibleError* asyncPossibleError = maybeAsyncArrow ? possibleError : nullptr;
|
||||
Node args = argumentList(yieldHandling, &isSpread, asyncPossibleError);
|
||||
if (!args)
|
||||
if (!argumentList(yieldHandling, nextMember, &isSpread, asyncPossibleError))
|
||||
return null();
|
||||
if (isSpread) {
|
||||
if (op == JSOP_EVAL)
|
||||
|
@ -8910,20 +8905,8 @@ GeneralParser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
|
|||
else
|
||||
op = JSOP_SPREADCALL;
|
||||
}
|
||||
|
||||
nextMember = handler.newCall(lhs, args);
|
||||
if (!nextMember)
|
||||
return null();
|
||||
} else {
|
||||
Node args = handler.newArguments(pos());
|
||||
if (!args)
|
||||
return null();
|
||||
|
||||
if (!taggedTemplate(yieldHandling, args, tt))
|
||||
return null();
|
||||
|
||||
nextMember = handler.newTaggedTemplate(lhs, args);
|
||||
if (!nextMember)
|
||||
if (!taggedTemplate(yieldHandling, nextMember, tt))
|
||||
return null();
|
||||
}
|
||||
handler.setOp(nextMember, op);
|
||||
|
|
|
@ -569,12 +569,8 @@ class MOZ_STACK_CLASS PerHandlerParser
|
|||
bool isValidSimpleAssignmentTarget(Node node,
|
||||
FunctionCallBehavior behavior = ForbidAssignmentToFunctionCalls);
|
||||
|
||||
Node newPropertyName(PropertyName* key, const TokenPos& pos) {
|
||||
return handler.newPropertyName(key, pos);
|
||||
}
|
||||
|
||||
Node newPropertyAccess(Node expr, Node key) {
|
||||
return handler.newPropertyAccess(expr, key);
|
||||
Node newPropertyAccess(Node expr, PropertyName* key, uint32_t end) {
|
||||
return handler.newPropertyAccess(expr, key, end);
|
||||
}
|
||||
|
||||
FunctionBox* newFunctionBox(Node fn, JSFunction* fun, uint32_t toStringStart,
|
||||
|
@ -1159,7 +1155,7 @@ class MOZ_STACK_CLASS GeneralParser
|
|||
|
||||
Node condition(InHandling inHandling, YieldHandling yieldHandling);
|
||||
|
||||
Node argumentList(YieldHandling yieldHandling, bool* isSpread,
|
||||
bool argumentList(YieldHandling yieldHandling, Node listNode, bool* isSpread,
|
||||
PossibleError* possibleError = nullptr);
|
||||
Node destructuringDeclaration(DeclarationKind kind, YieldHandling yieldHandling,
|
||||
TokenKind tt);
|
||||
|
|
|
@ -248,11 +248,9 @@ class SyntaxParseHandler
|
|||
MOZ_MUST_USE bool addSpreadElement(Node literal, uint32_t begin, Node inner) { return true; }
|
||||
void addArrayElement(Node literal, Node element) { }
|
||||
|
||||
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 newCall(const TokenPos& pos) { return NodeFunctionCall; }
|
||||
Node newSuperCall(Node callee) { return NodeGeneric; }
|
||||
Node newTaggedTemplate(const TokenPos& pos) { return NodeGeneric; }
|
||||
|
||||
Node newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; }
|
||||
Node newClassMethodList(uint32_t begin) { return NodeGeneric; }
|
||||
|
@ -330,12 +328,8 @@ class SyntaxParseHandler
|
|||
}
|
||||
Node newDebuggerStatement(const TokenPos& pos) { return NodeGeneric; }
|
||||
|
||||
Node newPropertyName(PropertyName* name, const TokenPos& pos) {
|
||||
lastAtom = name;
|
||||
return NodeGeneric;
|
||||
}
|
||||
|
||||
Node newPropertyAccess(Node expr, Node key) {
|
||||
Node newPropertyAccess(Node expr, PropertyName* key, uint32_t end) {
|
||||
lastAtom = key;
|
||||
return NodeDottedProperty;
|
||||
}
|
||||
|
||||
|
@ -430,7 +424,7 @@ class SyntaxParseHandler
|
|||
list == NodeFunctionCall);
|
||||
}
|
||||
|
||||
Node newNewExpression(uint32_t begin, Node ctor, Node args) {
|
||||
Node newNewExpression(uint32_t begin, Node ctor) {
|
||||
return NodeGeneric;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,12 +33,7 @@ function assertOffsetColumns(code, expectedBpts, expectedOrdering = null) {
|
|||
|
||||
// Set breakpoints everywhere and call the function.
|
||||
const dbg = new Debugger;
|
||||
let debuggeeFn = dbg.addDebuggee(global).makeDebuggeeValue(global.f);
|
||||
if (debuggeeFn.isBoundFunction) {
|
||||
debuggeeFn = debuggeeFn.boundTargetFunction;
|
||||
}
|
||||
|
||||
const { script } = debuggeeFn;
|
||||
const script = dbg.addDebuggee(global).makeDebuggeeValue(global.f).script;
|
||||
for (const offset of script.getAllColumnOffsets()) {
|
||||
assertEq(offset.lineNumber, 1);
|
||||
assertEq(offset.columnNumber < execCode.length, true);
|
||||
|
|
|
@ -83,58 +83,3 @@ assertOffsetColumns(
|
|||
"function f(n) { do { print(n); } while(false); }",
|
||||
" ^ ^ ^",
|
||||
);
|
||||
|
||||
// getColumnOffsets correctly places the part of normal ::Dot node with identifier root.
|
||||
assertOffsetColumns(
|
||||
"var args = [];\n" +
|
||||
"var obj = { base: { a(){ return { b(){} }; } } };\n" +
|
||||
"function f(n) { obj.base.a().b(...args); }",
|
||||
" ^ ^ ^ ^",
|
||||
"0 2 1 3",
|
||||
);
|
||||
|
||||
// getColumnOffsets correctly places the part of normal ::Dot node with "this" root.
|
||||
assertOffsetColumns(
|
||||
"var args = [];\n" +
|
||||
"var obj = { base: { a(){ return { b(){} }; } } };\n" +
|
||||
"var f = function() { this.base.a().b(...args); }.bind(obj);",
|
||||
" ^ ^ ^ ^",
|
||||
"0 2 1 3",
|
||||
);
|
||||
|
||||
// getColumnOffsets correctly places the part of normal ::Dot node with "super" base.
|
||||
assertOffsetColumns(
|
||||
"var args = [];\n" +
|
||||
"var obj = { base: { a(){ return { b(){} }; } } };\n" +
|
||||
"var f = { __proto__: obj, f(n) { super.base.a().b(...args); } }.f;",
|
||||
" ^ ^ ^ ^",
|
||||
"0 2 1 3",
|
||||
);
|
||||
|
||||
// getColumnOffsets correctly places the part of normal ::Dot node with other base.
|
||||
assertOffsetColumns(
|
||||
"var args = [];\n" +
|
||||
"var obj = { base: { a(){ return { b(){} }; } } };\n" +
|
||||
"function f(n) { (0, obj).base.a().b(...args); }",
|
||||
" ^ ^ ^ ^ ^ ^",
|
||||
"0 1 2 4 3 5",
|
||||
);
|
||||
|
||||
// getColumnOffsets correctly places the part of folded ::Elem node.
|
||||
assertOffsetColumns(
|
||||
"var args = [];\n" +
|
||||
"var obj = { base: { a(){ return { b(){} }; } } };\n" +
|
||||
// Constant folding makes the static string behave like a dot access.
|
||||
"function f(n) { obj.base['a']()['b'](...args); }",
|
||||
" ^ ^ ^ ^",
|
||||
"0 2 1 3",
|
||||
);
|
||||
|
||||
// getColumnOffsets correctly places the part of computed ::Elem node.
|
||||
assertOffsetColumns(
|
||||
"var args = [], a = 'a', b = 'b';\n" +
|
||||
"var obj = { base: { a(){ return { b(){} }; } } };\n" +
|
||||
"function f(n) { obj.base[a]()[b](...args); }",
|
||||
" ^ ^ ^^ ^",
|
||||
"0 1 3 2 4",
|
||||
);
|
||||
|
|
|
@ -438,21 +438,22 @@ static inline ParseNode*
|
|||
CallCallee(ParseNode* pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isKind(ParseNodeKind::Call));
|
||||
return BinaryLeft(pn);
|
||||
return ListHead(pn);
|
||||
}
|
||||
|
||||
static inline unsigned
|
||||
CallArgListLength(ParseNode* pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isKind(ParseNodeKind::Call));
|
||||
return ListLength(BinaryRight(pn));
|
||||
MOZ_ASSERT(ListLength(pn) >= 1);
|
||||
return ListLength(pn) - 1;
|
||||
}
|
||||
|
||||
static inline ParseNode*
|
||||
CallArgList(ParseNode* pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isKind(ParseNodeKind::Call));
|
||||
return ListHead(BinaryRight(pn));
|
||||
return NextNode(ListHead(pn));
|
||||
}
|
||||
|
||||
static inline ParseNode*
|
||||
|
@ -615,16 +616,16 @@ static ParseNode*
|
|||
DotBase(ParseNode* pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isKind(ParseNodeKind::Dot));
|
||||
MOZ_ASSERT(pn->isArity(PN_BINARY));
|
||||
return pn->pn_left;
|
||||
MOZ_ASSERT(pn->isArity(PN_NAME));
|
||||
return pn->expr();
|
||||
}
|
||||
|
||||
static PropertyName*
|
||||
DotMember(ParseNode* pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isKind(ParseNodeKind::Dot));
|
||||
MOZ_ASSERT(pn->isArity(PN_BINARY));
|
||||
return pn->pn_right->pn_atom->asPropertyName();
|
||||
MOZ_ASSERT(pn->isArity(PN_NAME));
|
||||
return pn->pn_atom->asPropertyName();
|
||||
}
|
||||
|
||||
static ParseNode*
|
||||
|
@ -2902,11 +2903,9 @@ IsArrayViewCtorName(ModuleValidator& m, PropertyName* name, Scalar::Type* type)
|
|||
}
|
||||
|
||||
static bool
|
||||
CheckNewArrayViewArgs(ModuleValidator& m, ParseNode* newExpr, PropertyName* bufferName)
|
||||
CheckNewArrayViewArgs(ModuleValidator& m, ParseNode* ctorExpr, PropertyName* bufferName)
|
||||
{
|
||||
ParseNode* ctorExpr = BinaryLeft(newExpr);
|
||||
ParseNode* ctorArgs = BinaryRight(newExpr);
|
||||
ParseNode* bufArg = ListHead(ctorArgs);
|
||||
ParseNode* bufArg = NextNode(ctorExpr);
|
||||
if (!bufArg || NextNode(bufArg) != nullptr)
|
||||
return m.fail(ctorExpr, "array view constructor takes exactly one argument");
|
||||
|
||||
|
@ -2927,7 +2926,7 @@ CheckNewArrayView(ModuleValidator& m, PropertyName* varName, ParseNode* newExpr)
|
|||
if (!bufferName)
|
||||
return m.fail(newExpr, "cannot create array view without an asm.js heap parameter");
|
||||
|
||||
ParseNode* ctorExpr = BinaryLeft(newExpr);
|
||||
ParseNode* ctorExpr = ListHead(newExpr);
|
||||
|
||||
PropertyName* field;
|
||||
Scalar::Type type;
|
||||
|
@ -2956,7 +2955,7 @@ CheckNewArrayView(ModuleValidator& m, PropertyName* varName, ParseNode* newExpr)
|
|||
type = global->viewType();
|
||||
}
|
||||
|
||||
if (!CheckNewArrayViewArgs(m, newExpr, bufferName))
|
||||
if (!CheckNewArrayViewArgs(m, ctorExpr, bufferName))
|
||||
return false;
|
||||
|
||||
return m.addArrayView(varName, type, field);
|
||||
|
|
Загрузка…
Ссылка в новой задаче