Bug 1498320 - Create a BytecodeCompiler subclass for standalone function compilation. r=tcampbell
authorJeff Walden <jwalden@mit.edu>
Thu, 01 Nov 2018 17:34:55 -0700
changeset 446504 9dc874d79c1f1f60869a806ddeb4f78915504360
parent 446503 3ed7e8a375625442194ebb38dc2fd4c1d476b760
child 446505 630a1645006614713cbe8698542c6d278601cb6f
push id35042
push useraiakab@mozilla.com
push dateThu, 15 Nov 2018 09:54:38 +0000
treeherdermozilla-central@dca9c72df68b [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 for standalone function compilation. r=tcampbell
js/src/frontend/BytecodeCompiler.cpp
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -71,66 +71,55 @@ 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 parseStandaloneFunction.
-    MOZ_MUST_USE bool prepareStandaloneFunctionParse(const Maybe<uint32_t>& parameterListEnd) {
-        return createSourceAndParser(ParseGoal::Script, parameterListEnd);
+  protected:
+    void assertSourceAndParserCreated() const {
+        MOZ_ASSERT(sourceObject != nullptr);
+        MOZ_ASSERT(scriptSource != nullptr);
+        MOZ_ASSERT(usedNames.isSome());
+        MOZ_ASSERT(parser.isSome());
     }
 
-    // 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();
 
+    // This uses explicitly-provided toString offsets as the created script's
+    // offsets in the source.
+    MOZ_MUST_USE bool createScript(uint32_t toStringStart, uint32_t toStringEnd);
+
     MOZ_MUST_USE bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
 
+    using TokenStreamPosition = frontend::TokenStreamPosition<char16_t>;
+
+    MOZ_MUST_USE bool handleParseFailure(const Directives& newDirectives,
+                                         TokenStreamPosition& startPosition);
+
   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);
 
-    // 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 handleParseFailure(const Directives& newDirectives, TokenStreamPosition& startPosition);
     bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment);
 };
 
 class MOZ_STACK_CLASS GlobalScriptBytecodeCompiler final
   : public BytecodeCompiler
 {
     GlobalSharedContext globalsc_;
 
@@ -181,16 +170,36 @@ class MOZ_STACK_CLASS ModuleBytecodeComp
     ModuleBytecodeCompiler(JSContext* cx, const ReadOnlyCompileOptions& options,
                            SourceBufferHolder& sourceBuffer)
       : BytecodeCompiler(cx, options, sourceBuffer)
     {}
 
     ModuleObject* compile();
 };
 
+class MOZ_STACK_CLASS StandaloneFunctionBytecodeCompiler
+  : public BytecodeCompiler
+{
+  public:
+    StandaloneFunctionBytecodeCompiler(JSContext* cx, const ReadOnlyCompileOptions& options,
+                                       SourceBufferHolder& sourceBuffer)
+      : BytecodeCompiler(cx, options, sourceBuffer)
+    {}
+
+    MOZ_MUST_USE bool prepare(const Maybe<uint32_t>& parameterListEnd) {
+        return createSourceAndParser(ParseGoal::Script, parameterListEnd);
+    }
+
+    CodeNode* parse(MutableHandleFunction fun, HandleScope enclosingScope,
+                    GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
+                    const Maybe<uint32_t>& parameterListEnd);
+
+    MOZ_MUST_USE bool compile(CodeNode* parsedFunction, MutableHandleFunction fun);
+};
+
 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;
@@ -502,21 +511,19 @@ ModuleBytecodeCompiler::compile()
     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.
 CodeNode*
-BytecodeCompiler::parseStandaloneFunction(MutableHandleFunction fun,
-                                          GeneratorKind generatorKind,
-                                          FunctionAsyncKind asyncKind,
-                                          const Maybe<uint32_t>& parameterListEnd,
-                                          HandleScope enclosingScope)
+StandaloneFunctionBytecodeCompiler::parse(MutableHandleFunction fun, HandleScope enclosingScope,
+                                          GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
+                                          const Maybe<uint32_t>& parameterListEnd)
 {
     MOZ_ASSERT(fun);
     MOZ_ASSERT(fun->isTenured());
 
     assertSourceAndParserCreated();
 
     TokenStreamPosition startPosition(keepAtoms, parser->tokenStream);
 
@@ -535,17 +542,17 @@ BytecodeCompiler::parseStandaloneFunctio
         }
     } while (!fn);
 
     return &fn->as<CodeNode>();
 }
 
 // Compile a standalone JS function.
 bool
