Backed out changeset dbea03a5c55e (bug 1497146) for bmsvc bustages on SessionStoreUtils.
authorCosmin Sabou <csabou@mozilla.com>
Fri, 04 Jan 2019 19:37:37 +0200
changeset 509663 5088f1dd3230fd48b243e3ae3f56e3a0e4982837
parent 509662 1612587e16bda67fe8814a14779544d8de2325dd
child 509664 4b3fc8b9128035c63821078328c73fbc525d1950
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)
bugs1497146
milestone66.0a1
backs outdbea03a5c55e1deb19b8092c0cc13bf33af8e99c
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset dbea03a5c55e (bug 1497146) for bmsvc bustages on SessionStoreUtils. SessionStoreUtils
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,16 +12,19 @@ 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
@@ -132,18 +135,17 @@ 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.
-    SessionStoreUtils.restoreDocShellCapabilities(this.docShell, tabData.disallow);
-
+    ssu.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.
@@ -291,17 +293,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) {
-        SessionStoreUtils.restoreScrollPosition(frame, data);
+        ssu.restoreScrollPosition(frame, data.scroll);
       }
     });
   },
 
   /**
    * 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,16 +21,18 @@ 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";
 
@@ -144,17 +146,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);
 
-    SessionStoreUtils.addDynamicFrameFilteredListener(this.mm, "load", this, true);
+    ssu.addDynamicFrameFilteredListener(this.mm, "load", this, true);
   }
 
   handleEvent(event) {
     let {content} = this.mm;
 
     // Ignore load events from subframes.
     if (event.target != content.document) {
       return;
@@ -322,34 +324,34 @@ SessionHistoryListener.prototype.QueryIn
  *
  * Example:
  *   {scroll: "100,100", children: [null, null, {scroll: "200,200"}]}
  */
 class ScrollPositionListener extends Handler {
   constructor(store) {
     super(store);
 
-    SessionStoreUtils.addDynamicFrameFilteredListener(this.mm, "scroll", this, false);
+    ssu.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, SessionStoreUtils.collectScrollPosition);
+    return mapFrameTree(this.mm, ssu.collectScrollPosition.bind(ssu));
   }
 }
 
 /**
  * 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.
  *
@@ -364,17 +366,17 @@ class ScrollPositionListener extends Han
  *       {url: "http://sub.mozilla.org/", id: {input_id: "input value 2"}}
  *     ]
  *   }
  */
 class FormDataListener extends Handler {
   constructor(store) {
     super(store);
 
-    SessionStoreUtils.addDynamicFrameFilteredListener(this.mm, "input", this, true);
+    ssu.addDynamicFrameFilteredListener(this.mm, "input", this, true);
     this.stateChangeNotifier.addObserver(this);
   }
 
   handleEvent() {
     this.messageQueue.push("formdata", () => this.collect());
   }
 
   onPageLoadStarted() {
@@ -404,17 +406,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 = SessionStoreUtils.collectDocShellCapabilities(this.mm.docShell);
+    let caps = ssu.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);
     }
   }
 }
@@ -459,24 +461,24 @@ class SessionStorageListener extends Han
 
   resetChanges() {
     this._changes = undefined;
   }
 
   resetEventListener() {
     if (!this._listener) {
       this._listener =
-        SessionStoreUtils.addDynamicFrameFilteredListener(this.mm, "MozSessionStorageChanged",
-                                                          this, true);
+        ssu.addDynamicFrameFilteredListener(this.mm, "MozSessionStorageChanged",
+                                            this, true);
     }
   }
 
   removeEventListener() {
-    SessionStoreUtils.removeDynamicFrameFilteredListener(this.mm, "MozSessionStorageChanged",
-                                                         this._listener, true);
+    ssu.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,16 +3,19 @@
 * 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);
@@ -48,17 +51,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.
-  SessionStoreUtils.forEachNonDynamicChildFrame(frame, subframe => {
+  ssu.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,22 +98,27 @@ 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;
-    SessionStoreUtils.forEachNonDynamicChildFrame(content, () => count++);
+    ssu.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 = [];
-    SessionStoreUtils.forEachNonDynamicChildFrame(
-        content, (frame, i) => indexes.push(i));
+    ssu.forEachNonDynamicChildFrame(content, (frame, i) => indexes.push(i));
     return indexes.join(",");
   });
 }
--- a/dom/chrome-webidl/moz.build
+++ b/dom/chrome-webidl/moz.build
@@ -45,17 +45,16 @@ 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,16 +10,19 @@ 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",
@@ -77,18 +80,17 @@ 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, SessionStoreUtils.collectScrollPosition);
+    let [formdata, scrolldata] = this.Utils.mapFrameTree(content, FormData.collect, ssu.collectScrollPosition.bind(ssu));
 
     // Save the current document resolution.
     let zoom = 1;
     let domWindowUtils = content.windowUtils;
     zoom = domWindowUtils.getResolution();
     scrolldata = scrolldata || {};
     scrolldata.zoom = {};
     scrolldata.zoom.resolution = zoom;
@@ -207,17 +209,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) {
-                  SessionStoreUtils.restoreScrollPosition(frame, data);
+                  ssu.restoreScrollPosition(frame, data.scroll);
                 }
               });
             }
             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,16 +15,19 @@ 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) {
@@ -924,18 +927,17 @@ 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, SessionStoreUtils.collectScrollPosition);
+    let [scrolldata] = Utils.mapFrameTree(content, ssu.collectScrollPosition.bind(ssu));
     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);
@@ -1411,17 +1413,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) {
-          SessionStoreUtils.restoreScrollPosition(frame, data);
+          ssu.restoreScrollPosition(frame, data.scroll);
         }
       });
     }
   },
 
   getBrowserState: function ss_getBrowserState() {
     return this._getCurrentState();
   },
--- a/toolkit/components/build/nsToolkitCompsModule.cpp
+++ b/toolkit/components/build/nsToolkitCompsModule.cpp
@@ -32,16 +32,18 @@
 
 #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
@@ -124,16 +126,18 @@ 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)
@@ -160,16 +164,17 @@ 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)
@@ -211,16 +216,18 @@ 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}};
 
@@ -256,16 +263,17 @@ 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[] = {
deleted file mode 100644
--- a/toolkit/components/sessionstore/SessionStoreUtils.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* -*- 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,18 +1,24 @@
 # -*- 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/.
 
-EXPORTS.mozilla.dom += [
-    'SessionStoreUtils.h',
+XPIDL_SOURCES += [
+    'nsISessionStoreUtils.idl',
+]
+
+XPIDL_MODULE = 'toolkit_sessionstore'
+
+EXPORTS += [
+    'nsSessionStoreUtils.h',
 ]
 
 UNIFIED_SOURCES += [
-    'SessionStoreUtils.cpp',
+    'nsSessionStoreUtils.cpp',
 ]
 
 FINAL_LIBRARY = 'xul'
 
 with Files('**'):
     BUG_COMPONENT = ('Firefox', 'Session Restore')
rename from dom/chrome-webidl/SessionStoreUtils.webidl
rename to toolkit/components/sessionstore/nsISessionStoreUtils.idl
--- a/dom/chrome-webidl/SessionStoreUtils.webidl
+++ b/toolkit/components/sessionstore/nsISessionStoreUtils.idl
@@ -1,91 +1,100 @@
 /* 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;
-interface nsISupports;
+webidl EventTarget;
+webidl Document;
+interface mozIDOMWindow;
 
 /**
- * A callback passed to SessionStoreUtils.forEachNonDynamicChildFrame().
+ * A callback passed to nsISessionStoreUtils.forEachNonDynamicChildFrame().
  */
-callback SessionStoreUtilsFrameCallback = void (WindowProxy frame, unsigned long index);
+[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);
+};
 
 /**
  * SessionStore utility functions implemented in C++ for performance reasons.
  */
-[ChromeOnly, Exposed=Window]
-namespace SessionStoreUtils {
+[scriptable, uuid(2be448ef-c783-45de-a0df-442bccbb4532)]
+interface nsISessionStoreUtils : nsISupports
+{
   /**
    * Calls the given |callback| once for each non-dynamic child frame of the
    * given |window|.
    */
-  [Throws]
-  void forEachNonDynamicChildFrame(WindowProxy window,
-                                   SessionStoreUtilsFrameCallback callback);
+  void forEachNonDynamicChildFrame(in mozIDOMWindowProxy window,
+                                   in nsISessionStoreUtilsFrameCallback 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.
    */
-  [Throws]
-  nsISupports? addDynamicFrameFilteredListener(EventTarget target,
-                                               DOMString type,
-                                               any listener,
-                                               boolean useCapture);
+  [implicit_jscontext]
+  nsISupports addDynamicFrameFilteredListener(in EventTarget target,
+                                              in AString type,
+                                              in jsval listener,
+                                              in 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.
    */
-  [Throws]
-  void removeDynamicFrameFilteredListener(EventTarget target,
-                                          DOMString type,
-                                          nsISupports listener,
-                                          boolean useCapture);
+  void removeDynamicFrameFilteredListener(in EventTarget target,
+                                          in AString type,
+                                          in nsISupports listener,
+                                          in boolean useCapture);
 
   /*
    * Save the docShell.allow* properties
    */
-  ByteString collectDocShellCapabilities(nsIDocShell docShell);
+  ACString collectDocShellCapabilities(in nsIDocShell docShell);
 
   /*
    * Restore the docShell.allow* properties
    */
-  void restoreDocShellCapabilities(nsIDocShell docShell,
-                                   ByteString disallowCapabilities);
+  void restoreDocShellCapabilities(in nsIDocShell docShell,
+                                   in ACString 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|.
    */
-  SSScrollPositionDict collectScrollPosition(Document document);
+  ACString collectScrollPosition(in Document document);
 
   /**
    * Restores scroll position data for any given |frame| in the frame hierarchy.
    *
    * @param frame (DOMWindow)
-   * @param value (object, see collectScrollPosition())
+   * @param value (ACString)
    */
-  void restoreScrollPosition(Window frame, optional SSScrollPositionDict data);
+  void restoreScrollPosition(in mozIDOMWindow frame, in ACString data);
 };
-
-dictionary SSScrollPositionDict {
-  ByteString scroll;
-};
rename from toolkit/components/sessionstore/SessionStoreUtils.cpp
rename to toolkit/components/sessionstore/nsSessionStoreUtils.cpp
--- a/toolkit/components/sessionstore/SessionStoreUtils.cpp
+++ b/toolkit/components/sessionstore/nsSessionStoreUtils.cpp
@@ -1,19 +1,25 @@
 /* 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
@@ -26,17 +32,17 @@ class DynamicFrameEventFilter final : pu
     if (mListener && TargetInNonDynamicDocShell(aEvent)) {
       mListener->HandleEvent(*aEvent);
     }
 
     return NS_OK;
   }
 
  private:
-  ~DynamicFrameEventFilter() = default;
+  ~DynamicFrameEventFilter() {}
 
   bool TargetInNonDynamicDocShell(Event* aEvent) {
     EventTarget* target = aEvent->GetTarget();
     if (!target) {
       return false;
     }
 
     nsPIDOMWindowOuter* outer = target->GetOwnerGlobalForBindingsInternal();
@@ -64,131 +70,130 @@ 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
 
-/* static */ void SessionStoreUtils::ForEachNonDynamicChildFrame(
-    const GlobalObject& aGlobal, WindowProxyHolder& aWindow,
-    SessionStoreUtilsFrameCallback& aCallback, ErrorResult& aRv) {
-  if (!aWindow.get()) {
-    aRv.Throw(NS_ERROR_INVALID_ARG);
-    return;
-  }
+NS_IMPL_ISUPPORTS(nsSessionStoreUtils, nsISessionStoreUtils)
 
-  nsCOMPtr<nsIDocShell> docShell = aWindow.get()->GetDocShell();
-  if (!docShell) {
-    aRv.Throw(NS_ERROR_FAILURE);
-    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);
 
   int32_t length;
-  aRv = docShell->GetChildCount(&length);
-  if (aRv.Failed()) {
-    return;
-  }
+  nsresult rv = docShell->GetChildCount(&length);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   for (int32_t i = 0; i < length; ++i) {
     nsCOMPtr<nsIDocShellTreeItem> item;
     docShell->GetChildAt(i, getter_AddRefs(item));
-    if (!item) {
-      aRv.Throw(NS_ERROR_FAILURE);
-      return;
-    }
+    NS_ENSURE_TRUE(item, NS_ERROR_FAILURE);
 
     nsCOMPtr<nsIDocShell> childDocShell(do_QueryInterface(item));
-    if (!childDocShell) {
-      aRv.Throw(NS_ERROR_FAILURE);
-      return;
-    }
+    NS_ENSURE_TRUE(childDocShell, NS_ERROR_FAILURE);
 
     bool isDynamic = false;
     nsresult rv = childDocShell->GetCreatedDynamically(&isDynamic);
     if (NS_SUCCEEDED(rv) && isDynamic) {
       continue;
     }
 
     int32_t childOffset = childDocShell->GetChildOffset();
-    aCallback.Call(WindowProxyHolder(item->GetWindow()->GetBrowsingContext()),
-                   childOffset);
+    aCallback->HandleFrame(item->GetWindow(), childOffset);
   }
+
+  return NS_OK;
 }
 
-/* static */ already_AddRefed<nsISupports>
-SessionStoreUtils::AddDynamicFrameFilteredListener(
-    const GlobalObject& aGlobal, EventTarget& aTarget, const nsAString& aType,
-    JS::Handle<JS::Value> aListener, bool aUseCapture, ErrorResult& aRv) {
+NS_IMETHODIMP
+nsSessionStoreUtils::AddDynamicFrameFilteredListener(
+    EventTarget* aTarget, const nsAString& aType,
+    JS::Handle<JS::Value> aListener, bool aUseCapture, JSContext* aCx,
+    nsISupports** aResult) {
   if (NS_WARN_IF(!aListener.isObject())) {
-    aRv.Throw(NS_ERROR_INVALID_ARG);
-    return nullptr;
-  }
-
-  JSContext* cx = aGlobal.Context();
-  JS::Rooted<JSObject*> obj(cx, &aListener.toObject());
-  JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
-  RefPtr<EventListener> listener =
-      new EventListener(cx, obj, global, GetIncumbentGlobal());
-  nsCOMPtr<nsIDOMEventListener> filter(new DynamicFrameEventFilter(listener));
-
-  aRv = aTarget.AddEventListener(aType, filter, aUseCapture);
-  if (aRv.Failed()) {
-    return nullptr;
+    return NS_ERROR_INVALID_ARG;
   }
 
-  return filter.forget();
+  NS_ENSURE_TRUE(aTarget, NS_ERROR_NO_INTERFACE);
+
+  JS::Rooted<JSObject*> obj(aCx, &aListener.toObject());
+  JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
+  RefPtr<EventListener> listener =
+      new EventListener(aCx, obj, global, GetIncumbentGlobal());
+
+  nsCOMPtr<nsIDOMEventListener> filter(new DynamicFrameEventFilter(listener));
+
+  nsresult rv = aTarget->AddEventListener(aType, filter, aUseCapture);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  filter.forget(aResult);
+  return NS_OK;
 }
 
-/* static */ void SessionStoreUtils::RemoveDynamicFrameFilteredListener(
-    const GlobalObject& global, EventTarget& aTarget, const nsAString& aType,
-    nsISupports* aListener, bool aUseCapture, ErrorResult& aRv) {
+NS_IMETHODIMP
+nsSessionStoreUtils::RemoveDynamicFrameFilteredListener(EventTarget* aTarget,
+                                                        const nsAString& aType,
+                                                        nsISupports* aListener,
+                                                        bool aUseCapture) {
+  NS_ENSURE_TRUE(aTarget, NS_ERROR_NO_INTERFACE);
+
   nsCOMPtr<nsIDOMEventListener> listener = do_QueryInterface(aListener);
-  if (!listener) {
-    aRv.Throw(NS_ERROR_NO_INTERFACE);
-    return;
-  }
+  NS_ENSURE_TRUE(listener, NS_ERROR_NO_INTERFACE);
 
-  aTarget.RemoveEventListener(aType, listener, aUseCapture);
+  aTarget->RemoveEventListener(aType, listener, aUseCapture);
+  return NS_OK;
 }
 
-/* static */ void SessionStoreUtils::CollectDocShellCapabilities(
-    const GlobalObject& aGlobal, nsIDocShell* aDocShell, nsCString& aRetVal) {
+NS_IMETHODIMP
+nsSessionStoreUtils::CollectDocShellCapabilities(
+    nsIDocShell* aDocShell, nsACString& aDisallowCapabilities) {
   bool allow;
 
-#define TRY_ALLOWPROP(y)          \
-  PR_BEGIN_MACRO                  \
-  aDocShell->GetAllow##y(&allow); \
-  if (!allow) {                   \
-    if (!aRetVal.IsEmpty()) {     \
-      aRetVal.Append(',');        \
-    }                             \
-    aRetVal.Append(#y);           \
-  }                               \
+#define TRY_ALLOWPROP(y)                    \
+  PR_BEGIN_MACRO                            \
+  aDocShell->GetAllow##y(&allow);           \
+  if (!allow) {                             \
+    if (!aDisallowCapabilities.IsEmpty()) { \
+      aDisallowCapabilities.Append(',');    \
+    }                                       \
+    aDisallowCapabilities.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;
 }
 
-/* static */ void SessionStoreUtils::RestoreDocShellCapabilities(
-    const GlobalObject& aGlobal, nsIDocShell* aDocShell,
-    const nsCString& aDisallowCapabilities) {
+NS_IMETHODIMP
+nsSessionStoreUtils::RestoreDocShellCapabilities(
+    nsIDocShell* aDocShell, const nsACString& 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);
@@ -220,46 +225,51 @@ SessionStoreUtils::AddDynamicFrameFilter
       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;
 }
 
-/* static */ void SessionStoreUtils::CollectScrollPosition(
-    const GlobalObject& aGlobal, Document& aDocument,
-    SSScrollPositionDict& aRetVal) {
-  nsIPresShell* presShell = aDocument.GetShell();
+NS_IMETHODIMP
+nsSessionStoreUtils::CollectScrollPosition(Document* aDocument,
+                                           nsACString& aRet) {
+  aRet.Truncate();
+
+  nsIPresShell* presShell = aDocument->GetShell();
   if (!presShell) {
-    return;
+    return NS_OK;
   }
 
   nsIScrollableFrame* frame = presShell->GetRootScrollFrameAsScrollable();
   if (!frame) {
-    return;
+    return NS_OK;
   }
 
   nsPoint scrollPos = frame->GetScrollPosition();
   int scrollX = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x);
   int scrollY = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y);
 
   if ((scrollX != 0) || (scrollY != 0)) {
-    aRetVal.mScroll.Construct() = nsPrintfCString("%d,%d", scrollX, scrollY);
+    const nsPrintfCString position("%d,%d", scrollX, scrollY);
+    aRet.Assign(position);
   }
+
+  return NS_OK;
 }
 
-/* static */ void SessionStoreUtils::RestoreScrollPosition(
-    const GlobalObject& aGlobal, nsGlobalWindowInner& aWindow,
-    const SSScrollPositionDict& aData) {
-  if (!aData.mScroll.WasPassed()) {
-    return;
-  }
-
-  nsCCharSeparatedTokenizer tokenizer(aData.mScroll.Value(), ',');
+NS_IMETHODIMP
+nsSessionStoreUtils::RestoreScrollPosition(mozIDOMWindow* aWindow,
+                                           const nsACString& aPos) {
+  nsCCharSeparatedTokenizer tokenizer(aPos, ',');
   nsAutoCString token(tokenizer.nextToken());
   int pos_X = atoi(token.get());
   token = tokenizer.nextToken();
   int pos_Y = atoi(token.get());
-  aWindow.ScrollTo(pos_X, pos_Y);
+  nsGlobalWindowInner::Cast(aWindow)->ScrollTo(pos_X, pos_Y);
+
+  return NS_OK;
 }
new file mode 100644
--- /dev/null
+++ b/toolkit/components/sessionstore/nsSessionStoreUtils.h
@@ -0,0 +1,32 @@
+/* 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,16 +9,19 @@ 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());
 });
 
@@ -153,21 +156,32 @@ 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(dataCollector => dataCollector(frame.document) || {});
+    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 children = dataCollectors.map(() => []);
 
     // Recurse into child frames.
-    SessionStoreUtils.forEachNonDynamicChildFrame(frame, (subframe, index) => {
+    ssu.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;
@@ -198,15 +212,15 @@ var Utils = Object.freeze({
       return;
     }
 
     if (!data.hasOwnProperty("children")) {
       return;
     }
 
     // Recurse into child frames.
-    SessionStoreUtils.forEachNonDynamicChildFrame(frame, (subframe, index) => {
+    ssu.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,17 +462,16 @@ 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,