Bug 1296814 - Move the Parser::checkFunctionDefinition call, out of Parser::functionDefinition, into its few Statement-related callers. r=anba
authorJeff Walden <jwalden@mit.edu>
Sun, 13 Nov 2016 00:05:10 -0800
changeset 322555 5908c363b5eeee05431335319b972c1c8e625360
parent 322554 d2ee58a58aa76762f06903a48c505370776ca913
child 322556 2f6b90c78c4b43dfea9db1895eeb90fa6cfc3d26
push id21
push usermaklebus@msu.edu
push dateThu, 01 Dec 2016 06:22:08 +0000
reviewersanba
bugs1296814
milestone52.0a1
Bug 1296814 - Move the Parser::checkFunctionDefinition call, out of Parser::functionDefinition, into its few Statement-related callers. r=anba
js/src/frontend/FullParseHandler.h
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/SyntaxParseHandler.h
js/src/wasm/AsmJS.cpp
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -662,19 +662,28 @@ class FullParseHandler
     inline MOZ_MUST_USE bool addCatchBlock(ParseNode* catchList, ParseNode* lexicalScope,
                                            ParseNode* catchName, ParseNode* catchGuard,
                                            ParseNode* catchBody);
 
     inline MOZ_MUST_USE bool setLastFunctionFormalParameterDefault(ParseNode* funcpn,
                                                                    ParseNode* pn);
     inline void setLastFunctionFormalParameterDestructuring(ParseNode* funcpn, ParseNode* pn);
 
-    ParseNode* newFunctionDefinition() {
-        return new_<CodeNode>(PNK_FUNCTION, pos());
+    ParseNode* newFunctionStatement() {
+        return new_<CodeNode>(PNK_FUNCTION, JSOP_NOP, pos());
     }
+
+    ParseNode* newFunctionExpression() {
+        return new_<CodeNode>(PNK_FUNCTION, JSOP_LAMBDA, pos());
+    }
+
+    ParseNode* newArrowFunction() {
+        return new_<CodeNode>(PNK_FUNCTION, JSOP_LAMBDA_ARROW, pos());
+    }
+
     bool setComprehensionLambdaBody(ParseNode* pn, ParseNode* body) {
         MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST));
         ParseNode* paramsBody = newList(PNK_PARAMSBODY, body);
         if (!paramsBody)
             return false;
         setFunctionFormalParametersAndBody(pn, paramsBody);
         return true;
     }
@@ -691,17 +700,17 @@ class FullParseHandler
         pn->pn_body->append(argpn);
     }
     void setFunctionBody(ParseNode* fn, ParseNode* body) {
         MOZ_ASSERT(fn->pn_body->isKind(PNK_PARAMSBODY));
         fn->pn_body->append(body);
     }
 
     ParseNode* newModule() {
-        return new_<CodeNode>(PNK_MODULE, pos());
+        return new_<CodeNode>(PNK_MODULE, JSOP_NOP, pos());
     }
 
     ParseNode* newLexicalScope(LexicalScope::Data* bindings, ParseNode* body) {
         return new_<LexicalScopeNode>(bindings, body);
     }
 
     ParseNode* newAssignment(ParseNodeKind kind, ParseNode* lhs, ParseNode* rhs,
                              JSOp op)
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -911,20 +911,24 @@ struct ListNode : public ParseNode
 
 #ifdef DEBUG
     void dump(int indent);
 #endif
 };
 
 struct CodeNode : public ParseNode
 {
-    CodeNode(ParseNodeKind kind, const TokenPos& pos)
-      : ParseNode(kind, JSOP_NOP, PN_CODE, pos)
+    CodeNode(ParseNodeKind kind, JSOp op, const TokenPos& pos)
+      : ParseNode(kind, op, PN_CODE, pos)
     {
         MOZ_ASSERT(kind == PNK_FUNCTION || kind == PNK_MODULE);
+        MOZ_ASSERT_IF(kind == PNK_MODULE, op == JSOP_NOP);
+        MOZ_ASSERT(op == JSOP_NOP || // statement, module
+                   op == JSOP_LAMBDA_ARROW || // arrow function
+                   op == JSOP_LAMBDA); // expression, method, comprehension, accessor, &c.
         MOZ_ASSERT(!pn_body);
         MOZ_ASSERT(!pn_objbox);
     }
 
   public:
 #ifdef DEBUG
     void dump(int indent);
 #endif
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2288,17 +2288,17 @@ Parser<FullParseHandler>::standaloneFunc
                                                  Handle<PropertyNameVector> formals,
                                                  GeneratorKind generatorKind,
                                                  FunctionAsyncKind asyncKind,
                                                  Directives inheritedDirectives,
                                                  Directives* newDirectives)
 {
     MOZ_ASSERT(checkOptionsCalled);
 
-    Node fn = handler.newFunctionDefinition();
+    Node fn = handler.newFunctionStatement();
     if (!fn)
         return null();
 
     ParseNode* argsbody = handler.newList(PNK_PARAMSBODY);
     if (!argsbody)
         return null();
     fn->pn_body = argsbody;
 
@@ -2966,70 +2966,64 @@ Parser<ParseHandler>::functionArguments(
         return false;
     }
 
     return true;
 }
 
 template <typename ParseHandler>
 bool
