Bug 608021, [@ nsFrameMessageManager::ReceiveMessage], r=jst
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Thu, 16 Jun 2011 21:21:08 +0300
changeset 71190 97bf954c6970
parent 71189 fb60f6e2f89e
child 71191 48774bdf7e41
push id20507
push useropettay@mozilla.com
push dateThu, 16 Jun 2011 20:09:16 +0000
treeherdermozilla-central@97bf954c6970 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst
bugs608021
milestone7.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 608021, [@ nsFrameMessageManager::ReceiveMessage], r=jst
content/base/src/nsFrameLoader.cpp
content/base/src/nsFrameMessageManager.cpp
content/base/src/nsFrameMessageManager.h
content/base/src/nsInProcessTabChildGlobal.cpp
dom/ipc/TabChild.cpp
dom/ipc/TabParent.cpp
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -1899,19 +1899,20 @@ public:
                         const nsAString& aMessage, const nsAString& aJSON)
     : mFrameLoader(aFrameLoader), mMessage(aMessage), mJSON(aJSON) {}
 
   NS_IMETHOD Run()
   {
     nsInProcessTabChildGlobal* tabChild =
       static_cast<nsInProcessTabChildGlobal*>(mFrameLoader->mChildMessageManager.get());
     if (tabChild && tabChild->GetInnerManager()) {
-      tabChild->GetInnerManager()->
-        ReceiveMessage(static_cast<nsPIDOMEventTarget*>(tabChild), mMessage,
-                       PR_FALSE, mJSON, nsnull, nsnull);
+      nsFrameScriptCx cx(static_cast<nsPIDOMEventTarget*>(tabChild), tabChild);
+      nsRefPtr<nsFrameMessageManager> mm = tabChild->GetInnerManager();
+      mm->ReceiveMessage(static_cast<nsPIDOMEventTarget*>(tabChild), mMessage,
+                         PR_FALSE, mJSON, nsnull, nsnull);
     }
     return NS_OK;
   }
   nsRefPtr<nsFrameLoader> mFrameLoader;
   nsString mMessage;
   nsString mJSON;
 };
 
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -457,16 +457,17 @@ nsFrameMessageManager::ReceiveMessage(ns
                              JSONCreator, &json)) {
               aJSONRetVal->AppendElement(json);
             }
           }
         }
       }
     }
   }
+  nsRefPtr<nsFrameMessageManager> kungfuDeathGrip = mParentManager;
   return mParentManager ? mParentManager->ReceiveMessage(aTarget, aMessage,
                                                          aSync, aJSON, aObjectsArray,
                                                          aJSONRetVal, mContext) : NS_OK;
 }
 
 void
 nsFrameMessageManager::AddChildManager(nsFrameMessageManager* aManager,
                                        PRBool aLoadScripts)
