Backed out 11 changesets (bug 1669790, bug 1669814, bug 1669851, bug 1670109) for SM Bustages on testDeduplication.cpp. CLOSED TREE
authorRazvan Maries <rmaries@mozilla.com>
Mon, 12 Oct 2020 10:39:14 +0300
changeset 618454 ba389884ca470e850567e236aad73d6b6dff8061
parent 618453 79707fcdaa2d026678b1e9f0f19ef27a1d3a9002
child 618455 786694e7b8053fa2c27134409c3ee075bf6fde4f
push id14302
push userffxbld-merge
push dateMon, 19 Oct 2020 16:06:48 +0000
treeherdermozilla-beta@13d947f127a7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1669790, 1669814, 1669851, 1670109
milestone83.0a1
backs out3884042fe3a8da12ece4d92b3d014b6e50ec0887
72821bddce2f3fe3dd2372e58ccd1530a5c1fc59
b1f373fe74c9f7167975bf31ebeaa2d93ae894da
90474951867be81e2b5ba4a8a808fdfc30b45be7
ef1eb570bdfdb12ee45103725824e4bcbc779533
7714b8069e44afe00acc6673a6f2e8a053ccb9cd
7e8fd3c2234766026f57a8fa0e32df7472fe7a93
15c9ef0258da5d05a4550d846282742ec6fad21a
0fc17964540435aff1a9c5f5f7192b1dc9a8d16e
a3ea444d23326a3aef3f0102b0392aea5acafcaf
735e4f5d61e4bda6b61d6bd24f5030f561be0cc9
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 11 changesets (bug 1669790, bug 1669814, bug 1669851, bug 1670109) for SM Bustages on testDeduplication.cpp. CLOSED TREE Backed out changeset 3884042fe3a8 (bug 1670109) Backed out changeset 72821bddce2f (bug 1670109) Backed out changeset b1f373fe74c9 (bug 1670109) Backed out changeset 90474951867b (bug 1670109) Backed out changeset ef1eb570bdfd (bug 1670109) Backed out changeset 7714b8069e44 (bug 1669851) Backed out changeset 7e8fd3c22347 (bug 1669851) Backed out changeset 15c9ef0258da (bug 1669851) Backed out changeset 0fc179645404 (bug 1669814) Backed out changeset a3ea444d2332 (bug 1669790) Backed out changeset 735e4f5d61e4 (bug 1669790)
js/src/builtin/ModuleObject.cpp
js/src/frontend/AbstractScopePtr.cpp
js/src/frontend/AbstractScopePtr.h
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeSection.cpp
js/src/frontend/CompilationInfo.h
js/src/frontend/EmitterScope.cpp
js/src/frontend/FoldConstants.cpp
js/src/frontend/FoldConstants.h
js/src/frontend/NameFunctions.cpp
js/src/frontend/NameFunctions.h
js/src/frontend/ObjLiteral.cpp
js/src/frontend/ObjLiteral.h
js/src/frontend/ParseContext.cpp
js/src/frontend/ParseNode.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/ParserAtom.cpp
js/src/frontend/ParserAtom.h
js/src/frontend/SharedContext-inl.h
js/src/frontend/Stencil.cpp
js/src/frontend/Stencil.h
js/src/frontend/TokenStream.cpp
js/src/frontend/TokenStream.h
js/src/jsnum.cpp
js/src/jsnum.h
js/src/util/StringBuffer.cpp
js/src/util/StringBuffer.h
js/src/vm/Instrumentation.cpp
js/src/vm/Instrumentation.h
js/src/vm/Scope.cpp
js/src/vm/Scope.h
js/src/wasm/AsmJS.cpp
js/src/wasm/AsmJS.h
--- a/js/src/builtin/ModuleObject.cpp
+++ b/js/src/builtin/ModuleObject.cpp
@@ -1276,17 +1276,17 @@ void ModuleBuilder::finishFunctionDecls(
 
 enum class ModuleArrayType {
   ImportEntryObject,
   ExportEntryObject,
   RequestedModuleObject,
 };
 
 static ArrayObject* ModuleBuilderInitArray(
-    JSContext* cx, frontend::CompilationAtomCache& atomCache,
+    JSContext* cx, frontend::CompilationInfo& compilationInfo,
     ModuleArrayType arrayType,
     const frontend::StencilModuleMetadata::EntryVector& vector) {
   RootedArrayObject resultArray(
       cx, NewDenseFullyAllocatedArray(cx, vector.length()));
   if (!resultArray) {
     return nullptr;
   }
 
@@ -1297,38 +1297,38 @@ static ArrayObject* ModuleBuilderInitArr
   RootedAtom importName(cx);
   RootedAtom exportName(cx);
   RootedObject req(cx);
 
   for (uint32_t i = 0; i < vector.length(); ++i) {
     const frontend::StencilModuleEntry& entry = vector[i];
 
     if (entry.specifier) {
-      specifier = entry.specifier->toJSAtom(cx, atomCache);
+      specifier = compilationInfo.liftParserAtomToJSAtom(cx, entry.specifier);
       if (!specifier) {
         return nullptr;
       }
     }
 
     if (entry.localName) {
-      localName = entry.localName->toJSAtom(cx, atomCache);
+      localName = compilationInfo.liftParserAtomToJSAtom(cx, entry.localName);
       if (!localName) {
         return nullptr;
       }
     }
 
     if (entry.importName) {
-      importName = entry.importName->toJSAtom(cx, atomCache);
+      importName = compilationInfo.liftParserAtomToJSAtom(cx, entry.importName);
       if (!importName) {
         return nullptr;
       }
     }
 
     if (entry.exportName) {
-      exportName = entry.exportName->toJSAtom(cx, atomCache);
+      exportName = compilationInfo.liftParserAtomToJSAtom(cx, entry.exportName);
       if (!exportName) {
         return nullptr;
       }
     }
 
     switch (arrayType) {
       case ModuleArrayType::ImportEntryObject:
         MOZ_ASSERT(localName && importName);
@@ -1355,54 +1355,54 @@ static ArrayObject* ModuleBuilderInitArr
     resultArray->initDenseElement(i, ObjectValue(*req));
   }
 
   return resultArray;
 }
 
 // Use StencilModuleMetadata data to fill in ModuleObject
 bool frontend::StencilModuleMetadata::initModule(
-    JSContext* cx, frontend::CompilationAtomCache& atomCache,
+    JSContext* cx, frontend::CompilationInfo& compilationInfo,
     JS::Handle<ModuleObject*> module) const {
   RootedArrayObject requestedModulesObject(
-      cx, ModuleBuilderInitArray(cx, atomCache,
+      cx, ModuleBuilderInitArray(cx, compilationInfo,
                                  ModuleArrayType::RequestedModuleObject,
                                  requestedModules));
   if (!requestedModulesObject) {
     return false;
   }
 
   RootedArrayObject importEntriesObject(
-      cx,
-      ModuleBuilderInitArray(cx, atomCache, ModuleArrayType::ImportEntryObject,
-                             importEntries));
+      cx, ModuleBuilderInitArray(cx, compilationInfo,
+                                 ModuleArrayType::ImportEntryObject,
+                                 importEntries));
   if (!importEntriesObject) {
     return false;
   }
 
   RootedArrayObject localExportEntriesObject(
-      cx,
-      ModuleBuilderInitArray(cx, atomCache, ModuleArrayType::ExportEntryObject,
-                             localExportEntries));
+      cx, ModuleBuilderInitArray(cx, compilationInfo,
+                                 ModuleArrayType::ExportEntryObject,
+                                 localExportEntries));
   if (!localExportEntriesObject) {
     return false;
   }
 
   RootedArrayObject indirectExportEntriesObject(
-      cx,
-      ModuleBuilderInitArray(cx, atomCache, ModuleArrayType::ExportEntryObject,
-                             indirectExportEntries));
+      cx, ModuleBuilderInitArray(cx, compilationInfo,
+                                 ModuleArrayType::ExportEntryObject,
+                                 indirectExportEntries));
   if (!indirectExportEntriesObject) {
     return false;
   }
 
   RootedArrayObject starExportEntriesObject(
-      cx,
-      ModuleBuilderInitArray(cx, atomCache, ModuleArrayType::ExportEntryObject,
-                             starExportEntries));
+      cx, ModuleBuilderInitArray(cx, compilationInfo,
+                                 ModuleArrayType::ExportEntryObject,
+                                 starExportEntries));
   if (!starExportEntriesObject) {
     return false;
   }
 
   // Copy the vector of declarations to the ModuleObject.
   FunctionDeclarationVector functionDeclsCopy;
   if (!functionDeclsCopy.appendAll(functionDecls)) {
     js::ReportOutOfMemory(cx);
--- a/js/src/frontend/AbstractScopePtr.cpp
+++ b/js/src/frontend/AbstractScopePtr.cpp
@@ -21,16 +21,26 @@ ScopeStencil& AbstractScopePtr::scopeDat
   return data.compilationInfo.stencil.scopeData[data.index.index];
 }
 
 CompilationInfo& AbstractScopePtr::compilationInfo() const {
   const Deferred& data = scope_.as<Deferred>();
   return data.compilationInfo;
 }
 
+Scope* AbstractScopePtr::existingScope(CompilationGCOutput& gcOutput) const {
+  if (isScopeStencil()) {
+    const Deferred& data = scope_.as<Deferred>();
+    Scope* result = gcOutput.scopes[data.index.index];
+    MOZ_ASSERT(result, "Scope must already exist to use this method");
+    return result;
+  }
+  return scope();
+}
+
 ScopeKind AbstractScopePtr::kind() const {
   MOZ_ASSERT(!isNullptr());
   if (isScopeStencil()) {
     return scopeData().kind();
   }
   return scope()->kind();
 }
 
