Bug 1461556 - Add a JSScript constructor to initialize JSScript inside JSScript::Create without using PodZero. r=jandem
authorJeff Walden <jwalden@mit.edu>
Wed, 16 May 2018 17:00:57 -0700
changeset 418919 7c45180cea08
parent 418918 1df7d4219611
child 418920 6ae525ee499f
push id103419
push userjwalden@mit.edu
push date2018-05-18 19:33 +0000
treeherdermozilla-inbound@7658d2d1e0d7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1461556
milestone62.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 1461556 - Add a JSScript constructor to initialize JSScript inside JSScript::Create without using PodZero. r=jandem
js/src/vm/JSScript-inl.h
js/src/vm/JSScript.cpp
js/src/vm/JSScript.h
js/src/vm/TypeInference.cpp
--- a/js/src/vm/JSScript-inl.h
+++ b/js/src/vm/JSScript-inl.h
@@ -199,12 +199,12 @@ JSScript::ensureHasAnalyzedArgsUsage(JSC
     if (analyzedArgsUsage())
         return true;
     return js::jit::AnalyzeArgumentsUsage(cx, this);
 }
 
 inline bool
 JSScript::isDebuggee() const
 {
-    return realm_->debuggerObservesAllExecution() || hasDebugScript_;
+    return realm_->debuggerObservesAllExecution() || bitFields_.hasDebugScript_;
 }
 
 #endif /* vm_JSScript_inl_h */
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/Unused.h"
 #include "mozilla/Vector.h"
 
 #include <algorithm>
+#include <new>
 #include <string.h>
 
 #include "jsapi.h"
 #include "jstypes.h"
 #include "jsutil.h"
 
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
@@ -63,17 +64,16 @@
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::frontend;
 
 using mozilla::Maybe;
 using mozilla::PodCopy;
