Bug 754588 - Set rt->gcPoke when doing xpconnect unrooting (r=mccr8)
authorBill McCloskey <wmccloskey@mozilla.com>
Tue, 22 May 2012 14:06:58 -0700
changeset 94623 e3cac83d3a14e5f0c7c799adf3be4d3532b0ce60
parent 94622 7b352f6f047f2540141fe65ebafdf085c61b4e84
child 94624 bfb4508c62aa7486dfab5df1cf85f0e9bb1d04e1
push id22732
push useremorley@mozilla.com
push dateWed, 23 May 2012 09:43:13 +0000
treeherdermozilla-central@aa2b52bd0374 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
bugs754588
milestone15.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 754588 - Set rt->gcPoke when doing xpconnect unrooting (r=mccr8)
js/src/jsapi.cpp
js/src/jscntxt.h
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsgc.cpp
js/xpconnect/src/XPCJSRuntime.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -713,16 +713,17 @@ JSRuntime::JSRuntime()
     gcMaxBytes(0),
     gcMaxMallocBytes(0),
     gcNumArenasFreeCommitted(0),
     gcVerifyData(NULL),
     gcChunkAllocationSinceLastGC(false),
     gcNextFullGCTime(0),
     gcJitReleaseTime(0),
     gcMode(JSGC_MODE_GLOBAL),
+    gcShouldCleanUpEverything(false),
     gcIsNeeded(0),
     gcWeakMapList(NULL),
     gcStats(thisFromCtor()),
     gcNumber(0),
     gcStartNumber(0),
     gcIsFull(false),
     gcTriggerReason(gcreason::NO_REASON),
     gcStrictCompartmentChecking(false),
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -485,16 +485,19 @@ struct JSRuntime : js::RuntimeFriendFiel
     volatile uint32_t   gcNumArenasFreeCommitted;
     js::GCMarker        gcMarker;
     void                *gcVerifyData;
     bool                gcChunkAllocationSinceLastGC;
     int64_t             gcNextFullGCTime;
     int64_t             gcJitReleaseTime;
     JSGCMode            gcMode;
 
+    /* During shutdown, the GC needs to clean up every possible object. */
+    bool                gcShouldCleanUpEverything;
+
     /*
      * These flags must be kept separate so that a thread requesting a
      * compartment GC doesn't cancel another thread's concurrent request for a
      * full GC.
      */
     volatile uintptr_t  gcIsNeeded;
 
     js::WeakMapBase     *gcWeakMapList;
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -780,16 +780,22 @@ IncrementalReferenceBarrier(void *ptr)
 }
 
 extern JS_FRIEND_API(void)
 IncrementalValueBarrier(const Value &v)
 {
     HeapValue::writeBarrierPre(v);
 }
 
