Bug 1075658: Make browser.loadURI synchronously update the browser remoteness. r=ttaubert
authorDave Townsend <dtownsend@oxymoronical.com>
Wed, 29 Oct 2014 13:26:14 -0700
changeset 229294 8c589a6d637e7cad54652f03cbf87f978927fa39
parent 229293 2381858cf8cfacdbc3492f17f8e5ec57028722a7
child 229295 0746593b7cde2f7e5dc9c82193946f0fab7939fa
push id7326
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:58:42 +0000
treeherdermozilla-aurora@d3a3b2a0f2f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersttaubert
bugs1075658
milestone36.0a1
Bug 1075658: Make browser.loadURI synchronously update the browser remoteness. r=ttaubert
browser/base/content/browser.css
browser/base/content/browser.js
browser/base/content/tabbrowser.xml
browser/base/content/test/general/browser.ini
browser/base/content/test/general/browser_e10s_switchbrowser.js
browser/components/sessionstore/ContentRestore.jsm
browser/components/sessionstore/SessionStore.jsm
browser/components/sessionstore/content/content-sessionStore.js
browser/components/sessionstore/test/browser.ini
browser/components/sessionstore/test/browser_423132.js
browser/components/sessionstore/test/browser_819510_perwindowpb.js
browser/components/tabview/test/browser.ini
browser/modules/E10SUtils.jsm
toolkit/content/widgets/browser.xml
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -17,18 +17,22 @@
 #main-window[customize-entered] {
   min-width: -moz-fit-content;
 }
 
 searchbar {
   -moz-binding: url("chrome://browser/content/search/search.xml#searchbar");
 }
 
+.browserStack > browser {
+  -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-browser");
+}
+
 .browserStack > browser[remote="true"] {
-  -moz-binding: url("chrome://global/content/bindings/remote-browser.xml#remote-browser");
+  -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-remote-browser");
 }
 
 toolbar[customizable="true"] {
   -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar");
 }
 
 %ifdef XP_MACOSX
 #toolbar-menubar {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -794,44 +794,72 @@ function gKeywordURIFixup({ target: brow
     // Do nothing if the URL is invalid (we don't want to show a notification in that case).
     if (ex.result != Cr.NS_ERROR_UNKNOWN_HOST) {
       // ... otherwise, report:
       Cu.reportError(ex);
     }
   }
 }
 
