Bug 1498320 - Templatize everything that's source-aware in bytecode compilation. r=tcampbell
authorJeff Walden <jwalden@mit.edu>
Fri, 02 Nov 2018 20:59:21 -0700
changeset 446430 422924c19ce5c0aa87174e713e3aa43564f1a4b3
parent 446429 532b05c76fa0ba9e56c278430a6e763feefa23a4
child 446431 56eaf6c976d377cba4e44a302bdeda9e7420bd94
push id109874
push userjwalden@mit.edu
push dateWed, 14 Nov 2018 23:38:56 +0000
treeherdermozilla-inbound@5b0d24759be6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstcampbell
bugs1498320
milestone65.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 1498320 - Templatize everything that's source-aware in bytecode compilation. r=tcampbell
js/src/frontend/BytecodeCompiler.cpp
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -35,20 +35,20 @@ using namespace js::frontend;
 
 using mozilla::Maybe;
 using mozilla::Nothing;
 
 using JS::CompileOptions;
 using JS::ReadOnlyCompileOptions;
 using JS::SourceBufferHolder;
 
-class SourceAwareCompiler;
-class ScriptCompiler;
-class ModuleCompiler;
-class StandaloneFunctionCompiler;
+template<typename Unit> class SourceAwareCompiler;
+template<typename Unit> class ScriptCompiler;
+template<typename Unit> class ModuleCompiler;
+template<typename Unit> class StandaloneFunctionCompiler;
 
 // The BytecodeCompiler class contains resources common to compiling scripts and
 // function bodies.
 class MOZ_STACK_CLASS BytecodeCompiler
 {
   protected:
     AutoKeepAtoms keepAtoms;
 
@@ -62,20 +62,20 @@ class MOZ_STACK_CLASS BytecodeCompiler
 
     Directives directives;
 
     RootedScript script;
 
   protected:
     BytecodeCompiler(JSContext* cx, const ReadOnlyCompileOptions& options);
 
-    friend class SourceAwareCompiler;
-    friend class ScriptCompiler;
-    friend class ModuleCompiler;
-    friend class StandaloneFunctionCompiler;
+    template<typename Unit> friend class SourceAwareCompiler;
+    template<typename Unit> friend class ScriptCompiler;
+    template<typename Unit> friend class ModuleCompiler;
+    template<typename Unit> friend class StandaloneFunctionCompiler;
 
   public:
     ScriptSourceObject* sourceObjectPtr() const {
         return sourceObject.get();
     }
 
   protected:
     void assertSourceCreated() const {
@@ -103,25 +103,26 @@ class MOZ_STACK_CLASS BytecodeCompiler
     MOZ_MUST_USE bool assignSource(SourceBufferHolder& sourceBuffer);
 
     bool canLazilyParse() const;
 
     MOZ_MUST_USE bool
     deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment);
 };
 
+template<typename Unit>
 class MOZ_STACK_CLASS SourceAwareCompiler
 {
   protected:
     SourceBufferHolder& sourceBuffer_;
 
-    Maybe<Parser<SyntaxParseHandler, char16_t>> syntaxParser;
-    Maybe<Parser<FullParseHandler, char16_t>> parser;
+    Maybe<Parser<SyntaxParseHandler, Unit>> syntaxParser;
+    Maybe<Parser<FullParseHandler, Unit>> parser;
 
-    using TokenStreamPosition = frontend::TokenStreamPosition<char16_t>;
+    using TokenStreamPosition = frontend::TokenStreamPosition<Unit>;
 
   protected:
     explicit SourceAwareCompiler(SourceBufferHolder& sourceBuffer)
       : sourceBuffer_(sourceBuffer)
     {
         MOZ_ASSERT(sourceBuffer_.get() != nullptr);
     }
 
@@ -160,20 +161,31 @@ class MOZ_STACK_CLASS SourceAwareCompile
         return info.internalCreateScript(toStringStart, toStringEnd, len);
     }
 
     MOZ_MUST_USE bool
     handleParseFailure(BytecodeCompiler& compiler, const Directives& newDirectives,
                        TokenStreamPosition& startPosition);
 };
 
