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