Bug 1500949 - Include innerWindowId/outerWindowId in PWindowGlobal, r=farre
authorNika Layzell <nika@thelayzells.com>
Sat, 20 Oct 2018 16:04:00 -0400
changeset 508680 f824e2415aa6e0acd6c431e9996d1134787a58a8
parent 508679 5bab2966c5c6c8df05e59d5a27b2b56696bf6f74
child 508681 64cab8bb3dc7759e24bbe99d2d963042d49332ee
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfarre
bugs1500949
milestone65.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 1500949 - Include innerWindowId/outerWindowId in PWindowGlobal, r=farre This will be useful as both an ID for PWindowGlobal, as well as a mechanism for taking advantage of already synchronized information. As an example, LoadInfo objects contain the inner window IDs of the window requesting the load, which can now be used to obtain a reference to the corresponding WindowGlobalParent in the parent process. Differential Revision: https://phabricator.services.mozilla.com/D9396
dom/chrome-webidl/WindowGlobalActors.webidl
dom/ipc/DOMTypes.ipdlh
dom/ipc/WindowGlobalChild.cpp
dom/ipc/WindowGlobalChild.h
dom/ipc/WindowGlobalParent.cpp
dom/ipc/WindowGlobalParent.h
--- a/dom/chrome-webidl/WindowGlobalActors.webidl
+++ b/dom/chrome-webidl/WindowGlobalActors.webidl
@@ -8,26 +8,36 @@ interface URI;
 interface nsIDocShell;
 
 [Exposed=Window, ChromeOnly]
 interface WindowGlobalParent {
   readonly attribute boolean isClosed;
   readonly attribute boolean isInProcess;
   readonly attribute ChromeBrowsingContext browsingContext;
 
+  readonly attribute unsigned long long innerWindowId;
+  readonly attribute unsigned long long outerWindowId;
+
   // XXX(nika): We would want to expose this, but |FrameLoader| isn't exposed on System.
   // readonly attribute FrameLoader? rootFrameLoader; // Embedded (browser) only
 
   readonly attribute WindowGlobalChild? childActor; // in-process only
 
   // Information about the currently loaded document.
   readonly attribute Principal documentPrincipal;
   readonly attribute URI? documentURI;
+
+  static WindowGlobalParent? getByInnerWindowId(unsigned long long innerWindowId);
 };
 
 [Exposed=Window, ChromeOnly]
 interface WindowGlobalChild {
   readonly attribute boolean isClosed;
   readonly attribute boolean isInProcess;
   readonly attribute BrowsingContext browsingContext;
 
+  readonly attribute unsigned long long innerWindowId;
+  readonly attribute unsigned long long outerWindowId;
+
   readonly attribute WindowGlobalParent? parentActor; // in-process only
+
+  static WindowGlobalChild? getByInnerWindowId(unsigned long long innerWIndowId);
 };
