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 = ¤t->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