@@ -596,21 +597,28 @@ nsFrameScriptExecutor::DidCreateCx()
 
     sScriptCacheCleaner = new nsScriptCacheCleaner();
   }
 }
 
 void
 nsFrameScriptExecutor::DestroyCx()
 {
-  nsIXPConnect* xpc = nsContentUtils::XPConnect();
-  if (xpc) {
-    xpc->ReleaseJSContext(mCx, PR_TRUE);
-  } else {
-    JS_DestroyContext(mCx);
+  if (mCxStackRefCnt) {
+    mDelayedCxDestroy = PR_TRUE;
+    return;
+  }
+  mDelayedCxDestroy = PR_FALSE;
+  if (mCx) {
+    nsIXPConnect* xpc = nsContentUtils::XPConnect();
+    if (xpc) {
+      xpc->ReleaseJSContext(mCx, PR_TRUE);
+    } else {
+      JS_DestroyContext(mCx);
+    }
   }
   mCx = nsnull;
   mGlobal = nsnull;
 }
 
 static PLDHashOperator
 CachedScriptUnrooter(const nsAString& aKey,
                        nsFrameScriptExecutorJSObjectHolder*& aData,
--- a/content/base/src/nsFrameMessageManager.h
+++ b/content/base/src/nsFrameMessageManager.h
@@ -196,33 +196,56 @@ struct nsFrameScriptExecutorJSObjectHold
   JSObject* mObject;
 };
 
 class nsFrameScriptExecutor
 {
 public:
   static void Shutdown();
 protected:
-  nsFrameScriptExecutor() : mCx(nsnull)
+  friend class nsFrameScriptCx;
+  nsFrameScriptExecutor() : mCx(nsnull), mCxStackRefCnt(0),
+                            mDelayedCxDestroy(PR_FALSE)
   { MOZ_COUNT_CTOR(nsFrameScriptExecutor); }
   ~nsFrameScriptExecutor()
   { MOZ_COUNT_DTOR(nsFrameScriptExecutor); }
   void DidCreateCx();
   // Call this when you want to destroy mCx.
   void DestroyCx();
   void LoadFrameScriptInternal(const nsAString& aURL);
   static void Traverse(nsFrameScriptExecutor *tmp,
                        nsCycleCollectionTraversalCallback &cb);
   nsCOMPtr<nsIXPConnectJSObjectHolder> mGlobal;
   JSContext* mCx;
+  PRUint32 mCxStackRefCnt;
+  PRPackedBool mDelayedCxDestroy;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   static nsDataHashtable<nsStringHashKey, nsFrameScriptExecutorJSObjectHolder*>* sCachedScripts;
   static nsRefPtr<nsScriptCacheCleaner> sScriptCacheCleaner;
 };
 
+class nsFrameScriptCx
+{
+public:
+  nsFrameScriptCx(nsISupports* aOwner, nsFrameScriptExecutor* aExec)
+  : mOwner(aOwner), mExec(aExec)
+  {
+    ++(mExec->mCxStackRefCnt);
+  }
+  ~nsFrameScriptCx()
+  {
+    if (--(mExec->mCxStackRefCnt) == 0 &&
+        mExec->mDelayedCxDestroy) {
+      mExec->DestroyCx();
+    }
+  }
+  nsCOMPtr<nsISupports> mOwner;
+  nsFrameScriptExecutor* mExec;
+};
+
 class nsScriptCacheCleaner : public nsIObserver
 {
   NS_DECL_ISUPPORTS
 
   nsScriptCacheCleaner()
   {
     nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
     if (obsSvc)
--- a/content/base/src/nsInProcessTabChildGlobal.cpp
+++ b/content/base/src/nsInProcessTabChildGlobal.cpp
@@ -63,36 +63,36 @@ bool SendSyncMessageToParent(void* aCall
   nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
   asyncMessages.SwapElements(tabChild->mASyncMessages);
   PRUint32 len = asyncMessages.Length();
   for (PRUint32 i = 0; i < len; ++i) {
     nsCOMPtr<nsIRunnable> async = asyncMessages[i];
     async->Run();
   }
   if (tabChild->mChromeMessageManager) {
-    tabChild->mChromeMessageManager->ReceiveMessage(owner, aMessage, PR_TRUE,
-                                                    aJSON, nsnull, aJSONRetVal);
+    nsRefPtr<nsFrameMessageManager> mm = tabChild->mChromeMessageManager;
+    mm->ReceiveMessage(owner, aMessage, PR_TRUE, aJSON, nsnull, aJSONRetVal);
   }
   return true;
 }
 
 class nsAsyncMessageToParent : public nsRunnable
 {
 public:
   nsAsyncMessageToParent(nsInProcessTabChildGlobal* aTabChild,
                          const nsAString& aMessage, const nsAString& aJSON)
     : mTabChild(aTabChild), mMessage(aMessage), mJSON(aJSON) {}
 
   NS_IMETHOD Run()
   {
     mTabChild->mASyncMessages.RemoveElement(this);
     if (mTabChild->mChromeMessageManager) {
-      mTabChild->mChromeMessageManager->ReceiveMessage(mTabChild->mOwner, mMessage,
-                                                       PR_FALSE,
-                                                       mJSON, nsnull, nsnull);
+      nsRefPtr<nsFrameMessageManager> mm = mTabChild->mChromeMessageManager;
+      mm->ReceiveMessage(mTabChild->mOwner, mMessage, PR_FALSE,
+                         mJSON, nsnull, nsnull);
     }
     return NS_OK;
   }
   nsRefPtr<nsInProcessTabChildGlobal> mTabChild;
   nsString mMessage;
   nsString mJSON;
 };
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -140,16 +140,17 @@ TabChild::Init()
   NS_ASSERTION(mWebNav, "nsWebBrowser doesn't implement nsIWebNavigation?");
 
   nsCOMPtr<nsIDocShellTreeItem> docShellItem(do_QueryInterface(mWebNav));
   docShellItem->SetItemType(nsIDocShellTreeItem::typeContentWrapper);
   return NS_OK;
 }
 
 NS_INTERFACE_MAP_BEGIN(TabChild)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome)
   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2)
   NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow)
   NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow2)
   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChromeFocus)
   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   NS_INTERFACE_MAP_ENTRY(nsIWindowProvider)
   NS_INTERFACE_MAP_ENTRY(nsITabChild)
@@ -749,19 +750,21 @@ TabChild::RecvLoadRemoteScript(const nsS
   return true;
 }
 
 bool
 TabChild::RecvAsyncMessage(const nsString& aMessage,
                            const nsString& aJSON)
 {
   if (mTabChildGlobal) {
-    static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get())->
-      ReceiveMessage(static_cast<nsPIDOMEventTarget*>(mTabChildGlobal),
-                     aMessage, PR_FALSE, aJSON, nsnull, nsnull);
+    nsFrameScriptCx cx(static_cast<nsIWebBrowserChrome*>(this), this);
+    nsRefPtr<nsFrameMessageManager> mm =
+      static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
+    mm->ReceiveMessage(static_cast<nsPIDOMEventTarget*>(mTabChildGlobal),
+                       aMessage, PR_FALSE, aJSON, nsnull, nsnull);
   }
   return true;
 }
 
 class UnloadScriptEvent : public nsRunnable
 {
 public:
   UnloadScriptEvent(TabChild* aTabChild, TabChildGlobal* aTabChildGlobal)
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -582,17 +582,18 @@ TabParent::RecvGetDPI(float* aValue)
 bool
 TabParent::ReceiveMessage(const nsString& aMessage,
                           PRBool aSync,
                           const nsString& aJSON,
                           InfallibleTArray<nsString>* aJSONRetVal)
 {
   nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
   if (frameLoader && frameLoader->GetFrameMessageManager()) {
-    nsFrameMessageManager* manager = frameLoader->GetFrameMessageManager();
+    nsRefPtr<nsFrameMessageManager> manager =
+      frameLoader->GetFrameMessageManager();
     JSContext* ctx = manager->GetJSContext();
     JSAutoRequest ar(ctx);
     PRUint32 len = 0; //TODO: obtain a real value in bug 572685
     // Because we want JS messages to have always the same properties,
     // create array even if len == 0.
     JSObject* objectsArray = JS_NewArrayObject(ctx, len, NULL);
     if (!objectsArray) {
       return false;