tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

FoldConstants.cpp (52703B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      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/Maybe.h"  // mozilla::Maybe
     10 #include "mozilla/Try.h"    // MOZ_TRY*
     11 
     12 #include "jslibmath.h"
     13 #include "jsmath.h"
     14 
     15 #include "frontend/FullParseHandler.h"
     16 #include "frontend/ParseNode.h"
     17 #include "frontend/ParseNodeVisitor.h"
     18 #include "frontend/Parser-macros.h"  // MOZ_TRY_VAR_OR_RETURN
     19 #include "frontend/ParserAtom.h"     // ParserAtomsTable, TaggedParserAtomIndex
     20 #include "js/Conversions.h"
     21 #include "js/Stack.h"            // JS::NativeStackLimit
     22 #include "util/StringBuilder.h"  // StringBuilder
     23 
     24 using namespace js;
     25 using namespace js::frontend;
     26 
     27 using JS::ToInt32;
     28 using JS::ToUint32;
     29 
     30 struct FoldInfo {
     31  FrontendContext* fc;
     32  ParserAtomsTable& parserAtoms;
     33  BigIntStencilVector& bigInts;
     34  FullParseHandler* handler;
     35 };
     36 
     37 // Don't use ReplaceNode directly, because we want the constant folder to keep
     38 // the attributes isInParens and isDirectRHSAnonFunction of the old node being
     39 // replaced.
     40 [[nodiscard]] inline bool TryReplaceNode(ParseNode** pnp,
     41                                         ParseNodeResult result) {
     42  // convenience check: can call TryReplaceNode(pnp, alloc_parsenode())
     43  // directly, without having to worry about alloc returning null.
     44  if (result.isErr()) {
     45    return false;
     46  }
     47  auto* pn = result.unwrap();
     48  pn->setInParens((*pnp)->isInParens());
     49  pn->setDirectRHSAnonFunction((*pnp)->isDirectRHSAnonFunction());
     50  ReplaceNode(pnp, pn);
     51  return true;
     52 }
     53 
     54 static bool ContainsHoistedDeclaration(FoldInfo& info, ParseNode* node,
     55                                       bool* result);
     56 
     57 static bool ListContainsHoistedDeclaration(FoldInfo& info, ListNode* list,
     58                                           bool* result) {
     59  for (ParseNode* node : list->contents()) {
     60    if (!ContainsHoistedDeclaration(info, node, result)) {
     61      return false;
     62    }
     63    if (*result) {
     64      return true;
     65    }
     66  }
     67 
     68  *result = false;
     69  return true;
     70 }
     71 
     72 // Determines whether the given ParseNode contains any declarations whose
     73 // visibility will extend outside the node itself -- that is, whether the
     74 // ParseNode contains any var statements.
     75 //
     76 // THIS IS NOT A GENERAL-PURPOSE FUNCTION.  It is only written to work in the
     77 // specific context of deciding that |node|, as one arm of a ParseNodeKind::If
     78 // controlled by a constant condition, contains a declaration that forbids
     79 // |node| being completely eliminated as dead.
     80 static bool ContainsHoistedDeclaration(FoldInfo& info, ParseNode* node,
     81                                       bool* result) {
     82  AutoCheckRecursionLimit recursion(info.fc);
     83  if (!recursion.check(info.fc)) {
     84    return false;
     85  }
     86 
     87 restart:
     88 
     89  // With a better-typed AST, we would have distinct parse node classes for
     90  // expressions and for statements and would characterize expressions with
     91  // ExpressionKind and statements with StatementKind.  Perhaps someday.  In
     92  // the meantime we must characterize every ParseNodeKind, even the
     93  // expression/sub-expression ones that, if we handle all statement kinds
     94  // correctly, we'll never see.
     95  switch (node->getKind()) {
     96    // Base case.
     97    case ParseNodeKind::VarStmt:
     98      *result = true;
     99      return true;
    100 
    101    // Non-global lexical declarations are block-scoped (ergo not hoistable).
    102    case ParseNodeKind::LetDecl:
    103    case ParseNodeKind::ConstDecl:
    104 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
    105    case ParseNodeKind::UsingDecl:
    106    case ParseNodeKind::AwaitUsingDecl:
    107 #endif
    108      MOZ_ASSERT(node->is<ListNode>());
    109      *result = false;
    110      return true;
    111 
    112    // Similarly to the lexical declarations above, classes cannot add hoisted
    113    // declarations
    114    case ParseNodeKind::ClassDecl:
    115      MOZ_ASSERT(node->is<ClassNode>());
    116      *result = false;
    117      return true;
    118 
    119    // Function declarations *can* be hoisted declarations.  But in the
    120    // magical world of the rewritten frontend, the declaration necessitated
    121    // by a nested function statement, not at body level, doesn't require
    122    // that we preserve an unreachable function declaration node against
    123    // dead-code removal.
    124    case ParseNodeKind::Function:
    125      *result = false;
    126      return true;
    127 
    128    case ParseNodeKind::Module:
    129      *result = false;
    130      return true;
    131 
    132    // Statements with no sub-components at all.
    133    case ParseNodeKind::EmptyStmt:
    134      MOZ_ASSERT(node->is<NullaryNode>());
    135      *result = false;
    136      return true;
    137 
    138    case ParseNodeKind::DebuggerStmt:
    139      MOZ_ASSERT(node->is<DebuggerStatement>());
    140      *result = false;
    141      return true;
    142 
    143    // Statements containing only an expression have no declarations.
    144    case ParseNodeKind::ExpressionStmt:
    145    case ParseNodeKind::ThrowStmt:
    146    case ParseNodeKind::ReturnStmt:
    147      MOZ_ASSERT(node->is<UnaryNode>());
    148      *result = false;
    149      return true;
    150 
    151    // These two aren't statements in the spec, but we sometimes insert them
    152    // in statement lists anyway.
    153    case ParseNodeKind::InitialYield:
    154    case ParseNodeKind::YieldStarExpr:
    155    case ParseNodeKind::YieldExpr:
    156      MOZ_ASSERT(node->is<UnaryNode>());
    157      *result = false;
    158      return true;
    159 
    160    // Other statements with no sub-statement components.
    161    case ParseNodeKind::BreakStmt:
    162    case ParseNodeKind::ContinueStmt:
    163    case ParseNodeKind::ImportDecl:
    164    case ParseNodeKind::ImportSpecList:
    165    case ParseNodeKind::ImportSpec:
    166    case ParseNodeKind::ImportNamespaceSpec:
    167    case ParseNodeKind::ExportFromStmt:
    168    case ParseNodeKind::ExportDefaultStmt:
    169    case ParseNodeKind::ExportSpecList:
    170    case ParseNodeKind::ExportSpec:
    171    case ParseNodeKind::ExportNamespaceSpec:
    172    case ParseNodeKind::ExportStmt:
    173    case ParseNodeKind::ExportBatchSpecStmt:
    174    case ParseNodeKind::CallImportExpr:
    175    case ParseNodeKind::CallImportSpec:
    176    case ParseNodeKind::ImportAttributeList:
    177    case ParseNodeKind::ImportAttribute:
    178    case ParseNodeKind::ImportModuleRequest:
    179      *result = false;
    180      return true;
    181 
    182    // Statements possibly containing hoistable declarations only in the left
    183    // half, in ParseNode terms -- the loop body in AST terms.
    184    case ParseNodeKind::DoWhileStmt:
    185      return ContainsHoistedDeclaration(info, node->as<BinaryNode>().left(),
    186                                        result);
    187 
    188    // Statements possibly containing hoistable declarations only in the
    189    // right half, in ParseNode terms -- the loop body or nested statement
    190    // (usually a block statement), in AST terms.
    191    case ParseNodeKind::WhileStmt:
    192    case ParseNodeKind::WithStmt:
    193      return ContainsHoistedDeclaration(info, node->as<BinaryNode>().right(),
    194                                        result);
    195 
    196    case ParseNodeKind::LabelStmt:
    197      return ContainsHoistedDeclaration(
    198          info, node->as<LabeledStatement>().statement(), result);
    199 
    200    // Statements with more complicated structures.
    201 
    202    // if-statement nodes may have hoisted declarations in their consequent
    203    // and alternative components.
    204    case ParseNodeKind::IfStmt: {
    205      TernaryNode* ifNode = &node->as<TernaryNode>();
    206      ParseNode* consequent = ifNode->kid2();
    207      if (!ContainsHoistedDeclaration(info, consequent, result)) {
    208        return false;
    209      }
    210      if (*result) {
    211        return true;
    212      }
    213 
    214      if ((node = ifNode->kid3())) {
    215        goto restart;
    216      }
    217 
    218      *result = false;
    219      return true;
    220    }
    221 
    222    // try-statements have statements to execute, and one or both of a
    223    // catch-list and a finally-block.
    224    case ParseNodeKind::TryStmt: {
    225      TernaryNode* tryNode = &node->as<TernaryNode>();
    226 
    227      MOZ_ASSERT(tryNode->kid2() || tryNode->kid3(),
    228                 "must have either catch or finally");
    229 
    230      ParseNode* tryBlock = tryNode->kid1();
    231      if (!ContainsHoistedDeclaration(info, tryBlock, result)) {
    232        return false;
    233      }
    234      if (*result) {
    235        return true;
    236      }
    237 
    238      if (ParseNode* catchScope = tryNode->kid2()) {
    239        BinaryNode* catchNode =
    240            &catchScope->as<LexicalScopeNode>().scopeBody()->as<BinaryNode>();
    241        MOZ_ASSERT(catchNode->isKind(ParseNodeKind::Catch));
    242 
    243        ParseNode* catchStatements = catchNode->right();
    244        if (!ContainsHoistedDeclaration(info, catchStatements, result)) {
    245          return false;
    246        }
    247        if (*result) {
    248          return true;
    249        }
    250      }
    251 
    252      if (ParseNode* finallyBlock = tryNode->kid3()) {
    253        return ContainsHoistedDeclaration(info, finallyBlock, result);
    254      }
    255 
    256      *result = false;
    257      return true;
    258    }
    259 
    260    // A switch node's left half is an expression; only its right half (a
    261    // list of cases/defaults, or a block node) could contain hoisted
    262    // declarations.
    263    case ParseNodeKind::SwitchStmt: {
    264      SwitchStatement* switchNode = &node->as<SwitchStatement>();
    265      return ContainsHoistedDeclaration(info, &switchNode->lexicalForCaseList(),
    266                                        result);
    267    }
    268 
    269    case ParseNodeKind::Case: {
    270      CaseClause* caseClause = &node->as<CaseClause>();
    271      return ContainsHoistedDeclaration(info, caseClause->statementList(),
    272                                        result);
    273    }
    274 
    275    case ParseNodeKind::ForStmt: {
    276      ForNode* forNode = &node->as<ForNode>();
    277      TernaryNode* loopHead = forNode->head();
    278      MOZ_ASSERT(loopHead->isKind(ParseNodeKind::ForHead) ||
    279                 loopHead->isKind(ParseNodeKind::ForIn) ||
    280                 loopHead->isKind(ParseNodeKind::ForOf));
    281 
    282      if (loopHead->isKind(ParseNodeKind::ForHead)) {
    283        // for (init?; cond?; update?), with only init possibly containing
    284        // a hoisted declaration.  (Note: a lexical-declaration |init| is
    285        // (at present) hoisted in SpiderMonkey parlance -- but such
    286        // hoisting doesn't extend outside of this statement, so it is not
    287        // hoisting in the sense meant by ContainsHoistedDeclaration.)
    288        ParseNode* init = loopHead->kid1();
    289        if (init && init->isKind(ParseNodeKind::VarStmt)) {
    290          *result = true;
    291          return true;
    292        }
    293      } else {
    294        MOZ_ASSERT(loopHead->isKind(ParseNodeKind::ForIn) ||
    295                   loopHead->isKind(ParseNodeKind::ForOf));
    296 
    297        // for each? (target in ...), where only target may introduce
    298        // hoisted declarations.
    299        //
    300        //   -- or --
    301        //
    302        // for (target of ...), where only target may introduce hoisted
    303        // declarations.
    304        //
    305        // Either way, if |target| contains a declaration, it's |loopHead|'s
    306        // first kid.
    307        ParseNode* decl = loopHead->kid1();
    308        if (decl && decl->isKind(ParseNodeKind::VarStmt)) {
    309          *result = true;
    310          return true;
    311        }
    312      }
    313 
    314      ParseNode* loopBody = forNode->body();
    315      return ContainsHoistedDeclaration(info, loopBody, result);
    316    }
    317 
    318    case ParseNodeKind::LexicalScope: {
    319      LexicalScopeNode* scope = &node->as<LexicalScopeNode>();
    320      ParseNode* expr = scope->scopeBody();
    321 
    322      if (expr->isKind(ParseNodeKind::ForStmt) || expr->is<FunctionNode>()) {
    323        return ContainsHoistedDeclaration(info, expr, result);
    324      }
    325 
    326      MOZ_ASSERT(expr->isKind(ParseNodeKind::StatementList));
    327      return ListContainsHoistedDeclaration(
    328          info, &scope->scopeBody()->as<ListNode>(), result);
    329    }
    330 
    331    // List nodes with all non-null children.
    332    case ParseNodeKind::StatementList:
    333      return ListContainsHoistedDeclaration(info, &node->as<ListNode>(),
    334                                            result);
    335 
    336    // Grammar sub-components that should never be reached directly by this
    337    // method, because some parent component should have asserted itself.
    338    case ParseNodeKind::ObjectPropertyName:
    339    case ParseNodeKind::ComputedName:
    340    case ParseNodeKind::Spread:
    341    case ParseNodeKind::MutateProto:
    342    case ParseNodeKind::PropertyDefinition:
    343    case ParseNodeKind::Shorthand:
    344    case ParseNodeKind::ConditionalExpr:
    345    case ParseNodeKind::TypeOfNameExpr:
    346    case ParseNodeKind::TypeOfExpr:
    347    case ParseNodeKind::AwaitExpr:
    348    case ParseNodeKind::VoidExpr:
    349    case ParseNodeKind::NotExpr:
    350    case ParseNodeKind::BitNotExpr:
    351    case ParseNodeKind::DeleteNameExpr:
    352    case ParseNodeKind::DeletePropExpr:
    353    case ParseNodeKind::DeleteElemExpr:
    354    case ParseNodeKind::DeleteOptionalChainExpr:
    355    case ParseNodeKind::DeleteExpr:
    356    case ParseNodeKind::PosExpr:
    357    case ParseNodeKind::NegExpr:
    358    case ParseNodeKind::PreIncrementExpr:
    359    case ParseNodeKind::PostIncrementExpr:
    360    case ParseNodeKind::PreDecrementExpr:
    361    case ParseNodeKind::PostDecrementExpr:
    362    case ParseNodeKind::CoalesceExpr:
    363    case ParseNodeKind::OrExpr:
    364    case ParseNodeKind::AndExpr:
    365    case ParseNodeKind::BitOrExpr:
    366    case ParseNodeKind::BitXorExpr:
    367    case ParseNodeKind::BitAndExpr:
    368    case ParseNodeKind::StrictEqExpr:
    369    case ParseNodeKind::EqExpr:
    370    case ParseNodeKind::StrictNeExpr:
    371    case ParseNodeKind::NeExpr:
    372    case ParseNodeKind::LtExpr:
    373    case ParseNodeKind::LeExpr:
    374    case ParseNodeKind::GtExpr:
    375    case ParseNodeKind::GeExpr:
    376    case ParseNodeKind::InstanceOfExpr:
    377    case ParseNodeKind::InExpr:
    378    case ParseNodeKind::PrivateInExpr:
    379    case ParseNodeKind::LshExpr:
    380    case ParseNodeKind::RshExpr:
    381    case ParseNodeKind::UrshExpr:
    382    case ParseNodeKind::AddExpr:
    383    case ParseNodeKind::SubExpr:
    384    case ParseNodeKind::MulExpr:
    385    case ParseNodeKind::DivExpr:
    386    case ParseNodeKind::ModExpr:
    387    case ParseNodeKind::PowExpr:
    388    case ParseNodeKind::InitExpr:
    389    case ParseNodeKind::AssignExpr:
    390    case ParseNodeKind::AddAssignExpr:
    391    case ParseNodeKind::SubAssignExpr:
    392    case ParseNodeKind::CoalesceAssignExpr:
    393    case ParseNodeKind::OrAssignExpr:
    394    case ParseNodeKind::AndAssignExpr:
    395    case ParseNodeKind::BitOrAssignExpr:
    396    case ParseNodeKind::BitXorAssignExpr:
    397    case ParseNodeKind::BitAndAssignExpr:
    398    case ParseNodeKind::LshAssignExpr:
    399    case ParseNodeKind::RshAssignExpr:
    400    case ParseNodeKind::UrshAssignExpr:
    401    case ParseNodeKind::MulAssignExpr:
    402    case ParseNodeKind::DivAssignExpr:
    403    case ParseNodeKind::ModAssignExpr:
    404    case ParseNodeKind::PowAssignExpr:
    405    case ParseNodeKind::CommaExpr:
    406    case ParseNodeKind::ArrayExpr:
    407    case ParseNodeKind::ObjectExpr:
    408    case ParseNodeKind::PropertyNameExpr:
    409    case ParseNodeKind::DotExpr:
    410    case ParseNodeKind::ArgumentsLength:
    411    case ParseNodeKind::ElemExpr:
    412    case ParseNodeKind::Arguments:
    413    case ParseNodeKind::CallExpr:
    414    case ParseNodeKind::PrivateMemberExpr:
    415    case ParseNodeKind::OptionalChain:
    416    case ParseNodeKind::OptionalDotExpr:
    417    case ParseNodeKind::OptionalElemExpr:
    418    case ParseNodeKind::OptionalCallExpr:
    419    case ParseNodeKind::OptionalPrivateMemberExpr:
    420    case ParseNodeKind::Name:
    421    case ParseNodeKind::PrivateName:
    422    case ParseNodeKind::TemplateStringExpr:
    423    case ParseNodeKind::TemplateStringListExpr:
    424    case ParseNodeKind::TaggedTemplateExpr:
    425    case ParseNodeKind::CallSiteObj:
    426    case ParseNodeKind::StringExpr:
    427    case ParseNodeKind::RegExpExpr:
    428    case ParseNodeKind::TrueExpr:
    429    case ParseNodeKind::FalseExpr:
    430    case ParseNodeKind::NullExpr:
    431    case ParseNodeKind::RawUndefinedExpr:
    432    case ParseNodeKind::ThisExpr:
    433    case ParseNodeKind::Elision:
    434    case ParseNodeKind::NumberExpr:
    435    case ParseNodeKind::BigIntExpr:
    436    case ParseNodeKind::NewExpr:
    437    case ParseNodeKind::Generator:
    438    case ParseNodeKind::ParamsBody:
    439    case ParseNodeKind::Catch:
    440    case ParseNodeKind::ForIn:
    441    case ParseNodeKind::ForOf:
    442    case ParseNodeKind::ForHead:
    443    case ParseNodeKind::DefaultConstructor:
    444    case ParseNodeKind::ClassBodyScope:
    445    case ParseNodeKind::ClassMethod:
    446    case ParseNodeKind::ClassField:
    447    case ParseNodeKind::StaticClassBlock:
    448    case ParseNodeKind::ClassMemberList:
    449    case ParseNodeKind::ClassNames:
    450    case ParseNodeKind::NewTargetExpr:
    451    case ParseNodeKind::ImportMetaExpr:
    452    case ParseNodeKind::PosHolder:
    453    case ParseNodeKind::SuperCallExpr:
    454    case ParseNodeKind::SuperBase:
    455    case ParseNodeKind::SetThis:
    456 #ifdef ENABLE_DECORATORS
    457    case ParseNodeKind::DecoratorList:
    458 #endif
    459      MOZ_CRASH(
    460          "ContainsHoistedDeclaration should have indicated false on "
    461          "some parent node without recurring to test this node");
    462    case ParseNodeKind::LastUnused:
    463    case ParseNodeKind::Limit:
    464      MOZ_CRASH("unexpected sentinel ParseNodeKind in node");
    465  }
    466 
    467  MOZ_CRASH("invalid node kind");
    468 }
    469 
    470 /*
    471 * Fold from one constant type to another.
    472 * XXX handles only strings and numbers for now
    473 */
    474 static bool FoldType(FoldInfo info, ParseNode** pnp, ParseNodeKind kind) {
    475  const ParseNode* pn = *pnp;
    476  if (!pn->isKind(kind)) {
    477    switch (kind) {
    478      case ParseNodeKind::NumberExpr:
    479        if (pn->isKind(ParseNodeKind::StringExpr)) {
    480          auto atom = pn->as<NameNode>().atom();
    481          double d = info.parserAtoms.toNumber(atom);
    482          if (!TryReplaceNode(
    483                  pnp, info.handler->newNumber(d, NoDecimal, pn->pn_pos))) {
    484            return false;
    485          }
    486        }
    487        break;
    488 
    489      case ParseNodeKind::StringExpr:
    490        if (pn->isKind(ParseNodeKind::NumberExpr)) {
    491          TaggedParserAtomIndex atom =
    492              pn->as<NumericLiteral>().toAtom(info.fc, info.parserAtoms);
    493          if (!atom) {
    494            return false;
    495          }
    496          if (!TryReplaceNode(
    497                  pnp, info.handler->newStringLiteral(atom, pn->pn_pos))) {
    498            return false;
    499          }
    500        }
    501        break;
    502 
    503      default:
    504        MOZ_CRASH("Invalid type in constant folding FoldType");
    505    }
    506  }
    507  return true;
    508 }
    509 
    510 static bool IsEffectless(ParseNode* node) {
    511  return node->isKind(ParseNodeKind::TrueExpr) ||
    512         node->isKind(ParseNodeKind::FalseExpr) ||
    513         node->isKind(ParseNodeKind::StringExpr) ||
    514         node->isKind(ParseNodeKind::TemplateStringExpr) ||
    515         node->isKind(ParseNodeKind::NumberExpr) ||
    516         node->isKind(ParseNodeKind::BigIntExpr) ||
    517         node->isKind(ParseNodeKind::NullExpr) ||
    518         node->isKind(ParseNodeKind::RawUndefinedExpr) ||
    519         node->isKind(ParseNodeKind::Function);
    520 }
    521 
    522 enum Truthiness { Truthy, Falsy, Unknown };
    523 
    524 static Truthiness Boolish(const FoldInfo& info, ParseNode* pn) {
    525  switch (pn->getKind()) {
    526    case ParseNodeKind::NumberExpr:
    527      return (pn->as<NumericLiteral>().value() != 0 &&
    528              !std::isnan(pn->as<NumericLiteral>().value()))
    529                 ? Truthy
    530                 : Falsy;
    531 
    532    case ParseNodeKind::BigIntExpr:
    533      return info.bigInts[pn->as<BigIntLiteral>().index()].isZero() ? Falsy
    534                                                                    : Truthy;
    535 
    536    case ParseNodeKind::StringExpr:
    537    case ParseNodeKind::TemplateStringExpr:
    538      return (pn->as<NameNode>().atom() ==
    539              TaggedParserAtomIndex::WellKnown::empty())
    540                 ? Falsy
    541                 : Truthy;
    542 
    543    case ParseNodeKind::TrueExpr:
    544    case ParseNodeKind::Function:
    545      return Truthy;
    546 
    547    case ParseNodeKind::FalseExpr:
    548    case ParseNodeKind::NullExpr:
    549    case ParseNodeKind::RawUndefinedExpr:
    550      return Falsy;
    551 
    552    case ParseNodeKind::VoidExpr: {
    553      // |void <foo>| evaluates to |undefined| which isn't truthy.  But the
    554      // sense of this method requires that the expression be literally
    555      // replaceable with true/false: not the case if the nested expression
    556      // is effectful, might throw, &c.  Walk past the |void| (and nested
    557      // |void| expressions, for good measure) and check that the nested
    558      // expression doesn't break this requirement before indicating falsity.
    559      do {
    560        pn = pn->as<UnaryNode>().kid();
    561      } while (pn->isKind(ParseNodeKind::VoidExpr));
    562 
    563      return IsEffectless(pn) ? Falsy : Unknown;
    564    }
    565 
    566    default:
    567      return Unknown;
    568  }
    569 }
    570 
    571 static bool SimplifyCondition(FoldInfo info, ParseNode** nodePtr) {
    572  // Conditions fold like any other expression, but then they sometimes can be
    573  // further folded to constants. *nodePtr should already have been
    574  // constant-folded.
    575 
    576  ParseNode* node = *nodePtr;
    577  if (Truthiness t = Boolish(info, node); t != Unknown) {
    578    // We can turn function nodes into constant nodes here, but mutating
    579    // function nodes is tricky --- in particular, mutating a function node
    580    // that appears on a method list corrupts the method list. However,
    581    // methods are M's in statements of the form 'this.foo = M;', which we
    582    // never fold, so we're okay.
    583    if (!TryReplaceNode(nodePtr, info.handler->newBooleanLiteral(
    584                                     t == Truthy, node->pn_pos))) {
    585      return false;
    586    }
    587  }
    588 
    589  return true;
    590 }
    591 
    592 static bool FoldTypeOfExpr(FoldInfo info, ParseNode** nodePtr) {
    593  UnaryNode* node = &(*nodePtr)->as<UnaryNode>();
    594  MOZ_ASSERT(node->isKind(ParseNodeKind::TypeOfExpr));
    595  ParseNode* expr = node->kid();
    596 
    597  // Constant-fold the entire |typeof| if given a constant with known type.
    598  TaggedParserAtomIndex result;
    599  if (expr->isKind(ParseNodeKind::StringExpr) ||
    600      expr->isKind(ParseNodeKind::TemplateStringExpr)) {
    601    result = TaggedParserAtomIndex::WellKnown::string();
    602  } else if (expr->isKind(ParseNodeKind::NumberExpr)) {
    603    result = TaggedParserAtomIndex::WellKnown::number();
    604  } else if (expr->isKind(ParseNodeKind::BigIntExpr)) {
    605    result = TaggedParserAtomIndex::WellKnown::bigint();
    606  } else if (expr->isKind(ParseNodeKind::NullExpr)) {
    607    result = TaggedParserAtomIndex::WellKnown::object();
    608  } else if (expr->isKind(ParseNodeKind::TrueExpr) ||
    609             expr->isKind(ParseNodeKind::FalseExpr)) {
    610    result = TaggedParserAtomIndex::WellKnown::boolean();
    611  } else if (expr->is<FunctionNode>()) {
    612    result = TaggedParserAtomIndex::WellKnown::function();
    613  }
    614 
    615  if (result) {
    616    if (!TryReplaceNode(nodePtr,
    617                        info.handler->newStringLiteral(result, node->pn_pos))) {
    618      return false;
    619    }
    620  }
    621 
    622  return true;
    623 }
    624 
    625 static bool FoldDeleteExpr(FoldInfo info, ParseNode** nodePtr) {
    626  UnaryNode* node = &(*nodePtr)->as<UnaryNode>();
    627 
    628  MOZ_ASSERT(node->isKind(ParseNodeKind::DeleteExpr));
    629  ParseNode* expr = node->kid();
    630 
    631  // Expression deletion evaluates the expression, then evaluates to true.
    632  // For effectless expressions, eliminate the expression evaluation.
    633  if (IsEffectless(expr)) {
    634    if (!TryReplaceNode(nodePtr,
    635                        info.handler->newBooleanLiteral(true, node->pn_pos))) {
    636      return false;
    637    }
    638  }
    639 
    640  return true;
    641 }
    642 
    643 static bool FoldDeleteElement(FoldInfo info, ParseNode** nodePtr) {
    644  UnaryNode* node = &(*nodePtr)->as<UnaryNode>();
    645  MOZ_ASSERT(node->isKind(ParseNodeKind::DeleteElemExpr));
    646  ParseNode* expr = node->kid();
    647 
    648  // If we're deleting an element, but constant-folding converted our
    649  // element reference into a dotted property access, we must *also*
    650  // morph the node's kind.
    651  //
    652  // In principle this also applies to |super["foo"] -> super.foo|,
    653  // but we don't constant-fold |super["foo"]| yet.
    654  MOZ_ASSERT(expr->isKind(ParseNodeKind::ElemExpr) ||
    655             expr->isKind(ParseNodeKind::DotExpr));
    656  if (expr->isKind(ParseNodeKind::DotExpr)) {
    657    // newDelete will detect and use DeletePropExpr
    658    if (!TryReplaceNode(nodePtr,
    659                        info.handler->newDelete(node->pn_pos.begin, expr))) {
    660      return false;
    661    }
    662    MOZ_ASSERT((*nodePtr)->getKind() == ParseNodeKind::DeletePropExpr);
    663  }
    664 
    665  return true;
    666 }
    667 
    668 static bool FoldNot(FoldInfo info, ParseNode** nodePtr) {
    669  UnaryNode* node = &(*nodePtr)->as<UnaryNode>();
    670  MOZ_ASSERT(node->isKind(ParseNodeKind::NotExpr));
    671 
    672  if (!SimplifyCondition(info, node->unsafeKidReference())) {
    673    return false;
    674  }
    675 
    676  ParseNode* expr = node->kid();
    677 
    678  if (expr->isKind(ParseNodeKind::TrueExpr) ||
    679      expr->isKind(ParseNodeKind::FalseExpr)) {
    680    bool newval = !expr->isKind(ParseNodeKind::TrueExpr);
    681 
    682    if (!TryReplaceNode(
    683            nodePtr, info.handler->newBooleanLiteral(newval, node->pn_pos))) {
    684      return false;
    685    }
    686  }
    687 
    688  return true;
    689 }
    690 
    691 static bool FoldUnaryArithmetic(FoldInfo info, ParseNode** nodePtr) {
    692  UnaryNode* node = &(*nodePtr)->as<UnaryNode>();
    693  MOZ_ASSERT(node->isKind(ParseNodeKind::BitNotExpr) ||
    694                 node->isKind(ParseNodeKind::PosExpr) ||
    695                 node->isKind(ParseNodeKind::NegExpr),
    696             "need a different method for this node kind");
    697 
    698  ParseNode* expr = node->kid();
    699 
    700  if (expr->isKind(ParseNodeKind::NumberExpr) ||
    701      expr->isKind(ParseNodeKind::TrueExpr) ||
    702      expr->isKind(ParseNodeKind::FalseExpr)) {
    703    double d = expr->isKind(ParseNodeKind::NumberExpr)
    704                   ? expr->as<NumericLiteral>().value()
    705                   : double(expr->isKind(ParseNodeKind::TrueExpr));
    706 
    707    if (node->isKind(ParseNodeKind::BitNotExpr)) {
    708      d = ~ToInt32(d);
    709    } else if (node->isKind(ParseNodeKind::NegExpr)) {
    710      d = -d;
    711    } else {
    712      MOZ_ASSERT(node->isKind(ParseNodeKind::PosExpr));  // nothing to do
    713    }
    714 
    715    if (!TryReplaceNode(nodePtr,
    716                        info.handler->newNumber(d, NoDecimal, node->pn_pos))) {
    717      return false;
    718    }
    719  } else if (expr->is<BigIntLiteral>()) {
    720    auto* literal = &expr->as<BigIntLiteral>();
    721    auto& bigInt = info.bigInts[literal->index()];
    722 
    723    if (node->isKind(ParseNodeKind::BitNotExpr)) {
    724      if (bigInt.inplaceBitNot()) {
    725        return TryReplaceNode(nodePtr, literal);
    726      }
    727    } else if (node->isKind(ParseNodeKind::NegExpr)) {
    728      if (bigInt.inplaceNegate()) {
    729        return TryReplaceNode(nodePtr, literal);
    730      }
    731    } else {
    732      MOZ_ASSERT(node->isKind(ParseNodeKind::PosExpr));  // nothing to do
    733    }
    734  }
    735 
    736  return true;
    737 }
    738 
    739 static bool FoldAndOrCoalesce(FoldInfo info, ParseNode** nodePtr) {
    740  ListNode* node = &(*nodePtr)->as<ListNode>();
    741 
    742  MOZ_ASSERT(node->isKind(ParseNodeKind::AndExpr) ||
    743             node->isKind(ParseNodeKind::CoalesceExpr) ||
    744             node->isKind(ParseNodeKind::OrExpr));
    745 
    746  bool isOrNode = node->isKind(ParseNodeKind::OrExpr);
    747  bool isAndNode = node->isKind(ParseNodeKind::AndExpr);
    748  bool isCoalesceNode = node->isKind(ParseNodeKind::CoalesceExpr);
    749  ParseNode** elem = node->unsafeHeadReference();
    750  do {
    751    Truthiness t = Boolish(info, *elem);
    752 
    753    // If we don't know the constant-folded node's truthiness, we can't
    754    // reduce this node with its surroundings.  Continue folding any
    755    // remaining nodes.
    756    if (t == Unknown) {
    757      elem = &(*elem)->pn_next;
    758      continue;
    759    }
    760 
    761    bool isTruthyCoalesceNode =
    762        isCoalesceNode && !((*elem)->isKind(ParseNodeKind::NullExpr) ||
    763                            (*elem)->isKind(ParseNodeKind::VoidExpr) ||
    764                            (*elem)->isKind(ParseNodeKind::RawUndefinedExpr));
    765    bool canShortCircuit = (isOrNode && t == Truthy) ||
    766                           (isAndNode && t == Falsy) || isTruthyCoalesceNode;
    767 
    768    // If the constant-folded node's truthiness will terminate the
    769    // condition -- `a || true || expr` or `b && false && expr` or
    770    // `false ?? c ?? expr` -- then trailing nodes will never be
    771    // evaluated.  Truncate the list after the known-truthiness node,
    772    // as it's the overall result.
    773    if (canShortCircuit) {
    774      for (ParseNode* next = (*elem)->pn_next; next; next = next->pn_next) {
    775        node->unsafeDecrementCount();
    776      }
    777 
    778      // Terminate the original and/or list at the known-truthiness
    779      // node.
    780      (*elem)->pn_next = nullptr;
    781      elem = &(*elem)->pn_next;
    782      break;
    783    }
    784 
    785    // We've encountered a vacuous node that'll never short-circuit
    786    // evaluation.
    787    if ((*elem)->pn_next) {
    788      // This node is never the overall result when there are
    789      // subsequent nodes.  Remove it.
    790      ParseNode* elt = *elem;
    791      *elem = elt->pn_next;
    792      node->unsafeDecrementCount();
    793    } else {
    794      // Otherwise this node is the result of the overall expression,
    795      // so leave it alone.  And we're done.
    796      elem = &(*elem)->pn_next;
    797      break;
    798    }
    799  } while (*elem);
    800 
    801  node->unsafeReplaceTail(elem);
    802 
    803  // If we removed nodes, we may have to replace a one-element list with
    804  // its element.
    805  if (node->count() == 1) {
    806    ParseNode* first = node->head();
    807    if (!TryReplaceNode(nodePtr, first)) {
    808      ;
    809      return false;
    810    }
    811  }
    812 
    813  return true;
    814 }
    815 
    816 static bool Fold(FoldInfo info, ParseNode** pnp);
    817 
    818 static bool FoldConditional(FoldInfo info, ParseNode** nodePtr) {
    819  ParseNode** nextNode = nodePtr;
    820 
    821  do {
    822    // |nextNode| on entry points to the C?T:F expression to be folded.
    823    // Reset it to exit the loop in the common case where F isn't another
    824    // ?: expression.
    825    nodePtr = nextNode;
    826    nextNode = nullptr;
    827 
    828    TernaryNode* node = &(*nodePtr)->as<TernaryNode>();
    829    MOZ_ASSERT(node->isKind(ParseNodeKind::ConditionalExpr));
    830 
    831    ParseNode** expr = node->unsafeKid1Reference();
    832    if (!Fold(info, expr)) {
    833      return false;
    834    }
    835    if (!SimplifyCondition(info, expr)) {
    836      return false;
    837    }
    838 
    839    ParseNode** ifTruthy = node->unsafeKid2Reference();
    840    if (!Fold(info, ifTruthy)) {
    841      return false;
    842    }
    843 
    844    ParseNode** ifFalsy = node->unsafeKid3Reference();
    845 
    846    // If our C?T:F node has F as another ?: node, *iteratively* constant-
    847    // fold F *after* folding C and T (and possibly eliminating C and one
    848    // of T/F entirely); otherwise fold F normally.  Making |nextNode| non-
    849    // null causes this loop to run again to fold F.
    850    //
    851    // Conceivably we could instead/also iteratively constant-fold T, if T
    852    // were more complex than F.  Such an optimization is unimplemented.
    853    if ((*ifFalsy)->isKind(ParseNodeKind::ConditionalExpr)) {
    854      MOZ_ASSERT((*ifFalsy)->is<TernaryNode>());
    855      nextNode = ifFalsy;
    856    } else {
    857      if (!Fold(info, ifFalsy)) {
    858        return false;
    859      }
    860    }
    861 
    862    // Try to constant-fold based on the condition expression.
    863    Truthiness t = Boolish(info, *expr);
    864    if (t == Unknown) {
    865      continue;
    866    }
    867 
    868    // Otherwise reduce 'C ? T : F' to T or F as directed by C.
    869    ParseNode* replacement = t == Truthy ? *ifTruthy : *ifFalsy;
    870 
    871    // Otherwise perform a replacement.  This invalidates |nextNode|, so
    872    // reset it (if the replacement requires folding) or clear it (if
    873    // |ifFalsy| is dead code) as needed.
    874    if (nextNode) {
    875      nextNode = (*nextNode == replacement) ? nodePtr : nullptr;
    876    }
    877    if (!TryReplaceNode(nodePtr, replacement)) {
    878      return false;
    879    }
    880  } while (nextNode);
    881 
    882  return true;
    883 }
    884 
    885 static bool FoldIf(FoldInfo info, ParseNode** nodePtr) {
    886  ParseNode** nextNode = nodePtr;
    887 
    888  do {
    889    // |nextNode| on entry points to the initial |if| to be folded.  Reset
    890    // it to exit the loop when the |else| arm isn't another |if|.
    891    nodePtr = nextNode;
    892    nextNode = nullptr;
    893 
    894    TernaryNode* node = &(*nodePtr)->as<TernaryNode>();
    895    MOZ_ASSERT(node->isKind(ParseNodeKind::IfStmt));
    896 
    897    ParseNode** expr = node->unsafeKid1Reference();
    898    if (!Fold(info, expr)) {
    899      return false;
    900    }
    901    if (!SimplifyCondition(info, expr)) {
    902      return false;
    903    }
    904 
    905    ParseNode** consequent = node->unsafeKid2Reference();
    906    if (!Fold(info, consequent)) {
    907      return false;
    908    }
    909 
    910    ParseNode** alternative = node->unsafeKid3Reference();
    911    if (*alternative) {
    912      // If in |if (C) T; else F;| we have |F| as another |if|,
    913      // *iteratively* constant-fold |F| *after* folding |C| and |T| (and
    914      // possibly completely replacing the whole thing with |T| or |F|);
    915      // otherwise fold F normally.  Making |nextNode| non-null causes
    916      // this loop to run again to fold F.
    917      if ((*alternative)->isKind(ParseNodeKind::IfStmt)) {
    918        MOZ_ASSERT((*alternative)->is<TernaryNode>());
    919        nextNode = alternative;
    920      } else {
    921        if (!Fold(info, alternative)) {
    922          return false;
    923        }
    924      }
    925    }
    926 
    927    // Eliminate the consequent or alternative if the condition has
    928    // constant truthiness.
    929    Truthiness t = Boolish(info, *expr);
    930    if (t == Unknown) {
    931      continue;
    932    }
    933 
    934    // Careful!  Either of these can be null: |replacement| in |if (0) T;|,
    935    // and |discarded| in |if (true) T;|.
    936    ParseNode* replacement;
    937    ParseNode* discarded;
    938    if (t == Truthy) {
    939      replacement = *consequent;
    940      discarded = *alternative;
    941    } else {
    942      replacement = *alternative;
    943      discarded = *consequent;
    944    }
    945 
    946    bool performReplacement = true;
    947    if (discarded) {
    948      // A declaration that hoists outside the discarded arm prevents the
    949      // |if| from being folded away.
    950      bool containsHoistedDecls;
    951      if (!ContainsHoistedDeclaration(info, discarded, &containsHoistedDecls)) {
    952        return false;
    953      }
    954 
    955      performReplacement = !containsHoistedDecls;
    956    }
    957 
    958    if (!performReplacement) {
    959      continue;
    960    }
    961 
    962    if (!replacement) {
    963      // If there's no replacement node, we have a constantly-false |if|
    964      // with no |else|.  Replace the entire thing with an empty
    965      // statement list.
    966      if (!TryReplaceNode(nodePtr,
    967                          info.handler->newStatementList(node->pn_pos))) {
    968        return false;
    969      }
    970    } else {
    971      // Replacement invalidates |nextNode|, so reset it (if the
    972      // replacement requires folding) or clear it (if |alternative|
    973      // is dead code) as needed.
    974      if (nextNode) {
    975        nextNode = (*nextNode == replacement) ? nodePtr : nullptr;
    976      }
    977      ReplaceNode(nodePtr, replacement);
    978    }
    979  } while (nextNode);
    980 
    981  return true;
    982 }
    983 
    984 static double ComputeBinary(ParseNodeKind kind, double left, double right) {
    985  if (kind == ParseNodeKind::AddExpr) {
    986    return left + right;
    987  }
    988 
    989  if (kind == ParseNodeKind::SubExpr) {
    990    return left - right;
    991  }
    992 
    993  if (kind == ParseNodeKind::MulExpr) {
    994    return left * right;
    995  }
    996 
    997  if (kind == ParseNodeKind::ModExpr) {
    998    return NumberMod(left, right);
    999  }
   1000 
   1001  if (kind == ParseNodeKind::UrshExpr) {
   1002    return ToUint32(left) >> (ToUint32(right) & 31);
   1003  }
   1004 
   1005  if (kind == ParseNodeKind::DivExpr) {
   1006    return NumberDiv(left, right);
   1007  }
   1008 
   1009  MOZ_ASSERT(kind == ParseNodeKind::LshExpr || kind == ParseNodeKind::RshExpr);
   1010 
   1011  int32_t i = ToInt32(left);
   1012  uint32_t j = ToUint32(right) & 31;
   1013  return int32_t((kind == ParseNodeKind::LshExpr) ? uint32_t(i) << j : i >> j);
   1014 }
   1015 
   1016 static bool FoldBinaryArithmetic(FoldInfo info, ParseNode** nodePtr) {
   1017  ListNode* node = &(*nodePtr)->as<ListNode>();
   1018  MOZ_ASSERT(node->isKind(ParseNodeKind::SubExpr) ||
   1019             node->isKind(ParseNodeKind::MulExpr) ||
   1020             node->isKind(ParseNodeKind::LshExpr) ||
   1021             node->isKind(ParseNodeKind::RshExpr) ||
   1022             node->isKind(ParseNodeKind::UrshExpr) ||
   1023             node->isKind(ParseNodeKind::DivExpr) ||
   1024             node->isKind(ParseNodeKind::ModExpr));
   1025  MOZ_ASSERT(node->count() >= 2);
   1026 
   1027  // Fold each operand to a number if possible.
   1028  ParseNode** listp = node->unsafeHeadReference();
   1029  for (; *listp; listp = &(*listp)->pn_next) {
   1030    if (!FoldType(info, listp, ParseNodeKind::NumberExpr)) {
   1031      return false;
   1032    }
   1033  }
   1034  node->unsafeReplaceTail(listp);
   1035 
   1036  // Now fold all leading numeric terms together into a single number.
   1037  // (Trailing terms for the non-shift operations can't be folded together
   1038  // due to floating point imprecision.  For example, if |x === -2**53|,
   1039  // |x - 1 - 1 === -2**53| but |x - 2 === -2**53 - 2|.  Shifts could be
   1040  // folded, but it doesn't seem worth the effort.)
   1041  ParseNode** elem = node->unsafeHeadReference();
   1042  ParseNode** next = &(*elem)->pn_next;
   1043  if ((*elem)->isKind(ParseNodeKind::NumberExpr)) {
   1044    ParseNodeKind kind = node->getKind();
   1045    while (true) {
   1046      if (!*next || !(*next)->isKind(ParseNodeKind::NumberExpr)) {
   1047        break;
   1048      }
   1049 
   1050      double d = ComputeBinary(kind, (*elem)->as<NumericLiteral>().value(),
   1051                               (*next)->as<NumericLiteral>().value());
   1052 
   1053      TokenPos pos((*elem)->pn_pos.begin, (*next)->pn_pos.end);
   1054      if (!TryReplaceNode(elem, info.handler->newNumber(d, NoDecimal, pos))) {
   1055        return false;
   1056      }
   1057 
   1058      (*elem)->pn_next = (*next)->pn_next;
   1059      next = &(*elem)->pn_next;
   1060      node->unsafeDecrementCount();
   1061    }
   1062 
   1063    if (node->count() == 1) {
   1064      MOZ_ASSERT(node->head() == *elem);
   1065      MOZ_ASSERT((*elem)->isKind(ParseNodeKind::NumberExpr));
   1066 
   1067      if (!TryReplaceNode(nodePtr, *elem)) {
   1068        return false;
   1069      }
   1070    }
   1071  }
   1072 
   1073  return true;
   1074 }
   1075 
   1076 static bool FoldExponentiation(FoldInfo info, ParseNode** nodePtr) {
   1077  ListNode* node = &(*nodePtr)->as<ListNode>();
   1078  MOZ_ASSERT(node->isKind(ParseNodeKind::PowExpr));
   1079  MOZ_ASSERT(node->count() >= 2);
   1080 
   1081  // Fold each operand, ideally into a number.
   1082  ParseNode** listp = node->unsafeHeadReference();
   1083  for (; *listp; listp = &(*listp)->pn_next) {
   1084    if (!FoldType(info, listp, ParseNodeKind::NumberExpr)) {
   1085      return false;
   1086    }
   1087  }
   1088 
   1089  node->unsafeReplaceTail(listp);
   1090 
   1091  // Unlike all other binary arithmetic operators, ** is right-associative:
   1092  // 2**3**5 is 2**(3**5), not (2**3)**5.  As list nodes singly-link their
   1093  // children, full constant-folding requires either linear space or dodgy
   1094  // in-place linked list reversal.  So we only fold one exponentiation: it's
   1095  // easy and addresses common cases like |2**32|.
   1096  if (node->count() > 2) {
   1097    return true;
   1098  }
   1099 
   1100  ParseNode* base = node->head();
   1101  ParseNode* exponent = base->pn_next;
   1102  if (!base->isKind(ParseNodeKind::NumberExpr) ||
   1103      !exponent->isKind(ParseNodeKind::NumberExpr)) {
   1104    return true;
   1105  }
   1106 
   1107  double d1 = base->as<NumericLiteral>().value();
   1108  double d2 = exponent->as<NumericLiteral>().value();
   1109 
   1110  return TryReplaceNode(nodePtr, info.handler->newNumber(
   1111                                     ecmaPow(d1, d2), NoDecimal, node->pn_pos));
   1112 }
   1113 
   1114 static bool FoldElement(FoldInfo info, ParseNode** nodePtr) {
   1115  PropertyByValue* elem = &(*nodePtr)->as<PropertyByValue>();
   1116 
   1117  ParseNode* expr = &elem->expression();
   1118  ParseNode* key = &elem->key();
   1119  TaggedParserAtomIndex name;
   1120  if (key->isKind(ParseNodeKind::StringExpr)) {
   1121    auto keyIndex = key->as<NameNode>().atom();
   1122    uint32_t index;
   1123    if (info.parserAtoms.isIndex(keyIndex, &index)) {
   1124      // Optimization 1: We have something like expr["100"]. This is
   1125      // equivalent to expr[100] which is faster.
   1126      if (!TryReplaceNode(
   1127              elem->unsafeRightReference(),
   1128              info.handler->newNumber(index, NoDecimal, key->pn_pos))) {
   1129        return false;
   1130      }
   1131      key = &elem->key();
   1132    } else {
   1133      name = keyIndex;
   1134    }
   1135  } else if (key->isKind(ParseNodeKind::NumberExpr)) {
   1136    auto* numeric = &key->as<NumericLiteral>();
   1137    double number = numeric->value();
   1138    if (number != ToUint32(number)) {
   1139      // Optimization 2: We have something like expr[3.14]. The number
   1140      // isn't an array index, so it converts to a string ("3.14"),
   1141      // enabling optimization 3 below.
   1142      name = numeric->toAtom(info.fc, info.parserAtoms);
   1143      if (!name) {
   1144        return false;
   1145      }
   1146    }
   1147  }
   1148 
   1149  // If we don't have a name, we can't optimize to getprop.
   1150  if (!name) {
   1151    return true;
   1152  }
   1153 
   1154  // Optimization 3: We have expr["foo"] where foo is not an index.  Convert
   1155  // to a property access (like expr.foo) that optimizes better downstream.
   1156 
   1157  NameNode* propertyNameExpr;
   1158  MOZ_TRY_VAR_OR_RETURN(propertyNameExpr,
   1159                        info.handler->newPropertyName(name, key->pn_pos),
   1160                        false);
   1161  if (!TryReplaceNode(
   1162          nodePtr, info.handler->newPropertyAccess(expr, propertyNameExpr))) {
   1163    return false;
   1164  }
   1165 
   1166  return true;
   1167 }
   1168 
   1169 static bool FoldAdd(FoldInfo info, ParseNode** nodePtr) {
   1170  ListNode* node = &(*nodePtr)->as<ListNode>();
   1171 
   1172  MOZ_ASSERT(node->isKind(ParseNodeKind::AddExpr));
   1173  MOZ_ASSERT(node->count() >= 2);
   1174 
   1175  // Fold leading numeric operands together:
   1176  //
   1177  //   (1 + 2 + x)  becomes  (3 + x)
   1178  //
   1179  // Don't go past the leading operands: additions after a string are
   1180  // string concatenations, not additions: ("1" + 2 + 3 === "123").
   1181  ParseNode** current = node->unsafeHeadReference();
   1182  ParseNode** next = &(*current)->pn_next;
   1183  if ((*current)->isKind(ParseNodeKind::NumberExpr)) {
   1184    do {
   1185      if (!(*next)->isKind(ParseNodeKind::NumberExpr)) {
   1186        break;
   1187      }
   1188 
   1189      double left = (*current)->as<NumericLiteral>().value();
   1190      double right = (*next)->as<NumericLiteral>().value();
   1191      TokenPos pos((*current)->pn_pos.begin, (*next)->pn_pos.end);
   1192 
   1193      if (!TryReplaceNode(
   1194              current, info.handler->newNumber(left + right, NoDecimal, pos))) {
   1195        return false;
   1196      }
   1197 
   1198      (*current)->pn_next = (*next)->pn_next;
   1199      next = &(*current)->pn_next;
   1200 
   1201      node->unsafeDecrementCount();
   1202    } while (*next);
   1203  }
   1204 
   1205  // If any operands remain, attempt string concatenation folding.
   1206  do {
   1207    // If no operands remain, we're done.
   1208    if (!*next) {
   1209      break;
   1210    }
   1211 
   1212    // (number + string) is string concatenation *only* at the start of
   1213    // the list: (x + 1 + "2" !== x + "12") when x is a number.
   1214    if ((*current)->isKind(ParseNodeKind::NumberExpr) &&
   1215        (*next)->isKind(ParseNodeKind::StringExpr)) {
   1216      if (!FoldType(info, current, ParseNodeKind::StringExpr)) {
   1217        return false;
   1218      }
   1219      next = &(*current)->pn_next;
   1220    }
   1221 
   1222    // The first string forces all subsequent additions to be
   1223    // string concatenations.
   1224    do {
   1225      if ((*current)->isKind(ParseNodeKind::StringExpr)) {
   1226        break;
   1227      }
   1228 
   1229      current = next;
   1230      next = &(*current)->pn_next;
   1231    } while (*next);
   1232 
   1233    // If there's nothing left to fold, we're done.
   1234    if (!*next) {
   1235      break;
   1236    }
   1237 
   1238    do {
   1239      // Concat all strings.
   1240      MOZ_ASSERT((*current)->isKind(ParseNodeKind::StringExpr));
   1241 
   1242      // To avoid unnecessarily copy when there's no strings after the
   1243      // first item, lazily construct StringBuilder and append the first item.
   1244      mozilla::Maybe<StringBuilder> accum;
   1245      TaggedParserAtomIndex firstAtom;
   1246      firstAtom = (*current)->as<NameNode>().atom();
   1247 
   1248      do {
   1249        // Try folding the next operand to a string.
   1250        if (!FoldType(info, next, ParseNodeKind::StringExpr)) {
   1251          return false;
   1252        }
   1253 
   1254        // Stop glomming once folding doesn't produce a string.
   1255        if (!(*next)->isKind(ParseNodeKind::StringExpr)) {
   1256          break;
   1257        }
   1258 
   1259        if (!accum) {
   1260          accum.emplace(info.fc);
   1261          if (!accum->append(info.parserAtoms, firstAtom)) {
   1262            return false;
   1263          }
   1264        }
   1265        // Append this string and remove the node.
   1266        if (!accum->append(info.parserAtoms, (*next)->as<NameNode>().atom())) {
   1267          return false;
   1268        }
   1269 
   1270        (*current)->pn_next = (*next)->pn_next;
   1271        next = &(*current)->pn_next;
   1272 
   1273        node->unsafeDecrementCount();
   1274      } while (*next);
   1275 
   1276      // Replace with concatenation if we multiple nodes.
   1277      if (accum) {
   1278        auto combination = accum->finishParserAtom(info.parserAtoms, info.fc);
   1279        if (!combination) {
   1280          return false;
   1281        }
   1282 
   1283        // Replace |current|'s string with the entire combination.
   1284        MOZ_ASSERT((*current)->isKind(ParseNodeKind::StringExpr));
   1285        (*current)->as<NameNode>().setAtom(combination);
   1286      }
   1287 
   1288      // If we're out of nodes, we're done.
   1289      if (!*next) {
   1290        break;
   1291      }
   1292 
   1293      current = next;
   1294      next = &(*current)->pn_next;
   1295 
   1296      // If we're out of nodes *after* the non-foldable-to-string
   1297      // node, we're done.
   1298      if (!*next) {
   1299        break;
   1300      }
   1301 
   1302      // Otherwise find the next node foldable to a string, and loop.
   1303      do {
   1304        current = next;
   1305 
   1306        if (!FoldType(info, current, ParseNodeKind::StringExpr)) {
   1307          return false;
   1308        }
   1309        next = &(*current)->pn_next;
   1310      } while (!(*current)->isKind(ParseNodeKind::StringExpr) && *next);
   1311    } while (*next);
   1312  } while (false);
   1313 
   1314  MOZ_ASSERT(!*next, "must have considered all nodes here");
   1315  MOZ_ASSERT(!(*current)->pn_next, "current node must be the last node");
   1316 
   1317  node->unsafeReplaceTail(&(*current)->pn_next);
   1318 
   1319  if (node->count() == 1) {
   1320    // We reduced the list to a constant.  Replace the ParseNodeKind::Add node
   1321    // with that constant.
   1322    ReplaceNode(nodePtr, *current);
   1323  }
   1324 
   1325  return true;
   1326 }
   1327 
   1328 class FoldVisitor : public RewritingParseNodeVisitor<FoldVisitor> {
   1329  using Base = RewritingParseNodeVisitor;
   1330 
   1331  ParserAtomsTable& parserAtoms;
   1332  BigIntStencilVector& bigInts;
   1333  FullParseHandler* handler;
   1334 
   1335  FoldInfo info() const { return FoldInfo{fc_, parserAtoms, bigInts, handler}; }
   1336 
   1337 public:
   1338  FoldVisitor(FrontendContext* fc, ParserAtomsTable& parserAtoms,
   1339              BigIntStencilVector& bigInts, FullParseHandler* handler)
   1340      : RewritingParseNodeVisitor(fc),
   1341        parserAtoms(parserAtoms),
   1342        bigInts(bigInts),
   1343        handler(handler) {}
   1344 
   1345  bool visitElemExpr(ParseNode*& pn) {
   1346    return Base::visitElemExpr(pn) && FoldElement(info(), &pn);
   1347  }
   1348 
   1349  bool visitTypeOfExpr(ParseNode*& pn) {
   1350    return Base::visitTypeOfExpr(pn) && FoldTypeOfExpr(info(), &pn);
   1351  }
   1352 
   1353  bool visitDeleteExpr(ParseNode*& pn) {
   1354    return Base::visitDeleteExpr(pn) && FoldDeleteExpr(info(), &pn);
   1355  }
   1356 
   1357  bool visitDeleteElemExpr(ParseNode*& pn) {
   1358    return Base::visitDeleteElemExpr(pn) && FoldDeleteElement(info(), &pn);
   1359  }
   1360 
   1361  bool visitNotExpr(ParseNode*& pn) {
   1362    return Base::visitNotExpr(pn) && FoldNot(info(), &pn);
   1363  }
   1364 
   1365  bool visitBitNotExpr(ParseNode*& pn) {
   1366    return Base::visitBitNotExpr(pn) && FoldUnaryArithmetic(info(), &pn);
   1367  }
   1368 
   1369  bool visitPosExpr(ParseNode*& pn) {
   1370    return Base::visitPosExpr(pn) && FoldUnaryArithmetic(info(), &pn);
   1371  }
   1372 
   1373  bool visitNegExpr(ParseNode*& pn) {
   1374    return Base::visitNegExpr(pn) && FoldUnaryArithmetic(info(), &pn);
   1375  }
   1376 
   1377  bool visitPowExpr(ParseNode*& pn) {
   1378    return Base::visitPowExpr(pn) && FoldExponentiation(info(), &pn);
   1379  }
   1380 
   1381  bool visitMulExpr(ParseNode*& pn) {
   1382    return Base::visitMulExpr(pn) && FoldBinaryArithmetic(info(), &pn);
   1383  }
   1384 
   1385  bool visitDivExpr(ParseNode*& pn) {
   1386    return Base::visitDivExpr(pn) && FoldBinaryArithmetic(info(), &pn);
   1387  }
   1388 
   1389  bool visitModExpr(ParseNode*& pn) {
   1390    return Base::visitModExpr(pn) && FoldBinaryArithmetic(info(), &pn);
   1391  }
   1392 
   1393  bool visitAddExpr(ParseNode*& pn) {
   1394    return Base::visitAddExpr(pn) && FoldAdd(info(), &pn);
   1395  }
   1396 
   1397  bool visitSubExpr(ParseNode*& pn) {
   1398    return Base::visitSubExpr(pn) && FoldBinaryArithmetic(info(), &pn);
   1399  }
   1400 
   1401  bool visitLshExpr(ParseNode*& pn) {
   1402    return Base::visitLshExpr(pn) && FoldBinaryArithmetic(info(), &pn);
   1403  }
   1404 
   1405  bool visitRshExpr(ParseNode*& pn) {
   1406    return Base::visitRshExpr(pn) && FoldBinaryArithmetic(info(), &pn);
   1407  }
   1408 
   1409  bool visitUrshExpr(ParseNode*& pn) {
   1410    return Base::visitUrshExpr(pn) && FoldBinaryArithmetic(info(), &pn);
   1411  }
   1412 
   1413  bool visitAndExpr(ParseNode*& pn) {
   1414    // Note that this does result in the unfortunate fact that dead arms of this
   1415    // node get constant folded. The same goes for visitOr and visitCoalesce.
   1416    return Base::visitAndExpr(pn) && FoldAndOrCoalesce(info(), &pn);
   1417  }
   1418 
   1419  bool visitOrExpr(ParseNode*& pn) {
   1420    return Base::visitOrExpr(pn) && FoldAndOrCoalesce(info(), &pn);
   1421  }
   1422 
   1423  bool visitCoalesceExpr(ParseNode*& pn) {
   1424    return Base::visitCoalesceExpr(pn) && FoldAndOrCoalesce(info(), &pn);
   1425  }
   1426 
   1427  bool visitConditionalExpr(ParseNode*& pn) {
   1428    // Don't call base-class visitConditional because FoldConditional processes
   1429    // pn's child nodes specially to save stack space.
   1430    return FoldConditional(info(), &pn);
   1431  }
   1432 
   1433 private:
   1434  bool internalVisitCall(BinaryNode* node) {
   1435    MOZ_ASSERT(node->isKind(ParseNodeKind::CallExpr) ||
   1436               node->isKind(ParseNodeKind::OptionalCallExpr) ||
   1437               node->isKind(ParseNodeKind::SuperCallExpr) ||
   1438               node->isKind(ParseNodeKind::NewExpr) ||
   1439               node->isKind(ParseNodeKind::TaggedTemplateExpr));
   1440 
   1441    // Don't fold a parenthesized callable component in an invocation, as this
   1442    // might cause a different |this| value to be used, changing semantics:
   1443    //
   1444    //   var prop = "global";
   1445    //   var obj = { prop: "obj", f: function() { return this.prop; } };
   1446    //   assertEq((true ? obj.f : null)(), "global");
   1447    //   assertEq(obj.f(), "obj");
   1448    //   assertEq((true ? obj.f : null)``, "global");
   1449    //   assertEq(obj.f``, "obj");
   1450    //
   1451    // As an exception to this, we do allow folding the function in
   1452    // `(function() { ... })()` (the module pattern), because that lets us
   1453    // constant fold code inside that function.
   1454    //
   1455    // See bug 537673 and bug 1182373.
   1456    ParseNode* callee = node->left();
   1457    if (node->isKind(ParseNodeKind::NewExpr) || !callee->isInParens() ||
   1458        callee->is<FunctionNode>()) {
   1459      if (!visit(*node->unsafeLeftReference())) {
   1460        return false;
   1461      }
   1462    }
   1463 
   1464    if (!visit(*node->unsafeRightReference())) {
   1465      return false;
   1466    }
   1467 
   1468    return true;
   1469  }
   1470 
   1471 public:
   1472  bool visitCallExpr(ParseNode*& pn) {
   1473    return internalVisitCall(&pn->as<BinaryNode>());
   1474  }
   1475 
   1476  bool visitOptionalCallExpr(ParseNode*& pn) {
   1477    return internalVisitCall(&pn->as<BinaryNode>());
   1478  }
   1479 
   1480  bool visitNewExpr(ParseNode*& pn) {
   1481    return internalVisitCall(&pn->as<BinaryNode>());
   1482  }
   1483 
   1484  bool visitSuperCallExpr(ParseNode*& pn) {
   1485    return internalVisitCall(&pn->as<BinaryNode>());
   1486  }
   1487 
   1488  bool visitTaggedTemplateExpr(ParseNode*& pn) {
   1489    return internalVisitCall(&pn->as<BinaryNode>());
   1490  }
   1491 
   1492  bool visitIfStmt(ParseNode*& pn) {
   1493    // Don't call base-class visitIf because FoldIf processes pn's child nodes
   1494    // specially to save stack space.
   1495    return FoldIf(info(), &pn);
   1496  }
   1497 
   1498  bool visitForStmt(ParseNode*& pn) {
   1499    if (!Base::visitForStmt(pn)) {
   1500      return false;
   1501    }
   1502 
   1503    ForNode& stmt = pn->as<ForNode>();
   1504    if (stmt.left()->isKind(ParseNodeKind::ForHead)) {
   1505      TernaryNode& head = stmt.left()->as<TernaryNode>();
   1506      ParseNode** test = head.unsafeKid2Reference();
   1507      if (*test) {
   1508        if (!SimplifyCondition(info(), test)) {
   1509          return false;
   1510        }
   1511        if ((*test)->isKind(ParseNodeKind::TrueExpr)) {
   1512          *test = nullptr;
   1513        }
   1514      }
   1515    }
   1516 
   1517    return true;
   1518  }
   1519 
   1520  bool visitWhileStmt(ParseNode*& pn) {
   1521    BinaryNode& node = pn->as<BinaryNode>();
   1522    return Base::visitWhileStmt(pn) &&
   1523           SimplifyCondition(info(), node.unsafeLeftReference());
   1524  }
   1525 
   1526  bool visitDoWhileStmt(ParseNode*& pn) {
   1527    BinaryNode& node = pn->as<BinaryNode>();
   1528    return Base::visitDoWhileStmt(pn) &&
   1529           SimplifyCondition(info(), node.unsafeRightReference());
   1530  }
   1531 
   1532  bool visitFunction(ParseNode*& pn) {
   1533    FunctionNode& node = pn->as<FunctionNode>();
   1534 
   1535    // Don't constant-fold inside "use asm" code, as this could create a parse
   1536    // tree that doesn't type-check as asm.js.
   1537    if (node.funbox()->useAsmOrInsideUseAsm()) {
   1538      return true;
   1539    }
   1540 
   1541    return Base::visitFunction(pn);
   1542  }
   1543 
   1544  bool visitArrayExpr(ParseNode*& pn) {
   1545    if (!Base::visitArrayExpr(pn)) {
   1546      return false;
   1547    }
   1548 
   1549    ListNode* list = &pn->as<ListNode>();
   1550    // Empty arrays are non-constant, since we cannot easily determine their
   1551    // type.
   1552    if (list->hasNonConstInitializer() && list->count() > 0) {
   1553      for (ParseNode* node : list->contents()) {
   1554        if (!node->isConstant()) {
   1555          return true;
   1556        }
   1557      }
   1558      list->unsetHasNonConstInitializer();
   1559    }
   1560    return true;
   1561  }
   1562 
   1563  bool visitObjectExpr(ParseNode*& pn) {
   1564    if (!Base::visitObjectExpr(pn)) {
   1565      return false;
   1566    }
   1567 
   1568    ListNode* list = &pn->as<ListNode>();
   1569    if (list->hasNonConstInitializer()) {
   1570      for (ParseNode* node : list->contents()) {
   1571        if (node->getKind() != ParseNodeKind::PropertyDefinition) {
   1572          return true;
   1573        }
   1574        BinaryNode* binary = &node->as<BinaryNode>();
   1575        if (binary->left()->isKind(ParseNodeKind::ComputedName)) {
   1576          return true;
   1577        }
   1578        if (!binary->right()->isConstant()) {
   1579          return true;
   1580        }
   1581      }
   1582      list->unsetHasNonConstInitializer();
   1583    }
   1584    return true;
   1585  }
   1586 };
   1587 
   1588 static bool Fold(FrontendContext* fc, ParserAtomsTable& parserAtoms,
   1589                 BigIntStencilVector& bigInts, FullParseHandler* handler,
   1590                 ParseNode** pnp) {
   1591  FoldVisitor visitor(fc, parserAtoms, bigInts, handler);
   1592  return visitor.visit(*pnp);
   1593 }
   1594 static bool Fold(FoldInfo info, ParseNode** pnp) {
   1595  return Fold(info.fc, info.parserAtoms, info.bigInts, info.handler, pnp);
   1596 }
   1597 
   1598 bool frontend::FoldConstants(FrontendContext* fc, ParserAtomsTable& parserAtoms,
   1599                             BigIntStencilVector& bigInts, ParseNode** pnp,
   1600                             FullParseHandler* handler) {
   1601  return Fold(fc, parserAtoms, bigInts, handler, pnp);
   1602 }