diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index c874e85c409..a32f2297225 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -1904,9 +1904,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) { JS_CHECK_RECURSION(cx, return false); - if (!pn || *answer) - return true; - switch (pn->getKind()) { // Trivial cases with no side effects. case PNK_NEWTARGET: @@ -2327,179 +2324,8 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) MOZ_CRASH("invalid node kind"); } - switch (pn->getArity()) { - case PN_CODE: - /* - * 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; + MOZ_CRASH("invalid, unenumerated ParseNodeKind value encountered in " + "BytecodeEmitter::checkSideEffects"); } bool