Bug 1487249 - Part 3: Add the WindowGlobal actor representing a single window global, r=bzbarsky
☠☠ backed out by 9bfe29337ffe ☠ ☠
authorNika Layzell <nika@thelayzells.com>
Wed, 29 Aug 2018 18:21:25 -0400
changeset 507653 c60fa11538dba13f2eced54a835a4a0ff65a0ebd
parent 507652 0190d4ffa54fab4397afd0cd43d2f896c052235a
child 507654 e0f95dd96d5458f60980f1e8b3f846beed6e5817
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)
reviewersbzbarsky
bugs1487249
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 1487249 - Part 3: Add the WindowGlobal actor representing a single window global, r=bzbarsky This actor can be used for communicating with individual frames, without depending on walking the tree in the content process. This is not yet complete. No tests have been written for it, the WindowGlobalParent objects need to be exposed to chrome JS, and a form of JS actors should be installed under them. In addition, BrowsingContextChrome objects should be updated to allow access to the current WindowGlobalParent in that context. Differential Revision: https://phabricator.services.mozilla.com/D4623
dom/base/nsDocument.cpp
dom/base/nsGlobalWindowInner.cpp
dom/base/nsPIDOMWindow.h
dom/ipc/ContentChild.cpp
dom/ipc/DOMTypes.ipdlh
dom/ipc/PBrowser.ipdl
dom/ipc/PWindowGlobal.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/ipc/WindowGlobalChild.cpp
dom/ipc/WindowGlobalChild.h
dom/ipc/WindowGlobalParent.cpp
dom/ipc/WindowGlobalParent.h
dom/ipc/moz.build
ipc/glue/InProcessChild.cpp
ipc/glue/InProcessChild.h
ipc/glue/InProcessImpl.cpp
ipc/glue/InProcessParent.cpp
ipc/glue/InProcessParent.h
ipc/glue/PInProcess.ipdl
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -266,16 +266,18 @@
 #include "nsXULCommandDispatcher.h"
 #include "nsXULPopupManager.h"
 #include "nsIDocShellTreeOwner.h"
 #endif
 #include "nsIPresShellInlines.h"
 
 #include "mozilla/DocLoadingTimelineMarker.h"
 
+#include "mozilla/dom/WindowGlobalChild.h"
+
 #include "nsISpeculativeConnect.h"
 
 #include "mozilla/MediaManager.h"
 
 #include "nsIURIClassifier.h"
 #include "nsIURIMutator.h"
 #include "mozilla/DocumentStyleRootIterator.h"
 #include "mozilla/PendingFullscreenEvent.h"
@@ -3090,16 +3092,23 @@ nsIDocument::SetDocumentURI(nsIURI* aURI
   if (!mOriginalURI)
     mOriginalURI = mDocumentURI;
 
   // If changing the document's URI changed the base URI of the document, we
   // need to refresh the hrefs of all the links on the page.
   if (!equalBases) {
     RefreshLinkHrefs();
   }
+
+  // Tell our WindowGlobalParent that the document's URI has been changed.
+  nsPIDOMWindowInner* inner = GetInnerWindow();
+  WindowGlobalChild* wgc = inner ? inner->GetWindowGlobalChild() : nullptr;
+  if (wgc) {
+    Unused << wgc->SendUpdateDocumentURI(mDocumentURI);
+  }
 }
 
 static void
 GetFormattedTimeString(PRTime aTime, nsAString& aFormattedTimeString)
 {
   PRExplodedTime prtime;
   PR_ExplodeTime(aTime, PR_LocalTimeParameters, &prtime);
   // "MM/DD/YYYY hh:mm:ss"
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -253,16 +253,18 @@
 #ifdef MOZ_WEBSPEECH
 #include "mozilla/dom/SpeechSynthesis.h"
 #endif
 
 #include "mozilla/dom/ClientManager.h"
 #include "mozilla/dom/ClientSource.h"
 #include "mozilla/dom/ClientState.h"
 
+#include "mozilla/dom/WindowGlobalChild.h"
+
 // Apple system headers seem to have a check() macro.  <sigh>
 #ifdef check
 class nsIScriptTimeoutHandler;
 #undef check
 #endif // check
 #include "AccessCheck.h"
 
 #ifdef ANDROID
@@ -1343,16 +1345,21 @@ nsGlobalWindowInner::FreeInnerObjects(bo
 
   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 = nullptr;
+
   mIntlUtils = nullptr;
 }
 
 //*****************************************************************************
 // nsGlobalWindowInner::nsISupports
 //*****************************************************************************
 
 // QueryInterface implementation for nsGlobalWindowInner
@@ -1733,16 +1740,25 @@ nsGlobalWindowInner::InnerSetNewDocument
   mPerformance = nullptr;
 
   // This must be called after nullifying the internal objects because here we
   // could recreate them, calling the getter methods, and store them into the JS
   // slots. If we nullify them after, the slot values and the objects will be
   // out of sync.
   ClearDocumentDependentSlots(aCx);
 
+  // FIXME: Currently, devtools can crete a fallback webextension window global
+  // in the content process which does not have a corresponding TabChild actor.
+  // This means we have no actor to be our parent. (Bug 1498293)
+  MOZ_DIAGNOSTIC_ASSERT(!mWindowGlobalChild,
+                        "Shouldn't have created WindowGlobalChild yet!");
+  if (XRE_IsParentProcess() || mTabChild) {
+    mWindowGlobalChild = WindowGlobalChild::Create(this);
+  }
+
 #ifdef DEBUG
   mLastOpenedURI = aDocument->GetDocumentURI();
 #endif
 
   Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,
                         mMutationBits ? 1 : 0);
   Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_TEXT_EVENT_LISTENERS,
                         mMayHaveTextEventListenerInDefaultGroup ? 1 : 0);
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -63,16 +63,17 @@ class Performance;
 class Report;
 class ReportBody;
 class ReportingObserver;
 class Selection;
 class ServiceWorker;
 class ServiceWorkerDescriptor;
 class Timeout;
 class TimeoutManager;
