Bug 1491736 - Split out type-set classes and related data types from vm/TypeInference.h into vm/TypeSet.h, and move TypeNewScript from vm/TypeInference.h to vm/TypeInference-inl.h, so code can use TypeSet types without needing JSFunction, Shape, and other super-complex types as well (via HeapPtr<T*> fields in TypeNewScript). r=jandem
authorJeff Walden <jwalden@mit.edu>
Sat, 15 Sep 2018 20:24:30 -0700
changeset 492475 60df00079cd46d23309f0637633f62908ba17d45
parent 492474 efcfd2f95057ea622a735a015a9cd3f547281fc1
child 492476 740b790557b9b70298dee6093753c4d2552001cc
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1491736
milestone64.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 1491736 - Split out type-set classes and related data types from vm/TypeInference.h into vm/TypeSet.h, and move TypeNewScript from vm/TypeInference.h to vm/TypeInference-inl.h, so code can use TypeSet types without needing JSFunction, Shape, and other super-complex types as well (via HeapPtr<T*> fields in TypeNewScript). r=jandem
js/src/builtin/AtomicsObject.h
js/src/gc/Zone.h
js/src/jit/CacheIR.cpp
js/src/jit/IonAnalysis.cpp
js/src/jit/IonAnalysis.h
js/src/vm/ArrayObject-inl.h
js/src/vm/JSObject.cpp
js/src/vm/JSScript.h
js/src/vm/NativeObject.cpp
js/src/vm/ObjectGroup.cpp
js/src/vm/ObjectGroup.h
js/src/vm/TypeInference-inl.h
js/src/vm/TypeInference.cpp
js/src/vm/TypeInference.h
js/src/vm/TypeSet.h
js/src/vm/UnboxedObject-inl.h
js/src/vm/UnboxedObject.cpp
js/src/vm/UnboxedObject.h
--- a/js/src/builtin/AtomicsObject.h
+++ b/js/src/builtin/AtomicsObject.h
@@ -6,16 +6,17 @@
 
 #ifndef builtin_AtomicsObject_h
 #define builtin_AtomicsObject_h
 
 #include "mozilla/Maybe.h"
 #include "mozilla/TimeStamp.h"
 
 #include "threading/ConditionVariable.h"
