Bug 1213650 - Stash the last value of lastArguments to navigateAndRestore to restore with. r=Mossop
authorMike Conley <mconley@mozilla.com>
Mon, 16 Nov 2015 16:58:12 -0500
changeset 273731 1f9d9bfafd5143618083adcd50f5fcb0fead5530
parent 273730 b97c0c3155ecd302ad614fedc2222ae83c5df135
child 273732 aef06cd725fc577d1b3449e15cec9fa9f578a286
push id68366
push usercbook@mozilla.com
push dateMon, 23 Nov 2015 13:31:58 +0000
treeherdermozilla-inbound@eff4131a3e4c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMossop
bugs1213650
milestone45.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 1213650 - Stash the last value of lastArguments to navigateAndRestore to restore with. r=Mossop
browser/base/content/browser.js
browser/components/sessionstore/SessionStore.jsm
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -911,16 +911,17 @@ function _loadURIWithFlags(browser, uri,
         postData: postData,
       });
     }
   } catch (e) {
     // If anything goes wrong just switch remoteness manually and load the URI.
     // We might lose history that way but at least the browser loaded a page.
     // This might be necessary if SessionStore wasn't initialized yet i.e.
     // when the homepage is a non-remote page.
+    Cu.reportError(e);
     gBrowser.updateBrowserRemotenessByURL(browser, uri);
     browser.webNavigation.loadURIWithOptions(uri, flags, referrer, referrerPolicy,
                                              postData, null, null);
   } finally {
     if (browser.userTypedClear) {
       browser.userTypedClear--;
     }
   }
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -400,16 +400,21 @@ var SessionStoreInternal = {
   // properly handle final update message.
   _closedTabs: new WeakMap(),
 
   // A map (xul:browser -> object) that maps a browser associated with a
   // recently closed tab due to a window closure to the tab state information
   // that is being stored in _closedWindows for that tab.
   _closedWindowTabs: new WeakMap(),
 
+  // A map (xul:browser -> object) that maps a browser that is switching
+  // remoteness via navigateAndRestore, to the loadArguments that were
+  // most recently passed when calling navigateAndRestore.
+  _remotenessChangingBrowsers: new WeakMap(),
+
   // whether a setBrowserState call is in progress
   _browserSetState: false,
 
   // time in milliseconds when the session was started (saved across sessions),
   // defaults to now if no session was restored or timestamp doesn't exist
   _sessionStartTime: Date.now(),
 
   // states for all currently opened windows
@@ -2368,29 +2373,56 @@ var SessionStoreInternal = {
   },
 
   /**
    * Navigate the given |tab| by first collecting its current state and then
    * either changing only the index of the currently shown shistory entry,
    * or restoring the exact same state again and passing the new URL to load
    * in |loadArguments|. Use this method to seamlessly switch between pages
    * loaded in the parent and pages loaded in the child process.
+   *
+   * This method might be called multiple times before it has finished
+   * flushing the browser tab. If that occurs, the loadArguments from
+   * the most recent call to navigateAndRestore will be used once the
+   * flush has finished.
    */
   navigateAndRestore(tab, loadArguments, historyIndex) {
     let window = tab.ownerDocument.defaultView;
     NS_ASSERT(window.__SSi, "tab's window must be tracked");
     let browser = tab.linkedBrowser;
 
+    // Were we already waiting for a flush from a previous call to
+    // navigateAndRestore on this tab?
+    let alreadyRestoring =
+      this._remotenessChangingBrowsers.has(browser.permanentKey);
+
+    // Stash the most recent loadArguments in this WeakMap so that
+    // we know to use it when the TabStateFlusher.flush resolves.
+    this._remotenessChangingBrowsers.set(browser.permanentKey, loadArguments);
+
+    if (alreadyRestoring) {
+      // This tab was already being restored to run in the
+      // correct process. We're done here.
+      return;
+    }
+
     // Set tab title to "Connecting..." and start the throbber to pretend we're
     // doing something while actually waiting for data from the frame script.
     window.gBrowser.setTabTitleLoading(tab);
     tab.setAttribute("busy", "true");
 
     // Flush to get the latest tab state.
     TabStateFlusher.flush(browser).then(() => {
+      // loadArguments might have been overwritten by multiple calls
+      // to navigateAndRestore while we waited for the tab to flush,
+      // so we use the most recently stored one.
+      let recentLoadArguments =
+        this._remotenessChangingBrowsers.get(browser.permanentKey);
+      this._remotenessChangingBrowsers.delete(browser.permanentKey);
+
       // The tab might have been closed/gone in the meantime.
       if (tab.closing || !tab.linkedBrowser) {
         return;
       }
 
       let window = tab.ownerDocument && tab.ownerDocument.defaultView;
 
       // The tab or its window might be gone.
@@ -2401,17 +2433,17 @@ var SessionStoreInternal = {
       let tabState = TabState.clone(tab);
       let options = {restoreImmediately: true};
 
       if (historyIndex >= 0) {
         tabState.index = historyIndex + 1;
         tabState.index = Math.max(1, Math.min(tabState.index, tabState.entries.length));
       } else {
         tabState.userTypedValue = null;
-        options.loadArguments = loadArguments;
+        options.loadArguments = recentLoadArguments;
       }
 
       // Need to reset restoring tabs.
       if (tab.linkedBrowser.__SS_restoreState) {
         this._resetLocalTabRestoringState(tab);
       }
 
       // Restore the state into the tab.