+extern JS_FRIEND_API(void)
+PokeGC(JSRuntime *rt)
+{
+    rt->gcPoke = true;
+}
+
 JS_FRIEND_API(JSObject *)
 GetTestingFunctions(JSContext *cx)
 {
     JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
     if (!obj)
         return NULL;
 
     if (!DefineTestingFunctions(cx, obj))
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -695,16 +695,19 @@ extern JS_FRIEND_API(bool)
 IsIncrementalBarrierNeededOnScript(JSScript *obj);
 
 extern JS_FRIEND_API(void)
 IncrementalReferenceBarrier(void *ptr);
 
 extern JS_FRIEND_API(void)
 IncrementalValueBarrier(const Value &v);
 
+extern JS_FRIEND_API(void)
+PokeGC(JSRuntime *rt);
+
 class ObjectPtr
 {
     JSObject *value;
 
   public:
     ObjectPtr() : value(NULL) {}
 
     ObjectPtr(JSObject *obj) : value(obj) {}
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2867,17 +2867,17 @@ PurgeRuntime(JSTracer *trc)
 
     for (ContextIter acx(rt); !acx.done(); acx.next())
         acx->purge();
 }
 
 static bool
 ShouldPreserveJITCode(JSCompartment *c, int64_t currentTime)
 {
-    if (!c->rt->hasContexts() || !c->types.inferenceEnabled)
+    if (c->rt->gcShouldCleanUpEverything || !c->types.inferenceEnabled)
         return false;
 
     if (c->rt->alwaysPreserveCode)
         return true;
     if (c->lastAnimationTime + PRMJ_USEC_PER_SEC >= currentTime &&
         c->lastCodeRelease + (PRMJ_USEC_PER_SEC * 300) >= currentTime) {
         return true;
     }
@@ -3623,16 +3623,22 @@ IsDeterministicGCReason(gcreason::Reason
 
     if (reason == gcreason::MAYBEGC)
         return false;
 
     return true;
 }
 #endif
 
+static bool
+ShouldCleanUpEverything(JSRuntime *rt, gcreason::Reason reason)
+{
+    return !rt->hasContexts() || reason == gcreason::CC_FORCED;
+}
+
 static void
 Collect(JSRuntime *rt, bool incremental, int64_t budget,
         JSGCInvocationKind gckind, gcreason::Reason reason)
 {
     JS_AbortIfWrongThread(rt);
 
 #ifdef JS_GC_ZEAL
     if (rt->gcDeterministicOnly && !IsDeterministicGCReason(reason))
@@ -3674,16 +3680,18 @@ Collect(JSRuntime *rt, bool incremental,
         if (rt->gcIncrementalState != NO_INCREMENTAL && c->needsBarrier())
             c->scheduleGC();
 
         compartmentCount++;
         if (c->isGCScheduled())
             collectedCount++;
     }
 
+    rt->gcShouldCleanUpEverything = ShouldCleanUpEverything(rt, reason);
+
     gcstats::AutoGCSlice agc(rt->gcStats, collectedCount, compartmentCount, reason);
 
     do {
         /*
          * Let the API user decide to defer a GC if it wants to (unless this
          * is the last context). Invoke the callback regardless.
          */
         if (rt->gcIncrementalState == NO_INCREMENTAL) {
@@ -3697,24 +3705,24 @@ Collect(JSRuntime *rt, bool incremental,
 
         if (rt->gcIncrementalState == NO_INCREMENTAL) {
             gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_GC_END);
             if (JSGCCallback callback = rt->gcCallback)
                 callback(rt, JSGC_END);
         }
 
         /* Need to re-schedule all compartments for GC. */
-        if (!rt->hasContexts() && rt->gcPoke)
+        if (rt->gcPoke && rt->gcShouldCleanUpEverything)
             PrepareForFullGC(rt);
 
         /*
          * On shutdown, iterate until finalizers or the JSGC_END callback
          * stop creating garbage.
          */
-    } while (!rt->hasContexts() && rt->gcPoke);
+    } while (rt->gcPoke && rt->gcShouldCleanUpEverything);
 }
 
 namespace js {
 
 void
 GC(JSRuntime *rt, JSGCInvocationKind gckind, gcreason::Reason reason)
 {
     Collect(rt, false, SliceBudget::Unlimited, gckind, reason);
@@ -4573,9 +4581,8 @@ JSXML *
 js_NewGCXML(JSContext *cx)
 {
     if (!cx->runningWithTrustedPrincipals())
         ++sE4XObjectsCreated;
 
     return NewGCThing<JSXML>(cx, js::gc::FINALIZE_XML, sizeof(JSXML));
 }
 #endif
-
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -2265,16 +2265,19 @@ XPCRootSetElem::AddToRootSet(XPCLock *lo
         mNext->mSelfp = &mNext;
     }
     *listHead = this;
 }
 
 void
 XPCRootSetElem::RemoveFromRootSet(XPCLock *lock)
 {
+    if (nsXPConnect *xpc = nsXPConnect::GetXPConnect())
+        js::PokeGC(xpc->GetRuntime()->GetJSRuntime());
+
     NS_ASSERTION(mSelfp, "Must be linked");
 
     XPCAutoLock autoLock(lock);
 
     NS_ASSERTION(*mSelfp == this, "Link invariant");
     *mSelfp = mNext;
     if (mNext)
         mNext->mSelfp = mSelfp;