+#include "threading/ProtectedData.h" // js::ThreadData
 #include "vm/JSObject.h"
 #include "vm/MutexIDs.h"
 #include "vm/NativeObject.h"
 
 namespace js {
 
 class GlobalObject;
 class SharedArrayRawBuffer;
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -9,16 +9,17 @@
 
 #include "mozilla/Atomics.h"
 #include "mozilla/HashFunctions.h"
 
 #include "gc/FindSCCs.h"
 #include "js/GCHashTable.h"
 #include "vm/MallocProvider.h"
 #include "vm/Runtime.h"
+#include "vm/TypeInference.h"
 
 namespace js {
 
 class Debugger;
 class RegExpZone;
 
 namespace jit {
 class JitZone;
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -13,16 +13,17 @@
 #include "jit/BaselineIC.h"
 #include "jit/CacheIRSpewer.h"
 #include "vm/SelfHosting.h"
 
 #include "jit/MacroAssembler-inl.h"
 #include "vm/EnvironmentObject-inl.h"
 #include "vm/JSContext-inl.h"
 #include "vm/JSObject-inl.h"
+#include "vm/TypeInference-inl.h"
 #include "vm/UnboxedObject-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::DebugOnly;
 using mozilla::Maybe;
 
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -17,16 +17,17 @@
 #include "jit/MIRGraph.h"
 #include "vm/RegExpObject.h"
 #include "vm/SelfHosting.h"
 
 #include "jit/shared/Lowering-shared-inl.h"
 #include "vm/BytecodeUtil-inl.h"
 #include "vm/JSObject-inl.h"
 #include "vm/JSScript-inl.h"
+#include "vm/TypeInference-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::DebugOnly;
 
 typedef Vector<MPhi*, 16, SystemAllocPolicy> MPhiVector;
 
@@ -4362,17 +4363,17 @@ jit::ConvertLinearInequality(TempAllocat
 
     return compare;
 }
 
 static bool
 AnalyzePoppedThis(JSContext* cx, ObjectGroup* group,
                   MDefinition* thisValue, MInstruction* ins, bool definitelyExecuted,
                   HandlePlainObject baseobj,
-                  Vector<TypeNewScript::Initializer>* initializerList,
+                  Vector<TypeNewScriptInitializer>* initializerList,
                   Vector<PropertyName*>* accessedProperties,
                   bool* phandled)
 {
     // Determine the effect that a use of the |this| value when calling |new|
     // on a script has on the properties definitely held by the new object.
 
     if (ins->isCallSetProperty()) {
         MCallSetProperty* setprop = ins->toCallSetProperty();
@@ -4431,26 +4432,26 @@ AnalyzePoppedThis(JSContext* cx, ObjectG
             if (!callerResumePoints.append(rp)) {
                 return false;
             }
         }
 
         for (int i = callerResumePoints.length() - 1; i >= 0; i--) {
             MResumePoint* rp = callerResumePoints[i];
             JSScript* script = rp->block()->info().script();
-            TypeNewScript::Initializer entry(TypeNewScript::Initializer::SETPROP_FRAME,
-                                             script->pcToOffset(rp->pc()));
+            TypeNewScriptInitializer entry(TypeNewScriptInitializer::SETPROP_FRAME,
+                                           script->pcToOffset(rp->pc()));
             if (!initializerList->append(entry)) {
                 return false;
             }
         }
 
         JSScript* script = ins->block()->info().script();
-        TypeNewScript::Initializer entry(TypeNewScript::Initializer::SETPROP,
-                                         script->pcToOffset(setprop->resumePoint()->pc()));
+        TypeNewScriptInitializer entry(TypeNewScriptInitializer::SETPROP,
+                                       script->pcToOffset(setprop->resumePoint()->pc()));
         if (!initializerList->append(entry)) {
             return false;
         }
 
         *phandled = true;
         return true;
     }
 
@@ -4496,17 +4497,17 @@ CmpInstructions(const void* a, const voi
 {
     return (*static_cast<MInstruction * const*>(a))->id() -
            (*static_cast<MInstruction * const*>(b))->id();
 }
 
 bool
 jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun,
                                         ObjectGroup* group, HandlePlainObject baseobj,
-                                        Vector<TypeNewScript::Initializer>* initializerList)
+                                        Vector<TypeNewScriptInitializer>* initializerList)
 {
     MOZ_ASSERT(cx->zone()->types.activeAnalysis);
 
     // When invoking 'new' on the specified script, try to find some properties
     // which will definitely be added to the created object before it has a
     // chance to escape and be accessed elsewhere.
 
     RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun));
--- a/js/src/jit/IonAnalysis.h
+++ b/js/src/jit/IonAnalysis.h
@@ -198,17 +198,17 @@ ConvertLinearSum(TempAllocator& alloc, M
 // Convert the test 'sum >= 0' to a comparison, adding any necessary
 // instructions to the end of block.
 MCompare*
 ConvertLinearInequality(TempAllocator& alloc, MBasicBlock* block, const LinearSum& sum);
 
 MOZ_MUST_USE bool
 AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun,
                                    ObjectGroup* group, HandlePlainObject baseobj,
-                                   Vector<TypeNewScript::Initializer>* initializerList);
+                                   Vector<TypeNewScriptInitializer>* initializerList);
 
 MOZ_MUST_USE bool
 AnalyzeArgumentsUsage(JSContext* cx, JSScript* script);
 
 bool
 DeadIfUnused(const MDefinition* def);
 
 bool
--- a/js/src/vm/ArrayObject-inl.h
+++ b/js/src/vm/ArrayObject-inl.h
@@ -8,16 +8,17 @@
 #define vm_ArrayObject_inl_h
 
 #include "vm/ArrayObject.h"
 
 #include "gc/GCTrace.h"
 #include "vm/StringType.h"
 
 #include "vm/JSObject-inl.h"
+#include "vm/ObjectGroup-inl.h"
 #include "vm/TypeInference-inl.h"
 
 namespace js {
 
 inline void
 ArrayObject::setLength(JSContext* cx, uint32_t length)
 {
     MOZ_ASSERT(lengthIsWritable());
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -64,20 +64,22 @@
 #include "vm/Caches-inl.h"
 #include "vm/Compartment-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/JSAtom-inl.h"
 #include "vm/JSContext-inl.h"
 #include "vm/JSFunction-inl.h"
 #include "vm/NativeObject-inl.h"
 #include "vm/NumberObject-inl.h"
+#include "vm/ObjectGroup-inl.h"
 #include "vm/Realm-inl.h"
 #include "vm/Shape-inl.h"
 #include "vm/StringObject-inl.h"
 #include "vm/TypedArrayObject-inl.h"
+#include "vm/TypeInference-inl.h"
 #include "vm/UnboxedObject-inl.h"
 
 using namespace js;
 
 void
 js::ReportNotObject(JSContext* cx, HandleValue v)
 {
     MOZ_ASSERT(!v.isObject());
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -44,23 +44,26 @@ namespace jit {
 } // namespace jit
 
 # define ION_DISABLED_SCRIPT ((js::jit::IonScript*)0x1)
 # define ION_COMPILING_SCRIPT ((js::jit::IonScript*)0x2)
 # define ION_PENDING_SCRIPT ((js::jit::IonScript*)0x3)
 
 # define BASELINE_DISABLED_SCRIPT ((js::jit::BaselineScript*)0x1)
 
+class AutoKeepTypeScripts;
+class AutoSweepTypeScript;
 class BreakpointSite;
 class Debugger;
 class LazyScript;
 class ModuleObject;
 class RegExpObject;
 class SourceCompressionTask;
 class Shape;
+class TypeScript;
 
 namespace frontend {
     struct BytecodeEmitter;
     class FunctionBox;
     class ModuleSharedContext;
 } // namespace frontend
 
 namespace detail {
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -18,16 +18,17 @@
 #include "vm/TypedArrayObject.h"
 #include "vm/UnboxedObject.h"
 
 #include "gc/Nursery-inl.h"
 #include "vm/ArrayObject-inl.h"
 #include "vm/EnvironmentObject-inl.h"
 #include "vm/JSObject-inl.h"
 #include "vm/Shape-inl.h"
+#include "vm/TypeInference-inl.h"
 #include "vm/UnboxedObject-inl.h"
 
 using namespace js;
 
 using JS::AutoCheckCannotGC;
 using mozilla::ArrayLength;
 using mozilla::CheckedInt;
 using mozilla::DebugOnly;
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -20,16 +20,17 @@
 #include "js/UniquePtr.h"
 #include "vm/ArrayObject.h"
 #include "vm/JSObject.h"
 #include "vm/RegExpObject.h"
 #include "vm/Shape.h"
 #include "vm/TaggedProto.h"
 
 #include "gc/Marking-inl.h"
+#include "vm/TypeInference-inl.h"
 #include "vm/UnboxedObject-inl.h"
 
 using namespace js;
 
 /////////////////////////////////////////////////////////////////////
 // ObjectGroup
 /////////////////////////////////////////////////////////////////////
 
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -11,26 +11,25 @@
 
 #include "ds/IdValuePair.h"
 #include "gc/Barrier.h"
 #include "gc/GCTrace.h"
 #include "js/CharacterEncoding.h"
 #include "js/GCHashTable.h"
 #include "js/TypeDecls.h"
 #include "vm/TaggedProto.h"
-#include "vm/TypeInference.h"
+#include "vm/TypeSet.h"
 
 namespace js {
 
 class TypeDescr;
 class UnboxedLayout;
 
 class PreliminaryObjectArrayWithTemplate;
 class TypeNewScript;
-class HeapTypeSet;
 class AutoClearTypeInferenceStateOnOOM;
 class AutoSweepObjectGroup;
 class CompilerConstraintList;
 class ObjectGroupRealm;
 
 namespace gc {
 void MergeRealms(JS::Realm* source, JS::Realm* target);
 } // namespace gc
@@ -321,20 +320,17 @@ class ObjectGroup : public gc::TenuredCe
         setAddendum(Addendum_PreliminaryObjects, preliminaryObjects);
     }
 
     void detachPreliminaryObjects() {
         MOZ_ASSERT(maybePreliminaryObjectsDontCheckGeneration());
         setAddendum(Addendum_None, nullptr);
     }
 
-    bool hasUnanalyzedPreliminaryObjects() {
-        return (newScriptDontCheckGeneration() && !newScriptDontCheckGeneration()->analyzed()) ||
-               maybePreliminaryObjectsDontCheckGeneration();
-    }
+    inline bool hasUnanalyzedPreliminaryObjects();
 
     inline UnboxedLayout* maybeUnboxedLayout(const AutoSweepObjectGroup& sweep);
     inline UnboxedLayout& unboxedLayout(const AutoSweepObjectGroup& sweep);
 
     UnboxedLayout* maybeUnboxedLayoutDontCheckGeneration() const {
         if (addendumKind() == Addendum_UnboxedLayout) {
             return &unboxedLayoutDontCheckGeneration();
         }
--- a/js/src/vm/TypeInference-inl.h
+++ b/js/src/vm/TypeInference-inl.h
@@ -13,19 +13,24 @@
 
 #include "mozilla/BinarySearch.h"
 #include "mozilla/Casting.h"
 #include "mozilla/PodOperations.h"
 
 #include "builtin/Symbol.h"
 #include "gc/GC.h"
 #include "jit/BaselineJIT.h"
+#include "js/HeapAPI.h"
 #include "vm/ArrayObject.h"
 #include "vm/BooleanObject.h"
+#include "vm/JSFunction.h"
+#include "vm/NativeObject.h"
 #include "vm/NumberObject.h"
+#include "vm/ObjectGroup.h"
+#include "vm/Shape.h"
 #include "vm/SharedArrayObject.h"
 #include "vm/StringObject.h"
 #include "vm/TypedArrayObject.h"
 #include "vm/UnboxedObject.h"
 
 #include "vm/JSContext-inl.h"
 #include "vm/ObjectGroup-inl.h"
 
@@ -263,16 +268,171 @@ TypeIdString(jsid id)
 {
 #ifdef DEBUG
     return TypeIdStringImpl(id);
 #else
     return "(missing)";
 #endif
 }
 
+// New script properties analyses overview.
+//
+// When constructing objects using 'new' on a script, we attempt to determine
+// the properties which that object will eventually have. This is done via two
+// analyses. One of these, the definite properties analysis, is static, and the
+// other, the acquired properties analysis, is dynamic. As objects are
+// constructed using 'new' on some script to create objects of group G, our
+// analysis strategy is as follows:
+//
+// - When the first objects are created, no analysis is immediately performed.
+//   Instead, all objects of group G are accumulated in an array.
+//
+// - After a certain number of such objects have been created, the definite
+//   properties analysis is performed. This analyzes the body of the
+//   constructor script and any other functions it calls to look for properties
+//   which will definitely be added by the constructor in a particular order,
+//   creating an object with shape S.
+//
+// - The properties in S are compared with the greatest common prefix P of the
+//   shapes of the objects that have been created. If P has more properties
+//   than S, the acquired properties analysis is performed.
+//
+// - The acquired properties analysis marks all properties in P as definite
+//   in G, and creates a new group IG for objects which are partially
+//   initialized. Objects of group IG are initially created with shape S, and if
+//   they are later given shape P, their group can be changed to G.
+//
+// For objects which are rarely created, the definite properties analysis can
+// be triggered after only one or a few objects have been allocated, when code
+// being Ion compiled might access them. In this case type information in the
+// constructor might not be good enough for the definite properties analysis to
+// compute useful information, but the acquired properties analysis will still
+// be able to identify definite properties in this case.
+//
+// This layered approach is designed to maximize performance on easily
+// analyzable code, while still allowing us to determine definite properties
+// robustly when code consistently adds the same properties to objects, but in
+// complex ways which can't be understood statically.
+class TypeNewScript
+{
+  private:
+    // Scripted function which this information was computed for.
+    HeapPtr<JSFunction*> function_ = {};
+
+    // Any preliminary objects with the type. The analyses are not performed
+    // until this array is cleared.
+    PreliminaryObjectArray* preliminaryObjects = nullptr;
+
+    // After the new script properties analyses have been performed, a template
+    // object to use for newly constructed objects. The shape of this object
+    // reflects all definite properties the object will have, and the
+    // allocation kind to use. This is null if the new objects have an unboxed
+    // layout, in which case the UnboxedLayout provides the initial structure
+    // of the object.
+    HeapPtr<PlainObject*> templateObject_ = {};
+
+    // Order in which definite properties become initialized. We need this in
+    // case the definite properties are invalidated (such as by adding a setter
+    // to an object on the prototype chain) while an object is in the middle of
+    // being initialized, so we can walk the stack and fixup any objects which
+    // look for in-progress objects which were prematurely set with an incorrect
+    // shape. Property assignments in inner frames are preceded by a series of
+    // SETPROP_FRAME entries specifying the stack down to the frame containing
+    // the write.
+    TypeNewScriptInitializer* initializerList = nullptr;
+
+    // If there are additional properties found by the acquired properties
+    // analysis which were not found by the definite properties analysis, this
+    // shape contains all such additional properties (plus the definite
+    // properties). When an object of this group acquires this shape, it is
+    // fully initialized and its group can be changed to initializedGroup.
+    HeapPtr<Shape*> initializedShape_ = {};
+
+    // Group with definite properties set for all properties found by
+    // both the definite and acquired properties analyses.
+    HeapPtr<ObjectGroup*> initializedGroup_ = {};
+
+  public:
+    TypeNewScript() = default;
+
+    ~TypeNewScript() {
+        js_delete(preliminaryObjects);
+        js_free(initializerList);
+    }
+
+    void clear() {
+        function_ = nullptr;
+        templateObject_ = nullptr;
+        initializedShape_ = nullptr;
+        initializedGroup_ = nullptr;
+    }
+
+    static void writeBarrierPre(TypeNewScript* newScript);
+
+    bool analyzed() const {
+        return preliminaryObjects == nullptr;
+    }
+
+    PlainObject* templateObject() const {
+        return templateObject_;
+    }
+
+    Shape* initializedShape() const {
+        return initializedShape_;
+    }
+
+    ObjectGroup* initializedGroup() const {
+        return initializedGroup_;
+    }
+
+    JSFunction* function() const {
+        return function_;
+    }
+
+    void trace(JSTracer* trc);
+    void sweep();
+
+    void registerNewObject(PlainObject* res);
+    bool maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, bool force = false);
+
+    bool rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* group);
+
+    static bool make(JSContext* cx, ObjectGroup* group, JSFunction* fun);
+    static TypeNewScript* makeNativeVersion(JSContext* cx, TypeNewScript* newScript,
+                                            PlainObject* templateObject);
+
+    size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
+
+    static size_t offsetOfPreliminaryObjects() {
+        return offsetof(TypeNewScript, preliminaryObjects);
+    }
+};
+
+inline
+UnboxedLayout::~UnboxedLayout()
+{
+    if (newScript_) {
+        newScript_->clear();
+    }
+    js_delete(newScript_);
+    js_free(traceList_);
+
+    nativeGroup_.init(nullptr);
+    nativeShape_.init(nullptr);
+    replacementGroup_.init(nullptr);
+    constructorCode_.init(nullptr);
+}
+
+inline bool
+ObjectGroup::hasUnanalyzedPreliminaryObjects()
+{
+    return (newScriptDontCheckGeneration() && !newScriptDontCheckGeneration()->analyzed()) ||
+           maybePreliminaryObjectsDontCheckGeneration();
+}
+
 /*
  * Structure for type inference entry point functions. All functions which can
  * change type information must use this, and functions which depend on
  * intermediate types (i.e. JITs) can use this to ensure that intermediate
  * information is not collected and does not change.
  *
  * Ensures that GC cannot occur. Does additional sanity checking that inference
  * is not reentrant and that recompilations occur properly.
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -4060,21 +4060,24 @@ TypeNewScript::makeNativeVersion(JSConte
     auto nativeNewScript = cx->make_unique<TypeNewScript>();
     if (!nativeNewScript) {
         return nullptr;
     }
 
     nativeNewScript->function_ = newScript->function();
     nativeNewScript->templateObject_ = templateObject;
 
-    Initializer* cursor = newScript->initializerList;
-    while (cursor->kind != Initializer::DONE) { cursor++; }
+    TypeNewScriptInitializer* cursor = newScript->initializerList;
+    while (cursor->kind != TypeNewScriptInitializer::DONE) {
+        cursor++;
+    }
+
     size_t initializerLength = cursor - newScript->initializerList + 1;
 
-    nativeNewScript->initializerList = cx->pod_calloc<Initializer>(initializerLength);
+    nativeNewScript->initializerList = cx->pod_calloc<TypeNewScriptInitializer>(initializerLength);
     if (!nativeNewScript->initializerList) {
         return nullptr;
     }
 
     PodCopy(nativeNewScript->initializerList, newScript->initializerList, initializerLength);
 
     return nativeNewScript.release();
 }
@@ -4227,17 +4230,17 @@ TypeNewScript::maybeAnalyze(JSContext* c
     }
 
     RootedObjectGroup groupRoot(cx, group);
     templateObject_ = NewObjectWithGroup<PlainObject>(cx, groupRoot, kind, TenuredObject);
     if (!templateObject_) {
         return false;
     }
 
-    Vector<Initializer> initializerVector(cx);
+    Vector<TypeNewScriptInitializer> initializerVector(cx);
 
     RootedPlainObject templateRoot(cx, templateObject());
     RootedFunction fun(cx, function());
     if (!jit::AnalyzeNewScriptDefiniteProperties(cx, fun, group, templateRoot, &initializerVector)) {
         return false;
     }
 
     if (!group->newScript(sweep)) {
@@ -4272,23 +4275,24 @@ TypeNewScript::maybeAnalyze(JSContext* c
                 shape = shape->previous();
                 templateShape = templateShape->previous();
             }
             if (!templateShape->isEmptyShape()) {
                 return true;
             }
         }
 
-        Initializer done(Initializer::DONE, 0);
+        TypeNewScriptInitializer done(TypeNewScriptInitializer::DONE, 0);
 
         if (!initializerVector.append(done)) {
             return false;
         }
 
-        initializerList = group->zone()->pod_calloc<Initializer>(initializerVector.length());
+        initializerList =
+            group->zone()->pod_calloc<TypeNewScriptInitializer>(initializerVector.length());
         if (!initializerList) {
             ReportOutOfMemory(cx);
             return false;
         }
         PodCopy(initializerList, initializerVector.begin(), initializerVector.length());
     }
 
     // Try to use an unboxed representation for the group.
@@ -4439,44 +4443,44 @@ TypeNewScript::rollbackPartiallyInitiali
         bool pastProperty = false;
 
         // Index in pcOffsets of the outermost frame.
         int callDepth = pcOffsets.length() - 1;
 
         // Index in pcOffsets of the frame currently being checked for a SETPROP.
         int setpropDepth = callDepth;
 
-        for (Initializer* init = initializerList;; init++) {
-            if (init->kind == Initializer::SETPROP) {
+        for (TypeNewScriptInitializer* init = initializerList; ; init++) {
+            if (init->kind == TypeNewScriptInitializer::SETPROP) {
                 if (!pastProperty && pcOffsets[setpropDepth] < init->offset) {
                     // Have not yet reached this setprop.
                     break;
                 }
                 // This setprop has executed, reset state for the next one.
                 numProperties++;
                 pastProperty = false;
                 setpropDepth = callDepth;
-            } else if (init->kind == Initializer::SETPROP_FRAME) {
+            } else if (init->kind == TypeNewScriptInitializer::SETPROP_FRAME) {
                 if (!pastProperty) {
                     if (pcOffsets[setpropDepth] < init->offset) {
                         // Have not yet reached this inner call.
                         break;
                     } else if (pcOffsets[setpropDepth] > init->offset) {
                         // Have advanced past this inner call.
                         pastProperty = true;
                     } else if (setpropDepth == 0) {
                         // Have reached this call but not yet in it.
                         break;
                     } else {
                         // Somewhere inside this inner call.
                         setpropDepth--;
                     }
                 }
             } else {
-                MOZ_ASSERT(init->kind == Initializer::DONE);
+                MOZ_ASSERT(init->kind == TypeNewScriptInitializer::DONE);
                 finished = true;
                 break;
             }
         }
 
         if (!finished) {
             (void) NativeObject::rollbackProperties(cx, obj, numProperties);
             found = true;
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -4,663 +4,47 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* Definitions related to javascript type inference. */
 
 #ifndef vm_TypeInference_h
 #define vm_TypeInference_h
 
+#include "mozilla/Attributes.h"
+#include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
 
 #include "jsfriendapi.h"
 #include "jstypes.h"
 
-#include "ds/IdValuePair.h"
 #include "ds/LifoAlloc.h"
 #include "gc/Barrier.h"
 #include "jit/IonTypes.h"
 #include "js/AllocPolicy.h"
+#include "js/HeapAPI.h" // js::CurrentThreadCanAccessZone
 #include "js/UbiNode.h"
 #include "js/Utility.h"
 #include "js/Vector.h"
-#include "threading/ProtectedData.h"
-#include "vm/TaggedProto.h"
+#include "threading/ProtectedData.h" // js::ZoneData
+#include "vm/TypeSet.h"
 
 namespace js {
 
-namespace jit {
-    struct IonScript;
-    class JitAllocPolicy;
-    class TempAllocator;
-} // namespace jit
-
 class TypeConstraint;
-class TypeNewScript;
 class TypeZone;
 class CompilerConstraintList;
 class HeapTypeSetKey;
 
-/*
- * Type inference memory management overview.
- *
- * Type information about the values observed within scripts and about the
- * contents of the heap is accumulated as the program executes. Compilation
- * accumulates constraints relating type information on the heap with the
- * compilations that should be invalidated when those types change. Type
- * information and constraints are allocated in the zone's typeLifoAlloc,
- * and on GC all data referring to live things is copied into a new allocator.
- * Thus, type set and constraints only hold weak references.
- */
-
-/* Flags and other state stored in TypeSet::flags */
-enum : uint32_t {
-    TYPE_FLAG_UNDEFINED =   0x1,
-    TYPE_FLAG_NULL      =   0x2,
-    TYPE_FLAG_BOOLEAN   =   0x4,
-    TYPE_FLAG_INT32     =   0x8,
-    TYPE_FLAG_DOUBLE    =  0x10,
-    TYPE_FLAG_STRING    =  0x20,
-    TYPE_FLAG_SYMBOL    =  0x40,
-#ifdef ENABLE_BIGINT
-    TYPE_FLAG_BIGINT    =  0x80,
-    TYPE_FLAG_LAZYARGS  = 0x100,
-    TYPE_FLAG_ANYOBJECT = 0x200,
-#else
-    TYPE_FLAG_LAZYARGS  = 0x80,
-    TYPE_FLAG_ANYOBJECT = 0x100,
-#endif
-
-    /* Mask containing all primitives */
-    TYPE_FLAG_PRIMITIVE = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_BOOLEAN |
-                          TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE | TYPE_FLAG_STRING |
-                          TYPE_FLAG_SYMBOL |
-                          IF_BIGINT(TYPE_FLAG_BIGINT, 0),
-
-    /* Mask/shift for the number of objects in objectSet */
-#ifdef ENABLE_BIGINT
-    TYPE_FLAG_OBJECT_COUNT_MASK     = 0x3c00,
-    TYPE_FLAG_OBJECT_COUNT_SHIFT    = 10,
-#else
-    TYPE_FLAG_OBJECT_COUNT_MASK     = 0x3e00,
-    TYPE_FLAG_OBJECT_COUNT_SHIFT    = 9,
-#endif
-    TYPE_FLAG_OBJECT_COUNT_LIMIT    = 7,
-    TYPE_FLAG_DOMOBJECT_COUNT_LIMIT =
-        TYPE_FLAG_OBJECT_COUNT_MASK >> TYPE_FLAG_OBJECT_COUNT_SHIFT,
-
-    /* Whether the contents of this type set are totally unknown. */
-    TYPE_FLAG_UNKNOWN             = 0x00004000,
-
-    /* Mask of normal type flags on a type set. */
-    TYPE_FLAG_BASE_MASK           = TYPE_FLAG_PRIMITIVE | TYPE_FLAG_LAZYARGS | TYPE_FLAG_ANYOBJECT | TYPE_FLAG_UNKNOWN,
-
-    /* Additional flags for HeapTypeSet sets. */
-
-    /*
-     * Whether the property has ever been deleted or reconfigured to behave
-     * differently from a plain data property, other than making the property
-     * non-writable.
-     */
-    TYPE_FLAG_NON_DATA_PROPERTY = 0x00008000,
-
-    /* Whether the property has ever been made non-writable. */
-    TYPE_FLAG_NON_WRITABLE_PROPERTY = 0x00010000,
-
-    /* Whether the property might not be constant. */
-    TYPE_FLAG_NON_CONSTANT_PROPERTY = 0x00020000,
-
-    /*
-     * Whether the property is definitely in a particular slot on all objects
-     * from which it has not been deleted or reconfigured. For singletons
-     * this may be a fixed or dynamic slot, and for other objects this will be
-     * a fixed slot.
-     *
-     * If the property is definite, mask and shift storing the slot + 1.
-     * Otherwise these bits are clear.
-     */
-    TYPE_FLAG_DEFINITE_MASK       = 0xfffc0000,
-    TYPE_FLAG_DEFINITE_SHIFT      = 18
-};
-typedef uint32_t TypeFlags;
-
-static_assert(TYPE_FLAG_PRIMITIVE < TYPE_FLAG_ANYOBJECT &&
-              TYPE_FLAG_LAZYARGS < TYPE_FLAG_ANYOBJECT,
-              "TYPE_FLAG_ANYOBJECT should be greater than primitive type flags");
-
-/* Flags and other state stored in ObjectGroup::Flags */
-enum : uint32_t {
-    /* Whether this group is associated with some allocation site. */
-    OBJECT_FLAG_FROM_ALLOCATION_SITE  = 0x1,
-
-    /* Whether this group is associated with a single object. */
-    OBJECT_FLAG_SINGLETON             = 0x2,
-
-    /*
-     * Whether this group is used by objects whose singleton groups have not
-     * been created yet.
-     */
-    OBJECT_FLAG_LAZY_SINGLETON        = 0x4,
-
-    /* Mask/shift for the number of properties in propertySet */
-    OBJECT_FLAG_PROPERTY_COUNT_MASK   = 0xfff8,
-    OBJECT_FLAG_PROPERTY_COUNT_SHIFT  = 3,
-    OBJECT_FLAG_PROPERTY_COUNT_LIMIT  =
-        OBJECT_FLAG_PROPERTY_COUNT_MASK >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT,
-
-    /* Whether any objects this represents may have sparse indexes. */
-    OBJECT_FLAG_SPARSE_INDEXES        = 0x00010000,
-
-    /* Whether any objects this represents may not have packed dense elements. */
-    OBJECT_FLAG_NON_PACKED            = 0x00020000,
-
-    /*
-     * Whether any objects this represents may be arrays whose length does not
-     * fit in an int32.
-     */
-    OBJECT_FLAG_LENGTH_OVERFLOW       = 0x00040000,
-
-    /* Whether any objects have been iterated over. */
-    OBJECT_FLAG_ITERATED              = 0x00080000,
-
-    /* Whether any object this represents may have non-extensible elements. */
-    OBJECT_FLAG_NON_EXTENSIBLE_ELEMENTS = 0x00100000,
-
-    /*
-     * For the function on a run-once script, whether the function has actually
-     * run multiple times.
-     */
-    OBJECT_FLAG_RUNONCE_INVALIDATED   = 0x00200000,
-
-    /*
-     * For a global object, whether any array buffers in this compartment with
-     * typed object views have ever been detached.
-     */
-    OBJECT_FLAG_TYPED_OBJECT_HAS_DETACHED_BUFFER = 0x00400000,
-
-    /*
-     * Whether objects with this type should be allocated directly in the
-     * tenured heap.
-     */
-    OBJECT_FLAG_PRE_TENURE            = 0x00800000,
-
-    /* Whether objects with this type might have copy on write elements. */
-    OBJECT_FLAG_COPY_ON_WRITE         = 0x01000000,
-
-    /* Whether this type has had its 'new' script cleared in the past. */
-    OBJECT_FLAG_NEW_SCRIPT_CLEARED    = 0x02000000,
-
-    /*
-     * Whether all properties of this object are considered unknown.
-     * If set, all other flags in DYNAMIC_MASK will also be set.
-     */
-    OBJECT_FLAG_UNKNOWN_PROPERTIES    = 0x04000000,
-
-    /* Flags which indicate dynamic properties of represented objects. */
-    OBJECT_FLAG_DYNAMIC_MASK          = 0x07ff0000,
-
-    // Mask/shift for the kind of addendum attached to this group.
-    OBJECT_FLAG_ADDENDUM_MASK         = 0x38000000,
-    OBJECT_FLAG_ADDENDUM_SHIFT        = 27,
-
-    // Mask/shift for this group's generation. If out of sync with the
-    // TypeZone's generation, this group hasn't been swept yet.
-    OBJECT_FLAG_GENERATION_MASK       = 0x40000000,
-    OBJECT_FLAG_GENERATION_SHIFT      = 30,
-};
-typedef uint32_t ObjectGroupFlags;
-
-class StackTypeSet;
-class HeapTypeSet;
-class TemporaryTypeSet;
-
-/*
- * [SMDOC] Type-Inference TypeSet
- *
- * Information about the set of types associated with an lvalue. There are
- * three kinds of type sets:
- *
- * - StackTypeSet are associated with TypeScripts, for arguments and values
- *   observed at property reads. These are implicitly frozen on compilation
- *   and only have constraints added to them which can trigger invalidation of
- *   TypeNewScript information.
- *
- * - HeapTypeSet are associated with the properties of ObjectGroups. These
- *   may have constraints added to them to trigger invalidation of either
- *   compiled code or TypeNewScript information.
- *
- * - TemporaryTypeSet are created during compilation and do not outlive
- *   that compilation.
- *
- * The contents of a type set completely describe the values that a particular
- * lvalue might have, except for the following cases:
- *
- * - If an object's prototype or class is dynamically mutated, its group will
- *   change. Type sets containing the old group will not necessarily contain
- *   the new group. When this occurs, the properties of the old and new group
- *   will both be marked as unknown, which will prevent Ion from optimizing
- *   based on the object's type information.
- *
- * - If an unboxed object is converted to a native object, its group will also
- *   change and type sets containing the old group will not necessarily contain
- *   the new group. Unlike the above case, this will not degrade property type
- *   information, but Ion will no longer optimize unboxed objects with the old
- *   group.
- */
-class TypeSet
-{
-  public:
-    // Type set entry for either a JSObject with singleton type or a
-    // non-singleton ObjectGroup.
-    class ObjectKey {
-      public:
-        static intptr_t keyBits(ObjectKey* obj) { return (intptr_t) obj; }
-        static ObjectKey* getKey(ObjectKey* obj) { return obj; }
-
-        static inline ObjectKey* get(JSObject* obj);
-        static inline ObjectKey* get(ObjectGroup* group);
-
-        bool isGroup() {
-            return (uintptr_t(this) & 1) == 0;
-        }
-        bool isSingleton() {
-            return (uintptr_t(this) & 1) != 0;
-        }
-
-        inline ObjectGroup* group();
-        inline JSObject* singleton();
-
-        inline ObjectGroup* groupNoBarrier();
-        inline JSObject* singletonNoBarrier();
-
-        const Class* clasp();
-        TaggedProto proto();
-        TypeNewScript* newScript();
-
-        bool unknownProperties();
-        bool hasFlags(CompilerConstraintList* constraints, ObjectGroupFlags flags);
-        bool hasStableClassAndProto(CompilerConstraintList* constraints);
-        void watchStateChangeForTypedArrayData(CompilerConstraintList* constraints);
-        void watchStateChangeForUnboxedConvertedToNative(CompilerConstraintList* constraints);
-        HeapTypeSetKey property(jsid id);
-        void ensureTrackedProperty(JSContext* cx, jsid id);
-
-        ObjectGroup* maybeGroup();
-
-        JS::Compartment* maybeCompartment();
-    } JS_HAZ_GC_POINTER;
-
-    // Information about a single concrete type. We pack this into one word,
-    // where small values are particular primitive or other singleton types and
-    // larger values are either specific JS objects or object groups.
-    class Type
-    {
-        friend class TypeSet;
-
-        uintptr_t data;
-        explicit Type(uintptr_t data) : data(data) {}
-
-      public:
-
-        uintptr_t raw() const { return data; }
-
-        bool isPrimitive() const {
-            return data < JSVAL_TYPE_OBJECT;
-        }
-
-        bool isPrimitive(JSValueType type) const {
-            MOZ_ASSERT(type < JSVAL_TYPE_OBJECT);
-            return (uintptr_t) type == data;
-        }
-
-        JSValueType primitive() const {
-            MOZ_ASSERT(isPrimitive());
-            return (JSValueType) data;
-        }
-
-        bool isMagicArguments() const {
-            return primitive() == JSVAL_TYPE_MAGIC;
-        }
-
-        bool isSomeObject() const {
-            return data == JSVAL_TYPE_OBJECT || data > JSVAL_TYPE_UNKNOWN;
-        }
-
-        bool isAnyObject() const {
-            return data == JSVAL_TYPE_OBJECT;
-        }
-
-        bool isUnknown() const {
-            return data == JSVAL_TYPE_UNKNOWN;
-        }
-
-        /* Accessors for types that are either JSObject or ObjectGroup. */
-
-        bool isObject() const {
-            MOZ_ASSERT(!isAnyObject() && !isUnknown());
-            return data > JSVAL_TYPE_UNKNOWN;
-        }
-
-        bool isObjectUnchecked() const {
-            return data > JSVAL_TYPE_UNKNOWN;
-        }
-
-        inline ObjectKey* objectKey() const;
-
-        /* Accessors for JSObject types */
+namespace jit {
 
-        bool isSingleton() const {
-            return isObject() && !!(data & 1);
-        }
-        bool isSingletonUnchecked() const {
-            return isObjectUnchecked() && !!(data & 1);
-        }
-
-        inline JSObject* singleton() const;
-        inline JSObject* singletonNoBarrier() const;
-
-        /* Accessors for ObjectGroup types */
-
-        bool isGroup() const {
-            return isObject() && !(data & 1);
-        }
-        bool isGroupUnchecked() const {
-            return isObjectUnchecked() && !(data & 1);
-        }
-
-        inline ObjectGroup* group() const;
-        inline ObjectGroup* groupNoBarrier() const;
-
-        inline void trace(JSTracer* trc);
-
-        JS::Compartment* maybeCompartment();
-
-        bool operator == (Type o) const { return data == o.data; }
-        bool operator != (Type o) const { return data != o.data; }
-    } JS_HAZ_GC_POINTER;
-
-    static inline Type UndefinedType() { return Type(JSVAL_TYPE_UNDEFINED); }
-    static inline Type NullType()      { return Type(JSVAL_TYPE_NULL); }
-    static inline Type BooleanType()   { return Type(JSVAL_TYPE_BOOLEAN); }
-    static inline Type Int32Type()     { return Type(JSVAL_TYPE_INT32); }
-    static inline Type DoubleType()    { return Type(JSVAL_TYPE_DOUBLE); }
-    static inline Type StringType()    { return Type(JSVAL_TYPE_STRING); }
-    static inline Type SymbolType()    { return Type(JSVAL_TYPE_SYMBOL); }
-#ifdef ENABLE_BIGINT
-    static inline Type BigIntType()    { return Type(JSVAL_TYPE_BIGINT); }
-#endif
-    static inline Type MagicArgType()  { return Type(JSVAL_TYPE_MAGIC); }
-    static inline Type AnyObjectType() { return Type(JSVAL_TYPE_OBJECT); }
-    static inline Type UnknownType()   { return Type(JSVAL_TYPE_UNKNOWN); }
-
-    static inline Type PrimitiveType(JSValueType type) {
-        MOZ_ASSERT(type < JSVAL_TYPE_UNKNOWN);
-        return Type(type);
-    }
-
-    static inline Type ObjectType(JSObject* obj);
-    static inline Type ObjectType(ObjectGroup* group);
-    static inline Type ObjectType(ObjectKey* key);
-
-    static const char* NonObjectTypeString(Type type);
-
-    static UniqueChars TypeString(Type type);
-    static UniqueChars ObjectGroupString(ObjectGroup* group);
-
-  protected:
-    /* Flags for this type set. */
-    TypeFlags flags;
-
-    /* Possible objects this type set can represent. */
-    ObjectKey** objectSet;
-
-  public:
-
-    TypeSet()
-      : flags(0), objectSet(nullptr)
-    {}
-
-    void print(FILE* fp = stderr);
-
-    /* Whether this set contains a specific type. */
-    MOZ_ALWAYS_INLINE bool hasType(Type type) const;
-
-    TypeFlags baseFlags() const { return flags & TYPE_FLAG_BASE_MASK; }
-    bool unknown() const { return !!(flags & TYPE_FLAG_UNKNOWN); }
-    bool unknownObject() const { return !!(flags & (TYPE_FLAG_UNKNOWN | TYPE_FLAG_ANYOBJECT)); }
-    bool empty() const { return !baseFlags() && !baseObjectCount(); }
-
-    bool hasAnyFlag(TypeFlags flags) const {
-        MOZ_ASSERT((flags & TYPE_FLAG_BASE_MASK) == flags);
-        return !!(baseFlags() & flags);
-    }
-
-    bool nonDataProperty() const {
-        return flags & TYPE_FLAG_NON_DATA_PROPERTY;
-    }
-    bool nonWritableProperty() const {
-        return flags & TYPE_FLAG_NON_WRITABLE_PROPERTY;
-    }
-    bool nonConstantProperty() const {
-        return flags & TYPE_FLAG_NON_CONSTANT_PROPERTY;
-    }
-    bool definiteProperty() const { return flags & TYPE_FLAG_DEFINITE_MASK; }
-    unsigned definiteSlot() const {
-        MOZ_ASSERT(definiteProperty());
-        return (flags >> TYPE_FLAG_DEFINITE_SHIFT) - 1;
-    }
-
-    /* Join two type sets into a new set. The result should not be modified further. */
-    static TemporaryTypeSet* unionSets(TypeSet* a, TypeSet* b, LifoAlloc* alloc);
-    /* Return the intersection of the 2 TypeSets. The result should not be modified further */
-    static TemporaryTypeSet* intersectSets(TemporaryTypeSet* a, TemporaryTypeSet* b, LifoAlloc* alloc);
-    /*
-     * Returns a copy of TypeSet a excluding/removing the types in TypeSet b.
-     * TypeSet b can only contain primitives or be any object. No support for
-     * specific objects. The result should not be modified further.
-     */
-    static TemporaryTypeSet* removeSet(TemporaryTypeSet* a, TemporaryTypeSet* b, LifoAlloc* alloc);
-
-    /* Add a type to this set using the specified allocator. */
-    void addType(Type type, LifoAlloc* alloc);
-
-    /* Get a list of all types in this set. */
-    typedef Vector<Type, 1, SystemAllocPolicy> TypeList;
-    template <class TypeListT> bool enumerateTypes(TypeListT* list) const;
-
-    /*
-     * Iterate through the objects in this set. getObjectCount overapproximates
-     * in the hash case (see SET_ARRAY_SIZE in TypeInference-inl.h), and
-     * getObject may return nullptr.
-     */
-    inline unsigned getObjectCount() const;
-    inline bool hasGroup(unsigned i) const;
-    inline bool hasSingleton(unsigned i) const;
-    inline ObjectKey* getObject(unsigned i) const;
-    inline JSObject* getSingleton(unsigned i) const;
-    inline ObjectGroup* getGroup(unsigned i) const;
-
-    /*
-     * Get the objects in the set without triggering barriers. This is
-     * potentially unsafe and you should only call these methods if you know
-     * what you're doing. For JIT compilation, use the following methods
-     * instead:
-     *  - MacroAssembler::getSingletonAndDelayBarrier()
-     *  - MacroAssembler::getGroupAndDelayBarrier()
-     */
-    inline JSObject* getSingletonNoBarrier(unsigned i) const;
-    inline ObjectGroup* getGroupNoBarrier(unsigned i) const;
-
-    /* The Class of an object in this set. */
-    inline const Class* getObjectClass(unsigned i) const;
-
-    bool canSetDefinite(unsigned slot) {
-        // Note: the cast is required to work around an MSVC issue.
-        return (slot + 1) <= (unsigned(TYPE_FLAG_DEFINITE_MASK) >> TYPE_FLAG_DEFINITE_SHIFT);
-    }
-    void setDefinite(unsigned slot) {
-        MOZ_ASSERT(canSetDefinite(slot));
-        flags |= ((slot + 1) << TYPE_FLAG_DEFINITE_SHIFT);
-        MOZ_ASSERT(definiteSlot() == slot);
-    }
+struct IonScript;
+class TempAllocator;
 
-    /* Whether any values in this set might have the specified type. */
-    bool mightBeMIRType(jit::MIRType type) const;
-
-    /*
-     * Get whether this type set is known to be a subset of other.
-     * This variant doesn't freeze constraints. That variant is called knownSubset
-     */
-    bool isSubset(const TypeSet* other) const;
-
-    /*
-     * Get whether the objects in this TypeSet are a subset of the objects
-     * in other.
-     */
-    bool objectsAreSubset(TypeSet* other);
-
-    /* Whether this TypeSet contains exactly the same types as other. */
-    bool equals(const TypeSet* other) const {
-        return this->isSubset(other) && other->isSubset(this);
-    }
-
-    bool objectsIntersect(const TypeSet* other) const;
-
-    /* Forward all types in this set to the specified constraint. */
-    bool addTypesToConstraint(JSContext* cx, TypeConstraint* constraint);
-
-    // Clone a type set into an arbitrary allocator.
-    TemporaryTypeSet* clone(LifoAlloc* alloc) const;
-
-    // |*result| is not even partly initialized when this function is called:
-    // this function placement-new's its contents into existence.
-    bool cloneIntoUninitialized(LifoAlloc* alloc, TemporaryTypeSet* result) const;
-
-    // Create a new TemporaryTypeSet where undefined and/or null has been filtered out.
-    TemporaryTypeSet* filter(LifoAlloc* alloc, bool filterUndefined, bool filterNull) const;
-    // Create a new TemporaryTypeSet where the type has been set to object.
-    TemporaryTypeSet* cloneObjectsOnly(LifoAlloc* alloc);
-    TemporaryTypeSet* cloneWithoutObjects(LifoAlloc* alloc);
-
-    JS::Compartment* maybeCompartment();
-
-    // Trigger a read barrier on all the contents of a type set.
-    static void readBarrier(const TypeSet* types);
-
-  protected:
-    uint32_t baseObjectCount() const {
-        return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT;
-    }
-    inline void setBaseObjectCount(uint32_t count);
-
-    void clearObjects();
-
-  public:
-    static inline Type GetValueType(const Value& val);
-
-    static inline bool IsUntrackedValue(const Value& val);
-
-    // Get the type of a possibly optimized out or uninitialized let value.
-    // This generally only happens on unconditional type monitors on bailing
-    // out of Ion, such as for argument and local types.
-    static inline Type GetMaybeUntrackedValueType(const Value& val);
-
-    static bool IsTypeMarked(JSRuntime* rt, Type* v);
-    static bool IsTypeAboutToBeFinalized(Type* v);
-} JS_HAZ_GC_POINTER;
-
-#if JS_BITS_PER_WORD == 32
-static const uintptr_t BaseTypeInferenceMagic = 0xa1a2b3b4;
-#else
-static const uintptr_t BaseTypeInferenceMagic = 0xa1a2b3b4c5c6d7d8;
-#endif
-static const uintptr_t TypeConstraintMagic = BaseTypeInferenceMagic + 1;
-static const uintptr_t ConstraintTypeSetMagic = BaseTypeInferenceMagic + 2;
-
-#ifdef JS_CRASH_DIAGNOSTICS
-extern void
-ReportMagicWordFailure(uintptr_t actual, uintptr_t expected);
-extern void
-ReportMagicWordFailure(uintptr_t actual, uintptr_t expected, uintptr_t flags, uintptr_t objectSet);
-#endif
-
-/*
- * A constraint which listens to additions to a type set and propagates those
- * changes to other type sets.
- */
-class TypeConstraint
-{
-#ifdef JS_CRASH_DIAGNOSTICS
-    uintptr_t magic_;
-#endif
-
-    /* Next constraint listening to the same type set. */
-    TypeConstraint* next_;
-
-  public:
-    TypeConstraint()
-      : next_(nullptr)
-    {
-#ifdef JS_CRASH_DIAGNOSTICS
-        magic_ = TypeConstraintMagic;
-#endif
-    }
-
-    void checkMagic() const {
-#ifdef JS_CRASH_DIAGNOSTICS
-        if (MOZ_UNLIKELY(magic_ != TypeConstraintMagic)) {
-            ReportMagicWordFailure(magic_, TypeConstraintMagic);
-        }
-#endif
-    }
-
-    TypeConstraint* next() const {
-        checkMagic();
-        if (next_) {
-            next_->checkMagic();
-        }
-        return next_;
-    }
-    void setNext(TypeConstraint* next) {
-        MOZ_ASSERT(!next_);
-        checkMagic();
-        if (next) {
-            next->checkMagic();
-        }
-        next_ = next;
-    }
-
-    /* Debugging name for this kind of constraint. */
-    virtual const char* kind() = 0;
-
-    /* Register a new type for the set this constraint is listening to. */
-    virtual void newType(JSContext* cx, TypeSet* source, TypeSet::Type type) = 0;
-
-    /*
-     * For constraints attached to an object property's type set, mark the
-     * property as having changed somehow.
-     */
-    virtual void newPropertyState(JSContext* cx, TypeSet* source) {}
-
-    /*
-     * For constraints attached to the JSID_EMPTY type set on an object,
-     * indicate a change in one of the object's dynamic property flags or other
-     * state.
-     */
-    virtual void newObjectState(JSContext* cx, ObjectGroup* group) {}
-
-    /*
-     * If the data this constraint refers to is still live, copy it into the
-     * zone's new allocator. Type constraints only hold weak references.
-     */
-    virtual bool sweep(TypeZone& zone, TypeConstraint** res) = 0;
-
-    /* The associated compartment, if any. */
-    virtual JS::Compartment* maybeCompartment() = 0;
-};
+} // namespace jit
 
 // If there is an OOM while sweeping types, the type information is deoptimized
 // so that it stays correct (i.e. overapproximates the possible types in the
 // zone), but constraints might not have been triggered on the deoptimization
 // or even copied over completely. In this case, destroy all JIT code and new
 // script information in the zone, the only things whose correctness depends on
 // the type constraints.
 class AutoClearTypeInferenceStateOnOOM
@@ -725,261 +109,19 @@ class MOZ_RAII AutoSweepTypeScript : pub
     inline ~AutoSweepTypeScript();
 
     JSScript* script() const {
         return script_;
     }
 #endif
 };
 
-/* Superclass common to stack and heap type sets. */
-class ConstraintTypeSet : public TypeSet
-{
-#ifdef JS_CRASH_DIAGNOSTICS
-    uintptr_t magic_;
-#endif
-
-  protected:
-    /* Chain of constraints which propagate changes out from this type set. */
-    TypeConstraint* constraintList_;
-
-  public:
-    ConstraintTypeSet()
-      : constraintList_(nullptr)
-    {
-#ifdef JS_CRASH_DIAGNOSTICS
-        magic_ = ConstraintTypeSetMagic;
-#endif
-    }
-
-#ifdef JS_CRASH_DIAGNOSTICS
-    void initMagic() {
-        MOZ_ASSERT(!magic_);
-        magic_ = ConstraintTypeSetMagic;
-    }
-#endif
-
-    void checkMagic() const {
-#ifdef JS_CRASH_DIAGNOSTICS
-        if (MOZ_UNLIKELY(magic_ != ConstraintTypeSetMagic)) {
-            ReportMagicWordFailure(magic_, ConstraintTypeSetMagic, uintptr_t(flags), uintptr_t(objectSet));
-        }
-#endif
-    }
-
-    // This takes a reference to AutoSweepBase to ensure we swept the owning
-    // ObjectGroup or TypeScript.
-    TypeConstraint* constraintList(const AutoSweepBase& sweep) const {
-        checkMagic();
-        if (constraintList_) {
-            constraintList_->checkMagic();
-        }
-        return constraintList_;
-    }
-    void setConstraintList(TypeConstraint* constraint) {
-        MOZ_ASSERT(!constraintList_);
-        checkMagic();
-        if (constraint) {
-            constraint->checkMagic();
-        }
-        constraintList_ = constraint;
-    }
-
-    /*
-     * Add a type to this set, calling any constraint handlers if this is a new
-     * possible type.
-     */
-    void addType(const AutoSweepBase& sweep, JSContext* cx, Type type);
-
-    /* Generalize to any type. */
-    void makeUnknown(const AutoSweepBase& sweep, JSContext* cx) {
-        addType(sweep, cx, UnknownType());
-    }
-
-    // Trigger a post barrier when writing to this set, if necessary.
-    // addType(cx, type) takes care of this automatically.
-    void postWriteBarrier(JSContext* cx, Type type);
-
-    /* Add a new constraint to this set. */
-    bool addConstraint(JSContext* cx, TypeConstraint* constraint, bool callExisting = true);
-
-    inline void sweep(const AutoSweepBase& sweep, JS::Zone* zone,
-                      AutoClearTypeInferenceStateOnOOM& oom);
-    inline void trace(JS::Zone* zone, JSTracer* trc);
-};
-
-class StackTypeSet : public ConstraintTypeSet
-{
-  public:
-};
-
-class HeapTypeSet : public ConstraintTypeSet
-{
-    inline void newPropertyState(const AutoSweepObjectGroup& sweep, JSContext* cx);
-
-  public:
-    /* Mark this type set as representing a non-data property. */
-    inline void setNonDataProperty(const AutoSweepObjectGroup& sweep, JSContext* cx);
-
-    /* Mark this type set as representing a non-writable property. */
-    inline void setNonWritableProperty(const AutoSweepObjectGroup& sweep, JSContext* cx);
-
-    // Mark this type set as being non-constant.
-    inline void setNonConstantProperty(const AutoSweepObjectGroup& sweep, JSContext* cx);
-};
-
 CompilerConstraintList*
 NewCompilerConstraintList(jit::TempAllocator& alloc);
 
-enum class DOMObjectKind : uint8_t { Proxy, Native, Unknown };
-
-class TemporaryTypeSet : public TypeSet
-{
-  public:
-    TemporaryTypeSet() {}
-    TemporaryTypeSet(LifoAlloc* alloc, Type type);
-
-    TemporaryTypeSet(uint32_t flags, ObjectKey** objectSet) {
-        this->flags = flags;
-        this->objectSet = objectSet;
-    }
-
-    TemporaryTypeSet(LifoAlloc* alloc, jit::MIRType type)
-      : TemporaryTypeSet(alloc, PrimitiveType(ValueTypeFromMIRType(type)))
-    {
-        MOZ_ASSERT(type != jit::MIRType::Value);
-    }
-
-    /*
-     * Constraints for JIT compilation.
-     *
-     * Methods for JIT compilation. These must be used when a script is
-     * currently being compiled (see AutoEnterCompilation) and will add
-     * constraints ensuring that if the return value change in the future due
-     * to new type information, the script's jitcode will be discarded.
-     */
-
-    /* Get any type tag which all values in this set must have. */
-    jit::MIRType getKnownMIRType();
-
-    bool isMagicArguments() { return getKnownMIRType() == jit::MIRType::MagicOptimizedArguments; }
-
-    /* Whether this value may be an object. */
-    bool maybeObject() { return unknownObject() || baseObjectCount() > 0; }
-
-    /*
-     * Whether this typeset represents a potentially sentineled object value:
-     * the value may be an object or null or undefined.
-     * Returns false if the value cannot ever be an object.
-     */
-    bool objectOrSentinel() {
-        TypeFlags flags = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_ANYOBJECT;
-        if (baseFlags() & (~flags & TYPE_FLAG_BASE_MASK)) {
-            return false;
-        }
-
-        return hasAnyFlag(TYPE_FLAG_ANYOBJECT) || baseObjectCount() > 0;
-    }
-
-    /* Whether the type set contains objects with any of a set of flags. */
-    bool hasObjectFlags(CompilerConstraintList* constraints, ObjectGroupFlags flags);
-
-    /* Get the class shared by all objects in this set, or nullptr. */
-    const Class* getKnownClass(CompilerConstraintList* constraints);
-
-    /*
-     * Get the realm shared by all objects in this set, or nullptr. Returns
-     * nullptr if the set contains proxies (because cross-compartment wrappers
-     * don't have a single realm associated with them).
-     */
-    Realm* getKnownRealm(CompilerConstraintList* constraints);
-
-    /* Result returned from forAllClasses */
-    enum ForAllResult {
-        EMPTY=1,                // Set empty
-        ALL_TRUE,               // Set not empty and predicate returned true for all classes
-        ALL_FALSE,              // Set not empty and predicate returned false for all classes
-        MIXED,                  // Set not empty and predicate returned false for some classes
-                                // and true for others, or set contains an unknown or non-object
-                                // type
-    };
-
-    /* Apply func to the members of the set and return an appropriate result.
-     * The iteration may end early if the result becomes known early.
-     */
-    ForAllResult forAllClasses(CompilerConstraintList* constraints,
-                               bool (*func)(const Class* clasp));
-
-    /*
-     * Returns true if all objects in this set have the same prototype, and
-     * assigns this object to *proto. The proto can be nullptr.
-     */
-    bool getCommonPrototype(CompilerConstraintList* constraints, JSObject** proto);
-
-    /* Whether the buffer mapped by a TypedArray is shared memory or not */
-    enum TypedArraySharedness {
-        UnknownSharedness=1,    // We can't determine sharedness
-        KnownShared,            // We know for sure the buffer is shared
-        KnownUnshared           // We know for sure the buffer is unshared
-    };
-
-    /* Get the typed array type of all objects in this set, or Scalar::MaxTypedArrayViewType.
-     * If there is such a common type and sharedness is not nullptr then
-     * *sharedness is set to what we know about the sharedness of the memory.
-     */
-    Scalar::Type getTypedArrayType(CompilerConstraintList* constraints,
-                                   TypedArraySharedness* sharedness = nullptr);
-
-    /* Whether all objects have JSCLASS_IS_DOMJSCLASS set. */
-    bool isDOMClass(CompilerConstraintList* constraints, DOMObjectKind* kind);
-
-    /* Whether clasp->isCallable() is true for one or more objects in this set. */
-    bool maybeCallable(CompilerConstraintList* constraints);
-
-    /* Whether clasp->emulatesUndefined() is true for one or more objects in this set. */
-    bool maybeEmulatesUndefined(CompilerConstraintList* constraints);
-
-    /* Get the single value which can appear in this type set, otherwise nullptr. */
-    JSObject* maybeSingleton();
-    ObjectKey* maybeSingleObject();
-
-    /* Whether any objects in the type set needs a barrier on id. */
-    bool propertyNeedsBarrier(CompilerConstraintList* constraints, jsid id);
-
-    /*
-     * Whether this set contains all types in other, except (possibly) the
-     * specified type.
-     */
-    bool filtersType(const TemporaryTypeSet* other, Type type) const;
-
-    enum DoubleConversion {
-        /* All types in the set should use eager double conversion. */
-        AlwaysConvertToDoubles,
-
-        /* Some types in the set should use eager double conversion. */
-        MaybeConvertToDoubles,
-
-        /* No types should use eager double conversion. */
-        DontConvertToDoubles,
-
-        /* Some types should use eager double conversion, others cannot. */
-        AmbiguousDoubleConversion
-    };
-
-    /*
-     * Whether known double optimizations are possible for element accesses on
-     * objects in this type set.
-     */
-    DoubleConversion convertDoubleElements(CompilerConstraintList* constraints);
-
-  private:
-    void getTypedArraySharedness(CompilerConstraintList* constraints,
-                                 TypedArraySharedness* sharedness);
-};
-
 bool
 AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* group, HandleId id);
 
 bool
 AddClearDefiniteFunctionUsesInScript(JSContext* cx, ObjectGroup* group,
                                      JSScript* script, JSScript* calleeScript);
 
 // For groups where only a small number of objects have been allocated, this
@@ -1032,159 +174,33 @@ class PreliminaryObjectArrayWithTemplate
 
     void maybeAnalyze(JSContext* cx, ObjectGroup* group, bool force = false);
 
     void trace(JSTracer* trc);
 
     static void writeBarrierPre(PreliminaryObjectArrayWithTemplate* preliminaryObjects);
 };
 
-// New script properties analyses overview.
-//
-// When constructing objects using 'new' on a script, we attempt to determine
-// the properties which that object will eventually have. This is done via two
-// analyses. One of these, the definite properties analysis, is static, and the
-// other, the acquired properties analysis, is dynamic. As objects are
-// constructed using 'new' on some script to create objects of group G, our
-// analysis strategy is as follows:
-//
-// - When the first objects are created, no analysis is immediately performed.
-//   Instead, all objects of group G are accumulated in an array.
-//
-// - After a certain number of such objects have been created, the definite
-//   properties analysis is performed. This analyzes the body of the
-//   constructor script and any other functions it calls to look for properties
-//   which will definitely be added by the constructor in a particular order,
-//   creating an object with shape S.
-//
-// - The properties in S are compared with the greatest common prefix P of the
-//   shapes of the objects that have been created. If P has more properties
-//   than S, the acquired properties analysis is performed.
-//
-// - The acquired properties analysis marks all properties in P as definite
-//   in G, and creates a new group IG for objects which are partially
-//   initialized. Objects of group IG are initially created with shape S, and if
-//   they are later given shape P, their group can be changed to G.
-//
-// For objects which are rarely created, the definite properties analysis can
-// be triggered after only one or a few objects have been allocated, when code
-// being Ion compiled might access them. In this case type information in the
-// constructor might not be good enough for the definite properties analysis to
-// compute useful information, but the acquired properties analysis will still
-// be able to identify definite properties in this case.
-//
-// This layered approach is designed to maximize performance on easily
-// analyzable code, while still allowing us to determine definite properties
-// robustly when code consistently adds the same properties to objects, but in
-// complex ways which can't be understood statically.
-class TypeNewScript
+/**
+ * A type representing the initializer of a property within a script being 'new'd.
+ */
+class TypeNewScriptInitializer
 {
   public:
-    struct Initializer {
-        enum Kind {
-            SETPROP,
-            SETPROP_FRAME,
-            DONE
-        } kind;
-        uint32_t offset;
-        Initializer(Kind kind, uint32_t offset)
-          : kind(kind), offset(offset)
-        {}
-    };
-
-  private:
-    // Scripted function which this information was computed for.
-    HeapPtr<JSFunction*> function_ = {};
-
-    // Any preliminary objects with the type. The analyses are not performed
-    // until this array is cleared.
-    PreliminaryObjectArray* preliminaryObjects = nullptr;
-
-    // After the new script properties analyses have been performed, a template
-    // object to use for newly constructed objects. The shape of this object
-    // reflects all definite properties the object will have, and the
-    // allocation kind to use. This is null if the new objects have an unboxed
-    // layout, in which case the UnboxedLayout provides the initial structure
-    // of the object.
-    HeapPtr<PlainObject*> templateObject_ = {};
-
-    // Order in which definite properties become initialized. We need this in
-    // case the definite properties are invalidated (such as by adding a setter
-    // to an object on the prototype chain) while an object is in the middle of
-    // being initialized, so we can walk the stack and fixup any objects which
-    // look for in-progress objects which were prematurely set with an incorrect
-    // shape. Property assignments in inner frames are preceded by a series of
-    // SETPROP_FRAME entries specifying the stack down to the frame containing
-    // the write.
-    Initializer* initializerList = nullptr;
-
-    // If there are additional properties found by the acquired properties
-    // analysis which were not found by the definite properties analysis, this
-    // shape contains all such additional properties (plus the definite
-    // properties). When an object of this group acquires this shape, it is
-    // fully initialized and its group can be changed to initializedGroup.
-    HeapPtr<Shape*> initializedShape_ = {};
-
-    // Group with definite properties set for all properties found by
-    // both the definite and acquired properties analyses.
-    HeapPtr<ObjectGroup*> initializedGroup_ = {};
+    enum Kind
+    {
+        SETPROP,
+        SETPROP_FRAME,
+        DONE
+    } kind;
+    uint32_t offset;
 
-  public:
-    TypeNewScript() = default;
-    ~TypeNewScript() {
-        js_delete(preliminaryObjects);
-        js_free(initializerList);
-    }
-
-    void clear() {
-        function_ = nullptr;
-        templateObject_ = nullptr;
-        initializedShape_ = nullptr;
-        initializedGroup_ = nullptr;
-    }
-
-    static void writeBarrierPre(TypeNewScript* newScript);
-
-    bool analyzed() const {
-        return preliminaryObjects == nullptr;
-    }
-
-    PlainObject* templateObject() const {
-        return templateObject_;
-    }
-
-    Shape* initializedShape() const {
-        return initializedShape_;
-    }
-
-    ObjectGroup* initializedGroup() const {
-        return initializedGroup_;
-    }
-
-    JSFunction* function() const {
-        return function_;
-    }
-
-    void trace(JSTracer* trc);
-    void sweep();
-
-    void registerNewObject(PlainObject* res);
-    bool maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, bool force = false);
-
-    bool rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* group);
-
-    static bool make(JSContext* cx, ObjectGroup* group, JSFunction* fun);
-    static TypeNewScript* makeNativeVersion(JSContext* cx, TypeNewScript* newScript,
-                                            PlainObject* templateObject);
-
-    size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
-
-    static size_t offsetOfPreliminaryObjects() {
-        return offsetof(TypeNewScript, preliminaryObjects);
-    }
+    TypeNewScriptInitializer(Kind kind, uint32_t offset)
+      : kind(kind), offset(offset)
+    {}
 };
 
 /* Is this a reasonable PC to be doing inlining on? */
 inline bool isInlinableCall(jsbytecode* pc);
 
 bool
 ClassCanHaveExtraProperties(const Class* clasp);
 
