зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1168992 - Part 4: Convert PNK_SUPERELEM to PNK_ELEM and fix reflection of super[elem]. (r=Waldo)
This commit is contained in:
Родитель
177ac7002d
Коммит
4a9887c685
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) ||
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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())
|
||||
|
|
Загрузка…
Ссылка в новой задаче