Bug 1461938 part 39 - Move savedStacks_ to JS::Realm. r=luke
authorJan de Mooij <jdemooij@mozilla.com>
Fri, 25 May 2018 11:12:04 +0200
changeset 419853 385b54738fb6cbae7a054939963747155408597e
parent 419852 2ce6ce0e629153bedd88afc63898fbca50ed6774
child 419854 d99b7e4e8cd9b6f7afece1e166d9a881a192b926
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 39 - Move savedStacks_ to JS::Realm. r=luke
js/src/builtin/TestingFunctions.cpp
js/src/jsapi.cpp
js/src/vm/DebuggerMemory.cpp
js/src/vm/JSCompartment.cpp
js/src/vm/JSCompartment.h
js/src/vm/JSContext-inl.h
js/src/vm/SavedStacks.cpp
js/src/vm/SavedStacks.h
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1266,40 +1266,39 @@ SetSavedStacksRNGState(JSContext* cx, un
         return false;
 
     int32_t seed;
     if (!ToInt32(cx, args[0], &seed))
         return false;
 
     // Either one or the other of the seed arguments must be non-zero;
     // make this true no matter what value 'seed' has.
-    cx->compartment()->savedStacks().setRNGState(seed, (seed + 1) * 33);
+    cx->realm()->savedStacks().setRNGState(seed, (seed + 1) * 33);
     return true;
 }
 
 static bool
 GetSavedFrameCount(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    args.rval().setNumber(cx->compartment()->savedStacks().count());
+    args.rval().setNumber(cx->realm()->savedStacks().count());
     return true;
 }
 
 static bool
 ClearSavedFrames(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    js::SavedStacks& savedStacks = cx->compartment()->savedStacks();
+    js::SavedStacks& savedStacks = cx->realm()->savedStacks();
     if (savedStacks.initialized())
         savedStacks.clear();
 
-    for (ActivationIterator iter(cx); !iter.done(); ++iter) {
+    for (ActivationIterator iter(cx); !iter.done(); ++iter)
         iter->clearLiveSavedFrameCache();
-    }
 
     args.rval().setUndefined();
     return true;
 }
 
 static bool
 SaveStack(JSContext* cx, unsigned argc, Value* vp)
 {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -7791,40 +7791,39 @@ JS::FirstSubsumedFrame::FirstSubsumedFra
 { }
 
 JS_PUBLIC_API(bool)
 JS::CaptureCurrentStack(JSContext* cx, JS::MutableHandleObject stackp,
                         JS::StackCapture&& capture /* = JS::StackCapture(JS::AllFrames()) */)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
-    MOZ_RELEASE_ASSERT(cx->compartment());
-
-    JSCompartment* compartment = cx->compartment();
+    MOZ_RELEASE_ASSERT(cx->realm());
+
+    Realm* realm = cx->realm();
     Rooted<SavedFrame*> frame(cx);
-    if (!compartment->savedStacks().saveCurrentStack(cx, &frame, mozilla::Move(capture)))
+    if (!realm->savedStacks().saveCurrentStack(cx, &frame, mozilla::Move(capture)))
         return false;
     stackp.set(frame.get());
     return true;
 }
 
 JS_PUBLIC_API(bool)
 JS::CopyAsyncStack(JSContext* cx, JS::HandleObject asyncStack,
                    JS::HandleString asyncCause, JS::MutableHandleObject stackp,
                    const Maybe<size_t>& maxFrameCount)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
-    MOZ_RELEASE_ASSERT(cx->compartment());
+    MOZ_RELEASE_ASSERT(cx->realm());
 
     js::AssertObjectIsSavedFrameOrWrapper(cx, asyncStack);
-    JSCompartment* compartment = cx->compartment();
+    Realm* realm = cx->realm();
     Rooted<SavedFrame*> frame(cx);