+template<typename Unit>
 class MOZ_STACK_CLASS ScriptCompiler
-  : public SourceAwareCompiler
+  : public SourceAwareCompiler<Unit>
 {
-    using Base = SourceAwareCompiler;
+    using Base = SourceAwareCompiler<Unit>;
+
+  protected:
+    using Base::parser;
+    using Base::sourceBuffer_;
+
+    using Base::assertSourceParserAndScriptCreated;
+    using Base::emplaceEmitter;
+    using Base::handleParseFailure;
+
+    using typename Base::TokenStreamPosition;
 
   protected:
     using Base::Base;
 
     JSScript* compileScript(BytecodeCompiler& compiler, HandleObject environment,
                             SharedContext* sc);
 };
 
@@ -190,20 +202,24 @@ class MOZ_STACK_CLASS GlobalScriptInfo f
         MOZ_ASSERT(scopeKind == ScopeKind::Global || scopeKind == ScopeKind::NonSyntactic);
     }
 
     GlobalSharedContext* sharedContext() {
         return &globalsc_;
     }
 };
 
+template<typename Unit>
 class MOZ_STACK_CLASS GlobalScriptCompiler final
-  : public ScriptCompiler
+  : public ScriptCompiler<Unit>
 {
-    using Base = ScriptCompiler;
+    using Base = ScriptCompiler<Unit>;
+
+    using Base::compileScript;
+    using Base::prepareScriptParse;
 
   public:
     explicit GlobalScriptCompiler(SourceBufferHolder& srcBuf)
       : Base(srcBuf)
     {}
 
     JSScript* compile(GlobalScriptInfo& info) {
         if (!prepareScriptParse(info)) {
@@ -231,20 +247,24 @@ class MOZ_STACK_CLASS EvalScriptInfo fin
         return environment_;
     }
 
     EvalSharedContext* sharedContext() {
         return &evalsc_;
     }
 };
 
+template<typename Unit>
 class MOZ_STACK_CLASS EvalScriptCompiler final
-  : public ScriptCompiler
+  : public ScriptCompiler<Unit>
 {
-    using Base = ScriptCompiler;
+    using Base = ScriptCompiler<Unit>;
+
+    using Base::compileScript;
+    using Base::prepareScriptParse;
 
   public:
     explicit EvalScriptCompiler(SourceBufferHolder& srcBuf)
       : Base(srcBuf)
     {}
 
     JSScript* compile(EvalScriptInfo& info) {
         if (!prepareScriptParse(info)) {
@@ -258,20 +278,27 @@ class MOZ_STACK_CLASS ModuleInfo final
   : public BytecodeCompiler
 {
   public:
     ModuleInfo(JSContext* cx, const ReadOnlyCompileOptions& options)
       : BytecodeCompiler(cx, options)
     {}
 };
 
+template<typename Unit>
 class MOZ_STACK_CLASS ModuleCompiler final
-  : public SourceAwareCompiler
+  : public SourceAwareCompiler<Unit>
 {
-    using Base = SourceAwareCompiler;
+    using Base = SourceAwareCompiler<Unit>;
+
+    using Base::assertSourceParserAndScriptCreated;
+    using Base::createCompleteScript;
+    using Base::createSourceAndParser;
+    using Base::emplaceEmitter;
+    using Base::parser;
 
   public:
     explicit ModuleCompiler(SourceBufferHolder& srcBuf)
       : Base(srcBuf)
     {}
 
     ModuleObject* compile(ModuleInfo& info);
 };
@@ -280,20 +307,30 @@ class MOZ_STACK_CLASS StandaloneFunction
   : public BytecodeCompiler
 {
   public:
     StandaloneFunctionInfo(JSContext* cx, const ReadOnlyCompileOptions& options)
       : BytecodeCompiler(cx, options)
     {}
 };
 
+template<typename Unit>
 class MOZ_STACK_CLASS StandaloneFunctionCompiler final
-  : public SourceAwareCompiler
+  : public SourceAwareCompiler<Unit>
 {
-    using Base = SourceAwareCompiler;
+    using Base = SourceAwareCompiler<Unit>;
+
+    using Base::assertSourceAndParserCreated;
+    using Base::createSourceAndParser;
+    using Base::emplaceEmitter;
+    using Base::handleParseFailure;
+    using Base::parser;
+    using Base::sourceBuffer_;
+
+    using typename Base::TokenStreamPosition;
 
   public:
     explicit StandaloneFunctionCompiler(SourceBufferHolder& srcBuf)
       : Base(srcBuf)
     {}
 
     MOZ_MUST_USE bool prepare(StandaloneFunctionInfo& info,
                               const Maybe<uint32_t>& parameterListEnd)
@@ -414,19 +451,20 @@ BytecodeCompiler::canLazilyParse() const
            !options.sourceIsLazy &&
            !cx->lcovEnabled() &&
            // Disabled during record/replay. The replay debugger requires
            // scripts to be constructed in a consistent order, which might not
            // happen with lazy parsing.
            !mozilla::recordreplay::IsRecordingOrReplaying();
 }
 
+template<typename Unit>
 bool
-SourceAwareCompiler::createSourceAndParser(BytecodeCompiler& info, ParseGoal goal,
-                                           const Maybe<uint32_t>& parameterListEnd /* = Nothing() */)
+SourceAwareCompiler<Unit>::createSourceAndParser(BytecodeCompiler& info, ParseGoal goal,
+                                                 const Maybe<uint32_t>& parameterListEnd /* = Nothing() */)
 {
     if (!info.createScriptSource(parameterListEnd)) {
         return false;
     }
 
     if (!info.assignSource(sourceBuffer_)) {
         return false;
     }
@@ -466,19 +504,21 @@ BytecodeCompiler::emplaceEmitter(Maybe<B
 {
     BytecodeEmitter::EmitterMode emitterMode =
         options.selfHostingMode ? BytecodeEmitter::SelfHosting : BytecodeEmitter::Normal;
     emitter.emplace(/* parent = */ nullptr, parser, sharedContext, script,
                     /* lazyScript = */ nullptr, options.lineno, emitterMode);
     return emitter->init();
 }
 
+template<typename Unit>
 bool
-SourceAwareCompiler::handleParseFailure(BytecodeCompiler& info, const Directives& newDirectives,
-                                        TokenStreamPosition& startPosition)
+SourceAwareCompiler<Unit>::handleParseFailure(BytecodeCompiler& info,
+                                              const Directives& newDirectives,
+                                              TokenStreamPosition& startPosition)
 {
     if (parser->hadAbortedSyntaxParse()) {
         // Hit some unrecoverable ambiguity during an inner syntax parse.
         // Syntax parsing has now been disabled in the parser, so retry
         // the parse.
         parser->clearAbortedSyntaxParse();
     } else if (parser->anyChars.hadError() || info.directives == newDirectives) {
         return false;
@@ -511,18 +551,20 @@ BytecodeCompiler::deoptimizeArgumentsInE
             }
         }
         env = env->enclosingEnvironment();
     }
 
     return true;
 }
 
+template<typename Unit>
 JSScript*
-ScriptCompiler::compileScript(BytecodeCompiler& info, HandleObject environment, SharedContext* sc)
+ScriptCompiler<Unit>::compileScript(BytecodeCompiler& info, HandleObject environment,
+                                    SharedContext* sc)
 {
     assertSourceParserAndScriptCreated(info);
 
     TokenStreamPosition startPosition(info.keepAtoms, parser->tokenStream);
 
     Maybe<BytecodeEmitter> emitter;
     if (!emplaceEmitter(info, emitter, sc)) {
         return nullptr;
@@ -577,18 +619,19 @@ ScriptCompiler::compileScript(BytecodeCo
         return nullptr;
     }
 
     MOZ_ASSERT_IF(!cx->helperThread(), !cx->isExceptionPending());
 
     return info.script;
 }
 
+template<typename Unit>
 ModuleObject*
-ModuleCompiler::compile(ModuleInfo& info)
+ModuleCompiler<Unit>::compile(ModuleInfo& info)
 {
     if (!createSourceAndParser(info, ParseGoal::Module) || !createCompleteScript(info)) {
         return nullptr;
     }
 
     JSContext* cx = info.cx;
 
     Rooted<ModuleObject*> module(cx, ModuleObject::create(cx));
@@ -633,21 +676,22 @@ ModuleCompiler::compile(ModuleInfo& info
 
     MOZ_ASSERT_IF(!cx->helperThread(), !cx->isExceptionPending());
     return module;
 }
 
 // Parse a standalone JS function, which might appear as the value of an
 // event handler attribute in an HTML <INPUT> tag, or in a Function()
 // constructor.
+template<typename Unit>
 CodeNode*
-StandaloneFunctionCompiler::parse(StandaloneFunctionInfo& info, MutableHandleFunction fun,
-                                  HandleScope enclosingScope, GeneratorKind generatorKind,
-                                  FunctionAsyncKind asyncKind,
-                                  const Maybe<uint32_t>& parameterListEnd)
+StandaloneFunctionCompiler<Unit>::parse(StandaloneFunctionInfo& info, MutableHandleFunction fun,
+                                        HandleScope enclosingScope, GeneratorKind generatorKind,
+                                        FunctionAsyncKind asyncKind,
+                                        const Maybe<uint32_t>& parameterListEnd)
 {
     MOZ_ASSERT(fun);
     MOZ_ASSERT(fun->isTenured());
 
     assertSourceAndParserCreated(info);
 
     TokenStreamPosition startPosition(info.keepAtoms, parser->tokenStream);
 
@@ -665,19 +709,20 @@ StandaloneFunctionCompiler::parse(Standa
             return nullptr;
         }
     } while (!fn);
 
     return &fn->as<CodeNode>();
 }
 
 // Compile a standalone JS function.
+template<typename Unit>
 bool
-StandaloneFunctionCompiler::compile(StandaloneFunctionInfo& info, CodeNode* parsedFunction,
-                                    MutableHandleFunction fun)
+StandaloneFunctionCompiler<Unit>::compile(StandaloneFunctionInfo& info, CodeNode* parsedFunction,
+                                          MutableHandleFunction fun)
 {
     FunctionBox* funbox = parsedFunction->funbox();
     if (funbox->function()->isInterpreted()) {
         MOZ_ASSERT(fun == funbox->function());
 
         if (!createFunctionScript(info, funbox->toStringStart, funbox->toStringEnd)) {
             return false;
         }
@@ -814,17 +859,17 @@ frontend::CompileGlobalScript(JSContext*
 {
     MOZ_ASSERT(scopeKind == ScopeKind::Global || scopeKind == ScopeKind::NonSyntactic);
 
     AutoAssertReportedException assertException(cx);
 
     GlobalScriptInfo info(cx, options, scopeKind);
     AutoInitializeSourceObject autoSSO(info, sourceObjectOut);
 
-    GlobalScriptCompiler compiler(srcBuf);
+    GlobalScriptCompiler<char16_t> compiler(srcBuf);
     JSScript* script = compiler.compile(info);
     if (!script) {
         return nullptr;
     }
 
     assertException.reset();
     return script;
 }
@@ -899,17 +944,17 @@ frontend::CompileEvalScript(JSContext* c
                             SourceBufferHolder& srcBuf,
                             ScriptSourceObject** sourceObjectOut)
 {
     AutoAssertReportedException assertException(cx);
 
     EvalScriptInfo info(cx, options, environment, enclosingScope);
     AutoInitializeSourceObject autoSSO(info, sourceObjectOut);
 
-    EvalScriptCompiler compiler(srcBuf);
+    EvalScriptCompiler<char16_t> compiler(srcBuf);
     JSScript* script = compiler.compile(info);
     if (!script) {
         return nullptr;
     }
 
     assertException.reset();
     return script;
 
@@ -928,17 +973,17 @@ frontend::CompileModule(JSContext* cx, c
     CompileOptions options(cx, optionsInput);
     options.maybeMakeStrictMode(true); // ES6 10.2.1 Module code is always strict mode code.
     options.setIsRunOnce(true);
     options.allowHTMLComments = false;
 
     ModuleInfo info(cx, options);
     AutoInitializeSourceObject autoSSO(info, sourceObjectOut);
 
-    ModuleCompiler compiler(srcBuf);
+    ModuleCompiler<char16_t> compiler(srcBuf);
     ModuleObject* module = compiler.compile(info);
     if (!module) {
         return nullptr;
     }
 
     assertException.reset();
     return module;
 }
@@ -1176,17 +1221,17 @@ frontend::CompileStandaloneFunction(JSCo
                                     JS::SourceBufferHolder& srcBuf,
                                     const Maybe<uint32_t>& parameterListEnd,
                                     HandleScope enclosingScope /* = nullptr */)
 {
     AutoAssertReportedException assertException(cx);
 
     StandaloneFunctionInfo info(cx, options);
 
-    StandaloneFunctionCompiler compiler(srcBuf);
+    StandaloneFunctionCompiler<char16_t> compiler(srcBuf);
     if (!compiler.prepare(info, parameterListEnd)) {
         return false;
     }
 
     RootedScope scope(cx, enclosingScope);
     if (!scope) {
         scope = &cx->global()->emptyGlobalScope();
     }
@@ -1206,17 +1251,17 @@ frontend::CompileStandaloneGenerator(JSC
                                      const JS::ReadOnlyCompileOptions& options,
                                      JS::SourceBufferHolder& srcBuf,
                                      const Maybe<uint32_t>& parameterListEnd)
 {
     AutoAssertReportedException assertException(cx);
 
     StandaloneFunctionInfo info(cx, options);
 
-    StandaloneFunctionCompiler compiler(srcBuf);
+    StandaloneFunctionCompiler<char16_t> compiler(srcBuf);
     if (!compiler.prepare(info, parameterListEnd)) {
         return false;
     }
 
     RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
     CodeNode* parsedFunction =
         compiler.parse(info, fun, emptyGlobalScope, GeneratorKind::Generator,
                        FunctionAsyncKind::SyncFunction, parameterListEnd);
@@ -1233,17 +1278,17 @@ frontend::CompileStandaloneAsyncFunction
                                          const ReadOnlyCompileOptions& options,
                                          JS::SourceBufferHolder& srcBuf,
                                          const Maybe<uint32_t>& parameterListEnd)
 {
     AutoAssertReportedException assertException(cx);
 
     StandaloneFunctionInfo info(cx, options);
 
-    StandaloneFunctionCompiler compiler(srcBuf);
+    StandaloneFunctionCompiler<char16_t> compiler(srcBuf);
     if (!compiler.prepare(info, parameterListEnd)) {
         return false;
     }
 
     RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
     CodeNode* parsedFunction =
         compiler.parse(info, fun, emptyGlobalScope, GeneratorKind::NotGenerator,
                        FunctionAsyncKind::AsyncFunction, parameterListEnd);
@@ -1260,17 +1305,17 @@ frontend::CompileStandaloneAsyncGenerato
                                           const ReadOnlyCompileOptions& options,
                                           JS::SourceBufferHolder& srcBuf,
                                           const Maybe<uint32_t>& parameterListEnd)
 {
     AutoAssertReportedException assertException(cx);
 
     StandaloneFunctionInfo info(cx, options);
 
-    StandaloneFunctionCompiler compiler(srcBuf);
+    StandaloneFunctionCompiler<char16_t> compiler(srcBuf);
     if (!compiler.prepare(info, parameterListEnd)) {
         return false;
     }
 
     RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
     CodeNode* parsedFunction =
         compiler.parse(info, fun, emptyGlobalScope, GeneratorKind::Generator,
                        FunctionAsyncKind::AsyncFunction, parameterListEnd);