Bug 1498320 - Implement CompileGlobalScript in terms of a template CreateGlobalScript function that handles UTF-8 and UTF-16 both. r=tcampbell
authorJeff Walden <jwalden@mit.edu>
Fri, 26 Oct 2018 21:28:14 -0700
changeset 446432 9d7d25507cacca3488f4efd3e4034d3a45d405eb
parent 446431 56eaf6c976d377cba4e44a302bdeda9e7420bd94
child 446433 ecf813f9f9ea656b973f79c25352e7f2727f6c0f
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 - Implement CompileGlobalScript in terms of a template CreateGlobalScript function that handles UTF-8 and UTF-16 both. r=tcampbell
js/src/frontend/BytecodeCompiler.cpp
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -35,21 +35,52 @@ using namespace js::frontend;
 
 using mozilla::Maybe;
 using mozilla::Nothing;
 
 using JS::CompileOptions;
 using JS::ReadOnlyCompileOptions;
 using JS::SourceText;
 
+class BytecodeCompiler;
+
 template<typename Unit> class SourceAwareCompiler;
 template<typename Unit> class ScriptCompiler;
 template<typename Unit> class ModuleCompiler;
 template<typename Unit> class StandaloneFunctionCompiler;
 
+// CompileScript independently returns the ScriptSourceObject (SSO) for the
+// compile.  This is used by off-thread script compilation (OT-SC).
+//
+// OT-SC cannot initialize the SSO when it is first constructed because the
+// SSO is allocated initially in a separate compartment.
+//
+// After OT-SC, the separate compartment is merged with the main compartment,
+// at which point the JSScripts created become observable by the debugger via
+// memory-space scanning.
+//
+// Whatever happens to the top-level script compilation (even if it fails and
+// returns null), we must finish initializing the SSO.  This is because there
+// may be valid inner scripts observable by the debugger which reference the
+// partially-initialized SSO.
+class MOZ_STACK_CLASS AutoInitializeSourceObject
+{
+    BytecodeCompiler& compiler_;
+    ScriptSourceObject** sourceObjectOut_;
+
+  public:
+    AutoInitializeSourceObject(BytecodeCompiler& compiler,
+                               ScriptSourceObject** sourceObjectOut)
+      : compiler_(compiler),
+        sourceObjectOut_(sourceObjectOut)
+    { }
+
+    inline ~AutoInitializeSourceObject();
+};
+
 // The BytecodeCompiler class contains resources common to compiling scripts and
 // function bodies.
 class MOZ_STACK_CLASS BytecodeCompiler
 {
   protected:
     AutoKeepAtoms keepAtoms;
 
     JSContext* cx;
@@ -68,16 +99,20 @@ class MOZ_STACK_CLASS BytecodeCompiler
     BytecodeCompiler(JSContext* cx, const ReadOnlyCompileOptions& options);
 
     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:
+    JSContext* context() const {
+        return cx;
+    }
+
     ScriptSourceObject* sourceObjectPtr() const {
         return sourceObject.get();
     }
 
   protected:
     void assertSourceCreated() const {
         MOZ_ASSERT(sourceObject != nullptr);
         MOZ_ASSERT(scriptSource != nullptr);
@@ -103,16 +138,62 @@ class MOZ_STACK_CLASS BytecodeCompiler
     MOZ_MUST_USE bool assignSource(SourceText<Unit>& sourceBuffer);
 
     bool canLazilyParse() const;
 
     MOZ_MUST_USE bool
     deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment);
 };
 
+inline
+AutoInitializeSourceObject::~AutoInitializeSourceObject()
+{
+    if (sourceObjectOut_) {
+        *sourceObjectOut_ = compiler_.sourceObjectPtr();
+    }
+}
+
+// RAII class to check the frontend reports an exception when it fails to
+// compile a script.
+class MOZ_RAII AutoAssertReportedException
+{
+#ifdef DEBUG
+    JSContext* cx_;
+    bool check_;
+
+  public:
+    explicit AutoAssertReportedException(JSContext* cx)
+      : cx_(cx),
+        check_(true)
+    {}
+    void reset() {
+        check_ = false;
+    }
+    ~AutoAssertReportedException() {
+        if (!check_) {
+            return;
+        }
+
+        if (!cx_->helperThread()) {
+            MOZ_ASSERT(cx_->isExceptionPending());
+            return;
+        }
+
+        ParseTask* task = cx_->helperThread()->parseTask();
+        MOZ_ASSERT(task->outOfMemory ||
+                   task->overRecursed ||
+                   !task->errors.empty());
+    }
+#else
+  public:
+    explicit AutoAssertReportedException(JSContext*) {}
+    void reset() {}
+#endif
+};
+
 template<typename Unit>
 class MOZ_STACK_CLASS SourceAwareCompiler
 {
   protected:
     SourceText<Unit>& sourceBuffer_;
 
     Maybe<Parser<SyntaxParseHandler, Unit>> syntaxParser;
     Maybe<Parser<FullParseHandler, Unit>> parser;
@@ -177,18 +258,24 @@ class MOZ_STACK_CLASS ScriptCompiler
     using Base::sourceBuffer_;
 
     using Base::assertSourceParserAndScriptCreated;
     using Base::emplaceEmitter;
     using Base::handleParseFailure;
 
     using typename Base::TokenStreamPosition;
 
-  protected:
-    using Base::Base;
+  public:
+    explicit ScriptCompiler(SourceText<Unit>& srcBuf)
+      : Base(srcBuf)
+    {}
+
+    MOZ_MUST_USE bool prepareScriptParse(BytecodeCompiler& compiler) {
+        return Base::prepareScriptParse(compiler);
+    }
 
     JSScript* compileScript(BytecodeCompiler& compiler, HandleObject environment,
                             SharedContext* sc);
 };
 
 class MOZ_STACK_CLASS GlobalScriptInfo final
   : public BytecodeCompiler
 {
@@ -203,36 +290,37 @@ class MOZ_STACK_CLASS GlobalScriptInfo f
     }
 
     GlobalSharedContext* sharedContext() {
         return &globalsc_;
     }
 };
 
 template<typename Unit>