-using mozilla::PodZero;
 
 
 // Check that JSScript::data hasn't experienced obvious memory corruption.
 // This is a diagnositic for Bug 1367896.
 static void
 CheckScriptDataIntegrity(JSScript* script)
 {
     ScopeArray* sa = script->scopes();
@@ -553,49 +553,49 @@ js::XDRScript(XDRState<mode>* xdr, Handl
 
         MOZ_ASSERT(!script->mainOffset());
         script->mainOffset_ = prologueLength;
         script->funLength_ = funLength;
 
         scriptp.set(script);
 
         if (scriptBits & (1 << Strict))
-            script->strict_ = true;
+            script->bitFields_.strict_ = true;
         if (scriptBits & (1 << ExplicitUseStrict))
-            script->explicitUseStrict_ = true;
+            script->bitFields_.explicitUseStrict_ = true;
         if (scriptBits & (1 << ContainsDynamicNameAccess))
-            script->bindingsAccessedDynamically_ = true;
+            script->bitFields_.bindingsAccessedDynamically_ = true;
         if (scriptBits & (1 << FunHasExtensibleScope))
-            script->funHasExtensibleScope_ = true;
+            script->bitFields_.funHasExtensibleScope_ = true;
         if (scriptBits & (1 << FunHasAnyAliasedFormal))
-            script->funHasAnyAliasedFormal_ = true;
+            script->bitFields_.funHasAnyAliasedFormal_ = true;
         if (scriptBits & (1 << ArgumentsHasVarBinding))
             script->setArgumentsHasVarBinding();
         if (scriptBits & (1 << NeedsArgsObj))
             script->setNeedsArgsObj(true);
         if (scriptBits & (1 << HasMappedArgsObj))
-            script->hasMappedArgsObj_ = true;
+            script->bitFields_.hasMappedArgsObj_ = true;
         if (scriptBits & (1 << FunctionHasThisBinding))
-            script->functionHasThisBinding_ = true;
+            script->bitFields_.functionHasThisBinding_ = true;
         if (scriptBits & (1 << FunctionHasExtraBodyVarScope))
-            script->functionHasExtraBodyVarScope_ = true;
+            script->bitFields_.functionHasExtraBodyVarScope_ = true;
         if (scriptBits & (1 << HasSingleton))
-            script->hasSingletons_ = true;
+            script->bitFields_.hasSingletons_ = true;
         if (scriptBits & (1 << TreatAsRunOnce))
-            script->treatAsRunOnce_ = true;
+            script->bitFields_.treatAsRunOnce_ = true;
         if (scriptBits & (1 << HasNonSyntacticScope))
-            script->hasNonSyntacticScope_ = true;
+            script->bitFields_.hasNonSyntacticScope_ = true;
         if (scriptBits & (1 << HasInnerFunctions))
-            script->hasInnerFunctions_ = true;
+            script->bitFields_.hasInnerFunctions_ = true;
         if (scriptBits & (1 << NeedsHomeObject))
-            script->needsHomeObject_ = true;
+            script->bitFields_.needsHomeObject_ = true;
         if (scriptBits & (1 << IsDerivedClassConstructor))
-            script->isDerivedClassConstructor_ = true;
+            script->bitFields_.isDerivedClassConstructor_ = true;
         if (scriptBits & (1 << IsDefaultClassConstructor))
-            script->isDefaultClassConstructor_ = true;
+            script->bitFields_.isDefaultClassConstructor_ = true;
         if (scriptBits & (1 << IsGenerator))
             script->setGeneratorKind(GeneratorKind::Generator);
         if (scriptBits & (1 << IsAsync))
             script->setAsyncKind(FunctionAsyncKind::AsyncFunction);
         if (scriptBits & (1 << HasRest))
             script->setHasRest();
     }
 
@@ -1081,17 +1081,17 @@ JSScript::initScriptCounts(JSContext* cx
 
     // Register the current ScriptCounts in the compartment's map.
     if (!map->putNew(this, sc)) {
         ReportOutOfMemory(cx);
         return false;
     }
 
     // safe to set this;  we can't fail after this point.
-    hasScriptCounts_ = true;
+    bitFields_.hasScriptCounts_ = true;
     guardScriptCounts.release();
 
     // Enable interrupts in any interpreter frames running on this script. This
     // is used to let the interpreter increment the PCCounts, if present.
     for (ActivationIterator iter(cx); !iter.done(); ++iter) {
         if (iter->isInterpreter())
             iter->asInterpreter()->enableInterruptsIfRunning(this);
     }
@@ -1293,27 +1293,27 @@ JSScript::getIonCounts()
 
 void
 JSScript::takeOverScriptCountsMapEntry(ScriptCounts* entryValue)
 {
 #ifdef DEBUG
     ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
     MOZ_ASSERT(entryValue == p->value());
 #endif
-    hasScriptCounts_ = false;
+    bitFields_.hasScriptCounts_ = false;
 }
 
 void
 JSScript::releaseScriptCounts(ScriptCounts* counts)
 {
     ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
     *counts = Move(*p->value());
     js_delete(p->value());
     compartment()->scriptCountsMap->remove(p);
-    hasScriptCounts_ = false;
+    bitFields_.hasScriptCounts_ = false;
 }
 
 void
 JSScript::destroyScriptCounts()
 {
     if (hasScriptCounts()) {
         ScriptCounts scriptCounts;
         releaseScriptCounts(&scriptCounts);
@@ -2621,60 +2621,86 @@ ScriptDataSize(uint32_t nscopes, uint32_
     if (nscopenotes != 0)
         size += sizeof(ScopeNoteArray) + nscopenotes * sizeof(ScopeNote);
     if (nyieldoffsets != 0)
         size += sizeof(YieldAndAwaitOffsetArray) + nyieldoffsets * sizeof(uint32_t);
 
      return size;
 }
 
-/* static */ JSScript*
-JSScript::Create(JSContext* cx, const ReadOnlyCompileOptions& options,
-                 HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd,
-                 uint32_t toStringStart, uint32_t toStringEnd)
+JSScript::JSScript(JS::Realm* realm, uint8_t* stubEntry, const ReadOnlyCompileOptions& options,
+                   HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd,
+                   uint32_t toStringStart, uint32_t toStringEnd)
+  :
+#ifndef JS_CODEGEN_NONE
+    jitCodeRaw_(stubEntry),
+    jitCodeSkipArgCheck_(stubEntry),
+#endif
+    realm_(realm),
+    sourceStart_(bufStart),
+    sourceEnd_(bufEnd),
+    toStringStart_(toStringStart),
+    toStringEnd_(toStringEnd),
+#ifdef MOZ_VTUNE
+    vtuneMethodId_(vtune::GenerateUniqueMethodID()),
+#endif
+    bitFields_{} // zeroes everything -- some fields custom-assigned below
 {
     // bufStart and bufEnd specify the range of characters parsed by the
     // Parser to produce this script. toStringStart and toStringEnd specify
     // the range of characters to be returned for Function.prototype.toString.
     MOZ_ASSERT(bufStart <= bufEnd);
     MOZ_ASSERT(toStringStart <= toStringEnd);
     MOZ_ASSERT(toStringStart <= bufStart);
     MOZ_ASSERT(toStringEnd >= bufEnd);
 
-    RootedScript script(cx, Allocate<JSScript>(cx));
+    bitFields_.noScriptRval_ = options.noScriptRval;
+    bitFields_.selfHosted_ = options.selfHostingMode;
+    bitFields_.treatAsRunOnce_ = options.isRunOnce;
+    bitFields_.hideScriptFromDebugger_ = options.hideScriptFromDebugger;
+
+    setSourceObject(sourceObject);
+}
+
+/* static */ JSScript*
+JSScript::createInitialized(JSContext* cx, const ReadOnlyCompileOptions& options,
+                            HandleObject sourceObject,
+                            uint32_t bufStart, uint32_t bufEnd,
+                            uint32_t toStringStart, uint32_t toStringEnd)
+{
+    void* script = Allocate<JSScript>(cx);
     if (!script)
         return nullptr;
 
-    PodZero(script.get());
-
-    script->realm_ = cx->realm();
-
+    uint8_t* stubEntry =
 #ifndef JS_CODEGEN_NONE
-    uint8_t* stubEntry = cx->runtime()->jitRuntime()->interpreterStub().value;
-    script->jitCodeRaw_ = stubEntry;
-    script->jitCodeSkipArgCheck_ = stubEntry;
+        cx->runtime()->jitRuntime()->interpreterStub().value
+#else
+        nullptr
 #endif
-
-    script->selfHosted_ = options.selfHostingMode;
-    script->noScriptRval_ = options.noScriptRval;
-    script->treatAsRunOnce_ = options.isRunOnce;
-
-    script->setSourceObject(sourceObject);
-    if (cx->runtime()->lcovOutput().isEnabled() && !script->initScriptName(cx))
+        ;
+
+    return new (script) JSScript(cx->realm(), stubEntry, options, sourceObject,
+                                 bufStart, bufEnd, toStringStart, toStringEnd);
+}
+
+/* static */ JSScript*
+JSScript::Create(JSContext* cx, const ReadOnlyCompileOptions& options,
+                 HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd,
+                 uint32_t toStringStart, uint32_t toStringEnd)
+{
+    RootedScript script(cx, createInitialized(cx, options, sourceObject, bufStart, bufEnd,
+                                              toStringStart, toStringEnd));
+    if (!script)
         return nullptr;
-    script->sourceStart_ = bufStart;
-    script->sourceEnd_ = bufEnd;
-    script->toStringStart_ = toStringStart;
-    script->toStringEnd_ = toStringEnd;
-
-    script->hideScriptFromDebugger_ = options.hideScriptFromDebugger;
-
-#ifdef MOZ_VTUNE
-    script->vtuneMethodId_ = vtune::GenerateUniqueMethodID();
-#endif
+
+    if (cx->runtime()->lcovOutput().isEnabled()) {
+        if (!script->initScriptName(cx))
+            return nullptr;
+    }
 
     return script;
 }
 
 bool
 JSScript::initScriptName(JSContext* cx)
 {
     MOZ_ASSERT(!hasScriptName());
@@ -2877,53 +2903,53 @@ InitAtomMap(frontend::AtomIndexMap& indi
 JSScript::initFromFunctionBox(HandleScript script, frontend::FunctionBox* funbox)
 {
     JSFunction* fun = funbox->function();
     if (fun->isInterpretedLazy())
         fun->setUnlazifiedScript(script);
     else
         fun->setScript(script);
 
-    script->funHasExtensibleScope_ = funbox->hasExtensibleScope();
-    script->needsHomeObject_       = funbox->needsHomeObject();
-    script->isDerivedClassConstructor_ = funbox->isDerivedClassConstructor();
+    script->bitFields_.funHasExtensibleScope_ = funbox->hasExtensibleScope();
+    script->bitFields_.needsHomeObject_ = funbox->needsHomeObject();
+    script->bitFields_.isDerivedClassConstructor_ = funbox->isDerivedClassConstructor();
 
     if (funbox->argumentsHasLocalBinding()) {
         script->setArgumentsHasVarBinding();
         if (funbox->definitelyNeedsArgsObj())
             script->setNeedsArgsObj(true);
     } else {
         MOZ_ASSERT(!funbox->definitelyNeedsArgsObj());
     }
-    script->hasMappedArgsObj_ = funbox->hasMappedArgsObj();
-
-    script->functionHasThisBinding_ = funbox->hasThisBinding();
-    script->functionHasExtraBodyVarScope_ = funbox->hasExtraBodyVarScope();
+    script->bitFields_.hasMappedArgsObj_ = funbox->hasMappedArgsObj();
+
+    script->bitFields_.functionHasThisBinding_ = funbox->hasThisBinding();
+    script->bitFields_.functionHasExtraBodyVarScope_ = funbox->hasExtraBodyVarScope();
 
     script->funLength_ = funbox->length;
 
     script->setGeneratorKind(funbox->generatorKind());
     script->setAsyncKind(funbox->asyncKind());
     if (funbox->hasRest())
         script->setHasRest();
 
     PositionalFormalParameterIter fi(script);
     while (fi && !fi.closedOver())
         fi++;
-    script->funHasAnyAliasedFormal_ = !!fi;
+    script->bitFields_.funHasAnyAliasedFormal_ = !!fi;
 
     script->setHasInnerFunctions(funbox->hasInnerFunctions());
 }
 
 /* static */ void
 JSScript::initFromModuleContext(HandleScript script)
 {
-    script->funHasExtensibleScope_ = false;
-    script->needsHomeObject_ = false;
-    script->isDerivedClassConstructor_ = false;
+    script->bitFields_.funHasExtensibleScope_ = false;
+    script->bitFields_.needsHomeObject_ = false;
+    script->bitFields_.isDerivedClassConstructor_ = false;
     script->funLength_ = 0;
 
     script->setGeneratorKind(GeneratorKind::NotGenerator);
 
     // Since modules are only run once, mark the script so that initializers
     // created within it may be given more precise types.
     script->setTreatAsRunOnce();
     MOZ_ASSERT(!script->hasRunOnce());
@@ -2972,31 +2998,32 @@ JSScript::fullyInitFromEmitter(JSContext
     if (bce->objectList.length != 0)
         bce->objectList.finish(script->objects());
     if (bce->scopeList.length() != 0)
         bce->scopeList.finish(script->scopes());
     if (bce->tryNoteList.length() != 0)
         bce->tryNoteList.finish(script->trynotes());
     if (bce->scopeNoteList.length() != 0)
         bce->scopeNoteList.finish(script->scopeNotes(), prologueLength);
-    script->strict_ = bce->sc->strict();
-    script->explicitUseStrict_ = bce->sc->hasExplicitUseStrict();
-    script->bindingsAccessedDynamically_ = bce->sc->bindingsAccessedDynamically();
-    script->hasSingletons_ = bce->hasSingletons;
+    script->bitFields_.strict_ = bce->sc->strict();
+    script->bitFields_.explicitUseStrict_ = bce->sc->hasExplicitUseStrict();
+    script->bitFields_.bindingsAccessedDynamically_ = bce->sc->bindingsAccessedDynamically();
+    script->bitFields_.hasSingletons_ = bce->hasSingletons;
 
     uint64_t nslots = bce->maxFixedSlots + static_cast<uint64_t>(bce->maxStackDepth);
     if (nslots > UINT32_MAX) {
         bce->reportError(nullptr, JSMSG_NEED_DIET, js_script_str);
         return false;
     }
 
     script->nfixed_ = bce->maxFixedSlots;
     script->nslots_ = nslots;
     script->bodyScopeIndex_ = bce->bodyScopeIndex;
-    script->hasNonSyntacticScope_ = bce->outermostScope()->hasOnChain(ScopeKind::NonSyntactic);
+    script->bitFields_.hasNonSyntacticScope_ =
+        bce->outermostScope()->hasOnChain(ScopeKind::NonSyntactic);
 
     if (bce->sc->isFunctionBox())
         initFromFunctionBox(script, bce->sc->asFunctionBox());
     else if (bce->sc->isModuleContext())
         initFromModuleContext(script);
 
     // Copy yield offsets last, as the generator kind is set in
     // initFromFunctionBox.
@@ -3533,36 +3560,36 @@ js::detail::CopyScript(JSContext* cx, Ha
     dst->bodyScopeIndex_ = src->bodyScopeIndex_;
     dst->funLength_ = src->funLength();
     dst->nTypeSets_ = src->nTypeSets();
     if (src->argumentsHasVarBinding()) {
         dst->setArgumentsHasVarBinding();
         if (src->analyzedArgsUsage())
             dst->setNeedsArgsObj(src->needsArgsObj());
     }
-    dst->hasMappedArgsObj_ = src->hasMappedArgsObj();
-    dst->functionHasThisBinding_ = src->functionHasThisBinding();
-    dst->functionHasExtraBodyVarScope_ = src->functionHasExtraBodyVarScope();
+    dst->bitFields_.hasMappedArgsObj_ = src->hasMappedArgsObj();
+    dst->bitFields_.functionHasThisBinding_ = src->functionHasThisBinding();
+    dst->bitFields_.functionHasExtraBodyVarScope_ = src->functionHasExtraBodyVarScope();
     dst->cloneHasArray(src);
-    dst->strict_ = src->strict();
-    dst->explicitUseStrict_ = src->explicitUseStrict();
-    dst->hasNonSyntacticScope_ = scopes[0]->hasOnChain(ScopeKind::NonSyntactic);
-    dst->bindingsAccessedDynamically_ = src->bindingsAccessedDynamically();
-    dst->funHasExtensibleScope_ = src->funHasExtensibleScope();
-    dst->funHasAnyAliasedFormal_ = src->funHasAnyAliasedFormal();
-    dst->hasSingletons_ = src->hasSingletons();
-    dst->treatAsRunOnce_ = src->treatAsRunOnce();
-    dst->hasInnerFunctions_ = src->hasInnerFunctions();
+    dst->bitFields_.strict_ = src->strict();
+    dst->bitFields_.explicitUseStrict_ = src->explicitUseStrict();
+    dst->bitFields_.hasNonSyntacticScope_ = scopes[0]->hasOnChain(ScopeKind::NonSyntactic);
+    dst->bitFields_.bindingsAccessedDynamically_ = src->bindingsAccessedDynamically();
+    dst->bitFields_.funHasExtensibleScope_ = src->funHasExtensibleScope();
+    dst->bitFields_.funHasAnyAliasedFormal_ = src->funHasAnyAliasedFormal();
+    dst->bitFields_.hasSingletons_ = src->hasSingletons();
+    dst->bitFields_.treatAsRunOnce_ = src->treatAsRunOnce();
+    dst->bitFields_.hasInnerFunctions_ = src->hasInnerFunctions();
     dst->setGeneratorKind(src->generatorKind());
-    dst->isDerivedClassConstructor_ = src->isDerivedClassConstructor();
-    dst->needsHomeObject_ = src->needsHomeObject();
-    dst->isDefaultClassConstructor_ = src->isDefaultClassConstructor();
-    dst->isAsync_ = src->isAsync_;
-    dst->hasRest_ = src->hasRest_;
-    dst->hideScriptFromDebugger_ = src->hideScriptFromDebugger_;
+    dst->bitFields_.isDerivedClassConstructor_ = src->isDerivedClassConstructor();
+    dst->bitFields_.needsHomeObject_ = src->needsHomeObject();
+    dst->bitFields_.isDefaultClassConstructor_ = src->isDefaultClassConstructor();
+    dst->bitFields_.isAsync_ = src->bitFields_.isAsync_;
+    dst->bitFields_.hasRest_ = src->bitFields_.hasRest_;
+    dst->bitFields_.hideScriptFromDebugger_ = src->bitFields_.hideScriptFromDebugger_;
 
     if (nconsts != 0) {
         GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->consts()->vector);
         dst->consts()->vector = vector;
         for (unsigned i = 0; i < nconsts; ++i)
             MOZ_ASSERT_IF(vector[i].isGCThing(), vector[i].toString()->isAtom());
     }
     if (nobjects != 0) {
@@ -3695,59 +3722,59 @@ js::CloneScriptIntoFunction(JSContext* c
         fun->initScript(dst);
 
     return dst;
 }
 
 DebugScript*
 JSScript::debugScript()
 {
-    MOZ_ASSERT(hasDebugScript_);
+    MOZ_ASSERT(bitFields_.hasDebugScript_);
     DebugScriptMap* map = compartment()->debugScriptMap;
     MOZ_ASSERT(map);
     DebugScriptMap::Ptr p = map->lookup(this);
     MOZ_ASSERT(p);
     return p->value();
 }
 
 DebugScript*
 JSScript::releaseDebugScript()
 {
-    MOZ_ASSERT(hasDebugScript_);
+    MOZ_ASSERT(bitFields_.hasDebugScript_);
     DebugScriptMap* map = compartment()->debugScriptMap;
     MOZ_ASSERT(map);
     DebugScriptMap::Ptr p = map->lookup(this);
     MOZ_ASSERT(p);
     DebugScript* debug = p->value();
     map->remove(p);
-    hasDebugScript_ = false;
+    bitFields_.hasDebugScript_ = false;
     return debug;
 }
 
 void
 JSScript::destroyDebugScript(FreeOp* fop)
 {
-    if (hasDebugScript_) {
+    if (bitFields_.hasDebugScript_) {
 #ifdef DEBUG
         for (jsbytecode* pc = code(); pc < codeEnd(); pc++) {
             if (BreakpointSite* site = getBreakpointSite(pc)) {
                 /* Breakpoints are swept before finalization. */
                 MOZ_ASSERT(site->firstBreakpoint() == nullptr);
                 MOZ_ASSERT(getBreakpointSite(pc) == nullptr);
             }
         }
 #endif
         fop->free_(releaseDebugScript());
     }
 }
 
 bool
 JSScript::ensureHasDebugScript(JSContext* cx)
 {
-    if (hasDebugScript_)
+    if (bitFields_.hasDebugScript_)
         return true;
 
     size_t nbytes = offsetof(DebugScript, breakpoints) + length() * sizeof(BreakpointSite*);
     DebugScript* debug = (DebugScript*) zone()->pod_calloc<uint8_t>(nbytes);
     if (!debug)
         return false;
 
     /* Create compartment's debugScriptMap if necessary. */
@@ -3761,17 +3788,17 @@ JSScript::ensureHasDebugScript(JSContext
         }
         compartment()->debugScriptMap = map;
     }
 
     if (!map->putNew(this, debug)) {
         js_free(debug);
         return false;
     }
-    hasDebugScript_ = true; // safe to set this;  we can't fail after this point
+    bitFields_.hasDebugScript_ = true; // safe to set this;  we can't fail after this point
 
     /*
      * Ensure that any Interpret() instances running on this script have
      * interrupts enabled. The interrupts must stay enabled until the
      * debug state is destroyed.
      */
     for (ActivationIterator iter(cx); !iter.done(); ++iter) {
         if (iter->isInterpreter())
@@ -4028,26 +4055,26 @@ JSScript::innermostScope(jsbytecode* pc)
     if (Scope* scope = lookupScope(pc))
         return scope;
     return bodyScope();
 }
 
 void
 JSScript::setArgumentsHasVarBinding()
 {
-    argsHasVarBinding_ = true;
-    needsArgsAnalysis_ = true;
+    bitFields_.argsHasVarBinding_ = true;
+    bitFields_.needsArgsAnalysis_ = true;
 }
 
 void
 JSScript::setNeedsArgsObj(bool needsArgsObj)
 {
     MOZ_ASSERT_IF(needsArgsObj, argumentsHasVarBinding());
-    needsArgsAnalysis_ = false;
-    needsArgsObj_ = needsArgsObj;
+    bitFields_.needsArgsAnalysis_ = false;
+    bitFields_.needsArgsObj_ = needsArgsObj;
 }
 
 void
 js::SetFrameArgumentsObject(JSContext* cx, AbstractFramePtr frame,
                             HandleScript script, JSObject* argsobj)
 {
     /*
      * Replace any optimized arguments in the frame with an explicit arguments
@@ -4100,17 +4127,17 @@ JSScript::argumentsOptimizationFailed(JS
      * argsobj.
      */
     if (script->needsArgsObj())
         return true;
 
     MOZ_ASSERT(!script->isGenerator());
     MOZ_ASSERT(!script->isAsync());
 
-    script->needsArgsObj_ = true;
+    script->bitFields_.needsArgsObj_ = true;
 
     /*
      * Since we can't invalidate baseline scripts, set a flag that's checked from
      * JIT code to indicate the arguments optimization failed and JSOP_ARGUMENTS
      * should create an arguments object next time.
      */
     if (script->hasBaselineScript())
         script->baselineScript()->setNeedsArgsObj();
@@ -4441,17 +4468,17 @@ JSScript::AutoDelazify::holdScript(JS::H
             // can't use JSAutoRealm: it could cause races. Functions in the
             // self-hosting compartment will never be lazy, so we can safely
             // assume we don't have to delazify.
             script_ = fun->nonLazyScript();
         } else {
             JSAutoRealm ar(cx_, fun);
             script_ = JSFunction::getOrCreateScript(cx_, fun);
             if (script_) {
-                oldDoNotRelazify_ = script_->doNotRelazify_;
+                oldDoNotRelazify_ = script_->bitFields_.doNotRelazify_;
                 script_->setDoNotRelazify(true);
             }
         }
     }
 }
 
 void
 JSScript::AutoDelazify::dropScript()
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -895,79 +895,78 @@ SweepScriptData(JSRuntime* rt);
 
 extern void
 FreeScriptData(JSRuntime* rt);
 
 } /* namespace js */
 
 class JSScript : public js::gc::TenuredCell
 {
-    template <js::XDRMode mode>
-    friend
-    js::XDRResult
-    js::XDRScript(js::XDRState<mode>* xdr, js::HandleScope enclosingScope,
-                  js::HandleScriptSourceObject sourceObject, js::HandleFunction fun,
-                  js::MutableHandleScript scriptp);
-
-    friend bool
-    js::detail::CopyScript(JSContext* cx, js::HandleScript src, js::HandleScript dst,
-                           js::MutableHandle<JS::GCVector<js::Scope*>> scopes);
-
   private:
     // Pointer to baseline->method()->raw(), ion->method()->raw(), a wasm jit
     // entry, the JIT's EnterInterpreter stub, or the lazy link stub. Must be
     // non-null.
-    uint8_t* jitCodeRaw_;
-    uint8_t* jitCodeSkipArgCheck_;
-
-    js::SharedScriptData* scriptData_;
+    uint8_t* jitCodeRaw_ = nullptr;
+    uint8_t* jitCodeSkipArgCheck_ = nullptr;
+
+    js::SharedScriptData* scriptData_ = nullptr;
+
   public:
-    uint8_t*        data;      /* pointer to variable-length data array (see
-                                   comment above Create() for details) */
-
-    JS::Realm* realm_;
+    // Pointer to variable-length data array (see comment above Create() for
+    // details).
+    uint8_t* data = nullptr;
+
+    JS::Realm* realm_ = nullptr;
 
   private:
     /* Persistent type information retained across GCs. */
-    js::TypeScript* types_;
+    js::TypeScript* types_ = nullptr;
 
     // This script's ScriptSourceObject, or a CCW thereof.
     //
     // (When we clone a JSScript into a new compartment, we don't clone its
     // source object. Instead, the clone refers to a wrapper.)
-    js::GCPtrObject sourceObject_;
+    js::GCPtrObject sourceObject_ = {};
 
     /*
      * Information attached by Ion. Nexto a valid IonScript this could be
      * ION_DISABLED_SCRIPT, ION_COMPILING_SCRIPT or ION_PENDING_SCRIPT.
      * The later is a ion compilation that is ready, but hasn't been linked
      * yet.
      */
-    js::jit::IonScript* ion;
+    js::jit::IonScript* ion = nullptr;
 
     /* Information attached by Baseline. */
-    js::jit::BaselineScript* baseline;
+    js::jit::BaselineScript* baseline = nullptr;
 
     /* Information used to re-lazify a lazily-parsed interpreted function. */
-    js::LazyScript* lazyScript;
+    js::LazyScript* lazyScript = nullptr;
 
     // 32-bit fields.
 
-    uint32_t        dataSize_;  /* size of the used part of the data array */
-
-    uint32_t        lineno_;    /* base line number of script */
-    uint32_t        column_;    /* base column of script, optionally set */
-
-    uint32_t        mainOffset_;/* offset of main entry point from code, after
-                                   predef'ing prologue */
-
-    uint32_t        nfixed_;    /* fixed frame slots */
-    uint32_t        nslots_;    /* slots plus maximum stack depth */
-
-    uint32_t        bodyScopeIndex_; /* index into the scopes array of the body scope */
+    /* Size of the used part of the data array. */
+    uint32_t dataSize_ = 0;
+
+    /* Base line number of script. */
+    uint32_t lineno_ = 0;
+
+    /* Base column of script, optionally set. */
+    uint32_t column_ = 0;
+
+    /* Offset of main entry point from code, after predef'ing prologue. */
+    uint32_t mainOffset_ = 0;
+
+    /* Fixed frame slots. */
+    uint32_t nfixed_ = 0;
+
+    /* Slots plus maximum stack depth. */
+    uint32_t nslots_ = 0;
+
+    /* Index into the scopes array of the body scope */
+    uint32_t bodyScopeIndex_ = 0;
 
     // Range of characters in scriptSource which contains this script's
     // source, that is, the range used by the Parser to produce this script.
     //
     // Most scripted functions have sourceStart_ == toStringStart_ and
     // sourceEnd_ == toStringEnd_. However, for functions with extra
     // qualifiers (e.g. generators, async) and for class constructors (which
     // need to return the entire class source), their values differ.
@@ -985,193 +984,237 @@ class JSScript : public js::gc::TenuredC
     // offset is used.
     //
     //   class C { constructor() { this.field = 42; } }
     //   ^         ^                                 ^ ^
     //   |         |                                 | `---------`
     //   |         sourceStart_                      sourceEnd_  |
     //   |                                                       |
     //   toStringStart_                                          toStringEnd_
-    uint32_t        sourceStart_;
-    uint32_t        sourceEnd_;
-    uint32_t        toStringStart_;
-    uint32_t        toStringEnd_;
+    uint32_t sourceStart_ = 0;
+    uint32_t sourceEnd_ = 0;
+    uint32_t toStringStart_ = 0;
+    uint32_t toStringEnd_ = 0;
 
 #ifdef MOZ_VTUNE
     // Unique Method ID passed to the VTune profiler, or 0 if unset.
     // Allows attribution of different jitcode to the same source script.
-    uint32_t        vtuneMethodId_;
+    uint32_t vtuneMethodId_ = 0;
     // Extra padding to maintain JSScript as a multiple of gc::CellAlignBytes.
-    uint32_t        __vtune_unused_padding_;
+    uint32_t __vtune_unused_padding_;
 #endif
 
     // Number of times the script has been called or has had backedges taken.
     // When running in ion, also increased for any inlined scripts. Reset if
     // the script's JIT code is forcibly discarded.
-    mozilla::Atomic<uint32_t, mozilla::Relaxed> warmUpCount;
+    mozilla::Atomic<uint32_t, mozilla::Relaxed> warmUpCount = {};
 
     // 16-bit fields.
 
-    uint16_t        warmUpResetCount; /* Number of times the |warmUpCount| was
-                                       * forcibly discarded. The counter is reset when
-                                       * a script is successfully jit-compiled. */
-
-    uint16_t        funLength_; /* ES6 function length */
-
-    uint16_t        nTypeSets_; /* number of type sets used in this script for
-                                   dynamic type monitoring */
+    /**
+     * Number of times the |warmUpCount| was forcibly discarded. The counter is
+     * reset when a script is successfully jit-compiled.
+     */
+    uint16_t warmUpResetCount = 0;
+
+    /* ES6 function length. */
+    uint16_t funLength_ = 0;
+
+    /* Number of type sets used in this script for dynamic type monitoring. */
+    uint16_t nTypeSets_ = 0;
 
     // Bit fields.
 
   public:
     // The kinds of the optional arrays.
     enum ArrayKind {
         CONSTS,
         OBJECTS,
         TRYNOTES,
         SCOPENOTES,
         ARRAY_KIND_BITS
     };
 
   private:
-    // The bits in this field indicate the presence/non-presence of several
-    // optional arrays in |data|.  See the comments above Create() for details.
-    uint8_t hasArrayBits:ARRAY_KIND_BITS;
-
-    // 1-bit fields.
-
-    // No need for result value of last expression statement.
-    bool noScriptRval_:1;
-
-    // Code is in strict mode.
-    bool strict_:1;
-
-    // Code has "use strict"; explicitly.
-    bool explicitUseStrict_:1;
-
-    // True if the script has a non-syntactic scope on its dynamic scope chain.
-    // That is, there are objects about which we know nothing between the
-    // outermost syntactic scope and the global.
-    bool hasNonSyntacticScope_:1;
-
-    // see Parser::selfHostingMode.
-    bool selfHosted_:1;
-
-    // See FunctionBox.
-    bool bindingsAccessedDynamically_:1;
-    bool funHasExtensibleScope_:1;
-
-    // True if any formalIsAliased(i).
-    bool funHasAnyAliasedFormal_:1;
-
-    // Have warned about uses of undefined properties in this script.
-    bool warnedAboutUndefinedProp_:1;
-
-    // Script has singleton objects.
-    bool hasSingletons_:1;
-
-    // Script is a lambda to treat as running once or a global or eval script
-    // that will only run once.  Which one it is can be disambiguated by
-    // checking whether function() is null.
-    bool treatAsRunOnce_:1;
-
-    // If treatAsRunOnce, whether script has executed.
-    bool hasRunOnce_:1;
-
-    // Script has been reused for a clone.
-    bool hasBeenCloned_:1;
-
-    // Script came from eval(), and is still active.
-    bool isActiveEval_:1;
-
-    // Script came from eval(), and is in eval cache.
-    bool isCachedEval_:1;
-
-    // 'this', 'arguments' and f.apply() are used. This is likely to be a wrapper.
-    bool isLikelyConstructorWrapper_:1;
-
-    // IonMonkey compilation hints.
-    bool failedBoundsCheck_:1; /* script has had hoisted bounds checks fail */
-    bool failedShapeGuard_:1; /* script has had hoisted shape guard fail */
-    bool hadFrequentBailouts_:1;
-    bool hadOverflowBailout_:1;
-    bool uninlineable_:1;    /* explicitly marked as uninlineable */
-
-    // Idempotent cache has triggered invalidation.
-    bool invalidatedIdempotentCache_:1;
-
-    // Lexical check did fail and bail out.
-    bool failedLexicalCheck_:1;
-
-    // Script has an entry in JSCompartment::scriptCountsMap.
-    bool hasScriptCounts_:1;
-
-    // Script has an entry in JSCompartment::debugScriptMap.
-    bool hasDebugScript_:1;
-
-    // Freeze constraints for stack type sets have been generated.
-    bool hasFreezeConstraints_:1;
-
-    /* See comments below. */
-    bool argsHasVarBinding_:1;
-    bool needsArgsAnalysis_:1;
-    bool needsArgsObj_:1;
-    bool functionHasThisBinding_:1;
-    bool functionHasExtraBodyVarScope_:1;
-
-    // Whether the arguments object for this script, if it needs one, should be
-    // mapped (alias formal parameters).
-    bool hasMappedArgsObj_:1;
-
-    // Generation for this script's TypeScript. If out of sync with the
-    // TypeZone's generation, the TypeScript needs to be swept.
-    //
-    // This should be a uint32 but is instead a bool so that MSVC packs it
-    // correctly.
-    bool typesGeneration_:1;
-
-    // Do not relazify this script. This is used by the relazify() testing
-    // function for scripts that are on the stack and also by the AutoDelazify
-    // RAII class. Usually we don't relazify functions in compartments with
-    // scripts on the stack, but the relazify() testing function overrides that,
-    // and sometimes we're working with a cross-compartment function and need to
-    // keep it from relazifying.
-    bool doNotRelazify_:1;
-
-    // Script contains inner functions. Used to check if we can relazify the
-    // script.
-    bool hasInnerFunctions_:1;
-
-    bool needsHomeObject_:1;
-
-    bool isDerivedClassConstructor_:1;
-    bool isDefaultClassConstructor_:1;
-
-    // True if this function is a generator function or async generator.
-    bool isGenerator_:1;
-
-    // True if this function is an async function or async generator.
-    bool isAsync_:1;
-
-    bool hasRest_:1;
-
-    // True if the debugger's onNewScript hook has not yet been called.
-    bool hideScriptFromDebugger_:1;
+    struct BitFields
+    {
+        /*
+         * Bit-fields can't have member initializers til C++2a, i.e. probably
+         * C++20, so we can't initialize these to zero in place.  Instead we
+         * braced-init this to all zeroes in the JSScript constructor, then
+         * custom-assign particular bit-fields in the constructor body.
+         */
+
+        // The bits in this field indicate the presence/non-presence of several
+        // optional arrays in |data|.  See the comments above Create() for details.
+        uint8_t hasArrayBits_ : ARRAY_KIND_BITS;
+
+        /*
+         * All remaining bit-fields are single-bit bools.
+         */
+
+        // No need for result value of last expression statement.
+        bool noScriptRval_ : 1;
+
+        // Code is in strict mode.
+        bool strict_ : 1;
+
+        // Code has "use strict"; explicitly.
+        bool explicitUseStrict_ : 1;
+
+        // True if the script has a non-syntactic scope on its dynamic scope chain.
+        // That is, there are objects about which we know nothing between the
+        // outermost syntactic scope and the global.
+        bool hasNonSyntacticScope_ : 1;
+
+        // see Parser::selfHostingMode.
+        bool selfHosted_ : 1;
+
+        // See FunctionBox.
+        bool bindingsAccessedDynamically_ : 1;
+        bool funHasExtensibleScope_ : 1;
+
+        // True if any formalIsAliased(i).
+        bool funHasAnyAliasedFormal_ : 1;
+
+        // Have warned about uses of undefined properties in this script.
+        bool warnedAboutUndefinedProp_ : 1;
+
+        // Script has singleton objects.
+        bool hasSingletons_ : 1;
+
+        // Script is a lambda to treat as running once or a global or eval script
+        // that will only run once.  Which one it is can be disambiguated by
+        // checking whether function() is null.
+        bool treatAsRunOnce_ : 1;
+
+        // If treatAsRunOnce, whether script has executed.
+        bool hasRunOnce_ : 1;
+
+        // Script has been reused for a clone.
+        bool hasBeenCloned_ : 1;
+
+        // Script came from eval(), and is still active.
+        bool isActiveEval_ : 1;
+
+        // Script came from eval(), and is in eval cache.
+        bool isCachedEval_ : 1;
+
+        // 'this', 'arguments' and f.apply() are used. This is likely to be a wrapper.
+        bool isLikelyConstructorWrapper_ : 1;
+
+        // IonMonkey compilation hints.
+
+        /* Script has had hoisted bounds checks fail. */
+        bool failedBoundsCheck_ : 1;
+
+        /* Script has had hoisted shape guard fail. */
+        bool failedShapeGuard_ : 1;
+
+        bool hadFrequentBailouts_ : 1;
+        bool hadOverflowBailout_ : 1;
+
+        /* Explicitly marked as uninlineable. */
+        bool uninlineable_ : 1;
+
+        // Idempotent cache has triggered invalidation.
+        bool invalidatedIdempotentCache_ : 1;
+
+        // Lexical check did fail and bail out.
+        bool failedLexicalCheck_ : 1;
+
+        // Script has an entry in JSCompartment::scriptCountsMap.
+        bool hasScriptCounts_ : 1;
+
+        // Script has an entry in JSCompartment::debugScriptMap.
+        bool hasDebugScript_ : 1;
+
+        // Freeze constraints for stack type sets have been generated.
+        bool hasFreezeConstraints_ : 1;
+
+        /* See comments below. */
+        bool argsHasVarBinding_ : 1;
+        bool needsArgsAnalysis_ : 1;
+        bool needsArgsObj_ : 1;
+        bool functionHasThisBinding_ : 1;
+        bool functionHasExtraBodyVarScope_ : 1;
+
+        // Whether the arguments object for this script, if it needs one, should be
+        // mapped (alias formal parameters).
+        bool hasMappedArgsObj_ : 1;
+
+        // Generation for this script's TypeScript. If out of sync with the
+        // TypeZone's generation, the TypeScript needs to be swept.
+        //
+        // This should be a uint32 but is instead a bool so that MSVC packs it
+        // correctly.
+        bool typesGeneration_ : 1;
+
+        // Do not relazify this script. This is used by the relazify() testing
+        // function for scripts that are on the stack and also by the AutoDelazify
+        // RAII class. Usually we don't relazify functions in compartments with
+        // scripts on the stack, but the relazify() testing function overrides that,
+        // and sometimes we're working with a cross-compartment function and need to
+        // keep it from relazifying.
+        bool doNotRelazify_ : 1;
+
+        // Script contains inner functions. Used to check if we can relazify the
+        // script.
+        bool hasInnerFunctions_ : 1;
+
+        bool needsHomeObject_ : 1;
+
+        bool isDerivedClassConstructor_ : 1;
+        bool isDefaultClassConstructor_ : 1;
+
+        // True if this function is a generator function or async generator.
+        bool isGenerator_ : 1;
+
+        // True if this function is an async function or async generator.
+        bool isAsync_ : 1;
+
+        bool hasRest_ : 1;
+
+        // True if the debugger's onNewScript hook has not yet been called.
+        bool hideScriptFromDebugger_ : 1;
+    } bitFields_;
 
     // Add padding so JSScript is gc::Cell aligned. Make padding protected
     // instead of private to suppress -Wunused-private-field compiler warnings.
   protected:
 #if JS_BITS_PER_WORD == 32
     uint32_t padding_;
 #endif
 
     //
     // End of fields.  Start methods.
     //
 
+  private:
+    template <js::XDRMode mode>
+    friend
+    js::XDRResult
+    js::XDRScript(js::XDRState<mode>* xdr, js::HandleScope enclosingScope,
+                  js::HandleScriptSourceObject sourceObject, js::HandleFunction fun,
+                  js::MutableHandleScript scriptp);
+
+    friend bool
+    js::detail::CopyScript(JSContext* cx, js::HandleScript src, js::HandleScript dst,
+                           js::MutableHandle<JS::GCVector<js::Scope*>> scopes);
+
+  private:
+    JSScript(JS::Realm* realm, uint8_t* stubEntry, const JS::ReadOnlyCompileOptions& options,
+             js::HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd,
+             uint32_t toStringStart, uint32_t toStringend);
+
+    static JSScript* createInitialized(JSContext* cx, const JS::ReadOnlyCompileOptions& options,
+                                       js::HandleObject sourceObject,
+                                       uint32_t bufStart, uint32_t bufEnd,
+                                       uint32_t toStringStart, uint32_t toStringEnd);
+
   public:
     static JSScript* Create(JSContext* cx,
                             const JS::ReadOnlyCompileOptions& options,
                             js::HandleObject sourceObject,
                             uint32_t sourceStart, uint32_t sourceEnd,
                             uint32_t toStringStart, uint32_t toStringEnd);
 
     // Three ways ways to initialize a JSScript. Callers of partiallyInit()
@@ -1322,234 +1365,236 @@ class JSScript : public js::gc::TenuredC
         return toStringStart_;
     }
 
     uint32_t toStringEnd() const {
         return toStringEnd_;
     }
 
     bool noScriptRval() const {
-        return noScriptRval_;
+        return bitFields_.noScriptRval_;
     }
 
     bool strict() const {
-        return strict_;
+        return bitFields_.strict_;
     }
 
-    bool explicitUseStrict() const { return explicitUseStrict_; }
+    bool explicitUseStrict() const { return bitFields_.explicitUseStrict_; }
 
     bool hasNonSyntacticScope() const {
-        return hasNonSyntacticScope_;
+        return bitFields_.hasNonSyntacticScope_;
     }
 
-    bool selfHosted() const { return selfHosted_; }
-    bool bindingsAccessedDynamically() const { return bindingsAccessedDynamically_; }
+    bool selfHosted() const { return bitFields_.selfHosted_; }
+    bool bindingsAccessedDynamically() const { return bitFields_.bindingsAccessedDynamically_; }
     bool funHasExtensibleScope() const {
-        return funHasExtensibleScope_;
+        return bitFields_.funHasExtensibleScope_;
     }
     bool funHasAnyAliasedFormal() const {
-        return funHasAnyAliasedFormal_;
+        return bitFields_.funHasAnyAliasedFormal_;
     }
 
-    bool hasSingletons() const { return hasSingletons_; }
+    bool hasSingletons() const { return bitFields_.hasSingletons_; }
     bool treatAsRunOnce() const {
-        return treatAsRunOnce_;
+        return bitFields_.treatAsRunOnce_;
     }
-    bool hasRunOnce() const { return hasRunOnce_; }
-    bool hasBeenCloned() const { return hasBeenCloned_; }
-
-    void setTreatAsRunOnce() { treatAsRunOnce_ = true; }
-    void setHasRunOnce() { hasRunOnce_ = true; }
-    void setHasBeenCloned() { hasBeenCloned_ = true; }
-
-    bool isActiveEval() const { return isActiveEval_; }
-    bool isCachedEval() const { return isCachedEval_; }
+    bool hasRunOnce() const { return bitFields_.hasRunOnce_; }
+    bool hasBeenCloned() const { return bitFields_.hasBeenCloned_; }
+
+    void setTreatAsRunOnce() { bitFields_.treatAsRunOnce_ = true; }
+    void setHasRunOnce() { bitFields_.hasRunOnce_ = true; }
+    void setHasBeenCloned() { bitFields_.hasBeenCloned_ = true; }
+
+    bool isActiveEval() const { return bitFields_.isActiveEval_; }
+    bool isCachedEval() const { return bitFields_.isCachedEval_; }
 
     void cacheForEval() {
-        MOZ_ASSERT(isActiveEval() && !isCachedEval());
-        isActiveEval_ = false;
-        isCachedEval_ = true;
+        MOZ_ASSERT(isActiveEval());
+        MOZ_ASSERT(!isCachedEval());
+        bitFields_.isActiveEval_ = false;
+        bitFields_.isCachedEval_ = true;
         // IsEvalCacheCandidate will make sure that there's nothing in this
         // script that would prevent reexecution even if isRunOnce is
         // true.  So just pretend like we never ran this script.
-        hasRunOnce_ = false;
+        bitFields_.hasRunOnce_ = false;
     }
 
     void uncacheForEval() {
-        MOZ_ASSERT(isCachedEval() && !isActiveEval());
-        isCachedEval_ = false;
-        isActiveEval_ = true;
+        MOZ_ASSERT(isCachedEval());
+        MOZ_ASSERT(!isActiveEval());
+        bitFields_.isCachedEval_ = false;
+        bitFields_.isActiveEval_ = true;
     }
 
-    void setActiveEval() { isActiveEval_ = true; }
+    void setActiveEval() { bitFields_.isActiveEval_ = true; }
 
     bool isLikelyConstructorWrapper() const {
-        return isLikelyConstructorWrapper_;
+        return bitFields_.isLikelyConstructorWrapper_;
     }
-    void setLikelyConstructorWrapper() { isLikelyConstructorWrapper_ = true; }
+    void setLikelyConstructorWrapper() { bitFields_.isLikelyConstructorWrapper_ = true; }
 
     bool failedBoundsCheck() const {
-        return failedBoundsCheck_;
+        return bitFields_.failedBoundsCheck_;
     }
     bool failedShapeGuard() const {
-        return failedShapeGuard_;
+        return bitFields_.failedShapeGuard_;
     }
     bool hadFrequentBailouts() const {
-        return hadFrequentBailouts_;
+        return bitFields_.hadFrequentBailouts_;
     }
     bool hadOverflowBailout() const {
-        return hadOverflowBailout_;
+        return bitFields_.hadOverflowBailout_;
     }
     bool uninlineable() const {
-        return uninlineable_;
+        return bitFields_.uninlineable_;
     }
     bool invalidatedIdempotentCache() const {
-        return invalidatedIdempotentCache_;
+        return bitFields_.invalidatedIdempotentCache_;
     }
     bool failedLexicalCheck() const {
-        return failedLexicalCheck_;
+        return bitFields_.failedLexicalCheck_;
     }
     bool isDefaultClassConstructor() const {
-        return isDefaultClassConstructor_;
+        return bitFields_.isDefaultClassConstructor_;
     }
 
-    void setFailedBoundsCheck() { failedBoundsCheck_ = true; }
-    void setFailedShapeGuard() { failedShapeGuard_ = true; }
-    void setHadFrequentBailouts() { hadFrequentBailouts_ = true; }
-    void setHadOverflowBailout() { hadOverflowBailout_ = true; }
-    void setUninlineable() { uninlineable_ = true; }
-    void setInvalidatedIdempotentCache() { invalidatedIdempotentCache_ = true; }
-    void setFailedLexicalCheck() { failedLexicalCheck_ = true; }
-    void setIsDefaultClassConstructor() { isDefaultClassConstructor_ = true; }
-
-    bool hasScriptCounts() const { return hasScriptCounts_; }
+    void setFailedBoundsCheck() { bitFields_.failedBoundsCheck_ = true; }
+    void setFailedShapeGuard() { bitFields_.failedShapeGuard_ = true; }
+    void setHadFrequentBailouts() { bitFields_.hadFrequentBailouts_ = true; }
+    void setHadOverflowBailout() { bitFields_.hadOverflowBailout_ = true; }
+    void setUninlineable() { bitFields_.uninlineable_ = true; }
+    void setInvalidatedIdempotentCache() { bitFields_.invalidatedIdempotentCache_ = true; }
+    void setFailedLexicalCheck() { bitFields_.failedLexicalCheck_ = true; }
+    void setIsDefaultClassConstructor() { bitFields_.isDefaultClassConstructor_ = true; }
+
+    bool hasScriptCounts() const { return bitFields_.hasScriptCounts_; }
     bool hasScriptName();
 
-    bool hasFreezeConstraints() const { return hasFreezeConstraints_; }
-    void setHasFreezeConstraints() { hasFreezeConstraints_ = true; }
-
-    bool warnedAboutUndefinedProp() const { return warnedAboutUndefinedProp_; }
-    void setWarnedAboutUndefinedProp() { warnedAboutUndefinedProp_ = true; }
+    bool hasFreezeConstraints() const { return bitFields_.hasFreezeConstraints_; }
+    void setHasFreezeConstraints() { bitFields_.hasFreezeConstraints_ = true; }
+
+    bool warnedAboutUndefinedProp() const { return bitFields_.warnedAboutUndefinedProp_; }
+    void setWarnedAboutUndefinedProp() { bitFields_.warnedAboutUndefinedProp_ = true; }
 
     /* See ContextFlags::funArgumentsHasLocalBinding comment. */
     bool argumentsHasVarBinding() const {
-        return argsHasVarBinding_;
+        return bitFields_.argsHasVarBinding_;
     }
     void setArgumentsHasVarBinding();
     bool argumentsAliasesFormals() const {
         return argumentsHasVarBinding() && hasMappedArgsObj();
     }
 
     js::GeneratorKind generatorKind() const {
-        return isGenerator_ ? js::GeneratorKind::Generator : js::GeneratorKind::NotGenerator;
+        return bitFields_.isGenerator_ ? js::GeneratorKind::Generator : js::GeneratorKind::NotGenerator;
     }
-    bool isGenerator() const { return isGenerator_; }
+    bool isGenerator() const { return bitFields_.isGenerator_; }
     void setGeneratorKind(js::GeneratorKind kind) {
         // A script only gets its generator kind set as part of initialization,
         // so it can only transition from not being a generator.
         MOZ_ASSERT(!isGenerator());
-        isGenerator_ = kind == js::GeneratorKind::Generator;
+        bitFields_.isGenerator_ = kind == js::GeneratorKind::Generator;
     }
 
     js::FunctionAsyncKind asyncKind() const {
-        return isAsync_
+        return bitFields_.isAsync_
                ? js::FunctionAsyncKind::AsyncFunction
                : js::FunctionAsyncKind::SyncFunction;
     }
     bool isAsync() const {
-        return isAsync_;
+        return bitFields_.isAsync_;
     }
 
     void setAsyncKind(js::FunctionAsyncKind kind) {
-        isAsync_ = kind == js::FunctionAsyncKind::AsyncFunction;
+        bitFields_.isAsync_ = kind == js::FunctionAsyncKind::AsyncFunction;
     }
 
     bool hasRest() const {
-        return hasRest_;
+        return bitFields_.hasRest_;
     }
     void setHasRest() {
-        hasRest_ = true;
+        bitFields_.hasRest_ = true;
     }
 
     bool hideScriptFromDebugger() const {
-        return hideScriptFromDebugger_;
+        return bitFields_.hideScriptFromDebugger_;
     }
     void clearHideScriptFromDebugger() {
-        hideScriptFromDebugger_ = false;
+        bitFields_.hideScriptFromDebugger_ = false;
     }
 
     void setNeedsHomeObject() {
-        needsHomeObject_ = true;
+        bitFields_.needsHomeObject_ = true;
     }
     bool needsHomeObject() const {
-        return needsHomeObject_;
+        return bitFields_.needsHomeObject_;
     }
 
     bool isDerivedClassConstructor() const {
-        return isDerivedClassConstructor_;
+        return bitFields_.isDerivedClassConstructor_;
     }
 
     /*
      * As an optimization, even when argsHasLocalBinding, the function prologue
      * may not need to create an arguments object. This is determined by
      * needsArgsObj which is set by AnalyzeArgumentsUsage. When !needsArgsObj,
      * the prologue may simply write MagicValue(JS_OPTIMIZED_ARGUMENTS) to
      * 'arguments's slot and any uses of 'arguments' will be guaranteed to
      * handle this magic value. To avoid spurious arguments object creation, we
      * maintain the invariant that needsArgsObj is only called after the script
      * has been analyzed.
      */
-    bool analyzedArgsUsage() const { return !needsArgsAnalysis_; }
+    bool analyzedArgsUsage() const { return !bitFields_.needsArgsAnalysis_; }
     inline bool ensureHasAnalyzedArgsUsage(JSContext* cx);
     bool needsArgsObj() const {
         MOZ_ASSERT(analyzedArgsUsage());
-        return needsArgsObj_;
+        return bitFields_.needsArgsObj_;
     }
     void setNeedsArgsObj(bool needsArgsObj);
     static bool argumentsOptimizationFailed(JSContext* cx, js::HandleScript script);
 
     bool hasMappedArgsObj() const {
-        return hasMappedArgsObj_;
+        return bitFields_.hasMappedArgsObj_;
     }
 
     bool functionHasThisBinding() const {
-        return functionHasThisBinding_;
+        return bitFields_.functionHasThisBinding_;
     }
 
     /*
      * Arguments access (via JSOP_*ARG* opcodes) must access the canonical
      * location for the argument. If an arguments object exists AND it's mapped
      * ('arguments' aliases formals), then all access must go through the
      * arguments object. Otherwise, the local slot is the canonical location for
      * the arguments. Note: if a formal is aliased through the scope chain, then
      * script->formalIsAliased and JSOP_*ARG* opcodes won't be emitted at all.
      */
     bool argsObjAliasesFormals() const {
         return needsArgsObj() && hasMappedArgsObj();
     }
 
     uint32_t typesGeneration() const {
-        return (uint32_t) typesGeneration_;
+        return (uint32_t) bitFields_.typesGeneration_;
     }
 
     void setTypesGeneration(uint32_t generation) {
         MOZ_ASSERT(generation <= 1);
-        typesGeneration_ = (bool) generation;
+        bitFields_.typesGeneration_ = (bool) generation;
     }
 
     void setDoNotRelazify(bool b) {
-        doNotRelazify_ = b;
+        bitFields_.doNotRelazify_ = b;
     }
 
     void setHasInnerFunctions(bool b) {
-        hasInnerFunctions_ = b;
+        bitFields_.hasInnerFunctions_ = b;
     }
 
     bool hasInnerFunctions() const {
-        return hasInnerFunctions_;
+        return bitFields_.hasInnerFunctions_;
     }
 
     bool hasAnyIonScript() const {
         return hasIonScript();
     }
 
     bool hasIonScript() const {
         bool res = ion && ion != ION_DISABLED_SCRIPT && ion != ION_COMPILING_SCRIPT &&
@@ -1604,21 +1649,21 @@ class JSScript : public js::gc::TenuredC
     static constexpr size_t offsetOfJitCodeSkipArgCheck() {
         return offsetof(JSScript, jitCodeSkipArgCheck_);
     }
     uint8_t* jitCodeRaw() const {
         return jitCodeRaw_;
     }
 
     bool isRelazifiable() const {
-        return (selfHosted() || lazyScript) && !hasInnerFunctions_ && !types_ &&
+        return (selfHosted() || lazyScript) && !bitFields_.hasInnerFunctions_ && !types_ &&
                !isGenerator() && !isAsync() &&
                !isDefaultClassConstructor() &&
                !hasBaselineScript() && !hasAnyIonScript() &&
-               !doNotRelazify_;
+               !bitFields_.doNotRelazify_;
     }
     void setLazyScript(js::LazyScript* lazy) {
         lazyScript = lazy;
     }
     js::LazyScript* maybeLazyScript() {
         return lazyScript;
     }
 
@@ -1734,18 +1779,18 @@ class JSScript : public js::gc::TenuredC
     js::Scope* outermostScope() const {
         // The body scope may not be the outermost scope in the script when
         // the decl env scope is present.
         size_t index = 0;
         return getScope(index);
     }
 
     bool functionHasExtraBodyVarScope() const {
-        MOZ_ASSERT_IF(functionHasExtraBodyVarScope_, functionHasParameterExprs());
-        return functionHasExtraBodyVarScope_;
+        MOZ_ASSERT_IF(bitFields_.functionHasExtraBodyVarScope_, functionHasParameterExprs());
+        return bitFields_.functionHasExtraBodyVarScope_;
     }
 
     js::VarScope* functionExtraBodyVarScope() const {
         MOZ_ASSERT(functionHasExtraBodyVarScope());
         for (uint32_t i = 0; i < scopes()->length; i++) {
             js::Scope* scope = getScope(i);
             if (scope->kind() == js::ScopeKind::FunctionBodyVar)
                 return &scope->as<js::VarScope>();
@@ -1815,20 +1860,22 @@ class JSScript : public js::gc::TenuredC
      * sizeOfData() is the size of the block allocated to hold all the data
      * sections (which can be larger than the in-use size).
      */
     size_t computedSizeOfData() const;
     size_t sizeOfData(mozilla::MallocSizeOf mallocSizeOf) const;
     size_t sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const;
 
     bool hasArray(ArrayKind kind) const {
-        return hasArrayBits & (1 << kind);
+        return bitFields_.hasArrayBits_ & (1 << kind);
     }
-    void setHasArray(ArrayKind kind) { hasArrayBits |= (1 << kind); }
-    void cloneHasArray(JSScript* script) { hasArrayBits = script->hasArrayBits; }
+    void setHasArray(ArrayKind kind) { bitFields_.hasArrayBits_ |= (1 << kind); }
+    void cloneHasArray(JSScript* script) {
+        bitFields_.hasArrayBits_ = script->bitFields_.hasArrayBits_;
+    }
 
     bool hasConsts() const       { return hasArray(CONSTS); }
     bool hasObjects() const      { return hasArray(OBJECTS); }
     bool hasTrynotes() const     { return hasArray(TRYNOTES); }
     bool hasScopeNotes() const   { return hasArray(SCOPENOTES); }
     bool hasYieldAndAwaitOffsets() const {
         return isGenerator() || isAsync();
     }
@@ -1993,25 +2040,25 @@ class JSScript : public js::gc::TenuredC
 
     bool ensureHasDebugScript(JSContext* cx);
     js::DebugScript* debugScript();
     js::DebugScript* releaseDebugScript();
     void destroyDebugScript(js::FreeOp* fop);
 
   public:
     bool hasBreakpointsAt(jsbytecode* pc);
-    bool hasAnyBreakpointsOrStepMode() { return hasDebugScript_; }
+    bool hasAnyBreakpointsOrStepMode() { return bitFields_.hasDebugScript_; }
 
     // See comment above 'debugMode' in JSCompartment.h for explanation of
     // invariants of debuggee compartments, scripts, and frames.
     inline bool isDebuggee() const;
 
     js::BreakpointSite* getBreakpointSite(jsbytecode* pc)
     {
-        return hasDebugScript_ ? debugScript()->breakpoints[pcToOffset(pc)] : nullptr;
+        return bitFields_.hasDebugScript_ ? debugScript()->breakpoints[pcToOffset(pc)] : nullptr;
     }
 
     js::BreakpointSite* getOrCreateBreakpointSite(JSContext* cx, jsbytecode* pc);
 
     void destroyBreakpointSite(js::FreeOp* fop, jsbytecode* pc);
 
     void clearBreakpointsIn(js::FreeOp* fop, js::Debugger* dbg, JSObject* handler);
 
@@ -2019,20 +2066,20 @@ class JSScript : public js::gc::TenuredC
      * Increment or decrement the single-step count. If the count is non-zero
      * then the script is in single-step mode.
      *
      * Only incrementing is fallible, as it could allocate a DebugScript.
      */
     bool incrementStepModeCount(JSContext* cx);
     void decrementStepModeCount(js::FreeOp* fop);
 
-    bool stepModeEnabled() { return hasDebugScript_ && !!debugScript()->stepMode; }
+    bool stepModeEnabled() { return bitFields_.hasDebugScript_ && !!debugScript()->stepMode; }
 
 #ifdef DEBUG
-    uint32_t stepModeCount() { return hasDebugScript_ ? debugScript()->stepMode : 0; }
+    uint32_t stepModeCount() { return bitFields_.hasDebugScript_ ? debugScript()->stepMode : 0; }
 #endif
 
     void finalize(js::FreeOp* fop);
 
     static const JS::TraceKind TraceKind = JS::TraceKind::Script;
 
     void traceChildren(JSTracer* trc);
 
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -4541,32 +4541,32 @@ JSScript::sweepTypes(const js::AutoSweep
         !hasBaselineScript() &&
         !hasIonScript())
     {
         types_->destroy();
         types_ = nullptr;
 
         // Freeze constraints on stack type sets need to be regenerated the
         // next time the script is analyzed.
-        hasFreezeConstraints_ = false;
+        bitFields_.hasFreezeConstraints_ = false;
 
         return;
     }
 
     unsigned num = TypeScript::NumTypeSets(this);
     StackTypeSet* typeArray = types_->typeArray();
 
     // Remove constraints and references to dead objects from stack type sets.
     for (unsigned i = 0; i < num; i++)
         typeArray[i].sweep(sweep, zone(), *oom);
 
     if (oom->hadOOM()) {
         // It's possible we OOM'd while copying freeze constraints, so they
         // need to be regenerated.
-        hasFreezeConstraints_ = false;
+        bitFields_.hasFreezeConstraints_ = false;
     }
 }
 
 void
 TypeScript::destroy()
 {
     js_delete(this);
 }