tor-browser

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

Stencil.cpp (207164B)


      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/Stencil.h"
      8 
      9 #include "mozilla/Assertions.h"             // MOZ_RELEASE_ASSERT
     10 #include "mozilla/CheckedInt.h"             // mozilla::CheckedInt
     11 #include "mozilla/Maybe.h"                  // mozilla::Maybe
     12 #include "mozilla/OperatorNewExtensions.h"  // mozilla::KnownNotNull
     13 #include "mozilla/PodOperations.h"          // mozilla::PodCopy
     14 #include "mozilla/RefPtr.h"                 // RefPtr
     15 #include "mozilla/ScopeExit.h"              // mozilla::ScopeExit
     16 #include "mozilla/Sprintf.h"                // SprintfLiteral
     17 
     18 #include <algorithm>  // std::fill
     19 #include <string.h>   // strlen
     20 
     21 #include "ds/LifoAlloc.h"               // LifoAlloc
     22 #include "frontend/AbstractScopePtr.h"  // ScopeIndex
     23 #include "frontend/BytecodeCompiler.h"  // CompileGlobalScriptToStencil, InstantiateStencils, CanLazilyParse, ParseModuleToStencil
     24 #include "frontend/BytecodeSection.h"   // EmitScriptThingsVector
     25 #include "frontend/CompilationStencil.h"  // CompilationStencil, CompilationState, ExtensibleCompilationStencil, CompilationGCOutput, CompilationStencilMerger
     26 #include "frontend/FrontendContext.h"
     27 #include "frontend/NameAnalysisTypes.h"  // EnvironmentCoordinate
     28 #include "frontend/ParserAtom.h"  // ParserAtom, ParserAtomIndex, TaggedParserAtomIndex, ParserAtomsTable, Length{1,2,3}StaticParserString, InstantiateMarkedAtoms, InstantiateMarkedAtomsAsPermanent, GetWellKnownAtom
     29 #include "frontend/ScopeBindingCache.h"  // ScopeBindingCache
     30 #include "frontend/SharedContext.h"
     31 #include "frontend/StencilXdr.h"  // XDRStencilEncoder, XDRStencilDecoder
     32 #include "gc/AllocKind.h"         // gc::AllocKind
     33 #include "gc/Tracer.h"            // TraceNullableRoot
     34 #include "jit/BaselineCompileTask.h"  // BaselineCompileTask::OffThreadBaselineCompilationAvailable
     35 #include "jit/BaselineJIT.h"  // jit::BaselineScript, jit::CanBaselineInterpretScript
     36 #include "jit/JitContext.h"     // jit::MethodStatus
     37 #include "jit/JitRuntime.h"     // jit::JitRuntime
     38 #include "jit/JitScript.h"      // AutoKeepJitScripts
     39 #include "js/CallArgs.h"        // JSNative
     40 #include "js/CompileOptions.h"  // JS::DecodeOptions, JS::ReadOnlyDecodeOptions
     41 #include "js/DOMEventDispatch.h"            // TRACE_FOR_TEST_DOM
     42 #include "js/experimental/CompileScript.h"  // JS::PrepareForInstantiate
     43 #include "js/experimental/JSStencil.h"      // JS::Stencil
     44 #include "js/GCAPI.h"                       // JS::AutoCheckCannotGC
     45 #include "js/Prefs.h"                       // JS::Prefs
     46 #include "js/Printer.h"                     // js::Fprinter
     47 #include "js/RealmOptions.h"                // JS::RealmBehaviors
     48 #include "js/RootingAPI.h"                  // Rooted
     49 #include "js/Transcoding.h"                 // JS::TranscodeBuffer
     50 #include "js/Utility.h"                     // js_malloc, js_calloc, js_free
     51 #include "js/Value.h"                       // ObjectValue
     52 #include "js/WasmModule.h"                  // JS::WasmModule
     53 #include "vm/BigIntType.h"   // ParseBigIntLiteral, BigInt::createFromInt64
     54 #include "vm/BindingKind.h"  // BindingKind
     55 #include "vm/EnvironmentObject.h"
     56 #include "vm/GeneratorAndAsyncKind.h"  // GeneratorKind, FunctionAsyncKind
     57 #include "vm/JSAtomUtils.h"            // AtomToPrintableString
     58 #include "vm/JSContext.h"              // JSContext
     59 #include "vm/JSFunction.h"  // JSFunction, GetFunctionPrototype, NewFunctionWithProto
     60 #include "vm/JSObject.h"      // JSObject, TenuredObject
     61 #include "vm/JSONPrinter.h"   // js::JSONPrinter
     62 #include "vm/JSScript.h"      // BaseScript, JSScript
     63 #include "vm/Realm.h"         // JS::Realm
     64 #include "vm/RegExpObject.h"  // js::RegExpObject
     65 #include "vm/Scope.h"  // Scope, *Scope, ScopeKind::*, ScopeKindString, ScopeIter, ScopeKindIsCatch, BindingIter, GetScopeDataTrailingNames, SizeOfParserScopeData
     66 #include "vm/ScopeKind.h"    // ScopeKind
     67 #include "vm/SelfHosting.h"  // SetClonedSelfHostedFunctionName
     68 #include "vm/StaticStrings.h"
     69 #include "vm/StencilEnums.h"  // ImmutableScriptFlagsEnum
     70 #include "vm/StringType.h"    // JSAtom, js::CopyChars
     71 #include "wasm/AsmJS.h"       // InstantiateAsmJS
     72 
     73 #include "jit/JitHints-inl.h"          // JitHints::mightHaveEagerBaselineHint
     74 #include "jit/JitScript-inl.h"         // AutoKeepJitScripts constructor
     75 #include "vm/EnvironmentObject-inl.h"  // JSObject::enclosingEnvironment
     76 #include "vm/JSFunction-inl.h"         // JSFunction::create
     77 #include "vm/JSScript-inl.h"           // JSScript::baselineScript
     78 
     79 using namespace js;
     80 using namespace js::frontend;
     81 
     82 // These 2 functions are used to write the same code with lambda using auto
     83 // arguments. The auto argument type is set by the Variant.match function of the
     84 // InputScope variant. Thus dispatching to either a Scope* or to a
     85 // ScopeStencilRef. This function can then be used as a way to specialize the
     86 // code within the lambda without duplicating the code.
     87 //
     88 // Identically, an InputName is constructed using the scope type and the
     89 // matching binding name type. This way, functions which are called by this
     90 // lambda can manipulate an InputName and do not have to be duplicated.
     91 //
     92 // for (InputScopeIter si(...); si; si++) {
     93 //   si.scope().match([](auto& scope) {
     94 //     for (auto bi = InputBindingIter(scope); bi; bi++) {
     95 //       InputName name(scope, bi.name());
     96 //     }
     97 //   });
     98 // }
     99 static js::BindingIter InputBindingIter(Scope* ptr) {
    100  return js::BindingIter(ptr);
    101 }
    102 
    103 static ParserBindingIter InputBindingIter(const ScopeStencilRef& ref) {
    104  return ParserBindingIter(ref);
    105 }
    106 
    107 static ParserBindingIter InputBindingIter(const FakeStencilGlobalScope&) {
    108  MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("No bindings on empty global.");
    109 }
    110 
    111 InputName InputScript::displayAtom() const {
    112  return script_.match(
    113      [](BaseScript* ptr) {
    114        return InputName(ptr, ptr->function()->fullDisplayAtom());
    115      },
    116      [](const ScriptStencilRef& ref) {
    117        auto& scriptData = ref.scriptDataFromEnclosing();
    118        return InputName(ref.enclosingScript(), scriptData.functionAtom);
    119      });
    120 }
    121 
    122 TaggedParserAtomIndex InputName::internInto(FrontendContext* fc,
    123                                            ParserAtomsTable& parserAtoms,
    124                                            CompilationAtomCache& atomCache) {
    125  return variant_.match(
    126      [&](JSAtom* ptr) -> TaggedParserAtomIndex {
    127        return parserAtoms.internJSAtom(fc, atomCache, ptr);
    128      },
    129      [&](NameStencilRef& ref) -> TaggedParserAtomIndex {
    130        return parserAtoms.internExternalParserAtomIndex(fc, ref.context_,
    131                                                         ref.atomIndex_);
    132      });
    133 }
    134 
    135 bool InputName::isEqualTo(FrontendContext* fc, ParserAtomsTable& parserAtoms,
    136                          CompilationAtomCache& atomCache,
    137                          TaggedParserAtomIndex other,
    138                          JSAtom** otherCached) const {
    139  return variant_.match(
    140      [&](const JSAtom* ptr) -> bool {
    141        if (ptr->hash() != parserAtoms.hash(other)) {
    142          return false;
    143        }
    144 
    145        // JSAtom variant is used only on the main thread delazification,
    146        // where JSContext is always available.
    147        JSContext* cx = fc->maybeCurrentJSContext();
    148        MOZ_ASSERT(cx);
    149 
    150        if (!*otherCached) {
    151          // TODO-Stencil:
    152          // Here, we convert our name into a JSAtom*, and hard-crash on failure
    153          // to allocate. This conversion should not be required as we should be
    154          // able to iterate up snapshotted scope chains that use parser atoms.
    155          //
    156          // This will be fixed when the enclosing scopes are snapshotted.
    157          //
    158          // See bug 1690277.
    159          AutoEnterOOMUnsafeRegion oomUnsafe;
    160          *otherCached = parserAtoms.toJSAtom(cx, fc, other, atomCache);
    161          if (!*otherCached) {
    162            oomUnsafe.crash("InputName::isEqualTo");
    163          }
    164        } else {
    165          MOZ_ASSERT(atomCache.getExistingAtomAt(cx, other) == *otherCached);
    166        }
    167        return ptr == *otherCached;
    168      },
    169      [&](const NameStencilRef& ref) -> bool {
    170        return parserAtoms.isEqualToExternalParserAtomIndex(other, ref.context_,
    171                                                            ref.atomIndex_);
    172      });
    173 }
    174 
    175 GenericAtom::GenericAtom(FrontendContext* fc, ParserAtomsTable& parserAtoms,
    176                         CompilationAtomCache& atomCache,
    177                         TaggedParserAtomIndex index)
    178    : ref(EmitterName(fc, parserAtoms, atomCache, index)) {
    179  hash = parserAtoms.hash(index);
    180 }
    181 
    182 GenericAtom::GenericAtom(const CompilationStencil& context,
    183                         TaggedParserAtomIndex index)
    184    : ref(StencilName{context, index}) {
    185  if (index.isParserAtomIndex()) {
    186    ParserAtom* atom = context.parserAtomData[index.toParserAtomIndex()];
    187    hash = atom->hash();
    188  } else {
    189    hash = index.staticOrWellKnownHash();
    190  }
    191 }
    192 
    193 GenericAtom::GenericAtom(ScopeStencilRef& scope, TaggedParserAtomIndex index)
    194    : GenericAtom(*scope.context(), index) {}
    195 
    196 BindingHasher<TaggedParserAtomIndex>::Lookup::Lookup(ScopeStencilRef& scope_ref,
    197                                                     const GenericAtom& other)
    198    : keyStencil(*scope_ref.context()), other(other) {}
    199 
    200 bool GenericAtom::operator==(const GenericAtom& other) const {
    201  return ref.match(
    202      [&other](const EmitterName& name) -> bool {
    203        return other.ref.match(
    204            [&name](const EmitterName& other) -> bool {
    205              // We never have multiple Emitter context at the same time.
    206              MOZ_ASSERT(name.fc == other.fc);
    207              MOZ_ASSERT(&name.parserAtoms == &other.parserAtoms);
    208              MOZ_ASSERT(&name.atomCache == &other.atomCache);
    209              return name.index == other.index;
    210            },
    211            [&name](const StencilName& other) -> bool {
    212              return name.parserAtoms.isEqualToExternalParserAtomIndex(
    213                  name.index, other.stencil, other.index);
    214            },
    215            [&name](JSAtom* other) -> bool {
    216              // JSAtom variant is used only on the main thread delazification,
    217              // where JSContext is always available.
    218              JSContext* cx = name.fc->maybeCurrentJSContext();
    219              MOZ_ASSERT(cx);
    220              AutoEnterOOMUnsafeRegion oomUnsafe;
    221              JSAtom* namePtr = name.parserAtoms.toJSAtom(
    222                  cx, name.fc, name.index, name.atomCache);
    223              if (!namePtr) {
    224                oomUnsafe.crash("GenericAtom(EmitterName == JSAtom*)");
    225              }
    226              return namePtr == other;
    227            });
    228      },
    229      [&other](const StencilName& name) -> bool {
    230        return other.ref.match(
    231            [&name](const EmitterName& other) -> bool {
    232              return other.parserAtoms.isEqualToExternalParserAtomIndex(
    233                  other.index, name.stencil, name.index);
    234            },
    235            [&name](const StencilName& other) -> bool {
    236              // Technically it is possible to have multiple stencils, but in
    237              // this particular case let's assume we never encounter a case
    238              // where we are comparing names from different stencils.
    239              //
    240              // The reason this assumption is safe today is that we are only
    241              // using this in the context of a stencil-delazification, where
    242              // the only StencilNames are coming from the CompilationStencil
    243              // provided to CompilationInput::initFromStencil.
    244              MOZ_ASSERT(&name.stencil == &other.stencil);
    245              return name.index == other.index;
    246            },
    247            [](JSAtom* other) -> bool {
    248              MOZ_CRASH("Never used.");
    249              return false;
    250            });
    251      },
    252      [&other](JSAtom* name) -> bool {
    253        return other.ref.match(
    254            [&name](const EmitterName& other) -> bool {
    255              // JSAtom variant is used only on the main thread delazification,
    256              // where JSContext is always available.
    257              JSContext* cx = other.fc->maybeCurrentJSContext();
    258              MOZ_ASSERT(cx);
    259              AutoEnterOOMUnsafeRegion oomUnsafe;
    260              JSAtom* otherPtr = other.parserAtoms.toJSAtom(
    261                  cx, other.fc, other.index, other.atomCache);
    262              if (!otherPtr) {
    263                oomUnsafe.crash("GenericAtom(JSAtom* == EmitterName)");
    264              }
    265              return name == otherPtr;
    266            },
    267            [](const StencilName& other) -> bool {
    268              MOZ_CRASH("Never used.");
    269              return false;
    270            },
    271            [&name](JSAtom* other) -> bool { return name == other; });
    272      });
    273 }
    274 
    275 #ifdef DEBUG
    276 template <typename SpanT, typename VecT>
    277 void AssertBorrowingSpan(const SpanT& span, const VecT& vec) {
    278  MOZ_ASSERT(span.size() == vec.length());
    279  MOZ_ASSERT(span.data() == vec.begin());
    280 }
    281 #endif
    282 
    283 bool ScopeBindingCache::canCacheFor(Scope* ptr) {
    284  MOZ_CRASH("Unexpected scope chain type: Scope*");
    285 }
    286 
    287 bool ScopeBindingCache::canCacheFor(ScopeStencilRef ref) {
    288  MOZ_CRASH("Unexpected scope chain type: ScopeStencilRef");
    289 }
    290 
    291 bool ScopeBindingCache::canCacheFor(const FakeStencilGlobalScope& ref) {
    292  MOZ_CRASH("Unexpected scope chain type: FakeStencilGlobalScope");
    293 }
    294 
    295 BindingMap<JSAtom*>* ScopeBindingCache::createCacheFor(Scope* ptr) {
    296  MOZ_CRASH("Unexpected scope chain type: Scope*");
    297 }
    298 
    299 BindingMap<JSAtom*>* ScopeBindingCache::lookupScope(Scope* ptr,
    300                                                    CacheGeneration gen) {
    301  MOZ_CRASH("Unexpected scope chain type: Scope*");
    302 }
    303 
    304 BindingMap<TaggedParserAtomIndex>* ScopeBindingCache::createCacheFor(
    305    ScopeStencilRef ref) {
    306  MOZ_CRASH("Unexpected scope chain type: ScopeStencilRef");
    307 }
    308 
    309 BindingMap<TaggedParserAtomIndex>* ScopeBindingCache::lookupScope(
    310    ScopeStencilRef ref, CacheGeneration gen) {
    311  MOZ_CRASH("Unexpected scope chain type: ScopeStencilRef");
    312 }
    313 
    314 BindingMap<TaggedParserAtomIndex>* ScopeBindingCache::createCacheFor(
    315    const FakeStencilGlobalScope& ref) {
    316  MOZ_CRASH("Unexpected scope chain type: FakeStencilGlobalScope");
    317 }
    318 
    319 BindingMap<TaggedParserAtomIndex>* ScopeBindingCache::lookupScope(
    320    const FakeStencilGlobalScope& ref, CacheGeneration gen) {
    321  MOZ_CRASH("Unexpected scope chain type: FakeStencilGlobalScope");
    322 }
    323 
    324 bool NoScopeBindingCache::canCacheFor(Scope* ptr) { return false; }
    325 
    326 bool NoScopeBindingCache::canCacheFor(ScopeStencilRef ref) { return false; }
    327 
    328 bool NoScopeBindingCache::canCacheFor(const FakeStencilGlobalScope& ref) {
    329  return false;
    330 }
    331 
    332 bool RuntimeScopeBindingCache::canCacheFor(Scope* ptr) { return true; }
    333 
    334 BindingMap<JSAtom*>* RuntimeScopeBindingCache::createCacheFor(Scope* ptr) {
    335  BaseScopeData* dataPtr = ptr->rawData();
    336  BindingMap<JSAtom*> bindingCache;
    337  if (!scopeMap.putNew(dataPtr, std::move(bindingCache))) {
    338    return nullptr;
    339  }
    340 
    341  return lookupScope(ptr, cacheGeneration);
    342 }
    343 
    344 BindingMap<JSAtom*>* RuntimeScopeBindingCache::lookupScope(
    345    Scope* ptr, CacheGeneration gen) {
    346  MOZ_ASSERT(gen == cacheGeneration);
    347  BaseScopeData* dataPtr = ptr->rawData();
    348  auto valuePtr = scopeMap.lookup(dataPtr);
    349  if (!valuePtr) {
    350    return nullptr;
    351  }
    352  return &valuePtr->value();
    353 }
    354 
    355 bool StencilScopeBindingCache::canCacheFor(ScopeStencilRef ref) { return true; }
    356 
    357 BindingMap<TaggedParserAtomIndex>* StencilScopeBindingCache::createCacheFor(
    358    ScopeStencilRef ref) {
    359 #ifdef DEBUG
    360  MOZ_ASSERT(&ref.stencils_ == &stencils_);
    361  MOZ_ASSERT_IF(
    362      ref.stencils_.getInitial() != ref.context(),
    363      ref.stencils_.getScriptIndexFor(ref.context()) == ref.scriptIndex_);
    364 #endif
    365  auto* dataPtr = ref.context()->scopeNames[ref.scopeIndex_];
    366  BindingMap<TaggedParserAtomIndex> bindingCache;
    367  if (!scopeMap.putNew(dataPtr, std::move(bindingCache))) {
    368    return nullptr;
    369  }
    370 
    371  return lookupScope(ref, 1);
    372 }
    373 
    374 BindingMap<TaggedParserAtomIndex>* StencilScopeBindingCache::lookupScope(
    375    ScopeStencilRef ref, CacheGeneration gen) {
    376 #ifdef DEBUG
    377  MOZ_ASSERT(&ref.stencils_ == &stencils_);
    378  MOZ_ASSERT_IF(
    379      ref.stencils_.getInitial() != ref.context(),
    380      ref.stencils_.getScriptIndexFor(ref.context()) == ref.scriptIndex_);
    381 #endif
    382  auto* dataPtr = ref.context()->scopeNames[ref.scopeIndex_];
    383  auto ptr = scopeMap.lookup(dataPtr);
    384  if (!ptr) {
    385    return nullptr;
    386  }
    387  return &ptr->value();
    388 }
    389 
    390 static AbstractBaseScopeData<TaggedParserAtomIndex>
    391    moduleGlobalAbstractScopeData;
    392 
    393 bool StencilScopeBindingCache::canCacheFor(const FakeStencilGlobalScope& ref) {
    394  return true;
    395 }
    396 
    397 BindingMap<TaggedParserAtomIndex>* StencilScopeBindingCache::createCacheFor(
    398    const FakeStencilGlobalScope& ref) {
    399  auto* dataPtr = &moduleGlobalAbstractScopeData;
    400  BindingMap<TaggedParserAtomIndex> bindingCache;
    401  if (!scopeMap.putNew(dataPtr, std::move(bindingCache))) {
    402    return nullptr;
    403  }
    404 
    405  return lookupScope(ref, 1);
    406 }
    407 
    408 BindingMap<TaggedParserAtomIndex>* StencilScopeBindingCache::lookupScope(
    409    const FakeStencilGlobalScope& ref, CacheGeneration gen) {
    410  auto* dataPtr = &moduleGlobalAbstractScopeData;
    411  auto ptr = scopeMap.lookup(dataPtr);
    412  if (!ptr) {
    413    return nullptr;
    414  }
    415  return &ptr->value();
    416 }
    417 
    418 bool ScopeContext::init(FrontendContext* fc, CompilationInput& input,
    419                        ParserAtomsTable& parserAtoms,
    420                        ScopeBindingCache* scopeCache, InheritThis inheritThis,
    421                        JSObject* enclosingEnv) {
    422  // Record the scopeCache to be used while looking up NameLocation bindings.
    423  this->scopeCache = scopeCache;
    424  scopeCacheGen = scopeCache->getCurrentGeneration();
    425 
    426  InputScope maybeNonDefaultEnclosingScope(
    427      input.maybeNonDefaultEnclosingScope());
    428 
    429  // If this eval is in response to Debugger.Frame.eval, we may have an
    430  // incomplete scope chain. In order to provide a better debugging experience,
    431  // we inspect the (optional) environment chain to determine it's enclosing
    432  // FunctionScope if there is one. If there is no such scope, we use the
    433  // orignal scope provided.
    434  //
    435  // NOTE: This is used to compute the ThisBinding kind and to allow access to
    436  //       private fields and methods, while other contextual information only
    437  //       uses the actual scope passed to the compile.
    438  auto effectiveScope =
    439      determineEffectiveScope(maybeNonDefaultEnclosingScope, enclosingEnv);
    440 
    441  if (inheritThis == InheritThis::Yes) {
    442    computeThisBinding(effectiveScope);
    443    computeThisEnvironment(maybeNonDefaultEnclosingScope);
    444  }
    445  computeInScope(maybeNonDefaultEnclosingScope);
    446 
    447  cacheEnclosingScope(input.enclosingScope);
    448 
    449  if (input.target == CompilationInput::CompilationTarget::Eval) {
    450    if (!cacheEnclosingScopeBindingForEval(fc, input, parserAtoms)) {
    451      return false;
    452    }
    453    if (!cachePrivateFieldsForEval(fc, input, enclosingEnv, effectiveScope,
    454                                   parserAtoms)) {
    455      return false;
    456    }
    457  }
    458 
    459  return true;
    460 }
    461 
    462 void ScopeContext::computeThisEnvironment(const InputScope& enclosingScope) {
    463  uint32_t envCount = 0;
    464  for (InputScopeIter si(enclosingScope); si; si++) {
    465    if (si.kind() == ScopeKind::Function) {
    466      // Arrow function inherit the "this" environment of the enclosing script,
    467      // so continue ignore them.
    468      if (!si.scope().isArrow()) {
    469        allowNewTarget = true;
    470 
    471        if (si.scope().allowSuperProperty()) {
    472          allowSuperProperty = true;
    473          enclosingThisEnvironmentHops = envCount;
    474        }
    475 
    476        if (si.scope().isClassConstructor()) {
    477          memberInitializers =
    478              si.scope().useMemberInitializers()
    479                  ? mozilla::Some(si.scope().getMemberInitializers())
    480                  : mozilla::Some(MemberInitializers::Empty());
    481          MOZ_ASSERT(memberInitializers->valid);
    482        } else {
    483          if (si.scope().isSyntheticFunction()) {
    484            allowArguments = false;
    485          }
    486        }
    487 
    488        if (si.scope().isDerivedClassConstructor()) {
    489          allowSuperCall = true;
    490        }
    491 
    492        // Found the effective "this" environment, so stop.
    493        return;
    494      }
    495    }
    496 
    497    if (si.scope().hasEnvironment()) {
    498      envCount++;
    499    }
    500  }
    501 }
    502 
    503 void ScopeContext::computeThisBinding(const InputScope& scope) {
    504  // Inspect the scope-chain.
    505  for (InputScopeIter si(scope); si; si++) {
    506    if (si.kind() == ScopeKind::Module) {
    507      thisBinding = ThisBinding::Module;
    508      return;
    509    }
    510 
    511    if (si.kind() == ScopeKind::Function) {
    512      // Arrow functions don't have their own `this` binding.
    513      if (si.scope().isArrow()) {
    514        continue;
    515      }
    516 
    517      // Derived class constructors (and their nested arrow functions and evals)
    518      // use ThisBinding::DerivedConstructor, which ensures TDZ checks happen
    519      // when accessing |this|.
    520      if (si.scope().isDerivedClassConstructor()) {
    521        thisBinding = ThisBinding::DerivedConstructor;
    522      } else {
    523        thisBinding = ThisBinding::Function;
    524      }
    525 
    526      return;
    527    }
    528  }
    529 
    530  thisBinding = ThisBinding::Global;
    531 }
    532 
    533 void ScopeContext::computeInScope(const InputScope& enclosingScope) {
    534  for (InputScopeIter si(enclosingScope); si; si++) {
    535    if (si.kind() == ScopeKind::ClassBody) {
    536      inClass = true;
    537    }
    538 
    539    if (si.kind() == ScopeKind::With) {
    540      inWith = true;
    541    }
    542  }
    543 }
    544 
    545 void ScopeContext::cacheEnclosingScope(const InputScope& enclosingScope) {
    546  if (enclosingScope.isNull()) {
    547    return;
    548  }
    549 
    550  enclosingScopeEnvironmentChainLength =
    551      enclosingScope.environmentChainLength();
    552  enclosingScopeKind = enclosingScope.kind();
    553 
    554  if (enclosingScopeKind == ScopeKind::Function) {
    555    enclosingScopeIsArrow = enclosingScope.isArrow();
    556  }
    557 
    558  enclosingScopeHasEnvironment = enclosingScope.hasEnvironment();
    559 
    560 #ifdef DEBUG
    561  hasNonSyntacticScopeOnChain =
    562      enclosingScope.hasOnChain(ScopeKind::NonSyntactic);
    563 
    564  // This computes a general answer for the query "does the enclosing scope
    565  // have a function scope that needs a home object?", but it's only asserted
    566  // if the parser parses eval body that contains `super` that needs a home
    567  // object.
    568  for (InputScopeIter si(enclosingScope); si; si++) {
    569    if (si.kind() == ScopeKind::Function) {
    570      if (si.scope().isArrow()) {
    571        continue;
    572      }
    573      if (si.scope().allowSuperProperty() && si.scope().needsHomeObject()) {
    574        hasFunctionNeedsHomeObjectOnChain = true;
    575      }
    576      break;
    577    }
    578  }
    579 #endif
    580 
    581  // Pre-fill the scope cache by iterating over all the names. Stop iterating
    582  // as soon as we find a scope which already has a filled scope cache.
    583  AutoEnterOOMUnsafeRegion oomUnsafe;
    584  for (InputScopeIter si(enclosingScope); si; si++) {
    585    // If the current scope already exists, then there is no need to go deeper
    586    // as the scope which are encoded after this one should already be present
    587    // in the cache.
    588    bool hasScopeCache = si.scope().match([&](auto& scope_ref) -> bool {
    589      MOZ_ASSERT(scopeCache->canCacheFor(scope_ref));
    590      return scopeCache->lookupScope(scope_ref, scopeCacheGen);
    591    });
    592    if (hasScopeCache) {
    593      return;
    594    }
    595 
    596    bool hasEnv = si.hasSyntacticEnvironment();
    597    auto setCatchAll = [&](NameLocation loc) {
    598      return si.scope().match([&](auto& scope_ref) {
    599        using BindingMapPtr = decltype(scopeCache->createCacheFor(scope_ref));
    600        BindingMapPtr bindingMapPtr = scopeCache->createCacheFor(scope_ref);
    601        if (!bindingMapPtr) {
    602          oomUnsafe.crash(
    603              "ScopeContext::cacheEnclosingScope: scopeCache->createCacheFor");
    604          return;
    605        }
    606 
    607        bindingMapPtr->catchAll.emplace(loc);
    608      });
    609    };
    610    auto createEmpty = [&]() {
    611      return si.scope().match([&](auto& scope_ref) {
    612        using BindingMapPtr = decltype(scopeCache->createCacheFor(scope_ref));
    613        BindingMapPtr bindingMapPtr = scopeCache->createCacheFor(scope_ref);
    614        if (!bindingMapPtr) {
    615          oomUnsafe.crash(
    616              "ScopeContext::cacheEnclosingScope: scopeCache->createCacheFor");
    617          return;
    618        }
    619      });
    620    };
    621 
    622    switch (si.kind()) {
    623      case ScopeKind::Function:
    624        if (hasEnv) {
    625          if (si.scope().funHasExtensibleScope()) {
    626            setCatchAll(NameLocation::Dynamic());
    627            return;
    628          }
    629 
    630          si.scope().match([&](auto& scope_ref) {
    631            using BindingMapPtr =
    632                decltype(scopeCache->createCacheFor(scope_ref));
    633            using Lookup =
    634                typename std::remove_pointer_t<BindingMapPtr>::Lookup;
    635            BindingMapPtr bindingMapPtr = scopeCache->createCacheFor(scope_ref);
    636            if (!bindingMapPtr) {
    637              oomUnsafe.crash(
    638                  "ScopeContext::cacheEnclosingScope: "
    639                  "scopeCache->createCacheFor");
    640              return;
    641            }
    642 
    643            for (auto bi = InputBindingIter(scope_ref); bi; bi++) {
    644              NameLocation loc = bi.nameLocation();
    645              if (loc.kind() != NameLocation::Kind::EnvironmentCoordinate) {
    646                continue;
    647              }
    648              auto ctxFreeKey = bi.name();
    649              GenericAtom ctxKey(scope_ref, ctxFreeKey);
    650              Lookup ctxLookup(scope_ref, ctxKey);
    651              if (!bindingMapPtr->hashMap.put(ctxLookup, ctxFreeKey, loc)) {
    652                oomUnsafe.crash(
    653                    "ScopeContext::cacheEnclosingScope: bindingMapPtr->put");
    654                return;
    655              }
    656            }
    657          });
    658        } else {
    659          createEmpty();
    660        }
    661        break;
    662 
    663      case ScopeKind::StrictEval:
    664      case ScopeKind::FunctionBodyVar:
    665      case ScopeKind::Lexical:
    666      case ScopeKind::NamedLambda:
    667      case ScopeKind::StrictNamedLambda:
    668      case ScopeKind::SimpleCatch:
    669      case ScopeKind::Catch:
    670      case ScopeKind::FunctionLexical:
    671      case ScopeKind::ClassBody:
    672        if (hasEnv) {
    673          si.scope().match([&](auto& scope_ref) {
    674            using BindingMapPtr =
    675                decltype(scopeCache->createCacheFor(scope_ref));
    676            using Lookup =
    677                typename std::remove_pointer_t<BindingMapPtr>::Lookup;
    678            BindingMapPtr bindingMapPtr = scopeCache->createCacheFor(scope_ref);
    679            if (!bindingMapPtr) {
    680              oomUnsafe.crash(
    681                  "ScopeContext::cacheEnclosingScope: "
    682                  "scopeCache->createCacheFor");
    683              return;
    684            }
    685 
    686            for (auto bi = InputBindingIter(scope_ref); bi; bi++) {
    687              NameLocation loc = bi.nameLocation();
    688              if (loc.kind() != NameLocation::Kind::EnvironmentCoordinate) {
    689                continue;
    690              }
    691              auto ctxFreeKey = bi.name();
    692              GenericAtom ctxKey(scope_ref, ctxFreeKey);
    693              Lookup ctxLookup(scope_ref, ctxKey);
    694              if (!bindingMapPtr->hashMap.putNew(ctxLookup, ctxFreeKey, loc)) {
    695                oomUnsafe.crash(
    696                    "ScopeContext::cacheEnclosingScope: bindingMapPtr->put");
    697                return;
    698              }
    699            }
    700          });
    701        } else {
    702          createEmpty();
    703        }
    704        break;
    705 
    706      case ScopeKind::Module:
    707        // This case is used only when delazifying a function inside
    708        // module.
    709        // Initial compilation of module doesn't have enlcosing scope.
    710        if (hasEnv) {
    711          si.scope().match([&](auto& scope_ref) {
    712            using BindingMapPtr =
    713                decltype(scopeCache->createCacheFor(scope_ref));
    714            using Lookup =
    715                typename std::remove_pointer_t<BindingMapPtr>::Lookup;
    716            BindingMapPtr bindingMapPtr = scopeCache->createCacheFor(scope_ref);
    717            if (!bindingMapPtr) {
    718              oomUnsafe.crash(
    719                  "ScopeContext::cacheEnclosingScope: "
    720                  "scopeCache->createCacheFor");
    721              return;
    722            }
    723 
    724            for (auto bi = InputBindingIter(scope_ref); bi; bi++) {
    725              // Imports are on the environment but are indirect
    726              // bindings and must be accessed dynamically instead of
    727              // using an EnvironmentCoordinate.
    728              NameLocation loc = bi.nameLocation();
    729              if (loc.kind() != NameLocation::Kind::EnvironmentCoordinate &&
    730                  loc.kind() != NameLocation::Kind::Import) {
    731                continue;
    732              }
    733              auto ctxFreeKey = bi.name();
    734              GenericAtom ctxKey(scope_ref, ctxFreeKey);
    735              Lookup ctxLookup(scope_ref, ctxKey);
    736              if (!bindingMapPtr->hashMap.putNew(ctxLookup, ctxFreeKey, loc)) {
    737                oomUnsafe.crash(
    738                    "ScopeContext::cacheEnclosingScope: bindingMapPtr->put");
    739                return;
    740              }
    741            }
    742          });
    743        } else {
    744          createEmpty();
    745        }
    746        break;
    747 
    748      case ScopeKind::Eval:
    749        // As an optimization, if the eval doesn't have its own var
    750        // environment and its immediate enclosing scope is a global
    751        // scope, all accesses are global.
    752        if (!hasEnv) {
    753          ScopeKind kind = si.scope().enclosing().kind();
    754          if (kind == ScopeKind::Global || kind == ScopeKind::NonSyntactic) {
    755            setCatchAll(NameLocation::Global(BindingKind::Var));
    756            return;
    757          }
    758        }
    759 
    760        setCatchAll(NameLocation::Dynamic());
    761        return;
    762 
    763      case ScopeKind::Global:
    764        setCatchAll(NameLocation::Global(BindingKind::Var));
    765        return;
    766 
    767      case ScopeKind::With:
    768      case ScopeKind::NonSyntactic:
    769        setCatchAll(NameLocation::Dynamic());
    770        return;
    771 
    772      case ScopeKind::WasmInstance:
    773      case ScopeKind::WasmFunction:
    774        MOZ_CRASH("No direct eval inside wasm functions");
    775    }
    776  }
    777 
    778  MOZ_CRASH("Malformed scope chain");
    779 }
    780 
    781 // Given an input scope, possibly refine this to a more precise scope.
    782 // This is used during eval in the debugger to provide the appropriate scope and
    783 // ThisBinding kind and environment, which is key to making private field eval
    784 // work correctly.
    785 //
    786 // The trick here is that an eval may have a non-syntatic scope but nevertheless
    787 // have an 'interesting' environment which can be traversed to find the
    788 // appropriate scope the the eval to function as desired. See the diagram below.
    789 //
    790 // Eval Scope    Eval Env         Frame Env    Frame Scope
    791 // ============  =============    =========    =============
    792 //
    793 // NonSyntactic
    794 //    |
    795 //    v
    796 //   null        DebugEnvProxy                 LexicalScope
    797 //                     |                            |
    798 //                     v                            v
    799 //               DebugEnvProxy --> CallObj --> FunctionScope
    800 //                     |              |             |
    801 //                     v              v             v
    802 //                    ...            ...           ...
    803 //
    804 InputScope ScopeContext::determineEffectiveScope(InputScope& scope,
    805                                                 JSObject* environment) {
    806  MOZ_ASSERT(effectiveScopeHops == 0);
    807  // If the scope-chain is non-syntactic, we may still determine a more precise
    808  // effective-scope to use instead.
    809  if (environment && scope.hasOnChain(ScopeKind::NonSyntactic)) {
    810    JSObject* env = environment;
    811    while (env) {
    812      // Look at target of any DebugEnvironmentProxy, but be sure to use
    813      // enclosingEnvironment() of the proxy itself.
    814      JSObject* unwrapped = env;
    815      if (env->is<DebugEnvironmentProxy>()) {
    816        unwrapped = &env->as<DebugEnvironmentProxy>().environment();
    817 #ifdef DEBUG
    818        enclosingEnvironmentIsDebugProxy_ = true;
    819 #endif
    820      }
    821 
    822      if (unwrapped->is<CallObject>()) {
    823        JSFunction* callee = &unwrapped->as<CallObject>().callee();
    824        return InputScope(callee->nonLazyScript()->bodyScope());
    825      }
    826 
    827      env = env->enclosingEnvironment();
    828      effectiveScopeHops++;
    829    }
    830  }
    831 
    832  return scope;
    833 }
    834 
    835 static uint32_t DepthOfNearestVarScopeForDirectEval(const InputScope& scope) {
    836  uint32_t depth = 0;
    837  if (scope.isNull()) {
    838    return depth;
    839  }
    840  for (InputScopeIter si(scope); si; si++) {
    841    depth++;
    842    switch (si.scope().kind()) {
    843      case ScopeKind::Function:
    844      case ScopeKind::FunctionBodyVar:
    845      case ScopeKind::Global:
    846      case ScopeKind::NonSyntactic:
    847        return depth;
    848      default:
    849        break;
    850    }
    851  }
    852  return depth;
    853 }
    854 
    855 bool ScopeContext::cacheEnclosingScopeBindingForEval(
    856    FrontendContext* fc, CompilationInput& input,
    857    ParserAtomsTable& parserAtoms) {
    858  enclosingLexicalBindingCache_.emplace();
    859 
    860  uint32_t varScopeDepth =
    861      DepthOfNearestVarScopeForDirectEval(input.enclosingScope);
    862  uint32_t depth = 0;
    863  for (InputScopeIter si(input.enclosingScope); si; si++) {
    864    bool success = si.scope().match([&](auto& scope_ref) {
    865      for (auto bi = InputBindingIter(scope_ref); bi; bi++) {
    866        switch (bi.kind()) {
    867          case BindingKind::Let: {
    868            // Annex B.3.5 allows redeclaring simple (non-destructured)
    869            // catch parameters with var declarations.
    870            bool annexB35Allowance = si.kind() == ScopeKind::SimpleCatch;
    871            if (!annexB35Allowance) {
    872              auto kind = ScopeKindIsCatch(si.kind())
    873                              ? EnclosingLexicalBindingKind::CatchParameter
    874                              : EnclosingLexicalBindingKind::Let;
    875              InputName binding(scope_ref, bi.name());
    876              if (!addToEnclosingLexicalBindingCache(
    877                      fc, parserAtoms, input.atomCache, binding, kind)) {
    878                return false;
    879              }
    880            }
    881            break;
    882          }
    883 
    884 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
    885          // TODO: Optimize cache population for `using` bindings. (Bug 1899502)
    886          case BindingKind::Using:
    887            break;
    888 #endif
    889          case BindingKind::Const: {
    890            InputName binding(scope_ref, bi.name());
    891            if (!addToEnclosingLexicalBindingCache(
    892                    fc, parserAtoms, input.atomCache, binding,
    893                    EnclosingLexicalBindingKind::Const)) {
    894              return false;
    895            }
    896            break;
    897          }
    898 
    899          case BindingKind::Synthetic: {
    900            InputName binding(scope_ref, bi.name());
    901            if (!addToEnclosingLexicalBindingCache(
    902                    fc, parserAtoms, input.atomCache, binding,
    903                    EnclosingLexicalBindingKind::Synthetic)) {
    904              return false;
    905            }
    906            break;
    907          }
    908 
    909          case BindingKind::PrivateMethod: {
    910            InputName binding(scope_ref, bi.name());
    911            if (!addToEnclosingLexicalBindingCache(
    912                    fc, parserAtoms, input.atomCache, binding,
    913                    EnclosingLexicalBindingKind::PrivateMethod)) {
    914              return false;
    915            }
    916            break;
    917          }
    918 
    919          case BindingKind::Import:
    920          case BindingKind::FormalParameter:
    921          case BindingKind::Var:
    922          case BindingKind::NamedLambdaCallee:
    923            break;
    924        }
    925      }
    926      return true;
    927    });
    928    if (!success) {
    929      return false;
    930    }
    931 
    932    if (++depth == varScopeDepth) {
    933      break;
    934    }
    935  }
    936 
    937  return true;
    938 }
    939 
    940 bool ScopeContext::addToEnclosingLexicalBindingCache(
    941    FrontendContext* fc, ParserAtomsTable& parserAtoms,
    942    CompilationAtomCache& atomCache, InputName& name,
    943    EnclosingLexicalBindingKind kind) {
    944  TaggedParserAtomIndex parserName =
    945      name.internInto(fc, parserAtoms, atomCache);
    946  if (!parserName) {
    947    return false;
    948  }
    949 
    950  // Same lexical binding can appear multiple times across scopes.
    951  //
    952  // enclosingLexicalBindingCache_ map is used for detecting conflicting
    953  // `var` binding, and inner binding should be reported in the error.
    954  //
    955  // cacheEnclosingScopeBindingForEval iterates from inner scope, and
    956  // inner-most binding is added to the map first.
    957  //
    958  // Do not overwrite the value with outer bindings.
    959  auto p = enclosingLexicalBindingCache_->lookupForAdd(parserName);
    960  if (!p) {
    961    if (!enclosingLexicalBindingCache_->add(p, parserName, kind)) {
    962      ReportOutOfMemory(fc);
    963      return false;
    964    }
    965  }
    966 
    967  return true;
    968 }
    969 
    970 static bool IsPrivateField(Scope*, JSAtom* atom) {
    971  MOZ_ASSERT(atom->length() > 0);
    972 
    973  JS::AutoCheckCannotGC nogc;
    974  if (atom->hasLatin1Chars()) {
    975    return atom->latin1Chars(nogc)[0] == '#';
    976  }
    977 
    978  return atom->twoByteChars(nogc)[0] == '#';
    979 }
    980 
    981 static bool IsPrivateField(ScopeStencilRef& scope, TaggedParserAtomIndex atom) {
    982  if (atom.isParserAtomIndex()) {
    983    const CompilationStencil& context = *scope.context();
    984    ParserAtom* parserAtom = context.parserAtomData[atom.toParserAtomIndex()];
    985    return parserAtom->isPrivateName();
    986  }
    987 
    988 #ifdef DEBUG
    989  if (atom.isWellKnownAtomId()) {
    990    const auto& info = GetWellKnownAtomInfo(atom.toWellKnownAtomId());
    991    // #constructor is a well-known term, but it is invalid private name.
    992    MOZ_ASSERT(!(info.length > 1 && info.content[0] == '#'));
    993  } else if (atom.isLength2StaticParserString()) {
    994    char content[2];
    995    ParserAtomsTable::getLength2Content(atom.toLength2StaticParserString(),
    996                                        content);
    997    // # character is not part of the allowed character of static strings.
    998    MOZ_ASSERT(content[0] != '#');
    999  }
   1000 #endif
   1001 
   1002  return false;
   1003 }
   1004 
   1005 static bool IsPrivateField(const FakeStencilGlobalScope&,
   1006                           TaggedParserAtomIndex) {
   1007  MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("No private fields on empty global.");
   1008 }
   1009 
   1010 bool ScopeContext::cachePrivateFieldsForEval(FrontendContext* fc,
   1011                                             CompilationInput& input,
   1012                                             JSObject* enclosingEnvironment,
   1013                                             const InputScope& effectiveScope,
   1014                                             ParserAtomsTable& parserAtoms) {
   1015  effectiveScopePrivateFieldCache_.emplace();
   1016 
   1017  // We compute an environment coordinate relative to the effective scope
   1018  // environment. In order to safely consume these environment coordinates,
   1019  // we re-map them to include the hops to get the to the effective scope:
   1020  // see EmitterScope::lookupPrivate
   1021  uint32_t hops = effectiveScopeHops;
   1022  for (InputScopeIter si(effectiveScope); si; si++) {
   1023    if (si.scope().kind() == ScopeKind::ClassBody) {
   1024      uint32_t slots = 0;
   1025      bool success = si.scope().match([&](auto& scope_ref) {
   1026        for (auto bi = InputBindingIter(scope_ref); bi; bi++) {
   1027          if (bi.kind() == BindingKind::PrivateMethod ||
   1028              (bi.kind() == BindingKind::Synthetic &&
   1029               IsPrivateField(scope_ref, bi.name()))) {
   1030            InputName binding(scope_ref, bi.name());
   1031            auto parserName =
   1032                binding.internInto(fc, parserAtoms, input.atomCache);
   1033            if (!parserName) {
   1034              return false;
   1035            }
   1036 
   1037            NameLocation loc = NameLocation::DebugEnvironmentCoordinate(
   1038                bi.kind(), hops, slots);
   1039 
   1040            if (!effectiveScopePrivateFieldCache_->put(parserName, loc)) {
   1041              ReportOutOfMemory(fc);
   1042              return false;
   1043            }
   1044          }
   1045          slots++;
   1046        }
   1047        return true;
   1048      });
   1049      if (!success) {
   1050        return false;
   1051      }
   1052    }
   1053 
   1054    // Hops is only consumed by GetAliasedDebugVar, which uses this to
   1055    // traverse the debug environment chain. See the [SMDOC] for Debug
   1056    // Environment Chain, which explains why we don't check for
   1057    // isEnvironment when computing hops here (basically, debug proxies
   1058    // pretend all scopes have environments, even if they were actually
   1059    // optimized out).
   1060    hops++;
   1061  }
   1062 
   1063  return true;
   1064 }
   1065 
   1066 #ifdef DEBUG
   1067 static bool NameIsOnEnvironment(FrontendContext* fc,
   1068                                ParserAtomsTable& parserAtoms,
   1069                                CompilationAtomCache& atomCache,
   1070                                InputScope& scope, TaggedParserAtomIndex name) {
   1071  JSAtom* jsname = nullptr;
   1072  return scope.match([&](auto& scope_ref) {
   1073    if (std::is_same_v<decltype(scope_ref), FakeStencilGlobalScope&>) {
   1074      // This condition is added to handle the FakeStencilGlobalScope which is
   1075      // used to emulate the global object when delazifying while executing, and
   1076      // which is not provided by the Stencil.
   1077      return true;
   1078    }
   1079    for (auto bi = InputBindingIter(scope_ref); bi; bi++) {
   1080      // If found, the name must already be on the environment or an import,
   1081      // or else there is a bug in the closed-over name analysis in the
   1082      // Parser.
   1083      InputName binding(scope_ref, bi.name());
   1084      if (binding.isEqualTo(fc, parserAtoms, atomCache, name, &jsname)) {
   1085        BindingLocation::Kind kind = bi.location().kind();
   1086 
   1087        if (bi.hasArgumentSlot()) {
   1088          // The following is equivalent to
   1089          // functionScope.script()->functionAllowsParameterRedeclaration()
   1090          if (scope.hasMappedArgsObj()) {
   1091            // Check for duplicate positional formal parameters.
   1092            using InputBindingIter = decltype(bi);
   1093            for (InputBindingIter bi2(bi); bi2 && bi2.hasArgumentSlot();
   1094                 bi2++) {
   1095              InputName binding2(scope_ref, bi2.name());
   1096              if (binding2.isEqualTo(fc, parserAtoms, atomCache, name,
   1097                                     &jsname)) {
   1098                kind = bi2.location().kind();
   1099              }
   1100            }
   1101          }
   1102        }
   1103 
   1104        return kind == BindingLocation::Kind::Global ||
   1105               kind == BindingLocation::Kind::Environment ||
   1106               kind == BindingLocation::Kind::Import;
   1107      }
   1108    }
   1109 
   1110    // If not found, assume it's on the global or dynamically accessed.
   1111    return true;
   1112  });
   1113 }
   1114 #endif
   1115 
   1116 NameLocation ScopeContext::searchInEnclosingScope(FrontendContext* fc,
   1117                                                  CompilationInput& input,
   1118                                                  ParserAtomsTable& parserAtoms,
   1119                                                  TaggedParserAtomIndex name) {
   1120  MOZ_ASSERT(input.target ==
   1121                 CompilationInput::CompilationTarget::Delazification ||
   1122             input.target == CompilationInput::CompilationTarget::Eval);
   1123 
   1124  MOZ_ASSERT(scopeCache);
   1125  if (scopeCacheGen != scopeCache->getCurrentGeneration()) {
   1126    return searchInEnclosingScopeNoCache(fc, input, parserAtoms, name);
   1127  }
   1128 
   1129 #ifdef DEBUG
   1130  // Catch assertion failures in the NoCache variant before looking at the
   1131  // cached content.
   1132  NameLocation expect =
   1133      searchInEnclosingScopeNoCache(fc, input, parserAtoms, name);
   1134 #endif
   1135 
   1136  NameLocation found =
   1137      searchInEnclosingScopeWithCache(fc, input, parserAtoms, name);
   1138  MOZ_ASSERT(expect == found);
   1139  return found;
   1140 }
   1141 
   1142 NameLocation ScopeContext::searchInEnclosingScopeWithCache(
   1143    FrontendContext* fc, CompilationInput& input, ParserAtomsTable& parserAtoms,
   1144    TaggedParserAtomIndex name) {
   1145  MOZ_ASSERT(input.target ==
   1146                 CompilationInput::CompilationTarget::Delazification ||
   1147             input.target == CompilationInput::CompilationTarget::Eval);
   1148 
   1149  // Generic atom of the looked up name.
   1150  GenericAtom genName(fc, parserAtoms, input.atomCache, name);
   1151  mozilla::Maybe<NameLocation> found;
   1152 
   1153  // Number of enclosing scope we walked over.
   1154  uint16_t hops = 0;
   1155 
   1156  for (InputScopeIter si(input.enclosingScope); si; si++) {
   1157    MOZ_ASSERT(NameIsOnEnvironment(fc, parserAtoms, input.atomCache, si.scope(),
   1158                                   name));
   1159 
   1160    // If the result happens to be in the cached content of the scope that we
   1161    // are iterating over, then return it.
   1162    si.scope().match([&](auto& scope_ref) {
   1163      using BindingMapPtr =
   1164          decltype(scopeCache->lookupScope(scope_ref, scopeCacheGen));
   1165      BindingMapPtr bindingMapPtr =
   1166          scopeCache->lookupScope(scope_ref, scopeCacheGen);
   1167      MOZ_ASSERT(bindingMapPtr);
   1168 
   1169      auto& bindingMap = *bindingMapPtr;
   1170      if (bindingMap.catchAll.isSome()) {
   1171        found = bindingMap.catchAll;
   1172        return;
   1173      }
   1174 
   1175      // The scope_ref is given as argument to know where to lookup the key
   1176      // index of the hash table if the names have to be compared.
   1177      using Lookup = typename std::remove_pointer_t<BindingMapPtr>::Lookup;
   1178      Lookup ctxName(scope_ref, genName);
   1179      auto ptr = bindingMap.hashMap.lookup(ctxName);
   1180      if (!ptr) {
   1181        return;
   1182      }
   1183 
   1184      found.emplace(ptr->value());
   1185    });
   1186 
   1187    if (found.isSome()) {
   1188      // Cached entries do not store the number of hops, as it might be reused
   1189      // by multiple inner functions, which might different number of hops.
   1190      found = found.map([&hops](NameLocation loc) {
   1191        if (loc.kind() != NameLocation::Kind::EnvironmentCoordinate) {
   1192          return loc;
   1193        }
   1194        return loc.addHops(hops);
   1195      });
   1196      return found.value();
   1197    }
   1198 
   1199    bool hasEnv = si.hasSyntacticEnvironment();
   1200 
   1201    if (hasEnv) {
   1202      MOZ_ASSERT(hops < ENVCOORD_HOPS_LIMIT - 1);
   1203      hops++;
   1204    }
   1205  }
   1206 
   1207  MOZ_CRASH("Malformed scope chain");
   1208 }
   1209 
   1210 NameLocation ScopeContext::searchInEnclosingScopeNoCache(
   1211    FrontendContext* fc, CompilationInput& input, ParserAtomsTable& parserAtoms,
   1212    TaggedParserAtomIndex name) {
   1213  MOZ_ASSERT(input.target ==
   1214                 CompilationInput::CompilationTarget::Delazification ||
   1215             input.target == CompilationInput::CompilationTarget::Eval);
   1216 
   1217  // Cached JSAtom equivalent of the TaggedParserAtomIndex `name` argument.
   1218  JSAtom* jsname = nullptr;
   1219 
   1220  // NameLocation which contains relative locations to access `name`.
   1221  mozilla::Maybe<NameLocation> result;
   1222 
   1223  // Number of enclosing scope we walked over.
   1224  uint16_t hops = 0;
   1225 
   1226  for (InputScopeIter si(input.enclosingScope); si; si++) {
   1227    MOZ_ASSERT(NameIsOnEnvironment(fc, parserAtoms, input.atomCache, si.scope(),
   1228                                   name));
   1229 
   1230    bool hasEnv = si.hasSyntacticEnvironment();
   1231    switch (si.kind()) {
   1232      case ScopeKind::Function:
   1233        if (hasEnv) {
   1234          if (si.scope().funHasExtensibleScope()) {
   1235            return NameLocation::Dynamic();
   1236          }
   1237 
   1238          si.scope().match([&](auto& scope_ref) {
   1239            for (auto bi = InputBindingIter(scope_ref); bi; bi++) {
   1240              InputName binding(scope_ref, bi.name());
   1241              if (!binding.isEqualTo(fc, parserAtoms, input.atomCache, name,
   1242                                     &jsname)) {
   1243                continue;
   1244              }
   1245 
   1246              BindingLocation bindLoc = bi.location();
   1247              // hasMappedArgsObj == script.functionAllowsParameterRedeclaration
   1248              if (bi.hasArgumentSlot() && si.scope().hasMappedArgsObj()) {
   1249                // Check for duplicate positional formal parameters.
   1250                using InputBindingIter = decltype(bi);
   1251                for (InputBindingIter bi2(bi); bi2 && bi2.hasArgumentSlot();
   1252                     bi2++) {
   1253                  if (bi.name() == bi2.name()) {
   1254                    bindLoc = bi2.location();
   1255                  }
   1256                }
   1257              }
   1258 
   1259              MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
   1260              result.emplace(NameLocation::EnvironmentCoordinate(
   1261                  bi.kind(), hops, bindLoc.slot()));
   1262              return;
   1263            }
   1264          });
   1265        }
   1266        break;
   1267 
   1268      case ScopeKind::StrictEval:
   1269      case ScopeKind::FunctionBodyVar:
   1270      case ScopeKind::Lexical:
   1271      case ScopeKind::NamedLambda:
   1272      case ScopeKind::StrictNamedLambda:
   1273      case ScopeKind::SimpleCatch:
   1274      case ScopeKind::Catch:
   1275      case ScopeKind::FunctionLexical:
   1276      case ScopeKind::ClassBody:
   1277        if (hasEnv) {
   1278          si.scope().match([&](auto& scope_ref) {
   1279            for (auto bi = InputBindingIter(scope_ref); bi; bi++) {
   1280              InputName binding(scope_ref, bi.name());
   1281              if (!binding.isEqualTo(fc, parserAtoms, input.atomCache, name,
   1282                                     &jsname)) {
   1283                continue;
   1284              }
   1285 
   1286              // The name must already have been marked as closed
   1287              // over. If this assertion is hit, there is a bug in the
   1288              // name analysis.
   1289              BindingLocation bindLoc = bi.location();
   1290              MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
   1291              result.emplace(NameLocation::EnvironmentCoordinate(
   1292                  bi.kind(), hops, bindLoc.slot()));
   1293              return;
   1294            }
   1295          });
   1296        }
   1297        break;
   1298 
   1299      case ScopeKind::Module:
   1300        // This case is used only when delazifying a function inside
   1301        // module.
   1302        // Initial compilation of module doesn't have enlcosing scope.
   1303        if (hasEnv) {
   1304          si.scope().match([&](auto& scope_ref) {
   1305            for (auto bi = InputBindingIter(scope_ref); bi; bi++) {
   1306              InputName binding(scope_ref, bi.name());
   1307              if (!binding.isEqualTo(fc, parserAtoms, input.atomCache, name,
   1308                                     &jsname)) {
   1309                continue;
   1310              }
   1311 
   1312              BindingLocation bindLoc = bi.location();
   1313 
   1314              // Imports are on the environment but are indirect
   1315              // bindings and must be accessed dynamically instead of
   1316              // using an EnvironmentCoordinate.
   1317              if (bindLoc.kind() == BindingLocation::Kind::Import) {
   1318                MOZ_ASSERT(si.kind() == ScopeKind::Module);
   1319                result.emplace(NameLocation::Import());
   1320                return;
   1321              }
   1322 
   1323              MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
   1324              result.emplace(NameLocation::EnvironmentCoordinate(
   1325                  bi.kind(), hops, bindLoc.slot()));
   1326              return;
   1327            }
   1328          });
   1329        }
   1330        break;
   1331 
   1332      case ScopeKind::Eval:
   1333        // As an optimization, if the eval doesn't have its own var
   1334        // environment and its immediate enclosing scope is a global
   1335        // scope, all accesses are global.
   1336        if (!hasEnv) {
   1337          ScopeKind kind = si.scope().enclosing().kind();
   1338          if (kind == ScopeKind::Global || kind == ScopeKind::NonSyntactic) {
   1339            return NameLocation::Global(BindingKind::Var);
   1340          }
   1341        }
   1342        return NameLocation::Dynamic();
   1343 
   1344      case ScopeKind::Global:
   1345        return NameLocation::Global(BindingKind::Var);
   1346 
   1347      case ScopeKind::With:
   1348      case ScopeKind::NonSyntactic:
   1349        return NameLocation::Dynamic();
   1350 
   1351      case ScopeKind::WasmInstance:
   1352      case ScopeKind::WasmFunction:
   1353        MOZ_CRASH("No direct eval inside wasm functions");
   1354    }
   1355 
   1356    if (result.isSome()) {
   1357      return result.value();
   1358    }
   1359 
   1360    if (hasEnv) {
   1361      MOZ_ASSERT(hops < ENVCOORD_HOPS_LIMIT - 1);
   1362      hops++;
   1363    }
   1364  }
   1365 
   1366  MOZ_CRASH("Malformed scope chain");
   1367 }
   1368 
   1369 mozilla::Maybe<ScopeContext::EnclosingLexicalBindingKind>
   1370 ScopeContext::lookupLexicalBindingInEnclosingScope(TaggedParserAtomIndex name) {
   1371  auto p = enclosingLexicalBindingCache_->lookup(name);
   1372  if (!p) {
   1373    return mozilla::Nothing();
   1374  }
   1375 
   1376  return mozilla::Some(p->value());
   1377 }
   1378 
   1379 bool ScopeContext::effectiveScopePrivateFieldCacheHas(
   1380    TaggedParserAtomIndex name) {
   1381  return effectiveScopePrivateFieldCache_->has(name);
   1382 }
   1383 
   1384 mozilla::Maybe<NameLocation> ScopeContext::getPrivateFieldLocation(
   1385    TaggedParserAtomIndex name) {
   1386  // The locations returned by this method are only valid for
   1387  // traversing debug environments.
   1388  //
   1389  // See the comment in cachePrivateFieldsForEval
   1390  MOZ_ASSERT(enclosingEnvironmentIsDebugProxy_);
   1391  auto p = effectiveScopePrivateFieldCache_->lookup(name);
   1392  if (!p) {
   1393    return mozilla::Nothing();
   1394  }
   1395  return mozilla::Some(p->value());
   1396 }
   1397 
   1398 bool CompilationInput::initScriptSource(FrontendContext* fc) {
   1399  source = do_AddRef(fc->getAllocator()->new_<ScriptSource>());
   1400  if (!source) {
   1401    return false;
   1402  }
   1403 
   1404  return source->initFromOptions(fc, options);
   1405 }
   1406 
   1407 bool CompilationInput::initForStandaloneFunctionInNonSyntacticScope(
   1408    FrontendContext* fc, Handle<Scope*> functionEnclosingScope) {
   1409  MOZ_ASSERT(!functionEnclosingScope->as<GlobalScope>().isSyntactic());
   1410 
   1411  target = CompilationTarget::StandaloneFunctionInNonSyntacticScope;
   1412  if (!initScriptSource(fc)) {
   1413    return false;
   1414  }
   1415  enclosingScope = InputScope(functionEnclosingScope);
   1416  return true;
   1417 }
   1418 
   1419 FunctionSyntaxKind CompilationInput::functionSyntaxKind() const {
   1420  if (functionFlags().isClassConstructor()) {
   1421    if (functionFlags().hasBaseScript() && isDerivedClassConstructor()) {
   1422      return FunctionSyntaxKind::DerivedClassConstructor;
   1423    }
   1424    return FunctionSyntaxKind::ClassConstructor;
   1425  }
   1426  if (functionFlags().isMethod()) {
   1427    if (functionFlags().hasBaseScript() && isSyntheticFunction()) {
   1428      // return FunctionSyntaxKind::FieldInitializer;
   1429      MOZ_ASSERT_UNREACHABLE(
   1430          "Lazy parsing of class field initializers not supported (yet)");
   1431    }
   1432    return FunctionSyntaxKind::Method;
   1433  }
   1434  if (functionFlags().isGetter()) {
   1435    return FunctionSyntaxKind::Getter;
   1436  }
   1437  if (functionFlags().isSetter()) {
   1438    return FunctionSyntaxKind::Setter;
   1439  }
   1440  if (functionFlags().isArrow()) {
   1441    return FunctionSyntaxKind::Arrow;
   1442  }
   1443  return FunctionSyntaxKind::Statement;
   1444 }
   1445 
   1446 bool CompilationInput::internExtraBindings(FrontendContext* fc,
   1447                                           ParserAtomsTable& parserAtoms) {
   1448  MOZ_ASSERT(hasExtraBindings());
   1449 
   1450  for (auto& bindingInfo : *maybeExtraBindings_) {
   1451    if (bindingInfo.isShadowed) {
   1452      continue;
   1453    }
   1454 
   1455    const char* chars = bindingInfo.nameChars.get();
   1456    auto index = parserAtoms.internUtf8(
   1457        fc, reinterpret_cast<const mozilla::Utf8Unit*>(chars), strlen(chars));
   1458    if (!index) {
   1459      return false;
   1460    }
   1461 
   1462    bindingInfo.nameIndex = index;
   1463  }
   1464 
   1465  return true;
   1466 }
   1467 
   1468 void InputScope::trace(JSTracer* trc) {
   1469  using ScopePtr = Scope*;
   1470  if (scope_.is<ScopePtr>()) {
   1471    ScopePtr* ptrAddr = &scope_.as<ScopePtr>();
   1472    TraceNullableRoot(trc, ptrAddr, "compilation-input-scope");
   1473  }
   1474 }
   1475 
   1476 void InputScript::trace(JSTracer* trc) {
   1477  using ScriptPtr = BaseScript*;
   1478  if (script_.is<ScriptPtr>()) {
   1479    ScriptPtr* ptrAddr = &script_.as<ScriptPtr>();
   1480    TraceNullableRoot(trc, ptrAddr, "compilation-input-lazy");
   1481  }
   1482 }
   1483 
   1484 void CompilationInput::trace(JSTracer* trc) {
   1485  atomCache.trace(trc);
   1486  lazy_.trace(trc);
   1487  enclosingScope.trace(trc);
   1488 }
   1489 
   1490 bool CompilationSyntaxParseCache::init(FrontendContext* fc, LifoAlloc& alloc,
   1491                                       ParserAtomsTable& parseAtoms,
   1492                                       CompilationAtomCache& atomCache,
   1493                                       const InputScript& lazy) {
   1494  if (!copyFunctionInfo(fc, parseAtoms, atomCache, lazy)) {
   1495    return false;
   1496  }
   1497  bool success = lazy.raw().match([&](auto& ref) {
   1498    if (!copyScriptInfo(fc, alloc, parseAtoms, atomCache, ref)) {
   1499      return false;
   1500    }
   1501    if (!copyClosedOverBindings(fc, alloc, parseAtoms, atomCache, ref)) {
   1502      return false;
   1503    }
   1504    return true;
   1505  });
   1506  if (!success) {
   1507    return false;
   1508  }
   1509 #ifdef DEBUG
   1510  isInitialized = true;
   1511 #endif
   1512  return true;
   1513 }
   1514 
   1515 bool CompilationSyntaxParseCache::copyFunctionInfo(
   1516    FrontendContext* fc, ParserAtomsTable& parseAtoms,
   1517    CompilationAtomCache& atomCache, const InputScript& lazy) {
   1518  InputName name = lazy.displayAtom();
   1519  if (!name.isNull()) {
   1520    displayAtom_ = name.internInto(fc, parseAtoms, atomCache);
   1521    if (!displayAtom_) {
   1522      return false;
   1523    }
   1524  }
   1525 
   1526  funExtra_.immutableFlags = lazy.immutableFlags();
   1527  funExtra_.extent = lazy.extent();
   1528  if (funExtra_.useMemberInitializers()) {
   1529    funExtra_.setMemberInitializers(lazy.getMemberInitializers());
   1530  }
   1531 
   1532  return true;
   1533 }
   1534 
   1535 bool CompilationSyntaxParseCache::copyScriptInfo(
   1536    FrontendContext* fc, LifoAlloc& alloc, ParserAtomsTable& parseAtoms,
   1537    CompilationAtomCache& atomCache, BaseScript* lazy) {
   1538  using GCThingsSpan = mozilla::Span<TaggedScriptThingIndex>;
   1539  using ScriptDataSpan = mozilla::Span<ScriptStencil>;
   1540  using ScriptExtraSpan = mozilla::Span<ScriptStencilExtra>;
   1541  cachedGCThings_ = GCThingsSpan(nullptr);
   1542  cachedScriptData_ = ScriptDataSpan(nullptr);
   1543  cachedScriptExtra_ = ScriptExtraSpan(nullptr);
   1544 
   1545  auto gcthings = lazy->gcthings();
   1546  size_t length = gcthings.Length();
   1547  if (length == 0) {
   1548    return true;
   1549  }
   1550 
   1551  // Reduce the length to the first element which is not a function.
   1552  for (size_t i = 0; i < length; i++) {
   1553    gc::Cell* cell = gcthings[i].asCell();
   1554    if (!cell || !cell->is<JSObject>()) {
   1555      length = i;
   1556      break;
   1557    }
   1558    MOZ_ASSERT(cell->as<JSObject>()->is<JSFunction>());
   1559  }
   1560 
   1561  TaggedScriptThingIndex* gcThingsData =
   1562      alloc.newArrayUninitialized<TaggedScriptThingIndex>(length);
   1563  ScriptStencil* scriptData =
   1564      alloc.newArrayUninitialized<ScriptStencil>(length);
   1565  ScriptStencilExtra* scriptExtra =
   1566      alloc.newArrayUninitialized<ScriptStencilExtra>(length);
   1567  if (!gcThingsData || !scriptData || !scriptExtra) {
   1568    ReportOutOfMemory(fc);
   1569    return false;
   1570  }
   1571 
   1572  for (size_t i = 0; i < length; i++) {
   1573    gc::Cell* cell = gcthings[i].asCell();
   1574    JSFunction* fun = &cell->as<JSObject>()->as<JSFunction>();
   1575    gcThingsData[i] = TaggedScriptThingIndex(ScriptIndex(i));
   1576    new (mozilla::KnownNotNull, &scriptData[i]) ScriptStencil();
   1577    ScriptStencil& data = scriptData[i];
   1578    new (mozilla::KnownNotNull, &scriptExtra[i]) ScriptStencilExtra();
   1579    ScriptStencilExtra& extra = scriptExtra[i];
   1580 
   1581    if (fun->fullDisplayAtom()) {
   1582      TaggedParserAtomIndex displayAtom =
   1583          parseAtoms.internJSAtom(fc, atomCache, fun->fullDisplayAtom());
   1584      if (!displayAtom) {
   1585        return false;
   1586      }
   1587      data.functionAtom = displayAtom;
   1588    }
   1589    data.functionFlags = fun->flags();
   1590 
   1591    BaseScript* lazy = fun->baseScript();
   1592    extra.immutableFlags = lazy->immutableFlags();
   1593    extra.extent = lazy->extent();
   1594 
   1595    // Info derived from parent compilation should not be set yet for our inner
   1596    // lazy functions. Instead that info will be updated when we finish our
   1597    // compilation.
   1598    MOZ_ASSERT(lazy->hasEnclosingScript());
   1599  }
   1600 
   1601  cachedGCThings_ = GCThingsSpan(gcThingsData, length);
   1602  cachedScriptData_ = ScriptDataSpan(scriptData, length);
   1603  cachedScriptExtra_ = ScriptExtraSpan(scriptExtra, length);
   1604  return true;
   1605 }
   1606 
   1607 bool CompilationSyntaxParseCache::copyScriptInfo(
   1608    FrontendContext* fc, LifoAlloc& alloc, ParserAtomsTable& parseAtoms,
   1609    CompilationAtomCache& atomCache, const ScriptStencilRef& lazy) {
   1610  using GCThingsSpan = mozilla::Span<TaggedScriptThingIndex>;
   1611  using ScriptDataSpan = mozilla::Span<ScriptStencil>;
   1612  using ScriptExtraSpan = mozilla::Span<ScriptStencilExtra>;
   1613  cachedGCThings_ = GCThingsSpan(nullptr);
   1614  cachedScriptData_ = ScriptDataSpan(nullptr);
   1615  cachedScriptExtra_ = ScriptExtraSpan(nullptr);
   1616 
   1617  // We are only interested in the functions within the gcthings. The initial
   1618  // stencil is already aware of all inner functions, and the script indexes can
   1619  // help build additional ScriptStencilRef.
   1620  auto gcThings = lazy.gcThingsFromInitial();
   1621  size_t length = gcThings.Length();
   1622  if (length == 0) {
   1623    return true;
   1624  }
   1625 
   1626  // Reduce the length to the first element which is not a function.
   1627  for (size_t i = 0; i < length; i++) {
   1628    if (!gcThings[i].isFunction()) {
   1629      length = i;
   1630      break;
   1631    }
   1632  }
   1633 
   1634  TaggedScriptThingIndex* gcThingsData =
   1635      alloc.newArrayUninitialized<TaggedScriptThingIndex>(length);
   1636  ScriptStencil* scriptData =
   1637      alloc.newArrayUninitialized<ScriptStencil>(length);
   1638  ScriptStencilExtra* scriptExtra =
   1639      alloc.newArrayUninitialized<ScriptStencilExtra>(length);
   1640  if (!gcThingsData || !scriptData || !scriptExtra) {
   1641    ReportOutOfMemory(fc);
   1642    return false;
   1643  }
   1644 
   1645  for (size_t i = 0; i < length; i++) {
   1646    // The gcThing array is taken out of the initial stencil, thus scriptIndex
   1647    // are valid for the initial stencil only.
   1648    ScriptIndex innerIndex = gcThings[i].toFunction();
   1649    ScriptStencilRef inner{lazy.stencils_, innerIndex};
   1650 
   1651    // scriptData is extracted from the initial stencil as we are about to
   1652    // compile the enclosing script.
   1653    const ScriptStencil& srcData = inner.scriptDataFromInitial();
   1654 
   1655    gcThingsData[i] = TaggedScriptThingIndex(ScriptIndex(i));
   1656    new (mozilla::KnownNotNull, &scriptData[i]) ScriptStencil();
   1657    ScriptStencil& data = scriptData[i];
   1658    new (mozilla::KnownNotNull, &scriptExtra[i]) ScriptStencilExtra();
   1659    ScriptStencilExtra& extra = scriptExtra[i];
   1660 
   1661    InputName name{inner.topLevelScript(), srcData.functionAtom};
   1662    if (!name.isNull()) {
   1663      auto displayAtom = name.internInto(fc, parseAtoms, atomCache);
   1664      if (!displayAtom) {
   1665        return false;
   1666      }
   1667      data.functionAtom = displayAtom;
   1668    }
   1669    data.functionFlags = srcData.functionFlags;
   1670 
   1671    extra = inner.scriptExtra();
   1672  }
   1673 
   1674  cachedGCThings_ = GCThingsSpan(gcThingsData, length);
   1675  cachedScriptData_ = ScriptDataSpan(scriptData, length);
   1676  cachedScriptExtra_ = ScriptExtraSpan(scriptExtra, length);
   1677  return true;
   1678 }
   1679 
   1680 bool CompilationSyntaxParseCache::copyClosedOverBindings(
   1681    FrontendContext* fc, LifoAlloc& alloc, ParserAtomsTable& parseAtoms,
   1682    CompilationAtomCache& atomCache, BaseScript* lazy) {
   1683  using ClosedOverBindingsSpan = mozilla::Span<TaggedParserAtomIndex>;
   1684  closedOverBindings_ = ClosedOverBindingsSpan(nullptr);
   1685 
   1686  // The gcthings() array contains the inner function list followed by the
   1687  // closed-over bindings data. Skip the inner function list, as it is already
   1688  // cached in cachedGCThings_. See also: BaseScript::CreateLazy.
   1689  size_t start = cachedGCThings_.Length();
   1690  auto gcthings = lazy->gcthings();
   1691  size_t length = gcthings.Length();
   1692  MOZ_ASSERT(start <= length);
   1693  if (length - start == 0) {
   1694    return true;
   1695  }
   1696 
   1697  TaggedParserAtomIndex* closedOverBindings =
   1698      alloc.newArrayUninitialized<TaggedParserAtomIndex>(length - start);
   1699  if (!closedOverBindings) {
   1700    ReportOutOfMemory(fc);
   1701    return false;
   1702  }
   1703 
   1704  for (size_t i = start; i < length; i++) {
   1705    gc::Cell* cell = gcthings[i].asCell();
   1706    if (!cell) {
   1707      closedOverBindings[i - start] = TaggedParserAtomIndex::null();
   1708      continue;
   1709    }
   1710 
   1711    MOZ_ASSERT(cell->as<JSString>()->isAtom());
   1712 
   1713    auto name = static_cast<JSAtom*>(cell);
   1714    auto parserAtom = parseAtoms.internJSAtom(fc, atomCache, name);
   1715    if (!parserAtom) {
   1716      return false;
   1717    }
   1718 
   1719    closedOverBindings[i - start] = parserAtom;
   1720  }
   1721 
   1722  closedOverBindings_ =
   1723      ClosedOverBindingsSpan(closedOverBindings, length - start);
   1724  return true;
   1725 }
   1726 
   1727 bool CompilationSyntaxParseCache::copyClosedOverBindings(
   1728    FrontendContext* fc, LifoAlloc& alloc, ParserAtomsTable& parseAtoms,
   1729    CompilationAtomCache& atomCache, const ScriptStencilRef& lazy) {
   1730  using ClosedOverBindingsSpan = mozilla::Span<TaggedParserAtomIndex>;
   1731  closedOverBindings_ = ClosedOverBindingsSpan(nullptr);
   1732 
   1733  // The gcthings array contains the inner function list followed by the
   1734  // closed-over bindings data. Skip the inner function list, as it is already
   1735  // cached in cachedGCThings_. See also: BaseScript::CreateLazy.
   1736  auto gcthings = lazy.gcThingsFromInitial();
   1737  size_t length = gcthings.Length();
   1738  size_t start = cachedGCThings_.Length();
   1739  MOZ_ASSERT(start <= length);
   1740  if (length - start == 0) {
   1741    return true;
   1742  }
   1743  length -= start;
   1744 
   1745  // Atoms from the lazy.context (CompilationStencil) are not registered in the
   1746  // the parseAtoms table. Thus we create a new span which will contain all the
   1747  // interned atoms.
   1748  TaggedParserAtomIndex* closedOverBindings =
   1749      alloc.newArrayUninitialized<TaggedParserAtomIndex>(length);
   1750  if (!closedOverBindings) {
   1751    ReportOutOfMemory(fc);
   1752    return false;
   1753  }
   1754 
   1755  for (size_t i = 0; i < length; i++) {
   1756    auto gcThing = gcthings[i + start];
   1757    if (gcThing.isNull()) {
   1758      closedOverBindings[i] = TaggedParserAtomIndex::null();
   1759      continue;
   1760    }
   1761 
   1762    MOZ_ASSERT(gcThing.isAtom());
   1763    InputName name(lazy.topLevelScript(), gcThing.toAtom());
   1764    auto parserAtom = name.internInto(fc, parseAtoms, atomCache);
   1765    if (!parserAtom) {
   1766      return false;
   1767    }
   1768 
   1769    closedOverBindings[i] = parserAtom;
   1770  }
   1771 
   1772  closedOverBindings_ = ClosedOverBindingsSpan(closedOverBindings, length);
   1773  return true;
   1774 }
   1775 
   1776 template <typename T>
   1777 PreAllocateableGCArray<T>::~PreAllocateableGCArray() {
   1778  if (elems_) {
   1779    js_free(elems_);
   1780    elems_ = nullptr;
   1781  }
   1782 }
   1783 
   1784 template <typename T>
   1785 bool PreAllocateableGCArray<T>::allocate(size_t length) {
   1786  MOZ_ASSERT(empty());
   1787 
   1788  length_ = length;
   1789 
   1790  if (isInline()) {
   1791    inlineElem_ = nullptr;
   1792    return true;
   1793  }
   1794 
   1795  elems_ = reinterpret_cast<T*>(js_calloc(sizeof(T) * length_));
   1796  if (!elems_) {
   1797    return false;
   1798  }
   1799 
   1800  return true;
   1801 }
   1802 
   1803 template <typename T>
   1804 bool PreAllocateableGCArray<T>::allocateWith(T init, size_t length) {
   1805  MOZ_ASSERT(empty());
   1806 
   1807  length_ = length;
   1808 
   1809  if (isInline()) {
   1810    inlineElem_ = init;
   1811    return true;
   1812  }
   1813 
   1814  elems_ = reinterpret_cast<T*>(js_malloc(sizeof(T) * length_));
   1815  if (!elems_) {
   1816    return false;
   1817  }
   1818 
   1819  std::fill(elems_, elems_ + length_, init);
   1820  return true;
   1821 }
   1822 
   1823 template <typename T>
   1824 void PreAllocateableGCArray<T>::steal(Preallocated&& buffer) {
   1825  MOZ_ASSERT(empty());
   1826 
   1827  length_ = buffer.length_;
   1828  buffer.length_ = 0;
   1829 
   1830  if (isInline()) {
   1831    inlineElem_ = nullptr;
   1832    return;
   1833  }
   1834 
   1835  elems_ = reinterpret_cast<T*>(buffer.elems_);
   1836  buffer.elems_ = nullptr;
   1837 
   1838 #ifdef DEBUG
   1839  for (size_t i = 0; i < length_; i++) {
   1840    MOZ_ASSERT(elems_[i] == nullptr);
   1841  }
   1842 #endif
   1843 }
   1844 
   1845 template <typename T>
   1846 void PreAllocateableGCArray<T>::trace(JSTracer* trc) {
   1847  if (empty()) {
   1848    return;
   1849  }
   1850 
   1851  if (isInline()) {
   1852    TraceNullableRoot(trc, &inlineElem_, "PreAllocateableGCArray::inlineElem_");
   1853    return;
   1854  }
   1855 
   1856  for (size_t i = 0; i < length_; i++) {
   1857    TraceNullableRoot(trc, &elems_[i], "PreAllocateableGCArray::elems_");
   1858  }
   1859 }
   1860 
   1861 template <typename T>
   1862 PreAllocateableGCArray<T>::Preallocated::~Preallocated() {
   1863  if (elems_) {
   1864    js_free(elems_);
   1865    elems_ = nullptr;
   1866  }
   1867 }
   1868 
   1869 template <typename T>
   1870 bool PreAllocateableGCArray<T>::Preallocated::allocate(size_t length) {
   1871  MOZ_ASSERT(empty());
   1872 
   1873  length_ = length;
   1874 
   1875  if (isInline()) {
   1876    return true;
   1877  }
   1878 
   1879  elems_ = reinterpret_cast<uintptr_t*>(js_calloc(sizeof(uintptr_t) * length_));
   1880  if (!elems_) {
   1881    return false;
   1882  }
   1883 
   1884  return true;
   1885 }
   1886 
   1887 template struct js::frontend::PreAllocateableGCArray<JSFunction*>;
   1888 template struct js::frontend::PreAllocateableGCArray<js::Scope*>;
   1889 
   1890 void CompilationAtomCache::trace(JSTracer* trc) { atoms_.trace(trc); }
   1891 
   1892 void CompilationGCOutput::trace(JSTracer* trc) {
   1893  TraceNullableRoot(trc, &script, "compilation-gc-output-script");
   1894  TraceNullableRoot(trc, &module, "compilation-gc-output-module");
   1895  TraceNullableRoot(trc, &sourceObject, "compilation-gc-output-source");
   1896  functions.trace(trc);
   1897  scopes.trace(trc);
   1898 }
   1899 
   1900 RegExpObject* RegExpStencil::createRegExp(
   1901    JSContext* cx, const CompilationAtomCache& atomCache) const {
   1902  Rooted<JSAtom*> atom(cx, atomCache.getExistingAtomAt(cx, atom_));
   1903  return RegExpObject::createSyntaxChecked(cx, atom, flags(), TenuredObject);
   1904 }
   1905 
   1906 RegExpObject* RegExpStencil::createRegExpAndEnsureAtom(
   1907    JSContext* cx, FrontendContext* fc, ParserAtomsTable& parserAtoms,
   1908    CompilationAtomCache& atomCache) const {
   1909  Rooted<JSAtom*> atom(cx, parserAtoms.toJSAtom(cx, fc, atom_, atomCache));
   1910  if (!atom) {
   1911    return nullptr;
   1912  }
   1913  return RegExpObject::createSyntaxChecked(cx, atom, flags(), TenuredObject);
   1914 }
   1915 
   1916 AbstractScopePtr ScopeStencil::enclosing(
   1917    CompilationState& compilationState) const {
   1918  if (hasEnclosing()) {
   1919    return AbstractScopePtr(compilationState, enclosing());
   1920  }
   1921 
   1922  return AbstractScopePtr::compilationEnclosingScope(compilationState);
   1923 }
   1924 
   1925 Scope* ScopeStencil::enclosingExistingScope(
   1926    const CompilationInput& input, const CompilationGCOutput& gcOutput) const {
   1927  if (hasEnclosing()) {
   1928    Scope* result = gcOutput.getScopeNoBaseIndex(enclosing());
   1929    MOZ_ASSERT(result, "Scope must already exist to use this method");
   1930    return result;
   1931  }
   1932 
   1933  // When creating a scope based on the input and a gc-output, we assume that
   1934  // the scope stencil that we are looking at has not been merged into another
   1935  // stencil, and thus that we still have the compilation input of the stencil.
   1936  //
   1937  // Otherwise, if this was in the case of an input generated from a Stencil
   1938  // instead of live-gc values, we would not know its associated gcOutput as it
   1939  // might not even have one yet.
   1940  return input.enclosingScope.variant().as<Scope*>();
   1941 }
   1942 
   1943 Scope* ScopeStencil::createScope(JSContext* cx, CompilationInput& input,
   1944                                 CompilationGCOutput& gcOutput,
   1945                                 BaseParserScopeData* baseScopeData) const {
   1946  Rooted<Scope*> enclosingScope(cx, enclosingExistingScope(input, gcOutput));
   1947  return createScope(cx, input.atomCache, enclosingScope, baseScopeData);
   1948 }
   1949 
   1950 Scope* ScopeStencil::createScope(JSContext* cx, CompilationAtomCache& atomCache,
   1951                                 Handle<Scope*> enclosingScope,
   1952                                 BaseParserScopeData* baseScopeData) const {
   1953  switch (kind()) {
   1954    case ScopeKind::Function: {
   1955      using ScopeType = FunctionScope;
   1956      MOZ_ASSERT(matchScopeKind<ScopeType>(kind()));
   1957      return createSpecificScope<ScopeType, CallObject>(
   1958          cx, atomCache, enclosingScope, baseScopeData);
   1959    }
   1960    case ScopeKind::Lexical:
   1961    case ScopeKind::SimpleCatch:
   1962    case ScopeKind::Catch:
   1963    case ScopeKind::NamedLambda:
   1964    case ScopeKind::StrictNamedLambda:
   1965    case ScopeKind::FunctionLexical: {
   1966      using ScopeType = LexicalScope;
   1967      MOZ_ASSERT(matchScopeKind<ScopeType>(kind()));
   1968      return createSpecificScope<ScopeType, BlockLexicalEnvironmentObject>(
   1969          cx, atomCache, enclosingScope, baseScopeData);
   1970    }
   1971    case ScopeKind::ClassBody: {
   1972      using ScopeType = ClassBodyScope;
   1973      MOZ_ASSERT(matchScopeKind<ScopeType>(kind()));
   1974      return createSpecificScope<ScopeType, BlockLexicalEnvironmentObject>(
   1975          cx, atomCache, enclosingScope, baseScopeData);
   1976    }
   1977    case ScopeKind::FunctionBodyVar: {
   1978      using ScopeType = VarScope;
   1979      MOZ_ASSERT(matchScopeKind<ScopeType>(kind()));
   1980      return createSpecificScope<ScopeType, VarEnvironmentObject>(
   1981          cx, atomCache, enclosingScope, baseScopeData);
   1982    }
   1983    case ScopeKind::Global:
   1984    case ScopeKind::NonSyntactic: {
   1985      using ScopeType = GlobalScope;
   1986      MOZ_ASSERT(matchScopeKind<ScopeType>(kind()));
   1987      return createSpecificScope<ScopeType, std::nullptr_t>(
   1988          cx, atomCache, enclosingScope, baseScopeData);
   1989    }
   1990    case ScopeKind::Eval:
   1991    case ScopeKind::StrictEval: {
   1992      using ScopeType = EvalScope;
   1993      MOZ_ASSERT(matchScopeKind<ScopeType>(kind()));
   1994      return createSpecificScope<ScopeType, VarEnvironmentObject>(
   1995          cx, atomCache, enclosingScope, baseScopeData);
   1996    }
   1997    case ScopeKind::Module: {
   1998      using ScopeType = ModuleScope;
   1999      MOZ_ASSERT(matchScopeKind<ScopeType>(kind()));
   2000      return createSpecificScope<ScopeType, ModuleEnvironmentObject>(
   2001          cx, atomCache, enclosingScope, baseScopeData);
   2002    }
   2003    case ScopeKind::With: {
   2004      using ScopeType = WithScope;
   2005      MOZ_ASSERT(matchScopeKind<ScopeType>(kind()));
   2006      return createSpecificScope<ScopeType, std::nullptr_t>(
   2007          cx, atomCache, enclosingScope, baseScopeData);
   2008    }
   2009    case ScopeKind::WasmFunction:
   2010    case ScopeKind::WasmInstance: {
   2011      // ScopeStencil does not support WASM
   2012      break;
   2013    }
   2014  }
   2015  MOZ_CRASH();
   2016 }
   2017 
   2018 bool CompilationState::prepareSharedDataStorage(FrontendContext* fc) {
   2019  size_t allScriptCount = scriptData.length();
   2020  size_t nonLazyScriptCount = nonLazyFunctionCount;
   2021  if (!scriptData[0].isFunction()) {
   2022    nonLazyScriptCount++;
   2023  }
   2024  return sharedData.prepareStorageFor(fc, nonLazyScriptCount, allScriptCount);
   2025 }
   2026 
   2027 static bool CreateLazyScript(JSContext* cx,
   2028                             const CompilationAtomCache& atomCache,
   2029                             const CompilationStencil& stencil,
   2030                             CompilationGCOutput& gcOutput,
   2031                             const ScriptStencil& script,
   2032                             const ScriptStencilExtra& scriptExtra,
   2033                             ScriptIndex scriptIndex, HandleFunction function) {
   2034  Rooted<ScriptSourceObject*> sourceObject(cx, gcOutput.sourceObject);
   2035 
   2036  size_t ngcthings = script.gcThingsLength;
   2037 
   2038  Rooted<BaseScript*> lazy(
   2039      cx, BaseScript::CreateRawLazy(cx, ngcthings, function, sourceObject,
   2040                                    scriptExtra.extent,
   2041                                    scriptExtra.immutableFlags));
   2042  if (!lazy) {
   2043    return false;
   2044  }
   2045 
   2046  if (ngcthings) {
   2047    if (!EmitScriptThingsVector(cx, atomCache, stencil, gcOutput,
   2048                                script.gcthings(stencil),
   2049                                lazy->gcthingsForInit())) {
   2050      return false;
   2051    }
   2052  }
   2053 
   2054  if (scriptExtra.useMemberInitializers()) {
   2055    lazy->setMemberInitializers(scriptExtra.memberInitializers());
   2056  }
   2057 
   2058  function->initScript(lazy);
   2059 
   2060  return true;
   2061 }
   2062 
   2063 // Parser-generated functions with the same prototype will share the same shape.
   2064 // By computing the correct values up front, we can save a lot of time in the
   2065 // Object creation code. For simplicity, we focus only on plain synchronous
   2066 // functions which are by far the most common.
   2067 //
   2068 // NOTE: Keep this in sync with `js::NewFunctionWithProto`.
   2069 static JSFunction* CreateFunctionFast(JSContext* cx,
   2070                                      CompilationAtomCache& atomCache,
   2071                                      Handle<SharedShape*> shape,
   2072                                      const ScriptStencil& script,
   2073                                      const ScriptStencilExtra& scriptExtra) {
   2074  MOZ_ASSERT(
   2075      !scriptExtra.immutableFlags.hasFlag(ImmutableScriptFlagsEnum::IsAsync));
   2076  MOZ_ASSERT(!scriptExtra.immutableFlags.hasFlag(
   2077      ImmutableScriptFlagsEnum::IsGenerator));
   2078  MOZ_ASSERT(!script.functionFlags.isAsmJSNative());
   2079 
   2080  FunctionFlags flags = script.functionFlags;
   2081  gc::AllocKind allocKind = flags.isExtended()
   2082                                ? gc::AllocKind::FUNCTION_EXTENDED
   2083                                : gc::AllocKind::FUNCTION;
   2084 
   2085  JSFunction* fun = JSFunction::create(cx, allocKind, gc::Heap::Tenured, shape);
   2086  if (!fun) {
   2087    return nullptr;
   2088  }
   2089 
   2090  fun->setArgCount(scriptExtra.nargs);
   2091  fun->setFlags(flags);
   2092 
   2093  fun->initScript(nullptr);
   2094  fun->initEnvironment(nullptr);
   2095 
   2096  if (script.functionAtom) {
   2097    JSAtom* atom = atomCache.getExistingAtomAt(cx, script.functionAtom);
   2098    MOZ_ASSERT(atom);
   2099    fun->initAtom(atom);
   2100  }
   2101 
   2102 #ifdef DEBUG
   2103  fun->assertFunctionKindIntegrity();
   2104 #endif
   2105 
   2106  return fun;
   2107 }
   2108 
   2109 static JSFunction* CreateFunction(JSContext* cx,
   2110                                  CompilationAtomCache& atomCache,
   2111                                  const CompilationStencil& stencil,
   2112                                  const ScriptStencil& script,
   2113                                  const ScriptStencilExtra& scriptExtra,
   2114                                  ScriptIndex functionIndex) {
   2115  GeneratorKind generatorKind =
   2116      scriptExtra.immutableFlags.hasFlag(ImmutableScriptFlagsEnum::IsGenerator)
   2117          ? GeneratorKind::Generator
   2118          : GeneratorKind::NotGenerator;
   2119  FunctionAsyncKind asyncKind =
   2120      scriptExtra.immutableFlags.hasFlag(ImmutableScriptFlagsEnum::IsAsync)
   2121          ? FunctionAsyncKind::AsyncFunction
   2122          : FunctionAsyncKind::SyncFunction;
   2123 
   2124  // Determine the new function's proto. This must be done for singleton
   2125  // functions.
   2126  RootedObject proto(cx);
   2127  if (!GetFunctionPrototype(cx, generatorKind, asyncKind, &proto)) {
   2128    return nullptr;
   2129  }
   2130 
   2131  gc::AllocKind allocKind = script.functionFlags.isExtended()
   2132                                ? gc::AllocKind::FUNCTION_EXTENDED
   2133                                : gc::AllocKind::FUNCTION;
   2134  bool isAsmJS = script.functionFlags.isAsmJSNative();
   2135 
   2136  JSNative maybeNative = isAsmJS ? InstantiateAsmJS : nullptr;
   2137 
   2138  Rooted<JSAtom*> displayAtom(cx);
   2139  if (script.functionAtom) {
   2140    displayAtom.set(atomCache.getExistingAtomAt(cx, script.functionAtom));
   2141    MOZ_ASSERT(displayAtom);
   2142  }
   2143  RootedFunction fun(
   2144      cx, NewFunctionWithProto(cx, maybeNative, scriptExtra.nargs,
   2145                               script.functionFlags, nullptr, displayAtom,
   2146                               proto, allocKind, TenuredObject));
   2147  if (!fun) {
   2148    return nullptr;
   2149  }
   2150 
   2151  if (isAsmJS) {
   2152    RefPtr<const JS::WasmModule> asmJS =
   2153        stencil.asmJS->moduleMap.lookup(functionIndex)->value();
   2154 
   2155    JSObject* moduleObj = asmJS->createObjectForAsmJS(cx);
   2156    if (!moduleObj) {
   2157      return nullptr;
   2158    }
   2159 
   2160    fun->setExtendedSlot(FunctionExtended::ASMJS_MODULE_SLOT,
   2161                         ObjectValue(*moduleObj));
   2162  }
   2163 
   2164  return fun;
   2165 }
   2166 
   2167 static bool InstantiateAtoms(JSContext* cx, FrontendContext* fc,
   2168                             CompilationAtomCache& atomCache,
   2169                             const CompilationStencil& stencil) {
   2170  return InstantiateMarkedAtoms(cx, fc, stencil.parserAtomData, atomCache);
   2171 }
   2172 
   2173 static bool InstantiateScriptSourceObject(JSContext* cx,
   2174                                          const JS::InstantiateOptions& options,
   2175                                          const CompilationStencil& stencil,
   2176                                          CompilationGCOutput& gcOutput) {
   2177  MOZ_ASSERT(stencil.source);
   2178 
   2179  gcOutput.sourceObject = ScriptSourceObject::create(cx, stencil.source.get());
   2180  if (!gcOutput.sourceObject) {
   2181    return false;
   2182  }
   2183 
   2184  Rooted<ScriptSourceObject*> sourceObject(cx, gcOutput.sourceObject);
   2185  if (!ScriptSourceObject::initFromOptions(cx, sourceObject, options)) {
   2186    return false;
   2187  }
   2188 
   2189  return true;
   2190 }
   2191 
   2192 // Instantiate ModuleObject. Further initialization is done after the associated
   2193 // BaseScript is instantiated in InstantiateTopLevel.
   2194 static bool InstantiateModuleObject(JSContext* cx, FrontendContext* fc,
   2195                                    CompilationAtomCache& atomCache,
   2196                                    const CompilationStencil& stencil,
   2197                                    CompilationGCOutput& gcOutput) {
   2198  MOZ_ASSERT(stencil.isModule());
   2199 
   2200  gcOutput.module = ModuleObject::create(cx);
   2201  if (!gcOutput.module) {
   2202    return false;
   2203  }
   2204 
   2205  Rooted<ModuleObject*> module(cx, gcOutput.module);
   2206  return stencil.moduleMetadata->initModule(cx, fc, atomCache, module);
   2207 }
   2208 
   2209 // Instantiate JSFunctions for each FunctionBox.
   2210 static bool InstantiateFunctions(JSContext* cx, FrontendContext* fc,
   2211                                 CompilationAtomCache& atomCache,
   2212                                 const CompilationStencil& stencil,
   2213                                 CompilationGCOutput& gcOutput) {
   2214  using ImmutableFlags = ImmutableScriptFlagsEnum;
   2215 
   2216  MOZ_ASSERT(gcOutput.functions.length() == stencil.scriptData.size());
   2217 
   2218  // Most JSFunctions will be have the same Shape so we can compute it now to
   2219  // allow fast object creation. Generators / Async will use the slow path
   2220  // instead.
   2221  Rooted<SharedShape*> functionShape(
   2222      cx, GlobalObject::getFunctionShapeWithDefaultProto(
   2223              cx, /* extended = */ false));
   2224  if (!functionShape) {
   2225    return false;
   2226  }
   2227 
   2228  Rooted<SharedShape*> extendedShape(
   2229      cx, GlobalObject::getFunctionShapeWithDefaultProto(
   2230              cx, /* extended = */ true));
   2231  if (!extendedShape) {
   2232    return false;
   2233  }
   2234 
   2235  for (auto item :
   2236       CompilationStencil::functionScriptStencils(stencil, gcOutput)) {
   2237    const auto& scriptStencil = item.script;
   2238    const auto& scriptExtra = (*item.scriptExtra);
   2239    auto index = item.index;
   2240 
   2241    MOZ_ASSERT(!item.function);
   2242 
   2243    // Plain functions can use a fast path.
   2244    bool useFastPath =
   2245        !scriptExtra.immutableFlags.hasFlag(ImmutableFlags::IsAsync) &&
   2246        !scriptExtra.immutableFlags.hasFlag(ImmutableFlags::IsGenerator) &&
   2247        !scriptStencil.functionFlags.isAsmJSNative();
   2248 
   2249    JSFunction* fun;
   2250    if (useFastPath) {
   2251      Handle<SharedShape*> shape = scriptStencil.functionFlags.isExtended()
   2252                                       ? extendedShape
   2253                                       : functionShape;
   2254      fun =
   2255          CreateFunctionFast(cx, atomCache, shape, scriptStencil, scriptExtra);
   2256    } else {
   2257      fun = CreateFunction(cx, atomCache, stencil, scriptStencil, scriptExtra,
   2258                           index);
   2259    }
   2260 
   2261    if (!fun) {
   2262      return false;
   2263    }
   2264 
   2265    // Self-hosted functions may have a canonical name to use when instantiating
   2266    // into other realms.
   2267    if (scriptStencil.hasSelfHostedCanonicalName()) {
   2268      JSAtom* canonicalName = atomCache.getExistingAtomAt(
   2269          cx, scriptStencil.selfHostedCanonicalName());
   2270      fun->setAtom(canonicalName);
   2271    }
   2272 
   2273    gcOutput.getFunctionNoBaseIndex(index) = fun;
   2274  }
   2275 
   2276  return true;
   2277 }
   2278 
   2279 // Instantiate Scope for each ScopeStencil.
   2280 //
   2281 // This should be called after InstantiateFunctions, given FunctionScope needs
   2282 // associated JSFunction pointer, and also should be called before
   2283 // InstantiateScriptStencils, given JSScript needs Scope pointer in gc things.
   2284 static bool InstantiateScopes(JSContext* cx, CompilationInput& input,
   2285                              const CompilationStencil& stencil,
   2286                              CompilationGCOutput& gcOutput) {
   2287  // While allocating Scope object from ScopeStencil, Scope object for the
   2288  // enclosing Scope should already be allocated.
   2289  //
   2290  // Enclosing scope of ScopeStencil can be either ScopeStencil or Scope*
   2291  // pointer.
   2292  //
   2293  // If the enclosing scope is ScopeStencil, it's guaranteed to be earlier
   2294  // element in stencil.scopeData, because enclosing_ field holds
   2295  // index into it, and newly created ScopeStencil is pushed back to the array.
   2296  //
   2297  // If the enclosing scope is Scope*, it's CompilationInput.enclosingScope.
   2298 
   2299  MOZ_ASSERT(stencil.scopeData.size() == stencil.scopeNames.size());
   2300  size_t scopeCount = stencil.scopeData.size();
   2301  for (size_t i = 0; i < scopeCount; i++) {
   2302    Scope* scope = stencil.scopeData[i].createScope(cx, input, gcOutput,
   2303                                                    stencil.scopeNames[i]);
   2304    if (!scope) {
   2305      return false;
   2306    }
   2307    gcOutput.scopes[i] = scope;
   2308  }
   2309 
   2310  return true;
   2311 }
   2312 
   2313 // Instantiate js::BaseScripts from ScriptStencils for inner functions of the
   2314 // compilation. Note that standalone functions and functions being delazified
   2315 // are handled below with other top-levels.
   2316 static bool InstantiateScriptStencils(JSContext* cx,
   2317                                      CompilationAtomCache& atomCache,
   2318                                      const CompilationStencil& stencil,
   2319                                      CompilationGCOutput& gcOutput) {
   2320  MOZ_ASSERT(stencil.isInitialStencil());
   2321 
   2322  Rooted<JSFunction*> fun(cx);
   2323  for (auto item :
   2324       CompilationStencil::functionScriptStencils(stencil, gcOutput)) {
   2325    auto& scriptStencil = item.script;
   2326    auto* scriptExtra = item.scriptExtra;
   2327    fun = item.function;
   2328    auto index = item.index;
   2329    if (scriptStencil.hasSharedData()) {
   2330      // If the function was not referenced by enclosing script's bytecode, we
   2331      // do not generate a BaseScript for it. For example, `(function(){});`.
   2332      //
   2333      // `wasEmittedByEnclosingScript` is false also for standalone
   2334      // functions. They are handled in InstantiateTopLevel.
   2335      if (!scriptStencil.wasEmittedByEnclosingScript()) {
   2336        continue;
   2337      }
   2338 
   2339      RootedScript script(
   2340          cx, JSScript::fromStencil(cx, atomCache, stencil, gcOutput, index));
   2341      if (!script) {
   2342        return false;
   2343      }
   2344 
   2345      if (scriptStencil.allowRelazify()) {
   2346        MOZ_ASSERT(script->isRelazifiable());
   2347        script->setAllowRelazify();
   2348      }
   2349    } else if (scriptStencil.functionFlags.isAsmJSNative()) {
   2350      MOZ_ASSERT(fun->isAsmJSNative());
   2351    } else {
   2352      MOZ_ASSERT(fun->isIncomplete());
   2353      if (!CreateLazyScript(cx, atomCache, stencil, gcOutput, scriptStencil,
   2354                            *scriptExtra, index, fun)) {
   2355        return false;
   2356      }
   2357    }
   2358  }
   2359 
   2360  return true;
   2361 }
   2362 
   2363 // Instantiate the Stencil for the top-level script of the compilation. This
   2364 // includes standalone functions and functions being delazified.
   2365 static bool InstantiateTopLevel(JSContext* cx, CompilationInput& input,
   2366                                const CompilationStencil& stencil,
   2367                                CompilationGCOutput& gcOutput) {
   2368  const ScriptStencil& scriptStencil =
   2369      stencil.scriptData[CompilationStencil::TopLevelIndex];
   2370 
   2371  // Top-level asm.js does not generate a JSScript.
   2372  if (scriptStencil.functionFlags.isAsmJSNative()) {
   2373    return true;
   2374  }
   2375 
   2376  MOZ_ASSERT(scriptStencil.hasSharedData());
   2377  MOZ_ASSERT(stencil.sharedData.get(CompilationStencil::TopLevelIndex));
   2378 
   2379  if (!stencil.isInitialStencil()) {
   2380    MOZ_ASSERT(input.lazyOuterBaseScript());
   2381    RootedScript script(cx,
   2382                        JSScript::CastFromLazy(input.lazyOuterBaseScript()));
   2383    if (!JSScript::fullyInitFromStencil(cx, input.atomCache, stencil, gcOutput,
   2384                                        script,
   2385                                        CompilationStencil::TopLevelIndex)) {
   2386      return false;
   2387    }
   2388 
   2389    if (scriptStencil.allowRelazify()) {
   2390      MOZ_ASSERT(script->isRelazifiable());
   2391      script->setAllowRelazify();
   2392    }
   2393 
   2394    gcOutput.script = script;
   2395    return true;
   2396  }
   2397 
   2398  gcOutput.script =
   2399      JSScript::fromStencil(cx, input.atomCache, stencil, gcOutput,
   2400                            CompilationStencil::TopLevelIndex);
   2401  if (!gcOutput.script) {
   2402    return false;
   2403  }
   2404 
   2405  if (scriptStencil.allowRelazify()) {
   2406    MOZ_ASSERT(gcOutput.script->isRelazifiable());
   2407    gcOutput.script->setAllowRelazify();
   2408  }
   2409 
   2410  const ScriptStencilExtra& scriptExtra =
   2411      stencil.scriptExtra[CompilationStencil::TopLevelIndex];
   2412 
   2413  // Finish initializing the ModuleObject if needed.
   2414  if (scriptExtra.isModule()) {
   2415    RootedScript script(cx, gcOutput.script);
   2416    Rooted<ModuleObject*> module(cx, gcOutput.module);
   2417 
   2418    script->outermostScope()->as<ModuleScope>().initModule(module);
   2419 
   2420    module->initScriptSlots(script);
   2421 
   2422    if (!ModuleObject::createEnvironment(cx, module)) {
   2423      return false;
   2424    }
   2425 
   2426    if (!ModuleObject::Freeze(cx, module)) {
   2427      return false;
   2428    }
   2429  }
   2430 
   2431  return true;
   2432 }
   2433 
   2434 // When a function is first referenced by enclosing script's bytecode, we need
   2435 // to update it with information determined by the BytecodeEmitter. This applies
   2436 // to both initial and delazification parses. The functions being update may or
   2437 // may not have bytecode at this point.
   2438 static void UpdateEmittedInnerFunctions(JSContext* cx,
   2439                                        CompilationAtomCache& atomCache,
   2440                                        const CompilationStencil& stencil,
   2441                                        CompilationGCOutput& gcOutput) {
   2442  for (auto item :
   2443       CompilationStencil::functionScriptStencils(stencil, gcOutput)) {
   2444    auto& scriptStencil = item.script;
   2445    auto& fun = item.function;
   2446    if (!scriptStencil.wasEmittedByEnclosingScript()) {
   2447      continue;
   2448    }
   2449 
   2450    if (scriptStencil.functionFlags.isAsmJSNative() ||
   2451        fun->baseScript()->hasBytecode()) {
   2452      // Non-lazy inner functions don't use the enclosingScope_ field.
   2453      MOZ_ASSERT(!scriptStencil.hasLazyFunctionEnclosingScopeIndex());
   2454    } else {
   2455      // Apply updates from FunctionEmitter::emitLazy().
   2456      BaseScript* script = fun->baseScript();
   2457 
   2458      ScopeIndex index = scriptStencil.lazyFunctionEnclosingScopeIndex();
   2459      Scope* scope = gcOutput.getScopeNoBaseIndex(index);
   2460      script->setEnclosingScope(scope);
   2461 
   2462      // Inferred and Guessed names are computed by BytecodeEmitter and so may
   2463      // need to be applied to existing JSFunctions during delazification.
   2464      if (fun->fullDisplayAtom() == nullptr) {
   2465        JSAtom* funcAtom = nullptr;
   2466        if (scriptStencil.functionFlags.hasInferredName() ||
   2467            scriptStencil.functionFlags.hasGuessedAtom()) {
   2468          funcAtom =
   2469              atomCache.getExistingAtomAt(cx, scriptStencil.functionAtom);
   2470          MOZ_ASSERT(funcAtom);
   2471        }
   2472        if (scriptStencil.functionFlags.hasInferredName()) {
   2473          fun->setInferredName(funcAtom);
   2474        }
   2475        if (scriptStencil.functionFlags.hasGuessedAtom()) {
   2476          fun->setGuessedAtom(funcAtom);
   2477        }
   2478      }
   2479    }
   2480  }
   2481 }
   2482 
   2483 // During initial parse we must link lazy-functions-inside-lazy-functions to
   2484 // their enclosing script.
   2485 static void LinkEnclosingLazyScript(const CompilationStencil& stencil,
   2486                                    CompilationGCOutput& gcOutput) {
   2487  for (auto item :
   2488       CompilationStencil::functionScriptStencils(stencil, gcOutput)) {
   2489    auto& scriptStencil = item.script;
   2490    auto& fun = item.function;
   2491    if (!scriptStencil.functionFlags.hasBaseScript()) {
   2492      continue;
   2493    }
   2494 
   2495    if (!fun->baseScript()) {
   2496      continue;
   2497    }
   2498 
   2499    if (fun->baseScript()->hasBytecode()) {
   2500      continue;
   2501    }
   2502 
   2503    BaseScript* script = fun->baseScript();
   2504    MOZ_ASSERT(!script->hasBytecode());
   2505 
   2506    for (auto inner : script->gcthings()) {
   2507      if (!inner.is<JSObject>()) {
   2508        continue;
   2509      }
   2510      JSFunction* innerFun = &inner.as<JSObject>().as<JSFunction>();
   2511 
   2512      MOZ_ASSERT(innerFun->hasBaseScript(),
   2513                 "inner function should have base script");
   2514      if (!innerFun->hasBaseScript()) {
   2515        continue;
   2516      }
   2517 
   2518      // Check for the case that the inner function has the base script flag,
   2519      // but still doesn't have the actual base script pointer.
   2520      // `baseScript` method asserts the pointer itself, so no extra MOZ_ASSERT
   2521      // here.
   2522      if (!innerFun->baseScript()) {
   2523        continue;
   2524      }
   2525 
   2526      innerFun->setEnclosingLazyScript(script);
   2527    }
   2528  }
   2529 }
   2530 
   2531 #ifdef DEBUG
   2532 // Some fields aren't used in delazification, given the target functions and
   2533 // scripts are already instantiated, but they still should match.
   2534 static void AssertDelazificationFieldsMatch(const CompilationStencil& stencil,
   2535                                            CompilationGCOutput& gcOutput) {
   2536  for (auto item :
   2537       CompilationStencil::functionScriptStencils(stencil, gcOutput)) {
   2538    auto& scriptStencil = item.script;
   2539    auto* scriptExtra = item.scriptExtra;
   2540    auto& fun = item.function;
   2541 
   2542    MOZ_ASSERT(scriptExtra == nullptr);
   2543 
   2544    // Names are updated by UpdateInnerFunctions.
   2545    constexpr uint16_t HAS_INFERRED_NAME =
   2546        uint16_t(FunctionFlags::Flags::HAS_INFERRED_NAME);
   2547    constexpr uint16_t HAS_GUESSED_ATOM =
   2548        uint16_t(FunctionFlags::Flags::HAS_GUESSED_ATOM);
   2549    constexpr uint16_t MUTABLE_FLAGS =
   2550        uint16_t(FunctionFlags::Flags::MUTABLE_FLAGS);
   2551    constexpr uint16_t acceptableDifferenceForFunction =
   2552        HAS_INFERRED_NAME | HAS_GUESSED_ATOM | MUTABLE_FLAGS;
   2553 
   2554    MOZ_ASSERT((fun->flags().toRaw() | acceptableDifferenceForFunction) ==
   2555               (scriptStencil.functionFlags.toRaw() |
   2556                acceptableDifferenceForFunction));
   2557 
   2558    // Delazification shouldn't delazify inner scripts.
   2559    MOZ_ASSERT_IF(item.index == CompilationStencil::TopLevelIndex,
   2560                  scriptStencil.hasSharedData());
   2561    MOZ_ASSERT_IF(item.index > CompilationStencil::TopLevelIndex,
   2562                  !scriptStencil.hasSharedData());
   2563  }
   2564 }
   2565 #endif  // DEBUG
   2566 
   2567 // When delazifying, use the existing JSFunctions. The initial and delazifying
   2568 // parse are required to generate the same sequence of functions for lazy
   2569 // parsing to work at all.
   2570 static void FunctionsFromExistingLazy(CompilationInput& input,
   2571                                      CompilationGCOutput& gcOutput) {
   2572  MOZ_ASSERT(!gcOutput.functions[0]);
   2573 
   2574  size_t instantiatedFunIndex = 0;
   2575  gcOutput.functions[instantiatedFunIndex++] = input.function();
   2576 
   2577  for (JS::GCCellPtr elem : input.lazyOuterBaseScript()->gcthings()) {
   2578    if (!elem.is<JSObject>()) {
   2579      continue;
   2580    }
   2581    JSFunction* fun = &elem.as<JSObject>().as<JSFunction>();
   2582    gcOutput.functions[instantiatedFunIndex++] = fun;
   2583  }
   2584 }
   2585 
   2586 void CompilationStencil::borrowFromExtensibleCompilationStencil(
   2587    ExtensibleCompilationStencil& extensibleStencil) {
   2588  canLazilyParse = extensibleStencil.canLazilyParse;
   2589  functionKey = extensibleStencil.functionKey;
   2590 
   2591  // Borrow the vector content as span.
   2592  scriptData = extensibleStencil.scriptData;
   2593  scriptExtra = extensibleStencil.scriptExtra;
   2594 
   2595  gcThingData = extensibleStencil.gcThingData;
   2596 
   2597  scopeData = extensibleStencil.scopeData;
   2598  scopeNames = extensibleStencil.scopeNames;
   2599 
   2600  regExpData = extensibleStencil.regExpData;
   2601  bigIntData = extensibleStencil.bigIntData;
   2602  objLiteralData = extensibleStencil.objLiteralData;
   2603 
   2604  // Borrow the parser atoms as span.
   2605  parserAtomData = extensibleStencil.parserAtoms.entries_;
   2606 
   2607  // Borrow container.
   2608  sharedData.setBorrow(&extensibleStencil.sharedData);
   2609 
   2610  // Share ref-counted data.
   2611  source = extensibleStencil.source;
   2612  asmJS = extensibleStencil.asmJS;
   2613  moduleMetadata = extensibleStencil.moduleMetadata;
   2614 }
   2615 
   2616 #ifdef DEBUG
   2617 void CompilationStencil::assertBorrowingFromExtensibleCompilationStencil(
   2618    const ExtensibleCompilationStencil& extensibleStencil) const {
   2619  MOZ_ASSERT(canLazilyParse == extensibleStencil.canLazilyParse);
   2620  MOZ_ASSERT(functionKey == extensibleStencil.functionKey);
   2621 
   2622  AssertBorrowingSpan(scriptData, extensibleStencil.scriptData);
   2623  AssertBorrowingSpan(scriptExtra, extensibleStencil.scriptExtra);
   2624 
   2625  AssertBorrowingSpan(gcThingData, extensibleStencil.gcThingData);
   2626 
   2627  AssertBorrowingSpan(scopeData, extensibleStencil.scopeData);
   2628  AssertBorrowingSpan(scopeNames, extensibleStencil.scopeNames);
   2629 
   2630  AssertBorrowingSpan(regExpData, extensibleStencil.regExpData);
   2631  AssertBorrowingSpan(bigIntData, extensibleStencil.bigIntData);
   2632  AssertBorrowingSpan(objLiteralData, extensibleStencil.objLiteralData);
   2633 
   2634  AssertBorrowingSpan(parserAtomData, extensibleStencil.parserAtoms.entries_);
   2635 
   2636  MOZ_ASSERT(sharedData.isBorrow());
   2637  MOZ_ASSERT(sharedData.asBorrow() == &extensibleStencil.sharedData);
   2638 
   2639  MOZ_ASSERT(source == extensibleStencil.source);
   2640  MOZ_ASSERT(asmJS == extensibleStencil.asmJS);
   2641  MOZ_ASSERT(moduleMetadata == extensibleStencil.moduleMetadata);
   2642 }
   2643 #endif
   2644 
   2645 CompilationStencil::CompilationStencil(
   2646    UniquePtr<ExtensibleCompilationStencil>&& extensibleStencil)
   2647    : alloc(LifoAllocChunkSize, js::BackgroundMallocArena) {
   2648  ownedBorrowStencil = std::move(extensibleStencil);
   2649 
   2650  storageType = StorageType::OwnedExtensible;
   2651 
   2652  borrowFromExtensibleCompilationStencil(*ownedBorrowStencil);
   2653 
   2654 #ifdef DEBUG
   2655  assertNoExternalDependency();
   2656 #endif
   2657 }
   2658 
   2659 // Instantiate JitScripts and eagerly baseline compile any potential
   2660 // candidate functions.
   2661 //
   2662 // Return value indicates whether a failure occured. (i.e. allocation failure.)
   2663 // There is no current indication of whether a function was actually dispatched
   2664 // for eager baseline compilation.
   2665 static bool MaybeDoEagerBaselineCompilations(JSContext* cx,
   2666                                             const CompilationStencil& stencil,
   2667                                             CompilationGCOutput& gcOutput,
   2668                                             bool doAggressive) {
   2669  if (!jit::IsBaselineInterpreterEnabled()) {
   2670    return true;
   2671  }
   2672 
   2673  if (!cx->zone()->ensureJitZoneExists(cx)) {
   2674    return false;
   2675  }
   2676 
   2677  jit::JitHintsMap* jitHints = nullptr;
   2678  if (!doAggressive) {
   2679    if (jit::JitOptions.disableJitHints ||
   2680        !cx->runtime()->jitRuntime()->hasJitHintsMap()) {
   2681      return true;
   2682    }
   2683    jitHints = cx->runtime()->jitRuntime()->getJitHintsMap();
   2684  }
   2685 
   2686  jit::AutoKeepJitScripts keepJitScript(cx);
   2687  RootedScript script(cx);
   2688  Rooted<JSFunction*> fn(cx);
   2689  jit::BaselineCompileQueue& queue = cx->realm()->baselineCompileQueue();
   2690 
   2691  for (auto item :
   2692       CompilationStencil::functionScriptStencils(stencil, gcOutput)) {
   2693    fn = item.function;
   2694    if (!fn->hasBytecode()) {
   2695      continue;
   2696    }
   2697 
   2698    script = fn->nonLazyScript();
   2699 
   2700    // Only eagerly baseline compile functions with hints unless aggressive
   2701    // strategy is set.
   2702    if (!doAggressive) {
   2703      if (!jitHints->mightHaveEagerBaselineHint(script)) {
   2704        continue;
   2705      }
   2706    }
   2707 
   2708    if (script->baselineDisabled()) {
   2709      continue;
   2710    }
   2711 
   2712    if (!jit::CanBaselineInterpretScript(script)) {
   2713      continue;
   2714    }
   2715 
   2716    if (!jit::BaselineCompileTask::OffThreadBaselineCompilationAvailable(
   2717            cx, script, /* isEager = */ true)) {
   2718      continue;
   2719    }
   2720 
   2721    // Add script to the baseline compile batch queue and dispatch if full.
   2722    if (queue.numQueued() >= jit::JitOptions.baselineQueueCapacity) {
   2723      if (!jit::DispatchOffThreadBaselineBatchEager(cx)) {
   2724        return false;
   2725      }
   2726      TRACE_FOR_TEST_DOM(cx, "omt_eager_baseline_dispatch");
   2727    }
   2728 
   2729    // Add script to queue
   2730    if (!queue.enqueue(script)) {
   2731      return false;
   2732    }
   2733    TRACE_FOR_TEST_DOM(cx, "omt_eager_baseline_function", script);
   2734  }
   2735 
   2736  // Dispatch any remaining scripts in the queue
   2737  if (queue.numQueued() > 0) {
   2738    if (!jit::DispatchOffThreadBaselineBatchEager(cx)) {
   2739      return false;
   2740    }
   2741    TRACE_FOR_TEST_DOM(cx, "omt_eager_baseline_dispatch");
   2742  }
   2743 
   2744  return true;
   2745 }
   2746 
   2747 /* static */
   2748 bool CompilationStencil::instantiateStencils(JSContext* cx,
   2749                                             CompilationInput& input,
   2750                                             const CompilationStencil& stencil,
   2751                                             CompilationGCOutput& gcOutput) {
   2752  AutoReportFrontendContext fc(cx);
   2753  if (!prepareForInstantiate(&fc, input.atomCache, stencil, gcOutput)) {
   2754    return false;
   2755  }
   2756 
   2757  if (!instantiateStencilAfterPreparation(cx, input, stencil, gcOutput)) {
   2758    return false;
   2759  }
   2760 
   2761  if (input.options.eagerBaselineStrategy() != JS::EagerBaselineOption::None) {
   2762    MOZ_ASSERT(!input.isDelazifying(),
   2763               "No current support for eager baseline during delazifications.");
   2764 
   2765    bool doAggressive = input.options.eagerBaselineStrategy() ==
   2766                        JS::EagerBaselineOption::Aggressive;
   2767    if (!MaybeDoEagerBaselineCompilations(cx, stencil, gcOutput,
   2768                                          doAggressive)) {
   2769      return false;
   2770    }
   2771  }
   2772 
   2773  return true;
   2774 }
   2775 
   2776 /* static */
   2777 bool CompilationStencil::instantiateStencilAfterPreparation(
   2778    JSContext* cx, CompilationInput& input, const CompilationStencil& stencil,
   2779    CompilationGCOutput& gcOutput) {
   2780  // Distinguish between the initial (possibly lazy) compile and any subsequent
   2781  // delazification compiles. Delazification will update existing GC things.
   2782  bool isInitialParse = stencil.isInitialStencil();
   2783  MOZ_ASSERT(stencil.isInitialStencil() == input.isInitialStencil());
   2784 
   2785  // Assert the consistency between the compile option and the target global.
   2786  MOZ_ASSERT_IF(cx->realm()->behaviors().discardSource(),
   2787                !stencil.canLazilyParse);
   2788 
   2789  CompilationAtomCache& atomCache = input.atomCache;
   2790  const JS::InstantiateOptions options(input.options);
   2791 
   2792  // Phase 1: Instantiate JSAtom/JSStrings.
   2793  AutoReportFrontendContext fc(cx);
   2794  if (!InstantiateAtoms(cx, &fc, atomCache, stencil)) {
   2795    return false;
   2796  }
   2797 
   2798  // Phase 2: Instantiate ScriptSourceObject, ModuleObject, JSFunctions.
   2799  if (isInitialParse) {
   2800    if (!InstantiateScriptSourceObject(cx, options, stencil, gcOutput)) {
   2801      return false;
   2802    }
   2803 
   2804    if (stencil.moduleMetadata) {
   2805      // The enclosing script of a module is always the global scope. Fetch the
   2806      // scope of the current global and update input data.
   2807      MOZ_ASSERT(input.enclosingScope.isNull());
   2808      input.enclosingScope = InputScope(&cx->global()->emptyGlobalScope());
   2809      MOZ_ASSERT(input.enclosingScope.environmentChainLength() ==
   2810                 ModuleScope::EnclosingEnvironmentChainLength);
   2811 
   2812      if (!InstantiateModuleObject(cx, &fc, atomCache, stencil, gcOutput)) {
   2813        return false;
   2814      }
   2815    }
   2816 
   2817    if (!InstantiateFunctions(cx, &fc, atomCache, stencil, gcOutput)) {
   2818      return false;
   2819    }
   2820  } else {
   2821    MOZ_ASSERT(
   2822        stencil.scriptData[CompilationStencil::TopLevelIndex].isFunction());
   2823 
   2824    // FunctionKey is used when caching to map a delazification stencil to a
   2825    // specific lazy script. It is not used by instantiation, but we should
   2826    // ensure it is correctly defined.
   2827    MOZ_ASSERT(stencil.functionKey == input.extent().toFunctionKey());
   2828 
   2829    FunctionsFromExistingLazy(input, gcOutput);
   2830    MOZ_ASSERT(gcOutput.functions.length() == stencil.scriptData.size());
   2831 
   2832 #ifdef DEBUG
   2833    AssertDelazificationFieldsMatch(stencil, gcOutput);
   2834 #endif
   2835  }
   2836 
   2837  // Phase 3: Instantiate js::Scopes.
   2838  if (!InstantiateScopes(cx, input, stencil, gcOutput)) {
   2839    return false;
   2840  }
   2841 
   2842  // Phase 4: Instantiate (inner) BaseScripts.
   2843  if (isInitialParse) {
   2844    if (!InstantiateScriptStencils(cx, atomCache, stencil, gcOutput)) {
   2845      return false;
   2846    }
   2847  }
   2848 
   2849  // Phase 5: Finish top-level handling
   2850  if (!InstantiateTopLevel(cx, input, stencil, gcOutput)) {
   2851    return false;
   2852  }
   2853 
   2854  // !! Must be infallible from here forward !!
   2855 
   2856  // Phase 6: Update lazy scripts.
   2857  if (stencil.canLazilyParse) {
   2858    UpdateEmittedInnerFunctions(cx, atomCache, stencil, gcOutput);
   2859 
   2860    if (isInitialParse) {
   2861      LinkEnclosingLazyScript(stencil, gcOutput);
   2862    }
   2863  }
   2864 
   2865  // Trigger the use counter for asm.js. This should fire even if asm.js
   2866  // optimizations are disabled, see the comment in FunctionBox::setUseAsm()
   2867  // for how we do that.
   2868  if (stencil.hasAsmJS()) {
   2869    cx->runtime()->setUseCounter(cx->global(), JSUseCounter::USE_ASM);
   2870  }
   2871 
   2872  return true;
   2873 }
   2874 
   2875 // The top-level self-hosted script is created and executed in each realm that
   2876 // needs it. While the stencil has a gcthings list for the various top-level
   2877 // functions, we use special machinery to create them on demand. So instead we
   2878 // use a placeholder JSFunction that should never be called.
   2879 static bool SelfHostedDummyFunction(JSContext* cx, unsigned argc,
   2880                                    JS::Value* vp) {
   2881  MOZ_CRASH("Self-hosting top-level should not use functions directly");
   2882 }
   2883 
   2884 bool CompilationStencil::instantiateSelfHostedAtoms(
   2885    JSContext* cx, AtomSet& atomSet, CompilationAtomCache& atomCache) const {
   2886  MOZ_ASSERT(isInitialStencil());
   2887 
   2888  // We must instantiate atoms during startup so they can be made permanent
   2889  // across multiple runtimes.
   2890  AutoReportFrontendContext fc(cx);
   2891  return InstantiateMarkedAtomsAsPermanent(cx, &fc, atomSet, parserAtomData,
   2892                                           atomCache);
   2893 }
   2894 
   2895 JSScript* CompilationStencil::instantiateSelfHostedTopLevelForRealm(
   2896    JSContext* cx, CompilationInput& input) {
   2897  MOZ_ASSERT(isInitialStencil());
   2898 
   2899  Rooted<CompilationGCOutput> gcOutput(cx);
   2900 
   2901  gcOutput.get().sourceObject = SelfHostingScriptSourceObject(cx);
   2902  if (!gcOutput.get().sourceObject) {
   2903    return nullptr;
   2904  }
   2905 
   2906  // The top-level script has ScriptIndex references in its gcthings list, but
   2907  // we do not want to instantiate those functions here since they are instead
   2908  // created on demand from the stencil. Create a dummy function and populate
   2909  // the functions array of the CompilationGCOutput with references to it.
   2910  RootedFunction dummy(
   2911      cx, NewNativeFunction(cx, SelfHostedDummyFunction, 0, nullptr));
   2912  if (!dummy) {
   2913    return nullptr;
   2914  }
   2915 
   2916  if (!gcOutput.get().functions.allocateWith(dummy, scriptData.size())) {
   2917    ReportOutOfMemory(cx);
   2918    return nullptr;
   2919  }
   2920 
   2921  if (!InstantiateTopLevel(cx, input, *this, gcOutput.get())) {
   2922    return nullptr;
   2923  }
   2924 
   2925  return gcOutput.get().script;
   2926 }
   2927 
   2928 JSFunction* CompilationStencil::instantiateSelfHostedLazyFunction(
   2929    JSContext* cx, CompilationAtomCache& atomCache, ScriptIndex index,
   2930    Handle<JSAtom*> name) {
   2931  MOZ_ASSERT(cx->zone()->suppressAllocationMetadataBuilder);
   2932 
   2933  GeneratorKind generatorKind = scriptExtra[index].immutableFlags.hasFlag(
   2934                                    ImmutableScriptFlagsEnum::IsGenerator)
   2935                                    ? GeneratorKind::Generator
   2936                                    : GeneratorKind::NotGenerator;
   2937  FunctionAsyncKind asyncKind = scriptExtra[index].immutableFlags.hasFlag(
   2938                                    ImmutableScriptFlagsEnum::IsAsync)
   2939                                    ? FunctionAsyncKind::AsyncFunction
   2940                                    : FunctionAsyncKind::SyncFunction;
   2941 
   2942  Rooted<JSAtom*> funName(cx);
   2943  if (scriptData[index].hasSelfHostedCanonicalName()) {
   2944    // SetCanonicalName was used to override the name.
   2945    funName = atomCache.getExistingAtomAt(
   2946        cx, scriptData[index].selfHostedCanonicalName());
   2947  } else if (name) {
   2948    // Our caller has a name it wants to use.
   2949    funName = name;
   2950  } else {
   2951    MOZ_ASSERT(scriptData[index].functionAtom);
   2952    funName = atomCache.getExistingAtomAt(cx, scriptData[index].functionAtom);
   2953  }
   2954 
   2955  RootedObject proto(cx);
   2956  if (!GetFunctionPrototype(cx, generatorKind, asyncKind, &proto)) {
   2957    return nullptr;
   2958  }
   2959 
   2960  RootedObject env(cx, &cx->global()->lexicalEnvironment());
   2961 
   2962  JSFunction* fun = NewFunctionWithProto(
   2963      cx, nullptr, scriptExtra[index].nargs, scriptData[index].functionFlags,
   2964      env, funName, proto, gc::AllocKind::FUNCTION_EXTENDED, TenuredObject);
   2965  if (!fun) {
   2966    return nullptr;
   2967  }
   2968 
   2969  fun->initSelfHostedLazyScript(&cx->runtime()->selfHostedLazyScript.ref());
   2970 
   2971  JSAtom* selfHostedName =
   2972      atomCache.getExistingAtomAt(cx, scriptData[index].functionAtom);
   2973  SetClonedSelfHostedFunctionName(fun, selfHostedName->asPropertyName());
   2974 
   2975  return fun;
   2976 }
   2977 
   2978 bool CompilationStencil::delazifySelfHostedFunction(
   2979    JSContext* cx, CompilationAtomCache& atomCache, ScriptIndexRange range,
   2980    Handle<JSAtom*> name, HandleFunction fun) {
   2981  // Determine the equivalent ScopeIndex range by looking at the outermost scope
   2982  // of the scripts defining the range. Take special care if this is the last
   2983  // script in the list.
   2984  auto getOutermostScope = [this](ScriptIndex scriptIndex) -> ScopeIndex {
   2985    MOZ_ASSERT(scriptData[scriptIndex].hasSharedData());
   2986    auto gcthings = scriptData[scriptIndex].gcthings(*this);
   2987    return gcthings[GCThingIndex::outermostScopeIndex()].toScope();
   2988  };
   2989  ScopeIndex scopeIndex = getOutermostScope(range.start);
   2990  ScopeIndex scopeLimit = (range.limit < scriptData.size())
   2991                              ? getOutermostScope(range.limit)
   2992                              : ScopeIndex(scopeData.size());
   2993 
   2994  // Prepare to instantiate by allocating the output arrays. We also set a base
   2995  // index to avoid allocations in most cases.
   2996  AutoReportFrontendContext fc(cx);
   2997  Rooted<CompilationGCOutput> gcOutput(cx);
   2998  if (!gcOutput.get().ensureAllocatedWithBaseIndex(
   2999          &fc, range.start, range.limit, scopeIndex, scopeLimit)) {
   3000    return false;
   3001  }
   3002 
   3003  // Phase 1: Instantiate JSAtoms.
   3004  //  NOTE: The self-hosted atoms are all "permanent" and the
   3005  //        CompilationAtomCache is already stored on the JSRuntime.
   3006 
   3007  // Phase 2: Instantiate ScriptSourceObject, ModuleObject, JSFunctions.
   3008 
   3009  // Get the corresponding ScriptSourceObject to use in current realm.
   3010  gcOutput.get().sourceObject = SelfHostingScriptSourceObject(cx);
   3011  if (!gcOutput.get().sourceObject) {
   3012    return false;
   3013  }
   3014 
   3015  size_t instantiatedFunIndex = 0;
   3016 
   3017  // Delazification target function.
   3018  gcOutput.get().functions[instantiatedFunIndex++] = fun;
   3019 
   3020  // Allocate inner functions. Self-hosted functions do not allocate these with
   3021  // the initial function.
   3022  for (size_t i = range.start + 1; i < range.limit; i++) {
   3023    JSFunction* innerFun = CreateFunction(cx, atomCache, *this, scriptData[i],
   3024                                          scriptExtra[i], ScriptIndex(i));
   3025    if (!innerFun) {
   3026      return false;
   3027    }
   3028    gcOutput.get().functions[instantiatedFunIndex++] = innerFun;
   3029  }
   3030 
   3031  // Phase 3: Instantiate js::Scopes.
   3032  // NOTE: When the enclosing scope is not a stencil, directly use the
   3033  //       `emptyGlobalScope` instead of reading from CompilationInput. This is
   3034  //       a special case for self-hosted delazification that allows us to reuse
   3035  //       the CompilationInput between different realms.
   3036  size_t instantiatedScopeIndex = 0;
   3037  for (size_t i = scopeIndex; i < scopeLimit; i++) {
   3038    ScopeStencil& data = scopeData[i];
   3039    Rooted<Scope*> enclosingScope(
   3040        cx, data.hasEnclosing() ? gcOutput.get().getScope(data.enclosing())
   3041                                : &cx->global()->emptyGlobalScope());
   3042 
   3043    js::Scope* scope =
   3044        data.createScope(cx, atomCache, enclosingScope, scopeNames[i]);
   3045    if (!scope) {
   3046      return false;
   3047    }
   3048    gcOutput.get().scopes[instantiatedScopeIndex++] = scope;
   3049  }
   3050 
   3051  // Phase 4: Instantiate (inner) BaseScripts.
   3052  ScriptIndex innerStart(range.start + 1);
   3053  for (size_t i = innerStart; i < range.limit; i++) {
   3054    if (!JSScript::fromStencil(cx, atomCache, *this, gcOutput.get(),
   3055                               ScriptIndex(i))) {
   3056      return false;
   3057    }
   3058  }
   3059 
   3060  // Phase 5: Finish top-level handling
   3061  // NOTE: We do not have a `CompilationInput` handy here, so avoid using the
   3062  //       `InstantiateTopLevel` helper and directly create the JSScript. Our
   3063  //       caller also handles the `AllowRelazify` flag for us since self-hosted
   3064  //       delazification is a special case.
   3065  Rooted<JSScript*> script(
   3066      cx,
   3067      JSScript::fromStencil(cx, atomCache, *this, gcOutput.get(), range.start));
   3068  if (!script) {
   3069    return false;
   3070  }
   3071 
   3072  if (JS::Prefs::experimental_self_hosted_cache()) {
   3073    Rooted<JSRuntime::JitCacheKey> jitCacheKey(cx, name, script->isDebuggee());
   3074 
   3075    // We eagerly baseline-compile self-hosted functions, and cache their
   3076    // JitCode for reuse across the runtime. If the cache already contains an
   3077    // entry for this function, update the JitScript. If not, compile it now and
   3078    // store it in the cache.
   3079    UniqueChars nameStr;
   3080    if (JS_SHOULD_LOG(selfHosted, Debug)) {
   3081      nameStr = AtomToPrintableString(cx, name);
   3082    }
   3083    auto& jitCache = cx->runtime()->selfHostJitCache.ref();
   3084    auto v = jitCache.readonlyThreadsafeLookup(jitCacheKey);
   3085    if (v && v->value()->method()) {
   3086      JS_LOG(selfHosted, Debug,
   3087             "self_hosted_cache: reusing JIT code for script '%s'",
   3088             nameStr.get());
   3089 
   3090      if (!cx->zone()->ensureJitZoneExists(cx)) {
   3091        return false;
   3092      }
   3093      jit::AutoKeepJitScripts keepJitScript(cx);
   3094      if (!script->ensureHasJitScript(cx, keepJitScript)) {
   3095        return false;
   3096      }
   3097      MOZ_ASSERT(!script->hasBaselineScript());
   3098 
   3099      // JSScript destroys its BaselineScript on finalize, so we need another
   3100      // copy here (for now)
   3101      jit::BaselineScript* baselineScript =
   3102          jit::BaselineScript::Copy(cx, v->value());
   3103      if (!baselineScript) {
   3104        return false;
   3105      }
   3106      mozilla::DebugOnly<bool> instrumentationEnabled =
   3107          cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(
   3108              cx->runtime());
   3109      MOZ_ASSERT(instrumentationEnabled ==
   3110                 baselineScript->isProfilerInstrumentationOn());
   3111      script->jitScript()->setBaselineScript(script, baselineScript);
   3112    } else if (jit::IsBaselineJitEnabled(cx) && script->canBaselineCompile() &&
   3113               !script->hasBaselineScript() &&
   3114               jit::CanBaselineInterpretScript(script)) {
   3115      JS_LOG(selfHosted, Debug,
   3116             "self_hosted_cache: new JIT code entry for script '%s'",
   3117             nameStr.get());
   3118 
   3119      if (!cx->zone()->ensureJitZoneExists(cx)) {
   3120        return false;
   3121      }
   3122 
   3123      jit::AutoKeepJitScripts keep(cx);
   3124      if (!script->ensureHasJitScript(cx, keep)) {
   3125        return false;
   3126      }
   3127 
   3128      jit::BaselineOptions options(
   3129          {jit::BaselineOption::ForceMainThreadCompilation});
   3130      jit::MethodStatus result =
   3131          jit::BaselineCompile(cx, script.get(), options);
   3132      if (result != jit::Method_Compiled) {
   3133        return false;
   3134      }
   3135      MOZ_ASSERT(script->hasBaselineScript());
   3136 
   3137      jit::BaselineScript* baselineScript =
   3138          jit::BaselineScript::Copy(cx, script->baselineScript());
   3139      if (!baselineScript) {
   3140        return false;
   3141      }
   3142      if (!jitCache.put(jitCacheKey, baselineScript)) {
   3143        return false;
   3144      }
   3145    } else {
   3146      JS_LOG(selfHosted, Debug,
   3147             "self_hosted_cache: script '%s' is not eligible for Baseline "
   3148             "compilation",
   3149             nameStr.get());
   3150    }
   3151  }
   3152 
   3153  // Phase 6: Update lazy scripts.
   3154  //  NOTE: Self-hosting is always fully parsed so there is nothing to do here.
   3155 
   3156  return true;
   3157 }
   3158 
   3159 /* static */
   3160 bool CompilationStencil::prepareForInstantiate(
   3161    FrontendContext* fc, CompilationAtomCache& atomCache,
   3162    const CompilationStencil& stencil, CompilationGCOutput& gcOutput) {
   3163  // Allocate the `gcOutput` arrays.
   3164  if (!gcOutput.ensureAllocated(fc, stencil.scriptData.size(),
   3165                                stencil.scopeData.size())) {
   3166    return false;
   3167  }
   3168 
   3169  return atomCache.allocate(fc, stencil.parserAtomData.size());
   3170 }
   3171 
   3172 /* static */
   3173 bool CompilationStencil::prepareForInstantiate(
   3174    FrontendContext* fc, const CompilationStencil& stencil,
   3175    PreallocatedCompilationGCOutput& gcOutput) {
   3176  return gcOutput.allocate(fc, stencil.scriptData.size(),
   3177                           stencil.scopeData.size());
   3178 }
   3179 
   3180 bool JS::PrepareForInstantiate(JS::FrontendContext* fc, JS::Stencil& stencil,
   3181                               JS::InstantiationStorage& storage) {
   3182  if (!storage.gcOutput_) {
   3183    storage.gcOutput_ =
   3184        fc->getAllocator()
   3185            ->new_<js::frontend::PreallocatedCompilationGCOutput>();
   3186    if (!storage.gcOutput_) {
   3187      return false;
   3188    }
   3189  }
   3190 
   3191  return CompilationStencil::prepareForInstantiate(fc, *stencil.getInitial(),
   3192                                                   *storage.gcOutput_);
   3193 }
   3194 
   3195 ExtensibleCompilationStencil::ExtensibleCompilationStencil(ScriptSource* source)
   3196    : alloc(CompilationStencil::LifoAllocChunkSize, js::BackgroundMallocArena),
   3197      source(source),
   3198      parserAtoms(alloc) {}
   3199 
   3200 ExtensibleCompilationStencil::ExtensibleCompilationStencil(
   3201    CompilationInput& input)
   3202    : canLazilyParse(CanLazilyParse(input.options)),
   3203      alloc(CompilationStencil::LifoAllocChunkSize, js::BackgroundMallocArena),
   3204      source(input.source),
   3205      parserAtoms(alloc) {}
   3206 
   3207 ExtensibleCompilationStencil::ExtensibleCompilationStencil(
   3208    const JS::ReadOnlyCompileOptions& options, RefPtr<ScriptSource> source)
   3209    : canLazilyParse(CanLazilyParse(options)),
   3210      alloc(CompilationStencil::LifoAllocChunkSize, js::BackgroundMallocArena),
   3211      source(std::move(source)),
   3212      parserAtoms(alloc) {}
   3213 
   3214 CompilationState::CompilationState(FrontendContext* fc,
   3215                                   LifoAllocScope& parserAllocScope,
   3216                                   CompilationInput& input)
   3217    : ExtensibleCompilationStencil(input),
   3218      directives(input.options.forceStrictMode()),
   3219      usedNames(fc),
   3220      parserAllocScope(parserAllocScope),
   3221      input(input) {}
   3222 
   3223 BorrowingCompilationStencil::BorrowingCompilationStencil(
   3224    ExtensibleCompilationStencil& extensibleStencil)
   3225    : CompilationStencil(extensibleStencil.source) {
   3226  storageType = StorageType::Borrowed;
   3227 
   3228  borrowFromExtensibleCompilationStencil(extensibleStencil);
   3229 }
   3230 
   3231 SharedDataContainer::~SharedDataContainer() {
   3232  if (isEmpty()) {
   3233    // Nothing to do.
   3234  } else if (isSingle()) {
   3235    asSingle()->Release();
   3236  } else if (isVector()) {
   3237    js_delete(asVector());
   3238  } else if (isMap()) {
   3239    js_delete(asMap());
   3240  } else {
   3241    MOZ_ASSERT(isBorrow());
   3242    // Nothing to do.
   3243  }
   3244 }
   3245 
   3246 bool SharedDataContainer::initVector(FrontendContext* fc) {
   3247  MOZ_ASSERT(isEmpty());
   3248 
   3249  auto* vec = js_new<SharedDataVector>();
   3250  if (!vec) {
   3251    ReportOutOfMemory(fc);
   3252    return false;
   3253  }
   3254  data_ = uintptr_t(vec) | VectorTag;
   3255  return true;
   3256 }
   3257 
   3258 bool SharedDataContainer::initMap(FrontendContext* fc) {
   3259  MOZ_ASSERT(isEmpty());
   3260 
   3261  auto* map = js_new<SharedDataMap>();
   3262  if (!map) {
   3263    ReportOutOfMemory(fc);
   3264    return false;
   3265  }
   3266  data_ = uintptr_t(map) | MapTag;
   3267  return true;
   3268 }
   3269 
   3270 bool SharedDataContainer::prepareStorageFor(FrontendContext* fc,
   3271                                            size_t nonLazyScriptCount,
   3272                                            size_t allScriptCount) {
   3273  MOZ_ASSERT(isEmpty());
   3274 
   3275  if (nonLazyScriptCount <= 1) {
   3276    MOZ_ASSERT(isSingle());
   3277    return true;
   3278  }
   3279 
   3280  // If the ratio of scripts with bytecode is small, allocating the Vector
   3281  // storage with the number of all scripts isn't space-efficient.
   3282  // In that case use HashMap instead.
   3283  //
   3284  // In general, we expect either all scripts to contain bytecode (priviledge
   3285  // and self-hosted), or almost none to (eg standard lazy parsing output).
   3286  constexpr size_t thresholdRatio = 8;
   3287  bool useHashMap = nonLazyScriptCount < allScriptCount / thresholdRatio;
   3288  if (useHashMap) {
   3289    if (!initMap(fc)) {
   3290      return false;
   3291    }
   3292    if (!asMap()->reserve(nonLazyScriptCount)) {
   3293      ReportOutOfMemory(fc);
   3294      return false;
   3295    }
   3296  } else {
   3297    if (!initVector(fc)) {
   3298      return false;
   3299    }
   3300    if (!asVector()->resize(allScriptCount)) {
   3301      ReportOutOfMemory(fc);
   3302      return false;
   3303    }
   3304  }
   3305 
   3306  return true;
   3307 }
   3308 
   3309 bool SharedDataContainer::cloneFrom(FrontendContext* fc,
   3310                                    const SharedDataContainer& other) {
   3311  MOZ_ASSERT(isEmpty());
   3312 
   3313  if (other.isBorrow()) {
   3314    return cloneFrom(fc, *other.asBorrow());
   3315  }
   3316 
   3317  if (other.isSingle()) {
   3318    // As we clone, we add an extra reference.
   3319    RefPtr<SharedImmutableScriptData> ref(other.asSingle());
   3320    setSingle(ref.forget());
   3321  } else if (other.isVector()) {
   3322    if (!initVector(fc)) {
   3323      return false;
   3324    }
   3325    if (!asVector()->appendAll(*other.asVector())) {
   3326      ReportOutOfMemory(fc);
   3327      return false;
   3328    }
   3329  } else if (other.isMap()) {
   3330    if (!initMap(fc)) {
   3331      return false;
   3332    }
   3333    auto& otherMap = *other.asMap();
   3334    if (!asMap()->reserve(otherMap.count())) {
   3335      ReportOutOfMemory(fc);
   3336      return false;
   3337    }
   3338    auto& map = *asMap();
   3339    for (auto iter = otherMap.iter(); !iter.done(); iter.next()) {
   3340      auto& entry = iter.get();
   3341      map.putNewInfallible(entry.key(), entry.value());
   3342    }
   3343  }
   3344  return true;
   3345 }
   3346 
   3347 js::SharedImmutableScriptData* SharedDataContainer::get(
   3348    ScriptIndex index) const {
   3349  if (isSingle()) {
   3350    if (index == CompilationStencil::TopLevelIndex) {
   3351      return asSingle();
   3352    }
   3353    return nullptr;
   3354  }
   3355 
   3356  if (isVector()) {
   3357    auto& vec = *asVector();
   3358    if (index.index < vec.length()) {
   3359      return vec[index];
   3360    }
   3361    return nullptr;
   3362  }
   3363 
   3364  if (isMap()) {
   3365    auto& map = *asMap();
   3366    auto p = map.lookup(index);
   3367    if (p) {
   3368      return p->value();
   3369    }
   3370    return nullptr;
   3371  }
   3372 
   3373  MOZ_ASSERT(isBorrow());
   3374  return asBorrow()->get(index);
   3375 }
   3376 
   3377 bool SharedDataContainer::convertFromSingleToMap(FrontendContext* fc) {
   3378  MOZ_ASSERT(isSingle());
   3379 
   3380  // Use a temporary container so that on OOM we do not break the stencil.
   3381  SharedDataContainer other;
   3382  if (!other.initMap(fc)) {
   3383    return false;
   3384  }
   3385 
   3386  if (!other.asMap()->putNew(CompilationStencil::TopLevelIndex, asSingle())) {
   3387    ReportOutOfMemory(fc);
   3388    return false;
   3389  }
   3390 
   3391  std::swap(data_, other.data_);
   3392  return true;
   3393 }
   3394 
   3395 bool SharedDataContainer::addAndShare(FrontendContext* fc, ScriptIndex index,
   3396                                      js::SharedImmutableScriptData* data) {
   3397  MOZ_ASSERT(!isBorrow());
   3398 
   3399  if (isSingle()) {
   3400    MOZ_ASSERT(index == CompilationStencil::TopLevelIndex);
   3401    RefPtr<SharedImmutableScriptData> ref(data);
   3402    if (!SharedImmutableScriptData::shareScriptData(fc, ref)) {
   3403      return false;
   3404    }
   3405    setSingle(ref.forget());
   3406    return true;
   3407  }
   3408 
   3409  if (isVector()) {
   3410    auto& vec = *asVector();
   3411    // Resized by SharedDataContainer::prepareStorageFor.
   3412    vec[index] = data;
   3413    return SharedImmutableScriptData::shareScriptData(fc, vec[index]);
   3414  }
   3415 
   3416  MOZ_ASSERT(isMap());
   3417  auto& map = *asMap();
   3418  // Reserved by SharedDataContainer::prepareStorageFor.
   3419  map.putNewInfallible(index, data);
   3420  auto p = map.lookup(index);
   3421  MOZ_ASSERT(p);
   3422  return SharedImmutableScriptData::shareScriptData(fc, p->value());
   3423 }
   3424 
   3425 bool SharedDataContainer::addExtraWithoutShare(
   3426    FrontendContext* fc, ScriptIndex index,
   3427    js::SharedImmutableScriptData* data) {
   3428  MOZ_ASSERT(!isEmpty());
   3429 
   3430  if (isSingle()) {
   3431    if (!convertFromSingleToMap(fc)) {
   3432      return false;
   3433    }
   3434  }
   3435 
   3436  if (isVector()) {
   3437    // SharedDataContainer::prepareStorageFor allocates space for all scripts.
   3438    (*asVector())[index] = data;
   3439    return true;
   3440  }
   3441 
   3442  MOZ_ASSERT(isMap());
   3443  // SharedDataContainer::prepareStorageFor doesn't allocate space for
   3444  // delazification, and this can fail.
   3445  if (!asMap()->putNew(index, data)) {
   3446    ReportOutOfMemory(fc);
   3447    return false;
   3448  }
   3449  return true;
   3450 }
   3451 
   3452 #ifdef DEBUG
   3453 void CompilationStencil::assertNoExternalDependency() const {
   3454  if (ownedBorrowStencil) {
   3455    ownedBorrowStencil->assertNoExternalDependency();
   3456 
   3457    assertBorrowingFromExtensibleCompilationStencil(*ownedBorrowStencil);
   3458    return;
   3459  }
   3460 
   3461  MOZ_ASSERT_IF(!scriptData.empty(), alloc.contains(scriptData.data()));
   3462  MOZ_ASSERT_IF(!scriptExtra.empty(), alloc.contains(scriptExtra.data()));
   3463 
   3464  MOZ_ASSERT_IF(!scopeData.empty(), alloc.contains(scopeData.data()));
   3465  MOZ_ASSERT_IF(!scopeNames.empty(), alloc.contains(scopeNames.data()));
   3466  for (const auto* data : scopeNames) {
   3467    MOZ_ASSERT_IF(data, alloc.contains(data));
   3468  }
   3469 
   3470  MOZ_ASSERT_IF(!regExpData.empty(), alloc.contains(regExpData.data()));
   3471 
   3472  MOZ_ASSERT_IF(!bigIntData.empty(), alloc.contains(bigIntData.data()));
   3473  for (const auto& data : bigIntData) {
   3474    MOZ_ASSERT(data.isContainedIn(alloc));
   3475  }
   3476 
   3477  MOZ_ASSERT_IF(!objLiteralData.empty(), alloc.contains(objLiteralData.data()));
   3478  for (const auto& data : objLiteralData) {
   3479    MOZ_ASSERT(data.isContainedIn(alloc));
   3480  }
   3481 
   3482  MOZ_ASSERT_IF(!parserAtomData.empty(), alloc.contains(parserAtomData.data()));
   3483  for (const auto* data : parserAtomData) {
   3484    MOZ_ASSERT_IF(data, alloc.contains(data));
   3485  }
   3486 
   3487  MOZ_ASSERT(!sharedData.isBorrow());
   3488 }
   3489 
   3490 void ExtensibleCompilationStencil::assertNoExternalDependency() const {
   3491  for (const auto& data : bigIntData) {
   3492    MOZ_ASSERT(data.isContainedIn(alloc));
   3493  }
   3494 
   3495  for (const auto& data : objLiteralData) {
   3496    MOZ_ASSERT(data.isContainedIn(alloc));
   3497  }
   3498 
   3499  for (const auto* data : scopeNames) {
   3500    MOZ_ASSERT_IF(data, alloc.contains(data));
   3501  }
   3502 
   3503  for (const auto* data : parserAtoms.entries()) {
   3504    MOZ_ASSERT_IF(data, alloc.contains(data));
   3505  }
   3506 
   3507  MOZ_ASSERT(!sharedData.isBorrow());
   3508 }
   3509 #endif  // DEBUG
   3510 
   3511 template <typename T, typename VectorT>
   3512 [[nodiscard]] bool CopySpanToVector(FrontendContext* fc, VectorT& vec,
   3513                                    mozilla::Span<T>& span) {
   3514  auto len = span.size();
   3515  if (len == 0) {
   3516    return true;
   3517  }
   3518 
   3519  if (!vec.append(span.data(), len)) {
   3520    js::ReportOutOfMemory(fc);
   3521    return false;
   3522  }
   3523  return true;
   3524 }
   3525 
   3526 template <typename T, typename IntoSpanT, size_t Inline, typename AllocPolicy>
   3527 [[nodiscard]] bool CopyToVector(FrontendContext* fc,
   3528                                mozilla::Vector<T, Inline, AllocPolicy>& vec,
   3529                                const IntoSpanT& source) {
   3530  mozilla::Span<const T> span = source;
   3531  return CopySpanToVector(fc, vec, span);
   3532 }
   3533 
   3534 // Span and Vector do not share the same method names.
   3535 template <typename T, size_t Inline, typename AllocPolicy>
   3536 size_t GetLength(const mozilla::Vector<T, Inline, AllocPolicy>& vec) {
   3537  return vec.length();
   3538 }
   3539 template <typename T>
   3540 size_t GetLength(const mozilla::Span<T>& span) {
   3541  return span.Length();
   3542 }
   3543 
   3544 // Copy scope names from `src` into `alloc`, and returns the allocated data.
   3545 BaseParserScopeData* CopyScopeData(FrontendContext* fc, LifoAlloc& alloc,
   3546                                   ScopeKind kind,
   3547                                   const BaseParserScopeData* src) {
   3548  MOZ_ASSERT(kind != ScopeKind::With);
   3549 
   3550  size_t dataSize = SizeOfParserScopeData(kind, src->length);
   3551 
   3552  auto* dest = static_cast<BaseParserScopeData*>(alloc.alloc(dataSize));
   3553  if (!dest) {
   3554    js::ReportOutOfMemory(fc);
   3555    return nullptr;
   3556  }
   3557  memcpy(dest, src, dataSize);
   3558 
   3559  return dest;
   3560 }
   3561 
   3562 template <typename Stencil>
   3563 bool ExtensibleCompilationStencil::cloneFromImpl(FrontendContext* fc,
   3564                                                 const Stencil& other) {
   3565  MOZ_ASSERT(alloc.isEmpty());
   3566 
   3567  canLazilyParse = other.canLazilyParse;
   3568  functionKey = other.functionKey;
   3569 
   3570  if (!CopyToVector(fc, scriptData, other.scriptData)) {
   3571    return false;
   3572  }
   3573 
   3574  if (!CopyToVector(fc, scriptExtra, other.scriptExtra)) {
   3575    return false;
   3576  }
   3577 
   3578  if (!CopyToVector(fc, gcThingData, other.gcThingData)) {
   3579    return false;
   3580  }
   3581 
   3582  size_t scopeSize = GetLength(other.scopeData);
   3583  if (!CopyToVector(fc, scopeData, other.scopeData)) {
   3584    return false;
   3585  }
   3586  if (!scopeNames.reserve(scopeSize)) {
   3587    js::ReportOutOfMemory(fc);
   3588    return false;
   3589  }
   3590  for (size_t i = 0; i < scopeSize; i++) {
   3591    if (other.scopeNames[i]) {
   3592      BaseParserScopeData* data = CopyScopeData(
   3593          fc, alloc, other.scopeData[i].kind(), other.scopeNames[i]);
   3594      if (!data) {
   3595        return false;
   3596      }
   3597      scopeNames.infallibleEmplaceBack(data);
   3598    } else {
   3599      scopeNames.infallibleEmplaceBack(nullptr);
   3600    }
   3601  }
   3602 
   3603  if (!CopyToVector(fc, regExpData, other.regExpData)) {
   3604    return false;
   3605  }
   3606 
   3607  // If CompilationStencil has external dependency, peform deep copy.
   3608 
   3609  size_t bigIntSize = GetLength(other.bigIntData);
   3610  if (!bigIntData.resize(bigIntSize)) {
   3611    js::ReportOutOfMemory(fc);
   3612    return false;
   3613  }
   3614  for (size_t i = 0; i < bigIntSize; i++) {
   3615    if (!bigIntData[i].init(fc, alloc, other.bigIntData[i])) {
   3616      return false;
   3617    }
   3618  }
   3619 
   3620  size_t objLiteralSize = GetLength(other.objLiteralData);
   3621  if (!objLiteralData.reserve(objLiteralSize)) {
   3622    js::ReportOutOfMemory(fc);
   3623    return false;
   3624  }
   3625  for (const auto& data : other.objLiteralData) {
   3626    size_t length = data.code().size();
   3627    auto* code = alloc.newArrayUninitialized<uint8_t>(length);
   3628    if (!code) {
   3629      js::ReportOutOfMemory(fc);
   3630      return false;
   3631    }
   3632    memcpy(code, data.code().data(), length);
   3633    objLiteralData.infallibleEmplaceBack(code, length, data.kind(),
   3634                                         data.flags(), data.propertyCount());
   3635  }
   3636 
   3637  // Regardless of whether CompilationStencil has external dependency or not,
   3638  // ParserAtoms should be interned, to populate internal HashMap.
   3639  for (const auto* entry : other.parserAtomsSpan()) {
   3640    if (!entry) {
   3641      if (!parserAtoms.addPlaceholder(fc)) {
   3642        return false;
   3643      }
   3644      continue;
   3645    }
   3646 
   3647    auto index = parserAtoms.internExternalParserAtom(fc, entry);
   3648    if (!index) {
   3649      return false;
   3650    }
   3651  }
   3652 
   3653  // We copy the stencil and increment the reference count of each
   3654  // SharedImmutableScriptData.
   3655  if (!sharedData.cloneFrom(fc, other.sharedData)) {
   3656    return false;
   3657  }
   3658 
   3659  // Note: moduleMetadata and asmJS are known after the first parse, and are
   3660  // not mutated by any delazifications later on. Thus we can safely increment
   3661  // the reference counter and keep these as-is.
   3662  moduleMetadata = other.moduleMetadata;
   3663  asmJS = other.asmJS;
   3664 
   3665 #ifdef DEBUG
   3666  assertNoExternalDependency();
   3667 #endif
   3668 
   3669  return true;
   3670 }
   3671 
   3672 bool ExtensibleCompilationStencil::cloneFrom(FrontendContext* fc,
   3673                                             const CompilationStencil& other) {
   3674  return cloneFromImpl(fc, other);
   3675 }
   3676 bool ExtensibleCompilationStencil::cloneFrom(
   3677    FrontendContext* fc, const ExtensibleCompilationStencil& other) {
   3678  return cloneFromImpl(fc, other);
   3679 }
   3680 
   3681 bool ExtensibleCompilationStencil::steal(FrontendContext* fc,
   3682                                         RefPtr<CompilationStencil>&& other) {
   3683  MOZ_ASSERT(alloc.isEmpty());
   3684  using StorageType = CompilationStencil::StorageType;
   3685  StorageType storageType = other->storageType;
   3686  if (other->hasMultipleReference()) {
   3687    storageType = StorageType::Borrowed;
   3688  }
   3689 
   3690  if (storageType == StorageType::OwnedExtensible) {
   3691    auto& otherExtensible = other->ownedBorrowStencil;
   3692 
   3693    canLazilyParse = otherExtensible->canLazilyParse;
   3694    functionKey = otherExtensible->functionKey;
   3695 
   3696    alloc.steal(&otherExtensible->alloc);
   3697 
   3698    source = std::move(otherExtensible->source);
   3699 
   3700    scriptData = std::move(otherExtensible->scriptData);
   3701    scriptExtra = std::move(otherExtensible->scriptExtra);
   3702    gcThingData = std::move(otherExtensible->gcThingData);
   3703    scopeData = std::move(otherExtensible->scopeData);
   3704    scopeNames = std::move(otherExtensible->scopeNames);
   3705    regExpData = std::move(otherExtensible->regExpData);
   3706    bigIntData = std::move(otherExtensible->bigIntData);
   3707    objLiteralData = std::move(otherExtensible->objLiteralData);
   3708 
   3709    parserAtoms = std::move(otherExtensible->parserAtoms);
   3710    parserAtoms.fixupAlloc(alloc);
   3711 
   3712    sharedData = std::move(otherExtensible->sharedData);
   3713    moduleMetadata = std::move(otherExtensible->moduleMetadata);
   3714    asmJS = std::move(otherExtensible->asmJS);
   3715 
   3716 #ifdef DEBUG
   3717    assertNoExternalDependency();
   3718 #endif
   3719 
   3720    return true;
   3721  }
   3722 
   3723  if (storageType == StorageType::Borrowed) {
   3724    return cloneFrom(fc, *other);
   3725  }
   3726 
   3727  MOZ_ASSERT(storageType == StorageType::Owned);
   3728 
   3729  canLazilyParse = other->canLazilyParse;
   3730  functionKey = other->functionKey;
   3731 
   3732 #ifdef DEBUG
   3733  other->assertNoExternalDependency();
   3734  MOZ_ASSERT(!other->hasMultipleReference());
   3735 #endif
   3736 
   3737  // If CompilationStencil has no external dependency,
   3738  // steal LifoAlloc and perform shallow copy.
   3739  alloc.steal(&other->alloc);
   3740 
   3741  if (!CopySpanToVector(fc, scriptData, other->scriptData)) {
   3742    return false;
   3743  }
   3744 
   3745  if (!CopySpanToVector(fc, scriptExtra, other->scriptExtra)) {
   3746    return false;
   3747  }
   3748 
   3749  if (!CopySpanToVector(fc, gcThingData, other->gcThingData)) {
   3750    return false;
   3751  }
   3752 
   3753  if (!CopySpanToVector(fc, scopeData, other->scopeData)) {
   3754    return false;
   3755  }
   3756  if (!CopySpanToVector(fc, scopeNames, other->scopeNames)) {
   3757    return false;
   3758  }
   3759 
   3760  if (!CopySpanToVector(fc, regExpData, other->regExpData)) {
   3761    return false;
   3762  }
   3763 
   3764  if (!CopySpanToVector(fc, bigIntData, other->bigIntData)) {
   3765    return false;
   3766  }
   3767 
   3768  if (!CopySpanToVector(fc, objLiteralData, other->objLiteralData)) {
   3769    return false;
   3770  }
   3771 
   3772  // Regardless of whether CompilationStencil has external dependency or not,
   3773  // ParserAtoms should be interned, to populate internal HashMap.
   3774  for (const auto* entry : other->parserAtomData) {
   3775    if (!entry) {
   3776      if (!parserAtoms.addPlaceholder(fc)) {
   3777        return false;
   3778      }
   3779      continue;
   3780    }
   3781 
   3782    auto index = parserAtoms.internExternalParserAtom(fc, entry);
   3783    if (!index) {
   3784      return false;
   3785    }
   3786  }
   3787 
   3788  sharedData = std::move(other->sharedData);
   3789  moduleMetadata = std::move(other->moduleMetadata);
   3790  asmJS = std::move(other->asmJS);
   3791 
   3792 #ifdef DEBUG
   3793  assertNoExternalDependency();
   3794 #endif
   3795 
   3796  return true;
   3797 }
   3798 
   3799 bool CompilationStencil::isModule() const {
   3800  return scriptExtra[CompilationStencil::TopLevelIndex].isModule();
   3801 }
   3802 
   3803 bool ExtensibleCompilationStencil::isModule() const {
   3804  return scriptExtra[CompilationStencil::TopLevelIndex].isModule();
   3805 }
   3806 
   3807 bool CompilationStencil::hasAsmJS() const { return asmJS; }
   3808 
   3809 bool ExtensibleCompilationStencil::hasAsmJS() const { return asmJS; }
   3810 
   3811 bool InitialStencilAndDelazifications::hasAsmJS() const {
   3812  return initial_->hasAsmJS();
   3813 }
   3814 
   3815 InitialStencilAndDelazifications::~InitialStencilAndDelazifications() {
   3816  MOZ_ASSERT(refCount_ == 0);
   3817 
   3818  for (size_t i = 0; i < delazifications_.length(); i++) {
   3819    CompilationStencil* delazification = delazifications_[i].exchange(nullptr);
   3820    if (delazification) {
   3821      delazification->Release();
   3822    }
   3823  }
   3824 }
   3825 
   3826 void InitialStencilAndDelazifications::AddRef() { refCount_++; }
   3827 
   3828 void InitialStencilAndDelazifications::Release() {
   3829  MOZ_RELEASE_ASSERT(refCount_ > 0);
   3830  if (--refCount_ == 0) {
   3831    js_delete(this);
   3832  }
   3833 }
   3834 
   3835 InitialStencilAndDelazifications::RelativeIndexesGuard
   3836 InitialStencilAndDelazifications::ensureRelativeIndexes(FrontendContext* fc) {
   3837  auto consumersGuard = relativeIndexes_.consumers_.lock();
   3838  if (consumersGuard > 0) {
   3839    MOZ_ASSERT(relativeIndexes_.indexes_.length() ==
   3840               initial_->scriptData.size() - 1);
   3841    consumersGuard += 1;
   3842    return RelativeIndexesGuard(this);
   3843  }
   3844 
   3845  if (!relativeIndexes_.indexes_.resize(initial_->scriptData.size() - 1)) {
   3846    ReportOutOfMemory(fc);
   3847    return RelativeIndexesGuard(nullptr);
   3848  }
   3849 
   3850  auto writeIndex = [&](ScriptIndex index, ScriptIndex enclosingInInitial,
   3851                        ScriptIndex enclosedInEnclosing) {
   3852    MOZ_ASSERT(index > 0);
   3853    MOZ_ASSERT(
   3854        index == getInitialIndexFor(enclosingInInitial, enclosedInEnclosing),
   3855        "getInitialIndexFor does not match relativeIndexes_");
   3856    relativeIndexes_[index - 1] =
   3857        ScriptIndexes{enclosingInInitial, enclosedInEnclosing};
   3858  };
   3859  for (size_t index = 0; index < initial_->scriptData.size(); index++) {
   3860    auto& scriptData = initial_->scriptData[index];
   3861    // index > 0 is used to iterate over the top-level which is not flagged as
   3862    // isInterpreted.
   3863    if (index > 0 &&
   3864        (scriptData.isGhost() || !scriptData.functionFlags.isInterpreted())) {
   3865      continue;
   3866    }
   3867 
   3868    auto gcthings = scriptData.gcthings(*initial_.get());
   3869    if (scriptData.hasSharedData()) {
   3870      // Then the gc things might not have a contiguous array of inner
   3871      // functions. Thus we have to iterate over all gcthings.
   3872      for (auto gcthing : gcthings) {
   3873        if (gcthing.isFunction()) {
   3874          writeIndex(gcthing.toFunction(), ScriptIndex(index),
   3875                     gcthing.toFunction());
   3876        }
   3877      }
   3878      continue;
   3879    }
   3880 
   3881    // The function is syntax-parsed in the initial compilation. In this case,
   3882    // the gcthings contains only the list of inner function indices followed by
   3883    // the list of closed over bindings. (see
   3884    // PerHandlerParser<SyntaxParseHandler>::finishFunction)
   3885 
   3886    // The first element of scriptData and scriptExtra is the compiled script
   3887    // it-self, in the upcoming delazification stencil, thus we start after, at
   3888    // 1 to index inner functions.
   3889    size_t functionIndex = 1;
   3890    for (auto gcthing : gcthings) {
   3891      if (!gcthing.isFunction()) {
   3892        break;
   3893      }
   3894      writeIndex(gcthing.toFunction(), ScriptIndex(index),
   3895                 ScriptIndex(functionIndex));
   3896      functionIndex++;
   3897    }
   3898  }
   3899 
   3900  consumersGuard += 1;
   3901  return RelativeIndexesGuard(this);
   3902 }
   3903 
   3904 void InitialStencilAndDelazifications::decrementRelativeIndexesConsumer() {
   3905  auto consumersGuard = relativeIndexes_.consumers_.lock();
   3906  consumersGuard -= 1;
   3907  if (consumersGuard == 0) {
   3908    relativeIndexes_.indexes_.clearAndFree();
   3909  }
   3910 }
   3911 
   3912 bool InitialStencilAndDelazifications::init(FrontendContext* fc,
   3913                                            const CompilationStencil* initial) {
   3914  MOZ_ASSERT(initial->isInitialStencil());
   3915 
   3916  initial_ = initial;
   3917 
   3918  if (!canLazilyParse()) {
   3919    // If the initial stencil is known to be fully-parsed, delazification
   3920    // never happens, and the delazifications_ vector and the
   3921    // functionKeyToInitialScriptIndex_ map is never used.
   3922    return true;
   3923  }
   3924 
   3925  if (!delazifications_.resize(initial_->scriptData.size())) {
   3926    ReportOutOfMemory(fc);
   3927    return false;
   3928  }
   3929 
   3930  return functionKeyToInitialScriptIndex_.init(fc, initial_);
   3931 }
   3932 
   3933 const CompilationStencil* InitialStencilAndDelazifications::getInitial() const {
   3934  return initial_.get();
   3935 }
   3936 
   3937 const CompilationStencil* InitialStencilAndDelazifications::getDelazificationAt(
   3938    size_t functionIndex) const {
   3939  MOZ_ASSERT(canLazilyParse());
   3940  MOZ_ASSERT(functionIndex > 0);
   3941 
   3942  return delazifications_[functionIndex - 1];
   3943 }
   3944 
   3945 const CompilationStencil*
   3946 InitialStencilAndDelazifications::getDelazificationFor(
   3947    const SourceExtent& extent) const {
   3948  MOZ_ASSERT(canLazilyParse());
   3949  auto maybeIndex =
   3950      functionKeyToInitialScriptIndex_.get(extent.toFunctionKey());
   3951  MOZ_ASSERT(maybeIndex,
   3952             "The extent parameter should be for a function inside the script");
   3953  return getDelazificationAt(*maybeIndex);
   3954 }
   3955 
   3956 ScriptIndex InitialStencilAndDelazifications::getScriptIndexFor(
   3957    const CompilationStencil* delazification) const {
   3958  MOZ_ASSERT(!delazification->isInitialStencil());
   3959  auto maybeIndex =
   3960      functionKeyToInitialScriptIndex_.get(delazification->functionKey);
   3961  MOZ_ASSERT(maybeIndex,
   3962             "The delazification should be for a function inside the script");
   3963  return *maybeIndex;
   3964 }
   3965 
   3966 const ScriptIndexes& InitialStencilAndDelazifications::getRelativeIndexesAt(
   3967    ScriptIndex initialIndex) const {
   3968  MOZ_ASSERT(initialIndex.index > 0);
   3969 
   3970  return relativeIndexes_[initialIndex.index - 1];
   3971 }
   3972 
   3973 ScriptIndex InitialStencilAndDelazifications::getInitialIndexFor(
   3974    ScriptIndex enclosingInInitial, ScriptIndex enclosedInEnclosing) const {
   3975  if (enclosedInEnclosing == 0) {
   3976    // The first function in a CompilationStencil is it-self.
   3977    return enclosingInInitial;
   3978  }
   3979 
   3980  auto& scriptDataFromInitial = initial_->scriptData[enclosingInInitial];
   3981  auto gcthings = scriptDataFromInitial.gcthings(*initial_.get());
   3982  // When looking for enclosed script, there is at least one entry in the array
   3983  // of gc things.
   3984  MOZ_ASSERT(gcthings.Length() > 0);
   3985  MOZ_ASSERT(scriptDataFromInitial.hasSharedData() == gcthings[0].isScope());
   3986  if (scriptDataFromInitial.hasSharedData()) {
   3987    // The function is already compiled as part of the initial stencil. Thus,
   3988    // the enclosedInEnclosing index is already an index in the initial stencil.
   3989    return enclosedInEnclosing;
   3990  }
   3991 
   3992  // When the functions does not have associated bytecode and scope-chains,
   3993  // then we have a contiguous array of inner functions that we can address
   3994  // using the enclosed index.
   3995  //
   3996  // We remove 1 as index 0 corresponds to the enclosing function, which is not
   3997  // listed in the set of gc things.
   3998  return gcthings[enclosedInEnclosing - 1].toFunction();
   3999 }
   4000 
   4001 const CompilationStencil* InitialStencilAndDelazifications::storeDelazification(
   4002    RefPtr<CompilationStencil>&& delazification) {
   4003  MOZ_ASSERT(!delazification->hasMultipleReference());
   4004  MOZ_ASSERT(canLazilyParse());
   4005 
   4006  auto maybeIndex =
   4007      functionKeyToInitialScriptIndex_.get(delazification->functionKey);
   4008  MOZ_ASSERT(maybeIndex);
   4009  size_t functionIndex = *maybeIndex;
   4010 
   4011  CompilationStencil* raw = delazification.forget().take();
   4012  if (delazifications_[functionIndex - 1].compareExchange(nullptr, raw)) {
   4013    return raw;
   4014  }
   4015 
   4016 #ifdef DEBUG
   4017  // The delazification vector already has an entry for the function. This is an
   4018  // opportunity to test whether we are generating the same stencils.
   4019  {
   4020    const CompilationStencil* saved = delazifications_[functionIndex - 1];
   4021    raw->assertNoExternalDependency();
   4022    saved->assertNoExternalDependency();
   4023    MOZ_ASSERT(raw->source == saved->source);
   4024    MOZ_ASSERT(raw->scriptData.size() == saved->scriptData.size());
   4025    MOZ_ASSERT(raw->scriptExtra.size() == saved->scriptExtra.size());
   4026    MOZ_ASSERT(raw->gcThingData.size() == saved->gcThingData.size());
   4027    MOZ_ASSERT(raw->scopeData.size() == saved->scopeData.size());
   4028    MOZ_ASSERT(raw->scopeNames.size() == saved->scopeNames.size());
   4029    MOZ_ASSERT(raw->regExpData.size() == saved->regExpData.size());
   4030    MOZ_ASSERT(raw->bigIntData.size() == saved->bigIntData.size());
   4031    MOZ_ASSERT(raw->objLiteralData.size() == saved->objLiteralData.size());
   4032    MOZ_ASSERT(raw->parserAtomData.size() == saved->parserAtomData.size());
   4033  }
   4034 #endif
   4035 
   4036  raw->Release();
   4037  return delazifications_[functionIndex - 1];
   4038 }
   4039 
   4040 CompilationStencil* InitialStencilAndDelazifications::getMerged(
   4041    FrontendContext* fc) const {
   4042  MOZ_ASSERT(canLazilyParse());
   4043 
   4044  UniquePtr<ExtensibleCompilationStencil> extensibleStencil(
   4045      fc->getAllocator()->new_<ExtensibleCompilationStencil>(initial_->source));
   4046  if (!extensibleStencil) {
   4047    return nullptr;
   4048  }
   4049 
   4050  if (!extensibleStencil->cloneFrom(fc, *initial_)) {
   4051    return nullptr;
   4052  }
   4053 
   4054  CompilationStencilMerger merger;
   4055  if (!merger.setInitial(fc, std::move(extensibleStencil))) {
   4056    return nullptr;
   4057  }
   4058 
   4059  for (const auto& delazification : delazifications_) {
   4060    if (!delazification) {
   4061      continue;
   4062    }
   4063 
   4064    // NOTE: The delazifications_ vector can be modified by other threads
   4065    //       during the iteration.
   4066    //       The enclosing delazification's is not guaranteed to be iterated
   4067    //       over in this iteration.
   4068    //       If the enclosing function wasn't merged, all inner functions are
   4069    //       ignored inside maybeAddDelazification.
   4070    if (!merger.maybeAddDelazification(fc, *delazification)) {
   4071      return nullptr;
   4072    }
   4073  }
   4074 
   4075  UniquePtr<ExtensibleCompilationStencil> merged = merger.takeResult();
   4076  return fc->getAllocator()->new_<CompilationStencil>(std::move(merged));
   4077 }
   4078 
   4079 /* static */
   4080 bool InitialStencilAndDelazifications::instantiateStencils(
   4081    JSContext* cx, CompilationInput& input,
   4082    InitialStencilAndDelazifications& stencils, CompilationGCOutput& gcOutput) {
   4083  if (!CompilationStencil::instantiateStencils(cx, input, *stencils.initial_,
   4084                                               gcOutput)) {
   4085    return false;
   4086  }
   4087 
   4088  if (input.options.populateDelazificationCache()) {
   4089    RefPtr<InitialStencilAndDelazifications> stencilsPtr = &stencils;
   4090    ScriptSourceObject* sso = gcOutput.script->sourceObject();
   4091    MOZ_ASSERT(!sso->maybeGetStencils());
   4092    if (!stencils.hasAsmJS()) {
   4093      sso->setStencils(stencilsPtr.forget());
   4094      sso->setSharingDelazifications();
   4095    }
   4096  }
   4097 
   4098  // At this point, gcOutput.script contains the top-level script, and
   4099  // gcOutput.functions[i] contains i-th function, where 0-th item is
   4100  // always nullptr.
   4101  // gcOutput.functions[i]->baseScript() is either JSScript or lazy script.
   4102  for (size_t i = 0, length = stencils.delazifications_.length(); i < length;
   4103       i++) {
   4104    const auto& delazification = stencils.delazifications_[i];
   4105    if (!delazification) {
   4106      continue;
   4107    }
   4108 
   4109    ScriptIndex scriptIndex = ScriptIndex(i + 1);
   4110    JS::Rooted<JSFunction*> fun(cx, gcOutput.functions[scriptIndex]);
   4111    if (!fun->baseScript()->isReadyForDelazification()) {
   4112      // NOTE: The delazifications_ vector can be modified by other threads
   4113      //       during the iteration.
   4114      //       The enclosing delazification's is not guaranteed to be iterated
   4115      //       over in this iteration.
   4116      //       If the enclosing function wasn't instantiated, ignore all inner
   4117      //       functions.
   4118      continue;
   4119    }
   4120 
   4121    JS::Rooted<CompilationInput> inputForFunc(cx,
   4122                                              CompilationInput(input.options));
   4123    inputForFunc.get().initFromLazy(cx, fun->baseScript(), input.source);
   4124 
   4125    // TODO: The preparation can be shared across iterations.
   4126    JS::Rooted<CompilationGCOutput> gcOutputForFunc(cx);
   4127    if (!CompilationStencil::instantiateStencils(
   4128            cx, inputForFunc.get(), *delazification, gcOutputForFunc.get())) {
   4129      return false;
   4130    }
   4131  }
   4132 
   4133  return true;
   4134 }
   4135 
   4136 size_t InitialStencilAndDelazifications::sizeOfExcludingThis(
   4137    mozilla::MallocSizeOf mallocSizeOf) const {
   4138  size_t size = 0;
   4139 
   4140  if (initial_) {
   4141    // The initial stencil can be shared between multiple owners, but
   4142    // in most case this instance is considered as the main owner, in term
   4143    // of the memory reporting.
   4144    size += initial_->sizeOfIncludingThis(mallocSizeOf);
   4145  }
   4146 
   4147  size += delazifications_.sizeOfExcludingThis(mallocSizeOf);
   4148 
   4149  for (const auto& delazification : delazifications_) {
   4150    if (!delazification) {
   4151      continue;
   4152    }
   4153 
   4154    // Delazifications are exclusively owned by this instance.
   4155    size += (*delazification).sizeOfIncludingThis(mallocSizeOf);
   4156  }
   4157 
   4158  size += functionKeyToInitialScriptIndex_.sizeOfExcludingThis(mallocSizeOf);
   4159 
   4160  return size;
   4161 }
   4162 
   4163 mozilla::Span<TaggedScriptThingIndex> ScriptStencil::gcthings(
   4164    const CompilationStencil& stencil) const {
   4165  return stencil.gcThingData.Subspan(gcThingsOffset, gcThingsLength);
   4166 }
   4167 
   4168 bool BigIntStencil::initFromChars(FrontendContext* fc, LifoAlloc& alloc,
   4169                                  mozilla::Span<const char16_t> buf) {
   4170  MOZ_ASSERT(ParseBigInt64Literal(buf).isNothing(),
   4171             "int64-sized BigInts are stored inline");
   4172 
   4173  size_t length = buf.size();
   4174  MOZ_ASSERT(length > 0);
   4175 
   4176  char16_t* p = alloc.template newArrayUninitialized<char16_t>(length);
   4177  if (!p) {
   4178    ReportOutOfMemory(fc);
   4179    return false;
   4180  }
   4181  mozilla::PodCopy(p, buf.data(), length);
   4182  bigInt_ = mozilla::AsVariant(mozilla::Span(p, length));
   4183  return true;
   4184 }
   4185 
   4186 bool BigIntStencil::init(FrontendContext* fc, LifoAlloc& alloc,
   4187                         mozilla::Span<const char16_t> buf) {
   4188  if (auto int64 = ParseBigInt64Literal(buf)) {
   4189    bigInt_ = mozilla::AsVariant(*int64);
   4190    return true;
   4191  }
   4192  return initFromChars(fc, alloc, buf);
   4193 }
   4194 
   4195 bool BigIntStencil::init(FrontendContext* fc, LifoAlloc& alloc,
   4196                         const BigIntStencil& other) {
   4197  if (other.bigInt_.is<int64_t>()) {
   4198    bigInt_ = other.bigInt_;
   4199    return true;
   4200  }
   4201  return initFromChars(fc, alloc, other.source());
   4202 }
   4203 
   4204 BigInt* BigIntStencil::createBigInt(JSContext* cx) const {
   4205  return bigInt_.match(
   4206      [cx](mozilla::Span<char16_t> source) {
   4207        return js::ParseBigIntLiteral(cx, source);
   4208      },
   4209      [cx](int64_t int64) {
   4210        // BigInts are stored in the script's data vector and therefore need to
   4211        // be allocated in the tenured heap.
   4212        constexpr gc::Heap heap = gc::Heap::Tenured;
   4213        return BigInt::createFromInt64(cx, int64, heap);
   4214      });
   4215 }
   4216 
   4217 bool BigIntStencil::isZero() const {
   4218  return bigInt_.match([](mozilla::Span<char16_t>) { return false; },
   4219                       [](int64_t int64) { return int64 == 0; });
   4220 }
   4221 
   4222 bool BigIntStencil::inplaceNegate() {
   4223  return bigInt_.match([](mozilla::Span<char16_t>) { return false; },
   4224                       [](int64_t& int64) {
   4225                         auto negated = -mozilla::CheckedInt<int64_t>{int64};
   4226                         if (!negated.isValid()) {
   4227                           return false;
   4228                         }
   4229                         int64 = negated.value();
   4230                         return true;
   4231                       });
   4232 }
   4233 
   4234 bool BigIntStencil::inplaceBitNot() {
   4235  return bigInt_.match([](mozilla::Span<char16_t>) { return false; },
   4236                       [](int64_t& int64) {
   4237                         int64 = ~int64;
   4238                         return true;
   4239                       });
   4240 }
   4241 
   4242 #ifdef DEBUG
   4243 bool BigIntStencil::isContainedIn(const LifoAlloc& alloc) const {
   4244  return bigInt_.match(
   4245      [&alloc](mozilla::Span<char16_t> source) {
   4246        return alloc.contains(source.data());
   4247      },
   4248      [](int64_t) { return true; });
   4249 }
   4250 #endif
   4251 
   4252 #if defined(DEBUG) || defined(JS_JITSPEW)
   4253 
   4254 void frontend::DumpTaggedParserAtomIndex(js::JSONPrinter& json,
   4255                                         TaggedParserAtomIndex taggedIndex,
   4256                                         const CompilationStencil* stencil) {
   4257  if (taggedIndex.isParserAtomIndex()) {
   4258    json.property("tag", "AtomIndex");
   4259    auto index = taggedIndex.toParserAtomIndex();
   4260    if (stencil && stencil->parserAtomData[index]) {
   4261      GenericPrinter& out = json.beginStringProperty("atom");
   4262      stencil->parserAtomData[index]->dumpCharsNoQuote(out);
   4263      json.endString();
   4264    } else {
   4265      json.property("index", size_t(index));
   4266    }
   4267    return;
   4268  }
   4269 
   4270  if (taggedIndex.isWellKnownAtomId()) {
   4271    json.property("tag", "WellKnown");
   4272    auto index = taggedIndex.toWellKnownAtomId();
   4273    switch (index) {
   4274      case WellKnownAtomId::empty_:
   4275        json.property("atom", "");
   4276        break;
   4277 
   4278 #  define CASE_(name, _) case WellKnownAtomId::name:
   4279        FOR_EACH_NONTINY_COMMON_PROPERTYNAME(CASE_)
   4280 #  undef CASE_
   4281 
   4282 #  define CASE_(name, _) case WellKnownAtomId::name:
   4283        JS_FOR_EACH_PROTOTYPE(CASE_)
   4284 #  undef CASE_
   4285 
   4286 #  define CASE_(name) case WellKnownAtomId::name:
   4287        JS_FOR_EACH_WELL_KNOWN_SYMBOL(CASE_)
   4288 #  undef CASE_
   4289 
   4290        {
   4291          GenericPrinter& out = json.beginStringProperty("atom");
   4292          ParserAtomsTable::dumpCharsNoQuote(out, index);
   4293          json.endString();
   4294          break;
   4295        }
   4296 
   4297      default:
   4298        // This includes tiny WellKnownAtomId atoms, which is invalid.
   4299        json.property("index", size_t(index));
   4300        break;
   4301    }
   4302    return;
   4303  }
   4304 
   4305  if (taggedIndex.isLength1StaticParserString()) {
   4306    json.property("tag", "Length1Static");
   4307    auto index = taggedIndex.toLength1StaticParserString();
   4308    GenericPrinter& out = json.beginStringProperty("atom");
   4309    ParserAtomsTable::dumpCharsNoQuote(out, index);
   4310    json.endString();
   4311    return;
   4312  }
   4313 
   4314  if (taggedIndex.isLength2StaticParserString()) {
   4315    json.property("tag", "Length2Static");
   4316    auto index = taggedIndex.toLength2StaticParserString();
   4317    GenericPrinter& out = json.beginStringProperty("atom");
   4318    ParserAtomsTable::dumpCharsNoQuote(out, index);
   4319    json.endString();
   4320    return;
   4321  }
   4322 
   4323  if (taggedIndex.isLength3StaticParserString()) {
   4324    json.property("tag", "Length3Static");
   4325    auto index = taggedIndex.toLength3StaticParserString();
   4326    GenericPrinter& out = json.beginStringProperty("atom");
   4327    ParserAtomsTable::dumpCharsNoQuote(out, index);
   4328    json.endString();
   4329    return;
   4330  }
   4331 
   4332  MOZ_ASSERT(taggedIndex.isNull());
   4333  json.property("tag", "null");
   4334 }
   4335 
   4336 void frontend::DumpTaggedParserAtomIndexNoQuote(
   4337    GenericPrinter& out, TaggedParserAtomIndex taggedIndex,
   4338    const CompilationStencil* stencil) {
   4339  if (taggedIndex.isParserAtomIndex()) {
   4340    auto index = taggedIndex.toParserAtomIndex();
   4341    if (stencil && stencil->parserAtomData[index]) {
   4342      stencil->parserAtomData[index]->dumpCharsNoQuote(out);
   4343    } else {
   4344      out.printf("AtomIndex#%zu", size_t(index));
   4345    }
   4346    return;
   4347  }
   4348 
   4349  if (taggedIndex.isWellKnownAtomId()) {
   4350    auto index = taggedIndex.toWellKnownAtomId();
   4351    switch (index) {
   4352      case WellKnownAtomId::empty_:
   4353        out.put("#<zero-length name>");
   4354        break;
   4355 
   4356 #  define CASE_(name, _) case WellKnownAtomId::name:
   4357        FOR_EACH_NONTINY_COMMON_PROPERTYNAME(CASE_)
   4358 #  undef CASE_
   4359 
   4360 #  define CASE_(name, _) case WellKnownAtomId::name:
   4361        JS_FOR_EACH_PROTOTYPE(CASE_)
   4362 #  undef CASE_
   4363 
   4364 #  define CASE_(name) case WellKnownAtomId::name:
   4365        JS_FOR_EACH_WELL_KNOWN_SYMBOL(CASE_)
   4366 #  undef CASE_
   4367 
   4368        {
   4369          ParserAtomsTable::dumpCharsNoQuote(out, index);
   4370          break;
   4371        }
   4372 
   4373      default:
   4374        // This includes tiny WellKnownAtomId atoms, which is invalid.
   4375        out.printf("WellKnown#%zu", size_t(index));
   4376        break;
   4377    }
   4378    return;
   4379  }
   4380 
   4381  if (taggedIndex.isLength1StaticParserString()) {
   4382    auto index = taggedIndex.toLength1StaticParserString();
   4383    ParserAtomsTable::dumpCharsNoQuote(out, index);
   4384    return;
   4385  }
   4386 
   4387  if (taggedIndex.isLength2StaticParserString()) {
   4388    auto index = taggedIndex.toLength2StaticParserString();
   4389    ParserAtomsTable::dumpCharsNoQuote(out, index);
   4390    return;
   4391  }
   4392 
   4393  if (taggedIndex.isLength3StaticParserString()) {
   4394    auto index = taggedIndex.toLength3StaticParserString();
   4395    ParserAtomsTable::dumpCharsNoQuote(out, index);
   4396    return;
   4397  }
   4398 
   4399  MOZ_ASSERT(taggedIndex.isNull());
   4400  out.put("#<null name>");
   4401 }
   4402 
   4403 void RegExpStencil::dump() const {
   4404  js::Fprinter out(stderr);
   4405  js::JSONPrinter json(out);
   4406  dump(json, nullptr);
   4407 }
   4408 
   4409 void RegExpStencil::dump(js::JSONPrinter& json,
   4410                         const CompilationStencil* stencil) const {
   4411  json.beginObject();
   4412  dumpFields(json, stencil);
   4413  json.endObject();
   4414 }
   4415 
   4416 void RegExpStencil::dumpFields(js::JSONPrinter& json,
   4417                               const CompilationStencil* stencil) const {
   4418  json.beginObjectProperty("pattern");
   4419  DumpTaggedParserAtomIndex(json, atom_, stencil);
   4420  json.endObject();
   4421 
   4422  GenericPrinter& out = json.beginStringProperty("flags");
   4423 
   4424  if (flags().global()) {
   4425    out.put("g");
   4426  }
   4427  if (flags().ignoreCase()) {
   4428    out.put("i");
   4429  }
   4430  if (flags().multiline()) {
   4431    out.put("m");
   4432  }
   4433  if (flags().dotAll()) {
   4434    out.put("s");
   4435  }
   4436  if (flags().unicode()) {
   4437    out.put("u");
   4438  }
   4439  if (flags().sticky()) {
   4440    out.put("y");
   4441  }
   4442 
   4443  json.endStringProperty();
   4444 }
   4445 
   4446 void BigIntStencil::dump() const {
   4447  js::Fprinter out(stderr);
   4448  js::JSONPrinter json(out);
   4449  dump(json);
   4450 }
   4451 
   4452 void BigIntStencil::dump(js::JSONPrinter& json) const {
   4453  GenericPrinter& out = json.beginString();
   4454  dumpCharsNoQuote(out);
   4455  json.endString();
   4456 }
   4457 
   4458 void BigIntStencil::dumpCharsNoQuote(GenericPrinter& out) const {
   4459  bigInt_.match(
   4460      [&out](mozilla::Span<char16_t> source) {
   4461        for (char16_t c : source) {
   4462          out.putChar(char(c));
   4463        }
   4464      },
   4465      [&out](int64_t int64) { out.printf("%" PRId64, int64); });
   4466 }
   4467 
   4468 void ScopeStencil::dump() const {
   4469  js::Fprinter out(stderr);
   4470  js::JSONPrinter json(out);
   4471  dump(json, nullptr, nullptr);
   4472 }
   4473 
   4474 void ScopeStencil::dump(js::JSONPrinter& json,
   4475                        const BaseParserScopeData* baseScopeData,
   4476                        const CompilationStencil* stencil) const {
   4477  json.beginObject();
   4478  dumpFields(json, baseScopeData, stencil);
   4479  json.endObject();
   4480 }
   4481 
   4482 void ScopeStencil::dumpFields(js::JSONPrinter& json,
   4483                              const BaseParserScopeData* baseScopeData,
   4484                              const CompilationStencil* stencil) const {
   4485  json.property("kind", ScopeKindString(kind_));
   4486 
   4487  if (hasEnclosing()) {
   4488    json.formatProperty("enclosing", "ScopeIndex(%zu)", size_t(enclosing()));
   4489  }
   4490 
   4491  json.property("firstFrameSlot", firstFrameSlot_);
   4492 
   4493  if (hasEnvironmentShape()) {
   4494    json.formatProperty("numEnvironmentSlots", "%zu",
   4495                        size_t(numEnvironmentSlots_));
   4496  }
   4497 
   4498  if (isFunction()) {
   4499    json.formatProperty("functionIndex", "ScriptIndex(%zu)",
   4500                        size_t(functionIndex_));
   4501  }
   4502 
   4503  json.beginListProperty("flags");
   4504  if (flags_ & HasEnclosing) {
   4505    json.value("HasEnclosing");
   4506  }
   4507  if (flags_ & HasEnvironmentShape) {
   4508    json.value("HasEnvironmentShape");
   4509  }
   4510  if (flags_ & IsArrow) {
   4511    json.value("IsArrow");
   4512  }
   4513  json.endList();
   4514 
   4515  if (!baseScopeData) {
   4516    return;
   4517  }
   4518 
   4519  json.beginObjectProperty("data");
   4520 
   4521  mozilla::Span<const ParserBindingName> trailingNames;
   4522  switch (kind_) {
   4523    case ScopeKind::Function: {
   4524      const auto* data =
   4525          static_cast<const FunctionScope::ParserData*>(baseScopeData);
   4526      json.property("nextFrameSlot", data->slotInfo.nextFrameSlot);
   4527      json.property("hasParameterExprs", data->slotInfo.hasParameterExprs());
   4528      json.property("nonPositionalFormalStart",
   4529                    data->slotInfo.nonPositionalFormalStart);
   4530      json.property("varStart", data->slotInfo.varStart);
   4531 
   4532      trailingNames = GetScopeDataTrailingNames(data);
   4533      break;
   4534    }
   4535 
   4536    case ScopeKind::FunctionBodyVar: {
   4537      const auto* data =
   4538          static_cast<const VarScope::ParserData*>(baseScopeData);
   4539      json.property("nextFrameSlot", data->slotInfo.nextFrameSlot);
   4540 
   4541      trailingNames = GetScopeDataTrailingNames(data);
   4542      break;
   4543    }
   4544 
   4545    case ScopeKind::Lexical:
   4546    case ScopeKind::SimpleCatch:
   4547    case ScopeKind::Catch:
   4548    case ScopeKind::NamedLambda:
   4549    case ScopeKind::StrictNamedLambda:
   4550    case ScopeKind::FunctionLexical: {
   4551      const auto* data =
   4552          static_cast<const LexicalScope::ParserData*>(baseScopeData);
   4553      json.property("nextFrameSlot", data->slotInfo.nextFrameSlot);
   4554      json.property("constStart", data->slotInfo.constStart);
   4555 
   4556      trailingNames = GetScopeDataTrailingNames(data);
   4557      break;
   4558    }
   4559 
   4560    case ScopeKind::ClassBody: {
   4561      const auto* data =
   4562          static_cast<const ClassBodyScope::ParserData*>(baseScopeData);
   4563      json.property("nextFrameSlot", data->slotInfo.nextFrameSlot);
   4564      json.property("privateMethodStart", data->slotInfo.privateMethodStart);
   4565 
   4566      trailingNames = GetScopeDataTrailingNames(data);
   4567      break;
   4568    }
   4569 
   4570    case ScopeKind::With: {
   4571      break;
   4572    }
   4573 
   4574    case ScopeKind::Eval:
   4575    case ScopeKind::StrictEval: {
   4576      const auto* data =
   4577          static_cast<const EvalScope::ParserData*>(baseScopeData);
   4578      json.property("nextFrameSlot", data->slotInfo.nextFrameSlot);
   4579 
   4580      trailingNames = GetScopeDataTrailingNames(data);
   4581      break;
   4582    }
   4583 
   4584    case ScopeKind::Global:
   4585    case ScopeKind::NonSyntactic: {
   4586      const auto* data =
   4587          static_cast<const GlobalScope::ParserData*>(baseScopeData);
   4588      json.property("letStart", data->slotInfo.letStart);
   4589      json.property("constStart", data->slotInfo.constStart);
   4590 
   4591      trailingNames = GetScopeDataTrailingNames(data);
   4592      break;
   4593    }
   4594 
   4595    case ScopeKind::Module: {
   4596      const auto* data =
   4597          static_cast<const ModuleScope::ParserData*>(baseScopeData);
   4598      json.property("nextFrameSlot", data->slotInfo.nextFrameSlot);
   4599      json.property("varStart", data->slotInfo.varStart);
   4600      json.property("letStart", data->slotInfo.letStart);
   4601      json.property("constStart", data->slotInfo.constStart);
   4602 
   4603      trailingNames = GetScopeDataTrailingNames(data);
   4604      break;
   4605    }
   4606 
   4607    case ScopeKind::WasmInstance: {
   4608      const auto* data =
   4609          static_cast<const WasmInstanceScope::ParserData*>(baseScopeData);
   4610      json.property("nextFrameSlot", data->slotInfo.nextFrameSlot);
   4611      json.property("globalsStart", data->slotInfo.globalsStart);
   4612 
   4613      trailingNames = GetScopeDataTrailingNames(data);
   4614      break;
   4615    }
   4616 
   4617    case ScopeKind::WasmFunction: {
   4618      const auto* data =
   4619          static_cast<const WasmFunctionScope::ParserData*>(baseScopeData);
   4620      json.property("nextFrameSlot", data->slotInfo.nextFrameSlot);
   4621 
   4622      trailingNames = GetScopeDataTrailingNames(data);
   4623      break;
   4624    }
   4625 
   4626    default: {
   4627      MOZ_CRASH("Unexpected ScopeKind");
   4628      break;
   4629    }
   4630  }
   4631 
   4632  if (!trailingNames.empty()) {
   4633    char index[64];
   4634    json.beginObjectProperty("trailingNames");
   4635    for (size_t i = 0; i < trailingNames.size(); i++) {
   4636      const auto& name = trailingNames[i];
   4637      SprintfLiteral(index, "%zu", i);
   4638      json.beginObjectProperty(index);
   4639 
   4640      json.boolProperty("closedOver", name.closedOver());
   4641 
   4642      json.boolProperty("isTopLevelFunction", name.isTopLevelFunction());
   4643 
   4644      json.beginObjectProperty("name");
   4645      DumpTaggedParserAtomIndex(json, name.name(), stencil);
   4646      json.endObject();
   4647 
   4648      json.endObject();
   4649    }
   4650    json.endObject();
   4651  }
   4652 
   4653  json.endObject();
   4654 }
   4655 
   4656 static void DumpModuleRequestVectorItems(
   4657    js::JSONPrinter& json, const StencilModuleMetadata::RequestVector& requests,
   4658    const CompilationStencil* stencil) {
   4659  for (const auto& request : requests) {
   4660    json.beginObject();
   4661    if (request.specifier) {
   4662      json.beginObjectProperty("specifier");
   4663      DumpTaggedParserAtomIndex(json, request.specifier, stencil);
   4664      json.endObject();
   4665    }
   4666    json.endObject();
   4667  }
   4668 }
   4669 
   4670 static void DumpModuleEntryVectorItems(
   4671    js::JSONPrinter& json, const StencilModuleMetadata::EntryVector& entries,
   4672    const CompilationStencil* stencil) {
   4673  for (const auto& entry : entries) {
   4674    json.beginObject();
   4675    if (entry.moduleRequest) {
   4676      json.property("moduleRequest", entry.moduleRequest.value());
   4677    }
   4678    if (entry.localName) {
   4679      json.beginObjectProperty("localName");
   4680      DumpTaggedParserAtomIndex(json, entry.localName, stencil);
   4681      json.endObject();
   4682    }
   4683    if (entry.importName) {
   4684      json.beginObjectProperty("importName");
   4685      DumpTaggedParserAtomIndex(json, entry.importName, stencil);
   4686      json.endObject();
   4687    }
   4688    if (entry.exportName) {
   4689      json.beginObjectProperty("exportName");
   4690      DumpTaggedParserAtomIndex(json, entry.exportName, stencil);
   4691      json.endObject();
   4692    }
   4693    // TODO: Dump assertions.
   4694    json.endObject();
   4695  }
   4696 }
   4697 
   4698 void StencilModuleMetadata::dump() const {
   4699  js::Fprinter out(stderr);
   4700  js::JSONPrinter json(out);
   4701  dump(json, nullptr);
   4702 }
   4703 
   4704 void StencilModuleMetadata::dump(js::JSONPrinter& json,
   4705                                 const CompilationStencil* stencil) const {
   4706  json.beginObject();
   4707  dumpFields(json, stencil);
   4708  json.endObject();
   4709 }
   4710 
   4711 void StencilModuleMetadata::dumpFields(
   4712    js::JSONPrinter& json, const CompilationStencil* stencil) const {
   4713  json.beginListProperty("moduleRequests");
   4714  DumpModuleRequestVectorItems(json, moduleRequests, stencil);
   4715  json.endList();
   4716 
   4717  json.beginListProperty("requestedModules");
   4718  DumpModuleEntryVectorItems(json, requestedModules, stencil);
   4719  json.endList();
   4720 
   4721  json.beginListProperty("importEntries");
   4722  DumpModuleEntryVectorItems(json, importEntries, stencil);
   4723  json.endList();
   4724 
   4725  json.beginListProperty("localExportEntries");
   4726  DumpModuleEntryVectorItems(json, localExportEntries, stencil);
   4727  json.endList();
   4728 
   4729  json.beginListProperty("indirectExportEntries");
   4730  DumpModuleEntryVectorItems(json, indirectExportEntries, stencil);
   4731  json.endList();
   4732 
   4733  json.beginListProperty("starExportEntries");
   4734  DumpModuleEntryVectorItems(json, starExportEntries, stencil);
   4735  json.endList();
   4736 
   4737  json.beginListProperty("functionDecls");
   4738  for (const auto& index : functionDecls) {
   4739    json.value("ScriptIndex(%zu)", size_t(index));
   4740  }
   4741  json.endList();
   4742 
   4743  json.boolProperty("isAsync", isAsync);
   4744 }
   4745 
   4746 void js::DumpImmutableScriptFlags(js::JSONPrinter& json,
   4747                                  ImmutableScriptFlags immutableFlags) {
   4748  for (uint32_t i = 1; i; i = i << 1) {
   4749    if (uint32_t(immutableFlags) & i) {
   4750      switch (ImmutableScriptFlagsEnum(i)) {
   4751        case ImmutableScriptFlagsEnum::IsForEval:
   4752          json.value("IsForEval");
   4753          break;
   4754        case ImmutableScriptFlagsEnum::IsModule:
   4755          json.value("IsModule");
   4756          break;
   4757        case ImmutableScriptFlagsEnum::IsFunction:
   4758          json.value("IsFunction");
   4759          break;
   4760        case ImmutableScriptFlagsEnum::SelfHosted:
   4761          json.value("SelfHosted");
   4762          break;
   4763        case ImmutableScriptFlagsEnum::ForceStrict:
   4764          json.value("ForceStrict");
   4765          break;
   4766        case ImmutableScriptFlagsEnum::HasNonSyntacticScope:
   4767          json.value("HasNonSyntacticScope");
   4768          break;
   4769        case ImmutableScriptFlagsEnum::NoScriptRval:
   4770          json.value("NoScriptRval");
   4771          break;
   4772        case ImmutableScriptFlagsEnum::TreatAsRunOnce:
   4773          json.value("TreatAsRunOnce");
   4774          break;
   4775        case ImmutableScriptFlagsEnum::Strict:
   4776          json.value("Strict");
   4777          break;
   4778        case ImmutableScriptFlagsEnum::HasModuleGoal:
   4779          json.value("HasModuleGoal");
   4780          break;
   4781        case ImmutableScriptFlagsEnum::HasInnerFunctions:
   4782          json.value("HasInnerFunctions");
   4783          break;
   4784        case ImmutableScriptFlagsEnum::HasDirectEval:
   4785          json.value("HasDirectEval");
   4786          break;
   4787        case ImmutableScriptFlagsEnum::BindingsAccessedDynamically:
   4788          json.value("BindingsAccessedDynamically");
   4789          break;
   4790        case ImmutableScriptFlagsEnum::HasCallSiteObj:
   4791          json.value("HasCallSiteObj");
   4792          break;
   4793        case ImmutableScriptFlagsEnum::IsAsync:
   4794          json.value("IsAsync");
   4795          break;
   4796        case ImmutableScriptFlagsEnum::IsGenerator:
   4797          json.value("IsGenerator");
   4798          break;
   4799        case ImmutableScriptFlagsEnum::FunHasExtensibleScope:
   4800          json.value("FunHasExtensibleScope");
   4801          break;
   4802        case ImmutableScriptFlagsEnum::FunctionHasThisBinding:
   4803          json.value("FunctionHasThisBinding");
   4804          break;
   4805        case ImmutableScriptFlagsEnum::NeedsHomeObject:
   4806          json.value("NeedsHomeObject");
   4807          break;
   4808        case ImmutableScriptFlagsEnum::IsDerivedClassConstructor:
   4809          json.value("IsDerivedClassConstructor");
   4810          break;
   4811        case ImmutableScriptFlagsEnum::IsSyntheticFunction:
   4812          json.value("IsSyntheticFunction");
   4813          break;
   4814        case ImmutableScriptFlagsEnum::UseMemberInitializers:
   4815          json.value("UseMemberInitializers");
   4816          break;
   4817        case ImmutableScriptFlagsEnum::HasRest:
   4818          json.value("HasRest");
   4819          break;
   4820        case ImmutableScriptFlagsEnum::NeedsFunctionEnvironmentObjects:
   4821          json.value("NeedsFunctionEnvironmentObjects");
   4822          break;
   4823        case ImmutableScriptFlagsEnum::FunctionHasExtraBodyVarScope:
   4824          json.value("FunctionHasExtraBodyVarScope");
   4825          break;
   4826        case ImmutableScriptFlagsEnum::ShouldDeclareArguments:
   4827          json.value("ShouldDeclareArguments");
   4828          break;
   4829        case ImmutableScriptFlagsEnum::NeedsArgsObj:
   4830          json.value("NeedsArgsObj");
   4831          break;
   4832        case ImmutableScriptFlagsEnum::HasMappedArgsObj:
   4833          json.value("HasMappedArgsObj");
   4834          break;
   4835        case ImmutableScriptFlagsEnum::IsInlinableLargeFunction:
   4836          json.value("IsInlinableLargeFunction");
   4837          break;
   4838        case ImmutableScriptFlagsEnum::FunctionHasNewTargetBinding:
   4839          json.value("FunctionHasNewTargetBinding");
   4840          break;
   4841        case ImmutableScriptFlagsEnum::UsesArgumentsIntrinsics:
   4842          json.value("UsesArgumentsIntrinsics");
   4843          break;
   4844        default:
   4845          json.value("Unknown(%x)", i);
   4846          break;
   4847      }
   4848    }
   4849  }
   4850 }
   4851 
   4852 void js::DumpFunctionFlagsItems(js::JSONPrinter& json,
   4853                                FunctionFlags functionFlags) {
   4854  switch (functionFlags.kind()) {
   4855    case FunctionFlags::FunctionKind::NormalFunction:
   4856      json.value("NORMAL_KIND");
   4857      break;
   4858    case FunctionFlags::FunctionKind::AsmJS:
   4859      json.value("ASMJS_KIND");
   4860      break;
   4861    case FunctionFlags::FunctionKind::Wasm:
   4862      json.value("WASM_KIND");
   4863      break;
   4864    case FunctionFlags::FunctionKind::Arrow:
   4865      json.value("ARROW_KIND");
   4866      break;
   4867    case FunctionFlags::FunctionKind::Method:
   4868      json.value("METHOD_KIND");
   4869      break;
   4870    case FunctionFlags::FunctionKind::ClassConstructor:
   4871      json.value("CLASSCONSTRUCTOR_KIND");
   4872      break;
   4873    case FunctionFlags::FunctionKind::Getter:
   4874      json.value("GETTER_KIND");
   4875      break;
   4876    case FunctionFlags::FunctionKind::Setter:
   4877      json.value("SETTER_KIND");
   4878      break;
   4879    default:
   4880      json.value("Unknown(%x)", uint8_t(functionFlags.kind()));
   4881      break;
   4882  }
   4883 
   4884  static_assert(FunctionFlags::FUNCTION_KIND_MASK == 0x0007,
   4885                "FunctionKind should use the lowest 3 bits");
   4886  for (uint16_t i = 1 << 3; i; i = i << 1) {
   4887    if (functionFlags.toRaw() & i) {
   4888      switch (FunctionFlags::Flags(i)) {
   4889        case FunctionFlags::Flags::EXTENDED:
   4890          json.value("EXTENDED");
   4891          break;
   4892        case FunctionFlags::Flags::SELF_HOSTED:
   4893          json.value("SELF_HOSTED");
   4894          break;
   4895        case FunctionFlags::Flags::BASESCRIPT:
   4896          json.value("BASESCRIPT");
   4897          break;
   4898        case FunctionFlags::Flags::SELFHOSTLAZY:
   4899          json.value("SELFHOSTLAZY");
   4900          break;
   4901        case FunctionFlags::Flags::CONSTRUCTOR:
   4902          json.value("CONSTRUCTOR");
   4903          break;
   4904        case FunctionFlags::Flags::LAZY_ACCESSOR_NAME:
   4905          json.value("LAZY_ACCESSOR_NAME");
   4906          break;
   4907        case FunctionFlags::Flags::LAMBDA:
   4908          json.value("LAMBDA");
   4909          break;
   4910        case FunctionFlags::Flags::NATIVE_JIT_ENTRY:
   4911          json.value("NATIVE_JIT_ENTRY");
   4912          break;
   4913        case FunctionFlags::Flags::HAS_INFERRED_NAME:
   4914          json.value("HAS_INFERRED_NAME");
   4915          break;
   4916        case FunctionFlags::Flags::HAS_GUESSED_ATOM:
   4917          json.value("HAS_GUESSED_ATOM");
   4918          break;
   4919        case FunctionFlags::Flags::RESOLVED_NAME:
   4920          json.value("RESOLVED_NAME");
   4921          break;
   4922        case FunctionFlags::Flags::RESOLVED_LENGTH:
   4923          json.value("RESOLVED_LENGTH");
   4924          break;
   4925        case FunctionFlags::Flags::GHOST_FUNCTION:
   4926          json.value("GHOST_FUNCTION");
   4927          break;
   4928        default:
   4929          json.value("Unknown(%x)", i);
   4930          break;
   4931      }
   4932    }
   4933  }
   4934 }
   4935 
   4936 static void DumpScriptThing(js::JSONPrinter& json,
   4937                            const CompilationStencil* stencil,
   4938                            TaggedScriptThingIndex thing) {
   4939  switch (thing.tag()) {
   4940    case TaggedScriptThingIndex::Kind::ParserAtomIndex:
   4941    case TaggedScriptThingIndex::Kind::WellKnown:
   4942      json.beginObject();
   4943      json.property("type", "Atom");
   4944      DumpTaggedParserAtomIndex(json, thing.toAtom(), stencil);
   4945      json.endObject();
   4946      break;
   4947    case TaggedScriptThingIndex::Kind::Null:
   4948      json.nullValue();
   4949      break;
   4950    case TaggedScriptThingIndex::Kind::BigInt:
   4951      json.value("BigIntIndex(%zu)", size_t(thing.toBigInt()));
   4952      break;
   4953    case TaggedScriptThingIndex::Kind::ObjLiteral:
   4954      json.value("ObjLiteralIndex(%zu)", size_t(thing.toObjLiteral()));
   4955      break;
   4956    case TaggedScriptThingIndex::Kind::RegExp:
   4957      json.value("RegExpIndex(%zu)", size_t(thing.toRegExp()));
   4958      break;
   4959    case TaggedScriptThingIndex::Kind::Scope:
   4960      json.value("ScopeIndex(%zu)", size_t(thing.toScope()));
   4961      break;
   4962    case TaggedScriptThingIndex::Kind::Function:
   4963      json.value("ScriptIndex(%zu)", size_t(thing.toFunction()));
   4964      break;
   4965    case TaggedScriptThingIndex::Kind::EmptyGlobalScope:
   4966      json.value("EmptyGlobalScope");
   4967      break;
   4968  }
   4969 }
   4970 
   4971 void ScriptStencil::dump() const {
   4972  js::Fprinter out(stderr);
   4973  js::JSONPrinter json(out);
   4974  dump(json, nullptr);
   4975 }
   4976 
   4977 void ScriptStencil::dump(js::JSONPrinter& json,
   4978                         const CompilationStencil* stencil) const {
   4979  json.beginObject();
   4980  dumpFields(json, stencil);
   4981  json.endObject();
   4982 }
   4983 
   4984 void ScriptStencil::dumpFields(js::JSONPrinter& json,
   4985                               const CompilationStencil* stencil) const {
   4986  json.formatProperty("gcThingsOffset", "CompilationGCThingIndex(%u)",
   4987                      gcThingsOffset.index);
   4988  json.property("gcThingsLength", gcThingsLength);
   4989 
   4990  if (stencil) {
   4991    json.beginListProperty("gcThings");
   4992    for (const auto& thing : gcthings(*stencil)) {
   4993      DumpScriptThing(json, stencil, thing);
   4994    }
   4995    json.endList();
   4996  }
   4997 
   4998  json.beginListProperty("flags");
   4999  if (flags_ & WasEmittedByEnclosingScriptFlag) {
   5000    json.value("WasEmittedByEnclosingScriptFlag");
   5001  }
   5002  if (flags_ & AllowRelazifyFlag) {
   5003    json.value("AllowRelazifyFlag");
   5004  }
   5005  if (flags_ & HasSharedDataFlag) {
   5006    json.value("HasSharedDataFlag");
   5007  }
   5008  if (flags_ & HasLazyFunctionEnclosingScopeIndexFlag) {
   5009    json.value("HasLazyFunctionEnclosingScopeIndexFlag");
   5010  }
   5011  json.endList();
   5012 
   5013  if (isFunction()) {
   5014    json.beginObjectProperty("functionAtom");
   5015    DumpTaggedParserAtomIndex(json, functionAtom, stencil);
   5016    json.endObject();
   5017 
   5018    json.beginListProperty("functionFlags");
   5019    DumpFunctionFlagsItems(json, functionFlags);
   5020    json.endList();
   5021 
   5022    if (hasLazyFunctionEnclosingScopeIndex()) {
   5023      json.formatProperty("lazyFunctionEnclosingScopeIndex", "ScopeIndex(%zu)",
   5024                          size_t(lazyFunctionEnclosingScopeIndex()));
   5025    }
   5026 
   5027    if (hasSelfHostedCanonicalName()) {
   5028      json.beginObjectProperty("selfHostCanonicalName");
   5029      DumpTaggedParserAtomIndex(json, selfHostedCanonicalName(), stencil);
   5030      json.endObject();
   5031    }
   5032  }
   5033 }
   5034 
   5035 void ScriptStencilExtra::dump() const {
   5036  js::Fprinter out(stderr);
   5037  js::JSONPrinter json(out);
   5038  dump(json);
   5039 }
   5040 
   5041 void ScriptStencilExtra::dump(js::JSONPrinter& json) const {
   5042  json.beginObject();
   5043  dumpFields(json);
   5044  json.endObject();
   5045 }
   5046 
   5047 void ScriptStencilExtra::dumpFields(js::JSONPrinter& json) const {
   5048  json.beginListProperty("immutableFlags");
   5049  DumpImmutableScriptFlags(json, immutableFlags);
   5050  json.endList();
   5051 
   5052  json.beginObjectProperty("extent");
   5053  json.property("sourceStart", extent.sourceStart);
   5054  json.property("sourceEnd", extent.sourceEnd);
   5055  json.property("toStringStart", extent.toStringStart);
   5056  json.property("toStringEnd", extent.toStringEnd);
   5057  json.property("lineno", extent.lineno);
   5058  json.property("column", extent.column.oneOriginValue());
   5059  json.endObject();
   5060 
   5061  json.property("memberInitializers", memberInitializers_);
   5062 
   5063  json.property("nargs", nargs);
   5064 }
   5065 
   5066 void SharedDataContainer::dump() const {
   5067  js::Fprinter out(stderr);
   5068  js::JSONPrinter json(out);
   5069  dump(json);
   5070 }
   5071 
   5072 void SharedDataContainer::dump(js::JSONPrinter& json) const {
   5073  json.beginObject();
   5074  dumpFields(json);
   5075  json.endObject();
   5076 }
   5077 
   5078 void SharedDataContainer::dumpFields(js::JSONPrinter& json) const {
   5079  if (isEmpty()) {
   5080    json.nullProperty("ScriptIndex(0)");
   5081    return;
   5082  }
   5083 
   5084  if (isSingle()) {
   5085    json.formatProperty("ScriptIndex(0)", "u8[%zu]",
   5086                        asSingle()->immutableDataLength());
   5087    return;
   5088  }
   5089 
   5090  if (isVector()) {
   5091    auto& vec = *asVector();
   5092 
   5093    char index[64];
   5094    for (size_t i = 0; i < vec.length(); i++) {
   5095      SprintfLiteral(index, "ScriptIndex(%zu)", i);
   5096      if (vec[i]) {
   5097        json.formatProperty(index, "u8[%zu]", vec[i]->immutableDataLength());
   5098      } else {
   5099        json.nullProperty(index);
   5100      }
   5101    }
   5102    return;
   5103  }
   5104 
   5105  if (isMap()) {
   5106    auto& map = *asMap();
   5107 
   5108    char index[64];
   5109    for (auto iter = map.iter(); !iter.done(); iter.next()) {
   5110      SprintfLiteral(index, "ScriptIndex(%u)", iter.get().key().index);
   5111      json.formatProperty(index, "u8[%zu]",
   5112                          iter.get().value()->immutableDataLength());
   5113    }
   5114    return;
   5115  }
   5116 
   5117  MOZ_ASSERT(isBorrow());
   5118  asBorrow()->dumpFields(json);
   5119 }
   5120 
   5121 struct DumpOptionsFields {
   5122  js::JSONPrinter& json;
   5123 
   5124  void operator()(const char* name, JS::AsmJSOption value) {
   5125    const char* valueStr = nullptr;
   5126    switch (value) {
   5127      case JS::AsmJSOption::Enabled:
   5128        valueStr = "JS::AsmJSOption::Enabled";
   5129        break;
   5130      case JS::AsmJSOption::DisabledByAsmJSPref:
   5131        valueStr = "JS::AsmJSOption::DisabledByAsmJSPref";
   5132        break;
   5133      case JS::AsmJSOption::DisabledByLinker:
   5134        valueStr = "JS::AsmJSOption::DisabledByLinker";
   5135        break;
   5136      case JS::AsmJSOption::DisabledByNoWasmCompiler:
   5137        valueStr = "JS::AsmJSOption::DisabledByNoWasmCompiler";
   5138        break;
   5139      case JS::AsmJSOption::DisabledByDebugger:
   5140        valueStr = "JS::AsmJSOption::DisabledByDebugger";
   5141        break;
   5142    }
   5143    json.property(name, valueStr);
   5144  }
   5145 
   5146  void operator()(const char* name, JS::DelazificationOption value) {
   5147    const char* valueStr = nullptr;
   5148    switch (value) {
   5149 #  define SelectValueStr_(Strategy)                      \
   5150    case JS::DelazificationOption::Strategy:             \
   5151      valueStr = "JS::DelazificationOption::" #Strategy; \
   5152      break;
   5153 
   5154      FOREACH_DELAZIFICATION_STRATEGY(SelectValueStr_)
   5155 #  undef SelectValueStr_
   5156    }
   5157    json.property(name, valueStr);
   5158  }
   5159 
   5160  void operator()(const char* name, JS::EagerBaselineOption value) {
   5161    const char* valueStr = nullptr;
   5162    switch (value) {
   5163      case JS::EagerBaselineOption::None:
   5164        valueStr = "JS::EagerBaselineOption::None";
   5165        break;
   5166      case JS::EagerBaselineOption::JitHints:
   5167        valueStr = "JS::EagerBaselineOption::JitHints";
   5168        break;
   5169      case JS::EagerBaselineOption::Aggressive:
   5170        valueStr = "JS::EagerBaselineOption::Aggressive";
   5171        break;
   5172      default:
   5173        MOZ_CRASH("Unknown JS::EagerBaselineOption enum");
   5174        break;
   5175    }
   5176    json.property(name, valueStr);
   5177  }
   5178 
   5179  void operator()(const char* name, char16_t* value) {}
   5180 
   5181  void operator()(const char* name, bool value) { json.property(name, value); }
   5182 
   5183  void operator()(const char* name, uint32_t value) {
   5184    json.property(name, value);
   5185  }
   5186 
   5187  void operator()(const char* name, uint64_t value) {
   5188    json.property(name, value);
   5189  }
   5190 
   5191  void operator()(const char* name, const char* value) {
   5192    if (value) {
   5193      json.property(name, value);
   5194      return;
   5195    }
   5196    json.nullProperty(name);
   5197  }
   5198 
   5199  void operator()(const char* name, JS::ConstUTF8CharsZ value) {
   5200    if (value) {
   5201      json.property(name, value.c_str());
   5202      return;
   5203    }
   5204    json.nullProperty(name);
   5205  }
   5206 };
   5207 
   5208 static void DumpOptionsFields(js::JSONPrinter& json,
   5209                              const JS::ReadOnlyCompileOptions& options) {
   5210  struct DumpOptionsFields printer{json};
   5211  options.dumpWith(printer);
   5212 }
   5213 
   5214 static void DumpInputScopeFields(js::JSONPrinter& json,
   5215                                 const InputScope& scope) {
   5216  json.property("kind", ScopeKindString(scope.kind()));
   5217 
   5218  InputScope enclosing = scope.enclosing();
   5219  if (enclosing.isNull()) {
   5220    json.nullProperty("enclosing");
   5221  } else {
   5222    json.beginObjectProperty("enclosing");
   5223    DumpInputScopeFields(json, enclosing);
   5224    json.endObject();
   5225  }
   5226 }
   5227 
   5228 static void DumpInputScriptFields(js::JSONPrinter& json,
   5229                                  const InputScript& script) {
   5230  json.beginObjectProperty("extent");
   5231  {
   5232    SourceExtent extent = script.extent();
   5233    json.property("sourceStart", extent.sourceStart);
   5234    json.property("sourceEnd", extent.sourceEnd);
   5235    json.property("toStringStart", extent.toStringStart);
   5236    json.property("toStringEnd", extent.toStringEnd);
   5237    json.property("lineno", extent.lineno);
   5238    json.property("column", extent.column.oneOriginValue());
   5239  }
   5240  json.endObject();
   5241 
   5242  json.beginListProperty("immutableFlags");
   5243  DumpImmutableScriptFlags(json, script.immutableFlags());
   5244  json.endList();
   5245 
   5246  json.beginListProperty("functionFlags");
   5247  DumpFunctionFlagsItems(json, script.functionFlags());
   5248  json.endList();
   5249 
   5250  json.property("hasPrivateScriptData", script.hasPrivateScriptData());
   5251 
   5252  InputScope scope = script.enclosingScope();
   5253  if (scope.isNull()) {
   5254    json.nullProperty("enclosingScope");
   5255  } else {
   5256    json.beginObjectProperty("enclosingScope");
   5257    DumpInputScopeFields(json, scope);
   5258    json.endObject();
   5259  }
   5260 
   5261  if (script.useMemberInitializers()) {
   5262    json.property("memberInitializers",
   5263                  script.getMemberInitializers().serialize());
   5264  }
   5265 }
   5266 
   5267 void CompilationInput::dump() const {
   5268  js::Fprinter out(stderr);
   5269  js::JSONPrinter json(out);
   5270  dump(json);
   5271  out.put("\n");
   5272 }
   5273 
   5274 void CompilationInput::dump(js::JSONPrinter& json) const {
   5275  json.beginObject();
   5276  dumpFields(json);
   5277  json.endObject();
   5278 }
   5279 
   5280 void CompilationInput::dumpFields(js::JSONPrinter& json) const {
   5281  const char* targetStr = nullptr;
   5282  switch (target) {
   5283    case CompilationTarget::Global:
   5284      targetStr = "CompilationTarget::Global";
   5285      break;
   5286    case CompilationTarget::SelfHosting:
   5287      targetStr = "CompilationTarget::SelfHosting";
   5288      break;
   5289    case CompilationTarget::StandaloneFunction:
   5290      targetStr = "CompilationTarget::StandaloneFunction";
   5291      break;
   5292    case CompilationTarget::StandaloneFunctionInNonSyntacticScope:
   5293      targetStr = "CompilationTarget::StandaloneFunctionInNonSyntacticScope";
   5294      break;
   5295    case CompilationTarget::Eval:
   5296      targetStr = "CompilationTarget::Eval";
   5297      break;
   5298    case CompilationTarget::Module:
   5299      targetStr = "CompilationTarget::Module";
   5300      break;
   5301    case CompilationTarget::Delazification:
   5302      targetStr = "CompilationTarget::Delazification";
   5303      break;
   5304  }
   5305  json.property("target", targetStr);
   5306 
   5307  json.beginObjectProperty("options");
   5308  DumpOptionsFields(json, options);
   5309  json.endObject();
   5310 
   5311  if (lazy_.isNull()) {
   5312    json.nullProperty("lazy_");
   5313  } else {
   5314    json.beginObjectProperty("lazy_");
   5315    DumpInputScriptFields(json, lazy_);
   5316    json.endObject();
   5317  }
   5318 
   5319  if (enclosingScope.isNull()) {
   5320    json.nullProperty("enclosingScope");
   5321  } else {
   5322    json.beginObjectProperty("enclosingScope");
   5323    DumpInputScopeFields(json, enclosingScope);
   5324    json.endObject();
   5325  }
   5326 
   5327  // TODO: Support printing the atomCache and the source fields.
   5328 }
   5329 
   5330 void CompilationStencil::dump() const {
   5331  js::Fprinter out(stderr);
   5332  js::JSONPrinter json(out);
   5333  dump(json);
   5334  out.put("\n");
   5335 }
   5336 
   5337 void CompilationStencil::dump(js::JSONPrinter& json) const {
   5338  json.beginObject();
   5339  dumpFields(json);
   5340  json.endObject();
   5341 }
   5342 
   5343 void CompilationStencil::dumpFields(js::JSONPrinter& json) const {
   5344  char index[64];
   5345 
   5346  json.beginObjectProperty("scriptData");
   5347  for (size_t i = 0; i < scriptData.size(); i++) {
   5348    SprintfLiteral(index, "ScriptIndex(%zu)", i);
   5349    json.beginObjectProperty(index);
   5350    scriptData[i].dumpFields(json, this);
   5351    json.endObject();
   5352  }
   5353  json.endObject();
   5354 
   5355  json.beginObjectProperty("scriptExtra");
   5356  for (size_t i = 0; i < scriptExtra.size(); i++) {
   5357    SprintfLiteral(index, "ScriptIndex(%zu)", i);
   5358    json.beginObjectProperty(index);
   5359    scriptExtra[i].dumpFields(json);
   5360    json.endObject();
   5361  }
   5362  json.endObject();
   5363 
   5364  json.beginObjectProperty("scopeData");
   5365  MOZ_ASSERT(scopeData.size() == scopeNames.size());
   5366  for (size_t i = 0; i < scopeData.size(); i++) {
   5367    SprintfLiteral(index, "ScopeIndex(%zu)", i);
   5368    json.beginObjectProperty(index);
   5369    scopeData[i].dumpFields(json, scopeNames[i], this);
   5370    json.endObject();
   5371  }
   5372  json.endObject();
   5373 
   5374  json.beginObjectProperty("sharedData");
   5375  sharedData.dumpFields(json);
   5376  json.endObject();
   5377 
   5378  json.beginObjectProperty("regExpData");
   5379  for (size_t i = 0; i < regExpData.size(); i++) {
   5380    SprintfLiteral(index, "RegExpIndex(%zu)", i);
   5381    json.beginObjectProperty(index);
   5382    regExpData[i].dumpFields(json, this);
   5383    json.endObject();
   5384  }
   5385  json.endObject();
   5386 
   5387  json.beginObjectProperty("bigIntData");
   5388  for (size_t i = 0; i < bigIntData.size(); i++) {
   5389    SprintfLiteral(index, "BigIntIndex(%zu)", i);
   5390    GenericPrinter& out = json.beginStringProperty(index);
   5391    bigIntData[i].dumpCharsNoQuote(out);
   5392    json.endStringProperty();
   5393  }
   5394  json.endObject();
   5395 
   5396  json.beginObjectProperty("objLiteralData");
   5397  for (size_t i = 0; i < objLiteralData.size(); i++) {
   5398    SprintfLiteral(index, "ObjLiteralIndex(%zu)", i);
   5399    json.beginObjectProperty(index);
   5400    objLiteralData[i].dumpFields(json, this);
   5401    json.endObject();
   5402  }
   5403  json.endObject();
   5404 
   5405  if (moduleMetadata) {
   5406    json.beginObjectProperty("moduleMetadata");
   5407    moduleMetadata->dumpFields(json, this);
   5408    json.endObject();
   5409  }
   5410 
   5411  json.beginObjectProperty("asmJS");
   5412  if (asmJS) {
   5413    for (auto iter = asmJS->moduleMap.iter(); !iter.done(); iter.next()) {
   5414      SprintfLiteral(index, "ScriptIndex(%u)", iter.get().key().index);
   5415      json.formatProperty(index, "asm.js");
   5416    }
   5417  }
   5418  json.endObject();
   5419 }
   5420 
   5421 void CompilationStencil::dumpAtom(TaggedParserAtomIndex index) const {
   5422  js::Fprinter out(stderr);
   5423  js::JSONPrinter json(out);
   5424  json.beginObject();
   5425  DumpTaggedParserAtomIndex(json, index, this);
   5426  json.endObject();
   5427 }
   5428 
   5429 void ExtensibleCompilationStencil::dump() {
   5430  frontend::BorrowingCompilationStencil borrowingStencil(*this);
   5431  borrowingStencil.dump();
   5432 }
   5433 
   5434 void ExtensibleCompilationStencil::dump(js::JSONPrinter& json) {
   5435  frontend::BorrowingCompilationStencil borrowingStencil(*this);
   5436  borrowingStencil.dump(json);
   5437 }
   5438 
   5439 void ExtensibleCompilationStencil::dumpFields(js::JSONPrinter& json) {
   5440  frontend::BorrowingCompilationStencil borrowingStencil(*this);
   5441  borrowingStencil.dumpFields(json);
   5442 }
   5443 
   5444 void ExtensibleCompilationStencil::dumpAtom(TaggedParserAtomIndex index) {
   5445  frontend::BorrowingCompilationStencil borrowingStencil(*this);
   5446  borrowingStencil.dumpAtom(index);
   5447 }
   5448 
   5449 void InitialStencilAndDelazifications::dump() const {
   5450  js::Fprinter out(stderr);
   5451  js::JSONPrinter json(out);
   5452  dump(json);
   5453  out.put("\n");
   5454 }
   5455 
   5456 void InitialStencilAndDelazifications::dump(js::JSONPrinter& json) const {
   5457  json.beginObject();
   5458  dumpFields(json);
   5459  json.endObject();
   5460 }
   5461 
   5462 void InitialStencilAndDelazifications::dumpFields(js::JSONPrinter& json) const {
   5463  if (initial_) {
   5464    json.beginObjectProperty("initial_");
   5465    initial_->dumpFields(json);
   5466    json.endObject();
   5467  } else {
   5468    json.nullProperty("initial_");
   5469  }
   5470 
   5471  for (size_t i = 0; i < delazifications_.length(); i++) {
   5472    const CompilationStencil* delazification = delazifications_[i];
   5473 
   5474    char index[64];
   5475    SprintfLiteral(index, "ScriptIndex(%zu)", i + 1);
   5476 
   5477    if (delazification) {
   5478      json.beginObjectProperty(index);
   5479      delazification->dumpFields(json);
   5480      json.endObject();
   5481    } else {
   5482      json.nullProperty(index);
   5483    }
   5484  }
   5485 }
   5486 
   5487 #endif  // defined(DEBUG) || defined(JS_JITSPEW)
   5488 
   5489 JSString* CompilationAtomCache::getExistingStringAt(
   5490    ParserAtomIndex index) const {
   5491  MOZ_RELEASE_ASSERT(atoms_.length() >= index);
   5492  return atoms_[index];
   5493 }
   5494 
   5495 JSString* CompilationAtomCache::getExistingStringAt(
   5496    JSContext* cx, TaggedParserAtomIndex taggedIndex) const {
   5497  if (taggedIndex.isParserAtomIndex()) {
   5498    auto index = taggedIndex.toParserAtomIndex();
   5499    return getExistingStringAt(index);
   5500  }
   5501 
   5502  if (taggedIndex.isWellKnownAtomId()) {
   5503    auto index = taggedIndex.toWellKnownAtomId();
   5504    return GetWellKnownAtom(cx, index);
   5505  }
   5506 
   5507  if (taggedIndex.isLength1StaticParserString()) {
   5508    auto index = taggedIndex.toLength1StaticParserString();
   5509    return cx->staticStrings().getUnit(char16_t(index));
   5510  }
   5511 
   5512  if (taggedIndex.isLength2StaticParserString()) {
   5513    auto index = taggedIndex.toLength2StaticParserString();
   5514    return cx->staticStrings().getLength2FromIndex(size_t(index));
   5515  }
   5516 
   5517  MOZ_ASSERT(taggedIndex.isLength3StaticParserString());
   5518  auto index = taggedIndex.toLength3StaticParserString();
   5519  return cx->staticStrings().getUint(uint32_t(index));
   5520 }
   5521 
   5522 JSString* CompilationAtomCache::getStringAt(ParserAtomIndex index) const {
   5523  if (size_t(index) >= atoms_.length()) {
   5524    return nullptr;
   5525  }
   5526  return atoms_[index];
   5527 }
   5528 
   5529 JSAtom* CompilationAtomCache::getExistingAtomAt(ParserAtomIndex index) const {
   5530  return &getExistingStringAt(index)->asAtom();
   5531 }
   5532 
   5533 JSAtom* CompilationAtomCache::getExistingAtomAt(
   5534    JSContext* cx, TaggedParserAtomIndex taggedIndex) const {
   5535  return &getExistingStringAt(cx, taggedIndex)->asAtom();
   5536 }
   5537 
   5538 JSAtom* CompilationAtomCache::getAtomAt(ParserAtomIndex index) const {
   5539  if (size_t(index) >= atoms_.length()) {
   5540    return nullptr;
   5541  }
   5542  if (!atoms_[index]) {
   5543    return nullptr;
   5544  }
   5545  return &atoms_[index]->asAtom();
   5546 }
   5547 
   5548 bool CompilationAtomCache::hasAtomAt(ParserAtomIndex index) const {
   5549  if (size_t(index) >= atoms_.length()) {
   5550    return false;
   5551  }
   5552  return !!atoms_[index];
   5553 }
   5554 
   5555 bool CompilationAtomCache::setAtomAt(FrontendContext* fc, ParserAtomIndex index,
   5556                                     JSString* atom) {
   5557  if (size_t(index) < atoms_.length()) {
   5558    atoms_[index] = atom;
   5559    return true;
   5560  }
   5561 
   5562  if (!atoms_.resize(size_t(index) + 1)) {
   5563    ReportOutOfMemory(fc);
   5564    return false;
   5565  }
   5566 
   5567  atoms_[index] = atom;
   5568  return true;
   5569 }
   5570 
   5571 bool CompilationAtomCache::allocate(FrontendContext* fc, size_t length) {
   5572  MOZ_ASSERT(length >= atoms_.length());
   5573  if (length == atoms_.length()) {
   5574    return true;
   5575  }
   5576 
   5577  if (!atoms_.resize(length)) {
   5578    ReportOutOfMemory(fc);
   5579    return false;
   5580  }
   5581 
   5582  return true;
   5583 }
   5584 
   5585 void CompilationAtomCache::stealBuffer(AtomCacheVector& atoms) {
   5586  atoms_ = std::move(atoms);
   5587  // Destroy elements, without unreserving.
   5588  atoms_.clear();
   5589 }
   5590 
   5591 void CompilationAtomCache::releaseBuffer(AtomCacheVector& atoms) {
   5592  atoms = std::move(atoms_);
   5593 }
   5594 
   5595 bool CompilationState::allocateGCThingsUninitialized(
   5596    FrontendContext* fc, ScriptIndex scriptIndex, size_t length,
   5597    TaggedScriptThingIndex** cursor) {
   5598  MOZ_ASSERT(gcThingData.length() <= UINT32_MAX);
   5599 
   5600  auto gcThingsOffset = CompilationGCThingIndex(gcThingData.length());
   5601 
   5602  if (length > INDEX_LIMIT) {
   5603    ReportAllocationOverflow(fc);
   5604    return false;
   5605  }
   5606  uint32_t gcThingsLength = length;
   5607 
   5608  if (!gcThingData.growByUninitialized(length)) {
   5609    js::ReportOutOfMemory(fc);
   5610    return false;
   5611  }
   5612 
   5613  if (gcThingData.length() > UINT32_MAX) {
   5614    ReportAllocationOverflow(fc);
   5615    return false;
   5616  }
   5617 
   5618  ScriptStencil& script = scriptData[scriptIndex];
   5619  script.gcThingsOffset = gcThingsOffset;
   5620  script.gcThingsLength = gcThingsLength;
   5621 
   5622  *cursor = gcThingData.begin() + gcThingsOffset;
   5623  return true;
   5624 }
   5625 
   5626 bool CompilationState::appendScriptStencilAndData(FrontendContext* fc) {
   5627  if (!scriptData.emplaceBack()) {
   5628    js::ReportOutOfMemory(fc);
   5629    return false;
   5630  }
   5631 
   5632  if (isInitialStencil()) {
   5633    if (!scriptExtra.emplaceBack()) {
   5634      scriptData.popBack();
   5635      MOZ_ASSERT(scriptData.length() == scriptExtra.length());
   5636 
   5637      js::ReportOutOfMemory(fc);
   5638      return false;
   5639    }
   5640  }
   5641 
   5642  return true;
   5643 }
   5644 
   5645 bool CompilationState::appendGCThings(
   5646    FrontendContext* fc, ScriptIndex scriptIndex,
   5647    mozilla::Span<const TaggedScriptThingIndex> things) {
   5648  MOZ_ASSERT(gcThingData.length() <= UINT32_MAX);
   5649 
   5650  auto gcThingsOffset = CompilationGCThingIndex(gcThingData.length());
   5651 
   5652  if (things.size() > INDEX_LIMIT) {
   5653    ReportAllocationOverflow(fc);
   5654    return false;
   5655  }
   5656  uint32_t gcThingsLength = uint32_t(things.size());
   5657 
   5658  if (!gcThingData.append(things.data(), things.size())) {
   5659    js::ReportOutOfMemory(fc);
   5660    return false;
   5661  }
   5662 
   5663  if (gcThingData.length() > UINT32_MAX) {
   5664    ReportAllocationOverflow(fc);
   5665    return false;
   5666  }
   5667 
   5668  ScriptStencil& script = scriptData[scriptIndex];
   5669  script.gcThingsOffset = gcThingsOffset;
   5670  script.gcThingsLength = gcThingsLength;
   5671  return true;
   5672 }
   5673 
   5674 CompilationState::CompilationStatePosition CompilationState::getPosition() {
   5675  return CompilationStatePosition{scriptData.length(),
   5676                                  asmJS ? asmJS->moduleMap.count() : 0};
   5677 }
   5678 
   5679 void CompilationState::rewind(
   5680    const CompilationState::CompilationStatePosition& pos) {
   5681  if (asmJS && asmJS->moduleMap.count() != pos.asmJSCount) {
   5682    for (size_t i = pos.scriptDataLength; i < scriptData.length(); i++) {
   5683      asmJS->moduleMap.remove(ScriptIndex(i));
   5684    }
   5685    MOZ_ASSERT(asmJS->moduleMap.count() == pos.asmJSCount);
   5686  }
   5687  // scriptExtra is empty for delazification.
   5688  if (scriptExtra.length()) {
   5689    MOZ_ASSERT(scriptExtra.length() == scriptData.length());
   5690    scriptExtra.shrinkTo(pos.scriptDataLength);
   5691  }
   5692  scriptData.shrinkTo(pos.scriptDataLength);
   5693 }
   5694 
   5695 void CompilationState::markGhost(
   5696    const CompilationState::CompilationStatePosition& pos) {
   5697  for (size_t i = pos.scriptDataLength; i < scriptData.length(); i++) {
   5698    scriptData[i].setIsGhost();
   5699  }
   5700 }
   5701 
   5702 ScriptIndex CompilationStencilMerger::getInitialScriptIndexFor(
   5703    const CompilationStencil& delazification) const {
   5704  auto maybeIndex =
   5705      functionKeyToInitialScriptIndex_.get(delazification.functionKey);
   5706  MOZ_ASSERT(maybeIndex);
   5707  return *maybeIndex;
   5708 }
   5709 
   5710 template <typename T>
   5711 bool FunctionKeyToScriptIndexMap::init(FrontendContext* fc,
   5712                                       const T& scriptExtra,
   5713                                       size_t scriptExtraSize) {
   5714  if (!map_.reserve(scriptExtraSize - 1)) {
   5715    ReportOutOfMemory(fc);
   5716    return false;
   5717  }
   5718 
   5719  for (size_t i = 1; i < scriptExtraSize; i++) {
   5720    const auto& extra = scriptExtra[i];
   5721    auto key = extra.extent.toFunctionKey();
   5722 
   5723    // There can be multiple ScriptStencilExtra with same extent if
   5724    // the function is parsed multiple times because of rewind for
   5725    // arrow function, and in that case the last one's index should be used.
   5726    // Overwrite with the last one.
   5727    //
   5728    // Already reserved above, but OOMTest can hit failure mode in
   5729    // HashTable::add.
   5730    if (!map_.put(key, ScriptIndex(i))) {
   5731      ReportOutOfMemory(fc);
   5732      return false;
   5733    }
   5734  }
   5735 
   5736  return true;
   5737 }
   5738 
   5739 bool FunctionKeyToScriptIndexMap::init(FrontendContext* fc,
   5740                                       const CompilationStencil* initial) {
   5741  return init(fc, initial->scriptExtra, initial->scriptExtra.size());
   5742 }
   5743 
   5744 bool FunctionKeyToScriptIndexMap::init(
   5745    FrontendContext* fc, const ExtensibleCompilationStencil* initial) {
   5746  return init(fc, initial->scriptExtra, initial->scriptExtra.length());
   5747 }
   5748 
   5749 mozilla::Maybe<ScriptIndex> FunctionKeyToScriptIndexMap::get(
   5750    FunctionKey key) const {
   5751  auto p = map_.readonlyThreadsafeLookup(key);
   5752  if (!p) {
   5753    return mozilla::Nothing();
   5754  }
   5755  return mozilla::Some(p->value());
   5756 }
   5757 
   5758 size_t FunctionKeyToScriptIndexMap::sizeOfExcludingThis(
   5759    mozilla::MallocSizeOf mallocSizeOf) const {
   5760  return map_.shallowSizeOfExcludingThis(mallocSizeOf);
   5761 }
   5762 
   5763 bool CompilationStencilMerger::buildAtomIndexMap(
   5764    FrontendContext* fc, const CompilationStencil& delazification,
   5765    AtomIndexMap& atomIndexMap) {
   5766  uint32_t atomCount = delazification.parserAtomData.size();
   5767  if (!atomIndexMap.reserve(atomCount)) {
   5768    ReportOutOfMemory(fc);
   5769    return false;
   5770  }
   5771  for (const auto& atom : delazification.parserAtomData) {
   5772    auto mappedIndex = initial_->parserAtoms.internExternalParserAtom(fc, atom);
   5773    if (!mappedIndex) {
   5774      return false;
   5775    }
   5776    atomIndexMap.infallibleAppend(mappedIndex);
   5777  }
   5778  return true;
   5779 }
   5780 
   5781 bool CompilationStencilMerger::setInitial(
   5782    FrontendContext* fc, UniquePtr<ExtensibleCompilationStencil>&& initial) {
   5783  MOZ_ASSERT(!initial_);
   5784 
   5785  initial_ = std::move(initial);
   5786 
   5787  return functionKeyToInitialScriptIndex_.init(fc, initial_.get());
   5788 }
   5789 
   5790 template <typename GCThingIndexMapFunc, typename AtomIndexMapFunc,
   5791          typename ScopeIndexMapFunc>
   5792 static void MergeScriptStencil(ScriptStencil& dest, const ScriptStencil& src,
   5793                               GCThingIndexMapFunc mapGCThingIndex,
   5794                               AtomIndexMapFunc mapAtomIndex,
   5795                               ScopeIndexMapFunc mapScopeIndex,
   5796                               bool isTopLevel) {
   5797  // If this function was lazy, all inner functions should have been lazy.
   5798  MOZ_ASSERT(!dest.hasSharedData());
   5799 
   5800  // If the inner lazy function is skipped, gcThingsLength is empty.
   5801  if (src.gcThingsLength) {
   5802    dest.gcThingsOffset = mapGCThingIndex(src.gcThingsOffset);
   5803    dest.gcThingsLength = src.gcThingsLength;
   5804  }
   5805 
   5806  if (src.functionAtom) {
   5807    dest.functionAtom = mapAtomIndex(src.functionAtom);
   5808  }
   5809 
   5810  if (!dest.hasLazyFunctionEnclosingScopeIndex() &&
   5811      src.hasLazyFunctionEnclosingScopeIndex()) {
   5812    // Both enclosing function and this function were lazy, and
   5813    // now enclosing function is non-lazy and this function is still lazy.
   5814    dest.setLazyFunctionEnclosingScopeIndex(
   5815        mapScopeIndex(src.lazyFunctionEnclosingScopeIndex()));
   5816  } else if (dest.hasLazyFunctionEnclosingScopeIndex() &&
   5817             !src.hasLazyFunctionEnclosingScopeIndex()) {
   5818    // The enclosing function was non-lazy and this function was lazy, and
   5819    // now this function is non-lazy.
   5820    dest.resetHasLazyFunctionEnclosingScopeIndexAfterStencilMerge();
   5821  } else {
   5822    // The enclosing function is still lazy.
   5823    MOZ_ASSERT(!dest.hasLazyFunctionEnclosingScopeIndex());
   5824    MOZ_ASSERT(!src.hasLazyFunctionEnclosingScopeIndex());
   5825  }
   5826 
   5827 #ifdef DEBUG
   5828  uint16_t BASESCRIPT = uint16_t(FunctionFlags::Flags::BASESCRIPT);
   5829  uint16_t HAS_INFERRED_NAME =
   5830      uint16_t(FunctionFlags::Flags::HAS_INFERRED_NAME);
   5831  uint16_t HAS_GUESSED_ATOM = uint16_t(FunctionFlags::Flags::HAS_GUESSED_ATOM);
   5832  uint16_t acceptableDifferenceForLazy = HAS_INFERRED_NAME | HAS_GUESSED_ATOM;
   5833  uint16_t acceptableDifferenceForNonLazy =
   5834      BASESCRIPT | HAS_INFERRED_NAME | HAS_GUESSED_ATOM;
   5835 
   5836  MOZ_ASSERT_IF(
   5837      isTopLevel,
   5838      (dest.functionFlags.toRaw() | acceptableDifferenceForNonLazy) ==
   5839          (src.functionFlags.toRaw() | acceptableDifferenceForNonLazy));
   5840 
   5841  // NOTE: Currently we don't delazify inner functions.
   5842  MOZ_ASSERT_IF(!isTopLevel,
   5843                (dest.functionFlags.toRaw() | acceptableDifferenceForLazy) ==
   5844                    (src.functionFlags.toRaw() | acceptableDifferenceForLazy));
   5845 #endif  // DEBUG
   5846  dest.functionFlags = src.functionFlags;
   5847 
   5848  // Other flags.
   5849 
   5850  if (src.wasEmittedByEnclosingScript()) {
   5851    // NOTE: the top-level function of the delazification have
   5852    //       src.wasEmittedByEnclosingScript() == false, and that shouldn't
   5853    //       be copied.
   5854    dest.setWasEmittedByEnclosingScript();
   5855  }
   5856 
   5857  if (src.allowRelazify()) {
   5858    dest.setAllowRelazify();
   5859  }
   5860 
   5861  if (src.hasSharedData()) {
   5862    dest.setHasSharedData();
   5863  }
   5864 }
   5865 
   5866 bool CompilationStencilMerger::addDelazification(
   5867    FrontendContext* fc, const CompilationStencil& delazification) {
   5868  MOZ_ASSERT(initial_);
   5869 
   5870  auto delazifiedFunctionIndex = getInitialScriptIndexFor(delazification);
   5871  auto& destFun = initial_->scriptData[delazifiedFunctionIndex];
   5872 
   5873  if (destFun.hasSharedData()) {
   5874    // If the function was already non-lazy, it means the following happened:
   5875    //   A. delazified twice within single collecting delazifications
   5876    //     1. this function is lazily parsed
   5877    //     2. collecting delazifications is started
   5878    //     3. this function is delazified, encoded, and merged
   5879    //     4. this function is relazified
   5880    //     5. this function is delazified, encoded, and merged
   5881    //
   5882    //   B. delazified twice across decode
   5883    //     1. this function is lazily parsed
   5884    //     2. collecting delazifications is started
   5885    //     3. this function is delazified, encoded, and merged
   5886    //     4. collecting delazifications is finished
   5887    //     5. decoded
   5888    //     6. collecting delazifications is started
   5889    //        here, this function is non-lazy
   5890    //     7. this function is relazified
   5891    //     8. this function is delazified, encoded, and merged
   5892    //
   5893    // A can happen with public API.
   5894    //
   5895    // B cannot happen with public API, but can happen if incremental
   5896    // encoding at step B.6 is explicitly started by internal function.
   5897    // See Evaluate and StartCollectingDelazifications in js/src/shell/js.cpp.
   5898    return true;
   5899  }
   5900 
   5901  // If any failure happens, the initial stencil is left in the broken state.
   5902  // Immediately discard it.
   5903  auto failureCase = mozilla::MakeScopeExit([&] { initial_.reset(); });
   5904 
   5905  mozilla::Maybe<ScopeIndex> functionEnclosingScope;
   5906  if (destFun.hasLazyFunctionEnclosingScopeIndex()) {
   5907    // lazyFunctionEnclosingScopeIndex_ can be Nothing if this is
   5908    // top-level function.
   5909    functionEnclosingScope =
   5910        mozilla::Some(destFun.lazyFunctionEnclosingScopeIndex());
   5911  }
   5912 
   5913  // A map from ParserAtomIndex in delazification to TaggedParserAtomIndex
   5914  // in initial_.
   5915  AtomIndexMap atomIndexMap;
   5916  if (!buildAtomIndexMap(fc, delazification, atomIndexMap)) {
   5917    return false;
   5918  }
   5919  auto mapAtomIndex = [&](TaggedParserAtomIndex index) {
   5920    if (index.isParserAtomIndex()) {
   5921      return atomIndexMap[index.toParserAtomIndex()];
   5922    }
   5923 
   5924    return index;
   5925  };
   5926 
   5927  size_t gcThingOffset = initial_->gcThingData.length();
   5928  size_t regExpOffset = initial_->regExpData.length();
   5929  size_t bigIntOffset = initial_->bigIntData.length();
   5930  size_t objLiteralOffset = initial_->objLiteralData.length();
   5931  size_t scopeOffset = initial_->scopeData.length();
   5932 
   5933  // Map delazification's ScriptIndex to initial's ScriptIndex.
   5934  //
   5935  // The lazy function's gcthings list stores inner function's ScriptIndex.
   5936  // The n-th gcthing holds the ScriptIndex of the (n+1)-th script in
   5937  // delazification.
   5938  //
   5939  // NOTE: Currently we don't delazify inner functions.
   5940  auto lazyFunctionGCThingsOffset = destFun.gcThingsOffset;
   5941  auto mapScriptIndex = [&](ScriptIndex index) {
   5942    if (index == CompilationStencil::TopLevelIndex) {
   5943      return delazifiedFunctionIndex;
   5944    }
   5945 
   5946    return initial_->gcThingData[lazyFunctionGCThingsOffset + index.index - 1]
   5947        .toFunction();
   5948  };
   5949 
   5950  // Map other delazification's indices into initial's indices.
   5951  auto mapGCThingIndex = [&](CompilationGCThingIndex offset) {
   5952    return CompilationGCThingIndex(gcThingOffset + offset.index);
   5953  };
   5954  auto mapRegExpIndex = [&](RegExpIndex index) {
   5955    return RegExpIndex(regExpOffset + index.index);
   5956  };
   5957  auto mapBigIntIndex = [&](BigIntIndex index) {
   5958    return BigIntIndex(bigIntOffset + index.index);
   5959  };
   5960  auto mapObjLiteralIndex = [&](ObjLiteralIndex index) {
   5961    return ObjLiteralIndex(objLiteralOffset + index.index);
   5962  };
   5963  auto mapScopeIndex = [&](ScopeIndex index) {
   5964    return ScopeIndex(scopeOffset + index.index);
   5965  };
   5966 
   5967  // Append gcThingData, with mapping TaggedScriptThingIndex.
   5968  if (!initial_->gcThingData.append(delazification.gcThingData.data(),
   5969                                    delazification.gcThingData.size())) {
   5970    js::ReportOutOfMemory(fc);
   5971    return false;
   5972  }
   5973  for (size_t i = gcThingOffset; i < initial_->gcThingData.length(); i++) {
   5974    auto& index = initial_->gcThingData[i];
   5975    if (index.isNull()) {
   5976      // Nothing to do.
   5977    } else if (index.isAtom()) {
   5978      index = TaggedScriptThingIndex(mapAtomIndex(index.toAtom()));
   5979    } else if (index.isBigInt()) {
   5980      index = TaggedScriptThingIndex(mapBigIntIndex(index.toBigInt()));
   5981    } else if (index.isObjLiteral()) {
   5982      index = TaggedScriptThingIndex(mapObjLiteralIndex(index.toObjLiteral()));
   5983    } else if (index.isRegExp()) {
   5984      index = TaggedScriptThingIndex(mapRegExpIndex(index.toRegExp()));
   5985    } else if (index.isScope()) {
   5986      index = TaggedScriptThingIndex(mapScopeIndex(index.toScope()));
   5987    } else if (index.isFunction()) {
   5988      index = TaggedScriptThingIndex(mapScriptIndex(index.toFunction()));
   5989    } else {
   5990      MOZ_ASSERT(index.isEmptyGlobalScope());
   5991      // Nothing to do
   5992    }
   5993  }
   5994 
   5995  // Append regExpData, with mapping RegExpStencil.atom_.
   5996  if (!initial_->regExpData.append(delazification.regExpData.data(),
   5997                                   delazification.regExpData.size())) {
   5998    js::ReportOutOfMemory(fc);
   5999    return false;
   6000  }
   6001  for (size_t i = regExpOffset; i < initial_->regExpData.length(); i++) {
   6002    auto& data = initial_->regExpData[i];
   6003    data.atom_ = mapAtomIndex(data.atom_);
   6004  }
   6005 
   6006  // Append bigIntData, with copying BigIntStencil.bigInt_.
   6007  if (!initial_->bigIntData.reserve(bigIntOffset +
   6008                                    delazification.bigIntData.size())) {
   6009    js::ReportOutOfMemory(fc);
   6010    return false;
   6011  }
   6012  for (const auto& data : delazification.bigIntData) {
   6013    initial_->bigIntData.infallibleEmplaceBack();
   6014    if (!initial_->bigIntData.back().init(fc, initial_->alloc, data)) {
   6015      return false;
   6016    }
   6017  }
   6018 
   6019  // Append objLiteralData, with copying ObjLiteralStencil.code_, and mapping
   6020  // TaggedParserAtomIndex in it.
   6021  if (!initial_->objLiteralData.reserve(objLiteralOffset +
   6022                                        delazification.objLiteralData.size())) {
   6023    js::ReportOutOfMemory(fc);
   6024    return false;
   6025  }
   6026  for (const auto& data : delazification.objLiteralData) {
   6027    size_t length = data.code().size();
   6028    auto* code = initial_->alloc.newArrayUninitialized<uint8_t>(length);
   6029    if (!code) {
   6030      js::ReportOutOfMemory(fc);
   6031      return false;
   6032    }
   6033    memcpy(code, data.code().data(), length);
   6034 
   6035    ObjLiteralModifier modifier(mozilla::Span(code, length));
   6036    modifier.mapAtom(mapAtomIndex);
   6037 
   6038    initial_->objLiteralData.infallibleEmplaceBack(
   6039        code, length, data.kind(), data.flags(), data.propertyCount());
   6040  }
   6041 
   6042  // Append scopeData, with mapping indices in ScopeStencil fields.
   6043  // And append scopeNames, with copying the entire data, and mapping
   6044  // trailingNames.
   6045  if (!initial_->scopeData.reserve(scopeOffset +
   6046                                   delazification.scopeData.size())) {
   6047    js::ReportOutOfMemory(fc);
   6048    return false;
   6049  }
   6050  if (!initial_->scopeNames.reserve(scopeOffset +
   6051                                    delazification.scopeNames.size())) {
   6052    js::ReportOutOfMemory(fc);
   6053    return false;
   6054  }
   6055  for (size_t i = 0; i < delazification.scopeData.size(); i++) {
   6056    const auto& srcData = delazification.scopeData[i];
   6057    const auto* srcNames = delazification.scopeNames[i];
   6058 
   6059    mozilla::Maybe<ScriptIndex> functionIndex = mozilla::Nothing();
   6060    if (srcData.isFunction()) {
   6061      // Inner functions should be in the same order as initial, beginning from
   6062      // the delazification's index.
   6063      functionIndex = mozilla::Some(mapScriptIndex(srcData.functionIndex()));
   6064    }
   6065 
   6066    BaseParserScopeData* destNames = nullptr;
   6067    if (srcNames) {
   6068      destNames = CopyScopeData(fc, initial_->alloc, srcData.kind(), srcNames);
   6069      if (!destNames) {
   6070        return false;
   6071      }
   6072      auto trailingNames =
   6073          GetParserScopeDataTrailingNames(srcData.kind(), destNames);
   6074      for (auto& name : trailingNames) {
   6075        if (name.name()) {
   6076          name.updateNameAfterStencilMerge(mapAtomIndex(name.name()));
   6077        }
   6078      }
   6079    }
   6080 
   6081    initial_->scopeData.infallibleEmplaceBack(
   6082        srcData.kind(),
   6083        srcData.hasEnclosing()
   6084            ? mozilla::Some(mapScopeIndex(srcData.enclosing()))
   6085            : functionEnclosingScope,
   6086        srcData.firstFrameSlot(),
   6087        srcData.hasEnvironmentShape()
   6088            ? mozilla::Some(srcData.numEnvironmentSlots())
   6089            : mozilla::Nothing(),
   6090        functionIndex, srcData.isArrow());
   6091 
   6092    initial_->scopeNames.infallibleEmplaceBack(destNames);
   6093  }
   6094 
   6095  // Add delazified function's shared data.
   6096  //
   6097  // NOTE: Currently we don't delazify inner functions.
   6098  if (!initial_->sharedData.addExtraWithoutShare(
   6099          fc, delazifiedFunctionIndex,
   6100          delazification.sharedData.get(CompilationStencil::TopLevelIndex))) {
   6101    return false;
   6102  }
   6103 
   6104  // Update scriptData, with mapping indices in ScriptStencil fields.
   6105  for (uint32_t i = 0; i < delazification.scriptData.size(); i++) {
   6106    auto destIndex = mapScriptIndex(ScriptIndex(i));
   6107    MergeScriptStencil(initial_->scriptData[destIndex],
   6108                       delazification.scriptData[i], mapGCThingIndex,
   6109                       mapAtomIndex, mapScopeIndex,
   6110                       i == CompilationStencil::TopLevelIndex);
   6111  }
   6112 
   6113  // WARNING: moduleMetadata and asmJS fields are known at script/module
   6114  // top-level parsing, any mutation made in this function should be reflected
   6115  // to ExtensibleCompilationStencil::steal and CompilationStencil::clone.
   6116 
   6117  // Function shouldn't be a module.
   6118  MOZ_ASSERT(!delazification.moduleMetadata);
   6119 
   6120  // asm.js shouldn't appear inside delazification, given asm.js forces
   6121  // full-parse.
   6122  MOZ_ASSERT(!delazification.hasAsmJS());
   6123 
   6124  failureCase.release();
   6125  return true;
   6126 }
   6127 
   6128 bool CompilationStencilMerger::maybeAddDelazification(
   6129    FrontendContext* fc, const CompilationStencil& delazification) {
   6130  auto delazifiedFunctionIndex = getInitialScriptIndexFor(delazification);
   6131  auto& destFun = initial_->scriptData[delazifiedFunctionIndex];
   6132 
   6133  if (!destFun.hasLazyFunctionEnclosingScopeIndex()) {
   6134    // The enclosing function is still lazy, and this inner function cannot
   6135    // be added.
   6136    return true;
   6137  }
   6138 
   6139  return addDelazification(fc, delazification);
   6140 }
   6141 
   6142 void CompilationStencil::AddRef() { refCount_++; }
   6143 void CompilationStencil::Release() {
   6144  MOZ_RELEASE_ASSERT(refCount_ > 0);
   6145  if (--refCount_ == 0) {
   6146    js_delete(this);
   6147  }
   6148 }
   6149 
   6150 void JS::StencilAddRef(JS::Stencil* stencil) { stencil->AddRef(); }
   6151 void JS::StencilRelease(JS::Stencil* stencil) { stencil->Release(); }
   6152 
   6153 JS_PUBLIC_API JSScript* JS::InstantiateGlobalStencil(
   6154    JSContext* cx, const JS::InstantiateOptions& options, JS::Stencil* stencil,
   6155    JS::InstantiationStorage* storage) {
   6156  MOZ_ASSERT_IF(storage, storage->isValid());
   6157 
   6158  CompileOptions compileOptions(cx);
   6159  options.copyTo(compileOptions);
   6160  Rooted<CompilationInput> input(cx, CompilationInput(compileOptions));
   6161  Rooted<CompilationGCOutput> gcOutput(cx);
   6162  if (storage) {
   6163    gcOutput.get().steal(std::move(*storage->gcOutput_));
   6164  }
   6165 
   6166  if (!InstantiateStencils(cx, input.get(), *stencil, gcOutput.get())) {
   6167    return nullptr;
   6168  }
   6169  return gcOutput.get().script;
   6170 }
   6171 
   6172 JS_PUBLIC_API bool JS::StencilIsBorrowed(JS::Stencil* stencil) {
   6173  return stencil->getInitial()->storageType ==
   6174         CompilationStencil::StorageType::Borrowed;
   6175 }
   6176 
   6177 JS_PUBLIC_API JSObject* JS::InstantiateModuleStencil(
   6178    JSContext* cx, const JS::InstantiateOptions& options, JS::Stencil* stencil,
   6179    JS::InstantiationStorage* storage) {
   6180  MOZ_ASSERT_IF(storage, storage->isValid());
   6181 
   6182  CompileOptions compileOptions(cx);
   6183  options.copyTo(compileOptions);
   6184  compileOptions.setModule();
   6185  Rooted<CompilationInput> input(cx, CompilationInput(compileOptions));
   6186  Rooted<CompilationGCOutput> gcOutput(cx);
   6187  if (storage) {
   6188    gcOutput.get().steal(std::move(*storage->gcOutput_));
   6189  }
   6190 
   6191  if (!InstantiateStencils(cx, input.get(), *stencil, gcOutput.get())) {
   6192    return nullptr;
   6193  }
   6194  return gcOutput.get().module;
   6195 }
   6196 
   6197 JS_PUBLIC_API size_t JS::SizeOfStencil(Stencil* stencil,
   6198                                       mozilla::MallocSizeOf mallocSizeOf) {
   6199  return stencil->sizeOfIncludingThis(mallocSizeOf);
   6200 }
   6201 
   6202 JS::InstantiationStorage::~InstantiationStorage() {
   6203  if (gcOutput_) {
   6204    js_delete(gcOutput_);
   6205    gcOutput_ = nullptr;
   6206  }
   6207 }
   6208 
   6209 bool JS::IsStencilCacheable(JS::Stencil* stencil) {
   6210  if (stencil->hasAsmJS()) {
   6211    return false;
   6212  }
   6213 
   6214  return true;
   6215 }
   6216 
   6217 JS_PUBLIC_API size_t JS::GetScriptSourceLength(JS::Stencil* stencil) {
   6218  const ScriptSource* source = stencil->getInitial()->source;
   6219  if (!source->hasSourceText()) {
   6220    return 0;
   6221  }
   6222  return source->length();
   6223 }