Bug 687724 (part 1) - Convert JSCompartment::gcRunning to gcState. r=wmccloskey.
authorNicholas Nethercote <nnethercote@mozilla.com>
Tue, 03 Jul 2012 17:24:03 -0700
changeset 98498 869b97c469b5
parent 98497 478b9ac3a85f
child 98499 7919de7e468c
push id23059
push usereakhgari@mozilla.com
push dateFri, 06 Jul 2012 14:45:18 +0000
treeherdermozilla-central@a8f682801a6d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswmccloskey
bugs687724
milestone16.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 687724 (part 1) - Convert JSCompartment::gcRunning to gcState. r=wmccloskey.
js/src/jsapi.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jscntxtinlines.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsfriendapi.cpp
js/src/jsgc.cpp
js/src/jsgcinlines.h
js/src/jsinferinlines.h
js/src/jsopcode.cpp
js/src/jspropertycache.cpp
js/src/jsscriptinlines.h
js/src/jsxml.cpp
js/src/vm/Debugger.cpp
js/src/vm/ObjectImpl-inl.h
js/src/vm/RegExpObject.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -213,44 +213,44 @@ TryArgumentFormatter(JSContext *cx, cons
             return map->formatter(cx, format, fromJS, vpp, app);
         }
     }
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
     return JS_FALSE;
 }
 
 static void
