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