Backed out 4 changesets (bug 1168992) for apparently breaking reftests CLOSED TREE

Backed out changeset cb3a01796c02 (bug 1168992)
Backed out changeset 45e16ff50caa (bug 1168992)
Backed out changeset 6155cc98258d (bug 1168992)
Backed out changeset 0ff820964ea0 (bug 1168992)
This commit is contained in:
Wes Kocher 2015-09-02 15:51:40 -07:00
parent 77b2282d48
commit 38d99f5a7a
18 changed files with 493 additions and 428 deletions

View File

@ -756,9 +756,7 @@ class NodeBuilder
bool generatorExpression(HandleValue body, NodeVector& blocks, HandleValue filter,
bool isLegacy, TokenPos* pos, MutableHandleValue dst);
bool metaProperty(HandleValue meta, HandleValue property, TokenPos* pos, MutableHandleValue dst);
bool super(TokenPos* pos, MutableHandleValue dst);
bool newTargetExpression(TokenPos* pos, MutableHandleValue dst);
/*
* declarations
@ -1821,33 +1819,20 @@ NodeBuilder::classDefinition(bool expr, HandleValue name, HandleValue heritage,
return callback(cb, name, heritage, block, pos, dst);
return newNode(type, pos,
"id", name,
"superClass", heritage,
"name", name,
"heritage", heritage,
"body", block,
dst);
}
bool
NodeBuilder::metaProperty(HandleValue meta, HandleValue property, TokenPos* pos, MutableHandleValue dst)
NodeBuilder::newTargetExpression(TokenPos* pos, MutableHandleValue dst)
{
RootedValue cb(cx, callbacks[AST_METAPROPERTY]);
if (!cb.isNull())
return callback(cb, meta, property, pos, dst);
return newNode(AST_METAPROPERTY, pos,
"meta", meta,
"property", property,
dst);
}
bool
NodeBuilder::super(TokenPos* pos, MutableHandleValue dst)
{
RootedValue cb(cx, callbacks[AST_SUPER]);
RootedValue cb(cx, callbacks[AST_NEWTARGET_EXPR]);
if (!cb.isNull())
return callback(cb, pos, dst);
return newNode(AST_SUPER, pos, dst);
return newNode(AST_NEWTARGET_EXPR, pos, dst);
}
namespace {
@ -3081,7 +3066,9 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
case PNK_DELETENAME:
case PNK_DELETEPROP:
case PNK_DELETESUPERPROP:
case PNK_DELETEELEM:
case PNK_DELETESUPERELEM:
case PNK_DELETEEXPR:
case PNK_TYPEOFNAME:
case PNK_TYPEOFEXPR:
@ -3142,20 +3129,21 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
{
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_expr->pn_pos));
RootedValue expr(cx);
RootedValue propname(cx);
RootedValue expr(cx), id(cx);
RootedAtom pnAtom(cx, pn->pn_atom);
return expression(pn->pn_expr, &expr) &&
identifier(pnAtom, nullptr, &id) &&
builder.memberExpression(false, expr, id, &pn->pn_pos, dst);
}
if (pn->as<PropertyAccess>().isSuper()) {
if (!builder.super(&pn->pn_expr->pn_pos, &expr))
return false;
} else {
if (!expression(pn->pn_expr, &expr))
return false;
}
return identifier(pnAtom, nullptr, &propname) &&
builder.memberExpression(false, expr, propname, &pn->pn_pos, dst);
case PNK_SUPERPROP:
{
RootedValue superBase(cx), id(cx);
RootedAtom superAtom(cx, cx->names().super);
RootedAtom pnAtom(cx, pn->pn_atom);
return identifier(superAtom, nullptr, &superBase) &&
identifier(pnAtom, nullptr, &id) &&
builder.memberExpression(false, superBase, id, &pn->pn_pos, dst);
}
case PNK_ELEM:
@ -3164,19 +3152,22 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
RootedValue left(cx), right(cx);
if (pn->as<PropertyByValue>().isSuper()) {
if (!builder.super(&pn->pn_left->pn_pos, &left))
return false;
} else {
if (!expression(pn->pn_left, &left))
return false;
}
return expression(pn->pn_right, &right) &&
return expression(pn->pn_left, &left) &&
expression(pn->pn_right, &right) &&
builder.memberExpression(true, left, right, &pn->pn_pos, dst);
}
case PNK_SUPERELEM:
{
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
RootedValue superBase(cx), expr(cx);
RootedAtom superAtom(cx, cx->names().super);
return identifier(superAtom, nullptr, &superBase) &&
expression(pn->pn_kid, &expr) &&
builder.memberExpression(true, superBase, expr, &pn->pn_pos, dst);
}
case PNK_CALLSITEOBJ:
{
NodeVector raw(cx);
@ -3321,22 +3312,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
return classDefinition(pn, true, dst);
case PNK_NEWTARGET:
{
MOZ_ASSERT(pn->pn_left->isKind(PNK_POSHOLDER));
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
MOZ_ASSERT(pn->pn_right->isKind(PNK_POSHOLDER));
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
RootedValue newIdent(cx);
RootedValue targetIdent(cx);
RootedAtom newStr(cx, cx->names().new_);
RootedAtom targetStr(cx, cx->names().target);
return identifier(newStr, &pn->pn_left->pn_pos, &newIdent) &&
identifier(targetStr, &pn->pn_right->pn_pos, &targetIdent) &&
builder.metaProperty(newIdent, targetIdent, &pn->pn_pos, dst);
}
return builder.newTargetExpression(&pn->pn_pos, dst);
default:
LOCAL_NOT_REACHED("unexpected expression type");

View File

@ -1915,6 +1915,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
switch (pn->getKind()) {
// Trivial cases with no side effects.
case PNK_NEWTARGET:
case PNK_NOP:
case PNK_STRING:
case PNK_TEMPLATE_STRING:
@ -1931,14 +1932,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
*answer = false;
return true;
// Trivial binary nodes with more token pos holders.
case PNK_NEWTARGET:
MOZ_ASSERT(pn->isArity(PN_BINARY));
MOZ_ASSERT(pn->pn_left->isKind(PNK_POSHOLDER));
MOZ_ASSERT(pn->pn_right->isKind(PNK_POSHOLDER));
*answer = false;
return true;
case PNK_BREAK:
case PNK_CONTINUE:
case PNK_DEBUGGER:
@ -1947,6 +1940,12 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
return true;
// Watch out for getters!
case PNK_SUPERPROP:
MOZ_ASSERT(pn->isArity(PN_NULLARY));
*answer = true;
return true;
// Again, getters.
case PNK_DOT:
MOZ_ASSERT(pn->isArity(PN_NAME));
*answer = true;
@ -2012,7 +2011,9 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
// Deletion generally has side effects, even if isolated cases have none.
case PNK_DELETENAME:
case PNK_DELETEPROP:
case PNK_DELETESUPERPROP:
case PNK_DELETEELEM:
case PNK_DELETESUPERELEM:
MOZ_ASSERT(pn->isArity(PN_UNARY));
*answer = true;
return true;
@ -2120,6 +2121,12 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
*answer = true;
return true;
// Again, getters.
case PNK_SUPERELEM:
MOZ_ASSERT(pn->isArity(PN_UNARY));
*answer = true;
return true;
// These affect visible names in this code, or in other code.
case PNK_IMPORT:
case PNK_EXPORT_FROM:
@ -2313,7 +2320,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_EXPORT_SPEC_LIST: // by PNK_EXPORT
case PNK_EXPORT_SPEC: // by PNK_EXPORT
case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE
case PNK_POSHOLDER: // by PNK_NEWTARGET
MOZ_CRASH("handled by parent nodes");
case PNK_LIMIT: // invalid sentinel value
@ -2546,9 +2552,6 @@ BytecodeEmitter::emitPropLHS(ParseNode* pn)
MOZ_ASSERT(pn->isKind(PNK_DOT));
ParseNode* pn2 = pn->maybeExpr();
// Don't want super sneaking in here.
MOZ_ASSERT(!pn2->isKind(PNK_POSHOLDER));
/*
* 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
@ -2565,7 +2568,7 @@ BytecodeEmitter::emitPropLHS(ParseNode* pn)
MOZ_ASSERT(!pndot->isUsed());
pndown = pndot->pn_expr;
pndot->pn_expr = pnup;
if (!pndown->isKind(PNK_DOT) || pndown->as<PropertyAccess>().isSuper())
if (!pndown->isKind(PNK_DOT))
break;
pnup = pndot;
pndot = pndown;
@ -2645,21 +2648,13 @@ BytecodeEmitter::emitPropIncDec(ParseNode* pn)
MOZ_ASSERT(pn->pn_kid->isKind(PNK_DOT));
bool post;
bool isSuper = pn->pn_kid->as<PropertyAccess>().isSuper();
JSOp binop = GetIncDecInfo(pn->getKind(), &post);
if (isSuper) {
if (!emitSuperPropLHS()) // THIS OBJ
return false;
if (!emit1(JSOP_DUP2)) // THIS OBJ THIS OBJ
return false;
} else {
if (!emitPropLHS(pn->pn_kid)) // OBJ
return false;
if (!emit1(JSOP_DUP)) // OBJ OBJ
return false;
}
if (!emitAtomOp(pn->pn_kid, isSuper? JSOP_GETPROP_SUPER : JSOP_GETPROP)) // OBJ V
if (!emitPropLHS(pn->pn_kid)) // OBJ
return false;
if (!emit1(JSOP_DUP)) // OBJ OBJ
return false;
if (!emitAtomOp(pn->pn_kid, JSOP_GETPROP)) // OBJ V
return false;
if (!emit1(JSOP_POS)) // OBJ N
return false;
@ -2671,20 +2666,13 @@ BytecodeEmitter::emitPropIncDec(ParseNode* pn)
return false;
if (post) {
if (!emit2(JSOP_PICK, 2 + isSuper)) // N? N+1 OBJ
if (!emit2(JSOP_PICK, 2)) // N? N+1 OBJ
return false;
if (!emit1(JSOP_SWAP)) // N? OBJ N+1
if (!emit1(JSOP_SWAP)) // N? OBJ N+1
return false;
if (isSuper) {
if (!emit2(JSOP_PICK, 3)) // N THIS N+1 OBJ
return false;
if (!emit1(JSOP_SWAP)) // N THIS OBJ N+1
return false;
}
}
JSOp setOp = isSuper ? sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER
: sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
JSOp setOp = sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
if (!emitAtomOp(pn->pn_kid, setOp)) // N? N+1
return false;
if (post && !emit1(JSOP_POP)) // RESULT
@ -2693,6 +2681,50 @@ BytecodeEmitter::emitPropIncDec(ParseNode* pn)
return true;
}
bool
BytecodeEmitter::emitSuperPropIncDec(ParseNode* pn)
{
MOZ_ASSERT(pn->pn_kid->isKind(PNK_SUPERPROP));
bool post;
JSOp binop = GetIncDecInfo(pn->getKind(), &post);
if (!emitSuperPropLHS()) // THIS OBJ
return false;
if (!emit1(JSOP_DUP2)) // THIS OBJ THIS OBJ
return false;
if (!emitAtomOp(pn->pn_kid, JSOP_GETPROP_SUPER)) // THIS OBJ V
return false;
if (!emit1(JSOP_POS)) // THIS OBJ N
return false;
if (post && !emit1(JSOP_DUP)) // THIS OBJ N? N
return false;
if (!emit1(JSOP_ONE)) // THIS OBJ N? N 1
return false;
if (!emit1(binop)) // THIS OBJ N? N+1
return false;
if (post) {
if (!emit2(JSOP_PICK, 3)) // OBJ N N+1 THIS
return false;
if (!emit1(JSOP_SWAP)) // OBJ N THIS N+1
return false;
if (!emit2(JSOP_PICK, 3)) // N THIS N+1 OBJ
return false;
if (!emit1(JSOP_SWAP)) // N THIS OBJ N+1
return false;
}
JSOp setOp = sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER;
if (!emitAtomOp(pn->pn_kid, setOp)) // N? N+1
return false;
if (post && !emit1(JSOP_POP)) // RESULT
return false;
return true;
}
bool
BytecodeEmitter::emitNameIncDec(ParseNode* pn)
{
@ -2754,14 +2786,14 @@ BytecodeEmitter::emitElemOperands(ParseNode* pn, JSOp op)
bool
BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts)
{
MOZ_ASSERT(pn->isKind(PNK_ELEM) && pn->as<PropertyByValue>().isSuper());
MOZ_ASSERT(pn->isKind(PNK_SUPERELEM));
// The ordering here is somewhat screwy. We need to evaluate the propval
// first, by spec. Do a little dance to not emit more than one JSOP_THIS.
// Since JSOP_THIS might throw in derived class constructors, we cannot
// just push it earlier as the receiver. We have to swap it down instead.
if (!emitTree(pn->pn_right))
if (!emitTree(pn->pn_kid))
return false;
// We need to convert the key to an object id first, so that we do not do
@ -2831,76 +2863,99 @@ BytecodeEmitter::emitElemIncDec(ParseNode* pn)
{
MOZ_ASSERT(pn->pn_kid->isKind(PNK_ELEM));
bool isSuper = pn->pn_kid->as<PropertyByValue>().isSuper();
if (isSuper) {
if (!emitSuperElemOperands(pn->pn_kid, SuperElem_IncDec))
return false;
} else {
if (!emitElemOperands(pn->pn_kid, JSOP_GETELEM))
return false;
}
if (!emitElemOperands(pn->pn_kid, JSOP_GETELEM))
return false;
bool post;
JSOp binop = GetIncDecInfo(pn->getKind(), &post);
JSOp getOp;
if (isSuper) {
// There's no such thing as JSOP_DUP3, so we have to be creative.
// Note that pushing things again is no fewer JSOps.
if (!emitDupAt(2)) // KEY THIS OBJ KEY
return false;
if (!emitDupAt(2)) // KEY THIS OBJ KEY THIS
return false;
if (!emitDupAt(2)) // KEY THIS OBJ KEY THIS OBJ
return false;
getOp = JSOP_GETELEM_SUPER;
} else {
// We need to convert the key to an object id first, so that we do not do
// it inside both the GETELEM and the SETELEM. In the super case, this is
// done by emitSuperElemOperands.
// OBJ KEY*
if (!emit1(JSOP_TOID)) // OBJ KEY
return false;
if (!emit1(JSOP_DUP2)) // OBJ KEY OBJ KEY
return false;
getOp = JSOP_GETELEM;
}
if (!emitElemOpBase(getOp)) // OBJ KEY V
/*
* We need to convert the key to an object id first, so that we do not do
* it inside both the GETELEM and the SETELEM.
*/
// OBJ KEY*
if (!emit1(JSOP_TOID)) // OBJ KEY
return false;
if (!emit1(JSOP_POS)) // OBJ KEY N
if (!emit1(JSOP_DUP2)) // OBJ KEY OBJ KEY
return false;
if (post && !emit1(JSOP_DUP)) // OBJ KEY N? N
if (!emitElemOpBase(JSOP_GETELEM)) // OBJ KEY V
return false;
if (!emit1(JSOP_ONE)) // OBJ KEY N? N 1
if (!emit1(JSOP_POS)) // OBJ KEY N
return false;
if (post && !emit1(JSOP_DUP)) // OBJ KEY N? N
return false;
if (!emit1(JSOP_ONE)) // OBJ KEY N? N 1
return false;
if (!emit1(binop)) // OBJ KEY N? N+1
return false;
if (!emit1(binop)) // OBJ KEY N? N+1
if (post) {
if (isSuper) {
// We have one more value to rotate around, because of |this|
// on the stack
if (!emit2(JSOP_PICK, 4))
return false;
}
if (!emit2(JSOP_PICK, 3 + isSuper)) // KEY N N+1 OBJ
if (!emit2(JSOP_PICK, 3)) // KEY N N+1 OBJ
return false;
if (!emit2(JSOP_PICK, 3 + isSuper)) // N N+1 OBJ KEY
if (!emit2(JSOP_PICK, 3)) // N N+1 OBJ KEY
return false;
if (!emit2(JSOP_PICK, 2 + isSuper)) // N OBJ KEY N+1
if (!emit2(JSOP_PICK, 2)) // N OBJ KEY N+1
return false;
}
JSOp setOp = isSuper ? (sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER)
: (sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM);
if (!emitElemOpBase(setOp)) // N? N+1
JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
if (!emitElemOpBase(setOp)) // N? N+1
return false;
if (post && !emit1(JSOP_POP)) // RESULT
if (post && !emit1(JSOP_POP)) // RESULT
return false;
return true;
}
bool
BytecodeEmitter::emitSuperElemIncDec(ParseNode* pn)
{
MOZ_ASSERT(pn->pn_kid->isKind(PNK_SUPERELEM));
if (!emitSuperElemOperands(pn->pn_kid, SuperElem_IncDec))
return false;
bool post;
JSOp binop = GetIncDecInfo(pn->getKind(), &post);
// There's no such thing as JSOP_DUP3, so we have to be creative.
// Note that pushing things again is no fewer JSOps.
if (!emitDupAt(2)) // KEY THIS OBJ KEY
return false;
if (!emitDupAt(2)) // KEY THIS OBJ KEY THIS
return false;
if (!emitDupAt(2)) // KEY THIS OBJ KEY THIS OBJ
return false;
if (!emitElemOpBase(JSOP_GETELEM_SUPER)) // KEY THIS OBJ V
return false;
if (!emit1(JSOP_POS)) // KEY THIS OBJ N
return false;
if (post && !emit1(JSOP_DUP)) // KEY THIS OBJ N? N
return false;
if (!emit1(JSOP_ONE)) // KEY THIS OBJ N? N 1
return false;
if (!emit1(binop)) // KEY THIS OBJ N? N+1
return false;
if (post) {
if (!emit2(JSOP_PICK, 4)) // THIS OBJ N N+1 KEY
return false;
if (!emit2(JSOP_PICK, 4)) // OBJ N N+1 KEY THIS
return false;
if (!emit2(JSOP_PICK, 4)) // N N+1 KEY THIS OBJ
return false;
if (!emit2(JSOP_PICK, 3)) // N KEY THIS OBJ N+1
return false;
}
JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER;
if (!emitElemOpBase(setOp)) // N? N+1
return false;
if (post && !emit1(JSOP_POP)) // RESULT
return false;
return true;
}
bool
BytecodeEmitter::emitNumberOp(double dval)
{
@ -3728,20 +3783,24 @@ BytecodeEmitter::emitDestructuringLHS(ParseNode* target, VarEmitOption emitOptio
// In `[a.x] = [b]`, per spec, `b` is evaluated before `a`. Then we
// need a property set -- but the operands are on the stack in the
// wrong order for JSOP_SETPROP, so we have to add a JSOP_SWAP.
JSOp setOp;
if (target->as<PropertyAccess>().isSuper()) {
if (!emitSuperPropLHS())
return false;
if (!emit2(JSOP_PICK, 2))
return false;
setOp = sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER;
} else {
if (!emitTree(target->pn_expr))
return false;
if (!emit1(JSOP_SWAP))
return false;
setOp = sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
}
if (!emitTree(target->pn_expr))
return false;
if (!emit1(JSOP_SWAP))
return false;
JSOp setOp = sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
if (!emitAtomOp(target, setOp))
return false;
break;
}
case PNK_SUPERPROP:
{
// See comment above at PNK_DOT. Pick up the pushed value, to fix ordering.
if (!emitSuperPropLHS())
return false;
if (!emit2(JSOP_PICK, 2))
return false;
JSOp setOp = sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER;
if (!emitAtomOp(target, setOp))
return false;
break;
@ -3752,15 +3811,19 @@ BytecodeEmitter::emitDestructuringLHS(ParseNode* target, VarEmitOption emitOptio
// See the comment at `case PNK_DOT:` above. This case,
// `[a[x]] = [b]`, is handled much the same way. The JSOP_SWAP
// is emitted by emitElemOperands.
if (target->as<PropertyByValue>().isSuper()) {
JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER;
if (!emitSuperElemOp(target, setOp))
return false;
} else {
JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
if (!emitElemOp(target, setOp))
return false;
}
JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
if (!emitElemOp(target, setOp))
return false;
break;
}
case PNK_SUPERELEM:
{
// See comment above in the PNK_ELEM case. Just as there, the
// reordering is handled by emitSuperElemOp.
JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER;
if (!emitSuperElemOp(target, setOp))
return false;
break;
}
@ -4385,31 +4448,31 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs)
}
break;
case PNK_DOT:
if (lhs->as<PropertyAccess>().isSuper()) {
if (!emitSuperPropLHS())
return false;
offset += 2;
} else {
if (!emitTree(lhs->expr()))
return false;
offset += 1;
}
if (!emitTree(lhs->expr()))
return false;
offset++;
if (!makeAtomIndex(lhs->pn_atom, &atomIndex))
return false;
break;
case PNK_SUPERPROP:
if (!emitSuperPropLHS())
return false;
offset += 2;
if (!makeAtomIndex(lhs->pn_atom, &atomIndex))
return false;
break;
case PNK_ELEM:
MOZ_ASSERT(lhs->isArity(PN_BINARY));
if (lhs->as<PropertyByValue>().isSuper()) {
if (!emitSuperElemOperands(lhs))
return false;
offset += 3;
} else {
if (!emitTree(lhs->pn_left))
return false;
if (!emitTree(lhs->pn_right))
return false;
offset += 2;
}
if (!emitTree(lhs->pn_left))
return false;
if (!emitTree(lhs->pn_right))
return false;
offset += 2;
break;
case PNK_SUPERELEM:
if (!emitSuperElemOperands(lhs))
return false;
offset += 3;
break;
case PNK_ARRAY:
case PNK_OBJECT:
@ -4467,40 +4530,35 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs)
}
break;
case PNK_DOT: {
JSOp getOp;
if (lhs->as<PropertyAccess>().isSuper()) {
if (!emit1(JSOP_DUP2))
return false;
getOp = JSOP_GETPROP_SUPER;
} else {
if (!emit1(JSOP_DUP))
return false;
bool isLength = (lhs->pn_atom == cx->names().length);
getOp = isLength ? JSOP_LENGTH : JSOP_GETPROP;
}
if (!emitIndex32(getOp, atomIndex))
if (!emit1(JSOP_DUP))
return false;
bool isLength = (lhs->pn_atom == cx->names().length);
if (!emitIndex32(isLength ? JSOP_LENGTH : JSOP_GETPROP, atomIndex))
return false;
break;
}
case PNK_ELEM: {
JSOp elemOp;
if (lhs->as<PropertyByValue>().isSuper()) {
if (!emitDupAt(2))
return false;
if (!emitDupAt(2))
return false;
if (!emitDupAt(2))
return false;
elemOp = JSOP_GETELEM_SUPER;
} else {
if (!emit1(JSOP_DUP2))
return false;
elemOp = JSOP_GETELEM;
}
if (!emitElemOpBase(elemOp))
case PNK_SUPERPROP:
if (!emit1(JSOP_DUP2))
return false;
if (!emitIndex32(JSOP_GETPROP_SUPER, atomIndex))
return false;
break;
case PNK_ELEM:
if (!emit1(JSOP_DUP2))
return false;
if (!emitElemOpBase(JSOP_GETELEM))
return false;
break;
case PNK_SUPERELEM:
if (!emitDupAt(2))
return false;
if (!emitDupAt(2))
return false;
if (!emitDupAt(2))
return false;
if (!emitElemOpBase(JSOP_GETELEM_SUPER))
return false;
break;
}
case PNK_CALL:
/*
* We just emitted a JSOP_SETCALL (which will always throw) and
@ -4559,9 +4617,14 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs)
break;
case PNK_DOT:
{
JSOp setOp = lhs->as<PropertyAccess>().isSuper() ?
(sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER) :
(sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP);
JSOp setOp = sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
if (!emitIndexOp(setOp, atomIndex))
return false;
break;
}
case PNK_SUPERPROP:
{
JSOp setOp = sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER;
if (!emitIndexOp(setOp, atomIndex))
return false;
break;
@ -4572,9 +4635,14 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs)
break;
case PNK_ELEM:
{
JSOp setOp = lhs->as<PropertyByValue>().isSuper() ?
sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER :
sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
if (!emit1(setOp))
return false;
break;
}
case PNK_SUPERELEM:
{
JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER;
if (!emit1(setOp))
return false;
break;
@ -6450,20 +6518,26 @@ BytecodeEmitter::emitDeleteProperty(ParseNode* node)
ParseNode* propExpr = node->pn_kid;
MOZ_ASSERT(propExpr->isKind(PNK_DOT));
if (propExpr->as<PropertyAccess>().isSuper()) {
// Still have to calculate the base, even though we are are going
// to throw unconditionally, as calculating the base could also
// throw.
if (!emit1(JSOP_SUPERBASE))
return false;
return emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER);
}
JSOp delOp = sc->strict() ? JSOP_STRICTDELPROP : JSOP_DELPROP;
return emitPropOp(propExpr, delOp);
}
bool
BytecodeEmitter::emitDeleteSuperProperty(ParseNode* node)
{
MOZ_ASSERT(node->isKind(PNK_DELETESUPERPROP));
MOZ_ASSERT(node->isArity(PN_UNARY));
MOZ_ASSERT(node->pn_kid->isKind(PNK_SUPERPROP));
// Still have to calculate the base, even though we are are going
// to throw unconditionally, as calculating the base could also
// throw.
if (!emit1(JSOP_SUPERBASE))
return false;
return emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER);
}
bool
BytecodeEmitter::emitDeleteElement(ParseNode* node)
{
@ -6473,26 +6547,34 @@ BytecodeEmitter::emitDeleteElement(ParseNode* node)
ParseNode* elemExpr = node->pn_kid;
MOZ_ASSERT(elemExpr->isKind(PNK_ELEM));
if (elemExpr->as<PropertyByValue>().isSuper()) {
// Still have to calculate everything, even though we're gonna throw
// since it may have side effects
if (!emitTree(elemExpr->pn_right))
return false;
if (!emit1(JSOP_SUPERBASE))
return false;
if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER))
return false;
// Another wrinkle: Balance the stack from the emitter's point of view.
// Execution will not reach here, as the last bytecode threw.
return emit1(JSOP_POP);
}
JSOp delOp = sc->strict() ? JSOP_STRICTDELELEM : JSOP_DELELEM;
return emitElemOp(elemExpr, delOp);
}
bool
BytecodeEmitter::emitDeleteSuperElement(ParseNode* node)
{
MOZ_ASSERT(node->isKind(PNK_DELETESUPERELEM));
MOZ_ASSERT(node->isArity(PN_UNARY));
ParseNode* superElemExpr = node->pn_kid;
MOZ_ASSERT(superElemExpr->isKind(PNK_SUPERELEM));
// Still have to calculate everything, even though we're gonna throw
// since it may have side effects
MOZ_ASSERT(superElemExpr->isArity(PN_UNARY));
if (!emitTree(superElemExpr->pn_kid))
return false;
if (!emit1(JSOP_SUPERBASE))
return false;
if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER))
return false;
// Another wrinkle: Balance the stack from the emitter's point of view.
// Execution will not reach here, as the last bytecode threw.
return emit1(JSOP_POP);
}
bool
BytecodeEmitter::emitDeleteExpression(ParseNode* node)
{
@ -6652,26 +6734,24 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
return false;
break;
case PNK_DOT:
if (pn2->as<PropertyAccess>().isSuper()) {
if (!emitSuperPropOp(pn2, JSOP_GETPROP_SUPER, /* isCall = */ callop))
return false;
} else {
if (!emitPropOp(pn2, callop ? JSOP_CALLPROP : JSOP_GETPROP))
if (!emitPropOp(pn2, callop ? JSOP_CALLPROP : JSOP_GETPROP))
return false;
break;
case PNK_SUPERPROP:
if (!emitSuperPropOp(pn2, JSOP_GETPROP_SUPER, /* isCall = */ callop))
return false;
break;
case PNK_ELEM:
if (!emitElemOp(pn2, callop ? JSOP_CALLELEM : JSOP_GETELEM))
return false;
if (callop) {
if (!emit1(JSOP_SWAP))
return false;
}
break;
case PNK_ELEM:
if (pn2->as<PropertyByValue>().isSuper()) {
if (!emitSuperElemOp(pn2, JSOP_GETELEM_SUPER, /* isCall = */ callop))
return false;
} else {
if (!emitElemOp(pn2, callop ? JSOP_CALLELEM : JSOP_GETELEM))
return false;
if (callop) {
if (!emit1(JSOP_SWAP))
return false;
}
}
case PNK_SUPERELEM:
if (!emitSuperElemOp(pn2, JSOP_GETELEM_SUPER, /* isCall = */ callop))
return false;
break;
case PNK_FUNCTION:
/*
@ -6829,10 +6909,18 @@ BytecodeEmitter::emitIncOrDec(ParseNode* pn)
if (!emitPropIncDec(pn))
return false;
break;
case PNK_SUPERPROP:
if (!emitSuperPropIncDec(pn))
return false;
break;
case PNK_ELEM:
if (!emitElemIncDec(pn))
return false;
break;
case PNK_SUPERELEM:
if (!emitSuperElemIncDec(pn))
return false;
break;
case PNK_CALL:
MOZ_ASSERT(pn2->pn_xflags & PNX_SETCALL);
if (!emitTree(pn2))
@ -7796,32 +7884,38 @@ BytecodeEmitter::emitTree(ParseNode* pn)
ok = emitDeleteProperty(pn);
break;
case PNK_DELETESUPERPROP:
ok = emitDeleteSuperProperty(pn);
break;
case PNK_DELETEELEM:
ok = emitDeleteElement(pn);
break;
case PNK_DELETESUPERELEM:
ok = emitDeleteSuperElement(pn);
break;
case PNK_DELETEEXPR:
ok = emitDeleteExpression(pn);
break;
case PNK_DOT:
if (pn->as<PropertyAccess>().isSuper()) {
if (!emitSuperPropOp(pn, JSOP_GETPROP_SUPER))
return false;
} else {
if (!emitPropOp(pn, JSOP_GETPROP))
return false;
}
ok = emitPropOp(pn, JSOP_GETPROP);
break;
case PNK_SUPERPROP:
if (!emitSuperPropOp(pn, JSOP_GETPROP_SUPER))
return false;
break;
case PNK_ELEM:
if (pn->as<PropertyByValue>().isSuper()) {
if (!emitSuperElemOp(pn, JSOP_GETELEM_SUPER))
return false;
} else {
if (!emitElemOp(pn, JSOP_GETELEM))
return false;
}
ok = emitElemOp(pn, JSOP_GETELEM);
break;
case PNK_SUPERELEM:
if (!emitSuperElemOp(pn, JSOP_GETELEM_SUPER))
return false;
break;
case PNK_NEW:
@ -7994,9 +8088,6 @@ BytecodeEmitter::emitTree(ParseNode* pn)
return false;
break;
case PNK_POSHOLDER:
MOZ_ASSERT_UNREACHABLE("Should never try to emit PNK_POSHOLDER");
default:
MOZ_ASSERT(0);
}

View File

@ -554,7 +554,9 @@ struct BytecodeEmitter
bool emitDeleteName(ParseNode* pn);
bool emitDeleteProperty(ParseNode* pn);
bool emitDeleteSuperProperty(ParseNode* pn);
bool emitDeleteElement(ParseNode* pn);
bool emitDeleteSuperElement(ParseNode* pn);
bool emitDeleteExpression(ParseNode* pn);
// |op| must be JSOP_TYPEOF or JSOP_TYPEOFEXPR.
@ -609,9 +611,11 @@ struct BytecodeEmitter
bool emitClass(ParseNode* pn);
bool emitSuperPropLHS(bool isCall = false);
bool emitSuperPropOp(ParseNode* pn, JSOp op, bool isCall = false);
bool emitSuperPropIncDec(ParseNode* pn);
enum SuperElemOptions { SuperElem_Get, SuperElem_Set, SuperElem_Call, SuperElem_IncDec };
bool emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts = SuperElem_Get);
bool emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall = false);
bool emitSuperElemIncDec(ParseNode* pn);
};
} /* namespace frontend */

View File

@ -334,7 +334,9 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
case PNK_BITNOT:
case PNK_DELETENAME:
case PNK_DELETEPROP:
case PNK_DELETESUPERPROP:
case PNK_DELETEELEM:
case PNK_DELETESUPERELEM:
case PNK_DELETEEXPR:
case PNK_POS:
case PNK_NEG:
@ -412,8 +414,9 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
case PNK_CLASSMETHOD:
case PNK_CLASSMETHODLIST:
case PNK_CLASSNAMES:
case PNK_SUPERPROP:
case PNK_SUPERELEM:
case PNK_NEWTARGET:
case PNK_POSHOLDER:
MOZ_CRASH("ContainsHoistedDeclaration should have indicated false on "
"some parent node without recurring to test this node");
@ -629,9 +632,9 @@ static bool
FoldDeleteElement(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser,
bool inGenexpLambda)
{
MOZ_ASSERT(node->isKind(PNK_DELETEELEM));
MOZ_ASSERT(node->isKind(PNK_DELETEELEM) || node->isKind(PNK_DELETESUPERELEM));
MOZ_ASSERT(node->isArity(PN_UNARY));
MOZ_ASSERT(node->pn_kid->isKind(PNK_ELEM));
MOZ_ASSERT(node->pn_kid->isKind(PNK_ELEM) || node->pn_kid->isKind(PNK_SUPERELEM));
ParseNode*& expr = node->pn_kid;
if (!Fold(cx, &expr, parser, inGenexpLambda))
@ -643,9 +646,11 @@ FoldDeleteElement(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler
//
// In principle this also applies to |super["foo"] -> super.foo|,
// but we don't constant-fold |super["foo"]| yet.
MOZ_ASSERT(expr->isKind(PNK_ELEM) || expr->isKind(PNK_DOT));
if (expr->isKind(PNK_DOT))
node->setKind(PNK_DELETEPROP);
if (node->isKind(PNK_DELETEELEM)) {
MOZ_ASSERT(expr->isKind(PNK_ELEM) || expr->isKind(PNK_DOT));
if (expr->isKind(PNK_DOT))
node->setKind(PNK_DELETEPROP);
}
return true;
}
@ -654,9 +659,9 @@ static bool
FoldDeleteProperty(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser,
bool inGenexpLambda)
{
MOZ_ASSERT(node->isKind(PNK_DELETEPROP));
MOZ_ASSERT(node->isKind(PNK_DELETEPROP) || node->isKind(PNK_DELETESUPERPROP));
MOZ_ASSERT(node->isArity(PN_UNARY));
MOZ_ASSERT(node->pn_kid->isKind(PNK_DOT));
MOZ_ASSERT(node->pn_kid->isKind(PNK_DOT) || node->pn_kid->isKind(PNK_SUPERPROP));
ParseNode*& expr = node->pn_kid;
#ifdef DEBUG
@ -1704,6 +1709,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
ParseNode* pn = *pnp;
switch (pn->getKind()) {
case PNK_NEWTARGET:
case PNK_NOP:
case PNK_REGEXP:
case PNK_STRING:
@ -1720,8 +1726,8 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
case PNK_GENERATOR:
case PNK_EXPORT_BATCH_SPEC:
case PNK_OBJECT_PROPERTY_NAME:
case PNK_SUPERPROP:
case PNK_FRESHENBLOCK:
case PNK_POSHOLDER:
MOZ_ASSERT(pn->isArity(PN_NULLARY));
return true;
@ -1744,9 +1750,11 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
return FoldDeleteExpr(cx, pn, parser, inGenexpLambda);
case PNK_DELETEELEM:
case PNK_DELETESUPERELEM:
return FoldDeleteElement(cx, pn, parser, inGenexpLambda);
case PNK_DELETEPROP:
case PNK_DELETESUPERPROP:
return FoldDeleteProperty(cx, pn, parser, inGenexpLambda);
case PNK_CONDITIONAL:
@ -1774,6 +1782,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
case PNK_MUTATEPROTO:
case PNK_COMPUTED_NAME:
case PNK_SPREAD:
case PNK_SUPERELEM:
case PNK_EXPORT:
case PNK_EXPORT_DEFAULT:
case PNK_VOID:
@ -1909,12 +1918,6 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
return Fold(cx, &pn->pn_left, parser, inGenexpLambda) &&
Fold(cx, &pn->pn_right, parser, inGenexpLambda);
case PNK_NEWTARGET:
MOZ_ASSERT(pn->isArity(PN_BINARY));
MOZ_ASSERT(pn->pn_left->isKind(PNK_POSHOLDER));
MOZ_ASSERT(pn->pn_right->isKind(PNK_POSHOLDER));
return true;
case PNK_CLASSNAMES:
MOZ_ASSERT(pn->isArity(PN_BINARY));
if (ParseNode*& outerBinding = pn->pn_left) {

View File

@ -73,7 +73,9 @@ class FullParseHandler
typedef Definition* DefinitionNode;
bool isPropertyAccess(ParseNode* node) {
return node->isKind(PNK_DOT) || node->isKind(PNK_ELEM);
if (node->isKind(PNK_DOT) || node->isKind(PNK_ELEM))
return true;
return node->isKind(PNK_SUPERPROP) || node->isKind(PNK_SUPERELEM);
}
bool isFunctionCall(ParseNode* node) {
@ -223,9 +225,13 @@ class FullParseHandler
if (expr->isKind(PNK_DOT))
return newUnary(PNK_DELETEPROP, JSOP_NOP, begin, expr);
if (expr->isKind(PNK_SUPERPROP))
return newUnary(PNK_DELETESUPERPROP, JSOP_NOP, begin, expr);
if (expr->isKind(PNK_ELEM))
return newUnary(PNK_DELETEELEM, JSOP_NOP, begin, expr);
if (expr->isKind(PNK_SUPERELEM))
return newUnary(PNK_DELETESUPERELEM, JSOP_NOP, begin, expr);
return newUnary(PNK_DELETEEXPR, JSOP_NOP, begin, expr);
}
@ -340,20 +346,14 @@ class FullParseHandler
ParseNode* newClassNames(ParseNode* outer, ParseNode* inner, const TokenPos& pos) {
return new_<ClassNames>(outer, inner, pos);
}
ParseNode* newNewTarget(ParseNode* newHolder, ParseNode* targetHolder) {
return new_<BinaryNode>(PNK_NEWTARGET, JSOP_NOP, newHolder, targetHolder);
ParseNode* newSuperProperty(JSAtom* atom, const TokenPos& pos) {
return new_<SuperProperty>(atom, pos);
}
ParseNode* newPosHolder(const TokenPos& pos) {
return new_<NullaryNode>(PNK_POSHOLDER, pos);
ParseNode* newSuperElement(ParseNode* expr, const TokenPos& pos) {
return new_<SuperElement>(expr, pos);
}
ParseNode* newSuperBase(const TokenPos& pos, ExclusiveContext* cx) {
ParseNode* node = newPosHolder(pos);
#ifdef DEBUG
// Set the atom for assertion purposes
if (node)
node->pn_atom = cx->names().super;
#endif
return node;
ParseNode* newNewTarget(const TokenPos& pos) {
return new_<NullaryNode>(PNK_NEWTARGET, pos);
}
bool addPrototypeMutation(ParseNode* literal, uint32_t begin, ParseNode* expr) {
@ -711,11 +711,6 @@ class FullParseHandler
(kind == PNK_SEMI && !node->pn_kid);
}
bool isSuperBase(ParseNode* node, ExclusiveContext* cx) {
MOZ_ASSERT_IF(node->isKind(PNK_POSHOLDER), node->pn_atom == cx->names().super);
return node->isKind(PNK_POSHOLDER);
}
inline bool finishInitializerAssignment(ParseNode* pn, ParseNode* init, JSOp op);
void setBeginPosition(ParseNode* pn, ParseNode* oth) {

View File

@ -375,7 +375,9 @@ class NameResolver
case PNK_DEBUGGER:
case PNK_EXPORT_BATCH_SPEC:
case PNK_FRESHENBLOCK:
case PNK_SUPERPROP:
case PNK_OBJECT_PROPERTY_NAME:
case PNK_NEWTARGET:
MOZ_ASSERT(cur->isArity(PN_NULLARY));
break;
@ -385,12 +387,6 @@ class NameResolver
MOZ_ASSERT(!cur->pn_kid->maybeExpr());
break;
case PNK_NEWTARGET:
MOZ_ASSERT(cur->isArity(PN_BINARY));
MOZ_ASSERT(cur->pn_left->isKind(PNK_POSHOLDER));
MOZ_ASSERT(cur->pn_right->isKind(PNK_POSHOLDER));
break;
// Nodes with a single non-null child requiring name resolution.
case PNK_TYPEOFEXPR:
case PNK_VOID:
@ -399,7 +395,9 @@ class NameResolver
case PNK_THROW:
case PNK_DELETENAME:
case PNK_DELETEPROP:
case PNK_DELETESUPERPROP:
case PNK_DELETEELEM:
case PNK_DELETESUPERELEM:
case PNK_DELETEEXPR:
case PNK_NEG:
case PNK_POS:
@ -411,6 +409,7 @@ class NameResolver
case PNK_ARRAYPUSH:
case PNK_SPREAD:
case PNK_MUTATEPROTO:
case PNK_SUPERELEM:
case PNK_EXPORT:
case PNK_EXPORT_DEFAULT:
MOZ_ASSERT(cur->isArity(PN_UNARY));
@ -441,6 +440,7 @@ class NameResolver
case PNK_DIVASSIGN:
case PNK_MODASSIGN:
case PNK_POWASSIGN:
case PNK_ELEM:
case PNK_COLON:
case PNK_CASE:
case PNK_SHORTHAND:
@ -457,14 +457,6 @@ class NameResolver
return false;
break;
case PNK_ELEM:
MOZ_ASSERT(cur->isArity(PN_BINARY));
if (!cur->as<PropertyByValue>().isSuper() && !resolve(cur->pn_left, prefix))
return false;
if (!resolve(cur->pn_right, prefix))
return false;
break;
case PNK_WITH:
MOZ_ASSERT(cur->isArity(PN_BINARY_OBJ));
if (!resolve(cur->pn_left, prefix))
@ -760,17 +752,8 @@ class NameResolver
break;
}
case PNK_DOT:
MOZ_ASSERT(cur->isArity(PN_NAME));
// Super prop nodes do not have a meaningful LHS
if (cur->as<PropertyAccess>().isSuper())
break;
if (!resolve(cur->expr(), prefix))
return false;
break;
case PNK_LABEL:
case PNK_DOT:
MOZ_ASSERT(cur->isArity(PN_NAME));
if (!resolve(cur->expr(), prefix))
return false;
@ -796,7 +779,6 @@ class NameResolver
case PNK_EXPORT_SPEC: // by PNK_EXPORT_SPEC_LIST
case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE
case PNK_CLASSNAMES: // by PNK_CLASS
case PNK_POSHOLDER: // by PNK_NEWTARGET, PNK_DOT
MOZ_CRASH("should have been handled by a parent node");
case PNK_LIMIT: // invalid sentinel value

View File

@ -214,7 +214,8 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
case PNK_EXPORT_BATCH_SPEC:
case PNK_OBJECT_PROPERTY_NAME:
case PNK_FRESHENBLOCK:
case PNK_POSHOLDER:
case PNK_SUPERPROP:
case PNK_NEWTARGET:
MOZ_ASSERT(pn->isArity(PN_NULLARY));
MOZ_ASSERT(!pn->isUsed(), "handle non-trivial cases separately");
MOZ_ASSERT(!pn->isDefn(), "handle non-trivial cases separately");
@ -229,7 +230,9 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
case PNK_THROW:
case PNK_DELETENAME:
case PNK_DELETEPROP:
case PNK_DELETESUPERPROP:
case PNK_DELETEELEM:
case PNK_DELETESUPERELEM:
case PNK_DELETEEXPR:
case PNK_POS:
case PNK_NEG:
@ -243,6 +246,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
case PNK_MUTATEPROTO:
case PNK_EXPORT:
case PNK_EXPORT_DEFAULT:
case PNK_SUPERELEM:
return PushUnaryNodeChild(pn, stack);
// Nodes with a single nullable child.
@ -281,7 +285,6 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
case PNK_SWITCH:
case PNK_LETBLOCK:
case PNK_CLASSMETHOD:
case PNK_NEWTARGET:
case PNK_FOR: {
MOZ_ASSERT(pn->isArity(PN_BINARY));
stack->push(pn->pn_left);
@ -1103,10 +1106,7 @@ NameNode::dump(int indent)
if (isKind(PNK_DOT)) {
fputc(' ', stderr);
if (as<PropertyAccess>().isSuper())
fprintf(stderr, "super");
else
DumpParseTree(expr(), indent + 2);
DumpParseTree(expr(), indent + 2);
fputc(')', stderr);
}
return;

View File

@ -138,7 +138,9 @@ class PackedScopeCoordinate
/* Delete operations. These must be sequential. */ \
F(DELETENAME) \
F(DELETEPROP) \
F(DELETESUPERPROP) \
F(DELETEELEM) \
F(DELETESUPERELEM) \
F(DELETEEXPR) \
F(TRY) \
F(CATCH) \
@ -174,8 +176,9 @@ class PackedScopeCoordinate
F(CLASSMETHOD) \
F(CLASSMETHODLIST) \
F(CLASSNAMES) \
F(SUPERPROP) \
F(SUPERELEM) \
F(NEWTARGET) \
F(POSHOLDER) \
\
/* Unary operators. */ \
F(TYPEOFNAME) \
@ -429,6 +432,7 @@ IsDeleteKind(ParseNodeKind kind)
* ctor is a MEMBER expr
* PNK_DELETENAME unary pn_kid: PNK_NAME expr
* PNK_DELETEPROP unary pn_kid: PNK_DOT expr
* PNK_DELETESUPERPROP unary pn_kid: PNK_SUPERPROP expr
* PNK_DELETEELEM unary pn_kid: PNK_ELEM expr
* PNK_DELETESUPERELEM unary pn_kid: PNK_SUPERELEM expr
* PNK_DELETEEXPR unary pn_kid: MEMBER expr that's evaluated, then the
@ -1319,11 +1323,6 @@ class PropertyAccess : public ParseNode
PropertyName& name() const {
return *pn_u.name.atom->asPropertyName();
}
bool isSuper() const {
// PNK_POSHOLDER cannot result from any expression syntax.
return expression().isKind(PNK_POSHOLDER);
}
};
class PropertyByValue : public ParseNode
@ -1335,17 +1334,6 @@ class PropertyByValue : public ParseNode
pn_u.binary.left = lhs;
pn_u.binary.right = propExpr;
}
static bool test(const ParseNode& node) {
bool match = node.isKind(PNK_ELEM);
MOZ_ASSERT_IF(match, node.isArity(PN_BINARY));
return match;
}
bool isSuper() const {
// Like PropertyAccess above, PNK_POSHOLDER is "good enough".
return pn_left->isKind(PNK_POSHOLDER);
}
};
/*
@ -1458,6 +1446,38 @@ struct ClassNode : public TernaryNode {
}
};
struct SuperProperty : public NullaryNode {
SuperProperty(JSAtom* atom, const TokenPos& pos)
: NullaryNode(PNK_SUPERPROP, JSOP_NOP, pos, atom)
{ }
static bool test(const ParseNode& node) {
bool match = node.isKind(PNK_SUPERPROP);
MOZ_ASSERT_IF(match, node.isArity(PN_NULLARY));
return match;
}
JSAtom* propName() const {
return pn_atom;
}
};
struct SuperElement : public UnaryNode {
SuperElement(ParseNode* expr, const TokenPos& pos)
: UnaryNode(PNK_SUPERELEM, JSOP_NOP, pos, expr)
{ }
static bool test(const ParseNode& node) {
bool match = node.isKind(PNK_SUPERELEM);
MOZ_ASSERT_IF(match, node.isArity(PN_UNARY));
return match;
}
ParseNode* expr() const {
return pn_kid;
}
};
#ifdef DEBUG
void DumpParseTree(ParseNode* pn, int indent = 0);
#endif

View File

@ -4965,7 +4965,9 @@ Parser<FullParseHandler>::isValidForStatementLHS(ParseNode* pn1, JSVersion versi
case PNK_ARRAY:
case PNK_CALL:
case PNK_DOT:
case PNK_SUPERPROP:
case PNK_ELEM:
case PNK_SUPERELEM:
case PNK_NAME:
case PNK_OBJECT:
return true;
@ -8248,6 +8250,9 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TokenKind tt, bool
JS_CHECK_RECURSION(context, return null());
bool isSuper = false;
uint32_t superBegin = pos().begin;
/* Check for new expression first. */
if (tt == TOK_NEW) {
uint32_t newBegin = pos().begin;
@ -8282,17 +8287,14 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TokenKind tt, bool
}
}
} else if (tt == TOK_SUPER) {
lhs = handler.newSuperBase(pos(), context);
if (!lhs)
return null();
lhs = null();
isSuper = true;
} else {
lhs = primaryExpr(yieldHandling, tt, invoked);
if (!lhs)
return null();
}
MOZ_ASSERT_IF(handler.isSuperBase(lhs, context), tokenStream.isCurrentTokenType(TOK_SUPER));
while (true) {
if (!tokenStream.getToken(&tt))
return null();
@ -8305,11 +8307,16 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TokenKind tt, bool
return null();
if (tt == TOK_NAME) {
PropertyName* field = tokenStream.currentName();
if (handler.isSuperBase(lhs, context) && !checkAndMarkSuperScope()) {
report(ParseError, false, null(), JSMSG_BAD_SUPERPROP, "property");
return null();
if (isSuper) {
isSuper = false;
if (!checkAndMarkSuperScope()) {
report(ParseError, false, null(), JSMSG_BAD_SUPERPROP, "property");
return null();
}
nextMember = handler.newSuperProperty(field, TokenPos(superBegin, pos().end));
} else {
nextMember = handler.newPropertyAccess(lhs, field, pos().end);
}
nextMember = handler.newPropertyAccess(lhs, field, pos().end);
if (!nextMember)
return null();
} else {
@ -8323,18 +8330,23 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TokenKind tt, bool
MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
if (handler.isSuperBase(lhs, context) && !checkAndMarkSuperScope()) {
if (isSuper) {
isSuper = false;
if (!checkAndMarkSuperScope()) {
report(ParseError, false, null(), JSMSG_BAD_SUPERPROP, "member");
return null();
}
nextMember = handler.newSuperElement(propExpr, TokenPos(superBegin, pos().end));
} else {
nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end);
}
nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end);
if (!nextMember)
return null();
} else if ((allowCallSyntax && tt == TOK_LP) ||
tt == TOK_TEMPLATE_HEAD ||
tt == TOK_NO_SUBS_TEMPLATE)
{
if (handler.isSuperBase(lhs, context)) {
if (isSuper) {
// For now...
report(ParseError, false, null(), JSMSG_BAD_SUPER);
return null();
@ -8398,16 +8410,18 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TokenKind tt, bool
}
handler.setOp(nextMember, op);
} else {
if (isSuper) {
report(ParseError, false, null(), JSMSG_BAD_SUPER);
return null();
}
tokenStream.ungetToken();
if (handler.isSuperBase(lhs, context))
break;
return lhs;
}
lhs = nextMember;
}
if (handler.isSuperBase(lhs, context)) {
if (isSuper) {
report(ParseError, false, null(), JSMSG_BAD_SUPER);
return null();
}
@ -8935,13 +8949,8 @@ Parser<ParseHandler>::tryNewTarget(Node &newTarget)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_NEW));
newTarget = null();
Node newHolder = handler.newPosHolder(pos());
if (!newHolder)
return false;
uint32_t begin = pos().begin;
newTarget = null();
// |new| expects to look for an operand, so we will honor that.
TokenKind next;
@ -8966,11 +8975,7 @@ Parser<ParseHandler>::tryNewTarget(Node &newTarget)
return false;
}
Node targetHolder = handler.newPosHolder(pos());
if (!targetHolder)
return false;
newTarget = handler.newNewTarget(newHolder, targetHolder);
newTarget = handler.newNewTarget(TokenPos(begin, pos().end));
return !!newTarget;
}

View File

@ -47,6 +47,9 @@ class SyntaxParseHandler
NodeThrow,
NodeEmptyStatement,
NodeSuperProperty,
NodeSuperElement,
// This is needed for proper assignment-target handling. ES6 formally
// requires function calls *not* pass IsValidSimpleAssignmentTarget,
// but at last check there were still sites with |f() = 5| and similar
@ -129,16 +132,13 @@ class SyntaxParseHandler
// warnings, and parsing with that option disables syntax parsing. But
// it seems best to be consistent, and perhaps the syntax parser will
// eventually enforce extraWarnings and will require this then.)
NodeUnparenthesizedAssignment,
// This node is necessary to determine if the LHS of a property access is
// super related.
NodeSuperBase
NodeUnparenthesizedAssignment
};
typedef Definition::Kind DefinitionNode;
bool isPropertyAccess(Node node) {
return node == NodeDottedProperty || node == NodeElement;
return node == NodeDottedProperty || node == NodeElement ||
node == NodeSuperProperty || node == NodeSuperElement;
}
bool isFunctionCall(Node node) {
@ -274,9 +274,14 @@ class SyntaxParseHandler
Node newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; }
Node newClassMethodList(uint32_t begin) { return NodeGeneric; }
Node newNewTarget(Node newHolder, Node targetHolder) { return NodeGeneric; }
Node newPosHolder(const TokenPos& pos) { return NodeGeneric; }
Node newSuperBase(const TokenPos& pos, ExclusiveContext* cx) { return NodeSuperBase; }
Node newSuperProperty(PropertyName* prop, const TokenPos& pos) {
return NodeSuperProperty;
}
Node newSuperElement(Node expr, const TokenPos& pos) {
return NodeSuperElement;
}
Node newNewTarget(const TokenPos& pos) { return NodeGeneric; }
bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; }
bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; }
@ -431,12 +436,6 @@ class SyntaxParseHandler
pn == NodeEmptyStatement;
}
bool isSuperBase(Node pn, ExclusiveContext* cx) {
// While NodePosHolder is used in other places than just as super-base,
// it is unique enough for our purposes.
return pn == NodeSuperBase;
}
void setOp(Node pn, JSOp op) {}
void setBlockId(Node pn, unsigned blockid) {}
void setFlag(Node pn, unsigned flag) {}

