LCOV - code coverage report
Current view: top level - js/src/frontend - FoldConstants.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 513 811 63.3 %
Date: 2017-07-14 16:53:18 Functions: 33 38 86.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "frontend/FoldConstants.h"
       8             : 
       9             : #include "mozilla/FloatingPoint.h"
      10             : 
      11             : #include "jslibmath.h"
      12             : 
      13             : #include "frontend/ParseNode.h"
      14             : #include "frontend/Parser.h"
      15             : #include "js/Conversions.h"
      16             : 
      17             : #include "jscntxtinlines.h"
      18             : #include "jsobjinlines.h"
      19             : 
      20             : using namespace js;
      21             : using namespace js::frontend;
      22             : 
      23             : using mozilla::IsNaN;
      24             : using mozilla::IsNegative;
      25             : using mozilla::NegativeInfinity;
      26             : using mozilla::PositiveInfinity;
      27             : using JS::GenericNaN;
      28             : using JS::ToInt32;
      29             : using JS::ToUint32;
      30             : 
      31             : static bool
      32             : ContainsHoistedDeclaration(JSContext* cx, ParseNode* node, bool* result);
      33             : 
      34             : static bool
      35           0 : ListContainsHoistedDeclaration(JSContext* cx, ListNode* list, bool* result)
      36             : {
      37           0 :     for (ParseNode* node = list->pn_head; node; node = node->pn_next) {
      38           0 :         if (!ContainsHoistedDeclaration(cx, node, result))
      39           0 :             return false;
      40           0 :         if (*result)
      41           0 :             return true;
      42             :     }
      43             : 
      44           0 :     *result = false;
      45           0 :     return true;
      46             : }
      47             : 
      48             : // Determines whether the given ParseNode contains any declarations whose
      49             : // visibility will extend outside the node itself -- that is, whether the
      50             : // ParseNode contains any var statements.
      51             : //
      52             : // THIS IS NOT A GENERAL-PURPOSE FUNCTION.  It is only written to work in the
      53             : // specific context of deciding that |node|, as one arm of a PNK_IF controlled
      54             : // by a constant condition, contains a declaration that forbids |node| being
      55             : // completely eliminated as dead.
      56             : static bool
      57           9 : ContainsHoistedDeclaration(JSContext* cx, ParseNode* node, bool* result)
      58             : {
      59           9 :     if (!CheckRecursionLimit(cx))
      60           0 :         return false;
      61             : 
      62             :   restart:
      63             : 
      64             :     // With a better-typed AST, we would have distinct parse node classes for
      65             :     // expressions and for statements and would characterize expressions with
      66             :     // ExpressionKind and statements with StatementKind.  Perhaps someday.  In
      67             :     // the meantime we must characterize every ParseNodeKind, even the
      68             :     // expression/sub-expression ones that, if we handle all statement kinds
      69             :     // correctly, we'll never see.
      70           9 :     switch (node->getKind()) {
      71             :       // Base case.
      72             :       case PNK_VAR:
      73           0 :         *result = true;
      74           0 :         return true;
      75             : 
      76             :       // Non-global lexical declarations are block-scoped (ergo not hoistable).
      77             :       case PNK_LET:
      78             :       case PNK_CONST:
      79           0 :         MOZ_ASSERT(node->isArity(PN_LIST));
      80           0 :         *result = false;
      81           0 :         return true;
      82             : 
      83             :       // Similarly to the lexical declarations above, classes cannot add hoisted
      84             :       // declarations
      85             :       case PNK_CLASS:
      86           0 :         MOZ_ASSERT(node->isArity(PN_TERNARY));
      87           0 :         *result = false;
      88           0 :         return true;
      89             : 
      90             :       // Function declarations *can* be hoisted declarations.  But in the
      91             :       // magical world of the rewritten frontend, the declaration necessitated
      92             :       // by a nested function statement, not at body level, doesn't require
      93             :       // that we preserve an unreachable function declaration node against
      94             :       // dead-code removal.
      95             :       case PNK_FUNCTION:
      96           0 :         MOZ_ASSERT(node->isArity(PN_CODE));
      97           0 :         *result = false;
      98           0 :         return true;
      99             : 
     100             :       case PNK_MODULE:
     101           0 :         *result = false;
     102           0 :         return true;
     103             : 
     104             :       // Statements with no sub-components at all.
     105             :       case PNK_NOP: // induced by function f() {} function f() {}
     106             :       case PNK_DEBUGGER:
     107           0 :         MOZ_ASSERT(node->isArity(PN_NULLARY));
     108           0 :         *result = false;
     109           0 :         return true;
     110             : 
     111             :       // Statements containing only an expression have no declarations.
     112             :       case PNK_SEMI:
     113             :       case PNK_THROW:
     114             :       case PNK_RETURN:
     115           9 :         MOZ_ASSERT(node->isArity(PN_UNARY));
     116           9 :         *result = false;
     117           9 :         return true;
     118             : 
     119             :       // These two aren't statements in the spec, but we sometimes insert them
     120             :       // in statement lists anyway.
     121             :       case PNK_INITIALYIELD:
     122             :       case PNK_YIELD_STAR:
     123             :       case PNK_YIELD:
     124           0 :         MOZ_ASSERT(node->isArity(PN_UNARY));
     125           0 :         *result = false;
     126           0 :         return true;
     127             : 
     128             :       // Other statements with no sub-statement components.
     129             :       case PNK_BREAK:
     130             :       case PNK_CONTINUE:
     131             :       case PNK_IMPORT:
     132             :       case PNK_IMPORT_SPEC_LIST:
     133             :       case PNK_IMPORT_SPEC:
     134             :       case PNK_EXPORT_FROM:
     135             :       case PNK_EXPORT_DEFAULT:
     136             :       case PNK_EXPORT_SPEC_LIST:
     137             :       case PNK_EXPORT_SPEC:
     138             :       case PNK_EXPORT:
     139             :       case PNK_EXPORT_BATCH_SPEC:
     140           0 :         *result = false;
     141           0 :         return true;
     142             : 
     143             :       // Statements possibly containing hoistable declarations only in the left
     144             :       // half, in ParseNode terms -- the loop body in AST terms.
     145             :       case PNK_DOWHILE:
     146           0 :         return ContainsHoistedDeclaration(cx, node->pn_left, result);
     147             : 
     148             :       // Statements possibly containing hoistable declarations only in the
     149             :       // right half, in ParseNode terms -- the loop body or nested statement
     150             :       // (usually a block statement), in AST terms.
     151             :       case PNK_WHILE:
     152             :       case PNK_WITH:
     153           0 :         return ContainsHoistedDeclaration(cx, node->pn_right, result);
     154             : 
     155             :       case PNK_LABEL:
     156           0 :         return ContainsHoistedDeclaration(cx, node->pn_expr, result);
     157             : 
     158             :       // Statements with more complicated structures.
     159             : 
     160             :       // if-statement nodes may have hoisted declarations in their consequent
     161             :       // and alternative components.
     162             :       case PNK_IF: {
     163           0 :         MOZ_ASSERT(node->isArity(PN_TERNARY));
     164             : 
     165           0 :         ParseNode* consequent = node->pn_kid2;
     166           0 :         if (!ContainsHoistedDeclaration(cx, consequent, result))
     167           0 :             return false;
     168           0 :         if (*result)
     169           0 :             return true;
     170             : 
     171           0 :         if ((node = node->pn_kid3))
     172           0 :             goto restart;
     173             : 
     174           0 :         *result = false;
     175           0 :         return true;
     176             :       }
     177             : 
     178             :       // Legacy array and generator comprehensions use PNK_IF to represent
     179             :       // conditions specified in the comprehension tail: for example,
     180             :       // [x for (x in obj) if (x)].  The consequent of such PNK_IF nodes is
     181             :       // either PNK_YIELD in a PNK_SEMI statement (generator comprehensions) or
     182             :       // PNK_ARRAYPUSH (array comprehensions) .  The first case is consistent
     183             :       // with normal if-statement structure with consequent/alternative as
     184             :       // statements.  The second case is abnormal and requires that we not
     185             :       // banish PNK_ARRAYPUSH to the unreachable list, handling it explicitly.
     186             :       //
     187             :       // We could require that this one weird PNK_ARRAYPUSH case be packaged in
     188             :       // a PNK_SEMI, for consistency.  That requires careful bytecode emitter
     189             :       // adjustment that seems unwarranted for a deprecated feature.
     190             :       case PNK_ARRAYPUSH:
     191           0 :         *result = false;
     192           0 :         return true;
     193             : 
     194             :       // try-statements have statements to execute, and one or both of a
     195             :       // catch-list and a finally-block.
     196             :       case PNK_TRY: {
     197           0 :         MOZ_ASSERT(node->isArity(PN_TERNARY));
     198           0 :         MOZ_ASSERT(node->pn_kid2 || node->pn_kid3,
     199             :                    "must have either catch(es) or finally");
     200             : 
     201           0 :         ParseNode* tryBlock = node->pn_kid1;
     202           0 :         if (!ContainsHoistedDeclaration(cx, tryBlock, result))
     203           0 :             return false;
     204           0 :         if (*result)
     205           0 :             return true;
     206             : 
     207           0 :         if (ParseNode* catchList = node->pn_kid2) {
     208           0 :             for (ParseNode* lexicalScope = catchList->pn_head;
     209           0 :                  lexicalScope;
     210           0 :                  lexicalScope = lexicalScope->pn_next)
     211             :             {
     212           0 :                 MOZ_ASSERT(lexicalScope->isKind(PNK_LEXICALSCOPE));
     213             : 
     214           0 :                 ParseNode* catchNode = lexicalScope->pn_expr;
     215           0 :                 MOZ_ASSERT(catchNode->isKind(PNK_CATCH));
     216             : 
     217           0 :                 ParseNode* catchStatements = catchNode->pn_kid3;
     218           0 :                 if (!ContainsHoistedDeclaration(cx, catchStatements, result))
     219           0 :                     return false;
     220           0 :                 if (*result)
     221           0 :                     return true;
     222             :             }
     223             :         }
     224             : 
     225           0 :         if (ParseNode* finallyBlock = node->pn_kid3)
     226           0 :             return ContainsHoistedDeclaration(cx, finallyBlock, result);
     227             : 
     228           0 :         *result = false;
     229           0 :         return true;
     230             :       }
     231             : 
     232             :       // A switch node's left half is an expression; only its right half (a
     233             :       // list of cases/defaults, or a block node) could contain hoisted
     234             :       // declarations.
     235             :       case PNK_SWITCH:
     236           0 :         MOZ_ASSERT(node->isArity(PN_BINARY));
     237           0 :         return ContainsHoistedDeclaration(cx, node->pn_right, result);
     238             : 
     239             :       case PNK_CASE:
     240           0 :         return ContainsHoistedDeclaration(cx, node->as<CaseClause>().statementList(), result);
     241             : 
     242             :       case PNK_FOR:
     243             :       case PNK_COMPREHENSIONFOR: {
     244           0 :         MOZ_ASSERT(node->isArity(PN_BINARY));
     245             : 
     246           0 :         ParseNode* loopHead = node->pn_left;
     247           0 :         MOZ_ASSERT(loopHead->isKind(PNK_FORHEAD) ||
     248             :                    loopHead->isKind(PNK_FORIN) ||
     249             :                    loopHead->isKind(PNK_FOROF));
     250             : 
     251           0 :         if (loopHead->isKind(PNK_FORHEAD)) {
     252             :             // for (init?; cond?; update?), with only init possibly containing
     253             :             // a hoisted declaration.  (Note: a lexical-declaration |init| is
     254             :             // (at present) hoisted in SpiderMonkey parlance -- but such
     255             :             // hoisting doesn't extend outside of this statement, so it is not
     256             :             // hoisting in the sense meant by ContainsHoistedDeclaration.)
     257           0 :             MOZ_ASSERT(loopHead->isArity(PN_TERNARY));
     258             : 
     259           0 :             ParseNode* init = loopHead->pn_kid1;
     260           0 :             if (init && init->isKind(PNK_VAR)) {
     261           0 :                 *result = true;
     262           0 :                 return true;
     263             :             }
     264             :         } else {
     265           0 :             MOZ_ASSERT(loopHead->isKind(PNK_FORIN) || loopHead->isKind(PNK_FOROF));
     266             : 
     267             :             // for each? (target in ...), where only target may introduce
     268             :             // hoisted declarations.
     269             :             //
     270             :             //   -- or --
     271             :             //
     272             :             // for (target of ...), where only target may introduce hoisted
     273             :             // declarations.
     274             :             //
     275             :             // Either way, if |target| contains a declaration, it's |loopHead|'s
     276             :             // first kid.
     277           0 :             MOZ_ASSERT(loopHead->isArity(PN_TERNARY));
     278             : 
     279           0 :             ParseNode* decl = loopHead->pn_kid1;
     280           0 :             if (decl && decl->isKind(PNK_VAR)) {
     281           0 :                 *result = true;
     282           0 :                 return true;
     283             :             }
     284             :         }
     285             : 
     286           0 :         ParseNode* loopBody = node->pn_right;
     287           0 :         return ContainsHoistedDeclaration(cx, loopBody, result);
     288             :       }
     289             : 
     290             :       case PNK_LEXICALSCOPE: {
     291           0 :         MOZ_ASSERT(node->isArity(PN_SCOPE));
     292           0 :         ParseNode* expr = node->pn_expr;
     293             : 
     294           0 :         if (expr->isKind(PNK_FOR) || expr->isKind(PNK_FUNCTION))
     295           0 :             return ContainsHoistedDeclaration(cx, expr, result);
     296             : 
     297           0 :         MOZ_ASSERT(expr->isKind(PNK_STATEMENTLIST));
     298           0 :         return ListContainsHoistedDeclaration(cx, &node->pn_expr->as<ListNode>(), result);
     299             :       }
     300             : 
     301             :       // List nodes with all non-null children.
     302             :       case PNK_STATEMENTLIST:
     303           0 :         return ListContainsHoistedDeclaration(cx, &node->as<ListNode>(), result);
     304             : 
     305             :       // Grammar sub-components that should never be reached directly by this
     306             :       // method, because some parent component should have asserted itself.
     307             :       case PNK_OBJECT_PROPERTY_NAME:
     308             :       case PNK_COMPUTED_NAME:
     309             :       case PNK_SPREAD:
     310             :       case PNK_MUTATEPROTO:
     311             :       case PNK_COLON:
     312             :       case PNK_SHORTHAND:
     313             :       case PNK_CONDITIONAL:
     314             :       case PNK_TYPEOFNAME:
     315             :       case PNK_TYPEOFEXPR:
     316             :       case PNK_AWAIT:
     317             :       case PNK_VOID:
     318             :       case PNK_NOT:
     319             :       case PNK_BITNOT:
     320             :       case PNK_DELETENAME:
     321             :       case PNK_DELETEPROP:
     322             :       case PNK_DELETEELEM:
     323             :       case PNK_DELETEEXPR:
     324             :       case PNK_POS:
     325             :       case PNK_NEG:
     326             :       case PNK_PREINCREMENT:
     327             :       case PNK_POSTINCREMENT:
     328             :       case PNK_PREDECREMENT:
     329             :       case PNK_POSTDECREMENT:
     330             :       case PNK_OR:
     331             :       case PNK_AND:
     332             :       case PNK_BITOR:
     333             :       case PNK_BITXOR:
     334             :       case PNK_BITAND:
     335             :       case PNK_STRICTEQ:
     336             :       case PNK_EQ:
     337             :       case PNK_STRICTNE:
     338             :       case PNK_NE:
     339             :       case PNK_LT:
     340             :       case PNK_LE:
     341             :       case PNK_GT:
     342             :       case PNK_GE:
     343             :       case PNK_INSTANCEOF:
     344             :       case PNK_IN:
     345             :       case PNK_LSH:
     346             :       case PNK_RSH:
     347             :       case PNK_URSH:
     348             :       case PNK_ADD:
     349             :       case PNK_SUB:
     350             :       case PNK_STAR:
     351             :       case PNK_DIV:
     352             :       case PNK_MOD:
     353             :       case PNK_POW:
     354             :       case PNK_ASSIGN:
     355             :       case PNK_ADDASSIGN:
     356             :       case PNK_SUBASSIGN:
     357             :       case PNK_BITORASSIGN:
     358             :       case PNK_BITXORASSIGN:
     359             :       case PNK_BITANDASSIGN:
     360             :       case PNK_LSHASSIGN:
     361             :       case PNK_RSHASSIGN:
     362             :       case PNK_URSHASSIGN:
     363             :       case PNK_MULASSIGN:
     364             :       case PNK_DIVASSIGN:
     365             :       case PNK_MODASSIGN:
     366             :       case PNK_POWASSIGN:
     367             :       case PNK_COMMA:
     368             :       case PNK_ARRAY:
     369             :       case PNK_OBJECT:
     370             :       case PNK_DOT:
     371             :       case PNK_ELEM:
     372             :       case PNK_CALL:
     373             :       case PNK_NAME:
     374             :       case PNK_TEMPLATE_STRING:
     375             :       case PNK_TEMPLATE_STRING_LIST:
     376             :       case PNK_TAGGED_TEMPLATE:
     377             :       case PNK_CALLSITEOBJ:
     378             :       case PNK_STRING:
     379             :       case PNK_REGEXP:
     380             :       case PNK_TRUE:
     381             :       case PNK_FALSE:
     382             :       case PNK_NULL:
     383             :       case PNK_RAW_UNDEFINED:
     384             :       case PNK_THIS:
     385             :       case PNK_ELISION:
     386             :       case PNK_NUMBER:
     387             :       case PNK_NEW:
     388             :       case PNK_GENERATOR:
     389             :       case PNK_GENEXP:
     390             :       case PNK_ARRAYCOMP:
     391             :       case PNK_PARAMSBODY:
     392             :       case PNK_CATCHLIST:
     393             :       case PNK_CATCH:
     394             :       case PNK_FORIN:
     395             :       case PNK_FOROF:
     396             :       case PNK_FORHEAD:
     397             :       case PNK_CLASSMETHOD:
     398             :       case PNK_CLASSMETHODLIST:
     399             :       case PNK_CLASSNAMES:
     400             :       case PNK_NEWTARGET:
     401             :       case PNK_POSHOLDER:
     402             :       case PNK_SUPERCALL:
     403             :       case PNK_SUPERBASE:
     404             :       case PNK_SETTHIS:
     405           0 :         MOZ_CRASH("ContainsHoistedDeclaration should have indicated false on "
     406             :                   "some parent node without recurring to test this node");
     407             : 
     408             :       case PNK_LIMIT: // invalid sentinel value
     409           0 :         MOZ_CRASH("unexpected PNK_LIMIT in node");
     410             :     }
     411             : 
     412           0 :     MOZ_CRASH("invalid node kind");
     413             : }
     414             : 
     415             : /*
     416             :  * Fold from one constant type to another.
     417             :  * XXX handles only strings and numbers for now
     418             :  */
     419             : static bool
     420        5418 : FoldType(JSContext* cx, ParseNode* pn, ParseNodeKind kind)
     421             : {
     422        5418 :     if (!pn->isKind(kind)) {
     423        2575 :         switch (kind) {
     424             :           case PNK_NUMBER:
     425         961 :             if (pn->isKind(PNK_STRING)) {
     426             :                 double d;
     427           0 :                 if (!StringToNumber(cx, pn->pn_atom, &d))
     428           0 :                     return false;
     429           0 :                 pn->pn_dval = d;
     430           0 :                 pn->setKind(PNK_NUMBER);
     431           0 :                 pn->setOp(JSOP_DOUBLE);
     432             :             }
     433         961 :             break;
     434             : 
     435             :           case PNK_STRING:
     436        1614 :             if (pn->isKind(PNK_NUMBER)) {
     437         579 :                 pn->pn_atom = NumberToAtom(cx, pn->pn_dval);
     438         579 :                 if (!pn->pn_atom)
     439           0 :                     return false;
     440         579 :                 pn->setKind(PNK_STRING);
     441         579 :                 pn->setOp(JSOP_STRING);
     442             :             }
     443        1614 :             break;
     444             : 
     445             :           default:;
     446             :         }
     447             :     }
     448        5418 :     return true;
     449             : }
     450             : 
     451             : // Remove a ParseNode, **pnp, from a parse tree, putting another ParseNode,
     452             : // *pn, in its place.
     453             : //
     454             : // pnp points to a ParseNode pointer. This must be the only pointer that points
     455             : // to the parse node being replaced. The replacement, *pn, is unchanged except
     456             : // for its pn_next pointer; updating that is necessary if *pn's new parent is a
     457             : // list node.
     458             : static void
     459         828 : ReplaceNode(ParseNode** pnp, ParseNode* pn)
     460             : {
     461         828 :     pn->pn_next = (*pnp)->pn_next;
     462         828 :     *pnp = pn;
     463         828 : }
     464             : 
     465             : static bool
     466           0 : IsEffectless(ParseNode* node)
     467             : {
     468           0 :     return node->isKind(PNK_TRUE) ||
     469           0 :            node->isKind(PNK_FALSE) ||
     470           0 :            node->isKind(PNK_STRING) ||
     471           0 :            node->isKind(PNK_TEMPLATE_STRING) ||
     472           0 :            node->isKind(PNK_NUMBER) ||
     473           0 :            node->isKind(PNK_NULL) ||
     474           0 :            node->isKind(PNK_RAW_UNDEFINED) ||
     475           0 :            node->isKind(PNK_FUNCTION) ||
     476           0 :            node->isKind(PNK_GENEXP);
     477             : }
     478             : 
     479             : enum Truthiness { Truthy, Falsy, Unknown };
     480             : 
     481             : static Truthiness
     482       25099 : Boolish(ParseNode* pn)
     483             : {
     484       25099 :     switch (pn->getKind()) {
     485             :       case PNK_NUMBER:
     486          16 :         return (pn->pn_dval != 0 && !IsNaN(pn->pn_dval)) ? Truthy : Falsy;
     487             : 
     488             :       case PNK_STRING:
     489             :       case PNK_TEMPLATE_STRING:
     490          20 :         return (pn->pn_atom->length() > 0) ? Truthy : Falsy;
     491             : 
     492             :       case PNK_TRUE:
     493             :       case PNK_FUNCTION:
     494             :       case PNK_GENEXP:
     495         132 :         return Truthy;
     496             : 
     497             :       case PNK_FALSE:
     498             :       case PNK_NULL:
     499             :       case PNK_RAW_UNDEFINED:
     500         115 :         return Falsy;
     501             : 
     502             :       case PNK_VOID: {
     503             :         // |void <foo>| evaluates to |undefined| which isn't truthy.  But the
     504             :         // sense of this method requires that the expression be literally
     505             :         // replaceable with true/false: not the case if the nested expression
     506             :         // is effectful, might throw, &c.  Walk past the |void| (and nested
     507             :         // |void| expressions, for good measure) and check that the nested
     508             :         // expression doesn't break this requirement before indicating falsity.
     509           0 :         do {
     510           0 :             pn = pn->pn_kid;
     511             :         } while (pn->isKind(PNK_VOID));
     512             : 
     513           0 :         return IsEffectless(pn) ? Falsy : Unknown;
     514             :       }
     515             : 
     516             :       default:
     517       24816 :         return Unknown;
     518             :     }
     519             : }
     520             : 
     521             : static bool
     522             : Fold(JSContext* cx, ParseNode** pnp, Parser<FullParseHandler, char16_t>& parser,
     523             :      bool inGenexpLambda);
     524             : 
     525             : static bool
     526       12003 : FoldCondition(JSContext* cx, ParseNode** nodePtr, Parser<FullParseHandler, char16_t>& parser,
     527             :               bool inGenexpLambda)
     528             : {
     529             :     // Conditions fold like any other expression...
     530       12003 :     if (!Fold(cx, nodePtr, parser, inGenexpLambda))
     531           0 :         return false;
     532             : 
     533             :     // ...but then they sometimes can be further folded to constants.
     534       12003 :     ParseNode* node = *nodePtr;
     535       12003 :     Truthiness t = Boolish(node);
     536       12003 :     if (t != Unknown) {
     537             :         // We can turn function nodes into constant nodes here, but mutating
     538             :         // function nodes is tricky --- in particular, mutating a function node
     539             :         // that appears on a method list corrupts the method list. However,
     540             :         // methods are M's in statements of the form 'this.foo = M;', which we
     541             :         // never fold, so we're okay.
     542         141 :         parser.prepareNodeForMutation(node);
     543         141 :         if (t == Truthy) {
     544          93 :             node->setKind(PNK_TRUE);
     545          93 :             node->setOp(JSOP_TRUE);
     546             :         } else {
     547          48 :             node->setKind(PNK_FALSE);
     548          48 :             node->setOp(JSOP_FALSE);
     549             :         }
     550         141 :         node->setArity(PN_NULLARY);
     551             :     }
     552             : 
     553       12003 :     return true;
     554             : }
     555             : 
     556             : static bool
     557          73 : FoldTypeOfExpr(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
     558             :                bool inGenexpLambda)
     559             : {
     560          73 :     MOZ_ASSERT(node->isKind(PNK_TYPEOFEXPR));
     561          73 :     MOZ_ASSERT(node->isArity(PN_UNARY));
     562             : 
     563          73 :     ParseNode*& expr = node->pn_kid;
     564          73 :     if (!Fold(cx, &expr, parser, inGenexpLambda))
     565           0 :         return false;
     566             : 
     567             :     // Constant-fold the entire |typeof| if given a constant with known type.
     568         146 :     RootedPropertyName result(cx);
     569          73 :     if (expr->isKind(PNK_STRING) || expr->isKind(PNK_TEMPLATE_STRING))
     570           0 :         result = cx->names().string;
     571          73 :     else if (expr->isKind(PNK_NUMBER))
     572           0 :         result = cx->names().number;
     573          73 :     else if (expr->isKind(PNK_NULL))
     574           0 :         result = cx->names().object;
     575          73 :     else if (expr->isKind(PNK_TRUE) || expr->isKind(PNK_FALSE))
     576           0 :         result = cx->names().boolean;
     577          73 :     else if (expr->isKind(PNK_FUNCTION))
     578           0 :         result = cx->names().function;
     579             : 
     580          73 :     if (result) {
     581           0 :         parser.prepareNodeForMutation(node);
     582             : 
     583           0 :         node->setKind(PNK_STRING);
     584           0 :         node->setArity(PN_NULLARY);
     585           0 :         node->setOp(JSOP_NOP);
     586           0 :         node->pn_atom = result;
     587             :     }
     588             : 
     589          73 :     return true;
     590             : }
     591             : 
     592             : static bool
     593           0 : FoldDeleteExpr(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
     594             :                bool inGenexpLambda)
     595             : {
     596           0 :     MOZ_ASSERT(node->isKind(PNK_DELETEEXPR));
     597           0 :     MOZ_ASSERT(node->isArity(PN_UNARY));
     598             : 
     599           0 :     ParseNode*& expr = node->pn_kid;
     600           0 :     if (!Fold(cx, &expr, parser, inGenexpLambda))
     601           0 :         return false;
     602             : 
     603             :     // Expression deletion evaluates the expression, then evaluates to true.
     604             :     // For effectless expressions, eliminate the expression evaluation.
     605           0 :     if (IsEffectless(expr)) {
     606           0 :         parser.prepareNodeForMutation(node);
     607           0 :         node->setKind(PNK_TRUE);
     608           0 :         node->setArity(PN_NULLARY);
     609           0 :         node->setOp(JSOP_TRUE);
     610             :     }
     611             : 
     612           0 :     return true;
     613             : }
     614             : 
     615             : static bool
     616          40 : FoldDeleteElement(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
     617             :                   bool inGenexpLambda)
     618             : {
     619          40 :     MOZ_ASSERT(node->isKind(PNK_DELETEELEM));
     620          40 :     MOZ_ASSERT(node->isArity(PN_UNARY));
     621          40 :     MOZ_ASSERT(node->pn_kid->isKind(PNK_ELEM));
     622             : 
     623          40 :     ParseNode*& expr = node->pn_kid;
     624          40 :     if (!Fold(cx, &expr, parser, inGenexpLambda))
     625           0 :         return false;
     626             : 
     627             :     // If we're deleting an element, but constant-folding converted our
     628             :     // element reference into a dotted property access, we must *also*
     629             :     // morph the node's kind.
     630             :     //
     631             :     // In principle this also applies to |super["foo"] -> super.foo|,
     632             :     // but we don't constant-fold |super["foo"]| yet.
     633          40 :     MOZ_ASSERT(expr->isKind(PNK_ELEM) || expr->isKind(PNK_DOT));
     634          40 :     if (expr->isKind(PNK_DOT))
     635           0 :         node->setKind(PNK_DELETEPROP);
     636             : 
     637          40 :     return true;
     638             : }
     639             : 
     640             : static bool
     641          58 : FoldDeleteProperty(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
     642             :                    bool inGenexpLambda)
     643             : {
     644          58 :     MOZ_ASSERT(node->isKind(PNK_DELETEPROP));
     645          58 :     MOZ_ASSERT(node->isArity(PN_UNARY));
     646          58 :     MOZ_ASSERT(node->pn_kid->isKind(PNK_DOT));
     647             : 
     648          58 :     ParseNode*& expr = node->pn_kid;
     649             : #ifdef DEBUG
     650          58 :     ParseNodeKind oldKind = expr->getKind();
     651             : #endif
     652             : 
     653          58 :     if (!Fold(cx, &expr, parser, inGenexpLambda))
     654           0 :         return false;
     655             : 
     656          58 :     MOZ_ASSERT(expr->isKind(oldKind),
     657             :                "kind should have remained invariant under folding");
     658             : 
     659          58 :     return true;
     660             : }
     661             : 
     662             : static bool
     663        3082 : FoldNot(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
     664             :         bool inGenexpLambda)
     665             : {
     666        3082 :     MOZ_ASSERT(node->isKind(PNK_NOT));
     667        3082 :     MOZ_ASSERT(node->isArity(PN_UNARY));
     668             : 
     669        3082 :     ParseNode*& expr = node->pn_kid;
     670        3082 :     if (!FoldCondition(cx, &expr, parser, inGenexpLambda))
     671           0 :         return false;
     672             : 
     673        3082 :     if (expr->isKind(PNK_NUMBER)) {
     674           0 :         double d = expr->pn_dval;
     675             : 
     676           0 :         parser.prepareNodeForMutation(node);
     677           0 :         if (d == 0 || IsNaN(d)) {
     678           0 :             node->setKind(PNK_TRUE);
     679           0 :             node->setOp(JSOP_TRUE);
     680             :         } else {
     681           0 :             node->setKind(PNK_FALSE);
     682           0 :             node->setOp(JSOP_FALSE);
     683             :         }
     684           0 :         node->setArity(PN_NULLARY);
     685        3082 :     } else if (expr->isKind(PNK_TRUE) || expr->isKind(PNK_FALSE)) {
     686          39 :         bool newval = !expr->isKind(PNK_TRUE);
     687             : 
     688          39 :         parser.prepareNodeForMutation(node);
     689          39 :         node->setKind(newval ? PNK_TRUE : PNK_FALSE);
     690          39 :         node->setArity(PN_NULLARY);
     691          39 :         node->setOp(newval ? JSOP_TRUE : JSOP_FALSE);
     692             :     }
     693             : 
     694        3082 :     return true;
     695             : }
     696             : 
     697             : static bool
     698         287 : FoldUnaryArithmetic(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
     699             :                     bool inGenexpLambda)
     700             : {
     701         287 :     MOZ_ASSERT(node->isKind(PNK_BITNOT) || node->isKind(PNK_POS) || node->isKind(PNK_NEG),
     702             :                "need a different method for this node kind");
     703         287 :     MOZ_ASSERT(node->isArity(PN_UNARY));
     704             : 
     705         287 :     ParseNode*& expr = node->pn_kid;
     706         287 :     if (!Fold(cx, &expr, parser, inGenexpLambda))
     707           0 :         return false;
     708             : 
     709         287 :     if (expr->isKind(PNK_NUMBER) || expr->isKind(PNK_TRUE) || expr->isKind(PNK_FALSE)) {
     710         266 :         double d = expr->isKind(PNK_NUMBER)
     711         266 :                    ? expr->pn_dval
     712         266 :                    : double(expr->isKind(PNK_TRUE));
     713             : 
     714         266 :         if (node->isKind(PNK_BITNOT))
     715           6 :             d = ~ToInt32(d);
     716         260 :         else if (node->isKind(PNK_NEG))
     717         260 :             d = -d;
     718             :         else
     719           0 :             MOZ_ASSERT(node->isKind(PNK_POS)); // nothing to do
     720             : 
     721         266 :         parser.prepareNodeForMutation(node);
     722         266 :         node->setKind(PNK_NUMBER);
     723         266 :         node->setOp(JSOP_DOUBLE);
     724         266 :         node->setArity(PN_NULLARY);
     725         266 :         node->pn_dval = d;
     726             :     }
     727             : 
     728         287 :     return true;
     729             : }
     730             : 
     731             : static bool
     732         745 : FoldIncrementDecrement(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
     733             :                        bool inGenexpLambda)
     734             : {
     735         745 :     MOZ_ASSERT(node->isKind(PNK_PREINCREMENT) ||
     736             :                node->isKind(PNK_POSTINCREMENT) ||
     737             :                node->isKind(PNK_PREDECREMENT) ||
     738             :                node->isKind(PNK_POSTDECREMENT));
     739         745 :     MOZ_ASSERT(node->isArity(PN_UNARY));
     740             : 
     741         745 :     ParseNode*& target = node->pn_kid;
     742         745 :     MOZ_ASSERT(parser.isValidSimpleAssignmentTarget(target, Parser<FullParseHandler, char16_t>::PermitAssignmentToFunctionCalls));
     743             : 
     744         745 :     if (!Fold(cx, &target, parser, inGenexpLambda))
     745           0 :         return false;
     746             : 
     747         745 :     MOZ_ASSERT(parser.isValidSimpleAssignmentTarget(target, Parser<FullParseHandler, char16_t>::PermitAssignmentToFunctionCalls));
     748             : 
     749         745 :     return true;
     750             : }
     751             : 
     752             : static bool
     753        2233 : FoldAndOr(JSContext* cx, ParseNode** nodePtr, Parser<FullParseHandler, char16_t>& parser,
     754             :           bool inGenexpLambda)
     755             : {
     756        2233 :     ParseNode* node = *nodePtr;
     757             : 
     758        2233 :     MOZ_ASSERT(node->isKind(PNK_AND) || node->isKind(PNK_OR));
     759        2233 :     MOZ_ASSERT(node->isArity(PN_LIST));
     760             : 
     761        2233 :     bool isOrNode = node->isKind(PNK_OR);
     762        2233 :     ParseNode** elem = &node->pn_head;
     763        2634 :     do {
     764        4867 :         if (!Fold(cx, elem, parser, inGenexpLambda))
     765           0 :             return false;
     766             : 
     767        4867 :         Truthiness t = Boolish(*elem);
     768             : 
     769             :         // If we don't know the constant-folded node's truthiness, we can't
     770             :         // reduce this node with its surroundings.  Continue folding any
     771             :         // remaining nodes.
     772        4867 :         if (t == Unknown) {
     773        4773 :             elem = &(*elem)->pn_next;
     774        4773 :             continue;
     775             :         }
     776             : 
     777             :         // If the constant-folded node's truthiness will terminate the
     778             :         // condition -- `a || true || expr` or |b && false && expr| -- then
     779             :         // trailing nodes will never be evaluated.  Truncate the list after
     780             :         // the known-truthiness node, as it's the overall result.
     781          94 :         if ((t == Truthy) == isOrNode) {
     782             :             ParseNode* afterNext;
     783          15 :             for (ParseNode* next = (*elem)->pn_next; next; next = afterNext) {
     784           0 :                 afterNext = next->pn_next;
     785           0 :                 parser.handler.freeTree(next);
     786           0 :                 --node->pn_count;
     787             :             }
     788             : 
     789             :             // Terminate the original and/or list at the known-truthiness
     790             :             // node.
     791          15 :             (*elem)->pn_next = nullptr;
     792          15 :             elem = &(*elem)->pn_next;
     793          15 :             break;
     794             :         }
     795             : 
     796          79 :         MOZ_ASSERT((t == Truthy) == !isOrNode);
     797             : 
     798             :         // We've encountered a vacuous node that'll never short- circuit
     799             :         // evaluation.
     800          79 :         if ((*elem)->pn_next) {
     801             :             // This node is never the overall result when there are
     802             :             // subsequent nodes.  Remove it.
     803           0 :             ParseNode* elt = *elem;
     804           0 :             *elem = elt->pn_next;
     805           0 :             parser.handler.freeTree(elt);
     806           0 :             --node->pn_count;
     807             :         } else {
     808             :             // Otherwise this node is the result of the overall expression,
     809             :             // so leave it alone.  And we're done.
     810          79 :             elem = &(*elem)->pn_next;
     811          79 :             break;
     812             :         }
     813        4773 :     } while (*elem);
     814             : 
     815             :     // If the last node in the list was replaced, we need to update the
     816             :     // tail pointer in the original and/or node.
     817        2233 :     node->pn_tail = elem;
     818             : 
     819        2233 :     node->checkListConsistency();
     820             : 
     821             :     // If we removed nodes, we may have to replace a one-element list with
     822             :     // its element.
     823        2233 :     if (node->pn_count == 1) {
     824           0 :         ParseNode* first = node->pn_head;
     825           0 :         ReplaceNode(nodePtr, first);
     826             : 
     827           0 :         node->setKind(PNK_NULL);
     828           0 :         node->setArity(PN_NULLARY);
     829           0 :         parser.freeTree(node);
     830             :     }
     831             : 
     832        2233 :     return true;
     833             : }
     834             : 
     835             : static bool
     836         700 : FoldConditional(JSContext* cx, ParseNode** nodePtr, Parser<FullParseHandler, char16_t>& parser,
     837             :                 bool inGenexpLambda)
     838             : {
     839         700 :     ParseNode** nextNode = nodePtr;
     840             : 
     841           0 :     do {
     842             :         // |nextNode| on entry points to the C?T:F expression to be folded.
     843             :         // Reset it to exit the loop in the common case where F isn't another
     844             :         // ?: expression.
     845         700 :         nodePtr = nextNode;
     846         700 :         nextNode = nullptr;
     847             : 
     848         700 :         ParseNode* node = *nodePtr;
     849         700 :         MOZ_ASSERT(node->isKind(PNK_CONDITIONAL));
     850         700 :         MOZ_ASSERT(node->isArity(PN_TERNARY));
     851             : 
     852         700 :         ParseNode*& expr = node->pn_kid1;
     853         700 :         if (!FoldCondition(cx, &expr, parser, inGenexpLambda))
     854           0 :             return false;
     855             : 
     856         700 :         ParseNode*& ifTruthy = node->pn_kid2;
     857         700 :         if (!Fold(cx, &ifTruthy, parser, inGenexpLambda))
     858           0 :             return false;
     859             : 
     860         700 :         ParseNode*& ifFalsy = node->pn_kid3;
     861             : 
     862             :         // If our C?T:F node has F as another ?: node, *iteratively* constant-
     863             :         // fold F *after* folding C and T (and possibly eliminating C and one
     864             :         // of T/F entirely); otherwise fold F normally.  Making |nextNode| non-
     865             :         // null causes this loop to run again to fold F.
     866             :         //
     867             :         // Conceivably we could instead/also iteratively constant-fold T, if T
     868             :         // were more complex than F.  Such an optimization is unimplemented.
     869         700 :         if (ifFalsy->isKind(PNK_CONDITIONAL)) {
     870           0 :             nextNode = &ifFalsy;
     871             :         } else {
     872         700 :             if (!Fold(cx, &ifFalsy, parser, inGenexpLambda))
     873           0 :                 return false;
     874             :         }
     875             : 
     876             :         // Try to constant-fold based on the condition expression.
     877         700 :         Truthiness t = Boolish(expr);
     878         700 :         if (t == Unknown)
     879         700 :             continue;
     880             : 
     881             :         // Otherwise reduce 'C ? T : F' to T or F as directed by C.
     882             :         ParseNode* replacement;
     883             :         ParseNode* discarded;
     884           0 :         if (t == Truthy) {
     885           0 :             replacement = ifTruthy;
     886           0 :             discarded = ifFalsy;
     887             :         } else {
     888           0 :             replacement = ifFalsy;
     889           0 :             discarded = ifTruthy;
     890             :         }
     891             : 
     892             :         // Otherwise perform a replacement.  This invalidates |nextNode|, so
     893             :         // reset it (if the replacement requires folding) or clear it (if
     894             :         // |ifFalsy| is dead code) as needed.
     895           0 :         if (nextNode)
     896           0 :             nextNode = (*nextNode == replacement) ? nodePtr : nullptr;
     897           0 :         ReplaceNode(nodePtr, replacement);
     898             : 
     899           0 :         parser.freeTree(discarded);
     900         700 :     } while (nextNode);
     901             : 
     902         700 :     return true;
     903             : }
     904             : 
     905             : static bool
     906        7222 : FoldIf(JSContext* cx, ParseNode** nodePtr, Parser<FullParseHandler, char16_t>& parser,
     907             :        bool inGenexpLambda)
     908             : {
     909        7222 :     ParseNode** nextNode = nodePtr;
     910             : 
     911         307 :     do {
     912             :         // |nextNode| on entry points to the initial |if| to be folded.  Reset
     913             :         // it to exit the loop when the |else| arm isn't another |if|.
     914        7529 :         nodePtr = nextNode;
     915        7529 :         nextNode = nullptr;
     916             : 
     917        7529 :         ParseNode* node = *nodePtr;
     918        7529 :         MOZ_ASSERT(node->isKind(PNK_IF));
     919        7529 :         MOZ_ASSERT(node->isArity(PN_TERNARY));
     920             : 
     921        7529 :         ParseNode*& expr = node->pn_kid1;
     922        7529 :         if (!FoldCondition(cx, &expr, parser, inGenexpLambda))
     923           0 :             return false;
     924             : 
     925        7529 :         ParseNode*& consequent = node->pn_kid2;
     926        7529 :         if (!Fold(cx, &consequent, parser, inGenexpLambda))
     927           0 :             return false;
     928             : 
     929        7529 :         ParseNode*& alternative = node->pn_kid3;
     930        7529 :         if (alternative) {
     931             :             // If in |if (C) T; else F;| we have |F| as another |if|,
     932             :             // *iteratively* constant-fold |F| *after* folding |C| and |T| (and
     933             :             // possibly completely replacing the whole thing with |T| or |F|);
     934             :             // otherwise fold F normally.  Making |nextNode| non-null causes
     935             :             // this loop to run again to fold F.
     936         972 :             if (alternative->isKind(PNK_IF)) {
     937         307 :                 nextNode = &alternative;
     938             :             } else {
     939         665 :                 if (!Fold(cx, &alternative, parser, inGenexpLambda))
     940           0 :                     return false;
     941             :             }
     942             :         }
     943             : 
     944             :         // Eliminate the consequent or alternative if the condition has
     945             :         // constant truthiness.  Don't eliminate if we have an |if (0)| in
     946             :         // trailing position in a generator expression, as this is a special
     947             :         // form we can't fold away.
     948        7529 :         Truthiness t = Boolish(expr);
     949        7529 :         if (t == Unknown || inGenexpLambda)
     950        7481 :             continue;
     951             : 
     952             :         // Careful!  Either of these can be null: |replacement| in |if (0) T;|,
     953             :         // and |discarded| in |if (true) T;|.
     954             :         ParseNode* replacement;
     955             :         ParseNode* discarded;
     956          48 :         if (t == Truthy) {
     957          39 :             replacement = consequent;
     958          39 :             discarded = alternative;
     959             :         } else {
     960           9 :             replacement = alternative;
     961           9 :             discarded = consequent;
     962             :         }
     963             : 
     964          48 :         bool performReplacement = true;
     965          48 :         if (discarded) {
     966             :             // A declaration that hoists outside the discarded arm prevents the
     967             :             // |if| from being folded away.
     968             :             bool containsHoistedDecls;
     969           9 :             if (!ContainsHoistedDeclaration(cx, discarded, &containsHoistedDecls))
     970           0 :                 return false;
     971             : 
     972           9 :             performReplacement = !containsHoistedDecls;
     973             :         }
     974             : 
     975          48 :         if (!performReplacement)
     976           0 :             continue;
     977             : 
     978          48 :         if (!replacement) {
     979             :             // If there's no replacement node, we have a constantly-false |if|
     980             :             // with no |else|.  Replace the entire thing with an empty
     981             :             // statement list.
     982           9 :             parser.prepareNodeForMutation(node);
     983           9 :             node->setKind(PNK_STATEMENTLIST);
     984           9 :             node->setArity(PN_LIST);
     985           9 :             node->makeEmpty();
     986             :         } else {
     987             :             // Replacement invalidates |nextNode|, so reset it (if the
     988             :             // replacement requires folding) or clear it (if |alternative|
     989             :             // is dead code) as needed.
     990          39 :             if (nextNode)
     991           0 :                 nextNode = (*nextNode == replacement) ? nodePtr : nullptr;
     992          39 :             ReplaceNode(nodePtr, replacement);
     993             : 
     994             :             // Morph the original node into a discardable node, then
     995             :             // aggressively free it and the discarded arm (if any) to suss out
     996             :             // any bugs in the preceding logic.
     997          39 :             node->setKind(PNK_STATEMENTLIST);
     998          39 :             node->setArity(PN_LIST);
     999          39 :             node->makeEmpty();
    1000          39 :             if (discarded)
    1001           0 :                 node->append(discarded);
    1002          39 :             parser.freeTree(node);
    1003             :         }
    1004        7529 :     } while (nextNode);
    1005             : 
    1006        7222 :     return true;
    1007             : }
    1008             : 
    1009             : static bool
    1010        7891 : FoldFunction(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
    1011             :              bool inGenexpLambda)
    1012             : {
    1013        7891 :     MOZ_ASSERT(node->isKind(PNK_FUNCTION));
    1014        7891 :     MOZ_ASSERT(node->isArity(PN_CODE));
    1015             : 
    1016             :     // Don't constant-fold inside "use asm" code, as this could create a parse
    1017             :     // tree that doesn't type-check as asm.js.
    1018        7891 :     if (node->pn_funbox->useAsmOrInsideUseAsm())
    1019           0 :         return true;
    1020             : 
    1021             :     // Note: pn_body is null for lazily-parsed functions.
    1022        7891 :     if (ParseNode*& functionBody = node->pn_body) {
    1023        5859 :         if (!Fold(cx, &functionBody, parser, node->pn_funbox->isGenexpLambda))
    1024           0 :             return false;
    1025             :     }
    1026             : 
    1027        7891 :     return true;
    1028             : }
    1029             : 
    1030             : static double
    1031         102 : ComputeBinary(ParseNodeKind kind, double left, double right)
    1032             : {
    1033         102 :     if (kind == PNK_ADD)
    1034           0 :         return left + right;
    1035             : 
    1036         102 :     if (kind == PNK_SUB)
    1037           6 :         return left - right;
    1038             : 
    1039          96 :     if (kind == PNK_STAR)
    1040          90 :         return left * right;
    1041             : 
    1042           6 :     if (kind == PNK_MOD)
    1043           0 :         return right == 0 ? GenericNaN() : js_fmod(left, right);
    1044             : 
    1045           6 :     if (kind == PNK_URSH)
    1046           0 :         return ToUint32(left) >> (ToUint32(right) & 31);
    1047             : 
    1048           6 :     if (kind == PNK_DIV) {
    1049           0 :         if (right == 0) {
    1050             : #if defined(XP_WIN)
    1051             :             /* XXX MSVC miscompiles such that (NaN == 0) */
    1052             :             if (IsNaN(right))
    1053             :                 return GenericNaN();
    1054             : #endif
    1055           0 :             if (left == 0 || IsNaN(left))
    1056           0 :                 return GenericNaN();
    1057           0 :             if (IsNegative(left) != IsNegative(right))
    1058           0 :                 return NegativeInfinity<double>();
    1059           0 :             return PositiveInfinity<double>();
    1060             :         }
    1061             : 
    1062           0 :         return left / right;
    1063             :     }
    1064             : 
    1065           6 :     MOZ_ASSERT(kind == PNK_LSH || kind == PNK_RSH);
    1066             : 
    1067           6 :     int32_t i = ToInt32(left);
    1068           6 :     uint32_t j = ToUint32(right) & 31;
    1069           6 :     return int32_t((kind == PNK_LSH) ? uint32_t(i) << j : i >> j);
    1070             : }
    1071             : 
    1072             : static bool
    1073           0 : FoldModule(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser)
    1074             : {
    1075           0 :     MOZ_ASSERT(node->isKind(PNK_MODULE));
    1076           0 :     MOZ_ASSERT(node->isArity(PN_CODE));
    1077             : 
    1078           0 :     ParseNode*& moduleBody = node->pn_body;
    1079           0 :     MOZ_ASSERT(moduleBody);
    1080           0 :     return Fold(cx, &moduleBody, parser, false);
    1081             : }
    1082             : 
    1083             : static bool
    1084         743 : FoldBinaryArithmetic(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
    1085             :                      bool inGenexpLambda)
    1086             : {
    1087         743 :     MOZ_ASSERT(node->isKind(PNK_SUB) ||
    1088             :                node->isKind(PNK_STAR) ||
    1089             :                node->isKind(PNK_LSH) ||
    1090             :                node->isKind(PNK_RSH) ||
    1091             :                node->isKind(PNK_URSH) ||
    1092             :                node->isKind(PNK_DIV) ||
    1093             :                node->isKind(PNK_MOD));
    1094         743 :     MOZ_ASSERT(node->isArity(PN_LIST));
    1095         743 :     MOZ_ASSERT(node->pn_count >= 2);
    1096             : 
    1097             :     // Fold each operand, ideally into a number.
    1098         743 :     ParseNode** listp = &node->pn_head;
    1099        3793 :     for (; *listp; listp = &(*listp)->pn_next) {
    1100        1525 :         if (!Fold(cx, listp, parser, inGenexpLambda))
    1101           0 :             return false;
    1102             : 
    1103        1525 :         if (!FoldType(cx, *listp, PNK_NUMBER))
    1104           0 :             return false;
    1105             :     }
    1106             : 
    1107             :     // Repoint the list's tail pointer.
    1108         743 :     node->pn_tail = listp;
    1109             : 
    1110             :     // Now fold all leading numeric terms together into a single number.
    1111             :     // (Trailing terms for the non-shift operations can't be folded together
    1112             :     // due to floating point imprecision.  For example, if |x === -2**53|,
    1113             :     // |x - 1 - 1 === -2**53| but |x - 2 === -2**53 - 2|.  Shifts could be
    1114             :     // folded, but it doesn't seem worth the effort.)
    1115         743 :     ParseNode* elem = node->pn_head;
    1116         743 :     ParseNode* next = elem->pn_next;
    1117         743 :     if (elem->isKind(PNK_NUMBER)) {
    1118         116 :         ParseNodeKind kind = node->getKind();
    1119             :         while (true) {
    1120         218 :             if (!next || !next->isKind(PNK_NUMBER))
    1121         116 :                 break;
    1122             : 
    1123         102 :             double d = ComputeBinary(kind, elem->pn_dval, next->pn_dval);
    1124             : 
    1125         102 :             ParseNode* afterNext = next->pn_next;
    1126         102 :             parser.freeTree(next);
    1127         102 :             next = afterNext;
    1128         102 :             elem->pn_next = next;
    1129             : 
    1130         102 :             elem->setKind(PNK_NUMBER);
    1131         102 :             elem->setOp(JSOP_DOUBLE);
    1132         102 :             elem->setArity(PN_NULLARY);
    1133         102 :             elem->pn_dval = d;
    1134             : 
    1135         102 :             node->pn_count--;
    1136         102 :         }
    1137             : 
    1138         116 :         if (node->pn_count == 1) {
    1139          72 :             MOZ_ASSERT(node->pn_head == elem);
    1140          72 :             MOZ_ASSERT(elem->isKind(PNK_NUMBER));
    1141             : 
    1142          72 :             double d = elem->pn_dval;
    1143          72 :             node->setKind(PNK_NUMBER);
    1144          72 :             node->setArity(PN_NULLARY);
    1145          72 :             node->setOp(JSOP_DOUBLE);
    1146          72 :             node->pn_dval = d;
    1147             : 
    1148          72 :             parser.freeTree(elem);
    1149             :         }
    1150             :     }
    1151             : 
    1152         743 :     return true;
    1153             : }
    1154             : 
    1155             : static bool
    1156           0 : FoldExponentiation(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
    1157             :                    bool inGenexpLambda)
    1158             : {
    1159           0 :     MOZ_ASSERT(node->isKind(PNK_POW));
    1160           0 :     MOZ_ASSERT(node->isArity(PN_LIST));
    1161           0 :     MOZ_ASSERT(node->pn_count >= 2);
    1162             : 
    1163             :     // Fold each operand, ideally into a number.
    1164           0 :     ParseNode** listp = &node->pn_head;
    1165           0 :     for (; *listp; listp = &(*listp)->pn_next) {
    1166           0 :         if (!Fold(cx, listp, parser, inGenexpLambda))
    1167           0 :             return false;
    1168             : 
    1169           0 :         if (!FoldType(cx, *listp, PNK_NUMBER))
    1170           0 :             return false;
    1171             :     }
    1172             : 
    1173             :     // Repoint the list's tail pointer.
    1174           0 :     node->pn_tail = listp;
    1175             : 
    1176             :     // Unlike all other binary arithmetic operators, ** is right-associative:
    1177             :     // 2**3**5 is 2**(3**5), not (2**3)**5.  As list nodes singly-link their
    1178             :     // children, full constant-folding requires either linear space or dodgy
    1179             :     // in-place linked list reversal.  So we only fold one exponentiation: it's
    1180             :     // easy and addresses common cases like |2**32|.
    1181           0 :     if (node->pn_count > 2)
    1182           0 :         return true;
    1183             : 
    1184           0 :     ParseNode* base = node->pn_head;
    1185           0 :     ParseNode* exponent = base->pn_next;
    1186           0 :     if (!base->isKind(PNK_NUMBER) || !exponent->isKind(PNK_NUMBER))
    1187           0 :         return true;
    1188             : 
    1189           0 :     double d1 = base->pn_dval, d2 = exponent->pn_dval;
    1190             : 
    1191           0 :     parser.prepareNodeForMutation(node);
    1192           0 :     node->setKind(PNK_NUMBER);
    1193           0 :     node->setArity(PN_NULLARY);
    1194           0 :     node->setOp(JSOP_DOUBLE);
    1195           0 :     node->pn_dval = ecmaPow(d1, d2);
    1196           0 :     return true;
    1197             : }
    1198             : 
    1199             : static bool
    1200       46281 : FoldList(JSContext* cx, ParseNode* list, Parser<FullParseHandler, char16_t>& parser,
    1201             :          bool inGenexpLambda)
    1202             : {
    1203       46281 :     MOZ_ASSERT(list->isArity(PN_LIST));
    1204             : 
    1205       46281 :     ParseNode** elem = &list->pn_head;
    1206      256301 :     for (; *elem; elem = &(*elem)->pn_next) {
    1207      105010 :         if (!Fold(cx, elem, parser, inGenexpLambda))
    1208           0 :             return false;
    1209             :     }
    1210             : 
    1211             :     // Repoint the list's tail pointer if the final element was replaced.
    1212       46281 :     list->pn_tail = elem;
    1213             : 
    1214       46281 :     list->checkListConsistency();
    1215             : 
    1216       46281 :     return true;
    1217             : }
    1218             : 
    1219             : static bool
    1220        6615 : FoldReturn(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
    1221             :            bool inGenexpLambda)
    1222             : {
    1223        6615 :     MOZ_ASSERT(node->isKind(PNK_RETURN));
    1224        6615 :     MOZ_ASSERT(node->isArity(PN_UNARY));
    1225             : 
    1226        6615 :     if (ParseNode*& expr = node->pn_kid) {
    1227        6086 :         if (!Fold(cx, &expr, parser, inGenexpLambda))
    1228           0 :             return false;
    1229             :     }
    1230             : 
    1231        6615 :     return true;
    1232             : }
    1233             : 
    1234             : static bool
    1235         513 : FoldTry(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
    1236             :         bool inGenexpLambda)
    1237             : {
    1238         513 :     MOZ_ASSERT(node->isKind(PNK_TRY));
    1239         513 :     MOZ_ASSERT(node->isArity(PN_TERNARY));
    1240             : 
    1241         513 :     ParseNode*& statements = node->pn_kid1;
    1242         513 :     if (!Fold(cx, &statements, parser, inGenexpLambda))
    1243           0 :         return false;
    1244             : 
    1245         513 :     if (ParseNode*& catchList = node->pn_kid2) {
    1246         491 :         if (!Fold(cx, &catchList, parser, inGenexpLambda))
    1247           0 :             return false;
    1248             :     }
    1249             : 
    1250         513 :     if (ParseNode*& finally = node->pn_kid3) {
    1251          41 :         if (!Fold(cx, &finally, parser, inGenexpLambda))
    1252           0 :             return false;
    1253             :     }
    1254             : 
    1255         513 :     return true;
    1256             : }
    1257             : 
    1258             : static bool
    1259         491 : FoldCatch(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
    1260             :           bool inGenexpLambda)
    1261             : {
    1262         491 :     MOZ_ASSERT(node->isKind(PNK_CATCH));
    1263         491 :     MOZ_ASSERT(node->isArity(PN_TERNARY));
    1264             : 
    1265         491 :     ParseNode*& declPattern = node->pn_kid1;
    1266         491 :     if (!Fold(cx, &declPattern, parser, inGenexpLambda))
    1267           0 :         return false;
    1268             : 
    1269         491 :     if (ParseNode*& cond = node->pn_kid2) {
    1270           0 :         if (!FoldCondition(cx, &cond, parser, inGenexpLambda))
    1271           0 :             return false;
    1272             :     }
    1273             : 
    1274         491 :     if (ParseNode*& statements = node->pn_kid3) {
    1275         491 :         if (!Fold(cx, &statements, parser, inGenexpLambda))
    1276           0 :             return false;
    1277             :     }
    1278             : 
    1279         491 :     return true;
    1280             : }
    1281             : 
    1282             : static bool
    1283          32 : FoldClass(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
    1284             :           bool inGenexpLambda)
    1285             : {
    1286          32 :     MOZ_ASSERT(node->isKind(PNK_CLASS));
    1287          32 :     MOZ_ASSERT(node->isArity(PN_TERNARY));
    1288             : 
    1289          32 :     if (ParseNode*& classNames = node->pn_kid1) {
    1290          26 :         if (!Fold(cx, &classNames, parser, inGenexpLambda))
    1291           0 :             return false;
    1292             :     }
    1293             : 
    1294          32 :     if (ParseNode*& heritage = node->pn_kid2) {
    1295          16 :         if (!Fold(cx, &heritage, parser, inGenexpLambda))
    1296           0 :             return false;
    1297             :     }
    1298             : 
    1299          32 :     ParseNode*& body = node->pn_kid3;
    1300          32 :     return Fold(cx, &body, parser, inGenexpLambda);
    1301             : }
    1302             : 
    1303             : static bool
    1304        3252 : FoldElement(JSContext* cx, ParseNode** nodePtr, Parser<FullParseHandler, char16_t>& parser,
    1305             :             bool inGenexpLambda)
    1306             : {
    1307        3252 :     ParseNode* node = *nodePtr;
    1308             : 
    1309        3252 :     MOZ_ASSERT(node->isKind(PNK_ELEM));
    1310        3252 :     MOZ_ASSERT(node->isArity(PN_BINARY));
    1311             : 
    1312        3252 :     ParseNode*& expr = node->pn_left;
    1313        3252 :     if (!Fold(cx, &expr, parser, inGenexpLambda))
    1314           0 :         return false;
    1315             : 
    1316        3252 :     ParseNode*& key = node->pn_right;
    1317        3252 :     if (!Fold(cx, &key, parser, inGenexpLambda))
    1318           0 :         return false;
    1319             : 
    1320        3252 :     PropertyName* name = nullptr;
    1321        3252 :     if (key->isKind(PNK_STRING)) {
    1322         238 :         JSAtom* atom = key->pn_atom;
    1323             :         uint32_t index;
    1324             : 
    1325         238 :         if (atom->isIndex(&index)) {
    1326             :             // Optimization 1: We have something like expr["100"]. This is
    1327             :             // equivalent to expr[100] which is faster.
    1328           0 :             key->setKind(PNK_NUMBER);
    1329           0 :             key->setOp(JSOP_DOUBLE);
    1330           0 :             key->pn_dval = index;
    1331             :         } else {
    1332         238 :             name = atom->asPropertyName();
    1333             :         }
    1334        3014 :     } else if (key->isKind(PNK_NUMBER)) {
    1335        1442 :         double number = key->pn_dval;
    1336        1442 :         if (number != ToUint32(number)) {
    1337             :             // Optimization 2: We have something like expr[3.14]. The number
    1338             :             // isn't an array index, so it converts to a string ("3.14"),
    1339             :             // enabling optimization 3 below.
    1340           0 :             JSAtom* atom = ToAtom<NoGC>(cx, DoubleValue(number));
    1341           0 :             if (!atom)
    1342           0 :                 return false;
    1343           0 :             name = atom->asPropertyName();
    1344             :         }
    1345             :     }
    1346             : 
    1347             :     // If we don't have a name, we can't optimize to getprop.
    1348        3252 :     if (!name)
    1349        3014 :         return true;
    1350             : 
    1351             :     // Optimization 3: We have expr["foo"] where foo is not an index.  Convert
    1352             :     // to a property access (like expr.foo) that optimizes better downstream.
    1353         238 :     ParseNode* dottedAccess = parser.handler.newPropertyAccess(expr, name, node->pn_pos.end);
    1354         238 :     if (!dottedAccess)
    1355           0 :         return false;
    1356         238 :     dottedAccess->setInParens(node->isInParens());
    1357         238 :     ReplaceNode(nodePtr, dottedAccess);
    1358             : 
    1359             :     // If we've replaced |expr["prop"]| with |expr.prop|, we can now free the
    1360             :     // |"prop"| and |expr["prop"]| nodes -- but not the |expr| node that we're
    1361             :     // now using as a sub-node of |dottedAccess|.  Munge |expr["prop"]| into a
    1362             :     // node with |"prop"| as its only child, that'll pass AST sanity-checking
    1363             :     // assertions during freeing, then free it.
    1364         238 :     node->setKind(PNK_TYPEOFEXPR);
    1365         238 :     node->setArity(PN_UNARY);
    1366         238 :     node->pn_kid = key;
    1367         238 :     parser.freeTree(node);
    1368             : 
    1369         238 :     return true;
    1370             : }
    1371             : 
    1372             : static bool
    1373        2465 : FoldAdd(JSContext* cx, ParseNode** nodePtr, Parser<FullParseHandler, char16_t>& parser,
    1374             :         bool inGenexpLambda)
    1375             : {
    1376        2465 :     ParseNode* node = *nodePtr;
    1377             : 
    1378        2465 :     MOZ_ASSERT(node->isKind(PNK_ADD));
    1379        2465 :     MOZ_ASSERT(node->isArity(PN_LIST));
    1380        2465 :     MOZ_ASSERT(node->pn_count >= 2);
    1381             : 
    1382             :     // Generically fold all operands first.
    1383        2465 :     if (!FoldList(cx, node, parser, inGenexpLambda))
    1384           0 :         return false;
    1385             : 
    1386             :     // Fold leading numeric operands together:
    1387             :     //
    1388             :     //   (1 + 2 + x)  becomes  (3 + x)
    1389             :     //
    1390             :     // Don't go past the leading operands: additions after a string are
    1391             :     // string concatenations, not additions: ("1" + 2 + 3 === "123").
    1392        2465 :     ParseNode* current = node->pn_head;
    1393        2465 :     ParseNode* next = current->pn_next;
    1394        2465 :     if (current->isKind(PNK_NUMBER)) {
    1395           0 :         do {
    1396           6 :             if (!next->isKind(PNK_NUMBER))
    1397           6 :                 break;
    1398             : 
    1399           0 :             current->pn_dval += next->pn_dval;
    1400           0 :             current->pn_next = next->pn_next;
    1401           0 :             parser.freeTree(next);
    1402           0 :             next = current->pn_next;
    1403             : 
    1404           0 :             MOZ_ASSERT(node->pn_count > 1);
    1405           0 :             node->pn_count--;
    1406           0 :         } while (next);
    1407             :     }
    1408             : 
    1409             :     // If any operands remain, attempt string concatenation folding.
    1410             :     do {
    1411             :         // If no operands remain, we're done.
    1412        2465 :         if (!next)
    1413        1158 :             break;
    1414             : 
    1415             :         // (number + string) is string concatenation *only* at the start of
    1416             :         // the list: (x + 1 + "2" !== x + "12") when x is a number.
    1417        2465 :         if (current->isKind(PNK_NUMBER) && next->isKind(PNK_STRING)) {
    1418           0 :             if (!FoldType(cx, current, PNK_STRING))
    1419           0 :                 return false;
    1420           0 :             next = current->pn_next;
    1421             :         }
    1422             : 
    1423             :         // The first string forces all subsequent additions to be
    1424             :         // string concatenations.
    1425         116 :         do {
    1426        2581 :             if (current->isKind(PNK_STRING))
    1427        1307 :                 break;
    1428             : 
    1429        1274 :             current = next;
    1430        1274 :             next = next->pn_next;
    1431        1274 :         } while (next);
    1432             : 
    1433             :         // If there's nothing left to fold, we're done.
    1434        2465 :         if (!next)
    1435        1158 :             break;
    1436             : 
    1437        2614 :         RootedString combination(cx);
    1438        2614 :         RootedString tmp(cx);
    1439         253 :         do {
    1440             :             // Create a rope of the current string and all succeeding
    1441             :             // constants that we can convert to strings, then atomize it
    1442             :             // and replace them all with that fresh string.
    1443        1560 :             MOZ_ASSERT(current->isKind(PNK_STRING));
    1444             : 
    1445        1560 :             combination = current->pn_atom;
    1446             : 
    1447        1816 :             do {
    1448             :                 // Try folding the next operand to a string.
    1449        3376 :                 if (!FoldType(cx, next, PNK_STRING))
    1450           0 :                     return false;
    1451             : 
    1452             :                 // Stop glomming once folding doesn't produce a string.
    1453        3376 :                 if (!next->isKind(PNK_STRING))
    1454        1002 :                     break;
    1455             : 
    1456             :                 // Add this string to the combination and remove the node.
    1457        2374 :                 tmp = next->pn_atom;
    1458        2374 :                 combination = ConcatStrings<CanGC>(cx, combination, tmp);
    1459        2374 :                 if (!combination)
    1460           0 :                     return false;
    1461             : 
    1462        2374 :                 current->pn_next = next->pn_next;
    1463        2374 :                 parser.freeTree(next);
    1464        2374 :                 next = current->pn_next;
    1465             : 
    1466        2374 :                 MOZ_ASSERT(node->pn_count > 1);
    1467        2374 :                 node->pn_count--;
    1468        2374 :             } while (next);
    1469             : 
    1470             :             // Replace |current|'s string with the entire combination.
    1471        1560 :             MOZ_ASSERT(current->isKind(PNK_STRING));
    1472        1560 :             combination = AtomizeString(cx, combination);
    1473        1560 :             if (!combination)
    1474           0 :                 return false;
    1475        1560 :             current->pn_atom = &combination->asAtom();
    1476             : 
    1477             : 
    1478             :             // If we're out of nodes, we're done.
    1479        1560 :             if (!next)
    1480         558 :                 break;
    1481             : 
    1482        1002 :             current = next;
    1483        1002 :             next = current->pn_next;
    1484             : 
    1485             :             // If we're out of nodes *after* the non-foldable-to-string
    1486             :             // node, we're done.
    1487        1002 :             if (!next)
    1488         506 :                 break;
    1489             : 
    1490             :             // Otherwise find the next node foldable to a string, and loop.
    1491         517 :             do {
    1492         517 :                 current = next;
    1493         517 :                 next = current->pn_next;
    1494             : 
    1495         517 :                 if (!FoldType(cx, current, PNK_STRING))
    1496           0 :                     return false;
    1497         517 :                 next = current->pn_next;
    1498         517 :             } while (!current->isKind(PNK_STRING) && next);
    1499         496 :         } while (next);
    1500             :     } while (false);
    1501             : 
    1502        2465 :     MOZ_ASSERT(!next, "must have considered all nodes here");
    1503        2465 :     MOZ_ASSERT(!current->pn_next, "current node must be the last node");
    1504             : 
    1505        2465 :     node->pn_tail = &current->pn_next;
    1506        2465 :     node->checkListConsistency();
    1507             : 
    1508        2465 :     if (node->pn_count == 1) {
    1509             :         // We reduced the list to a constant.  Replace the PNK_ADD node
    1510             :         // with that constant.
    1511         551 :         ReplaceNode(nodePtr, current);
    1512             : 
    1513             :         // Free the old node to aggressively verify nothing uses it.
    1514         551 :         node->setKind(PNK_TRUE);
    1515         551 :         node->setArity(PN_NULLARY);
    1516         551 :         node->setOp(JSOP_TRUE);
    1517         551 :         parser.freeTree(node);
    1518             :     }
    1519             : 
    1520        2465 :     return true;
    1521             : }
    1522             : 
    1523             : static bool
    1524       22883 : FoldCall(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
    1525             :          bool inGenexpLambda)
    1526             : {
    1527       22883 :     MOZ_ASSERT(node->isKind(PNK_CALL) || node->isKind(PNK_SUPERCALL) ||
    1528             :                node->isKind(PNK_TAGGED_TEMPLATE));
    1529       22883 :     MOZ_ASSERT(node->isArity(PN_LIST));
    1530             : 
    1531             :     // Don't fold a parenthesized callable component in an invocation, as this
    1532             :     // might cause a different |this| value to be used, changing semantics:
    1533             :     //
    1534             :     //   var prop = "global";
    1535             :     //   var obj = { prop: "obj", f: function() { return this.prop; } };
    1536             :     //   assertEq((true ? obj.f : null)(), "global");
    1537             :     //   assertEq(obj.f(), "obj");
    1538             :     //   assertEq((true ? obj.f : null)``, "global");
    1539             :     //   assertEq(obj.f``, "obj");
    1540             :     //
    1541             :     // See bug 537673 and bug 1182373.
    1542       22883 :     ParseNode** listp = &node->pn_head;
    1543       22883 :     if ((*listp)->isInParens())
    1544          48 :         listp = &(*listp)->pn_next;
    1545             : 
    1546      144261 :     for (; *listp; listp = &(*listp)->pn_next) {
    1547       60689 :         if (!Fold(cx, listp, parser, inGenexpLambda))
    1548           0 :             return false;
    1549             :     }
    1550             : 
    1551             :     // If the last node in the list was replaced, pn_tail points into the wrong node.
    1552       22883 :     node->pn_tail = listp;
    1553             : 
    1554       22883 :     node->checkListConsistency();
    1555       22883 :     return true;
    1556             : }
    1557             : 
    1558             : static bool
    1559         384 : FoldForInOrOf(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
    1560             :               bool inGenexpLambda)
    1561             : {
    1562         384 :     MOZ_ASSERT(node->isKind(PNK_FORIN) || node->isKind(PNK_FOROF));
    1563         384 :     MOZ_ASSERT(node->isArity(PN_TERNARY));
    1564         384 :     MOZ_ASSERT(!node->pn_kid2);
    1565             : 
    1566         768 :     return Fold(cx, &node->pn_kid1, parser, inGenexpLambda) &&
    1567         768 :            Fold(cx, &node->pn_kid3, parser, inGenexpLambda);
    1568             : }
    1569             : 
    1570             : static bool
    1571         471 : FoldForHead(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
    1572             :             bool inGenexpLambda)
    1573             : {
    1574         471 :     MOZ_ASSERT(node->isKind(PNK_FORHEAD));
    1575         471 :     MOZ_ASSERT(node->isArity(PN_TERNARY));
    1576             : 
    1577         471 :     if (ParseNode*& init = node->pn_kid1) {
    1578         423 :         if (!Fold(cx, &init, parser, inGenexpLambda))
    1579           0 :             return false;
    1580             :     }
    1581             : 
    1582         471 :     if (ParseNode*& test = node->pn_kid2) {
    1583         462 :         if (!FoldCondition(cx, &test, parser, inGenexpLambda))
    1584           0 :             return false;
    1585             : 
    1586         462 :         if (test->isKind(PNK_TRUE)) {
    1587           0 :             parser.freeTree(test);
    1588           0 :             test = nullptr;
    1589             :         }
    1590             :     }
    1591             : 
    1592         471 :     if (ParseNode*& update = node->pn_kid3) {
    1593         462 :         if (!Fold(cx, &update, parser, inGenexpLambda))
    1594           0 :             return false;
    1595             :     }
    1596             : 
    1597         471 :     return true;
    1598             : }
    1599             : 
    1600             : static bool
    1601       27629 : FoldDottedProperty(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
    1602             :                    bool inGenexpLambda)
    1603             : {
    1604       27629 :     MOZ_ASSERT(node->isKind(PNK_DOT));
    1605       27629 :     MOZ_ASSERT(node->isArity(PN_NAME));
    1606             : 
    1607             :     // Iterate through a long chain of dotted property accesses to find the
    1608             :     // most-nested non-dotted property node, then fold that.
    1609       27629 :     ParseNode** nested = &node->pn_expr;
    1610       37097 :     while ((*nested)->isKind(PNK_DOT)) {
    1611        4734 :         MOZ_ASSERT((*nested)->isArity(PN_NAME));
    1612        4734 :         nested = &(*nested)->pn_expr;
    1613             :     }
    1614             : 
    1615       27629 :     return Fold(cx, nested, parser, inGenexpLambda);
    1616             : }
    1617             : 
    1618             : static bool
    1619       98435 : FoldName(JSContext* cx, ParseNode* node, Parser<FullParseHandler, char16_t>& parser,
    1620             :          bool inGenexpLambda)
    1621             : {
    1622       98435 :     MOZ_ASSERT(node->isKind(PNK_NAME));
    1623       98435 :     MOZ_ASSERT(node->isArity(PN_NAME));
    1624             : 
    1625       98435 :     if (!node->pn_expr)
    1626       88915 :         return true;
    1627             : 
    1628        9520 :     return Fold(cx, &node->pn_expr, parser, inGenexpLambda);
    1629             : }
    1630             : 
    1631             : bool
    1632      343048 : Fold(JSContext* cx, ParseNode** pnp, Parser<FullParseHandler, char16_t>& parser,
    1633             :      bool inGenexpLambda)
    1634             : {
    1635      343048 :     if (!CheckRecursionLimit(cx))
    1636           0 :         return false;
    1637             : 
    1638      343048 :     ParseNode* pn = *pnp;
    1639             : 
    1640      343048 :     switch (pn->getKind()) {
    1641             :       case PNK_NOP:
    1642             :       case PNK_REGEXP:
    1643             :       case PNK_STRING:
    1644             :       case PNK_TRUE:
    1645             :       case PNK_FALSE:
    1646             :       case PNK_NULL:
    1647             :       case PNK_RAW_UNDEFINED:
    1648             :       case PNK_ELISION:
    1649             :       case PNK_NUMBER:
    1650             :       case PNK_DEBUGGER:
    1651             :       case PNK_BREAK:
    1652             :       case PNK_CONTINUE:
    1653             :       case PNK_TEMPLATE_STRING:
    1654             :       case PNK_GENERATOR:
    1655             :       case PNK_EXPORT_BATCH_SPEC:
    1656             :       case PNK_OBJECT_PROPERTY_NAME:
    1657             :       case PNK_POSHOLDER:
    1658       53690 :         MOZ_ASSERT(pn->isArity(PN_NULLARY));
    1659       53690 :         return true;
    1660             : 
    1661             :       case PNK_SUPERBASE:
    1662             :       case PNK_TYPEOFNAME:
    1663         477 :         MOZ_ASSERT(pn->isArity(PN_UNARY));
    1664         477 :         MOZ_ASSERT(pn->pn_kid->isKind(PNK_NAME));
    1665         477 :         MOZ_ASSERT(!pn->pn_kid->expr());
    1666         477 :         return true;
    1667             : 
    1668             :       case PNK_TYPEOFEXPR:
    1669          73 :         return FoldTypeOfExpr(cx, pn, parser, inGenexpLambda);
    1670             : 
    1671             :       case PNK_DELETENAME: {
    1672           0 :         MOZ_ASSERT(pn->isArity(PN_UNARY));
    1673           0 :         MOZ_ASSERT(pn->pn_kid->isKind(PNK_NAME));
    1674           0 :         return true;
    1675             :       }
    1676             : 
    1677             :       case PNK_DELETEEXPR:
    1678           0 :         return FoldDeleteExpr(cx, pn, parser, inGenexpLambda);
    1679             : 
    1680             :       case PNK_DELETEELEM:
    1681          40 :         return FoldDeleteElement(cx, pn, parser, inGenexpLambda);
    1682             : 
    1683             :       case PNK_DELETEPROP:
    1684          58 :         return FoldDeleteProperty(cx, pn, parser, inGenexpLambda);
    1685             : 
    1686             :       case PNK_CONDITIONAL:
    1687         700 :         return FoldConditional(cx, pnp, parser, inGenexpLambda);
    1688             : 
    1689             :       case PNK_IF:
    1690        7222 :         return FoldIf(cx, pnp, parser, inGenexpLambda);
    1691             : 
    1692             :       case PNK_NOT:
    1693        3082 :         return FoldNot(cx, pn, parser, inGenexpLambda);
    1694             : 
    1695             :       case PNK_BITNOT:
    1696             :       case PNK_POS:
    1697             :       case PNK_NEG:
    1698         287 :         return FoldUnaryArithmetic(cx, pn, parser, inGenexpLambda);
    1699             : 
    1700             :       case PNK_PREINCREMENT:
    1701             :       case PNK_POSTINCREMENT:
    1702             :       case PNK_PREDECREMENT:
    1703             :       case PNK_POSTDECREMENT:
    1704         745 :         return FoldIncrementDecrement(cx, pn, parser, inGenexpLambda);
    1705             : 
    1706             :       case PNK_THROW:
    1707             :       case PNK_ARRAYPUSH:
    1708             :       case PNK_MUTATEPROTO:
    1709             :       case PNK_COMPUTED_NAME:
    1710             :       case PNK_SPREAD:
    1711             :       case PNK_EXPORT:
    1712             :       case PNK_VOID:
    1713         624 :         MOZ_ASSERT(pn->isArity(PN_UNARY));
    1714         624 :         return Fold(cx, &pn->pn_kid, parser, inGenexpLambda);
    1715             : 
    1716             :       case PNK_EXPORT_DEFAULT:
    1717           0 :         MOZ_ASSERT(pn->isArity(PN_BINARY));
    1718           0 :         return Fold(cx, &pn->pn_left, parser, inGenexpLambda);
    1719             : 
    1720             :       case PNK_SEMI:
    1721             :       case PNK_THIS:
    1722       23680 :         MOZ_ASSERT(pn->isArity(PN_UNARY));
    1723       23680 :         if (ParseNode*& expr = pn->pn_kid)
    1724       22930 :             return Fold(cx, &expr, parser, inGenexpLambda);
    1725         750 :         return true;
    1726             : 
    1727             :       case PNK_AND:
    1728             :       case PNK_OR:
    1729        2233 :         return FoldAndOr(cx, pnp, parser, inGenexpLambda);
    1730             : 
    1731             :       case PNK_FUNCTION:
    1732        7891 :         return FoldFunction(cx, pn, parser, inGenexpLambda);
    1733             : 
    1734             :       case PNK_MODULE:
    1735           0 :         return FoldModule(cx, pn, parser);
    1736             : 
    1737             :       case PNK_SUB:
    1738             :       case PNK_STAR:
    1739             :       case PNK_LSH:
    1740             :       case PNK_RSH:
    1741             :       case PNK_URSH:
    1742             :       case PNK_DIV:
    1743             :       case PNK_MOD:
    1744         743 :         return FoldBinaryArithmetic(cx, pn, parser, inGenexpLambda);
    1745             : 
    1746             :       case PNK_POW:
    1747           0 :         return FoldExponentiation(cx, pn, parser, inGenexpLambda);
    1748             : 
    1749             :       // Various list nodes not requiring care to minimally fold.  Some of
    1750             :       // these could be further folded/optimized, but we don't make the effort.
    1751             :       case PNK_BITOR:
    1752             :       case PNK_BITXOR:
    1753             :       case PNK_BITAND:
    1754             :       case PNK_STRICTEQ:
    1755             :       case PNK_EQ:
    1756             :       case PNK_STRICTNE:
    1757             :       case PNK_NE:
    1758             :       case PNK_LT:
    1759             :       case PNK_LE:
    1760             :       case PNK_GT:
    1761             :       case PNK_GE:
    1762             :       case PNK_INSTANCEOF:
    1763             :       case PNK_IN:
    1764             :       case PNK_COMMA:
    1765             :       case PNK_NEW:
    1766             :       case PNK_ARRAY:
    1767             :       case PNK_OBJECT:
    1768             :       case PNK_ARRAYCOMP:
    1769             :       case PNK_STATEMENTLIST:
    1770             :       case PNK_CLASSMETHODLIST:
    1771             :       case PNK_CATCHLIST:
    1772             :       case PNK_TEMPLATE_STRING_LIST:
    1773             :       case PNK_VAR:
    1774             :       case PNK_CONST:
    1775             :       case PNK_LET:
    1776             :       case PNK_PARAMSBODY:
    1777             :       case PNK_CALLSITEOBJ:
    1778             :       case PNK_EXPORT_SPEC_LIST:
    1779             :       case PNK_IMPORT_SPEC_LIST:
    1780             :       case PNK_GENEXP:
    1781       43816 :         return FoldList(cx, pn, parser, inGenexpLambda);
    1782             : 
    1783             :       case PNK_INITIALYIELD:
    1784         110 :         MOZ_ASSERT(pn->isArity(PN_UNARY));
    1785         110 :         MOZ_ASSERT(pn->pn_kid->isKind(PNK_ASSIGN) &&
    1786             :                    pn->pn_kid->pn_left->isKind(PNK_NAME) &&
    1787             :                    pn->pn_kid->pn_right->isKind(PNK_GENERATOR));
    1788         110 :         return true;
    1789             : 
    1790             :       case PNK_YIELD_STAR:
    1791           3 :         MOZ_ASSERT(pn->isArity(PN_UNARY));
    1792           3 :         return Fold(cx, &pn->pn_kid, parser, inGenexpLambda);
    1793             : 
    1794             :       case PNK_YIELD:
    1795             :       case PNK_AWAIT:
    1796         209 :         MOZ_ASSERT(pn->isArity(PN_UNARY));
    1797         209 :         if (!pn->pn_kid)
    1798           0 :             return true;
    1799         209 :         return Fold(cx, &pn->pn_kid, parser, inGenexpLambda);
    1800             : 
    1801             :       case PNK_RETURN:
    1802        6615 :         return FoldReturn(cx, pn, parser, inGenexpLambda);
    1803             : 
    1804             :       case PNK_TRY:
    1805         513 :         return FoldTry(cx, pn, parser, inGenexpLambda);
    1806             : 
    1807             :       case PNK_CATCH:
    1808         491 :         return FoldCatch(cx, pn, parser, inGenexpLambda);
    1809             : 
    1810             :       case PNK_CLASS:
    1811          32 :         return FoldClass(cx, pn, parser, inGenexpLambda);
    1812             : 
    1813             :       case PNK_ELEM:
    1814        3252 :         return FoldElement(cx, pnp, parser, inGenexpLambda);
    1815             : 
    1816             :       case PNK_ADD:
    1817        2465 :         return FoldAdd(cx, pnp, parser, inGenexpLambda);
    1818             : 
    1819             :       case PNK_CALL:
    1820             :       case PNK_SUPERCALL:
    1821             :       case PNK_TAGGED_TEMPLATE:
    1822       22883 :         return FoldCall(cx, pn, parser, inGenexpLambda);
    1823             : 
    1824             :       case PNK_SWITCH:
    1825             :       case PNK_COLON:
    1826             :       case PNK_ASSIGN:
    1827             :       case PNK_ADDASSIGN:
    1828             :       case PNK_SUBASSIGN:
    1829             :       case PNK_BITORASSIGN:
    1830             :       case PNK_BITANDASSIGN:
    1831             :       case PNK_BITXORASSIGN:
    1832             :       case PNK_LSHASSIGN:
    1833             :       case PNK_RSHASSIGN:
    1834             :       case PNK_URSHASSIGN:
    1835             :       case PNK_DIVASSIGN:
    1836             :       case PNK_MODASSIGN:
    1837             :       case PNK_MULASSIGN:
    1838             :       case PNK_POWASSIGN:
    1839             :       case PNK_IMPORT:
    1840             :       case PNK_EXPORT_FROM:
    1841             :       case PNK_SHORTHAND:
    1842             :       case PNK_FOR:
    1843             :       case PNK_COMPREHENSIONFOR:
    1844             :       case PNK_CLASSMETHOD:
    1845             :       case PNK_IMPORT_SPEC:
    1846             :       case PNK_EXPORT_SPEC:
    1847             :       case PNK_SETTHIS:
    1848       18848 :         MOZ_ASSERT(pn->isArity(PN_BINARY));
    1849       37696 :         return Fold(cx, &pn->pn_left, parser, inGenexpLambda) &&
    1850       37696 :                Fold(cx, &pn->pn_right, parser, inGenexpLambda);
    1851             : 
    1852             :       case PNK_NEWTARGET:
    1853          12 :         MOZ_ASSERT(pn->isArity(PN_BINARY));
    1854          12 :         MOZ_ASSERT(pn->pn_left->isKind(PNK_POSHOLDER));
    1855          12 :         MOZ_ASSERT(pn->pn_right->isKind(PNK_POSHOLDER));
    1856          12 :         return true;
    1857             : 
    1858             :       case PNK_CLASSNAMES:
    1859          26 :         MOZ_ASSERT(pn->isArity(PN_BINARY));
    1860          26 :         if (ParseNode*& outerBinding = pn->pn_left) {
    1861          26 :             if (!Fold(cx, &outerBinding, parser, inGenexpLambda))
    1862           0 :                 return false;
    1863             :         }
    1864          26 :         return Fold(cx, &pn->pn_right, parser, inGenexpLambda);
    1865             : 
    1866             :       case PNK_DOWHILE:
    1867          23 :         MOZ_ASSERT(pn->isArity(PN_BINARY));
    1868          46 :         return Fold(cx, &pn->pn_left, parser, inGenexpLambda) &&
    1869          46 :                FoldCondition(cx, &pn->pn_right, parser, inGenexpLambda);
    1870             : 
    1871             :       case PNK_WHILE:
    1872         207 :         MOZ_ASSERT(pn->isArity(PN_BINARY));
    1873         414 :         return FoldCondition(cx, &pn->pn_left, parser, inGenexpLambda) &&
    1874         414 :                Fold(cx, &pn->pn_right, parser, inGenexpLambda);
    1875             : 
    1876             :       case PNK_CASE: {
    1877        1186 :         MOZ_ASSERT(pn->isArity(PN_BINARY));
    1878             : 
    1879             :         // pn_left is null for DefaultClauses.
    1880        1186 :         if (pn->pn_left) {
    1881        1128 :             if (!Fold(cx, &pn->pn_left, parser, inGenexpLambda))
    1882           0 :                 return false;
    1883             :         }
    1884        1186 :         return Fold(cx, &pn->pn_right, parser, inGenexpLambda);
    1885             :       }
    1886             : 
    1887             :       case PNK_WITH:
    1888           0 :         MOZ_ASSERT(pn->isArity(PN_BINARY));
    1889           0 :         return Fold(cx, &pn->pn_left, parser, inGenexpLambda) &&
    1890           0 :                Fold(cx, &pn->pn_right, parser, inGenexpLambda);
    1891             : 
    1892             :       case PNK_FORIN:
    1893             :       case PNK_FOROF:
    1894         384 :         return FoldForInOrOf(cx, pn, parser, inGenexpLambda);
    1895             : 
    1896             :       case PNK_FORHEAD:
    1897         471 :         return FoldForHead(cx, pn, parser, inGenexpLambda);
    1898             : 
    1899             :       case PNK_LABEL:
    1900           0 :         MOZ_ASSERT(pn->isArity(PN_NAME));
    1901           0 :         return Fold(cx, &pn->pn_expr, parser, inGenexpLambda);
    1902             : 
    1903             :       case PNK_DOT:
    1904       27629 :         return FoldDottedProperty(cx, pn, parser, inGenexpLambda);
    1905             : 
    1906             :       case PNK_LEXICALSCOPE:
    1907       13893 :         MOZ_ASSERT(pn->isArity(PN_SCOPE));
    1908       13893 :         if (!pn->scopeBody())
    1909           0 :             return true;
    1910       13893 :         return Fold(cx, &pn->pn_u.scope.body, parser, inGenexpLambda);
    1911             : 
    1912             :       case PNK_NAME:
    1913       98435 :         return FoldName(cx, pn, parser, inGenexpLambda);
    1914             : 
    1915             :       case PNK_LIMIT: // invalid sentinel value
    1916           0 :         MOZ_CRASH("invalid node kind");
    1917             :     }
    1918             : 
    1919           0 :     MOZ_CRASH("shouldn't reach here");
    1920             :     return false;
    1921             : }
    1922             : 
    1923             : template<typename CharT>
    1924             : bool
    1925       10854 : frontend::FoldConstants(JSContext* cx, ParseNode** pnp, Parser<FullParseHandler, CharT>* parser)
    1926             : {
    1927             :     // Don't constant-fold inside "use asm" code, as this could create a parse
    1928             :     // tree that doesn't type-check as asm.js.
    1929       10854 :     if (parser->pc->useAsmOrInsideUseAsm())
    1930           0 :         return true;
    1931             : 
    1932       21708 :     AutoTraceLog traceLog(TraceLoggerForCurrentThread(cx), TraceLogger_BytecodeFoldConstants);
    1933       10854 :     return Fold(cx, pnp, *parser, false);
    1934             : }
    1935             : 
    1936             : template bool
    1937             : frontend::FoldConstants(JSContext* cx, ParseNode** pnp,
    1938           9 :                         Parser<FullParseHandler, char16_t>* parser);

Generated by: LCOV version 1.13