Bug 1674351 - Part 4: Move ParserAtomVector out of ParserAtomsTable. r=tcampbell
authorTooru Fujisawa <arai_a@mac.com>
Thu, 05 Nov 2020 15:32:44 +0000
changeset 556082 6f1bf8c8117fa09123eaf86c59fba05fcc600f54
parent 556081 7a4ce0db75ba7d9d36d61479ae71b42b7440f217
child 556083 e4312f01e2d6a3b6478cf81ae92357ce145da689
push id130313
push userarai_a@mac.com
push dateThu, 05 Nov 2020 20:22:51 +0000
treeherderautoland@f0df0bb8123d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstcampbell
bugs1674351
milestone84.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1674351 - Part 4: Move ParserAtomVector out of ParserAtomsTable. r=tcampbell Now ParserAtomsTable is part of CompilationState, or stack variable inside XDRStencilDecoder. It's always created after CompilationInfo is stored into Rooted, and now we don't have to worry about LifoAlloc pointer in move constructor. Differential Revision: https://phabricator.services.mozilla.com/D95842
js/src/builtin/ReflectParse.cpp
js/src/debugger/Debugger.cpp
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/CompilationInfo.h
js/src/frontend/Frontend2.cpp
js/src/frontend/Parser.cpp
js/src/frontend/ParserAtom.cpp
js/src/frontend/ParserAtom.h
js/src/frontend/Stencil.cpp
js/src/jsapi-tests/testParserAtom.cpp
js/src/shell/js.cpp
js/src/vm/CompilationAndEvaluation.cpp
js/src/vm/HelperThreads.cpp
js/src/vm/Xdr.cpp
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -3777,18 +3777,18 @@ static bool reflect_parse(JSContext* cx,
     }
   } else {
     if (!compilationInfo.get().input.initForModule(cx)) {
       return false;
     }
   }
 
   LifoAllocScope allocScope(&cx->tempLifoAlloc());
-  frontend::CompilationState compilationState(
-      cx, allocScope, options, compilationInfo.get().stencil.parserAtoms);
+  frontend::CompilationState compilationState(cx, allocScope, options,
+                                              compilationInfo.get().stencil);
 
   Parser<FullParseHandler, char16_t> parser(
       cx, options, chars.begin().get(), chars.length(),
       /* foldConstants = */ false, compilationInfo.get(), compilationState,
       nullptr, nullptr);
   if (!parser.checkOptions()) {
     return false;
   }