@@ -1343,64 +359,16 @@ bool
 FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList* constraints,
                   IonCompilationId compilationId, bool* isValidOut);
 
 // Update the actual types in any scripts queried by constraints with any
 // speculative types added during the definite properties analysis.
 void
 FinishDefinitePropertiesAnalysis(JSContext* cx, CompilerConstraintList* constraints);
 
-// Representation of a heap type property which may or may not be instantiated.
-// Heap properties for singleton types are instantiated lazily as they are used
-// by the compiler, but this is only done on the main thread. If we are
-// compiling off thread and use a property which has not yet been instantiated,
-// it will be treated as empty and non-configured and will be instantiated when
-// rejoining to the main thread. If it is in fact not empty, the compilation
-// will fail; to avoid this, we try to instantiate singleton property types
-// during generation of baseline caches.
-class HeapTypeSetKey
-{
-    friend class TypeSet::ObjectKey;
-
-    // Object and property being accessed.
-    TypeSet::ObjectKey* object_;
-    jsid id_;
-
-    // If instantiated, the underlying heap type set.
-    HeapTypeSet* maybeTypes_;
-
-  public:
-    HeapTypeSetKey()
-      : object_(nullptr), id_(JSID_EMPTY), maybeTypes_(nullptr)
-    {}
-
-    TypeSet::ObjectKey* object() const { return object_; }
-    jsid id() const { return id_; }
-
-    HeapTypeSet* maybeTypes() const {
-        if (maybeTypes_) {
-            maybeTypes_->checkMagic();
-        }
-        return maybeTypes_;
-    }
-
-    bool instantiate(JSContext* cx);
-
-    void freeze(CompilerConstraintList* constraints);
-    jit::MIRType knownMIRType(CompilerConstraintList* constraints);
-    bool nonData(CompilerConstraintList* constraints);
-    bool nonWritable(CompilerConstraintList* constraints);
-    bool isOwnProperty(CompilerConstraintList* constraints, bool allowEmptyTypesForGlobal = false);
-    bool knownSubset(CompilerConstraintList* constraints, const HeapTypeSetKey& other);
-    JSObject* singleton(CompilerConstraintList* constraints);
-    bool needsBarrier(CompilerConstraintList* constraints);
-    bool constant(CompilerConstraintList* constraints, Value* valOut);
-    bool couldBeConstant(CompilerConstraintList* constraints);
-};
-
 struct AutoEnterAnalysis;
 
 class TypeZone
 {
     JS::Zone* const zone_;
 
     /* Pool for type information in this zone. */
     static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 8 * 1024;
copy from js/src/vm/TypeInference.h
copy to js/src/vm/TypeSet.h
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeSet.h
@@ -1,63 +1,87 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-/* Definitions related to javascript type inference. */
+/* TypeSet classes and functions. */
 
-#ifndef vm_TypeInference_h
-#define vm_TypeInference_h
+#ifndef vm_TypeSet_h
+#define vm_TypeSet_h
 
-#include "mozilla/MemoryReporting.h"
+#include "mozilla/Assertions.h" // MOZ_ASSERT
+#include "mozilla/Attributes.h" // MOZ_ALWAYS_INLINE
+#include "mozilla/Likely.h" // MOZ_UNLIKELY
 
-#include "jsfriendapi.h"
-#include "jstypes.h"
+#include <stdint.h> // intptr_t, uintptr_t, uint8_t, uint32_t
+#include <stdio.h> // FILE
+
+#include "jstypes.h" // JS_BITS_PER_WORD
+#include "jsutil.h" // JS_CRASH_DIAGNOSTICS
 
-#include "ds/IdValuePair.h"
-#include "ds/LifoAlloc.h"
-#include "gc/Barrier.h"
-#include "jit/IonTypes.h"
-#include "js/AllocPolicy.h"
-#include "js/UbiNode.h"
-#include "js/Utility.h"
-#include "js/Vector.h"
-#include "threading/ProtectedData.h"
-#include "vm/TaggedProto.h"
+#include "jit/IonTypes.h" // jit::MIRType
+#include "js/GCAnnotations.h" // JS_HAZ_GC_POINTER
+#include "js/TracingAPI.h" // JSTracer
+#include "js/TypeDecls.h" // IF_BIGINT
+#include "js/Utility.h" // UniqueChars
+#include "js/Value.h" // JSVAL_TYPE_*
+#include "js/Vector.h" // js::Vector
+#include "vm/TaggedProto.h" // js::TaggedProto
+
+struct JSContext;
+struct jsid;
+class JSObject;
+
+namespace JS {
+
+class Compartment;
+class Realm;
+class Zone;
+
+} // namespace JS
 
 namespace js {
 
 namespace jit {
-    struct IonScript;
-    class JitAllocPolicy;
-    class TempAllocator;
+
+struct IonScript;
+class TempAllocator;
+
 } // namespace jit
 
+class AutoClearTypeInferenceStateOnOOM;
+class AutoSweepBase;
+class AutoSweepObjectGroup;
+struct Class;
+class CompilerConstraintList;
+class HeapTypeSetKey;
+class LifoAlloc;
+class ObjectGroup;
+class SystemAllocPolicy;
 class TypeConstraint;
 class TypeNewScript;
 class TypeZone;
-class CompilerConstraintList;
-class HeapTypeSetKey;
 
 /*
  * Type inference memory management overview.
  *
  * Type information about the values observed within scripts and about the
  * contents of the heap is accumulated as the program executes. Compilation
  * accumulates constraints relating type information on the heap with the
  * compilations that should be invalidated when those types change. Type
  * information and constraints are allocated in the zone's typeLifoAlloc,
  * and on GC all data referring to live things is copied into a new allocator.
  * Thus, type set and constraints only hold weak references.
  */
 
 /* Flags and other state stored in TypeSet::flags */
-enum : uint32_t {
+enum : uint32_t
+{
     TYPE_FLAG_UNDEFINED =   0x1,
     TYPE_FLAG_NULL      =   0x2,
     TYPE_FLAG_BOOLEAN   =   0x4,
     TYPE_FLAG_INT32     =   0x8,
     TYPE_FLAG_DOUBLE    =  0x10,
     TYPE_FLAG_STRING    =  0x20,
     TYPE_FLAG_SYMBOL    =  0x40,
 #ifdef ENABLE_BIGINT
@@ -115,24 +139,25 @@ enum : uint32_t {
      * a fixed slot.
      *
      * If the property is definite, mask and shift storing the slot + 1.
      * Otherwise these bits are clear.
      */
     TYPE_FLAG_DEFINITE_MASK       = 0xfffc0000,
     TYPE_FLAG_DEFINITE_SHIFT      = 18
 };
-typedef uint32_t TypeFlags;
+using TypeFlags = uint32_t;
 
 static_assert(TYPE_FLAG_PRIMITIVE < TYPE_FLAG_ANYOBJECT &&
               TYPE_FLAG_LAZYARGS < TYPE_FLAG_ANYOBJECT,
               "TYPE_FLAG_ANYOBJECT should be greater than primitive type flags");
 
 /* Flags and other state stored in ObjectGroup::Flags */
-enum : uint32_t {
+enum : uint32_t
+{
     /* Whether this group is associated with some allocation site. */
     OBJECT_FLAG_FROM_ALLOCATION_SITE  = 0x1,
 
     /* Whether this group is associated with a single object. */
     OBJECT_FLAG_SINGLETON             = 0x2,
 
     /*
      * Whether this group is used by objects whose singleton groups have not
@@ -201,17 +226,17 @@ enum : uint32_t {
     OBJECT_FLAG_ADDENDUM_MASK         = 0x38000000,
     OBJECT_FLAG_ADDENDUM_SHIFT        = 27,
 
     // Mask/shift for this group's generation. If out of sync with the
     // TypeZone's generation, this group hasn't been swept yet.
     OBJECT_FLAG_GENERATION_MASK       = 0x40000000,
     OBJECT_FLAG_GENERATION_SHIFT      = 30,
 };
-typedef uint32_t ObjectGroupFlags;
+using ObjectGroupFlags = uint32_t;
 
 class StackTypeSet;
 class HeapTypeSet;
 class TemporaryTypeSet;
 
 /*
  * [SMDOC] Type-Inference TypeSet
  *
@@ -242,20 +267,34 @@ class TemporaryTypeSet;
  * - If an unboxed object is converted to a native object, its group will also
  *   change and type sets containing the old group will not necessarily contain
  *   the new group. Unlike the above case, this will not degrade property type
  *   information, but Ion will no longer optimize unboxed objects with the old
  *   group.
  */
 class TypeSet
 {
+  protected:
+    /* Flags for this type set. */
+    TypeFlags flags = 0;
+
   public:
+    class ObjectKey;
+
+  protected:
+    /* Possible objects this type set can represent. */
+    ObjectKey** objectSet = nullptr;
+
+  public:
+    TypeSet() = default;
+
     // Type set entry for either a JSObject with singleton type or a
     // non-singleton ObjectGroup.
-    class ObjectKey {
+    class ObjectKey
+    {
       public:
         static intptr_t keyBits(ObjectKey* obj) { return (intptr_t) obj; }
         static ObjectKey* getKey(ObjectKey* obj) { return obj; }
 
         static inline ObjectKey* get(JSObject* obj);
         static inline ObjectKey* get(ObjectGroup* group);
 
         bool isGroup() {
@@ -397,32 +436,20 @@ class TypeSet
     }
 
     static inline Type ObjectType(JSObject* obj);
     static inline Type ObjectType(ObjectGroup* group);
     static inline Type ObjectType(ObjectKey* key);
 
     static const char* NonObjectTypeString(Type type);
 
-    static UniqueChars TypeString(Type type);
-    static UniqueChars ObjectGroupString(ObjectGroup* group);
-
-  protected:
-    /* Flags for this type set. */
-    TypeFlags flags;
-
-    /* Possible objects this type set can represent. */
-    ObjectKey** objectSet;
+    static JS::UniqueChars TypeString(Type type);
+    static JS::UniqueChars ObjectGroupString(ObjectGroup* group);
 
   public:
-
-    TypeSet()
-      : flags(0), objectSet(nullptr)
-    {}
-
     void print(FILE* fp = stderr);
 
     /* Whether this set contains a specific type. */
     MOZ_ALWAYS_INLINE bool hasType(Type type) const;
 
     TypeFlags baseFlags() const { return flags & TYPE_FLAG_BASE_MASK; }
     bool unknown() const { return !!(flags & TYPE_FLAG_UNKNOWN); }
     bool unknownObject() const { return !!(flags & (TYPE_FLAG_UNKNOWN | TYPE_FLAG_ANYOBJECT)); }
@@ -458,17 +485,17 @@ class TypeSet
      * specific objects. The result should not be modified further.
      */
     static TemporaryTypeSet* removeSet(TemporaryTypeSet* a, TemporaryTypeSet* b, LifoAlloc* alloc);
 
     /* Add a type to this set using the specified allocator. */
     void addType(Type type, LifoAlloc* alloc);
 
     /* Get a list of all types in this set. */
-    typedef Vector<Type, 1, SystemAllocPolicy> TypeList;
+    using TypeList = Vector<Type, 1, SystemAllocPolicy>;
     template <class TypeListT> bool enumerateTypes(TypeListT* list) const;
 
     /*
      * Iterate through the objects in this set. getObjectCount overapproximates
      * in the hash case (see SET_ARRAY_SIZE in TypeInference-inl.h), and
      * getObject may return nullptr.
      */
     inline unsigned getObjectCount() const;
@@ -549,24 +576,24 @@ class TypeSet
     uint32_t baseObjectCount() const {
         return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT;
     }
     inline void setBaseObjectCount(uint32_t count);
 
     void clearObjects();
 
   public:
-    static inline Type GetValueType(const Value& val);
+    static inline Type GetValueType(const JS::Value& val);
 
-    static inline bool IsUntrackedValue(const Value& val);
+    static inline bool IsUntrackedValue(const JS::Value& val);
 
     // Get the type of a possibly optimized out or uninitialized let value.
     // This generally only happens on unconditional type monitors on bailing
     // out of Ion, such as for argument and local types.
-    static inline Type GetMaybeUntrackedValueType(const Value& val);
+    static inline Type GetMaybeUntrackedValueType(const JS::Value& val);
 
     static bool IsTypeMarked(JSRuntime* rt, Type* v);
     static bool IsTypeAboutToBeFinalized(Type* v);
 } JS_HAZ_GC_POINTER;
 
 #if JS_BITS_PER_WORD == 32
 static const uintptr_t BaseTypeInferenceMagic = 0xa1a2b3b4;
 #else
@@ -583,31 +610,26 @@ ReportMagicWordFailure(uintptr_t actual,
 #endif
 
 /*
  * A constraint which listens to additions to a type set and propagates those
  * changes to other type sets.
  */
 class TypeConstraint
 {
+  private:
 #ifdef JS_CRASH_DIAGNOSTICS
-    uintptr_t magic_;
+    uintptr_t magic_ = TypeConstraintMagic;
 #endif
 
     /* Next constraint listening to the same type set. */
-    TypeConstraint* next_;
+    TypeConstraint* next_ = nullptr;
 
   public:
-    TypeConstraint()
-      : next_(nullptr)
-    {
-#ifdef JS_CRASH_DIAGNOSTICS
-        magic_ = TypeConstraintMagic;
-#endif
-    }
+    TypeConstraint() = default;
 
     void checkMagic() const {
 #ifdef JS_CRASH_DIAGNOSTICS
         if (MOZ_UNLIKELY(magic_ != TypeConstraintMagic)) {
             ReportMagicWordFailure(magic_, TypeConstraintMagic);
         }
 #endif
     }
@@ -652,108 +674,30 @@ class TypeConstraint
      * zone's new allocator. Type constraints only hold weak references.
      */
     virtual bool sweep(TypeZone& zone, TypeConstraint** res) = 0;
 
     /* The associated compartment, if any. */
     virtual JS::Compartment* maybeCompartment() = 0;
 };
 
-// If there is an OOM while sweeping types, the type information is deoptimized
-// so that it stays correct (i.e. overapproximates the possible types in the
-// zone), but constraints might not have been triggered on the deoptimization
-// or even copied over completely. In this case, destroy all JIT code and new
-// script information in the zone, the only things whose correctness depends on
-// the type constraints.
-class AutoClearTypeInferenceStateOnOOM
-{
-    Zone* zone;
-    bool oom;
-
-    AutoClearTypeInferenceStateOnOOM(const AutoClearTypeInferenceStateOnOOM&) = delete;
-    void operator=(const AutoClearTypeInferenceStateOnOOM&) = delete;
-
-  public:
-    explicit AutoClearTypeInferenceStateOnOOM(Zone* zone);
-    ~AutoClearTypeInferenceStateOnOOM();
-
-    void setOOM() {
-        oom = true;
-    }
-    bool hadOOM() const {
-        return oom;
-    }
-};
-
-class MOZ_RAII AutoSweepBase
-{
-    // Make sure we don't GC while this class is live since GC might trigger
-    // (incremental) sweeping.
-    JS::AutoCheckCannotGC nogc;
-};
-
-// Sweep an ObjectGroup. Functions that expect a swept group should take a
-// reference to this class.
-class MOZ_RAII AutoSweepObjectGroup : public AutoSweepBase
-{
-#ifdef DEBUG
-    ObjectGroup* group_;
-#endif
-
-  public:
-    inline explicit AutoSweepObjectGroup(ObjectGroup* group);
-    inline AutoSweepObjectGroup(ObjectGroup* group, AutoClearTypeInferenceStateOnOOM& oom);
-#ifdef DEBUG
-    inline ~AutoSweepObjectGroup();
-
-    ObjectGroup* group() const {
-        return group_;
-    }
-#endif
-};
-
-// Sweep a TypeScript. Functions that expect a swept script should take a
-// reference to this class.
-class MOZ_RAII AutoSweepTypeScript : public AutoSweepBase
-{
-#ifdef DEBUG
-    JSScript* script_;
-#endif
-
-  public:
-    inline explicit AutoSweepTypeScript(JSScript* script);
-    inline AutoSweepTypeScript(JSScript* script, AutoClearTypeInferenceStateOnOOM& oom);
-#ifdef DEBUG
-    inline ~AutoSweepTypeScript();
-
-    JSScript* script() const {
-        return script_;
-    }
-#endif
-};
-
 /* Superclass common to stack and heap type sets. */
 class ConstraintTypeSet : public TypeSet
 {
+  private:
 #ifdef JS_CRASH_DIAGNOSTICS
-    uintptr_t magic_;
+    uintptr_t magic_ = ConstraintTypeSetMagic;
 #endif
 
   protected:
     /* Chain of constraints which propagate changes out from this type set. */
-    TypeConstraint* constraintList_;
+    TypeConstraint* constraintList_ = nullptr;
 
   public:
-    ConstraintTypeSet()
-      : constraintList_(nullptr)
-    {
-#ifdef JS_CRASH_DIAGNOSTICS
-        magic_ = ConstraintTypeSetMagic;
-#endif
-    }
+    ConstraintTypeSet() = default;
 
 #ifdef JS_CRASH_DIAGNOSTICS
     void initMagic() {
         MOZ_ASSERT(!magic_);
         magic_ = ConstraintTypeSetMagic;
     }
 #endif
 
@@ -821,19 +765,16 @@ class HeapTypeSet : public ConstraintTyp
 
     /* Mark this type set as representing a non-writable property. */
     inline void setNonWritableProperty(const AutoSweepObjectGroup& sweep, JSContext* cx);
 
     // Mark this type set as being non-constant.
     inline void setNonConstantProperty(const AutoSweepObjectGroup& sweep, JSContext* cx);
 };
 
-CompilerConstraintList*
-NewCompilerConstraintList(jit::TempAllocator& alloc);
-
 enum class DOMObjectKind : uint8_t { Proxy, Native, Unknown };
 
 class TemporaryTypeSet : public TypeSet
 {
   public:
     TemporaryTypeSet() {}
     TemporaryTypeSet(LifoAlloc* alloc, Type type);
 
@@ -885,21 +826,22 @@ class TemporaryTypeSet : public TypeSet
     /* Get the class shared by all objects in this set, or nullptr. */
     const Class* getKnownClass(CompilerConstraintList* constraints);
 
     /*
      * Get the realm shared by all objects in this set, or nullptr. Returns
      * nullptr if the set contains proxies (because cross-compartment wrappers
      * don't have a single realm associated with them).
      */
-    Realm* getKnownRealm(CompilerConstraintList* constraints);
+    JS::Realm* getKnownRealm(CompilerConstraintList* constraints);
 
     /* Result returned from forAllClasses */
-    enum ForAllResult {
-        EMPTY=1,                // Set empty
+    enum ForAllResult
+    {
+        EMPTY = 1,              // Set empty
         ALL_TRUE,               // Set not empty and predicate returned true for all classes
         ALL_FALSE,              // Set not empty and predicate returned false for all classes
         MIXED,                  // Set not empty and predicate returned false for some classes
                                 // and true for others, or set contains an unknown or non-object
                                 // type
     };
 
     /* Apply func to the members of the set and return an appropriate result.
@@ -910,23 +852,25 @@ class TemporaryTypeSet : public TypeSet
 
     /*
      * Returns true if all objects in this set have the same prototype, and
      * assigns this object to *proto. The proto can be nullptr.
      */
     bool getCommonPrototype(CompilerConstraintList* constraints, JSObject** proto);
 
     /* Whether the buffer mapped by a TypedArray is shared memory or not */
-    enum TypedArraySharedness {
-        UnknownSharedness=1,    // We can't determine sharedness
+    enum TypedArraySharedness
+    {
+        UnknownSharedness = 1,  // We can't determine sharedness
         KnownShared,            // We know for sure the buffer is shared
         KnownUnshared           // We know for sure the buffer is unshared
     };
 
-    /* Get the typed array type of all objects in this set, or Scalar::MaxTypedArrayViewType.
+    /*
+     * Get the typed array type of all objects in this set, or Scalar::MaxTypedArrayViewType.
      * If there is such a common type and sharedness is not nullptr then
      * *sharedness is set to what we know about the sharedness of the memory.
      */
     Scalar::Type getTypedArrayType(CompilerConstraintList* constraints,
                                    TypedArraySharedness* sharedness = nullptr);
 
     /* Whether all objects have JSCLASS_IS_DOMJSCLASS set. */
     bool isDOMClass(CompilerConstraintList* constraints, DOMObjectKind* kind);
@@ -945,17 +889,18 @@ class TemporaryTypeSet : public TypeSet
     bool propertyNeedsBarrier(CompilerConstraintList* constraints, jsid id);
 
     /*
      * Whether this set contains all types in other, except (possibly) the
      * specified type.
      */
     bool filtersType(const TemporaryTypeSet* other, Type type) const;
 
-    enum DoubleConversion {
+    enum DoubleConversion
+    {
         /* All types in the set should use eager double conversion. */
         AlwaysConvertToDoubles,
 
         /* Some types in the set should use eager double conversion. */
         MaybeConvertToDoubles,
 
         /* No types should use eager double conversion. */
         DontConvertToDoubles,
@@ -970,389 +915,16 @@ class TemporaryTypeSet : public TypeSet
      */
     DoubleConversion convertDoubleElements(CompilerConstraintList* constraints);
 
   private:
     void getTypedArraySharedness(CompilerConstraintList* constraints,
                                  TypedArraySharedness* sharedness);
 };
 
-bool
-AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* group, HandleId id);
-
-bool
-AddClearDefiniteFunctionUsesInScript(JSContext* cx, ObjectGroup* group,
-                                     JSScript* script, JSScript* calleeScript);
-
-// For groups where only a small number of objects have been allocated, this
-// structure keeps track of all objects in the group. Once COUNT objects have
-// been allocated, this structure is cleared and the objects are analyzed, to
-// perform the new script properties analyses or determine if an unboxed
-// representation can be used.
-class PreliminaryObjectArray
-{
-  public:
-    static const uint32_t COUNT = 20;
-
-  private:
-    // All objects with the type which have been allocated. The pointers in
-    // this array are weak.
-    JSObject* objects[COUNT] = {}; // zeroes
-
-  public:
-    PreliminaryObjectArray() = default;
-
-    void registerNewObject(PlainObject* res);
-    void unregisterObject(PlainObject* obj);
-
-    JSObject* get(size_t i) const {
-        MOZ_ASSERT(i < COUNT);
-        return objects[i];
-    }
-
-    bool full() const;
-    bool empty() const;
-    void sweep();
-};
-
-class PreliminaryObjectArrayWithTemplate : public PreliminaryObjectArray
-{
-    HeapPtr<Shape*> shape_;
-
-  public:
-    explicit PreliminaryObjectArrayWithTemplate(Shape* shape)
-      : shape_(shape)
-    {}
-
-    void clear() {
-        shape_.init(nullptr);
-    }
-
-    Shape* shape() {
-        return shape_;
-    }
-
-    void maybeAnalyze(JSContext* cx, ObjectGroup* group, bool force = false);
-
-    void trace(JSTracer* trc);
-
-    static void writeBarrierPre(PreliminaryObjectArrayWithTemplate* preliminaryObjects);
-};
-
-// New script properties analyses overview.
-//
-// When constructing objects using 'new' on a script, we attempt to determine
-// the properties which that object will eventually have. This is done via two
-// analyses. One of these, the definite properties analysis, is static, and the
-// other, the acquired properties analysis, is dynamic. As objects are
-// constructed using 'new' on some script to create objects of group G, our
-// analysis strategy is as follows:
-//
-// - When the first objects are created, no analysis is immediately performed.
-//   Instead, all objects of group G are accumulated in an array.
-//
-// - After a certain number of such objects have been created, the definite
-//   properties analysis is performed. This analyzes the body of the
-//   constructor script and any other functions it calls to look for properties
-//   which will definitely be added by the constructor in a particular order,
-//   creating an object with shape S.
-//
-// - The properties in S are compared with the greatest common prefix P of the
-//   shapes of the objects that have been created. If P has more properties
-//   than S, the acquired properties analysis is performed.
-//
-// - The acquired properties analysis marks all properties in P as definite
-//   in G, and creates a new group IG for objects which are partially
-//   initialized. Objects of group IG are initially created with shape S, and if
-//   they are later given shape P, their group can be changed to G.
-//
-// For objects which are rarely created, the definite properties analysis can
-// be triggered after only one or a few objects have been allocated, when code
-// being Ion compiled might access them. In this case type information in the
-// constructor might not be good enough for the definite properties analysis to
-// compute useful information, but the acquired properties analysis will still
-// be able to identify definite properties in this case.
-//
-// This layered approach is designed to maximize performance on easily
-// analyzable code, while still allowing us to determine definite properties
-// robustly when code consistently adds the same properties to objects, but in
-// complex ways which can't be understood statically.
-class TypeNewScript
-{
-  public:
-    struct Initializer {
-        enum Kind {
-            SETPROP,
-            SETPROP_FRAME,
-            DONE
-        } kind;
-        uint32_t offset;
-        Initializer(Kind kind, uint32_t offset)
-          : kind(kind), offset(offset)
-        {}
-    };
-
-  private:
-    // Scripted function which this information was computed for.
-    HeapPtr<JSFunction*> function_ = {};
-
-    // Any preliminary objects with the type. The analyses are not performed
-    // until this array is cleared.
-    PreliminaryObjectArray* preliminaryObjects = nullptr;
-
-    // After the new script properties analyses have been performed, a template
-    // object to use for newly constructed objects. The shape of this object
-    // reflects all definite properties the object will have, and the
-    // allocation kind to use. This is null if the new objects have an unboxed
-    // layout, in which case the UnboxedLayout provides the initial structure
-    // of the object.
-    HeapPtr<PlainObject*> templateObject_ = {};
-
-    // Order in which definite properties become initialized. We need this in
-    // case the definite properties are invalidated (such as by adding a setter
-    // to an object on the prototype chain) while an object is in the middle of
-    // being initialized, so we can walk the stack and fixup any objects which
-    // look for in-progress objects which were prematurely set with an incorrect
-    // shape. Property assignments in inner frames are preceded by a series of
-    // SETPROP_FRAME entries specifying the stack down to the frame containing
-    // the write.
-    Initializer* initializerList = nullptr;
-
-    // If there are additional properties found by the acquired properties
-    // analysis which were not found by the definite properties analysis, this
-    // shape contains all such additional properties (plus the definite
-    // properties). When an object of this group acquires this shape, it is
-    // fully initialized and its group can be changed to initializedGroup.
-    HeapPtr<Shape*> initializedShape_ = {};
-
-    // Group with definite properties set for all properties found by
-    // both the definite and acquired properties analyses.
-    HeapPtr<ObjectGroup*> initializedGroup_ = {};
-
-  public:
-    TypeNewScript() = default;
-    ~TypeNewScript() {
-        js_delete(preliminaryObjects);
-        js_free(initializerList);
-    }
-
-    void clear() {
-        function_ = nullptr;
-        templateObject_ = nullptr;
-        initializedShape_ = nullptr;
-        initializedGroup_ = nullptr;
-    }
-
-    static void writeBarrierPre(TypeNewScript* newScript);
-
-    bool analyzed() const {
-        return preliminaryObjects == nullptr;
-    }
-
-    PlainObject* templateObject() const {
-        return templateObject_;
-    }
-
-    Shape* initializedShape() const {
-        return initializedShape_;
-    }
-
-    ObjectGroup* initializedGroup() const {
-        return initializedGroup_;
-    }
-
-    JSFunction* function() const {
-        return function_;
-    }
-
-    void trace(JSTracer* trc);
-    void sweep();
-
-    void registerNewObject(PlainObject* res);
-    bool maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, bool force = false);
-
-    bool rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* group);
-
-    static bool make(JSContext* cx, ObjectGroup* group, JSFunction* fun);
-    static TypeNewScript* makeNativeVersion(JSContext* cx, TypeNewScript* newScript,
-                                            PlainObject* templateObject);
-
-    size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
-
-    static size_t offsetOfPreliminaryObjects() {
-        return offsetof(TypeNewScript, preliminaryObjects);
-    }
-};
-
-/* Is this a reasonable PC to be doing inlining on? */
-inline bool isInlinableCall(jsbytecode* pc);
-
-bool
-ClassCanHaveExtraProperties(const Class* clasp);
-
-class RecompileInfo
-{
-    JSScript* script_;
-    IonCompilationId id_;
-
-  public:
-    RecompileInfo(JSScript* script, IonCompilationId id)
-      : script_(script),
-        id_(id)
-    {}
-
-    JSScript* script() const {
-        return script_;
-    }
-
-    inline jit::IonScript* maybeIonScriptToInvalidate(const TypeZone& zone) const;
-
-    inline bool shouldSweep(const TypeZone& zone);
-
-    bool operator==(const RecompileInfo& other) const {
-        return script_== other.script_ && id_ == other.id_;
-    }
-};
-
-// The RecompileInfoVector has a MinInlineCapacity of one so that invalidating a
-// single IonScript doesn't require an allocation.
-typedef Vector<RecompileInfo, 1, SystemAllocPolicy> RecompileInfoVector;
-
-/* Persistent type information for a script, retained across GCs. */
-class TypeScript
-{
-    friend class ::JSScript;
-
-    // The freeze constraints added to stack type sets will only directly
-    // invalidate the script containing those stack type sets. This Vector
-    // contains compilations that inlined this script, so we can invalidate
-    // them as well.
-    RecompileInfoVector inlinedCompilations_;
-
-    // Variable-size array
-    StackTypeSet typeArray_[1];
-
-  public:
-    RecompileInfoVector& inlinedCompilations() {
-        return inlinedCompilations_;
-    }
-    MOZ_MUST_USE bool addInlinedCompilation(RecompileInfo info) {
-        if (!inlinedCompilations_.empty() && inlinedCompilations_.back() == info) {
-            return true;
-        }
-        return inlinedCompilations_.append(info);
-    }
-
-    /* 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_);
-    }
-
-    static inline size_t SizeIncludingTypeArray(size_t arraySize) {
-        // Ensure typeArray_ is the last data member of TypeScript.
-        JS_STATIC_ASSERT(sizeof(TypeScript) ==
-            sizeof(StackTypeSet) + offsetof(TypeScript, typeArray_));
-        return offsetof(TypeScript, typeArray_) + arraySize * sizeof(StackTypeSet);
-    }
-
-    static inline unsigned NumTypeSets(JSScript* script);
-
-    static inline StackTypeSet* ThisTypes(JSScript* script);
-    static inline StackTypeSet* ArgTypes(JSScript* script, unsigned i);
-
-    /* Get the type set for values observed at an opcode. */
-    static inline StackTypeSet* BytecodeTypes(JSScript* script, jsbytecode* pc);
-
-    template <typename TYPESET>
-    static inline TYPESET* BytecodeTypes(JSScript* script, jsbytecode* pc, uint32_t* bytecodeMap,
-                                         uint32_t* hint, TYPESET* typeArray);
-
-    /*
-     * Monitor a bytecode pushing any value. This must be called for any opcode
-     * which is JOF_TYPESET, and where either the script has not been analyzed
-     * by type inference or where the pc has type barriers. For simplicity, we
-     * always monitor JOF_TYPESET opcodes in the interpreter and stub calls,
-     * and only look at barriers when generating JIT code for the script.
-     */
-    static inline void Monitor(JSContext* cx, JSScript* script, jsbytecode* pc,
-                               const js::Value& val);
-    static inline void Monitor(JSContext* cx, JSScript* script, jsbytecode* pc,
-                               TypeSet::Type type);
-    static inline void Monitor(JSContext* cx, const js::Value& rval);
-
-    static inline void Monitor(JSContext* cx, JSScript* script, jsbytecode* pc,
-                               StackTypeSet* types, const js::Value& val);
-
-    /* Monitor an assignment at a SETELEM on a non-integer identifier. */
-    static inline void MonitorAssign(JSContext* cx, HandleObject obj, jsid id);
-
-    /* Add a type for a variable in a script. */
-    static inline void SetThis(JSContext* cx, JSScript* script, TypeSet::Type type);
-    static inline void SetThis(JSContext* cx, JSScript* script, const js::Value& value);
-    static inline void SetArgument(JSContext* cx, JSScript* script, unsigned arg,
-                                   TypeSet::Type type);
-    static inline void SetArgument(JSContext* cx, JSScript* script, unsigned arg,
-                                   const js::Value& value);
-
-    /*
-     * Freeze all the stack type sets in a script, for a compilation. Returns
-     * copies of the type sets which will be checked against the actual ones
-     * under FinishCompilation, to detect any type changes.
-     */
-    static bool FreezeTypeSets(CompilerConstraintList* constraints, JSScript* script,
-                               TemporaryTypeSet** pThisTypes,
-                               TemporaryTypeSet** pArgTypes,
-                               TemporaryTypeSet** pBytecodeTypes);
-
-    static void Purge(JSContext* cx, HandleScript script);
-
-    void destroy();
-
-    size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
-        return mallocSizeOf(this);
-    }
-
-#ifdef DEBUG
-    void printTypes(JSContext* cx, HandleScript script) const;
-#endif
-};
-
-// Ensures no TypeScripts are purged in the current zone.
-class MOZ_RAII AutoKeepTypeScripts
-{
-    TypeZone& zone_;
-    bool prev_;
-
-    AutoKeepTypeScripts(const AutoKeepTypeScripts&) = delete;
-    void operator=(const AutoKeepTypeScripts&) = delete;
-
-  public:
-    explicit inline AutoKeepTypeScripts(JSContext* cx);
-    inline ~AutoKeepTypeScripts();
-};
-
-void
-FillBytecodeTypeMap(JSScript* script, uint32_t* bytecodeMap);
-
-class RecompileInfo;
-
-// Generate the type constraints for the compilation. Sets |isValidOut| based on
-// whether the type constraints still hold.
-bool
-FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList* constraints,
-                  IonCompilationId compilationId, bool* isValidOut);
-
-// Update the actual types in any scripts queried by constraints with any
-// speculative types added during the definite properties analysis.
-void
-FinishDefinitePropertiesAnalysis(JSContext* cx, CompilerConstraintList* constraints);
-
 // Representation of a heap type property which may or may not be instantiated.
 // Heap properties for singleton types are instantiated lazily as they are used
 // by the compiler, but this is only done on the main thread. If we are
 // compiling off thread and use a property which has not yet been instantiated,
 // it will be treated as empty and non-configured and will be instantiated when
 // rejoining to the main thread. If it is in fact not empty, the compilation
 // will fail; to avoid this, we try to instantiate singleton property types
 // during generation of baseline caches.
@@ -1391,136 +963,11 @@ class HeapTypeSetKey
     bool isOwnProperty(CompilerConstraintList* constraints, bool allowEmptyTypesForGlobal = false);
     bool knownSubset(CompilerConstraintList* constraints, const HeapTypeSetKey& other);
     JSObject* singleton(CompilerConstraintList* constraints);
     bool needsBarrier(CompilerConstraintList* constraints);
     bool constant(CompilerConstraintList* constraints, Value* valOut);
     bool couldBeConstant(CompilerConstraintList* constraints);
 };
 
-struct AutoEnterAnalysis;
-
-class TypeZone
-{
-    JS::Zone* const zone_;
-
-    /* Pool for type information in this zone. */
-    static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 8 * 1024;
-    ZoneData<LifoAlloc> typeLifoAlloc_;
-
-    // Under CodeGenerator::link, the id of the current compilation.
-    ZoneData<mozilla::Maybe<IonCompilationId>> currentCompilationId_;
-
-    TypeZone(const TypeZone&) = delete;
-    void operator=(const TypeZone&) = delete;
-
-  public:
-    // Current generation for sweeping.
-    ZoneOrGCTaskOrIonCompileData<uint32_t> generation;
-
-    // During incremental sweeping, allocator holding the old type information
-    // for the zone.
-    ZoneData<LifoAlloc> sweepTypeLifoAlloc;
-
-    // During incremental sweeping, whether to try to destroy all type
-    // information attached to scripts.
-    ZoneData<bool> sweepReleaseTypes;
-
-    ZoneData<bool> sweepingTypes;
-
-    ZoneData<bool> keepTypeScripts;
-
-    // The topmost AutoEnterAnalysis on the stack, if there is one.
-    ZoneData<AutoEnterAnalysis*> activeAnalysis;
-
-    explicit TypeZone(JS::Zone* zone);
-    ~TypeZone();
-
-    JS::Zone* zone() const { return zone_; }
-
-    LifoAlloc& typeLifoAlloc() {
-#ifdef JS_CRASH_DIAGNOSTICS
-        MOZ_RELEASE_ASSERT(CurrentThreadCanAccessZone(zone_));
-#endif
-        return typeLifoAlloc_.ref();
-    }
-
-    void beginSweep(bool releaseTypes);
-    void endSweep(JSRuntime* rt);
-    void clearAllNewScriptsOnOOM(AutoClearTypeInferenceStateOnOOM& oom);
-
-    /* Mark a script as needing recompilation once inference has finished. */
-    void addPendingRecompile(JSContext* cx, const RecompileInfo& info);
-    void addPendingRecompile(JSContext* cx, JSScript* script);
-
-    void processPendingRecompiles(FreeOp* fop, RecompileInfoVector& recompiles);
-
-    void setSweepingTypes(bool sweeping) {
-        MOZ_RELEASE_ASSERT(sweepingTypes != sweeping);
-        sweepingTypes = sweeping;
-    }
-
-    mozilla::Maybe<IonCompilationId> currentCompilationId() const {
-        return currentCompilationId_.ref();
-    }
-    mozilla::Maybe<IonCompilationId>& currentCompilationIdRef() {
-        return currentCompilationId_.ref();
-    }
-};
-
-enum SpewChannel {
-    ISpewOps,      /* ops: New constraints and types. */
-    ISpewResult,   /* result: Final type sets. */
-    SPEW_COUNT
-};
-
-#ifdef DEBUG
-
-bool InferSpewActive(SpewChannel channel);
-const char * InferSpewColorReset();
-const char * InferSpewColor(TypeConstraint* constraint);
-const char * InferSpewColor(TypeSet* types);
-
-#define InferSpew(channel, ...) if (InferSpewActive(channel)) { InferSpewImpl(__VA_ARGS__); } else {}
-void InferSpewImpl(const char* fmt, ...) MOZ_FORMAT_PRINTF(1, 2);
-
-/* Check that the type property for id in group contains value. */
-bool ObjectGroupHasProperty(JSContext* cx, ObjectGroup* group, jsid id, const Value& value);
-
-#else
-
-inline const char * InferSpewColorReset() { return nullptr; }
-inline const char * InferSpewColor(TypeConstraint* constraint) { return nullptr; }
-inline const char * InferSpewColor(TypeSet* types) { return nullptr; }
-
-#define InferSpew(channel, ...) do {} while (0)
-
-#endif
-
-// Prints type information for a context if spew is enabled or force is set.
-void
-PrintTypes(JSContext* cx, JS::Compartment* comp, bool force);
-
 } /* namespace js */
 
-// JS::ubi::Nodes can point to object groups; they're js::gc::Cell instances
-// with no associated compartment.
-namespace JS {
-namespace ubi {
-
-template<>
-class Concrete<js::ObjectGroup> : TracerConcrete<js::ObjectGroup> {
-  protected:
-    explicit Concrete(js::ObjectGroup *ptr) : TracerConcrete<js::ObjectGroup>(ptr) { }
-
-  public:
-    static void construct(void *storage, js::ObjectGroup *ptr) { new (storage) Concrete(ptr); }
-
-    Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
-
-    const char16_t* typeName() const override { return concreteTypeName; }
-    static const char16_t concreteTypeName[];
-};
-
-} // namespace ubi
-} // namespace JS
-
-#endif /* vm_TypeInference_h */
+#endif /* vm_TypeSet_h */
--- a/js/src/vm/UnboxedObject-inl.h
+++ b/js/src/vm/UnboxedObject-inl.h
@@ -4,18 +4,19 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef vm_UnboxedObject_inl_h
 #define vm_UnboxedObject_inl_h
 
 #include "vm/UnboxedObject.h"
 
+#include "vm/TypeInference.h"
+
 #include "gc/StoreBuffer-inl.h"
-#include "vm/ArrayObject-inl.h"
 #include "vm/NativeObject-inl.h"
 
 namespace js {
 
 /////////////////////////////////////////////////////////////////////
 // UnboxedPlainObject
 /////////////////////////////////////////////////////////////////////
 
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -13,16 +13,17 @@
 #include "jit/ExecutableAllocator.h"
 #include "jit/JitCommon.h"
 #include "jit/Linker.h"
 
 #include "gc/Nursery-inl.h"
 #include "jit/MacroAssembler-inl.h"
 #include "vm/JSObject-inl.h"
 #include "vm/Shape-inl.h"
+#include "vm/TypeInference-inl.h"
 
 using mozilla::ArrayLength;
 using mozilla::PodCopy;
 
 using namespace js;
 
 /////////////////////////////////////////////////////////////////////
 // UnboxedLayout
--- a/js/src/vm/UnboxedObject.h
+++ b/js/src/vm/UnboxedObject.h
@@ -8,16 +8,19 @@
 #define vm_UnboxedObject_h
 
 #include "gc/DeletePolicy.h"
 #include "vm/JSObject.h"
 #include "vm/Runtime.h"
 
 namespace js {
 
+struct AutoEnterAnalysis;
+class PreliminaryObjectArray;
+
 // Memory required for an unboxed value of a given type. Returns zero for types
 // which can't be used for unboxed objects.
 static inline size_t
 UnboxedTypeSize(JSValueType type)
 {
     switch (type) {
       case JSVAL_TYPE_BOOLEAN: return 1;
       case JSVAL_TYPE_INT32:   return 4;
@@ -39,95 +42,81 @@ UnboxedTypeNeedsPostBarrier(JSValueType 
 {
     return type == JSVAL_TYPE_STRING || type == JSVAL_TYPE_OBJECT;
 }
 
 // Class tracking information specific to unboxed objects.
 class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
 {
   public:
-    struct Property {
-        PropertyName* name;
-        uint32_t offset;
-        JSValueType type;
+    struct Property
+    {
+        PropertyName* name = nullptr;
+        uint32_t offset = UINT32_MAX;
+        JSValueType type = JSVAL_TYPE_MAGIC;
 
-        Property()
-          : name(nullptr), offset(UINT32_MAX), type(JSVAL_TYPE_MAGIC)
-        {}
+        Property() = default;
     };
 
-    typedef Vector<Property, 0, SystemAllocPolicy> PropertyVector;
+    using PropertyVector = Vector<Property, 0, SystemAllocPolicy>;
 
   private:
     JS::Zone* zone_;
 
     // If objects in this group have ever been converted to native objects,
     // these store the corresponding native group and initial shape for such
     // objects. Type information for this object is reflected in nativeGroup.
-    GCPtrObjectGroup nativeGroup_;
-    GCPtrShape nativeShape_;
+    GCPtrObjectGroup nativeGroup_ = {};
+    GCPtrShape nativeShape_ = {};
 
     // Any script/pc which the associated group is created for.
-    GCPtrScript allocationScript_;
-    jsbytecode* allocationPc_;
+    GCPtrScript allocationScript_ = {};
+    jsbytecode* allocationPc_ = {};
 
     // If nativeGroup is set and this object originally had a TypeNewScript or
     // was keyed to an allocation site, this points to the group which replaced
     // this one. This link is only needed to keep the replacement group from
     // being GC'ed. If it were GC'ed and a new one regenerated later, that new
     // group might have a different allocation kind from this group.
-    GCPtrObjectGroup replacementGroup_;
+    GCPtrObjectGroup replacementGroup_ = {};
 
     // The following members are only used for unboxed plain objects.
 
     // All properties on objects with this layout, in enumeration order.
     PropertyVector properties_;
 
     // Byte size of the data for objects with this layout.
-    size_t size_;
+    size_t size_ = 0;
 
     // Any 'new' script information associated with this layout.
-    TypeNewScript* newScript_;
+    TypeNewScript* newScript_ = nullptr;
 
     // List for use in tracing objects with this layout. This has the same
     // structure as the trace list on a TypeDescr.
-    int32_t* traceList_;
+    int32_t* traceList_ = nullptr;
 
     // If this layout has been used to construct script or JSON constant
     // objects, this code might be filled in to more quickly fill in objects
     // from an array of values.
-    GCPtrJitCode constructorCode_;
+    GCPtrJitCode constructorCode_ = {};
 
   public:
     explicit UnboxedLayout(JS::Zone* zone)
-      : zone_(zone), nativeGroup_(nullptr), nativeShape_(nullptr),
-        allocationScript_(nullptr), allocationPc_(nullptr), replacementGroup_(nullptr),
-        size_(0), newScript_(nullptr), traceList_(nullptr), constructorCode_(nullptr)
+      : zone_(zone)
     {}
 
+    inline ~UnboxedLayout();
+
     JS::Zone* zone() const { return zone_; }
 
     bool initProperties(const PropertyVector& properties, size_t size) {
         size_ = size;
         return properties_.appendAll(properties);
     }
 
-    ~UnboxedLayout() {
-        if (newScript_) {
-            newScript_->clear();
-        }
-        js_delete(newScript_);
-        js_free(traceList_);
-
-        nativeGroup_.init(nullptr);
-        nativeShape_.init(nullptr);
-        replacementGroup_.init(nullptr);
-        constructorCode_.init(nullptr);
-    }
-
     void detachFromRealm();
 
     const PropertyVector& properties() const {
         return properties_;
     }
 
     TypeNewScript* newScript() const {
         return newScript_;