+class WindowGlobalChild;
 class CustomElementRegistry;
 enum class CallerType : uint32_t;
 } // namespace dom
 } // namespace mozilla
 
 // Popup control state enum. The values in this enum must go from most
 // permissive to least permissive so that it's safe to push state in
 // all situations. Pushing popup state onto the stack never makes the
@@ -391,16 +392,21 @@ public:
   nsIDocument* GetDoc()
   {
     if (!mDoc) {
       MaybeCreateDoc();
     }
     return mDoc;
   }
 
+  mozilla::dom::WindowGlobalChild* GetWindowGlobalChild()
+  {
+    return mWindowGlobalChild;
+  }
+
   virtual PopupControlState GetPopupControlState() const = 0;
 
   // Determine if the window is suspended or frozen.  Outer windows
   // will forward this call to the inner window for convenience.  If
   // there is no inner window then the outer window is considered
   // suspended and frozen by default.
   virtual bool IsSuspended() const = 0;
   virtual bool IsFrozen() const = 0;
@@ -726,16 +732,22 @@ protected:
   // List of Report objects for ReportingObservers.
   nsTArray<RefPtr<mozilla::dom::ReportingObserver>> mReportingObservers;
   nsTArray<RefPtr<mozilla::dom::Report>> mReportRecords;
 
   // This is a list of storage access granted for the current window. These are
   // also set as permissions, but it could happen that we need to access them
   // synchronously in this context, and for this, we need a copy here.
   nsTArray<nsCString> mStorageAccessGranted;
