Merge inbound to mozilla-central r=merge a=merge
authorAndreea Pavel <apavel@mozilla.com>
Sat, 11 Nov 2017 11:59:20 +0200
changeset 444663 57eb0baf17ce8678767abfbf17bdb0acfd8909ad
parent 444662 21f9b2532a408fd6f6b943f9696d0ef98bdb0a2b (current diff)
parent 444661 2d726fc06e2fa68b774f7871df1d27ecc397703d (diff)
child 444664 9d19d489729b63790fb9fbd82272ac77c644713f
child 444666 12a211729fa623199fe0d627589272307da8bdce
child 444679 fa1adc80866df83946da2991273861af06ebf98b
child 444686 d72ea7c0051f76d546f9378e1d39160910e26e22
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone58.0a1
first release with
nightly linux32
57eb0baf17ce / 58.0a1 / 20171111100349 / files
nightly linux64
57eb0baf17ce / 58.0a1 / 20171111100349 / files
nightly mac
57eb0baf17ce / 58.0a1 / 20171111100349 / files
nightly win32
57eb0baf17ce / 58.0a1 / 20171111100349 / files
nightly win64
57eb0baf17ce / 58.0a1 / 20171111100349 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central r=merge a=merge
dom/interfaces/html/nsIDOMHTMLBaseElement.idl
dom/interfaces/html/nsIDOMHTMLHtmlElement.idl
dom/interfaces/html/nsIDOMHTMLScriptElement.idl
gfx/thebes/gfxBlur.cpp
toolkit/components/extensions/ExtensionParent.jsm
--- a/.eslintignore
+++ b/.eslintignore
@@ -176,16 +176,17 @@ devtools/client/inspector/markup/test/ev
 devtools/client/netmonitor/test/xhr_bundle.js
 devtools/client/webconsole/new-console-output/test/mochitest/code_bundle_nosource.js
 devtools/client/webconsole/new-console-output/test/mochitest/code_bundle_invalidmap.js
 devtools/server/tests/unit/babel_and_browserify_script_with_source_map.js
 devtools/server/tests/unit/setBreakpoint*
 devtools/server/tests/unit/sourcemapped.js
 
 # dom/ exclusions
+dom/abort/**
 dom/animation/**
 dom/archivereader/**
 dom/asmjscache/**
 dom/audiochannel/**
 dom/base/**
 dom/battery/**
 dom/bindings/**
 dom/broadcastchannel/**
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -20,16 +20,17 @@
 #include "HTMLTableAccessibleWrap.h"
 #include "HyperTextAccessibleWrap.h"
 #include "RootAccessible.h"
 #include "nsAccUtils.h"
 #include "nsArrayUtils.h"
 #include "nsAttrName.h"
 #include "nsEventShell.h"
 #include "nsIURI.h"
+#include "nsTextFormatter.h"
 #include "OuterDocAccessible.h"
 #include "Platform.h"
 #include "Role.h"
 #ifdef MOZ_ACCESSIBILITY_ATK
 #include "RootAccessibleWrap.h"
 #endif
 #include "States.h"
 #include "Statistics.h"
@@ -1379,18 +1380,17 @@ void
 nsAccessibilityService::Shutdown()
 {
   // Application is going to be closed, shutdown accessibility and mark
   // accessibility service as shutdown to prevent calls of its methods.
   // Don't null accessibility service static member at this point to be safe
   // if someone will try to operate with it.
 
   MOZ_ASSERT(gConsumers, "Accessibility was shutdown already");
-
-  gConsumers = 0;
+  UnsetConsumers(eXPCOM | eMainProcess | ePlatformAPI);
 
   // Remove observers.
   nsCOMPtr<nsIObserverService> observerService =
       mozilla::services::GetObserverService();
   if (observerService) {
     observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
 
     static const char16_t kShutdownIndicator[] = { '0', 0 };
@@ -1838,30 +1838,71 @@ nsAccessibilityService::CreateAccessible
 
   // Table or tree table accessible.
   RefPtr<Accessible> accessible =
     new XULTreeGridAccessibleWrap(aContent, aDoc, treeFrame);
   return accessible.forget();
 }
 #endif
 
+void
+nsAccessibilityService::SetConsumers(uint32_t aConsumers) {
+  if (gConsumers & aConsumers) {
+    return;
+  }
+
+  gConsumers |= aConsumers;
+  NotifyOfConsumersChange();
+}
+
+void
+nsAccessibilityService::UnsetConsumers(uint32_t aConsumers) {
+  if (!(gConsumers & aConsumers)) {
+    return;
+  }
+
+  gConsumers &= ~aConsumers;
+  NotifyOfConsumersChange();
+}
+
+void
+nsAccessibilityService::NotifyOfConsumersChange()
+{
+  nsCOMPtr<nsIObserverService> observerService =
+    mozilla::services::GetObserverService();
+
+  if (!observerService) {
+    return;
+  }
+
+  const char16_t* kJSONFmt =
+    u"{ \"XPCOM\": %s, \"MainProcess\": %s, \"PlatformAPI\": %s }";
+  nsString json;
+  nsTextFormatter::ssprintf(json, kJSONFmt,
+    gConsumers & eXPCOM ? "true" : "false",
+    gConsumers & eMainProcess ? "true" : "false",
+    gConsumers & ePlatformAPI ? "true" : "false");
+  observerService->NotifyObservers(
+    nullptr, "a11y-consumers-changed", json.get());
+}
+
 nsAccessibilityService*
 GetOrCreateAccService(uint32_t aNewConsumer)
 {
   if (!nsAccessibilityService::gAccessibilityService) {
     RefPtr<nsAccessibilityService> service = new nsAccessibilityService();
     if (!service->Init()) {
       service->Shutdown();
       return nullptr;
     }
   }
 
   MOZ_ASSERT(nsAccessibilityService::gAccessibilityService,
              "Accessible service is not initialized.");
-  nsAccessibilityService::gConsumers |= aNewConsumer;
+  nsAccessibilityService::gAccessibilityService->SetConsumers(aNewConsumer);
   return nsAccessibilityService::gAccessibilityService;
 }
 
 void
 MaybeShutdownAccService(uint32_t aFormerConsumer)
 {
   nsAccessibilityService* accService =
     nsAccessibilityService::gAccessibilityService;
@@ -1869,24 +1910,25 @@ MaybeShutdownAccService(uint32_t aFormer
   if (!accService || accService->IsShutdown()) {
     return;
   }
 
   if (nsCoreUtils::AccEventObserversExist() ||
       xpcAccessibilityService::IsInUse() ||
       accService->HasXPCDocuments()) {
     // Still used by XPCOM
-    nsAccessibilityService::gConsumers =
-      (nsAccessibilityService::gConsumers & ~aFormerConsumer) |
-      nsAccessibilityService::eXPCOM;
+    if (aFormerConsumer != nsAccessibilityService::eXPCOM) {
+      // Only unset non-XPCOM consumers.
+      accService->UnsetConsumers(aFormerConsumer);
+    }
     return;
   }
 
   if (nsAccessibilityService::gConsumers & ~aFormerConsumer) {
-    nsAccessibilityService::gConsumers &= ~aFormerConsumer;
+    accService->UnsetConsumers(aFormerConsumer);
   } else {
     accService->Shutdown(); // Will unset all nsAccessibilityService::gConsumers
   }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Services
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/base/nsAccessibilityService.h
+++ b/accessible/base/nsAccessibilityService.h
@@ -288,16 +288,31 @@ private:
 
   /**
    * Create an accessible whose type depends on the given frame.
    */
   already_AddRefed<Accessible>
     CreateAccessibleByFrameType(nsIFrame* aFrame, nsIContent* aContent,
                                 Accessible* aContext);
 
+  /**
+   * Notify observers about change of the accessibility service's consumers.
+   */
+  void NotifyOfConsumersChange();
+
+  /**
+   * Set accessibility service consumers.
+   */
+  void SetConsumers(uint32_t aConsumers);
+
+  /**
+   * Unset accessibility service consumers.
+   */
+  void UnsetConsumers(uint32_t aConsumers);
+
 #ifdef MOZ_XUL
   /**
    * Create accessible for XUL tree element.
    */
   already_AddRefed<Accessible>
     CreateAccessibleForXULTree(nsIContent* aContent, DocAccessible* aDoc);
 #endif
 
--- a/accessible/tests/browser/browser_shutdown_remote_no_reference.js
+++ b/accessible/tests/browser/browser_shutdown_remote_no_reference.js
@@ -20,29 +20,47 @@ add_task(async function() {
       </html>`
   }, async function(browser) {
     info("Creating a service in parent and waiting for service to be created " +
       "in content");
     // Create a11y service in the main process. This will trigger creating of
     // the a11y service in parent as well.
     let parentA11yInit = initPromise();
     let contentA11yInit = initPromise(browser);
+    let parentConsumersChanged = a11yConsumersChangedPromise();
+    let contentConsumersChanged =
+      ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
     let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
       Ci.nsIAccessibilityService);
     ok(accService, "Service initialized in parent");
     await Promise.all([parentA11yInit, contentA11yInit]);
+    await parentConsumersChanged.then(data => Assert.deepEqual(data, {
+      XPCOM: true, MainProcess: false, PlatformAPI: false
+    }, "Accessibility service consumers in parent are correct."));
+    await contentConsumersChanged.then(data => Assert.deepEqual(data, {
+      XPCOM: false, MainProcess: true, PlatformAPI: false
+    }, "Accessibility service consumers in content are correct."));
 
     info("Removing a service in parent and waiting for service to be shut " +
       "down in content");
     // Remove a11y service reference in the main process.
     let parentA11yShutdown = shutdownPromise();
     let contentA11yShutdown = shutdownPromise(browser);
+    parentConsumersChanged = a11yConsumersChangedPromise();
+    contentConsumersChanged =
+      ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
     accService = null;
     ok(!accService, "Service is removed in parent");
     // Force garbage collection that should trigger shutdown in both main and
     // content process.
     forceGC();
     await Promise.all([parentA11yShutdown, contentA11yShutdown]);
+    await parentConsumersChanged.then(data => Assert.deepEqual(data, {
+      XPCOM: false, MainProcess: false, PlatformAPI: false
+    }, "Accessibility service consumers are correct."));
+    await contentConsumersChanged.then(data => Assert.deepEqual(data, {
+      XPCOM: false, MainProcess: false, PlatformAPI: false
+    }, "Accessibility service consumers are correct."));
   });
 
   // Unsetting e10s related preferences.
   await unsetE10sPrefs();
 });
--- a/accessible/tests/browser/browser_shutdown_remote_own_reference.js
+++ b/accessible/tests/browser/browser_shutdown_remote_own_reference.js
@@ -20,56 +20,76 @@ add_task(async function() {
       </html>`
   }, async function(browser) {
     info("Creating a service in parent and waiting for service to be created " +
       "in content");
     // Create a11y service in the main process. This will trigger creating of
     // the a11y service in parent as well.
     let parentA11yInit = initPromise();
     let contentA11yInit = initPromise(browser);
+    let contentConsumersChanged =
+      ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
     let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
       Ci.nsIAccessibilityService);
     ok(accService, "Service initialized in parent");
     await Promise.all([parentA11yInit, contentA11yInit]);
+    await contentConsumersChanged.then(data => Assert.deepEqual(data, {
+      XPCOM: false, MainProcess: true, PlatformAPI: false
+    }, "Accessibility service consumers in content are correct."));
 
     info("Adding additional reference to accessibility service in content " +
       "process");
+    contentConsumersChanged =
+      ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
     // Add a new reference to the a11y service inside the content process.
     loadFrameScripts(browser, `let accService = Components.classes[
       '@mozilla.org/accessibilityService;1'].getService(
         Components.interfaces.nsIAccessibilityService);`);
+    await contentConsumersChanged.then(data => Assert.deepEqual(data, {
+      XPCOM: true, MainProcess: true, PlatformAPI: false
+    }, "Accessibility service consumers in content are correct."));
 
     info("Shutting down a service in parent and making sure the one in " +
       "content stays alive");
     let contentCanShutdown = false;
     let parentA11yShutdown = shutdownPromise();
+    contentConsumersChanged =
+      ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
     // This promise will resolve only if contentCanShutdown flag is set to true.
     // If 'a11y-init-or-shutdown' event with '0' flag (in content) comes before
     // it can be shut down, the promise will reject.
     let contentA11yShutdown = new Promise((resolve, reject) =>
       shutdownPromise(browser).then(flag => contentCanShutdown ?
         resolve() : reject("Accessible service was shut down incorrectly")));
     // Remove a11y service reference in the main process and force garbage
     // collection. This should not trigger shutdown in content since a11y
     // service is used by XPCOM.
     accService = null;
     ok(!accService, "Service is removed in parent");
     // Force garbage collection that should not trigger shutdown because there
     // is a reference in a content process.
     forceGC();
     loadFrameScripts(browser, `Components.utils.forceGC();`);
     await parentA11yShutdown;
+    await contentConsumersChanged.then(data => Assert.deepEqual(data, {
+      XPCOM: true, MainProcess: false, PlatformAPI: false
+    }, "Accessibility service consumers in content are correct."));
 
     // Have some breathing room between a11y service shutdowns.
     await new Promise(resolve => executeSoon(resolve));
 
     info("Removing a service in content");
     // Now allow a11y service to shutdown in content.
     contentCanShutdown = true;
+    contentConsumersChanged =
+      ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
     // Remove last reference to a11y service in content and force garbage
     // collection that should trigger shutdown.
     loadFrameScripts(browser, `accService = null; Components.utils.forceGC();`);
     await contentA11yShutdown;
+    await contentConsumersChanged.then(data => Assert.deepEqual(data, {
+      XPCOM: false, MainProcess: false, PlatformAPI: false
+    }, "Accessibility service consumers in content are correct."));
 
     // Unsetting e10s related preferences.
     await unsetE10sPrefs();
   });
 });