--- a/js/src/debugger/Debugger.cpp
+++ b/js/src/debugger/Debugger.cpp
@@ -6024,18 +6024,18 @@ bool Debugger::isCompilableUnit(JSContex
   CompileOptions options(cx);
   Rooted<frontend::CompilationInfo> compilationInfo(
       cx, frontend::CompilationInfo(cx, options));
   if (!compilationInfo.get().input.initForGlobal(cx)) {
     return false;
   }
 
   LifoAllocScope allocScope(&cx->tempLifoAlloc());
-  frontend::CompilationState compilationState(
-      cx, allocScope, options, compilationInfo.get().stencil.parserAtoms);
+  frontend::CompilationState compilationState(cx, allocScope, options,
+                                              compilationInfo.get().stencil);
 
   JS::AutoSuppressWarningReporter suppressWarnings(cx);
   frontend::Parser<frontend::FullParseHandler, char16_t> parser(
       cx, options, chars.twoByteChars(), length,
       /* foldConstants = */ true, compilationInfo.get(), compilationState,
       nullptr, nullptr);
   if (!parser.checkOptions() || !parser.parse()) {
     // We ran into an error. If it was because we ran out of memory we report
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -95,22 +95,22 @@ class MOZ_STACK_CLASS frontend::SourceAw
   Maybe<Parser<SyntaxParseHandler, Unit>> syntaxParser;
   Maybe<Parser<FullParseHandler, Unit>> parser;
 
   using TokenStreamPosition = frontend::TokenStreamPosition<Unit>;
 
  protected:
   explicit SourceAwareCompiler(JSContext* cx, LifoAllocScope& allocScope,
                                const JS::ReadOnlyCompileOptions& options,
-                               ParserAtomsTable& parserAtoms,
+                               CompilationStencil& stencil,
                                SourceText<Unit>& sourceBuffer,
                                js::Scope* enclosingScope = nullptr,
                                JSObject* enclosingEnv = nullptr)
       : sourceBuffer_(sourceBuffer),
-        compilationState_(cx, allocScope, options, parserAtoms, enclosingScope,
+        compilationState_(cx, allocScope, options, stencil, enclosingScope,
                           enclosingEnv) {
     MOZ_ASSERT(sourceBuffer_.get() != nullptr);
   }
 
   // Call this before calling compile{Global,Eval}Script.
   MOZ_MUST_USE bool createSourceAndParser(JSContext* cx,
                                           CompilationInfo& compilationInfo);
 
@@ -156,21 +156,21 @@ class MOZ_STACK_CLASS frontend::ScriptCo
   using Base::emplaceEmitter;
   using Base::handleParseFailure;
 
   using typename Base::TokenStreamPosition;
 
  public:
   explicit ScriptCompiler(JSContext* cx, LifoAllocScope& allocScope,
                           const JS::ReadOnlyCompileOptions& options,
-                          ParserAtomsTable& parserAtoms,
+                          CompilationStencil& stencil,
                           SourceText<Unit>& sourceBuffer,
                           js::Scope* enclosingScope = nullptr,
                           JSObject* enclosingEnv = nullptr)
-      : Base(cx, allocScope, options, parserAtoms, sourceBuffer, enclosingScope,
+      : Base(cx, allocScope, options, stencil, sourceBuffer, enclosingScope,
              enclosingEnv) {}
 
   using Base::createSourceAndParser;
 
   bool compileScriptToStencil(JSContext* cx, CompilationInfo& compilationInfo,
                               SharedContext* sc);
 };
 
@@ -245,19 +245,19 @@ static bool CompileGlobalScriptToStencil
   if (!fallback) {
     return true;
   }
 #endif  // JS_ENABLE_SMOOSH
 
   AutoAssertReportedException assertException(cx);
 
   LifoAllocScope allocScope(&cx->tempLifoAlloc());
-  frontend::ScriptCompiler<Unit> compiler(
-      cx, allocScope, compilationInfo.input.options,
-      compilationInfo.stencil.parserAtoms, srcBuf);
+  frontend::ScriptCompiler<Unit> compiler(cx, allocScope,
+                                          compilationInfo.input.options,
+                                          compilationInfo.stencil, srcBuf);
 
   if (!compiler.createSourceAndParser(cx, compilationInfo)) {
     return false;
   }
 
   SourceExtent extent = SourceExtent::makeGlobalExtent(
       srcBuf.length(), compilationInfo.input.options.lineno,
       compilationInfo.input.options.column);
@@ -445,18 +445,17 @@ static JSScript* CompileEvalScriptImpl(
   if (!compilationInfo.get().input.initForEval(cx, enclosingScope)) {
     return nullptr;
   }
 
   LifoAllocScope allocScope(&cx->tempLifoAlloc());
 
   frontend::ScriptCompiler<Unit> compiler(
       cx, allocScope, compilationInfo.get().input.options,
-      compilationInfo.get().stencil.parserAtoms, srcBuf, enclosingScope,
-      enclosingEnv);
+      compilationInfo.get().stencil, srcBuf, enclosingScope, enclosingEnv);
   if (!compiler.createSourceAndParser(cx, compilationInfo.get())) {
     return nullptr;
   }
 
   uint32_t len = srcBuf.length();
   SourceExtent extent = SourceExtent::makeGlobalExtent(
       len, compilationInfo.get().input.options.lineno,
       compilationInfo.get().input.options.column);
@@ -493,21 +492,21 @@ class MOZ_STACK_CLASS frontend::ModuleCo
   using Base::compilationState_;
   using Base::createSourceAndParser;
   using Base::emplaceEmitter;
   using Base::parser;
 
  public:
   explicit ModuleCompiler(JSContext* cx, LifoAllocScope& allocScope,
                           const JS::ReadOnlyCompileOptions& options,
-                          ParserAtomsTable& parserAtoms,
+                          CompilationStencil& stencil,
                           SourceText<Unit>& sourceBuffer,
                           js::Scope* enclosingScope = nullptr,
                           JSObject* enclosingEnv = nullptr)
-      : Base(cx, allocScope, options, parserAtoms, sourceBuffer, enclosingScope,
+      : Base(cx, allocScope, options, stencil, sourceBuffer, enclosingScope,
              enclosingEnv) {}
 
   bool compile(JSContext* cx, CompilationInfo& compilationInfo);
 };
 
 template <typename Unit>
 class MOZ_STACK_CLASS frontend::StandaloneFunctionCompiler final
     : public SourceAwareCompiler<Unit> {
@@ -521,21 +520,21 @@ class MOZ_STACK_CLASS frontend::Standalo
   using Base::parser;
   using Base::sourceBuffer_;
 
   using typename Base::TokenStreamPosition;
 
  public:
   explicit StandaloneFunctionCompiler(JSContext* cx, LifoAllocScope& allocScope,
                                       const JS::ReadOnlyCompileOptions& options,
-                                      ParserAtomsTable& parserAtoms,
+                                      CompilationStencil& stencil,
                                       SourceText<Unit>& sourceBuffer,
                                       js::Scope* enclosingScope = nullptr,
                                       JSObject* enclosingEnv = nullptr)
-      : Base(cx, allocScope, options, parserAtoms, sourceBuffer, enclosingScope,
+      : Base(cx, allocScope, options, stencil, sourceBuffer, enclosingScope,
              enclosingEnv) {}
 
   using Base::createSourceAndParser;
 
   FunctionNode* parse(JSContext* cx, CompilationInfo& compilationInfo,
                       FunctionSyntaxKind syntaxKind,
                       GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
                       const Maybe<uint32_t>& parameterListEnd);
@@ -889,17 +888,17 @@ static bool ParseModuleToStencilImpl(JSC
                                      CompilationInfo& compilationInfo,
                                      SourceText<Unit>& srcBuf) {
   MOZ_ASSERT(srcBuf.get());
 
   AutoAssertReportedException assertException(cx);
 
   LifoAllocScope allocScope(&cx->tempLifoAlloc());
   ModuleCompiler<Unit> compiler(cx, allocScope, compilationInfo.input.options,
-                                compilationInfo.stencil.parserAtoms, srcBuf);
+                                compilationInfo.stencil, srcBuf);
   if (!compiler.compile(cx, compilationInfo)) {
     return false;
   }
 
   assertException.reset();
   return true;
 }
 
@@ -1015,18 +1014,18 @@ static bool CompileLazyFunctionToStencil
   MOZ_ASSERT(lazy->isReadyForDelazification());
 
   AutoAssertReportedException assertException(cx);
 
   Rooted<JSFunction*> fun(cx, lazy->function());
 
   LifoAllocScope allocScope(&cx->tempLifoAlloc());
   frontend::CompilationState compilationState(
-      cx, allocScope, compilationInfo.input.options,
-      compilationInfo.stencil.parserAtoms, fun->enclosingScope());
+      cx, allocScope, compilationInfo.input.options, compilationInfo.stencil,
+      fun->enclosingScope());
 
   Parser<FullParseHandler, Unit> parser(
       cx, compilationInfo.input.options, units, length,
       /* foldConstants = */ true, compilationInfo, compilationState, nullptr,
       lazy);
   if (!parser.checkOptions()) {
     return false;
   }
@@ -1115,17 +1114,17 @@ static JSFunction* CompileStandaloneFunc
   Rooted<CompilationInfo> compilationInfo(cx, CompilationInfo(cx, options));
   if (!compilationInfo.get().input.initForStandaloneFunction(cx, scope)) {
     return nullptr;
   }
 
   LifoAllocScope allocScope(&cx->tempLifoAlloc());
   StandaloneFunctionCompiler<char16_t> compiler(
       cx, allocScope, compilationInfo.get().input.options,
-      compilationInfo.get().stencil.parserAtoms, srcBuf, enclosingScope);
+      compilationInfo.get().stencil, srcBuf, enclosingScope);
   if (!compiler.createSourceAndParser(cx, compilationInfo.get())) {
     return nullptr;
   }
 
   FunctionNode* parsedFunction =
       compiler.parse(cx, compilationInfo.get(), syntaxKind, generatorKind,
                      asyncKind, parameterListEnd);
   if (!parsedFunction) {
--- a/js/src/frontend/CompilationInfo.h
+++ b/js/src/frontend/CompilationInfo.h
@@ -88,17 +88,17 @@ struct ScopeContext {
   void computeInWith(Scope* scope);
   void computeExternalInitializers(Scope* scope);
   void computeInClass(Scope* scope);
 
   static Scope* determineEffectiveScope(Scope* scope, JSObject* environment);
 };
 
 struct CompilationAtomCache {
-  // Atoms lowered into or converted from CompilationStencil.parserAtoms.
+  // Atoms lowered into or converted from CompilationStencil.parserAtomData.
   //
   // 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;
@@ -189,38 +189,35 @@ struct CompilationInput {
   MOZ_MUST_USE bool assignSource(JSContext* cx,
                                  JS::SourceText<Unit>& sourceBuffer) {
     return source()->assignSource(cx, options, sourceBuffer);
   }
 
   void trace(JSTracer* trc);
 } JS_HAZ_GC_POINTER;
 
+struct CompilationStencil;
+
 struct MOZ_RAII CompilationState {
   // Until we have dealt with Atoms in the front end, we need to hold
   // onto them.
   Directives directives;
 
   ScopeContext scopeContext;
 
   UsedNameTracker usedNames;
   LifoAllocScope& allocScope;
 
-  ParserAtomsTable& parserAtoms;
+  // Table of parser atoms for this compilation.
+  ParserAtomsTable parserAtoms;
 
-  CompilationState(JSContext* cx, LifoAllocScope& alloc,
+  CompilationState(JSContext* cx, LifoAllocScope& frontendAllocScope,
                    const JS::ReadOnlyCompileOptions& options,
-                   ParserAtomsTable& parserAtoms,
-                   Scope* enclosingScope = nullptr,
-                   JSObject* enclosingEnv = nullptr)
-      : directives(options.forceStrictMode()),
-        scopeContext(cx, enclosingScope, enclosingEnv),
-        usedNames(cx),
-        allocScope(alloc),
-        parserAtoms(parserAtoms) {}
+                   CompilationStencil& stencil, Scope* enclosingScope = nullptr,
+                   JSObject* enclosingEnv = nullptr);
 };
 
 // The top level struct of stencil.
 struct CompilationStencil {
   // This holds allocations that do not require destructors to be run but are
   // live until the stencil is released.
   LifoAlloc alloc;
 
@@ -249,41 +246,38 @@ struct CompilationStencil {
   // Module metadata if this is a module compile.
   StencilModuleMetadata moduleMetadata;
 
   // AsmJS modules generated by parsing.
   HashMap<FunctionIndex, RefPtr<const JS::WasmModule>,
           mozilla::DefaultHasher<FunctionIndex>, js::SystemAllocPolicy>
       asmJS;
 
-  // Table of parser atoms for this compilation.
-  ParserAtomsTable parserAtoms;
+  // List of parser atoms for this compilation.
+  ParserAtomVector parserAtomData;
 
   // Parameterized chunk size to use for LifoAlloc.
   static constexpr size_t LifoAllocChunkSize = 512;
 
-  explicit CompilationStencil(JSRuntime* rt)
-      : alloc(LifoAllocChunkSize), parserAtoms(rt, alloc) {}
+  CompilationStencil() : alloc(LifoAllocChunkSize) {}
 
   // We need a move-constructor to work with Rooted, but must be explicit in
   // order to steal the LifoAlloc data.
   CompilationStencil(CompilationStencil&& other) noexcept
       : alloc(LifoAllocChunkSize),
         regExpData(std::move(other.regExpData)),
         bigIntData(std::move(other.bigIntData)),
         objLiteralData(std::move(other.objLiteralData)),
         scriptData(std::move(other.scriptData)),
         scopeData(std::move(other.scopeData)),
         moduleMetadata(std::move(other.moduleMetadata)),
         asmJS(std::move(other.asmJS)),
-        parserAtoms(std::move(other.parserAtoms)) {
-    // Steal the data from the LifoAlloc. Anything that holds a reference to
-    // this will need to be updated.
+        parserAtomData(std::move(other.parserAtomData)) {
+    // Steal the data from the LifoAlloc.
     alloc.steal(&other.alloc);
-    parserAtoms.updateLifoAlloc(alloc);
   }
 
 #if defined(DEBUG) || defined(JS_JITSPEW)
   void dump();
   void dump(js::JSONPrinter& json);
 #endif
 };
 
@@ -417,17 +411,17 @@ struct CompilationInfo {
     size_t asmJSCount = 0;
   };
 
   RewindToken getRewindToken();
   void rewind(const RewindToken& pos);
 
   // Construct a CompilationInfo
   CompilationInfo(JSContext* cx, const JS::ReadOnlyCompileOptions& options)
-      : input(options), stencil(cx->runtime()) {}
+      : input(options) {}
 
   MOZ_MUST_USE bool prepareInputAndStencilForInstantiate(JSContext* cx);
   MOZ_MUST_USE bool prepareGCOutputForInstantiate(
       JSContext* cx, CompilationGCOutput& gcOutput);
 
   MOZ_MUST_USE bool prepareForInstantiate(JSContext* cx,
                                           CompilationGCOutput& gcOutput);
   MOZ_MUST_USE bool instantiateStencils(JSContext* cx,
--- a/js/src/frontend/Frontend2.cpp
+++ b/js/src/frontend/Frontend2.cpp
@@ -14,64 +14,63 @@
 
 #include <stddef.h>  // size_t
 #include <stdint.h>  // uint8_t, uint32_t
 
 #include "jsapi.h"
 
 #include "frontend/AbstractScopePtr.h"  // ScopeIndex
 #include "frontend/BytecodeSection.h"   // EmitScriptThingsVector
-#include "frontend/CompilationInfo.h"   // CompilationInfo
+#include "frontend/CompilationInfo.h"   // CompilationState, CompilationInfo
 #include "frontend/Parser.h"  // NewEmptyLexicalScopeData, NewEmptyGlobalScopeData, NewEmptyVarScopeData, NewEmptyFunctionScopeData
 #include "frontend/ParserAtom.h"        // ParserAtomsTable
 #include "frontend/smoosh_generated.h"  // CVec, Smoosh*, smoosh_*
 #include "frontend/SourceNotes.h"       // SrcNote
 #include "frontend/Stencil.h"  // ScopeStencil, RegExpIndex, FunctionIndex, NullScriptThing
 #include "frontend/TokenStream.h"  // TokenStreamAnyChars
 #include "irregexp/RegExpAPI.h"    // irregexp::CheckPatternSyntax
 #include "js/CharacterEncoding.h"  // JS::UTF8Chars, UTF8CharsToNewTwoByteCharsZ
 #include "js/friend/ErrorMessages.h"  // js::GetErrorMessage, JSMSG_*
 #include "js/GCAPI.h"                 // JS::AutoCheckCannotGC
 #include "js/HeapAPI.h"               // JS::GCCellPtr
 #include "js/RegExpFlags.h"           // JS::RegExpFlag, JS::RegExpFlags
 #include "js/RootingAPI.h"            // JS::MutableHandle
 #include "js/UniquePtr.h"             // js::UniquePtr
-#include "js/Utility.h"        // JS::UniqueTwoByteChars, StringBufferArena
-#include "vm/JSScript.h"       // JSScript
-#include "vm/ScopeKind.h"      // ScopeKind
+#include "js/Utility.h"    // JS::UniqueTwoByteChars, StringBufferArena
+#include "vm/JSScript.h"   // JSScript
+#include "vm/ScopeKind.h"  // ScopeKind
 #include "vm/SharedStencil.h"  // ImmutableScriptData, ScopeNote, TryNote, GCThingIndex
 
 using mozilla::Utf8Unit;
 
 using namespace js::gc;
 using namespace js::frontend;
 using namespace js;
 
 namespace js {
 
 namespace frontend {
 
 // Given the result of SmooshMonkey's parser, Convert the list of atoms into
 // the list of ParserAtoms.
 bool ConvertAtoms(JSContext* cx, const SmooshResult& result,
-                  CompilationInfo& compilationInfo,
+                  CompilationState& compilationState,
                   Vector<const ParserAtom*>& allAtoms) {
   size_t numAtoms = result.all_atoms_len;
 
   if (!allAtoms.reserve(numAtoms)) {
     return false;
   }
 
   for (size_t i = 0; i < numAtoms; i++) {
     auto s = reinterpret_cast<const mozilla::Utf8Unit*>(
         smoosh_get_atom_at(result, i));
     auto len = smoosh_get_atom_len_at(result, i);
     const ParserAtom* atom =
-        compilationInfo.stencil.parserAtoms.internUtf8(cx, s, len)
-            .unwrapOr(nullptr);
+        compilationState.parserAtoms.internUtf8(cx, s, len).unwrapOr(nullptr);
     if (!atom) {
       return false;
     }
     atom->markUsedByStencil();
     allAtoms.infallibleAppend(atom);
   }
 
   return true;
@@ -244,17 +243,18 @@ bool ConvertScopeStencil(JSContext* cx, 
   }
 
   return true;
 }
 
 // Given the result of SmooshMonkey's parser, convert a list of RegExp data
 // into a list of RegExpStencil.
 bool ConvertRegExpData(JSContext* cx, const SmooshResult& result,
-                       CompilationInfo& compilationInfo) {
+                       CompilationInfo& compilationInfo,
+                       CompilationState& compilationState) {
   for (size_t i = 0; i < result.regexps.len; i++) {
     SmooshRegExpItem& item = result.regexps.data[i];
     auto s = smoosh_get_slice_at(result, item.pattern);
     auto len = smoosh_get_slice_len_at(result, item.pattern);
 
     JS::RegExpFlags::Flag flags = JS::RegExpFlag::NoFlags;
     if (item.global) {
       flags |= JS::RegExpFlag::Global;
@@ -295,17 +295,17 @@ bool ConvertRegExpData(JSContext* cx, co
     LifoAllocScope allocScope(&cx->tempLifoAlloc());
     if (!irregexp::CheckPatternSyntax(cx, ts, range, flags)) {
       return false;
     }
 
     const mozilla::Utf8Unit* sUtf8 =
         reinterpret_cast<const mozilla::Utf8Unit*>(s);
     const ParserAtom* atom =
-        compilationInfo.stencil.parserAtoms.internUtf8(cx, sUtf8, len)
+        compilationState.parserAtoms.internUtf8(cx, sUtf8, len)
             .unwrapOr(nullptr);
     if (!atom) {
       return false;
     }
     atom->markUsedByStencil();
 
     RegExpIndex index(compilationInfo.stencil.regExpData.length());
     if (!compilationInfo.stencil.regExpData.emplaceBack(
@@ -557,26 +557,30 @@ bool Smoosh::compileGlobalScriptToStenci
 
   if (result.unimplemented) {
     *unimplemented = true;
     return false;
   }
 
   *unimplemented = false;
 
+  LifoAllocScope allocScope(&cx->tempLifoAlloc());
+
   Vector<const ParserAtom*> allAtoms(cx);
-  if (!ConvertAtoms(cx, result, compilationInfo, allAtoms)) {
+  CompilationState compilationState(
+      cx, allocScope, compilationInfo.input.options, compilationInfo.stencil);
+  if (!ConvertAtoms(cx, result, compilationState, allAtoms)) {
     return false;
   }
 
   if (!ConvertScopeStencil(cx, result, allAtoms, compilationInfo)) {
     return false;
   }
 
-  if (!ConvertRegExpData(cx, result, compilationInfo)) {
+  if (!ConvertRegExpData(cx, result, compilationInfo, compilationState)) {
     return false;
   }
 
   if (!compilationInfo.stencil.scriptData.reserve(result.scripts.len)) {
     js::ReportOutOfMemory(cx);
     return false;
   }
 
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -10292,20 +10292,19 @@ RegExpLiteral* Parser<FullParseHandler, 
     // skip this.
     LifoAllocScope allocScope(&cx_->tempLifoAlloc());
     if (!irregexp::CheckPatternSyntax(cx_, anyChars, range, flags, Some(line),
                                       Some(column))) {
       return nullptr;
     }
   }
 
-  const ParserAtom* atom =
-      this->getCompilationInfo()
-          .stencil.parserAtoms.internChar16(cx_, chars.begin(), chars.length())
-          .unwrapOr(nullptr);
+  const ParserAtom* atom = this->compilationState_.parserAtoms
+                               .internChar16(cx_, chars.begin(), chars.length())
+                               .unwrapOr(nullptr);
   if (!atom) {
     return nullptr;
   }
   atom->markUsedByStencil();
 
   RegExpIndex index(this->getCompilationInfo().stencil.regExpData.length());
   if (!this->getCompilationInfo().stencil.regExpData.emplaceBack(atom, flags)) {
     js::ReportOutOfMemory(cx_);
--- a/js/src/frontend/ParserAtom.cpp
+++ b/js/src/frontend/ParserAtom.cpp
@@ -312,18 +312,21 @@ void ParserAtomEntry::dumpCharsNoQuote(j
   if (hasLatin1Chars()) {
     JSString::dumpCharsNoQuote<Latin1Char>(latin1Chars(), length(), out);
   } else {
     JSString::dumpCharsNoQuote<char16_t>(twoByteChars(), length(), out);
   }
 }
 #endif
 
-ParserAtomsTable::ParserAtomsTable(JSRuntime* rt, LifoAlloc& alloc)
-    : wellKnownTable_(*rt->commonParserNames), alloc_(&alloc) {}
+ParserAtomsTable::ParserAtomsTable(JSRuntime* rt, LifoAlloc& alloc,
+                                   ParserAtomVector& entries)
+    : wellKnownTable_(*rt->commonParserNames),
+      alloc_(alloc),
+      entries_(entries) {}
 
 JS::Result<const ParserAtom*, OOM> ParserAtomsTable::addEntry(
     JSContext* cx, EntryMap::AddPtr& addPtr, ParserAtomEntry* entry) {
   MOZ_ASSERT(!addPtr);
   ParserAtomIndex index = ParserAtomIndex(entries_.length());
   if (!entries_.append(entry)) {
     return RaiseParserAtomsOOMError(cx);
   }
@@ -335,27 +338,27 @@ JS::Result<const ParserAtom*, OOM> Parse
 
 template <typename AtomCharT, typename SeqCharT>
 JS::Result<const ParserAtom*, OOM> ParserAtomsTable::internChar16Seq(
     JSContext* cx, EntryMap::AddPtr& addPtr, HashNumber hash,
     InflatedChar16Sequence<SeqCharT> seq, uint32_t length) {
   MOZ_ASSERT(!addPtr);
 
   ParserAtomEntry* entry;
-  MOZ_TRY_VAR(entry, ParserAtomEntry::allocate<AtomCharT>(cx, *alloc_, seq,
+  MOZ_TRY_VAR(entry, ParserAtomEntry::allocate<AtomCharT>(cx, alloc_, seq,
                                                           length, hash));
   return addEntry(cx, addPtr, entry);
 }
 
 template <typename AtomCharT, typename SeqCharT>
 JS::Result<const ParserAtom*, OOM> ParserAtomsTable::internChar16Seq(
     JSContext* cx, HashNumber hash, InflatedChar16Sequence<SeqCharT> seq,
     uint32_t length) {
   ParserAtomEntry* entry;
-  MOZ_TRY_VAR(entry, ParserAtomEntry::allocate<AtomCharT>(cx, *alloc_, seq,
+  MOZ_TRY_VAR(entry, ParserAtomEntry::allocate<AtomCharT>(cx, alloc_, seq,
                                                           length, hash));
 
   ParserAtomIndex index = ParserAtomIndex(entries_.length());
   if (!entries_.append(entry)) {
     return RaiseParserAtomsOOMError(cx);
   }
   SpecificParserAtomLookup<SeqCharT> lookup(seq, hash);
   // This will be removed in later patch.
@@ -618,29 +621,29 @@ const ParserAtom* ParserAtomsTable::getW
 const ParserAtom* ParserAtomsTable::getStatic1(StaticParserString1 s) const {
   return WellKnownParserAtoms::rom_.length1Table[size_t(s)].asAtom();
 }
 
 const ParserAtom* ParserAtomsTable::getStatic2(StaticParserString2 s) const {
   return WellKnownParserAtoms::rom_.length2Table[size_t(s)].asAtom();
 }
 
-size_t ParserAtomsTable::requiredNonStaticAtomCount() const {
+size_t RequiredNonStaticAtomCount(const ParserAtomVector& entries) {
   size_t count = 0;
-  for (const auto& entry : entries_) {
+  for (const auto& entry : entries) {
     if (entry->isNotInstantiatedAndMarked() || entry->isAtomIndex()) {
       count++;
     }
   }
   return count;
 }
 
-bool ParserAtomsTable::instantiateMarkedAtoms(
-    JSContext* cx, CompilationAtomCache& atomCache) const {
-  for (const auto& entry : entries_) {
+bool InstantiateMarkedAtoms(JSContext* cx, const ParserAtomVector& entries,
+                            CompilationAtomCache& atomCache) {
+  for (const auto& entry : entries) {
     if (entry->isNotInstantiatedAndMarked()) {
       if (!entry->instantiate(cx, atomCache)) {
         return false;
       }
     }
   }
   return true;
 }
--- a/js/src/frontend/ParserAtom.h
+++ b/js/src/frontend/ParserAtom.h
@@ -496,38 +496,43 @@ class WellKnownParserAtoms {
       const SpecificParserAtomLookup<CharT>& lookup) const;
 
   template <typename CharsT>
   const ParserAtom* lookupTiny(CharsT chars, size_t length) const {
     return rom_.lookupTiny(chars, length);
   }
 };
 
+// The number of atoms with either NotInstantiatedAndMarked or AtomIndex kind,
+// that requires space in CompilationAtomCache.atoms during instantiation.
+size_t RequiredNonStaticAtomCount(const ParserAtomVector& entries);
+
+bool InstantiateMarkedAtoms(JSContext* cx, const ParserAtomVector& entries,
+                            CompilationAtomCache& atomCache);
+
 /**
  * A ParserAtomsTable owns and manages the vector of ParserAtom entries
  * associated with a given compile session.
  */
 class ParserAtomsTable {
  private:
   const WellKnownParserAtoms& wellKnownTable_;
 
-  LifoAlloc* alloc_;
+  LifoAlloc& alloc_;
 
   // The ParserAtomEntry are owned by the LifoAlloc.
   using EntryMap = HashMap<ParserAtomEntry*, ParserAtomIndex,
                            ParserAtomLookupHasher, js::SystemAllocPolicy>;
   EntryMap entryMap_;
-  ParserAtomVector entries_;
+  ParserAtomVector& entries_;
 
  public:
-  explicit ParserAtomsTable(JSRuntime* rt, LifoAlloc& alloc);
+  ParserAtomsTable(JSRuntime* rt, LifoAlloc& alloc, ParserAtomVector& entries);
   ParserAtomsTable(ParserAtomsTable&&) = default;
 
-  void updateLifoAlloc(LifoAlloc& alloc) { alloc_ = &alloc; }
-
  private:
   // Internal APIs for interning to the table after well-known atoms cases have
   // been tested.
   JS::Result<const ParserAtom*, OOM> addEntry(JSContext* cx,
                                               EntryMap::AddPtr& addPtr,
                                               ParserAtomEntry* entry);
   template <typename AtomCharT, typename SeqCharT>
   JS::Result<const ParserAtom*, OOM> internChar16Seq(
@@ -536,23 +541,16 @@ class ParserAtomsTable {
   template <typename AtomCharT, typename SeqCharT>
   JS::Result<const ParserAtom*, OOM> internChar16Seq(
       JSContext* cx, HashNumber hash, InflatedChar16Sequence<SeqCharT> seq,
       uint32_t length);
 
  public:
   bool empty() const { return entryMap_.empty(); }
 
-  // The number of atoms with either NotInstantiatedAndMarked or AtomIndex kind,
-  // that requires space in CompilationAtomCache.atoms while instantiation.
-  size_t requiredNonStaticAtomCount() const;
-
-  bool instantiateMarkedAtoms(JSContext* cx,
-                              CompilationAtomCache& atomCache) const;
-
   JS::Result<const ParserAtom*, OOM> internAscii(JSContext* cx,
                                                  const char* asciiPtr,
                                                  uint32_t length);
 
   JS::Result<const ParserAtom*, OOM> internLatin1(
       JSContext* cx, const JS::Latin1Char* latin1Ptr, uint32_t length);
 
   JS::Result<const ParserAtom*, OOM> internLatin1ForXDR(
--- a/js/src/frontend/Stencil.cpp
+++ b/js/src/frontend/Stencil.cpp
@@ -224,18 +224,18 @@ static JSFunction* CreateFunction(JSCont
     fun->setExtendedSlot(FunctionExtended::ASMJS_MODULE_SLOT,
                          ObjectValue(*moduleObj));
   }
 
   return fun;
 }
 
 static bool InstantiateAtoms(JSContext* cx, CompilationInfo& compilationInfo) {
-  return compilationInfo.stencil.parserAtoms.instantiateMarkedAtoms(
-      cx, compilationInfo.input.atomCache);
+  return InstantiateMarkedAtoms(cx, compilationInfo.stencil.parserAtomData,
+                                compilationInfo.input.atomCache);
 }
 
 static bool InstantiateScriptSourceObject(JSContext* cx,
                                           CompilationInfo& compilationInfo,
                                           CompilationGCOutput& gcOutput) {
   MOZ_ASSERT(compilationInfo.input.source());
 
   gcOutput.sourceObject =
@@ -795,17 +795,17 @@ bool CompilationInfoVector::instantiateS
     }
   }
 
   return true;
 }
 
 bool CompilationInfo::prepareInputAndStencilForInstantiate(JSContext* cx) {
   if (!input.atomCache.atoms.reserve(
-          stencil.parserAtoms.requiredNonStaticAtomCount())) {
+          RequiredNonStaticAtomCount(stencil.parserAtomData))) {
     ReportOutOfMemory(cx);
     return false;
   }
 
   preparationIsPerformed = true;
 
   return true;
 }
@@ -883,17 +883,17 @@ bool CompilationInfo::serializeStencils(
 }
 
 bool CompilationInfoVector::deserializeStencils(JSContext* cx,
                                                 const JS::TranscodeRange& range,
                                                 bool* succeededOut) {
   if (succeededOut) {
     *succeededOut = false;
   }
-  MOZ_ASSERT(initial.stencil.parserAtoms.empty());
+  MOZ_ASSERT(initial.stencil.parserAtomData.empty());
   XDRStencilDecoder decoder(cx, &initial.input.options, range);
 
   XDRResult res = decoder.codeStencils(*this);
   if (res.isErr()) {
     if (res.unwrapErr() & JS::TranscodeResult_Failure) {
       return true;
     }
     MOZ_ASSERT(res.unwrapErr() == JS::TranscodeResult_Throw);
@@ -902,16 +902,28 @@ bool CompilationInfoVector::deserializeS
   }
 
   if (succeededOut) {
     *succeededOut = true;
   }
   return true;
 }
 
+CompilationState::CompilationState(JSContext* cx,
+                                   LifoAllocScope& frontendAllocScope,
+                                   const JS::ReadOnlyCompileOptions& options,
+                                   CompilationStencil& stencil,
+                                   Scope* enclosingScope /* = nullptr */,
+                                   JSObject* enclosingEnv /* = nullptr */)
+    : directives(options.forceStrictMode()),
+      scopeContext(cx, enclosingScope, enclosingEnv),
+      usedNames(cx),
+      allocScope(frontendAllocScope),
+      parserAtoms(cx->runtime(), stencil.alloc, stencil.parserAtomData) {}
+
 #if defined(DEBUG) || defined(JS_JITSPEW)
 
 void RegExpStencil::dump() {
   js::Fprinter out(stderr);
   js::JSONPrinter json(out);
   dump(json);
 }
 
--- a/js/src/jsapi-tests/testParserAtom.cpp
+++ b/js/src/jsapi-tests/testParserAtom.cpp
@@ -12,19 +12,21 @@
 #include "frontend/ParserAtom.h"  // js::frontend::ParserAtomsTable
 #include "js/TypeDecls.h"         // JS::Latin1Char
 #include "jsapi-tests/tests.h"
 
 // Test empty strings behave consistently.
 BEGIN_TEST(testParserAtom_empty) {
   using js::frontend::ParserAtom;
   using js::frontend::ParserAtomsTable;
+  using js::frontend::ParserAtomVector;
 
   js::LifoAlloc alloc(512);
-  ParserAtomsTable atomTable(cx->runtime(), alloc);
+  ParserAtomVector atoms;
+  ParserAtomsTable atomTable(cx->runtime(), alloc, atoms);
 
   const char ascii[] = {};
   const JS::Latin1Char latin1[] = {};
   const mozilla::Utf8Unit utf8[] = {};
   const char16_t char16[] = {};
 
   const uint8_t bytes[] = {};
   const js::LittleEndianChars leTwoByte(bytes);
@@ -48,19 +50,21 @@ BEGIN_TEST(testParserAtom_empty) {
   return true;
 }
 END_TEST(testParserAtom_empty)
 
 // Test length-1 fast-path is consistent across entry points.
 BEGIN_TEST(testParserAtom_tiny1) {
   using js::frontend::ParserAtom;
   using js::frontend::ParserAtomsTable;
+  using js::frontend::ParserAtomVector;
 
   js::LifoAlloc alloc(512);
-  ParserAtomsTable atomTable(cx->runtime(), alloc);
+  ParserAtomVector atoms;
+  ParserAtomsTable atomTable(cx->runtime(), alloc, atoms);
 
   char16_t a = 'a';
   const char ascii[] = {'a'};
   JS::Latin1Char latin1[] = {'a'};
   const mozilla::Utf8Unit utf8[] = {mozilla::Utf8Unit('a')};
   char16_t char16[] = {'a'};
 
   const uint8_t bytes[] = {'a', 0};
@@ -88,19 +92,21 @@ BEGIN_TEST(testParserAtom_tiny1) {
   return true;
 }
 END_TEST(testParserAtom_tiny1)
 
 // Test length-2 fast-path is consistent across entry points.
 BEGIN_TEST(testParserAtom_tiny2) {
   using js::frontend::ParserAtom;
   using js::frontend::ParserAtomsTable;
+  using js::frontend::ParserAtomVector;
 
   js::LifoAlloc alloc(512);
-  ParserAtomsTable atomTable(cx->runtime(), alloc);
+  ParserAtomVector atoms;
+  ParserAtomsTable atomTable(cx->runtime(), alloc, atoms);
 
   const char ascii[] = {'a', '0'};
   JS::Latin1Char latin1[] = {'a', '0'};
   const mozilla::Utf8Unit utf8[] = {mozilla::Utf8Unit('a'),
                                     mozilla::Utf8Unit('0')};
   char16_t char16[] = {'a', '0'};
 
   const uint8_t bytes[] = {'a', 0, '0', 0};
@@ -127,19 +133,21 @@ BEGIN_TEST(testParserAtom_tiny2) {
 
   return true;
 }
 END_TEST(testParserAtom_tiny2)
 
 BEGIN_TEST(testParserAtom_concat) {
   using js::frontend::ParserAtom;
   using js::frontend::ParserAtomsTable;
+  using js::frontend::ParserAtomVector;
 
   js::LifoAlloc alloc(512);
-  ParserAtomsTable atomTable(cx->runtime(), alloc);
+  ParserAtomVector atoms;
+  ParserAtomsTable atomTable(cx->runtime(), alloc, atoms);
 
   auto CheckConcat = [&](const char16_t* exp,
                          std::initializer_list<const char16_t*> args) -> bool {
     // Intern each argument literal
     std::vector<const ParserAtom*> inputs;
     for (const char16_t* arg : args) {
       size_t len = std::char_traits<char16_t>::length(arg);
       const ParserAtom* atom = atomTable.internChar16(cx, arg, len).unwrap();
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5582,18 +5582,18 @@ static bool FrontendTest(JSContext* cx, 
     }
   } else {
     if (!compilationInfo.get().input.initForModule(cx)) {
       return false;
     }
   }
 
   LifoAllocScope allocScope(&cx->tempLifoAlloc());
-  frontend::CompilationState compilationState(
-      cx, allocScope, options, compilationInfo.get().stencil.parserAtoms);
+  frontend::CompilationState compilationState(cx, allocScope, options,
+                                              compilationInfo.get().stencil);
 
   if (isAscii) {
     const Latin1Char* latin1 = stableChars.latin1Range().begin().get();
     auto utf8 = reinterpret_cast<const mozilla::Utf8Unit*>(latin1);
     if (!DumpAST<mozilla::Utf8Unit>(cx, options, utf8, length,
                                     compilationInfo.get(), compilationState,
                                     goal)) {
       return false;
@@ -5648,18 +5648,18 @@ static bool SyntaxParse(JSContext* cx, u
 
   js::Rooted<frontend::CompilationInfo> compilationInfo(
       cx, js::frontend::CompilationInfo(cx, options));
   if (!compilationInfo.get().input.initForGlobal(cx)) {
     return false;
   }
 
   LifoAllocScope allocScope(&cx->tempLifoAlloc());
-  frontend::CompilationState compilationState(
-      cx, allocScope, options, compilationInfo.get().stencil.parserAtoms);
+  frontend::CompilationState compilationState(cx, allocScope, options,
+                                              compilationInfo.get().stencil);
 
   Parser<frontend::SyntaxParseHandler, char16_t> parser(
       cx, options, chars, length, false, compilationInfo.get(),
       compilationState, nullptr, nullptr);
   if (!parser.checkOptions()) {
     return false;
   }
 
--- a/js/src/vm/CompilationAndEvaluation.cpp
+++ b/js/src/vm/CompilationAndEvaluation.cpp
@@ -201,18 +201,18 @@ JS_PUBLIC_API bool JS_Utf8BufferIsCompil
   CompileOptions options(cx);
   Rooted<frontend::CompilationInfo> compilationInfo(
       cx, frontend::CompilationInfo(cx, options));
   if (!compilationInfo.get().input.initForGlobal(cx)) {
     return false;
   }
 
   LifoAllocScope allocScope(&cx->tempLifoAlloc());
-  frontend::CompilationState compilationState(
-      cx, allocScope, options, compilationInfo.get().stencil.parserAtoms);
+  frontend::CompilationState compilationState(cx, allocScope, options,
+                                              compilationInfo.get().stencil);
 
   JS::AutoSuppressWarningReporter suppressWarnings(cx);
   Parser<FullParseHandler, char16_t> parser(cx, options, chars.get(), length,
                                             /* foldConstants = */ true,
                                             compilationInfo.get(),
                                             compilationState, nullptr, nullptr);
   if (!parser.checkOptions() || !parser.parse()) {
     // We ran into an error. If it was because we ran out of source, we
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/ScopeExit.h"
 #include "mozilla/Unused.h"
 #include "mozilla/Utf8.h"  // mozilla::Utf8Unit
 
 #include <algorithm>
 
 #include "frontend/BytecodeCompilation.h"
 #include "frontend/CompilationInfo.h"  // frontend::CompilationInfo, frontend::CompilationGCOutput
+#include "frontend/ParserAtom.h"  // frontend::ParserAtomsTable
 #include "jit/IonCompileTask.h"
 #include "jit/JitRuntime.h"
 #include "js/ContextOptions.h"      // JS::ContextOptions
 #include "js/friend/StackLimits.h"  // js::ReportOverRecursed
 #include "js/OffThreadScriptCompilation.h"  // JS::OffThreadToken, JS::OffThreadCompileCallback
 #include "js/SourceText.h"
 #include "js/UniquePtr.h"
 #include "js/Utility.h"
--- a/js/src/vm/Xdr.cpp
+++ b/js/src/vm/Xdr.cpp
@@ -747,17 +747,20 @@ XDRResult XDRIncrementalStencilEncoder::
 void XDRDecoder::trace(JSTracer* trc) { atomTable_.trace(trc); }
 
 void XDRIncrementalEncoder::trace(JSTracer* trc) { atomMap_.trace(trc); }
 
 XDRResult XDRStencilDecoder::codeStencils(
     frontend::CompilationInfoVector& compilationInfos) {
   MOZ_ASSERT(compilationInfos.delazifications.length() == 0);
 
-  parserAtoms_ = &compilationInfos.initial.stencil.parserAtoms;
+  frontend::ParserAtomsTable parserAtoms(
+      cx()->runtime(), compilationInfos.initial.stencil.alloc,
+      compilationInfos.initial.stencil.parserAtomData);
+  parserAtoms_ = &parserAtoms;
   stencilAlloc_ = &compilationInfos.initial.stencil.alloc;
 
   MOZ_TRY(codeStencil(compilationInfos.initial));
 
   if (!compilationInfos.delazifications.reserve(nchunks_ - 1)) {
     ReportOutOfMemory(cx());
     return fail(JS::TranscodeResult_Throw);
   }
@@ -765,17 +768,19 @@ XDRResult XDRStencilDecoder::codeStencil
   for (size_t i = 1; i < nchunks_; i++) {
     compilationInfos.delazifications.infallibleEmplaceBack(
         cx(), compilationInfos.initial.input.options);
     auto& funInfo = compilationInfos.delazifications[i - 1];
 
     parserAtomTable_.clear();
     hasFinishedAtomTable_ = false;
 
-    parserAtoms_ = &funInfo.stencil.parserAtoms;
+    frontend::ParserAtomsTable parserAtoms(
+        cx()->runtime(), funInfo.stencil.alloc, funInfo.stencil.parserAtomData);
+    parserAtoms_ = &parserAtoms;
     stencilAlloc_ = &funInfo.stencil.alloc;
 
     MOZ_TRY(codeFunctionStencil(funInfo.stencil));
   }
 
   return Ok();
 }