Bug 1183400 - Remove special |void| handling by making Boolish recognize |void| expressions as falsy, when they're obviously so. r=efaust
authorJeff Walden <jwalden@mit.edu>
Mon, 13 Jul 2015 13:09:54 -0700
changeset 257759 aacd11c8f3ca9522b6c91a0386f44982b6ee8980
parent 257758 60862f5c7abf30f27173bb268f4d457a50f4abee
child 257760 7d13f9aefa3e41dc84ee0cb8ed505ec358f7f495
push id29226
push userryanvm@gmail.com
push dateFri, 14 Aug 2015 13:01:14 +0000
treeherdermozilla-central@1b2402247429 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs1183400
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1183400 - Remove special |void| handling by making Boolish recognize |void| expressions as falsy, when they're obviously so. r=efaust
js/src/frontend/FoldConstants.cpp
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -482,27 +482,54 @@ enum Truthiness { Truthy, Falsy, Unknown
 static Truthiness
 Boolish(ParseNode* pn)
 {
     switch (pn->getKind()) {
       case PNK_NUMBER:
         return (pn->pn_dval != 0 && !IsNaN(pn->pn_dval)) ? Truthy : Falsy;
 
       case PNK_STRING:
+      case PNK_TEMPLATE_STRING:
         return (pn->pn_atom->length() > 0) ? Truthy : Falsy;
 
       case PNK_TRUE:
       case PNK_FUNCTION:
       case PNK_GENEXP:
         return Truthy;
 
       case PNK_FALSE:
       case PNK_NULL:
         return Falsy;
 
+      case PNK_VOID: {
+        // |void <foo>| evaluates to |undefined| which isn't truthy.  But the
+        // sense of this method requires that the expression be literally
+        // replaceable with true/false: not the case if the nested expression
+        // is effectful, might throw, &c.  Walk past the |void| (and nested
+        // |void| expressions, for good measure) and check that the nested
+        // expression doesn't break this requirement before indicating falsity.
+        do {
+            pn = pn->pn_kid;
+        } while (pn->isKind(PNK_VOID));
+
+        if (pn->isKind(PNK_TRUE) ||
+            pn->isKind(PNK_FALSE) ||
+            pn->isKind(PNK_STRING) ||
+            pn->isKind(PNK_TEMPLATE_STRING) ||
+            pn->isKind(PNK_NUMBER) ||
+            pn->isKind(PNK_NULL) ||
+            pn->isKind(PNK_FUNCTION) ||
+            pn->isKind(PNK_GENEXP))
+        {
+            return Falsy;
+        }
+
+        return Unknown;
+      }
+
       default:
         return Unknown;
     }
 }
 
 // Expressions that appear in a few specific places are treated specially
 // during constant folding. This enum tells where a parse node appears.
 enum class SyntacticContext : int {
@@ -583,46 +610,16 @@ FoldTypeOfExpr(ExclusiveContext* cx, Par
         node->setOp(JSOP_NOP);
         node->pn_atom = result;
     }
 
     return true;
 }
 
 static bool
-FoldVoid(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser,
-         bool inGenexpLambda, SyntacticContext sc)
-{
-    MOZ_ASSERT(node->isKind(PNK_VOID));
-    MOZ_ASSERT(node->isArity(PN_UNARY));
-
-    ParseNode*& expr = node->pn_kid;
-    if (!Fold(cx, &expr, parser, inGenexpLambda, SyntacticContext::Other))
-        return false;
-
-    if (sc == SyntacticContext::Condition) {
-        if (expr->isKind(PNK_TRUE) ||
-            expr->isKind(PNK_FALSE) ||
-            expr->isKind(PNK_STRING) ||
-            expr->isKind(PNK_TEMPLATE_STRING) ||
-            expr->isKind(PNK_NUMBER) ||
-            expr->isKind(PNK_NULL) ||
-            expr->isKind(PNK_FUNCTION))
-        {
-            parser.prepareNodeForMutation(node);
-            node->setKind(PNK_FALSE);
-            node->setArity(PN_NULLARY);
-            node->setOp(JSOP_FALSE);
-        }
-    }
-
-    return true;
-}
-
-static bool
 FoldDeleteExpr(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser,
                bool inGenexpLambda)
 {
     MOZ_ASSERT(node->isKind(PNK_DELETEEXPR));
     MOZ_ASSERT(node->isArity(PN_UNARY));
 
     ParseNode*& expr = node->pn_kid;
     if (!Fold(cx, &expr, parser, inGenexpLambda, SyntacticContext::Other))
@@ -1751,19 +1748,16 @@ Fold(ExclusiveContext* cx, ParseNode** p
         MOZ_ASSERT(pn->isArity(PN_UNARY));
         MOZ_ASSERT(pn->pn_kid->isKind(PNK_NAME));
         MOZ_ASSERT(!pn->pn_kid->maybeExpr());
         return true;
 
       case PNK_TYPEOFEXPR:
         return FoldTypeOfExpr(cx, pn, parser, inGenexpLambda);
 
-      case PNK_VOID:
-        return FoldVoid(cx, pn, parser, inGenexpLambda, sc);
-
       case PNK_DELETENAME: {
         MOZ_ASSERT(pn->isArity(PN_UNARY));
         MOZ_ASSERT(pn->pn_kid->isKind(PNK_NAME));
         return true;
       }
 
       case PNK_DELETEEXPR:
         return FoldDeleteExpr(cx, pn, parser, inGenexpLambda);
@@ -1799,16 +1793,17 @@ Fold(ExclusiveContext* cx, ParseNode** p
       case PNK_THROW:
       case PNK_ARRAYPUSH:
       case PNK_MUTATEPROTO:
       case PNK_COMPUTED_NAME:
       case PNK_SPREAD:
       case PNK_SUPERELEM:
       case PNK_EXPORT:
       case PNK_EXPORT_DEFAULT:
+      case PNK_VOID:
         MOZ_ASSERT(pn->isArity(PN_UNARY));
         return Fold(cx, &pn->pn_kid, parser, inGenexpLambda, SyntacticContext::Other);
 
       case PNK_SEMI:
         MOZ_ASSERT(pn->isArity(PN_UNARY));
         if (ParseNode*& expr = pn->pn_kid)
             return Fold(cx, &expr, parser, inGenexpLambda, SyntacticContext::Other);
         return true;