Bug 1521189 - Asynchronously destroy WindowGlobalChild, r=farre
☠☠ backed out by 7ea32bdfebf1 ☠ ☠
authorNika Layzell <nika@thelayzells.com>
Fri, 25 Jan 2019 15:59:30 +0000
changeset 515523 1e68675bce75e958c4d6a7f14a021cbd914b2a9c
parent 515522 a8dc6f53432ef0e0afb8c7e43a74533f46b1a8ec
child 515524 f83934422518dcba917afb08e9b103aa702cf772
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfarre
bugs1521189
milestone66.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 1521189 - Asynchronously destroy WindowGlobalChild, r=farre Differential Revision: https://phabricator.services.mozilla.com/D17030
dom/base/nsGlobalWindowInner.cpp
dom/ipc/PWindowGlobal.ipdl
dom/ipc/WindowGlobalChild.cpp
dom/ipc/WindowGlobalChild.h
dom/ipc/WindowGlobalParent.cpp
dom/ipc/WindowGlobalParent.h
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -1269,17 +1269,17 @@ void nsGlobalWindowInner::FreeInnerObjec
   if (mCleanMessageManager) {
     MOZ_ASSERT(mIsChrome, "only chrome should have msg manager cleaned");
     if (mChromeFields.mMessageManager) {
       mChromeFields.mMessageManager->Disconnect();
     }
   }
 
   if (mWindowGlobalChild && !mWindowGlobalChild->IsClosed()) {
-    mWindowGlobalChild->Send__delete__(mWindowGlobalChild);
+    mWindowGlobalChild->Destroy();
   }
   mWindowGlobalChild = nullptr;
 
   mIntlUtils = nullptr;
 }
 
 //*****************************************************************************
 // nsGlobalWindowInner::nsISupports