--- a/accessible/tests/browser/head.js
+++ b/accessible/tests/browser/head.js
@@ -1,16 +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/. */
 
 "use strict";
 
 /* exported initPromise, shutdownPromise, waitForEvent, setE10sPrefs,
-            unsetE10sPrefs */
+            unsetE10sPrefs, a11yConsumersChangedPromise */
 
 /**
  * Set e10s related preferences in the test environment.
  * @return {Promise} promise that resolves when preferences are set.
  */
 function setE10sPrefs() {
   return new Promise(resolve =>
     SpecialPowers.pushPrefEnv({
@@ -33,16 +33,30 @@ function unsetE10sPrefs() {
 
 // Load the shared-head file first.
 /* import-globals-from shared-head.js */
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
   this);
 
 /**
+ * Returns a promise that resolves when 'a11y-consumers-changed' event is fired.
+ * @return {Promise} event promise evaluating to event's data
+ */
+function a11yConsumersChangedPromise() {
+  return new Promise(resolve => {
+    let observe = (subject, topic, data) => {
+      Services.obs.removeObserver(observe, "a11y-consumers-changed");
+      resolve(JSON.parse(data));
+    };
+    Services.obs.addObserver(observe, "a11y-consumers-changed");
+  });
+}
+
+/**
  * Returns a promise that resolves when 'a11y-init-or-shutdown' event is fired.
  * @return {Promise} event promise evaluating to event's data
  */
 function a11yInitOrShutdownPromise() {
   return new Promise(resolve => {
     let observe = (subject, topic, data) => {
       Services.obs.removeObserver(observe, "a11y-init-or-shutdown");
       resolve(data);
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -10,19 +10,17 @@ var Cu = Components.utils;
 var Cc = Components.classes;
 var Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/AppConstants.jsm");
 Cu.import("resource://gre/modules/NotificationDB.jsm");
 
-XPCOMUtils.defineLazyGetter(this, "extensionNameFromURI", () => {
-  return Cu.import("resource://gre/modules/ExtensionParent.jsm", {}).extensionNameFromURI;
-});
+const {WebExtensionPolicy} = Cu.getGlobalForObject(Services);
 
 // lazy module getters
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   AboutHome: "resource:///modules/AboutHome.jsm",
   BrowserUITelemetry: "resource:///modules/BrowserUITelemetry.jsm",
   BrowserUsageTelemetry: "resource:///modules/BrowserUsageTelemetry.jsm",
   BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
@@ -7123,19 +7121,19 @@ var gIdentityHandler = {
    *
    * These URIs, like "about:" and "data:" URIs, will usually be treated as a
    * non-secure connection, unless they refer to an internally implemented
    * browser page or resolve to "file:" URIs.
    */
   _uriHasHost: false,
 
   /**
-   * Whether this is a "moz-extension:" page, loaded from a WebExtension.
+   * If this tab belongs to a WebExtension, contains its WebExtensionPolicy.
    */
-  _isExtensionPage: false,
+  _pageExtensionPolicy: null,
 
   /**
    * Whether this._uri refers to an internally implemented browser page.
    *
    * Note that this is set for some "about:" pages, but general "chrome:" URIs
    * are not included in this category by default.
    */
   _isSecureInternalUI: false,
@@ -7566,19 +7564,19 @@ var gIdentityHandler = {
         // swap the positions of the organization and country code labels.
         // The Unicode ranges reflect the definition of the UCS2_CHAR_IS_BIDI
         // macro in intl/unicharutil/util/nsBidiUtils.h. When bug 218823 gets
         // fixed, this test should be replaced by one adhering to the
         // Unicode Bidirectional Algorithm proper (at the paragraph level).
         icon_labels_dir = /^[\u0590-\u08ff\ufb1d-\ufdff\ufe70-\ufefc]/.test(icon_label) ?
                           "rtl" : "ltr";
       }
-    } else if (this._isExtensionPage) {
+    } else if (this._pageExtensionPolicy) {
       this._identityBox.className = "extensionPage";
-      let extensionName = extensionNameFromURI(this._uri);
+      let extensionName = this._pageExtensionPolicy.name;
       icon_label = gNavigatorBundle.getFormattedString(
         "identity.extension.label", [extensionName]);
     } else if (this._uriHasHost && this._isSecure) {
       this._identityBox.className = "verifiedDomain";
       if (this._isMixedActiveContentBlocked) {
         this._identityBox.classList.add("mixedActiveBlocked");
       }
       if (!this._isCertUserOverridden) {
@@ -7647,18 +7645,18 @@ var gIdentityHandler = {
         gBrowser.selectedBrowser.blockedPopups.length) {
       let icon = permissionAnchors.popup;
       icon.setAttribute("showing", "true");
     }
 
     // Push the appropriate strings out to the UI
     this._connectionIcon.setAttribute("tooltiptext", tooltip);
 
-    if (this._isExtensionPage) {
-      let extensionName = extensionNameFromURI(this._uri);
+    if (this._pageExtensionPolicy) {
+      let extensionName = this._pageExtensionPolicy.name;
       this._extensionIcon.setAttribute("tooltiptext",
         gNavigatorBundle.getFormattedString("identity.extension.tooltip", [extensionName]));
     }
 
     this._identityIconLabels.setAttribute("tooltiptext", tooltip);
     this._identityIcon.setAttribute("tooltiptext", gNavigatorBundle.getString("identity.icon.tooltip"));
     this._identityIconLabel.setAttribute("value", icon_label);
     this._identityIconCountryLabel.setAttribute("value", icon_country_label);
@@ -7684,17 +7682,17 @@ var gIdentityHandler = {
 
     // The expander switches its tooltip when toggled, change it to the default.
     this._popupExpander.tooltipText = gNavigatorBundle.getString("identity.showDetails.tooltip");
 
     // Determine connection security information.
     let connection = "not-secure";
     if (this._isSecureInternalUI) {
       connection = "chrome";
-    } else if (this._isExtensionPage) {
+    } else if (this._pageExtensionPolicy) {
       connection = "extension";
     } else if (this._isURILoadedFromFile) {
       connection = "file";
     } else if (this._isEV) {
       connection = "secure-ev";
     } else if (this._isCertUserOverridden) {
       connection = "secure-cert-user-overridden";
     } else if (this._isSecure) {
@@ -7766,18 +7764,18 @@ var gIdentityHandler = {
     // Fallback for special protocols.
     if (!host) {
       host = this._uri.specIgnoringRef;
       // Special URIs without a host (eg, about:) should crop the end so
       // the protocol can be seen.
       hostless = true;
     }
 
-    if (this._isExtensionPage) {
-      host = extensionNameFromURI(this._uri);
+    if (this._pageExtensionPolicy) {
+      host = this._pageExtensionPolicy.name;
     }
 
     // Fill in the CA name if we have a valid TLS certificate.
     if (this._isSecure || this._isCertUserOverridden) {
       verifier = this._identityIconLabels.tooltipText;
     }
 
     // Fill in organization information if we have a valid EV certificate.
@@ -7823,17 +7821,17 @@ var gIdentityHandler = {
       this._uriHasHost = true;
     } catch (ex) {
       this._uriHasHost = false;
     }
 
     this._isSecureInternalUI = uri.schemeIs("about") &&
       this._secureInternalUIWhitelist.test(uri.pathQueryRef);
 
-    this._isExtensionPage = uri.schemeIs("moz-extension");
+    this._pageExtensionPolicy = WebExtensionPolicy.getByURI(uri);
 
     // Create a channel for the sole purpose of getting the resolved URI
     // of the request to determine if it's loaded from the file system.
     this._isURILoadedFromFile = false;
     let chanOptions = {uri: this._uri, loadUsingSystemPrincipal: true};
     let resolvedURI;
     try {
       resolvedURI = NetUtil.newChannel(chanOptions).URI;
--- a/browser/components/extensions/ext-bookmarks.js
+++ b/browser/components/extensions/ext-bookmarks.js
@@ -1,17 +1,16 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 // The ext-* files are imported into the same scopes.
 /* import-globals-from ext-browserAction.js */
 
-XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
-                                  "resource://gre/modules/PlacesUtils.jsm");
+Cu.import("resource://gre/modules/PlacesUtils.jsm");
 
 const {
   TYPE_BOOKMARK,
   TYPE_FOLDER,
   TYPE_SEPARATOR,
 } = PlacesUtils.bookmarks;
 
 const BOOKMARKS_TYPES_TO_API_TYPES_MAP = new Map([
--- a/browser/components/extensions/ext-devtools-inspectedWindow.js
+++ b/browser/components/extensions/ext-devtools-inspectedWindow.js
@@ -1,19 +1,16 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 // The ext-* files are imported into the same scopes.
 /* import-globals-from ext-devtools.js */
 /* import-globals-from ext-browser.js */
 
-XPCOMUtils.defineLazyModuleGetter(this, "DevToolsShim",
-                                  "chrome://devtools-shim/content/DevToolsShim.jsm");
-
 var {
   SpreadArgs,
 } = ExtensionCommon;
 
 this.devtools_inspectedWindow = class extends ExtensionAPI {
   getAPI(context) {
     // Lazily retrieved inspectedWindow actor front per child context.
     let waitForInspectedWindowFront;
--- a/browser/components/extensions/ext-geckoProfiler.js
+++ b/browser/components/extensions/ext-geckoProfiler.js
@@ -1,20 +1,19 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 // The ext-* files are imported into the same scopes.
 /* import-globals-from ../../../toolkit/components/extensions/ext-toolkit.js */
 
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.importGlobalProperties(["fetch", "TextEncoder", "TextDecoder"]);
+Cu.importGlobalProperties(["TextEncoder", "TextDecoder"]);
 
 XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "ParseSymbols", "resource:///modules/ParseSymbols.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Subprocess", "resource://gre/modules/Subprocess.jsm");
 
 const PREF_ASYNC_STACK = "javascript.options.asyncstack";
 const PREF_SYMBOLS_URL = "extensions.geckoProfiler.symbols.url";
 const PREF_GET_SYMBOL_RULES = "extensions.geckoProfiler.getSymbolRules";
 
 const ASYNC_STACKS_ENABLED = Services.prefs.getBoolPref(PREF_ASYNC_STACK, false);
 
--- a/browser/components/extensions/ext-sidebarAction.js
+++ b/browser/components/extensions/ext-sidebarAction.js
@@ -1,20 +1,15 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 // The ext-* files are imported into the same scopes.
 /* import-globals-from ext-browser.js */
 
-XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
-                                  "resource:///modules/CustomizableUI.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Services",
-                                  "resource://gre/modules/Services.jsm");
-
 Cu.import("resource://gre/modules/ExtensionParent.jsm");
 
 var {
   ExtensionError,
 } = ExtensionUtils;
 
 var {
   IconDetails,
--- a/docshell/base/nsDocShellTreeOwner.cpp
+++ b/docshell/base/nsDocShellTreeOwner.cpp
@@ -33,17 +33,16 @@
 #include "Link.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/SVGTitleElement.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMFileList.h"
 #include "nsIDOMMouseEvent.h"
 #include "nsIFormControl.h"
 #include "nsIDOMHTMLInputElement.h"
-#include "nsIDOMHTMLHtmlElement.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIImageLoadingContent.h"
 #include "nsIWebNavigation.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIPresShell.h"
 #include "nsIStringBundle.h"
 #include "nsPIDOMWindow.h"
 #include "nsPIWindowRoot.h"
--- a/dom/abort/tests/moz.build
+++ b/dom/abort/tests/moz.build
@@ -1,7 +1,9 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MOCHITEST_MANIFESTS += ['mochitest.ini']
+
+XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
new file mode 100644
--- /dev/null
+++ b/dom/abort/tests/unit/test_abort.js
@@ -0,0 +1,8 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function run_test() {
+  let ac = new AbortController();
+  do_check_true(ac instanceof AbortController);
+  do_check_true(ac.signal instanceof AbortSignal);
+}
new file mode 100644
--- /dev/null
+++ b/dom/abort/tests/unit/xpcshell.ini
@@ -0,0 +1,5 @@
+[DEFAULT]
+head =
+support-files =
+
+[test_abort.js]
--- a/dom/html/HTMLScriptElement.cpp
+++ b/dom/html/HTMLScriptElement.cpp
@@ -43,17 +43,16 @@ HTMLScriptElement::HTMLScriptElement(alr
   AddMutationObserver(this);
 }
 
 HTMLScriptElement::~HTMLScriptElement()
 {
 }
 
 NS_IMPL_ISUPPORTS_INHERITED(HTMLScriptElement, nsGenericHTMLElement,
-                            nsIDOMHTMLScriptElement,
                             nsIScriptLoaderObserver,
                             nsIScriptElement,
                             nsIMutationObserver)
 
 nsresult
 HTMLScriptElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers)
@@ -110,133 +109,16 @@ HTMLScriptElement::Clone(mozilla::dom::N
   it->mLineNumber = mLineNumber;
   it->mMalformed = mMalformed;
 
   kungFuDeathGrip.swap(*aResult);
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-HTMLScriptElement::GetText(nsAString& aValue)
-{
-  if (!nsContentUtils::GetNodeTextContent(this, false, aValue, fallible)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-HTMLScriptElement::SetText(const nsAString& aValue)
-{
-  ErrorResult rv;
-  SetText(aValue, rv);
-  return rv.StealNSResult();
-}
-
-void
-HTMLScriptElement::SetText(const nsAString& aValue, ErrorResult& rv)
-{
-  rv = nsContentUtils::SetNodeTextContent(this, aValue, true);
-}
-
-
-NS_IMPL_STRING_ATTR(HTMLScriptElement, Charset, charset)
-NS_IMPL_BOOL_ATTR(HTMLScriptElement, Defer, defer)
-// If this ever gets changed to return "" if the attr value is "" (see
-// https://github.com/whatwg/html/issues/1739 for why it might not get changed),
-// it may be worth it to use GetSrc instead of GetAttr and manual
-// NewURIWithDocumentCharset in FreezeUriAsyncDefer.
-NS_IMPL_URI_ATTR(HTMLScriptElement, Src, src)
-NS_IMPL_STRING_ATTR(HTMLScriptElement, Type, type)
-NS_IMPL_STRING_ATTR(HTMLScriptElement, HtmlFor, _for)
-NS_IMPL_STRING_ATTR(HTMLScriptElement, Event, event)
-
-void
-HTMLScriptElement::SetCharset(const nsAString& aCharset, ErrorResult& rv)
-{
-  SetHTMLAttr(nsGkAtoms::charset, aCharset, rv);
-}
-
-void
-HTMLScriptElement::SetDefer(bool aDefer, ErrorResult& rv)
-{
-  SetHTMLBoolAttr(nsGkAtoms::defer, aDefer, rv);
-}
-
-bool
-HTMLScriptElement::Defer()
-{
-  return GetBoolAttr(nsGkAtoms::defer);
-}
-
-void
-HTMLScriptElement::SetSrc(const nsAString& aSrc, nsIPrincipal& aTriggeringPrincipal, ErrorResult& rv)
-{
-  SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, rv);
-}
-
-void
-HTMLScriptElement::SetType(const nsAString& aType, ErrorResult& rv)
-{
-  SetHTMLAttr(nsGkAtoms::type, aType, rv);
-}
-
-void
-HTMLScriptElement::SetHtmlFor(const nsAString& aHtmlFor, ErrorResult& rv)
-{
-  SetHTMLAttr(nsGkAtoms::_for, aHtmlFor, rv);
-}
-
-void
-HTMLScriptElement::SetEvent(const nsAString& aEvent, ErrorResult& rv)
-{
-  SetHTMLAttr(nsGkAtoms::event, aEvent, rv);
-}
-
-nsresult
-HTMLScriptElement::GetAsync(bool* aValue)
-{
-  *aValue = Async();
-  return NS_OK;
-}
-
-bool
-HTMLScriptElement::Async()
-{
-  return mForceAsync || GetBoolAttr(nsGkAtoms::async);
-}
-
-nsresult
-HTMLScriptElement::SetAsync(bool aValue)
-{
-  ErrorResult rv;
-  SetAsync(aValue, rv);
-  return rv.StealNSResult();
-}
-
-void
-HTMLScriptElement::SetAsync(bool aValue, ErrorResult& rv)
-{
-  mForceAsync = false;
-  SetHTMLBoolAttr(nsGkAtoms::async, aValue, rv);
-}
-
-bool
-HTMLScriptElement::NoModule()
-{
-  return GetBoolAttr(nsGkAtoms::nomodule);
-}
-
-void
-HTMLScriptElement::SetNoModule(bool aValue, ErrorResult& aRv)
-{
-  SetHTMLBoolAttr(nsGkAtoms::nomodule, aValue, aRv);
-}
-
 nsresult
 HTMLScriptElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
                                 const nsAttrValue* aValue,
                                 const nsAttrValue* aOldValue,
                                 nsIPrincipal* aMaybeScriptedPrincipal,
                                 bool aNotify)
 {
   if (nsGkAtoms::async == aName && kNameSpaceID_None == aNamespaceID) {
@@ -264,29 +146,44 @@ HTMLScriptElement::GetInnerHTML(nsAStrin
 
 void
 HTMLScriptElement::SetInnerHTML(const nsAString& aInnerHTML,
                                 ErrorResult& aError)
 {
   aError = nsContentUtils::SetNodeTextContent(this, aInnerHTML, true);
 }
 
+void
+HTMLScriptElement::GetText(nsAString& aValue, ErrorResult& aRv)
+{
+  if (!nsContentUtils::GetNodeTextContent(this, false, aValue, fallible)) {
+    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+  }
+}
+
+void
+HTMLScriptElement::SetText(const nsAString& aValue, ErrorResult& aRv)
+{
+  aRv = nsContentUtils::SetNodeTextContent(this, aValue, true);
+}
+
 // variation of this code in nsSVGScriptElement - check if changes
 // need to be transfered when modifying
 
 bool
 HTMLScriptElement::GetScriptType(nsAString& type)
 {
   return GetAttr(kNameSpaceID_None, nsGkAtoms::type, type);
 }
 
 void
 HTMLScriptElement::GetScriptText(nsAString& text)
 {
-  GetText(text);
+  IgnoredErrorResult rv;
+  GetText(text, rv);
 }
 
 void
 HTMLScriptElement::GetScriptCharset(nsAString& charset)
 {
   GetCharset(charset);
 }
 
@@ -325,19 +222,18 @@ HTMLScriptElement::FreezeUriAsyncDefer()
         nsContentUtils::eDOM_PROPERTIES, "ScriptSourceEmpty",
         params, ArrayLength(params), nullptr,
         EmptyString(), GetScriptLineNumber());
     }
 
     // At this point mUri will be null for invalid URLs.
     mExternal = true;
 
-    bool defer, async;
-    GetAsync(&async);
-    GetDefer(&defer);
+    bool async = Async();
+    bool defer = Defer();
 
     mDefer = !async && defer;
     mAsync = async;
   }
 
   mFrozen = true;
 }
 
--- a/dom/html/HTMLScriptElement.h
+++ b/dom/html/HTMLScriptElement.h
@@ -2,45 +2,40 @@
 /* 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/. */
 
 #ifndef mozilla_dom_HTMLScriptElement_h
 #define mozilla_dom_HTMLScriptElement_h
 
-#include "nsIDOMHTMLScriptElement.h"
 #include "nsGenericHTMLElement.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/ScriptElement.h"
 
 namespace mozilla {
 namespace dom {
 
 class HTMLScriptElement final : public nsGenericHTMLElement,
-                                public nsIDOMHTMLScriptElement,
                                 public ScriptElement
 {
 public:
   using Element::GetText;
   using Element::SetText;
 
   HTMLScriptElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
                     FromParser aFromParser);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML) override;
   virtual void SetInnerHTML(const nsAString& aInnerHTML,
                             mozilla::ErrorResult& aError) override;
 
-  // nsIDOMHTMLScriptElement
-  NS_DECL_NSIDOMHTMLSCRIPTELEMENT
-
   // nsIScriptElement
   virtual bool GetScriptType(nsAString& type) override;
   virtual void GetScriptText(nsAString& text) override;
   virtual void GetScriptCharset(nsAString& charset) override;
   virtual void FreezeUriAsyncDefer() override;
   virtual CORSMode GetCORSMode() const override;
 
   // nsIContent
@@ -58,55 +53,127 @@ public:
   // Element
   virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
                                 const nsAttrValue* aValue,
                                 const nsAttrValue* aOldValue,
                                 nsIPrincipal* aMaybeScriptedPrincipal,
                                 bool aNotify) override;
 
   // WebIDL
-  void SetText(const nsAString& aValue, ErrorResult& rv);
-  void SetCharset(const nsAString& aCharset, ErrorResult& rv);
-  void SetDefer(bool aDefer, ErrorResult& rv);
-  bool Defer();
-  void SetSrc(const nsAString& aSrc, nsIPrincipal& aTriggeringPrincipal, ErrorResult& rv);
-  void GetSrc(nsString& aSrc, nsIPrincipal&)
+  void GetText(nsAString& aValue, ErrorResult& aRv);
+
+  void SetText(const nsAString& aValue, ErrorResult& aRv);
+
+  void GetCharset(nsAString& aCharset)
+  {
+    GetHTMLAttr(nsGkAtoms::charset, aCharset);
+  }
+  void SetCharset(const nsAString& aCharset, ErrorResult& aRv)
+  {
+    SetHTMLAttr(nsGkAtoms::charset, aCharset, aRv);
+  }
+
+  bool Defer()
+  {
+    return GetBoolAttr(nsGkAtoms::defer);
+  }
+  void SetDefer(bool aDefer, ErrorResult& aRv)
+  {
+    SetHTMLBoolAttr(nsGkAtoms::defer, aDefer, aRv);
+  }
+
+  void GetSrc(nsAString& aSrc, nsIPrincipal&)
   {
     GetSrc(aSrc);
-  };
-  void SetType(const nsAString& aType, ErrorResult& rv);
-  void SetHtmlFor(const nsAString& aHtmlFor, ErrorResult& rv);
-  void SetEvent(const nsAString& aEvent, ErrorResult& rv);
+  }
+  void GetSrc(nsAString& aSrc)
+  {
+    GetURIAttr(nsGkAtoms::src, nullptr, aSrc);
+  }
+  void SetSrc(const nsAString& aSrc, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aRv)
+  {
+    SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, aRv);
+  }
+
+  void GetType(nsAString& aType)
+  {
+    GetHTMLAttr(nsGkAtoms::type, aType);
+  }
+  void SetType(const nsAString& aType, ErrorResult& aRv)
+  {
+    SetHTMLAttr(nsGkAtoms::type, aType, aRv);
+  }
+
+  void GetHtmlFor(nsAString& aHtmlFor)
+  {
+    GetHTMLAttr(nsGkAtoms::_for, aHtmlFor);
+  }
+  void SetHtmlFor(const nsAString& aHtmlFor, ErrorResult& aRv)
+  {
+    SetHTMLAttr(nsGkAtoms::_for, aHtmlFor, aRv);
+  }
+
+  void GetEvent(nsAString& aEvent)
+  {
+    GetHTMLAttr(nsGkAtoms::event, aEvent);
+  }
+  void SetEvent(const nsAString& aEvent, ErrorResult& aRv)
+  {
+    SetHTMLAttr(nsGkAtoms::event, aEvent, aRv);
+  }
+
+  bool Async()
+  {
+    return mForceAsync || GetBoolAttr(nsGkAtoms::async);
+  }
+
+  void SetAsync(bool aValue, ErrorResult& aRv)
+  {
+    mForceAsync = false;
+    SetHTMLBoolAttr(nsGkAtoms::async, aValue, aRv);
+  }
+
+  bool NoModule()
+  {
+    return GetBoolAttr(nsGkAtoms::nomodule);
+  }
+
+  void SetNoModule(bool aValue, ErrorResult& aRv)
+  {
+    SetHTMLBoolAttr(nsGkAtoms::nomodule, aValue, aRv);
+  }
+
   void GetCrossOrigin(nsAString& aResult)
   {
     // Null for both missing and invalid defaults is ok, since we
     // always parse to an enum value, so we don't need an invalid
     // default, and we _want_ the missing default to be null.
     GetEnumAttr(nsGkAtoms::crossorigin, nullptr, aResult);
   }
   void SetCrossOrigin(const nsAString& aCrossOrigin, ErrorResult& aError)
   {
     SetOrRemoveNullableStringAttr(nsGkAtoms::crossorigin, aCrossOrigin, aError);
   }
   void GetIntegrity(nsAString& aIntegrity)
   {
     GetHTMLAttr(nsGkAtoms::integrity, aIntegrity);
   }
-  void SetIntegrity(const nsAString& aIntegrity, ErrorResult& rv)
+  void SetIntegrity(const nsAString& aIntegrity, ErrorResult& aRv)
   {
-    SetHTMLAttr(nsGkAtoms::integrity, aIntegrity, rv);
+    SetHTMLAttr(nsGkAtoms::integrity, aIntegrity, aRv);
   }
-  bool Async();
-  void SetAsync(bool aValue, ErrorResult& rv);
-  bool NoModule();
-  void SetNoModule(bool aValue, ErrorResult& rv);
 
 protected:
   virtual ~HTMLScriptElement();
 
+  virtual bool GetAsyncState() override
+  {
+    return Async();
+  }
+
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   // ScriptElement
   virtual bool HasScriptContent() override;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/html/HTMLSharedElement.cpp
+++ b/dom/html/HTMLSharedElement.cpp
@@ -26,72 +26,41 @@ namespace mozilla {
 namespace dom {
 
 extern nsAttrValue::EnumTable kListTypeTable[];
 
 HTMLSharedElement::~HTMLSharedElement()
 {
 }
 
-NS_IMPL_ADDREF_INHERITED(HTMLSharedElement, nsGenericHTMLElement)
-NS_IMPL_RELEASE_INHERITED(HTMLSharedElement, nsGenericHTMLElement)
-
-// QueryInterface implementation for HTMLSharedElement
-NS_INTERFACE_MAP_BEGIN(HTMLSharedElement)
-  NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLBaseElement, base)
-  NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLHtmlElement, html)
-NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
-
-
 NS_IMPL_ELEMENT_CLONE(HTMLSharedElement)
 
-// nsIDOMHTMLQuoteElement
-// Empty
-
-// nsIDOMHTMLHeadElement
-// Empty
-
-// nsIDOMHTMLHtmlElement
-NS_IMPL_STRING_ATTR(HTMLSharedElement, Version, version)
-
-// nsIDOMHTMLBaseElement
-NS_IMPL_STRING_ATTR(HTMLSharedElement, Target, target)
-
-NS_IMETHODIMP
+void
 HTMLSharedElement::GetHref(nsAString& aValue)
 {
   MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::base),
              "This should only get called for <base> elements");
   nsAutoString href;
   GetAttr(kNameSpaceID_None, nsGkAtoms::href, href);
 
   nsCOMPtr<nsIURI> uri;
   nsIDocument* doc = OwnerDoc();
   nsContentUtils::NewURIWithDocumentCharset(
     getter_AddRefs(uri), href, doc, doc->GetFallbackBaseURI());
 
   if (!uri) {
     aValue = href;
-    return NS_OK;
+    return;
   }
 
   nsAutoCString spec;
   uri->GetSpec(spec);
   CopyUTF8toUTF16(spec, aValue);
-
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-HTMLSharedElement::SetHref(const nsAString& aValue)
-{
-  return SetAttrHelper(nsGkAtoms::href, aValue);
-}
-
-
 bool
 HTMLSharedElement::ParseAttribute(int32_t aNamespaceID,
                                   nsAtom* aAttribute,
                                   const nsAString& aValue,
                                   nsAttrValue& aResult)
 {
   if (aNamespaceID == kNameSpaceID_None &&
       mNodeInfo->Equals(nsGkAtoms::dir)) {
--- a/dom/html/HTMLSharedElement.h
+++ b/dom/html/HTMLSharedElement.h
@@ -2,51 +2,38 @@
 /* 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/. */
 
 #ifndef mozilla_dom_HTMLSharedElement_h
 #define mozilla_dom_HTMLSharedElement_h
 
-#include "nsIDOMHTMLBaseElement.h"
-#include "nsIDOMHTMLHtmlElement.h"
 #include "nsGenericHTMLElement.h"
 
 #include "nsGkAtoms.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Assertions.h"
 
 namespace mozilla {
 namespace dom {
 
-class HTMLSharedElement final : public nsGenericHTMLElement,
-                                public nsIDOMHTMLBaseElement,
-                                public nsIDOMHTMLHtmlElement
+class HTMLSharedElement final : public nsGenericHTMLElement
 {
 public:
   explicit HTMLSharedElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
     : nsGenericHTMLElement(aNodeInfo)
   {
     if (mNodeInfo->Equals(nsGkAtoms::head) ||
         mNodeInfo->Equals(nsGkAtoms::html)) {
       SetHasWeirdParserInsertionMode();
     }
   }
 
-  // nsISupports
-  NS_DECL_ISUPPORTS_INHERITED
-
-  // nsIDOMHTMLBaseElement
-  NS_DECL_NSIDOMHTMLBASEELEMENT
-
-  // nsIDOMHTMLHtmlElement
-  NS_DECL_NSIDOMHTMLHTMLELEMENT
-
   // nsIContent
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) override;
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
@@ -110,17 +97,18 @@ public:
     MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::base));
     GetHTMLAttr(nsGkAtoms::target, aValue);
   }
   void SetTarget(const nsAString& aValue, ErrorResult& aResult)
   {
     MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::base));
     SetHTMLAttr(nsGkAtoms::target, aValue, aResult);
   }
-  // The XPCOM GetHref is fine for us
+
+  void GetHref(nsAString& aValue);
   void SetHref(const nsAString& aValue, ErrorResult& aResult)
   {
     MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::base));
     SetHTMLAttr(nsGkAtoms::href, aValue, aResult);
   }
 
   // HTMLDirectoryElement
   bool Compact() const
--- a/dom/interfaces/html/moz.build
+++ b/dom/interfaces/html/moz.build
@@ -3,25 +3,22 @@
 # 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/.
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "DOM")
 
 XPIDL_SOURCES += [
-    'nsIDOMHTMLBaseElement.idl',
     'nsIDOMHTMLCollection.idl',
     'nsIDOMHTMLDocument.idl',
     'nsIDOMHTMLElement.idl',
     'nsIDOMHTMLFormElement.idl',
-    'nsIDOMHTMLHtmlElement.idl',
     'nsIDOMHTMLInputElement.idl',
     'nsIDOMHTMLMediaElement.idl',
-    'nsIDOMHTMLScriptElement.idl',
     'nsIDOMMozBrowserFrame.idl',
     'nsIDOMTimeRanges.idl',
     'nsIDOMValidityState.idl',
     'nsIMozBrowserFrame.idl',
 ]
 
 XPIDL_MODULE = 'dom_html'
 
deleted file mode 100644
--- a/dom/interfaces/html/nsIDOMHTMLBaseElement.idl
+++ /dev/null
@@ -1,24 +0,0 @@
-/* -*- 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/. */
-
-#include "nsIDOMHTMLElement.idl"
-
-/**
- * The nsIDOMHTMLBaseElement interface is the interface to a [X]HTML
- * base element.
- *
- * This interface is trying to follow the DOM Level 2 HTML specification:
- * http://www.w3.org/TR/DOM-Level-2-HTML/
- *
- * with changes from the work-in-progress WHATWG HTML specification:
- * http://www.whatwg.org/specs/web-apps/current-work/
- */
-
-[uuid(a348ac22-7880-4613-af4c-984ec2ef5adc)]
-interface nsIDOMHTMLBaseElement : nsISupports
-{
-           attribute DOMString        href;
-           attribute DOMString        target;
-};
deleted file mode 100644
--- a/dom/interfaces/html/nsIDOMHTMLHtmlElement.idl
+++ /dev/null
@@ -1,23 +0,0 @@
-/* -*- 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/. */
-
-#include "nsIDOMHTMLElement.idl"
-
-/**
- * The nsIDOMHTMLHtmlElement interface is the interface to a [X]HTML
- * html element.
- *
- * This interface is trying to follow the DOM Level 2 HTML specification:
- * http://www.w3.org/TR/DOM-Level-2-HTML/
- *
- * with changes from the work-in-progress WHATWG HTML specification:
- * http://www.whatwg.org/specs/web-apps/current-work/
- */
-
-[uuid(6a5d2ce7-2c45-43c1-bdab-9df7a06caed1)]
-interface nsIDOMHTMLHtmlElement : nsISupports
-{
-           attribute DOMString        version;
-};
deleted file mode 100644
--- a/dom/interfaces/html/nsIDOMHTMLScriptElement.idl
+++ /dev/null
@@ -1,31 +0,0 @@
-/* -*- 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/. */
-
-#include "nsIDOMHTMLElement.idl"
-
-/**
- * The nsIDOMHTMLScriptElement interface is the interface to a [X]HTML
- * script element.
- *
- * This interface is trying to follow the DOM Level 2 HTML specification:
- * http://www.w3.org/TR/DOM-Level-2-HTML/
- *
- * with changes from the work-in-progress WHATWG HTML specification:
- * http://www.whatwg.org/specs/web-apps/current-work/
- */
-
-[uuid(fe96dc1c-40e4-4974-9354-e3fce663c3d5)]
-interface nsIDOMHTMLScriptElement : nsISupports
-{
-           attribute DOMString        src;
-           attribute boolean          async;
-           attribute boolean          defer;
-           attribute DOMString        type;
-           attribute DOMString        charset;
-           attribute DOMString        text;
-
-           attribute DOMString        htmlFor;
-           attribute DOMString        event;
-};
--- a/dom/script/ScriptLoader.cpp
+++ b/dom/script/ScriptLoader.cpp
@@ -32,17 +32,16 @@
 #include "nsJSPrincipals.h"
 #include "nsContentPolicyUtils.h"
 #include "nsIHttpChannel.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIClassOfService.h"
 #include "nsICacheInfoChannel.h"
 #include "nsITimedChannel.h"
 #include "nsIScriptElement.h"
-#include "nsIDOMHTMLScriptElement.h"
 #include "nsIDocShell.h"
 #include "nsContentUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsAutoPtr.h"
 #include "nsIXPConnect.h"
 #include "nsError.h"
 #include "nsThreadUtils.h"
 #include "nsDocShellCID.h"
--- a/dom/script/nsIScriptElement.h
+++ b/dom/script/nsIScriptElement.h
@@ -8,18 +8,18 @@
 #define nsIScriptElement_h___
 
 #include "nsISupports.h"
 #include "nsIURI.h"
 #include "nsCOMPtr.h"
 #include "nsIScriptLoaderObserver.h"
 #include "nsWeakPtr.h"
 #include "nsIParser.h"
+#include "nsIContent.h"
 #include "nsContentCreatorFunctions.h"
-#include "nsIDOMHTMLScriptElement.h"
 #include "mozilla/CORSMode.h"
 
 #define NS_ISCRIPTELEMENT_IID \
 { 0xe60fca9b, 0x1b96, 0x4e4e, \
  { 0xa9, 0xb4, 0xdc, 0x98, 0x4f, 0x88, 0x3f, 0x9c } }
 
 /**
  * Internal interface implemented by script elements
@@ -147,22 +147,17 @@ public:
   }
 
   void LoseParserInsertedness()
   {
     mFrozen = false;
     mUri = nullptr;
     mCreatorParser = nullptr;
     mParserCreated = mozilla::dom::NOT_FROM_PARSER;
-    bool async = false;
-    nsCOMPtr<nsIDOMHTMLScriptElement> htmlScript = do_QueryInterface(this);
-    if (htmlScript) {
-      htmlScript->GetAsync(&async);
-    }
-    mForceAsync = !async;
+    mForceAsync = !GetAsyncState();
   }
 
   void SetCreatorParser(nsIParser* aParser)
   {
     mCreatorParser = do_GetWeakReference(aParser);
   }
 
   /**
@@ -266,16 +261,22 @@ protected:
    * document-tree.
    *
    * @return whether the parser will be blocked while this script is being
    *         loaded
    */
   virtual bool MaybeProcessScript() = 0;
 
   /**
+   * Since we've removed the XPCOM interface to HTML elements, we need a way to
+   * retreive async state from script elements without bringing the type in.
+   */
+  virtual bool GetAsyncState() = 0;
+
+  /**
    * The start line number of the script.
    */
   uint32_t mLineNumber;
 
   /**
    * The "already started" flag per HTML5.
    */
   bool mAlreadyStarted;
--- a/dom/svg/SVGScriptElement.h
+++ b/dom/svg/SVGScriptElement.h
@@ -74,16 +74,23 @@ public:
   void SetCrossOrigin(const nsAString & aCrossOrigin, ErrorResult& aError);
   already_AddRefed<SVGAnimatedString> Href();
 
 protected:
   ~SVGScriptElement();
 
   virtual StringAttributesInfo GetStringInfo() override;
 
+  // SVG Script elements don't have the ability to set async properties on
+  // themselves, so this will always return false.
+  virtual bool GetAsyncState() override
+  {
+    return false;
+  }
+
   enum { HREF, XLINK_HREF };
   nsSVGString mStringAttributes[2];
   static StringInfo sStringInfo[2];
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/system/OSFileConstants.cpp
+++ b/dom/system/OSFileConstants.cpp
@@ -58,22 +58,25 @@
 #include "nsIObserver.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsIXULRuntime.h"
 #include "nsIPropertyBag2.h"
 #include "nsXPCOMCIDInternal.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsSystemInfo.h"
-#include "nsAutoPtr.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsXULAppAPI.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "mozJSComponentLoader.h"
 
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/UniquePtr.h"
+
 #include "OSFileConstants.h"
 #include "nsIOSFileConstantsService.h"
 #include "nsZipArchive.h"
 
 #if defined(__DragonFly__) || defined(__FreeBSD__) \
   || defined(__NetBSD__) || defined(__OpenBSD__)
 #define __dd_fd dd_fd
 #endif
@@ -81,25 +84,25 @@
 /**
  * This module defines the basic libc constants (error numbers, open modes,
  * etc.) used by OS.File and possibly other OS-bound JavaScript libraries.
  */
 
 
 namespace mozilla {
 
-// Use an anonymous namespace to hide the symbols and avoid any collision
-// with, for instance, |extern bool gInitialized;|
 namespace {
-/**
- * |true| if this module has been initialized, |false| otherwise
- */
-bool gInitialized = false;
+
+StaticRefPtr<OSFileConstantsService> gInstance;
 
-struct Paths {
+} // anonymous namespace
+
+struct
+OSFileConstantsService::Paths
+{
   /**
    * The name of the directory holding all the libraries (libxpcom, libnss, etc.)
    */
   nsString libDir;
   nsString tmpDir;
   nsString profileDir;
   nsString localProfileDir;
   /**
@@ -173,29 +176,16 @@ struct Paths {
     macUserLibDir.SetIsVoid(true);
     macLocalApplicationsDir.SetIsVoid(true);
     macTrashDir.SetIsVoid(true);
 #endif // defined(XP_MACOSX)
   }
 };
 
 /**
- * System directories.
- */
-Paths* gPaths = nullptr;
-
-/**
- * (Unix) the umask, which goes in OS.Constants.Sys but
- * can only be looked up (via the system-info service)
- * on the main thread.
- */
-uint32_t gUserUmask = 0;
-} // namespace
-
-/**
  * Return the path to one of the special directories.
  *
  * @param aKey The key to the special directory (e.g. "TmpD", "ProfD", ...)
  * @param aOutPath The path to the special directory. In case of error,
  * the string is set to void.
  */
 nsresult GetPathToSpecialDir(const char *aKey, nsString& aOutPath)
 {
@@ -210,65 +200,55 @@ nsresult GetPathToSpecialDir(const char 
 
 /**
  * In some cases, OSFileConstants may be instantiated before the
  * profile is setup. In such cases, |OS.Constants.Path.profileDir| and
  * |OS.Constants.Path.localProfileDir| are undefined. However, we want
  * to ensure that this does not break existing code, so that future
  * workers spawned after the profile is setup have these constants.
  *
- * For this purpose, we register an observer to set |gPaths->profileDir|
- * and |gPaths->localProfileDir| once the profile is setup.
+ * For this purpose, we register an observer to set |mPaths->profileDir|
+ * and |mPaths->localProfileDir| once the profile is setup.
  */
-class DelayedPathSetter final: public nsIObserver
+NS_IMETHODIMP
+OSFileConstantsService::Observe(nsISupports*,
+                                const char* aTopic,
+                                const char16_t*)
 {
-  ~DelayedPathSetter() {}
-
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIOBSERVER
-
-  DelayedPathSetter() {}
-};
-
-NS_IMPL_ISUPPORTS(DelayedPathSetter, nsIObserver)
-
-NS_IMETHODIMP
-DelayedPathSetter::Observe(nsISupports*, const char * aTopic, const char16_t*)
-{
-  if (gPaths == nullptr) {
-    // Initialization of gPaths has not taken place, something is wrong,
+  if (!mInitialized) {
+    // Initialization has not taken place, something is wrong,
     // don't make things worse.
     return NS_OK;
   }
-  nsresult rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_50_DIR, gPaths->profileDir);
+
+  nsresult rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_50_DIR, mPaths->profileDir);
   if (NS_FAILED(rv)) {
     return rv;
   }
-  rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_LOCAL_50_DIR, gPaths->localProfileDir);
+  rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_LOCAL_50_DIR, mPaths->localProfileDir);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   return NS_OK;
 }
 
 /**
  * Perform the part of initialization that can only be
  * executed on the main thread.
  */
-nsresult InitOSFileConstants()
+nsresult
+OSFileConstantsService::InitOSFileConstants()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  if (gInitialized) {
+  if (mInitialized) {
     return NS_OK;
   }
 
-  gInitialized = true;
-
-  nsAutoPtr<Paths> paths(new Paths);
+  UniquePtr<Paths> paths(new Paths);
 
   // Initialize paths->libDir
   nsCOMPtr<nsIFile> file;
   nsresult rv = NS_GetSpecialDirectory(NS_XPCOM_LIBRARY_FILE, getter_AddRefs(file));
   if (NS_FAILED(rv)) {
     return rv;
   }
 
@@ -293,18 +273,17 @@ nsresult InitOSFileConstants()
 
   // Otherwise, delay setup of profileDir/localProfileDir until they
   // become available.
   if (NS_FAILED(rv)) {
     nsCOMPtr<nsIObserverService> obsService = do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
     if (NS_FAILED(rv)) {
       return rv;
     }
-    RefPtr<DelayedPathSetter> pathSetter = new DelayedPathSetter();
-    rv = obsService->AddObserver(pathSetter, "profile-do-change", false);
+    rv = obsService->AddObserver(this, "profile-do-change", false);
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
 
   // For other directories, ignore errors (they may be undefined on
   // some platforms or in non-Firefox embeddings of Gecko).
 
@@ -319,45 +298,30 @@ nsresult InitOSFileConstants()
 #endif // defined(XP_WIN)
 
 #if defined(XP_MACOSX)
   GetPathToSpecialDir(NS_MAC_USER_LIB_DIR, paths->macUserLibDir);
   GetPathToSpecialDir(NS_OSX_LOCAL_APPLICATIONS_DIR, paths->macLocalApplicationsDir);
   GetPathToSpecialDir(NS_MAC_TRASH_DIR, paths->macTrashDir);
 #endif // defined(XP_MACOSX)
 
-  gPaths = paths.forget();
+  mPaths = Move(paths);
 
   // Get the umask from the system-info service.
   // The property will always be present, but it will be zero on
   // non-Unix systems.
   // nsSystemInfo::gUserUmask is initialized by NS_InitXPCOM2 so we don't need
   // to initialize the service.
-  gUserUmask = nsSystemInfo::gUserUmask;
+  mUserUmask = nsSystemInfo::gUserUmask;
 
+  mInitialized = true;
   return NS_OK;
 }
 
 /**
- * Perform the cleaning up that can only be executed on the main thread.
- */
-void CleanupOSFileConstants()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  if (!gInitialized) {
-    return;
-  }
-
-  gInitialized = false;
-  delete gPaths;
-  gPaths = nullptr;
-}
-
-
-/**
  * Define a simple read-only property holding an integer.
  *
  * @param name The name of the constant. Used both as the JS name for the
  * constant and to access its value. Must be defined.
  *
  * Produces a |ConstantSpec|.
  */
 #define INT_CONSTANT(name)      \
@@ -870,187 +834,185 @@ bool SetStringProperty(JSContext *cx, JS
 }
 
 /**
  * Define OS-specific constants.
  *
  * This function creates or uses JS object |OS.Constants| to store
  * all its constants.
  */
-bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global)
+bool
+OSFileConstantsService::DefineOSFileConstants(JSContext* aCx,
+                                              JS::Handle<JSObject*> aGlobal)
 {
-  if (!gInitialized || gPaths == nullptr) {
-    // If an initialization error was ignored, we may end up with
-    // |gInitialized == true| but |gPaths == nullptr|. We cannot
-    // |MOZ_ASSERT| this, as this would kill precompile_cache.js,
-    // so we simply return an error.
-    JS_ReportErrorNumberASCII(cx, js::GetErrorMessage, nullptr,
+  if (!mInitialized) {
+    JS_ReportErrorNumberASCII(aCx, js::GetErrorMessage, nullptr,
                               JSMSG_CANT_OPEN,
                               "OSFileConstants", "initialization has failed");
     return false;
   }
 
-  JS::Rooted<JSObject*> objOS(cx);
-  if (!(objOS = GetOrCreateObjectProperty(cx, global, "OS"))) {
+  JS::Rooted<JSObject*> objOS(aCx);
+  if (!(objOS = GetOrCreateObjectProperty(aCx, aGlobal, "OS"))) {
     return false;
   }
-  JS::Rooted<JSObject*> objConstants(cx);
-  if (!(objConstants = GetOrCreateObjectProperty(cx, objOS, "Constants"))) {
+  JS::Rooted<JSObject*> objConstants(aCx);
+  if (!(objConstants = GetOrCreateObjectProperty(aCx, objOS, "Constants"))) {
     return false;
   }
 
   // Build OS.Constants.libc
 
-  JS::Rooted<JSObject*> objLibc(cx);
-  if (!(objLibc = GetOrCreateObjectProperty(cx, objConstants, "libc"))) {
+  JS::Rooted<JSObject*> objLibc(aCx);
+  if (!(objLibc = GetOrCreateObjectProperty(aCx, objConstants, "libc"))) {
     return false;
   }
-  if (!dom::DefineConstants(cx, objLibc, gLibcProperties)) {
+  if (!dom::DefineConstants(aCx, objLibc, gLibcProperties)) {
     return false;
   }
 
 #if defined(XP_WIN)
   // Build OS.Constants.Win
 
-  JS::Rooted<JSObject*> objWin(cx);
-  if (!(objWin = GetOrCreateObjectProperty(cx, objConstants, "Win"))) {
+  JS::Rooted<JSObject*> objWin(aCx);
+  if (!(objWin = GetOrCreateObjectProperty(aCx, objConstants, "Win"))) {
     return false;
   }
-  if (!dom::DefineConstants(cx, objWin, gWinProperties)) {
+  if (!dom::DefineConstants(aCx, objWin, gWinProperties)) {
     return false;
   }
 #endif // defined(XP_WIN)
 
   // Build OS.Constants.Sys
 
-  JS::Rooted<JSObject*> objSys(cx);
-  if (!(objSys = GetOrCreateObjectProperty(cx, objConstants, "Sys"))) {
+  JS::Rooted<JSObject*> objSys(aCx);
+  if (!(objSys = GetOrCreateObjectProperty(aCx, objConstants, "Sys"))) {
     return false;
   }
 
   nsCOMPtr<nsIXULRuntime> runtime = do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
   if (runtime) {
     nsAutoCString os;
     DebugOnly<nsresult> rv = runtime->GetOS(os);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
 
-    JSString* strVersion = JS_NewStringCopyZ(cx, os.get());
+    JSString* strVersion = JS_NewStringCopyZ(aCx, os.get());
     if (!strVersion) {
       return false;
     }
 
-    JS::Rooted<JS::Value> valVersion(cx, JS::StringValue(strVersion));
-    if (!JS_SetProperty(cx, objSys, "Name", valVersion)) {
+    JS::Rooted<JS::Value> valVersion(aCx, JS::StringValue(strVersion));
+    if (!JS_SetProperty(aCx, objSys, "Name", valVersion)) {
       return false;
     }
   }
 
 #if defined(DEBUG)
-  JS::Rooted<JS::Value> valDebug(cx, JS::TrueValue());
-  if (!JS_SetProperty(cx, objSys, "DEBUG", valDebug)) {
+  JS::Rooted<JS::Value> valDebug(aCx, JS::TrueValue());
+  if (!JS_SetProperty(aCx, objSys, "DEBUG", valDebug)) {
     return false;
   }
 #endif
 
 #if defined(HAVE_64BIT_BUILD)
-  JS::Rooted<JS::Value> valBits(cx, JS::Int32Value(64));
+  JS::Rooted<JS::Value> valBits(aCx, JS::Int32Value(64));
 #else
-  JS::Rooted<JS::Value> valBits(cx, JS::Int32Value(32));
+  JS::Rooted<JS::Value> valBits(aCx, JS::Int32Value(32));
 #endif //defined (HAVE_64BIT_BUILD)
-  if (!JS_SetProperty(cx, objSys, "bits", valBits)) {
+  if (!JS_SetProperty(aCx, objSys, "bits", valBits)) {
     return false;
   }
 
-  if (!JS_DefineProperty(cx, objSys, "umask", gUserUmask,
+  if (!JS_DefineProperty(aCx, objSys, "umask", mUserUmask,
                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
       return false;
   }
 
   // Build OS.Constants.Path
 
-  JS::Rooted<JSObject*> objPath(cx);
-  if (!(objPath = GetOrCreateObjectProperty(cx, objConstants, "Path"))) {
+  JS::Rooted<JSObject*> objPath(aCx);
+  if (!(objPath = GetOrCreateObjectProperty(aCx, objConstants, "Path"))) {
     return false;
   }
 
   // Locate libxul
   // Note that we don't actually provide the full path, only the name of the
   // library, which is sufficient to link to the library using js-ctypes.
 
 #if defined(XP_MACOSX)
   // Under MacOS X, for some reason, libxul is called simply "XUL",
   // and we need to provide the full path.
   nsAutoString libxul;
-  libxul.Append(gPaths->libDir);
+  libxul.Append(mPaths->libDir);
   libxul.AppendLiteral("/XUL");
 #else
   // On other platforms, libxul is a library "xul" with regular
   // library prefix/suffix.
   nsAutoString libxul;
   libxul.AppendLiteral(DLL_PREFIX);
   libxul.AppendLiteral("xul");
   libxul.AppendLiteral(DLL_SUFFIX);
 #endif // defined(XP_MACOSX)
 
-  if (!SetStringProperty(cx, objPath, "libxul", libxul)) {
+  if (!SetStringProperty(aCx, objPath, "libxul", libxul)) {
     return false;
   }
 
-  if (!SetStringProperty(cx, objPath, "libDir", gPaths->libDir)) {
+  if (!SetStringProperty(aCx, objPath, "libDir", mPaths->libDir)) {
     return false;
   }
 
-  if (!SetStringProperty(cx, objPath, "tmpDir", gPaths->tmpDir)) {
+  if (!SetStringProperty(aCx, objPath, "tmpDir", mPaths->tmpDir)) {
     return false;
   }
 
   // Configure profileDir only if it is available at this stage
-  if (!gPaths->profileDir.IsVoid()
-    && !SetStringProperty(cx, objPath, "profileDir", gPaths->profileDir)) {
+  if (!mPaths->profileDir.IsVoid()
+    && !SetStringProperty(aCx, objPath, "profileDir", mPaths->profileDir)) {
     return false;
   }
 
   // Configure localProfileDir only if it is available at this stage
-  if (!gPaths->localProfileDir.IsVoid()
-    && !SetStringProperty(cx, objPath, "localProfileDir", gPaths->localProfileDir)) {
+  if (!mPaths->localProfileDir.IsVoid()
+    && !SetStringProperty(aCx, objPath, "localProfileDir", mPaths->localProfileDir)) {
     return false;
   }
 
-  if (!SetStringProperty(cx, objPath, "homeDir", gPaths->homeDir)) {
+  if (!SetStringProperty(aCx, objPath, "homeDir", mPaths->homeDir)) {
     return false;
   }
 
-  if (!SetStringProperty(cx, objPath, "desktopDir", gPaths->desktopDir)) {
+  if (!SetStringProperty(aCx, objPath, "desktopDir", mPaths->desktopDir)) {
     return false;
   }
 
-  if (!SetStringProperty(cx, objPath, "userApplicationDataDir", gPaths->userApplicationDataDir)) {
+  if (!SetStringProperty(aCx, objPath, "userApplicationDataDir", mPaths->userApplicationDataDir)) {
     return false;
   }
 
 #if defined(XP_WIN)
-  if (!SetStringProperty(cx, objPath, "winAppDataDir", gPaths->winAppDataDir)) {
+  if (!SetStringProperty(aCx, objPath, "winAppDataDir", mPaths->winAppDataDir)) {
     return false;
   }
 
-  if (!SetStringProperty(cx, objPath, "winStartMenuProgsDir", gPaths->winStartMenuProgsDir)) {
+  if (!SetStringProperty(aCx, objPath, "winStartMenuProgsDir", mPaths->winStartMenuProgsDir)) {
     return false;
   }
 #endif // defined(XP_WIN)
 
 #if defined(XP_MACOSX)
-  if (!SetStringProperty(cx, objPath, "macUserLibDir", gPaths->macUserLibDir)) {
+  if (!SetStringProperty(aCx, objPath, "macUserLibDir", mPaths->macUserLibDir)) {
     return false;
   }
 
-  if (!SetStringProperty(cx, objPath, "macLocalApplicationsDir", gPaths->macLocalApplicationsDir)) {
+  if (!SetStringProperty(aCx, objPath, "macLocalApplicationsDir", mPaths->macLocalApplicationsDir)) {
     return false;
   }
 
-  if (!SetStringProperty(cx, objPath, "macTrashDir", gPaths->macTrashDir)) {
+  if (!SetStringProperty(aCx, objPath, "macTrashDir", mPaths->macTrashDir)) {
     return false;
   }
 #endif // defined(XP_MACOSX)
 
   // sqlite3 is linked from different places depending on the platform
   nsAutoString libsqlite3;
 #if defined(ANDROID)
   // On Android, we use the system's libsqlite3
@@ -1062,48 +1024,72 @@ bool DefineOSFileConstants(JSContext *cx
   libsqlite3.AppendLiteral(DLL_PREFIX);
   libsqlite3.AppendLiteral("nss3");
   libsqlite3.AppendLiteral(DLL_SUFFIX);
 #else
     // On other platforms, we link sqlite3 into libxul
   libsqlite3 = libxul;
 #endif // defined(ANDROID) || defined(XP_WIN)
 
-  if (!SetStringProperty(cx, objPath, "libsqlite3", libsqlite3)) {
+  if (!SetStringProperty(aCx, objPath, "libsqlite3", libsqlite3)) {
     return false;
   }
 
   return true;
 }
 
-NS_IMPL_ISUPPORTS(OSFileConstantsService, nsIOSFileConstantsService)
+NS_IMPL_ISUPPORTS(OSFileConstantsService, nsIOSFileConstantsService,
+                  nsIObserver)
+
+/* static */ already_AddRefed<OSFileConstantsService>
+OSFileConstantsService::GetOrCreate()
+{
+  if (!gInstance) {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    RefPtr<OSFileConstantsService> service = new OSFileConstantsService();
+    nsresult rv = service->InitOSFileConstants();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return nullptr;
+    }
+
+    gInstance = service.forget();
+    ClearOnShutdown(&gInstance);
+  }
+
+  RefPtr<OSFileConstantsService> copy = gInstance;
+  return copy.forget();
+}
 
 OSFileConstantsService::OSFileConstantsService()
+  : mInitialized(false)
+  , mUserUmask(0)
 {
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 OSFileConstantsService::~OSFileConstantsService()
 {
-  mozilla::CleanupOSFileConstants();
+  MOZ_ASSERT(NS_IsMainThread());
 }
 
-
 NS_IMETHODIMP
 OSFileConstantsService::Init(JSContext *aCx)
 {
-  nsresult rv = mozilla::InitOSFileConstants();
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsresult rv = InitOSFileConstants();
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   mozJSComponentLoader* loader = mozJSComponentLoader::Get();
   JS::Rooted<JSObject*> targetObj(aCx);
   loader->FindTargetObject(aCx, &targetObj);
 
-  if (!mozilla::DefineOSFileConstants(aCx, targetObj)) {
+  if (!DefineOSFileConstants(aCx, targetObj)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 } // namespace mozilla
--- a/dom/system/OSFileConstants.h
+++ b/dom/system/OSFileConstants.h
@@ -2,59 +2,58 @@
 /* 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/. */
 
 #ifndef mozilla_osfileconstants_h__
 #define mozilla_osfileconstants_h__
 
+#include "nsIObserver.h"
 #include "nsIOSFileConstantsService.h"
 #include "mozilla/Attributes.h"
 
 namespace mozilla {
 
 /**
- * Perform initialization of this module.
- *
- * This function _must_ be called:
- * - from the main thread;
- * - before any Chrome Worker is created.
- *
- * The function is idempotent.
- */
-nsresult InitOSFileConstants();
-
-/**
- * Perform cleanup of this module.
- *
- * This function _must_ be called:
- * - from the main thread;
- * - after all Chrome Workers are dead.
- *
- * The function is idempotent.
- */
-void CleanupOSFileConstants();
-
-/**
- * Define OS-specific constants.
- *
- * This function creates or uses JS object |OS.Constants| to store
- * all its constants.
- */
-bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global);
-
-/**
  * XPConnect initializer, for use in the main thread.
+ * This class is thread-safe but it must be first be initialized on the
+ * main-thread.
  */
 class OSFileConstantsService final : public nsIOSFileConstantsService
+                                   , public nsIObserver
 {
- public:
-  NS_DECL_ISUPPORTS
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIOSFILECONSTANTSSERVICE
-  OSFileConstantsService();
+  NS_DECL_NSIOBSERVER
+
+  static already_AddRefed<OSFileConstantsService>
+  GetOrCreate();
+
+  bool
+  DefineOSFileConstants(JSContext* aCx,
+                        JS::Handle<JSObject*> aGlobal);
+
 private:
+
+  nsresult
+  InitOSFileConstants();
+
+  OSFileConstantsService();
   ~OSFileConstantsService();
+
+  bool mInitialized;
+
+  struct Paths;
+  UniquePtr<Paths> mPaths;
+
+  /**
+   * (Unix) the umask, which goes in OS.Constants.Sys but
+   * can only be looked up (via the system-info service)
+   * on the main thread.
+   */
+  uint32_t mUserUmask;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_osfileconstants_h__
--- a/dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp
+++ b/dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp
@@ -20,22 +20,20 @@
 #include "nsContentCID.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsFrameLoader.h"
 #include "nsIComponentRegistrar.h"
 #include "nsIContent.h"
 #include "nsIDOMAttr.h"
 #include "nsIDOMComment.h"
 #include "nsIDOMDocument.h"
-#include "nsIDOMHTMLBaseElement.h"
 #include "nsIDOMHTMLCollection.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMHTMLMediaElement.h"
-#include "nsIDOMHTMLScriptElement.h"
 #include "nsIDOMMozNamedAttrMap.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMNodeFilter.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMProcessingInstruction.h"
 #include "nsIDOMTreeWalker.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsIDocShell.h"
@@ -509,18 +507,17 @@ ResourceReader::OnWalkDOMNode(nsIDOMNode
     if (content->IsHTMLElement(nsGkAtoms::tr)) {
         return OnWalkAttribute(aNode, "background");
     }
 
     if (content->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th)) {
         return OnWalkAttribute(aNode, "background");
     }
 
-    nsCOMPtr<nsIDOMHTMLScriptElement> nodeAsScript = do_QueryInterface(aNode);
-    if (nodeAsScript) {
+    if (content->IsHTMLElement(nsGkAtoms::script)) {
         return OnWalkAttribute(aNode, "src");
     }
 
     if (content->IsSVGElement(nsGkAtoms::script)) {
         return OnWalkAttribute(aNode, "href", "http://www.w3.org/1999/xlink");
     }
 
     if (content->IsHTMLElement(nsGkAtoms::embed)) {
@@ -896,45 +893,46 @@ PersistNodeFixup::FixupNode(nsIDOMNode *
                     FixupURI(href);
                     FixupXMLStyleSheetLink(outNode, href);
                 }
             }
         }
         return NS_OK;
     }
 
-    // BASE elements are replaced by a comment so relative links are not hosed.
-    if (!IsFlagSet(IWBP::PERSIST_FLAGS_NO_BASE_TAG_MODIFICATIONS)) {
-        nsCOMPtr<nsIDOMHTMLBaseElement> nodeAsBase = do_QueryInterface(aNodeIn);
-        if (nodeAsBase) {
-            nsCOMPtr<nsIDOMDocument> ownerDocument;
-            auto* base = static_cast<dom::HTMLSharedElement*>(nodeAsBase.get());
-            base->GetOwnerDocument(getter_AddRefs(ownerDocument));
-            if (ownerDocument) {
-                nsAutoString href;
-                base->GetHref(href); // Doesn't matter if this fails
-                nsCOMPtr<nsIDOMComment> comment;
-                nsAutoString commentText;
-                commentText.AssignLiteral(" base ");
-                if (!href.IsEmpty()) {
-                    commentText += NS_LITERAL_STRING("href=\"") + href
-                                   + NS_LITERAL_STRING("\" ");
-                }
-                rv = ownerDocument->CreateComment(commentText,
-                                                  getter_AddRefs(comment));
-                if (comment) {
-                    return CallQueryInterface(comment, aNodeOut);
-                }
-            }
-            return NS_OK;
-        }
+    nsCOMPtr<nsIContent> content = do_QueryInterface(aNodeIn);
+    if (!content) {
+        return NS_OK;
     }
 
-    nsCOMPtr<nsIContent> content = do_QueryInterface(aNodeIn);
-    if (!content) {
+    // BASE elements are replaced by a comment so relative links are not hosed.
+    if (!IsFlagSet(IWBP::PERSIST_FLAGS_NO_BASE_TAG_MODIFICATIONS) &&
+        content->IsHTMLElement(nsGkAtoms::base)) {
+        nsCOMPtr<nsIDOMDocument> ownerDocument;
+        // Base uses HTMLSharedElement, which would be awkward to implement
+        // FromContent on, since it represents multiple elements. Since we've
+        // already checked IsHTMLElement here, just cast as we were doing.
+        auto* base = static_cast<dom::HTMLSharedElement*>(content.get());
+        base->GetOwnerDocument(getter_AddRefs(ownerDocument));
+        if (ownerDocument) {
+            nsAutoString href;
+            base->GetHref(href); // Doesn't matter if this fails
+            nsCOMPtr<nsIDOMComment> comment;
+            nsAutoString commentText;
+            commentText.AssignLiteral(" base ");
+            if (!href.IsEmpty()) {
+                commentText += NS_LITERAL_STRING("href=\"") + href
+                    + NS_LITERAL_STRING("\" ");
+            }
+            rv = ownerDocument->CreateComment(commentText,
+                                              getter_AddRefs(comment));
+            if (comment) {
+                return CallQueryInterface(comment, aNodeOut);
+            }
+        }
         return NS_OK;
     }
 
     // Fix up href and file links in the elements
     RefPtr<dom::HTMLAnchorElement> nodeAsAnchor = dom::HTMLAnchorElement::FromContent(content);
     if (nodeAsAnchor) {
         rv = GetNodeToFixup(aNodeIn, aNodeOut);
         if (NS_SUCCEEDED(rv) && *aNodeOut) {
@@ -1026,18 +1024,17 @@ PersistNodeFixup::FixupNode(nsIDOMNode *
                 imgCon->SetLoadingEnabled(false);
 
             // FixupAnchor(*aNodeOut);  // XXXjwatt: is this line needed?
             FixupAttribute(*aNodeOut, "href", "http://www.w3.org/1999/xlink");
         }
         return rv;
     }
 
-    nsCOMPtr<nsIDOMHTMLScriptElement> nodeAsScript = do_QueryInterface(aNodeIn);
-    if (nodeAsScript) {
+    if (content->IsHTMLElement(nsGkAtoms::script)) {
         rv = GetNodeToFixup(aNodeIn, aNodeOut);
         if (NS_SUCCEEDED(rv) && *aNodeOut) {
             FixupAttribute(*aNodeOut, "src");
         }
         return rv;
     }
 
     if (content->IsSVGElement(nsGkAtoms::script)) {
--- a/dom/webidl/AbortController.webidl
+++ b/dom/webidl/AbortController.webidl
@@ -2,14 +2,14 @@
 /* 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/.
  *
  * The origin of this IDL file is
  * https://dom.spec.whatwg.org/#abortcontroller
  */
 
-[Constructor(), Exposed=(Window,Worker)]
+[Constructor(), Exposed=(Window,Worker,System)]
 interface AbortController {
   readonly attribute AbortSignal signal;
 
   void abort();
 };
--- a/dom/webidl/AbortSignal.webidl
+++ b/dom/webidl/AbortSignal.webidl
@@ -2,14 +2,14 @@
 /* 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/.
  *
  * The origin of this IDL file is
  * https://dom.spec.whatwg.org/#abortsignal
  */
 
-[Exposed=(Window,Worker)]
+[Exposed=(Window,Worker,System)]
 interface AbortSignal : EventTarget {
   readonly attribute boolean aborted;
 
   attribute EventHandler onabort;
 };
--- a/dom/webidl/HTMLScriptElement.webidl
+++ b/dom/webidl/HTMLScriptElement.webidl
@@ -19,17 +19,17 @@ interface HTMLScriptElement : HTMLElemen
   [CEReactions, SetterThrows]
   attribute DOMString charset;
   [CEReactions, SetterThrows]
   attribute boolean async;
   [CEReactions, SetterThrows]
   attribute boolean defer;
   [CEReactions, SetterThrows]
   attribute DOMString? crossOrigin;
-  [CEReactions, SetterThrows]
+  [CEReactions, Throws]
   attribute DOMString text;
 };
 
 // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
 partial interface HTMLScriptElement {
   [CEReactions, SetterThrows]
   attribute DOMString event;
   [CEReactions, SetterThrows]
--- a/dom/workers/RegisterBindings.cpp
+++ b/dom/workers/RegisterBindings.cpp
@@ -20,18 +20,23 @@ bool
 WorkerPrivate::RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
 {
   // Init Web IDL bindings
   if (!RegisterWorkerBindings(aCx, aGlobal)) {
     return false;
   }
 
   if (IsChromeWorker()) {
-    if (!DefineChromeWorkerFunctions(aCx, aGlobal) ||
-        !DefineOSFileConstants(aCx, aGlobal)) {
+    if (!DefineChromeWorkerFunctions(aCx, aGlobal)) {
+      return false;
+    }
+
+    RefPtr<OSFileConstantsService> service =
+      OSFileConstantsService::GetOrCreate();
+    if (!service->DefineOSFileConstants(aCx, aGlobal)) {
       return false;
     }
   }
 
   if (!JS_DefineProfilingFunctions(aCx, aGlobal)) {
     return false;
   }
 
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -2027,19 +2027,20 @@ RuntimeService::Init()
                                              MAX_WORKERS_PER_DOMAIN);
   gMaxWorkersPerDomain = std::max(0, maxPerDomain);
 
   int32_t maxHardwareConcurrency =
     Preferences::GetInt(PREF_WORKERS_MAX_HARDWARE_CONCURRENCY,
                         MAX_HARDWARE_CONCURRENCY);
   gMaxHardwareConcurrency = std::max(0, maxHardwareConcurrency);
 
-  rv = InitOSFileConstants();
-  if (NS_FAILED(rv)) {
-    return rv;
+  RefPtr<OSFileConstantsService> osFileConstantsService =
+    OSFileConstantsService::GetOrCreate();
+  if (NS_WARN_IF(!osFileConstantsService)) {
+    return NS_ERROR_FAILURE;
   }
 
   if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
     return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
 }
@@ -2200,17 +2201,16 @@ RuntimeService::Cleanup()
         NS_WARNING("Failed to unregister for offline notification event!");
       }
       obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID);
       obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
       mObserved = false;
     }
   }
 
-  CleanupOSFileConstants();
   nsLayoutStatics::Release();
 }
 
 void
 RuntimeService::AddAllTopLevelWorkersToArray(nsTArray<WorkerPrivate*>& aWorkers)
 {
   for (auto iter = mDomainMap.Iter(); !iter.Done(); iter.Next()) {
 
--- a/editor/libeditor/HTMLEditorDataTransfer.cpp
+++ b/editor/libeditor/HTMLEditorDataTransfer.cpp
@@ -36,17 +36,16 @@
 #include "nsIClipboard.h"
 #include "nsIContent.h"
 #include "nsIContentFilter.h"
 #include "nsIDOMComment.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentFragment.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMHTMLInputElement.h"
-#include "nsIDOMHTMLScriptElement.h"
 #include "nsIDOMNode.h"
 #include "nsIDocument.h"
 #include "nsIEditRules.h"
 #include "nsIFile.h"
 #include "nsIInputStream.h"
 #include "nsIMIMEService.h"
 #include "nsNameSpaceManager.h"
 #include "nsINode.h"
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -431,16 +431,22 @@ ClientLayerManager::EndTransaction(DrawP
                                    void* aCallbackData,
                                    EndTransactionFlags aFlags)
 {
   if (!mForwarder->IPCOpen()) {
     mInTransaction = false;
     return;
   }
 
+  if (mTransactionIncomplete) {
+    // If the previous transaction was incomplete then we may have buffer operations
+    // running on the paint thread that haven't finished yet
+    GetCompositorBridgeChild()->FlushAsyncPaints();
+  }
+
   if (mWidget) {
     mWidget->PrepareWindowEffects();
   }
   EndTransactionInternal(aCallback, aCallbackData, aFlags);
   ForwardTransaction(!(aFlags & END_NO_REMOTE_COMPOSITE));
 
   if (mRepeatTransaction) {
     mRepeatTransaction = false;
--- a/gfx/thebes/gfxBlur.cpp
+++ b/gfx/thebes/gfxBlur.cpp
@@ -280,16 +280,18 @@ struct BlurCacheKey : public PLDHashEntr
     , mBlurRadius(aBlurRadius)
     , mShadowColor(aShadowColor)
     , mBackend(aBackendType)
     , mCornerRadii(aCornerRadii ? *aCornerRadii : RectCornerRadii())
     , mIsInset(aIsInset)
     , mInnerMinSize(aInnerMinSize)
   { }
 
+  BlurCacheKey(BlurCacheKey&&) = default;
+
   static PLDHashNumber
   HashKey(const KeyTypePointer aKey)
   {
     PLDHashNumber hash = 0;
     hash = AddToHash(hash, aKey->mMinSize.width, aKey->mMinSize.height);
     hash = AddToHash(hash, aKey->mBlurRadius.width, aKey->mBlurRadius.height);
 
     hash = AddToHash(hash, HashBytes(&aKey->mShadowColor.r,
@@ -339,27 +341,23 @@ struct BlurCacheKey : public PLDHashEntr
   }
 };
 
 /**
  * This class is what is cached. It need to be allocated in an object separated
  * to the cache entry to be able to be tracked by the nsExpirationTracker.
  * */
 struct BlurCacheData {
-  BlurCacheData(SourceSurface* aBlur, const IntMargin& aBlurMargin, const BlurCacheKey& aKey)
+  BlurCacheData(SourceSurface* aBlur, const IntMargin& aBlurMargin, BlurCacheKey&& aKey)
     : mBlur(aBlur)
     , mBlurMargin(aBlurMargin)
-    , mKey(aKey)
+    , mKey(Move(aKey))
   {}
 
-  BlurCacheData(const BlurCacheData& aOther)
-    : mBlur(aOther.mBlur)
-    , mBlurMargin(aOther.mBlurMargin)
-    , mKey(aOther.mKey)
-  { }
+  BlurCacheData(BlurCacheData&& aOther) = default;
 
   nsExpirationState *GetExpirationState() {
     return &mExpirationState;
   }
 
   nsExpirationState mExpirationState;
   RefPtr<SourceSurface> mBlur;
   IntMargin mBlurMargin;
@@ -501,17 +499,17 @@ CacheBlur(DrawTarget* aDT,
           const IntSize& aMinSize,
           const IntSize& aBlurRadius,
           const RectCornerRadii* aCornerRadii,
           const Color& aShadowColor,
           const IntMargin& aBlurMargin,
           SourceSurface* aBoxShadow)
 {
   BlurCacheKey key(aMinSize, aBlurRadius, aCornerRadii, aShadowColor, aDT->GetBackendType());
-  BlurCacheData* data = new BlurCacheData(aBoxShadow, aBlurMargin, key);
+  BlurCacheData* data = new BlurCacheData(aBoxShadow, aBlurMargin, Move(key));
   if (!gBlurCache->RegisterEntry(data)) {
     delete data;
   }
 }
 
 // Blurs a small surface and creates the colored box shadow.
 static already_AddRefed<SourceSurface>
 CreateBoxShadow(DrawTarget* aDestDrawTarget,
@@ -1083,17 +1081,17 @@ CacheInsetBlur(const IntSize& aMinOuterS
                SourceSurface* aBoxShadow)
 {
   bool isInsetBlur = true;
   BlurCacheKey key(aMinOuterSize, aMinInnerSize,
                    aBlurRadius, aCornerRadii,
                    aShadowColor, isInsetBlur,
                    aBackendType);
   IntMargin blurMargin(0, 0, 0, 0);
-  BlurCacheData* data = new BlurCacheData(aBoxShadow, blurMargin, key);
+  BlurCacheData* data = new BlurCacheData(aBoxShadow, blurMargin, Move(key));
   if (!gBlurCache->RegisterEntry(data)) {
     delete data;
   }
 }
 
 already_AddRefed<SourceSurface>
 gfxAlphaBoxBlur::GetInsetBlur(const Rect& aOuterRect,
                               const Rect& aWhitespaceRect,
--- a/gfx/thebes/gfxGradientCache.cpp
+++ b/gfx/thebes/gfxGradientCache.cpp
@@ -29,16 +29,18 @@ struct GradientCacheKey : public PLDHash
   GradientCacheKey(const nsTArray<GradientStop>& aStops, ExtendMode aExtend, BackendType aBackendType)
     : mStops(aStops), mExtend(aExtend), mBackendType(aBackendType)
   { }
 
   explicit GradientCacheKey(const GradientCacheKey* aOther)
     : mStops(aOther->mStops), mExtend(aOther->mExtend), mBackendType(aOther->mBackendType)
   { }
 
+  GradientCacheKey(GradientCacheKey&& aOther) = default;
+
   union FloatUint32
   {
     float    f;
     uint32_t u;
   };
 
   static PLDHashNumber
   HashKey(const KeyTypePointer aKey)
@@ -81,25 +83,22 @@ struct GradientCacheKey : public PLDHash
   }
 };
 
 /**
  * This class is what is cached. It need to be allocated in an object separated
  * to the cache entry to be able to be tracked by the nsExpirationTracker.
  * */
 struct GradientCacheData {
-  GradientCacheData(GradientStops* aStops, const GradientCacheKey& aKey)
+  GradientCacheData(GradientStops* aStops, GradientCacheKey&& aKey)
     : mStops(aStops),
-      mKey(aKey)
+      mKey(Move(aKey))
   {}
 
-  GradientCacheData(const GradientCacheData& aOther)
-    : mStops(aOther.mStops),
-      mKey(aOther.mKey)
-  { }
+  GradientCacheData(GradientCacheData&& aOther) = default;
 
   nsExpirationState *GetExpirationState() {
     return &mExpirationState;
   }
 
   nsExpirationState mExpirationState;
   const RefPtr<GradientStops> mStops;
   GradientCacheKey mKey;
--- a/gfx/webrender_bindings/WebRenderTypes.h
+++ b/gfx/webrender_bindings/WebRenderTypes.h
@@ -300,17 +300,17 @@ static inline wr::LayoutRect ToLayoutRec
   wr::LayoutRect r;
   r.origin.x = rect.x;
   r.origin.y = rect.y;
   r.size.width = rect.Width();
   r.size.height = rect.Height();
   return r;
 }
 
-static inline wr::LayoutRect ToLayoutRect(const gfxRect rect)
+static inline wr::LayoutRect ToLayoutRect(const gfxRect& rect)
 {
   wr::LayoutRect r;
   r.origin.x = rect.x;
   r.origin.y = rect.y;
   r.size.width = rect.Width();
   r.size.height = rect.Height();
   return r;
 }
--- a/intl/locale/LocaleService.cpp
+++ b/intl/locale/LocaleService.cpp
@@ -19,24 +19,19 @@
 
 #include "unicode/uloc.h"
 
 #define INTL_SYSTEM_LOCALES_CHANGED "intl:system-locales-changed"
 
 #define MATCH_OS_LOCALE_PREF "intl.locale.matchOS"
 #define SELECTED_LOCALE_PREF "general.useragent.locale"
 
-//XXX: This pref is used only by Android and we use it to emulate
-//     retrieving OS locale until we get proper hook into JNI in bug 1337078.
-#define ANDROID_OS_LOCALE_PREF "intl.locale.os"
-
 static const char* kObservedPrefs[] = {
   MATCH_OS_LOCALE_PREF,
   SELECTED_LOCALE_PREF,
-  ANDROID_OS_LOCALE_PREF,
   nullptr
 };
 
 using namespace mozilla::intl;
 using namespace mozilla;
 
 NS_IMPL_ISUPPORTS(LocaleService, mozILocaleService, nsIObserver,
                   nsISupportsWeakReference)
@@ -570,26 +565,20 @@ LocaleService::Observe(nsISupports *aSub
                       const char16_t *aData)
 {
   MOZ_ASSERT(mIsServer, "This should only be called in the server mode.");
 
   if (!strcmp(aTopic, INTL_SYSTEM_LOCALES_CHANGED)) {
     RequestedLocalesChanged();
   } else {
     NS_ConvertUTF16toUTF8 pref(aData);
-
-    // This is a temporary solution until we get bug 1337078 landed.
-    if (pref.EqualsLiteral(ANDROID_OS_LOCALE_PREF)) {
-      OSPreferences::GetInstance()->Refresh();
-    }
     // At the moment the only thing we're observing are settings indicating
     // user requested locales.
     if (pref.EqualsLiteral(MATCH_OS_LOCALE_PREF) ||
-        pref.EqualsLiteral(SELECTED_LOCALE_PREF) ||
-        pref.EqualsLiteral(ANDROID_OS_LOCALE_PREF)) {
+        pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
       RequestedLocalesChanged();
     }
   }
 
   return NS_OK;
 }
 
 bool
--- a/intl/locale/android/OSPreferences_android.cpp
+++ b/intl/locale/android/OSPreferences_android.cpp
@@ -2,32 +2,35 @@
  *
  * 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 "OSPreferences.h"
 #include "mozilla/Preferences.h"
 
+#include "FennecJNIWrappers.h"
+#include "GeneratedJNIWrappers.h"
+
 using namespace mozilla::intl;
 
 bool
 OSPreferences::ReadSystemLocales(nsTArray<nsCString>& aLocaleList)
 {
-  //XXX: This is a quite sizable hack to work around the fact that we cannot
-  //     retrieve OS locale in C++ without reaching out to JNI.
-  //     Once we fix this (bug 1337078), this hack should not be necessary.
-  //
+  if (!mozilla::jni::IsAvailable()) {
+    return false;
+  }
+
   //XXX: Notice, this value may be empty on an early read. In that case
   //     we won't add anything to the return list so that it doesn't get
   //     cached in mSystemLocales.
-  nsAutoCString locale;
-  Preferences::GetCString("intl.locale.os", locale);
-  if (!locale.IsEmpty()) {
-    aLocaleList.AppendElement(locale);
+  auto locale = mozilla::jni::IsFennec() ? java::BrowserLocaleManager::GetLocale() :
+                java::GeckoAppShell::GetDefaultLocale();
+  if (locale) {
+    aLocaleList.AppendElement(locale->ToCString());
     return true;
   }
   return false;
 }
 
 bool
 OSPreferences::ReadRegionalPrefsLocales(nsTArray<nsCString>& aLocaleList)
 {
--- a/js/src/builtin/Object.js
+++ b/js/src/builtin/Object.js
@@ -200,17 +200,17 @@ function ObjectOrReflectDefineProperty(o
 
     // Step 2.
     propertyKey = TO_PROPERTY_KEY(propertyKey);
 
     // Step 3 (Call to 6.2.4.5 ToPropertyDescriptor).
 
     // 6.2.4.5 ToPropertyDescriptor, step 1.
     if (!IsObject(attributes))
-        ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, DecompileArg(2, obj));
+        ThrowArgTypeNotObject(NOT_OBJECT_KIND_DESCRIPTOR, attributes);
 
     // 6.2.4.5 ToPropertyDescriptor, step 2.
     var attrs = 0, hasValue = false;
     var value, getter = null, setter = null;
 
     // 6.2.4.5 ToPropertyDescriptor, steps 3-4.
     if ("enumerable" in attributes)
         attrs |= attributes.enumerable ? ATTR_ENUMERABLE : ATTR_NONENUMERABLE;
--- a/js/src/builtin/SelfHostingDefines.h
+++ b/js/src/builtin/SelfHostingDefines.h
@@ -136,9 +136,11 @@
 #define STRING_GENERICS_TO_UPPER_CASE         20
 #define STRING_GENERICS_TRIM                  21
 #define STRING_GENERICS_TRIM_LEFT             22
 #define STRING_GENERICS_TRIM_RIGHT            23
 #define STRING_GENERICS_METHODS_LIMIT         24
 
 #define INTL_INTERNALS_OBJECT_SLOT 0
 
+#define NOT_OBJECT_KIND_DESCRIPTOR 0
+
 #endif
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -1870,16 +1870,31 @@ intrinsic_WarnDeprecatedStringMethod(JSC
         cx->compartment()->warnedAboutStringGenericsMethods |= mask;
     }
 
     args.rval().setUndefined();
     return true;
 }
 
 static bool
+intrinsic_ThrowArgTypeNotObject(JSContext* cx, unsigned argc ,Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc,vp);
+    MOZ_ASSERT(args.length() == 2);
+    MOZ_ASSERT(args[0].isNumber());
+    MOZ_ASSERT(!args[1].isObject());
+    if (args[0].toNumber() == NOT_OBJECT_KIND_DESCRIPTOR)
+        ReportNotObjectWithName(cx, "descriptor", args[1]);
+    else
+        MOZ_CRASH("unexpected kind");
+
+    return false;
+}
+
+static bool
 intrinsic_ConstructFunction(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 3);
     MOZ_ASSERT(IsConstructor(args[0]));
     MOZ_ASSERT(IsConstructor(args[1]));
     MOZ_ASSERT(args[2].toObject().is<ArrayObject>());
 
@@ -2500,16 +2515,17 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("FlatStringMatch", FlatStringMatch, 2,0),
     JS_FN("FlatStringSearch", FlatStringSearch, 2,0),
     JS_INLINABLE_FN("StringReplaceString", intrinsic_StringReplaceString, 3, 0,
                     IntrinsicStringReplaceString),
     JS_INLINABLE_FN("StringSplitString", intrinsic_StringSplitString, 2, 0,
                     IntrinsicStringSplitString),
     JS_FN("StringSplitStringLimit", intrinsic_StringSplitStringLimit, 3, 0),
     JS_FN("WarnDeprecatedStringMethod", intrinsic_WarnDeprecatedStringMethod, 2, 0),
+    JS_FN("ThrowArgTypeNotObject", intrinsic_ThrowArgTypeNotObject, 2, 0),
 
     // See builtin/RegExp.h for descriptions of the regexp_* functions.
     JS_FN("regexp_exec_no_statics", regexp_exec_no_statics, 2,0),
     JS_FN("regexp_test_no_statics", regexp_test_no_statics, 2,0),
     JS_FN("regexp_construct_raw_flags", regexp_construct_raw_flags, 2,0),
 
     JS_FN("IsModule", intrinsic_IsInstanceOfBuiltin<ModuleObject>, 1, 0),
     JS_FN("CallModuleMethodIfWrapped",
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -527,17 +527,19 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(CSPServic
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsMixedContentBlocker)
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(ContentPrincipal)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(SystemPrincipal,
     nsScriptSecurityManager::SystemPrincipalSingletonConstructor)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NullPrincipal, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsStructuredCloneContainer)
 
-NS_GENERIC_FACTORY_CONSTRUCTOR(OSFileConstantsService)
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(OSFileConstantsService,
+                                         OSFileConstantsService::GetOrCreate);
+
 NS_GENERIC_FACTORY_CONSTRUCTOR(UDPSocketChild)
 
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(GeckoMediaPluginService, GeckoMediaPluginService::GetGeckoMediaPluginService)
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsScriptError)
 
 #ifdef ACCESSIBILITY
 #include "xpcAccessibilityService.h"
--- a/layout/generic/ViewportFrame.cpp
+++ b/layout/generic/ViewportFrame.cpp
@@ -164,16 +164,19 @@ ViewportFrame::BuildDisplayListForTopLay
       if (!(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
         MOZ_ASSERT(!elem->GetParent()->IsHTMLElement(), "HTML element "
                    "should always be out-of-flow if in the top layer");
         continue;
       }
       if (nsIFrame* backdropPh =
           frame->GetChildList(kBackdropList).FirstChild()) {
         MOZ_ASSERT(backdropPh->IsPlaceholderFrame());
+        MOZ_ASSERT(!backdropPh->GetNextSibling(), "more than one ::backdrop?");
+        MOZ_ASSERT(backdropPh->HasAnyStateBits(NS_FRAME_FIRST_REFLOW),
+                   "did you intend to reflow ::backdrop placeholders?");
         nsIFrame* backdropFrame =
           static_cast<nsPlaceholderFrame*>(backdropPh)->GetOutOfFlowFrame();
         MOZ_ASSERT(backdropFrame);
         BuildDisplayListForTopLayerFrame(aBuilder, backdropFrame, aList);
       }
       BuildDisplayListForTopLayerFrame(aBuilder, frame, aList);
     }
   }
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/1415185.html
@@ -0,0 +1,18 @@
+<html>
+  <head>
+    <style>
+      * { -moz-column-count: 17 }
+    </style>
+    <script>
+    try { o1 = document.createElement('p') } catch(e) { }
+    try { o2 = document.createElement('iframe') } catch(e) { }
+    try { o3 = document.createElement('details') } catch(e) { }
+    try { o4 = document.createElement('track') } catch(e) { }
+    try { document.documentElement.appendChild(o1) } catch(e) { }
+    try { document.documentElement.appendChild(o2) } catch(e) { }
+    try { o1.appendChild(o3) } catch(e) { }
+    try { o2.contentWindow.location.reload() } catch(e) { }
+    try { o3.appendChild(o4) } catch(e) { }
+    </script>
+  </head>
+</html>
\ No newline at end of file
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -669,8 +669,9 @@ load 1368617-1.html
 load 1373586.html
 load 1375858.html
 load 1381134.html
 load 1381134-2.html
 load 1401420-1.html
 load 1401709.html
 load 1401807.html
 load 1405443.html
+load 1415185.html
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -5822,38 +5822,26 @@ nsBlockInFlowLineIterator::FindValidLine
         NS_ASSERTION(mLine != mLineList->end(), "empty overflow line list?");
         return true;
       }
     }
     currentlyInOverflowLines = !currentlyInOverflowLines;
   }
 }
 
-static void RemoveBlockChild(nsIFrame* aFrame,
-                             bool      aRemoveOnlyFluidContinuations)
-{
-  if (!aFrame) {
-    return;
-  }
-  nsBlockFrame* nextBlock = nsLayoutUtils::GetAsBlock(aFrame->GetParent());
-  NS_ASSERTION(nextBlock,
-               "Our child's continuation's parent is not a block?");
-  nextBlock->DoRemoveFrame(aFrame,
-      (aRemoveOnlyFluidContinuations ? 0 : nsBlockFrame::REMOVE_FIXED_CONTINUATIONS));
-}
-
 // This function removes aDeletedFrame and all its continuations.  It
 // is optimized for deleting a whole series of frames. The easy
 // implementation would invoke itself recursively on
 // aDeletedFrame->GetNextContinuation, then locate the line containing
 // aDeletedFrame and remove aDeletedFrame from that line. But here we
 // start by locating aDeletedFrame and then scanning from that point
 // on looking for continuations.
 void
-nsBlockFrame::DoRemoveFrame(nsIFrame* aDeletedFrame, uint32_t aFlags)
+nsBlockFrame::DoRemoveFrameInternal(nsIFrame* aDeletedFrame, uint32_t aFlags,
+                                    PostDestroyData& aPostDestroyData)
 {
   // Clear our line cursor, since our lines may change.
   ClearLineCursor();
 
   if (aDeletedFrame->GetStateBits() &
       (NS_FRAME_OUT_OF_FLOW | NS_FRAME_IS_OVERFLOW_CONTAINER)) {
     if (!aDeletedFrame->GetPrevInFlow()) {
       NS_ASSERTION(aDeletedFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
@@ -5970,17 +5958,17 @@ nsBlockFrame::DoRemoveFrame(nsIFrame* aD
     // If next-in-flow is an overflow container, must remove it first.
     if (deletedNextContinuation &&
         deletedNextContinuation->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
       deletedNextContinuation->GetParent()->
         DeleteNextInFlowChild(deletedNextContinuation, false);
       deletedNextContinuation = nullptr;
     }
 
-    aDeletedFrame->Destroy();
+    aDeletedFrame->DestroyFrom(aDeletedFrame, aPostDestroyData);
     aDeletedFrame = deletedNextContinuation;
 
     bool haveAdvancedToNextLine = false;
     // If line is empty, remove it now.
     if (0 == line->GetChildCount()) {
 #ifdef NOISY_REMOVE_FRAME
         printf("DoRemoveFrame: %s line=%p became empty so it will be removed\n",
                searchingOverflowList?"overflow":"normal", line.get());
@@ -6071,18 +6059,25 @@ nsBlockFrame::DoRemoveFrame(nsIFrame* aD
     line.next()->SetInvalidateTextRuns(true);
   }
 
 #ifdef DEBUG
   VerifyLines(true);
   VerifyOverflowSituation();
 #endif
 
-  // Advance to next flow block if the frame has more continuations
-  RemoveBlockChild(aDeletedFrame, !(aFlags & REMOVE_FIXED_CONTINUATIONS));
+  // Advance to next flow block if the frame has more continuations.
+  if (!aDeletedFrame) {
+    return;
+  }
+  nsBlockFrame* nextBlock = nsLayoutUtils::GetAsBlock(aDeletedFrame->GetParent());
+  NS_ASSERTION(nextBlock,
+               "Our child's continuation's parent is not a block?");
+  uint32_t flags = (aFlags & REMOVE_FIXED_CONTINUATIONS);
+  nextBlock->DoRemoveFrameInternal(aDeletedFrame, flags, aPostDestroyData);
 }
 
 static bool
 FindBlockLineFor(nsIFrame*             aChild,
                  nsLineList::iterator  aBegin,
                  nsLineList::iterator  aEnd,
                  nsLineList::iterator* aResult)
 {
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -529,17 +529,21 @@ public:
    * -- marks textruns dirty (unless FRAMES_ARE_EMPTY is given, in which
    * case textruns do not need to be dirtied)
    * -- destroys all removed frames
    */
   enum {
     REMOVE_FIXED_CONTINUATIONS = 0x02,
     FRAMES_ARE_EMPTY = 0x04
   };
-  void DoRemoveFrame(nsIFrame* aDeletedFrame, uint32_t aFlags);
+  void DoRemoveFrame(nsIFrame* aDeletedFrame, uint32_t aFlags)
+  {
+    AutoPostDestroyData data(PresContext());
+    DoRemoveFrameInternal(aDeletedFrame, aFlags, data.mData);
+  }
 
   void ReparentFloats(nsIFrame* aFirstFrame, nsBlockFrame* aOldParent,
                       bool aReparentSiblings);
 
   virtual bool ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas) override;
 
   virtual void UnionChildOverflow(nsOverflowAreas& aOverflowAreas) override;
 
@@ -580,16 +584,19 @@ public:
     return false;
   }
 
   virtual bool RenumberChildFrames(int32_t* aOrdinal,
                                    int32_t aDepth,
                                    int32_t aIncrement,
                                    bool aForCounting) override;
 protected:
+  /** @see DoRemoveFrame */
+  void DoRemoveFrameInternal(nsIFrame* aDeletedFrame, uint32_t aFlags,
+                             PostDestroyData& data);
 
   /** grab overflow lines from this block's prevInFlow, and make them
     * part of this block's mLines list.
     * @return true if any lines were drained.
     */
   bool DrainOverflowLines();
 
   /**
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -6460,16 +6460,19 @@ nsGridContainerFrame::InsertFrames(Child
 }
 
 void
 nsGridContainerFrame::RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame)
 {
 #ifdef DEBUG
   ChildListIDs supportedLists =
     kAbsoluteList | kFixedList | kPrincipalList | kNoReflowPrincipalList;
+  // We don't handle the kBackdropList frames in any way, but it only contains
+  // a placeholder for ::backdrop which is OK to not reflow (for now anyway).
+  supportedLists |= kBackdropList;
   MOZ_ASSERT(supportedLists.Contains(aListID), "unexpected child list");
 
   // Note that kPrincipalList doesn't mean aOldFrame must be on that list.
   // It can also be on kOverflowList, in which case it might be a pushed
   // item, and if it's the only pushed item our DID_PUSH_ITEMS bit will lie.
   if (aListID == kPrincipalList && !aOldFrame->GetPrevInFlow()) {
     // Since the bit may lie, set the mDidPushItemsBitMayLie value to true for
     // ourself and for all our contiguous previous-in-flow nsGridContainerFrames.
@@ -6679,16 +6682,19 @@ nsGridContainerFrame::GetFrameName(nsASt
 
 void
 nsGridContainerFrame::NoteNewChildren(ChildListID aListID,
                                       const nsFrameList& aFrameList)
 {
 #ifdef DEBUG
   ChildListIDs supportedLists =
     kAbsoluteList | kFixedList | kPrincipalList | kNoReflowPrincipalList;
+  // We don't handle the kBackdropList frames in any way, but it only contains
+  // a placeholder for ::backdrop which is OK to not reflow (for now anyway).
+  supportedLists |= kBackdropList;
   MOZ_ASSERT(supportedLists.Contains(aListID), "unexpected child list");
 #endif
 
   nsIPresShell* shell = PresShell();
   for (auto pif = GetPrevInFlow(); pif; pif = pif->GetPrevInFlow()) {
     if (aListID == kPrincipalList) {
       pif->AddStateBits(NS_STATE_GRID_DID_PUSH_ITEMS);
     }
@@ -6798,18 +6804,23 @@ nsGridContainerFrame::FindLastItemInGrid
   return result;
 }
 
 #ifdef DEBUG
 void
 nsGridContainerFrame::SetInitialChildList(ChildListID  aListID,
                                           nsFrameList& aChildList)
 {
+#ifdef DEBUG
   ChildListIDs supportedLists = kAbsoluteList | kFixedList | kPrincipalList;
+  // We don't handle the kBackdropList frames in any way, but it only contains
+  // a placeholder for ::backdrop which is OK to not reflow (for now anyway).
+  supportedLists |= kBackdropList;
   MOZ_ASSERT(supportedLists.Contains(aListID), "unexpected child list");
+#endif
 
   return nsContainerFrame::SetInitialChildList(aListID, aChildList);
 }
 
 void
 nsGridContainerFrame::SanityCheckGridItemsBeforeReflow() const
 {
   ChildListIDs absLists = kAbsoluteList | kFixedList |
@@ -6817,17 +6828,18 @@ nsGridContainerFrame::SanityCheckGridIte
   ChildListIDs itemLists = kPrincipalList | kOverflowList;
   for (const nsIFrame* f = this; f; f = f->GetNextInFlow()) {
     MOZ_ASSERT(!f->HasAnyStateBits(NS_STATE_GRID_DID_PUSH_ITEMS),
                "At start of reflow, we should've pulled items back from all "
                "NIFs and cleared NS_STATE_GRID_DID_PUSH_ITEMS in the process");
     for (nsIFrame::ChildListIterator childLists(f);
          !childLists.IsDone(); childLists.Next()) {
       if (!itemLists.Contains(childLists.CurrentID())) {
-        MOZ_ASSERT(absLists.Contains(childLists.CurrentID()),
+        MOZ_ASSERT(absLists.Contains(childLists.CurrentID()) ||
+                   childLists.CurrentID() == kBackdropList,
                    "unexpected non-empty child list");
         continue;
       }
       for (auto child : childLists.CurrentList()) {
         MOZ_ASSERT(f == this || child->GetPrevInFlow(),
                    "all pushed items must be pulled up before reflow");
       }
     }
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -658,36 +658,44 @@ public:
    * @param   aContent the content object associated with the frame
    * @param   aParent the parent frame
    * @param   aPrevInFlow the prev-in-flow frame
    */
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) = 0;
 
+  using PostDestroyData = mozilla::layout::PostFrameDestroyData;
+  struct MOZ_RAII AutoPostDestroyData
+  {
+    explicit AutoPostDestroyData(nsPresContext* aPresContext)
+      : mPresContext(aPresContext) {}
+    ~AutoPostDestroyData() {
+      for (auto& content : mozilla::Reversed(mData.mAnonymousContent)) {
+        nsIFrame::DestroyAnonymousContent(mPresContext, content.forget());
+      }
+      for (auto& content : mozilla::Reversed(mData.mGeneratedContent)) {
+        content->UnbindFromTree();
+      }
+    }
+    nsPresContext* mPresContext;
+    PostDestroyData mData;
+  };
   /**
    * Destroys this frame and each of its child frames (recursively calls
    * Destroy() for each child). If this frame is a first-continuation, this
    * also removes the frame from the primary frame map and clears undisplayed
    * content for its content node.
    * If the frame is a placeholder, it also ensures the out-of-flow frame's
    * removal and destruction.
    */
-  using PostDestroyData = mozilla::layout::PostFrameDestroyData;
   void Destroy() {
-    nsPresContext* presContext = PresContext();
-    PostDestroyData data;
-    DestroyFrom(this, data);
+    AutoPostDestroyData data(PresContext());
+    DestroyFrom(this, data.mData);
     // Note that |this| is deleted at this point.
-    for (auto& content : mozilla::Reversed(data.mAnonymousContent)) {
-      DestroyAnonymousContent(presContext, content.forget());
-    }
-    for (auto& content : mozilla::Reversed(data.mGeneratedContent)) {
-      content->UnbindFromTree();
-    }
   }
 
   /** Flags for PeekOffsetCharacter, PeekOffsetNoAmount, PeekOffsetWord return values.
     */
   enum FrameSearchResult {
     // Peek found a appropriate offset within frame.
     FOUND = 0x00,
     // try next frame for offset.
@@ -714,16 +722,18 @@ public:
     PeekOffsetCharacterOptions()
       : mRespectClusters(true)
       , mIgnoreUserStyleAll(false)
     {
     }
   };
 
 protected:
+  friend class nsBlockFrame; // for access to DestroyFrom
+
   /**
    * Return true if the frame is part of a Selection.
    * Helper method to implement the public IsSelected() API.
    */
   virtual bool IsFrameSelected() const;
 
   /**
    * Implements Destroy(). Do not call this directly except from within a
new file mode 100644
--- /dev/null
+++ b/layout/reftests/layers/component-alpha-enter-1-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>Test transition from single-alpha layer to component-alpha layer from a display port size change</title>
+<script type="text/javascript">
+  document.addEventListener('MozReftestInvalidate', function() {
+    var scrollbox = document.getElementById('scrollbox');
+    scrollbox.scrollTop = 1000;
+    document.documentElement.className = '';
+  });
+</script>
+<style>
+#scrollbox {
+  margin: 20px;
+  width: 300px;
+  height: 400px;
+  overflow-y: scroll;
+  background: linear-gradient(#FFF, #FFF);
+}
+
+#inner {
+  background-color: #000;
+  margin-top: 10px;
+  height: 5px;
+  line-height: 5px;
+  padding-bottom: 400px;
+}
+</style>
+
+<div id="scrollbox">
+  <div id="inner">
+    Text
+  </div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/layers/component-alpha-enter-1.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>Test transition from single-alpha layer to component-alpha layer from a display port size change</title>
+<script type="text/javascript">
+  document.addEventListener('MozReftestInvalidate', function() {
+    var scrollbox = document.getElementById('scrollbox');
+    scrollbox.scrollTop = 1000;
+
+    window.addEventListener("MozAfterPaint", function() {
+      // Remove dummy to make scrollbox the first scroll element giving it a
+      // display port. The display port will then contain the text forcing the
+      // layer to transition to component alpha.
+      document.getElementById('dummy').remove();
+      document.documentElement.className = '';
+    }, {once: true});
+  });
+</script>
+<style>
+#dummy {
+  margin: 20px;
+  width: 300px;
+  height: 400px;
+  overflow: scroll;
+}
+
+#filler {
+  height: 600px;
+}
+
+#scrollbox {
+  margin: 20px;
+  width: 300px;
+  height: 400px;
+  overflow-y: scroll;
+  background: linear-gradient(#FFF, #FFF);
+}
+
+#inner {
+  background-color: #000;
+  margin-top: 10px;
+  height: 5px;
+  line-height: 5px;
+  padding-bottom: 400px;
+}
+</style>
+
+<div id="dummy">
+  <div id="filler">
+  </div>
+</div>
+
+<div id="scrollbox">
+  <div id="inner">
+    Text
+  </div>
+</div>
--- a/layout/reftests/layers/reftest.list
+++ b/layout/reftests/layers/reftest.list
@@ -1,10 +1,11 @@
 == move-to-background-1.html move-to-background-1-ref.html
 fuzzy-if(cocoaWidget,2,6) random-if(Android) == component-alpha-exit-1.html component-alpha-exit-1-ref.html # bug 760275
+fuzzy-if(cocoaWidget,2,6) random-if(Android) == component-alpha-enter-1.html component-alpha-enter-1-ref.html
 
 != pull-background-1.html about:blank
 skip-if(styloVsGecko) != pull-background-2.html about:blank # skip styloVsGecko for imperceptible pixel rounding differences between Stylo and Gecko
 != pull-background-3.html about:blank
 != pull-background-4.html about:blank
 fuzzy-if(styloVsGecko,1,1) != pull-background-5.html about:blank
 != pull-background-6.html about:blank
 
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserLocaleManager.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserLocaleManager.java
@@ -12,16 +12,17 @@ import java.util.Locale;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.annotation.ReflectionTarget;
+import org.mozilla.gecko.annotation.WrapForJNI;
 import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.GeckoJarReader;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
@@ -220,16 +221,22 @@ public class BrowserLocaleManager implem
         prefs.edit().putString("osLocale", osLocaleString).apply();
 
         // The value we send to Gecko should be a language tag, not
         // a Java locale string.
         final GeckoBundle data = new GeckoBundle(1);
         data.putString("languageTag", Locales.getLanguageTag(osLocale));
 
         EventDispatcher.getInstance().dispatch("Locale:OS", data);
+
+        if (GeckoThread.isRunning()) {
+            refreshLocales();
+        } else {
+            GeckoThread.queueNativeCall(BrowserLocaleManager.class, "refreshLocales");
+        }
     }
 
     @Override
     public String getAndApplyPersistedLocale(Context context) {
         initialize(context);
 
         final long t1 = android.os.SystemClock.uptimeMillis();
         final String localeCode = getPersistedLocale(context);
@@ -446,9 +453,23 @@ public class BrowserLocaleManager implem
     /**
      * @return the single default locale baked into this application.
      *         Applicable when there is no multilocale.json present.
      */
     @SuppressWarnings("static-method")
     public String getFallbackLocaleTag() {
         return FALLBACK_LOCALE_TAG;
     }
+
+    @WrapForJNI
+    public static native void refreshLocales();
+
+
+    @WrapForJNI
+    private static String getLocale() {
+        try {
+            return Locales.getLocaleManager().getCurrentLocale(GeckoAppShell.getApplicationContext()).toString();
+        } catch (NullPointerException e) {
+            Log.i(LOG_TAG, "Couldn't get current locale.");
+            return null;
+        }
+    }
 }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java
@@ -15,16 +15,17 @@ import java.io.PipedInputStream;
 import java.io.PipedOutputStream;
 import java.net.MalformedURLException;
 import java.net.Proxy;
 import java.net.URLConnection;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.StringTokenizer;
 import java.util.TreeMap;
 
 import org.mozilla.gecko.annotation.JNITarget;
 import org.mozilla.gecko.annotation.RobocopTarget;
 import org.mozilla.gecko.annotation.WrapForJNI;
 import org.mozilla.gecko.gfx.BitmapUtils;
@@ -1859,9 +1860,14 @@ public class GeckoAppShell
             return 0;
         }
         final String prop = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
         if (prop == null) {
             return 0;
         }
         return Integer.parseInt(prop);
     }
+
+    @WrapForJNI
+    public static String getDefaultLocale() {
+        return Locale.getDefault().toString();
+    }
 }
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -31,21 +31,18 @@ this.EXPORTED_SYMBOLS = ["Extension", "E
  * to run in the same process of the existing addon debugging browser element).
  */
 
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cu = Components.utils;
 const Cr = Components.results;
 
-Cu.importGlobalProperties(["TextEncoder"]);
-
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.importGlobalProperties(["fetch"]);
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   AddonManager: "resource://gre/modules/AddonManager.jsm",
   AddonManagerPrivate: "resource://gre/modules/AddonManager.jsm",
   AppConstants: "resource://gre/modules/AppConstants.jsm",
   AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm",
   ExtensionCommon: "resource://gre/modules/ExtensionCommon.jsm",
   ExtensionPermissions: "resource://gre/modules/ExtensionPermissions.jsm",
--- a/toolkit/components/extensions/ExtensionChildDevToolsUtils.jsm
+++ b/toolkit/components/extensions/ExtensionChildDevToolsUtils.jsm
@@ -9,22 +9,20 @@
  */
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["ExtensionChildDevToolsUtils"];
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
+Cu.import("resource://gre/modules/EventEmitter.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
-                                  "resource://gre/modules/EventEmitter.jsm");
-
 // Create a variable to hold the cached ThemeChangeObserver which does not
 // get created until a devtools context has been created.
 let themeChangeObserver;
 
 /**
  * An observer that watches for changes to the devtools theme and provides
  * that information to the devtools.panels.themeName API property, as well as
  * emits events for the devtools.panels.onThemeChanged event. It also caches
--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -1207,34 +1207,16 @@ function watchExtensionProxyContextLoad(
   return () => {
     extension.off("extension-proxy-context-load", listener);
   };
 }
 
 // Used to cache the list of WebExtensionManifest properties defined in the BASE_SCHEMA.
 let gBaseManifestProperties = null;
 
-/**
- * Function to obtain the extension name from a moz-extension URI without exposing GlobalManager.
- *
- * @param {Object} uri The URI for the extension to look up.
- * @returns {string} the name of the extension.
- */
-function extensionNameFromURI(uri) {
-  let id = null;
-  try {
-    id = gAddonPolicyService.extensionURIToAddonId(uri);
-  } catch (ex) {
-    if (ex.name != "NS_ERROR_XPC_BAD_CONVERT_JS") {
-      Cu.reportError("Extension cannot be found in AddonPolicyService.");
-    }
-  }
-  return GlobalManager.getExtension(id).name;
-}
-
 // Manages icon details for toolbar buttons in the |pageAction| and
 // |browserAction| APIs.
 let IconDetails = {
   // WeakMap<Extension -> Map<url-string -> Map<iconType-string -> object>>>
   iconCache: new DefaultWeakMap(() => {
     return new DefaultMap(() => new DefaultMap(() => new Map()));
   }),
 
@@ -1565,17 +1547,16 @@ class CacheStore {
   }
 }
 
 for (let name of StartupCache.STORE_NAMES) {
   StartupCache[name] = new CacheStore(name);
 }
 
 var ExtensionParent = {
-  extensionNameFromURI,
   GlobalManager,
   HiddenExtensionPage,
   IconDetails,
   ParentAPIManager,
   StartupCache,
   WebExtensionPolicy,
   apiManager,
   get baseManifestProperties() {
--- a/toolkit/components/extensions/ExtensionPermissions.jsm
+++ b/toolkit/components/extensions/ExtensionPermissions.jsm
@@ -1,17 +1,16 @@
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   ExtensionParent: "resource://gre/modules/ExtensionParent.jsm",
-  ExtensionUtils: "resource://gre/modules/ExtensionUtils.jsm",
   JSONFile: "resource://gre/modules/JSONFile.jsm",
   OS: "resource://gre/modules/osfile.jsm",
 });
 
 XPCOMUtils.defineLazyGetter(this, "StartupCache", () => ExtensionParent.StartupCache);
 
 this.EXPORTED_SYMBOLS = ["ExtensionPermissions"];
 
--- a/toolkit/components/extensions/ExtensionStorageSync.jsm
+++ b/toolkit/components/extensions/ExtensionStorageSync.jsm
@@ -42,17 +42,16 @@ const SCALAR_STORAGE_CONSUMED = "storage
 const KINTO_REQUEST_TIMEOUT = 30000;
 
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/ExtensionUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetters(this, {
-  AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm",
   BulkKeyBundle: "resource://services-sync/keys.js",
   CollectionKeyManager: "resource://services-sync/record.js",
   CommonUtils: "resource://services-common/utils.js",
   CryptoUtils: "resource://services-crypto/utils.js",
   fxAccounts: "resource://gre/modules/FxAccounts.jsm",
   KintoHttpClient: "resource://services-common/kinto-http-client.js",
   Kinto: "resource://services-common/kinto-offline-client.js",
   FirefoxAdapter: "resource://services-common/kinto-storage-adapter.js",
--- a/toolkit/components/extensions/ExtensionTestCommon.jsm
+++ b/toolkit/components/extensions/ExtensionTestCommon.jsm
@@ -16,18 +16,16 @@ const {classes: Cc, interfaces: Ci, util
 
 Cu.importGlobalProperties(["TextEncoder"]);
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
-                                  "resource://gre/modules/AppConstants.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Extension",
                                   "resource://gre/modules/Extension.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionParent",
                                   "resource://gre/modules/ExtensionParent.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "OS",
                                   "resource://gre/modules/osfile.jsm");
--- a/toolkit/components/extensions/ExtensionUtils.jsm
+++ b/toolkit/components/extensions/ExtensionUtils.jsm
@@ -8,18 +8,16 @@ this.EXPORTED_SYMBOLS = ["ExtensionUtils
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "ConsoleAPI",
                                   "resource://gre/modules/Console.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "OS",
-                                  "resource://gre/modules/osfile.jsm");
 
 function getConsole() {
   return new ConsoleAPI({
     maxLogLevelPref: "extensions.webextensions.log.level",
     prefix: "WebExtensions",
   });
 }
 
--- a/toolkit/components/extensions/ext-protocolHandlers.js
+++ b/toolkit/components/extensions/ext-protocolHandlers.js
@@ -3,17 +3,16 @@
 "use strict";
 
 XPCOMUtils.defineLazyServiceGetter(this, "handlerService",
                                    "@mozilla.org/uriloader/handler-service;1",
                                    "nsIHandlerService");
 XPCOMUtils.defineLazyServiceGetter(this, "protocolService",
                                    "@mozilla.org/uriloader/external-protocol-service;1",
                                    "nsIExternalProtocolService");
-Cu.importGlobalProperties(["URL"]);
 
 const hasHandlerApp = handlerConfig => {
   let protoInfo = protocolService.getProtocolHandlerInfo(handlerConfig.protocol);
   let appHandlers = protoInfo.possibleApplicationHandlers;
   for (let i = 0; i < appHandlers.length; i++) {
     let handler = appHandlers.queryElementAt(i, Ci.nsISupports);
     if (handler instanceof Ci.nsIWebHandlerApp &&
         handler.uriTemplate === handlerConfig.uriTemplate) {
--- a/widget/android/GeneratedJNIWrappers.cpp
+++ b/widget/android/GeneratedJNIWrappers.cpp
@@ -313,16 +313,24 @@ auto GeckoAppShell::GetCurrentBatteryInf
 constexpr char GeckoAppShell::GetCurrentNetworkInformation_t::name[];
 constexpr char GeckoAppShell::GetCurrentNetworkInformation_t::signature[];
 
 auto GeckoAppShell::GetCurrentNetworkInformation() -> mozilla::jni::DoubleArray::LocalRef
 {
     return mozilla::jni::Method<GetCurrentNetworkInformation_t>::Call(GeckoAppShell::Context(), nullptr);
 }
 
+constexpr char GeckoAppShell::GetDefaultLocale_t::name[];
+constexpr char GeckoAppShell::GetDefaultLocale_t::signature[];
+
+auto GeckoAppShell::GetDefaultLocale() -> mozilla::jni::String::LocalRef
+{
+    return mozilla::jni::Method<GetDefaultLocale_t>::Call(GeckoAppShell::Context(), nullptr);
+}
+
 constexpr char GeckoAppShell::GetDensity_t::name[];
 constexpr char GeckoAppShell::GetDensity_t::signature[];
 
 auto GeckoAppShell::GetDensity() -> float
 {
     return mozilla::jni::Method<GetDensity_t>::Call(GeckoAppShell::Context(), nullptr);
 }
 
--- a/widget/android/GeneratedJNIWrappers.h
+++ b/widget/android/GeneratedJNIWrappers.h
@@ -893,16 +893,35 @@ public:
         static const mozilla::jni::CallingThread callingThread =
                 mozilla::jni::CallingThread::GECKO;
         static const mozilla::jni::DispatchTarget dispatchTarget =
                 mozilla::jni::DispatchTarget::CURRENT;
     };
 
     static auto GetCurrentNetworkInformation() -> mozilla::jni::DoubleArray::LocalRef;
 
+    struct GetDefaultLocale_t {
+        typedef GeckoAppShell Owner;
+        typedef mozilla::jni::String::LocalRef ReturnType;
+        typedef mozilla::jni::String::Param SetterType;
+        typedef mozilla::jni::Args<> Args;
+        static constexpr char name[] = "getDefaultLocale";
+        static constexpr char signature[] =
+                "()Ljava/lang/String;";
+        static const bool isStatic = true;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+        static const mozilla::jni::CallingThread callingThread =
+                mozilla::jni::CallingThread::ANY;
+        static const mozilla::jni::DispatchTarget dispatchTarget =
+                mozilla::jni::DispatchTarget::CURRENT;
+    };
+
+    static auto GetDefaultLocale() -> mozilla::jni::String::LocalRef;
+
     struct GetDensity_t {
         typedef GeckoAppShell Owner;
         typedef float ReturnType;
         typedef float SetterType;
         typedef mozilla::jni::Args<> Args;
         static constexpr char name[] = "getDensity";
         static constexpr char signature[] =
                 "()F";
--- a/widget/android/fennec/FennecJNINatives.h
+++ b/widget/android/fennec/FennecJNINatives.h
@@ -34,16 +34,31 @@ const JNINativeMethod ANRReporter::Nativ
             ::template Wrap<&Impl::ReleaseNativeStack>),
 
     mozilla::jni::MakeNativeMethod<ANRReporter::RequestNativeStack_t>(
             mozilla::jni::NativeStub<ANRReporter::RequestNativeStack_t, Impl>
             ::template Wrap<&Impl::RequestNativeStack>)
 };
 
 template<class Impl>
+class BrowserLocaleManager::Natives : public mozilla::jni::NativeImpl<BrowserLocaleManager, Impl>
+{
+public:
+    static const JNINativeMethod methods[1];
+};
+
+template<class Impl>
+const JNINativeMethod BrowserLocaleManager::Natives<Impl>::methods[] = {
+
+    mozilla::jni::MakeNativeMethod<BrowserLocaleManager::RefreshLocales_t>(
+            mozilla::jni::NativeStub<BrowserLocaleManager::RefreshLocales_t, Impl>
+            ::template Wrap<&Impl::RefreshLocales>)
+};
+
+template<class Impl>
 class GeckoJavaSampler::Natives : public mozilla::jni::NativeImpl<GeckoJavaSampler, Impl>
 {
 public:
     static const JNINativeMethod methods[1];
 };
 
 template<class Impl>
 const JNINativeMethod GeckoJavaSampler::Natives<Impl>::methods[] = {
--- a/widget/android/fennec/FennecJNIWrappers.cpp
+++ b/widget/android/fennec/FennecJNIWrappers.cpp
@@ -19,16 +19,30 @@ constexpr char ANRReporter::GetNativeSta
 constexpr char ANRReporter::GetNativeStack_t::signature[];
 
 constexpr char ANRReporter::ReleaseNativeStack_t::name[];
 constexpr char ANRReporter::ReleaseNativeStack_t::signature[];
 
 constexpr char ANRReporter::RequestNativeStack_t::name[];
 constexpr char ANRReporter::RequestNativeStack_t::signature[];
 
+const char BrowserLocaleManager::name[] =
+        "org/mozilla/gecko/BrowserLocaleManager";
+
+constexpr char BrowserLocaleManager::GetLocale_t::name[];
+constexpr char BrowserLocaleManager::GetLocale_t::signature[];
+
+auto BrowserLocaleManager::GetLocale() -> mozilla::jni::String::LocalRef
+{
+    return mozilla::jni::Method<GetLocale_t>::Call(BrowserLocaleManager::Context(), nullptr);
+}
+
+constexpr char BrowserLocaleManager::RefreshLocales_t::name[];
+constexpr char BrowserLocaleManager::RefreshLocales_t::signature[];
+
 const char DownloadsIntegration::name[] =
         "org/mozilla/gecko/DownloadsIntegration";
 
 constexpr char DownloadsIntegration::GetTemporaryDownloadDirectory_t::name[];
 constexpr char DownloadsIntegration::GetTemporaryDownloadDirectory_t::signature[];
 
 auto DownloadsIntegration::GetTemporaryDownloadDirectory() -> mozilla::jni::String::LocalRef
 {
--- a/widget/android/fennec/FennecJNIWrappers.h
+++ b/widget/android/fennec/FennecJNIWrappers.h
@@ -74,16 +74,65 @@ public:
     };
 
     static const mozilla::jni::CallingThread callingThread =
             mozilla::jni::CallingThread::ANY;
 
     template<class Impl> class Natives;
 };
 
+class BrowserLocaleManager : public mozilla::jni::ObjectBase<BrowserLocaleManager>
+{
+public:
+    static const char name[];
+
+    explicit BrowserLocaleManager(const Context& ctx) : ObjectBase<BrowserLocaleManager>(ctx) {}
+
+    struct GetLocale_t {
+        typedef BrowserLocaleManager Owner;
+        typedef mozilla::jni::String::LocalRef ReturnType;
+        typedef mozilla::jni::String::Param SetterType;
+        typedef mozilla::jni::Args<> Args;
+        static constexpr char name[] = "getLocale";
+        static constexpr char signature[] =
+                "()Ljava/lang/String;";
+        static const bool isStatic = true;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+        static const mozilla::jni::CallingThread callingThread =
+                mozilla::jni::CallingThread::ANY;
+        static const mozilla::jni::DispatchTarget dispatchTarget =
+                mozilla::jni::DispatchTarget::CURRENT;
+    };
+
+    static auto GetLocale() -> mozilla::jni::String::LocalRef;
+
+    struct RefreshLocales_t {
+        typedef BrowserLocaleManager Owner;
+        typedef void ReturnType;
+        typedef void SetterType;
+        typedef mozilla::jni::Args<> Args;
+        static constexpr char name[] = "refreshLocales";
+        static constexpr char signature[] =
+                "()V";
+        static const bool isStatic = true;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+        static const mozilla::jni::CallingThread callingThread =
+                mozilla::jni::CallingThread::ANY;
+        static const mozilla::jni::DispatchTarget dispatchTarget =
+                mozilla::jni::DispatchTarget::CURRENT;
+    };
+
+    static const mozilla::jni::CallingThread callingThread =
+            mozilla::jni::CallingThread::ANY;
+
+    template<class Impl> class Natives;
+};
+
 class DownloadsIntegration : public mozilla::jni::ObjectBase<DownloadsIntegration>
 {
 public:
     static const char name[];
 
     explicit DownloadsIntegration(const Context& ctx) : ObjectBase<DownloadsIntegration>(ctx) {}
 
     struct GetTemporaryDownloadDirectory_t {
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -32,16 +32,17 @@
 #include "nsGeoPosition.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/Services.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Hal.h"
 #include "mozilla/dom/TabChild.h"
+#include "mozilla/intl/OSPreferences.h"
 #include "prenv.h"
 
 #include "AndroidBridge.h"
 #include "AndroidBridgeUtilities.h"
 #include "GeneratedJNINatives.h"
 #include <android/log.h>
 #include <pthread.h>
 #include <wchar.h>
@@ -375,16 +376,28 @@ public:
         }
 
         widget::AndroidAlerts::NotifyListener(
                 aName->ToString(), aTopic->ToCString().get(),
                 aCookie->ToString().get());
     }
 };
 
+
+class BrowserLocaleManagerSupport final
+  : public java::BrowserLocaleManager::Natives<BrowserLocaleManagerSupport>
+{
+public:
+  static void RefreshLocales()
+  {
+    intl::OSPreferences::GetInstance()->Refresh();
+  }
+};
+
+
 nsAppShell::nsAppShell()
     : mSyncRunFinished(*(sAppShellLock = new Mutex("nsAppShell")),
                        "nsAppShell.SyncRun")
     , mSyncRunQuit(false)
 {
     {
         MutexAutoLock lock(*sAppShellLock);
         sAppShell = this;
@@ -407,16 +420,17 @@ nsAppShell::nsAppShell()
         mozilla::GeckoNetworkManager::Init();
         mozilla::GeckoProcessManager::Init();
         mozilla::GeckoScreenOrientation::Init();
         mozilla::PrefsHelper::Init();
         mozilla::GeckoVRManager::Init();
         nsWindow::InitNatives();
 
         if (jni::IsFennec()) {
+            BrowserLocaleManagerSupport::Init();
             mozilla::ANRReporter::Init();
             mozilla::MemoryMonitor::Init();
             mozilla::widget::Telemetry::Init();
             mozilla::ThumbnailHelper::Init();
         }
 
         java::GeckoThread::SetState(java::GeckoThread::State::JNI_READY());
 
--- a/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp
+++ b/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp
@@ -40,25 +40,22 @@
 #include "nsIDOMElement.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMFileList.h"
 #include "nsIDOMFocusEvent.h"
 #include "nsIDOMFormData.h"
 #include "nsIDOMGeoPositionError.h"
 #include "nsIDOMHistory.h"
-#include "nsIDOMHTMLBaseElement.h"
 #include "nsIDOMHTMLCollection.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIDOMHTMLFormElement.h"
-#include "nsIDOMHTMLHtmlElement.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMHTMLMediaElement.h"
-#include "nsIDOMHTMLScriptElement.h"
 #include "nsIDOMKeyEvent.h"
 #include "nsIDOMMediaList.h"
 #include "nsIDOMMouseEvent.h"
 #include "nsIDOMMouseScrollEvent.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsIDOMMozNamedAttrMap.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMNodeIterator.h"
@@ -137,27 +134,25 @@
 #include "mozilla/dom/EventTargetBinding.h"
 #include "mozilla/dom/FileListBinding.h"
 #include "mozilla/dom/FocusEventBinding.h"
 #include "mozilla/dom/FormDataBinding.h"
 #include "mozilla/dom/FrameLoaderBinding.h"
 #include "mozilla/dom/HistoryBinding.h"
 #include "mozilla/dom/HTMLAnchorElementBinding.h"
 #include "mozilla/dom/HTMLAreaElementBinding.h"
-#include "mozilla/dom/HTMLBaseElementBinding.h"
 #include "mozilla/dom/HTMLButtonElementBinding.h"
 #include "mozilla/dom/HTMLCollectionBinding.h"
 #include "mozilla/dom/HTMLDocumentBinding.h"
 #include "mozilla/dom/HTMLElementBinding.h"
 #include "mozilla/dom/HTMLFormElementBinding.h"
 #include "mozilla/dom/HTMLFrameSetElementBinding.h"
 #include "mozilla/dom/HTMLHtmlElementBinding.h"
 #include "mozilla/dom/HTMLInputElementBinding.h"
 #include "mozilla/dom/HTMLMediaElementBinding.h"
-#include "mozilla/dom/HTMLScriptElementBinding.h"
 #include "mozilla/dom/KeyEventBinding.h"
 #include "mozilla/dom/ListBoxObjectBinding.h"
 #include "mozilla/dom/MediaListBinding.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/MenuBoxObjectBinding.h"
 #include "mozilla/dom/MouseEventBinding.h"
 #include "mozilla/dom/MouseScrollEventBinding.h"
 #include "mozilla/dom/MutationEventBinding.h"
@@ -290,25 +285,22 @@ const ComponentsInterfaceShimEntry kComp
   DEFINE_SHIM(Event),
   DEFINE_SHIM(EventTarget),
   DEFINE_SHIM(FileList),
   DEFINE_SHIM(FocusEvent),
   DEFINE_SHIM(FormData),
   DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIFrameLoader, FrameLoader),
   DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMGeoPositionError, PositionError),
   DEFINE_SHIM(History),
-  DEFINE_SHIM(HTMLBaseElement),
   DEFINE_SHIM(HTMLCollection),
   DEFINE_SHIM(HTMLDocument),
   DEFINE_SHIM(HTMLElement),
   DEFINE_SHIM(HTMLFormElement),
-  DEFINE_SHIM(HTMLHtmlElement),
   DEFINE_SHIM(HTMLInputElement),
   DEFINE_SHIM(HTMLMediaElement),
-  DEFINE_SHIM(HTMLScriptElement),
   DEFINE_SHIM(KeyEvent),
   DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIListBoxObject, ListBoxObject),
   DEFINE_SHIM(MediaList),
   DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIMenuBoxObject, MenuBoxObject),
   DEFINE_SHIM(MouseEvent),
   DEFINE_SHIM(MouseScrollEvent),
   DEFINE_SHIM(MutationEvent),
   DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMMozNamedAttrMap, NamedNodeMap),