Backed out 7 changesets (bug 1364364) for causing bug 1399182.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 12 Sep 2017 13:21:17 -0400
changeset 429741 4069ad6982eabbab5b30fd45de159fe746e5a517
parent 429740 b0e945eed81db8bf076daf64e381c514f70144f0
child 429742 f02124dcec04ef4a5a325355762a05ab45467285
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1364364, 1399182
milestone57.0a1
backs outc517d8071dfbfa47d2f8da8699a59d314cb14b23
809036cfd7d9caa8f384efc5cfffd236c337c8a8
c394b06dc30c91f0e465d28351255e656c3286b5
c5a737bbfdebce7fcf3472047bc118aac955dc08
21ee8f318a478dc0e8210710d95e9f03f1dff683
074475da0f2ca66b29b9a26dd40067938f7191ce
de6c153ec533cd99d2f6bf6ea998e88e0c7d9188
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
Backed out 7 changesets (bug 1364364) for causing bug 1399182. Backed out changeset c517d8071dfb (bug 1364364) Backed out changeset 809036cfd7d9 (bug 1364364) Backed out changeset c394b06dc30c (bug 1364364) Backed out changeset c5a737bbfdeb (bug 1364364) Backed out changeset 21ee8f318a47 (bug 1364364) Backed out changeset 074475da0f2c (bug 1364364) Backed out changeset de6c153ec533 (bug 1364364)
docshell/base/nsDocShell.cpp
docshell/shistory/nsISHistoryInternal.idl
docshell/shistory/nsSHEntryShared.cpp
docshell/shistory/nsSHistory.cpp
docshell/shistory/nsSHistory.h
docshell/test/chrome/bug608669.xul
docshell/test/chrome/test_bug608669.xul
docshell/test/navigation/file_bug1364364-1.html
docshell/test/navigation/file_bug1364364-2.html
docshell/test/navigation/mochitest.ini
docshell/test/navigation/test_bug1364364.html
dom/indexedDB/test/bfcache_iframe1.html
dom/indexedDB/test/bfcache_iframe2.html
dom/indexedDB/test/bfcache_page1.html
dom/indexedDB/test/bfcache_page2.html
dom/indexedDB/test/mochitest.ini
dom/indexedDB/test/test_bfcache.html
dom/media/webspeech/synth/test/file_bfcache_frame.html
dom/media/webspeech/synth/test/file_bfcache_frame2.html
dom/media/webspeech/synth/test/file_bfcache_page1.html
dom/media/webspeech/synth/test/file_bfcache_page2.html
dom/media/webspeech/synth/test/mochitest.ini
dom/media/webspeech/synth/test/test_bfcache.html
dom/workers/test/WorkerDebugger_frozen_iframe1.html
dom/workers/test/WorkerDebugger_frozen_iframe2.html
dom/workers/test/WorkerDebugger_frozen_window1.html
dom/workers/test/WorkerDebugger_frozen_window2.html
dom/workers/test/blank.html
dom/workers/test/chrome.ini
dom/workers/test/mochitest.ini
dom/workers/test/multi_sharedWorker_frame.html
dom/workers/test/suspend_iframe.html
dom/workers/test/suspend_window.html
dom/workers/test/test_WorkerDebugger_frozen.xul
dom/workers/test/test_multi_sharedWorker_lifetimes.html
dom/workers/test/test_onLine.html
dom/workers/test/test_suspend.html
layout/base/nsDocumentViewer.cpp
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -8309,21 +8309,26 @@ nsDocShell::CanSavePresentation(uint32_t
   }
 
   // Avoid doing the work of saving the presentation state in the case where
   // the content viewer cache is disabled.
   if (nsSHistory::GetMaxTotalViewers() == 0) {
     return false;
   }
 
-  // Don't cache the content viewer if we're in a subframe.
-  nsCOMPtr<nsIDocShellTreeItem> root;
-  GetSameTypeParent(getter_AddRefs(root));
-  if (root && root != this) {
-    return false;  // this is a subframe load
+  // Don't cache the content viewer if we're in a subframe and the subframe
+  // pref is disabled.
+  bool cacheFrames =
+    Preferences::GetBool("browser.sessionhistory.cache_subframes", false);
+  if (!cacheFrames) {
+    nsCOMPtr<nsIDocShellTreeItem> root;
+    GetSameTypeParent(getter_AddRefs(root));
+    if (root && root != this) {
+      return false;  // this is a subframe load
+    }
   }
 
   // If the document does not want its presentation cached, then don't.
   nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc();
   return doc && doc->CanSavePresentation(aNewRequest);
 }
 
 void
--- a/docshell/shistory/nsISHistoryInternal.idl
+++ b/docshell/shistory/nsISHistoryInternal.idl
@@ -116,28 +116,14 @@ interface nsISHistoryInternal: nsISuppor
     *        The container to start looking for dynamic entries. Only the
     *        dynamic descendants of the container will be removed. If not given,
     *        all dynamic entries at the index will be removed.
     */
    [noscript, notxpcom] void RemoveDynEntries(in long aIndex,
                                               in nsISHContainer aContainer);
 
    /**
-    * Similar to RemoveDynEntries, but instead of specifying an index, use the
-    * given BFCacheEntry to find the index and remove dynamic entries from the
-    * index.
-    *
-    * The method takes no effect if the bfcache entry is not or no longer hold
-    * by the SHistory instance.
-    *
-    * @param aEntry
-    *        The bfcache entry to look up for index to remove dynamic entries
-    *        from.
-    */
-   [noscript, notxpcom] void RemoveDynEntriesForBFCacheEntry(in nsIBFCacheEntry aEntry);
-
-   /**
     * Removes entries from the history if their docshellID is in
     * aIDs array.
     */
    [noscript, notxpcom] void RemoveEntries(in nsDocshellIDArray aIDs,
                                            in long aStartIndex);
 };
