tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

BytecodeCompiler.cpp (63464B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "frontend/BytecodeCompiler.h"
      8 
      9 #include "mozilla/Attributes.h"
     10 #include "mozilla/Maybe.h"
     11 #include "mozilla/Utf8.h"     // mozilla::Utf8Unit
     12 #include "mozilla/Variant.h"  // mozilla::Variant
     13 
     14 #include "debugger/DebugAPI.h"
     15 #include "ds/LifoAlloc.h"
     16 #include "frontend/BytecodeEmitter.h"
     17 #include "frontend/CompilationStencil.h"  // ExtensibleCompilationStencil, ExtraBindingInfoVector, CompilationInput, CompilationGCOutput
     18 #include "frontend/EitherParser.h"
     19 #include "frontend/FrontendContext.h"  // AutoReportFrontendContext
     20 #include "frontend/ModuleSharedContext.h"
     21 #include "frontend/ParserAtom.h"     // ParserAtomsTable, TaggedParserAtomIndex
     22 #include "frontend/SharedContext.h"  // SharedContext, GlobalSharedContext
     23 #include "frontend/Stencil.h"        // ParserBindingIter
     24 #include "frontend/UsedNameTracker.h"  // UsedNameTracker, UsedNameMap
     25 #include "js/AllocPolicy.h"        // js::SystemAllocPolicy, ReportOutOfMemory
     26 #include "js/CharacterEncoding.h"  // JS_EncodeStringToUTF8
     27 #include "js/ColumnNumber.h"       // JS::ColumnNumberOneOrigin
     28 #include "js/EnvironmentChain.h"   // JS::SupportUnscopables
     29 #include "js/ErrorReport.h"        // JS_ReportErrorASCII
     30 #include "js/experimental/CompileScript.h"  // JS::CompileGlobalScriptToStencil, JS::CompileModuleScriptToStencil
     31 #include "js/experimental/JSStencil.h"
     32 #include "js/GCVector.h"    // JS::StackGCVector
     33 #include "js/Id.h"          // JS::PropertyKey
     34 #include "js/Modules.h"     // JS::ImportAssertionVector
     35 #include "js/RootingAPI.h"  // JS::Handle, JS::MutableHandle
     36 #include "js/SourceText.h"  // JS::SourceText
     37 #include "js/UniquePtr.h"
     38 #include "js/Utility.h"                // UniqueChars
     39 #include "js/Value.h"                  // JS::Value
     40 #include "vm/EnvironmentObject.h"      // WithEnvironmentObject
     41 #include "vm/FunctionFlags.h"          // FunctionFlags
     42 #include "vm/GeneratorAndAsyncKind.h"  // js::GeneratorKind, js::FunctionAsyncKind
     43 #include "vm/HelperThreads.h"  // StartOffThreadDelazification, WaitForAllDelazifyTasks
     44 #include "vm/JSContext.h"      // JSContext
     45 #include "vm/JSObject.h"       // SetIntegrityLevel, IntegrityLevel
     46 #include "vm/JSScript.h"       // ScriptSource, UncompressedSourceCache
     47 #include "vm/ModuleBuilder.h"  // js::ModuleBuilder
     48 #include "vm/NativeObject.h"   // NativeDefineDataProperty
     49 #include "vm/PlainObject.h"    // NewPlainObjectWithProto
     50 #include "vm/Time.h"           // AutoIncrementalTimer
     51 #include "wasm/AsmJS.h"
     52 
     53 #include "vm/Compartment-inl.h"  // JS::Compartment::wrap
     54 #include "vm/GeckoProfiler-inl.h"
     55 #include "vm/JSContext-inl.h"
     56 #include "vm/JSObject-inl.h"  // JSObject::maybeHasInterestingSymbolProperty for ObjectOperations-inl.h
     57 #include "vm/ObjectOperations-inl.h"  // HasProperty
     58 
     59 using namespace js;
     60 using namespace js::frontend;
     61 
     62 using mozilla::Maybe;
     63 using mozilla::Utf8Unit;
     64 
     65 using JS::CompileOptions;
     66 using JS::ReadOnlyCompileOptions;
     67 using JS::SourceText;
     68 
     69 // RAII class to check the frontend reports an exception when it fails to
     70 // compile a script.
     71 class MOZ_RAII AutoAssertReportedException {
     72 #ifdef DEBUG
     73  JSContext* maybeCx_;
     74  FrontendContext* fc_;
     75  bool check_;
     76 
     77 public:
     78  explicit AutoAssertReportedException(JSContext* maybeCx, FrontendContext* fc)
     79      : maybeCx_(maybeCx), fc_(fc), check_(true) {}
     80  void reset() { check_ = false; }
     81  ~AutoAssertReportedException() {
     82    if (!check_) {
     83      return;
     84    }
     85 
     86    // Error while compiling self-hosted code isn't set as an exception.
     87    // TODO: Remove this once all errors are added to frontend context.
     88    if (maybeCx_ && !maybeCx_->runtime()->hasInitializedSelfHosting()) {
     89      return;
     90    }
     91 
     92    // TODO: Remove this once JSContext is removed from frontend.
     93    if (maybeCx_) {
     94      MOZ_ASSERT(maybeCx_->isExceptionPending() || fc_->hadErrors());
     95    } else {
     96      MOZ_ASSERT(fc_->hadErrors());
     97    }
     98  }
     99 #else
    100 public:
    101  explicit AutoAssertReportedException(JSContext*, FrontendContext*) {}
    102  void reset() {}
    103 #endif
    104 };
    105 
    106 static bool EmplaceEmitter(CompilationState& compilationState,
    107                           Maybe<BytecodeEmitter>& emitter, FrontendContext* fc,
    108                           const EitherParser& parser, SharedContext* sc);
    109 
    110 template <typename Unit>
    111 class MOZ_STACK_CLASS SourceAwareCompiler {
    112 protected:
    113  SourceText<Unit>& sourceBuffer_;
    114 
    115  CompilationState compilationState_;
    116 
    117  Maybe<Parser<SyntaxParseHandler, Unit>> syntaxParser;
    118  Maybe<Parser<FullParseHandler, Unit>> parser;
    119  FrontendContext* fc_ = nullptr;
    120 
    121  using TokenStreamPosition = frontend::TokenStreamPosition<Unit>;
    122 
    123 protected:
    124  explicit SourceAwareCompiler(FrontendContext* fc,
    125                               LifoAllocScope& parserAllocScope,
    126                               CompilationInput& input,
    127                               SourceText<Unit>& sourceBuffer)
    128      : sourceBuffer_(sourceBuffer),
    129        compilationState_(fc, parserAllocScope, input) {
    130    MOZ_ASSERT(sourceBuffer_.get() != nullptr);
    131  }
    132 
    133  [[nodiscard]] bool init(FrontendContext* fc, ScopeBindingCache* scopeCache,
    134                          InheritThis inheritThis = InheritThis::No,
    135                          JSObject* enclosingEnv = nullptr) {
    136    if (!compilationState_.init(fc, scopeCache, inheritThis, enclosingEnv)) {
    137      return false;
    138    }
    139 
    140    return createSourceAndParser(fc);
    141  }
    142 
    143  // Call this before calling compile{Global,Eval}Script.
    144  [[nodiscard]] bool createSourceAndParser(FrontendContext* fc);
    145 
    146  void assertSourceAndParserCreated() const {
    147    MOZ_ASSERT(compilationState_.source != nullptr);
    148    MOZ_ASSERT(parser.isSome());
    149  }
    150 
    151  void assertSourceParserAndScriptCreated() { assertSourceAndParserCreated(); }
    152 
    153  [[nodiscard]] bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter,
    154                                    SharedContext* sharedContext) {
    155    return EmplaceEmitter(compilationState_, emitter, fc_,
    156                          EitherParser(parser.ptr()), sharedContext);
    157  }
    158 
    159  bool canHandleParseFailure(const Directives& newDirectives);
    160 
    161  void handleParseFailure(
    162      const Directives& newDirectives, TokenStreamPosition& startPosition,
    163      CompilationState::CompilationStatePosition& startStatePosition);
    164 
    165 public:
    166  CompilationState& compilationState() { return compilationState_; };
    167 
    168  ExtensibleCompilationStencil& stencil() { return compilationState_; }
    169 };
    170 
    171 template <typename Unit>
    172 class MOZ_STACK_CLASS ScriptCompiler : public SourceAwareCompiler<Unit> {
    173  using Base = SourceAwareCompiler<Unit>;
    174 
    175 protected:
    176  using Base::compilationState_;
    177  using Base::parser;
    178  using Base::sourceBuffer_;
    179 
    180  using Base::assertSourceParserAndScriptCreated;
    181  using Base::canHandleParseFailure;
    182  using Base::emplaceEmitter;
    183  using Base::handleParseFailure;
    184 
    185  using typename Base::TokenStreamPosition;
    186 
    187 public:
    188  explicit ScriptCompiler(FrontendContext* fc, LifoAllocScope& parserAllocScope,
    189                          CompilationInput& input,
    190                          SourceText<Unit>& sourceBuffer)
    191      : Base(fc, parserAllocScope, input, sourceBuffer) {}
    192 
    193  using Base::init;
    194  using Base::stencil;
    195 
    196  [[nodiscard]] bool compile(JSContext* cx, SharedContext* sc);
    197 
    198 private:
    199  [[nodiscard]] bool popupateExtraBindingsFields(GlobalSharedContext* globalsc);
    200 };
    201 
    202 static already_AddRefed<JS::Stencil> CreateInitialStencilAndDelazifications(
    203    FrontendContext* fc, CompilationStencil* initial) {
    204  RefPtr stencils =
    205      fc->getAllocator()->new_<frontend::InitialStencilAndDelazifications>();
    206  if (!stencils) {
    207    return nullptr;
    208  }
    209  if (!stencils->init(fc, initial)) {
    210    return nullptr;
    211  }
    212  return stencils.forget();
    213 }
    214 
    215 using BytecodeCompilerOutput =
    216    mozilla::Variant<RefPtr<CompilationStencil>, CompilationGCOutput*>;
    217 
    218 static bool ConvertGlobalScriptStencilMaybeInstantiate(
    219    JSContext* maybeCx, FrontendContext* fc, CompilationInput& input,
    220    ExtensibleCompilationStencil&& extensibleStencil,
    221    CompilationStencil** initialStencilOut,
    222    InitialStencilAndDelazifications** stencilsOut,
    223    CompilationGCOutput* gcOutput) {
    224  RefPtr<CompilationStencil> initialStencil;
    225  if (input.options.populateDelazificationCache() || initialStencilOut ||
    226      stencilsOut) {
    227    auto extensibleStencilOnHeap =
    228        fc->getAllocator()->make_unique<frontend::ExtensibleCompilationStencil>(
    229            std::move(extensibleStencil));
    230    if (!extensibleStencilOnHeap) {
    231      return false;
    232    }
    233 
    234    initialStencil = fc->getAllocator()->new_<CompilationStencil>(
    235        std::move(extensibleStencilOnHeap));
    236    if (!initialStencil) {
    237      return false;
    238    }
    239 
    240    if (initialStencilOut) {
    241      *initialStencilOut = initialStencil.get();
    242      (*initialStencilOut)->AddRef();
    243    }
    244  }
    245 
    246  RefPtr<InitialStencilAndDelazifications> stencils;
    247  if (input.options.populateDelazificationCache() || stencilsOut) {
    248    stencils = CreateInitialStencilAndDelazifications(fc, initialStencil.get());
    249    if (!stencils) {
    250      return false;
    251    }
    252 
    253    if (stencilsOut) {
    254      *stencilsOut = stencils.get();
    255      (*stencilsOut)->AddRef();
    256    }
    257  }
    258 
    259  if (input.options.populateDelazificationCache()) {
    260    // NOTE: Delazification can be triggered from off-thread compilation.
    261    StartOffThreadDelazification(maybeCx, input.options, stencils.get());
    262 
    263    // When we are trying to validate whether on-demand delazification
    264    // generate the same stencil as concurrent delazification, we want to
    265    // parse everything eagerly off-thread ahead of re-parsing everything on
    266    // demand, to compare the outcome.
    267    //
    268    // This option works only from main-thread compilation, to avoid
    269    // dead-lock.
    270    if (input.options.waitForDelazificationCache() && maybeCx) {
    271      WaitForAllDelazifyTasks(maybeCx->runtime());
    272    }
    273  }
    274 
    275  if (gcOutput) {
    276    MOZ_ASSERT(maybeCx);
    277    if (stencils) {
    278      if (!InstantiateStencils(maybeCx, input, *stencils.get(), *gcOutput)) {
    279        return false;
    280      }
    281    } else {
    282      MOZ_ASSERT(!initialStencilOut);
    283      BorrowingCompilationStencil borrowingStencil(extensibleStencil);
    284      if (!InstantiateStencils(maybeCx, input, borrowingStencil, *gcOutput)) {
    285        return false;
    286      }
    287    }
    288  }
    289 
    290  return true;
    291 }
    292 
    293 static constexpr ExtraBindingInfoVector* NoExtraBindings = nullptr;
    294 static constexpr CompilationStencil** NoInitialStencilOut = nullptr;
    295 static constexpr InitialStencilAndDelazifications** NoStencilsOut = nullptr;
    296 static constexpr CompilationGCOutput* NoGCOutput = nullptr;
    297 
    298 // Compile global script, and return it as one of:
    299 //   * ExtensibleCompilationStencil (without instantiation)
    300 //   * CompilationStencil (without instantiation, has no external dependency)
    301 //   * CompilationGCOutput (with instantiation).
    302 template <typename Unit>
    303 [[nodiscard]] static bool CompileGlobalScriptToStencilAndMaybeInstantiate(
    304    JSContext* maybeCx, FrontendContext* fc, js::LifoAlloc& tempLifoAlloc,
    305    CompilationInput& input, ScopeBindingCache* scopeCache,
    306    JS::SourceText<Unit>& srcBuf, ScopeKind scopeKind,
    307    ExtraBindingInfoVector* maybeExtraBindings,
    308    CompilationStencil** initialStencilOut,
    309    InitialStencilAndDelazifications** stencilsOut,
    310    CompilationGCOutput* gcOutput) {
    311  if (input.options.selfHostingMode) {
    312    if (!input.initForSelfHostingGlobal(fc)) {
    313      return false;
    314    }
    315  } else if (maybeExtraBindings) {
    316    if (!input.initForGlobalWithExtraBindings(fc, maybeExtraBindings)) {
    317      return false;
    318    }
    319  } else {
    320    if (!input.initForGlobal(fc)) {
    321      return false;
    322    }
    323  }
    324 
    325  AutoAssertReportedException assertException(maybeCx, fc);
    326 
    327  LifoAllocScope parserAllocScope(&tempLifoAlloc);
    328  ScriptCompiler<Unit> compiler(fc, parserAllocScope, input, srcBuf);
    329  if (!compiler.init(fc, scopeCache)) {
    330    return false;
    331  }
    332 
    333  SourceExtent extent = SourceExtent::makeGlobalExtent(
    334      srcBuf.length(), input.options.lineno,
    335      JS::LimitedColumnNumberOneOrigin::fromUnlimited(
    336          JS::ColumnNumberOneOrigin(input.options.column)));
    337 
    338  GlobalSharedContext globalsc(fc, scopeKind, input.options,
    339                               compiler.compilationState().directives, extent);
    340 
    341  if (!compiler.compile(maybeCx, &globalsc)) {
    342    return false;
    343  }
    344 
    345  if (!ConvertGlobalScriptStencilMaybeInstantiate(
    346          maybeCx, fc, input, std::move(compiler.stencil()), initialStencilOut,
    347          stencilsOut, gcOutput)) {
    348    return false;
    349  }
    350 
    351  assertException.reset();
    352  return true;
    353 }
    354 
    355 template <typename Unit>
    356 static already_AddRefed<CompilationStencil>
    357 CompileGlobalScriptToStencilWithInputImpl(
    358    JSContext* maybeCx, FrontendContext* fc, js::LifoAlloc& tempLifoAlloc,
    359    CompilationInput& input, ScopeBindingCache* scopeCache,
    360    JS::SourceText<Unit>& srcBuf, ScopeKind scopeKind) {
    361  RefPtr<CompilationStencil> stencil;
    362  if (!CompileGlobalScriptToStencilAndMaybeInstantiate(
    363          maybeCx, fc, tempLifoAlloc, input, scopeCache, srcBuf, scopeKind,
    364          NoExtraBindings, getter_AddRefs(stencil), NoGCOutput)) {
    365    return nullptr;
    366  }
    367  return stencil.forget();
    368 }
    369 
    370 already_AddRefed<CompilationStencil>
    371 frontend::CompileGlobalScriptToStencilWithInput(
    372    JSContext* cx, FrontendContext* fc, js::LifoAlloc& tempLifoAlloc,
    373    CompilationInput& input, ScopeBindingCache* scopeCache,
    374    JS::SourceText<Utf8Unit>& srcBuf, ScopeKind scopeKind) {
    375  RefPtr<CompilationStencil> stencil;
    376  if (!CompileGlobalScriptToStencilAndMaybeInstantiate(
    377          cx, fc, tempLifoAlloc, input, scopeCache, srcBuf, scopeKind,
    378          NoExtraBindings, getter_AddRefs(stencil), NoStencilsOut,
    379          NoGCOutput)) {
    380    return nullptr;
    381  }
    382  return stencil.forget();
    383 }
    384 
    385 template <typename CharT>
    386 static already_AddRefed<JS::Stencil> CompileGlobalScriptToStencilImpl(
    387    JSContext* cx, const JS::ReadOnlyCompileOptions& options,
    388    JS::SourceText<CharT>& srcBuf) {
    389  ScopeKind scopeKind =
    390      options.nonSyntacticScope ? ScopeKind::NonSyntactic : ScopeKind::Global;
    391 
    392  AutoReportFrontendContext fc(cx);
    393 
    394  NoScopeBindingCache scopeCache;
    395  Rooted<CompilationInput> input(cx, CompilationInput(options));
    396  RefPtr<InitialStencilAndDelazifications> stencils;
    397  if (!CompileGlobalScriptToStencilAndMaybeInstantiate(
    398          cx, &fc, cx->tempLifoAlloc(), input.get(), &scopeCache, srcBuf,
    399          scopeKind, NoExtraBindings, NoInitialStencilOut,
    400          getter_AddRefs(stencils), NoGCOutput)) {
    401    return nullptr;
    402  }
    403  return stencils.forget();
    404 }
    405 
    406 already_AddRefed<JS::Stencil> JS::CompileGlobalScriptToStencil(
    407    JSContext* cx, const JS::ReadOnlyCompileOptions& options,
    408    JS::SourceText<mozilla::Utf8Unit>& srcBuf) {
    409  return CompileGlobalScriptToStencilImpl(cx, options, srcBuf);
    410 }
    411 
    412 already_AddRefed<JS::Stencil> JS::CompileGlobalScriptToStencil(
    413    JSContext* cx, const JS::ReadOnlyCompileOptions& options,
    414    JS::SourceText<char16_t>& srcBuf) {
    415  return CompileGlobalScriptToStencilImpl(cx, options, srcBuf);
    416 }
    417 
    418 template <typename CharT>
    419 static already_AddRefed<JS::Stencil> CompileGlobalScriptToStencilImpl(
    420    JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
    421    JS::SourceText<CharT>& srcBuf) {
    422  ScopeKind scopeKind =
    423      options.nonSyntacticScope ? ScopeKind::NonSyntactic : ScopeKind::Global;
    424 
    425  NoScopeBindingCache scopeCache;
    426  js::LifoAlloc tempLifoAlloc(JSContext::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE,
    427                              js::BackgroundMallocArena);
    428  CompilationInput compilationInput(options);
    429  RefPtr<InitialStencilAndDelazifications> stencils;
    430  if (!CompileGlobalScriptToStencilAndMaybeInstantiate(
    431          nullptr, fc, tempLifoAlloc, compilationInput, &scopeCache, srcBuf,
    432          scopeKind, NoExtraBindings, NoInitialStencilOut,
    433          getter_AddRefs(stencils), NoGCOutput)) {
    434    JS_HAZ_VALUE_IS_GC_SAFE(compilationInput);
    435    return nullptr;
    436  }
    437  // CompilationInput initialized with CompileGlobalScriptToStencil only
    438  // references information from the JS::Stencil context and the
    439  // ref-counted ScriptSource, which are both GC-free.
    440  JS_HAZ_VALUE_IS_GC_SAFE(compilationInput);
    441  return stencils.forget();
    442 }
    443 
    444 already_AddRefed<JS::Stencil> JS::CompileGlobalScriptToStencil(
    445    JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
    446    JS::SourceText<mozilla::Utf8Unit>& srcBuf) {
    447 #ifdef DEBUG
    448  fc->assertNativeStackLimitThread();
    449 #endif
    450  return CompileGlobalScriptToStencilImpl(fc, options, srcBuf);
    451 }
    452 
    453 already_AddRefed<JS::Stencil> JS::CompileGlobalScriptToStencil(
    454    JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
    455    JS::SourceText<char16_t>& srcBuf) {
    456 #ifdef DEBUG
    457  fc->assertNativeStackLimitThread();
    458 #endif
    459  return CompileGlobalScriptToStencilImpl(fc, options, srcBuf);
    460 }
    461 
    462 static void FireOnNewScript(JSContext* cx,
    463                            const JS::InstantiateOptions& options,
    464                            JS::Handle<JSScript*> script) {
    465  if (!options.hideFromNewScriptInitial()) {
    466    DebugAPI::onNewScript(cx, script);
    467  }
    468 }
    469 
    470 static inline ScriptSource* getSource(const CompilationStencil& stencil) {
    471  return stencil.source;
    472 }
    473 
    474 static inline ScriptSource* getSource(
    475    const InitialStencilAndDelazifications& stencils) {
    476  return stencils.getInitial()->source;
    477 }
    478 
    479 template <typename T>
    480 bool InstantiateStencilsImpl(JSContext* cx, CompilationInput& input, T& stencil,
    481                             CompilationGCOutput& gcOutput) {
    482  {
    483    AutoGeckoProfilerEntry pseudoFrame(cx, "stencil instantiate",
    484                                       JS::ProfilingCategoryPair::JS_Parsing);
    485 
    486    if (!T::instantiateStencils(cx, input, stencil, gcOutput)) {
    487      return false;
    488    }
    489  }
    490 
    491  // Enqueue an off-thread source compression task after finishing parsing.
    492  if (!getSource(stencil)->tryCompressOffThread(cx)) {
    493    return false;
    494  }
    495 
    496  Rooted<JSScript*> script(cx, gcOutput.script);
    497  const JS::InstantiateOptions instantiateOptions(input.options);
    498  FireOnNewScript(cx, instantiateOptions, script);
    499 
    500  return true;
    501 }
    502 
    503 bool frontend::InstantiateStencils(JSContext* cx, CompilationInput& input,
    504                                   const CompilationStencil& stencil,
    505                                   CompilationGCOutput& gcOutput) {
    506  return InstantiateStencilsImpl(cx, input, stencil, gcOutput);
    507 }
    508 
    509 bool frontend::InstantiateStencils(JSContext* cx, CompilationInput& input,
    510                                   InitialStencilAndDelazifications& stencils,
    511                                   CompilationGCOutput& gcOutput) {
    512  return InstantiateStencilsImpl(cx, input, stencils, gcOutput);
    513 }
    514 
    515 template <typename Unit>
    516 static JSScript* CompileGlobalScriptImpl(
    517    JSContext* cx, FrontendContext* fc,
    518    const JS::ReadOnlyCompileOptions& options, JS::SourceText<Unit>& srcBuf,
    519    ScopeKind scopeKind, ExtraBindingInfoVector* maybeExtraBindings) {
    520  Rooted<CompilationInput> input(cx, CompilationInput(options));
    521  Rooted<CompilationGCOutput> gcOutput(cx);
    522  NoScopeBindingCache scopeCache;
    523  if (!CompileGlobalScriptToStencilAndMaybeInstantiate(
    524          cx, fc, cx->tempLifoAlloc(), input.get(), &scopeCache, srcBuf,
    525          scopeKind, maybeExtraBindings, NoInitialStencilOut, NoStencilsOut,
    526          gcOutput.address())) {
    527    return nullptr;
    528  }
    529  return gcOutput.get().script;
    530 }
    531 
    532 JSScript* frontend::CompileGlobalScript(
    533    JSContext* cx, FrontendContext* fc,
    534    const JS::ReadOnlyCompileOptions& options, JS::SourceText<char16_t>& srcBuf,
    535    ScopeKind scopeKind) {
    536  return CompileGlobalScriptImpl(cx, fc, options, srcBuf, scopeKind,
    537                                 NoExtraBindings);
    538 }
    539 
    540 static bool CreateExtraBindingInfoVector(
    541    JSContext* cx,
    542    JS::Handle<JS::StackGCVector<JS::PropertyKey>> unwrappedBindingKeys,
    543    JS::Handle<JS::StackGCVector<JS::Value>> unwrappedBindingValues,
    544    ExtraBindingInfoVector& extraBindings) {
    545  MOZ_ASSERT(unwrappedBindingKeys.length() == unwrappedBindingValues.length());
    546 
    547  if (!extraBindings.reserve(unwrappedBindingKeys.length())) {
    548    ReportOutOfMemory(cx);
    549    return false;
    550  }
    551 
    552  JS::Rooted<JSObject*> globalLexical(cx, &cx->global()->lexicalEnvironment());
    553  JS::Rooted<JS::PropertyKey> id(cx);
    554  for (size_t i = 0; i < unwrappedBindingKeys.length(); i++) {
    555    if (!unwrappedBindingKeys[i].isString()) {
    556      JS_ReportErrorASCII(cx, "The bindings key should be a string.");
    557      return false;
    558    }
    559 
    560    JS::Rooted<JSString*> str(cx, unwrappedBindingKeys[i].toString());
    561 
    562    UniqueChars utf8chars = JS_EncodeStringToUTF8(cx, str);
    563    if (!utf8chars) {
    564      return false;
    565    }
    566 
    567    bool isShadowed = false;
    568 
    569    id = unwrappedBindingKeys[i];
    570    cx->markId(id);
    571 
    572    bool found;
    573    if (!HasProperty(cx, cx->global(), id, &found)) {
    574      return false;
    575    }
    576    if (found) {
    577      isShadowed = true;
    578    } else {
    579      if (!HasProperty(cx, globalLexical, id, &found)) {
    580        return false;
    581      }
    582      if (found) {
    583        isShadowed = true;
    584      }
    585    }
    586 
    587    extraBindings.infallibleEmplaceBack(std::move(utf8chars), isShadowed);
    588  }
    589 
    590  return true;
    591 }
    592 
    593 static WithEnvironmentObject* CreateExtraBindingsEnvironment(
    594    JSContext* cx,
    595    JS::Handle<JS::StackGCVector<JS::PropertyKey>> unwrappedBindingKeys,
    596    JS::Handle<JS::StackGCVector<JS::Value>> unwrappedBindingValues,
    597    const ExtraBindingInfoVector& extraBindings) {
    598  JS::Rooted<PlainObject*> extraBindingsObj(
    599      cx, NewPlainObjectWithProto(cx, nullptr));
    600  if (!extraBindingsObj) {
    601    return nullptr;
    602  }
    603 
    604  MOZ_ASSERT(unwrappedBindingKeys.length() == extraBindings.length());
    605 
    606  JS::Rooted<JS::PropertyKey> id(cx);
    607  size_t i = 0;
    608  for (const auto& bindingInfo : extraBindings) {
    609    if (bindingInfo.isShadowed) {
    610      i++;
    611      continue;
    612    }
    613 
    614    id = unwrappedBindingKeys[i];
    615    cx->markId(id);
    616    JS::Rooted<JS::Value> val(cx, unwrappedBindingValues[i]);
    617    if (!cx->compartment()->wrap(cx, &val) ||
    618        !NativeDefineDataProperty(cx, extraBindingsObj, id, val, 0)) {
    619      return nullptr;
    620    }
    621    i++;
    622  }
    623 
    624  // The list of bindings shouldn't be modified.
    625  if (!SetIntegrityLevel(cx, extraBindingsObj, IntegrityLevel::Sealed)) {
    626    return nullptr;
    627  }
    628 
    629  JS::Rooted<JSObject*> globalLexical(cx, &cx->global()->lexicalEnvironment());
    630  return WithEnvironmentObject::createNonSyntactic(
    631      cx, extraBindingsObj, globalLexical, JS::SupportUnscopables::No);
    632 }
    633 
    634 JSScript* frontend::CompileGlobalScriptWithExtraBindings(
    635    JSContext* cx, FrontendContext* fc,
    636    const JS::ReadOnlyCompileOptions& options, JS::SourceText<char16_t>& srcBuf,
    637    JS::Handle<JS::StackGCVector<JS::PropertyKey>> unwrappedBindingKeys,
    638    JS::Handle<JS::StackGCVector<JS::Value>> unwrappedBindingValues,
    639    JS::MutableHandle<JSObject*> env) {
    640  ExtraBindingInfoVector extraBindings;
    641  if (!CreateExtraBindingInfoVector(cx, unwrappedBindingKeys,
    642                                    unwrappedBindingValues, extraBindings)) {
    643    return nullptr;
    644  }
    645 
    646  JS::Rooted<JSScript*> script(
    647      cx, CompileGlobalScriptImpl(cx, fc, options, srcBuf,
    648                                  ScopeKind::NonSyntactic, &extraBindings));
    649  if (!script) {
    650    if (fc->extraBindingsAreNotUsed()) {
    651      // Compile the script as regular global script in global lexical.
    652 
    653      fc->clearNoExtraBindingReferencesFound();
    654 
    655      // Warnings can be reported. Clear them to avoid reporting twice.
    656      fc->clearWarnings();
    657 
    658      // No other error should be reported.
    659      MOZ_ASSERT(!fc->hadErrors());
    660      MOZ_ASSERT(!cx->isExceptionPending());
    661 
    662      env.set(&cx->global()->lexicalEnvironment());
    663 
    664      JS::CompileOptions copiedOptions(nullptr, options);
    665      copiedOptions.setNonSyntacticScope(false);
    666 
    667      return CompileGlobalScript(cx, fc, copiedOptions, srcBuf,
    668                                 ScopeKind::Global);
    669    }
    670 
    671    return nullptr;
    672  }
    673 
    674  WithEnvironmentObject* extraBindingsEnv = CreateExtraBindingsEnvironment(
    675      cx, unwrappedBindingKeys, unwrappedBindingValues, extraBindings);
    676  if (!extraBindingsEnv) {
    677    return nullptr;
    678  }
    679 
    680  env.set(extraBindingsEnv);
    681 
    682  return script;
    683 }
    684 
    685 JSScript* frontend::CompileGlobalScript(
    686    JSContext* cx, FrontendContext* fc,
    687    const JS::ReadOnlyCompileOptions& options, JS::SourceText<Utf8Unit>& srcBuf,
    688    ScopeKind scopeKind) {
    689  return CompileGlobalScriptImpl(cx, fc, options, srcBuf, scopeKind,
    690                                 NoExtraBindings);
    691 }
    692 
    693 template <typename Unit>
    694 static JSScript* CompileEvalScriptImpl(
    695    JSContext* cx, const JS::ReadOnlyCompileOptions& options,
    696    SourceText<Unit>& srcBuf, JS::Handle<js::Scope*> enclosingScope,
    697    JS::Handle<JSObject*> enclosingEnv) {
    698  JS::Rooted<JSScript*> script(cx);
    699  {
    700    AutoReportFrontendContext fc(cx);
    701    AutoAssertReportedException assertException(cx, &fc);
    702 
    703    Rooted<CompilationInput> input(cx, CompilationInput(options));
    704    if (!input.get().initForEval(&fc, enclosingScope)) {
    705      return nullptr;
    706    }
    707 
    708    LifoAllocScope parserAllocScope(&cx->tempLifoAlloc());
    709 
    710    ScopeBindingCache* scopeCache = &cx->caches().scopeCache;
    711    ScriptCompiler<Unit> compiler(&fc, parserAllocScope, input.get(), srcBuf);
    712    if (!compiler.init(&fc, scopeCache, InheritThis::Yes, enclosingEnv)) {
    713      return nullptr;
    714    }
    715 
    716    uint32_t len = srcBuf.length();
    717    SourceExtent extent = SourceExtent::makeGlobalExtent(
    718        len, options.lineno,
    719        JS::LimitedColumnNumberOneOrigin::fromUnlimited(
    720            JS::ColumnNumberOneOrigin(options.column)));
    721    EvalSharedContext evalsc(&fc, compiler.compilationState(), extent);
    722    if (!compiler.compile(cx, &evalsc)) {
    723      return nullptr;
    724    }
    725 
    726    Rooted<CompilationGCOutput> gcOutput(cx);
    727    {
    728      BorrowingCompilationStencil borrowingStencil(compiler.stencil());
    729      if (!InstantiateStencils(cx, input.get(), borrowingStencil,
    730                               gcOutput.get())) {
    731        return nullptr;
    732      }
    733    }
    734 
    735    assertException.reset();
    736    script = gcOutput.get().script;
    737  }
    738  return script;
    739 }
    740 
    741 JSScript* frontend::CompileEvalScript(JSContext* cx,
    742                                      const JS::ReadOnlyCompileOptions& options,
    743                                      JS::SourceText<char16_t>& srcBuf,
    744                                      JS::Handle<js::Scope*> enclosingScope,
    745                                      JS::Handle<JSObject*> enclosingEnv) {
    746  return CompileEvalScriptImpl(cx, options, srcBuf, enclosingScope,
    747                               enclosingEnv);
    748 }
    749 
    750 template <typename Unit>
    751 class MOZ_STACK_CLASS ModuleCompiler final : public SourceAwareCompiler<Unit> {
    752  using Base = SourceAwareCompiler<Unit>;
    753 
    754  using Base::assertSourceParserAndScriptCreated;
    755  using Base::compilationState_;
    756  using Base::emplaceEmitter;
    757  using Base::parser;
    758 
    759 public:
    760  explicit ModuleCompiler(FrontendContext* fc, LifoAllocScope& parserAllocScope,
    761                          CompilationInput& input,
    762                          SourceText<Unit>& sourceBuffer)
    763      : Base(fc, parserAllocScope, input, sourceBuffer) {}
    764 
    765  using Base::init;
    766  using Base::stencil;
    767 
    768  [[nodiscard]] bool compile(JSContext* maybeCx, FrontendContext* fc);
    769 };
    770 
    771 template <typename Unit>
    772 class MOZ_STACK_CLASS StandaloneFunctionCompiler final
    773    : public SourceAwareCompiler<Unit> {
    774  using Base = SourceAwareCompiler<Unit>;
    775 
    776  using Base::assertSourceAndParserCreated;
    777  using Base::canHandleParseFailure;
    778  using Base::compilationState_;
    779  using Base::emplaceEmitter;
    780  using Base::handleParseFailure;
    781  using Base::parser;
    782  using Base::sourceBuffer_;
    783 
    784  using typename Base::TokenStreamPosition;
    785 
    786 public:
    787  explicit StandaloneFunctionCompiler(FrontendContext* fc,
    788                                      LifoAllocScope& parserAllocScope,
    789                                      CompilationInput& input,
    790                                      SourceText<Unit>& sourceBuffer)
    791      : Base(fc, parserAllocScope, input, sourceBuffer) {}
    792 
    793  using Base::init;
    794  using Base::stencil;
    795 
    796 private:
    797  FunctionNode* parse(JSContext* cx, FunctionSyntaxKind syntaxKind,
    798                      GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
    799                      const Maybe<uint32_t>& parameterListEnd);
    800 
    801 public:
    802  [[nodiscard]] bool compile(JSContext* cx, FunctionSyntaxKind syntaxKind,
    803                             GeneratorKind generatorKind,
    804                             FunctionAsyncKind asyncKind,
    805                             const Maybe<uint32_t>& parameterListEnd);
    806 };
    807 
    808 template <typename Unit>
    809 bool SourceAwareCompiler<Unit>::createSourceAndParser(FrontendContext* fc) {
    810  const auto& options = compilationState_.input.options;
    811 
    812  fc_ = fc;
    813 
    814  if (!compilationState_.source->assignSource(fc, options, sourceBuffer_)) {
    815    return false;
    816  }
    817 
    818  MOZ_ASSERT(compilationState_.canLazilyParse ==
    819             CanLazilyParse(compilationState_.input.options));
    820  if (compilationState_.canLazilyParse) {
    821    syntaxParser.emplace(fc_, options, sourceBuffer_.units(),
    822                         sourceBuffer_.length(), compilationState_,
    823                         /* syntaxParser = */ nullptr);
    824    if (!syntaxParser->checkOptions()) {
    825      return false;
    826    }
    827  }
    828 
    829  parser.emplace(fc_, options, sourceBuffer_.units(), sourceBuffer_.length(),
    830                 compilationState_, syntaxParser.ptrOr(nullptr));
    831  parser->ss = compilationState_.source.get();
    832  return parser->checkOptions();
    833 }
    834 
    835 static bool EmplaceEmitter(CompilationState& compilationState,
    836                           Maybe<BytecodeEmitter>& emitter, FrontendContext* fc,
    837                           const EitherParser& parser, SharedContext* sc) {
    838  BytecodeEmitter::EmitterMode emitterMode =
    839      sc->selfHosted() ? BytecodeEmitter::SelfHosting : BytecodeEmitter::Normal;
    840  emitter.emplace(fc, parser, sc, compilationState, emitterMode);
    841  return emitter->init();
    842 }
    843 
    844 template <typename Unit>
    845 bool SourceAwareCompiler<Unit>::canHandleParseFailure(
    846    const Directives& newDirectives) {
    847  // Try to reparse if no parse errors were thrown and the directives changed.
    848  //
    849  // NOTE:
    850  // Only the following two directive changes force us to reparse the script:
    851  // - The "use asm" directive was encountered.
    852  // - The "use strict" directive was encountered and duplicate parameter names
    853  //   are present. We reparse in this case to display the error at the correct
    854  //   source location. See |Parser::hasValidSimpleStrictParameterNames()|.
    855  return !parser->anyChars.hadError() &&
    856         compilationState_.directives != newDirectives;
    857 }
    858 
    859 template <typename Unit>
    860 void SourceAwareCompiler<Unit>::handleParseFailure(
    861    const Directives& newDirectives, TokenStreamPosition& startPosition,
    862    CompilationState::CompilationStatePosition& startStatePosition) {
    863  MOZ_ASSERT(canHandleParseFailure(newDirectives));
    864 
    865  // Rewind to starting position to retry.
    866  parser->tokenStream.rewind(startPosition);
    867  compilationState_.rewind(startStatePosition);
    868 
    869  // Assignment must be monotonic to prevent reparsing iloops
    870  MOZ_ASSERT_IF(compilationState_.directives.strict(), newDirectives.strict());
    871  MOZ_ASSERT_IF(compilationState_.directives.asmJS(), newDirectives.asmJS());
    872  compilationState_.directives = newDirectives;
    873 }
    874 
    875 static bool UsesExtraBindings(GlobalSharedContext* globalsc,
    876                              const ExtraBindingInfoVector& extraBindings,
    877                              const UsedNameTracker::UsedNameMap& usedNameMap) {
    878  for (const auto& bindingInfo : extraBindings) {
    879    if (bindingInfo.isShadowed) {
    880      continue;
    881    }
    882 
    883    for (auto r = usedNameMap.all(); !r.empty(); r.popFront()) {
    884      const auto& item = r.front();
    885      const auto& name = item.key();
    886      if (bindingInfo.nameIndex != name) {
    887        continue;
    888      }
    889 
    890      const auto& nameInfo = item.value();
    891      if (nameInfo.empty()) {
    892        continue;
    893      }
    894 
    895      // This name is free, and uses the extra binding.
    896      return true;
    897    }
    898  }
    899 
    900  return false;
    901 }
    902 
    903 template <typename Unit>
    904 bool ScriptCompiler<Unit>::popupateExtraBindingsFields(
    905    GlobalSharedContext* globalsc) {
    906  if (!compilationState_.input.internExtraBindings(
    907          this->fc_, compilationState_.parserAtoms)) {
    908    return false;
    909  }
    910 
    911  bool hasNonShadowedBinding = false;
    912  for (auto& bindingInfo : compilationState_.input.extraBindings()) {
    913    if (bindingInfo.isShadowed) {
    914      continue;
    915    }
    916 
    917    bool isShadowed = false;
    918 
    919    if (globalsc->bindings) {
    920      for (ParserBindingIter bi(*globalsc->bindings); bi; bi++) {
    921        if (bindingInfo.nameIndex == bi.name()) {
    922          isShadowed = true;
    923          break;
    924        }
    925      }
    926    }
    927 
    928    bindingInfo.isShadowed = isShadowed;
    929    if (!isShadowed) {
    930      hasNonShadowedBinding = true;
    931    }
    932  }
    933 
    934  if (!hasNonShadowedBinding) {
    935    // All bindings are shadowed.
    936    this->fc_->reportExtraBindingsAreNotUsed();
    937    return false;
    938  }
    939 
    940  if (globalsc->hasDirectEval()) {
    941    // Direct eval can contain reference.
    942    return true;
    943  }
    944 
    945  if (!UsesExtraBindings(globalsc, compilationState_.input.extraBindings(),
    946                         parser->usedNames().map())) {
    947    this->fc_->reportExtraBindingsAreNotUsed();
    948    return false;
    949  }
    950 
    951  return true;
    952 }
    953 
    954 template <typename Unit>
    955 bool ScriptCompiler<Unit>::compile(JSContext* maybeCx, SharedContext* sc) {
    956  assertSourceParserAndScriptCreated();
    957 
    958  TokenStreamPosition startPosition(parser->tokenStream);
    959 
    960  // Emplace the topLevel stencil
    961  MOZ_ASSERT(compilationState_.scriptData.length() ==
    962             CompilationStencil::TopLevelIndex);
    963  if (!compilationState_.appendScriptStencilAndData(sc->fc_)) {
    964    return false;
    965  }
    966 
    967  ParseNode* pn;
    968  {
    969    Maybe<AutoGeckoProfilerEntry> pseudoFrame;
    970    if (maybeCx) {
    971      pseudoFrame.emplace(maybeCx, "script parsing",
    972                          JS::ProfilingCategoryPair::JS_Parsing);
    973    }
    974    if (sc->isEvalContext()) {
    975      pn = parser->evalBody(sc->asEvalContext()).unwrapOr(nullptr);
    976    } else {
    977      pn = parser->globalBody(sc->asGlobalContext()).unwrapOr(nullptr);
    978    }
    979  }
    980 
    981  if (!pn) {
    982    // Global and eval scripts don't get reparsed after a new directive was
    983    // encountered:
    984    // - "use strict" doesn't require any special error reporting for scripts.
    985    // - "use asm" directives don't have an effect in global/eval contexts.
    986    MOZ_ASSERT(!canHandleParseFailure(compilationState_.directives));
    987    return false;
    988  }
    989 
    990  if (sc->isGlobalContext() && compilationState_.input.hasExtraBindings()) {
    991    if (!popupateExtraBindingsFields(sc->asGlobalContext())) {
    992      return false;
    993    }
    994  }
    995 
    996  {
    997    // Successfully parsed. Emit the script.
    998    Maybe<AutoGeckoProfilerEntry> pseudoFrame;
    999    if (maybeCx) {
   1000      pseudoFrame.emplace(maybeCx, "script emit",
   1001                          JS::ProfilingCategoryPair::JS_Parsing);
   1002    }
   1003 
   1004    Maybe<BytecodeEmitter> emitter;
   1005    if (!emplaceEmitter(emitter, sc)) {
   1006      return false;
   1007    }
   1008 
   1009    if (!emitter->emitScript(pn)) {
   1010      return false;
   1011    }
   1012  }
   1013 
   1014  MOZ_ASSERT(!this->fc_->hadErrors());
   1015 
   1016  return true;
   1017 }
   1018 
   1019 template <typename Unit>
   1020 bool ModuleCompiler<Unit>::compile(JSContext* maybeCx, FrontendContext* fc) {
   1021  // Emplace the topLevel stencil
   1022  MOZ_ASSERT(compilationState_.scriptData.length() ==
   1023             CompilationStencil::TopLevelIndex);
   1024  if (!compilationState_.appendScriptStencilAndData(fc)) {
   1025    return false;
   1026  }
   1027 
   1028  ModuleBuilder builder(fc, parser.ptr());
   1029 
   1030  const auto& options = compilationState_.input.options;
   1031 
   1032  uint32_t len = this->sourceBuffer_.length();
   1033  SourceExtent extent = SourceExtent::makeGlobalExtent(
   1034      len, options.lineno,
   1035      JS::LimitedColumnNumberOneOrigin::fromUnlimited(
   1036          JS::ColumnNumberOneOrigin(options.column)));
   1037  ModuleSharedContext modulesc(fc, options, builder, extent);
   1038 
   1039  ParseNode* pn = parser->moduleBody(&modulesc).unwrapOr(nullptr);
   1040  if (!pn) {
   1041    return false;
   1042  }
   1043 
   1044  Maybe<BytecodeEmitter> emitter;
   1045  if (!emplaceEmitter(emitter, &modulesc)) {
   1046    return false;
   1047  }
   1048 
   1049  if (!emitter->emitScript(pn->as<ModuleNode>().body())) {
   1050    return false;
   1051  }
   1052 
   1053  StencilModuleMetadata& moduleMetadata = *compilationState_.moduleMetadata;
   1054 
   1055  builder.finishFunctionDecls(moduleMetadata);
   1056 
   1057  MOZ_ASSERT(!this->fc_->hadErrors());
   1058 
   1059  return true;
   1060 }
   1061 
   1062 // Parse a standalone JS function, which might appear as the value of an
   1063 // event handler attribute in an HTML <INPUT> tag, or in a Function()
   1064 // constructor.
   1065 template <typename Unit>
   1066 FunctionNode* StandaloneFunctionCompiler<Unit>::parse(
   1067    JSContext* cx, FunctionSyntaxKind syntaxKind, GeneratorKind generatorKind,
   1068    FunctionAsyncKind asyncKind, const Maybe<uint32_t>& parameterListEnd) {
   1069  assertSourceAndParserCreated();
   1070 
   1071  TokenStreamPosition startPosition(parser->tokenStream);
   1072  auto startStatePosition = compilationState_.getPosition();
   1073 
   1074  // Speculatively parse using the default directives implied by the context.
   1075  // If a directive is encountered (e.g., "use strict") that changes how the
   1076  // function should have been parsed, we backup and reparse with the new set
   1077  // of directives.
   1078 
   1079  FunctionNode* fn;
   1080  for (;;) {
   1081    Directives newDirectives = compilationState_.directives;
   1082    fn = parser
   1083             ->standaloneFunction(parameterListEnd, syntaxKind, generatorKind,
   1084                                  asyncKind, compilationState_.directives,
   1085                                  &newDirectives)
   1086             .unwrapOr(nullptr);
   1087    if (fn) {
   1088      break;
   1089    }
   1090 
   1091    // Maybe we encountered a new directive. See if we can try again.
   1092    if (!canHandleParseFailure(newDirectives)) {
   1093      return nullptr;
   1094    }
   1095 
   1096    handleParseFailure(newDirectives, startPosition, startStatePosition);
   1097  }
   1098 
   1099  return fn;
   1100 }
   1101 
   1102 // Compile a standalone JS function.
   1103 template <typename Unit>
   1104 bool StandaloneFunctionCompiler<Unit>::compile(
   1105    JSContext* cx, FunctionSyntaxKind syntaxKind, GeneratorKind generatorKind,
   1106    FunctionAsyncKind asyncKind, const Maybe<uint32_t>& parameterListEnd) {
   1107  FunctionNode* parsedFunction =
   1108      parse(cx, syntaxKind, generatorKind, asyncKind, parameterListEnd);
   1109  if (!parsedFunction) {
   1110    return false;
   1111  }
   1112 
   1113  FunctionBox* funbox = parsedFunction->funbox();
   1114 
   1115  if (funbox->isInterpreted()) {
   1116    Maybe<BytecodeEmitter> emitter;
   1117    if (!emplaceEmitter(emitter, funbox)) {
   1118      return false;
   1119    }
   1120 
   1121    if (!emitter->emitFunctionScript(parsedFunction)) {
   1122      return false;
   1123    }
   1124 
   1125    // The parser extent has stripped off the leading `function...` but
   1126    // we want the SourceExtent used in the final standalone script to
   1127    // start from the beginning of the buffer, and use the provided
   1128    // line and column.
   1129    const auto& options = compilationState_.input.options;
   1130    compilationState_.scriptExtra[CompilationStencil::TopLevelIndex].extent =
   1131        SourceExtent{/* sourceStart = */ 0,
   1132                     sourceBuffer_.length(),
   1133                     funbox->extent().toStringStart,
   1134                     funbox->extent().toStringEnd,
   1135                     options.lineno,
   1136                     JS::LimitedColumnNumberOneOrigin::fromUnlimited(
   1137                         JS::ColumnNumberOneOrigin(options.column))};
   1138  } else {
   1139    // The asm.js module was created by parser. Instantiation below will
   1140    // allocate the JSFunction that wraps it.
   1141    MOZ_ASSERT(funbox->isAsmJSModule());
   1142    MOZ_ASSERT(compilationState_.asmJS->moduleMap.has(funbox->index()));
   1143    MOZ_ASSERT(compilationState_.scriptData[CompilationStencil::TopLevelIndex]
   1144                   .functionFlags.isAsmJSNative());
   1145  }
   1146 
   1147  return true;
   1148 }
   1149 
   1150 // Compile module, and return it as one of:
   1151 //   * ExtensibleCompilationStencil (without instantiation)
   1152 //   * CompilationStencil (without instantiation, has no external dependency)
   1153 //   * CompilationGCOutput (with instantiation).
   1154 template <typename Unit>
   1155 [[nodiscard]] static bool ParseModuleToStencilAndMaybeInstantiate(
   1156    JSContext* maybeCx, FrontendContext* fc, js::LifoAlloc& tempLifoAlloc,
   1157    CompilationInput& input, ScopeBindingCache* scopeCache,
   1158    SourceText<Unit>& srcBuf, BytecodeCompilerOutput& output) {
   1159  MOZ_ASSERT(srcBuf.get());
   1160  MOZ_ASSERT(input.options.lineno != 0,
   1161             "Module cannot be compiled with lineNumber == 0");
   1162 
   1163  if (!input.initForModule(fc)) {
   1164    return false;
   1165  }
   1166 
   1167  AutoAssertReportedException assertException(maybeCx, fc);
   1168 
   1169  LifoAllocScope parserAllocScope(&tempLifoAlloc);
   1170  ModuleCompiler<Unit> compiler(fc, parserAllocScope, input, srcBuf);
   1171  if (!compiler.init(fc, scopeCache)) {
   1172    return false;
   1173  }
   1174 
   1175  if (!compiler.compile(maybeCx, fc)) {
   1176    return false;
   1177  }
   1178 
   1179  if (output.is<RefPtr<CompilationStencil>>()) {
   1180    Maybe<AutoGeckoProfilerEntry> pseudoFrame;
   1181    if (maybeCx) {
   1182      pseudoFrame.emplace(maybeCx, "script emit",
   1183                          JS::ProfilingCategoryPair::JS_Parsing);
   1184    }
   1185 
   1186    auto extensibleStencil =
   1187        fc->getAllocator()->make_unique<frontend::ExtensibleCompilationStencil>(
   1188            std::move(compiler.stencil()));
   1189    if (!extensibleStencil) {
   1190      return false;
   1191    }
   1192 
   1193    RefPtr<CompilationStencil> stencil =
   1194        fc->getAllocator()->new_<CompilationStencil>(
   1195            std::move(extensibleStencil));
   1196    if (!stencil) {
   1197      return false;
   1198    }
   1199 
   1200    output.as<RefPtr<CompilationStencil>>() = std::move(stencil);
   1201  } else {
   1202    MOZ_ASSERT(maybeCx);
   1203    BorrowingCompilationStencil borrowingStencil(compiler.stencil());
   1204    if (!InstantiateStencils(maybeCx, input, borrowingStencil,
   1205                             *(output.as<CompilationGCOutput*>()))) {
   1206      return false;
   1207    }
   1208  }
   1209 
   1210  assertException.reset();
   1211  return true;
   1212 }
   1213 
   1214 template <typename Unit>
   1215 already_AddRefed<CompilationStencil> ParseModuleToStencilImpl(
   1216    JSContext* maybeCx, FrontendContext* fc, js::LifoAlloc& tempLifoAlloc,
   1217    CompilationInput& input, ScopeBindingCache* scopeCache,
   1218    SourceText<Unit>& srcBuf) {
   1219  using OutputType = RefPtr<CompilationStencil>;
   1220  BytecodeCompilerOutput output((OutputType()));
   1221  if (!ParseModuleToStencilAndMaybeInstantiate(
   1222          maybeCx, fc, tempLifoAlloc, input, scopeCache, srcBuf, output)) {
   1223    return nullptr;
   1224  }
   1225  return output.as<OutputType>().forget();
   1226 }
   1227 
   1228 template <typename CharT>
   1229 static already_AddRefed<JS::Stencil> CompileModuleScriptToStencilImpl(
   1230    JSContext* cx, const JS::ReadOnlyCompileOptions& optionsInput,
   1231    JS::SourceText<CharT>& srcBuf) {
   1232  JS::CompileOptions options(cx, optionsInput);
   1233  options.setModule();
   1234 
   1235  AutoReportFrontendContext fc(cx);
   1236 
   1237  NoScopeBindingCache scopeCache;
   1238  Rooted<CompilationInput> input(cx, CompilationInput(options));
   1239  RefPtr<CompilationStencil> stencil = ParseModuleToStencilImpl(
   1240      cx, &fc, cx->tempLifoAlloc(), input.get(), &scopeCache, srcBuf);
   1241  if (!stencil) {
   1242    return nullptr;
   1243  }
   1244  return CreateInitialStencilAndDelazifications(&fc, stencil.get());
   1245 }
   1246 
   1247 already_AddRefed<JS::Stencil> JS::CompileModuleScriptToStencil(
   1248    JSContext* cx, const JS::ReadOnlyCompileOptions& options,
   1249    JS::SourceText<mozilla::Utf8Unit>& srcBuf) {
   1250  return CompileModuleScriptToStencilImpl(cx, options, srcBuf);
   1251 }
   1252 
   1253 already_AddRefed<JS::Stencil> JS::CompileModuleScriptToStencil(
   1254    JSContext* cx, const JS::ReadOnlyCompileOptions& options,
   1255    JS::SourceText<char16_t>& srcBuf) {
   1256  return CompileModuleScriptToStencilImpl(cx, options, srcBuf);
   1257 }
   1258 
   1259 template <typename CharT>
   1260 static already_AddRefed<JS::Stencil> CompileModuleScriptToStencilImpl(
   1261    JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& optionsInput,
   1262    JS::SourceText<CharT>& srcBuf) {
   1263  JS::CompileOptions options(nullptr, optionsInput);
   1264  options.setModule();
   1265 
   1266  frontend::CompilationInput compilationInput(options);
   1267 
   1268  NoScopeBindingCache scopeCache;
   1269  js::LifoAlloc tempLifoAlloc(JSContext::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE,
   1270                              js::BackgroundMallocArena);
   1271  RefPtr<CompilationStencil> stencil = ParseModuleToStencilImpl(
   1272      nullptr, fc, tempLifoAlloc, compilationInput, &scopeCache, srcBuf);
   1273  if (!stencil) {
   1274    JS_HAZ_VALUE_IS_GC_SAFE(compilationInput);
   1275    return nullptr;
   1276  }
   1277  // CompilationInput initialized with ParseModuleToStencil only
   1278  // references information from the JS::Stencil context and the
   1279  // ref-counted ScriptSource, which are both GC-free.
   1280  JS_HAZ_VALUE_IS_GC_SAFE(compilationInput);
   1281  return CreateInitialStencilAndDelazifications(fc, stencil.get());
   1282 }
   1283 
   1284 already_AddRefed<JS::Stencil> JS::CompileModuleScriptToStencil(
   1285    JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& optionsInput,
   1286    JS::SourceText<mozilla::Utf8Unit>& srcBuf) {
   1287 #ifdef DEBUG
   1288  fc->assertNativeStackLimitThread();
   1289 #endif
   1290  return CompileModuleScriptToStencilImpl(fc, optionsInput, srcBuf);
   1291 }
   1292 
   1293 already_AddRefed<JS::Stencil> JS::CompileModuleScriptToStencil(
   1294    JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& optionsInput,
   1295    JS::SourceText<char16_t>& srcBuf) {
   1296 #ifdef DEBUG
   1297  fc->assertNativeStackLimitThread();
   1298 #endif
   1299  return CompileModuleScriptToStencilImpl(fc, optionsInput, srcBuf);
   1300 }
   1301 
   1302 template <typename Unit>
   1303 static ModuleObject* CompileModuleImpl(
   1304    JSContext* cx, FrontendContext* fc,
   1305    const JS::ReadOnlyCompileOptions& optionsInput, SourceText<Unit>& srcBuf) {
   1306  AutoAssertReportedException assertException(cx, fc);
   1307 
   1308  CompileOptions options(cx, optionsInput);
   1309  options.setModule();
   1310 
   1311  Rooted<CompilationInput> input(cx, CompilationInput(options));
   1312  Rooted<CompilationGCOutput> gcOutput(cx);
   1313  BytecodeCompilerOutput output(gcOutput.address());
   1314 
   1315  NoScopeBindingCache scopeCache;
   1316  if (!ParseModuleToStencilAndMaybeInstantiate(cx, fc, cx->tempLifoAlloc(),
   1317                                               input.get(), &scopeCache, srcBuf,
   1318                                               output)) {
   1319    return nullptr;
   1320  }
   1321 
   1322  assertException.reset();
   1323  return gcOutput.get().module;
   1324 }
   1325 
   1326 ModuleObject* frontend::CompileModule(JSContext* cx, FrontendContext* fc,
   1327                                      const JS::ReadOnlyCompileOptions& options,
   1328                                      SourceText<char16_t>& srcBuf) {
   1329  return CompileModuleImpl(cx, fc, options, srcBuf);
   1330 }
   1331 
   1332 ModuleObject* frontend::CompileModule(JSContext* cx, FrontendContext* fc,
   1333                                      const JS::ReadOnlyCompileOptions& options,
   1334                                      SourceText<Utf8Unit>& srcBuf) {
   1335  return CompileModuleImpl(cx, fc, options, srcBuf);
   1336 }
   1337 
   1338 static bool InstantiateLazyFunction(JSContext* cx, CompilationInput& input,
   1339                                    const CompilationStencil& stencil) {
   1340  mozilla::DebugOnly<uint32_t> lazyFlags =
   1341      static_cast<uint32_t>(input.immutableFlags());
   1342 
   1343  Rooted<CompilationGCOutput> gcOutput(cx);
   1344 
   1345  if (!CompilationStencil::instantiateStencils(cx, input, stencil,
   1346                                               gcOutput.get())) {
   1347    return false;
   1348  }
   1349 
   1350  // NOTE: After instantiation succeeds and bytecode is attached, the rest of
   1351  //       this operation should be infallible. Any failure during
   1352  //       delazification should restore the function back to a consistent
   1353  //       lazy state.
   1354 
   1355  MOZ_ASSERT(lazyFlags == gcOutput.get().script->immutableFlags());
   1356  MOZ_ASSERT(gcOutput.get().script->outermostScope()->hasOnChain(
   1357                 ScopeKind::NonSyntactic) ==
   1358             gcOutput.get().script->immutableFlags().hasFlag(
   1359                 JSScript::ImmutableFlags::HasNonSyntacticScope));
   1360 
   1361  return true;
   1362 }
   1363 
   1364 // Compile lazy functinn specified by a pair of `units` + `length`, and
   1365 // optionally instantiate.
   1366 //
   1367 // If `stencils` is provided, the result of delazification is stored into it.
   1368 //
   1369 // If `borrowOut` is provided, a borrowing pointer is returned.
   1370 //
   1371 // If `borrowOut` is not provided, the function is instantiated.
   1372 // In this case, `maybeCx` should be provided and `input` should be initialized
   1373 // with a BaseScript.
   1374 template <typename Unit>
   1375 static bool CompileLazyFunctionToStencilMaybeInstantiate(
   1376    JSContext* maybeCx, FrontendContext* fc, js::LifoAlloc& tempLifoAlloc,
   1377    CompilationInput& input, ScopeBindingCache* scopeCache, const Unit* units,
   1378    size_t length, InitialStencilAndDelazifications* stencils,
   1379    const CompilationStencil** borrowOut) {
   1380  MOZ_ASSERT(input.source);
   1381 
   1382  AutoAssertReportedException assertException(maybeCx, fc);
   1383 
   1384  InheritThis inheritThis =
   1385      input.functionFlags().isArrow() ? InheritThis::Yes : InheritThis::No;
   1386 
   1387  LifoAllocScope parserAllocScope(&tempLifoAlloc);
   1388  CompilationState compilationState(fc, parserAllocScope, input);
   1389  compilationState.setFunctionKey(input.extent());
   1390  MOZ_ASSERT(!compilationState.isInitialStencil());
   1391  if (!compilationState.init(fc, scopeCache, inheritThis)) {
   1392    return false;
   1393  }
   1394 
   1395  Parser<FullParseHandler, Unit> parser(fc, input.options, units, length,
   1396                                        compilationState,
   1397                                        /* syntaxParser = */ nullptr);
   1398  if (!parser.checkOptions()) {
   1399    return false;
   1400  }
   1401 
   1402  FunctionNode* pn =
   1403      parser
   1404          .standaloneLazyFunction(input, input.extent().toStringStart,
   1405                                  input.strict(), input.generatorKind(),
   1406                                  input.asyncKind())
   1407          .unwrapOr(nullptr);
   1408  if (!pn) {
   1409    return false;
   1410  }
   1411 
   1412  BytecodeEmitter bce(fc, &parser, pn->funbox(), compilationState,
   1413                      BytecodeEmitter::LazyFunction);
   1414  if (!bce.init(pn->pn_pos)) {
   1415    return false;
   1416  }
   1417 
   1418  if (!bce.emitFunctionScript(pn)) {
   1419    return false;
   1420  }
   1421 
   1422  // NOTE: Only allow relazification if there was no lazy PrivateScriptData.
   1423  // This excludes non-leaf functions and all script class constructors.
   1424  bool hadLazyScriptData = input.hasPrivateScriptData();
   1425  bool isRelazifiableAfterDelazify = input.isRelazifiable();
   1426  if (isRelazifiableAfterDelazify && !hadLazyScriptData) {
   1427    compilationState.scriptData[CompilationStencil::TopLevelIndex]
   1428        .setAllowRelazify();
   1429  }
   1430 
   1431  if (stencils && input.options.checkDelazificationCache()) {
   1432    const CompilationStencil* cached =
   1433        stencils->getDelazificationFor(input.extent());
   1434    if (cached) {
   1435      auto& concurrentSharedData = cached->sharedData;
   1436      auto concurrentData =
   1437          concurrentSharedData.isSingle()
   1438              ? concurrentSharedData.asSingle()->get()->immutableData()
   1439              : concurrentSharedData.asBorrow()
   1440                    ->asSingle()
   1441                    ->get()
   1442                    ->immutableData();
   1443      auto ondemandData =
   1444          compilationState.sharedData.asSingle()->get()->immutableData();
   1445      MOZ_RELEASE_ASSERT(concurrentData.Length() == ondemandData.Length(),
   1446                         "Non-deterministic stencils");
   1447      for (size_t i = 0; i < concurrentData.Length(); i++) {
   1448        MOZ_RELEASE_ASSERT(concurrentData[i] == ondemandData[i],
   1449                           "Non-deterministic stencils");
   1450      }
   1451    }
   1452  }
   1453 
   1454  if (borrowOut) {
   1455    auto extensibleStencil =
   1456        fc->getAllocator()->make_unique<frontend::ExtensibleCompilationStencil>(
   1457            std::move(compilationState));
   1458    if (!extensibleStencil) {
   1459      return false;
   1460    }
   1461 
   1462    RefPtr<CompilationStencil> stencil =
   1463        fc->getAllocator()->new_<CompilationStencil>(
   1464            std::move(extensibleStencil));
   1465    if (!stencil) {
   1466      return false;
   1467    }
   1468 
   1469    *borrowOut = stencils->storeDelazification(std::move(stencil));
   1470  } else {
   1471    MOZ_ASSERT(maybeCx);
   1472    if (stencils) {
   1473      auto extensibleStencil =
   1474          maybeCx->make_unique<frontend::ExtensibleCompilationStencil>(
   1475              std::move(compilationState));
   1476      if (!extensibleStencil) {
   1477        return false;
   1478      }
   1479 
   1480      RefPtr<CompilationStencil> stencil =
   1481          maybeCx->new_<CompilationStencil>(std::move(extensibleStencil));
   1482      if (!stencil) {
   1483        return false;
   1484      }
   1485 
   1486      const CompilationStencil* borrowed =
   1487          stencils->storeDelazification(std::move(stencil));
   1488 
   1489      if (!InstantiateLazyFunction(maybeCx, input, *borrowed)) {
   1490        return false;
   1491      }
   1492    } else {
   1493      BorrowingCompilationStencil borrowingStencil(compilationState);
   1494      if (!InstantiateLazyFunction(maybeCx, input, borrowingStencil)) {
   1495        return false;
   1496      }
   1497    }
   1498  }
   1499 
   1500  assertException.reset();
   1501  return true;
   1502 }
   1503 
   1504 template <typename Unit>
   1505 static bool DelazifyCanonicalScriptedFunctionImpl(JSContext* cx,
   1506                                                  FrontendContext* fc,
   1507                                                  ScopeBindingCache* scopeCache,
   1508                                                  JS::Handle<JSFunction*> fun,
   1509                                                  JS::Handle<BaseScript*> lazy,
   1510                                                  ScriptSource* ss) {
   1511  MOZ_ASSERT(!lazy->hasBytecode(), "Script is already compiled!");
   1512  MOZ_ASSERT(lazy->function() == fun);
   1513 
   1514  MOZ_DIAGNOSTIC_ASSERT(!fun->isGhost());
   1515 
   1516  AutoIncrementalTimer timer(cx->realm()->timers.delazificationTime);
   1517 
   1518  JS::CompileOptions options(cx);
   1519  options.setMutedErrors(lazy->mutedErrors())
   1520      .setFileAndLine(lazy->filename(), lazy->lineno())
   1521      .setColumn(JS::ColumnNumberOneOrigin(lazy->column()))
   1522      .setScriptSourceOffset(lazy->sourceStart())
   1523      .setNoScriptRval(false)
   1524      .setSelfHostingMode(false)
   1525      .setEagerDelazificationStrategy(lazy->delazificationMode())
   1526      .setEagerBaselineStrategy(JS::EagerBaselineOption::None);
   1527 
   1528  Rooted<CompilationInput> input(cx, CompilationInput(options));
   1529  input.get().initFromLazy(cx, lazy, ss);
   1530 
   1531  RefPtr<InitialStencilAndDelazifications> stencils =
   1532      lazy->sourceObject()->maybeGetStencils();
   1533 
   1534  if (stencils && input.get().options.consumeDelazificationCache()) {
   1535    const CompilationStencil* cached =
   1536        stencils->getDelazificationFor(input.get().extent());
   1537    if (cached) {
   1538      return InstantiateLazyFunction(cx, input.get(), *cached);
   1539    }
   1540  }
   1541 
   1542  size_t sourceStart = lazy->sourceStart();
   1543  size_t sourceLength = lazy->sourceEnd() - lazy->sourceStart();
   1544 
   1545  MOZ_ASSERT(ss->hasSourceText());
   1546 
   1547  // Parse and compile the script from source.
   1548  UncompressedSourceCache::AutoHoldEntry holder;
   1549 
   1550  MOZ_ASSERT(ss->hasSourceType<Unit>());
   1551 
   1552  ScriptSource::PinnedUnits<Unit> units(cx, ss, holder, sourceStart,
   1553                                        sourceLength);
   1554  if (!units.get()) {
   1555    return false;
   1556  }
   1557 
   1558  return CompileLazyFunctionToStencilMaybeInstantiate(
   1559      cx, fc, cx->tempLifoAlloc(), input.get(), scopeCache, units.get(),
   1560      sourceLength, stencils, nullptr);
   1561 }
   1562 
   1563 bool frontend::DelazifyCanonicalScriptedFunction(JSContext* cx,
   1564                                                 FrontendContext* fc,
   1565                                                 JS::Handle<JSFunction*> fun) {
   1566  Maybe<AutoGeckoProfilerEntry> pseudoFrame;
   1567  if (cx) {
   1568    pseudoFrame.emplace(cx, "script delazify",
   1569                        JS::ProfilingCategoryPair::JS_Parsing);
   1570  }
   1571 
   1572  Rooted<BaseScript*> lazy(cx, fun->baseScript());
   1573  ScriptSource* ss = lazy->scriptSource();
   1574  ScopeBindingCache* scopeCache = &cx->caches().scopeCache;
   1575 
   1576  if (ss->hasSourceType<Utf8Unit>()) {
   1577    // UTF-8 source text.
   1578    return DelazifyCanonicalScriptedFunctionImpl<Utf8Unit>(cx, fc, scopeCache,
   1579                                                           fun, lazy, ss);
   1580  }
   1581 
   1582  MOZ_ASSERT(ss->hasSourceType<char16_t>());
   1583 
   1584  // UTF-16 source text.
   1585  return DelazifyCanonicalScriptedFunctionImpl<char16_t>(cx, fc, scopeCache,
   1586                                                         fun, lazy, ss);
   1587 }
   1588 
   1589 template <typename Unit>
   1590 static const CompilationStencil* DelazifyCanonicalScriptedFunctionImpl(
   1591    FrontendContext* fc, js::LifoAlloc& tempLifoAlloc,
   1592    const JS::PrefableCompileOptions& prefableOptions,
   1593    ScopeBindingCache* scopeCache, ScriptIndex scriptIndex,
   1594    InitialStencilAndDelazifications* stencils,
   1595    DelazifyFailureReason* failureReason) {
   1596  MOZ_ASSERT(stencils);
   1597 
   1598  ScriptStencilRef script{*stencils, scriptIndex};
   1599  const CompilationStencil* cached = script.maybeContext();
   1600  if (cached) {
   1601    return cached;
   1602  }
   1603 
   1604  const ScriptStencilExtra& extra = script.scriptExtra();
   1605 
   1606 #if defined(EARLY_BETA_OR_EARLIER) || defined(DEBUG)
   1607  MOZ_ASSERT(!script.isEagerlyCompiledInInitial(),
   1608             "Script is already compiled in initial stencil!");
   1609  const ScriptStencil& data = script.scriptDataFromEnclosing();
   1610  MOZ_DIAGNOSTIC_ASSERT(!data.isGhost());
   1611  MOZ_DIAGNOSTIC_ASSERT(data.wasEmittedByEnclosingScript());
   1612 #endif
   1613 
   1614  size_t sourceStart = extra.extent.sourceStart;
   1615  size_t sourceLength = extra.extent.sourceEnd - sourceStart;
   1616 
   1617  ScriptSource* ss = stencils->getInitial()->source;
   1618  MOZ_ASSERT(ss->hasSourceText());
   1619 
   1620  MOZ_ASSERT(ss->hasSourceType<Unit>());
   1621 
   1622  ScriptSource::PinnedUnitsIfUncompressed<Unit> units(ss, sourceStart,
   1623                                                      sourceLength);
   1624  if (!units.get()) {
   1625    *failureReason = DelazifyFailureReason::Compressed;
   1626    return nullptr;
   1627  }
   1628 
   1629  JS::CompileOptions options(prefableOptions);
   1630  options.setMutedErrors(ss->mutedErrors())
   1631      .setFileAndLine(ss->filename(), extra.extent.lineno)
   1632      .setColumn(JS::ColumnNumberOneOrigin(extra.extent.column))
   1633      .setScriptSourceOffset(sourceStart)
   1634      .setNoScriptRval(false)
   1635      .setSelfHostingMode(false);
   1636 
   1637  // CompilationInput initialized with initFromStencil only reference
   1638  // information from the CompilationStencil context and the ref-counted
   1639  // ScriptSource, which are both GC-free.
   1640  JS_HAZ_NON_GC_POINTER CompilationInput input(options);
   1641  input.initFromStencil(*stencils, scriptIndex, ss);
   1642 
   1643  const CompilationStencil* borrow;
   1644  if (!CompileLazyFunctionToStencilMaybeInstantiate(
   1645          nullptr, fc, tempLifoAlloc, input, scopeCache, units.get(),
   1646          sourceLength, stencils, &borrow)) {
   1647    *failureReason = DelazifyFailureReason::Other;
   1648    return nullptr;
   1649  }
   1650 
   1651  return borrow;
   1652 }
   1653 
   1654 const CompilationStencil* frontend::DelazifyCanonicalScriptedFunction(
   1655    FrontendContext* fc, js::LifoAlloc& tempLifoAlloc,
   1656    const JS::PrefableCompileOptions& prefableOptions,
   1657    ScopeBindingCache* scopeCache, ScriptIndex scriptIndex,
   1658    InitialStencilAndDelazifications* stencils,
   1659    DelazifyFailureReason* failureReason) {
   1660  ScriptSource* ss = stencils->getInitial()->source;
   1661  if (ss->hasSourceType<Utf8Unit>()) {
   1662    // UTF-8 source text.
   1663    return DelazifyCanonicalScriptedFunctionImpl<Utf8Unit>(
   1664        fc, tempLifoAlloc, prefableOptions, scopeCache, scriptIndex, stencils,
   1665        failureReason);
   1666  }
   1667 
   1668  // UTF-16 source text.
   1669  MOZ_ASSERT(ss->hasSourceType<char16_t>());
   1670  return DelazifyCanonicalScriptedFunctionImpl<char16_t>(
   1671      fc, tempLifoAlloc, prefableOptions, scopeCache, scriptIndex, stencils,
   1672      failureReason);
   1673 }
   1674 
   1675 static JSFunction* CompileStandaloneFunction(
   1676    JSContext* cx, const JS::ReadOnlyCompileOptions& options,
   1677    JS::SourceText<char16_t>& srcBuf, const Maybe<uint32_t>& parameterListEnd,
   1678    FunctionSyntaxKind syntaxKind, GeneratorKind generatorKind,
   1679    FunctionAsyncKind asyncKind, JS::Handle<Scope*> enclosingScope = nullptr) {
   1680  JS::Rooted<JSFunction*> fun(cx);
   1681  {
   1682    AutoReportFrontendContext fc(cx);
   1683    AutoAssertReportedException assertException(cx, &fc);
   1684 
   1685    Rooted<CompilationInput> input(cx, CompilationInput(options));
   1686    if (enclosingScope) {
   1687      if (!input.get().initForStandaloneFunctionInNonSyntacticScope(
   1688              &fc, enclosingScope)) {
   1689        return nullptr;
   1690      }
   1691    } else {
   1692      if (!input.get().initForStandaloneFunction(cx, &fc)) {
   1693        return nullptr;
   1694      }
   1695    }
   1696 
   1697    LifoAllocScope parserAllocScope(&cx->tempLifoAlloc());
   1698    InheritThis inheritThis = (syntaxKind == FunctionSyntaxKind::Arrow)
   1699                                  ? InheritThis::Yes
   1700                                  : InheritThis::No;
   1701    ScopeBindingCache* scopeCache = &cx->caches().scopeCache;
   1702    StandaloneFunctionCompiler<char16_t> compiler(&fc, parserAllocScope,
   1703                                                  input.get(), srcBuf);
   1704    if (!compiler.init(&fc, scopeCache, inheritThis)) {
   1705      return nullptr;
   1706    }
   1707 
   1708    if (!compiler.compile(cx, syntaxKind, generatorKind, asyncKind,
   1709                          parameterListEnd)) {
   1710      return nullptr;
   1711    }
   1712 
   1713    Rooted<CompilationGCOutput> gcOutput(cx);
   1714    RefPtr<ScriptSource> source;
   1715    {
   1716      BorrowingCompilationStencil borrowingStencil(compiler.stencil());
   1717      if (!CompilationStencil::instantiateStencils(
   1718              cx, input.get(), borrowingStencil, gcOutput.get())) {
   1719        return nullptr;
   1720      }
   1721      source = borrowingStencil.source;
   1722    }
   1723 
   1724    fun = gcOutput.get().getFunctionNoBaseIndex(
   1725        CompilationStencil::TopLevelIndex);
   1726    MOZ_ASSERT(fun->hasBytecode() || IsAsmJSModule(fun));
   1727 
   1728    // Enqueue an off-thread source compression task after finishing parsing.
   1729    if (!source->tryCompressOffThread(cx)) {
   1730      return nullptr;
   1731    }
   1732 
   1733    // Note: If AsmJS successfully compiles, the into.script will still be
   1734    // nullptr. In this case we have compiled to a native function instead of an
   1735    // interpreted script.
   1736    if (gcOutput.get().script) {
   1737      if (parameterListEnd) {
   1738        source->setParameterListEnd(*parameterListEnd);
   1739      }
   1740 
   1741      const JS::InstantiateOptions instantiateOptions(options);
   1742      Rooted<JSScript*> script(cx, gcOutput.get().script);
   1743      FireOnNewScript(cx, instantiateOptions, script);
   1744    }
   1745 
   1746    assertException.reset();
   1747  }
   1748  return fun;
   1749 }
   1750 
   1751 JSFunction* frontend::CompileStandaloneFunction(
   1752    JSContext* cx, const JS::ReadOnlyCompileOptions& options,
   1753    JS::SourceText<char16_t>& srcBuf, const Maybe<uint32_t>& parameterListEnd,
   1754    FunctionSyntaxKind syntaxKind) {
   1755  return CompileStandaloneFunction(cx, options, srcBuf, parameterListEnd,
   1756                                   syntaxKind, GeneratorKind::NotGenerator,
   1757                                   FunctionAsyncKind::SyncFunction);
   1758 }
   1759 
   1760 JSFunction* frontend::CompileStandaloneGenerator(
   1761    JSContext* cx, const JS::ReadOnlyCompileOptions& options,
   1762    JS::SourceText<char16_t>& srcBuf, const Maybe<uint32_t>& parameterListEnd,
   1763    FunctionSyntaxKind syntaxKind) {
   1764  return CompileStandaloneFunction(cx, options, srcBuf, parameterListEnd,
   1765                                   syntaxKind, GeneratorKind::Generator,
   1766                                   FunctionAsyncKind::SyncFunction);
   1767 }
   1768 
   1769 JSFunction* frontend::CompileStandaloneAsyncFunction(
   1770    JSContext* cx, const ReadOnlyCompileOptions& options,
   1771    JS::SourceText<char16_t>& srcBuf, const Maybe<uint32_t>& parameterListEnd,
   1772    FunctionSyntaxKind syntaxKind) {
   1773  return CompileStandaloneFunction(cx, options, srcBuf, parameterListEnd,
   1774                                   syntaxKind, GeneratorKind::NotGenerator,
   1775                                   FunctionAsyncKind::AsyncFunction);
   1776 }
   1777 
   1778 JSFunction* frontend::CompileStandaloneAsyncGenerator(
   1779    JSContext* cx, const ReadOnlyCompileOptions& options,
   1780    JS::SourceText<char16_t>& srcBuf, const Maybe<uint32_t>& parameterListEnd,
   1781    FunctionSyntaxKind syntaxKind) {
   1782  return CompileStandaloneFunction(cx, options, srcBuf, parameterListEnd,
   1783                                   syntaxKind, GeneratorKind::Generator,
   1784                                   FunctionAsyncKind::AsyncFunction);
   1785 }
   1786 
   1787 JSFunction* frontend::CompileStandaloneFunctionInNonSyntacticScope(
   1788    JSContext* cx, const JS::ReadOnlyCompileOptions& options,
   1789    JS::SourceText<char16_t>& srcBuf, const Maybe<uint32_t>& parameterListEnd,
   1790    FunctionSyntaxKind syntaxKind, JS::Handle<Scope*> enclosingScope) {
   1791  MOZ_ASSERT(enclosingScope);
   1792  return CompileStandaloneFunction(cx, options, srcBuf, parameterListEnd,
   1793                                   syntaxKind, GeneratorKind::NotGenerator,
   1794                                   FunctionAsyncKind::SyncFunction,
   1795                                   enclosingScope);
   1796 }