mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1169171 - Split PNK_DELETE into several different kinds for each of the syntactically distinct modes of |delete| operation, depending upon the syntax of the operand. r=efaust
This commit is contained in:
parent
e8686eca4b
commit
e778a50c9d
@ -1998,31 +1998,26 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
||||
|
||||
case PN_UNARY:
|
||||
switch (pn->getKind()) {
|
||||
case PNK_DELETE:
|
||||
{
|
||||
ParseNode* pn2 = pn->pn_kid;
|
||||
switch (pn2->getKind()) {
|
||||
case PNK_NAME:
|
||||
if (!bindNameToSlot(pn2))
|
||||
return false;
|
||||
if (pn2->isConst()) {
|
||||
MOZ_ASSERT(*answer == false);
|
||||
return true;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
case PNK_DOT:
|
||||
case PNK_CALL:
|
||||
case PNK_ELEM:
|
||||
case PNK_SUPERELEM:
|
||||
/* All these delete addressing modes have effects too. */
|
||||
*answer = true;
|
||||
return true;
|
||||
default:
|
||||
return checkSideEffects(pn2, answer);
|
||||
}
|
||||
MOZ_CRASH("We have a returning default case");
|
||||
case PNK_DELETENAME: {
|
||||
ParseNode* nameExpr = pn->pn_kid;
|
||||
MOZ_ASSERT(nameExpr->isKind(PNK_NAME));
|
||||
if (!bindNameToSlot(nameExpr))
|
||||
return false;
|
||||
*answer = !nameExpr->isConst();
|
||||
return true;
|
||||
}
|
||||
|
||||
case PNK_DELETEPROP:
|
||||
case PNK_DELETESUPERPROP:
|
||||
case PNK_DELETEELEM:
|
||||
case PNK_DELETESUPERELEM:
|
||||
// All these delete addressing modes have effects, too.
|
||||
*answer = true;
|
||||
return true;
|
||||
|
||||
case PNK_DELETEEXPR:
|
||||
return checkSideEffects(pn->pn_kid, answer);
|
||||
|
||||
case PNK_TYPEOF:
|
||||
case PNK_VOID:
|
||||
case PNK_NOT:
|
||||
@ -6157,82 +6152,110 @@ BytecodeEmitter::emitStatement(ParseNode* pn)
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitDelete(ParseNode* pn)
|
||||
BytecodeEmitter::emitDeleteName(ParseNode* node)
|
||||
{
|
||||
/*
|
||||
* Under ECMA 3, deleting a non-reference returns true -- but alas we
|
||||
* must evaluate the operand if it appears it might have side effects.
|
||||
*/
|
||||
ParseNode* pn2 = pn->pn_kid;
|
||||
switch (pn2->getKind()) {
|
||||
case PNK_NAME:
|
||||
if (!bindNameToSlot(pn2))
|
||||
return false;
|
||||
if (!emitAtomOp(pn2, pn2->getOp()))
|
||||
return false;
|
||||
break;
|
||||
case PNK_DOT:
|
||||
{
|
||||
JSOp delOp = sc->strict() ? JSOP_STRICTDELPROP : JSOP_DELPROP;
|
||||
if (!emitPropOp(pn2, delOp))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case 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;
|
||||
if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER))
|
||||
return false;
|
||||
break;
|
||||
case PNK_ELEM:
|
||||
{
|
||||
JSOp delOp = sc->strict() ? JSOP_STRICTDELELEM : JSOP_DELELEM;
|
||||
if (!emitElemOp(pn2, delOp))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case PNK_SUPERELEM:
|
||||
// Still have to calculate everything, even though we're gonna throw
|
||||
// since it may have side effects
|
||||
if (!emitTree(pn2->pn_kid))
|
||||
return false;
|
||||
if (!emit1(JSOP_SUPERBASE))
|
||||
return false;
|
||||
if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER))
|
||||
return false;
|
||||
MOZ_ASSERT(node->isKind(PNK_DELETENAME));
|
||||
MOZ_ASSERT(node->isArity(PN_UNARY));
|
||||
|
||||
// Another wrinkle: Balance the stack from the emitter's point of view.
|
||||
// Execution will not reach here, as the last bytecode threw.
|
||||
ParseNode* nameExpr = node->pn_kid;
|
||||
MOZ_ASSERT(nameExpr->isKind(PNK_NAME));
|
||||
|
||||
if (!bindNameToSlot(nameExpr))
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(nameExpr->isOp(JSOP_DELNAME));
|
||||
return emitAtomOp(nameExpr, JSOP_DELNAME);
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitDeleteProperty(ParseNode* node)
|
||||
{
|
||||
MOZ_ASSERT(node->isKind(PNK_DELETEPROP));
|
||||
MOZ_ASSERT(node->isArity(PN_UNARY));
|
||||
|
||||
ParseNode* propExpr = node->pn_kid;
|
||||
MOZ_ASSERT(propExpr->isKind(PNK_DOT));
|
||||
|
||||
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)
|
||||
{
|
||||
MOZ_ASSERT(node->isKind(PNK_DELETEELEM));
|
||||
MOZ_ASSERT(node->isArity(PN_UNARY));
|
||||
|
||||
ParseNode* elemExpr = node->pn_kid;
|
||||
MOZ_ASSERT(elemExpr->isKind(PNK_ELEM));
|
||||
|
||||
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)
|
||||
{
|
||||
MOZ_ASSERT(node->isKind(PNK_DELETEEXPR));
|
||||
MOZ_ASSERT(node->isArity(PN_UNARY));
|
||||
|
||||
ParseNode* expression = node->pn_kid;
|
||||
|
||||
// If useless, just emit JSOP_TRUE; otherwise convert |delete <expr>| to
|
||||
// effectively |<expr>, true|.
|
||||
bool useful = false;
|
||||
if (!checkSideEffects(expression, &useful))
|
||||
return false;
|
||||
|
||||
if (useful) {
|
||||
MOZ_ASSERT_IF(expression->isKind(PNK_CALL), !(expression->pn_xflags & PNX_SETCALL));
|
||||
if (!emitTree(expression))
|
||||
return false;
|
||||
if (!emit1(JSOP_POP))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
/*
|
||||
* If useless, just emit JSOP_TRUE; otherwise convert delete foo()
|
||||
* to foo(), true (a comma expression).
|
||||
*/
|
||||
bool useful = false;
|
||||
if (!checkSideEffects(pn2, &useful))
|
||||
return false;
|
||||
|
||||
if (useful) {
|
||||
MOZ_ASSERT_IF(pn2->isKind(PNK_CALL), !(pn2->pn_xflags & PNX_SETCALL));
|
||||
if (!emitTree(pn2))
|
||||
return false;
|
||||
if (!emit1(JSOP_POP))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emit1(JSOP_TRUE))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return emit1(JSOP_TRUE);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -7461,8 +7484,28 @@ BytecodeEmitter::emitTree(ParseNode* pn)
|
||||
ok = emitIncOrDec(pn);
|
||||
break;
|
||||
|
||||
case PNK_DELETE:
|
||||
ok = emitDelete(pn);
|
||||
case PNK_DELETENAME:
|
||||
ok = emitDeleteName(pn);
|
||||
break;
|
||||
|
||||
case PNK_DELETEPROP:
|
||||
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:
|
||||
|
@ -545,7 +545,13 @@ struct BytecodeEmitter
|
||||
bool emitStatement(ParseNode* pn);
|
||||
bool emitStatementList(ParseNode* pn, ptrdiff_t top);
|
||||
|
||||
bool emitDelete(ParseNode* pn);
|
||||
bool emitDeleteName(ParseNode* pn);
|
||||
bool emitDeleteProperty(ParseNode* pn);
|
||||
bool emitDeleteSuperProperty(ParseNode* pn);
|
||||
bool emitDeleteElement(ParseNode* pn);
|
||||
bool emitDeleteSuperElement(ParseNode* pn);
|
||||
bool emitDeleteExpression(ParseNode* pn);
|
||||
|
||||
bool emitLogical(ParseNode* pn);
|
||||
bool emitUnary(ParseNode* pn);
|
||||
|
||||
|
@ -325,7 +325,12 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
|
||||
case PNK_VOID:
|
||||
case PNK_NOT:
|
||||
case PNK_BITNOT:
|
||||
case PNK_DELETE:
|
||||
case PNK_DELETENAME:
|
||||
case PNK_DELETEPROP:
|
||||
case PNK_DELETESUPERPROP:
|
||||
case PNK_DELETEELEM:
|
||||
case PNK_DELETESUPERELEM:
|
||||
case PNK_DELETEEXPR:
|
||||
case PNK_POS:
|
||||
case PNK_NEG:
|
||||
case PNK_PREINCREMENT:
|
||||
@ -716,7 +721,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp,
|
||||
SyntacticContext kidsc =
|
||||
pn->isKind(PNK_NOT)
|
||||
? SyntacticContext::Condition
|
||||
: pn->isKind(PNK_DELETE)
|
||||
: IsDeleteKind(pn->getKind())
|
||||
? SyntacticContext::Delete
|
||||
: SyntacticContext::Other;
|
||||
if (!Fold(cx, &pn->pn_kid, handler, options, inGenexpLambda, kidsc))
|
||||
@ -746,7 +751,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp,
|
||||
break;
|
||||
}
|
||||
|
||||
// The immediate child of a PNK_DELETE node should not be replaced
|
||||
// The immediate child of a PNK_DELETE* node should not be replaced
|
||||
// with node indicating a different syntactic form; |delete x| is not
|
||||
// the same as |delete (true && x)|. See bug 888002.
|
||||
//
|
||||
|
@ -187,11 +187,23 @@ class FullParseHandler
|
||||
}
|
||||
|
||||
ParseNode* newDelete(uint32_t begin, ParseNode* expr) {
|
||||
if (expr->getKind() == PNK_NAME) {
|
||||
if (expr->isKind(PNK_NAME)) {
|
||||
expr->pn_dflags |= PND_DEOPTIMIZED;
|
||||
expr->setOp(JSOP_DELNAME);
|
||||
return newUnary(PNK_DELETENAME, JSOP_NOP, begin, expr);
|
||||
}
|
||||
return newUnary(PNK_DELETE, JSOP_NOP, begin, expr);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
ParseNode* newNullary(ParseNodeKind kind, JSOp op, const TokenPos& pos) {
|
||||
|
@ -383,7 +383,12 @@ class NameResolver
|
||||
case PNK_NOT:
|
||||
case PNK_BITNOT:
|
||||
case PNK_THROW:
|
||||
case PNK_DELETE:
|
||||
case PNK_DELETENAME:
|
||||
case PNK_DELETEPROP:
|
||||
case PNK_DELETESUPERPROP:
|
||||
case PNK_DELETEELEM:
|
||||
case PNK_DELETESUPERELEM:
|
||||
case PNK_DELETEEXPR:
|
||||
case PNK_NEG:
|
||||
case PNK_POS:
|
||||
case PNK_PREINCREMENT:
|
||||
|
@ -226,7 +226,12 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
|
||||
case PNK_NOT:
|
||||
case PNK_BITNOT:
|
||||
case PNK_THROW:
|
||||
case PNK_DELETE:
|
||||
case PNK_DELETENAME:
|
||||
case PNK_DELETEPROP:
|
||||
case PNK_DELETESUPERPROP:
|
||||
case PNK_DELETEELEM:
|
||||
case PNK_DELETESUPERELEM:
|
||||
case PNK_DELETEEXPR:
|
||||
case PNK_POS:
|
||||
case PNK_NEG:
|
||||
case PNK_PREINCREMENT:
|
||||
|
@ -118,7 +118,13 @@ class UpvarCookie
|
||||
F(WITH) \
|
||||
F(RETURN) \
|
||||
F(NEW) \
|
||||
F(DELETE) \
|
||||
/* Delete operations. These must be sequential. */ \
|
||||
F(DELETENAME) \
|
||||
F(DELETEPROP) \
|
||||
F(DELETESUPERPROP) \
|
||||
F(DELETEELEM) \
|
||||
F(DELETESUPERELEM) \
|
||||
F(DELETEEXPR) \
|
||||
F(TRY) \
|
||||
F(CATCH) \
|
||||
F(CATCHLIST) \
|
||||
@ -227,6 +233,12 @@ enum ParseNodeKind
|
||||
PNK_ASSIGNMENT_LAST = PNK_MODASSIGN
|
||||
};
|
||||
|
||||
inline bool
|
||||
IsDeleteKind(ParseNodeKind kind)
|
||||
{
|
||||
return PNK_DELETENAME <= kind && kind <= PNK_DELETEEXPR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Label Variant Members
|
||||
* ----- ------- -------
|
||||
@ -393,7 +405,16 @@ enum ParseNodeKind
|
||||
* PNK_NEW list pn_head: list of ctor, arg1, arg2, ... argN
|
||||
* pn_count: 1 + N (where N is number of args)
|
||||
* ctor is a MEMBER expr
|
||||
* PNK_DELETE unary pn_kid: 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
|
||||
* overall delete evaluates to true; can't be a kind
|
||||
* for a more-specific PNK_DELETE* unless constant
|
||||
* folding (or a similar parse tree manipulation) has
|
||||
* occurred
|
||||
* PNK_DOT name pn_expr: MEMBER expr to left of .
|
||||
* pn_atom: name to right of .
|
||||
* PNK_ELEM binary pn_left: MEMBER expr to left of [
|
||||
|
@ -159,7 +159,9 @@ class SyntaxParseHandler
|
||||
|
||||
Node newElision() { return NodeGeneric; }
|
||||
|
||||
Node newDelete(uint32_t begin, Node expr) { return NodeGeneric; }
|
||||
Node newDelete(uint32_t begin, Node expr) {
|
||||
return NodeGeneric;
|
||||
}
|
||||
|
||||
Node newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, Node kid) {
|
||||
return NodeGeneric;
|
||||
|
@ -1910,7 +1910,7 @@ ASTSerializer::aop(JSOp op)
|
||||
UnaryOperator
|
||||
ASTSerializer::unop(ParseNodeKind kind, JSOp op)
|
||||
{
|
||||
if (kind == PNK_DELETE)
|
||||
if (IsDeleteKind(kind))
|
||||
return UNOP_DELETE;
|
||||
|
||||
switch (op) {
|
||||
@ -2926,7 +2926,12 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
||||
case PNK_INSTANCEOF:
|
||||
return leftAssociate(pn, dst);
|
||||
|
||||
case PNK_DELETE:
|
||||
case PNK_DELETENAME:
|
||||
case PNK_DELETEPROP:
|
||||
case PNK_DELETESUPERPROP:
|
||||
case PNK_DELETEELEM:
|
||||
case PNK_DELETESUPERELEM:
|
||||
case PNK_DELETEEXPR:
|
||||
case PNK_TYPEOF:
|
||||
case PNK_VOID:
|
||||
case PNK_NOT:
|
||||
|
Loading…
Reference in New Issue
Block a user