-Parser<ParseHandler>::checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind,
+Parser<ParseHandler>::checkFunctionDefinition(HandlePropertyName funName, Node pn,
                                               GeneratorKind generatorKind, bool* tryAnnexB)
 {
-    if (kind == Statement) {
-        TokenPos pos = handler.getPosition(pn);
-        RootedPropertyName funName(context, funAtom->asPropertyName());
-
-        // In sloppy mode, Annex B.3.2 allows labelled function
-        // declarations. Otherwise it is a parse error.
-        ParseContext::Statement* declaredInStmt = pc->innermostStatement();
-        if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) {
-            MOZ_ASSERT(!pc->sc()->strict(),
-                       "labeled functions shouldn't be parsed in strict mode");
-
-            // Find the innermost non-label statement.  Report an error if it's
-            // unbraced: functions can't appear in it.  Otherwise the statement
-            // (or its absence) determines the scope the function's bound in.
-            while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label)
-                declaredInStmt = declaredInStmt->enclosing();
-
-            if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) {
-                reportWithOffset(ParseError, false, pos.begin, JSMSG_SLOPPY_FUNCTION_LABEL);
+    TokenPos pos = handler.getPosition(pn);
+
+    // In sloppy mode, Annex B.3.2 allows labelled function
+    // declarations. Otherwise it is a parse error.
+    ParseContext::Statement* declaredInStmt = pc->innermostStatement();
+    if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) {
+        MOZ_ASSERT(!pc->sc()->strict(),
+                   "labeled functions shouldn't be parsed in strict mode");
+
+        // Find the innermost non-label statement.  Report an error if it's
+        // unbraced: functions can't appear in it.  Otherwise the statement
+        // (or its absence) determines the scope the function's bound in.
+        while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label)
+            declaredInStmt = declaredInStmt->enclosing();
+
+        if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) {
+            reportWithOffset(ParseError, false, pos.begin, JSMSG_SLOPPY_FUNCTION_LABEL);
+            return false;
+        }
+    }
+
+    if (declaredInStmt) {
+        MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label);
+        MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind()));
+
+        if (!pc->sc()->strict() && generatorKind == NotGenerator) {
+            // Under sloppy mode, try Annex B.3.3 semantics. If making an
+            // additional 'var' binding of the same name does not throw an
+            // early error, do so. This 'var' binding would be assigned
+            // the function object when its declaration is reached, not at
+            // the start of the block.
+
+            if (!tryDeclareVarForAnnexBLexicalFunction(funName, tryAnnexB))
                 return false;
-            }
-        }
-
-        if (declaredInStmt) {
-            MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label);
-            MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind()));
-
-            if (!pc->sc()->strict() && generatorKind == NotGenerator) {
-                // Under sloppy mode, try Annex B.3.3 semantics. If making an
-                // additional 'var' binding of the same name does not throw an
-                // early error, do so. This 'var' binding would be assigned
-                // the function object when its declaration is reached, not at
-                // the start of the block.
-
-                if (!tryDeclareVarForAnnexBLexicalFunction(funName, tryAnnexB))
-                    return false;
-            }
-
-            if (!noteDeclaredName(funName, DeclarationKind::LexicalFunction, pos))
-                return false;
-        } else {
-            if (!noteDeclaredName(funName, DeclarationKind::BodyLevelFunction, pos))
-                return false;
-
-            // Body-level functions in modules are always closed over.
-            if (pc->atModuleLevel())
-                pc->varScope().lookupDeclaredName(funName)->value()->setClosedOver();
-        }
+        }
+
+        if (!noteDeclaredName(funName, DeclarationKind::LexicalFunction, pos))
+            return false;
     } else {
-        // A function expression does not introduce any binding.
-        handler.setOp(pn, kind == Arrow ? JSOP_LAMBDA_ARROW : JSOP_LAMBDA);
+        if (!noteDeclaredName(funName, DeclarationKind::BodyLevelFunction, pos))
+            return false;
+
+        // Body-level functions in modules are always closed over.
+        if (pc->atModuleLevel())
+            pc->varScope().lookupDeclaredName(funName)->value()->setClosedOver();
     }
 
     return true;
 }
 
 template <>
 bool
 Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKind kind,