-    if (!compartment->savedStacks().copyAsyncStack(cx, asyncStack, asyncCause,
-                                                   &frame, maxFrameCount))
+    if (!realm->savedStacks().copyAsyncStack(cx, asyncStack, asyncCause, &frame, maxFrameCount))
         return false;
     stackp.set(frame.get());
     return true;
 }
 
 JS_PUBLIC_API(Zone*)
 JS::GetObjectZone(JSObject* obj)
 {
--- a/js/src/vm/DebuggerMemory.cpp
+++ b/js/src/vm/DebuggerMemory.cpp
@@ -303,20 +303,20 @@ DebuggerMemory::setAllocationSamplingPro
         return false;
     }
 
     Debugger* dbg = memory->getDebugger();
     if (dbg->allocationSamplingProbability != probability) {
         dbg->allocationSamplingProbability = probability;
 
         // If this is a change any debuggees would observe, have all debuggee
-        // compartments recompute their sampling probabilities.
+        // realms recompute their sampling probabilities.
         if (dbg->enabled && dbg->trackingAllocationSites) {
             for (auto r = dbg->debuggees.all(); !r.empty(); r.popFront())
-                r.front()->compartment()->chooseAllocationSamplingProbability();
+                r.front()->realm()->chooseAllocationSamplingProbability();
         }
     }
 
     args.rval().setUndefined();
     return true;
 }
 
 /* static */ bool
--- a/js/src/vm/JSCompartment.cpp
+++ b/js/src/vm/JSCompartment.cpp
@@ -38,19 +38,17 @@
 using namespace js;
 using namespace js::gc;
 using namespace js::jit;
 
 using mozilla::PodArrayZero;
 
 JSCompartment::JSCompartment(Zone* zone)
   : zone_(zone),
-    runtime_(zone->runtimeFromAnyThread()),
-    data(nullptr),
-    gcIncomingGrayPointers(nullptr)
+    runtime_(zone->runtimeFromAnyThread())
 {
     runtime_->numCompartments++;
 }
 
 ObjectRealm::ObjectRealm(JS::Zone* zone)
   : innerViews(zone)
 {}
 
@@ -786,17 +784,17 @@ JSCompartment::sweepAfterMinorGC(JSTrace
 {
     crossCompartmentWrappers.sweepAfterMinorGC(trc);
 
     Realm* realm = JS::GetRealmForCompartment(this);
     realm->sweepAfterMinorGC();
 }
 
 void
-JSCompartment::sweepSavedStacks()
+Realm::sweepSavedStacks()
 {
     savedStacks_.sweep();
 }
 
 void
 Realm::sweepGlobalObject()
 {
     if (global_ && IsAboutToBeFinalized(&global_))
--- a/js/src/vm/JSCompartment.h
+++ b/js/src/vm/JSCompartment.h
@@ -552,73 +552,64 @@ class WeakMapBase;
 
 struct JSCompartment
 {
   protected:
     JS::Zone*                    zone_;
     JSRuntime*                   runtime_;
 
   private:
-    friend struct JSRuntime;
-    friend struct JSContext;
+    js::WrapperMap crossCompartmentWrappers;
 
   public:
+    /*
+     * During GC, stores the head of a list of incoming pointers from gray cells.
+     *
+     * The objects in the list are either cross-compartment wrappers, or
+     * debugger wrapper objects.  The list link is either in the second extra
+     * slot for the former, or a special slot for the latter.
+     */
+    JSObject* gcIncomingGrayPointers = nullptr;
+
+    void* data = nullptr;
+
+    // These flags help us to discover if a compartment that shouldn't be alive
+    // manages to outlive a GC. Note that these flags have to be on the
+    // compartment, not the realm, because same-compartment realms can have
+    // cross-realm pointers without wrappers.
+    bool scheduledForDestruction = false;
+    bool maybeAlive = true;
+
     JS::Zone* zone() { return zone_; }
     const JS::Zone* zone() const { return zone_; }
 
     JSRuntime* runtimeFromMainThread() const {
         MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_));
         return runtime_;
     }
 
     // Note: Unrestricted access to the zone's runtime from an arbitrary
     // thread can easily lead to races. Use this method very carefully.
     JSRuntime* runtimeFromAnyThread() const {
         return runtime_;
     }
 
-  public:
-    void*                        data;
-
-  protected:
-    js::SavedStacks              savedStacks_;
-
-  private:
-    js::WrapperMap               crossCompartmentWrappers;
-
-  public:
     void assertNoCrossCompartmentWrappers() {
         MOZ_ASSERT(crossCompartmentWrappers.empty());
     }
 
-  public:
-    // Recompute the probability with which this compartment should record
-    // profiling data (stack traces, allocations log, etc.) about each
-    // allocation. We consult the probabilities requested by the Debugger
-    // instances observing us, if any.
-    void chooseAllocationSamplingProbability() { savedStacks_.chooseSamplingProbability(this); }
-
   protected:
     void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                 size_t* crossCompartmentWrappersArg);
 
   public:
 #ifdef JSGC_HASH_TABLE_CHECKS
     void checkWrapperMapAfterMovingGC();
 #endif
 