--- a/dom/ipc/DOMTypes.ipdlh
+++ b/dom/ipc/DOMTypes.ipdlh
@@ -184,12 +184,14 @@ struct PerformanceInfo
   // Counters per category. For workers, a single entry
   CategoryDispatch[] items;
 };
 
 struct WindowGlobalInit
 {
   nsIPrincipal principal;
   BrowsingContextId browsingContextId;
+  uint64_t innerWindowId;
+  uint64_t outerWindowId;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/WindowGlobalChild.cpp
+++ b/dom/ipc/WindowGlobalChild.cpp
@@ -7,37 +7,46 @@
 #include "mozilla/dom/WindowGlobalChild.h"
 #include "mozilla/ipc/InProcessChild.h"
 #include "mozilla/dom/BrowsingContext.h"
 #include "mozilla/dom/WindowGlobalActorsBinding.h"
 
 namespace mozilla {
 namespace dom {
 
-WindowGlobalChild::WindowGlobalChild(nsGlobalWindowInner* aWindow, dom::BrowsingContext* aBrowsingContext)
+typedef nsRefPtrHashtable<nsUint64HashKey, WindowGlobalChild> WGCByIdMap;
+static StaticAutoPtr<WGCByIdMap> gWindowGlobalChildById;
+
+WindowGlobalChild::WindowGlobalChild(nsGlobalWindowInner* aWindow,
+                                     dom::BrowsingContext* aBrowsingContext)
   : mWindowGlobal(aWindow)
   , mBrowsingContext(aBrowsingContext)
-  , mIPCClosed(false)
+  , mInnerWindowId(aWindow->WindowID())
+  , mOuterWindowId(aWindow->GetOuterWindow()->WindowID())
+  , mIPCClosed(true)
 {
 }
 
 already_AddRefed<WindowGlobalChild>
 WindowGlobalChild::Create(nsGlobalWindowInner* aWindow)
 {
   nsCOMPtr<nsIPrincipal> principal = aWindow->GetPrincipal();
   MOZ_ASSERT(principal);
 
   RefPtr<nsDocShell> docshell = nsDocShell::Cast(aWindow->GetDocShell());
   MOZ_ASSERT(docshell);
 
   // Initalize our WindowGlobalChild object.
   RefPtr<dom::BrowsingContext> bc = docshell->GetBrowsingContext();
   RefPtr<WindowGlobalChild> wgc = new WindowGlobalChild(aWindow, bc);
 
-  WindowGlobalInit init(principal, BrowsingContextId(wgc->BrowsingContext()->Id()));
+  WindowGlobalInit init(principal,
+                        BrowsingContextId(wgc->BrowsingContext()->Id()),
+                        wgc->mInnerWindowId,
+                        wgc->mOuterWindowId);
 
   // Send the link constructor over PInProcessChild or PBrowser.
   if (XRE_IsParentProcess()) {
     InProcessChild* ipc = InProcessChild::Singleton();
     if (!ipc) {
       return nullptr;
     }
 
@@ -45,38 +54,60 @@ WindowGlobalChild::Create(nsGlobalWindow
     ipc->SendPWindowGlobalConstructor(do_AddRef(wgc).take(), init);
   } else {
     RefPtr<TabChild> tabChild = TabChild::GetFrom(static_cast<mozIDOMWindow*>(aWindow));
     MOZ_ASSERT(tabChild);
 
     // Note: ref is released in DeallocPWindowGlobalChild
     tabChild->SendPWindowGlobalConstructor(do_AddRef(wgc).take(), init);
   }
+  wgc->mIPCClosed = false;
+
+  // Register this WindowGlobal in the gWindowGlobalParentsById map.
+  if (!gWindowGlobalChildById) {
+    gWindowGlobalChildById = new WGCByIdMap();
+    ClearOnShutdown(&gWindowGlobalChildById);
+  }
+  auto entry = gWindowGlobalChildById->LookupForAdd(wgc->mInnerWindowId);
+  MOZ_RELEASE_ASSERT(!entry, "Duplicate WindowGlobalChild entry for ID!");
+  entry.OrInsert([&] { return wgc; });
 
   return wgc.forget();
 }
 
+/* static */ already_AddRefed<WindowGlobalChild>
+WindowGlobalChild::GetByInnerWindowId(uint64_t aInnerWindowId)
+{
+  if (!gWindowGlobalChildById) {
+    return nullptr;
+  }
+  return gWindowGlobalChildById->Get(aInnerWindowId);
+}
+
 already_AddRefed<WindowGlobalParent>
 WindowGlobalChild::GetParentActor()
 {
   if (mIPCClosed) {
     return nullptr;
   }
   IProtocol* otherSide = InProcessChild::ParentActorFor(this);
   return do_AddRef(static_cast<WindowGlobalParent*>(otherSide));
 }
 
 void
 WindowGlobalChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   mIPCClosed = true;
+  gWindowGlobalChildById->Remove(mInnerWindowId);
 }
 
 WindowGlobalChild::~WindowGlobalChild()
 {
+  MOZ_ASSERT(!gWindowGlobalChildById ||
+             !gWindowGlobalChildById->Contains(mInnerWindowId));
 }
 
 JSObject*
 WindowGlobalChild::WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto)
 {
   return WindowGlobalChild_Binding::Wrap(aCx, this, aGivenProto);
 }
--- a/dom/ipc/WindowGlobalChild.h
+++ b/dom/ipc/WindowGlobalChild.h
@@ -26,26 +26,38 @@ class WindowGlobalParent;
  */
 class WindowGlobalChild : public nsWrapperCache
                         , public PWindowGlobalChild
 {
 public:
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WindowGlobalChild)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WindowGlobalChild)
 
+  static already_AddRefed<WindowGlobalChild>
+  GetByInnerWindowId(uint64_t aInnerWindowId);
+
+  static already_AddRefed<WindowGlobalChild>
+  GetByInnerWindowId(const GlobalObject& aGlobal, uint64_t aInnerWindowId) {
+    return GetByInnerWindowId(aInnerWindowId);
+  }
+
   dom::BrowsingContext* BrowsingContext() { return mBrowsingContext; }
   nsGlobalWindowInner* WindowGlobal() { return mWindowGlobal; }
 
   // Has this actor been shut down
   bool IsClosed() { return mIPCClosed; }
 
   // 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; }
+
   // 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();
 
   // Create and initialize the WindowGlobalChild object.
   static already_AddRefed<WindowGlobalChild>
   Create(nsGlobalWindowInner* aWindow);
 
@@ -57,15 +69,17 @@ protected:
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
 private:
   WindowGlobalChild(nsGlobalWindowInner* aWindow, dom::BrowsingContext* aBc);
   ~WindowGlobalChild();
 
   RefPtr<nsGlobalWindowInner> mWindowGlobal;
   RefPtr<dom::BrowsingContext> mBrowsingContext;
+  uint64_t mInnerWindowId;
+  uint64_t mOuterWindowId;
   bool mIPCClosed;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // !defined(mozilla_dom_WindowGlobalChild_h)
--- a/dom/ipc/WindowGlobalParent.cpp
+++ b/dom/ipc/WindowGlobalParent.cpp
@@ -9,19 +9,24 @@
 #include "mozilla/dom/ChromeBrowsingContext.h"
 #include "mozilla/dom/WindowGlobalActorsBinding.h"
 
 using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace dom {
 
+typedef nsRefPtrHashtable<nsUint64HashKey, WindowGlobalParent> WGPByIdMap;
+static StaticAutoPtr<WGPByIdMap> gWindowGlobalParentsById;
+
 WindowGlobalParent::WindowGlobalParent(const WindowGlobalInit& aInit,
                                        bool aInProcess)
   : mDocumentPrincipal(aInit.principal())
+  , mInnerWindowId(aInit.innerWindowId())
+  , mOuterWindowId(aInit.outerWindowId())
   , mInProcess(aInProcess)
   , mIPCClosed(true)  // Closed until WGP::Init
 {
   MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess(), "Parent process only");
   MOZ_RELEASE_ASSERT(mDocumentPrincipal, "Must have a valid principal");
 
   // NOTE: mBrowsingContext initialized in Init()
   MOZ_RELEASE_ASSERT(aInit.browsingContextId() != 0,
@@ -32,16 +37,25 @@ void
 WindowGlobalParent::Init(const WindowGlobalInit& aInit)
 {
   MOZ_ASSERT(Manager(), "Should have a manager!");
   MOZ_ASSERT(!mFrameLoader, "Cannot Init() a WindowGlobalParent twice!");
 
   MOZ_ASSERT(mIPCClosed, "IPC shouldn't be open yet");
   mIPCClosed = false;
 
+  // Register this WindowGlobal in the gWindowGlobalParentsById map.
+  if (!gWindowGlobalParentsById) {
+    gWindowGlobalParentsById = new WGPByIdMap();
+    ClearOnShutdown(&gWindowGlobalParentsById);
+  }
+  auto entry = gWindowGlobalParentsById->LookupForAdd(mInnerWindowId);
+  MOZ_RELEASE_ASSERT(!entry, "Duplicate WindowGlobalParent entry for ID!");
+  entry.OrInsert([&] { return this; });
+
   // Determine which content process the window global is coming from.
   ContentParentId processId(0);
   if (!mInProcess) {
     processId = static_cast<ContentParent*>(Manager()->Manager())->ChildID();
   }
 
   mBrowsingContext = ChromeBrowsingContext::Get(aInit.browsingContextId());
   MOZ_ASSERT(mBrowsingContext);
@@ -77,16 +91,25 @@ WindowGlobalParent::Init(const WindowGlo
   // Extract the nsFrameLoader from the current frame element. We may not have a
   // nsFrameLoader if we are a chrome document.
   nsCOMPtr<nsIFrameLoaderOwner> flOwner = do_QueryInterface(frameElement);
   if (flOwner) {
     mFrameLoader = flOwner->GetFrameLoader();
   }
 }
 
+/* static */ already_AddRefed<WindowGlobalParent>
+WindowGlobalParent::GetByInnerWindowId(uint64_t aInnerWindowId)
+{
+  if (!gWindowGlobalParentsById) {
+    return nullptr;
+  }
+  return gWindowGlobalParentsById->Get(aInnerWindowId);
+}
+
 already_AddRefed<WindowGlobalChild>
 WindowGlobalParent::GetChildActor()
 {
   if (mIPCClosed) {
     return nullptr;
   }
   IProtocol* otherSide = InProcessParent::ChildActorFor(this);
   return do_AddRef(static_cast<WindowGlobalChild*>(otherSide));
@@ -100,21 +123,24 @@ WindowGlobalParent::RecvUpdateDocumentUR
   mDocumentURI = aURI;
   return IPC_OK();
 }
 
 void
 WindowGlobalParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   mIPCClosed = true;
+  gWindowGlobalParentsById->Remove(mInnerWindowId);
   mBrowsingContext->UnregisterWindowGlobal(this);
 }
 
 WindowGlobalParent::~WindowGlobalParent()
 {
+  MOZ_ASSERT(!gWindowGlobalParentsById ||
+             !gWindowGlobalParentsById->Contains(mInnerWindowId));
 }
 
 JSObject*
 WindowGlobalParent::WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto)
 {
   return WindowGlobalParent_Binding::Wrap(aCx, this, aGivenProto);
 }
--- a/dom/ipc/WindowGlobalParent.h
+++ b/dom/ipc/WindowGlobalParent.h
@@ -26,16 +26,24 @@ class WindowGlobalChild;
  */
 class WindowGlobalParent final : public nsWrapperCache
                                , public PWindowGlobalParent
 {
 public:
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WindowGlobalParent)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WindowGlobalParent)
 
+  static already_AddRefed<WindowGlobalParent>
+  GetByInnerWindowId(uint64_t aInnerWindowId);
+
+  static already_AddRefed<WindowGlobalParent>
+  GetByInnerWindowId(const GlobalObject& aGlobal, uint64_t aInnerWindowId) {
+    return GetByInnerWindowId(aInnerWindowId);
+  }
+
   // Has this actor been shut down
   bool IsClosed() { return mIPCClosed; }
 
   // 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
@@ -54,16 +62,20 @@ public:
   // which this WindowGlobal is a part of. This will be the nsFrameLoader
   // holding the TabParent for remote tabs, and the root content frameloader for
   // non-remote tabs.
   nsFrameLoader* GetRootFrameLoader() { return mFrameLoader; }
 
   // The current URI which loaded in the document.
   nsIURI* GetDocumentURI() { return mDocumentURI; }
 
+  // Window IDs for inner/outer windows.
+  uint64_t OuterWindowId() { return mOuterWindowId; }
+  uint64_t InnerWindowId() { return mInnerWindowId; }
+
   // Create a WindowGlobalParent from over IPC. This method should not be called
   // from outside of the IPC constructors.
   WindowGlobalParent(const WindowGlobalInit& aInit, bool aInProcess);
 
   // Initialize the mFrameLoader fields for a created WindowGlobalParent. Must
   // be called after setting the Manager actor.
   void Init(const WindowGlobalInit& aInit);
 
@@ -81,16 +93,18 @@ private:
   ~WindowGlobalParent();
 
   // NOTE: This document principal doesn't reflect possible |document.domain|
   // mutations which may have been made in the actual document.
   nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
   nsCOMPtr<nsIURI> mDocumentURI;
   RefPtr<nsFrameLoader> mFrameLoader;
   RefPtr<ChromeBrowsingContext> mBrowsingContext;
+  uint64_t mInnerWindowId;
+  uint64_t mOuterWindowId;
   bool mInProcess;
   bool mIPCClosed;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // !defined(mozilla_dom_WindowGlobalParent_h)