summaryrefslogtreecommitdiff
path: root/js/src/frontend/FoldConstants.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/frontend/FoldConstants.cpp')
-rw-r--r--js/src/frontend/FoldConstants.cpp46
1 files changed, 30 insertions, 16 deletions
diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp
index 979af29b42..c3354e44a4 100644
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -326,6 +326,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
case PNK_POSTINCREMENT:
case PNK_PREDECREMENT:
case PNK_POSTDECREMENT:
+ case PNK_COALESCE:
case PNK_OR:
case PNK_AND:
case PNK_BITOR:
@@ -482,15 +483,19 @@ IsEffectless(ParseNode* node)
enum Truthiness { Truthy, Falsy, Unknown };
static Truthiness
-Boolish(ParseNode* pn)
+Boolish(ParseNode* pn, bool isNullish = false)
{
switch (pn->getKind()) {
- case PNK_NUMBER:
- return (pn->pn_dval != 0 && !IsNaN(pn->pn_dval)) ? Truthy : Falsy;
+ case PNK_NUMBER: {
+ bool isNonZeroNumber = (pn->pn_dval != 0 && !IsNaN(pn->pn_dval));
+ return (isNullish || isNonZeroNumber) ? Truthy : Falsy;
+ }
case PNK_STRING:
- case PNK_TEMPLATE_STRING:
- return (pn->pn_atom->length() > 0) ? Truthy : Falsy;
+ case PNK_TEMPLATE_STRING: {
+ bool isNonZeroLengthString = (pn->pn_atom->length() > 0);
+ return (isNullish || isNonZeroLengthString) ? Truthy : Falsy;
+ }
case PNK_TRUE:
case PNK_FUNCTION:
@@ -498,6 +503,8 @@ Boolish(ParseNode* pn)
return Truthy;
case PNK_FALSE:
+ return isNullish ? Truthy : Falsy;
+
case PNK_NULL:
case PNK_RAW_UNDEFINED:
return Falsy;
@@ -752,21 +759,24 @@ FoldIncrementDecrement(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHa
}
static bool
-FoldAndOr(ExclusiveContext* cx, ParseNode** nodePtr, Parser<FullParseHandler>& parser,
+FoldLogical(ExclusiveContext* cx, ParseNode** nodePtr, Parser<FullParseHandler>& parser,
bool inGenexpLambda)
{
ParseNode* node = *nodePtr;
- MOZ_ASSERT(node->isKind(PNK_AND) || node->isKind(PNK_OR));
+ bool isCoalesceNode = node->isKind(PNK_COALESCE);
+ bool isOrNode = node->isKind(PNK_OR);
+ bool isAndNode = node->isKind(PNK_AND);
+
+ MOZ_ASSERT(isCoalesceNode || isOrNode || isAndNode);
MOZ_ASSERT(node->isArity(PN_LIST));
- bool isOrNode = node->isKind(PNK_OR);
ParseNode** elem = &node->pn_head;
do {
if (!Fold(cx, elem, parser, inGenexpLambda))
return false;
- Truthiness t = Boolish(*elem);
+ Truthiness t = Boolish(*elem, isCoalesceNode);
// If we don't know the constant-folded node's truthiness, we can't
// reduce this node with its surroundings. Continue folding any
@@ -776,11 +786,16 @@ FoldAndOr(ExclusiveContext* cx, ParseNode** nodePtr, Parser<FullParseHandler>& p
continue;
}
+ bool terminateEarly = (isOrNode && t == Truthy) ||
+ (isAndNode && t == Falsy) ||
+ (isCoalesceNode && t == Truthy);
+
// If the constant-folded node's truthiness will terminate the
- // condition -- `a || true || expr` or |b && false && expr| -- then
- // trailing nodes will never be evaluated. Truncate the list after
- // the known-truthiness node, as it's the overall result.
- if ((t == Truthy) == isOrNode) {
+ // condition -- `a || true || expr` or `b && false && expr` or
+ // `false ?? c ?? expr` -- then trailing nodes will never be
+ // evaluated. Truncate the list after the known-truthiness node,
+ // as it's the overall result.
+ if (terminateEarly) {
ParseNode* afterNext;
for (ParseNode* next = (*elem)->pn_next; next; next = afterNext) {
afterNext = next->pn_next;
@@ -795,8 +810,6 @@ FoldAndOr(ExclusiveContext* cx, ParseNode** nodePtr, Parser<FullParseHandler>& p
break;
}
- MOZ_ASSERT((t == Truthy) == !isOrNode);
-
// We've encountered a vacuous node that'll never short- circuit
// evaluation.
if ((*elem)->pn_next) {
@@ -1738,9 +1751,10 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
return Fold(cx, &expr, parser, inGenexpLambda);
return true;
+ case PNK_COALESCE:
case PNK_AND:
case PNK_OR:
- return FoldAndOr(cx, pnp, parser, inGenexpLambda);
+ return FoldLogical(cx, pnp, parser, inGenexpLambda);
case PNK_FUNCTION:
return FoldFunction(cx, pn, parser, inGenexpLambda);