Bug 1167823 - Remove dead code for checking whether a parse tree node has side effects. r=shu

This commit is contained in:
Jeff Walden 2015-05-19 15:47:28 -07:00
parent 053b0396c8
commit 7fce2ca1d6

View File

@ -1904,9 +1904,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
{ {
JS_CHECK_RECURSION(cx, return false); JS_CHECK_RECURSION(cx, return false);
if (!pn || *answer)
return true;
switch (pn->getKind()) { switch (pn->getKind()) {
// Trivial cases with no side effects. // Trivial cases with no side effects.
case PNK_NEWTARGET: case PNK_NEWTARGET:
@ -2327,179 +2324,8 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
MOZ_CRASH("invalid node kind"); MOZ_CRASH("invalid node kind");
} }
switch (pn->getArity()) { MOZ_CRASH("invalid, unenumerated ParseNodeKind value encountered in "
case PN_CODE: "BytecodeEmitter::checkSideEffects");
/*
* A named function, contrary to ES3, is no longer useful, because we
* bind its name lexically (using JSOP_CALLEE) instead of creating an
* Object instance and binding a readonly, permanent property in it
* (the object and binding can be detected and hijacked or captured).
* This is a bug fix to ES3; it is fixed in ES3.1 drafts.
*/
MOZ_ASSERT(*answer == false);
return true;
case PN_LIST:
if (pn->isOp(JSOP_NOP) || pn->isOp(JSOP_OR) || pn->isOp(JSOP_AND) ||
pn->isOp(JSOP_STRICTEQ) || pn->isOp(JSOP_STRICTNE)) {
/*
* Non-operators along with ||, &&, ===, and !== never invoke
* toString or valueOf.
*/
bool ok = true;
for (ParseNode* pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next)
ok &= checkSideEffects(pn2, answer);
return ok;
}
if (pn->isKind(PNK_GENEXP)) {
/* Generator-expressions are harmless if the result is ignored. */
MOZ_ASSERT(*answer == false);
return true;
}
/*
* All invocation operations (construct: PNK_NEW, call: PNK_CALL)
* are presumed to be useful, because they may have side effects
* even if their main effect (their return value) is discarded.
*
* PNK_ELEM binary trees of 3+ nodes are flattened into lists to
* avoid too much recursion. All such lists must be presumed to be
* useful because each index operation could invoke a getter.
*
* Likewise, array and object initialisers may call prototype
* setters (the __defineSetter__ built-in, and writable __proto__
* on Array.prototype create this hazard). Initialiser list nodes
* have JSOP_NEWINIT in their pn_op.
*/
*answer = true;
return true;
case PN_TERNARY:
return checkSideEffects(pn->pn_kid1, answer) &&
checkSideEffects(pn->pn_kid2, answer) &&
checkSideEffects(pn->pn_kid3, answer);
case PN_BINARY:
case PN_BINARY_OBJ:
if (pn->isAssignment()) {
/*
* Assignment is presumed to be useful, even if the next operation
* is another assignment overwriting this one's ostensible effect,
* because the left operand may be a property with a setter that
* has side effects.
*
* The only exception is assignment of a useless value to a const
* declared in the function currently being compiled.
*/
ParseNode* pn2 = pn->pn_left;
if (!pn2->isKind(PNK_NAME)) {
*answer = true;
} else {
if (!bindNameToSlot(pn2))
return false;
if (!checkSideEffects(pn->pn_right, answer))
return false;
if (!*answer && (!pn->isOp(JSOP_NOP) || !pn2->isConst()))
*answer = true;
}
return true;
}
MOZ_ASSERT(!pn->isOp(JSOP_OR), "|| produces a list now");
MOZ_ASSERT(!pn->isOp(JSOP_AND), "&& produces a list now");
MOZ_ASSERT(!pn->isOp(JSOP_STRICTEQ), "=== produces a list now");
MOZ_ASSERT(!pn->isOp(JSOP_STRICTNE), "!== produces a list now");
/*
* We can't easily prove that neither operand ever denotes an
* object with a toString or valueOf method.
*/
*answer = true;
return true;
case PN_UNARY:
switch (pn->getKind()) {
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_TYPEOFNAME:
case PNK_TYPEOFEXPR:
case PNK_VOID:
case PNK_NOT:
case PNK_BITNOT:
if (pn->isOp(JSOP_NOT)) {
/* ! does not convert its operand via toString or valueOf. */
return checkSideEffects(pn->pn_kid, answer);
}
/* FALL THROUGH */
default:
/*
* All of PNK_INC, PNK_DEC and PNK_THROW have direct effects. Of
* the remaining unary-arity node types, we can't easily prove that
* the operand never denotes an object with a toString or valueOf
* method.
*/
*answer = true;
return true;
}
MOZ_CRASH("We have a returning default case");
case PN_NAME:
/*
* Take care to avoid trying to bind a label name (labels, both for
* statements and property values in object initialisers, have pn_op
* defaulted to JSOP_NOP).
*/
if (pn->isKind(PNK_NAME) && !pn->isOp(JSOP_NOP)) {
if (!bindNameToSlot(pn))
return false;
if (!pn->isOp(JSOP_CALLEE) && pn->pn_cookie.isFree()) {
/*
* Not a use of an unshadowed named function expression's given
* name, so this expression could invoke a getter that has side
* effects.
*/
*answer = true;
}
}
if (pn->isHoistedLexicalUse()) {
// Hoisted uses of lexical bindings throw on access.
*answer = true;
}
if (pn->isKind(PNK_DOT)) {
/* Dotted property references in general can call getters. */
*answer = true;
}
return checkSideEffects(pn->maybeExpr(), answer);
case PN_NULLARY:
if (pn->isKind(PNK_DEBUGGER) ||
pn->isKind(PNK_SUPERPROP))
*answer = true;
return true;
}
return true;
} }
bool bool