Bug 1514919 - Do not constant-fold the same nodes more than once. r=jorendorff
authorAshley Hauck <khyperia@mozilla.com>
Wed, 09 Jan 2019 21:27:39 +0000
changeset 510464 585a078ac5b3ffa4d19fbe5eddecfbb4fefa3ea7
parent 510463 47b94d26f8a57c50298b284342f270151d273ed5
child 510465 5641b0f246e9d113528cf2b8813e2f716d4830e0
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1514919
milestone66.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 1514919 - Do not constant-fold the same nodes more than once. r=jorendorff Differential Revision: https://phabricator.services.mozilla.com/D14813
js/src/frontend/FoldConstants.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -1438,16 +1438,59 @@ class FoldVisitor : public ParseNodeVisi
     // Don't constant-fold inside "use asm" code, as this could create a parse
     // tree that doesn't type-check as asm.js.
     if (node.funbox()->useAsmOrInsideUseAsm()) {
       return true;
     }
 
     return Base::visitFunction(pn);
   }
+
+  bool visitArrayExpr(ParseNode*& pn) {
+    if (!Base::visitArrayExpr(pn)) {
+      return false;
+    }
+
+    ListNode* list = &pn->as<ListNode>();
+    // Empty arrays are non-constant, since we cannot easily determine their
+    // type.
+    if (list->hasNonConstInitializer() && list->count() > 0) {
+      for (ParseNode* node : list->contents()) {
+        if (!node->isConstant()) {
+          return true;
+        }
+      }
+      list->unsetHasNonConstInitializer();
+    }
+    return true;
+  }
+
+  bool visitObjectExpr(ParseNode*& pn) {
+    if (!Base::visitObjectExpr(pn)) {
+      return false;
+    }
+
+    ListNode* list = &pn->as<ListNode>();
+    if (list->hasNonConstInitializer()) {
+      for (ParseNode* node : list->contents()) {
+        if (node->getKind() != ParseNodeKind::Colon) {
+          return true;
+        }
+        BinaryNode* binary = &node->as<BinaryNode>();
+        if (binary->left()->isKind(ParseNodeKind::ComputedName)) {
+          return true;
+        }
+        if (!binary->right()->isConstant()) {
+          return true;
+        }
+      }
+      list->unsetHasNonConstInitializer();
+    }
+    return true;
+  }
 };
 
 bool Fold(JSContext* cx, ParseNode** pnp) {
   FoldVisitor visitor(cx);
   return visitor.visit(*pnp);
 }
 
 bool frontend::FoldConstants(JSContext* cx, ParseNode** pnp,
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -1229,38 +1229,42 @@ class ListNode : public ParseNode {
 
   MOZ_MUST_USE bool hasArrayHoleOrSpread() const {
     MOZ_ASSERT(isKind(ParseNodeKind::ArrayExpr));
     return pn_u.list.xflags & hasArrayHoleOrSpreadBit;
   }
 
   MOZ_MUST_USE bool hasNonConstInitializer() const {
     MOZ_ASSERT(isKind(ParseNodeKind::ArrayExpr) ||
-               isKind(ParseNodeKind::ObjectExpr) ||
-               isKind(ParseNodeKind::ClassMemberList));
+               isKind(ParseNodeKind::ObjectExpr));
     return pn_u.list.xflags & hasNonConstInitializerBit;
   }
 
   void setHasTopLevelFunctionDeclarations() {
     MOZ_ASSERT(isKind(ParseNodeKind::StatementList));
     pn_u.list.xflags |= hasTopLevelFunctionDeclarationsBit;
   }
 
   void setHasArrayHoleOrSpread() {
     MOZ_ASSERT(isKind(ParseNodeKind::ArrayExpr));
     pn_u.list.xflags |= hasArrayHoleOrSpreadBit;
   }
 
   void setHasNonConstInitializer() {
     MOZ_ASSERT(isKind(ParseNodeKind::ArrayExpr) ||
-               isKind(ParseNodeKind::ObjectExpr) ||
-               isKind(ParseNodeKind::ClassMemberList));
+               isKind(ParseNodeKind::ObjectExpr));
     pn_u.list.xflags |= hasNonConstInitializerBit;
   }
 
+  void unsetHasNonConstInitializer() {
+    MOZ_ASSERT(isKind(ParseNodeKind::ArrayExpr) ||
+               isKind(ParseNodeKind::ObjectExpr));
+    pn_u.list.xflags &= ~hasNonConstInitializerBit;
+  }
+
   /*
    * Compute a pointer to the last element in a singly-linked list. NB: list
    * must be non-empty -- this is asserted!
    */
   ParseNode* last() const {
     MOZ_ASSERT(!empty());
     //
     // ParseNode                      ParseNode
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -3760,24 +3760,16 @@ GeneralParser<ParseHandler, Unit>::bindi
   }
 
   BinaryNodeType assign =
       handler.newAssignment(ParseNodeKind::AssignExpr, lhs, rhs);
   if (!assign) {
     return null();
   }
 
-  if (foldConstants) {
-    Node node = assign;
-    if (!FoldConstants(context, &node, this)) {
-      return null();
-    }
-    assign = handler.asBinary(node);
-  }
-
   return assign;
 }
 
 template <class ParseHandler, typename Unit>
 typename ParseHandler::NameNodeType
 GeneralParser<ParseHandler, Unit>::bindingIdentifier(
     DeclarationKind kind, YieldHandling yieldHandling) {
   RootedPropertyName name(context, bindingIdentifier(yieldHandling));
@@ -9262,19 +9254,16 @@ GeneralParser<ParseHandler, Unit>::array
                                   &possibleErrorInner);
         if (!element) {
           return null();
         }
         if (!checkDestructuringAssignmentElement(
                 element, elementPos, &possibleErrorInner, possibleError)) {
           return null();
         }
