Bug 1168992 - Part 4: Convert PNK_SUPERELEM to PNK_ELEM and fix reflection of super[elem]. (r=Waldo)

This commit is contained in:
Eric Faust 2015-09-02 15:09:06 -07:00
parent f76d34de05
commit 06d506b806
12 changed files with 167 additions and 247 deletions

View File

@ -3082,7 +3082,6 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
case PNK_DELETENAME:
case PNK_DELETEPROP:
case PNK_DELETEELEM:
case PNK_DELETESUPERELEM:
case PNK_DELETEEXPR:
case PNK_TYPEOFNAME:
case PNK_TYPEOFEXPR:
@ -3165,22 +3164,19 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
RootedValue left(cx), right(cx);
return expression(pn->pn_left, &left) &&
expression(pn->pn_right, &right) &&
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) &&
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);

View File

@ -2013,7 +2013,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_DELETENAME:
case PNK_DELETEPROP:
case PNK_DELETEELEM:
case PNK_DELETESUPERELEM:
MOZ_ASSERT(pn->isArity(PN_UNARY));
*answer = true;
return true;
@ -2121,12 +2120,6 @@ 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:
@ -2761,14 +2754,14 @@ BytecodeEmitter::emitElemOperands(ParseNode* pn, JSOp op)
bool
BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts)
{
MOZ_ASSERT(pn->isKind(PNK_SUPERELEM));
MOZ_ASSERT(pn->isKind(PNK_ELEM) && pn->as<PropertyByValue>().isSuper());
// 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_kid))
if (!emitTree(pn->pn_right))
return false;
// We need to convert the key to an object id first, so that we do not do
@ -2838,99 +2831,77 @@ BytecodeEmitter::emitElemIncDec(ParseNode* pn)
{
MOZ_ASSERT(pn->pn_kid->isKind(PNK_ELEM));
if (!emitElemOperands(pn->pn_kid, JSOP_GETELEM))
return false;
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;
}
bool post;
JSOp binop = GetIncDecInfo(pn->getKind(), &post);
/*
* 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
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
return false;
if (!emit1(JSOP_DUP2)) // OBJ KEY OBJ KEY
if (!emit1(JSOP_POS)) // OBJ KEY N
return false;
if (!emitElemOpBase(JSOP_GETELEM)) // OBJ KEY V
if (post && !emit1(JSOP_DUP)) // OBJ KEY N? N
return false;
if (!emit1(JSOP_POS)) // OBJ KEY N
if (!emit1(JSOP_ONE)) // OBJ KEY N? N 1
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
if (!emit1(binop)) // OBJ KEY N? N+1
return false;
if (post) {
if (!emit2(JSOP_PICK, 3)) // KEY N N+1 OBJ
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
return false;
if (!emit2(JSOP_PICK, 3)) // N N+1 OBJ KEY
if (!emit2(JSOP_PICK, 3 + isSuper)) // N N+1 OBJ KEY
return false;
if (!emit2(JSOP_PICK, 2)) // N OBJ KEY N+1
if (!emit2(JSOP_PICK, 2 + isSuper)) // N OBJ KEY N+1
return false;
}
JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
if (!emitElemOpBase(setOp)) // N? N+1
JSOp setOp = isSuper ? (sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER)
: (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)
{
@ -3782,19 +3753,15 @@ 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.
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;
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;
}
break;
}
@ -4433,16 +4400,17 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs)
break;
case PNK_ELEM:
MOZ_ASSERT(lhs->isArity(PN_BINARY));
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;
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;
}
break;
case PNK_ARRAY:
case PNK_OBJECT:
@ -4515,22 +4483,25 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs)
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))
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))
return false;
break;
}
case PNK_CALL:
/*
* We just emitted a JSOP_SETCALL (which will always throw) and
@ -4602,14 +4573,9 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs)
break;
case PNK_ELEM:
{
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;
JSOp setOp = lhs->as<PropertyByValue>().isSuper() ?
sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER :
sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
if (!emit1(setOp))
return false;
break;
@ -6508,34 +6474,26 @@ 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)
{
@ -6704,17 +6662,18 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
}
break;
case PNK_ELEM:
if (!emitElemOp(pn2, callop ? JSOP_CALLELEM : JSOP_GETELEM))
return false;
if (callop) {
if (!emit1(JSOP_SWAP))
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;
}
}
break;
case PNK_SUPERELEM:
if (!emitSuperElemOp(pn2, JSOP_GETELEM_SUPER, /* isCall = */ callop))
return false;
break;
case PNK_FUNCTION:
/*
* Top level lambdas which are immediately invoked should be
@ -6875,10 +6834,6 @@ BytecodeEmitter::emitIncOrDec(ParseNode* pn)
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))
@ -7846,10 +7801,6 @@ BytecodeEmitter::emitTree(ParseNode* pn)
ok = emitDeleteElement(pn);
break;
case PNK_DELETESUPERELEM:
ok = emitDeleteSuperElement(pn);
break;
case PNK_DELETEEXPR:
ok = emitDeleteExpression(pn);
break;
@ -7865,12 +7816,13 @@ BytecodeEmitter::emitTree(ParseNode* pn)
break;
case PNK_ELEM:
ok = emitElemOp(pn, JSOP_GETELEM);
break;
case PNK_SUPERELEM:
if (!emitSuperElemOp(pn, JSOP_GETELEM_SUPER))
return false;
if (pn->as<PropertyByValue>().isSuper()) {
if (!emitSuperElemOp(pn, JSOP_GETELEM_SUPER))
return false;
} else {
if (!emitElemOp(pn, JSOP_GETELEM))
return false;
}
break;
case PNK_NEW:

View File

@ -555,7 +555,6 @@ struct BytecodeEmitter
bool emitDeleteName(ParseNode* pn);
bool emitDeleteProperty(ParseNode* pn);
bool emitDeleteElement(ParseNode* pn);
bool emitDeleteSuperElement(ParseNode* pn);
bool emitDeleteExpression(ParseNode* pn);
// |op| must be JSOP_TYPEOF or JSOP_TYPEOFEXPR.
@ -613,7 +612,6 @@ struct BytecodeEmitter
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

@ -335,7 +335,6 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
case PNK_DELETENAME:
case PNK_DELETEPROP:
case PNK_DELETEELEM:
case PNK_DELETESUPERELEM:
case PNK_DELETEEXPR:
case PNK_POS:
case PNK_NEG:
@ -413,7 +412,6 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
case PNK_CLASSMETHOD:
case PNK_CLASSMETHODLIST:
case PNK_CLASSNAMES:
case PNK_SUPERELEM:
case PNK_NEWTARGET:
case PNK_POSHOLDER:
MOZ_CRASH("ContainsHoistedDeclaration should have indicated false on "
@ -631,9 +629,9 @@ static bool
FoldDeleteElement(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser,
bool inGenexpLambda)
{
MOZ_ASSERT(node->isKind(PNK_DELETEELEM) || node->isKind(PNK_DELETESUPERELEM));
MOZ_ASSERT(node->isKind(PNK_DELETEELEM));
MOZ_ASSERT(node->isArity(PN_UNARY));
MOZ_ASSERT(node->pn_kid->isKind(PNK_ELEM) || node->pn_kid->isKind(PNK_SUPERELEM));
MOZ_ASSERT(node->pn_kid->isKind(PNK_ELEM));
ParseNode*& expr = node->pn_kid;
if (!Fold(cx, &expr, parser, inGenexpLambda))
@ -645,11 +643,9 @@ 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.
if (node->isKind(PNK_DELETEELEM)) {
MOZ_ASSERT(expr->isKind(PNK_ELEM) || expr->isKind(PNK_DOT));
if (expr->isKind(PNK_DOT))
node->setKind(PNK_DELETEPROP);
}
MOZ_ASSERT(expr->isKind(PNK_ELEM) || expr->isKind(PNK_DOT));
if (expr->isKind(PNK_DOT))
node->setKind(PNK_DELETEPROP);
return true;
}
@ -1748,7 +1744,6 @@ 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:
@ -1779,7 +1774,6 @@ 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:

View File

@ -73,9 +73,7 @@ class FullParseHandler
typedef Definition* DefinitionNode;
bool isPropertyAccess(ParseNode* node) {
if (node->isKind(PNK_DOT) || node->isKind(PNK_ELEM))
return true;
return node->isKind(PNK_SUPERELEM);
return node->isKind(PNK_DOT) || node->isKind(PNK_ELEM);
}
bool isFunctionCall(ParseNode* node) {
@ -228,8 +226,6 @@ class FullParseHandler
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);
}
@ -344,9 +340,6 @@ class FullParseHandler
ParseNode* newClassNames(ParseNode* outer, ParseNode* inner, const TokenPos& pos) {
return new_<ClassNames>(outer, inner, pos);
}
ParseNode* newSuperElement(ParseNode* expr, const TokenPos& pos) {
return new_<SuperElement>(expr, pos);
}
ParseNode* newNewTarget(ParseNode* newHolder, ParseNode* targetHolder) {
return new_<BinaryNode>(PNK_NEWTARGET, JSOP_NOP, newHolder, targetHolder);
}

View File

@ -400,7 +400,6 @@ class NameResolver
case PNK_DELETENAME:
case PNK_DELETEPROP:
case PNK_DELETEELEM:
case PNK_DELETESUPERELEM:
case PNK_DELETEEXPR:
case PNK_NEG:
case PNK_POS:
@ -412,7 +411,6 @@ 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));
@ -443,7 +441,6 @@ class NameResolver
case PNK_DIVASSIGN:
case PNK_MODASSIGN:
case PNK_POWASSIGN:
case PNK_ELEM:
case PNK_COLON:
case PNK_CASE:
case PNK_SHORTHAND:
@ -460,6 +457,14 @@ 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))

View File

@ -230,7 +230,6 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
case PNK_DELETENAME:
case PNK_DELETEPROP:
case PNK_DELETEELEM:
case PNK_DELETESUPERELEM:
case PNK_DELETEEXPR:
case PNK_POS:
case PNK_NEG:
@ -244,7 +243,6 @@ 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.

View File

@ -139,7 +139,6 @@ class PackedScopeCoordinate
F(DELETENAME) \
F(DELETEPROP) \
F(DELETEELEM) \
F(DELETESUPERELEM) \
F(DELETEEXPR) \
F(TRY) \
F(CATCH) \
@ -175,7 +174,6 @@ class PackedScopeCoordinate
F(CLASSMETHOD) \
F(CLASSMETHODLIST) \
F(CLASSNAMES) \
F(SUPERELEM) \
F(NEWTARGET) \
F(POSHOLDER) \
\
@ -1337,6 +1335,17 @@ 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);
}
};
/*
@ -1449,22 +1458,6 @@ struct ClassNode : public TernaryNode {
}
};
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

@ -4966,7 +4966,6 @@ Parser<FullParseHandler>::isValidForStatementLHS(ParseNode* pn1, JSVersion versi
case PNK_CALL:
case PNK_DOT:
case PNK_ELEM:
case PNK_SUPERELEM:
case PNK_NAME:
case PNK_OBJECT:
return true;
@ -8249,8 +8248,6 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TokenKind tt, bool
JS_CHECK_RECURSION(context, return null());
uint32_t superBegin = pos().begin;
/* Check for new expression first. */
if (tt == TOK_NEW) {
uint32_t newBegin = pos().begin;
@ -8326,15 +8323,11 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TokenKind tt, bool
MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
if (handler.isSuperBase(lhs, context)) {
if (!checkAndMarkSuperScope()) {
if (handler.isSuperBase(lhs, context) && !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) ||

View File

@ -47,8 +47,6 @@ class SyntaxParseHandler
NodeThrow,
NodeEmptyStatement,
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
@ -140,8 +138,7 @@ class SyntaxParseHandler
typedef Definition::Kind DefinitionNode;
bool isPropertyAccess(Node node) {
return node == NodeDottedProperty || node == NodeElement ||
node == NodeSuperElement;
return node == NodeDottedProperty || node == NodeElement;
}
bool isFunctionCall(Node node) {
@ -277,9 +274,6 @@ class SyntaxParseHandler
Node newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; }
Node newClassMethodList(uint32_t begin) { return NodeGeneric; }
Node newSuperElement(Node expr, const TokenPos& pos) {
return NodeSuperElement;
}
Node newNewTarget(Node newHolder, Node targetHolder) { return NodeGeneric; }
Node newPosHolder(const TokenPos& pos) { return NodeGeneric; }
Node newSuperBase(const TokenPos& pos, ExclusiveContext* cx) { return NodeSuperBase; }

View File

@ -7,11 +7,15 @@ class testNonExistent {
super["prop"]();
}
}
assertThrownErrorContains(() => new testNonExistent(), 'super["prop"]');
// Should fold to 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

@ -127,7 +127,7 @@ function superProp(id) {
return dotExpr(Pattern({ type: "Super" }), id);
}
function superElem(id) {
return memExpr(ident("super"), id);
return memExpr(Pattern({ type: "Super" }), id);
}
function classStmt(id, heritage, body) {