Bug 1424946 - Move various abstract syntax-parsing functions into PerHandlerParser, out of their current location in Parser specializations. r=arai
authorJeff Walden <jwalden@mit.edu>
Tue, 12 Dec 2017 15:20:59 -0600
changeset 448156 cfe57fd2ed05f83bd5959bc7e9359bf98d3e13e7
parent 448155 f2878c19d261ebaf9f8d6a1446132077a4134663
child 448157 4daa95c889080272786d3874cf9c1a02e34688bc
push id8527
push userCallek@gmail.com
push dateThu, 11 Jan 2018 21:05:50 +0000
treeherdermozilla-beta@95342d212a7a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarai
bugs1424946
milestone59.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 1424946 - Move various abstract syntax-parsing functions into PerHandlerParser, out of their current location in Parser specializations. r=arai
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -604,23 +604,16 @@ inline const typename GeneralParser<Pars
 GeneralParser<ParseHandler, CharT>::asFinalParser() const
 {
     static_assert(mozilla::IsBaseOf<GeneralParser<ParseHandler, CharT>, FinalParser>::value,
                   "inheritance relationship required by the static_cast<> below");
 
     return static_cast<const FinalParser*>(this);
 }
 
-template<class ParseHandler, typename CharT>
-inline bool
-GeneralParser<ParseHandler, CharT>::abortIfSyntaxParser()
-{
-    return asFinalParser()->abortIfSyntaxParser();
-}
-
 template <class ParseHandler, typename CharT>
 void
 GeneralParser<ParseHandler, CharT>::error(unsigned errorNumber, ...)
 {
     va_list args;
     va_start(args, errorNumber);
 
     ErrorMetadata metadata;
@@ -867,34 +860,41 @@ template <class ParseHandler, typename C
 GeneralParser<ParseHandler, CharT>::GeneralParser(JSContext* cx, LifoAlloc& alloc,
                                                   const ReadOnlyCompileOptions& options,
                                                   const CharT* chars, size_t length,
                                                   bool foldConstants,
                                                   UsedNameTracker& usedNames,
                                                   SyntaxParser* syntaxParser,
                                                   LazyScript* lazyOuterFunction)
   : Base(cx, alloc, options, chars, length, foldConstants, usedNames, lazyOuterFunction),
-    syntaxParser_(syntaxParser),
     tokenStream(cx, options, chars, length)
-{}
+{
+    // The Mozilla specific JSOPTION_EXTRA_WARNINGS option adds extra warnings
+    // which are not generated if functions are parsed lazily. Note that the
+    // standard "use strict" does not inhibit lazy parsing.
+    if (options.extraWarningsOption)
+        disableSyntaxParser();
+    else
+        setSyntaxParser(syntaxParser);
+}
 
 template <typename CharT>
 void
 Parser<SyntaxParseHandler, CharT>::setAwaitHandling(AwaitHandling awaitHandling)
 {
     this->awaitHandling_ = awaitHandling;
 }
 
 template <typename CharT>
 void
 Parser<FullParseHandler, CharT>::setAwaitHandling(AwaitHandling awaitHandling)
 {
     this->awaitHandling_ = awaitHandling;
-    if (syntaxParser_)
-        syntaxParser_->setAwaitHandling(awaitHandling);
+    if (SyntaxParser* syntaxParser = getSyntaxParser())
+        syntaxParser->setAwaitHandling(awaitHandling);
 }
 
 template <class ParseHandler, typename CharT>
 inline void
 GeneralParser<ParseHandler, CharT>::setAwaitHandling(AwaitHandling awaitHandling)
 {
     asFinalParser()->setAwaitHandling(awaitHandling);
 }
@@ -3431,56 +3431,57 @@ Parser<FullParseHandler, CharT>::trySynt
         // pays off for lots of code.
         if (funcNode->isLikelyIIFE() &&
             generatorKind == GeneratorKind::NotGenerator &&
             asyncKind == FunctionAsyncKind::SyncFunction)
         {
             break;
         }
 
-        if (!syntaxParser_)
+        SyntaxParser* syntaxParser = getSyntaxParser();
+        if (!syntaxParser)
             break;
 
         UsedNameTracker::RewindToken token = usedNames.getRewindToken();
 
         // Move the syntax parser to the current position in the stream.
         typename TokenStream::Position position(keepAtoms);
         tokenStream.tell(&position);
-        if (!syntaxParser_->tokenStream.seek(position, anyChars))
+        if (!syntaxParser->tokenStream.seek(position, anyChars))
             return false;
 
         // Make a FunctionBox before we enter the syntax parser, because |pn|
         // still expects a FunctionBox to be attached to it during BCE, and
         // the syntax parser cannot attach one to it.
         FunctionBox* funbox = newFunctionBox(funcNode, fun, toStringStart, inheritedDirectives,
                                              generatorKind, asyncKind);
         if (!funbox)
             return false;
         funbox->initWithEnclosingParseContext(pc, kind);
 
-        if (!syntaxParser_->innerFunctionForFunctionBox(SyntaxParseHandler::NodeGeneric,
-                                                        pc, funbox, inHandling, yieldHandling,
-                                                        kind, newDirectives))
+        if (!syntaxParser->innerFunctionForFunctionBox(SyntaxParseHandler::NodeGeneric,
+                                                       pc, funbox, inHandling, yieldHandling,
+                                                       kind, newDirectives))
         {
-            if (syntaxParser_->hadAbortedSyntaxParse()) {
+            if (syntaxParser->hadAbortedSyntaxParse()) {
                 // Try again with a full parse. UsedNameTracker needs to be
                 // rewound to just before we tried the syntax parse for
                 // correctness.
-                syntaxParser_->clearAbortedSyntaxParse();
+                syntaxParser->clearAbortedSyntaxParse();
                 usedNames.rewind(token);
-                MOZ_ASSERT_IF(!syntaxParser_->context->helperThread(),
-                              !syntaxParser_->context->isExceptionPending());
+                MOZ_ASSERT_IF(!syntaxParser->context->helperThread(),
+                              !syntaxParser->context->isExceptionPending());
                 break;
             }
             return false;
         }
 
         // Advance this parser over tokens processed by the syntax parser.
-        syntaxParser_->tokenStream.tell(&position);
-        if (!tokenStream.seek(position, syntaxParser_->anyChars))
+        syntaxParser->tokenStream.tell(&position);
+        if (!tokenStream.seek(position, syntaxParser->anyChars))
             return false;
 
         // Update the end position of the parse node.
         funcNode->pn_pos.end = anyChars.currentToken().pos.end;
 
         // Append possible Annex B function box only upon successfully parsing.
         if (tryAnnexB) {
             if (!pc->innermostScope()->addPossibleAnnexBFunctionBox(pc, funbox))
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -281,23 +281,43 @@ enum FunctionCallBehavior {
 template <class ParseHandler>
 class PerHandlerParser
   : public ParserBase
 {
   private:
     using Node = typename ParseHandler::Node;
 
   protected:
+    /* State specific to the kind of parse being performed. */
+    ParseHandler handler;
+
+    // When ParseHandler is FullParseHandler:
+    //
+    //   If non-null, this field holds the syntax parser used to attempt lazy
+    //   parsing of inner functions. If null, then lazy parsing is disabled.
+    //
+    // When ParseHandler is SyntaxParseHandler:
+    //
+    //   If non-null, this field must be a sentinel value signaling that the
+    //   syntax parse was aborted. If null, then lazy parsing was aborted due
+    //   to encountering unsupported language constructs.
+    //
+    // |internalSyntaxParser_| is really a |Parser<SyntaxParseHandler, CharT>*|
+    // where |CharT| varies per |Parser<ParseHandler, CharT>|.  But this
+    // template class doesn't have access to |CharT|, so we store a |void*|
+    // here, then intermediate all access to this field through accessors in
+    // |GeneralParser<ParseHandler, CharT>| that impose the real type on this
+    // field.
+    void* internalSyntaxParser_;
+
+  protected:
     PerHandlerParser(JSContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
                      const char16_t* chars, size_t length, bool foldConstants,
                      UsedNameTracker& usedNames, LazyScript* lazyOuterFunction);
 
-    /* State specific to the kind of parse being performed. */
-    ParseHandler handler;
-
     static Node null() { return ParseHandler::null(); }
 
     const char* nameIsArgumentsOrEval(Node node);
 
     bool noteDestructuredPositionalFormalParameter(Node fn, Node destruct);
 
     bool noteUsedName(HandlePropertyName name) {
         // If the we are delazifying, the LazyScript already has all the
@@ -319,25 +339,115 @@ class PerHandlerParser
 
     inline Node newName(PropertyName* name);
     inline Node newName(PropertyName* name, TokenPos pos);
 
     Node newInternalDotName(HandlePropertyName name);
     Node newThisName();
     Node newDotGeneratorName();
 
+    // If ParseHandler is SyntaxParseHandler:
+    //   Do nothing.
+    // If ParseHandler is FullParseHandler:
+    //   Disable syntax parsing of all future inner functions during this
+    //   full-parse.
+    inline void disableSyntaxParser();
+
+    // If ParseHandler is SyntaxParseHandler:
+    //   Flag the current syntax parse as aborted due to unsupported language
+    //   constructs and return false.  Aborting the current syntax parse does
+    //   not disable attempts to syntax-parse future inner functions.
+    // If ParseHandler is FullParseHandler:
+    //    Disable syntax parsing of all future inner functions and return true.
+    inline bool abortIfSyntaxParser();
+
+    // If ParseHandler is SyntaxParseHandler:
+    //   Return whether the last syntax parse was aborted due to unsupported
+    //   language constructs.
+    // If ParseHandler is FullParseHandler:
+    //   Return false.
+    inline bool hadAbortedSyntaxParse();
+
+    // If ParseHandler is SyntaxParseHandler:
+    //   Clear whether the last syntax parse was aborted.
+    // If ParseHandler is FullParseHandler:
+    //   Do nothing.
+    inline void clearAbortedSyntaxParse();
+
   public:
     bool isValidSimpleAssignmentTarget(Node node,
                                        FunctionCallBehavior behavior = ForbidAssignmentToFunctionCalls);
 
     FunctionBox* newFunctionBox(Node fn, JSFunction* fun, uint32_t toStringStart,
                                 Directives directives, GeneratorKind generatorKind,
                                 FunctionAsyncKind asyncKind);
 };
 
+#define ABORTED_SYNTAX_PARSE_SENTINEL reinterpret_cast<void*>(0x1)
+
+template<>
+inline void
+PerHandlerParser<SyntaxParseHandler>::disableSyntaxParser()
+{
+}
+
+template<>
+inline bool
+PerHandlerParser<SyntaxParseHandler>::abortIfSyntaxParser()
+{
+    internalSyntaxParser_ = ABORTED_SYNTAX_PARSE_SENTINEL;
+    return false;
+}
+
+template<>
+inline bool
+PerHandlerParser<SyntaxParseHandler>::hadAbortedSyntaxParse()
+{
+    return internalSyntaxParser_ == ABORTED_SYNTAX_PARSE_SENTINEL;
+}
+
+template<>
+inline void
+PerHandlerParser<SyntaxParseHandler>::clearAbortedSyntaxParse()
+{
+    internalSyntaxParser_ = nullptr;
+}
+
+#undef ABORTED_SYNTAX_PARSE_SENTINEL
+
+// Disable syntax parsing of all future inner functions during this
+// full-parse.
+template<>
+inline void
+PerHandlerParser<FullParseHandler>::disableSyntaxParser()
+{
+    internalSyntaxParser_ = nullptr;
+}
+
+template<>
+inline bool
+PerHandlerParser<FullParseHandler>::abortIfSyntaxParser()
+{
+    disableSyntaxParser();
+    return true;
+}
+
+template<>
+inline bool
+PerHandlerParser<FullParseHandler>::hadAbortedSyntaxParse()
+{
+    return false;
+}
+
+template<>
+inline void
+PerHandlerParser<FullParseHandler>::clearAbortedSyntaxParse()
+{
+}
+
 enum class ExpressionClosure { Allowed, Forbidden };
 
 template<class Parser>
 class ParserAnyCharsAccess
 {
   public:
     using TokenStreamSpecific = typename Parser::TokenStream;
     using TokenStreamChars = typename TokenStreamSpecific::CharsBase;
@@ -362,16 +472,17 @@ template <class ParseHandler, typename C
 class GeneralParser
   : public PerHandlerParser<ParseHandler>
 {
   private:
     using Base = PerHandlerParser<ParseHandler>;
     using FinalParser = Parser<ParseHandler, CharT>;
     using Node = typename ParseHandler::Node;
     using typename Base::InvokedPrediction;
+    using SyntaxParser = Parser<SyntaxParseHandler, CharT>;
 
   protected:
     using Modifier = TokenStreamShared::Modifier;
 
     using Base::PredictUninvoked;
     using Base::PredictInvoked;
 
     using Base::alloc;
@@ -394,16 +505,21 @@ class GeneralParser
     using Base::null;
     using Base::options;
     using Base::pos;
     using Base::propagateFreeNamesAndMarkClosedOverBindings;
     using Base::setLocalStrictMode;
     using Base::traceListHead;
     using Base::yieldExpressionsSupported;
 
+    using Base::disableSyntaxParser;
+    using Base::abortIfSyntaxParser;
+    using Base::hadAbortedSyntaxParse;
+    using Base::clearAbortedSyntaxParse;
+
   public:
     using Base::anyChars;
     using Base::context;
     using Base::handler;
     using Base::isValidSimpleAssignmentTarget;
     using Base::pc;
     using Base::usedNames;
 
@@ -543,32 +659,29 @@ class GeneralParser
 
         // Pass pending errors between possible error instances. This is useful
         // for extending the lifetime of a pending error beyond the scope of
         // the PossibleError where it was initially set (keeping in mind that
         // PossibleError is a MOZ_STACK_CLASS).
         void transferErrorsTo(PossibleError* other);
     };
 
+  private:
+    // DO NOT USE THE syntaxParser_ FIELD DIRECTLY.  Use the accessors defined
+    // below to access this field per its actual type.
+    using Base::internalSyntaxParser_;
+
   protected:
-    // When ParseHandler is FullParseHandler:
-    //
-    //   If non-null, this field holds the syntax parser used to attempt lazy
-    //   parsing of inner functions. If null, then lazy parsing is disabled.
-    //
-    // When ParseHandler is SyntaxParseHandler:
-    //
-    //   If non-null, this field must be a sentinel value signaling that the
-    //   syntax parse was aborted. If null, then lazy parsing was aborted due
-    //   to encountering unsupported language constructs.
-    using SyntaxParser = Parser<SyntaxParseHandler, CharT>;
-    SyntaxParser* syntaxParser_;
+    SyntaxParser* getSyntaxParser() const {
+        return reinterpret_cast<SyntaxParser*>(internalSyntaxParser_);
+    }
 
-  private:
-    inline bool abortIfSyntaxParser();
+    void setSyntaxParser(SyntaxParser* syntaxParser) {
+        internalSyntaxParser_ = syntaxParser;
+    }
 
   public:
     using TokenStream = TokenStreamSpecific<CharT, ParserAnyCharsAccess<GeneralParser>>;
     TokenStream tokenStream;
 
     void prepareNodeForMutation(Node node) { handler.prepareNodeForMutation(node); }
     void freeTree(Node node) { handler.freeTree(node); }
 
@@ -999,17 +1112,19 @@ class Parser<SyntaxParseHandler, CharT> 
 
     // Inherited types, listed here to have non-dependent names.
     using typename Base::Modifier;
 
     // Inherited functions, listed here to have non-dependent names.
 
   public:
     using Base::anyChars;
+    using Base::clearAbortedSyntaxParse;
     using Base::context;
+    using Base::hadAbortedSyntaxParse;
     using Base::innerFunctionForFunctionBox;
     using Base::tokenStream;
 
   private:
     using Base::alloc;
 #if DEBUG
     using Base::checkOptionsCalled;
 #endif
@@ -1029,19 +1144,22 @@ class Parser<SyntaxParseHandler, CharT> 
     using Base::null;
     using Base::options;
     using Base::pc;
     using Base::pos;
     using Base::propagateFreeNamesAndMarkClosedOverBindings;
     using Base::ss;
     using Base::statementList;
     using Base::stringLiteral;
-    using Base::syntaxParser_;
     using Base::usedNames;
 
+  private:
+    using Base::abortIfSyntaxParser;
+    using Base::disableSyntaxParser;
+
   public:
     // Functions with multiple overloads of different visibility.  We can't
     // |using| the whole thing into existence because of the visibility
     // distinction, so we instead must manually delegate the required overload.
 
     PropertyName* bindingIdentifier(YieldHandling yieldHandling) {
         return Base::bindingIdentifier(yieldHandling);
     }
@@ -1071,43 +1189,16 @@ class Parser<SyntaxParseHandler, CharT> 
                                      FunctionAsyncKind asyncKind, bool tryAnnexB,
                                      Directives inheritedDirectives, Directives* newDirectives);
 
     bool skipLazyInnerFunction(Node funcNode, uint32_t toStringStart, FunctionSyntaxKind kind,
                                bool tryAnnexB);
 
     bool finishFunction(bool isStandaloneFunction = false);
 
-#define ABORTED_SYNTAX_PARSE_SENTINEL reinterpret_cast<SyntaxParser*>(0x1)
-
-    // Flag the current syntax parse as aborted due to unsupported language
-    // constructs and return false.  Aborting the current syntax parse does not
-    // disable attempts to syntax parse future inner functions.
-    bool abortIfSyntaxParser() {
-        syntaxParser_ = ABORTED_SYNTAX_PARSE_SENTINEL;
-        return false;
-    }
-
-    // Return whether the last syntax parse was aborted due to unsupported
-    // language constructs.
-    bool hadAbortedSyntaxParse() {
-        return syntaxParser_ == ABORTED_SYNTAX_PARSE_SENTINEL;
-    }
-
-    // Clear whether the last syntax parse was aborted.
-    void clearAbortedSyntaxParse() {
-        syntaxParser_ = nullptr;
-    }
-
-    // Disable syntax parsing of all future inner functions during this
-    // full-parse.
-    void disableSyntaxParser() {}
-
-#undef ABORTED_SYNTAX_PARSE_SENTINEL
-
     bool asmJS(Node list);
 
     // Functions present only in Parser<SyntaxParseHandler, CharT>.
 };
 
 template <typename CharT>
 class Parser<FullParseHandler, CharT> final
   : public GeneralParser<FullParseHandler, CharT>
@@ -1121,39 +1212,28 @@ class Parser<FullParseHandler, CharT> fi
     //
     //   return asFinalParser()->func(...);
     //
     // and must be able to call functions here.  Add a friendship relationship
     // so functions here can be hidden when appropriate.
     friend class GeneralParser<FullParseHandler, CharT>;
 
   public:
-    Parser(JSContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
-           const CharT* chars, size_t length, bool foldConstants, UsedNameTracker& usedNames,
-           SyntaxParser* syntaxParser, LazyScript* lazyOuterFunction)
-      : Base(cx, alloc, options, chars, length, foldConstants, usedNames, syntaxParser,
-             lazyOuterFunction)
-    {
-        // The Mozilla specific JSOPTION_EXTRA_WARNINGS option adds extra warnings
-        // which are not generated if functions are parsed lazily. Note that the
-        // standard "use strict" does not inhibit lazy parsing.
-        if (options.extraWarningsOption)
-            disableSyntaxParser();
-    }
-
     using Base::Base;
 
     // Inherited types, listed here to have non-dependent names.
     using typename Base::Modifier;
 
     // Inherited functions, listed here to have non-dependent names.
 
   public:
     using Base::anyChars;
+    using Base::clearAbortedSyntaxParse;
     using Base::functionFormalParametersAndBody;
+    using Base::hadAbortedSyntaxParse;
     using Base::handler;
     using Base::newFunctionBox;
     using Base::options;
     using Base::pc;
     using Base::pos;
     using Base::ss;
     using Base::tokenStream;
 
@@ -1179,19 +1259,23 @@ class Parser<FullParseHandler, CharT> fi
     using Base::newModuleScopeData;
     using Base::newName;
     using Base::newVarScopeData;
     using Base::noteDeclaredName;
     using Base::null;
     using Base::propagateFreeNamesAndMarkClosedOverBindings;
     using Base::statementList;
     using Base::stringLiteral;
-    using Base::syntaxParser_;
     using Base::usedNames;
 
+    using Base::abortIfSyntaxParser;
+    using Base::disableSyntaxParser;
+    using Base::getSyntaxParser;
+    using Base::setSyntaxParser;
+
   public:
     // Functions with multiple overloads of different visibility.  We can't
     // |using| the whole thing into existence because of the visibility
     // distinction, so we instead must manually delegate the required overload.
 
     PropertyName* bindingIdentifier(YieldHandling yieldHandling) {
         return Base::bindingIdentifier(yieldHandling);
     }
@@ -1243,36 +1327,16 @@ class Parser<FullParseHandler, CharT> fi
 
     // Parse a function, used for the Function, GeneratorFunction, and
     // AsyncFunction constructors.
     Node standaloneFunction(HandleFunction fun, HandleScope enclosingScope,
                             const mozilla::Maybe<uint32_t>& parameterListEnd,
                             GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
                             Directives inheritedDirectives, Directives* newDirectives);
 
-    bool abortIfSyntaxParser() {
-        disableSyntaxParser();
-        return true;
-    }
-
-    // Return whether the last syntax parse was aborted due to unsupported
-    // language constructs.
-    bool hadAbortedSyntaxParse() {
-        return false;
-    }
-
-    // Clear whether the last syntax parse was aborted.
-    void clearAbortedSyntaxParse() {}
-
-    // Disable syntax parsing of all future inner functions during this
-    // full-parse.
-    void disableSyntaxParser() {
-        syntaxParser_ = nullptr;
-    }
-
     bool checkStatementsEOF();
 
     // Parse the body of a global script.
     Node globalBody(GlobalSharedContext* globalsc);
 
     bool namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet);
 
     PropertyName* importedBinding() {