+
+  // The WindowGlobalChild actor for this window.
+  //
+  // This will be non-null during the full lifetime of the window, initialized
+  // during SetNewDocument, and cleared during FreeInnerObjects.
+  RefPtr<mozilla::dom::WindowGlobalChild> mWindowGlobalChild;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsPIDOMWindowInner, NS_PIDOMWINDOWINNER_IID)
 
 class nsPIDOMWindowOuter : public mozIDOMWindowProxy
 {
 protected:
   explicit nsPIDOMWindowOuter(uint64_t aWindowID);
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -949,34 +949,36 @@ ContentChild::ProvideWindowCommon(TabChi
     tabGroup = aTabOpener->TabGroup();
   } else {
     tabGroup = new TabGroup();
   }
 
   TabContext newTabContext = aTabOpener ? *aTabOpener : TabContext();
   RefPtr<TabChild> newChild = new TabChild(this, tabId, tabGroup,
                                            newTabContext, aChromeFlags);
-  if (NS_FAILED(newChild->Init(aParent))) {
-    return NS_ERROR_ABORT;
-  }
 
   if (aTabOpener) {
     MOZ_ASSERT(ipcContext->type() == IPCTabContext::TPopupIPCTabContext);
     ipcContext->get_PopupIPCTabContext().opener() = aTabOpener;
   }
 
   nsCOMPtr<nsIEventTarget> target = tabGroup->EventTargetFor(TaskCategory::Other);
   SetEventTargetForActor(newChild, target);
 
   Unused << SendPBrowserConstructor(
     // We release this ref in DeallocPBrowserChild
     RefPtr<TabChild>(newChild).forget().take(),
     tabId, TabId(0), *ipcContext, aChromeFlags,
     GetID(), IsForBrowser());
 
+  // Now that |newChild| has had its IPC link established, call |Init| to set it up.
+  if (NS_FAILED(newChild->Init(aParent))) {
+    return NS_ERROR_ABORT;
+  }
+
   nsCOMPtr<nsPIDOMWindowInner> parentTopInnerWindow;
   if (aParent) {
     nsCOMPtr<nsPIDOMWindowOuter> parentTopWindow =
       nsPIDOMWindowOuter::From(aParent)->GetTop();
     if (parentTopWindow) {
       parentTopInnerWindow = parentTopWindow->GetCurrentInnerWindow();
     }
   }
--- a/dom/ipc/DOMTypes.ipdlh
+++ b/dom/ipc/DOMTypes.ipdlh
@@ -21,16 +21,18 @@ using LayoutDeviceIntRect from "Units.h"
 using DesktopIntRect from "Units.h";
 using DesktopToLayoutDeviceScale from "Units.h";
 using CSSToLayoutDeviceScale from "Units.h";
 using CSSRect from "Units.h";
 using CSSSize from "Units.h";
 using mozilla::LayoutDeviceIntPoint from "Units.h";
 using hal::ScreenOrientation from "mozilla/HalScreenConfiguration.h";
 using mozilla::gfx::SurfaceFormat from "mozilla/gfx/Types.h";
+using refcounted class nsIPrincipal from "mozilla/dom/PermissionMessageUtils.h";
+using mozilla::dom::BrowsingContextId from "mozilla/dom/ipc/IdType.h";
 
 
 namespace mozilla {
 namespace dom {
 
 struct MessagePortIdentifier
 {
   nsID uuid;
@@ -178,10 +180,16 @@ struct PerformanceInfo
   // True if the document window is the top window
   bool isTopLevel;
   // Memory
   PerformanceMemoryInfo memory;
   // Counters per category. For workers, a single entry
   CategoryDispatch[] items;
 };
 
+struct WindowGlobalInit
+{
+  nsIPrincipal principal;
+  BrowsingContextId browsingContextId;
+};
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -13,16 +13,17 @@ include protocol PFilePicker;
 include protocol PIndexedDBPermissionRequest;
 include protocol PPluginWidget;
 include protocol PRemotePrintJob;
 include protocol PChildToParentStream;
 include protocol PParentToChildStream;
 include protocol PFileDescriptorSet;
 include protocol PIPCBlobInputStream;
 include protocol PPaymentRequest;
+include protocol PWindowGlobal;
 
 include DOMTypes;
 include IPCBlob;
 include IPCStream;
 include JavaScriptTypes;
 include URIParams;
 include PPrintingTypes;
 include PTabContext;
@@ -81,16 +82,17 @@ using mozilla::EventMessage from "mozill
 using nsEventStatus from "mozilla/EventForwards.h";
 using mozilla::Modifiers from "mozilla/EventForwards.h";
 using nsSizeMode from "nsIWidgetListener.h";
 using mozilla::widget::CandidateWindowPosition from "ipc/nsGUIEventIPC.h";
 using class mozilla::NativeEventData from "ipc/nsGUIEventIPC.h";
 using mozilla::FontRange from "ipc/nsGUIEventIPC.h";
 using mozilla::a11y::IAccessibleHolder from "mozilla/a11y/IPCTypes.h";
 using mozilla::OriginAttributes from "mozilla/ipc/BackgroundUtils.h";
+using mozilla::dom::BrowsingContextId from "mozilla/dom/ipc/IdType.h";
 
 namespace mozilla {
 namespace dom {
 
 struct ShowInfo
 {
   nsString name;
   bool fullscreenAllowed;
@@ -113,16 +115,17 @@ nested(upto inside_cpow) sync protocol P
     manager PContent or PContentBridge;
 
     manages PColorPicker;
     manages PDocAccessible;
     manages PFilePicker;
     manages PIndexedDBPermissionRequest;
     manages PPluginWidget;
     manages PPaymentRequest;
+    manages PWindowGlobal;
 
 both:
     async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
                        Principal aPrincipal, ClonedMessageData aData);
 
 parent:
     /**
      * Tell the parent process a new accessible document has been created.
@@ -140,16 +143,22 @@ parent:
      * in e10s mode. This is always initiated from the child in response
      * to windowed plugin creation.
      */
     sync PPluginWidget();
 
     async PPaymentRequest();
 
     /**
+     * Construct a new WindowGlobal actor for a window global in the given
+     * BrowsingContext and with the given principal.
+     */
+    async PWindowGlobal(WindowGlobalInit init);
+
+    /**
      * Sends an NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW to be adopted by the
      * widget's shareable window on the chrome side. Only used on Windows.
      */
     async SetNativeChildOfShareableWindow(uintptr_t childWindow);
 
     /**
      * When content moves focus from a native plugin window that's a child
      * of the native browser window we need to move native focus to the
new file mode 100644
--- /dev/null
+++ b/dom/ipc/PWindowGlobal.ipdl
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PBrowser;
+include protocol PInProcess;
+
+include DOMTypes;
+
+using refcounted class nsIURI from "mozilla/ipc/URIUtils.h";
+
+namespace mozilla {
+namespace dom {
+
+/**
+ * A PWindowGlobal actor has a lifetime matching that of a single Window Global,
+ * 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;
+
+parent:
+  /// Update the URI of the document in this WindowGlobal.
+  async UpdateDocumentURI(nsIURI aUri);
+
+  async __delete__();
+};
+
+} // namespace dom
+} // namespace mozilla
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -118,16 +118,17 @@
 #include "nsQueryObject.h"
 #include "nsIHttpChannel.h"
 #include "mozilla/dom/DocGroup.h"
 #include "nsString.h"
 #include "nsISupportsPrimitives.h"
 #include "mozilla/Telemetry.h"
 #include "nsDocShellLoadState.h"
 #include "nsWebBrowser.h"
+#include "mozilla/dom/WindowGlobalChild.h"
 
 #ifdef XP_WIN
 #include "mozilla/plugins/PluginWidgetChild.h"
 #endif
 
 #ifdef NS_PRINTING
 #include "nsIPrintSession.h"
 #include "nsIPrintSettings.h"
@@ -3430,16 +3431,31 @@ TabChild::AllocPPaymentRequestChild()
 
 bool
 TabChild::DeallocPPaymentRequestChild(PPaymentRequestChild* actor)
 {
   delete actor;
   return true;
 }
 
+PWindowGlobalChild*
+TabChild::AllocPWindowGlobalChild(const WindowGlobalInit&)
+{
+  MOZ_CRASH("We should never be manually allocating PWindowGlobalChild actors");
+  return nullptr;
+}
+
+bool
+TabChild::DeallocPWindowGlobalChild(PWindowGlobalChild* aActor)
+{
+  // This reference was added in WindowGlobalChild::Create.
+  static_cast<WindowGlobalChild*>(aActor)->Release();
+  return true;
+}
+
 ScreenIntSize
 TabChild::GetInnerSize()
 {
   LayoutDeviceIntSize innerSize =
     RoundedToInt(mUnscaledInnerSize * mPuppetWidget->GetDefaultScale());
   return ViewAs<ScreenPixel>(innerSize, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
 };
 
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -700,16 +700,20 @@ public:
   {
     MOZ_ASSERT(HasVisibleTabs());
     return *sVisibleTabs;
   }
 
 protected:
   virtual ~TabChild();
 
+  virtual PWindowGlobalChild* AllocPWindowGlobalChild(const WindowGlobalInit& aInit) override;
+
+  virtual bool DeallocPWindowGlobalChild(PWindowGlobalChild* aActor) override;
+
   virtual mozilla::ipc::IPCResult RecvDestroy() override;
 
   virtual mozilla::ipc::IPCResult RecvSetDocShellIsActive(const bool& aIsActive) override;
 
   virtual mozilla::ipc::IPCResult RecvRenderLayers(const bool& aEnabled, const bool& aForce, const layers::LayersObserverEpoch& aEpoch) override;
 
   virtual mozilla::ipc::IPCResult RecvRequestRootPaint(const IntRect& aRect, const float& aScale, const nscolor& aBackgroundColor, RequestRootPaintResolver&& aResolve) override;
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -95,16 +95,17 @@
 #include "ImageOps.h"
 #include "UnitTransforms.h"
 #include <algorithm>
 #include "mozilla/NullPrincipal.h"
 #include "mozilla/WebBrowserPersistDocumentParent.h"
 #include "ProcessPriorityManager.h"
 #include "nsString.h"
 #include "IHistory.h"
+#include "mozilla/dom/WindowGlobalParent.h"
 
 #ifdef XP_WIN
 #include "mozilla/plugins/PluginWidgetParent.h"
 #endif
 
 #if defined(XP_WIN) && defined(ACCESSIBILITY)
 #include "mozilla/a11y/AccessibleWrap.h"
 #include "mozilla/a11y/Compatibility.h"
@@ -1057,16 +1058,39 @@ TabParent::DeallocPIndexedDBPermissionRe
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aActor);
 
   return
     mozilla::dom::indexedDB::DeallocPIndexedDBPermissionRequestParent(aActor);
 }
 
+IPCResult
+TabParent::RecvPWindowGlobalConstructor(PWindowGlobalParent* aActor,
+                                        const WindowGlobalInit& aInit)
+{
+  static_cast<WindowGlobalParent*>(aActor)->Init();
+  return IPC_OK();
+}
+
+PWindowGlobalParent*
+TabParent::AllocPWindowGlobalParent(const WindowGlobalInit& aInit)
+{
+  // Reference freed in DeallocPWindowGlobalParent.
+  return do_AddRef(new WindowGlobalParent(aInit, /* inproc */ false)).take();
+}
+
+bool
+TabParent::DeallocPWindowGlobalParent(PWindowGlobalParent* aActor)
+{
+  // Free reference from AllocPWindowGlobalParent.
+  static_cast<WindowGlobalParent*>(aActor)->Release();
+  return true;
+}
+
 void
 TabParent::SendMouseEvent(const nsAString& aType, float aX, float aY,
                           int32_t aButton, int32_t aClickCount,
                           int32_t aModifiers, bool aIgnoreRootScrollFrame)
 {
   if (!mIsDestroyed) {
     Unused << PBrowserParent::SendMouseEvent(nsString(aType), aX, aY,
                                              aButton, aClickCount,
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -322,16 +322,26 @@ public:
                                 const uint32_t& aMsaaID,
                                 const IAccessibleHolder& aDocCOMProxy) override;
 
   /**
    * Return the top level doc accessible parent for this tab.
    */
   a11y::DocAccessibleParent* GetTopLevelDocAccessible() const;
 
+  virtual PWindowGlobalParent*
+  AllocPWindowGlobalParent(const WindowGlobalInit& aInit) override;
+
+  virtual bool
+  DeallocPWindowGlobalParent(PWindowGlobalParent* aActor) override;
+
+  virtual mozilla::ipc::IPCResult
+  RecvPWindowGlobalConstructor(PWindowGlobalParent* aActor,
+                               const WindowGlobalInit& aInit) override;
+
   void LoadURL(nsIURI* aURI);
 
   void InitRendering();
   void MaybeShowFrame();
 
   // XXX/cjones: it's not clear what we gain by hiding these
   // message-sending functions under a layer of indirection and
   // eating the return values
new file mode 100644
--- /dev/null
+++ b/dom/ipc/WindowGlobalChild.cpp
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/WindowGlobalChild.h"
+#include "mozilla/ipc/InProcessChild.h"
+#include "mozilla/dom/BrowsingContext.h"
+
+namespace mozilla {
+namespace dom {
+
+WindowGlobalChild::WindowGlobalChild(nsGlobalWindowInner* aWindow, dom::BrowsingContext* aBrowsingContext)
+  : mWindowGlobal(aWindow)
+  , mBrowsingContext(aBrowsingContext)
+  , mIPCClosed(false)
+{
+}
+
+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()));
+
+  // Send the link constructor over PInProcessChild or PBrowser.
+  if (XRE_IsParentProcess()) {
+    InProcessChild* ipc = InProcessChild::Singleton();
+    if (!ipc) {
+      return nullptr;
+    }
+
+    // Note: ref is released in DeallocPWindowGlobalChild
+    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);
+  }
+
+  return wgc.forget();
+}
+
+already_AddRefed<WindowGlobalParent>
+WindowGlobalChild::GetOtherSide()
+{
+  if (mIPCClosed) {
+    return nullptr;
+  }
+  IProtocol* otherSide = InProcessChild::ParentActorFor(this);
+  return do_AddRef(static_cast<WindowGlobalParent*>(otherSide));
+}
+
+void
+WindowGlobalChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  mIPCClosed = true;
+}
+
+WindowGlobalChild::~WindowGlobalChild()
+{
+}
+
+NS_IMPL_CYCLE_COLLECTION(WindowGlobalChild, mWindowGlobal, mBrowsingContext)
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WindowGlobalChild, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WindowGlobalChild, Release)
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/WindowGlobalChild.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_WindowGlobalChild_h
+#define mozilla_dom_WindowGlobalChild_h
+
+#include "mozilla/RefPtr.h"
+#include "mozilla/dom/PWindowGlobalChild.h"
+
+class nsGlobalWindowInner;
+class nsDocShell;
+
+namespace mozilla {
+namespace dom  {
+
+class BrowsingContext;
+class WindowGlobalParent;
+
+/**
+ * Actor for a single nsGlobalWindowInner. This actor is used to communicate
+ * information to the parent process asynchronously.
+ */
+class WindowGlobalChild : public PWindowGlobalChild
+{
+public:
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WindowGlobalChild)
+  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(WindowGlobalChild)
+
+  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(); }
+
+  // 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> GetOtherSide();
+
+  // Create and initialize the WindowGlobalChild object.
+  static already_AddRefed<WindowGlobalChild>
+  Create(nsGlobalWindowInner* aWindow);
+
+protected:
+  virtual void ActorDestroy(ActorDestroyReason aWhy) override;
+
+private:
+  WindowGlobalChild(nsGlobalWindowInner* aWindow, dom::BrowsingContext* aBc);
+  ~WindowGlobalChild();
+
+  RefPtr<nsGlobalWindowInner> mWindowGlobal;
+  RefPtr<dom::BrowsingContext> mBrowsingContext;
+  bool mIPCClosed;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // !defined(mozilla_dom_WindowGlobalChild_h)
new file mode 100644
--- /dev/null
+++ b/dom/ipc/WindowGlobalParent.cpp
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/WindowGlobalParent.h"
+#include "mozilla/ipc/InProcessParent.h"
+#include "mozilla/dom/BrowsingContext.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla {
+namespace dom {
+
+WindowGlobalParent::WindowGlobalParent(const WindowGlobalInit& aInit,
+                                       bool aInProcess)
+  : mBrowsingContextId(aInit.browsingContextId())
+  , mDocumentPrincipal(aInit.principal())
+  , mInProcess(aInProcess)
+  , mIPCClosed(false)
+{
+  MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess(), "Parent process only");
+  MOZ_RELEASE_ASSERT(mDocumentPrincipal, "Must have a valid principal");
+  MOZ_RELEASE_ASSERT(mBrowsingContextId != 0, "Must be made in BrowsingContext");
+}
+
+void
+WindowGlobalParent::Init()
+{
+  MOZ_ASSERT(Manager(), "Should have a manager!");
+  MOZ_ASSERT(!mFrameLoader, "Cannot Init() a WindowGlobalParent twice!");
+
+  // Determine what toplevel frame element our WindowGlobalParent is being
+  // embedded in.
+  RefPtr<Element> frameElement;
+  if (mInProcess) {
+    // In the in-process case, we can get it from the other side's
+    // WindowGlobalChild.
+    MOZ_ASSERT(Manager()->GetProtocolTypeId() == PInProcessMsgStart);
+    RefPtr<WindowGlobalChild> otherSide = GetOtherSide();
+    if (otherSide && otherSide->WindowGlobal()) {
+      // Get the toplevel window from the other side.
+      RefPtr<nsDocShell> docShell = nsDocShell::Cast(otherSide->WindowGlobal()->GetDocShell());
+      if (docShell) {
+        docShell->GetTopFrameElement(getter_AddRefs(frameElement));
+      }
+    }
+  } else {
+    // In the cross-process case, we can get the frame element from our manager.
+    MOZ_ASSERT(Manager()->GetProtocolTypeId() == PBrowserMsgStart);
+    frameElement = static_cast<TabParent*>(Manager())->GetOwnerElement();
+  }
+
+  // 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();
+  }
+}
+
+already_AddRefed<dom::BrowsingContext>
+WindowGlobalParent::BrowsingContext()
+{
+  return dom::BrowsingContext::Get(mBrowsingContextId);
+}
+
+already_AddRefed<WindowGlobalChild>
+WindowGlobalParent::GetOtherSide()
+{
+  if (mIPCClosed) {
+    return nullptr;
+  }
+  IProtocol* otherSide = InProcessParent::ChildActorFor(this);
+  return do_AddRef(static_cast<WindowGlobalChild*>(otherSide));
+}
+
+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();
+}
+
+void
+WindowGlobalParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  mIPCClosed = true;
+}
+
+WindowGlobalParent::~WindowGlobalParent()
+{
+}
+
+NS_IMPL_CYCLE_COLLECTION(WindowGlobalParent, mFrameLoader)
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WindowGlobalParent, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WindowGlobalParent, Release)
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/WindowGlobalParent.h
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_WindowGlobalParent_h
+#define mozilla_dom_WindowGlobalParent_h
+
+#include "mozilla/RefPtr.h"
+#include "mozilla/dom/PWindowGlobalParent.h"
+
+class nsIPrincipal;
+class nsIURI;
+class nsFrameLoader;
+
+namespace mozilla {
+namespace dom  {
+
+class BrowsingContext;
+class WindowGlobalChild;
+
+/**
+ * A handle in the parent process to a specific nsGlobalWindowInner object.
+ */
+class WindowGlobalParent final : public PWindowGlobalParent
+{
+public:
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WindowGlobalParent)
+  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(WindowGlobalParent)
+
+  // 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
+  // |nullptr| if the actor has been torn down, or is not in-process.
+  already_AddRefed<WindowGlobalChild> GetOtherSide();
+
+  // 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.
+  already_AddRefed<dom::BrowsingContext> BrowsingContext();
+
+  // Get the root nsFrameLoader object for the tree of BrowsingContext nodes
+  // 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; }
+
+  // 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();
+
+protected:
+  // IPC messages
+  mozilla::ipc::IPCResult RecvUpdateDocumentURI(nsIURI* aURI) override;
+
+  void ActorDestroy(ActorDestroyReason aWhy) override;
+
+private:
+  ~WindowGlobalParent();
+
+  // XXX(nika): We should store the BrowsingContext here. Unfortunately, the
+  // parent process is not sent down the BrowsingContext object until
+  // potentially after the WindowGlobalChild has been created. We should change
+  // this in the future.
+  uint64_t mBrowsingContextId;
+
+  // 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;
+  bool mInProcess;
+  bool mIPCClosed;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // !defined(mozilla_dom_WindowGlobalParent_h)
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -45,16 +45,18 @@ EXPORTS.mozilla.dom += [
     'nsIContentParent.h',
     'PermissionMessageUtils.h',
     'TabChild.h',
     'TabContext.h',
     'TabMessageUtils.h',
     'TabParent.h',
     'URLClassifierChild.h',
     'URLClassifierParent.h',
+    'WindowGlobalChild.h',
+    'WindowGlobalParent.h',
 ]
 
 EXPORTS.mozilla += [
     'PreallocatedProcessManager.h',
     'ProcessHangMonitor.h',
     'ProcessHangMonitorIPC.h',
     'ProcessPriorityManager.h',
 ]
@@ -80,16 +82,18 @@ UNIFIED_SOURCES += [
     'SharedMap.cpp',
     'SharedStringMap.cpp',
     'StructuredCloneData.cpp',
     'TabChild.cpp',
     'TabContext.cpp',
     'TabMessageUtils.cpp',
     'TabParent.cpp',
     'URLClassifierParent.cpp',
+    'WindowGlobalChild.cpp',
+    'WindowGlobalParent.cpp',
 ]
 
 # ContentChild.cpp cannot be compiled in unified mode on  linux due to Time conflict
 SOURCES += [
     'ContentChild.cpp',
     'ProcessHangMonitor.cpp',
 ]
 
@@ -107,16 +111,17 @@ IPDL_SOURCES += [
     'PFilePicker.ipdl',
     'PLoginReputation.ipdl',
     'PPluginWidget.ipdl',
     'PProcessHangMonitor.ipdl',
     'PTabContext.ipdlh',
     'PURLClassifier.ipdl',
     'PURLClassifierInfo.ipdlh',
     'PURLClassifierLocal.ipdl',
+    'PWindowGlobal.ipdl',
     'ServiceWorkerConfiguration.ipdlh',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_TARGET'] == 'Darwin':
--- a/ipc/glue/InProcessChild.cpp
+++ b/ipc/glue/InProcessChild.cpp
@@ -1,13 +1,31 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ipc/InProcessChild.h"
+#include "mozilla/dom/WindowGlobalChild.h"
+
+using namespace mozilla::dom;
 
 namespace mozilla {
 namespace ipc {
 
+PWindowGlobalChild*
+InProcessChild::AllocPWindowGlobalChild(const WindowGlobalInit& aInit)
+{
+  MOZ_ASSERT_UNREACHABLE("PWindowGlobalChild should not be created manually");
+  return nullptr;
+}
+
+bool
+InProcessChild::DeallocPWindowGlobalChild(PWindowGlobalChild* aActor)
+{
+  // Free IPC-held reference
+  static_cast<WindowGlobalChild*>(aActor)->Release();
+  return true;
+}
+
 } // namespace ipc
 } // namespace mozilla
--- a/ipc/glue/InProcessChild.h
+++ b/ipc/glue/InProcessChild.h
@@ -6,16 +6,21 @@
 
 #ifndef mozilla_ipc_InProcessChild_h
 #define mozilla_ipc_InProcessChild_h
 
 #include "mozilla/ipc/PInProcessChild.h"
 #include "mozilla/StaticPtr.h"
 
 namespace mozilla {
+namespace dom {
+class PWindowGlobalParent;
+class PWindowGlobalChild;
+} // namespace dom
+
 namespace ipc {
 
 class InProcessParent;
 
 /**
  * The `InProcessChild` class represents the child half of a main-thread to
  * main-thread actor.
  *
@@ -33,16 +38,23 @@ public:
   // Get the singleton instance of this actor.
   static InProcessChild* Singleton();
 
   // Get the parent side of the in-process child actor |aActor|. If |aActor| is
   // not an in-process actor, or is not connected, this method will return
   // |nullptr|.
   static IProtocol* ParentActorFor(IProtocol* aActor);
 
+protected:
+  virtual mozilla::dom::PWindowGlobalChild*
+  AllocPWindowGlobalChild(const WindowGlobalInit& aInit) override;
+
+  virtual bool
+  DeallocPWindowGlobalChild(mozilla::dom::PWindowGlobalChild* aActor) override;
+
 private:
   // NOTE: PInProcess lifecycle management is declared as staic methods and
   // state on InProcessParent, and implemented in InProcessImpl.cpp.
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
   virtual void DeallocPInProcessChild() override;
   ~InProcessChild() = default;
 
   static StaticRefPtr<InProcessChild> sSingleton;
--- a/ipc/glue/InProcessImpl.cpp
+++ b/ipc/glue/InProcessImpl.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ipc/InProcessParent.h"
 #include "mozilla/ipc/InProcessChild.h"
+#include "nsIObserverService.h"
+#include "mozilla/Services.h"
 
 // This file contains the implementation of core InProcess lifecycle management
 // facilities.
 
 namespace mozilla {
 namespace ipc {
 
 StaticRefPtr<InProcessParent> InProcessParent::sSingleton;
--- a/ipc/glue/InProcessParent.cpp
+++ b/ipc/glue/InProcessParent.cpp
@@ -1,15 +1,41 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ipc/InProcessParent.h"
+#include "mozilla/dom/WindowGlobalParent.h"
+
+using namespace mozilla::dom;
 
 namespace mozilla {
 namespace ipc {
 
 NS_IMPL_ISUPPORTS(InProcessParent, nsIObserver)
 
+IPCResult
+InProcessParent::RecvPWindowGlobalConstructor(PWindowGlobalParent* aActor,
+                                              const WindowGlobalInit& aInit)
+{
+  static_cast<WindowGlobalParent*>(aActor)->Init();
+  return IPC_OK();
+}
+
+PWindowGlobalParent*
+InProcessParent::AllocPWindowGlobalParent(const WindowGlobalInit& aInit)
+{
+  // Reference freed in DeallocPWindowGlobalParent.
+  return do_AddRef(new WindowGlobalParent(aInit, /* inproc */ true)).take();
+}
+
+bool
+InProcessParent::DeallocPWindowGlobalParent(PWindowGlobalParent* aActor)
+{
+  // Free IPC-held reference.
+  static_cast<WindowGlobalParent*>(aActor)->Release();
+  return true;
+}
+
 } // namespace ipc
 } // namespace mozilla
