Bug 1353867 - Change WindowProxy type. r=bzbarsky
☠☠ backed out by cc4bb8c7fa92 ☠ ☠
authorPeter Van der Beken <peterv@propagandism.org>
Mon, 31 Dec 2018 10:50:36 +0000
changeset 509291 ebdf4531b3bde9d88da6a22c2df5290dda137c34
parent 509290 20c58f920675ca1518432c982e678386b6c2d9e9
child 509292 8b60851b93da2cf1f622e1bad41ba2e0527876c5
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs1353867
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 1353867 - Change WindowProxy type. r=bzbarsky Add a WindowProxyHolder type and generate binding code that takes or returns it whenever the WebIDL refers to the WindowProxy type. This patch just makes the WindowProxyHolder hold a strong reference to a nsPIDOMWindowOuter. Differential Revision: https://phabricator.services.mozilla.com/D12650
dom/base/ContentFrameMessageManager.h
dom/base/InProcessTabChildMessageManager.cpp
dom/base/InProcessTabChildMessageManager.h
dom/base/WindowProxyHolder.h
dom/base/moz.build
dom/base/nsDocument.cpp
dom/base/nsGlobalWindowInner.cpp
dom/base/nsGlobalWindowInner.h
dom/base/nsGlobalWindowOuter.cpp
dom/base/nsGlobalWindowOuter.h
dom/base/nsIDocument.h
dom/base/nsINode.cpp
dom/base/nsINode.h
dom/base/nsObjectLoadingContent.cpp
dom/base/nsObjectLoadingContent.h
dom/base/nsWindowRoot.cpp
dom/base/nsWindowRoot.h
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/Bindings.conf
dom/bindings/Codegen.py
dom/browser-element/BrowserElementParent.cpp
dom/events/DOMEventTargetHelper.h
dom/events/EventTarget.cpp
dom/events/EventTarget.h
dom/events/MessageEvent.cpp
dom/events/UIEvent.h
dom/html/HTMLObjectElement.cpp
dom/html/HTMLObjectElement.h
dom/html/nsGenericHTMLFrameElement.cpp
dom/html/nsGenericHTMLFrameElement.h
dom/html/nsHTMLDocument.cpp
dom/html/nsHTMLDocument.h
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/smil/TimeEvent.h
dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp
dom/xul/XULFrameElement.cpp
dom/xul/XULFrameElement.h
toolkit/components/antitracking/AntiTrackingCommon.cpp
toolkit/components/extensions/WebExtensionContentScript.h
toolkit/components/extensions/WebExtensionPolicy.cpp
toolkit/components/extensions/WebExtensionPolicy.h
toolkit/components/sessionstore/nsSessionStoreUtils.cpp
--- a/dom/base/ContentFrameMessageManager.h
+++ b/dom/base/ContentFrameMessageManager.h
@@ -10,16 +10,20 @@
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/MessageManagerGlobal.h"
 #include "nsContentUtils.h"
 #include "xpcpublic.h"
 
 namespace mozilla {
 namespace dom {
 
+template <typename>
+struct Nullable;
+class WindowProxyHolder;
+
 #define NS_CONTENTFRAMEMESSAGEMANAGER_IID            \
   {                                                  \
     0x97e192a6, 0xab7a, 0x4c8f, {                    \
       0xb7, 0xdd, 0xf7, 0xec, 0x36, 0x38, 0x71, 0xb5 \
     }                                                \
   }
 
 /**
@@ -28,18 +32,17 @@ namespace dom {
 class ContentFrameMessageManager : public DOMEventTargetHelper,
                                    public MessageManagerGlobal {
  public:
   using DOMEventTargetHelper::AddRef;
   using DOMEventTargetHelper::Release;
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_CONTENTFRAMEMESSAGEMANAGER_IID)
 
-  virtual already_AddRefed<nsPIDOMWindowOuter> GetContent(
-      ErrorResult& aError) = 0;
+  virtual Nullable<WindowProxyHolder> GetContent(ErrorResult& aError) = 0;
   virtual already_AddRefed<nsIDocShell> GetDocShell(ErrorResult& aError) = 0;
   virtual already_AddRefed<nsIEventTarget> GetTabEventTarget() = 0;
   virtual uint64_t ChromeOuterWindowID() = 0;
 
   nsFrameMessageManager* GetMessageManager() { return mMessageManager; }
   void DisconnectMessageManager() {
     mMessageManager->Disconnect();
     mMessageManager = nullptr;
--- a/dom/base/InProcessTabChildMessageManager.cpp
+++ b/dom/base/InProcessTabChildMessageManager.cpp
@@ -14,16 +14,17 @@
 #include "nsFrameLoader.h"
 #include "xpcpublic.h"
 #include "nsIMozBrowserFrame.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/dom/ChromeMessageSender.h"
 #include "mozilla/dom/MessageManagerBinding.h"
 #include "mozilla/dom/SameProcessMessageQueue.h"
 #include "mozilla/dom/ScriptLoader.h"
+#include "mozilla/dom/WindowProxyHolder.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::dom::ipc;
 
 bool InProcessTabChildMessageManager::DoSendBlockingMessage(
     JSContext* aCx, const nsAString& aMessage, StructuredCloneData& aData,
     JS::Handle<JSObject*> aCpows, nsIPrincipal* aPrincipal,
@@ -142,23 +143,26 @@ JSObject* InProcessTabChildMessageManage
   return ContentFrameMessageManager_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 void InProcessTabChildMessageManager::CacheFrameLoader(
     nsFrameLoader* aFrameLoader) {
   mFrameLoader = aFrameLoader;
 }
 
-already_AddRefed<nsPIDOMWindowOuter>
-InProcessTabChildMessageManager::GetContent(ErrorResult& aError) {
+Nullable<WindowProxyHolder> InProcessTabChildMessageManager::GetContent(
+    ErrorResult& aError) {
   nsCOMPtr<nsPIDOMWindowOuter> content;
   if (mDocShell) {
     content = mDocShell->GetWindow();
   }
-  return content.forget();
+  if (!content) {
+    return nullptr;
+  }
+  return WindowProxyHolder(content);
 }
 
 already_AddRefed<nsIEventTarget>
 InProcessTabChildMessageManager::GetTabEventTarget() {
   nsCOMPtr<nsIEventTarget> target = GetMainThreadEventTarget();
   return target.forget();
 }
 
--- a/dom/base/InProcessTabChildMessageManager.h
+++ b/dom/base/InProcessTabChildMessageManager.h
@@ -60,18 +60,17 @@ class InProcessTabChildMessageManager fi
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
       InProcessTabChildMessageManager, DOMEventTargetHelper)
 
   void MarkForCC();
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
-  virtual already_AddRefed<nsPIDOMWindowOuter> GetContent(
-      ErrorResult& aError) override;
+  Nullable<WindowProxyHolder> GetContent(ErrorResult& aError) override;
   virtual already_AddRefed<nsIDocShell> GetDocShell(
       ErrorResult& aError) override {
     nsCOMPtr<nsIDocShell> docShell(mDocShell);
     return docShell.forget();
   }
   virtual already_AddRefed<nsIEventTarget> GetTabEventTarget() override;
   virtual uint64_t ChromeOuterWindowID() override;
 
new file mode 100644
--- /dev/null
+++ b/dom/base/WindowProxyHolder.h
@@ -0,0 +1,67 @@
+/* -*- 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/. */
+
+#ifndef mozilla_dom_WindowProxyHolder_h__
+#define mozilla_dom_WindowProxyHolder_h__
+
+#include "nsPIDOMWindow.h"
+
+namespace mozilla {
+namespace dom {
+
+/**
+ * This class is used for passing arguments and the return value for WebIDL
+ * binding code that takes/returns a WindowProxy object and for WebIDL
+ * unions/dictionaries that contain a WindowProxy member. It should never
+ * contain null; if the value in WebIDL is nullable the binding code will use a
+ * Nullable<WindowProxyHolder>.
+ */
+class WindowProxyHolder {
+ public:
+  WindowProxyHolder() = default;
+  explicit WindowProxyHolder(nsPIDOMWindowOuter* aWin) : mWindow(aWin) {
+    MOZ_ASSERT(mWindow, "Don't set WindowProxyHolder to null.");
+  }
+  explicit WindowProxyHolder(already_AddRefed<nsPIDOMWindowOuter>&& aWin)
+      : mWindow(std::move(aWin)) {
+    MOZ_ASSERT(mWindow, "Don't set WindowProxyHolder to null.");
+  }
+  WindowProxyHolder& operator=(nsPIDOMWindowOuter* aWin) {
+    mWindow = aWin;
+    MOZ_ASSERT(mWindow, "Don't set WindowProxyHolder to null.");
+    return *this;
+  }
+  WindowProxyHolder& operator=(already_AddRefed<nsPIDOMWindowOuter>&& aWin) {
+    mWindow = std::move(aWin);
+    MOZ_ASSERT(mWindow, "Don't set WindowProxyHolder to null.");
+    return *this;
+  }
+
+  nsPIDOMWindowOuter* get() const {
+    MOZ_ASSERT(mWindow, "WindowProxyHolder hasn't been initialized.");
+    return mWindow;
+  }
+
+ private:
+  friend void ImplCycleCollectionUnlink(WindowProxyHolder& aProxy);
+
+  nsCOMPtr<nsPIDOMWindowOuter> mWindow;
+};
+
+inline void ImplCycleCollectionTraverse(
+    nsCycleCollectionTraversalCallback& aCallback, WindowProxyHolder& aProxy,
+    const char* aName, uint32_t aFlags = 0) {
+  CycleCollectionNoteChild(aCallback, aProxy.get(), "mWindow", aFlags);
+}
+
+inline void ImplCycleCollectionUnlink(WindowProxyHolder& aProxy) {
+  aProxy.mWindow = nullptr;
+}
+
+}  // namespace dom
+}  // namespace mozilla
+
+#endif /* mozilla_dom_WindowProxyHolder_h__ */
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -230,16 +230,17 @@ EXPORTS.mozilla.dom += [
     'Timeout.h',
     'TimeoutHandler.h',
     'TimeoutManager.h',
     'TreeIterator.h',
     'TreeWalker.h',
     'VisualViewport.h',
     'WebKitCSSMatrix.h',
     'WindowOrientationObserver.h',
+    'WindowProxyHolder.h',
 ]
 
 if CONFIG['FUZZING']:
     EXPORTS.mozilla.dom += [
         'FuzzingFunctions.h',
     ]
 
 UNIFIED_SOURCES += [
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -289,16 +289,17 @@
 #include "mozilla/RestyleManager.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "nsHTMLTags.h"
 #include "NodeUbiReporting.h"
 #include "nsICookieService.h"
 #include "mozilla/net/ChannelEventQueue.h"
 #include "mozilla/net/RequestContextService.h"
 #include "StorageAccessPermissionRequest.h"
+#include "mozilla/dom/WindowProxyHolder.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 typedef nsTArray<Link*> LinkArray;
 
 static LazyLogModule gDocumentLeakPRLog("DocumentLeak");
 static LazyLogModule gCspPRLog("CSP");
@@ -3363,16 +3364,24 @@ nsresult nsIDocument::GetSrcdocData(nsAS
     if (inStrmChan) {
       return inStrmChan->GetSrcdocData(aSrcdocData);
     }
   }
   aSrcdocData = VoidString();
   return NS_OK;
 }
 
+Nullable<WindowProxyHolder> nsIDocument::GetDefaultView() const {
+  nsPIDOMWindowOuter* win = GetWindow();
+  if (!win) {
+    return nullptr;
+  }
+  return WindowProxyHolder(win);
+}
+
 Element* nsIDocument::GetActiveElement() {
   // Get the focused element.
   Element* focusedElement = GetRetargetedFocusedElement();
   if (focusedElement) {
     return focusedElement;
   }
 
   // No focused element anywhere in this document.  Try to get the BODY.
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -2541,17 +2541,17 @@ bool nsGlobalWindowInner::HasActiveSpeec
     return !mSpeechSynthesis->HasEmptyQueue();
   }
 
   return false;
 }
 
 #endif
 
-already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowInner::GetParent(
+Nullable<WindowProxyHolder> nsGlobalWindowInner::GetParent(
     ErrorResult& aError) {
   FORWARD_TO_OUTER_OR_THROW(GetParentOuter, (), aError, nullptr);
 }
 
 /**
  * GetScriptableParent is called when script reads window.parent.
  *
  * In contrast to GetRealParent, GetScriptableParent respects <iframe
@@ -3301,17 +3301,17 @@ double nsGlobalWindowInner::GetScrollX(E
 }
 
 double nsGlobalWindowInner::GetScrollY(ErrorResult& aError) {
   FORWARD_TO_OUTER_OR_THROW(GetScrollYOuter, (), aError, 0);
 }
 
 uint32_t nsGlobalWindowInner::Length() { FORWARD_TO_OUTER(Length, (), 0); }
 
-already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowInner::GetTop(
+Nullable<WindowProxyHolder> nsGlobalWindowInner::GetTop(
     mozilla::ErrorResult& aError) {
   FORWARD_TO_OUTER_OR_THROW(GetTopOuter, (), aError, nullptr);
 }
 
 nsPIDOMWindowOuter* nsGlobalWindowInner::GetChildWindow(
     const nsAString& aName) {
   if (GetOuterWindowInternal()) {
     return GetOuterWindowInternal()->GetChildWindow(aName);
@@ -3679,24 +3679,25 @@ void nsGlobalWindowInner::CaptureEvents(
 }
 
 void nsGlobalWindowInner::ReleaseEvents() {
   if (mDoc) {
     mDoc->WarnOnceAbout(nsIDocument::eUseOfReleaseEvents);
   }
 }
 
-already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowInner::Open(
-    const nsAString& aUrl, const nsAString& aName, const nsAString& aOptions,
-    ErrorResult& aError) {
+Nullable<WindowProxyHolder> nsGlobalWindowInner::Open(const nsAString& aUrl,
+                                                      const nsAString& aName,
+                                                      const nsAString& aOptions,
+                                                      ErrorResult& aError) {
   FORWARD_TO_OUTER_OR_THROW(OpenOuter, (aUrl, aName, aOptions, aError), aError,
                             nullptr);
 }
 
-already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowInner::OpenDialog(
+Nullable<WindowProxyHolder> nsGlobalWindowInner::OpenDialog(
     JSContext* aCx, const nsAString& aUrl, const nsAString& aName,
     const nsAString& aOptions, const Sequence<JS::Value>& aExtraArgument,
     ErrorResult& aError) {
   FORWARD_TO_OUTER_OR_THROW(
       OpenDialogOuter, (aCx, aUrl, aName, aOptions, aExtraArgument, aError),
       aError, nullptr);
 }
 
@@ -3876,17 +3877,17 @@ void nsGlobalWindowInner::Btoa(const nsA
                                ErrorResult& aError) {
   aError = nsContentUtils::Btoa(aBinaryData, aAsciiBase64String);
 }
 
 //*****************************************************************************
 // EventTarget
 //*****************************************************************************
 
-nsPIDOMWindowOuter* nsGlobalWindowInner::GetOwnerGlobalForBindings() {
+nsPIDOMWindowOuter* nsGlobalWindowInner::GetOwnerGlobalForBindingsInternal() {
   return nsPIDOMWindowOuter::GetFromCurrentInner(this);
 }
 
 bool nsGlobalWindowInner::DispatchEvent(Event& aEvent, CallerType aCallerType,
                                         ErrorResult& aRv) {
   if (!IsCurrentInnerWindow()) {
     NS_WARNING(
         "DispatchEvent called on non-current inner window, dropping. "
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -301,17 +301,17 @@ class nsGlobalWindowInner final : public
 
   virtual mozilla::EventListenerManager* GetExistingListenerManager()
       const override;
 
   virtual mozilla::EventListenerManager* GetOrCreateListenerManager() override;
 
   bool ComputeDefaultWantsUntrusted(mozilla::ErrorResult& aRv) final;
 
-  virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindings() override;
+  virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindingsInternal() override;
 
   virtual nsIGlobalObject* GetOwnerGlobal() const override;
 
   EventTarget* GetTargetForDOMEvent() override;
 
   using mozilla::dom::EventTarget::DispatchEvent;
   bool DispatchEvent(mozilla::dom::Event& aEvent,
                      mozilla::dom::CallerType aCallerType,
@@ -618,39 +618,40 @@ class nsGlobalWindowInner final : public
   bool GetClosed(mozilla::ErrorResult& aError);
   void Stop(mozilla::ErrorResult& aError);
   void Focus(mozilla::ErrorResult& aError);
   nsresult Focus() override;
   void Blur(mozilla::ErrorResult& aError);
   nsDOMWindowList* GetFrames() final;
   already_AddRefed<nsPIDOMWindowOuter> GetFrames(mozilla::ErrorResult& aError);
   uint32_t Length();
-  already_AddRefed<nsPIDOMWindowOuter> GetTop(mozilla::ErrorResult& aError);
+  mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetTop(
+      mozilla::ErrorResult& aError);
 
  protected:
   explicit nsGlobalWindowInner(nsGlobalWindowOuter* aOuterWindow);
   // Initializes the mWasOffline member variable
   void InitWasOffline();
 
  public:
   nsPIDOMWindowOuter* GetOpenerWindow(mozilla::ErrorResult& aError);
   void GetOpener(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval,
                  mozilla::ErrorResult& aError);
   void SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener,
                  mozilla::ErrorResult& aError);
   void GetEvent(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval);
-  already_AddRefed<nsPIDOMWindowOuter> GetParent(mozilla::ErrorResult& aError);
+  mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetParent(
+      mozilla::ErrorResult& aError);
   nsPIDOMWindowOuter* GetScriptableParent() override;
   mozilla::dom::Element* GetFrameElement(nsIPrincipal& aSubjectPrincipal,
                                          mozilla::ErrorResult& aError);
   mozilla::dom::Element* GetFrameElement() override;
-  already_AddRefed<nsPIDOMWindowOuter> Open(const nsAString& aUrl,
-                                            const nsAString& aName,
-                                            const nsAString& aOptions,
-                                            mozilla::ErrorResult& aError);
+  mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> Open(
+      const nsAString& aUrl, const nsAString& aName, const nsAString& aOptions,
+      mozilla::ErrorResult& aError);
   nsDOMOfflineResourceList* GetApplicationCache(mozilla::ErrorResult& aError);
   nsDOMOfflineResourceList* GetApplicationCache() override;
 
 #if defined(MOZ_WIDGET_ANDROID)
   int16_t Orientation(mozilla::dom::CallerType aCallerType) const;
 #endif
 
   already_AddRefed<mozilla::dom::Console> GetConsole(JSContext* aCx,
@@ -852,17 +853,17 @@ class nsGlobalWindowInner final : public
   void SetFullScreen(bool aFullscreen, mozilla::ErrorResult& aError);
   bool Find(const nsAString& aString, bool aCaseSensitive, bool aBackwards,
             bool aWrapAround, bool aWholeWord, bool aSearchInFrames,
             bool aShowDialog, mozilla::ErrorResult& aError);
   uint64_t GetMozPaintCount(mozilla::ErrorResult& aError);
 
   bool ShouldResistFingerprinting();
 
-  already_AddRefed<nsPIDOMWindowOuter> OpenDialog(
+  mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> OpenDialog(
       JSContext* aCx, const nsAString& aUrl, const nsAString& aName,
       const nsAString& aOptions,
       const mozilla::dom::Sequence<JS::Value>& aExtraArgument,
       mozilla::ErrorResult& aError);
   void UpdateCommands(const nsAString& anAction, mozilla::dom::Selection* aSel,
                       int16_t aReason);
 
   void GetContent(JSContext* aCx, JS::MutableHandle<JSObject*> aRetval,
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -33,16 +33,17 @@
 #include "mozilla/dom/Performance.h"
 #include "mozilla/dom/StorageEvent.h"
 #include "mozilla/dom/StorageEventBinding.h"
 #include "mozilla/dom/StorageNotifierService.h"
 #include "mozilla/dom/StorageUtils.h"
 #include "mozilla/dom/Timeout.h"
 #include "mozilla/dom/TimeoutHandler.h"
 #include "mozilla/dom/TimeoutManager.h"
+#include "mozilla/dom/WindowProxyHolder.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #if defined(MOZ_WIDGET_ANDROID)
 #include "mozilla/dom/WindowOrientationObserver.h"
 #endif
 #include "nsError.h"
 #include "nsIIdleService.h"
 #include "nsISizeOfEventTarget.h"
 #include "nsDOMJSUtils.h"
@@ -2619,41 +2620,43 @@ bool nsPIDOMWindowOuter::GetServiceWorke
   // iframes get the correct devtools setting.
   nsCOMPtr<nsPIDOMWindowOuter> topWindow = GetScriptableTop();
   if (!topWindow) {
     return false;
   }
   return topWindow->mServiceWorkersTestingEnabled;
 }
 
-already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowOuter::GetParentOuter() {
-  if (!mDocShell) {
+Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetParentOuter() {
+  nsPIDOMWindowOuter* parent = GetScriptableParent();
+  if (!parent) {
     return nullptr;
   }
 
-  nsCOMPtr<nsPIDOMWindowOuter> parent;
-  if (mDocShell->GetIsMozBrowser()) {
-    parent = this;
-  } else {
-    parent = GetParent();
-  }
-
-  return parent.forget();
+  return WindowProxyHolder(parent);
 }
 
 /**
  * GetScriptableParent is called when script reads window.parent.
  *
  * In contrast to GetRealParent, GetScriptableParent respects <iframe
  * mozbrowser> boundaries, so if |this| is contained by an <iframe
  * mozbrowser>, we will return |this| as its own parent.
  */
 nsPIDOMWindowOuter* nsGlobalWindowOuter::GetScriptableParent() {
-  nsCOMPtr<nsPIDOMWindowOuter> parent = GetParentOuter();
-  return parent.get();
+  if (!mDocShell) {
+    return nullptr;
+  }
+
+  if (mDocShell->GetIsMozBrowser()) {
+    return this;
+  }
+
+  nsCOMPtr<nsPIDOMWindowOuter> parent = GetParent();
+  return parent;
 }
 
 /**
  * Behavies identically to GetScriptableParent extept that it returns null
  * if GetScriptableParent would return this window.
  */
 nsPIDOMWindowOuter* nsGlobalWindowOuter::GetScriptableParentOrNull() {
   nsPIDOMWindowOuter* parent = GetScriptableParent();
@@ -2764,17 +2767,18 @@ already_AddRefed<nsPIDOMWindowOuter> nsG
       GetChildWindow(NS_LITERAL_STRING("content"));
   if (domWindow) {
     return domWindow.forget();
   }
 
   // If we're contained in <iframe mozbrowser>, then GetContent is the same as
   // window.top.
   if (mDocShell && mDocShell->GetIsInMozBrowser()) {
-    return GetTopOuter();
+    domWindow = GetScriptableTop();
+    return domWindow.forget();
   }
 
   nsCOMPtr<nsIDocShellTreeItem> primaryContent;
   if (aCallerType != CallerType::System) {
     if (mDoc) {
       mDoc->WarnOnceAbout(nsIDocument::eWindowContentUntrusted);
     }
     // If we're called by non-chrome code, make sure we don't return
@@ -3545,19 +3549,22 @@ double nsGlobalWindowOuter::GetScrollXOu
 double nsGlobalWindowOuter::GetScrollYOuter() { return GetScrollXY(false).y; }
 
 uint32_t nsGlobalWindowOuter::Length() {
   nsDOMWindowList* windows = GetFrames();
 
   return windows ? windows->GetLength() : 0;
 }
 
-already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowOuter::GetTopOuter() {
+Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetTopOuter() {
   nsCOMPtr<nsPIDOMWindowOuter> top = GetScriptableTop();
-  return top.forget();
+  if (!top) {
+    return nullptr;
+  }
+  return WindowProxyHolder(top.forget());
 }
 
 nsPIDOMWindowOuter* nsGlobalWindowOuter::GetChildWindow(
     const nsAString& aName) {
   nsCOMPtr<nsIDocShell> docShell(GetDocShell());
   NS_ENSURE_TRUE(docShell, nullptr);
 
   nsCOMPtr<nsIDocShellTreeItem> child;
@@ -5222,22 +5229,25 @@ void nsGlobalWindowOuter::FireAbuseEvent
     ios->NewURI(NS_ConvertUTF16toUTF8(aPopupURL), nullptr, baseURL,
                 getter_AddRefs(popupURI));
 
   // fire an event block full of informative URIs
   FirePopupBlockedEvent(topDoc, popupURI, aPopupWindowName,
                         aPopupWindowFeatures);
 }
 
-already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowOuter::OpenOuter(
+Nullable<WindowProxyHolder> nsGlobalWindowOuter::OpenOuter(
     const nsAString& aUrl, const nsAString& aName, const nsAString& aOptions,
     ErrorResult& aError) {
   nsCOMPtr<nsPIDOMWindowOuter> window;
   aError = OpenJS(aUrl, aName, aOptions, getter_AddRefs(window));
-  return window.forget();
+  if (!window) {
+    return nullptr;
+  }
+  return WindowProxyHolder(window.forget());
 }
 
 nsresult nsGlobalWindowOuter::Open(const nsAString& aUrl,
                                    const nsAString& aName,
                                    const nsAString& aOptions,
                                    nsDocShellLoadState* aLoadState,
                                    bool aForceNoOpener,
                                    nsPIDOMWindowOuter** _retval) {
@@ -5297,17 +5307,17 @@ nsresult nsGlobalWindowOuter::OpenDialog
                       false,             // aDoJSFixups
                       false,             // aNavigate
                       nullptr, nullptr,  // No args
                       nullptr,           // aLoadState
                       false,             // aForceNoOpener
                       _retval);
 }
 
-already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowOuter::OpenDialogOuter(
+Nullable<WindowProxyHolder> nsGlobalWindowOuter::OpenDialogOuter(
     JSContext* aCx, const nsAString& aUrl, const nsAString& aName,
     const nsAString& aOptions, const Sequence<JS::Value>& aExtraArgument,
     ErrorResult& aError) {
   nsCOMPtr<nsIJSArgArray> argvArray;
   aError =
       NS_CreateJSArgv(aCx, aExtraArgument.Length(), aExtraArgument.Elements(),
                       getter_AddRefs(argvArray));
   if (aError.Failed()) {
@@ -5320,17 +5330,20 @@ already_AddRefed<nsPIDOMWindowOuter> nsG
                         false,               // aContentModal
                         false,               // aCalledNoScript
                         false,               // aDoJSFixups
                         true,                // aNavigate
                         argvArray, nullptr,  // Arguments
                         nullptr,             // aLoadState
                         false,               // aForceNoOpener
                         getter_AddRefs(dialog));
-  return dialog.forget();
+  if (!dialog) {
+    return nullptr;
+  }
+  return WindowProxyHolder(dialog.forget());
 }
 
 already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowOuter::GetFramesOuter() {
   RefPtr<nsPIDOMWindowOuter> frames(this);
   FlushPendingNotifications(FlushType::ContentAndNotify);
   return frames.forget();
 }
 
@@ -6085,17 +6098,17 @@ bool nsGlobalWindowOuter::FindOuter(cons
   aError = finder->FindNext(&didFind);
   return didFind;
 }
 
 //*****************************************************************************
 // EventTarget
 //*****************************************************************************
 
-nsPIDOMWindowOuter* nsGlobalWindowOuter::GetOwnerGlobalForBindings() {
+nsPIDOMWindowOuter* nsGlobalWindowOuter::GetOwnerGlobalForBindingsInternal() {
   return this;
 }
 
 bool nsGlobalWindowOuter::DispatchEvent(Event& aEvent, CallerType aCallerType,
                                         ErrorResult& aRv) {
   FORWARD_TO_INNER(DispatchEvent, (aEvent, aCallerType, aRv), false);
 }
 
--- a/dom/base/nsGlobalWindowOuter.h
+++ b/dom/base/nsGlobalWindowOuter.h
@@ -266,17 +266,17 @@ class nsGlobalWindowOuter final : public
 
   virtual mozilla::EventListenerManager* GetExistingListenerManager()
       const override;
 
   virtual mozilla::EventListenerManager* GetOrCreateListenerManager() override;
 
   bool ComputeDefaultWantsUntrusted(mozilla::ErrorResult& aRv) final;
 
-  virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindings() override;
+  virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindingsInternal() override;
 
   virtual nsIGlobalObject* GetOwnerGlobal() const override;
 
   EventTarget* GetTargetForEventTargetChain() override;
 
   using mozilla::dom::EventTarget::DispatchEvent;
   bool DispatchEvent(mozilla::dom::Event& aEvent,
                      mozilla::dom::CallerType aCallerType,
@@ -524,39 +524,38 @@ class nsGlobalWindowOuter final : public
   bool Closed() override;
   void StopOuter(mozilla::ErrorResult& aError);
   void FocusOuter(mozilla::ErrorResult& aError);
   nsresult Focus() override;
   void BlurOuter();
   already_AddRefed<nsPIDOMWindowOuter> GetFramesOuter();
   nsDOMWindowList* GetFrames() final;
   uint32_t Length();
-  already_AddRefed<nsPIDOMWindowOuter> GetTopOuter();
+  mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetTopOuter();
 
   nsresult GetPrompter(nsIPrompt** aPrompt) override;
 
  protected:
   nsPIDOMWindowOuter* GetOpenerWindowOuter();
   // Initializes the mWasOffline member variable
   void InitWasOffline();
 
  public:
   nsPIDOMWindowOuter* GetSanitizedOpener(nsPIDOMWindowOuter* aOpener);
 
   already_AddRefed<nsPIDOMWindowOuter> GetOpener() override;
-  already_AddRefed<nsPIDOMWindowOuter> GetParentOuter();
+  mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetParentOuter();
   already_AddRefed<nsPIDOMWindowOuter> GetParent() override;
   nsPIDOMWindowOuter* GetScriptableParent() override;
   nsPIDOMWindowOuter* GetScriptableParentOrNull() override;
   mozilla::dom::Element* GetFrameElementOuter(nsIPrincipal& aSubjectPrincipal);
   mozilla::dom::Element* GetFrameElement() override;
-  already_AddRefed<nsPIDOMWindowOuter> OpenOuter(const nsAString& aUrl,
-                                                 const nsAString& aName,
-                                                 const nsAString& aOptions,
-                                                 mozilla::ErrorResult& aError);
+  mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> OpenOuter(
+      const nsAString& aUrl, const nsAString& aName, const nsAString& aOptions,
+      mozilla::ErrorResult& aError);
   nsresult Open(const nsAString& aUrl, const nsAString& aName,
                 const nsAString& aOptions, nsDocShellLoadState* aLoadState,
                 bool aForceNoOpener, nsPIDOMWindowOuter** _retval) override;
   mozilla::dom::Navigator* GetNavigator() override;
 
 #if defined(MOZ_WIDGET_ANDROID)
   int16_t Orientation(mozilla::dom::CallerType aCallerType) const;
 #endif
@@ -610,17 +609,17 @@ class nsGlobalWindowOuter final : public
   nsresult SetFullScreen(bool aFullscreen) override;
   bool FindOuter(const nsAString& aString, bool aCaseSensitive, bool aBackwards,
                  bool aWrapAround, bool aWholeWord, bool aSearchInFrames,
                  bool aShowDialog, mozilla::ErrorResult& aError);
   uint64_t GetMozPaintCountOuter();
 
   bool ShouldResistFingerprinting();
 
-  already_AddRefed<nsPIDOMWindowOuter> OpenDialogOuter(
+  mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> OpenDialogOuter(
       JSContext* aCx, const nsAString& aUrl, const nsAString& aName,
       const nsAString& aOptions,
       const mozilla::dom::Sequence<JS::Value>& aExtraArgument,
       mozilla::ErrorResult& aError);
   nsresult OpenDialog(const nsAString& aUrl, const nsAString& aName,
                       const nsAString& aOptions, nsISupports* aExtraArgument,
                       nsPIDOMWindowOuter** _retval) override;
   void UpdateCommands(const nsAString& anAction, mozilla::dom::Selection* aSel,
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -3072,17 +3072,18 @@ class nsIDocument : public nsINode,
   nsIHTMLCollection* Plugins() { return Embeds(); }
   nsIHTMLCollection* Links();
   nsIHTMLCollection* Forms();
   nsIHTMLCollection* Scripts();
   already_AddRefed<nsContentList> GetElementsByName(const nsAString& aName) {
     return GetFuncStringContentList<nsCachableElementsByNameNodeList>(
         this, MatchNameAttribute, nullptr, UseExistingNameString, aName);
   }
-  nsPIDOMWindowOuter* GetDefaultView() const { return GetWindow(); }
+  mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetDefaultView()
+      const;
   Element* GetActiveElement();
   bool HasFocus(mozilla::ErrorResult& rv) const;
   nsIHTMLCollection* Applets();
   nsIHTMLCollection* Anchors();
   mozilla::TimeStamp LastFocusTime() const;
   void SetLastFocusTime(const mozilla::TimeStamp& aFocusTime);
   // Event handlers are all on nsINode already
   bool MozSyntheticDocument() const { return IsSyntheticDocument(); }
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -1042,17 +1042,17 @@ nsresult nsINode::PostHandleEvent(EventC
 EventListenerManager* nsINode::GetOrCreateListenerManager() {
   return nsContentUtils::GetListenerManagerForNode(this);
 }
 
 EventListenerManager* nsINode::GetExistingListenerManager() const {
   return nsContentUtils::GetExistingListenerManagerForNode(this);
 }
 
-nsPIDOMWindowOuter* nsINode::GetOwnerGlobalForBindings() {
+nsPIDOMWindowOuter* nsINode::GetOwnerGlobalForBindingsInternal() {
   bool dummy;
   auto* window = static_cast<nsGlobalWindowInner*>(
       OwnerDoc()->GetScriptHandlingObject(dummy));
   return window ? nsPIDOMWindowOuter::GetFromCurrentInner(window->AsInner())
                 : nullptr;
 }
 
 nsIGlobalObject* nsINode::GetOwnerGlobal() const {
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -939,17 +939,17 @@ class nsINode : public mozilla::dom::Eve
   virtual mozilla::EventListenerManager* GetExistingListenerManager()
       const override;
   virtual mozilla::EventListenerManager* GetOrCreateListenerManager() override;
 
   bool ComputeDefaultWantsUntrusted(mozilla::ErrorResult& aRv) final;
 
   virtual bool IsApzAware() const override;
 
-  virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindings() override;
+  virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindingsInternal() override;
   virtual nsIGlobalObject* GetOwnerGlobal() const override;
 
   using mozilla::dom::EventTarget::DispatchEvent;
   bool DispatchEvent(mozilla::dom::Event& aEvent,
                      mozilla::dom::CallerType aCallerType,
                      mozilla::ErrorResult& aRv) override;
 
   nsresult PostHandleEvent(mozilla::EventChainPostVisitor& aVisitor) override;
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -1072,18 +1072,18 @@ nsObjectLoadingContent::OnDataAvailable(
 
 // nsIFrameLoaderOwner
 NS_IMETHODIMP_(already_AddRefed<nsFrameLoader>)
 nsObjectLoadingContent::GetFrameLoader() {
   RefPtr<nsFrameLoader> loader = mFrameLoader;
   return loader.forget();
 }
 
-void nsObjectLoadingContent::PresetOpenerWindow(mozIDOMWindowProxy* aWindow,
-                                                mozilla::ErrorResult& aRv) {
+void nsObjectLoadingContent::PresetOpenerWindow(
+    const Nullable<WindowProxyHolder>& aOpenerWindow, ErrorResult& aRv) {
   aRv.Throw(NS_ERROR_FAILURE);
 }
 
 void nsObjectLoadingContent::InternalSetFrameLoader(
     nsFrameLoader* aNewFrameLoader) {
   MOZ_CRASH(
       "You shouldn't be calling this function, it doesn't make any sense on "
       "this type.");
--- a/dom/base/nsObjectLoadingContent.h
+++ b/dom/base/nsObjectLoadingContent.h
@@ -34,16 +34,19 @@ class nsPluginFrame;
 class nsPluginInstanceOwner;
 
 namespace mozilla {
 namespace dom {
 template <typename T>
 class Sequence;
 struct MozPluginParameter;
 class HTMLIFrameElement;
+template <typename T>
+struct Nullable;
+class WindowProxyHolder;
 class XULFrameElement;
 }  // namespace dom
 }  // namespace mozilla
 
 class nsObjectLoadingContent : public nsImageLoadingContent,
                                public nsIStreamListener,
                                public nsIFrameLoaderOwner,
                                public nsIObjectLoadingContent,
@@ -230,17 +233,18 @@ class nsObjectLoadingContent : public ns
                   JS::MutableHandle<JS::Value> aRetval,
                   mozilla::ErrorResult& aRv);
 
   uint32_t GetRunID(mozilla::dom::SystemCallerGuarantee,
                     mozilla::ErrorResult& aRv);
 
   bool IsRewrittenYoutubeEmbed() const { return mRewrittenYoutubeEmbed; }
 
-  void PresetOpenerWindow(mozIDOMWindowProxy* aOpenerWindow,
+  void PresetOpenerWindow(const mozilla::dom::Nullable<
+                              mozilla::dom::WindowProxyHolder>& aOpenerWindow,
                           mozilla::ErrorResult& aRv);
 
  protected:
   /**
    * Begins loading the object when called
    *
    * Attributes of |this| QI'd to nsIContent will be inspected, depending on
    * the node type. This function currently assumes it is a <object> or
--- a/dom/base/nsWindowRoot.cpp
+++ b/dom/base/nsWindowRoot.cpp
@@ -101,17 +101,17 @@ void nsWindowRoot::GetEventTargetParent(
   aVisitor.mItemData = static_cast<nsISupports*>(mWindow);
   aVisitor.SetParentTarget(mParent, false);
 }
 
 nsresult nsWindowRoot::PostHandleEvent(EventChainPostVisitor& aVisitor) {
   return NS_OK;
 }
 
-nsPIDOMWindowOuter* nsWindowRoot::GetOwnerGlobalForBindings() {
+nsPIDOMWindowOuter* nsWindowRoot::GetOwnerGlobalForBindingsInternal() {
   return GetWindow();
 }
 
 nsIGlobalObject* nsWindowRoot::GetOwnerGlobal() const {
   nsCOMPtr<nsIGlobalObject> global =
       do_QueryInterface(mWindow->GetCurrentInnerWindow());
   // We're still holding a ref to it, so returning the raw pointer is ok...
   return global;
--- a/dom/base/nsWindowRoot.h
+++ b/dom/base/nsWindowRoot.h
@@ -55,17 +55,17 @@ class nsWindowRoot final : public nsPIWi
   virtual void SetPopupNode(nsINode* aNode) override;
 
   virtual void SetParentTarget(mozilla::dom::EventTarget* aTarget) override {
     mParent = aTarget;
   }
   virtual mozilla::dom::EventTarget* GetParentTarget() override {
     return mParent;
   }
-  virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindings() override;
+  virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindingsInternal() override;
   virtual nsIGlobalObject* GetOwnerGlobal() const override;
 
   nsIGlobalObject* GetParentObject();
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsWindowRoot)
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1121,16 +1121,21 @@ bool VariantToJsval(JSContext* aCx, nsIV
       Throw(aCx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
     }
     return false;
   }
 
   return true;
 }
 
+bool WrapObject(JSContext* cx, const WindowProxyHolder& p,
+                JS::MutableHandle<JS::Value> rval) {
+  return ToJSValue(cx, p.get(), rval);
+}
+
 static int CompareIdsAtIndices(const void* aElement1, const void* aElement2,
                                void* aClosure) {
   const uint16_t index1 = *static_cast<const uint16_t*>(aElement1);
   const uint16_t index2 = *static_cast<const uint16_t*>(aElement2);
   const PropertyInfo* infos = static_cast<PropertyInfo*>(aClosure);
 
   MOZ_ASSERT(JSID_BITS(infos[index1].Id()) != JSID_BITS(infos[index2].Id()));
 
@@ -3218,24 +3223,24 @@ nsresult UnwrapArgImpl(JSContext* cx, JS
 
   // We need to go through the QueryInterface logic to make this return
   // the right thing for the various 'special' interfaces; e.g.
   // nsIPropertyBag. We must use AggregatedQueryInterface in cases where
   // there is an outer to avoid nasty recursion.
   return wrappedJS->QueryInterface(iid, ppArg);
 }
 
-nsresult UnwrapWindowProxyImpl(JSContext* cx, JS::Handle<JSObject*> src,
-                               nsPIDOMWindowOuter** ppArg) {
+nsresult UnwrapWindowProxyArg(JSContext* cx, JS::Handle<JSObject*> src,
+                              WindowProxyHolder& ppArg) {
   nsCOMPtr<nsPIDOMWindowInner> inner;
   nsresult rv = UnwrapArg<nsPIDOMWindowInner>(cx, src, getter_AddRefs(inner));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsPIDOMWindowOuter> outer = inner->GetOuterWindow();
-  outer.forget(ppArg);
+  ppArg = outer.forget();
   return NS_OK;
 }
 
 template <decltype(JS::NewMapObject) Method>
 bool GetMaplikeSetlikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
                                     size_t aSlotIndex,
                                     JS::MutableHandle<JSObject*> aBackingObj,
                                     bool* aBackingObjCreated) {
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -49,38 +49,32 @@ namespace mozilla {
 
 enum UseCounter : int16_t;
 
 namespace dom {
 class CustomElementReactionsStack;
 class MessageManagerGlobal;
 template <typename KeyType, typename ValueType>
 class Record;
+class WindowProxyHolder;
 
 nsresult UnwrapArgImpl(JSContext* cx, JS::Handle<JSObject*> src,
                        const nsIID& iid, void** ppArg);
 
-nsresult UnwrapWindowProxyImpl(JSContext* cx, JS::Handle<JSObject*> src,
-                               nsPIDOMWindowOuter** ppArg);
-
 /** Convert a jsval to an XPCOM pointer. Caller must not assume that src will
     keep the XPCOM pointer rooted. */
 template <class Interface>
 inline nsresult UnwrapArg(JSContext* cx, JS::Handle<JSObject*> src,
                           Interface** ppArg) {
   return UnwrapArgImpl(cx, src, NS_GET_TEMPLATE_IID(Interface),
                        reinterpret_cast<void**>(ppArg));
 }
 
-template <>
-inline nsresult UnwrapArg<nsPIDOMWindowOuter>(JSContext* cx,
-                                              JS::Handle<JSObject*> src,
-                                              nsPIDOMWindowOuter** ppArg) {
-  return UnwrapWindowProxyImpl(cx, src, ppArg);
-}
+nsresult UnwrapWindowProxyArg(JSContext* cx, JS::Handle<JSObject*> src,
+                              WindowProxyHolder& ppArg);
 
 bool ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
                       bool aSecurityError, const char* aInterfaceName);
 
 bool ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
                       bool aSecurityError, prototypes::ID aProtoId);
 
 // Returns true if the JSClass is used for DOM objects.
@@ -1419,16 +1413,19 @@ inline bool WrapObject<JSObject>(JSConte
 }
 
 inline bool WrapObject(JSContext* cx, JSObject& p,
                        JS::MutableHandle<JS::Value> rval) {
   rval.set(JS::ObjectValue(p));
   return true;
 }
 
+bool WrapObject(JSContext* cx, const WindowProxyHolder& p,
+                JS::MutableHandle<JS::Value> rval);
+
 // Given an object "p" that inherits from nsISupports, wrap it and return the
 // result.  Null is returned on wrapping failure.  This is somewhat similar to
 // WrapObject() above, but does NOT allow Xrays around the result, since we
 // don't want those for our parent object.
 template <typename T>
 static inline JSObject* WrapNativeISupports(JSContext* cx, T* p,
                                             nsWrapperCache* cache) {
   xpcObjectHelper helper(ToSupports(p), cache);
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1482,18 +1482,17 @@ DOMInterfaces = {
     },
     'implicitJSContext': [
         'createImageBitmap',
         'requestIdleCallback'
     ],
 },
 
 'WindowProxy': {
-    'nativeType': 'nsPIDOMWindowOuter',
-    'headerFile': 'nsPIDOMWindow.h',
+    'nativeType': 'mozilla::dom::WindowProxyHolder',
     'concrete': False
 },
 
 'WindowRoot': {
     'nativeType': 'nsWindowRoot'
 },
 
 'WorkerDebuggerGlobalScope': {
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1383,16 +1383,21 @@ def UnionTypes(unionTypes, config):
                             # Callback interfaces always use strong refs, so
                             # we need to include the right header to be able
                             # to Release() in our inlined code.
                             #
                             # Similarly, sequences always contain strong
                             # refs, so we'll need the header to handler
                             # those.
                             headers.add(typeDesc.headerFile)
+                        elif typeDesc.interface.identifier.name == "WindowProxy":
+                            # In UnionTypes.h we need to see the declaration of the
+                            # WindowProxyHolder that we use to store the WindowProxy, so
+                            # we have its sizeof and know how big to make our union.
+                            headers.add(typeDesc.headerFile)
                         else:
                             declarations.add((typeDesc.nativeType, False))
                             implheaders.add(typeDesc.headerFile)
                 elif f.isDictionary():
                     # For a dictionary, we need to see its declaration in
                     # UnionTypes.h so we have its sizeof and know how big to
                     # make our union.
                     headers.add(CGHeaders.getDeclarationFilename(f.inner))
@@ -5486,16 +5491,38 @@ def getJSToNativeConversionInfo(type, de
                                                      isOptional)
             template = wrapObjectTemplate(conversion, type,
                                           "${declName} = nullptr;\n",
                                           failureCode)
             return JSToNativeConversionInfo(template, declType=declType,
                                             declArgs=declArgs,
                                             dealWithOptional=isOptional)
 
+        if descriptor.interface.identifier.name == "WindowProxy":
+            declType = CGGeneric("mozilla::dom::WindowProxyHolder")
+            if type.nullable():
+                declType = CGTemplatedType("Nullable", declType)
+                windowProxyHolderRef = "${declName}.SetValue()"
+            else:
+                windowProxyHolderRef = "${declName}"
+
+            failureCode = onFailureBadType(failureCode, descriptor.interface.identifier.name).define()
+            templateBody = fill("""
+                JS::Rooted<JSObject*> source(cx, &$${val}.toObject());
+                if (NS_FAILED(UnwrapWindowProxyArg(cx, source, ${windowProxyHolderRef}))) {
+                    $*{onFailure}
+                }
+                """,
+                windowProxyHolderRef=windowProxyHolderRef,
+                onFailure=failureCode)
+            templateBody = wrapObjectTemplate(templateBody, type,
+                                              "${declName}.SetNull();\n", failureCode)
+            return JSToNativeConversionInfo(templateBody, declType=declType,
+                                            dealWithOptional=isOptional)
+
         # This is an interface that we implement as a concrete class
         # or an XPCOM interface.
 
         # Allow null pointers for nullable types and old-binding classes, and
         # use an RefPtr or raw pointer for callback return values to make
         # them easier to return.
         argIsPointer = (type.nullable() or type.unroll().inner.isExternal() or
                         isCallbackReturnValue)
@@ -6670,16 +6697,26 @@ def getWrapTemplateForType(type, descrip
         # the various RefPtr, rawptr, NonNull, etc cases, which ToJSValue will
         # handle for us.  So just eat the cost of the function call.
         return (wrapAndSetPtr("ToJSValue(cx, %s, ${jsvalHandle})" % result),
                 False)
 
     if type.isGeckoInterface() and not type.isCallbackInterface():
         descriptor = descriptorProvider.getDescriptor(type.unroll().inner.identifier.name)
         if type.nullable():
+            if descriptor.interface.identifier.name == "WindowProxy":
+                template, infal = getWrapTemplateForType(type.inner, descriptorProvider,
+                                                         "%s.Value()" % result, successCode,
+                                                         returnsNewObject, exceptionCode,
+                                                         spiderMonkeyInterfacesAreStructs)
+                return ("if (%s.IsNull()) {\n" % result +
+                        indent(setNull()) +
+                        "}\n" +
+                        template, infal)
+
             wrappingCode = ("if (!%s) {\n" % (result) +
                             indent(setNull()) +
                             "}\n")
         else:
             wrappingCode = ""
 
         if not descriptor.interface.isExternal():
             if descriptor.wrapperCache:
@@ -6991,18 +7028,24 @@ def getRetvalDeclarationForType(returnTy
         return CGGeneric("nsCString"), "ref", None, None, None
     if returnType.isEnum():
         result = CGGeneric(returnType.unroll().inner.identifier.name)
         if returnType.nullable():
             result = CGTemplatedType("Nullable", result)
         return result, None, None, None, None
     if returnType.isGeckoInterface() or returnType.isPromise():
         if returnType.isGeckoInterface():
-            typeName = descriptorProvider.getDescriptor(
-                returnType.unroll().inner.identifier.name).nativeType
+            typeName = returnType.unroll().inner.identifier.name
+            if typeName == "WindowProxy":
+                result = CGGeneric("WindowProxyHolder")
+                if returnType.nullable():
+                    result = CGTemplatedType("Nullable", result)
+                return result, None, None, None, None
+
+            typeName = descriptorProvider.getDescriptor(typeName).nativeType
         else:
             typeName = "Promise"
         if isMember:
             conversion = None
             result = CGGeneric("StrongPtrForMember<%s>::Type" % typeName)
         else:
             conversion = CGGeneric("StrongOrRawPtr<%s>" % typeName)
             result = CGGeneric("auto")
@@ -9829,21 +9872,23 @@ def getUnionAccessorSignatureType(type, 
 
     # Nested unions are unwrapped automatically into our flatMemberTypes.
     assert not type.isUnion()
 
     if type.isGeckoInterface():
         descriptor = descriptorProvider.getDescriptor(
             type.unroll().inner.identifier.name)
         typeName = CGGeneric(descriptor.nativeType)
-        # Allow null pointers for old-binding classes.
-        if type.unroll().inner.isExternal():
+        if not type.unroll().inner.isExternal():
+            typeName = CGWrapper(typeName, post="&")
+        elif descriptor.interface.identifier.name == "WindowProxy":
+            typeName = CGGeneric("WindowProxyHolder const&")
+        else:
+            # Allow null pointers for old-binding classes.
             typeName = CGWrapper(typeName, post="*")
-        else:
-            typeName = CGWrapper(typeName, post="&")
         return typeName
 
     if type.isSpiderMonkeyInterface():
         typeName = CGGeneric(type.name)
         return CGWrapper(typeName, post=" const &")
 
     if type.isDOMString() or type.isUSVString():
         return CGGeneric("const nsAString&")
@@ -14471,16 +14516,19 @@ class CGNativeMember(ClassMethod):
             if optional or isMember:
                 typeDecl = "OwningNonNull<Promise>"
             else:
                 typeDecl = "Promise&"
             return (typeDecl, False, False)
 
         if type.isGeckoInterface() and not type.isCallbackInterface():
             iface = type.unroll().inner
+            if iface.identifier.name == "WindowProxy":
+                return "WindowProxyHolder", True, False
+
             argIsPointer = type.nullable() or iface.isExternal()
             forceOwningType = (iface.isCallback() or isMember)
             if argIsPointer:
                 if (optional or isMember) and forceOwningType:
                     typeDecl = "RefPtr<%s>"
                 else:
                     typeDecl = "%s*"
             else:
--- a/dom/browser-element/BrowserElementParent.cpp
+++ b/dom/browser-element/BrowserElementParent.cpp
@@ -13,16 +13,17 @@
 #ifdef CreateEvent
 #undef CreateEvent
 #endif
 
 #include "BrowserElementParent.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/dom/HTMLIFrameElement.h"
 #include "mozilla/dom/ToJSValue.h"
+#include "mozilla/dom/WindowProxyHolder.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsVariant.h"
 #include "mozilla/dom/BrowserElementDictionariesBinding.h"
 #include "mozilla/dom/CustomEvent.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::layers;
@@ -229,17 +230,18 @@ BrowserElementParent::OpenWindowInProces
 
   nsAutoCString spec;
   if (aURI) {
     aURI->GetSpec(spec);
   }
 
   if (!aForceNoOpener) {
     ErrorResult res;
-    popupFrameElement->PresetOpenerWindow(aOpenerWindow, res);
+    popupFrameElement->PresetOpenerWindow(WindowProxyHolder(aOpenerWindow),
+                                          res);
     MOZ_ASSERT(!res.Failed());
   }
 
   OpenWindowResult opened = DispatchOpenWindowEvent(
       openerFrameElement, popupFrameElement, NS_ConvertUTF8toUTF16(spec), aName,
       NS_ConvertUTF8toUTF16(aFeatures));
 
   if (opened != BrowserElementParent::OPEN_WINDOW_ADDED) {
--- a/dom/events/DOMEventTargetHelper.h
+++ b/dom/events/DOMEventTargetHelper.h
@@ -123,17 +123,17 @@ class DOMEventTargetHelper : public dom:
   bool HasListenersFor(const nsAString& aType) const {
     return mListenerManager && mListenerManager->HasListenersFor(aType);
   }
 
   bool HasListenersFor(nsAtom* aTypeWithOn) const {
     return mListenerManager && mListenerManager->HasListenersFor(aTypeWithOn);
   }
 
-  virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindings() override {
+  virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindingsInternal() override {
     return nsPIDOMWindowOuter::GetFromCurrentInner(GetOwner());
   }
 
   nsresult CheckInnerWindowCorrectness() const {
     NS_ENSURE_STATE(!mHasOrHasHadOwnerWindow || mOwnerWindow);
     if (mOwnerWindow && !mOwnerWindow->IsCurrentInnerWindow()) {
       return NS_ERROR_FAILURE;
     }
--- a/dom/events/EventTarget.cpp
+++ b/dom/events/EventTarget.cpp
@@ -3,16 +3,18 @@
 /* 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/EventListenerManager.h"
 #include "mozilla/dom/EventTarget.h"
 #include "mozilla/dom/EventTargetBinding.h"
 #include "mozilla/dom/ConstructibleEventTarget.h"
+#include "mozilla/dom/Nullable.h"
+#include "mozilla/dom/WindowProxyHolder.h"
 #include "nsIGlobalObject.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 /* static */
 already_AddRefed<EventTarget> EventTarget::Constructor(
@@ -177,10 +179,19 @@ void EventTarget::DispatchEvent(Event& a
 }
 
 void EventTarget::DispatchEvent(Event& aEvent, ErrorResult& aRv) {
   // The caller type doesn't really matter if we don't care about the
   // return value, but let's be safe and pass NonSystem.
   Unused << DispatchEvent(aEvent, CallerType::NonSystem, IgnoreErrors());
 }
 
+Nullable<WindowProxyHolder> EventTarget::GetOwnerGlobalForBindings() {
+  nsPIDOMWindowOuter* win = GetOwnerGlobalForBindingsInternal();
+  if (!win) {
+    return nullptr;
+  }
+
+  return WindowProxyHolder(win);
+}
+
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/events/EventTarget.h
+++ b/dom/events/EventTarget.h
@@ -29,16 +29,19 @@ class EventListenerManager;
 namespace dom {
 
 class AddEventListenerOptionsOrBoolean;
 class Event;
 class EventListener;
 class EventListenerOptionsOrBoolean;
 class EventHandlerNonNull;
 class GlobalObject;
+template <typename>
+struct Nullable;
+class WindowProxyHolder;
 
 // IID for the dom::EventTarget interface
 #define NS_EVENTTARGET_IID                           \
   {                                                  \
     0xde651c36, 0x0053, 0x4c67, {                    \
       0xb1, 0x3d, 0x67, 0xb9, 0x40, 0xfc, 0x82, 0xe4 \
     }                                                \
   }
@@ -170,17 +173,18 @@ class EventTarget : public nsISupports, 
   virtual void EventListenerAdded(nsAtom* aType) {}
 
   // For an event 'foo' aType will be 'onfoo'.
   virtual void EventListenerRemoved(nsAtom* aType) {}
 
   // Returns an outer window that corresponds to the inner window this event
   // target is associated with.  Will return null if the inner window is not the
   // current inner or if there is no window around at all.
-  virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindings() = 0;
+  Nullable<WindowProxyHolder> GetOwnerGlobalForBindings();
+  virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindingsInternal() = 0;
 
   // The global object this event target is associated with, if any.
   // This may be an inner window or some other global object.  This
   // will never be an outer window.
   virtual nsIGlobalObject* GetOwnerGlobal() const = 0;
 
   /**
    * Get the event listener manager, creating it if it does not already exist.
--- a/dom/events/MessageEvent.cpp
+++ b/dom/events/MessageEvent.cpp
@@ -103,17 +103,17 @@ void MessageEvent::GetSource(
 
   mozilla::HoldJSObjects(event.get());
 
   event->mOrigin = aParam.mOrigin;
   event->mLastEventId = aParam.mLastEventId;
 
   if (!aParam.mSource.IsNull()) {
     if (aParam.mSource.Value().IsWindowProxy()) {
-      event->mWindowSource = aParam.mSource.Value().GetAsWindowProxy();
+      event->mWindowSource = aParam.mSource.Value().GetAsWindowProxy().get();
     } else if (aParam.mSource.Value().IsMessagePort()) {
       event->mPortSource = aParam.mSource.Value().GetAsMessagePort();
     } else {
       event->mServiceWorkerSource = aParam.mSource.Value().GetAsServiceWorker();
     }
 
     MOZ_ASSERT(event->mWindowSource || event->mPortSource ||
                event->mServiceWorkerSource);
@@ -139,17 +139,17 @@ void MessageEvent::InitMessageEvent(
   mLastEventId = aLastEventId;
 
   mWindowSource = nullptr;
   mPortSource = nullptr;
   mServiceWorkerSource = nullptr;
 
   if (!aSource.IsNull()) {
     if (aSource.Value().IsWindowProxy()) {
-      mWindowSource = aSource.Value().GetAsWindowProxy();
+      mWindowSource = aSource.Value().GetAsWindowProxy().get();
     } else if (aSource.Value().IsMessagePort()) {
       mPortSource = &aSource.Value().GetAsMessagePort();
     } else {
       mServiceWorkerSource = &aSource.Value().GetAsServiceWorker();
     }
   }
 
   mPorts.Clear();
--- a/dom/events/UIEvent.h
+++ b/dom/events/UIEvent.h
@@ -4,17 +4,19 @@
  * 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_UIEvent_h_
 #define mozilla_dom_UIEvent_h_
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/Event.h"
+#include "mozilla/dom/Nullable.h"
 #include "mozilla/dom/UIEventBinding.h"
+#include "mozilla/dom/WindowProxyHolder.h"
 #include "nsDeviceContext.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 
 class nsINode;
 
 namespace mozilla {
 namespace dom {
@@ -42,17 +44,22 @@ class UIEvent : public Event {
   }
 
   UIEvent* AsUIEvent() override { return this; }
 
   void InitUIEvent(const nsAString& typeArg, bool canBubbleArg,
                    bool cancelableArg, nsGlobalWindowInner* viewArg,
                    int32_t detailArg);
 
-  nsPIDOMWindowOuter* GetView() const { return mView; }
+  Nullable<WindowProxyHolder> GetView() const {
+    if (!mView) {
+      return nullptr;
+    }
+    return WindowProxyHolder(mView);
+  }
 
   int32_t Detail() const { return mDetail; }
 
   int32_t LayerX() const { return GetLayerPoint().x; }
 
   int32_t LayerY() const { return GetLayerPoint().y; }
 
   int32_t PageX() const;
--- a/dom/html/HTMLObjectElement.cpp
+++ b/dom/html/HTMLObjectElement.cpp
@@ -369,21 +369,24 @@ HTMLObjectElement::SubmitNamesValues(HTM
 
   return aFormSubmission->AddNameValuePair(name, value);
 }
 
 int32_t HTMLObjectElement::TabIndexDefault() {
   return IsFocusableForTabIndex() ? 0 : -1;
 }
 
-nsPIDOMWindowOuter* HTMLObjectElement::GetContentWindow(
+Nullable<WindowProxyHolder> HTMLObjectElement::GetContentWindow(
     nsIPrincipal& aSubjectPrincipal) {
   nsIDocument* doc = GetContentDocument(aSubjectPrincipal);
   if (doc) {
-    return doc->GetWindow();
+    nsPIDOMWindowOuter* win = doc->GetWindow();
+    if (win) {
+      return WindowProxyHolder(win);
+    }
   }
 
   return nullptr;
 }
 
 bool HTMLObjectElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
                                        const nsAString& aValue,
                                        nsIPrincipal* aMaybeScriptedPrincipal,
--- a/dom/html/HTMLObjectElement.h
+++ b/dom/html/HTMLObjectElement.h
@@ -11,16 +11,19 @@
 #include "nsGenericHTMLElement.h"
 #include "nsObjectLoadingContent.h"
 #include "nsIConstraintValidation.h"
 
 namespace mozilla {
 namespace dom {
 
 class HTMLFormSubmission;
+template <typename T>
+struct Nullable;
+class WindowProxyHolder;
 
 class HTMLObjectElement final : public nsGenericHTMLFormElement,
                                 public nsObjectLoadingContent,
                                 public nsIConstraintValidation {
  public:
   explicit HTMLObjectElement(
       already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
       FromParser aFromParser = NOT_FROM_PARSER);
@@ -116,17 +119,17 @@ class HTMLObjectElement final : public n
     SetHTMLAttr(nsGkAtoms::width, aValue, aRv);
   }
   void GetHeight(DOMString& aValue) { GetHTMLAttr(nsGkAtoms::height, aValue); }
   void SetHeight(const nsAString& aValue, ErrorResult& aRv) {
     SetHTMLAttr(nsGkAtoms::height, aValue, aRv);
   }
   using nsObjectLoadingContent::GetContentDocument;
 
-  nsPIDOMWindowOuter* GetContentWindow(nsIPrincipal& aSubjectPrincipal);
+  Nullable<WindowProxyHolder> GetContentWindow(nsIPrincipal& aSubjectPrincipal);
 
   using nsIConstraintValidation::GetValidationMessage;
   using nsIConstraintValidation::SetCustomValidity;
   void GetAlign(DOMString& aValue) { GetHTMLAttr(nsGkAtoms::align, aValue); }
   void SetAlign(const nsAString& aValue, ErrorResult& aRv) {
     SetHTMLAttr(nsGkAtoms::align, aValue, aRv);
   }
   void GetArchive(DOMString& aValue) {
--- a/dom/html/nsGenericHTMLFrameElement.cpp
+++ b/dom/html/nsGenericHTMLFrameElement.cpp
@@ -66,17 +66,17 @@ int32_t nsGenericHTMLFrameElement::TabIn
 nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement() {
   if (mFrameLoader) {
     mFrameLoader->Destroy();
   }
 }
 
 nsIDocument* nsGenericHTMLFrameElement::GetContentDocument(
     nsIPrincipal& aSubjectPrincipal) {
-  nsCOMPtr<nsPIDOMWindowOuter> win = GetContentWindow();
+  nsCOMPtr<nsPIDOMWindowOuter> win = GetContentWindowInternal();
   if (!win) {
     return nullptr;
   }
 
   nsIDocument* doc = win->GetDoc();
   if (!doc) {
     return nullptr;
   }
@@ -84,17 +84,17 @@ nsIDocument* nsGenericHTMLFrameElement::
   // Return null for cross-origin contentDocument.
   if (!aSubjectPrincipal.SubsumesConsideringDomain(doc->NodePrincipal())) {
     return nullptr;
   }
   return doc;
 }
 
 already_AddRefed<nsPIDOMWindowOuter>
-nsGenericHTMLFrameElement::GetContentWindow() {
+nsGenericHTMLFrameElement::GetContentWindowInternal() {
   EnsureFrameLoader();
 
   if (!mFrameLoader) {
     return nullptr;
   }
 
   if (mFrameLoader->DepthTooGreat()) {
     // Claim to have no contentWindow
@@ -102,22 +102,25 @@ nsGenericHTMLFrameElement::GetContentWin
   }
 
   nsCOMPtr<nsIDocShell> doc_shell = mFrameLoader->GetDocShell(IgnoreErrors());
   if (!doc_shell) {
     return nullptr;
   }
 
   nsCOMPtr<nsPIDOMWindowOuter> win = doc_shell->GetWindow();
+  return win.forget();
+}
 
+Nullable<WindowProxyHolder> nsGenericHTMLFrameElement::GetContentWindow() {
+  nsCOMPtr<nsPIDOMWindowOuter> win = GetContentWindowInternal();
   if (!win) {
     return nullptr;
   }
-
-  return win.forget();
+  return WindowProxyHolder(win.forget());
 }
 
 void nsGenericHTMLFrameElement::EnsureFrameLoader() {
   if (!IsInComposedDoc() || mFrameLoader || mFrameLoaderCreationDisallowed) {
     // If frame loader is there, we just keep it around, cached
     return;
   }
 
@@ -145,20 +148,21 @@ nsresult nsGenericHTMLFrameElement::Crea
 }
 
 NS_IMETHODIMP_(already_AddRefed<nsFrameLoader>)
 nsGenericHTMLFrameElement::GetFrameLoader() {
   RefPtr<nsFrameLoader> loader = mFrameLoader;
   return loader.forget();
 }
 
-void nsGenericHTMLFrameElement::PresetOpenerWindow(mozIDOMWindowProxy* aWindow,
-                                                   ErrorResult& aRv) {
+void nsGenericHTMLFrameElement::PresetOpenerWindow(
+    const Nullable<WindowProxyHolder>& aOpenerWindow, ErrorResult& aRv) {
   MOZ_ASSERT(!mFrameLoader);
-  mOpenerWindow = nsPIDOMWindowOuter::From(aWindow);
+  mOpenerWindow =
+      aOpenerWindow.IsNull() ? nullptr : aOpenerWindow.Value().get();
 }
 
 void nsGenericHTMLFrameElement::InternalSetFrameLoader(
     nsFrameLoader* aNewFrameLoader) {
   mFrameLoader = aNewFrameLoader;
 }
 
 void nsGenericHTMLFrameElement::SwapFrameLoaders(
--- a/dom/html/nsGenericHTMLFrameElement.h
+++ b/dom/html/nsGenericHTMLFrameElement.h
@@ -14,18 +14,21 @@
 #include "nsFrameLoader.h"
 #include "nsGenericHTMLElement.h"
 #include "nsIDOMEventListener.h"
 #include "nsIFrameLoaderOwner.h"
 #include "nsIMozBrowserFrame.h"
 
 namespace mozilla {
 namespace dom {
+template <typename>
+struct Nullable;
+class WindowProxyHolder;
 class XULFrameElement;
-}
+}  // namespace dom
 }  // namespace mozilla
 
 #define NS_GENERICHTMLFRAMEELEMENT_IID               \
   {                                                  \
     0x8190db72, 0xdab0, 0x4d72, {                    \
       0x94, 0x26, 0x87, 0x5f, 0x5a, 0x8a, 0x2a, 0xe5 \
     }                                                \
   }
@@ -79,17 +82,18 @@ class nsGenericHTMLFrameElement : public
                         mozilla::ErrorResult& aError);
 
   void SwapFrameLoaders(mozilla::dom::XULFrameElement& aOtherLoaderOwner,
                         mozilla::ErrorResult& aError);
 
   void SwapFrameLoaders(nsIFrameLoaderOwner* aOtherLoaderOwner,
                         mozilla::ErrorResult& rv);
 
-  void PresetOpenerWindow(mozIDOMWindowProxy* aOpenerWindow,
+  void PresetOpenerWindow(const mozilla::dom::Nullable<
+                              mozilla::dom::WindowProxyHolder>& aOpenerWindow,
                           mozilla::ErrorResult& aRv);
 
   static void InitStatics();
   static bool BrowserFramesEnabled();
 
   /**
    * Helper method to map a HTML 'scrolling' attribute value to a nsIScrollable
    * enum value.  scrolling="no" (and its synonyms) maps to
@@ -107,17 +111,17 @@ class nsGenericHTMLFrameElement : public
  protected:
   virtual ~nsGenericHTMLFrameElement();
 
   // This doesn't really ensure a frame loader in all cases, only when
   // it makes sense.
   void EnsureFrameLoader();
   void LoadSrc();
   nsIDocument* GetContentDocument(nsIPrincipal& aSubjectPrincipal);
-  already_AddRefed<nsPIDOMWindowOuter> GetContentWindow();
+  mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetContentWindow();
 
   virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
                                 const nsAttrValue* aValue,
                                 const nsAttrValue* aOldValue,
                                 nsIPrincipal* aSubjectPrincipal,
                                 bool aNotify) override;
   virtual nsresult OnAttrSetButNotChanged(int32_t aNamespaceID, nsAtom* aName,
                                           const nsAttrValueOrString& aValue,
@@ -160,14 +164,16 @@ class nsGenericHTMLFrameElement : public
    * @param aName the localname of the attribute being set
    * @param aValue the value being set or null if the value is being unset
    * @param aNotify Whether we plan to notify document observers.
    */
   void AfterMaybeChangeAttr(int32_t aNamespaceID, nsAtom* aName,
                             const nsAttrValueOrString* aValue,
                             nsIPrincipal* aMaybeScriptedPrincipal,
                             bool aNotify);
+
+  already_AddRefed<nsPIDOMWindowOuter> GetContentWindowInternal();
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsGenericHTMLFrameElement,
                               NS_GENERICHTMLFRAMEELEMENT_IID)
 
 #endif  // nsGenericHTMLFrameElement_h
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -1133,17 +1133,17 @@ void nsHTMLDocument::SetCookie(const nsA
       }
     }
 
     NS_ConvertUTF16toUTF8 cookie(aCookie);
     service->SetCookieString(codebaseURI, nullptr, cookie.get(), channel);
   }
 }
 
-already_AddRefed<nsPIDOMWindowOuter> nsHTMLDocument::Open(
+mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> nsHTMLDocument::Open(
     JSContext* /* unused */, const nsAString& aURL, const nsAString& aName,
     const nsAString& aFeatures, bool aReplace, ErrorResult& rv) {
   MOZ_ASSERT(nsContentUtils::CanCallerAccess(this),
              "XOW should have caught this!");
 
   nsCOMPtr<nsPIDOMWindowInner> window = GetInnerWindow();
   if (!window) {
     rv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
@@ -1154,17 +1154,20 @@ already_AddRefed<nsPIDOMWindowOuter> nsH
   if (!outer) {
     rv.Throw(NS_ERROR_NOT_INITIALIZED);
     return nullptr;
   }
   RefPtr<nsGlobalWindowOuter> win = nsGlobalWindowOuter::Cast(outer);
   nsCOMPtr<nsPIDOMWindowOuter> newWindow;
   // XXXbz We ignore aReplace for now.
   rv = win->OpenJS(aURL, aName, aFeatures, getter_AddRefs(newWindow));
-  return newWindow.forget();
+  if (!newWindow) {
+    return nullptr;
+  }
+  return WindowProxyHolder(newWindow.forget());
 }
 
 already_AddRefed<nsIDocument> nsHTMLDocument::Open(
     JSContext* cx, const Optional<nsAString>& /* unused */,
     const nsAString& aReplace, ErrorResult& aError) {
   // Implements the "When called with two arguments (or fewer)" steps here:
   // https://html.spec.whatwg.org/multipage/webappapis.html#opening-the-input-stream
 
--- a/dom/html/nsHTMLDocument.h
+++ b/dom/html/nsHTMLDocument.h
@@ -25,16 +25,19 @@ class nsIURI;
 class nsIDocShell;
 class nsICachingChannel;
 class nsIWyciwygChannel;
 class nsILoadGroup;
 
 namespace mozilla {
 namespace dom {
 class HTMLAllCollection;
+template <typename T>
+struct Nullable;
+class WindowProxyHolder;
 }  // namespace dom
 }  // namespace mozilla
 
 class nsHTMLDocument : public nsDocument, public nsIHTMLDocument {
   typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
 
  public:
   using nsDocument::GetPlugins;
@@ -145,17 +148,17 @@ class nsHTMLDocument : public nsDocument
     if ((aFound = ResolveName(cx, aName, &v, rv))) {
       aRetval.set(v.toObjectOrNull());
     }
   }
   void GetSupportedNames(nsTArray<nsString>& aNames);
   already_AddRefed<nsIDocument> Open(
       JSContext* cx, const mozilla::dom::Optional<nsAString>& /* unused */,
       const nsAString& aReplace, mozilla::ErrorResult& aError);
-  already_AddRefed<nsPIDOMWindowOuter> Open(
+  mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> Open(
       JSContext* cx, const nsAString& aURL, const nsAString& aName,
       const nsAString& aFeatures, bool aReplace, mozilla::ErrorResult& rv);
   void Close(mozilla::ErrorResult& rv);
   void Write(JSContext* cx, const mozilla::dom::Sequence<nsString>& aText,
              mozilla::ErrorResult& rv);
   void Writeln(JSContext* cx, const mozilla::dom::Sequence<nsString>& aText,
                mozilla::ErrorResult& rv);
   void GetDesignMode(nsAString& aDesignMode);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -20,17 +20,19 @@
 #include "mozilla/BrowserElementParent.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/dom/DataTransfer.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestChild.h"
 #include "mozilla/dom/MessageManagerBinding.h"
 #include "mozilla/dom/MouseEventBinding.h"
+#include "mozilla/dom/Nullable.h"
 #include "mozilla/dom/PaymentRequestChild.h"
+#include "mozilla/dom/WindowProxyHolder.h"
 #include "mozilla/gfx/CrossProcessPaint.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/ipc/URIUtils.h"
 #include "mozilla/layers/APZChild.h"
 #include "mozilla/layers/APZCCallbackHelper.h"
 #include "mozilla/layers/APZCTreeManagerChild.h"
 #include "mozilla/layers/APZEventState.h"
 #include "mozilla/layers/ContentProcessController.h"
@@ -3254,25 +3256,28 @@ void TabChildMessageManager::MarkForCC()
   }
   EventListenerManager* elm = GetExistingListenerManager();
   if (elm) {
     elm->MarkForCC();
   }
   MessageManagerGlobal::MarkForCC();
 }
 
-already_AddRefed<nsPIDOMWindowOuter> TabChildMessageManager::GetContent(
+Nullable<WindowProxyHolder> TabChildMessageManager::GetContent(
     ErrorResult& aError) {
   if (!mTabChild) {
     aError.Throw(NS_ERROR_NULL_POINTER);
     return nullptr;
   }
   nsCOMPtr<nsPIDOMWindowOuter> window =
       do_GetInterface(mTabChild->WebNavigation());
-  return window.forget();
+  if (!window) {
+    return nullptr;
+  }
+  return WindowProxyHolder(window.forget());
 }
 
 already_AddRefed<nsIDocShell> TabChildMessageManager::GetDocShell(
     ErrorResult& aError) {
   if (!mTabChild) {
     aError.Throw(NS_ERROR_NULL_POINTER);
     return nullptr;
   }
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -89,18 +89,17 @@ class TabChildMessageManager : public Co
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(TabChildMessageManager,
                                            DOMEventTargetHelper)
 
   void MarkForCC();
 
   JSObject* WrapObject(JSContext* aCx,
                        JS::Handle<JSObject*> aGivenProto) override;
 
-  virtual already_AddRefed<nsPIDOMWindowOuter> GetContent(
-      ErrorResult& aError) override;
+  virtual Nullable<WindowProxyHolder> GetContent(ErrorResult& aError) override;
   virtual already_AddRefed<nsIDocShell> GetDocShell(
       ErrorResult& aError) override;
   virtual already_AddRefed<nsIEventTarget> GetTabEventTarget() override;
   virtual uint64_t ChromeOuterWindowID() override;
 
   NS_FORWARD_SAFE_NSIMESSAGESENDER(mMessageManager)
 
   void GetEventTargetParent(EventChainPreVisitor& aVisitor) override {
--- a/dom/smil/TimeEvent.h
+++ b/dom/smil/TimeEvent.h
@@ -4,16 +4,18 @@
  * 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_TimeEvent_h_
 #define mozilla_dom_TimeEvent_h_
 
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/TimeEventBinding.h"
+#include "mozilla/dom/Nullable.h"
+#include "mozilla/dom/WindowProxyHolder.h"
 
 class nsGlobalWindowInner;
 
 namespace mozilla {
 namespace dom {
 
 class TimeEvent final : public Event {
  public:
@@ -29,17 +31,22 @@ class TimeEvent final : public Event {
     return TimeEvent_Binding::Wrap(aCx, this, aGivenProto);
   }
 
   void InitTimeEvent(const nsAString& aType, nsGlobalWindowInner* aView,
                      int32_t aDetail);
 
   int32_t Detail() const { return mDetail; }
 
-  nsPIDOMWindowOuter* GetView() const { return mView; }
+  Nullable<WindowProxyHolder> GetView() const {
+    if (!mView) {
+      return nullptr;
+    }
+    return WindowProxyHolder(mView);
+  }
 
   TimeEvent* AsTimeEvent() final { return this; }
 
  private:
   ~TimeEvent() {}
 
   nsCOMPtr<nsPIDOMWindowOuter> mView;
   int32_t mDetail;
--- a/dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp
+++ b/dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp
@@ -128,17 +128,17 @@ WebBrowserPersistLocalDocument::GetTitle
 NS_IMETHODIMP
 WebBrowserPersistLocalDocument::GetReferrer(nsAString& aReferrer) {
   mDocument->GetReferrer(aReferrer);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 WebBrowserPersistLocalDocument::GetContentDisposition(nsAString& aCD) {
-  nsCOMPtr<nsPIDOMWindowOuter> window = mDocument->GetDefaultView();
+  nsCOMPtr<nsPIDOMWindowOuter> window = mDocument->GetWindow();
   if (NS_WARN_IF(!window)) {
     aCD.SetIsVoid(true);
     return NS_OK;
   }
   nsCOMPtr<nsIDOMWindowUtils> utils =
       nsGlobalWindowOuter::Cast(window)->WindowUtils();
   nsresult rv =
       utils->GetDocumentMetadata(NS_LITERAL_STRING("content-disposition"), aCD);
@@ -171,17 +171,17 @@ WebBrowserPersistLocalDocument::GetPostD
 NS_IMETHODIMP
 WebBrowserPersistLocalDocument::GetPrincipal(nsIPrincipal** aPrincipal) {
   nsCOMPtr<nsIPrincipal> nodePrincipal = mDocument->NodePrincipal();
   nodePrincipal.forget(aPrincipal);
   return NS_OK;
 }
 
 already_AddRefed<nsISHEntry> WebBrowserPersistLocalDocument::GetHistory() {
-  nsCOMPtr<nsPIDOMWindowOuter> window = mDocument->GetDefaultView();
+  nsCOMPtr<nsPIDOMWindowOuter> window = mDocument->GetWindow();
   if (NS_WARN_IF(!window)) {
     return nullptr;
   }
   nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(window);
   if (NS_WARN_IF(!webNav)) {
     return nullptr;
   }
   nsCOMPtr<nsIWebPageDescriptor> desc = do_QueryInterface(webNav);
--- a/dom/xul/XULFrameElement.cpp
+++ b/dom/xul/XULFrameElement.cpp
@@ -43,29 +43,37 @@ nsIDocShell* XULFrameElement::GetDocShel
 }
 
 already_AddRefed<nsIWebNavigation> XULFrameElement::GetWebNavigation() {
   nsCOMPtr<nsIDocShell> docShell = GetDocShell();
   nsCOMPtr<nsIWebNavigation> webnav = do_QueryInterface(docShell);
   return webnav.forget();
 }
 
-already_AddRefed<nsPIDOMWindowOuter> XULFrameElement::GetContentWindow() {
+Nullable<WindowProxyHolder> XULFrameElement::GetContentWindow() {
   nsCOMPtr<nsIDocShell> docShell = GetDocShell();
   if (docShell) {
     nsCOMPtr<nsPIDOMWindowOuter> win = docShell->GetWindow();
-    return win.forget();
+    if (win) {
+      return WindowProxyHolder(win.forget());
+    }
   }
 
   return nullptr;
 }
 
 nsIDocument* XULFrameElement::GetContentDocument() {
-  nsCOMPtr<nsPIDOMWindowOuter> win = GetContentWindow();
-  return win ? win->GetDoc() : nullptr;
+  nsCOMPtr<nsIDocShell> docShell = GetDocShell();
+  if (docShell) {
+    nsCOMPtr<nsPIDOMWindowOuter> win = docShell->GetWindow();
+    if (win) {
+      return win->GetDoc();
+    }
+  }
+  return nullptr;
 }
 
 void XULFrameElement::LoadSrc() {
   if (!IsInUncomposedDoc() || !OwnerDoc()->GetRootElement()) {
     return;
   }
   RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
   if (!frameLoader) {
--- a/dom/xul/XULFrameElement.h
+++ b/dom/xul/XULFrameElement.h
@@ -4,16 +4,18 @@
  * 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 XULFrameElement_h__
 #define XULFrameElement_h__
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
+#include "mozilla/dom/Nullable.h"
+#include "mozilla/dom/WindowProxyHolder.h"
 #include "js/TypeDecls.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsWrapperCache.h"
 #include "nsString.h"
 #include "nsXULElement.h"
 
 class nsIWebNavigation;
 class nsFrameLoader;
@@ -27,31 +29,32 @@ class XULFrameElement final : public nsX
       : nsXULElement(std::move(aNodeInfo)) {}
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(XULFrameElement, nsXULElement)
 
   // XULFrameElement.webidl
   nsIDocShell* GetDocShell();
   already_AddRefed<nsIWebNavigation> GetWebNavigation();
-  already_AddRefed<nsPIDOMWindowOuter> GetContentWindow();
+  Nullable<WindowProxyHolder> GetContentWindow();
   nsIDocument* GetContentDocument();
 
   // nsIFrameLoaderOwner / MozFrameLoaderOwner
   NS_IMETHOD_(already_AddRefed<nsFrameLoader>) GetFrameLoader() override {
     return do_AddRef(mFrameLoader);
   }
 
   NS_IMETHOD_(void)
   InternalSetFrameLoader(nsFrameLoader* aFrameLoader) override {
     mFrameLoader = aFrameLoader;
   }
 
-  void PresetOpenerWindow(mozIDOMWindowProxy* aWindow, ErrorResult& aRv) {
-    mOpener = do_QueryInterface(aWindow);
+  void PresetOpenerWindow(const Nullable<WindowProxyHolder>& aWindow,
+                          ErrorResult& aRv) {
+    mOpener = aWindow.IsNull() ? nullptr : aWindow.Value().get();
   }
 
   void SwapFrameLoaders(mozilla::dom::HTMLIFrameElement& aOtherLoaderOwner,
                         mozilla::ErrorResult& rv);
   void SwapFrameLoaders(XULFrameElement& aOtherLoaderOwner,
                         mozilla::ErrorResult& rv);
   void SwapFrameLoaders(nsIFrameLoaderOwner* aOtherLoaderOwner,
                         mozilla::ErrorResult& rv);
--- a/toolkit/components/antitracking/AntiTrackingCommon.cpp
+++ b/toolkit/components/antitracking/AntiTrackingCommon.cpp
@@ -355,17 +355,17 @@ already_AddRefed<nsPIDOMWindowOuter> Get
   nsIChannel* channel = document->GetChannel();
   if (!channel) {
     return nullptr;
   }
 
   nsCOMPtr<nsPIDOMWindowOuter> pwin;
   auto* outer = nsGlobalWindowOuter::Cast(aWindow->GetOuterWindow());
   if (outer) {
-    pwin = outer->GetTopOuter();
+    pwin = outer->GetScriptableTop();
   }
 
   if (!pwin) {
     return nullptr;
   }
 
   return pwin.forget();
 }
--- a/toolkit/components/extensions/WebExtensionContentScript.h
+++ b/toolkit/components/extensions/WebExtensionContentScript.h
@@ -8,16 +8,17 @@
 
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/WebExtensionContentScriptBinding.h"
 
 #include "jspubtd.h"
 
 #include "mozilla/Maybe.h"
 #include "mozilla/Variant.h"
+#include "mozilla/dom/WindowProxyHolder.h"
 #include "mozilla/extensions/MatchGlob.h"
 #include "mozilla/extensions/MatchPattern.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsISupports.h"
 #include "nsIDocShell.h"
 #include "nsWrapperCache.h"
 
@@ -108,18 +109,18 @@ class MozDocumentMatcher : public nsISup
       ErrorResult& aRv);
 
   bool Matches(const DocInfo& aDoc) const;
   bool MatchesURI(const URLInfo& aURL) const;
 
   bool MatchesLoadInfo(const URLInfo& aURL, nsILoadInfo* aLoadInfo) const {
     return Matches({aURL, aLoadInfo});
   }
-  bool MatchesWindow(nsPIDOMWindowOuter* aWindow) const {
-    return Matches(aWindow);
+  bool MatchesWindow(const dom::WindowProxyHolder& aWindow) const {
+    return Matches(aWindow.get());
   }
 
   WebExtensionPolicy* GetExtension() { return mExtension; }
 
   WebExtensionPolicy* Extension() { return mExtension; }
   const WebExtensionPolicy* Extension() const { return mExtension; }
 
   bool AllFrames() const { return mAllFrames; }
--- a/toolkit/components/extensions/WebExtensionPolicy.cpp
+++ b/toolkit/components/extensions/WebExtensionPolicy.cpp
@@ -440,22 +440,23 @@ void WebExtensionPolicy::GetContentScrip
   aScripts.AppendElements(mContentScripts);
 }
 
 bool WebExtensionPolicy::CanAccessContext(nsILoadContext* aContext) const {
   MOZ_ASSERT(aContext);
   return mPrivateBrowsingAllowed || !aContext->UsePrivateBrowsing();
 }
 
-bool WebExtensionPolicy::CanAccessWindow(nsPIDOMWindowOuter* aWindow) const {
+bool WebExtensionPolicy::CanAccessWindow(
+    const dom::WindowProxyHolder& aWindow) const {
   if (mPrivateBrowsingAllowed) {
     return true;
   }
   // match browsing mode with policy
-  nsIDocShell* docShell = aWindow->GetDocShell();
+  nsIDocShell* docShell = aWindow.get()->GetDocShell();
   nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
   return !(loadContext && loadContext->UsePrivateBrowsing());
 }
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebExtensionPolicy, mParent,
                                       mLocalizeCallback, mHostPermissions,
                                       mWebAccessiblePaths, mContentScripts)
 
@@ -669,17 +670,17 @@ void DocumentObserver::Observe(
 
 void DocumentObserver::Disconnect() {
   Unused << EPS().UnregisterObserver(*this);
 }
 
 void DocumentObserver::NotifyMatch(MozDocumentMatcher& aMatcher,
                                    nsPIDOMWindowOuter* aWindow) {
   IgnoredErrorResult rv;
-  mCallbacks->OnNewDocument(aMatcher, aWindow, rv);
+  mCallbacks->OnNewDocument(aMatcher, dom::WindowProxyHolder(aWindow), rv);
 }
 
 void DocumentObserver::NotifyMatch(MozDocumentMatcher& aMatcher,
                                    nsILoadInfo* aLoadInfo) {
   IgnoredErrorResult rv;
   mCallbacks->OnPreloadDocument(aMatcher, aLoadInfo, rv);
 }
 
--- a/toolkit/components/extensions/WebExtensionPolicy.h
+++ b/toolkit/components/extensions/WebExtensionPolicy.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_extensions_WebExtensionPolicy_h
 #define mozilla_extensions_WebExtensionPolicy_h
 
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/Nullable.h"
 #include "mozilla/dom/WebExtensionPolicyBinding.h"
+#include "mozilla/dom/WindowProxyHolder.h"
 #include "mozilla/extensions/MatchPattern.h"
 
 #include "jspubtd.h"
 
 #include "mozilla/Result.h"
 #include "mozilla/WeakPtr.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
@@ -123,17 +124,17 @@ class WebExtensionPolicy final : public 
 
   bool PrivateBrowsingAllowed() const { return mPrivateBrowsingAllowed; }
   void SetPrivateBrowsingAllowed(bool aPrivateBrowsingAllowed) {
     mPrivateBrowsingAllowed = aPrivateBrowsingAllowed;
   };
 
   bool CanAccessContext(nsILoadContext* aContext) const;
 
-  bool CanAccessWindow(nsPIDOMWindowOuter* aWindow) const;
+  bool CanAccessWindow(const dom::WindowProxyHolder& aWindow) const;
 
   static void GetActiveExtensions(
       dom::GlobalObject& aGlobal,
       nsTArray<RefPtr<WebExtensionPolicy>>& aResults);
 
   static already_AddRefed<WebExtensionPolicy> GetByID(
       dom::GlobalObject& aGlobal, const nsAString& aID);
 
--- a/toolkit/components/sessionstore/nsSessionStoreUtils.cpp
+++ b/toolkit/components/sessionstore/nsSessionStoreUtils.cpp
@@ -40,17 +40,17 @@ class DynamicFrameEventFilter final : pu
   ~DynamicFrameEventFilter() {}
 
   bool TargetInNonDynamicDocShell(Event* aEvent) {
     EventTarget* target = aEvent->GetTarget();
     if (!target) {
       return false;
     }
 
-    nsPIDOMWindowOuter* outer = target->GetOwnerGlobalForBindings();
+    nsPIDOMWindowOuter* outer = target->GetOwnerGlobalForBindingsInternal();
     if (!outer) {
       return false;
     }
 
     nsIDocShell* docShell = outer->GetDocShell();
     if (!docShell) {
       return false;
     }