View File

@ -38,7 +38,7 @@ functionDeclaration = (id, params, body) => Pattern({
});
classDeclaration = (name) => Pattern({
type: "ClassStatement",
id: name
name: name
});
variableDeclaration = (decls) => Pattern({
type: "VariableDeclaration",

View File

@ -38,8 +38,7 @@ ASTDEF(AST_COMP_EXPR, "ComprehensionExpression", "comprehensi
ASTDEF(AST_GENERATOR_EXPR, "GeneratorExpression", "generatorExpression")
ASTDEF(AST_YIELD_EXPR, "YieldExpression", "yieldExpression")
ASTDEF(AST_CLASS_EXPR, "ClassExpression", "classExpression")
ASTDEF(AST_METAPROPERTY, "MetaProperty", "metaProperty")
ASTDEF(AST_SUPER, "Super", "super")
ASTDEF(AST_NEWTARGET_EXPR, "NewTargetExpression", "newTargetExpression")
ASTDEF(AST_EMPTY_STMT, "EmptyStatement", "emptyStatement")
ASTDEF(AST_BLOCK_STMT, "BlockStatement", "blockStatement")

View File

@ -76,6 +76,7 @@ const char js_import_str[] = "import";
const char js_in_str[] = "in";
const char js_instanceof_str[] = "instanceof";
const char js_interface_str[] = "interface";
const char js_new_str[] = "new";
const char js_package_str[] = "package";
const char js_private_str[] = "private";
const char js_protected_str[] = "protected";

View File

@ -176,6 +176,7 @@ extern const char js_import_str[];
extern const char js_in_str[];
extern const char js_instanceof_str[];
extern const char js_interface_str[];
extern const char js_new_str[];
extern const char js_package_str[];
extern const char js_private_str[];
extern const char js_protected_str[];

View File

@ -7,15 +7,11 @@ class testNonExistent {
super["prop"]();
}
}
// Should fold to super.prop
assertThrownErrorContains(() => new testNonExistent(), 'super.prop');
assertThrownErrorContains(() => new testNonExistent(), 'super["prop"]');
var ol = { testNonExistent() { super.prop(); } };
assertThrownErrorContains(() => ol.testNonExistent(), "super.prop");
var olElem = { testNonExistent() { var prop = "prop"; super[prop](); } };
assertThrownErrorContains(() => olElem.testNonExistent(), "super[prop]");
`;
if (classesEnabled())

View File

@ -124,7 +124,7 @@ function letStmt(head, body) {
}
function superProp(id) {
return dotExpr(Pattern({ type: "Super" }), id);
return dotExpr(ident("super"), id);
}
function superElem(id) {
return memExpr(ident("super"), id);
@ -132,14 +132,14 @@ function superElem(id) {
function classStmt(id, heritage, body) {
return Pattern({ type: "ClassStatement",
id: id,
superClass: heritage,
name: id,
heritage: heritage,
body: body});
}
function classExpr(id, heritage, body) {
return Pattern({ type: "ClassExpression",
id: id,
superClass: heritage,
name: id,
heritage: heritage,
body: body});
}
function classMethod(id, body, kind, static) {
@ -170,15 +170,9 @@ function arrowExpr(args, body) {
body: body });
}
function metaProperty(meta, property) {
return Pattern({ type: "MetaProperty",
meta: meta,
property: property });
}
function newTarget() {
return metaProperty(ident("new"), ident("target"));
return Pattern({ type: "NewTargetExpression" });
}
function unExpr(op, arg) {
return Pattern({ type: "UnaryExpression", operator: op, argument: arg });
}

View File

@ -150,7 +150,6 @@
macro(multiline, multiline, "multiline") \
macro(name, name, "name") \
macro(NaN, NaN, "NaN") \
macro(new, new_, "new") \
macro(next, next, "next") \
macro(NFC, NFC, "NFC") \
macro(NFD, NFD, "NFD") \

View File

@ -769,7 +769,7 @@
* Stack: callee, this, args[0], ..., args[argc-1], newTarget => rval
* nuses: (argc+3)
*/ \
macro(JSOP_NEW, 82, "new", NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
macro(JSOP_NEW, 82, js_new_str, NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
/*
* Pushes newly created object onto the stack with provided [[Prototype]].
*