Bug 1498320 - Introduce a new BytecodeCompilation.h header for fresh bytecode compilation signatures coming soon. r=tcampbell
authorJeff Walden <jwalden@mit.edu>
Thu, 08 Nov 2018 18:45:26 -0800
changeset 446514 1dd5267839b3ccd35c62bcff81f7b8c60304f13e
parent 446513 ba6ba95b3cd24e79ea99df4adb2ab4e7be1d7d0a
child 446515 24670a08843eba386bc29ad58c8289c39ac969e7
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 - Introduce a new BytecodeCompilation.h header for fresh bytecode compilation signatures coming soon. r=tcampbell
js/src/frontend/BytecodeCompilation.h
js/src/frontend/BytecodeCompiler.cpp
copy from js/src/frontend/BytecodeCompiler.cpp
copy to js/src/frontend/BytecodeCompilation.h
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompilation.h
@@ -1,107 +1,66 @@
 /* -*- 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"
+#ifndef frontend_BytecodeCompilation_h
+#define frontend_BytecodeCompilation_h
 
-#include "mozilla/Attributes.h"
-#include "mozilla/IntegerPrintfMacros.h"
-#include "mozilla/Maybe.h"
+#include "mozilla/Assertions.h" // MOZ_ASSERT
+#include "mozilla/Attributes.h" // MOZ_MUST_USE, MOZ_STACK_CLASS
+#include "mozilla/Maybe.h" // mozilla::Maybe, mozilla::Nothing
+
+#include <stdint.h> // uint32_t
 
-#include "builtin/ModuleObject.h"
-#if defined(JS_BUILD_BINAST)
-# include "frontend/BinSource.h"
-#endif // JS_BUILD_BINAST
-#include "frontend/BytecodeEmitter.h"
-#include "frontend/EitherParser.h"
-#include "frontend/ErrorReporter.h"
-#include "frontend/FoldConstants.h"
-#include "frontend/Parser.h"
-#include "js/SourceText.h"
-#include "vm/GlobalObject.h"
-#include "vm/JSContext.h"
-#include "vm/JSScript.h"
-#include "vm/TraceLogging.h"
-#include "wasm/AsmJS.h"
+#include "frontend/EitherParser.h" // js::frontend::EitherParser
+#include "frontend/ParseContext.h" // js::frontend::UsedNameTracker
+#include "frontend/SharedContext.h" // js::frontend::Directives, js::frontend::{,Eval,Global}SharedContext
+#include "js/CompileOptions.h" // JS::ReadOnlyCompileOptions
+#include "js/RootingAPI.h" // JS::{,Mutable}Handle, JS::Rooted
+#include "js/SourceText.h" // JS::SourceText
+#include "vm/JSContext.h" // js::AutoKeepAtoms
+#include "vm/JSScript.h" // js::{FunctionAsync,Generator}Kind, JSScript, js::ScriptSource, js::ScriptSourceObject
+#include "vm/Scope.h" // js::ScopeKind
 
-#include "vm/EnvironmentObject-inl.h"
-#include "vm/GeckoProfiler-inl.h"
-#include "vm/JSContext-inl.h"
-
-using namespace js;
-using namespace js::frontend;
+class JSFunction;
+class JSObject;
 
-using mozilla::Maybe;
-using mozilla::Nothing;
+namespace js {
 
-using JS::CompileOptions;
-using JS::ReadOnlyCompileOptions;
-using JS::SourceText;
-
-class BytecodeCompiler;
+namespace frontend {
 
 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;
-    const ReadOnlyCompileOptions& options;
+    const JS::ReadOnlyCompileOptions& options;
 
-    RootedScriptSourceObject sourceObject;
+    JS::Rooted<ScriptSourceObject*> sourceObject;
     ScriptSource* scriptSource = nullptr;
 
-    Maybe<UsedNameTracker> usedNames;
+    mozilla::Maybe<UsedNameTracker> usedNames;
 
     Directives directives;
 
-    RootedScript script;
+    JS::Rooted<JSScript*> script;
 
   protected:
-    BytecodeCompiler(JSContext* cx, const ReadOnlyCompileOptions& options);
+    BytecodeCompiler(JSContext* cx, const JS::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 {
@@ -113,1222 +72,97 @@ class MOZ_STACK_CLASS BytecodeCompiler
     }
 
   protected:
     void assertSourceCreated() const {
         MOZ_ASSERT(sourceObject != nullptr);
         MOZ_ASSERT(scriptSource != nullptr);
     }
 
-    MOZ_MUST_USE bool createScriptSource(const Maybe<uint32_t>& parameterListEnd);
+    MOZ_MUST_USE bool createScriptSource(const mozilla::Maybe<uint32_t>& parameterListEnd);
 
     void createUsedNames() {
         usedNames.emplace(cx);
     }
 
     // Create a script for source of the given length, using the explicitly-
     // provided toString offsets as the created script's offsets in the source.
     MOZ_MUST_USE bool internalCreateScript(uint32_t toStringStart, uint32_t toStringEnd,
                                            uint32_t sourceBufferLength);
 
-    MOZ_MUST_USE bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter,
+    MOZ_MUST_USE bool emplaceEmitter(mozilla::Maybe<BytecodeEmitter>& emitter,
                                      const EitherParser& parser, SharedContext* sharedContext);
 
     // This function lives here, not in SourceAwareCompiler, because it mostly
     // uses fields in *this* class.
     template<typename Unit>
-    MOZ_MUST_USE bool assignSource(SourceText<Unit>& sourceBuffer);
+    MOZ_MUST_USE bool assignSource(JS::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;
-
-    using TokenStreamPosition = frontend::TokenStreamPosition<Unit>;
-
-  protected:
-    explicit SourceAwareCompiler(SourceText<Unit>& sourceBuffer)
-      : sourceBuffer_(sourceBuffer)
-    {
-        MOZ_ASSERT(sourceBuffer_.get() != nullptr);
-    }
-
-    // Call this before calling compile{Global,Eval}Script.
-    MOZ_MUST_USE bool prepareScriptParse(BytecodeCompiler& info) {
-        return createSourceAndParser(info, ParseGoal::Script) && createCompleteScript(info);
-    }
-
-    void assertSourceAndParserCreated(BytecodeCompiler& info) const {
-        info.assertSourceCreated();
-        MOZ_ASSERT(info.usedNames.isSome());
-        MOZ_ASSERT(parser.isSome());
-    }
-
-    void assertSourceParserAndScriptCreated(BytecodeCompiler& info) {
-        assertSourceAndParserCreated(info);
-        MOZ_ASSERT(info.script != nullptr);
-    }
-
-    MOZ_MUST_USE bool emplaceEmitter(BytecodeCompiler& info, Maybe<BytecodeEmitter>& emitter,
-                                     SharedContext* sharedContext)
-    {
-        return info.emplaceEmitter(emitter, EitherParser(parser.ptr()), sharedContext);
-    }
-
-    MOZ_MUST_USE bool createSourceAndParser(BytecodeCompiler& compiler, 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(BytecodeCompiler& info) {
-        uint32_t toStringStart = 0;
-        uint32_t len = sourceBuffer_.length();
-        uint32_t toStringEnd = len;
-        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<Unit>
-{
-    using Base = SourceAwareCompiler<Unit>;
-
-  protected:
-    using Base::parser;
-    using Base::sourceBuffer_;
-
-    using Base::assertSourceParserAndScriptCreated;
-    using Base::emplaceEmitter;
-    using Base::handleParseFailure;
-
-    using typename Base::TokenStreamPosition;
-
-  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);
+    deoptimizeArgumentsInEnclosingScripts(JSContext* cx, JS::Handle<JSObject*> environment);
 };
 
 class MOZ_STACK_CLASS GlobalScriptInfo final
   : public BytecodeCompiler
 {
     GlobalSharedContext globalsc_;
 
   public:
-    GlobalScriptInfo(JSContext* cx, const ReadOnlyCompileOptions& options, ScopeKind scopeKind)
+    GlobalScriptInfo(JSContext* cx, const JS::ReadOnlyCompileOptions& options, ScopeKind scopeKind)
       : BytecodeCompiler(cx, options),
         globalsc_(cx, scopeKind, directives, options.extraWarningsOption)
     {
         MOZ_ASSERT(scopeKind == ScopeKind::Global || scopeKind == ScopeKind::NonSyntactic);
     }
 
     GlobalSharedContext* sharedContext() {
         return &globalsc_;
     }
 };
 
-template<typename Unit>
-static JSScript*
-CreateGlobalScript(GlobalScriptInfo& info, JS::SourceText<Unit>& srcBuf,
-                   ScriptSourceObject** sourceObjectOut = nullptr)
-{
-    AutoAssertReportedException assertException(info.context());
-
-    ScriptCompiler<Unit> compiler(srcBuf);
-    AutoInitializeSourceObject autoSSO(info, sourceObjectOut);
-
-    if (!compiler.prepareScriptParse(info)) {
-        return nullptr;
-    }
-
-    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_;
+    JS::Handle<JSObject*> environment_;
     EvalSharedContext evalsc_;
 
   public:
-    EvalScriptInfo(JSContext* cx, const ReadOnlyCompileOptions& options, HandleObject environment,
-                   HandleScope enclosingScope)
+    EvalScriptInfo(JSContext* cx, const JS::ReadOnlyCompileOptions& options,
+                   JS::Handle<JSObject*> environment, JS::Handle<Scope*> enclosingScope)
       : BytecodeCompiler(cx, options),
         environment_(environment),
         evalsc_(cx, environment_, enclosingScope, directives, options.extraWarningsOption)
     {}
 
     HandleObject environment() {
         return environment_;
     }
 
     EvalSharedContext* sharedContext() {
         return &evalsc_;
     }
 };
 
-template<typename Unit>
-class MOZ_STACK_CLASS EvalScriptCompiler final
-  : public ScriptCompiler<Unit>
-{
-    using Base = ScriptCompiler<Unit>;
-
-    using Base::compileScript;
-    using Base::prepareScriptParse;
-
-  public:
-    explicit EvalScriptCompiler(SourceText<Unit>& srcBuf)
-      : Base(srcBuf)
-    {}
-
-    JSScript* compile(EvalScriptInfo& info) {
-        if (!prepareScriptParse(info)) {
-            return nullptr;
-        }
-        return compileScript(info, info.environment(), info.sharedContext());
-    }
-};
-
 class MOZ_STACK_CLASS ModuleInfo final
   : public BytecodeCompiler
 {
   public:
-    ModuleInfo(JSContext* cx, const ReadOnlyCompileOptions& options)
+    ModuleInfo(JSContext* cx, const JS::ReadOnlyCompileOptions& options)
       : BytecodeCompiler(cx, options)
     {}
 };
 
-template<typename Unit>
-class MOZ_STACK_CLASS ModuleCompiler final
-  : public SourceAwareCompiler<Unit>
-{
-    using Base = SourceAwareCompiler<Unit>;
-
-    using Base::assertSourceParserAndScriptCreated;
-    using Base::createCompleteScript;
-    using Base::createSourceAndParser;
-    using Base::emplaceEmitter;
-    using Base::parser;
-
-  public:
-    explicit ModuleCompiler(SourceText<Unit>& srcBuf)
-      : Base(srcBuf)
-    {}
-
-    ModuleObject* compile(ModuleInfo& info);
-};
-
 class MOZ_STACK_CLASS StandaloneFunctionInfo final
   : public BytecodeCompiler
 {
   public:
-    StandaloneFunctionInfo(JSContext* cx, const ReadOnlyCompileOptions& options)
+    StandaloneFunctionInfo(JSContext* cx, const JS::ReadOnlyCompileOptions& options)
       : BytecodeCompiler(cx, options)
     {}
 };
 
-template<typename Unit>
-class MOZ_STACK_CLASS StandaloneFunctionCompiler final
-  : public SourceAwareCompiler<Unit>
-{
-    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(SourceText<Unit>& srcBuf)
-      : Base(srcBuf)
-    {}
-
-    MOZ_MUST_USE bool prepare(StandaloneFunctionInfo& info,
-                              const Maybe<uint32_t>& parameterListEnd)
-    {
-        return createSourceAndParser(info, ParseGoal::Script, parameterListEnd);
-    }
-
-    CodeNode* parse(StandaloneFunctionInfo& info, MutableHandleFunction fun,
-                    HandleScope enclosingScope, GeneratorKind generatorKind,
-                    FunctionAsyncKind asyncKind, const Maybe<uint32_t>& parameterListEnd);
-
-    MOZ_MUST_USE bool compile(StandaloneFunctionInfo& info, CodeNode* parsedFunction,
-                              MutableHandleFunction fun);
-
-  private:
-    // Create a script for a function with the given toString offsets in source
-    // text.
-    MOZ_MUST_USE bool createFunctionScript(StandaloneFunctionInfo& info,
-                                           uint32_t toStringStart, uint32_t toStringEnd)
-    {
-        return info.internalCreateScript(toStringStart, toStringEnd, sourceBuffer_.length());
-    }
-};
-
-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;
-    if (errorReporter.hasTokenizationStarted()) {
-        line = errorReporter.options().lineno;
-        column = errorReporter.options().column;
-    } else {
-        errorReporter.currentLineAndColumn(&line, &column);
-    }
-    frontendEvent_.emplace(TraceLogger_Frontend, errorReporter.getFilename(), line, column);
-    frontendLog_.emplace(logger_, *frontendEvent_);
-    typeLog_.emplace(logger_, id);
-}
-#else
-{ }
-#endif
-
-AutoFrontendTraceLog::AutoFrontendTraceLog(JSContext* cx, const TraceLoggerTextId id,
-                                           const ErrorReporter& errorReporter,
-                                           FunctionBox* funbox)
-#ifdef JS_TRACE_LOGGING
-  : logger_(TraceLoggerForCurrentThread(cx))
-{
-    frontendEvent_.emplace(TraceLogger_Frontend, errorReporter.getFilename(),
-                           funbox->startLine, funbox->startColumn);
-    frontendLog_.emplace(logger_, *frontendEvent_);
-    typeLog_.emplace(logger_, id);
-}
-#else
-{ }
-#endif
-
-AutoFrontendTraceLog::AutoFrontendTraceLog(JSContext* cx, const TraceLoggerTextId id,
-                                           const ErrorReporter& errorReporter, ParseNode* pn)
-#ifdef JS_TRACE_LOGGING
-  : logger_(TraceLoggerForCurrentThread(cx))
-{
-    uint32_t line, column;
-    errorReporter.lineAndColumnAt(pn->pn_pos.begin, &line, &column);
-    frontendEvent_.emplace(TraceLogger_Frontend, errorReporter.getFilename(), line, column);
-    frontendLog_.emplace(logger_, *frontendEvent_);
-    typeLog_.emplace(logger_, id);
-}
-#else
-{ }
-#endif
-
-BytecodeCompiler::BytecodeCompiler(JSContext* cx, const ReadOnlyCompileOptions& options)
-  : keepAtoms(cx),
-    cx(cx),
-    options(options),
-    sourceObject(cx),
-    directives(options.strictOption),
-    script(cx)
-{}
-
-bool
-BytecodeCompiler::createScriptSource(const Maybe<uint32_t>& parameterListEnd)
-{
-    sourceObject = CreateScriptSourceObject(cx, options, parameterListEnd);
-    if (!sourceObject) {
-        return false;
-    }
-
-    scriptSource = sourceObject->source();
-    return true;
-}
-
-template<typename Unit>
-bool
-BytecodeCompiler::assignSource(SourceText<Unit>& sourceBuffer)
-{
-    if (!cx->realm()->behaviors().discardSource()) {
-        if (options.sourceIsLazy) {
-            scriptSource->setSourceRetrievable();
-        } else if (!scriptSource->setSourceCopy(cx, sourceBuffer)) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-bool
-BytecodeCompiler::canLazilyParse() const
-{
-    return options.canLazilyParse &&
-           !cx->realm()->behaviors().disableLazyParsing() &&
-           !cx->realm()->behaviors().discardSource() &&
-           !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<Unit>::createSourceAndParser(BytecodeCompiler& info, ParseGoal goal,
-                                                 const Maybe<uint32_t>& parameterListEnd /* = Nothing() */)
-{
-    if (!info.createScriptSource(parameterListEnd)) {
-        return false;
-    }
-
-    if (!info.assignSource(sourceBuffer_)) {
-        return false;
-    }
-
-    info.createUsedNames();
-
-    if (info.canLazilyParse()) {
-        syntaxParser.emplace(info.cx, info.cx->tempLifoAlloc(), info.options,
-                             sourceBuffer_.units(), sourceBuffer_.length(),
-                             /* foldConstants = */ false, *info.usedNames, nullptr, nullptr,
-                             info.sourceObject, goal);
-        if (!syntaxParser->checkOptions()) {
-            return false;
-        }
-    }
-
-    parser.emplace(info.cx, info.cx->tempLifoAlloc(), info.options,
-                   sourceBuffer_.units(), sourceBuffer_.length(), /* foldConstants = */ true,
-                   *info.usedNames, syntaxParser.ptrOr(nullptr), nullptr, info.sourceObject, goal);
-    parser->ss = info.scriptSource;
-    return parser->checkOptions();
-}
-
-bool
-BytecodeCompiler::internalCreateScript(uint32_t toStringStart, uint32_t toStringEnd,
-                                       uint32_t sourceBufferLength)
-{
-    script = JSScript::Create(cx, options, sourceObject, /* sourceStart = */ 0, sourceBufferLength,
-                              toStringStart, toStringEnd);
-    return script != nullptr;
-}
-
-bool
-BytecodeCompiler::emplaceEmitter(Maybe<BytecodeEmitter>& emitter,
-                                 const EitherParser& parser, SharedContext* sharedContext)
-{
-    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<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;
-    }
-
-    parser->tokenStream.seek(startPosition);
-
-    // Assignment must be monotonic to prevent reparsing iloops
-    MOZ_ASSERT_IF(info.directives.strict(), newDirectives.strict());
-    MOZ_ASSERT_IF(info.directives.asmJS(), newDirectives.asmJS());
-    info.directives = newDirectives;
-    return true;
-}
-
-bool
-BytecodeCompiler::deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment)
-{
-    RootedObject env(cx, environment);
-    while (env->is<EnvironmentObject>() || env->is<DebugEnvironmentProxy>()) {
-        if (env->is<CallObject>()) {
-            RootedFunction fun(cx, &env->as<CallObject>().callee());
-            RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun));
-            if (!script) {
-                return false;
-            }
-            if (script->argumentsHasVarBinding()) {
-                if (!JSScript::argumentsOptimizationFailed(cx, script)) {
-                    return false;
-                }
-            }
-        }
-        env = env->enclosingEnvironment();
-    }
-
-    return true;
-}
-
-template<typename Unit>
-JSScript*
-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;
-    }
-
-    JSContext* cx = info.cx;
-
-    for (;;) {
-        ParseNode* pn;
-        {
-            AutoGeckoProfilerEntry pseudoFrame(cx, "script parsing");
-            if (sc->isEvalContext()) {
-                pn = parser->evalBody(sc->asEvalContext());
-            } else {
-                pn = parser->globalBody(sc->asGlobalContext());
-            }
-        }
-
-        // Successfully parsed. Emit the script.
-        AutoGeckoProfilerEntry pseudoFrame(cx, "script emit");
-        if (pn) {
-            if (sc->isEvalContext() && sc->hasDebuggerStatement() && !cx->helperThread()) {
-                // If the eval'ed script contains any debugger statement, force construction
-                // of arguments objects for the caller script and any other scripts it is
-                // transitively nested inside. The debugger can access any variable on the
-                // scope chain.
-                if (!info.deoptimizeArgumentsInEnclosingScripts(cx, environment)) {
-                    return nullptr;
-                }
-            }
-            if (!emitter->emitScript(pn)) {
-                return nullptr;
-            }
-            break;
-        }
-
-        // Maybe we aborted a syntax parse. See if we can try again.
-        if (!handleParseFailure(info, info.directives, startPosition)) {
-            return nullptr;
-        }
-
-        // Reset UsedNameTracker state before trying again.
-        info.usedNames->reset();
-    }
-
-    // We have just finished parsing the source. Inform the source so that we
-    // can compute statistics (e.g. how much time our functions remain lazy).
-    info.script->scriptSource()->recordParseEnded();
-
-    // Enqueue an off-thread source compression task after finishing parsing.
-    if (!info.scriptSource->tryCompressOffThread(cx)) {
-        return nullptr;
-    }
-
-    MOZ_ASSERT_IF(!cx->helperThread(), !cx->isExceptionPending());
-
-    return info.script;
-}
-
-template<typename Unit>
-ModuleObject*
-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));
-    if (!module) {
-        return nullptr;
-    }
-
-    module->init(info.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(info, emitter, &modulesc)) {
-        return nullptr;
-    }
-    if (!emitter->emitScript(pn->as<CodeNode>().body())) {
-        return nullptr;
-    }
-
-    if (!builder.initModule()) {
-        return nullptr;
-    }
-
-    RootedModuleEnvironmentObject env(cx, ModuleEnvironmentObject::create(cx, module));
-    if (!env) {
-        return nullptr;
-    }
-
-    module->setInitialEnvironment(env);
-
-    // Enqueue an off-thread source compression task after finishing parsing.
-    if (!info.scriptSource->tryCompressOffThread(cx)) {
-        return nullptr;
-    }
-
-    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<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);
-
-    // Speculatively parse using the default directives implied by the context.
-    // If a directive is encountered (e.g., "use strict") that changes how the
-    // function should have been parsed, we backup and reparse with the new set
-    // of directives.
-
-    ParseNode* fn;
-    do {
-        Directives newDirectives = info.directives;
-        fn = parser->standaloneFunction(fun, enclosingScope, parameterListEnd, generatorKind,
-                                        asyncKind, info.directives, &newDirectives);
-        if (!fn && !handleParseFailure(info, newDirectives, startPosition)) {
-            return nullptr;
-        }
-    } while (!fn);
-
-    return &fn->as<CodeNode>();
-}
-
-// Compile a standalone JS function.
-template<typename Unit>
-bool
-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;
-        }
-
-        Maybe<BytecodeEmitter> emitter;
-        if (!emplaceEmitter(info, emitter, funbox)) {
-            return false;
-        }
-        if (!emitter->emitFunctionScript(parsedFunction, BytecodeEmitter::TopLevelFunction::Yes)) {
-            return false;
-        }
-    } else {
-        fun.set(funbox->function());
-        MOZ_ASSERT(IsAsmJSModule(fun));
-    }
-
-    // Enqueue an off-thread source compression task after finishing parsing.
-    return info.scriptSource->tryCompressOffThread(info.cx);
-}
-
-ScriptSourceObject*
-frontend::CreateScriptSourceObject(JSContext* cx, const ReadOnlyCompileOptions& options,
-                                   const Maybe<uint32_t>& parameterListEnd /* = Nothing() */)
-{
-    ScriptSource* ss = cx->new_<ScriptSource>();
-    if (!ss) {
-        return nullptr;
-    }
-    ScriptSourceHolder ssHolder(ss);
-
-    if (!ss->initFromOptions(cx, options, parameterListEnd)) {
-        return nullptr;
-    }
-
-    RootedScriptSourceObject sso(cx, ScriptSourceObject::create(cx, ss));
-    if (!sso) {
-        return nullptr;
-    }
-
-    // Off-thread compilations do all their GC heap allocation, including the
-    // SSO, in a temporary compartment. Hence, for the SSO to refer to the
-    // gc-heap-allocated values in |options|, it would need cross-compartment
-    // wrappers from the temporary compartment to the real compartment --- which
-    // would then be inappropriate once we merged the temporary and real
-    // compartments.
-    //
-    // Instead, we put off populating those SSO slots in off-thread compilations
-    // until after we've merged compartments.
-    if (!cx->helperThread()) {
-        if (!ScriptSourceObject::initFromOptions(cx, sso, options)) {
-            return nullptr;
-        }
-    }
+} // namespace frontend
 
