Bug 1524499 part 2 - Move the AutoSweepTypeScript& from JSScript::types() to TypeScript methods that depend on swept data. r=tcampbell
authorJan de Mooij <jdemooij@mozilla.com>
Wed, 06 Feb 2019 07:56:49 +0000
changeset 518272 936d2328fb864d10c086729bc3105d115430009b
parent 518271 fdc01631d226da0960703451ed2045853658304c
child 518273 71b541173043dfb9ab7f58b8438374d3c7466cb1
push id2032
push userffxbld-merge
push dateMon, 13 May 2019 09:36:57 +0000
treeherdermozilla-release@455c1065dcbe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstcampbell
bugs1524499
milestone67.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 1524499 part 2 - Move the AutoSweepTypeScript& from JSScript::types() to TypeScript methods that depend on swept data. r=tcampbell As we add more fields to TypeScript (= JitScript in the future), the AutoSweepTypeScript argument to JSScript::types() is becoming annoying. This patch moves the argument to TypeScript::typeArray() and TypeScript::inlinedCompilations() because that's the data affected by type sweeping. Differential Revision: https://phabricator.services.mozilla.com/D18549
js/src/gc/Zone.cpp
js/src/jit/BaselineJIT.cpp
js/src/jit/IonBuilder.cpp
js/src/vm/BytecodeUtil.cpp
js/src/vm/Debugger.cpp
js/src/vm/JSScript.h
js/src/vm/TypeInference-inl.h
js/src/vm/TypeInference.cpp
js/src/vm/TypeInference.h
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -205,17 +205,17 @@ void Zone::discardJitCode(FreeOp* fop,
   if (isPreservingCode()) {
     return;
   }
 
   if (discardBaselineCode || releaseTypes) {
 #ifdef DEBUG
     // Assert no TypeScripts are marked as active.
     for (auto script = cellIter<JSScript>(); !script.done(); script.next()) {
-      if (TypeScript* types = script->typesDontCheckGeneration()) {
+      if (TypeScript* types = script->types()) {
         MOZ_ASSERT(!types->active());
       }
     }
 #endif
 
     // Mark TypeScripts on the stack as active.
     jit::MarkActiveTypeScripts(this);
   }
@@ -260,17 +260,17 @@ void Zone::discardJitCode(FreeOp* fop,
     // doesn't point into it. We do this after (potentially) releasing types
     // because TypeScript contains the ICScript* and there's no need to
     // purge stubs if we just destroyed the Typescript.
     if (discardBaselineCode && script->hasICScript()) {
       script->icScript()->purgeOptimizedStubs(script);
     }
 
     // Finally, reset the active flag.
-    if (TypeScript* types = script->typesDontCheckGeneration()) {
+    if (TypeScript* types = script->types()) {
       types->resetActive();
     }
   }
 
   /*
    * When scripts contains pointers to nursery things, the store buffer
    * can contain entries that point into the optimized stub space. Since
    * this method can be called outside the context of a GC, this situation
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -1137,17 +1137,17 @@ void jit::JitSpewBaselineICStats(JSScrip
 }
 #endif
 
 void jit::FinishDiscardBaselineScript(FreeOp* fop, JSScript* script) {
   if (!script->hasBaselineScript()) {
     return;
   }
 
-  if (script->typesDontCheckGeneration()->active()) {
+  if (script->types()->active()) {
     // The baseline caches have been wiped out, so the script will need to
     // warm back up before it can be inlined during Ion compilation.
     script->baselineScript()->clearIonCompiledOrInlined();
     return;
   }
 
   BaselineScript* baseline = script->baselineScript();
   script->setBaselineScript(fop->runtime(), nullptr);
@@ -1213,35 +1213,35 @@ void jit::ToggleBaselineTraceLoggerEngin
 #endif
 
 static void MarkActiveTypeScripts(JSContext* cx,
                                   const JitActivationIterator& activation) {
   for (OnlyJSJitFrameIter iter(activation); !iter.done(); ++iter) {
     const JSJitFrameIter& frame = iter.frame();
     switch (frame.type()) {
       case FrameType::BaselineJS:
-        frame.script()->typesDontCheckGeneration()->setActive();
+        frame.script()->types()->setActive();
         break;
       case FrameType::Exit:
         if (frame.exitFrame()->is<LazyLinkExitFrameLayout>()) {
           LazyLinkExitFrameLayout* ll =
               frame.exitFrame()->as<LazyLinkExitFrameLayout>();
           JSScript* script =
               ScriptFromCalleeToken(ll->jsFrame()->calleeToken());
-          script->typesDontCheckGeneration()->setActive();
+          script->types()->setActive();
         }
         break;
       case FrameType::Bailout:
       case FrameType::IonJS: {
         // Keep the TypeScript and BaselineScript around, since bailouts from
         // the ion jitcode need to re-enter into the Baseline code.
-        frame.script()->typesDontCheckGeneration()->setActive();
+        frame.script()->types()->setActive();
         for (InlineFrameIterator inlineIter(cx, &frame); inlineIter.more();
              ++inlineIter) {
-          inlineIter.script()->typesDontCheckGeneration()->setActive();
+          inlineIter.script()->types()->setActive();
         }
         break;
       }
       default:;
     }
   }
 }
 
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -751,18 +751,17 @@ AbortReasonOr<Ok> IonBuilder::init() {
   if (inlineCallInfo_) {
     // If we're inlining, the actual this/argument types are not necessarily
     // a subset of the script's observed types. |argTypes| is never accessed
     // for inlined scripts, so we just null it.
     thisTypes = inlineCallInfo_->thisArg()->resultTypeSet();
     argTypes = nullptr;
   }
 
-  AutoSweepTypeScript sweep(script());
-  bytecodeTypeMap = script()->types(sweep)->bytecodeTypeMap();
+  bytecodeTypeMap = script()->types()->bytecodeTypeMap();
 
   return Ok();
 }
 
 AbortReasonOr<Ok> IonBuilder::build() {
   // Spew IC info for inlined script, but only when actually compiling,
   // not when analyzing it.
 #ifdef JS_STRUCTURED_SPEW
--- a/js/src/vm/BytecodeUtil.cpp
+++ b/js/src/vm/BytecodeUtil.cpp
@@ -2547,18 +2547,17 @@ JS_FRIEND_API void js::StopPCCountProfil
       cx, ScriptAndCountsVector(SystemAllocPolicy()));
   if (!vec) {
     return;
   }
 
   for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
     for (auto script = zone->cellIter<JSScript>(); !script.done();
          script.next()) {
-      AutoSweepTypeScript sweep(script);
-      if (script->hasScriptCounts() && script->types(sweep)) {
+      if (script->hasScriptCounts() && script->types()) {
         if (!vec->append(script)) {
           return;
         }
       }
     }
   }
 
   rt->profilingScripts = false;
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -2703,17 +2703,17 @@ class MOZ_RAII ExecutionObservableScript
   }
 
   return true;
 }
 
 static inline void MarkTypeScriptActiveIfObservable(
     JSScript* script, const Debugger::ExecutionObservableSet& obs) {
   if (obs.shouldRecompileOrInvalidate(script)) {
-    script->typesDontCheckGeneration()->setActive();
+    script->types()->setActive();
   }
 }
 
 static bool AppendAndInvalidateScript(JSContext* cx, Zone* zone,
                                       JSScript* script,
                                       Vector<JSScript*>& scripts) {
   // Enter the script's realm as addPendingRecompile attempts to
   // cancel off-thread compilations, whose books are kept on the
@@ -2787,17 +2787,17 @@ static bool UpdateExecutionObservability
   }
 
   // Iterate through the scripts again and finish discarding
   // BaselineScripts. This must be done as a separate phase as we can only
   // discard the BaselineScript on scripts that have no IonScript.
   for (size_t i = 0; i < scripts.length(); i++) {
     MOZ_ASSERT_IF(scripts[i]->isDebuggee(), observing);
     FinishDiscardBaselineScript(fop, scripts[i]);
-    scripts[i]->typesDontCheckGeneration()->resetActive();
+    scripts[i]->types()->resetActive();
   }
 
   // Iterate through all wasm instances to find ones that need to be updated.
   for (RealmsInZoneIter r(zone); !r.done(); r.next()) {
     for (wasm::Instance* instance : r->wasm.instances()) {
       if (!instance->debugEnabled()) {
         continue;
       }
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -2414,21 +2414,19 @@ class JSScript : public js::gc::TenuredC
    *
    * If this script has a function associated to it, then it is not the
    * top-level of a file.
    */
   bool isTopLevel() { return code() && !functionNonDelazifying(); }
 
   /* Ensure the script has a TypeScript. */
   inline bool ensureHasTypes(JSContext* cx, js::AutoKeepTypeScripts&);
-
-  inline js::TypeScript* types(const js::AutoSweepTypeScript& sweep);
   inline bool typesNeedsSweep() const;
 
-  js::TypeScript* typesDontCheckGeneration() { return types_; }
+  js::TypeScript* types() { return types_; }
 
   void maybeReleaseTypes();
   void sweepTypes(const js::AutoSweepTypeScript& sweep);
 
   inline js::GlobalObject& global() const;
   inline bool hasGlobal(const js::GlobalObject* global) const;
   js::GlobalObject& uninlinedGlobal() const;
 
--- a/js/src/vm/TypeInference-inl.h
+++ b/js/src/vm/TypeInference-inl.h
@@ -464,21 +464,18 @@ void TypeMonitorCallSlow(JSContext* cx, 
 /*
  * Monitor a javascript call, either on entry to the interpreter or made
  * from within the interpreter.
  */
 inline void TypeMonitorCall(JSContext* cx, const js::CallArgs& args,
                             bool constructing) {
   if (args.callee().is<JSFunction>()) {
     JSFunction* fun = &args.callee().as<JSFunction>();
-    if (fun->isInterpreted()) {
-      AutoSweepTypeScript sweep(fun->nonLazyScript());
-      if (fun->nonLazyScript()->types(sweep)) {
-        TypeMonitorCallSlow(cx, &args.callee(), args, constructing);
-      }
+    if (fun->isInterpreted() && fun->nonLazyScript()->types()) {
+      TypeMonitorCallSlow(cx, &args.callee(), args, constructing);
     }
   }
 }
 
 MOZ_ALWAYS_INLINE bool TrackPropertyTypes(JSObject* obj, jsid id) {
   if (obj->hasLazyGroup() ||
       obj->group()->unknownPropertiesDontCheckGeneration()) {
     return false;
@@ -623,35 +620,35 @@ extern void TypeMonitorResult(JSContext*
 extern void TypeMonitorResult(JSContext* cx, JSScript* script, jsbytecode* pc,
                               const Value& rval);
 
 /////////////////////////////////////////////////////////////////////
 // Script interface functions
 /////////////////////////////////////////////////////////////////////
 
 /* static */ inline StackTypeSet* TypeScript::ThisTypes(JSScript* script) {
-  AutoSweepTypeScript sweep(script);
-  if (TypeScript* types = script->types(sweep)) {
-    return types->typeArray() + script->numBytecodeTypeSets();
+  if (TypeScript* types = script->types()) {
+    AutoSweepTypeScript sweep(script);
+    return types->typeArray(sweep) + script->numBytecodeTypeSets();
   }
   return nullptr;
 }
 
 /*
  * Note: for non-escaping arguments, argTypes reflect only the initial type of
  * the variable (e.g. passed values for argTypes, or undefined for localTypes)
  * and not types from subsequent assignments.
  */
 
 /* static */ inline StackTypeSet* TypeScript::ArgTypes(JSScript* script,
                                                        unsigned i) {
   MOZ_ASSERT(i < script->functionNonDelazifying()->nargs());
-  AutoSweepTypeScript sweep(script);
-  if (TypeScript* types = script->types(sweep)) {
-    return types->typeArray() + script->numBytecodeTypeSets() + 1 + i;
+  if (TypeScript* types = script->types()) {
+    AutoSweepTypeScript sweep(script);
+    return types->typeArray(sweep) + script->numBytecodeTypeSets() + 1 + i;
   }
   return nullptr;
 }
 
 template <typename TYPESET>
 /* static */ inline TYPESET* TypeScript::BytecodeTypes(JSScript* script,
                                                        jsbytecode* pc,
                                                        uint32_t* bytecodeMap,
@@ -687,24 +684,24 @@ template <typename TYPESET>
 
   *hint = mozilla::AssertedCast<uint32_t>(loc);
   return typeArray + *hint;
 }
 
 /* static */ inline StackTypeSet* TypeScript::BytecodeTypes(JSScript* script,
                                                             jsbytecode* pc) {
   MOZ_ASSERT(CurrentThreadCanAccessZone(script->zone()));
-  AutoSweepTypeScript sweep(script);
-  TypeScript* types = script->types(sweep);
+  TypeScript* types = script->types();
   if (!types) {
     return nullptr;
   }
+  AutoSweepTypeScript sweep(script);
   uint32_t* hint = types->bytecodeTypeMapHint();
   return BytecodeTypes(script, pc, types->bytecodeTypeMap(), hint,
-                       types->typeArray());
+                       types->typeArray(sweep));
 }
 
 /* static */ inline void TypeScript::Monitor(JSContext* cx, JSScript* script,
                                              jsbytecode* pc,
                                              const js::Value& rval) {
   TypeMonitorResult(cx, script, pc, rval);
 }
 
@@ -1433,24 +1430,18 @@ inline AutoSweepTypeScript::AutoSweepTyp
 inline AutoSweepTypeScript::~AutoSweepTypeScript() {
   // This should still hold.
   MOZ_ASSERT(!script_->typesNeedsSweep());
 }
 #endif
 
 }  // namespace js
 
-inline js::TypeScript* JSScript::types(const js::AutoSweepTypeScript& sweep) {
-  MOZ_ASSERT(sweep.script() == this);
-  return types_;
-}
-
 inline bool JSScript::typesNeedsSweep() const {
   MOZ_ASSERT(!js::TlsContext.get()->inUnsafeCallWithABI);
   return types_ && typesGeneration() != zone()->types.generation;
 }
 
 inline bool JSScript::ensureHasTypes(JSContext* cx, js::AutoKeepTypeScripts&) {
-  js::AutoSweepTypeScript sweep(this);
-  return types(sweep) || makeTypes(cx);
+  return types() || makeTypes(cx);
 }
 
 #endif /* vm_TypeInference_inl_h */
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -1190,18 +1190,18 @@ CompilerConstraintList* js::NewCompilerC
 }
 
 /* static */ bool TypeScript::FreezeTypeSets(
     CompilerConstraintList* constraints, JSScript* script,
     TemporaryTypeSet** pThisTypes, TemporaryTypeSet** pArgTypes,
     TemporaryTypeSet** pBytecodeTypes) {
   LifoAlloc* alloc = constraints->alloc();
   AutoSweepTypeScript sweep(script);
-  TypeScript* typeScript = script->types(sweep);
-  StackTypeSet* existing = typeScript->typeArray();
+  TypeScript* typeScript = script->types();
+  StackTypeSet* existing = typeScript->typeArray(sweep);
 
   size_t count = typeScript->numTypeSets();
   TemporaryTypeSet* types =
       alloc->newArrayUninitialized<TemporaryTypeSet>(count);
   if (!types) {
     return false;
   }
 
@@ -1501,67 +1501,67 @@ bool js::FinishCompilation(JSContext* cx
     if (!constraint->generateTypeConstraint(cx, recompileInfo)) {
       succeeded = false;
     }
   }
 
   for (size_t i = 0; i < constraints->numFrozenScripts(); i++) {
     const CompilerConstraintList::FrozenScript& entry =
         constraints->frozenScript(i);
-    AutoSweepTypeScript sweep(entry.script);
-    TypeScript* types = entry.script->types(sweep);
+    TypeScript* types = entry.script->types();
     if (!types) {
       succeeded = false;
       break;
     }
 
     // It could happen that one of the compiled scripts was made a
     // debuggee mid-compilation (e.g., via setting a breakpoint). If so,
     // throw away the compilation.
     if (entry.script->isDebuggee()) {
       succeeded = false;
       break;
     }
 
+    AutoSweepTypeScript sweep(entry.script);
     if (!CheckFrozenTypeSet(sweep, cx, entry.thisTypes,
                             TypeScript::ThisTypes(entry.script))) {
       succeeded = false;
     }
     unsigned nargs = entry.script->functionNonDelazifying()
                          ? entry.script->functionNonDelazifying()->nargs()
                          : 0;
     for (size_t i = 0; i < nargs; i++) {
       if (!CheckFrozenTypeSet(sweep, cx, &entry.argTypes[i],
                               TypeScript::ArgTypes(entry.script, i))) {
         succeeded = false;
       }
     }
     for (size_t i = 0; i < entry.script->numBytecodeTypeSets(); i++) {
       if (!CheckFrozenTypeSet(sweep, cx, &entry.bytecodeTypes[i],
-                              &types->typeArray()[i])) {
+                              &types->typeArray(sweep)[i])) {
         succeeded = false;
       }
     }
 
     // Add this compilation to the inlinedCompilations list of each inlined
     // script, so we can invalidate it on changes to stack type sets.
     if (entry.script != script) {
-      if (!types->addInlinedCompilation(recompileInfo)) {
+      if (!types->addInlinedCompilation(sweep, recompileInfo)) {
         succeeded = false;
       }
     }
 
     // If necessary, add constraints to trigger invalidation on the script
     // after any future changes to the stack type sets.
     if (entry.script->hasFreezeConstraints()) {
       continue;
     }
 
     size_t count = types->numTypeSets();
-    StackTypeSet* array = types->typeArray();
+    StackTypeSet* array = types->typeArray(sweep);
     for (size_t i = 0; i < count; i++) {
       if (!array[i].addConstraint(
               cx,
               cx->typeLifoAlloc().new_<TypeConstraintFreezeStack>(entry.script),
               false)) {
         succeeded = false;
       }
     }
@@ -1606,59 +1606,59 @@ void js::FinishDefinitePropertiesAnalysi
   // Assert no new types have been added to the StackTypeSets. Do this before
   // calling CheckDefinitePropertiesTypeSet, as it may add new types to the
   // StackTypeSets and break these invariants if a script is inlined more
   // than once. See also CheckDefinitePropertiesTypeSet.
   for (size_t i = 0; i < constraints->numFrozenScripts(); i++) {
     const CompilerConstraintList::FrozenScript& entry =
         constraints->frozenScript(i);
     JSScript* script = entry.script;
-    AutoSweepTypeScript sweep(script);
-    MOZ_ASSERT(script->types(sweep));
+    MOZ_ASSERT(script->types());
 
     MOZ_ASSERT(TypeScript::ThisTypes(script)->isSubset(entry.thisTypes));
 
     unsigned nargs = entry.script->functionNonDelazifying()
                          ? entry.script->functionNonDelazifying()->nargs()
                          : 0;
     for (size_t j = 0; j < nargs; j++) {
       MOZ_ASSERT(TypeScript::ArgTypes(script, j)->isSubset(&entry.argTypes[j]));
     }
 
+    AutoSweepTypeScript sweep(script);
     for (size_t j = 0; j < script->numBytecodeTypeSets(); j++) {
-      MOZ_ASSERT(script->types(sweep)->typeArray()[j].isSubset(
+      MOZ_ASSERT(script->types()->typeArray(sweep)[j].isSubset(
           &entry.bytecodeTypes[j]));
     }
   }
 #endif
 
   for (size_t i = 0; i < constraints->numFrozenScripts(); i++) {
     const CompilerConstraintList::FrozenScript& entry =
         constraints->frozenScript(i);
     JSScript* script = entry.script;
-    AutoSweepTypeScript sweep(script);
-    TypeScript* types = script->types(sweep);
+    TypeScript* types = script->types();
     if (!types) {
       MOZ_CRASH();
     }
 
+    AutoSweepTypeScript sweep(script);
     CheckDefinitePropertiesTypeSet(sweep, cx, entry.thisTypes,
                                    TypeScript::ThisTypes(script));
 
     unsigned nargs = script->functionNonDelazifying()
                          ? script->functionNonDelazifying()->nargs()
                          : 0;
     for (size_t j = 0; j < nargs; j++) {
       CheckDefinitePropertiesTypeSet(sweep, cx, &entry.argTypes[j],
                                      TypeScript::ArgTypes(script, j));
     }
 
     for (size_t j = 0; j < script->numBytecodeTypeSets(); j++) {
       CheckDefinitePropertiesTypeSet(sweep, cx, &entry.bytecodeTypes[j],
-                                     &types->typeArray()[j]);
+                                     &types->typeArray(sweep)[j]);
     }
   }
 }
 
 namespace {
 
 // Constraint which triggers recompilation of a script if any type is added to a
 // type set. */
@@ -2725,22 +2725,22 @@ void TypeZone::addPendingRecompile(JSCon
   }
 
   if (script->hasIonScript()) {
     addPendingRecompile(
         cx, RecompileInfo(script, script->ionScript()->compilationId()));
   }
 
   // Trigger recompilation of any callers inlining this script.
-  AutoSweepTypeScript sweep(script);
-  if (TypeScript* types = script->types(sweep)) {
-    for (const RecompileInfo& info : types->inlinedCompilations()) {
+  if (TypeScript* types = script->types()) {
+    AutoSweepTypeScript sweep(script);
+    for (const RecompileInfo& info : types->inlinedCompilations(sweep)) {
       addPendingRecompile(cx, info);
     }
-    types->inlinedCompilations().clearAndFree();
+    types->inlinedCompilations(sweep).clearAndFree();
   }
 }
 
 #ifdef JS_CRASH_DIAGNOSTICS
 void js::ReportMagicWordFailure(uintptr_t actual, uintptr_t expected) {
   MOZ_CRASH_UNSAFE_PRINTF("Got 0x%" PRIxPTR " expected magic word 0x%" PRIxPTR,
                           actual, expected);
 }
@@ -2762,19 +2762,18 @@ void js::PrintTypes(JSContext* cx, Compa
 
   if (!force && !InferSpewActive(ISpewResult)) {
     return;
   }
 
   RootedScript script(cx);
   for (auto iter = zone->cellIter<JSScript>(); !iter.done(); iter.next()) {
     script = iter;
-    AutoSweepTypeScript sweep(script);
-    if (script->types(sweep)) {
-      script->types(sweep)->printTypes(cx, script);
+    if (TypeScript* types = script->types()) {
+      types->printTypes(cx, script);
     }
   }
 
   for (auto group = zone->cellIter<ObjectGroup>(); !group.done();
        group.next()) {
     AutoSweepObjectGroup sweep(group);
     group->print(sweep);
   }
@@ -3439,19 +3438,19 @@ bool js::AddClearDefiniteFunctionUsesInS
   // analysis was done is stable. We only need to look at type sets which
   // contain a single object, as IonBuilder does not inline polymorphic sites
   // during the definite properties analysis.
 
   TypeSet::ObjectKey* calleeKey =
       TypeSet::ObjectType(calleeScript->functionNonDelazifying()).objectKey();
 
   AutoSweepTypeScript sweep(script);
-  TypeScript* typeScript = script->types(sweep);
+  TypeScript* typeScript = script->types();
   unsigned count = typeScript->numTypeSets();
-  StackTypeSet* typeArray = typeScript->typeArray();
+  StackTypeSet* typeArray = typeScript->typeArray(sweep);
 
   for (unsigned i = 0; i < count; i++) {
     StackTypeSet* types = &typeArray[i];
     if (!types->unknownObject() && types->getObjectCount() == 1) {
       if (calleeKey != types->getObject(0)) {
         // Also check if the object is the Function.call or
         // Function.apply native. IonBuilder uses the presence of these
         // functions during inlining.
@@ -3593,17 +3592,17 @@ static size_t NumTypeSets(JSScript* scri
 }
 
 TypeScript::TypeScript(JSScript* script, ICScriptPtr&& icScript,
                        uint32_t numTypeSets)
     : icScript_(std::move(icScript)),
       numTypeSets_(numTypeSets),
       bytecodeTypeMapHint_(0),
       active_(false) {
-  StackTypeSet* array = typeArray();
+  StackTypeSet* array = typeArrayDontCheckGeneration();
   for (unsigned i = 0; i < numTypeSets; i++) {
     new (&array[i]) StackTypeSet();
   }
 
   FillBytecodeTypeMap(script, bytecodeTypeMap());
 }
 
 bool JSScript::makeTypes(JSContext* cx) {
@@ -3640,17 +3639,17 @@ bool JSScript::makeTypes(JSContext* cx) 
   }
 
   prepareForDestruction.release();
 
   types_ = new (typeScript) TypeScript(this, std::move(icScript), numTypeSets);
   setTypesGeneration(cx->zone()->types.generation);
 
 #ifdef DEBUG
-  StackTypeSet* typeArray = typeScript->typeArray();
+  StackTypeSet* typeArray = typeScript->typeArrayDontCheckGeneration();
   for (unsigned i = 0; i < numBytecodeTypeSets(); i++) {
     InferSpew(ISpewOps, "typeSet: %sT%p%s bytecode%u %p",
               InferSpewColor(&typeArray[i]), &typeArray[i],
               InferSpewColorReset(), i, this);
   }
   TypeSet* thisTypes = TypeScript::ThisTypes(this);
   InferSpew(ISpewOps, "typeSet: %sT%p%s this %p", InferSpewColor(thisTypes),
             thisTypes, InferSpewColorReset(), this);
@@ -4711,30 +4710,31 @@ void ObjectGroup::sweep(const AutoSweepO
   if (!zone()->types.isSweepingTypes()) {
     clearStateOnOOM.emplace(zone());
   }
 
   TypeZone& types = zone()->types;
 
   // Sweep the inlinedCompilations Vector.
   {
-    RecompileInfoVector& inlinedCompilations = types_->inlinedCompilations();
+    RecompileInfoVector& inlinedCompilations =
+        types_->inlinedCompilations(sweep);
     size_t dest = 0;
     for (size_t i = 0; i < inlinedCompilations.length(); i++) {
       if (inlinedCompilations[i].shouldSweep(types)) {
         continue;
       }
       inlinedCompilations[dest] = inlinedCompilations[i];
       dest++;
     }
     inlinedCompilations.shrinkTo(dest);
   }
 
   unsigned num = types_->numTypeSets();
-  StackTypeSet* typeArray = types_->typeArray();
+  StackTypeSet* typeArray = types_->typeArray(sweep);
 
   // Remove constraints and references to dead objects from stack type sets.
   for (unsigned i = 0; i < num; i++) {
     typeArray[i].sweep(sweep, zone());
   }
 
   if (zone()->types.hadOOMSweepingTypes()) {
     // It's possible we OOM'd while copying freeze constraints, so they
@@ -4843,23 +4843,19 @@ AutoClearTypeInferenceStateOnOOM::~AutoC
     zone->discardJitCode(rt->defaultFreeOp(), Zone::KeepBaselineCode);
     zone->types.clearAllNewScriptsOnOOM();
   }
 
   zone->types.setSweepingTypes(false);
 }
 
 #ifdef DEBUG
-void TypeScript::printTypes(JSContext* cx, HandleScript script) const {
+void TypeScript::printTypes(JSContext* cx, HandleScript script) {
   AutoSweepTypeScript sweep(script);
-  MOZ_ASSERT(script->types(sweep) == this);
-
-  if (!script->hasBaselineScript()) {
-    return;
-  }
+  MOZ_ASSERT(script->types() == this);
 
   AutoEnterAnalysis enter(nullptr, script->zone());
   Fprinter out(stderr);
 
   if (script->functionNonDelazifying()) {
     fprintf(stderr, "Function");
   } else if (script->isForEval()) {
     fprintf(stderr, "Eval");
@@ -4895,17 +4891,17 @@ void TypeScript::printTypes(JSContext* c
         return;
       }
       Disassemble1(cx, script, pc, script->pcToOffset(pc), true, &sprinter);
       fprintf(stderr, "%s", sprinter.string());
     }
 
     if (CodeSpec[*pc].format & JOF_TYPESET) {
       StackTypeSet* types = TypeScript::BytecodeTypes(script, pc);
-      fprintf(stderr, "  typeset %u:", unsigned(types - typeArray()));
+      fprintf(stderr, "  typeset %u:", unsigned(types - typeArray(sweep)));
       types->print();
       fprintf(stderr, "\n");
     }
   }
 
   fprintf(stderr, "\n");
 }
 #endif /* DEBUG */
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -222,21 +222,35 @@ class TypeScript {
 
   // Flag set when discarding JIT code to indicate this script is on the stack
   // and type information and JIT code should not be discarded.
   bool active_;
 
   // Variable-size array. This is followed by the bytecode type map.
   StackTypeSet typeArray_[1];
 
+  StackTypeSet* typeArrayDontCheckGeneration() {
+    // Ensure typeArray_ is the last data member of TypeScript.
+    static_assert(sizeof(TypeScript) ==
+                      sizeof(typeArray_) + offsetof(TypeScript, typeArray_),
+                  "typeArray_ must be the last member of TypeScript");
+    return const_cast<StackTypeSet*>(typeArray_);
+  }
+
  public:
   TypeScript(JSScript* script, ICScriptPtr&& icScript, uint32_t numTypeSets);
 
-  RecompileInfoVector& inlinedCompilations() { return inlinedCompilations_; }
-  MOZ_MUST_USE bool addInlinedCompilation(RecompileInfo info) {
+  RecompileInfoVector& inlinedCompilations(
+      const js::AutoSweepTypeScript& sweep) {
+    MOZ_ASSERT(sweep.script()->types() == this);
+    return inlinedCompilations_;
+  }
+  MOZ_MUST_USE bool addInlinedCompilation(const js::AutoSweepTypeScript& sweep,
+                                          RecompileInfo info) {
+    MOZ_ASSERT(sweep.script()->types() == this);
     if (!inlinedCompilations_.empty() && inlinedCompilations_.back() == info) {
       return true;
     }
     return inlinedCompilations_.append(info);
   }
 
   uint32_t numTypeSets() const { return numTypeSets_; }
 
@@ -247,21 +261,19 @@ class TypeScript {
   void resetActive() { active_ = false; }
 
   jit::ICScript* icScript() const {
     MOZ_ASSERT(icScript_);
     return icScript_.get();
   }
 
   /* Array of type sets for variables and JOF_TYPESET ops. */
-  StackTypeSet* typeArray() const {
-    // Ensure typeArray_ is the last data member of TypeScript.
-    JS_STATIC_ASSERT(sizeof(TypeScript) ==
-                     sizeof(typeArray_) + offsetof(TypeScript, typeArray_));
-    return const_cast<StackTypeSet*>(typeArray_);
+  StackTypeSet* typeArray(const js::AutoSweepTypeScript& sweep) {
+    MOZ_ASSERT(sweep.script()->types() == this);
+    return typeArrayDontCheckGeneration();
   }
 
   uint32_t* bytecodeTypeMap() {
     MOZ_ASSERT(numTypeSets_ > 0);
     return reinterpret_cast<uint32_t*>(typeArray_ + numTypeSets_);
   }
 
   static inline StackTypeSet* ThisTypes(JSScript* script);
@@ -327,17 +339,17 @@ class TypeScript {
     // Note: icScript_ is a UniquePtr that stores the raw pointer. If that ever
     // changes and this assertion fails, we should stop using UniquePtr.
     static_assert(sizeof(icScript_) == sizeof(uintptr_t),
                   "JIT code assumes icScript_ is pointer-sized");
     return offsetof(TypeScript, icScript_);
   }
 
 #ifdef DEBUG
-  void printTypes(JSContext* cx, HandleScript script) const;
+  void printTypes(JSContext* cx, HandleScript script);
 #endif
 };
 
 // Ensures no TypeScripts are purged in the current zone.
 class MOZ_RAII AutoKeepTypeScripts {
   TypeZone& zone_;
   bool prev_;