Bug 1415645 - Part 1: Make nsGlobalWindow.cpp use the specific {Inner,Outer} variants in more places internally, r=smaug
authorNika Layzell <nika@thelayzells.com>
Wed, 08 Nov 2017 10:37:39 -0500
changeset 436464 8fdfee217a97f07574a600f2868b06646debaf48
parent 436463 fe6091ddbf6b74d022627ee0094a6113a3e4e883
child 436465 4a6c2c5490f454e53d3b962ea0ce9dd29c9da298
push id117
push userfmarier@mozilla.com
push dateTue, 28 Nov 2017 20:17:16 +0000
reviewerssmaug
bugs1415645
milestone59.0a1
Bug 1415645 - Part 1: Make nsGlobalWindow.cpp use the specific {Inner,Outer} variants in more places internally, r=smaug MozReview-Commit-ID: LsgjJTbuH3L
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -285,25 +285,25 @@ using mozilla::OriginAttributes;
 using mozilla::TimeStamp;
 using mozilla::TimeDuration;
 using mozilla::dom::cache::CacheStorage;
 
 static LazyLogModule gDOMLeakPRLog("DOMLeak");
 
 nsGlobalWindowInner::InnerWindowByIdTable *nsGlobalWindowInner::sInnerWindowsById = nullptr;
 nsGlobalWindowOuter::OuterWindowByIdTable *nsGlobalWindowOuter::sOuterWindowsById = nullptr;
-bool nsGlobalWindow::sIdleObserversAPIFuzzTimeDisabled = false;
-
-static int32_t              gRefCnt                    = 0;
-static int32_t              gOpenPopupSpamCount        = 0;
-static PopupControlState    gPopupControlState         = openAbused;
-static bool                 gMouseDown                 = false;
-static bool                 gDragServiceDisabled       = false;
-static FILE                *gDumpFile                  = nullptr;
-static uint32_t             gSerialCounter             = 0;
+
+static int32_t              gRefCnt                           = 0;
+static int32_t              gOpenPopupSpamCount               = 0;
+static PopupControlState    gPopupControlState                = openAbused;
+static bool                 gMouseDown                        = false;
+static bool                 gDragServiceDisabled              = false;
+static FILE                *gDumpFile                         = nullptr;
+static uint32_t             gSerialCounter                    = 0;
+static bool                 gIdleObserversAPIFuzzTimeDisabled = false;
 
 #ifdef DEBUG_jst
 int32_t gTimeoutCnt                                    = 0;
 #endif
 
 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
 #define DEBUG_PAGE_CACHE
 #endif
@@ -315,62 +315,62 @@ int32_t gTimeoutCnt                     
 // The interval at which we execute idle callbacks
 static uint32_t gThrottledIdlePeriodLength;
 
 #define DEFAULT_THROTTLED_IDLE_PERIOD_LENGTH 10000
 
 #define FORWARD_TO_OUTER(method, args, err_rval)                              \
   PR_BEGIN_MACRO                                                              \
   if (IsInnerWindow()) {                                                      \
-    nsGlobalWindow *outer = GetOuterWindowInternal();                         \
+    nsGlobalWindowOuter *outer = GetOuterWindowInternal();                    \
     if (!AsInner()->HasActiveDocument()) {                                    \
       NS_WARNING(outer ?                                                      \
                  "Inner window does not have active document." :              \
                  "No outer window available!");                               \
       return err_rval;                                                        \
     }                                                                         \
     return outer->method args;                                                \
   }                                                                           \
   PR_END_MACRO
 
 #define FORWARD_TO_OUTER_OR_THROW(method, args, errorresult, err_rval)        \
   PR_BEGIN_MACRO                                                              \
   MOZ_RELEASE_ASSERT(IsInnerWindow());                                        \
-  nsGlobalWindow *outer = GetOuterWindowInternal();                           \
+  nsGlobalWindowOuter *outer = GetOuterWindowInternal();                      \
   if (MOZ_LIKELY(AsInner()->HasActiveDocument())) {                           \
     return outer->method args;                                                \
   }                                                                           \
   if (!outer) {                                                               \
     NS_WARNING("No outer window available!");                                 \
     errorresult.Throw(NS_ERROR_NOT_INITIALIZED);                              \
   } else {                                                                    \
     errorresult.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO);                    \
   }                                                                           \
   return err_rval;                                                            \
   PR_END_MACRO
 
 #define FORWARD_TO_OUTER_VOID(method, args)                                   \
   PR_BEGIN_MACRO                                                              \
   if (IsInnerWindow()) {                                                      \
-    nsGlobalWindow *outer = GetOuterWindowInternal();                         \
+    nsGlobalWindowOuter *outer = GetOuterWindowInternal();                    \
     if (!AsInner()->HasActiveDocument()) {                                    \
       NS_WARNING(outer ?                                                      \
                  "Inner window does not have active document." :              \
                  "No outer window available!");                               \
       return;                                                                 \
     }                                                                         \
     outer->method args;                                                       \
     return;                                                                   \
   }                                                                           \
   PR_END_MACRO
 
 #define FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(method, args, err_rval)         \
   PR_BEGIN_MACRO                                                              \
   if (IsInnerWindow()) {                                                      \
-    nsGlobalWindow *outer = GetOuterWindowInternal();                         \
+    nsGlobalWindowOuter *outer = GetOuterWindowInternal();                    \
     if (!AsInner()->HasActiveDocument()) {                                    \
       NS_WARNING(outer ?                                                      \
                  "Inner window does not have active document." :              \
                  "No outer window available!");                               \
       return err_rval;                                                        \
     }                                                                         \
     return ((nsGlobalModalWindow *)outer)->method args;                       \
   }                                                                           \
@@ -439,17 +439,17 @@ static NS_DEFINE_CID(kXULControllersCID,
  * An indirect observer object that means we don't have to implement nsIObserver
  * on nsGlobalWindow, where any script could see it.
  */
 class nsGlobalWindowObserver final : public nsIObserver
                                    , public nsIInterfaceRequestor
                                    , public StorageNotificationObserver
 {
 public:
-  explicit nsGlobalWindowObserver(nsGlobalWindow* aWindow) : mWindow(aWindow) {}
+  explicit nsGlobalWindowObserver(nsGlobalWindowInner* aWindow) : mWindow(aWindow) {}
   NS_DECL_ISUPPORTS
   NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) override
   {
     if (!mWindow)
       return NS_OK;
     return mWindow->Observe(aSubject, aTopic, aData);
   }
   void Forget() { mWindow = nullptr; }
@@ -490,17 +490,17 @@ public:
     return mWindow ? mWindow->EventTargetFor(TaskCategory::Other) : nullptr;
   }
 
 private:
   ~nsGlobalWindowObserver() = default;
 
   // This reference is non-owning and safe because it's cleared by
   // nsGlobalWindow::CleanUp().
