Bug 1461938 part 36 - Rename ObjectGroupCompartment to ObjectGroupRealm and move to JS::Realm. r=luke
authorJan de Mooij <jdemooij@mozilla.com>
Fri, 25 May 2018 11:12:03 +0200
changeset 419850 12a249851bed14747c7e49f7edabccdf4827fb8e
parent 419849 7fe5ca35982d9509fb9a53ba434a0946c756d9c5
child 419851 b9c8a89ecb9d5e59c3f9073db495b4408db95ede
push id34052
push userccoroiu@mozilla.com
push dateFri, 25 May 2018 17:52:14 +0000
treeherdermozilla-central@94d7f0e1c4d0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1461938
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1461938 part 36 - Rename ObjectGroupCompartment to ObjectGroupRealm and move to JS::Realm. r=luke
js/src/builtin/Array.cpp
js/src/builtin/MapObject.cpp
js/src/builtin/Object.cpp
js/src/gc/GC.cpp
js/src/jit/CacheIR.cpp
js/src/jit/MCallOptimize.cpp
js/src/jit/Recover.cpp
js/src/vm/EnvironmentObject.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/Iteration.cpp
js/src/vm/JSCompartment.cpp
js/src/vm/JSCompartment.h
js/src/vm/JSFunction.cpp
js/src/vm/JSObject-inl.h
js/src/vm/JSObject.cpp
js/src/vm/JSObject.h
js/src/vm/ObjectGroup.cpp
js/src/vm/ObjectGroup.h
js/src/vm/ProxyObject.cpp
js/src/vm/RegExpObject.cpp
js/src/vm/SelfHosting.cpp
js/src/vm/TypeInference.cpp
js/src/vm/UnboxedObject.cpp
--- a/js/src/builtin/Array.cpp
+++ b/js/src/builtin/Array.cpp
@@ -3697,17 +3697,18 @@ CreateArrayPrototype(JSContext* cx, JSPr
     }
 
     /*
      * The default 'new' group of Array.prototype is required by type inference
      * to have unknown properties, to simplify handling of e.g. heterogenous
      * arrays in JSON and script literals and allows setDenseArrayElement to
      * be used without updating the indexed type set for such default arrays.
      */