-    /*
-     * During GC, stores the head of a list of incoming pointers from gray cells.
-     *
-     * The objects in the list are either cross-compartment wrappers, or
-     * debugger wrapper objects.  The list link is either in the second extra
-     * slot for the former, or a special slot for the latter.
-     */
-    JSObject*                    gcIncomingGrayPointers;
-
   private:
     bool getNonWrapperObjectForCurrentCompartment(JSContext* cx, js::MutableHandleObject obj);
     bool getOrCreateWrapper(JSContext* cx, js::HandleObject existing, js::MutableHandleObject obj);
 
   protected:
     explicit JSCompartment(JS::Zone* zone);
     ~JSCompartment();
 
@@ -676,31 +667,21 @@ struct JSCompartment
      * when compacting to update cross-compartment pointers.
      */
     void traceOutgoingCrossCompartmentWrappers(JSTracer* trc);
     static void traceIncomingCrossCompartmentEdgesForZoneGC(JSTracer* trc);
 
     void sweepAfterMinorGC(JSTracer* trc);
 
     void sweepCrossCompartmentWrappers();
-    void sweepSavedStacks();
 
     static void fixupCrossCompartmentWrappersAfterMovingGC(JSTracer* trc);
     void fixupAfterMovingGC();
 
-    js::SavedStacks& savedStacks() { return savedStacks_; }
-
     void findOutgoingEdges(js::gc::ZoneComponentFinder& finder);
