Bug 1013531 - Clarify the naming of the rooting analysis supression guards; r=sfink
authorTerrence Cole <terrence@mozilla.com>
Wed, 28 May 2014 17:34:36 -0700
changeset 185959 57014191cb434d704159cf4ef73086a10cf7f88c
parent 185958 ad3dfab38899fdb0bc382dc523b247f2eb538c51
child 185960 45a8e70514e497b9c2a803f6b82994a5df974d9a
push id44201
push usertcole@mozilla.com
push dateFri, 30 May 2014 21:13:01 +0000
treeherdermozilla-inbound@57014191cb43 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1013531
milestone32.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 1013531 - Clarify the naming of the rooting analysis supression guards; r=sfink
dom/bindings/BindingUtils.h
dom/bindings/CallbackObject.cpp
js/public/GCAPI.h
js/src/devtools/rootAnalysis/annotations.js
js/src/devtools/rootAnalysis/computeGCTypes.js
js/src/gc/GCRuntime.h
js/src/jsapi-tests/testGCExactRooting.cpp
js/src/jsgc.cpp
js/src/jsgcinlines.h
js/src/jsobj.h
js/src/jsweakmap.cpp
js/src/jsworkers.cpp
js/src/vm/ForkJoin.cpp
js/src/vm/ForkJoin.h
js/src/vm/SPSProfiler.cpp
js/src/vm/Stack.cpp
js/src/vm/StructuredClone.cpp
js/xpconnect/src/nsCxPusher.cpp
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -2712,25 +2712,22 @@ CreateGlobal(JSContext* aCx, T* aNative,
              JS::MutableHandle<JSObject*> aGlobal)
 {
   aOptions.setTrace(CreateGlobalOptions<T>::TraceGlobal);
 
   aGlobal.set(JS_NewGlobalObject(aCx, aClass, aPrincipal,
                                  JS::DontFireOnNewGlobalHook, aOptions));
   if (!aGlobal) {
     NS_WARNING("Failed to create global");
-    return nullptr;
+    return false;
   }
 
   JSAutoCompartment ac(aCx, aGlobal);
 
   {
-    JS::AutoAssertNoGC nogc;
-
-    // The setup of our global needs to be done before a GC happens.
     js::SetReservedSlot(aGlobal, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aNative));
     NS_ADDREF(aNative);
 
     aCache->SetIsDOMBinding();
     aCache->SetWrapper(aGlobal);
 
     dom::AllocateProtoAndIfaceCache(aGlobal,
                                     CreateGlobalOptions<T>::ProtoAndIfaceCacheKind);
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -76,17 +76,20 @@ CallbackObject::CallSetup::CallSetup(Cal
   // callable.
 
   // First, find the real underlying callback.
   JSObject* realCallback = js::UncheckedUnwrap(aCallback->CallbackPreserveColor());
   JSContext* cx = nullptr;
   nsIGlobalObject* globalObject = nullptr;
 
   {
-    JS::AutoAssertNoGC nogc;
+    // Bug 955660: we cannot do "proper" rooting here because we need the
+    // global to get a context. Everything here is simple getters that cannot
+    // GC, so just paper over the necessary dataflow inversion.
+    JS::AutoSuppressGCAnalysis nogc;
     if (mIsMainThread) {
       // Now get the global and JSContext for this callback.
       nsGlobalWindow* win = xpc::WindowGlobalOrNull(realCallback);
       if (win) {
         // Make sure that if this is a window it's the current inner, since the
         // nsIScriptContext and hence JSContext are associated with the outer
         // window.  Which means that if someone holds on to a function from a
         // now-unloaded document we'd have the new document as the script entry
--- a/js/public/GCAPI.h
+++ b/js/public/GCAPI.h
@@ -364,44 +364,68 @@ GetGCNumber();
  * The GC does not immediately return the unused memory freed by a collection
  * back to the system incase it is needed soon afterwards. This call forces the
  * GC to return this memory immediately.
  */
 extern JS_FRIEND_API(void)
 ShrinkGCBuffers(JSRuntime *rt);
 
 /*
- * Assert if any GC occured while this guard object was live. This is most
- * useful to help the exact rooting hazard analysis in complex regions, since
- * it cannot understand dataflow.
+ * Assert if a GC occurs while this class is live. This class does not disable
+ * the static rooting hazard analysis.
+ */
+class JS_PUBLIC_API(AutoAssertOnGC)
+{
+    JSRuntime *runtime;
+    size_t gcNumber;
+
+  public:
+    AutoAssertOnGC();
+    explicit AutoAssertOnGC(JSRuntime *rt);
+    ~AutoAssertOnGC();
+
+    static void VerifyIsSafeToGC(JSRuntime *rt);
+};
+
+/*
+ * Disable the static rooting hazard analysis in the live region, but assert if
+ * any GC occurs while this guard object is live. This is most useful to help
+ * the exact rooting hazard analysis in complex regions, since it cannot
+ * understand dataflow.
  *
  * Note: GC behavior is unpredictable even when deterministice and is generally
  *       non-deterministic in practice. The fact that this guard has not
  *       asserted is not a guarantee that a GC cannot happen in the guarded
  *       region. As a rule, anyone performing a GC unsafe action should
  *       understand the GC properties of all code in that region and ensure
  *       that the hazard analysis is correct for that code, rather than relying
  *       on this class.
  */
-class JS_PUBLIC_API(AutoAssertNoGC)
+class JS_PUBLIC_API(AutoSuppressGCAnalysis) : public AutoAssertOnGC
 {
-#ifdef JS_DEBUG
-    JSRuntime *runtime;
-    size_t gcNumber;
-
   public:
-    AutoAssertNoGC();
-    AutoAssertNoGC(JSRuntime *rt);
-    ~AutoAssertNoGC();
-#else
+    AutoSuppressGCAnalysis() : AutoAssertOnGC() {}
+    explicit AutoSuppressGCAnalysis(JSRuntime *rt) : AutoAssertOnGC(rt) {}
+};
+
+/*
+ * Place AutoCheckCannotGC in scopes that you believe can never GC. These
+ * annotations will be verified both dynamically via AutoAssertOnGC, and
+ * statically with the rooting hazard analysis (implemented by making the
+ * analysis consider AutoCheckCannotGC to be a GC pointer, and therefore
+ * complain if it is live across a GC call.) It is useful when dealing with
+ * internal pointers to GC things where the GC thing itself may not be present
+ * for the static analysis: e.g. acquiring inline chars from a JSString* on the
+ * heap.
+ */
+class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertOnGC
+{
   public:
-    /* Prevent unreferenced local warnings in opt builds. */
-    AutoAssertNoGC() {}
-    explicit AutoAssertNoGC(JSRuntime *) {}
-#endif
+    AutoCheckCannotGC() : AutoAssertOnGC() {}
+    explicit AutoCheckCannotGC(JSRuntime *rt) : AutoAssertOnGC(rt) {}
 };
 
 class JS_PUBLIC_API(ObjectPtr)
 {
     Heap<JSObject *> value;
 
   public:
     ObjectPtr() : value(nullptr) {}
--- a/js/src/devtools/rootAnalysis/annotations.js
+++ b/js/src/devtools/rootAnalysis/annotations.js
@@ -133,17 +133,17 @@ function ignoreEdgeAddressTaken(edge)
 
 // Ignore calls of these functions (so ignore any stack containing these)
 var ignoreFunctions = {
     "ptio.c:pt_MapError" : true,
     "je_malloc_printf" : true,
     "PR_ExplodeTime" : true,
     "PR_ErrorInstallTable" : true,
     "PR_SetThreadPrivate" : true,
-    "JSObject* js::GetWeakmapKeyDelegate(JSObject*)" : true, // FIXME: mark with AutoAssertNoGC instead
+    "JSObject* js::GetWeakmapKeyDelegate(JSObject*)" : true, // FIXME: mark with AutoSuppressGCAnalysis instead
     "uint8 NS_IsMainThread()" : true,
 
     // FIXME!
     "NS_LogInit": true,
     "NS_LogTerm": true,
     "NS_LogAddRef": true,
     "NS_LogRelease": true,
     "NS_LogCtor": true,
@@ -156,17 +156,17 @@ var ignoreFunctions = {
 
     // These are a little overzealous -- these destructors *can* GC if they end
     // up wrapping a pending exception. See bug 898815 for the heavyweight fix.
     "void js::AutoCompartment::~AutoCompartment(int32)" : true,
     "void JSAutoCompartment::~JSAutoCompartment(int32)" : true,
 
     // Bug 948646 - the only thing AutoJSContext's constructor calls
     // is an Init() routine whose entire body is covered with an
-    // AutoAssertNoGC. AutoSafeJSContext is the same thing, just with
+    // AutoSuppressGCAnalysis. AutoSafeJSContext is the same thing, just with
     // a different value for the 'aSafe' parameter.
     "void mozilla::AutoJSContext::AutoJSContext(mozilla::detail::GuardObjectNotifier*)" : true,
     "void mozilla::AutoSafeJSContext::~AutoSafeJSContext(int32)" : true,
 
     // And these are workarounds to avoid even more analysis work,
     // which would sadly still be needed even with bug 898815.
     "void js::AutoCompartment::AutoCompartment(js::ExclusiveContext*, JSCompartment*)": true,
 };
@@ -225,17 +225,17 @@ function isRootedPointerTypeName(name)
 
     return name.startsWith('Rooted') || name.startsWith('PersistentRooted');
 }
 
 function isSuppressConstructor(name)
 {
     return name.indexOf("::AutoSuppressGC") != -1
         || name.indexOf("::AutoEnterAnalysis") != -1
-        || name.indexOf("::AutoAssertNoGC") != -1
+        || name.indexOf("::AutoSuppressGCAnalysis") != -1
         || name.indexOf("::AutoIgnoreRootingHazards") != -1;
 }
 
 // nsISupports subclasses' methods may be scriptable (or overridden
 // via binary XPCOM), and so may GC. But some fields just aren't going
 // to get overridden with something that can GC.
 function isOverridableField(initialCSU, csu, field)
 {
--- a/js/src/devtools/rootAnalysis/computeGCTypes.js
+++ b/js/src/devtools/rootAnalysis/computeGCTypes.js
@@ -128,16 +128,17 @@ addGCType('js::ObjectImpl');
 addGCType('JSString');
 addGCType('js::Shape');
 addGCType('js::BaseShape');
 addGCType('JSScript');
 addGCType('js::LazyScript');
 addGCType('js::ion::IonCode');
 addGCPointer('JS::Value');
 addGCPointer('jsid');
+addGCPointer('JS::AutoCheckCannotGC');
 
 function explain(csu, indent, seen) {
     if (!seen)
         seen = Set();
     seen.add(csu);
     if (!(csu in gcFields))
         return;
     if (gcFields[csu].has('<annotation>')) {
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -532,16 +532,24 @@ class GCRuntime
     size_t                systemPageSize;
 
     /* The OS allocation granularity may not match the page size. */
     size_t                systemAllocGranularity;
 
     /* Strong references on scripts held for PCCount profiling API. */
     js::ScriptAndCountsVector *scriptAndCountsVector;
 
+    /*
+     * Some regions of code are hard for the static rooting hazard analysis to
+     * understand. In those cases, we trade the static analysis for a dynamic
+     * analysis. When this is non-zero, we should assert if we trigger, or
+     * might trigger, a GC.
+     */
+    int inUnsafeRegion;
+
   private:
     /* Always preserve JIT code during GCs, for testing. */
     bool                  alwaysPreserveCode;
 
 #ifdef DEBUG
     size_t                noGCOrAllocationCheck;
 #endif
 
--- a/js/src/jsapi-tests/testGCExactRooting.cpp
+++ b/js/src/jsapi-tests/testGCExactRooting.cpp
@@ -16,8 +16,22 @@ BEGIN_TEST(testGCExactRooting)
 
     /* Use the objects we just created to ensure that they are still alive. */
     JS_DefineProperty(cx, rootCx, "foo", JS::UndefinedHandleValue, 0);
     JS_DefineProperty(cx, rootRt, "foo", JS::UndefinedHandleValue, 0);
 
     return true;
 }
 END_TEST(testGCExactRooting)
+
+BEGIN_TEST(testGCSuppressions)
+{
+    JS::AutoAssertOnGC nogc;
+    JS::AutoCheckCannotGC checkgc;
+    JS::AutoSuppressGCAnalysis noanalysis;
+
+    JS::AutoAssertOnGC nogcRt(cx->runtime());
+    JS::AutoCheckCannotGC checkgcRt(cx->runtime());
+    JS::AutoSuppressGCAnalysis noanalysisRt(cx->runtime());
+
+    return true;
+}
+END_TEST(testGCSuppressions)
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -183,16 +183,17 @@
 # include <unistd.h>
 #endif
 
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jsobj.h"
+#include "jsprf.h"
 #include "jsscript.h"
 #include "jstypes.h"
 #include "jsutil.h"
 #include "jswatchpoint.h"
 #include "jsweakmap.h"
 #ifdef XP_WIN
 # include "jswin.h"
 #endif
@@ -1109,23 +1110,24 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
 #endif
     validate(true),
     fullCompartmentChecks(false),
     gcCallback(nullptr),
     sliceCallback(nullptr),
     mallocBytes(0),
     mallocGCTriggered(false),
     scriptAndCountsVector(nullptr),
+    helperState(rt),
     alwaysPreserveCode(false),
 #ifdef DEBUG
     noGCOrAllocationCheck(0),
 #endif
     lock(nullptr),
     lockOwner(nullptr),
-    helperState(rt)
+    inUnsafeRegion(0)
 {
 }
 
 #ifdef JS_GC_ZEAL
 
 extern void
 js::SetGCZeal(JSRuntime *rt, uint8_t zeal, uint32_t frequency)
 {
@@ -4308,16 +4310,19 @@ AutoGCSession::AutoGCSession(GCRuntime *
     gc->isNeeded = false;
     gc->interFrameGC = true;
 
     gc->number++;
 
     // It's ok if threads other than the main thread have suppressGC set, as
     // they are operating on zones which will not be collected from here.
     JS_ASSERT(!gc->rt->mainThread.suppressGC);
+
+    // Assert if this is a GC unsafe region.
+    JS::AutoAssertOnGC::VerifyIsSafeToGC(gc->rt);
 }
 
 AutoGCSession::~AutoGCSession()
 {
     if (canceled)
         return;
 
 #ifndef JS_MORE_DETERMINISTIC
@@ -5598,37 +5603,55 @@ js::gc::AssertGCThingHasType(js::gc::Cel
 JS_FRIEND_API(size_t)
 JS::GetGCNumber()
 {
     JSRuntime *rt = js::TlsPerThreadData.get()->runtimeFromMainThread();
     if (!rt)
         return 0;
     return rt->gc.number;
 }
-
-JS::AutoAssertNoGC::AutoAssertNoGC()
+#endif
+
+JS::AutoAssertOnGC::AutoAssertOnGC()
   : runtime(nullptr), gcNumber(0)
 {
     js::PerThreadData *data = js::TlsPerThreadData.get();
     if (data) {
         /*
          * GC's from off-thread will always assert, so off-thread is implicitly
-         * AutoAssertNoGC. We still need to allow AutoAssertNoGC to be used in
+         * AutoAssertOnGC. We still need to allow AutoAssertOnGC to be used in
          * code that works from both threads, however. We also use this to
          * annotate the off thread run loops.
          */
         runtime = data->runtimeIfOnOwnerThread();
-        if (runtime)
+        if (runtime) {
             gcNumber = runtime->gc.number;
+            ++runtime->gc.inUnsafeRegion;
+        }
     }
 }
 
-JS::AutoAssertNoGC::AutoAssertNoGC(JSRuntime *rt)
+JS::AutoAssertOnGC::AutoAssertOnGC(JSRuntime *rt)
   : runtime(rt), gcNumber(rt->gc.number)
 {
-}
-
-JS::AutoAssertNoGC::~AutoAssertNoGC()
-{
-    if (runtime)
-        MOZ_ASSERT(gcNumber == runtime->gc.number, "GC ran inside an AutoAssertNoGC scope.");
-}
-#endif
+    ++rt->gc.inUnsafeRegion;
+}
+
+JS::AutoAssertOnGC::~AutoAssertOnGC()
+{
+    if (runtime) {
+        --runtime->gc.inUnsafeRegion;
+        MOZ_ASSERT(runtime->gc.inUnsafeRegion >= 0);
+
+        /*
+         * The following backstop assertion should never fire: if we bumped the
+         * gcNumber, we should have asserted because inUnsafeRegion was true.
+         */
+        MOZ_ASSERT(gcNumber == runtime->gc.number, "GC ran inside an AutoAssertOnGC scope.");
+    }
+}
+
+/* static */ void
+JS::AutoAssertOnGC::VerifyIsSafeToGC(JSRuntime *rt)
+{
+    if (rt->gc.inUnsafeRegion > 0)
+        MOZ_CRASH("[AutoAssertOnGC] possible GC in GC-unsafe region");
+}
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -499,16 +499,20 @@ CheckAllocatorState(ThreadSafeContext *c
     JS_ASSERT_IF(rt->isAtomsCompartment(ncx->compartment()),
                  kind == FINALIZE_STRING ||
                  kind == FINALIZE_FAT_INLINE_STRING ||
                  kind == FINALIZE_JITCODE);
     JS_ASSERT(!rt->isHeapBusy());
     JS_ASSERT(rt->gc.isAllocAllowed());
 #endif
 
+    // Crash if we perform a GC action when it is not safe.
+    if (allowGC && !rt->mainThread.suppressGC)
+        JS::AutoAssertOnGC::VerifyIsSafeToGC(rt);
+
     // For testing out of memory conditions
     if (!PossiblyFail()) {
         js_ReportOutOfMemory(cx);
         return false;
     }
 
     if (allowGC) {
 #ifdef JS_GC_ZEAL
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1198,17 +1198,17 @@ js_IsCallable(const js::Value &v)
 {
     return v.isObject() && v.toObject().isCallable();
 }
 
 inline JSObject *
 GetInnerObject(JSObject *obj)
 {
     if (js::InnerObjectOp op = obj->getClass()->ext.innerObject) {
-        JS::AutoAssertNoGC nogc;
+        JS::AutoSuppressGCAnalysis nogc;
         return op(obj);
     }
     return obj;
 }
 
 inline JSObject *
 GetOuterObject(JSContext *cx, js::HandleObject obj)
 {
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -160,17 +160,17 @@ WeakMapBase::removeWeakMapFromList(WeakM
 bool
 ObjectValueMap::findZoneEdges()
 {
     /*
      * For unmarked weakmap keys with delegates in a different zone, add a zone
      * edge to ensure that the delegate zone does finish marking after the key
      * zone.
      */
-    JS::AutoAssertNoGC nogc;
+    JS::AutoSuppressGCAnalysis nogc;
     Zone *mapZone = compartment->zone();
     for (Range r = all(); !r.empty(); r.popFront()) {
         JSObject *key = r.front().key();
         if (key->isMarked(BLACK) && !key->isMarked(GRAY))
             continue;
         JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp;
         if (!op)
             continue;
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -1042,17 +1042,17 @@ HelperThread::handleGCHelperWorkload()
     }
 
     gcHelperState = nullptr;
 }
 
 void
 HelperThread::threadLoop()
 {
-    JS::AutoAssertNoGC nogc;
+    JS::AutoSuppressGCAnalysis nogc;
     AutoLockHelperThreadState lock;
 
     js::TlsPerThreadData.set(threadData.addr());
 
     // Compute the thread's stack limit, for over-recursed checks.
     uintptr_t stackLimit = GetNativeStackBase();
 #if JS_STACK_GROWTH_DIRECTION > 0
     stackLimit += HELPER_STACK_QUOTA;
--- a/js/src/vm/ForkJoin.cpp
+++ b/js/src/vm/ForkJoin.cpp
@@ -1498,25 +1498,25 @@ ForkJoinShared::executeFromMainThread(Th
 }
 
 void
 ForkJoinShared::executePortion(PerThreadData *perThread, ThreadPoolWorker *worker)
 {
     // WARNING: This code runs ON THE PARALLEL WORKER THREAD.
     // Be careful when accessing cx_.
 
-    // ForkJoinContext already contains an AutoAssertNoGC; however, the analysis
-    // does not propagate this type information. We duplicate the assertion
-    // here for maximum clarity.
-    JS::AutoAssertNoGC nogc(runtime());
-
     Allocator *allocator = allocators_[worker->id()];
     ForkJoinContext cx(perThread, worker, allocator, this, &records_[worker->id()]);
     AutoSetForkJoinContext autoContext(&cx);
 
+    // ForkJoinContext already contains an AutoSuppressGCAnalysis; however, the
+    // analysis does not propagate this type information. We duplicate the
+    // assertion here for maximum clarity.
+    JS::AutoSuppressGCAnalysis nogc;
+
 #ifdef DEBUG
     // Set the maximum worker and slice number for prettier spewing.
     cx.maxWorkerId = threadPool_->numWorkers();
 #endif
 
     Spew(SpewOps, "Up");
 
     // Make a new IonContext for the slice, which is needed if we need to
@@ -1617,17 +1617,17 @@ ForkJoinContext::ForkJoinContext(PerThre
                                  ParallelBailoutRecord *bailoutRecord)
   : ThreadSafeContext(shared->runtime(), perThreadData, Context_ForkJoin),
     bailoutRecord(bailoutRecord),
     targetRegionStart(nullptr),
     targetRegionEnd(nullptr),
     shared_(shared),
     worker_(worker),
     acquiredJSContext_(false),
-    nogc_(shared->runtime())
+    nogc_()
 {
     /*
      * Unsafely set the zone. This is used to track malloc counters and to
      * trigger GCs and is otherwise not thread-safe to access.
      */
     zone_ = shared->zone();
 
     /*
--- a/js/src/vm/ForkJoin.h
+++ b/js/src/vm/ForkJoin.h
@@ -421,17 +421,17 @@ class ForkJoinContext : public ThreadSaf
     ForkJoinShared *const shared_;
 
     ThreadPoolWorker *worker_;
 
     bool acquiredJSContext_;
 
     // ForkJoinContext is allocated on the stack. It would be dangerous to GC
     // with it live because of the GC pointer fields stored in the context.
-    JS::AutoAssertNoGC nogc_;
+    JS::AutoSuppressGCAnalysis nogc_;
 };
 
 // Locks a JSContext for its scope. Be very careful, because locking a
 // JSContext does *not* allow you to safely mutate the data in the
 // JSContext unless you can guarantee that any of the other threads
 // that want to access that data will also acquire the lock, which is
 // generally not the case. For example, the lock is used in the IC
 // code to allow us to atomically patch up the dispatch table, but we
--- a/js/src/vm/SPSProfiler.cpp
+++ b/js/src/vm/SPSProfiler.cpp
@@ -138,17 +138,17 @@ SPSProfiler::onScriptFinalized(JSScript 
     }
 }
 
 void
 SPSProfiler::markEvent(const char *event)
 {
     JS_ASSERT(enabled());
     if (eventMarker_) {
-        JS::AutoAssertNoGC nogc;
+        JS::AutoSuppressGCAnalysis nogc;
         eventMarker_(event);
     }
 }
 
 bool
 SPSProfiler::enter(JSScript *script, JSFunction *maybeFun)
 {
     const char *str = profileString(script, maybeFun);
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -554,17 +554,17 @@ FrameIter::settleOnActivation()
             continue;
         }
 
         // If the caller supplied principals, only show activations which are subsumed (of the same
         // origin or of an origin accessible) by these principals.
         if (data_.principals_) {
             JSContext *cx = data_.cx_->asJSContext();
             if (JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes) {
-                JS::AutoAssertNoGC nogc;
+                JS::AutoSuppressGCAnalysis nogc;
                 if (!subsumes(data_.principals_, activation->compartment()->principals)) {
                     ++data_.activations_;
                     continue;
                 }
             }
         }
 
 #ifdef JS_ION
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -365,17 +365,17 @@ Discard(uint64_t *buffer, size_t nbytes,
     SCInput::getPair(point++, &tag, &data);
     if (tag != SCTAG_TRANSFER_MAP_HEADER)
         return;
 
     if (TransferableMapHeader(data) == SCTAG_TM_TRANSFERRED)
         return;
 
     // freeTransfer should not GC
-    JS::AutoAssertNoGC nogc;
+    JS::AutoSuppressGCAnalysis nogc;
 
     uint64_t numTransferables = LittleEndian::readUint64(point++);
     while (numTransferables--) {
         uint32_t ownership;
         SCInput::getPair(point++, &tag, &ownership);
         JS_ASSERT(tag >= SCTAG_TRANSFER_MAP_PENDING_ENTRY);
 
         void *content;
--- a/js/xpconnect/src/nsCxPusher.cpp
+++ b/js/xpconnect/src/nsCxPusher.cpp
@@ -178,17 +178,17 @@ AutoJSContext::AutoJSContext(bool aSafe 
   : mCx(nullptr)
 {
   Init(aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT);
 }
 
 void
 AutoJSContext::Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
 {
-  JS::AutoAssertNoGC nogc;
+  JS::AutoSuppressGCAnalysis nogc;
   MOZ_ASSERT(!mCx, "mCx should not be initialized!");
 
   MOZ_GUARD_OBJECT_NOTIFIER_INIT;
 
   nsXPConnect *xpc = nsXPConnect::XPConnect();
   if (!aSafe) {
     mCx = xpc->GetCurrentJSContext();
   }