--- a/dom/ipc/PWindowGlobal.ipdl
+++ b/dom/ipc/PWindowGlobal.ipdl
@@ -18,20 +18,23 @@ namespace dom {
  * specifically a |nsGlobalWindowInner|. These actors will form a parent/child
  * link either between the chrome/content process, or will be in-process, for
  * documents which are loaded in the chrome process.
  */
 async protocol PWindowGlobal
 {
   manager PBrowser or PInProcess;
 
+child:
+  async __delete__();
+
 parent:
   /// Update the URI of the document in this WindowGlobal.
   async UpdateDocumentURI(nsIURI aUri);
 
   /// Notify the parent that this PWindowGlobal is now the current global.
   async BecomeCurrentWindowGlobal();
 
-  async __delete__();
+  async Destroy();
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/WindowGlobalChild.cpp
+++ b/dom/ipc/WindowGlobalChild.cpp
@@ -85,16 +85,34 @@ bool WindowGlobalChild::IsCurrentGlobal(
 already_AddRefed<WindowGlobalParent> WindowGlobalChild::GetParentActor() {
   if (mIPCClosed) {
     return nullptr;
   }
   IProtocol* otherSide = InProcessChild::ParentActorFor(this);
   return do_AddRef(static_cast<WindowGlobalParent*>(otherSide));
 }
 
+already_AddRefed<TabChild> WindowGlobalChild::GetTabChild() {
+  if (IsInProcess() || mIPCClosed) {
+    return nullptr;
+  }
+  return do_AddRef(static_cast<TabChild*>(Manager()));
+}
+
+void WindowGlobalChild::Destroy() {
+  // Perform async IPC shutdown unless we're not in-process, and our TabChild is
+  // in the process of being destroyed, which will destroy us as well.
+  RefPtr<TabChild> tabChild = GetTabChild();
+  if (!tabChild || !tabChild->IsDestroyed()) {
+    SendDestroy();
+  }
+
+  mIPCClosed = true;
+}
+
 void WindowGlobalChild::ActorDestroy(ActorDestroyReason aWhy) {
   mIPCClosed = true;
   gWindowGlobalChildById->Remove(mInnerWindowId);
 }
 
 WindowGlobalChild::~WindowGlobalChild() {
   MOZ_ASSERT(!gWindowGlobalChildById ||
              !gWindowGlobalChildById->Contains(mInnerWindowId));
--- a/dom/ipc/WindowGlobalChild.h
+++ b/dom/ipc/WindowGlobalChild.h
@@ -37,31 +37,36 @@ class WindowGlobalChild : public nsWrapp
     return GetByInnerWindowId(aInnerWindowId);
   }
 
   dom::BrowsingContext* BrowsingContext() { return mBrowsingContext; }
   nsGlobalWindowInner* WindowGlobal() { return mWindowGlobal; }
 
   // Has this actor been shut down
   bool IsClosed() { return mIPCClosed; }
+  void Destroy();
 
   // Check if this actor is managed by PInProcess, as-in the document is loaded
   // in the chrome process.
   bool IsInProcess() { return XRE_IsParentProcess(); }
 
   // The Window ID for this WindowGlobal
   uint64_t InnerWindowId() { return mInnerWindowId; }
   uint64_t OuterWindowId() { return mOuterWindowId; }
 
   bool IsCurrentGlobal();
 
   // Get the other side of this actor if it is an in-process actor. Returns
   // |nullptr| if the actor has been torn down, or is not in-process.
   already_AddRefed<WindowGlobalParent> GetParentActor();
 
+  // Get this actor's manager if it is not an in-process actor. Returns
+  // |nullptr| if the actor has been torn down, or is in-process.
+  already_AddRefed<TabChild> GetTabChild();
+
   // Create and initialize the WindowGlobalChild object.
   static already_AddRefed<WindowGlobalChild> Create(
       nsGlobalWindowInner* aWindow);
 
   nsISupports* GetParentObject();
   JSObject* WrapObject(JSContext* aCx,
                        JS::Handle<JSObject*> aGivenProto) override;
 
--- a/dom/ipc/WindowGlobalParent.cpp
+++ b/dom/ipc/WindowGlobalParent.cpp
@@ -111,28 +111,45 @@ WindowGlobalParent::GetByInnerWindowId(u
 already_AddRefed<WindowGlobalChild> WindowGlobalParent::GetChildActor() {
   if (mIPCClosed) {
     return nullptr;
   }
   IProtocol* otherSide = InProcessParent::ChildActorFor(this);
   return do_AddRef(static_cast<WindowGlobalChild*>(otherSide));
 }
 
+already_AddRefed<TabParent> WindowGlobalParent::GetTabParent() {
+  if (IsInProcess() || mIPCClosed) {
+    return nullptr;
+  }
+  return do_AddRef(static_cast<TabParent*>(Manager()));
+}
+
 IPCResult WindowGlobalParent::RecvUpdateDocumentURI(nsIURI* aURI) {
   // XXX(nika): Assert that the URI change was one which makes sense (either
   // about:blank -> a real URI, or a legal push/popstate URI change?)
   mDocumentURI = aURI;
   return IPC_OK();
 }
 
 IPCResult WindowGlobalParent::RecvBecomeCurrentWindowGlobal() {
   mBrowsingContext->SetCurrentWindowGlobal(this);
   return IPC_OK();
 }
 
+IPCResult WindowGlobalParent::RecvDestroy() {
+  if (!mIPCClosed) {
+    RefPtr<TabParent> tabParent = GetTabParent();
+    if (!tabParent || !tabParent->IsDestroyed()) {
+      Unused << Send__delete__(this);
+    }
+  }
+  return IPC_OK();
+}
+
 bool WindowGlobalParent::IsCurrentGlobal() {
   return !mIPCClosed && mBrowsingContext->GetCurrentWindowGlobal() == this;
 }
 
 void WindowGlobalParent::ActorDestroy(ActorDestroyReason aWhy) {
   mIPCClosed = true;
   gWindowGlobalParentsById->Remove(mInnerWindowId);
   mBrowsingContext->UnregisterWindowGlobal(this);
--- a/dom/ipc/WindowGlobalParent.h
+++ b/dom/ipc/WindowGlobalParent.h
@@ -46,16 +46,20 @@ class WindowGlobalParent final : public 
   // Check if this actor is managed by PInProcess, as-in the document is loaded
   // in-process.
   bool IsInProcess() { return mInProcess; }
 
   // Get the other side of this actor if it is an in-process actor. Returns
   // |nullptr| if the actor has been torn down, or is not in-process.
   already_AddRefed<WindowGlobalChild> GetChildActor();
 
+  // Get this actor's manager if it is not an in-process actor. Returns
+  // |nullptr| if the actor has been torn down, or is in-process.
+  already_AddRefed<TabParent> GetTabParent();
+
   // The principal of this WindowGlobal. This value will not change over the
   // lifetime of the WindowGlobal object, even to reflect changes in
   // |document.domain|.
   nsIPrincipal* DocumentPrincipal() { return mDocumentPrincipal; }
 
   // The BrowsingContext which this WindowGlobal has been loaded into.
   ChromeBrowsingContext* BrowsingContext() { return mBrowsingContext; }
 
@@ -85,16 +89,17 @@ class WindowGlobalParent final : public 
   nsISupports* GetParentObject();
   JSObject* WrapObject(JSContext* aCx,
                        JS::Handle<JSObject*> aGivenProto) override;
 
  protected:
   // IPC messages
   mozilla::ipc::IPCResult RecvUpdateDocumentURI(nsIURI* aURI) override;
   mozilla::ipc::IPCResult RecvBecomeCurrentWindowGlobal() override;
+  mozilla::ipc::IPCResult RecvDestroy() override;
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
  private:
   ~WindowGlobalParent();
 
   // NOTE: This document principal doesn't reflect possible |document.domain|
   // mutations which may have been made in the actual document.