--- a/js/src/frontend/AbstractScopePtr.h
+++ b/js/src/frontend/AbstractScopePtr.h
@@ -83,16 +83,20 @@ class AbstractScopePtr {
   explicit operator bool() const { return !isNullptr(); }
 
   bool isScopeStencil() const { return scope_.is<Deferred>(); }
 
   // Note: this handle is rooted in the CompilationInfo.
   frontend::ScopeStencil& scopeData() const;
   frontend::CompilationInfo& compilationInfo() const;
 
+  // Concrete GC scope. If a deferred scope, the target must already have been
+  // converted to a GC scope.
+  Scope* existingScope(frontend::CompilationGCOutput& gcOutput) const;
+
   // This allows us to check whether or not this provider wraps
   // or otherwise would reify to a particular scope type.
   template <typename T>
   bool is() const {
     static_assert(std::is_base_of_v<Scope, T>,
                   "Trying to ask about non-Scope type");
     if (isNullptr()) {
       return false;
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -1170,22 +1170,20 @@ bool frontend::CompilationInput::initScr
     return false;
   }
   setSource(ss);
 
   return ss->initFromOptions(cx, options);
 }
 
 void CompilationInput::trace(JSTracer* trc) {
-  atomCache.trace(trc);
+  atoms.trace(trc);
   TraceNullableRoot(trc, &lazy, "compilation-input-lazy");
   source_.trace(trc);
   TraceNullableRoot(trc, &enclosingScope, "compilation-input-enclosing-scope");
 }
 
-void CompilationAtomCache::trace(JSTracer* trc) { atoms.trace(trc); }
-
 void CompilationInfo::trace(JSTracer* trc) { input.trace(trc); }
 
 void CompilationInfoVector::trace(JSTracer* trc) {
   initial.trace(trc);
   delazifications.trace(trc);
 }
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2475,17 +2475,17 @@ bool BytecodeEmitter::emitScript(ParseNo
   if (!emitReturnRval()) {
     return false;
   }
 
   if (!emitterScope.leave(this)) {
     return false;
   }
 
-  if (!NameFunctions(cx, compilationInfo.stencil.parserAtoms, body)) {
+  if (!NameFunctions(cx, compilationInfo, body)) {
     return false;
   }
 
   // Create a Stencil and convert it into a JSScript.
   return intoScriptStencil(
       &compilationInfo.stencil.scriptData[CompilationInfo::TopLevelIndex]);
 }
 
@@ -2555,17 +2555,17 @@ bool BytecodeEmitter::emitFunctionScript
   }
 
   if (!fse.emitEndBody()) {
     //              [stack]
     return false;
   }
 
   if (isTopLevel == TopLevelFunction::Yes) {
-    if (!NameFunctions(cx, compilationInfo.stencil.parserAtoms, funNode)) {
+    if (!NameFunctions(cx, compilationInfo, funNode)) {
       return false;
     }
   }
 
   return fse.intoStencil();
 }
 
 bool BytecodeEmitter::emitDestructuringLHSRef(ParseNode* target,
@@ -8647,18 +8647,18 @@ bool BytecodeEmitter::emitPropertyList(L
 
     auto emitValue = [this, &key, &propVal, accessorType, &pe]() {
       //            [stack] CTOR? OBJ CTOR? KEY?
 
       if (propVal->isDirectRHSAnonFunction()) {
         if (key->isKind(ParseNodeKind::NumberExpr)) {
           MOZ_ASSERT(accessorType == AccessorType::None);
 
-          const ParserAtom* keyAtom = key->as<NumericLiteral>().toAtom(
-              cx, compilationInfo.stencil.parserAtoms);
+          const ParserAtom* keyAtom =
+              key->as<NumericLiteral>().toAtom(cx, compilationInfo);
           if (!keyAtom) {
             return false;
           }
           if (!emitAnonymousFunctionWithName(propVal, keyAtom)) {
             //      [stack] CTOR? OBJ CTOR? KEY VAL
             return false;
           }
         } else if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
@@ -9258,17 +9258,17 @@ bool BytecodeEmitter::emitPrivateMethodI
         if (!storedMethodName.append(".setter")) {
           return false;
         }
         break;
       default:
         MOZ_CRASH("Invalid private method accessor type");
     }
     const ParserAtom* storedMethodAtom =
-        storedMethodName.finishParserAtom(compilationInfo.stencil.parserAtoms);
+        storedMethodName.finishParserAtom(compilationInfo);
 
     // Emit the private method body and store it as a lexical var.
     if (!emitFunction(&propdef->as<ClassMethod>().method())) {
       //              [stack] HOMEOBJ HERITAGE? ARRAY METHOD
       // or:
       //              [stack] CTOR HOMEOBJ ARRAY METHOD
       return false;
     }
@@ -10477,17 +10477,17 @@ MOZ_NEVER_INLINE bool BytecodeEmitter::e
 
   // Push undefined for the call's |this| value.
   if (!emit1(JSOp::Undefined)) {
     return false;
   }
   //            [stack] CALLBACK UNDEFINED
 
   const ParserAtom* atom = RealmInstrumentation::getInstrumentationKindName(
-      cx, compilationInfo.stencil.parserAtoms, kind);
+      cx, compilationInfo, kind);
   if (!atom) {
     return false;
   }
 
   if (!emitAtomOp(JSOp::String, atom)) {
     return false;
   }
   //            [stack] CALLBACK UNDEFINED KIND
--- a/js/src/frontend/BytecodeSection.cpp
+++ b/js/src/frontend/BytecodeSection.cpp
@@ -58,59 +58,59 @@ bool js::frontend::EmitScriptThingsVecto
                                           CompilationGCOutput& gcOutput,
                                           const ScriptThingsVector& objects,
                                           mozilla::Span<JS::GCCellPtr> output) {
   MOZ_ASSERT(objects.length() <= INDEX_LIMIT);
   MOZ_ASSERT(objects.length() == output.size());
 
   struct Matcher {
     JSContext* cx;
-    CompilationAtomCache& atomCache;
-    CompilationStencil& stencil;
+    CompilationInfo& compilationInfo;
     CompilationGCOutput& gcOutput;
     uint32_t i;
     mozilla::Span<JS::GCCellPtr>& output;
 
     bool operator()(const ScriptAtom& data) {
-      JSAtom* atom = data->toJSAtom(cx, atomCache);
-      if (!atom) {
+      auto maybeAtom = data->toJSAtom(cx, compilationInfo);
+      if (maybeAtom.isErr()) {
         return false;
       }
-      output[i] = JS::GCCellPtr(atom);
+      MOZ_ASSERT(maybeAtom.unwrap());
+      output[i] = JS::GCCellPtr(maybeAtom.unwrap());
       return true;
     }
 
     bool operator()(const NullScriptThing& data) {
       output[i] = JS::GCCellPtr(nullptr);
       return true;
     }
 
     bool operator()(const BigIntIndex& index) {
-      BigIntStencil& data = stencil.bigIntData[index];
+      BigIntStencil& data = compilationInfo.stencil.bigIntData[index];
       BigInt* bi = data.createBigInt(cx);
       if (!bi) {
         return false;
       }
       output[i] = JS::GCCellPtr(bi);
       return true;
     }
 
     bool operator()(const RegExpIndex& rindex) {
-      RegExpStencil& data = stencil.regExpData[rindex];
+      RegExpStencil& data = compilationInfo.stencil.regExpData[rindex];
       RegExpObject* regexp = data.createRegExp(cx);
       if (!regexp) {
         return false;
       }
       output[i] = JS::GCCellPtr(regexp);
       return true;
     }
 
     bool operator()(const ObjLiteralIndex& index) {
-      ObjLiteralStencil& data = stencil.objLiteralData[index];
-      JSObject* obj = data.create(cx, atomCache);
+      ObjLiteralStencil& data = compilationInfo.stencil.objLiteralData[index];
+      JSObject* obj = data.create(cx, compilationInfo);
       if (!obj) {
         return false;
       }
       output[i] = JS::GCCellPtr(obj);
       return true;
     }
 
     bool operator()(const ScopeIndex& index) {
@@ -126,22 +126,17 @@ bool js::frontend::EmitScriptThingsVecto
     bool operator()(const EmptyGlobalScopeType& emptyGlobalScope) {
       Scope* scope = &cx->global()->emptyGlobalScope();
       output[i] = JS::GCCellPtr(scope);
       return true;
     }
   };
 
   for (uint32_t i = 0; i < objects.length(); i++) {
-    Matcher m{cx,
-              compilationInfo.input.atomCache,
-              compilationInfo.stencil,
-              gcOutput,
-              i,
-              output};
+    Matcher m{cx, compilationInfo, gcOutput, i, output};
     if (!objects[i].match(m)) {
       return false;
     }
   }
   return true;
 }
 
 bool CGTryNoteList::append(TryNoteKind kind, uint32_t stackDepth,
@@ -179,18 +174,18 @@ void CGScopeNoteList::recordEndFunctionB
 void CGScopeNoteList::recordEndImpl(uint32_t index, uint32_t offset) {
   MOZ_ASSERT(index < length());
   MOZ_ASSERT(list[index].length == 0);
   MOZ_ASSERT(offset >= list[index].start);
   list[index].length = offset - list[index].start;
 }
 
 JSObject* ObjLiteralStencil::create(JSContext* cx,
-                                    CompilationAtomCache& atomCache) const {
-  return InterpretObjLiteral(cx, atomCache, atoms_, writer_);
+                                    CompilationInfo& compilationInfo) const {
+  return InterpretObjLiteral(cx, compilationInfo, atoms_, writer_);
 }
 
 BytecodeSection::BytecodeSection(JSContext* cx, uint32_t lineNum)
     : code_(cx),
       notes_(cx),
       lastNoteOffset_(0),
       tryNoteList_(cx),
       scopeNoteList_(cx),
--- a/js/src/frontend/CompilationInfo.h
+++ b/js/src/frontend/CompilationInfo.h
@@ -86,33 +86,27 @@ struct ScopeContext {
   void computeThisBinding(Scope* scope);
   void computeInWith(Scope* scope);
   void computeExternalInitializers(Scope* scope);
   void computeInClass(Scope* scope);
 
   static Scope* determineEffectiveScope(Scope* scope, JSObject* environment);
 };
 
-struct CompilationAtomCache {
+// Input of the compilation, including source and enclosing context.
+struct CompilationInput {
+  const JS::ReadOnlyCompileOptions& options;
+
   // Atoms lowered into or converted from CompilationStencil.parserAtoms.
   //
   // This field is here instead of in CompilationGCOutput because atoms lowered
   // from JSAtom is part of input (enclosing scope bindings, lazy function name,
   // etc), and having 2 vectors in both input/output is error prone.
   JS::GCVector<JSAtom*, 0, js::SystemAllocPolicy> atoms;
 
-  void trace(JSTracer* trc);
-} JS_HAZ_GC_POINTER;
-
-// Input of the compilation, including source and enclosing context.
-struct CompilationInput {
-  const JS::ReadOnlyCompileOptions& options;
-
-  CompilationAtomCache atomCache;
-
   BaseScript* lazy = nullptr;
 
   ScriptSourceHolder source_;
 
   //  * If we're compiling standalone function, the non-null enclosing scope of
   //    the function
   //  * If we're compiling eval, the non-null enclosing scope of the `eval`.
   //  * If we're compiling module, null that means empty global scope
@@ -388,16 +382,19 @@ struct CompilationInfo {
   CompilationInfo(JSContext* cx, const JS::ReadOnlyCompileOptions& options)
       : input(options), stencil(cx->runtime()) {}
 
   MOZ_MUST_USE bool instantiateStencils(JSContext* cx,
                                         CompilationGCOutput& gcOutput);
   MOZ_MUST_USE bool serializeStencils(JSContext* cx, JS::TranscodeBuffer& buf,
                                       bool* succeededOut = nullptr);
 
+  JSAtom* liftParserAtomToJSAtom(JSContext* cx, const ParserAtom* parserAtom) {
+    return parserAtom->toJSAtom(cx, *this).unwrapOr(nullptr);
+  }
   const ParserAtom* lowerJSAtomToParserAtom(JSContext* cx, JSAtom* atom) {
     auto result = stencil.parserAtoms.internJSAtom(cx, *this, atom);
     return result.unwrapOr(nullptr);
   }
 
   // Move constructor is necessary to use Rooted.
   CompilationInfo(CompilationInfo&&) = default;
 
--- a/js/src/frontend/EmitterScope.cpp
+++ b/js/src/frontend/EmitterScope.cpp
@@ -333,18 +333,17 @@ NameLocation EmitterScope::searchAndCach
     //   able to iterate up snapshotted scope chains that use parser atoms.
     //
     //   This will be fixed when parser scopes are snapshotted, and
     //   `searchInEnclosingScope` changes to accepting a `const ParserAtom*`
     //   instead of a `JSAtom*`.
     //
     //   See bug 1660275.
     AutoEnterOOMUnsafeRegion oomUnsafe;
-    JSAtom* jsname =
-        name->toJSAtom(bce->cx, bce->compilationInfo.input.atomCache);
+    JSAtom* jsname = bce->compilationInfo.liftParserAtomToJSAtom(bce->cx, name);
     if (!jsname) {
       oomUnsafe.crash("EmitterScope::searchAndCache");
     }
 
     inCurrentScript = false;
     loc = Some(searchInEnclosingScope(
         jsname, bce->compilationInfo.input.enclosingScope, hops));
   }
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -29,17 +29,17 @@ using JS::ToInt32;
 using JS::ToUint32;
 using mozilla::IsNaN;
 using mozilla::IsNegative;
 using mozilla::NegativeInfinity;
 using mozilla::PositiveInfinity;
 
 struct FoldInfo {
   JSContext* cx;
-  ParserAtomsTable& parserAtoms;
+  CompilationInfo& compilationInfo;
   FullParseHandler* handler;
 };
 
 // Don't use ReplaceNode directly, because we want the constant folder to keep
 // the attributes isInParens and isDirectRHSAnonFunction of the old node being
 // replaced.
 inline MOZ_MUST_USE bool TryReplaceNode(ParseNode** pnp, ParseNode* pn) {
   // convenience check: can call TryReplaceNode(pnp, alloc_parsenode())
@@ -472,17 +472,17 @@ static bool FoldType(FoldInfo info, Pars
             return false;
           }
         }
         break;
 
       case ParseNodeKind::StringExpr:
         if (pn->isKind(ParseNodeKind::NumberExpr)) {
           const ParserAtom* atom =
-              pn->as<NumericLiteral>().toAtom(info.cx, info.parserAtoms);
+              pn->as<NumericLiteral>().toAtom(info.cx, info.compilationInfo);
           if (!atom) {
             return false;
           }
           if (!TryReplaceNode(
                   pnp, info.handler->newStringLiteral(atom, pn->pn_pos))) {
             return false;
           }
         }
@@ -1103,17 +1103,17 @@ static bool FoldElement(FoldInfo info, P
     }
   } else if (key->isKind(ParseNodeKind::NumberExpr)) {
     auto* numeric = &key->as<NumericLiteral>();
     double number = numeric->value();
     if (number != ToUint32(number)) {
       // Optimization 2: We have something like expr[3.14]. The number
       // isn't an array index, so it converts to a string ("3.14"),
       // enabling optimization 3 below.
-      const ParserAtom* atom = numeric->toAtom(info.cx, info.parserAtoms);
+      const ParserAtom* atom = numeric->toAtom(info.cx, info.compilationInfo);
       if (!atom) {
         return false;
       }
       name = atom->asName();
     }
   }
 
   // If we don't have a name, we can't optimize to getprop.
@@ -1238,17 +1238,17 @@ static bool FoldAdd(FoldInfo info, Parse
 
         node->unsafeDecrementCount();
       } while (*next);
 
       // Replace with concatenation if we multiple nodes.
       if (accum.length() > 1) {
         // Construct the concatenated atom.
         const ParserAtom* combination =
-            info.parserAtoms
+            info.compilationInfo.stencil.parserAtoms
                 .concatAtoms(info.cx,
                              mozilla::Range(accum.begin(), accum.length()))
                 .unwrapOr(nullptr);
         if (!combination) {
           return false;
         }
 
         // Replace |current|'s string with the entire combination.
@@ -1295,27 +1295,27 @@ static bool FoldAdd(FoldInfo info, Parse
 
   return true;
 }
 
 class FoldVisitor : public RewritingParseNodeVisitor<FoldVisitor> {
   using Base = RewritingParseNodeVisitor;
 
   JSContext* cx;
-  ParserAtomsTable& parserAtoms;
+  CompilationInfo& compilationInfo;
   FullParseHandler* handler;
 
-  FoldInfo info() const { return FoldInfo{cx, parserAtoms, handler}; }
+  FoldInfo info() const { return FoldInfo{cx, compilationInfo, handler}; }
 
  public:
-  explicit FoldVisitor(JSContext* cx, ParserAtomsTable& parserAtoms,
+  explicit FoldVisitor(JSContext* cx, CompilationInfo& compilationInfo,
                        FullParseHandler* handler)
       : RewritingParseNodeVisitor(cx),
         cx(cx),
-        parserAtoms(parserAtoms),
+        compilationInfo(compilationInfo),
         handler(handler) {}
 
   bool visitElemExpr(ParseNode*& pn) {
     return Base::visitElemExpr(pn) && FoldElement(info(), &pn);
   }
 
   bool visitTypeOfExpr(ParseNode*& pn) {
     return Base::visitTypeOfExpr(pn) && FoldTypeOfExpr(info(), &pn);
@@ -1551,24 +1551,24 @@ class FoldVisitor : public RewritingPars
         }
       }
       list->unsetHasNonConstInitializer();
     }
     return true;
   }
 };
 
-static bool Fold(JSContext* cx, ParserAtomsTable& parserAtoms,
+static bool Fold(JSContext* cx, CompilationInfo& compilationInfo,
                  FullParseHandler* handler, ParseNode** pnp) {
-  FoldVisitor visitor(cx, parserAtoms, handler);
+  FoldVisitor visitor(cx, compilationInfo, handler);
   return visitor.visit(*pnp);
 }
 static bool Fold(FoldInfo info, ParseNode** pnp) {
-  return Fold(info.cx, info.parserAtoms, info.handler, pnp);
+  return Fold(info.cx, info.compilationInfo, info.handler, pnp);
 }
 
-bool frontend::FoldConstants(JSContext* cx, ParserAtomsTable& parserAtoms,
+bool frontend::FoldConstants(JSContext* cx, CompilationInfo& compilationInfo,
                              ParseNode** pnp, FullParseHandler* handler) {
   AutoTraceLog traceLog(TraceLoggerForCurrentThread(cx),
                         TraceLogger_BytecodeFoldConstants);
 
-  return Fold(cx, parserAtoms, handler, pnp);
+  return Fold(cx, compilationInfo, handler, pnp);
 }
--- a/js/src/frontend/FoldConstants.h
+++ b/js/src/frontend/FoldConstants.h
@@ -25,26 +25,26 @@ class PerHandlerParser;
 // AST. On success, *pnp points to the root node of the new tree, which may be
 // the same node (unchanged or modified in place) or a new node.
 //
 // Usage:
 //    pn = parser->statement();
 //    if (!pn) {
 //        return false;
 //    }
-//    if (!FoldConstants(cx, parserAtoms, &pn, parser)) {
+//    if (!FoldConstants(cx, &pn, parser)) {
 //        return false;
 //    }
 extern MOZ_MUST_USE bool FoldConstants(JSContext* cx,
-                                       ParserAtomsTable& parserAtoms,
+                                       CompilationInfo& compilationInfo,
                                        ParseNode** pnp,
                                        FullParseHandler* handler);
 
 inline MOZ_MUST_USE bool FoldConstants(JSContext* cx,
-                                       ParserAtomsTable& parserAtoms,
+                                       CompilationInfo& compilationInfo,
                                        typename SyntaxParseHandler::Node* pnp,
                                        SyntaxParseHandler* handler) {
   return true;
 }
 
 } /* namespace frontend */
 } /* namespace js */
 
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -6,35 +6,35 @@
 
 #include "frontend/NameFunctions.h"
 
 #include "mozilla/MemoryChecking.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/Sprintf.h"
 
 #include "frontend/BytecodeCompiler.h"
+#include "frontend/CompilationInfo.h"
 #include "frontend/ParseNode.h"
 #include "frontend/ParseNodeVisitor.h"
-#include "frontend/ParserAtom.h"
 #include "frontend/SharedContext.h"
 #include "util/Poison.h"
 #include "util/StringBuffer.h"
 #include "vm/JSFunction.h"
 
 using namespace js;
 using namespace js::frontend;
 
 namespace {
 
 class NameResolver : public ParseNodeVisitor<NameResolver> {
   using Base = ParseNodeVisitor;
 
   static const size_t MaxParents = 100;
 
-  ParserAtomsTable& parserAtoms_;
+  CompilationInfo& compilationInfo_;
   const ParserAtom* prefix_;
 
   // Number of nodes in the parents array.
   size_t nparents_;
 
   // Stack of ParseNodes from the root to the current node.
   // Only elements 0..nparents_ are initialized.
   MOZ_INIT_OUTSIDE_CTOR
@@ -235,17 +235,17 @@ class NameResolver : public ParseNodeVis
       if (!prefix_) {
         *retId = funbox->displayAtom();
         return true;
       }
       if (!buf_.append(prefix_) || !buf_.append('/') ||
           !buf_.append(funbox->displayAtom())) {
         return false;
       }
-      *retId = buf_.finishParserAtom(parserAtoms_);
+      *retId = buf_.finishParserAtom(compilationInfo_);
       return !!*retId;
     }
 
     // If a prefix is specified, then it is a form of namespace.
     if (prefix_) {
       if (!buf_.append(prefix_) || !buf_.append('/')) {
         return false;
       }
@@ -310,17 +310,17 @@ class NameResolver : public ParseNodeVis
         !buf_.append('<')) {
       return false;
     }
 
     if (buf_.empty()) {
       return true;
     }
 
-    *retId = buf_.finishParserAtom(parserAtoms_);
+    *retId = buf_.finishParserAtom(compilationInfo_);
     if (!*retId) {
       return false;
     }
 
     // Skip assigning the guessed name if the function has a (dynamically)
     // computed inferred name.
     if (!funNode->isDirectRHSAnonFunction()) {
       funbox->setGuessedAtom(*retId);
@@ -435,19 +435,19 @@ class NameResolver : public ParseNodeVis
   MOZ_MUST_USE bool visitImportSpecList(ListNode* pn) {
     return internalVisitSpecList(pn);
   }
 
   MOZ_MUST_USE bool visitExportSpecList(ListNode* pn) {
     return internalVisitSpecList(pn);
   }
 
-  explicit NameResolver(JSContext* cx, ParserAtomsTable& parserAtoms)
+  explicit NameResolver(JSContext* cx, CompilationInfo& compilationInfo)
       : ParseNodeVisitor(cx),
-        parserAtoms_(parserAtoms),
+        compilationInfo_(compilationInfo),
         prefix_(nullptr),
         nparents_(0),
         buf_(cx) {}
 
   /*
    * Resolve names for all anonymous functions in the given ParseNode tree.
    */
   MOZ_MUST_USE bool visit(ParseNode* pn) {
@@ -471,15 +471,15 @@ class NameResolver : public ParseNodeVis
                  sizeof(parents_[initialParents]), MemCheckKind::MakeUndefined);
 
     return ok;
   }
 };
 
 } /* anonymous namespace */
 
-bool frontend::NameFunctions(JSContext* cx, ParserAtomsTable& parserAtoms,
+bool frontend::NameFunctions(JSContext* cx, CompilationInfo& compilationInfo,
                              ParseNode* pn) {
   AutoTraceLog traceLog(TraceLoggerForCurrentThread(cx),
                         TraceLogger_BytecodeNameFunctions);
-  NameResolver nr(cx, parserAtoms);
+  NameResolver nr(cx, compilationInfo);
   return nr.visit(pn);
 }
--- a/js/src/frontend/NameFunctions.h
+++ b/js/src/frontend/NameFunctions.h
@@ -10,17 +10,17 @@
 #include "mozilla/Attributes.h"
 
 #include "js/TypeDecls.h"
 
 namespace js {
 namespace frontend {
 
 class ParseNode;
-class ParserAtomsTable;
+struct CompilationInfo;
 
-MOZ_MUST_USE bool NameFunctions(JSContext* cx, ParserAtomsTable& parserAtoms,
+MOZ_MUST_USE bool NameFunctions(JSContext* cx, CompilationInfo& compilationInfo,
                                 ParseNode* pn);
 
 } /* namespace frontend */
 } /* namespace js */
 
 #endif /* frontend_NameFunctions_h */
--- a/js/src/frontend/ObjLiteral.cpp
+++ b/js/src/frontend/ObjLiteral.cpp
@@ -4,47 +4,47 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "frontend/ObjLiteral.h"
 
 #include "mozilla/DebugOnly.h"
 
-#include "frontend/CompilationInfo.h"  // frontend::CompilationAtomCache
+#include "frontend/CompilationInfo.h"  // frontend::CompilationInfo
 #include "frontend/ParserAtom.h"  // frontend::ParserAtom, frontend::ParserAtomTable
 #include "js/RootingAPI.h"
 #include "vm/JSAtom.h"
 #include "vm/JSObject.h"
 #include "vm/JSONPrinter.h"  // js::JSONPrinter
 #include "vm/ObjectGroup.h"
 #include "vm/Printer.h"  // js::Fprinter
 
 #include "gc/ObjectKind-inl.h"
 #include "vm/JSAtom-inl.h"
 #include "vm/JSObject-inl.h"
 
 namespace js {
 
 static bool InterpretObjLiteralValue(JSContext* cx,
                                      const ObjLiteralAtomVector& atoms,
-                                     frontend::CompilationAtomCache& atomCache,
+                                     frontend::CompilationInfo& compilationInfo,
                                      const ObjLiteralInsn& insn,
                                      JS::Value* valOut) {
   switch (insn.getOp()) {
     case ObjLiteralOpcode::ConstValue:
       *valOut = insn.getConstValue();
       return true;
     case ObjLiteralOpcode::ConstAtom: {
       uint32_t index = insn.getAtomIndex();
       // TODO-Stencil
       //   This needs to be coalesced to wherever jsatom creation is eventually
       //   Seems like InterpretLiteralObj would be called from main-thread
       //   stencil instantiation.
-      JSAtom* jsatom = atoms[index]->toJSAtom(cx, atomCache);
+      JSAtom* jsatom = compilationInfo.liftParserAtomToJSAtom(cx, atoms[index]);
       if (!jsatom) {
         return false;
       }
       *valOut = StringValue(jsatom);
       return true;
     }
     case ObjLiteralOpcode::Null:
       *valOut = NullValue();
@@ -59,17 +59,17 @@ static bool InterpretObjLiteralValue(JSC
       *valOut = BooleanValue(false);
       return true;
     default:
       MOZ_CRASH("Unexpected object-literal instruction opcode");
   }
 }
 
 static JSObject* InterpretObjLiteralObj(
-    JSContext* cx, frontend::CompilationAtomCache& atomCache,
+    JSContext* cx, frontend::CompilationInfo& compilationInfo,
     const ObjLiteralAtomVector& atoms,
     const mozilla::Span<const uint8_t> literalInsns, ObjLiteralFlags flags) {
   bool specificGroup = flags.contains(ObjLiteralFlag::SpecificGroup);
   bool singleton = flags.contains(ObjLiteralFlag::Singleton);
   bool noValues = flags.contains(ObjLiteralFlag::NoValues);
 
   ObjLiteralReader reader(literalInsns);
   ObjLiteralInsn insn;
@@ -84,26 +84,27 @@ static JSObject* InterpretObjLiteralObj(
     if (insn.getKey().isArrayIndex()) {
       propId = INT_TO_JSID(insn.getKey().getArrayIndex());
     } else {
       // TODO-Stencil
       //   Just a note, but it seems like this is an OK place to convert atoms
       //   since the other GC allocations in the function (properties vector,
       //   etc.) would need to be addressed.
       const frontend::ParserAtom* atom = atoms[insn.getKey().getAtomIndex()];
-      JSAtom* jsatom = atom->toJSAtom(cx, atomCache);
+      JSAtom* jsatom = compilationInfo.liftParserAtomToJSAtom(cx, atom);
       if (!jsatom) {
         return nullptr;
       }
       propId = AtomToId(jsatom);
     }
 
     JS::Value propVal;
     if (!noValues) {
-      if (!InterpretObjLiteralValue(cx, atoms, atomCache, insn, &propVal)) {
+      if (!InterpretObjLiteralValue(cx, atoms, compilationInfo, insn,
+                                    &propVal)) {
         return nullptr;
       }
     }
 
     if (!properties.emplaceBack(propId, propVal)) {
       return nullptr;
     }
   }
@@ -114,30 +115,30 @@ static JSObject* InterpretObjLiteralObj(
         singleton ? SingletonObject : TenuredObject);
   }
 
   return NewPlainObjectWithProperties(cx, properties.begin(),
                                       properties.length(), TenuredObject);
 }
 
 static JSObject* InterpretObjLiteralArray(
-    JSContext* cx, frontend::CompilationAtomCache& atomCache,
+    JSContext* cx, frontend::CompilationInfo& compilationInfo,
     const ObjLiteralAtomVector& atoms,
     const mozilla::Span<const uint8_t> literalInsns, ObjLiteralFlags flags) {
   bool isCow = flags.contains(ObjLiteralFlag::ArrayCOW);
   ObjLiteralReader reader(literalInsns);
   ObjLiteralInsn insn;
 
   Rooted<ValueVector> elements(cx, ValueVector(cx));
 
   while (reader.readInsn(&insn)) {
     MOZ_ASSERT(insn.isValid());
 
     JS::Value propVal;
-    if (!InterpretObjLiteralValue(cx, atoms, atomCache, insn, &propVal)) {
+    if (!InterpretObjLiteralValue(cx, atoms, compilationInfo, insn, &propVal)) {
       return nullptr;
     }
     if (!elements.append(propVal)) {
       return nullptr;
     }
   }
 
   ObjectGroup::NewArrayKind arrayKind =
@@ -149,24 +150,24 @@ static JSObject* InterpretObjLiteralArra
   if (!result) {
     return nullptr;
   }
 
   return result;
 }
 
 JSObject* InterpretObjLiteral(JSContext* cx,
-                              frontend::CompilationAtomCache& atomCache,
+                              frontend::CompilationInfo& compilationInfo,
                               const ObjLiteralAtomVector& atoms,
                               const mozilla::Span<const uint8_t> literalInsns,
                               ObjLiteralFlags flags) {
   return flags.contains(ObjLiteralFlag::Array)
-             ? InterpretObjLiteralArray(cx, atomCache, atoms, literalInsns,
-                                        flags)
-             : InterpretObjLiteralObj(cx, atomCache, atoms, literalInsns,
+             ? InterpretObjLiteralArray(cx, compilationInfo, atoms,
+                                        literalInsns, flags)
+             : InterpretObjLiteralObj(cx, compilationInfo, atoms, literalInsns,
                                       flags);
 }
 
 #if defined(DEBUG) || defined(JS_JITSPEW)
 
 static void DumpObjLiteralFlagsItems(js::JSONPrinter& json,
                                      ObjLiteralFlags flags) {
   if (flags.contains(ObjLiteralFlag::Array)) {
--- a/js/src/frontend/ObjLiteral.h
+++ b/js/src/frontend/ObjLiteral.h
@@ -138,17 +138,17 @@
  * special flags to ensure its shape is looked up based on properties instead.
  */
 
 namespace js {
 
 class JSONPrinter;
 
 namespace frontend {
-struct CompilationAtomCache;
+struct CompilationInfo;
 class StencilXDR;
 }  // namespace frontend
 
 // Object-literal instruction opcodes. An object literal is constructed by a
 // straight-line sequence of these ops, each adding one property to the
 // object.
 enum class ObjLiteralOpcode : uint8_t {
   INVALID = 0,
@@ -561,26 +561,26 @@ struct ObjLiteralReader : private ObjLit
     return true;
   }
 };
 
 typedef Vector<const frontend::ParserAtom*, 4, js::SystemAllocPolicy>
     ObjLiteralAtomVector;
 
 JSObject* InterpretObjLiteral(JSContext* cx,
-                              frontend::CompilationAtomCache& atomCache,
+                              frontend::CompilationInfo& compilationInfo,
                               const ObjLiteralAtomVector& atoms,
                               const mozilla::Span<const uint8_t> insns,
                               ObjLiteralFlags flags);
 
 inline JSObject* InterpretObjLiteral(JSContext* cx,
-                                     frontend::CompilationAtomCache& atomCache,
+                                     frontend::CompilationInfo& compilationInfo,
                                      const ObjLiteralAtomVector& atoms,
                                      const ObjLiteralWriter& writer) {
-  return InterpretObjLiteral(cx, atomCache, atoms, writer.getCode(),
+  return InterpretObjLiteral(cx, compilationInfo, atoms, writer.getCode(),
                              writer.getFlags());
 }
 
 class ObjLiteralStencil {
   friend class frontend::StencilXDR;
 
   ObjLiteralWriter writer_;
   ObjLiteralAtomVector atoms_;
@@ -595,18 +595,17 @@ class ObjLiteralStencil {
     *index = atoms_.length();
     if (!atoms_.append(atom)) {
       js::ReportOutOfMemory(cx);
       return false;
     }
     return true;
   }
 
-  JSObject* create(JSContext* cx,
-                   frontend::CompilationAtomCache& atomCache) const;
+  JSObject* create(JSContext* cx, frontend::CompilationInfo& info) const;
 
 #if defined(DEBUG) || defined(JS_JITSPEW)
   void dump();
   void dump(JSONPrinter& json);
   void dumpFields(JSONPrinter& json);
 #endif
 };
 
--- a/js/src/frontend/ParseContext.cpp
+++ b/js/src/frontend/ParseContext.cpp
@@ -416,21 +416,21 @@ bool ParseContext::isVarRedeclaredInInne
 bool ParseContext::isVarRedeclaredInEval(const ParserName* name,
                                          DeclarationKind kind,
                                          Maybe<DeclarationKind>* out) {
   MOZ_ASSERT(out);
   MOZ_ASSERT(DeclarationKindIsVar(kind));
   MOZ_ASSERT(sc()->isEvalContext());
 
   // TODO-Stencil: After scope snapshotting, this can be done away with.
-  JSAtom* nameAtom =
-      name->toJSAtom(sc()->cx_, sc()->compilationInfo().input.atomCache);
-  if (!nameAtom) {
+  auto mbNameAtom = name->toJSAtom(sc()->cx_, sc()->compilationInfo());
+  if (mbNameAtom.isErr()) {
     return false;
   }
+  JSAtom* nameAtom = mbNameAtom.unwrap();
 
   // In the case of eval, we also need to check enclosing VM scopes to see
   // if the var declaration is allowed in the context.
   js::Scope* enclosingScope = sc()->compilationInfo().input.enclosingScope;
   js::Scope* varScope = EvalScope::nearestVarScopeForDirectEval(enclosingScope);
   MOZ_ASSERT(varScope);
   for (ScopeIter si(enclosingScope); si; si++) {
     for (js::BindingIter bi(si.scope()); bi; bi++) {
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -5,19 +5,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "frontend/ParseNode.h"
 
 #include "mozilla/FloatingPoint.h"
 
 #include "jsnum.h"
 
+#include "frontend/CompilationInfo.h"
 #include "frontend/FullParseHandler.h"
 #include "frontend/ParseContext.h"
-#include "frontend/ParserAtom.h"
 #include "frontend/SharedContext.h"
 #include "vm/BigIntType.h"
 #include "vm/Printer.h"
 #include "vm/RegExpObject.h"
 
 using namespace js;
 using namespace js::frontend;
 
@@ -387,19 +387,19 @@ void LexicalScopeNode::dumpImpl(GenericP
 #endif
 
 BigInt* BigIntLiteral::create(JSContext* cx) {
   return stencil_.bigIntData[index_].createBigInt(cx);
 }
 
 bool BigIntLiteral::isZero() { return stencil_.bigIntData[index_].isZero(); }
 
-const ParserAtom* NumericLiteral::toAtom(JSContext* cx,
-                                         ParserAtomsTable& parserAtoms) const {
-  return NumberToParserAtom(cx, parserAtoms, value());
+const ParserAtom* NumericLiteral::toAtom(
+    JSContext* cx, CompilationInfo& compilationInfo) const {
+  return NumberToParserAtom(cx, compilationInfo, value());
 }
 
 RegExpObject* RegExpStencil::createRegExp(JSContext* cx) const {
   MOZ_ASSERT(buf_);
   return RegExpObject::createSyntaxChecked(cx, buf_.get(), length_, flags_,
                                            TenuredObject);
 }
 
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -53,17 +53,16 @@ namespace js {
 
 class GenericPrinter;
 class LifoAlloc;
 class RegExpObject;
 
 namespace frontend {
 
 class ParseContext;
-class ParserAtomsTable;
 struct CompilationStencil;
 class ParserSharedBase;
 class FullParseHandler;
 
 class FunctionBox;
 
 // This typedef unfortunately needs to be replicated here.
 using ParserBindingName = AbstractBindingName<const ParserAtom>;
@@ -1568,17 +1567,18 @@ class NumericLiteral : public ParseNode 
 
   DecimalPoint decimalPoint() const { return decimalPoint_; }
 
   void setValue(double v) { value_ = v; }
 
   void setDecimalPoint(DecimalPoint d) { decimalPoint_ = d; }
 
   // Return the decimal string representation of this numeric literal.
-  const ParserAtom* toAtom(JSContext* cx, ParserAtomsTable& parserAtoms) const;
+  const ParserAtom* toAtom(JSContext* cx,
+                           CompilationInfo& compilationInfo) const;
 };
 
 class BigIntLiteral : public ParseNode {
   CompilationStencil& stencil_;
   BigIntIndex index_;
 
  public:
   BigIntLiteral(BigIntIndex index, CompilationStencil& stencil,
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -201,18 +201,17 @@ PerHandlerParser<ParseHandler>::PerHandl
 template <class ParseHandler, typename Unit>
 GeneralParser<ParseHandler, Unit>::GeneralParser(
     JSContext* cx, const ReadOnlyCompileOptions& options, const Unit* units,
     size_t length, bool foldConstants, CompilationInfo& compilationInfo,
     CompilationState& compilationState, SyntaxParser* syntaxParser,
     BaseScript* lazyOuterFunction)
     : Base(cx, options, foldConstants, compilationInfo, compilationState,
            syntaxParser, lazyOuterFunction),
-      tokenStream(cx, &compilationInfo.stencil.parserAtoms, options, units,
-                  length) {}
+      tokenStream(cx, &compilationInfo, options, units, length) {}
 
 template <typename Unit>
 void Parser<SyntaxParseHandler, Unit>::setAwaitHandling(
     AwaitHandling awaitHandling) {
   this->awaitHandling_ = awaitHandling;
 }
 
 template <typename Unit>
@@ -380,18 +379,17 @@ typename ParseHandler::ListNodeType Gene
     return null();
   }
 
   if (foldConstants_) {
     Node node = stmtList;
     // Don't constant-fold inside "use asm" code, as this could create a parse
     // tree that doesn't type-check as asm.js.
     if (!pc_->useAsmOrInsideUseAsm()) {
-      if (!FoldConstants(cx_, this->getCompilationInfo().stencil.parserAtoms,
-                         &node, &handler_)) {
+      if (!FoldConstants(cx_, this->getCompilationInfo(), &node, &handler_)) {
         return null();
       }
     }
     stmtList = handler_.asList(node);
   }
 
   return stmtList;
 }
@@ -1584,18 +1582,17 @@ LexicalScopeNode* Parser<FullParseHandle
   if (!CheckParseTree(cx_, alloc_, body)) {
     return null();
   }
 
   ParseNode* node = body;
   // Don't constant-fold inside "use asm" code, as this could create a parse
   // tree that doesn't type-check as asm.js.
   if (!pc_->useAsmOrInsideUseAsm()) {
-    if (!FoldConstants(cx_, this->getCompilationInfo().stencil.parserAtoms,
-                       &node, &handler_)) {
+    if (!FoldConstants(cx_, this->getCompilationInfo(), &node, &handler_)) {
       return null();
     }
   }
   body = handler_.asLexicalScope(node);
 
   if (!this->setSourceMapInfo()) {
     return nullptr;
   }
@@ -1645,18 +1642,17 @@ ListNode* Parser<FullParseHandler, Unit>
   if (!checkForUndefinedPrivateFields()) {
     return null();
   }
 
   ParseNode* node = body;
   // Don't constant-fold inside "use asm" code, as this could create a parse
   // tree that doesn't type-check as asm.js.
   if (!pc_->useAsmOrInsideUseAsm()) {
-    if (!FoldConstants(cx_, this->getCompilationInfo().stencil.parserAtoms,
-                       &node, &handler_)) {
+    if (!FoldConstants(cx_, this->getCompilationInfo(), &node, &handler_)) {
       return null();
     }
   }
   body = &node->as<ListNode>();
 
   if (!this->setSourceMapInfo()) {
     return nullptr;
   }
@@ -1757,18 +1753,17 @@ ModuleNode* Parser<FullParseHandler, Uni
   if (!CheckParseTree(cx_, alloc_, stmtList)) {
     return null();
   }
 
   ParseNode* node = stmtList;
   // Don't constant-fold inside "use asm" code, as this could create a parse
   // tree that doesn't type-check as asm.js.
   if (!pc_->useAsmOrInsideUseAsm()) {
-    if (!FoldConstants(cx_, this->getCompilationInfo().stencil.parserAtoms,
-                       &node, &handler_)) {
+    if (!FoldConstants(cx_, this->getCompilationInfo(), &node, &handler_)) {
       return null();
     }
   }
   stmtList = &node->as<ListNode>();
 
   if (!this->setSourceMapInfo()) {
     return null();
   }
@@ -2149,18 +2144,17 @@ FunctionNode* Parser<FullParseHandler, U
   if (!CheckParseTree(cx_, alloc_, funNode)) {
     return null();
   }
 
   ParseNode* node = funNode;
   // Don't constant-fold inside "use asm" code, as this could create a parse
   // tree that doesn't type-check as asm.js.
   if (!pc_->useAsmOrInsideUseAsm()) {
-    if (!FoldConstants(cx_, this->getCompilationInfo().stencil.parserAtoms,
-                       &node, &handler_)) {
+    if (!FoldConstants(cx_, this->getCompilationInfo(), &node, &handler_)) {
       return null();
     }
   }
   funNode = &node->as<FunctionNode>();
 
   if (!checkForUndefinedPrivateFields(nullptr)) {
     return null();
   }
@@ -3244,18 +3238,17 @@ FunctionNode* Parser<FullParseHandler, U
   if (!CheckParseTree(cx_, alloc_, funNode)) {
     return null();
   }
 
   ParseNode* node = funNode;
   // Don't constant-fold inside "use asm" code, as this could create a parse
   // tree that doesn't type-check as asm.js.
   if (!pc_->useAsmOrInsideUseAsm()) {
-    if (!FoldConstants(cx_, this->getCompilationInfo().stencil.parserAtoms,
-                       &node, &handler_)) {
+    if (!FoldConstants(cx_, this->getCompilationInfo(), &node, &handler_)) {
       return null();
     }
   }
   funNode = &node->as<FunctionNode>();
 
   return funNode;
 }
 
@@ -3645,18 +3638,17 @@ bool Parser<FullParseHandler, Unit>::asm
   pc_->functionBox()->useAsm = true;
 
   // Attempt to validate and compile this asm.js module. On success, the
   // tokenStream has been advanced to the closing }. On failure, the
   // tokenStream is in an indeterminate state and we must reparse the
   // function from the beginning. Reparsing is triggered by marking that a
   // new directive has been encountered and returning 'false'.
   bool validated;
-  if (!CompileAsmJS(cx_, this->compilationInfo_.stencil.parserAtoms, *this,
-                    list, &validated)) {
+  if (!CompileAsmJS(cx_, this->compilationInfo_, *this, list, &validated)) {
     return false;
   }
   if (!validated) {
     pc_->newDirectives->setAsmJS();
     return false;
   }
 
   return true;
@@ -7330,18 +7322,18 @@ bool GeneralParser<ParseHandler, Unit>::
         case AccessorType::Setter:
           if (!storedMethodName.append(".setter")) {
             return false;
           }
           break;
         default:
           MOZ_CRASH("Invalid private method accessor type");
       }
-      const ParserAtom* storedMethodAtom = storedMethodName.finishParserAtom(
-          this->compilationInfo_.stencil.parserAtoms);
+      const ParserAtom* storedMethodAtom =
+          storedMethodName.finishParserAtom(this->compilationInfo_);
       if (!storedMethodAtom) {
         return false;
       }
       const ParserName* storedMethodProp = storedMethodAtom->asName();
       if (!noteDeclaredName(storedMethodProp, DeclarationKind::Const, pos())) {
         return false;
       }
 
@@ -10603,19 +10595,18 @@ typename ParseHandler::Node GeneralParse
   //   IdentifierName
   //   StringLiteral
   //   NumericLiteral
   TokenKind ltok = anyChars.currentToken().type;
 
   *propAtomOut = nullptr;
   switch (ltok) {
     case TokenKind::Number: {
-      const ParserAtom* numAtom =
-          NumberToParserAtom(cx_, this->compilationInfo_.stencil.parserAtoms,
-                             anyChars.currentToken().number());
+      const ParserAtom* numAtom = NumberToParserAtom(
+          cx_, this->compilationInfo_, anyChars.currentToken().number());
       if (!numAtom) {
         return null();
       }
       *propAtomOut = numAtom;
       return newNumber(anyChars.currentToken());
     }
 
     case TokenKind::BigInt: {
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -266,17 +266,17 @@ class MOZ_STACK_CLASS ParserSharedBase :
 
   // For tracking used names in this parsing session.
   UsedNameTracker& usedNames_;
 
  public:
   CompilationInfo& getCompilationInfo() { return compilationInfo_; }
 
   JSAtom* liftParserAtomToJSAtom(const ParserAtom* parserAtom) {
-    return parserAtom->toJSAtom(cx_, compilationInfo_.input.atomCache);
+    return compilationInfo_.liftParserAtomToJSAtom(cx_, parserAtom);
   }
   const ParserAtom* lowerJSAtomToParserAtom(JSAtom* atom) {
     return compilationInfo_.lowerJSAtomToParserAtom(cx_, atom);
   }
 };
 
 class MOZ_STACK_CLASS ParserBase : public ParserSharedBase,
                                    public ErrorReportMixin {
--- a/js/src/frontend/ParserAtom.cpp
+++ b/js/src/frontend/ParserAtom.cpp
@@ -208,21 +208,21 @@ bool ParserAtomEntry::isIndex(uint32_t* 
   if (hasLatin1Chars()) {
     return mozilla::IsAsciiDigit(*latin1Chars()) &&
            js::CheckStringIsIndex(latin1Chars(), len, indexp);
   }
   return mozilla::IsAsciiDigit(*twoByteChars()) &&
          js::CheckStringIsIndex(twoByteChars(), len, indexp);
 }
 
-JSAtom* ParserAtomEntry::toJSAtom(JSContext* cx,
-                                  CompilationAtomCache& atomCache) const {
+JS::Result<JSAtom*, OOM> ParserAtomEntry::toJSAtom(
+    JSContext* cx, CompilationInfo& compilationInfo) const {
   switch (atomIndexKind_) {
     case AtomIndexKind::AtomIndex:
-      return atomCache.atoms[atomIndex_];
+      return compilationInfo.input.atoms[atomIndex_];
 
     case AtomIndexKind::WellKnown:
       return GetWellKnownAtom(cx, WellKnownAtomId(atomIndex_));
 
     case AtomIndexKind::Static1: {
       char16_t ch = static_cast<char16_t>(atomIndex_);
       return cx->staticStrings().getUnit(ch);
     }
@@ -236,23 +236,21 @@ JSAtom* ParserAtomEntry::toJSAtom(JSCont
 
   JSAtom* atom;
   if (hasLatin1Chars()) {
     atom = AtomizeChars(cx, latin1Chars(), length());
   } else {
     atom = AtomizeChars(cx, twoByteChars(), length());
   }
   if (!atom) {
-    js::ReportOutOfMemory(cx);
-    return nullptr;
+    return RaiseParserAtomsOOMError(cx);
   }
-  auto index = atomCache.atoms.length();
-  if (!atomCache.atoms.append(atom)) {
-    js::ReportOutOfMemory(cx);
-    return nullptr;
+  auto index = compilationInfo.input.atoms.length();
+  if (!compilationInfo.input.atoms.append(atom)) {
+    return RaiseParserAtomsOOMError(cx);
   }
 
   const_cast<ParserAtomEntry*>(this)->setAtomIndex(AtomIndex(index));
 
   return atom;
 }
 
 bool ParserAtomEntry::toNumber(JSContext* cx, double* result) const {
@@ -505,26 +503,26 @@ JS::Result<const ParserAtom*, OOM> Parse
       return result;
     }
     id = result.unwrap();
   }
 
   if (id->atomIndexKind_ == ParserAtomEntry::AtomIndexKind::Unresolved) {
     MOZ_ASSERT(id->equalsJSAtom(atom));
 
-    auto index = AtomIndex(compilationInfo.input.atomCache.atoms.length());
-    if (!compilationInfo.input.atomCache.atoms.append(atom)) {
+    auto index = AtomIndex(compilationInfo.input.atoms.length());
+    if (!compilationInfo.input.atoms.append(atom)) {
       return RaiseParserAtomsOOMError(cx);
     }
 
     const_cast<ParserAtom*>(id)->setAtomIndex(AtomIndex(index));
   }
 
   // We should (infallibly) map back to the same JSAtom.
-  MOZ_ASSERT(id->toJSAtom(cx, compilationInfo.input.atomCache) == atom);
+  MOZ_ASSERT(id->toJSAtom(cx, compilationInfo).unwrap() == atom);
 
   return id;
 }
 
 JS::Result<const ParserAtom*, OOM> ParserAtomsTable::concatAtoms(
     JSContext* cx, mozilla::Range<const ParserAtom*> atoms) {
   MOZ_ASSERT(atoms.length() >= 2,
              "concatAtoms should only be used for multiple inputs");
--- a/js/src/frontend/ParserAtom.h
+++ b/js/src/frontend/ParserAtom.h
@@ -18,29 +18,28 @@
 #include "js/UniquePtr.h"         // js::UniquePtr
 #include "js/Vector.h"            // Vector
 #include "vm/CommonPropertyNames.h"
 #include "vm/StringType.h"  // CompareChars, StringEqualsAscii
 
 namespace js {
 namespace frontend {
 
-struct CompilationAtomCache;
 struct CompilationInfo;
 class ParserAtom;
 class ParserName;
 
 template <typename CharT>
 class SpecificParserAtomLookup;
 
 class ParserAtomsTable;
 
 mozilla::GenericErrorResult<OOM> RaiseParserAtomsOOMError(JSContext* cx);
 
-// An index into CompilationAtomCache.
+// An index into CompilationInfo.atoms.
 // This is local to the current compilation.
 using AtomIndex = TypedIndex<JSAtom*>;
 
 // An index to map WellKnownParserAtoms to cx->names().
 // This is consistent across multiple compilation.
 //
 // GetWellKnownAtom in ParserAtom.cpp relies on the fact that
 // JSAtomState fields and this enum variants use the same order.
@@ -101,17 +100,17 @@ class alignas(alignof(uint32_t)) ParserA
   HashNumber hash_ = 0;
 
   // The length of the buffer in chars_.
   uint32_t length_ = 0;
 
   // Mapping into from ParserAtoms to JSAtoms.
   enum class AtomIndexKind : uint8_t {
     Unresolved,  // Not yet resolved
-    AtomIndex,   // Index into CompilationAtomCache
+    AtomIndex,   // Index into CompilationInfo atoms map
     WellKnown,   // WellKnownAtomId to index into cx->names() set
     Static1,     // Index into StaticStrings length-1 set
     Static2,     // Index into StaticStrings length-2 set
   };
   uint32_t atomIndex_ = 0;
   AtomIndexKind atomIndexKind_ = AtomIndexKind::Unresolved;
 
   // Encoding type.
@@ -230,17 +229,18 @@ class alignas(alignof(uint32_t)) ParserA
     hash_ = hash;
     length_ = length;
     hasTwoByteChars_ = hasTwoByteChars;
   }
 
  public:
   // Convert this entry to a js-atom.  The first time this method is called
   // the entry will cache the JSAtom pointer to return later.
-  JSAtom* toJSAtom(JSContext* cx, CompilationAtomCache& atomCache) const;
+  JS::Result<JSAtom*, OOM> toJSAtom(JSContext* cx,
+                                    CompilationInfo& compilationInfo) const;
 
   // Convert this entry to a number.
   bool toNumber(JSContext* cx, double* result) const;
 
 #if defined(DEBUG) || defined(JS_JITSPEW)
   void dump() const;
   void dumpCharsNoQuote(js::GenericPrinter& out) const;
 #endif
--- a/js/src/frontend/SharedContext-inl.h
+++ b/js/src/frontend/SharedContext-inl.h
@@ -13,17 +13,17 @@
 namespace js {
 namespace frontend {
 
 inline Directives::Directives(ParseContext* parent)
     : strict_(parent->sc()->strict()), asmJS_(parent->useAsmOrInsideUseAsm()) {}
 
 inline JSAtom* SharedContext::liftParserAtomToJSAtom(JSContext* cx,
                                                      const ParserAtom* atomId) {
-  return atomId->toJSAtom(cx, compilationInfo_.input.atomCache);
+  return compilationInfo_.liftParserAtomToJSAtom(cx, atomId);
 }
 inline const ParserAtom* SharedContext::lowerJSAtomToParserAtom(JSContext* cx,
                                                                 JSAtom* atom) {
   return compilationInfo_.lowerJSAtomToParserAtom(cx, atom);
 }
 
 }  // namespace frontend
 
--- a/js/src/frontend/Stencil.cpp
+++ b/js/src/frontend/Stencil.cpp
@@ -41,72 +41,62 @@ AbstractScopePtr ScopeStencil::enclosing
     CompilationInfo& compilationInfo) const {
   if (enclosing_) {
     return AbstractScopePtr(compilationInfo, *enclosing_);
   }
 
   return AbstractScopePtr(compilationInfo.input.enclosingScope);
 }
 
-Scope* ScopeStencil::enclosingExistingScope(
-    const CompilationInput& input, const CompilationGCOutput& gcOutput) const {
-  if (enclosing_) {
-    Scope* result = gcOutput.scopes[*enclosing_];
-    MOZ_ASSERT(result, "Scope must already exist to use this method");
-    return result;
-  }
-
-  return input.enclosingScope;
-}
-
-Scope* ScopeStencil::createScope(JSContext* cx, CompilationInput& input,
+Scope* ScopeStencil::createScope(JSContext* cx,
+                                 CompilationInfo& compilationInfo,
                                  CompilationGCOutput& gcOutput) const {
   Scope* scope = nullptr;
   switch (kind()) {
     case ScopeKind::Function: {
-      scope =
-          createSpecificScope<FunctionScope, CallObject>(cx, input, gcOutput);
+      scope = createSpecificScope<FunctionScope, CallObject>(
+          cx, compilationInfo, gcOutput);
       break;
     }
     case ScopeKind::Lexical:
     case ScopeKind::SimpleCatch:
     case ScopeKind::Catch:
     case ScopeKind::NamedLambda:
     case ScopeKind::StrictNamedLambda:
     case ScopeKind::FunctionLexical:
     case ScopeKind::ClassBody: {
       scope = createSpecificScope<LexicalScope, LexicalEnvironmentObject>(
-          cx, input, gcOutput);
+          cx, compilationInfo, gcOutput);
       break;
     }
     case ScopeKind::FunctionBodyVar: {
-      scope = createSpecificScope<VarScope, VarEnvironmentObject>(cx, input,
-                                                                  gcOutput);
+      scope = createSpecificScope<VarScope, VarEnvironmentObject>(
+          cx, compilationInfo, gcOutput);
       break;
     }
     case ScopeKind::Global:
     case ScopeKind::NonSyntactic: {
-      scope =
-          createSpecificScope<GlobalScope, std::nullptr_t>(cx, input, gcOutput);
+      scope = createSpecificScope<GlobalScope, std::nullptr_t>(
+          cx, compilationInfo, gcOutput);
       break;
     }
     case ScopeKind::Eval:
     case ScopeKind::StrictEval: {
-      scope = createSpecificScope<EvalScope, VarEnvironmentObject>(cx, input,
-                                                                   gcOutput);
+      scope = createSpecificScope<EvalScope, VarEnvironmentObject>(
+          cx, compilationInfo, gcOutput);
       break;
     }
     case ScopeKind::Module: {
       scope = createSpecificScope<ModuleScope, ModuleEnvironmentObject>(
-          cx, input, gcOutput);
+          cx, compilationInfo, gcOutput);
       break;
     }
     case ScopeKind::With: {
-      scope =
-          createSpecificScope<WithScope, std::nullptr_t>(cx, input, gcOutput);
+      scope = createSpecificScope<WithScope, std::nullptr_t>(
+          cx, compilationInfo, gcOutput);
       break;
     }
     case ScopeKind::WasmFunction:
     case ScopeKind::WasmInstance: {
       MOZ_CRASH("Unexpected deferred type");
     }
   }
   return scope;
@@ -196,17 +186,17 @@ static JSFunction* CreateFunction(JSCont
                                 : gc::AllocKind::FUNCTION;
   bool isAsmJS = script.functionFlags.isAsmJSNative();
 
   JSNative maybeNative = isAsmJS ? InstantiateAsmJS : nullptr;
 
   RootedAtom displayAtom(cx);
   if (script.functionAtom) {
     displayAtom.set(
-        script.functionAtom->toJSAtom(cx, compilationInfo.input.atomCache));
+        compilationInfo.liftParserAtomToJSAtom(cx, script.functionAtom));
     if (!displayAtom) {
       return nullptr;
     }
   }
   RootedFunction fun(
       cx, NewFunctionWithProto(cx, maybeNative, script.nargs,
                                script.functionFlags, nullptr, displayAtom,
                                proto, allocKind, TenuredObject));
@@ -266,18 +256,18 @@ static bool MaybeInstantiateModule(JSCon
                                    CompilationGCOutput& gcOutput) {
   if (compilationInfo.stencil.scriptData[CompilationInfo::TopLevelIndex]
           .isModule()) {
     gcOutput.module = ModuleObject::create(cx);
     if (!gcOutput.module) {
       return false;
     }
 
-    if (!compilationInfo.stencil.moduleMetadata.initModule(
-            cx, compilationInfo.input.atomCache, gcOutput.module)) {
+    if (!compilationInfo.stencil.moduleMetadata.initModule(cx, compilationInfo,
+                                                           gcOutput.module)) {
       return false;
     }
   }
 
   return true;
 }
 
 // Instantiate JSFunctions for each FunctionBox.
@@ -307,30 +297,28 @@ static bool InstantiateFunctions(JSConte
 // associated JSFunction pointer, and also should be called before
 // InstantiateScriptStencils, given JSScript needs Scope pointer in gc things.
 static bool InstantiateScopes(JSContext* cx, CompilationInfo& compilationInfo,
                               CompilationGCOutput& gcOutput) {
   // While allocating Scope object from ScopeStencil, Scope object for the
   // enclosing Scope should already be allocated.
   //
   // Enclosing scope of ScopeStencil can be either ScopeStencil or Scope*
-  // pointer.
+  // pointer, capsulated by AbstractScopePtr.
   //
   // If the enclosing scope is ScopeStencil, it's guaranteed to be earlier
-  // element in compilationInfo.scopeData, because enclosing_ field holds index
+  // element in compilationInfo.scopeData, because AbstractScopePtr holds index
   // into it, and newly created ScopeStencil is pushed back to the vector.
-  //
-  // If the enclosing scope is Scope*, it's CompilationInput.enclosingScope.
 
   if (!gcOutput.scopes.reserve(compilationInfo.stencil.scopeData.length())) {
     return false;
   }
 
   for (const ScopeStencil& scd : compilationInfo.stencil.scopeData) {
-    Scope* scope = scd.createScope(cx, compilationInfo.input, gcOutput);
+    Scope* scope = scd.createScope(cx, compilationInfo, gcOutput);
     if (!scope) {
       return false;
     }
     gcOutput.scopes.infallibleAppend(scope);
   }
 
   return true;
 }
@@ -366,18 +354,18 @@ static bool SetTypeAndNameForExposedFunc
     }
 
     // Inferred and Guessed names are computed by BytecodeEmitter and so may
     // need to be applied to existing JSFunctions during delazification.
     if (fun->displayAtom() == nullptr) {
       JSAtom* funcAtom = nullptr;
       if (scriptStencil.functionFlags.hasInferredName() ||
           scriptStencil.functionFlags.hasGuessedAtom()) {
-        funcAtom = scriptStencil.functionAtom->toJSAtom(
-            cx, compilationInfo.input.atomCache);
+        funcAtom = compilationInfo.liftParserAtomToJSAtom(
+            cx, scriptStencil.functionAtom);
         if (!funcAtom) {
           return false;
         }
       }
       if (scriptStencil.functionFlags.hasInferredName()) {
         fun->setInferredName(funcAtom);
       }
 
@@ -391,27 +379,25 @@ static bool SetTypeAndNameForExposedFunc
 }
 
 // Instantiate js::BaseScripts from ScriptStencils for inner functions of the
 // compilation. Note that standalone functions and functions being delazified
 // are handled below with other top-levels.
 static bool InstantiateScriptStencils(JSContext* cx,
                                       CompilationInfo& compilationInfo,
                                       CompilationGCOutput& gcOutput) {
-  MOZ_ASSERT(compilationInfo.input.lazy == nullptr);
-
   for (auto item : compilationInfo.functionScriptStencils(gcOutput)) {
     auto& scriptStencil = item.script;
     auto& fun = item.function;
     if (scriptStencil.sharedData) {
       // If the function was not referenced by enclosing script's bytecode, we
       // do not generate a BaseScript for it. For example, `(function(){});`.
       //
-      // `wasFunctionEmitted` is false also for standalone functions. They are
-      // handled in InstantiateTopLevel.
+      // `wasFunctionEmitted` is false also for standalone functions and
+      // functions being delazified. they are handled in InstantiateTopLevel.
       if (!scriptStencil.wasFunctionEmitted) {
         continue;
       }
 
       RootedScript script(cx,
                           JSScript::fromStencil(cx, compilationInfo, gcOutput,
                                                 scriptStencil, fun));
       if (!script) {
@@ -421,18 +407,20 @@ static bool InstantiateScriptStencils(JS
       // NOTE: Inner functions can be marked `allowRelazify` after merging
       // a stencil for delazification into the top-level stencil.
       if (scriptStencil.allowRelazify) {
         MOZ_ASSERT(script->isRelazifiable());
         script->setAllowRelazify();
       }
     } else if (scriptStencil.functionFlags.isAsmJSNative()) {
       MOZ_ASSERT(fun->isAsmJSNative());
-    } else {
-      MOZ_ASSERT(fun->isIncomplete());
+    } else if (fun->isIncomplete()) {
+      // Lazy functions are generally only allocated in the initial parse.
+      MOZ_ASSERT(compilationInfo.input.lazy == nullptr);
+
       if (!CreateLazyScript(cx, compilationInfo, gcOutput, scriptStencil,
                             fun)) {
         return false;
       }
     }
   }
 
   return true;
@@ -603,20 +591,16 @@ static void AssertDelazificationFieldsMa
         uint16_t(FunctionFlags::Flags::MUTABLE_FLAGS);
     constexpr uint16_t acceptableDifferenceForFunction =
         HAS_INFERRED_NAME | HAS_GUESSED_ATOM | MUTABLE_FLAGS;
 
     MOZ_ASSERT((fun->flags().toRaw() | acceptableDifferenceForFunction) ==
                (scriptStencil.functionFlags.toRaw() |
                 acceptableDifferenceForFunction));
 
-    // Delazification shouldn't delazify inner scripts.
-    MOZ_ASSERT_IF(item.functionIndex == 0, scriptStencil.sharedData);
-    MOZ_ASSERT_IF(item.functionIndex > 0, !scriptStencil.sharedData);
-
     // FIXME: If this function is lazily parsed again, nargs isn't set to
     //        correct value (bug 1666978).
     MOZ_ASSERT_IF(scriptStencil.sharedData,
                   fun->nargs() == scriptStencil.nargs);
   }
 }
 #endif  // DEBUG
 
@@ -641,32 +625,30 @@ static void FunctionsFromExistingLazy(Co
 }
 
 bool CompilationInfo::instantiateStencils(JSContext* cx,
                                           CompilationGCOutput& gcOutput) {
   if (!gcOutput.functions.resize(stencil.scriptData.length())) {
     return false;
   }
 
+  if (stencil.scriptData[CompilationInfo::TopLevelIndex].isModule()) {
+    MOZ_ASSERT(input.enclosingScope == nullptr);
+    input.enclosingScope = &cx->global()->emptyGlobalScope();
+    MOZ_ASSERT(input.enclosingScope->environmentChainLength() ==
+               ModuleScope::EnclosingEnvironmentChainLength);
+  }
+
   if (input.lazy) {
-    MOZ_ASSERT(!stencil.scriptData[CompilationInfo::TopLevelIndex].isModule());
-
     FunctionsFromExistingLazy(*this, gcOutput);
 
 #ifdef DEBUG
     AssertDelazificationFieldsMatch(*this, gcOutput);
 #endif
   } else {
-    if (stencil.scriptData[CompilationInfo::TopLevelIndex].isModule()) {
-      MOZ_ASSERT(input.enclosingScope == nullptr);
-      input.enclosingScope = &cx->global()->emptyGlobalScope();
-      MOZ_ASSERT(input.enclosingScope->environmentChainLength() ==
-                 ModuleScope::EnclosingEnvironmentChainLength);
-    }
-
     if (!InstantiateScriptSourceObject(cx, *this, gcOutput)) {
       return false;
     }
 
     if (!MaybeInstantiateModule(cx, *this, gcOutput)) {
       return false;
     }
 
@@ -678,31 +660,29 @@ bool CompilationInfo::instantiateStencil
   if (!InstantiateScopes(cx, *this, gcOutput)) {
     return false;
   }
 
   if (!SetTypeAndNameForExposedFunctions(cx, *this, gcOutput)) {
     return false;
   }
 
-  if (!input.lazy) {
-    if (!InstantiateScriptStencils(cx, *this, gcOutput)) {
-      return false;
-    }
+  if (!InstantiateScriptStencils(cx, *this, gcOutput)) {
+    return false;
   }
 
   if (!InstantiateTopLevel(cx, *this, gcOutput)) {
     return false;
   }
 
   // Must be infallible from here forward.
 
   UpdateEmittedInnerFunctions(*this, gcOutput);
 
-  if (!input.lazy) {
+  if (input.lazy == nullptr) {
     LinkEnclosingLazyScript(*this, gcOutput);
   }
 
   return true;
 }
 
 bool CompilationInfoVector::buildDelazificationStencilMap(
     FunctionMap& functionMap) {
--- a/js/src/frontend/Stencil.h
+++ b/js/src/frontend/Stencil.h
@@ -36,17 +36,16 @@
 
 namespace js {
 
 class JSONPrinter;
 
 namespace frontend {
 
 struct CompilationInfo;
-struct CompilationAtomCache;
 struct CompilationStencil;
 struct CompilationGCOutput;
 class ScriptStencil;
 class RegExpStencil;
 class BigIntStencil;
 class StencilXDR;
 
 using BaseParserScopeData = AbstractBaseScopeData<const ParserAtom>;
@@ -241,31 +240,29 @@ class ScopeStencil {
                                    mozilla::Maybe<ScopeIndex> enclosing,
                                    ScopeIndex* index);
 
   static bool createForWithScope(JSContext* cx, CompilationStencil& stencil,
                                  mozilla::Maybe<ScopeIndex> enclosing,
                                  ScopeIndex* index);
 
   AbstractScopePtr enclosing(CompilationInfo& compilationInfo) const;
-  js::Scope* enclosingExistingScope(const CompilationInput& input,
-                                    const CompilationGCOutput& gcOutput) const;
 
   ScopeKind kind() const { return kind_; }
 
   bool hasEnvironment() const {
     // Check if scope kind alone means we have an env shape, and
     // otherwise check if we have one created.
     bool hasEnvironmentShape = numEnvironmentSlots_.isSome();
     return Scope::hasEnvironment(kind(), hasEnvironmentShape);
   }
 
   bool isArrow() const { return isArrow_; }
 
-  Scope* createScope(JSContext* cx, CompilationInput& input,
+  Scope* createScope(JSContext* cx, CompilationInfo& compilationInfo,
                      CompilationGCOutput& gcOutput) const;
 
   uint32_t nextFrameSlot() const;
 
 #if defined(DEBUG) || defined(JS_JITSPEW)
   void dump();
   void dump(JSONPrinter& json);
   void dumpFields(JSONPrinter& json);
@@ -281,33 +278,33 @@ class ScopeStencil {
 
     MOZ_ASSERT(data_);
     return *static_cast<Data*>(data_.get());
   }
 
   // Transfer ownership into a new UniquePtr.
   template <typename SpecificScopeType>
   UniquePtr<typename SpecificScopeType::Data> createSpecificScopeData(
-      JSContext* cx, CompilationAtomCache& atomCache,
+      JSContext* cx, CompilationInfo& compilationInfo,
       CompilationGCOutput& gcOutput) const;
 
   template <typename SpecificScopeType>
   uint32_t nextFrameSlot() const {
     // If a scope has been allocated for the ScopeStencil we no longer own data,
     // so defer to scope
     return data<SpecificScopeType>().nextFrameSlot;
   }
 
   template <typename SpecificEnvironmentType>
   MOZ_MUST_USE bool createSpecificShape(JSContext* cx, ScopeKind kind,
                                         BaseScopeData* scopeData,
                                         MutableHandleShape shape) const;
 
   template <typename SpecificScopeType, typename SpecificEnvironmentType>
-  Scope* createSpecificScope(JSContext* cx, CompilationInput& input,
+  Scope* createSpecificScope(JSContext* cx, CompilationInfo& compilationInfo,
                              CompilationGCOutput& gcOutput) const;
 };
 
 // As an alternative to a ScopeIndex (which references a ScopeStencil), we may
 // instead refer to an existing scope from GlobalObject::emptyGlobalScope().
 //
 // NOTE: This is only used for the self-hosting global.
 class EmptyGlobalScopeType {};
@@ -406,17 +403,17 @@ class StencilModuleMetadata {
   EntryVector importEntries;
   EntryVector localExportEntries;
   EntryVector indirectExportEntries;
   EntryVector starExportEntries;
   FunctionDeclarationVector functionDecls;
 
   StencilModuleMetadata() = default;
 
-  bool initModule(JSContext* cx, CompilationAtomCache& atomCache,
+  bool initModule(JSContext* cx, CompilationInfo& compilationInfo,
                   JS::Handle<ModuleObject*> module) const;
 
 #if defined(DEBUG) || defined(JS_JITSPEW)
   void dump();
   void dump(JSONPrinter& json);
   void dumpFields(JSONPrinter& json);
 #endif
 };
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -537,22 +537,20 @@ TokenStreamAnyChars::TokenStreamAnyChars
   isExprEnding[size_t(TokenKind::Semi)] = true;
   isExprEnding[size_t(TokenKind::Colon)] = true;
   isExprEnding[size_t(TokenKind::RightParen)] = true;
   isExprEnding[size_t(TokenKind::RightBracket)] = true;
   isExprEnding[size_t(TokenKind::RightCurly)] = true;
 }
 
 template <typename Unit>
-TokenStreamCharsBase<Unit>::TokenStreamCharsBase(JSContext* cx,
-                                                 ParserAtomsTable* pasrerAtoms,
-                                                 const Unit* units,
-                                                 size_t length,
-                                                 size_t startOffset)
-    : TokenStreamCharsShared(cx, pasrerAtoms),
+TokenStreamCharsBase<Unit>::TokenStreamCharsBase(
+    JSContext* cx, CompilationInfo* compilationInfo, const Unit* units,
+    size_t length, size_t startOffset)
+    : TokenStreamCharsShared(cx, compilationInfo),
       sourceUnits(units, length, startOffset) {}
 
 template <>
 MOZ_MUST_USE bool TokenStreamCharsBase<char16_t>::
     fillCharBufferFromSourceNormalizingAsciiLineBreaks(const char16_t* cur,
                                                        const char16_t* end) {
   MOZ_ASSERT(this->charBuffer.length() == 0);
 
@@ -608,19 +606,19 @@ MOZ_MUST_USE bool TokenStreamCharsBase<U
   }
 
   MOZ_ASSERT(cur == end);
   return true;
 }
 
 template <typename Unit, class AnyCharsAccess>
 TokenStreamSpecific<Unit, AnyCharsAccess>::TokenStreamSpecific(
-    JSContext* cx, ParserAtomsTable* pasrerAtoms,
+    JSContext* cx, CompilationInfo* compilationInfo,
     const ReadOnlyCompileOptions& options, const Unit* units, size_t length)
-    : TokenStreamChars<Unit, AnyCharsAccess>(cx, pasrerAtoms, units, length,
+    : TokenStreamChars<Unit, AnyCharsAccess>(cx, compilationInfo, units, length,
                                              options.scriptSourceOffset) {}
 
 bool TokenStreamAnyChars::checkOptions() {
   // Constrain starting columns to half of the range of a signed 32-bit value,
   // to avoid overflow.
   if (options().column >= std::numeric_limits<int32_t>::max() / 2 + 1) {
     reportErrorNoOffset(JSMSG_BAD_COLUMN_NUMBER);
     return false;
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -198,16 +198,17 @@
 #include <stdarg.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <type_traits>
 
 #include "jspubtd.h"
 
+#include "frontend/CompilationInfo.h"
 #include "frontend/ErrorReporter.h"
 #include "frontend/ParserAtom.h"
 #include "frontend/Token.h"
 #include "frontend/TokenKind.h"
 #include "js/CompileOptions.h"
 #include "js/HashTable.h"    // js::HashMap
 #include "js/RegExpFlags.h"  // JS::RegExpFlags
 #include "js/UniquePtr.h"
@@ -1503,21 +1504,22 @@ class TokenStreamCharsShared {
   /**
    * Buffer transiently used to store sequences of identifier or string code
    * points when such can't be directly processed from the original source
    * text (e.g. because it contains escapes).
    */
   CharBuffer charBuffer;
 
   /** Information for parsing with a lifetime longer than the parser itself. */
-  ParserAtomsTable* parserAtoms;
+  CompilationInfo* compilationInfo;
 
  protected:
-  explicit TokenStreamCharsShared(JSContext* cx, ParserAtomsTable* parserAtoms)
-      : cx(cx), charBuffer(cx), parserAtoms(parserAtoms) {}
+  explicit TokenStreamCharsShared(JSContext* cx,
+                                  CompilationInfo* compilationInfo)
+      : cx(cx), charBuffer(cx), compilationInfo(compilationInfo) {}
 
   MOZ_MUST_USE bool appendCodePointToCharBuffer(uint32_t codePoint);
 
   MOZ_MUST_USE bool copyCharBufferTo(
       JSContext* cx, UniquePtr<char16_t[], JS::FreePolicy>* destination);
 
   /**
    * Determine whether a code unit constitutes a complete ASCII code point.
@@ -1526,18 +1528,18 @@ class TokenStreamCharsShared {
    */
   static constexpr MOZ_ALWAYS_INLINE MOZ_MUST_USE bool isAsciiCodePoint(
       int32_t unit) {
     return mozilla::IsAscii(static_cast<char32_t>(unit));
   }
 
   const ParserAtom* drainCharBufferIntoAtom() {
     // Add to parser atoms table.
-    auto maybeId = this->parserAtoms->internChar16(cx, charBuffer.begin(),
-                                                   charBuffer.length());
+    auto maybeId = this->compilationInfo->stencil.parserAtoms.internChar16(
+        cx, charBuffer.begin(), charBuffer.length());
     if (maybeId.isErr()) {
       return nullptr;
     }
 
     charBuffer.clear();
     return maybeId.unwrap();
   }
 
@@ -1577,17 +1579,17 @@ class TokenStreamCharsBase : public Toke
   using SourceUnits = frontend::SourceUnits<Unit>;
 
   /** Code units in the source code being tokenized. */
   SourceUnits sourceUnits;
 
   // End of fields.
 
  protected:
-  TokenStreamCharsBase(JSContext* cx, ParserAtomsTable* parserAtoms,
+  TokenStreamCharsBase(JSContext* cx, CompilationInfo* compilationInfo,
                        const Unit* units, size_t length, size_t startOffset);
 
   /**
    * Convert a non-EOF code unit returned by |getCodeUnit()| or
    * |peekCodeUnit()| to a Unit code unit.
    */
   inline Unit toUnit(int32_t codeUnitValue);
 
@@ -1684,25 +1686,27 @@ template <typename Unit>
 inline void TokenStreamCharsBase<Unit>::consumeKnownCodeUnit(int32_t unit) {
   sourceUnits.consumeKnownCodeUnit(toUnit(unit));
 }
 
 template <>
 MOZ_ALWAYS_INLINE const ParserAtom*
 TokenStreamCharsBase<char16_t>::atomizeSourceChars(
     mozilla::Span<const char16_t> units) {
-  return this->parserAtoms->internChar16(cx, units.data(), units.size())
+  return this->compilationInfo->stencil.parserAtoms
+      .internChar16(cx, units.data(), units.size())
       .unwrapOr(nullptr);
 }
 
 template <>
 /* static */ MOZ_ALWAYS_INLINE const ParserAtom*
 TokenStreamCharsBase<mozilla::Utf8Unit>::atomizeSourceChars(
     mozilla::Span<const mozilla::Utf8Unit> units) {
-  return this->parserAtoms->internUtf8(cx, units.data(), units.size())
+  return this->compilationInfo->stencil.parserAtoms
+      .internUtf8(cx, units.data(), units.size())
       .unwrapOr(nullptr);
 }
 
 template <typename Unit>
 class SpecializedTokenStreamCharsBase;
 
 template <>
 class SpecializedTokenStreamCharsBase<char16_t>
@@ -2452,17 +2456,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
   using CharsBase::toUnit;
   using GeneralCharsBase::ungetCodeUnit;
   using GeneralCharsBase::updateLineInfoForEOL;
 
   template <typename CharU>
   friend class TokenStreamPosition;
 
  public:
-  TokenStreamSpecific(JSContext* cx, ParserAtomsTable* parserAtoms,
+  TokenStreamSpecific(JSContext* cx, CompilationInfo* compilationInfo,
                       const JS::ReadOnlyCompileOptions& options,
                       const Unit* units, size_t length);
 
   /**
    * Get the next code point, converting LineTerminatorSequences to '\n' and
    * updating internal line-counter state if needed.  Return true on success
    * and store the code point in |*cp|.  Return false and leave |*cp|
    * undefined on failure.
@@ -2897,22 +2901,22 @@ class TokenStreamAnyCharsAccess {
 };
 
 class MOZ_STACK_CLASS TokenStream
     : public TokenStreamAnyChars,
       public TokenStreamSpecific<char16_t, TokenStreamAnyCharsAccess> {
   using Unit = char16_t;
 
  public:
-  TokenStream(JSContext* cx, ParserAtomsTable* parserAtoms,
+  TokenStream(JSContext* cx, CompilationInfo* compilationInfo,
               const JS::ReadOnlyCompileOptions& options, const Unit* units,
               size_t length, StrictModeGetter* smg)
       : TokenStreamAnyChars(cx, options, smg),
         TokenStreamSpecific<Unit, TokenStreamAnyCharsAccess>(
-            cx, parserAtoms, options, units, length) {}
+            cx, compilationInfo, options, units, length) {}
 };
 
 class MOZ_STACK_CLASS DummyTokenStream final : public TokenStream {
  public:
   DummyTokenStream(JSContext* cx, const JS::ReadOnlyCompileOptions& options)
       : TokenStream(cx, nullptr, options, nullptr, 0, nullptr) {}
 };
 
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -21,17 +21,18 @@
 #  include <locale.h>
 #endif
 #include <math.h>
 #include <string.h>  // memmove
 
 #include "jstypes.h"
 
 #include "double-conversion/double-conversion.h"
-#include "frontend/ParserAtom.h"  // frontend::ParserAtom, frontend::ParserAtomsTable
+#include "frontend/CompilationInfo.h"  // frontend::CompilationInfo
+#include "frontend/ParserAtom.h"       // frontend::ParserAtom
 #include "jit/InlinableNatives.h"
 #include "js/CharacterEncoding.h"
 #include "js/Conversions.h"
 #if !JS_HAS_INTL_API
 #  include "js/LocaleSensitive.h"
 #endif
 #include "js/PropertySpec.h"
 #include "util/DoubleToString.h"
@@ -843,28 +844,29 @@ JSAtom* js::Int32ToAtom(JSContext* cx, i
     return nullptr;
   }
 
   CacheNumber(cx, si, atom);
   return atom;
 }
 
 const frontend::ParserAtom* js::Int32ToParserAtom(
-    JSContext* cx, frontend::ParserAtomsTable& parserAtoms, int32_t si) {
+    JSContext* cx, frontend::CompilationInfo& compilationInfo, int32_t si) {
   char buffer[JSFatInlineString::MAX_LENGTH_TWO_BYTE + 1];
   size_t length;
   char* start = BackfillInt32InBuffer(
       si, buffer, JSFatInlineString::MAX_LENGTH_TWO_BYTE + 1, &length);
 
   Maybe<uint32_t> indexValue;
   if (si >= 0) {
     indexValue.emplace(si);
   }
 
-  return parserAtoms.internAscii(cx, start, length).unwrapOr(nullptr);
+  return compilationInfo.stencil.parserAtoms.internAscii(cx, start, length)
+      .unwrapOr(nullptr);
 }
 
 /* Returns a non-nullptr pointer to inside cbuf.  */
 static char* Int32ToCString(ToCStringBuf* cbuf, int32_t i, size_t* len,
                             int base = 10) {
   uint32_t u = Abs(i);
 
   RangedPtr<char> cp(cbuf->sbuf + ToCStringBuf::sbufSize - 1, cbuf->sbuf,
@@ -1644,33 +1646,34 @@ JSAtom* js::NumberToAtom(JSContext* cx, 
   }
 
   CacheNumber(cx, d, atom);
 
   return atom;
 }
 
 const frontend::ParserAtom* js::NumberToParserAtom(
-    JSContext* cx, frontend::ParserAtomsTable& parserAtoms, double d) {
+    JSContext* cx, frontend::CompilationInfo& compilationInfo, double d) {
   int32_t si;
   if (NumberEqualsInt32(d, &si)) {
-    return Int32ToParserAtom(cx, parserAtoms, si);
+    return Int32ToParserAtom(cx, compilationInfo, si);
   }
 
   ToCStringBuf cbuf;
   char* numStr = FracNumberToCString(cx, &cbuf, d);
   if (!numStr) {
     ReportOutOfMemory(cx);
     return nullptr;
   }
   MOZ_ASSERT(!cbuf.dbuf && numStr >= cbuf.sbuf &&
              numStr < cbuf.sbuf + cbuf.sbufSize);
 
   size_t length = strlen(numStr);
-  return parserAtoms.internAscii(cx, numStr, length).unwrapOr(nullptr);
+  return compilationInfo.stencil.parserAtoms.internAscii(cx, numStr, length)
+      .unwrapOr(nullptr);
 }
 
 JSLinearString* js::IndexToString(JSContext* cx, uint32_t index) {
   if (StaticStrings::hasUint(index)) {
     return cx->staticStrings().getUint(index);
   }
 
   Realm* realm = cx->realm();
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -17,17 +17,17 @@
 #include "js/friend/ErrorMessages.h"
 
 #include "vm/StringType.h"
 
 namespace js {
 
 namespace frontend {
 
-class ParserAtomsTable;
+struct CompilationInfo;
 class ParserAtom;
 
 }  // namespace frontend
 
 class GlobalObject;
 class StringBuffer;
 
 extern MOZ_MUST_USE bool InitRuntimeNumberState(JSRuntime* rt);
@@ -46,27 +46,27 @@ extern JSObject* InitNumberClass(JSConte
 template <AllowGC allowGC>
 extern JSString* NumberToString(JSContext* cx, double d);
 
 extern JSString* NumberToStringHelperPure(JSContext* cx, double d);
 
 extern JSAtom* NumberToAtom(JSContext* cx, double d);
 
 const frontend::ParserAtom* NumberToParserAtom(
-    JSContext* cx, frontend::ParserAtomsTable& parserAtoms, double d);
+    JSContext* cx, frontend::CompilationInfo& compilationInfo, double d);
 
 template <AllowGC allowGC>
 extern JSLinearString* Int32ToString(JSContext* cx, int32_t i);
 
 extern JSLinearString* Int32ToStringHelperPure(JSContext* cx, int32_t i);
 
 extern JSAtom* Int32ToAtom(JSContext* cx, int32_t si);
 
 const frontend::ParserAtom* Int32ToParserAtom(
-    JSContext* cx, frontend::ParserAtomsTable& parserAtoms, int32_t si);
+    JSContext* cx, frontend::CompilationInfo& compilationInfo, int32_t si);
 
 // ES6 15.7.3.12
 extern bool IsInteger(const Value& val);
 
 extern bool IsInteger(double d);
 
 /*
  * Convert an integer or double (contained in the given value) to a string and
--- a/js/src/util/StringBuffer.cpp
+++ b/js/src/util/StringBuffer.cpp
@@ -7,17 +7,18 @@
 #include "util/StringBuffer.h"
 
 #include "mozilla/Latin1.h"
 #include "mozilla/Range.h"
 #include "mozilla/Unused.h"
 
 #include <algorithm>
 
-#include "frontend/ParserAtom.h"  // frontend::ParserAtom, frontend::ParserAtomsTable
+#include "frontend/CompilationInfo.h"  // frontend::CompilationInfo
+#include "frontend/ParserAtom.h"       // frontend::ParserAtom
 #include "vm/JSObject-inl.h"
 #include "vm/StringType-inl.h"
 
 using namespace js;
 
 template <typename CharT, class Buffer>
 static CharT* ExtractWellSized(Buffer& cb) {
   size_t capacity = cb.capacity();
@@ -149,32 +150,34 @@ JSAtom* StringBuffer::finishAtom() {
   }
 
   JSAtom* atom = AtomizeChars(cx_, twoByteChars().begin(), len);
   twoByteChars().clear();
   return atom;
 }
 
 const frontend::ParserAtom* StringBuffer::finishParserAtom(
-    frontend::ParserAtomsTable& parserAtoms) {
+    frontend::CompilationInfo& compilationInfo) {
   size_t len = length();
   if (len == 0) {
     return cx_->parserNames().empty;
   }
 
   if (isLatin1()) {
-    auto result = parserAtoms.internLatin1(cx_, latin1Chars().begin(), len);
+    auto result = compilationInfo.stencil.parserAtoms.internLatin1(
+        cx_, latin1Chars().begin(), len);
     if (result.isErr()) {
       return nullptr;
     }
     latin1Chars().clear();
     return result.unwrap();
   }
 
-  auto result = parserAtoms.internChar16(cx_, twoByteChars().begin(), len);
+  auto result = compilationInfo.stencil.parserAtoms.internChar16(
+      cx_, twoByteChars().begin(), len);
   if (result.isErr()) {
     return nullptr;
   }
   twoByteChars().clear();
   return result.unwrap();
 }
 
 bool js::ValueToStringBufferSlow(JSContext* cx, const Value& arg,
--- a/js/src/util/StringBuffer.h
+++ b/js/src/util/StringBuffer.h
@@ -14,17 +14,17 @@
 #include "js/Vector.h"
 #include "vm/JSContext.h"
 
 namespace js {
 
 namespace frontend {
 
 class ParserAtom;
-class ParserAtomsTable;
+struct CompilationInfo;
 
 }  // namespace frontend
 
 class StringBufferAllocPolicy {
   TempAllocPolicy impl_;
 
   const arena_id_t& arenaId_;
 
@@ -315,17 +315,17 @@ class StringBuffer {
   Latin1Char* rawLatin1Begin() { return begin<Latin1Char>(); }
   Latin1Char* rawLatin1End() { return end<Latin1Char>(); }
   const Latin1Char* rawLatin1Begin() const { return begin<Latin1Char>(); }
   const Latin1Char* rawLatin1End() const { return end<Latin1Char>(); }
 
   /* Identical to finishString() except that an atom is created. */
   JSAtom* finishAtom();
   const frontend::ParserAtom* finishParserAtom(
-      frontend::ParserAtomsTable& parserAtoms);
+      frontend::CompilationInfo& compilationInfo);
 
   /*
    * Creates a raw string from the characters in this buffer.  The string is
    * exactly the characters in this buffer (inflated to TwoByte), it is *not*
    * null-terminated unless the last appended character was '\0'.
    */
   char16_t* stealChars();
 };
--- a/js/src/vm/Instrumentation.cpp
+++ b/js/src/vm/Instrumentation.cpp
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "vm/Instrumentation.h"
 
 #include "jsapi.h"
 
 #include "debugger/DebugAPI.h"
-#include "frontend/ParserAtom.h"
+#include "frontend/CompilationInfo.h"
 #include "js/Object.h"  // JS::GetReservedSlot
 #include "proxy/DeadObjectProxy.h"
 
 #include "vm/JSObject-inl.h"
 
 namespace js {
 
 RealmInstrumentation::RealmInstrumentation(Zone* zone, JSObject* callback,
@@ -90,21 +90,21 @@ static bool StringToInstrumentationKind(
   }
 
   JS_ReportErrorASCII(cx, "Unknown instrumentation kind");
   return false;
 }
 
 /* static */
 const frontend::ParserAtom* RealmInstrumentation::getInstrumentationKindName(
-    JSContext* cx, frontend::ParserAtomsTable& parserAtoms,
+    JSContext* cx, frontend::CompilationInfo& compilationInfo,
     InstrumentationKind kind) {
   for (size_t i = 0; i < mozilla::ArrayLength(instrumentationNames); i++) {
     if (kind == (InstrumentationKind)(1 << i)) {
-      return parserAtoms
+      return compilationInfo.stencil.parserAtoms
           .internAscii(cx, instrumentationNames[i],
                        strlen(instrumentationNames[i]))
           .unwrapOr(nullptr);
     }
   }
   MOZ_CRASH("Unexpected instrumentation kind");
 }
 
--- a/js/src/vm/Instrumentation.h
+++ b/js/src/vm/Instrumentation.h
@@ -8,18 +8,18 @@
 #define vm_Instrumentation_h
 
 #include "js/UniquePtr.h"
 #include "vm/GlobalObject.h"
 
 namespace js {
 
 namespace frontend {
+struct CompilationInfo;
 class ParserAtom;
-class ParserAtomsTable;
 }  // namespace frontend
 
 // Logic related to instrumentation which can be performed in a realm.
 
 #define FOR_EACH_INSTRUMENTATION_KIND(MACRO)                                \
   /* The main entry point of a script. */                                   \
   MACRO(Main, "main", 1 << 0)                                               \
   /* Points other than the main entry point where a frame for the script */ \
@@ -65,17 +65,17 @@ class RealmInstrumentation {
 
   static JSObject* getCallback(GlobalObject* global);
 
   // Get the mask of operation kinds which should be instrumented.
   static uint32_t getInstrumentationKinds(GlobalObject* global);
 
   // Get the string name of an instrumentation kind.
   static const frontend::ParserAtom* getInstrumentationKindName(
-      JSContext* cx, frontend::ParserAtomsTable& parserAtoms,
+      JSContext* cx, frontend::CompilationInfo& compilationInfo,
       InstrumentationKind kind);
 
   static bool getScriptId(JSContext* cx, Handle<GlobalObject*> global,
                           HandleScript script, int32_t* id);
 
   static bool setActive(JSContext* cx, Handle<GlobalObject*> global,
                         Debugger* dbg, bool active);
 
--- a/js/src/vm/Scope.cpp
+++ b/js/src/vm/Scope.cpp
@@ -8,18 +8,18 @@
 
 #include "mozilla/OperatorNewExtensions.h"  // mozilla::KnownNotNull
 #include "mozilla/ScopeExit.h"
 
 #include <memory>
 #include <new>
 
 #include "builtin/ModuleObject.h"
-#include "frontend/CompilationInfo.h"  // CompiltionAtomCache, CompilationInput, CompilationStencil, CompilationGCOutput
-#include "frontend/Parser.h"           // Copy*ScopeData
+#include "frontend/CompilationInfo.h"
+#include "frontend/Parser.h"  // Copy*ScopeData
 #include "frontend/SharedContext.h"
 #include "frontend/Stencil.h"
 #include "gc/Allocator.h"
 #include "gc/MaybeRooted.h"
 #include "util/StringBuffer.h"
 #include "vm/EnvironmentObject.h"
 #include "vm/JSScript.h"
 #include "wasm/WasmInstance.h"
@@ -145,34 +145,35 @@ Shape* js::CreateEnvironmentShape(JSCont
       }
     }
   }
 
   return shape;
 }
 
 Shape* js::CreateEnvironmentShape(
-    JSContext* cx, frontend::CompilationAtomCache& atomCache,
+    JSContext* cx, frontend::CompilationInfo& compilationInfo,
     AbstractBindingIter<const frontend::ParserAtom>& bi, const JSClass* cls,
     uint32_t numSlots, uint32_t baseShapeFlags) {
   RootedShape shape(cx,
                     EmptyEnvironmentShape(cx, cls, numSlots, baseShapeFlags));
   if (!shape) {
     return nullptr;
   }
 
   RootedAtom name(cx);
   StackBaseShape stackBase(cls, baseShapeFlags);
   for (; bi; bi++) {
     BindingLocation loc = bi.location();
     if (loc.kind() == BindingLocation::Kind::Environment) {
-      name = bi.name()->toJSAtom(cx, atomCache);
-      if (!name) {
+      auto mbJSAtom = bi.name()->toJSAtom(cx, compilationInfo);
+      if (mbJSAtom.isErr()) {
         return nullptr;
       }
+      name = mbJSAtom.unwrap();
       MOZ_ASSERT(name);
       cx->markAtom(name);
       shape = NextEnvironmentShape(cx, name, bi.kind(), loc.slot(), stackBase,
                                    shape);
       if (!shape) {
         return nullptr;
       }
     }
@@ -290,32 +291,32 @@ static UniquePtr<AbstractScopeData<Concr
   if (data) {
     new (data) Data(length);
   }
   return UniquePtr<Data>(data);
 }
 
 template <typename ConcreteScope>
 static UniquePtr<typename ConcreteScope::Data> LiftParserScopeData(
-    JSContext* cx, frontend::CompilationAtomCache& atomCache,
+    JSContext* cx, frontend::CompilationInfo& compilationInfo,
     ParserScopeData<ConcreteScope>* data) {
   using ConcreteData = typename ConcreteScope::Data;
 
   // Convert all scope ParserAtoms to rooted JSAtoms.
   // Rooting is necessary as conversion can gc.
   JS::RootedVector<JSAtom*> jsatoms(cx);
   if (!jsatoms.reserve(data->length)) {
     return nullptr;
   }
   auto* names = data->trailingNames.start();
   uint32_t length = data->length;
   for (size_t i = 0; i < length; i++) {
     JSAtom* jsatom = nullptr;
     if (names[i].name()) {
-      jsatom = names[i].name()->toJSAtom(cx, atomCache);
+      jsatom = names[i].name()->toJSAtom(cx, compilationInfo).unwrapOr(nullptr);
       if (jsatom == nullptr) {
         return nullptr;
       }
     }
     jsatoms.infallibleAppend(jsatom);
   }
 
   // Allocate a new scope-data of the right kind.
@@ -2196,116 +2197,120 @@ bool ScopeStencil::createForWithScope(JS
     js::ReportOutOfMemory(cx);
     return false;
   }
   return true;
 }
 
 template <typename SpecificScopeT>
 UniquePtr<typename SpecificScopeT::Data> ScopeStencil::createSpecificScopeData(
-    JSContext* cx, CompilationAtomCache& atomCache,
+    JSContext* cx, CompilationInfo& compilationInfo,
     CompilationGCOutput& gcOutput) const {
-  return LiftParserScopeData<SpecificScopeT>(cx, atomCache,
+  return LiftParserScopeData<SpecificScopeT>(cx, compilationInfo,
                                              &data<SpecificScopeT>());
 }
 
 template <>
 UniquePtr<FunctionScope::Data>
 ScopeStencil::createSpecificScopeData<FunctionScope>(
-    JSContext* cx, CompilationAtomCache& atomCache,
+    JSContext* cx, CompilationInfo& compilationInfo,
     CompilationGCOutput& gcOutput) const {
   // Allocate a new vm function-scope.
   UniquePtr<FunctionScope::Data> data = LiftParserScopeData<FunctionScope>(
-      cx, atomCache, &this->data<FunctionScope>());
+      cx, compilationInfo, &this->data<FunctionScope>());
   if (!data) {
     return nullptr;
   }
 
   // Initialize the GCPtrs in the FunctionScope::Data.
   data->canonicalFunction = gcOutput.functions[*functionIndex_];
 
   return data;
 }
 
 template <>
 UniquePtr<ModuleScope::Data> ScopeStencil::createSpecificScopeData<ModuleScope>(
-    JSContext* cx, CompilationAtomCache& atomCache,
+    JSContext* cx, CompilationInfo& compilationInfo,
     CompilationGCOutput& gcOutput) const {
   // Allocate a new vm module-scope.
   UniquePtr<ModuleScope::Data> data = LiftParserScopeData<ModuleScope>(
-      cx, atomCache, &this->data<ModuleScope>());
+      cx, compilationInfo, &this->data<ModuleScope>());
   if (!data) {
     return nullptr;
   }
 
   // Initialize the GCPtrs in the ModuleScope::Data.
   data->module = gcOutput.module;
 
   return data;
 }
 
 // WithScope does not use binding data.
 template <>
 Scope* ScopeStencil::createSpecificScope<WithScope, std::nullptr_t>(
-    JSContext* cx, CompilationInput& input,
+    JSContext* cx, CompilationInfo& compilationInfo,
     CompilationGCOutput& gcOutput) const {
-  RootedScope enclosingScope(cx, enclosingExistingScope(input, gcOutput));
+  RootedScope enclosingScope(
+      cx, enclosing(compilationInfo).existingScope(gcOutput));
   return Scope::create(cx, ScopeKind::With, enclosingScope, nullptr);
 }
 
 // GlobalScope has bindings but no environment shape.
 template <>
 Scope* ScopeStencil::createSpecificScope<GlobalScope, std::nullptr_t>(
-    JSContext* cx, CompilationInput& input,
+    JSContext* cx, CompilationInfo& compilationInfo,
     CompilationGCOutput& gcOutput) const {
   Rooted<UniquePtr<GlobalScope::Data>> rootedData(
-      cx, createSpecificScopeData<GlobalScope>(cx, input.atomCache, gcOutput));
+      cx, createSpecificScopeData<GlobalScope>(cx, compilationInfo, gcOutput));
   if (!rootedData) {
     return nullptr;
   }
 
-  MOZ_ASSERT(!enclosing_);
-  MOZ_ASSERT(!input.enclosingScope);
+  MOZ_ASSERT(enclosing(compilationInfo).isNullptr());
 
   // Because we already baked the data here, we needn't do it again.
   return Scope::create<GlobalScope>(cx, kind(), nullptr, nullptr, &rootedData);
 }
 
 template <typename SpecificScopeT, typename SpecificEnvironmentT>
-Scope* ScopeStencil::createSpecificScope(JSContext* cx, CompilationInput& input,
+Scope* ScopeStencil::createSpecificScope(JSContext* cx,
+                                         CompilationInfo& compilationInfo,
                                          CompilationGCOutput& gcOutput) const {
   Rooted<UniquePtr<typename SpecificScopeT::Data>> rootedData(
       cx,
-      createSpecificScopeData<SpecificScopeT>(cx, input.atomCache, gcOutput));
+      createSpecificScopeData<SpecificScopeT>(cx, compilationInfo, gcOutput));
   if (!rootedData) {
     return nullptr;
   }
 
   RootedShape shape(cx);
   if (!createSpecificShape<SpecificEnvironmentT>(
           cx, kind(), rootedData.get().get(), &shape)) {
     return nullptr;
   }
 
-  RootedScope enclosingScope(cx, enclosingExistingScope(input, gcOutput));
+  RootedScope enclosingScope(
+      cx, enclosing(compilationInfo).existingScope(gcOutput));
 
   // Because we already baked the data here, we needn't do it again.
   return Scope::create<SpecificScopeT>(cx, kind(), enclosingScope, shape,
                                        &rootedData);
 }
 
 template Scope* ScopeStencil::createSpecificScope<FunctionScope, CallObject>(
-    JSContext* cx, CompilationInput& input,
+    JSContext* cx, CompilationInfo& compilationInfo,
     CompilationGCOutput& gcOutput) const;
 template Scope*
 ScopeStencil::createSpecificScope<LexicalScope, LexicalEnvironmentObject>(
-    JSContext* cx, CompilationInput& input,
+    JSContext* cx, CompilationInfo& compilationInfo,
     CompilationGCOutput& gcOutput) const;
-template Scope* ScopeStencil::createSpecificScope<
-    EvalScope, VarEnvironmentObject>(JSContext* cx, CompilationInput& input,
-                                     CompilationGCOutput& gcOutput) const;
-template Scope* ScopeStencil::createSpecificScope<
-    VarScope, VarEnvironmentObject>(JSContext* cx, CompilationInput& input,
-                                    CompilationGCOutput& gcOutput) const;
+template Scope*
+ScopeStencil::createSpecificScope<EvalScope, VarEnvironmentObject>(
+    JSContext* cx, CompilationInfo& compilationInfo,
+    CompilationGCOutput& gcOutput) const;
+template Scope*
+ScopeStencil::createSpecificScope<VarScope, VarEnvironmentObject>(
+    JSContext* cx, CompilationInfo& compilationInfo,
+    CompilationGCOutput& gcOutput) const;
 template Scope*
 ScopeStencil::createSpecificScope<ModuleScope, ModuleEnvironmentObject>(
-    JSContext* cx, CompilationInput& input,
+    JSContext* cx, CompilationInfo& compilationInfo,
     CompilationGCOutput& gcOutput) const;
--- a/js/src/vm/Scope.h
+++ b/js/src/vm/Scope.h
@@ -21,17 +21,17 @@
 #include "vm/JSObject.h"
 #include "vm/Printer.h"  // GenericPrinter
 #include "vm/ScopeKind.h"
 #include "vm/Xdr.h"
 
 namespace js {
 
 namespace frontend {
-struct CompilationAtomCache;
+struct CompilationInfo;
 class ScriptStencil;
 class ScopeStencil;
 class ParserAtom;
 };  // namespace frontend
 
 template <typename NameT>
 class AbstractBaseScopeData;
 
@@ -1632,17 +1632,17 @@ class MutableWrappedPtrOperations<ScopeI
   void operator++(int) { iter().operator++(1); }
 };
 
 Shape* CreateEnvironmentShape(JSContext* cx, BindingIter& bi,
                               const JSClass* cls, uint32_t numSlots,
                               uint32_t baseShapeFlags);
 
 Shape* CreateEnvironmentShape(
-    JSContext* cx, frontend::CompilationAtomCache& atomCache,
+    JSContext* cx, frontend::CompilationInfo& compilationInfo,
     AbstractBindingIter<const frontend::ParserAtom>& bi, const JSClass* cls,
     uint32_t numSlots, uint32_t baseShapeFlags);
 
 Shape* EmptyEnvironmentShape(JSContext* cx, const JSClass* cls,
                              uint32_t numSlots, uint32_t baseShapeFlags);
 
 }  // namespace js
 
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -31,17 +31,16 @@
 #include <algorithm>
 #include <new>
 
 #include "jsmath.h"
 
 #include "frontend/FunctionSyntaxKind.h"  // FunctionSyntaxKind
 #include "frontend/ParseNode.h"
 #include "frontend/Parser.h"
-#include "frontend/ParserAtom.h"
 #include "frontend/SharedContext.h"  // TopLevelFunction
 #include "gc/Policy.h"
 #include "js/BuildId.h"  // JS::BuildIdCharVector
 #include "js/MemoryMetrics.h"
 #include "js/Printf.h"
 #include "js/ScalarType.h"  // js::Scalar::Type
 #include "js/SourceText.h"
 #include "js/StableStringChars.h"
@@ -1311,17 +1310,17 @@ class MOZ_STACK_CLASS ModuleValidatorSha
   using SigSet = HashSet<HashableSig, HashableSig>;
   using FuncImportMap = HashMap<NamedSig, uint32_t, NamedSig>;
   using GlobalMap = HashMap<const ParserName*, Global*>;
   using MathNameMap = HashMap<const ParserName*, MathBuiltin>;
   using ArrayViewVector = Vector<ArrayView>;
 
  protected:
   JSContext* cx_;
-  ParserAtomsTable& parserAtoms_;
+  CompilationInfo& compilationInfo_;
   FunctionNode* moduleFunctionNode_;
   const ParserName* moduleFunctionName_;
   const ParserName* globalArgumentName_ = nullptr;
   const ParserName* importArgumentName_ = nullptr;
   const ParserName* bufferArgumentName_ = nullptr;
   MathNameMap standardLibraryMathNames_;
 
   // Validation-internal state:
@@ -1339,20 +1338,20 @@ class MOZ_STACK_CLASS ModuleValidatorSha
   MutableAsmJSMetadata asmJSMetadata_;
 
   // Error reporting:
   UniqueChars errorString_ = nullptr;
   uint32_t errorOffset_ = UINT32_MAX;
   bool errorOverRecursed_ = false;
 
  protected:
-  ModuleValidatorShared(JSContext* cx, ParserAtomsTable& parserAtoms,
+  ModuleValidatorShared(JSContext* cx, CompilationInfo& compilationInfo,
                         FunctionNode* moduleFunctionNode)
       : cx_(cx),
-        parserAtoms_(parserAtoms),
+        compilationInfo_(compilationInfo),
         moduleFunctionNode_(moduleFunctionNode),
         moduleFunctionName_(FunctionName(moduleFunctionNode)),
         standardLibraryMathNames_(cx),
         validationLifo_(VALIDATION_LIFO_DEFAULT_CHUNK_SIZE),
         funcDefs_(cx),
         tables_(cx),
         globalMap_(cx),
         sigSet_(cx),
@@ -1380,17 +1379,18 @@ class MOZ_STACK_CLASS ModuleValidatorSha
         {"abs", AsmJSMathBuiltin_abs},       {"atan2", AsmJSMathBuiltin_atan2},
         {"imul", AsmJSMathBuiltin_imul},     {"clz32", AsmJSMathBuiltin_clz32},
         {"fround", AsmJSMathBuiltin_fround}, {"min", AsmJSMathBuiltin_min},
         {"max", AsmJSMathBuiltin_max},
     };
 
     auto AddMathFunction = [this](const char* name,
                                   AsmJSMathBuiltinFunction func) {
-      auto mbAtom = parserAtoms_.internAscii(cx_, name, strlen(name));
+      auto mbAtom = compilationInfo_.stencil.parserAtoms.internAscii(
+          cx_, name, strlen(name));
       if (mbAtom.isErr()) {
         return false;
       }
       MathBuiltin builtin(func);
       return this->standardLibraryMathNames_.putNew(mbAtom.unwrap()->asName(),
                                                     builtin);
     };
 
@@ -1410,17 +1410,18 @@ class MOZ_STACK_CLASS ModuleValidatorSha
         {"LOG2E", M_LOG2E},
         {"LOG10E", M_LOG10E},
         {"PI", M_PI},
         {"SQRT1_2", M_SQRT1_2},
         {"SQRT2", M_SQRT2},
     };
 
     auto AddMathConstant = [this](const char* name, double cst) {
-      auto mbAtom = parserAtoms_.internAscii(cx_, name, strlen(name));
+      auto mbAtom = compilationInfo_.stencil.parserAtoms.internAscii(
+          cx_, name, strlen(name));
       if (mbAtom.isErr()) {
         return false;
       }
       MathBuiltin builtin(cst);
       return this->standardLibraryMathNames_.putNew(mbAtom.unwrap()->asName(),
                                                     builtin);
     };
 
@@ -1848,19 +1849,19 @@ class MOZ_STACK_CLASS ModuleValidatorSha
 // the module and the validation of function's pointer tables. It also finishes
 // the compilation of all the module's stubs.
 template <typename Unit>
 class MOZ_STACK_CLASS ModuleValidator : public ModuleValidatorShared {
  private:
   AsmJSParser<Unit>& parser_;
 
  public:
-  ModuleValidator(JSContext* cx, ParserAtomsTable& parserAtoms,
+  ModuleValidator(JSContext* cx, CompilationInfo& compilationInfo,
                   AsmJSParser<Unit>& parser, FunctionNode* moduleFunctionNode)
-      : ModuleValidatorShared(cx, parserAtoms, moduleFunctionNode),
+      : ModuleValidatorShared(cx, compilationInfo, moduleFunctionNode),
         parser_(parser) {}
 
   ~ModuleValidator() {
     if (errorString_) {
       MOZ_ASSERT(errorOffset_ != UINT32_MAX);
       typeFailure(errorOffset_, errorString_.get());
     }
     if (errorOverRecursed_) {
@@ -6348,24 +6349,24 @@ static bool CheckModuleEnd(ModuleValidat
         "top-level export (return) must be the last statement");
   }
 
   m.parser().tokenStream.anyCharsAccess().ungetToken();
   return true;
 }
 
 template <typename Unit>
-static SharedModule CheckModule(JSContext* cx, ParserAtomsTable& parserAtoms,
+static SharedModule CheckModule(JSContext* cx, CompilationInfo& compilationInfo,
                                 AsmJSParser<Unit>& parser, ParseNode* stmtList,
                                 unsigned* time) {
   int64_t before = PRMJ_Now();
 
   FunctionNode* moduleFunctionNode = parser.pc_->functionBox()->functionNode;
 
-  ModuleValidator<Unit> m(cx, parserAtoms, parser, moduleFunctionNode);
+  ModuleValidator<Unit> m(cx, compilationInfo, parser, moduleFunctionNode);
   if (!m.init()) {
     return nullptr;
   }
 
   if (!CheckFunctionHead(m, moduleFunctionNode)) {
     return nullptr;
   }
 
@@ -7043,30 +7044,31 @@ static bool EstablishPreconditions(JSCon
     return TypeFailureWarning(
         parser, "Disabled by class constructor or method context");
   }
 
   return true;
 }
 
 template <typename Unit>
-static bool DoCompileAsmJS(JSContext* cx, ParserAtomsTable& parserAtoms,
+static bool DoCompileAsmJS(JSContext* cx, CompilationInfo& compilationInfo,
                            AsmJSParser<Unit>& parser, ParseNode* stmtList,
                            bool* validated) {
   *validated = false;
 
   // Various conditions disable asm.js optimizations.
   if (!EstablishPreconditions(cx, parser)) {
     return NoExceptionPending(cx);
   }
 
   // "Checking" parses, validates and compiles, producing a fully compiled
   // WasmModuleObject as result.
   unsigned time;
-  SharedModule module = CheckModule(cx, parserAtoms, parser, stmtList, &time);
+  SharedModule module =
+      CheckModule(cx, compilationInfo, parser, stmtList, &time);
   if (!module) {
     return NoExceptionPending(cx);
   }
 
   // Finished! Save the ref-counted module on the FunctionBox. When JSFunctions
   // are eventually allocated we will create an asm.js constructor for it.
   FunctionBox* funbox = parser.pc_->functionBox();
   MOZ_ASSERT(funbox->isInterpreted());
@@ -7076,26 +7078,26 @@ static bool DoCompileAsmJS(JSContext* cx
 
   // Success! Write to the console with a "warning" message indicating
   // total compilation time.
   *validated = true;
   SuccessfulValidation(parser, time);
   return NoExceptionPending(cx);
 }
 
-bool js::CompileAsmJS(JSContext* cx, ParserAtomsTable& parserAtoms,
+bool js::CompileAsmJS(JSContext* cx, CompilationInfo& compilationInfo,
                       AsmJSParser<char16_t>& parser, ParseNode* stmtList,
                       bool* validated) {
-  return DoCompileAsmJS(cx, parserAtoms, parser, stmtList, validated);
-}
-
-bool js::CompileAsmJS(JSContext* cx, ParserAtomsTable& parserAtoms,
+  return DoCompileAsmJS(cx, compilationInfo, parser, stmtList, validated);
+}
+
+bool js::CompileAsmJS(JSContext* cx, CompilationInfo& compilationInfo,
                       AsmJSParser<Utf8Unit>& parser, ParseNode* stmtList,
                       bool* validated) {
-  return DoCompileAsmJS(cx, parserAtoms, parser, stmtList, validated);
+  return DoCompileAsmJS(cx, compilationInfo, parser, stmtList, validated);
 }
 
 /*****************************************************************************/
 // asm.js testing functions
 
 bool js::IsAsmJSModuleNative(Native native) {
   return native == InstantiateAsmJS;
 }
--- a/js/src/wasm/AsmJS.h
+++ b/js/src/wasm/AsmJS.h
@@ -38,17 +38,18 @@ template <typename T>
 class Handle;
 
 }  // namespace JS
 
 namespace js {
 
 namespace frontend {
 
-class ParserAtomsTable;
+struct CompilationInfo;
+
 class ParseContext;
 class ParseNode;
 
 template <class ParseHandler, typename CharT>
 class Parser;
 class FullParseHandler;
 
 }  // namespace frontend
@@ -58,27 +59,25 @@ using AsmJSParser = frontend::Parser<fro
 
 // This function takes over parsing of a function starting with "use asm". The
 // return value indicates whether an error was reported which the caller should
 // propagate. If no error was reported, the function may still fail to validate
 // as asm.js. In this case, the parser.tokenStream has been advanced an
 // indeterminate amount and the entire function should be reparsed from the
 // beginning.
 
-extern MOZ_MUST_USE bool CompileAsmJS(JSContext* cx,
-                                      frontend::ParserAtomsTable& parserAtoms,
-                                      AsmJSParser<mozilla::Utf8Unit>& parser,
-                                      frontend::ParseNode* stmtList,
-                                      bool* validated);
+extern MOZ_MUST_USE bool CompileAsmJS(
+    JSContext* cx, frontend::CompilationInfo& compilationInfo,
+    AsmJSParser<mozilla::Utf8Unit>& parser, frontend::ParseNode* stmtList,
+    bool* validated);
 
-extern MOZ_MUST_USE bool CompileAsmJS(JSContext* cx,
-                                      frontend::ParserAtomsTable& parserAtoms,
-                                      AsmJSParser<char16_t>& parser,
-                                      frontend::ParseNode* stmtList,
-                                      bool* validated);
+extern MOZ_MUST_USE bool CompileAsmJS(
+    JSContext* cx, frontend::CompilationInfo& compilationInfo,
+    AsmJSParser<char16_t>& parser, frontend::ParseNode* stmtList,
+    bool* validated);
 
 // asm.js module/export queries:
 
 extern bool IsAsmJSModuleNative(JSNative native);
 
 extern bool IsAsmJSModule(JSFunction* fun);
 
 extern bool IsAsmJSFunction(JSFunction* fun);