\ No newline at end of file
--- a/ipc/glue/InProcessParent.h
+++ b/ipc/glue/InProcessParent.h
@@ -6,16 +6,21 @@
 
 #ifndef mozilla_ipc_InProcessParent_h
 #define mozilla_ipc_InProcessParent_h
 
 #include "mozilla/ipc/PInProcessParent.h"
 #include "mozilla/StaticPtr.h"
 
 namespace mozilla {
+namespace dom {
+class PWindowGlobalParent;
+class PWindowGlobalChild;
+} // namespace dom
+
 namespace ipc {
 
 class InProcessChild;
 
 /**
  * The `InProcessParent` class represents the parent half of a main-thread to
  * main-thread actor.
  *
@@ -35,16 +40,27 @@ public:
   // Get the singleton instance of this actor.
   static InProcessParent* Singleton();
 
   // Get the child side of the in-process child actor |aActor|. If |aActor| is
   // not an in-process actor, or is not connected, this method will return
   // |nullptr|.
   static IProtocol* ChildActorFor(IProtocol* aActor);
 
+protected:
+  virtual mozilla::dom::PWindowGlobalParent*
+  AllocPWindowGlobalParent(const WindowGlobalInit& aInit) override;
+
+  virtual bool
+  DeallocPWindowGlobalParent(mozilla::dom::PWindowGlobalParent* aActor) override;
+
+  virtual IPCResult
+  RecvPWindowGlobalConstructor(mozilla::dom::PWindowGlobalParent* aActor,
+                               const WindowGlobalInit& aInit) override;
+
 private:
   // Lifecycle management is implemented in InProcessImpl.cpp
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
   virtual void DeallocPInProcessParent() override;
   ~InProcessParent() = default;
 
   static void Startup();
   static void Shutdown();
--- a/ipc/glue/PInProcess.ipdl
+++ b/ipc/glue/PInProcess.ipdl
@@ -1,23 +1,35 @@
 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+include protocol PWindowGlobal;
+
+include DOMTypes;
+
 namespace mozilla {
 namespace ipc {
 
 /**
  * PInProcess is intended for use as an alternative actor manager to PContent
  * for async actors which want to be used uniformly in both Content->Chrome and
  * Chrome->Chrome circumstances.
  *
  * `mozilla::ipc::InProcess{Parent, Child}::Singleton()` should be used to get
  * an instance of this actor.
  */
 async protocol PInProcess
 {
+  manages PWindowGlobal;
+
+parent:
+  /**
+   * Construct a new WindowGlobal actor for a window global in the given
+   * BrowsingContext and with the given principal.
+   */
+  async PWindowGlobal(WindowGlobalInit init);
 };
 
 } // namespace ipc
 } // namespace mozilla