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 392015 8fdfee217a97f07574a600f2868b06646debaf48
parent 392014 fe6091ddbf6b74d022627ee0094a6113a3e4e883
child 392016 4a6c2c5490f454e53d3b962ea0ce9dd29c9da298
push id32909
push usercbrindusan@mozilla.com
push dateWed, 15 Nov 2017 22:25:14 +0000
treeherdermozilla-central@f41930a869a8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1415645
milestone59.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 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___ */