Bug 1528837 - Part 14: Add ParserSharedBase class. r=Yoric
authorTooru Fujisawa <arai_a@mac.com>
Sun, 24 Feb 2019 09:42:51 +0000
changeset 518661 151271d3dfc2
parent 518660 f55920d58943
child 518662 58e77ffe2a65
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersYoric
bugs1528837
milestone67.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 1528837 - Part 14: Add ParserSharedBase class. r=Yoric Differential Revision: https://phabricator.services.mozilla.com/D20226
js/src/frontend/BinASTParserBase.cpp
js/src/frontend/BinASTParserBase.h
js/src/frontend/BinASTParserPerTokenizer.h
js/src/frontend/EitherParser.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
--- a/js/src/frontend/BinASTParserBase.cpp
+++ b/js/src/frontend/BinASTParserBase.cpp
@@ -6,53 +6,21 @@
 
 #include "frontend/BinASTParserBase.h"
 
 #include "vm/JSContext-inl.h"
 
 namespace js {
 namespace frontend {
 
-using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
-
 BinASTParserBase::BinASTParserBase(JSContext* cx, LifoAlloc& alloc,
                                    UsedNameTracker& usedNames,
                                    HandleScriptSourceObject sourceObject,
                                    Handle<LazyScript*> lazyScript)
-    : AutoGCRooter(cx, AutoGCRooter::Tag::BinParser),
-      cx_(cx),
-      alloc_(alloc),
-      traceListHead_(nullptr),
-      usedNames_(usedNames),
+    : ParserSharedBase(cx, alloc, usedNames, sourceObject),
       nodeAlloc_(cx, alloc),
-      keepAtoms_(cx),
-      sourceObject_(cx, sourceObject),
       lazyScript_(cx, lazyScript),
-      pc_(nullptr),
       handler_(cx, alloc, nullptr, SourceKind::Binary) {
   MOZ_ASSERT_IF(lazyScript, lazyScript->isBinAST());
-  cx->frontendCollectionPool().addActiveCompilation();
-  tempPoolMark_ = alloc.mark();
-}
-
-BinASTParserBase::~BinASTParserBase() {
-  alloc_.release(tempPoolMark_);
-
-  /*
-   * The parser can allocate enormous amounts of memory for large functions.
-   * Eagerly free the memory now (which otherwise won't be freed until the
-   * next GC) to avoid unnecessary OOMs.
-   */
-  alloc_.freeAllIfHugeAndUnused();
-
-  cx_->frontendCollectionPool().removeActiveCompilation();
-}
-
-bool BinASTParserBase::hasUsedName(HandlePropertyName name) {
-  if (UsedNamePtr p = usedNames_.lookup(name)) {
-    return p->value().isUsedInScript(pc_->scriptId());
-  }
-
-  return false;
 }
 
 }  // namespace frontend
 }  // namespace js
--- a/js/src/frontend/BinASTParserBase.h
+++ b/js/src/frontend/BinASTParserBase.h
@@ -8,78 +8,57 @@
 #define frontend_BinASTParserBase_h
 
 #include <stddef.h>
 
 #include "ds/LifoAlloc.h"
 #include "frontend/FullParseHandler.h"
 #include "frontend/ParseContext.h"
 #include "frontend/ParseNode.h"
+#include "frontend/Parser.h"
 #include "frontend/SharedContext.h"
 #include "js/RootingAPI.h"
 #include "js/TracingAPI.h"
 #include "js/Utility.h"
 #include "vm/JSContext.h"
 #include "vm/JSScript.h"
 
 namespace js {
 namespace frontend {
 
-class BinASTParserBase : private JS::AutoGCRooter {
+class BinASTParserBase : public ParserSharedBase {
  public:
   BinASTParserBase(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames,
                    HandleScriptSourceObject sourceObject,
                    Handle<LazyScript*> lazyScript);
-  ~BinASTParserBase();
+  ~BinASTParserBase() = default;
 
  public:
-  // Names
-
-  bool hasUsedName(HandlePropertyName name);
-
   // --- GC.
 
   virtual void doTrace(JSTracer* trc) {}
 
   void trace(JSTracer* trc) {
     TraceListNode::TraceList(trc, traceListHead_);
     doTrace(trc);
   }
 
  public:
   ParseNode* allocParseNode(size_t size) {
     return static_cast<ParseNode*>(nodeAlloc_.allocNode(size));
   }
 
   JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline)
 
-  // Needs access to AutoGCRooter.
-  friend void TraceBinParser(JSTracer* trc, JS::AutoGCRooter* parser);
-
- protected:
-  JSContext* cx_;
-
-  // ---- Memory-related stuff
- protected:
-  LifoAlloc& alloc_;
-  TraceListNode* traceListHead_;
-  UsedNameTracker& usedNames_;
-
  private:
-  LifoAlloc::Mark tempPoolMark_;
   ParseNodeAllocator nodeAlloc_;
 
   // ---- Parsing-related stuff
  protected:
-  // Root atoms and objects allocated for the parse tree.
-  AutoKeepAtoms keepAtoms_;
-
-  RootedScriptSourceObject sourceObject_;
   Rooted<LazyScript*> lazyScript_;
-  ParseContext* pc_;
   FullParseHandler handler_;
 
   friend class BinParseContext;
 };
 
 }  // namespace frontend
 }  // namespace js
 