-    return sso;
-}
-
-JSScript*
-frontend::CompileGlobalScript(JSContext* cx, ScopeKind scopeKind,
-                              const ReadOnlyCompileOptions& options,
-                              SourceText<char16_t>& srcBuf,
-                              ScriptSourceObject** sourceObjectOut)
-{
-    MOZ_ASSERT(scopeKind == ScopeKind::Global || scopeKind == ScopeKind::NonSyntactic);
-
-    GlobalScriptInfo info(cx, options, scopeKind);
-    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)
-{
-    AutoAssertReportedException assertException(cx);
-
-    frontend::UsedNameTracker usedNames(cx);
-
-    RootedScriptSourceObject sourceObj(cx, CreateScriptSourceObject(cx, options));
-
-    if (!sourceObj) {
-        return nullptr;
-    }
-
-    if (!sourceObj->source()->setBinASTSourceCopy(cx, src, len)) {
-        return nullptr;
-    }
-
-    RootedScript script(cx, JSScript::Create(cx, options, sourceObj, 0, len, 0, len));
-
-    if (!script) {
-        return nullptr;
-    }
-
-    Directives directives(options.strictOption);
-    GlobalSharedContext globalsc(cx, ScopeKind::Global, directives, options.extraWarningsOption);
-
-    frontend::BinASTParser<BinTokenReaderMultipart> parser(cx, alloc, usedNames, options, sourceObj);
-
-    // Metadata stores internal pointers, so we must use the same buffer every time, including for lazy parses
-    ScriptSource* ss = sourceObj->source();
-    BinASTSourceMetadata* metadata = nullptr;
-    auto parsed = parser.parse(&globalsc, ss->binASTSource(), ss->length(), &metadata);
-
-    if (parsed.isErr()) {
-        return nullptr;
-    }
-
-    sourceObj->source()->setBinASTSourceMetadata(metadata);
-
-    BytecodeEmitter bce(nullptr, &parser, &globalsc, script, nullptr, 0);
-
-    if (!bce.init()) {
-        return nullptr;
-    }
-
-    ParseNode *pn = parsed.unwrap();
-    if (!bce.emitScript(pn)) {
-        return nullptr;
-    }
-
-    if (sourceObjectOut) {
-        *sourceObjectOut = sourceObj;
-    }
-
-    assertException.reset();
-    return script;
-}
-
-#endif // JS_BUILD_BINAST
-
-JSScript*
-frontend::CompileEvalScript(JSContext* cx, HandleObject environment,
-                            HandleScope enclosingScope,
-                            const ReadOnlyCompileOptions& options,
-                            SourceText<char16_t>& srcBuf,
-                            ScriptSourceObject** sourceObjectOut)
-{
-    AutoAssertReportedException assertException(cx);
-
-    EvalScriptInfo info(cx, options, environment, enclosingScope);
-    AutoInitializeSourceObject autoSSO(info, sourceObjectOut);
-
-    EvalScriptCompiler<char16_t> compiler(srcBuf);
-    JSScript* script = compiler.compile(info);
-    if (!script) {
-        return nullptr;
-    }
-
-    assertException.reset();
-    return script;
-
-}
-
-ModuleObject*
-frontend::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& optionsInput,
-                        SourceText<char16_t>& srcBuf,
-                        ScriptSourceObject** sourceObjectOut)
-{
-    MOZ_ASSERT(srcBuf.get());
-    MOZ_ASSERT_IF(sourceObjectOut, *sourceObjectOut == nullptr);
-
-    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;
-
-    ModuleInfo info(cx, options);
-    AutoInitializeSourceObject autoSSO(info, sourceObjectOut);
-
-    ModuleCompiler<char16_t> compiler(srcBuf);
-    ModuleObject* module = compiler.compile(info);
-    if (!module) {
-        return nullptr;
-    }
-
-    assertException.reset();
-    return module;
-}
-
-ModuleObject*
-frontend::CompileModule(JSContext* cx, const JS::ReadOnlyCompileOptions& options,
-                        SourceText<char16_t>& srcBuf)
-{
-    AutoAssertReportedException assertException(cx);
-
-    if (!GlobalObject::ensureModulePrototypesCreated(cx, cx->global())) {
-        return nullptr;
-    }
-
-    RootedModuleObject module(cx, CompileModule(cx, options, srcBuf, nullptr));
-    if (!module) {
-        return nullptr;
-    }
-
-    // This happens in GlobalHelperThreadState::finishModuleParseTask() when a
-    // module is compiled off thread.
-    if (!ModuleObject::Freeze(cx, module)) {
-        return nullptr;
-    }
-
-    assertException.reset();
-    return module;
-}
-
-// When leaving this scope, the given function should either:
-//   * be linked to a fully compiled script
-//   * remain linking to a lazy script
-class MOZ_STACK_CLASS AutoAssertFunctionDelazificationCompletion
-{
-#ifdef DEBUG
-    RootedFunction fun_;
-#endif
-
-  public:
-    AutoAssertFunctionDelazificationCompletion(JSContext* cx, HandleFunction fun)
-#ifdef DEBUG
-      : fun_(cx, fun)
-#endif
-    {
-        MOZ_ASSERT(fun_->isInterpretedLazy());
-        MOZ_ASSERT(!fun_->lazyScript()->hasScript());
-    }
-
-    ~AutoAssertFunctionDelazificationCompletion() {
-#ifdef DEBUG
-        if (!fun_) {
-            return;
-        }
-#endif
-
-        // If fun_ is not nullptr, it means delazification doesn't complete.
-        // Assert that the function keeps linking to lazy script
-        MOZ_ASSERT(fun_->isInterpretedLazy());
-        MOZ_ASSERT(!fun_->lazyScript()->hasScript());
-    }
-
-    void complete() {
-        // Assert the completion of delazification and forget the function.
-        MOZ_ASSERT(fun_->hasScript());
-        MOZ_ASSERT(!fun_->hasUncompletedScript());
-
-#ifdef DEBUG
-        fun_ = nullptr;
-#endif
-    }
-};
-
-bool
-frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length)
-{
-    MOZ_ASSERT(cx->compartment() == lazy->functionNonDelazifying()->compartment());
-
-    // We can only compile functions whose parents have previously been
-    // compiled, because compilation requires full information about the
-    // function's immediately enclosing scope.
-    MOZ_ASSERT(lazy->enclosingScriptHasEverBeenCompiled());
-
-    MOZ_ASSERT(!lazy->isBinAST());
-
-    AutoAssertReportedException assertException(cx);
-    Rooted<JSFunction*> fun(cx, lazy->functionNonDelazifying());
-    AutoAssertFunctionDelazificationCompletion delazificationCompletion(cx, fun);
-
-    JS::CompileOptions options(cx);
-    options.setMutedErrors(lazy->mutedErrors())
-           .setFileAndLine(lazy->filename(), lazy->lineno())
-           .setColumn(lazy->column())
-           .setScriptSourceOffset(lazy->sourceStart())
-           .setNoScriptRval(false)
-           .setSelfHostingMode(false);
-
-    // Update statistics to find out if we are delazifying just after having
-    // lazified. Note that we are interested in the delta between end of
-    // syntax parsing and start of full parsing, so we do this now rather than
-    // after parsing below.
-    if (!lazy->scriptSource()->parseEnded().IsNull()) {
-        const mozilla::TimeDuration delta = ReallyNow() -
-            lazy->scriptSource()->parseEnded();
+} // namespace js
 
-        // Differentiate between web-facing and privileged code, to aid
-        // with optimization. Due to the number of calls to this function,
-        // we use `cx->runningWithTrustedPrincipals`, which is fast but
-        // will classify addons alongside with web-facing code.
-        const int HISTOGRAM = cx->runningWithTrustedPrincipals()
-            ? JS_TELEMETRY_PRIVILEGED_PARSER_COMPILE_LAZY_AFTER_MS
-            : JS_TELEMETRY_WEB_PARSER_COMPILE_LAZY_AFTER_MS;
-        cx->runtime()->addTelemetry(HISTOGRAM, delta.ToMilliseconds());
-    }
-
-    UsedNameTracker usedNames(cx);
-
-    RootedScriptSourceObject sourceObject(cx, &lazy->sourceObject());
-    Parser<FullParseHandler, char16_t> parser(cx, cx->tempLifoAlloc(), options, chars, length,
-                                              /* foldConstants = */ true, usedNames, nullptr,
-                                              lazy, sourceObject, lazy->parseGoal());
-    if (!parser.checkOptions()) {
-        return false;
-    }
-
-    ParseNode* pn = parser.standaloneLazyFunction(fun, lazy->toStringStart(),
-                                                  lazy->strict(), lazy->generatorKind(),
-                                                  lazy->asyncKind());
-    if (!pn) {
-        return false;
-    }
-
-    Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
-                                                  lazy->sourceStart(), lazy->sourceEnd(),
-                                                  lazy->toStringStart(), lazy->toStringEnd()));
-    if (!script) {
-        return false;
-    }
-
-    if (lazy->isLikelyConstructorWrapper()) {
-        script->setLikelyConstructorWrapper();
-    }
-    if (lazy->hasBeenCloned()) {
-        script->setHasBeenCloned();
-    }
-
-    BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->as<CodeNode>().funbox(), script, lazy,
-                        pn->pn_pos, BytecodeEmitter::LazyFunction);
-    if (!bce.init()) {
-        return false;
-    }
-
-    if (!bce.emitFunctionScript(&pn->as<CodeNode>(), BytecodeEmitter::TopLevelFunction::Yes)) {
-        return false;
-    }
-
-    delazificationCompletion.complete();
-    assertException.reset();
-    return true;
-}
-
-#ifdef JS_BUILD_BINAST
-
-bool
-frontend::CompileLazyBinASTFunction(JSContext* cx, Handle<LazyScript*> lazy, const uint8_t* buf, size_t length)
-{
-    MOZ_ASSERT(cx->compartment() == lazy->functionNonDelazifying()->compartment());
-
-    // We can only compile functions whose parents have previously been
-    // compiled, because compilation requires full information about the
-    // function's immediately enclosing scope.
-    MOZ_ASSERT(lazy->enclosingScriptHasEverBeenCompiled());
-    MOZ_ASSERT(lazy->isBinAST());
-
-    AutoAssertReportedException assertException(cx);
-    Rooted<JSFunction*> fun(cx, lazy->functionNonDelazifying());
-    AutoAssertFunctionDelazificationCompletion delazificationCompletion(cx, fun);
-
-    CompileOptions options(cx);
-    options.setMutedErrors(lazy->mutedErrors())
-           .setFileAndLine(lazy->filename(), lazy->lineno())
-           .setColumn(lazy->column())
-           .setScriptSourceOffset(lazy->sourceStart())
-           .setNoScriptRval(false)
-           .setSelfHostingMode(false);
-
-    UsedNameTracker usedNames(cx);
-
-    RootedScriptSourceObject sourceObj(cx, &lazy->sourceObject());
-    MOZ_ASSERT(sourceObj);
-
-    RootedScript script(cx, JSScript::Create(cx, options, sourceObj, lazy->sourceStart(), lazy->sourceEnd(),
-                                             lazy->sourceStart(), lazy->sourceEnd()));
-
-    if (!script) {
-        return false;
-    }
-
-    if (lazy->hasBeenCloned()) {
-        script->setHasBeenCloned();
-    }
-
-    frontend::BinASTParser<BinTokenReaderMultipart> parser(cx, cx->tempLifoAlloc(),
-                                                           usedNames, options, sourceObj,
-                                                           lazy);
-
-    auto parsed = parser.parseLazyFunction(lazy->scriptSource(), lazy->sourceStart());
-
-    if (parsed.isErr()) {
-        return false;
-    }
-
-    ParseNode *pn = parsed.unwrap();
-
-    BytecodeEmitter bce(nullptr, &parser, pn->as<CodeNode>().funbox(), script,
-                        lazy, pn->pn_pos, BytecodeEmitter::LazyFunction);
-
-    if (!bce.init()) {
-        return false;
-    }
-
-    if (!bce.emitFunctionScript(&pn->as<CodeNode>(), BytecodeEmitter::TopLevelFunction::Yes)) {
-        return false;
-    }
-
-    delazificationCompletion.complete();
-    assertException.reset();
-    return script;
-}
-
-#endif // JS_BUILD_BINAST
-
-bool
-frontend::CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
-                                    const JS::ReadOnlyCompileOptions& options,
-                                    JS::SourceText<char16_t>& srcBuf,
-                                    const Maybe<uint32_t>& parameterListEnd,
-                                    HandleScope enclosingScope /* = nullptr */)
-{
-    AutoAssertReportedException assertException(cx);
-
-    StandaloneFunctionInfo info(cx, options);
-
-    StandaloneFunctionCompiler<char16_t> compiler(srcBuf);
-    if (!compiler.prepare(info, parameterListEnd)) {
-        return false;
-    }
-
-    RootedScope scope(cx, enclosingScope);
-    if (!scope) {
-        scope = &cx->global()->emptyGlobalScope();
-    }
-
-    CodeNode* parsedFunction = compiler.parse(info ,fun, scope, GeneratorKind::NotGenerator,
-                                              FunctionAsyncKind::SyncFunction, parameterListEnd);
-    if (!parsedFunction || !compiler.compile(info, parsedFunction, fun)) {
-        return false;
-    }
-
-    assertException.reset();
-    return true;
-}
-
-bool
-frontend::CompileStandaloneGenerator(JSContext* cx, MutableHandleFunction fun,
-                                     const JS::ReadOnlyCompileOptions& options,
-                                     JS::SourceText<char16_t>& srcBuf,
-                                     const Maybe<uint32_t>& parameterListEnd)
-{
-    AutoAssertReportedException assertException(cx);
-
-    StandaloneFunctionInfo info(cx, options);
-
-    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);
-    if (!parsedFunction || !compiler.compile(info, parsedFunction, fun)) {
-        return false;
-    }
-
-    assertException.reset();
-    return true;
-}
-
-bool
-frontend::CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
-                                         const ReadOnlyCompileOptions& options,
-                                         JS::SourceText<char16_t>& srcBuf,
-                                         const Maybe<uint32_t>& parameterListEnd)
-{
-    AutoAssertReportedException assertException(cx);
-
-    StandaloneFunctionInfo info(cx, options);
-
-    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);
-    if (!parsedFunction || !compiler.compile(info, parsedFunction, fun)) {
-        return false;
-    }
-
-    assertException.reset();
-    return true;
-}
-
-bool
-frontend::CompileStandaloneAsyncGenerator(JSContext* cx, MutableHandleFunction fun,
-                                          const ReadOnlyCompileOptions& options,
-                                          JS::SourceText<char16_t>& srcBuf,
-                                          const Maybe<uint32_t>& parameterListEnd)
-{
-    AutoAssertReportedException assertException(cx);
-
-    StandaloneFunctionInfo info(cx, options);
-
-    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);
-    if (!parsedFunction || !compiler.compile(info, parsedFunction, fun)) {
-        return false;
-    }
-
-    assertException.reset();
-    return true;
-}
+#endif // frontend_BytecodeCompilation_h
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -9,16 +9,17 @@
 #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/BytecodeCompilation.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/EitherParser.h"
 #include "frontend/ErrorReporter.h"
 #include "frontend/FoldConstants.h"
 #include "frontend/Parser.h"
 #include "js/SourceText.h"
 #include "vm/GlobalObject.h"
 #include "vm/JSContext.h"