@@ -3147,26 +3141,22 @@ Parser<ParseHandler>::templateLiteral(Yi
     return nodeList;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::functionDefinition(Node pn, InHandling inHandling,
                                          YieldHandling yieldHandling, HandleAtom funName,
                                          FunctionSyntaxKind kind,
-                                         GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
+                                         GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
+                                         bool tryAnnexB /* = false */)
 {
     MOZ_ASSERT_IF(kind == Statement, funName);
     MOZ_ASSERT_IF(asyncKind == AsyncFunction, generatorKind == StarGenerator);
 
-    // Note the declared name and check for early errors.
-    bool tryAnnexB = false;
-    if (!checkFunctionDefinition(funName, pn, kind, generatorKind, &tryAnnexB))
-        return null();
-
     // When fully parsing a LazyScript, we do not fully reparse its inner
     // functions, which are also lazy. Instead, their free variables and
     // source extents are recorded and may be skipped.
     if (handler.canSkipLazyInnerFunctions()) {
         if (!skipLazyInnerFunction(pn, kind, tryAnnexB))
             return null();
         return pn;
     }
@@ -3383,17 +3373,17 @@ Parser<ParseHandler>::appendToCallSiteOb
 template <>
 ParseNode*
 Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict,
                                                  GeneratorKind generatorKind,
                                                  FunctionAsyncKind asyncKind)
 {
     MOZ_ASSERT(checkOptionsCalled);
 
-    Node pn = handler.newFunctionDefinition();
+    Node pn = handler.newFunctionStatement();
     if (!pn)
         return null();
 
     Directives directives(strict);
     FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, asyncKind,
                                          /* tryAnnexB = */ false);
     if (!funbox)
         return null();
@@ -3585,23 +3575,28 @@ Parser<ParseHandler>::functionStmt(Yield
         name = context->names().starDefaultStar;
         tokenStream.ungetToken();
     } else {
         /* Unnamed function expressions are forbidden in statement context. */
         error(JSMSG_UNNAMED_FUNCTION_STMT);
         return null();
     }
 
-    Node pn = handler.newFunctionDefinition();
+    Node pn = handler.newFunctionStatement();
     if (!pn)
         return null();
 
+    // Note the declared name and check for early errors.
+    bool tryAnnexB = false;
+    if (!checkFunctionDefinition(name, pn, generatorKind, &tryAnnexB))
+        return null();
+
     YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind);
     return functionDefinition(pn, InAllowed, newYieldHandling, name, Statement, generatorKind,
-                              asyncKind);
+                              asyncKind, tryAnnexB);
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::functionExpr(InvokedPrediction invoked, FunctionAsyncKind asyncKind)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
 