--- a/js/src/frontend/BinASTParserPerTokenizer.h
+++ b/js/src/frontend/BinASTParserPerTokenizer.h
@@ -319,14 +319,16 @@ class BinParseContext : public ParseCont
  public:
   template <typename Tok>
   BinParseContext(JSContext* cx, BinASTParserPerTokenizer<Tok>* parser,
                   SharedContext* sc, Directives* newDirectives)
       : ParseContext(cx, parser->pc_, sc, *parser, parser->usedNames_,
                      newDirectives, /* isFull = */ true) {}
 };
 
+void TraceBinParser(JSTracer* trc, JS::AutoGCRooter* parser);
+
 extern template class BinASTParserPerTokenizer<BinTokenReaderMultipart>;
 
 }  // namespace frontend
 }  // namespace js
 
 #endif  // frontend_BinASTParserPerTokenizer_h
--- a/js/src/frontend/EitherParser.h
+++ b/js/src/frontend/EitherParser.h
@@ -88,20 +88,20 @@ struct TokenStreamComputeLineAndColumn {
 
 struct ParseHandlerMatcher {
   template <class Parser>
   frontend::FullParseHandler& match(Parser* parser) {
     return parser->handler_;
   }
 };
 
-struct ParserBaseMatcher {
+struct ParserSharedBaseMatcher {
   template <class Parser>
-  frontend::ParserBase& match(Parser* parser) {
-    return *static_cast<frontend::ParserBase*>(parser);
+  frontend::ParserSharedBase& match(Parser* parser) {
+    return *static_cast<frontend::ParserSharedBase*>(parser);
   }
 };
 
 struct ErrorReporterMatcher {
   template <class Parser>
   frontend::ErrorReporter& match(Parser* parser) {
     return parser->tokenStream;
   }
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -130,65 +130,71 @@ bool GeneralParser<ParseHandler, Unit>::
   }
   if (!condition(actual)) {
     errorReport(actual);
     return false;
   }
   return true;
 }
 
-ParserBase::ParserBase(JSContext* cx, LifoAlloc& alloc,
-                       const ReadOnlyCompileOptions& options,
-                       bool foldConstants, UsedNameTracker& usedNames,
-                       ScriptSourceObject* sourceObject, ParseGoal parseGoal)
-    : AutoGCRooter(cx, AutoGCRooter::Tag::Parser),
+ParserSharedBase::ParserSharedBase(JSContext* cx, LifoAlloc& alloc,
+                                   UsedNameTracker& usedNames,
+                                   ScriptSourceObject* sourceObject)
+    : JS::AutoGCRooter(cx, AutoGCRooter::Tag::Parser),
       cx_(cx),
       alloc_(alloc),
-      anyChars(cx, options, thisForCtor()),
       traceListHead_(nullptr),
       pc_(nullptr),
       usedNames_(usedNames),
-      ss(nullptr),
       sourceObject_(cx, sourceObject),
-      keepAtoms_(cx),
-      foldConstants_(foldConstants),
-#ifdef DEBUG
-      checkOptionsCalled_(false),
-#endif
-      isUnexpectedEOF_(false),
-      awaitHandling_(AwaitIsName),
-      inParametersOfAsyncFunction_(false),
-      parseGoal_(uint8_t(parseGoal)) {
+      keepAtoms_(cx) {
   cx->frontendCollectionPool().addActiveCompilation();
   tempPoolMark_ = alloc_.mark();
 }
 
-bool ParserBase::checkOptions() {
-#ifdef DEBUG
-  checkOptionsCalled_ = true;
-#endif
-
-  return anyChars.checkOptions();
-}
-
-ParserBase::~ParserBase() {
-  MOZ_ASSERT(checkOptionsCalled_);
-
+ParserSharedBase::~ParserSharedBase() {
   alloc_.release(tempPoolMark_);
 
   /*
    * The parser can allocate enormous amounts of memory for large functions.
    * Eagerly free the memory now (which otherwise won't be freed until the
    * next GC) to avoid unnecessary OOMs.
    */
   alloc_.freeAllIfHugeAndUnused();
 
   cx_->frontendCollectionPool().removeActiveCompilation();
 }
 
+ParserBase::ParserBase(JSContext* cx, LifoAlloc& alloc,
+                       const ReadOnlyCompileOptions& options,
+                       bool foldConstants, UsedNameTracker& usedNames,
+                       ScriptSourceObject* sourceObject, ParseGoal parseGoal)
+    : ParserSharedBase(cx, alloc, usedNames, sourceObject),
+      anyChars(cx, options, thisForCtor()),
+      ss(nullptr),
+      foldConstants_(foldConstants),
+#ifdef DEBUG
+      checkOptionsCalled_(false),
+#endif
+      isUnexpectedEOF_(false),
+      awaitHandling_(AwaitIsName),
+      inParametersOfAsyncFunction_(false),
+      parseGoal_(uint8_t(parseGoal)) {
+}
+
+bool ParserBase::checkOptions() {
+#ifdef DEBUG
+  checkOptionsCalled_ = true;
+#endif
+
+  return anyChars.checkOptions();
+}
+
+ParserBase::~ParserBase() { MOZ_ASSERT(checkOptionsCalled_); }
+
 template <class ParseHandler>
 PerHandlerParser<ParseHandler>::PerHandlerParser(
     JSContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
     bool foldConstants, UsedNameTracker& usedNames,
     LazyScript* lazyOuterFunction, ScriptSourceObject* sourceObject,
     ParseGoal parseGoal, void* internalSyntaxParser)
     : ParserBase(cx, alloc, options, foldConstants, usedNames, sourceObject,
                  parseGoal),
@@ -244,17 +250,17 @@ void Parser<FullParseHandler, Unit>::set
 
 template <class ParseHandler, typename Unit>
 inline void GeneralParser<ParseHandler, Unit>::setInParametersOfAsyncFunction(
     bool inParameters) {
   asFinalParser()->setInParametersOfAsyncFunction(inParameters);
 }
 
 template <typename BoxT, typename ArgT>
-BoxT* ParserBase::newTraceListNode(ArgT* arg) {
+BoxT* ParserSharedBase::newTraceListNode(ArgT* arg) {
   MOZ_ASSERT(arg);
 
   /*
    * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
    * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
    * arenas containing the entries must be alive until we are done with
    * scanning, parsing and code generation for the whole script or top-level
    * function.
@@ -266,21 +272,21 @@ BoxT* ParserBase::newTraceListNode(ArgT*
     return nullptr;
   }
 
   traceListHead_ = box;
 
   return box;
 }
 
-ObjectBox* ParserBase::newObjectBox(JSObject* obj) {
+ObjectBox* ParserSharedBase::newObjectBox(JSObject* obj) {
   return newTraceListNode<ObjectBox, JSObject>(obj);
 }
 
-BigIntBox* ParserBase::newBigIntBox(BigInt* val) {
+BigIntBox* ParserSharedBase::newBigIntBox(BigInt* val) {
   return newTraceListNode<BigIntBox, BigInt>(val);
 }
 
 template <class ParseHandler>
 FunctionBox* PerHandlerParser<ParseHandler>::newFunctionBox(
     FunctionNodeType funNode, JSFunction* fun, uint32_t toStringStart,
     Directives inheritedDirectives, GeneratorKind generatorKind,
     FunctionAsyncKind asyncKind) {
@@ -795,17 +801,17 @@ bool ParserBase::noteUsedNameInternal(Ha
   ParseContext::Scope* scope = pc_->innermostScope();
   if (pc_->sc()->isGlobalContext() && scope == &pc_->varScope()) {
     return true;
   }
 
   return usedNames_.noteUse(cx_, name, pc_->scriptId(), scope->id());
 }
 
-bool ParserBase::hasUsedName(HandlePropertyName name) {
+bool ParserSharedBase::hasUsedName(HandlePropertyName name) {
   if (UsedNamePtr p = usedNames_.lookup(name)) {
     return p->value().isUsedInScript(pc_->scriptId());
   }
   return false;
 }
 
 template <class ParseHandler>
 bool PerHandlerParser<ParseHandler>::
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -21,36 +21,41 @@
  * Like token streams (see the comment near the top of TokenStream.h), parser
  * classes are heavily templatized -- along the token stream's character-type
  * axis, and also along a full-parse/syntax-parse axis.  Certain limitations of
  * C++ (primarily the inability to partially specialize function templates),
  * plus the desire to minimize compiled code size in duplicate function
  * template instantiations wherever possible, mean that Parser exhibits much of
  * the same unholy template/inheritance complexity as token streams.
  *
- * == ParserBase → JS::AutoGCRooter, ErrorReportMixin ==
+ * == ParserSharedBase → JS::AutoGCRooter ==
+ *
+ * ParserSharedBase is the base class for both regular JS and BinAST parser.
+ * This class contains common fields and methods between both parsers.
  *
- * ParserBase is the base parser class, shared by all parsers of all character
- * types and parse-handling behavior.  It stores everything character- and
- * handler-agnostic.
+ * Of particular note: making ParserSharedBase inherit JS::AutoGCRooter (rather
+ * than placing it under one of the more-derived parser classes) means that all
+ * parsers can be traced using the same AutoGCRooter mechanism: it's not
+ * necessary to have separate tracing functionality for syntax/full parsers or
+ * parsers of different character types.
+ *
+ * == ParserBase → ParserSharedBase, ErrorReportMixin ==
+ *
+ * ParserBase is the base class for regular JS parser, shared by all regular JS
+ * parsers of all character types and parse-handling behavior.  It stores
+ * everything character- and handler-agnostic.
  *
  * ParserBase's most important field is the parser's token stream's
  * |TokenStreamAnyChars| component, for all tokenizing aspects that are
  * character-type-agnostic.  The character-type-sensitive components residing
  * in |TokenStreamSpecific| (see the comment near the top of TokenStream.h)
  * live elsewhere in this hierarchy.  These separate locations are the reason
  * for the |AnyCharsAccess| template parameter to |TokenStreamChars| and
  * |TokenStreamSpecific|.
  *
- * Of particular note: making ParserBase inherit JS::AutoGCRooter (rather than
- * placing it under one of the more-derived parser classes) means that all
- * parsers can be traced using the same AutoGCRooter mechanism: it's not
- * necessary to have separate tracing functionality for syntax/full parsers or
- * parsers of different character types.
- *
  * == PerHandlerParser<ParseHandler> → ParserBase ==
  *
  * Certain parsing behavior varies between full parsing and syntax-only parsing
  * but does not vary across source-text character types.  For example, the work
  * to "create an arguments object for a function" obviously varies between
  * syntax and full parsing but (because no source characters are examined) does
  * not vary by source text character type.  Such functionality is implemented
  * through functions in PerHandlerParser.
@@ -186,18 +191,16 @@
 #include "vm/ErrorReporting.h"
 
 namespace js {
 
 class ModuleObject;
 
 namespace frontend {
 
-class ParserBase;
-
 template <class ParseHandler, typename Unit>
 class GeneralParser;
 
 class SourceParseContext : public ParseContext {
  public:
   template <typename ParseHandler, typename Unit>
   SourceParseContext(GeneralParser<ParseHandler, Unit>* prs, SharedContext* sc,
                      Directives* newDirectives)
@@ -230,51 +233,78 @@ enum AwaitHandling : uint8_t {
 };
 
 template <class ParseHandler, typename Unit>
 class AutoAwaitIsKeyword;
 
 template <class ParseHandler, typename Unit>
 class AutoInParametersOfAsyncFunction;
 
-class MOZ_STACK_CLASS ParserBase : private JS::AutoGCRooter,
-                                   public ErrorReportMixin {
-  using Base = ErrorReportMixin;
-
- private:
-  ParserBase* thisForCtor() { return this; }
-
-  // This is needed to cast a parser to JS::AutoGCRooter.
-  friend void js::frontend::TraceParser(JSTracer* trc,
-                                        JS::AutoGCRooter* parser);
+class MOZ_STACK_CLASS ParserSharedBase : private JS::AutoGCRooter {
+ public:
+  ParserSharedBase(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames,
+                   ScriptSourceObject* sourceObject);
+  ~ParserSharedBase();
 
  public:
   JSContext* const cx_;
 
   LifoAlloc& alloc_;
 
-  TokenStreamAnyChars anyChars;
   LifoAlloc::Mark tempPoolMark_;
 
-  /* list of parsed objects and BigInts for GC tracing */
+  // list of parsed objects and BigInts for GC tracing
   TraceListNode* traceListHead_;
 
-  /* innermost parse context (stack-allocated) */
+  // innermost parse context (stack-allocated)
   ParseContext* pc_;
 
   // For tracking used names in this parsing session.
   UsedNameTracker& usedNames_;
 
-  ScriptSource* ss;
-
   RootedScriptSourceObject sourceObject_;
 
-  /* Root atoms and objects allocated for the parsed tree. */
+  // Root atoms and objects allocated for the parsed tree.
   AutoKeepAtoms keepAtoms_;
 
+ private:
+  // This is needed to cast a parser to JS::AutoGCRooter.
+  friend void js::frontend::TraceParser(JSTracer* trc,
+                                        JS::AutoGCRooter* parser);
+  friend void js::frontend::TraceBinParser(JSTracer* trc,
+                                           JS::AutoGCRooter* parser);
+
+ protected:
+  bool hasUsedName(HandlePropertyName name);
+
+ private:
+  // Create a new traceable node and store it into the trace list.
+  template <typename BoxT, typename ArgT>
+  BoxT* newTraceListNode(ArgT* arg);
+
+ public:
+  // Create a new JSObject and store it into the trace list.
+  ObjectBox* newObjectBox(JSObject* obj);
+
+  // Create a new BigInt and store it into the trace list.
+  BigIntBox* newBigIntBox(BigInt* val);
+};
+
+class MOZ_STACK_CLASS ParserBase : public ParserSharedBase,
+                                   public ErrorReportMixin {
+  using Base = ErrorReportMixin;
+
+ private:
+  ParserBase* thisForCtor() { return this; }
+
+ public:
+  TokenStreamAnyChars anyChars;
+
+  ScriptSource* ss;
+
   // Perform constant-folding; must be true when interfacing with the emitter.
   const bool foldConstants_ : 1;
 
  protected:
 #if DEBUG
   /* Our fallible 'checkOptions' member function has been called. */
   bool checkOptionsCalled_ : 1;
 #endif
@@ -389,24 +419,17 @@ class MOZ_STACK_CLASS ParserBase : priva
     m.traceListHead = traceListHead_;
     return m;
   }
   void release(Mark m) {
     alloc_.release(m.mark);
     traceListHead_ = m.traceListHead;
   }
 
- private:
-  template <typename BoxT, typename ArgT>
-  BoxT* newTraceListNode(ArgT* arg);
-
  public:
-  ObjectBox* newObjectBox(JSObject* obj);
-  BigIntBox* newBigIntBox(BigInt* val);
-
   mozilla::Maybe<GlobalScope::Data*> newGlobalScopeData(
       ParseContext::Scope& scope);
   mozilla::Maybe<ModuleScope::Data*> newModuleScopeData(
       ParseContext::Scope& scope);
   mozilla::Maybe<EvalScope::Data*> newEvalScopeData(ParseContext::Scope& scope);
   mozilla::Maybe<FunctionScope::Data*> newFunctionScopeData(
       ParseContext::Scope& scope, bool hasParameterExprs);
   mozilla::Maybe<VarScope::Data*> newVarScopeData(ParseContext::Scope& scope);
@@ -418,17 +441,16 @@ class MOZ_STACK_CLASS ParserBase : priva
   enum ForInitLocation { InForInit, NotInForInit };
 
   // While on a |let| Name token, examine |next| (which must already be
   // gotten).  Indicate whether |next|, the next token already gotten with
   // modifier TokenStream::None, continues a LexicalDeclaration.
   bool nextTokenContinuesLetDeclaration(TokenKind next);
 
   bool noteUsedNameInternal(HandlePropertyName name);
-  bool hasUsedName(HandlePropertyName name);
   bool hasUsedFunctionSpecialName(HandlePropertyName name);
 
   bool checkAndMarkSuperScope();
 
   bool declareDotGeneratorName();
 
   bool leaveInnerFunction(ParseContext* outerpc);