Bug 1498320 - Create a BytecodeCompiler subclass to perform module compilation. r=tcampbell
authorJeff Walden <jwalden@mit.edu>
Thu, 01 Nov 2018 17:34:54 -0700
changeset 446426 3ed7e8a375625442194ebb38dc2fd4c1d476b760
parent 446425 76feab5328edddcedcacf16353b3fd8c05b2eedf
child 446427 9dc874d79c1f1f60869a806ddeb4f78915504360
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 - Create a BytecodeCompiler subclass to perform module compilation. r=tcampbell
js/src/frontend/BytecodeCompiler.cpp
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "frontend/BytecodeCompiler.h"
 
+#include "mozilla/Attributes.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/Maybe.h"
 
 #include "builtin/ModuleObject.h"
 #if defined(JS_BUILD_BINAST)
 # include "frontend/BinSource.h"
 #endif // JS_BUILD_BINAST
 #include "frontend/BytecodeEmitter.h"
@@ -70,70 +71,65 @@ class MOZ_STACK_CLASS BytecodeCompiler
         return sourceObject.get();
     }
 
     // Call this before calling compile{Global,Eval}Script.
     MOZ_MUST_USE bool prepareScriptParse() {
         return createSourceAndParser(ParseGoal::Script) && createCompleteScript();
     }
 
-    // Call this before calling compileModule.
-    MOZ_MUST_USE bool prepareModuleParse() {
-        return createSourceAndParser(ParseGoal::Module) && createCompleteScript();
-    }
-
-    ModuleObject* compileModule(HandleScope enclosingScope);
-
     // Call this before calling parseStandaloneFunction.
     MOZ_MUST_USE bool prepareStandaloneFunctionParse(const Maybe<uint32_t>& parameterListEnd) {
         return createSourceAndParser(ParseGoal::Script, parameterListEnd);
     }
 
     // Call this before calling compileStandaloneFunction.
     CodeNode* parseStandaloneFunction(MutableHandleFunction fun, GeneratorKind generatorKind,
                                       FunctionAsyncKind asyncKind,
                                       const Maybe<uint32_t>& parameterListEnd,
                                       HandleScope enclosingScope);
 
     bool compileStandaloneFunction(CodeNode* parsedFunction, MutableHandleFunction fun);
 
   protected:
     JSScript* compileScript(HandleObject environment, SharedContext* sc);
 
+    MOZ_MUST_USE bool createSourceAndParser(ParseGoal goal,
+                                            const Maybe<uint32_t>& parameterListEnd = Nothing());
+
+    // This assumes the created script's offsets in the source used to parse it
+    // are the same as are used to compute its Function.prototype.toString()
+    // value.
+    MOZ_MUST_USE bool createCompleteScript();
+
+    MOZ_MUST_USE bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
+
   private:
     void assertSourceAndParserCreated() const {
         MOZ_ASSERT(sourceObject != nullptr);
         MOZ_ASSERT(scriptSource != nullptr);
         MOZ_ASSERT(usedNames.isSome());
         MOZ_ASSERT(parser.isSome());
     }
 
     void assertSourceParserAndScriptCreated() const {
         assertSourceAndParserCreated();
         MOZ_ASSERT(script != nullptr);
     }
 
     bool createScriptSource(const Maybe<uint32_t>& parameterListEnd);
     bool canLazilyParse();
     bool createParser(ParseGoal goal);
-    bool createSourceAndParser(ParseGoal goal,
-                               const Maybe<uint32_t>& parameterListEnd = Nothing());
-
-    // This assumes the created script's offsets in the source used to parse it
-    // are the same as are used to compute its Function.prototype.toString()
-    // value.
-    bool createCompleteScript();
 
     // This uses explicitly-provided toString offsets as the created script's
     // offsets in the source.
     bool createScript(uint32_t toStringStart, uint32_t toStringEnd);
 
     using TokenStreamPosition = frontend::TokenStreamPosition<char16_t>;
 
-    bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
     bool handleParseFailure(const Directives& newDirectives, TokenStreamPosition& startPosition);
     bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment);
 };
 
 class MOZ_STACK_CLASS GlobalScriptBytecodeCompiler final
   : public BytecodeCompiler
 {
     GlobalSharedContext globalsc_;
@@ -173,16 +169,28 @@ class MOZ_STACK_CLASS EvalScriptBytecode
     JSScript* compile() {
         if (!prepareScriptParse()) {
             return nullptr;
         }
         return compileScript(environment_, &evalsc_);
     }
 };
 
+class MOZ_STACK_CLASS ModuleBytecodeCompiler final
+  : public BytecodeCompiler
+{
+  public:
+    ModuleBytecodeCompiler(JSContext* cx, const ReadOnlyCompileOptions& options,
+                           SourceBufferHolder& sourceBuffer)
+      : BytecodeCompiler(cx, options, sourceBuffer)
+    {}
+
+    ModuleObject* compile();
+};
+
 AutoFrontendTraceLog::AutoFrontendTraceLog(JSContext* cx, const TraceLoggerTextId id,
                                            const ErrorReporter& errorReporter)
 #ifdef JS_TRACE_LOGGING
   : logger_(TraceLoggerForCurrentThread(cx))
 {
     // If the tokenizer hasn't yet gotten any tokens, use the line and column
     // numbers from CompileOptions.
     uint32_t line, column;
@@ -440,29 +448,32 @@ BytecodeCompiler::compileScript(HandleOb
     }
 
     MOZ_ASSERT_IF(!cx->helperThread(), !cx->isExceptionPending());
 
     return script;
 }
 
 ModuleObject*
-BytecodeCompiler::compileModule(HandleScope enclosingScope)
+ModuleBytecodeCompiler::compile()
 {
-    assertSourceParserAndScriptCreated();
+    if (!createSourceAndParser(ParseGoal::Module) || !createCompleteScript()) {
+        return nullptr;
+    }
 
     Rooted<ModuleObject*> module(cx, ModuleObject::create(cx));
     if (!module) {
         return nullptr;
     }
 
     module->init(script);
 
     ModuleBuilder builder(cx, module, parser->anyChars);
 
+    RootedScope enclosingScope(cx, &cx->global()->emptyGlobalScope());
     ModuleSharedContext modulesc(cx, module, enclosingScope, builder);
     ParseNode* pn = parser->moduleBody(&modulesc);
     if (!pn) {
         return nullptr;
     }
 
     Maybe<BytecodeEmitter> emitter;
     if (!emplaceEmitter(emitter, &modulesc)) {
@@ -780,25 +791,20 @@ frontend::CompileModule(JSContext* cx, c
 
     AutoAssertReportedException assertException(cx);
 
     CompileOptions options(cx, optionsInput);
     options.maybeMakeStrictMode(true); // ES6 10.2.1 Module code is always strict mode code.
     options.setIsRunOnce(true);
     options.allowHTMLComments = false;
 
-    BytecodeCompiler compiler(cx, options, srcBuf);
+    ModuleBytecodeCompiler compiler(cx, options, srcBuf);
     AutoInitializeSourceObject autoSSO(compiler, sourceObjectOut);
 
-    if (!compiler.prepareModuleParse()) {
-        return nullptr;
-    }
-
-    RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
-    ModuleObject* module = compiler.compileModule(emptyGlobalScope);
+    ModuleObject* module = compiler.compile();
     if (!module) {
         return nullptr;
     }
 
     assertException.reset();
     return module;
 }