@@ -3627,17 +3622,17 @@ Parser<ParseHandler>::functionExpr(Invok
     if (tt == TOK_NAME || tt == TOK_YIELD) {
         name = bindingIdentifier(yieldHandling);
         if (!name)
             return null();
     } else {
         tokenStream.ungetToken();
     }
 
-    Node pn = handler.newFunctionDefinition();
+    Node pn = handler.newFunctionExpression();
     if (!pn)
         return null();
 
     if (invoked)
         pn = handler.setLikelyIIFE(pn);
 
     return functionDefinition(pn, InAllowed, yieldHandling, name, Expression, generatorKind,
                               asyncKind);
@@ -6518,41 +6513,16 @@ JSOpFromPropertyType(PropertyType propTy
       case PropertyType::Constructor:
       case PropertyType::DerivedConstructor:
         return JSOP_INITPROP;
       default:
         MOZ_CRASH("unexpected property type");
     }
 }
 
-static FunctionSyntaxKind
-FunctionSyntaxKindFromPropertyType(PropertyType propType)
-{
-    switch (propType) {
-      case PropertyType::Getter:
-        return Getter;
-      case PropertyType::GetterNoExpressionClosure:
-        return GetterNoExpressionClosure;
-      case PropertyType::Setter:
-        return Setter;
-      case PropertyType::SetterNoExpressionClosure:
-        return SetterNoExpressionClosure;
-      case PropertyType::Method:
-      case PropertyType::GeneratorMethod:
-      case PropertyType::AsyncMethod:
-        return Method;
-      case PropertyType::Constructor:
-        return ClassConstructor;
-      case PropertyType::DerivedConstructor:
-        return DerivedClassConstructor;
-      default:
-        MOZ_CRASH("unexpected property type");
-    }
-}
-
 static GeneratorKind
 GeneratorKindFromPropertyType(PropertyType propType)
 {
     if (propType == PropertyType::GeneratorMethod)
         return StarGenerator;
     if (propType == PropertyType::AsyncMethod)
         return StarGenerator;
     return NotGenerator;
@@ -7721,17 +7691,17 @@ Parser<ParseHandler>::assignExpr(InHandl
                     generatorKind = StarGenerator;
                     asyncKind = AsyncFunction;
                 }
             } else {
                 tokenStream.ungetToken();
             }
         }
 
-        Node pn = handler.newFunctionDefinition();
+        Node pn = handler.newArrowFunction();
         if (!pn)
             return null();
 
         Node arrowFunc = functionDefinition(pn, inHandling, yieldHandling, nullptr,
                                             Arrow, generatorKind, asyncKind);
         if (!arrowFunc)
             return null();
 
@@ -8064,20 +8034,19 @@ Parser<ParseHandler>::unaryExpr(YieldHan
  * specifications for a while. Shortly after this syntax was implemented in SM,
  * TC39 decided to drop it.)
  */
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
 {
-    Node genfn = handler.newFunctionDefinition();
+    Node genfn = handler.newFunctionExpression();
     if (!genfn)
         return null();
-    handler.setOp(genfn, JSOP_LAMBDA);
 
     ParseContext* outerpc = pc;
 
     // If we are off the main thread, the generator meta-objects have
     // already been created by js::StartOffThreadParseScript, so cx will not
     // be necessary.
     RootedObject proto(context);
     JSContext* cx = context->maybeJSContext();
@@ -9351,22 +9320,57 @@ Parser<ParseHandler>::objectLiteral(Yiel
     handler.setEndPosition(literal, pos().end);
     return literal;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::methodDefinition(PropertyType propType, HandleAtom funName)
 {
-    FunctionSyntaxKind kind = FunctionSyntaxKindFromPropertyType(propType);
+    FunctionSyntaxKind kind;
+    switch (propType) {
+      case PropertyType::Getter:
+        kind = Getter;
+        break;
+
+      case PropertyType::GetterNoExpressionClosure:
+        kind = GetterNoExpressionClosure;
+        break;
+
+      case PropertyType::Setter:
+        kind = Setter;
+        break;
+
+      case PropertyType::SetterNoExpressionClosure:
+        kind = SetterNoExpressionClosure;
+        break;
+
+      case PropertyType::Method:
+      case PropertyType::GeneratorMethod:
+      case PropertyType::AsyncMethod:
+        kind = Method;
+        break;
+
+      case PropertyType::Constructor:
+        kind = ClassConstructor;
+        break;
+
+      case PropertyType::DerivedConstructor:
+        kind = DerivedClassConstructor;
+        break;
+
+      default:
+        MOZ_CRASH("unexpected property type");
+    }
+
     GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType);
     FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType);
     YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
 
-    Node pn = handler.newFunctionDefinition();
+    Node pn = handler.newFunctionExpression();
     if (!pn)
         return null();
 
     return functionDefinition(pn, InAllowed, yieldHandling, funName, kind, generatorKind, asyncKind);
 }
 
 template <typename ParseHandler>
 bool
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -1251,17 +1251,18 @@ class Parser final : private JS::AutoGCR
     /*
      * Additional JS parsers.
      */
     bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind,
                            Node funcpn);
 
     Node functionDefinition(Node func, InHandling inHandling, YieldHandling yieldHandling,
                             HandleAtom name, FunctionSyntaxKind kind,
-                            GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
+                            GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
+                            bool tryAnnexB = false);
 
     // Parse a function body.  Pass StatementListBody if the body is a list of
     // statements; pass ExpressionBody if the body is a single expression.
     enum FunctionBodyType { StatementListBody, ExpressionBody };
     Node functionBody(InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind,
                       FunctionBodyType type);
 
     Node unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind, JSOp op, uint32_t begin);
