Bug 941540 - Use browser.permanentKey to handle docShell swaps more easily r=yoric
authorTim Taubert <ttaubert@mozilla.com>
Mon, 20 Jan 2014 20:50:17 +0100
changeset 165123 0bc8711e7dd2b40002ffa82c97328536a81b4fe1
parent 165122 dcee48651880bc2267e5eaf17c8e5d9e4aae3ed2
child 165124 e0cd2d1ff7b79cabb7f31beedc4c1afc7e629146
push id26075
push userryanvm@gmail.com
push dateFri, 24 Jan 2014 22:00:17 +0000
treeherdermozilla-central@a12c7d7ac590 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersyoric
bugs941540
milestone29.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 941540 - Use browser.permanentKey to handle docShell swaps more easily r=yoric
browser/components/sessionstore/src/SessionStore.jsm
browser/components/sessionstore/src/TabState.jsm
browser/components/sessionstore/src/TabStateCache.jsm
browser/components/sessionstore/src/Utils.jsm
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -707,22 +707,16 @@ let SessionStoreInternal = {
 
   /**
    * Implement nsIDOMEventListener for handling various window and tab events
    */
   handleEvent: function ssi_handleEvent(aEvent) {
     var win = aEvent.currentTarget.ownerDocument.defaultView;
     let browser;
     switch (aEvent.type) {
-      case "SwapDocShells":
-        browser = aEvent.currentTarget;
-        let otherBrowser = aEvent.detail;
-        TabState.onBrowserContentsSwapped(browser, otherBrowser);
-        TabStateCache.onBrowserContentsSwapped(browser, otherBrowser);
-        break;
       case "TabOpen":
         this.onTabAdd(win, aEvent.originalTarget);
         break;
       case "TabClose":
         // aEvent.detail determines if the tab was closed by moving to a different window
         if (!aEvent.detail)
           this.onTabClose(win, aEvent.originalTarget);
         this.onTabRemove(win, aEvent.originalTarget);
@@ -1292,20 +1286,17 @@ let SessionStoreInternal = {
    * @param aWindow
    *        Window reference
    * @param aTab
    *        Tab reference
    * @param aNoNotification
    *        bool Do not save state if we're updating an existing tab
    */
   onTabAdd: function ssi_onTabAdd(aWindow, aTab, aNoNotification) {
-    let browser = aTab.linkedBrowser;
-    browser.addEventListener("SwapDocShells", this, true);
-
-    let mm = browser.messageManager;
+    let mm = aTab.linkedBrowser.messageManager;
     MESSAGES.forEach(msg => mm.addMessageListener(msg, this));
 
     // Load the frame script after registering listeners.
     mm.loadFrameScript("chrome://browser/content/content-sessionStore.js", false);
 
     if (!aNoNotification) {
       this.saveStateDelayed(aWindow);
     }
@@ -1319,18 +1310,16 @@ let SessionStoreInternal = {
    *        Window reference
    * @param aTab
    *        Tab reference
    * @param aNoNotification
    *        bool Do not save state if we're updating an existing tab
    */
   onTabRemove: function ssi_onTabRemove(aWindow, aTab, aNoNotification) {
     let browser = aTab.linkedBrowser;
-    browser.removeEventListener("SwapDocShells", this, true);
-
     let mm = browser.messageManager;
     MESSAGES.forEach(msg => mm.removeMessageListener(msg, this));
 
     delete browser.__SS_data;
 
     // If this tab was in the middle of restoring or still needs to be restored,
     // we need to reset that state. If the tab was restoring, we will attempt to
     // restore the next tab.
@@ -2597,17 +2586,17 @@ let SessionStoreInternal = {
 
       // Save the index in case we updated it above.
       tabData.index = activeIndex + 1;
 
       // 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, epoch);
+      this._browserEpochs.set(browser.permanentKey, epoch);
 
       // keep the data around to prevent dataloss in case
       // a tab gets closed before it's been properly restored
       browser.__SS_data = tabData;
       browser.__SS_restoreState = TAB_STATE_NEEDS_RESTORE;
       browser.setAttribute("pending", "true");
       tab.setAttribute("pending", "true");
 
@@ -3463,17 +3452,17 @@ let SessionStoreInternal = {
     let window = aTab.ownerDocument.defaultView;
     let browser = aTab.linkedBrowser;
 
     // Keep the tab's previous state for later in this method
     let previousState = browser.__SS_restoreState;
 
     // The browser is no longer in any sort of restoring state.
     delete browser.__SS_restoreState;
-    this._browserEpochs.delete(browser);
+    this._browserEpochs.delete(browser.permanentKey);
 
     aTab.removeAttribute("pending");
     browser.removeAttribute("pending");
 
     if (previousState == TAB_STATE_RESTORING) {
       if (this._tabsRestoringCount)
         this._tabsRestoringCount--;
     } else if (previousState == TAB_STATE_NEEDS_RESTORE) {
@@ -3495,17 +3484,17 @@ let SessionStoreInternal = {
   /**
    * Each time a <browser> element is restored, we increment its "epoch". To
    * check if a message from content-sessionStore.js is out of date, we can
    * compare the epoch received with the message to the <browser> element's
    * epoch. This function does that, and returns true if |epoch| is up-to-date
    * with respect to |browser|.
    */
   isCurrentEpoch: function (browser, epoch) {
-    return this._browserEpochs.get(browser, 0) == epoch;
+    return this._browserEpochs.get(browser.permanentKey, 0) == epoch;
   },
 
 };
 
 /**
  * Priority queue that keeps track of a list of tabs to restore and returns
  * the tab we should restore next, based on priority rules. We decide between
  * pinned, visible and hidden tabs in that and FIFO order. Hidden tabs are only
--- a/browser/components/sessionstore/src/TabState.jsm
+++ b/browser/components/sessionstore/src/TabState.jsm
@@ -15,31 +15,25 @@ Cu.import("resource://gre/modules/Task.j
 XPCOMUtils.defineLazyModuleGetter(this, "console",
   "resource://gre/modules/devtools/Console.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivacyFilter",
   "resource:///modules/sessionstore/PrivacyFilter.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "TabStateCache",
   "resource:///modules/sessionstore/TabStateCache.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "TabAttributes",
   "resource:///modules/sessionstore/TabAttributes.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Utils",
-  "resource:///modules/sessionstore/Utils.jsm");
 
 /**
  * Module that contains tab state collection methods.
  */
 this.TabState = Object.freeze({
   setSyncHandler: function (browser, handler) {
     TabStateInternal.setSyncHandler(browser, handler);
   },
 
-  onBrowserContentsSwapped: function (browser, otherBrowser) {
-    TabStateInternal.onBrowserContentsSwapped(browser, otherBrowser);
-  },
-
   update: function (browser, data) {
     TabStateInternal.update(browser, data);
   },
 
   flush: function (browser) {
     TabStateInternal.flush(browser);
   },
 
@@ -65,65 +59,53 @@ let TabStateInternal = {
   // A map (xul:browser -> int) that maps a browser to the
   // last "SessionStore:update" message ID we received for it.
   _latestMessageID: new WeakMap(),
 
   /**
    * Install the sync handler object from a given tab.
    */
   setSyncHandler: function (browser, handler) {
-    this._syncHandlers.set(browser, handler);
-    this._latestMessageID.set(browser, 0);
+    this._syncHandlers.set(browser.permanentKey, handler);
+    this._latestMessageID.set(browser.permanentKey, 0);
   },
 
   /**
    * Processes a data update sent by the content script.
    */
   update: function (browser, {id, data}) {
     // Only ever process messages that have an ID higher than the last one we
     // saw. This ensures we don't use stale data that has already been received
     // synchronously.
-    if (id > this._latestMessageID.get(browser)) {
-      this._latestMessageID.set(browser, id);
+    if (id > this._latestMessageID.get(browser.permanentKey)) {
+      this._latestMessageID.set(browser.permanentKey, id);
       TabStateCache.update(browser, data);
     }
   },
 
   /**
    * Flushes all data currently queued in the given browser's content script.
    */
   flush: function (browser) {
-    if (this._syncHandlers.has(browser)) {
-      let lastID = this._latestMessageID.get(browser);
-      this._syncHandlers.get(browser).flush(lastID);
+    if (this._syncHandlers.has(browser.permanentKey)) {
+      let lastID = this._latestMessageID.get(browser.permanentKey);
+      this._syncHandlers.get(browser.permanentKey).flush(lastID);
     }
   },
 
   /**
    * Flushes queued content script data for all browsers of a given window.
    */
   flushWindow: function (window) {
     for (let browser of window.gBrowser.browsers) {
       this.flush(browser);
     }
   },
 
   /**
-   * When a docshell swap happens, a xul:browser element will be
-   * associated with a different content-sessionStore.js script
-   * global. In this case, the sync handler for the element needs to
-   * be swapped just like the docshell.
-   */
-  onBrowserContentsSwapped: function (browser, otherBrowser) {
-    // Swap data stored per-browser.
-    [this._syncHandlers, this._latestMessageID]
-      .forEach(map => Utils.swapMapEntries(map, browser, otherBrowser));
-  },
-
-  /**
    * Collect data related to a single tab, synchronously.
    *
    * @param tab
    *        tabbrowser tab
    *
    * @returns {TabData} An object with the data for this tab.  If the
    * tab has not been invalidated since the last call to
    * collect(aTab), the same object is returned.
--- a/browser/components/sessionstore/src/TabStateCache.jsm
+++ b/browser/components/sessionstore/src/TabStateCache.jsm
@@ -1,47 +1,28 @@
 /* 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/. */
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["TabStateCache"];
 
-const Cu = Components.utils;
-Cu.import("resource://gre/modules/Services.jsm", this);
-Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
-
-XPCOMUtils.defineLazyModuleGetter(this, "Utils",
-  "resource:///modules/sessionstore/Utils.jsm");
-
 /**
  * A cache for tabs data.
  *
  * This cache implements a weak map from tabs (as XUL elements)
  * to tab data (as objects).
  *
  * Note that we should never cache private data, as:
  * - that data is used very seldom by SessionStore;
  * - caching private data in addition to public data is memory consuming.
  */
 this.TabStateCache = Object.freeze({
   /**
-   * Swap cached data for two given browsers.
-   *
-   * @param {xul:browser} browser
-   *        The first of the two browsers that swapped docShells.
-   * @param {xul:browser} otherBrowser
-   *        The second of the two browsers that swapped docShells.
-   */
-  onBrowserContentsSwapped: function(browser, otherBrowser) {
-    TabStateCacheInternal.onBrowserContentsSwapped(browser, otherBrowser);
-  },
-
-  /**
    * Retrieves cached data for a given |browser|.
    *
    * @param browser (xul:browser)
    *        The browser to retrieve cached data for.
    * @return (object)
    *         The cached data stored for the given |browser|.
    */
   get: function (browser) {
@@ -60,55 +41,42 @@ this.TabStateCache = Object.freeze({
     TabStateCacheInternal.update(browser, newData);
   }
 });
 
 let TabStateCacheInternal = {
   _data: new WeakMap(),
 
   /**
-   * Swap cached data for two given browsers.
-   *
-   * @param {xul:browser} browser
-   *        The first of the two browsers that swapped docShells.
-   * @param {xul:browser} otherBrowser
-   *        The second of the two browsers that swapped docShells.
-   */
-  onBrowserContentsSwapped: function(browser, otherBrowser) {
-    // Swap data stored per-browser.
-    Utils.swapMapEntries(this._data, browser, otherBrowser);
-  },
-
-  /**
    * Retrieves cached data for a given |browser|.
    *
    * @param browser (xul:browser)
    *        The browser to retrieve cached data for.
    * @return (object)
    *         The cached data stored for the given |browser|.
    */
   get: function (browser) {
-    return this._data.get(browser);
+    return this._data.get(browser.permanentKey);
   },
 
   /**
    * Updates cached data for a given |browser|.
    *
    * @param browser (xul:browser)
    *        The browser belonging to the given tab data.
    * @param newData (object)
    *        The new data to be stored for the given |browser|.
    */
   update: function (browser, newData) {
-    let data = this._data.get(browser) || {};
+    let data = this._data.get(browser.permanentKey) || {};
 
     for (let key of Object.keys(newData)) {
       let value = newData[key];
       if (value === null) {
         delete data[key];
       } else {
         data[key] = value;
       }
     }
 
-    this._data.set(browser, data);
+    this._data.set(browser.permanentKey, data);
   }
 };
--- a/browser/components/sessionstore/src/Utils.jsm
+++ b/browser/components/sessionstore/src/Utils.jsm
@@ -36,33 +36,10 @@ this.Utils = Object.freeze({
       return false;
 
     if (host == domain)
       return true;
 
     let prevChar = host[index - 1];
     return (index == (host.length - domain.length)) &&
            (prevChar == "." || prevChar == "/");
-  },
-
-  swapMapEntries: function (map, key, otherKey) {
-    // Make sure that one or the other of these has an entry in the map,
-    // and let it be |key|.
-    if (!map.has(key)) {
-      [key, otherKey] = [otherKey, key];
-      if (!map.has(key)) {
-        return;
-      }
-    }
-
-    // At this point, |key| is guaranteed to have an entry,
-    // although |otherKey| may not. Perform the swap.
-    let value = map.get(key);
-    if (map.has(otherKey)) {
-      let otherValue = map.get(otherKey);
-      map.set(key, otherValue);
-      map.set(otherKey, value);
-    } else {
-      map.set(otherKey, value);
-      map.delete(key);
-    }
   }
 });