-// Called when a docshell has attempted to load a page in an incorrect process.
-// This function is responsible for loading the page in the correct process.
-function RedirectLoad({ target: browser, data }) {
+// A shared function used by both remote and non-remote browser XBL bindings to
+// load a URI or redirect it to the correct process.
+function _loadURIWithFlags(browser, uri, flags, referrer, charset, postdata) {
+  if (!uri) {
+    uri = "about:blank";
+  }
+
+  if (!(flags & browser.webNavigation.LOAD_FLAGS_FROM_EXTERNAL)) {
+    browser.userTypedClear++;
+  }
+
+  try {
+    let shouldBeRemote = gMultiProcessBrowser &&
+                         E10SUtils.shouldBrowserBeRemote(uri);
+    if (browser.isRemoteBrowser == shouldBeRemote) {
+      browser.webNavigation.loadURI(uri, flags, referrer, postdata, null);
+    } else {
+      LoadInOtherProcess(browser, {
+        uri: uri,
+        flags: flags,
+        referrer: referrer ? referrer.spec : null,
+      });
+    }
+  } finally {
+    if (browser.userTypedClear) {
+      browser.userTypedClear--;
+    }
+  }
+}
+
+// Starts a new load in the browser first switching the browser to the correct
+// process
+function LoadInOtherProcess(browser, loadOptions, historyIndex = -1) {
   let tab = gBrowser.getTabForBrowser(browser);
   // Flush the tab state before getting it
   TabState.flush(browser);
   let tabState = JSON.parse(SessionStore.getTabState(tab));
 
-  if (data.historyIndex < 0) {
-    // Add a pseudo-history state for the new url to load
-    let newEntry = {
-      url: data.uri,
-      referrer: data.referrer,
-    };
-
-    tabState.entries = tabState.entries.slice(0, tabState.index);
-    tabState.entries.push(newEntry);
-    tabState.index++;
+  if (historyIndex < 0) {
     tabState.userTypedValue = null;
+    // Tell session history the new page to load
+    SessionStore._restoreTabAndLoad(tab, JSON.stringify(tabState), loadOptions);
   }
   else {
     // Update the history state to point to the requested index
-    tabState.index = data.historyIndex + 1;
-  }
-
-  // SessionStore takes care of setting the browser remoteness before restoring
-  // history into it.
-  SessionStore.setTabState(tab, JSON.stringify(tabState));
+    tabState.index = historyIndex + 1;
+    // SessionStore takes care of setting the browser remoteness before restoring
+    // history into it.
+    SessionStore.setTabState(tab, JSON.stringify(tabState));
+  }
+}
+
+// Called when a docshell has attempted to load a page in an incorrect process.
+// This function is responsible for loading the page in the correct process.
+function RedirectLoad({ target: browser, data }) {
+  LoadInOtherProcess(browser, data.loadOptions, data.historyIndex);
 }
 
 var gBrowserInit = {
   delayedStartupFinished: false,
 
   onLoad: function() {
     var mustLoadSidebar = false;
 
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -5372,9 +5372,47 @@
 
           return val;
         ]]>
         </setter>
       </property>
     </implementation>
   </binding>
 
+  <binding id="tabbrowser-browser"
+           extends="chrome://global/content/bindings/browser.xml#browser">
+    <implementation>
+      <!-- throws exception for unknown schemes -->
+      <method name="loadURIWithFlags">
+        <parameter name="aURI"/>
+        <parameter name="aFlags"/>
+        <parameter name="aReferrerURI"/>
+        <parameter name="aCharset"/>
+        <parameter name="aPostData"/>
+        <body>
+          <![CDATA[
+            _loadURIWithFlags(this, aURI, aFlags, aReferrerURI, aCharset, aPostData);
+          ]]>
+        </body>
+      </method>
+    </implementation>
+  </binding>
+
+  <binding id="tabbrowser-remote-browser"
+           extends="chrome://global/content/bindings/remote-browser.xml#remote-browser">
+    <implementation>
+      <!-- throws exception for unknown schemes -->
+      <method name="loadURIWithFlags">
+        <parameter name="aURI"/>
+        <parameter name="aFlags"/>
+        <parameter name="aReferrerURI"/>
+        <parameter name="aCharset"/>
+        <parameter name="aPostData"/>
+        <body>
+          <![CDATA[
+            _loadURIWithFlags(this, aURI, aFlags, aReferrerURI, aCharset, aPostData);
+          ]]>
+        </body>
+      </method>
+    </implementation>
+  </binding>
+
 </bindings>
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -226,17 +226,16 @@ skip-if = e10s
 [browser_bug575830.js]
 skip-if = e10s # Bug 691614 - no e10s zoom support yet
 [browser_bug577121.js]
 [browser_bug578534.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content
 [browser_bug579872.js]
 [browser_bug580638.js]
 [browser_bug580956.js]
-skip-if = e10s # Bug 516755 - SessionStore disabled for e10s
 [browser_bug581242.js]
 skip-if = e10s # Bug 930863 - pageshow issues ("TypeError: charset is undefined" in pageshow listener, as document is null)
 [browser_bug581253.js]
 skip-if = e10s # Bug 930863 - pageshow issues ("TypeError: charset is undefined" in pageshow listener, as document is null)
 [browser_bug581947.js]
 skip-if = e10s
 [browser_bug585558.js]
 [browser_bug585785.js]
@@ -249,17 +248,16 @@ skip-if = e10s # Bug 653065 - Make the l
 skip-if = e10s # Bug 691601 - no form submit observers
 [browser_bug596687.js]
 [browser_bug597218.js]
 [browser_bug609700.js]
 skip-if = e10s # Bug 516755 - SessionStore disabled for e10s (calls duplicateTabIn, which uses SessionStore)
 [browser_bug623155.js]
 skip-if = e10s # Bug ?????? - URLBar issues (apparently issues with redirection)
 [browser_bug623893.js]
-skip-if = e10s # Bug 916974 - Session history doesn't work in e10s
 [browser_bug624734.js]
 [browser_bug633691.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (eg, var expertDiv = gBrowser.contentDocument.getElementById("expertContent");)
 [browser_bug647886.js]
 skip-if = buildapp == 'mulet' || e10s # Bug 916974 - Session history doesn't work in e10s
 [browser_bug655584.js]
 skip-if = e10s
 [browser_bug664672.js]
@@ -267,32 +265,32 @@ skip-if = e10s
 skip-if = buildapp == 'mulet' || os == "mac" || e10s # mac: Intermittent failures, bug 925225; e10s: Bug ?????? - test directly manipulates content (event.target.location)
 [browser_bug678392.js]
 skip-if = e10s # Bug ?????? - Obscure non-windows failures ("Snapshot array has correct length of 1 after loading one page. - Got 0, expected 1" and more)
 [browser_bug710878.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (doc.querySelector)
 [browser_bug719271.js]
 skip-if = e10s # Bug 691614 - no e10s zoom support yet
 [browser_bug724239.js]
+skip-if = e10s # Bug 1077738
 [browser_bug734076.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content
 [browser_bug735471.js]
 [browser_bug749738.js]
 skip-if = e10s # Bug 921935 - focusmanager issues with e10s
 [browser_bug763468_perwindowpb.js]
 skip-if = e10s
 [browser_bug767836_perwindowpb.js]
 skip-if = e10s # Bug ?????? - test reports a leaked nsGlobalWindow with e10s enabled.
 [browser_bug771331.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content
 [browser_bug783614.js]
 [browser_bug816527.js]
 skip-if = e10s # Bug 916974 - Session history doesn't work in e10s
 [browser_bug817947.js]
-skip-if = e10s # Bug 916974 - Session history doesn't work in e10s
 [browser_bug822367.js]
 [browser_bug832435.js]
 [browser_bug839103.js]
 [browser_bug880101.js]
 [browser_bug882977.js]
 [browser_bug902156.js]
 skip-if = e10s
 [browser_bug906190.js]
@@ -489,17 +487,16 @@ skip-if = (os == "win" && !debug) || e10
 skip-if = buildapp == 'mulet'
 [browser_wyciwyg_urlbarCopying.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (content.document.getElementById)
 [browser_zbug569342.js]
 skip-if = e10s # Bug 516755 - SessionStore disabled for e10s
 [browser_registerProtocolHandler_notification.js]
 skip-if = e10s # Bug 940206 - nsIWebContentHandlerRegistrar::registerProtocolHandler doesn't work in e10s
 [browser_no_mcb_on_http_site.js]
-skip-if = e10s # Bug 516755 - SessionStore disabled for e10s
 [browser_bug1003461-switchtab-override.js]
 skip-if = e10s
 [browser_bug1024133-switchtab-override-keynav.js]
 skip-if = e10s
 [browser_bug1025195_switchToTabHavingURI_ignoreFragment.js]
 [browser_addCertException.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (content.document.getElementById)
 [browser_bug1045809.js]
--- a/browser/base/content/test/general/browser_e10s_switchbrowser.js
+++ b/browser/base/content/test/general/browser_e10s_switchbrowser.js
@@ -47,17 +47,18 @@ let check_history = Task.async(function*
     is(entry.uri, gExpectedHistory.entries[i].uri, "Should have the right URI");
     is(entry.title, gExpectedHistory.entries[i].title, "Should have the right title");
   }
 });
 
 // Waits for a load and updates the known history
 let waitForLoad = Task.async(function*(uri) {
   info("Loading " + uri);
-  gBrowser.loadURI(uri);
+  // Longwinded but this ensures we don't just shortcut to LoadInNewProcess
+  gBrowser.selectedBrowser.webNavigation.loadURI(uri, Ci.nsIWebNavigation.LOAD_FLAGS_NONE, null, null, null);
 
   yield waitForDocLoadComplete();
   gExpectedHistory.index++;
   gExpectedHistory.entries.push({
     uri: gBrowser.currentURI.spec,
     title: gBrowser.contentTitle
   });
 });
@@ -73,17 +74,17 @@ let forward = Task.async(function*() {
   info("Going forward");
   gBrowser.goForward();
   yield waitForDocLoadComplete();
   gExpectedHistory.index++;
 });
 
 // Tests that navigating from a page that should be in the remote process and
 // a page that should be in the main process works and retains history
-add_task(function*() {
+add_task(function* test_navigation() {
   SimpleTest.requestCompleteLog();
 
   let remoting = Services.prefs.getBoolPref("browser.tabs.remote.autostart");
   let expectedRemote = remoting ? "true" : "";
 
   info("1");
   // Create a tab and load a remote page in it
   gBrowser.selectedTab = gBrowser.addTab("about:blank", {skipAnimation: true});
@@ -133,10 +134,64 @@ add_task(function*() {
 
   info("8");
   yield forward();
   is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct");
   is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same");
   yield check_history();
 
   info("9");
+  yield back();
+  is(gBrowser.selectedTab.getAttribute("remote"), "", "Remote attribute should be correct");
+  is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same");
+  yield check_history();
+
+  info("10");
+  // Load a new remote page, this should replace the last history entry
+  gExpectedHistory.entries.splice(gExpectedHistory.entries.length - 1, 1);
+  yield waitForLoad("http://example.com/" + DUMMY_PATH);
+  is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct");
+  is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same");
+  yield check_history();
+
+  info("11");
   gBrowser.removeCurrentTab();
 });
+
+// Tests that calling gBrowser.loadURI or browser.loadURI to load a page in a
+// different process updates the browser synchronously
+add_task(function* test_synchronous() {
+  let remoting = Services.prefs.getBoolPref("browser.tabs.remote.autostart");
+  let expectedRemote = remoting ? "true" : "";
+
+  info("1");
+  // Create a tab and load a remote page in it
+  gBrowser.selectedTab = gBrowser.addTab("about:blank", {skipAnimation: true});
+  let {permanentKey} = gBrowser.selectedBrowser;
+  yield waitForLoad("http://example.org/" + DUMMY_PATH);
+  is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct");
+  is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same");
+
+  info("2");
+  // Load another page
+  info("Loading about:robots");
+  gBrowser.selectedBrowser.loadURI("about:robots");
+  is(gBrowser.selectedTab.getAttribute("remote"), "", "Remote attribute should be correct");
+  is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same");
+
+  yield waitForDocLoadComplete();
+  is(gBrowser.selectedTab.getAttribute("remote"), "", "Remote attribute should be correct");
+  is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same");
+
+  info("3");
+  // Load the remote page again
+  info("Loading http://example.org/" + DUMMY_PATH);
+  gBrowser.loadURI("http://example.org/" + DUMMY_PATH);
+  is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct");
+  is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same");
+
+  yield waitForDocLoadComplete();
+  is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct");
+  is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same");
+
+  info("4");
+  gBrowser.removeCurrentTab();
+});
--- a/browser/components/sessionstore/ContentRestore.jsm
+++ b/browser/components/sessionstore/ContentRestore.jsm
@@ -154,17 +154,17 @@ ContentRestoreInternal.prototype = {
     if (tabData.storage && this.docShell instanceof Ci.nsIDocShell)
       SessionStorage.restore(this.docShell, tabData.storage);
   },
 
   /**
    * Start loading the current page. When the data has finished loading from the
    * network, finishCallback is called. Returns true if the load was successful.
    */
-  restoreTabContent: function (finishCallback) {
+  restoreTabContent: function (loadArguments, finishCallback) {
     let tabData = this._tabData;
     this._tabData = null;
 
     let webNavigation = this.docShell.QueryInterface(Ci.nsIWebNavigation);
     let history = webNavigation.sessionHistory;
 
     // The reload listener is no longer needed.
     this._historyListener.uninstall();
@@ -183,17 +183,29 @@ ContentRestoreInternal.prototype = {
     this._progressListener = progressListener;
 
     // Reset the current URI to about:blank. We changed it above for
     // switch-to-tab, but now it must go back to the correct value before the
     // load happens.
     webNavigation.setCurrentURI(Utils.makeURI("about:blank"));
 
     try {
-      if (tabData.userTypedValue && tabData.userTypedClear) {
+      if (loadArguments) {
+        // A load has been redirected to a new process so get history into the
+        // same state it was before the load started then trigger the load.
+        let activeIndex = tabData.index - 1;
+        if (activeIndex > 0) {
+          // Go to the right history entry, but don't load anything yet.
+          history.getEntryAtIndex(activeIndex, true);
+        }
+        let referrer = loadArguments.referrer ?
+                       Utils.makeURI(loadArguments.referrer) : null;
+        webNavigation.loadURI(loadArguments.uri, loadArguments.loadFlags,
+                              referrer, null, null);
+      } else if (tabData.userTypedValue && tabData.userTypedClear) {
         // If the user typed a URL into the URL bar and hit enter right before
         // we crashed, we want to start loading that page again. A non-zero
         // userTypedClear value means that the load had started.
         let activeIndex = tabData.index - 1;
         if (activeIndex > 0) {
           // Go to the right history entry, but don't load anything yet.
           history.getEntryAtIndex(activeIndex, true);
         }
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -187,16 +187,26 @@ this.SessionStore = {
   getTabState: function ss_getTabState(aTab) {
     return SessionStoreInternal.getTabState(aTab);
   },
 
   setTabState: function ss_setTabState(aTab, aState) {
     SessionStoreInternal.setTabState(aTab, aState);
   },
 
+  // This should not be used by external code, the intention is to remove it
+  // once a better fix is in place for process switching in e10s.
+  // See bug 1075658 for context.
+  _restoreTabAndLoad: function ss_restoreTabAndLoad(aTab, aState, aLoadArguments) {
+    SessionStoreInternal.setTabState(aTab, aState, {
+      restoreImmediately: true,
+      loadArguments: aLoadArguments
+    });
+  },
+
   duplicateTab: function ss_duplicateTab(aWindow, aTab, aDelta = 0) {
     return SessionStoreInternal.duplicateTab(aWindow, aTab, aDelta);
   },
 
   getClosedTabCount: function ss_getClosedTabCount(aWindow) {
     return SessionStoreInternal.getClosedTabCount(aWindow);
   },
 
@@ -1567,17 +1577,17 @@ let SessionStoreInternal = {
       throw Components.Exception("Default view is not tracked", Cr.NS_ERROR_INVALID_ARG);
     }
 
     let tabState = TabState.collect(aTab);
 
     return this._toJSONString(tabState);
   },
 
-  setTabState: function ssi_setTabState(aTab, aState) {
+  setTabState: function ssi_setTabState(aTab, aState, aOptions) {
     // Remove the tab state from the cache.
     // Note that we cannot simply replace the contents of the cache
     // as |aState| can be an incomplete state that will be completed
     // by |restoreTabs|.
     let tabState = JSON.parse(aState);
     if (!tabState) {
       throw Components.Exception("Invalid state string: not JSON", Cr.NS_ERROR_INVALID_ARG);
     }
@@ -1592,17 +1602,17 @@ let SessionStoreInternal = {
     if (!("__SSi" in window)) {
       throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
     }
 
     if (aTab.linkedBrowser.__SS_restoreState) {
       this._resetTabRestoringState(aTab);
     }
 
-    this.restoreTab(aTab, tabState);
+    this.restoreTab(aTab, tabState, aOptions);
   },
 
   duplicateTab: function ssi_duplicateTab(aWindow, aTab, aDelta = 0) {
     if (!aTab.ownerDocument.defaultView.__SSi) {
       throw Components.Exception("Default view is not tracked", Cr.NS_ERROR_INVALID_ARG);
     }
     if (!aWindow.getBrowser) {
       throw Components.Exception("Invalid window object: no getBrowser", Cr.NS_ERROR_INVALID_ARG);
@@ -1618,17 +1628,19 @@ let SessionStoreInternal = {
     tabState.index += aDelta;
     tabState.index = Math.max(1, Math.min(tabState.index, tabState.entries.length));
     tabState.pinned = false;
 
     let newTab = aTab == aWindow.gBrowser.selectedTab ?
       aWindow.gBrowser.addTab(null, {relatedToCurrent: true, ownerTab: aTab}) :
       aWindow.gBrowser.addTab();
 
-    this.restoreTab(newTab, tabState, true /* Load this tab right away. */);
+    this.restoreTab(newTab, tabState, {
+      restoreImmediately: true /* Load this tab right away. */
+    });
     return newTab;
   },
 
   getClosedTabCount: function ssi_getClosedTabCount(aWindow) {
     if ("__SSi" in aWindow) {
       return this._windows[aWindow.__SSi]._closedTabs.length;
     }
 
@@ -2522,17 +2534,19 @@ let SessionStoreInternal = {
 
     // Restore all tabs.
     for (let t = 0; t < aTabs.length; t++) {
       this.restoreTab(aTabs[t], aTabData[t]);
     }
   },
 
   // Restores the given tab state for a given tab.
-  restoreTab(tab, tabData, restoreImmediately = false) {
+  restoreTab(tab, tabData, options = {}) {
+    let restoreImmediately = options.restoreImmediately;
+    let loadArguments = options.loadArguments;
     let browser = tab.linkedBrowser;
     let window = tab.ownerDocument.defaultView;
     let tabbrowser = window.gBrowser;
 
     // Increase the busy state counter before modifying the tab.
     this._setWindowStateBusy(window);
 
     // It's important to set the window state to dirty so that
@@ -2590,16 +2604,19 @@ let SessionStoreInternal = {
 
     // Save the index in case we updated it above.
     tabData.index = activeIndex + 1;
 
     // In electrolysis, we may need to change the browser's remote
     // attribute so that it runs in a content process.
     let activePageData = tabData.entries[activeIndex] || null;
     let uri = activePageData ? activePageData.url || null : null;
+    if (loadArguments) {
+      uri = loadArguments.uri;
+    }
     tabbrowser.updateBrowserRemotenessByURL(browser, uri);
 
     // Start a new epoch and include the epoch in the restoreHistory
     // message. If a message is received that relates to a previous epoch, we
     // discard it.
     let epoch = this._nextRestoreEpoch++;
     this._browserEpochs.set(browser.permanentKey, epoch);
 
@@ -2625,18 +2642,18 @@ let SessionStoreInternal = {
 
     // Restore tab attributes.
     if ("attributes" in tabData) {
       TabAttributes.set(tab, tabData.attributes);
     }
 
     // This could cause us to ignore MAX_CONCURRENT_TAB_RESTORES a bit, but
     // it ensures each window will have its selected tab loaded.
-    if (restoreImmediately || tabbrowser.selectedBrowser == browser) {
-      this.restoreTabContent(tab);
+    if (restoreImmediately || tabbrowser.selectedBrowser == browser || loadArguments) {
+      this.restoreTabContent(tab, loadArguments);
     } else {
       TabRestoreQueue.add(tab);
       this.restoreNextTab();
     }
 
     // Decrease the busy state counter after we're done.
     this._setWindowStateReady(window);
   },
@@ -2653,17 +2670,17 @@ let SessionStoreInternal = {
    * restore the next tab. In the other case (selecting the tab, reloading the
    * tab), the caller doesn't actually want to do anything if no page is loaded.
    *
    * @param aTab
    *        the tab to restore
    *
    * @returns true/false indicating whether or not a load actually happened
    */
-  restoreTabContent: function (aTab) {
+  restoreTabContent: function (aTab, aLoadArguments = null) {
     let window = aTab.ownerDocument.defaultView;
     let browser = aTab.linkedBrowser;
     let tabData = browser.__SS_data;
 
     // Make sure that this tab is removed from the priority queue.
     TabRestoreQueue.remove(aTab);
 
     // Increase our internal count.
@@ -2682,17 +2699,18 @@ let SessionStoreInternal = {
       // preserved in the plain history entries (mainly scroll state and text data)
       browser.__SS_restore_data = tabData.entries[activeIndex] || {};
     } else {
       browser.__SS_restore_data = {};
     }
 
     browser.__SS_restore_tab = aTab;
 
-    browser.messageManager.sendAsyncMessage("SessionStore:restoreTabContent");
+    browser.messageManager.sendAsyncMessage("SessionStore:restoreTabContent",
+      {loadArguments: aLoadArguments});
   },
 
   /**
    * This _attempts_ to restore the next available tab. If the restore fails,
    * then we will attempt the next one.
    * There are conditions where this won't do anything:
    *   if we're in the process of quitting
    *   if there are no tabs to restore
--- a/browser/components/sessionstore/content/content-sessionStore.js
+++ b/browser/components/sessionstore/content/content-sessionStore.js
@@ -140,17 +140,17 @@ let MessageListener = {
         let epoch = gContentRestore.getRestoreEpoch();
         let finishCallback = () => {
           // Tell SessionStore.jsm that it may want to restore some more tabs,
           // since it restores a max of MAX_CONCURRENT_TAB_RESTORES at a time.
           sendAsyncMessage("SessionStore:restoreTabContentComplete", {epoch: epoch});
         };
 
         // We need to pass the value of didStartLoad back to SessionStore.jsm.
-        let didStartLoad = gContentRestore.restoreTabContent(finishCallback);
+        let didStartLoad = gContentRestore.restoreTabContent(data.loadArguments, finishCallback);
 
         sendAsyncMessage("SessionStore:restoreTabContentStarted", {epoch: epoch});
 
         if (!didStartLoad) {
           // Pretend that the load succeeded so that event handlers fire correctly.
           sendAsyncMessage("SessionStore:restoreTabContentComplete", {epoch: epoch});
           sendAsyncMessage("SessionStore:restoreDocumentComplete", {epoch: epoch});
         }
--- a/browser/components/sessionstore/test/browser.ini
+++ b/browser/components/sessionstore/test/browser.ini
@@ -61,40 +61,38 @@ support-files =
 [browser_aboutPrivateBrowsing.js]
 [browser_aboutSessionRestore.js]
 [browser_attributes.js]
 [browser_backup_recovery.js]
 [browser_broadcast.js]
 [browser_capabilities.js]
 [browser_cleaner.js]
 [browser_dying_cache.js]
-skip-if = e10s
 [browser_dynamic_frames.js]
 [browser_form_restore_events.js]
 [browser_formdata.js]
 skip-if = buildapp == 'mulet'
 [browser_formdata_format.js]
 [browser_formdata_xpath.js]
 [browser_frametree.js]
 [browser_frame_history.js]
 [browser_global_store.js]
 [browser_history_cap.js]
 [browser_label_and_icon.js]
 [browser_merge_closed_tabs.js]
 [browser_pageStyle.js]
 [browser_privatetabs.js]
 [browser_scrollPositions.js]
 [browser_sessionHistory.js]
+# Disabled because of bug 1077581
 skip-if = e10s
 [browser_sessionStorage.js]
-skip-if = e10s
 [browser_swapDocShells.js]
 skip-if = e10s # See bug 918634
 [browser_telemetry.js]
-skip-if = e10s
 [browser_upgrade_backup.js]
 [browser_windowRestore_perwindowpb.js]
 [browser_248970_b_perwindowpb.js]
 # Disabled because of leaks.
 # Re-enabling and rewriting this test is tracked in bug 936919.
 skip-if = true
 [browser_339445.js]
 [browser_345898.js]
@@ -102,34 +100,31 @@ skip-if = true
 [browser_354894_perwindowpb.js]
 [browser_367052.js]
 [browser_393716.js]
 [browser_394759_basic.js]
 # Disabled for intermittent failures, bug 944372.
 skip-if = true
 [browser_394759_behavior.js]
 [browser_394759_perwindowpb.js]
-skip-if = e10s
 [browser_394759_purge.js]
 [browser_423132.js]
-skip-if = e10s
 [browser_447951.js]
 [browser_454908.js]
 [browser_456342.js]
 [browser_461634.js]
 [browser_463205.js]
 [browser_463206.js]
 [browser_464199.js]
 [browser_465215.js]
 [browser_465223.js]
 [browser_466937.js]
 [browser_467409-backslashplosion.js]
 [browser_477657.js]
 [browser_480893.js]
-skip-if = e10s
 [browser_485482.js]
 [browser_485563.js]
 [browser_490040.js]
 [browser_491168.js]
 # Disabled for too many intermittent failures.
 # Can be re-enabled once bug 930202 lands.
 skip-if = true
 [browser_491577.js]
@@ -192,11 +187,11 @@ skip-if = os == "linux" || e10s # Linux:
 # Disabled for frequent intermittent failures
 [browser_464620_a.js]
 skip-if = true
 [browser_464620_b.js]
 skip-if = true
 
 # Disabled on OS X:
 [browser_625016.js]
-skip-if = os == "mac" || e10s
+skip-if = os == "mac"
 
 [browser_911547.js]
--- a/browser/components/sessionstore/test/browser_423132.js
+++ b/browser/components/sessionstore/test/browser_423132.js
@@ -20,53 +20,56 @@ function test() {
 
   // open a new window
   let newWin = openDialog(location, "_blank", "chrome,all,dialog=no", "about:blank");
 
   // make sure sessionstore saves the cookie data, then close the window
   newWin.addEventListener("load", function (aEvent) {
     newWin.removeEventListener("load", arguments.callee, false);
 
-    newWin.gBrowser.loadURI(testURL, null, null);
+    // Wait for sessionstore to be ready to restore this window
+    executeSoon(function() {
+      newWin.gBrowser.loadURI(testURL, null, null);
 
-    whenBrowserLoaded(newWin.gBrowser.selectedBrowser, function() {
-      // get the sessionstore state for the window
-      TabState.flush(newWin.gBrowser.selectedBrowser);
-      let state = ss.getWindowState(newWin);
+      whenBrowserLoaded(newWin.gBrowser.selectedBrowser, function() {
+        // get the sessionstore state for the window
+        TabState.flush(newWin.gBrowser.selectedBrowser);
+        let state = ss.getWindowState(newWin);
 
-      // verify our cookie got set during pageload
-      let e = cs.enumerator;
-      let cookie;
-      let i = 0;
-      while (e.hasMoreElements()) {
-        cookie = e.getNext().QueryInterface(Ci.nsICookie);
-        i++;
-      }
-      is(i, 1, "expected one cookie");
+        // verify our cookie got set during pageload
+        let e = cs.enumerator;
+        let cookie;
+        let i = 0;
+        while (e.hasMoreElements()) {
+          cookie = e.getNext().QueryInterface(Ci.nsICookie);
+          i++;
+        }
+        is(i, 1, "expected one cookie");
 
-      // remove the cookie
-      cs.removeAll();
+        // remove the cookie
+        cs.removeAll();
 
-      // restore the window state
-      ss.setWindowState(newWin, state, true);
+        // restore the window state
+        ss.setWindowState(newWin, state, true);
 
-      // at this point, the cookie should be restored...
-      e = cs.enumerator;
-      let cookie2;
-      while (e.hasMoreElements()) {
-        cookie2 = e.getNext().QueryInterface(Ci.nsICookie);
-        if (cookie.name == cookie2.name)
-          break;
-      }
-      is(cookie.name, cookie2.name, "cookie name successfully restored");
-      is(cookie.value, cookie2.value, "cookie value successfully restored");
-      is(cookie.path, cookie2.path, "cookie path successfully restored");
+        // at this point, the cookie should be restored...
+        e = cs.enumerator;
+        let cookie2;
+        while (e.hasMoreElements()) {
+          cookie2 = e.getNext().QueryInterface(Ci.nsICookie);
+          if (cookie.name == cookie2.name)
+            break;
+        }
+        is(cookie.name, cookie2.name, "cookie name successfully restored");
+        is(cookie.value, cookie2.value, "cookie value successfully restored");
+        is(cookie.path, cookie2.path, "cookie path successfully restored");
 
-      // clean up
-      if (gPrefService.prefHasUserValue("browser.sessionstore.interval"))
-        gPrefService.clearUserPref("browser.sessionstore.interval");
-      cs.removeAll();
-      newWin.close();
-      finish();
-    }, true, testURL);
+        // clean up
+        if (gPrefService.prefHasUserValue("browser.sessionstore.interval"))
+          gPrefService.clearUserPref("browser.sessionstore.interval");
+        cs.removeAll();
+        newWin.close();
+        finish();
+      }, true, testURL);
+    });
   }, false);
 }
 
--- a/browser/components/sessionstore/test/browser_819510_perwindowpb.js
+++ b/browser/components/sessionstore/test/browser_819510_perwindowpb.js
@@ -170,14 +170,14 @@ function forceWriteState(aCallback) {
 }
 
 function testOnWindow(aIsPrivate, aCallback) {
   whenNewWindowLoaded({private: aIsPrivate}, aCallback);
 }
 
 function waitForTabLoad(aWin, aURL, aCallback) {
   let browser = aWin.gBrowser.selectedBrowser;
+  browser.loadURI(aURL);
   whenBrowserLoaded(browser, function () {
     TabState.flush(browser);
     executeSoon(aCallback);
   });
-  browser.loadURI(aURL);
 }
--- a/browser/components/tabview/test/browser.ini
+++ b/browser/components/tabview/test/browser.ini
@@ -12,16 +12,17 @@ support-files =
 [browser_tabview_alltabs.js]
 [browser_tabview_apptabs.js]
 [browser_tabview_bug580412.js]
 [browser_tabview_bug586553.js]
 [browser_tabview_bug587043.js]
 [browser_tabview_bug587231.js]
 skip-if = buildapp == 'mulet'
 [browser_tabview_bug587276.js]
+skip-if = e10s # Bug 1091200
 [browser_tabview_bug587351.js]
 [browser_tabview_bug587503.js]
 [browser_tabview_bug587990.js]
 [browser_tabview_bug588265.js]
 [browser_tabview_bug589324.js]
 skip-if = e10s # Bug 1086190
 [browser_tabview_bug590606.js]
 [browser_tabview_bug591706.js]
--- a/browser/modules/E10SUtils.jsm
+++ b/browser/modules/E10SUtils.jsm
@@ -46,15 +46,18 @@ this.E10SUtils = {
 
   redirectLoad: function(aDocShell, aURI, aReferrer) {
     // Retarget the load to the correct process
     let messageManager = aDocShell.QueryInterface(Ci.nsIInterfaceRequestor)
                                   .getInterface(Ci.nsIContentFrameMessageManager);
     let sessionHistory = aDocShell.getInterface(Ci.nsIWebNavigation).sessionHistory;
 
     messageManager.sendAsyncMessage("Browser:LoadURI", {
-      uri: aURI.spec,
-      referrer: aReferrer ? aReferrer.spec : null,
+      loadOptions: {
+        uri: aURI.spec,
+        flags: Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
+        referrer: aReferrer ? aReferrer.spec : null,
+      },
       historyIndex: sessionHistory.requestedIndex,
     });
     return false;
   },
 };
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -128,24 +128,16 @@
         <parameter name="aReferrerURI"/>
         <parameter name="aCharset"/>
         <parameter name="aPostData"/>
         <body>
           <![CDATA[
             if (!aURI)
               aURI = "about:blank";
 
-            if (aCharset) {
-              try {
-                this.docShell.parentCharset = aCharset;
-              }
-              catch (e) {
-              }
-            }
-
             if (!(aFlags & this.webNavigation.LOAD_FLAGS_FROM_EXTERNAL))
               this.userTypedClear++;
 
             try {
               this.webNavigation.loadURI(aURI, aFlags, aReferrerURI, aPostData, null);
             } finally {
               if (this.userTypedClear)
                 this.userTypedClear--;