@@ -1337,18 +1338,18 @@ class Parser final : private JS::AutoGCR
     bool hasUsedFunctionSpecialName(HandlePropertyName name);
     bool declareFunctionArgumentsObject();
     bool declareFunctionThis();
     Node newInternalDotName(HandlePropertyName name);
     Node newThisName();
     Node newDotGeneratorName();
     bool declareDotGeneratorName();
 
-    bool checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind,
-                                 GeneratorKind generatorKind, bool* tryAnnexB);
+    bool checkFunctionDefinition(HandlePropertyName funName, Node pn, GeneratorKind generatorKind,
+                                 bool* tryAnnexB);
     bool skipLazyInnerFunction(Node pn, FunctionSyntaxKind kind, bool tryAnnexB);
     bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun,
                        InHandling inHandling, YieldHandling yieldHandling,
                        FunctionSyntaxKind kind,
                        GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
                        Directives inheritedDirectives, Directives* newDirectives);
     bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, InHandling inHandling,
                                      YieldHandling yieldHandling, FunctionSyntaxKind kind,
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -339,17 +339,21 @@ class SyntaxParseHandler
     }
 
     Node newPropertyByValue(Node pn, Node kid, uint32_t end) { return NodeElement; }
 
     MOZ_MUST_USE bool addCatchBlock(Node catchList, Node letBlock, Node catchName,
                                     Node catchGuard, Node catchBody) { return true; }
 
     MOZ_MUST_USE bool setLastFunctionFormalParameterDefault(Node funcpn, Node pn) { return true; }
-    Node newFunctionDefinition() { return NodeFunctionDefinition; }
+
+    Node newFunctionStatement() { return NodeFunctionDefinition; }
+    Node newFunctionExpression() { return NodeFunctionDefinition; }
+    Node newArrowFunction() { return NodeFunctionDefinition; }
+
     bool setComprehensionLambdaBody(Node pn, Node body) { return true; }
     void setFunctionFormalParametersAndBody(Node pn, Node kid) {}
     void setFunctionBody(Node pn, Node kid) {}
     void setFunctionBox(Node pn, FunctionBox* funbox) {}
     void addFunctionFormalParameter(Node pn, Node argpn) {}
 
     Node newForStatement(uint32_t begin, Node forHead, Node body, unsigned iflags) {
         return NodeGeneric;
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -7055,17 +7055,17 @@ ParseFunction(ModuleValidator& m, ParseN
         return false;
     if (tk != TOK_NAME && tk != TOK_YIELD)
         return false;  // The regular parser will throw a SyntaxError, no need to m.fail.
 
     RootedPropertyName name(m.cx(), m.parser().bindingIdentifier(YieldIsName));
     if (!name)
         return false;
 
-    ParseNode* fn = m.parser().handler.newFunctionDefinition();
+    ParseNode* fn = m.parser().handler.newFunctionStatement();
     if (!fn)
         return false;
 
     RootedFunction& fun = m.dummyFunction();
     fun->setAtom(name);
     fun->setArgCount(0);
 
     ParseContext* outerpc = m.parser().pc;