-  nsGlobalWindow* MOZ_NON_OWNING_REF mWindow;
+  nsGlobalWindowInner* MOZ_NON_OWNING_REF mWindow;
 };
 
 NS_IMPL_ISUPPORTS(nsGlobalWindowObserver, nsIObserver, nsIInterfaceRequestor)
 
 static already_AddRefed<nsIVariant>
 CreateVoidVariant()
 {
   RefPtr<nsVariantCC> writable = new nsVariantCC();
@@ -566,17 +566,17 @@ NS_INTERFACE_MAP_END_INHERITING(TimeoutH
 
 
 class IdleRequestExecutor final : public nsIRunnable
                                 , public nsICancelableRunnable
                                 , public nsINamed
                                 , public nsIIdleRunnable
 {
 public:
-  explicit IdleRequestExecutor(nsGlobalWindow* aWindow)
+  explicit IdleRequestExecutor(nsGlobalWindowInner* aWindow)
     : mDispatched(false)
     , mDeadline(TimeStamp::Now())
     , mWindow(aWindow)
   {
     MOZ_DIAGNOSTIC_ASSERT(mWindow);
     MOZ_DIAGNOSTIC_ASSERT(mWindow->IsInnerWindow());
 
     mIdlePeriodLimit = { mDeadline, mWindow->LastIdleRequestHandle() };
@@ -617,17 +617,17 @@ private:
 
   void DelayedDispatch(uint32_t aDelay);
 
   ~IdleRequestExecutor() override {}
 
   bool mDispatched;
   TimeStamp mDeadline;
   IdlePeriodLimit mIdlePeriodLimit;
-  RefPtr<nsGlobalWindow> mWindow;
+  RefPtr<nsGlobalWindowInner> mWindow;
   // The timeout handler responsible for dispatching this executor in
   // the case of immediate dispatch to the idle queue isn't
   // desirable. This is used if we've dispatched all idle callbacks
   // that are allowed to run in the current idle period, or if the
   // associated window is currently in the background.
   nsCOMPtr<nsITimeoutHandler> mDelayedExecutorDispatcher;
   // If not Nothing() then this value is the handle to the currently
   // scheduled delayed executor dispatcher. This is needed to be able
@@ -776,17 +776,17 @@ IdleRequestExecutorTimeoutHandler::Call(
 }
 
 void
 nsGlobalWindow::ScheduleIdleRequestDispatch()
 {
   AssertIsOnMainThread();
 
   if (!mIdleRequestExecutor) {
-    mIdleRequestExecutor = new IdleRequestExecutor(this);
+    mIdleRequestExecutor = new IdleRequestExecutor(AssertInner());
   }
 
   mIdleRequestExecutor->MaybeDispatch();
 }
 
 void
 nsGlobalWindow::SuspendIdleRequests()
 {
@@ -1124,19 +1124,19 @@ public:
   }
   bool isConstructor(JSObject *obj) const override {
     return false;
   }
 
   static const nsOuterWindowProxy singleton;
 
 protected:
-  static nsGlobalWindow* GetOuterWindow(JSObject *proxy)
+  static nsGlobalWindowOuter* GetOuterWindow(JSObject *proxy)
   {
-    nsGlobalWindow* outerWindow = nsGlobalWindow::FromSupports(
+    nsGlobalWindowOuter* outerWindow = nsGlobalWindowOuter::FromSupports(
       static_cast<nsISupports*>(js::GetProxyReservedSlot(proxy, 0).toPrivate()));
     MOZ_ASSERT_IF(outerWindow, outerWindow->IsOuterWindow());
     return outerWindow;
   }
 
   // False return value means we threw an exception.  True return value
   // but false "found" means we didn't have a subframe at that index.
   bool GetSubframeWindow(JSContext *cx, JS::Handle<JSObject*> proxy,
@@ -1168,17 +1168,17 @@ nsOuterWindowProxy::className(JSContext 
     MOZ_ASSERT(js::IsProxy(proxy));
 
     return "Window";
 }
 
 void
 nsOuterWindowProxy::finalize(JSFreeOp *fop, JSObject *proxy) const
 {
-  nsGlobalWindow* outerWindow = GetOuterWindow(proxy);
+  nsGlobalWindowOuter* outerWindow = GetOuterWindow(proxy);
   if (outerWindow) {
     outerWindow->ClearWrapper(proxy);
 
     // Ideally we would use OnFinalize here, but it's possible that
     // EnsureScriptEnvironment will later be called on the window, and we don't
     // want to create a new script object in that case. Therefore, we need to
     // write a non-null value that will reliably crash when dereferenced.
     outerWindow->PoisonOuterWindowProxy(proxy);
@@ -1446,17 +1446,17 @@ nsOuterWindowProxy::GetSubframeWindow(JS
                                       JS::Handle<JSObject*> proxy,
                                       JS::Handle<jsid> id) const
 {
   uint32_t index = GetArrayIndexFromId(cx, id);
   if (!IsArrayIndex(index)) {
     return nullptr;
   }
 
-  nsGlobalWindow* win = GetOuterWindow(proxy);
+  nsGlobalWindowOuter* win = GetOuterWindow(proxy);
   MOZ_ASSERT(win->IsOuterWindow());
   return win->IndexedGetterOuter(index);
 }
 
 bool
 nsOuterWindowProxy::AppendIndexedPropertyNames(JSContext *cx, JSObject *proxy,
                                                JS::AutoIdVector &props) const
 {
@@ -1472,17 +1472,17 @@ nsOuterWindowProxy::AppendIndexedPropert
   }
 
   return true;
 }
 
 size_t
 nsOuterWindowProxy::objectMoved(JSObject *obj, JSObject *old) const
 {
-  nsGlobalWindow* outerWindow = GetOuterWindow(obj);
+  nsGlobalWindowOuter* outerWindow = GetOuterWindow(obj);
   if (outerWindow) {
     outerWindow->UpdateWrapper(obj, old);
   }
   return 0;
 }
 
 const nsOuterWindowProxy
 nsOuterWindowProxy::singleton;
@@ -1525,17 +1525,17 @@ NewOuterWindowProxy(JSContext *cx, JS::H
   MOZ_ASSERT_IF(obj, js::IsWindowProxy(obj));
   return obj;
 }
 
 //*****************************************************************************
 //***    nsGlobalWindow: Object Management
 //*****************************************************************************
 
-nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
+nsGlobalWindow::nsGlobalWindow(nsGlobalWindowOuter *aOuterWindow)
   : nsPIDOMWindow<nsISupports>(aOuterWindow ? aOuterWindow->AsOuter() : nullptr),
     mIdleFuzzFactor(0),
     mIdleCallbackIndex(-1),
     mCurrentlyIdle(false),
     mAddActiveEventFuzzTime(true),
     mFullScreen(false),
     mFullscreenMode(false),
     mIsClosed(false),
@@ -1589,17 +1589,17 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
   // Initialize the PRCList (this).
   PR_INIT_CLIST(this);
 
   if (aOuterWindow) {
     // |this| is an inner window, add this inner window to the outer
     // window list of inners.
     PR_INSERT_AFTER(this, aOuterWindow);
 
-    mObserver = new nsGlobalWindowObserver(this);
+    mObserver = new nsGlobalWindowObserver(AssertInner());
     if (mObserver) {
       nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
       if (os) {
         // Watch for online/offline status changes so we can fire events. Use
         // a strong reference.
         os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
                         false);
 
@@ -1632,17 +1632,17 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
   // to create the entropy collector, so we should
   // try to get one until we succeed.
 
   gRefCnt++;
 
   static bool sFirstTime = true;
   if (sFirstTime) {
     TimeoutManager::Initialize();
-    Preferences::AddBoolVarCache(&sIdleObserversAPIFuzzTimeDisabled,
+    Preferences::AddBoolVarCache(&gIdleObserversAPIFuzzTimeDisabled,
                                  "dom.idle-observers-api.fuzz_time.disabled",
                                  false);
 
     Preferences::AddUintVarCache(&gThrottledIdlePeriodLength,
                                  "dom.idle_period.throttled_length",
                                  DEFAULT_THROTTLED_IDLE_PERIOD_LENGTH);
     sFirstTime = false;
   }
@@ -1790,19 +1790,19 @@ nsGlobalWindow::~nsGlobalWindow()
 
     // An inner window is destroyed, pull it out of the outer window's
     // list if inner windows.
 
     PR_REMOVE_LINK(this);
 
     // If our outer window's inner window is this window, null out the
     // outer window's reference to this window that's being deleted.
-    nsGlobalWindow *outer = GetOuterWindowInternal();
+    nsGlobalWindowOuter *outer = GetOuterWindowInternal();
     if (outer) {
-      outer->MaybeClearInnerWindow(this);
+      outer->MaybeClearInnerWindow(AssertInner());
     }
   }
 
   // We don't have to leave the tab group if we are an inner window.
   if (mTabGroup && IsOuterWindow()) {
     mTabGroup->Leave(AsOuter());
   }
 
@@ -1987,17 +1987,17 @@ nsGlobalWindow::CleanUp()
   mOpener = nullptr;             // Forces Release
   if (mContext) {
     mContext = nullptr;            // Forces Release
   }
   mChromeEventHandler = nullptr; // Forces Release
   mParentTarget = nullptr;
 
   if (IsOuterWindow()) {
-    nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
+    nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal();
     if (inner) {
       inner->CleanUp();
     }
   }
 
   if (IsInnerWindow()) {
     DisableGamepadUpdates();
     mHasGamepad = false;
@@ -2061,17 +2061,17 @@ nsGlobalWindow::ClearControllers()
 void
 nsGlobalWindow::FreeInnerObjects()
 {
   NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
 
   // Make sure that this is called before we null out the document and
   // other members that the window destroyed observers could
   // re-create.
-  NotifyDOMWindowDestroyed(this);
+  NotifyDOMWindowDestroyed(AssertInner());
   if (auto* reporter = nsWindowMemoryReporter::Get()) {
     reporter->ObserveDOMWindowDetached(AssertInner());
   }
 
   mInnerObjectsFreed = true;
 
   // Kill all of the workers for this window.
   mozilla::dom::workers::CancelWorkersForWindow(AsInner());
@@ -2353,17 +2353,18 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mServiceWorkerRegistrationTable)
 
 #ifdef MOZ_WEBSPEECH
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis)
 #endif
 
   if (tmp->mOuterWindow) {
-    nsGlobalWindowOuter::Cast(tmp->mOuterWindow)->MaybeClearInnerWindow(tmp);
+    nsGlobalWindowOuter::Cast(tmp->mOuterWindow)->
+      MaybeClearInnerWindow(tmp->AssertInner());
     NS_IMPL_CYCLE_COLLECTION_UNLINK(mOuterWindow)
   }
 
   if (tmp->mListenerManager) {
     tmp->mListenerManager->Disconnect();
     NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
   }
 
@@ -2470,17 +2471,17 @@ nsGlobalWindow::IsBlackForCC(bool aTraci
 
 //*****************************************************************************
 // nsGlobalWindow::nsIScriptGlobalObject
 //*****************************************************************************
 
 nsresult
 nsGlobalWindow::EnsureScriptEnvironment()
 {
-  nsGlobalWindow* outer = GetOuterWindowInternal();
+  nsGlobalWindowOuter* outer = GetOuterWindowInternal();
   if (!outer) {
     NS_WARNING("No outer window available!");
     return NS_ERROR_FAILURE;
   }
 
   if (outer->GetWrapperPreserveColor()) {
     return NS_OK;
   }
@@ -2503,17 +2504,17 @@ nsGlobalWindow::EnsureScriptEnvironment(
 
   outer->mContext = context;
   return NS_OK;
 }
 
 nsIScriptContext *
 nsGlobalWindow::GetScriptContext()
 {
-  nsGlobalWindow* outer = GetOuterWindowInternal();
+  nsGlobalWindowOuter* outer = GetOuterWindowInternal();
   if (!outer) {
     return nullptr;
   }
   return outer->mContext;
 }
 
 JSObject *
 nsGlobalWindow::GetGlobalJSObject()
@@ -2672,38 +2673,38 @@ nsGlobalWindow::GetPopupControlState() c
 {0x0b917c3e, 0xbd50, 0x4683, {0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26}}
 
 class WindowStateHolder final : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)
   NS_DECL_ISUPPORTS
 
-  explicit WindowStateHolder(nsGlobalWindow *aWindow);
-
-  nsGlobalWindow* GetInnerWindow() { return mInnerWindow; }
+  explicit WindowStateHolder(nsGlobalWindowInner *aWindow);
+
+  nsGlobalWindowInner* GetInnerWindow() { return mInnerWindow; }
 
   void DidRestoreWindow()
   {
     mInnerWindow = nullptr;
     mInnerWindowReflector = nullptr;
   }
 
 protected:
   ~WindowStateHolder();
 
-  nsGlobalWindow *mInnerWindow;
+  nsGlobalWindowInner *mInnerWindow;
   // We hold onto this to make sure the inner window doesn't go away. The outer
   // window ends up recalculating it anyway.
   JS::PersistentRooted<JSObject*> mInnerWindowReflector;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
 
-WindowStateHolder::WindowStateHolder(nsGlobalWindow* aWindow)
+WindowStateHolder::WindowStateHolder(nsGlobalWindowInner* aWindow)
   : mInnerWindow(aWindow),
     mInnerWindowReflector(RootingCx(), aWindow->GetWrapper())
 {
   NS_PRECONDITION(aWindow, "null window");
   NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window");
 
   aWindow->Suspend();
 
@@ -2858,23 +2859,23 @@ nsGlobalWindow::ComputeIsSecureContext(n
       return true;
     }
   }
 
   return false;
 }
 
 static JS::CompartmentCreationOptions&
-SelectZoneGroup(nsGlobalWindow* aNewInner,
+SelectZoneGroup(nsGlobalWindowInner* aNewInner,
                 JS::CompartmentCreationOptions& aOptions)
 {
   JS::CompartmentCreationOptions options;
 
   if (aNewInner->GetOuterWindow()) {
-    nsGlobalWindow *top = aNewInner->GetTopInternal();
+    nsGlobalWindowOuter *top = aNewInner->GetTopInternal();
 
     // If we have a top-level window, use its zone (and zone group).
     if (top && top->GetGlobalJSObject()) {
       return aOptions.setExistingZone(top->GetGlobalJSObject());
     }
   }
 
   // If we're in the parent process, don't bother with zone groups.
@@ -3017,17 +3018,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
   }
 
   if (!mDoc) {
     // First document load.
 
     // Get our private root. If it is equal to us, then we need to
     // attach our global key bindings that handles browser scrolling
     // and other browser commands.
-    nsPIDOMWindowOuter* privateRoot = nsGlobalWindow::GetPrivateRoot();
+    nsPIDOMWindowOuter* privateRoot = GetPrivateRoot();
 
     if (privateRoot == AsOuter()) {
       nsXBLService::AttachGlobalKeyHandler(mChromeEventHandler);
     }
   }
 
   /* No mDocShell means we're already been partially closed down.  When that
      happens, setting status isn't a big requirement, so don't. (Doesn't happen
@@ -3053,23 +3054,23 @@ nsGlobalWindow::SetNewDocument(nsIDocume
   mSuspendedDoc = nullptr;
 
 #ifdef DEBUG
   mLastOpenedURI = aDocument->GetDocumentURI();
 #endif
 
   mContext->WillInitializeContext();
 
-  nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
+  nsGlobalWindowInner *currentInner = GetCurrentInnerWindowInternal();
 
   if (currentInner && currentInner->mNavigator) {
     currentInner->mNavigator->OnNavigation();
   }
 
-  RefPtr<nsGlobalWindow> newInnerWindow;
+  RefPtr<nsGlobalWindowInner> newInnerWindow;
   bool createdInnerWindow = false;
 
   bool thisChrome = IsChromeWindow();
 
   nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
   NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
 
   JS::Rooted<JSObject*> newInnerGlobal(cx);
@@ -3115,21 +3116,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
       // get created with a principal that subsumes our new principal.
       xpc::ClearContentXBLScope(newInnerGlobal);
     }
   } else {
     if (aState) {
       newInnerWindow = wsh->GetInnerWindow();
       newInnerGlobal = newInnerWindow->GetWrapperPreserveColor();
     } else {
-      if (thisChrome) {
-        newInnerWindow = nsGlobalWindow::CreateChrome(this);
-      } else {
-        newInnerWindow = nsGlobalWindow::Create(this);
-      }
+      newInnerWindow = nsGlobalWindowInner::Create(AssertOuter(), thisChrome);
 
       // The outer window is automatically treated as frozen when we
       // null out the inner window. As a result, initializing classes
       // on the new inner won't end up reaching into the old inner
       // window for classes etc.
       //
       // [This happens with Object.prototype when XPConnect creates
       // a temporary global while initializing classes; the reason
@@ -3137,17 +3134,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
       // and proto, which makes the JS engine look up classes in
       // cx->globalObject, i.e. this outer window].
 
       mInnerWindow = nullptr;
 
       mCreatingInnerWindow = true;
       // Every script context we are initialized with must create a
       // new global.
-      rv = CreateNativeGlobalForInner(cx, newInnerWindow->AssertInner(),
+      rv = CreateNativeGlobalForInner(cx, newInnerWindow,
                                       aDocument->GetDocumentURI(),
                                       aDocument->NodePrincipal(),
                                       &newInnerGlobal,
                                       ComputeIsSecureContext(aDocument));
       NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerGlobal &&
                    newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal,
                    "Failed to get script global");
       newInnerWindow->mIsSecureContextIfOpenerIgnored =
@@ -3552,17 +3549,17 @@ nsGlobalWindow::DetachFromDocShell()
     inner->FreeInnerObjects();
   }
 
   // Don't report that we were detached to the nsWindowMemoryReporter, as it
   // only tracks inner windows.
 
   NotifyWindowIDDestroyed("outer-window-destroyed");
 
-  nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
+  nsGlobalWindowInner *currentInner = GetCurrentInnerWindowInternal();
 
   if (currentInner) {
     NS_ASSERTION(mDoc, "Must have doc!");
 
     // Remember the document's principal and URI.
     mDocumentPrincipal = mDoc->NodePrincipal();
     mDocumentURI = mDoc->GetDocumentURI();
     mDocBaseURI = mDoc->GetDocBaseURI();
@@ -3667,17 +3664,17 @@ nsGlobalWindow::UpdateParentTarget()
   // child global, and if it doesn't have one, just use the chrome event
   // handler itself.
 
   nsCOMPtr<Element> frameElement = GetOuterWindow()->GetFrameElementInternal();
   nsCOMPtr<EventTarget> eventTarget =
     TryGetTabChildGlobalAsEventTarget(frameElement);
 
   if (!eventTarget) {
-    nsGlobalWindow* topWin = GetScriptableTopInternal();
+    nsGlobalWindowOuter* topWin = GetScriptableTopInternal();
     if (topWin) {
       frameElement = topWin->AsOuter()->GetFrameElementInternal();
       eventTarget = TryGetTabChildGlobalAsEventTarget(frameElement);
     }
   }
 
   if (!eventTarget) {
     eventTarget = TryGetTabChildGlobalAsEventTarget(mChromeEventHandler);
@@ -3753,43 +3750,43 @@ nsGlobalWindow::GetEventTargetParent(Eve
   return NS_OK;
 }
 
 bool
 nsGlobalWindow::ShouldPromptToBlockDialogs()
 {
   MOZ_ASSERT(IsOuterWindow());
 
-  nsGlobalWindow *topWindow = GetScriptableTopInternal();
-  if (!topWindow) {
+  nsGlobalWindowOuter *topWindowOuter = GetScriptableTopInternal();
+  if (!topWindowOuter) {
     NS_ASSERTION(!mDocShell, "ShouldPromptToBlockDialogs() called without a top window?");
     return true;
   }
 
-  topWindow = topWindow->GetCurrentInnerWindowInternal();
+  nsGlobalWindowInner* topWindow = topWindowOuter->GetCurrentInnerWindowInternal();
   if (!topWindow) {
     return true;
   }
 
   return topWindow->DialogsAreBeingAbused();
 }
 
 bool
 nsGlobalWindow::AreDialogsEnabled()
 {
   MOZ_ASSERT(IsOuterWindow());
 
-  nsGlobalWindow *topWindow = GetScriptableTopInternal();
-  if (!topWindow) {
+  nsGlobalWindowOuter *topWindowOuter = GetScriptableTopInternal();
+  if (!topWindowOuter) {
     NS_ERROR("AreDialogsEnabled() called without a top window?");
     return false;
   }
 
   // TODO: Warn if no top window?
-  topWindow = topWindow->GetCurrentInnerWindowInternal();
+  nsGlobalWindowInner* topWindow = topWindowOuter->GetCurrentInnerWindowInternal();
   if (!topWindow) {
     return false;
   }
 
   // Dialogs are blocked if the content viewer is hidden
   if (mDocShell) {
     nsCOMPtr<nsIContentViewer> cv;
     mDocShell->GetContentViewer(getter_AddRefs(cv));
@@ -3874,40 +3871,40 @@ nsGlobalWindow::ConfirmDialogIfNeeded()
   }
 
   return true;
 }
 
 void
 nsGlobalWindow::DisableDialogs()
 {
-  nsGlobalWindow *topWindow = GetScriptableTopInternal();
-  if (!topWindow) {
+  nsGlobalWindowOuter *topWindowOuter = GetScriptableTopInternal();
+  if (!topWindowOuter) {
     NS_ERROR("DisableDialogs() called without a top window?");
     return;
   }
 
-  topWindow = topWindow->GetCurrentInnerWindowInternal();
+  nsGlobalWindowInner* topWindow = topWindowOuter->GetCurrentInnerWindowInternal();
   // TODO: Warn if no top window?
   if (topWindow) {
     topWindow->mAreDialogsEnabled = false;
   }
 }
 
 void
 nsGlobalWindow::EnableDialogs()
 {
-  nsGlobalWindow *topWindow = GetScriptableTopInternal();
-  if (!topWindow) {
+  nsGlobalWindowOuter *topWindowOuter = GetScriptableTopInternal();
+  if (!topWindowOuter) {
     NS_ERROR("EnableDialogs() called without a top window?");
     return;
   }
 
   // TODO: Warn if no top window?
-  topWindow = topWindow->GetCurrentInnerWindowInternal();
+  nsGlobalWindowInner* topWindow = topWindowOuter->GetCurrentInnerWindowInternal();
   if (topWindow) {
     topWindow->mAreDialogsEnabled = true;
   }
 }
 
 nsresult
 nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor)
 {
@@ -3940,17 +3937,17 @@ nsGlobalWindow::PostHandleEvent(EventCha
     // If any VR display presentation is active at unload, the next page
     // will receive a vrdisplayactive event to indicate that it should
     // immediately begin vr presentation. This should occur when navigating
     // forwards, navigating backwards, and on page reload.
     for (const auto& display : mVRDisplays) {
       if (display->IsPresenting()) {
         // Save this VR display ID to trigger vrdisplayactivate event
         // after the next load event.
-        nsGlobalWindow* outer = GetOuterWindowInternal();
+        nsGlobalWindowOuter* outer = GetOuterWindowInternal();
         if (outer) {
           outer->SetAutoActivateVRDisplayID(display->DisplayId());
         }
 
         // XXX The WebVR 1.1 spec does not define which of multiple VR
         // presenting VR displays will be chosen during navigation.
         // As the underlying platform VR API's currently only allow a single
         // VR display, it is safe to choose the first VR display for now.
@@ -3987,17 +3984,17 @@ nsGlobalWindow::PostHandleEvent(EventCha
       // but not always (i.e. if this window is not shown there won't
       // be a pres context available). Since we're not firing a GUI
       // event we don't need a pres context anyway so we just pass
       // null as the pres context all the time here.
       EventDispatcher::Dispatch(element, nullptr, &event, nullptr, &status);
     }
 
     uint32_t autoActivateVRDisplayID = 0;
-    nsGlobalWindow* outer = GetOuterWindowInternal();
+    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
     if (outer) {
       autoActivateVRDisplayID = outer->GetAutoActivateVRDisplayID();
     }
     if (autoActivateVRDisplayID) {
       DispatchVRDisplayActivate(autoActivateVRDisplayID,
                                 VRDisplayEventReason::Navigation);
     }
   }
@@ -4027,17 +4024,17 @@ nsGlobalWindow::SetArguments(nsIArray *a
   // Moreover, per-spec |dialogArguments| is a property of the browsing context
   // (outer), whereas |arguments| lives on the inner.
   //
   // We've now mostly separated them, but the difference is still opaque to
   // nsWindowWatcher (the caller of SetArguments in this little back-and-forth
   // embedding waltz we do here).
   //
   // So we need to demultiplex the two cases here.
-  nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
+  nsGlobalWindowInner *currentInner = GetCurrentInnerWindowInternal();
 
   mArguments = aArguments;
   rv = currentInner->DefineArgumentsProperty(aArguments);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
@@ -4452,17 +4449,17 @@ nsPIDOMWindowInner::TryToCacheTopInnerWi
   if (mHasTriedToCacheTopInnerWindow) {
     return;
   }
 
   MOZ_ASSERT(!mInnerObjectsFreed);
 
   mHasTriedToCacheTopInnerWindow = true;
 
-  nsGlobalWindow* window = nsGlobalWindowInner::Cast(AsInner());
+  nsGlobalWindowInner* window = nsGlobalWindowInner::Cast(AsInner());
 
   MOZ_ASSERT(window);
 
   if (nsCOMPtr<nsPIDOMWindowOuter> topOutter = window->GetScriptableTop()) {
     mTopInnerWindow = topOutter->GetCurrentInnerWindow();
   }
 }
 
@@ -4823,17 +4820,17 @@ nsGlobalWindow::GetParent()
     return win.forget();
   }
 
   nsCOMPtr<nsPIDOMWindowOuter> win(AsOuter());
   return win.forget();
 }
 
 static nsresult
-GetTopImpl(nsGlobalWindow* aWin, nsPIDOMWindowOuter** aTop, bool aScriptable)
+GetTopImpl(nsGlobalWindowOuter* aWin, nsPIDOMWindowOuter** aTop, bool aScriptable)
 {
   *aTop = nullptr;
 
   // Walk up the parent chain.
 
   nsCOMPtr<nsPIDOMWindowOuter> prevParent = aWin->AsOuter();
   nsCOMPtr<nsPIDOMWindowOuter> parent = aWin->AsOuter();
   do {
@@ -4869,26 +4866,26 @@ GetTopImpl(nsGlobalWindow* aWin, nsPIDOM
  * boundaries.  If we encounter a window owned by an <iframe mozbrowser> while
  * walking up the window hierarchy, we'll stop and return that window.
  */
 nsPIDOMWindowOuter*
 nsGlobalWindow::GetScriptableTop()
 {
   FORWARD_TO_OUTER(GetScriptableTop, (), nullptr);
   nsCOMPtr<nsPIDOMWindowOuter> window;
-  GetTopImpl(this, getter_AddRefs(window), /* aScriptable = */ true);
+  GetTopImpl(AssertOuter(), getter_AddRefs(window), /* aScriptable = */ true);
   return window.get();
 }
 
 already_AddRefed<nsPIDOMWindowOuter>
 nsGlobalWindow::GetTop()
 {
   MOZ_ASSERT(IsOuterWindow());
   nsCOMPtr<nsPIDOMWindowOuter> window;
-  GetTopImpl(this, getter_AddRefs(window), /* aScriptable = */ false);
+  GetTopImpl(AssertOuter(), getter_AddRefs(window), /* aScriptable = */ false);
   return window.forget();
 }
 
 void
 nsGlobalWindow::GetContentOuter(JSContext* aCx,
                                 JS::MutableHandle<JSObject*> aRetval,
                                 CallerType aCallerType,
                                 ErrorResult& aError)
@@ -4998,17 +4995,17 @@ nsGlobalWindow::GetMozSelfSupport(ErrorR
   mMozSelfSupport = MozSelfSupport::Constructor(global, cx, aError);
   return mMozSelfSupport;
 }
 
 nsresult
 nsGlobalWindow::GetPrompter(nsIPrompt** aPrompt)
 {
   if (IsInnerWindow()) {
-    nsGlobalWindow* outer = GetOuterWindowInternal();
+    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
     if (!outer) {
       NS_WARNING("No outer window available!");
       return NS_ERROR_NOT_INITIALIZED;
     }
     return outer->GetPrompter(aPrompt);
   }
 
   if (!mDocShell)
@@ -5426,17 +5423,17 @@ nsGlobalWindow::GetControllers(nsIContro
 
 nsPIDOMWindowOuter*
 nsGlobalWindow::GetSanitizedOpener(nsPIDOMWindowOuter* aOpener)
 {
   if (!aOpener) {
     return nullptr;
   }
 
-  nsGlobalWindow* win = nsGlobalWindowOuter::Cast(aOpener);
+  nsGlobalWindowOuter* win = nsGlobalWindowOuter::Cast(aOpener);
 
   // First, ensure that we're not handing back a chrome window to content:
   if (win->IsChromeWindow()) {
     return nullptr;
   }
 
   // We don't want to reveal the opener if the opener is a mail window,
   // because opener can be used to spoof the contents of a message (bug 105050).
@@ -6942,17 +6939,17 @@ GetFullscreenTransitionDuration(bool aEn
            &aDuration->mFadeIn, &aDuration->mFadeOut);
   }
 }
 
 class FullscreenTransitionTask : public Runnable
 {
 public:
   FullscreenTransitionTask(const FullscreenTransitionDuration& aDuration,
-                           nsGlobalWindow* aWindow,
+                           nsGlobalWindowOuter* aWindow,
                            bool aFullscreen,
                            nsIWidget* aWidget,
                            nsIScreen* aScreen,
                            nsISupports* aTransitionData)
     : mozilla::Runnable("FullscreenTransitionTask")
     , mWindow(aWindow)
     , mWidget(aWidget)
     , mScreen(aScreen)
@@ -7019,17 +7016,17 @@ private:
   private:
     ~Observer() = default;
 
     RefPtr<FullscreenTransitionTask> mTask;
   };
 
   static const char* const kPaintedTopic;
 
-  RefPtr<nsGlobalWindow> mWindow;
+  RefPtr<nsGlobalWindowOuter> mWindow;
   nsCOMPtr<nsIWidget> mWidget;
   nsCOMPtr<nsIScreen> mScreen;
   nsCOMPtr<nsITimer> mTimer;
   nsCOMPtr<nsISupports> mTransitionData;
 
   TimeStamp mFullscreenChangeStartTime;
   FullscreenTransitionDuration mDuration;
   Stage mStage;
@@ -7139,17 +7136,17 @@ FullscreenTransitionTask::Observer::Obse
     obs->RemoveObserver(this, kPaintedTopic);
     mTask->mTimer = nullptr;
     mTask->Run();
   }
   return NS_OK;
 }
 
 static bool
-MakeWidgetFullscreen(nsGlobalWindow* aWindow, FullscreenReason aReason,
+MakeWidgetFullscreen(nsGlobalWindowOuter* aWindow, FullscreenReason aReason,
                      bool aFullscreen)
 {
   nsCOMPtr<nsIWidget> widget = aWindow->GetMainWidget();
   if (!widget) {
     return false;
   }
 
   FullscreenTransitionDuration duration;
@@ -7253,17 +7250,17 @@ nsGlobalWindow::SetFullscreenInternal(Fu
   // gone full screen, the state trap above works.
   mFullScreen = aFullScreen;
 
   // Sometimes we don't want the top-level widget to actually go fullscreen,
   // for example in the B2G desktop client, we don't want the emulated screen
   // dimensions to appear to increase when entering fullscreen mode; we just
   // want the content to fill the entire client area of the emulator window.
   if (!Preferences::GetBool("full-screen-api.ignore-widgets", false)) {
-    if (MakeWidgetFullscreen(this, aReason, aFullScreen)) {
+    if (MakeWidgetFullscreen(AssertOuter(), aReason, aFullScreen)) {
       // The rest of code for switching fullscreen is in nsGlobalWindow::
       // FinishFullscreenChange() which will be called after sizemodechange
       // event is dispatched.
       return NS_OK;
     }
   }
 
   FinishFullscreenChange(aFullScreen);
@@ -9140,17 +9137,17 @@ nsGlobalWindow::PostMessageMozOuter(JSCo
   // Window.postMessage is an intentional subversion of the same-origin policy.
   // As such, this code must be particularly careful in the information it
   // exposes to calling code.
   //
   // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
   //
 
   // First, get the caller's window
-  RefPtr<nsGlobalWindow> callerInnerWin = CallerInnerWindow();
+  RefPtr<nsGlobalWindowInner> callerInnerWin = CallerInnerWindow();
   nsIPrincipal* callerPrin;
   if (callerInnerWin) {
     MOZ_ASSERT(callerInnerWin->IsInnerWindow(),
                "should have gotten an inner window here");
 
     // Compute the caller's origin either from its principal or, in the case the
     // principal doesn't carry a URI (e.g. the system principal), the caller's
     // document.  We must get this now instead of when the event is created and
@@ -9308,29 +9305,29 @@ nsGlobalWindow::PostMessageMoz(JSContext
   }
 
   PostMessageMoz(aCx, aMessage, aTargetOrigin, transferArray,
                  aSubjectPrincipal, aRv);
 }
 
 class nsCloseEvent : public Runnable {
 
-  RefPtr<nsGlobalWindow> mWindow;
+  RefPtr<nsGlobalWindowOuter> mWindow;
   bool mIndirect;
 
-  nsCloseEvent(nsGlobalWindow* aWindow, bool aIndirect)
+  nsCloseEvent(nsGlobalWindowOuter* aWindow, bool aIndirect)
     : mozilla::Runnable("nsCloseEvent")
     , mWindow(aWindow)
     , mIndirect(aIndirect)
   {}
 
 public:
 
   static nsresult
-  PostCloseEvent(nsGlobalWindow* aWindow, bool aIndirect) {
+  PostCloseEvent(nsGlobalWindowOuter* aWindow, bool aIndirect) {
     nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow, aIndirect);
     nsresult rv =
       aWindow->Dispatch(TaskCategory::Other, ev.forget());
     if (NS_SUCCEEDED(rv))
       aWindow->MaybeForgiveSpamCount();
     return rv;
   }
 
@@ -9525,17 +9522,17 @@ nsGlobalWindow::FinalClose()
   // In particular, if some inner of |win| is the entry global, we must
   // complete _two_ round-trips to the event loop before the call to
   // ReallyCloseWindow. This allows setTimeout handlers that are set after
   // FinalClose() is called to run before the window is torn down.
   nsCOMPtr<nsPIDOMWindowInner> entryWindow =
     do_QueryInterface(GetEntryGlobal());
   bool indirect =
     entryWindow && entryWindow->GetOuterWindow() == this->AsOuter();
-  if (NS_FAILED(nsCloseEvent::PostCloseEvent(this, indirect))) {
+  if (NS_FAILED(nsCloseEvent::PostCloseEvent(AssertOuter(), indirect))) {
     ReallyCloseWindow();
   } else {
     mHavePendingClose = true;
   }
 }
 
 
 void
@@ -9593,17 +9590,17 @@ nsGlobalWindow::ReallyCloseWindow()
 
 void
 nsGlobalWindow::EnterModalState()
 {
   MOZ_ASSERT(IsOuterWindow(), "Modal state is maintained on outer windows");
 
   // GetScriptableTop, not GetTop, so that EnterModalState works properly with
   // <iframe mozbrowser>.
-  nsGlobalWindow* topWin = GetScriptableTopInternal();
+  nsGlobalWindowOuter* topWin = GetScriptableTopInternal();
 
   if (!topWin) {
     NS_ERROR("Uh, EnterModalState() called w/o a reachable top window?");
     return;
   }
 
   // If there is an active ESM in this window, clear it. Otherwise, this can
   // cause a problem if a modal state is entered during a mouseup event.
@@ -9646,42 +9643,42 @@ nsGlobalWindow::EnterModalState()
   if (topWin->mModalStateDepth == 0) {
     NS_ASSERTION(!topWin->mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
 
     topWin->mSuspendedDoc = topDoc;
     if (topDoc) {
       topDoc->SuppressEventHandling();
     }
 
-    nsGlobalWindow* inner = topWin->GetCurrentInnerWindowInternal();
+    nsGlobalWindowInner* inner = topWin->GetCurrentInnerWindowInternal();
     if (inner) {
       topWin->GetCurrentInnerWindowInternal()->Suspend();
     }
   }
   topWin->mModalStateDepth++;
 }
 
 void
 nsGlobalWindow::LeaveModalState()
 {
   MOZ_ASSERT(IsOuterWindow(), "Modal state is maintained on outer windows");
 
-  nsGlobalWindow* topWin = GetScriptableTopInternal();
+  nsGlobalWindowOuter* topWin = GetScriptableTopInternal();
 
   if (!topWin) {
     NS_ERROR("Uh, LeaveModalState() called w/o a reachable top window?");
     return;
   }
 
   MOZ_ASSERT(topWin->mModalStateDepth != 0);
   MOZ_ASSERT(IsSuspended());
   MOZ_ASSERT(topWin->IsSuspended());
   topWin->mModalStateDepth--;
 
-  nsGlobalWindow* inner = topWin->GetCurrentInnerWindowInternal();
+  nsGlobalWindowInner* inner = topWin->GetCurrentInnerWindowInternal();
 
   if (topWin->mModalStateDepth == 0) {
     if (inner) {
       inner->Resume();
     }
 
     if (topWin->mSuspendedDoc) {
       nsCOMPtr<nsIDocument> currentDoc = topWin->GetExtantDoc();
@@ -9703,30 +9700,30 @@ nsGlobalWindow::LeaveModalState()
     bool dummy;
     topWin->DispatchEvent(event, &dummy);
   }
 }
 
 bool
 nsGlobalWindow::IsInModalState()
 {
-  nsGlobalWindow *topWin = GetScriptableTopInternal();
+  nsGlobalWindowOuter *topWin = GetScriptableTopInternal();
 
   if (!topWin) {
     // IsInModalState() getting called w/o a reachable top window is a bit
     // iffy, but valid enough not to make noise about it.  See bug 404828
     return false;
   }
 
   return topWin->mModalStateDepth != 0;
 }
 
 // static
 void
-nsGlobalWindow::NotifyDOMWindowDestroyed(nsGlobalWindow* aWindow) {
+nsGlobalWindow::NotifyDOMWindowDestroyed(nsGlobalWindowInner* aWindow) {
   nsCOMPtr<nsIObserverService> observerService =
     services::GetObserverService();
   if (observerService) {
     observerService->
       NotifyObservers(ToSupports(aWindow),
                       DOM_WINDOW_DESTROYED_TOPIC, nullptr);
   }
 }
@@ -9811,17 +9808,19 @@ public:
       }
       break;
 
       case Phase::Nuking:
       {
         nsCOMPtr<nsISupports> window = do_QueryReferent(mWindow);
         if (window) {
           nsGlobalWindow* win = nsGlobalWindow::FromSupports(window);
-          nsGlobalWindow* currentInner = win->IsInnerWindow() ? win : win->GetCurrentInnerWindowInternal();
+          nsGlobalWindowInner* currentInner = win->IsInnerWindow()
+            ? win->AssertInner()
+            : win->GetCurrentInnerWindowInternal();
           NS_ENSURE_TRUE(currentInner, NS_OK);
 
           AutoSafeJSContext cx;
           JS::Rooted<JSObject*> obj(cx, currentInner->FastGetGlobalJSObject());
           if (obj && !js::IsSystemCompartment(js::GetObjectCompartment(obj))) {
             JSCompartment* cpt = js::GetObjectCompartment(obj);
             nsCOMPtr<nsIPrincipal> pc = nsJSPrincipals::get(JS_GetCompartmentPrincipals(cpt));
 
@@ -9860,32 +9859,32 @@ nsGlobalWindow::NotifyWindowIDDestroyed(
   nsresult rv = Dispatch(TaskCategory::Other, runnable.forget());
   if (NS_SUCCEEDED(rv)) {
     mNotifiedIDDestroyed = true;
   }
 }
 
 // static
 void
-nsGlobalWindow::NotifyDOMWindowFrozen(nsGlobalWindow* aWindow) {
-  if (aWindow && aWindow->IsInnerWindow()) {
+nsGlobalWindow::NotifyDOMWindowFrozen(nsGlobalWindowInner* aWindow) {
+  if (aWindow) {
     nsCOMPtr<nsIObserverService> observerService =
       services::GetObserverService();
     if (observerService) {
       observerService->
         NotifyObservers(ToSupports(aWindow),
                         DOM_WINDOW_FROZEN_TOPIC, nullptr);
     }
   }
 }
 
 // static
 void
-nsGlobalWindow::NotifyDOMWindowThawed(nsGlobalWindow* aWindow) {
-  if (aWindow && aWindow->IsInnerWindow()) {
+nsGlobalWindow::NotifyDOMWindowThawed(nsGlobalWindowInner* aWindow) {
+  if (aWindow) {
     nsCOMPtr<nsIObserverService> observerService =
       services::GetObserverService();
     if (observerService) {
       observerService->
         NotifyObservers(ToSupports(aWindow),
                         DOM_WINDOW_THAWED_TOPIC, nullptr);
     }
   }
@@ -10173,17 +10172,17 @@ nsGlobalWindow::UpdateCommands(const nsA
   if (nsIDocShell* docShell = GetDocShell()) {
     if (nsCOMPtr<nsITabChild> child = docShell->GetTabChild()) {
       nsContentUtils::AddScriptRunner(new ChildCommandDispatcher(this, child,
                                                                  anAction));
       return NS_OK;
     }
   }
 
-  nsPIDOMWindowOuter *rootWindow = nsGlobalWindow::GetPrivateRoot();
+  nsPIDOMWindowOuter *rootWindow = GetPrivateRoot();
   if (!rootWindow)
     return NS_OK;
 
   nsCOMPtr<nsIDOMXULDocument> xulDoc =
     do_QueryInterface(rootWindow->GetExtantDoc());
   // See if we contain a XUL document.
   // selectionchange action is only used for mozbrowser, not for XUL. So we bypass
   // XUL command dispatch if anAction is "selectionchange".
@@ -10514,17 +10513,17 @@ nsGlobalWindow::GetPrivateParent()
 
   return parent;
 }
 
 nsPIDOMWindowOuter*
 nsGlobalWindow::GetPrivateRoot()
 {
   if (IsInnerWindow()) {
-    nsGlobalWindow* outer = GetOuterWindowInternal();
+    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
     if (!outer) {
       NS_WARNING("No outer window available!");
       return nullptr;
     }
     return outer->GetPrivateRoot();
   }
 
   nsCOMPtr<nsPIDOMWindowOuter> top = GetTop();
@@ -10643,17 +10642,17 @@ nsGlobalWindow::IsTopLevelWindowActive()
 
 void nsGlobalWindow::SetIsBackground(bool aIsBackground)
 {
   MOZ_ASSERT(IsOuterWindow());
 
   bool changed = aIsBackground != AsOuter()->IsBackground();
   SetIsBackgroundInternal(aIsBackground);
 
-  nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
+  nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal();
 
   if (inner && changed) {
     inner->mTimeoutManager->UpdateBackgroundState();
   }
 
   if (aIsBackground) {
     // Notify gamepadManager we are at the background window,
     // we need to stop vibrate.
@@ -10962,17 +10961,17 @@ nsGlobalWindow::PageHidden()
   mNeedsFocus = true;
 }
 
 class HashchangeCallback : public Runnable
 {
 public:
   HashchangeCallback(const nsAString& aOldURL,
                      const nsAString& aNewURL,
-                     nsGlobalWindow* aWindow)
+                     nsGlobalWindowInner* aWindow)
     : mozilla::Runnable("HashchangeCallback")
     , mWindow(aWindow)
   {
     MOZ_ASSERT(mWindow);
     MOZ_ASSERT(mWindow->IsInnerWindow());
     mOldURL.Assign(aOldURL);
     mNewURL.Assign(aNewURL);
   }
@@ -10981,17 +10980,17 @@ public:
   {
     NS_PRECONDITION(NS_IsMainThread(), "Should be called on the main thread.");
     return mWindow->FireHashchange(mOldURL, mNewURL);
   }
 
 private:
   nsString mOldURL;
   nsString mNewURL;
-  RefPtr<nsGlobalWindow> mWindow;
+  RefPtr<nsGlobalWindowInner> mWindow;
 };
 
 nsresult
 nsGlobalWindow::DispatchAsyncHashchange(nsIURI *aOldURI, nsIURI *aNewURI)
 {
   MOZ_RELEASE_ASSERT(IsInnerWindow());
 
   // Make sure that aOldURI and aNewURI are identical up to the '#', and that
@@ -11011,17 +11010,17 @@ nsGlobalWindow::DispatchAsyncHashchange(
   NS_ENSURE_SUCCESS(rv, rv);
   rv = aNewURI->GetSpec(newSpec);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ConvertUTF8toUTF16 oldWideSpec(oldSpec);
   NS_ConvertUTF8toUTF16 newWideSpec(newSpec);
 
   nsCOMPtr<nsIRunnable> callback =
-    new HashchangeCallback(oldWideSpec, newWideSpec, this);
+    new HashchangeCallback(oldWideSpec, newWideSpec, AssertInner());
   return Dispatch(TaskCategory::Other, callback.forget());
 }
 
 nsresult
 nsGlobalWindow::FireHashchange(const nsAString &aOldURL,
                                const nsAString &aNewURL)
 {
   MOZ_ASSERT(IsInnerWindow());
@@ -11418,40 +11417,40 @@ nsGlobalWindow::GetIndexedDB(ErrorResult
 
 NS_IMETHODIMP
 nsGlobalWindow::GetInterface(const nsIID & aIID, void **aSink)
 {
   NS_ENSURE_ARG_POINTER(aSink);
   *aSink = nullptr;
 
   if (aIID.Equals(NS_GET_IID(nsIDocCharset))) {
-    nsGlobalWindow* outer = GetOuterWindowInternal();
+    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
     NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 
     NS_WARNING("Using deprecated nsIDocCharset: use nsIDocShell.GetCharset() instead ");
     nsCOMPtr<nsIDocCharset> docCharset(do_QueryInterface(outer->mDocShell));
     docCharset.forget(aSink);
   }
   else if (aIID.Equals(NS_GET_IID(nsIWebNavigation))) {
-    nsGlobalWindow* outer = GetOuterWindowInternal();
+    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
     NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 
     nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(outer->mDocShell));
     webNav.forget(aSink);
   }
   else if (aIID.Equals(NS_GET_IID(nsIDocShell))) {
-    nsGlobalWindow* outer = GetOuterWindowInternal();
+    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
     NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 
     nsCOMPtr<nsIDocShell> docShell = outer->mDocShell;
     docShell.forget(aSink);
   }
 #ifdef NS_PRINTING
   else if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint))) {
-    nsGlobalWindow* outer = GetOuterWindowInternal();
+    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
     NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 
     if (outer->mDocShell) {
       nsCOMPtr<nsIContentViewer> viewer;
       outer->mDocShell->GetContentViewer(getter_AddRefs(viewer));
       if (viewer) {
         nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
         webBrowserPrint.forget(aSink);
@@ -11466,17 +11465,17 @@ nsGlobalWindow::GetInterface(const nsIID
     if (!mWindowUtils) {
       mWindowUtils = new nsDOMWindowUtils(outer);
     }
 
     *aSink = mWindowUtils;
     NS_ADDREF(((nsISupports *) *aSink));
   }
   else if (aIID.Equals(NS_GET_IID(nsILoadContext))) {
-    nsGlobalWindow* outer = GetOuterWindowInternal();
+    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
     NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 
     nsCOMPtr<nsILoadContext> loadContext(do_QueryInterface(outer->mDocShell));
     loadContext.forget(aSink);
   }
   else {
     return QueryInterface(aIID, aSink);
   }
@@ -11576,17 +11575,17 @@ nsGlobalWindow::FireOfflineStatusEventIf
 }
 
 class NotifyIdleObserverRunnable : public Runnable
 {
 public:
   NotifyIdleObserverRunnable(nsIIdleObserver* aIdleObserver,
                              uint32_t aTimeInS,
                              bool aCallOnidle,
-                             nsGlobalWindow* aIdleWindow)
+                             nsGlobalWindowInner* aIdleWindow)
     : mozilla::Runnable("NotifyIdleObserverRunnable")
     , mIdleObserver(aIdleObserver)
     , mTimeInS(aTimeInS)
     , mIdleWindow(aIdleWindow)
     , mCallOnidle(aCallOnidle)
   { }
 
   NS_IMETHOD Run() override
@@ -11595,33 +11594,34 @@ public:
       return mCallOnidle ? mIdleObserver->Onidle() : mIdleObserver->Onactive();
     }
     return NS_OK;
   }
 
 private:
   nsCOMPtr<nsIIdleObserver> mIdleObserver;
   uint32_t mTimeInS;
-  RefPtr<nsGlobalWindow> mIdleWindow;
+  RefPtr<nsGlobalWindowInner> mIdleWindow;
 
   // If false then call on active
   bool mCallOnidle;
 };
 
 void
 nsGlobalWindow::NotifyIdleObserver(IdleObserverHolder* aIdleObserverHolder,
                                    bool aCallOnidle)
 {
+  MOZ_ASSERT(IsInnerWindow());
   MOZ_ASSERT(aIdleObserverHolder);
   aIdleObserverHolder->mPrevNotificationIdle = aCallOnidle;
 
   nsCOMPtr<nsIRunnable> caller =
     new NotifyIdleObserverRunnable(aIdleObserverHolder->mIdleObserver,
                                    aIdleObserverHolder->mTimeInS,
-                                   aCallOnidle, this);
+                                   aCallOnidle, AssertInner());
   if (NS_FAILED(Dispatch(TaskCategory::Other, caller.forget()))) {
     NS_WARNING("Failed to dispatch thread for idle observer notification.");
   }
 }
 
 bool
 nsGlobalWindow::ContainsIdleObserver(nsIIdleObserver* aIdleObserver, uint32_t aTimeInS)
 {
@@ -11637,25 +11637,27 @@ nsGlobalWindow::ContainsIdleObserver(nsI
     }
   }
   return found;
 }
 
 void
 IdleActiveTimerCallback(nsITimer* aTimer, void* aClosure)
 {
-  RefPtr<nsGlobalWindow> idleWindow = static_cast<nsGlobalWindow*>(aClosure);
+  RefPtr<nsGlobalWindowInner> idleWindow =
+    static_cast<nsGlobalWindowInner*>(aClosure);
   MOZ_ASSERT(idleWindow, "Idle window has not been instantiated.");
   idleWindow->HandleIdleActiveEvent();
 }
 
 void
 IdleObserverTimerCallback(nsITimer* aTimer, void* aClosure)
 {
-  RefPtr<nsGlobalWindow> idleWindow = static_cast<nsGlobalWindow*>(aClosure);
+  RefPtr<nsGlobalWindowInner> idleWindow =
+    static_cast<nsGlobalWindowInner*>(aClosure);
   MOZ_ASSERT(idleWindow, "Idle window has not been instantiated.");
   idleWindow->HandleIdleObserverCallback();
 }
 
 void
 nsGlobalWindow::HandleIdleObserverCallback()
 {
   MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
@@ -11690,31 +11692,31 @@ nsGlobalWindow::ScheduleNextIdleObserver
   uint32_t callbackTimeMS = 0;
   if (idleObserver.mTimeInS * 1000 + mIdleFuzzFactor > userIdleTimeMS) {
     callbackTimeMS = idleObserver.mTimeInS * 1000 - userIdleTimeMS + mIdleFuzzFactor;
   }
 
   mIdleTimer->Cancel();
   rv = mIdleTimer->InitWithNamedFuncCallback(
     IdleObserverTimerCallback,
-    this,
+    AssertInner(),
     callbackTimeMS,
     nsITimer::TYPE_ONE_SHOT,
     "nsGlobalWindow::ScheduleNextIdleObserverCallback");
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 uint32_t
 nsGlobalWindow::GetFuzzTimeMS()
 {
   MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 
-  if (sIdleObserversAPIFuzzTimeDisabled) {
+  if (gIdleObserversAPIFuzzTimeDisabled) {
     return 0;
   }
 
   uint32_t randNum = MAX_IDLE_FUZZ_TIME_MS;
   size_t nbytes = PR_GetRandomNoise(&randNum, sizeof(randNum));
   if (nbytes != sizeof(randNum)) {
     NS_WARNING("PR_GetRandomNoise(...) Not implemented or no available noise!");
     return MAX_IDLE_FUZZ_TIME_MS;
@@ -11737,17 +11739,17 @@ nsGlobalWindow::ScheduleActiveTimerCallb
   }
 
   MOZ_ASSERT(mIdleTimer);
   mIdleTimer->Cancel();
 
   uint32_t fuzzFactorInMS = GetFuzzTimeMS();
   nsresult rv = mIdleTimer->InitWithNamedFuncCallback(
     IdleActiveTimerCallback,
-    this,
+    AssertInner(),
     fuzzFactorInMS,
     nsITimer::TYPE_ONE_SHOT,
     "nsGlobalWindow::ScheduleActiveTimerCallback");
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
 nsresult
@@ -11836,17 +11838,17 @@ nsGlobalWindow::ShowSlowScriptDialog(con
     if (action == ProcessHangMonitor::TerminateGlobal) {
       return KillScriptGlobal;
     }
 
     if (action == ProcessHangMonitor::StartDebugger) {
       // Spin a nested event loop so that the debugger in the parent can fetch
       // any information it needs. Once the debugger has started, return to the
       // script.
-      RefPtr<nsGlobalWindow> outer = GetOuterWindowInternal();
+      RefPtr<nsGlobalWindowOuter> outer = GetOuterWindowInternal();
       outer->EnterModalState();
       SpinEventLoopUntil([&]() { return monitor->IsDebuggerStartupComplete(); });
       outer->LeaveModalState();
       return ContinueSlowScript;
     }
 
     return ContinueSlowScriptAndKeepNotifying;
   }
@@ -12567,17 +12569,19 @@ nsGlobalWindow::FreezeInternal()
   if (mFreezeDepth != 1) {
     return;
   }
 
   mozilla::dom::workers::FreezeWorkersForWindow(AsInner());
 
   mTimeoutManager->Freeze();
 
-  NotifyDOMWindowFrozen(this);
+  if (IsInnerWindow()) {
+    NotifyDOMWindowFrozen(AssertInner());
+  }
 }
 
 void
 nsGlobalWindow::Thaw()
 {
   MOZ_ASSERT(NS_IsMainThread());
   ThawInternal();
   Resume();
@@ -12599,17 +12603,19 @@ nsGlobalWindow::ThawInternal()
   if (mFreezeDepth != 0) {
     return;
   }
 
   mTimeoutManager->Thaw();
 
   mozilla::dom::workers::ThawWorkersForWindow(AsInner());
 
-  NotifyDOMWindowThawed(this);
+  if (IsInnerWindow()) {
+    NotifyDOMWindowThawed(AssertInner());
+  }
 }
 
 bool
 nsGlobalWindow::IsFrozen() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   // No inner means we are effectively frozen
   if (IsOuterWindow()) {
@@ -12753,17 +12759,17 @@ nsGlobalWindow::FireDelayedDOMEvents()
 //*****************************************************************************
 // nsGlobalWindow: Window Control Functions
 //*****************************************************************************
 
 nsPIDOMWindowOuter*
 nsGlobalWindow::GetParentInternal()
 {
   if (IsInnerWindow()) {
-    nsGlobalWindow* outer = GetOuterWindowInternal();
+    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
     if (!outer) {
       // No outer window available!
       return nullptr;
     }
     return outer->GetParentInternal();
   }
 
   nsCOMPtr<nsPIDOMWindowOuter> parent = GetParent();
@@ -12780,19 +12786,19 @@ nsGlobalWindow::UnblockScriptedClosing()
 {
   MOZ_ASSERT(IsOuterWindow());
   mBlockScriptedClosingFlag = false;
 }
 
 class AutoUnblockScriptClosing
 {
 private:
-  RefPtr<nsGlobalWindow> mWin;
+  RefPtr<nsGlobalWindowOuter> mWin;
 public:
-  explicit AutoUnblockScriptClosing(nsGlobalWindow* aWin)
+  explicit AutoUnblockScriptClosing(nsGlobalWindowOuter* aWin)
     : mWin(aWin)
   {
     MOZ_ASSERT(mWin);
     MOZ_ASSERT(mWin->IsOuterWindow());
   }
   ~AutoUnblockScriptClosing()
   {
     void (nsGlobalWindow::*run)() = &nsGlobalWindow::UnblockScriptedClosing;
@@ -12899,17 +12905,17 @@ nsGlobalWindow::OpenInternal(const nsASt
         // so that whatever popup blocker UI the app has will be visible.
         nsCOMPtr<nsPIDOMWindowInner> entryWindow =
           do_QueryInterface(GetEntryGlobal());
         // Note that entryWindow can be null here if some JS component was the
         // place where script was entered for this JS execution.
         if (entryWindow &&
             entryWindow->GetOuterWindow() == this->AsOuter()) {
           mBlockScriptedClosingFlag = true;
-          closeUnblocker.emplace(this);
+          closeUnblocker.emplace(AssertOuter());
         }
       }
 
       FireAbuseEvents(aUrl, aName, aOptions);
       return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
     }
   }
 
@@ -13009,23 +13015,23 @@ nsGlobalWindow::OpenInternal(const nsASt
 
 //*****************************************************************************
 // nsGlobalWindow: Timeout Functions
 //*****************************************************************************
 
 nsGlobalWindowInner*
 nsGlobalWindow::InnerForSetTimeoutOrInterval(ErrorResult& aError)
 {
-  nsGlobalWindow* currentInner;
-  nsGlobalWindow* forwardTo;
+  nsGlobalWindowInner* currentInner;
+  nsGlobalWindowInner* forwardTo;
   if (IsInnerWindow()) {
-    nsGlobalWindow* outer = GetOuterWindowInternal();
-    currentInner = outer ? outer->GetCurrentInnerWindowInternal() : this;
-
-    forwardTo = this;
+    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
+    currentInner = outer ? outer->GetCurrentInnerWindowInternal() : AssertInner();
+
+    forwardTo = AssertInner();
   } else {
     currentInner = GetCurrentInnerWindowInternal();
 
     // This needs to forward to the inner window, but since the current
     // inner may not be the inner in the calling scope, we need to treat
     // this specially here as we don't want timeouts registered in a
     // dying inner window to get registered and run on the current inner
     // window. To get this right, we need to forward this call to the
@@ -13046,26 +13052,24 @@ nsGlobalWindow::InnerForSetTimeoutOrInte
     if (forwardTo->GetOuterWindow() != AsOuter() ||
         !forwardTo->IsInnerWindow()) {
       if (!currentInner) {
         NS_WARNING("No inner window available!");
         aError.Throw(NS_ERROR_NOT_INITIALIZED);
         return nullptr;
       }
 
-      return static_cast<nsGlobalWindowInner*>(currentInner);
+      return currentInner;
     }
   }
 
   // If forwardTo is not the window with an active document then we want the
   // call to setTimeout/Interval to be a noop, so return null but don't set an
   // error.
-  return forwardTo->AsInner()->HasActiveDocument()
-    ? static_cast<nsGlobalWindowInner*>(currentInner)
-    : nullptr;
+  return forwardTo->AsInner()->HasActiveDocument() ? currentInner : nullptr;
 }
 
 int32_t
 nsGlobalWindow::SetTimeout(JSContext* aCx, Function& aFunction,
                            int32_t aTimeout,
                            const Sequence<JS::Value>& aArguments,
                            ErrorResult& aError)
 {
@@ -13120,17 +13124,17 @@ nsGlobalWindow::SetInterval(JSContext* a
 }
 
 int32_t
 nsGlobalWindow::SetTimeoutOrInterval(JSContext *aCx, Function& aFunction,
                                      int32_t aTimeout,
                                      const Sequence<JS::Value>& aArguments,
                                      bool aIsInterval, ErrorResult& aError)
 {
-  nsGlobalWindow* inner = InnerForSetTimeoutOrInterval(aError);
+  nsGlobalWindowInner* inner = InnerForSetTimeoutOrInterval(aError);
   if (!inner) {
     return -1;
   }
 
   if (inner != this) {
     return inner->SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments,
                                        aIsInterval, aError);
   }
@@ -13148,17 +13152,17 @@ nsGlobalWindow::SetTimeoutOrInterval(JSC
   return result;
 }
 
 int32_t
 nsGlobalWindow::SetTimeoutOrInterval(JSContext* aCx, const nsAString& aHandler,
                                      int32_t aTimeout, bool aIsInterval,
                                      ErrorResult& aError)
 {
-  nsGlobalWindow* inner = InnerForSetTimeoutOrInterval(aError);
+  nsGlobalWindowInner* inner = InnerForSetTimeoutOrInterval(aError);
   if (!inner) {
     return -1;
   }
 
   if (inner != this) {
     return inner->SetTimeoutOrInterval(aCx, aHandler, aTimeout, aIsInterval,
                                        aError);
   }
@@ -13415,33 +13419,33 @@ nsGlobalWindow::FlushPendingNotification
 void
 nsGlobalWindow::EnsureSizeAndPositionUpToDate()
 {
   MOZ_ASSERT(IsOuterWindow());
 
   // If we're a subframe, make sure our size is up to date.  It's OK that this
   // crosses the content/chrome boundary, since chrome can have pending reflows
   // too.
-  nsGlobalWindow *parent = nsGlobalWindowOuter::Cast(GetPrivateParent());
+  nsGlobalWindowOuter *parent = nsGlobalWindowOuter::Cast(GetPrivateParent());
   if (parent) {
     parent->FlushPendingNotifications(FlushType::Layout);
   }
 }
 
 already_AddRefed<nsISupports>
 nsGlobalWindow::SaveWindowState()
 {
   NS_PRECONDITION(IsOuterWindow(), "Can't save the inner window's state");
 
   if (!mContext || !GetWrapperPreserveColor()) {
     // The window may be getting torn down; don't bother saving state.
     return nullptr;
   }
 
-  nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
+  nsGlobalWindowInner *inner = GetCurrentInnerWindowInternal();
   NS_ASSERTION(inner, "No inner window to save");
 
   // Don't do anything else to this inner window! After this point, all
   // calls to SetTimeoutOrInterval will create entries in the timeout
   // list that will only run after this window has come out of the bfcache.
   // Also, while we're frozen, we won't dispatch online/offline events
   // to the page.
   inner->Freeze();
@@ -13468,17 +13472,17 @@ nsGlobalWindow::RestoreWindowState(nsISu
   nsCOMPtr<WindowStateHolder> holder = do_QueryInterface(aState);
   NS_ENSURE_TRUE(holder, NS_ERROR_FAILURE);
 
 #ifdef DEBUG_PAGE_CACHE
   printf("restoring window state, state = %p\n", (void*)holder);
 #endif
 
   // And we're ready to go!
-  nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
+  nsGlobalWindowInner *inner = GetCurrentInnerWindowInternal();
 
   // if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes
   // it easy to tell which link was last clicked when going back a page.
   nsIContent* focusedNode = inner->GetFocusedNode();
   if (IsLink(focusedNode)) {
     nsIFocusManager* fm = nsFocusManager::GetFocusManager();
     if (fm) {
       nsCOMPtr<nsIDOMElement> focusedElement(do_QueryInterface(focusedNode));
@@ -14018,33 +14022,16 @@ nsGlobalWindow::DispatchVRDisplayPresent
       Unused << DispatchEvent(event, &defaultActionEnabled);
       // Once we dispatch the event, we must not access any members as an event
       // listener can do anything, including closing windows.
       return;
     }
   }
 }
 
-/* static */ already_AddRefed<nsGlobalWindow>
-nsGlobalWindow::CreateChrome(nsGlobalWindow *aOuterWindow)
-{
-  RefPtr<nsGlobalWindow> window;
-  if (aOuterWindow) {
-    window = new nsGlobalWindowInner(
-      static_cast<nsGlobalWindowOuter*>(aOuterWindow));
-  } else {
-    window = new nsGlobalWindowOuter();
-  }
-  window->mIsChrome = true;
-  window->mCleanMessageManager = true;
-
-  window->InitWasOffline();
-  return window.forget();
-}
-
 enum WindowState {
   // These constants need to match the constants in Window.webidl
   STATE_MAXIMIZED = 1,
   STATE_MINIMIZED = 2,
   STATE_NORMAL = 3,
   STATE_FULLSCREEN = 4
 };
 
@@ -14415,30 +14402,16 @@ nsGlobalWindow::TakeOpenerForInitialCont
 {
   MOZ_RELEASE_ASSERT(IsChromeWindow());
   MOZ_RELEASE_ASSERT(IsOuterWindow());
   // Intentionally forget our own member
   mChromeFields.mOpenerForInitialContentBrowser.forget(aOpenerWindow);
   return NS_OK;
 }
 
-/* static */ already_AddRefed<nsGlobalWindow>
-nsGlobalWindow::Create(nsGlobalWindow *aOuterWindow)
-{
-  RefPtr<nsGlobalWindow> window;
-  if (aOuterWindow) {
-    window = new nsGlobalWindowInner(
-      static_cast<nsGlobalWindowOuter*>(aOuterWindow));
-  } else {
-    window = new nsGlobalWindowOuter();
-  }
-  window->InitWasOffline();
-  return window.forget();
-}
-
 void
 nsGlobalWindow::InitWasOffline()
 {
   mWasOffline = NS_IsOffline();
 }
 
 #if defined(MOZ_WIDGET_ANDROID)
 int16_t
@@ -14654,17 +14627,17 @@ nsGlobalWindow::SetReplaceableWindowCoor
                                           ErrorResult& aError)
 {
   MOZ_ASSERT(IsInnerWindow());
 
   /*
    * If caller is not chrome and the user has not explicitly exempted the site,
    * just treat this the way we would an IDL replaceable property.
    */
-  nsGlobalWindow* outer = GetOuterWindowInternal();
+  nsGlobalWindowOuter* outer = GetOuterWindowInternal();
   if (!outer ||
       !outer->CanMoveResizeWindows(aCallerType) ||
       outer->IsFrame()) {
     RedefineProperty(aCx, aPropName, aValue, aError);
     return;
   }
 
   int32_t value;
@@ -14916,50 +14889,53 @@ nsGlobalWindow::TabGroupOuter()
 mozilla::dom::TabGroup*
 nsGlobalWindow::TabGroupInner()
 {
   MOZ_RELEASE_ASSERT(IsInnerWindow());
 
   // If we don't have a TabGroup yet, try to get it from the outer window and
   // cache it.
   if (!mTabGroup) {
-    nsGlobalWindow* outer = GetOuterWindowInternal();
+    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
     // This will never be called without either an outer window, or a cached tab group.
     // This is because of the following:
     // * This method is only called on inner windows
     // * This method is called as a document is attached to it's script global
     //   by the document
     // * Inner windows are created in nsGlobalWindow::SetNewDocument, which
     //   immediately sets a document, which will call this method, causing
     //   the TabGroup to be cached.
     MOZ_RELEASE_ASSERT(outer, "Inner window without outer window has no cached tab group!");
     mTabGroup = outer->TabGroup();
   }
   MOZ_ASSERT(mTabGroup);
 
 #ifdef DEBUG
-  nsGlobalWindow* outer = GetOuterWindowInternal();
+  nsGlobalWindowOuter* outer = GetOuterWindowInternal();
   MOZ_ASSERT_IF(outer, outer->TabGroup() == mTabGroup);
 #endif
 
   return mTabGroup;
 }
 
 template<typename T>
 mozilla::dom::TabGroup*
 nsPIDOMWindow<T>::TabGroup()
 {
-  nsGlobalWindow* globalWindow =
-    static_cast<nsGlobalWindow*>(
+  if (IsInnerWindow()) {
+    nsGlobalWindowInner* globalWindow =
+      static_cast<nsGlobalWindowInner*>(
         reinterpret_cast<nsPIDOMWindow<nsISupports>*>(this));
-
-  if (IsInnerWindow()) {
     return globalWindow->TabGroupInner();
-  }
-  return globalWindow->TabGroupOuter();
+  } else {
+    nsGlobalWindowOuter* globalWindow =
+      static_cast<nsGlobalWindowOuter*>(
+        reinterpret_cast<nsPIDOMWindow<nsISupports>*>(this));
+    return globalWindow->TabGroupOuter();
+  }
 }
 
 template<typename T>
 mozilla::dom::DocGroup*
 nsPIDOMWindow<T>::GetDocGroup() const
 {
   nsIDocument* doc = GetExtantDoc();
   if (doc) {
@@ -14995,30 +14971,31 @@ nsGlobalWindow::AbstractMainThreadFor(Ta
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   if (GetDocGroup()) {
     return GetDocGroup()->AbstractMainThreadFor(aCategory);
   }
   return DispatcherTrait::AbstractMainThreadFor(aCategory);
 }
 
 nsGlobalWindow::TemporarilyDisableDialogs::TemporarilyDisableDialogs(
-  nsGlobalWindow* aWindow MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+  nsGlobalWindowOuter* aWindow MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
 {
   MOZ_GUARD_OBJECT_NOTIFIER_INIT;
 
   MOZ_ASSERT(aWindow);
-  nsGlobalWindow* topWindow = aWindow->GetScriptableTopInternal();
-  if (!topWindow) {
+  nsGlobalWindowOuter* topWindowOuter = aWindow->GetScriptableTopInternal();
+  if (!topWindowOuter) {
     NS_ERROR("nsGlobalWindow::TemporarilyDisableDialogs used without a top "
              "window?");
     return;
   }
 
   // TODO: Warn if no top window?
-  topWindow = topWindow->GetCurrentInnerWindowInternal();
+  nsGlobalWindowInner* topWindow =
+    topWindowOuter->GetCurrentInnerWindowInternal();
   if (topWindow) {
     mTopWindow = topWindow;
     mSavedDialogsEnabled = mTopWindow->mAreDialogsEnabled;
     mTopWindow->mAreDialogsEnabled = false;
   }
 }
 
 nsGlobalWindow::TemporarilyDisableDialogs::~TemporarilyDisableDialogs()
@@ -15104,16 +15081,29 @@ nsGlobalWindowOuter::nsGlobalWindowOuter
 
 nsGlobalWindowOuter::~nsGlobalWindowOuter()
 {
   // NOTE: We remove ourselves from the sOuterWindowsById table in
   // nsGlobalWindow::~nsGlobalWindow. We can't do it here because we have to
   // remove ourselves before running some cleanup in that function.
 }
 
+/* static */ already_AddRefed<nsGlobalWindowOuter>
+nsGlobalWindowOuter::Create(bool aIsChrome)
+{
+  RefPtr<nsGlobalWindowOuter> window = new nsGlobalWindowOuter();
+  if (aIsChrome) {
+    window->mIsChrome = true;
+    window->mCleanMessageManager = true;
+  }
+
+  window->InitWasOffline();
+  return window.forget();
+}
+
 nsGlobalWindowInner::nsGlobalWindowInner(nsGlobalWindowOuter* aOuterWindow)
   : nsGlobalWindow(aOuterWindow)
 {
   // Add ourselves to the inner windows list.
   MOZ_ASSERT(sInnerWindowsById, "Inner Windows hash table must be created!");
   MOZ_ASSERT(!sInnerWindowsById->Get(mWindowID),
              "This window shouldn't be in the hash table yet!");
   // We seem to see crashes in release builds because of null |sInnerWindowsById|.
@@ -15127,11 +15117,24 @@ nsGlobalWindowInner::nsGlobalWindowInner
 
 nsGlobalWindowInner::~nsGlobalWindowInner()
 {
   // NOTE: We remove ourselves from the sInnerWindowsById table in
   // nsGlobalWindow::~nsGlobalWindow. We can't do it here because we have to
   // remove ourselves before running some cleanup in that function.
 }
 
+/* static */ already_AddRefed<nsGlobalWindowInner>
+nsGlobalWindowInner::Create(nsGlobalWindowOuter *aOuterWindow, bool aIsChrome)
+{
+  RefPtr<nsGlobalWindowInner> window = new nsGlobalWindowInner(aOuterWindow);
+  if (aIsChrome) {
+    window->mIsChrome = true;
+    window->mCleanMessageManager = true;
+  }
+
+  window->InitWasOffline();
+  return window.forget();
+}
+
 template class nsPIDOMWindow<mozIDOMWindowProxy>;
 template class nsPIDOMWindow<mozIDOMWindow>;
 template class nsPIDOMWindow<nsISupports>;
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -464,19 +464,16 @@ public:
   // The return value is whether DoResolve might end up resolving the given id.
   // If in doubt, return true.
   static bool MayResolve(jsid aId);
 
   void GetOwnPropertyNames(JSContext* aCx, JS::AutoIdVector& aNames,
                            bool aEnumerableOnly, mozilla::ErrorResult& aRv);
 
   // Object Management
-  static already_AddRefed<nsGlobalWindow> Create(nsGlobalWindow *aOuterWindow);
-  static already_AddRefed<nsGlobalWindow> CreateChrome(nsGlobalWindow *aOuterWindow);
-
   static nsGlobalWindow *FromSupports(nsISupports *supports)
   {
     // Make sure this matches the casts we do in QueryInterface().
     return (nsGlobalWindow *)(mozilla::dom::EventTarget *)supports;
   }
   static nsGlobalWindow *FromWrapper(nsIXPConnectWrappedNative *wrapper)
   {
     return FromSupports(wrapper->Native());
@@ -510,28 +507,27 @@ public:
   void EnableDialogs();
   void DisableDialogs();
   // Outer windows only.
   bool AreDialogsEnabled();
 
   class MOZ_RAII TemporarilyDisableDialogs
   {
   public:
-    // Takes an inner _or_ outer window.
-    explicit TemporarilyDisableDialogs(nsGlobalWindow* aWindow
+    explicit TemporarilyDisableDialogs(nsGlobalWindowOuter* aWindow
                                        MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
     ~TemporarilyDisableDialogs();
 
   private:
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 
     // Always an inner window; this is the window whose dialog state we messed
     // with.  We just want to keep it alive, because we plan to poke at its
     // members in our destructor.
-    RefPtr<nsGlobalWindow> mTopWindow;
+    RefPtr<nsGlobalWindowInner> mTopWindow;
     // This is not a AutoRestore<bool> because that would require careful
     // member destructor ordering, which is a bit fragile.  This way we can
     // explicitly restore things before we drop our ref to mTopWindow.
     bool mSavedDialogsEnabled;
   };
   friend class TemporarilyDisableDialogs;
 
   nsIScriptContext *GetContextInternal();
@@ -809,17 +805,17 @@ public:
   already_AddRefed<nsIDOMWindowCollection> GetFrames() override;
   already_AddRefed<nsPIDOMWindowOuter> GetFrames(mozilla::ErrorResult& aError);
   uint32_t Length();
   already_AddRefed<nsPIDOMWindowOuter> GetTopOuter();
   already_AddRefed<nsPIDOMWindowOuter> GetTop(mozilla::ErrorResult& aError);
 
   nsresult GetPrompter(nsIPrompt** aPrompt) override;
 protected:
-  explicit nsGlobalWindow(nsGlobalWindow *aOuterWindow);
+  explicit nsGlobalWindow(nsGlobalWindowOuter *aOuterWindow);
   nsPIDOMWindowOuter* GetOpenerWindowOuter();
   // Initializes the mWasOffline member variable
   void InitWasOffline();
 public:
   nsPIDOMWindowOuter*
   GetSanitizedOpener(nsPIDOMWindowOuter* aOpener);
 
   nsPIDOMWindowOuter* GetOpenerWindow(mozilla::ErrorResult& aError);
@@ -1361,35 +1357,28 @@ protected:
   // Set to true when a fuzz time needs to be applied
   // to active notifications to the idle observer.
   bool mAddActiveEventFuzzTime;
 
   nsCOMPtr <nsIIdleService> mIdleService;
 
   RefPtr<mozilla::dom::WakeLock> mWakeLock;
 
-  static bool sIdleObserversAPIFuzzTimeDisabled;
-
   friend class HashchangeCallback;
   friend class mozilla::dom::BarProp;
 
   // Object Management
   virtual ~nsGlobalWindow();
   void DropOuterWindowDocs();
   void CleanUp();
   void ClearControllers();
   // Outer windows only.
   void FinalClose();
 
-  inline void MaybeClearInnerWindow(nsGlobalWindow* aExpectedInner)
-  {
-    if(mInnerWindow == aExpectedInner->AsInner()) {
-      mInnerWindow = nullptr;
-    }
-  }
+  inline void MaybeClearInnerWindow(nsGlobalWindowInner* aExpectedInner);
 
   void FreeInnerObjects();
   nsGlobalWindowInner *CallerInnerWindow();
 
   // Only to be called on an inner window.
   // aDocument must not be null.
   void InnerSetNewDocument(JSContext* aCx, nsIDocument* aDocument);
 
@@ -1611,21 +1600,21 @@ public:
 
   // Inner windows only.
   void UpdateCanvasFocus(bool aFocusChanged, nsIContent* aNewContent);
 
 public:
   virtual already_AddRefed<nsPIWindowRoot> GetTopWindowRoot() override;
 
 protected:
-  static void NotifyDOMWindowDestroyed(nsGlobalWindow* aWindow);
+  static void NotifyDOMWindowDestroyed(nsGlobalWindowInner* aWindow);
   void NotifyWindowIDDestroyed(const char* aTopic);
 
-  static void NotifyDOMWindowFrozen(nsGlobalWindow* aWindow);
-  static void NotifyDOMWindowThawed(nsGlobalWindow* aWindow);
+  static void NotifyDOMWindowFrozen(nsGlobalWindowInner* aWindow);
+  static void NotifyDOMWindowThawed(nsGlobalWindowInner* aWindow);
 
   void ClearStatus();
 
   virtual void UpdateParentTarget() override;
 
   void InitializeShowFocusRings();
 
   // Clear the document-dependent slots on our JS wrapper.  Inner windows only.
@@ -2007,16 +1996,17 @@ ToCanonicalSupports(nsGlobalWindow *p)
 }
 
 class nsGlobalWindowOuter : public nsGlobalWindow
 {
 public:
   typedef nsDataHashtable<nsUint64HashKey, nsGlobalWindowOuter*> OuterWindowByIdTable;
 
   friend class nsGlobalWindow;
+  friend class nsGlobalWindowInner;
 
   static nsGlobalWindowOuter* Cast(nsPIDOMWindowOuter* aPIWin) {
     return static_cast<nsGlobalWindowOuter*>(
                         reinterpret_cast<nsPIDOMWindow<nsISupports>*>(aPIWin));
   }
   static const nsGlobalWindowOuter* Cast(const nsPIDOMWindowOuter* aPIWin) {
     return static_cast<const nsGlobalWindowOuter*>(
                         reinterpret_cast<const nsPIDOMWindow<nsISupports>*>(aPIWin));
@@ -2041,29 +2031,38 @@ public:
   }
 
   static OuterWindowByIdTable* GetWindowsTable() {
     AssertIsOnMainThread();
 
     return sOuterWindowsById;
   }
 
+  static nsGlobalWindowOuter *FromSupports(nsISupports *supports)
+  {
+    // Make sure this matches the casts we do in QueryInterface().
+    return (nsGlobalWindowOuter *)(mozilla::dom::EventTarget *)supports;
+  }
+
+  static already_AddRefed<nsGlobalWindowOuter> Create(bool aIsChrome);
+
 private:
   nsGlobalWindowOuter();
   ~nsGlobalWindowOuter();
 
   static OuterWindowByIdTable* sOuterWindowsById;
 };
 
 class nsGlobalWindowInner : public nsGlobalWindow
 {
 public:
   typedef nsDataHashtable<nsUint64HashKey, nsGlobalWindowInner*> InnerWindowByIdTable;
 
   friend class nsGlobalWindow;
+  friend class nsGlobalWindowOuter;
 
   static nsGlobalWindowInner* Cast(nsPIDOMWindowInner* aPIWin) {
     return static_cast<nsGlobalWindowInner*>(
                         reinterpret_cast<nsPIDOMWindow<nsISupports>*>(aPIWin));
   }
   static const nsGlobalWindowInner* Cast(const nsPIDOMWindowInner* aPIWin) {
     return static_cast<const nsGlobalWindowInner*>(
                         reinterpret_cast<const nsPIDOMWindow<nsISupports>*>(aPIWin));
@@ -2089,17 +2088,26 @@ public:
   }
 
   static InnerWindowByIdTable* GetWindowsTable() {
     AssertIsOnMainThread();
 
     return sInnerWindowsById;
   }
 
+  static nsGlobalWindowInner *FromSupports(nsISupports *supports)
+  {
+    // Make sure this matches the casts we do in QueryInterface().
+    return (nsGlobalWindowInner *)(mozilla::dom::EventTarget *)supports;
+  }
+
 private:
+  static already_AddRefed<nsGlobalWindowInner>
+  Create(nsGlobalWindowOuter* aOuter, bool aIsChrome);
+
   explicit nsGlobalWindowInner(nsGlobalWindowOuter* aOuter);
   ~nsGlobalWindowInner();
 
   static InnerWindowByIdTable* sInnerWindowsById;
 };
 
 inline nsIGlobalObject*
 nsGlobalWindow::GetOwnerGlobal() const
@@ -2109,17 +2117,17 @@ nsGlobalWindow::GetOwnerGlobal() const
   }
 
   return const_cast<nsGlobalWindow*>(this);
 }
 
 inline nsGlobalWindowOuter*
 nsGlobalWindow::GetTopInternal()
 {
-  nsGlobalWindow* outer = IsOuterWindow() ? this : GetOuterWindowInternal();
+  nsGlobalWindowOuter* outer = IsOuterWindow() ? AssertOuter() : GetOuterWindowInternal();
   nsCOMPtr<nsPIDOMWindowOuter> top = outer ? outer->GetTop() : nullptr;
   if (top) {
     return nsGlobalWindowOuter::Cast(top);
   }
   return nullptr;
 }
 
 inline nsGlobalWindowOuter*
@@ -2191,24 +2199,24 @@ nsGlobalWindow::AssertInner()
 
 inline nsGlobalWindowOuter*
 nsGlobalWindow::AssertOuter()
 {
   MOZ_RELEASE_ASSERT(IsOuterWindow());
   return static_cast<nsGlobalWindowOuter*>(this);
 }
 
+inline void
+nsGlobalWindow::MaybeClearInnerWindow(nsGlobalWindowInner* aExpectedInner)
+{
+  if(mInnerWindow == aExpectedInner->AsInner()) {
+    mInnerWindow = nullptr;
+  }
+}
+
 /* factory function */
 inline already_AddRefed<nsGlobalWindowOuter>
 NS_NewScriptGlobalObject(bool aIsChrome)
 {
-  RefPtr<nsGlobalWindow> global;
-
-  if (aIsChrome) {
-    global = nsGlobalWindow::CreateChrome(nullptr);
-  } else {
-    global = nsGlobalWindow::Create(nullptr);
-  }
-
-  return global.forget().downcast<nsGlobalWindowOuter>();
+  return nsGlobalWindowOuter::Create(aIsChrome);
 }
 
 #endif /* nsGlobalWindow_h___ */