-AssertNoGC(JSRuntime *rt)
-{
-    JS_ASSERT(!rt->gcRunning);
+AssertHeapIsIdle(JSRuntime *rt)
+{
+    JS_ASSERT(rt->heapState == JSRuntime::Idle);
 }
 
 static void
-AssertNoGC(JSContext *cx)
-{
-    AssertNoGC(cx->runtime);
+AssertHeapIsIdle(JSContext *cx)
+{
+    AssertHeapIsIdle(cx->runtime);
 }
 
 static void
-AssertNoGCOrFlatString(JSContext *cx, JSString *str)
+AssertHeapIsIdleOrStringIsFlat(JSContext *cx, JSString *str)
 {
     /*
      * We allow some functions to be called during a GC as long as the argument
      * is a flat string, since that will not cause allocation.
      */
-    JS_ASSERT_IF(cx->runtime->gcRunning, str->isFlat());
+    JS_ASSERT_IF(cx->runtime->isHeapBusy(), str->isFlat());
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ConvertArguments(JSContext *cx, unsigned argc, jsval *argv, const char *format, ...)
 {
     va_list ap;
     JSBool ok;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
 
     va_start(ap, format);
     ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
     va_end(ap);
     return ok;
 }
 
 JS_PUBLIC_API(JSBool)
@@ -258,17 +258,17 @@ JS_ConvertArgumentsVA(JSContext *cx, uns
 {
     jsval *sp;
     JSBool required;
     char c;
     double d;
     JSString *str;
     JSObject *obj;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, JSValueArray(argv - 2, argc + 2));
     sp = argv;
     required = JS_TRUE;
     while ((c = *format++) != '\0') {
         if (isspace(c))
             continue;
         if (c == '/') {
@@ -415,17 +415,17 @@ JS_RemoveArgumentFormatter(JSContext *cx
 JS_PUBLIC_API(JSBool)
 JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
 {
     JSBool ok;
     JSObject *obj;
     JSString *str;
     double d;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
     switch (type) {
       case JSTYPE_VOID:
         *vp = JSVAL_VOID;
         ok = JS_TRUE;
         break;
       case JSTYPE_OBJECT:
@@ -461,62 +461,62 @@ JS_ConvertValue(JSContext *cx, jsval v, 
       }
     }
     return ok;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
     return js_ValueToObjectOrNull(cx, v, objp);
 }
 
 JS_PUBLIC_API(JSFunction *)
 JS_ValueToFunction(JSContext *cx, jsval v)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
     return ReportIfNotFunction(cx, v);
 }
 
 JS_PUBLIC_API(JSFunction *)
 JS_ValueToConstructor(JSContext *cx, jsval v)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
     return ReportIfNotFunction(cx, v);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_ValueToString(JSContext *cx, jsval v)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
     return ToString(cx, v);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_ValueToSource(JSContext *cx, jsval v)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
     return js_ValueToSource(cx, v);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToNumber(JSContext *cx, jsval v, double *dp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
 
     return ToNumber(cx, v, dp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DoubleIsInt32(double d, int32_t *ip)
@@ -534,38 +534,38 @@ JS_PUBLIC_API(uint32_t)
 JS_DoubleToUint32(double d)
 {
     return ToUint32(d);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32_t *ip)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
 
     RootedValue value(cx, v);
     return ToInt32(cx, value, ip);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32_t *ip)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
 
     return ToUint32(cx, v, (uint32_t *)ip);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToInt32(JSContext *cx, jsval v, int32_t *ip)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
 
     if (v.isInt32()) {
         *ip = v.toInt32();
         return true;
     }
 
@@ -584,80 +584,80 @@ JS_ValueToInt32(JSContext *cx, jsval v, 
 
     *ip = (int32_t) floor(d + 0.5);  /* Round to nearest */
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToUint16(JSContext *cx, jsval v, uint16_t *ip)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
 
     return ValueToUint16(cx, v, (uint16_t *)ip);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
     *bp = js_ValueToBoolean(v);
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSType)
 JS_TypeOfValue(JSContext *cx, jsval v)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
     return TypeOfValue(cx, v);
 }
 
 JS_PUBLIC_API(const char *)
 JS_GetTypeName(JSContext *cx, JSType type)
 {
     if ((unsigned)type >= (unsigned)JSTYPE_LIMIT)
         return NULL;
     return JS_TYPE_STR(type);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v1, v2);
     bool eq;
     if (!StrictlyEqual(cx, v1, v2, &eq))
         return false;
     *equal = eq;
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_LooselyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v1, v2);
     bool eq;
     if (!LooselyEqual(cx, v1, v2, &eq))
         return false;
     *equal = eq;
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v1, v2);
     bool s;
     if (!SameValue(cx, v1, v2, &s))
         return false;
     *same = s;
     return true;
 }
@@ -734,17 +734,17 @@ JSRuntime::JSRuntime()
     gcDisableStrictProxyCheckingCount(0),
     gcIncrementalState(gc::NO_INCREMENTAL),
     gcLastMarkSlice(false),
     gcInterFrameGC(0),
     gcSliceBudget(SliceBudget::Unlimited),
     gcIncrementalEnabled(true),
     gcExactScanningEnabled(true),
     gcPoke(false),
-    gcRunning(false),
+    heapState(Idle),
 #ifdef JS_GC_ZEAL
     gcZeal_(0),
     gcZealFrequency(0),
     gcNextScheduled(0),
     gcDeterministicOnly(false),
     gcIncrementalLimit(0),
 #endif
     gcCallback(NULL),
@@ -1350,17 +1350,17 @@ JS_SetWrapObjectCallbacks(JSRuntime *rt,
     rt->sameCompartmentWrapObjectCallback = sccallback;
     rt->preWrapObjectCallback = precallback;
     return old;
 }
 
 JS_PUBLIC_API(JSCrossCompartmentCall *)
 JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     JS_ASSERT(target);
     AutoCompartment *call = cx->new_<AutoCompartment>(cx, target);
     if (!call)
         return NULL;
     if (!call->enter()) {
         Foreground::delete_(call);
@@ -1381,45 +1381,45 @@ Class dummy_class = {
     JS_ConvertStub
 };
 
 } /*namespace js */
 
 JS_PUBLIC_API(JSCrossCompartmentCall *)
 JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     GlobalObject &global = target->compartment()->global();
     return JS_EnterCrossCompartmentCall(cx, &global);
 }
 
 JS_PUBLIC_API(JSCrossCompartmentCall *)
 JS_EnterCrossCompartmentCallStackFrame(JSContext *cx, JSStackFrame *target)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     return JS_EnterCrossCompartmentCall(cx, &Valueify(target)->global());
 }
 
 JS_PUBLIC_API(void)
 JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
 {
     AutoCompartment *realcall = reinterpret_cast<AutoCompartment *>(call);
-    AssertNoGC(realcall->context);
+    AssertHeapIsIdle(realcall->context);
     CHECK_REQUEST(realcall->context);
     realcall->leave();
     Foreground::delete_(realcall);
 }
 
 bool
 JSAutoEnterCompartment::enter(JSContext *cx, JSObject *target)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     JS_ASSERT(state == STATE_UNENTERED);
     if (cx->compartment == target->compartment()) {
         state = STATE_SAME_COMPARTMENT;
         return true;
     }
 
     JS_STATIC_ASSERT(sizeof(bytes) == sizeof(AutoCompartment));
     CHECK_REQUEST(cx);
@@ -1493,25 +1493,25 @@ JS_PUBLIC_API(void *)
 JS_GetCompartmentPrivate(JSCompartment *compartment)
 {
     return compartment->data;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_WrapObject(JSContext *cx, JSObject **objp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return cx->compartment->wrap(cx, objp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_WrapValue(JSContext *cx, jsval *vp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return cx->compartment->wrap(cx, vp);
 }
 
 /*
  * Identity remapping. Not for casual consumers.
  *
  * Normally, an object's contents and its identity are inextricably linked.
@@ -1537,17 +1537,17 @@ JS_WrapValue(JSContext *cx, jsval *vp)
  *
  * Second, the new identity object's contents will be those of |target|. A swap()
  * is used to make this happen if an object other than |target| is used.
  */
 
 JS_PUBLIC_API(JSObject *)
 JS_TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     JS_ASSERT(origobj != target);
     JS_ASSERT(!IsCrossCompartmentWrapper(origobj));
     JS_ASSERT(!IsCrossCompartmentWrapper(target));
 
     JSCompartment *destination = target->compartment();
     WrapperMap &map = destination->crossCompartmentWrappers;
     Value origv = ObjectValue(*origobj);
     JSObject *newIdentity;
@@ -1609,17 +1609,17 @@ JS_TransplantObject(JSContext *cx, JSObj
  */
 JS_FRIEND_API(JSObject *)
 js_TransplantObjectWithWrapper(JSContext *cx,
                                JSObject *origobj,
                                JSObject *origwrapper,
                                JSObject *targetobj,
                                JSObject *targetwrapper)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     JS_ASSERT(!IsCrossCompartmentWrapper(origobj));
     JS_ASSERT(!IsCrossCompartmentWrapper(origwrapper));
     JS_ASSERT(!IsCrossCompartmentWrapper(targetobj));
     JS_ASSERT(!IsCrossCompartmentWrapper(targetwrapper));
 
     JSObject *newWrapper;
     JSCompartment *destination = targetobj->compartment();
     WrapperMap &map = destination->crossCompartmentWrappers;
@@ -1687,29 +1687,29 @@ JS_PUBLIC_API(JSObject *)
 JS_GetGlobalObject(JSContext *cx)
 {
     return cx->globalObject;
 }
 
 JS_PUBLIC_API(void)
 JS_SetGlobalObject(JSContext *cx, JSObject *obj)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     cx->globalObject = obj;
     if (!cx->hasfp())
         cx->resetCompartment();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_InitStandardClasses(JSContext *cx, JSObject *obj)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     /*
      * JS_SetGlobalObject might or might not change cx's compartment, so call
      * it before assertSameCompartment. (The API contract is that *after* this,
      * cx and obj must be in the same compartment.)
      */
     if (!cx->globalObject)
@@ -1868,17 +1868,17 @@ JS_ResolveStandardClass(JSContext *cx, J
     JSString *idstr;
     JSRuntime *rt;
     JSAtom *atom;
     JSStdName *stdnm;
     unsigned i;
 
     RootedObject obj(cx, obj_);
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     *resolved = false;
 
     rt = cx->runtime;
     if (!rt->hasContexts() || !JSID_IS_ATOM(id))
         return true;
 
@@ -1963,17 +1963,17 @@ JS_ResolveStandardClass(JSContext *cx, J
         *resolved = true;
     }
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj_)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj_);
 
     RootedObject obj(cx, obj_);
 
     /*
      * Check whether we need to bind 'undefined' and define it if so.
      * Since ES5 15.1.1.3 undefined can't be deleted.
@@ -2067,17 +2067,17 @@ JS_PUBLIC_API(JSIdArray *)
 JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj, JSIdArray *ida)
 {
     JSRuntime *rt;
     int i, j, k;
     PropertyName *name;
     JSBool found;
     JSClassInitializerOp init;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, ida);
     rt = cx->runtime;
     if (ida) {
         i = ida->length;
     } else {
         ida = NewIdArray(cx, 8);
         if (!ida)
@@ -2128,17 +2128,17 @@ JS_EnumerateResolvedStandardClasses(JSCo
 #undef CLASP
 #undef EAGER_ATOM
 #undef EAGER_CLASS_ATOM
 #undef EAGER_ATOM_CLASP
 
 JS_PUBLIC_API(JSBool)
 JS_GetClassObject(JSContext *cx, JSObject *obj_, JSProtoKey key, JSObject **objp_)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     RootedObject obj(cx, obj_);
     RootedObject objp(cx);
     assertSameCompartment(cx, obj);
     bool result = js_GetClassObject(cx, obj, key, &objp);
     *objp_ = objp;
     return result;
 }
@@ -2157,33 +2157,33 @@ JS_GetFunctionPrototype(JSContext *cx, J
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, forObj);
     return forObj->global().getOrCreateFunctionPrototype(cx);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     assertSameCompartment(cx, obj);
     return &obj->global();
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetGlobalForScopeChain(JSContext *cx)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return GetGlobalForScopeChain(cx);
 }
 
 JS_PUBLIC_API(jsval)
 JS_ComputeThis(JSContext *cx, jsval *vp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     assertSameCompartment(cx, JSValueArray(vp, 2));
     CallReceiver call = CallReceiverFromVp(vp);
     if (!BoxNonStrictThis(cx, call))
         return JSVAL_NULL;
     return call.thisv();
 }
 
 JS_PUBLIC_API(void)
@@ -2196,25 +2196,25 @@ JS_PUBLIC_API(void)
 JS_FreeInCompartment(JSCompartment *comp, size_t nbytes)
 {
     comp->freeInCompartment(nbytes);
 }
 
 JS_PUBLIC_API(void *)
 JS_malloc(JSContext *cx, size_t nbytes)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return cx->malloc_(nbytes);
 }
 
 JS_PUBLIC_API(void *)
 JS_realloc(JSContext *cx, void *p, size_t nbytes)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return cx->realloc_(p, nbytes);
 }
 
 JS_PUBLIC_API(void)
 JS_free(JSContext *cx, void *p)
 {
     return cx->free_(p);
@@ -2236,103 +2236,103 @@ JS_PUBLIC_API(void)
 JS_updateMallocCounter(JSContext *cx, size_t nbytes)
 {
     return cx->runtime->updateMallocCounter(cx, nbytes);
 }
 
 JS_PUBLIC_API(char *)
 JS_strdup(JSContext *cx, const char *s)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     size_t n = strlen(s) + 1;
     void *p = cx->malloc_(n);
     if (!p)
         return NULL;
     return (char *)js_memcpy(p, s, n);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_NewNumberValue(JSContext *cx, double d, jsval *rval)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     d = JS_CANONICALIZE_NAN(d);
     rval->setNumber(d);
     return JS_TRUE;
 }
 
 #undef JS_AddRoot
 
 JS_PUBLIC_API(JSBool)
 JS_AddValueRoot(JSContext *cx, jsval *vp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return js_AddRoot(cx, vp, NULL);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_AddStringRoot(JSContext *cx, JSString **rp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return js_AddGCThingRoot(cx, (void **)rp, NULL);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_AddObjectRoot(JSContext *cx, JSObject **rp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return js_AddGCThingRoot(cx, (void **)rp, NULL);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_AddGCThingRoot(JSContext *cx, void **rp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return js_AddGCThingRoot(cx, (void **)rp, NULL);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_AddNamedValueRoot(JSContext *cx, jsval *vp, const char *name)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return js_AddRoot(cx, vp, name);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_AddNamedStringRoot(JSContext *cx, JSString **rp, const char *name)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return js_AddGCThingRoot(cx, (void **)rp, name);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return js_AddGCThingRoot(cx, (void **)rp, name);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_AddNamedScriptRoot(JSContext *cx, JSScript **rp, const char *name)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return js_AddGCThingRoot(cx, (void **)rp, name);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_AddNamedGCThingRoot(JSContext *cx, void **rp, const char *name)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return js_AddGCThingRoot(cx, (void **)rp, name);
 }
 
 /* We allow unrooting from finalizers within the GC */
 
 JS_PUBLIC_API(void)
 JS_RemoveValueRoot(JSContext *cx, jsval *vp)
@@ -2416,64 +2416,64 @@ JS_MapGCRoots(JSRuntime *rt, JSGCRootMap
     return js_MapGCRoots(rt, map, data);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_LockGCThing(JSContext *cx, void *thing)
 {
     JSBool ok;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     ok = js_LockGCThingRT(cx->runtime, thing);
     if (!ok)
         JS_ReportOutOfMemory(cx);
     return ok;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_LockGCThingRT(JSRuntime *rt, void *thing)
 {
     return js_LockGCThingRT(rt, thing);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_UnlockGCThing(JSContext *cx, void *thing)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     js_UnlockGCThingRT(cx->runtime, thing);
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
 {
     js_UnlockGCThingRT(rt, thing);
     return true;
 }
 
 JS_PUBLIC_API(void)
 JS_SetExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
 {
-    AssertNoGC(rt);
+    AssertHeapIsIdle(rt);
     rt->gcBlackRootsTraceOp = traceOp;
     rt->gcBlackRootsData = data;
 }
 
 JS_PUBLIC_API(void)
 JS_TracerInit(JSTracer *trc, JSRuntime *rt, JSTraceCallback callback)
 {
     InitTracer(trc, rt, callback);
 }
 
 JS_PUBLIC_API(void)
 JS_TraceRuntime(JSTracer *trc)
 {
-    AssertNoGC(trc->runtime);
+    AssertHeapIsIdle(trc->runtime);
     TraceRuntime(trc);
 }
 
 JS_PUBLIC_API(void)
 JS_TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind)
 {
     js::TraceChildren(trc, thing, kind);
 }
@@ -2854,38 +2854,38 @@ extern JS_PUBLIC_API(JSBool)
 JS_IsGCMarkingTracer(JSTracer *trc)
 {
     return IS_GC_MARKING_TRACER(trc);
 }
 
 JS_PUBLIC_API(void)
 JS_GC(JSRuntime *rt)
 {
-    AssertNoGC(rt);
+    AssertHeapIsIdle(rt);
     PrepareForFullGC(rt);
     GC(rt, GC_NORMAL, gcreason::API);
 }
 
 JS_PUBLIC_API(void)
 JS_MaybeGC(JSContext *cx)
 {
     MaybeGC(cx);
 }
 
 JS_PUBLIC_API(void)
 JS_SetGCCallback(JSRuntime *rt, JSGCCallback cb)
 {
-    AssertNoGC(rt);
+    AssertHeapIsIdle(rt);
     rt->gcCallback = cb;
 }
 
 JS_PUBLIC_API(void)
 JS_SetFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb)
 {
-    AssertNoGC(rt);
+    AssertHeapIsIdle(rt);
     rt->gcFinalizeCallback = cb;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_IsAboutToBeFinalized(void *thing)
 {
     gc::Cell *t = static_cast<gc::Cell *>(thing);
     bool isMarked = IsCellMarked(&t);
@@ -2959,17 +2959,17 @@ JS_GetGCParameterForThread(JSContext *cx
     JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
     return 0;
 }
 
 JS_PUBLIC_API(JSString *)
 JS_NewExternalString(JSContext *cx, const jschar *chars, size_t length,
                      const JSStringFinalizer *fin)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     JSString *s = JSExternalString::new_(cx, chars, length, fin);
     Probes::createString(cx, s, length);
     return s;
 }
 
 extern JS_PUBLIC_API(JSBool)
 JS_IsExternalString(JSString *str)
@@ -3026,36 +3026,36 @@ JS_PUBLIC_API(void)
 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
 {
     DestroyIdArray(cx->runtime->defaultFreeOp(), ida);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
     return ValueToId(cx, v, idp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     *vp = IdToJsval(id);
     assertSameCompartment(cx, *vp);
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     JS_ASSERT(obj != NULL);
     JS_ASSERT(hint == JSTYPE_VOID || hint == JSTYPE_STRING || hint == JSTYPE_NUMBER);
     return obj->defaultValue(cx, hint, vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_PropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, jsval *vp)
@@ -3092,17 +3092,17 @@ JS_ConvertStub(JSContext *cx, JSHandleOb
 JS_PUBLIC_API(JSObject *)
 JS_InitClass(JSContext *cx, JSObject *obj_, JSObject *parent_proto,
              JSClass *clasp, JSNative constructor, unsigned nargs,
              JSPropertySpec *ps, JSFunctionSpec *fs,
              JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
 {
     RootedObject obj(cx, obj_);
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, parent_proto);
     return js_InitClass(cx, obj, parent_proto, Valueify(clasp), constructor,
                         nargs, ps, fs, static_ps, static_fs);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_LinkConstructorAndPrototype(JSContext *cx, JSObject *ctor, JSObject *proto)
@@ -3114,17 +3114,17 @@ JS_PUBLIC_API(JSClass *)
 JS_GetClass(JSObject *obj)
 {
     return obj->getJSClass();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 #ifdef DEBUG
     if (argv) {
         assertSameCompartment(cx, obj);
         assertSameCompartment(cx, JSValueArray(argv - 2, 2));
     }
 #endif
     if (!obj || obj->getJSClass() != clasp) {
@@ -3135,17 +3135,17 @@ JS_InstanceOf(JSContext *cx, JSObject *o
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_HasInstance(JSContext *cx, JSObject *obj_, jsval v, JSBool *bp)
 {
     RootedObject obj(cx, obj_);
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     assertSameCompartment(cx, obj, v);
     return HasInstance(cx, obj, &v, bp);
 }
 
 JS_PUBLIC_API(void *)
 JS_GetPrivate(JSObject *obj)
 {
     /* This function can be called by a finalizer. */
@@ -3171,17 +3171,17 @@ JS_PUBLIC_API(JSObject *)
 JS_GetPrototype(JSObject *obj)
 {
     return obj->getProto();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetPrototype(JSContext *cx, JSObject *obj_, JSObject *proto_)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj_, proto_);
 
     Rooted<JSObject*> obj(cx, obj_);
     Rooted<JSObject*> proto(cx, proto_);
     return SetProto(cx, obj, proto, JS_FALSE);
 }
 
@@ -3190,33 +3190,33 @@ JS_GetParent(JSObject *obj)
 {
     JS_ASSERT(!obj->isScope());
     return obj->getParent();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetParent(JSContext *cx, JSObject *obj_, JSObject *parent_)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     JS_ASSERT(!obj_->isScope());
     JS_ASSERT(parent_ || !obj_->getParent());
     assertSameCompartment(cx, obj_, parent_);
 
     Rooted<JSObject*> obj(cx, obj_);
     Rooted<JSObject*> parent(cx, parent_);
     return JSObject::setParent(cx, obj, parent);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetConstructor(JSContext *cx, JSObject *proto)
 {
     Value cval;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, proto);
     {
         JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
 
         if (!proto->getProperty(cx, cx->runtime->atomState.constructorAtom, &cval))
             return NULL;
     }
@@ -3226,17 +3226,17 @@ JS_GetConstructor(JSContext *cx, JSObjec
         return NULL;
     }
     return &cval.toObject();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     assertSameCompartment(cx, obj);
     *idp = OBJECT_TO_JSID(obj);
     return JS_TRUE;
 }
 
 class AutoHoldCompartment {
   public:
     explicit AutoHoldCompartment(JSCompartment *compartment JS_GUARD_OBJECT_NOTIFIER_PARAM)
@@ -3252,17 +3252,17 @@ class AutoHoldCompartment {
   private:
     bool *holdp;
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 JS_PUBLIC_API(JSObject *)
 JS_NewGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
 
     JSCompartment *compartment = NewCompartment(cx, principals);
     if (!compartment)
         return NULL;
 
     AutoHoldCompartment hold(compartment);
@@ -3277,17 +3277,17 @@ JS_NewGlobalObject(JSContext *cx, JSClas
 
 JS_PUBLIC_API(JSObject *)
 JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *proto_, JSObject *parent_)
 {
     RootedObject proto(cx, proto_);
     RootedObject parent(cx, parent_);
 
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, proto, parent);
 
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
         clasp = &ObjectClass;    /* default class is Object */
 
     JS_ASSERT(clasp != &FunctionClass);
@@ -3307,17 +3307,17 @@ JS_NewObject(JSContext *cx, JSClass *jsc
     JS_ASSERT_IF(obj, obj->getParent());
     return obj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, proto, parent);
 
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
         clasp = &ObjectClass;    /* default class is Object */
 
     JS_ASSERT(clasp != &FunctionClass);
@@ -3328,17 +3328,17 @@ JS_NewObjectWithGivenProto(JSContext *cx
     if (obj)
         MarkTypeObjectUnknownProperties(cx, obj->type());
     return obj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewObjectForConstructor(JSContext *cx, JSClass *clasp, const jsval *vp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, *vp);
 
     return js_CreateThis(cx, Valueify(clasp), JSVAL_TO_OBJECT(*vp));
 }
 
 JS_PUBLIC_API(JSBool)
 JS_IsExtensible(JSObject *obj)
@@ -3356,28 +3356,28 @@ JS_PUBLIC_API(JSRuntime *)
 JS_GetObjectRuntime(JSObject *obj)
 {
     return obj->compartment()->rt;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_FreezeObject(JSContext *cx, JSObject *obj)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
 
     return obj->freeze(cx);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DeepFreezeObject(JSContext *cx, JSObject *obj_)
 {
     RootedObject obj(cx, obj_);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
 
     /* Assume that non-extensible objects are already deep-frozen, to avoid divergence. */
     if (!obj->isExtensible())
         return true;
 
     if (!obj->freeze(cx))
@@ -3394,17 +3394,17 @@ JS_DeepFreezeObject(JSContext *cx, JSObj
 
     return true;
 }
 
 static JSBool
 LookupPropertyById(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
                    MutableHandleObject objp, MutableHandleShape propp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
 
     JSAutoResolveFlags rf(cx, flags);
     return obj->lookupGeneric(cx, id, objp, propp);
 }
 
 #define AUTO_NAMELEN(s,n)   (((n) == (size_t)-1) ? js_strlen(s) : (n))
@@ -3485,17 +3485,17 @@ JS_PUBLIC_API(JSBool)
 JS_LookupPropertyWithFlagsById(JSContext *cx, JSObject *obj_, jsid id_, unsigned flags,
                                JSObject **objp_, jsval *vp)
 {
     RootedObject obj(cx, obj_);
     RootedObject objp(cx, *objp_);
     RootedId id(cx, id_);
     RootedShape prop(cx);
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     if (!(obj->isNative()
           ? LookupPropertyWithFlags(cx, obj, id, flags, &objp, &prop)
           : obj->lookupGeneric(cx, id, &objp, &prop)))
         return false;
 
     if (!LookupResult(cx, obj, objp, id, prop, vp))
@@ -3524,17 +3524,17 @@ JS_HasPropertyById(JSContext *cx, JSObje
                                    &obj2, &prop);
     *foundp = (prop != NULL);
     return ok;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_HasElement(JSContext *cx, JSObject *obj, uint32_t index, JSBool *foundp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     jsid id;
     if (!IndexToId(cx, index, &id))
         return false;
     return JS_HasPropertyById(cx, obj, id, foundp);
 }
 
 JS_PUBLIC_API(JSBool)
@@ -3553,17 +3553,17 @@ JS_HasUCProperty(JSContext *cx, JSObject
 }
 
 JS_PUBLIC_API(JSBool)
 JS_AlreadyHasOwnPropertyById(JSContext *cx, JSObject *obj_, jsid id_, JSBool *foundp)
 {
     RootedId id(cx, id_);
     RootedObject obj(cx, obj_);
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
 
     if (!obj->isNative()) {
         RootedObject obj2(cx);
         RootedShape prop(cx);
 
         if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
@@ -3576,17 +3576,17 @@ JS_AlreadyHasOwnPropertyById(JSContext *
 
     *foundp = obj->nativeContains(cx, id);
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_AlreadyHasOwnElement(JSContext *cx, JSObject *obj, uint32_t index, JSBool *foundp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     jsid id;
     if (!IndexToId(cx, index, &id))
         return false;
     return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp);
 }
 
 JS_PUBLIC_API(JSBool)
@@ -3642,17 +3642,17 @@ DefinePropertyById(JSContext *cx, Handle
             if (!setobj)
                 return false;
             setter = JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setobj);
             attrs |= JSPROP_SETTER;
         }
     }
 
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id, value,
                             (attrs & JSPROP_GETTER)
                             ? JS_FUNC_TO_DATA_PTR(JSObject *, getter)
                             : NULL,
                             (attrs & JSPROP_SETTER)
                             ? JS_FUNC_TO_DATA_PTR(JSObject *, setter)
                             : NULL);
@@ -3677,17 +3677,17 @@ JS_DefinePropertyById(JSContext *cx, JSO
 
 JS_PUBLIC_API(JSBool)
 JS_DefineElement(JSContext *cx, JSObject *obj_, uint32_t index, jsval value_,
                  JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
 {
     RootedObject obj(cx, obj_);
     RootedValue value(cx, value_);
     AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     RootedId id(cx);
     if (!IndexToId(cx, index, id.address()))
         return false;
     return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, 0, 0);
 }
 
 static JSBool
@@ -3756,32 +3756,32 @@ JS_DefineUCPropertyWithTinyId(JSContext 
 {
     return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, attrs,
                             Shape::HAS_SHORTID, tinyid);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DefineOwnProperty(JSContext *cx, JSObject *obj_, jsid id_, jsval descriptor, JSBool *bp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj_, id_, descriptor);
 
     Rooted<JSObject*> obj(cx, obj_);
     Rooted<jsid> id(cx, id_);
     return js_DefineOwnProperty(cx, obj, id, descriptor, bp);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_DefineObject(JSContext *cx, JSObject *obj_, const char *name, JSClass *jsclasp,
                 JSObject *proto, unsigned attrs)
 {
     RootedObject obj(cx, obj_), nobj(cx);
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, proto);
 
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
         clasp = &ObjectClass;    /* default class is Object */
 
     nobj = NewObjectWithClassProto(cx, clasp, proto, obj);
@@ -3797,17 +3797,17 @@ JS_DefineObject(JSContext *cx, JSObject 
 JS_PUBLIC_API(JSBool)
 JS_DefineConstDoubles(JSContext *cx, JSObject *obj_, JSConstDoubleSpec *cds)
 {
     RootedObject obj(cx, obj_);
 
     JSBool ok;
     unsigned attrs;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     for (ok = JS_TRUE; cds->name; cds++) {
         Value value = DoubleValue(cds->dval);
         attrs = cds->flags;
         if (!attrs)
             attrs = JSPROP_READONLY | JSPROP_PERMANENT;
         ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, attrs, 0, 0);
         if (!ok)
@@ -3943,17 +3943,17 @@ JS_GetUCPropertyAttrsGetterAndSetter(JSC
     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
     return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, AtomToId(atom),
                                                           attrsp, foundp, getterp, setterp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj_, jsid id_, jsval *vp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     Rooted<JSObject*> obj(cx, obj_);
     Rooted<jsid> id(cx, id_);
     return GetOwnPropertyDescriptor(cx, obj, id, vp);
 }
 
 static JSBool
@@ -4003,17 +4003,17 @@ JS_GetPropertyById(JSContext *cx, JSObje
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ForwardGetPropertyTo(JSContext *cx, JSObject *obj, jsid id_, JSObject *onBehalfOf_, jsval *vp)
 {
     RootedId id(cx, id_);
     RootedObject onBehalfOf(cx, onBehalfOf_);
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     assertSameCompartment(cx, onBehalfOf);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
     return obj->getGeneric(cx, onBehalfOf, id, vp);
 }
 
 JS_PUBLIC_API(JSBool)
@@ -4030,29 +4030,29 @@ JS_GetElement(JSContext *cx, JSObject *o
     return JS_ForwardGetElementTo(cx, obj, index, obj, vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ForwardGetElementTo(JSContext *cx, JSObject *obj, uint32_t index, JSObject *onBehalfOf_, jsval *vp)
 {
     RootedObject onBehalfOf(cx, onBehalfOf_);
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
     return obj->getElement(cx, onBehalfOf, index, vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetElementIfPresent(JSContext *cx, JSObject *obj, uint32_t index, JSObject *onBehalfOf_, jsval *vp, JSBool* present)
 {
     RootedObject onBehalfOf(cx, onBehalfOf_);
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
     bool isPresent;
     if (!obj->getElementIfPresent(cx, onBehalfOf, index, vp, &isPresent))
         return false;
     *present = isPresent;
     return true;
@@ -4083,17 +4083,17 @@ JS_GetUCProperty(JSContext *cx, JSObject
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetMethodById(JSContext *cx, JSObject *obj_, jsid id_, JSObject **objp, jsval *vp)
 {
     RootedObject obj(cx, obj_);
     RootedId id(cx, id_);
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     if (!GetMethod(cx, obj, id, 0, vp))
         return JS_FALSE;
     if (objp)
         *objp = obj;
     return JS_TRUE;
 }
@@ -4106,29 +4106,29 @@ JS_GetMethod(JSContext *cx, JSObject *ob
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetPropertyById(JSContext *cx, JSObject *objArg, jsid id_, jsval *vp)
 {
     RootedId id(cx, id_);
     Rooted<JSObject*> obj(cx, objArg);
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
     return obj->setGeneric(cx, obj, id, vp, false);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetElement(JSContext *cx, JSObject *obj_, uint32_t index, jsval *vp)
 {
     RootedObject obj(cx, obj_);
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, *vp);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
     return obj->setElement(cx, obj, index, vp, false);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetProperty(JSContext *cx, JSObject *obj_, const char *name, jsval *vp)
@@ -4144,33 +4144,33 @@ JS_SetUCProperty(JSContext *cx, JSObject
     RootedObject obj(cx, obj_);
     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
     return atom && JS_SetPropertyById(cx, obj, AtomToId(atom), vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
 
     if (JSID_IS_SPECIAL(id)) {
         Rooted<SpecialId> sid(cx, JSID_TO_SPECIALID(id));
         return obj->deleteSpecial(cx, sid, rval, false);
     }
 
     return obj->deleteByValue(cx, IdToValue(id), rval, false);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DeleteElement2(JSContext *cx, JSObject *obj, uint32_t index, jsval *rval)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
     return obj->deleteElement(cx, index, rval, false);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DeleteProperty2(JSContext *cx, JSObject *obj_, const char *name, jsval *rval)
@@ -4225,17 +4225,17 @@ JS_DeleteProperty(JSContext *cx, JSObjec
     return JS_DeleteProperty2(cx, obj, name, &junk);
 }
 
 JS_PUBLIC_API(void)
 JS_ClearScope(JSContext *cx, JSObject *obj_)
 {
     RootedObject obj(cx, obj_);
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
 
     ClearOp clearOp = obj->getOps()->clear;
     if (clearOp)
         clearOp(cx, obj);
 
     if (obj->isNative())
@@ -4246,17 +4246,17 @@ JS_ClearScope(JSContext *cx, JSObject *o
         obj->asGlobal().clear(cx);
 
     js_InitRandom(cx);
 }
 
 JS_PUBLIC_API(JSIdArray *)
 JS_Enumerate(JSContext *cx, JSObject *obj)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
 
     AutoIdVector props(cx);
     JSIdArray *ida;
     if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props) || !VectorToIdArray(cx, props, &ida))
         return NULL;
     return ida;
@@ -4330,17 +4330,17 @@ JS_PUBLIC_API(JSObject *)
 JS_NewPropertyIterator(JSContext *cx, JSObject *obj_)
 {
     RootedObject obj(cx, obj_);
     JSObject *iterobj;
     void *pdata;
     int index;
     JSIdArray *ida;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     iterobj = NewObjectWithClassProto(cx, &prop_iter_class, NULL, obj);
     AssertRootingUnnecessary safe(cx);
     if (!iterobj)
         return NULL;
 
     if (obj->isNative()) {
@@ -4370,17 +4370,17 @@ JS_NewPropertyIterator(JSContext *cx, JS
 JS_PUBLIC_API(JSBool)
 JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
 {
     AssertRootingUnnecessary safe(cx);
     int32_t i;
     Shape *shape;
     JSIdArray *ida;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, iterobj);
     i = iterobj->getSlot(JSSLOT_ITER_INDEX).toInt32();
     if (i < 0) {
         /* Native case: private data is a property tree node pointer. */
         JS_ASSERT(iterobj->getParent()->isNative());
         shape = (Shape *) iterobj->getPrivate();
 
@@ -4407,17 +4407,17 @@ JS_NextProperty(JSContext *cx, JSObject 
         }
     }
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewElementIterator(JSContext *cx, JSObject *obj_)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj_);
 
     Rooted<JSObject*> obj(cx, obj_);
     return ElementIteratorObject::create(cx, obj);
 }
 
 JS_PUBLIC_API(JSObject *)
@@ -4438,55 +4438,55 @@ JS_SetReservedSlot(JSObject *obj, uint32
 {
     obj->setReservedSlot(index, v);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewArrayObject(JSContext *cx, int length, jsval *vector)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     assertSameCompartment(cx, JSValueArray(vector, vector ? (uint32_t)length : 0));
     return NewDenseCopiedArray(cx, (uint32_t)length, vector);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_IsArrayObject(JSContext *cx, JSObject *obj)
 {
     assertSameCompartment(cx, obj);
     return ObjectClassIs(*obj, ESClass_Array, cx);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetArrayLength(JSContext *cx, JSObject *obj, uint32_t *lengthp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     return js_GetLengthProperty(cx, obj, lengthp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetArrayLength(JSContext *cx, JSObject *obj, uint32_t length)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     return js_SetLengthProperty(cx, obj, length);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id_, JSAccessMode mode,
                jsval *vp, unsigned *attrsp)
 {
     RootedId id(cx, id_);
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     return CheckAccess(cx, obj, id, mode, vp, attrsp);
 }
 
 JS_PUBLIC_API(void)
 JS_HoldPrincipals(JSPrincipals *principals)
 {
@@ -4532,17 +4532,17 @@ JS_PUBLIC_API(JSFunction *)
 JS_NewFunction(JSContext *cx, JSNative native, unsigned nargs, unsigned flags,
                JSObject *parent_, const char *name)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     JSAtom *atom;
 
     RootedObject parent(cx, parent_);
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, parent);
 
     if (!name) {
         atom = NULL;
     } else {
         atom = js_Atomize(cx, name, strlen(name));
         if (!atom)
@@ -4555,27 +4555,27 @@ JS_NewFunction(JSContext *cx, JSNative n
 JS_PUBLIC_API(JSFunction *)
 JS_NewFunctionById(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, JSObject *parent_,
                    jsid id)
 {
     RootedObject parent(cx, parent_);
 
     JS_ASSERT(JSID_IS_STRING(id));
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, parent);
 
     return js_NewFunction(cx, NULL, native, nargs, flags, parent, JSID_TO_ATOM(id));
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent_)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, parent_);  // XXX no funobj for now
 
     RootedObject parent(cx, parent_);
 
     if (!parent) {
         if (cx->hasfp())
             parent = cx->fp()->scopeChain();
@@ -4689,17 +4689,17 @@ JS_DefineFunctions(JSContext *cx, JSObje
 {
     RootedObject obj(cx, obj_);
 
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     unsigned flags;
     RootedObject ctor(cx);
     JSFunction *fun;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     for (; fs->name; fs++) {
         flags = fs->flags;
 
         RootedAtom atom(cx, js_Atomize(cx, fs->name, strlen(fs->name)));
         if (!atom)
             return JS_FALSE;
@@ -4739,17 +4739,17 @@ JS_DefineFunctions(JSContext *cx, JSObje
 
 JS_PUBLIC_API(JSFunction *)
 JS_DefineFunction(JSContext *cx, JSObject *obj_, const char *name, JSNative call,
                   unsigned nargs, unsigned attrs)
 {
     RootedObject obj(cx, obj_);
 
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JSAtom *atom = js_Atomize(cx, name, strlen(name));
     if (!atom)
         return NULL;
     Rooted<jsid> id(cx, AtomToId(atom));
     return js_DefineFunction(cx, obj, id, call, nargs, attrs);
 }
@@ -4757,34 +4757,34 @@ JS_DefineFunction(JSContext *cx, JSObjec
 JS_PUBLIC_API(JSFunction *)
 JS_DefineUCFunction(JSContext *cx, JSObject *obj_,
                     const jschar *name, size_t namelen, JSNative call,
                     unsigned nargs, unsigned attrs)
 {
     RootedObject obj(cx, obj_);
 
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
     if (!atom)
         return NULL;
     Rooted<jsid> id(cx, AtomToId(atom));
     return js_DefineFunction(cx, obj, id, call, nargs, attrs);
 }
 
 extern JS_PUBLIC_API(JSFunction *)
 JS_DefineFunctionById(JSContext *cx, JSObject *obj_, jsid id_, JSNative call,
                       unsigned nargs, unsigned attrs)
 {
     RootedObject obj(cx, obj_);
     RootedId id(cx, id_);
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     return js_DefineFunction(cx, obj, id, call, nargs, attrs);
 }
 
 extern JS_PUBLIC_API(JSBool)
 JS_CallNonGenericMethodOnProxy(JSContext *cx, unsigned argc, jsval *vp, JSNative native,
                                JSClass *clasp)
@@ -4816,17 +4816,17 @@ struct AutoLastFrameCheck {
 static JSScript *
 CompileUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj_,
                                    JSPrincipals *principals, JSPrincipals *originPrincipals,
                                    const jschar *chars, size_t length,
                                    const char *filename, unsigned lineno, JSVersion version)
 {
     RootedObject obj(cx, obj_);
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, principals);
     AutoLastFrameCheck lfc(cx);
 
     bool compileAndGo = cx->hasRunOption(JSOPTION_COMPILE_N_GO);
     bool noScriptRval = cx->hasRunOption(JSOPTION_NO_SCRIPT_RVAL);
     bool needScriptGlobal = true;
     return frontend::CompileScript(cx, obj, NULL, principals, originPrincipals,
@@ -4891,17 +4891,17 @@ JS_PUBLIC_API(JSScript *)
 JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj_,
                               JSPrincipals *principals,
                               const char *bytes, size_t length,
                               const char *filename, unsigned lineno)
 {
     RootedObject obj(cx, obj_);
 
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     jschar *chars = InflateString(cx, bytes, &length);
     if (!chars)
         return NULL;
     JSScript *script =
         JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length, filename, lineno);
     cx->free_(chars);
@@ -4921,17 +4921,17 @@ JS_BufferIsCompilableUnit(JSContext *cx,
 {
     RootedObject obj(cx, obj_);
 
     jschar *chars;
     JSBool result;
     JSExceptionState *exnState;
     JSErrorReporter older;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     if (bytes_are_utf8)
         chars = InflateString(cx, bytes, &length, CESU8Encoding);
     else
         chars = InflateString(cx, bytes, &length);
     if (!chars)
         return JS_TRUE;
@@ -5047,17 +5047,17 @@ CompileUTF8FileHelper(JSContext *cx, JSO
 }
 
 JS_PUBLIC_API(JSScript *)
 JS_CompileUTF8File(JSContext *cx, JSObject *obj_, const char *filename)
 {
     RootedObject obj(cx, obj_);
 
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     AutoLastFrameCheck lfc(cx);
 
     FILE *fp;
     if (!filename || strcmp(filename, "-") == 0) {
         fp = stdin;
     } else {
@@ -5075,17 +5075,17 @@ JS_CompileUTF8File(JSContext *cx, JSObje
     return script;
 }
 
 JS_PUBLIC_API(JSScript *)
 JS_CompileUTF8FileHandleForPrincipals(JSContext *cx, JSObject *obj, const char *filename,
                                       FILE *file, JSPrincipals *principals)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, principals);
     AutoLastFrameCheck lfc(cx);
 
     return CompileUTF8FileHelper(cx, obj, principals, filename, file);
 }
 
 JS_PUBLIC_API(JSScript *)
@@ -5117,17 +5117,17 @@ CompileUCFunctionForPrincipalsCommon(JSC
                                      JSPrincipals *principals, const char *name,
                                      unsigned nargs, const char **argnames,
                                      const jschar *chars, size_t length,
                                      const char *filename, unsigned lineno, JSVersion version)
 {
     RootedObject obj(cx, obj_);
 
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, principals);
     AutoLastFrameCheck lfc(cx);
 
     RootedAtom funAtom(cx);
     if (name) {
         funAtom = js_Atomize(cx, name, strlen(name));
         if (!funAtom)
@@ -5229,17 +5229,17 @@ JS_CompileFunction(JSContext *cx, JSObje
 
 JS_PUBLIC_API(JSString *)
 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, unsigned indent)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     JSPrinter *jp;
     JSString *str;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 #ifdef DEBUG
     if (cx->compartment != script->compartment())
         CompartmentChecker::fail(cx->compartment, script->compartment());
 #endif
     jp = js_NewPrinter(cx, name, NULL,
                        indent & ~JS_DONT_PRETTY_PRINT,
                        !(indent & JS_DONT_PRETTY_PRINT),
@@ -5253,45 +5253,45 @@ JS_DecompileScript(JSContext *cx, JSScri
     js_DestroyPrinter(jp);
     return str;
 }
 
 JS_PUBLIC_API(JSString *)
 JS_DecompileFunction(JSContext *cx, JSFunction *fun, unsigned indent)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, fun);
     return js_DecompileToString(cx, "JS_DecompileFunction", fun,
                                 indent & ~JS_DONT_PRETTY_PRINT,
                                 !(indent & JS_DONT_PRETTY_PRINT),
                                 false, false, js_DecompileFunction);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, unsigned indent)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, fun);
     return js_DecompileToString(cx, "JS_DecompileFunctionBody", fun,
                                 indent & ~JS_DONT_PRETTY_PRINT,
                                 !(indent & JS_DONT_PRETTY_PRINT),
                                 false, false, js_DecompileFunctionBody);
 }
 
 JS_NEVER_INLINE JS_PUBLIC_API(JSBool)
 JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *scriptArg_, jsval *rval)
 {
     RootedScript scriptArg(cx, scriptArg_);
 
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     if (cx->compartment != obj->compartment())
         *(volatile int *) 0 = 0xf0;
     AutoLastFrameCheck lfc(cx);
 
     JS::Anchor<JSScript *> script(NULL);
 
@@ -5432,30 +5432,30 @@ JS_EvaluateScript(JSContext *cx, JSObjec
     return JS_EvaluateScriptForPrincipals(cx, obj, NULL, bytes, nbytes, filename, lineno, rval);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, unsigned argc, jsval *argv,
                 jsval *rval)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, fun, JSValueArray(argv, argc));
     AutoLastFrameCheck lfc(cx);
 
     return Invoke(cx, ObjectOrNullValue(obj), ObjectValue(*fun), argc, argv, rval);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_CallFunctionName(JSContext *cx, JSObject *obj_, const char *name, unsigned argc, jsval *argv,
                     jsval *rval)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj_, JSValueArray(argv, argc));
     AutoLastFrameCheck lfc(cx);
 
     RootedObject obj(cx, obj_);
 
     Value v;
     JSAtom *atom = js_Atomize(cx, name, strlen(name));
@@ -5467,43 +5467,43 @@ JS_CallFunctionName(JSContext *cx, JSObj
            Invoke(cx, ObjectOrNullValue(obj), v, argc, argv, rval);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, unsigned argc, jsval *argv,
                      jsval *rval)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, fval, JSValueArray(argv, argc));
     AutoLastFrameCheck lfc(cx);
 
     return Invoke(cx, ObjectOrNullValue(obj), fval, argc, argv, rval);
 }
 
 namespace JS {
 
 JS_PUBLIC_API(bool)
 Call(JSContext *cx, jsval thisv, jsval fval, unsigned argc, jsval *argv, jsval *rval)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, thisv, fval, JSValueArray(argv, argc));
     AutoLastFrameCheck lfc(cx);
 
     return Invoke(cx, thisv, fval, argc, argv, rval);
 }
 
 } // namespace JS
 
 JS_PUBLIC_API(JSObject *)
 JS_New(JSContext *cx, JSObject *ctor, unsigned argc, jsval *argv)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, ctor, JSValueArray(argv, argc));
     AutoLastFrameCheck lfc(cx);
 
     // This is not a simple variation of JS_CallFunctionValue because JSOP_NEW
     // is not a simple variation of JSOP_CALL. We have to determine what class
     // of object to create, create it, and clamp the return value to an object,
     // among other details. InvokeConstructor does the hard work.
@@ -5561,25 +5561,25 @@ JS_IsRunning(JSContext *cx)
     while (fp && fp->isDummyFrame())
         fp = fp->prev();
     return fp != NULL;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SaveFrameChain(JSContext *cx)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return cx->stack.saveFrameChain();
 }
 
 JS_PUBLIC_API(void)
 JS_RestoreFrameChain(JSContext *cx)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     cx->stack.restoreFrameChain();
 }
 
 #ifdef MOZ_TRACE_JSCALLS
 JS_PUBLIC_API(void)
 JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb)
 {
@@ -5592,46 +5592,46 @@ JS_GetFunctionCallback(JSContext *cx)
     return cx->functionCallback;
 }
 #endif
 
 /************************************************************************/
 JS_PUBLIC_API(JSString *)
 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return js_NewStringCopyN(cx, s, n);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_NewStringCopyZ(JSContext *cx, const char *s)
 {
     size_t n;
     jschar *js;
     JSString *str;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     if (!s || !*s)
         return cx->runtime->emptyString;
     n = strlen(s);
     js = InflateString(cx, s, &n);
     if (!js)
         return NULL;
     str = js_NewString(cx, js, n);
     if (!str)
         cx->free_(js);
     return str;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_StringHasBeenInterned(JSContext *cx, JSString *str)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     if (!str->isAtom())
         return false;
 
     return AtomIsInterned(cx, &str->asAtom());
 }
 
@@ -5642,63 +5642,63 @@ INTERNED_STRING_TO_JSID(JSContext *cx, J
     JS_ASSERT(((size_t)str & JSID_TYPE_MASK) == 0);
     JS_ASSERT_IF(cx, JS_StringHasBeenInterned(cx, str));
     return AtomToId(&str->asAtom());
 }
 
 JS_PUBLIC_API(JSString *)
 JS_InternJSString(JSContext *cx, JSString *str)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     JSAtom *atom = js_AtomizeString(cx, str, InternAtom);
     JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
     return atom;
 }
 
 JS_PUBLIC_API(JSString *)
 JS_InternString(JSContext *cx, const char *s)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     JSAtom *atom = js_Atomize(cx, s, strlen(s), InternAtom);
     JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
     return atom;
 }
 
 JS_PUBLIC_API(JSString *)
 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return js_NewString(cx, chars, length);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return js_NewStringCopyN(cx, s, n);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     if (!s)
         return cx->runtime->emptyString;
     return js_NewStringCopyZ(cx, s);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     JSAtom *atom = js_AtomizeChars(cx, s, length, InternAtom);
     JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
     return atom;
 }
 
 JS_PUBLIC_API(JSString *)
 JS_InternUCString(JSContext *cx, const jschar *s)
@@ -5710,36 +5710,36 @@ JS_PUBLIC_API(size_t)
 JS_GetStringLength(JSString *str)
 {
     return str->length();
 }
 
 JS_PUBLIC_API(const jschar *)
 JS_GetStringCharsZ(JSContext *cx, JSString *str)
 {
-    AssertNoGCOrFlatString(cx, str);
+    AssertHeapIsIdleOrStringIsFlat(cx, str);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, str);
     return str->getCharsZ(cx);
 }
 
 JS_PUBLIC_API(const jschar *)
 JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *plength)
 {
-    AssertNoGCOrFlatString(cx, str);
+    AssertHeapIsIdleOrStringIsFlat(cx, str);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, str);
     *plength = str->length();
     return str->getCharsZ(cx);
 }
 
 JS_PUBLIC_API(const jschar *)
 JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *plength)
 {
-    AssertNoGCOrFlatString(cx, str);
+    AssertHeapIsIdleOrStringIsFlat(cx, str);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, str);
     *plength = str->length();
     return str->getChars(cx);
 }
 
 JS_PUBLIC_API(const jschar *)
 JS_GetInternedStringChars(JSString *str)
@@ -5753,41 +5753,41 @@ JS_GetInternedStringCharsAndLength(JSStr
     JSAtom &atom = str->asAtom();
     *plength = atom.length();
     return atom.chars();
 }
 
 extern JS_PUBLIC_API(JSFlatString *)
 JS_FlattenString(JSContext *cx, JSString *str)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, str);
     return str->getCharsZ(cx) ? (JSFlatString *)str : NULL;
 }
 
 extern JS_PUBLIC_API(const jschar *)
 JS_GetFlatStringChars(JSFlatString *str)
 {
     return str->chars();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *result)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     return CompareStrings(cx, str1, str2, result);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, JSBool *match)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     JSLinearString *linearStr = str->ensureLinear(cx);
     if (!linearStr)
         return false;
     *match = StringEqualsAscii(linearStr, asciiBytes);
     return true;
 }
@@ -5802,76 +5802,76 @@ JS_PUBLIC_API(size_t)
 JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote)
 {
     return PutEscapedString(buffer, size, str, quote);
 }
 
 JS_PUBLIC_API(size_t)
 JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     JSLinearString *linearStr = str->ensureLinear(cx);
     if (!linearStr)
         return size_t(-1);
     return PutEscapedString(buffer, size, linearStr, quote);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_FileEscapedString(FILE *fp, JSString *str, char quote)
 {
     JSLinearString *linearStr = str->ensureLinear(NULL);
     return linearStr && FileEscapedString(fp, linearStr, quote);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return js_NewString(cx, chars, length);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_NewDependentString(JSContext *cx, JSString *str, size_t start, size_t length)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return js_NewDependentString(cx, str, start, length);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     Rooted<JSString*> lstr(cx, left);
     Rooted<JSString*> rstr(cx, right);
     return js_ConcatStrings(cx, lstr, rstr);
 }
 
 JS_PUBLIC_API(const jschar *)
 JS_UndependString(JSContext *cx, JSString *str)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return str->getCharsZ(cx);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_MakeStringImmutable(JSContext *cx, JSString *str)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return !!str->ensureFixed(cx);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst, size_t *dstlenp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     size_t n;
     if (!dst) {
         n = GetDeflatedStringLength(cx, src, srclen);
         if (n == (size_t)-1) {
             *dstlenp = 0;
             return JS_FALSE;
@@ -5881,48 +5881,48 @@ JS_EncodeCharacters(JSContext *cx, const
     }
 
     return DeflateStringToBuffer(cx, src, srclen, dst, dstlenp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_t *dstlenp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return InflateStringToBuffer(cx, src, srclen, dst, dstlenp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DecodeUTF8(JSContext *cx, const char *src, size_t srclen, jschar *dst,
               size_t *dstlenp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return InflateUTF8StringToBuffer(cx, src, srclen, dst, dstlenp);
 }
 
 JS_PUBLIC_API(char *)
 JS_EncodeString(JSContext *cx, JSString *str)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     const jschar *chars = str->getChars(cx);
     if (!chars)
         return NULL;
     return DeflateString(cx, chars, str->length());
 }
 
 JS_PUBLIC_API(size_t)
 JS_GetStringEncodingLength(JSContext *cx, JSString *str)
 {
     /* jsd calls us with a NULL cx. Ugh. */
     if (cx) {
-        AssertNoGC(cx);
+        AssertHeapIsIdle(cx);
         CHECK_REQUEST(cx);
     }
 
     const jschar *chars = str->getChars(cx);
     if (!chars)
         return size_t(-1);
     return GetDeflatedStringLength(cx, chars, str->length());
 }
@@ -5954,54 +5954,54 @@ JS_EncodeStringToBuffer(JSString *str, c
     }
     return necessaryLength;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space,
              JSONWriteCallback callback, void *data)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, replacer, space);
     StringBuffer sb(cx);
     if (!js_Stringify(cx, vp, replacer, space, sb))
         return false;
     if (sb.empty()) {
         JSAtom *nullAtom = cx->runtime->atomState.nullAtom;
         return callback(nullAtom->chars(), nullAtom->length(), data);
     }
     return callback(sb.begin(), sb.length(), data);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ParseJSON(JSContext *cx, const jschar *chars, uint32_t len, jsval *vp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     return ParseJSONWithReviver(cx, chars, len, NullValue(), vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32_t len, jsval reviver, jsval *vp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     return ParseJSONWithReviver(cx, chars, len, reviver, vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ReadStructuredClone(JSContext *cx, const uint64_t *buf, size_t nbytes,
                        uint32_t version, jsval *vp,
                        const JSStructuredCloneCallbacks *optionalCallbacks,
                        void *closure)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     if (version > JS_STRUCTURED_CLONE_VERSION) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CLONE_VERSION);
         return false;
     }
     const JSStructuredCloneCallbacks *callbacks =
         optionalCallbacks ?
@@ -6010,33 +6010,33 @@ JS_ReadStructuredClone(JSContext *cx, co
     return ReadStructuredClone(cx, buf, nbytes, vp, callbacks, closure);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_WriteStructuredClone(JSContext *cx, jsval v, uint64_t **bufp, size_t *nbytesp,
                         const JSStructuredCloneCallbacks *optionalCallbacks,
                         void *closure)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
 
     const JSStructuredCloneCallbacks *callbacks =
         optionalCallbacks ?
         optionalCallbacks :
         cx->runtime->structuredCloneCallbacks;
     return WriteStructuredClone(cx, v, (uint64_t **) bufp, nbytesp, callbacks, closure);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_StructuredClone(JSContext *cx, jsval v, jsval *vp,
                    const JSStructuredCloneCallbacks *optionalCallbacks,
                    void *closure)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
 
     const JSStructuredCloneCallbacks *callbacks =
         optionalCallbacks ?
         optionalCallbacks :
         cx->runtime->structuredCloneCallbacks;
     JSAutoStructuredCloneBuffer buf;
@@ -6192,86 +6192,86 @@ JS_SetCStringsAreUTF8()
 
 /************************************************************************/
 
 JS_PUBLIC_API(void)
 JS_ReportError(JSContext *cx, const char *format, ...)
 {
     va_list ap;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     va_start(ap, format);
     js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
     va_end(ap);
 }
 
 JS_PUBLIC_API(void)
 JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
                      void *userRef, const unsigned errorNumber, ...)
 {
     va_list ap;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     va_start(ap, errorNumber);
     js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
                            errorNumber, JS_TRUE, ap);
     va_end(ap);
 }
 
 JS_PUBLIC_API(void)
 JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
                      void *userRef, const unsigned errorNumber, ...)
 {
     va_list ap;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     va_start(ap, errorNumber);
     js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
                            errorNumber, JS_FALSE, ap);
     va_end(ap);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ReportWarning(JSContext *cx, const char *format, ...)
 {
     va_list ap;
     JSBool ok;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     va_start(ap, format);
     ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
     va_end(ap);
     return ok;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ReportErrorFlagsAndNumber(JSContext *cx, unsigned flags,
                              JSErrorCallback errorCallback, void *userRef,
                              const unsigned errorNumber, ...)
 {
     va_list ap;
     JSBool ok;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     va_start(ap, errorNumber);
     ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
                                 errorNumber, JS_TRUE, ap);
     va_end(ap);
     return ok;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ReportErrorFlagsAndNumberUC(JSContext *cx, unsigned flags,
                                JSErrorCallback errorCallback, void *userRef,
                                const unsigned errorNumber, ...)
 {
     va_list ap;
     JSBool ok;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     va_start(ap, errorNumber);
     ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
                                 errorNumber, JS_FALSE, ap);
     va_end(ap);
     return ok;
 }
 
 JS_PUBLIC_API(void)
@@ -6305,164 +6305,164 @@ JS_SetErrorReporter(JSContext *cx, JSErr
 /************************************************************************/
 
 /*
  * Dates.
  */
 JS_PUBLIC_API(JSObject *)
 JS_NewDateObject(JSContext *cx, int year, int mon, int mday, int hour, int min, int sec)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return js_NewDateObject(cx, year, mon, mday, hour, min, sec);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewDateObjectMsec(JSContext *cx, double msec)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return js_NewDateObjectMsec(cx, msec);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ObjectIsDate(JSContext *cx, JSObject *obj)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     JS_ASSERT(obj);
     return obj->isDate();
 }
 
 /************************************************************************/
 
 /*
  * Regular Expressions.
  */
 JS_PUBLIC_API(JSObject *)
 JS_NewRegExpObject(JSContext *cx, JSObject *obj_, char *bytes, size_t length, unsigned flags)
 {
     RootedObject obj(cx, obj_);
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     jschar *chars = InflateString(cx, bytes, &length);
     if (!chars)
         return NULL;
 
     RegExpStatics *res = obj->asGlobal().getRegExpStatics();
     RegExpObject *reobj = RegExpObject::create(cx, res, chars, length, RegExpFlag(flags), NULL);
     cx->free_(chars);
     return reobj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewUCRegExpObject(JSContext *cx, JSObject *obj, jschar *chars, size_t length, unsigned flags)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     RegExpStatics *res = obj->asGlobal().getRegExpStatics();
     return RegExpObject::create(cx, res, chars, length, RegExpFlag(flags), NULL);
 }
 
 JS_PUBLIC_API(void)
 JS_SetRegExpInput(JSContext *cx, JSObject *obj, JSString *input, JSBool multiline)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, input);
 
     obj->asGlobal().getRegExpStatics()->reset(cx, input, !!multiline);
 }
 
 JS_PUBLIC_API(void)
 JS_ClearRegExpStatics(JSContext *cx, JSObject *obj)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     JS_ASSERT(obj);
 
     obj->asGlobal().getRegExpStatics()->clear();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ExecuteRegExp(JSContext *cx, JSObject *obj, JSObject *reobj, jschar *chars, size_t length,
                  size_t *indexp, JSBool test, jsval *rval)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     RegExpStatics *res = obj->asGlobal().getRegExpStatics();
     return ExecuteRegExp(cx, res, reobj->asRegExp(), NULL, chars, length,
                          indexp, test ? RegExpTest : RegExpExec, rval);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewRegExpObjectNoStatics(JSContext *cx, char *bytes, size_t length, unsigned flags)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     jschar *chars = InflateString(cx, bytes, &length);
     if (!chars)
         return NULL;
     RegExpObject *reobj = RegExpObject::createNoStatics(cx, chars, length, RegExpFlag(flags), NULL);
     cx->free_(chars);
     return reobj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewUCRegExpObjectNoStatics(JSContext *cx, jschar *chars, size_t length, unsigned flags)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return RegExpObject::createNoStatics(cx, chars, length, RegExpFlag(flags), NULL);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ExecuteRegExpNoStatics(JSContext *cx, JSObject *obj, jschar *chars, size_t length,
                           size_t *indexp, JSBool test, jsval *rval)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     return ExecuteRegExp(cx, NULL, obj->asRegExp(), NULL, chars, length, indexp,
                          test ? RegExpTest : RegExpExec, rval);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ObjectIsRegExp(JSContext *cx, JSObject *obj)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     JS_ASSERT(obj);
     return obj->isRegExp();
 }
 
 JS_PUBLIC_API(unsigned)
 JS_GetRegExpFlags(JSContext *cx, JSObject *obj)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     return obj->asRegExp().getFlags();
 }
 
 JS_PUBLIC_API(JSString *)
 JS_GetRegExpSource(JSContext *cx, JSObject *obj)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     return obj->asRegExp().getSource();
 }
 
 /************************************************************************/
 
 JS_PUBLIC_API(void)
 JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     cx->localeCallbacks = callbacks;
 }
 
 JS_PUBLIC_API(JSLocaleCallbacks *)
 JS_GetLocaleCallbacks(JSContext *cx)
 {
     /* This function can be called by a finalizer. */
     return cx->localeCallbacks;
@@ -6475,147 +6475,147 @@ JS_IsExceptionPending(JSContext *cx)
 {
     /* This function can be called by a finalizer. */
     return (JSBool) cx->isExceptionPending();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetPendingException(JSContext *cx, jsval *vp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     if (!cx->isExceptionPending())
         return JS_FALSE;
     *vp = cx->getPendingException();
     assertSameCompartment(cx, *vp);
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(void)
 JS_SetPendingException(JSContext *cx, jsval v)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
     cx->setPendingException(v);
 }
 
 JS_PUBLIC_API(void)
 JS_ClearPendingException(JSContext *cx)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     cx->clearPendingException();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ReportPendingException(JSContext *cx)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     return js_ReportUncaughtException(cx);
 }
 
 struct JSExceptionState {
     JSBool throwing;
     jsval  exception;
 };
 
 JS_PUBLIC_API(JSExceptionState *)
 JS_SaveExceptionState(JSContext *cx)
 {
     JSExceptionState *state;
 
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     state = (JSExceptionState *) cx->malloc_(sizeof(JSExceptionState));
     if (state) {
         state->throwing = JS_GetPendingException(cx, &state->exception);
         if (state->throwing && JSVAL_IS_GCTHING(state->exception))
             js_AddRoot(cx, &state->exception, "JSExceptionState.exception");
     }
     return state;
 }
 
 JS_PUBLIC_API(void)
 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     if (state) {
         if (state->throwing)
             JS_SetPendingException(cx, state->exception);
         else
             JS_ClearPendingException(cx);
         JS_DropExceptionState(cx, state);
     }
 }
 
 JS_PUBLIC_API(void)
 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     if (state) {
         if (state->throwing && JSVAL_IS_GCTHING(state->exception)) {
             assertSameCompartment(cx, state->exception);
             JS_RemoveValueRoot(cx, &state->exception);
         }
         cx->free_(state);
     }
 }
 
 JS_PUBLIC_API(JSErrorReport *)
 JS_ErrorFromException(JSContext *cx, jsval v)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
     return js_ErrorFromException(cx, v);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ThrowReportedError(JSContext *cx, const char *message,
                       JSErrorReport *reportp)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     return JS_IsRunning(cx) &&
            js_ErrorToException(cx, message, reportp, NULL, NULL);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ThrowStopIteration(JSContext *cx)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     return js_ThrowStopIteration(cx);
 }
 
 JS_PUBLIC_API(intptr_t)
 JS_GetCurrentThread()
 {
 #ifdef JS_THREADSAFE
     return reinterpret_cast<intptr_t>(PR_GetCurrentThread());
 #else
     return 0;
 #endif
 }
 
 extern JS_PUBLIC_API(void)
 JS_ClearRuntimeThread(JSRuntime *rt)
 {
-    AssertNoGC(rt);
+    AssertHeapIsIdle(rt);
 #ifdef JS_THREADSAFE
     rt->clearOwnerThread();
 #endif
 }
 
 extern JS_PUBLIC_API(void)
 JS_SetRuntimeThread(JSRuntime *rt)
 {
-    AssertNoGC(rt);
+    AssertHeapIsIdle(rt);
 #ifdef JS_THREADSAFE
     rt->setOwnerThread();
 #endif
 }
 
 extern JS_NEVER_INLINE JS_PUBLIC_API(void)
 JS_AbortIfWrongThread(JSRuntime *rt)
 {
@@ -6759,17 +6759,17 @@ AutoEnumStateRooter::~AutoEnumStateRoote
     if (!stateValue.isNull())
         MOZ_ALWAYS_TRUE(obj->enumerate(context, JSENUMERATE_DESTROY, &stateValue, 0));
 }
 
 #ifdef DEBUG
 JS_PUBLIC_API(void)
 AssertArgumentsAreSane(JSContext *cx, const JS::Value &v)
 {
-    AssertNoGC(cx);
+    AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
 }
 #endif /* DEBUG */
 
 } // namespace JS
 
 JS_PUBLIC_API(void *)
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -286,17 +286,17 @@ js::DestroyContext(JSContext *cx, Destro
              */
             JS_ALWAYS_TRUE(cxCallback(cx, JSCONTEXT_DESTROY));
         }
     }
 
     JS_REMOVE_LINK(&cx->link);
     bool last = !rt->hasContexts();
     if (last) {
-        JS_ASSERT(!rt->gcRunning);
+        JS_ASSERT(!rt->isHeapBusy());
 
         /*
          * Dump remaining type inference results first. This printing
          * depends on atoms still existing.
          */
         for (CompartmentsIter c(rt); !c.done(); c.next())
             c->types.print(cx, false);
 
@@ -306,17 +306,17 @@ js::DestroyContext(JSContext *cx, Destro
         /* Clear debugging state to remove GC roots. */
         for (CompartmentsIter c(rt); !c.done(); c.next())
             c->clearTraps(rt->defaultFreeOp());
         JS_ClearAllWatchPoints(cx);
 
         PrepareForFullGC(rt);
         GC(rt, GC_NORMAL, gcreason::LAST_CONTEXT);
     } else if (mode == DCM_FORCE_GC) {
-        JS_ASSERT(!rt->gcRunning);
+        JS_ASSERT(!rt->isHeapBusy());
         PrepareForFullGC(rt);
         GC(rt, GC_NORMAL, gcreason::DESTROY_CONTEXT);
     }
     Foreground::delete_(cx);
 }
 
 namespace js {
 
@@ -1161,17 +1161,17 @@ JS_FRIEND_API(void)
 JSRuntime::onTooMuchMalloc()
 {
     TriggerGC(this, gcreason::TOO_MUCH_MALLOC);
 }
 
 JS_FRIEND_API(void *)
 JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx)
 {
-    if (gcRunning)
+    if (isHeapBusy())
         return NULL;
 
     /*
      * Retry when we are done with the background sweeping and have stopped
      * all the allocations and released the empty GC chunks.
      */
     ShrinkGCBuffers(this);
     gcHelperThread.waitBackgroundSweepOrAllocEnd();
@@ -1308,17 +1308,17 @@ JSContext::mark(JSTracer *trc)
 
 namespace JS {
 
 #if defined JS_THREADSAFE && defined DEBUG
 
 AutoCheckRequestDepth::AutoCheckRequestDepth(JSContext *cx)
     : cx(cx)
 {
-    JS_ASSERT(cx->runtime->requestDepth || cx->runtime->gcRunning);
+    JS_ASSERT(cx->runtime->requestDepth || cx->runtime->isHeapBusy());
     JS_ASSERT(cx->runtime->onOwnerThread());
     cx->runtime->checkRequestDepth++;
 }
 
 AutoCheckRequestDepth::~AutoCheckRequestDepth()
 {
     JS_ASSERT(cx->runtime->checkRequestDepth != 0);
     cx->runtime->checkRequestDepth--;
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -573,17 +573,26 @@ struct JSRuntime : js::RuntimeFriendFiel
         JSGCTraceKind kind;
 
         SavedGCRoot(void *thing, JSGCTraceKind kind) : thing(thing), kind(kind) {}
     };
     js::Vector<SavedGCRoot, 0, js::SystemAllocPolicy> gcSavedRoots;
 #endif
 
     bool                gcPoke;
-    bool                gcRunning;
+
+    enum HeapState {
+        Idle,       // doing nothing with the GC heap
+        Tracing,    // tracing the GC heap without collecting, e.g. IterateCompartments()
+        Collecting  // doing a GC of the heap
+    };
+
+    HeapState           heapState;
+
+    bool isHeapBusy() { return heapState != Idle; }
 
     /*
      * These options control the zealousness of the GC. The fundamental values
      * are gcNextScheduled and gcDebugCompartmentGC. At every allocation,
      * gcNextScheduled is decremented. When it reaches zero, we do either a
      * full or a compartmental GC, based on gcDebugCompartmentGC.
      *
      * At this point, if gcZeal_ is one of the types that trigger periodic
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -323,17 +323,17 @@ class CompartmentChecker
 
 #endif
 
 /*
  * Don't perform these checks when called from a finalizer. The checking
  * depends on other objects not having been swept yet.
  */
 #define START_ASSERT_SAME_COMPARTMENT()                                       \
-    if (cx->runtime->gcRunning)                                               \
+    if (cx->runtime->isHeapBusy())                                            \
         return;                                                               \
     CompartmentChecker c(cx)
 
 template <class T1> inline void
 assertSameCompartment(JSContext *cx, const T1 &t1)
 {
 #ifdef DEBUG
     START_ASSERT_SAME_COMPARTMENT();
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -675,17 +675,17 @@ JSCompartment::updateForDebugMode(FreeOp
     //
     // It suffices to do a garbage collection cycle or to finish the
     // ongoing GC cycle. The necessary cleanup happens in
     // JSCompartment::sweep.
     //
     // dmgc makes sure we can't forget to GC, but it is also important not
     // to run any scripts in this compartment until the dmgc is destroyed.
     // That is the caller's responsibility.
-    if (!rt->gcRunning)
+    if (!rt->isHeapBusy())
         dmgc.scheduleGC(this);
 #endif
 }
 
 bool
 JSCompartment::addDebuggee(JSContext *cx, js::GlobalObject *global)
 {
     bool wasEnabled = debugMode();
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -155,17 +155,17 @@ struct JSCompartment
     };
 
     CompartmentGCState           gcState;
     bool                         gcPreserveCode;
 
   public:
     bool isCollecting() const {
         /* Allow this if we're in the middle of an incremental GC. */
-        if (rt->gcRunning) {
+        if (rt->isHeapBusy()) {
             return gcState == GCRunning;
         } else {
             JS_ASSERT(gcState != GCRunning);
             return needsBarrier();
         }
     }
 
     bool isPreservingCode() const {
@@ -176,31 +176,31 @@ struct JSCompartment
      * If this returns true, all object tracing must be done with a GC marking
      * tracer.
      */
     bool requireGCTracer() const {
         return gcState == GCRunning;
     }
 
     void setCollecting(bool collecting) {
-        JS_ASSERT(rt->gcRunning);
+        JS_ASSERT(rt->isHeapBusy());
         if (collecting)
             gcState = GCRunning;
         else
             gcState = NoGCScheduled;
     }
 
     void scheduleGC() {
-        JS_ASSERT(!rt->gcRunning);
+        JS_ASSERT(!rt->isHeapBusy());
         JS_ASSERT(gcState != GCRunning);
         gcState = GCScheduled;
     }
 
     void unscheduleGC() {
-        JS_ASSERT(!rt->gcRunning);
+        JS_ASSERT(!rt->isHeapBusy());
         JS_ASSERT(gcState != GCRunning);
         gcState = NoGCScheduled;
     }
 
     bool isGCScheduled() const {
         return gcState == GCScheduled;
     }
 
@@ -409,17 +409,17 @@ class js::AutoDebugModeGC
         // the garbage collector may try to retain JIT code and analyses.
         // The DEBUG_MODE_GC reason forces the collector to always throw
         // everything away, as required for debug mode transitions.
         if (needGC)
             GC(rt, GC_NORMAL, gcreason::DEBUG_MODE_GC);
     }
 
     void scheduleGC(JSCompartment *compartment) {
-        JS_ASSERT(!rt->gcRunning);
+        JS_ASSERT(!rt->isHeapBusy());
         PrepareCompartmentForGC(compartment);
         needGC = true;
     }
 };
 
 inline void
 JSContext::setCompartment(JSCompartment *compartment)
 {
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -793,17 +793,17 @@ extern JS_FRIEND_API(void)
 DisableIncrementalGC(JSRuntime *rt)
 {
     rt->gcIncrementalEnabled = false;
 }
 
 JS_FRIEND_API(bool)
 IsIncrementalBarrierNeeded(JSRuntime *rt)
 {
-    return (rt->gcIncrementalState == gc::MARK && !rt->gcRunning);
+    return (rt->gcIncrementalState == gc::MARK && !rt->isHeapBusy());
 }
 
 JS_FRIEND_API(bool)
 IsIncrementalBarrierNeeded(JSContext *cx)
 {
     return IsIncrementalBarrierNeeded(cx->runtime);
 }
 
@@ -819,17 +819,17 @@ IsIncrementalBarrierNeededOnScript(JSScr
     return script->compartment()->needsBarrier();
 }
 
 extern JS_FRIEND_API(void)
 IncrementalReferenceBarrier(void *ptr)
 {
     if (!ptr)
         return;
-    JS_ASSERT(!static_cast<gc::Cell *>(ptr)->compartment()->rt->gcRunning);
+    JS_ASSERT(!static_cast<gc::Cell *>(ptr)->compartment()->rt->isHeapBusy());
     uint32_t kind = gc::GetGCThingTraceKind(ptr);
     if (kind == JSTRACE_OBJECT)
         JSObject::writeBarrierPre((JSObject *) ptr);
     else if (kind == JSTRACE_STRING)
         JSString::writeBarrierPre((JSString *) ptr);
     else if (kind == JSTRACE_SCRIPT)
         JSScript::writeBarrierPre((JSScript *) ptr);
     else if (kind == JSTRACE_SHAPE)
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -209,17 +209,17 @@ ArenaHeader::checkSynchronizedWithFreeLi
      */
     JS_ASSERT(allocated());
 
     /*
      * We can be called from the background finalization thread when the free
      * list in the compartment can mutate at any moment. We cannot do any
      * checks in this case.
      */
-    if (!compartment->rt->gcRunning)
+    if (!compartment->rt->isHeapBusy())
         return;
 
     FreeSpan firstSpan = FreeSpan::decodeOffsets(arenaAddress(), firstFreeSpanOffsets);
     if (firstSpan.isEmpty())
         return;
     const FreeSpan *list = compartment->arenas.getFreeList(getAllocKind());
     if (list->isEmpty() || firstSpan.arenaAddress() != list->arenaAddress())
         return;
@@ -1628,17 +1628,17 @@ RunLastDitchGC(JSContext *cx, gcreason::
 
 /* static */ void *
 ArenaLists::refillFreeList(JSContext *cx, AllocKind thingKind)
 {
     JS_ASSERT(cx->compartment->arenas.freeLists[thingKind].isEmpty());
 
     JSCompartment *comp = cx->compartment;
     JSRuntime *rt = comp->rt;
-    JS_ASSERT(!rt->gcRunning);
+    JS_ASSERT(!rt->isHeapBusy());
 
     bool runGC = rt->gcIncrementalState != NO_INCREMENTAL && comp->gcBytes > comp->gcTriggerBytes;
     for (;;) {
         if (JS_UNLIKELY(runGC)) {
             PrepareCompartmentForGC(comp);
             RunLastDitchGC(cx, gcreason::LAST_DITCH);
 
             /*
@@ -2022,17 +2022,17 @@ GCMarker::sizeOfExcludingThis(JSMallocSi
 {
     return stack.sizeOfExcludingThis(mallocSizeOf) +
            grayRoots.sizeOfExcludingThis(mallocSizeOf);
 }
 
 void
 SetMarkStackLimit(JSRuntime *rt, size_t limit)
 {
-    JS_ASSERT(!rt->gcRunning);
+    JS_ASSERT(!rt->isHeapBusy());
     rt->gcMarker.setSizeLimit(limit);
 }
 
 } /* namespace js */
 
 static void
 gc_root_traversal(JSTracer *trc, const RootEntry &entry)
 {
@@ -2426,30 +2426,30 @@ TriggerOperationCallback(JSRuntime *rt, 
     rt->triggerOperationCallback();
 }
 
 void
 TriggerGC(JSRuntime *rt, gcreason::Reason reason)
 {
     JS_ASSERT(rt->onOwnerThread());
 
-    if (rt->gcRunning)
+    if (rt->isHeapBusy())
         return;
 
     PrepareForFullGC(rt);
     TriggerOperationCallback(rt, reason);
 }
 
 void
 TriggerCompartmentGC(JSCompartment *comp, gcreason::Reason reason)
 {
     JSRuntime *rt = comp->rt;
     JS_ASSERT(rt->onOwnerThread());
 
-    if (rt->gcRunning)
+    if (rt->isHeapBusy())
         return;
 
     if (rt->gcZeal() == ZealAllocValue) {
         TriggerGC(rt, reason);
         return;
     }
 
     if (comp == rt->atomsCompartment) {
@@ -2563,17 +2563,17 @@ DecommitArenasFromAvailableList(JSRuntim
             bool ok;
             {
                 /*
                  * If the main thread waits for the decommit to finish, skip
                  * potentially expensive unlock/lock pair on the contested
                  * lock.
                  */
                 Maybe<AutoUnlockGC> maybeUnlock;
-                if (!rt->gcRunning)
+                if (!rt->isHeapBusy())
                     maybeUnlock.construct(rt);
                 ok = MarkPagesUnused(aheader->getArena(), ArenaSize);
             }
 
             if (ok) {
                 ++chunk->info.numArenasFree;
                 chunk->decommittedArenas.set(arenaIndex);
             } else {
@@ -3280,19 +3280,19 @@ ValidateIncrementalMarking(JSRuntime *rt
 #endif
 
 static void
 SweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool *startBackgroundSweep)
 {
     /*
      * Sweep phase.
      *
-     * Finalize as we sweep, outside of rt->gcLock but with rt->gcRunning set
-     * so that any attempt to allocate a GC-thing from a finalizer will fail,
-     * rather than nest badly and leave the unmarked newborn to be swept.
+     * Finalize as we sweep, outside of rt->gcLock but with rt->isHeapBusy()
+     * true so that any attempt to allocate a GC-thing from a finalizer will
+     * fail, rather than nest badly and leave the unmarked newborn to be swept.
      *
      * We first sweep atom state so we can use IsAboutToBeFinalized on
      * JSString held in a hashtable to check if the hashtable entry can be
      * freed. Note that even after the entry is freed, JSObject finalizers can
      * continue to access the corresponding JSString* assuming that they are
      * unique. This works since the atomization API must not be called during
      * the GC.
      */
@@ -3415,53 +3415,54 @@ SweepPhase(JSRuntime *rt, JSGCInvocation
     for (CompartmentsIter c(rt); !c.done(); c.next())
         c->setGCLastBytes(c->gcBytes, c->gcMallocAndFreeBytes, gckind);
 }
 
 /*
  * This class should be used by any code that needs to exclusive access to the
  * heap in order to trace through it...
  */
-class AutoHeapSession {
+class AutoTraceSession {
   public:
-    explicit AutoHeapSession(JSRuntime *rt);
-    ~AutoHeapSession();
+    AutoTraceSession(JSRuntime *rt, JSRuntime::HeapState state = JSRuntime::Tracing);
+    ~AutoTraceSession();
 
   protected:
     JSRuntime *runtime;
 
   private:
-    AutoHeapSession(const AutoHeapSession&) MOZ_DELETE;
-    void operator=(const AutoHeapSession&) MOZ_DELETE;
+    AutoTraceSession(const AutoTraceSession&) MOZ_DELETE;
+    void operator=(const AutoTraceSession&) MOZ_DELETE;
 };
 
 /* ...while this class is to be used only for garbage collection. */
-class AutoGCSession : AutoHeapSession {
+class AutoGCSession : AutoTraceSession {
   public:
     explicit AutoGCSession(JSRuntime *rt);
     ~AutoGCSession();
 };
 
 /* Start a new heap session. */
-AutoHeapSession::AutoHeapSession(JSRuntime *rt)
+AutoTraceSession::AutoTraceSession(JSRuntime *rt, JSRuntime::HeapState heapState)
   : runtime(rt)
 {
     JS_ASSERT(!rt->noGCOrAllocationCheck);
-    JS_ASSERT(!rt->gcRunning);
-    rt->gcRunning = true;
+    JS_ASSERT(!rt->isHeapBusy());
+    JS_ASSERT(heapState == JSRuntime::Collecting || heapState == JSRuntime::Tracing);
+    rt->heapState = heapState;
 }
 
-AutoHeapSession::~AutoHeapSession()
+AutoTraceSession::~AutoTraceSession()
 {
-    JS_ASSERT(runtime->gcRunning);
-    runtime->gcRunning = false;
+    JS_ASSERT(runtime->isHeapBusy());
+    runtime->heapState = JSRuntime::Idle;
 }
 
 AutoGCSession::AutoGCSession(JSRuntime *rt)
-  : AutoHeapSession(rt)
+  : AutoTraceSession(rt, JSRuntime::Collecting)
 {
     DebugOnly<bool> any = false;
     for (CompartmentsIter c(rt); !c.done(); c.next()) {
         if (c->isGCScheduled()) {
             c->setCollecting(true);
             any = true;
         }
     }
@@ -3740,17 +3741,17 @@ static JS_NEVER_INLINE void
 GCCycle(JSRuntime *rt, bool incremental, int64_t budget, JSGCInvocationKind gckind, gcreason::Reason reason)
 {
 #ifdef DEBUG
     for (CompartmentsIter c(rt); !c.done(); c.next())
         JS_ASSERT_IF(rt->gcMode == JSGC_MODE_GLOBAL, c->isGCScheduled());
 #endif
 
     /* Recursive GC is no-op. */
-    if (rt->gcRunning)
+    if (rt->isHeapBusy())
         return;
 
     /* Don't GC if we are reporting an OOM. */
     if (rt->inOOMReport)
         return;
 
     AutoGCSession gcsession(rt);
 
@@ -3951,34 +3952,34 @@ PrepareForDebugGC(JSRuntime *rt)
 
     PrepareForFullGC(rt);
 }
 
 void
 ShrinkGCBuffers(JSRuntime *rt)
 {
     AutoLockGC lock(rt);
-    JS_ASSERT(!rt->gcRunning);
+    JS_ASSERT(!rt->isHeapBusy());
 #ifndef JS_THREADSAFE
     ExpireChunksAndArenas(rt, true);
 #else
     rt->gcHelperThread.startBackgroundShrink();
 #endif
 }
 
 void
 TraceRuntime(JSTracer *trc)
 {
     JS_ASSERT(!IS_GC_MARKING_TRACER(trc));
 
 #ifdef JS_THREADSAFE
     {
         JSRuntime *rt = trc->runtime;
-        if (!rt->gcRunning) {
-            AutoHeapSession session(rt);
+        if (!rt->isHeapBusy()) {
+            AutoTraceSession session(rt);
 
             rt->gcHelperThread.waitBackgroundSweepEnd();
 
             AutoCopyFreeListToArenas copy(rt);
             RecordNativeStackTopForGC(rt);
             MarkRuntime(trc);
             return;
         }
@@ -4024,19 +4025,19 @@ struct IterateCellCallbackOp
 };
 
 void
 IterateCompartmentsArenasCells(JSRuntime *rt, void *data,
                                JSIterateCompartmentCallback compartmentCallback,
                                IterateArenaCallback arenaCallback,
                                IterateCellCallback cellCallback)
 {
-    JS_ASSERT(!rt->gcRunning);
-
-    AutoHeapSession session(rt);
+    JS_ASSERT(!rt->isHeapBusy());
+
+    AutoTraceSession session(rt);
     rt->gcHelperThread.waitBackgroundSweepEnd();
 
     AutoCopyFreeListToArenas copy(rt);
     for (CompartmentsIter c(rt); !c.done(); c.next()) {
         (*compartmentCallback)(rt, data, c);
 
         for (size_t thingKind = 0; thingKind != FINALIZE_LIMIT; thingKind++) {
             JSGCTraceKind traceKind = MapAllocToTraceKind(AllocKind(thingKind));
@@ -4047,33 +4048,33 @@ IterateCompartmentsArenasCells(JSRuntime
         }
     }
 }
 
 void
 IterateChunks(JSRuntime *rt, void *data, IterateChunkCallback chunkCallback)
 {
     /* :XXX: Any way to common this preamble with IterateCompartmentsArenasCells? */
-    JS_ASSERT(!rt->gcRunning);
-
-    AutoHeapSession session(rt);
+    JS_ASSERT(!rt->isHeapBusy());
+
+    AutoTraceSession session(rt);
     rt->gcHelperThread.waitBackgroundSweepEnd();
 
     for (js::GCChunkSet::Range r = rt->gcChunkSet.all(); !r.empty(); r.popFront())
         chunkCallback(rt, data, r.front());
 }
 
 void
 IterateCells(JSRuntime *rt, JSCompartment *compartment, AllocKind thingKind,
              void *data, IterateCellCallback cellCallback)
 {
     /* :XXX: Any way to common this preamble with IterateCompartmentsArenasCells? */
-    JS_ASSERT(!rt->gcRunning);
-
-    AutoHeapSession session(rt);
+    JS_ASSERT(!rt->isHeapBusy());
+
+    AutoTraceSession session(rt);
     rt->gcHelperThread.waitBackgroundSweepEnd();
 
     AutoCopyFreeListToArenas copy(rt);
 
     JSGCTraceKind traceKind = MapAllocToTraceKind(thingKind);
     size_t thingSize = Arena::thingSize(thingKind);
 
     if (compartment) {
@@ -4087,19 +4088,19 @@ IterateCells(JSRuntime *rt, JSCompartmen
     }
 }
 
 void
 IterateGrayObjects(JSCompartment *compartment, GCThingCallback *cellCallback, void *data)
 {
     JS_ASSERT(compartment);
     JSRuntime *rt = compartment->rt;
-    JS_ASSERT(!rt->gcRunning);
-
-    AutoHeapSession session(rt);
+    JS_ASSERT(!rt->isHeapBusy());
+
+    AutoTraceSession session(rt);
     rt->gcHelperThread.waitBackgroundSweepEnd();
 
     AutoCopyFreeListToArenas copy(rt);
 
     for (size_t finalizeKind = 0; finalizeKind <= FINALIZE_OBJECT_LAST; finalizeKind++) {
         for (CellIterUnderGC i(compartment, AllocKind(finalizeKind)); !i.done(); i.next()) {
             Cell *cell = i.getCell();
             if (cell->isMarked(GRAY))
@@ -4449,17 +4450,17 @@ NextNode(VerifyNode *node)
 }
 
 static void
 StartVerifyBarriers(JSRuntime *rt)
 {
     if (rt->gcVerifyData || rt->gcIncrementalState != NO_INCREMENTAL)
         return;
 
-    AutoHeapSession session(rt);
+    AutoTraceSession session(rt);
 
     if (!IsIncrementalGCSafe(rt))
         return;
 
     rt->gcHelperThread.waitBackgroundSweepOrAllocEnd();
 
     AutoCopyFreeListToArenas copy(rt);
     RecordNativeStackTopForGC(rt);
@@ -4577,17 +4578,17 @@ AssertMarkedOrAllocated(const EdgeValue 
     JS_snprintf(msgbuf, sizeof(msgbuf), "[barrier verifier] Unmarked edge: %s", label);
     MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
     MOZ_CRASH();
 }
 
 static void
 EndVerifyBarriers(JSRuntime *rt)
 {
-    AutoHeapSession session(rt);
+    AutoTraceSession session(rt);
 
     rt->gcHelperThread.waitBackgroundSweepOrAllocEnd();
 
     AutoCopyFreeListToArenas copy(rt);
     RecordNativeStackTopForGC(rt);
 
     VerifyTracer *trc = (VerifyTracer *)rt->gcVerifyData;
 
@@ -4793,19 +4794,19 @@ PurgePCCounts(JSContext *cx)
 }
 
 } /* namespace js */
 
 JS_PUBLIC_API(void)
 JS_IterateCompartments(JSRuntime *rt, void *data,
                        JSIterateCompartmentCallback compartmentCallback)
 {
-    JS_ASSERT(!rt->gcRunning);
-
-    AutoHeapSession session(rt);
+    JS_ASSERT(!rt->isHeapBusy());
+
+    AutoTraceSession session(rt);
     rt->gcHelperThread.waitBackgroundSweepOrAllocEnd();
 
     for (CompartmentsIter c(rt); !c.done(); c.next())
         (*compartmentCallback)(rt, data, c);
 }
 
 #if JS_HAS_XML_SUPPORT
 extern size_t sE4XObjectsCreated;
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -288,22 +288,22 @@ class CellIterImpl
         thing += thingSize;
     }
 };
 
 class CellIterUnderGC : public CellIterImpl
 {
   public:
     CellIterUnderGC(JSCompartment *comp, AllocKind kind) {
-        JS_ASSERT(comp->rt->gcRunning);
+        JS_ASSERT(comp->rt->isHeapBusy());
         init(comp, kind);
     }
 
     CellIterUnderGC(ArenaHeader *aheader) {
-        JS_ASSERT(aheader->compartment->rt->gcRunning);
+        JS_ASSERT(aheader->compartment->rt->isHeapBusy());
         init(aheader);
     }
 };
 
 /*
  * When using the iterator outside the GC the caller must ensure that no GC or
  * allocations of GC things are possible and that the background finalization
  * for the given thing kind is not enabled or is done.
@@ -325,17 +325,17 @@ class CellIter : public CellIterImpl
          * against other threads iterating or allocating. However, we do have
          * background finalization; make sure people aren't using CellIter to
          * walk such allocation kinds.
          */
         JS_ASSERT(!IsBackgroundAllocKind(kind));
         if (lists->isSynchronizedFreeList(kind)) {
             lists = NULL;
         } else {
-            JS_ASSERT(!comp->rt->gcRunning);
+            JS_ASSERT(!comp->rt->isHeapBusy());
             lists->copyFreeListToArena(kind);
         }
 #ifdef DEBUG
         counter = &comp->rt->noGCOrAllocationCheck;
         ++*counter;
 #endif
         init(comp, kind);
     }
@@ -356,17 +356,17 @@ inline void EmptyArenaOp(Arena *arena) {
 inline void EmptyCellOp(Cell *t) {}
 
 class GCCompartmentsIter {
   private:
     JSCompartment **it, **end;
 
   public:
     GCCompartmentsIter(JSRuntime *rt) {
-        JS_ASSERT(rt->gcRunning);
+        JS_ASSERT(rt->isHeapBusy());
         it = rt->compartments.begin();
         end = rt->compartments.end();
         if (!(*it)->isCollecting())
             next();
     }
 
     bool done() const { return it == end; }
 
@@ -395,17 +395,17 @@ class GCCompartmentsIter {
 
 template <typename T>
 inline T *
 NewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize)
 {
     JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind));
     JS_ASSERT_IF(cx->compartment == cx->runtime->atomsCompartment,
                  kind == js::gc::FINALIZE_STRING || kind == js::gc::FINALIZE_SHORT_STRING);
-    JS_ASSERT(!cx->runtime->gcRunning);
+    JS_ASSERT(!cx->runtime->isHeapBusy());
     JS_ASSERT(!cx->runtime->noGCOrAllocationCheck);
 
     /* For testing out of memory conditions */
     JS_OOM_POSSIBLY_FAIL_REPORT(cx);
 
 #ifdef JS_GC_ZEAL
     if (cx->runtime->needZealousGC())
         js::gc::RunDebugGC(cx);
@@ -426,17 +426,17 @@ NewGCThing(JSContext *cx, js::gc::AllocK
 /* Alternate form which allocates a GC thing if doing so cannot trigger a GC. */
 template <typename T>
 inline T *
 TryNewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize)
 {
     JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind));
     JS_ASSERT_IF(cx->compartment == cx->runtime->atomsCompartment,
                  kind == js::gc::FINALIZE_STRING || kind == js::gc::FINALIZE_SHORT_STRING);
-    JS_ASSERT(!cx->runtime->gcRunning);
+    JS_ASSERT(!cx->runtime->isHeapBusy());
     JS_ASSERT(!cx->runtime->noGCOrAllocationCheck);
 
 #ifdef JS_GC_ZEAL
     if (cx->runtime->needZealousGC())
         return NULL;
 #endif
 
     void *t = cx->compartment->arenas.allocateFromFreeList(kind, thingSize);
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -774,17 +774,17 @@ TypeCompartment::compartment()
 {
     return (JSCompartment *)((char *)this - offsetof(JSCompartment, types));
 }
 
 inline void
 TypeCompartment::addPending(JSContext *cx, TypeConstraint *constraint, TypeSet *source, Type type)
 {
     JS_ASSERT(this == &cx->compartment->types);
-    JS_ASSERT(!cx->runtime->gcRunning);
+    JS_ASSERT(!cx->runtime->isHeapBusy());
 
     InferSpew(ISpewOps, "pending: %sC%p%s %s",
               InferSpewColor(constraint), constraint, InferSpewColorReset(),
               TypeString(type));
 
     if ((pendingCount == pendingCapacity) && !growPendingArray(cx))
         return;
 
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -399,17 +399,17 @@ ToDisassemblySource(JSContext *cx, jsval
             return false;
         nbytes = JS_sprintf_append(NULL, "%s", nbytes);
         if (!nbytes)
             return false;
         bytes->initBytes(nbytes);
         return true;
     }
 
-    if (cx->runtime->gcRunning || cx->runtime->noGCOrAllocationCheck) {
+    if (cx->runtime->isHeapBusy() || cx->runtime->noGCOrAllocationCheck) {
         char *source = JS_sprintf_append(NULL, "<value>");
         if (!source)
             return false;
         bytes->initBytes(source);
         return true;
     }
 
     if (!JSVAL_IS_PRIMITIVE(v)) {
--- a/js/src/jspropertycache.cpp
+++ b/js/src/jspropertycache.cpp
@@ -14,17 +14,17 @@
 
 using namespace js;
 
 PropertyCacheEntry *
 PropertyCache::fill(JSContext *cx, JSObject *obj, unsigned scopeIndex, JSObject *pobj,
                     Shape *shape)
 {
     JS_ASSERT(this == &JS_PROPERTY_CACHE(cx));
-    JS_ASSERT(!cx->runtime->gcRunning);
+    JS_ASSERT(!cx->runtime->isHeapBusy());
 
     /*
      * Check for overdeep scope and prototype chain. Because resolve, getter,
      * and setter hooks can change the prototype chain using JS_SetPrototype
      * after LookupPropertyWithFlags has returned, we calculate the protoIndex
      * here and not in LookupPropertyWithFlags.
      *
      * The scopeIndex can't be wrong. We require JS_SetParent calls to happen
--- a/js/src/jsscriptinlines.h
+++ b/js/src/jsscriptinlines.h
@@ -250,17 +250,17 @@ inline void
 JSScript::writeBarrierPre(JSScript *script)
 {
 #ifdef JSGC_INCREMENTAL
     if (!script)
         return;
 
     JSCompartment *comp = script->compartment();
     if (comp->needsBarrier()) {
-        JS_ASSERT(!comp->rt->gcRunning);
+        JS_ASSERT(!comp->rt->isHeapBusy());
         JSScript *tmp = script;
         MarkScriptUnbarriered(comp->barrierTracer(), &tmp, "write barrier");
         JS_ASSERT(tmp == script);
     }
 #endif
 }
 
 inline void
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -924,17 +924,17 @@ JSXMLArray<T>::trim()
     if (length < capacity)
         setCapacity(NULL, length);
 }
 
 template<class T>
 void
 JSXMLArray<T>::finish(FreeOp *fop)
 {
-    if (!fop->runtime()->gcRunning) {
+    if (!fop->runtime()->isHeapBusy()) {
         /* We need to clear these to trigger a write barrier. */
         for (uint32_t i = 0; i < length; i++)
             vector[i].~HeapPtr<T>();
     }
 
     fop->free_(vector);
 
     while (JSXMLArrayCursor<T> *cursor = cursors)
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -271,17 +271,17 @@ BreakpointSite::clearTrap(FreeOp *fop, J
     if (handlerp)
         *handlerp = trapHandler;
     if (closurep)
         *closurep = trapClosure;
 
     trapHandler = NULL;
     trapClosure = UndefinedValue();
     if (enabledCount == 0) {
-        if (!fop->runtime()->gcRunning) {
+        if (!fop->runtime()->isHeapBusy()) {
             /* If the GC is running then the script is being destroyed. */
             recompile(fop);
         }
         destroyIfEmpty(fop);
     }
 }
 
 void
@@ -366,17 +366,17 @@ Debugger::Debugger(JSContext *cx, JSObje
     JS_INIT_CLIST(&breakpoints);
 }
 
 Debugger::~Debugger()
 {
     JS_ASSERT(debuggees.empty());
 
     /* This always happens in the GC thread, so no locking is required. */
-    JS_ASSERT(object->compartment()->rt->gcRunning);
+    JS_ASSERT(object->compartment()->rt->isHeapBusy());
     JS_REMOVE_LINK(&link);
 }
 
 bool
 Debugger::init(JSContext *cx)
 {
     bool ok = debuggees.init() &&
               frames.init() &&
--- a/js/src/vm/ObjectImpl-inl.h
+++ b/js/src/vm/ObjectImpl-inl.h
@@ -322,17 +322,17 @@ js::ObjectImpl::sizeOfThis() const
 }
 
 /* static */ inline void
 js::ObjectImpl::readBarrier(ObjectImpl *obj)
 {
 #ifdef JSGC_INCREMENTAL
     JSCompartment *comp = obj->compartment();
     if (comp->needsBarrier()) {
-        MOZ_ASSERT(!comp->rt->gcRunning);
+        MOZ_ASSERT(!comp->rt->isHeapBusy());
         JSObject *tmp = obj->asObjectPtr();
         MarkObjectUnbarriered(comp->barrierTracer(), &tmp, "read barrier");
         MOZ_ASSERT(tmp == obj->asObjectPtr());
     }
 #endif
 }
 
 inline void
@@ -360,17 +360,17 @@ js::ObjectImpl::writeBarrierPre(ObjectIm
      * This would normally be a null test, but TypeScript::global uses 0x1 as a
      * special value.
      */
     if (uintptr_t(obj) < 32)
         return;
 
     JSCompartment *comp = obj->compartment();
     if (comp->needsBarrier()) {
-        MOZ_ASSERT(!comp->rt->gcRunning);
+        MOZ_ASSERT(!comp->rt->isHeapBusy());
         JSObject *tmp = obj->asObjectPtr();
         MarkObjectUnbarriered(comp->barrierTracer(), &tmp, "write barrier");
         MOZ_ASSERT(tmp == obj->asObjectPtr());
     }
 #endif
 }
 
 /* static */ inline void
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -237,20 +237,20 @@ RegExpCode::execute(JSContext *cx, const
 
 /* RegExpObject */
 
 static void
 regexp_trace(JSTracer *trc, JSObject *obj)
 {
      /*
       * We have to check both conditions, since:
-      *   1. During TraceRuntime, gcRunning is set
+      *   1. During TraceRuntime, isHeapBusy() is true
       *   2. When a write barrier executes, IS_GC_MARKING_TRACER is true.
       */
-    if (trc->runtime->gcRunning && IS_GC_MARKING_TRACER(trc))
+    if (trc->runtime->isHeapBusy() && IS_GC_MARKING_TRACER(trc))
         obj->setPrivate(NULL);
 }
 
 Class js::RegExpClass = {
     js_RegExp_str,
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(RegExpObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp),