Bug 1497146 part 1 - Add SessionStoreUtils.webidl r=nika
☠☠ backed out by 5088f1dd3230 ☠ ☠
authorAlphan Chen <alchen@mozilla.com>
Fri, 04 Jan 2019 16:26:13 +0000
changeset 509659 dbea03a5c55e1deb19b8092c0cc13bf33af8e99c
parent 509658 227f1a73b16fba34216e1fb408eca5aeefcf8497
child 509660 eacca0ce75d8d2625df1e7ebddaeeab99672751e
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnika
bugs1497146
milestone66.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 1497146 part 1 - Add SessionStoreUtils.webidl r=nika Let SessionStoreUtils be a WebIDL namespace, rather than a XPCOM service Differential Revision: https://phabricator.services.mozilla.com/D9776
browser/components/sessionstore/ContentRestore.jsm
browser/components/sessionstore/ContentSessionStore.jsm
browser/components/sessionstore/SessionStorage.jsm
browser/components/sessionstore/test/browser_frametree.js
dom/chrome-webidl/SessionStoreUtils.webidl
dom/chrome-webidl/moz.build
mobile/android/chrome/geckoview/GeckoViewContentChild.js
mobile/android/components/SessionStore.js
toolkit/components/build/nsToolkitCompsModule.cpp
toolkit/components/sessionstore/SessionStoreUtils.cpp
toolkit/components/sessionstore/SessionStoreUtils.h
toolkit/components/sessionstore/moz.build
toolkit/components/sessionstore/nsISessionStoreUtils.idl
toolkit/components/sessionstore/nsSessionStoreUtils.cpp
toolkit/components/sessionstore/nsSessionStoreUtils.h
toolkit/modules/sessionstore/Utils.jsm
tools/lint/eslint/eslint-plugin-mozilla/lib/environments/privileged.js
--- a/browser/components/sessionstore/ContentRestore.jsm
+++ b/browser/components/sessionstore/ContentRestore.jsm
@@ -12,19 +12,16 @@ ChromeUtils.defineModuleGetter(this, "Fo
   "resource://gre/modules/FormData.jsm");
 ChromeUtils.defineModuleGetter(this, "SessionHistory",
   "resource://gre/modules/sessionstore/SessionHistory.jsm");
 ChromeUtils.defineModuleGetter(this, "SessionStorage",
   "resource:///modules/sessionstore/SessionStorage.jsm");
 ChromeUtils.defineModuleGetter(this, "Utils",
   "resource://gre/modules/sessionstore/Utils.jsm");
 
-const ssu = Cc["@mozilla.org/browser/sessionstore/utils;1"]
-              .getService(Ci.nsISessionStoreUtils);
-
 /**
  * This module implements the content side of session restoration. The chrome
  * side is handled by SessionStore.jsm. The functions in this module are called
  * by content-sessionStore.js based on messages received from SessionStore.jsm
  * (or, in one case, based on a "load" event). Each tab has its own
  * ContentRestore instance, constructed by content-sessionStore.js.
  *
  * In a typical restore, content-sessionStore.js will call the following based
@@ -135,17 +132,18 @@ ContentRestoreInternal.prototype = {
       this.restoreTabContent(null, false, callbacks.onLoadFinished);
     });
 
     webNavigation.sessionHistory.legacySHistory.addSHistoryListener(listener);
     this._historyListener = listener;
 
     // Make sure to reset the capabilities and attributes in case this tab gets
     // reused.
-    ssu.restoreDocShellCapabilities(this.docShell, tabData.disallow);
+    SessionStoreUtils.restoreDocShellCapabilities(this.docShell, tabData.disallow);
+
 
     if (tabData.storage && this.docShell instanceof Ci.nsIDocShell) {
       SessionStorage.restore(this.docShell, tabData.storage);
       delete tabData.storage;
     }
 
     // Add a progress listener to correctly handle browser.loadURI()
     // calls from foreign code.
@@ -293,17 +291,17 @@ ContentRestoreInternal.prototype = {
       // current |frame| and its descendants, if |data.url| is given but
       // doesn't match the loaded document's URL.
       return FormData.restore(frame, data);
     });
 
     // Restore scroll data.
     Utils.restoreFrameTreeData(window, scrollPositions, (frame, data) => {
       if (data.scroll) {
-        ssu.restoreScrollPosition(frame, data.scroll);
+        SessionStoreUtils.restoreScrollPosition(frame, data);
       }
     });
   },
 
   /**
    * Cancel an ongoing restore. This function can be called any time between
    * restoreHistory and restoreDocument.
    *
--- a/browser/components/sessionstore/ContentSessionStore.jsm
+++ b/browser/components/sessionstore/ContentSessionStore.jsm
@@ -21,18 +21,16 @@ ChromeUtils.defineModuleGetter(this, "Co
   "resource:///modules/sessionstore/ContentRestore.jsm");
 ChromeUtils.defineModuleGetter(this, "SessionHistory",
   "resource://gre/modules/sessionstore/SessionHistory.jsm");
 ChromeUtils.defineModuleGetter(this, "SessionStorage",
   "resource:///modules/sessionstore/SessionStorage.jsm");
 
 ChromeUtils.defineModuleGetter(this, "Utils",
   "resource://gre/modules/sessionstore/Utils.jsm");
-const ssu = Cc["@mozilla.org/browser/sessionstore/utils;1"]
-              .getService(Ci.nsISessionStoreUtils);
 
 // A bound to the size of data to store for DOM Storage.
 const DOM_STORAGE_LIMIT_PREF = "browser.sessionstore.dom_storage_limit";
 
 // This pref controls whether or not we send updates to the parent on a timeout
 // or not, and should only be used for tests or debugging.
 const TIMEOUT_DISABLED_PREF = "browser.sessionstore.debug.no_auto_updates";
 
@@ -146,17 +144,17 @@ StateChangeNotifier.prototype.QueryInter
 /**
  * Listens for and handles content events that we need for the
  * session store service to be notified of state changes in content.
  */
 class EventListener extends Handler {
   constructor(store) {
     super(store);
 
-    ssu.addDynamicFrameFilteredListener(this.mm, "load", this, true);
+    SessionStoreUtils.addDynamicFrameFilteredListener(this.mm, "load", this, true);
   }
 
   handleEvent(event) {
     let {content} = this.mm;
 
     // Ignore load events from subframes.
     if (event.target != content.document) {
       return;
@@ -324,34 +322,34 @@ SessionHistoryListener.prototype.QueryIn
  *
  * Example:
  *   {scroll: "100,100", children: [null, null, {scroll: "200,200"}]}
  */
 class ScrollPositionListener extends Handler {
   constructor(store) {
     super(store);
 
-    ssu.addDynamicFrameFilteredListener(this.mm, "scroll", this, false);
+    SessionStoreUtils.addDynamicFrameFilteredListener(this.mm, "scroll", this, false);
     this.stateChangeNotifier.addObserver(this);
   }
 
   handleEvent() {
     this.messageQueue.push("scroll", () => this.collect());
   }
 
   onPageLoadCompleted() {
     this.messageQueue.push("scroll", () => this.collect());
   }
 
   onPageLoadStarted() {
     this.messageQueue.push("scroll", () => null);
   }
 
   collect() {
-    return mapFrameTree(this.mm, ssu.collectScrollPosition.bind(ssu));
+    return mapFrameTree(this.mm, SessionStoreUtils.collectScrollPosition);
   }
 }
 
 /**
  * Listens for changes to input elements. Whenever the value of an input
  * element changes we will re-collect data for the current frame tree and send
  * a message to the parent process.
  *
@@ -366,17 +364,17 @@ class ScrollPositionListener extends Han
  *       {url: "http://sub.mozilla.org/", id: {input_id: "input value 2"}}
  *     ]
  *   }
  */
 class FormDataListener extends Handler {
   constructor(store) {
     super(store);
 
-    ssu.addDynamicFrameFilteredListener(this.mm, "input", this, true);
+    SessionStoreUtils.addDynamicFrameFilteredListener(this.mm, "input", this, true);
     this.stateChangeNotifier.addObserver(this);
   }
 
   handleEvent() {
     this.messageQueue.push("formdata", () => this.collect());
   }
 
   onPageLoadStarted() {
@@ -406,17 +404,17 @@ class DocShellCapabilitiesListener exten
      * that have just been collected. If nothing changed we won't send a message.
      */
     this._latestCapabilities = "";
 
     this.stateChangeNotifier.addObserver(this);
   }
 
   onPageLoadStarted() {
-    let caps = ssu.collectDocShellCapabilities(this.mm.docShell);
+    let caps = SessionStoreUtils.collectDocShellCapabilities(this.mm.docShell);
 
     // Send new data only when the capability list changes.
     if (caps != this._latestCapabilities) {
       this._latestCapabilities = caps;
       this.messageQueue.push("disallow", () => caps || null);
     }
   }
 }
@@ -461,24 +459,24 @@ class SessionStorageListener extends Han
 
   resetChanges() {
     this._changes = undefined;
   }
 
   resetEventListener() {
     if (!this._listener) {
       this._listener =
-        ssu.addDynamicFrameFilteredListener(this.mm, "MozSessionStorageChanged",
-                                            this, true);
+        SessionStoreUtils.addDynamicFrameFilteredListener(this.mm, "MozSessionStorageChanged",
+                                                          this, true);
     }
   }
 
   removeEventListener() {
-    ssu.removeDynamicFrameFilteredListener(this.mm, "MozSessionStorageChanged",
-                                           this._listener, true);
+    SessionStoreUtils.removeDynamicFrameFilteredListener(this.mm, "MozSessionStorageChanged",
+                                                         this._listener, true);
     this._listener = null;
   }
 
   handleEvent(event) {
     if (!this.mm.docShell) {
       return;
     }
 
--- a/browser/components/sessionstore/SessionStorage.jsm
+++ b/browser/components/sessionstore/SessionStorage.jsm
@@ -3,19 +3,16 @@
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["SessionStorage"];
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
-const ssu = Cc["@mozilla.org/browser/sessionstore/utils;1"]
-              .createInstance(Ci.nsISessionStoreUtils);
-
 // A bound to the size of data to store for DOM Storage.
 const DOM_STORAGE_LIMIT_PREF = "browser.sessionstore.dom_storage_limit";
 
 // Returns the principal for a given |frame| contained in a given |docShell|.
 function getPrincipalForFrame(docShell, frame) {
   let ssm = Services.scriptSecurityManager;
   let uri = frame.document.documentURIObject;
   return ssm.getDocShellCodebasePrincipal(uri, docShell);
@@ -51,17 +48,17 @@ var SessionStorage = Object.freeze({
 /**
  * Calls the given callback |cb|, passing |frame| and each of its descendants.
  */
 function forEachNonDynamicChildFrame(frame, cb) {
   // Call for current frame.
   cb(frame);
 
   // Call the callback recursively for each descendant.
-  ssu.forEachNonDynamicChildFrame(frame, subframe => {
+  SessionStoreUtils.forEachNonDynamicChildFrame(frame, subframe => {
     return forEachNonDynamicChildFrame(subframe, cb);
   });
 }
 
 var SessionStorageInternal = {
   /**
    * Reads all session storage data from the given docShell.
    * @param content
--- a/browser/components/sessionstore/test/browser_frametree.js
+++ b/browser/components/sessionstore/test/browser_frametree.js
@@ -98,27 +98,22 @@ add_task(async function test_frametree_d
   is(await enumerateIndexes(browser), "1", "correct index 1");
 
   // Cleanup.
   BrowserTestUtils.removeTab(tab);
 });
 
 async function countNonDynamicFrames(browser) {
   return ContentTask.spawn(browser, null, async () => {
-    const ssu = Cc["@mozilla.org/browser/sessionstore/utils;1"]
-                  .getService(Ci.nsISessionStoreUtils);
-
     let count = 0;
-    ssu.forEachNonDynamicChildFrame(content, () => count++);
+    SessionStoreUtils.forEachNonDynamicChildFrame(content, () => count++);
     return count;
   });
 }
 
 async function enumerateIndexes(browser) {
   return ContentTask.spawn(browser, null, async () => {
-    const ssu = Cc["@mozilla.org/browser/sessionstore/utils;1"]
-                  .getService(Ci.nsISessionStoreUtils);
-
     let indexes = [];
-    ssu.forEachNonDynamicChildFrame(content, (frame, i) => indexes.push(i));
+    SessionStoreUtils.forEachNonDynamicChildFrame(
+        content, (frame, i) => indexes.push(i));
     return indexes.join(",");
   });
 }
rename from toolkit/components/sessionstore/nsISessionStoreUtils.idl
rename to dom/chrome-webidl/SessionStoreUtils.webidl
--- a/toolkit/components/sessionstore/nsISessionStoreUtils.idl
+++ b/dom/chrome-webidl/SessionStoreUtils.webidl
@@ -1,100 +1,91 @@
 /* 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/. */
 
-#include "nsISupports.idl"
-
-interface mozIDOMWindowProxy;
 interface nsIDocShell;
-webidl EventTarget;
-webidl Document;
-interface mozIDOMWindow;
+interface nsISupports;
 
 /**
- * A callback passed to nsISessionStoreUtils.forEachNonDynamicChildFrame().
+ * A callback passed to SessionStoreUtils.forEachNonDynamicChildFrame().
  */
-[function, scriptable, uuid(8199ebf7-76c0-43d6-bcbe-913dd3de3ebf)]
-interface nsISessionStoreUtilsFrameCallback : nsISupports
-{
-  /**
-   * handleFrame() will be called once for each non-dynamic child frame of the
-   * given parent |frame|. The second argument is the |index| of the frame in
-   * the list of all child frames.
-   */
-  void handleFrame(in mozIDOMWindowProxy frame, in unsigned long index);
-};
+callback SessionStoreUtilsFrameCallback = void (WindowProxy frame, unsigned long index);
 
 /**
  * SessionStore utility functions implemented in C++ for performance reasons.
  */
-[scriptable, uuid(2be448ef-c783-45de-a0df-442bccbb4532)]
-interface nsISessionStoreUtils : nsISupports
-{
+[ChromeOnly, Exposed=Window]
+namespace SessionStoreUtils {
   /**
    * Calls the given |callback| once for each non-dynamic child frame of the
    * given |window|.
    */
-  void forEachNonDynamicChildFrame(in mozIDOMWindowProxy window,
-                                   in nsISessionStoreUtilsFrameCallback callback);
+  [Throws]
+  void forEachNonDynamicChildFrame(WindowProxy window,
+                                   SessionStoreUtilsFrameCallback callback);
 
   /**
    * Takes the given listener, wraps it in a filter that filters out events from
    * dynamic docShells, and adds that filter as a listener for the given event
    * type on the given event target.  The listener that was added is returned
    * (as nsISupports) so that it can later be removed via
    * removeDynamicFrameFilteredListener.
    *
    * This is implemented as a native filter, rather than a JS-based one, for
    * performance reasons.
    */
-  [implicit_jscontext]
-  nsISupports addDynamicFrameFilteredListener(in EventTarget target,
-                                              in AString type,
-                                              in jsval listener,
-                                              in boolean useCapture);
+  [Throws]
+  nsISupports? addDynamicFrameFilteredListener(EventTarget target,
+                                               DOMString type,
+                                               any listener,
+                                               boolean useCapture);
 
   /**
    * Remove the passed-in filtered listener from the given event target, if it's
    * currently a listener for the given event type there.  The 'listener'
    * argument must be something that was returned by
    * addDynamicFrameFilteredListener.
    *
    * This is needed, instead of the normal removeEventListener, because the
    * caller doesn't actually have something that WebIDL considers an
    * EventListener.
    */
-  void removeDynamicFrameFilteredListener(in EventTarget target,
-                                          in AString type,
-                                          in nsISupports listener,
-                                          in boolean useCapture);
+  [Throws]
+  void removeDynamicFrameFilteredListener(EventTarget target,
+                                          DOMString type,
+                                          nsISupports listener,
+                                          boolean useCapture);
 
   /*
    * Save the docShell.allow* properties
    */
-  ACString collectDocShellCapabilities(in nsIDocShell docShell);
+  ByteString collectDocShellCapabilities(nsIDocShell docShell);
 
   /*
    * Restore the docShell.allow* properties
    */
-  void restoreDocShellCapabilities(in nsIDocShell docShell,
-                                   in ACString disallowCapabilities);
+  void restoreDocShellCapabilities(nsIDocShell docShell,
+                                   ByteString disallowCapabilities);
 
   /**
    * Collects scroll position data for any given |frame| in the frame hierarchy.
    *
    * @param document (DOMDocument)
    *
    * @return {scroll: "x,y"} e.g. {scroll: "100,200"}
    *         Returns null when there is no scroll data we want to store for the
    *         given |frame|.
    */
-  ACString collectScrollPosition(in Document document);
+  SSScrollPositionDict collectScrollPosition(Document document);
 
   /**
    * Restores scroll position data for any given |frame| in the frame hierarchy.
    *
    * @param frame (DOMWindow)
-   * @param value (ACString)
+   * @param value (object, see collectScrollPosition())
    */
-  void restoreScrollPosition(in mozIDOMWindow frame, in ACString data);
+  void restoreScrollPosition(Window frame, optional SSScrollPositionDict data);
 };
+
+dictionary SSScrollPositionDict {
+  ByteString scroll;
+};
--- a/dom/chrome-webidl/moz.build
+++ b/dom/chrome-webidl/moz.build
@@ -45,16 +45,17 @@ WEBIDL_FILES = [
     'MessageManager.webidl',
     'MozDocumentObserver.webidl',
     'MozSharedMap.webidl',
     'MozStorageAsyncStatementParams.webidl',
     'MozStorageStatementParams.webidl',
     'MozStorageStatementRow.webidl',
     'PrecompiledScript.webidl',
     'PromiseDebugging.webidl',
+    'SessionStoreUtils.webidl',
     'StructuredCloneHolder.webidl',
     'TelemetryStopwatch.webidl',
     'WebExtensionContentScript.webidl',
     'WebExtensionPolicy.webidl',
     'WindowGlobalActors.webidl',
     'XULFrameElement.webidl',
     'XULMenuElement.webidl',
     'XULScrollElement.webidl',
--- a/mobile/android/chrome/geckoview/GeckoViewContentChild.js
+++ b/mobile/android/chrome/geckoview/GeckoViewContentChild.js
@@ -10,19 +10,16 @@ XPCOMUtils.defineLazyModuleGetters(this,
   FormData: "resource://gre/modules/FormData.jsm",
   FormLikeFactory: "resource://gre/modules/FormLikeFactory.jsm",
   GeckoViewAutoFill: "resource://gre/modules/GeckoViewAutoFill.jsm",
   PrivacyFilter: "resource://gre/modules/sessionstore/PrivacyFilter.jsm",
   Services: "resource://gre/modules/Services.jsm",
   SessionHistory: "resource://gre/modules/sessionstore/SessionHistory.jsm",
 });
 
-const ssu = Cc["@mozilla.org/browser/sessionstore/utils;1"]
-              .getService(Ci.nsISessionStoreUtils);
-
 class GeckoViewContentChild extends GeckoViewChildModule {
   onInit() {
     debug `onInit`;
 
     // We don't load this in the global namespace because
     // a Utils.jsm in a11y will clobber us.
     XPCOMUtils.defineLazyModuleGetters(this, {
       Utils: "resource://gre/modules/sessionstore/Utils.jsm",
@@ -80,17 +77,18 @@ class GeckoViewContentChild extends Geck
     removeEventListener("MozDOMFullscreen:Exit", this);
     removeEventListener("MozDOMFullscreen:Exited", this);
     removeEventListener("MozDOMFullscreen:Request", this);
     removeEventListener("contextmenu", this, { capture: true });
   }
 
   collectSessionState() {
     let history = SessionHistory.collect(docShell);
-    let [formdata, scrolldata] = this.Utils.mapFrameTree(content, FormData.collect, ssu.collectScrollPosition.bind(ssu));
+    let [formdata, scrolldata] = this.Utils.mapFrameTree(
+        content, FormData.collect, SessionStoreUtils.collectScrollPosition);
 
     // Save the current document resolution.
     let zoom = 1;
     let domWindowUtils = content.windowUtils;
     zoom = domWindowUtils.getResolution();
     scrolldata = scrolldata || {};
     scrolldata.zoom = {};
     scrolldata.zoom.resolution = zoom;
@@ -209,17 +207,17 @@ class GeckoViewContentChild extends Geck
             }
           }, {capture: true, mozSystemGroup: true, once: true});
 
           addEventListener("pageshow", _ => {
             const scrolldata = this._savedState.scrolldata;
             if (scrolldata) {
               this.Utils.restoreFrameTreeData(content, scrolldata, (frame, data) => {
                 if (data.scroll) {
-                  ssu.restoreScrollPosition(frame, data.scroll);
+                  SessionStoreUtils.restoreScrollPosition(frame, data);
                 }
               });
             }
             delete this._savedState;
           }, {capture: true, mozSystemGroup: true, once: true});
 
           if (!this.progressFilter) {
             this.progressFilter =
--- a/mobile/android/components/SessionStore.js
+++ b/mobile/android/components/SessionStore.js
@@ -15,19 +15,16 @@ XPCOMUtils.defineLazyModuleGetters(this,
   PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
   SessionHistory: "resource://gre/modules/sessionstore/SessionHistory.jsm",
   SharedPreferences: "resource://gre/modules/SharedPreferences.jsm",
   Utils: "resource://gre/modules/sessionstore/Utils.jsm",
 });
 
 XPCOMUtils.defineLazyModuleGetter(this, "Log", "resource://gre/modules/AndroidLog.jsm", "AndroidLog");
 
-const ssu = Cc["@mozilla.org/browser/sessionstore/utils;1"]
-              .getService(Ci.nsISessionStoreUtils);
-
 function dump(a) {
   Services.console.logStringMessage(a);
 }
 
 let loggingEnabled = false;
 
 function log(a) {
   if (!loggingEnabled) {
@@ -927,17 +924,18 @@ SessionStore.prototype = {
 
     // Neither bother if we're yet to restore the previous scroll position.
     if (aBrowser.__SS_restoreDataOnLoad || aBrowser.__SS_restoreDataOnPageshow) {
       return;
     }
 
     // Save the scroll position itself.
     let content = aBrowser.contentWindow;
-    let [scrolldata] = Utils.mapFrameTree(content, ssu.collectScrollPosition.bind(ssu));
+    let [scrolldata] =
+        Utils.mapFrameTree(content, SessionStoreUtils.collectScrollPosition);
     scrolldata = scrolldata || {};
 
     // Save the current document resolution.
     let zoom = 1;
     zoom = content.windowUtils.getResolution();
     scrolldata.zoom = {};
     scrolldata.zoom.resolution = zoom;
     log("onTabScroll() zoom level: " + zoom);
@@ -1413,17 +1411,17 @@ SessionStore.prototype = {
   /**
   * Takes serialized scroll positions and restores them into the given browser.
   */
   _restoreScrollPosition: function ss_restoreScrollPosition(aScrollData, aBrowser) {
     if (aScrollData) {
       log("_restoreScrollPosition()");
       Utils.restoreFrameTreeData(aBrowser.contentWindow, aScrollData, (frame, data) => {
         if (data.scroll) {
-          ssu.restoreScrollPosition(frame, data.scroll);
+          SessionStoreUtils.restoreScrollPosition(frame, data);
         }
       });
     }
   },
 
   getBrowserState: function ss_getBrowserState() {
     return this._getCurrentState();
   },
--- a/toolkit/components/build/nsToolkitCompsModule.cpp
+++ b/toolkit/components/build/nsToolkitCompsModule.cpp
@@ -32,18 +32,16 @@
 
 #include "nsBrowserStatusFilter.h"
 #include "mozilla/FinalizationWitnessService.h"
 #include "mozilla/NativeOSFileInternals.h"
 #include "mozilla/AddonContentPolicy.h"
 #include "mozilla/AddonManagerStartup.h"
 #include "mozilla/ExtensionPolicyService.h"
 
-#include "nsSessionStoreUtils.h"
-
 #if defined(XP_WIN)
 #include "NativeFileWatcherWin.h"
 #else
 #include "NativeFileWatcherNotSupported.h"
 #endif  // (XP_WIN)
 
 #if !defined(MOZ_WIDGET_ANDROID)
 #define MOZ_HAS_TERMINATOR
@@ -126,18 +124,16 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(NativeOSF
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NativeFileWatcherService, Init)
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(AddonContentPolicy)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AddonManagerStartup,
                                          AddonManagerStartup::GetInstance)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(ExtensionPolicyService,
                                          ExtensionPolicyService::GetInstance)
 
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsSessionStoreUtils)
-
 #if defined(ENABLE_TESTS)
 NS_GENERIC_FACTORY_CONSTRUCTOR(TelemetryGeckoViewTestingImpl)
 #endif
 
 NS_DEFINE_NAMED_CID(NS_TOOLKIT_APPSTARTUP_CID);
 #if defined(MOZ_HAS_PERFSTATS)
 NS_DEFINE_NAMED_CID(NS_TOOLKIT_PERFORMANCESTATSSERVICE_CID);
 #endif  // defined (MOZ_HAS_PERFSTATS)
@@ -164,17 +160,16 @@ NS_DEFINE_NAMED_CID(NS_BROWSERSTATUSFILT
 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
 NS_DEFINE_NAMED_CID(NS_UPDATEPROCESSOR_CID);
 #endif
 NS_DEFINE_NAMED_CID(FINALIZATIONWITNESSSERVICE_CID);
 NS_DEFINE_NAMED_CID(NATIVE_OSFILE_INTERNALS_SERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_ADDONCONTENTPOLICY_CID);
 NS_DEFINE_NAMED_CID(NS_ADDON_MANAGER_STARTUP_CID);
 NS_DEFINE_NAMED_CID(NS_ADDON_POLICY_SERVICE_CID);
-NS_DEFINE_NAMED_CID(NS_SESSIONSTOREUTILS_CID);
 NS_DEFINE_NAMED_CID(NATIVE_FILEWATCHER_SERVICE_CID);
 #if defined(ENABLE_TESTS)
 NS_DEFINE_NAMED_CID(NS_TELEMETRYGECKOVIEWTESTING_CID);
 #endif
 
 static const Module::CIDEntry kToolkitCIDs[] = {
     {&kNS_TOOLKIT_APPSTARTUP_CID, false, nullptr, nsAppStartupConstructor},
 #if defined(MOZ_HAS_TERMINATOR)
@@ -216,18 +211,16 @@ static const Module::CIDEntry kToolkitCI
     {&kNATIVE_OSFILE_INTERNALS_SERVICE_CID, false, nullptr,
      NativeOSFileInternalsServiceConstructor},
     {&kNS_ADDONCONTENTPOLICY_CID, false, nullptr,
      AddonContentPolicyConstructor},
     {&kNS_ADDON_MANAGER_STARTUP_CID, false, nullptr,
      AddonManagerStartupConstructor},
     {&kNS_ADDON_POLICY_SERVICE_CID, false, nullptr,
      ExtensionPolicyServiceConstructor},
-    {&kNS_SESSIONSTOREUTILS_CID, false, nullptr,
-     nsSessionStoreUtilsConstructor},
     {&kNATIVE_FILEWATCHER_SERVICE_CID, false, nullptr,
      NativeFileWatcherServiceConstructor},
 #if defined(ENABLE_TESTS)
     {&kNS_TELEMETRYGECKOVIEWTESTING_CID, false, nullptr,
      TelemetryGeckoViewTestingImplConstructor},
 #endif
     {nullptr}};
 
@@ -263,17 +256,16 @@ static const Module::ContractIDEntry kTo
     {NS_UPDATEPROCESSOR_CONTRACTID, &kNS_UPDATEPROCESSOR_CID},
 #endif
     {FINALIZATIONWITNESSSERVICE_CONTRACTID, &kFINALIZATIONWITNESSSERVICE_CID},
     {NATIVE_OSFILE_INTERNALS_SERVICE_CONTRACTID,
      &kNATIVE_OSFILE_INTERNALS_SERVICE_CID},
     {NS_ADDONCONTENTPOLICY_CONTRACTID, &kNS_ADDONCONTENTPOLICY_CID},
     {NS_ADDONMANAGERSTARTUP_CONTRACTID, &kNS_ADDON_MANAGER_STARTUP_CID},
     {NS_ADDON_POLICY_SERVICE_CONTRACTID, &kNS_ADDON_POLICY_SERVICE_CID},
-    {NS_SESSIONSTOREUTILS_CONTRACTID, &kNS_SESSIONSTOREUTILS_CID},
     {NATIVE_FILEWATCHER_SERVICE_CONTRACTID, &kNATIVE_FILEWATCHER_SERVICE_CID},
 #if defined(ENABLE_TESTS)
     {NS_TELEMETRYGECKOVIEWTESTING_CONTRACTID,
      &kNS_TELEMETRYGECKOVIEWTESTING_CID},
 #endif
     {nullptr}};
 
 static const mozilla::Module::CategoryEntry kToolkitCategories[] = {
rename from toolkit/components/sessionstore/nsSessionStoreUtils.cpp
rename to toolkit/components/sessionstore/SessionStoreUtils.cpp
--- a/toolkit/components/sessionstore/nsSessionStoreUtils.cpp
+++ b/toolkit/components/sessionstore/SessionStoreUtils.cpp
@@ -1,25 +1,19 @@
 /* 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/. */
 
-#include "nsSessionStoreUtils.h"
-
-#include "mozilla/dom/Event.h"
-#include "mozilla/dom/EventListenerBinding.h"
-#include "mozilla/dom/EventTarget.h"
-#include "mozilla/dom/ScriptSettings.h"
-#include "nsPIDOMWindow.h"
 #include "nsIDocShell.h"
 #include "nsGlobalWindowOuter.h"
 #include "nsIScrollableFrame.h"
 #include "nsPresContext.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsPrintfCString.h"
+#include "mozilla/dom/SessionStoreUtils.h"
 
 using namespace mozilla::dom;
 
 namespace {
 
 class DynamicFrameEventFilter final : public nsIDOMEventListener {
  public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -32,17 +26,17 @@ class DynamicFrameEventFilter final : pu
     if (mListener && TargetInNonDynamicDocShell(aEvent)) {
       mListener->HandleEvent(*aEvent);
     }
 
     return NS_OK;
   }
 
  private:
-  ~DynamicFrameEventFilter() {}
+  ~DynamicFrameEventFilter() = default;
 
   bool TargetInNonDynamicDocShell(Event* aEvent) {
     EventTarget* target = aEvent->GetTarget();
     if (!target) {
       return false;
     }
 
     nsPIDOMWindowOuter* outer = target->GetOwnerGlobalForBindingsInternal();
@@ -70,130 +64,131 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DynamicFrameEventFilter)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DynamicFrameEventFilter)
 
 }  // anonymous namespace
 
-NS_IMPL_ISUPPORTS(nsSessionStoreUtils, nsISessionStoreUtils)
+/* static */ void SessionStoreUtils::ForEachNonDynamicChildFrame(
+    const GlobalObject& aGlobal, WindowProxyHolder& aWindow,
+    SessionStoreUtilsFrameCallback& aCallback, ErrorResult& aRv) {
+  if (!aWindow.get()) {
+    aRv.Throw(NS_ERROR_INVALID_ARG);
+    return;
+  }
 
-NS_IMETHODIMP
-nsSessionStoreUtils::ForEachNonDynamicChildFrame(
-    mozIDOMWindowProxy* aWindow, nsISessionStoreUtilsFrameCallback* aCallback) {
-  NS_ENSURE_TRUE(aWindow, NS_ERROR_INVALID_ARG);
-
-  nsCOMPtr<nsPIDOMWindowOuter> outer = nsPIDOMWindowOuter::From(aWindow);
-  NS_ENSURE_TRUE(outer, NS_ERROR_FAILURE);
-
-  nsCOMPtr<nsIDocShell> docShell = outer->GetDocShell();
-  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
+  nsCOMPtr<nsIDocShell> docShell = aWindow.get()->GetDocShell();
+  if (!docShell) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
 
   int32_t length;
-  nsresult rv = docShell->GetChildCount(&length);
-  NS_ENSURE_SUCCESS(rv, rv);
+  aRv = docShell->GetChildCount(&length);
+  if (aRv.Failed()) {
+    return;
+  }
 
   for (int32_t i = 0; i < length; ++i) {
     nsCOMPtr<nsIDocShellTreeItem> item;
     docShell->GetChildAt(i, getter_AddRefs(item));
-    NS_ENSURE_TRUE(item, NS_ERROR_FAILURE);
+    if (!item) {
+      aRv.Throw(NS_ERROR_FAILURE);
+      return;
+    }
 
     nsCOMPtr<nsIDocShell> childDocShell(do_QueryInterface(item));
-    NS_ENSURE_TRUE(childDocShell, NS_ERROR_FAILURE);
+    if (!childDocShell) {
+      aRv.Throw(NS_ERROR_FAILURE);
+      return;
+    }
 
     bool isDynamic = false;
     nsresult rv = childDocShell->GetCreatedDynamically(&isDynamic);
     if (NS_SUCCEEDED(rv) && isDynamic) {
       continue;
     }
 
     int32_t childOffset = childDocShell->GetChildOffset();
-    aCallback->HandleFrame(item->GetWindow(), childOffset);
+    aCallback.Call(WindowProxyHolder(item->GetWindow()->GetBrowsingContext()),
+                   childOffset);
   }
-
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsSessionStoreUtils::AddDynamicFrameFilteredListener(
-    EventTarget* aTarget, const nsAString& aType,
-    JS::Handle<JS::Value> aListener, bool aUseCapture, JSContext* aCx,
-    nsISupports** aResult) {
+/* static */ already_AddRefed<nsISupports>
+SessionStoreUtils::AddDynamicFrameFilteredListener(
+    const GlobalObject& aGlobal, EventTarget& aTarget, const nsAString& aType,
+    JS::Handle<JS::Value> aListener, bool aUseCapture, ErrorResult& aRv) {
   if (NS_WARN_IF(!aListener.isObject())) {
-    return NS_ERROR_INVALID_ARG;
+    aRv.Throw(NS_ERROR_INVALID_ARG);
+    return nullptr;
   }
 
-  NS_ENSURE_TRUE(aTarget, NS_ERROR_NO_INTERFACE);
-
-  JS::Rooted<JSObject*> obj(aCx, &aListener.toObject());
-  JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
+  JSContext* cx = aGlobal.Context();
+  JS::Rooted<JSObject*> obj(cx, &aListener.toObject());
+  JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
   RefPtr<EventListener> listener =
-      new EventListener(aCx, obj, global, GetIncumbentGlobal());
-
+      new EventListener(cx, obj, global, GetIncumbentGlobal());
   nsCOMPtr<nsIDOMEventListener> filter(new DynamicFrameEventFilter(listener));
 
-  nsresult rv = aTarget->AddEventListener(aType, filter, aUseCapture);
-  NS_ENSURE_SUCCESS(rv, rv);
+  aRv = aTarget.AddEventListener(aType, filter, aUseCapture);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
 
-  filter.forget(aResult);
-  return NS_OK;
+  return filter.forget();
 }
 
-NS_IMETHODIMP
-nsSessionStoreUtils::RemoveDynamicFrameFilteredListener(EventTarget* aTarget,
-                                                        const nsAString& aType,
-                                                        nsISupports* aListener,
-                                                        bool aUseCapture) {
-  NS_ENSURE_TRUE(aTarget, NS_ERROR_NO_INTERFACE);
+/* static */ void SessionStoreUtils::RemoveDynamicFrameFilteredListener(
+    const GlobalObject& global, EventTarget& aTarget, const nsAString& aType,
+    nsISupports* aListener, bool aUseCapture, ErrorResult& aRv) {
+  nsCOMPtr<nsIDOMEventListener> listener = do_QueryInterface(aListener);
+  if (!listener) {
+    aRv.Throw(NS_ERROR_NO_INTERFACE);
+    return;
+  }
 
-  nsCOMPtr<nsIDOMEventListener> listener = do_QueryInterface(aListener);
-  NS_ENSURE_TRUE(listener, NS_ERROR_NO_INTERFACE);
-
-  aTarget->RemoveEventListener(aType, listener, aUseCapture);
-  return NS_OK;
+  aTarget.RemoveEventListener(aType, listener, aUseCapture);
 }
 
-NS_IMETHODIMP
-nsSessionStoreUtils::CollectDocShellCapabilities(
-    nsIDocShell* aDocShell, nsACString& aDisallowCapabilities) {
+/* static */ void SessionStoreUtils::CollectDocShellCapabilities(
+    const GlobalObject& aGlobal, nsIDocShell* aDocShell, nsCString& aRetVal) {
   bool allow;
 
-#define TRY_ALLOWPROP(y)                    \
-  PR_BEGIN_MACRO                            \
-  aDocShell->GetAllow##y(&allow);           \
-  if (!allow) {                             \
-    if (!aDisallowCapabilities.IsEmpty()) { \
-      aDisallowCapabilities.Append(',');    \
-    }                                       \
-    aDisallowCapabilities.Append(#y);       \
-  }                                         \
+#define TRY_ALLOWPROP(y)          \
+  PR_BEGIN_MACRO                  \
+  aDocShell->GetAllow##y(&allow); \
+  if (!allow) {                   \
+    if (!aRetVal.IsEmpty()) {     \
+      aRetVal.Append(',');        \
+    }                             \
+    aRetVal.Append(#y);           \
+  }                               \
   PR_END_MACRO
 
   TRY_ALLOWPROP(Plugins);
   // Bug 1328013 : Don't collect "AllowJavascript" property
   // TRY_ALLOWPROP(Javascript);
   TRY_ALLOWPROP(MetaRedirects);
   TRY_ALLOWPROP(Subframes);
   TRY_ALLOWPROP(Images);
   TRY_ALLOWPROP(Media);
   TRY_ALLOWPROP(DNSPrefetch);
   TRY_ALLOWPROP(WindowControl);
   TRY_ALLOWPROP(Auth);
   TRY_ALLOWPROP(ContentRetargeting);
   TRY_ALLOWPROP(ContentRetargetingOnChildren);
-
 #undef TRY_ALLOWPROP
-
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsSessionStoreUtils::RestoreDocShellCapabilities(
-    nsIDocShell* aDocShell, const nsACString& aDisallowCapabilities) {
+/* static */ void SessionStoreUtils::RestoreDocShellCapabilities(
+    const GlobalObject& aGlobal, nsIDocShell* aDocShell,
+    const nsCString& aDisallowCapabilities) {
   aDocShell->SetAllowPlugins(true);
   aDocShell->SetAllowJavascript(true);
   aDocShell->SetAllowMetaRedirects(true);
   aDocShell->SetAllowSubframes(true);
   aDocShell->SetAllowImages(true);
   aDocShell->SetAllowMedia(true);
   aDocShell->SetAllowDNSPrefetch(true);
   aDocShell->SetAllowWindowControl(true);
@@ -225,51 +220,46 @@ nsSessionStoreUtils::RestoreDocShellCapa
       aDocShell->SetAllowContentRetargeting(
           false);  // will also set AllowContentRetargetingOnChildren
       aDocShell->SetAllowContentRetargetingOnChildren(
           allow);  // restore the allowProp to original
     } else if (token.EqualsLiteral("ContentRetargetingOnChildren")) {
       aDocShell->SetAllowContentRetargetingOnChildren(false);
     }
   }
-
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsSessionStoreUtils::CollectScrollPosition(Document* aDocument,
-                                           nsACString& aRet) {
-  aRet.Truncate();
-
-  nsIPresShell* presShell = aDocument->GetShell();
+/* static */ void SessionStoreUtils::CollectScrollPosition(
+    const GlobalObject& aGlobal, Document& aDocument,
+    SSScrollPositionDict& aRetVal) {
+  nsIPresShell* presShell = aDocument.GetShell();
   if (!presShell) {
-    return NS_OK;
+    return;
   }
 
   nsIScrollableFrame* frame = presShell->GetRootScrollFrameAsScrollable();
   if (!frame) {
-    return NS_OK;
+    return;
   }
 
   nsPoint scrollPos = frame->GetScrollPosition();
   int scrollX = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x);
   int scrollY = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y);
 
   if ((scrollX != 0) || (scrollY != 0)) {
-    const nsPrintfCString position("%d,%d", scrollX, scrollY);
-    aRet.Assign(position);
+    aRetVal.mScroll.Construct() = nsPrintfCString("%d,%d", scrollX, scrollY);
+  }
+}
+
+/* static */ void SessionStoreUtils::RestoreScrollPosition(
+    const GlobalObject& aGlobal, nsGlobalWindowInner& aWindow,
+    const SSScrollPositionDict& aData) {
+  if (!aData.mScroll.WasPassed()) {
+    return;
   }
 
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSessionStoreUtils::RestoreScrollPosition(mozIDOMWindow* aWindow,
-                                           const nsACString& aPos) {
-  nsCCharSeparatedTokenizer tokenizer(aPos, ',');
+  nsCCharSeparatedTokenizer tokenizer(aData.mScroll.Value(), ',');
   nsAutoCString token(tokenizer.nextToken());
   int pos_X = atoi(token.get());
   token = tokenizer.nextToken();
   int pos_Y = atoi(token.get());
-  nsGlobalWindowInner::Cast(aWindow)->ScrollTo(pos_X, pos_Y);
-
-  return NS_OK;
+  aWindow.ScrollTo(pos_X, pos_Y);
 }
new file mode 100644
--- /dev/null
+++ b/toolkit/components/sessionstore/SessionStoreUtils.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/. */
+
+#ifndef mozilla_dom_SessionStoreUtils_h
+#define mozilla_dom_SessionStoreUtils_h
+
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/SessionStoreUtilsBinding.h"
+
+class nsIDocument;
+class nsGlobalWindowInner;
+
+namespace mozilla {
+namespace dom {
+
+class GlobalObject;
+struct SSScrollPositionDict;
+
+class SessionStoreUtils {
+ public:
+  static void ForEachNonDynamicChildFrame(
+      const GlobalObject& aGlobal, WindowProxyHolder& aWindow,
+      SessionStoreUtilsFrameCallback& aCallback, ErrorResult& aRv);
+
+  static already_AddRefed<nsISupports> AddDynamicFrameFilteredListener(
+      const GlobalObject& aGlobal, EventTarget& aTarget, const nsAString& aType,
+      JS::Handle<JS::Value> aListener, bool aUseCapture, ErrorResult& aRv);
+
+  static void RemoveDynamicFrameFilteredListener(
+      const GlobalObject& aGlobal, EventTarget& aTarget, const nsAString& aType,
+      nsISupports* aListener, bool aUseCapture, ErrorResult& aRv);
+
+  static void CollectDocShellCapabilities(const GlobalObject& aGlobal,
+                                          nsIDocShell* aDocShell,
+                                          nsCString& aRetVal);
+
+  static void RestoreDocShellCapabilities(
+      const GlobalObject& aGlobal, nsIDocShell* aDocShell,
+      const nsCString& aDisallowCapabilities);
+
+  static void CollectScrollPosition(const GlobalObject& aGlobal,
+                                    Document& aDocument,
+                                    SSScrollPositionDict& aRetVal);
+
+  static void RestoreScrollPosition(const GlobalObject& aGlobal,
+                                    nsGlobalWindowInner& aWindow,
+                                    const SSScrollPositionDict& data);
+};
+
+}  // namespace dom
+}  // namespace mozilla
+
+#endif  // mozilla_dom_SessionStoreUtils_h
--- a/toolkit/components/sessionstore/moz.build
+++ b/toolkit/components/sessionstore/moz.build
@@ -1,24 +1,18 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-XPIDL_SOURCES += [
-    'nsISessionStoreUtils.idl',
-]
-
-XPIDL_MODULE = 'toolkit_sessionstore'
-
-EXPORTS += [
-    'nsSessionStoreUtils.h',
+EXPORTS.mozilla.dom += [
+    'SessionStoreUtils.h',
 ]
 
 UNIFIED_SOURCES += [
-    'nsSessionStoreUtils.cpp',
+    'SessionStoreUtils.cpp',
 ]
 
 FINAL_LIBRARY = 'xul'
 
 with Files('**'):
     BUG_COMPONENT = ('Firefox', 'Session Restore')
deleted file mode 100644
--- a/toolkit/components/sessionstore/nsSessionStoreUtils.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* 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/. */
-
-#ifndef nsSessionStoreUtils_h
-#define nsSessionStoreUtils_h
-
-#include "nsCycleCollectionParticipant.h"
-#include "nsISessionStoreUtils.h"
-#include "nsIDOMEventListener.h"
-#include "nsCOMPtr.h"
-
-#define NS_SESSIONSTOREUTILS_CID                     \
-  {                                                  \
-    0xd713b4be, 0x8285, 0x4cab, {                    \
-      0x9c, 0x0e, 0x0b, 0xbc, 0x38, 0xbf, 0xb9, 0x3c \
-    }                                                \
-  }
-
-#define NS_SESSIONSTOREUTILS_CONTRACTID \
-  "@mozilla.org/browser/sessionstore/utils;1"
-
-class nsSessionStoreUtils final : public nsISessionStoreUtils {
- public:
-  NS_DECL_NSISESSIONSTOREUTILS
-  NS_DECL_ISUPPORTS
-
- private:
-  ~nsSessionStoreUtils() {}
-};
-
-#endif  // nsSessionStoreUtils_h
--- a/toolkit/modules/sessionstore/Utils.jsm
+++ b/toolkit/modules/sessionstore/Utils.jsm
@@ -9,19 +9,16 @@ var EXPORTED_SYMBOLS = ["Utils"];
 ChromeUtils.import("resource://gre/modules/Services.jsm", this);
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", this);
 
 ChromeUtils.defineModuleGetter(this, "NetUtil",
                                "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "serializationHelper",
                                    "@mozilla.org/network/serialization-helper;1",
                                    "nsISerializationHelper");
-XPCOMUtils.defineLazyServiceGetter(this, "ssu",
-                                   "@mozilla.org/browser/sessionstore/utils;1",
-                                   "nsISessionStoreUtils");
 XPCOMUtils.defineLazyServiceGetter(this, "eTLDService",
                                    "@mozilla.org/network/effective-tld-service;1",
                                    "nsIEffectiveTLDService");
 
 XPCOMUtils.defineLazyGetter(this, "SERIALIZED_SYSTEMPRINCIPAL", function() {
   return Utils.serializePrincipal(Services.scriptSecurityManager.getSystemPrincipal());
 });
 
@@ -156,32 +153,21 @@ var Utils = Object.freeze({
    *                                     wish to save for that respective frame.
    * @return {object[]} An array with one entry per dataCollector, containing
    *                    the collected data as a nested data structure according
    *                    to the layout of the frame tree, or null if no data was
    *                    returned by the respective dataCollector.
    */
   mapFrameTree(frame, ...dataCollectors) {
     // Collect data for the current frame.
-    let objs = dataCollectors.map(function(dataCollector) {
-      let obj = dataCollector(frame.document);
-        if (!obj || typeof(obj) == "object") {
-          return obj || {};
-        }
-        // Currently, we return string type when collecting scroll position.
-        // Will switched to webidl and return objects in the future.
-        if (typeof(obj) == "string") {
-          return {scroll: obj};
-        }
-        return obj;
-    });
+    let objs = dataCollectors.map(dataCollector => dataCollector(frame.document) || {});
     let children = dataCollectors.map(() => []);
 
     // Recurse into child frames.
-    ssu.forEachNonDynamicChildFrame(frame, (subframe, index) => {
+    SessionStoreUtils.forEachNonDynamicChildFrame(frame, (subframe, index) => {
       let results = this.mapFrameTree(subframe, ...dataCollectors);
       if (!results) {
         return;
       }
 
       for (let j = results.length - 1; j >= 0; --j) {
         if (!results[j] || !Object.getOwnPropertyNames(results[j]).length) {
           continue;
@@ -212,15 +198,15 @@ var Utils = Object.freeze({
       return;
     }
 
     if (!data.hasOwnProperty("children")) {
       return;
     }
 
     // Recurse into child frames.
-    ssu.forEachNonDynamicChildFrame(frame, (subframe, index) => {
+    SessionStoreUtils.forEachNonDynamicChildFrame(frame, (subframe, index) => {
       if (data.children[index]) {
         this.restoreFrameTreeData(subframe, data.children[index], cb);
       }
     });
   },
 });
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/privileged.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/privileged.js
@@ -462,16 +462,17 @@ module.exports = {
     "RTCTrackEvent": false,
     "RadioNodeList": false,
     "Range": false,
     "Report": false,
     "ReportBody": false,
     "ReportingObserver": false,
     "Request": false,
     "Response": false,
+    "SessionStoreUtils": false,
     "SVGAElement": false,
     "SVGAngle": false,
     "SVGAnimateElement": false,
     "SVGAnimateMotionElement": false,
     "SVGAnimateTransformElement": false,
     "SVGAnimatedAngle": false,
     "SVGAnimatedBoolean": false,
     "SVGAnimatedEnumeration": false,