@@ -35,23 +36,16 @@ 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
@@ -68,94 +62,23 @@ class MOZ_STACK_CLASS AutoInitializeSour
 
   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;
-    const ReadOnlyCompileOptions& options;
-
-    RootedScriptSourceObject sourceObject;
-    ScriptSource* scriptSource = nullptr;
-
-    Maybe<UsedNameTracker> usedNames;
-
-    Directives directives;
-
-    RootedScript script;
-
-  protected:
-    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();
+    inline ~AutoInitializeSourceObject() {
+        if (sourceObjectOut_) {
+            *sourceObjectOut_ = compiler_.sourceObjectPtr();
+        }
     }
-
-  protected:
-    void assertSourceCreated() const {
-        MOZ_ASSERT(sourceObject != nullptr);
-        MOZ_ASSERT(scriptSource != nullptr);
-    }
-
-    MOZ_MUST_USE bool createScriptSource(const Maybe<uint32_t>& parameterListEnd);
-
-    void createUsedNames() {
-        usedNames.emplace(cx);
-    }
-
-    // Create a script for source of the given length, using the explicitly-
-    // provided toString offsets as the created script's offsets in the source.
-    MOZ_MUST_USE bool internalCreateScript(uint32_t toStringStart, uint32_t toStringEnd,
-                                           uint32_t sourceBufferLength);
-
-    MOZ_MUST_USE bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter,
-                                     const EitherParser& parser, SharedContext* sharedContext);
-
-    // This function lives here, not in SourceAwareCompiler, because it mostly
-    // uses fields in *this* class.
-    template<typename Unit>
-    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_;
 
