Merge mozilla-central to inbound. a=merge CLOSED TREE
authorshindli <shindli@mozilla.com>
Tue, 05 Mar 2019 23:48:26 +0200
changeset 520395 e02a16f52eafdabcf99e3cde269a49e9adeb9860
parent 520394 3682b31958e1b0c3604eddea18c712bb29ed35dc (current diff)
parent 520279 996a48b306521112d483b3bd8bede1e4fa23d3fa (diff)
child 520396 f19a83763e503190da29a68f2a644412142f3c1d
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone67.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
Merge mozilla-central to inbound. a=merge CLOSED TREE
devtools/client/shared/test/browser_dbg_event-listeners-01.js
devtools/client/shared/test/browser_dbg_event-listeners-02.js
devtools/client/shared/test/browser_dbg_event-listeners-03.js
dom/base/test/test_bug715041.xul
dom/base/test/test_bug715041_removal.xul
dom/tests/mochitest/general/test_idleapi_permissions.html
editor/reftests/xul/emptymultiline-1.xul
editor/reftests/xul/emptymultiline-2.xul
editor/reftests/xul/emptymultiline-ref.xul
js/src/jit/CodeGenerator.cpp
layout/base/tests/chrome/test_bug504311.xul
layout/xul/reftest/textbox-multiline-noresize.xul
layout/xul/reftest/textbox-multiline-resize.xul
--- a/accessible/tests/mochitest/events/test_focus_general.xul
+++ b/accessible/tests/mochitest/events/test_focus_general.xul
@@ -27,18 +27,16 @@
     var gQueue = null;
     function doTests()
     {
       // Test focus events.
       gQueue = new eventQueue();
 
       gQueue.push(new synthFocus("textbox",
                                  new focusChecker(getNode("textbox").inputField)));
-      gQueue.push(new synthFocus("textbox_multiline",
-                                 new focusChecker(getNode("textbox_multiline").inputField)));
       gQueue.push(new synthFocusOnFrame("editabledoc"));
       gQueue.push(new synthFocus("radioclothes",
                                  new focusChecker("radiosweater")));
       gQueue.push(new synthDownKey("radiosweater",
                                    new focusChecker("radiojacket")));
       gQueue.push(new synthFocus("checkbox"));
       gQueue.push(new synthFocus("button"));
       gQueue.push(new synthFocus("checkbutton"));
@@ -83,17 +81,16 @@
       <p id="display"></p>
       <div id="content" style="display: none"></div>
       <pre id="test">
       </pre>
     </body>
 
     <vbox flex="1">
       <textbox id="textbox" value="hello"/>
-      <textbox id="textbox_multiline" multiline="true" value="hello"/>
       <iframe id="editabledoc" src="focus.html"/>
       <radiogroup id="radioclothes">
         <radio id="radiosweater" label="radiosweater"/>
         <radio id="radiocap" label="radiocap" disabled="true"/>
         <radio id="radiojacket" label="radiojacket"/>
       </radiogroup>
       <checkbox id="checkbox" label="checkbox"/>
       <button id="button" label="button"/>
--- a/accessible/tests/mochitest/states/test_textbox.xul
+++ b/accessible/tests/mochitest/states/test_textbox.xul
@@ -39,25 +39,16 @@
       testStates(getInput("password"),
                  STATE_FOCUSABLE | STATE_PROTECTED,
                  EXT_STATE_EDITABLE,
                  STATE_UNAVAILABLE,
                  EXT_STATE_SUPPORTS_AUTOCOMPLETION,
                  "password textbox");
 
       //////////////////////////////////////////////////////////////////////////
-      // Textarea
-      testStates(getInput("textarea"),
-                 STATE_FOCUSABLE,
-                 EXT_STATE_EDITABLE | EXT_STATE_MULTI_LINE,
-                 STATE_PROTECTED | STATE_UNAVAILABLE,
-                 EXT_STATE_SUPPORTS_AUTOCOMPLETION,
-                 "multiline textbox");
-
-      //////////////////////////////////////////////////////////////////////////
       // Readonly textbox
       testStates(getInput("readonly_textbox"),
                  STATE_FOCUSABLE | STATE_READONLY,
                  EXT_STATE_EDITABLE,
                  STATE_PROTECTED | STATE_UNAVAILABLE,
                  EXT_STATE_SUPPORTS_AUTOCOMPLETION,
                  "readonly textbox");
 
@@ -66,34 +57,16 @@
       testStates(getInput("disabled_textbox"),
                  STATE_UNAVAILABLE,
                  EXT_STATE_EDITABLE,
                  STATE_FOCUSABLE | STATE_PROTECTED,
                  EXT_STATE_SUPPORTS_AUTOCOMPLETION,
                  "readonly textbox");
 
       //////////////////////////////////////////////////////////////////////////
-      // Readonly textarea
-      testStates(getInput("readonly_textarea"),
-                 STATE_FOCUSABLE | STATE_READONLY,
-                 EXT_STATE_EDITABLE | EXT_STATE_MULTI_LINE,
-                 STATE_PROTECTED | STATE_UNAVAILABLE,
-                 EXT_STATE_SUPPORTS_AUTOCOMPLETION,
-                 "readonly multiline textbox");
-
-      //////////////////////////////////////////////////////////////////////////
-      // Disabled textarea
-      testStates(getInput("disabled_textarea"),
-                 STATE_UNAVAILABLE,
-                 EXT_STATE_EDITABLE| EXT_STATE_MULTI_LINE,
-                 STATE_PROTECTED | STATE_FOCUSABLE,
-                 EXT_STATE_SUPPORTS_AUTOCOMPLETION,
-                 "readonly multiline textbox");
-
-      //////////////////////////////////////////////////////////////////////////
       // Search textbox without search button, searches as you type and filters
       // a separate control.
       testStates(getInput("searchbox"),
                  STATE_FOCUSABLE,
                  EXT_STATE_EDITABLE | EXT_STATE_SUPPORTS_AUTOCOMPLETION,
                  STATE_PROTECTED | STATE_UNAVAILABLE,
                  0,
                  "searchbox");
@@ -131,23 +104,18 @@
     <div id="content" style="display: none"></div>
     <pre id="test">
     </pre>
   </body>
 
   <vbox flex="1">
     <textbox id="textbox"/>
     <textbox id="password" type="password"/>
-    <textbox id="textarea" multiline="true" cols="80" rows="5"/>
 
     <textbox id="readonly_textbox" readonly="true"/>
     <textbox id="disabled_textbox" disabled="true"/>
-    <textbox id="readonly_textarea" multiline="true" readonly="true"
-             cols="80" rows="5"/>
-    <textbox id="disabled_textarea" multiline="true" disabled="true"
-             cols="80" rows="5"/>
 
     <textbox id="searchbox" flex="1" type="search" results="historyTree"/>
     <textbox id="searchfield" placeholder="Search all add-ons"
              type="search" searchbutton="true"/>
   </vbox>
   </hbox>
 </window>
--- a/accessible/tests/mochitest/text/test_general.xul
+++ b/accessible/tests/mochitest/text/test_general.xul
@@ -70,11 +70,11 @@
     <div id="content" style="display: none">
     </div>
     <pre id="test">
     </pre>
   </body>
   <label id="label1" value="Hello"/>
   <label id="label2">Hello</label>
 
-  <textbox id="tbox1" value="test" multiline="true"/>
+  <textbox id="tbox1" value="test"/>
   </vbox>
 </window>
--- a/accessible/tests/mochitest/tree/test_txtctrl.xul
+++ b/accessible/tests/mochitest/tree/test_txtctrl.xul
@@ -33,19 +33,16 @@
         { SECTION: [
           { ENTRY: [ { TEXT_LEAF: [] } ] },
           { MENUPOPUP: [] }
         ] };
 
       // default textbox
       testAccessibleTree("txc", accTree);
 
-      // multiline
-      testAccessibleTree("txc_multiline", accTree);
-
       //////////////////////////////////////////////////////////////////////////
       // search textbox
       accTree =
         { SECTION: [
           { ENTRY: [ { TEXT_LEAF: [] } ] },
           { MENUPOPUP: [] }
         ] };
       testAccessibleTree("txc_search", accTree);
@@ -159,14 +156,13 @@
     </body>
 
     <vbox flex="1">
       <textbox id="txc" value="hello"/>
       <textbox id="txc_search" type="search" value="hello"/>
       <textbox id="txc_search_searchbutton" searchbutton="true" type="search" value="hello"/>
       <textbox id="txc_number" type="number" value="44"/>
       <textbox id="txc_password" type="password" value="hello"/>
-      <textbox id="txc_multiline" multiline="true" value="hello"/>
       <textbox id="txc_autocomplete" type="autocomplete" value="hello"/>
     </vbox>
   </hbox>
 
 </window>
--- a/browser/base/content/test/general/browser_double_close_tab.js
+++ b/browser/base/content/test/general/browser_double_close_tab.js
@@ -1,19 +1,18 @@
 /* eslint-disable mozilla/no-arbitrary-setTimeout */
 "use strict";
 const TEST_PAGE = "http://mochi.test:8888/browser/browser/base/content/test/general/file_double_close_tab.html";
 var testTab;
 
-SpecialPowers.pushPrefEnv({"set": [["dom.require_user_interaction_for_beforeunload", false]]});
-
 function waitForDialog(callback) {
   function onTabModalDialogLoaded(node) {
     Services.obs.removeObserver(onTabModalDialogLoaded, "tabmodal-dialog-loaded");
-    callback(node);
+    // Allow dialog's onLoad call to run to completion
+    Promise.resolve().then(() => callback(node));
   }
 
   // Listen for the dialog being created
   Services.obs.addObserver(onTabModalDialogLoaded, "tabmodal-dialog-loaded");
 }
 
 function waitForDialogDestroyed(node, callback) {
   // Now listen for the dialog going away again...
@@ -33,18 +32,19 @@ function waitForDialogDestroyed(node, ca
     clearTimeout(failureTimeout);
     observer.disconnect();
     observer = null;
     callback();
   }
 }
 
 add_task(async function() {
-  testTab = gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
-  await promiseTabLoadEvent(testTab, TEST_PAGE);
+  await SpecialPowers.pushPrefEnv({"set": [["dom.require_user_interaction_for_beforeunload", false]]});
+
+  testTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE);
   // XXXgijs the reason this has nesting and callbacks rather than promises is
   // that DOM promises resolve on the next tick. So they're scheduled
   // in an event queue. So when we spin a new event queue for a modal dialog...
   // everything gets messed up and the promise's .then callbacks never get
   // called, despite resolve() being called just fine.
   await new Promise(resolveOuter => {
     waitForDialog(dialogNode => {
       waitForDialogDestroyed(dialogNode, () => {
@@ -65,17 +65,19 @@ add_task(async function() {
     });
     // Click once:
     document.getAnonymousElementByAttribute(testTab, "anonid", "close-button").click();
   });
   await TestUtils.waitForCondition(() => !testTab.parentNode);
   ok(!testTab.parentNode, "Tab should be closed completely");
 });
 
-registerCleanupFunction(function() {
+registerCleanupFunction(async function() {
   if (testTab.parentNode) {
     // Remove the handler, or closing this tab will prove tricky:
     try {
-      testTab.linkedBrowser.contentWindow.onbeforeunload = null;
+      await ContentTask.spawn(testTab.linkedBrowser, null, function() {
+        content.window.onbeforeunload = null;
+      });
     } catch (ex) {}
     gBrowser.removeTab(testTab);
   }
 });
--- a/browser/components/controlcenter/content/panel.inc.xul
+++ b/browser/components/controlcenter/content/panel.inc.xul
@@ -325,17 +325,17 @@
         </vbox>
         <vbox id="identity-popup-breakageReportView-body" class="panel-view-body-unscrollable">
           <vbox class="identity-popup-breakageReportView-collection-section">
             <label>&contentBlocking.breakageReportView.collection.url.label;</label>
             <textbox readonly="true" id="identity-popup-breakageReportView-collection-url"/>
           </vbox>
           <vbox class="identity-popup-breakageReportView-collection-section">
             <label>&contentBlocking.breakageReportView.collection.comments.label;</label>
-            <textbox multiline="true" id="identity-popup-breakageReportView-collection-comments"/>
+            <html:textarea id="identity-popup-breakageReportView-collection-comments"/>
           </vbox>
         </vbox>
         <vbox id="identity-popup-breakageReportView-footer"
               class="panel-footer">
           <button id="identity-popup-breakageReportView-cancel"
                   label="&contentBlocking.breakageReportView.cancel.label;"
                   oncommand="ContentBlocking.backToMainView();"/>
           <button id="identity-popup-breakageReportView-submit"
--- a/browser/components/extensions/test/browser/browser_ext_incognito_popup.js
+++ b/browser/components/extensions/test/browser/browser_ext_incognito_popup.js
@@ -1,14 +1,15 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 add_task(async function testIncognitoPopup() {
   let extension = ExtensionTestUtils.loadExtension({
+    incognitoOverride: "spanning",
     manifest: {
       "permissions": ["tabs"],
       "browser_action": {
         "default_popup": "popup.html",
       },
       "page_action": {
         "default_popup": "popup.html",
       },
--- a/browser/components/extensions/test/browser/browser_ext_incognito_views.js
+++ b/browser/components/extensions/test/browser/browser_ext_incognito_views.js
@@ -2,16 +2,17 @@
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 add_task(async function testIncognitoViews() {
   // Make sure the mouse isn't hovering over the browserAction widget.
   EventUtils.synthesizeMouseAtCenter(gURLBar.textbox, {type: "mouseover"}, window);
 
   let extension = ExtensionTestUtils.loadExtension({
+    incognitoOverride: "spanning",
     manifest: {
       "permissions": ["tabs"],
       "browser_action": {
         "default_popup": "popup.html",
       },
     },
 
     background: async function() {
--- a/browser/components/extensions/test/browser/browser_ext_tabs_cookieStoreId.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_cookieStoreId.js
@@ -26,16 +26,17 @@ add_task(async function() {
     {privateTab: true, cookieStoreId: null, success: true, expectedCookieStoreId: "firefox-private"},
     {privateTab: true, cookieStoreId: "firefox-private", success: true, expectedCookieStoreId: "firefox-private"},
     {privateTab: true, cookieStoreId: "firefox-default", failure: "privateToDefault"},
     {privateTab: true, cookieStoreId: "firefox-container-1", failure: "privateToDefault"},
     {privateTab: true, cookieStoreId: "wow", failure: "illegal"},
   ];
 
   let extension = ExtensionTestUtils.loadExtension({
+    incognitoOverride: "spanning",
     manifest: {
       "permissions": ["tabs", "cookies"],
     },
 
     background: function() {
       function testTab(data, tab) {
         browser.test.assertTrue(data.success, "we want a success");
         browser.test.assertTrue(!!tab, "we have a tab");
--- a/browser/components/extensions/test/browser/browser_ext_tabs_cookieStoreId_private.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_cookieStoreId_private.js
@@ -7,16 +7,17 @@ add_task(async function perma_private_br
   await SpecialPowers.pushPrefEnv({"set": [
     ["privacy.userContext.enabled", true],
   ]});
 
   Assert.equal(Services.prefs.getBoolPref("browser.privatebrowsing.autostart"),
                true, "Permanent private browsing is enabled");
 
   let extension = ExtensionTestUtils.loadExtension({
+    incognitoOverride: "spanning",
     manifest: {
       "permissions": ["tabs", "cookies"],
     },
     async background() {
       let win = await browser.windows.create({});
       browser.test.assertTrue(win.incognito, "New window should be private when perma-PBM is enabled.");
       await browser.test.assertRejects(
         browser.tabs.create({cookieStoreId: "firefox-container-1", windowId: win.id}),
--- a/browser/components/extensions/test/browser/browser_ext_tabs_create_url.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_create_url.js
@@ -78,16 +78,17 @@ add_task(async function test_urlbar_focu
   extension.sendMessage("remove", tab2.id);
   await extension.awaitMessage("result");
 
   await extension.unload();
 });
 
 add_task(async function default_url() {
   const extension = ExtensionTestUtils.loadExtension({
+    incognitoOverride: "spanning",
     manifest: {
       permissions: ["tabs"],
     },
     background() {
       function promiseNonBlankTab() {
         return new Promise(resolve => {
           browser.tabs.onUpdated.addListener(function listener(tabId, changeInfo, tab) {
             if (changeInfo.status === "complete" && tab.url !== "about:blank") {
--- a/browser/components/extensions/test/browser/browser_ext_windows_create_cookieStoreId.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_create_cookieStoreId.js
@@ -23,16 +23,17 @@ add_task(async function no_cookies_permi
 });
 
 add_task(async function invalid_cookieStoreId() {
   await SpecialPowers.pushPrefEnv({"set": [
     ["privacy.userContext.enabled", true],
   ]});
 
   let extension = ExtensionTestUtils.loadExtension({
+    incognitoOverride: "spanning",
     manifest: {
       permissions: ["cookies"],
     },
     async background() {
       await browser.test.assertRejects(
         browser.windows.create({cookieStoreId: "not-firefox-container-1"}),
         /Illegal cookieStoreId/,
         "cookieStoreId must be valid");
@@ -59,16 +60,17 @@ add_task(async function invalid_cookieSt
   await extension.awaitMessage("done");
   await extension.unload();
 });
 
 add_task(async function perma_private_browsing_mode() {
   await SpecialPowers.pushPrefEnv({set: [["browser.privatebrowsing.autostart", true]]});
 
   let extension = ExtensionTestUtils.loadExtension({
+    incognitoOverride: "spanning",
     manifest: {
       "permissions": ["tabs", "cookies"],
     },
     async background() {
       await browser.test.assertRejects(
         browser.windows.create({cookieStoreId: "firefox-container-1"}),
         /Contextual identities are unavailable in permanent private browsing mode/,
         "cookieStoreId cannot be a container tab ID in perma-private browsing mode");
@@ -235,16 +237,17 @@ add_task(async function valid_cookieStor
 });
 
 add_task(async function cookieStoreId_and_tabId() {
   await SpecialPowers.pushPrefEnv({"set": [
     ["privacy.userContext.enabled", true],
   ]});
 
   let extension = ExtensionTestUtils.loadExtension({
+    incognitoOverride: "spanning",
     manifest: {
       permissions: ["cookies"],
     },
     async background() {
       for (let cookieStoreId of ["firefox-default", "firefox-container-1"]) {
         let {id: normalTabId} = await browser.tabs.create({cookieStoreId});
 
         await browser.test.assertRejects(
--- a/browser/components/extensions/test/browser/browser_ext_windows_create_tabId.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_create_tabId.js
@@ -134,16 +134,17 @@ add_task(async function testWindowCreate
       browser.test.notifyPass("window-create");
     } catch (e) {
       browser.test.fail(`${e} :: ${e.stack}`);
       browser.test.notifyFail("window-create");
     }
   }
 
   let extension = ExtensionTestUtils.loadExtension({
+    incognitoOverride: "spanning",
     manifest: {
       "permissions": ["tabs"],
     },
 
     background,
   });
 
   await extension.startup();
--- a/browser/components/preferences/connection.xul
+++ b/browser/components/preferences/connection.xul
@@ -135,17 +135,17 @@
                 data-l10n-id="connection-proxy-reload"
                 oncommand="gConnectionsDialog.reloadPAC();"
                 preference="pref.advanced.proxies.disable_button.reload"/>
       </hbox>
     </radiogroup>
   </groupbox>
   <separator class="thin"/>
   <label data-l10n-id="connection-proxy-noproxy" control="networkProxyNone"/>
-  <textbox id="networkProxyNone" preference="network.proxy.no_proxies_on" multiline="true" rows="2"/>
+  <html:textarea id="networkProxyNone" preference="network.proxy.no_proxies_on" rows="2"/>
   <label control="networkProxyNone" data-l10n-id="connection-proxy-noproxy-desc" />
   <checkbox id="autologinProxy"
             data-l10n-id="connection-proxy-autologin"
             preference="signon.autologin.proxy" />
   <checkbox id="networkProxySOCKSRemoteDNS"
             preference="network.proxy.socks_remote_dns"
             data-l10n-id="connection-proxy-socks-remote-dns" />
   <checkbox id="networkDnsOverHttps"
--- a/browser/components/preferences/in-content/tests/browser_connection.js
+++ b/browser/components/preferences/in-content/tests/browser_connection.js
@@ -47,18 +47,18 @@ function test() {
 // run a bunch of tests on the window containing connection.xul
 function runConnectionTests(win) {
   let doc = win.document;
   let networkProxyNone = doc.getElementById("networkProxyNone");
   let networkProxyNonePref = win.Preferences.get("network.proxy.no_proxies_on");
   let networkProxyTypePref = win.Preferences.get("network.proxy.type");
 
   // make sure the networkProxyNone textbox is formatted properly
-  is(networkProxyNone.getAttribute("multiline"), "true",
-     "networkProxyNone textbox is multiline");
+  is(networkProxyNone.localName, "textarea",
+     "networkProxyNone is a textarea");
   is(networkProxyNone.getAttribute("rows"), "2",
      "networkProxyNone textbox has two rows");
 
   // make sure manual proxy controls are disabled when the window is opened
   let networkProxyHTTP = doc.getElementById("networkProxyHTTP");
   is(networkProxyHTTP.disabled, true, "networkProxyHTTP textbox is disabled");
 
   // check if sanitizing the given input for the no_proxies_on pref results in
--- a/browser/components/preferences/in-content/tests/browser_extension_controlled.js
+++ b/browser/components/preferences/in-content/tests/browser_extension_controlled.js
@@ -752,17 +752,17 @@ add_task(async function testExtensionCon
         }, "The user is notified that an extension is controlling proxy settings.");
       }
       function getProxyControls() {
         let controlGroup = doc.getElementById("networkProxyType");
         let manualControlContainer = controlGroup.querySelector("grid");
         return {
           manualControls: [
             ...manualControlContainer.querySelectorAll("label[data-l10n-id]:not([control=networkProxyNone])"),
-            ...manualControlContainer.querySelectorAll("textbox:not(#networkProxyNone)"),
+            ...manualControlContainer.querySelectorAll("textbox"),
             ...manualControlContainer.querySelectorAll("checkbox"),
             ...doc.querySelectorAll("#networkProxySOCKSVersion > radio")],
           pacControls: [doc.getElementById("networkProxyAutoconfigURL")],
           otherControls: [
             doc.querySelector("label[control=networkProxyNone]"),
             doc.getElementById("networkProxyNone"),
             ...controlGroup.querySelectorAll(":scope > radio"),
             ...doc.querySelectorAll("#ConnectionsDialogPane > checkbox")],
@@ -841,18 +841,21 @@ add_task(async function testExtensionCon
   let panelDoc = panelObj.panel.document;
 
   verifyState(panelDoc, false);
 
   await closeProxyPanel(panelObj);
 
   verifyState(mainDoc, false);
 
-  // Install an extension that controls proxy settings.
+  // Install an extension that controls proxy settings. The extension needs
+  // incognitoOverride because controlling the proxy.settings requires private
+  // browsing access.
   let extension = ExtensionTestUtils.loadExtension({
+    incognitoOverride: "spanning",
     useAddonManager: "permanent",
     manifest: {
       name: "set_proxy",
       applications: {gecko: {id: EXTENSION_ID}},
       permissions: ["proxy"],
     },
     background,
   });
--- a/browser/components/urlbar/UrlbarController.jsm
+++ b/browser/components/urlbar/UrlbarController.jsm
@@ -188,16 +188,52 @@ class UrlbarController {
    * or save resourced on repeated searches.
    */
   viewContextChanged() {
     this.cancelQuery();
     this._notify("onViewContextChanged");
   }
 
   /**
+   * Checks whether a keyboard event that would normally open the view should
+   * instead be handled natively by the input field.
+   * On certain platforms, the up and down keys can be used to move the caret,
+   * in which case we only want to open the view if the caret is at the
+   * start or end of the input.
+   *
+   * @param {KeyboardEvent} event
+   *   The DOM KeyboardEvent.
+   * @returns {boolean}
+   *   Returns true if the event should move the caret instead of opening the
+   *   view.
+   */
+  keyEventMovesCaret(event) {
+    if (this.view.isOpen) {
+      return false;
+    }
+    if (AppConstants.platform != "macosx" &&
+        AppConstants.platform != "linux") {
+      return false;
+    }
+    let isArrowUp = event.keyCode == KeyEvent.DOM_VK_UP;
+    let isArrowDown = event.keyCode == KeyEvent.DOM_VK_DOWN;
+    if (!isArrowUp && !isArrowDown) {
+      return false;
+    }
+    let start = this.input.selectionStart;
+    let end = this.input.selectionEnd;
+    if (end != start ||
+        (isArrowUp && start > 0) ||
+        (isArrowDown && end < this.input.textValue.length)) {
+      return true;
+    }
+    return false;
+  }
+
+  /**
    * Receives keyboard events from the input and handles those that should
    * navigate within the view or pick the currently selected item.
    *
    * @param {KeyboardEvent} event
    *   The DOM KeyboardEvent.
    */
   handleKeyNavigation(event) {
     const isMac = AppConstants.platform == "macosx";
@@ -256,16 +292,19 @@ class UrlbarController {
           this.userSelectionBehavior = "arrow";
           this.view.selectBy(
             event.keyCode == KeyEvent.DOM_VK_PAGE_DOWN ||
             event.keyCode == KeyEvent.DOM_VK_PAGE_UP ?
               5 : 1,
             { reverse: event.keyCode == KeyEvent.DOM_VK_UP ||
                        event.keyCode == KeyEvent.DOM_VK_PAGE_UP });
         } else {
+          if (this.keyEventMovesCaret(event)) {
+            break;
+          }
           this.input.startQuery();
         }
         event.preventDefault();
         break;
       case KeyEvent.DOM_VK_DELETE:
       case KeyEvent.DOM_VK_BACK_SPACE:
         if (event.shiftKey && this.view.isOpen && this._handleDeleteEntry()) {
           event.preventDefault();
--- a/browser/components/urlbar/UrlbarEventBufferer.jsm
+++ b/browser/components/urlbar/UrlbarEventBufferer.jsm
@@ -237,16 +237,21 @@ class UrlbarEventBufferer {
     let isMacNavigation = AppConstants.platform == "macosx" &&
                           event.ctrlKey &&
                           this.input.view.isOpen &&
                           (event.key === "n" || event.key === "p");
     if (!DEFERRED_KEY_CODES.has(event.keyCode) && !isMacNavigation) {
       return false;
     }
 
+    if (DEFERRED_KEY_CODES.has(event.keyCode) &&
+        this.input.controller.keyEventMovesCaret(event)) {
+      return false;
+    }
+
     // This is an event that we'd defer, but if enough time has passed since the
     // start of the search, we don't want to block the user's workflow anymore.
     if (this._lastQuery.startDate + DEFERRING_TIMEOUT_MS <= Cu.now()) {
       return false;
     }
 
     if (event.keyCode == KeyEvent.DOM_VK_TAB && !this.input.view.isOpen) {
       // The view is closed and the user pressed the Tab key.  The focus should
--- a/browser/components/urlbar/UrlbarUtils.jsm
+++ b/browser/components/urlbar/UrlbarUtils.jsm
@@ -13,17 +13,16 @@ var EXPORTED_SYMBOLS = [
   "UrlbarMuxer",
   "UrlbarProvider",
   "UrlbarQueryContext",
   "UrlbarUtils",
 ];
 
 const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetters(this, {
-  BinarySearch: "resource://gre/modules/BinarySearch.jsm",
   BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
   PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
   PlacesUIUtils: "resource:///modules/PlacesUIUtils.jsm",
   PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
   Services: "resource://gre/modules/Services.jsm",
   UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
 });
 
@@ -227,33 +226,42 @@ var UrlbarUtils = {
    *            [matchIndex_0, matchLength_0],
    *            [matchIndex_1, matchLength_1],
    *            ...
    *            [matchIndex_n, matchLength_n]
    *          ].
    *          The array is sorted by match indexes ascending.
    */
   getTokenMatches(tokens, str) {
-    return tokens.reduce((matches, token) => {
-      let index = 0;
+    // To generate non-overlapping ranges, we start from a 0-filled array with
+    // the same length of the string, and use it as a collision marker, setting
+    // 1 where a token matches.
+    let hits = new Array(str.length).fill(0);
+    for (let token of tokens) {
       // Ideally we should never hit the empty token case, but just in case
       // the value check protects us from an infinite loop.
-      while (index >= 0 && token.value) {
-        index = str.indexOf(token.value, index);
+      for (let index = 0, needle = token.value; index >= 0 && needle;) {
+        index = str.indexOf(needle, index);
         if (index >= 0) {
-          let match = [index, token.value.length];
-          let matchesIndex = BinarySearch.insertionIndexOf((a, b) => {
-            return a[0] - b[0];
-          }, matches, match);
-          matches.splice(matchesIndex, 0, match);
-          index += token.value.length;
+          hits.fill(1, index, index + needle.length);
+          index += needle.length;
         }
       }
-      return matches;
-    }, []);
+    }
+    // Starting from the collision array, generate [start, len] tuples
+    // representing the ranges to be highlighted.
+    let ranges = [];
+    for (let index = hits.indexOf(1); index >= 0 && index < hits.length;) {
+      let len = 0;
+      for (let j = index; j < hits.length && hits[j]; ++j, ++len);
+      ranges.push([index, len]);
+      // Move to the next 1.
+      index = hits.indexOf(1, index + len);
+    }
+    return ranges;
   },
 
   /**
    * Extracts an url from a result, if possible.
    * @param {UrlbarResult} result The result to extract from.
    * @returns {object} a {url, postData} object, or null if a url can't be built
    *          from this result.
    */
--- a/browser/components/urlbar/tests/UrlbarTestUtils.jsm
+++ b/browser/components/urlbar/tests/UrlbarTestUtils.jsm
@@ -191,16 +191,25 @@ var UrlbarTestUtils = {
    * @param {function} [closeFn] Function to be used to close the popup, if not
    *        supplied it will default to a closing the popup directly.
    * @returns {Promise} resolved once the popup is closed
    */
   promisePopupClose(win, closeFn = null) {
     let urlbar = getUrlbarAbstraction(win);
     return urlbar.promisePopupClose(closeFn);
   },
+
+  /**
+   * @param {object} win The browser window
+   * @returns {boolean} Whether the popup is open
+   */
+  isPopupOpen(win) {
+    let urlbar = getUrlbarAbstraction(win);
+    return urlbar.isPopupOpen();
+  },
 };
 
 /**
  * Maps windows to urlbar abstractions.
  */
 var gUrlbarAbstractions = new WeakMap();
 
 function getUrlbarAbstraction(win) {
@@ -473,14 +482,15 @@ class UrlbarAbstraction {
   }
 
   async promisePopupClose(closeFn) {
     if (closeFn) {
       await closeFn();
     } else {
       this.closePopup();
     }
-    if (!this.quantumbar) {
-      return BrowserTestUtils.waitForPopupEvent(this.urlbar.popup, "hidden");
-    }
-    return BrowserTestUtils.waitForPopupEvent(this.urlbar.view.panel, "hidden");
+    return BrowserTestUtils.waitForPopupEvent(this.panel, "hidden");
+  }
+
+  isPopupOpen() {
+    return this.panel.state == "open" || this.panel.state == "showing";
   }
 }
--- a/browser/components/urlbar/tests/browser/browser.ini
+++ b/browser/components/urlbar/tests/browser/browser.ini
@@ -27,16 +27,17 @@ skip-if = os != "mac" # Mac only feature
 skip-if = true # Bug 1531348 - Failing with QuantumBar.
 [browser_autoFill_canonize.js]
 skip-if = true # Bug 1531348 - Failing with QuantumBar.
 [browser_autoFill_preserveCase.js]
 skip-if = true # Bug 1531348 - Failing with QuantumBar.
 [browser_autoFill_trimURLs.js]
 skip-if = true # Bug 1531348 - Failing with QuantumBar.
 [browser_canonizeURL.js]
+[browser_caret_navigation.js]
 [browser_dragdropURL.js]
 [browser_keepStateAcrossTabSwitches.js]
 [browser_keyword_override.js]
 [browser_keyword_select_and_type.js]
 [browser_keyword.js]
 support-files =
   print_postdata.sjs
 [browser_locationBarCommand.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/urlbar/tests/browser/browser_caret_navigation.js
@@ -0,0 +1,71 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Tests that up and down keys move the caret on certain platforms, and that
+ * opening the popup doesn't change the caret position.
+ */
+
+add_task(async function() {
+  await promiseAutocompleteResultPopup("This is a generic sentence");
+  await UrlbarTestUtils.promisePopupClose(window);
+
+  const INITIAL_SELECTION_START = 3;
+  const INITIAL_SELECTION_END = 10;
+  gURLBar.selectionStart = INITIAL_SELECTION_START;
+  gURLBar.selectionEnd = INITIAL_SELECTION_END;
+
+  if (AppConstants.platform == "macosx" ||
+      AppConstants.platform == "linux") {
+    if (AppConstants.platform == "linux") {
+      await checkCaretMoves("KEY_ArrowUp", INITIAL_SELECTION_START, "Selection should be collapsed to its start");
+
+      gURLBar.selectionStart = INITIAL_SELECTION_START;
+      gURLBar.selectionEnd = INITIAL_SELECTION_END;
+      await checkCaretMoves("KEY_ArrowDown", INITIAL_SELECTION_END, "Selection should be collapsed to its end");
+    }
+
+    await checkCaretMoves("KEY_ArrowDown", gURLBar.textValue.length, "Caret should have moved to the end");
+    await checkPopupOpens("KEY_ArrowDown", gURLBar.textValue.length);
+
+    await checkCaretMoves("KEY_ArrowUp", 0, "Caret should have moved to the start");
+    await checkPopupOpens("KEY_ArrowUp", 0);
+  } else {
+    await checkPopupOpens("KEY_ArrowDown", gURLBar.textValue.length);
+    await checkPopupOpens("KEY_ArrowUp", gURLBar.textValue.length);
+  }
+});
+
+async function checkCaretMoves(key, pos, msg) {
+  checkIfKeyStartsQuery(key, false);
+  Assert.equal(UrlbarTestUtils.isPopupOpen(window), false, `${key}: Popup shouldn't be open`);
+  Assert.equal(gURLBar.selectionStart, gURLBar.selectionEnd, `${key}: Input selection should be empty`);
+  Assert.equal(gURLBar.selectionStart, pos, `${key}: ${msg}`);
+}
+
+async function checkPopupOpens(key, expectedCaretPosition) {
+  await UrlbarTestUtils.promisePopupOpen(window, () => {
+    checkIfKeyStartsQuery(key, true);
+  });
+  Assert.equal(UrlbarTestUtils.getSelectedIndex(window), 0, `${key}: Heuristic result should be selected`);
+  Assert.equal(gURLBar.selectionStart, gURLBar.selectionEnd, `${key}: Input selection should be empty`);
+  Assert.equal(gURLBar.selectionStart, expectedCaretPosition, `${key}: Caret is at the expected position`);
+  await UrlbarTestUtils.promisePopupClose(window);
+}
+
+function checkIfKeyStartsQuery(key, shouldStartQuery) {
+  let queryStarted = false;
+  let queryListener = {
+    onQueryStarted() {
+      queryStarted = true;
+    },
+  };
+  gURLBar.controller.addQueryListener(queryListener);
+  EventUtils.synthesizeKey(key);
+  gURLBar.eventBufferer.replayAllDeferredEvents();
+  gURLBar.controller.removeQueryListener(queryListener);
+  Assert.equal(queryStarted, shouldStartQuery,
+               `${key}: Should${shouldStartQuery ? "" : "n't"} have started a query`);
+}
--- a/browser/components/urlbar/tests/browser/browser_keyword.js
+++ b/browser/components/urlbar/tests/browser/browser_keyword.js
@@ -24,19 +24,17 @@ function assertURL(result, expectedUrl, 
     // We need to make a real URI out of this to ensure it's normalised for
     // comparison.
     Assert.equal(result.url, PlacesUtils.mozActionURI("keyword",
       {url: expectedUrl, input, postData}),
       "Expect correct url");
   }
 }
 
-const TEST_PATH = getRootDirectory(gTestPath)
-  .replace("chrome://mochitests/content", "http://mochi.test:8888");
-const TEST_URL = `${TEST_PATH}print_postdata.sjs`;
+const TEST_URL = `${TEST_BASE_URL}print_postdata.sjs`;
 
 add_task(async function setup() {
   await PlacesUtils.keywords.insert({ keyword: "get",
                                       url: TEST_URL + "?q=%s" });
   await PlacesUtils.keywords.insert({ keyword: "post",
                                       url: TEST_URL,
                                       postData: "q=%s" });
   registerCleanupFunction(async function() {
@@ -51,32 +49,32 @@ add_task(async function setup() {
 add_task(async function test_display_keyword_without_query() {
   await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
 
   // Test a keyword that also has blank spaces to ensure they are ignored as well.
   let result = await promise_first_result("get  ");
 
   Assert.equal(result.type, UrlbarUtils.RESULT_TYPE.KEYWORD,
     "Should have a keyword result");
-  Assert.equal(result.displayed.title, "mochi.test:8888",
+  Assert.equal(result.displayed.title, "example.com",
     "Node should contain the name of the bookmark");
   Assert.equal(result.displayed.action,
     Services.strings.createBundle("chrome://global/locale/autocomplete.properties")
             .GetStringFromName("visit"),
      "Should have visit indicated");
 });
 
 add_task(async function test_keyword_using_get() {
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
 
   let result = await promise_first_result("get something");
 
   Assert.equal(result.type, UrlbarUtils.RESULT_TYPE.KEYWORD,
     "Should have a keyword result");
-  Assert.equal(result.displayed.title, "mochi.test:8888: something",
+  Assert.equal(result.displayed.title, "example.com: something",
      "Node should contain the name of the bookmark and query");
   Assert.ok(!result.displayed.action, "Should have an empty action");
 
   assertURL(result, TEST_URL + "?q=something", "get something");
 
   let element = await UrlbarTestUtils.waitForAutocompleteResultAt(window, 0);
 
   if (!UrlbarPrefs.get("quantumbar")) {
@@ -117,17 +115,17 @@ add_task(async function test_keyword_usi
 
 add_task(async function test_keyword_using_post() {
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
 
   let result = await promise_first_result("post something");
 
   Assert.equal(result.type, UrlbarUtils.RESULT_TYPE.KEYWORD,
     "Should have a keyword result");
-  Assert.equal(result.displayed.title, "mochi.test:8888: something",
+  Assert.equal(result.displayed.title, "example.com: something",
      "Node should contain the name of the bookmark and query");
   Assert.ok(!result.displayed.action, "Should have an empty action");
 
   assertURL(result, TEST_URL, "post something", "q=something");
 
   // Click on the result
   info("Normal click on result");
   let tabPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
--- a/browser/components/urlbar/tests/browser/browser_populateAfterPushState.js
+++ b/browser/components/urlbar/tests/browser/browser_populateAfterPushState.js
@@ -4,20 +4,19 @@
 "use strict";
 
 /* When a user clears the URL bar, and then the page pushes state, we should
  * re-fill the URL bar so it doesn't remain empty indefinitely. See bug 1441039.
  * For normal loads, this happens automatically because a non-same-document state
  * change takes place.
  */
 add_task(async function() {
-  const TEST_PATH = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "http://example.com");
-  await BrowserTestUtils.withNewTab(TEST_PATH + "dummy_page.html", async function(browser) {
+  await BrowserTestUtils.withNewTab(TEST_BASE_URL + "dummy_page.html", async function(browser) {
     gURLBar.value = "";
 
-    let locationChangePromise = BrowserTestUtils.waitForLocationChange(gBrowser, TEST_PATH + "dummy_page2.html");
+    let locationChangePromise = BrowserTestUtils.waitForLocationChange(gBrowser, TEST_BASE_URL + "dummy_page2.html");
     await ContentTask.spawn(browser, null, function() {
       content.history.pushState({}, "Page 2", "dummy_page2.html");
     });
     await locationChangePromise;
-    is(gURLBar.value, TEST_PATH + "dummy_page2.html", "Should have updated the URL bar.");
+    is(gURLBar.value, TEST_BASE_URL + "dummy_page2.html", "Should have updated the URL bar.");
   });
 });
--- a/browser/components/urlbar/tests/browser/browser_raceWithTabs.js
+++ b/browser/components/urlbar/tests/browser/browser_raceWithTabs.js
@@ -1,11 +1,12 @@
-const TEST_PATH = getRootDirectory(gTestPath)
-  .replace("chrome://mochitests/content", "http://example.com");
-const TEST_URL = `${TEST_PATH}dummy_page.html`;
+/* Any copyright is dedicated to the Public Domain.
+ * https://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TEST_URL = `${TEST_BASE_URL}dummy_page.html`;
 
 async function addBookmark(bookmark) {
   if (bookmark.keyword) {
     await PlacesUtils.keywords.insert({
       keyword: bookmark.keyword,
       url: bookmark.url,
     });
   }
--- a/browser/components/urlbar/tests/browser/browser_redirect_error.js
+++ b/browser/components/urlbar/tests/browser/browser_redirect_error.js
@@ -1,14 +1,12 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-const TEST_PATH = getRootDirectory(gTestPath)
-  .replace("chrome://mochitests/content", "http://example.com");
-const REDIRECT_FROM = `${TEST_PATH}redirect_error.sjs`;
+const REDIRECT_FROM = `${TEST_BASE_URL}redirect_error.sjs`;
 
 const REDIRECT_TO = "https://www.bank1.com/"; // Bad-cert host.
 
 function isRedirectedURISpec(aURISpec) {
   return isRedirectedURI(Services.io.newURI(aURISpec));
 }
 
 function isRedirectedURI(aURI) {
--- a/browser/components/urlbar/tests/browser/browser_remotetab.js
+++ b/browser/components/urlbar/tests/browser/browser_remotetab.js
@@ -5,19 +5,17 @@
  * This tests checks that the remote tab result is displayed and can be
  * selected.
  */
 
 "use strict";
 
 const {SyncedTabs} = ChromeUtils.import("resource://services-sync/SyncedTabs.jsm");
 
-const TEST_PATH = getRootDirectory(gTestPath)
-  .replace("chrome://mochitests/content", "http://example.org");
-const TEST_URL = `${TEST_PATH}dummy_page.html`;
+const TEST_URL = `${TEST_BASE_URL}dummy_page.html`;
 
 const REMOTE_TAB = {
   "id": "7cqCr77ptzX3",
   "type": "client",
   "lastModified": 1492201200,
   "name": "zcarter's Nightly on MacBook-Pro-25",
   "clientType": "desktop",
   "tabs": [
--- a/browser/components/urlbar/tests/browser/browser_stop_pending.js
+++ b/browser/components/urlbar/tests/browser/browser_stop_pending.js
@@ -54,18 +54,17 @@ add_task(async function() {
  * The URL bar continues to contain the URL of the page we wanted to visit.
  */
 add_task(async function() {
   let socket = Cc["@mozilla.org/network/server-socket;1"].createInstance(Ci.nsIServerSocket);
   socket.init(-1, true, -1);
   const PORT = socket.port;
   registerCleanupFunction(() => { socket.close(); });
 
-  const TEST_PATH = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com");
-  const BASE_PAGE = TEST_PATH + "dummy_page.html";
+  const BASE_PAGE = TEST_BASE_URL + "dummy_page.html";
   const SLOW_HOST = `https://localhost:${PORT}/`;
   info("Using URLs: " + SLOW_HOST);
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_PAGE);
   info("opened tab");
   await ContentTask.spawn(tab.linkedBrowser, SLOW_HOST, URL => {
     let link = content.document.createElement("a");
     link.href = URL;
     link.textContent = "click me to open a slow page";
@@ -100,18 +99,17 @@ add_task(async function() {
   let socket = Cc["@mozilla.org/network/server-socket;1"].createInstance(Ci.nsIServerSocket);
   socket.init(-1, true, -1);
   const PORT1 = socket.port;
   let socket2 = Cc["@mozilla.org/network/server-socket;1"].createInstance(Ci.nsIServerSocket);
   socket2.init(-1, true, -1);
   const PORT2 = socket2.port;
   registerCleanupFunction(() => { socket.close(); socket2.close(); });
 
-  const TEST_PATH = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com");
-  const BASE_PAGE = TEST_PATH + "dummy_page.html";
+  const BASE_PAGE = TEST_BASE_URL + "dummy_page.html";
   const SLOW_HOST1 = `https://localhost:${PORT1}/`;
   const SLOW_HOST2 = `https://localhost:${PORT2}/`;
   info("Using URLs: " + SLOW_HOST1 + " and " + SLOW_HOST2);
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_PAGE);
   info("opened tab");
   await ContentTask.spawn(tab.linkedBrowser, SLOW_HOST1, URL => {
     let link = content.document.createElement("a");
     link.href = URL;
--- a/browser/components/urlbar/tests/browser/browser_switchTab_decodeuri.js
+++ b/browser/components/urlbar/tests/browser/browser_switchTab_decodeuri.js
@@ -3,19 +3,17 @@
 
 /**
  * This test ensures that switch to tab still works when the URI contains an
  * encoded part.
  */
 
 "use strict";
 
-const TEST_PATH = getRootDirectory(gTestPath)
-  .replace("chrome://mochitests/content", "http://example.org");
-const TEST_URL = `${TEST_PATH}dummy_page.html#test%7C1`;
+const TEST_URL = `${TEST_BASE_URL}dummy_page.html#test%7C1`;
 
 add_task(async function test_switchtab_decodeuri() {
   info("Opening first tab");
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
 
   info("Opening and selecting second tab");
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
 
--- a/browser/components/urlbar/tests/browser/browser_switchTab_override.js
+++ b/browser/components/urlbar/tests/browser/browser_switchTab_override.js
@@ -4,19 +4,17 @@
 
 /**
  * This test ensures that overriding switch-to-tab correctly loads the page
  * rather than switching to it.
  */
 
 "use strict";
 
-const TEST_PATH = getRootDirectory(gTestPath)
-  .replace("chrome://mochitests/content", "http://example.org/");
-const TEST_URL = `${TEST_PATH}dummy_page.html`;
+const TEST_URL = `${TEST_BASE_URL}dummy_page.html`;
 
 
 add_task(async function test_switchtab_override() {
   info("Opening first tab");
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
 
   info("Opening and selecting second tab");
   let secondTab = gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
--- a/browser/components/urlbar/tests/browser/browser_tabMatchesInAwesomebar.js
+++ b/browser/components/urlbar/tests/browser/browser_tabMatchesInAwesomebar.js
@@ -8,21 +8,19 @@
 
 /**
  * Tests for ensuring that the tab switch results correctly match what is
  * currently available.
  */
 
 requestLongerTimeout(2);
 
-const TEST_PATH = getRootDirectory(gTestPath)
-  .replace("chrome://mochitests/content", "http://example.com");
 const TEST_URL_BASES = [
-  `${TEST_PATH}dummy_page.html#tabmatch`,
-  `${TEST_PATH}moz.png#tabmatch`,
+  `${TEST_BASE_URL}dummy_page.html#tabmatch`,
+  `${TEST_BASE_URL}moz.png#tabmatch`,
 ];
 
 const RESTRICT_TOKEN_OPENPAGE = "%";
 
 var gTabCounter = 0;
 
 add_task(async function step_1() {
   info("Running step 1");
--- a/browser/components/urlbar/tests/browser/browser_tabMatchesInAwesomebar_perwindowpb.js
+++ b/browser/components/urlbar/tests/browser/browser_tabMatchesInAwesomebar_perwindowpb.js
@@ -3,19 +3,17 @@
 
 "use strict";
 
 /**
  * This test ensures that we don't move switch between tabs when one is in
  * private browsing and the other is normal, or vice-versa.
  */
 
-const TEST_PATH = getRootDirectory(gTestPath)
-  .replace("chrome://mochitests/content", "http://example.com");
-const TEST_URL = `${TEST_PATH}dummy_page.html`;
+const TEST_URL = `${TEST_BASE_URL}dummy_page.html`;
 
 add_task(async function() {
   let normalWindow = await BrowserTestUtils.openNewBrowserWindow();
   let privateWindow = await BrowserTestUtils.openNewBrowserWindow({private: true});
   await runTest(normalWindow, privateWindow, false);
   await BrowserTestUtils.closeWindow(normalWindow);
   await BrowserTestUtils.closeWindow(privateWindow);
 
@@ -61,17 +59,19 @@ async function runTest(aSourceWindow, aD
   await ContentTask.spawn(testTab.linkedBrowser, null, async function() {
     ok(!content.document.body.hasChildNodes(),
        "The test tab has no child nodes");
   });
   ok(!testTab.hasAttribute("busy"),
      "The test tab doesn't have the busy attribute");
 
   // Wait for the Awesomebar popup to appear.
-  await promiseAutocompleteResultPopup(TEST_URL, aDestWindow);
+  // Use a slice to workaround bug 1507755.
+  let searchString = UrlbarPrefs.get("quantumbar") ? TEST_URL : TEST_URL.slice(1);
+  await promiseAutocompleteResultPopup(searchString, aDestWindow);
 
   info(`awesomebar popup appeared. aExpectSwitch: ${aExpectSwitch}`);
   // Make sure the last match is selected.
   while (UrlbarTestUtils.getSelectedIndex(aDestWindow) <
          UrlbarTestUtils.getResultCount(aDestWindow) - 1) {
     info("handling key navigation for DOM_VK_DOWN key");
     EventUtils.synthesizeKey("KEY_ArrowDown", {}, aDestWindow);
   }
--- a/browser/components/urlbar/tests/browser/browser_urlbarHashChangeProxyState.js
+++ b/browser/components/urlbar/tests/browser/browser_urlbarHashChangeProxyState.js
@@ -1,19 +1,19 @@
-"use strict";
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-const TEST_PATH = getRootDirectory(gTestPath)
-  .replace("chrome://mochitests/content", "https://example.org");
+"use strict";
 
 /**
  * Check that navigating through both the URL bar and using in-page hash- or ref-
  * based links and back or forward navigation updates the URL bar and identity block correctly.
  */
 add_task(async function() {
-  let baseURL = `${TEST_PATH}dummy_page.html`;
+  let baseURL = `${TEST_BASE_URL}dummy_page.html`;
   let url = baseURL + "#foo";
   await BrowserTestUtils.withNewTab({ gBrowser, url }, async function(browser) {
     let identityBox = document.getElementById("identity-box");
     let expectedURL = url;
 
     let verifyURLBarState = testType => {
       is(gURLBar.textValue, expectedURL, "URL bar visible value should be correct " + testType);
       is(gURLBar.value, expectedURL, "URL bar value should be correct " + testType);
@@ -90,17 +90,17 @@ add_task(async function() {
 /**
  * Check that initial secure loads that swap remoteness
  * get the correct page icon when finished.
  */
 add_task(async function() {
   // Ensure there's no preloaded newtab browser, since that'll not fire a load event.
   gBrowser.removePreloadedBrowser();
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:newtab");
-  let url = `${TEST_PATH}dummy_page.html#foo`;
+  let url = `${TEST_BASE_URL}dummy_page.html#foo`;
   gURLBar.value = url;
   gURLBar.select();
   EventUtils.sendKey("return");
   await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
 
   is(gURLBar.textValue, url, "URL bar visible value should be correct when the page loads from about:newtab");
   is(gURLBar.value, url, "URL bar value should be correct when the page loads from about:newtab");
   let identityBox = document.getElementById("identity-box");
--- a/browser/components/urlbar/tests/browser/browser_urlbarValueOnTabSwitch.js
+++ b/browser/components/urlbar/tests/browser/browser_urlbarValueOnTabSwitch.js
@@ -4,19 +4,17 @@
 
 /**
  * This tests for the correct URL being displayed in the URL bar after switching
  * tabs which are in different states (e.g. deleted, partially deleted).
  */
 
 "use strict";
 
-const TEST_PATH = getRootDirectory(gTestPath)
-  .replace("chrome://mochitests/content", "http://example.com");
-const TEST_URL = `${TEST_PATH}dummy_page.html`;
+const TEST_URL = `${TEST_BASE_URL}dummy_page.html`;
 
 add_task(async function() {
   let charsToDelete, deletedURLTab, fullURLTab, partialURLTab, testPartialURL, testURL;
 
   charsToDelete = 5;
   deletedURLTab = BrowserTestUtils.addTab(gBrowser);
   fullURLTab = BrowserTestUtils.addTab(gBrowser);
   partialURLTab = BrowserTestUtils.addTab(gBrowser);
--- a/browser/components/urlbar/tests/browser/browser_urlbar_blanking.js
+++ b/browser/components/urlbar/tests/browser/browser_urlbar_blanking.js
@@ -1,13 +1,14 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
 "use strict";
 
-const TEST_PATH = getRootDirectory(gTestPath)
-  .replace("chrome://mochitests/content", "http://www.example.com");
-const TEST_URL = `${TEST_PATH}file_blank_but_not_blank.html`;
+const TEST_URL = `${TEST_BASE_URL}file_blank_but_not_blank.html`;
 
 add_task(async function() {
   for (let page of gInitialPages) {
     if (page == "about:newtab") {
       // New tab preloading makes this a pain to test, so skip
       continue;
     }
     let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, page);
--- a/browser/components/urlbar/tests/browser/browser_urlbar_content_opener.js
+++ b/browser/components/urlbar/tests/browser/browser_urlbar_content_opener.js
@@ -1,17 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-const TEST_PATH = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com");
-
 add_task(async function() {
-  await BrowserTestUtils.withNewTab(TEST_PATH + "dummy_page.html", async function(browser) {
+  await BrowserTestUtils.withNewTab(TEST_BASE_URL + "dummy_page.html", async function(browser) {
     let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
     await ContentTask.spawn(browser, null, function() {
       content.window.open("", "_BLANK", "toolbar=no,height=300,width=500");
     });
     let newWin = await windowOpenedPromise;
     is(newWin.gURLBar.value, "about:blank", "Should be displaying about:blank for the opened window.");
     await BrowserTestUtils.closeWindow(newWin);
   });
--- a/browser/components/urlbar/tests/browser/browser_urlbar_locationchange_urlbar_edit_dos.js
+++ b/browser/components/urlbar/tests/browser/browser_urlbar_locationchange_urlbar_edit_dos.js
@@ -1,13 +1,14 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
 "use strict";
 
-const TEST_PATH = getRootDirectory(gTestPath)
-  .replace("chrome://mochitests/content", "http://www.example.com");
-const TEST_URL = `${TEST_PATH}file_urlbar_edit_dos.html`;
+const TEST_URL = `${TEST_BASE_URL}file_urlbar_edit_dos.html`;
 
 async function checkURLBarValueStays(browser) {
   gURLBar.select();
   EventUtils.sendString("a");
   is(gURLBar.value, "a", "URL bar value should match after sending a key");
   await new Promise(resolve => {
     let listener = {
       onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
--- a/browser/components/urlbar/tests/browser/browser_userTypedValue.js
+++ b/browser/components/urlbar/tests/browser/browser_userTypedValue.js
@@ -1,11 +1,13 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
 function test() {
-  const TEST_PATH = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com");
-  const URI = TEST_PATH + "file_userTypedValue.html";
+  const URI = TEST_BASE_URL + "file_userTypedValue.html";
   window.browserDOMWindow.openURI(makeURI(URI),
                                   null,
                                   Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
                                   Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL,
                                   Services.scriptSecurityManager.getSystemPrincipal());
 
   is(gBrowser.userTypedValue, URI, "userTypedValue matches test URI");
   is(gURLBar.value, URI, "location bar value matches test URI");
--- a/browser/components/urlbar/tests/browser/head-common.js
+++ b/browser/components/urlbar/tests/browser/head-common.js
@@ -7,16 +7,20 @@ XPCOMUtils.defineLazyModuleGetters(this,
   PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
   PlacesTestUtils: "resource://testing-common/PlacesTestUtils.jsm",
   Preferences: "resource://gre/modules/Preferences.jsm",
   SearchTestUtils: "resource://testing-common/SearchTestUtils.jsm",
   UrlbarTestUtils: "resource://testing-common/UrlbarTestUtils.jsm",
   UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.jsm",
 });
 
+XPCOMUtils.defineLazyGetter(this, "TEST_BASE_URL", () =>
+  getRootDirectory(gTestPath).replace("chrome://mochitests/content",
+                                      "https://example.com"));
+
 SearchTestUtils.init(Assert, registerCleanupFunction);
 
 function is_element_visible(element, msg) {
   isnot(element, null, "Element should not be null, when checking visibility");
   ok(BrowserTestUtils.is_visible(element), msg || "Element should be visible");
 }
 
 function is_element_hidden(element, msg) {
--- a/browser/components/urlbar/tests/legacy/browser_switchtab_copy.js
+++ b/browser/components/urlbar/tests/legacy/browser_switchtab_copy.js
@@ -1,15 +1,13 @@
 /* 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/. */
 
-const TEST_PATH = getRootDirectory(gTestPath)
-  .replace("chrome://mochitests/content", "http://example.com");
-const TEST_URL = `${TEST_PATH}dummy_page.html`;
+const TEST_URL = `${TEST_BASE_URL}dummy_page.html`;
 var testActionURL = "moz-action:switchtab," + JSON.stringify({url: TEST_URL});
 const testURL = gURLBar.trimValue(TEST_URL);
 var testTab;
 
 function runNextTest() {
   if (tests.length) {
     let t = tests.shift();
     waitForClipboard(t.expected, t.setup, function() {
--- a/browser/components/urlbar/tests/legacy/browser_switchtab_override_keynav.js
+++ b/browser/components/urlbar/tests/legacy/browser_switchtab_override_keynav.js
@@ -1,15 +1,13 @@
 /* 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/. */
 
-const TEST_PATH = getRootDirectory(gTestPath)
-  .replace("chrome://mochitests/content", "http://example.org");
-const TEST_URL = `${TEST_PATH}dummy_page.html`;
+const TEST_URL = `${TEST_BASE_URL}dummy_page.html`;
 
 add_task(async function test_switchtab_override_keynav() {
   info("Opening first tab");
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
 
   info("Opening and selecting second tab");
   let secondTab = gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
   registerCleanupFunction(() => {
new file mode 100644
--- /dev/null
+++ b/browser/components/urlbar/tests/unit/test_UrlbarUtils_getTokenMatches.js
@@ -0,0 +1,58 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests UrlbarUtils.getTokenMatches.
+ */
+
+"use strict";
+
+add_task(function test() {
+  const tests = [
+    {
+      tokens: ["mozilla", "is", "i"],
+      phrase: "mozilla is for the Open Web",
+      expected: [[0, 7], [8, 2]],
+    },
+    {
+      tokens: ["mo", "b"],
+      phrase: "mozilla is for the Open Web",
+      expected: [[0, 2], [26, 1]],
+    },
+    {
+      tokens: ["mo", ""],
+      phrase: "mozilla is for the Open Web",
+      expected: [[0, 2]],
+    },
+    {
+      tokens: ["mozilla"],
+      phrase: "mozilla",
+      expected: [[0, 7]],
+    },
+    {
+      tokens: ["mo", "zilla"],
+      phrase: "mozilla",
+      expected: [[0, 7]],
+    },
+    {
+      tokens: ["moz", "zilla"],
+      phrase: "mozilla",
+      expected: [[0, 7]],
+    },
+    {
+      tokens: [""], // Should never happen in practice.
+      phrase: "mozilla",
+      expected: [],
+    },
+    {
+      tokens: ["mo", "om"],
+      phrase: "mozilla mozzarella momo",
+      expected: [[0, 2], [8, 2], [19, 4]],
+    },
+  ];
+  for (let {tokens, phrase, expected} of tests) {
+    tokens = tokens.map(t => ({value: t}));
+    Assert.deepEqual(UrlbarUtils.getTokenMatches(tokens, phrase), expected,
+                     `Match "${tokens.map(t => t.value).join(", ")}" on "${phrase}"`);
+  }
+});
--- a/browser/components/urlbar/tests/unit/xpcshell.ini
+++ b/browser/components/urlbar/tests/unit/xpcshell.ini
@@ -12,8 +12,9 @@ support-files =
 [test_providersManager_maxResults.js]
 [test_tokenizer.js]
 [test_UrlbarController_unit.js]
 [test_UrlbarController_telemetry.js]
 [test_UrlbarController_integration.js]
 [test_UrlbarQueryContext.js]
 [test_UrlbarUtils_addToUrlbarHistory.js]
 [test_UrlbarUtils_getShortcutOrURIAndPostData.js]
+[test_UrlbarUtils_getTokenMatches.js]
--- a/build/mobile/remoteautomation.py
+++ b/build/mobile/remoteautomation.py
@@ -1,21 +1,18 @@
 # 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/.
 
 import datetime
-import glob
 import time
 import re
-import os
 import posixpath
 import tempfile
 import shutil
-import sys
 
 from automation import Automation
 from mozdevice import ADBTimeoutError
 from mozlog import get_default_logger
 from mozscreenshot import dump_screen, dump_device_screen
 import mozcrash
 
 # signatures for logcat messages that we don't care about much
@@ -136,80 +133,17 @@ class RemoteAutomation(Automation):
                                % self.lastTestSeen)
         if status == 2:
             self.log.error("TEST-UNEXPECTED-FAIL | %s | "
                            "application timed out after %d seconds with no output"
                            % (self.lastTestSeen, int(timeout)))
 
         return status
 
-    def deleteANRs(self):
-        # Remove files from the dalvik stack-trace directory.
-        if not self.device.is_dir(self.device.stack_trace_dir, root=True):
-            return
-        try:
-            for trace_file in self.device.ls(self.device.stack_trace_dir, root=True):
-                trace_path = posixpath.join(self.device.stack_trace_dir, trace_file)
-                self.device.chmod(trace_path, root=True)
-                self.device.rm(trace_path, root=True)
-        except Exception as e:
-            print("Error deleting %s: %s" % (self.device.stack_trace_dir, str(e)))
-
-    def checkForANRs(self):
-        if not self.device.is_dir(self.device.stack_trace_dir):
-            print("%s not found" % self.device.stack_trace_dir)
-            return
-        try:
-            for trace_file in self.device.ls(self.device.stack_trace_dir, root=True):
-                trace_path = posixpath.join(self.device.stack_trace_dir, trace_file)
-                t = self.device.get_file(trace_path)
-                if t:
-                    stripped = t.strip()
-                    if len(stripped) > 0:
-                        print("Contents of %s:" % trace_path)
-                        print(t)
-            # Once reported, delete traces
-            self.deleteANRs()
-        except Exception as e:
-            print("Error pulling %s: %s" % (self.device.stack_trace_dir, str(e)))
-
-    def deleteTombstones(self):
-        # delete any tombstone files from device
-        self.device.rm("/data/tombstones", force=True, recursive=True, root=True)
-
-    def checkForTombstones(self):
-        # pull any tombstones from device and move to MOZ_UPLOAD_DIR
-        remoteDir = "/data/tombstones"
-        uploadDir = os.environ.get('MOZ_UPLOAD_DIR', None)
-        if uploadDir:
-            if not os.path.exists(uploadDir):
-                os.mkdir(uploadDir)
-            if self.device.is_dir(remoteDir):
-                # copy tombstone files from device to local upload directory
-                self.device.chmod(remoteDir, recursive=True, root=True)
-                self.device.pull(remoteDir, uploadDir)
-                self.deleteTombstones()
-                for f in glob.glob(os.path.join(uploadDir, "tombstone_??")):
-                    # add a unique integer to the file name, in case there are
-                    # multiple tombstones generated with the same name, for
-                    # instance, after multiple robocop tests
-                    for i in xrange(1, sys.maxint):
-                        newname = "%s.%d.txt" % (f, i)
-                        if not os.path.exists(newname):
-                            os.rename(f, newname)
-                            break
-            else:
-                print("%s does not exist; tombstone check skipped" % remoteDir)
-        else:
-            print("MOZ_UPLOAD_DIR not defined; tombstone check skipped")
-
     def checkForCrashes(self, symbolsPath):
-        self.checkForANRs()
-        self.checkForTombstones()
-
         logcat = self.device.get_logcat(
             filter_out_regexps=fennecLogcatFilters)
 
         javaException = mozcrash.check_for_java_exception(
             logcat, test_name=self.lastTestSeen)
         if javaException:
             return True
 
--- a/devtools/client/debugger/new/src/client/firefox/commands.js
+++ b/devtools/client/debugger/new/src/client/firefox/commands.js
@@ -328,20 +328,16 @@ async function setSkipPausing(thread: st
     type: "skipBreakpoints"
   });
 }
 
 function interrupt(thread: string): Promise<*> {
   return lookupThreadClient(thread).interrupt();
 }
 
-function eventListeners(): Promise<*> {
-  return threadClient.eventListeners();
-}
-
 function setEventListenerBreakpoints(eventTypes: EventListenerBreakpoints) {
   // TODO: Figure out what sendpoint we want to hit
 }
 
 function pauseGrip(thread: string, func: Function): ObjectClient {
   return lookupThreadClient(thread).pauseGrip(func);
 }
 
@@ -434,17 +430,16 @@ async function getBreakpointPositions(
 }
 
 const clientCommands = {
   autocomplete,
   blackBox,
   createObjectClient,
   releaseActor,
   interrupt,
-  eventListeners,
   pauseGrip,
   resume,
   stepIn,
   stepOut,
   stepOver,
   rewind,
   reverseStepIn,
   reverseStepOut,
--- a/devtools/client/jsonview/components/MainTabbedArea.js
+++ b/devtools/client/jsonview/components/MainTabbedArea.js
@@ -18,17 +18,17 @@ define(function(require, exports, module
   /**
    * This object represents the root application template
    * responsible for rendering the basic tab layout.
    */
   class MainTabbedArea extends Component {
     static get propTypes() {
       return {
         jsonText: PropTypes.instanceOf(Text),
-        tabActive: PropTypes.number,
+        activeTab: PropTypes.number,
         actions: PropTypes.object,
         headers: PropTypes.object,
         searchFilter: PropTypes.string,
         json: PropTypes.oneOfType([
           PropTypes.string,
           PropTypes.object,
           PropTypes.array,
           PropTypes.bool,
@@ -40,30 +40,30 @@ define(function(require, exports, module
 
     constructor(props) {
       super(props);
 
       this.state = {
         json: props.json,
         expandedNodes: props.expandedNodes,
         jsonText: props.jsonText,
-        tabActive: props.tabActive,
+        activeTab: props.activeTab,
       };
 
       this.onTabChanged = this.onTabChanged.bind(this);
     }
 
     onTabChanged(index) {
-      this.setState({tabActive: index});
+      this.setState({activeTab: index});
     }
 
     render() {
       return (
         Tabs({
-          tabActive: this.state.tabActive,
+          activeTab: this.state.activeTab,
           onAfterChange: this.onTabChanged},
           TabPanel({
             id: "json",
             className: "json",
             title: JSONView.Locale.$STR("jsonViewer.tab.JSON")},
             JsonPanel({
               data: this.state.json,
               expandedNodes: this.state.expandedNodes,
--- a/devtools/client/jsonview/json-viewer.js
+++ b/devtools/client/jsonview/json-viewer.js
@@ -17,17 +17,17 @@ define(function(require, exports, module
 
   let prettyURL;
 
   // Application state object.
   const input = {
     jsonText: JSONView.json,
     jsonPretty: null,
     headers: JSONView.headers,
-    tabActive: 0,
+    activeTab: 0,
     prettified: false,
     expandedNodes: new Set(),
   };
 
   /**
    * Application actions/commands. This list implements all commands
    * available for the JSON viewer.
    */
@@ -134,23 +134,23 @@ define(function(require, exports, module
    * Render the main application component. It's the main tab bar displayed
    * at the top of the window. This component also represents ReacJS root.
    */
   const content = document.getElementById("content");
   const promise = (async function parseJSON() {
     if (document.readyState == "loading") {
       // If the JSON has not been loaded yet, render the Raw Data tab first.
       input.json = {};
-      input.tabActive = 1;
+      input.activeTab = 1;
       return new Promise(resolve => {
         document.addEventListener("DOMContentLoaded", resolve, {once: true});
       }).then(parseJSON).then(() => {
         // Now update the state and switch to the JSON tab.
         theApp.setState({
-          tabActive: 0,
+          activeTab: 0,
           json: input.json,
           expandedNodes: input.expandedNodes,
         });
       });
     }
 
     // If the JSON has been loaded, parse it immediately before loading the app.
     const jsonString = input.jsonText.textContent;
--- a/devtools/client/locales/en-US/netmonitor.properties
+++ b/devtools/client/locales/en-US/netmonitor.properties
@@ -126,16 +126,21 @@ jsonFilterText=Filter properties
 # LOCALIZATION NOTE (jsonScopeName): This is the text displayed
 # in the response tab of the network details pane for a JSON scope.
 jsonScopeName=JSON
 
 # LOCALIZATION NOTE (jsonpScopeName): This is the text displayed
 # in the response tab of the network details pane for a JSONP scope.
 jsonpScopeName=JSONP → callback %S()
 
+# LOCALIZATION NOTE (responseTruncated): This is the text displayed
+# in the response tab of the network details pane when the response is over
+# the truncation limit and thus was truncated.
+responseTruncated=Response has been truncated
+
 # LOCALIZATION NOTE (responsePreview): This is the text displayed
 # in the response tab of the network details pane for an HTML preview.
 responsePreview=Preview
 
 # LOCALIZATION NOTE (networkMenu.sortedAsc): This is the tooltip displayed
 # in the network table toolbar, for any column that is sorted ascending.
 networkMenu.sortedAsc=Sorted ascending
 
--- a/devtools/client/memory/components/Toolbar.js
+++ b/devtools/client/memory/components/Toolbar.js
@@ -9,44 +9,34 @@ const PropTypes = require("devtools/clie
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const { L10N } = require("../utils");
 const models = require("../models");
 const { viewState } = require("../constants");
 
 class Toolbar extends Component {
   static get propTypes() {
     return {
-      censusDisplays: PropTypes.arrayOf(PropTypes.shape({
-        displayName: PropTypes.string.isRequired,
-      })).isRequired,
-      censusDisplay: PropTypes.shape({
-        displayName: PropTypes.string.isRequired,
-      }).isRequired,
+      censusDisplays: PropTypes.arrayOf(models.censusDisplay).isRequired,
+      censusDisplay: models.censusDisplay.isRequired,
       onTakeSnapshotClick: PropTypes.func.isRequired,
       onImportClick: PropTypes.func.isRequired,
       onClearSnapshotsClick: PropTypes.func.isRequired,
       onCensusDisplayChange: PropTypes.func.isRequired,
       onToggleRecordAllocationStacks: PropTypes.func.isRequired,
       allocations: models.allocations,
       filterString: PropTypes.string,
       setFilterString: PropTypes.func.isRequired,
       diffing: models.diffingModel,
       onToggleDiffing: PropTypes.func.isRequired,
       view: models.view.isRequired,
       onViewChange: PropTypes.func.isRequired,
-      labelDisplays: PropTypes.arrayOf(PropTypes.shape({
-        displayName: PropTypes.string.isRequired,
-      })).isRequired,
-      labelDisplay: PropTypes.shape({
-        displayName: PropTypes.string.isRequired,
-      }).isRequired,
+      labelDisplays: PropTypes.arrayOf(models.labelDisplay).isRequired,
+      labelDisplay: models.labelDisplay.isRequired,
       onLabelDisplayChange: PropTypes.func.isRequired,
-      treeMapDisplays: PropTypes.arrayOf(PropTypes.shape({
-        displayName: PropTypes.string.isRequired,
-      })).isRequired,
+      treeMapDisplays: PropTypes.arrayOf(models.treeMapDisplay).isRequired,
       onTreeMapDisplayChange: PropTypes.func.isRequired,
       snapshots: PropTypes.arrayOf(models.snapshot).isRequired,
     };
   }
 
   render() {
     const {
       onTakeSnapshotClick,
--- a/devtools/client/netmonitor/src/components/HeadersPanel.js
+++ b/devtools/client/netmonitor/src/components/HeadersPanel.js
@@ -64,17 +64,17 @@ const SUMMARY_REFERRER_POLICY = L10N.get
  * Headers panel component
  * Lists basic information about the request
  */
 class HeadersPanel extends Component {
   static get propTypes() {
     return {
       connector: PropTypes.object.isRequired,
       cloneSelectedRequest: PropTypes.func.isRequired,
-      member: PropTypes.object.isRequired,
+      member: PropTypes.object,
       request: PropTypes.object.isRequired,
       renderValue: PropTypes.func,
       openLink: PropTypes.func,
     };
   }
 
   constructor(props) {
     super(props);
--- a/devtools/client/netmonitor/src/components/ResponsePanel.js
+++ b/devtools/client/netmonitor/src/components/ResponsePanel.js
@@ -2,16 +2,17 @@
  * 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";
 
 const { Component, createFactory } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+const Services = require("Services");
 const { L10N } = require("../utils/l10n");
 const {
   decodeUnicodeBase64,
   fetchNetworkUpdatePacket,
   formDataURI,
   getUrlBaseName,
 } = require("../utils/request-utils");
 const { Filters } = require("../utils/filter-predicates");
@@ -22,16 +23,17 @@ const PropertiesView = createFactory(req
 const { div, img } = dom;
 const JSON_SCOPE_NAME = L10N.getStr("jsonScopeName");
 const JSON_FILTER_TEXT = L10N.getStr("jsonFilterText");
 const RESPONSE_IMG_NAME = L10N.getStr("netmonitor.response.name");
 const RESPONSE_IMG_DIMENSIONS = L10N.getStr("netmonitor.response.dimensions");
 const RESPONSE_IMG_MIMETYPE = L10N.getStr("netmonitor.response.mime");
 const RESPONSE_PAYLOAD = L10N.getStr("responsePayload");
 const RESPONSE_PREVIEW = L10N.getStr("responsePreview");
+const RESPONSE_TRUNCATED = L10N.getStr("responseTruncated");
 
 const JSON_VIEW_MIME_TYPE = "application/vnd.mozilla.json.view";
 
 /**
  * Response panel component
  * Displays the GET parameters and POST data of a request
  */
 class ResponsePanel extends Component {
@@ -97,18 +99,28 @@ class ResponsePanel extends Component {
    * MIME type for "json" after any word boundary. This works
    * for the standard "application/json", and also for custom
    * types like "x-bigcorp-json". Additionally, we also
    * directly parse the response text content to verify whether
    * it's json or not, to handle responses incorrectly labeled
    * as text/plain instead.
    */
   isJSON(mimeType, response) {
+    const limit = Services.prefs.getIntPref("devtools.netmonitor.responseBodyLimit");
+    const { request } = this.props;
     let json, error;
 
+    // Check if the response has been truncated, in which case no parse should
+    // be attempted.
+    if (limit <= request.responseContent.content.size) {
+      const result = {};
+      result.error = RESPONSE_TRUNCATED;
+      return result;
+    }
+
     try {
       json = JSON.parse(response);
     } catch (err) {
       if (this.isBase64(response)) {
         try {
           json = JSON.parse(atob(response));
         } catch (err64) {
           error = err;
--- a/devtools/client/netmonitor/src/har/har-builder-utils.js
+++ b/devtools/client/netmonitor/src/har/har-builder-utils.js
@@ -2,17 +2,17 @@
  * 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";
 
 /**
  * Currently supported HAR version.
  */
-const HAR_VERSION = "1.1";
+const HAR_VERSION = "1.2";
 
 function buildHarLog(appInfo) {
   return {
     log: {
       version: HAR_VERSION,
       creator: {
         name: appInfo.name,
         version: appInfo.version,
--- a/devtools/client/responsive.html/components/Toolbar.js
+++ b/devtools/client/responsive.html/components/Toolbar.js
@@ -94,25 +94,29 @@ class Toolbar extends PureComponent {
       onToggleLeftAlignment,
       onToggleReloadOnTouchSimulation,
       onToggleReloadOnUserAgent,
       onToggleUserAgentInput,
       onUpdateDeviceModal,
       screenshot,
       selectedDevice,
       selectedPixelRatio,
+      showUserAgentInput,
       touchSimulationEnabled,
       viewport,
     } = this.props;
 
     return (
       dom.header(
         {
           id: "toolbar",
-          className: leftAlignmentEnabled ? "left-aligned" : "",
+          className: [
+            leftAlignmentEnabled ? "left-aligned" : "",
+            showUserAgentInput ? "user-agent" : "",
+          ].join(" ").trim(),
         },
         dom.div(
           { id: "toolbar-center-controls" },
           DeviceSelector({
             devices,
             onChangeDevice,
             onResizeViewport,
             onUpdateDeviceModal,
--- a/devtools/client/responsive.html/index.css
+++ b/devtools/client/responsive.html/index.css
@@ -80,59 +80,147 @@ body,
  */
 
 #toolbar {
   background-color: var(--theme-tab-toolbar-background);
   border-bottom: 1px solid var(--theme-splitter-color);
   display: grid;
   grid-template-columns: auto min-content;
   width: 100%;
-  min-height: 29px;
   -moz-user-select: none;
 }
 
 #toolbar-center-controls,
 #toolbar-end-controls {
-  display: flex;
-  align-items: center;
-}
-
-#toolbar-center-controls {
-  flex: 1;
-  justify-content: center;
+  display: grid;
+  grid-auto-flow: column;
+  grid-auto-rows: 29px;
   margin: 1px;
 }
 
-#toolbar.left-aligned #toolbar-center-controls {
-  justify-content: start;
+#toolbar-center-controls {
+  grid-template-columns:
+    [device-selector]
+    minmax(auto, 90px)
+    [separator]
+    max-content
+    [size-selector]
+    max-content
+    [rotate-icon]
+    max-content
+    [separator]
+    max-content
+    [dpr]
+    minmax(auto, 60px)
+    [separator]
+    max-content
+    [throttling]
+    minmax(auto, 90px)
+    [separator]
+    max-content
+    [touch-simulation]
+    max-content;
 }
 
-#toolbar.left-aligned #toolbar-end-controls {
-  justify-self: end;
+#toolbar.user-agent #toolbar-center-controls {
+  grid-template-columns:
+    [device-selector]
+    minmax(auto, 90px)
+    [separator]
+    max-content
+    [size-selector]
+    max-content
+    [rotate-icon]
+    max-content
+    [separator]
+    max-content
+    [dpr]
+    minmax(auto, 60px)
+    [separator]
+    max-content
+    [throttling]
+    minmax(auto, 90px)
+    [separator]
+    max-content
+    [ua]
+    minmax(auto, 300px)
+    [separator]
+    max-content
+    [touch-simulation]
+    max-content;
 }
 
-#rotate-button::before {
-  background-image: url("./images/rotate-viewport.svg");
+#toolbar:not(.left-aligned) #toolbar-center-controls {
+  justify-content: center;
 }
 
 #user-agent-label {
   display: flex;
   align-items: center;
   margin-inline-start: 3px;
   margin-inline-end: 3px;
-  width: 300px;
 }
 
-#user-agent-label:focus-within {
+#user-agent-input {
+  margin-inline-start: 3px;
   flex: 1;
 }
 
-#user-agent-input {
-  margin-inline-start: 3px;;
-  width: 100%;
+@media (max-width: 520px) {
+  /* When room becomes scarce, no need to constrain the selectors with a minmax like we
+     do in larger viewports, here they can occupy 1fr */
+  #toolbar.user-agent #toolbar-center-controls {
+    grid-template-columns:
+      [device-selector]
+      .8fr
+      [separator]
+      max-content
+      [size-selector]
+      max-content
+      [rotate-icon]
+      max-content
+      [separator]
+      max-content
+      [dpr]
+      .6fr
+      [separator]
+      max-content
+      [throttling]
+      1fr
+      [separator]
+      max-content
+      [touch-simulation]
+      max-content;
+  }
+
+  /* Drop the user agent label to the next line if there isn't enough space */
+  #user-agent-label {
+    grid-column: 1 / -1;
+    grid-row: 2;
+    margin-inline-start: 9px;
+  }
+
+  /* Since the UA is hidden, no need for a separator after it */
+  #user-agent-label + .devtools-separator {
+    display: none;
+  }
+
+  /* When the UA label is here and it's on a second line, draw a separator between the
+     2 lines*/
+  #toolbar.user-agent {
+    background-image: linear-gradient(to bottom,
+      transparent calc(50% - .5px),
+      var(--separator-border-color) calc(50% - .5px),
+      var(--separator-border-color) calc(50% + .5px),
+      transparent 0);
+  }
+}
+
+#rotate-button::before {
+  background-image: url("./images/rotate-viewport.svg");
 }
 
 #touch-simulation-button::before {
   background-image: url("./images/touch-events.svg");
 }
 
 #screenshot-button::before {
   background-image: url("chrome://devtools/skin/images/command-screenshot.svg");
--- a/devtools/client/shared/components/Sidebar.js
+++ b/devtools/client/shared/components/Sidebar.js
@@ -22,17 +22,17 @@ class Sidebar extends PureComponent {
       renderOnlySelected: PropTypes.bool,
       showAllTabsMenu: PropTypes.bool,
       sidebarToggleButton: PropTypes.shape({
         collapsed: PropTypes.bool.isRequired,
         collapsePaneTitle: PropTypes.string.isRequired,
         expandPaneTitle: PropTypes.string.isRequired,
         onClick: PropTypes.func.isRequired,
       }),
-      tabActive: PropTypes.number,
+      activeTab: PropTypes.number,
     };
   }
 
   constructor(props) {
     super(props);
     this.renderSidebarToggle = this.renderSidebarToggle.bind(this);
   }
 
@@ -61,27 +61,27 @@ class Sidebar extends PureComponent {
   render() {
     const { renderSidebarToggle } = this;
     const {
       children,
       onAfterChange,
       onAllTabsMenuClick,
       renderOnlySelected,
       showAllTabsMenu,
-      tabActive,
+      activeTab,
     } = this.props;
 
     return (
       Tabs({
         onAfterChange,
         onAllTabsMenuClick,
         renderOnlySelected,
         renderSidebarToggle,
         showAllTabsMenu,
-        tabActive,
+        activeTab,
       },
         children
       )
     );
   }
 }
 
 module.exports = Sidebar;
--- a/devtools/client/shared/components/tabs/TabBar.js
+++ b/devtools/client/shared/components/tabs/TabBar.js
@@ -325,17 +325,17 @@ class Tabbar extends Component {
 
     return (
       div({className: "devtools-sidebar-tabs"},
         Sidebar({
           onAllTabsMenuClick: this.onAllTabsMenuClick,
           renderOnlySelected: this.props.renderOnlySelected,
           showAllTabsMenu: this.props.showAllTabsMenu,
           sidebarToggleButton: this.props.sidebarToggleButton,
-          tabActive: this.state.activeTab,
+          activeTab: this.state.activeTab,
           onAfterChange: this.onTabChanged,
         },
           tabs
         )
       )
     );
   }
 }
--- a/devtools/client/shared/components/tabs/Tabs.js
+++ b/devtools/client/shared/components/tabs/Tabs.js
@@ -34,17 +34,17 @@ define(function(require, exports, module
   class Tabs extends Component {
     static get propTypes() {
       return {
         className: PropTypes.oneOfType([
           PropTypes.array,
           PropTypes.string,
           PropTypes.object,
         ]),
-        tabActive: PropTypes.number,
+        activeTab: PropTypes.number,
         onMount: PropTypes.func,
         onBeforeChange: PropTypes.func,
         onAfterChange: PropTypes.func,
         children: PropTypes.oneOfType([
           PropTypes.array,
           PropTypes.element,
         ]).isRequired,
         showAllTabsMenu: PropTypes.bool,
@@ -57,27 +57,27 @@ define(function(require, exports, module
         // opposite of the created array, and it's useful if panels content
         // is unpredictable and update frequently.
         renderOnlySelected: PropTypes.bool,
       };
     }
 
     static get defaultProps() {
       return {
-        tabActive: 0,
+        activeTab: 0,
         showAllTabsMenu: false,
         renderOnlySelected: false,
       };
     }
 
     constructor(props) {
       super(props);
 
       this.state = {
-        tabActive: props.tabActive,
+        activeTab: props.activeTab,
 
         // This array is used to store an object containing information on whether a tab
         // at a specified index has already been created (e.g. selected at least once) and
         // the tab id. An example of the object structure is the following:
         // [{ isCreated: true, tabId: "ruleview" }, { isCreated: false, tabId: "foo" }].
         // If the tab at the specified index has already been created, it's rendered even
         // if not currently selected. This is because in some cases we don't want
         // to re-create tab content when it's being unselected/selected.
@@ -108,24 +108,24 @@ define(function(require, exports, module
       // of all-tabs-menu. This menu is displayed when there
       // is not enough h-space to render all tabs.
       // It allows the user to select a tab even if it's hidden.
       if (this.props.showAllTabsMenu) {
         node.addEventListener("overflow", this.onOverflow);
         node.addEventListener("underflow", this.onUnderflow);
       }
 
-      const index = this.state.tabActive;
+      const index = this.state.activeTab;
       if (this.props.onMount) {
         this.props.onMount(index);
       }
     }
 
     componentWillReceiveProps(nextProps) {
-      let { children, tabActive } = nextProps;
+      let { children, activeTab } = nextProps;
       const panels = children.filter(panel => panel);
       let created = [...this.state.created];
 
       // If the children props has changed due to an addition or removal of a tab,
       // update the state's created array with the latest tab ids and whether or not
       // the tab is already created.
       if (this.state.created.length != panels.length) {
         created = panels.map(panel => {
@@ -138,28 +138,28 @@ define(function(require, exports, module
 
           return {
             isCreated,
             tabId,
           };
         });
       }
 
-      // Check type of 'tabActive' props to see if it's valid (it's 0-based index).
-      if (typeof tabActive === "number") {
+      // Check type of 'activeTab' props to see if it's valid (it's 0-based index).
+      if (typeof activeTab === "number") {
         // Reset to index 0 if index overflows the range of panel array
-        tabActive = (tabActive < panels.length && tabActive >= 0) ?
-          tabActive : 0;
+        activeTab = (activeTab < panels.length && activeTab >= 0) ?
+          activeTab : 0;
 
-        created[tabActive] = Object.assign({}, created[tabActive], {
+        created[activeTab] = Object.assign({}, created[activeTab], {
           isCreated: true,
         });
 
         this.setState({
-          tabActive,
+          activeTab,
         });
       }
 
       this.setState({
         created,
       });
     }
 
@@ -192,30 +192,30 @@ define(function(require, exports, module
     }
 
     onKeyDown(event) {
       // Bail out if the focus isn't on a tab.
       if (!event.target.closest(".tabs-menu-item")) {
         return;
       }
 
-      let tabActive = this.state.tabActive;
+      let activeTab = this.state.activeTab;
       const tabCount = this.props.children.length;
 
       switch (event.code) {
         case "ArrowRight":
-          tabActive = Math.min(tabCount - 1, tabActive + 1);
+          activeTab = Math.min(tabCount - 1, activeTab + 1);
           break;
         case "ArrowLeft":
-          tabActive = Math.max(0, tabActive - 1);
+          activeTab = Math.max(0, activeTab - 1);
           break;
       }
 
-      if (this.state.tabActive != tabActive) {
-        this.setActive(tabActive);
+      if (this.state.activeTab != activeTab) {
+        this.setActive(activeTab);
       }
     }
 
     onClickTab(index, event) {
       this.setActive(index);
 
       if (event) {
         event.preventDefault();
@@ -237,17 +237,17 @@ define(function(require, exports, module
 
       const created = [...this.state.created];
       created[index] = Object.assign({}, created[index], {
         isCreated: true,
       });
 
       const newState = Object.assign({}, this.state, {
         created,
-        tabActive: index,
+        activeTab: index,
       });
 
       this.setState(newState, () => {
         // Properly set focus on selected tab.
         const selectedTab = this.tabsEl.current.querySelector(".is-active > a");
         if (selectedTab) {
           selectedTab.focus();
         }
@@ -277,17 +277,17 @@ define(function(require, exports, module
             id,
             className: tabClassName,
             title,
             badge,
             showBadge,
           } = tab.props;
 
           const ref = "tab-menu-" + index;
-          const isTabSelected = this.state.tabActive === index;
+          const isTabSelected = this.state.activeTab === index;
 
           const className = [
             "tabs-menu-item",
             tabClassName,
             isTabSelected ? "is-active" : "",
           ].join(" ");
 
           // Set tabindex to -1 (except the selected tab) so, it's focusable,
@@ -352,17 +352,17 @@ define(function(require, exports, module
       if (!children) {
         throw new Error("There must be at least one Tab");
       }
 
       if (!Array.isArray(children)) {
         children = [children];
       }
 
-      const selectedIndex = this.state.tabActive;
+      const selectedIndex = this.state.activeTab;
 
       const panels = children
         .map((tab) => typeof tab === "function" ? tab() : tab)
         .filter((tab) => tab)
         .map((tab, index) => {
           const selected = selectedIndex === index;
           if (renderOnlySelected && !selected) {
             return null;
--- a/devtools/client/shared/test/browser.ini
+++ b/devtools/client/shared/test/browser.ini
@@ -9,18 +9,16 @@ support-files =
   code_WorkerTargetActor.attach-worker1.js
   code_WorkerTargetActor.attach-worker2.js
   code_WorkerTargetActor.attachThread-worker.js
   code_frame-script.js
   doc_cubic-bezier-01.html
   doc_cubic-bezier-02.html
   doc_empty-tab-01.html
   doc_empty-tab-02.html
-  doc_event-listeners-01.html
-  doc_event-listeners-03.html
   doc_filter-editor-01.html
   doc_html_tooltip-02.xul
   doc_html_tooltip-03.xul
   doc_html_tooltip-04.xul
   doc_html_tooltip-05.xul
   doc_html_tooltip.xul
   doc_html_tooltip_arrow-01.xul
   doc_html_tooltip_arrow-02.xul
@@ -74,24 +72,16 @@ support-files =
 [browser_cubic-bezier-03.js]
 [browser_cubic-bezier-04.js]
 [browser_cubic-bezier-05.js]
 [browser_cubic-bezier-06.js]
 [browser_cubic-bezier-07.js]
 tags = addons
 [browser_dbg_debugger-statement.js]
 skip-if = e10s && debug
-[browser_dbg_event-listeners-01.js]
-skip-if = e10s && debug
-[browser_dbg_event-listeners-02.js]
-skip-if = e10s && debug
-[browser_dbg_event-listeners-03.js]
-skip-if = e10s && debug
-[browser_dbg_globalactor.js]
-skip-if = e10s
 [browser_dbg_listworkers.js]
 [browser_filter-editor-01.js]
 [browser_filter-editor-02.js]
 [browser_filter-editor-03.js]
 [browser_filter-editor-04.js]
 [browser_filter-editor-05.js]
 [browser_filter-editor-06.js]
 [browser_filter-editor-07.js]
@@ -261,9 +251,9 @@ skip-if = true # bug 1368569
 skip-if = e10s && debug
 [browser_dbg_worker-console-03.js]
 skip-if = debug # bug 1334683
 [browser_dbg_worker-console-04.js]
 skip-if = e10s && debug
 [browser_dbg_WorkerTargetActor.attach.js]
 skip-if = e10s && debug
 [browser_dbg_worker-window.js]
-skip-if = (e10s && debug) || true # Bug 1486974
\ No newline at end of file
+skip-if = (e10s && debug) || true # Bug 1486974
deleted file mode 100644
--- a/devtools/client/shared/test/browser_dbg_event-listeners-01.js
+++ /dev/null
@@ -1,130 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-/**
- * Tests that the eventListeners request works.
- */
-
-// Import helpers for the workers
-/* import-globals-from helper_workers.js */
-Services.scriptloader.loadSubScript(
-  "chrome://mochitests/content/browser/devtools/client/shared/test/helper_workers.js",
-  this);
-
-const TAB_URL = TEST_URI_ROOT + "doc_event-listeners-01.html";
-
-add_task(async function() {
-  const tab = await addTab(TAB_URL);
-  const { client, threadClient } = await attachThreadActorForTab(tab);
-
-  await pauseDebuggee(tab, client, threadClient);
-  await testEventListeners(client, threadClient);
-});
-
-function pauseDebuggee(tab, client, threadClient) {
-  const deferred = getDeferredPromise().defer();
-
-  client.addOneTimeListener("paused", (event, packet) => {
-    is(packet.type, "paused",
-      "We should now be paused.");
-    is(packet.why.type, "debuggerStatement",
-      "The debugger statement was hit.");
-
-    deferred.resolve(threadClient);
-  });
-
-  generateMouseClickInTab(tab, "content.document.querySelector('button')");
-
-  return deferred.promise;
-}
-
-async function testEventListeners(client, threadClient) {
-  const packet = await threadClient.eventListeners();
-
-  if (packet.error) {
-    const msg = "Error getting event listeners: " + packet.message;
-    Assert.ok(false, msg);
-    return;
-  }
-
-  is(packet.listeners.length, 3, "Found all event listeners.");
-
-  const listeners = await getDeferredPromise().all(packet.listeners.map(listener => {
-    const lDeferred = getDeferredPromise().defer();
-    threadClient.pauseGrip(listener.function).getDefinitionSite(response => {
-      if (response.error) {
-        const msg = "Error getting function definition site: " + response.message;
-        ok(false, msg);
-        lDeferred.reject(msg);
-        return;
-      }
-      listener.function.url = response.source.url;
-      lDeferred.resolve(listener);
-    });
-    return lDeferred.promise;
-  }));
-
-  const types = [];
-
-  for (const l of listeners) {
-    info("Listener for the " + l.type + " event.");
-    const node = l.node;
-    ok(node, "There is a node property.");
-    ok(node.object, "There is a node object property.");
-    if (node.selector != "window") {
-      const nodeCount =
-        await ContentTask.spawn(gBrowser.selectedBrowser, node.selector,
-          async (selector) => {
-            return content.document.querySelectorAll(selector).length;
-          });
-      Assert.equal(nodeCount, 1, "The node property is a unique CSS selector.");
-    } else {
-      Assert.ok(true, "The node property is a unique CSS selector.");
-    }
-
-    const func = l.function;
-    ok(func, "There is a function property.");
-    is(func.type, "object", "The function form is of type 'object'.");
-    is(func.class, "Function", "The function form is of class 'Function'.");
-
-    // The onchange handler is an inline string that doesn't have
-    // a URL because it's basically eval'ed
-    if (l.type !== "change") {
-      is(func.url, TAB_URL, "The function url is correct.");
-    }
-
-    is(l.allowsUntrusted, true,
-      "'allowsUntrusted' property has the right value.");
-    is(l.inSystemEventGroup, false,
-      "'inSystemEventGroup' property has the right value.");
-
-    types.push(l.type);
-
-    if (l.type == "keyup") {
-      is(l.capturing, true,
-        "Capturing property has the right value.");
-      is(l.isEventHandler, false,
-        "'isEventHandler' property has the right value.");
-    } else if (l.type == "load") {
-      is(l.capturing, false,
-        "Capturing property has the right value.");
-      is(l.isEventHandler, false,
-        "'isEventHandler' property has the right value.");
-    } else {
-      is(l.capturing, false,
-        "Capturing property has the right value.");
-      is(l.isEventHandler, true,
-        "'isEventHandler' property has the right value.");
-    }
-  }
-
-  Assert.ok(types.includes("click"), "Found the click handler.");
-  Assert.ok(types.includes("change"), "Found the change handler.");
-  Assert.ok(types.includes("keyup"), "Found the keyup handler.");
-
-  await threadClient.resume();
-}
deleted file mode 100644
--- a/devtools/client/shared/test/browser_dbg_event-listeners-02.js
+++ /dev/null
@@ -1,109 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-/**
- * Tests that the eventListeners request works when bound functions are used as
- * event listeners.
- */
-
-// Import helpers for the workers
-/* import-globals-from helper_workers.js */
-Services.scriptloader.loadSubScript(
-  "chrome://mochitests/content/browser/devtools/client/shared/test/helper_workers.js",
-  this);
-
-const TAB_URL = TEST_URI_ROOT + "doc_event-listeners-03.html";
-
-add_task(async function() {
-  const tab = await addTab(TAB_URL);
-  const { client, threadClient } = await attachThreadActorForTab(tab);
-
-  await pauseDebuggee(tab, client, threadClient);
-  await testEventListeners(client, threadClient);
-});
-
-function pauseDebuggee(tab, client, threadClient) {
-  const deferred = getDeferredPromise().defer();
-
-  client.addOneTimeListener("paused", (event, packet) => {
-    is(packet.type, "paused",
-      "We should now be paused.");
-    is(packet.why.type, "debuggerStatement",
-      "The debugger statement was hit.");
-
-    deferred.resolve(threadClient);
-  });
-
-  generateMouseClickInTab(tab, "content.document.querySelector('button')");
-
-  return deferred.promise;
-}
-
-async function testEventListeners(client, threadClient) {
-  const packet = await threadClient.eventListeners();
-
-  if (packet.error) {
-    const msg = "Error getting event listeners: " + packet.message;
-    ok(false, msg);
-    return;
-  }
-
-  is(packet.listeners.length, 3,
-    "Found all event listeners.");
-
-  const listeners = await getDeferredPromise().all(packet.listeners.map(listener => {
-    const lDeferred = getDeferredPromise().defer();
-    threadClient.pauseGrip(listener.function).getDefinitionSite(response => {
-      if (response.error) {
-        const msg = "Error getting function definition site: " + response.message;
-        ok(false, msg);
-        lDeferred.reject(msg);
-        return;
-      }
-      listener.function.url = response.source.url;
-      lDeferred.resolve(listener);
-    });
-    return lDeferred.promise;
-  }));
-
-  Assert.equal(listeners.length, 3, "Found three event listeners.");
-
-  for (const l of listeners) {
-    const node = l.node;
-    ok(node, "There is a node property.");
-    ok(node.object, "There is a node object property.");
-
-    if (node.selector != "window") {
-      const nodeCount =
-        await ContentTask.spawn(gBrowser.selectedBrowser, node.selector,
-          async (selector) => {
-            return content.document.querySelectorAll(selector).length;
-          });
-      Assert.equal(nodeCount, 1, "The node property is a unique CSS selector.");
-    } else {
-      Assert.ok(true, "The node property is a unique CSS selector.");
-    }
-
-    const func = l.function;
-    ok(func, "There is a function property.");
-    is(func.type, "object", "The function form is of type 'object'.");
-    is(func.class, "Function", "The function form is of class 'Function'.");
-    is(func.url, TAB_URL, "The function url is correct.");
-
-    is(l.type, "click", "This is a click event listener.");
-    is(l.allowsUntrusted, true,
-      "'allowsUntrusted' property has the right value.");
-    is(l.inSystemEventGroup, false,
-      "'inSystemEventGroup' property has the right value.");
-    is(l.isEventHandler, false,
-      "'isEventHandler' property has the right value.");
-    is(l.capturing, false,
-      "Capturing property has the right value.");
-  }
-
-  await threadClient.resume();
-}
deleted file mode 100644
--- a/devtools/client/shared/test/browser_dbg_event-listeners-03.js
+++ /dev/null
@@ -1,65 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-/**
- * Tests that the eventListeners request works when there are event handlers
- * that the debugger cannot unwrap.
- */
-
-// Import helpers for the workers
-/* import-globals-from helper_workers.js */
-Services.scriptloader.loadSubScript(
-  "chrome://mochitests/content/browser/devtools/client/shared/test/helper_workers.js",
-  this);
-
-const TAB_URL = TEST_URI_ROOT + "doc_native-event-handler.html";
-
-add_task(async () => {
-  const tab = await addTab(TAB_URL);
-  const { client, threadClient } = await attachThreadActorForTab(tab);
-
-  await pauseDebuggee(client, tab, threadClient);
-  await testEventListeners(threadClient);
-});
-
-function pauseDebuggee(client, tab, threadClient) {
-  const deferred = getDeferredPromise().defer();
-
-  client.addOneTimeListener("paused", (event, packet) => {
-    is(packet.type, "paused",
-      "We should now be paused.");
-    is(packet.why.type, "debuggerStatement",
-      "The debugger statement was hit.");
-
-    deferred.resolve(threadClient);
-  });
-
-  generateMouseClickInTab(tab, "content.document.querySelector('button')");
-
-  return deferred.promise;
-}
-
-function testEventListeners(threadClient) {
-  const deferred = getDeferredPromise().defer();
-
-  threadClient.eventListeners(packet => {
-    if (packet.error) {
-      const msg = "Error getting event listeners: " + packet.message;
-      ok(false, msg);
-      deferred.reject(msg);
-      return;
-    }
-
-    // There are 2 event listeners in the page: button.onclick, window.onload.
-    // The video element controls listeners are skipped — they cannot be
-    // unwrapped but they shouldn't cause us to throw either.
-    is(packet.listeners.length, 2, "Found all event listeners.");
-    threadClient.resume(deferred.resolve);
-  });
-
-  return deferred.promise;
-}
--- a/devtools/client/themes/toolbars.css
+++ b/devtools/client/themes/toolbars.css
@@ -187,14 +187,15 @@ html[dir="rtl"] .devtools-dropdown-butto
 
 .devtools-dropdown-button:not(:hover) {
   background-color: transparent;
 }
 
 /* Style for title holder inside the dropdown menu button */
 .devtools-dropdown-button .title {
   display: inline-block;
+  width: 100%;
   overflow: hidden;
   padding-top: 0.15em;
   text-align: center;
   text-overflow: ellipsis;
   white-space: nowrap;
 }
--- a/devtools/client/themes/webconsole.css
+++ b/devtools/client/themes/webconsole.css
@@ -970,16 +970,21 @@ body {
   fill: var(--theme-icon-dimmed-color);
 }
 
 .webconsole-app .tree .arrow.expanded,
 .webconsole-app .object-inspector .tree-node .arrow.expanded {
   transform: rotate(0deg);
 }
 
+.webconsole-app .tree.focused .arrow,
+.webconsole-app .object-inspector .tree-node.focused .arrow {
+  fill: currentColor
+}
+
 /* Sidebar */
 .sidebar {
   display: flex;
   grid-row: 1 / -1;
   grid-column: -1 / -2;
   background-color: var(--theme-sidebar-background);
   border-inline-start: 1px solid var(--theme-splitter-color);
 }
--- a/devtools/client/webconsole/components/ConsoleOutput.js
+++ b/devtools/client/webconsole/components/ConsoleOutput.js
@@ -194,16 +194,17 @@ class ConsoleOutput extends Component {
         getMessage: () => messages.get(messageId),
         isPaused: !!pausedMessage && pausedMessage.id == messageId,
         maybeScrollToBottom: this.maybeScrollToBottom,
       }));
 
     return (
       dom.div({
         className: "webconsole-output",
+        role: "main",
         onContextMenu: this.onContextMenu,
         ref: node => {
           this.outputNode = node;
         },
       }, messageNodes
       )
     );
   }
--- a/devtools/server/actors/thread.js
+++ b/devtools/server/actors/thread.js
@@ -14,17 +14,16 @@ const { longStringGrip } = require("devt
 const { ActorClassWithSpec, Actor } = require("devtools/shared/protocol");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 const { assert, dumpn } = DevToolsUtils;
 const { threadSpec } = require("devtools/shared/specs/script");
 const {
   getAvailableEventBreakpoints,
 } = require("devtools/server/actors/utils/event-breakpoints");
 
-loader.lazyRequireGetter(this, "findCssSelector", "devtools/shared/inspector/css-logic", true);
 loader.lazyRequireGetter(this, "EnvironmentActor", "devtools/server/actors/environment", true);
 loader.lazyRequireGetter(this, "BreakpointActorMap", "devtools/server/actors/utils/breakpoint-actor-map", true);
 loader.lazyRequireGetter(this, "PauseScopedObjectActor", "devtools/server/actors/pause-scoped", true);
 loader.lazyRequireGetter(this, "EventLoopStack", "devtools/server/actors/utils/event-loop", true);
 loader.lazyRequireGetter(this, "FrameActor", "devtools/server/actors/frame", true);
 loader.lazyRequireGetter(this, "throttle", "devtools/shared/throttle", true);
 
 /**
@@ -1226,95 +1225,16 @@ const ThreadActor = ActorClassWithSpec(t
       return null;
     } catch (e) {
       reportError(e);
       return { error: "notInterrupted", message: e.toString() };
     }
   },
 
   /**
-   * Handle a protocol request to retrieve all the event listeners on the page.
-   */
-  onEventListeners: function(request) {
-    // This request is only supported in content debugging.
-    if (!this.global) {
-      return {
-        error: "notImplemented",
-        message: "eventListeners request is only supported in content debugging",
-      };
-    }
-
-    let nodes = this.global.document.getElementsByTagName("*");
-    nodes = [this.global].concat([].slice.call(nodes));
-    const listeners = [];
-
-    for (const node of nodes) {
-      const handlers = Services.els.getListenerInfoFor(node);
-
-      for (const handler of handlers) {
-        // Create a form object for serializing the listener via the protocol.
-        const listenerForm = Object.create(null);
-        const listener = handler.listenerObject;
-        // Native event listeners don't provide any listenerObject or type and
-        // are not that useful to a JS debugger.
-        if (!listener || !handler.type) {
-          continue;
-        }
-
-        // There will be no tagName if the event listener is set on the window.
-        const selector = node.tagName ? findCssSelector(node) : "window";
-        const nodeDO = this.globalDebugObject.makeDebuggeeValue(node);
-        listenerForm.node = {
-          selector: selector,
-          object: createValueGrip(nodeDO, this._pausePool, this.objectGrip),
-        };
-        listenerForm.type = handler.type;
-        listenerForm.capturing = handler.capturing;
-        listenerForm.allowsUntrusted = handler.allowsUntrusted;
-        listenerForm.inSystemEventGroup = handler.inSystemEventGroup;
-        const handlerName = "on" + listenerForm.type;
-        listenerForm.isEventHandler = false;
-        if (typeof node.hasAttribute !== "undefined") {
-          listenerForm.isEventHandler = !!node.hasAttribute(handlerName);
-        }
-        if (node[handlerName]) {
-          listenerForm.isEventHandler = !!node[handlerName];
-        }
-        // Get the Debugger.Object for the listener object.
-        let listenerDO = this.globalDebugObject.makeDebuggeeValue(listener);
-        // If the listener is an object with a 'handleEvent' method, use that.
-        if (listenerDO.class === "Object" || /^XUL\w*Element$/.test(listenerDO.class)) {
-          // For some events we don't have permission to access the
-          // 'handleEvent' property when running in content scope.
-          if (!listenerDO.unwrap()) {
-            continue;
-          }
-          let heDesc;
-          while (!heDesc && listenerDO) {
-            heDesc = listenerDO.getOwnPropertyDescriptor("handleEvent");
-            listenerDO = listenerDO.proto;
-          }
-          if (heDesc && heDesc.value) {
-            listenerDO = heDesc.value;
-          }
-        }
-        // When the listener is a bound function, we are actually interested in
-        // the target function.
-        while (listenerDO.isBoundFunction) {
-          listenerDO = listenerDO.boundTargetFunction;
-        }
-        listenerForm.function = createValueGrip(listenerDO, this._pausePool,
-          this.objectGrip);
-        listeners.push(listenerForm);
-      }
-    }
-    return { listeners: listeners };
-  },
-
-  /**
    * Return the Debug.Frame for a frame mentioned by the protocol.
    */
   _requestFrame: function(frameID) {
     if (!frameID) {
       return this.youngestFrame;
     }
 
     if (this._framePool.has(frameID)) {
@@ -1850,17 +1770,16 @@ const ThreadActor = ActorClassWithSpec(t
 Object.assign(ThreadActor.prototype.requestTypes, {
   "attach": ThreadActor.prototype.onAttach,
   "detach": ThreadActor.prototype.onDetach,
   "reconfigure": ThreadActor.prototype.onReconfigure,
   "resume": ThreadActor.prototype.onResume,
   "clientEvaluate": ThreadActor.prototype.onClientEvaluate,
   "frames": ThreadActor.prototype.onFrames,
   "interrupt": ThreadActor.prototype.onInterrupt,
-  "eventListeners": ThreadActor.prototype.onEventListeners,
   "releaseMany": ThreadActor.prototype.onReleaseMany,
   "sources": ThreadActor.prototype.onSources,
   "threadGrips": ThreadActor.prototype.onThreadGrips,
   "skipBreakpoints": ThreadActor.prototype.onSkipBreakpoints,
 });
 
 exports.ThreadActor = ThreadActor;
 
--- a/devtools/shared/client/thread-client.js
+++ b/devtools/shared/client/thread-client.js
@@ -365,26 +365,16 @@ ThreadClient.prototype = {
    *        An array with actor IDs to promote.
    */
   threadGrips: DebuggerClient.requester({
     type: "threadGrips",
     actors: arg(0),
   }),
 
   /**
-   * Return the event listeners defined on the page.
-   *
-   * @param onResponse Function
-   *        Called with the thread's response.
-   */
-  eventListeners: DebuggerClient.requester({
-    type: "eventListeners",
-  }),
-
-  /**
    * Request the loaded sources for the current thread.
    *
    * @param onResponse Function
    *        Called with the thread's response.
    */
   getSources: DebuggerClient.requester({
     type: "sources",
   }),
--- a/devtools/shared/specs/targets/addon.js
+++ b/devtools/shared/specs/targets/addon.js
@@ -31,16 +31,16 @@ const addonTargetSpec = generateActorSpe
     },
   },
 
   events: {
     // The thread actor is no longer emitting newSource event in the name of the target
     // actor (bug 1269919), but as we may still connect to older servers which still do,
     // we have to keep it being mentioned here. Otherwise the event is considered as a
     // response to a request and confuses the packet ordering.
-    // We can remove that once FF57 is no longer supported.
+    // We can remove that once FF66 is no longer supported.
     newSource: {
       type: "newSource",
     },
   },
 });
 
 exports.addonTargetSpec = addonTargetSpec;
--- a/devtools/shared/specs/targets/browsing-context.js
+++ b/devtools/shared/specs/targets/browsing-context.js
@@ -136,17 +136,17 @@ const browsingContextTargetSpecPrototype
     workerListChanged: {
       type: "workerListChanged",
     },
 
     // The thread actor is no longer emitting newSource event in the name of the target
     // actor (bug 1269919), but as we may still connect to older servers which still do,
     // we have to keep it being mentioned here. Otherwise the event is considered as a
     // response to a request and confuses the packet ordering.
-    // We can remove that once FF57 is no longer supported.
+    // We can remove that once FF66 is no longer supported.
     newSource: {
       type: "newSource",
     },
   },
 };
 
 const browsingContextTargetSpec = generateActorSpec(browsingContextTargetSpecPrototype);
 
--- a/devtools/shared/specs/targets/content-process.js
+++ b/devtools/shared/specs/targets/content-process.js
@@ -24,16 +24,16 @@ const contentProcessTargetSpec = generat
     workerListChanged: {
       type: "workerListChanged",
     },
 
     // The thread actor is no longer emitting newSource event in the name of the target
     // actor (bug 1269919), but as we may still connect to older servers which still do,
     // we have to keep it being mentioned here. Otherwise the event is considered as a
     // response to a request and confuses the packet ordering.
-    // We can remove that once FF57 is no longer supported.
+    // We can remove that once FF66 is no longer supported.
     newSource: {
       type: "newSource",
     },
   },
 });
 
 exports.contentProcessTargetSpec = contentProcessTargetSpec;
--- a/devtools/shared/specs/targets/worker.js
+++ b/devtools/shared/specs/targets/worker.js
@@ -36,16 +36,16 @@ const workerTargetSpec = generateActorSp
     "worker-close": {
       type: "close",
     },
 
     // The thread actor is no longer emitting newSource event in the name of the target
     // actor (bug 1269919), but as we may still connect to older servers which still do,
     // we have to keep it being mentioned here. Otherwise the event is considered as a
     // response to a request and confuses the packet ordering.
-    // We can remove that once FF57 is no longer supported.
+    // We can remove that once FF66 is no longer supported.
     newSource: {
       type: "newSource",
     },
   },
 });
 
 exports.workerTargetSpec = workerTargetSpec;
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -660,38 +660,16 @@ void VibrateWindowListener::RemoveListen
   }
   NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange");
   target->RemoveSystemEventListener(visibilitychange, this,
                                     true /* use capture */);
 }
 
 }  // namespace
 
-void Navigator::AddIdleObserver(MozIdleObserver& aIdleObserver,
-                                ErrorResult& aRv) {
-  if (!mWindow) {
-    aRv.Throw(NS_ERROR_UNEXPECTED);
-    return;
-  }
-  if (NS_FAILED(mWindow->RegisterIdleObserver(aIdleObserver))) {
-    NS_WARNING("Failed to add idle observer.");
-  }
-}
-
-void Navigator::RemoveIdleObserver(MozIdleObserver& aIdleObserver,
-                                   ErrorResult& aRv) {
-  if (!mWindow) {
-    aRv.Throw(NS_ERROR_UNEXPECTED);
-    return;
-  }
-  if (NS_FAILED(mWindow->UnregisterIdleObserver(aIdleObserver))) {
-    NS_WARNING("Failed to remove idle observer.");
-  }
-}
-
 void Navigator::SetVibrationPermission(bool aPermitted, bool aPersistent) {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsTArray<uint32_t> pattern;
   pattern.SwapElements(mRequestedVibrationPattern);
 
   if (!mWindow) {
     return;
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -52,17 +52,16 @@ namespace dom {
 class Permissions;
 
 namespace battery {
 class BatteryManager;
 }  // namespace battery
 
 class Promise;
 
-class MozIdleObserver;
 class Gamepad;
 class GamepadServiceTest;
 class NavigatorUserMediaSuccessCallback;
 class NavigatorUserMediaErrorCallback;
 class MozGetUserMediaDevicesSuccessCallback;
 
 struct MIDIOptions;
 
@@ -153,18 +152,16 @@ class Navigator final : public nsISuppor
   void GetVendor(nsAString& aVendor);
   void GetProductSub(nsAString& aProductSub);
   bool CookieEnabled();
   void GetBuildID(nsAString& aBuildID, CallerType aCallerType,
                   ErrorResult& aRv) const;
   bool JavaEnabled() { return false; }
   uint64_t HardwareConcurrency();
   bool TaintEnabled() { return false; }
-  void AddIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv);
-  void RemoveIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv);
 
   already_AddRefed<LegacyMozTCPSocket> MozTCPSocket();
   network::Connection* GetConnection(ErrorResult& aRv);
   MediaDevices* GetMediaDevices(ErrorResult& aRv);
 
   void GetGamepads(nsTArray<RefPtr<Gamepad>>& aGamepads, ErrorResult& aRv);
   GamepadServiceTest* RequestGamepadServiceTest();
   already_AddRefed<Promise> GetVRDisplays(ErrorResult& aRv);
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -38,17 +38,16 @@
 #include "mozilla/dom/VisualViewport.h"
 #include "mozilla/dom/WindowProxyHolder.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #if defined(MOZ_WIDGET_ANDROID)
 #  include "mozilla/dom/WindowOrientationObserver.h"
 #endif
 #include "nsDOMOfflineResourceList.h"
 #include "nsError.h"
-#include "nsIIdleService.h"
 #include "nsISizeOfEventTarget.h"
 #include "nsDOMJSUtils.h"
 #include "nsArrayUtils.h"
 #include "nsDOMWindowList.h"
 #include "mozilla/dom/WakeLock.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocumentLoader.h"
@@ -337,28 +336,21 @@ static nsGlobalWindowOuter* GetOuterWind
 // Amount of time allowed between alert/prompt/confirm before enabling
 // the stop dialog checkbox.
 #define DEFAULT_SUCCESSIVE_DIALOG_TIME_LIMIT 3  // 3 sec
 
 // Maximum number of successive dialogs before we prompt users to disable
 // dialogs for this window.
 #define MAX_SUCCESSIVE_DIALOG_COUNT 5
 
-// Idle fuzz time upper limit
-#define MAX_IDLE_FUZZ_TIME_MS 90000
-
-// Min idle notification time in seconds.
-#define MIN_IDLE_NOTIFICATION_TIME_S 1
-
 // Max number of Report objects
 #define MAX_REPORT_RECORDS 100
 
 static LazyLogModule gDOMLeakPRLogInner("DOMLeakInner");
 
-static bool gIdleObserversAPIFuzzTimeDisabled = false;
 static FILE* gDumpFile = nullptr;
 
 nsGlobalWindowInner::InnerWindowByIdTable*
     nsGlobalWindowInner::sInnerWindowsById = nullptr;
 
 bool nsGlobalWindowInner::sDragServiceDisabled = false;
 bool nsGlobalWindowInner::sMouseDown = false;
 
@@ -837,24 +829,18 @@ class PromiseDocumentFlushedResolver fin
 
 //*****************************************************************************
 //***    nsGlobalWindowInner: Object Management
 //*****************************************************************************
 
 nsGlobalWindowInner::nsGlobalWindowInner(nsGlobalWindowOuter* aOuterWindow)
     : nsPIDOMWindowInner(aOuterWindow->AsOuter()),
       mozilla::webgpu::InstanceProvider(this),
-      mIdleFuzzFactor(0),
-      mIdleCallbackIndex(-1),
-      mCurrentlyIdle(false),
-      mAddActiveEventFuzzTime(true),
       mWasOffline(false),
       mHasHadSlowScript(false),
-      mNotifyIdleObserversIdleOnThaw(false),
-      mNotifyIdleObserversActiveOnThaw(false),
       mIsChrome(false),
       mCleanMessageManager(false),
       mNeedsFocus(true),
       mHasFocus(false),
       mShowFocusRingForContent(false),
       mFocusByKeyOccurred(false),
       mDidFireDocElemInserted(false),
       mHasGamepad(false),
@@ -921,19 +907,16 @@ nsGlobalWindowInner::nsGlobalWindowInner
   // We could have failed the first time through trying
   // to create the entropy collector, so we should
   // try to get one until we succeed.
 
   static bool sFirstTime = true;
   if (sFirstTime) {
     sFirstTime = false;
     TimeoutManager::Initialize();
-    Preferences::AddBoolVarCache(&gIdleObserversAPIFuzzTimeDisabled,
-                                 "dom.idle-observers-api.fuzz_time.disabled",
-                                 false);
   }
 
   if (gDumpFile == nullptr) {
     nsAutoCString fname;
     Preferences::GetCString("browser.dom.window.dump.file", fname);
     if (!fname.IsEmpty()) {
       // If this fails to open, Dump() knows to just go to stdout on null.
       gDumpFile = fopen(fname.get(), "wb+");
@@ -1109,23 +1092,16 @@ void nsGlobalWindowInner::FreeInnerObjec
   while (iter.HasMore()) {
     iter.GetNext()->Close();
   }
 
   if (mTimeoutManager) {
     mTimeoutManager->ClearAllTimeouts();
   }
 
-  if (mIdleTimer) {
-    mIdleTimer->Cancel();
-    mIdleTimer = nullptr;
-  }
-
-  mIdleObservers.Clear();
-
   DisableIdleCallbackRequests();
 
   mChromeEventHandler = nullptr;
 
   if (mListenerManager) {
     mListenerManager->Disconnect();
     mListenerManager = nullptr;
   }
@@ -1225,20 +1201,16 @@ void nsGlobalWindowInner::FreeInnerObjec
       }
     }
 
     RefPtr<StorageNotifierService> sns = StorageNotifierService::GetOrCreate();
     if (sns) {
       sns->Unregister(mObserver);
     }
 
-    if (mIdleService) {
-      mIdleService->RemoveIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S);
-    }
-
     Preferences::RemoveObserver(mObserver, "intl.accept_languages");
 
     // Drop its reference to this dying window, in case for some bogus reason
     // the object stays around.
     mObserver->Forget();
   }
 
   mMenubar = nullptr;
@@ -1375,25 +1347,22 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharedWorkers)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplicationCache)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChild)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleRequestExecutor)
   for (IdleRequest* request : tmp->mIdleRequestCallbacks) {
     cb.NoteNativeChild(request, NS_CYCLE_COLLECTION_PARTICIPANT(IdleRequest));
   }
 
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers)
-
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClientSource)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepads)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRDisplays)
 
   // Traverse stuff from nsPIDOMWindow
@@ -1474,18 +1443,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   }
   if (tmp->mIndexedDB) {
     tmp->mIndexedDB->DisconnectFromWindow(tmp);
     NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mTabChild)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mGamepads)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mVRDisplays)
 
   // Unlink stuff from nsPIDOMWindow
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)
@@ -1898,23 +1865,16 @@ void nsGlobalWindowInner::GetEventTarget
       if (ds) {
         sDragServiceDisabled = false;
         ds->Unsuppress();
       }
     }
   }
 
   aVisitor.SetParentTarget(GetParentTarget(), true);
-
-  // Handle 'active' event.
-  if (!mIdleObservers.IsEmpty() && aVisitor.mEvent->IsTrusted() &&
-      (aVisitor.mEvent->HasMouseEventMessage() ||
-       aVisitor.mEvent->HasDragEventMessage())) {
-    mAddActiveEventFuzzTime = false;
-  }
 }
 
 bool nsGlobalWindowInner::DialogsAreBeingAbused() {
   NS_ASSERTION(
       GetScriptableTopInternal() &&
           GetScriptableTopInternal()->GetCurrentInnerWindowInternal() == this,
       "DialogsAreBeingAbused called with invalid window");
 
@@ -4514,189 +4474,16 @@ void nsGlobalWindowInner::FireOfflineSta
     name.AssignLiteral("offline");
   } else {
     name.AssignLiteral("online");
   }
   nsContentUtils::DispatchTrustedEvent(mDoc, static_cast<EventTarget*>(this),
                                        name, CanBubble::eNo, Cancelable::eNo);
 }
 
-class NotifyIdleObserverRunnable : public Runnable {
- public:
-  NotifyIdleObserverRunnable(MozIdleObserver& aIdleObserver, uint32_t aTimeInS,
-                             bool aCallOnidle, nsGlobalWindowInner* aIdleWindow)
-      : mozilla::Runnable("NotifyIdleObserverRunnable"),
-        mIdleObserver(aIdleObserver),
-        mTimeInS(aTimeInS),
-        mIdleWindow(aIdleWindow),
-        mCallOnidle(aCallOnidle) {}
-
-  NS_IMETHOD Run() override {
-    if (mIdleWindow->ContainsIdleObserver(mIdleObserver, mTimeInS)) {
-      if (mCallOnidle) {
-        mIdleObserver->Onidle(IgnoreErrors());
-      } else {
-        mIdleObserver->Onactive(IgnoreErrors());
-      }
-    }
-    return NS_OK;
-  }
-
- private:
-  OwningNonNull<MozIdleObserver> mIdleObserver;
-  uint32_t mTimeInS;
-  RefPtr<nsGlobalWindowInner> mIdleWindow;
-
-  // If false then call on active
-  bool mCallOnidle;
-};
-
-void nsGlobalWindowInner::NotifyIdleObserver(
-    IdleObserverHolder* aIdleObserverHolder, bool aCallOnidle) {
-  MOZ_ASSERT(aIdleObserverHolder);
-  aIdleObserverHolder->mPrevNotificationIdle = aCallOnidle;
-
-  nsCOMPtr<nsIRunnable> caller = new NotifyIdleObserverRunnable(
-      aIdleObserverHolder->mIdleObserver, aIdleObserverHolder->mTimeInS,
-      aCallOnidle, this);
-  if (NS_FAILED(Dispatch(TaskCategory::Other, caller.forget()))) {
-    NS_WARNING("Failed to dispatch thread for idle observer notification.");
-  }
-}
-
-bool nsGlobalWindowInner::ContainsIdleObserver(MozIdleObserver& aIdleObserver,
-                                               uint32_t aTimeInS) {
-  bool found = false;
-  nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
-  while (iter.HasMore()) {
-    IdleObserverHolder& idleObserver = iter.GetNext();
-    if (idleObserver.mIdleObserver.ref() == aIdleObserver &&
-        idleObserver.mTimeInS == aTimeInS) {
-      found = true;
-      break;
-    }
-  }
-  return found;
-}
-
-void IdleActiveTimerCallback(nsITimer* aTimer, void* aClosure) {
-  RefPtr<nsGlobalWindowInner> idleWindow =
-      static_cast<nsGlobalWindowInner*>(aClosure);
-  MOZ_ASSERT(idleWindow, "Idle window has not been instantiated.");
-  idleWindow->HandleIdleActiveEvent();
-}
-
-void IdleObserverTimerCallback(nsITimer* aTimer, void* aClosure) {
-  RefPtr<nsGlobalWindowInner> idleWindow =
-      static_cast<nsGlobalWindowInner*>(aClosure);
-  MOZ_ASSERT(idleWindow, "Idle window has not been instantiated.");
-  idleWindow->HandleIdleObserverCallback();
-}
-
-void nsGlobalWindowInner::HandleIdleObserverCallback() {
-  MOZ_ASSERT(
-      static_cast<uint32_t>(mIdleCallbackIndex) < mIdleObservers.Length(),
-      "Idle callback index exceeds array bounds!");
-  IdleObserverHolder& idleObserver =
-      mIdleObservers.ElementAt(mIdleCallbackIndex);
-  NotifyIdleObserver(&idleObserver, true);
-  mIdleCallbackIndex++;
-  if (NS_FAILED(ScheduleNextIdleObserverCallback())) {
-    NS_WARNING("Failed to set next idle observer callback.");
-  }
-}
-
-nsresult nsGlobalWindowInner::ScheduleNextIdleObserverCallback() {
-  MOZ_ASSERT(mIdleService, "No idle service!");
-
-  if (mIdleCallbackIndex < 0 ||
-      static_cast<uint32_t>(mIdleCallbackIndex) >= mIdleObservers.Length()) {
-    return NS_OK;
-  }
-
-  IdleObserverHolder& idleObserver =
-      mIdleObservers.ElementAt(mIdleCallbackIndex);
-
-  uint32_t userIdleTimeMS = 0;
-  nsresult rv = mIdleService->GetIdleTime(&userIdleTimeMS);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  uint32_t callbackTimeMS = 0;
-  if (idleObserver.mTimeInS * 1000 + mIdleFuzzFactor > userIdleTimeMS) {
-    callbackTimeMS =
-        idleObserver.mTimeInS * 1000 - userIdleTimeMS + mIdleFuzzFactor;
-  }
-
-  mIdleTimer->Cancel();
-  rv = mIdleTimer->InitWithNamedFuncCallback(
-      IdleObserverTimerCallback, this, callbackTimeMS, nsITimer::TYPE_ONE_SHOT,
-      "nsGlobalWindowInner::ScheduleNextIdleObserverCallback");
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
-uint32_t nsGlobalWindowInner::GetFuzzTimeMS() {
-  if (gIdleObserversAPIFuzzTimeDisabled) {
-    return 0;
-  }
-
-  uint32_t randNum = MAX_IDLE_FUZZ_TIME_MS;
-  size_t nbytes = PR_GetRandomNoise(&randNum, sizeof(randNum));
-  if (nbytes != sizeof(randNum)) {
-    NS_WARNING("PR_GetRandomNoise(...) Not implemented or no available noise!");
-    return MAX_IDLE_FUZZ_TIME_MS;
-  }
-
-  if (randNum > MAX_IDLE_FUZZ_TIME_MS) {
-    randNum %= MAX_IDLE_FUZZ_TIME_MS;
-  }
-
-  return randNum;
-}
-
-nsresult nsGlobalWindowInner::ScheduleActiveTimerCallback() {
-  if (!mAddActiveEventFuzzTime) {
-    return HandleIdleActiveEvent();
-  }
-
-  MOZ_ASSERT(mIdleTimer);
-  mIdleTimer->Cancel();
-
-  uint32_t fuzzFactorInMS = GetFuzzTimeMS();
-  nsresult rv = mIdleTimer->InitWithNamedFuncCallback(
-      IdleActiveTimerCallback, this, fuzzFactorInMS, nsITimer::TYPE_ONE_SHOT,
-      "nsGlobalWindowInner::ScheduleActiveTimerCallback");
-  NS_ENSURE_SUCCESS(rv, rv);
-  return NS_OK;
-}
-
-nsresult nsGlobalWindowInner::HandleIdleActiveEvent() {
-  if (mCurrentlyIdle) {
-    mIdleCallbackIndex = 0;
-    mIdleFuzzFactor = GetFuzzTimeMS();
-    nsresult rv = ScheduleNextIdleObserverCallback();
-    NS_ENSURE_SUCCESS(rv, rv);
-    return NS_OK;
-  }
-
-  mIdleCallbackIndex = -1;
-  MOZ_ASSERT(mIdleTimer);
-  mIdleTimer->Cancel();
-  nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
-  while (iter.HasMore()) {
-    IdleObserverHolder& idleObserver = iter.GetNext();
-    if (idleObserver.mPrevNotificationIdle) {
-      NotifyIdleObserver(&idleObserver, false);
-    }
-  }
-
-  return NS_OK;
-}
-
 nsGlobalWindowInner::SlowScriptResponse
 nsGlobalWindowInner::ShowSlowScriptDialog(const nsString& aAddonId) {
   nsresult rv;
   AutoJSContext cx;
 
   if (Preferences::GetBool("dom.always_stop_slow_scripts")) {
     return KillSlowScript;
   }
@@ -4915,190 +4702,16 @@ nsGlobalWindowInner::ShowSlowScriptDialo
   }
 
   JS_ClearPendingException(cx);
 
   if (checkboxValue && isAddonScript) return KillScriptGlobal;
   return KillSlowScript;
 }
 
-uint32_t nsGlobalWindowInner::FindInsertionIndex(
-    IdleObserverHolder* aIdleObserver) {
-  MOZ_ASSERT(aIdleObserver, "Idle observer not instantiated.");
-
-  uint32_t i = 0;
-  nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
-  while (iter.HasMore()) {
-    IdleObserverHolder& idleObserver = iter.GetNext();
-    if (idleObserver.mTimeInS > aIdleObserver->mTimeInS) {
-      break;
-    }
-    i++;
-    MOZ_ASSERT(i <= mIdleObservers.Length(),
-               "Array index out of bounds error.");
-  }
-
-  return i;
-}
-
-nsresult nsGlobalWindowInner::RegisterIdleObserver(
-    MozIdleObserver& aIdleObserver) {
-  nsresult rv;
-  if (mIdleObservers.IsEmpty()) {
-    mIdleService = do_GetService("@mozilla.org/widget/idleservice;1", &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = mIdleService->AddIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (!mIdleTimer) {
-      mIdleTimer = NS_NewTimer();
-      NS_ENSURE_TRUE(mIdleTimer, NS_ERROR_OUT_OF_MEMORY);
-    } else {
-      mIdleTimer->Cancel();
-    }
-  }
-
-  MOZ_ASSERT(mIdleService);
-  MOZ_ASSERT(mIdleTimer);
-
-  IdleObserverHolder tmpIdleObserver;
-  tmpIdleObserver.mIdleObserver = aIdleObserver;
-  ErrorResult err;
-  tmpIdleObserver.mTimeInS = aIdleObserver.GetTime(err);
-  if (NS_WARN_IF(err.Failed())) {
-    return err.StealNSResult();
-  }
-  NS_ENSURE_ARG_MAX(tmpIdleObserver.mTimeInS, UINT32_MAX / 1000);
-  NS_ENSURE_ARG_MIN(tmpIdleObserver.mTimeInS, MIN_IDLE_NOTIFICATION_TIME_S);
-
-  uint32_t insertAtIndex = FindInsertionIndex(&tmpIdleObserver);
-  if (insertAtIndex == mIdleObservers.Length()) {
-    mIdleObservers.AppendElement(tmpIdleObserver);
-  } else {
-    mIdleObservers.InsertElementAt(insertAtIndex, tmpIdleObserver);
-  }
-
-  bool userIsIdle = false;
-  rv = nsContentUtils::IsUserIdle(MIN_IDLE_NOTIFICATION_TIME_S, &userIsIdle);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Special case. First idle observer added to empty list while the user is
-  // idle. Haven't received 'idle' topic notification from slow idle service
-  // yet. Need to wait for the idle notification and then notify idle observers
-  // in the list.
-  if (userIsIdle && mIdleCallbackIndex == -1) {
-    return NS_OK;
-  }
-
-  if (!mCurrentlyIdle) {
-    return NS_OK;
-  }
-
-  MOZ_ASSERT(mIdleCallbackIndex >= 0);
-
-  if (static_cast<int32_t>(insertAtIndex) < mIdleCallbackIndex) {
-    IdleObserverHolder& idleObserver = mIdleObservers.ElementAt(insertAtIndex);
-    NotifyIdleObserver(&idleObserver, true);
-    mIdleCallbackIndex++;
-    return NS_OK;
-  }
-
-  if (static_cast<int32_t>(insertAtIndex) == mIdleCallbackIndex) {
-    mIdleTimer->Cancel();
-    rv = ScheduleNextIdleObserverCallback();
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  return NS_OK;
-}
-
-nsresult nsGlobalWindowInner::FindIndexOfElementToRemove(
-    MozIdleObserver& aIdleObserver, int32_t* aRemoveElementIndex) {
-  *aRemoveElementIndex = 0;
-  if (mIdleObservers.IsEmpty()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  ErrorResult rv;
-  uint32_t aIdleObserverTimeInS = aIdleObserver.GetTime(rv);
-  if (NS_WARN_IF(rv.Failed())) {
-    return rv.StealNSResult();
-  }
-  NS_ENSURE_ARG_MIN(aIdleObserverTimeInS, MIN_IDLE_NOTIFICATION_TIME_S);
-
-  nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
-  while (iter.HasMore()) {
-    IdleObserverHolder& idleObserver = iter.GetNext();
-    if (idleObserver.mTimeInS == aIdleObserverTimeInS &&
-        idleObserver.mIdleObserver.ref() == aIdleObserver) {
-      break;
-    }
-    (*aRemoveElementIndex)++;
-  }
-  return static_cast<uint32_t>(*aRemoveElementIndex) >= mIdleObservers.Length()
-             ? NS_ERROR_FAILURE
-             : NS_OK;
-}
-
-nsresult nsGlobalWindowInner::UnregisterIdleObserver(
-    MozIdleObserver& aIdleObserver) {
-  int32_t removeElementIndex;
-  nsresult rv = FindIndexOfElementToRemove(aIdleObserver, &removeElementIndex);
-  if (NS_FAILED(rv)) {
-    NS_WARNING(
-        "Idle observer not found in list of idle observers. No idle observer "
-        "removed.");
-    return NS_OK;
-  }
-  mIdleObservers.RemoveElementAt(removeElementIndex);
-
-  MOZ_ASSERT(mIdleTimer);
-  if (mIdleObservers.IsEmpty() && mIdleService) {
-    rv = mIdleService->RemoveIdleObserver(mObserver,
-                                          MIN_IDLE_NOTIFICATION_TIME_S);
-    NS_ENSURE_SUCCESS(rv, rv);
-    mIdleService = nullptr;
-
-    mIdleTimer->Cancel();
-    mIdleCallbackIndex = -1;
-    return NS_OK;
-  }
-
-  if (!mCurrentlyIdle) {
-    return NS_OK;
-  }
-
-  if (removeElementIndex < mIdleCallbackIndex) {
-    mIdleCallbackIndex--;
-    return NS_OK;
-  }
-
-  if (removeElementIndex != mIdleCallbackIndex) {
-    return NS_OK;
-  }
-
-  mIdleTimer->Cancel();
-
-  // If the last element in the array had been notified then decrement
-  // mIdleCallbackIndex because an idle was removed from the list of
-  // idle observers.
-  // Example: add idle observer with time 1, 2, 3,
-  // Idle notifications for idle observers with time 1, 2, 3 are complete
-  // Remove idle observer with time 3 while the user is still idle.
-  // The user never transitioned to active state.
-  // Add an idle observer with idle time 4
-  if (static_cast<uint32_t>(mIdleCallbackIndex) == mIdleObservers.Length()) {
-    mIdleCallbackIndex--;
-  }
-  rv = ScheduleNextIdleObserverCallback();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
 nsresult nsGlobalWindowInner::Observe(nsISupports* aSubject, const char* aTopic,
                                       const char16_t* aData) {
   if (!nsCRT::strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC)) {
     if (!IsFrozen()) {
       // Fires an offline status event if the offline status has changed
       FireOfflineStatusEventIfChanged();
     }
     return NS_OK;
@@ -5114,39 +4727,16 @@ nsresult nsGlobalWindowInner::Observe(ns
 
   if (!nsCRT::strcmp(aTopic, "clear-site-data-reload-needed")) {
     // The reload is propagated from the top-level window only.
     NS_ConvertUTF16toUTF8 otherOrigin(aData);
     PropagateClearSiteDataReload(otherOrigin);
     return NS_OK;
   }
 
-  if (!nsCRT::strcmp(aTopic, OBSERVER_TOPIC_IDLE)) {
-    mCurrentlyIdle = true;
-    if (IsFrozen()) {
-      // need to fire only one idle event while the window is frozen.
-      mNotifyIdleObserversIdleOnThaw = true;
-      mNotifyIdleObserversActiveOnThaw = false;
-    } else if (IsCurrentInnerWindow()) {
-      HandleIdleActiveEvent();
-    }
-    return NS_OK;
-  }
-
-  if (!nsCRT::strcmp(aTopic, OBSERVER_TOPIC_ACTIVE)) {
-    mCurrentlyIdle = false;
-    if (IsFrozen()) {
-      mNotifyIdleObserversActiveOnThaw = true;
-      mNotifyIdleObserversIdleOnThaw = false;
-    } else if (IsCurrentInnerWindow()) {
-      ScheduleActiveTimerCallback();
-    }
-    return NS_OK;
-  }
-
   if (!nsCRT::strcmp(aTopic, "offline-cache-update-added")) {
     if (mApplicationCache) return NS_OK;
 
     // Instantiate the application object now. It observes update belonging to
     // this window's document and correctly updates the applicationCache object
     // state.
     nsCOMPtr<nsIObserver> observer = GetApplicationCache();
     if (observer) observer->Observe(aSubject, aTopic, aData);
@@ -5716,26 +5306,16 @@ nsresult nsGlobalWindowInner::FireDelaye
   if (mApplicationCache) {
     static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())
         ->FirePendingEvents();
   }
 
   // Fires an offline status event if the offline status has changed
   FireOfflineStatusEventIfChanged();
 
-  if (mNotifyIdleObserversIdleOnThaw) {
-    mNotifyIdleObserversIdleOnThaw = false;
-    HandleIdleActiveEvent();
-  }
-
-  if (mNotifyIdleObserversActiveOnThaw) {
-    mNotifyIdleObserversActiveOnThaw = false;
-    ScheduleActiveTimerCallback();
-  }
-
   nsCOMPtr<nsIDocShell> docShell = GetDocShell();
   if (docShell) {
     int32_t childCount = 0;
     docShell->GetChildCount(&childCount);
 
     // Take a copy of the current children so that modifications to
     // the child list don't affect to the iteration.
     AutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> children;
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -150,47 +150,16 @@ extern already_AddRefed<nsIScriptTimeout
     mozilla::ErrorResult& aError);
 
 extern already_AddRefed<nsIScriptTimeoutHandler> NS_CreateJSTimeoutHandler(
     JSContext* aCx, nsGlobalWindowInner* aWindow, const nsAString& aExpression,
     mozilla::ErrorResult& aError);
 
 extern const js::Class OuterWindowProxyClass;
 
-struct IdleObserverHolder {
-  mozilla::OwningNonNull<mozilla::dom::MozIdleObserver> mIdleObserver;
-  uint32_t mTimeInS;
-  bool mPrevNotificationIdle;
-
-  IdleObserverHolder() : mTimeInS(0), mPrevNotificationIdle(false) {
-    MOZ_COUNT_CTOR(IdleObserverHolder);
-  }
-
-  IdleObserverHolder(const IdleObserverHolder& aOther)
-      : mIdleObserver(aOther.mIdleObserver),
-        mTimeInS(aOther.mTimeInS),
-        mPrevNotificationIdle(aOther.mPrevNotificationIdle) {
-    MOZ_COUNT_CTOR(IdleObserverHolder);
-  }
-
-  bool operator==(const IdleObserverHolder& aOther) const {
-    return mIdleObserver.ref() == aOther.mIdleObserver &&
-           mTimeInS == aOther.mTimeInS;
-  }
-
-  ~IdleObserverHolder() { MOZ_COUNT_DTOR(IdleObserverHolder); }
-};
-
-inline void ImplCycleCollectionTraverse(
-    nsCycleCollectionTraversalCallback& aCallback, IdleObserverHolder& aField,
-    const char* aName, unsigned aFlags) {
-  CycleCollectionNoteChild(aCallback, aField.mIdleObserver.get(), aName,
-                           aFlags);
-}
-
 //*****************************************************************************
 // nsGlobalWindowInner: Global Object for Scripting
 //*****************************************************************************
 
 // nsGlobalWindowInner inherits PRCList for maintaining a list of all inner
 // windows still in memory for any given outer window. This list is needed to
 // ensure that mOuterWindow doesn't end up dangling. The nature of PRCList means
 // that the window itself is always in the list, and an outer window's list will
@@ -486,23 +455,16 @@ class nsGlobalWindowInner final : public
 
 #if defined(MOZ_WIDGET_ANDROID)
   virtual void EnableOrientationChangeListener() override;
   virtual void DisableOrientationChangeListener() override;
 #endif
 
   void AddSizeOfIncludingThis(nsWindowSizes& aWindowSizes) const;
 
-  void NotifyIdleObserver(IdleObserverHolder* aIdleObserverHolder,
-                          bool aCallOnidle);
-  nsresult HandleIdleActiveEvent();
-  bool ContainsIdleObserver(mozilla::dom::MozIdleObserver& aIdleObserver,
-                            uint32_t timeInS);
-  void HandleIdleObserverCallback();
-
   enum SlowScriptResponse {
     ContinueSlowScript = 0,
     ContinueSlowScriptAndKeepNotifying,
     AlwaysContinueSlowScript,
     KillSlowScript,
     KillScriptGlobal
   };
   SlowScriptResponse ShowSlowScriptDialog(const nsString& aAddonId);
@@ -1006,39 +968,16 @@ class nsGlobalWindowInner final : public
   void SetOuterWidth(int32_t aOuterWidth, mozilla::dom::CallerType aCallerType,
                      mozilla::ErrorResult& aError);
   int32_t GetOuterHeight(mozilla::dom::CallerType aCallerType,
                          mozilla::ErrorResult& aError);
   void SetOuterHeight(int32_t aOuterHeight,
                       mozilla::dom::CallerType aCallerType,
                       mozilla::ErrorResult& aError);
 
-  // Array of idle observers that are notified of idle events.
-  nsTObserverArray<IdleObserverHolder> mIdleObservers;
-
-  // Idle timer used for function callbacks to notify idle observers.
-  nsCOMPtr<nsITimer> mIdleTimer;
-
-  // Idle fuzz time added to idle timer callbacks.
-  uint32_t mIdleFuzzFactor;
-
-  // Index in mArrayIdleObservers
-  // Next idle observer to notify user idle status
-  int32_t mIdleCallbackIndex;
-
-  // If false then the topic is "active"
-  // If true then the topic is "idle"
-  bool mCurrentlyIdle;
-
-  // Set to true when a fuzz time needs to be applied
-  // to active notifications to the idle observer.
-  bool mAddActiveEventFuzzTime;
-
-  nsCOMPtr<nsIIdleService> mIdleService;
-
   RefPtr<mozilla::dom::WakeLock> mWakeLock;
 
   friend class HashchangeCallback;
   friend class mozilla::dom::BarProp;
 
   // Object Management
   virtual ~nsGlobalWindowInner();
 
@@ -1121,29 +1060,16 @@ class nsGlobalWindowInner final : public
   already_AddRefed<nsIDocShellTreeOwner> GetTreeOwner();
   already_AddRefed<nsIWebBrowserChrome> GetWebBrowserChrome();
   bool IsPrivateBrowsing();
 
   void FireOfflineStatusEventIfChanged();
 
  public:
   // Inner windows only.
-  nsresult ScheduleNextIdleObserverCallback();
-  uint32_t GetFuzzTimeMS();
-  nsresult ScheduleActiveTimerCallback();
-  uint32_t FindInsertionIndex(IdleObserverHolder* aIdleObserver);
-  nsresult RegisterIdleObserver(
-      mozilla::dom::MozIdleObserver& aIdleObserverPtr) override;
-  nsresult FindIndexOfElementToRemove(
-      mozilla::dom::MozIdleObserver& aIdleObserver,
-      int32_t* aRemoveElementIndex);
-  nsresult UnregisterIdleObserver(
-      mozilla::dom::MozIdleObserver& aIdleObserverPtr) override;
-
-  // Inner windows only.
   nsresult FireHashchange(const nsAString& aOldURL, const nsAString& aNewURL);
 
   void FlushPendingNotifications(mozilla::FlushType aType);
 
   void ScrollTo(const mozilla::CSSIntPoint& aScroll,
                 const mozilla::dom::ScrollOptions& aOptions);
 
   bool IsFrame();
@@ -1285,20 +1211,16 @@ class nsGlobalWindowInner final : public
   bool mWasOffline : 1;
 
   // Represents whether the inner window's page has had a slow script notice.
   // Only used by inner windows; will always be false for outer windows.
   // This is used to implement Telemetry measures such as
   // SLOW_SCRIPT_PAGE_COUNT.
   bool mHasHadSlowScript : 1;
 
-  // Track what sorts of events we need to fire when thawed
-  bool mNotifyIdleObserversIdleOnThaw : 1;
-  bool mNotifyIdleObserversActiveOnThaw : 1;
-
   // Fast way to tell if this is a chrome window (without having to QI).
   bool mIsChrome : 1;
 
   // Hack to indicate whether a chrome window needs its message manager
   // to be disconnected, since clean up code is shared in the global
   // window superclass.
   bool mCleanMessageManager : 1;
 
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -24,33 +24,31 @@
 #include "nsISecureBrowserUI.h"
 #include "nsIWebProgressListener.h"
 #include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/dom/ContentFrameMessageManager.h"
 #include "mozilla/dom/EventTarget.h"
 #include "mozilla/dom/LocalStorage.h"
 #include "mozilla/dom/LSObject.h"
 #include "mozilla/dom/Storage.h"
-#include "mozilla/dom/IdleRequest.h"
 #include "mozilla/dom/MaybeCrossOriginObject.h"
 #include "mozilla/dom/Performance.h"
 #include "mozilla/dom/StorageEvent.h"
 #include "mozilla/dom/StorageEventBinding.h"
 #include "mozilla/dom/StorageNotifierService.h"
 #include "mozilla/dom/StorageUtils.h"
 #include "mozilla/dom/Timeout.h"
 #include "mozilla/dom/TimeoutHandler.h"
 #include "mozilla/dom/TimeoutManager.h"
 #include "mozilla/dom/WindowProxyHolder.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #if defined(MOZ_WIDGET_ANDROID)
 #  include "mozilla/dom/WindowOrientationObserver.h"
 #endif
 #include "nsError.h"
-#include "nsIIdleService.h"
 #include "nsISizeOfEventTarget.h"
 #include "nsDOMJSUtils.h"
 #include "nsArrayUtils.h"
 #include "nsDOMWindowList.h"
 #include "mozilla/dom/WakeLock.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIInterfaceRequestorUtils.h"
@@ -1093,20 +1091,16 @@ static JSObject* NewOuterWindowProxy(JSC
 }
 
 //*****************************************************************************
 //***    nsGlobalWindowOuter: Object Management
 //*****************************************************************************
 
 nsGlobalWindowOuter::nsGlobalWindowOuter(uint64_t aWindowID)
     : nsPIDOMWindowOuter(aWindowID),
-      mIdleFuzzFactor(0),
-      mIdleCallbackIndex(-1),
-      mCurrentlyIdle(false),
-      mAddActiveEventFuzzTime(true),
       mFullscreen(false),
       mFullscreenMode(false),
       mIsClosed(false),
       mInClose(false),
       mHavePendingClose(false),
       mHadOriginalOpener(false),
       mIsPopupSpam(false),
       mBlockScriptedClosingFlag(false),
@@ -1319,21 +1313,16 @@ void nsGlobalWindowOuter::CleanUp() {
   if (mContext) {
     mContext = nullptr;  // Forces Release
   }
   mChromeEventHandler = nullptr;  // Forces Release
   mParentTarget = nullptr;
   mMessageManager = nullptr;
 
   mArguments = nullptr;
-
-  if (mIdleTimer) {
-    mIdleTimer->Cancel();
-    mIdleTimer = nullptr;
-  }
 }
 
 void nsGlobalWindowOuter::ClearControllers() {
   if (mControllers) {
     uint32_t count;
     mControllers->GetControllerCount(&count);
 
     while (count--) {
@@ -1413,19 +1402,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedDoc)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService)
-
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers)
 
   // Traverse stuff from nsPIDOMWindow
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOpenerForInitialContentBrowser)
 
@@ -1442,18 +1428,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedDoc)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers)
 
   // Unlink stuff from nsPIDOMWindow
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOpenerForInitialContentBrowser)
 
--- a/dom/base/nsGlobalWindowOuter.h
+++ b/dom/base/nsGlobalWindowOuter.h
@@ -75,42 +75,35 @@ class mozIDOMWindowProxy;
 
 class nsDocShellLoadState;
 class nsDOMWindowList;
 class nsScreen;
 class nsHistory;
 class nsGlobalWindowObserver;
 class nsGlobalWindowInner;
 class nsDOMWindowUtils;
-class nsIIdleService;
 struct nsRect;
 
 class nsWindowSizes;
 
-class IdleRequestExecutor;
-
-struct IdleObserverHolder;
-
 namespace mozilla {
 class AbstractThread;
 class DOMEventTargetHelper;
 namespace dom {
 class BarProp;
 class BrowsingContext;
 struct ChannelPixelLayout;
 class Console;
 class Crypto;
 class CustomElementRegistry;
 class DocGroup;
 class External;
 class Function;
 class Gamepad;
 enum class ImageBitmapFormat : uint8_t;
-class IdleRequest;
-class IdleRequestCallback;
 class IncrementalRunnable;
 class IntlUtils;
 class Location;
 class MediaQueryList;
 class Navigator;
 class OwningExternalOrWindowProxy;
 class Promise;
 class PostMessageData;
@@ -720,39 +713,16 @@ class nsGlobalWindowOuter final : public
                           mozilla::dom::CallerType aCallerType,
                           mozilla::ErrorResult& aError);
   int32_t GetOuterHeightOuter(mozilla::dom::CallerType aCallerType,
                               mozilla::ErrorResult& aError);
   void SetOuterHeightOuter(int32_t aOuterHeight,
                            mozilla::dom::CallerType aCallerType,
                            mozilla::ErrorResult& aError);
 
-  // Array of idle observers that are notified of idle events.
-  nsTObserverArray<IdleObserverHolder> mIdleObservers;
-
-  // Idle timer used for function callbacks to notify idle observers.
-  nsCOMPtr<nsITimer> mIdleTimer;
-
-  // Idle fuzz time added to idle timer callbacks.
-  uint32_t mIdleFuzzFactor;
-
-  // Index in mArrayIdleObservers
-  // Next idle observer to notify user idle status
-  int32_t mIdleCallbackIndex;
-
-  // If false then the topic is "active"
-  // If true then the topic is "idle"
-  bool mCurrentlyIdle;
-
-  // Set to true when a fuzz time needs to be applied
-  // to active notifications to the idle observer.
-  bool mAddActiveEventFuzzTime;
-
-  nsCOMPtr<nsIIdleService> mIdleService;
-
   RefPtr<mozilla::dom::WakeLock> mWakeLock;
 
   friend class HashchangeCallback;
   friend class mozilla::dom::BarProp;
 
   // Object Management
   virtual ~nsGlobalWindowOuter();
   void DropOuterWindowDocs();
@@ -1172,17 +1142,16 @@ class nsGlobalWindowOuter final : public
   } mChromeFields;
 
   friend class nsDOMScriptableHelper;
   friend class nsDOMWindowUtils;
   friend class mozilla::dom::BrowsingContext;
   friend class mozilla::dom::PostMessageEvent;
   friend class DesktopNotification;
   friend class mozilla::dom::TimeoutManager;
-  friend class IdleRequestExecutor;
   friend class nsGlobalWindowInner;
 };
 
 // XXX: EWW - This is an awful hack - let's not do this
 #include "nsGlobalWindowInner.h"
 
 inline nsISupports* ToSupports(nsGlobalWindowOuter* p) {
   return static_cast<mozilla::dom::EventTarget*>(p);
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -49,17 +49,16 @@ class AudioContext;
 class BrowsingContext;
 class ClientInfo;
 class ClientState;
 class ContentFrameMessageManager;
 class DocGroup;
 class Document;
 class TabGroup;
 class Element;
-class MozIdleObserver;
 class Navigator;
 class Performance;
 class Report;
 class ReportBody;
 class ReportingObserver;
 class Selection;
 class ServiceWorker;
 class ServiceWorkerDescriptor;
@@ -338,21 +337,16 @@ class nsPIDOMWindowInner : public mozIDO
   virtual nsPIDOMWindowOuter* GetScriptableTop() = 0;
   virtual nsPIDOMWindowOuter* GetScriptableParent() = 0;
   virtual already_AddRefed<nsPIWindowRoot> GetTopWindowRoot() = 0;
 
   mozilla::dom::EventTarget* GetChromeEventHandler() const {
     return mChromeEventHandler;
   }
 
-  virtual nsresult RegisterIdleObserver(
-      mozilla::dom::MozIdleObserver& aIdleObserver) = 0;
-  virtual nsresult UnregisterIdleObserver(
-      mozilla::dom::MozIdleObserver& aIdleObserver) = 0;
-
   mozilla::dom::EventTarget* GetParentTarget() {
     if (!mParentTarget) {
       UpdateParentTarget();
     }
     return mParentTarget;
   }
 
   virtual void MaybeUpdateTouchState() {}
--- a/dom/base/test/chrome.ini
+++ b/dom/base/test/chrome.ini
@@ -15,18 +15,16 @@ support-files =
   referrer_testserver.sjs
   mozbrowser_api_utils.js
   !/image/test/mochitest/shaver.png
 
 [test_anonymousContent_xul_window.xul]
 [test_blockParsing.html]
 [test_blocking_image.html]
 [test_bug419527.xhtml]
-[test_bug715041.xul]
-[test_bug715041_removal.xul]
 [test_bug945152.html]
 [test_bug1008126.html]
 [test_bug1016960.html]
 [test_anchor_target_blank_referrer.html]
 [test_copypaste.xul]
 subsuite = clipboard
 [test_domrequesthelper.xul]
 [test_fragment_sanitization.xul]
deleted file mode 100644
--- a/dom/base/test/test_bug715041.xul
+++ /dev/null
@@ -1,808 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
-<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=715041
--->
-    <window title="Mozilla Bug 715041"
-xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-    <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
-
-    <!-- test results are displayed in the html:body -->
-    <body xmlns="http://www.w3.org/1999/xhtml">
-    <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=715041"
-target="_blank">Mozilla Bug 715041</a>
-    </body>
-
-    <!-- test code goes here -->
-    <script type="application/javascript">
-    <![CDATA[
-
-  /** Mock Idle Service Test for Bug 715041 **/
-  //class mock javascript idle service
-  var idleServiceObj = {
-    observers: [],
-    windowObservers: [],
-    idleTimeInMS: 5000,   //in milli seconds
-
-    // takes note of the idle observers added as the minimum idle observer
-    // with the idle service
-    timesAdded: [],
-
-    QueryInterface: function(iid) {
-      if (iid.equals(Ci.nsISupports) ||
-          iid.equals(Ci.nsIFactory) ||
-          iid.equals(Ci.nsIIdleService)) {
-        return this;
-      }
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    },
-
-    createInstance: function(outer, iid) {
-      return this.QueryInterface(iid);
-    },
-
-    get idleTime() {
-      return this.idleTimeInMS; //in milli seconds
-    },
-
-    set idleTime(timeInMS) {
-      this.idleTimeInMS = timeInMS;
-    },
-
-    getWindowFromObserver: function(observer) {
-      try {
-        var interfaceRequestor = observer.QueryInterface(Ci.nsIInterfaceRequestor);
-        var window = interfaceRequestor.getInterface(Ci.nsIDOMWindow);
-        return window;
-      }
-      catch (e) {}
-
-      return null;
-    },
-
-    testIdleBackService: function(observer, topic) {
-      dump("\nJS FAKE IDLE SERVICE\n");
-      dump("JS NUM OBSERVERS: " + this.observers.length + "\n");
-
-      if (this.observers.length > 1) {
-        this.observers[1].observer.observe(observer, topic, '\0');
-        dump("JS CALLED OBSERVE FUNCTION!!!\n\n");
-      }
-    },
-
-    addIdleObserver: function(observer, time) {
-      dump("\nJS FAKE IDLE SERVICE add idle observer before\n");
-      dump("JS NUM OBSERVERS: " + this.observers.length + "\n");
-
-      var window = this.getWindowFromObserver(observer);
-      dump("window is: " + window + "\n");
-
-      if (window) {
-        this.observers.push({ observer: observer, time: time, });
-        addedIdleObserver = true;
-        numIdleObserversAdded++;
-        this.timesAdded.push(time);
-
-        dump ("\nMOCK IDLE SERVICE ADDING idle observer with time: " + time + "\n");
-        dump("MOCK IDLE SERVICE: num idle observers added: " + numIdleObserversAdded + "\n\n");
-      }
-      else {
-        dump("SHOULD NEVER GET HERE!");
-        oldIdleService.addIdleObserver(observer, time);
-        addedIdleObserver = false;
-      }
-
-      dump("\nJS FAKE IDLE SERVICE end of add idle observer\n");
-      dump("JS NUM OBSERVERS: " + this.observers.length + "\n");
-    },
-
-    removeIdleObserver: function(observer, time) {
-      dump("\nJS REMOVE IDLE OBSERVER () time to be removed: " + time + "\n");
-      var window = this.getWindowFromObserver(observer);
-      if (!window) {
-        oldIdleService.removeIdleObserver(observer, time);
-      }
-      else {
-        var observerIndex = -1;
-        for (var i=0; i<this.observers.length; i++) {
-          dump("JS removeIdleObserver() observer time: " + this.observers[i].time + "\n");
-          if (this.observers[i].time === time) {
-            observerIndex = i;
-            break;
-          }
-        }
-
-        if (observerIndex != -1 && this.observers.length > 0) {
-          numIdleObserversRemoved++;
-          this.observers.splice(observerIndex, 1);
-          removedIdleObserver = true;
-          dump("MOCK IDLE SERVICE REMOVING idle observer with time " + time + "\n");
-          dump("MOCK IDLE SERVICE numIdleObserversRemoved: " + numIdleObserversRemoved + " numIdleObserversAdded: " + numIdleObserversAdded + "\n\n");
-        }
-        else {
-          removedIdleObserver = false;
-        }
-      }
-      dump("\nJS FAKE IDLE SERVICE end of remove idle observer\n");
-      dump("JS NUM OBSERVERS: " + this.observers.length + "\n");
-    },
-  };
-
-  /** Test for Bug 715041 **/
-  dump("\n\n\nJS STARTING TESTING FOR BUG 715041\n");
-
-  //bool variables
-  var addedIdleObserver = removedIdleObserver = passed = cleanUp = false;
-
-  //test case enabled
-  var AddOutOfOrderActiveEnabled = AddOutOfOrderIdleEnabled =
-      AddShiftLocalEnabled = AddNewLocalWhileAllIdleEnabled =
-      TestActiveToActiveNotification = ShiftLocalTimerBackEnabled =
-      AddRemoveIdleObserverWithInvalidTimeEnabled = true;
-
-  //msgXCount
-  var msg0Count = msg1Count = msg2Count = msg3Count = msg4Count = msg5Count =
-      msg6Count = tcZero = currTestCaseNum = prevMsgNum =
-      numIdleObserversRemoved = numIdleObserversAdded = 0;
-
-  //test case number
-  var tcZero = 0;
-  var tcAddOutOfOrderActive = 1;
-  var tcAddOutOfOrderIdle = 2;
-  var tcAddShiftLocal = 3;
-  var tcAddNewLocalWhileAllIdle = 4;
-  var tcShiftLocalTimerBack = 5;
-  var tcAddRemoveIdleObserverWithInvalidTime = 6;
-  var tcTestActiveToActiveNotification = 7;
-
-  function ResetMsgCounts() {
-    msg0Count = msg1Count = msg2Count = msg3Count = msg4Count = msg5Count =
-    msg6Count = prevMsgNum = 0;
-  }
-
-  function ResetVars() {
-    msg0Count = msg1Count = msg2Count = msg3Count = msg4Count = msg5Count =
-    msg6Count = prevMsgNum = 0;
-
-    numIdleObserversAdded = numIdleObserversRemoved = 0;
-    currTestCaseNum = -1;
-    addedIdleObserver = removedIdleObserver = passed = cleanUp = false;
-  }
-
-  /*
-   * - function printMsgCounts()
-   */
-  function printMsgCounts() {
-    dump("\nmsg0Count: " + msg0Count +
-         "\nmsg1Count: " + msg1Count +
-         "\nmsg2Count: " + msg2Count +
-         "\nmsg3Count: " + msg3Count +
-         "\nmsg5Count: " + msg5Count +
-         "\nmsg6Count: " + msg6Count +
-         "\n"
-         );
-  }
-
-  function performNextTest() {
-    dump("\nfunction performNextTest()\ncurrTestCaseNum: " + currTestCaseNum +
-         "\ncleanUp: " + cleanUp +
-         "\npassed: " + passed +
-         "\nnumIdleObserversRemoved: " + numIdleObserversRemoved +
-         "\nnumIdleObservesAdded: " + numIdleObserversAdded + "\n");
-
-    switch (currTestCaseNum) {
-      case tcZero:
-        ok(passed, "Test case 0 failed clean up!");
-        caseZeroCleanUp();
-        break;
-      case tcAddShiftLocal:
-        if (cleanUp && numIdleObserversRemoved === 1) {
-          passed = true;
-          ok(passed, "Failed test case AddShiftLocalCleanUp()");
-          if (AddNewLocalWhileAllIdleEnabled) {
-            AddNewLocalWhileAllIdle();
-          }
-          else {
-            SimpleTest.finish();
-          }
-        }
-        break;
-      case tcAddNewLocalWhileAllIdle:
-        ok(passed, "Failed test case: AddNewLocalWhileAllIdle()");
-        AddNewLocalWhileAllIdleCleanUp();
-        break;
-      default:
-        //do nothing.
-        break;
-    }
-  }
-
-  //Place Holder.
-  var idleHandler0 = function() { dump("rmsg 0, should never be used!\n"); };
-
-  //idleHandler1
-  function idleHandler1() {
-    msg1Count++;
-    dump("msg 1 Count: " + msg1Count + "\n");
-
-    switch (currTestCaseNum) {
-    case tcAddOutOfOrderIdle:
-      if (msg1Count === 1 && msg2Count === 1 && msg3Count === 1) {
-        idleServiceObj.idleTime = 0;
-        idleServiceObj.testIdleBackService(idleObserversArray[1], "active");
-      }
-      else if (msg1Count === 4 && msg2Count === 4 && msg3Count === 4) {
-        passed = true;
-        AddOutOfOrderIdleCleanUp();
-      }
-      break;
-    case tcTestActiveToActiveNotification:
-      if (msg1Count === 1 && !msg2Count && !msg3Count && !msg4Count && !msg5Count) {
-        idleServiceObj.idleTime = 500;
-        idleServiceObj.testIdleBackService(idleObserversArray[1], "active");
-        return;
-      }
-      
-      if (msg1Count === 2 && !msg2Count && !msg3Count && !msg4Count && !msg5Count) {        
-        idleServiceObj.idleTime = 1000;
-        idleServiceObj.testIdleBackService(idleObserversArray[1], "idle");
-        return;
-      }
-
-      if (msg1Count === 3 && !msg2Count && !msg3Count && !msg4Count && !msg5Count) {
-        return;
-      }
-      ok(false, "Failed test active to active notification.");
-      SimpleTest.finish();
-      break;  
-    default:
-      break;
-    }
-  }
-
-  //idleHandler2
-  function idleHandler2() {
-    msg2Count++;
-    dump("msg 2 Count: " + msg2Count + "\n");
-
-    switch (currTestCaseNum) {
-    case tcZero:
-      switch (msg2Count) {
-      case 2:
-        passed = true;
-        performNextTest();
-        break;
-      default:
-        break;
-      }
-      break;
-    case tcAddOutOfOrderIdle:
-      if (msg3Count === 1 && msg2Count === 1 && !msg1Count) {
-        idleServiceObj.idleTime = 4000;
-        window.navigator.addIdleObserver(idleObserversArray[1]);
-      }
-      break;
-    case tcAddShiftLocal:
-      if (!msg1Count && msg2Count === 1 && !msg3Count && !msg4Count) {
-        window.navigator.addIdleObserver(idleObserversArray[3]);
-      }
-      AddShiftLocalCleanUp();
-      break;
-    case tcAddNewLocalWhileAllIdle:
-      if (msg1Count === 1 && msg2Count === 2) {
-        idleServiceObj.idleTime = 3500;
-        window.navigator.addIdleObserver(idleObserversArray[5]);
-      }
-      break;
-    case (tcShiftLocalTimerBack):
-      if (!msg1Count && msg2Count === 1 && !msg3Count && !msg4Count && !msg5Count) {
-        window.navigator.addIdleObserver(idleObserversArray[5]);
-        window.navigator.addIdleObserver(idleObserversArray[4]);
-      }
-      break;
-    default:
-      //do nothing.
-      break;
-    }
-  }
-
-  //idleHandler3
-  function idleHandler3() {
-    msg3Count++;
-    dump("msg 3 Count: " + msg3Count + "\n");
-
-    switch (currTestCaseNum) {
-    case (tcAddOutOfOrderIdle):
-      if (msg3Count === 1) {
-        idleServiceObj.idleTime = 3500;
-        window.navigator.addIdleObserver(idleObserversArray[2]);
-      }
-      if (msg1Count === 2 && msg2Count === 2 && msg3Count === 2) {
-        idleServiceObj.idleTime = 1000;
-        idleServiceObj.testIdleBackService(idleObserversArray[1], "idle");
-      }
-      else if (msg1Count === 3 && msg2Count === 3 && msg3Count === 3) {
-        AddOutOfOrderIdle();
-      }
-      else if (msg1Count === 3 && msg2Count === 3 && msg3Count === 4) {
-        passed = true;
-        AddOutOfOrderIdleCleanUp();
-      }
-      break;
-    default:
-      break;
-    }
-  }
-
-  //idleHandler4
-  function idleHandler4() {
-    msg4Count++;
-    dump("msg 4 Count: " + msg4Count + "\n");
-
-    switch (currTestCaseNum) {
-    case tcAddOutOfOrderActive:
-      if (msg1Count && msg2Count && msg3Count && msg4Count) {
-        passed = true;
-        ok(passed, "idleHandler4: failed AddOutOfOrderActive()");
-        AddOutOfOrderActiveCleanUp();
-        cleanUp = true;
-      }
-      break;
-    case tcAddShiftLocal:
-      if (msg1Count === 1 && msg3Count === 1 && msg4Count === 1) {
-        idleServiceObj.idleTime = 3200;
-        window.navigator.addIdleObserver(idleObserversArray[2]);
-      }
-      break;
-    default:
-      //do nothing.
-      break;
-    }
-  }
-
-  //idleHandler5
-  function idleHandler5() {
-    msg5Count++;
-    dump("msg 5 Count: " + msg5Count + "\n");
-
-    switch (currTestCaseNum) {
-    case tcAddNewLocalWhileAllIdle:
-      if (msg1Count === 1 && msg2Count === 2 && msg5Count === 1) {
-        passed = true;
-        performNextTest();
-      }
-      break;
-    case tcShiftLocalTimerBack:
-      if (!msg1Count && msg2Count === 1 && !msg3Count && msg4Count === 1 && msg5Count === 1) {
-        passed = true;
-        ShiftLocalTimerBackCleanUp();
-      }
-      break;
-    case tcTestActiveToActiveNotification:
-      passed = false;
-      if (msg1Count === 3 && !msg2Count && !msg3Count && !msg4Count && msg5Count === 1) {
-        passed = true;
-      }
-      ok(passed, "Failed TestActiveToActiveNotification.");
-          TestActiveNotificationCleanUp();
-      break;  
-    default:
-      //do nothing.
-      break;
-    }
-  }
-
-  //idleHandler6
-  function idleHandler6() {
-    dump("msg 6 Count: " + msg6Count + "\n");
-  }
-
-  var  idleObserversArray = [];
-  idleObserversArray[0] = {time: 0, onidle: idleHandler0, onactive: idleHandler0};
-  idleObserversArray[1] = {time: 1, onidle: idleHandler1, onactive: idleHandler1};
-  idleObserversArray[2] = {time: 2, onidle: idleHandler2, onactive: idleHandler2};
-  idleObserversArray[3] = {time: 3, onidle: idleHandler3, onactive: idleHandler3};
-  idleObserversArray[4] = {time: 4, onidle: idleHandler4, onactive: idleHandler4};
-  idleObserversArray[5] = {time: 5, onidle: idleHandler5, onactive: idleHandler5};
-  idleObserversArray[6] = {time: 0, onidle: idleHandler6, onactive: idleHandler6};
-  idleObserversArray[7] = {time: 2, onidle: null, onactive: null};
-
-  idleServiceObj.observers.push( {observer: idleObserversArray[0], time: 0, } );
-
-  /*
-   * - case 0
-   * - AddSingleIdleObserver
-   * - takes care of adding duplicate local too
-   * - user is currently idle since the
-   *   requested idle time of 2s < current idle time of 5000ms set below.
-   */
-  function caseZero() {
-    dump("\n\nTESTING CASE 0\n");
-    dump("==============\n");
-
-    ResetVars();
-    currTestCaseNum = tcZero;
-    idleServiceObj.idleTime = 5000;
-
-    window.navigator.addIdleObserver(idleObserversArray[2]);
-    idleServiceObj.testIdleBackService(idleObserversArray[2], "idle");
-    window.navigator.addIdleObserver(idleObserversArray[2]);
-  }
-
-  function caseZeroCleanUp() {
-    dump("\ncaseZeroCleanUp()\n");
-    dump("==============\n");
-    ResetVars();
-    currTestCaseNum = tcZero;
-    cleanUp = false;
-
-    window.navigator.removeIdleObserver(idleObserversArray[2]);
-    window.navigator.removeIdleObserver(idleObserversArray[2]);
-
-    if (AddOutOfOrderActiveEnabled) {
-      AddOutOfOrderActive();
-    }
-    else {
-      dump("Finishing testing idle API.\n");
-      SimpleTest.finish();
-    }
-  }
-
-  /*
-    AddOutOfOrderActive()
-    - Tests if the idle observer with the min time is always registered correctly
-      with the idle service.
-  */
-  function AddOutOfOrderActive() {
-    dump("\n\nTESTING CASE AddOutOfOrderActive\n");
-    dump("==============\n");
-
-    ResetVars();
-    currTestCaseNum = tcAddOutOfOrderActive;
-    idleServiceObj.idleTime = 500;
-
-    window.navigator.addIdleObserver(idleObserversArray[3]); //msg3
-    window.navigator.addIdleObserver(idleObserversArray[4]); //msg4
-    window.navigator.addIdleObserver(idleObserversArray[1]); //msg1
-    window.navigator.addIdleObserver(idleObserversArray[2]); //msg2
-    passed = false;
-
-    idleServiceObj.idleTime = 1000;
-    idleServiceObj.testIdleBackService(idleObserversArray[1], "idle");
-  }
-
-  /*
-    - AddOutOfOrderActiveCleanUp()
-  */
-  function AddOutOfOrderActiveCleanUp() {
-    dump("\nAddOutOfOrderActiveCleanUp()\n");
-    dump("==============================\n");
-    ResetVars();
-    currTestCaseNum = tcAddOutOfOrderActive;
-    cleanUp = false;
-    idleServiceObj.idleTime = 4500;
-
-    for (var i=1; i<5; i++) {
-      window.navigator.removeIdleObserver(idleObserversArray[i]);
-    }
-    dump("JS AddOutOfOrderActiveCleanUp() DONE\n");
-    if (AddOutOfOrderIdleEnabled) {
-      AddOutOfOrderIdle();
-    }
-    else {
-      dump("Finishing testing idle API.\n");
-      SimpleTest.finish();
-    }
-  }
-
-  /*
-    - AddOutOfOrderIdle()
-  */
-  function AddOutOfOrderIdle() {
-    dump("\nAddOutOfOrderIdle()\n");
-    dump("======================================================================\n");
-
-    dump("\nJS AddOutOfOrderIdle\n");
-    dump("JS NUM OBSERVERS: " + idleServiceObj.observers.length + "\n");
-
-    if (!msg1Count && !msg2Count && !msg3Count) {
-      ResetVars();
-    }
-    currTestCaseNum = tcAddOutOfOrderIdle;
-    cleanUp = false;
-
-    if (!msg1Count && !msg2Count && !msg3Count) {
-      idleServiceObj.idleTime = 3100;
-    }
-    window.navigator.addIdleObserver(idleObserversArray[3]);
-    if (!msg1Count && !msg2Count && !msg3Count) {
-      idleServiceObj.testIdleBackService(idleObserversArray[3], "idle");
-    }
-  }
-
-  /*
-   - AddOutOfOrderIdleCleanUp()
-  */
-  function AddOutOfOrderIdleCleanUp() {
-    ok(passed, "Failed test case: AddOutOfOrderIdle()");
-    dump("\nAddOutOfOrderIdleCleanUp()\n");
-    dump("==========================\n");
-    ResetVars();
-    currTestCaseNum = tcAddOutOfOrderIdle;
-    cleanUp = true;
-    idleServiceObj.idleTime = 4100;
-
-    for (var j=1; j<4; j++) {
-      window.navigator.removeIdleObserver(idleObserversArray[j]);
-    }
-    window.navigator.removeIdleObserver(idleObserversArray[3]);
-
-    if (idleServiceObj.observers.length === 1) {
-      passed = true;
-    }
-    else {
-      passed = false;
-    }
-    ok(passed, "Failed test case: AddOutOfOrderIdleCleanUp()");
-    if (AddShiftLocalEnabled) {
-      AddShiftLocal();
-    }
-    else {
-      dump("Finished AddOutOfOrderIdleCleanUp() test.\n");
-      SimpleTest.finish();
-    }
-  }
-
-  /*
-   * function AddShiftLocal()
-   * - user is idle
-   * - check that local idle timer is shifted correctly
-   * - msg 1 fired when user is idle
-   * - msg 3 fired when 3000
-   * - msg 2 fired immediately when added at 3200 ms
-   * - msg 4 fired by local timer.
-   */
-  function AddShiftLocal()
-  {
-    dump("\n\nTESTING CASE AddShiftLocal\n");
-    dump("==============\n");
-
-    ResetVars();
-    currTestCaseNum = tcAddShiftLocal;
-    idleServiceObj.idleTime = 500;
-
-    window.navigator.addIdleObserver(idleObserversArray[1]);
-    window.navigator.addIdleObserver(idleObserversArray[3]);
-    window.navigator.addIdleObserver(idleObserversArray[4]);
-
-    idleServiceObj.idleTime = 1000;
-    idleServiceObj.testIdleBackService(idleObserversArray[1], "idle");
-  }
-
-  /*
-   * function AddShiftLocalCleanUp()
-   */
-  function AddShiftLocalCleanUp()
-  {
-    dump("\n\nTESTING CASE AddShiftLocalCleanUp\n");
-    dump("==============\n");
-
-    ResetVars();
-    currTestCaseNum = tcAddShiftLocal;
-
-    for (var i=1; i<5; i++) {
-      window.navigator.removeIdleObserver(idleObserversArray[i]);
-    }
-    dump("AddShiftLocalCleanUp() done clean up\n");
-    if (AddNewLocalWhileAllIdleEnabled) {
-      AddNewLocalWhileAllIdle();
-    }
-    else {
-      dump("Finished testing AddShiftLocal()\n");
-      SimpleTest.finish();
-    }
-  }
-
-  /*
-   * AddNewLocalWhileAllIdle()
-   * - no local idle timer exists because all of the idle observers that were added had a requested
-   *   idle time of < curr user idle time and so were fired immediately. No local timer was required.
-   * - now add an idle observer whose requested idle time is > current use idle time and > min idle
-   *   requested time in the list of idle observers.
-   */
-  function AddNewLocalWhileAllIdle()
-  {
-    dump("\n\nTESTING CASE AddNewLocalWhileAllIdle\n");
-    dump("==============\n");
-
-    ResetVars();
-    currTestCaseNum = tcAddNewLocalWhileAllIdle;
-    idleServiceObj.idleTime = 500;
-
-    window.navigator.addIdleObserver(idleObserversArray[1]);
-    window.navigator.addIdleObserver(idleObserversArray[2]);
-    window.navigator.addIdleObserver(idleObserversArray[2]);
-
-    idleServiceObj.idleTime = 1000;
-    idleServiceObj.testIdleBackService(idleObserversArray[1], "idle");
-  }
-
-  function AddNewLocalWhileAllIdleCleanUp()
-  {
-    dump("\n\nTESTING CASE AddNewLocalWhileAllIdleCleanUp\n");
-    dump("==============\n");
-
-    ResetVars();
-    currTestCaseNum = tcAddNewLocalWhileAllIdle;
-
-    window.navigator.removeIdleObserver(idleObserversArray[1]);
-    window.navigator.removeIdleObserver(idleObserversArray[2]);
-    window.navigator.removeIdleObserver(idleObserversArray[2]);
-    window.navigator.removeIdleObserver(idleObserversArray[5]);
-
-    if (ShiftLocalTimerBackEnabled) {
-      ShiftLocalTimerBack();
-    }
-    else {
-      dump("Finished testing TestActiveToActiveNotificationCleanUp()\n");
-      SimpleTest.finish();
-    }
-  }
-
-  /*
-   * ShiftLocalTimerBack()
-   * - add a new idle observer whose requested time is > current user idle time
-   *   but < the current local timer that has been set.
-   * - the local timer will need to be reset to fire the new msg added.
-   * RESULT
-   * - should print all of them in order
-   */
-  function ShiftLocalTimerBack()
-  {
-    dump("\n\nTESTING CASE ShiftLocalTimerBack()\n");
-    dump("==============\n");
-
-    ResetVars();
-    currTestCaseNum = tcShiftLocalTimerBack;
-    idleServiceObj.idleTime = 2100;
-
-    window.navigator.addIdleObserver(idleObserversArray[2]);
-    idleServiceObj.testIdleBackService(idleObserversArray[2], "idle");
-  }
-
-  function ShiftLocalTimerBackCleanUp()
-  {
-    dump("\n\nTESTING CASE ShiftLocalTimerBackCleanUp\n");
-    dump("==============\n");
-
-    ResetVars();
-    currTestCaseNum = tcShiftLocalTimerBack;
-    window.navigator.removeIdleObserver(idleObserversArray[2]);
-    window.navigator.removeIdleObserver(idleObserversArray[4]);
-    window.navigator.removeIdleObserver(idleObserversArray[5]);
-    dump("ShiftLocalTimerBackCleanUp() done clean up\n");
-
-    if (TestActiveToActiveNotificationEnabled) {
-      TestActiveNotification();
-    }
-    else {
-      dump("Finished testing AddNewLocalWhileAllIdle()\n");
-      SimpleTest.finish();
-    }   
-  }
-
-  function TestActiveNotification()
-  {
-    dump("\n\nTESTING CASE TestActiveNotification\n");
-    dump("===============================================\n");
-
-    ResetVars();
-    currTestCaseNum = tcTestActiveToActiveNotification;
-
-    idleServiceObj.idleTime = 500;
-    window.navigator.addIdleObserver(idleObserversArray[1]);
-    window.navigator.addIdleObserver(idleObserversArray[5]);
-    idleServiceObj.idleTime = 1000;
-    idleServiceObj.testIdleBackService(idleObserversArray[1], "idle");    
-  }
-
-  function TestActiveNotificationCleanUp()
-  {
-    dump("\n\nTESTING CASE TestActiveNotificationCleanUp\n");
-    dump("===============================================\n");
-
-    try {
-      componentMgr.unregisterFactory(idleServiceCID, idleServiceObj);
-    }
-    catch(err) {
-      dump("test_bug715041.xul: ShiftLocalTimerBackCleanUp() Failed to unregister factory, mock idle service!\n");
-    }
-
-    try {
-      componentMgr.registerFactory(oldIdleServiceCID, "Re registering old idle service", idleServiceContractID, null);
-    }
-    catch(err) {
-      dump("test_bug715041.xul: ShiftLocalTimerBackCleanUp() Failed to register factory, original idle service!\n");
-    }
-
-    SimpleTest.finish();
-  }
-
-  /*
-   * function AddRemoveIdleObserverWithInvalidTime()
-   */
-  function AddRemoveIdleObserverWithInvalidTime()
-  {
-    dump("\n\nTESTING CASE AddRemoveIdleObserverWithInvalidTime()\n");
-    dump("==============\n");
-
-    ResetVars();
-    currTestCaseNum = tcAddRemoveIdleObserverWithInvalidTime;
-
-    //while idle
-    idleServiceObj.idleTime = 2100;
-    var rv = window.navigator.addIdleObserver(idleObserversArray[6]);
-    dump("rv: " + rv + "\n");
-    rv = window.navigator.removeIdleObserver(idleObserversArray[6]);
-
-    idleServiceObj.idleTime = 0;
-    window.navigator.addIdleObserver(idleObserversArray[6]);
-    window.navigator.removeIdleObserver(idleObserversArray[6]);
-
-    SimpleTest.finish();
-  }
-
-  try {
-    var idleServiceCID = Components.ID("287075a6-f968-4516-8043-406c46f503b4");
-    var idleServiceContractID = "@mozilla.org/widget/idleservice;1";
-    var oldIdleService = Cc[idleServiceContractID].getService(Ci.nsIIdleService);
-  }
-  catch(ex) {
-    dump("test_bug715041.xul: 1) Failed to get old idle service.\n");
-  }
-
-  try {
-    // Registering new moch JS idle service
-    var componentMgr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-  }
-  catch(err) {
-    dump("test_bug715041.xul: Failed to query component registrar interface.\n");
-  }
-
-  try {
-    var oldIdleServiceFactoryObj = componentMgr.getClassObjectByContractID(idleServiceContractID, Ci.nsIFactory);
-  }
-  catch(err) {
-    dump("test_bug715041.xul: Failed to get old idle service.\n");
-  }
-
-  try {
-    var oldIdleServiceCID = componentMgr.contractIDToCID(idleServiceContractID);
-  }
-  catch(err) {
-    dump("test_bug715041.xul: Failed to convert ID to CID for old idle service.\n");
-  }
-
-  try {
-    componentMgr.registerFactory(idleServiceCID, "Test Simple Idle/Back Notifications", idleServiceContractID, idleServiceObj);
-  }
-  catch(err) {
-    dump("test_bug715041.xul: Failed to register mock idle service.\n");
-  }
-
-  SimpleTest.waitForExplicitFinish();
-  SimpleTest.requestLongerTimeout(10);
-
-  AddOutOfOrderActiveEnabled = true;
-  AddOutOfOrderIdleEnabled = true;
-  AddNewLocalWhileAllIdleEnabled = true;
-  TestActiveToActiveNotificationEnabled = true;
-  AddShiftLocalEnabled = true;
-  AddIdleObserverWithInvalidTimeEnabled = false;
-  
-  SpecialPowers.pushPrefEnv({"set":[['dom.idle-observers-api.fuzz_time.disabled', true]]}, caseZero);
-    ]]>
-    </script>
-    </window>
-
deleted file mode 100644
--- a/dom/base/test/test_bug715041_removal.xul
+++ /dev/null
@@ -1,834 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
-<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=715041
--->
-    <window title="Mozilla Bug 715041"
-xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-    <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
-
-    <!-- test results are displayed in the html:body -->
-    <body xmlns="http://www.w3.org/1999/xhtml">
-    <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=715041"
-target="_blank">Mozilla Bug 715041</a>
-    </body>
-
-    <!-- test code goes here -->
-    <script type="application/javascript">
-    <![CDATA[
-
-  /** Mock Idle Service Test for Bug 715041 **/
-  try {
-    var idleServiceCID = Components.ID("6f95d965-4322-4829-8a3c-5dc8a4587f4d");
-    var idleServiceContractID = "@mozilla.org/widget/idleservice;1";
-    var oldIdleService = Cc[idleServiceContractID].getService(Ci.nsIIdleService);
-  }
-  catch (ex) {
-    dump("test_bug715041_removal.xul: failed to get old idle service 1.");
-  }
-
-  //class mock javascript idle service
-  var idleServiceObj = {
-    observers: [],
-    windowObservers: [],
-    idleTimeInMS: 5000,   //in milli seconds
-
-    // takes note of the idle observers added as the minimum idle observer
-    //with the idle service
-    timesAdded: [],
-
-    QueryInterface: function(iid) {
-      if (iid.equals(Ci.nsISupports) ||
-          iid.equals(Ci.nsIFactory) ||
-          iid.equals(Ci.nsIIdleService)) {
-        return this;
-      }
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    },
-
-    createInstance: function(outer, iid) {
-      return this.QueryInterface(iid);
-    },
-
-    get idleTime() {
-      return this.idleTimeInMS; //in milli seconds
-    },
-
-    set idleTime(timeInMS) {
-      this.idleTimeInMS = timeInMS;
-    },
-
-    getWindowFromObserver: function(observer) {
-      try {
-        var interfaceRequestor = observer.QueryInterface(Ci.nsIInterfaceRequestor);
-        var window = interfaceRequestor.getInterface(Ci.nsIDOMWindow);
-        return window;
-      }
-      catch (e) {}
-
-      return null;
-    },
-
-    testIdleBackService: function(observer, topic) {
-      dump("\nJS FAKE IDLE SERVICE\n");
-      dump("JS NUM OBSERVERS: " + this.observers.length + "\n");
-
-      if (this.observers.length > 1) {
-        this.observers[1].observer.observe(observer, topic, '\0');
-        dump("JS CALLED OBSERVE FUNCTION!!!\n\n");
-      }
-    },
-
-    addIdleObserver: function(observer, time) {
-      dump("\nJS FAKE IDLE SERVICE add idle observer before\n");
-      dump("JS NUM OBSERVERS: " + this.observers.length + "\n");
-      var window = this.getWindowFromObserver(observer);
-
-      if (window) {
-        this.observers.push({ observer: observer, time: time, });
-        addedIdleObserver = true;
-        numIdleObserversAdded++;
-        this.timesAdded.push(time);
-        dump ("\nMOCK IDLE SERVICE ADDING idle observer with time: " + time + "\n");
-        dump("MOCK IDLE SERVICE: num idle observers added: " + numIdleObserversAdded + "\n\n");
-      }
-      else {
-        dump("SHOULD NEVER GET HERE!");
-        oldIdleService.addIdleObserver(observer, time);
-        addedIdleObserver = false;
-      }
-
-      dump("\nJS FAKE IDLE SERVICE end of add idle observer\n");
-      dump("JS NUM OBSERVERS: " + this.observers.length + "\n");
-    },
-
-    removeIdleObserver: function(observer, time) {
-      dump("\nJS REMOVE IDLE OBSERVER () time to be removed: " + time + "\n");
-      var window = this.getWindowFromObserver(observer);
-      if (!window) {
-        oldIdleService.removeIdleObserver(observer, time);
-      }
-      else {
-        var observerIndex = -1;
-        for (var i=0; i<this.observers.length; i++) {
-          dump("JS removeIdleObserver() observer time: " + this.observers[i].time + "\n");
-          if (this.observers[i].time === time) {
-              observerIndex = i;
-              break;
-          }
-         }
-
-        if (observerIndex != -1 && this.observers.length > 0) {
-          numIdleObserversRemoved++;
-          this.observers.splice(observerIndex, 1);
-          removedIdleObserver = true;
-          dump("MOCK IDLE SERVICE REMOVING idle observer with time " + time + "\n");
-          dump("MOCK IDLE SERVICE numIdleObserversRemoved: " + numIdleObserversRemoved + " numIdleObserversAdded: " + numIdleObserversAdded + "\n\n");
-        }
-        else {
-          removedIdleObserver = false;
-        }
-      }
-      dump("\nJS FAKE IDLE SERVICE end of remove idle observer\n");
-      dump("JS NUM OBSERVERS: " + this.observers.length + "\n");
-    },
-  };
-
-  /** Test for Bug 715041 **/
-  dump("\n\n\nJS STARTING TESTING FOR BUG 715041 REMOVAL\n");
-
-  //bool variables
-  var addedIdleObserver = removedIdleObserver = passed = cleanUp = false;
-
-  //msgXCount
-  var msg0Count = msg1Count = msg2Count = msg3Count = msg4Count = msg5Count =
-      msg6Count = tcZero = currTestCaseNum = prevMsgNum = 0;
-
-  //test case number
-  var tcRemoveHeadIdleObserverWhileActive = 0;
-  var tcRemoveLocalIdleObserverWhileIdle = 1;
-  var tcRemoveHeadIdleObserver = 2;
-  var tcRemoveLocalIdleTimerWhileIdle = 3;
-  var tcRemoveLocalIdleTimerLastElement = 4;
-  var tcRemoveHeadAfterLastLocalFired = 5;
-  var tcRemoveHeadIdleObserverWhileIdleCase1 = 6;
-  var tcRemoveLastAddLast = 7;
-
-  function ResetMsgCounts() {
-    msg0Count = msg1Count = msg2Count = msg3Count = msg4Count = msg5Count =
-    msg6Count = prevMsgNum = 0;
-  }
-
-  function ResetVars() {
-    msg0Count = msg1Count = msg2Count = msg3Count = msg4Count = msg5Count =
-    msg6Count = prevMsgNum = 0;
-
-    numIdleObserversAdded = numIdleObserversRemoved = 0;
-    currTestCaseNum = -1;
-    addedIdleObserver = removedIdleObserver = passed = cleanUp = false;
-  }
-
-  function printVariableValues()
-  {
-    dump("\nfunction printVariableValues()\ncurrTestCaseNum: " + currTestCaseNum +
-          "\ncleanUp: " + cleanUp +
-          "\npassed: " + passed +
-          "\nnumIdleObserversRemoved: " + numIdleObserversRemoved +
-          "\nnumIdleObservesAdded: " + numIdleObserversAdded +
-          "\nmsg1Count " + msg1Count +
-          "\nmsg2Count " + msg2Count +
-          "\nmsg3Count " + msg3Count +
-          "\nmsg4Count " + msg4Count +
-          "\nmsg5Count " + msg5Count +
-          "\n");
-  }
-
-  //Place Holder.
-  var idleHandler0 = function() { dump("msg 0, should never be used!\n"); };
-
-  //idleHandler1
-  function idleHandler1() {
-    msg1Count++;
-    dump("msg 1 Count: " + msg1Count + "\n");
-
-    switch (currTestCaseNum) {
-    case tcRemoveHeadIdleObserver:
-      if (msg1Count === 1 && !msg2Count && !msg3Count && !msg4Count && !msg5Count) {
-        window.navigator.removeIdleObserver(idleObserversArray[1]);
-      }
-      break;
-    case tcRemoveLocalIdleObserverWhileIdle:
-      if (msg1Count === 1 && !msg2Count && !msg3Count && !msg4Count) {
-        window.navigator.removeIdleObserver(idleObserversArray[2]);
-      }
-      break;
-    case tcRemoveLocalIdleTimerWhileIdle:
-      if (msg1Count === 1 && !msg2Count && !msg3Count && !msg4Count) {
-        idleServiceObj.idleTime = 2000;
-        window.navigator.removeIdleObserver(idleObserversArray[3]);
-      }
-      break;
-    case tcRemoveHeadIdleObserverWhileIdleCase1:
-      if (msg1Count === 1 && !msg2Count && !msg3Count && !msg4Count) {
-        for (var i=1; i<4; i++) {
-          window.navigator.addIdleObserver(idleObserversArray[i]);
-        }
-        window.navigator.addIdleObserver(idleObserversArray[2]);
-        window.navigator.addIdleObserver(idleObserversArray[3]);
-
-        idleServiceObj.idleTime = 1200;
-        window.navigator.removeIdleObserver(idleObserversArray[1]);
-      }
-      break;
-    case tcRemoveLocalIdleTimerLastElement:
-      if (msg1Count === 1 && !msg2Count && !msg3Count && !msg4Count && !msg5Count) {
-        idleServiceObj.idleTime = 1500;
-        window.navigator.removeIdleObserver(idleObserversArray[1]);
-        idleServiceObj.idleTime = 1700;
-        window.navigator.addIdleObserver(idleObserversArray[2]);
-        idleServiceObj.idleTime = 2000;
-        idleServiceObj.testIdleBackService(idleObserversArray[2], "idle");
-      }
-      break;
-    case tcRemoveHeadAfterLastLocalFired:
-      if (msg1Count === 1 && !msg2Count && !msg3Count && !msg4Count && !msg5Count) {
-        dump("idle handler 1:     case tcRemoveHeadAfterLastLocalFired:\n");
-        window.navigator.addIdleObserver(idleObserversArray[2]);
-        window.navigator.addIdleObserver(idleObserversArray[3]);
-        window.navigator.addIdleObserver(idleObserversArray[4]);
-      }
-      break;
-    case tcRemoveLastAddLast:
-      window.navigator.addIdleObserver(idleObserversArray[2]);
-      window.navigator.addIdleObserver(idleObserversArray[3]);
-      break;
-    default:
-      break;
-    }
-  }
-
-  //idleHandler2
-  function idleHandler2() {
-    msg2Count++;
-    dump("msg 2 Count: " + msg2Count + "\n");
-
-    switch (currTestCaseNum) {
-    case tcRemoveLocalIdleTimerLastElement:
-      if (msg1Count === 1 && msg2Count === 1 && !msg3Count && !msg4Count) {
-        window.navigator.addIdleObserver(idleObserversArray[3]);
-        window.navigator.addIdleObserver(idleObserversArray[4]);
-        window.navigator.removeIdleObserver(idleObserversArray[3]);
-      }
-      break;
-    default:
-      //do nothing.
-      break;
-    }
-  }
-
-  //idleHandler3
-  function idleHandler3() {
-    msg3Count++;
-    dump("msg 3 Count: " + msg3Count + "\n");
-    passed = false;
-    switch (currTestCaseNum) {
-    case tcRemoveHeadIdleObserverWhileActive:
-      if (!msg1Count && msg2Count === 1 && msg3Count === 1) {
-        passed = true;
-      }
-      dump("idleHandler3: passed: " + passed + "\n");
-      RemoveHeadIdleObserverWhileActiveCleanUp();
-      break;
-    case tcRemoveHeadIdleObserverWhileIdleCase1:
-      if (msg3Count != 2 && msg3Count != 4) {
-        return;
-      }
-
-      if (msg1Count === 2 && msg2Count === 2 && msg3Count === 2 && !msg4Count) {
-        passed = true;
-        ok(passed, "Failed test case remove head idle observer while idle case 1, part 1.\n");
-        idleServiceObj.testIdleBackService(idleObserversArray[1], "active");
-        return;
-      }
-
-      if (msg1Count === 3 && msg2Count === 4 && msg3Count === 4 &&
-        !msg4Count && !msg5Count) {
-        passed = true;
-      }
-      RemoveHeadIdleObserverWhileIdleCase1CleanUp();
-      break;
-    case tcRemoveLastAddLast:
-      if (msg1Count === 1 && msg2Count === 1 && msg3Count === 1
-          && !msg4Count && !msg5Count) {
-        idleServiceObj.idleTime = 3200;
-        window.navigator.removeIdleObserver(idleObserversArray[3]);
-        idleServiceObj.idleTime = 3500;
-        window.navigator.addIdleObserver(idleObserversArray[4]);
-        return;
-      }
-      break;
-    case tcRemoveHeadAfterLastLocalFired:
-      if (msg3Count === 1) {
-        return;
-      }
-
-      if (msg1Count === 2 && msg2Count === 2 && msg3Count === 2 && msg4Count === 1) {
-        passed = true;
-      }
-      RemoveHeadAfterLastLocalFiredCleanUp();
-      break;
-    default:
-      break;
-    }
-  }
-
-  //idleHandler4
-  function idleHandler4() {
-    msg4Count++;
-    dump("msg 4 Count: " + msg4Count + "\n");
-
-    switch (currTestCaseNum) {
-    case tcRemoveLocalIdleObserverWhileIdle:
-      if (msg1Count === 1 && !msg2Count && msg3Count === 1 && msg4Count === 1) {
-        passed = true;
-        RemoveLocalIdleObserverWhileIdleCleanUp();
-      }
-      break;
-    case tcRemoveHeadIdleObserver:
-      printVariableValues();
-      if (msg1Count === 1 && msg2Count === 1 && msg3Count === 1 && msg4Count === 1) {
-        passed = true;
-        RemoveHeadIdleObserverCleanUp();
-      }
-      break;
-    case tcRemoveLocalIdleTimerWhileIdle:
-      if (msg1Count === 1 && !msg2Count && !msg3Count && msg4Count === 1) {
-        passed = true;
-        RemoveLocalIdleTimerWhileIdleCleanUp();
-      }
-      break
-    case tcRemoveLocalIdleTimerLastElement:
-      if (msg1Count === 1 && msg2Count === 1 && !msg3Count && msg4Count === 1) {
-        passed = true;
-        ok(passed, "Failed test case remove local idle timer last element.\n");
-        RemoveLocalIdleTimerLastElementCleanUp();
-      }
-    break;
-    case tcRemoveHeadAfterLastLocalFired:
-      if (msg1Count === 1 && msg2Count === 1 && msg3Count === 1 && msg4Count === 1) {
-        window.navigator.removeIdleObserver(idleObserversArray[4]);
-        passed = true;
-        ok(passed, "Failed remove head after last local fired.\n");
-        idleServiceObj.testIdleBackService(idleObserversArray[1], "active");
-      }
-      break;
-    case tcRemoveLastAddLast:
-      if (msg1Count === 1 && msg2Count === 1 && msg3Count === 1 && msg4Count == 1) {
-        idleServiceObj.idleTime = 4100;
-        passed = true;
-        RemoveLastAddLastCleanUp();
-      }
-      break;
-    default:
-      //do nothing.
-      break;
-    }
-  }
-
-  //idleHandler5
-  function idleHandler5() {
-    msg5Count++;
-    dump("msg 5 Count: " + msg5Count + "\n");
-
-    switch (currTestCaseNum) {
-
-    default:
-      //do nothing.
-      break;
-    }
-  }
-
-  //idleHandler6
-  function idleHandler6() {
-    dump("msg 6 Count: " + msg6Count + "\n");
-  }
-
-  var  idleObserversArray = [];
-  idleObserversArray[0] = {time: 0, onidle: idleHandler0, onactive: idleHandler0};
-  idleObserversArray[1] = {time: 1, onidle: idleHandler1, onactive: idleHandler1};
-  idleObserversArray[2] = {time: 2, onidle: idleHandler2, onactive: idleHandler2};
-  idleObserversArray[3] = {time: 3, onidle: idleHandler3, onactive: idleHandler3};
-  idleObserversArray[4] = {time: 4, onidle: idleHandler4, onactive: idleHandler4};
-  idleObserversArray[5] = {time: 5, onidle: idleHandler5, onactive: idleHandler5};
-  idleObserversArray[6] = {time: 0, onidle: idleHandler6, onactive: idleHandler6};
-
-  //observers array space holder at index zero
-  idleServiceObj.observers.push( {observer: idleObserversArray[0], time: 0, } );
-
-    /*
-  * - function RemoveHeadIdleObserverWhileActive1()
-  * - Remove head idle observer before the head idle notification is fired by the
-  *   idle service. I.e. remove the head idle observer while the user is active.
-  * - RESULT: prints 2 in 2ms, 3
-  */
-  function RemoveHeadIdleObserverWhileActive() {
-    dump("\n\nTESTING CASE RemoveHeadIdleObserverWhileActive\n");
-    dump("=================================\n");
-
-    ResetVars();
-    currTestCaseNum = tcRemoveHeadIdleObserverWhileActive;
-    idleServiceObj.idleTime = 500;
-
-    window.navigator.addIdleObserver(idleObserversArray[1]);
-    dump("test_bug715041_removal.xul: RemoveHeadIdleObserverWhileActive() idle time " + idleServiceObj.idleTime + "\n");
-    window.navigator.addIdleObserver(idleObserversArray[2]);
-    window.navigator.addIdleObserver(idleObserversArray[3]);
-
-    idleServiceObj.idleTime = 800;
-    window.navigator.removeIdleObserver(idleObserversArray[1]);
-
-    idleServiceObj.idleTime = 1000;
-    idleServiceObj.testIdleBackService(idleObserversArray[2], "idle");
-  }
-
-  function RemoveHeadIdleObserverWhileActiveCleanUp() {
-    dump("\nRemoveHeadIdleObserverWhileActiveCleanUp()\n");
-    dump("=====================================\n");
-
-    dump("Passed: " + passed + "\n");
-    ok(passed, "Failed test case: RemoveHeadIdleObserverWhileActive");
-
-    ResetVars();
-    currTestCaseNum = tcRemoveHeadIdleObserverWhileActive;
-    idleServiceObj.idleTime = 3500;
-
-    for (var i=2; i<4; i++) {
-      window.navigator.removeIdleObserver(idleObserversArray[i]);
-    }
-
-    dump("JS RemoveHeadIdleObserverWhileActiveCleanUp() DONE\n");
-    if (RemoveLocalIdleObserverWhileIdleEnabled) {
-        RemoveLocalIdleObserverWhileIdle();
-    }
-    else {
-      dump("Finishing testing idle API.\n");
-      SimpleTest.finish();
-    }
-  }
-
-  /*
-  * function RemoveLocalIdleObserverWhileIdle()
-  * Remove local observer before the local oberver at index 1 is triggered while
-  * the user is idle.
-  * RESULT: should print 1, 3, 4
-  */
-  function RemoveLocalIdleObserverWhileIdle() {
-    dump("\n\nTESTING CASE RemoveLocalIdleObserverWhileIdle\n");
-    dump("=================================\n");
-
-    ResetVars();
-    currTestCaseNum = tcRemoveLocalIdleObserverWhileIdle;
-    idleServiceObj.idleTime = 500;
-
-    window.navigator.addIdleObserver(idleObserversArray[1]);
-    window.navigator.addIdleObserver(idleObserversArray[2]);
-    window.navigator.addIdleObserver(idleObserversArray[3]);
-    window.navigator.addIdleObserver(idleObserversArray[4]);
-
-    idleServiceObj.idleTime = 1000;
-    idleServiceObj.testIdleBackService(idleObserversArray[1], "idle");
-  }
-
-  function RemoveLocalIdleObserverWhileIdleCleanUp()  {
-    dump("\nRemoveLocalIdleObserverWhileIdleCleanUp()\n");
-    dump("=====================================\n");
-
-    ok(passed, "Failed test case: RemoveLocalIdleObserverWhileIdleCleanUp()");
-
-    ResetVars();
-    currTestCaseNum = tcRemoveHeadIdleObserverWhileActive;
-    idleServiceObj.idleTime = 3500;
-
-    window.navigator.removeIdleObserver(idleObserversArray[1]);
-    window.navigator.removeIdleObserver(idleObserversArray[3]);
-    window.navigator.removeIdleObserver(idleObserversArray[4]);
-
-    dump("JS RemoveLocalIdleObserverWhileIdleCleanUp() DONE\n");
-    if (RemoveHeadIdleObserverEnabled) {
-      RemoveHeadIdleObserver();
-    }
-    else {
-      dump("Finishing testing idle API.\n");
-      SimpleTest.finish();
-    }
-  }
-
-
-  /*
-   * function RemoveHeadIdleObserver()
-   * Remove head idle observer while the user has been idle for 2400 ms.
-   * - RESULT: prints 1, 2, remove 2, 3, 4
-   */
-  function RemoveHeadIdleObserver() {
-    dump("\n\nTESTING CASE RemoveHeadIdleObserver\n");
-    dump("=================================\n");
-
-    ResetVars();
-    currTestCaseNum = tcRemoveHeadIdleObserver;
-    idleServiceObj.idleTime = 500;
-
-    window.navigator.addIdleObserver(idleObserversArray[1]);
-    window.navigator.addIdleObserver(idleObserversArray[2]);
-    window.navigator.addIdleObserver(idleObserversArray[3]);
-    window.navigator.addIdleObserver(idleObserversArray[4]);
-
-    idleServiceObj.idleTime = 1000;
-    idleServiceObj.testIdleBackService(idleObserversArray[1], "idle");
-  }
-
-  function RemoveHeadIdleObserverCleanUp()  {
-    dump("\nRemoveHeadIdleObserverCleanUp()\n");
-    dump("=====================================\n");
-
-    ok(passed, "Failed test case: RemoveHeadIdleObserverCleanUp()");
-
-    ResetVars();
-    currTestCaseNum = tcRemoveHeadIdleObserver;
-    idleServiceObj.idleTime = 3500;
-
-    for (var i=2; i<5; i++) {
-      window.navigator.removeIdleObserver(idleObserversArray[i]);
-    }
-
-    dump("JS RemoveHeadIdleObserverCleanUp() DONE\n");
-    if (RemoveLocalIdleTimerWhileIdleEnabled) {
-      RemoveLocalIdleTimerWhileIdle();
-    }
-    else {
-      dump("Finishing testing idle API.\n");
-      SimpleTest.finish();
-    }
-  }
-
-  /*
-   * RemoveLocalIdleTimerWhileIdle()
-   * - Removes the idle observer that is also set as the current local idle timer callback
-   *   local idle observer being removed is NOT at index 1!
-   * - RESULT: should trigger 1 in 1ms and 4 in 4ms
-   */
-  function RemoveLocalIdleTimerWhileIdle()
-  {
-    dump("\n\nTESTING CASE RemoveLocalIdleTimerWhileIdle\n");
-    dump("=================================\n");
-
-    ResetVars();
-    currTestCaseNum = tcRemoveLocalIdleTimerWhileIdle;
-    idleServiceObj.idleTime = 500;
-
-    window.navigator.addIdleObserver(idleObserversArray[1]);
-    window.navigator.addIdleObserver(idleObserversArray[3]);
-    window.navigator.addIdleObserver(idleObserversArray[4]);
-
-    idleServiceObj.idleTime = 1000;
-    idleServiceObj.testIdleBackService(idleObserversArray[1], "idle");
-  }
-
-  function RemoveLocalIdleTimerWhileIdleCleanUp()
-  {
-    dump("\nRemoveLocalIdleTimerWhileIdleCleanUp()\n");
-    dump("=====================================\n");
-
-    ok(passed, "Failed test case: RemoveLocalIdleTimerWhileIdleCleanUp()");
-
-    ResetVars();
-    currTestCaseNum = tcRemoveLocalIdleTimerWhileIdle;
-
-    window.navigator.removeIdleObserver(idleObserversArray[1]);
-    window.navigator.removeIdleObserver(idleObserversArray[4]);
-
-    dump("JS RemoveLocalIdleTimerWhileIdleCleanUp() DONE\n");
-    if (RemoveLocalIdleTimerLastElementEnabled) {
-        RemoveLocalIdleTimerLastElement();
-    }
-    else {
-      dump("Finishing testing idle API.\n");
-      SimpleTest.finish();
-    }
-  }
-
-  /*
-   * function RemoveLocalIdleTimerLastElement()
-   */
-  function RemoveLocalIdleTimerLastElement()
-  {
-    dump("\n\nTESTING CASE RemoveLocalIdleTimerLastElement\n");
-    dump("=================================\n");
-
-    ResetVars();
-    currTestCaseNum = tcRemoveLocalIdleTimerLastElement;
-    idleServiceObj.idleTime = 1200;
-
-    window.navigator.addIdleObserver(idleObserversArray[1]);
-    idleServiceObj.testIdleBackService(idleObserversArray[1], "idle");
-  }
-
-  function RemoveLocalIdleTimerLastElementCleanUp() {
-    dump("\nRemoveLocalIdleTimerLastElementCleanUp()\n");
-    dump("=====================================\n");
-
-    ok(passed, "Failed test case: RemoveLocalIdleTimerLastElementCleanUp()");
-
-    ResetVars();
-    currTestCaseNum = tcRemoveLocalIdleTimerLastElement;
-    window.navigator.removeIdleObserver(idleObserversArray[2]);
-    window.navigator.removeIdleObserver(idleObserversArray[4]);
-
-    dump("JS RemoveLocalIdleTimerLastElementCleanUp() DONE\n");
-    if (RemoveHeadAfterLastLocalFiredEnabled) {
-      RemoveHeadAfterLastLocalFired();
-    }
-    else {
-      dump("Finishing testing idle API.\n");
-      SimpleTest.finish();
-    }
-  }
-
-  /*
-   - Remove the head after the last local idle timer has been fired
-   - add 1 2 3 4
-   - after 4 has been notified, removed idle observer with time 4
-   - send a back topic
-   - message notification should be 1, 2, 3.
-  */
-  function RemoveHeadAfterLastLocalFired()
-  {
-    dump("\n\nTESTING CASE RemoveHeadAfterLastLocalFired\n");
-    dump("=================================\n");
-
-    ResetVars();
-    currTestCaseNum = tcRemoveHeadAfterLastLocalFired;
-    idleServiceObj.idleTime = 1200;
-
-    window.navigator.addIdleObserver(idleObserversArray[1]);
-    idleServiceObj.testIdleBackService(idleObserversArray[1], "idle");
-  }
-
-  function RemoveHeadAfterLastLocalFiredCleanUp() {
-    dump("\RemoveHeadAfterLastLocalFiredCleanUp()\n");
-    dump("=====================================\n");
-
-    ok(passed, "Failed test case: RemoveHeadAfterLastLocalFiredCleanUp()");
-
-    ResetVars();
-    currTestCaseNum = tcRemoveHeadAfterLastLocalFired;
-
-    window.navigator.removeIdleObserver(idleObserversArray[1]);
-    window.navigator.removeIdleObserver(idleObserversArray[2]);
-    window.navigator.removeIdleObserver(idleObserversArray[3]);
-
-    dump("JS RemoveHeadAfterLastLocalFiredCleanUp() DONE\n");
-    if (RemoveHeadIdleObserverWhileIdleCase1Enabled) {
-      RemoveHeadIdleObserverWhileIdleCase1();
-    }
-    else {
-      dump("Finishing testing idle API.\n");
-      SimpleTest.finish();
-    }
-  }
-
-  function RemoveHeadIdleObserverWhileIdleCase1() {
-    dump("\n\nTESTING CASE RemoveHeadIdleObserverWhileIdleCase1\n");
-    dump("=================================\n");
-
-    ResetVars();
-    currTestCaseNum = tcRemoveHeadIdleObserverWhileIdleCase1;
-    idleServiceObj.idleTime = 1000;
-    window.navigator.addIdleObserver(idleObserversArray[1]);
-    idleServiceObj.testIdleBackService(idleObserversArray[1], "idle");
-  }
-
-  function RemoveHeadIdleObserverWhileIdleCase1CleanUp() {
-    dump("\nRemoveHeadIdleObserverWhileIdleCase1CleanUp()\n");
-    dump("=====================================\n");
-
-    ok(passed, "Failed test case: RemoveHeadIdleObserverWhileIdleCase1CleanUp()");
-
-    ResetVars();
-    currTestCaseNum = tcRemoveHeadIdleObserverWhileIdleCase1;
-
-    for (var i=1; i<4; i++) {
-      window.navigator.removeIdleObserver(idleObserversArray[i]);
-    }
-
-    window.navigator.removeIdleObserver(idleObserversArray[2]);
-    window.navigator.removeIdleObserver(idleObserversArray[3]);
-
-    dump("JS RemoveHeadIdleObserverWhileIdleCase1CleanUp() DONE\n");
-    if (RemoveLastAddLastEnabled) {
-      RemoveLastAddLast();
-    }
-    else {
-      dump("Finishing testing idle API.\n");
-      SimpleTest.finish();
-    }
-  }
-
-  /*
-   * - RemoveLastAddLast()
-   *
-   * - User is currently idle.
-   * - Add callback 1, 2, 3,
-   * - Remove callback 3 after 3200 MS. I.e. after callback 3 has been notified.
-   * - Add callback 4 after 3500 MS
-   * - Output: 1, 2, 3, 4
-   */
-  function RemoveLastAddLast()
-  {
-    dump("\n\nTESTING CASE RemoveLastAddLast()\n");
-    dump("=================================\n");
-
-    ResetVars();
-    currTestCaseNum = tcRemoveLastAddLast;
-    idleServiceObj.idleTime = 1000;
-    window.navigator.addIdleObserver(idleObserversArray[1]);
-    idleServiceObj.testIdleBackService(idleObserversArray[1], "idle");
-  }
-
-  function RemoveLastAddLastCleanUp()
-  {
-    dump("\RemoveLastAddLastCleanUp()\n");
-    dump("=====================================\n");
-
-    ok(passed, "Failed test case: RemoveLastAddLastCleanUp()");
-
-    ResetVars();
-    currTestCaseNum = tcRemoveLastAddLast;
-
-    window.navigator.removeIdleObserver(idleObserversArray[1]);
-    window.navigator.removeIdleObserver(idleObserversArray[2]);
-    window.navigator.removeIdleObserver(idleObserversArray[4]);
-
-    if (numIdleObserversRemoved === 1 && !numIdleObserversAdded) {
-      ok(true, "Failed test case: RemoveLastAddLastCleanUp()");
-    }
-    else {
-      ok(false, "Failed test case: RemoveLastAddLastCleanUp()");
-    }
-
-
-    try {
-      componentMgr.unregisterFactory(idleServiceCID, idleServiceObj);
-    }
-    catch(err) {
-      dump("test_bug715041_removal.xul: RemoveLastAddLastCleanUp() Failed to unregister factory, mock idle service!\n");
-    }
-
-    try {
-      componentMgr.registerFactory(oldIdleServiceCID, "Re registering old idle service", idleServiceContractID, null);
-    }
-    catch(err) {
-      dump("test_bug715041_removal.xul: RemoveLastAddLastCleanUp() Failed to register factory, original idle service!\n");
-    }
-
-    dump("JS RemoveLastAddLastCleanUp() DONE\n");
-    dump("Finishing testing idle API.\n");
-    SimpleTest.finish();
-  }
-
-
-  // Registering new moch JS idle service
-  SimpleTest.waitForExplicitFinish();
-  SimpleTest.requestLongerTimeout(10);
-
-  try {
-    var idleServiceCID = Components.ID("0fdc1bbf-3868-4660-9855-0c2e376922bc");
-    var idleServiceContractID = "@mozilla.org/widget/idleservice;1";
-    var oldIdleService = Cc[idleServiceContractID].getService(Ci.nsIIdleService);
-  }
-  catch(ex) {
-    dump("test_bug715041_removal.xul: 1) Failed to get old idle service.\n");
-  }
-
-  try {
-    // Registering new moch JS idle service
-    var componentMgr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-  }
-  catch(err) {
-    dump("test_bug715041_removal.xul: Failed to query component registrar interface.\n");
-  }
-
-  try {
-    var oldIdleServiceFactoryObj = componentMgr.getClassObjectByContractID(idleServiceContractID, Ci.nsIFactory);
-  }
-  catch(err) {
-    dump("test_bug715041_removal.xul: Failed to get old idle service.\n");
-  }
-
-  try {
-    var oldIdleServiceCID = componentMgr.contractIDToCID(idleServiceContractID);
-  }
-  catch(err) {
-    dump("test_bug715041._removalxul: Failed to convert ID to CID for old idle service.\n");
-  }
-
-  try {
-    componentMgr.registerFactory(idleServiceCID, "Test Simple Idle/Back Notifications", idleServiceContractID, idleServiceObj);
-  }
-  catch(err) {
-    dump("test_bug715041_removal.xul: Failed to register mock idle service.\n");
-  }
-
-  //test case enabled
-  var RemoveLocalIdleObserverWhileIdleEnabled = true;
-  var RemoveHeadIdleObserverEnabled = true;
-  var RemoveLocalIdleTimerWhileIdleEnabled = true;
-  var RemoveLocalIdleTimerLastElementEnabled = true;
-  var RemoveHeadAfterLastLocalFiredEnabled = true;
-  var RemoveHeadIdleObserverWhileIdleCase1Enabled = true;
-  var RemoveLastAddLastEnabled = true;
-  SpecialPowers.pushPrefEnv({"set":[['dom.idle-observers-api.fuzz_time.disabled', true]]}, RemoveHeadIdleObserverWhileActive);
-]]>
-    </script>
-    </window>
-
--- a/dom/cache/CacheTypes.ipdlh
+++ b/dom/cache/CacheTypes.ipdlh
@@ -82,17 +82,17 @@ struct CacheResponse
   ResponseType type;
   nsCString[] urlList;
   uint32_t status;
   nsCString statusText;
   HeadersEntry[] headers;
   HeadersGuardEnum headersGuard;
   CacheReadStreamOrVoid body;
   IPCChannelInfo channelInfo;
-  OptionalPrincipalInfo principalInfo;
+  PrincipalInfo? principalInfo;
   uint32_t paddingInfo;
   int64_t paddingSize;
 };
 
 union CacheResponseOrVoid
 {
   void_t;
   CacheResponse;
--- a/dom/cache/DBSchema.cpp
+++ b/dom/cache/DBSchema.cpp
@@ -2211,20 +2211,19 @@ nsresult InsertEntry(mozIStorageConnecti
                                 securityId);
   }
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsAutoCString serializedInfo;
   // We only allow content serviceworkers right now.
-  if (aResponse.principalInfo().type() ==
-      mozilla::ipc::OptionalPrincipalInfo::TPrincipalInfo) {
+  if (aResponse.principalInfo().isSome()) {
     const mozilla::ipc::PrincipalInfo& principalInfo =
-        aResponse.principalInfo().get_PrincipalInfo();
+        aResponse.principalInfo().ref();
     MOZ_DIAGNOSTIC_ASSERT(principalInfo.type() ==
                           mozilla::ipc::PrincipalInfo::TContentPrincipalInfo);
     const mozilla::ipc::ContentPrincipalInfo& cInfo =
         principalInfo.get_ContentPrincipalInfo();
 
     serializedInfo.Append(cInfo.spec());
 
     nsAutoCString suffix;
@@ -2464,17 +2463,17 @@ nsresult ReadResponse(mozIStorageConnect
   }
 
   nsAutoCString serializedInfo;
   rv = state->GetUTF8String(5, serializedInfo);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  aSavedResponseOut->mValue.principalInfo() = void_t();
+  aSavedResponseOut->mValue.principalInfo() = Nothing();
   if (!serializedInfo.IsEmpty()) {
     nsAutoCString specNoSuffix;
     OriginAttributes attrs;
     if (!attrs.PopulateFromOrigin(serializedInfo, specNoSuffix)) {
       NS_WARNING("Something went wrong parsing a serialized principal!");
       return NS_ERROR_FAILURE;
     }
 
@@ -2490,18 +2489,18 @@ nsresult ReadResponse(mozIStorageConnect
 #endif
 
     nsCString origin;
     url->Origin(origin);
 
     // CSP is recovered from the headers, no need to initialise it here.
     nsTArray<mozilla::ipc::ContentSecurityPolicy> policies;
     aSavedResponseOut->mValue.principalInfo() =
-        mozilla::ipc::ContentPrincipalInfo(attrs, origin, specNoSuffix,
-                                           Nothing(), std::move(policies));
+        Some(mozilla::ipc::ContentPrincipalInfo(
+            attrs, origin, specNoSuffix, Nothing(), std::move(policies)));
   }
 
   bool nullPadding = false;
   rv = state->GetIsNull(6, &nullPadding);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
--- a/dom/cache/TypeUtils.cpp
+++ b/dom/cache/TypeUtils.cpp
@@ -187,19 +187,19 @@ void TypeUtils::ToCacheResponseWithoutBo
   if (HasVaryStar(headers)) {
     aRv.ThrowTypeError<MSG_RESPONSE_HAS_VARY_STAR>();
     return;
   }
   ToHeadersEntryList(aOut.headers(), headers);
   aOut.headersGuard() = headers->Guard();
   aOut.channelInfo() = aIn.GetChannelInfo().AsIPCChannelInfo();
   if (aIn.GetPrincipalInfo()) {
-    aOut.principalInfo() = *aIn.GetPrincipalInfo();
+    aOut.principalInfo() = Some(*aIn.GetPrincipalInfo());
   } else {
-    aOut.principalInfo() = void_t();
+    aOut.principalInfo() = Nothing();
   }
 
   aOut.paddingInfo() = aIn.GetPaddingInfo();
   aOut.paddingSize() = aIn.GetPaddingSize();
 }
 
 void TypeUtils::ToCacheResponse(
     JSContext* aCx, CacheResponse& aOut, Response& aIn,
@@ -268,20 +268,19 @@ already_AddRefed<Response> TypeUtils::To
   // Be careful to fill the headers before setting the guard in order to
   // correctly re-create the original headers.
   ir->Headers()->Fill(*internalHeaders, result);
   MOZ_DIAGNOSTIC_ASSERT(!result.Failed());
   ir->Headers()->SetGuard(aIn.headersGuard(), result);
   MOZ_DIAGNOSTIC_ASSERT(!result.Failed());
 
   ir->InitChannelInfo(aIn.channelInfo());
-  if (aIn.principalInfo().type() ==
-      mozilla::ipc::OptionalPrincipalInfo::TPrincipalInfo) {
-    UniquePtr<mozilla::ipc::PrincipalInfo> info(new mozilla::ipc::PrincipalInfo(
-        aIn.principalInfo().get_PrincipalInfo()));
+  if (aIn.principalInfo().isSome()) {
+    UniquePtr<mozilla::ipc::PrincipalInfo> info(
+        new mozilla::ipc::PrincipalInfo(aIn.principalInfo().ref()));
     ir->SetPrincipalInfo(std::move(info));
   }
 
   nsCOMPtr<nsIInputStream> stream = ReadStream::Create(aIn.body());
   ir->SetBody(stream, InternalResponse::UNKNOWN_BODY_SIZE);
 
   switch (aIn.type()) {
     case ResponseType::Basic:
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -4642,18 +4642,25 @@ void CanvasRenderingContext2D::DrawWindo
         mBufferProvider->GetType() != LayersBackend::LAYERS_WR))) {
     thebes = gfxContext::CreateOrNull(mTarget);
     MOZ_ASSERT(thebes);  // already checked the draw target above
                          // (in SupportsAzureContentForDrawTarget)
     thebes->SetMatrix(matrix);
   } else {
     IntSize dtSize = IntSize::Ceil(sw, sh);
     if (!Factory::AllowedSurfaceSize(dtSize)) {
-      aError.Throw(NS_ERROR_FAILURE);
-      return;
+      // attempt to limit the DT to what will actually cover the target
+      Size limitSize(mTarget->GetSize());
+      limitSize.Scale(matrix._11, matrix._22);
+      dtSize = Min(dtSize, IntSize::Ceil(limitSize));
+      // if the DT is still too big, then error
+      if (!Factory::AllowedSurfaceSize(dtSize)) {
+        aError.Throw(NS_ERROR_FAILURE);
+        return;
+      }
     }
     drawDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
         dtSize, SurfaceFormat::B8G8R8A8);
     if (!drawDT || !drawDT->IsValid()) {
       aError.Throw(NS_ERROR_FAILURE);
       return;
     }
 
--- a/dom/chrome-webidl/ChromeUtils.webidl
+++ b/dom/chrome-webidl/ChromeUtils.webidl
@@ -588,16 +588,29 @@ dictionary HeapSnapshotBoundaries {
 };
 
 dictionary Base64URLEncodeOptions {
   /** Specifies whether the output should be padded with "=" characters. */
   required boolean pad;
 };
 
 dictionary WindowActorOptions {
+  /**
+   * If this is set to `true`, allow this actor to be created for subframes,
+   * and not just toplevel window globals.
+   */
+  boolean allFrames = false;
+
+  /**
+   * If this is set to `true`, allow this actor to be created for window
+   * globals loaded in chrome browsing contexts, such as those used to load the
+   * tabbrowser.
+   */
+  boolean includeChrome = false;
+
   /** This fields are used for configuring individual sides of the actor. */
   required WindowActorSidedOptions parent;
   required WindowActorChildOptions child;
 };
 
 dictionary WindowActorSidedOptions {
   /** The module path which should be loaded for the actor on this side. */
   required ByteString moduleURI;
--- a/dom/ipc/JSWindowActorService.cpp
+++ b/dom/ipc/JSWindowActorService.cpp
@@ -115,41 +115,49 @@ class JSWindowActorProtocol final : publ
   };
 
   struct ChildSide : public Sided {
     nsTArray<EventDecl> mEvents;
     nsTArray<nsCString> mObservers;
   };
 
   const nsAString& Name() const { return mName; }
+  bool AllFrames() const { return mAllFrames; }
+  bool IncludeChrome() const { return mIncludeChrome; }
   const ParentSide& Parent() const { return mParent; }
   const ChildSide& Child() const { return mChild; }
 
   void RegisterListenersFor(EventTarget* aRoot);
   void UnregisterListenersFor(EventTarget* aRoot);
   void AddObservers();
   void RemoveObservers();
 
  private:
   explicit JSWindowActorProtocol(const nsAString& aName) : mName(aName) {}
 
   ~JSWindowActorProtocol() = default;
 
   nsString mName;
+  bool mAllFrames = false;
+  bool mIncludeChrome = false;
   ParentSide mParent;
   ChildSide mChild;
 };
 
 NS_IMPL_ISUPPORTS(JSWindowActorProtocol, nsIObserver, nsIDOMEventListener);
 
 /* static */ already_AddRefed<JSWindowActorProtocol>
 JSWindowActorProtocol::FromIPC(const JSWindowActorInfo& aInfo) {
   MOZ_DIAGNOSTIC_ASSERT(XRE_IsContentProcess());
 
   RefPtr<JSWindowActorProtocol> proto = new JSWindowActorProtocol(aInfo.name());
+  // Content processes cannot load chrome browsing contexts, so this flag is
+  // irrelevant and not propagated.
+  proto->mIncludeChrome = false;
+  proto->mAllFrames = aInfo.allFrames();
   proto->mChild.mModuleURI.Assign(aInfo.url());
 
   proto->mChild.mEvents.SetCapacity(aInfo.events().Length());
   for (auto& ipc : aInfo.events()) {
     auto* event = proto->mChild.mEvents.AppendElement();
     event->mName.Assign(ipc.name());
     event->mFlags.mCapture = ipc.capture();
     event->mFlags.mInSystemGroup = ipc.systemGroup();
@@ -163,16 +171,17 @@ JSWindowActorProtocol::FromIPC(const JSW
   return proto.forget();
 }
 
 JSWindowActorInfo JSWindowActorProtocol::ToIPC() {
   MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
 
   JSWindowActorInfo info;
   info.name() = mName;
+  info.allFrames() = mAllFrames;
   info.url() = mChild.mModuleURI;
 
   info.events().SetCapacity(mChild.mEvents.Length());
   for (auto& event : mChild.mEvents) {
     auto* ipc = info.events().AppendElement();
     ipc->name().Assign(event.mName);
     ipc->capture() = event.mFlags.mCapture;
     ipc->systemGroup() = event.mFlags.mInSystemGroup;
@@ -189,16 +198,18 @@ JSWindowActorInfo JSWindowActorProtocol:
 
 already_AddRefed<JSWindowActorProtocol>
 JSWindowActorProtocol::FromWebIDLOptions(const nsAString& aName,
                                          const WindowActorOptions& aOptions,
                                          ErrorResult& aRv) {
   MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
 
   RefPtr<JSWindowActorProtocol> proto = new JSWindowActorProtocol(aName);
+  proto->mAllFrames = aOptions.mAllFrames;
+
   proto->mParent.mModuleURI = aOptions.mParent.mModuleURI;
   proto->mChild.mModuleURI = aOptions.mChild.mModuleURI;
 
   // For each event declared in the source dictionary, initialize the
   // corresponding envent declaration entry in the JSWindowActorProtocol.
   if (aOptions.mChild.mEvents.WasPassed()) {
     auto& entries = aOptions.mChild.mEvents.Value().Entries();
     proto->mChild.mEvents.SetCapacity(entries.Length());
@@ -254,18 +265,24 @@ NS_IMETHODIMP JSWindowActorProtocol::Han
   RefPtr<WindowGlobalChild> wgc = inner->GetWindowGlobalChild();
   if (NS_WARN_IF(!wgc)) {
     return NS_ERROR_FAILURE;
   }
 
   // Ensure our actor is present.
   ErrorResult error;
   RefPtr<JSWindowActorChild> actor = wgc->GetActor(mName, error);
-  if (NS_WARN_IF(error.Failed())) {
-    return error.StealNSResult();
+  if (error.Failed()) {
+    nsresult rv = error.StealNSResult();
+
+    // Don't raise an error if creation of our actor was vetoed.
+    if (rv == NS_ERROR_NOT_AVAILABLE) {
+      return NS_OK;
+    }
+    return rv;
   }
 
   // Call the "handleEvent" method on our actor.
   JS::Rooted<JS::Value> dummy(RootingCx());
   return CallJSActorMethod(actor, "handleEvent", aEvent, &dummy);
 }
 
 NS_IMETHODIMP JSWindowActorProtocol::Observe(nsISupports* aSubject,
@@ -469,16 +486,17 @@ void JSWindowActorService::GetJSWindowAc
 
   for (auto iter = mDescriptors.ConstIter(); !iter.Done(); iter.Next()) {
     aInfos.AppendElement(iter.Data()->ToIPC());
   }
 }
 
 void JSWindowActorService::ConstructActor(const nsAString& aName,
                                           bool aParentSide,
+                                          BrowsingContext* aBrowsingContext,
                                           JS::MutableHandleObject aActor,
                                           ErrorResult& aRv) {
   MOZ_ASSERT_IF(aParentSide, XRE_IsParentProcess());
 
   // Constructing an actor requires a running script, so push an AutoEntryScript
   // onto the stack.
   AutoEntryScript aes(xpc::PrivilegedJunkScope(), "JSWindowActor construction");
   JSContext* cx = aes.cx();
@@ -492,16 +510,28 @@ void JSWindowActorService::ConstructActo
 
   const JSWindowActorProtocol::Sided* side;
   if (aParentSide) {
     side = &proto->Parent();
   } else {
     side = &proto->Child();
   }
 
+  // Check if our current BrowsingContext matches the requirements for this
+  // actor to load.
+  if (!proto->AllFrames() && aBrowsingContext->GetParent()) {
+    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+    return;
+  }
+
+  if (!proto->IncludeChrome() && !aBrowsingContext->IsContent()) {
+    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+    return;
+  }
+
   // Load the module using mozJSComponentLoader.
   RefPtr<mozJSComponentLoader> loader = mozJSComponentLoader::Get();
   MOZ_ASSERT(loader);
 
   JS::RootedObject global(cx);
   JS::RootedObject exports(cx);
   aRv = loader->Import(cx, side->mModuleURI, &global, &exports);
   if (aRv.Failed()) {
--- a/dom/ipc/JSWindowActorService.h
+++ b/dom/ipc/JSWindowActorService.h
@@ -35,16 +35,17 @@ class JSWindowActorService final {
   // Get the named of Window Actor and the child's WindowActorOptions
   // from mDescriptors to JSWindowActorInfos.
   void GetJSWindowActorInfos(nsTArray<JSWindowActorInfo>& aInfos);
 
   // Load the module for the named Window Actor and contruct it.
   // This method will not initialize the actor or set its manager,
   // which is handled by callers.
   void ConstructActor(const nsAString& aName, bool aParentSide,
+                      BrowsingContext* aBrowsingContext,
                       JS::MutableHandleObject aActor, ErrorResult& aRv);
 
   void ReceiveMessage(JS::RootedObject& aObj, const nsString& aMessageName,
                       ipc::StructuredCloneData& aData);
 
   // Register or unregister a WindowRoot object from this JSWindowActorService.
   void RegisterWindowRoot(EventTarget* aRoot);
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -235,16 +235,17 @@ struct JSWindowActorEventDecl
   // encoded as two booleans.
   bool hasPassive;
   bool passive;
 };
 
 struct JSWindowActorInfo
 {
   nsString name;
+  bool allFrames;
   nsCString url;
 
   JSWindowActorEventDecl[] events;
   nsCString[] observers;
 };
 
 struct GMPAPITags
 {
--- a/dom/ipc/WindowGlobalChild.cpp
+++ b/dom/ipc/WindowGlobalChild.cpp
@@ -161,17 +161,18 @@ already_AddRefed<JSWindowActorChild> Win
   // Otherwise, we want to create a new instance of this actor. Call into the
   // JSWindowActorService to trigger construction.
   RefPtr<JSWindowActorService> actorSvc = JSWindowActorService::GetSingleton();
   if (!actorSvc) {
     return nullptr;
   }
 
   JS::RootedObject obj(RootingCx());
-  actorSvc->ConstructActor(aName, /* aChildSide */ false, &obj, aRv);
+  actorSvc->ConstructActor(aName, /* aChildSide */ false, mBrowsingContext,
+                           &obj, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   // Unwrap our actor to a JSWindowActorChild object.
   RefPtr<JSWindowActorChild> actor;
   if (NS_FAILED(UNWRAP_OBJECT(JSWindowActorChild, &obj, actor))) {
     return nullptr;
--- a/dom/ipc/WindowGlobalParent.cpp
+++ b/dom/ipc/WindowGlobalParent.cpp
@@ -204,17 +204,18 @@ already_AddRefed<JSWindowActorParent> Wi
   // Otherwise, we want to create a new instance of this actor. Call into the
   // JSWindowActorService to trigger construction
   RefPtr<JSWindowActorService> actorSvc = JSWindowActorService::GetSingleton();
   if (!actorSvc) {
     return nullptr;
   }
 
   JS::RootedObject obj(RootingCx());
-  actorSvc->ConstructActor(aName, /* aParentSide */ true, &obj, aRv);
+  actorSvc->ConstructActor(aName, /* aParentSide */ true, mBrowsingContext,
+                           &obj, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   // Unwrap our actor to a JSWindowActorParent object.
   RefPtr<JSWindowActorParent> actor;
   if (NS_FAILED(UNWRAP_OBJECT(JSWindowActorParent, &obj, actor))) {
     return nullptr;
--- a/dom/ipc/tests/test_JSWindowActor.xul
+++ b/dom/ipc/tests/test_JSWindowActor.xul
@@ -13,16 +13,17 @@
   <body xmlns="http://www.w3.org/1999/xhtml">
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
   const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
   const URL = "about:blank";
   let windowActorOptions = {
+    allFrames: true,
     parent: {
       moduleURI: "resource://testing-common/TestParent.jsm",
     },
     child: {
       moduleURI: "resource://testing-common/TestChild.jsm",
       observers: [
         "test-js-window-actor-child-observer",
       ],
--- a/dom/media/gmp/GMPServiceChild.h
+++ b/dom/media/gmp/GMPServiceChild.h
@@ -44,17 +44,17 @@ class GeckoMediaPluginServiceChild : pub
 
   void BeginShutdown();
 
  protected:
   void InitializePlugins(AbstractThread*) override {
     // Nothing to do here.
   }
 
-  virtual RefPtr<GetGMPContentParentPromise> GetContentParent(
+  RefPtr<GetGMPContentParentPromise> GetContentParent(
       GMPCrashHelper* aHelper, const nsACString& aNodeIdString,
       const nsCString& aAPI, const nsTArray<nsCString>& aTags) override;
 
   RefPtr<GetGMPContentParentPromise> GetContentParent(
       GMPCrashHelper* aHelper, const NodeId& aNodeId, const nsCString& aAPI,
       const nsTArray<nsCString>& aTags) override;
 
  private:
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -1724,27 +1724,16 @@ mozilla::ipc::IPCResult GMPServiceParent
     const nsString& aGMPName, nsCString* aID) {
   nsresult rv = mService->GetNodeId(aOrigin, aTopLevelOrigin, aGMPName, *aID);
   if (!NS_SUCCEEDED(rv)) {
     return IPC_FAIL_NO_REASON(this);
   }
   return IPC_OK();
 }
 
-class DeleteGMPServiceParent : public mozilla::Runnable {
- public:
-  explicit DeleteGMPServiceParent(GMPServiceParent* aToDelete)
-      : Runnable("gmp::DeleteGMPServiceParent"), mToDelete(aToDelete) {}
-
-  NS_IMETHOD Run() override { return NS_OK; }
-
- private:
-  nsAutoPtr<GMPServiceParent> mToDelete;
-};
-
 void GMPServiceParent::CloseTransport(Monitor* aSyncMonitor, bool* aCompleted) {
   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
 
   MonitorAutoLock lock(*aSyncMonitor);
 
   // This deletes the transport.
   SetTransport(nullptr);
 
--- a/dom/media/gmp/GMPServiceParent.h
+++ b/dom/media/gmp/GMPServiceParent.h
@@ -85,18 +85,16 @@ class GeckoMediaPluginServiceParent fina
 
   nsresult GetNodeId(const nsAString& aOrigin, const nsAString& aTopLevelOrigin,
                      const nsAString& aGMPName, nsACString& aOutId);
 
   void UnloadPlugins();
   void CrashPlugins();
   void NotifySyncShutdownComplete();
 
-  void ProcessPossiblePlugin(nsIFile* aDir);
-
   void RemoveOnGMPThread(const nsAString& aDirectory,
                          const bool aDeleteFromDisk, const bool aCanDefer);
 
   struct DirectoryFilter {
     virtual bool operator()(nsIFile* aPath) = 0;
     ~DirectoryFilter() {}
   };
   void ClearNodeIdAndPlugin(DirectoryFilter& aFilter);
@@ -112,17 +110,17 @@ class GeckoMediaPluginServiceParent fina
  protected:
   friend class GMPParent;
   void ReAddOnGMPThread(const RefPtr<GMPParent>& aOld);
   void PluginTerminated(const RefPtr<GMPParent>& aOld);
   void InitializePlugins(AbstractThread* aAbstractGMPThread) override;
   RefPtr<GenericPromise> LoadFromEnvironment();
   RefPtr<GenericPromise> AddOnGMPThread(nsString aDirectory);
 
-  virtual RefPtr<GetGMPContentParentPromise> GetContentParent(
+  RefPtr<GetGMPContentParentPromise> GetContentParent(
       GMPCrashHelper* aHelper, const nsACString& aNodeIdString,
       const nsCString& aAPI, const nsTArray<nsCString>& aTags) override;
 
   RefPtr<GetGMPContentParentPromise> GetContentParent(
       GMPCrashHelper* aHelper, const NodeId& aNodeId, const nsCString& aAPI,
       const nsTArray<nsCString>& aTags) override;
 
  private:
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -314,16 +314,24 @@ bool PDMFactory::SupportsMimeType(
   return Supports(*trackInfo, aDiagnostics);
 }
 
 bool PDMFactory::Supports(const TrackInfo& aTrackInfo,
                           DecoderDoctorDiagnostics* aDiagnostics) const {
   if (mEMEPDM) {
     return mEMEPDM->Supports(aTrackInfo, aDiagnostics);
   }
+  if (VPXDecoder::IsVPX(aTrackInfo.mMimeType,
+                        VPXDecoder::VP8 | VPXDecoder::VP9)) {
+    // Work around bug 1521370, where trying to instantiate an external decoder
+    // could cause a crash.
+    // We always ship a VP8/VP9 decoder (libvpx) and optionally we have ffvpx.
+    // So we can speed up the test by assuming that this codec is supported.
+    return true;
+  }
   RefPtr<PlatformDecoderModule> current = GetDecoder(aTrackInfo, aDiagnostics);
   return !!current;
 }
 
 void PDMFactory::CreatePDMs() {
   RefPtr<PlatformDecoderModule> m;
 
   if (StaticPrefs::MediaUseBlankDecoder()) {
--- a/dom/network/UDPSocketChild.cpp
+++ b/dom/network/UDPSocketChild.cpp
@@ -79,17 +79,17 @@ UDPSocketChild::Bind(nsIUDPSocketInterna
 
   mSocket = aSocket;
   AddIPDLReference();
 
   if (mBackgroundManager) {
     // If we want to support a passed-in principal here we'd need to
     // convert it to a PrincipalInfo
     MOZ_ASSERT(!aPrincipal);
-    mBackgroundManager->SendPUDPSocketConstructor(this, void_t(), mFilterName);
+    mBackgroundManager->SendPUDPSocketConstructor(this, Nothing(), mFilterName);
   } else {
     if (aMainThreadEventTarget) {
       gNeckoChild->SetEventTargetForActor(this, aMainThreadEventTarget);
     }
     gNeckoChild->SendPUDPSocketConstructor(this, IPC::Principal(aPrincipal),
                                            mFilterName);
   }
 
--- a/dom/tests/mochitest/general/chrome.ini
+++ b/dom/tests/mochitest/general/chrome.ini
@@ -1,8 +1,7 @@
 [DEFAULT]
 skip-if = os == 'android'
 
-[test_idleapi_permissions.html]
 [test_innerScreen.xul]
 [test_offsets.xul]
 support-files = test_offsets.css test_offsets.js
 [test_spacetopagedown.html]
deleted file mode 100644
--- a/dom/tests/mochitest/general/test_idleapi_permissions.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Test for idle api permissions</title>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<p id="display"></p>
-<div id="content" style="display: none">
-</div>
-<pre id="test">
-<script type="application/javascript">
-
-var idleObserver = {
-  onidle: null,
-  onactive: null
-};
-
-function doAddIdleObserver(obs) {
-  var i = document.createElement("iframe");
-  document.body.appendChild(i);
-  var added = false;
-  try {
-    i.contentWindow.navigator.addIdleObserver(obs);
-    added = true;
-  } catch (e) { }
-  i.remove();
-  return added;
-}
-
-function run_test() {
-  // addIdleObserver checks whether time is > 0.
-  this.idleObserver.time = 100;
-
-  SpecialPowers.pushPermissions([{type: "idle", allow: true, context: document}], () => {
-    added = doAddIdleObserver(this.idleObserver, true);
-    ok(added, "Should be able to add idle observer with permission.");
-    SimpleTest.finish();
-  });
-}
-
-SimpleTest.waitForExplicitFinish();
-addLoadEvent(run_test);
-</script>
-</pre>
-</body>
-</html>
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -170,24 +170,16 @@ partial interface Navigator {
      * @param permitted permission state (true for allowing vibration)
      * @param persistent make the permission session-persistent
      */
     [ChromeOnly]
     void setVibrationPermission(boolean permitted,
                                 optional boolean persistent = true);
 };
 
-callback interface MozIdleObserver {
-  // Time is in seconds and is read only when idle observers are added
-  // and removed.
-  readonly attribute unsigned long time;
-  void onidle();
-  void onactive();
-};
-
 partial interface Navigator {
   [Throws, Constant, Cached, NeedsCallerType]
   readonly attribute DOMString oscpu;
   // WebKit/Blink support this; Trident/Presto do not.
   readonly attribute DOMString vendor;
   // WebKit/Blink supports this (hardcoded ""); Trident/Presto do not.
   readonly attribute DOMString vendorSub;
   // WebKit/Blink supports this (hardcoded "20030107"); Trident/Presto don't
@@ -195,28 +187,16 @@ partial interface Navigator {
   // WebKit/Blink/Trident/Presto support this.
   readonly attribute boolean cookieEnabled;
   [Throws, Constant, Cached, NeedsCallerType]
   readonly attribute DOMString buildID;
 
   // WebKit/Blink/Trident/Presto support this.
   [Affects=Nothing, DependsOn=Nothing]
   boolean javaEnabled();
-
-  /**
-   * Navigator requests to add an idle observer to the existing window.
-   */
-  [Throws, ChromeOnly]
-  void addIdleObserver(MozIdleObserver aIdleObserver);
-
-  /**
-   * Navigator requests to remove an idle observer from the existing window.
-   */
-  [Throws, ChromeOnly]
-  void removeIdleObserver(MozIdleObserver aIdleObserver);
 };
 
 // NetworkInformation
 partial interface Navigator {
   [Throws, Pref="dom.netinfo.enabled"]
   readonly attribute NetworkInformation connection;
 };
 
--- a/dom/xslt/tests/XSLTMark/XSLTMark.xul
+++ b/dom/xslt/tests/XSLTMark/XSLTMark.xul
@@ -4,16 +4,17 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
 <?xml-stylesheet href="XSLTMark.css" type="text/css"?>
 <window id="XSLTMarkHarness"
         title="XSLTMark"
         onload="view.onLoad()"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        xmlns:html="http://www.w3.org/1999/xhtml"
         orient="vertical">
 <script type="application/x-javascript" src="XSLTMark-static.js" />
 <script type="application/x-javascript" src="XSLTMark-test.js" />
 <script type="application/x-javascript" src="XSLTMark-view.js" />
 
 <hbox>
   <groupbox orient="horizontal">
     <caption label="test description file" />
@@ -39,14 +40,14 @@
   </groupbox>
 </hbox>
 <hbox>
   <textbox id="currentStatus" readonly="true" flex="1"/>
   <progressmeter id="currentProgress" mode="normal" value="0" flex="2"/>
   <progressmeter id="totalProgress" mode="normal" value="0" flex="2"/>
 </hbox>
 <hbox flex="1">
-  <textbox id="transformOutput" class="out" readonly="true" multiline="true" flex="1"/>
+  <html:textarea id="transformOutput" class="out" readonly="true" flex="1"/>
 </hbox>
 <hbox flex="1">
-  <textbox id="transformDetailedOutput" class="out" readonly="true" multiline="true" flex="1"/>
+  <html:textarea id="transformDetailedOutput" class="out" readonly="true" flex="1"/>
 </hbox>
 </window>
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -1086,38 +1086,43 @@ nsresult nsXULElement::PreHandleEvent(Ev
   return nsStyledElement::PreHandleEvent(aVisitor);
 }
 
 //----------------------------------------------------------------------
 // Implementation methods
 
 nsChangeHint nsXULElement::GetAttributeChangeHint(const nsAtom* aAttribute,
                                                   int32_t aModType) const {
-  nsChangeHint retval(nsChangeHint(0));
-
   if (aAttribute == nsGkAtoms::value &&
       (aModType == MutationEvent_Binding::REMOVAL ||
-       aModType == MutationEvent_Binding::ADDITION)) {
-    if (IsAnyOfXULElements(nsGkAtoms::label, nsGkAtoms::description))
-      // Label and description dynamically morph between a normal
-      // block and a cropping single-line XUL text frame.  If the
-      // value attribute is being added or removed, then we need to
-      // return a hint of frame change.  (See bugzilla bug 95475 for
-      // details.)
-      retval = nsChangeHint_ReconstructFrame;
-  } else {
-    // if left or top changes we reflow. This will happen in xul
-    // containers that manage positioned children such as a stack.
-    if (nsGkAtoms::left == aAttribute || nsGkAtoms::top == aAttribute ||
-        nsGkAtoms::right == aAttribute || nsGkAtoms::bottom == aAttribute ||
-        nsGkAtoms::start == aAttribute || nsGkAtoms::end == aAttribute)
-      retval = NS_STYLE_HINT_REFLOW;
+       aModType == MutationEvent_Binding::ADDITION) &&
+      IsAnyOfXULElements(nsGkAtoms::label, nsGkAtoms::description)) {
+    // Label and description dynamically morph between a normal
+    // block and a cropping single-line XUL text frame.  If the
+    // value attribute is being added or removed, then we need to
+    // return a hint of frame change.  (See bugzilla bug 95475 for
+    // details.)
+    return nsChangeHint_ReconstructFrame;
   }
 
-  return retval;
+  if (aAttribute == nsGkAtoms::type &&
+      IsAnyOfXULElements(nsGkAtoms::toolbarbutton, nsGkAtoms::button)) {
+    // type=menu switches from a button frame to a menu frame.
+    return nsChangeHint_ReconstructFrame;
+  }
+
+  // if left or top changes we reflow. This will happen in xul
+  // containers that manage positioned children such as a stack.
+  if (nsGkAtoms::left == aAttribute || nsGkAtoms::top == aAttribute ||
+      nsGkAtoms::right == aAttribute || nsGkAtoms::bottom == aAttribute ||
+      nsGkAtoms::start == aAttribute || nsGkAtoms::end == aAttribute) {
+    return NS_STYLE_HINT_REFLOW;
+  }
+
+  return nsChangeHint(0);
 }
 
 NS_IMETHODIMP_(bool)
 nsXULElement::IsAttributeMapped(const nsAtom* aAttribute) const {
   return false;
 }
 
 nsIControllers* nsXULElement::GetControllers(ErrorResult& rv) {
--- a/dom/xul/test/test_bug199692.xul
+++ b/dom/xul/test/test_bug199692.xul
@@ -23,17 +23,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   </vbox>
 
 <body id="body" xmlns="http://www.w3.org/1999/xhtml">
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=199692">Mozilla Bug 199692</a>
 
 <vbox id="content" style="position: relative;"
 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <xul:label id="non-anon-label" value="a textbox!:" control="textbox"/>
-  <xul:textbox id="textbox" multiline="true" rows="4" />
+  <html:textarea id="textbox" rows="4"/>
   <xul:radiogroup style="outline: 2px solid orange;">
     <xul:radio id="unselected-radio" label="Orange" style="outline: 2px solid red;"/>
     <xul:radio id="selected-radio" label="Violet" selected="true"/>
     <xul:radio id="disabled-radio" label="Yellow" disabled="true"/>
   </xul:radiogroup>
   <hbox id="bound" style="-moz-binding:url('#anon'); border: 2px solid green;"></hbox>
 </vbox>
 <pre id="test">
@@ -57,37 +57,37 @@ xmlns="http://www.mozilla.org/keymaster/
   function upper_left(e) {
     return { "x": e.getBoundingClientRect().x + d,
              "y": e.getBoundingClientRect().y + d };
   }
   function scrollbar_button(e) { // a bit down from upper right
     return { "x": e.getBoundingClientRect().x + e.getBoundingClientRect().width - d,
              "y": e.getBoundingClientRect().y + d + 15 };
   }
-  
+
   function test(ptFunc, id, message) {
     var pt = ptFunc($(id));
     var e = document.elementFromPoint(pt.x, pt.y);
     ok(e != null, message + " (returned null)");
     is(e.id, id, message);
   }
-  
+
   function do_test() {
     // Avoid hardcoding x,y pixel values, to better deal with differing default
     // font sizes or other layout defaults.
-    
+
     test(middle, 'textbox', "Point within textbox should return textbox element");
     test(lower_right, 'textbox', "Point on textbox's scrollbar should return textbox element");
     test(scrollbar_button, 'textbox', "Point on textbox's scrollbar button should return textbox element");
     test(middle, 'non-anon-label', "Point on label should return label");
     test(upper_left, 'bound', "Point on XBL content should return element with -moz-binding style");
-    
+
     SimpleTest.finish();
   }
-  $("textbox").setAttribute("value", 
+  $("textbox").setAttribute("value",
       "lorem ipsum dolor sit amet " +
       "lorem ipsum dolor sit amet " +
       "lorem ipsum dolor sit amet " +
       "lorem ipsum dolor sit amet " +
       "lorem ipsum dolor sit amet " +
       "lorem ipsum dolor sit amet " +
       "lorem ipsum dolor sit amet "); // force scrollbars to appear
   addLoadEvent(do_test);
deleted file mode 100644
--- a/editor/reftests/xul/emptymultiline-1.xul
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="resource://reftest/input.css" type="text/css"?>
-
-<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-        xmlns:html="http://www.w3.org/1999/xhtml"
-        title="Textbox tests">
-
-  <script type="text/javascript" src="platform.js"/>
-
-  <textbox multiline="true"/>
-      
-</window>
deleted file mode 100644
--- a/editor/reftests/xul/emptymultiline-2.xul
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="resource://reftest/input.css" type="text/css"?>
-
-<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-        xmlns:html="http://www.w3.org/1999/xhtml"
-        title="Textbox tests">
-
-  <script type="text/javascript" src="platform.js"/>
-
-  <textbox multiline="true" rows="10"/>
-      
-</window>
deleted file mode 100644
--- a/editor/reftests/xul/emptymultiline-ref.xul
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="resource://reftest/input.css" type="text/css"?>
-
-<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-        xmlns:html="http://www.w3.org/1999/xhtml"
-        title="Textbox tests">
-
-  <script type="text/javascript" src="platform.js"/>
-
-  <html:textarea rows="10" style="resize: none;"/>
-      
-</window>
--- a/editor/reftests/xul/input.css
+++ b/editor/reftests/xul/input.css
@@ -1,35 +1,23 @@
 @namespace url('http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul');
 @namespace html url('http://www.w3.org/1999/xhtml');
 
-:root > html|input,
-:root > html|textarea {
+:root > html|input {
   margin: 2px 4px;
   padding: 2px 2px 3px;
   padding-inline-start: 5px;
 }
 
-#mac > html|input,
-#mac > html|textarea {
+#mac > html|input {
   margin: 4px;
   padding: 0 1px;
 }
 
-textbox[multiline="true"],
-html|textarea {
-  border: none !important;
-  -moz-appearance: none !important;
-  background-color: white !important;
-  border-top-right-radius: 0;
-  border-bottom-left-radius: 0;
-}
-
-html|input,
-html|textarea {
+html|input {
   font: inherit;
 }
 
 html|input.empty {
   color: graytext;
 }
 
 @media (-moz-windows-default-theme) and (-moz-os-version: windows-win7) {
--- a/editor/reftests/xul/reftest.list
+++ b/editor/reftests/xul/reftest.list
@@ -1,16 +1,14 @@
 fails-if(Android) skip-if(winWidget) == empty-1.xul empty-ref.xul # Windows: bug 1239170
 != empty-2.xul empty-ref.xul
 # There is no way to simulate an autocomplete textbox in windows XP/Vista/7/8/10 default theme using CSS.
 # Therefore, the equlity tests below should be marked as failing.
 fails-if(Android) fails-if(windowsDefaultTheme&&/^Windows\x20NT\x20(5\.[12]|6\.[012]|10\.0)/.test(http.oscpu)) == autocomplete-1.xul autocomplete-ref.xul # bug 783658
 fails-if(Android) fails-if(windowsDefaultTheme&&/^Windows\x20NT\x20(5\.[12]|6\.[012]|10\.0)/.test(http.oscpu)) == emptyautocomplete-1.xul emptyautocomplete-ref.xul # bug 783658
-!= emptymultiline-1.xul emptymultiline-ref.xul
-fails-if(Android) == emptymultiline-2.xul emptymultiline-ref.xul # bug 783658
 fails-if(Android) skip-if(winWidget) == emptytextbox-1.xul emptytextbox-ref.xul # Windows: bug 1239170
 fails-if(Android) skip-if(winWidget) == emptytextbox-2.xul emptytextbox-ref.xul # Windows: bug 1239170
 != emptytextbox-4.xul emptytextbox-ref.xul
 fails-if(Android) skip-if(winWidget) == passwd-1.xul passwd-ref.xul # Windows: bug 1239170
 fails-if(Android) skip-if(winWidget) == passwd-2.xul passwd-ref.xul # Windows: bug 1239170
 != passwd-3.xul passwd-ref.xul
 fails-if(Android) == plain-1.xul plain-ref.xul # bug 783658
 fails-if(Android) skip-if(winWidget) == textbox-1.xul textbox-ref.xul # Windows: bug 1239170
--- a/ipc/glue/BackgroundChildImpl.cpp
+++ b/ipc/glue/BackgroundChildImpl.cpp
@@ -423,17 +423,17 @@ bool BackgroundChildImpl::DeallocPVsyncC
 
   // This actor already has one ref-count. Please check AllocPVsyncChild().
   RefPtr<mozilla::layout::VsyncChild> actor =
       dont_AddRef(static_cast<mozilla::layout::VsyncChild*>(aActor));
   return true;
 }
 
 PUDPSocketChild* BackgroundChildImpl::AllocPUDPSocketChild(
-    const OptionalPrincipalInfo& aPrincipalInfo, const nsCString& aFilter) {
+    const Maybe<PrincipalInfo>& aPrincipalInfo, const nsCString& aFilter) {
   MOZ_CRASH("AllocPUDPSocket should not be called");
   return nullptr;
 }
 
 bool BackgroundChildImpl::DeallocPUDPSocketChild(PUDPSocketChild* child) {
   UDPSocketChild* p = static_cast<UDPSocketChild*>(child);
   p->ReleaseIPDLReference();
   return true;
--- a/ipc/glue/BackgroundChildImpl.h
+++ b/ipc/glue/BackgroundChildImpl.h
@@ -158,17 +158,17 @@ class BackgroundChildImpl : public PBack
 
   virtual bool DeallocPCamerasChild(PCamerasChild* aActor) override;
 
   virtual PVsyncChild* AllocPVsyncChild() override;
 
   virtual bool DeallocPVsyncChild(PVsyncChild* aActor) override;
 
   virtual PUDPSocketChild* AllocPUDPSocketChild(
-      const OptionalPrincipalInfo& aPrincipalInfo,
+      const Maybe<PrincipalInfo>& aPrincipalInfo,
       const nsCString& aFilter) override;
   virtual bool DeallocPUDPSocketChild(PUDPSocketChild* aActor) override;
 
   virtual PBroadcastChannelChild* AllocPBroadcastChannelChild(
       const PrincipalInfo& aPrincipalInfo, const nsCString& aOrigin,
       const nsString& aChannel) override;
 
   virtual bool DeallocPBroadcastChannelChild(
--- a/ipc/glue/BackgroundParentImpl.cpp
+++ b/ipc/glue/BackgroundParentImpl.cpp
@@ -674,30 +674,30 @@ bool BackgroundParentImpl::DeallocPCamer
 #ifdef MOZ_WEBRTC
   RefPtr<mozilla::camera::CamerasParent> actor =
       dont_AddRef(static_cast<mozilla::camera::CamerasParent*>(aActor));
 #endif
   return true;
 }
 
 auto BackgroundParentImpl::AllocPUDPSocketParent(
-    const OptionalPrincipalInfo& /* unused */, const nsCString & /* unused */)
+    const Maybe<PrincipalInfo>& /* unused */, const nsCString & /* unused */)
     -> PUDPSocketParent* {
   RefPtr<UDPSocketParent> p = new UDPSocketParent(this);
 
   return p.forget().take();
 }
 
 mozilla::ipc::IPCResult BackgroundParentImpl::RecvPUDPSocketConstructor(
-    PUDPSocketParent* aActor, const OptionalPrincipalInfo& aOptionalPrincipal,
+    PUDPSocketParent* aActor, const Maybe<PrincipalInfo>& aOptionalPrincipal,
     const nsCString& aFilter) {
   AssertIsInMainOrSocketProcess();
   AssertIsOnBackgroundThread();
 
-  if (aOptionalPrincipal.type() == OptionalPrincipalInfo::TPrincipalInfo) {
+  if (aOptionalPrincipal.isSome()) {
     // Support for checking principals (for non-mtransport use) will be handled
     // in bug 1167039
     return IPC_FAIL_NO_REASON(this);
   }
   // No principal - This must be from mtransport (WebRTC/ICE) - We'd want
   // to DispatchToMainThread() here, but if we do we must block RecvBind()
   // until Init() gets run.  Since we don't have a principal, and we verify
   // we have a filter, we can safely skip the Dispatch and just invoke Init()
--- a/ipc/glue/BackgroundParentImpl.h
+++ b/ipc/glue/BackgroundParentImpl.h
@@ -238,19 +238,19 @@ class BackgroundParentImpl : public PBac
 
   virtual dom::cache::PCacheStreamControlParent*
   AllocPCacheStreamControlParent() override;
 
   virtual bool DeallocPCacheStreamControlParent(
       dom::cache::PCacheStreamControlParent* aActor) override;
 
   virtual PUDPSocketParent* AllocPUDPSocketParent(
-      const OptionalPrincipalInfo& pInfo, const nsCString& aFilter) override;
+      const Maybe<PrincipalInfo>& pInfo, const nsCString& aFilter) override;
   virtual mozilla::ipc::IPCResult RecvPUDPSocketConstructor(
-      PUDPSocketParent*, const OptionalPrincipalInfo& aPrincipalInfo,
+      PUDPSocketParent*, const Maybe<PrincipalInfo>& aPrincipalInfo,
       const nsCString& aFilter) override;
   virtual bool DeallocPUDPSocketParent(PUDPSocketParent*) override;
 
   virtual PMessagePortParent* AllocPMessagePortParent(
       const nsID& aUUID, const nsID& aDestinationUUID,
       const uint32_t& aSequenceID) override;
 
   virtual mozilla::ipc::IPCResult RecvPMessagePortConstructor(
--- a/ipc/glue/BackgroundUtils.cpp
+++ b/ipc/glue/BackgroundUtils.cpp
@@ -368,64 +368,65 @@ nsresult LoadInfoToLoadInfoArgs(nsILoadI
                                 Maybe<LoadInfoArgs>* aOptionalLoadInfoArgs) {
   if (!aLoadInfo) {
     // if there is no loadInfo, then there is nothing to serialize
     *aOptionalLoadInfoArgs = Nothing();
     return NS_OK;
   }
 
   nsresult rv = NS_OK;
-  OptionalPrincipalInfo loadingPrincipalInfo = mozilla::void_t();
+  Maybe<PrincipalInfo> loadingPrincipalInfo;
   if (aLoadInfo->LoadingPrincipal()) {
     PrincipalInfo loadingPrincipalInfoTemp;
     rv = PrincipalToPrincipalInfo(aLoadInfo->LoadingPrincipal(),
                                   &loadingPrincipalInfoTemp);
     NS_ENSURE_SUCCESS(rv, rv);
-    loadingPrincipalInfo = loadingPrincipalInfoTemp;
+    loadingPrincipalInfo = Some(loadingPrincipalInfoTemp);
   }
 
   PrincipalInfo triggeringPrincipalInfo;
   rv = PrincipalToPrincipalInfo(aLoadInfo->TriggeringPrincipal(),
                                 &triggeringPrincipalInfo);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  OptionalPrincipalInfo principalToInheritInfo = mozilla::void_t();
+  Maybe<PrincipalInfo> principalToInheritInfo;
   if (aLoadInfo->PrincipalToInherit()) {
     PrincipalInfo principalToInheritInfoTemp;
     rv = PrincipalToPrincipalInfo(aLoadInfo->PrincipalToInherit(),
                                   &principalToInheritInfoTemp);
     NS_ENSURE_SUCCESS(rv, rv);
-    principalToInheritInfo = principalToInheritInfoTemp;
+    principalToInheritInfo = Some(principalToInheritInfoTemp);
   }
 
-  OptionalPrincipalInfo sandboxedLoadingPrincipalInfo = mozilla::void_t();
+  Maybe<PrincipalInfo> sandboxedLoadingPrincipalInfo;
   if (aLoadInfo->GetLoadingSandboxed()) {
     PrincipalInfo sandboxedLoadingPrincipalInfoTemp;
     rv = PrincipalToPrincipalInfo(aLoadInfo->GetSandboxedLoadingPrincipal(),
                                   &sandboxedLoadingPrincipalInfoTemp);
     NS_ENSURE_SUCCESS(rv, rv);
-    sandboxedLoadingPrincipalInfo = sandboxedLoadingPrincipalInfoTemp;
+    sandboxedLoadingPrincipalInfo = Some(sandboxedLoadingPrincipalInfoTemp);
   }
 
-  OptionalPrincipalInfo topLevelPrincipalInfo = mozilla::void_t();
+  Maybe<PrincipalInfo> topLevelPrincipalInfo;
   if (aLoadInfo->GetTopLevelPrincipal()) {
     PrincipalInfo topLevelPrincipalInfoTemp;
     rv = PrincipalToPrincipalInfo(aLoadInfo->GetTopLevelPrincipal(),
                                   &topLevelPrincipalInfoTemp);
     NS_ENSURE_SUCCESS(rv, rv);
-    topLevelPrincipalInfo = topLevelPrincipalInfoTemp;
+    topLevelPrincipalInfo = Some(topLevelPrincipalInfoTemp);
   }
 
-  OptionalPrincipalInfo topLevelStorageAreaPrincipalInfo = mozilla::void_t();
+  Maybe<PrincipalInfo> topLevelStorageAreaPrincipalInfo;
   if (aLoadInfo->GetTopLevelStorageAreaPrincipal()) {
     PrincipalInfo topLevelStorageAreaPrincipalInfoTemp;
     rv = PrincipalToPrincipalInfo(aLoadInfo->GetTopLevelStorageAreaPrincipal(),
                                   &topLevelStorageAreaPrincipalInfoTemp);
     NS_ENSURE_SUCCESS(rv, rv);
-    topLevelStorageAreaPrincipalInfo = topLevelStorageAreaPrincipalInfoTemp;
+    topLevelStorageAreaPrincipalInfo =
+        Some(topLevelStorageAreaPrincipalInfoTemp);
   }
 
   OptionalURIParams optionalResultPrincipalURI = mozilla::void_t();
   nsCOMPtr<nsIURI> resultPrincipalURI;
   Unused << aLoadInfo->GetResultPrincipalURI(
       getter_AddRefs(resultPrincipalURI));
   if (resultPrincipalURI) {
     SerializeURI(resultPrincipalURI, optionalResultPrincipalURI);
@@ -527,57 +528,52 @@ nsresult LoadInfoArgsToLoadInfo(
     *outLoadInfo = nullptr;
     return NS_OK;
   }
 
   const LoadInfoArgs& loadInfoArgs = aOptionalLoadInfoArgs.ref();
 
   nsresult rv = NS_OK;
   nsCOMPtr<nsIPrincipal> loadingPrincipal;
-  if (loadInfoArgs.requestingPrincipalInfo().type() !=
-      OptionalPrincipalInfo::Tvoid_t) {
-    loadingPrincipal =
-        PrincipalInfoToPrincipal(loadInfoArgs.requestingPrincipalInfo(), &rv);
+  if (loadInfoArgs.requestingPrincipalInfo().isSome()) {
+    loadingPrincipal = PrincipalInfoToPrincipal(
+        loadInfoArgs.requestingPrincipalInfo().ref(), &rv);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
   nsCOMPtr<nsIPrincipal> triggeringPrincipal =
       PrincipalInfoToPrincipal(loadInfoArgs.triggeringPrincipalInfo(), &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIPrincipal> principalToInherit;
-  if (loadInfoArgs.principalToInheritInfo().type() !=
-      OptionalPrincipalInfo::Tvoid_t) {
-    principalToInherit =
-        PrincipalInfoToPrincipal(loadInfoArgs.principalToInheritInfo(), &rv);
+  if (loadInfoArgs.principalToInheritInfo().isSome()) {
+    principalToInherit = PrincipalInfoToPrincipal(
+        loadInfoArgs.principalToInheritInfo().ref(), &rv);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsCOMPtr<nsIPrincipal> sandboxedLoadingPrincipal;
-  if (loadInfoArgs.sandboxedLoadingPrincipalInfo().type() !=
-      OptionalPrincipalInfo::Tvoid_t) {
+  if (loadInfoArgs.sandboxedLoadingPrincipalInfo().isSome()) {
     sandboxedLoadingPrincipal = PrincipalInfoToPrincipal(
-        loadInfoArgs.sandboxedLoadingPrincipalInfo(), &rv);
+        loadInfoArgs.sandboxedLoadingPrincipalInfo().ref(), &rv);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsCOMPtr<nsIPrincipal> topLevelPrincipal;
-  if (loadInfoArgs.topLevelPrincipalInfo().type() !=
-      OptionalPrincipalInfo::Tvoid_t) {
-    topLevelPrincipal =
-        PrincipalInfoToPrincipal(loadInfoArgs.topLevelPrincipalInfo(), &rv);
+  if (loadInfoArgs.topLevelPrincipalInfo().isSome()) {
+    topLevelPrincipal = PrincipalInfoToPrincipal(
+        loadInfoArgs.topLevelPrincipalInfo().ref(), &rv);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsCOMPtr<nsIPrincipal> topLevelStorageAreaPrincipal;
-  if (loadInfoArgs.topLevelStorageAreaPrincipalInfo().type() !=
-      OptionalPrincipalInfo::Tvoid_t) {
+  if (loadInfoArgs.topLevelStorageAreaPrincipalInfo().isSome()) {
     topLevelStorageAreaPrincipal = PrincipalInfoToPrincipal(
-        loadInfoArgs.topLevelStorageAreaPrincipalInfo(), &rv);
+        loadInfoArgs.topLevelStorageAreaPrincipalInfo().ref(), &rv);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsCOMPtr<nsIURI> resultPrincipalURI;
   if (loadInfoArgs.resultPrincipalURI().type() != OptionalURIParams::Tvoid_t) {
     resultPrincipalURI = DeserializeURI(loadInfoArgs.resultPrincipalURI());
     NS_ENSURE_TRUE(resultPrincipalURI, NS_ERROR_UNEXPECTED);
   }
--- a/ipc/glue/PBackground.ipdl
+++ b/ipc/glue/PBackground.ipdl
@@ -165,17 +165,17 @@ parent:
                                      uint32_t privateBrowsingId);
 
   async PBackgroundStorage(nsString profilePath);
 
   async PVsync();
 
   async PCameras();
 
-  async PUDPSocket(OptionalPrincipalInfo pInfo, nsCString filter);
+  async PUDPSocket(PrincipalInfo? pInfo, nsCString filter);
   async PBroadcastChannel(PrincipalInfo pInfo, nsCString origin, nsString channel);
 
   async PServiceWorkerManager();
 
   async ShutdownServiceWorkerRegistrar();
 
   async PCacheStorage(Namespace aNamespace, PrincipalInfo aPrincipalInfo);
 
--- a/ipc/glue/PBackgroundSharedTypes.ipdlh
+++ b/ipc/glue/PBackgroundSharedTypes.ipdlh
@@ -53,16 +53,10 @@ struct ExpandedPrincipalInfo
 union PrincipalInfo
 {
   ContentPrincipalInfo;
   SystemPrincipalInfo;
   NullPrincipalInfo;
   ExpandedPrincipalInfo;
 };
 
-union OptionalPrincipalInfo
-{
-  void_t;
-  PrincipalInfo;
-};
-
 } // namespace ipc
 } // namespace mozilla
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -6730,16 +6730,232 @@ static AccessorType ToAccessorType(Prope
     case PropertyType::DerivedConstructor:
       return AccessorType::None;
     default:
       MOZ_CRASH("unexpected property type");
   }
 }
 
 template <class ParseHandler, typename Unit>
+bool GeneralParser<ParseHandler, Unit>::classMember(
+    YieldHandling yieldHandling, DefaultHandling defaultHandling,
+    const ParseContext::ClassStatement& classStmt, HandlePropertyName className,
+    uint32_t classStartOffset, bool hasHeritage,
+    size_t& numFieldsWithInitializers, ListNodeType& classMembers, bool* done) {
+  *done = false;
+
+  TokenKind tt;
+  if (!tokenStream.getToken(&tt)) {
+    return false;
+  }
+  if (tt == TokenKind::RightCurly) {
+    *done = true;
+    return true;
+  }
+
+  if (tt == TokenKind::Semi) {
+    return true;
+  }
+
+  bool isStatic = false;
+  if (tt == TokenKind::Static) {
+    if (!tokenStream.peekToken(&tt)) {
+      return false;
+    }
+    if (tt == TokenKind::RightCurly) {
+      tokenStream.consumeKnownToken(tt);
+      error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt));
+      return false;
+    }
+
+    if (tt != TokenKind::LeftParen) {
+      isStatic = true;
+    } else {
+      anyChars.ungetToken();
+    }
+  } else {
+    anyChars.ungetToken();
+  }
+
+  uint32_t propNameOffset;
+  if (!tokenStream.peekOffset(&propNameOffset)) {
+    return false;
+  }
+
+  RootedAtom propAtom(cx_);
+  PropertyType propType;
+  Node propName = propertyName(yieldHandling, PropertyNameInClass,
+                               /* maybeDecl = */ Nothing(), classMembers,
+                               &propType, &propAtom);
+  if (!propName) {
+    return false;
+  }
+
+  if (propType == PropertyType::Field) {
+    // TODO(khyperia): Delete the two lines below once fields are fully
+    // supported in the backend. We can't fail in BytecodeCompiler because of
+    // lazy parsing.
+    errorAt(propNameOffset, JSMSG_FIELDS_NOT_SUPPORTED);
+    return false;
+
+    if (isStatic) {
+      errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
+      return false;
+    }
+    if (!tokenStream.getToken(&tt)) {
+      return false;
+    }
+
+    FunctionNodeType initializer = null();
+    if (tt == TokenKind::Assign) {
+      initializer = fieldInitializer(yieldHandling, propAtom);
+      if (!initializer) {
+        return false;
+      }
+
+      numFieldsWithInitializers++;
+      if (!tokenStream.getToken(&tt)) {
+        return false;
+      }
+    }
+
+    // TODO(khyperia): Implement ASI
+    if (tt != TokenKind::Semi) {
+      error(JSMSG_MISSING_SEMI_FIELD);
+      return false;
+    }
+
+    return handler_.addClassFieldDefinition(classMembers, propName,
+                                            initializer);
+  }
+
+  if (propType != PropertyType::Getter && propType != PropertyType::Setter &&
+      propType != PropertyType::Method &&
+      propType != PropertyType::GeneratorMethod &&
+      propType != PropertyType::AsyncMethod &&
+      propType != PropertyType::AsyncGeneratorMethod) {
+    errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
+    return false;
+  }
+
+  bool isConstructor = !isStatic && propAtom == cx_->names().constructor;
+  if (isConstructor) {
+    if (propType != PropertyType::Method) {
+      errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
+      return false;
+    }
+    if (classStmt.constructorBox) {
+      errorAt(propNameOffset, JSMSG_DUPLICATE_PROPERTY, "constructor");
+      return false;
+    }
+    propType = hasHeritage ? PropertyType::DerivedConstructor
+                           : PropertyType::Constructor;
+  } else if (isStatic && propAtom == cx_->names().prototype) {
+    errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
+    return false;
+  }
+
+  RootedAtom funName(cx_);
+  switch (propType) {
+    case PropertyType::Getter:
+    case PropertyType::Setter:
+      if (!anyChars.isCurrentTokenType(TokenKind::RightBracket)) {
+        funName = prefixAccessorName(propType, propAtom);
+        if (!funName) {
+          return false;
+        }
+      }
+      break;
+    case PropertyType::Constructor:
+    case PropertyType::DerivedConstructor:
+      funName = className;
+      break;
+    default:
+      if (!anyChars.isCurrentTokenType(TokenKind::RightBracket)) {
+        funName = propAtom;
+      }
+  }
+
+  // Calling toString on constructors need to return the source text for
+  // the entire class. The end offset is unknown at this point in
+  // parsing and will be amended when class parsing finishes below.
+  FunctionNodeType funNode = methodDefinition(
+      isConstructor ? classStartOffset : propNameOffset, propType, funName);
+  if (!funNode) {
+    return false;
+  }
+
+  AccessorType atype = ToAccessorType(propType);
+  return handler_.addClassMethodDefinition(classMembers, propName, funNode,
+                                           atype, isStatic);
+}
+
+template <class ParseHandler, typename Unit>
+bool GeneralParser<ParseHandler, Unit>::finishClassConstructor(
+    const ParseContext::ClassStatement& classStmt, HandlePropertyName className,
+    uint32_t classStartOffset, uint32_t classEndOffset,
+    size_t numFieldsWithInitializers, ListNodeType& classMembers) {
+  // Fields cannot re-use the constructor obtained via JSOP_CLASSCONSTRUCTOR or
+  // JSOP_DERIVEDCONSTRUCTOR due to needing to emit calls to the field
+  // initializers in the constructor. So, synthesize a new one.
+  if (classStmt.constructorBox == nullptr && numFieldsWithInitializers > 0) {
+    // synthesizeConstructor assigns to classStmt.constructorBox
+    FunctionNodeType synthesizedCtor =
+        synthesizeConstructor(className, classStartOffset);
+    if (!synthesizedCtor) {
+      return false;
+    }
+
+    MOZ_ASSERT(classStmt.constructorBox != nullptr);
+
+    // Note: the *function* has the name of the class, but the *property*
+    // containing the function has the name "constructor"
+    Node constructorNameNode =
+        handler_.newObjectLiteralPropertyName(cx_->names().constructor, pos());
+    if (!constructorNameNode) {
+      return false;
+    }
+
+    if (!handler_.addClassMethodDefinition(classMembers, constructorNameNode,
+                                           synthesizedCtor, AccessorType::None,
+                                           /* isStatic = */ false)) {
+      return false;
+    }
+  }
+
+  if (FunctionBox* ctorbox = classStmt.constructorBox) {
+    // Amend the toStringEnd offset for the constructor now that we've
+    // finished parsing the class.
+    ctorbox->toStringEnd = classEndOffset;
+
+    if (numFieldsWithInitializers > 0) {
+      // Field initialization need access to `this`.
+      ctorbox->setHasThisBinding();
+    }
+
+    // Set the same information, but on the lazyScript.
+    if (ctorbox->function()->isInterpretedLazy()) {
+      ctorbox->function()->lazyScript()->setToStringEnd(classEndOffset);
+
+      if (numFieldsWithInitializers > 0) {
+        ctorbox->function()->lazyScript()->setHasThisBinding();
+      }
+
+      // Field initializers can be retrieved if the class and constructor are
+      // being compiled at the same time, but we need to stash the field
+      // information if the constructor is being compiled lazily.
+      FieldInitializers fieldInfo(numFieldsWithInitializers);
+      ctorbox->function()->lazyScript()->setFieldInitializers(fieldInfo);
+    }
+  }
+
+  return true;
+}
+
+template <class ParseHandler, typename Unit>
 typename ParseHandler::ClassNodeType
 GeneralParser<ParseHandler, Unit>::classDefinition(
     YieldHandling yieldHandling, ClassContext classContext,
     DefaultHandling defaultHandling) {
   MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Class));
 
   uint32_t classStartOffset = pos().begin;
   bool savedStrictness = setLocalStrictMode(true);
@@ -6764,294 +6980,103 @@ GeneralParser<ParseHandler, Unit>::class
       error(JSMSG_UNNAMED_CLASS_STMT);
       return null();
     }
   } else {
     // Make sure to put it back, whatever it was
     anyChars.ungetToken();
   }
 
+  // Because the binding definitions keep track of their blockId, we need to
+  // create at least the inner binding later. Keep track of the name's
+  // position in order to provide it for the nodes created later.
+  TokenPos namePos = pos();
+
   // Push a ParseContext::ClassStatement to keep track of the constructor
   // funbox.
   ParseContext::ClassStatement classStmt(pc_);
 
-  RootedAtom propAtom(cx_);
-
-  // A named class creates a new lexical scope with a const binding of the
-  // class name for the "inner name".
-  Maybe<ParseContext::Statement> innerScopeStmt;
-  Maybe<ParseContext::Scope> innerScope;
-  if (className) {
-    innerScopeStmt.emplace(pc_, StatementKind::Block);
-    innerScope.emplace(this);
-    if (!innerScope->init(pc_)) {
-      return null();
-    }
-  }
-
-  // Because the binding definitions keep track of their blockId, we need to
-  // create at least the inner binding later. Keep track of the name's position
-  // in order to provide it for the nodes created later.
-  TokenPos namePos = pos();
-
+  NameNodeType innerName;
+  Node nameNode = null();
   Node classHeritage = null();
-  bool hasHeritage;
-  if (!tokenStream.matchToken(&hasHeritage, TokenKind::Extends)) {
-    return null();
-  }
-  if (hasHeritage) {
-    if (!tokenStream.getToken(&tt)) {
-      return null();
-    }
-    classHeritage = memberExpr(yieldHandling, TripledotProhibited, tt);
-    if (!classHeritage) {
-      return null();
-    }
-  }
-
-  if (!mustMatchToken(TokenKind::LeftCurly, JSMSG_CURLY_BEFORE_CLASS)) {
-    return null();
-  }
-
-  ListNodeType classMembers = handler_.newClassMemberList(pos().begin);
-  if (!classMembers) {
-    return null();
-  }
-
-  Maybe<DeclarationKind> declKind = Nothing();
-  size_t numFieldsWithInitializers = 0;
-  for (;;) {
-    TokenKind tt;
-    if (!tokenStream.getToken(&tt)) {
-      return null();
-    }
-    if (tt == TokenKind::RightCurly) {
-      break;
-    }
-
-    if (tt == TokenKind::Semi) {
-      continue;
-    }
-
-    bool isStatic = false;
-    if (tt == TokenKind::Static) {
-      if (!tokenStream.peekToken(&tt)) {
-        return null();
-      }
-      if (tt == TokenKind::RightCurly) {
-        tokenStream.consumeKnownToken(tt);
-        error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt));
-        return null();
-      }
-
-      if (tt != TokenKind::LeftParen) {
-        isStatic = true;
-      } else {
-        anyChars.ungetToken();
-      }
-    } else {
-      anyChars.ungetToken();
-    }
-
-    uint32_t propNameOffset;
-    if (!tokenStream.peekOffset(&propNameOffset)) {
-      return null();
-    }
-
-    PropertyType propType;
-    Node propName = propertyName(yieldHandling, PropertyNameInClass, declKind,
-                                 classMembers, &propType, &propAtom);
-    if (!propName) {
-      return null();
-    }
-
-    if (propType == PropertyType::Field) {
-      // TODO(khyperia): Delete the two lines below once fields are fully
-      // supported in the backend. We can't fail in BytecodeCompiler because of
-      // lazy parsing.
-      errorAt(propNameOffset, JSMSG_FIELDS_NOT_SUPPORTED);
-      return null();
-
-      if (isStatic) {
-        errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
-        return null();
-      }
+  Node classBlock = null();
+  uint32_t classEndOffset;
+  {
+    // A named class creates a new lexical scope with a const binding of the
+    // class name for the "inner name".
+    ParseContext::Statement innerScopeStmt(pc_, StatementKind::Block);
+    ParseContext::Scope innerScope(this);
+    if (!innerScope.init(pc_)) {
+      return null();
+    }
+
+    bool hasHeritage;
+    if (!tokenStream.matchToken(&hasHeritage, TokenKind::Extends)) {
+      return null();
+    }
+    if (hasHeritage) {
       if (!tokenStream.getToken(&tt)) {
         return null();
       }
-
-      FunctionNodeType initializer = null();
-      if (tt == TokenKind::Assign) {
-        initializer = fieldInitializer(yieldHandling, propAtom);
-        if (!initializer) {
-          return null();
-        }
-
-        numFieldsWithInitializers++;
-        if (!tokenStream.getToken(&tt)) {
-          return null();
-        }
-      }
-
-      // TODO(khyperia): Implement ASI
-      if (tt != TokenKind::Semi) {
-        error(JSMSG_MISSING_SEMI_FIELD);
-        return null();
-      }
-
-      if (!handler_.addClassFieldDefinition(classMembers, propName,
-                                            initializer)) {
-        return null();
-      }
-
-      continue;
-    }
-
-    if (propType != PropertyType::Getter && propType != PropertyType::Setter &&
-        propType != PropertyType::Method &&
-        propType != PropertyType::GeneratorMethod &&
-        propType != PropertyType::AsyncMethod &&
-        propType != PropertyType::AsyncGeneratorMethod) {
-      errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
-      return null();
-    }
-
-    bool isConstructor = !isStatic && propAtom == cx_->names().constructor;
-    if (isConstructor) {
-      if (propType != PropertyType::Method) {
-        errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
-        return null();
-      }
-      if (classStmt.constructorBox) {
-        errorAt(propNameOffset, JSMSG_DUPLICATE_PROPERTY, "constructor");
-        return null();
-      }
-      propType = hasHeritage ? PropertyType::DerivedConstructor
-                             : PropertyType::Constructor;
-    } else if (isStatic && propAtom == cx_->names().prototype) {
-      errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
-      return null();
-    }
-
-    RootedAtom funName(cx_);
-    switch (propType) {
-      case PropertyType::Getter:
-      case PropertyType::Setter:
-        if (!anyChars.isCurrentTokenType(TokenKind::RightBracket)) {
-          funName = prefixAccessorName(propType, propAtom);
-          if (!funName) {
-            return null();
-          }
-        }
-        break;
-      case PropertyType::Constructor:
-      case PropertyType::DerivedConstructor:
-        funName = className;
+      classHeritage = memberExpr(yieldHandling, TripledotProhibited, tt);
+      if (!classHeritage) {
+        return null();
+      }
+    }
+
+    if (!mustMatchToken(TokenKind::LeftCurly, JSMSG_CURLY_BEFORE_CLASS)) {
+      return null();
+    }
+
+    ListNodeType classMembers = handler_.newClassMemberList(pos().begin);
+    if (!classMembers) {
+      return null();
+    }
+
+    size_t numFieldsWithInitializers = 0;
+    for (;;) {
+      bool done;
+      if (!classMember(yieldHandling, defaultHandling, classStmt, className,
+                       classStartOffset, hasHeritage, numFieldsWithInitializers,
+                       classMembers, &done)) {
+        return null();
+      }
+      if (done) {
         break;
-      default:
-        if (!anyChars.isCurrentTokenType(TokenKind::RightBracket)) {
-          funName = propAtom;
-        }
-    }
-
-    // Calling toString on constructors need to return the source text for
-    // the entire class. The end offset is unknown at this point in
-    // parsing and will be amended when class parsing finishes below.
-    FunctionNodeType funNode = methodDefinition(
-        isConstructor ? classStartOffset : propNameOffset, propType, funName);
-    if (!funNode) {
-      return null();
-    }
-
-    AccessorType atype = ToAccessorType(propType);
-    if (!handler_.addClassMethodDefinition(classMembers, propName, funNode,
-                                           atype, isStatic)) {
-      return null();
-    }
-  }
-
-  // Fields cannot re-use the constructor obtained via JSOP_CLASSCONSTRUCTOR or
-  // JSOP_DERIVEDCONSTRUCTOR due to needing to emit calls to the field
-  // initializers in the constructor. So, synthesize a new one.
-  if (classStmt.constructorBox == nullptr && numFieldsWithInitializers > 0) {
-    // synthesizeConstructor assigns to classStmt.constructorBox
-    FunctionNodeType synthesizedCtor =
-        synthesizeConstructor(className, classStartOffset);
-    if (!synthesizedCtor) {
-      return null();
-    }
-
-    MOZ_ASSERT(classStmt.constructorBox != nullptr);
-
-    // Note: the *function* has the name of the class, but the *property*
-    // containing the function has the name "constructor"
-    Node constructorNameNode =
-        handler_.newObjectLiteralPropertyName(cx_->names().constructor, pos());
-    if (!constructorNameNode) {
-      return null();
-    }
-
-    if (!handler_.addClassMethodDefinition(classMembers, constructorNameNode,
-                                           synthesizedCtor, AccessorType::None,
-                                           /* isStatic = */ false)) {
-      return null();
-    }
-  }
-
-  uint32_t classEndOffset = pos().end;
-  if (FunctionBox* ctorbox = classStmt.constructorBox) {
-    // Amend the toStringEnd offset for the constructor now that we've
-    // finished parsing the class.
-    ctorbox->toStringEnd = classEndOffset;
-
-    if (numFieldsWithInitializers > 0) {
-      // Field initialization need access to `this`.
-      ctorbox->setHasThisBinding();
-    }
-
-    // Set the same information, but on the lazyScript.
-    if (ctorbox->function()->isInterpretedLazy()) {
-      ctorbox->function()->lazyScript()->setToStringEnd(classEndOffset);
-
-      if (numFieldsWithInitializers > 0) {
-        ctorbox->function()->lazyScript()->setHasThisBinding();
-      }
-
-      // Field initializers can be retrieved if the class and constructor are
-      // being compiled at the same time, but we need to stash the field
-      // information if the constructor is being compiled lazily.
-      FieldInitializers fieldInfo(numFieldsWithInitializers);
-      ctorbox->function()->lazyScript()->setFieldInitializers(fieldInfo);
-    }
-  }
-
-  Node nameNode = null();
-  Node membersOrBlock = classMembers;
-  if (className) {
-    // The inner name is immutable.
-    if (!noteDeclaredName(className, DeclarationKind::Const, namePos)) {
-      return null();
-    }
-
-    NameNodeType innerName = newName(className, namePos);
-    if (!innerName) {
-      return null();
-    }
-
-    Node classBlock = finishLexicalScope(*innerScope, classMembers);
+      }
+    }
+
+    classEndOffset = pos().end;
+    if (!finishClassConstructor(classStmt, className, classStartOffset,
+                                classEndOffset, numFieldsWithInitializers,
+                                classMembers)) {
+      return null();
+    }
+
+    if (className) {
+      // The inner name is immutable.
+      if (!noteDeclaredName(className, DeclarationKind::Const, namePos)) {
+        return null();
+      }
+
+      innerName = newName(className, namePos);
+      if (!innerName) {
+        return null();
+      }
+    }
+
+    classBlock = finishLexicalScope(innerScope, classMembers);
     if (!classBlock) {
       return null();
     }
 
-    membersOrBlock = classBlock;
-
     // Pop the inner scope.
-    innerScope.reset();
-    innerScopeStmt.reset();
-
+  }
+
+  if (className) {
     NameNodeType outerName = null();
     if (classContext == ClassStatement) {
       // The outer name is mutable.
       if (!noteDeclaredName(className, DeclarationKind::Class, namePos)) {
         return null();
       }
 
       outerName = newName(className, namePos);
@@ -7063,17 +7088,17 @@ GeneralParser<ParseHandler, Unit>::class
     nameNode = handler_.newClassNames(outerName, innerName, namePos);
     if (!nameNode) {
       return null();
     }
   }
 
   MOZ_ALWAYS_TRUE(setLocalStrictMode(savedStrictness));
 
-  return handler_.newClass(nameNode, classHeritage, membersOrBlock,
+  return handler_.newClass(nameNode, classHeritage, classBlock,
                            TokenPos(classStartOffset, classEndOffset));
 }
 
 template <class ParseHandler, typename Unit>
 typename ParseHandler::FunctionNodeType
 GeneralParser<ParseHandler, Unit>::synthesizeConstructor(
     HandleAtom className, uint32_t classNameOffset) {
   FunctionSyntaxKind functionSyntaxKind = FunctionSyntaxKind::ClassConstructor;
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -1298,16 +1298,28 @@ class MOZ_STACK_CLASS GeneralParser : pu
   inline bool checkExportedNameForFunction(FunctionNodeType funNode);
   inline bool checkExportedNameForClass(ClassNodeType classNode);
   inline bool checkExportedNameForClause(NameNodeType nameNode);
 
   enum ClassContext { ClassStatement, ClassExpression };
   ClassNodeType classDefinition(YieldHandling yieldHandling,
                                 ClassContext classContext,
                                 DefaultHandling defaultHandling);
+  MOZ_MUST_USE bool classMember(YieldHandling yieldHandling,
+                                DefaultHandling defaultHandling,
+                                const ParseContext::ClassStatement& classStmt,
+                                HandlePropertyName className,
+                                uint32_t classStartOffset, bool hasHeritage,
+                                size_t& numFieldsWithInitializers,
+                                ListNodeType& classMembers, bool* done);
+  MOZ_MUST_USE bool finishClassConstructor(
+      const ParseContext::ClassStatement& classStmt,
+      HandlePropertyName className, uint32_t classStartOffset,
+      uint32_t classEndOffset, size_t numFieldsWithInitializers,
+      ListNodeType& classMembers);
 
   FunctionNodeType fieldInitializer(YieldHandling yieldHandling,
                                     HandleAtom atom);
   FunctionNodeType synthesizeConstructor(HandleAtom className,
                                          uint32_t classNameOffset);
 
   bool checkBindingIdentifier(PropertyName* ident, uint32_t offset,
                               YieldHandling yieldHandling,
--- a/js/src/jit-test/tests/auto-regress/bug1263857.js
+++ b/js/src/jit-test/tests/auto-regress/bug1263857.js
@@ -1,4 +1,8 @@
-// |jit-test| allow-oom; allow-unhandlable-oom
+// |jit-test| allow-oom; allow-unhandlable-oom; skip-if: getBuildConfiguration('arm64')
+//
+// Disabled on ARM64 due to Bug 1529034: the harness expects unhandlable-oom error
+// messages on stderr, but Android builds output to the system log file.
+// Therefore unhandlable-oom appears as a segfault with no message, and the test fails.
 gcparam("maxBytes", gcparam("gcBytes") + 1);
 fullcompartmentchecks(true);
 /x/g[Symbol.replace]("        x".repeat(32768), "");
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -580,18 +580,18 @@ void BaselineInterpreterCodeGen::storeFr
 
   // Push frame descriptor based on the full frame size.
   masm.makeFrameDescriptor(scratch1, FrameType::BaselineJS,
                            ExitFrameLayout::Size());
   masm.push(scratch1);
 }
 
 template <typename Handler>
-bool BaselineCodeGen<Handler>::callVM(const VMFunctionData& fun,
-                                      TrampolinePtr code, CallVMPhase phase) {
+bool BaselineCodeGen<Handler>::callVMInternal(VMFunctionId id,
+                                              CallVMPhase phase) {
 #ifdef DEBUG
   // Assert prepareVMCall() has been called.
   MOZ_ASSERT(inCall_);
   inCall_ = false;
 
   // Assert the frame does not have an override pc when we're executing JIT
   // code.
   {
@@ -599,16 +599,19 @@ bool BaselineCodeGen<Handler>::callVM(co
     masm.branchTest32(Assembler::Zero, frame.addressOfFlags(),
                       Imm32(BaselineFrame::HAS_OVERRIDE_PC), &ok);
     masm.assumeUnreachable(
         "BaselineFrame shouldn't override pc when executing JIT code");
     masm.bind(&ok);
   }
 #endif
 
+  TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(id);
+  const VMFunctionData& fun = GetVMFunction(id);
+
   // Compute argument size. Note that this include the size of the frame pointer
   // pushed by prepareVMCall.
   uint32_t argSize = fun.explicitStackSlots() * sizeof(void*) + sizeof(void*);
 
   // Assert all arguments were pushed.
   MOZ_ASSERT(masm.framePushed() - pushedBeforeCall_ == argSize);
 
   Address frameSizeAddress(BaselineFrameReg,
@@ -660,34 +663,21 @@ bool BaselineCodeGen<Handler>::callVM(co
     masm.bind(&ok);
   }
 #endif
 
   return handler.appendRetAddrEntry(cx, RetAddrEntry::Kind::CallVM, callOffset);
 }
 
 template <typename Handler>
-bool BaselineCodeGen<Handler>::callVM(const VMFunction& fun,
-                                      CallVMPhase phase) {
-  TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
-  return callVM(fun, code, phase);
-}
-
-template <typename Handler>
 template <typename Fn, Fn fn>
 bool BaselineCodeGen<Handler>::callVM(CallVMPhase phase) {
   VMFunctionId fnId = VMFunctionToId<Fn, fn>::id;
-  TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(fnId);
-  return callVM(GetVMFunction(fnId), code, phase);
-}
-
-typedef bool (*CheckOverRecursedBaselineFn)(JSContext*, BaselineFrame*);
-static const VMFunction CheckOverRecursedBaselineInfo =
-    FunctionInfo<CheckOverRecursedBaselineFn>(CheckOverRecursedBaseline,
-                                              "CheckOverRecursedBaseline");
+  return callVMInternal(fnId, phase);
+}
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emitStackCheck() {
   // If this is the late stack check for a frame which contains an early stack
   // check, then the early stack check might have failed and skipped past the
   // pushing of locals on the stack.
   //
   // If this is a possibility, then the OVER_RECURSED flag should be checked,
@@ -712,17 +702,18 @@ bool BaselineCodeGen<Handler>::emitStack
   masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
   pushArg(R1.scratchReg());
 
   CallVMPhase phase = POST_INITIALIZE;
   if (handler.needsEarlyStackCheck()) {
     phase = CHECK_OVER_RECURSED;
   }
 
-  if (!callVMNonOp(CheckOverRecursedBaselineInfo, phase)) {
+  using Fn = bool (*)(JSContext*, BaselineFrame*);
+  if (!callVMNonOp<Fn, CheckOverRecursedBaseline>(phase)) {
     return false;
   }
 
   handler.markLastRetAddrEntryKind(RetAddrEntry::Kind::StackCheck);
 
   masm.bind(&skipCall);
   return true;
 }
@@ -934,29 +925,16 @@ bool BaselineCodeGen<Handler>::emitDebug
     return false;
   }
 
   debugOsrPrologueOffset_ = CodeOffset(masm.currentOffset());
 
   return true;
 }
 
-typedef bool (*CheckGlobalOrEvalDeclarationConflictsFn)(JSContext*,
-                                                        HandleObject,
-                                                        HandleScript);
-static const VMFunction CheckGlobalOrEvalDeclarationConflictsInfo =
-    FunctionInfo<CheckGlobalOrEvalDeclarationConflictsFn>(
-        js::CheckGlobalOrEvalDeclarationConflicts,
-        "CheckGlobalOrEvalDeclarationConflicts");
-
-typedef bool (*InitFunctionEnvironmentObjectsFn)(JSContext*, BaselineFrame*);
-static const VMFunction InitFunctionEnvironmentObjectsInfo =
-    FunctionInfo<InitFunctionEnvironmentObjectsFn>(
-        jit::InitFunctionEnvironmentObjects, "InitFunctionEnvironmentObjects");
-
 template <>
 void BaselineCompilerCodeGen::emitPreInitEnvironmentChain(
     Register nonFunctionEnv) {
   if (handler.function()) {
     masm.storePtr(ImmPtr(nullptr), frame.addressOfEnvironmentChain());
   } else {
     masm.storePtr(nonFunctionEnv, frame.addressOfEnvironmentChain());
   }
@@ -988,32 +966,34 @@ bool BaselineCompilerCodeGen::initEnviro
 
     if (fun->needsFunctionEnvironmentObjects()) {
       // Call into the VM to create the proper environment objects.
       prepareVMCall();
 
       masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
       pushArg(R0.scratchReg());
 
-      if (!callVMNonOp(InitFunctionEnvironmentObjectsInfo, phase)) {
+      using Fn = bool (*)(JSContext*, BaselineFrame*);
+      if (!callVMNonOp<Fn, jit::InitFunctionEnvironmentObjects>(phase)) {
         return false;
       }
     }
   } else if (!handler.module()) {
     // EnvironmentChain pointer in BaselineFrame has already been initialized
     // in prologue, but we need to check for redeclaration errors in global and
     // eval scripts.
 
     prepareVMCall();
 
     pushScriptArg(R2.scratchReg());
     masm.loadPtr(frame.addressOfEnvironmentChain(), R0.scratchReg());
     pushArg(R0.scratchReg());
 
-    if (!callVMNonOp(CheckGlobalOrEvalDeclarationConflictsInfo, phase)) {
+    using Fn = bool (*)(JSContext*, HandleObject, HandleScript);
+    if (!callVMNonOp<Fn, js::CheckGlobalOrEvalDeclarationConflicts>(phase)) {
       return false;
     }
   }
 
   return true;
 }
 
 template <>
@@ -1700,17 +1680,19 @@ bool BaselineCodeGen<Handler>::emit_JSOP
   frame.popRegsAndSync(1);
 
   // Inline path for int32 and double; otherwise call VM.
   Label done;
   masm.branchTestNumber(Assembler::Equal, R0, &done);
 
   prepareVMCall();
   pushArg(R0);
-  if (!callVM(ToNumberInfo)) {
+
+  using Fn = bool (*)(JSContext*, HandleValue, MutableHandleValue);
+  if (!callVM<Fn, DoToNumber>()) {
     return false;
   }
 
   masm.bind(&done);
   frame.push(R0);
   return true;
 }
 
@@ -1720,17 +1702,19 @@ bool BaselineCodeGen<Handler>::emit_JSOP
   frame.popRegsAndSync(1);
 
   // Inline path for int32 and double; otherwise call VM.
   Label done;
   masm.branchTestNumber(Assembler::Equal, R0, &done);
 
   prepareVMCall();
   pushArg(R0);
-  if (!callVM(ToNumericInfo)) {
+
+  using Fn = bool (*)(JSContext*, HandleValue, MutableHandleValue);
+  if (!callVM<Fn, DoToNumeric>()) {
     return false;
   }
 
   masm.bind(&done);
   frame.push(R0);
   return true;
 }
 
@@ -2709,17 +2693,19 @@ bool BaselineCodeGen<Handler>::emitSetEl
   pushArg(Imm32(strict));
   pushArg(R1);  // receiver
   pushArg(R0);  // rval
   masm.loadValue(frame.addressOfStackValue(-2), R0);
   pushArg(R0);  // propval
   masm.unboxObject(frame.addressOfStackValue(-1), R0.scratchReg());
   pushArg(R0.scratchReg());  // obj
 
-  if (!callVM(SetObjectElementInfo)) {
+  using Fn = bool (*)(JSContext*, HandleObject, HandleValue, HandleValue,
+                      HandleValue, bool);
+  if (!callVM<Fn, js::SetObjectElementWithReceiver>()) {
     return false;
   }
 
   frame.popn(2);
   return true;
 }
 
 template <typename Handler>
@@ -3944,32 +3930,29 @@ bool BaselineCodeGen<Handler>::emit_JSOP
     return false;
   }
 
   masm.boxNonDouble(JSVAL_TYPE_BOOLEAN, ReturnReg, R0);
   frame.push(R0);
   return true;
 }
 
-typedef bool (*ImplicitThisFn)(JSContext*, HandleObject, HandlePropertyName,
-                               MutableHandleValue);
-const VMFunction ImplicitThisInfo = FunctionInfo<ImplicitThisFn>(
-    ImplicitThisOperation, "ImplicitThisOperation");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_IMPLICITTHIS() {
   frame.syncStack(0);
   masm.loadPtr(frame.addressOfEnvironmentChain(), R0.scratchReg());
 
   prepareVMCall();
 
   pushScriptNameArg();
   pushArg(R0.scratchReg());
 
-  if (!callVM(ImplicitThisInfo)) {
+  using Fn = bool (*)(JSContext*, HandleObject, HandlePropertyName,
+                      MutableHandleValue);
+  if (!callVM<Fn, ImplicitThisOperation>()) {
     return false;
   }
 
   frame.push(R0);
   return true;
 }
 
 template <typename Handler>
@@ -4008,39 +3991,35 @@ bool BaselineCodeGen<Handler>::emit_JSOP
   return true;
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_TYPEOFEXPR() {
   return emit_JSOP_TYPEOF();
 }
 
-typedef bool (*ThrowMsgFn)(JSContext*, const unsigned);
-static const VMFunction ThrowMsgInfo =
-    FunctionInfo<ThrowMsgFn>(js::ThrowMsgOperation, "ThrowMsgOperation");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_THROWMSG() {
   prepareVMCall();
   pushUint16BytecodeOperandArg();
-  return callVM(ThrowMsgInfo);
-}
-
-typedef bool (*ThrowFn)(JSContext*, HandleValue);
-static const VMFunction ThrowInfo = FunctionInfo<ThrowFn>(js::Throw, "Throw");
+
+  using Fn = bool (*)(JSContext*, const unsigned);
+  return callVM<Fn, js::ThrowMsgOperation>();
+}
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_THROW() {
   // Keep value to throw in R0.
   frame.popRegsAndSync(1);
 
   prepareVMCall();
   pushArg(R0);
 
-  return callVM(ThrowInfo);
+  using Fn = bool (*)(JSContext*, HandleValue);
+  return callVM<Fn, js::ThrowOperation>();
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_TRY() {
   // Ionmonkey can't inline function with JSOP_TRY.
   if (JSScript* script = handler.maybeScript()) {
     script->setUninlineable();
   }
@@ -4102,17 +4081,19 @@ bool BaselineCodeGen<Handler>::emit_JSOP
   frame.popRegsAndSync(2);
 
   Label isReturn;
   masm.branchTestBooleanTruthy(/* branchIfTrue = */ false, R0, &isReturn);
 
   // R0 is |true|. We need to throw R1.
   prepareVMCall();
   pushArg(R1);
-  if (!callVM(ThrowInfo)) {
+
+  using Fn = bool (*)(JSContext*, HandleValue);
+  if (!callVM<Fn, js::ThrowOperation>()) {
     return false;
   }
 
   masm.bind(&isReturn);
 
   // R0 is |false|. R1 contains the resumeIndex to jump to.
   Register resumeIndexReg = R1.scratchReg();
   masm.unboxInt32(R1, resumeIndexReg);
@@ -4165,273 +4146,221 @@ MOZ_MUST_USE bool BaselineInterpreterCod
   if (ifNotDebuggee && !(*ifNotDebuggee)()) {
     return false;
   }
 
   masm.bind(&done);
   return true;
 }
 
-typedef bool (*PushLexicalEnvFn)(JSContext*, BaselineFrame*,
-                                 Handle<LexicalScope*>);
-static const VMFunction PushLexicalEnvInfo =
-    FunctionInfo<PushLexicalEnvFn>(jit::PushLexicalEnv, "PushLexicalEnv");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_PUSHLEXICALENV() {
   // Call a stub to push the block on the block chain.
   prepareVMCall();
   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
 
   pushScriptScopeArg();
   pushArg(R0.scratchReg());
 
-  return callVM(PushLexicalEnvInfo);
-}
-
-typedef bool (*PopLexicalEnvFn)(JSContext*, BaselineFrame*);
-static const VMFunction PopLexicalEnvInfo =
-    FunctionInfo<PopLexicalEnvFn>(jit::PopLexicalEnv, "PopLexicalEnv");
-
-typedef bool (*DebugLeaveThenPopLexicalEnvFn)(JSContext*, BaselineFrame*,
-                                              jsbytecode*);
-static const VMFunction DebugLeaveThenPopLexicalEnvInfo =
-    FunctionInfo<DebugLeaveThenPopLexicalEnvFn>(
-        jit::DebugLeaveThenPopLexicalEnv, "DebugLeaveThenPopLexicalEnv");
+  using Fn = bool (*)(JSContext*, BaselineFrame*, Handle<LexicalScope*>);
+  return callVM<Fn, jit::PushLexicalEnv>();
+}
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_POPLEXICALENV() {
   frame.syncStack(0);
 
   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
 
   auto ifDebuggee = [this]() {
     prepareVMCall();
     pushBytecodePCArg();
     pushArg(R0.scratchReg());
-    return callVM(DebugLeaveThenPopLexicalEnvInfo);
+
+    using Fn = bool (*)(JSContext*, BaselineFrame*, jsbytecode*);
+    return callVM<Fn, jit::DebugLeaveThenPopLexicalEnv>();
   };
   auto ifNotDebuggee = [this]() {
     prepareVMCall();
     pushArg(R0.scratchReg());
-    return callVM(PopLexicalEnvInfo);
+
+    using Fn = bool (*)(JSContext*, BaselineFrame*);
+    return callVM<Fn, jit::PopLexicalEnv>();
   };
   return emitDebugInstrumentation(ifDebuggee, mozilla::Some(ifNotDebuggee));
 }
 
-typedef bool (*FreshenLexicalEnvFn)(JSContext*, BaselineFrame*);
-static const VMFunction FreshenLexicalEnvInfo =
-    FunctionInfo<FreshenLexicalEnvFn>(jit::FreshenLexicalEnv,
-                                      "FreshenLexicalEnv");
-
-typedef bool (*DebugLeaveThenFreshenLexicalEnvFn)(JSContext*, BaselineFrame*,
-                                                  jsbytecode*);
-static const VMFunction DebugLeaveThenFreshenLexicalEnvInfo =
-    FunctionInfo<DebugLeaveThenFreshenLexicalEnvFn>(
-        jit::DebugLeaveThenFreshenLexicalEnv,
-        "DebugLeaveThenFreshenLexicalEnv");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_FRESHENLEXICALENV() {
   frame.syncStack(0);
 
   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
 
   auto ifDebuggee = [this]() {
     prepareVMCall();
     pushBytecodePCArg();
     pushArg(R0.scratchReg());
-    return callVM(DebugLeaveThenFreshenLexicalEnvInfo);
+
+    using Fn = bool (*)(JSContext*, BaselineFrame*, jsbytecode*);
+    return callVM<Fn, jit::DebugLeaveThenFreshenLexicalEnv>();
   };
   auto ifNotDebuggee = [this]() {
     prepareVMCall();
     pushArg(R0.scratchReg());
-    return callVM(FreshenLexicalEnvInfo);
+
+    using Fn = bool (*)(JSContext*, BaselineFrame*);
+    return callVM<Fn, jit::FreshenLexicalEnv>();
   };
   return emitDebugInstrumentation(ifDebuggee, mozilla::Some(ifNotDebuggee));
 }
 
-typedef bool (*RecreateLexicalEnvFn)(JSContext*, BaselineFrame*);
-static const VMFunction RecreateLexicalEnvInfo =
-    FunctionInfo<RecreateLexicalEnvFn>(jit::RecreateLexicalEnv,
-                                       "RecreateLexicalEnv");
-
-typedef bool (*DebugLeaveThenRecreateLexicalEnvFn)(JSContext*, BaselineFrame*,
-                                                   jsbytecode*);
-static const VMFunction DebugLeaveThenRecreateLexicalEnvInfo =
-    FunctionInfo<DebugLeaveThenRecreateLexicalEnvFn>(
-        jit::DebugLeaveThenRecreateLexicalEnv,
-        "DebugLeaveThenRecreateLexicalEnv");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_RECREATELEXICALENV() {
   frame.syncStack(0);
 
   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
 
   auto ifDebuggee = [this]() {
     prepareVMCall();
     pushBytecodePCArg();
     pushArg(R0.scratchReg());
-    return callVM(DebugLeaveThenRecreateLexicalEnvInfo);
+
+    using Fn = bool (*)(JSContext*, BaselineFrame*, jsbytecode*);
+    return callVM<Fn, jit::DebugLeaveThenRecreateLexicalEnv>();
   };
   auto ifNotDebuggee = [this]() {
     prepareVMCall();
     pushArg(R0.scratchReg());
-    return callVM(RecreateLexicalEnvInfo);
+
+    using Fn = bool (*)(JSContext*, BaselineFrame*);
+    return callVM<Fn, jit::RecreateLexicalEnv>();
   };
   return emitDebugInstrumentation(ifDebuggee, mozilla::Some(ifNotDebuggee));
 }
 
-typedef bool (*DebugLeaveLexicalEnvFn)(JSContext*, BaselineFrame*, jsbytecode*);
-static const VMFunction DebugLeaveLexicalEnvInfo =
-    FunctionInfo<DebugLeaveLexicalEnvFn>(jit::DebugLeaveLexicalEnv,
-                                         "DebugLeaveLexicalEnv");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_DEBUGLEAVELEXICALENV() {
   auto ifDebuggee = [this]() {
     prepareVMCall();
     masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
     pushBytecodePCArg();
     pushArg(R0.scratchReg());
-    return callVM(DebugLeaveLexicalEnvInfo);
+
+    using Fn = bool (*)(JSContext*, BaselineFrame*, jsbytecode*);
+    return callVM<Fn, jit::DebugLeaveLexicalEnv>();
   };
   return emitDebugInstrumentation(ifDebuggee);
 }
 
-typedef bool (*PushVarEnvFn)(JSContext*, BaselineFrame*, HandleScope);
-static const VMFunction PushVarEnvInfo =
-    FunctionInfo<PushVarEnvFn>(jit::PushVarEnv, "PushVarEnv");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_PUSHVARENV() {
   prepareVMCall();
   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
   pushScriptScopeArg();
   pushArg(R0.scratchReg());
 
-  return callVM(PushVarEnvInfo);
-}
-
-typedef bool (*PopVarEnvFn)(JSContext*, BaselineFrame*);
-static const VMFunction PopVarEnvInfo =
-    FunctionInfo<PopVarEnvFn>(jit::PopVarEnv, "PopVarEnv");
+  using Fn = bool (*)(JSContext*, BaselineFrame*, HandleScope);
+  return callVM<Fn, jit::PushVarEnv>();
+}
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_POPVARENV() {
   prepareVMCall();
   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
   pushArg(R0.scratchReg());
 
-  return callVM(PopVarEnvInfo);
-}
-
-typedef bool (*EnterWithFn)(JSContext*, BaselineFrame*, HandleValue,
-                            Handle<WithScope*>);
-static const VMFunction EnterWithInfo =
-    FunctionInfo<EnterWithFn>(jit::EnterWith, "EnterWith");
+  using Fn = bool (*)(JSContext*, BaselineFrame*);
+  return callVM<Fn, jit::PopVarEnv>();
+}
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_ENTERWITH() {
   // Pop "with" object to R0.
   frame.popRegsAndSync(1);
 
   // Call a stub to push the object onto the environment chain.
   prepareVMCall();
   masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
 
   pushScriptScopeArg();
   pushArg(R0);
   pushArg(R1.scratchReg());
 
-  return callVM(EnterWithInfo);
-}
-
-typedef bool (*LeaveWithFn)(JSContext*, BaselineFrame*);
-static const VMFunction LeaveWithInfo =
-    FunctionInfo<LeaveWithFn>(jit::LeaveWith, "LeaveWith");
+  using Fn =
+      bool (*)(JSContext*, BaselineFrame*, HandleValue, Handle<WithScope*>);
+  return callVM<Fn, jit::EnterWith>();
+}
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_LEAVEWITH() {
   // Call a stub to pop the with object from the environment chain.
   prepareVMCall();
 
   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
   pushArg(R0.scratchReg());
 
-  return callVM(LeaveWithInfo);
-}
-
-typedef bool (*GetAndClearExceptionFn)(JSContext*, MutableHandleValue);
-static const VMFunction GetAndClearExceptionInfo =
-    FunctionInfo<GetAndClearExceptionFn>(GetAndClearException,
-                                         "GetAndClearException");
+  using Fn = bool (*)(JSContext*, BaselineFrame*);
+  return callVM<Fn, jit::LeaveWith>();
+}
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_EXCEPTION() {
   prepareVMCall();
 
-  if (!callVM(GetAndClearExceptionInfo)) {
+  using Fn = bool (*)(JSContext*, MutableHandleValue);
+  if (!callVM<Fn, GetAndClearException>()) {
     return false;
   }
 
   frame.push(R0);
   return true;
 }
 
-typedef bool (*OnDebuggerStatementFn)(JSContext*, BaselineFrame*,
-                                      jsbytecode* pc, bool*);
-static const VMFunction OnDebuggerStatementInfo =
-    FunctionInfo<OnDebuggerStatementFn>(jit::OnDebuggerStatement,
-                                        "OnDebuggerStatement");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_DEBUGGER() {
   prepareVMCall();
   pushBytecodePCArg();
 
   frame.assertSyncedStack();
   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
   pushArg(R0.scratchReg());
 
-  if (!callVM(OnDebuggerStatementInfo)) {
+  using Fn = bool (*)(JSContext*, BaselineFrame*, jsbytecode*, bool*);
+  if (!callVM<Fn, jit::OnDebuggerStatement>()) {
     return false;
   }
 
   // If the stub returns |true|, return the frame's return value.
   Label done;
   masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &done);
   {
     masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
     masm.jump(&return_);
   }
   masm.bind(&done);
   return true;
 }
 
-typedef bool (*DebugEpilogueFn)(JSContext*, BaselineFrame*, jsbytecode*);
-static const VMFunction DebugEpilogueInfo = FunctionInfo<DebugEpilogueFn>(
-    jit::DebugEpilogueOnBaselineReturn, "DebugEpilogueOnBaselineReturn");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emitReturn() {
   auto ifDebuggee = [this]() {
     // Move return value into the frame's rval slot.
     masm.storeValue(JSReturnOperand, frame.addressOfReturnValue());
     masm.or32(Imm32(BaselineFrame::HAS_RVAL), frame.addressOfFlags());
 
     // Load BaselineFrame pointer in R0.
     frame.syncStack(0);
     masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
 
     prepareVMCall();
     pushBytecodePCArg();
     pushArg(R0.scratchReg());
-    if (!callVM(DebugEpilogueInfo)) {
+
+    using Fn = bool (*)(JSContext*, BaselineFrame*, jsbytecode*);
+    if (!callVM<Fn, jit::DebugEpilogueOnBaselineReturn>()) {
       return false;
     }
 
     // Fix up the RetAddrEntry appended by callVM for on-stack recompilation.
     handler.markLastRetAddrEntryKind(RetAddrEntry::Kind::DebugEpilogue);
 
     masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
     return true;
@@ -4486,83 +4415,74 @@ bool BaselineCodeGen<Handler>::emit_JSOP
                       &done);
     masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
     masm.bind(&done);
   }
 
   return emitReturn();
 }
 
-typedef bool (*ToIdFn)(JSContext*, HandleValue, MutableHandleValue);
-static const VMFunction ToIdInfo =
-    FunctionInfo<ToIdFn>(js::ToIdOperation, "ToIdOperation");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_TOID() {
   // Load index in R0, but keep values on the stack for the decompiler.
   frame.syncStack(0);
   masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   // No-op if the index is trivally convertable to an id.
   Label done;
   masm.branchTestInt32(Assembler::Equal, R0, &done);
   masm.branchTestString(Assembler::Equal, R0, &done);
   masm.branchTestSymbol(Assembler::Equal, R0, &done);
 
   prepareVMCall();
 
   pushArg(R0);
 
-  if (!callVM(ToIdInfo)) {
+  using Fn = bool (*)(JSContext*, HandleValue, MutableHandleValue);
+  if (!callVM<Fn, js::ToIdOperation>()) {
     return false;
   }
 
   masm.bind(&done);
   frame.pop();  // Pop index.
   frame.push(R0);
   return true;
 }
 
-typedef JSObject* (*ToAsyncIterFn)(JSContext*, HandleObject, HandleValue);
-static const VMFunction ToAsyncIterInfo =
-    FunctionInfo<ToAsyncIterFn>(js::CreateAsyncFromSyncIterator, "ToAsyncIter");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_TOASYNCITER() {
   frame.syncStack(0);
   masm.unboxObject(frame.addressOfStackValue(-2), R0.scratchReg());
   masm.loadValue(frame.addressOfStackValue(-1), R1);
 
   prepareVMCall();
   pushArg(R1);
   pushArg(R0.scratchReg());
 
-  if (!callVM(ToAsyncIterInfo)) {
+  using Fn = JSObject* (*)(JSContext*, HandleObject, HandleValue);
+  if (!callVM<Fn, js::CreateAsyncFromSyncIterator>()) {
     return false;
   }
 
   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
   frame.popn(2);
   frame.push(R0);
   return true;
 }
 
-typedef bool (*TrySkipAwaitFn)(JSContext*, HandleValue, MutableHandleValue);
-static const VMFunction TrySkipAwaitInfo =
-    FunctionInfo<TrySkipAwaitFn>(jit::TrySkipAwait, "TrySkipAwait");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_TRYSKIPAWAIT() {
   frame.syncStack(0);
   masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   prepareVMCall();
   pushArg(R0);
 
-  if (!callVM(TrySkipAwaitInfo)) {
+  using Fn = bool (*)(JSContext*, HandleValue, MutableHandleValue);
+  if (!callVM<Fn, jit::TrySkipAwait>()) {
     return false;
   }
 
   Label cannotSkip, done;
   masm.branchTestMagicValue(Assembler::Equal, R0, JS_CANNOT_SKIP_AWAIT,
                             &cannotSkip);
   masm.moveValue(BooleanValue(true), R1);
   masm.jump(&done);
@@ -4574,118 +4494,101 @@ bool BaselineCodeGen<Handler>::emit_JSOP
   masm.bind(&done);
 
   frame.pop();
   frame.push(R0);
   frame.push(R1);
   return true;
 }
 
-typedef JSObject* (*AsyncFunctionAwaitFn)(JSContext*,
-                                          Handle<AsyncFunctionGeneratorObject*>,
-                                          HandleValue);
-static const VMFunction AsyncFunctionAwaitInfo =
-    FunctionInfo<AsyncFunctionAwaitFn>(js::AsyncFunctionAwait,
-                                       "AsyncFunctionAwait");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_ASYNCAWAIT() {
   frame.syncStack(0);
   masm.loadValue(frame.addressOfStackValue(-2), R1);
   masm.unboxObject(frame.addressOfStackValue(-1), R0.scratchReg());
 
   prepareVMCall();
   pushArg(R1);
   pushArg(R0.scratchReg());
 
-  if (!callVM(AsyncFunctionAwaitInfo)) {
+  using Fn = JSObject* (*)(JSContext*, Handle<AsyncFunctionGeneratorObject*>,
+                           HandleValue);
+  if (!callVM<Fn, js::AsyncFunctionAwait>()) {
     return false;
   }
 
   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
   frame.popn(2);
   frame.push(R0);
   return true;
 }
 
-typedef JSObject* (*AsyncFunctionResolveFn)(
-    JSContext*, Handle<AsyncFunctionGeneratorObject*>, HandleValue,
-    AsyncFunctionResolveKind);
-static const VMFunction AsyncFunctionResolveInfo =
-    FunctionInfo<AsyncFunctionResolveFn>(js::AsyncFunctionResolve,
-                                         "AsyncFunctionResolve");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_ASYNCRESOLVE() {
   frame.syncStack(0);
   masm.loadValue(frame.addressOfStackValue(-2), R1);
   masm.unboxObject(frame.addressOfStackValue(-1), R0.scratchReg());
 
   prepareVMCall();
   pushUint8BytecodeOperandArg();
   pushArg(R1);
   pushArg(R0.scratchReg());
 
-  if (!callVM(AsyncFunctionResolveInfo)) {
+  using Fn = JSObject* (*)(JSContext*, Handle<AsyncFunctionGeneratorObject*>,
+                           HandleValue, AsyncFunctionResolveKind);
+  if (!callVM<Fn, js::AsyncFunctionResolve>()) {
     return false;
   }
 
   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
   frame.popn(2);
   frame.push(R0);
   return true;
 }
 
-typedef bool (*ThrowObjectCoercibleFn)(JSContext*, HandleValue);
-static const VMFunction ThrowObjectCoercibleInfo =
-    FunctionInfo<ThrowObjectCoercibleFn>(ThrowObjectCoercible,
-                                         "ThrowObjectCoercible");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_CHECKOBJCOERCIBLE() {
   frame.syncStack(0);
   masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   Label fail, done;
 
   masm.branchTestUndefined(Assembler::Equal, R0, &fail);
   masm.branchTestNull(Assembler::NotEqual, R0, &done);
 
   masm.bind(&fail);
   prepareVMCall();
 
   pushArg(R0);
 
-  if (!callVM(ThrowObjectCoercibleInfo)) {
+  using Fn = bool (*)(JSContext*, HandleValue);
+  if (!callVM<Fn, ThrowObjectCoercible>()) {
     return false;
   }
 
   masm.bind(&done);
   return true;
 }
 
-typedef JSString* (*ToStringFn)(JSContext*, HandleValue);
-static const VMFunction ToStringInfo =
-    FunctionInfo<ToStringFn>(ToStringSlow, "ToStringSlow");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_TOSTRING() {
   // Keep top stack value in R0.
   frame.popRegsAndSync(1);
 
   // Inline path for string.
   Label done;
   masm.branchTestString(Assembler::Equal, R0, &done);
 
   prepareVMCall();
 
   pushArg(R0);
 
   // Call ToStringSlow which doesn't handle string inputs.
-  if (!callVM(ToStringInfo)) {
+  using Fn = JSString* (*)(JSContext*, HandleValue);
+  if (!callVM<Fn, ToStringSlow<CanGC>>()) {
     return false;
   }
 
   masm.tagValue(JSVAL_TYPE_STRING, ReturnReg, R0);
 
   masm.bind(&done);
   frame.push(R0);
   return true;
@@ -4883,21 +4786,16 @@ bool BaselineCompilerCodeGen::emit_JSOP_
   return true;
 }
 
 template <>
 bool BaselineInterpreterCodeGen::emit_JSOP_ENVCALLEE() {
   MOZ_CRASH("NYI: interpreter JSOP_ENVCALLEE");
 }
 
-typedef JSObject* (*HomeObjectSuperBaseFn)(JSContext*, HandleObject);
-static const VMFunction HomeObjectSuperBaseInfo =
-    FunctionInfo<HomeObjectSuperBaseFn>(HomeObjectSuperBase,
-                                        "HomeObjectSuperBase");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_SUPERBASE() {
   frame.popRegsAndSync(1);
 
   Register scratch = R0.scratchReg();
   Register proto = R1.scratchReg();
 
   // Unbox callee.
@@ -4919,32 +4817,30 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 
   Label hasProto;
   MOZ_ASSERT(uintptr_t(TaggedProto::LazyProto) == 1);
   masm.branchPtr(Assembler::Above, proto, ImmWord(1), &hasProto);
 
   // Use VMCall for missing or lazy proto
   prepareVMCall();
   pushArg(scratch);  // [[HomeObject]]
-  if (!callVM(HomeObjectSuperBaseInfo)) {
+
+  using Fn = JSObject* (*)(JSContext*, HandleObject);
+  if (!callVM<Fn, HomeObjectSuperBase>()) {
     return false;
   }
   masm.movePtr(ReturnReg, proto);
 
   // Box prototype and return
   masm.bind(&hasProto);
   masm.tagValue(JSVAL_TYPE_OBJECT, proto, R1);
   frame.push(R1);
   return true;
 }
 
-typedef JSObject* (*SuperFunOperationFn)(JSContext*, HandleObject);
-static const VMFunction SuperFunOperationInfo =
-    FunctionInfo<SuperFunOperationFn>(SuperFunOperation, "SuperFunOperation");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_SUPERFUN() {
   frame.popRegsAndSync(1);
 
   Register callee = R0.scratchReg();
   Register proto = R1.scratchReg();
   Register scratch = R2.scratchReg();
 
@@ -4971,34 +4867,30 @@ bool BaselineCodeGen<Handler>::emit_JSOP
   // Valid constructor
   Label hasSuperFun;
   masm.jump(&hasSuperFun);
 
   // Slow path VM Call
   masm.bind(&needVMCall);
   prepareVMCall();
   pushArg(callee);
-  if (!callVM(SuperFunOperationInfo)) {
+
+  using Fn = JSObject* (*)(JSContext*, HandleObject);
+  if (!callVM<Fn, js::SuperFunOperation>()) {
     return false;
   }
   masm.movePtr(ReturnReg, proto);
 
   // Box prototype and return
   masm.bind(&hasSuperFun);
   masm.tagValue(JSVAL_TYPE_OBJECT, proto, R1);
   frame.push(R1);
   return true;
 }
 
-typedef bool (*NewArgumentsObjectFn)(JSContext*, BaselineFrame*,
-                                     MutableHandleValue);
-static const VMFunction NewArgumentsObjectInfo =
-    FunctionInfo<NewArgumentsObjectFn>(jit::NewArgumentsObject,
-                                       "NewArgumentsObject");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_ARGUMENTS() {
   frame.syncStack(0);
 
   MOZ_ASSERT_IF(handler.maybeScript(),
                 handler.maybeScript()->argumentsHasVarBinding());
 
   Label done;
@@ -5016,17 +4908,18 @@ bool BaselineCodeGen<Handler>::emit_JSOP
         Imm32(uint32_t(JSScript::MutableFlags::NeedsArgsObj)), &done);
   }
 
   prepareVMCall();
 
   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
   pushArg(R0.scratchReg());
 
-  if (!callVM(NewArgumentsObjectInfo)) {
+  using Fn = bool (*)(JSContext*, BaselineFrame*, MutableHandleValue);
+  if (!callVM<Fn, jit::NewArgumentsObject>()) {
     return false;
   }
 
   masm.bind(&done);
   frame.push(R0);
   return true;
 }
 
@@ -5038,29 +4931,27 @@ bool BaselineCodeGen<Handler>::emit_JSOP
     return false;
   }
 
   // Mark R0 as pushed stack value.
   frame.push(R0);
   return true;
 }
 
-typedef JSObject* (*CreateGeneratorFn)(JSContext*, BaselineFrame*);
-static const VMFunction CreateGeneratorInfo =
-    FunctionInfo<CreateGeneratorFn>(jit::CreateGenerator, "CreateGenerator");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_GENERATOR() {
   frame.assertStackDepth(0);
 
   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
 
   prepareVMCall();
   pushArg(R0.scratchReg());
-  if (!callVM(CreateGeneratorInfo)) {
+
+  using Fn = JSObject* (*)(JSContext*, BaselineFrame*);
+  if (!callVM<Fn, jit::CreateGenerator>()) {
     return false;
   }
 
   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
   frame.push(R0);
   return true;
 }
 
@@ -5093,21 +4984,16 @@ bool BaselineCodeGen<Handler>::emit_JSOP
   masm.call(&postBarrierSlot_);
   masm.pop(genObj);
   masm.bind(&skipBarrier);
 
   masm.tagValue(JSVAL_TYPE_OBJECT, genObj, JSReturnOperand);
   return emitReturn();
 }
 
-typedef bool (*NormalSuspendFn)(JSContext*, HandleObject, BaselineFrame*,
-                                jsbytecode*);
-static const VMFunction NormalSuspendInfo =
-    FunctionInfo<NormalSuspendFn>(jit::NormalSuspend, "NormalSuspend");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_YIELD() {
   // Store generator in R0.
   frame.popRegsAndSync(1);
 
   Register genObj = R2.scratchReg();
   masm.unboxObject(R0, genObj);
 
@@ -5137,44 +5023,42 @@ bool BaselineCodeGen<Handler>::emit_JSOP
   } else {
     masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
 
     prepareVMCall();
     pushBytecodePCArg();
     pushArg(R1.scratchReg());
     pushArg(genObj);
 
-    if (!callVM(NormalSuspendInfo)) {
+    using Fn = bool (*)(JSContext*, HandleObject, BaselineFrame*, jsbytecode*);
+    if (!callVM<Fn, jit::NormalSuspend>()) {
       return false;
     }
   }
 
   masm.loadValue(frame.addressOfStackValue(-1), JSReturnOperand);
   return emitReturn();
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_AWAIT() {
   return emit_JSOP_YIELD();
 }
 
-typedef bool (*DebugAfterYieldFn)(JSContext*, BaselineFrame*, jsbytecode*,
-                                  bool*);
-static const VMFunction DebugAfterYieldInfo =
-    FunctionInfo<DebugAfterYieldFn>(jit::DebugAfterYield, "DebugAfterYield");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_DEBUGAFTERYIELD() {
   auto ifDebuggee = [this]() {
     frame.assertSyncedStack();
     masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
     prepareVMCall();
     pushBytecodePCArg();
     pushArg(R0.scratchReg());
-    if (!callVM(DebugAfterYieldInfo)) {
+
+    using Fn = bool (*)(JSContext*, BaselineFrame*, jsbytecode*, bool*);
+    if (!callVM<Fn, jit::DebugAfterYield>()) {
       return false;
     }
 
     handler.markLastRetAddrEntryKind(RetAddrEntry::Kind::DebugAfterYield);
 
     Label done;
     masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &done);
     {
@@ -5182,43 +5066,35 @@ bool BaselineCodeGen<Handler>::emit_JSOP
       masm.jump(&return_);
     }
     masm.bind(&done);
     return true;
   };
   return emitDebugInstrumentation(ifDebuggee);
 }
 
-typedef bool (*FinalSuspendFn)(JSContext*, HandleObject, jsbytecode*);
-static const VMFunction FinalSuspendInfo =
-    FunctionInfo<FinalSuspendFn>(jit::FinalSuspend, "FinalSuspend");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_FINALYIELDRVAL() {
   // Store generator in R0.
   frame.popRegsAndSync(1);
   masm.unboxObject(R0, R0.scratchReg());
 
   prepareVMCall();
   pushBytecodePCArg();
   pushArg(R0.scratchReg());
 
-  if (!callVM(FinalSuspendInfo)) {
+  using Fn = bool (*)(JSContext*, HandleObject, jsbytecode*);
+  if (!callVM<Fn, jit::FinalSuspend>()) {
     return false;
   }
 
   masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
   return emitReturn();
 }
 
-typedef bool (*InterpretResumeFn)(JSContext*, HandleObject, HandleValue,
-                                  HandlePropertyName, MutableHandleValue);
-static const VMFunction InterpretResumeInfo =
-    FunctionInfo<InterpretResumeFn>(jit::InterpretResume, "InterpretResume");
-
 typedef bool (*GeneratorThrowFn)(JSContext*, BaselineFrame*,
                                  Handle<AbstractGeneratorObject*>, HandleValue,
                                  uint32_t);
 static const VMFunction GeneratorThrowOrReturnInfo =
     FunctionInfo<GeneratorThrowFn>(jit::GeneratorThrowOrReturn,
                                    "GeneratorThrowOrReturn", TailCall);
 
 template <>
@@ -5473,17 +5349,19 @@ bool BaselineCompilerCodeGen::emit_JSOP_
     MOZ_ASSERT(resumeKind == AbstractGeneratorObject::RETURN);
     pushArg(ImmGCPtr(cx->names().return_));
   }
 
   masm.loadValue(frame.addressOfStackValue(-1), retVal);
   pushArg(retVal);
   pushArg(genObj);
 
-  if (!callVM(InterpretResumeInfo)) {
+  using Fn = bool (*)(JSContext*, HandleObject, HandleValue, HandlePropertyName,
+                      MutableHandleValue);
+  if (!callVM<Fn, jit::InterpretResume>()) {
     return false;
   }
 
   // After the generator returns, we restore the stack pointer, switch back to
   // the current realm, push the return value, and we're done.
   masm.bind(&returnTarget);
   masm.computeEffectiveAddress(frame.addressOfStackValue(-1),
                                masm.getStackPointer());
@@ -5493,30 +5371,28 @@ bool BaselineCompilerCodeGen::emit_JSOP_
   return true;
 }
 
 template <>
 bool BaselineInterpreterCodeGen::emit_JSOP_RESUME() {
   MOZ_CRASH("NYI: interpreter JSOP_RESUME");
 }
 
-typedef bool (*CheckSelfHostedFn)(JSContext*, HandleValue);
-static const VMFunction CheckSelfHostedInfo = FunctionInfo<CheckSelfHostedFn>(
-    js::Debug_CheckSelfHosted, "Debug_CheckSelfHosted");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_DEBUGCHECKSELFHOSTED() {
 #ifdef DEBUG
   frame.syncStack(0);
 
   masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   prepareVMCall();
   pushArg(R0);
-  if (!callVM(CheckSelfHostedInfo)) {
+
+  using Fn = bool (*)(JSContext*, HandleValue);
+  if (!callVM<Fn, js::Debug_CheckSelfHosted>()) {
     return false;
   }
 #endif
   return true;
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_IS_CONSTRUCTING() {
@@ -5536,31 +5412,28 @@ bool BaselineCompilerCodeGen::emit_JSOP_
   return true;
 }
 
 template <>
 bool BaselineInterpreterCodeGen::emit_JSOP_JUMPTARGET() {
   MOZ_CRASH("NYI: interpreter JSOP_JUMPTARGET");
 }
 
-typedef bool (*CheckClassHeritageOperationFn)(JSContext*, HandleValue);
-static const VMFunction CheckClassHeritageOperationInfo =
-    FunctionInfo<CheckClassHeritageOperationFn>(js::CheckClassHeritageOperation,
-                                                "CheckClassHeritageOperation");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_CHECKCLASSHERITAGE() {
   frame.syncStack(0);
 
   // Leave the heritage value on the stack.
   masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   prepareVMCall();
   pushArg(R0);
-  return callVM(CheckClassHeritageOperationInfo);
+
+  using Fn = bool (*)(JSContext*, HandleValue);
+  return callVM<Fn, js::CheckClassHeritageOperation>();
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_INITHOMEOBJECT() {
   // Load HomeObject in R0.
   frame.popRegsAndSync(1);
 
   // Load function off stack
@@ -5588,101 +5461,89 @@ bool BaselineCompilerCodeGen::emit_JSOP_
   JSObject* builtin = BuiltinProtoOperation(cx, handler.pc());
   if (!builtin) {
     return false;
   }
   frame.push(ObjectValue(*builtin));
   return true;
 }
 
-typedef JSObject* (*BuiltinProtoOperationFn)(JSContext*, jsbytecode*);
-static const VMFunction BuiltinProtoOperationInfo =
-    FunctionInfo<BuiltinProtoOperationFn>(BuiltinProtoOperation,
-                                          "BuiltinProtoOperation");
-
 template <>
 bool BaselineInterpreterCodeGen::emit_JSOP_BUILTINPROTO() {
   prepareVMCall();
 
   pushBytecodePCArg();
 
-  if (!callVM(BuiltinProtoOperationInfo)) {
+  using Fn = JSObject* (*)(JSContext*, jsbytecode*);
+  if (!callVM<Fn, BuiltinProtoOperation>()) {
     return false;
   }
 
   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
   frame.push(R0);
   return true;
 }
 
-typedef JSObject* (*ObjectWithProtoOperationFn)(JSContext*, HandleValue);
-static const VMFunction ObjectWithProtoOperationInfo =
-    FunctionInfo<ObjectWithProtoOperationFn>(js::ObjectWithProtoOperation,
-                                             "ObjectWithProtoOperationInfo");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_OBJWITHPROTO() {
   frame.syncStack(0);
 
   // Leave the proto value on the stack for the decompiler
   masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   prepareVMCall();
   pushArg(R0);
-  if (!callVM(ObjectWithProtoOperationInfo)) {
+
+  using Fn = JSObject* (*)(JSContext*, HandleValue);
+  if (!callVM<Fn, js::ObjectWithProtoOperation>()) {
     return false;
   }
 
   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
   frame.pop();
   frame.push(R0);
   return true;
 }
 
-typedef JSObject* (*FunWithProtoFn)(JSContext*, HandleFunction, HandleObject,
-                                    HandleObject);
-static const VMFunction FunWithProtoInfo = FunctionInfo<FunWithProtoFn>(
-    js::FunWithProtoOperation, "FunWithProtoOperation");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_FUNWITHPROTO() {
   frame.popRegsAndSync(1);
 
   masm.unboxObject(R0, R0.scratchReg());
   masm.loadPtr(frame.addressOfEnvironmentChain(), R1.scratchReg());
 
   prepareVMCall();
   pushArg(R0.scratchReg());
   pushArg(R1.scratchReg());
   pushScriptObjectArg(ScriptObjectType::Function);
-  if (!callVM(FunWithProtoInfo)) {
+
+  using Fn =
+      JSObject* (*)(JSContext*, HandleFunction, HandleObject, HandleObject);
+  if (!callVM<Fn, js::FunWithProtoOperation>()) {
     return false;
   }
 
   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
   frame.push(R0);
   return true;
 }
 
-typedef JSFunction* (*MakeDefaultConstructorFn)(JSContext*, HandleScript,
-                                                jsbytecode*, HandleObject);
-static const VMFunction MakeDefaultConstructorInfo =
-    FunctionInfo<MakeDefaultConstructorFn>(js::MakeDefaultConstructor,
-                                           "MakeDefaultConstructor");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_CLASSCONSTRUCTOR() {
   frame.syncStack(0);
 
   // Pass nullptr as prototype to MakeDefaultConstructor
   prepareVMCall();
   pushArg(ImmPtr(nullptr));
   pushBytecodePCArg();
   pushScriptArg(R2.scratchReg());
-  if (!callVM(MakeDefaultConstructorInfo)) {
+
+  using Fn =
+      JSFunction* (*)(JSContext*, HandleScript, jsbytecode*, HandleObject);
+  if (!callVM<Fn, js::MakeDefaultConstructor>()) {
     return false;
   }
 
   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
   frame.push(R0);
   return true;
 }
 
@@ -5691,86 +5552,78 @@ bool BaselineCodeGen<Handler>::emit_JSOP
   frame.popRegsAndSync(1);
 
   masm.unboxObject(R0, R0.scratchReg());
 
   prepareVMCall();
   pushArg(R0.scratchReg());
   pushBytecodePCArg();
   pushScriptArg(R2.scratchReg());
-  if (!callVM(MakeDefaultConstructorInfo)) {
+
+  using Fn =
+      JSFunction* (*)(JSContext*, HandleScript, jsbytecode*, HandleObject);
+  if (!callVM<Fn, js::MakeDefaultConstructor>()) {
     return false;
   }
 
   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
   frame.push(R0);
   return true;
 }
 
-typedef JSObject* (*GetOrCreateModuleMetaObjectFn)(JSContext*, HandleObject);
-static const VMFunction GetOrCreateModuleMetaObjectInfo =
-    FunctionInfo<GetOrCreateModuleMetaObjectFn>(js::GetOrCreateModuleMetaObject,
-                                                "GetOrCreateModuleMetaObject");
-
 template <>
 bool BaselineCompilerCodeGen::emit_JSOP_IMPORTMETA() {
   // Note: this is like the interpreter implementation, but optimized a bit by
   // calling GetModuleObjectForScript at compile-time.
 
   RootedModuleObject module(cx, GetModuleObjectForScript(handler.script()));
   MOZ_ASSERT(module);
 
   frame.syncStack(0);
 
   prepareVMCall();
   pushArg(ImmGCPtr(module));
-  if (!callVM(GetOrCreateModuleMetaObjectInfo)) {
+
+  using Fn = JSObject* (*)(JSContext*, HandleObject);
+  if (!callVM<Fn, js::GetOrCreateModuleMetaObject>()) {
     return false;
   }
 
   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
   frame.push(R0);
   return true;
 }
 
-typedef JSObject* (*ImportMetaOperationFn)(JSContext*, HandleScript);
-static const VMFunction ImportMetaOperationInfo =
-    FunctionInfo<ImportMetaOperationFn>(ImportMetaOperation,
-                                        "ImportMetaOperation");
-
 template <>
 bool BaselineInterpreterCodeGen::emit_JSOP_IMPORTMETA() {
   prepareVMCall();
 
   pushScriptArg(R2.scratchReg());
 
-  if (!callVM(ImportMetaOperationInfo)) {
+  using Fn = JSObject* (*)(JSContext*, HandleScript);
+  if (!callVM<Fn, ImportMetaOperation>()) {
     return false;
   }
 
   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
   frame.push(R0);
   return true;
 }
 
-typedef JSObject* (*StartDynamicModuleImportFn)(JSContext*, HandleScript,
-                                                HandleValue);
-static const VMFunction StartDynamicModuleImportInfo =
-    FunctionInfo<StartDynamicModuleImportFn>(js::StartDynamicModuleImport,
-                                             "StartDynamicModuleImport");
-
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_DYNAMIC_IMPORT() {
   // Put specifier value in R0.
   frame.popRegsAndSync(1);
 
   prepareVMCall();
   pushArg(R0);
   pushScriptArg(R2.scratchReg());
-  if (!callVM(StartDynamicModuleImportInfo)) {
+
+  using Fn = JSObject* (*)(JSContext*, HandleScript, HandleValue);
+  if (!callVM<Fn, js::StartDynamicModuleImport>()) {
     return false;
   }
 
   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
   frame.push(R0);
   return true;
 }
 
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -341,25 +341,24 @@ class BaselineCodeGen {
 
   void prepareVMCall();
 
   void storeFrameSizeAndPushDescriptor(uint32_t frameBaseSize, uint32_t argSize,
                                        const Address& frameSizeAddr,
                                        Register scratch1, Register scratch2);
 
   enum CallVMPhase { POST_INITIALIZE, CHECK_OVER_RECURSED };
-  bool callVM(const VMFunctionData& fun, TrampolinePtr code,
-              CallVMPhase phase = POST_INITIALIZE);
-  bool callVM(const VMFunction& fun, CallVMPhase phase = POST_INITIALIZE);
+  bool callVMInternal(VMFunctionId id, CallVMPhase phase);
 
   template <typename Fn, Fn fn>
   bool callVM(CallVMPhase phase = POST_INITIALIZE);
 
-  bool callVMNonOp(const VMFunction& fun, CallVMPhase phase = POST_INITIALIZE) {
-    if (!callVM(fun, phase)) {
+  template <typename Fn, Fn fn>
+  bool callVMNonOp(CallVMPhase phase = POST_INITIALIZE) {
+    if (!callVM<Fn, fn>(phase)) {
       return false;
     }
     handler.markLastRetAddrEntryKind(RetAddrEntry::Kind::NonOpCallVM);
     return true;
   }
 
   // ifDebuggee should be a function emitting code for when the script is a
   // debuggee script. ifNotDebuggee (if present) is called to emit code for
@@ -662,14 +661,12 @@ class BaselineInterpreterHandler {
 
 using BaselineInterpreterCodeGen = BaselineCodeGen<BaselineInterpreterHandler>;
 
 class BaselineInterpreterGenerator final : private BaselineInterpreterCodeGen {
  public:
   explicit BaselineInterpreterGenerator(JSContext* cx);
 };
 
-extern const VMFunction ImplicitThisInfo;
-
 }  // namespace jit
 }  // namespace js
 
 #endif /* jit_BaselineCompiler_h */
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -7001,16 +7001,21 @@ void CodeGenerator::visitComputeThis(LCo
   OutOfLineCode* ool = oolCallVM(BoxNonStrictThisInfo, lir, ArgList(value),
                                  StoreValueTo(output));
 
   masm.branchTestObject(Assembler::NotEqual, value, ool->entry());
   masm.moveValue(value, output);
   masm.bind(ool->rejoin());
 }
 
+typedef bool (*ImplicitThisFn)(JSContext*, HandleObject, HandlePropertyName,
+                               MutableHandleValue);
+static const VMFunction ImplicitThisInfo = FunctionInfo<ImplicitThisFn>(
+    ImplicitThisOperation, "ImplicitThisOperation");
+
 void CodeGenerator::visitImplicitThis(LImplicitThis* lir) {
   pushArg(ImmGCPtr(lir->mir()->name()));
   pushArg(ToRegister(lir->env()));
   callVM(ImplicitThisInfo, lir);
 }
 
 void CodeGenerator::visitArrowNewTarget(LArrowNewTarget* lir) {
   Register callee = ToRegister(lir->callee());
@@ -11468,17 +11473,17 @@ void CodeGenerator::visitSetPropertyCach
   addSetPropertyCache(ins, liveRegs, objReg, temp, tempDouble, tempF32, id,
                       value, ins->mir()->strict(),
                       ins->mir()->needsPostBarrier(),
                       ins->mir()->needsTypeBarrier(), ins->mir()->guardHoles());
 }
 
 typedef bool (*ThrowFn)(JSContext*, HandleValue);
 static const VMFunction ThrowInfoCodeGen =
-    FunctionInfo<ThrowFn>(js::Throw, "Throw");
+    FunctionInfo<ThrowFn>(js::ThrowOperation, "ThrowOperation");
 
 void CodeGenerator::visitThrow(LThrow* lir) {
   pushArg(ToValue(lir, LThrow::Value));
   callVM(ThrowInfoCodeGen, lir);
 }
 
 typedef bool (*BitNotFn)(JSContext*, MutableHandleValue, MutableHandleValue);
 static const VMFunction BitNotInfo = FunctionInfo<BitNotFn>(BitNot, "BitNot");
--- a/js/src/jit/VMFunctionList-inl.h
+++ b/js/src/jit/VMFunctionList-inl.h
@@ -2,64 +2,115 @@
  * vim: set ts=8 sts=2 et sw=2 tw=80:
  * 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 "jit/BaselineIC.h"
 #include "jit/JitRealm.h"
 #include "jit/VMFunctions.h"
+#include "vm/AsyncFunction.h"
+#include "vm/AsyncIteration.h"
 #include "vm/Interpreter.h"
 
 #include "jit/BaselineFrame-inl.h"
 #include "vm/Interpreter-inl.h"
 
 namespace js {
 namespace jit {
 
 // List of all VM functions to be used with callVM. Each entry stores the name
 // (must be unique, used for the VMFunctionId enum and profiling) and the C++
 // function to be called. This list must be sorted on the name field.
-#define VMFUNCTION_LIST(_)                                                   \
-  _(BaselineDebugPrologue, js::jit::DebugPrologue)                           \
-  _(BaselineGetFunctionThis, js::jit::BaselineGetFunctionThis)               \
-  _(BaselineThrowInitializedThis, js::jit::BaselineThrowInitializedThis)     \
-  _(BaselineThrowUninitializedThis, js::jit::BaselineThrowUninitializedThis) \
-  _(BindVarOperation, js::BindVarOperation)                                  \
-  _(CheckIsCallable, js::jit::CheckIsCallable)                               \
-  _(CheckOverRecursedBaseline, js::jit::CheckOverRecursedBaseline)           \
-  _(CloneRegExpObject, js::CloneRegExpObject)                                \
-  _(DefFunOperation, js::DefFunOperation)                                    \
-  _(DefLexicalOperation, js::DefLexicalOperation)                            \
-  _(DefVarOperation, js::DefVarOperation)                                    \
-  _(DeleteElementNonStrict, js::DeleteElementJit<false>)                     \
-  _(DeleteElementStrict, js::DeleteElementJit<true>)                         \
-  _(DeleteNameOperation, js::DeleteNameOperation)                            \
-  _(DeletePropertyNonStrict, js::DeletePropertyJit<false>)                   \
-  _(DeletePropertyStrict, js::DeletePropertyJit<true>)                       \
-  _(GetImportOperation, js::GetImportOperation)                              \
-  _(GetNonSyntacticGlobalThis, js::GetNonSyntacticGlobalThis)                \
-  _(InitElemGetterSetterOperation, js::InitElemGetterSetterOperation)        \
-  _(InitPropGetterSetterOperation, js::InitPropGetterSetterOperation)        \
-  _(InterruptCheck, js::jit::InterruptCheck)                                 \
-  _(IonCompileScriptForBaseline, js::jit::IonCompileScriptForBaseline)       \
-  _(Lambda, js::Lambda)                                                      \
-  _(LambdaArrow, js::LambdaArrow)                                            \
-  _(MutatePrototype, js::jit::MutatePrototype)                               \
-  _(NewArrayCopyOnWriteOperation, js::NewArrayCopyOnWriteOperation)          \
-  _(NewDenseCopyOnWriteArray, js::NewDenseCopyOnWriteArray)                  \
-  _(OptimizeSpreadCall, js::OptimizeSpreadCall)                              \
-  _(ProcessCallSiteObjOperation, js::ProcessCallSiteObjOperation)            \
-  _(SetFunctionName, js::SetFunctionName)                                    \
-  _(SetIntrinsicOperation, js::SetIntrinsicOperation)                        \
-  _(SetPropertySuper, js::SetPropertySuper)                                  \
-  _(SingletonObjectLiteralOperation, js::SingletonObjectLiteralOperation)    \
-  _(ThrowBadDerivedReturn, js::jit::ThrowBadDerivedReturn)                   \
-  _(ThrowCheckIsObject, js::ThrowCheckIsObject)                              \
-  _(ThrowRuntimeLexicalError, js::jit::ThrowRuntimeLexicalError)
+#define VMFUNCTION_LIST(_)                                                     \
+  _(AsyncFunctionAwait, js::AsyncFunctionAwait)                                \
+  _(AsyncFunctionResolve, js::AsyncFunctionResolve)                            \
+  _(BaselineDebugPrologue, js::jit::DebugPrologue)                             \
+  _(BaselineGetFunctionThis, js::jit::BaselineGetFunctionThis)                 \
+  _(BaselineThrowInitializedThis, js::jit::BaselineThrowInitializedThis)       \
+  _(BaselineThrowUninitializedThis, js::jit::BaselineThrowUninitializedThis)   \
+  _(BindVarOperation, js::BindVarOperation)                                    \
+  _(BuiltinProtoOperation, js::BuiltinProtoOperation)                          \
+  _(CheckClassHeritageOperation, js::CheckClassHeritageOperation)              \
+  _(CheckGlobalOrEvalDeclarationConflicts,                                     \
+    js::CheckGlobalOrEvalDeclarationConflicts)                                 \
+  _(CheckIsCallable, js::jit::CheckIsCallable)                                 \
+  _(CheckOverRecursedBaseline, js::jit::CheckOverRecursedBaseline)             \
+  _(CloneRegExpObject, js::CloneRegExpObject)                                  \
+  _(CreateAsyncFromSyncIterator, js::CreateAsyncFromSyncIterator)              \
+  _(CreateGenerator, js::jit::CreateGenerator)                                 \
+  _(DebugAfterYield, js::jit::DebugAfterYield)                                 \
+  _(DebugEpilogueOnBaselineReturn, js::jit::DebugEpilogueOnBaselineReturn)     \
+  _(DebugLeaveLexicalEnv, js::jit::DebugLeaveLexicalEnv)                       \
+  _(DebugLeaveThenFreshenLexicalEnv, js::jit::DebugLeaveThenFreshenLexicalEnv) \
+  _(DebugLeaveThenPopLexicalEnv, js::jit::DebugLeaveThenPopLexicalEnv)         \
+  _(DebugLeaveThenRecreateLexicalEnv,                                          \
+    js::jit::DebugLeaveThenRecreateLexicalEnv)                                 \
+  _(Debug_CheckSelfHosted, js::Debug_CheckSelfHosted)                          \
+  _(DefFunOperation, js::DefFunOperation)                                      \
+  _(DefLexicalOperation, js::DefLexicalOperation)                              \
+  _(DefVarOperation, js::DefVarOperation)                                      \
+  _(DeleteElementNonStrict, js::DeleteElementJit<false>)                       \
+  _(DeleteElementStrict, js::DeleteElementJit<true>)                           \
+  _(DeleteNameOperation, js::DeleteNameOperation)                              \
+  _(DeletePropertyNonStrict, js::DeletePropertyJit<false>)                     \
+  _(DeletePropertyStrict, js::DeletePropertyJit<true>)                         \
+  _(DoToNumber, js::jit::DoToNumber)                                           \
+  _(DoToNumeric, js::jit::DoToNumeric)                                         \
+  _(EnterWith, js::jit::EnterWith)                                             \
+  _(FinalSuspend, js::jit::FinalSuspend)                                       \
+  _(FreshenLexicalEnv, js::jit::FreshenLexicalEnv)                             \
+  _(FunWithProtoOperation, js::FunWithProtoOperation)                          \
+  _(GetAndClearException, js::GetAndClearException)                            \
+  _(GetImportOperation, js::GetImportOperation)                                \
+  _(GetNonSyntacticGlobalThis, js::GetNonSyntacticGlobalThis)                  \
+  _(GetOrCreateModuleMetaObject, js::GetOrCreateModuleMetaObject)              \
+  _(HomeObjectSuperBase, js::HomeObjectSuperBase)                              \
+  _(ImplicitThisOperation, js::ImplicitThisOperation)                          \
+  _(ImportMetaOperation, js::ImportMetaOperation)                              \
+  _(InitElemGetterSetterOperation, js::InitElemGetterSetterOperation)          \
+  _(InitFunctionEnvironmentObjects, js::jit::InitFunctionEnvironmentObjects)   \
+  _(InitPropGetterSetterOperation, js::InitPropGetterSetterOperation)          \
+  _(InterpretResume, js::jit::InterpretResume)                                 \
+  _(InterruptCheck, js::jit::InterruptCheck)                                   \
+  _(IonCompileScriptForBaseline, js::jit::IonCompileScriptForBaseline)         \
+  _(Lambda, js::Lambda)                                                        \
+  _(LambdaArrow, js::LambdaArrow)                                              \
+  _(LeaveWith, js::jit::LeaveWith)                                             \
+  _(MakeDefaultConstructor, js::MakeDefaultConstructor)                        \
+  _(MutatePrototype, js::jit::MutatePrototype)                                 \
+  _(NewArgumentsObject, js::jit::NewArgumentsObject)                           \
+  _(NewArrayCopyOnWriteOperation, js::NewArrayCopyOnWriteOperation)            \
+  _(NewDenseCopyOnWriteArray, js::NewDenseCopyOnWriteArray)                    \
+  _(NormalSuspend, js::jit::NormalSuspend)                                     \
+  _(ObjectWithProtoOperation, js::ObjectWithProtoOperation)                    \
+  _(OnDebuggerStatement, js::jit::OnDebuggerStatement)                         \
+  _(OptimizeSpreadCall, js::OptimizeSpreadCall)                                \
+  _(PopLexicalEnv, js::jit::PopLexicalEnv)                                     \
+  _(PopVarEnv, js::jit::PopVarEnv)                                             \
+  _(ProcessCallSiteObjOperation, js::ProcessCallSiteObjOperation)              \
+  _(PushLexicalEnv, js::jit::PushLexicalEnv)                                   \
+  _(PushVarEnv, js::jit::PushVarEnv)                                           \
+  _(RecreateLexicalEnv, js::jit::RecreateLexicalEnv)                           \
+  _(SetFunctionName, js::SetFunctionName)                                      \
+  _(SetIntrinsicOperation, js::SetIntrinsicOperation)                          \
+  _(SetObjectElementWithReceiver, js::SetObjectElementWithReceiver)            \
+  _(SetPropertySuper, js::SetPropertySuper)                                    \
+  _(SingletonObjectLiteralOperation, js::SingletonObjectLiteralOperation)      \
+  _(StartDynamicModuleImport, js::StartDynamicModuleImport)                    \
+  _(SuperFunOperation, js::SuperFunOperation)                                  \
+  _(ThrowBadDerivedReturn, js::jit::ThrowBadDerivedReturn)                     \
+  _(ThrowCheckIsObject, js::ThrowCheckIsObject)                                \
+  _(ThrowMsgOperation, js::ThrowMsgOperation)                                  \
+  _(ThrowObjectCoercible, js::jit::ThrowObjectCoercible)                       \
+  _(ThrowOperation, js::ThrowOperation)                                        \
+  _(ThrowRuntimeLexicalError, js::jit::ThrowRuntimeLexicalError)               \
+  _(ToIdOperation, js::ToIdOperation)                                          \
+  _(ToStringSlow, js::ToStringSlow<CanGC>)                                     \
+  _(TrySkipAwait, js::jit::TrySkipAwait)
 
 enum class VMFunctionId {
 #define DEF_ID(name, fp) name,
   VMFUNCTION_LIST(DEF_ID)
 #undef DEF_ID
       Count
 };
 
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1840,18 +1840,18 @@ bool GetPrototypeOf(JSContext* cx, Handl
     return false;
   }
   rval.setObjectOrNull(proto);
   return true;
 }
 
 typedef bool (*SetObjectElementFn)(JSContext*, HandleObject, HandleValue,
                                    HandleValue, HandleValue, bool);
-const VMFunction SetObjectElementInfo =
-    FunctionInfo<SetObjectElementFn>(js::SetObjectElement, "SetObjectElement");
+const VMFunction SetObjectElementInfo = FunctionInfo<SetObjectElementFn>(
+    js::SetObjectElementWithReceiver, "SetObjectElementWithReceiver");
 
 typedef JSString* (*ConcatStringsFn)(JSContext*, HandleString, HandleString);
 const VMFunction ConcatStringsInfo =
     FunctionInfo<ConcatStringsFn>(ConcatStrings<CanGC>, "ConcatStrings");
 
 static JSString* ConvertObjectToStringForConcat(JSContext* cx,
                                                 HandleValue obj) {
   MOZ_ASSERT(obj.isObject());
@@ -1982,23 +1982,22 @@ const VMFunction AddOrUpdateSparseElemen
 
 typedef bool (*GetSparseElementHelperFn)(JSContext* cx, HandleArrayObject obj,
                                          int32_t int_id,
                                          MutableHandleValue result);
 const VMFunction GetSparseElementHelperInfo =
     FunctionInfo<GetSparseElementHelperFn>(GetSparseElementHelper,
                                            "getSparseElementHelper");
 
-static bool DoToNumber(JSContext* cx, HandleValue arg, MutableHandleValue ret) {
+bool DoToNumber(JSContext* cx, HandleValue arg, MutableHandleValue ret) {
   ret.set(arg);
   return ToNumber(cx, ret);
 }
 
-static bool DoToNumeric(JSContext* cx, HandleValue arg,
-                        MutableHandleValue ret) {
+bool DoToNumeric(JSContext* cx, HandleValue arg, MutableHandleValue ret) {
   ret.set(arg);
   return ToNumeric(cx, ret);
 }
 
 typedef bool (*ToNumericFn)(JSContext*, HandleValue, MutableHandleValue);
 const VMFunction ToNumberInfo =
     FunctionInfo<ToNumericFn>(DoToNumber, "ToNumber");
 const VMFunction ToNumericInfo =
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -1209,16 +1209,19 @@ bool DoConcatStringObject(JSContext* cx,
 // If the await operation can be skipped and the resolution value for `val` can
 // be acquired, stored the resolved value to `resolved`.  Otherwise, stores
 // the JS_CANNOT_SKIP_AWAIT magic value to `resolved`.
 MOZ_MUST_USE bool TrySkipAwait(JSContext* cx, HandleValue val,
                                MutableHandleValue resolved);
 
 bool IsPossiblyWrappedTypedArray(JSContext* cx, JSObject* obj, bool* result);
 
+bool DoToNumber(JSContext* cx, HandleValue arg, MutableHandleValue ret);
+bool DoToNumeric(JSContext* cx, HandleValue arg, MutableHandleValue ret);
+
 // VMFunctions shared by JITs
 extern const VMFunction SetArrayLengthInfo;
 extern const VMFunction SetObjectElementInfo;
 
 extern const VMFunction StringsEqualInfo;
 extern const VMFunction StringsNotEqualInfo;
 extern const VMFunction ConcatStringsInfo;
 extern const VMFunction StringSplitHelperInfo;
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -2933,17 +2933,18 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_
           "setelem-super and strictsetelem-super must be the same size");
 
       ReservedRooted<Value> receiver(&rootValue0, REGS.sp[-4]);
       ReservedRooted<Value> index(&rootValue1, REGS.sp[-3]);
       ReservedRooted<JSObject*> obj(&rootObject1, &REGS.sp[-2].toObject());
       HandleValue value = REGS.stackHandleAt(-1);
 
       bool strict = JSOp(*REGS.pc) == JSOP_STRICTSETELEM_SUPER;
-      if (!SetObjectElement(cx, obj, index, value, receiver, strict)) {
+      if (!SetObjectElementWithReceiver(cx, obj, index, value, receiver,
+                                        strict)) {
         goto error;
       }
       REGS.sp[-4] = value;
       REGS.sp -= 3;
     }
     END_CASE(JSOP_SETELEM_SUPER)
 
     CASE(JSOP_EVAL)
@@ -3876,17 +3877,17 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_
 
     CASE(JSOP_FINALLY) { CHECK_BRANCH(); }
     END_CASE(JSOP_FINALLY)
 
     CASE(JSOP_THROW) {
       CHECK_BRANCH();
       ReservedRooted<Value> v(&rootValue0);
       POP_COPY_TO(v);
-      MOZ_ALWAYS_FALSE(Throw(cx, v));
+      MOZ_ALWAYS_FALSE(ThrowOperation(cx, v));
       /* let the code at error try to catch the exception. */
       goto error;
     }
 
     CASE(JSOP_INSTANCEOF) {
       ReservedRooted<Value> rref(&rootValue0, REGS.sp[-1]);
       if (HandleValue(rref).isPrimitive()) {
         ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rref, nullptr);
@@ -4398,17 +4399,17 @@ leave_on_safe_point:
   return interpReturnOK;
 
 prologue_error:
   interpReturnOK = false;
   frameHalfInitialized = true;
   goto prologue_return_continuation;
 }
 
-bool js::Throw(JSContext* cx, HandleValue v) {
+bool js::ThrowOperation(JSContext* cx, HandleValue v) {
   MOZ_ASSERT(!cx->isExceptionPending());
   cx->setPendingException(v);
   return false;
 }
 
 bool js::GetProperty(JSContext* cx, HandleValue v, HandlePropertyName name,
                      MutableHandleValue vp) {
   if (name == cx->names().length) {
@@ -4809,19 +4810,19 @@ bool js::SetObjectElement(JSContext* cx,
   if (!ToPropertyKey(cx, index, &id)) {
     return false;
   }
   RootedValue receiver(cx, ObjectValue(*obj));
   return SetObjectElementOperation(cx, obj, id, value, receiver, strict, script,
                                    pc);
 }
 
-bool js::SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index,
-                          HandleValue value, HandleValue receiver,
-                          bool strict) {
+bool js::SetObjectElementWithReceiver(JSContext* cx, HandleObject obj,
+                                      HandleValue index, HandleValue value,
+                                      HandleValue receiver, bool strict) {
   RootedId id(cx);
   if (!ToPropertyKey(cx, index, &id)) {
     return false;
   }
   return SetObjectElementOperation(cx, obj, id, value, receiver, strict);
 }
 
 bool js::SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index,
--- a/js/src/vm/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -420,17 +420,17 @@ class MOZ_STACK_CLASS TryNoteIter {
   const JSTryNote* operator*() const { return tn_; }
 };
 
 bool HandleClosingGeneratorReturn(JSContext* cx, AbstractFramePtr frame,
                                   bool ok);
 
 /************************************************************************/
 
-bool Throw(JSContext* cx, HandleValue v);
+bool ThrowOperation(JSContext* cx, HandleValue v);
 
 bool GetProperty(JSContext* cx, HandleValue value, HandlePropertyName name,
                  MutableHandleValue vp);
 
 JSObject* Lambda(JSContext* cx, HandleFunction fun, HandleObject parent);
 
 JSObject* LambdaArrow(JSContext* cx, HandleFunction fun, HandleObject parent,
                       HandleValue newTargetv);
@@ -442,18 +442,19 @@ bool CallElement(JSContext* cx, MutableH
                  MutableHandleValue res);
 
 bool SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index,
                       HandleValue value, bool strict);
 bool SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index,
                       HandleValue value, bool strict, HandleScript script,
                       jsbytecode* pc);
 
-bool SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index,
-                      HandleValue value, HandleValue receiver, bool strict);
+bool SetObjectElementWithReceiver(JSContext* cx, HandleObject obj,
+                                  HandleValue index, HandleValue value,
+                                  HandleValue receiver, bool strict);
 bool SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index,
                       HandleValue value, HandleValue receiver, bool strict,
                       HandleScript script, jsbytecode* pc);
 
 bool InitElementArray(JSContext* cx, jsbytecode* pc, HandleObject obj,
                       uint32_t index, HandleValue value);
 
 bool AddValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -3955,30 +3955,31 @@ static nsIFrame* NS_NewGridBoxFrame(nsIP
 /* static */
 const nsCSSFrameConstructor::FrameConstructionData*
 nsCSSFrameConstructor::FindXULTagData(const Element& aElement, nsAtom* aTag,
                                       ComputedStyle& aStyle) {
   MOZ_ASSERT(aElement.IsXULElement());
 
   static const FrameConstructionDataByTag sXULTagData[] = {
 #ifdef MOZ_XUL
-      SCROLLABLE_XUL_CREATE(button, NS_NewButtonBoxFrame),
       SCROLLABLE_XUL_CREATE(thumb, NS_NewButtonBoxFrame),
       SCROLLABLE_XUL_CREATE(checkbox, NS_NewButtonBoxFrame),
       SCROLLABLE_XUL_CREATE(radio, NS_NewButtonBoxFrame),
       SCROLLABLE_XUL_CREATE(titlebar, NS_NewTitleBarFrame),
       SCROLLABLE_XUL_CREATE(resizer, NS_NewResizerFrame),
       SCROLLABLE_XUL_CREATE(toolbarpaletteitem, NS_NewBoxFrame),
       SCROLLABLE_XUL_CREATE(treecolpicker, NS_NewButtonBoxFrame),
       SIMPLE_XUL_CREATE(image, NS_NewImageBoxFrame),
       SIMPLE_XUL_CREATE(spring, NS_NewLeafBoxFrame),
       SIMPLE_XUL_CREATE(spacer, NS_NewLeafBoxFrame),
       SIMPLE_XUL_CREATE(treechildren, NS_NewTreeBodyFrame),
       SIMPLE_XUL_CREATE(treecol, NS_NewTreeColFrame),
       SIMPLE_XUL_CREATE(text, NS_NewTextBoxFrame),
+      SIMPLE_TAG_CHAIN(button, nsCSSFrameConstructor::FindXULButtonData),
+      SIMPLE_TAG_CHAIN(toolbarbutton, nsCSSFrameConstructor::FindXULButtonData),
       SIMPLE_TAG_CHAIN(label, nsCSSFrameConstructor::FindXULLabelData),
       SIMPLE_TAG_CHAIN(description,
                        nsCSSFrameConstructor::FindXULDescriptionData),
       SIMPLE_XUL_CREATE(menu, NS_NewMenuFrame),
       SIMPLE_XUL_CREATE(menubutton, NS_NewMenuFrame),
       SIMPLE_XUL_CREATE(menulist, NS_NewMenuFrame),
       SIMPLE_XUL_CREATE(menuitem, NS_NewMenuItemFrame),
 #  ifdef XP_MACOSX
@@ -4016,16 +4017,32 @@ nsCSSFrameConstructor::FindPopupGroupDat
 
 /* static */
 const nsCSSFrameConstructor::FrameConstructionData
     nsCSSFrameConstructor::sXULTextBoxData =
         SIMPLE_XUL_FCDATA(NS_NewTextBoxFrame);
 
 /* static */
 const nsCSSFrameConstructor::FrameConstructionData*
+nsCSSFrameConstructor::FindXULButtonData(const Element& aElement,
+                                         ComputedStyle&) {
+  static const FrameConstructionData sXULMenuData =
+      SIMPLE_XUL_FCDATA(NS_NewMenuFrame);
+  if (aElement.AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
+                           nsGkAtoms::menu, eCaseMatters)) {
+    return &sXULMenuData;
+  }
+
+  static const FrameConstructionData sXULButtonData =
+      SCROLLABLE_XUL_FCDATA(NS_NewButtonBoxFrame);
+  return &sXULButtonData;
+}
+
+/* static */
+const nsCSSFrameConstructor::FrameConstructionData*
 nsCSSFrameConstructor::FindXULLabelData(const Element& aElement,
                                         ComputedStyle&) {
   if (aElement.HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
     return &sXULTextBoxData;
   }
 
   static const FrameConstructionData sLabelData =
       SIMPLE_XUL_FCDATA(NS_NewXULLabelFrame);
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -1518,16 +1518,18 @@ class nsCSSFrameConstructor final : publ
                                                      nsAtom* aTag,
                                                      ComputedStyle&);
   // XUL data-finding helper functions and structures
 #ifdef MOZ_XUL
   static const FrameConstructionData* FindPopupGroupData(const Element&,
                                                          ComputedStyle&);
   // sXULTextBoxData used for both labels and descriptions
   static const FrameConstructionData sXULTextBoxData;
+  static const FrameConstructionData* FindXULButtonData(const Element&,
+                                                        ComputedStyle&);
   static const FrameConstructionData* FindXULLabelData(const Element&,
                                                        ComputedStyle&);
   static const FrameConstructionData* FindXULDescriptionData(const Element&,
                                                              ComputedStyle&);
 #  ifdef XP_MACOSX
   static const FrameConstructionData* FindXULMenubarData(const Element&,
                                                          ComputedStyle&);
 #  endif /* XP_MACOSX */
--- a/layout/base/tests/chrome/chrome.ini
+++ b/layout/base/tests/chrome/chrome.ini
@@ -16,17 +16,16 @@ support-files =
   printpreview_font_mozprintcallback.html
   printpreview_font_mozprintcallback_ref.html
   file_bug1018265.xul
 
 [test_bug396367-1.html]
 [test_bug396367-2.html]
 [test_bug420499.xul]
 [test_bug458898.html]
-[test_bug504311.xul]
 [test_bug514660.xul]
 [test_bug533845.xul]
 skip-if = os == 'linux' && !debug # Bug 1208197
 [test_bug551434.html]
 [test_bug708062.html]
 [test_bug812817.xul]
 [test_bug847890_paintFlashing.html]
 [test_bug1018265.xul]
deleted file mode 100644
--- a/layout/base/tests/chrome/test_bug504311.xul
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
-<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
-                 type="text/css"?>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=504311
--->
-<window title="Mozilla Bug 504311"
-        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-        onload="doTest()">
-  <script type="application/javascript"
-          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-<body xmlns="http://www.w3.org/1999/xhtml">
-<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=504311"
-   target="_blank">Mozilla Bug 504311</a>
-</body>
-  <!-- test code goes here -->
-<script type="application/javascript">
-<![CDATA[
-SimpleTest.waitForExplicitFinish();
-
-function doTest()
-{
-  var tb = document.getElementById("tb01");
-  var inputField = tb.inputField;
-  var editor = inputField.editor;
-  editor = editor.QueryInterface(Ci.nsIPlaintextEditor);
-  editor.wrapWidth = -1;
-
-  ok(true, "Didn't crash");
-  SimpleTest.finish();
-}
-]]></script>
-<textbox id="tb01" multiline="true"/>
-</window>
--- a/layout/style/res/quirk.css
+++ b/layout/style/res/quirk.css
@@ -46,24 +46,16 @@ table {
 
   /* Quirk: cut off all font inheritance in tables except for family. */
   font-size: initial;
   font-weight: initial;
   font-style: initial;
   font-variant: initial;
 }
 
-/*
- * Make table borders gray for compatibility with what other browsers do
- * in all modes, rather than using the foreground color.
- */
-table, td, th, tr, thead, tbody, tfoot, colgroup, col {
-  border-color: gray;
-}
-
 
 /* Quirk: collapse top margin of BODY and TD and bottom margin of TD */
 
 /*
  * While it may seem simpler to use :-moz-first-node and :-moz-last-node without
  * tags, it's slower, since we have to do the :-moz-first-node or :-moz-last-node
  * check on every single element in the document.  If we list all the
  * element names for which the UA stylesheet specifies a margin, the
--- a/layout/tools/reftest/reftest-analyzer.xhtml
+++ b/layout/tools/reftest/reftest-analyzer.xhtml
@@ -220,55 +220,59 @@ var gTestItems;
 // in process_log.
 function test_parsing() {
   // Note that the logs in these testcases have been manually edited to strip
   // out stuff for brevity.
   var testcases = [
     { "name": "empty log",
       "log": "",
       "expected": { "pass": 0, "unexpected": 0, "random": 0, "skip": 0 },
+      "expected_images": 0,
     },
     { "name": "android log",
       "log": `[task 2018-12-28T10:36:45.718Z] 10:36:45     INFO -  REFTEST TEST-START | a == b
 [task 2018-12-28T10:36:45.719Z] 10:36:45     INFO -  REFTEST TEST-LOAD | a | 78 / 275 (28%)
 [task 2018-12-28T10:36:56.138Z] 10:36:56     INFO -  REFTEST TEST-LOAD | b | 78 / 275 (28%)
 [task 2018-12-28T10:37:06.559Z] 10:37:06     INFO -  REFTEST TEST-UNEXPECTED-FAIL | a == b | image comparison, max difference: 255, number of differing pixels: 5950
 [task 2018-12-28T10:37:06.568Z] 10:37:06     INFO -  REFTEST   IMAGE 1 (TEST): data:image/png;base64,
 [task 2018-12-28T10:37:06.577Z] 10:37:06     INFO -  REFTEST   IMAGE 2 (REFERENCE): data:image/png;base64,
 [task 2018-12-28T10:37:06.577Z] 10:37:06     INFO -  REFTEST INFO | Saved log: stuff trimmed here
 [task 2018-12-28T10:37:06.582Z] 10:37:06     INFO -  REFTEST TEST-END | a == b
 [task 2018-12-28T10:37:06.583Z] 10:37:06     INFO -  REFTEST TEST-START | a2 == b2
 [task 2018-12-28T10:37:06.583Z] 10:37:06     INFO -  REFTEST TEST-LOAD | a2 | 79 / 275 (28%)
 [task 2018-12-28T10:37:06.584Z] 10:37:06     INFO -  REFTEST TEST-LOAD | b2 | 79 / 275 (28%)
 [task 2018-12-28T10:37:16.982Z] 10:37:16     INFO -  REFTEST TEST-PASS | a2 == b2 | image comparison, max difference: 0, number of differing pixels: 0
 [task 2018-12-28T10:37:16.982Z] 10:37:16     INFO -  REFTEST TEST-END | a2 == b2`,
       "expected": { "pass": 1, "unexpected": 1, "random": 0, "skip": 0 },
+      "expected_images": 2,
     },
     { "name": "local reftest run (Linux)",
       "log": `REFTEST TEST-START | file:///a == file:///b
 REFTEST TEST-LOAD | file:///a | 73 / 86 (84%)
 REFTEST TEST-LOAD | file:///b | 73 / 86 (84%)
 REFTEST TEST-PASS | file:///a == file:///b | image comparison, max difference: 0, number of differing pixels: 0
 REFTEST TEST-END | file:///a == file:///b`,
       "expected": { "pass": 1, "unexpected": 0, "random": 0, "skip": 0 },
+      "expected_images": 0,
     },
     { "name": "wpt reftests (Linux automation)",
       "log": `16:50:43     INFO - TEST-START | /a
 16:50:43     INFO - PID 4276 | 1548694243694	Marionette	INFO	Testing http://web-platform.test:8000/a == http://web-platform.test:8000/b
 16:50:43     INFO - PID 4276 | 1548694243963	Marionette	INFO	No differences allowed
 16:50:44     INFO - TEST-PASS | /a | took 370ms
 16:50:44     INFO - TEST-START | /a2
 16:50:44     INFO - PID 4276 | 1548694244066	Marionette	INFO	Testing http://web-platform.test:8000/a2 == http://web-platform.test:8000/b2
 16:50:44     INFO - PID 4276 | 1548694244792	Marionette	INFO	No differences allowed
 16:50:44     INFO - PID 4276 | 1548694244792	Marionette	INFO	Found 28 pixels different, maximum difference per channel 14
 16:50:44     INFO - TEST-UNEXPECTED-FAIL | /a2 | Testing http://web-platform.test:8000/a2 == http://web-platform.test:8000/b2
 16:50:44     INFO - REFTEST   IMAGE 1 (TEST): data:image/png;base64,
 16:50:44     INFO - REFTEST   IMAGE 2 (REFERENCE): data:image/png;base64,
 16:50:44     INFO - TEST-INFO took 840ms`,
       "expected": { "pass": 1, "unexpected": 1, "random": 0, "skip": 0 },
+      "expected_images": 2,
     },
     { "name": "windows log",
       "log": `12:17:14     INFO - REFTEST TEST-START | a == b
 12:17:14     INFO - REFTEST TEST-LOAD | a | 1603 / 2053 (78%)
 12:17:14     INFO - REFTEST TEST-LOAD | b | 1603 / 2053 (78%)
 12:17:14     INFO - REFTEST TEST-PASS(EXPECTED RANDOM) | a == b | image comparison, max difference: 0, number of differing pixels: 0
 12:17:14     INFO - REFTEST TEST-END | a == b
 12:17:14     INFO - REFTEST TEST-START | a2 == b2
@@ -280,48 +284,94 @@ 12:17:14     INFO - REFTEST   IMAGE 2 (R
 12:17:14     INFO - REFTEST INFO | Saved log: stuff trimmed here
 12:17:14     INFO - REFTEST TEST-END | a2 == b2
 12:01:09     INFO - REFTEST TEST-START | a3 == b3
 12:01:09     INFO - REFTEST TEST-LOAD | a3 | 66 / 189 (34%)
 12:01:09     INFO - REFTEST TEST-LOAD | b3 | 66 / 189 (34%)
 12:01:09     INFO - REFTEST TEST-KNOWN-FAIL | a3 == b3 | image comparison, max difference: 255, number of differing pixels: 9654
 12:01:09     INFO - REFTEST TEST-END | a3 == b3`,
       "expected": { "pass": 1, "unexpected": 1, "random": 1, "skip": 0 },
+      "expected_images": 2,
     },
     { "name": "webrender wrench log (windows)",
       "log": `[task 2018-12-29T04:29:48.800Z] REFTEST a == b
 [task 2018-12-29T04:29:48.984Z] REFTEST a2 == b2
 [task 2018-12-29T04:29:49.053Z] REFTEST TEST-UNEXPECTED-FAIL | a2 == b2 | image comparison, max difference: 255, number of differing pixels: 3128
 [task 2018-12-29T04:29:49.053Z] REFTEST   IMAGE 1 (TEST): data:image/png;
 [task 2018-12-29T04:29:49.053Z] REFTEST   IMAGE 2 (REFERENCE): data:image/png;
 [task 2018-12-29T04:29:49.053Z] REFTEST TEST-END | a2 == b2`,
       "expected": { "pass": 0, "unexpected": 1, "random": 0, "skip": 0 },
+      "expected_images": 2,
+    },
+    { "name": "wpt reftests (Linux local; Bug 1530008)",
+      "log": `SUITE-START | Running 1 tests
+TEST-START | /css/css-backgrounds/border-image-6.html
+TEST-UNEXPECTED-FAIL | /css/css-backgrounds/border-image-6.html | Testing http://web-platform.test:8000/css/css-backgrounds/border-image-6.html == http://web-platform.test:8000/css/css-backgrounds/border-image-6-ref.html
+REFTEST   IMAGE 1 (TEST): data:image/png;base64,
+REFTEST   IMAGE 2 (REFERENCE): data:image/png;base64,
+TEST-INFO took 425ms
+SUITE-END | took 2s`,
+      "expected": { "pass": 0, "unexpected": 1, "random": 0, "skip": 0 },
+      "expected_images": 2,
+    },
+    { "name": "local reftest run with timestamps (Linux; Bug 1167712)",
+      "log": ` 0:05.21 REFTEST TEST-START | a
+ 0:05.21 REFTEST REFTEST TEST-LOAD | a | 0 / 1 (0%)
+ 0:05.27 REFTEST REFTEST TEST-LOAD | b | 0 / 1 (0%)
+ 0:05.66 REFTEST TEST-UNEXPECTED-FAIL | a | image comparison (==), max difference: 106, number of differing pixels: 800
+ 0:05.67 REFTEST REFTEST   IMAGE 1 (TEST): data:image/png;base64,
+ 0:05.67 REFTEST REFTEST   IMAGE 2 (REFERENCE): data:image/png;base64,
+ 0:05.73 REFTEST REFTEST TEST-END | a`,
+      "expected": { "pass": 0, "unexpected": 1, "random": 0, "skip": 0 },
+      "expected_images": 2,
+    },
+    { "name": "reftest run with whitespace compressed (Treeherder; Bug 1084322)",
+      "log": ` REFTEST TEST-START | a
+REFTEST TEST-LOAD | a | 0 / 1 (0%)
+REFTEST TEST-LOAD | b | 0 / 1 (0%)
+REFTEST TEST-UNEXPECTED-FAIL | a | image comparison (==), max difference: 106, number of differing pixels: 800
+REFTEST REFTEST IMAGE 1 (TEST): data:image/png;base64,
+REFTEST REFTEST IMAGE 2 (REFERENCE): data:image/png;base64,
+REFTEST REFTEST TEST-END | a`,
+      "expected": { "pass": 0, "unexpected": 1, "random": 0, "skip": 0 },
+      "expected_images": 2,
     },
   ];
 
   var current_test = 0;
 
   // Override the build_viewer function invoked at the end of process_log to
   // actually just check the results of parsing.
   build_viewer = function() {
     var expected = testcases[current_test].expected;
+    var expected_images = testcases[current_test].expected_images;
     for (var result of gTestItems) {
       for (let type in expected) { // type is "pass", "unexpected" etc.
         if (result[type]) {
           expected[type]--;
         }
       }
     }
     var failed = false;
     for (let type in expected) {
       if (expected[type] != 0) {
         console.log(`Failure: for testcase ${testcases[current_test].name} got ${expected[type]} fewer ${type} results than expected!`);
         failed = true;
       }
     }
+
+    let total_images = 0;
+    for (var result of gTestItems) {
+      total_images += result.images.length;
+    }
+    if (total_images !== expected_images) {
+      console.log(`Failure: for testcase ${testcases[current_test].name} got ${total_images} images, expected ${expected_images}`);
+      failed = true;
+    }
+
     if (!failed) {
       console.log(`Success for testcase ${testcases[current_test].name}`);
     }
   };
 
   while (current_test < testcases.length) {
     process_log(testcases[current_test].log);
     current_test++;
@@ -337,27 +387,26 @@ function process_log(contents) {
     // When making any changes to this code, please add a test to the
     // test_parsing function above, and ensure all existing tests pass.
     // !!!!!!
 
     var line = lines[j];
     // Ignore duplicated output in logcat.
     if (line.match(/I\/Gecko.*?REFTEST/))
       continue;
-    var match = line.match(/^.*?(?:REFTEST\s+)(.*)$/);
+    var match = line.match(/^.*?(?:REFTEST\s+)+(.*)$/);
     if (!match) {
       // WPT reftests don't always have the "REFTEST" prefix but do have
       // mozharness prefixing. Trying to match both prefixes optionally with a
       // single regex either makes an unreadable mess or matches everything so
       // we do them separately.
       match = line.match(/^(?:.*? (?:INFO|ERROR) -\s+)(.*)$/);
     }
-    if (!match)
-      continue;
-    line = match[1];
+    if (match)
+      line = match[1];
     match = line.match(/^(TEST-PASS|TEST-UNEXPECTED-PASS|TEST-FAIL|TEST-KNOWN-FAIL|TEST-UNEXPECTED-FAIL|TEST-DEBUG-INFO)(\(EXPECTED RANDOM\)|) \| ([^\|]+)(?: \|(.*)|$)/);
     if (match) {
       var state = match[1];
       var random = match[2];
       var url = match[3];
       var extra = match[4];
       gTestItems.push(
         {
@@ -367,17 +416,17 @@ function process_log(contents) {
           random: (random == "(EXPECTED RANDOM)"),
           skip: (extra == " (SKIP)"),
           url: url,
           images: [],
           imageLabels: []
         });
       continue;
     }
-    match = line.match(/IMAGE([^:]*): (data:.*)$/);
+    match = line.match(/^IMAGE([^:]*): (data:.*)$/);
     if (match) {
       var item = gTestItems[gTestItems.length - 1];
       item.images.push(match[2]);
       item.imageLabels.push(match[1]);
     }
   }
 
   build_viewer();
--- a/layout/tools/reftest/remotereftest.py
+++ b/layout/tools/reftest/remotereftest.py
@@ -191,18 +191,16 @@ class RemoteReftest(RefTest):
 
         self.remoteCache = os.path.join(options.remoteTestRoot, "cache/")
 
         # Check that Firefox is installed
         expected = options.app.split('/')[-1]
         if not self.device.is_app_installed(expected):
             raise Exception("%s is not installed on this device" % expected)
 
-        self.automation.deleteANRs()
-        self.automation.deleteTombstones()
         self.device.clear_logcat()
 
         self.device.rm(self.remoteCache, force=True, recursive=True)
 
         procName = options.app.split('/')[-1]
         self.device.stop_application(procName)
         if self.device.process_exist(procName):
             self.log.error("unable to kill %s before starting tests!" % procName)
--- a/layout/xul/reftest/reftest.list
+++ b/layout/xul/reftest/reftest.list
@@ -1,9 +1,7 @@
-fails-if(Android) == textbox-multiline-noresize.xul textbox-multiline-ref.xul # reference is blank on Android (due to no native theme support?)
-!= textbox-multiline-resize.xul textbox-multiline-ref.xul
 == popup-explicit-size.xul popup-explicit-size-ref.xul
 random-if(Android) == image-size.xul image-size-ref.xul
 == image-scaling-min-height-1.xul image-scaling-min-height-1-ref.xul
 == textbox-text-transform.xul textbox-text-transform-ref.xul
 
 == checkbox-dynamic-change.xul checkbox-dynamic-change-ref.xul
 == radio-dynamic-change.xul radio-dynamic-change-ref.xul
deleted file mode 100644
--- a/layout/xul/reftest/textbox-multiline-noresize.xul
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-<window align="start" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-<textbox style="margin: 0;" multiline="true" width="100" height="100"/>
-</window>
deleted file mode 100644
--- a/layout/xul/reftest/textbox-multiline-resize.xul
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-<window align="start" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-<textbox style="margin: 0;" resizable="true" multiline="true" width="100" height="100"/>
-</window>
--- a/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationClient.java
+++ b/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationClient.java
@@ -6,61 +6,73 @@
 package org.mozilla.gecko.notifications;
 
 import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.support.annotation.NonNull;
 import android.support.v4.app.NotificationCompat;
 import android.support.v4.app.NotificationManagerCompat;
 
+import com.squareup.picasso.Picasso;
+
 import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.GeckoActivityMonitor;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoService;
 import org.mozilla.gecko.NotificationListener;
 import org.mozilla.gecko.R;
-import org.mozilla.gecko.util.BitmapUtils;
+import org.mozilla.gecko.util.ThreadUtils;
 
+import java.io.IOException;
 import java.util.HashMap;
 
 /**
  * Client for posting notifications.
  */
 public final class NotificationClient implements NotificationListener {
     private static final String LOGTAG = "GeckoNotificationClient";
     /* package */ static final String CLICK_ACTION = AppConstants.ANDROID_PACKAGE_NAME + ".NOTIFICATION_CLICK";
     /* package */ static final String CLOSE_ACTION = AppConstants.ANDROID_PACKAGE_NAME + ".NOTIFICATION_CLOSE";
     /* package */ static final String PERSISTENT_INTENT_EXTRA = "persistentIntent";
 
     private final Context mContext;
     private final NotificationManagerCompat mNotificationManager;
 
     private final HashMap<String, Notification> mNotifications = new HashMap<>();
+    private final int notificationLargeIconHeight;
+    private final int notificationLargeIconWidth;
 
     /**
      * Notification associated with this service's foreground state.
      *
      * {@link android.app.Service#startForeground(int, android.app.Notification)}
      * associates the foreground with exactly one notification from the service.
      * To keep Fennec alive during downloads (and to make sure it can be killed
      * once downloads are complete), we make sure that the foreground is always
      * associated with an active progress notification if and only if at least
      * one download is in progress.
      */
     private String mForegroundNotification;
 
     public NotificationClient(Context context) {
         mContext = context.getApplicationContext();
         mNotificationManager = NotificationManagerCompat.from(mContext);
+
+        Resources resources = mContext.getResources();
+        notificationLargeIconHeight = resources
+                .getDimensionPixelSize(android.R.dimen.notification_large_icon_height);
+        notificationLargeIconWidth = resources
+                .getDimensionPixelSize(android.R.dimen.notification_large_icon_width);
     }
 
     @Override // NotificationListener
     public void showNotification(String name, String cookie, String title,
                                  String text, String host, String imageUrl) {
         showNotification(name, cookie, title, text, host, imageUrl, /* data */ null);
     }
 
@@ -156,18 +168,32 @@ public final class NotificationClient im
 
         if (!AppConstants.Versions.preO) {
             builder.setChannelId(NotificationHelper.getInstance(mContext)
                     .getNotificationChannel(NotificationHelper.Channel.SITE_NOTIFICATIONS).getId());
         }
 
         // Fetch icon.
         if (!imageUrl.isEmpty()) {
-            final Bitmap image = BitmapUtils.decodeUrl(imageUrl);
-            builder.setLargeIcon(image);
+            ThreadUtils.postToBackgroundThread(() -> {
+                Bitmap largeIcon = null;
+                try {
+                    largeIcon = Picasso.with(mContext)
+                            .load(imageUrl)
+                            .resize(notificationLargeIconWidth, notificationLargeIconHeight)
+                            .centerInside()
+                            .get();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+
+                if (largeIcon != null) {
+                    updateLargeIconForExistingNotification(name, largeIcon, builder);
+                }
+            });
         }
 
         builder.setWhen(System.currentTimeMillis());
         final Notification notification = builder.build();
 
         synchronized (this) {
             mNotifications.put(name, notification);
         }
@@ -358,9 +384,35 @@ public final class NotificationClient im
                 onNotificationClose(name);
                 setForegroundNotificationLocked(name, notification);
                 return;
             }
         }
 
         removeForegroundNotificationLocked();
     }
+
+    /**
+     * Update the largeIcon for an already posted {@link NotificationCompat}.
+     * <br>
+     * It may be a foreground notification or not and it may have already been removed
+     * in which case nothing will happen.
+     *
+     * @param notificationName the unique name by which to identify a particular notification
+     * @param largeIcon image to be used as {@link Notification#getLargeIcon()}
+     * @param builder the builder for the original notification. Holds all previous configuration.
+     */
+    private synchronized void updateLargeIconForExistingNotification(@NonNull final String notificationName,
+                                                        @NonNull final Bitmap largeIcon,
+                                                        @NonNull final NotificationCompat.Builder builder) {
+        // check if the notification hasn't been removed in the meantime
+        Notification notification = mNotifications.get(notificationName);
+
+        if (notification == null) {
+            return;
+        }
+
+        builder.setOnlyAlertOnce(true)
+                .setLargeIcon(largeIcon);
+
+        add(notificationName, builder.build());
+    }
 }
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5318,20 +5318,16 @@ pref("layout.css.touch_action.enabled", 
 pref("memory.ghost_window_timeout_seconds", 60);
 
 // Don't dump memory reports on OOM, by default.
 pref("memory.dump_reports_on_oom", false);
 
 // Number of stack frames to capture in createObjectURL for about:memory.
 pref("memory.blob_report.stack_frames", 0);
 
-// Disable idle observer fuzz, because only privileged content can access idle
-// observers (bug 780507).
-pref("dom.idle-observers-api.fuzz_time.disabled", true);
-
 // Activates the activity monitor
 pref("io.activity.enabled", false);
 
 // If true, reuse the same global for (almost) everything loaded by the component
 // loader (JS components, JSMs, etc). This saves memory, but makes it possible
 // for the scripts to interfere with each other.  A restart is required for this
 // to take effect.
 pref("jsloader.shareGlobal", true);
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -46,22 +46,22 @@ struct RedirectHistoryEntryInfo
 {
   PrincipalInfo       principalInfo;
   OptionalURIParams   referrerUri;
   nsCString           remoteAddress;
 };
 
 struct LoadInfoArgs
 {
-  OptionalPrincipalInfo       requestingPrincipalInfo;
+  PrincipalInfo?              requestingPrincipalInfo;
   PrincipalInfo               triggeringPrincipalInfo;
-  OptionalPrincipalInfo       principalToInheritInfo;
-  OptionalPrincipalInfo       sandboxedLoadingPrincipalInfo;
-  OptionalPrincipalInfo       topLevelPrincipalInfo;
-  OptionalPrincipalInfo       topLevelStorageAreaPrincipalInfo;
+  PrincipalInfo?              principalToInheritInfo;
+  PrincipalInfo?              sandboxedLoadingPrincipalInfo;
+  PrincipalInfo?              topLevelPrincipalInfo;
+  PrincipalInfo?              topLevelStorageAreaPrincipalInfo;
   OptionalURIParams           resultPrincipalURI;
   uint32_t                    securityFlags;
   uint32_t                    contentPolicyType;
   uint32_t                    tainting;
   bool                        upgradeInsecureRequests;
   bool                        browserUpgradeInsecureRequests;
   bool                        browserWouldUpgradeInsecureRequests;
   bool                        verifySignedContent;
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -60,17 +60,16 @@ using mozilla::dom::ChromeUtils;
 using mozilla::dom::ContentParent;
 using mozilla::dom::ServiceWorkerManager;
 using mozilla::dom::TabContext;
 using mozilla::dom::TabParent;
 using mozilla::dom::TCPServerSocketParent;
 using mozilla::dom::TCPSocketParent;
 using mozilla::dom::UDPSocketParent;
 using mozilla::ipc::LoadInfoArgsToLoadInfo;
-using mozilla::ipc::OptionalPrincipalInfo;