--- a/docshell/shistory/nsSHEntryShared.cpp
+++ b/docshell/shistory/nsSHEntryShared.cpp
@@ -163,76 +163,76 @@ nsSHEntryShared::SetContentViewer(nsICon
   return NS_OK;
 }
 
 nsresult
 nsSHEntryShared::RemoveFromBFCacheSync()
 {
   MOZ_ASSERT(mContentViewer && mDocument, "we're not in the bfcache!");
 
-  // The call to DropPresentationState could drop the last reference, so hold
-  // |this| until RemoveDynEntriesForBFCacheEntry finishes.
-  RefPtr<nsSHEntryShared> kungFuDeathGrip = this;
-
-  // DropPresentationState would clear mContentViewer.
   nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
   DropPresentationState();
 
+  // Warning! The call to DropPresentationState could have dropped the last
+  // reference to this object, so don't access members beyond here.
+
   if (viewer) {
     viewer->Destroy();
   }
 
-  // Now that we've dropped the viewer, we have to clear associated dynamic
-  // subframe entries.
-  nsCOMPtr<nsISHistoryInternal> shistory = do_QueryReferent(mSHistory);
-  if (shistory) {
-    shistory->RemoveDynEntriesForBFCacheEntry(this);
+  return NS_OK;
+}
+
+class DestroyViewerEvent : public mozilla::Runnable
+{
+public:
+  DestroyViewerEvent(nsIContentViewer* aViewer, nsIDocument* aDocument)
+    : mozilla::Runnable("DestroyViewerEvent")
+    , mViewer(aViewer)
+    , mDocument(aDocument)
+  {
   }
 
-  return NS_OK;
-}
+  NS_IMETHOD Run() override
+  {
+    if (mViewer) {
+      mViewer->Destroy();
+    }
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIContentViewer> mViewer;
+  nsCOMPtr<nsIDocument> mDocument;
+};
 
 nsresult
 nsSHEntryShared::RemoveFromBFCacheAsync()
 {
   MOZ_ASSERT(mContentViewer && mDocument, "we're not in the bfcache!");
 
-  // Check it again to play safe in release builds.
+  // Release the reference to the contentviewer asynchronously so that the
+  // document doesn't get nuked mid-mutation.
+
   if (!mDocument) {
     return NS_ERROR_UNEXPECTED;
   }
-
-  // DropPresentationState would clear mContentViewer & mDocument. Capture and
-  // release the references asynchronously so that the document doesn't get
-  // nuked mid-mutation.
-  nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
-  nsCOMPtr<nsIDocument> document = mDocument;
-  RefPtr<nsSHEntryShared> self = this;
-  nsresult rv = mDocument->Dispatch(mozilla::TaskCategory::Other,
-    NS_NewRunnableFunction("nsSHEntryShared::RemoveFromBFCacheAsync",
-    [self, viewer, document]() {
-      if (viewer) {
-        viewer->Destroy();
-      }
-
-      nsCOMPtr<nsISHistoryInternal> shistory = do_QueryReferent(self->mSHistory);
-      if (shistory) {
-        shistory->RemoveDynEntriesForBFCacheEntry(self);
-      }
-    }));
-
+  nsCOMPtr<nsIRunnable> evt = new DestroyViewerEvent(mContentViewer, mDocument);
+  nsresult rv = mDocument->Dispatch(mozilla::TaskCategory::Other, evt.forget());
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch RemoveFromBFCacheAsync runnable.");
+    NS_WARNING("failed to dispatch DestroyViewerEvent");
   } else {
     // Drop presentation. Only do this if we succeeded in posting the event
     // since otherwise the document could be torn down mid-mutation, causing
     // crashes.
     DropPresentationState();
   }
 
+  // Careful! The call to DropPresentationState could have dropped the last
+  // reference to this nsSHEntryShared, so don't access members beyond here.
+
   return NS_OK;
 }
 
 nsresult
 nsSHEntryShared::GetID(uint64_t* aID)
 {
   *aID = mID;
   return NS_OK;
--- a/docshell/shistory/nsSHistory.cpp
+++ b/docshell/shistory/nsSHistory.cpp
@@ -208,17 +208,17 @@ nsSHistory::EvictContentViewerForTransac
   entry->GetAnyContentViewer(getter_AddRefs(ownerEntry),
                              getter_AddRefs(viewer));
   if (viewer) {
     NS_ASSERTION(ownerEntry, "Content viewer exists but its SHEntry is null");
 
     LOG_SHENTRY_SPEC(("Evicting content viewer 0x%p for "
                       "owning SHEntry 0x%p at %s.",
                       viewer.get(), ownerEntry.get(), _spec),
-                      ownerEntry);
+                     ownerEntry);
 
     // Drop the presentation state before destroying the viewer, so that
     // document teardown is able to correctly persist the state.
     ownerEntry->SetContentViewer(nullptr);
     ownerEntry->SyncPresentationState();
     viewer->Destroy();
   }
 
@@ -583,17 +583,17 @@ nsSHistory::GetEntryAtIndex(int32_t aInd
         NOTIFY_LISTENERS(OnIndexChanged, (mIndex))
       }
     }
   }
   return rv;
 }
 
 /* Get the transaction at a given index */