@@ -185,17 +108,17 @@ class MOZ_RAII AutoAssertReportedExcepti
 #else
   public:
     explicit AutoAssertReportedException(JSContext*) {}
     void reset() {}
 #endif
 };
 
 template<typename Unit>
-class MOZ_STACK_CLASS SourceAwareCompiler
+class MOZ_STACK_CLASS frontend::SourceAwareCompiler
 {
   protected:
     SourceText<Unit>& sourceBuffer_;
 
     Maybe<Parser<SyntaxParseHandler, Unit>> syntaxParser;
     Maybe<Parser<FullParseHandler, Unit>> parser;
 
     using TokenStreamPosition = frontend::TokenStreamPosition<Unit>;
@@ -243,17 +166,17 @@ class MOZ_STACK_CLASS SourceAwareCompile
     }
 
     MOZ_MUST_USE bool
     handleParseFailure(BytecodeCompiler& compiler, const Directives& newDirectives,
                        TokenStreamPosition& startPosition);
 };
 
 template<typename Unit>
-class MOZ_STACK_CLASS ScriptCompiler
+class MOZ_STACK_CLASS frontend::ScriptCompiler
   : public SourceAwareCompiler<Unit>
 {
     using Base = SourceAwareCompiler<Unit>;
 
   protected:
     using Base::parser;
     using Base::sourceBuffer_;
 
@@ -271,80 +194,39 @@ class MOZ_STACK_CLASS ScriptCompiler
     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
-{
-    GlobalSharedContext globalsc_;
-
-  public:
-    GlobalScriptInfo(JSContext* cx, const ReadOnlyCompileOptions& options, ScopeKind scopeKind)
-      : BytecodeCompiler(cx, options),
-        globalsc_(cx, scopeKind, directives, options.extraWarningsOption)
-    {
-        MOZ_ASSERT(scopeKind == ScopeKind::Global || scopeKind == ScopeKind::NonSyntactic);
-    }
-
-    GlobalSharedContext* sharedContext() {
-        return &globalsc_;
-    }
-};
-
 template<typename Unit>
 static JSScript*
 CreateGlobalScript(GlobalScriptInfo& info, JS::SourceText<Unit>& srcBuf,
                    ScriptSourceObject** sourceObjectOut = nullptr)
 {
     AutoAssertReportedException assertException(info.context());
 
-    ScriptCompiler<Unit> compiler(srcBuf);
+    frontend::ScriptCompiler<Unit> compiler(srcBuf);
     AutoInitializeSourceObject autoSSO(info, sourceObjectOut);
 
     if (!compiler.prepareScriptParse(info)) {
         return nullptr;
     }
 
     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:
-    EvalScriptInfo(JSContext* cx, const ReadOnlyCompileOptions& options, HandleObject environment,
-                   HandleScope enclosingScope)
-      : BytecodeCompiler(cx, options),
-        environment_(environment),
-        evalsc_(cx, environment_, enclosingScope, directives, options.extraWarningsOption)
-    {}
-
-    HandleObject environment() {
-        return environment_;
-    }
-
-    EvalSharedContext* sharedContext() {
-        return &evalsc_;
-    }
-};
-
 template<typename Unit>
 class MOZ_STACK_CLASS EvalScriptCompiler final
   : public ScriptCompiler<Unit>
 {
     using Base = ScriptCompiler<Unit>;
 
     using Base::compileScript;
     using Base::prepareScriptParse;
@@ -357,27 +239,18 @@ class MOZ_STACK_CLASS EvalScriptCompiler
     JSScript* compile(EvalScriptInfo& info) {
         if (!prepareScriptParse(info)) {
             return nullptr;
         }
         return compileScript(info, info.environment(), info.sharedContext());
     }
 };
 
-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
+class MOZ_STACK_CLASS frontend::ModuleCompiler final
   : public SourceAwareCompiler<Unit>
 {
     using Base = SourceAwareCompiler<Unit>;
 
     using Base::assertSourceParserAndScriptCreated;
     using Base::createCompleteScript;
     using Base::createSourceAndParser;
     using Base::emplaceEmitter;
@@ -386,27 +259,18 @@ class MOZ_STACK_CLASS ModuleCompiler fin
   public:
     explicit ModuleCompiler(SourceText<Unit>& srcBuf)
       : Base(srcBuf)
     {}
 
     ModuleObject* compile(ModuleInfo& info);
 };
 
-class MOZ_STACK_CLASS StandaloneFunctionInfo final
-  : public BytecodeCompiler
-{
-  public:
-    StandaloneFunctionInfo(JSContext* cx, const ReadOnlyCompileOptions& options)
-      : BytecodeCompiler(cx, options)
-    {}
-};
-
 template<typename Unit>
-class MOZ_STACK_CLASS StandaloneFunctionCompiler final
+class MOZ_STACK_CLASS frontend::StandaloneFunctionCompiler final
   : public SourceAwareCompiler<Unit>
 {
     using Base = SourceAwareCompiler<Unit>;
 
     using Base::assertSourceAndParserCreated;
     using Base::createSourceAndParser;
     using Base::emplaceEmitter;
     using Base::handleParseFailure;
@@ -542,18 +406,18 @@ BytecodeCompiler::canLazilyParse() const
            // 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<Unit>::createSourceAndParser(BytecodeCompiler& info, ParseGoal goal,
-                                                 const Maybe<uint32_t>& parameterListEnd /* = Nothing() */)
+frontend::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;
     }