-BytecodeCompiler::compileStandaloneFunction(CodeNode* parsedFunction, MutableHandleFunction fun)
+StandaloneFunctionBytecodeCompiler::compile(CodeNode* parsedFunction, MutableHandleFunction fun)
 {
     FunctionBox* funbox = parsedFunction->funbox();
     if (funbox->function()->isInterpreted()) {
         MOZ_ASSERT(fun == funbox->function());
 
         if (!createScript(funbox->toStringStart, funbox->toStringEnd)) {
             return false;
         }
@@ -1039,106 +1046,99 @@ bool
 frontend::CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
                                     const JS::ReadOnlyCompileOptions& options,
                                     JS::SourceBufferHolder& srcBuf,
                                     const Maybe<uint32_t>& parameterListEnd,
                                     HandleScope enclosingScope /* = nullptr */)
 {
     AutoAssertReportedException assertException(cx);
 
-    BytecodeCompiler compiler(cx, options, srcBuf);
-    if (!compiler.prepareStandaloneFunctionParse(parameterListEnd)) {
+    StandaloneFunctionBytecodeCompiler compiler(cx, options, srcBuf);
+    if (!compiler.prepare(parameterListEnd)) {
         return false;
     }
 
     RootedScope scope(cx, enclosingScope);
     if (!scope) {
         scope = &cx->global()->emptyGlobalScope();
     }
 
-    CodeNode* parsedFunction = compiler.parseStandaloneFunction(fun, GeneratorKind::NotGenerator,
-                                                                FunctionAsyncKind::SyncFunction,
-                                                                parameterListEnd, scope);
-    if (!parsedFunction || !compiler.compileStandaloneFunction(parsedFunction, fun)) {
+    CodeNode* parsedFunction = compiler.parse(fun, scope, GeneratorKind::NotGenerator,
+                                              FunctionAsyncKind::SyncFunction, parameterListEnd);
+    if (!parsedFunction || !compiler.compile(parsedFunction, fun)) {
         return false;
     }
 
     assertException.reset();
     return true;
 }
 
 bool
 frontend::CompileStandaloneGenerator(JSContext* cx, MutableHandleFunction fun,
                                      const JS::ReadOnlyCompileOptions& options,
                                      JS::SourceBufferHolder& srcBuf,
                                      const Maybe<uint32_t>& parameterListEnd)
 {
     AutoAssertReportedException assertException(cx);
 
-    BytecodeCompiler compiler(cx, options, srcBuf);
-    if (!compiler.prepareStandaloneFunctionParse(parameterListEnd)) {
+    StandaloneFunctionBytecodeCompiler compiler(cx, options, srcBuf);
+    if (!compiler.prepare(parameterListEnd)) {
         return false;
     }
 
     RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
-    CodeNode* parsedFunction = compiler.parseStandaloneFunction(fun, GeneratorKind::Generator,
-                                                                FunctionAsyncKind::SyncFunction,
-                                                                parameterListEnd,
-                                                                emptyGlobalScope);
-    if (!parsedFunction || !compiler.compileStandaloneFunction(parsedFunction, fun)) {
+    CodeNode* parsedFunction = compiler.parse(fun, emptyGlobalScope, GeneratorKind::Generator,
+                                              FunctionAsyncKind::SyncFunction, parameterListEnd);
+    if (!parsedFunction || !compiler.compile(parsedFunction, fun)) {
         return false;
     }
 
     assertException.reset();
     return true;
 }
 
 bool
 frontend::CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
                                          const ReadOnlyCompileOptions& options,
                                          JS::SourceBufferHolder& srcBuf,
                                          const Maybe<uint32_t>& parameterListEnd)
 {
     AutoAssertReportedException assertException(cx);
 
-    BytecodeCompiler compiler(cx, options, srcBuf);
-    if (!compiler.prepareStandaloneFunctionParse(parameterListEnd)) {
+    StandaloneFunctionBytecodeCompiler compiler(cx, options, srcBuf);
+    if (!compiler.prepare(parameterListEnd)) {
         return false;
     }
 
     RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
-    CodeNode* parsedFunction = compiler.parseStandaloneFunction(fun, GeneratorKind::NotGenerator,
-                                                                FunctionAsyncKind::AsyncFunction,
-                                                                parameterListEnd,
-                                                                emptyGlobalScope);
-    if (!parsedFunction || !compiler.compileStandaloneFunction(parsedFunction, fun)) {
+    CodeNode* parsedFunction = compiler.parse(fun, emptyGlobalScope, GeneratorKind::NotGenerator,
+                                              FunctionAsyncKind::AsyncFunction, parameterListEnd);
+    if (!parsedFunction || !compiler.compile(parsedFunction, fun)) {
         return false;
     }
 
     assertException.reset();
     return true;
 }
 
 bool
 frontend::CompileStandaloneAsyncGenerator(JSContext* cx, MutableHandleFunction fun,
                                           const ReadOnlyCompileOptions& options,
                                           JS::SourceBufferHolder& srcBuf,
                                           const Maybe<uint32_t>& parameterListEnd)
 {
     AutoAssertReportedException assertException(cx);
 
-    BytecodeCompiler compiler(cx, options, srcBuf);
-    if (!compiler.prepareStandaloneFunctionParse(parameterListEnd)) {
+    StandaloneFunctionBytecodeCompiler compiler(cx, options, srcBuf);
+    if (!compiler.prepare(parameterListEnd)) {
         return false;
     }
 
     RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
-    CodeNode* parsedFunction = compiler.parseStandaloneFunction(fun, GeneratorKind::Generator,
-                                                                FunctionAsyncKind::AsyncFunction,
-                                                                parameterListEnd,
-                                                                emptyGlobalScope);
-    if (!parsedFunction || !compiler.compileStandaloneFunction(parsedFunction, fun)) {
+    CodeNode* parsedFunction = compiler.parse(fun, emptyGlobalScope, GeneratorKind::Generator,
+                                              FunctionAsyncKind::AsyncFunction, parameterListEnd);
+    if (!parsedFunction || !compiler.compile(parsedFunction, fun)) {
         return false;
     }
 
     assertException.reset();
     return true;
 }