Bug 742570 - Change API for compartment GCs (r=igor)
authorBill McCloskey <wmccloskey@mozilla.com>
Tue, 03 Apr 2012 12:23:11 -0700
changeset 94442 bc7f3c6766263a33daf4fe0817c9d7b5fb738014
parent 94441 94efe1ec3367688a9871c67da042e59750b6543b
child 94443 15a23c3923ff9752395c339165cdf113629608a4
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersigor
bugs742570
milestone14.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 742570 - Change API for compartment GCs (r=igor)
dom/workers/WorkerPrivate.cpp
js/src/builtin/TestingFunctions.cpp
js/src/jsapi.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsgc.cpp
js/src/jsgc.h
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/nsXPConnect.cpp
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -3886,16 +3886,17 @@ WorkerPrivate::UpdateGCZealInternal(JSCo
 #endif
 
 void
 WorkerPrivate::GarbageCollectInternal(JSContext* aCx, bool aShrinking,
                                       bool aCollectChildren)
 {
   AssertIsOnWorkerThread();
 
+  js::PrepareForFullGC(JS_GetRuntime(aCx));
   if (aShrinking) {
     js::ShrinkingGC(aCx, js::gcreason::DOM_WORKER);
   }
   else {
     js::GCForReason(aCx, js::gcreason::DOM_WORKER);
   }
 
   if (aCollectChildren) {
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -27,17 +27,21 @@ GC(JSContext *cx, unsigned argc, jsval *
         if (arg.isObject())
             comp = UnwrapObject(&arg.toObject())->compartment();
     }
 
 #ifndef JS_MORE_DETERMINISTIC
     size_t preBytes = cx->runtime->gcBytes;
 #endif
 
-    JS_CompartmentGC(cx, comp);
+    if (comp)
+        PrepareCompartmentForGC(comp);
+    else
+        PrepareForFullGC(cx->runtime);
+    GCForReason(cx, gcreason::API);
 
     char buf[256] = { '\0' };
 #ifndef JS_MORE_DETERMINISTIC
     JS_snprintf(buf, sizeof(buf), "before %lu, after %lu\n",
                 (unsigned long)preBytes, (unsigned long)cx->runtime->gcBytes);
 #endif
     JSString *str = JS_NewStringCopyZ(cx, buf);
     if (!str)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2854,37 +2854,22 @@ JS_DumpHeap(JSRuntime *rt, FILE *fp, voi
 #endif /* DEBUG */
 
 extern JS_PUBLIC_API(JSBool)
 JS_IsGCMarkingTracer(JSTracer *trc)
 {
     return IS_GC_MARKING_TRACER(trc);
 }
 
-extern JS_PUBLIC_API(void)
-JS_CompartmentGC(JSContext *cx, JSCompartment *comp)
-{
-    AssertNoGC(cx);
-
-    /* We cannot GC the atoms compartment alone; use a full GC instead. */
-    JS_ASSERT(comp != cx->runtime->atomsCompartment);
-
-    if (comp) {
-        PrepareCompartmentForGC(comp);
-        GC(cx, GC_NORMAL, gcreason::API);
-    } else {
-        PrepareForFullGC(cx->runtime);
-        GC(cx, GC_NORMAL, gcreason::API);
-    }
-}
-
 JS_PUBLIC_API(void)
 JS_GC(JSContext *cx)
 {
-    JS_CompartmentGC(cx, NULL);
+    AssertNoGC(cx);
+    PrepareForFullGC(cx->runtime);
+    GC(cx, GC_NORMAL, gcreason::API);
 }
 
 JS_PUBLIC_API(void)
 JS_MaybeGC(JSContext *cx)
 {
     MaybeGC(cx);
 }
 
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -127,43 +127,43 @@ JS_NewObjectWithUniqueType(JSContext *cx
 {
     JSObject *obj = JS_NewObject(cx, clasp, proto, parent);
     if (!obj || !obj->setSingletonType(cx))
         return NULL;
     return obj;
 }
 
 JS_FRIEND_API(void)
-js::GCForReason(JSContext *cx, gcreason::Reason reason)
+js::PrepareCompartmentForGC(JSCompartment *comp)
 {
-    PrepareForFullGC(cx->runtime);
-    GC(cx, GC_NORMAL, reason);
+    comp->scheduleGC();
 }
 
 JS_FRIEND_API(void)
-js::CompartmentGCForReason(JSContext *cx, JSCompartment *comp, gcreason::Reason reason)
+js::PrepareForFullGC(JSRuntime *rt)
 {
-    /* We cannot GC the atoms compartment alone; use a full GC instead. */
-    JS_ASSERT(comp != cx->runtime->atomsCompartment);
+    for (CompartmentsIter c(rt); !c.done(); c.next())
+        c->scheduleGC();
+}
 
-    PrepareCompartmentForGC(comp);
+JS_FRIEND_API(void)
+js::GCForReason(JSContext *cx, gcreason::Reason reason)
+{
     GC(cx, GC_NORMAL, reason);
 }
 
 JS_FRIEND_API(void)
 js::ShrinkingGC(JSContext *cx, gcreason::Reason reason)
 {
-    PrepareForFullGC(cx->runtime);
     GC(cx, GC_SHRINK, reason);
 }
 
 JS_FRIEND_API(void)
 js::IncrementalGC(JSContext *cx, gcreason::Reason reason)
 {
-    PrepareForFullGC(cx->runtime);
     GCSlice(cx, GC_NORMAL, reason);
 }
 
 JS_FRIEND_API(void)
 JS_ShrinkGCBuffers(JSRuntime *rt)
 {
     ShrinkGCBuffers(rt);
 }
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -662,20 +662,30 @@ enum Reason {
 #undef MAKE_REASON
     NO_REASON,
     NUM_REASONS
 };
 
 } /* namespace gcreason */
 
 extern JS_FRIEND_API(void)
-GCForReason(JSContext *cx, gcreason::Reason reason);
+PrepareCompartmentForGC(JSCompartment *comp);
 
 extern JS_FRIEND_API(void)
-CompartmentGCForReason(JSContext *cx, JSCompartment *comp, gcreason::Reason reason);
+PrepareForFullGC(JSRuntime *rt);
+
+/*
+ * When triggering a GC using one of the functions below, it is first necessary
+ * to select the compartments to be collected. To do this, you can call
+ * PrepareCompartmentForGC on each compartment, or you can call PrepareForFullGC
+ * to select all compartments. Failing to select any compartment is an error.
+ */
+
+extern JS_FRIEND_API(void)
+GCForReason(JSContext *cx, gcreason::Reason reason);
 
 extern JS_FRIEND_API(void)
 ShrinkingGC(JSContext *cx, gcreason::Reason reason);
 
 extern JS_FRIEND_API(void)
 IncrementalGC(JSContext *cx, gcreason::Reason reason);
 
 extern JS_FRIEND_API(void)
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2819,29 +2819,16 @@ GCHelperThread::doSweep()
     if (!shrinking && shrinkFlag) {
         shrinkFlag = false;
         ExpireChunksAndArenas(rt, true);
     }
 }
 
 #endif /* JS_THREADSAFE */
 
-void
-PrepareForFullGC(JSRuntime *rt)
-{
-    for (CompartmentsIter c(rt); !c.done(); c.next())
-        c->scheduleGC();
-}
-
-void
-PrepareCompartmentForGC(JSCompartment *comp)
-{
-    comp->scheduleGC();
-}
-
 } /* namespace js */
 
 static bool
 ReleaseObservedTypes(JSRuntime *rt)
 {
     bool releaseTypes = false;
     int64_t now = PRMJ_Now();
     if (now >= rt->gcJitReleaseTime) {
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1381,19 +1381,16 @@ extern void
 MaybeGC(JSContext *cx);
 
 extern void
 ShrinkGCBuffers(JSRuntime *rt);
 
 extern void
 PrepareForFullGC(JSRuntime *rt);
 
-extern void
-PrepareCompartmentForGC(JSCompartment *comp);
-
 /*
  * Kinds of js_GC invocation.
  */
 typedef enum JSGCInvocationKind {
     /* Normal invocation. */
     GC_NORMAL           = 0,
 
     /* Minimize GC triggers and release empty GC chunks right away. */
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -3615,24 +3615,26 @@ nsXPCComponents_Utils::GetWeakReference(
     ref.forget(_retval);
     return NS_OK;
 }
 
 /* void forceGC (); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::ForceGC(JSContext *cx)
 {
+    js::PrepareForFullGC(JS_GetRuntime(cx));
     js::GCForReason(cx, js::gcreason::COMPONENT_UTILS);
     return NS_OK;
 }
 
 /* void forceShrinkingGC (); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::ForceShrinkingGC(JSContext *cx)
 {
+    js::PrepareForFullGC(JS_GetRuntime(cx));
     js::ShrinkingGC(cx, js::gcreason::COMPONENT_UTILS);
     return NS_OK;
 }
 
 class PreciseGCRunnable : public nsRunnable
 {
   public:
     PreciseGCRunnable(JSContext *aCx, ScheduledGCCallback* aCallback, bool aShrinking)
@@ -3650,16 +3652,17 @@ class PreciseGCRunnable : public nsRunna
         JSContext *cx;
         JSContext *iter = nsnull;
         while ((cx = JS_ContextIterator(rt, &iter)) != NULL) {
             if (JS_IsRunning(cx)) {
                 return NS_DispatchToMainThread(this);
             }
         }
 
+        js::PrepareForFullGC(JS_GetRuntime(mCx));
         if (mShrinking)
             js::ShrinkingGC(mCx, js::gcreason::COMPONENT_UTILS);
         else
             js::GCForReason(mCx, js::gcreason::COMPONENT_UTILS);
 
         mCallback->Callback();
         return NS_OK;
     }
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -409,25 +409,27 @@ nsXPConnect::Collect(PRUint32 reason, PR
     // To improve debugging, if DEBUG_CC is defined all JS objects are
     // traversed.
 
     XPCCallContext ccx(NATIVE_CALLER);
     if (!ccx.IsValid())
         return;
 
     JSContext *cx = ccx.GetJSContext();
+    JSRuntime *rt = GetRuntime()->GetJSRuntime();
 
     // We want to scan the current thread for GC roots only if it was in a
     // request prior to the Collect call to avoid false positives during the
     // cycle collection. So to compensate for JS_BeginRequest in
     // XPCCallContext::Init we disable the conservative scanner if that call
     // has started the request on this thread.
     js::AutoSkipConservativeScan ascs(cx);
     MOZ_ASSERT(reason < js::gcreason::NUM_REASONS);
     js::gcreason::Reason gcreason = (js::gcreason::Reason)reason;
+    js::PrepareForFullGC(rt);
     if (kind == nsGCShrinking) {
         js::ShrinkingGC(cx, gcreason);
     } else if (kind == nsGCIncremental) {
         js::IncrementalGC(cx, gcreason);
     } else {
         MOZ_ASSERT(kind == nsGCNormal);
         js::GCForReason(cx, gcreason);
     }