Merge autoland to mozilla-central. a=merge
authorshindli <shindli@mozilla.com>
Thu, 21 Mar 2019 06:33:42 +0200
changeset 465298 ac0cd1a710f3
parent 465172 74b3bf36f5e8 (current diff)
parent 465297 13b6a2368271 (diff)
child 465357 5cac2c92926e
child 465369 29476d3ca61d
push id35735
push usershindli@mozilla.com
push dateThu, 21 Mar 2019 04:34:45 +0000
treeherdermozilla-central@ac0cd1a710f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone68.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 autoland to mozilla-central. a=merge
browser/components/urlbar/tests/browser/browser_UrlbarInput_autofill.js
devtools/client/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.notftl
devtools/server/actors/csscoverage.js
devtools/shared/fronts/csscoverage.js
devtools/shared/locales/en-US/csscoverage.dtd
devtools/shared/locales/en-US/csscoverage.properties
devtools/shared/specs/csscoverage.js
js/src/tests/non262/fields/access.js
js/src/tests/non262/fields/basic.js
js/src/tests/non262/fields/error.js
js/src/tests/non262/fields/field_types.js
js/src/tests/non262/fields/literal.js
js/src/tests/non262/fields/mixed_methods.js
js/src/tests/non262/fields/quirks.js
security/manager/ssl/CertBlocklist.cpp
security/manager/ssl/CertBlocklist.h
security/manager/ssl/nsICertBlocklist.idl
security/manager/ssl/tests/unit/test_cert_blocklist.js
testing/web-platform/meta/webrtc/RTCPeerConnection-onsignalingstatechanged.https.html.ini
toolkit/components/passwordmgr/test/mochitest/test_autofill_from_bfache.html
toolkit/locales/en-US/chrome/passwordmgr/passwordManager.dtd
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -372,16 +372,30 @@ version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "cc"
 version = "1.0.23"
 source = "git+https://github.com/glandium/cc-rs?branch=1.0.23-clang-cl-aarch64#2aa71628b1261b5515bd8668afca591669ba195d"
 
 [[package]]
+name = "cert_storage"
+version = "0.0.1"
+dependencies = [
+ "base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "nserror 0.1.0",
+ "nsstring 0.1.0",
+ "rkv 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "style 0.0.1",
+ "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "xpcom 0.1.0",
+]
+
+[[package]]
 name = "cexpr"
 version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1122,16 +1136,17 @@ dependencies = [
 
 [[package]]
 name = "gkrust-shared"
 version = "0.1.0"
 dependencies = [
  "arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "audioipc-client 0.4.0",
  "audioipc-server 0.2.3",
+ "cert_storage 0.0.1",
  "cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "cubeb-pulse 0.2.0",
  "cubeb-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding_c 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding_glue 0.1.0",
  "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "geckoservo 0.0.1",
  "gkrust_utils 0.1.0",
@@ -1167,17 +1182,17 @@ source = "registry+https://github.com/ru
 dependencies = [
  "khronos_api 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "gleam"
-version = "0.6.12"
+version = "0.6.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "glob"
 version = "0.2.11"
@@ -3128,17 +3143,17 @@ dependencies = [
  "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "plane-split 0.13.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3179,17 +3194,17 @@ dependencies = [
  "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "nsstring 0.1.0",
  "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender 0.60.0",
 ]
 
@@ -3434,17 +3449,17 @@ dependencies = [
 "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
 "checksum futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "884dbe32a6ae4cd7da5c6db9b78114449df9953b8d490c9d7e1b51720b922c62"
 "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
 "checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
 "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
 "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592"
 "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
 "checksum gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0ffaf173cf76c73a73e080366bf556b4776ece104b06961766ff11449f38604"
-"checksum gleam 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "f1519ca611d230e1deadbedfb79044b921ac4a961ab8823fef10e37271e2c38e"
+"checksum gleam 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "17bca843dd3cf25db1bf415d55de9c0f0ae09dd7fa952ec3cef9930f90de1339"
 "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
 "checksum goblin 0.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "5911d7df7b8f65ab676c5327b50acea29d3c6a1a4ad05e444cf5dce321b26db2"
 "checksum h2 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "a27e7ed946e8335bdf9a191bc1b9b14a03ba822d013d2f58437f4fabcbd7fc2c"
 "checksum http 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "dca621d0fa606a5ff2850b6e337b57ad6137ee4d67e940449643ff45af6874c6"
 "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07"
 "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e"
 "checksum hyper 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c087746de95e20e4dabe86606c3a019964a8fde2d5f386152939063c116c5971"
 "checksum ident_case 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9826188e666f2ed92071d2dadef6edc430b11b158b5b2b3f4babbcc891eaaa"
--- a/accessible/jsat/EventManager.jsm
+++ b/accessible/jsat/EventManager.jsm
@@ -5,22 +5,18 @@
 "use strict";
 
 ChromeUtils.defineModuleGetter(this, "Services",
   "resource://gre/modules/Services.jsm");
 ChromeUtils.defineModuleGetter(this, "Utils",
   "resource://gre/modules/accessibility/Utils.jsm");
 ChromeUtils.defineModuleGetter(this, "Logger",
   "resource://gre/modules/accessibility/Utils.jsm");
-ChromeUtils.defineModuleGetter(this, "Roles",
-  "resource://gre/modules/accessibility/Constants.jsm");
 ChromeUtils.defineModuleGetter(this, "Events",
   "resource://gre/modules/accessibility/Constants.jsm");
-ChromeUtils.defineModuleGetter(this, "States",
-  "resource://gre/modules/accessibility/Constants.jsm");
 
 var EXPORTED_SYMBOLS = ["EventManager"];
 
 function EventManager(aContentScope) {
   this.contentScope = aContentScope;
   this.addEventListener = this.contentScope.addEventListener.bind(
     this.contentScope);
   this.removeEventListener = this.contentScope.removeEventListener.bind(
@@ -80,37 +76,16 @@ this.EventManager.prototype = {
         // NS_ERROR_FAILURE. Checking for aEvent.accessibleDocument.docType ==
         // 'window' does not currently work.
         (aEvent.accessibleDocument.DOMDocument.doctype &&
          aEvent.accessibleDocument.DOMDocument.doctype.name === "window")) {
       return;
     }
 
     switch (aEvent.eventType) {
-      case Events.VIRTUALCURSOR_CHANGED:
-      {
-        if (!aEvent.isFromUserInput) {
-          break;
-        }
-
-        const event = aEvent.
-          QueryInterface(Ci.nsIAccessibleVirtualCursorChangeEvent);
-        const position = event.newAccessible;
-
-        // We pass control to the vc in the embedded frame.
-        if (position && position.role == Roles.INTERNAL_FRAME) {
-          break;
-        }
-
-        // Blur to document if new position is not explicitly focused.
-        if (!position || !Utils.getState(position).contains(States.FOCUSED)) {
-          aEvent.accessibleDocument.takeFocus();
-        }
-        break;
-      }
       case Events.NAME_CHANGE:
       {
         // XXX: Port to Android
         break;
       }
       case Events.SCROLLING_START:
       {
         this.contentControl.autoMove(aEvent.accessible);
--- a/accessible/tests/browser/events/browser_test_focus_urlbar.js
+++ b/accessible/tests/browser/events/browser_test_focus_urlbar.js
@@ -18,16 +18,22 @@ function isEventForAutocompleteItem(even
 
 /**
  * Wait for an autocomplete search to finish.
  * This is necessary to ensure predictable results, as these searches are
  * async. Pressing down arrow will use results from the previous input if the
  * search isn't finished yet.
  */
 function waitForSearchFinish() {
+  if (UrlbarPrefs.get("quantumbar")) {
+    return Promise.all([
+      gURLBar.lastQueryContextPromise,
+      BrowserTestUtils.waitForCondition(() => gURLBar.view.isOpen)
+    ]);
+  }
   return BrowserTestUtils.waitForCondition(() =>
     (gURLBar.popupOpen && gURLBar.controller.searchStatus >=
       Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH),
     "Waiting for search to complete");
 }
 
 // Check that the URL bar manages accessibility focus appropriately.
 async function runTests() {
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -3313,17 +3313,17 @@ window._gBrowser = {
       var isBusy = aOtherTab.hasAttribute("busy");
       if (isBusy) {
         aOurTab.setAttribute("busy", "true");
         modifiedAttrs.push("busy");
         if (aOurTab.selected)
           this._isBusy = true;
       }
 
-      this._swapBrowserDocShells(aOurTab, otherBrowser, Ci.nsIBrowser.SWAP_DEFAULT, stateFlags);
+      this._swapBrowserDocShells(aOurTab, otherBrowser, stateFlags);
     }
 
     // Unregister the previously opened URI
     if (otherBrowser.registeredOpenURI) {
       let userContextId = otherBrowser.getAttribute("usercontextid") || 0;
       this.UrlbarProviderOpenTabs.unregisterOpenTab(otherBrowser.registeredOpenURI.spec,
                                                     userContextId);
       delete otherBrowser.registeredOpenURI;
@@ -3362,39 +3362,39 @@ window._gBrowser = {
 
     if (modifiedAttrs.length) {
       this._tabAttrModified(aOurTab, modifiedAttrs);
     }
 
     return true;
   },
 
-  swapBrowsers(aOurTab, aOtherTab, aFlags) {
+  swapBrowsers(aOurTab, aOtherTab) {
     let otherBrowser = aOtherTab.linkedBrowser;
     let otherTabBrowser = otherBrowser.getTabBrowser();
 
     // We aren't closing the other tab so, we also need to swap its tablisteners.
     let filter = otherTabBrowser._tabFilters.get(aOtherTab);
     let tabListener = otherTabBrowser._tabListeners.get(aOtherTab);
     otherBrowser.webProgress.removeProgressListener(filter);
     filter.removeProgressListener(tabListener);
 
     // Perform the docshell swap through the common mechanism.
-    this._swapBrowserDocShells(aOurTab, otherBrowser, aFlags);
+    this._swapBrowserDocShells(aOurTab, otherBrowser);
 
     // Restore the listeners for the swapped in tab.
     tabListener = new otherTabBrowser.ownerGlobal.TabProgressListener(aOtherTab, otherBrowser, false, false);
     otherTabBrowser._tabListeners.set(aOtherTab, tabListener);
 
     const notifyAll = Ci.nsIWebProgress.NOTIFY_ALL;
     filter.addProgressListener(tabListener, notifyAll);
     otherBrowser.webProgress.addProgressListener(filter, notifyAll);
   },
 
-  _swapBrowserDocShells(aOurTab, aOtherBrowser, aFlags, aStateFlags) {
+  _swapBrowserDocShells(aOurTab, aOtherBrowser, aStateFlags) {
     // aOurTab's browser needs to be inserted now if it hasn't already.
     this._insertBrowser(aOurTab);
 
     // Unhook our progress listener
     const filter = this._tabFilters.get(aOurTab);
     let tabListener = this._tabListeners.get(aOurTab);
     let ourBrowser = this.getBrowserForTab(aOurTab);
     ourBrowser.webProgress.removeProgressListener(filter);
@@ -3427,27 +3427,25 @@ window._gBrowser = {
     }
 
     // Register new outerWindowIDs.
     this._outerWindowIDBrowserMap.set(ourBrowser.outerWindowID, ourBrowser);
     if (remoteBrowser) {
       remoteBrowser._outerWindowIDBrowserMap.set(aOtherBrowser.outerWindowID, aOtherBrowser);
     }
 
-    if (!(aFlags & Ci.nsIBrowser.SWAP_KEEP_PERMANENT_KEY)) {
-      // Swap permanentKey properties.
-      let ourPermanentKey = ourBrowser.permanentKey;
-      ourBrowser.permanentKey = aOtherBrowser.permanentKey;
-      aOtherBrowser.permanentKey = ourPermanentKey;
-      aOurTab.permanentKey = ourBrowser.permanentKey;
-      if (remoteBrowser) {
-        let otherTab = remoteBrowser.getTabForBrowser(aOtherBrowser);
-        if (otherTab) {
-          otherTab.permanentKey = aOtherBrowser.permanentKey;
-        }
+    // Swap permanentKey properties.
+    let ourPermanentKey = ourBrowser.permanentKey;
+    ourBrowser.permanentKey = aOtherBrowser.permanentKey;
+    aOtherBrowser.permanentKey = ourPermanentKey;
+    aOurTab.permanentKey = ourBrowser.permanentKey;
+    if (remoteBrowser) {
+      let otherTab = remoteBrowser.getTabForBrowser(aOtherBrowser);
+      if (otherTab) {
+        otherTab.permanentKey = aOtherBrowser.permanentKey;
       }
     }
 
     // Restore the progress listener
     tabListener = new TabProgressListener(aOurTab, ourBrowser, false, false, aStateFlags);
     this._tabListeners.set(aOurTab, tabListener);
 
     const notifyAll = Ci.nsIWebProgress.NOTIFY_ALL;
--- a/browser/base/content/test/performance/browser_urlbar_keyed_search.js
+++ b/browser/base/content/test/performance/browser_urlbar_keyed_search.js
@@ -9,30 +9,16 @@
  * be modifying your code to avoid the reflow.
  *
  * See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
  * for tips on how to do that.
  */
 
 /* These reflows happen only the first time the panel opens. */
 const EXPECTED_REFLOWS_FIRST_OPEN = [
-  // This is the this.panel.openPopup() call in UrlbarView._openPanel.  See bug
-  // 1359989, which was filed against the legacy awesomebar but applies here too
-  // because it seems to be caused by platform code.
-  {
-    stack: [
-      "_openPanel@resource:///modules/UrlbarView.jsm",
-      "onQueryResults@resource:///modules/UrlbarView.jsm",
-      "_notify@resource:///modules/UrlbarController.jsm",
-      "receiveResults@resource:///modules/UrlbarController.jsm",
-      "notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
-      "add@resource:///modules/UrlbarProvidersManager.jsm",
-      "onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
-    ],
-  },
   {
     stack: [
       "__rebuild@chrome://browser/content/search/search-one-offs.js",
       /* This is limited to a one-line stack, because the next item is an async
          function and as such not supported on all trees, according to bug 1501761.
       "async*_rebuild@chrome://browser/content/search/search-one-offs.js",
       "async*_on_popupshowing@chrome://browser/content/search/search-one-offs.js",
       "handleEvent@chrome://browser/content/search/search-one-offs.js",
@@ -41,13 +27,22 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
       "_notify@resource:///modules/UrlbarController.jsm",
       "receiveResults@resource:///modules/UrlbarController.jsm",
       "notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
       "add@resource:///modules/UrlbarProvidersManager.jsm",
       "onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
       */
     ],
   },
+  // This is the this.panel.openPopup() call in UrlbarView._openPanel.  See bug
+  // 1359989, which was filed against the legacy awesomebar but applies here too
+  // because it seems to be caused by platform code.
+  {
+    stack: [
+      "_openPanel@resource:///modules/UrlbarView.jsm",
+      "onQueryResults@resource:///modules/UrlbarView.jsm",
+    ],
+  },
 ];
 
 add_task(async function quantumbar() {
   await runUrlbarTest(false, true, EXPECTED_REFLOWS_FIRST_OPEN);
 });
--- a/browser/base/content/test/performance/browser_urlbar_search.js
+++ b/browser/base/content/test/performance/browser_urlbar_search.js
@@ -11,59 +11,52 @@
  * See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
  * for tips on how to do that.
  */
 
 /* These reflows happen only the first time the panel opens. */
 const EXPECTED_REFLOWS_FIRST_OPEN = [
   {
     stack: [
-      "_openPanel@resource:///modules/UrlbarView.jsm",
-      "onQueryResults@resource:///modules/UrlbarView.jsm",
-      "_notify@resource:///modules/UrlbarController.jsm",
-      "receiveResults@resource:///modules/UrlbarController.jsm",
-      "notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
-      "add@resource:///modules/UrlbarProvidersManager.jsm",
-      "onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
-    ],
-  },
-  {
-    stack: [
       "__rebuild@chrome://browser/content/search/search-one-offs.js",
       /* This is limited to a one-line stack, because the next item is an async
          function and as such not supported on all trees, according to bug 1501761.
       "async*_rebuild@chrome://browser/content/search/search-one-offs.js",
       "async*_on_popupshowing@chrome://browser/content/search/search-one-offs.js",
       "handleEvent@chrome://browser/content/search/search-one-offs.js",
       "_openPanel@resource:///modules/UrlbarView.jsm",
       "onQueryResults@resource:///modules/UrlbarView.jsm",
       "_notify@resource:///modules/UrlbarController.jsm",
       "receiveResults@resource:///modules/UrlbarController.jsm",
       "notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
       "add@resource:///modules/UrlbarProvidersManager.jsm",
       "onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
       */
     ],
   },
+  // This is the this.panel.openPopup() call in UrlbarView._openPanel.  See bug
+  // 1359989, which was filed against the legacy awesomebar but applies here too
+  // because it seems to be caused by platform code.
+  {
+    stack: [
+      "_openPanel@resource:///modules/UrlbarView.jsm",
+      "onQueryResults@resource:///modules/UrlbarView.jsm",
+    ],
+  },
 ];
 
 /* These reflows happen every time the panel opens. */
 const EXPECTED_REFLOWS_SECOND_OPEN = [
   // This is the this.panel.openPopup() call in UrlbarView._openPanel.  See bug
   // 1359989, which was filed against the legacy awesomebar but applies here too
   // because it seems to be caused by platform code.
   {
     stack: [
       "_openPanel@resource:///modules/UrlbarView.jsm",
       "onQueryResults@resource:///modules/UrlbarView.jsm",
-      "_notify@resource:///modules/UrlbarController.jsm",
-      "receiveResults@resource:///modules/UrlbarController.jsm",
-      "notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
-      "add@resource:///modules/UrlbarProvidersManager.jsm",
-      "onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
     ],
   },
 ];
 
 add_task(async function quantumbar() {
   await runUrlbarTest(false, false, EXPECTED_REFLOWS_FIRST_OPEN,
                       EXPECTED_REFLOWS_SECOND_OPEN);
 });
--- a/browser/base/content/test/performance/head.js
+++ b/browser/base/content/test/performance/head.js
@@ -688,16 +688,34 @@ async function runUrlbarTest(useAwesomeb
       };
 
       win.setTimeout = (fn, ms) => {
         return oldSetTimeout(() => {
           dirtyFrame(win);
           fn();
         }, ms);
       };
+    } else {
+      let popup = URLBar.view;
+      let oldOnQueryResults = popup.onQueryResults.bind(popup);
+      let oldOnQueryFinished = popup.onQueryFinished.bind(popup);
+
+      // We need to invalidate the frame tree outside of the normal
+      // mechanism since invalidations and result additions to the
+      // URL bar occur without firing JS events (which is how we
+      // normally know to dirty the frame tree).
+      popup.onQueryResults = (context) => {
+        dirtyFrame(win);
+        oldOnQueryResults(context);
+      };
+
+      popup.onQueryFinished = (context) => {
+        dirtyFrame(win);
+        oldOnQueryFinished(context);
+      };
     }
 
     let waitExtra = async () => {
       // There are several setTimeout(fn, 0); calls inside autocomplete.xml
       // that we need to wait for. Since those have higher priority than
       // idle callbacks, we can be sure they will have run once this
       // idle callback is called. The timeout seems to be required in
       // automation - presumably because the machines can be pretty busy
--- a/browser/base/content/test/static/browser_all_files_referenced.js
+++ b/browser/base/content/test/static/browser_all_files_referenced.js
@@ -167,18 +167,16 @@ var whitelist = [
   {file: "chrome://devtools/skin/images/aboutdebugging-firefox-beta.svg",
    isFromDevTools: true},
   {file: "chrome://devtools/skin/images/aboutdebugging-firefox-release.svg",
    isFromDevTools: true},
   {file: "chrome://devtools/skin/images/next.svg", isFromDevTools: true},
   // kvstore.jsm wraps the API in nsIKeyValue.idl in a more ergonomic API
   // It landed in bug 1490496, and we expect to start using it shortly.
   {file: "resource://gre/modules/kvstore.jsm"},
-  {file: "chrome://devtools/content/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.ftl",
-   isFromDevTools: true},
   // Bug 1526672
   {file: "resource://app/localization/en-US/browser/touchbar/touchbar.ftl",
    platforms: ["linux", "win"]},
   // Referenced by the webcompat system addon for localization
   {file: "resource://gre/localization/en-US/toolkit/about/aboutCompat.ftl"},
 ];
 
 whitelist = new Set(whitelist.filter(item =>
--- a/browser/components/BrowserGlue.jsm
+++ b/browser/components/BrowserGlue.jsm
@@ -2267,17 +2267,17 @@ BrowserGlue.prototype = {
       }
     }
   },
 
   // eslint-disable-next-line complexity
   _migrateUI: function BG__migrateUI() {
     // Use an increasing number to keep track of the current migration state.
     // Completely unrelated to the current Firefox release number.
-    const UI_VERSION = 80;
+    const UI_VERSION = 81;
     const BROWSER_DOCURL = AppConstants.BROWSER_CHROME_URL;
 
     let currentUIVersion;
     if (Services.prefs.prefHasUserValue("browser.migration.version")) {
       currentUIVersion = Services.prefs.getIntPref("browser.migration.version");
     } else {
       // This is a new profile, nothing to migrate.
       Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
@@ -2580,16 +2580,36 @@ BrowserGlue.prototype = {
     if (currentUIVersion < 80) {
       let hosts = Services.prefs.getCharPref("network.proxy.no_proxies_on");
       // remove "localhost" and "127.0.0.1" from the no_proxies_on list
       const kLocalHosts = new Set(["localhost", "127.0.0.1"]);
       hosts = hosts.split(/[ ,]+/).filter(host => !kLocalHosts.has(host)).join(", ");
       Services.prefs.setCharPref("network.proxy.no_proxies_on", hosts);
     }
 
+    if (currentUIVersion < 81) {
+      // Reset homepage pref for users who have it set to a default from before Firefox 4:
+      //   <locale>.(start|start2|start3).mozilla.(com|org)
+      const HOMEPAGE_PREF = "browser.startup.homepage";
+      if (Services.prefs.prefHasUserValue(HOMEPAGE_PREF)) {
+        const DEFAULT = Services.prefs.getDefaultBranch(HOMEPAGE_PREF).getCharPref("");
+        let value = Services.prefs.getCharPref(HOMEPAGE_PREF);
+        let updated = value.replace(
+          /https?:\/\/([\w\-]+[.])?start[\d]*\.mozilla\.(org|com)[^|]*/ig, DEFAULT);
+        if (updated != value) {
+          if (updated == DEFAULT) {
+            Services.prefs.clearUserPref(HOMEPAGE_PREF);
+          } else {
+            value = updated;
+            Services.prefs.setCharPref(HOMEPAGE_PREF, value);
+          }
+        }
+      }
+    }
+
     // Update the migration version.
     Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
   },
 
   _checkForDefaultBrowser() {
     // Perform default browser checking.
     if (!ShellService) {
       return;
--- a/browser/components/preferences/in-content/tests/browser_connection_bug1445991.js
+++ b/browser/components/preferences/in-content/tests/browser_connection_bug1445991.js
@@ -12,17 +12,16 @@ add_task(async function testAutoconfigRe
       ["network.proxy.type", 2],
       ["network.proxy.autoconfig_url", "file:///nonexistent.pac"],
     ],
   });
 
   await openPreferencesViaOpenPreferencesAPI("general", { leaveOpen: true });
   const connectionURL = "chrome://browser/content/preferences/connection.xul";
   const promiseDialogLoaded = promiseLoadSubDialog(connectionURL);
-  // eslint-disable-next-line mozilla/no-cpows-in-tests
   gBrowser.contentDocument.getElementById("connectionSettings").click();
   const dialog = await promiseDialogLoaded;
 
   ok(!dialog.document.getElementById("autoReload").disabled,
      "Reload button is enabled when proxy type is autoconfig");
 
   dialog.close();
   gBrowser.removeCurrentTab();
--- a/browser/components/preferences/in-content/tests/browser_extension_controlled.js
+++ b/browser/components/preferences/in-content/tests/browser_extension_controlled.js
@@ -83,17 +83,16 @@ async function openNotificationsPermissi
   });
 
   sitePermissionsDialog = await dialogOpened;
   await sitePermissionsDialog.document.mozSubdialogReady;
 }
 
 add_task(async function testExtensionControlledHomepage() {
   await openPreferencesViaOpenPreferencesAPI("paneHome", {leaveOpen: true});
-  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   is(gBrowser.currentURI.spec, "about:preferences#home",
      "#home should be in the URI for about:preferences");
   let homepagePref = () => Services.prefs.getCharPref("browser.startup.homepage");
   let originalHomepagePref = homepagePref();
   let extensionHomepage = "https://developer.mozilla.org/";
   let controlledContent = doc.getElementById("browserHomePageExtensionContent");
 
@@ -153,17 +152,16 @@ add_task(async function testExtensionCon
   await promise;
   // Do the uninstall now that the enable code has been run.
   await addon.uninstall();
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 add_task(async function testPrefLockedHomepage() {
   await openPreferencesViaOpenPreferencesAPI("paneHome", {leaveOpen: true});
-  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   is(gBrowser.currentURI.spec, "about:preferences#home",
      "#home should be in the URI for about:preferences");
 
   let homePagePref = "browser.startup.homepage";
   let buttonPrefs = [
     "pref.browser.homepage.disable_button.current_page",
     "pref.browser.homepage.disable_button.bookmark_page",
@@ -300,17 +298,16 @@ add_task(async function testPrefLockedHo
   is(controlledContent.hidden, true,
      "The extension controlled message is hidden when unlocked with no extension");
 
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 add_task(async function testExtensionControlledNewTab() {
   await openPreferencesViaOpenPreferencesAPI("paneHome", {leaveOpen: true});
-  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   is(gBrowser.currentURI.spec, "about:preferences#home",
      "#home should be in the URI for about:preferences");
 
   let controlledContent = doc.getElementById("browserNewTabExtensionContent");
 
   // The new tab is set to the default and message is hidden.
   ok(!aboutNewTabService.newTabURL.startsWith("moz-extension:"), "new tab is not set");
@@ -528,17 +525,16 @@ add_task(async function testExtensionCon
   await originalExtension.unload();
   await updatedExtension.unload();
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 add_task(async function testExtensionControlledHomepageUninstalledAddon() {
   async function checkHomepageEnabled() {
     await openPreferencesViaOpenPreferencesAPI("paneHome", {leaveOpen: true});
-    // eslint-disable-next-line mozilla/no-cpows-in-tests
     let doc = gBrowser.contentDocument;
     is(gBrowser.currentURI.spec, "about:preferences#home",
       "#home should be in the URI for about:preferences");
     let controlledContent = doc.getElementById("browserHomePageExtensionContent");
 
     // The homepage is enabled.
     let homepageInput = doc.getElementById("homePageUrl");
     is(homepageInput.disabled, false, "The homepage input is enabled");
--- a/browser/components/preferences/in-content/tests/browser_homepages_filter_aboutpreferences.js
+++ b/browser/components/preferences/in-content/tests/browser_homepages_filter_aboutpreferences.js
@@ -1,15 +1,14 @@
 var {HomePage} = ChromeUtils.import("resource:///modules/HomePage.jsm");
 
 add_task(async function testSetHomepageUseCurrent() {
   is(gBrowser.currentURI.spec, "about:blank", "Test starts with about:blank open");
   await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:home");
   await openPreferencesViaOpenPreferencesAPI("paneHome", {leaveOpen: true});
-  // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
   is(gBrowser.currentURI.spec, "about:preferences#home",
      "#home should be in the URI for about:preferences");
   let oldHomepage = HomePage.get();
 
   let useCurrent = doc.getElementById("useCurrentBtn");
   useCurrent.click();
 
--- a/browser/components/urlbar/UrlbarInput.jsm
+++ b/browser/components/urlbar/UrlbarInput.jsm
@@ -86,16 +86,18 @@ class UrlbarInput {
     });
     this.controller.setInput(this);
     this.view = new UrlbarView(this);
     this.valueIsTyped = false;
     this.userInitiatedFocus = false;
     this.isPrivate = PrivateBrowsingUtils.isWindowPrivate(this.window);
     this.lastQueryContextPromise = Promise.resolve();
     this._actionOverrideKeyCount = 0;
+    this._autofillPlaceholder = "";
+    this._lastSearchString = "";
     this._resultForCurrentValue = null;
     this._suppressStartQuery = false;
     this._untrimmedValue = "";
 
     // Forward textbox methods and properties.
     const METHODS = ["addEventListener", "removeEventListener",
       "setAttribute", "hasAttribute", "removeAttribute", "getAttribute",
       "select"];
@@ -463,22 +465,20 @@ class UrlbarInput {
       this.value = this._lastSearchString;
     } else {
       // For autofilled results, the value that should be canonized is not the
       // autofilled value but the value that the user typed.
       canonizedUrl = this._maybeCanonizeURL(event, result.autofill ?
                        this._lastSearchString : this.textValue);
       if (canonizedUrl) {
         this.value = canonizedUrl;
+      } else if (result.autofill) {
+        this._autofillValue(result.autofill);
       } else {
         this.value = this._getValueFromResult(result);
-        if (result.autofill) {
-          this.selectionStart = result.autofill.selectionStart;
-          this.selectionEnd = result.autofill.selectionEnd;
-        }
       }
     }
     this._resultForCurrentValue = result;
 
     // Also update userTypedValue. See bug 287996.
     this.window.gBrowser.userTypedValue = this.value;
 
     // The value setter clobbers the actiontype attribute, so update this after that.
@@ -492,47 +492,63 @@ class UrlbarInput {
           break;
       }
     }
 
     return !!canonizedUrl;
   }
 
   /**
-   * Starts a query based on the user input.
+   * Starts a query based on the current input value.
    *
+   * @param {boolean} [options.allowAutofill]
+   *   Whether or not to allow providers to include autofill results.
    * @param {number} [options.lastKey]
    *   The last key the user entered (as a key code).
+   * @param {string} [options.searchString]
+   *   The search string.  If not given, the current input value is used.
+   *   Otherwise, the current input value must start with this value.  The
+   *   intended use for this parameter is related to the autofill placeholder.
+   *   When the placeholder is autofilled before the new search starts, the
+   *   current input value will be the entire autofilled placeholder, not the
+   *   value the user typed, which is the value we should search with.
+   * @param {boolean} [resetSearchState]
+   *   If this is the first search of a user interaction with the input, set
+   *   this to true (the default) so that search-related state from the previous
+   *   interaction doesn't interfere with the new interaction.  Otherwise set it
+   *   to false so that state is maintained during a single interaction.  The
+   *   intended use for this parameter is that it should be set to false when
+   *   this method is called due to input events.
    */
   startQuery({
+    allowAutofill = true,
     lastKey = null,
+    searchString = null,
+    resetSearchState = true,
   } = {}) {
     if (this._suppressStartQuery) {
       return;
     }
 
-    let searchString = this.textValue;
+    if (resetSearchState) {
+      this._resetSearchState();
+    }
 
-    // We should autofill only when all of the following are true:
-    // * The pref is enabled.
-    // * The end of the selection is at the end of the input.
-    // * The user hasn't deleted text at the end of the input since the last
-    //   query.  Do a simple prefix comparison to guess whether that happened.
-    let enableAutofill =
-      UrlbarPrefs.get("autoFill") &&
-      this.selectionEnd == searchString.length &&
-      (!this._lastSearchString ||
-       !this._lastSearchString.startsWith(searchString));
+    if (!searchString) {
+      searchString = this.textValue;
+    } else if (!this.textValue.startsWith(searchString)) {
+      throw new Error("The current value doesn't start with the search string");
+    }
     this._lastSearchString = searchString;
 
     // TODO (Bug 1522902): This promise is necessary for tests, because some
     // tests are not listening for completion when starting a query through
     // other methods than startQuery (input events for example).
     this.lastQueryContextPromise = this.controller.startQuery(new UrlbarQueryContext({
-      enableAutofill,
+      allowAutofill,
       isPrivate: this.isPrivate,
       lastKey,
       maxResults: UrlbarPrefs.get("maxRichResults"),
       muxer: "UnifiedComplete",
       providers: ["UnifiedComplete"],
       searchString,
     }));
   }
@@ -555,19 +571,20 @@ class UrlbarInput {
     }
 
     // Avoid selecting the text if this method is called twice in a row.
     this.selectionStart = -1;
 
     // Note: proper IME Composition handling depends on the fact this generates
     // an input event, rather than directly invoking the controller; everything
     // goes through _on_input, that will properly skip the search until the
-    // composition is committed.
-    // If this assumption changes, we'll have to first check we are not
-    // composing, before starting a search.
+    // composition is committed. _on_input also skips the search when it's the
+    // same as the previous search, but we want to allow consecutive searches
+    // with the same string. So clear _lastSearchString first.
+    this._lastSearchString = "";
     let event = this.document.createEvent("UIEvents");
     event.initUIEvent("input", true, false, this.window, 0);
     this.inputField.dispatchEvent(event);
   }
 
   /**
    * Focus without the focus styles.
    * This is used by Activity Stream and about:privatebrowsing for search hand-off.
@@ -600,46 +617,46 @@ class UrlbarInput {
     return this.inputField.value;
   }
 
   get value() {
     return this._untrimmedValue;
   }
 
   set value(val) {
+    return this._setValue(val, true);
+  }
+
+  // Private methods below.
+
+  _setValue(val, allowTrim) {
     this._untrimmedValue = val;
 
     let originalUrl = ReaderMode.getOriginalUrlObjectForDisplay(val);
     if (originalUrl) {
       val = originalUrl.displaySpec;
     }
 
-    val = this.trimValue(val);
+    val = allowTrim ? this.trimValue(val) : val;
 
     this.valueIsTyped = false;
     this._resultForCurrentValue = null;
     this.inputField.value = val;
     this.formatValue();
     this.removeAttribute("actiontype");
 
     // Dispatch ValueChange event for accessibility.
     let event = this.document.createEvent("Events");
     event.initEvent("ValueChange", true, true);
     this.inputField.dispatchEvent(event);
 
     return val;
   }
 
-  // Private methods below.
-
   _getValueFromResult(result) {
-    if (result.autofill) {
-      return result.autofill.value;
-    }
-
     switch (result.type) {
       case UrlbarUtils.RESULT_TYPE.KEYWORD:
         return result.payload.input;
       case UrlbarUtils.RESULT_TYPE.SEARCH:
         return (result.payload.keyword ? result.payload.keyword + " " : "") +
                (result.payload.suggestion || result.payload.query);
       case UrlbarUtils.RESULT_TYPE.OMNIBOX:
         return result.payload.content;
@@ -650,16 +667,66 @@ class UrlbarInput {
       if (uri) {
         return this.window.losslessDecodeURI(uri);
       }
     } catch (ex) {}
 
     return "";
   }
 
+  /**
+   * Resets some state so that searches from the user's previous interaction
+   * with the input don't interfere with searches from a new interaction.
+   */
+  _resetSearchState() {
+    this._lastSearchString = this.textValue;
+    this._autofillPlaceholder = "";
+  }
+
+  /**
+   * Autofills the autofill placeholder string if appropriate, and determines
+   * whether autofill should be allowed for the new search started by an input
+   * event.
+   *
+   * @param {string} value
+   *   The new search string.
+   * @param {boolean} deletedAutofilledSubstring
+   *   Whether the user deleted the previously autofilled substring.
+   * @returns {boolean}
+   *   Whether autofill should be allowed in the new search.
+   */
+  _maybeAutofillOnInput(value, deletedAutofilledSubstring) {
+    // Determine whether autofill should be allowed for the new search triggered
+    // by the input event.
+    let lastSearchStartsWithNewSearch =
+      value.length < this._lastSearchString.length &&
+      this._lastSearchString.startsWith(value);
+    let allowAutofill =
+      !lastSearchStartsWithNewSearch &&
+      !deletedAutofilledSubstring &&
+      this.selectionEnd == value.length;
+
+    // The autofill placeholder is a string that we autofill now, before we
+    // start waiting on the new search's first result, in order to prevent a
+    // flicker in the input caused by the previous autofilled substring
+    // disappearing and reappearing when the new first result arrives.  Of
+    // course we can only autofill the placeholder if it starts with the new
+    // search string.
+    if (!allowAutofill ||
+        this._autofillPlaceholder.length <= value.length ||
+        !this._autofillPlaceholder.startsWith(value)) {
+      this._autofillPlaceholder = "";
+    }
+    if (this._autofillPlaceholder) {
+      this._autofillValueOnInput(this._autofillPlaceholder);
+    }
+
+    return allowAutofill;
+  }
+
   _updateTextOverflow() {
     if (!this._overflowing) {
       this.removeAttribute("textoverflow");
       return;
     }
 
     this.window.promiseDocumentFlushed(() => {
       // Check overflow again to ensure it didn't change in the meantime.
@@ -856,16 +923,59 @@ class UrlbarInput {
     }
     value = "http://www." + value;
 
     this.value = value;
     return value;
   }
 
   /**
+   * Autofills a value into the input in response to the user's typing.  The
+   * autofill value must start with the value that's already in the input.  If
+   * it doesn't, this method doesn't do anything.  If it does, this method will
+   * autofill and set the selection automatically.
+   *
+   * @param {string} value
+   *   The value to autofill.
+   */
+  _autofillValueOnInput(value) {
+    // Don't ever autofill on input if the caret/selection isn't at the end, or
+    // if the value doesn't start with what the user typed.
+    if (this.selectionEnd != this.value.length ||
+        !value.startsWith(this._lastSearchString)) {
+      return;
+    }
+    this._autofillValue({
+      value,
+      selectionStart: this._lastSearchString.length,
+      selectionEnd: value.length,
+    });
+  }
+
+  /**
+   * Autofills a value into the input.  The value will be autofilled regardless
+   * of the input's current value.
+   *
+   * @param {string} options.value
+   *   The value to autofill.
+   * @param {integer} options.selectionStart
+   *   The new selectionStart.
+   * @param {integer} options.selectionEnd
+   *   The new selectionEnd.
+   */
+  _autofillValue({ value, selectionStart, selectionEnd } = {}) {
+    // The autofilled value may be a URL that includes a scheme at the
+    // beginning.  Do not allow it to be trimmed.
+    this._setValue(value, false);
+    this.selectionStart = selectionStart;
+    this.selectionEnd = selectionEnd;
+    this._autofillPlaceholder = value;
+  }
+
+  /**
    * Loads the url in the appropriate place.
    *
    * @param {string} url
    *   The URL to open.
    * @param {string} openUILinkWhere
    *   Where we expect the result to be opened.
    * @param {object} params
    *   The parameters related to how and where the result will be opened.
@@ -1029,16 +1139,17 @@ class UrlbarInput {
     // the browser toolbox.
     if (!UrlbarPrefs.get("ui.popup.disable_autohide")) {
       this.view.close(UrlbarUtils.CANCEL_REASON.BLUR);
     }
     // We may have hidden popup notifications, show them again if necessary.
     if (this.getAttribute("pageproxystate") != "valid") {
       this.window.UpdatePopupNotificationsVisibility();
     }
+    this._resetSearchState();
   }
 
   _on_focus(event) {
     this._updateUrlTooltip();
     this.formatValue();
 
     // Hide popup notifications, to reduce visual noise.
     if (this.getAttribute("pageproxystate") != "valid") {
@@ -1094,28 +1205,50 @@ class UrlbarInput {
     // 3. a compositionend event
     // 4. an input event
 
     // We should do nothing during composition.
     if (this._compositionState == UrlbarUtils.COMPOSITION.COMPOSING) {
       return;
     }
 
-    if (this._compositionState == UrlbarUtils.COMPOSITION.COMMIT) {
+    let handlingCompositionCommit =
+      this._compositionState == UrlbarUtils.COMPOSITION.COMMIT;
+    if (handlingCompositionCommit) {
       this._compositionState = UrlbarUtils.COMPOSITION.NONE;
     }
 
-    // Note: if in the future we should re-implement the legacy optimization
-    // where we didn't search again when the string is the same, skip it if we
-    // are committing a composition; since the search was canceled on
-    // composition start, we should restart it.
+    let sameSearchStrings = value == this._lastSearchString;
+
+    // TODO (bug 1524550): Properly detect autofill removal, rather than
+    // guessing based on string prefixes.
+    let deletedAutofilledSubstring =
+      sameSearchStrings &&
+      value.length < this._autofillPlaceholder.length &&
+      this._autofillPlaceholder.startsWith(value);
+
+    // Don't search again when the new search would produce the same results.
+    // If we're handling a composition commit, we must continue the search
+    // because we canceled the previous search on composition start.
+    if (sameSearchStrings &&
+        !deletedAutofilledSubstring &&
+        !handlingCompositionCommit &&
+        value.length > 0) {
+      return;
+    }
+
+    let allowAutofill =
+      this._maybeAutofillOnInput(value, deletedAutofilledSubstring);
 
     // XXX Fill in lastKey, and add anything else we need.
     this.startQuery({
+      searchString: value,
+      allowAutofill,
       lastKey: null,
+      resetSearchState: false,
     });
   }
 
   _on_select(event) {
     if (!Services.clipboard.supportsSelectionClipboard()) {
       return;
     }
 
@@ -1189,16 +1322,17 @@ class UrlbarInput {
     }
   }
 
   _on_scrollend(event) {
     this._updateTextOverflow();
   }
 
   _on_TabSelect(event) {
+    this._resetSearchState();
     this.controller.viewContextChanged();
   }
 
   _on_keydown(event) {
     this._toggleActionOverride(event);
     this.eventBufferer.maybeDeferEvent(event, () => {
       this.controller.handleKeyNavigation(event);
     });
--- a/browser/components/urlbar/UrlbarProviderUnifiedComplete.jsm
+++ b/browser/components/urlbar/UrlbarProviderUnifiedComplete.jsm
@@ -109,17 +109,17 @@ class ProviderUnifiedComplete extends Ur
       params.push("private-window");
       if (!PrivateBrowsingUtils.permanentPrivateBrowsing) {
         params.push("disable-private-actions");
       }
     }
     if (queryContext.userContextId) {
       params.push(`user-context-id:${queryContext.userContextId}}`);
     }
-    if (!queryContext.enableAutofill) {
+    if (!queryContext.allowAutofill) {
       params.push("prohibit-autofill");
     }
 
     let urls = new Set();
     await new Promise(resolve => {
       let listener = {
         onSearchResult(_, result) {
           let {done, matches} = convertResultToMatches(queryContext, result, urls);
--- a/browser/components/urlbar/UrlbarUtils.jsm
+++ b/browser/components/urlbar/UrlbarUtils.jsm
@@ -384,22 +384,22 @@ class UrlbarQueryContext {
    *   in the case of the user opening the popup via the mouse.
    * @param {number} options.lastKey
    *   The last key the user entered (as a key code). Could be null if the search
    *   was started via the mouse.
    * @param {boolean} options.isPrivate
    *   Set to true if this query was started from a private browsing window.
    * @param {number} options.maxResults
    *   The maximum number of results that will be displayed for this query.
-   * @param {boolean} options.enableAutofill
-   *   Whether or not to include autofill results.
+   * @param {boolean} options.allowAutofill
+   *   Whether or not to allow providers to include autofill results.
    */
   constructor(options = {}) {
     this._checkRequiredOptions(options, [
-      "enableAutofill",
+      "allowAutofill",
       "isPrivate",
       "lastKey",
       "maxResults",
       "searchString",
     ]);
 
     if (isNaN(parseInt(options.maxResults))) {
       throw new Error(`Invalid maxResults property provided to UrlbarQueryContext`);
--- a/browser/components/urlbar/tests/UrlbarTestUtils.jsm
+++ b/browser/components/urlbar/tests/UrlbarTestUtils.jsm
@@ -41,25 +41,34 @@ var UrlbarTestUtils = {
    * @param {function} waitForFocus The Simpletest function
    * @param {boolean} fireInputEvent whether an input event should be used when
    *        starting the query (necessary to set userTypedValued)
    */
   async promiseAutocompleteResultPopup(win, inputText, waitForFocus, fireInputEvent = false) {
     let urlbar = getUrlbarAbstraction(win);
     let restoreAnimationsFn = urlbar.disableAnimations();
     await new Promise(resolve => waitForFocus(resolve, win));
+    let lastSearchString = urlbar.lastSearchString;
     urlbar.focus();
     urlbar.value = inputText;
     if (fireInputEvent) {
       // This is necessary to get the urlbar to set gBrowser.userTypedValue.
       urlbar.fireInputEvent();
     }
-    // In the quantum bar it's enough to fire the input event to start a query,
-    // invoking startSearch would do it twice.
-    if (!urlbar.quantumbar || !fireInputEvent) {
+    // With awesomebar, we must call startSearch to start the search.  With
+    // quantumbar, we can either fire an input event or call start search, so be
+    // careful not to do both since that would start two searches.  However,
+    // there's one wrinkle with quantumbar: If the new search and old search are
+    // the same, the input event will *not* start a new search, by design.  Many
+    // existing tests do consecutive searches with the same string and expect
+    // new searches to start.  To keep those tests running, call startSearch
+    // directly in those cases.
+    if (!urlbar.quantumbar ||
+        !fireInputEvent ||
+        inputText == lastSearchString) {
       urlbar.startSearch(inputText);
     }
     return this.promiseSearchComplete(win, restoreAnimationsFn);
   },
 
   /**
    * Waits for a result to be added at a certain index. Since we implement lazy
    * results replacement, even if we have a result at an index, it may be
@@ -283,16 +292,21 @@ class UrlbarAbstraction {
 
   set value(val) {
     this.urlbar.value = val;
   }
   get value() {
     return this.urlbar.value;
   }
 
+  get lastSearchString() {
+    return this.quantumbar ? this.urlbar._lastSearchString :
+                             this.urlbar.controller.searchString;
+  }
+
   get panel() {
     return this.quantumbar ? this.urlbar.panel : this.urlbar.popup;
   }
 
   get oneOffSearchButtons() {
     return this.quantumbar ? this.urlbar.view.oneOffSearchButtons :
            this.urlbar.popup.oneOffSearchButtons;
   }
--- a/browser/components/urlbar/tests/browser/browser.ini
+++ b/browser/components/urlbar/tests/browser/browser.ini
@@ -19,23 +19,20 @@ skip-if = true # Bug 1524539 - need to f
 [browser_autocomplete_cursor.js]
 [browser_autocomplete_edit_completed.js]
 [browser_autocomplete_enter_race.js]
 [browser_autocomplete_no_title.js]
 [browser_autocomplete_readline_navigation.js]
 skip-if = os != "mac" # Mac only feature
 [browser_autocomplete_tag_star_visibility.js]
 [browser_autoFill_backspaced.js]
-skip-if = true # Bug 1531348 - Failing with QuantumBar.
 [browser_autoFill_canonize.js]
-skip-if = true # Bug 1531348 - Failing with QuantumBar.
+[browser_autoFill_caretNotAtEnd.js]
 [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 =
@@ -103,17 +100,16 @@ support-files =
 [browser_urlbarCutting.js]
 [browser_urlbarDecode.js]
 [browser_urlbarDelete.js]
 [browser_urlbarEnter.js]
 [browser_urlbarEnterAfterMouseOver.js]
 skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s
 [browser_urlbarFocusedCmdK.js]
 [browser_urlbarHashChangeProxyState.js]
-[browser_UrlbarInput_autofill.js]
 [browser_UrlbarInput_formatValue.js]
 [browser_UrlbarInput_hiddenFocus.js]
 [browser_UrlbarInput_overflow.js]
 [browser_UrlbarInput_tooltip.js]
 [browser_UrlbarInput_trimURLs.js]
 subsuite = clipboard
 [browser_UrlbarInput_unit.js]
 support-files = empty.xul
--- a/browser/components/urlbar/tests/browser/browser_UrlbarInput_unit.js
+++ b/browser/components/urlbar/tests/browser/browser_UrlbarInput_unit.js
@@ -160,37 +160,37 @@ add_task(async function test_autofill_di
     // search for "autofill" -- autofill should be enabled
     input.inputField.value = "autofill";
     input.handleEvent({
       target: input.inputField,
       type: "input",
     });
     checkStartQueryCall(fakeController.startQuery, {
       searchString: "autofill",
-      enableAutofill: true,
+      allowAutofill: true,
     });
 
     // search for "auto" -- autofill should be disabled since the previous
     // search string starts with the new search string
     input.inputField.value = "auto";
     input.handleEvent({
       target: input.inputField,
       type: "input",
     });
     checkStartQueryCall(fakeController.startQuery, {
       searchString: "auto",
-      enableAutofill: false,
+      allowAutofill: false,
     }, 1);
 
     // search for "autofill" again -- autofill should be enabled
     input.inputField.value = "autofill";
     input.handleEvent({
       target: input.inputField,
       type: "input",
     });
     checkStartQueryCall(fakeController.startQuery, {
       searchString: "autofill",
-      enableAutofill: true,
+      allowAutofill: true,
     }, 2);
 
     sandbox.resetHistory();
   });
 });
--- a/browser/components/urlbar/tests/browser/browser_autoFill_backspaced.js
+++ b/browser/components/urlbar/tests/browser/browser_autoFill_backspaced.js
@@ -11,16 +11,17 @@ async function test_autocomplete(data) {
   let {desc, typed, autofilled, modified, keys, type, onAutoFill} = data;
   info(desc);
 
   await promiseAutocompleteResultPopup(typed);
   Assert.equal(gURLBar.textValue, autofilled, "autofilled value is as expected");
   if (onAutoFill)
     onAutoFill();
 
+  info("Synthesizing keys");
   keys.forEach(key => EventUtils.synthesizeKey(key));
 
   Assert.equal(gURLBar.textValue, modified, "backspaced value is as expected");
 
   await promiseSearchComplete();
 
   Assert.greater(UrlbarTestUtils.getResultCount(window), 0,
     "Should get at least 1 result");
rename from browser/components/urlbar/tests/browser/browser_UrlbarInput_autofill.js
rename to browser/components/urlbar/tests/browser/browser_autoFill_caretNotAtEnd.js
--- a/browser/components/urlbar/tests/browser/browser_UrlbarInput_autofill.js
+++ b/browser/components/urlbar/tests/browser/browser_autoFill_caretNotAtEnd.js
@@ -1,54 +1,33 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-/**
- * Tests the autofill functionality of UrlbarInput.
- */
-
 "use strict";
 
-add_task(async function setValueFromResult() {
-  gURLBar.setValueFromResult({
-    autofill: {
-      value: "foobar",
-      selectionStart: "foo".length,
-      selectionEnd: "foobar".length,
-    },
-    type: UrlbarUtils.RESULT_TYPE.URL,
-  });
-  Assert.equal(gURLBar.value, "foobar",
-    "The input value should be correct");
-  Assert.equal(gURLBar.selectionStart, "foo".length,
-    "The start of the selection should be correct");
-  Assert.equal(gURLBar.selectionEnd, "foobar".length,
-    "The end of the selection should be correct");
-});
-
 add_task(async function noAutofillWhenCaretNotAtEnd() {
   gURLBar.focus();
 
-  // Autofill is disabled when the new search starts with the previous search,
-  // so to make sure that doesn't mess up this test, trigger a search now.
-  EventUtils.sendString("blah");
-
   // Add a visit that can be autofilled.
   await PlacesUtils.history.clear();
   await PlacesTestUtils.addVisits([{
     uri: "http://example.com/",
   }]);
 
-  // Fill the input with xample.com.
-  gURLBar.inputField.value = "xample.com";
+  // Fill the input with xample.
+  gURLBar.inputField.value = "xample";
 
   // Move the caret to the beginning and type e.
   gURLBar.selectionStart = 0;
   gURLBar.selectionEnd = 0;
   EventUtils.sendString("e");
 
-  // Get the first result.
+  // Check the first result and input.
   let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
   Assert.ok(!result.autofill, "The first result should not be autofill");
 
+  Assert.equal(gURLBar.value, "example");
+  Assert.equal(gURLBar.selectionStart, 1);
+  Assert.equal(gURLBar.selectionEnd, 1);
+
   await UrlbarTestUtils.promisePopupClose(window);
   await PlacesUtils.history.clear();
 });
--- a/browser/components/urlbar/tests/browser/browser_autoFill_trimURLs.js
+++ b/browser/components/urlbar/tests/browser/browser_autoFill_trimURLs.js
@@ -33,17 +33,17 @@ add_task(async function setup() {
 async function promiseSearch(searchtext) {
   gURLBar.focus();
   gURLBar.inputField.value = searchtext.substr(0, searchtext.length - 1);
   EventUtils.sendString(searchtext.substr(-1, 1));
   await promiseSearchComplete();
 }
 
 async function promiseTestResult(test) {
-  info("Searching for '${test.search}'");
+  info(`Searching for '${test.search}'`);
 
   await promiseSearch(test.search);
 
   Assert.equal(gURLBar.inputField.value, test.autofilledValue,
     `Autofilled value is as expected for search '${test.search}'`);
 
   let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
 
@@ -56,49 +56,55 @@ async function promiseTestResult(test) {
   } else {
     Assert.equal(result.displayed.action, test.resultListActionText,
       `Autocomplete action text should be as expected for search '${test.search}'`);
   }
 
   Assert.equal(result.type, test.resultListType,
     `Autocomplete result should have searchengine for the type for search '${test.search}'`);
 
-  if (UrlbarPrefs.get("quantumbar")) {
-    Assert.equal(result.url, test.expectedUrl, "Should have the correct URL");
+  Assert.equal(!!result.searchParams, !!test.searchParams,
+    "Should have search params if expected");
+  if (test.searchParams) {
+    let definedParams = {};
+    for (let [k, v] of Object.entries(result.searchParams)) {
+      if (v !== undefined) {
+        definedParams[k] = v;
+      }
+    }
+    Assert.deepEqual(definedParams, test.searchParams,
+      "Shoud have the correct search params");
   } else {
-    let actualValue = gURLBar.mController.getFinalCompleteValueAt(0);
-    let actualAction = PlacesUtils.parseActionUrl(actualValue);
-    let expectedAction = PlacesUtils.parseActionUrl(test.finalCompleteValue);
-    Assert.equal(!!actualAction, !!expectedAction,
-      "Should have an action if expected");
-    if (actualAction) {
-      Assert.deepEqual(actualAction, expectedAction,
-        "Should have the correct action details");
-    } else {
-      Assert.equal(actualValue, test.finalCompleteValue,
-        "Should have the correct action details");
-    }
+    Assert.equal(result.url, test.finalCompleteValue,
+      "Should have the correct URL/finalCompleteValue");
   }
 }
 
-const tests = [{
+const tests = [
+  {
     search: "http://",
     autofilledValue: "http://",
     resultListDisplayTitle: "http://",
     resultListActionText: "Search with Google",
     resultListType: UrlbarUtils.RESULT_TYPE.SEARCH,
-    finalCompleteValue: 'moz-action:searchengine,{"engineName":"Google","input":"http%3A%2F%2F","searchQuery":"http%3A%2F%2F"}',
+    searchParams: {
+      engine: "Google",
+      query: "http://",
+    },
   },
   {
     search: "https://",
     autofilledValue: "https://",
     resultListDisplayTitle: "https://",
     resultListActionText: "Search with Google",
     resultListType: UrlbarUtils.RESULT_TYPE.SEARCH,
-    finalCompleteValue: 'moz-action:searchengine,{"engineName":"Google","input":"https%3A%2F%2F","searchQuery":"https%3A%2F%2F"}',
+    searchParams: {
+      engine: "Google",
+      query: "https://",
+    },
   },
   {
     search: "au",
     autofilledValue: "autofilltrimurl.com/",
     resultListDisplayTitle: "www.autofilltrimurl.com",
     resultListActionText: "Visit",
     resultListType: UrlbarUtils.RESULT_TYPE.URL,
     finalCompleteValue: "http://www.autofilltrimurl.com/",
--- a/browser/components/urlbar/tests/browser/browser_urlbarTokenAlias.js
+++ b/browser/components/urlbar/tests/browser/browser_urlbarTokenAlias.js
@@ -315,62 +315,59 @@ async function doSimpleTest(revertBetwee
   // When autofill is enabled, searching for "@tes" will autofill to "@test",
   // which gets in the way of this test task, so temporarily disable it.
   Services.prefs.setBoolPref("browser.urlbar.autoFill", false);
   registerCleanupFunction(() => {
     Services.prefs.clearUserPref("browser.urlbar.autoFill");
   });
 
   // "@tes" -- not an alias, no highlight
-  gURLBar.search(ALIAS.substr(0, ALIAS.length - 1));
-  await promiseSearchComplete();
+  await promiseAutocompleteResultPopup(ALIAS.substr(0, ALIAS.length - 1),
+                                       window, true);
   await waitForAutocompleteResultAt(0);
   await assertAlias(false);
 
   if (revertBetweenSteps) {
     gURLBar.handleRevert();
     gURLBar.blur();
   }
 
   // "@test" -- alias, highlight
-  gURLBar.search(ALIAS);
-  await promiseSearchComplete();
+  await promiseAutocompleteResultPopup(ALIAS, window, true);
   await waitForAutocompleteResultAt(0);
   await assertAlias(true);
 
   if (revertBetweenSteps) {
     gURLBar.handleRevert();
     gURLBar.blur();
   }
 
   // "@test foo" -- alias, highlight
-  gURLBar.search(ALIAS + " foo");
-  await promiseSearchComplete();
+  await promiseAutocompleteResultPopup(ALIAS + " foo", window, true);
   await waitForAutocompleteResultAt(0);
   await assertAlias(true);
 
   if (revertBetweenSteps) {
     gURLBar.handleRevert();
     gURLBar.blur();
   }
 
   // "@test" -- alias, highlight
-  gURLBar.search(ALIAS);
-  await promiseSearchComplete();
+  await promiseAutocompleteResultPopup(ALIAS, window, true);
   await waitForAutocompleteResultAt(0);
   await assertAlias(true);
 
   if (revertBetweenSteps) {
     gURLBar.handleRevert();
     gURLBar.blur();
   }
 
   // "@tes" -- not an alias, no highlight
-  gURLBar.search(ALIAS.substr(0, ALIAS.length - 1));
-  await promiseSearchComplete();
+  await promiseAutocompleteResultPopup(ALIAS.substr(0, ALIAS.length - 1),
+                                       window, true);
   await waitForAutocompleteResultAt(0);
   await assertAlias(false);
 
   await UrlbarTestUtils.promisePopupClose(window,
     () => EventUtils.synthesizeKey("KEY_Escape"));
 
   Services.prefs.clearUserPref("browser.urlbar.autoFill");
 }
--- a/browser/components/urlbar/tests/unit/head.js
+++ b/browser/components/urlbar/tests/unit/head.js
@@ -30,17 +30,17 @@ const {sinon} = ChromeUtils.import("reso
 /**
  * @param {string} searchString The search string to insert into the context.
  * @param {object} properties Overrides for the default values.
  * @returns {UrlbarQueryContext} Creates a dummy query context with pre-filled
  *          required options.
  */
 function createContext(searchString = "foo", properties = {}) {
   let context = new UrlbarQueryContext({
-    enableAutofill: UrlbarPrefs.get("autoFill"),
+    allowAutofill: UrlbarPrefs.get("autoFill"),
     isPrivate: true,
     lastKey: searchString ? searchString[searchString.length - 1] : "",
     maxResults: UrlbarPrefs.get("maxRichResults"),
     searchString,
   });
   return Object.assign(context, properties);
 }
 
--- a/browser/components/urlbar/tests/unit/test_UrlbarController_unit.js
+++ b/browser/components/urlbar/tests/unit/test_UrlbarController_unit.js
@@ -144,29 +144,29 @@ add_task(function test_handle_query_star
   Assert.equal(generalListener.onQueryStarted.callCount, 1,
     "Should have called onQueryStarted for the listener");
   Assert.deepEqual(generalListener.onQueryStarted.args[0], [context],
     "Should have called onQueryStarted with the context");
 
   sandbox.resetHistory();
 });
 
-add_task(function test_handle_query_starts_search_sets_enableAutofill() {
+add_task(function test_handle_query_starts_search_sets_allowAutofill() {
   let originalValue = Services.prefs.getBoolPref("browser.urlbar.autoFill");
   Services.prefs.setBoolPref("browser.urlbar.autoFill", !originalValue);
 
   controller.startQuery(createContext());
 
   Assert.equal(fPM.startQuery.callCount, 1,
     "Should have called startQuery once");
   Assert.equal(fPM.startQuery.args[0].length, 2,
     "Should have called startQuery with two arguments");
 
   assertContextMatches(fPM.startQuery.args[0][0], {
-    enableAutofill: !originalValue,
+    allowAutofill: !originalValue,
   });
   Assert.equal(fPM.startQuery.args[0][1], controller,
     "Should have passed the controller as the second argument");
 
   sandbox.resetHistory();
 
   Services.prefs.clearUserPref("browser.urlbar.autoFill");
 });
--- a/browser/components/urlbar/tests/unit/test_UrlbarQueryContext.js
+++ b/browser/components/urlbar/tests/unit/test_UrlbarQueryContext.js
@@ -1,60 +1,60 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 add_task(function test_constructor() {
   Assert.throws(() => new UrlbarQueryContext(),
-    /Missing or empty enableAutofill provided to UrlbarQueryContext/,
+    /Missing or empty allowAutofill provided to UrlbarQueryContext/,
     "Should throw with no arguments");
 
   Assert.throws(() => new UrlbarQueryContext({
-    enableAutofill: true,
+    allowAutofill: true,
     isPrivate: false,
     maxResults: 1,
     searchString: "foo",
   }), /Missing or empty lastKey provided to UrlbarQueryContext/,
     "Should throw with a missing lastKey parameter");
 
   Assert.throws(() => new UrlbarQueryContext({
-    enableAutofill: true,
+    allowAutofill: true,
     isPrivate: false,
     lastKey: "b",
     searchString: "foo",
   }), /Missing or empty maxResults provided to UrlbarQueryContext/,
     "Should throw with a missing maxResults parameter");
 
   Assert.throws(() => new UrlbarQueryContext({
-    enableAutofill: true,
+    allowAutofill: true,
     lastKey: "b",
     maxResults: 1,
     searchString: "foo",
   }), /Missing or empty isPrivate provided to UrlbarQueryContext/,
     "Should throw with a missing isPrivate parameter");
 
   Assert.throws(() => new UrlbarQueryContext({
     isPrivate: false,
     lastKey: "b",
     maxResults: 1,
     searchString: "foo",
-  }), /Missing or empty enableAutofill provided to UrlbarQueryContext/,
-    "Should throw with a missing enableAutofill parameter");
+  }), /Missing or empty allowAutofill provided to UrlbarQueryContext/,
+    "Should throw with a missing allowAutofill parameter");
 
   let qc = new UrlbarQueryContext({
-    enableAutofill: false,
+    allowAutofill: false,
     isPrivate: true,
     lastKey: "b",
     maxResults: 1,
     searchString: "foo",
   });
 
-  Assert.strictEqual(qc.enableAutofill, false,
-    "Should have saved the correct value for enableAutofill");
+  Assert.strictEqual(qc.allowAutofill, false,
+    "Should have saved the correct value for allowAutofill");
   Assert.strictEqual(qc.isPrivate, true,
     "Should have saved the correct value for isPrivate");
   Assert.equal(qc.lastKey, "b",
     "Should have saved the correct value for lastKey");
   Assert.equal(qc.maxResults, 1,
     "Should have saved the correct value for maxResults");
   Assert.equal(qc.searchString, "foo",
     "Should have saved the correct value for searchString");
--- a/browser/docs/AddressBar.rst
+++ b/browser/docs/AddressBar.rst
@@ -50,17 +50,20 @@ The UrlbarQueryContext
 
 The *UrlbarQueryContext* object describes a single instance of a search.
 It is augmented as it progresses through the system, with various information:
 
 .. highlight:: JavaScript
 .. code::
 
   UrlbarQueryContext {
-    enableAutofill; // {boolean} Whether or not to include autofill results.
+    allowAutofill; // {boolean} If true, providers are allowed to return
+                   // autofill results.  Even if true, it's up to providers
+                   // whether to include autofill results, but when false, no
+                   // provider should include them.
     isPrivate; // {boolean} Whether the search started in a private context.
     lastKey; // {string} The last key pressed by the user. This can affect the
              // behavior, for example by not autofilling again when the user
              // hit backspace.
     maxResults; // {integer} The maximum number of results requested. It is
                 // possible to request more results than the shown ones, and
                 // do additional filtering at the View level.
     searchString; // {string} The user typed string.
--- a/browser/themes/shared/customizableui/customizeMode.inc.css
+++ b/browser/themes/shared/customizableui/customizeMode.inc.css
@@ -587,17 +587,17 @@ toolbarpaletteitem[place=toolbar] > tool
 }
 
 #customization-palette[whimsypong] > toolbarpaletteitem > toolbarspring {
   margin: 0 -7px;
 }
 
 %ifdef XP_UNIX
 %ifndef XP_MACOSX
-#customization-palette[whimsypong] > toolbarpaletteitem > toolbarspring {
+#customization-palette[whimsypong] > toolbarpaletteitem[id^="wrapper-customizableui-special-spring"] {
   font-size: 12px;
 }
 %endif
 %endif
 
 #wp-lives,
 #wp-ball {
   /* Don't need HiDPI versions since the size used will be scaled down to 20x20. */
--- a/build/clang-plugin/CanRunScriptChecker.cpp
+++ b/build/clang-plugin/CanRunScriptChecker.cpp
@@ -106,19 +106,27 @@ void CanRunScriptChecker::registerMatche
                 )
               )
             )
           ),
           // and which is not a MOZ_KnownLive wrapped value.
           unless(
             anyOf(
               MozKnownLiveCall,
-              // MOZ_KnownLive applied to a RefPtr or nsCOMPtr just returns that
-              // same RefPtr/nsCOMPtr type which causes us to have a conversion
-              // operator applied after the MOZ_KnownLive.
+              // MOZ_KnownLive applied to a smartptr just returns that
+              // same smartptr type which causes us to have a conversion
+              // operator applied after the MOZ_KnownLive.  Allow that by
+              // allowing member calls on the result of MOZ_KnownLive, but only
+              // if the type is a known smartptr type.  Otherwise we would think
+              // that things of the form "MOZ_KnownLive(someptr)->foo()" are
+              // live!
+              //
+              // This relies on member calls on smartptr types that return a
+              // refcounted pointer only returning the pointer the smartptr is
+              // keeping alive.
               cxxMemberCallExpr(on(allOf(hasType(isSmartPtrToRefCounted()),
                                          MozKnownLiveCall)))
             )
           ),
           expr().bind("invalidArg")));
 
   auto OptionalInvalidExplicitArg = anyOf(
       // We want to find any argument which is invalid.
@@ -326,11 +334,11 @@ void CanRunScriptChecker::check(const Ma
   if (ParentFunction) {
     assert(!hasCustomAttribute<moz_can_run_script>(ParentFunction) &&
            "Matcher missed something");
 
     diag(CallRange.getBegin(), ErrorNonCanRunScriptParent, DiagnosticIDs::Error)
         << CallRange;
 
     diag(ParentFunction->getCanonicalDecl()->getLocation(),
-	 NoteNonCanRunScriptParent, DiagnosticIDs::Note);
+         NoteNonCanRunScriptParent, DiagnosticIDs::Note);
   }
 }
--- a/build/clang-plugin/tests/TestCanRunScript.cpp
+++ b/build/clang-plugin/tests/TestCanRunScript.cpp
@@ -277,8 +277,34 @@ struct AllowKnownLiveMemberArgs {
   RefPtr<RefCountedBase> mRefCounted;
   MOZ_CAN_RUN_SCRIPT void foo() {
     MOZ_KnownLive(mRefCounted)->method_test();
   }
   MOZ_CAN_RUN_SCRIPT void bar() {
     test2(MOZ_KnownLive(mRefCounted));
   }
 };
+
+struct WeakPtrReturner : public RefCountedBase {
+  RefCountedBase* getWeakPtr() { return new RefCountedBase(); }
+};
+
+struct DisallowMemberCallsOnRandomKnownLive {
+  RefPtr<WeakPtrReturner> mWeakPtrReturner1;
+  WeakPtrReturner* mWeakPtrReturner2;
+
+  MOZ_CAN_RUN_SCRIPT void test_refptr_method() {
+    MOZ_KnownLive(mWeakPtrReturner1)->getWeakPtr()->method_test(); // expected-error {{arguments must all be strong refs or parent parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument)}}
+  }
+
+  MOZ_CAN_RUN_SCRIPT void test_refptr_function() {
+    test2(MOZ_KnownLive(mWeakPtrReturner1)->getWeakPtr()); // expected-error {{arguments must all be strong refs or parent parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument)}}
+  }
+
+  MOZ_CAN_RUN_SCRIPT void test_raw_method() {
+    MOZ_KnownLive(mWeakPtrReturner2)->getWeakPtr()->method_test(); // expected-error {{arguments must all be strong refs or parent parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument)}}
+  }
+
+  MOZ_CAN_RUN_SCRIPT void test_raw_function() {
+    test2(MOZ_KnownLive(mWeakPtrReturner2)->getWeakPtr()); // expected-error {{arguments must all be strong refs or parent parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument)}}
+  }
+};
+
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -1193,17 +1193,18 @@ def check_have_64_bit(have_64_bit, compi
         configure_error('The target compiler does not agree with configure '
                         'about the target bitness.')
 
 
 @depends(c_compiler, target)
 def default_debug_flags(compiler_info, target):
     # Debug info is ON by default.
     if compiler_info.type == 'clang-cl':
-        return '-Z7'
+        # -fno-limit-debug-info works around https://llvm.org/pr38944
+        return '-Z7 -fno-limit-debug-info'
     elif target.kernel == 'WINNT' and compiler_info.type == 'clang':
         return '-g -gcodeview'
     return '-g'
 
 
 option(env='MOZ_DEBUG_FLAGS',
        nargs=1,
        help='Debug compiler flags')
--- a/devtools/client/aboutdebugging-new/aboutdebugging.js
+++ b/devtools/client/aboutdebugging-new/aboutdebugging.js
@@ -104,17 +104,16 @@ const AboutDebugging = {
 
   onUSBRuntimesUpdated() {
     this.actions.updateUSBRuntimes(getUSBRuntimes());
   },
 
   async destroy() {
     const width = this.getRoundedViewportWidth();
     this.actions.recordTelemetryEvent("close_adbg", { width });
-    l10n.destroy();
 
     const state = this.store.getState();
     const currentRuntimeId = state.runtimes.selectedRuntimeId;
     if (currentRuntimeId) {
       await this.actions.unwatchRuntime(currentRuntimeId);
     }
 
     // Remove all client listeners.
--- a/devtools/client/aboutdebugging-new/src/components/App.js
+++ b/devtools/client/aboutdebugging-new/src/components/App.js
@@ -12,78 +12,66 @@ const PropTypes = require("devtools/clie
 const FluentReact = require("devtools/client/shared/vendor/fluent-react");
 const Localized = createFactory(FluentReact.Localized);
 
 const Route = createFactory(require("devtools/client/shared/vendor/react-router-dom").Route);
 const Switch = createFactory(require("devtools/client/shared/vendor/react-router-dom").Switch);
 const Redirect = createFactory(require("devtools/client/shared/vendor/react-router-dom").Redirect);
 
 const Types = require("../types/index");
-const { RUNTIMES } = require("../constants");
+const { PAGE_TYPES, RUNTIMES } = require("../constants");
 
 const ConnectPage = createFactory(require("./connect/ConnectPage"));
 const RuntimePage = createFactory(require("./RuntimePage"));
 const Sidebar = createFactory(require("./sidebar/Sidebar"));
 
 class App extends PureComponent {
   static get propTypes() {
     return {
       adbAddonStatus: Types.adbAddonStatus,
       // The "dispatch" helper is forwarded to the App component via connect.
       // From that point, components are responsible for forwarding the dispatch
       // property to all components who need to dispatch actions.
       dispatch: PropTypes.func.isRequired,
       // getString prop is injected by the withLocalization wrapper
       getString: PropTypes.func.isRequired,
       isScanningUsb: PropTypes.bool.isRequired,
-      networkEnabled: PropTypes.bool.isRequired,
       networkLocations: PropTypes.arrayOf(Types.location).isRequired,
       networkRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
       selectedPage: Types.page,
       selectedRuntimeId: PropTypes.string,
       usbRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
-      wifiEnabled: PropTypes.bool.isRequired,
     };
   }
 
   componentDidUpdate() {
     this.updateTitle();
   }
 
   updateTitle() {
     const { getString, selectedPage, selectedRuntimeId } = this.props;
 
-    const runtimeTitle = selectedRuntimeId ?
-                          getString(
-                            "about-debugging-page-title-with-runtime",
-                            { selectedPage, selectedRuntimeId }
-                          )
-                          : getString(
-                            "about-debugging-page-title",
-                            { selectedPage }
-                          );
+    const pageTitle = selectedPage === PAGE_TYPES.RUNTIME ?
+      getString("about-debugging-page-title-runtime-page", { selectedRuntimeId }) :
+      getString("about-debugging-page-title-setup-page");
 
-    document.title = runtimeTitle;
+    document.title = pageTitle;
   }
 
   renderConnect() {
     const {
       adbAddonStatus,
       dispatch,
-      networkEnabled,
       networkLocations,
-      wifiEnabled,
     } = this.props;
 
     return ConnectPage({
       adbAddonStatus,
       dispatch,
-      networkEnabled,
       networkLocations,
-      wifiEnabled,
     });
   }
 
   // The `match` object here is passed automatically by the Route object.
   // We are using it to read the route path.
   // See react-router docs:
   // https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/match.md
   renderRuntime({ match }) {
@@ -177,23 +165,21 @@ class App extends PureComponent {
     );
   }
 }
 
 const mapStateToProps = state => {
   return {
     adbAddonStatus: state.ui.adbAddonStatus,
     isScanningUsb: state.ui.isScanningUsb,
-    networkEnabled: state.ui.networkEnabled,
     networkLocations: state.ui.networkLocations,
     networkRuntimes: state.runtimes.networkRuntimes,
     selectedPage: state.ui.selectedPage,
     selectedRuntimeId: state.runtimes.selectedRuntimeId,
     usbRuntimes: state.runtimes.usbRuntimes,
-    wifiEnabled: state.ui.wifiEnabled,
   };
 };
 
 const mapDispatchToProps = dispatch => ({
   dispatch,
 });
 
 module.exports = FluentReact
--- a/devtools/client/aboutdebugging-new/src/components/RuntimeInfo.js
+++ b/devtools/client/aboutdebugging-new/src/components/RuntimeInfo.js
@@ -57,22 +57,27 @@ class RuntimeInfo extends PureComponent 
       deviceName ?
         dom.label(
           {
             className: "main-heading-subtitle runtime-info__subtitle",
           },
           deviceName
         ) : null,
       runtimeId !== RUNTIMES.THIS_FIREFOX ?
-        dom.button(
+        Localized(
           {
-            className: "default-button runtime-info__action qa-runtime-info__action",
-            onClick() {
-              dispatch(Actions.disconnectRuntime(runtimeId, true));
+            id: "about-debugging-runtime-disconnect-button",
+          },
+          dom.button(
+            {
+              className: "default-button runtime-info__action qa-runtime-info__action",
+              onClick() {
+                dispatch(Actions.disconnectRuntime(runtimeId, true));
+              },
             },
-          },
-          "Disconnect"
+            "Disconnect"
+          )
         ) : null,
     );
   }
 }
 
 module.exports = RuntimeInfo;
--- a/devtools/client/aboutdebugging-new/src/components/connect/ConnectPage.css
+++ b/devtools/client/aboutdebugging-new/src/components/connect/ConnectPage.css
@@ -1,16 +1,12 @@
 /* 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/. */
 
-.connect-page__disabled-section {
-  color: var(--grey-40);
-}
-
 .connect-page__breather {
   margin-block-start: calc(var(--base-unit) * 6);
 }
 
 /*
  *   +--------+----------------------+
  *   | USB    |            |<button> |
  *   +--------+            |         |
--- a/devtools/client/aboutdebugging-new/src/components/connect/ConnectPage.js
+++ b/devtools/client/aboutdebugging-new/src/components/connect/ConnectPage.js
@@ -20,32 +20,28 @@ const Actions = require("../../actions/i
 loader.lazyRequireGetter(this, "ADB_ADDON_STATES", "devtools/shared/adb/adb-addon", true);
 
 const Link = createFactory(require("devtools/client/shared/vendor/react-router-dom").Link);
 const ConnectSection = createFactory(require("./ConnectSection"));
 const ConnectSteps = createFactory(require("./ConnectSteps"));
 const NetworkLocationsForm = createFactory(require("./NetworkLocationsForm"));
 const NetworkLocationsList = createFactory(require("./NetworkLocationsList"));
 
-const { PREFERENCES, PAGE_TYPES, RUNTIMES } = require("../../constants");
+const { PAGE_TYPES, RUNTIMES } = require("../../constants");
 const Types = require("../../types/index");
 
 const USB_ICON_SRC = "chrome://devtools/skin/images/aboutdebugging-usb-icon.svg";
 const GLOBE_ICON_SRC = "chrome://devtools/skin/images/aboutdebugging-globe-icon.svg";
 
 class ConnectPage extends PureComponent {
   static get propTypes() {
     return {
       adbAddonStatus: Types.adbAddonStatus,
       dispatch: PropTypes.func.isRequired,
-      // Provided by wrapping the component with FluentReact.withLocalization.
-      getString: PropTypes.func.isRequired,
-      networkEnabled: PropTypes.bool.isRequired,
       networkLocations: PropTypes.arrayOf(Types.location).isRequired,
-      wifiEnabled: PropTypes.bool.isRequired,
     };
   }
 
   // TODO: avoid the use of this method
   // https://bugzilla.mozilla.org/show_bug.cgi?id=1508688
   componentWillMount() {
     this.props.dispatch(Actions.selectPage(PAGE_TYPES.CONNECT));
   }
@@ -175,62 +171,44 @@ class ConnectPage extends PureComponent 
             "Enabling this will download and add the required Android USB debugging " +
               "components to Firefox."
           )
         ),
     );
   }
 
   renderNetwork() {
-    const { dispatch, networkEnabled, networkLocations } = this.props;
+    const { dispatch, networkLocations } = this.props;
 
     return Localized(
       {
-        id: "about-debugging-connect-network",
+        id: "about-debugging-setup-network",
         attrs: { title: true },
       },
-      ConnectSection(
-        {
-          className: "connect-page__breather",
-          icon: GLOBE_ICON_SRC,
-          title: "Network Location",
-          extraContent: networkEnabled
-            ? dom.div(
-              {},
-              NetworkLocationsList({ dispatch, networkLocations }),
-              NetworkLocationsForm({ dispatch }),
-            )
-            : null,
-        },
-        networkEnabled
-          ? null
-          : Localized(
-            {
-                id: "about-debugging-connect-network-disabled",
-                $pref: PREFERENCES.NETWORK_ENABLED,
-            },
-            dom.div(
-              {
-                className: "connect-page__disabled-section",
-              },
-              "about-debugging-connect-network-disabled"
-            )
-          ),
-      )
+      ConnectSection({
+        className: "connect-page__breather",
+        icon: GLOBE_ICON_SRC,
+        title: "Network Location",
+        extraContent: dom.div(
+          {},
+          NetworkLocationsList({ dispatch, networkLocations }),
+          NetworkLocationsForm({ dispatch }),
+        ),
+      })
     );
   }
 
   render() {
     return dom.article(
       {
         className: "page connect-page js-connect-page",
       },
       Localized(
         {
-          id: "about-debugging-connect-title",
+          id: "about-debugging-setup-title",
         },
         dom.h1(
           {
             className: "alt-heading",
           },
           "Setup"
         ),
       ),
@@ -238,22 +216,22 @@ class ConnectPage extends PureComponent 
         {
           id: "about-debugging-setup-intro",
         },
         dom.p(
           {},
           "Configure the connection method you wish to remotely debug your device with."
         )
       ),
-      Localized(
-        {
-          id: "about-debugging-setup-link-android-devices",
-        },
-        dom.p(
-          {},
+      dom.p(
+        {},
+        Localized(
+          {
+            id: "about-debugging-setup-link-android-devices",
+          },
           dom.a(
             {
               href: "https://support.mozilla.org/kb/will-firefox-work-my-mobile-device#w_android-devices",
               target: "_blank",
             },
             "View list of supported android devices"
           )
         ),
--- a/devtools/client/aboutdebugging-new/src/components/debugtarget/ExtensionDetail.js
+++ b/devtools/client/aboutdebugging-new/src/components/debugtarget/ExtensionDetail.js
@@ -127,17 +127,17 @@ class ExtensionDetail extends PureCompon
         href: manifestURL,
         target: "_blank",
       },
       manifestURL,
     );
 
     return Localized(
       {
-        id: "about-debugging-extension-manifest-link",
+        id: "about-debugging-extension-manifest-url",
         attrs: { label: true },
       },
       FieldPair(
         {
           label: "Manifest URL",
           value: link,
         }
       )
--- a/devtools/client/aboutdebugging-new/src/components/debugtarget/ServiceWorkerAction.js
+++ b/devtools/client/aboutdebugging-new/src/components/debugtarget/ServiceWorkerAction.js
@@ -43,25 +43,38 @@ class ServiceWorkerAction extends PureCo
 
     return InspectAction({
       disabled: this.props.runtimeDetails.isMultiE10s,
       dispatch: this.props.dispatch,
       target: this.props.target,
     });
   }
 
+  _getStatusLocalizationId(status) {
+    switch (status) {
+      case SERVICE_WORKER_STATUSES.REGISTERING.toLowerCase():
+        return "about-debugging-worker-status-registering";
+      case SERVICE_WORKER_STATUSES.RUNNING.toLowerCase():
+        return "about-debugging-worker-status-running";
+      case SERVICE_WORKER_STATUSES.STOPPED.toLowerCase():
+        return "about-debugging-worker-status-stopped";
+      default:
+        // Assume status is stopped for unknown status value.
+        return "about-debugging-worker-status-stopped";
+    }
+  }
+
   _renderStatus() {
     const status = this.props.target.details.status.toLowerCase();
     const statusClassName = status === SERVICE_WORKER_STATUSES.RUNNING.toLowerCase()
                               ? "service-worker-action__status--running" : "";
 
     return Localized(
       {
-        id: "about-debugging-worker-status",
-        $status: status,
+        id: this._getStatusLocalizationId(status),
       },
       dom.span(
         {
           className:
             `service-worker-action__status js-worker-status ${ statusClassName }`,
         },
         status
       )
--- a/devtools/client/aboutdebugging-new/src/constants.js
+++ b/devtools/client/aboutdebugging-new/src/constants.js
@@ -90,24 +90,20 @@ const MESSAGE_LEVEL = {
 };
 
 const PAGE_TYPES = {
   RUNTIME: "runtime",
   CONNECT: "connect",
 };
 
 const PREFERENCES = {
-  // Temporary preference without any default value until network locations are enabled.
-  NETWORK_ENABLED: "devtools.aboutdebugging.network",
   // Preference that drives the display of the "Processes" debug target category.
   PROCESS_DEBUGGING_ENABLED: "devtools.aboutdebugging.process-debugging",
   // Preference that drives the display of system addons in about:debugging.
   SHOW_SYSTEM_ADDONS: "devtools.aboutdebugging.showSystemAddons",
-  // Temporary preference without any default value until wifi is enabled.
-  WIFI_ENABLED: "devtools.aboutdebugging.wifi",
 };
 
 const RUNTIME_PREFERENCE = {
   CHROME_DEBUG_ENABLED: "devtools.chrome.enabled",
   CONNECTION_PROMPT: "devtools.debugger.prompt-connection",
   PERMANENT_PRIVATE_BROWSING: "browser.privatebrowsing.autostart",
   REMOTE_DEBUG_ENABLED: "devtools.debugger.remote-enabled",
   SERVICE_WORKERS_ENABLED: "dom.serviceWorkers.enabled",
--- a/devtools/client/aboutdebugging-new/src/create-store.js
+++ b/devtools/client/aboutdebugging-new/src/create-store.js
@@ -44,17 +44,14 @@ function configureStore() {
                                      waitUntilService);
 
   return createStore(rootReducer, initialState, middleware);
 }
 
 function getUiState() {
   const collapsibilities = getDebugTargetCollapsibilities();
   const locations = getNetworkLocations();
-  const networkEnabled = Services.prefs.getBoolPref(PREFERENCES.NETWORK_ENABLED, false);
-  const wifiEnabled = Services.prefs.getBoolPref(PREFERENCES.WIFI_ENABLED, false);
   const showSystemAddons = Services.prefs.getBoolPref(PREFERENCES.SHOW_SYSTEM_ADDONS,
     false);
-  return new UiState(locations, collapsibilities, networkEnabled, wifiEnabled,
-    showSystemAddons);
+  return new UiState(locations, collapsibilities, showSystemAddons);
 }
 
 exports.configureStore = configureStore;
--- a/devtools/client/aboutdebugging-new/src/modules/l10n.js
+++ b/devtools/client/aboutdebugging-new/src/modules/l10n.js
@@ -2,36 +2,25 @@
  * 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 Services = require("Services");
 
 const FluentReact = require("devtools/client/shared/vendor/fluent-react");
-const { L10nRegistry, FileSource } =
-  require("resource://gre/modules/L10nRegistry.jsm");
+const { L10nRegistry } = require("resource://gre/modules/L10nRegistry.jsm");
 
 class L10n {
   async init() {
-    // XXX Until the strings for the updated about:debugging stabilize, we
-    // locate them outside the regular directory for locale resources so that
-    // they don't get picked up by localization tools.
-    if (!L10nRegistry.sources.has("aboutdebugging")) {
-      const temporarySource = new FileSource(
-        "aboutdebugging",
-        ["en-US"],
-        "chrome://devtools/content/aboutdebugging-new/tmp-locale/{locale}/"
-      );
-      L10nRegistry.registerSource(temporarySource);
-    }
-
     const locales = Services.locale.appLocalesAsBCP47;
-    const generator =
-      L10nRegistry.generateBundles(locales, ["aboutdebugging.ftl"]);
+    const generator = L10nRegistry.generateBundles(locales, [
+      "branding/brand.ftl",
+      "devtools/aboutdebugging.ftl",
+    ]);
 
     this._bundles = [];
     for await (const bundle of generator) {
       this._bundles.push(bundle);
     }
     this._reactLocalization = new FluentReact.ReactLocalization(this._bundles);
   }
 
@@ -46,16 +35,12 @@ class L10n {
    * Returns the localized string for the provided id, formatted using args.
    */
   getString(id, args, fallback) {
     // Forward arguments via .apply() so that the original method can:
     // - perform asserts based on the number of arguments
     // - add new arguments
     return this._reactLocalization.getString.apply(this._reactLocalization, arguments);
   }
-
-  destroy() {
-    L10nRegistry.removeSource("aboutdebugging");
-  }
 }
 
 // Export a singleton that will be shared by all aboutdebugging modules.
 exports.l10n = new L10n();
--- a/devtools/client/aboutdebugging-new/src/reducers/ui-state.js
+++ b/devtools/client/aboutdebugging-new/src/reducers/ui-state.js
@@ -13,29 +13,26 @@ const {
   SHOW_PROFILER_DIALOG,
   TEMPORARY_EXTENSION_INSTALL_FAILURE,
   TEMPORARY_EXTENSION_INSTALL_SUCCESS,
   USB_RUNTIMES_SCAN_START,
   USB_RUNTIMES_SCAN_SUCCESS,
 } = require("../constants");
 
 function UiState(locations = [], debugTargetCollapsibilities = {},
-                 networkEnabled = false, wifiEnabled = false,
                  showSystemAddons = false) {
   return {
     adbAddonStatus: null,
     debugTargetCollapsibilities,
     isScanningUsb: false,
-    networkEnabled,
     networkLocations: locations,
     selectedPage: null,
     showProfilerDialog: false,
     showSystemAddons,
     temporaryInstallError: null,
-    wifiEnabled,
   };
 }
 
 function uiReducer(state = UiState(), action) {
   switch (action.type) {
     case ADB_ADDON_STATUS_UPDATED: {
       const { adbAddonStatus } = action;
       return Object.assign({}, state, { adbAddonStatus });
--- a/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_navigate.js
+++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_navigate.js
@@ -21,17 +21,18 @@ add_task(async function() {
   const { document, tab, window } = await openAboutDebugging();
   const AboutDebugging = window.AboutDebugging;
   await selectThisFirefoxPage(document, AboutDebugging.store);
 
   const connectSidebarItem = findSidebarItemByText("Setup", document);
   const connectLink = connectSidebarItem.querySelector(".js-sidebar-link");
   ok(connectSidebarItem, "Found the Connect sidebar item");
 
-  const thisFirefoxSidebarItem = findSidebarItemByText("This Firefox", document);
+  const thisFirefoxString = getThisFirefoxString(window);
+  const thisFirefoxSidebarItem = findSidebarItemByText(thisFirefoxString, document);
   const thisFirefoxLink = thisFirefoxSidebarItem.querySelector(".js-sidebar-link");
   ok(thisFirefoxSidebarItem, "Found the ThisFirefox sidebar item");
   ok(isSidebarItemSelected(thisFirefoxSidebarItem),
     "ThisFirefox sidebar item is selected by default");
 
   info("Open a new background tab TAB1");
   const backgroundTab1 = await addTab(TAB_URL_1, { background: true });
 
--- a/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_select_page_with_serviceworker.js
+++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_select_page_with_serviceworker.js
@@ -39,17 +39,18 @@ add_task(async function() {
   };
   networkClient.listWorkers = () => workers;
   networkClient._eventEmitter.emit("workersUpdated");
 
   info("Wait until the service worker is displayed");
   await waitUntil(() => findDebugTargetByText(WORKER_NAME, document));
 
   info("Go to This Firefox again");
-  const thisFirefoxSidebarItem = findSidebarItemByText("This Firefox", document);
+  const thisFirefoxString = getThisFirefoxString(window);
+  const thisFirefoxSidebarItem = findSidebarItemByText(thisFirefoxString, document);
   const thisFirefoxLink = thisFirefoxSidebarItem.querySelector(".js-sidebar-link");
   info("Click on the ThisFirefox item in the sidebar");
   const requestsSuccess = waitForRequestsSuccess(window.AboutDebugging.store);
   thisFirefoxLink.click();
 
   info("Wait for all target requests to complete");
   await requestsSuccess;
 
--- a/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_thisfirefox.js
+++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_thisfirefox.js
@@ -16,21 +16,23 @@ const EXPECTED_TARGET_PANES = [
   "Shared Workers",
   "Other Workers",
 ];
 
 add_task(async function() {
   const { document, tab, window } = await openAboutDebugging();
   await selectThisFirefoxPage(document, window.AboutDebugging.store);
 
-  // Check that the selected sidebar item is "This Firefox"
+  // Check that the selected sidebar item is "This Firefox"/"This Nightly"/...
   const selectedSidebarItem = document.querySelector(".js-sidebar-item-selected");
   ok(selectedSidebarItem, "An item is selected in the sidebar");
-  is(selectedSidebarItem.textContent, "This Firefox",
-    "The selected sidebar item is This Firefox");
+
+  const thisFirefoxString = getThisFirefoxString(window);
+  is(selectedSidebarItem.textContent, thisFirefoxString,
+    "The selected sidebar item is " + thisFirefoxString);
 
   const paneTitlesEls = document.querySelectorAll(".js-debug-target-pane-title");
   is(paneTitlesEls.length, EXPECTED_TARGET_PANES.length,
     "This Firefox has the expecte number of debug target categories");
 
   const paneTitles = [...paneTitlesEls].map(el => el.textContent);
 
   for (let i = 0; i < EXPECTED_TARGET_PANES.length; i++) {
--- a/devtools/client/aboutdebugging-new/test/browser/head.js
+++ b/devtools/client/aboutdebugging-new/test/browser/head.js
@@ -36,17 +36,16 @@ registerCleanupFunction(async function()
   await remoteClientManager.removeAllClients();
 });
 
 /**
  * Enable the new about:debugging panel.
  */
 async function enableNewAboutDebugging() {
   await pushPref("devtools.aboutdebugging.new-enabled", true);
-  await pushPref("devtools.aboutdebugging.network", true);
 }
 
 async function openAboutDebugging({ enableWorkerUpdates } = {}) {
   if (!enableWorkerUpdates) {
     silenceWorkerUpdates();
   }
 
   await enableNewAboutDebugging();
@@ -108,18 +107,18 @@ async function closeAboutDevtoolsToolbox
 
 async function reloadAboutDebugging(tab) {
   info("reload about:debugging");
 
   await refreshTab(tab);
   const browser = tab.linkedBrowser;
   const document = browser.contentDocument;
   const window = browser.contentWindow;
-  info("wait for the initial about:debugging requests to be successful");
-  await waitForRequestsSuccess(window.AboutDebugging.store);
+  info("wait for the initial about:debugging requests to settle");
+  await waitForRequestsToSettle(window.AboutDebugging.store);
 
   return document;
 }
 
 // Wait for all about:debugging target request actions to succeed.
 // They will typically be triggered after watching a new runtime or loading
 // about:debugging.
 function waitForRequestsSuccess(store) {
@@ -284,8 +283,18 @@ async function openProfilerDialog(client
 
   info("Click on the Profile Runtime button");
   const profileButton = doc.querySelector(".js-profile-runtime-button");
   profileButton.click();
 
   info("Wait for the loadPerformanceProfiler callback to be executed on client-wrapper");
   return onProfilerLoaded;
 }
+
+/**
+ * The "This Firefox" string depends on the brandShortName, which will be different
+ * depending on the channel where tests are running.
+ */
+function getThisFirefoxString(aboutDebuggingWindow) {
+  const loader = aboutDebuggingWindow.getBrowserLoaderForWindow();
+  const { l10n } = loader.require("devtools/client/aboutdebugging-new/src/modules/l10n");
+  return l10n.getString("about-debugging-this-firefox-runtime-name");
+}
deleted file mode 100644
--- a/devtools/client/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.notftl
+++ /dev/null
@@ -1,313 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-### These strings are used inside the about:debugging panel which is available
-### by setting the preference `devtools.aboutdebugging.new-enabled` to true.
-
-# Display name of the runtime "This Firefox". Reused as the sidebar name for This Firefox
-# (about-debugging-sidebar-this-firefox.name). Not displayed elsewhere in the application
-# at the moment.
-# This should the same string as the part outside of the parentheses in toolbox.properties
-# toolbox.debugTargetInfo.runtimeLabel.thisFirefox. See 1520525.
-about-debugging-this-firefox-runtime-name = This Firefox
-
-# Sidebar heading for selecting the currently running instance of Firefox
-about-debugging-sidebar-this-firefox =
-  .name = { about-debugging-this-firefox-runtime-name }
-
-# Sidebar heading for connecting to some remote source
-about-debugging-sidebar-setup =
-  .name = Setup
-
-# Text displayed in the about:debugging sidebar when USB devices discovery is enabled.
-about-debugging-sidebar-usb-enabled = USB enabled
-
-# Text displayed in the about:debugging sidebar when USB devices discovery is disabled
-# (for instance because the mandatory ADB extension is not installed).
-about-debugging-sidebar-usb-disabled = USB disabled
-
-# Connection status (connected) for runtime items in the sidebar
-aboutdebugging-sidebar-runtime-connection-status-connected = Connected
-# Connection status (disconnected) for runtime items in the sidebar
-aboutdebugging-sidebar-runtime-connection-status-disconnected = Disconnected
-
-# Text displayed in the about:debugging sidebar when no device was found.
-about-debugging-sidebar-no-devices = No devices discovered
-
-# Text displayed in buttons found in sidebar items representing remote runtimes.
-# Clicking on the button will attempt to connect to the runtime.
-about-debugging-sidebar-item-connect-button = Connect
-
-# Temporary text displayed in sidebar items representing remote runtimes after
-# successfully connecting to them. Temporary UI, do not localize.
-about-debugging-sidebar-item-connected-label = Connected
-
-# Text displayed in sidebar items for remote devices where a compatible runtime (eg
-# Firefox) has not been detected yet. Typically, Android phones connected via USB with
-# USB debugging enabled, but where Firefox is not started.
-about-debugging-sidebar-runtime-item-waiting-for-runtime = Waiting for runtime…
-
-# Title for runtime sidebar items that are related to a specific device (USB, WiFi).
-about-debugging-sidebar-runtime-item-name =
-  .title = { $displayName } ({ $deviceName })
-# Title for runtime sidebar items where we cannot get device information (network
-# locations).
-about-debugging-sidebar-runtime-item-name-no-device =
-  .title = { $displayName }
-
-# Temporary text displayed in a sidebar button to refresh USB devices. Temporary
-# UI, do not localize.
-about-debugging-refresh-usb-devices-button = Refresh devices
-
-# Title of the Setup page.
-about-debugging-connect-title = Setup
-
-# Explanatory text in the Setup page about what the 'This Firefox' page is for
-about-debugging-setup-this-firefox = Use <a>This Firefox</a> to debug tags, extensions and service workers on this version of Firefox.
-
-# USB section of the Setup page
-about-debugging-setup-usb-title = USB
-about-debugging-setup-usb-disabled = Enabling this will download and add the required Android USB debugging components to Firefox.
-about-debugging-setup-usb-enable-button = Enable USB Devices
-about-debugging-setup-usb-disable-button = Disable USB Devices
-about-debugging-setup-usb-updating-button = Updating…
-
-# USB section of the Setup page (USB status)
-about-debugging-setup-usb-status-enabled = Enabled
-about-debugging-setup-usb-status-disabled = Disabled
-about-debugging-setup-usb-status-updating = Updating…
-
-# USB section step by step guide
-about-debugging-setup-usb-step-enable-dev-menu = Enable Developer menu on your Android device. <a>Learn how</a>
-
-# USB section step by step guide
-about-debugging-setup-usb-step-enable-debug = Enable USB Debugging in the Android Developer Menu. <a>Learn how</a>
-
-# USB section step by step guide
-about-debugging-setup-usb-step-enable-debug-firefox = Enable USB Debugging in Firefox on the Android device. <a>Learn how</a>
-
-# USB section step by step guide
-about-debugging-setup-usb-step-plug-device = Connect the Android device to your computer.
-
-# Network section of the Connect page
-about-debugging-connect-network =
-  .title = Network Location
-
-# Temporary text displayed when network location support is turned off via preferences.
-# { $pref } is the name of the preference that enables network locations
-# Do not localize
-about-debugging-connect-network-disabled = Network location support currently under development. You can enable it with the preference “{ $pref }”.
-
-# Below are the titles for the various categories of debug targets that can be found
-# on "runtime" pages of about:debugging.
-# Title of the temporary extensions category (only available for "This Firefox" runtime).
-about-debugging-runtime-temporary-extensions =
-  .name = Temporary Extensions
-# Title of the extensions category.
-about-debugging-runtime-extensions =
-  .name = Extensions
-# Title of the tabs category.
-about-debugging-runtime-tabs =
-  .name = Tabs
-# Title of the service workers category.
-about-debugging-runtime-service-workers =
-  .name = Service Workers
-# Title of the shared workers category.
-about-debugging-runtime-shared-workers =
-  .name = Shared Workers
-# Title of the other workers category.
-about-debugging-runtime-other-workers =
-  .name = Other Workers
-
-# Label of the button opening the performance profiler panel in runtime pages for remote
-# runtimes.
-about-debugging-runtime-profile-button = Profile Runtime
-
-# This string is displayed in the runtime page if the current configuration of the
-# target runtime is incompatible with service workers. "Learn more" points to MDN.
-# https://developer.mozilla.org/en-US/docs/Tools/about%3Adebugging#Service_workers_not_compatible
-about-debugging-runtime-service-workers-not-compatible = Your browser configuration is not compatible with Service Workers. <a>Learn more</a>
-
-# This string is displayed in the runtime page if the remote runtime version is too old.
-# "Troubleshooting" link points to https://developer.mozilla.org/docs/Tools/WebIDE/Troubleshooting
-# { $runtimeVersion } is the version of the remote runtime (for instance "67.0a1")
-# { $minVersion } is the minimum version that is compatible with the current Firefox instance (same format)
-about-debugging-runtime-version-too-old = The connected runtime has an old version ({ $runtimeVersion }). The minimum supported version is ({ $minVersion }). This is an unsupported setup and may cause DevTools to fail. Please update the connected runtime. <a>Troubleshooting</a>
-
-# Dedicated message for a backward compatibility issue that occurs when connecting:
-# - from Fx 67 to 66 or to 65
-# - from Fx 68 to 66
-# Those are normally in range for DevTools compatibility policy, but specific non
-# backward compatible changes broke the debugger in those scenarios (Bug 1528219).
-# { $runtimeVersion } is the version of the remote runtime (for instance "67.0a1")
-about-debugging-runtime-version-too-old-67-debugger = The Debugger panel may not work with the connected runtime. Please use Firefox { $runtimeVersion } if you need to use the Debugger with this runtime.
-
-# This string is displayed in the runtime page if the remote runtime version is too recent.
-# "Troubleshooting" link points to https://developer.mozilla.org/en-US/docs/Tools/WebIDE/Troubleshooting
-# { $runtimeID } is the build ID of the remote runtime (for instance "20181231", format is yyyyMMdd)
-# { $localID } is the build ID of the current Firefox instance (same format)
-# { $runtimeVersion } is the version of the remote runtime (for instance "67.0a1")
-# { $localVersion } is the version of your current runtime (same format)
-about-debugging-runtime-version-too-recent = The connected runtime is more recent ({ $runtimeVersion }, buildID { $runtimeID }) than your desktop Firefox ({ $localVersion }, buildID { $localID }). This is an unsupported setup and may cause DevTools to fail. Please update Firefox. <a>Troubleshooting</a>
-
-# Displayed in the categories of "runtime" pages that don't have any debug target to
-# show. Debug targets depend on the category (extensions, tabs, workers...).
-about-debugging-debug-target-list-empty = Nothing yet.
-
-# Text of a button displayed next to debug targets of "runtime" pages. Clicking on this
-# button will open a DevTools toolbox that will allow inspecting the target.
-# A target can be an addon, a tab, a worker...
-about-debugging-debug-target-inspect-button = Inspect
-
-# Text of a button displayed in the "This Firefox" page, in the Temporary Extension
-# section. Clicking on the button will open a file picker to load a temporary extension
-about-debugging-tmp-extension-install-button = Load Temporary Add-on…
-
-# Text displayed when trying to install a temporary extension in the "This Firefox" page.
-about-debugging-tmp-extension-install-error = There was an error during the temporary add-on installation.
-
-# Text of a button displayed for a temporary extension loaded in the "This Firefox" page.
-# Clicking on the button will reload the extension.
-about-debugging-tmp-extension-reload-button = Reload
-
-# Text of a button displayed for a temporary extension loaded in the "This Firefox" page.
-# Clicking on the button will uninstall the extension and remove it from the page.
-about-debugging-tmp-extension-remove-button = Remove
-
-# Message displayed in the file picker that opens to select a temporary extension to load
-# (triggered by the button using "about-debugging-tmp-extension-install-button")
-# manifest.json .xpi and .zip should not be localized.
-# Note: this message is only displayed in Windows and Linux platforms.
-about-debugging-tmp-extension-install-message = Select manifest.json file or .xpi/.zip archive
-
-# This string is displayed as a message about the add-on having a temporaryID.
-about-debugging-tmp-extension-temporary-id = This WebExtension has a temporary ID. <a>Learn more</a>
-
-# Text of a link displayed for extensions in "runtime" pages.
-# Clicking on the link should open the manifest file in a new tab.
-about-debugging-extension-manifest-link = Manifest URL
-
-# Text displayed for extensions in "runtime" pages, before displaying the extension's uuid.
-# UUIDs look like b293e463-481e-5148-a487-5aaf7a130429
-about-debugging-extension-uuid =
-  .label = Internal UUID
-
-# Text displayed for extensions (temporary extensions only) in "runtime" pages, before
-# displaying the location of the temporary extension.
-about-debugging-extension-location =
-  .label = Location
-
-# Text displayed for extensions in "runtime" pages, before displaying the extension's ID.
-# For instance "geckoprofiler@mozilla.com" or "{ed26ddcb-5611-4512-a89a-51b8db81cfb2}".
-about-debugging-extension-id = Extension ID
-
-# Text of a button displayed after the network locations "Host" input.
-# Clicking on it will add the new network location to the list.
-about-debugging-network-locations-add-button = Add
-
-# Text to display when there are no locations to show.
-about-debugging-network-locations-empty-text = No network locations have been added yet.
-
-# Text of the label for the text input that allows users to add new network locations in
-# the Connect page. A host is a hostname and a port separated by a colon, as suggested by
-# the input's placeholder "localhost:6080".
-about-debugging-network-locations-host-input-label = Host
-
-# Text of a button displayed next to existing network locations in the Connect page.
-# Clicking on it removes the network location from the list.
-about-debugging-network-locations-remove-button = Remove
-
-# This string is displayed as a label of the button that pushes a test payload
-# to a service worker.
-# Notes, this relates to the "Push" API, which is normally not localized so it is
-# probably better to not localize it.
-about-debugging-worker-action-push = Push
-
-# This string is displayed as a label of the button that starts a service worker.
-about-debugging-worker-action-start = Start
-
-# This string is displayed as a label of the button that unregisters a service worker.
-about-debugging-worker-action-unregister = Unregister
-
-# Reused for the service worker fetch status labels.
-# "Fetch" is an event type and should not be localized.
--worker-fetch-label = Fetch
-
-# Displayed for service workers in runtime pages that listen to Fetch events.
-about-debugging-worker-fetch-listening =
-  .label = { -worker-fetch-label }
-  .value = Listening for fetch events
-
-# Displayed for service workers in runtime pages that do not listen to Fetch events.
-about-debugging-worker-fetch-not-listening =
-  .label = { -worker-fetch-label }
-  .value = Not listening for fetch events
-
-# Displayed for service workers in runtime pages, to indicate the status of a worker.
-# For workers for which no registration could be found yet, they are considered as
-# 'registering' (only active registrations are visible from about:debugging).
-about-debugging-worker-status =
-  { $status ->
-    [running] Running
-   *[stopped] Stopped
-    [registering] Registering
-  }
-
-# Displayed for service workers in runtime pages, to label the scope of a worker
-about-debugging-worker-scope =
-  .label = Scope
-
-# Displayed for service workers in runtime pages, to label the push service endpoint (url)
-# of a worker
-about-debugging-worker-push-service =
-  .label = Push Service
-
-# Displayed for runtime info in runtime pages.
-# { $name } is brand name such as "Firefox Nightly"
-# { $version } is version such as "64.0a1"
-about-debugging-runtime-name = { $name } ({ $version })
-
-# Text of the connection prompt button displayed in Runtime pages, when the preference
-# "devtools.debugger.prompt-connection" is false on the target runtime.
-about-debugging-connection-prompt-enable-button = Enable connection prompt
-
-# Text of the connection prompt button displayed in Runtime pages, when the preference
-# "devtools.debugger.prompt-connection" is true on the target runtime.
-about-debugging-connection-prompt-disable-button = Disable connection prompt
-
-# Title of the application displayed in the tab
--application-title = Debugging
-
-# Page title of connect / runtime page
-# Part of "about-debugging-page-title" string defined below
-about-debugging-page-title-selected-page =
-  { $selectedPage ->
-     [connect] Setup
-     *[runtime] Runtime
-  }
-
-# Page title with the runtime displayed in the tab
-# { $selectedRuntimeId } is the id of the current runtime, such as "this-firefox", "localhost:6080", ...
-about-debugging-page-title-with-runtime = { -application-title } - { about-debugging-page-title-selected-page } / { $selectedRuntimeId }
-
-# Page title without the runtime displayed in the tab
-about-debugging-page-title = { -application-title } - { about-debugging-page-title-selected-page }
-
-# Title of a modal dialog displayed on remote runtime pages after clicking on the Profile Runtime button.
-about-debugging-profiler-dialog-title = Performance Profiler
-
-# Label of a checkbox displayed in the runtime page for "This Firefox".
-# This checkbox will toggle preferences that enable local addon debugging.
-# The "Learn more" link points to MDN.
-# https://developer.mozilla.org/docs/Tools/about:debugging#Enabling_add-on_debugging
-about-debugging-extension-debug-setting-label = Enable extension debugging <a>Learn more</a>
-
-# Clicking on the header of a debug target category will expand or collapse the debug
-# target items in the category. This text is used as ’title’ attribute of the header,
-# to describe this feature.
-about-debugging-collapse-expand-debug-targets = Collapse / expand
-
-about-debugging-main-process-name = Main Process
-about-debugging-main-process-description = Main Process for the target runtime
-
--- a/devtools/client/debugger/new/src/client/firefox/types.js
+++ b/devtools/client/debugger/new/src/client/firefox/types.js
@@ -154,17 +154,16 @@ export type FramesResponse = {
   from: ActorId
 };
 
 export type TabPayload = {
   actor: ActorId,
   animationsActor: ActorId,
   consoleActor: ActorId,
   cssPropertiesActor: ActorId,
-  cssUsageActor: ActorId,
   directorManagerActor: ActorId,
   emulationActor: ActorId,
   eventLoopLagActor: ActorId,
   framerateActor: ActorId,
   inspectorActor: ActorId,
   memoryActor: ActorId,
   monitorActor: ActorId,
   outerWindowID: number,
--- a/devtools/client/debugger/new/src/client/index.js
+++ b/devtools/client/debugger/new/src/client/index.js
@@ -2,38 +2,28 @@
  * 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/>. */
 
 // @flow
 
 import * as firefox from "./firefox";
 import * as chrome from "./chrome";
 
-import { prefs, asyncStore, verifyPrefSchema } from "../utils/prefs";
+import { asyncStore, verifyPrefSchema } from "../utils/prefs";
 import { setupHelper } from "../utils/dbg";
 
 import {
   bootstrapApp,
   bootstrapStore,
   bootstrapWorkers
 } from "../utils/bootstrap";
 import { initialBreakpointsState } from "../reducers/breakpoints";
 
 import type { Panel } from "./firefox/types";
 
-function loadFromPrefs(actions: Object) {
-  const { pauseOnExceptions, pauseOnCaughtExceptions } = prefs;
-  if (pauseOnExceptions || pauseOnCaughtExceptions) {
-    return actions.pauseOnExceptions(
-      pauseOnExceptions,
-      pauseOnCaughtExceptions
-    );
-  }
-}
-
 async function syncBreakpoints() {
   const breakpoints = await asyncStore.pendingBreakpoints;
   const breakpointValues = (Object.values(breakpoints): any);
   breakpointValues.forEach(({ disabled, options, generatedLocation }) => {
     if (!disabled) {
       firefox.clientCommands.setBreakpoint(generatedLocation, options);
     }
   });
@@ -89,17 +79,16 @@ export async function onConnect(
     sourceMaps,
     panel,
     initialState
   );
 
   const workers = bootstrapWorkers();
   await client.onConnect(connection, actions);
 
-  await loadFromPrefs(actions);
   syncBreakpoints();
   syncXHRBreakpoints();
   setupHelper({
     store,
     actions,
     selectors,
     workers: { ...workers, sourceMaps },
     connection,
--- a/devtools/client/debugger/new/test/mochitest/helpers.js
+++ b/devtools/client/debugger/new/test/mochitest/helpers.js
@@ -963,17 +963,17 @@ function waitForActive(dbg) {
  * @static
  */
 function invokeInTab(fnc, ...args) {
   info(`Invoking in tab: ${fnc}(${args.map(uneval).join(",")})`);
   return ContentTask.spawn(gBrowser.selectedBrowser, { fnc, args }, function*({
     fnc,
     args
   }) {
-    return content.wrappedJSObject[fnc](...args); // eslint-disable-line mozilla/no-cpows-in-tests, max-len
+    return content.wrappedJSObject[fnc](...args); // max-len
   });
 }
 
 const isLinux = Services.appinfo.OS === "Linux";
 const isMac = Services.appinfo.OS === "Darwin";
 const cmdOrCtrl = isLinux ? { ctrlKey: true } : { metaKey: true };
 const shiftOrAlt = isMac
   ? { accelKey: true, shiftKey: true }
--- a/devtools/client/jar.mn
+++ b/devtools/client/jar.mn
@@ -45,19 +45,16 @@ devtools.jar:
     content/shared/widgets/graphs-frame.xhtml (shared/widgets/graphs-frame.xhtml)
     content/shared/widgets/cubic-bezier.css (shared/widgets/cubic-bezier.css)
     content/shared/widgets/filter-widget.css (shared/widgets/filter-widget.css)
     content/shared/widgets/spectrum.css (shared/widgets/spectrum.css)
     content/aboutdebugging/aboutdebugging.xhtml (aboutdebugging/aboutdebugging.xhtml)
     content/aboutdebugging/aboutdebugging.css (aboutdebugging/aboutdebugging.css)
     content/aboutdebugging-new/index.html (aboutdebugging-new/index.html)
     content/aboutdebugging-new/aboutdebugging.css (aboutdebugging-new/aboutdebugging.css)
-    # The following line is temporary until the strings for the new
-    # about:debugging feature stabilize.
-    content/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.ftl (aboutdebugging-new/tmp-locale/en-US/aboutdebugging.notftl)
     content/responsive.html/index.xhtml (responsive.html/index.xhtml)
     content/dom/index.html (dom/index.html)
     content/dom/main.js (dom/main.js)
     content/accessibility/index.html (accessibility/index.html)
     content/accessibility/main.js (accessibility/main.js)
 %   skin devtools classic/1.0 %skin/
     skin/devtools-browser.css (themes/devtools-browser.css)
     skin/dark-theme.css (themes/dark-theme.css)
new file mode 100644
--- /dev/null
+++ b/devtools/client/locales/en-US/aboutdebugging.ftl
@@ -0,0 +1,332 @@
+# 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/.
+
+### These strings are used inside the about:debugging UI.
+
+# Page Title strings
+
+# Page title (ie tab title) for the Setup page
+about-debugging-page-title-setup-page = Debugging - Setup
+
+# Page title (ie tab title) for the Runtime page
+# { $selectedRuntimeId } is the id of the current runtime, such as "this-firefox", "localhost:6080", ...
+about-debugging-page-title-runtime-page = Debugging - Runtime / { $selectedRuntimeId }
+
+# Sidebar strings
+
+# Display name of the runtime for the currently running instance of Firefox. Used in the
+# Sidebar and in the Setup page.
+about-debugging-this-firefox-runtime-name = This { -brand-shorter-name }
+
+# Sidebar heading for selecting the currently running instance of Firefox
+about-debugging-sidebar-this-firefox =
+  .name = { about-debugging-this-firefox-runtime-name }
+
+# Sidebar heading for connecting to some remote source
+about-debugging-sidebar-setup =
+  .name = Setup
+
+# Text displayed in the about:debugging sidebar when USB devices discovery is enabled.
+about-debugging-sidebar-usb-enabled = USB enabled
+
+# Text displayed in the about:debugging sidebar when USB devices discovery is disabled
+# (for instance because the mandatory ADB extension is not installed).
+about-debugging-sidebar-usb-disabled = USB disabled
+
+# Connection status (connected) for runtime items in the sidebar
+aboutdebugging-sidebar-runtime-connection-status-connected = Connected
+# Connection status (disconnected) for runtime items in the sidebar
+aboutdebugging-sidebar-runtime-connection-status-disconnected = Disconnected
+
+# Text displayed in the about:debugging sidebar when no device was found.
+about-debugging-sidebar-no-devices = No devices discovered
+
+# Text displayed in buttons found in sidebar items representing remote runtimes.
+# Clicking on the button will attempt to connect to the runtime.
+about-debugging-sidebar-item-connect-button = Connect
+
+# Temporary text displayed in sidebar items representing remote runtimes after
+# successfully connecting to them. Temporary UI, do not localize.
+about-debugging-sidebar-item-connected-label = Connected
+
+# Text displayed in sidebar items for remote devices where a compatible runtime (eg
+# Firefox) has not been detected yet. Typically, Android phones connected via USB with
+# USB debugging enabled, but where Firefox is not started.
+about-debugging-sidebar-runtime-item-waiting-for-runtime = Waiting for runtime…
+
+# Title for runtime sidebar items that are related to a specific device (USB, WiFi).
+about-debugging-sidebar-runtime-item-name =
+  .title = { $displayName } ({ $deviceName })
+# Title for runtime sidebar items where we cannot get device information (network
+# locations).
+about-debugging-sidebar-runtime-item-name-no-device =
+  .title = { $displayName }
+
+# Text displayed in a sidebar button to refresh the list of USB devices. Clicking on it
+# will attempt to update the list of devices displayed in the sidebar.
+about-debugging-refresh-usb-devices-button = Refresh devices
+
+# Setup Page strings
+
+# Title of the Setup page.
+about-debugging-setup-title = Setup
+
+# Introduction text in the Setup page to explain how to configure remote debugging.
+about-debugging-setup-intro = Configure the connection method you wish to remotely debug your device with.
+
+# Link displayed in the Setup page that leads to MDN page with list of supported devices.
+# Temporarily leads to https://support.mozilla.org/en-US/kb/will-firefox-work-my-mobile-device#w_android-devices
+about-debugging-setup-link-android-devices = View list of supported Android devices
+
+# Explanatory text in the Setup page about what the 'This Firefox' page is for
+about-debugging-setup-this-firefox = Use <a>{ about-debugging-this-firefox-runtime-name }</a> to debug tabs, extensions and service workers on this version of { -brand-shorter-name }.
+
+# Title of the heading Connect section of the Setup page.
+about-debugging-setup-connect-heading = Connect a Device
+
+# USB section of the Setup page
+about-debugging-setup-usb-title = USB
+
+# Explanatory text displayed in the Setup page when USB debugging is disabled
+about-debugging-setup-usb-disabled = Enabling this will download and add the required Android USB debugging components to { -brand-shorter-name }.
+
+# Text of the button displayed in the USB section of the setup page when USB debugging is disabled.
+# Clicking on it will download components needed to debug USB Devices remotely.
+about-debugging-setup-usb-enable-button = Enable USB Devices
+
+# Text of the button displayed in the USB section of the setup page when USB debugging is enabled.
+about-debugging-setup-usb-disable-button = Disable USB Devices
+
+# Text of the button displayed in the USB section of the setup page while USB debugging
+# components are downloaded and installed.
+about-debugging-setup-usb-updating-button = Updating…
+
+# USB section of the Setup page (USB status)
+about-debugging-setup-usb-status-enabled = Enabled
+about-debugging-setup-usb-status-disabled = Disabled
+about-debugging-setup-usb-status-updating = Updating…
+
+# USB section step by step guide
+about-debugging-setup-usb-step-enable-dev-menu = Enable Developer menu on your Android device. <a>Learn how</a>
+
+# USB section step by step guide
+about-debugging-setup-usb-step-enable-debug = Enable USB Debugging in the Android Developer Menu. <a>Learn how</a>
+
+# USB section step by step guide
+about-debugging-setup-usb-step-enable-debug-firefox = Enable USB Debugging in Firefox on the Android device. <a>Learn how</a>
+
+# USB section step by step guide
+about-debugging-setup-usb-step-plug-device = Connect the Android device to your computer.
+
+# Network section of the Setup page
+about-debugging-setup-network =
+  .title = Network Location
+
+# Text of a button displayed after the network locations "Host" input.
+# Clicking on it will add the new network location to the list.
+about-debugging-network-locations-add-button = Add
+
+# Text to display when there are no locations to show.
+about-debugging-network-locations-empty-text = No network locations have been added yet.
+
+# Text of the label for the text input that allows users to add new network locations in
+# the Connect page. A host is a hostname and a port separated by a colon, as suggested by
+# the input's placeholder "localhost:6080".
+about-debugging-network-locations-host-input-label = Host
+
+# Text of a button displayed next to existing network locations in the Connect page.
+# Clicking on it removes the network location from the list.
+about-debugging-network-locations-remove-button = Remove
+
+# Runtime Page strings
+
+# Below are the titles for the various categories of debug targets that can be found
+# on "runtime" pages of about:debugging.
+# Title of the temporary extensions category (only available for "This Firefox" runtime).
+about-debugging-runtime-temporary-extensions =
+  .name = Temporary Extensions
+# Title of the extensions category.
+about-debugging-runtime-extensions =
+  .name = Extensions
+# Title of the tabs category.
+about-debugging-runtime-tabs =
+  .name = Tabs
+# Title of the service workers category.
+about-debugging-runtime-service-workers =
+  .name = Service Workers
+# Title of the shared workers category.
+about-debugging-runtime-shared-workers =
+  .name = Shared Workers
+# Title of the other workers category.
+about-debugging-runtime-other-workers =
+  .name = Other Workers
+# Title of the processes category.
+about-debugging-runtime-processes =
+  .name = Processes
+
+# Label of the button opening the performance profiler panel in runtime pages for remote
+# runtimes.
+about-debugging-runtime-profile-button = Profile Runtime
+
+# This string is displayed in the runtime page if the current configuration of the
+# target runtime is incompatible with service workers. "Learn more" points to MDN.
+# https://developer.mozilla.org/en-US/docs/Tools/about%3Adebugging#Service_workers_not_compatible
+about-debugging-runtime-service-workers-not-compatible = Your browser configuration is not compatible with Service Workers. <a>Learn more</a>
+
+# This string is displayed in the runtime page if the remote runtime version is too old.
+# "Troubleshooting" link points to https://developer.mozilla.org/docs/Tools/WebIDE/Troubleshooting
+# { $runtimeVersion } is the version of the remote runtime (for instance "67.0a1")
+# { $minVersion } is the minimum version that is compatible with the current Firefox instance (same format)
+about-debugging-runtime-version-too-old = The connected runtime has an old version ({ $runtimeVersion }). The minimum supported version is ({ $minVersion }). This is an unsupported setup and may cause DevTools to fail. Please update the connected runtime. <a>Troubleshooting</a>
+
+# Dedicated message for a backward compatibility issue that occurs when connecting:
+# - from Fx 67 to 66 or to 65
+# - from Fx 68 to 66
+# Those are normally in range for DevTools compatibility policy, but specific non
+# backward compatible changes broke the debugger in those scenarios (Bug 1528219).
+# { $runtimeVersion } is the version of the remote runtime (for instance "67.0a1")
+about-debugging-runtime-version-too-old-67-debugger = The Debugger panel may not work with the connected runtime. Please use Firefox { $runtimeVersion } if you need to use the Debugger with this runtime.
+
+# This string is displayed in the runtime page if the remote runtime version is too recent.
+# "Troubleshooting" link points to https://developer.mozilla.org/en-US/docs/Tools/WebIDE/Troubleshooting
+# { $runtimeID } is the build ID of the remote runtime (for instance "20181231", format is yyyyMMdd)
+# { $localID } is the build ID of the current Firefox instance (same format)
+# { $runtimeVersion } is the version of the remote runtime (for instance "67.0a1")
+# { $localVersion } is the version of your current runtime (same format)
+about-debugging-runtime-version-too-recent = The connected runtime is more recent ({ $runtimeVersion }, buildID { $runtimeID }) than your { -brand-shorter-name } ({ $localVersion }, buildID { $localID }). This is an unsupported setup and may cause DevTools to fail. Please update Firefox. <a>Troubleshooting</a>
+
+# Displayed for runtime info in runtime pages.
+# { $name } is brand name such as "Firefox Nightly"
+# { $version } is version such as "64.0a1"
+about-debugging-runtime-name = { $name } ({ $version })
+
+# Text of a button displayed in Runtime pages for remote runtimes.
+# Clicking on the button will close the connection to the runtime.
+about-debugging-runtime-disconnect-button = Disconnect
+
+# Text of the connection prompt button displayed in Runtime pages, when the preference
+# "devtools.debugger.prompt-connection" is false on the target runtime.
+about-debugging-connection-prompt-enable-button = Enable connection prompt
+
+# Text of the connection prompt button displayed in Runtime pages, when the preference
+# "devtools.debugger.prompt-connection" is true on the target runtime.
+about-debugging-connection-prompt-disable-button = Disable connection prompt
+
+# Title of a modal dialog displayed on remote runtime pages after clicking on the Profile Runtime button.
+about-debugging-profiler-dialog-title = Performance Profiler
+
+# Label of a checkbox displayed in the runtime page for "This Firefox".
+# This checkbox will toggle preferences that enable local addon debugging.
+# The "Learn more" link points to MDN.
+# https://developer.mozilla.org/docs/Tools/about:debugging#Enabling_add-on_debugging
+about-debugging-extension-debug-setting-label = Enable extension debugging. <a>Learn more</a>
+
+# Clicking on the header of a debug target category will expand or collapse the debug
+# target items in the category. This text is used as ’title’ attribute of the header,
+# to describe this feature.
+about-debugging-collapse-expand-debug-targets = Collapse / expand
+
+# Debug Targets strings
+
+# Displayed in the categories of "runtime" pages that don't have any debug target to
+# show. Debug targets depend on the category (extensions, tabs, workers...).
+about-debugging-debug-target-list-empty = Nothing yet.
+
+# Text of a button displayed next to debug targets of "runtime" pages. Clicking on this
+# button will open a DevTools toolbox that will allow inspecting the target.
+# A target can be an addon, a tab, a worker...
+about-debugging-debug-target-inspect-button = Inspect
+
+# Text of a button displayed in the "This Firefox" page, in the Temporary Extension
+# section. Clicking on the button will open a file picker to load a temporary extension
+about-debugging-tmp-extension-install-button = Load Temporary Add-on…
+
+# Text displayed when trying to install a temporary extension in the "This Firefox" page.
+about-debugging-tmp-extension-install-error = There was an error during the temporary add-on installation.
+
+# Text of a button displayed for a temporary extension loaded in the "This Firefox" page.
+# Clicking on the button will reload the extension.
+about-debugging-tmp-extension-reload-button = Reload
+
+# Text of a button displayed for a temporary extension loaded in the "This Firefox" page.
+# Clicking on the button will uninstall the extension and remove it from the page.
+about-debugging-tmp-extension-remove-button = Remove
+
+# Message displayed in the file picker that opens to select a temporary extension to load
+# (triggered by the button using "about-debugging-tmp-extension-install-button")
+# manifest.json .xpi and .zip should not be localized.
+# Note: this message is only displayed in Windows and Linux platforms.
+about-debugging-tmp-extension-install-message = Select manifest.json file or .xpi/.zip archive
+
+# This string is displayed as a message about the add-on having a temporaryID.
+about-debugging-tmp-extension-temporary-id = This WebExtension has a temporary ID. <a>Learn more</a>
+
+# Text displayed for extensions in "runtime" pages, before displaying a link the extension's
+# manifest URL.
+about-debugging-extension-manifest-url =
+  .label = Manifest URL
+
+# Text displayed for extensions in "runtime" pages, before displaying the extension's uuid.
+# UUIDs look like b293e463-481e-5148-a487-5aaf7a130429
+about-debugging-extension-uuid =
+  .label = Internal UUID
+
+# Text displayed for extensions (temporary extensions only) in "runtime" pages, before
+# displaying the location of the temporary extension.
+about-debugging-extension-location =
+  .label = Location
+
+# Text displayed for extensions in "runtime" pages, before displaying the extension's ID.
+# For instance "geckoprofiler@mozilla.com" or "{ed26ddcb-5611-4512-a89a-51b8db81cfb2}".
+about-debugging-extension-id =
+  .label = Extension ID
+
+# This string is displayed as a label of the button that pushes a test payload
+# to a service worker.
+# Notes, this relates to the "Push" API, which is normally not localized so it is
+# probably better to not localize it.
+about-debugging-worker-action-push = Push
+
+# This string is displayed as a label of the button that starts a service worker.
+about-debugging-worker-action-start = Start
+
+# This string is displayed as a label of the button that unregisters a service worker.
+about-debugging-worker-action-unregister = Unregister
+
+# Displayed for service workers in runtime pages that listen to Fetch events.
+about-debugging-worker-fetch-listening =
+  .label = Fetch
+  .value = Listening for fetch events
+
+# Displayed for service workers in runtime pages that do not listen to Fetch events.
+about-debugging-worker-fetch-not-listening =
+  .label = Fetch
+  .value = Not listening for fetch events
+
+# Displayed for service workers in runtime pages that are currently running (service
+# worker instance is active).
+about-debugging-worker-status-running = Running
+
+# Displayed for service workers in runtime pages that are registered but stopped.
+about-debugging-worker-status-stopped = Stopped
+
+# Displayed for service workers in runtime pages that are registering.
+about-debugging-worker-status-registering = Registering
+
+# Displayed for service workers in runtime pages, to label the scope of a worker
+about-debugging-worker-scope =
+  .label = Scope
+
+# Displayed for service workers in runtime pages, to label the push service endpoint (url)
+# of a worker
+about-debugging-worker-push-service =
+  .label = Push Service
+
+# Displayed as name for the Main Process debug target in the Processes category. Only for
+# remote runtimes, if `devtools.aboutdebugging.process-debugging` is true.
+about-debugging-main-process-name = Main Process
+
+# Displayed as description for the Main Process debug target in the Processes category.
+# Only for remote runtimes, if `devtools.aboutdebugging.process-debugging` is true.
+about-debugging-main-process-description = Main Process for the target runtime
--- a/devtools/client/locales/en-US/startup.properties
+++ b/devtools/client/locales/en-US/startup.properties
@@ -93,30 +93,16 @@ ToolboxStyleEditor.panelLabel=Style Edit
 # displayed inside the developer tools window.
 # A keyboard shortcut for Stylesheet Editor will be shown inside the latter pair of brackets.
 ToolboxStyleEditor.tooltip3=Stylesheet Editor (CSS) (%S)
 
 # LOCALIZATION NOTE (open.accesskey): The access key used to open the style
 # editor.
 open.accesskey=l
 
-# LOCALIZATION NOTE (ToolboxWebAudioEditor1.label):
-# This string is displayed in the title of the tab when the Web Audio Editor
-# is displayed inside the developer tools window and in the Developer Tools Menu.
-ToolboxWebAudioEditor1.label=Web Audio
-
-# LOCALIZATION NOTE (ToolboxWebAudioEditor1.panelLabel):
-# This is used as the label for the toolbox panel.
-ToolboxWebAudioEditor1.panelLabel=Web Audio Panel
-
-# LOCALIZATION NOTE (ToolboxWebAudioEditor1.tooltip):
-# This string is displayed in the tooltip of the tab when the Web Audio Editor is
-# displayed inside the developer tools window.
-ToolboxWebAudioEditor1.tooltip=Web Audio context visualizer and audio node inspector
-
 # LOCALIZATION NOTE (inspector.*)
 # Used for the menuitem in the tool menu
 inspector.label=Inspector
 inspector.accesskey=I
 
 # LOCALIZATION NOTE (inspector.panelLabel)
 # Labels applied to the panel and views within the panel in the toolbox
 inspector.panelLabel=Inspector Panel
--- a/devtools/client/locales/en-US/styleeditor.properties
+++ b/devtools/client/locales/en-US/styleeditor.properties
@@ -27,20 +27,16 @@ newStyleSheet=New style sheet #%S
 ruleCount.label=#1 rule.;#1 rules.
 
 # LOCALIZATION NOTE  (error-load): This is shown when loading fails.
 error-load=Style sheet could not be loaded.
 
 # LOCALIZATION NOTE  (error-save): This is shown when saving fails.
 error-save=Style sheet could not be saved.
 
-# LOCALIZATION NOTE  (error-compressed): This is shown when we can't show
-# coverage information because the css source is compressed.
-error-compressed=Can’t show coverage information for compressed stylesheets
-
 # LOCALIZATION NOTE  (importStyleSheet.title): This is the file picker title,
 # when you import a style sheet into the Style Editor.
 importStyleSheet.title=Import style sheet
 
 # LOCALIZATION NOTE  (importStyleSheet.filter): This is the *.css filter title
 importStyleSheet.filter=CSS files
 
 # LOCALIZATION NOTE  (saveStyleSheet.title): This is the file picker title,
--- a/devtools/client/preferences/devtools-client.js
+++ b/devtools/client/preferences/devtools-client.js
@@ -336,20 +336,16 @@ pref("devtools.responsive.show-setting-t
 #if defined(NIGHTLY_BUILD)
 pref("devtools.responsive.showUserAgentInput", true);
 #else
 pref("devtools.responsive.showUserAgentInput", false);
 #endif
 
 // Enable new about:debugging.
 pref("devtools.aboutdebugging.new-enabled", false);
-// Enable the network location feature.
-pref("devtools.aboutdebugging.network", false);
-// Enable the wifi feature.
-pref("devtools.aboutdebugging.wifi", false);
 // Show process debug targets.
 pref("devtools.aboutdebugging.process-debugging", false);
 // Stringified array of network locations that users can connect to.
 pref("devtools.aboutdebugging.network-locations", "[]");
 // Debug target pane collapse/expand settings.
 pref("devtools.aboutdebugging.collapsibilities.installedExtension", false);
 pref("devtools.aboutdebugging.collapsibilities.otherWorker", false);
 pref("devtools.aboutdebugging.collapsibilities.serviceWorker", false);
--- a/devtools/client/shared/telemetry.js
+++ b/devtools/client/shared/telemetry.js
@@ -701,17 +701,16 @@ function getChartsFromToolId(id) {
     case "NETMONITOR":
     case "OPTIONS":
     case "PAINTFLASHING":
     case "RESPONSIVE":
     case "SCRATCHPAD":
     case "STORAGE":
     case "STYLEEDITOR":
     case "TOOLBOX":
-    case "WEBAUDIOEDITOR":
     case "WEBCONSOLE":
     case "WEBIDE":
       timerHist = `DEVTOOLS_${id}_TIME_ACTIVE_SECONDS`;
       countHist = `DEVTOOLS_${id}_OPENED_COUNT`;
       break;
     case "ACCESSIBILITY":
     case "APPLICATION":
       timerHist = `DEVTOOLS_${id}_TIME_ACTIVE_SECONDS`;
--- a/devtools/client/storage/ui.js
+++ b/devtools/client/storage/ui.js
@@ -75,17 +75,16 @@ const ITEM_NAME_MAX_LENGTH = 32;
  * @param {Target} target
  *        Interface for the page we're debugging
  * @param {Window} panelWin
  *        Window of the toolbox panel to populate UI in.
  */
 class StorageUI {
   constructor(front, target, panelWin, toolbox) {
     EventEmitter.decorate(this);
-
     this._target = target;
     this._window = panelWin;
     this._panelDoc = panelWin.document;
     this._toolbox = toolbox;
     this.front = front;
     this.storageTypes = null;
     this.sidebarToggledOpen = null;
     this.shouldLoadMoreItems = true;
@@ -596,17 +595,18 @@ class StorageUI {
     if (reason !== REASON.NEXT_50_ITEMS &&
         reason !== REASON.UPDATE &&
         reason !== REASON.NEW_ROW &&
         reason !== REASON.POPULATE) {
       throw new Error("Invalid reason specified");
     }
 
     try {
-      if (reason === REASON.POPULATE) {
+      if (reason === REASON.POPULATE ||
+          (reason === REASON.NEW_ROW && this.table.items.size === 0)) {
         let subType = null;
         // The indexedDB type could have sub-type data to fetch.
         // If having names specified, then it means
         // we are fetching details of specific database or of object store.
         if (type === "indexedDB" && names) {
           const [ dbName, objectStoreName ] = JSON.parse(names[0]);
           if (dbName) {
             subType = "database";
@@ -625,16 +625,18 @@ class StorageUI {
           await this._target.actorHasMethod(type, "removeAllSessionCookies");
 
         await this.resetColumns(type, host, subType);
       }
 
       const {data} = await storageType.getStoreObjects(host, names, fetchOpts);
       if (data.length) {
         await this.populateTable(data, reason);
+      } else if (reason === REASON.POPULATE) {
+        await this.clearHeaders();
       }
       this.updateToolbar();
       this.emit("store-objects-updated");
     } catch (ex) {
       console.error(ex);
     }
   }
 
@@ -648,19 +650,16 @@ class StorageUI {
     // The first node is just a title e.g. "Cookies" so we need to be at least
     // 2 nodes in to show the add button.
     const canAdd = this.actorSupportsAddItem && howManyNodesIn > 1;
 
     if (canAdd) {
       this._addButton.hidden = false;
       this._addButton.setAttribute("tooltiptext",
         L10N.getFormatStr("storage.popupMenu.addItemLabel"));
-    } else {
-      this._addButton.hidden = true;
-      this._addButton.removeAttribute("tooltiptext");
     }
   }
 
   /**
    * Populates the storage tree which displays the list of storages present for
    * the page.
    *
    * @param {object} storageTypes
@@ -980,26 +979,35 @@ class StorageUI {
     const [type, host] = item;
     this.table.host = host;
     this.table.datatype = type;
 
     this.updateToolbar();
 
     let names = null;
     if (!host) {
+      // If selected item has no host then reset table headers
+      await this.clearHeaders();
       return;
     }
     if (item.length > 2) {
       names = [JSON.stringify(item.slice(2))];
     }
     await this.fetchStorageObjects(type, host, names, REASON.POPULATE);
     this.itemOffset = 0;
   }
 
   /**
+   * Clear the column headers in the storage table
+   */
+  async clearHeaders() {
+    this.table.setColumns({}, null, {}, {});
+  }
+
+  /**
    * Resets the column headers in the storage table with the pased object `data`
    *
    * @param {string} type
    *        The type of storage corresponding to the after-reset columns in the
    *        table.
    * @param {string} host
    *        The host name corresponding to the table after reset.
    *
@@ -1114,16 +1122,20 @@ class StorageUI {
    */
   handleKeypress(event) {
     if (event.keyCode == KeyCodes.DOM_VK_ESCAPE && !this.sidebar.hidden) {
       // Stop Propagation to prevent opening up of split console
       this.hideSidebar();
       this.sidebarToggledOpen = false;
       event.stopPropagation();
       event.preventDefault();
+    } else if (event.keyCode == KeyCodes.DOM_VK_BACK_SPACE && this.table.selectedRow) {
+      this.onRemoveItem();
+      event.stopPropagation();
+      event.preventDefault();
     }
   }
 
   /**
    * Handles filtering the table
    */
   filterItems() {
     const value = this.searchBox.value;
@@ -1295,23 +1307,27 @@ class StorageUI {
   }
 
   /**
    * Handles removing an item from the storage
    */
   onRemoveItem() {
     const [, host, ...path] = this.tree.selectedItem;
     const front = this.getCurrentFront();
-    const rowId = this.table.contextMenuRowId;
+    const uniqueId = this.table.uniqueId;
+    const rowId = this.table.contextMenuRowId || this.table.selectedRow[uniqueId];
     const data = this.table.items.get(rowId);
+
     let name = data[this.table.uniqueId];
     if (path.length > 0) {
       name = JSON.stringify([...path, name]);
     }
     front.removeItem(host, name);
+
+    return false;
   }
 
   /**
    * Handles removing all items from the storage
    */
   onRemoveAll() {
     // Cannot use this.currentActor() if the handler is called from the
     // tree context menu: it returns correct value only after the table
--- a/devtools/client/styleeditor/StyleEditorUI.jsm
+++ b/devtools/client/styleeditor/StyleEditorUI.jsm
@@ -644,40 +644,16 @@ StyleEditorUI.prototype = {
             const inputElement =
                 details.querySelector(".stylesheet-editor-input");
             await showEditor.load(inputElement, this._cssProperties);
           }
 
           showEditor.onShow();
 
           this.emit("editor-selected", showEditor);
-
-          // Is there any CSS coverage markup to include?
-          const usage = await this._target.getFront("cssUsage");
-          if (usage == null) {
-            return;
-          }
-
-          const sheet = showEditor.styleSheet;
-          const {reports} = await usage.createEditorReportForSheet(sheet);
-
-          showEditor.removeAllUnusedRegions();
-
-          if (reports.length > 0) {
-            // Only apply if this file isn't compressed. We detect a
-            // compressed file if there are more rules than lines.
-            const editorText = showEditor.sourceEditor.getText();
-            const lineCount = editorText.split("\n").length;
-            const ruleCount = showEditor.styleSheet.ruleCount;
-            if (lineCount >= ruleCount) {
-              showEditor.addUnusedRegions(reports);
-            } else {
-              this.emit("error", { key: "error-compressed", level: "info" });
-            }
-          }
         }.bind(this))().catch(console.error);
       },
     });
   },
 
   /**
    * Switch to the editor that has been marked to be selected.
    *
--- a/devtools/client/styleeditor/StyleSheetEditor.jsm
+++ b/devtools/client/styleeditor/StyleSheetEditor.jsm
@@ -37,19 +37,16 @@ const TRANSITION_PREF = "devtools.stylee
 
 // How long to wait to update linked CSS file after original source was saved
 // to disk. Time in ms.
 const CHECK_LINKED_SHEET_DELAY = 500;
 
 // How many times to check for linked file changes
 const MAX_CHECK_COUNT = 10;
 
-// The classname used to show a line that is not used
-const UNUSED_CLASS = "cm-unused-line";
-
 // How much time should the mouse be still before the selector at that position
 // gets highlighted?
 const SELECTOR_HIGHLIGHT_TIMEOUT = 500;
 
 // Minimum delay between firing two media-rules-changed events.
 const EMIT_MEDIA_RULES_THROTTLING = 500;
 
 /**
@@ -301,51 +298,16 @@ StyleSheetEditor.prototype = {
         this.emit("error", { key: LOAD_ERROR, append: this.styleSheet.href,
                              level: "warning" });
         throw e;
       }
     });
   },
 
   /**
-   * Add markup to a region. UNUSED_CLASS is added to specified lines
-   * @param region An object shaped like
-   *   {
-   *     start: { line: L1, column: C1 },
-   *     end: { line: L2, column: C2 }    // optional
-   *   }
-   */
-  addUnusedRegion: function(region) {
-    this.sourceEditor.addLineClass(region.start.line - 1, UNUSED_CLASS);
-    if (region.end) {
-      for (let i = region.start.line; i <= region.end.line; i++) {
-        this.sourceEditor.addLineClass(i - 1, UNUSED_CLASS);
-      }
-    }
-  },
-
-  /**
-   * As addUnusedRegion except that it takes an array of regions
-   */
-  addUnusedRegions: function(regions) {
-    for (const region of regions) {
-      this.addUnusedRegion(region);
-    }
-  },
-
-  /**
-   * Remove all the unused markup regions added by addUnusedRegion
-   */
-  removeAllUnusedRegions: function() {
-    for (let i = 0; i < this.sourceEditor.lineCount(); i++) {
-      this.sourceEditor.removeLineClass(i, UNUSED_CLASS);
-    }
-  },
-
-  /**
    * Forward property-change event from stylesheet.
    *
    * @param  {string} event
    *         Event type
    * @param  {string} property
    *         Property that has changed on sheet
    */
   _onPropertyChange: function(property, value) {
--- a/devtools/client/styleeditor/index.xul
+++ b/devtools/client/styleeditor/index.xul
@@ -4,18 +4,16 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <!DOCTYPE window [
 <!ENTITY % styleEditorDTD SYSTEM "chrome://devtools/locale/styleeditor.dtd" >
  %styleEditorDTD;
 <!ENTITY % editMenuStrings SYSTEM "chrome://global/locale/editMenuOverlay.dtd">
  %editMenuStrings;
 <!ENTITY % sourceEditorStrings SYSTEM "chrome://devtools/locale/sourceeditor.dtd">
  %sourceEditorStrings;
-<!ENTITY % csscoverageDTD SYSTEM "chrome://devtools-shared/locale/csscoverage.dtd">
- %csscoverageDTD;
 ]>
 
 <?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
 <?xml-stylesheet href="chrome://devtools/content/shared/widgets/widgets.css" type="text/css"?>
 <?xml-stylesheet href="chrome://devtools/content/shared/splitview.css" type="text/css"?>
 <?xml-stylesheet href="chrome://devtools/skin/chart.css" type="text/css"?>
 <?xml-stylesheet href="chrome://devtools/skin/widgets.css" type="text/css"?>
 <?xml-stylesheet href="chrome://devtools/skin/splitview.css" type="text/css"?>
@@ -164,65 +162,11 @@
                 <html:div class="stylesheet-media-list" />
               </vbox>
             </vbox>
           </hbox>
         </box>
       </html:div> <!-- #splitview-templates -->
     </box>   <!-- .splitview-root -->
 
-    <box class="csscoverage-template" hidden="true">
-      <toolbar class="devtools-toolbar csscoverage-toolbar">
-        <button class="devtools-toolbarbutton csscoverage-toolbarbutton"
-            label="&csscoverage.backButton;"
-            onclick="${onback}"/>
-      </toolbar>
-      <!-- The data for this comes from CSSUsageActor.createPageReport -->
-      <html:div class="csscoverage-report-container">
-        <html:div class="csscoverage-report-content">
-          <html:div class="csscoverage-report-summary">
-            <html:div class="csscoverage-report-chart"/>
-          </html:div>
-          <html:div class="csscoverage-report-unused">
-            <html:h2>&csscoverage.unused;</html:h2>
-            <html:p>&csscoverage.noMatches;</html:p>
-            <html:div foreach="page in ${unused}">
-              <html:h3>${page.url}</html:h3>
-              <html:code foreach="rule in ${page.rules}"
-                         href="${rule.url}"
-                         class="csscoverage-list">${rule.selectorText}</html:code>
-            </html:div>
-          </html:div>
-          <html:div class="csscoverage-report-optimize">
-            <html:h2>&csscoverage.optimize.header;</html:h2>
-            <html:p>
-              &csscoverage.optimize.body1;
-              <html:code>&lt;link ...></html:code>
-              &csscoverage.optimize.body2;
-              <html:code>&lt;style>...</html:code>
-              &csscoverage.optimize.body3;
-            </html:p>
-            <html:div if="${preload.length == 0}">&csscoverage.optimize.bodyX;</html:div>
-            <html:div if="${preload.length > 0}">
-              <html:div foreach="page in ${preload}">
-                <html:h3>${page.url}</html:h3>
-                <html:textarea>&lt;style>
-<html:loop foreach="rule in ${page.rules}"
-                      onclick="${rule.onclick}">${rule.formattedCssText}</html:loop>&lt;/style></html:textarea>
-              </html:div>
-            </html:div>
-            <html:p>
-              &csscoverage.footer1;
-              <html:a target="_blank" href="&csscoverage.footer2a;">&csscoverage.footer3;</html:a>
-              &csscoverage.footer4;
-            </html:p>
-          </html:div>
-          <html:p>&#160;</html:p>
-        </html:div>
-      </html:div>
-    </box>
-
-    <box class="csscoverage-report" hidden="true">
-    </box>
-
   </stack>
 
 </window>
--- a/devtools/client/themes/styleeditor.css
+++ b/devtools/client/themes/styleeditor.css
@@ -273,147 +273,8 @@ h3 {
     -moz-box-flex: 1;
     -moz-box-pack: end;
   }
 
   .stylesheet-more > spacer {
     -moz-box-flex: 0;
   }
 }
-
-/* CSS coverage */
-.csscoverage-report {
-  background-color: var(--theme-toolbar-background);
-  -moz-box-orient: horizontal;
-}
-
-.csscoverage-report-container {
-  height: 100vh;
-  padding: 0 10px;
-  overflow-x: hidden;
-  overflow-y: auto;
-  -moz-box-flex: 1;
-}
-
-.csscoverage-report-content {
-  margin: 20px auto;
-  -moz-column-width: 300px;
-  font-size: 13px;
-  -moz-user-select: text;
-}
-
-.csscoverage-report-summary,
-.csscoverage-report-unused,
-.csscoverage-report-optimize {
-  display: inline-block;
-}
-
-.csscoverage-report-unused,
-.csscoverage-report-optimize {
-  flex: 1;
-  min-width: 0;
-}
-
-@media (max-width: 950px) {
-  .csscoverage-report-content {
-    display: block;
-  }
-
-  .csscoverage-report-summary {
-    display: block;
-    text-align: center;
-  }
-}
-
-.csscoverage-report h1 {
-  font-size: 120%;
-}
-
-.csscoverage-report h2 {
-  font-size: 110%;
-}
-
-.csscoverage-report h1,
-.csscoverage-report h2,
-.csscoverage-report h3 {
-  font-weight: bold;
-  margin: 10px 0;
-}
-
-.csscoverage-report code,
-.csscoverage-report textarea {
-  font-family: var(--monospace-font-family);
-  font-size: inherit;
-}
-
-.csscoverage-list:after {
-  content: ', ';
-}
-
-.csscoverage-list:last-child:after {
-  display: none;
-}
-
-.csscoverage-report textarea {
-  width: 100%;
-  height: 100px;
-}
-
-.csscoverage-report a {
-  cursor: pointer;
-  text-decoration: underline;
-}
-
-.csscoverage-report > .csscoverage-toolbar {
-  border: none;
-  margin: 0;
-  padding: 0;
-}
-
-.csscoverage-report > .csscoverage-toolbarbutton {
-  min-width: 4em;
-  min-height: 100vh;
-  margin: 0;
-  padding: 0;
-  border-radius: 0;
-  border-top: none;
-  border-bottom: none;
-  border-inline-start: none;
-}
-
-.csscoverage-report .pie-table-chart-container {
-  -moz-box-orient: vertical;
-  text-align: start;
-}
-
-.chart-colored-blob[name="Used Preload"] {
-  fill: var(--theme-highlight-pink);
-  background: var(--theme-highlight-pink);
-}
-
-.chart-colored-blob[name=Used] {
-  fill: var(--theme-highlight-green);
-  background: var(--theme-highlight-green);
-}
-
-.chart-colored-blob[name=Unused] {
-  fill: var(--theme-highlight-lightorange);
-  background: var(--theme-highlight-lightorange);
-}
-
-/* Undo 'largest' customization */
-.theme-dark .pie-chart-slice[largest] {
-  stroke-width: 1px;
-  stroke: rgba(0,0,0,0.2);
-}
-
-.theme-light .pie-chart-slice[largest] {
-  stroke-width: 1px;
-  stroke: rgba(255,255,255,0.8);
-}
-
-.csscoverage-report .pie-chart-slice {
-  cursor: default;
-}
-
-.csscoverage-report-chart {
-  margin: 0 20px;
-}
deleted file mode 100644
--- a/devtools/server/actors/csscoverage.js
+++ /dev/null
@@ -1,715 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const { Ci } = require("chrome");
-
-const InspectorUtils = require("InspectorUtils");
-const Services = require("Services");
-const ChromeUtils = require("ChromeUtils");
-
-const protocol = require("devtools/shared/protocol");
-const { cssUsageSpec } = require("devtools/shared/specs/csscoverage");
-
-loader.lazyRequireGetter(this, "prettifyCSS", "devtools/shared/inspector/css-logic", true);
-
-const MAX_UNUSED_RULES = 10000;
-
-/**
- * Allow: let foo = l10n.lookup("csscoverageFoo");
- */
-const l10n = exports.l10n = {
-  _URI: "chrome://devtools-shared/locale/csscoverage.properties",
-  lookup: function(msg) {
-    if (this._stringBundle == null) {
-      this._stringBundle = Services.strings.createBundle(this._URI);
-    }
-    return this._stringBundle.GetStringFromName(msg);
-  },
-};
-
-/**
- * CSSUsage manages the collection of CSS usage data.
- * The core of a CSSUsage is a JSON-able data structure called _knownRules
- * which looks like this:
- * This records the CSSStyleRules and their usage.
- * The format is:
- *     Map({
- *       <CSS-URL>|<START-LINE>|<START-COLUMN>: {
- *         selectorText: <CSSStyleRule.selectorText>,
- *         test: <simplify(CSSStyleRule.selectorText)>,
- *         cssText: <CSSStyleRule.cssText>,
- *         isUsed: <TRUE|FALSE>,
- *         presentOn: Set([ <HTML-URL>, ... ]),
- *         preLoadOn: Set([ <HTML-URL>, ... ]),
- *         isError: <TRUE|FALSE>,
- *       }
- *     })
- *
- * For example:
- *     this._knownRules = Map({
- *       "http://eg.com/styles1.css|15|0": {
- *         selectorText: "p.quote:hover",
- *         test: "p.quote",
- *         cssText: "p.quote { color: red; }",
- *         isUsed: true,
- *         presentOn: Set([ "http://eg.com/page1.html", ... ]),
- *         preLoadOn: Set([ "http://eg.com/page1.html" ]),
- *         isError: false,
- *       }, ...
- *     });
- */
-var CSSUsageActor = protocol.ActorClassWithSpec(cssUsageSpec, {
-  initialize: function(conn, targetActor) {
-    protocol.Actor.prototype.initialize.call(this, conn);
-
-    this._targetActor = targetActor;
-    this._running = false;
-
-    this._onTabLoad = this._onTabLoad.bind(this);
-    this._onChange = this._onChange.bind(this);
-
-    this._notifyOn = Ci.nsIWebProgress.NOTIFY_STATE_ALL;
-  },
-
-  destroy: function() {
-    this._targetActor = undefined;
-
-    delete this._onTabLoad;
-    delete this._onChange;
-
-    protocol.Actor.prototype.destroy.call(this);
-  },
-
-  /**
-   * Begin recording usage data
-   * @param noreload It's best if we start by reloading the current page
-   * because that starts the test at a known point, but there could be reasons
-   * why we don't want to do that (e.g. the page contains state that will be
-   * lost across a reload)
-   */
-  start: function(noreload) {
-    if (this._running) {
-      throw new Error(l10n.lookup("csscoverageRunningError"));
-    }
-
-    this._isOneShot = false;
-    this._visitedPages = new Set();
-    this._knownRules = new Map();
-    this._running = true;
-    this._tooManyUnused = false;
-
-    this._progressListener = {
-      QueryInterface: ChromeUtils.generateQI([ Ci.nsIWebProgressListener,
-                                               Ci.nsISupportsWeakReference ]),
-
-      onStateChange: (progress, request, flags, status) => {
-        const isStop = flags & Ci.nsIWebProgressListener.STATE_STOP;
-        const isWindow = flags & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
-
-        if (isStop && isWindow) {
-          this._onTabLoad(progress.DOMWindow.document);
-        }
-      },
-
-      destroy: () => {},
-    };
-
-    this._progress = this._targetActor.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
-                                            .getInterface(Ci.nsIWebProgress);
-    this._progress.addProgressListener(this._progressListener, this._notifyOn);
-
-    if (noreload) {
-      // If we're not starting by reloading the page, then pretend that onload
-      // has just happened.
-      this._onTabLoad(this._targetActor.window.document);
-    } else {
-      this._targetActor.window.location.reload();
-    }
-
-    this.emit("state-change", { isRunning: true });
-  },
-
-  /**
-   * Cease recording usage data
-   */
-  stop: function() {
-    if (!this._running) {
-      throw new Error(l10n.lookup("csscoverageNotRunningError"));
-    }
-
-    this._progress.removeProgressListener(this._progressListener, this._notifyOn);
-    this._progress = undefined;
-
-    this._running = false;
-    this.emit("state-change", { isRunning: false });
-  },
-
-  /**
-   * Start/stop recording usage data depending on what we're currently doing.
-   */
-  toggle: function() {
-    return this._running ? this.stop() : this.start();
-  },
-
-  /**
-   * Running start() quickly followed by stop() does a bunch of unnecessary
-   * work, so this cuts all that out
-   */
-  oneshot: function() {
-    if (this._running) {
-      throw new Error(l10n.lookup("csscoverageRunningError"));
-    }
-
-    this._isOneShot = true;
-    this._visitedPages = new Set();
-    this._knownRules = new Map();
-
-    this._populateKnownRules(this._targetActor.window.document);
-    this._updateUsage(this._targetActor.window.document, false);
-  },
-
-  /**
-   * Called by the ProgressListener to simulate a "load" event
-   */
-  _onTabLoad: function(document) {
-    this._populateKnownRules(document);
-    this._updateUsage(document, true);
-
-    this._observeMutations(document);
-  },
-
-  /**
-   * Setup a MutationObserver on the current document
-   */
-  _observeMutations: function(document) {
-    const MutationObserver = document.defaultView.MutationObserver;
-    const observer = new MutationObserver(mutations => {
-      // It's possible that one of the mutations in this list adds a 'use' of
-      // a CSS rule, and another takes it away. See Bug 1010189
-      this._onChange(document);
-    });
-
-    observer.observe(document, {
-      attributes: true,
-      childList: true,
-      characterData: false,
-      subtree: true,
-    });
-  },
-
-  /**
-   * Event handler for whenever we think the page has changed in a way that
-   * means the CSS usage might have changed.
-   */
-  _onChange: function(document) {
-    // Ignore changes pre 'load'
-    if (!this._visitedPages.has(getURL(document))) {
-      return;
-    }
-    this._updateUsage(document, false);
-  },
-
-  /**
-   * Called whenever we think the list of stylesheets might have changed so
-   * we can update the list of rules that we should be checking
-   */
-  _populateKnownRules: function(document) {
-    const url = getURL(document);
-    this._visitedPages.add(url);
-    // Go through all the rules in the current sheets adding them to knownRules
-    // if needed and adding the current url to the list of pages they're on
-    for (const rule of getAllSelectorRules(document)) {
-      const ruleId = ruleToId(rule);
-      let ruleData = this._knownRules.get(ruleId);
-      if (ruleData == null) {
-        ruleData = {
-          selectorText: rule.selectorText,
-          cssText: rule.cssText,
-          test: getTestSelector(rule.selectorText),
-          isUsed: false,
-          presentOn: new Set(),
-          preLoadOn: new Set(),
-          isError: false,
-        };
-        this._knownRules.set(ruleId, ruleData);
-      }
-
-      ruleData.presentOn.add(url);
-    }
-  },
-
-  /**
-   * Update knownRules with usage information from the current page
-   */
-  _updateUsage: function(document, isLoad) {
-    let qsaCount = 0;
-
-    // Update this._data with matches to say 'used at load time' by sheet X
-    const url = getURL(document);
-
-    for (const [ , ruleData ] of this._knownRules) {
-      // If it broke before, don't try again selectors don't change
-      if (ruleData.isError) {
-        continue;
-      }
-
-      // If it's used somewhere already, don't bother checking again unless
-      // this is a load event in which case we need to add preLoadOn
-      if (!isLoad && ruleData.isUsed) {
-        continue;
-      }
-
-      // Ignore rules that are not present on this page
-      if (!ruleData.presentOn.has(url)) {
-        continue;
-      }
-
-      qsaCount++;
-      if (qsaCount > MAX_UNUSED_RULES) {
-        console.error("Too many unused rules on " + url + " ");
-        this._tooManyUnused = true;
-        continue;
-      }
-
-      try {
-        const match = document.querySelector(ruleData.test);
-        if (match != null) {
-          ruleData.isUsed = true;
-          if (isLoad) {
-            ruleData.preLoadOn.add(url);
-          }
-        }
-      } catch (ex) {
-        ruleData.isError = true;
-      }
-    }
-  },
-
-  /**
-   * Returns a JSONable structure designed to help marking up the style editor,
-   * which describes the CSS selector usage.
-   * Example:
-   *   [
-   *     {
-   *       selectorText: "p#content",
-   *       usage: "unused|used",
-   *       start: { line: 3, column: 0 },
-   *     },
-   *     ...
-   *   ]
-   */
-  createEditorReport: function(url) {
-    if (this._knownRules == null) {
-      return { reports: [] };
-    }
-
-    const reports = [];
-    for (const [ruleId, ruleData] of this._knownRules) {
-      const { url: ruleUrl, line, column } = deconstructRuleId(ruleId);
-      if (ruleUrl !== url || ruleData.isUsed) {
-        continue;
-      }
-
-      const ruleReport = {
-        selectorText: ruleData.selectorText,
-        start: { line: line, column: column },
-      };
-
-      if (ruleData.end) {
-        ruleReport.end = ruleData.end;
-      }
-
-      reports.push(ruleReport);
-    }
-
-    return { reports: reports };
-  },
-
-  /**
-   * Compute the stylesheet URL and delegate the report creation to createEditorReport.
-   * See createEditorReport documentation.
-   *
-   * @param {StyleSheetActor} stylesheetActor
-   *        the stylesheet actor for which the coverage report should be generated.
-   */
-  createEditorReportForSheet: function(stylesheetActor) {
-    const url = sheetToUrl(stylesheetActor.rawSheet);
-    return this.createEditorReport(url);
-  },
-
-  /**
-   * Returns a JSONable structure designed for the page report which shows
-   * the recommended changes to a page.
-   *
-   * "preload" means that a rule is used before the load event happens, which
-   * means that the page could by optimized by placing it in a <style> element
-   * at the top of the page, moving the <link> elements to the bottom.
-   *
-   * Example:
-   *   {
-   *     preload: [
-   *       {
-   *         url: "http://example.org/page1.html",
-   *         shortUrl: "page1.html",
-   *         rules: [
-   *           {
-   *             url: "http://example.org/style1.css",
-   *             shortUrl: "style1.css",
-   *             start: { line: 3, column: 4 },
-   *             selectorText: "p#content",
-   *             formattedCssText: "p#content {\n  color: red;\n }\n"
-   *          },
-   *          ...
-   *         ]
-   *       }
-   *     ],
-   *     unused: [
-   *       {
-   *         url: "http://example.org/style1.css",
-   *         shortUrl: "style1.css",
-   *         rules: [ ... ]
-   *       }
-   *     ]
-   *   }
-   */
-  createPageReport: function() {
-    if (this._running) {
-      throw new Error(l10n.lookup("csscoverageRunningError"));
-    }
-
-    if (this._visitedPages == null) {
-      throw new Error(l10n.lookup("csscoverageNotRunError"));
-    }
-
-    if (this._isOneShot) {
-      throw new Error(l10n.lookup("csscoverageOneShotReportError"));
-    }
-
-    // Helper function to create a JSONable data structure representing a rule
-    const ruleToRuleReport = function(rule, ruleData) {
-      return {
-        url: rule.url,
-        shortUrl: rule.url.split("/").slice(-1)[0],
-        start: { line: rule.line, column: rule.column },
-        selectorText: ruleData.selectorText,
-        formattedCssText: prettifyCSS(ruleData.cssText),
-      };
-    };
-
-    // A count of each type of rule for the bar chart
-    const summary = { used: 0, unused: 0, preload: 0 };
-
-    // Create the set of the unused rules
-    const unusedMap = new Map();
-    for (const [ruleId, ruleData] of this._knownRules) {
-      const rule = deconstructRuleId(ruleId);
-      let rules = unusedMap.get(rule.url);
-      if (rules == null) {
-        rules = [];
-        unusedMap.set(rule.url, rules);
-      }
-      if (!ruleData.isUsed) {
-        const ruleReport = ruleToRuleReport(rule, ruleData);
-        rules.push(ruleReport);
-      } else {
-        summary.unused++;
-      }
-    }
-    const unused = [];
-    for (const [url, rules] of unusedMap) {
-      unused.push({
-        url: url,
-        shortUrl: url.split("/").slice(-1),
-        rules: rules,
-      });
-    }
-
-    // Create the set of rules that could be pre-loaded
-    const preload = [];
-    for (const url of this._visitedPages) {
-      const page = {
-        url: url,
-        shortUrl: url.split("/").slice(-1),
-        rules: [],
-      };
-
-      for (const [ruleId, ruleData] of this._knownRules) {
-        if (ruleData.preLoadOn.has(url)) {
-          const rule = deconstructRuleId(ruleId);
-          const ruleReport = ruleToRuleReport(rule, ruleData);
-          page.rules.push(ruleReport);
-          summary.preload++;
-        } else {
-          summary.used++;
-        }
-      }
-
-      if (page.rules.length > 0) {
-        preload.push(page);
-      }
-    }
-
-    return {
-      summary: summary,
-      preload: preload,
-      unused: unused,
-    };
-  },
-
-  /**
-   * For testing only. What pages did we visit.
-   */
-  _testOnlyVisitedPages: function() {
-    return [...this._visitedPages];
-  },
-});
-
-exports.CSSUsageActor = CSSUsageActor;
-
-/**
- * Generator that filters the CSSRules out of _getAllRules so it only
- * iterates over the CSSStyleRules
- */
-function* getAllSelectorRules(document) {
-  for (const rule of getAllRules(document)) {
-    if (rule.type === CSSRule.STYLE_RULE && rule.selectorText !== "") {
-      yield rule;
-    }
-  }
-}
-
-/**
- * Generator to iterate over the CSSRules in all the stylesheets the
- * current document (i.e. it includes import rules, media rules, etc)
- */
-function* getAllRules(document) {
-  // sheets is an array of the <link> and <style> element in this document
-  const sheets = getAllSheets(document);
-  for (let i = 0; i < sheets.length; i++) {
-    for (let j = 0; j < sheets[i].cssRules.length; j++) {
-      yield sheets[i].cssRules[j];
-    }
-  }
-}
-
-/**
- * Get an array of all the stylesheets that affect this document. That means
- * the <link> and <style> based sheets, and the @imported sheets (recursively)
- * but not the sheets in nested frames.
- */
-function getAllSheets(document) {
-  // sheets is an array of the <link> and <style> element in this document
-  let sheets = Array.slice(document.styleSheets);
-  // Add @imported sheets
-  for (let i = 0; i < sheets.length; i++) {
-    const subSheets = getImportedSheets(sheets[i]);
-    sheets = sheets.concat(...subSheets);
-  }
-  return sheets;
-}
-
-/**
- * Recursively find @import rules in the given stylesheet.
- * We're relying on the browser giving rule.styleSheet == null to resolve
- * @import loops
- */
-function getImportedSheets(stylesheet) {
-  let sheets = [];
-  for (let i = 0; i < stylesheet.cssRules.length; i++) {
-    const rule = stylesheet.cssRules[i];
-    // rule.styleSheet == null with duplicate @imports for the same URL.
-    if (rule.type === CSSRule.IMPORT_RULE && rule.styleSheet != null) {
-      sheets.push(rule.styleSheet);
-      const subSheets = getImportedSheets(rule.styleSheet);
-      sheets = sheets.concat(...subSheets);
-    }
-  }
-  return sheets;
-}
-
-/**
- * Get a unique identifier for a rule. This is currently the string
- * <CSS-URL>|<START-LINE>|<START-COLUMN>
- * @see deconstructRuleId(ruleId)
- */
-function ruleToId(rule) {
-  const line = InspectorUtils.getRelativeRuleLine(rule);
-  const column = InspectorUtils.getRuleColumn(rule);
-  return sheetToUrl(rule.parentStyleSheet) + "|" + line + "|" + column;
-}
-
-/**
- * Convert a ruleId to an object with { url, line, column } properties
- * @see ruleToId(rule)
- */
-const deconstructRuleId = exports.deconstructRuleId = function(ruleId) {
-  const split = ruleId.split("|");
-  if (split.length > 3) {
-    const replace = split.slice(0, split.length - 3 + 1).join("|");
-    split.splice(0, split.length - 3 + 1, replace);
-  }
-  const [ url, line, column ] = split;
-  return {
-    url: url,
-    line: parseInt(line, 10),
-    column: parseInt(column, 10),
-  };
-};
-
-/**
- * We're only interested in the origin and pathname, because changes to the
- * username, password, hash, or query string probably don't significantly
- * change the CSS usage properties of a page.
- * @param document
- */
-const getURL = exports.getURL = function(document) {
-  const url = new document.defaultView.URL(document.documentURI);
-  return url == "about:blank" ? "" : "" + url.origin + url.pathname;
-};
-
-/**
- * Pseudo class handling constants:
- * We split pseudo-classes into a number of categories so we can decide how we
- * should match them. See getTestSelector for how we use these constants.
- *
- * @see http://dev.w3.org/csswg/selectors4/#overview
- * @see https://developer.mozilla.org/en-US/docs/tag/CSS%20Pseudo-class
- * @see https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements
- */
-
-/**
- * Category 1: Pseudo-classes that depend on external browser/OS state
- * This includes things like the time, locale, position of mouse/caret/window,
- * contents of browser history, etc. These can be hard to mimic.
- * Action: Remove from selectors
- */
-const SEL_EXTERNAL = [
-  "active", "active-drop", "current", "dir", "focus", "future", "hover",
-  "invalid-drop", "lang", "past", "placeholder-shown", "target", "valid-drop",
-  "visited",
-];
-
-/**
- * Category 2: Pseudo-classes that depend on user-input state
- * These are pseudo-classes that arguably *should* be covered by unit tests but
- * which probably aren't and which are unlikely to be covered by manual tests.
- * We're currently stripping them out,
- * Action: Remove from selectors (but consider future command line flag to
- * enable them in the future. e.g. 'csscoverage start --strict')
- */
-const SEL_FORM = [
-  "checked", "default", "disabled", "enabled", "fullscreen", "in-range",
-  "indeterminate", "invalid", "optional", "out-of-range", "required", "valid",
-];
-
-/**
- * Category 3: Pseudo-elements
- * querySelectorAll doesn't return matches with pseudo-elements because there
- * is no element to match (they're pseudo) so we have to remove them all.
- * (See http://codepen.io/joewalker/pen/sanDw for a demo)
- * Action: Remove from selectors (including deprecated single colon versions)
- */
-const SEL_ELEMENT = [
-  "after", "before", "first-letter", "first-line", "selection",
-];
-
-/**
- * Category 4: Structural pseudo-classes
- * This is a category defined by the spec (also called tree-structural and
- * grid-structural) for selection based on relative position in the document
- * tree that cannot be represented by other simple selectors or combinators.
- * Action: Require a page-match
- */
-const SEL_STRUCTURAL = [
-  "empty", "first-child", "first-of-type", "last-child", "last-of-type",
-  "nth-column", "nth-last-column", "nth-child", "nth-last-child",
-  "nth-last-of-type", "nth-of-type", "only-child", "only-of-type", "root",
-];
-
-/**
- * Category 4a: Semi-structural pseudo-classes
- * These are not structural according to the spec, but act nevertheless on
- * information in the document tree.
- * Action: Require a page-match
- */
-const SEL_SEMI = [ "any-link", "link", "read-only", "read-write", "scope" ];
-
-/**
- * Category 5: Combining pseudo-classes
- * has(), not() etc join selectors together in various ways. We take care when
- * removing pseudo-classes to convert "not(:hover)" into "not(*)" and so on.
- * With these changes the combining pseudo-classes should probably stand on
- * their own.
- * Action: Require a page-match
- */
-const SEL_COMBINING = [ "not", "has", "matches" ];
-
-/**
- * Category 6: Media pseudo-classes
- * Pseudo-classes that should be ignored because they're only relevant to
- * media queries
- * Action: Don't need removing from selectors as they appear in media queries
- */
-const SEL_MEDIA = [ "blank", "first", "left", "right" ];
-
-/**
- * A test selector is a reduced form of a selector that we actually test
- * against. This code strips out pseudo-elements and some pseudo-classes that
- * we think should not have to match in order for the selector to be relevant.
- */
-function getTestSelector(selector) {
-  let replacement = selector;
-  const replaceSelector = pseudo => {
-    replacement = replacement.replace(" :" + pseudo, " *")
-                             .replace("(:" + pseudo, "(*")
-                             .replace(":" + pseudo, "");
-  };
-
-  SEL_EXTERNAL.forEach(replaceSelector);
-  SEL_FORM.forEach(replaceSelector);
-  SEL_ELEMENT.forEach(replaceSelector);
-
-  // Pseudo elements work in : and :: forms
-  SEL_ELEMENT.forEach(pseudo => {
-    replacement = replacement.replace("::" + pseudo, "");
-  });
-
-  return replacement;
-}
-
-/**
- * I've documented all known pseudo-classes above for 2 reasons: To allow
- * checking logic and what might be missing, but also to allow a unit test
- * that fetches the list of supported pseudo-classes and pseudo-elements from
- * the platform and check that they were all represented here.
- */
-exports.SEL_ALL = [
-  SEL_EXTERNAL, SEL_FORM, SEL_ELEMENT, SEL_STRUCTURAL, SEL_SEMI,
-  SEL_COMBINING, SEL_MEDIA,
-].reduce(function(prev, curr) {
-  return prev.concat(curr);
-}, []);
-
-/**
- * Find a URL for a given stylesheet
- * @param {StyleSheet} stylesheet raw stylesheet
- */
-const sheetToUrl = function(stylesheet) {
-  // For <link> elements
-  if (stylesheet.href) {
-    return stylesheet.href;
-  }
-
-  // For <style> elements
-  if (stylesheet.ownerNode) {
-    const document = stylesheet.ownerNode.ownerDocument;
-    const sheets = [...document.querySelectorAll("style")];
-    const index = sheets.indexOf(stylesheet.ownerNode);
-    return getURL(document) + " → <style> index " + index;
-  }
-
-  throw new Error("Unknown sheet source");
-};
--- a/devtools/server/actors/moz.build
+++ b/devtools/server/actors/moz.build
@@ -23,17 +23,16 @@ DevToolsModules(
     'actor-registry.js',
     'animation-type-longhand.js',
     'animation.js',
     'array-buffer.js',
     'breakpoint.js',
     'changes.js',
     'common.js',
     'css-properties.js',
-    'csscoverage.js',
     'device.js',
     'emulation.js',
     'environment.js',
     'errordocs.js',
     'frame.js',
     'framerate.js',
     'heap-snapshot-file.js',
     'highlighters.css',
@@ -67,19 +66,16 @@ with Files('animation.js'):
     BUG_COMPONENT = ('DevTools', 'Inspector: Animations')
 
 with Files('breakpoint.js'):
     BUG_COMPONENT = ('DevTools', 'Debugger')
 
 with Files('css-properties.js'):
     BUG_COMPONENT = ('DevTools', 'Inspector: Rules')
 
-with Files('csscoverage.js'):
-    BUG_COMPONENT = ('DevTools', 'Graphics Commandline and Toolbar')
-
 with Files('memory.js'):
     BUG_COMPONENT = ('DevTools', 'Memory')
 
 with Files('performance*'):
     BUG_COMPONENT = ('DevTools', 'Performance Tools (Profiler/Timeline)')
 
 with Files('source.js'):
     BUG_COMPONENT = ('DevTools', 'Debugger')
--- a/devtools/server/actors/utils/actor-registry.js
+++ b/devtools/server/actors/utils/actor-registry.js
@@ -188,21 +188,16 @@ const ActorRegistry = {
       constructor: "ReflowActor",
       type: { target: true },
     });
     this.registerModule("devtools/server/actors/css-properties", {
       prefix: "cssProperties",
       constructor: "CssPropertiesActor",
       type: { target: true },
     });
-    this.registerModule("devtools/server/actors/csscoverage", {
-      prefix: "cssUsage",
-      constructor: "CSSUsageActor",
-      type: { target: true },
-    });
     if ("nsIProfiler" in Ci &&
         !Services.prefs.getBoolPref("devtools.performance.new-panel-enabled", false)) {
       this.registerModule("devtools/server/actors/performance", {
         prefix: "performance",
         constructor: "PerformanceActor",
         type: { target: true },
       });
     }
deleted file mode 100644
--- a/devtools/shared/fronts/csscoverage.js
+++ /dev/null
@@ -1,105 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-const {cssUsageSpec} = require("devtools/shared/specs/csscoverage");
-const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
-
-const {LocalizationHelper} = require("devtools/shared/l10n");
-const L10N = new LocalizationHelper("devtools/shared/locales/csscoverage.properties");
-
-loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
-
-/**
- * Allow: let foo = l10n.lookup("csscoverageFoo");
- */
-const l10n = exports.l10n = {
-  lookup: (msg) => L10N.getStr(msg),
-};
-
-/**
- * Running more than one usage report at a time is probably bad for performance
- * and it isn't particularly useful, and it's confusing from a notification POV
- * so we only allow one.
- */
-var isRunning = false;
-var notification;
-var target;
-var chromeWindow;
-
-/**
- * Front for CSSUsageActor
- */
-class CSSUsageFront extends FrontClassWithSpec(cssUsageSpec) {
-  constructor(client) {
-    super(client);
-    this.before("state-change", this._onStateChange.bind(this));
-
-    // Attribute name from which to retrieve the actorID out of the target actor's form
-    this.formAttributeName = "cssUsageActor";
-  }
-
-  _onStateChange(ev) {
-    isRunning = ev.isRunning;
-    ev.target = target;
-
-    if (isRunning) {
-      const gnb = chromeWindow.gNotificationBox;
-      notification = gnb.getNotificationWithValue("csscoverage-running");
-
-      if (notification == null) {
-        const notifyStop = reason => {
-          if (reason == "removed") {
-            this.stop();
-          }
-        };
-
-        const msg = l10n.lookup("csscoverageRunningReply");
-        notification = gnb.appendNotification(msg, "csscoverage-running",
-                                              "",
-                                              gnb.PRIORITY_INFO_HIGH,
-                                              null,
-                                              notifyStop);
-      }
-    } else {
-      if (notification) {
-        notification.close();
-        notification = undefined;
-      }
-
-      gDevTools.showToolbox(target, "styleeditor");
-      target = undefined;
-    }
-  }
-
-  /**
-   * Server-side start is above. Client-side start adds a notification box
-   */
-  start(newChromeWindow, newTarget, noreload = false) {
-    target = newTarget;
-    chromeWindow = newChromeWindow;
-
-    return super.start(noreload);
-  }
-
-  /**
-   * Server-side start is above. Client-side start adds a notification box
-   */
-  toggle(newChromeWindow, newTarget) {
-    target = newTarget;
-    chromeWindow = newChromeWindow;
-
-    return super.toggle();
-  }
-
-  /**
-   * We count STARTING and STOPPING as 'running'
-   */
-  isRunning() {
-    return isRunning;
-  }
-}
-
-exports.CSSUsageFront = CSSUsageFront;
-registerFront(CSSUsageFront);
--- a/devtools/shared/fronts/moz.build
+++ b/devtools/shared/fronts/moz.build
@@ -12,17 +12,16 @@ DIRS += [
 ]
 
 DevToolsModules(
     'accessibility.js',
     'actor-registry.js',
     'animation.js',
     'changes.js',
     'css-properties.js',
-    'csscoverage.js',
     'device.js',
     'emulation.js',
     'framerate.js',
     'highlighters.js',
     'inspector.js',
     'layout.js',
     'memory.js',
     'node.js',
deleted file mode 100644
--- a/devtools/shared/locales/en-US/csscoverage.dtd
+++ /dev/null
@@ -1,47 +0,0 @@
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<!-- LOCALIZATION NOTE : FILE This file contains the CSS Coverage Report
-   - strings. See the 'csscoverage' command for more information, and
-   - devtools/client/styleeditor/index.xul for context -->
-
-<!-- LOCALIZATION NOTE : FILE The correct localization of this file might be to
-   - keep it in English, or another language commonly spoken among web developers.
-   - You want to make that choice consistent across the developer tools.
-   - A good criteria is the language in which you'd find the best
-   - documentation on web development on the web. -->
-
-<!-- LOCALIZATION NOTE (csscoverage.backButton):
-  -  Text on the button to go back to the main style editor -->
-<!ENTITY csscoverage.backButton "Back">
-
-<!-- LOCALIZATION NOTE (csscoverage.unused, csscoverage.noMatches):
-  -  This is the heading and body text for the CSS usage part of the report -->
-<!ENTITY csscoverage.unused "Unused Rules">
-<!ENTITY csscoverage.noMatches "No matches found for the following rules:">
-
-<!-- LOCALIZATION NOTE (csscoverage.optimize.header):
-  -  This is the heading for the CSS optimization part of the report -->
-<!ENTITY csscoverage.optimize.header "Optimizable Pages">
-
-<!-- LOCALIZATION NOTE (csscoverage.preload1, csscoverage.preload2,
-  -  csscoverage.preload3): These 3 are part of a paragraph with 1 and 2
-  -  separated by a styled <link> tag and 2 and 3 separated by a styled
-  -  <style> tag -->
-<!ENTITY csscoverage.optimize.body1 "You can sometimes speed up loading by moving">
-<!ENTITY csscoverage.optimize.body2 "tags to the bottom of the page and creating a new inline">
-<!ENTITY csscoverage.optimize.body3 "element with the styles needed before the ‘load’ event to the top. Here are the style blocks you need:">
-
-<!-- LOCALIZATION NOTE (csscoverage.optimize.bodyX):
-  -  This is what we say when we have no optimization suggestions -->
-<!ENTITY csscoverage.optimize.bodyX "All rules are inlined.">
-
-<!-- LOCALIZATION NOTE (csscoverage.footer1, csscoverage.footer2a,
-  -  csscoverage.footer3, csscoverage.footer4): The text displayed at the
-  -  bottom of the page, with 2a being the URL opened when the link text in 3
-  -  is clicked -->
-<!ENTITY csscoverage.footer1 "See">
-<!ENTITY csscoverage.footer2a "https://developer.mozilla.org/docs/Tools/CSS_Coverage">
-<!ENTITY csscoverage.footer3 "the MDN article on the CSS Coverage Tool">
-<!ENTITY csscoverage.footer4 "for caveats in the generation of this report.">
deleted file mode 100644
--- a/devtools/shared/locales/en-US/csscoverage.properties
+++ /dev/null
@@ -1,32 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# LOCALIZATION NOTE These strings are used in the 'csscoverage' command and in
-# the user interface that this command creates.
-
-# LOCALIZATION NOTE (csscoverageDesc, csscoverageStartDesc2,
-# csscoverageStopDesc2, csscoverageOneShotDesc2, csscoverageToggleDesc2,
-# csscoverageReportDesc2): Short descriptions of the csscoverage commands
-csscoverageDesc=Control CSS coverage analysis
-csscoverageStartDesc2=Begin collecting CSS coverage data
-csscoverageStopDesc2=Stop collecting CSS coverage data
-csscoverageOneShotDesc2=Collect instantaneous CSS coverage data
-csscoverageToggleDesc2=Toggle collecting CSS coverage data
-csscoverageReportDesc2=Show CSS coverage report
-csscoverageStartNoReloadDesc=Don’t start with a page reload
-csscoverageStartNoReloadManual=It’s best if we start by reloading the current page because that starts the test at a known point, but there could be reasons why we don’t want to do that (e.g. the page contains state that will be lost across a reload)
-
-# LOCALIZATION NOTE (csscoverageRunningReply, csscoverageDoneReply): Text that
-# describes the current state of the css coverage system
-csscoverageRunningReply=Running CSS coverage analysis
-csscoverageDoneReply=CSS Coverage analysis completed
-
-# LOCALIZATION NOTE (csscoverageRunningError, csscoverageNotRunningError,
-# csscoverageNotRunError): Error message that describe things that can go wrong
-# with the css coverage system
-csscoverageRunningError=CSS coverage analysis already running
-csscoverageNotRunningError=CSS coverage analysis not running
-csscoverageNotRunError=CSS coverage analysis has not been run
-csscoverageNoRemoteError=Target does not support CSS Coverage
-csscoverageOneShotReportError=CSS coverage report is not available for ‘oneshot’ data. Please use start/stop.
deleted file mode 100644
--- a/devtools/shared/specs/csscoverage.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-const {Arg, RetVal, generateActorSpec} = require("devtools/shared/protocol");
-
-const cssUsageSpec = generateActorSpec({
-  typeName: "cssUsage",
-
-  events: {
-    "state-change": {
-      type: "stateChange",
-      stateChange: Arg(0, "json"),
-    },
-  },
-
-  methods: {
-    start: {
-      request: { url: Arg(0, "boolean") },
-    },
-    stop: {},
-    toggle: {},
-    oneshot: {},
-    createEditorReport: {
-      request: { url: Arg(0, "string") },
-      response: { reports: RetVal("array:json") },
-    },
-    createEditorReportForSheet: {
-      request: { url: Arg(0, "stylesheet") },
-      response: { reports: RetVal("array:json") },
-    },
-    createPageReport: {
-      response: RetVal("json"),
-    },
-    _testOnlyVisitedPages: {
-      response: { value: RetVal("array:string") },
-    },
-  },
-});
-
-exports.cssUsageSpec = cssUsageSpec;
--- a/devtools/shared/specs/index.js
+++ b/devtools/shared/specs/index.js
@@ -48,21 +48,16 @@ const Types = exports.__TypesForTests = 
     front: "devtools/shared/fronts/changes",
   },
   {
     types: ["cssProperties"],
     spec: "devtools/shared/specs/css-properties",
     front: "devtools/shared/fronts/css-properties",
   },
   {
-    types: ["cssUsage"],
-    spec: "devtools/shared/specs/csscoverage",
-    front: "devtools/shared/fronts/csscoverage",
-  },
-  {
     types: ["device"],
     spec: "devtools/shared/specs/device",
     front: "devtools/shared/fronts/device",
   },
   {
     types: ["emulation"],
     spec: "devtools/shared/specs/emulation",
     front: "devtools/shared/fronts/emulation",
--- a/devtools/shared/specs/moz.build
+++ b/devtools/shared/specs/moz.build
@@ -11,17 +11,16 @@ DIRS += [
 ]
 
 DevToolsModules(
     'accessibility.js',
     'actor-registry.js',
     'animation.js',
     'changes.js',
     'css-properties.js',
-    'csscoverage.js',
     'device.js',
     'emulation.js',
     'environment.js',
     'frame.js',
     'framerate.js',
     'heap-snapshot-file.js',
     'highlighters.js',
     'index.js',
--- a/dom/base/nsContentPermissionHelper.cpp
+++ b/dom/base/nsContentPermissionHelper.cpp
@@ -12,16 +12,17 @@
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/PContentPermission.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "mozilla/dom/PContentPermissionRequestParent.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/TabParent.h"
+#include "mozilla/Attributes.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Unused.h"
 #include "nsComponentManagerUtils.h"
 #include "nsArrayUtils.h"
 #include "nsIMutableArray.h"
 #include "nsContentPermissionHelper.h"
 #include "nsJSUtils.h"
@@ -130,16 +131,18 @@ class ContentPermissionRequestParent : p
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsIPrincipal> mTopLevelPrincipal;
   nsCOMPtr<Element> mElement;
   bool mIsHandlingUserInput;
   RefPtr<nsContentPermissionRequestProxy> mProxy;
   nsTArray<PermissionRequest> mRequests;
 
  private:
+  // Not MOZ_CAN_RUN_SCRIPT because we can't annotate the thing we override yet.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   virtual mozilla::ipc::IPCResult Recvprompt() override;
   virtual mozilla::ipc::IPCResult RecvNotifyVisibility(
       const bool& aIsVisible) override;
   virtual mozilla::ipc::IPCResult RecvDestroy() override;
   virtual void ActorDestroy(ActorDestroyReason why) override;
 };
 
 ContentPermissionRequestParent::ContentPermissionRequestParent(
@@ -157,17 +160,18 @@ ContentPermissionRequestParent::ContentP
 
 ContentPermissionRequestParent::~ContentPermissionRequestParent() {
   MOZ_COUNT_DTOR(ContentPermissionRequestParent);
 }
 
 mozilla::ipc::IPCResult ContentPermissionRequestParent::Recvprompt() {
   mProxy = new nsContentPermissionRequestProxy(this);
   if (NS_FAILED(mProxy->Init(mRequests))) {
-    mProxy->Cancel();
+    RefPtr<nsContentPermissionRequestProxy> proxy(mProxy);
+    proxy->Cancel();
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult ContentPermissionRequestParent::RecvNotifyVisibility(
     const bool& aIsVisible) {
   if (!mProxy) {
     return IPC_FAIL_NO_REASON(this);
@@ -626,21 +630,24 @@ class RequestPromptEvent : public Runnab
 
 class RequestAllowEvent : public Runnable {
  public:
   RequestAllowEvent(bool allow, ContentPermissionRequestBase* request)
       : mozilla::Runnable("RequestAllowEvent"),
         mAllow(allow),
         mRequest(request) {}
 
+  // Not MOZ_CAN_RUN_SCRIPT because we can't annotate the thing we override yet.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   NS_IMETHOD Run() override {
+    // MOZ_KnownLive is OK, because we never drop the ref to mRequest.
     if (mAllow) {
-      mRequest->Allow(JS::UndefinedHandleValue);
+      MOZ_KnownLive(mRequest)->Allow(JS::UndefinedHandleValue);
     } else {
-      mRequest->Cancel();
+      MOZ_KnownLive(mRequest)->Cancel();
     }
     return NS_OK;
   }
 
  private:
   bool mAllow;
   RefPtr<ContentPermissionRequestBase> mRequest;
 };
@@ -926,22 +933,24 @@ RemotePermissionRequest::RemotePermissio
 RemotePermissionRequest::~RemotePermissionRequest() {
   MOZ_ASSERT(
       !mIPCOpen,
       "Protocol must not be open when RemotePermissionRequest is destroyed.");
 }
 
 void RemotePermissionRequest::DoCancel() {
   NS_ASSERTION(mRequest, "We need a request");
-  mRequest->Cancel();
+  nsCOMPtr<nsIContentPermissionRequest> request(mRequest);
+  request->Cancel();
 }
 
 void RemotePermissionRequest::DoAllow(JS::HandleValue aChoices) {
   NS_ASSERTION(mRequest, "We need a request");
-  mRequest->Allow(aChoices);
+  nsCOMPtr<nsIContentPermissionRequest> request(mRequest);
+  request->Allow(aChoices);
 }
 
 // PContentPermissionRequestChild
 mozilla::ipc::IPCResult RemotePermissionRequest::RecvNotifyResult(
     const bool& aAllow, InfallibleTArray<PermissionChoice>&& aChoices) {
   Destroy();
 
   if (aAllow && mWindow->IsCurrentInnerWindow()) {
--- a/dom/base/nsContentPermissionHelper.h
+++ b/dom/base/nsContentPermissionHelper.h
@@ -215,17 +215,19 @@ class RemotePermissionRequest final
       public mozilla::dom::PContentPermissionRequestChild {
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSICONTENTPERMISSIONREQUESTCALLBACK
 
   RemotePermissionRequest(nsIContentPermissionRequest* aRequest,
                           nsPIDOMWindowInner* aWindow);
 
-  // It will be called when prompt dismissed.
+  // It will be called when prompt dismissed.  MOZ_CAN_RUN_SCRIPT_BOUNDARY
+  // because we don't have MOZ_CAN_RUN_SCRIPT bits in IPC code yet.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   mozilla::ipc::IPCResult RecvNotifyResult(
       const bool& aAllow, InfallibleTArray<PermissionChoice>&& aChoices);
 
   mozilla::ipc::IPCResult RecvGetVisibility();
 
   void IPDLAddRef() {
     mIPCOpen = true;
     AddRef();
@@ -238,17 +240,19 @@ class RemotePermissionRequest final
 
   void Destroy();
 
   bool IPCOpen() const { return mIPCOpen && !mDestroyed; }
 
  private:
   virtual ~RemotePermissionRequest();
 
+  MOZ_CAN_RUN_SCRIPT
   void DoAllow(JS::HandleValue aChoices);
+  MOZ_CAN_RUN_SCRIPT
   void DoCancel();
 
   nsCOMPtr<nsIContentPermissionRequest> mRequest;
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
   bool mIPCOpen;
   bool mDestroyed;
   RefPtr<VisibilityChangeListener> mListener;
 };
--- a/dom/base/test/chrome/bug884693.sjs
+++ b/dom/base/test/chrome/bug884693.sjs
@@ -1,8 +1,9 @@
 function handleRequest(request, response)
 {
-  let [status, statusText, body] = request.queryString.split("&");
+  let [status, statusText, encodedBody] = request.queryString.split("&");
+  let body = decodeURIComponent(encodedBody);
   response.setStatusLine(request.httpVersion, status, statusText);
   response.setHeader("Content-Type", "text/xml", false);
   response.setHeader("Content-Length", "" + body.length, false);
   response.write(body);
 }
--- a/dom/base/test/chrome/test_bug884693.xul
+++ b/dom/base/test/chrome/test_bug884693.xul
@@ -14,16 +14,17 @@ https://bugzilla.mozilla.org/show_bug.cg
      target="_blank">Mozilla Bug 884693</a>
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
 
     const SERVER_URL = "http://mochi.test:8888/tests/dom/base/test/chrome/bug884693.sjs";
     const INVALID_XML = "InvalidXML";
+    const XML_WITHOUT_ROOT = "<?xml version='1.0'?>";
 
     let consoleService = Cc["@mozilla.org/consoleservice;1"].
                          getService(Ci.nsIConsoleService)
 
     function runTest(status, statusText, body, expectedResponse, expectedMessages)
     {
       return new Promise((resolve, reject) => {
         consoleService.reset();
@@ -58,14 +59,15 @@ https://bugzilla.mozilla.org/show_bug.cg
       then(() => { return runTest(202, "Accepted", "", "", []); }).
       then(() => { return runTest(202, "Accepted", INVALID_XML, INVALID_XML, []); }).
       then(() => { return runTest(204, "No Content", "", "", []); }).
       then(() => { return runTest(204, "No Content", INVALID_XML, "", []); }).
       then(() => { return runTest(205, "Reset Content", "", "", []); }).
       then(() => { return runTest(205, "Reset Content", INVALID_XML, "", []); }).
       then(() => { return runTest(304, "Not modified", "", "", []); }).
       then(() => { return runTest(304, "Not modified", INVALID_XML, "", []); }).
-      then(() => { return runTest(200, "OK", "", "", ["no root element found"]); }).
+      then(() => { return runTest(200, "OK", "", "", []); }).
+      then(() => { return runTest(200, "OK", XML_WITHOUT_ROOT, XML_WITHOUT_ROOT, ["no root element found"]); }).
       then(() => { return runTest(200, "OK", INVALID_XML, INVALID_XML, ["syntax error"]); }).
       then(SimpleTest.finish);
 
   ]]></script>
 </window>
--- a/dom/bindings/CallbackObject.h
+++ b/dom/bindings/CallbackObject.h
@@ -548,18 +548,23 @@ template <class T, class U>
 void ImplCycleCollectionUnlink(CallbackObjectHolder<T, U>& aField) {
   aField.UnlinkSelf();
 }
 
 // T is expected to be a RefPtr or OwningNonNull around a CallbackObject
 // subclass.  This class is used in bindings to safely handle Fast* callbacks;
 // it ensures that the callback is traced, and that if something is holding onto
 // the callback when we're done with it HoldJSObjects is called.
+//
+// Since we effectively hold a ref to a refcounted thing (like RefPtr or
+// OwningNonNull), we are also MOZ_IS_SMARTPTR_TO_REFCOUNTED for static analysis
+// purposes.
 template <typename T>
-class MOZ_RAII RootedCallback : public JS::Rooted<T> {
+class MOZ_RAII MOZ_IS_SMARTPTR_TO_REFCOUNTED RootedCallback
+    : public JS::Rooted<T> {
  public:
   explicit RootedCallback(JSContext* cx) : JS::Rooted<T>(cx), mCx(cx) {}
 
   // We need a way to make assignment from pointers (how we're normally used)
   // work.
   template <typename S>
   void operator=(S* arg) {
     this->get().operator=(arg);
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -7316,17 +7316,17 @@ class CGCallGenerator(CGThing):
             if (((a.type.isGeckoInterface() or a.type.isCallback() or
                   a.type.isPromise()) and
                  not a.type.nullable()) or
                 a.type.isDOMString()):
                 arg = CGWrapper(arg, pre="NonNullHelper(", post=")")
 
             # If it's a refcounted object, let the static analysis know it's
             # alive for the duration of the call.
-            if a.type.isGeckoInterface():
+            if a.type.isGeckoInterface() or a.type.isCallback():
                 arg = CGWrapper(arg, pre="MOZ_KnownLive(", post=")")
 
             args.append(arg)
 
         needResultDecl = False
 
         # Return values that go in outparams go here
         if resultOutParam is not None:
@@ -10640,17 +10640,17 @@ class ClassBase(ClassItem):
         return ''
 
 
 class ClassMethod(ClassItem):
     def __init__(self, name, returnType, args, inline=False, static=False,
                  virtual=False, const=False, bodyInHeader=False,
                  templateArgs=None, visibility='public', body=None,
                  breakAfterReturnDecl="\n",
-                 breakAfterSelf="\n", override=False):
+                 breakAfterSelf="\n", override=False, canRunScript=False):
         """
         override indicates whether to flag the method as override
         """
         assert not override or virtual
         assert not (override and static)
         self.returnType = returnType
         self.args = args
         self.inline = inline or bodyInHeader
@@ -10658,20 +10658,23 @@ class ClassMethod(ClassItem):
         self.virtual = virtual
         self.const = const
         self.bodyInHeader = bodyInHeader
         self.templateArgs = templateArgs
         self.body = body
         self.breakAfterReturnDecl = breakAfterReturnDecl
         self.breakAfterSelf = breakAfterSelf
         self.override = override
+        self.canRunScript = canRunScript;
         ClassItem.__init__(self, name, visibility)
 
     def getDecorators(self, declaring):
         decorators = []
+        if self.canRunScript:
+            decorators.append('MOZ_CAN_RUN_SCRIPT')
         if self.inline:
             decorators.append('inline')
         if declaring:
             if self.static:
                 decorators.append('static')
             if self.virtual:
                 decorators.append('virtual')
         if decorators:
@@ -14778,17 +14781,17 @@ class CGBindingRoot(CGThing):
         return self.root.deps()
 
 
 class CGNativeMember(ClassMethod):
     def __init__(self, descriptorProvider, member, name, signature, extendedAttrs,
                  breakAfter=True, passJSBitsAsNeeded=True, visibility="public",
                  spiderMonkeyInterfacesAreStructs=True,
                  variadicIsSequence=False, resultNotAddRefed=False,
-                 virtual=False, override=False):
+                 virtual=False, override=False, canRunScript=False):
         """
         If spiderMonkeyInterfacesAreStructs is false, SpiderMonkey interfaces
         will be passed as JS::Handle<JSObject*>.  If it's true they will be
         passed as one of the dom::SpiderMonkeyInterfaceObjectStorage subclasses.
 
         If passJSBitsAsNeeded is false, we don't automatically pass in a
         JSContext* or a JSObject* based on the return and argument types.  We
         can still pass it based on 'implicitJSContext' annotations.
@@ -14808,17 +14811,18 @@ class CGNativeMember(ClassMethod):
                              # Mark our getters, which are attrs that
                              # have a non-void return type, as const.
                              const=(not member.isStatic() and member.isAttr() and
                                     not signature[0].isVoid()),
                              breakAfterReturnDecl=" ",
                              breakAfterSelf=breakAfterSelf,
                              visibility=visibility,
                              virtual=virtual,
-                             override=override)
+                             override=override,
+                             canRunScript=canRunScript)
 
     def getReturnType(self, type, isMember):
         return self.getRetvalInfo(type, isMember)[0]
 
     def getRetvalInfo(self, type, isMember):
         """
         Returns a tuple:
 
@@ -16222,27 +16226,31 @@ class CGCallback(CGClass):
             return ${methodName}(${callArgs});
             """,
             methodName=method.name,
             callArgs=", ".join(argnamesWithoutThisAndRv))
 
         return [ClassMethod(method.name, method.returnType, args,
                             bodyInHeader=True,
                             templateArgs=["typename T"],
-                            body=bodyWithThis),
+                            body=bodyWithThis,
+                            canRunScript=method.canRunScript),
                 ClassMethod(method.name, method.returnType, argsWithoutThis,
                             bodyInHeader=True,
-                            body=bodyWithoutThis),
+                            body=bodyWithoutThis,
+                            canRunScript=method.canRunScript),
                 ClassMethod(method.name, method.returnType, argsWithoutRv,
                             bodyInHeader=True,
                             templateArgs=["typename T"],
-                            body=bodyWithThisWithoutRv),
+                            body=bodyWithThisWithoutRv,
+                            canRunScript=method.canRunScript),
                 ClassMethod(method.name, method.returnType, argsWithoutThisAndRv,
                             bodyInHeader=True,
-                            body=bodyWithoutThisAndRv),
+                            body=bodyWithoutThisAndRv,
+                            canRunScript=method.canRunScript),
                 method]
 
     def deps(self):
         return self._deps
 
 
 class CGCallbackFunction(CGCallback):
     def __init__(self, callback, descriptorProvider):
@@ -16383,17 +16391,18 @@ class FakeMember():
 
 class CallbackMember(CGNativeMember):
     # XXXbz It's OK to use CallbackKnownNotGray for wrapScope because
     # CallSetup already handled the unmark-gray bits for us. we don't have
     # anything better to use for 'obj', really...
     def __init__(self, sig, name, descriptorProvider, needThisHandling,
                  rethrowContentException=False,
                  spiderMonkeyInterfacesAreStructs=False,
-                 wrapScope='CallbackKnownNotGray()'):
+                 wrapScope='CallbackKnownNotGray()',
+                 canRunScript=False):
         """
         needThisHandling is True if we need to be able to accept a specified
         thisObj, False otherwise.
         """
         assert not rethrowContentException or not needThisHandling
 
         self.retvalType = sig[0]
         self.originalSig = sig
@@ -16417,17 +16426,18 @@ class CallbackMember(CGNativeMember):
         # We don't care, for callback codegen, whether our original member was
         # a method or attribute or whatnot.  Just always pass FakeMember()
         # here.
         CGNativeMember.__init__(self, descriptorProvider, FakeMember(),
                                 name, (self.retvalType, args),
                                 extendedAttrs={},
                                 passJSBitsAsNeeded=False,
                                 visibility=visibility,
-                                spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs)
+                                spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs,
+                                canRunScript=canRunScript)
         # We have to do all the generation of our body now, because
         # the caller relies on us throwing if we can't manage it.
         self.exceptionCode = ("aRv.Throw(NS_ERROR_UNEXPECTED);\n"
                               "return%s;\n" % self.getDefaultRetval())
         self.body = self.getImpl()
 
     def getImpl(self):
         setupCall = self.getCallSetup()
@@ -16639,20 +16649,22 @@ class CallbackMember(CGNativeMember):
                               "that.  %s" %
                               (type, idlObject.identifier.name,
                                idlObject.location))
 
 
 class CallbackMethod(CallbackMember):
     def __init__(self, sig, name, descriptorProvider, needThisHandling,
                  rethrowContentException=False,
-                 spiderMonkeyInterfacesAreStructs=False):
+                 spiderMonkeyInterfacesAreStructs=False,
+                 canRunScript=False):
         CallbackMember.__init__(self, sig, name, descriptorProvider,
                                 needThisHandling, rethrowContentException,
-                                spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs)
+                                spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs,
+                                canRunScript=canRunScript)
 
     def getRvalDecl(self):
         return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
 
     def getCall(self):
         if self.argCount > 0:
             args = "JS::HandleValueArray::subarray(argv, 0, argc)"
         else:
@@ -16675,17 +16687,18 @@ class CallbackMethod(CallbackMember):
             args=args,
             errorReturn=self.getDefaultRetval())
 
 
 class CallCallback(CallbackMethod):
     def __init__(self, callback, descriptorProvider):
         self.callback = callback
         CallbackMethod.__init__(self, callback.signatures()[0], "Call",
-                                descriptorProvider, needThisHandling=True)
+                                descriptorProvider, needThisHandling=True,
+                                canRunScript=not callback.isRunScriptBoundary())
 
     def getThisDecl(self):
         return ""
 
     def getThisVal(self):
         return "aThisVal"
 
     def getCallableDecl(self):
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -4659,16 +4659,17 @@ class IDLCallback(IDLObjectWithScope):
         IDLObjectWithScope.__init__(self, location, parentScope, identifier)
 
         for (returnType, arguments) in self.signatures():
             for argument in arguments:
                 argument.resolve(self)
 
         self._treatNonCallableAsNull = False
         self._treatNonObjectAsNull = False
+        self._isRunScriptBoundary = False
 
     def isCallback(self):
         return True
 
     def signatures(self):
         return [(self._returnType, self._arguments)]
 
     def finish(self, scope):
@@ -4696,27 +4697,32 @@ class IDLCallback(IDLObjectWithScope):
 
     def addExtendedAttributes(self, attrs):
         unhandledAttrs = []
         for attr in attrs:
             if attr.identifier() == "TreatNonCallableAsNull":
                 self._treatNonCallableAsNull = True
             elif attr.identifier() == "TreatNonObjectAsNull":
                 self._treatNonObjectAsNull = True
+            elif attr.identifier() == "MOZ_CAN_RUN_SCRIPT_BOUNDARY":
+                self._isRunScriptBoundary = True
             else:
                 unhandledAttrs.append(attr)
         if self._treatNonCallableAsNull and self._treatNonObjectAsNull:
             raise WebIDLError("Cannot specify both [TreatNonCallableAsNull] "
                               "and [TreatNonObjectAsNull]", [self.location])
         if len(unhandledAttrs) != 0:
             IDLType.addExtendedAttributes(self, unhandledAttrs)
 
     def _getDependentObjects(self):
         return set([self._returnType] + self._arguments)
 
+    def isRunScriptBoundary(self):
+        return self._isRunScriptBoundary;
+
 
 class IDLCallbackType(IDLType):
     def __init__(self, location, callback):
         IDLType.__init__(self, location, callback.identifier.name)
         self.callback = callback
 
     def isCallback(self):
         return True
--- a/dom/bindings/test/TestFunctions.h
+++ b/dom/bindings/test/TestFunctions.h
@@ -23,16 +23,17 @@ class TestFunctions : public NonRefcount
  public:
   static TestFunctions* Constructor(GlobalObject& aGlobal, ErrorResult& aRv);
 
   static void ThrowUncatchableException(GlobalObject& aGlobal,
                                         ErrorResult& aRv);
 
   static Promise* PassThroughPromise(GlobalObject& aGlobal, Promise& aPromise);
 
+  MOZ_CAN_RUN_SCRIPT
   static already_AddRefed<Promise> PassThroughCallbackPromise(
       GlobalObject& aGlobal, PromiseReturner& aCallback, ErrorResult& aRv);
 
   void SetStringData(const nsAString& aString);
 
   void GetStringDataAsAString(nsAString& aString);
   void GetStringDataAsAString(uint32_t aLength, nsAString& aString);
   void GetStringDataAsDOMString(const Optional<uint32_t>& aLength,
--- a/dom/chrome-webidl/PlacesObservers.webidl
+++ b/dom/chrome-webidl/PlacesObservers.webidl
@@ -1,14 +1,15 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/.
  */
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback PlacesEventCallback = void (sequence<PlacesEvent> events);
 
 [ChromeOnly, Exposed=Window,
  Constructor(PlacesEventCallback callback)]
 interface PlacesWeakCallbackWrapper {
 };
 
 // Global singleton which should handle all events for places.
--- a/dom/chrome-webidl/SessionStoreUtils.webidl
+++ b/dom/chrome-webidl/SessionStoreUtils.webidl
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 interface nsIDocShell;
 interface nsISupports;
 
 /**
  * A callback passed to SessionStoreUtils.forEachNonDynamicChildFrame().
  */
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback SessionStoreUtilsFrameCallback = void (WindowProxy frame, unsigned long index);
 
 /**
  * SessionStore utility functions implemented in C++ for performance reasons.
  */
 [ChromeOnly, Exposed=Window]
 namespace SessionStoreUtils {
   /**
--- a/dom/chrome-webidl/WebExtensionPolicy.webidl
+++ b/dom/chrome-webidl/WebExtensionPolicy.webidl
@@ -1,15 +1,16 @@
 /* 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/. */
 
 interface URI;
 interface WindowProxy;
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback WebExtensionLocalizeCallback = DOMString (DOMString unlocalizedText);
 
 /**
  * Defines the platform-level policies for a WebExtension, including its
  * permissions and the characteristics of its moz-extension: URLs.
  */
 [Constructor(WebExtensionInit options), ChromeOnly, Exposed=Window]
 interface WebExtensionPolicy {
--- a/dom/geolocation/PositionError.cpp
+++ b/dom/geolocation/PositionError.cpp
@@ -42,17 +42,17 @@ nsWrapperCache* PositionError::GetParent
 JSObject* PositionError::WrapObject(JSContext* aCx,
                                     JS::Handle<JSObject*> aGivenProto) {
   return PositionError_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 void PositionError::NotifyCallback(const GeoPositionErrorCallback& aCallback) {
   nsAutoMicroTask mt;
   if (aCallback.HasWebIDLCallback()) {
-    PositionErrorCallback* callback = aCallback.GetWebIDLCallback();
+    RefPtr<PositionErrorCallback> callback = aCallback.GetWebIDLCallback();
 
     if (callback) {
       callback->Call(*this);
     }
   } else {
     nsIDOMGeoPositionErrorCallback* callback = aCallback.GetXPCOMCallback();
     if (callback) {
       callback->HandleEvent(this);
--- a/dom/geolocation/PositionError.h
+++ b/dom/geolocation/PositionError.h
@@ -33,16 +33,17 @@ class PositionError final : public nsWra
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
   int16_t Code() const { return mCode; }
 
   void GetMessage(nsAString& aMessage) const;
 
+  MOZ_CAN_RUN_SCRIPT
   void NotifyCallback(const GeoPositionErrorCallback& callback);
 
  private:
   ~PositionError();
   int16_t mCode;
   RefPtr<Geolocation> mParent;
 };
 
--- a/dom/geolocation/nsGeolocation.cpp
+++ b/dom/geolocation/nsGeolocation.cpp
@@ -78,29 +78,34 @@ class nsGeolocationRequest final
   nsGeolocationRequest(Geolocation* aLocator, GeoPositionCallback aCallback,
                        GeoPositionErrorCallback aErrorCallback,
                        UniquePtr<PositionOptions>&& aOptions,
                        uint8_t aProtocolType, nsIEventTarget* aMainThreadTarget,
                        bool aWatchPositionRequest = false,
                        int32_t aWatchId = 0);
 
   // nsIContentPermissionRequest
-  NS_IMETHOD Cancel(void) override;
-  NS_IMETHOD Allow(JS::HandleValue choices) override;
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD Cancel(void) override;
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD Allow(JS::HandleValue choices) override;
 
   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsGeolocationRequest)
 
   void Shutdown();
 
+  // MOZ_CAN_RUN_SCRIPT_BOUNDARY is OK here because we're always called from a
+  // runnable.  Ideally nsIRunnable::Run and its overloads would just be
+  // MOZ_CAN_RUN_SCRIPT and then we could be too...
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   void SendLocation(nsIDOMGeoPosition* aLocation);
   bool WantsHighAccuracy() {
     return !mShutdown && mOptions && mOptions->mEnableHighAccuracy;
   }
   void SetTimeoutTimer();
   void StopTimeoutTimer();
+  MOZ_CAN_RUN_SCRIPT
   void NotifyErrorAndShutdown(uint16_t);
   using ContentPermissionRequestBase::GetPrincipal;
   nsIPrincipal* GetPrincipal();
 
   bool IsWatch() { return mIsWatchPositionRequest; }
   int32_t WatchId() { return mWatchId; }
 
  private:
@@ -119,17 +124,18 @@ class nsGeolocationRequest final
       return NS_OK;
     }
 
    private:
     ~TimerCallbackHolder() = default;
     WeakPtr<nsGeolocationRequest> mRequest;
   };
 
-  void Notify();
+  // Only called from a timer, so MOZ_CAN_RUN_SCRIPT_BOUNDARY ok for now.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY void Notify();
 
   bool mIsWatchPositionRequest;
 
   nsCOMPtr<nsITimer> mTimeoutTimer;
   GeoPositionCallback mCallback;
   GeoPositionErrorCallback mErrorCallback;
   UniquePtr<PositionOptions> mOptions;
 
@@ -327,17 +333,18 @@ nsGeolocationRequest::Allow(JS::HandleVa
     // invoke the errorCallback (if present) with TIMEOUT code
     if (mOptions && mOptions->mTimeout == 0 && !mIsWatchPositionRequest) {
       NotifyError(PositionError_Binding::TIMEOUT);
       return NS_OK;
     }
   }
 
   // Kick off the geo device, if it isn't already running
-  nsresult rv = gs->StartDevice(GetPrincipal());
+  nsCOMPtr<nsIPrincipal> principal = GetPrincipal();
+  nsresult rv = gs->StartDevice(principal);
 
   if (NS_FAILED(rv)) {
     // Location provider error
     NotifyError(PositionError_Binding::POSITION_UNAVAILABLE);
     return NS_OK;
   }
 
   if (mIsWatchPositionRequest || !canUseCache) {
@@ -405,17 +412,17 @@ void nsGeolocationRequest::SendLocation(
   if (!mIsWatchPositionRequest) {
     // Cancel timer and position updates in case the position
     // callback spins the event loop
     Shutdown();
   }
 
   nsAutoMicroTask mt;
   if (mCallback.HasWebIDLCallback()) {
-    PositionCallback* callback = mCallback.GetWebIDLCallback();
+    RefPtr<PositionCallback> callback = mCallback.GetWebIDLCallback();
 
     MOZ_ASSERT(callback);
     callback->Call(*wrapped);
   } else {
     nsIDOMGeoPositionCallback* callback = mCallback.GetXPCOMCallback();
     MOZ_ASSERT(callback);
     callback->HandleEvent(aPosition);
   }
@@ -937,23 +944,25 @@ Geolocation::NotifyError(uint16_t aError
   if (!WindowOwnerStillExists()) {
     Shutdown();
     return NS_OK;
   }
 
   mozilla::Telemetry::Accumulate(mozilla::Telemetry::GEOLOCATION_ERROR, true);
 
   for (uint32_t i = mPendingCallbacks.Length(); i > 0; i--) {
-    mPendingCallbacks[i - 1]->NotifyErrorAndShutdown(aErrorCode);
+    RefPtr<nsGeolocationRequest> request = mPendingCallbacks[i - 1];
+    request->NotifyErrorAndShutdown(aErrorCode);
     // NotifyErrorAndShutdown() removes the request from the array
   }
 
   // notify everyone that is watching
   for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
-    mWatchingCallbacks[i]->NotifyErrorAndShutdown(aErrorCode);
+    RefPtr<nsGeolocationRequest> request = mWatchingCallbacks[i];
+    request->NotifyErrorAndShutdown(aErrorCode);
   }
 
   return NS_OK;
 }
 
 bool Geolocation::IsAlreadyCleared(nsGeolocationRequest* aRequest) {
   for (uint32_t i = 0, length = mClearedWatchIDs.Length(); i < length; ++i) {
     if (mClearedWatchIDs[i] == aRequest->WatchId()) {
--- a/dom/geolocation/nsGeolocation.h
+++ b/dom/geolocation/nsGeolocation.h
@@ -71,16 +71,17 @@ class nsGeolocationService final : publi
   // Management of the Geolocation objects
   void AddLocator(mozilla::dom::Geolocation* locator);
   void RemoveLocator(mozilla::dom::Geolocation* locator);
 
   void SetCachedPosition(nsIDOMGeoPosition* aPosition);
   CachedPositionAndAccuracy GetCachedPosition();
 
   // Find and startup a geolocation device (gps, nmea, etc.)
+  MOZ_CAN_RUN_SCRIPT
   nsresult StartDevice(nsIPrincipal* aPrincipal);
 
   // Stop the started geolocation device (gps, nmea, etc.)
   void StopDevice();
 
   // create, or reinitalize the callback timer
   void SetDisconnectTimer();
 
@@ -127,27 +128,29 @@ class Geolocation final : public nsIGeol
   Geolocation();
 
   nsresult Init(nsPIDOMWindowInner* aContentDom = nullptr);
 
   nsPIDOMWindowInner* GetParentObject() const;
   virtual JSObject* WrapObject(JSContext* aCtx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
+  MOZ_CAN_RUN_SCRIPT
   int32_t WatchPosition(PositionCallback& aCallback,
                         PositionErrorCallback* aErrorCallback,
                         const PositionOptions& aOptions, CallerType aCallerType,
                         ErrorResult& aRv);
   void GetCurrentPosition(PositionCallback& aCallback,
                           PositionErrorCallback* aErrorCallback,
                           const PositionOptions& aOptions,
                           CallerType aCallerType, ErrorResult& aRv);
   void ClearWatch(int32_t aWatchId);
 
   // A WatchPosition for C++ use.  Returns -1 if we failed to actually watch.
+  MOZ_CAN_RUN_SCRIPT
   int32_t WatchPosition(nsIDOMGeoPositionCallback* aCallback,
                         nsIDOMGeoPositionErrorCallback* aErrorCallback,
                         UniquePtr<PositionOptions>&& aOptions);
 
   // Returns true if any of the callbacks are repeating
   bool HasActiveCallbacks();
 
   // Register an allowed request
@@ -181,16 +184,17 @@ class Geolocation final : public nsIGeol
 
  private:
   ~Geolocation();
 
   nsresult GetCurrentPosition(GeoPositionCallback aCallback,
                               GeoPositionErrorCallback aErrorCallback,
                               UniquePtr<PositionOptions>&& aOptions,
                               CallerType aCallerType);
+  MOZ_CAN_RUN_SCRIPT
   int32_t WatchPosition(GeoPositionCallback aCallback,
                         GeoPositionErrorCallback aErrorCallback,
                         UniquePtr<PositionOptions>&& aOptions,
                         CallerType aCallerType, ErrorResult& aRv);
 
   bool RegisterRequestWithPrompt(nsGeolocationRequest* request);
 
   // Check if clearWatch is already called
--- a/dom/indexedDB/test/browser_private_idb.js
+++ b/dom/indexedDB/test/browser_private_idb.js
@@ -1,16 +1,15 @@
 async function idbCheckFunc() {
   let factory;
   try {
     // in a worker, this resolves directly.
     factory = indexedDB;
   } catch (ex) {
     // in a frame-script, we need to pierce "content"
-    // eslint-disable-next-line mozilla/no-cpows-in-tests
     factory = content.indexedDB;
   }
   try {
     console.log("opening db");
     const req = factory.open("db", 1);
     const result = await new Promise((resolve, reject) => {
       req.onerror = () => { resolve("error"); };
       // we expect the db to not exist and for created to resolve first
@@ -68,17 +67,16 @@ const workerScriptBlob = new Blob([worke
 
 /**
  * This function is deployed via ContextTask.spawn and operates in a tab
  * frame script context.  Its job is to create the worker that will run the
  * idbCheckFunc and return the result to us.
  */
 async function workerCheckDeployer({ srcBlob, workerType }) {
   let worker, port;
-  // eslint-disable-next-line mozilla/no-cpows-in-tests
   const url = content.URL.createObjectURL(srcBlob);
   if (workerType === "dedicated") {
     worker = new content.Worker(url);
     port = worker;
   } else if (workerType === "shared") {
     worker = new content.SharedWorker(url);
     port = worker.port;
     port.start();
--- a/dom/interfaces/base/nsIBrowser.idl
+++ b/dom/interfaces/base/nsIBrowser.idl
@@ -29,44 +29,28 @@ interface nsIBrowser : nsISupports
    * @param triggeringPrincipal a principal that initiated loading
    *                            of the dropped links
    */
   void dropLinks(in unsigned long linksCount,
                  [array, size_is(linksCount)] in wstring links,
                  in nsIPrincipal aTriggeringPrincipal);
 
   /**
-   * Flags for controlling the behavior of swapBrowsers
-   */
-
-  /**
-   * The default options. This is used for swapping browsers between windows
-   */
-  const unsigned long SWAP_DEFAULT = 0;
-
-  /**
-   * If this bit is set, swapping the browsers will not swap the permanentKey of
-   * the browsers. This is used when performing cross process loads by swapping
-   * browsers.
-   */
-  const unsigned long SWAP_KEEP_PERMANENT_KEY = 0x1;
-
-  /**
    * Swapping of frameloaders are usually initiated from a frameloader owner
    * or other components operating on frameloader owners. This is done by calling
    * swapFrameLoaders at MozFrameLoaderOwner webidl interface.
    *
    * This function aimed to provide the other way around -
    * if the swapping is initiated from frameloader itself or other platform level
    * components, it uses this interface to delegate the swapping request to
    * frameloader owners and ask them to re-initiate frameloader swapping, so that
    * frameloader owners such as <xul:browser> can setup their properties and /
    * or listeners properly on swapping.
    */
-  void swapBrowsers(in nsIBrowser aOtherBrowser, in unsigned long aFlags);
+  void swapBrowsers(in nsIBrowser aOtherBrowser);
 
   /**
    * Close the browser (usually means to remove a tab).
    */
   void closeBrowser();
 
   /**
    * A browser can change from remote to non-remote and vice versa.
--- a/dom/interfaces/base/nsIContentPermissionPrompt.idl
+++ b/dom/interfaces/base/nsIContentPermissionPrompt.idl
@@ -93,18 +93,19 @@ interface nsIContentPermissionRequest : 
    *  The requester to get the required information of
    *  the window.
    */
   readonly attribute nsIContentPermissionRequester requester;
 
   /**
    * allow or cancel the request
    */
-
+  [can_run_script]
   void cancel();
+  [can_run_script]
   void allow([optional] in jsval choices); // {"type1": "choice1", "type2": "choiceA"}
 };
 
 /**
  * Interface provides a way for the application to handle
  * the UI prompts associated with geo position.
  */
 [scriptable, function, uuid(F72DE90D-E954-4E69-9A61-917303029301)]
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -371,16 +371,19 @@ class ContentChild final : public PConte
       nsTArray<StringBundleDescriptor>&& stringBundles);
 
   mozilla::ipc::IPCResult RecvUpdateSharedData(
       const FileDescriptor& aMapFile, const uint32_t& aMapSize,
       nsTArray<IPCBlob>&& aBlobs, nsTArray<nsCString>&& aChangedKeys);
 
   mozilla::ipc::IPCResult RecvGeolocationUpdate(nsIDOMGeoPosition* aPosition);
 
+  // MOZ_CAN_RUN_SCRIPT_BOUNDARY because we don't have MOZ_CAN_RUN_SCRIPT bits
+  // in IPC code yet.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   mozilla::ipc::IPCResult RecvGeolocationError(const uint16_t& errorCode);
 
   mozilla::ipc::IPCResult RecvUpdateDictionaryList(
       InfallibleTArray<nsString>&& aDictionaries);
 
   mozilla::ipc::IPCResult RecvUpdateFontList(
       InfallibleTArray<SystemFontListEntry>&& aFontList);
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -3996,16 +3996,17 @@ mozilla::ipc::IPCResult ContentParent::R
     ipc::UnpackClonedMessageDataForParent(aData, data);
 
     ppm->ReceiveMessage(ppm, nullptr, aMsg, false, &data, &cpows, aPrincipal,
                         nullptr, IgnoreErrors());
   }
   return IPC_OK();
 }
 
+MOZ_CAN_RUN_SCRIPT
 static int32_t AddGeolocationListener(
     nsIDOMGeoPositionCallback* watcher,
     nsIDOMGeoPositionErrorCallback* errorCallBack, bool highAccuracy) {
   RefPtr<Geolocation> geo = Geolocation::NonWindowSingleton();
 
   UniquePtr<PositionOptions> options = MakeUnique<PositionOptions>();
   options->mTimeout = 0;
   options->mMaximumAge = 0;
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -984,20 +984,26 @@ class ContentParent final : public PCont
       InfallibleTArray<CpowEntry>&& aCpows, const IPC::Principal& aPrincipal,
       nsTArray<StructuredCloneData>* aRetvals);
 
   mozilla::ipc::IPCResult RecvAsyncMessage(const nsString& aMsg,
                                            InfallibleTArray<CpowEntry>&& aCpows,
                                            const IPC::Principal& aPrincipal,
                                            const ClonedMessageData& aData);
 
+  // MOZ_CAN_RUN_SCRIPT_BOUNDARY because we don't have MOZ_CAN_RUN_SCRIPT bits
+  // in IPC code yet.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   mozilla::ipc::IPCResult RecvAddGeolocationListener(
       const IPC::Principal& aPrincipal, const bool& aHighAccuracy);
   mozilla::ipc::IPCResult RecvRemoveGeolocationListener();
 
+  // MOZ_CAN_RUN_SCRIPT_BOUNDARY because we don't have MOZ_CAN_RUN_SCRIPT bits
+  // in IPC code yet.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   mozilla::ipc::IPCResult RecvSetGeolocationHigherAccuracy(const bool& aEnable);
 
   mozilla::ipc::IPCResult RecvConsoleMessage(const nsString& aMessage);
 
   mozilla::ipc::IPCResult RecvScriptError(
       const nsString& aMessage, const nsString& aSourceName,
       const nsString& aSourceLine, const uint32_t& aLineNumber,
       const uint32_t& aColNumber, const uint32_t& aFlags,
--- a/dom/manifest/ValueExtractor.jsm
+++ b/dom/manifest/ValueExtractor.jsm
@@ -45,17 +45,20 @@ ValueExtractor.prototype = {
       return value.trim() || undefined;
     }
     return value;
   },
   extractColorValue(spec) {
     const value = this.extractValue(spec);
     let color;
     if (InspectorUtils.isValidCSSColor(value)) {
-      color = value;
+      const rgba = InspectorUtils.colorToRGBA(value);
+      color = "#" + ((rgba.r << 16) |
+        (rgba.g << 8) |
+        rgba.b).toString(16);
     } else if (value) {
       this.console.warn(this.domBundle.formatStringFromName("ManifestInvalidCSSColor",
                                                             [spec.property, value],
                                                             2));
     }
     return color;
   },
 };
--- a/dom/manifest/test/common.js
+++ b/dom/manifest/test/common.js
@@ -15,8 +15,111 @@ const whiteSpace = `${seperators}${lineT
 const typeTests = [1, null, {},
   [], false,
 ];
 const data = {
   jsonText: "{}",
   manifestURL,
   docURL,
 };
+
+const validThemeColors = [
+  ["maroon", "#800000"],
+  ["#f00", "#ff0000"],
+  ["#ff0000", "#ff0000"],
+  ["rgb(255,0,0)", "#ff0000"],
+  ["rgb(255,0,0,1)", "#ff0000"],
+  ["rgb(255,0,0,1.0)", "#ff0000"],
+  ["rgb(255,0,0,100%)", "#ff0000"],
+  ["rgb(255 0 0)", "#ff0000"],
+  ["rgb(255 0 0 / 1)", "#ff0000"],
+  ["rgb(255 0 0 / 1.0)", "#ff0000"],
+  ["rgb(255 0 0 / 100%)", "#ff0000"],
+  ["rgb(100%, 0%, 0%)", "#ff0000"],
+  ["rgb(100%, 0%, 0%, 1)", "#ff0000"],
+  ["rgb(100%, 0%, 0%, 1.0)", "#ff0000"],
+  ["rgb(100%, 0%, 0%, 100%)", "#ff0000"],
+  ["rgb(100% 0% 0%)", "#ff0000"],
+  ["rgb(100% 0% 0% / 1)", "#ff0000"],
+  ["rgb(100%, 0%, 0%, 1.0)", "#ff0000"],
+  ["rgb(100%, 0%, 0%, 100%)", "#ff0000"],
+  ["rgb(300,0,0)", "#ff0000"],
+  ["rgb(300 0 0)", "#ff0000"],
+  ["rgb(255,-10,0)", "#ff0000"],
+  ["rgb(110%, 0%, 0%)", "#ff0000"],
+  ["rgba(255,0,0)", "#ff0000"],
+  ["rgba(255,0,0,1)", "#ff0000"],
+  ["rgba(255 0 0 / 1)", "#ff0000"],
+  ["rgba(100%,0%,0%,1)", "#ff0000"],
+  ["rgba(0,0,255,0.5)", "#ff"],
+  ["rgba(100%, 50%, 0%, 0.1)", "#ff8000"],
+  ["hsl(120, 100%, 50%)", "#ff00"],
+  ["hsl(120 100% 50%)", "#ff00"],
+  ["hsl(120, 100%, 50%, 1.0)", "#ff00"],
+  ["hsl(120 100% 50% / 1.0)", "#ff00"],
+  ["hsla(120, 100%, 50%)", "#ff00"],
+  ["hsla(120 100% 50%)", "#ff00"],
+  ["hsla(120, 100%, 50%, 1.0)", "#ff00"],
+  ["hsla(120 100% 50% / 1.0)", "#ff00"],
+  ["hsl(120deg, 100%, 50%)", "#ff00"],
+  ["hsl(133.33333333grad, 100%, 50%)", "#ff00"],
+  ["hsl(2.0943951024rad, 100%, 50%)", "#ff00"],
+  ["hsl(0.3333333333turn, 100%, 50%)", "#ff00"],
+];
+
+function setupManifest(key, value) {
+  const manifest = {};
+  manifest[key] = value;
+  data.jsonText = JSON.stringify(manifest);
+}
+
+function testValidColors(key) {
+  validThemeColors.forEach(item => {
+    const [manifest_color, parsed_color] = item;
+    setupManifest(key, manifest_color);
+    const result = processor.process(data);
+
+    is(result[key], parsed_color, `Expect ${key} to be returned for ${manifest_color}`);
+  });
+
+  // Trim tests
+  validThemeColors.forEach(item => {
+    const [manifest_color, parsed_color] = item;
+    const expandedThemeColor = `${seperators}${lineTerminators}${manifest_color}${lineTerminators}${seperators}`;
+    setupManifest(key, expandedThemeColor);
+    const result = processor.process(data);
+
+    is(result[key], parsed_color, `Expect trimmed ${key} to be returned for ${manifest_color}`);
+  });
+}
+
+const invalidThemeColors = [
+  "marooon",
+  "f000000",
+  "#ff00000",
+  "rgb(100, 0%, 0%)",
+  "rgb(255,0)",
+  "rbg(255,-10,0)",
+  "rgb(110, 0%, 0%)",
+  "(255,0,0) }",
+  "rgba(255)",
+  " rgb(100%,0%,0%) }",
+  "hsl(120, 100%, 50)",
+  "hsl(120, 100%, 50.0)",
+  "hsl 120, 100%, 50%",
+  "hsla{120, 100%, 50%, 1}",
+];
+
+function testInvalidColors(key) {
+  typeTests.forEach(type => {
+    setupManifest(key, type);
+    const result = processor.process(data);
+
+    is(result[key], undefined, `Expect non-string ${key} to be undefined: ${typeof type}.`);
+  });
+
+  invalidThemeColors.forEach(manifest_color => {
+    setupManifest(key, manifest_color);
+    const result = processor.process(data);
+
+    is(result[key], undefined, `Expect ${key} to be undefined: ${manifest_color}.`);
+  });
+}
--- a/dom/manifest/test/test_ManifestProcessor_background_color.html
+++ b/dom/manifest/test/test_ManifestProcessor_background_color.html
@@ -11,108 +11,12 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script src="common.js"></script>
   <script>
 /**
  * background_color member
  * https://w3c.github.io/manifest/#background_color-member
  **/
 "use strict";
 
-typeTests.forEach(type => {
-  data.jsonText = JSON.stringify({
-    background_color: type,
-  });
-  var result = processor.process(data);
-
-  is(result.background_color, undefined, `Expect non-string background_color to be undefined: ${typeof type}.`);
-});
-
-var validThemeColors = [
-  "maroon",
-  "#f00",
-  "#ff0000",
-  "rgb(255,0,0)",
-  "rgb(255,0,0,1)",
-  "rgb(255,0,0,1.0)",
-  "rgb(255,0,0,100%)",
-  "rgb(255 0 0)",
-  "rgb(255 0 0 / 1)",
-  "rgb(255 0 0 / 1.0)",
-  "rgb(255 0 0 / 100%)",
-  "rgb(100%, 0%, 0%)",
-  "rgb(100%, 0%, 0%, 1)",
-  "rgb(100%, 0%, 0%, 1.0)",
-  "rgb(100%, 0%, 0%, 100%)",
-  "rgb(100% 0% 0%)",
-  "rgb(100% 0% 0% / 1)",
-  "rgb(100%, 0%, 0%, 1.0)",
-  "rgb(100%, 0%, 0%, 100%)",
-  "rgb(300,0,0)",
-  "rgb(300 0 0)",
-  "rgb(255,-10,0)",
-  "rgb(110%, 0%, 0%)",
-  "rgba(255,0,0)",
-  "rgba(255,0,0,1)",
-  "rgba(255 0 0 / 1)",
-  "rgba(100%,0%,0%,1)",
-  "rgba(0,0,255,0.5)",
-  "rgba(100%, 50%, 0%, 0.1)",
-  "hsl(120, 100%, 50%)",
-  "hsl(120 100% 50%)",
-  "hsl(120, 100%, 50%, 1.0)",
-  "hsl(120 100% 50% / 1.0)",
-  "hsla(120, 100%, 50%)",
-  "hsla(120 100% 50%)",
-  "hsla(120, 100%, 50%, 1.0)",
-  "hsla(120 100% 50% / 1.0)",
-  "hsl(120deg, 100%, 50%)",
-  "hsl(133.33333333grad, 100%, 50%)",
-  "hsl(2.0943951024rad, 100%, 50%)",
-  "hsl(0.3333333333turn, 100%, 50%)",
-];
-
-validThemeColors.forEach(background_color => {
-  data.jsonText = JSON.stringify({
-    background_color,
-  });
-  var result = processor.process(data);
-
-  is(result.background_color, background_color, `Expect background_color to be returned: ${background_color}.`);
-});
-
-var invalidThemeColors = [
-  "marooon",
-  "f000000",
-  "#ff00000",
-  "rgb(100, 0%, 0%)",
-  "rgb(255,0)",
-  "rbg(255,-10,0)",
-  "rgb(110, 0%, 0%)",
-  "(255,0,0) }",
-  "rgba(255)",
-  " rgb(100%,0%,0%) }",
-  "hsl(120, 100%, 50)",
-  "hsl(120, 100%, 50.0)",
-  "hsl 120, 100%, 50%",
-  "hsla{120, 100%, 50%, 1}",
-];
-
-invalidThemeColors.forEach(background_color => {
-  data.jsonText = JSON.stringify({
-    background_color,
-  });
-  var result = processor.process(data);
-
-  is(result.background_color, undefined, `Expect background_color to be undefined: ${background_color}.`);
-});
-
-// Trim tests
-validThemeColors.forEach(background_color => {
-  var expandedThemeColor = `${seperators}${lineTerminators}${background_color}${lineTerminators}${seperators}`;
-  data.jsonText = JSON.stringify({
-    background_color: expandedThemeColor,
-  });
-  var result = processor.process(data);
-
-  is(result.background_color, background_color, `Expect trimmed background_color to be returned.`);
-});
+testValidColors("background_color");
+testInvalidColors("background_color");
   </script>
 </head>
--- a/dom/manifest/test/test_ManifestProcessor_theme_color.html
+++ b/dom/manifest/test/test_ManifestProcessor_theme_color.html
@@ -11,108 +11,12 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script src="common.js"></script>
   <script>
 /**
  * theme_color member
  * https://w3c.github.io/manifest/#theme_color-member
  **/
 "use strict";
 
-typeTests.forEach(type => {
-  data.jsonText = JSON.stringify({
-    theme_color: type,
-  });
-  var result = processor.process(data);
-
-  is(result.theme_color, undefined, `Expect non-string theme_color to be undefined: ${typeof type}.`);
-});
-
-var validThemeColors = [
-  "maroon",
-  "#f00",
-  "#ff0000",
-  "rgb(255,0,0)",
-  "rgb(255,0,0,1)",
-  "rgb(255,0,0,1.0)",
-  "rgb(255,0,0,100%)",
-  "rgb(255 0 0)",
-  "rgb(255 0 0 / 1)",
-  "rgb(255 0 0 / 1.0)",
-  "rgb(255 0 0 / 100%)",
-  "rgb(100%, 0%, 0%)",
-  "rgb(100%, 0%, 0%, 1)",
-  "rgb(100%, 0%, 0%, 1.0)",
-  "rgb(100%, 0%, 0%, 100%)",
-  "rgb(100% 0% 0%)",
-  "rgb(100% 0% 0% / 1)",
-  "rgb(100%, 0%, 0%, 1.0)",
-  "rgb(100%, 0%, 0%, 100%)",
-  "rgb(300,0,0)",
-  "rgb(300 0 0)",
-  "rgb(255,-10,0)",
-  "rgb(110%, 0%, 0%)",
-  "rgba(255,0,0)",
-  "rgba(255,0,0,1)",
-  "rgba(255 0 0 / 1)",
-  "rgba(100%,0%,0%,1)",
-  "rgba(0,0,255,0.5)",
-  "rgba(100%, 50%, 0%, 0.1)",
-  "hsl(120, 100%, 50%)",
-  "hsl(120 100% 50%)",
-  "hsl(120, 100%, 50%, 1.0)",
-  "hsl(120 100% 50% / 1.0)",
-  "hsla(120, 100%, 50%)",
-  "hsla(120 100% 50%)",
-  "hsla(120, 100%, 50%, 1.0)",
-  "hsla(120 100% 50% / 1.0)",
-  "hsl(120deg, 100%, 50%)",
-  "hsl(133.33333333grad, 100%, 50%)",
-  "hsl(2.0943951024rad, 100%, 50%)",
-  "hsl(0.3333333333turn, 100%, 50%)",
-];
-
-validThemeColors.forEach(theme_color => {
-  data.jsonText = JSON.stringify({
-    theme_color,
-  });
-  var result = processor.process(data);
-
-  is(result.theme_color, theme_color, `Expect theme_color to be returned: ${theme_color}.`);
-});
-
-var invalidThemeColors = [
-  "marooon",
-  "f000000",
-  "#ff00000",
-  "rgb(100, 0%, 0%)",
-  "rgb(255,0)",
-  "rbg(255,-10,0)",
-  "rgb(110, 0%, 0%)",
-  "(255,0,0) }",
-  "rgba(255)",
-  " rgb(100%,0%,0%) }",
-  "hsl(120, 100%, 50)",
-  "hsl(120, 100%, 50.0)",
-  "hsl 120, 100%, 50%",
-  "hsla{120, 100%, 50%, 1}",
-];
-
-invalidThemeColors.forEach(theme_color => {
-  data.jsonText = JSON.stringify({
-    theme_color,
-  });
-  var result = processor.process(data);
-
-  is(result.theme_color, undefined, `Expect theme_color to be undefined: ${theme_color}.`);
-});
-
-// Trim tests
-validThemeColors.forEach(theme_color => {
-  var expandedThemeColor = `${seperators}${lineTerminators}${theme_color}${lineTerminators}${seperators}`;
-  data.jsonText = JSON.stringify({
-    theme_color: expandedThemeColor,
-  });
-  var result = processor.process(data);
-
-  is(result.theme_color, theme_color, `Expect trimmed theme_color to be returned.`);
-});
+testValidColors("theme_color");
+testInvalidColors("theme_color");
   </script>
 </head>
--- a/dom/media/PeerConnection.jsm
+++ b/dom/media/PeerConnection.jsm
@@ -1672,22 +1672,20 @@ class PeerConnectionObserver {
     this._dompc._onCreateAnswerSuccess(sdp);
   }
 
   onCreateAnswerError(code, message) {
     this._dompc._onCreateAnswerFailure(this.newError(message, code));
   }
 
   onSetLocalDescriptionSuccess() {
-    this._dompc._syncTransceivers();
     this._dompc._onSetLocalDescriptionSuccess();
   }
 
   onSetRemoteDescriptionSuccess() {
-    this._dompc._syncTransceivers();
     this._dompc._processTrackAdditionsAndRemovals();
     this._dompc._fireLegacyAddStreamEvents();
     this._dompc._transceivers = this._dompc._transceivers.filter(t => !t.shouldRemove);
     this._dompc._onSetRemoteDescriptionSuccess();
   }
 
   onSetLocalDescriptionError(code, message) {
     this._dompc._onSetLocalDescriptionFailure(this.newError(message, code));
--- a/dom/media/mp4/MoofParser.cpp
+++ b/dom/media/mp4/MoofParser.cpp
@@ -1096,17 +1096,16 @@ Sbgp::Sbgp(Box& aBox) : mGroupingTypePar
 }
 
 Result<Ok, nsresult> Sbgp::Parse(Box& aBox) {
   BoxReader reader(aBox);
 
   uint32_t flags;
   MOZ_TRY_VAR(flags, reader->ReadU32());
   const uint8_t version = flags >> 24;
-  flags = flags & 0xffffff;
 
   uint32_t type;
   MOZ_TRY_VAR(type, reader->ReadU32());
   mGroupingType = type;
 
   if (version == 1) {
     MOZ_TRY_VAR(mGroupingTypeParam, reader->ReadU32());
   }
--- a/dom/system/mac/CoreLocationLocationProvider.h
+++ b/dom/system/mac/CoreLocationLocationProvider.h
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "nsCOMPtr.h"
 #include "nsIGeolocationProvider.h"
+#include "mozilla/Attributes.h"
 
 /*
  * The CoreLocationObjects class contains the CoreLocation objects
  * we'll need.
  *
  * Declaring them directly in CoreLocationLocationProvider
  * would require Objective-C++ syntax, which would contaminate all
  * files that include this header and require them to be Objective-C++
@@ -25,16 +26,20 @@ class CoreLocationObjects;
 class MLSFallback;
 
 class CoreLocationLocationProvider : public nsIGeolocationProvider {
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIGEOLOCATIONPROVIDER
 
   CoreLocationLocationProvider();
+  // MOZ_CAN_RUN_SCRIPT_BOUNDARY because we can't mark Objective-C methods as
+  // MOZ_CAN_RUN_SCRIPT as far as I can tell, and this method is called from
+  // Objective-C.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   void NotifyError(uint16_t aErrorCode);
   void Update(nsIDOMGeoPosition* aSomewhere);
   void CreateMLSFallbackProvider();
   void CancelMLSFallbackProvider();
 
  private:
   virtual ~CoreLocationLocationProvider() = default;
 
--- a/dom/system/mac/CoreLocationLocationProvider.mm
+++ b/dom/system/mac/CoreLocationLocationProvider.mm
@@ -219,17 +219,18 @@ CoreLocationLocationProvider::SetHighAcc
 }
 
 void CoreLocationLocationProvider::Update(nsIDOMGeoPosition* aSomewhere) {
   if (aSomewhere && mCallback) {
     mCallback->Update(aSomewhere);
   }
 }
 void CoreLocationLocationProvider::NotifyError(uint16_t aErrorCode) {
-  mCallback->NotifyError(aErrorCode);
+  nsCOMPtr<nsIGeolocationUpdate> callback(mCallback);
+  callback->NotifyError(aErrorCode);
 }
 void CoreLocationLocationProvider::CreateMLSFallbackProvider() {
   if (mMLSFallbackProvider) {
     return;
   }
 
   mMLSFallbackProvider = new MLSFallback(0);
   mMLSFallbackProvider->Startup(new MLSUpdate(*this));
--- a/dom/system/windows/WindowsLocationProvider.cpp
+++ b/dom/system/windows/WindowsLocationProvider.cpp
@@ -4,16 +4,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/. */
 
 #include "WindowsLocationProvider.h"
 #include "nsGeoPosition.h"
 #include "nsComponentManagerUtils.h"
 #include "prtime.h"
 #include "MLSFallback.h"
+#include "mozilla/Attributes.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/PositionErrorBinding.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_ISUPPORTS(WindowsLocationProvider::MLSUpdate, nsIGeolocationUpdate);
@@ -35,31 +36,33 @@ WindowsLocationProvider::MLSUpdate::Upda
   Telemetry::Accumulate(Telemetry::GEOLOCATION_WIN8_SOURCE_IS_MLS, true);
   return mCallback->Update(aPosition);
 }
 NS_IMETHODIMP
 WindowsLocationProvider::MLSUpdate::NotifyError(uint16_t aError) {
   if (!mCallback) {
     return NS_ERROR_FAILURE;
   }
-  return mCallback->NotifyError(aError);
+  nsCOMPtr<nsIGeolocationUpdate> callback(mCallback);
+  return callback->NotifyError(aError);
 }
 
 class LocationEvent final : public ILocationEvents {
  public:
   LocationEvent(nsIGeolocationUpdate* aCallback,
                 WindowsLocationProvider* aProvider)
       : mCallback(aCallback), mProvider(aProvider), mCount(0) {}
 
   // IUnknown interface
   STDMETHODIMP_(ULONG) AddRef() override;
   STDMETHODIMP_(ULONG) Release() override;
   STDMETHODIMP QueryInterface(REFIID iid, void** ppv) override;
 
   // ILocationEvents interface
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   STDMETHODIMP OnStatusChanged(REFIID aReportType,
                                LOCATION_REPORT_STATUS aStatus) override;
   STDMETHODIMP OnLocationChanged(REFIID aReportType,
                                  ILocationReport* aReport) override;
 
  private:
   nsCOMPtr<nsIGeolocationUpdate> mCallback;
   RefPtr<WindowsLocationProvider> mProvider;
@@ -122,17 +125,18 @@ LocationEvent::OnStatusChanged(REFIID aR
       break;
     case REPORT_NOT_SUPPORTED:
     case REPORT_ERROR:
       err = PositionError_Binding::POSITION_UNAVAILABLE;
       break;
     default:
       return S_OK;
   }
-  mCallback->NotifyError(err);
+  nsCOMPtr<nsIGeolocationUpdate> callback(mCallback);
+  callback->NotifyError(err);
   return S_OK;
 }
 
 STDMETHODIMP
 LocationEvent::OnLocationChanged(REFIID aReportType, ILocationReport* aReport) {
   if (aReportType != IID_ILatLongReport) {
     return S_OK;
   }
--- a/dom/u2f/U2F.cpp
+++ b/dom/u2f/U2F.cpp
@@ -265,17 +265,17 @@ void U2F::Register(const nsAString& aApp
   ListenForVisibilityEvents();
 #endif
 
   NS_ConvertUTF16toUTF8 clientData(clientDataJSON);
   uint32_t adjustedTimeoutMillis = AdjustedTimeoutMillis(opt_aTimeoutSeconds);
 
   WebAuthnMakeCredentialInfo info(mOrigin, adjustedAppId, challenge, clientData,
                                   adjustedTimeoutMillis, excludeList,
-                                  null_t() /* no extra info for U2F */);
+                                  Nothing() /* no extra info for U2F */);
 
   MOZ_ASSERT(mTransaction.isNothing());
   mTransaction = Some(U2FTransaction(AsVariant(callback)));
   mChild->SendRequestRegister(mTransaction.ref().mId, info);
 }
 
 void U2F::FinishMakeCredential(const uint64_t& aTransactionId,
                                const WebAuthnMakeCredentialResult& aResult) {
@@ -412,17 +412,17 @@ void U2F::Sign(const nsAString& aAppId, 
   // Always blank for U2F
   nsTArray<WebAuthnExtension> extensions;
 
   NS_ConvertUTF16toUTF8 clientData(clientDataJSON);
   uint32_t adjustedTimeoutMillis = AdjustedTimeoutMillis(opt_aTimeoutSeconds);
 
   WebAuthnGetAssertionInfo info(mOrigin, adjustedAppId, challenge, clientData,
                                 adjustedTimeoutMillis, permittedList,
-                                null_t() /* no extra info for U2F */);
+                                Nothing() /* no extra info for U2F */);
 
   MOZ_ASSERT(mTransaction.isNothing());
   mTransaction = Some(U2FTransaction(AsVariant(callback)));
   mChild->SendRequestSign(mTransaction.ref().mId, info);
 }
 
 void U2F::FinishGetAssertion(const uint64_t& aTransactionId,
                              const WebAuthnGetAssertionResult& aResult) {
--- a/dom/webauthn/PWebAuthnTransaction.ipdl
+++ b/dom/webauthn/PWebAuthnTransaction.ipdl
@@ -11,30 +11,27 @@
  * keys, etc) or interruption (another transaction was started in another
  * content process). Similarly, the content process can also request a cancel,
  * either triggered explicitly by the user/script or due to UI events like
  * selecting a different tab.
  */
 
 include protocol PBackground;
 
-using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
+using mozilla::dom::AttestationConveyancePreference from "mozilla/dom/WebAuthnUtil.h";
+using mozilla::dom::AuthenticatorAttachment from "mozilla/dom/WebAuthnUtil.h";
+using mozilla::dom::UserVerificationRequirement from "mozilla/dom/WebAuthnUtil.h";
 
 namespace mozilla {
 namespace dom {
 
-union WebAuthnMaybeAuthenticatorAttachment {
-  uint8_t;
-  null_t;
-};
-
 struct WebAuthnAuthenticatorSelection {
   bool requireResidentKey;
-  uint8_t userVerificationRequirement;
-  WebAuthnMaybeAuthenticatorAttachment authenticatorAttachment;
+  UserVerificationRequirement userVerificationRequirement;
+  AuthenticatorAttachment? authenticatorAttachment;
 };
 
 struct WebAuthnScopedCredential {
   uint8_t[] id;
   uint8_t transports;
 };
 
 struct WebAuthnExtensionAppId {
@@ -71,60 +68,50 @@ struct CoseAlg {
 };
 
 struct WebAuthnMakeCredentialExtraInfo {
   WebAuthnMakeCredentialRpInfo Rp;
   WebAuthnMakeCredentialUserInfo User;
   CoseAlg[] coseAlgs;
   WebAuthnExtension[] Extensions;
   WebAuthnAuthenticatorSelection AuthenticatorSelection;
-  uint8_t attestationConveyancePreference;
-};
-
-union WebAuthnMaybeMakeCredentialExtraInfo {
-  WebAuthnMakeCredentialExtraInfo;
-  null_t;
+  AttestationConveyancePreference attestationConveyancePreference;
 };
 
 struct WebAuthnMakeCredentialInfo {
   nsString Origin;
   nsString RpId;
   uint8_t[] Challenge;
   nsCString ClientDataJSON;
   uint32_t TimeoutMS;
   WebAuthnScopedCredential[] ExcludeList;
-  WebAuthnMaybeMakeCredentialExtraInfo Extra;
+  WebAuthnMakeCredentialExtraInfo? Extra;
 };
 
 struct WebAuthnMakeCredentialResult {
   nsCString ClientDataJSON;
   uint8_t[] AttestationObject;
   uint8_t[] KeyHandle;
   /* Might be empty if the token implementation doesn't support CTAP1. */
   uint8_t[] RegistrationData;
 };
 
 struct WebAuthnGetAssertionExtraInfo {
   WebAuthnExtension[] Extensions;
-  uint8_t userVerificationRequirement;
-};
-
-union WebAuthnMaybeGetAssertionExtraInfo {
-  WebAuthnGetAssertionExtraInfo;
-  null_t;
+  UserVerificationRequirement userVerificationRequirement;
 };
 
 struct WebAuthnGetAssertionInfo {
   nsString Origin;
   nsString RpId;
   uint8_t[] Challenge;
   nsCString ClientDataJSON;
   uint32_t TimeoutMS;
   WebAuthnScopedCredential[] AllowList;
-  WebAuthnMaybeGetAssertionExtraInfo Extra;
+  WebAuthnGetAssertionExtraInfo? Extra;
 };
 
 struct WebAuthnGetAssertionResult {
   nsCString ClientDataJSON;
   uint8_t[] KeyHandle;
   uint8_t[] Signature;
   uint8_t[] AuthenticatorData;
   WebAuthnExtensionResult[] Extensions;
--- a/dom/webauthn/U2FHIDTokenManager.cpp
+++ b/dom/webauthn/U2FHIDTokenManager.cpp
@@ -104,33 +104,30 @@ void U2FHIDTokenManager::Drop() {
 // *      attestation signature
 //
 RefPtr<U2FRegisterPromise> U2FHIDTokenManager::Register(
     const WebAuthnMakeCredentialInfo& aInfo, bool aForceNoneAttestation) {
   mozilla::ipc::AssertIsOnBackgroundThread();
 
   uint64_t registerFlags = 0;
 
-  if (aInfo.Extra().type() != WebAuthnMaybeMakeCredentialExtraInfo::Tnull_t) {
-    const auto& extra = aInfo.Extra().get_WebAuthnMakeCredentialExtraInfo();
+  if (aInfo.Extra().isSome()) {
+    const auto& extra = aInfo.Extra().ref();
     const WebAuthnAuthenticatorSelection& sel = extra.AuthenticatorSelection();
 
     UserVerificationRequirement userVerificaitonRequirement =
-        static_cast<UserVerificationRequirement>(
-            sel.userVerificationRequirement());
+        sel.userVerificationRequirement();
 
     bool requireUserVerification =
         userVerificaitonRequirement == UserVerificationRequirement::Required;
 
     bool requirePlatformAttachment = false;
-    if (sel.authenticatorAttachment().type() ==
-        WebAuthnMaybeAuthenticatorAttachment::Tuint8_t) {
+    if (sel.authenticatorAttachment().isSome()) {
       const AuthenticatorAttachment authenticatorAttachment =
-          static_cast<AuthenticatorAttachment>(
-              sel.authenticatorAttachment().get_uint8_t());
+          sel.authenticatorAttachment().value();
       if (authenticatorAttachment == AuthenticatorAttachment::Platform) {
         requirePlatformAttachment = true;
       }
     }
 
     // Set flags for credential creation.
     if (sel.requireResidentKey()) {
       registerFlags |= U2F_FLAG_REQUIRE_RESIDENT_KEY;
@@ -223,22 +220,21 @@ RefPtr<U2FSignPromise> U2FHIDTokenManage
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return U2FSignPromise::CreateAndReject(NS_ERROR_DOM_UNKNOWN_ERR, __func__);
   }
 
   uint64_t signFlags = 0;
   nsTArray<nsTArray<uint8_t>> appIds;
   appIds.AppendElement(rpIdHash);
 
-  if (aInfo.Extra().type() != WebAuthnMaybeGetAssertionExtraInfo::Tnull_t) {
-    const auto& extra = aInfo.Extra().get_WebAuthnGetAssertionExtraInfo();
+  if (aInfo.Extra().isSome()) {
+    const auto& extra = aInfo.Extra().ref();
 
     UserVerificationRequirement userVerificaitonReq =
-        static_cast<UserVerificationRequirement>(
-            extra.userVerificationRequirement());
+        extra.userVerificationRequirement();
 
     // Set flags for credential requests.
     if (userVerificaitonReq == UserVerificationRequirement::Required) {
       signFlags |= U2F_FLAG_REQUIRE_USER_VERIFICATION;
     }
 
     // Process extensions.
     for (const WebAuthnExtension& ext : extra.Extensions()) {
--- a/dom/webauthn/U2FSoftTokenManager.cpp
+++ b/dom/webauthn/U2FSoftTokenManager.cpp
@@ -569,33 +569,30 @@ RefPtr<U2FRegisterPromise> U2FSoftTokenM
     const WebAuthnMakeCredentialInfo& aInfo, bool aForceNoneAttestation) {
   if (!mInitialized) {
     nsresult rv = Init();
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return U2FRegisterPromise::CreateAndReject(rv, __func__);
     }
   }
 
-  if (aInfo.Extra().type() != WebAuthnMaybeMakeCredentialExtraInfo::Tnull_t) {
-    const auto& extra = aInfo.Extra().get_WebAuthnMakeCredentialExtraInfo();
+  if (aInfo.Extra().isSome()) {
+    const auto& extra = aInfo.Extra().ref();
     const WebAuthnAuthenticatorSelection& sel = extra.AuthenticatorSelection();
 
     UserVerificationRequirement userVerificaitonRequirement =
-        static_cast<UserVerificationRequirement>(
-            sel.userVerificationRequirement());
+        sel.userVerificationRequirement();
 
     bool requireUserVerification =
         userVerificaitonRequirement == UserVerificationRequirement::Required;
 
     bool requirePlatformAttachment = false;
-    if (sel.authenticatorAttachment().type() ==
-        WebAuthnMaybeAuthenticatorAttachment::Tuint8_t) {
+    if (sel.authenticatorAttachment().isSome()) {
       const AuthenticatorAttachment authenticatorAttachment =
-          static_cast<AuthenticatorAttachment>(
-              sel.authenticatorAttachment().get_uint8_t());
+          sel.authenticatorAttachment().value();
       if (authenticatorAttachment == AuthenticatorAttachment::Platform) {
         requirePlatformAttachment = true;
       }
     }
 
     // The U2F softtoken neither supports resident keys or
     // user verification, nor is it a platform authenticator.
     if (sel.requireResidentKey() || requireUserVerification ||
@@ -811,22 +808,21 @@ RefPtr<U2FSignPromise> U2FSoftTokenManag
                                        clientDataHash);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return U2FSignPromise::CreateAndReject(NS_ERROR_DOM_UNKNOWN_ERR, __func__);
   }
 
   nsTArray<nsTArray<uint8_t>> appIds;
   appIds.AppendElement(rpIdHash);
 
-  if (aInfo.Extra().type() != WebAuthnMaybeGetAssertionExtraInfo::Tnull_t) {
-    const auto& extra = aInfo.Extra().get_WebAuthnGetAssertionExtraInfo();
+  if (aInfo.Extra().isSome()) {
+    const auto& extra = aInfo.Extra().ref();
 
     UserVerificationRequirement userVerificaitonReq =
-        static_cast<UserVerificationRequirement>(
-            extra.userVerificationRequirement());
+        extra.userVerificationRequirement();
 
     // The U2F softtoken doesn't support user verification.
     if (userVerificaitonReq == UserVerificationRequirement::Required) {
       return U2FSignPromise::CreateAndReject(NS_ERROR_DOM_NOT_ALLOWED_ERR,
                                              __func__);
     }
 
     // Process extensions.
--- a/dom/webauthn/U2FTokenManager.cpp
+++ b/dom/webauthn/U2FTokenManager.cpp
@@ -276,24 +276,21 @@ void U2FTokenManager::Register(
     AbortTransaction(aTransactionId, NS_ERROR_DOM_NOT_ALLOWED_ERR);
     return;
   }
 
   mLastTransactionId = aTransactionId;
 
   // Determine whether direct attestation was requested.
   bool directAttestationRequested = false;
-  if (aTransactionInfo.Extra().type() ==
-      WebAuthnMaybeMakeCredentialExtraInfo::TWebAuthnMakeCredentialExtraInfo) {
-    const auto& extra =
-        aTransactionInfo.Extra().get_WebAuthnMakeCredentialExtraInfo();
+  if (aTransactionInfo.Extra().isSome()) {
+    const auto& extra = aTransactionInfo.Extra().ref();
 
     AttestationConveyancePreference attestation =
-        static_cast<AttestationConveyancePreference>(
-            extra.attestationConveyancePreference());
+        extra.attestationConveyancePreference();
 
     directAttestationRequested =
         attestation == AttestationConveyancePreference::Direct;
   }
 
   // Start a register request immediately if direct attestation
   // wasn't requested or the test pref is set.
   if (!directAttestationRequested ||
--- a/dom/webauthn/WebAuthnManager.cpp
+++ b/dom/webauthn/WebAuthnManager.cpp
@@ -337,57 +337,47 @@ already_AddRefed<Promise> WebAuthnManage
   // TODO: Add extension list building
   nsTArray<WebAuthnExtension> extensions;
 
   const auto& selection = aOptions.mAuthenticatorSelection;
   const auto& attachment = selection.mAuthenticatorAttachment;
   const AttestationConveyancePreference& attestation = aOptions.mAttestation;
 
   // Attachment
-  WebAuthnMaybeAuthenticatorAttachment authenticatorAttachment(
-      WebAuthnMaybeAuthenticatorAttachment::Tnull_t);
+  Maybe<AuthenticatorAttachment> authenticatorAttachment;
   if (attachment.WasPassed()) {
-    authenticatorAttachment = WebAuthnMaybeAuthenticatorAttachment(
-        static_cast<uint8_t>(attachment.Value()));
+    authenticatorAttachment.emplace(attachment.Value());
   }
 
-  // User Verification
-  uint8_t userVerificationRequirement =
-      static_cast<uint8_t>(selection.mUserVerification);
-
   // Create and forward authenticator selection criteria.
   WebAuthnAuthenticatorSelection authSelection(selection.mRequireResidentKey,
-                                               userVerificationRequirement,
+                                               selection.mUserVerification,
                                                authenticatorAttachment);
 
-  // aOptions.mAttestation
-  uint8_t attestationConveyancePreference = static_cast<uint8_t>(attestation);
-
   nsString rpIcon;
   if (aOptions.mRp.mIcon.WasPassed()) {
     rpIcon = aOptions.mRp.mIcon.Value();
   }
 
   nsString userIcon;
   if (aOptions.mUser.mIcon.WasPassed()) {
     userIcon = aOptions.mUser.mIcon.Value();
   }
 
   WebAuthnMakeCredentialRpInfo rpInfo(aOptions.mRp.mName, rpIcon);
 
   WebAuthnMakeCredentialUserInfo userInfo(
       userId, aOptions.mUser.mName, userIcon, aOptions.mUser.mDisplayName);
 
   WebAuthnMakeCredentialExtraInfo extra(rpInfo, userInfo, coseAlgos, extensions,
-                                        authSelection,
-                                        attestationConveyancePreference);
+                                        authSelection, attestation);
 
   WebAuthnMakeCredentialInfo info(origin, NS_ConvertUTF8toUTF16(rpId),
                                   challenge, clientDataJSON, adjustedTimeout,
-                                  excludeList, extra);
+                                  excludeList, Some(extra));
 
 #ifdef OS_WIN
   if (!WinWebAuthnManager::AreWebAuthNApisAvailable()) {
     ListenForVisibilityEvents();
   }
 #else
   ListenForVisibilityEvents();
 #endif
@@ -519,20 +509,16 @@ already_AddRefed<Promise> WebAuthnManage
     }
   }
 
   if (!MaybeCreateBackgroundActor()) {
     promise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
     return promise.forget();
   }
 
-  // User Verification
-  uint8_t userVerificationRequirement =
-      static_cast<uint8_t>(aOptions.mUserVerification);
-
   // If extensions were specified, process any extensions supported by this
   // client platform, to produce the extension data that needs to be sent to the
   // authenticator. If an error is encountered while processing an extension,
   // skip that extension and do not produce any extension data for it. Call the
   // result of this processing clientExtensions.
   nsTArray<WebAuthnExtension> extensions;
 
   // <https://w3c.github.io/webauthn/#sctn-appid-extension>
@@ -557,21 +543,21 @@ already_AddRefed<Promise> WebAuthnManage
       promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
       return promise.forget();
     }
 
     // Append the hash and send it to the backend.
     extensions.AppendElement(WebAuthnExtensionAppId(appIdHash, appId));
   }
 
-  WebAuthnGetAssertionExtraInfo extra(extensions, userVerificationRequirement);
+  WebAuthnGetAssertionExtraInfo extra(extensions, aOptions.mUserVerification);
 
   WebAuthnGetAssertionInfo info(origin, NS_ConvertUTF8toUTF16(rpId), challenge,
                                 clientDataJSON, adjustedTimeout, allowList,
-                                extra);
+                                Some(extra));
 
 #ifdef OS_WIN
   if (!WinWebAuthnManager::AreWebAuthNApisAvailable()) {
     ListenForVisibilityEvents();
   }
 #else
   ListenForVisibilityEvents();
 #endif
--- a/dom/webauthn/WebAuthnUtil.h
+++ b/dom/webauthn/WebAuthnUtil.h
@@ -7,16 +7,17 @@
 #ifndef mozilla_dom_WebAuthnUtil_h
 #define mozilla_dom_WebAuthnUtil_h
 
 /*
  * Utility functions used by both WebAuthnManager and U2FTokenManager.
  */
 
 #include "mozilla/dom/CryptoBuffer.h"
+#include "mozilla/dom/WebAuthenticationBinding.h"
 
 namespace mozilla {
 namespace dom {
 
 enum class U2FOperation { Register, Sign };
 
 bool EvaluateAppID(nsPIDOMWindowInner* aParent, const nsString& aOrigin,
                    const U2FOperation& aOp, /* in/out */ nsString& aAppId);
@@ -56,9 +57,34 @@ nsresult HashCString(const nsACString& a
 nsresult BuildTransactionHashes(const nsCString& aRpId,
                                 const nsCString& aClientDataJSON,
                                 /* out */ CryptoBuffer& aRpIdHash,
                                 /* out */ CryptoBuffer& aClientDataHash);
 
 }  // namespace dom
 }  // namespace mozilla
 
+namespace IPC {
+
+template <>
+struct ParamTraits<mozilla::dom::AuthenticatorAttachment>
+    : public ContiguousEnumSerializer<
+          mozilla::dom::AuthenticatorAttachment,
+          mozilla::dom::AuthenticatorAttachment::Platform,
+          mozilla::dom::AuthenticatorAttachment::EndGuard_> {};
+
+template <>
+struct ParamTraits<mozilla::dom::UserVerificationRequirement>
+    : public ContiguousEnumSerializer<
+          mozilla::dom::UserVerificationRequirement,
+          mozilla::dom::UserVerificationRequirement::Required,
+          mozilla::dom::UserVerificationRequirement::EndGuard_> {};
+
+template <>
+struct ParamTraits<mozilla::dom::AttestationConveyancePreference>
+    : public ContiguousEnumSerializer<
+          mozilla::dom::AttestationConveyancePreference,
+          mozilla::dom::AttestationConveyancePreference::None,
+          mozilla::dom::AttestationConveyancePreference::EndGuard_> {};
+
+}  // namespace IPC
+
 #endif  // mozilla_dom_WebAuthnUtil_h
--- a/dom/webauthn/WinWebAuthnManager.cpp
+++ b/dom/webauthn/WinWebAuthnManager.cpp
@@ -202,19 +202,18 @@ void WinWebAuthnManager::Register(
   DWORD winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY;
 
   // Resident Key
   BOOL winRequireResidentKey = FALSE;
 
   // AttestationConveyance
   DWORD winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_ANY;
 
-  if (aInfo.Extra().type() ==
-      WebAuthnMaybeMakeCredentialExtraInfo::TWebAuthnMakeCredentialExtraInfo) {
-    const auto& extra = aInfo.Extra().get_WebAuthnMakeCredentialExtraInfo();
+  if (aInfo.Extra().isSome()) {
+    const auto& extra = aInfo.Extra().ref();
 
     rpInfo.pwszName = extra.Rp().Name().get();
     rpInfo.pwszIcon = extra.Rp().Icon().get();
 
     userInfo.cbId = static_cast<DWORD>(extra.User().Id().Length());
     userInfo.pbId = const_cast<unsigned char*>(extra.User().Id().Elements());
     userInfo.pwszName = extra.User().Name().get();
     userInfo.pwszIcon = extra.User().Icon().get();
@@ -225,18 +224,17 @@ void WinWebAuthnManager::Register(
           WEBAUTHN_COSE_CREDENTIAL_PARAMETER_CURRENT_VERSION,
           WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY, coseAlg.alg()};
       coseParams.AppendElement(coseAlgorithm);
     }
 
     const auto& sel = extra.AuthenticatorSelection();
 
     UserVerificationRequirement userVerificationReq =
-        static_cast<UserVerificationRequirement>(
-            sel.userVerificationRequirement());
+        sel.userVerificationRequirement();
     switch (userVerificationReq) {
       case UserVerificationRequirement::Required:
         winUserVerificationReq =
             WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED;
         break;
       case UserVerificationRequirement::Preferred:
         winUserVerificationReq =
             WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED;
@@ -245,39 +243,36 @@ void WinWebAuthnManager::Register(
         winUserVerificationReq =
             WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED;
         break;
       default:
         winUserVerificationReq = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY;
         break;
     }
 
-    if (sel.authenticatorAttachment().type() ==
-        WebAuthnMaybeAuthenticatorAttachment::Tuint8_t) {
+    if (sel.authenticatorAttachment().isSome()) {
       const AuthenticatorAttachment authenticatorAttachment =
-          static_cast<AuthenticatorAttachment>(
-              sel.authenticatorAttachment().get_uint8_t());
+          sel.authenticatorAttachment().value();
       switch (authenticatorAttachment) {
         case AuthenticatorAttachment::Platform:
           winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_PLATFORM;
           break;
         case AuthenticatorAttachment::Cross_platform:
           winAttachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM;
           break;
         default:
           break;
       }
     }
 
     winRequireResidentKey = sel.requireResidentKey();
 
     // AttestationConveyance
     AttestationConveyancePreference attestation =
-        static_cast<AttestationConveyancePreference>(
-            extra.attestationConveyancePreference());
+        extra.attestationConveyancePreference();
     DWORD winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_ANY;
     switch (attestation) {
       case AttestationConveyancePreference::Direct:
         winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT;
         break;
       case AttestationConveyancePreference::Indirect:
         winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_INDIRECT;
         break;
@@ -384,18 +379,17 @@ void WinWebAuthnManager::Register(
         pWebAuthNCredentialAttestation->cbAttestationObject);
 
     nsTArray<uint8_t> credentialId;
     credentialId.AppendElements(pWebAuthNCredentialAttestation->pbCredentialId,
                                 pWebAuthNCredentialAttestation->cbCredentialId);
 
     nsTArray<uint8_t> authenticatorData;
 
-    if (aInfo.Extra().type() == WebAuthnMaybeMakeCredentialExtraInfo::
-                                    TWebAuthnMakeCredentialExtraInfo) {
+    if (aInfo.Extra().isSome()) {
       authenticatorData.AppendElements(
           pWebAuthNCredentialAttestation->pbAuthenticatorData,
           pWebAuthNCredentialAttestation->cbAuthenticatorData);
     } else {
       PWEBAUTHN_COMMON_ATTESTATION attestation =
           reinterpret_cast<PWEBAUTHN_COMMON_ATTESTATION>(
               pWebAuthNCredentialAttestation->pvAttestationDecode);
 
@@ -487,36 +481,34 @@ void WinWebAuthnManager::Sign(PWebAuthnT
   BOOL* pbU2fAppIdUsed = nullptr;
   PCWSTR winAppIdentifier = nullptr;
 
   // Client Data
   WEBAUTHN_CLIENT_DATA WebAuthNClientData = {
       WEBAUTHN_CLIENT_DATA_CURRENT_VERSION, aInfo.ClientDataJSON().Length(),
       (BYTE*)(aInfo.ClientDataJSON().get()), WEBAUTHN_HASH_ALGORITHM_SHA_256};
 
-  if (aInfo.Extra().type() ==
-      WebAuthnMaybeGetAssertionExtraInfo::TWebAuthnGetAssertionExtraInfo) {
-    const auto& extra = aInfo.Extra().get_WebAuthnGetAssertionExtraInfo();
+  if (aInfo.Extra().isSome()) {
+    const auto& extra = aInfo.Extra().ref();
 
     for (const WebAuthnExtension& ext : extra.Extensions()) {
       if (ext.type() == WebAuthnExtension::TWebAuthnExtensionAppId) {
         winAppIdentifier =
             ext.get_WebAuthnExtensionAppId().appIdentifier().get();
         pbU2fAppIdUsed = &bU2fAppIdUsed;
         break;
       }
     }
 
     // RPID
     rpID = aInfo.RpId().get();
 
     // User Verification Requirement
     UserVerificationRequirement userVerificationReq =
-        static_cast<UserVerificationRequirement>(
-            extra.userVerificationRequirement());
+        extra.userVerificationRequirement();
 
     switch (userVerificationReq) {
       case UserVerificationRequirement::Required:
         winUserVerificationReq =
             WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED;
         break;
       case UserVerificationRequirement::Preferred:
         winUserVerificationReq =
@@ -607,18 +599,17 @@ void WinWebAuthnManager::Sign(PWebAuthnT
   HRESULT hr =
       gWinWebauthnGetAssertion(hWnd, rpID, &WebAuthNClientData,
                                &WebAuthNAssertionOptions, &pWebAuthNAssertion);
 
   mCancellationIds.erase(aTransactionId);
 
   if (hr == S_OK) {
     nsTArray<uint8_t> signature;
-    if (aInfo.Extra().type() ==
-        WebAuthnMaybeGetAssertionExtraInfo::TWebAuthnGetAssertionExtraInfo) {
+    if (aInfo.Extra().isSome()) {
       signature.AppendElements(pWebAuthNAssertion->pbSignature,
                                pWebAuthNAssertion->cbSignature);
     } else {
       // AuthenticatorData Length check.
       // First 32 bytes: RPID Hash
       // Next 1 byte: Flags
       // Next 4 bytes: Counter
       if (pWebAuthNAssertion->cbAuthenticatorData < 32 + 1 + 4) {
--- a/dom/webidl/BaseAudioContext.webidl
+++ b/dom/webidl/BaseAudioContext.webidl
@@ -5,17 +5,19 @@
  *
  * The origin of this IDL file is
  * https://webaudio.github.io/web-audio-api/#idl-def-BaseAudioContext
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback DecodeSuccessCallback = void (AudioBuffer decodedData);
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback DecodeErrorCallback = void (DOMException error);
 
 enum AudioContextState {
     "suspended",
     "running",
     "closed"
 };
 
--- a/dom/webidl/Console.webidl
+++ b/dom/webidl/Console.webidl
@@ -184,16 +184,17 @@ interface ConsoleInstance {
 
   void _exception(any... data);
   void timeStamp(optional any data);
 
   void profile(any... data);
   void profileEnd(any... data);
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback ConsoleInstanceDumpCallback = void (DOMString message);
 
 enum ConsoleLogLevel {
   "All", "Debug", "Log", "Info", "Clear", "Trace", "TimeLog", "TimeEnd", "Time",
   "Group", "GroupEnd", "Profile", "ProfileEnd", "Dir", "Dirxml", "Warn", "Error",
   "Off"
 };
 
--- a/dom/webidl/CustomElementRegistry.webidl
+++ b/dom/webidl/CustomElementRegistry.webidl
@@ -14,9 +14,10 @@ interface CustomElementRegistry {
   Promise<void> whenDefined(DOMString name);
   [CEReactions] void upgrade(Node root);
 };
 
 dictionary ElementDefinitionOptions {
   DOMString extends;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback CustomElementCreationCallback = void (DOMString name);
--- a/dom/webidl/DataTransferItem.webidl
+++ b/dom/webidl/DataTransferItem.webidl
@@ -12,16 +12,17 @@ interface DataTransferItem {
   readonly attribute DOMString kind;
   readonly attribute DOMString type;
   [Throws, NeedsSubjectPrincipal]
   void getAsString(FunctionStringCallback? _callback);
   [Throws, NeedsSubjectPrincipal]
   File? getAsFile();
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback FunctionStringCallback = void (DOMString data);
 
 // https://wicg.github.io/entries-api/#idl-index
 partial interface DataTransferItem {
   [Pref="dom.webkitBlink.filesystem.enabled", BinaryName="getAsEntry", Throws,
    NeedsSubjectPrincipal]
   FileSystemEntry? webkitGetAsEntry();
 };
--- a/dom/webidl/EventHandler.webidl
+++ b/dom/webidl/EventHandler.webidl
@@ -5,25 +5,25 @@
  *
  * The origin of this IDL file is
  * http://www.whatwg.org/specs/web-apps/current-work/#eventhandler
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  * Opera Software ASA. You are granted a license to use, reproduce
  * and create derivative works of this document.
  */
-[TreatNonObjectAsNull]
+[TreatNonObjectAsNull, MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback EventHandlerNonNull = any (Event event);
 typedef EventHandlerNonNull? EventHandler;
 
-[TreatNonObjectAsNull]
+[TreatNonObjectAsNull, MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback OnBeforeUnloadEventHandlerNonNull = DOMString? (Event event);
 typedef OnBeforeUnloadEventHandlerNonNull? OnBeforeUnloadEventHandler;
 
-[TreatNonObjectAsNull]
+[TreatNonObjectAsNull, MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback OnErrorEventHandlerNonNull = any ((Event or DOMString) event, optional DOMString source, optional unsigned long lineno, optional unsigned long column, optional any error);
 typedef OnErrorEventHandlerNonNull? OnErrorEventHandler;
 
 [NoInterfaceObject]
 interface GlobalEventHandlers {
            attribute EventHandler onabort;
            attribute EventHandler onblur;
 // We think the spec is wrong here. See OnErrorEventHandlerForNodes/Window
--- a/dom/webidl/FileSystem.webidl
+++ b/dom/webidl/FileSystem.webidl
@@ -6,16 +6,18 @@
  * https://wicg.github.io/entries-api/#idl-index
  */
 
 dictionary FileSystemFlags {
     boolean create = false;
     boolean exclusive = false;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback FileSystemEntryCallback = void (FileSystemEntry entry);
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback ErrorCallback = void (DOMException err);
 
 interface FileSystem {
     readonly    attribute USVString name;
     readonly    attribute FileSystemDirectoryEntry root;
 };
--- a/dom/webidl/FileSystemDirectoryReader.webidl
+++ b/dom/webidl/FileSystemDirectoryReader.webidl
@@ -1,16 +1,17 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/.
  *
  * https://wicg.github.io/entries-api/#idl-index
  */
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback FileSystemEntriesCallback = void (sequence<FileSystemEntry> entries);
 
 interface FileSystemDirectoryReader {
 
     // readEntries can be called just once. The second time it returns no data.
 
     [Throws]
     void readEntries(FileSystemEntriesCallback successCallback,
--- a/dom/webidl/FileSystemFileEntry.webidl
+++ b/dom/webidl/FileSystemFileEntry.webidl
@@ -1,15 +1,16 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/.
  *
  * https://wicg.github.io/entries-api/#idl-index
  */
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback FileCallback = void (File file);
 
 interface FileSystemFileEntry : FileSystemEntry {
     [BinaryName="GetFile"]
     void file (FileCallback successCallback,
                optional ErrorCallback errorCallback);
 };
--- a/dom/webidl/FontFaceSet.webidl
+++ b/dom/webidl/FontFaceSet.webidl
@@ -18,16 +18,17 @@ dictionary FontFaceSetIteratorResult
 };
 
 // To implement FontFaceSet's iterator until we can use setlike.
 [NoInterfaceObject]
 interface FontFaceSetIterator {
   [Throws] FontFaceSetIteratorResult next();
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback FontFaceSetForEachCallback = void (FontFace value, FontFace key, FontFaceSet set);
 
 enum FontFaceSetLoadStatus { "loading", "loaded" };
 
 // Bug 1072762 is for the FontFaceSet constructor.
 // [Constructor(sequence<FontFace> initialFaces)]
 [Pref="layout.css.font-loading-api.enabled"]
 interface FontFaceSet : EventTarget {
--- a/dom/webidl/Function.webidl
+++ b/dom/webidl/Function.webidl
@@ -5,12 +5,12 @@
  *
  * The origin of this IDL file is
  * http://www.whatwg.org/specs/web-apps/current-work/#functiocn
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  * Opera Software ASA. You are granted a license to use, reproduce
  * and create derivative works of this document.
  */
-
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback Function = any(any... arguments);
 
 callback VoidFunction = void ();
--- a/dom/webidl/HTMLCanvasElement.webidl
+++ b/dom/webidl/HTMLCanvasElement.webidl
@@ -61,11 +61,13 @@ interface MozCanvasPrintState
 {
   // A canvas rendering context.
   readonly attribute nsISupports context;
 
   // To be called when rendering to the context is done.
   void done();
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback PrintCallback = void(MozCanvasPrintState ctx);
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback BlobCallback = void(Blob? blob);
--- a/dom/webidl/IntersectionObserver.webidl
+++ b/dom/webidl/IntersectionObserver.webidl
@@ -39,16 +39,17 @@ interface IntersectionObserver {
   void unobserve(Element target);
   void disconnect();
   sequence<IntersectionObserverEntry> takeRecords();
 
   [ChromeOnly]
   readonly attribute IntersectionCallback intersectionCallback;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback IntersectionCallback =
   void (sequence<IntersectionObserverEntry> entries, IntersectionObserver observer);
 
 dictionary IntersectionObserverEntryInit {
   required DOMHighResTimeStamp time;
   required DOMRectInit rootBounds;
   required DOMRectInit boundingClientRect;
   required DOMRectInit intersectionRect;
--- a/dom/webidl/L10nUtils.webidl
+++ b/dom/webidl/L10nUtils.webidl
@@ -29,10 +29,11 @@ dictionary AttributeNameValue {
   required DOMString value;
 };
 
 dictionary L10nValue {
   DOMString? value = null;
   sequence<AttributeNameValue>? attributes = null;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback L10nCallback =
   Promise<sequence<L10nValue>> (sequence<L10nElement> l10nElements);
--- a/dom/webidl/MutationObserver.webidl
+++ b/dom/webidl/MutationObserver.webidl
@@ -47,16 +47,17 @@ interface MutationObserver {
   [ChromeOnly, Throws]
   sequence<MutationObservingInfo?> getObservingInfo();
   [ChromeOnly]
   readonly attribute MutationCallback mutationCallback;
   [ChromeOnly]
   attribute boolean mergeAttributeRecords;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback MutationCallback = void (sequence<MutationRecord> mutations, MutationObserver observer);
 
 dictionary MutationObserverInit {
   boolean childList = false;
   boolean attributes;
   boolean characterData;
   boolean subtree = false;
   boolean attributeOldValue;
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -229,33 +229,36 @@ partial interface Navigator {
 };
 
 // http://webaudio.github.io/web-midi-api/#requestmidiaccess
 partial interface Navigator {
   [Throws, Pref="dom.webmidi.enabled"]
   Promise<MIDIAccess> requestMIDIAccess(optional MIDIOptions options);
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback NavigatorUserMediaSuccessCallback = void (MediaStream stream);
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback NavigatorUserMediaErrorCallback = void (MediaStreamError error);
 
 partial interface Navigator {
   [Throws, Func="Navigator::HasUserMediaSupport"]
   readonly attribute MediaDevices mediaDevices;
 
   // Deprecated. Use mediaDevices.getUserMedia instead.
   [Deprecated="NavigatorGetUserMedia", Throws,
    Func="Navigator::HasUserMediaSupport",
    NeedsCallerType]
   void mozGetUserMedia(MediaStreamConstraints constraints,
                        NavigatorUserMediaSuccessCallback successCallback,
                        NavigatorUserMediaErrorCallback errorCallback);
 };
 
 // nsINavigatorUserMedia
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback MozGetUserMediaDevicesSuccessCallback = void (nsIVariant? devices);
 partial interface Navigator {
   [Throws, ChromeOnly]
   void mozGetUserMediaDevices(MediaStreamConstraints constraints,
                               MozGetUserMediaDevicesSuccessCallback onsuccess,
                               NavigatorUserMediaErrorCallback onerror,
                               // The originating innerWindowID is needed to
                               // avoid calling the callbacks if the window has
--- a/dom/webidl/Notification.webidl
+++ b/dom/webidl/Notification.webidl
@@ -83,15 +83,16 @@ dictionary NotificationBehavior {
 };
 
 enum NotificationPermission {
   "default",
   "denied",
   "granted"
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback NotificationPermissionCallback = void (NotificationPermission permission);
 
 enum NotificationDirection {
   "auto",
   "ltr",
   "rtl"
 };
--- a/dom/webidl/PerformanceObserver.webidl
+++ b/dom/webidl/PerformanceObserver.webidl
@@ -7,16 +7,17 @@
  * https://w3c.github.io/performance-timeline/#the-performanceobserver-interface
  */
 
 dictionary PerformanceObserverInit {
   required sequence<DOMString> entryTypes;
   boolean buffered = false;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback PerformanceObserverCallback = void (PerformanceObserverEntryList entries,
                                              PerformanceObserver observer);
 
 [Func="mozilla::dom::DOMPrefs::dom_enable_performance_observer",
  Constructor(PerformanceObserverCallback callback),
  Exposed=(Window,Worker)]
 interface PerformanceObserver {
     void observe(PerformanceObserverInit options);
--- a/dom/webidl/Promise.webidl
+++ b/dom/webidl/Promise.webidl
@@ -2,18 +2,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * This IDL file contains utilities to help connect JS promises to our
  * Web IDL infrastructure.
  */
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback PromiseJobCallback = void();
 
-[TreatNonCallableAsNull]
+[TreatNonCallableAsNull, MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback AnyCallback = any (any value);
 
 // Hack to allow us to have JS owning and properly tracing/CCing/etc a
 // PromiseNativeHandler.
 [NoInterfaceObject, Exposed=(Window,Worker)]
 interface PromiseNativeHandler {
 };
--- a/dom/webidl/RTCIdentityProvider.webidl
+++ b/dom/webidl/RTCIdentityProvider.webidl
@@ -30,20 +30,22 @@ interface RTCIdentityProviderRegistrar {
   validateAssertion(DOMString assertion, DOMString origin);
 };
 
 dictionary RTCIdentityProvider {
   required GenerateAssertionCallback generateAssertion;
   required ValidateAssertionCallback validateAssertion;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback GenerateAssertionCallback =
   Promise<RTCIdentityAssertionResult>
     (DOMString contents, DOMString origin,
      RTCIdentityProviderOptions options);
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback ValidateAssertionCallback =
   Promise<RTCIdentityValidationResult> (DOMString assertion, DOMString origin);
 
 dictionary RTCIdentityAssertionResult {
   required RTCIdentityProviderDetails idp;
   required DOMString assertion;
 };
 
--- a/dom/webidl/Reporting.webidl
+++ b/dom/webidl/Reporting.webidl
@@ -21,16 +21,17 @@ interface Report {
 [Constructor(ReportingObserverCallback callback, optional ReportingObserverOptions options),
  Func="mozilla::dom::DOMPrefs::dom_reporting_enabled"]
 interface ReportingObserver {
   void observe();
   void disconnect();
   ReportList takeRecords();
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback ReportingObserverCallback = void (sequence<Report> reports, ReportingObserver observer);
 
 dictionary ReportingObserverOptions {
   sequence<DOMString> types;
   boolean buffered = false;
 };
 
 typedef sequence<Report> ReportList;
--- a/dom/webidl/U2F.webidl
+++ b/dom/webidl/U2F.webidl
@@ -59,17 +59,19 @@ dictionary SignResponse {
     DOMString signatureData;
     DOMString clientData;
 
     // From Error
     ErrorCode? errorCode;
     DOMString? errorMessage;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback U2FRegisterCallback = void(RegisterResponse response);
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback U2FSignCallback = void(SignResponse response);
 
 [SecureContext, Pref="security.webauth.u2f"]
 interface U2F {
   // These enumerations are defined in the FIDO U2F Javascript API under the
   // interface "ErrorCode" as constant integers, and also in the U2F.cpp file.
   // Any changes to these must occur in both locations.
   const unsigned short OK = 0;
--- a/dom/webidl/WebComponents.webidl
+++ b/dom/webidl/WebComponents.webidl
@@ -5,24 +5,29 @@
  *
  * The origin of this IDL file is
  * http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback LifecycleConnectedCallback = void();
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback LifecycleDisconnectedCallback = void();
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback LifecycleAdoptedCallback = void(Document? oldDocument,
                                          Document? newDocment);
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback LifecycleAttributeChangedCallback = void(DOMString attrName,
                                                   DOMString? oldValue,
                                                   DOMString? newValue,
                                                   DOMString? namespaceURI);
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback LifecycleGetCustomInterfaceCallback = object?(any iid);
 
 dictionary LifecycleCallbacks {
   LifecycleConnectedCallback connectedCallback;
   LifecycleDisconnectedCallback disconnectedCallback;
   LifecycleAdoptedCallback adoptedCallback;
   LifecycleAttributeChangedCallback attributeChangedCallback;
   [ChromeOnly] LifecycleGetCustomInterfaceCallback getCustomInterfaceCallback;
--- a/dom/webidl/WebrtcGlobalInformation.webidl
+++ b/dom/webidl/WebrtcGlobalInformation.webidl
@@ -3,17 +3,19 @@
  * 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/.
  */
 
 dictionary WebrtcGlobalStatisticsReport {
   sequence<RTCStatsReportInternal> reports;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback WebrtcGlobalStatisticsCallback = void (WebrtcGlobalStatisticsReport reports);
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback WebrtcGlobalLoggingCallback = void (sequence<DOMString> logMessages);
 
 [ChromeOnly]
 interface WebrtcGlobalInformation {
 
   [Throws]
   static void getAllStats(WebrtcGlobalStatisticsCallback callback,
                           optional DOMString pcIdFilter);
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -206,16 +206,17 @@ partial interface Window {
   [Throws, NeedsCallerType] attribute any outerHeight;
 };
 
 // https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/RequestAnimationFrame/Overview.html
 partial interface Window {
   [Throws] long requestAnimationFrame(FrameRequestCallback callback);
   [Throws] void cancelAnimationFrame(long handle);
 };
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback FrameRequestCallback = void (DOMHighResTimeStamp time);
 
 // https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html
 partial interface Window {
   [Replaceable, Pure, StoreInSlot] readonly attribute Performance? performance;
 };
 
 // https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html
@@ -391,16 +392,17 @@ partial interface Window {
 #ifdef HAVE_SIDEBAR
 // Mozilla extension
 partial interface Window {
   [Replaceable, Throws, UseCounter, Pref="dom.sidebar.enabled"]
   readonly attribute (External or WindowProxy) sidebar;
 };
 #endif
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback PromiseDocumentFlushedCallback = any ();
 
 // Mozilla extensions for Chrome windows.
 partial interface Window {
   // The STATE_* constants need to match the corresponding enum in nsGlobalWindow.cpp.
   [Func="nsGlobalWindowInner::IsPrivilegedChromeWindow"]
   const unsigned short STATE_MAXIMIZED = 1;
   [Func="nsGlobalWindowInner::IsPrivilegedChromeWindow"]
@@ -550,16 +552,17 @@ partial interface Window {
   [Func="nsGlobalWindowInner::IsRequestIdleCallbackEnabled"]
   void          cancelIdleCallback(unsigned long handle);
 };
 
 dictionary IdleRequestOptions {
   unsigned long timeout;
 };
 
+[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
 callback IdleRequestCallback = void (IdleDeadline deadline);
 
 partial interface Window {
   /**
    * Returns a list of locales that the internationalization components
    * should be localized to.
    *
    * The function name refers to Regional Preferences which can be either
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -1883,16 +1883,25 @@ XMLHttpRequestMainThread::OnStartRequest
 
   // Set up responseXML
   // Note: Main Fetch step 18 requires to ignore body for head/connect methods.
   bool parseBody = (mResponseType == XMLHttpRequestResponseType::_empty ||
                     mResponseType == XMLHttpRequestResponseType::Document) &&
                    !(mRequestMethod.EqualsLiteral("HEAD") ||
                      mRequestMethod.EqualsLiteral("CONNECT"));
 
+  if (parseBody) {
+    // Do not try to parse documents if content-length = 0
+    int64_t contentLength;
+    if (NS_SUCCEEDED(mChannel->GetContentLength(&contentLength)) &&
+        contentLength == 0) {
+      parseBody = false;
+    }
+  }
+
   mIsHtml = false;
   mWarnAboutSyncHtml = false;
   if (parseBody && NS_SUCCEEDED(status)) {
     // We can gain a huge performance win by not even trying to
     // parse non-XML data. This also protects us from the situation
     // where we have an XML document and sink, but HTML (or other)
     // parser, which can produce unreliable results.
     nsAutoCString type;
--- a/gfx/webrender_bindings/Cargo.toml
+++ b/gfx/webrender_bindings/Cargo.toml
@@ -4,19 +4,19 @@ version = "0.1.0"
 authors = ["The Mozilla Project Developers"]
 license = "MPL-2.0"
 
 [dependencies]
 rayon = "1"
 thread_profiler = "0.1.1"
 euclid = { version = "0.19.4", features = ["serde"] }
 app_units = "0.7"
-gleam = "0.6.9"
+gleam = "0.6.14"
 log = "0.4"
-nsstring = { path = "../../xpcom/rust/nsstring" } 
+nsstring = { path = "../../xpcom/rust/nsstring" }
 bincode = "1.0"
 uuid = { version = "0.6", features = ["v4"] }
 fxhash = "0.2.1"
 
 [dependencies.webrender]
 path = "../wr/webrender"
 version = "0.60.0"
 default-features = false
--- a/gfx/webrender_bindings/RenderCompositor.cpp
+++ b/gfx/webrender_bindings/RenderCompositor.cpp
@@ -11,33 +11,33 @@
 #include "mozilla/layers/SyncObject.h"
 #include "mozilla/webrender/RenderCompositorOGL.h"
 #include "mozilla/widget/CompositorWidget.h"
 
 #ifdef XP_WIN
 #  include "mozilla/webrender/RenderCompositorANGLE.h"
 #endif
 
-#ifdef MOZ_WAYLAND
+#if defined(MOZ_WAYLAND) || defined(MOZ_WIDGET_ANDROID)
 #  include "mozilla/webrender/RenderCompositorEGL.h"
 #endif
 
 namespace mozilla {
 namespace wr {
 
 /* static */
 UniquePtr<RenderCompositor> RenderCompositor::Create(
     RefPtr<widget::CompositorWidget>&& aWidget) {
 #ifdef XP_WIN
   if (gfx::gfxVars::UseWebRenderANGLE()) {
     return RenderCompositorANGLE::Create(std::move(aWidget));
   }
 #endif
 
-#ifdef MOZ_WAYLAND
+#if defined(MOZ_WAYLAND) || defined(MOZ_WIDGET_ANDROID)
   UniquePtr<RenderCompositor> eglCompositor =
       RenderCompositorEGL::Create(aWidget);
   if (eglCompositor) {
     return eglCompositor;
   }
 #endif
 
   return RenderCompositorOGL::Create(std::move(aWidget));
--- a/gfx/webrender_bindings/RenderCompositorANGLE.cpp
+++ b/gfx/webrender_bindings/RenderCompositorANGLE.cpp
@@ -27,16 +27,21 @@
 #include <dxgi1_2.h>
 
 namespace mozilla {
 namespace wr {
 
 /* static */
 UniquePtr<RenderCompositor> RenderCompositorANGLE::Create(
     RefPtr<widget::CompositorWidget>&& aWidget) {
+  if (!RenderThread::Get()->SharedGL()) {
+    gfxCriticalNote << "Failed to get shared GL context";
+    return nullptr;
+  }
+
   UniquePtr<RenderCompositorANGLE> compositor =
       MakeUnique<RenderCompositorANGLE>(std::move(aWidget));
   if (!compositor->Initialize()) {
     return nullptr;
   }
   return compositor;
 }
 
--- a/gfx/webrender_bindings/RenderCompositorEGL.cpp
+++ b/gfx/webrender_bindings/RenderCompositorEGL.cpp
@@ -5,103 +5,145 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "RenderCompositorEGL.h"
 
 #include "GLContext.h"
 #include "GLContextEGL.h"
 #include "GLContextProvider.h"
 #include "GLLibraryEGL.h"
+#include "mozilla/webrender/RenderThread.h"
 #include "mozilla/widget/CompositorWidget.h"
-#include "mozilla/widget/GtkCompositorWidget.h"
 
-#include <gdk/gdk.h>
-#include <gdk/gdkx.h>
+#ifdef MOZ_WAYLAND
+#  include "mozilla/widget/GtkCompositorWidget.h"
+#  include <gdk/gdk.h>
+#  include <gdk/gdkx.h>
+#endif
 
 namespace mozilla {
 namespace wr {
 
 /* static */
 UniquePtr<RenderCompositor> RenderCompositorEGL::Create(
     RefPtr<widget::CompositorWidget> aWidget) {
+#ifdef MOZ_WIDGET_ANDROID
+  if (!RenderThread::Get()->SharedGL()) {
+    gfxCriticalNote << "Failed to get shared GL context";
+    return nullptr;
+  }
+  return MakeUnique<RenderCompositorEGL>(aWidget);
+#elif defined(MOZ_WAYLAND)
+  // Disabled SharedGL() usage on wayland. Its usage caused flicker when
+  // multiple windows were opened. See Bug 1535893.
   if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
     return nullptr;
   }
-
   RefPtr<gl::GLContext> gl;
   gl = CreateGLContext();
   if (!gl) {
     return nullptr;
   }
   return MakeUnique<RenderCompositorEGL>(gl, aWidget);
+#endif
 }
 
+#ifdef MOZ_WAYLAND
 /* static */ already_AddRefed<gl::GLContext>
 RenderCompositorEGL::CreateGLContext() {
   // Create GLContext with dummy EGLSurface.
   RefPtr<gl::GLContext> gl =
       gl::GLContextProviderEGL::CreateForCompositorWidget(
           nullptr, /* aWebRender */ true, /* aForceAccelerated */ true);
   if (!gl || !gl->MakeCurrent()) {
     gfxCriticalNote << "Failed GL context creation for WebRender: "
                     << gfx::hexa(gl.get());
     return nullptr;
   }
 
   return gl.forget();
 }
+#endif
 
 EGLSurface RenderCompositorEGL::CreateEGLSurface() {
   EGLSurface surface = EGL_NO_SURFACE;
   surface = gl::GLContextEGL::CreateEGLSurfaceForCompositorWidget(
       mWidget, gl::GLContextEGL::Cast(gl())->mConfig);
   if (surface == EGL_NO_SURFACE) {
     gfxCriticalNote << "Failed to create EGLSurface";
   }
   return surface;
 }
 
+#ifdef MOZ_WIDGET_ANDROID
+RenderCompositorEGL::RenderCompositorEGL(
+    RefPtr<widget::CompositorWidget> aWidget)
+    : RenderCompositor(std::move(aWidget)), mEGLSurface(EGL_NO_SURFACE) {}
+#elif defined(MOZ_WAYLAND)
 RenderCompositorEGL::RenderCompositorEGL(
     RefPtr<gl::GLContext> aGL, RefPtr<widget::CompositorWidget> aWidget)
     : RenderCompositor(std::move(aWidget)),
       mGL(aGL),
       mEGLSurface(EGL_NO_SURFACE) {
   MOZ_ASSERT(mGL);
 }
+#endif
 
 RenderCompositorEGL::~RenderCompositorEGL() { DestroyEGLSurface(); }
 
 bool RenderCompositorEGL::BeginFrame() {
+#ifdef MOZ_WAYLAND
   if (mWidget->AsX11() &&
       mWidget->AsX11()->WaylandRequestsUpdatingEGLSurface()) {
     // Destroy EGLSurface if it exists.
     DestroyEGLSurface();
     mEGLSurface = CreateEGLSurface();
     gl::GLContextEGL::Cast(gl())->SetEGLSurfaceOverride(mEGLSurface);
   }
-
-  if (!mGL->MakeCurrent()) {
+#endif
+  if (!gl()->MakeCurrent()) {
     gfxCriticalNote << "Failed to make render context current, can't draw.";
     return false;
   }
 
   return true;
 }
 
 void RenderCompositorEGL::EndFrame() {
   if (mEGLSurface != EGL_NO_SURFACE) {
-    mGL->SwapBuffers();
+    gl()->SwapBuffers();
   }
 }
 
 void RenderCompositorEGL::WaitForGPU() {}
 
-void RenderCompositorEGL::Pause() {}
+void RenderCompositorEGL::Pause() {
+#ifdef MOZ_WIDGET_ANDROID
+  DestroyEGLSurface();
+#endif
+}
 
-bool RenderCompositorEGL::Resume() { return true; }
+bool RenderCompositorEGL::Resume() {
+#ifdef MOZ_WIDGET_ANDROID
+  // Destroy EGLSurface if it exists.
+  DestroyEGLSurface();
+  mEGLSurface = CreateEGLSurface();
+  gl::GLContextEGL::Cast(gl())->SetEGLSurfaceOverride(mEGLSurface);
+#endif
+  return true;
+}
+
+gl::GLContext* RenderCompositorEGL::gl() const {
+#ifdef MOZ_WIDGET_ANDROID
+  return RenderThread::Get()->SharedGL();
+#elif defined(MOZ_WAYLAND)
+  MOZ_ASSERT(mGL);
+  return mGL;
+#endif
+}
 
 bool RenderCompositorEGL::MakeCurrent() {
   gl::GLContextEGL::Cast(gl())->SetEGLSurfaceOverride(mEGLSurface);
   return gl()->MakeCurrent();
 }
 
 void RenderCompositorEGL::DestroyEGLSurface() {
   auto* egl = gl::GLLibraryEGL::Get();
--- a/gfx/webrender_bindings/RenderCompositorEGL.h
+++ b/gfx/webrender_bindings/RenderCompositorEGL.h
@@ -14,40 +14,48 @@ namespace mozilla {
 
 namespace wr {
 
 class RenderCompositorEGL : public RenderCompositor {
  public:
   static UniquePtr<RenderCompositor> Create(
       RefPtr<widget::CompositorWidget> aWidget);
 
+#ifdef MOZ_WIDGET_ANDROID
+  explicit RenderCompositorEGL(RefPtr<widget::CompositorWidget> aWidget);
+#elif defined(MOZ_WAYLAND)
   RenderCompositorEGL(RefPtr<gl::GLContext> aGL,
                       RefPtr<widget::CompositorWidget> aWidget);
+#endif
   virtual ~RenderCompositorEGL();
 
   bool BeginFrame() override;
   void EndFrame() override;
   void WaitForGPU() override;
   void Pause() override;
   bool Resume() override;
 
-  gl::GLContext* gl() const override { return mGL; }
+  gl::GLContext* gl() const override;
 
   bool MakeCurrent() override;
 
   bool UseANGLE() const override { return false; }
 
   LayoutDeviceIntSize GetBufferSize() override;
 
  protected:
+#ifdef MOZ_WAYLAND
   static already_AddRefed<gl::GLContext> CreateGLContext();
+#endif
   EGLSurface CreateEGLSurface();
 
   void DestroyEGLSurface();
 
+#ifdef MOZ_WAYLAND
   const RefPtr<gl::GLContext> mGL;
+#endif
   EGLSurface mEGLSurface;
 };
 
 }  // namespace wr
 }  // namespace mozilla
 
 #endif  // MOZILLA_GFX_RENDERCOMPOSITOR_EGL_H
--- a/gfx/webrender_bindings/RenderThread.cpp
+++ b/gfx/webrender_bindings/RenderThread.cpp
@@ -21,16 +21,20 @@
 #include "mozilla/webrender/RenderTextureHost.h"
 #include "mozilla/widget/CompositorWidget.h"
 
 #ifdef XP_WIN
 #  include "GLLibraryEGL.h"
 #  include "mozilla/widget/WinCompositorWindowThread.h"
 #endif
 
+#ifdef MOZ_WIDGET_ANDROID
+#  include "GLLibraryEGL.h"
+#endif
+
 using namespace mozilla;
 
 static already_AddRefed<gl::GLContext> CreateGLContext();
 
 MOZ_DEFINE_MALLOC_SIZE_OF(WebRenderRendererMallocSizeOf)
 
 namespace mozilla {
 namespace wr {
@@ -797,22 +801,47 @@ static already_AddRefed<gl::GLContext> C
                     << gfx::hexa(gl.get());
     return nullptr;
   }
 
   return gl.forget();
 }
 #endif
 
+#ifdef MOZ_WIDGET_ANDROID
+static already_AddRefed<gl::GLContext> CreateGLContextEGL() {
+  nsCString discardFailureId;
+  if (!gl::GLLibraryEGL::EnsureInitialized(/* forceAccel */ true,
+                                           &discardFailureId)) {
+    gfxCriticalNote << "Failed to load EGL library: " << discardFailureId.get();
+    return nullptr;
+  }
+  // Create GLContext with dummy EGLSurface.
+  RefPtr<gl::GLContext> gl =
+      gl::GLContextProviderEGL::CreateForCompositorWidget(
+          nullptr, /* aWebRender */ true, /* aForceAccelerated */ true);
+  if (!gl || !gl->MakeCurrent()) {
+    gfxCriticalNote << "Failed GL context creation for WebRender: "
+                    << gfx::hexa(gl.get());
+    return nullptr;
+  }
+  return gl.forget();
+}
+#endif
+
 static already_AddRefed<gl::GLContext> CreateGLContext() {
 #ifdef XP_WIN
   if (gfx::gfxVars::UseWebRenderANGLE()) {
     return CreateGLContextANGLE();
   }
 #endif
+
+#ifdef MOZ_WIDGET_ANDROID
+  return CreateGLContextEGL();
+#endif
   // We currently only support a shared GLContext
   // with ANGLE.
   return nullptr;
 }
 
 extern "C" {
 
 static void HandleFrame(mozilla::wr::WrWindowId aWindowId, bool aRender) {
--- a/gfx/webrender_bindings/moz.build
+++ b/gfx/webrender_bindings/moz.build
@@ -43,19 +43,21 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'coco
     ]
     UNIFIED_SOURCES += [
         'RenderMacIOSurfaceTextureHostOGL.cpp',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
     EXPORTS.mozilla.webrender += [
         'RenderAndroidSurfaceTextureHostOGL.h',
+        'RenderCompositorEGL.h',
     ]
     UNIFIED_SOURCES += [
         'RenderAndroidSurfaceTextureHostOGL.cpp',
+        'RenderCompositorEGL.cpp',
     ]
 
 if CONFIG['MOZ_ENABLE_D3D10_LAYER']:
     DEFINES['MOZ_ENABLE_D3D10_LAYER'] = True
     EXPORTS.mozilla.webrender += [
         'RenderCompositorANGLE.h',
         'RenderD3D11TextureHostOGL.h',
     ]
--- a/gfx/wr/Cargo.lock
+++ b/gfx/wr/Cargo.lock
@@ -138,17 +138,17 @@ name = "cfg-if"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "cgl"
 version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "gleam 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "clap"
 version = "2.31.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -365,17 +365,17 @@ dependencies = [
  "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "direct-composition"
 version = "0.1.0"
 dependencies = [
  "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "mozangle 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender 0.60.0",
  "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "winit 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "dlib"
@@ -564,17 +564,17 @@ source = "registry+https://github.com/ru
 dependencies = [
  "khronos_api 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "gleam"
-version = "0.6.12"
+version = "0.6.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "glutin"
 version = "0.17.0"
@@ -1635,17 +1635,17 @@ dependencies = [
  "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cstr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "mozangle 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "pathfinder_font_renderer 0.5.0 (git+https://github.com/pcwalton/pathfinder?branch=webrender)",
@@ -1671,17 +1671,17 @@ dependencies = [
 
 [[package]]
 name = "webrender-examples"
 version = "0.1.0"
 dependencies = [
  "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "glutin 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender 0.60.0",
  "winit 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "webrender_api"
@@ -1788,17 +1788,17 @@ dependencies = [
  "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "font-loader 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "glutin 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "mozangle 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "osmesa-src 0.1.1 (git+https://github.com/servo/osmesa-src)",
  "osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1935,17 +1935,17 @@ dependencies = [
 "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
 "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
 "checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
 "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
 "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592"
 "checksum gif 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff3414b424657317e708489d2857d9575f4403698428b040b609b9d1c1a84a2c"
 "checksum gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0ffaf173cf76c73a73e080366bf556b4776ece104b06961766ff11449f38604"
 "checksum gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a795170cbd85b5a7baa58d6d7525cae6a03e486859860c220f7ebbbdd379d0a"
-"checksum gleam 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "f1519ca611d230e1deadbedfb79044b921ac4a961ab8823fef10e37271e2c38e"
+"checksum gleam 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "17bca843dd3cf25db1bf415d55de9c0f0ae09dd7fa952ec3cef9930f90de1339"
 "checksum glutin 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a70c5fe78efbd5a3b243a804ea1032053c584510f8822819f94cfb29b2100317"
 "checksum half 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d5c5f71a723d10dfc58927cbed37c3071a50afc7f073d86fd7d3e5727db890f"
 "checksum httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f407128745b78abc95c0ffbe4e5d37427fdc0d45470710cfef8c44522a2e37"
 "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e"
 "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
 "checksum image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "52fb0666a1273dac46f9725aa4859bcd5595fc3554cf3495051b4de8db745e7d"
 "checksum inflate 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec18d981200fd14e65ee8e35fb60ed1ce55227a02407303f3a72517c6146dcc"
 "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
--- a/gfx/wr/webrender/Cargo.toml
+++ b/gfx/wr/webrender/Cargo.toml
@@ -24,17 +24,17 @@ webrender_build = { version = "0.0.1", p
 [dependencies]
 base64 = { optional = true, version = "0.10" }
 bincode = "1.0"
 bitflags = "1.0"
 byteorder = "1.0"
 cfg-if = "0.1.2"
 cstr = "0.1.2"
 fxhash = "0.2.1"
-gleam = "0.6.12"
+gleam = "0.6.14"
 image = { optional = true, version = "0.21" }
 lazy_static = "1"
 log = "0.4"
 malloc_size_of_derive = "0.1"
 num-traits = "0.2"
 plane-split = "0.13.7"
 png = { optional = true, version = "0.14" }
 rayon = "1"
--- a/ipc/ipdl/test/cxx/IPDLUnitTestUtils.h
+++ b/ipc/ipdl/test/cxx/IPDLUnitTestUtils.h
@@ -1,12 +1,14 @@
 
 #ifndef mozilla__ipdltest_IPDLUnitTestUtils
 #define mozilla__ipdltest_IPDLUnitTestUtils 1
 
+#include "ipc/IPCMessageUtils.h"
+
 namespace mozilla {
 namespace _ipdltest {
 
 struct Bad {};
 
 }  // namespace _ipdltest
 }  // namespace mozilla
 
copy from js/src/jsapi.h
copy to js/public/RealmOptions.h
--- a/js/src/jsapi.h
+++ b/js/public/RealmOptions.h
@@ -1,938 +1,45 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * 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/. */
 
-/* JavaScript API. */
-
-#ifndef jsapi_h
-#define jsapi_h
+/*
+ * Options specified when creating a realm to determine its behavior, immutable
+ * options determining the behavior of an existing realm, and mutable options on
+ * an existing realm that may be changed when desired.
+ */
 
-#include "mozilla/AlreadyAddRefed.h"
-#include "mozilla/FloatingPoint.h"
-#include "mozilla/MemoryReporting.h"
-#include "mozilla/Range.h"
-#include "mozilla/RangedPtr.h"
-#include "mozilla/RefPtr.h"
-#include "mozilla/Utf8.h"
-#include "mozilla/Variant.h"
-
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include "jspubtd.h"
+#ifndef js_RealmOptions_h
+#define js_RealmOptions_h
 
-#include "js/AllocPolicy.h"
-#include "js/CallArgs.h"
-#include "js/CharacterEncoding.h"
-#include "js/Class.h"
-#include "js/CompileOptions.h"
-#include "js/ErrorReport.h"
-#include "js/GCVector.h"
-#include "js/HashTable.h"
-#include "js/Id.h"
-#include "js/OffThreadScriptCompilation.h"
-#include "js/Principals.h"
-#include "js/PropertyDescriptor.h"
-#include "js/Realm.h"
-#include "js/RefCounted.h"
-#include "js/RootingAPI.h"
-#include "js/TracingAPI.h"
-#include "js/Transcoding.h"
-#include "js/UniquePtr.h"
-#include "js/Utility.h"
-#include "js/Value.h"
-#include "js/Vector.h"
+#include "mozilla/Assertions.h"  // MOZ_ASSERT
+
+#include "jstypes.h"  // JS_PUBLIC_API
 
-/************************************************************************/
+#include "js/Class.h"  // JSTraceOp
 
-struct JSFreeOp;
-struct JSFunctionSpec;
-struct JSPropertySpec;
+struct JSContext;
+class JSObject;
 
 namespace JS {
 
-template <typename UnitT>
-class SourceText;
-
-class TwoByteChars;
-
-/** AutoValueArray roots an internal fixed-size array of Values. */
-template <size_t N>
-class MOZ_RAII AutoValueArray : public AutoGCRooter {
-  const size_t length_;
-  Value elements_[N];
-
- public:
-  explicit AutoValueArray(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : AutoGCRooter(cx, AutoGCRooter::Tag::ValueArray), length_(N) {
-    /* Always initialize in case we GC before assignment. */
-    mozilla::PodArrayZero(elements_);
-    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-  }
-
-  unsigned length() const { return length_; }
-  const Value* begin() const { return elements_; }
-  Value* begin() { return elements_; }
-
-  HandleValue operator[](unsigned i) const {
-    MOZ_ASSERT(i < N);
-    return HandleValue::fromMarkedLocation(&elements_[i]);
-  }
-  MutableHandleValue operator[](unsigned i) {
-    MOZ_ASSERT(i < N);
-    return MutableHandleValue::fromMarkedLocation(&elements_[i]);
-  }
-
-  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
-using ValueVector = JS::GCVector<JS::Value>;
-using IdVector = JS::GCVector<jsid>;
-using ScriptVector = JS::GCVector<JSScript*>;
-using StringVector = JS::GCVector<JSString*>;
-
-/**
- * Custom rooting behavior for internal and external clients.
- */
-class MOZ_RAII JS_PUBLIC_API CustomAutoRooter : private AutoGCRooter {
- public:
-  template <typename CX>
-  explicit CustomAutoRooter(const CX& cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : AutoGCRooter(cx, AutoGCRooter::Tag::Custom) {
-    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-  }
-
-  friend void AutoGCRooter::trace(JSTracer* trc);
-
- protected:
-  virtual ~CustomAutoRooter() {}
-
-  /** Supplied by derived class to trace roots. */
-  virtual void trace(JSTracer* trc) = 0;
-
- private:
-  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
-/** A handle to an array of rooted values. */
-class HandleValueArray {
-  const size_t length_;
-  const Value* const elements_;
-
-  HandleValueArray(size_t len, const Value* elements)
-      : length_(len), elements_(elements) {}
-
- public:
-  explicit HandleValueArray(HandleValue value)
-      : length_(1), elements_(value.address()) {}
-
-  MOZ_IMPLICIT HandleValueArray(const AutoValueVector& values)
-      : length_(values.length()), elements_(values.begin()) {}
-
-  template <size_t N>
-  MOZ_IMPLICIT HandleValueArray(const AutoValueArray<N>& values)
-      : length_(N), elements_(values.begin()) {}
-
-  /** CallArgs must already be rooted somewhere up the stack. */
-  MOZ_IMPLICIT HandleValueArray(const JS::CallArgs& args)
-      : length_(args.length()), elements_(args.array()) {}
-
-  /** Use with care! Only call this if the data is guaranteed to be marked. */
-  static HandleValueArray fromMarkedLocation(size_t len,
-                                             const Value* elements) {
-    return HandleValueArray(len, elements);
-  }
-
-  static HandleValueArray subarray(const HandleValueArray& values,
-                                   size_t startIndex, size_t len) {
-    MOZ_ASSERT(startIndex + len <= values.length());
-    return HandleValueArray(len, values.begin() + startIndex);
-  }
-
-  static HandleValueArray empty() { return HandleValueArray(0, nullptr); }
-
-  size_t length() const { return length_; }
-  const Value* begin() const { return elements_; }
-
-  HandleValue operator[](size_t i) const {
-    MOZ_ASSERT(i < length_);
-    return HandleValue::fromMarkedLocation(&elements_[i]);
-  }
-};
-
-} /* namespace JS */
-
-/* Callbacks and their arguments. */
-
-/************************************************************************/
-
-typedef bool (*JSInterruptCallback)(JSContext* cx);
-
-/**
- * Callback used to ask the embedding for the cross compartment wrapper handler
- * that implements the desired prolicy for this kind of object in the
- * destination compartment. |obj| is the object to be wrapped. If |existing| is
- * non-nullptr, it will point to an existing wrapper object that should be
- * re-used if possible. |existing| is guaranteed to be a cross-compartment
- * wrapper with a lazily-defined prototype and the correct global. It is
- * guaranteed not to wrap a function.
- */
-typedef JSObject* (*JSWrapObjectCallback)(JSContext* cx,
-                                          JS::HandleObject existing,
-                                          JS::HandleObject obj);
-
-/**
- * Callback used by the wrap hook to ask the embedding to prepare an object
- * for wrapping in a context. This might include unwrapping other wrappers
- * or even finding a more suitable object for the new compartment.
- */
-typedef void (*JSPreWrapCallback)(JSContext* cx, JS::HandleObject scope,
-                                  JS::HandleObject obj,
-                                  JS::HandleObject objectPassedToWrap,
-                                  JS::MutableHandleObject retObj);
-
-struct JSWrapObjectCallbacks {
-  JSWrapObjectCallback wrap;
-  JSPreWrapCallback preWrap;
-};
-
-typedef void (*JSDestroyCompartmentCallback)(JSFreeOp* fop,
-                                             JS::Compartment* compartment);
-
-typedef size_t (*JSSizeOfIncludingThisCompartmentCallback)(
-    mozilla::MallocSizeOf mallocSizeOf, JS::Compartment* compartment);
-
-/**
- * Callback used by memory reporting to ask the embedder how much memory an
- * external string is keeping alive.  The embedder is expected to return a value
- * that corresponds to the size of the allocation that will be released by the
- * JSStringFinalizer passed to JS_NewExternalString for this string.
- *
- * Implementations of this callback MUST NOT do anything that can cause GC.
- */
-using JSExternalStringSizeofCallback =
-    size_t (*)(JSString* str, mozilla::MallocSizeOf mallocSizeOf);
+class Compartment;
+class Realm;
+class Zone;
 
-/**
- * Callback used to intercept JavaScript errors.
- */
-struct JSErrorInterceptor {
-  /**
-   * This method is called whenever an error has been raised from JS code.
-   *
-   * This method MUST be infallible.
-   */
-  virtual void interceptError(JSContext* cx, JS::HandleValue error) = 0;
-};
-
-/************************************************************************/
-
-static MOZ_ALWAYS_INLINE JS::Value JS_NumberValue(double d) {
-  int32_t i;
-  d = JS::CanonicalizeNaN(d);
-  if (mozilla::NumberIsInt32(d, &i)) {
-    return JS::Int32Value(i);
-  }
-  return JS::DoubleValue(d);
-}
-
-/************************************************************************/
-
-JS_PUBLIC_API bool JS_StringHasBeenPinned(JSContext* cx, JSString* str);
-
-/************************************************************************/
-
-/** Microseconds since the epoch, midnight, January 1, 1970 UTC. */
-extern JS_PUBLIC_API int64_t JS_Now(void);
-
-/** Don't want to export data, so provide accessors for non-inline Values. */
-extern JS_PUBLIC_API JS::Value JS_GetNaNValue(JSContext* cx);
-
-extern JS_PUBLIC_API JS::Value JS_GetNegativeInfinityValue(JSContext* cx);
-
-extern JS_PUBLIC_API JS::Value JS_GetPositiveInfinityValue(JSContext* cx);
-
-extern JS_PUBLIC_API JS::Value JS_GetEmptyStringValue(JSContext* cx);
-
-extern JS_PUBLIC_API JSString* JS_GetEmptyString(JSContext* cx);
-
-extern JS_PUBLIC_API bool JS_ValueToObject(JSContext* cx, JS::HandleValue v,
-                                           JS::MutableHandleObject objp);
-
-extern JS_PUBLIC_API JSFunction* JS_ValueToFunction(JSContext* cx,
-                                                    JS::HandleValue v);
-
-extern JS_PUBLIC_API JSFunction* JS_ValueToConstructor(JSContext* cx,
-                                                       JS::HandleValue v);
-
-extern JS_PUBLIC_API JSString* JS_ValueToSource(JSContext* cx,
-                                                JS::Handle<JS::Value> v);
-
-extern JS_PUBLIC_API bool JS_DoubleIsInt32(double d, int32_t* ip);
-
-extern JS_PUBLIC_API JSType JS_TypeOfValue(JSContext* cx,
-                                           JS::Handle<JS::Value> v);
-
-namespace JS {
-
-extern JS_PUBLIC_API const char* InformalValueTypeName(const JS::Value& v);
-
-} /* namespace JS */
-
-/** True iff fun is the global eval function. */
-extern JS_PUBLIC_API bool JS_IsBuiltinEvalFunction(JSFunction* fun);
-
-/** True iff fun is the Function constructor. */
-extern JS_PUBLIC_API bool JS_IsBuiltinFunctionConstructor(JSFunction* fun);
-
-/************************************************************************/
-
-// [SMDOC] Data Structures (JSContext, JSRuntime, Realm, Compartment, Zone)
-//
-// SpiderMonkey uses some data structures that behave a lot like Russian dolls:
-// runtimes contain zones, zones contain compartments, compartments contain
-// realms. Each layer has its own purpose.
-//
-// Realm
-// -----
-// Data associated with a global object. In the browser each frame has its
-// own global/realm.
-//
-// Compartment
-// -----------
-// Security membrane; when an object from compartment A is used in compartment
-// B, a cross-compartment wrapper (a kind of proxy) is used. In the browser each
-// compartment currently contains one global/realm, but we want to change that
-// so each compartment contains multiple same-origin realms (bug 1357862).
-//
-// Zone
-// ----
-// A Zone is a group of compartments that share GC resources (arenas, strings,
-// etc) for memory usage and performance reasons. Zone is the GC unit: the GC
-// can operate on one or more zones at a time. The browser uses roughly one zone
-// per tab.
-//
-// Context
-// -------
-// JSContext represents a thread: there must be exactly one JSContext for each
-// thread running JS/Wasm. Internally, helper threads have their own JSContext.
-//
-// Runtime
-// -------
-// JSRuntime is very similar to JSContext: each runtime belongs to one context
-// (thread), but helper threads don't have their own runtimes (they're shared by
-// all runtimes in the process and use the runtime of the task they're
-// executing).
-
-/*
- * Locking, contexts, and memory allocation.
- *
- * It is important that SpiderMonkey be initialized, and the first context
- * be created, in a single-threaded fashion.  Otherwise the behavior of the
- * library is undefined.
- * See:
- * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_reference
- */
-
-// Create a new context (and runtime) for this thread.
-extern JS_PUBLIC_API JSContext* JS_NewContext(
-    uint32_t maxbytes, uint32_t maxNurseryBytes = JS::DefaultNurseryBytes,
-    JSRuntime* parentRuntime = nullptr);
-
-// The methods below for controlling the active context in a cooperatively
-// multithreaded runtime are not threadsafe, and the caller must ensure they
-// are called serially if there is a chance for contention between threads.
-
-// Called from the active context for a runtime, yield execution so that
-// this context is no longer active and can no longer use the API.
-extern JS_PUBLIC_API void JS_YieldCooperativeContext(JSContext* cx);
-
-// Called from a context whose runtime has no active context, this thread
-// becomes the active context for that runtime and may use the API.
-extern JS_PUBLIC_API void JS_ResumeCooperativeContext(JSContext* cx);
-
-// Create a new context on this thread for cooperative multithreading in the
-// same runtime as siblingContext. Called on a runtime (as indicated by
-// siblingContet) which has no active context, on success the new context will
-// become the runtime's active context.
-extern JS_PUBLIC_API JSContext* JS_NewCooperativeContext(
-    JSContext* siblingContext);
-
-// Destroy a context allocated with JS_NewContext or JS_NewCooperativeContext.
-// The context must be the current active context in the runtime, and after
-// this call the runtime will have no active context.
-extern JS_PUBLIC_API void JS_DestroyContext(JSContext* cx);
-
-JS_PUBLIC_API void* JS_GetContextPrivate(JSContext* cx);
-
-JS_PUBLIC_API void JS_SetContextPrivate(JSContext* cx, void* data);
-
-extern JS_PUBLIC_API JSRuntime* JS_GetParentRuntime(JSContext* cx);
-
-extern JS_PUBLIC_API JSRuntime* JS_GetRuntime(JSContext* cx);
-
-extern JS_PUBLIC_API void JS_SetFutexCanWait(JSContext* cx);
-
-namespace js {
-
-void AssertHeapIsIdle();
-
-} /* namespace js */
+} // namespace JS
 
 namespace JS {
 
 /**
- * Initialize the runtime's self-hosted code. Embeddings should call this
- * exactly once per runtime/context, before the first JS_NewGlobalObject
- * call.
- */
-JS_PUBLIC_API bool InitSelfHostedCode(JSContext* cx);
-
-/**
- * Asserts (in debug and release builds) that `obj` belongs to the current
- * thread's context.
- */
-JS_PUBLIC_API void AssertObjectBelongsToCurrentThread(JSObject* obj);
-
-} /* namespace JS */
-
-extern JS_PUBLIC_API const char* JS_GetImplementationVersion(void);
-
-extern JS_PUBLIC_API void JS_SetDestroyCompartmentCallback(
-    JSContext* cx, JSDestroyCompartmentCallback callback);
-
-extern JS_PUBLIC_API void JS_SetSizeOfIncludingThisCompartmentCallback(
-    JSContext* cx, JSSizeOfIncludingThisCompartmentCallback callback);
-
-extern JS_PUBLIC_API void JS_SetWrapObjectCallbacks(
-    JSContext* cx, const JSWrapObjectCallbacks* callbacks);
-
-extern JS_PUBLIC_API void JS_SetExternalStringSizeofCallback(
-    JSContext* cx, JSExternalStringSizeofCallback callback);
-
-#if defined(NIGHTLY_BUILD)
-
-// Set a callback that will be called whenever an error
-// is thrown in this runtime. This is designed as a mechanism
-// for logging errors. Note that the VM makes no attempt to sanitize
-// the contents of the error (so it may contain private data)
-// or to sort out among errors (so it may not be the error you
-// are interested in or for the component in which you are
-// interested).
-//
-// If the callback sets a new error, this new error
-// will replace the original error.
-//
-// May be `nullptr`.
-extern JS_PUBLIC_API void JS_SetErrorInterceptorCallback(
-    JSRuntime*, JSErrorInterceptor* callback);
-
-extern JS_PUBLIC_API JSErrorInterceptor* JS_GetErrorInterceptorCallback(
-    JSRuntime*);
-
-// Examine a value to determine if it is one of the built-in Error types.
-// If so, return the error type.
-extern JS_PUBLIC_API mozilla::Maybe<JSExnType> JS_GetErrorType(
-    const JS::Value& val);
-
-#endif  // defined(NIGHTLY_BUILD)
-
-extern JS_PUBLIC_API void JS_SetCompartmentPrivate(JS::Compartment* compartment,
-                                                   void* data);
-
-extern JS_PUBLIC_API void* JS_GetCompartmentPrivate(
-    JS::Compartment* compartment);
-
-extern JS_PUBLIC_API void JS_SetZoneUserData(JS::Zone* zone, void* data);
-
-extern JS_PUBLIC_API void* JS_GetZoneUserData(JS::Zone* zone);
-
-extern JS_PUBLIC_API bool JS_WrapObject(JSContext* cx,
-                                        JS::MutableHandleObject objp);
-
-extern JS_PUBLIC_API bool JS_WrapValue(JSContext* cx,
-                                       JS::MutableHandleValue vp);
-
-extern JS_PUBLIC_API JSObject* JS_TransplantObject(JSContext* cx,
-                                                   JS::HandleObject origobj,
-                                                   JS::HandleObject target);
-
-extern JS_PUBLIC_API bool JS_RefreshCrossCompartmentWrappers(
-    JSContext* cx, JS::Handle<JSObject*> obj);
-
-/*
- * At any time, a JSContext has a current (possibly-nullptr) realm.
- * Realms are described in:
- *
- *   developer.mozilla.org/en-US/docs/SpiderMonkey/SpiderMonkey_compartments
- *
- * The current realm of a context may be changed. The preferred way to do
- * this is with JSAutoRealm:
- *
- *   void foo(JSContext* cx, JSObject* obj) {
- *     // in some realm 'r'
- *     {
- *       JSAutoRealm ar(cx, obj);  // constructor enters
- *       // in the realm of 'obj'
- *     }                           // destructor leaves
- *     // back in realm 'r'
- *   }
- *
- * The object passed to JSAutoRealm must *not* be a cross-compartment wrapper,
- * because CCWs are not associated with a single realm.
- *
- * For more complicated uses that don't neatly fit in a C++ stack frame, the
- * realm can be entered and left using separate function calls:
- *
- *   void foo(JSContext* cx, JSObject* obj) {
- *     // in 'oldRealm'
- *     JS::Realm* oldRealm = JS::EnterRealm(cx, obj);
- *     // in the realm of 'obj'
- *     JS::LeaveRealm(cx, oldRealm);
- *     // back in 'oldRealm'
- *   }
- *
- * Note: these calls must still execute in a LIFO manner w.r.t all other
- * enter/leave calls on the context. Furthermore, only the return value of a
- * JS::EnterRealm call may be passed as the 'oldRealm' argument of
- * the corresponding JS::LeaveRealm call.
- *
- * Entering a realm roots the realm and its global object for the lifetime of
- * the JSAutoRealm.
- */
-
-class MOZ_RAII JS_PUBLIC_API JSAutoRealm {
-  JSContext* cx_;
-  JS::Realm* oldRealm_;
-
- public:
-  JSAutoRealm(JSContext* cx, JSObject* target MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
-  JSAutoRealm(JSContext* cx, JSScript* target MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
-  ~JSAutoRealm();
-
-  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
-class MOZ_RAII JS_PUBLIC_API JSAutoNullableRealm {
-  JSContext* cx_;
-  JS::Realm* oldRealm_;
-
- public:
-  explicit JSAutoNullableRealm(
-      JSContext* cx, JSObject* targetOrNull MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
-  ~JSAutoNullableRealm();
-
-  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
-namespace JS {
-
-/** NB: This API is infallible; a nullptr return value does not indicate error.
- *
- * |target| must not be a cross-compartment wrapper because CCWs are not
- * associated with a single realm.
- *
- * Entering a realm roots the realm and its global object until the matching
- * JS::LeaveRealm() call.
- */
-extern JS_PUBLIC_API JS::Realm* EnterRealm(JSContext* cx, JSObject* target);
-
-extern JS_PUBLIC_API void LeaveRealm(JSContext* cx, JS::Realm* oldRealm);
-
-using IterateRealmCallback = void (*)(JSContext* cx, void* data,
-                                      Handle<Realm*> realm);
-
-/**
- * This function calls |realmCallback| on every realm. Beware that there is no
- * guarantee that the realm will survive after the callback returns. Also,
- * barriers are disabled via the TraceSession.
- */
-extern JS_PUBLIC_API void IterateRealms(JSContext* cx, void* data,
-                                        IterateRealmCallback realmCallback);
-
-/**
- * Like IterateRealms, but only call the callback for realms using |principals|.
- */
-extern JS_PUBLIC_API void IterateRealmsWithPrincipals(
-    JSContext* cx, JSPrincipals* principals, void* data,
-    IterateRealmCallback realmCallback);
-
-/**
- * Like IterateRealms, but only iterates realms in |compartment|.
- */
-extern JS_PUBLIC_API void IterateRealmsInCompartment(
-    JSContext* cx, JS::Compartment* compartment, void* data,
-    IterateRealmCallback realmCallback);
-
-}  // namespace JS
-
-/**
- * An enum that JSIterateCompartmentCallback can return to indicate
- * whether to keep iterating.
- */
-namespace JS {
-enum class CompartmentIterResult { KeepGoing, Stop };
-}  // namespace JS
-
-typedef JS::CompartmentIterResult (*JSIterateCompartmentCallback)(
-    JSContext* cx, void* data, JS::Compartment* compartment);
-
-/**
- * This function calls |compartmentCallback| on every compartment until either
- * all compartments have been iterated or CompartmentIterResult::Stop is
- * returned. Beware that there is no guarantee that the compartment will survive
- * after the callback returns. Also, barriers are disabled via the TraceSession.
- */
-extern JS_PUBLIC_API void JS_IterateCompartments(
-    JSContext* cx, void* data,
-    JSIterateCompartmentCallback compartmentCallback);
-
-/**
- * This function calls |compartmentCallback| on every compartment in the given
- * zone until either all compartments have been iterated or
- * CompartmentIterResult::Stop is returned. Beware that there is no guarantee
- * that the compartment will survive after the callback returns. Also, barriers
- * are disabled via the TraceSession.
- */
-extern JS_PUBLIC_API void JS_IterateCompartmentsInZone(
-    JSContext* cx, JS::Zone* zone, void* data,
-    JSIterateCompartmentCallback compartmentCallback);
-
-/**
- * Mark a jsid after entering a new compartment. Different zones separately
- * mark the ids in a runtime, and this must be used any time an id is obtained
- * from one compartment and then used in another compartment, unless the two
- * compartments are guaranteed to be in the same zone.
- */
-extern JS_PUBLIC_API void JS_MarkCrossZoneId(JSContext* cx, jsid id);
-
-/**
- * If value stores a jsid (an atomized string or symbol), mark that id as for
- * JS_MarkCrossZoneId.
- */
-extern JS_PUBLIC_API void JS_MarkCrossZoneIdValue(JSContext* cx,
-                                                  const JS::Value& value);
-
-/**
- * Resolve id, which must contain either a string or an int, to a standard
- * class name in obj if possible, defining the class's constructor and/or
- * prototype and storing true in *resolved.  If id does not name a standard
- * class or a top-level property induced by initializing a standard class,
- * store false in *resolved and just return true.  Return false on error,
- * as usual for bool result-typed API entry points.
- *
- * This API can be called directly from a global object class's resolve op,
- * to define standard classes lazily. The class should either have an enumerate
- * hook that calls JS_EnumerateStandardClasses, or a newEnumerate hook that
- * calls JS_NewEnumerateStandardClasses. newEnumerate is preferred because it's
- * faster (does not define all standard classes).
- */
-extern JS_PUBLIC_API bool JS_ResolveStandardClass(JSContext* cx,
-                                                  JS::HandleObject obj,
-                                                  JS::HandleId id,
-                                                  bool* resolved);
-
-extern JS_PUBLIC_API bool JS_MayResolveStandardClass(const JSAtomState& names,
-                                                     jsid id,
-                                                     JSObject* maybeObj);
-
-extern JS_PUBLIC_API bool JS_EnumerateStandardClasses(JSContext* cx,
-                                                      JS::HandleObject obj);
-
-/**
- * Fill "properties" with a list of standard class names that have not yet been
- * resolved on "obj".  This can be used as (part of) a newEnumerate class hook
- * on a global.  Already-resolved things are excluded because they might have
- * been deleted by script after being resolved and enumeration considers
- * already-defined properties anyway.
+ * Specification for which compartment/zone a newly created realm should use.
  */
-extern JS_PUBLIC_API bool JS_NewEnumerateStandardClasses(
-    JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties,
-    bool enumerableOnly);
-
-/**
- * Fill "properties" with a list of standard class names.  This can be used for
- * proxies that want to define behavior that looks like enumerating a global
- * without touching the global itself.
- */
-extern JS_PUBLIC_API bool JS_NewEnumerateStandardClassesIncludingResolved(
-    JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties,
-    bool enumerableOnly);
-
-extern JS_PUBLIC_API bool JS_GetClassObject(JSContext* cx, JSProtoKey key,
-                                            JS::MutableHandle<JSObject*> objp);
-
-extern JS_PUBLIC_API bool JS_GetClassPrototype(
-    JSContext* cx, JSProtoKey key, JS::MutableHandle<JSObject*> objp);
-
-namespace JS {
-
-/*
- * Determine if the given object is an instance/prototype/constructor for a
- * standard class. If so, return the associated JSProtoKey. If not, return
- * JSProto_Null.
- */
-
-extern JS_PUBLIC_API JSProtoKey IdentifyStandardInstance(JSObject* obj);
-
-extern JS_PUBLIC_API JSProtoKey IdentifyStandardPrototype(JSObject* obj);
-
-extern JS_PUBLIC_API JSProtoKey
-IdentifyStandardInstanceOrPrototype(JSObject* obj);
-
-extern JS_PUBLIC_API JSProtoKey IdentifyStandardConstructor(JSObject* obj);
-
-extern JS_PUBLIC_API void ProtoKeyToId(JSContext* cx, JSProtoKey key,
-                                       JS::MutableHandleId idp);
-
-} /* namespace JS */
-
-extern JS_PUBLIC_API JSProtoKey JS_IdToProtoKey(JSContext* cx, JS::HandleId id);
-
-extern JS_PUBLIC_API bool JS_IsGlobalObject(JSObject* obj);
-
-extern JS_PUBLIC_API JSObject* JS_GlobalLexicalEnvironment(JSObject* obj);
-
-extern JS_PUBLIC_API bool JS_HasExtensibleLexicalEnvironment(JSObject* obj);
-
-extern JS_PUBLIC_API JSObject* JS_ExtensibleLexicalEnvironment(JSObject* obj);
-
-namespace JS {
-
-/**
- * Get the current realm's global. Returns nullptr if no realm has been
- * entered.
- */
-extern JS_PUBLIC_API JSObject* CurrentGlobalOrNull(JSContext* cx);
-
-/**
- * Get the global object associated with an object's realm. The object must not
- * be a cross-compartment wrapper (because CCWs are shared by all realms in the
- * compartment).
- */
-extern JS_PUBLIC_API JSObject* GetNonCCWObjectGlobal(JSObject* obj);
-
-}  // namespace JS
-
-/**
- * Add 'Reflect.parse', a SpiderMonkey extension, to the Reflect object on the
- * given global.
- */
-extern JS_PUBLIC_API bool JS_InitReflectParse(JSContext* cx,
-                                              JS::HandleObject global);
-
-/**
- * Add various profiling-related functions as properties of the given object.
- * Defined in builtin/Profilers.cpp.
- */
-extern JS_PUBLIC_API bool JS_DefineProfilingFunctions(JSContext* cx,
-                                                      JS::HandleObject obj);
-
-/* Defined in vm/Debugger.cpp. */
-extern JS_PUBLIC_API bool JS_DefineDebuggerObject(JSContext* cx,
-                                                  JS::HandleObject obj);
-
-namespace JS {
-
-/**
- * Tell JS engine whether Profile Timeline Recording is enabled or not.
- * If Profile Timeline Recording is enabled, data shown there like stack won't
- * be optimized out.
- * This is global state and not associated with specific runtime or context.
- */
-extern JS_PUBLIC_API void SetProfileTimelineRecordingEnabled(bool enabled);
-
-extern JS_PUBLIC_API bool IsProfileTimelineRecordingEnabled();
-
-}  // namespace JS
-
-#ifdef JS_HAS_CTYPES
-/**
- * Initialize the 'ctypes' object on a global variable 'obj'. The 'ctypes'
- * object will be sealed.
- */
-extern JS_PUBLIC_API bool JS_InitCTypesClass(JSContext* cx,
-                                             JS::HandleObject global);
-
-/**
- * Convert a unicode string 'source' of length 'slen' to the platform native
- * charset, returning a null-terminated string allocated with JS_malloc. On
- * failure, this function should report an error.
- */
-typedef char* (*JSCTypesUnicodeToNativeFun)(JSContext* cx,
-                                            const char16_t* source,
-                                            size_t slen);
-
-/**
- * Set of function pointers that ctypes can use for various internal functions.
- * See JS_SetCTypesCallbacks below. Providing nullptr for a function is safe,
- * and will result in the applicable ctypes functionality not being available.
- */
-struct JSCTypesCallbacks {
-  JSCTypesUnicodeToNativeFun unicodeToNative;
-};
-
-/**
- * Set the callbacks on the provided 'ctypesObj' object. 'callbacks' should be a
- * pointer to static data that exists for the lifetime of 'ctypesObj', but it
- * may safely be altered after calling this function and without having
- * to call this function again.
- */
-extern JS_PUBLIC_API void JS_SetCTypesCallbacks(
-    JSObject* ctypesObj, const JSCTypesCallbacks* callbacks);
-#endif
-
-/*
- * A replacement for MallocAllocPolicy that allocates in the JS heap and adds no
- * extra behaviours.
- *
- * This is currently used for allocating source buffers for parsing. Since these
- * are temporary and will not be freed by GC, the memory is not tracked by the
- * usual accounting.
- */
-class JS_PUBLIC_API JSMallocAllocPolicy : public js::AllocPolicyBase {
- public:
-  void reportAllocOverflow() const {}
-
-  MOZ_MUST_USE bool checkSimulatedOOM() const { return true; }
-};
-
-/**
- * Set the size of the native stack that should not be exceed. To disable
- * stack size checking pass 0.
- *
- * SpiderMonkey allows for a distinction between system code (such as GCs, which
- * may incidentally be triggered by script but are not strictly performed on
- * behalf of such script), trusted script (as determined by
- * JS_SetTrustedPrincipals), and untrusted script. Each kind of code may have a
- * different stack quota, allowing embedders to keep higher-priority machinery
- * running in the face of scripted stack exhaustion by something else.
- *
- * The stack quotas for each kind of code should be monotonically descending,
- * and may be specified with this function. If 0 is passed for a given kind
- * of code, it defaults to the value of the next-highest-priority kind.
- *
- * This function may only be called immediately after the runtime is initialized
- * and before any code is executed and/or interrupts requested.
- */
-extern JS_PUBLIC_API void JS_SetNativeStackQuota(
-    JSContext* cx, size_t systemCodeStackSize,
-    size_t trustedScriptStackSize = 0, size_t untrustedScriptStackSize = 0);
-
-/************************************************************************/
-
-extern JS_PUBLIC_API bool JS_ValueToId(JSContext* cx, JS::HandleValue v,
-                                       JS::MutableHandleId idp);
-
-extern JS_PUBLIC_API bool JS_StringToId(JSContext* cx, JS::HandleString s,
-                                        JS::MutableHandleId idp);
-
-extern JS_PUBLIC_API bool JS_IdToValue(JSContext* cx, jsid id,
-                                       JS::MutableHandle<JS::Value> vp);
-
-namespace JS {
-
-/**
- * Convert obj to a primitive value. On success, store the result in vp and
- * return true.
- *
- * The hint argument must be JSTYPE_STRING, JSTYPE_NUMBER, or
- * JSTYPE_UNDEFINED (no hint).
- *
- * Implements: ES6 7.1.1 ToPrimitive(input, [PreferredType]).
- */
-extern JS_PUBLIC_API bool ToPrimitive(JSContext* cx, JS::HandleObject obj,
-                                      JSType hint, JS::MutableHandleValue vp);
-
-/**
- * If args.get(0) is one of the strings "string", "number", or "default", set
- * result to JSTYPE_STRING, JSTYPE_NUMBER, or JSTYPE_UNDEFINED accordingly and
- * return true. Otherwise, return false with a TypeError pending.
- *
- * This can be useful in implementing a @@toPrimitive method.
- */
-extern JS_PUBLIC_API bool GetFirstArgumentAsTypeHint(JSContext* cx,
-                                                     CallArgs args,
-                                                     JSType* result);
-
-} /* namespace JS */
-
-template <typename T>
-struct JSConstScalarSpec {
-  const char* name;
-  T val;
-};
-
-using JSConstDoubleSpec = JSConstScalarSpec<double>;
-using JSConstIntegerSpec = JSConstScalarSpec<int32_t>;
-
-extern JS_PUBLIC_API JSObject* JS_InitClass(
-    JSContext* cx, JS::HandleObject obj, JS::HandleObject parent_proto,
-    const JSClass* clasp, JSNative constructor, unsigned nargs,
-    const JSPropertySpec* ps, const JSFunctionSpec* fs,
-    const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs);
-
-/**
- * Set up ctor.prototype = proto and proto.constructor = ctor with the
- * right property flags.
- */
-extern JS_PUBLIC_API bool JS_LinkConstructorAndPrototype(
-    JSContext* cx, JS::Handle<JSObject*> ctor, JS::Handle<JSObject*> proto);
-
-extern JS_PUBLIC_API const JSClass* JS_GetClass(JSObject* obj);
-
-extern JS_PUBLIC_API bool JS_InstanceOf(JSContext* cx,
-                                        JS::Handle<JSObject*> obj,
-                                        const JSClass* clasp,
-                                        JS::CallArgs* args);
-
-extern JS_PUBLIC_API bool JS_HasInstance(JSContext* cx,
-                                         JS::Handle<JSObject*> obj,
-                                         JS::Handle<JS::Value> v, bool* bp);
-
-namespace JS {
-
-// Implementation of
-// http://www.ecma-international.org/ecma-262/6.0/#sec-ordinaryhasinstance.  If
-// you're looking for the equivalent of "instanceof", you want JS_HasInstance,
-// not this function.
-extern JS_PUBLIC_API bool OrdinaryHasInstance(JSContext* cx,
-                                              HandleObject objArg,
-                                              HandleValue v, bool* bp);
-
-// Implementation of
-// https://www.ecma-international.org/ecma-262/6.0/#sec-instanceofoperator
-// This is almost identical to JS_HasInstance, except the latter may call a
-// custom hasInstance class op instead of InstanceofOperator.
-extern JS_PUBLIC_API bool InstanceofOperator(JSContext* cx, HandleObject obj,
-                                             HandleValue v, bool* bp);
-
-}  // namespace JS
-
-extern JS_PUBLIC_API void* JS_GetPrivate(JSObject* obj);
-
-extern JS_PUBLIC_API void JS_SetPrivate(JSObject* obj, void* data);
-
-extern JS_PUBLIC_API void* JS_GetInstancePrivate(JSContext* cx,
-                                                 JS::Handle<JSObject*> obj,
-                                                 const JSClass* clasp,
-                                                 JS::CallArgs* args);
-
-extern JS_PUBLIC_API JSObject* JS_GetConstructor(JSContext* cx,
-                                                 JS::Handle<JSObject*> proto);
-
-namespace JS {
-
-// Specification for which compartment/zone a newly created realm should use.
 enum class CompartmentSpecifier {
   // Create a new realm and compartment in the single runtime wide system
   // zone. The meaning of this zone is left to the embedder.
   NewCompartmentInSystemZone,
 
   // Create a new realm and compartment in a particular existing zone.
   NewCompartmentInExistingZone,
 
@@ -944,58 +51,45 @@ enum class CompartmentSpecifier {
 };
 
 /**
  * RealmCreationOptions specifies options relevant to creating a new realm, that
  * are either immutable characteristics of that realm or that are discarded
  * after the realm has been created.
  *
  * Access to these options on an existing realm is read-only: if you need
- * particular selections, make them before you create the realm.
+ * particular selections, you must make them before you create the realm.
  */
 class JS_PUBLIC_API RealmCreationOptions {
  public:
-  RealmCreationOptions()
-      : traceGlobal_(nullptr),
-        compSpec_(CompartmentSpecifier::NewCompartmentAndZone),
-        comp_(nullptr),
-        invisibleToDebugger_(false),
-        mergeable_(false),
-        preserveJitCode_(false),
-        cloneSingletons_(false),
-        sharedMemoryAndAtomics_(false),
-        streams_(false),
-        bigint_(false),
-        fields_(false),
-        secureContext_(false),
-        clampAndJitterTime_(true) {}
+  RealmCreationOptions() : comp_(nullptr) {}
 
   JSTraceOp getTrace() const { return traceGlobal_; }
   RealmCreationOptions& setTrace(JSTraceOp op) {
     traceGlobal_ = op;
     return *this;
   }
 
-  JS::Zone* zone() const {
+  Zone* zone() const {
     MOZ_ASSERT(compSpec_ == CompartmentSpecifier::NewCompartmentInExistingZone);
     return zone_;
   }
-  JS::Compartment* compartment() const {
+  Compartment* compartment() const {
     MOZ_ASSERT(compSpec_ == CompartmentSpecifier::ExistingCompartment);
     return comp_;
   }
   CompartmentSpecifier compartmentSpecifier() const { return compSpec_; }
 
   // Set the compartment/zone to use for the realm. See CompartmentSpecifier
   // above.
   RealmCreationOptions& setNewCompartmentInSystemZone();
   RealmCreationOptions& setNewCompartmentInExistingZone(JSObject* obj);
   RealmCreationOptions& setNewCompartmentAndZone();
   RealmCreationOptions& setExistingCompartment(JSObject* obj);
-  RealmCreationOptions& setExistingCompartment(JS::Compartment* compartment);
+  RealmCreationOptions& setExistingCompartment(Compartment* compartment);
 
   // Certain compartments are implementation details of the embedding, and
   // references to them should never leak out to script. This flag causes this
   // realm to skip firing onNewGlobalObject and makes addDebuggee a no-op for
   // this global.
   //
   // Debugger visibility is per-compartment, not per-realm (it's only practical
   // to enforce visibility on compartment boundaries), so if a realm is being
@@ -1064,40 +158,56 @@ class JS_PUBLIC_API RealmCreationOptions
 
   bool clampAndJitterTime() const { return clampAndJitterTime_; }
   RealmCreationOptions& setClampAndJitterTime(bool flag) {
     clampAndJitterTime_ = flag;
     return *this;
   }
 
  private:
-  JSTraceOp traceGlobal_;
-  CompartmentSpecifier compSpec_;
+  JSTraceOp traceGlobal_ = nullptr;
+  CompartmentSpecifier compSpec_ = CompartmentSpecifier::NewCompartmentAndZone;
   union {
-    JS::Compartment* comp_;
-    JS::Zone* zone_;
+    Compartment* comp_;
+    Zone* zone_;
   };
-  bool invisibleToDebugger_;
-  bool mergeable_;
-  bool preserveJitCode_;
-  bool cloneSingletons_;
-  bool sharedMemoryAndAtomics_;
-  bool streams_;
-  bool bigint_;
-  bool fields_;
-  bool secureContext_;
-  bool clampAndJitterTime_;
+  bool invisibleToDebugger_ = false;
+  bool mergeable_ = false;
+  bool preserveJitCode_ = false;
+  bool cloneSingletons_ = false;
+  bool sharedMemoryAndAtomics_ = false;
+  bool streams_ = false;
+  bool bigint_ = false;
+  bool fields_ = false;
+  bool secureContext_ = false;
+  bool clampAndJitterTime_ = true;
 };
 
 /**
  * RealmBehaviors specifies behaviors of a realm that can be changed after the
  * realm's been created.
  */
 class JS_PUBLIC_API RealmBehaviors {
  public:
+  RealmBehaviors() = default;
+
+  // For certain globals, we know enough about the code that will run in them
+  // that we can discard script source entirely.
+  bool discardSource() const { return discardSource_; }
+  RealmBehaviors& setDiscardSource(bool flag) {
+    discardSource_ = flag;
+    return *this;
+  }
+
+  bool disableLazyParsing() const { return disableLazyParsing_; }
+  RealmBehaviors& setDisableLazyParsing(bool flag) {
+    disableLazyParsing_ = flag;
+    return *this;
+  }
+
   class Override {
    public:
     Override() : mode_(Default) {}
 
     bool get(bool defaultValue) const {
       if (mode_ == Default) {
         return defaultValue;
       }
@@ -1111,53 +221,34 @@ class JS_PUBLIC_API RealmBehaviors {
     void reset() { mode_ = Default; }
 
    private:
     enum Mode { Default, ForceTrue, ForceFalse };
 
     Mode mode_;
   };
 
-  RealmBehaviors()
-      : discardSource_(false),
-        disableLazyParsing_(false),
-        singletonsAsTemplates_(true) {}
-
-  // For certain globals, we know enough about the code that will run in them
-  // that we can discard script source entirely.
-  bool discardSource() const { return discardSource_; }
-  RealmBehaviors& setDiscardSource(bool flag) {
-    discardSource_ = flag;
-    return *this;
-  }
-
-  bool disableLazyParsing() const { return disableLazyParsing_; }
-  RealmBehaviors& setDisableLazyParsing(bool flag) {
-    disableLazyParsing_ = flag;
-    return *this;
-  }
-
   bool extraWarnings(JSContext* cx) const;
   Override& extraWarningsOverride() { return extraWarningsOverride_; }
 
   bool getSingletonsAsTemplates() const { return singletonsAsTemplates_; }
   RealmBehaviors& setSingletonsAsValues() {
     singletonsAsTemplates_ = false;
     return *this;
   }
 
  private:
-  bool discardSource_;
-  bool disableLazyParsing_;
-  Override extraWarningsOverride_;
+  bool discardSource_ = false;
+  bool disableLazyParsing_ = false;
+  Override extraWarningsOverride_ = {};
 
   // To XDR singletons, we need to ensure that all singletons are all used as
   // templates, by making JSOP_OBJECT return a clone of the JSScript
   // singleton, instead of returning the value which is baked in the JSScript.
-  bool singletonsAsTemplates_;
+  bool singletonsAsTemplates_ = true;
 };
 
 /**
  * RealmOptions specifies realm characteristics: both those that can't be
  * changed on a realm once it's been created (RealmCreationOptions), and those
  * that can be changed on an existing realm (RealmBehaviors).
  */
 class JS_PUBLIC_API RealmOptions {
@@ -1181,2577 +272,21 @@ class JS_PUBLIC_API RealmOptions {
   RealmBehaviors& behaviors() { return behaviors_; }
   const RealmBehaviors& behaviors() const { return behaviors_; }
 
  private:
   RealmCreationOptions creationOptions_;
   RealmBehaviors behaviors_;
 };
 
-JS_PUBLIC_API const RealmCreationOptions& RealmCreationOptionsRef(
-    JS::Realm* realm);
+extern JS_PUBLIC_API const RealmCreationOptions& RealmCreationOptionsRef(
+    Realm* realm);
 
-JS_PUBLIC_API const RealmCreationOptions& RealmCreationOptionsRef(
+extern JS_PUBLIC_API const RealmCreationOptions& RealmCreationOptionsRef(
     JSContext* cx);
 
-JS_PUBLIC_API RealmBehaviors& RealmBehaviorsRef(JS::Realm* realm);
-
-JS_PUBLIC_API RealmBehaviors& RealmBehaviorsRef(JSContext* cx);
-
-/**
- * During global creation, we fire notifications to callbacks registered
- * via the Debugger API. These callbacks are arbitrary script, and can touch
- * the global in arbitrary ways. When that happens, the global should not be
- * in a half-baked state. But this creates a problem for consumers that need
- * to set slots on the global to put it in a consistent state.
- *
- * This API provides a way for consumers to set slots atomically (immediately
- * after the global is created), before any debugger hooks are fired. It's
- * unfortunately on the clunky side, but that's the way the cookie crumbles.
- *
- * If callers have no additional state on the global to set up, they may pass
- * |FireOnNewGlobalHook| to JS_NewGlobalObject, which causes that function to
- * fire the hook as its final act before returning. Otherwise, callers should
- * pass |DontFireOnNewGlobalHook|, which means that they are responsible for
- * invoking JS_FireOnNewGlobalObject upon successfully creating the global. If
- * an error occurs and the operation aborts, callers should skip firing the
- * hook. But otherwise, callers must take care to fire the hook exactly once
- * before compiling any script in the global's scope (we have assertions in
- * place to enforce this). This lets us be sure that debugger clients never miss
- * breakpoints.
- */
-enum OnNewGlobalHookOption { FireOnNewGlobalHook, DontFireOnNewGlobalHook };
-
-} /* namespace JS */
-
-extern JS_PUBLIC_API JSObject* JS_NewGlobalObject(
-    JSContext* cx, const JSClass* clasp, JSPrincipals* principals,
-    JS::OnNewGlobalHookOption hookOption, const JS::RealmOptions& options);
-/**
- * Spidermonkey does not have a good way of keeping track of what compartments
- * should be marked on their own. We can mark the roots unconditionally, but
- * marking GC things only relevant in live compartments is hard. To mitigate
- * this, we create a static trace hook, installed on each global object, from
- * which we can be sure the compartment is relevant, and mark it.
- *
- * It is still possible to specify custom trace hooks for global object classes.
- * They can be provided via the RealmOptions passed to JS_NewGlobalObject.
- */
-extern JS_PUBLIC_API void JS_GlobalObjectTraceHook(JSTracer* trc,
-                                                   JSObject* global);
-
-namespace JS {
-
-/**
- * This allows easily constructing a global object without having to deal with
- * JSClassOps, forgetting to add JS_GlobalObjectTraceHook, or forgetting to call
- * JS::InitRealmStandardClasses(). Example:
- *
- *     const JSClass globalClass = { "MyGlobal", JSCLASS_GLOBAL_FLAGS,
- *         &JS::DefaultGlobalClassOps };
- *     JS_NewGlobalObject(cx, &globalClass, ...);
- */
-extern JS_PUBLIC_DATA const JSClassOps DefaultGlobalClassOps;
-
-}  // namespace JS
-
-extern JS_PUBLIC_API void JS_FireOnNewGlobalObject(JSContext* cx,
-                                                   JS::HandleObject global);
-
-extern JS_PUBLIC_API JSObject* JS_NewObject(JSContext* cx,
-                                            const JSClass* clasp);
-
-extern JS_PUBLIC_API bool JS_IsNative(JSObject* obj);
-
-/**
- * Unlike JS_NewObject, JS_NewObjectWithGivenProto does not compute a default
- * proto. If proto is nullptr, the JS object will have `null` as [[Prototype]].
- */
-extern JS_PUBLIC_API JSObject* JS_NewObjectWithGivenProto(
-    JSContext* cx, const JSClass* clasp, JS::Handle<JSObject*> proto);
-
-/**
- * Creates a new plain object, like `new Object()`, with Object.prototype as
- * [[Prototype]].
- */
-extern JS_PUBLIC_API JSObject* JS_NewPlainObject(JSContext* cx);
-
-/**
- * Freeze obj, and all objects it refers to, recursively. This will not recurse
- * through non-extensible objects, on the assumption that those are already
- * deep-frozen.
- */
-extern JS_PUBLIC_API bool JS_DeepFreezeObject(JSContext* cx,
-                                              JS::Handle<JSObject*> obj);
-
-/**
- * Freezes an object; see ES5's Object.freeze(obj) method.
- */
-extern JS_PUBLIC_API bool JS_FreezeObject(JSContext* cx,
-                                          JS::Handle<JSObject*> obj);
-
-/*** Standard internal methods **********************************************
- *
- * The functions below are the fundamental operations on objects.
- *
- * ES6 specifies 14 internal methods that define how objects behave.  The
- * standard is actually quite good on this topic, though you may have to read
- * it a few times. See ES6 sections 6.1.7.2 and 6.1.7.3.
- *
- * When 'obj' is an ordinary object, these functions have boring standard
- * behavior as specified by ES6 section 9.1; see the section about internal
- * methods in js/src/vm/NativeObject.h.
- *
- * Proxies override the behavior of internal methods. So when 'obj' is a proxy,
- * any one of the functions below could do just about anything. See
- * js/public/Proxy.h.
- */
-
-/**
- * Get the prototype of obj, storing it in result.
- *
- * Implements: ES6 [[GetPrototypeOf]] internal method.
- */
-extern JS_PUBLIC_API bool JS_GetPrototype(JSContext* cx, JS::HandleObject obj,
-                                          JS::MutableHandleObject result);
-
-/**
- * If |obj| (underneath any functionally-transparent wrapper proxies) has as
- * its [[GetPrototypeOf]] trap the ordinary [[GetPrototypeOf]] behavior defined
- * for ordinary objects, set |*isOrdinary = true| and store |obj|'s prototype
- * in |result|.  Otherwise set |*isOrdinary = false|.  In case of error, both
- * outparams have unspecified value.
- */
-extern JS_PUBLIC_API bool JS_GetPrototypeIfOrdinary(
-    JSContext* cx, JS::HandleObject obj, bool* isOrdinary,
-    JS::MutableHandleObject result);
-
-/**
- * Change the prototype of obj.
- *
- * Implements: ES6 [[SetPrototypeOf]] internal method.
- *
- * In cases where ES6 [[SetPrototypeOf]] returns false without an exception,
- * JS_SetPrototype throws a TypeError and returns false.
- *
- * Performance warning: JS_SetPrototype is very bad for performance. It may
- * cause compiled jit-code to be invalidated. It also causes not only obj but
- * all other objects in the same "group" as obj to be permanently deoptimized.
- * It's better to create the object with the right prototype from the start.
- */
-extern JS_PUBLIC_API bool JS_SetPrototype(JSContext* cx, JS::HandleObject obj,
-                                          JS::HandleObject proto);
-
-/**
- * Determine whether obj is extensible. Extensible objects can have new
- * properties defined on them. Inextensible objects can't, and their
- * [[Prototype]] slot is fixed as well.
- *
- * Implements: ES6 [[IsExtensible]] internal method.
- */
-extern JS_PUBLIC_API bool JS_IsExtensible(JSContext* cx, JS::HandleObject obj,
-                                          bool* extensible);
-
-/**
- * Attempt to make |obj| non-extensible.
- *
- * Not all failures are treated as errors. See the comment on
- * JS::ObjectOpResult in js/public/Class.h.
- *
- * Implements: ES6 [[PreventExtensions]] internal method.
- */
-extern JS_PUBLIC_API bool JS_PreventExtensions(JSContext* cx,
-                                               JS::HandleObject obj,
-                                               JS::ObjectOpResult& result);
-
-/**
- * Attempt to make the [[Prototype]] of |obj| immutable, such that any attempt
- * to modify it will fail.  If an error occurs during the attempt, return false
- * (with a pending exception set, depending upon the nature of the error).  If
- * no error occurs, return true with |*succeeded| set to indicate whether the
- * attempt successfully made the [[Prototype]] immutable.
- *
- * This is a nonstandard internal method.
- */
-extern JS_PUBLIC_API bool JS_SetImmutablePrototype(JSContext* cx,
-                                                   JS::HandleObject obj,
-                                                   bool* succeeded);
-
-/**
- * Get a description of one of obj's own properties. If no such property exists
- * on obj, return true with desc.object() set to null.
- *
- * Implements: ES6 [[GetOwnProperty]] internal method.
- */
-extern JS_PUBLIC_API bool JS_GetOwnPropertyDescriptorById(
-    JSContext* cx, JS::HandleObject obj, JS::HandleId id,
-    JS::MutableHandle<JS::PropertyDescriptor> desc);
-
-extern JS_PUBLIC_API bool JS_GetOwnPropertyDescriptor(
-    JSContext* cx, JS::HandleObject obj, const char* name,
-    JS::MutableHandle<JS::PropertyDescriptor> desc);
-
-extern JS_PUBLIC_API bool JS_GetOwnUCPropertyDescriptor(
-    JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
-    JS::MutableHandle<JS::PropertyDescriptor> desc);
-
-/**
- * Like JS_GetOwnPropertyDescriptorById, but also searches the prototype chain
- * if no own property is found directly on obj. The object on which the
- * property is found is returned in desc.object(). If the property is not found
- * on the prototype chain, this returns true with desc.object() set to null.
- */
-extern JS_PUBLIC_API bool JS_GetPropertyDescriptorById(
-    JSContext* cx, JS::HandleObject obj, JS::HandleId id,
-    JS::MutableHandle<JS::PropertyDescriptor> desc);
-
-extern JS_PUBLIC_API bool JS_GetPropertyDescriptor(
-    JSContext* cx, JS::HandleObject obj, const char* name,
-    JS::MutableHandle<JS::PropertyDescriptor> desc);
-
-extern JS_PUBLIC_API bool JS_GetUCPropertyDescriptor(
-    JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
-    JS::MutableHandle<JS::PropertyDescriptor> desc);
-
-/**
- * Define a property on obj.
- *
- * This function uses JS::ObjectOpResult to indicate conditions that ES6
- * specifies as non-error failures. This is inconvenient at best, so use this
- * function only if you are implementing a proxy handler's defineProperty()
- * method. For all other purposes, use one of the many DefineProperty functions
- * below that throw an exception in all failure cases.
- *
- * Implements: ES6 [[DefineOwnProperty]] internal method.
- */
-extern JS_PUBLIC_API bool JS_DefinePropertyById(
-    JSContext* cx, JS::HandleObject obj, JS::HandleId id,
-    JS::Handle<JS::PropertyDescriptor> desc, JS::ObjectOpResult& result);
-
-/**
- * Define a property on obj, throwing a TypeError if the attempt fails.
- * This is the C++ equivalent of `Object.defineProperty(obj, id, desc)`.
- */
-extern JS_PUBLIC_API bool JS_DefinePropertyById(
-    JSContext* cx, JS::HandleObject obj, JS::HandleId id,
-    JS::Handle<JS::PropertyDescriptor> desc);
-
-extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx,
-                                                JS::HandleObject obj,
-                                                JS::HandleId id,
-                                                JS::HandleValue value,
-                                                unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefinePropertyById(
-    JSContext* cx, JS::HandleObject obj, JS::HandleId id, JSNative getter,
-    JSNative setter, unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefinePropertyById(
-    JSContext* cx, JS::HandleObject obj, JS::HandleId id,
-    JS::HandleObject getter, JS::HandleObject setter, unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx,
-                                                JS::HandleObject obj,
-                                                JS::HandleId id,
-                                                JS::HandleObject value,
-                                                unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx,
-                                                JS::HandleObject obj,
-                                                JS::HandleId id,
-                                                JS::HandleString value,
-                                                unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx,
-                                                JS::HandleObject obj,
-                                                JS::HandleId id, int32_t value,
-                                                unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx,
-                                                JS::HandleObject obj,
-                                                JS::HandleId id, uint32_t value,
-                                                unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx,
-                                                JS::HandleObject obj,
-                                                JS::HandleId id, double value,
-                                                unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj,
-                                            const char* name,
-                                            JS::HandleValue value,
-                                            unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj,
-                                            const char* name, JSNative getter,
-                                            JSNative setter, unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj,
-                                            const char* name,
-                                            JS::HandleObject getter,
-                                            JS::HandleObject setter,
-                                            unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj,
-                                            const char* name,
-                                            JS::HandleObject value,
-                                            unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj,
-                                            const char* name,
-                                            JS::HandleString value,
-                                            unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj,
-                                            const char* name, int32_t value,
-                                            unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj,
-                                            const char* name, uint32_t value,
-                                            unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj,
-                                            const char* name, double value,
-                                            unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineUCProperty(
-    JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
-    JS::Handle<JS::PropertyDescriptor> desc, JS::ObjectOpResult& result);
-
-extern JS_PUBLIC_API bool JS_DefineUCProperty(
-    JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
-    JS::Handle<JS::PropertyDescriptor> desc);
-
-extern JS_PUBLIC_API bool JS_DefineUCProperty(
-    JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
-    JS::HandleValue value, unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineUCProperty(
-    JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
-    JS::HandleObject getter, JS::HandleObject setter, unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineUCProperty(
-    JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
-    JS::HandleObject value, unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineUCProperty(
-    JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
-    JS::HandleString value, unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx,
-                                              JS::HandleObject obj,
-                                              const char16_t* name,
-                                              size_t namelen, int32_t value,
-                                              unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx,
-                                              JS::HandleObject obj,
-                                              const char16_t* name,
-                                              size_t namelen, uint32_t value,
-                                              unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx,
-                                              JS::HandleObject obj,
-                                              const char16_t* name,
-                                              size_t namelen, double value,
-                                              unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj,
-                                           uint32_t index,
-                                           JS::HandleValue value,
-                                           unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj,
-                                           uint32_t index,
-                                           JS::HandleObject getter,
-                                           JS::HandleObject setter,
-                                           unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj,
-                                           uint32_t index,
-                                           JS::HandleObject value,
-                                           unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj,
-                                           uint32_t index,
-                                           JS::HandleString value,
-                                           unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj,
-                                           uint32_t index, int32_t value,
-                                           unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj,
-                                           uint32_t index, uint32_t value,
-                                           unsigned attrs);
-
-extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj,
-                                           uint32_t index, double value,
-                                           unsigned attrs);
-
-/**
- * Compute the expression `id in obj`.
- *
- * If obj has an own or inherited property obj[id], set *foundp = true and
- * return true. If not, set *foundp = false and return true. On error, return
- * false with an exception pending.
- *
- * Implements: ES6 [[Has]] internal method.
- */
-extern JS_PUBLIC_API bool JS_HasPropertyById(JSContext* cx,
-                                             JS::HandleObject obj,
-                                             JS::HandleId id, bool* foundp);
-
-extern JS_PUBLIC_API bool JS_HasProperty(JSContext* cx, JS::HandleObject obj,
-                                         const char* name, bool* foundp);
-
-extern JS_PUBLIC_API bool JS_HasUCProperty(JSContext* cx, JS::HandleObject obj,
-                                           const char16_t* name, size_t namelen,
-                                           bool* vp);
-
-extern JS_PUBLIC_API bool JS_HasElement(JSContext* cx, JS::HandleObject obj,
-                                        uint32_t index, bool* foundp);
-
-/**
- * Determine whether obj has an own property with the key `id`.
- *
- * Implements: ES6 7.3.11 HasOwnProperty(O, P).
- */
-extern JS_PUBLIC_API bool JS_HasOwnPropertyById(JSContext* cx,
-                                                JS::HandleObject obj,
-                                                JS::HandleId id, bool* foundp);
-
-extern JS_PUBLIC_API bool JS_HasOwnProperty(JSContext* cx, JS::HandleObject obj,
-                                            const char* name, bool* foundp);
-
-/**
- * Get the value of the property `obj[id]`, or undefined if no such property
- * exists. This is the C++ equivalent of `vp = Reflect.get(obj, id, receiver)`.
- *
- * Most callers don't need the `receiver` argument. Consider using
- * JS_GetProperty instead. (But if you're implementing a proxy handler's set()
- * method, it's often correct to call this function and pass the receiver
- * through.)
- *
- * Implements: ES6 [[Get]] internal method.
- */
-extern JS_PUBLIC_API bool JS_ForwardGetPropertyTo(JSContext* cx,
-                                                  JS::HandleObject obj,
-                                                  JS::HandleId id,
-                                                  JS::HandleValue receiver,
-                                                  JS::MutableHandleValue vp);
-
-extern JS_PUBLIC_API bool JS_ForwardGetElementTo(JSContext* cx,
-                                                 JS::HandleObject obj,
-                                                 uint32_t index,
-                                                 JS::HandleObject receiver,
-                                                 JS::MutableHandleValue vp);
-
-/**
- * Get the value of the property `obj[id]`, or undefined if no such property
- * exists. The result is stored in vp.
- *
- * Implements: ES6 7.3.1 Get(O, P).
- */
-extern JS_PUBLIC_API bool JS_GetPropertyById(JSContext* cx,
-                                             JS::HandleObject obj,
-                                             JS::HandleId id,
-                                             JS::MutableHandleValue vp);
-
-extern JS_PUBLIC_API bool JS_GetProperty(JSContext* cx, JS::HandleObject obj,
-                                         const char* name,
-                                         JS::MutableHandleValue vp);
-
-extern JS_PUBLIC_API bool JS_GetUCProperty(JSContext* cx, JS::HandleObject obj,
-                                           const char16_t* name, size_t namelen,
-                                           JS::MutableHandleValue vp);
-
-extern JS_PUBLIC_API bool JS_GetElement(JSContext* cx, JS::HandleObject obj,
-                                        uint32_t index,
-                                        JS::MutableHandleValue vp);
-
-/**
- * Perform the same property assignment as `Reflect.set(obj, id, v, receiver)`.
- *
- * This function has a `receiver` argument that most callers don't need.
- * Consider using JS_SetProperty instead.
- *
- * Implements: ES6 [[Set]] internal method.
- */
-extern JS_PUBLIC_API bool JS_ForwardSetPropertyTo(
-    JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v,
-    JS::HandleValue receiver, JS::ObjectOpResult& result);
-
-/**
- * Perform the assignment `obj[id] = v`.
- *
- * This function performs non-strict assignment, so if the property is
- * read-only, nothing happens and no error is thrown.
- */
-extern JS_PUBLIC_API bool JS_SetPropertyById(JSContext* cx,
-                                             JS::HandleObject obj,
-                                             JS::HandleId id,
-                                             JS::HandleValue v);
-
-extern JS_PUBLIC_API bool JS_SetProperty(JSContext* cx, JS::HandleObject obj,
-                                         const char* name, JS::HandleValue v);
-
-extern JS_PUBLIC_API bool JS_SetUCProperty(JSContext* cx, JS::HandleObject obj,
-                                           const char16_t* name, size_t namelen,
-                                           JS::HandleValue v);
-
-extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj,
-                                        uint32_t index, JS::HandleValue v);
-
-extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj,
-                                        uint32_t index, JS::HandleObject v);
-
-extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj,
-                                        uint32_t index, JS::HandleString v);
-
-extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj,
-                                        uint32_t index, int32_t v);
-
-extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj,
-                                        uint32_t index, uint32_t v);
-
-extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj,
-                                        uint32_t index, double v);
-
-/**
- * Delete a property. This is the C++ equivalent of
- * `result = Reflect.deleteProperty(obj, id)`.
- *
- * This function has a `result` out parameter that most callers don't need.
- * Unless you can pass through an ObjectOpResult provided by your caller, it's
- * probably best to use the JS_DeletePropertyById signature with just 3
- * arguments.
- *
- * Implements: ES6 [[Delete]] internal method.
- */
-extern JS_PUBLIC_API bool JS_DeletePropertyById(JSContext* cx,
-                                                JS::HandleObject obj,
-                                                JS::HandleId id,
-                                                JS::ObjectOpResult& result);
-
-extern JS_PUBLIC_API bool JS_DeleteProperty(JSContext* cx, JS::HandleObject obj,
-                                            const char* name,
-                                            JS::ObjectOpResult& result);
-
-extern JS_PUBLIC_API bool JS_DeleteUCProperty(JSContext* cx,
-                                              JS::HandleObject obj,
-                                              const char16_t* name,
-                                              size_t namelen,
-                                              JS::ObjectOpResult& result);
-
-extern JS_PUBLIC_API bool JS_DeleteElement(JSContext* cx, JS::HandleObject obj,
-                                           uint32_t index,
-                                           JS::ObjectOpResult& result);
-
-/**
- * Delete a property, ignoring strict failures. This is the C++ equivalent of
- * the JS `delete obj[id]` in non-strict mode code.
- */
-extern JS_PUBLIC_API bool JS_DeletePropertyById(JSContext* cx,
-                                                JS::HandleObject obj, jsid id);
-
-extern JS_PUBLIC_API bool JS_DeleteProperty(JSContext* cx, JS::HandleObject obj,
-                                            const char* name);
-
-extern JS_PUBLIC_API bool JS_DeleteElement(JSContext* cx, JS::HandleObject obj,
-                                           uint32_t index);
-
-/**
- * Get an array of the non-symbol enumerable properties of obj.
- * This function is roughly equivalent to:
- *
- *     var result = [];
- *     for (key in obj) {
- *         result.push(key);
- *     }
- *     return result;
- *
- * This is the closest thing we currently have to the ES6 [[Enumerate]]
- * internal method.
- *
- * The array of ids returned by JS_Enumerate must be rooted to protect its
- * contents from garbage collection. Use JS::Rooted<JS::IdVector>.
- */
-extern JS_PUBLIC_API bool JS_Enumerate(JSContext* cx, JS::HandleObject obj,
-                                       JS::MutableHandle<JS::IdVector> props);
-
-/**
- * Equivalent to `Object.assign(target, src)`: Copies the properties from the
- * `src` object (which must not be null) to `target` (which also must not be
- * null).
- */
-extern JS_PUBLIC_API bool JS_AssignObject(JSContext* cx,
-                                          JS::HandleObject target,
-                                          JS::HandleObject src);
-
-/*
- * API for determining callability and constructability. [[Call]] and
- * [[Construct]] are internal methods that aren't present on all objects, so it
- * is useful to ask if they are there or not. The standard itself asks these
- * questions routinely.
- */
-namespace JS {
-
-/**
- * Return true if the given object is callable. In ES6 terms, an object is
- * callable if it has a [[Call]] internal method.
- *
- * Implements: ES6 7.2.3 IsCallable(argument).
- *
- * Functions are callable. A scripted proxy or wrapper is callable if its
- * target is callable. Most other objects aren't callable.
- */
-extern JS_PUBLIC_API bool IsCallable(JSObject* obj);
-
-/**
- * Return true if the given object is a constructor. In ES6 terms, an object is
- * a constructor if it has a [[Construct]] internal method. The expression
- * `new obj()` throws a TypeError if obj is not a constructor.
- *
- * Implements: ES6 7.2.4 IsConstructor(argument).
- *
- * JS functions and classes are constructors. Arrow functions and most builtin
- * functions are not. A scripted proxy or wrapper is a constructor if its
- * target is a constructor.
- */
-extern JS_PUBLIC_API bool IsConstructor(JSObject* obj);
-
-} /* namespace JS */
+extern JS_PUBLIC_API RealmBehaviors& RealmBehaviorsRef(Realm* realm);
 
-/**
- * Call a function, passing a this-value and arguments. This is the C++
- * equivalent of `rval = Reflect.apply(fun, obj, args)`.
- *
- * Implements: ES6 7.3.12 Call(F, V, [argumentsList]).
- * Use this function to invoke the [[Call]] internal method.
- */