-        if (foldConstants && !FoldConstants(context, &element, this)) {
-          return null();
-        }
         handler.addArrayElement(literal, element);
       }
 
       bool matched;
       if (!tokenStream.matchToken(&matched, TokenKind::Comma,
                                   TokenStream::Operand)) {
         return null();
       }
@@ -9383,17 +9372,18 @@ typename ParseHandler::Node GeneralParse
       propName = stringLiteral();
       if (!propName) {
         return null();
       }
       break;
     }
 
     case TokenKind::LeftBracket:
-      propName = computedPropertyName(yieldHandling, maybeDecl, propList);
+      propName = computedPropertyName(yieldHandling, maybeDecl,
+                                      propertyNameContext, propList);
       if (!propName) {
         return null();
       }
       break;
 
     default: {
       if (!TokenKindIsPossibleIdentifierName(ltok)) {
         error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(ltok));
@@ -9448,17 +9438,18 @@ typename ParseHandler::Node GeneralParse
         if (!propAtom.get()) {
           return null();
         }
         return newNumber(anyChars.currentToken());
       }
       if (tt == TokenKind::LeftBracket) {
         tokenStream.consumeKnownToken(TokenKind::LeftBracket);
 
-        return computedPropertyName(yieldHandling, maybeDecl, propList);
+        return computedPropertyName(yieldHandling, maybeDecl,
+                                    propertyNameContext, propList);
       }
 
       // Not an accessor property after all.
       propName = handler.newObjectLiteralPropertyName(propAtom.get(), pos());
       if (!propName) {
         return null();
       }
       break;
@@ -9523,26 +9514,27 @@ typename ParseHandler::Node GeneralParse
   error(JSMSG_COLON_AFTER_ID);
   return null();
 }
 
 template <class ParseHandler, typename Unit>
 typename ParseHandler::UnaryNodeType
 GeneralParser<ParseHandler, Unit>::computedPropertyName(
     YieldHandling yieldHandling, const Maybe<DeclarationKind>& maybeDecl,
-    ListNodeType literal) {
+    PropertyNameContext propertyNameContext, ListNodeType literal) {
   MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket));
 
   uint32_t begin = pos().begin;
 
   if (maybeDecl) {
     if (*maybeDecl == DeclarationKind::FormalParameter) {
       pc->functionBox()->hasParameterExprs = true;
     }
-  } else {
+  } else if (propertyNameContext ==
+             PropertyNameContext::PropertyNameInLiteral) {
     handler.setListHasNonConstInitializer(literal);
   }
 
   Node assignNode = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
   if (!assignNode) {
     return null();
   }
 
@@ -9642,41 +9634,32 @@ GeneralParser<ParseHandler, Unit>::objec
 
             // Otherwise delay error reporting until we've
             // determined whether or not we're destructuring.
             possibleError->setPendingExpressionErrorAt(
                 namePos, JSMSG_DUPLICATE_PROTO_PROPERTY);
           }
           seenPrototypeMutation = true;
 
-          if (foldConstants && !FoldConstants(context, &propExpr, this)) {
-            return null();
-          }
-
           // This occurs *only* if we observe PropertyType::Normal!
           // Only |__proto__: v| mutates [[Prototype]]. Getters,
           // setters, method/generator definitions, computed
           // property name versions of all of these, and shorthands
           // do not.
           if (!handler.addPrototypeMutation(literal, namePos.begin, propExpr)) {
             return null();
           }
         } else {
-          // Use Node instead of BinaryNodeType to pass it to
-          // FoldConstants.
-          Node propDef = handler.newPropertyDefinition(propName, propExpr);
+          BinaryNodeType propDef =
+              handler.newPropertyDefinition(propName, propExpr);
           if (!propDef) {
             return null();
           }
 
-          if (foldConstants && !FoldConstants(context, &propDef, this)) {
-            return null();
-          }
-
-          handler.addPropertyDefinition(literal, handler.asBinary(propDef));
+          handler.addPropertyDefinition(literal, propDef);
         }
       } else if (propType == PropertyType::Shorthand) {
         /*
          * Support, e.g., |({x, y} = o)| as destructuring shorthand
          * for |({x: x, y: y} = o)|, and |var o = {x, y}| as
          * initializer shorthand for |var o = {x: x, y: y}|.
          */
         Rooted<PropertyName*> name(context, identifierReference(yieldHandling));
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -1343,17 +1343,18 @@ class MOZ_STACK_CLASS GeneralParser : pu
   };
   Node propertyName(YieldHandling yieldHandling,
                     PropertyNameContext propertyNameContext,
                     const mozilla::Maybe<DeclarationKind>& maybeDecl,
                     ListNodeType propList, PropertyType* propType,
                     MutableHandleAtom propAtom);
   UnaryNodeType computedPropertyName(
       YieldHandling yieldHandling,
-      const mozilla::Maybe<DeclarationKind>& maybeDecl, ListNodeType literal);
+      const mozilla::Maybe<DeclarationKind>& maybeDecl,
+      PropertyNameContext propertyNameContext, ListNodeType literal);
   ListNodeType arrayInitializer(YieldHandling yieldHandling,
                                 PossibleError* possibleError);
   inline RegExpLiteralType newRegExp();
 
   ListNodeType objectLiteral(YieldHandling yieldHandling,
                              PossibleError* possibleError);
 
   BinaryNodeType bindingInitializer(Node lhs, DeclarationKind kind,