-    if (!JSObject::setNewGroupUnknown(cx, &ArrayObject::class_, arrayProto))
+    ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
+    if (!JSObject::setNewGroupUnknown(cx, realm, &ArrayObject::class_, arrayProto))
         return nullptr;
 
     return arrayProto;
 }
 
 static bool
 array_proto_finish(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto)
 {
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -371,17 +371,17 @@ MapIteratorObject::next(Handle<MapIterat
 /* static */ JSObject*
 MapIteratorObject::createResultPair(JSContext* cx)
 {
     RootedArrayObject resultPairObj(cx, NewDenseFullyAllocatedArray(cx, 2, nullptr, TenuredObject));
     if (!resultPairObj)
         return nullptr;
 
     Rooted<TaggedProto> proto(cx, resultPairObj->taggedProto());
-    ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, resultPairObj->getClass(), proto);
+    ObjectGroup* group = ObjectGroupRealm::makeGroup(cx, resultPairObj->getClass(), proto);
     if (!group)
         return nullptr;
     resultPairObj->setGroup(group);
 
     resultPairObj->setDenseInitializedLength(2);
     resultPairObj->initDenseElement(0, NullValue());
     resultPairObj->initDenseElement(1, NullValue());
 
@@ -1199,17 +1199,17 @@ SetIteratorObject::next(Handle<SetIterat
 /* static */ JSObject*
 SetIteratorObject::createResult(JSContext* cx)
 {
     RootedArrayObject resultObj(cx, NewDenseFullyAllocatedArray(cx, 1, nullptr, TenuredObject));
     if (!resultObj)
         return nullptr;
 
     Rooted<TaggedProto> proto(cx, resultObj->taggedProto());
-    ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, resultObj->getClass(), proto);
+    ObjectGroup* group = ObjectGroupRealm::makeGroup(cx, resultObj->getClass(), proto);
     if (!group)
         return nullptr;
     resultObj->setGroup(group);
 
     resultObj->setDenseInitializedLength(1);
     resultObj->initDenseElement(0, NullValue());
 
     // See comments in SetIteratorObject::next.
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -2018,17 +2018,18 @@ CreateObjectPrototype(JSContext* cx, JSP
                "should have been able to make a fresh Object.prototype's "
                "[[Prototype]] immutable");
 
     /*
      * The default 'new' type of Object.prototype is required by type inference
      * to have unknown properties, to simplify handling of e.g. heterogenous
      * objects in JSON and script literals.
      */
-    if (!JSObject::setNewGroupUnknown(cx, &PlainObject::class_, objectProto))
+    ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
+    if (!JSObject::setNewGroupUnknown(cx, realm, &PlainObject::class_, objectProto))
         return nullptr;
 
     return objectProto;
 }
 
 static bool
 FinishObjectClassInit(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto)
 {
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -2572,17 +2572,17 @@ GCRuntime::sweepZoneAfterCompacting(Zone
     zone->sweepWeakMaps();
     for (auto* cache : zone->weakCaches())
         cache->sweep();
 
     if (jit::JitZone* jitZone = zone->jitZone())
         jitZone->sweep();
 
     for (RealmsInZoneIter r(zone); !r.done(); r.next()) {
-        r->objectGroups.sweep();
+        r->sweepObjectGroups();
         r->sweepRegExps();
         r->sweepSavedStacks();
         r->sweepVarNames();
         r->sweepGlobalObject();
         r->sweepSelfHostingScriptSource();
         r->sweepDebugEnvironments();
         r->sweepJitRealm();
         r->sweepObjectRealm();
@@ -5419,18 +5419,18 @@ SweepCCWrappers(GCParallelTask* task)
     for (SweepGroupCompartmentsIter c(runtime); !c.done(); c.next())
         c->sweepCrossCompartmentWrappers();
 }
 
 static void
 SweepObjectGroups(GCParallelTask* task)
 {
     JSRuntime* runtime = task->runtime();
-    for (SweepGroupCompartmentsIter c(runtime); !c.done(); c.next())
-        c->objectGroups.sweep();
+    for (SweepGroupRealmsIter r(runtime); !r.done(); r.next())
+        r->sweepObjectGroups();
 }
 
 static void
 SweepMisc(GCParallelTask* task)
 {
     JSRuntime* runtime = task->runtime();
     for (SweepGroupRealmsIter r(runtime); !r.done(); r.next()) {
         r->sweepGlobalObject();
@@ -8477,17 +8477,17 @@ js::gc::CheckHashTablesAfterMovingGC(JSR
         JS::AutoCheckCannotGC nogc;
         for (auto baseShape = zone->cellIter<BaseShape>(); !baseShape.done(); baseShape.next()) {
             if (ShapeTable* table = baseShape->maybeTable(nogc))
                 table->checkAfterMovingGC();
         }
     }
 
     for (RealmsIter r(rt, SkipAtoms); !r.done(); r.next()) {
-        r->objectGroups.checkTablesAfterMovingGC();
+        r->checkObjectGroupTablesAfterMovingGC();
         r->dtoaCache.checkCacheAfterMovingGC();
         JS::GetCompartmentForRealm(r)->checkWrapperMapAfterMovingGC();
         r->checkScriptMapsAfterMovingGC();
         if (r->debugEnvs())
             r->debugEnvs()->checkHashTablesAfterMovingGC();
     }
 }
 #endif
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -4401,17 +4401,17 @@ CallIRGenerator::tryAttachStringSplit()
 
     // Just for now: if they're both atoms, then do not optimize using
     // CacheIR and allow the legacy "ConstStringSplit" BaselineIC optimization
     // to proceed.
     if (args_[0].toString()->isAtom() && args_[1].toString()->isAtom())
         return false;
 
     // Get the object group to use for this location.
-    RootedObjectGroup group(cx_, ObjectGroupCompartment::getStringSplitStringGroup(cx_));
+    RootedObjectGroup group(cx_, ObjectGroupRealm::getStringSplitStringGroup(cx_));
     if (!group)
         return false;
 
     AutoAssertNoPendingException aanpe(cx_);
     Int32OperandId argcId(writer.setInputOperandId(0));
 
     // Ensure argc == 1.
     writer.guardSpecificInt32Immediate(argcId, 2);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -1765,17 +1765,17 @@ IonBuilder::inlineStringSplitString(Call
         return InliningStatus_NotInlined;
 
     IonBuilder::InliningStatus resultConstStringSplit;
     MOZ_TRY_VAR(resultConstStringSplit, inlineConstantStringSplitString(callInfo));
     if (resultConstStringSplit != InliningStatus_NotInlined)
         return resultConstStringSplit;
 
     JSContext* cx = TlsContext.get();
-    ObjectGroup* group = ObjectGroupCompartment::getStringSplitStringGroup(cx);
+    ObjectGroup* group = ObjectGroupRealm::getStringSplitStringGroup(cx);
     if (!group)
         return InliningStatus_NotInlined;
     AutoSweepObjectGroup sweep(group);
     if (group->maybePreliminaryObjects(sweep))
         return InliningStatus_NotInlined;
 
     TypeSet::ObjectKey* retKey = TypeSet::ObjectKey::get(group);
     if (retKey->unknownProperties())
--- a/js/src/jit/Recover.cpp
+++ b/js/src/jit/Recover.cpp
@@ -1124,17 +1124,17 @@ MStringSplit::writeRecoverData(CompactBu
 RStringSplit::RStringSplit(CompactBufferReader& reader)
 {}
 
 bool
 RStringSplit::recover(JSContext* cx, SnapshotIterator& iter) const
 {
     RootedString str(cx, iter.read().toString());
     RootedString sep(cx, iter.read().toString());
-    RootedObjectGroup group(cx, ObjectGroupCompartment::getStringSplitStringGroup(cx));
+    RootedObjectGroup group(cx, ObjectGroupRealm::getStringSplitStringGroup(cx));
     if (!group) {
         return false;
     }
     RootedValue result(cx);
 
     JSObject* res = str_split_string(cx, group, str, sep, INT32_MAX);
     if (!res)
         return false;
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -140,17 +140,19 @@ CallObject::create(JSContext* cx, Handle
 
 CallObject*
 CallObject::createSingleton(JSContext* cx, HandleShape shape)
 {
     gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
     MOZ_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_));
     kind = gc::GetBackgroundAllocKind(kind);
 
-    RootedObjectGroup group(cx, ObjectGroup::lazySingletonGroup(cx, &class_, TaggedProto(nullptr)));
+    ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
+    RootedObjectGroup group(cx, ObjectGroup::lazySingletonGroup(cx, realm, &class_,
+                                                                TaggedProto(nullptr)));
     if (!group)
         return nullptr;
 
     JSObject* obj;
     JS_TRY_VAR_OR_RETURN_NULL(cx, obj, NativeObject::create(cx, kind, gc::TenuredHeap, shape, group));
 
     MOZ_ASSERT(obj->isSingleton(),
                "group created inline above must be a singleton");
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -341,20 +341,20 @@ GlobalObject::resolveOffThreadConstructo
         return false;
 
     if (key == JSProto_Object &&
         !JSObject::setFlags(cx, placeholder, BaseShape::IMMUTABLE_PROTOTYPE))
     {
         return false;
     }
 
-    if ((key == JSProto_Object || key == JSProto_Function || key == JSProto_Array) &&
-        !JSObject::setNewGroupUnknown(cx, placeholder->getClass(), placeholder))
-    {
-        return false;
+    if (key == JSProto_Object || key == JSProto_Function || key == JSProto_Array) {
+        ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
+        if (!JSObject::setNewGroupUnknown(cx, realm, placeholder->getClass(), placeholder))
+            return false;
     }
 
     global->setPrototype(key, ObjectValue(*placeholder));
     global->setConstructor(key, MagicValue(JS_OFF_THREAD_CONSTRUCTOR));
     return true;
 }
 
 /* static */ JSObject*
--- a/js/src/vm/Iteration.cpp
+++ b/js/src/vm/Iteration.cpp
@@ -966,18 +966,18 @@ Realm::getOrCreateIterResultTemplateObje
 
     // Create template plain object
     RootedNativeObject templateObject(cx, NewBuiltinClassInstance<PlainObject>(cx, TenuredObject));
     if (!templateObject)
         return iterResultTemplate_; // = nullptr
 
     // Create a new group for the template.
     Rooted<TaggedProto> proto(cx, templateObject->taggedProto());
-    RootedObjectGroup group(cx, ObjectGroupCompartment::makeGroup(cx, templateObject->getClass(),
-                                                                  proto));
+    RootedObjectGroup group(cx, ObjectGroupRealm::makeGroup(cx, templateObject->getClass(),
+                                                            proto));
     if (!group)
         return iterResultTemplate_; // = nullptr
     templateObject->setGroup(group);
 
     // Set dummy `value` property
     if (!NativeDefineDataProperty(cx, templateObject, cx->names().value, UndefinedHandleValue,
                                   JSPROP_ENUMERATE))
     {
--- a/js/src/vm/JSCompartment.cpp
+++ b/js/src/vm/JSCompartment.cpp
@@ -928,26 +928,31 @@ JSCompartment::fixupCrossCompartmentWrap
         comp->sweepCrossCompartmentWrappers();
         // Trace the wrappers in the map to update their cross-compartment edges
         // to wrapped values in other compartments that may have been moved.
         comp->traceOutgoingCrossCompartmentWrappers(trc);
     }
 }
 
 void
+Realm::fixupAfterMovingGC()
+{
+    purge();
+    fixupGlobal();
+    objectGroups_.fixupTablesAfterMovingGC();
+    fixupScriptMapsAfterMovingGC();
+}
+
+void
 JSCompartment::fixupAfterMovingGC()
 {
     MOZ_ASSERT(zone()->isGCCompacting());
 
     Realm* realm = JS::GetRealmForCompartment(this);
-
-    realm->purge();
-    realm->fixupGlobal();
-    objectGroups.fixupTablesAfterMovingGC();
-    realm->fixupScriptMapsAfterMovingGC();
+    realm->fixupAfterMovingGC();
 
     // Sweep the wrapper map to update values (wrapper objects) in this
     // compartment that may have been moved.
     sweepCrossCompartmentWrappers();
 }
 
 void
 Realm::fixupGlobal()
@@ -1030,34 +1035,34 @@ Realm::checkScriptMapsAfterMovingGC()
 }
 #endif
 
 void
 Realm::purge()
 {
     dtoaCache.purge();
     newProxyCache.purge();
-    objectGroups.purge();
+    objectGroups_.purge();
     objects_.iteratorCache.clearAndShrink();
     arraySpeciesLookup.purge();
 }
 
 void
 Realm::clearTables()
 {
     global_.set(nullptr);
 
     // No scripts should have run in this realm. This is used when merging
     // a realm that has been used off thread into another realm and zone.
     JS::GetCompartmentForRealm(this)->assertNoCrossCompartmentWrappers();
     MOZ_ASSERT(!jitRealm_);
     MOZ_ASSERT(!debugEnvs_);
     MOZ_ASSERT(objects_.enumerators->next() == objects_.enumerators);
 
-    objectGroups.clearTables();
+    objectGroups_.clearTables();
     if (savedStacks_.initialized())
         savedStacks_.clear();
     if (varNames_.initialized())
         varNames_.clear();
 }
 
 void
 Realm::setAllocationMetadataBuilder(const js::AllocationMetadataBuilder* builder)
@@ -1366,19 +1371,19 @@ Realm::addSizeOfIncludingThis(mozilla::M
                               size_t* jitRealm,
                               size_t* privateData,
                               size_t* scriptCountsMapArg)
 {
     // This is temporary until Realm and JSCompartment are completely separated.
     JSCompartment::addSizeOfExcludingThis(mallocSizeOf, crossCompartmentWrappersArg);
 
     *realmObject += mallocSizeOf(this);
-    objectGroups.addSizeOfExcludingThis(mallocSizeOf, tiAllocationSiteTables,
-                                        tiArrayTypeTables, tiObjectTypeTables,
-                                        realmTables);
+    objectGroups_.addSizeOfExcludingThis(mallocSizeOf, tiAllocationSiteTables,
+                                         tiArrayTypeTables, tiObjectTypeTables,
+                                         realmTables);
     wasm.addSizeOfExcludingThis(mallocSizeOf, realmTables);
 
     objects_.addSizeOfExcludingThis(mallocSizeOf,
                                     innerViewsArg,
                                     lazyArrayBuffersArg,
                                     objectMetadataTablesArg,
                                     nonSyntacticLexicalEnvironmentsArg);
 
--- a/js/src/vm/JSCompartment.h
+++ b/js/src/vm/JSCompartment.h
@@ -598,19 +598,16 @@ struct JSCompartment
     // instances observing us, if any.
     void chooseAllocationSamplingProbability() { savedStacks_.chooseSamplingProbability(this); }
 
   protected:
     void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                 size_t* crossCompartmentWrappersArg);
 
   public:
-    // Object group tables and other state in the compartment.
-    js::ObjectGroupCompartment   objectGroups;
-
 #ifdef JSGC_HASH_TABLE_CHECKS
     void checkWrapperMapAfterMovingGC();
 #endif
 
     // All unboxed layouts in the compartment.
     mozilla::LinkedList<js::UnboxedLayout> unboxedLayouts;
 
     /*
@@ -785,16 +782,22 @@ class JS::Realm : public JSCompartment
 
     friend struct ::JSContext;
     js::ReadBarrieredGlobalObject global_;
 
     // Note: this is private to enforce use of ObjectRealm::get(obj).
     js::ObjectRealm objects_;
     friend js::ObjectRealm& js::ObjectRealm::get(const JSObject*);
 
+    // Object group tables and other state in the realm. This is private to
+    // enforce use of ObjectGroupRealm::get(group)/getForNewObject(cx).
+    js::ObjectGroupRealm objectGroups_;
+    friend js::ObjectGroupRealm& js::ObjectGroupRealm::get(js::ObjectGroup* group);
+    friend js::ObjectGroupRealm& js::ObjectGroupRealm::getForNewObject(JSContext* cx);
+
     // The global environment record's [[VarNames]] list that contains all
     // names declared using FunctionDeclaration, GeneratorDeclaration, and
     // VariableDeclaration declarations in global code in this realm.
     // Names are only removed from this list by a |delete IdentifierReference|
     // that successfully removes that global property.
     using VarNamesSet = JS::GCHashSet<JSAtom*,
                                       js::DefaultHasher<JSAtom*>,
                                       js::SystemAllocPolicy>;
@@ -986,24 +989,32 @@ class JS::Realm : public JSCompartment
     void finishRoots();
 
     void sweepAfterMinorGC();
     void sweepDebugEnvironments();
     void sweepObjectRealm();
     void sweepSelfHostingScriptSource();
     void sweepTemplateObjects();
 
+    void sweepObjectGroups() {
+        objectGroups_.sweep();
+    }
+
     void clearScriptCounts();
     void clearScriptNames();
 
     void purge();
 
+    void fixupAfterMovingGC();
     void fixupScriptMapsAfterMovingGC();
 
 #ifdef JSGC_HASH_TABLE_CHECKS
+    void checkObjectGroupTablesAfterMovingGC() {
+        objectGroups_.checkTablesAfterMovingGC();
+    }
     void checkScriptMapsAfterMovingGC();
 #endif
 
     // Add a name to [[VarNames]].  Reports OOM on failure.
     MOZ_MUST_USE bool addToVarNames(JSContext* cx, JS::Handle<JSAtom*> name);
     void sweepVarNames();
 
     void removeFromVarNames(JS::Handle<JSAtom*> name) {
--- a/js/src/vm/JSFunction.cpp
+++ b/js/src/vm/JSFunction.cpp
@@ -885,17 +885,18 @@ CreateFunctionPrototype(JSContext* cx, J
 
     protoGroup->setInterpretedFunction(functionProto);
 
     /*
      * The default 'new' group of Function.prototype is required by type
      * inference to have unknown properties, to simplify handling of e.g.
      * NewFunctionClone.
      */
-    if (!JSObject::setNewGroupUnknown(cx, &JSFunction::class_, functionProto))
+    ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
+    if (!JSObject::setNewGroupUnknown(cx, realm, &JSFunction::class_, functionProto))
         return nullptr;
 
     return functionProto;
 }
 
 static const ClassOps JSFunctionClassOps = {
     nullptr,                 /* addProperty */
     nullptr,                 /* delProperty */
--- a/js/src/vm/JSObject-inl.h
+++ b/js/src/vm/JSObject-inl.h
@@ -153,17 +153,18 @@ js::NativeObject::updateDictionaryListPo
         shape()->listp = shapePtr();
 }
 
 /* static */ inline bool
 JSObject::setSingleton(JSContext* cx, js::HandleObject obj)
 {
     MOZ_ASSERT(!IsInsideNursery(obj));
 
-    js::ObjectGroup* group = js::ObjectGroup::lazySingletonGroup(cx, obj->getClass(),
+    js::ObjectGroupRealm& realm = js::ObjectGroupRealm::get(obj->group_);
+    js::ObjectGroup* group = js::ObjectGroup::lazySingletonGroup(cx, realm, obj->getClass(),
                                                                  obj->taggedProto());
     if (!group)
         return false;
 
     obj->group_ = group;
     return true;
 }
 
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -2103,17 +2103,17 @@ SetClassAndProto(JSContext* cx, HandleOb
     RootedObjectGroup oldGroup(cx, obj->group());
 
     ObjectGroup* newGroup;
     if (oldGroup->maybeInterpretedFunction()) {
         // We're changing the group/proto of a scripted function. Create a new
         // group so we can keep track of the interpreted function for Ion
         // inlining.
         MOZ_ASSERT(obj->is<JSFunction>());
-        newGroup = ObjectGroupCompartment::makeGroup(cx, &JSFunction::class_, proto);
+        newGroup = ObjectGroupRealm::makeGroup(cx, &JSFunction::class_, proto);
         if (!newGroup)
             return false;
         newGroup->setInterpretedFunction(oldGroup->maybeInterpretedFunction());
     } else {
         newGroup = ObjectGroup::defaultNewGroup(cx, clasp, proto);
         if (!newGroup)
             return false;
     }
@@ -2139,17 +2139,18 @@ SetClassAndProto(JSContext* cx, HandleOb
 
 /* static */ bool
 JSObject::changeToSingleton(JSContext* cx, HandleObject obj)
 {
     MOZ_ASSERT(!obj->isSingleton());
 
     MarkObjectGroupUnknownProperties(cx, obj->group());
 
-    ObjectGroup* group = ObjectGroup::lazySingletonGroup(cx, obj->getClass(),
+    ObjectGroupRealm& realm = ObjectGroupRealm::get(obj->group());
+    ObjectGroup* group = ObjectGroup::lazySingletonGroup(cx, realm, obj->getClass(),
                                                          obj->taggedProto());
     if (!group)
         return false;
 
     obj->group_ = group;
     return true;
 }
 
--- a/js/src/vm/JSObject.h
+++ b/js/src/vm/JSObject.h
@@ -385,17 +385,18 @@ class JSObject : public js::gc::Cell
         return setFlags(cx, obj, js::BaseShape::ITERATED_SINGLETON);
     }
 
     /*
      * Mark an object as requiring its default 'new' type to have unknown
      * properties.
      */
     inline bool isNewGroupUnknown() const;
-    static bool setNewGroupUnknown(JSContext* cx, const js::Class* clasp, JS::HandleObject obj);
+    static bool setNewGroupUnknown(JSContext* cx, js::ObjectGroupRealm& realm,
+                                   const js::Class* clasp, JS::HandleObject obj);
 
     /* Set a new prototype for an object with a singleton type. */
     static bool splicePrototype(JSContext* cx, js::HandleObject obj, const js::Class* clasp,
                                 js::Handle<js::TaggedProto> proto);
 
     /*
      * For bootstrapping, whether to splice a prototype for Function.prototype
      * or the global object.
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -317,54 +317,55 @@ JSObject::makeLazyGroup(JSContext* cx, H
 
     if (obj->isNative() && obj->as<NativeObject>().isIndexed())
         initialFlags |= OBJECT_FLAG_SPARSE_INDEXES;
 
     if (obj->is<ArrayObject>() && obj->as<ArrayObject>().length() > INT32_MAX)
         initialFlags |= OBJECT_FLAG_LENGTH_OVERFLOW;
 
     Rooted<TaggedProto> proto(cx, obj->taggedProto());
-    ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, obj->getClass(), proto,
-                                                           initialFlags);
+    ObjectGroup* group = ObjectGroupRealm::makeGroup(cx, obj->getClass(), proto,
+                                                     initialFlags);
     if (!group)
         return nullptr;
 
     AutoEnterAnalysis enter(cx);
 
     /* Fill in the type according to the state of this object. */
 
     if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted())
         group->setInterpretedFunction(&obj->as<JSFunction>());
 
     obj->group_ = group;
 
     return group;
 }
 
 /* static */ bool
-JSObject::setNewGroupUnknown(JSContext* cx, const js::Class* clasp, JS::HandleObject obj)
+JSObject::setNewGroupUnknown(JSContext* cx, ObjectGroupRealm& realm, const js::Class* clasp,
+                             JS::HandleObject obj)
 {
-    ObjectGroup::setDefaultNewGroupUnknown(cx, clasp, obj);
+    ObjectGroup::setDefaultNewGroupUnknown(cx, realm, clasp, obj);
     return JSObject::setFlags(cx, obj, BaseShape::NEW_GROUP_UNKNOWN);
 }
 
 /////////////////////////////////////////////////////////////////////
-// ObjectGroupCompartment NewTable
+// ObjectGroupRealm NewTable
 /////////////////////////////////////////////////////////////////////
 
 /*
- * Entries for the per-compartment set of groups which are the default
+ * Entries for the per-realm set of groups which are the default
  * types to use for some prototype. An optional associated object is used which
  * allows multiple groups to be created with the same prototype. The
  * associated object may be a function (for types constructed with 'new') or a
  * type descriptor (for typed objects). These entries are also used for the set
- * of lazy groups in the compartment, which use a null associated object
- * (though there are only a few of these per compartment).
+ * of lazy groups in the realm, which use a null associated object
+ * (though there are only a few of these per realm).
  */
-struct ObjectGroupCompartment::NewEntry
+struct ObjectGroupRealm::NewEntry
 {
     ReadBarrieredObjectGroup group;
 
     // Note: This pointer is only used for equality and does not need a read barrier.
     JSObject* associated;
 
     NewEntry(ObjectGroup* group, JSObject* associated)
       : group(group), associated(associated)
@@ -400,17 +401,17 @@ struct ObjectGroupCompartment::NewEntry
     }
 
     static inline HashNumber hash(const Lookup& lookup) {
         HashNumber hash = MovableCellHasher<TaggedProto>::hash(lookup.proto);
         hash = mozilla::AddToHash(hash, MovableCellHasher<JSObject*>::hash(lookup.associated));
         return mozilla::AddToHash(hash, mozilla::HashGeneric(lookup.clasp));
     }
 
-    static inline bool match(const ObjectGroupCompartment::NewEntry& key, const Lookup& lookup) {
+    static inline bool match(const ObjectGroupRealm::NewEntry& key, const Lookup& lookup) {
         if (lookup.clasp && key.group.unbarrieredGet()->clasp() != lookup.clasp)
             return false;
 
         TaggedProto proto = key.group.unbarrieredGet()->proto();
         if (!MovableCellHasher<TaggedProto>::match(proto, lookup.proto))
             return false;
 
         return MovableCellHasher<JSObject*>::match(key.associated, lookup.associated);
@@ -425,39 +426,51 @@ struct ObjectGroupCompartment::NewEntry
 
     bool operator==(const NewEntry& other) const {
         return group == other.group && associated == other.associated;
     }
 };
 
 namespace js {
 template <>
-struct FallibleHashMethods<ObjectGroupCompartment::NewEntry>
+struct FallibleHashMethods<ObjectGroupRealm::NewEntry>
 {
     template <typename Lookup> static bool hasHash(Lookup&& l) {
-        return ObjectGroupCompartment::NewEntry::hasHash(mozilla::Forward<Lookup>(l));
+        return ObjectGroupRealm::NewEntry::hasHash(mozilla::Forward<Lookup>(l));
     }
     template <typename Lookup> static bool ensureHash(Lookup&& l) {
-        return ObjectGroupCompartment::NewEntry::ensureHash(mozilla::Forward<Lookup>(l));
+        return ObjectGroupRealm::NewEntry::ensureHash(mozilla::Forward<Lookup>(l));
     }
 };
 } // namespace js
 
-class ObjectGroupCompartment::NewTable : public JS::WeakCache<js::GCHashSet<NewEntry, NewEntry,
+class ObjectGroupRealm::NewTable : public JS::WeakCache<js::GCHashSet<NewEntry, NewEntry,
                                                                             SystemAllocPolicy>>
 {
     using Table = js::GCHashSet<NewEntry, NewEntry, SystemAllocPolicy>;
     using Base = JS::WeakCache<Table>;
 
   public:
     explicit NewTable(Zone* zone) : Base(zone) {}
 };
 
+/* static*/ ObjectGroupRealm&
+ObjectGroupRealm::get(ObjectGroup* group)
+{
+    return group->realm()->objectGroups_;
+}
+
+/* static*/ ObjectGroupRealm&
+ObjectGroupRealm::getForNewObject(JSContext* cx)
+{
+    return cx->realm()->objectGroups_;
+}
+
 MOZ_ALWAYS_INLINE ObjectGroup*
-ObjectGroupCompartment::DefaultNewGroupCache::lookup(const Class* clasp, TaggedProto proto,
+ObjectGroupRealm::DefaultNewGroupCache::lookup(const Class* clasp, TaggedProto proto,
                                                      JSObject* associated)
 {
     if (group_ &&
         associated_ == associated &&
         group_->proto() == proto &&
         (!clasp || group_->clasp() == clasp))
     {
         return group_;
@@ -498,27 +511,27 @@ ObjectGroup::defaultNewGroup(JSContext* 
         } else {
             associated = nullptr;
         }
 
         if (!associated)
             clasp = &PlainObject::class_;
     }
 
-    ObjectGroupCompartment& groups = cx->compartment()->objectGroups;
+    ObjectGroupRealm& groups = ObjectGroupRealm::getForNewObject(cx);
 
     if (ObjectGroup* group = groups.defaultNewGroupCache.lookup(clasp, proto, associated))
         return group;
 
     AutoEnterAnalysis enter(cx);
 
-    ObjectGroupCompartment::NewTable*& table = groups.defaultNewTable;
+    ObjectGroupRealm::NewTable*& table = groups.defaultNewTable;
 
     if (!table) {
-        table = cx->new_<ObjectGroupCompartment::NewTable>(cx->zone());
+        table = cx->new_<ObjectGroupRealm::NewTable>(cx->zone());
         if (!table || !table->init()) {
             js_delete(table);
             table = nullptr;
             ReportOutOfMemory(cx);
             return nullptr;
         }
     }
 
@@ -540,39 +553,39 @@ ObjectGroup::defaultNewGroup(JSContext* 
             if (protoObj->hasUncacheableProto()) {
                 HandleNativeObject nobj = protoObj.as<NativeObject>();
                 if (!NativeObject::clearFlag(cx, nobj, BaseShape::UNCACHEABLE_PROTO))
                     return nullptr;
             }
         }
     }
 
-    ObjectGroupCompartment::NewTable::AddPtr p =
-        table->lookupForAdd(ObjectGroupCompartment::NewEntry::Lookup(clasp, proto, associated));
+    ObjectGroupRealm::NewTable::AddPtr p =
+        table->lookupForAdd(ObjectGroupRealm::NewEntry::Lookup(clasp, proto, associated));
     if (p) {
         ObjectGroup* group = p->group;
         MOZ_ASSERT_IF(clasp, group->clasp() == clasp);
         MOZ_ASSERT_IF(!clasp, group->clasp() == &PlainObject::class_ ||
                               group->clasp() == &UnboxedPlainObject::class_);
         MOZ_ASSERT(group->proto() == proto);
         groups.defaultNewGroupCache.put(group, associated);
         return group;
     }
 
     ObjectGroupFlags initialFlags = 0;
     if (proto.isDynamic() || (proto.isObject() && proto.toObject()->isNewGroupUnknown()))
         initialFlags = OBJECT_FLAG_DYNAMIC_MASK;
 
     Rooted<TaggedProto> protoRoot(cx, proto);
-    ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, clasp ? clasp : &PlainObject::class_,
-                                                           protoRoot, initialFlags);
+    ObjectGroup* group = ObjectGroupRealm::makeGroup(cx, clasp ? clasp : &PlainObject::class_,
+                                                     protoRoot, initialFlags);
     if (!group)
         return nullptr;
 
-    if (!table->add(p, ObjectGroupCompartment::NewEntry(group, associated))) {
+    if (!table->add(p, ObjectGroupRealm::NewEntry(group, associated))) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
     if (associated) {
         if (associated->is<JSFunction>()) {
             if (!TypeNewScript::make(cx, group, &associated->as<JSFunction>()))
                 return nullptr;
@@ -600,80 +613,82 @@ ObjectGroup::defaultNewGroup(JSContext* 
         AddTypePropertyId(cx, group, nullptr, NameToId(names.columnNumber), TypeSet::Int32Type());
     }
 
     groups.defaultNewGroupCache.put(group, associated);
     return group;
 }
 
 /* static */ ObjectGroup*
-ObjectGroup::lazySingletonGroup(JSContext* cx, const Class* clasp, TaggedProto proto)
+ObjectGroup::lazySingletonGroup(JSContext* cx, ObjectGroupRealm& realm, const Class* clasp,
+                                TaggedProto proto)
 {
     MOZ_ASSERT_IF(proto.isObject(), cx->compartment() == proto.toObject()->compartment());
 
-    ObjectGroupCompartment::NewTable*& table = cx->compartment()->objectGroups.lazyTable;
+    ObjectGroupRealm::NewTable*& table = realm.lazyTable;
 
     if (!table) {
-        table = cx->new_<ObjectGroupCompartment::NewTable>(cx->zone());
+        table = cx->new_<ObjectGroupRealm::NewTable>(cx->zone());
         if (!table || !table->init()) {
             ReportOutOfMemory(cx);
             js_delete(table);
             table = nullptr;
             return nullptr;
         }
     }
 
-    ObjectGroupCompartment::NewTable::AddPtr p =
-        table->lookupForAdd(ObjectGroupCompartment::NewEntry::Lookup(clasp, proto, nullptr));
+    ObjectGroupRealm::NewTable::AddPtr p =
+        table->lookupForAdd(ObjectGroupRealm::NewEntry::Lookup(clasp, proto, nullptr));
     if (p) {
         ObjectGroup* group = p->group;
         MOZ_ASSERT(group->lazy());
 
         return group;
     }
 
     AutoEnterAnalysis enter(cx);
 
     Rooted<TaggedProto> protoRoot(cx, proto);
     ObjectGroup* group =
-        ObjectGroupCompartment::makeGroup(cx, clasp, protoRoot,
-                                          OBJECT_FLAG_SINGLETON | OBJECT_FLAG_LAZY_SINGLETON);
+        ObjectGroupRealm::makeGroup(cx, clasp, protoRoot,
+                                    OBJECT_FLAG_SINGLETON | OBJECT_FLAG_LAZY_SINGLETON);
     if (!group)
         return nullptr;
 
-    if (!table->add(p, ObjectGroupCompartment::NewEntry(group, nullptr))) {
+    if (!table->add(p, ObjectGroupRealm::NewEntry(group, nullptr))) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
     return group;
 }
 
 /* static */ void
-ObjectGroup::setDefaultNewGroupUnknown(JSContext* cx, const Class* clasp, HandleObject obj)
+ObjectGroup::setDefaultNewGroupUnknown(JSContext* cx, ObjectGroupRealm& realm, const Class* clasp,
+                                       HandleObject obj)
 {
     // If the object already has a new group, mark that group as unknown.
-    ObjectGroupCompartment::NewTable* table = cx->compartment()->objectGroups.defaultNewTable;
+    ObjectGroupRealm::NewTable* table = realm.defaultNewTable;
     if (table) {
         Rooted<TaggedProto> taggedProto(cx, TaggedProto(obj));
-        auto lookup = ObjectGroupCompartment::NewEntry::Lookup(clasp, taggedProto, nullptr);
+        auto lookup = ObjectGroupRealm::NewEntry::Lookup(clasp, taggedProto, nullptr);
         auto p = table->lookup(lookup);
         if (p)
             MarkObjectGroupUnknownProperties(cx, p->group);
     }
 }
 
 #ifdef DEBUG
 /* static */ bool
 ObjectGroup::hasDefaultNewGroup(JSObject* proto, const Class* clasp, ObjectGroup* group)
 {
-    ObjectGroupCompartment::NewTable* table = proto->compartment()->objectGroups.defaultNewTable;
+    ObjectGroupRealm::NewTable* table = ObjectGroupRealm::get(group).defaultNewTable;
 
     if (table) {
-        auto lookup = ObjectGroupCompartment::NewEntry::Lookup(clasp, TaggedProto(proto), nullptr);
+        auto lookup = ObjectGroupRealm::NewEntry::Lookup(clasp, TaggedProto(proto), nullptr);
         auto p = table->lookup(lookup);
         return p && p->group == group;
     }
     return false;
 }
 #endif /* DEBUG */
 
 inline const Class*
@@ -730,20 +745,20 @@ ObjectGroup::defaultNewGroup(JSContext* 
         proto = GlobalObject::getOrCreatePrototype(cx, key);
         if (!proto)
             return nullptr;
     }
     return defaultNewGroup(cx, GetClassForProtoKey(key), TaggedProto(proto));
 }
 
 /////////////////////////////////////////////////////////////////////
-// ObjectGroupCompartment ArrayObjectTable
+// ObjectGroupRealm ArrayObjectTable
 /////////////////////////////////////////////////////////////////////
 
-struct ObjectGroupCompartment::ArrayObjectKey : public DefaultHasher<ArrayObjectKey>
+struct ObjectGroupRealm::ArrayObjectKey : public DefaultHasher<ArrayObjectKey>
 {
     TypeSet::Type type;
 
     ArrayObjectKey()
       : type(TypeSet::UndefinedType())
     {}
 
     explicit ArrayObjectKey(TypeSet::Type type)
@@ -828,47 +843,47 @@ ObjectGroup::newArrayObject(JSContext* c
                 } else {
                     elementType = TypeSet::UnknownType();
                     break;
                 }
             }
         }
     }
 
-    ObjectGroupCompartment::ArrayObjectTable*& table =
-        cx->compartment()->objectGroups.arrayObjectTable;
+    ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
+    ObjectGroupRealm::ArrayObjectTable*& table = realm.arrayObjectTable;
 
     if (!table) {
-        table = cx->new_<ObjectGroupCompartment::ArrayObjectTable>();
+        table = cx->new_<ObjectGroupRealm::ArrayObjectTable>();
         if (!table || !table->init()) {
             ReportOutOfMemory(cx);
             js_delete(table);
             table = nullptr;
             return nullptr;
         }
     }
 
-    ObjectGroupCompartment::ArrayObjectKey key(elementType);
-    DependentAddPtr<ObjectGroupCompartment::ArrayObjectTable> p(cx, *table, key);
+    ObjectGroupRealm::ArrayObjectKey key(elementType);
+    DependentAddPtr<ObjectGroupRealm::ArrayObjectTable> p(cx, *table, key);
 
     RootedObjectGroup group(cx);
     if (p) {
         group = p->value();
     } else {
         JSObject* proto = GlobalObject::getOrCreateArrayPrototype(cx, cx->global());
         if (!proto)
             return nullptr;
         Rooted<TaggedProto> taggedProto(cx, TaggedProto(proto));
-        group = ObjectGroupCompartment::makeGroup(cx, &ArrayObject::class_, taggedProto);
+        group = ObjectGroupRealm::makeGroup(cx, &ArrayObject::class_, taggedProto);
         if (!group)
             return nullptr;
 
         AddTypePropertyId(cx, group, nullptr, JSID_VOID, elementType);
 
-        if (!p.add(cx, *table, ObjectGroupCompartment::ArrayObjectKey(elementType), group))
+        if (!p.add(cx, *table, ObjectGroupRealm::ArrayObjectKey(elementType), group))
             return nullptr;
     }
 
     // The type of the elements being added will already be reflected in type
     // information.
     ShouldUpdateTypes updateTypes = ShouldUpdateTypes::DontUpdate;
     return NewCopiedArrayTryUseGroup(cx, group, vp, length, newKind, updateTypes);
 }
@@ -1036,20 +1051,20 @@ js::CombinePlainObjectPropertyTypes(JSCo
             }
         }
     }
 
     return true;
 }
 
 /////////////////////////////////////////////////////////////////////
-// ObjectGroupCompartment PlainObjectTable
+// ObjectGroupRealm PlainObjectTable
 /////////////////////////////////////////////////////////////////////
 
-struct ObjectGroupCompartment::PlainObjectKey
+struct ObjectGroupRealm::PlainObjectKey
 {
     jsid* properties;
     uint32_t nproperties;
 
     struct Lookup {
         IdValuePair* properties;
         uint32_t nproperties;
 
@@ -1077,17 +1092,17 @@ struct ObjectGroupCompartment::PlainObje
         for (unsigned i = 0; i < nproperties; i++) {
             if (gc::IsAboutToBeFinalizedUnbarriered(&properties[i]))
                 return true;
         }
         return false;
     }
 };
 
-struct ObjectGroupCompartment::PlainObjectEntry
+struct ObjectGroupRealm::PlainObjectEntry
 {
     ReadBarrieredObjectGroup group;
     ReadBarrieredShape shape;
     TypeSet::Type* types;
 
     bool needsSweep(unsigned nproperties) {
         if (IsAboutToBeFinalized(&group))
             return true;
@@ -1151,43 +1166,43 @@ js::NewPlainObjectWithProperties(JSConte
 /* static */ JSObject*
 ObjectGroup::newPlainObject(JSContext* cx, IdValuePair* properties, size_t nproperties,
                             NewObjectKind newKind)
 {
     // Watch for simple cases where we don't try to reuse plain object groups.
     if (newKind == SingletonObject || nproperties == 0 || nproperties >= PropertyTree::MAX_HEIGHT)
         return NewPlainObjectWithProperties(cx, properties, nproperties, newKind);
 
-    ObjectGroupCompartment::PlainObjectTable*& table =
-        cx->compartment()->objectGroups.plainObjectTable;
+    ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
+    ObjectGroupRealm::PlainObjectTable*& table = realm.plainObjectTable;
 
     if (!table) {
-        table = cx->new_<ObjectGroupCompartment::PlainObjectTable>();
+        table = cx->new_<ObjectGroupRealm::PlainObjectTable>();
         if (!table || !table->init()) {
             ReportOutOfMemory(cx);
             js_delete(table);
             table = nullptr;
             return nullptr;
         }
     }
 
-    ObjectGroupCompartment::PlainObjectKey::Lookup lookup(properties, nproperties);
-    ObjectGroupCompartment::PlainObjectTable::Ptr p = table->lookup(lookup);
+    ObjectGroupRealm::PlainObjectKey::Lookup lookup(properties, nproperties);
+    ObjectGroupRealm::PlainObjectTable::Ptr p = table->lookup(lookup);
 
     if (!p) {
         if (!CanShareObjectGroup(properties, nproperties))
             return NewPlainObjectWithProperties(cx, properties, nproperties, newKind);
 
         JSObject* proto = GlobalObject::getOrCreatePrototype(cx, JSProto_Object);
         if (!proto)
             return nullptr;
 
         Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
-        RootedObjectGroup group(cx, ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_,
-                                                                      tagged));
+        RootedObjectGroup group(cx, ObjectGroupRealm::makeGroup(cx, &PlainObject::class_,
+                                                                tagged));
         if (!group)
             return nullptr;
 
         gc::AllocKind allocKind = gc::GetGCObjectKind(nproperties);
         RootedPlainObject obj(cx, NewObjectWithGroup<PlainObject>(cx, group,
                                                                   allocKind, TenuredObject));
         if (!obj || !AddPlainObjectProperties(cx, obj, properties, nproperties))
             return nullptr;
@@ -1229,27 +1244,27 @@ ObjectGroup::newPlainObject(JSContext* c
         }
 
         for (size_t i = 0; i < nproperties; i++) {
             ids[i] = properties[i].id;
             types[i] = GetValueTypeForTable(obj->getSlot(i));
             AddTypePropertyId(cx, group, nullptr, IdToTypeId(ids[i]), types[i]);
         }
 
-        ObjectGroupCompartment::PlainObjectKey key;
+        ObjectGroupRealm::PlainObjectKey key;
         key.properties = ids;
         key.nproperties = nproperties;
-        MOZ_ASSERT(ObjectGroupCompartment::PlainObjectKey::match(key, lookup));
+        MOZ_ASSERT(ObjectGroupRealm::PlainObjectKey::match(key, lookup));
 
-        ObjectGroupCompartment::PlainObjectEntry entry;
+        ObjectGroupRealm::PlainObjectEntry entry;
         entry.group.set(group);
         entry.shape.set(obj->lastProperty());
         entry.types = types;
 
-        ObjectGroupCompartment::PlainObjectTable::AddPtr np = table->lookupForAdd(lookup);
+        ObjectGroupRealm::PlainObjectTable::AddPtr np = table->lookupForAdd(lookup);
         if (!table->add(np, key, entry)) {
             ReportOutOfMemory(cx);
             return nullptr;
         }
 
         ids.forget();
         types.forget();
 
@@ -1318,20 +1333,20 @@ ObjectGroup::newPlainObject(JSContext* c
         group->maybePreliminaryObjects(*sweep)->registerNewObject(obj);
         group->maybePreliminaryObjects(*sweep)->maybeAnalyze(cx, group);
     }
 
     return obj;
 }
 
 /////////////////////////////////////////////////////////////////////
-// ObjectGroupCompartment AllocationSiteTable
+// ObjectGroupRealm AllocationSiteTable
 /////////////////////////////////////////////////////////////////////
 
-struct ObjectGroupCompartment::AllocationSiteKey : public DefaultHasher<AllocationSiteKey> {
+struct ObjectGroupRealm::AllocationSiteKey : public DefaultHasher<AllocationSiteKey> {
     ReadBarrieredScript script;
 
     uint32_t offset : 24;
     JSProtoKey kind : 8;
 
     ReadBarrieredObject proto;
 
     static const uint32_t OFFSET_LIMIT = (1 << 23);
@@ -1389,17 +1404,17 @@ struct ObjectGroupCompartment::Allocatio
     bool operator==(const AllocationSiteKey& other) const {
         return script == other.script &&
                offset == other.offset &&
                kind == other.kind &&
                proto == other.proto;
     }
 };
 
-class ObjectGroupCompartment::AllocationSiteTable
+class ObjectGroupRealm::AllocationSiteTable
   : public JS::WeakCache<js::GCHashMap<AllocationSiteKey, ReadBarrieredObjectGroup,
                                        AllocationSiteKey, SystemAllocPolicy>>
 {
     using Table = js::GCHashMap<AllocationSiteKey, ReadBarrieredObjectGroup,
                                 AllocationSiteKey, SystemAllocPolicy>;
     using Base = JS::WeakCache<Table>;
 
   public:
@@ -1407,58 +1422,59 @@ class ObjectGroupCompartment::Allocation
 };
 
 /* static */ ObjectGroup*
 ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* scriptArg, jsbytecode* pc,
                                  JSProtoKey kind, HandleObject protoArg /* = nullptr */)
 {
     MOZ_ASSERT(!useSingletonForAllocationSite(scriptArg, pc, kind));
     MOZ_ASSERT_IF(protoArg, kind == JSProto_Array);
+    MOZ_ASSERT(cx->realm() == scriptArg->realm());
 
     uint32_t offset = scriptArg->pcToOffset(pc);
 
-    if (offset >= ObjectGroupCompartment::AllocationSiteKey::OFFSET_LIMIT) {
+    if (offset >= ObjectGroupRealm::AllocationSiteKey::OFFSET_LIMIT) {
         if (protoArg)
             return defaultNewGroup(cx, GetClassForProtoKey(kind), TaggedProto(protoArg));
         return defaultNewGroup(cx, kind);
     }
 
-    ObjectGroupCompartment::AllocationSiteTable*& table =
-        cx->compartment()->objectGroups.allocationSiteTable;
+    ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
+    ObjectGroupRealm::AllocationSiteTable*& table = realm.allocationSiteTable;
 
     if (!table) {
-        table = cx->new_<ObjectGroupCompartment::AllocationSiteTable>(cx->zone());
+        table = cx->new_<ObjectGroupRealm::AllocationSiteTable>(cx->zone());
         if (!table || !table->init()) {
             ReportOutOfMemory(cx);
             js_delete(table);
             table = nullptr;
             return nullptr;
         }
     }
 
     RootedScript script(cx, scriptArg);
     JSObject* proto = protoArg;
     if (!proto && kind != JSProto_Null) {
         proto = GlobalObject::getOrCreatePrototype(cx, kind);
         if (!proto)
             return nullptr;
     }
 
-    Rooted<ObjectGroupCompartment::AllocationSiteKey> key(cx,
-        ObjectGroupCompartment::AllocationSiteKey(script, offset, kind, proto));
+    Rooted<ObjectGroupRealm::AllocationSiteKey> key(cx,
+        ObjectGroupRealm::AllocationSiteKey(script, offset, kind, proto));
 
-    ObjectGroupCompartment::AllocationSiteTable::AddPtr p = table->lookupForAdd(key);
+    ObjectGroupRealm::AllocationSiteTable::AddPtr p = table->lookupForAdd(key);
     if (p)
         return p->value();
 
     AutoEnterAnalysis enter(cx);
 
     Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
-    ObjectGroup* res = ObjectGroupCompartment::makeGroup(cx, GetClassForProtoKey(kind), tagged,
-                                                         OBJECT_FLAG_FROM_ALLOCATION_SITE);
+    ObjectGroup* res = ObjectGroupRealm::makeGroup(cx, GetClassForProtoKey(kind), tagged,
+                                                   OBJECT_FLAG_FROM_ALLOCATION_SITE);
     if (!res)
         return nullptr;
 
     if (JSOp(*pc) == JSOP_NEWOBJECT) {
         // Keep track of the preliminary objects with this group, so we can try
         // to use an unboxed layout for the object once some are allocated.
         Shape* shape = script->getObject(pc)->as<PlainObject>().lastProperty();
         if (!shape->isEmptyShape()) {
@@ -1475,19 +1491,21 @@ ObjectGroup::allocationSiteGroup(JSConte
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
     return res;
 }
 
 void
-ObjectGroupCompartment::replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc,
-                                                   JSProtoKey kind, ObjectGroup* group)
+ObjectGroupRealm::replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc,
+                                             JSProtoKey kind, ObjectGroup* group)
 {
+    MOZ_ASSERT(script->realm() == group->realm());
+
     AllocationSiteKey key(script, script->pcToOffset(pc), kind, group->proto().toObjectOrNull());
 
     AllocationSiteTable::Ptr p = allocationSiteTable->lookup(key);
     MOZ_RELEASE_ASSERT(p);
     allocationSiteTable->remove(p);
     {
         AutoEnterOOMUnsafeRegion oomUnsafe;
         if (!allocationSiteTable->putNew(key, group))
@@ -1585,63 +1603,63 @@ ObjectGroup::getCopyOnWriteObject(JSScri
 
 /* static */ bool
 ObjectGroup::findAllocationSite(JSContext* cx, ObjectGroup* group,
                                 JSScript** script, uint32_t* offset)
 {
     *script = nullptr;
     *offset = 0;
 
-    const ObjectGroupCompartment::AllocationSiteTable* table =
-        cx->compartment()->objectGroups.allocationSiteTable;
+    ObjectGroupRealm& realm = ObjectGroupRealm::get(group);
+    const ObjectGroupRealm::AllocationSiteTable* table = realm.allocationSiteTable;
 
     if (!table)
         return false;
 
-    for (ObjectGroupCompartment::AllocationSiteTable::Range r = table->all();
+    for (ObjectGroupRealm::AllocationSiteTable::Range r = table->all();
          !r.empty();
          r.popFront())
     {
         if (group == r.front().value()) {
             *script = r.front().key().script;
             *offset = r.front().key().offset;
             return true;
         }
     }
 
     return false;
 }
 
 /////////////////////////////////////////////////////////////////////
-// ObjectGroupCompartment
+// ObjectGroupRealm
 /////////////////////////////////////////////////////////////////////
 
-ObjectGroupCompartment::~ObjectGroupCompartment()
+ObjectGroupRealm::~ObjectGroupRealm()
 {
     js_delete(defaultNewTable);
     js_delete(lazyTable);
     js_delete(arrayObjectTable);
     js_delete(plainObjectTable);
     js_delete(allocationSiteTable);
     stringSplitStringGroup = nullptr;
 }
 
 void
-ObjectGroupCompartment::removeDefaultNewGroup(const Class* clasp, TaggedProto proto,
+ObjectGroupRealm::removeDefaultNewGroup(const Class* clasp, TaggedProto proto,
                                               JSObject* associated)
 {
     auto p = defaultNewTable->lookup(NewEntry::Lookup(clasp, proto, associated));
     MOZ_RELEASE_ASSERT(p);
 
     defaultNewTable->remove(p);
     defaultNewGroupCache.purge();
 }
 
 void
-ObjectGroupCompartment::replaceDefaultNewGroup(const Class* clasp, TaggedProto proto,
+ObjectGroupRealm::replaceDefaultNewGroup(const Class* clasp, TaggedProto proto,
                                                JSObject* associated, ObjectGroup* group)
 {
     NewEntry::Lookup lookup(clasp, proto, associated);
 
     auto p = defaultNewTable->lookup(lookup);
     MOZ_RELEASE_ASSERT(p);
     defaultNewTable->remove(p);
     defaultNewGroupCache.purge();
@@ -1649,35 +1667,35 @@ ObjectGroupCompartment::replaceDefaultNe
         AutoEnterOOMUnsafeRegion oomUnsafe;
         if (!defaultNewTable->putNew(lookup, NewEntry(group, associated)))
             oomUnsafe.crash("Inconsistent object table");
     }
 }
 
 /* static */
 ObjectGroup*
-ObjectGroupCompartment::makeGroup(JSContext* cx, const Class* clasp,
-                                  Handle<TaggedProto> proto,
-                                  ObjectGroupFlags initialFlags /* = 0 */)
+ObjectGroupRealm::makeGroup(JSContext* cx, const Class* clasp,
+                            Handle<TaggedProto> proto,
+                            ObjectGroupFlags initialFlags /* = 0 */)
 {
     MOZ_ASSERT_IF(proto.isObject(), cx->isInsideCurrentCompartment(proto.toObject()));
 
     ObjectGroup* group = Allocate<ObjectGroup>(cx);
     if (!group)
         return nullptr;
     new(group) ObjectGroup(clasp, proto, cx->realm(), initialFlags);
 
     return group;
 }
 
 /* static */
 ObjectGroup*
-ObjectGroupCompartment::getStringSplitStringGroup(JSContext* cx)
+ObjectGroupRealm::getStringSplitStringGroup(JSContext* cx)
 {
-    ObjectGroupCompartment& groups = cx->compartment()->objectGroups;
+    ObjectGroupRealm& groups = ObjectGroupRealm::getForNewObject(cx);
 
     ObjectGroup* group = groups.stringSplitStringGroup.get();
     if (group) {
         return group;
     }
 
     // The following code is a specialized version of the code
     // for ObjectGroup::allocationSiteGroup().
@@ -1693,21 +1711,21 @@ ObjectGroupCompartment::getStringSplitSt
     if (!group)
         return nullptr;
 
     groups.stringSplitStringGroup.set(group);
     return group;
 }
 
 void
-ObjectGroupCompartment::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
+ObjectGroupRealm::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                                size_t* allocationSiteTables,
                                                size_t* arrayObjectGroupTables,
                                                size_t* plainObjectGroupTables,
-                                               size_t* compartmentTables)
+                                               size_t* realmTables)
 {
     if (allocationSiteTable)
         *allocationSiteTables += allocationSiteTable->sizeOfIncludingThis(mallocSizeOf);
 
     if (arrayObjectTable)
         *arrayObjectGroupTables += arrayObjectTable->sizeOfIncludingThis(mallocSizeOf);
 
     if (plainObjectTable) {
@@ -1721,24 +1739,24 @@ ObjectGroupCompartment::addSizeOfExcludi
             const PlainObjectEntry& value = e.front().value();
 
             /* key.ids and values.types have the same length. */
             *plainObjectGroupTables += mallocSizeOf(key.properties) + mallocSizeOf(value.types);
         }
     }
 
     if (defaultNewTable)
-        *compartmentTables += defaultNewTable->sizeOfIncludingThis(mallocSizeOf);
+        *realmTables += defaultNewTable->sizeOfIncludingThis(mallocSizeOf);
 
     if (lazyTable)
-        *compartmentTables += lazyTable->sizeOfIncludingThis(mallocSizeOf);
+        *realmTables += lazyTable->sizeOfIncludingThis(mallocSizeOf);
 }
 
 void
-ObjectGroupCompartment::clearTables()
+ObjectGroupRealm::clearTables()
 {
     if (allocationSiteTable && allocationSiteTable->initialized())
         allocationSiteTable->clear();
     if (arrayObjectTable && arrayObjectTable->initialized())
         arrayObjectTable->clear();
     if (plainObjectTable && plainObjectTable->initialized()) {
         for (PlainObjectTable::Enum e(*plainObjectTable); !e.empty(); e.popFront()) {
             const PlainObjectKey& key = e.front().key();
@@ -1751,28 +1769,28 @@ ObjectGroupCompartment::clearTables()
     if (defaultNewTable && defaultNewTable->initialized())
         defaultNewTable->clear();
     if (lazyTable && lazyTable->initialized())
         lazyTable->clear();
     defaultNewGroupCache.purge();
 }
 
 /* static */ bool
-ObjectGroupCompartment::PlainObjectTableSweepPolicy::needsSweep(PlainObjectKey* key,
-                                                                PlainObjectEntry* entry)
+ObjectGroupRealm::PlainObjectTableSweepPolicy::needsSweep(PlainObjectKey* key,
+                                                          PlainObjectEntry* entry)
 {
     if (!(JS::GCPolicy<PlainObjectKey>::needsSweep(key) || entry->needsSweep(key->nproperties)))
         return false;
     js_free(key->properties);
     js_free(entry->types);
     return true;
 }
 
 void
-ObjectGroupCompartment::sweep()
+ObjectGroupRealm::sweep()
 {
     /*
      * Iterate through the array/object group tables and remove all entries
      * referencing collected data. These tables only hold weak references.
      */
 
     if (arrayObjectTable)
         arrayObjectTable->sweep();
@@ -1781,17 +1799,17 @@ ObjectGroupCompartment::sweep()
     if (stringSplitStringGroup) {
         if (JS::GCPolicy<ReadBarrieredObjectGroup>::needsSweep(&stringSplitStringGroup)) {
             stringSplitStringGroup = nullptr;
         }
     }
 }
 
 void
-ObjectGroupCompartment::fixupNewTableAfterMovingGC(NewTable* table)
+ObjectGroupRealm::fixupNewTableAfterMovingGC(NewTable* table)
 {
     /*
      * Each entry's hash depends on the object's prototype and we can't tell
      * whether that has been moved or not in sweepNewObjectGroupTable().
      */
     if (table && table->initialized()) {
         for (NewTable::Enum e(*table); !e.empty(); e.popFront()) {
             NewEntry& entry = e.mutableFront();
@@ -1812,17 +1830,17 @@ ObjectGroupCompartment::fixupNewTableAft
                 entry.associated = Forwarded(entry.associated);
         }
     }
 }
 
 #ifdef JSGC_HASH_TABLE_CHECKS
 
 void
-ObjectGroupCompartment::checkNewTableAfterMovingGC(NewTable* table)
+ObjectGroupRealm::checkNewTableAfterMovingGC(NewTable* table)
 {
     /*
      * Assert that nothing points into the nursery or needs to be relocated, and
      * that the hash table entries are discoverable.
      */
     if (!table || !table->initialized())
         return;
 
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -24,16 +24,17 @@ class TypeDescr;
 class UnboxedLayout;
 
 class PreliminaryObjectArrayWithTemplate;
 class TypeNewScript;
 class HeapTypeSet;
 class AutoClearTypeInferenceStateOnOOM;
 class AutoSweepObjectGroup;
 class CompilerConstraintList;
+class ObjectGroupRealm;
 
 namespace gc {
 void MergeCompartments(JSCompartment* source, JSCompartment* target);
 } // namespace gc
 
 /*
  * The NewObjectKind allows an allocation site to specify the type properties
  * and lifetime requirements that must be fixed at allocation time.
@@ -522,31 +523,32 @@ class ObjectGroup : public gc::TenuredCe
     static bool useSingletonForNewObject(JSContext* cx, JSScript* script, jsbytecode* pc);
 
     // Whether to make a singleton object at an allocation site.
     static bool useSingletonForAllocationSite(JSScript* script, jsbytecode* pc,
                                               JSProtoKey key);
     static bool useSingletonForAllocationSite(JSScript* script, jsbytecode* pc,
                                               const Class* clasp);
 
-    // Static accessors for ObjectGroupCompartment NewTable.
+    // Static accessors for ObjectGroupRealm NewTable.
 
     static ObjectGroup* defaultNewGroup(JSContext* cx, const Class* clasp,
                                         TaggedProto proto,
                                         JSObject* associated = nullptr);
-    static ObjectGroup* lazySingletonGroup(JSContext* cx, const Class* clasp,
-                                           TaggedProto proto);
+    static ObjectGroup* lazySingletonGroup(JSContext* cx, ObjectGroupRealm& realm,
+                                           const Class* clasp, TaggedProto proto);
 
-    static void setDefaultNewGroupUnknown(JSContext* cx, const js::Class* clasp, JS::HandleObject obj);
+    static void setDefaultNewGroupUnknown(JSContext* cx, ObjectGroupRealm& realm,
+                                          const js::Class* clasp, JS::HandleObject obj);
 
 #ifdef DEBUG
     static bool hasDefaultNewGroup(JSObject* proto, const Class* clasp, ObjectGroup* group);
 #endif
 
-    // Static accessors for ObjectGroupCompartment ArrayObjectTable and PlainObjectTable.
+    // Static accessors for ObjectGroupRealm ArrayObjectTable and PlainObjectTable.
 
     enum class NewArrayKind {
         Normal,       // Specialize array group based on its element type.
         CopyOnWrite,  // Make an array with copy-on-write elements.
         UnknownIndex  // Make an array with an unknown element type.
     };
 
     // Create an ArrayObject with the specified elements and a group specialized
@@ -556,17 +558,17 @@ class ObjectGroup : public gc::TenuredCe
                                        NewArrayKind arrayKind = NewArrayKind::Normal);
 
     // Create a PlainObject or UnboxedPlainObject with the specified properties
     // and a group specialized for those properties.
     static JSObject* newPlainObject(JSContext* cx,
                                     IdValuePair* properties, size_t nproperties,
                                     NewObjectKind newKind);
 
-    // Static accessors for ObjectGroupCompartment AllocationSiteTable.
+    // Static accessors for ObjectGroupRealm AllocationSiteTable.
 
     // Get a non-singleton group to use for objects created at the specified
     // allocation site.
     static ObjectGroup* allocationSiteGroup(JSContext* cx, JSScript* script, jsbytecode* pc,
                                             JSProtoKey key, HandleObject proto = nullptr);
 
     // Get a non-singleton group to use for objects created in a JSNative call.
     static ObjectGroup* callingAllocationSiteGroup(JSContext* cx, JSProtoKey key,
@@ -584,18 +586,18 @@ class ObjectGroup : public gc::TenuredCe
     // Returns false if not found.
     static bool findAllocationSite(JSContext* cx, ObjectGroup* group,
                                    JSScript** script, uint32_t* offset);
 
   private:
     static ObjectGroup* defaultNewGroup(JSContext* cx, JSProtoKey key);
 };
 
-// Structure used to manage the groups in a compartment.
-class ObjectGroupCompartment
+// Structure used to manage the groups in a realm.
+class ObjectGroupRealm
 {
   private:
     class NewTable;
 
     struct ArrayObjectKey;
     using ArrayObjectTable = js::GCRekeyableHashMap<ArrayObjectKey,
                                                     ReadBarrieredObjectGroup,
                                                     ArrayObjectKey,
@@ -610,17 +612,17 @@ class ObjectGroupCompartment
                                            PlainObjectEntry,
                                            PlainObjectKey,
                                            SystemAllocPolicy,
                                            PlainObjectTableSweepPolicy>;
 
     class AllocationSiteTable;
 
   private:
-    // Set of default 'new' or lazy groups in the compartment.
+    // Set of default 'new' or lazy groups in the realm.
     NewTable* defaultNewTable = nullptr;
     NewTable* lazyTable = nullptr;
 
     // This cache is purged on GC.
     class DefaultNewGroupCache
     {
         ObjectGroup* group_;
         JSObject* associated_;
@@ -650,17 +652,17 @@ class ObjectGroupCompartment
     // objects which have the same shape and property types will also share a
     // group. We don't try to collate arrays or objects with type mismatches.
     ArrayObjectTable* arrayObjectTable = nullptr;
     PlainObjectTable* plainObjectTable = nullptr;
 
     // Table for referencing types of objects keyed to an allocation site.
     AllocationSiteTable* allocationSiteTable = nullptr;
 
-    // A single per-compartment ObjectGroup for all calls to StringSplitString.
+    // A single per-realm ObjectGroup for all calls to StringSplitString.
     // StringSplitString is always called from self-hosted code, and conceptually
     // the return object for a string.split(string) operation should have a
     // unified type.  Having a global group for this also allows us to remove
     // the hash-table lookup that would be required if we allocated this group
     // on the basis of call-site pc.
     ReadBarrieredObjectGroup stringSplitStringGroup = {};
 
     // END OF PROPERTIES
@@ -668,18 +670,24 @@ class ObjectGroupCompartment
   private:
     friend class ObjectGroup;
 
     struct AllocationSiteKey;
 
   public:
     struct NewEntry;
 
-    ObjectGroupCompartment() = default;
-    ~ObjectGroupCompartment();
+    ObjectGroupRealm() = default;
+    ~ObjectGroupRealm();
+
+    ObjectGroupRealm(ObjectGroupRealm&) = delete;
+    void operator=(ObjectGroupRealm&) = delete;
+
+    static ObjectGroupRealm& get(ObjectGroup* group);
+    static ObjectGroupRealm& getForNewObject(JSContext* cx);
 
     void replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc,
                                     JSProtoKey kind, ObjectGroup* group);
 
     void removeDefaultNewGroup(const Class* clasp, TaggedProto proto, JSObject* associated);
     void replaceDefaultNewGroup(const Class* clasp, TaggedProto proto, JSObject* associated,
                                 ObjectGroup* group);
 
@@ -688,17 +696,17 @@ class ObjectGroupCompartment
                                   ObjectGroupFlags initialFlags = 0);
 
     static ObjectGroup* getStringSplitStringGroup(JSContext* cx);
 
     void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                 size_t* allocationSiteTables,
                                 size_t* arrayGroupTables,
                                 size_t* plainObjectGroupTables,
-                                size_t* compartmentTables);
+                                size_t* realmTables);
 
     void clearTables();
 
     void sweep();
 
     void purge() {
         defaultNewGroupCache.purge();
     }
--- a/js/src/vm/ProxyObject.cpp
+++ b/js/src/vm/ProxyObject.cpp
@@ -59,18 +59,19 @@ ProxyObject::New(JSContext* cx, const Ba
     /*
      * Eagerly mark properties unknown for proxies, so we don't try to track
      * their properties and so that we don't need to walk the compartment if
      * their prototype changes later.  But don't do this for DOM proxies,
      * because we want to be able to keep track of them in typesets in useful
      * ways.
      */
     if (proto.isObject() && !options.singleton() && !clasp->isDOMClass()) {
+        ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
         RootedObject protoObj(cx, proto.toObject());
-        if (!JSObject::setNewGroupUnknown(cx, clasp, protoObj))
+        if (!JSObject::setNewGroupUnknown(cx, realm, clasp, protoObj))
             return nullptr;
     }
 
     // Ensure that the wrapper has the same lifetime assumptions as the
     // wrappee. Prefer to allocate in the nursery, when possible.
     NewObjectKind newKind = NurseryAllocatedProxy;
     if (options.singleton()) {
         MOZ_ASSERT(priv.isNull() || (priv.isGCThing() && priv.toGCThing()->isTenured()));
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -1224,17 +1224,17 @@ RegExpCompartment::createMatchResultTemp
     /* Create template array object */
     RootedArrayObject templateObject(cx, NewDenseUnallocatedArray(cx, RegExpObject::MaxPairCount,
                                                                   nullptr, TenuredObject));
     if (!templateObject)
         return matchResultTemplateObject_; // = nullptr
 
     // Create a new group for the template.
     Rooted<TaggedProto> proto(cx, templateObject->taggedProto());
-    ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, templateObject->getClass(), proto);
+    ObjectGroup* group = ObjectGroupRealm::makeGroup(cx, templateObject->getClass(), proto);
     if (!group)
         return matchResultTemplateObject_; // = nullptr
     templateObject->setGroup(group);
 
     /* Set dummy index property */
     RootedValue index(cx, Int32Value(0));
     if (!NativeDefineDataProperty(cx, templateObject, cx->names().index, index, JSPROP_ENUMERATE))
         return matchResultTemplateObject_; // = nullptr
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -1759,17 +1759,17 @@ bool
 js::intrinsic_StringSplitString(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 2);
 
     RootedString string(cx, args[0].toString());
     RootedString sep(cx, args[1].toString());
 
-    RootedObjectGroup group(cx, ObjectGroupCompartment::getStringSplitStringGroup(cx));
+    RootedObjectGroup group(cx, ObjectGroupRealm::getStringSplitStringGroup(cx));
     if (!group)
         return false;
 
     JSObject* aobj = str_split_string(cx, group, string, sep, INT32_MAX);
     if (!aobj)
         return false;
 
     args.rval().setObject(*aobj);
@@ -1785,17 +1785,17 @@ intrinsic_StringSplitStringLimit(JSConte
     RootedString string(cx, args[0].toString());
     RootedString sep(cx, args[1].toString());
 
     // args[2] should be already in UInt32 range, but it could be double typed,
     // because of Ion optimization.
     uint32_t limit = uint32_t(args[2].toNumber());
     MOZ_ASSERT(limit > 0, "Zero limit case is already handled in self-hosted code.");
 
-    RootedObjectGroup group(cx, ObjectGroupCompartment::getStringSplitStringGroup(cx));
+    RootedObjectGroup group(cx, ObjectGroupRealm::getStringSplitStringGroup(cx));
     if (!group)
         return false;
 
     JSObject* aobj = str_split_string(cx, group, string, sep, limit);
     if (!aobj)
         return false;
 
     args.rval().setObject(*aobj);
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -3016,17 +3016,17 @@ ObjectGroup::detachNewScript(bool writeB
     // analyzed, remove it from the newObjectGroups table so that it will not be
     // produced by calling 'new' on the associated function anymore.
     // The TypeNewScript is not actually destroyed.
     AutoSweepObjectGroup sweep(this);
     TypeNewScript* newScript = anyNewScript(sweep);
     MOZ_ASSERT(newScript);
 
     if (newScript->analyzed()) {
-        ObjectGroupCompartment& objectGroups = newScript->function()->compartment()->objectGroups;
+        ObjectGroupRealm& objectGroups = ObjectGroupRealm::get(this);
         TaggedProto proto = this->proto();
         if (proto.isObject() && IsForwarded(proto.toObject()))
             proto = TaggedProto(Forwarded(proto.toObject()));
         JSObject* associated = MaybeForwarded(newScript->function());
         if (replacement) {
             AutoSweepObjectGroup sweepReplacement(replacement);
             MOZ_ASSERT(replacement->newScript(sweepReplacement)->function() == newScript->function());
             objectGroups.replaceDefaultNewGroup(nullptr, proto, associated, replacement);
@@ -3471,18 +3471,18 @@ JSFunction::setTypeForScriptedFunction(J
                                        bool singleton /* = false */)
 {
     if (singleton) {
         if (!setSingleton(cx, fun))
             return false;
     } else {
         RootedObject funProto(cx, fun->staticPrototype());
         Rooted<TaggedProto> taggedProto(cx, TaggedProto(funProto));
-        ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, &JSFunction::class_,
-                                                               taggedProto);
+        ObjectGroup* group = ObjectGroupRealm::makeGroup(cx, &JSFunction::class_,
+                                                         taggedProto);
         if (!group)
             return false;
 
         fun->setGroup(group);
         group->setInterpretedFunction(fun);
     }
 
     return true;
@@ -3800,16 +3800,17 @@ TypeNewScript::maybeAnalyze(JSContext* c
 
     // Make sure there aren't dead references in preliminaryObjects. This can
     // clear out the new script information on OOM.
     AutoSweepObjectGroup sweep(group);
     if (!group->newScript(sweep))
         return true;
 
     MOZ_ASSERT(this == group->newScript(sweep));
+    MOZ_ASSERT(cx->realm() == group->realm());
 
     if (regenerate)
         *regenerate = false;
 
     if (analyzed()) {
         // The analyses have already been performed.
         return true;
     }
@@ -3989,26 +3990,26 @@ TypeNewScript::maybeAnalyze(JSContext* c
     // existing group to represent fully initialized objects with all
     // definite properties in the prefix shape, and make a new group to
     // represent partially initialized objects.
     MOZ_ASSERT(prefixShape->slotSpan() > templateObject()->slotSpan());
 
     ObjectGroupFlags initialFlags = group->flags(sweep) & OBJECT_FLAG_DYNAMIC_MASK;
 
     Rooted<TaggedProto> protoRoot(cx, group->proto());
-    ObjectGroup* initialGroup = ObjectGroupCompartment::makeGroup(cx, group->clasp(), protoRoot,
-                                                                  initialFlags);
+    ObjectGroup* initialGroup = ObjectGroupRealm::makeGroup(cx, group->clasp(), protoRoot,
+                                                            initialFlags);
     if (!initialGroup)
         return false;
 
     initialGroup->addDefiniteProperties(cx, templateObject()->lastProperty());
     group->addDefiniteProperties(cx, prefixShape);
 
-    cx->compartment()->objectGroups.replaceDefaultNewGroup(nullptr, group->proto(), function(),
-                                                           initialGroup);
+    ObjectGroupRealm& realm = ObjectGroupRealm::get(group);
+    realm.replaceDefaultNewGroup(nullptr, group->proto(), function(), initialGroup);
 
     templateObject()->setGroup(initialGroup);
 
     // Transfer this TypeNewScript from the fully initialized group to the
     // partially initialized group.
     group->detachNewScript();
     initialGroup->setNewScript(this);
 
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -548,16 +548,18 @@ MakeReplacementTemplateObject(JSContext*
     }
 
     return obj;
 }
 
 /* static */ bool
 UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group)
 {
+    MOZ_ASSERT(cx->realm() == group->realm());
+
     AutoEnterAnalysis enter(cx);
 
     AutoSweepObjectGroup sweep(group);
     UnboxedLayout& layout = group->unboxedLayout(sweep);
     Rooted<TaggedProto> proto(cx, group->proto());
 
     MOZ_ASSERT(!layout.nativeGroup());
 
@@ -565,17 +567,17 @@ UnboxedLayout::makeNativeGroup(JSContext
 
     // Immediately clear any new script on the group. This is done by replacing
     // the existing new script with one for a replacement default new group.
     // This is done so that the size of the replacment group's objects is the
     // same as that for the unboxed group, so that we do not see polymorphic
     // slot accesses later on for sites that see converted objects from this
     // group and objects that were allocated using the replacement new group.
     if (layout.newScript()) {
-        replacementGroup = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto);
+        replacementGroup = ObjectGroupRealm::makeGroup(cx, &PlainObject::class_, proto);
         if (!replacementGroup)
             return false;
 
         PlainObject* templateObject = MakeReplacementTemplateObject(cx, replacementGroup, layout);
         if (!templateObject)
             return false;
 
         TypeNewScript* replacementNewScript =
@@ -590,25 +592,25 @@ UnboxedLayout::makeNativeGroup(JSContext
     }
 
     // Similarly, if this group is keyed to an allocation site, replace its
     // entry with a new group that has no unboxed layout.
     if (layout.allocationScript()) {
         RootedScript script(cx, layout.allocationScript());
         jsbytecode* pc = layout.allocationPc();
 
-        replacementGroup = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto);
+        replacementGroup = ObjectGroupRealm::makeGroup(cx, &PlainObject::class_, proto);
         if (!replacementGroup)
             return false;
 
         PlainObject* templateObject = &script->getObject(pc)->as<PlainObject>();
         replacementGroup->addDefiniteProperties(cx, templateObject->lastProperty());
 
-        cx->compartment()->objectGroups.replaceAllocationSiteGroup(script, pc, JSProto_Object,
-                                                                   replacementGroup);
+        ObjectGroupRealm& realm = ObjectGroupRealm::get(group);
+        realm.replaceAllocationSiteGroup(script, pc, JSProto_Object, replacementGroup);
 
         // Clear any baseline information at this opcode which might use the old group.
         if (script->hasBaselineScript()) {
             jit::ICEntry& entry = script->baselineScript()->icEntryFromPCOffset(script->pcToOffset(pc));
             jit::ICFallbackStub* fallback = entry.fallbackStub();
             for (jit::ICStubIterator iter = fallback->beginChain(); !iter.atEnd(); iter++)
                 iter.unlink(cx);
             if (fallback->isNewObject_Fallback())
@@ -631,18 +633,18 @@ UnboxedLayout::makeNativeGroup(JSContext
         Rooted<StackShape> child(cx, StackShape(shape->base()->unowned(), NameToId(property.name),
                                                 i, JSPROP_ENUMERATE));
         shape = cx->zone()->propertyTree().getChild(cx, shape, child);
         if (!shape)
             return false;
     }
 
     ObjectGroup* nativeGroup =
-        ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto,
-                                          group->flags(sweep) & OBJECT_FLAG_DYNAMIC_MASK);
+        ObjectGroupRealm::makeGroup(cx, &PlainObject::class_, proto,
+                                    group->flags(sweep) & OBJECT_FLAG_DYNAMIC_MASK);
     if (!nativeGroup)
         return false;
 
     // No sense propagating if we don't know what we started with.
     AutoSweepObjectGroup sweepNative(nativeGroup);
     if (!group->unknownProperties(sweep)) {
         for (size_t i = 0; i < layout.properties().length(); i++) {
             const UnboxedLayout::Property& property = layout.properties()[i];