Bug 899367 - Explicitly trace outer windows, rather than doing it via JSContext iteration. r=mccr8
authorBobby Holley <bobbyholley@gmail.com>
Wed, 04 Sep 2013 14:06:54 -0700
changeset 158484 c800b53263d221923333191d3e1933af1bac6112
parent 158483 001f423a94e8fedf82591e2f7cb9e225cf679cd6
child 158485 bb9646daf4c382ba31f91df5acd20a6e62a5fb38
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
bugs899367
milestone26.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 899367 - Explicitly trace outer windows, rather than doing it via JSContext iteration. r=mccr8
dom/base/nsJSEnvironment.cpp
dom/base/nsJSEnvironment.h
js/xpconnect/src/XPCJSRuntime.cpp
xpcom/base/CycleCollectedJSRuntime.cpp
xpcom/base/CycleCollectedJSRuntime.h
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2935,16 +2935,31 @@ mozilla::dom::ShutdownJSEnvironment()
     NS_IF_RELEASE(sRuntimeService);
     NS_IF_RELEASE(sSecurityManager);
   }
 
   sShuttingDown = true;
   sDidShutdown = true;
 }
 
+void
+mozilla::dom::TraceOuterWindows(JSTracer* aTracer)
+{
+  MOZ_ASSERT_IF(JS_IsGCMarkingTracer(aTracer), JS_IsMarkingGray(aTracer));
+  for (nsJSContext* cx = sContextList; cx; cx = cx->mNext) {
+    JSObject* outer;
+    if (cx->mContext &&
+        (outer = js::DefaultObjectForContextOrNull(cx->mContext)))
+    {
+      JS::AssertGCThingMustBeTenured(outer);
+      JS_CallObjectTracer(aTracer, &outer, "Outer Window");
+    }
+  }
+}
+
 // A fast-array class for JS.  This class supports both nsIJSScriptArray and
 // nsIArray.  If it is JS itself providing and consuming this class, all work
 // can be done via nsIJSScriptArray, and avoid the conversion of elements
 // to/from nsISupports.
 // When consumed by non-JS (eg, another script language), conversion is done
 // on-the-fly.
 class nsJSArgArray MOZ_FINAL : public nsIJSArgArray {
 public:
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -24,16 +24,24 @@ class nsScriptNameSpaceManager;
 namespace mozilla {
 template <class> class Maybe;
 }
 
 // The amount of time we wait between a request to GC (due to leaving
 // a page) and doing the actual GC.
 #define NS_GC_DELAY                 4000 // ms
 
+namespace mozilla {
+namespace dom {
+
+void TraceOuterWindows(JSTracer *aTracer);
+
+} /* namespace dom */
+} /* namespace mozilla */
+
 class nsJSContext : public nsIScriptContext
 {
 public:
   nsJSContext(bool aGCOnDestruction, nsIScriptGlobalObject* aGlobalObject);
   virtual ~nsJSContext();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSContext,
@@ -167,16 +175,19 @@ private:
   PRTime mOperationCallbackTime;
 
   PRTime mModalStateTime;
   uint32_t mModalStateDepth;
 
   nsJSContext *mNext;
   nsJSContext **mPrev;
 
+  /* This function needs access to the linked list members above. */
+  friend void mozilla::dom::TraceOuterWindows(JSTracer *aTracer);
+
   // mGlobalObjectRef ensures that the outer window stays alive as long as the
   // context does. It is eventually collected by the cycle collector.
   nsCOMPtr<nsIScriptGlobalObject> mGlobalObjectRef;
 
   static int JSOptionChangedCallback(const char *pref, void *data);
 
   static bool DOMOperationCallback(JSContext *cx);
 };
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -491,16 +491,20 @@ void XPCJSRuntime::TraceNativeBlackRoots
     dom::TraceBlackJS(trc, JS_GetGCParameter(Runtime(), JSGC_NUMBER),
                       nsXPConnect::XPConnect()->IsShuttingDown());
 }
 
 void XPCJSRuntime::TraceAdditionalNativeGrayRoots(JSTracer *trc)
 {
     XPCAutoLock lock(mMapLock);
 
+    // Trace outer windows, which are the default compartment objects for DOM
+    // JSContexts.
+    dom::TraceOuterWindows(trc);
+
     XPCWrappedNativeScope::TraceWrappedNativesInAllScopes(trc, this);
 
     for (XPCRootSetElem *e = mVariantRoots; e ; e = e->GetNextRoot())
         static_cast<XPCTraceableVariant*>(e)->TraceJS(trc);
 
     for (XPCRootSetElem *e = mWrappedJSRoots; e ; e = e->GetNextRoot())
         static_cast<nsXPCWrappedJS*>(e)->TraceJS(trc);
 }
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -534,36 +534,16 @@ UnmarkJSHolder(void* holder, nsScriptObj
 
 void
 CycleCollectedJSRuntime::UnmarkSkippableJSHolders()
 {
   mJSHolders.Enumerate(UnmarkJSHolder, nullptr);
 }
 
 void
-CycleCollectedJSRuntime::MaybeTraceGlobals(JSTracer* aTracer) const
-{
-  JSContext* iter = nullptr;
-  while (JSContext* acx = JS_ContextIterator(Runtime(), &iter)) {
-    // DOM JSContexts are the only JSContexts that cycle-collect their default
-    // compartment object, so they're the only ones that we need to do the
-    // JSOPTION_UNROOTED_GLOBAL dance for. The other ones are just marked black.
-    MOZ_ASSERT(js::HasUnrootedGlobal(acx) == !!GetScriptContextFromJSContext(acx));
-    if (!js::HasUnrootedGlobal(acx)) {
-      continue;
-    }
-
-    if (JSObject* global = js::DefaultObjectForContextOrNull(acx)) {
-      JS::AssertGCThingMustBeTenured(global);
-      JS_CallObjectTracer(aTracer, &global, "Global Object");
-    }
-  }
-}
-
-void
 CycleCollectedJSRuntime::DescribeGCThing(bool aIsMarked, void* aThing,
                                          JSGCTraceKind aTraceKind,
                                          nsCycleCollectionTraversalCallback& aCb) const
 {
   if (!aCb.WantDebugInfo()) {
     aCb.DescribeGCedNode(aIsMarked, "JS Object");
     return;
   }
@@ -835,18 +815,16 @@ TraceJSHolder(void* aHolder, nsScriptObj
   aTracer->Trace(aHolder, JsGcTracer(), aArg);
 
   return PL_DHASH_NEXT;
 }
 
 void
 CycleCollectedJSRuntime::TraceNativeGrayRoots(JSTracer* aTracer)
 {
-  MaybeTraceGlobals(aTracer);
-
   // NB: This is here just to preserve the existing XPConnect order. I doubt it
   // would hurt to do this after the JS holders.
   TraceAdditionalNativeGrayRoots(aTracer);
 
   mJSHolders.Enumerate(TraceJSHolder, aTracer);
 }
 
 void
--- a/xpcom/base/CycleCollectedJSRuntime.h
+++ b/xpcom/base/CycleCollectedJSRuntime.h
@@ -141,19 +141,16 @@ private:
 
   static void
   TraverseObjectShim(void* aData, void* aThing);
 
   void MaybeTraverseGlobals(nsCycleCollectionNoteRootCallback& aCb) const;
 
   void TraverseNativeRoots(nsCycleCollectionNoteRootCallback& aCb);
 
-  void MaybeTraceGlobals(JSTracer* aTracer) const;
-
-
   static void TraceBlackJS(JSTracer* aTracer, void* aData);
   static void TraceGrayJS(JSTracer* aTracer, void* aData);
   static void GCCallback(JSRuntime* aRuntime, JSGCStatus aStatus, void* aData);
   static bool ContextCallback(JSContext* aCx, unsigned aOperation,
                               void* aData);
 
   virtual void TraceNativeBlackRoots(JSTracer* aTracer) { };
   void TraceNativeGrayRoots(JSTracer* aTracer);