@@ -594,19 +458,19 @@ BytecodeCompiler::emplaceEmitter(Maybe<B
         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<Unit>::handleParseFailure(BytecodeCompiler& info,
-                                              const Directives& newDirectives,
-                                              TokenStreamPosition& startPosition)
+frontend::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;
@@ -641,18 +505,18 @@ BytecodeCompiler::deoptimizeArgumentsInE
         env = env->enclosingEnvironment();
     }
 
     return true;
 }
 
 template<typename Unit>
 JSScript*
-ScriptCompiler<Unit>::compileScript(BytecodeCompiler& info, HandleObject environment,
-                                    SharedContext* sc)
+frontend::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;
@@ -709,17 +573,17 @@ ScriptCompiler<Unit>::compileScript(Byte
 
     MOZ_ASSERT_IF(!cx->helperThread(), !cx->isExceptionPending());
 
     return info.script;
 }
 
 template<typename Unit>
 ModuleObject*
-ModuleCompiler<Unit>::compile(ModuleInfo& info)
+frontend::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));
@@ -766,20 +630,22 @@ ModuleCompiler<Unit>::compile(ModuleInfo
     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<Unit>::parse(StandaloneFunctionInfo& info, MutableHandleFunction fun,
-                                        HandleScope enclosingScope, GeneratorKind generatorKind,
-                                        FunctionAsyncKind asyncKind,
-                                        const Maybe<uint32_t>& parameterListEnd)
+frontend::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);
 
@@ -799,18 +665,19 @@ StandaloneFunctionCompiler<Unit>::parse(
     } while (!fn);
 
     return &fn->as<CodeNode>();
 }
 
 // Compile a standalone JS function.
 template<typename Unit>
 bool
-StandaloneFunctionCompiler<Unit>::compile(StandaloneFunctionInfo& info, CodeNode* parsedFunction,
-                                          MutableHandleFunction fun)
+frontend::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;
         }