-nsresult
+NS_IMETHODIMP
 nsSHistory::GetTransactionAtIndex(int32_t aIndex, nsISHTransaction** aResult)
 {
   nsresult rv;
   NS_ENSURE_ARG_POINTER(aResult);
 
   if (mLength <= 0 || aIndex < 0 || aIndex >= mLength) {
     return NS_ERROR_FAILURE;
   }
@@ -1285,23 +1285,18 @@ nsSHistory::GloballyEvictContentViewers(
   for (int32_t i = transactions.Length() - 1; i >= sHistoryMaxTotalViewers;
        --i) {
     (transactions[i].mSHistory)->
       EvictContentViewerForTransaction(transactions[i].mTransaction);
   }
 }
 
 nsresult
-nsSHistory::FindTransactionForBFCache(nsIBFCacheEntry* aEntry,
-                                      nsISHTransaction** aResult,
-                                      int32_t* aResultIndex)
+nsSHistory::EvictExpiredContentViewerForEntry(nsIBFCacheEntry* aEntry)
 {
-  *aResult = nullptr;
-  *aResultIndex = -1;
-
   int32_t startIndex = std::max(0, mIndex - nsISHistory::VIEWER_WINDOW);
   int32_t endIndex = std::min(mLength - 1, mIndex + nsISHistory::VIEWER_WINDOW);
   nsCOMPtr<nsISHTransaction> trans;
   GetTransactionAtIndex(startIndex, getter_AddRefs(trans));
 
   int32_t i;
   for (i = startIndex; trans && i <= endIndex; ++i) {
     nsCOMPtr<nsISHEntry> entry;
@@ -1311,39 +1306,25 @@ nsSHistory::FindTransactionForBFCache(ns
     if (entry->HasBFCacheEntry(aEntry)) {
       break;
     }
 
     nsCOMPtr<nsISHTransaction> temp = trans;
     temp->GetNext(getter_AddRefs(trans));
   }
   if (i > endIndex) {
-    return NS_ERROR_FAILURE;
+    return NS_OK;
   }
 
-  trans.forget(aResult);
-  *aResultIndex = i;
-  return NS_OK;
-}
-
-nsresult
-nsSHistory::EvictExpiredContentViewerForEntry(nsIBFCacheEntry* aEntry)
-{
-  int32_t index;
-  nsCOMPtr<nsISHTransaction> trans;
-  FindTransactionForBFCache(aEntry, getter_AddRefs(trans), &index);
-
-  if (index == mIndex) {
+  if (i == mIndex) {
     NS_WARNING("How did the current SHEntry expire?");
     return NS_OK;
   }
 
-  if (trans) {
-    EvictContentViewerForTransaction(trans);
-  }
+  EvictContentViewerForTransaction(trans);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSHistory::AddToExpirationTracker(nsIBFCacheEntry* aEntry)
 {
   RefPtr<nsSHEntryShared> entry = static_cast<nsSHEntryShared*>(aEntry);
@@ -1600,30 +1581,16 @@ nsSHistory::RemoveDynEntries(int32_t aIn
     AutoTArray<nsID, 16> toBeRemovedEntries;
     GetDynamicChildren(container, toBeRemovedEntries, true);
     if (toBeRemovedEntries.Length()) {
       RemoveEntries(toBeRemovedEntries, aIndex);
     }
   }
 }
 
-void
-nsSHistory::RemoveDynEntriesForBFCacheEntry(nsIBFCacheEntry* aEntry)
-{
-  int32_t index;
-  nsCOMPtr<nsISHTransaction> trans;
-  FindTransactionForBFCache(aEntry, getter_AddRefs(trans), &index);
-  if (trans) {
-    nsCOMPtr<nsISHEntry> entry;
-    trans->GetSHEntry(getter_AddRefs(entry));
-    nsCOMPtr<nsISHContainer> container(do_QueryInterface(entry));
-    RemoveDynEntries(index, container);
-  }
-}
-
 NS_IMETHODIMP
 nsSHistory::UpdateIndex()
 {
   // Update the actual index with the right value.
   if (mIndex != mRequestedIndex && mRequestedIndex != -1) {
     mIndex = mRequestedIndex;
     NOTIFY_LISTENERS(OnIndexChanged, (mIndex))
   }
@@ -1731,17 +1698,17 @@ nsSHistory::LoadNextPossibleEntry(int32_
     return LoadEntry(aNewIndex - 1, aLoadType, aHistCmd);
   }
   if (aNewIndex > mIndex) {
     return LoadEntry(aNewIndex + 1, aLoadType, aHistCmd);
   }
   return NS_ERROR_FAILURE;
 }
 
-nsresult
+NS_IMETHODIMP
 nsSHistory::LoadEntry(int32_t aIndex, long aLoadType, uint32_t aHistCmd)
 {
   if (!mRootDocShell) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIURI> nextURI;
   nsCOMPtr<nsISHEntry> prevEntry;
--- a/docshell/shistory/nsSHistory.h
+++ b/docshell/shistory/nsSHistory.h
@@ -78,35 +78,30 @@ public:
   // Otherwise, it comes straight from the pref.
   static uint32_t GetMaxTotalViewers() { return sHistoryMaxTotalViewers; }
 
 private:
   virtual ~nsSHistory();
   friend class nsSHEnumerator;
   friend class nsSHistoryObserver;
 
-  nsresult GetTransactionAtIndex(int32_t aIndex, nsISHTransaction** aResult);
+  // Could become part of nsIWebNavigation
+  NS_IMETHOD GetTransactionAtIndex(int32_t aIndex, nsISHTransaction** aResult);
   nsresult LoadDifferingEntries(nsISHEntry* aPrevEntry, nsISHEntry* aNextEntry,
                                 nsIDocShell* aRootDocShell, long aLoadType,
                                 bool& aDifferenceFound);
   nsresult InitiateLoad(nsISHEntry* aFrameEntry, nsIDocShell* aFrameDS,
                         long aLoadType);
 
-  nsresult LoadEntry(int32_t aIndex, long aLoadType, uint32_t aHistCmd);
+  NS_IMETHOD LoadEntry(int32_t aIndex, long aLoadType, uint32_t aHistCmd);
 
 #ifdef DEBUG
   nsresult PrintHistory();
 #endif
 
-  // Find the transaction for a given bfcache entry. It only looks up between
-  // the range where alive viewers may exist (i.e nsISHistory::VIEWER_WINDOW).
-  nsresult FindTransactionForBFCache(nsIBFCacheEntry* aEntry,
-                                     nsISHTransaction** aResult,
-                                     int32_t* aResultIndex);
-
   // Evict content viewers in this window which don't lie in the "safe" range
   // around aIndex.
   void EvictOutOfRangeWindowContentViewers(int32_t aIndex);
   void EvictContentViewerForTransaction(nsISHTransaction* aTrans);
   static void GloballyEvictContentViewers();
   static void GloballyEvictAllContentViewers();
 
   // Calculates a max number of total
--- a/docshell/test/chrome/bug608669.xul
+++ b/docshell/test/chrome/bug608669.xul
@@ -1,14 +1,6 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <window title="Mozilla Bug 608669 - Blank page"
-  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-  onload="notifyOpener();">
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <description flex="1" value="This window is intentionally left blank"/>
-  <script type="application/javascript">
-  function notifyOpener() {
-    if (opener) {
-      opener.postMessage("load", "*");
-    }
-  }
-  </script>
 </window>
--- a/docshell/test/chrome/test_bug608669.xul
+++ b/docshell/test/chrome/test_bug608669.xul
@@ -13,28 +13,53 @@ https://bugzilla.mozilla.org/show_bug.cg
   <body xmlns="http://www.w3.org/1999/xhtml">
   <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=608669"
      target="_blank">Mozilla Bug 608669</a>
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
 
+var gOrigMaxTotalViewers = undefined;
+function setCachePref(enabled) {
+  var prefBranch = Components.classes["@mozilla.org/preferences-service;1"]
+                             .getService(Components.interfaces.nsIPrefBranch);
+  if (enabled) {
+    is(typeof gOrigMaxTotalViewers, "undefined", "don't double-enable bfcache");
+    prefBranch.setBoolPref("browser.sessionhistory.cache_subframes", true);
+    gOrigMaxTotalViewers = prefBranch.getIntPref("browser.sessionhistory.max_total_viewers");
+    prefBranch.setIntPref("browser.sessionhistory.max_total_viewers", 10);
+  }
+  else {
+    is(typeof gOrigMaxTotalViewers, "number", "don't double-disable bfcache");
+    prefBranch.setIntPref("browser.sessionhistory.max_total_viewers", gOrigMaxTotalViewers);
+    gOrigMaxTotalViewers = undefined;
+    try {
+      prefBranch.clearUserPref("browser.sessionhistory.cache_subframes");
+    } catch (e) { /* Pref didn't exist, meh */ }
+  }
+}
+
+
 /** Test for Bug 608669 **/
 SimpleTest.waitForExplicitFinish();
 
 addLoadEvent(nextTest);
 
 gen = doTest();
 
 function nextTest() {
   gen.next();
 }
 
 function* doTest() {
+  var container = document.getElementById('container');
+
+  setCachePref(true);
+
   var notificationCount = 0;
   var observer = {
     observe: function(aSubject, aTopic, aData) {
       is(aTopic, "chrome-document-global-created",
          "correct topic");
       is(aData, "null",
          "correct data");
       notificationCount++;
@@ -43,36 +68,49 @@ function* doTest() {
 
   var os = Components.classes["@mozilla.org/observer-service;1"].
     getService(Components.interfaces.nsIObserverService);
   os.addObserver(observer, "chrome-document-global-created");
   os.addObserver(observer, "content-document-global-created");
 
   is(notificationCount, 0, "initial count");
 
-  // create a new window
-  var testWin = window.open("", "bug 608669", "chrome,width=600,height=600");
-  testWin.x = "y";
-  is(notificationCount, 1, "after created window");
-
-  // Try loading in the window
-  testWin.location = "bug608669.xul";
-  window.onmessage = nextTest;
+  // create a new iframe
+  var iframe = document.createElement("iframe");
+  container.appendChild(iframe);
+  iframe.contentWindow.x = "y";
+  is(notificationCount, 1, "after created iframe");
+  
+  // Try loading in an iframe
+  iframe.setAttribute("src", "bug608669.xul");
+  iframe.onload = nextTest;
   yield undefined;
   is(notificationCount, 1, "after first load");
-  is(testWin.x, "y", "reused window");
+  is(iframe.contentWindow.x, "y", "reused window");
 
-  // Try loading again in the window
-  testWin.location = "bug608669.xul?x";
-  window.onmessage = nextTest;
+  // Try loading again in an iframe
+  iframe.setAttribute("src", "bug608669.xul?x");
+  iframe.onload = nextTest;
   yield undefined;
   is(notificationCount, 2, "after second load");
-  is("x" in testWin, false, "didn't reuse window");
+  is("x" in iframe.contentWindow, false, "didn't reuse window");
 
-  testWin.close();
+  // Open a new window using window.open
+  popup = window.open("bug608669.xul", "bug 608669",
+                      "chrome,width=600,height=600");
+  popup.onload = nextTest;
+  yield undefined;
+  is(notificationCount, 3, "after window.open load");
+  popup.close();
 
+  setCachePref(false);
   os.removeObserver(observer, "chrome-document-global-created");
   os.removeObserver(observer, "content-document-global-created");
   SimpleTest.finish();
 }
 
+
+
   ]]></script>
+  <vbox id="container" flex="1">
+    <description>Below will an iframe be added</description>
+  </vbox>
 </window>
deleted file mode 100644
--- a/docshell/test/navigation/file_bug1364364-1.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <meta charset="utf-8">
-    <title>title</title>
-  </head>
-  <body onload="loadFramesAndNavigate();">
-    <p id="content"></p>
-    <div id="frameContainer">
-    </div>
-    <script type="application/javascript">
-    function waitForLoad(frame) {
-      return new Promise(r => frame.onload = r);
-    }
-
-    async function loadFramesAndNavigate() {
-      let dynamicFrame = document.createElement("iframe");
-      dynamicFrame.src = "data:text/html,iframe1";
-      document.querySelector("#frameContainer").appendChild(dynamicFrame);
-      await waitForLoad(dynamicFrame);
-      dynamicFrame.src = "data:text/html,iframe2";
-      await waitForLoad(dynamicFrame);
-      dynamicFrame.src = "data:text/html,iframe3";
-      await waitForLoad(dynamicFrame);
-      dynamicFrame.src = "data:text/html,iframe4";
-      await waitForLoad(dynamicFrame);
-      dynamicFrame.src = "data:text/html,iframe5";
-      await waitForLoad(dynamicFrame);
-      location.href = "file_bug1364364-2.html";
-    }
-    </script>
-  </body>
-</html>
deleted file mode 100644
--- a/docshell/test/navigation/file_bug1364364-2.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <meta charset="utf-8">
-    <title>title</title>
-  </head>
-  <body onload="notifyOpener();">
-    <script type="application/javascript">
-    function notifyOpener() {
-      opener.postMessage("navigation-done", "*");
-    }
-    </script>
-  </body>
-</html>
--- a/docshell/test/navigation/mochitest.ini
+++ b/docshell/test/navigation/mochitest.ini
@@ -44,33 +44,30 @@ support-files =
   file_triggeringprincipal_iframe_iframe_window_open_frame_a_nav.html
   file_bug1300461.html
   file_bug1300461_redirect.html
   file_bug1300461_redirect.html^headers^
   file_bug1300461_back.html
   file_contentpolicy_block_window.html
   file_bug1326251.html
   file_bug1326251_evict_cache.html
-  file_bug1364364-1.html
-  file_bug1364364-2.html
   file_bug1375833.html
   file_bug1375833-frame1.html
   file_bug1375833-frame2.html
 
 [test_bug13871.html]
 [test_bug270414.html]
 [test_bug278916.html]
 [test_bug279495.html]
 [test_bug344861.html]
 skip-if = toolkit == "android" || toolkit == "windows" # disabled on Windows because of bug 1234520
 [test_bug386782.html]
 [test_bug430624.html]
 [test_bug430723.html]
 skip-if = (toolkit == 'android') || (!debug && (os == 'mac' || os == 'win')) # Bug 874423
-[test_bug1364364.html]
 [test_bug1375833.html]
 [test_child.html]
 [test_grandchild.html]
 [test_not-opener.html]
 [test_opener.html]
 [test_popup-navigates-children.html]
 [test_reserved.html]
 skip-if = (toolkit == 'android') || (debug && e10s) #too slow on Android 4.3 aws only; bug 1030403; bug 1263213 for debug e10s
deleted file mode 100644
--- a/docshell/test/navigation/test_bug1364364.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1364364
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 1364364</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-  <script type="application/javascript">
-
-  /** Test for Bug 1364364 **/
-  let testWin, testDoc;
-  async function test() {
-    SimpleTest.waitForExplicitFinish();
-    testWin = window.open("file_bug1364364-1.html");
-    await waitForLoad(testWin);
-    testDoc = testWin.document;
-
-    // file_bug1364364-1.html will load a few dynamic iframes and then navigate
-    // top browsing context to file_bug1364364-2.html, which will postMessage
-    // back.
-  }
-
-  function waitForLoad(win) {
-    return new Promise(r => win.addEventListener("load", r, { once: true}));
-  }
-
-  window.addEventListener("message", async function(msg) {
-    if (msg.data == "navigation-done") {
-      is(testWin.history.length, 6, "check history.length");
-
-      // Modify a document in bfcache should cause the cache being dropped tho
-      // RemoveFromBFCacheAsync.
-      testDoc.querySelector("#content").textContent = "modified";
-      await new Promise(r => setTimeout(r, 0));
-
-      is(testWin.history.length, 2, "check history.length after bfcache dropped");
-      testWin.close();
-      SimpleTest.finish();
-    }
-  });
-
-  </script>
-</head>
-<body onload="test();">
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1364364">Mozilla Bug 1364364</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
rename from dom/indexedDB/test/bfcache_page1.html
rename to dom/indexedDB/test/bfcache_iframe1.html
--- a/dom/indexedDB/test/bfcache_page1.html
+++ b/dom/indexedDB/test/bfcache_iframe1.html
@@ -1,27 +1,27 @@
 <!DOCTYPE html>
 <html>
 <head>
   <script>
-  var request = indexedDB.open(opener.location, 1);
+  var request = indexedDB.open(parent.location, 1);
   request.onupgradeneeded = function(e) {
     var db = e.target.result;
     // This should never be called
     db.onversionchange = function(e) {
       db.transaction(["mystore"]).objectStore("mystore").put({ hello: "fail" }, 42);
     }
     var trans = e.target.transaction;
     if (db.objectStoreNames.contains("mystore")) {
       db.deleteObjectStore("mystore");
     }
     var store = db.createObjectStore("mystore");
     store.add({ hello: "world" }, 42);
     trans.oncomplete = function() {
-      opener.postMessage("go", "http://mochi.test:8888");
+      parent.postMessage("go", "http://mochi.test:8888");
     }
   };
   </script>
 </head>
 <body>
   This is page one.
 </body>
 </html>
rename from dom/indexedDB/test/bfcache_page2.html
rename to dom/indexedDB/test/bfcache_iframe2.html
--- a/dom/indexedDB/test/bfcache_page2.html
+++ b/dom/indexedDB/test/bfcache_iframe2.html
@@ -1,28 +1,28 @@
 <!DOCTYPE html>
 <html>
 <head>
   <script>
   var res = {};
-  var request = indexedDB.open(opener.location, 2);
+  var request = indexedDB.open(parent.location, 2);
   request.onblocked = function() {
     res.blockedFired = true;
   }
   request.onupgradeneeded  = function(e) {
     var db = e.target.result;
     res.version = db.version;
     res.storeCount = db.objectStoreNames.length;
 
     var trans = request.transaction;
     trans.objectStore("mystore").get(42).onsuccess = function(e) {
       res.value = JSON.stringify(e.target.result);
     }
     trans.oncomplete = function() {
-      opener.postMessage(JSON.stringify(res), "http://mochi.test:8888");
+      parent.postMessage(JSON.stringify(res), "http://mochi.test:8888");
     }
   };
 
   </script>
 </head>
 <body>
   This is page two.
 </body>
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -1,16 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 [DEFAULT]
 support-files =
-  bfcache_page1.html
-  bfcache_page2.html
+  bfcache_iframe1.html
+  bfcache_iframe2.html
   blob_worker_crash_iframe.html
   error_events_abort_transactions_iframe.html
   event_propagation_iframe.html
   exceptions_in_events_iframe.html
   file.js
   helpers.js
   leaving_page_iframe.html
   third_party_iframe1.html
--- a/dom/indexedDB/test/test_bfcache.html
+++ b/dom/indexedDB/test/test_bfcache.html
@@ -5,37 +5,63 @@
 <html>
 <head>
   <title>Indexed Database Property Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="text/javascript">
     /* import-globals-from helpers.js */
+    var gOrigMaxTotalViewers = undefined;
+    function setCachePref(enabled) {
+      if (enabled) {
+        is(typeof gOrigMaxTotalViewers, "undefined",
+           "don't double-enable bfcache");
+        SpecialPowers.setBoolPref("browser.sessionhistory.cache_subframes",
+                                  true);
+        gOrigMaxTotalViewers =
+          SpecialPowers.getIntPref("browser.sessionhistory.max_total_viewers");
+        SpecialPowers.setIntPref("browser.sessionhistory.max_total_viewers",
+                                 10);
+      }
+      else {
+        is(typeof gOrigMaxTotalViewers, "number",
+           "don't double-disable bfcache");
+        SpecialPowers.setIntPref("browser.sessionhistory.max_total_viewers",
+                                 gOrigMaxTotalViewers);
+        gOrigMaxTotalViewers = undefined;
+        try {
+          SpecialPowers.clearUserPref("browser.sessionhistory.cache_subframes");
+        } catch (e) { /* Pref didn't exist, meh */ }
+      }
+    }
 
     function* testSteps()
     {
+      var iframe = $("iframe");
+      setCachePref(true);
       window.onmessage = grabEventAndContinueHandler;
 
-      let testWin = window.open("bfcache_page1.html", "testWin");
+      iframe.src = "bfcache_iframe1.html";
       var event = yield undefined;
       is(event.data, "go", "set up database successfully");
 
-      testWin.location = "bfcache_page2.html";
+      iframe.src = "bfcache_iframe2.html";
       let res = JSON.parse((yield).data);
       is(res.version, 2, "version was set correctly");
       is(res.storeCount, 1, "correct set of stores");
       ok(!("blockedFired" in res), "blocked shouldn't fire");
       is(res.value, JSON.stringify({ hello: "world" }),
          "correct value found in store");
 
-      testWin.close();
+      setCachePref(false);
       finishTest();
     }
   </script>
   <script type="text/javascript" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();">
+  <iframe id="iframe"></iframe>
 </body>
 
 </html>
rename from dom/media/webspeech/synth/test/file_bfcache_page1.html
rename to dom/media/webspeech/synth/test/file_bfcache_frame.html
--- a/dom/media/webspeech/synth/test/file_bfcache_page1.html
+++ b/dom/media/webspeech/synth/test/file_bfcache_frame.html
@@ -2,17 +2,17 @@
 <html>
 <head>
   <meta charset="utf-8">
   <script type="application/javascript">
     addEventListener('pageshow', function onshow(evt) {
       var u = new SpeechSynthesisUtterance('hello');
       u.lang = 'it-IT-noend';
       u.addEventListener('start', function() {
-        location = "file_bfcache_page2.html";
+        location = "file_bfcache_frame2.html";
       });
       speechSynthesis.speak(u);
     });
   </script>
 </head>
 <body>
 </body>
 </html>
rename from dom/media/webspeech/synth/test/file_bfcache_page2.html
rename to dom/media/webspeech/synth/test/file_bfcache_frame2.html
--- a/dom/media/webspeech/synth/test/file_bfcache_page2.html
+++ b/dom/media/webspeech/synth/test/file_bfcache_frame2.html
@@ -1,14 +1,14 @@
 <html>
 <script>
 var frameUnloaded = function() {
   var u = new SpeechSynthesisUtterance('hi');
   u.addEventListener('end', function () {
-    opener.ok(true, 'Successfully spoke utterance from new frame.');
-    opener.onDone();
+    parent.ok(true, 'Successfully spoke utterance from new frame.');
+    parent.onDone();
   });
   speechSynthesis.speak(u);
 };
 </script>
 
 <body onpageshow="frameUnloaded()"></body></html>
 
--- a/dom/media/webspeech/synth/test/mochitest.ini
+++ b/dom/media/webspeech/synth/test/mochitest.ini
@@ -1,15 +1,15 @@
 [DEFAULT]
 tags=msg
 subsuite = media
 support-files =
   common.js
-  file_bfcache_page1.html
-  file_bfcache_page2.html
+  file_bfcache_frame.html
+  file_bfcache_frame2.html
   file_setup.html
   file_speech_queue.html
   file_speech_simple.html
   file_speech_cancel.html
   file_speech_error.html
   file_indirect_service_events.html
   file_global_queue.html
   file_global_queue_cancel.html
--- a/dom/media/webspeech/synth/test/test_bfcache.html
+++ b/dom/media/webspeech/synth/test/test_bfcache.html
@@ -8,39 +8,38 @@ https://bugzilla.mozilla.org/show_bug.cg
   <title>Test for Bug 1230533: Test speech is stopped from a window when unloaded</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="common.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1230533">Mozilla Bug 1230533</a>
 <p id="display"></p>
+<iframe id="testFrame"></iframe>
 <div id="content" style="display: none">
-
+  
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 525444 **/
 
 SimpleTest.waitForExplicitFinish();
-let testWin;
+
+var iframe;
 
 function onDone() {
-  testWin.close();
   SimpleTest.finish();
 }
 
 SpecialPowers.pushPrefEnv({ set: [
   ['media.webspeech.synth.enabled', true],
-  ['media.webspeech.synth.force_global_queue', true]] },
+  ['media.webspeech.synth.force_global_queue', true],
+  ['browser.sessionhistory.cache_subframes', true],
+  ['browser.sessionhistory.max_total_viewers', 10]] },
   function() {
-    testWin = window.open("about:blank", "testWin");
-    testWin.onload = function(e) {
-      waitForVoices(testWin)
-        .then(() => testWin.location = "file_bfcache_page1.html")
-    };
+    loadSpeechTest("file_bfcache_frame.html");
   });
 
 </script>
 </pre>
 </body>
 </html>
rename from dom/workers/test/WorkerDebugger_frozen_window1.html
rename to dom/workers/test/WorkerDebugger_frozen_iframe1.html
--- a/dom/workers/test/WorkerDebugger_frozen_window1.html
+++ b/dom/workers/test/WorkerDebugger_frozen_iframe1.html
@@ -1,15 +1,15 @@
 <!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="utf-8">
     <script>
       var worker = new Worker("WorkerDebugger_frozen_worker1.js");
       worker.onmessage = function () {
-        opener.postMessage("ready", "*");
+        parent.postMessage("ready", "*");
       };
     </script>
   </head>
   <body>
     This is page 1.
   </body>
 <html>
rename from dom/workers/test/WorkerDebugger_frozen_window2.html
rename to dom/workers/test/WorkerDebugger_frozen_iframe2.html
--- a/dom/workers/test/WorkerDebugger_frozen_window2.html
+++ b/dom/workers/test/WorkerDebugger_frozen_iframe2.html
@@ -1,15 +1,15 @@
 <!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="utf-8">
     <script>
       var worker = new Worker("WorkerDebugger_frozen_worker2.js");
       worker.onmessage = function () {
-        opener.postMessage("ready", "*");
+        parent.postMessage("ready", "*");
       };
     </script>
   </head>
   <body>
     This is page 2.
   </body>
 <html>
deleted file mode 100644
--- a/dom/workers/test/blank.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <meta charset="utf-8">
-    <title>Blank</title>
-  </head>
-  <body onload="notifyOnload();">
-    <script type="application/javascript">
-    function notifyOnload() {
-      opener.postMessage({event: 'load'}, '*');
-    }
-    </script>
-  </body>
-</html>
-
--- a/dom/workers/test/chrome.ini
+++ b/dom/workers/test/chrome.ini
@@ -19,18 +19,18 @@ support-files =
   WorkerDebuggerGlobalScope.reportError_childWorker.js
   WorkerDebuggerGlobalScope.reportError_debugger.js
   WorkerDebuggerGlobalScope.reportError_worker.js
   WorkerDebuggerGlobalScope.setImmediate_debugger.js
   WorkerDebuggerGlobalScope.setImmediate_worker.js
   WorkerDebuggerManager_childWorker.js
   WorkerDebuggerManager_worker.js
   WorkerDebugger_childWorker.js
-  WorkerDebugger_frozen_window1.html
-  WorkerDebugger_frozen_window2.html
+  WorkerDebugger_frozen_iframe1.html
+  WorkerDebugger_frozen_iframe2.html
   WorkerDebugger_frozen_worker1.js
   WorkerDebugger_frozen_worker2.js
   WorkerDebugger_promise_debugger.js
   WorkerDebugger_promise_worker.js
   WorkerDebugger_sharedWorker.js
   WorkerDebugger_suspended_debugger.js
   WorkerDebugger_suspended_worker.js
   WorkerDebugger_worker.js
--- a/dom/workers/test/mochitest.ini
+++ b/dom/workers/test/mochitest.ini
@@ -1,13 +1,12 @@
 [DEFAULT]
 support-files =
   WorkerTest_badworker.js
   atob_worker.js
-  blank.html
   bug978260_worker.js
   bug1014466_data1.txt
   bug1014466_data2.txt
   bug1014466_worker.js
   bug1020226_worker.js
   bug1020226_frame.html
   bug998474_worker.js
   bug1063538_worker.js
@@ -52,17 +51,17 @@ support-files =
   promise_worker.js
   recursion_worker.js
   recursiveOnerror_worker.js
   redirect_to_foreign.sjs
   rvals_worker.js
   sharedWorker_console.js
   sharedWorker_sharedWorker.js
   simpleThread_worker.js
-  suspend_window.html
+  suspend_iframe.html
   suspend_worker.js
   terminate_worker.js
   test_csp.html^headers^
   test_csp.js
   referrer_worker.html
   threadErrors_worker1.js
   threadErrors_worker2.js
   threadErrors_worker3.js
--- a/dom/workers/test/multi_sharedWorker_frame.html
+++ b/dom/workers/test/multi_sharedWorker_frame.html
@@ -2,41 +2,25 @@
   Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/
 -->
 <!DOCTYPE HTML>
 <html>
   <head>
     <title>Test for SharedWorker</title>
   </head>
-  <body onload="notifyOpenerLoadEvent();">
+  <body>
     <script type="text/javascript">
       "use strict";
 
-      function postMessageToParentOrOpener(message) {
-        if (parent != window) {
-          parent.postMessage(message, "*");
-        }
-        if (opener) {
-          opener.postMessage(message, "*");
-        }
-      }
-
-      // Used by test_multi_sharedWorker_lifetimes.html
-      function notifyOpenerLoadEvent() {
-        if (opener) {
-          opener.postMessage({event: "load"}, "*");
-        }
-      }
-
       function debug(message) {
         if (typeof(message) != "string") {
           throw new Error("debug() only accepts strings!");
         }
-        postMessageToParentOrOpener(message);
+        parent.postMessage(message, "*");
       }
 
       let worker;
 
       window.addEventListener("message", function(event) {
         if (!worker) {
           worker = new SharedWorker("multi_sharedWorker_sharedWorker.js",
                                     "FrameWorker");
@@ -46,22 +30,22 @@
 
             let data = {
               type: "error",
               message: event.message,
               filename: event.filename,
               lineno: event.lineno,
               isErrorEvent: event instanceof ErrorEvent
             };
-            postMessageToParentOrOpener(data);
+            parent.postMessage(data, "*");
           };
 
           worker.port.onmessage = function(event) {
             debug("Worker message: " + JSON.stringify(event.data));
-            postMessageToParentOrOpener(event.data);
+            parent.postMessage(event.data, "*");
           };
         }
 
         debug("Posting message: " + JSON.stringify(event.data));
         worker.port.postMessage(event.data);
       });
     </script>
   </body>
rename from dom/workers/test/suspend_window.html
rename to dom/workers/test/suspend_iframe.html
--- a/dom/workers/test/test_WorkerDebugger_frozen.xul
+++ b/dom/workers/test/test_WorkerDebugger_frozen.xul
@@ -11,69 +11,80 @@
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
   <script type="application/javascript" src="dom_worker_helper.js"/>
 
   <script type="application/javascript">
   <![CDATA[
 
-    const WINDOW1_URL = "WorkerDebugger_frozen_window1.html";
-    const WINDOW2_URL = "WorkerDebugger_frozen_window2.html";
+    const CACHE_SUBFRAMES = "browser.sessionhistory.cache_subframes";
+    const MAX_TOTAL_VIEWERS = "browser.sessionhistory.max_total_viewers";
+
+    const IFRAME1_URL = "WorkerDebugger_frozen_iframe1.html";
+    const IFRAME2_URL = "WorkerDebugger_frozen_iframe2.html";
 
     const WORKER1_URL = "WorkerDebugger_frozen_worker1.js";
     const WORKER2_URL = "WorkerDebugger_frozen_worker2.js";
 
     function test() {
       (async function() {
         SimpleTest.waitForExplicitFinish();
 
-        SpecialPowers.pushPrefEnv({set:
-          [["browser.sessionhistory.max_total_viewers", 10]]});
+        var oldMaxTotalViewers = SpecialPowers.getIntPref(MAX_TOTAL_VIEWERS);
+
+        SpecialPowers.setBoolPref(CACHE_SUBFRAMES, true);
+        SpecialPowers.setIntPref(MAX_TOTAL_VIEWERS, 10);
+
+        let iframe = $("iframe");
 
         let promise = waitForMultiple([
           waitForRegister(WORKER1_URL),
           waitForWindowMessage(window, "ready"),
         ]);
-        let testWin = window.open(WINDOW1_URL, "testWin");;
+        iframe.src = IFRAME1_URL;
         let [dbg1] = await promise;
         is(dbg1.isClosed, false,
            "debugger for worker on page 1 should not be closed");
 
         promise = waitForMultiple([
           waitForUnregister(WORKER1_URL),
           waitForDebuggerClose(dbg1),
           waitForRegister(WORKER2_URL),
           waitForWindowMessage(window, "ready"),
         ]);
-        testWin.location = WINDOW2_URL;
+        iframe.src = IFRAME2_URL;
         let [,, dbg2] = await promise;
         is(dbg1.isClosed, true,
            "debugger for worker on page 1 should be closed");
         is(dbg2.isClosed, false,
            "debugger for worker on page 2 should not be closed");
 
         promise = Promise.all([
           waitForUnregister(WORKER2_URL),
           waitForDebuggerClose(dbg2),
           waitForRegister(WORKER1_URL)
         ]);
-        testWin.history.back();
+        iframe.contentWindow.history.back();
         [,, dbg1] = await promise;
         is(dbg1.isClosed, false,
            "debugger for worker on page 1 should not be closed");
         is(dbg2.isClosed, true,
            "debugger for worker on page 2 should be closed");
 
+        SpecialPowers.clearUserPref(CACHE_SUBFRAMES);
+        SpecialPowers.setIntPref(MAX_TOTAL_VIEWERS, oldMaxTotalViewers);
+
         SimpleTest.finish();
       })();
     }
 
   ]]>
   </script>
 
   <body xmlns="http://www.w3.org/1999/xhtml">
     <p id="display"></p>
     <div id="content" style="display:none;"></div>
     <pre id="test"></pre>
+    <iframe id="iframe"></iframe>
   </body>
   <label id="test-result"/>
 </window>
--- a/dom/workers/test/test_multi_sharedWorker_lifetimes.html
+++ b/dom/workers/test/test_multi_sharedWorker_lifetimes.html
@@ -7,134 +7,149 @@
   <head>
     <title>Test for SharedWorker</title>
     <script src="/tests/SimpleTest/SimpleTest.js"></script>
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
       <script class="testbody" type="text/javascript">
         "use strict";
 
         const scrollbarPref = "layout.testing.overlay-scrollbars.always-visible";
-        const viewersPref = "browser.sessionhistory.max_total_viewers";
+        const bfCacheEnabledPref = "browser.sessionhistory.cache_subframes";
+        const bfCacheDepthPref = "browser.sessionhistory.max_total_viewers";
+        const bfCacheDepth = 10;
 
-        const windowRelativeURL = "multi_sharedWorker_frame.html";
+        const frameRelativeURL = "multi_sharedWorker_frame.html";
         const storedData = "0123456789abcdefghijklmnopqrstuvwxyz";
 
         let testGenerator = (function*() {
           SimpleTest.waitForExplicitFinish();
 
-          // Force scrollbar to always be shown.  The scrollbar setting is
-          // necessary to avoid the fade-in/fade-out from evicting our document
-          // from the BF cache below.  If bug 1049277 is fixed, then we can
-          // stop setting the scrollbar pref here.
-          SpecialPowers.pushPrefEnv({ set: [[scrollbarPref, true],
-                                            [viewersPref, 10]] },
+	  // Force scrollbar to always be shown.  The scrollbar setting is
+	  // necessary to avoid the fade-in/fade-out from evicting our document
+	  // from the BF cache below.  If bug 1049277 is fixed, then we can
+	  // stop setting the scrollbar pref here.
+          SpecialPowers.pushPrefEnv({ set: [[scrollbarPref, true]] },
                                     sendToGenerator);
           yield undefined;
 
           window.addEventListener("message", function(event) {
             if (typeof(event.data) == "string") {
               info(event.data);
             } else {
               sendToGenerator(event);
             }
           });
 
-          let testWin = window.open(windowRelativeURL, "testWin");
+          let frame = document.getElementById("frame");
+          frame.src = frameRelativeURL;
+          frame.onload = sendToGenerator;
+
           yield undefined;
 
-          testWin.postMessage({ command: "retrieve" }, "*");
+          frame = frame.contentWindow;
+          frame.postMessage({ command: "retrieve" }, "*");
 
           let event = yield undefined;
           ok(event instanceof MessageEvent, "Got a MessageEvent");
-          is(event.source, testWin, "Correct window got the event");
+          is(event.source, frame, "Correct window got the event");
           is(event.data.type, "result", "Got a result message");
           is(event.data.data, undefined, "No data stored yet");
 
-          testWin.postMessage({ command: "store", data: storedData }, "*");
-          testWin.postMessage({ command: "retrieve" }, "*");
+          frame.postMessage({ command: "store", data: storedData }, "*");
+          frame.postMessage({ command: "retrieve" }, "*");
 
           event = yield undefined;
           ok(event instanceof MessageEvent, "Got a MessageEvent");
-          is(event.source, testWin, "Correct window got the event");
+          is(event.source, frame, "Correct window got the event");
           is(event.data.type, "result", "Got a result message");
           is(event.data.data, storedData, "Got stored data");
 
           // Navigate when the bfcache is disabled.
-          info("Navigating to a blank page");
-          testWin.onunload = function(){};;
-          testWin.location = "blank.html";
-          testWin.document.body.offsetTop;
+          info("Navigating to about:blank");
+          frame = document.getElementById("frame");
+          frame.onload = sendToGenerator;
+          frame.src = "about:blank";
+          frame.contentWindow.document.body.offsetTop;
 
           yield undefined;
 
-          info("Navigating to " + windowRelativeURL);
-          testWin.onunload = function(){};
-          testWin.location = windowRelativeURL;
-          testWin.document.body.offsetTop;
+          info("Navigating to " + frameRelativeURL);
+          frame.src = frameRelativeURL;
+          frame.contentWindow.document.body.offsetTop;
 
           yield undefined;
 
-          testWin.postMessage({ command: "retrieve" }, "*");
+          frame = frame.contentWindow;
+          frame.postMessage({ command: "retrieve" }, "*");
 
           event = yield undefined;
           ok(event instanceof MessageEvent, "Got a MessageEvent");
-          is(event.source, testWin, "Correct window got the event");
+          is(event.source, frame, "Correct window got the event");
           is(event.data.type, "result", "Got a result message");
           is(event.data.data, undefined, "No data stored");
 
-          testWin.postMessage({ command: "store", data: storedData }, "*");
-          testWin.postMessage({ command: "retrieve" }, "*");
+          frame.postMessage({ command: "store", data: storedData }, "*");
+          frame.postMessage({ command: "retrieve" }, "*");
 
           event = yield undefined;
           ok(event instanceof MessageEvent, "Got a MessageEvent");
-          is(event.source, testWin, "Correct window got the event");
+          is(event.source, frame, "Correct window got the event");
           is(event.data.type, "result", "Got a result message");
           is(event.data.data, storedData, "Got stored data");
 
+          info("Enabling '" + bfCacheEnabledPref + "' pref");
+          SpecialPowers.pushPrefEnv({ set: [[bfCacheEnabledPref, true],
+                                            [bfCacheDepthPref, bfCacheDepth]] },
+                                    sendToGenerator);
+          yield undefined;
+
           // Navigate when the bfcache is enabled.
-          info("Navigating to a blank page");
-          testWin.location = "blank.html";
-          testWin.document.body.offsetTop;
+          frame = document.getElementById("frame");
+          frame.onload = sendToGenerator;
+
+          info("Navigating to about:blank");
+          frame.src = "about:blank";
+          frame.contentWindow.document.body.offsetTop;
 
           yield undefined;
 
           for (let i = 0; i < 3; i++) {
             info("Running GC");
             SpecialPowers.exactGC(sendToGenerator);
             yield undefined;
 
-            // It seems using SpecialPowers.executeSoon() would make the
-            // entryGlobal being the TabChildGlobal (and that would make the
-            // baseURI in the location assignment below being incorrect);
-            // setTimeout on the otherhand ensures the entryGlobal is this
-            // window.
             info("Waiting the event queue to clear");
-            setTimeout(sendToGenerator, 0);
+            SpecialPowers.executeSoon(sendToGenerator);
             yield undefined;
           }
 
-          info("Navigating to " + windowRelativeURL);
-          testWin.location = windowRelativeURL;
-          testWin.document.body.offsetTop;
+          info("Navigating to " + frameRelativeURL);
+          frame.src = frameRelativeURL;
+          frame.contentWindow.document.body.offsetTop;
 
           yield undefined;
 
-          testWin.postMessage({ command: "retrieve" }, "*");
+          frame = frame.contentWindow;
+          frame.postMessage({ command: "retrieve" }, "*");
 
           event = yield undefined;
           ok(event instanceof MessageEvent, "Got a MessageEvent");
-          is(event.source, testWin, "Correct window got the event");
+          is(event.source, frame, "Correct window got the event");
           is(event.data.type, "result", "Got a result message");
           is(event.data.data, storedData, "Still have data stored");
 
+          info("Resetting '" + bfCacheEnabledPref + "' pref");
+          SpecialPowers.popPrefEnv(sendToGenerator);
+          yield undefined;
+
           window.removeEventListener("message", sendToGenerator);
 
-          testWin.close();
           SimpleTest.finish();
         })();
 
         let sendToGenerator = testGenerator.next.bind(testGenerator);
 
       </script>
   </head>
   <body onload="testGenerator.next();">
+    <iframe id="frame"></iframe>
   </body>
 </html>
--- a/dom/workers/test/test_onLine.html
+++ b/dom/workers/test/test_onLine.html
@@ -21,26 +21,17 @@ http://creativecommons.org/licenses/publ
 
 <script class="testbody" type="text/javascript">
 
 addLoadEvent(function() {
   var w = new Worker("onLine_worker.js");
 
   w.onmessage = function(e) {
     if (e.data.type === 'ready') {
-      // XXX Important trick here.
-      //
-      // Setting iosvc.offline would trigger a sync notifyObservers call, and if
-      // there exists a preloaded about:newtab (see tabbrowser._handleNewTab),
-      // that tab will be notified.
-      //
-      // This implies a sync call across different tabGroups, and will hit the
-      // assertion in SchedulerGroup::ValidateAccess(). So use executeSoon to
-      // re-dispatch an unlabeled runnable to the event queue.
-      SpecialPowers.executeSoon(doTest);
+      doTest();
     } else if (e.data.type === 'ok') {
       ok(e.data.test, e.data.message);
     } else if (e.data.type === 'finished') {
       SimpleTest.finish();
     }
   }
 
   function doTest() {
--- a/dom/workers/test/test_suspend.html
+++ b/dom/workers/test/test_suspend.html
@@ -9,126 +9,130 @@
   <title>Test for DOM Worker Threads</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <p id="display"></p>
 <div id="content" style="display: none"></div>
 <pre id="test">
+<iframe id="workerFrame" src="suspend_iframe.html" onload="subframeLoaded();">
+</iframe>
 <script class="testbody" type="text/javascript">
 
   SimpleTest.waitForExplicitFinish();
 
-  const BLANK_URI = location.href.replace("test_suspend.html", "blank.html");
-
+  var iframe;
   var lastCount;
 
   var suspended = false;
   var resumed = false;
   var finished = false;
 
   var interval;
   var oldMessageCount;
   var waitCount = 0;
 
-  var testWin = window.open("suspend_window.html", "testWin");
-  testWin.onload = testWinLoaded;
-
-  window.addEventListener("message", msg => {
-    if (suspended) {
-      badOnloadCallback();
-    } else {
-      suspendCallback();
-    }
-  })
-
   function finishTest() {
     if (finished) {
       return;
     }
     finished = true;
-    testWin.terminateWorker();
-    testWin.close();
-    SimpleTest.finish();
+    SpecialPowers.flushPrefEnv(function () {
+      iframe.terminateWorker();
+      SimpleTest.finish();
+    });
   }
 
   function waitInterval() {
     if (finished) {
       return;
     }
-    is(testWin.location.href, BLANK_URI, "Wrong url!");
+    is(String(iframe.location), "about:blank", "Wrong url!");
     is(suspended, true, "Not suspended?");
     is(resumed, false, "Already resumed?!");
     is(lastCount, oldMessageCount, "Received a message while suspended!");
     if (++waitCount == 5) {
       clearInterval(interval);
       resumed = true;
-      testWin.history.back();
+      iframe.history.back();
     }
   }
 
   function badOnloadCallback() {
     if (finished) {
       return;
     }
-    ok(false, "We don't want suspend_window.html to fire a new load event, we want it to come out of the bfcache!");
+    ok(false, "We don't want suspend_iframe.html to fire a new load event, we want it to come out of the bfcache!");
     finishTest();
   }
 
   function suspendCallback() {
     if (finished) {
       return;
     }
-    is(testWin.location.href, BLANK_URI, "Wrong url!");
+    is(String(iframe.location), "about:blank", "Wrong url!");
     is(suspended, false, "Already suspended?");
     is(resumed, false, "Already resumed?");
-    suspended = true;
-    oldMessageCount = lastCount;
-    interval = setInterval(waitInterval, 1000);
+    SpecialPowers.popPrefEnv(function () {
+      suspended = true;
+      var iframeElement = document.getElementById("workerFrame");
+      iframeElement.onload = badOnloadCallback;
+      oldMessageCount = lastCount;
+      interval = setInterval(waitInterval, 1000);
+    });
   }
 
   function messageCallback(data) {
     if (finished) {
       return;
     }
 
     if (!suspended) {
       ok(lastCount === undefined || lastCount == data - 1,
          "Got good data, lastCount = " + lastCount + ", data = " + data);
       lastCount = data;
       if (lastCount == 25) {
-        testWin.location = "blank.html";
-        // We want suspend_window.html to go into bfcache, so we need to flush
-        // out all pending notifications. Otherwise, if they're flushed too
-        // late, they could kick us out of the bfcache again.
-        testWin.document.body.offsetTop;
+        SpecialPowers.pushPrefEnv({"set": [["browser.sessionhistory.cache_subframes", true]]}, function () {
+          iframe.location = "about:blank";
+          // We want suspend_iframe.html to go into bfcache, so we need to flush
+          // out all pending notifications. Otherwise, if they're flushed too
+          // late, they could kick us out of the bfcache again.
+          iframe.document.body.offsetTop;
+        });
       }
       return;
     }
 
-    var newLocation = location.href.replace("test_suspend.html",
-                                            "suspend_window.html");
-    is(testWin.location.href, newLocation, "Wrong url!");
+    var newLocation =
+      window.location.toString().replace("test_suspend.html",
+                                         "suspend_iframe.html");
+    is(newLocation.indexOf(iframe.location.toString()), 0, "Wrong url!");
     is(resumed, true, "Got message before resumed!");
     is(lastCount, data - 1, "Missed a message, suspend failed!");
     finishTest();
   }
 
   function errorCallback(data) {
     if (finished) {
       return;
     }
-    ok(false, "testWin had an error: '" + data + "'");
+    ok(false, "Iframe had an error: '" + data + "'");
     finishTest();
   }
 
-  function testWinLoaded() {
+  function subframeLoaded() {
     if (finished) {
       return;
     }
-    testWin.startWorker(messageCallback, errorCallback);
+    var iframeElement = document.getElementById("workerFrame");
+    iframeElement.onload = suspendCallback;
+
+    iframe = iframeElement.contentWindow;
+    ok(iframe, "No iframe?!");
+
+    iframe.startWorker(messageCallback, errorCallback);
   }
 
 </script>
 </pre>
 </body>
 </html>
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -1502,18 +1502,16 @@ nsDocumentViewer::Open(nsISupports *aSta
       nsCOMPtr<nsIDocShell> shell = do_QueryInterface(item);
       AttachContainerRecurse(shell);
     }
   }
 
   SyncParentSubDocMap();
 
   if (mFocusListener && mDocument) {
-    // The focus listener may have been disconnected.
-    mFocusListener->Init(this);
     mDocument->AddEventListener(NS_LITERAL_STRING("focus"), mFocusListener,
                                 false, false);
     mDocument->AddEventListener(NS_LITERAL_STRING("blur"), mFocusListener,
                                 false, false);
   }
 
   // XXX re-enable image animations once that works correctly