-
-    // These flags help us to discover if a compartment that shouldn't be alive
-    // manages to outlive a GC. Note that these flags have to be on the
-    // compartment, not the realm, because same-compartment realms can have
-    // cross-realm pointers without wrappers.
-    bool scheduledForDestruction = false;
-    bool maybeAlive = true;
 };
 
 namespace js {
 
 // ObjectRealm stores various tables and other state associated with particular
 // objects in a realm. To make sure the correct ObjectRealm is used for an
 // object, use of the ObjectRealm::get(obj) static method is required.
 class ObjectRealm
@@ -804,16 +785,18 @@ class JS::Realm : public JSCompartment
 
     JSPrincipals* principals_ = nullptr;
 
     js::UniquePtr<js::jit::JitRealm> jitRealm_;
 
     // Bookkeeping information for debug scope objects.
     js::UniquePtr<js::DebugEnvironments> debugEnvs_;
 
+    js::SavedStacks savedStacks_;
+
     // Used by memory reporters and invalid otherwise.
     JS::RealmStats* realmStats_ = nullptr;
 
     const js::AllocationMetadataBuilder* allocationMetadataBuilder_ = nullptr;
     void* realmPrivate_ = nullptr;
 
     // This pointer is controlled by the embedder. If it is non-null, and if
     // cx->enableAccessValidation is true, then we assert that *validAccessPtr
@@ -1273,16 +1256,30 @@ class JS::Realm : public JSCompartment
 
     js::DebugEnvironments* debugEnvs() {
         return debugEnvs_.get();
     }
     js::UniquePtr<js::DebugEnvironments>& debugEnvsRef() {
         return debugEnvs_;
     }
 
+    js::SavedStacks& savedStacks() {
+        return savedStacks_;
+    }
+
+    // Recompute the probability with which this realm should record
+    // profiling data (stack traces, allocations log, etc.) about each
+    // allocation. We consult the probabilities requested by the Debugger
+    // instances observing us, if any.
+    void chooseAllocationSamplingProbability() {
+        savedStacks_.chooseSamplingProbability(this);
+    }
+
+    void sweepSavedStacks();
+
     static constexpr size_t offsetOfRegExps() {
         return offsetof(JS::Realm, regExps);
     }
 };
 
 namespace js {
 
 // We only set the maybeAlive flag for objects and scripts. It's assumed that,
--- a/js/src/vm/JSContext-inl.h
+++ b/js/src/vm/JSContext-inl.h
@@ -161,17 +161,16 @@ class CompartmentChecker
     void check(JSScript* script) {
         MOZ_ASSERT(JS::CellIsNotGray(script));
         if (script)
             check(script->compartment());
     }
 
     void check(InterpreterFrame* fp);
     void check(AbstractFramePtr frame);
-    void check(SavedStacks* stacks);
 
     void check(Handle<PropertyDescriptor> desc) {
         check(desc.object());
         if (desc.hasGetterObject())
             check(desc.getterObject());
         if (desc.hasSetterObject())
             check(desc.setterObject());
         check(desc.value());
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -96,40 +96,40 @@ LiveSavedFrameCache::insert(JSContext* c
 
 void
 LiveSavedFrameCache::find(JSContext* cx, FramePtr& framePtr, const jsbytecode* pc,
                           MutableHandleSavedFrame frame) const
 {
     MOZ_ASSERT(initialized());
     MOZ_ASSERT(framePtr.hasCachedSavedFrame());
 
-    // If we flushed the cache due to a compartment mismatch, then we shouldn't
+    // If we flushed the cache due to a realm mismatch, then we shouldn't
     // expect to find any frames in the cache.
     if (frames->empty()) {
         frame.set(nullptr);
         return;
     }
 
-    // All our SavedFrames should be in the same compartment. If the last
-    // entry's SavedFrame's compartment doesn't match cx's, flush the cache.
-    if (frames->back().savedFrame->compartment() != cx->compartment()) {
+    // All our SavedFrames should be in the same realm. If the last
+    // entry's SavedFrame's realm doesn't match cx's, flush the cache.
+    if (frames->back().savedFrame->realm() != cx->realm()) {
 #ifdef DEBUG
-        // Check that they are, indeed, all in the same compartment.
-        auto compartment = frames->back().savedFrame->compartment();
+        // Check that they are, indeed, all in the same realm.
+        auto compartment = frames->back().savedFrame->realm();
         for (const auto& f : (*frames))
-            MOZ_ASSERT(compartment == f.savedFrame->compartment());
+            MOZ_ASSERT(compartment == f.savedFrame->realm());
 #endif
         frames->clear();
         frame.set(nullptr);
         return;
     }
 
     Key key(framePtr);
     while (key != frames->back().key) {
-        MOZ_ASSERT(frames->back().savedFrame->compartment() == cx->compartment());
+        MOZ_ASSERT(frames->back().savedFrame->realm() == cx->realm());
 
         // We know that the cache does contain an entry for frameIter's frame,
         // since its bit is set. That entry must be below this one in the stack,
         // so frames->back() must correspond to a frame younger than
         // frameIter's. If frameIter is the youngest frame with its bit set,
         // then its entry is the youngest that is valid, and we can pop this
         // entry. Even if frameIter is not the youngest frame with its bit set,
         // since we're going to push new cache entries for all frames younger
@@ -554,17 +554,17 @@ SavedFrame::initFromLookup(JSContext* cx
 SavedFrame::create(JSContext* cx)
 {
     RootedGlobalObject global(cx, cx->global());
     assertSameCompartment(cx, global);
 
     // Ensure that we don't try to capture the stack again in the
     // `SavedStacksMetadataBuilder` for this new SavedFrame object, and
     // accidentally cause O(n^2) behavior.
-    SavedStacks::AutoReentrancyGuard guard(cx->compartment()->savedStacks());
+    SavedStacks::AutoReentrancyGuard guard(cx->realm()->savedStacks());
 
     RootedNativeObject proto(cx, GlobalObject::getOrCreateSavedFramePrototype(cx, global));
     if (!proto)
         return nullptr;
     assertSameCompartment(cx, proto);
 
     return NewObjectWithGivenProto<SavedFrame>(cx, proto, TenuredObject);
 }
@@ -824,17 +824,17 @@ UnwrapSavedFrame(JSContext* cx, HandleOb
 }
 
 JS_PUBLIC_API(SavedFrameResult)
 GetSavedFrameSource(JSContext* cx, HandleObject savedFrame, MutableHandleString sourcep,
                     SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
 {
     js::AssertHeapIsIdle();
     CHECK_REQUEST(cx);
-    MOZ_RELEASE_ASSERT(cx->compartment());
+    MOZ_RELEASE_ASSERT(cx->realm());
 
     {
         AutoMaybeEnterFrameRealm ar(cx, savedFrame);
         bool skippedAsync;
         js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync));
         if (!frame) {
             sourcep.set(cx->runtime()->emptyString);
             return SavedFrameResult::AccessDenied;
@@ -847,17 +847,17 @@ GetSavedFrameSource(JSContext* cx, Handl
 }
 
 JS_PUBLIC_API(SavedFrameResult)
 GetSavedFrameLine(JSContext* cx, HandleObject savedFrame, uint32_t* linep,
                   SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
 {
     js::AssertHeapIsIdle();
     CHECK_REQUEST(cx);
-    MOZ_RELEASE_ASSERT(cx->compartment());
+    MOZ_RELEASE_ASSERT(cx->realm());
     MOZ_ASSERT(linep);
 
     AutoMaybeEnterFrameRealm ar(cx, savedFrame);
     bool skippedAsync;
     js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync));
     if (!frame) {
         *linep = 0;
         return SavedFrameResult::AccessDenied;
@@ -867,17 +867,17 @@ GetSavedFrameLine(JSContext* cx, HandleO
 }
 
 JS_PUBLIC_API(SavedFrameResult)
 GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp,
                     SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
 {
     js::AssertHeapIsIdle();
     CHECK_REQUEST(cx);
-    MOZ_RELEASE_ASSERT(cx->compartment());
+    MOZ_RELEASE_ASSERT(cx->realm());
     MOZ_ASSERT(columnp);
 
     AutoMaybeEnterFrameRealm ar(cx, savedFrame);
     bool skippedAsync;
     js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync));
     if (!frame) {
         *columnp = 0;
         return SavedFrameResult::AccessDenied;
@@ -887,17 +887,17 @@ GetSavedFrameColumn(JSContext* cx, Handl
 }
 
 JS_PUBLIC_API(SavedFrameResult)
 GetSavedFrameFunctionDisplayName(JSContext* cx, HandleObject savedFrame, MutableHandleString namep,
                                  SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
 {
     js::AssertHeapIsIdle();
     CHECK_REQUEST(cx);
-    MOZ_RELEASE_ASSERT(cx->compartment());
+    MOZ_RELEASE_ASSERT(cx->realm());
 
     {
         AutoMaybeEnterFrameRealm ar(cx, savedFrame);
         bool skippedAsync;
         js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync));
         if (!frame) {
             namep.set(nullptr);
             return SavedFrameResult::AccessDenied;
@@ -910,17 +910,17 @@ GetSavedFrameFunctionDisplayName(JSConte
 }
 
 JS_PUBLIC_API(SavedFrameResult)
 GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleString asyncCausep,
                         SavedFrameSelfHosted unused_ /* = SavedFrameSelfHosted::Include */)
 {
     js::AssertHeapIsIdle();
     CHECK_REQUEST(cx);
-    MOZ_RELEASE_ASSERT(cx->compartment());
+    MOZ_RELEASE_ASSERT(cx->realm());
 
     {
         AutoMaybeEnterFrameRealm ar(cx, savedFrame);
         bool skippedAsync;
         // This function is always called with self-hosted frames excluded by
         // GetValueIfNotCached in dom/bindings/Exceptions.cpp. However, we want
         // to include them because our Promise implementation causes us to have
         // the async cause on a self-hosted frame. So we just ignore the
@@ -941,17 +941,17 @@ GetSavedFrameAsyncCause(JSContext* cx, H
 }
 
 JS_PUBLIC_API(SavedFrameResult)
 GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject asyncParentp,
                          SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
 {
     js::AssertHeapIsIdle();
     CHECK_REQUEST(cx);
-    MOZ_RELEASE_ASSERT(cx->compartment());
+    MOZ_RELEASE_ASSERT(cx->realm());
 
     AutoMaybeEnterFrameRealm ar(cx, savedFrame);
     bool skippedAsync;
     js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync));
     if (!frame) {
         asyncParentp.set(nullptr);
         return SavedFrameResult::AccessDenied;
     }
@@ -974,17 +974,17 @@ GetSavedFrameAsyncParent(JSContext* cx, 
 }
 
 JS_PUBLIC_API(SavedFrameResult)
 GetSavedFrameParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject parentp,
                     SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
 {
     js::AssertHeapIsIdle();
     CHECK_REQUEST(cx);
-    MOZ_RELEASE_ASSERT(cx->compartment());
+    MOZ_RELEASE_ASSERT(cx->realm());
 
     AutoMaybeEnterFrameRealm ar(cx, savedFrame);
     bool skippedAsync;
     js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync));
     if (!frame) {
         parentp.set(nullptr);
         return SavedFrameResult::AccessDenied;
     }
@@ -1080,17 +1080,17 @@ FormatV8StackFrame(JSContext* cx, js::St
 }
 
 JS_PUBLIC_API(bool)
 BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp,
                  size_t indent, js::StackFormat format)
 {
     js::AssertHeapIsIdle();
     CHECK_REQUEST(cx);
-    MOZ_RELEASE_ASSERT(cx->compartment());
+    MOZ_RELEASE_ASSERT(cx->realm());
 
     js::StringBuffer sb(cx);
 
     if (format == js::StackFormat::Default)
         format = cx->runtime()->stackFormat();
     MOZ_ASSERT(format != js::StackFormat::Default);
 
     // Enter a new block to constrain the scope of possibly entering the stack's
@@ -1274,18 +1274,18 @@ SavedStacks::init()
            pcLocationMap.init();
 }
 
 bool
 SavedStacks::saveCurrentStack(JSContext* cx, MutableHandleSavedFrame frame,
                               JS::StackCapture&& capture /* = JS::StackCapture(JS::AllFrames()) */)
 {
     MOZ_ASSERT(initialized());
-    MOZ_RELEASE_ASSERT(cx->compartment());
-    assertSameCompartment(cx, this);
+    MOZ_RELEASE_ASSERT(cx->realm());
+    MOZ_DIAGNOSTIC_ASSERT(&cx->realm()->savedStacks() == this);
 
     if (creatingSavedFrame ||
         cx->isExceptionPending() ||
         !cx->global() ||
         !cx->global()->isStandardClassResolved(JSProto_Object))
     {
         frame.set(nullptr);
         return true;
@@ -1296,18 +1296,18 @@ SavedStacks::saveCurrentStack(JSContext*
 }
 
 bool
 SavedStacks::copyAsyncStack(JSContext* cx, HandleObject asyncStack, HandleString asyncCause,
                             MutableHandleSavedFrame adoptedStack,
                             const Maybe<size_t>& maxFrameCount)
 {
     MOZ_ASSERT(initialized());
-    MOZ_RELEASE_ASSERT(cx->compartment());
-    assertSameCompartment(cx, this);
+    MOZ_RELEASE_ASSERT(cx->realm());
+    MOZ_DIAGNOSTIC_ASSERT(&cx->realm()->savedStacks() == this);
 
     RootedAtom asyncCauseAtom(cx, AtomizeString(cx, asyncCause));
     if (!asyncCauseAtom)
         return false;
 
     RootedObject asyncStackObj(cx, CheckedUnwrap(asyncStack));
     MOZ_RELEASE_ASSERT(asyncStackObj);
     MOZ_RELEASE_ASSERT(js::SavedFrame::isSavedFrameAndNotProto(*asyncStackObj));
@@ -1470,17 +1470,17 @@ SavedStacks::insertFrames(JSContext* cx,
                 break;
         }
 
         // We'll be pushing this frame onto stackChain. Gather the information
         // needed to construct the SavedFrame::Lookup.
         Rooted<LocationValue> location(cx);
         {
             AutoRealmUnchecked ar(cx, iter.compartment());
-            if (!cx->compartment()->savedStacks().getLocation(cx, iter, &location))
+            if (!cx->realm()->savedStacks().getLocation(cx, iter, &location))
                 return false;
         }
 
         RootedAtom displayAtom(cx, iter.maybeFunctionDisplayAtom());
 
         auto principals = JS::GetRealmForCompartment(iter.compartment())->principals();
         MOZ_ASSERT_IF(framePtr && !iter.isWasm(), iter.pc());
 
@@ -1613,22 +1613,22 @@ SavedStacks::adoptAsyncStack(JSContext* 
         }
 
         currentSavedFrame = currentSavedFrame->getParent();
     }
 
     // Attach the asyncCause to the youngest frame.
     stackChain[0]->asyncCause = asyncCause;
 
-    // If we walked the entire stack, and it's in cx's compartment, we don't
+    // If we walked the entire stack, and it's in cx's realm, we don't
     // need to rebuild the full chain again using the lookup objects - we can
     // just use the existing chain. Only the asyncCause on the youngest frame
     // needs to be changed.
     if (currentSavedFrame == nullptr &&
-        asyncStack->compartment() == cx->compartment())
+        asyncStack->realm() == cx->realm())
     {
         SavedFrame::HandleLookup lookup = stackChain[0];
         lookup->parent = asyncStack->getParent();
         asyncStack.set(getOrCreateSavedFrame(cx, lookup));
         return !!asyncStack;
     }
 
     // If we captured the maximum number of frames and the caller requested no
@@ -1743,17 +1743,18 @@ SavedStacks::createFrameFromLookup(JSCon
 bool
 SavedStacks::getLocation(JSContext* cx, const FrameIter& iter,
                          MutableHandle<LocationValue> locationp)
 {
     // We should only ever be caching location values for scripts in this
     // compartment. Otherwise, we would get dead cross-compartment scripts in
     // the cache because our compartment's sweep method isn't called when their
     // compartment gets collected.
-    assertSameCompartment(cx, this, iter.compartment());
+    MOZ_DIAGNOSTIC_ASSERT(&cx->realm()->savedStacks() == this);
+    assertSameCompartment(cx, iter.compartment());
 
     // When we have a |JSScript| for this frame, use a potentially memoized
     // location from our PCLocationMap and copy it into |locationp|. When we do
     // not have a |JSScript| for this frame (wasm frames), we take a slow path
     // that doesn't employ memoization, and update |locationp|'s slots directly.
 
     if (iter.isWasm()) {
         // Only asm.js has a displayURL.
@@ -1801,19 +1802,18 @@ SavedStacks::getLocation(JSContext* cx, 
         }
     }
 
     locationp.set(p->value());
     return true;
 }
 
 void
-SavedStacks::chooseSamplingProbability(JSCompartment* compartment)
+SavedStacks::chooseSamplingProbability(Realm* realm)
 {
-    Realm* realm = JS::GetRealmForCompartment(compartment);
     GlobalObject* global = realm->maybeGlobal();
     if (!global)
         return;
 
     GlobalObject::DebuggerVector* dbgs = global->getDebuggers();
     if (!dbgs || dbgs->empty())
         return;
 
@@ -1845,45 +1845,33 @@ SavedStacks::chooseSamplingProbability(J
 }
 
 JSObject*
 SavedStacks::MetadataBuilder::build(JSContext* cx, HandleObject target,
                                     AutoEnterOOMUnsafeRegion& oomUnsafe) const
 {
     RootedObject obj(cx, target);
 
-    SavedStacks& stacks = cx->compartment()->savedStacks();
+    SavedStacks& stacks = cx->realm()->savedStacks();
     if (!stacks.bernoulli.trial())
         return nullptr;
 
     RootedSavedFrame frame(cx);
     if (!stacks.saveCurrentStack(cx, &frame))
         oomUnsafe.crash("SavedStacksMetadataBuilder");
 
     if (!Debugger::onLogAllocationSite(cx, obj, frame, mozilla::TimeStamp::Now()))
         oomUnsafe.crash("SavedStacksMetadataBuilder");
 
     MOZ_ASSERT_IF(frame, !frame->is<WrapperObject>());
     return frame;
 }
 
 const SavedStacks::MetadataBuilder SavedStacks::metadataBuilder;
 
-#ifdef JS_CRASH_DIAGNOSTICS
-void
-CompartmentChecker::check(SavedStacks* stacks)
-{
-    if (&compartment->savedStacks() != stacks) {
-        printf("*** Compartment SavedStacks mismatch: %p vs. %p\n",
-               (void*) &compartment->savedStacks(), stacks);
-        MOZ_CRASH();
-    }
-}
-#endif /* JS_CRASH_DIAGNOSTICS */
-
 /* static */ ReconstructedSavedFramePrincipals ReconstructedSavedFramePrincipals::IsSystem;
 /* static */ ReconstructedSavedFramePrincipals ReconstructedSavedFramePrincipals::IsNotSystem;
 
 UTF8CharsZ
 BuildUTF8StackString(JSContext* cx, HandleObject stack)
 {
     RootedString stackStr(cx);
     if (!JS::BuildStackString(cx, stack, &stackStr))
@@ -1996,17 +1984,17 @@ ConstructSavedFrameStackSlow(JSContext* 
 
         ubiFrame = ubiFrame.get().parent();
     }
 
     js::RootedSavedFrame parentFrame(cx);
     for (size_t i = stackChain->length(); i != 0; i--) {
         SavedFrame::HandleLookup lookup = stackChain[i-1];
         lookup->parent = parentFrame;
-        parentFrame = cx->compartment()->savedStacks().getOrCreateSavedFrame(cx, lookup);
+        parentFrame = cx->realm()->savedStacks().getOrCreateSavedFrame(cx, lookup);
         if (!parentFrame)
             return false;
     }
 
     outSavedFrameStack.set(parentFrame);
     return true;
 }
 
--- a/js/src/vm/SavedStacks.h
+++ b/js/src/vm/SavedStacks.h
@@ -169,17 +169,17 @@ class SavedStacks {
     MOZ_MUST_USE bool copyAsyncStack(JSContext* cx, HandleObject asyncStack,
                                      HandleString asyncCause,
                                      MutableHandleSavedFrame adoptedStack,
                                      const mozilla::Maybe<size_t>& maxFrameCount);
     void sweep();
     void trace(JSTracer* trc);
     uint32_t count();
     void clear();
-    void chooseSamplingProbability(JSCompartment*);
+    void chooseSamplingProbability(JS::Realm* realm);
 
     // Set the sampling random number generator's state to |state0| and
     // |state1|. One or the other must be non-zero. See the comments for
     // mozilla::non_crypto::XorShift128PlusRNG::setState for details.
     void setRNGState(uint64_t state0, uint64_t state1) { bernoulli.setRandomState(state0, state1); }
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);