Bug 587222 - Script caching in messageManager leaks; r=Olli.Pettay a=blocking-because-550936-is-a-blocker
authorAlon Zakai <azakai@mozilla.com>
Mon, 16 Aug 2010 16:40:04 -0400
changeset 50684 8541ae9ea9b3102d068981b3d4c232e54d2959c8
parent 50683 d773ca26da83c85fc4a1097d6f2cc43cd209308a
child 50685 c8dc4dd369ee9b8668685d3a2011473cde7390f1
push idunknown
push userunknown
push dateunknown
reviewersOlli, blocking-because-550936-is-a-blocker
bugs587222, 550936
milestone2.0b4pre
Bug 587222 - Script caching in messageManager leaks; r=Olli.Pettay a=blocking-because-550936-is-a-blocker
content/base/src/nsFrameMessageManager.cpp
content/base/src/nsFrameMessageManager.h
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -505,25 +505,28 @@ NS_NewGlobalMessageManager(nsIChromeFram
                                                         nsnull,
                                                         PR_TRUE);
   NS_ENSURE_TRUE(mm, NS_ERROR_OUT_OF_MEMORY);
   return CallQueryInterface(mm, aResult);
 }
 
 nsDataHashtable<nsStringHashKey, nsFrameScriptExecutorJSObjectHolder*>*
   nsFrameScriptExecutor::sCachedScripts = nsnull;
+nsRefPtr<nsScriptCacheCleaner> nsFrameScriptExecutor::sScriptCacheCleaner;
 
 void
 nsFrameScriptExecutor::DidCreateCx()
 {
   NS_ASSERTION(mCx, "Should have mCx!");
   if (!sCachedScripts) {
     sCachedScripts =
       new nsDataHashtable<nsStringHashKey, nsFrameScriptExecutorJSObjectHolder*>;
     sCachedScripts->Init();
+
+    sScriptCacheCleaner = new nsScriptCacheCleaner();
   }
 }
 
 void
 nsFrameScriptExecutor::DestroyCx()
 {
   nsIXPConnect* xpc = nsContentUtils::XPConnect();
   if (xpc) {
@@ -559,16 +562,18 @@ nsFrameScriptExecutor::Shutdown()
       NS_ASSERTION(sCachedScripts != nsnull, "Need cached scripts");
       sCachedScripts->Enumerate(CachedScriptUnrooter, cx);
     } else {
       NS_WARNING("No context available. Leaking cached scripts!\n");
     }
 
     delete sCachedScripts;
     sCachedScripts = nsnull;
+
+    sScriptCacheCleaner = nsnull;
   }
 }
 
 void
 nsFrameScriptExecutor::LoadFrameScriptInternal(const nsAString& aURL)
 {
   if (!mGlobal || !mCx) {
     return;
@@ -667,8 +672,11 @@ nsFrameScriptExecutor::LoadFrameScriptIn
         //XXX Argh, JSPrincipals are manually refcounted!
         JSPRINCIPALS_DROP(mCx, jsprin);
       }
     } 
     JSContext* unused;
     nsContentUtils::ThreadJSContextStack()->Pop(&unused);
   }
 }
+
+NS_IMPL_ISUPPORTS1(nsScriptCacheCleaner, nsIObserver);
+
--- a/content/base/src/nsFrameMessageManager.h
+++ b/content/base/src/nsFrameMessageManager.h
@@ -33,26 +33,29 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 #ifndef nsFrameMessageManager_h__
 #define nsFrameMessageManager_h__
 
 #include "nsIFrameMessageManager.h"
+#include "nsIObserver.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsCOMArray.h"
 #include "nsTArray.h"
 #include "nsIAtom.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsTArray.h"
 #include "nsIPrincipal.h"
 #include "nsIXPConnect.h"
 #include "nsDataHashtable.h"
+#include "mozilla/Services.h"
+#include "nsIObserverService.h"
 
 class nsAXPCNativeCallContext;
 struct JSContext;
 struct JSObject;
 
 struct nsMessageListenerInfo
 {
   nsCOMPtr<nsIFrameMessageListener> mListener;
@@ -148,16 +151,18 @@ protected:
   nsSyncMessageCallback mSyncCallback;
   nsAsyncMessageCallback mAsyncCallback;
   nsLoadScriptCallback mLoadScriptCallback;
   void* mCallbackData;
   JSContext* mContext;
   nsTArray<nsString> mPendingScripts;
 };
 
+class nsScriptCacheCleaner;
+
 struct nsFrameScriptExecutorJSObjectHolder
 {
   nsFrameScriptExecutorJSObjectHolder(JSObject* aObject) : mObject(aObject) {}
   JSObject* mObject;
 };
 
 class nsFrameScriptExecutor
 {
@@ -168,11 +173,32 @@ protected:
   void DidCreateCx();
   // Call this when you want to destroy mCx.
   void DestroyCx();
   void LoadFrameScriptInternal(const nsAString& aURL);
   nsCOMPtr<nsIXPConnectJSObjectHolder> mGlobal;
   JSContext* mCx;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   static nsDataHashtable<nsStringHashKey, nsFrameScriptExecutorJSObjectHolder*>* sCachedScripts;
+  static nsRefPtr<nsScriptCacheCleaner> sScriptCacheCleaner;
+};
+
+class nsScriptCacheCleaner : public nsIObserver
+{
+  NS_DECL_ISUPPORTS
+
+  nsScriptCacheCleaner()
+  {
+    nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
+    if (obsSvc)
+      obsSvc->AddObserver(this, "xpcom-shutdown", PR_FALSE);
+  }
+
+  NS_IMETHODIMP Observe(nsISupports *aSubject,
+                        const char *aTopic,
+                        const PRUnichar *aData)
+  {
+    nsFrameScriptExecutor::Shutdown();
+    return NS_OK;
+  }
 };
 
 #endif