-class MOZ_STACK_CLASS GlobalScriptCompiler final
-  : public ScriptCompiler<Unit>
+static JSScript*
+CreateGlobalScript(GlobalScriptInfo& info, JS::SourceText<Unit>& srcBuf,
+                   ScriptSourceObject** sourceObjectOut = nullptr)
 {
-    using Base = ScriptCompiler<Unit>;
+    AutoAssertReportedException assertException(info.context());
 
-    using Base::compileScript;
-    using Base::prepareScriptParse;
+    ScriptCompiler<Unit> compiler(srcBuf);
+    AutoInitializeSourceObject autoSSO(info, sourceObjectOut);
 
-  public:
-    explicit GlobalScriptCompiler(SourceText<Unit>& srcBuf)
-      : Base(srcBuf)
-    {}
+    if (!compiler.prepareScriptParse(info)) {
+        return nullptr;
+    }
 
-    JSScript* compile(GlobalScriptInfo& info) {
-        if (!prepareScriptParse(info)) {
-            return nullptr;
-        }
-        return compileScript(info, nullptr, info.sharedContext());
+    JSScript* script = compiler.compileScript(info, nullptr, info.sharedContext());
+    if (!script) {
+        return nullptr;
     }
-};
+
+    assertException.reset();
+    return script;
+}
 
 class MOZ_STACK_CLASS EvalScriptInfo final
   : public BytecodeCompiler
 {
     HandleObject environment_;
     EvalSharedContext evalsc_;
 
   public:
@@ -776,108 +864,26 @@ frontend::CreateScriptSourceObject(JSCon
         if (!ScriptSourceObject::initFromOptions(cx, sso, options)) {
             return nullptr;
         }
     }
 
     return sso;
 }
 
-// CompileScript independently returns the ScriptSourceObject (SSO) for the
-// compile.  This is used by off-thread script compilation (OT-SC).
-//
-// OT-SC cannot initialize the SSO when it is first constructed because the
-// SSO is allocated initially in a separate compartment.
-//
-// After OT-SC, the separate compartment is merged with the main compartment,
-// at which point the JSScripts created become observable by the debugger via
-// memory-space scanning.
-//
-// Whatever happens to the top-level script compilation (even if it fails and
-// returns null), we must finish initializing the SSO.  This is because there
-// may be valid inner scripts observable by the debugger which reference the
-// partially-initialized SSO.
-class MOZ_STACK_CLASS AutoInitializeSourceObject
-{
-    BytecodeCompiler& compiler_;
-    ScriptSourceObject** sourceObjectOut_;
-
-  public:
-    AutoInitializeSourceObject(BytecodeCompiler& compiler,
-                               ScriptSourceObject** sourceObjectOut)
-      : compiler_(compiler),
-        sourceObjectOut_(sourceObjectOut)
-    { }
-
-    ~AutoInitializeSourceObject() {
-        if (sourceObjectOut_) {
-            *sourceObjectOut_ = compiler_.sourceObjectPtr();
-        }
-    }
-};
-
-// RAII class to check the frontend reports an exception when it fails to
-// compile a script.
-class MOZ_RAII AutoAssertReportedException
-{
-#ifdef DEBUG
-    JSContext* cx_;
-    bool check_;
-
-  public:
-    explicit AutoAssertReportedException(JSContext* cx)
-      : cx_(cx),
-        check_(true)
-    {}
-    void reset() {
-        check_ = false;
-    }
-    ~AutoAssertReportedException() {
-        if (!check_) {
-            return;
-        }
-
-        if (!cx_->helperThread()) {
-            MOZ_ASSERT(cx_->isExceptionPending());
-            return;
-        }
-
-        ParseTask* task = cx_->helperThread()->parseTask();
-        MOZ_ASSERT(task->outOfMemory ||
-                   task->overRecursed ||
-                   !task->errors.empty());
-    }
-#else
-  public:
-    explicit AutoAssertReportedException(JSContext*) {}
-    void reset() {}
-#endif
-};
-
 JSScript*
 frontend::CompileGlobalScript(JSContext* cx, ScopeKind scopeKind,
                               const ReadOnlyCompileOptions& options,
                               SourceText<char16_t>& srcBuf,
                               ScriptSourceObject** sourceObjectOut)
 {
     MOZ_ASSERT(scopeKind == ScopeKind::Global || scopeKind == ScopeKind::NonSyntactic);
 
-    AutoAssertReportedException assertException(cx);
-
     GlobalScriptInfo info(cx, options, scopeKind);
-    AutoInitializeSourceObject autoSSO(info, sourceObjectOut);
-
-    GlobalScriptCompiler<char16_t> compiler(srcBuf);
-    JSScript* script = compiler.compile(info);
-    if (!script) {
-        return nullptr;
-    }
-
-    assertException.reset();
-    return script;
+    return CreateGlobalScript(info, srcBuf, sourceObjectOut);
 }
 
 #if defined(JS_BUILD_BINAST)
 
 JSScript*
 frontend::CompileGlobalBinASTScript(JSContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
                                     const uint8_t* src, size_t len, ScriptSourceObject** sourceObjectOut)
 {