Merge autoland to mozilla-central. a=merge
authorAlexandru Michis <malexandru@mozilla.com>
Sat, 23 Oct 2021 00:29:53 +0300
changeset 596767 9226c23abfe35c9cea21fc73726568f86276c8af
parent 596696 5ee274790b7c8cbd01cab5913aba83dd8847b5cb (current diff)
parent 596766 95d6b5368d6fe45f646aceaa33d489d0df75f7dd (diff)
child 596785 580f17b9901a28adf889ba906396dc60cd19b46d
push id38907
push usermalexandru@mozilla.com
push dateFri, 22 Oct 2021 21:32:34 +0000
treeherdermozilla-central@9226c23abfe3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone95.0a1
first release with
nightly linux32
9226c23abfe3 / 95.0a1 / 20211022213234 / files
nightly linux64
9226c23abfe3 / 95.0a1 / 20211022213234 / files
nightly mac
9226c23abfe3 / 95.0a1 / 20211022213234 / files
nightly win32
9226c23abfe3 / 95.0a1 / 20211022213234 / files
nightly win64
9226c23abfe3 / 95.0a1 / 20211022213234 / 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 autoland to mozilla-central. a=merge
--- a/browser/components/BrowserGlue.jsm
+++ b/browser/components/BrowserGlue.jsm
@@ -53,17 +53,16 @@ XPCOMUtils.defineLazyModuleGetters(this,
   Interactions: "resource:///modules/Interactions.jsm",
   Log: "resource://gre/modules/Log.jsm",
   LoginBreaches: "resource:///modules/LoginBreaches.jsm",
   PageDataService: "resource:///modules/pagedata/PageDataService.jsm",
   NetUtil: "resource://gre/modules/NetUtil.jsm",
   NewTabUtils: "resource://gre/modules/NewTabUtils.jsm",
   NimbusFeatures: "resource://nimbus/ExperimentAPI.jsm",
   Normandy: "resource://normandy/Normandy.jsm",
-  OS: "resource://gre/modules/osfile.jsm",
   OsEnvironment: "resource://gre/modules/OsEnvironment.jsm",
   PageActions: "resource:///modules/PageActions.jsm",
   PageThumbs: "resource://gre/modules/PageThumbs.jsm",
   PdfJs: "resource://pdf.js/PdfJs.jsm",
   PermissionUI: "resource:///modules/PermissionUI.jsm",
   PlacesBackups: "resource://gre/modules/PlacesBackups.jsm",
   PlacesDBUtils: "resource://gre/modules/PlacesDBUtils.jsm",
   PlacesUIUtils: "resource:///modules/PlacesUIUtils.jsm",
@@ -3108,17 +3107,17 @@ BrowserGlue.prototype = {
           await BookmarkJSONUtils.importFromFile(lastBackupFile, {
             replace: true,
             source: PlacesUtils.bookmarks.SOURCES.RESTORE_ON_STARTUP,
           });
           importBookmarks = false;
         } else {
           // We have created a new database but we don't have any backup available
           importBookmarks = true;
-          if (await OS.File.exists(BookmarkHTMLUtils.defaultPath)) {
+          if (await IOUtils.exists(BookmarkHTMLUtils.defaultPath)) {
             // If bookmarks.html is available in current profile import it...
             importBookmarksHTML = true;
           } else {
             // ...otherwise we will restore defaults
             restoreDefaultBookmarks = true;
           }
         }
       }
@@ -3136,18 +3135,18 @@ BrowserGlue.prototype = {
           Cu.reportError(e);
         }
       } else {
         // An import operation is about to run.
         let bookmarksUrl = null;
         if (restoreDefaultBookmarks) {
           // User wants to restore bookmarks.html file from default profile folder
           bookmarksUrl = "chrome://browser/locale/bookmarks.html";
-        } else if (await OS.File.exists(BookmarkHTMLUtils.defaultPath)) {
-          bookmarksUrl = OS.Path.toFileURI(BookmarkHTMLUtils.defaultPath);
+        } else if (await IOUtils.exists(BookmarkHTMLUtils.defaultPath)) {
+          bookmarksUrl = PathUtils.toFileURI(BookmarkHTMLUtils.defaultPath);
         }
 
         if (bookmarksUrl) {
           // Import from bookmarks.html file.
           try {
             if (Services.policies.isAllowed("defaultBookmarks")) {
               await BookmarkHTMLUtils.importFromURL(bookmarksUrl, {
                 replace: true,
@@ -3299,16 +3298,18 @@ BrowserGlue.prototype = {
 
   // eslint-disable-next-line complexity
   _migrateUI: function BG__migrateUI() {
     // Use an increasing number to keep track of the current migration state.
     // Completely unrelated to the current Firefox release number.
     const UI_VERSION = 119;
     const BROWSER_DOCURL = AppConstants.BROWSER_CHROME_URL;
 
+    const PROFILE_DIR = Services.dirsvc.get("ProfD", Ci.nsIFile).path;
+
     if (!Services.prefs.prefHasUserValue("browser.migration.version")) {
       // This is a new profile, nothing to migrate.
       Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
       this._isNewProfile = true;
       return;
     }
 
     this._isNewProfile = false;
@@ -3317,20 +3318,19 @@ BrowserGlue.prototype = {
     );
     if (currentUIVersion >= UI_VERSION) {
       return;
     }
 
     let xulStore = Services.xulStore;
 
     if (currentUIVersion < 64) {
-      OS.File.remove(
-        OS.Path.join(OS.Constants.Path.profileDir, "directoryLinks.json"),
-        { ignoreAbsent: true }
-      );
+      IOUtils.remove(PathUtils.join(PROFILE_DIR, "directoryLinks.json"), {
+        ignoreAbsent: true,
+      });
     }
 
     if (
       currentUIVersion < 65 &&
       Services.prefs.getCharPref("general.config.filename", "") ==
         "dsengine.cfg"
     ) {
       let searchInitializedPromise = new Promise(resolve => {
@@ -3365,20 +3365,19 @@ BrowserGlue.prototype = {
       // Migrate devtools firebug theme users to light theme (bug 1378108):
       if (Services.prefs.getCharPref("devtools.theme") == "firebug") {
         Services.prefs.setCharPref("devtools.theme", "light");
       }
     }
 
     if (currentUIVersion < 68) {
       // Remove blocklists legacy storage, now relying on IndexedDB.
-      OS.File.remove(
-        OS.Path.join(OS.Constants.Path.profileDir, "kinto.sqlite"),
-        { ignoreAbsent: true }
-      );
+      IOUtils.remove(PathUtils.join(PROFILE_DIR, "kinto.sqlite"), {
+        ignoreAbsent: true,
+      });
     }
 
     if (currentUIVersion < 69) {
       // Clear old social prefs from profile (bug 1460675)
       let socialPrefs = Services.prefs.getBranch("social.");
       if (socialPrefs) {
         let socialPrefsArray = socialPrefs.getChildList("");
         for (let item of socialPrefsArray) {
@@ -3416,31 +3415,28 @@ BrowserGlue.prototype = {
       Services.prefs.setIntPref(
         pref,
         Services.prefs.getIntPref(pref, 1) * 1000
       );
     }
 
     if (currentUIVersion < 73) {
       // Remove blocklist JSON local dumps in profile.
-      OS.File.removeDir(
-        OS.Path.join(OS.Constants.Path.profileDir, "blocklists"),
-        { ignoreAbsent: true }
-      );
-      OS.File.removeDir(
-        OS.Path.join(OS.Constants.Path.profileDir, "blocklists-preview"),
-        { ignoreAbsent: true }
-      );
+      IOUtils.remove(PathUtils.join(PROFILE_DIR, "blocklists"), {
+        recursive: true,
+        ignoreAbsent: true,
+      });
+      IOUtils.remove(PathUtils.join(PROFILE_DIR, "blocklists-preview"), {
+        recursive: true,
+        ignoreAbsent: true,
+      });
       for (const filename of ["addons.json", "plugins.json", "gfx.json"]) {
         // Some old versions used to dump without subfolders. Clean them while we are at it.
-        const path = OS.Path.join(
-          OS.Constants.Path.profileDir,
-          `blocklists-${filename}`
-        );
-        OS.File.remove(path, { ignoreAbsent: true });
+        const path = PathUtils.join(PROFILE_DIR, `blocklists-${filename}`);
+        IOUtils.remove(path, { ignoreAbsent: true });
       }
     }
 
     if (currentUIVersion < 76) {
       // Clear old onboarding prefs from profile (bug 1462415)
       let onboardingPrefs = Services.prefs.getBranch("browser.onboarding.");
       if (onboardingPrefs) {
         let onboardingPrefsArray = onboardingPrefs.getChildList("");
--- a/browser/components/extensions/test/browser/browser_ext_management.js
+++ b/browser/components/extensions/test/browser/browser_ext_management.js
@@ -1,17 +1,16 @@
 "use strict";
 
 const { AddonTestUtils } = ChromeUtils.import(
   "resource://testing-common/AddonTestUtils.jsm"
 );
 
-const { computeHash } = ChromeUtils.import(
-  "resource://gre/modules/addons/ProductAddonChecker.jsm",
-  null
+const { ProductAddonChecker } = ChromeUtils.import(
+  "resource://gre/modules/addons/ProductAddonChecker.jsm"
 );
 
 AddonTestUtils.initMochitest(this);
 
 const testServer = AddonTestUtils.createHttpServer();
 
 add_task(async function test_management_install() {
   await SpecialPowers.pushPrefEnv({
@@ -65,17 +64,20 @@ add_task(async function test_management_
       theme: {
         colors: {
           frame: "orange",
         },
       },
     },
   });
 
-  let themeXPIFileHash = await computeHash("sha256", themeXPIFile.path);
+  let themeXPIFileHash = await ProductAddonChecker.computeHash(
+    "sha256",
+    themeXPIFile.path
+  );
 
   const otherXPIFile = AddonTestUtils.createTempWebExtensionFile({
     manifest: {
       manifest_version: 2,
       name: "Tigers Don't Matter",
       version: "1.0",
       applications: {
         gecko: {
--- a/browser/components/extensions/test/browser/browser_ext_tabs_removeCSS.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_removeCSS.js
@@ -121,24 +121,24 @@ add_task(async function testExecuteScrip
 
   await extension.startup();
 
   await extension.awaitFinish("removeCSS");
 
   // Verify that scripts created by tabs.removeCSS are not added to the content scripts
   // that requires cleanup (Bug 1464711).
   await SpecialPowers.spawn(tab.linkedBrowser, [extension.id], async extId => {
-    const { DocumentManager } = ChromeUtils.import(
-      "resource://gre/modules/ExtensionContent.jsm",
-      null
+    const { ExtensionContent } = ChromeUtils.import(
+      "resource://gre/modules/ExtensionContent.jsm"
     );
 
-    let contentScriptContext = Array.from(
-      DocumentManager.getContexts(content.window).values()
-    ).find(context => context.extension.id === extId);
+    let contentScriptContext = ExtensionContent.getContextByExtensionId(
+      extId,
+      content.window
+    );
 
     for (let script of contentScriptContext.scripts) {
       if (script.matcher.removeCSS && script.requiresCleanup) {
         throw new Error("tabs.removeCSS scripts should not require cleanup");
       }
     }
   }).catch(err => {
     // Log the error so that it is easy to see where the failure is coming from.
--- a/browser/components/newtab/aboutwelcome/content/aboutwelcome.css
+++ b/browser/components/newtab/aboutwelcome/content/aboutwelcome.css
@@ -53,16 +53,21 @@ body[lwt-newtab-brighttext] {
   text-align: center;
   overflow-x: auto;
   height: 100vh;
   background: radial-gradient(79.33% 221.6% at 7.58% 89.55%, #15141A 0%, rgba(21, 20, 26, 0) 54.36%, rgba(21, 20, 26, 0.63) 100%) center/cover no-repeat fixed;
   background-color: #212121;
   --main-content-min-height: 271px;
   --transition: 0.6s opacity, 0.6s scale, 0.6s rotate, 0.6s translate;
 }
+@media (prefers-contrast: more) {
+  .onboardingContainer {
+    background-color: var(--in-content-page-background);
+  }
+}
 @media (prefers-reduced-motion: no-preference) {
   .onboardingContainer {
     --translate: 30px;
     --rotate: 20deg;
     --scale: 0.4;
   }
   .onboardingContainer:dir(rtl) {
     --scale: -0.4 0.4;
--- a/browser/components/newtab/content-src/aboutwelcome/aboutwelcome.scss
+++ b/browser/components/newtab/content-src/aboutwelcome/aboutwelcome.scss
@@ -33,16 +33,20 @@ body {
 
 .onboardingContainer {
   text-align: center;
   overflow-x: auto;
   height: 100vh;
   background: radial-gradient(79.33% 221.6% at 7.58% 89.55%, #15141A 0%, rgba(21, 20, 26, 0) 54.36%, rgba(21, 20, 26, 0.63) 100%) center / cover no-repeat fixed;
   background-color: #212121;
 
+  @media (prefers-contrast: more) {
+    background-color: var(--in-content-page-background);
+  }
+
   --main-content-min-height: 271px;
 
   // Transition all of these and reduced motion effectively only does opacity.
   --transition: 0.6s opacity, 0.6s scale, 0.6s rotate, 0.6s translate;
 
   // Define some variables that are used for in/out states.
   @media (prefers-reduced-motion: no-preference) {
     --translate: 30px;
--- a/browser/components/places/content/places-menupopup.js
+++ b/browser/components/places/content/places-menupopup.js
@@ -566,17 +566,16 @@
   class MozPlacesPopupArrow extends MozPlacesPopup {
     constructor() {
       super();
 
       const event_names = [
         "popupshowing",
         "popuppositioned",
         "popupshown",
-        "transitionend",
         "popuphiding",
         "popuphidden",
       ];
       for (let event_name of event_names) {
         this.addEventListener(event_name, ev => this[`on_${event_name}`](ev));
       }
     }
 
@@ -613,17 +612,16 @@
       }
 
       super.connectedCallback();
       this.initializeAttributeInheritance();
 
       this.setAttribute("flip", "both");
       this.setAttribute("side", "top");
       this.setAttribute("position", "bottomcenter topright");
-      this.style.pointerEvents = "none";
     }
 
     get container() {
       return this.shadowRoot.querySelector(".panel-arrowcontainer");
     }
     get arrowbox() {
       return this.shadowRoot.querySelector(".panel-arrowbox");
     }
@@ -693,74 +691,44 @@
       }
 
       arrow.hidden = false;
     }
 
     on_popupshowing(event) {
       if (event.target == this) {
         this.setAttribute("animate", "open");
+        this.style.pointerEvents = "none";
       }
     }
 
     on_popuppositioned(event) {
       if (event.target == this) {
         this.adjustArrowPosition(event);
       }
     }
 
     on_popupshown(event) {
       if (event.target != this) {
         return;
       }
 
       this.setAttribute("panelopen", "true");
-      let disablePointerEvents;
-      if (!this.hasAttribute("disablepointereventsfortransition")) {
-        let cs = getComputedStyle(this.container);
-        let transitionProp = cs.transitionProperty;
-        let transitionTime = parseFloat(cs.transitionDuration);
-        disablePointerEvents =
-          (transitionProp.includes("transform") || transitionProp == "all") &&
-          transitionTime > 0;
-        this.setAttribute(
-          "disablepointereventsfortransition",
-          disablePointerEvents
-        );
-      } else {
-        disablePointerEvents =
-          this.getAttribute("disablepointereventsfortransition") == "true";
-      }
-      if (!disablePointerEvents) {
-        this.style.removeProperty("pointer-events");
-      }
-    }
-
-    on_transitionend(event) {
-      if (
-        event.originalTarget.classList.contains("panel-arrowcontainer") &&
-        (event.propertyName == "transform" ||
-          event.propertyName == "-moz-window-transform")
-      ) {
-        this.style.removeProperty("pointer-events");
-      }
+      this.style.removeProperty("pointer-events");
     }
 
     on_popuphiding(event) {
       if (event.target == this) {
         this.setAttribute("animate", "cancel");
       }
     }
 
     on_popuphidden(event) {
       if (event.target == this) {
         this.removeAttribute("panelopen");
-        if (this.getAttribute("disablepointereventsfortransition") == "true") {
-          this.style.pointerEvents = "none";
-        }
         this.removeAttribute("animate");
       }
     }
   }
 
   customElements.define("places-popup-arrow", MozPlacesPopupArrow, {
     extends: "menupopup",
   });
--- a/browser/extensions/webcompat/data/shims.js
+++ b/browser/extensions/webcompat/data/shims.js
@@ -480,16 +480,30 @@ const AVAILABLE_SHIMS = [
       "*://hlsrv.vidible.tv/prod/*.m3u8*",
       "*://videos.vidible.tv/prod/*.key*",
       "*://videos.vidible.tv/prod/*.mp4*",
       "*://videos.vidible.tv/prod/*.webm*",
       "*://videos.vidible.tv/prod/*.ts*",
     ],
   },
   {
+    id: "Hamropatro",
+    platform: "desktop",
+    name: "Hamropatro",
+    bug: "1660446",
+    contentScripts: [
+      {
+        js: "hamropatro.js",
+        matches: ["*://we.hamropatro.com/login*"],
+        runAt: "document_start",
+      },
+    ],
+    onlyIfDFPIActive: true,
+  },
+  {
     id: "Kinja",
     platform: "desktop",
     name: "Kinja",
     bug: "1656171",
     contentScripts: [
       {
         js: "kinja.js",
         matches: [
--- a/browser/extensions/webcompat/manifest.json
+++ b/browser/extensions/webcompat/manifest.json
@@ -1,13 +1,13 @@
 {
   "manifest_version": 2,
   "name": "Web Compatibility Interventions",
   "description": "Urgent post-release fixes for web compatibility.",
-  "version": "27.3.0",
+  "version": "27.4.0",
   "applications": {
     "gecko": {
       "id": "webcompat@mozilla.org",
       "strict_min_version": "59.0b5"
     }
   },
 
   "experiment_apis": {
@@ -107,16 +107,17 @@
     "shims/google-ads.js",
     "shims/google-analytics-and-tag-manager.js",
     "shims/google-analytics-ecommerce-plugin.js",
     "shims/google-analytics-legacy.js",
     "shims/google-ima.js",
     "shims/google-page-ad.js",
     "shims/google-publisher-tags.js",
     "shims/google-safeframe.html",
+    "shims/hamropatro.js",
     "shims/iaspet.js",
     "shims/kinja.js",
     "shims/live-test-shim.js",
     "shims/moat.js",
     "shims/mochitest-shim-1.js",
     "shims/mochitest-shim-2.js",
     "shims/mochitest-shim-3.js",
     "shims/optimizely.js",
--- a/browser/extensions/webcompat/moz.build
+++ b/browser/extensions/webcompat/moz.build
@@ -99,16 +99,17 @@ FINAL_TARGET_FILES.features["webcompat@m
     "shims/google-ads.js",
     "shims/google-analytics-and-tag-manager.js",
     "shims/google-analytics-ecommerce-plugin.js",
     "shims/google-analytics-legacy.js",
     "shims/google-ima.js",
     "shims/google-page-ad.js",
     "shims/google-publisher-tags.js",
     "shims/google-safeframe.html",
+    "shims/hamropatro.js",
     "shims/iaspet.js",
     "shims/kinja.js",
     "shims/live-test-shim.js",
     "shims/moat.js",
     "shims/mochitest-shim-1.js",
     "shims/mochitest-shim-2.js",
     "shims/mochitest-shim-3.js",
     "shims/optimizely.js",
new file mode 100644
--- /dev/null
+++ b/browser/extensions/webcompat/shims/hamropatro.js
@@ -0,0 +1,52 @@
+/* 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";
+
+/**
+ * Hamropatro's oauth logins with Google and Facebook redirect through a
+ * different subdomain, and so require the use of the Storage Access API
+ * for dFPI. This shim calls requestStorageAccess on behalf of the site
+ * when a user logs in using Google or Facebook.
+ */
+
+// Origin we need to request storage access for.
+const STORAGE_ACCESS_ORIGIN = "https://hamropatro.firebaseapp.com";
+
+console.warn(
+  `When using oauth, Firefox calls the Storage Access API on behalf of the site. See https://bugzilla.mozilla.org/show_bug.cgi?id=1660446 for details.`
+);
+
+document.documentElement.addEventListener(
+  "click",
+  e => {
+    const { target, isTrusted } = e;
+    if (!isTrusted) {
+      return;
+    }
+
+    const button = target.closest("button");
+    if (!button) {
+      return;
+    }
+
+    const buttonText = button.innerText?.toLowerCase();
+    if (buttonText?.includes("facebook") || buttonText?.includes("google")) {
+      button.disabled = true;
+      button.style.opacity = 0.5;
+      e.stopPropagation();
+      e.preventDefault();
+      document
+        .requestStorageAccessForOrigin(STORAGE_ACCESS_ORIGIN)
+        .then(() => {
+          target.click();
+        })
+        .catch(() => {
+          button.disabled = false;
+          button.style.opacity = 1.0;
+        });
+    }
+  },
+  true
+);
--- a/browser/locales/en-US/pdfviewer/viewer.properties
+++ b/browser/locales/en-US/pdfviewer/viewer.properties
@@ -56,16 +56,18 @@ page_rotate_cw_label=Rotate Clockwise
 page_rotate_ccw.title=Rotate Counterclockwise
 page_rotate_ccw_label=Rotate Counterclockwise
 
 cursor_text_select_tool.title=Enable Text Selection Tool
 cursor_text_select_tool_label=Text Selection Tool
 cursor_hand_tool.title=Enable Hand Tool
 cursor_hand_tool_label=Hand Tool
 
+scroll_page.title=Use Page Scrolling
+scroll_page_label=Page Scrolling
 scroll_vertical.title=Use Vertical Scrolling
 scroll_vertical_label=Vertical Scrolling
 scroll_horizontal.title=Use Horizontal Scrolling
 scroll_horizontal_label=Horizontal Scrolling
 scroll_wrapped.title=Use Wrapped Scrolling
 scroll_wrapped_label=Wrapped Scrolling
 
 spread_none.title=Do not join page spreads
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -79,16 +79,21 @@
 .titlebar-button {
   display: none;
 }
 
 .titlebar-buttonbox-container {
   -moz-box-align: center;
 }
 
+/* Hide window controls in fullscreen */
+:root[inFullscreen] .titlebar-buttonbox-container {
+  display: none;
+}
+
 .titlebar-buttonbox:-moz-locale-dir(ltr) {
   margin-left: 12px;
   margin-right: 0;
 }
 
 .titlebar-buttonbox:-moz-locale-dir(rtl) {
   margin-left: 12px;
   margin-right: 12px;
--- a/browser/themes/shared/downloads/downloads.inc.css
+++ b/browser/themes/shared/downloads/downloads.inc.css
@@ -45,16 +45,17 @@
 @item@:is(.openWhenFinished).hoveringMainArea:hover,
 @item@:not([verdict]) > .downloadButton:hover,
 @item@[verdict]:hover,
 .downloadsPanelFooterButton:hover {
   background-color: var(--panel-item-hover-bgcolor);
 }
 
 @itemFinished@[exists].hoveringMainArea:hover:active,
+@item@:is(.openWhenFinished).hoveringMainArea:hover:active,
 @item@:not([verdict]) > .downloadButton:hover:active,
 .downloadsPanelFooterButton[open="true"],
 @item@[verdict]:hover:active {
   background-color: var(--panel-item-active-bgcolor);
 }
 
 @item@[verdict="Insecure"] .downloadDetails,
 @item@[verdict="Malware"] .downloadDetails {
--- a/devtools/client/inspector/animation/test/browser.ini
+++ b/devtools/client/inspector/animation/test/browser.ini
@@ -46,16 +46,18 @@ skip-if =
   (os == "linux" && !debug && !asan && !swgl && !ccov) # Bug 1665011
   win10_2004 # Bug 1723573
 [browser_animation_animation-target_select.js]
 [browser_animation_animation-timeline-tick.js]
 [browser_animation_css-transition-with-playstate-idle.js]
 [browser_animation_current-time-label.js]
 [browser_animation_current-time-scrubber.js]
 [browser_animation_current-time-scrubber-rtl.js]
+skip-if = 
+  os == "linux" && debug # Bug 1721716
 [browser_animation_current-time-scrubber_each-different-creation-time-animations.js]
 [browser_animation_current-time-scrubber-with-negative-delay.js]
 [browser_animation_empty_on_invalid_nodes.js]
 [browser_animation_fission_switch-target.js]
 [browser_animation_indication-bar.js]
 [browser_animation_infinity-duration_current-time-scrubber.js]
 [browser_animation_infinity-duration_summary-graph.js]
 [browser_animation_infinity-duration_tick-label.js]
--- a/devtools/client/storage/test/browser_storage_cache_navigation.js
+++ b/devtools/client/storage/test/browser_storage_cache_navigation.js
@@ -2,81 +2,77 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* import-globals-from head.js */
 
 "use strict";
 
 add_task(async function() {
-  // Using https-first for this test is blocked on Bug 1733420.
-  // We cannot assert cache status "OK" with HTTPS requests to httpd.js.
-  await pushPref("dom.security.https_first", false);
-
-  const URL1 = buildInsecureURLWithContent(
+  const URL1 = buildURLWithContent(
     "example.com",
     `<h1>example.com</h1>` +
       `<script>
         caches.open("lorem").then(cache => {
-          cache.add("${URL_ROOT_COM}storage-blank.html");
+          cache.add("${URL_ROOT_COM_SSL}storage-blank.html");
         });
         function clear() {
           caches.delete("lorem");
         }
       </script>`
   );
-  const URL2 = buildInsecureURLWithContent(
+  const URL2 = buildURLWithContent(
     "example.net",
     `<h1>example.net</h1>` +
       `<script>
         caches.open("foo").then(cache => {
-          cache.add("${URL_ROOT_NET}storage-blank.html");
+          cache.add("${URL_ROOT_NET_SSL}storage-blank.html");
         });
         function clear() {
           caches.delete("foo");
         }
       </script>`
   );
 
   // open tab
   await openTabAndSetupStorage(URL1);
   const doc = gPanelWindow.document;
 
   // Check first domain
   // check that host appears in the storage tree
-  checkTree(doc, ["Cache", "http://example.com", "lorem"]);
+  checkTree(doc, ["Cache", "https://example.com", "lorem"]);
   // check the table for values
-  await selectTreeItem(["Cache", "http://example.com", "lorem"]);
-  checkCacheData(URL_ROOT_COM + "storage-blank.html", "OK");
+  await selectTreeItem(["Cache", "https://example.com", "lorem"]);
+  checkCacheData(URL_ROOT_COM_SSL + "storage-blank.html", "OK");
 
   // clear up the cache before navigating
   info("Cleaning up cache…");
   await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() {
     const win = content.wrappedJSObject;
     await win.clear();
   });
 
   // Check second domain
   await navigateTo(URL2);
 
   // Select the Cache view in order to force updating it
-  await selectTreeItem(["Cache", "http://example.net"]);
+  await selectTreeItem(["Cache", "https://example.net"]);
 
   // wait for storage tree refresh, and check host
   info("Waiting for storage tree to update…");
-  await waitUntil(() => isInTree(doc, ["Cache", "http://example.net", "foo"]));
+  await waitUntil(() => isInTree(doc, ["Cache", "https://example.net", "foo"]));
 
   ok(
-    !isInTree(doc, ["Cache", "http://example.com"]),
+    !isInTree(doc, ["Cache", "https://example.com"]),
     "example.com item is not in the tree anymore"
   );
 
   // check the table for values
-  await selectTreeItem(["Cache", "http://example.net", "foo"]);
-  checkCacheData(URL_ROOT_NET + "storage-blank.html", "OK");
+  await selectTreeItem(["Cache", "https://example.net", "foo"]);
+  checkCacheData(URL_ROOT_NET_SSL + "storage-blank.html", "OK");
 
   info("Check that the Cache node still has the expected label");
   is(
     getTreeNodeLabel(doc, ["Cache"]),
     "Cache Storage",
     "Cache item is properly displayed"
   );
 });
--- a/devtools/client/storage/test/browser_storage_fission_cache.js
+++ b/devtools/client/storage/test/browser_storage_fission_cache.js
@@ -2,34 +2,30 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* import-globals-from head.js */
 
 "use strict";
 
 add_task(async function() {
-  // Using https-first for this test is blocked on Bug 1733420.
-  // We cannot assert cache status "OK" with HTTPS requests to httpd.js.
-  await pushPref("dom.security.https_first", false);
-
   // open tab
-  const URL = URL_ROOT_COM + "storage-cache-basic.html";
+  const URL = URL_ROOT_COM_SSL + "storage-cache-basic.html";
   await openTabAndSetupStorage(URL);
   const doc = gPanelWindow.document;
 
   // check that host appears in the storage tree
-  checkTree(doc, ["Cache", "http://example.com", "lorem"]);
-  checkTree(doc, ["Cache", "http://example.net", "foo"]);
+  checkTree(doc, ["Cache", "https://example.com", "lorem"]);
+  checkTree(doc, ["Cache", "https://example.net", "foo"]);
   // Check top level page
-  await selectTreeItem(["Cache", "http://example.com", "lorem"]);
-  checkCacheData(URL_ROOT_COM + "storage-blank.html", "OK");
+  await selectTreeItem(["Cache", "https://example.com", "lorem"]);
+  checkCacheData(URL_ROOT_COM_SSL + "storage-blank.html", "OK");
   // Check iframe
-  await selectTreeItem(["Cache", "http://example.net", "foo"]);
-  checkCacheData(URL_ROOT_NET + "storage-blank.html", "OK");
+  await selectTreeItem(["Cache", "https://example.net", "foo"]);
+  checkCacheData(URL_ROOT_NET_SSL + "storage-blank.html", "OK");
 });
 
 function checkCacheData(url, status) {
   is(
     gUI.table.items.get(url)?.status,
     status,
     `Table row has an entry for: ${url} with status: ${status}`
   );
--- a/devtools/client/storage/test/head.js
+++ b/devtools/client/storage/test/head.js
@@ -1148,23 +1148,16 @@ function hasStorageData(name, value) {
  * @param {String} html
  * @param {String} protocol
  */
 function buildURLWithContent(domain, html, protocol = "https") {
   return `${protocol}://${domain}/document-builder.sjs?html=${encodeURI(html)}`;
 }
 
 /**
- * Same as buildURLWithContent, but will use http instead of https.
- */
-function buildInsecureURLWithContent(domain, html) {
-  return buildURLWithContent(domain, html, "http");
-}
-
-/**
  * Asserts that the given cookie holds the provided value in the data table
  * @param {String} name
  * @param {String} value
  */
 function checkCookieData(name, value) {
   ok(
     hasCookieData(name, value),
     `Table row has an entry for: ${name} with value: ${value}`
--- a/devtools/client/storage/test/storage-cache-basic.html
+++ b/devtools/client/storage/test/storage-cache-basic.html
@@ -13,11 +13,11 @@
       cache.add("storage-blank.html");
     });
   }
   function clear() { // eslint-disable-line no-unused-vars
     caches.delete("lorem");
   }
 </script>
 
-<iframe src="http://example.net/browser/devtools/client/storage/test/storage-cache-basic-iframe.html"></iframe>
+<iframe src="https://example.net/browser/devtools/client/storage/test/storage-cache-basic-iframe.html"></iframe>
 </body>
 </html>
--- a/devtools/server/actors/errordocs.js
+++ b/devtools/server/actors/errordocs.js
@@ -26,16 +26,17 @@ const ErrorDocs = {
   JSMSG_BAD_ARRAY_LENGTH: "Invalid_array_length",
   JSMSG_NEGATIVE_REPETITION_COUNT: "Negative_repetition_count",
   JSMSG_RESULTING_STRING_TOO_LARGE: "Resulting_string_too_large",
   JSMSG_BAD_RADIX: "Bad_radix",
   JSMSG_PRECISION_RANGE: "Precision_range",
   JSMSG_STMT_AFTER_RETURN: "Stmt_after_return",
   JSMSG_NOT_A_CODEPOINT: "Not_a_codepoint",
   JSMSG_BAD_SORT_ARG: "Array_sort_argument",
+  JSMSG_BAD_WITHSORTED_ARG: "Array_withSorted_argument",
   JSMSG_UNEXPECTED_TYPE: "Unexpected_type",
   JSMSG_NOT_DEFINED: "Not_defined",
   JSMSG_NOT_FUNCTION: "Not_a_function",
   JSMSG_EQUAL_AS_ASSIGN: "Equal_as_assign",
   JSMSG_UNDEFINED_PROP: "Undefined_prop",
   JSMSG_DEPRECATED_PRAGMA: "Deprecated_source_map_pragma",
   JSMSG_DEPRECATED_USAGE: "Deprecated_caller_or_arguments_usage",
   JSMSG_CANT_DELETE: "Cant_delete",
--- a/docs/contributing/debugging/debugging_firefox_with_valgrind.rst
+++ b/docs/contributing/debugging/debugging_firefox_with_valgrind.rst
@@ -24,21 +24,21 @@ of a rough ride.
    rate than on Linux.
 -  Valgrind's handling of malloc zones on Yosemite is imperfect. Regard
    leak reports with caution.
 -  Valgrind has been known to cause kernel panics, for unknown reasons.
 
 Where to get Valgrind
 ---------------------
 
-Linux: Download `Valgrind <http://valgrind.org/>`__ directly, or use
+Linux: Download `Valgrind <https://valgrind.org/>`__ directly, or use
 your distribution's package manager (if it has a recent enough version).
 
 MacOSX: `Get Valgrind trunk from
-SVN <http://valgrind.org/downloads/repository.html>`__ and build it.
+SVN <https://valgrind.org/downloads/repository.html>`__ and build it.
 Don't use 3.10.x or any other tarball.
 
 Make sure you have Valgrind 3.14 or later, version 3.16.1 is known to work,
 3.13.0 did not.  Newer versions tend to have better compatibility with both
 Firefox's JITs and newer toolchain components (compiler, libc and linker
 versions).
 
 Basics
@@ -159,17 +159,17 @@ you are hunting down such an error, it's
 waiting for.
 
 Additional help
 ---------------
 
 The `Valgrind Quick Start
 Guide <http://www.valgrind.org/docs/manual/quick-start.html>`__ is short
 and worth reading. The `User
-Manual <http://valgrind.org/docs/manual/manual.html>`__ is also useful.
+Manual <https://valgrind.org/docs/manual/manual.html>`__ is also useful.
 
 If Valgrind asserts, crashes, doesn't do what you expect, or otherwise
 acts up, first of all read this page and make sure you have both Firefox
 and Valgrind correctly configured.  If that's all OK, try using the
 `Valgrind trunk from
 SVN <http://www.valgrind.org/downloads/repository.html>`__.  Oftentimes
 bugs are fixed in the trunk before most users fall across them.  If that
 doesn't help, consider `filing a bug
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -24,16 +24,17 @@
 #include "mozilla/AutoRestore.h"
 #include "mozilla/HoldDropJSObjects.h"
 #include "nsHTMLTags.h"
 #include "jsapi.h"
 #include "js/ForOfIterator.h"       // JS::ForOfIterator
 #include "js/PropertyAndElement.h"  // JS_GetProperty, JS_GetUCProperty
 #include "xpcprivate.h"
 #include "nsGlobalWindow.h"
+#include "nsNameSpaceManager.h"
 
 namespace mozilla::dom {
 
 //-----------------------------------------------------
 // CustomElementUpgradeReaction
 
 class CustomElementUpgradeReaction final : public CustomElementReaction {
  public:
@@ -1214,18 +1215,18 @@ void CustomElementRegistry::Upgrade(Elem
 
       const nsAttrName* name = info.mName;
       nsAtom* attrName = name->LocalName();
 
       if (aDefinition->IsInObservedAttributeList(attrName)) {
         int32_t namespaceID = name->NamespaceID();
         nsAutoString attrValue, namespaceURI;
         info.mValue->ToString(attrValue);
-        nsContentUtils::NameSpaceManager()->GetNameSpaceURI(namespaceID,
-                                                            namespaceURI);
+        nsNameSpaceManager::GetInstance()->GetNameSpaceURI(namespaceID,
+                                                           namespaceURI);
 
         LifecycleCallbackArgs args = {
             nsDependentAtomString(attrName), VoidString(), attrValue,
             (namespaceURI.IsEmpty() ? VoidString() : namespaceURI)};
         nsContentUtils::EnqueueLifecycleCallback(
             ElementCallbackType::eAttributeChanged, aElement, &args, nullptr,
             aDefinition);
       }
--- a/dom/base/DocumentOrShadowRoot.cpp
+++ b/dom/base/DocumentOrShadowRoot.cpp
@@ -12,20 +12,22 @@
 #include "mozilla/StyleSheet.h"
 #include "mozilla/SVGUtils.h"
 #include "mozilla/dom/AnimatableBinding.h"
 #include "mozilla/dom/Document.h"
 #include "mozilla/dom/HTMLInputElement.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "mozilla/dom/StyleSheetList.h"
 #include "nsTHashtable.h"
+#include "nsContentUtils.h"
 #include "nsFocusManager.h"
 #include "nsIRadioVisitor.h"
 #include "nsIFormControl.h"
 #include "nsLayoutUtils.h"
+#include "nsNameSpaceManager.h"
 #include "nsWindowSizes.h"
 
 namespace mozilla::dom {
 
 DocumentOrShadowRoot::DocumentOrShadowRoot(ShadowRoot* aShadowRoot)
     : mAsNode(aShadowRoot), mKind(Kind::ShadowRoot) {
   MOZ_ASSERT(mAsNode);
 }
@@ -259,17 +261,17 @@ already_AddRefed<nsContentList> Document
 }
 
 already_AddRefed<nsContentList> DocumentOrShadowRoot::GetElementsByTagNameNS(
     const nsAString& aNamespaceURI, const nsAString& aLocalName,
     ErrorResult& aResult) {
   int32_t nameSpaceId = kNameSpaceID_Wildcard;
 
   if (!aNamespaceURI.EqualsLiteral("*")) {
-    aResult = nsContentUtils::NameSpaceManager()->RegisterNameSpace(
+    aResult = nsNameSpaceManager::GetInstance()->RegisterNameSpace(
         aNamespaceURI, nameSpaceId);
     if (aResult.Failed()) {
       return nullptr;
     }
   }
 
   NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
   return NS_GetContentList(&AsNode(), nameSpaceId, aLocalName);
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1476,17 +1476,17 @@ already_AddRefed<Attr> Element::RemoveAt
   nsAutoString nameSpaceURI;
   aAttribute.NodeInfo()->GetNamespaceURI(nameSpaceURI);
   return Attributes()->RemoveNamedItemNS(
       nameSpaceURI, aAttribute.NodeInfo()->LocalName(), aError);
 }
 
 void Element::GetAttributeNS(const nsAString& aNamespaceURI,
                              const nsAString& aLocalName, nsAString& aReturn) {
-  int32_t nsid = nsContentUtils::NameSpaceManager()->GetNameSpaceID(
+  int32_t nsid = nsNameSpaceManager::GetInstance()->GetNameSpaceID(
       aNamespaceURI, nsContentUtils::IsChromeDoc(OwnerDoc()));
 
   if (nsid == kNameSpaceID_Unknown) {
     // Unknown namespace means no attribute.
     SetDOMStringToNull(aReturn);
     return;
   }
 
@@ -1549,17 +1549,17 @@ void Element::SetAttributeDevtoolsNS(con
   RefPtr<nsIPrincipal> dtPrincipal = CreateDevtoolsPrincipal();
   SetAttributeNS(aNamespaceURI, aLocalName, aValue, dtPrincipal, aError);
 }
 
 void Element::RemoveAttributeNS(const nsAString& aNamespaceURI,
                                 const nsAString& aLocalName,
                                 ErrorResult& aError) {
   RefPtr<nsAtom> name = NS_AtomizeMainThread(aLocalName);
-  int32_t nsid = nsContentUtils::NameSpaceManager()->GetNameSpaceID(
+  int32_t nsid = nsNameSpaceManager::GetInstance()->GetNameSpaceID(
       aNamespaceURI, nsContentUtils::IsChromeDoc(OwnerDoc()));
 
   if (nsid == kNameSpaceID_Unknown) {
     // If the namespace ID is unknown, it means there can't possibly be an
     // existing attribute. We would need a known namespace ID to pass into
     // UnsetAttr, so we return early if we don't have one.
     return;
   }
@@ -1583,31 +1583,31 @@ already_AddRefed<Attr> Element::SetAttri
 }
 
 already_AddRefed<nsIHTMLCollection> Element::GetElementsByTagNameNS(
     const nsAString& aNamespaceURI, const nsAString& aLocalName,
     ErrorResult& aError) {
   int32_t nameSpaceId = kNameSpaceID_Wildcard;
 
   if (!aNamespaceURI.EqualsLiteral("*")) {
-    aError = nsContentUtils::NameSpaceManager()->RegisterNameSpace(
-        aNamespaceURI, nameSpaceId);
+    aError = nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespaceURI,
+                                                                  nameSpaceId);
     if (aError.Failed()) {
       return nullptr;
     }
   }
 
   NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
 
   return NS_GetContentList(this, nameSpaceId, aLocalName);
 }
 
 bool Element::HasAttributeNS(const nsAString& aNamespaceURI,
                              const nsAString& aLocalName) const {
-  int32_t nsid = nsContentUtils::NameSpaceManager()->GetNameSpaceID(
+  int32_t nsid = nsNameSpaceManager::GetInstance()->GetNameSpaceID(
       aNamespaceURI, nsContentUtils::IsChromeDoc(OwnerDoc()));
 
   if (nsid == kNameSpaceID_Unknown) {
     // Unknown namespace means no attr...
     return false;
   }
 
   RefPtr<nsAtom> name = NS_AtomizeMainThread(aLocalName);
@@ -2499,17 +2499,17 @@ nsresult Element::SetAttrAndNotify(
         oldValueAtom = oldValue->GetAsAtom();
       } else {
         // If there is no old value, get the value of the uninitialized
         // attribute that was swapped with aParsedValue.
         oldValueAtom = aParsedValue.GetAsAtom();
       }
       RefPtr<nsAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom();
       nsAutoString ns;
-      nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
+      nsNameSpaceManager::GetInstance()->GetNameSpaceURI(aNamespaceID, ns);
 
       LifecycleCallbackArgs args = {nsDependentAtomString(aName),
                                     aModType == MutationEvent_Binding::ADDITION
                                         ? VoidString()
                                         : nsDependentAtomString(oldValueAtom),
                                     nsDependentAtomString(newValueAtom),
                                     (ns.IsEmpty() ? VoidString() : ns)};
 
@@ -2540,17 +2540,17 @@ nsresult Element::SetAttrAndNotify(
         this, aNamespaceID, aName, aModType,
         aParsedValue.StoresOwnData() ? &aParsedValue : nullptr);
   }
 
   if (aFireMutation) {
     InternalMutationEvent mutation(true, eLegacyAttrModified);
 
     nsAutoString ns;
-    nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
+    nsNameSpaceManager::GetInstance()->GetNameSpaceURI(aNamespaceID, ns);
     Attr* attrNode =
         GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName));
     mutation.mRelatedNode = attrNode;
 
     mutation.mAttrName = aName;
     nsAutoString newValue;
     GetAttr(aNamespaceID, aName, newValue);
     if (!newValue.IsEmpty()) {
@@ -2685,17 +2685,17 @@ nsresult Element::OnAttrSetButNotChanged
                                          bool aNotify) {
   const CustomElementData* data = GetCustomElementData();
   if (data && data->mState == CustomElementData::State::eCustom) {
     CustomElementDefinition* definition = data->GetCustomElementDefinition();
     MOZ_ASSERT(definition, "Should have a valid CustomElementDefinition");
 
     if (definition->IsInObservedAttributeList(aName)) {
       nsAutoString ns;
-      nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
+      nsNameSpaceManager::GetInstance()->GetNameSpaceURI(aNamespaceID, ns);
 
       nsAutoString value(aValue.String());
       LifecycleCallbackArgs args = {nsDependentAtomString(aName), value, value,
                                     (ns.IsEmpty() ? VoidString() : ns)};
 
       nsContentUtils::EnqueueLifecycleCallback(
           ElementCallbackType::eAttributeChanged, this, &args, nullptr,
           definition);
@@ -2762,17 +2762,17 @@ nsresult Element::UnsetAttr(int32_t aNam
                      this, NS_EVENT_BITS_MUTATION_ATTRMODIFIED, this);
 
   PreIdMaybeChange(aNameSpaceID, aName, nullptr);
 
   // Grab the attr node if needed before we remove it from the attr map
   RefPtr<Attr> attrNode;
   if (hasMutationListeners) {
     nsAutoString ns;
-    nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns);
+    nsNameSpaceManager::GetInstance()->GetNameSpaceURI(aNameSpaceID, ns);
     attrNode = GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName));
   }
 
   // Clear the attribute out from attribute map.
   nsDOMSlots* slots = GetExistingDOMSlots();
   if (slots && slots->mAttributeMap) {
     slots->mAttributeMap->DropAttribute(aNameSpaceID, aName);
   }
@@ -2797,17 +2797,17 @@ nsresult Element::UnsetAttr(int32_t aNam
 
   const CustomElementData* data = GetCustomElementData();
   if (data && data->mState == CustomElementData::State::eCustom) {
     CustomElementDefinition* definition = data->GetCustomElementDefinition();
     MOZ_ASSERT(definition, "Should have a valid CustomElementDefinition");
 
     if (definition->IsInObservedAttributeList(aName)) {
       nsAutoString ns;
-      nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns);
+      nsNameSpaceManager::GetInstance()->GetNameSpaceURI(aNameSpaceID, ns);
 
       RefPtr<nsAtom> oldValueAtom = oldValue.GetAsAtom();
       LifecycleCallbackArgs args = {
           nsDependentAtomString(aName), nsDependentAtomString(oldValueAtom),
           VoidString(), (ns.IsEmpty() ? VoidString() : ns)};
 
       nsContentUtils::EnqueueLifecycleCallback(
           ElementCallbackType::eAttributeChanged, this, &args, nullptr,
--- a/dom/base/NodeInfo.cpp
+++ b/dom/base/NodeInfo.cpp
@@ -150,29 +150,29 @@ void NodeInfo::GetPrefix(nsAString& aPre
     mInner.mPrefix->ToString(aPrefix);
   } else {
     SetDOMStringToNull(aPrefix);
   }
 }
 
 void NodeInfo::GetNamespaceURI(nsAString& aNameSpaceURI) const {
   if (mInner.mNamespaceID > 0) {
-    nsresult rv = nsContentUtils::NameSpaceManager()->GetNameSpaceURI(
+    nsresult rv = nsNameSpaceManager::GetInstance()->GetNameSpaceURI(
         mInner.mNamespaceID, aNameSpaceURI);
     // How can we possibly end up with a bogus namespace ID here?
     if (NS_FAILED(rv)) {
       MOZ_CRASH();
     }
   } else {
     SetDOMStringToNull(aNameSpaceURI);
   }
 }
 
 bool NodeInfo::NamespaceEquals(const nsAString& aNamespaceURI) const {
-  int32_t nsid = nsContentUtils::NameSpaceManager()->GetNameSpaceID(
+  int32_t nsid = nsNameSpaceManager::GetInstance()->GetNameSpaceID(
       aNamespaceURI, nsContentUtils::IsChromeDoc(mOwnerManager->GetDocument()));
 
   return mozilla::dom::NodeInfo::NamespaceEquals(nsid);
 }
 
 void NodeInfo::DeleteCycleCollectable() {
   RefPtr<nsNodeInfoManager> kungFuDeathGrip = mOwnerManager;
   mozilla::Unused
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -410,17 +410,16 @@ using namespace mozilla::widget;
 using namespace mozilla;
 
 const char kLoadAsData[] = "loadAsData";
 
 nsIXPConnect* nsContentUtils::sXPConnect;
 nsIScriptSecurityManager* nsContentUtils::sSecurityManager;
 nsIPrincipal* nsContentUtils::sSystemPrincipal;
 nsIPrincipal* nsContentUtils::sNullSubjectPrincipal;
-nsNameSpaceManager* nsContentUtils::sNameSpaceManager;
 nsIIOService* nsContentUtils::sIOService;
 nsIUUIDGenerator* nsContentUtils::sUUIDGenerator;
 nsIConsoleService* nsContentUtils::sConsoleService;
 nsTHashMap<nsRefPtrHashKey<nsAtom>, EventNameMapping>*
     nsContentUtils::sAtomEventTable = nullptr;
 nsTHashMap<nsStringHashKey, EventNameMapping>*
     nsContentUtils::sStringEventTable = nullptr;
 nsTArray<RefPtr<nsAtom>>* nsContentUtils::sUserDefinedEvents = nullptr;
@@ -739,20 +738,16 @@ nsresult nsContentUtils::Init() {
   if (sInitialized) {
     NS_WARNING("Init() called twice");
 
     return NS_OK;
   }
 
   nsHTMLTags::AddRefTable();
 
-  sNameSpaceManager = nsNameSpaceManager::GetInstance();
-  NS_ENSURE_TRUE(sNameSpaceManager, NS_ERROR_OUT_OF_MEMORY);
-  NS_ADDREF(sNameSpaceManager);
-
   sXPConnect = nsXPConnect::XPConnect();
   // We hold a strong ref to sXPConnect to ensure that it does not go away until
   // nsLayoutStatics::Shutdown is happening.  Otherwise ~nsXPConnect can be
   // triggered by xpcModuleDtor late in shutdown and cause crashes due to
   // various stuff already being torn down by then.  Note that this means that
   // we are effectively making sure that if we leak nsLayoutStatics then we also
   // leak nsXPConnect.
   NS_ADDREF(sXPConnect);
@@ -1878,17 +1873,16 @@ void nsContentUtils::Shutdown() {
   NS_IF_RELEASE(sStringBundleService);
   NS_IF_RELEASE(sConsoleService);
   NS_IF_RELEASE(sXPConnect);
   NS_IF_RELEASE(sSecurityManager);
   NS_IF_RELEASE(sSystemPrincipal);
   NS_IF_RELEASE(sNullSubjectPrincipal);
   NS_IF_RELEASE(sIOService);
   NS_IF_RELEASE(sUUIDGenerator);
-  NS_IF_RELEASE(sNameSpaceManager);
   sLineBreaker = nullptr;
   sWordBreaker = nullptr;
   sBidiKeyboard = nullptr;
 
   delete sAtomEventTable;
   sAtomEventTable = nullptr;
   delete sStringEventTable;
   sStringEventTable = nullptr;
@@ -3342,17 +3336,17 @@ nsresult nsContentUtils::SplitQName(cons
   if (colon) {
     const char16_t* end;
     aQName.EndReading(end);
     nsAutoString nameSpace;
     rv = aNamespaceResolver->LookupNamespaceURIInternal(
         Substring(aQName.get(), colon), nameSpace);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    *aNamespace = NameSpaceManager()->GetNameSpaceID(
+    *aNamespace = nsNameSpaceManager::GetInstance()->GetNameSpaceID(
         nameSpace, nsContentUtils::IsChromeDoc(aNamespaceResolver->OwnerDoc()));
     if (*aNamespace == kNameSpaceID_Unknown) return NS_ERROR_FAILURE;
 
     *aLocalName = NS_AtomizeMainThread(Substring(colon + 1, end)).take();
   } else {
     *aNamespace = kNameSpaceID_None;
     *aLocalName = NS_AtomizeMainThread(aQName).take();
   }
@@ -3366,17 +3360,17 @@ nsresult nsContentUtils::GetNodeInfoFrom
     nsNodeInfoManager* aNodeInfoManager, uint16_t aNodeType,
     mozilla::dom::NodeInfo** aNodeInfo) {
   const nsString& qName = PromiseFlatString(aQualifiedName);
   const char16_t* colon;
   nsresult rv = nsContentUtils::CheckQName(qName, true, &colon);
   NS_ENSURE_SUCCESS(rv, rv);
 
   int32_t nsID;
-  sNameSpaceManager->RegisterNameSpace(aNamespaceURI, nsID);
+  nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespaceURI, nsID);
   if (colon) {
     const char16_t* end;
     qName.EndReading(end);
 
     RefPtr<nsAtom> prefix = NS_AtomizeMainThread(Substring(qName.get(), colon));
 
     rv = aNodeInfoManager->GetNodeInfo(Substring(colon + 1, end), prefix, nsID,
                                        aNodeType, aNodeInfo);
@@ -3417,22 +3411,18 @@ void nsContentUtils::SplitExpatName(cons
       } else {
         uriEnd = pos;
       }
     }
   }
 
   const char16_t* nameStart;
   if (uriEnd) {
-    if (sNameSpaceManager) {
-      sNameSpaceManager->RegisterNameSpace(
-          nsDependentSubstring(aExpatName, uriEnd), *aNameSpaceID);
-    } else {
-      *aNameSpaceID = kNameSpaceID_Unknown;
-    }
+    nsNameSpaceManager::GetInstance()->RegisterNameSpace(
+        nsDependentSubstring(aExpatName, uriEnd), *aNameSpaceID);
 
     nameStart = (uriEnd + 1);
     if (nameEnd) {
       const char16_t* prefixStart = nameEnd + 1;
       *aPrefix = NS_AtomizeMainThread(Substring(prefixStart, pos)).take();
     } else {
       nameEnd = pos;
       *aPrefix = nullptr;
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -108,17 +108,16 @@ class nsISerialEventTarget;
 class nsIStringBundle;
 class nsIStringBundleService;
 class nsISupports;
 class nsITransferable;
 class nsIURI;
 class nsIUUIDGenerator;
 class nsIWidget;
 class nsIXPConnect;
-class nsNameSpaceManager;
 class nsNodeInfoManager;
 class nsPIWindowRoot;
 class nsPresContext;
 class nsStringBuffer;
 class nsStringHashKey;
 class nsTextFragment;
 class nsView;
 class nsWrapperCache;
@@ -753,18 +752,16 @@ class nsContentUtils {
    * depending on the context), this function returns false.
    */
   static bool IsAbsoluteURL(const nsACString& aURL);
 
   // Check if a node is in the document prolog, i.e. before the document
   // element.
   static bool InProlog(nsINode* aNode);
 
-  static nsNameSpaceManager* NameSpaceManager() { return sNameSpaceManager; }
-
   static nsIIOService* GetIOService() { return sIOService; }
 
   static nsIBidiKeyboard* GetBidiKeyboard();
 
   /**
    * Get the cache security manager service. Can return null if the layout
    * module has been shut down.
    */
@@ -3344,18 +3341,16 @@ class nsContentUtils {
       nsIContent* aContent1, nsIContent* aContent2);
 
   static nsIXPConnect* sXPConnect;
 
   static nsIScriptSecurityManager* sSecurityManager;
   static nsIPrincipal* sSystemPrincipal;
   static nsIPrincipal* sNullSubjectPrincipal;
 
-  static nsNameSpaceManager* sNameSpaceManager;
-
   static nsIIOService* sIOService;
   static nsIUUIDGenerator* sUUIDGenerator;
 
   static nsIConsoleService* sConsoleService;
 
   static nsTHashMap<nsRefPtrHashKey<nsAtom>, EventNameMapping>* sAtomEventTable;
   static nsTHashMap<nsStringHashKey, EventNameMapping>* sStringEventTable;
   static nsTArray<RefPtr<nsAtom>>* sUserDefinedEvents;
--- a/dom/base/nsDOMAttributeMap.cpp
+++ b/dom/base/nsDOMAttributeMap.cpp
@@ -336,17 +336,17 @@ already_AddRefed<mozilla::dom::NodeInfo>
     const nsAString& aNamespaceURI, const nsAString& aLocalName) {
   if (!mContent) {
     return nullptr;
   }
 
   int32_t nameSpaceID = kNameSpaceID_None;
 
   if (!aNamespaceURI.IsEmpty()) {
-    nameSpaceID = nsContentUtils::NameSpaceManager()->GetNameSpaceID(
+    nameSpaceID = nsNameSpaceManager::GetInstance()->GetNameSpaceID(
         aNamespaceURI, nsContentUtils::IsChromeDoc(mContent->OwnerDoc()));
 
     if (nameSpaceID == kNameSpaceID_Unknown) {
       return nullptr;
     }
   }
 
   uint32_t i, count = mContent->GetAttrCount();
--- a/dom/base/nsDOMMutationObserver.cpp
+++ b/dom/base/nsDOMMutationObserver.cpp
@@ -16,16 +16,17 @@
 #include "mozilla/dom/DocGroup.h"
 
 #include "mozilla/BasePrincipal.h"
 
 #include "nsContentUtils.h"
 #include "nsCSSPseudoElements.h"
 #include "nsError.h"
 #include "nsIScriptGlobalObject.h"
+#include "nsNameSpaceManager.h"
 #include "nsServiceManagerUtils.h"
 #include "nsTextFragment.h"
 #include "nsThreadUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using mozilla::dom::DocGroup;
 using mozilla::dom::HTMLSlotElement;
@@ -183,18 +184,18 @@ void nsMutationReceiver::AttributeWillCh
   NS_ASSERTION(!m->mTarget || m->mTarget == aElement, "Wrong target!");
   NS_ASSERTION(!m->mAttrName || m->mAttrName == aAttribute, "Wrong attribute!");
   if (!m->mTarget) {
     m->mTarget = aElement;
     m->mAttrName = aAttribute;
     if (aNameSpaceID == kNameSpaceID_None) {
       m->mAttrNamespace.SetIsVoid(true);
     } else {
-      nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID,
-                                                          m->mAttrNamespace);
+      nsNameSpaceManager::GetInstance()->GetNameSpaceURI(aNameSpaceID,
+                                                         m->mAttrNamespace);
     }
   }
 
   if (AttributeOldValue() && m->mPrevValue.IsVoid()) {
     if (!aElement->GetAttr(aNameSpaceID, aAttribute, m->mPrevValue)) {
       m->mPrevValue.SetIsVoid(true);
     }
   }
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -2017,17 +2017,17 @@ already_AddRefed<nsIHTMLCollection> nsIN
 
 already_AddRefed<nsIHTMLCollection> nsINode::GetElementsByAttributeNS(
     const nsAString& aNamespaceURI, const nsAString& aAttribute,
     const nsAString& aValue, ErrorResult& aRv) {
   RefPtr<nsAtom> attrAtom(NS_Atomize(aAttribute));
 
   int32_t nameSpaceId = kNameSpaceID_Wildcard;
   if (!aNamespaceURI.EqualsLiteral("*")) {
-    nsresult rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(
+    nsresult rv = nsNameSpaceManager::GetInstance()->RegisterNameSpace(
         aNamespaceURI, nameSpaceId);
     if (NS_FAILED(rv)) {
       aRv.Throw(rv);
       return nullptr;
     }
   }
 
   RefPtr<nsContentList> list = new nsContentList(
--- a/dom/base/nsNodeInfoManager.cpp
+++ b/dom/base/nsNodeInfoManager.cpp
@@ -205,17 +205,17 @@ nsresult nsNodeInfoManager::GetNodeInfo(
 
 nsresult nsNodeInfoManager::GetNodeInfo(const nsAString& aName, nsAtom* aPrefix,
                                         const nsAString& aNamespaceURI,
                                         uint16_t aNodeType,
                                         NodeInfo** aNodeInfo) {
   int32_t nsid = kNameSpaceID_None;
 
   if (!aNamespaceURI.IsEmpty()) {
-    nsresult rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(
+    nsresult rv = nsNameSpaceManager::GetInstance()->RegisterNameSpace(
         aNamespaceURI, nsid);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return GetNodeInfo(aName, aPrefix, nsid, aNodeType, aNodeInfo);
 }
 
 already_AddRefed<NodeInfo> nsNodeInfoManager::GetTextNodeInfo() {
--- a/dom/serializers/nsXHTMLContentSerializer.cpp
+++ b/dom/serializers/nsXHTMLContentSerializer.cpp
@@ -237,17 +237,17 @@ bool nsXHTMLContentSerializer::Serialize
     if (attrPrefix) {
       attrPrefix->ToString(prefixStr);
     } else {
       prefixStr.Truncate();
     }
 
     bool addNSAttr = false;
     if (kNameSpaceID_XMLNS != namespaceID) {
-      nsContentUtils::NameSpaceManager()->GetNameSpaceURI(namespaceID, uriStr);
+      nsNameSpaceManager::GetInstance()->GetNameSpaceURI(namespaceID, uriStr);
       addNSAttr = ConfirmPrefix(prefixStr, uriStr, aOriginalElement, true);
     }
 
     info.mValue->ToString(valueStr);
 
     nsDependentAtomString nameStr(attrName);
     bool isJS = false;
 
--- a/dom/serializers/nsXMLContentSerializer.cpp
+++ b/dom/serializers/nsXMLContentSerializer.cpp
@@ -805,17 +805,17 @@ bool nsXMLContentSerializer::SerializeAt
     if (attrPrefix) {
       attrPrefix->ToString(prefixStr);
     } else {
       prefixStr.Truncate();
     }
 
     bool addNSAttr = false;
     if (kNameSpaceID_XMLNS != namespaceID) {
-      nsContentUtils::NameSpaceManager()->GetNameSpaceURI(namespaceID, uriStr);
+      nsNameSpaceManager::GetInstance()->GetNameSpaceURI(namespaceID, uriStr);
       addNSAttr = ConfirmPrefix(prefixStr, uriStr, aOriginalElement, true);
     }
 
     aElement->GetAttr(namespaceID, attrName, valueStr);
 
     nsDependentAtomString nameStr(attrName);
     bool isJS = IsJavaScript(aElement, attrName, namespaceID, valueStr);
 
--- a/dom/streams/UnderlyingSourceCallbackHelpers.cpp
+++ b/dom/streams/UnderlyingSourceCallbackHelpers.cpp
@@ -118,79 +118,35 @@ void UnderlyingSourceStartCallbackHelper
   return callback->Call(thisObj, aController, aRetVal, aRv,
                         "UnderlyingSource.start",
                         CallbackFunction::eRethrowExceptions);
 }
 
 already_AddRefed<Promise> IDLUnderlyingSourcePullCallbackHelper::PullCallback(
     JSContext* aCx, ReadableStreamDefaultController& aController,
     ErrorResult& aRv) {
-  // See https://bugzilla.mozilla.org/show_bug.cgi?id=1726595 for why all this
-  // gorp exists.
-
-  // Pre-allocate a promise which we may end up discarding or rejecting.
-  // We do this here in order to avoid having to try allocating on a
-  // failure path after the callback is called.
-  nsIGlobalObject* global = GetIncumbentGlobal();
-  RefPtr<Promise> maybeRejectPromise = Promise::Create(global, aRv);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
   JS::RootedObject thisObj(aCx, mThisObj);
 
   // Strong Ref
   RefPtr<UnderlyingSourcePullCallback> callback(mCallback);
   RefPtr<Promise> promise =
       callback->Call(thisObj, aController, aRv, "UnderlyingSource.pull",
                      CallbackFunction::eRethrowExceptions);
 
-  // Inform the ErrorResult that we're handling a JS exception if it happened.
-  aRv.WouldReportJSException();
-  if (aRv.Failed()) {
-    MOZ_ASSERT(!promise);
-
-    // Use the previously allocated promise now.
-    maybeRejectPromise->MaybeReject(std::move(aRv));
-    return maybeRejectPromise.forget();
-  }
-
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 IDLUnderlyingSourceCancelCallbackHelper::CancelCallback(
     JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aReason,
     ErrorResult& aRv) {
-  // See https://bugzilla.mozilla.org/show_bug.cgi?id=1726595 for why all this
-  // gorp exists.
-
-  // Pre-allocate a promise which we may end up discarding or rejecting.
-  // We do this here in order to avoid having to try allocating on a
-  // failure path after the callback is called.
-  nsIGlobalObject* global = GetIncumbentGlobal();
-  RefPtr<Promise> maybeRejectPromise = Promise::Create(global, aRv);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
   JS::RootedObject thisObj(aCx, mThisObj);
 
   // Strong Ref
   RefPtr<UnderlyingSourceCancelCallback> callback(mCallback);
   RefPtr<Promise> promise =
       callback->Call(thisObj, aReason, aRv, "UnderlyingSource.cancel",
                      CallbackFunction::eRethrowExceptions);
 
-  // Inform the ErrorResult that we're handling a JS exception if it happened.
-  aRv.WouldReportJSException();
-  if (aRv.Failed()) {
-    MOZ_ASSERT(!promise);
-
-    // Use the previously allocated promise now.
-    maybeRejectPromise->MaybeReject(std::move(aRv));
-    return maybeRejectPromise.forget();
-  }
-
   return promise.forget();
 }
 
 }  // namespace mozilla::dom
--- a/dom/webidl/APZTestData.webidl
+++ b/dom/webidl/APZTestData.webidl
@@ -52,27 +52,36 @@ namespace APZHitResultFlags {
 dictionary APZHitResult {
   float screenX;
   float screenY;
   unsigned short hitResult; // combination of the APZHitResultFlags.* flags
   unsigned long long layersId;
   unsigned long long scrollId;
 };
 
+dictionary APZSampledResult {
+  float scrollOffsetX;
+  float scrollOffsetY;
+  DOMHighResTimeStamp sampledTimeStamp;
+  unsigned long long layersId;
+  unsigned long long scrollId;
+};
+
 dictionary AdditionalDataEntry {
   DOMString key;
   DOMString value;
 };
 
 // All the paints and repaint requests. This is the top-level data structure.
 [GenerateConversionToJS]
 dictionary APZTestData {
   sequence<APZBucket> paints;
   sequence<APZBucket> repaintRequests;
   sequence<APZHitResult> hitResults;
+  sequence<APZSampledResult> sampledResults;
   sequence<AdditionalDataEntry> additionalData;
 };
 
 // A frame uniformity measurement for every scrollable layer
 dictionary FrameUniformity {
   unsigned long layerAddress;
   float frameUniformity;
 };
--- a/dom/xml/nsXMLContentSink.cpp
+++ b/dom/xml/nsXMLContentSink.cpp
@@ -491,17 +491,17 @@ nsresult nsXMLContentSink::CreateElement
   // XHTML needs some special attention
   if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
     mPrettyPrintHasFactoredElements = true;
   } else {
     // If we care, find out if we just used a special factory.
     if (!mPrettyPrintHasFactoredElements && !mPrettyPrintHasSpecialRoot &&
         mPrettyPrintXML) {
       mPrettyPrintHasFactoredElements =
-          nsContentUtils::NameSpaceManager()->HasElementCreator(
+          nsNameSpaceManager::GetInstance()->HasElementCreator(
               aNodeInfo->NamespaceID());
     }
 
     if (!aNodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
       content.forget(aResult);
 
       return NS_OK;
     }
--- a/dom/xslt/base/txExpandedNameMap.cpp
+++ b/dom/xslt/base/txExpandedNameMap.cpp
@@ -25,18 +25,16 @@ class txMapItemComparator {
 nsresult txExpandedNameMap_base::addItem(const txExpandedName& aKey,
                                          void* aValue) {
   size_t pos = mItems.IndexOf(aKey, 0, txMapItemComparator());
   if (pos != mItems.NoIndex) {
     return NS_ERROR_XSLT_ALREADY_SET;
   }
 
   MapItem* item = mItems.AppendElement();
-  NS_ENSURE_TRUE(item, NS_ERROR_OUT_OF_MEMORY);
-
   item->mNamespaceID = aKey.mNamespaceID;
   item->mLocalName = aKey.mLocalName;
   item->mValue = aValue;
 
   return NS_OK;
 }
 
 /**
@@ -52,18 +50,16 @@ nsresult txExpandedNameMap_base::setItem
   size_t pos = mItems.IndexOf(aKey, 0, txMapItemComparator());
   if (pos != mItems.NoIndex) {
     *aOldValue = mItems[pos].mValue;
     mItems[pos].mValue = aValue;
     return NS_OK;
   }
 
   MapItem* item = mItems.AppendElement();
-  NS_ENSURE_TRUE(item, NS_ERROR_OUT_OF_MEMORY);
-
   item->mNamespaceID = aKey.mNamespaceID;
   item->mLocalName = aKey.mLocalName;
   item->mValue = aValue;
 
   return NS_OK;
 }
 
 /**
--- a/dom/xslt/base/txList.cpp
+++ b/dom/xslt/base/txList.cpp
@@ -20,37 +20,32 @@ txList::txList() {
 }  //-- txList;
 
 /**
  * txList destructor, cleans up ListItems, but will not delete the Object
  * references
  */
 txList::~txList() { clear(); }  //-- ~txList
 
-void txList::add(void* objPtr) { insertBefore(objPtr, 0); }  //-- add
+void txList::add(void* objPtr) { insertBefore(objPtr, nullptr); }  //-- add
 
 /**
  * Returns the number of items in this txList
  **/
 int32_t List::getLength() { return itemCount; }  //-- getLength
 
 /**
  * Inserts the given Object pointer as the item just after refItem.
  * If refItem is a null pointer the Object will be inserted at the
  * beginning of the txList (ie, insert after nothing).
  * This method assumes refItem is a member of this list, and since this
  * is a private method, I feel that's a valid assumption
  **/
 void txList::insertAfter(void* objPtr, ListItem* refItem) {
-  //-- if refItem == null insert at front
-  if (!refItem) {
-    insertBefore(objPtr, firstItem);
-  } else {
-    insertBefore(objPtr, refItem->nextItem);
-  }
+  insertBefore(objPtr, refItem ? refItem->nextItem : firstItem);
 }  //-- insertAfter
 
 /**
  * Inserts the given Object pointer as the item just before refItem.
  * If refItem is a null pointer the Object will be inserted at the
  * end of the txList (ie, insert before nothing).
  * This method assumes refItem is a member of this list, and since this
  * is a private method, I feel that's a valid assumption
@@ -138,31 +133,31 @@ txListIterator::txListIterator(txList* l
  * The Object pointer is inserted as the next item in the txList
  * based on the current position within the txList
  * @param objPtr the Object pointer to add to the list
  **/
 void txListIterator::addAfter(void* objPtr) {
   if (currentItem || !atEndOfList) {
     list->insertAfter(objPtr, currentItem);
   } else {
-    list->insertBefore(objPtr, 0);
+    list->insertBefore(objPtr, nullptr);
   }
 }  //-- addAfter
 
 /**
  * Adds the Object pointer to the txList pointed to by this txListIterator.
  * The Object pointer is inserted as the previous item in the txList
  * based on the current position within the txList
  * @param objPtr the Object pointer to add to the list
  **/
 void txListIterator::addBefore(void* objPtr) {
   if (currentItem || atEndOfList) {
     list->insertBefore(objPtr, currentItem);
   } else {
-    list->insertAfter(objPtr, 0);
+    list->insertAfter(objPtr, nullptr);
   }
 }  //-- addBefore
 
 /**
  * Returns true if a successful call to the next() method can be made
  * @return true if a successful call to the next() method can be made,
  * otherwise false
  **/
--- a/dom/xslt/base/txNamespaceMap.cpp
+++ b/dom/xslt/base/txNamespaceMap.cpp
@@ -41,22 +41,17 @@ nsresult txNamespaceMap::mapNamespace(ns
   int32_t index = mPrefixes.IndexOf(prefix);
   if (index >= 0) {
     mNamespaces.ElementAt(index) = nsId;
 
     return NS_OK;
   }
 
   // New mapping
-  // XXX(Bug 1631371) Check if this should use a fallible operation as it
-  // pretended earlier.
   mPrefixes.AppendElement(prefix);
-
-  // XXX(Bug 1631371) Check if this should use a fallible operation as it
-  // pretended earlier.
   mNamespaces.AppendElement(nsId);
 
   return NS_OK;
 }
 
 int32_t txNamespaceMap::lookupNamespace(nsAtom* aPrefix) {
   if (aPrefix == nsGkAtoms::xml) {
     return kNameSpaceID_XML;
--- a/dom/xslt/base/txNamespaceMap.h
+++ b/dom/xslt/base/txNamespaceMap.h
@@ -2,17 +2,17 @@
 /* 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 TRANSFRMX_TXNAMESPACEMAP_H
 #define TRANSFRMX_TXNAMESPACEMAP_H
 
 #include "nsAtom.h"
-#include "nsCOMArray.h"
+#include "nsCOMPtr.h"
 #include "nsTArray.h"
 
 class txNamespaceMap {
  public:
   txNamespaceMap();
   txNamespaceMap(const txNamespaceMap& aOther);
 
   nsrefcnt AddRef() { return ++mRefCnt; }
--- a/dom/xslt/base/txStack.h
+++ b/dom/xslt/base/txStack.h
@@ -22,22 +22,17 @@ class txStack : private nsTArray<void*> 
   }
 
   /**
    * Adds the specified object to the top of this stack.
    *
    * @param obj a pointer to the object that is to be added to the
    * top of this stack.
    */
-  inline nsresult push(void* aObject) {
-    // XXX(Bug 1631371) Check if this should use a fallible operation as it
-    // pretended earlier, or change the return type to void.
-    AppendElement(aObject);
-    return NS_OK;
-  }
+  inline void push(void* aObject) { AppendElement(aObject); }
 
   /**
    * Removes and returns the specified object from the top of this
    * stack.
    *
    * @return a pointer to the object that was the top of this stack.
    */
   inline void* pop() {
--- a/dom/xslt/xpath/XPathEvaluator.cpp
+++ b/dom/xslt/xpath/XPathEvaluator.cpp
@@ -166,17 +166,17 @@ nsresult XPathEvaluatorParseContext::res
 
   if (ns.IsEmpty()) {
     aID = kNameSpaceID_None;
 
     return NS_OK;
   }
 
   // get the namespaceID for the URI
-  return nsContentUtils::NameSpaceManager()->RegisterNameSpace(ns, aID);
+  return nsNameSpaceManager::GetInstance()->RegisterNameSpace(ns, aID);
 }
 
 nsresult XPathEvaluatorParseContext::resolveFunctionCall(nsAtom* aName,
                                                          int32_t aID,
                                                          FunctionCall** aFn) {
   return NS_ERROR_XPATH_UNKNOWN_FUNCTION;
 }
 
--- a/dom/xslt/xpath/XPathResult.cpp
+++ b/dom/xslt/xpath/XPathResult.cpp
@@ -24,17 +24,17 @@ XPathResult::XPathResult(nsINode* aParen
       mResultType(ANY_TYPE),
       mInvalidIteratorState(true),
       mBooleanResult(false),
       mNumberResult(0) {}
 
 XPathResult::XPathResult(const XPathResult& aResult)
     : mParent(aResult.mParent),
       mResult(aResult.mResult),
-      mResultNodes(aResult.mResultNodes),
+      mResultNodes(aResult.mResultNodes.Clone()),
       mDocument(aResult.mDocument),
       mContextNode(aResult.mContextNode),
       mCurrentPos(0),
       mResultType(aResult.mResultType),
       mInvalidIteratorState(aResult.mInvalidIteratorState) {
   if (mDocument) {
     mDocument->AddMutationObserver(this);
   }
@@ -88,17 +88,17 @@ nsINode* XPathResult::IterateNext(ErrorR
   }
 
   if (mInvalidIteratorState) {
     aRv.ThrowInvalidStateError(
         "The document has been mutated since the result was returned");
     return nullptr;
   }
 
-  return mResultNodes.SafeObjectAt(mCurrentPos++);
+  return mResultNodes.SafeElementAt(mCurrentPos++);
 }
 
 void XPathResult::NodeWillBeDestroyed(const nsINode* aNode) {
   nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
   // Set to null to avoid unregistring unnecessarily
   mDocument = nullptr;
   Invalidate(aNode->IsContent() ? aNode->AsContent() : nullptr);
 }
@@ -172,32 +172,32 @@ void XPathResult::SetExprResult(txAExprR
     }
   }
 
   if (aExprResult->getResultType() == txAExprResult::NODESET) {
     txNodeSet* nodeSet = static_cast<txNodeSet*>(aExprResult);
     int32_t i, count = nodeSet->size();
     for (i = 0; i < count; ++i) {
       nsINode* node = txXPathNativeNode::getNode(nodeSet->get(i));
-      mResultNodes.AppendObject(node);
+      mResultNodes.AppendElement(node);
     }
 
     if (count > 0) {
       mResult = nullptr;
     }
   }
 
   if (!isIterator()) {
     return;
   }
 
   mCurrentPos = 0;
   mInvalidIteratorState = false;
 
-  if (mResultNodes.Count() > 0) {
+  if (!mResultNodes.IsEmpty()) {
     // If we support the document() function in DOM-XPath we need to
     // observe all documents that we have resultnodes in.
     mDocument = mResultNodes[0]->OwnerDoc();
     NS_ASSERTION(mDocument, "We need a document!");
     if (mDocument) {
       mDocument->AddMutationObserver(this);
     }
   }
@@ -226,26 +226,22 @@ nsresult XPathResult::GetExprResult(txAE
   }
 
   if (mResult) {
     NS_ADDREF(*aExprResult = mResult);
 
     return NS_OK;
   }
 
-  if (mResultNodes.Count() == 0) {
+  if (mResultNodes.IsEmpty()) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   RefPtr<txNodeSet> nodeSet = new txNodeSet(nullptr);
-  if (!nodeSet) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  uint32_t i, count = mResultNodes.Count();
+  uint32_t i, count = mResultNodes.Length();
   for (i = 0; i < count; ++i) {
     UniquePtr<txXPathNode> node(
         txXPathNativeNode::createXPathNode(mResultNodes[i]));
     if (!node) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     nodeSet->append(*node);
--- a/dom/xslt/xpath/XPathResult.h
+++ b/dom/xslt/xpath/XPathResult.h
@@ -3,19 +3,19 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_XPathResult_h
 #define mozilla_dom_XPathResult_h
 
 #include "nsStubMutationObserver.h"
 #include "nsCOMPtr.h"
-#include "nsCOMArray.h"
+#include "nsCycleCollectionParticipant.h"
 #include "nsIWeakReferenceUtils.h"
-#include "nsCycleCollectionParticipant.h"
+#include "nsTArray.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
 #include "nsString.h"
 #include "nsWrapperCache.h"
 #include "nsINode.h"
 
 class txAExprResult;
 
@@ -105,37 +105,37 @@ class XPathResult final : public nsIXPat
     return mBooleanResult;
   }
   nsINode* GetSingleNodeValue(ErrorResult& aRv) const {
     if (!isNode()) {
       aRv.ThrowTypeError("Result is not a node");
       return nullptr;
     }
 
-    return mResultNodes.SafeObjectAt(0);
+    return mResultNodes.SafeElementAt(0);
   }
   bool InvalidIteratorState() const {
     return isIterator() && mInvalidIteratorState;
   }
   uint32_t GetSnapshotLength(ErrorResult& aRv) const {
     if (!isSnapshot()) {
       aRv.ThrowTypeError("Result is not a snapshot");
       return 0;
     }
 
-    return (uint32_t)mResultNodes.Count();
+    return (uint32_t)mResultNodes.Length();
   }
   nsINode* IterateNext(ErrorResult& aRv);
   nsINode* SnapshotItem(uint32_t aIndex, ErrorResult& aRv) const {
     if (!isSnapshot()) {
       aRv.ThrowTypeError("Result is not a snapshot");
       return nullptr;
     }
 
-    return mResultNodes.SafeObjectAt(aIndex);
+    return mResultNodes.SafeElementAt(aIndex);
   }
 
   // nsIMutationObserver interface
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
@@ -163,17 +163,17 @@ class XPathResult final : public nsIXPat
   bool isSnapshot() const { return isSnapshot(mResultType); }
   bool isIterator() const { return isIterator(mResultType); }
   bool isNode() const { return isNode(mResultType); }
 
   void Invalidate(const nsIContent* aChangeRoot);
 
   nsCOMPtr<nsINode> mParent;
   RefPtr<txAExprResult> mResult;
-  nsCOMArray<nsINode> mResultNodes;
+  nsTArray<nsCOMPtr<nsINode>> mResultNodes;
   RefPtr<Document> mDocument;
   nsWeakPtr mContextNode;
   uint32_t mCurrentPos;
   uint16_t mResultType;
   bool mInvalidIteratorState;
   bool mBooleanResult;
   double mNumberResult;
   nsString mStringResult;
--- a/dom/xslt/xpath/txExpr.h
+++ b/dom/xslt/xpath/txExpr.h
@@ -217,24 +217,18 @@ class Expr {
  **/
 class FunctionCall : public Expr {
  public:
   /**
    * Adds the given parameter to this FunctionCall's parameter list.
    * The ownership of the given Expr is passed over to the FunctionCall,
    * even on failure.
    * @param aExpr the Expr to add to this FunctionCall's parameter list
-   * @return nsresult indicating out of memory
    */
-  nsresult addParam(Expr* aExpr) {
-    // XXX(Bug 1631371) Check if this should use a fallible operation as it
-    // pretended earlier, or change the return type to void.
-    mParams.AppendElement(aExpr);
-    return NS_OK;
-  }
+  void addParam(Expr* aExpr) { mParams.AppendElement(aExpr); }
 
   /**
    * Check if the number of parameters falls within a range.
    *
    * @param aParamCountMin minimum number of required parameters.
    * @param aParamCountMax maximum number of parameters. If aParamCountMax
    *                       is negative the maximum number is not checked.
    * @return boolean representing whether the number of parameters falls
@@ -442,24 +436,20 @@ class txPredicatedNodeTest : public txNo
  **/
 class PredicateList {
  public:
   /**
    * Adds the given Expr to the list.
    * The ownership of the given Expr is passed over the PredicateList,
    * even on failure.
    * @param aExpr the Expr to add to the list
-   * @return nsresult indicating out of memory
    */
-  nsresult add(Expr* aExpr) {
+  void add(Expr* aExpr) {
     NS_ASSERTION(aExpr, "missing expression");
-    // XXX(Bug 1631371) Check if this should use a fallible operation as it
-    // pretended earlier, or change the return type to void.
     mPredicates.AppendElement(aExpr);
-    return NS_OK;
   }
 
   nsresult evaluatePredicates(txNodeSet* aNodes, txIMatchContext* aContext);
 
   /**
    * Drops the first predicate without deleting it.
    */
   void dropFirst() { mPredicates.RemoveElementAt(0); }
@@ -705,19 +695,18 @@ class PathExpr : public Expr {
   //-- LF, changed from static const short to enum
   enum PathOperator { RELATIVE_OP, DESCENDANT_OP };
 
   /**
    * Adds the Expr to this PathExpr
    * The ownership of the given Expr is passed over the PathExpr,
    * even on failure.
    * @param aExpr the Expr to add to this PathExpr
-   * @return nsresult indicating out of memory
    */
-  nsresult addExpr(Expr* aExpr, PathOperator pathOp);
+  void addExpr(Expr* aExpr, PathOperator pathOp);
 
   /**
    * Removes and deletes the expression at the given index.
    */
   void deleteExprAt(uint32_t aPos) {
     NS_ASSERTION(aPos < mItems.Length(), "killing bad expression index");
     mItems.RemoveElementAt(aPos);
   }
@@ -782,24 +771,18 @@ class RootExpr : public Expr {
  **/
 class UnionExpr : public Expr {
  public:
   /**
    * Adds the PathExpr to this UnionExpr
    * The ownership of the given Expr is passed over the UnionExpr,
    * even on failure.
    * @param aExpr the Expr to add to this UnionExpr
-   * @return nsresult indicating out of memory
    */
-  nsresult addExpr(Expr* aExpr) {
-    // XXX(Bug 1631371) Check if this should use a fallible operation as it
-    // pretended earlier, or change the return type to void.
-    mExpressions.AppendElement(aExpr);
-    return NS_OK;
-  }
+  void addExpr(Expr* aExpr) { mExpressions.AppendElement(aExpr); }
 
   /**
    * Removes and deletes the expression at the given index.
    */
   void deleteExprAt(uint32_t aPos) {
     NS_ASSERTION(aPos < mExpressions.Length(), "killing bad expression index");
 
     delete mExpressions[aPos];
@@ -829,21 +812,18 @@ class txNamedAttributeStep : public Expr
   RefPtr<nsAtom> mLocalName;
 };
 
 /**
  *
  */
 class txUnionNodeTest : public txNodeTest {
  public:
-  nsresult addNodeTest(txNodeTest* aNodeTest) {
-    // XXX(Bug 1631371) Check if this should use a fallible operation as it
-    // pretended earlier, or change the return type to void.
+  void addNodeTest(txNodeTest* aNodeTest) {
     mNodeTests.AppendElement(aNodeTest);
-    return NS_OK;
   }
 
   TX_DECL_NODE_TEST
 
  private:
   txOwningArray<txNodeTest> mNodeTests;
 };
 
--- a/dom/xslt/xpath/txExprLexer.cpp
+++ b/dom/xslt/xpath/txExprLexer.cpp
@@ -314,17 +314,16 @@ nsresult txExprLexer::parse(const nsAStr
           ++mPosition;
           break;
         default:
           // Error, don't grok character :-(
           return NS_ERROR_XPATH_ILLEGAL_CHAR;
       }
     }
     if (isToken) {
-      NS_ENSURE_TRUE(newToken, NS_ERROR_OUT_OF_MEMORY);
       NS_ENSURE_TRUE(newToken != mLastItem, NS_ERROR_FAILURE);
       prevToken = newToken;
       addToken(newToken);
     }
   }
 
   // add a endToken to the list
   newToken = new Token(end, end, Token::END);
--- a/dom/xslt/xpath/txExprParser.cpp
+++ b/dom/xslt/xpath/txExprParser.cpp
@@ -116,23 +116,21 @@ nsresult txExprParser::createAVT(const n
     }
 
     // Add expression, create a concat() call if necessary
     if (!expr) {
       expr = std::move(newExpr);
     } else {
       if (!concat) {
         concat = new txCoreFunctionCall(txCoreFunctionCall::CONCAT);
-        rv = concat->addParam(expr.release());
+        concat->addParam(expr.release());
         expr = WrapUnique(concat);
-        NS_ENSURE_SUCCESS(rv, rv);
       }
 
-      rv = concat->addParam(newExpr.release());
-      NS_ENSURE_SUCCESS(rv, rv);
+      concat->addParam(newExpr.release());
     }
   }
 
   if (inExpr) {
     aContext->SetErrorOffset(iter - avtStart);
     return NS_ERROR_XPATH_UNBALANCED_CURLY_BRACE;
   }
 
@@ -169,18 +167,17 @@ nsresult txExprParser::createExprInterna
     aExpression.BeginReading(start);
     aContext->SetErrorOffset(lexer.peek()->mStart - start + aSubStringPos);
 
     return rv;
   }
 
   txXPathOptimizer optimizer;
   Expr* newExpr = nullptr;
-  rv = optimizer.optimize(expr.get(), &newExpr);
-  NS_ENSURE_SUCCESS(rv, rv);
+  optimizer.optimize(expr.get(), &newExpr);
 
   *aExpr = newExpr ? newExpr : expr.release();
 
   return NS_OK;
 }
 
 /**
  * Private Methods
@@ -248,17 +245,16 @@ nsresult txExprParser::createBinaryExpr(
       expr = new RelationalExpr(left.get(), right.get(),
                                 RelationalExpr::GREATER_OR_EQUAL);
       break;
 
     default:
       MOZ_ASSERT_UNREACHABLE("operator tokens should be already checked");
       return NS_ERROR_UNEXPECTED;
   }
-  NS_ENSURE_TRUE(expr, NS_ERROR_OUT_OF_MEMORY);
 
   Unused << left.release();
   Unused << right.release();
 
   *aResult = expr;
   return NS_OK;
 }
 
@@ -283,23 +279,21 @@ nsresult txExprParser::createExpr(txExpr
 
     rv = createUnionExpr(lexer, aContext, getter_Transfers(expr));
     if (NS_FAILED(rv)) {
       break;
     }
 
     if (negations > 0) {
       if (negations % 2 == 0) {
-        FunctionCall* fcExpr =
-            new txCoreFunctionCall(txCoreFunctionCall::NUMBER);
+        auto fcExpr =
+            MakeUnique<txCoreFunctionCall>(txCoreFunctionCall::NUMBER);
 
-        rv = fcExpr->addParam(expr.get());
-        if (NS_FAILED(rv)) return rv;
-        Unused << expr.release();
-        expr = WrapUnique(fcExpr);
+        fcExpr->addParam(expr.release());
+        expr = std::move(fcExpr);
       } else {
         expr = MakeUnique<UnaryExpr>(expr.release());
       }
     }
 
     short tokPrecedence = precedence(lexer.peek());
     if (tokPrecedence != 0) {
       Token* tok = lexer.nextToken();
@@ -586,18 +580,16 @@ nsresult txExprParser::createNodeTypeTes
     case Token::TEXT_AND_PAREN:
       lexer.nextToken();
       nodeTest = MakeUnique<txNodeTypeTest>(txNodeTypeTest::TEXT_TYPE);
       break;
     default:
       return NS_ERROR_XPATH_NO_NODE_TYPE_TEST;
   }
 
-  NS_ENSURE_TRUE(nodeTest, NS_ERROR_OUT_OF_MEMORY);
-
   if (nodeTok->mType == Token::PROC_INST_AND_PAREN &&
       lexer.peek()->mType == Token::LITERAL) {
     Token* tok = lexer.nextToken();
     nodeTest->setNodeName(tok->Value());
   }
   if (lexer.peek()->mType != Token::R_PAREN) {
     return NS_ERROR_XPATH_PAREN_EXPECTED;
   }
@@ -646,21 +638,17 @@ nsresult txExprParser::createPathExpr(tx
 
 #ifdef TX_TO_STRING
     static_cast<RootExpr*>(expr.get())->setSerialize(false);
 #endif
   }
 
   // We have a PathExpr containing several steps
   UniquePtr<PathExpr> pathExpr(new PathExpr());
-
-  rv = pathExpr->addExpr(expr.get(), PathExpr::RELATIVE_OP);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  Unused << expr.release();
+  pathExpr->addExpr(expr.release(), PathExpr::RELATIVE_OP);
 
   // this is ugly
   while (1) {
     PathExpr::PathOperator pathOp;
     switch (lexer.peek()->mType) {
       case Token::ANCESTOR_OP:
         pathOp = PathExpr::DESCENDANT_OP;
         break;
@@ -671,20 +659,17 @@ nsresult txExprParser::createPathExpr(tx
         *aResult = pathExpr.release();
         return NS_OK;
     }
     lexer.nextToken();
 
     rv = createLocationStep(lexer, aContext, getter_Transfers(expr));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = pathExpr->addExpr(expr.get(), pathOp);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    Unused << expr.release();
+    pathExpr->addExpr(expr.release(), pathOp);
   }
   MOZ_ASSERT_UNREACHABLE("internal xpath parser error");
   return NS_ERROR_UNEXPECTED;
 }
 
 /**
  * Creates a PathExpr using the given txExprLexer
  * @param lexer the txExprLexer for retrieving Tokens
@@ -699,30 +684,25 @@ nsresult txExprParser::createUnionExpr(t
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (lexer.peek()->mType != Token::UNION_OP) {
     *aResult = expr.release();
     return NS_OK;
   }
 
   UniquePtr<UnionExpr> unionExpr(new UnionExpr());
-
-  rv = unionExpr->addExpr(expr.get());
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  Unused << expr.release();
+  unionExpr->addExpr(expr.release());
 
   while (lexer.peek()->mType == Token::UNION_OP) {
     lexer.nextToken();  //-- eat token
 
     rv = createPathExpr(lexer, aContext, getter_Transfers(expr));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = unionExpr->addExpr(expr.release());
-    NS_ENSURE_SUCCESS(rv, rv);
+    unionExpr->addExpr(expr.release());
   }
 
   *aResult = unionExpr.release();
   return NS_OK;
 }
 
 bool txExprParser::isLocationStepToken(Token* aToken) {
   // We could put these in consecutive order in ExprLexer.h for speed
@@ -751,20 +731,17 @@ nsresult txExprParser::parsePredicates(P
   nsresult rv = NS_OK;
   while (lexer.peek()->mType == Token::L_BRACKET) {
     //-- eat Token
     lexer.nextToken();
 
     rv = createExpr(lexer, aContext, getter_Transfers(expr));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = aPredicateList->add(expr.get());
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    Unused << expr.release();
+    aPredicateList->add(expr.release());
 
     if (lexer.peek()->mType != Token::R_BRACKET) {
       return NS_ERROR_XPATH_BRACKET_EXPECTED;
     }
     lexer.nextToken();
   }
   return NS_OK;
 }
@@ -787,18 +764,17 @@ nsresult txExprParser::parseParameters(F
 
   UniquePtr<Expr> expr;
   nsresult rv = NS_OK;
   while (1) {
     rv = createExpr(lexer, aContext, getter_Transfers(expr));
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (aFnCall) {
-      rv = aFnCall->addParam(expr.release());
-      NS_ENSURE_SUCCESS(rv, rv);
+      aFnCall->addParam(expr.release());
     }
 
     switch (lexer.peek()->mType) {
       case Token::R_PAREN:
         lexer.nextToken();
         return NS_OK;
       case Token::COMMA:  //-- param separator
         lexer.nextToken();
--- a/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp
+++ b/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp
@@ -9,16 +9,17 @@
 #include "nsPrintfCString.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nsTextFragment.h"
 #include "txXMLUtils.h"
 #include "txLog.h"
 #include "nsUnicharUtils.h"
 #include "nsAttrName.h"
+#include "nsNameSpaceManager.h"
 #include "nsTArray.h"
 #include "mozilla/dom/Attr.h"
 #include "mozilla/dom/CharacterData.h"
 #include "mozilla/dom/Element.h"
 #include <stdint.h>
 #include <algorithm>
 
 using namespace mozilla::dom;
@@ -378,18 +379,18 @@ int32_t txXPathNodeUtils::getNamespaceID
       ->AsElement()
       ->GetAttrNameAt(aNode.mIndex)
       ->NamespaceID();
 }
 
 /* static */
 void txXPathNodeUtils::getNamespaceURI(const txXPathNode& aNode,
                                        nsAString& aURI) {
-  nsContentUtils::NameSpaceManager()->GetNameSpaceURI(getNamespaceID(aNode),
-                                                      aURI);
+  nsNameSpaceManager::GetInstance()->GetNameSpaceURI(getNamespaceID(aNode),
+                                                     aURI);
 }
 
 /* static */
 uint16_t txXPathNodeUtils::getNodeType(const txXPathNode& aNode) {
   if (aNode.isDocument()) {
     return txXPathNodeType::DOCUMENT_NODE;
   }
 
@@ -634,18 +635,18 @@ nsINode* txXPathNativeNode::getNode(cons
   if (!aNode.isAttribute()) {
     return aNode.mNode;
   }
 
   const nsAttrName* name =
       aNode.Content()->AsElement()->GetAttrNameAt(aNode.mIndex);
 
   nsAutoString namespaceURI;
-  nsContentUtils::NameSpaceManager()->GetNameSpaceURI(name->NamespaceID(),
-                                                      namespaceURI);
+  nsNameSpaceManager::GetInstance()->GetNameSpaceURI(name->NamespaceID(),
+                                                     namespaceURI);
 
   nsCOMPtr<Element> element = do_QueryInterface(aNode.mNode);
   nsDOMAttributeMap* map = element->Attributes();
   return map->GetNamedItemNS(namespaceURI,
                              nsDependentAtomString(name->LocalName()));
 }
 
 /* static */
--- a/dom/xslt/xpath/txPathExpr.cpp
+++ b/dom/xslt/xpath/txPathExpr.cpp
@@ -16,27 +16,22 @@ using mozilla::WrapUnique;
 //------------/
 //- PathExpr -/
 //------------/
 
 /**
  * Adds the Expr to this PathExpr
  * @param expr the Expr to add to this PathExpr
  **/
-nsresult PathExpr::addExpr(Expr* aExpr, PathOperator aPathOp) {
+void PathExpr::addExpr(Expr* aExpr, PathOperator aPathOp) {
   NS_ASSERTION(!mItems.IsEmpty() || aPathOp == RELATIVE_OP,
                "First step has to be relative in PathExpr");
   PathExprItem* pxi = mItems.AppendElement();
-  if (!pxi) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
   pxi->expr = WrapUnique(aExpr);
   pxi->pathOp = aPathOp;
-
-  return NS_OK;
 }
 
 //-----------------------------/
 //- Virtual methods from Expr -/
 //-----------------------------/
 
 /**
  * Evaluates this Expr based on the given context node and processor state
--- a/dom/xslt/xpath/txResultRecycler.cpp
+++ b/dom/xslt/xpath/txResultRecycler.cpp
@@ -27,38 +27,28 @@ txResultRecycler::~txResultRecycler() {
   }
 }
 
 void txResultRecycler::recycle(txAExprResult* aResult) {
   NS_ASSERTION(aResult->mRefCnt == 0, "In-use txAExprResult recycled");
   RefPtr<txResultRecycler> kungFuDeathGrip;
   aResult->mRecycler.swap(kungFuDeathGrip);
 
-  nsresult rv = NS_OK;
   switch (aResult->getResultType()) {
     case txAExprResult::STRING: {
-      rv = mStringResults.push(static_cast<StringResult*>(aResult));
-      if (NS_FAILED(rv)) {
-        delete aResult;
-      }
+      mStringResults.push(static_cast<StringResult*>(aResult));
       return;
     }
     case txAExprResult::NODESET: {
       static_cast<txNodeSet*>(aResult)->clear();
-      rv = mNodeSetResults.push(static_cast<txNodeSet*>(aResult));
-      if (NS_FAILED(rv)) {
-        delete aResult;
-      }
+      mNodeSetResults.push(static_cast<txNodeSet*>(aResult));
       return;
     }
     case txAExprResult::NUMBER: {
-      rv = mNumberResults.push(static_cast<NumberResult*>(aResult));
-      if (NS_FAILED(rv)) {
-        delete aResult;
-      }
+      mNumberResults.push(static_cast<NumberResult*>(aResult));
       return;
     }
     default: {
       delete aResult;
     }
   }
 }
 
--- a/dom/xslt/xpath/txXPathNode.h
+++ b/dom/xslt/xpath/txXPathNode.h
@@ -5,17 +5,16 @@
 
 #ifndef txXPathNode_h__
 #define txXPathNode_h__
 
 #include "nsIContent.h"
 #include "mozilla/dom/Document.h"
 #include "nsINode.h"
 #include "nsNameSpaceManager.h"
-#include "nsContentUtils.h"  // For NameSpaceManager().
 
 using txXPathNodeType = nsINode;
 
 class txXPathNode {
  public:
   bool operator==(const txXPathNode& aNode) const;
   bool operator!=(const txXPathNode& aNode) const { return !(*this == aNode); }
   ~txXPathNode();
@@ -69,24 +68,24 @@ class txNamespaceManager {
   static int32_t getNamespaceID(const nsAString& aNamespaceURI);
   static nsresult getNamespaceURI(const int32_t aID, nsAString& aResult);
 };
 
 /* static */
 inline int32_t txNamespaceManager::getNamespaceID(
     const nsAString& aNamespaceURI) {
   int32_t namespaceID = kNameSpaceID_Unknown;
-  nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
-                                                        namespaceID);
+  nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespaceURI,
+                                                       namespaceID);
   return namespaceID;
 }
 
 /* static */
 inline nsresult txNamespaceManager::getNamespaceURI(const int32_t aID,
                                                     nsAString& aResult) {
-  return nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aID, aResult);
+  return nsNameSpaceManager::GetInstance()->GetNameSpaceURI(aID, aResult);
 }
 
 inline bool txXPathNode::operator==(const txXPathNode& aNode) const {
   return mIndex == aNode.mIndex && mNode == aNode.mNode;
 }
 
 #endif /* txXPathNode_h__ */
--- a/dom/xslt/xpath/txXPathOptimizer.cpp
+++ b/dom/xslt/xpath/txXPathOptimizer.cpp
@@ -41,102 +41,99 @@ class txEarlyEvalContext : public txIEva
   uint32_t position() override {
     MOZ_CRASH("shouldn't depend on this context");
   }
 
  private:
   txResultRecycler* mRecycler;
 };
 
-nsresult txXPathOptimizer::optimize(Expr* aInExpr, Expr** aOutExpr) {
+void txXPathOptimizer::optimize(Expr* aInExpr, Expr** aOutExpr) {
   *aOutExpr = nullptr;
-  nsresult rv = NS_OK;
 
   // First check if the expression will produce the same result
   // under any context.
   Expr::ExprType exprType = aInExpr->getType();
   if (exprType != Expr::LITERAL_EXPR &&
       !aInExpr->isSensitiveTo(Expr::ANY_CONTEXT)) {
     RefPtr<txResultRecycler> recycler = new txResultRecycler;
     txEarlyEvalContext context(recycler);
     RefPtr<txAExprResult> exprRes;
 
     // Don't throw if this fails since it could be that the expression
     // is or contains an error-expression.
-    rv = aInExpr->evaluate(&context, getter_AddRefs(exprRes));
+    nsresult rv = aInExpr->evaluate(&context, getter_AddRefs(exprRes));
     if (NS_SUCCEEDED(rv)) {
       *aOutExpr = new txLiteralExpr(exprRes);
     }
 
-    return NS_OK;
+    return;
   }
 
   // Then optimize sub expressions
   uint32_t i = 0;
   Expr* subExpr;
   while ((subExpr = aInExpr->getSubExprAt(i))) {
     Expr* newExpr = nullptr;
-    rv = optimize(subExpr, &newExpr);
-    NS_ENSURE_SUCCESS(rv, rv);
+    optimize(subExpr, &newExpr);
     if (newExpr) {
       delete subExpr;
       aInExpr->setSubExprAt(i, newExpr);
     }
 
     ++i;
   }
 
   // Finally see if current expression can be optimized
   switch (exprType) {
     case Expr::LOCATIONSTEP_EXPR:
-      return optimizeStep(aInExpr, aOutExpr);
+      optimizeStep(aInExpr, aOutExpr);
+      return;
 
     case Expr::PATH_EXPR:
-      return optimizePath(aInExpr, aOutExpr);
+      optimizePath(aInExpr, aOutExpr);
+      return;
 
     case Expr::UNION_EXPR:
-      return optimizeUnion(aInExpr, aOutExpr);
+      optimizeUnion(aInExpr, aOutExpr);
+      return;
 
     default:
-      break;
+      return;
   }
-
-  return NS_OK;
 }
 
-nsresult txXPathOptimizer::optimizeStep(Expr* aInExpr, Expr** aOutExpr) {
+void txXPathOptimizer::optimizeStep(Expr* aInExpr, Expr** aOutExpr) {
   LocationStep* step = static_cast<LocationStep*>(aInExpr);
 
   if (step->getAxisIdentifier() == LocationStep::ATTRIBUTE_AXIS) {
     // Test for @foo type steps.
     txNameTest* nameTest = nullptr;
     if (!step->getSubExprAt(0) &&
         step->getNodeTest()->getType() == txNameTest::NAME_TEST &&
         (nameTest = static_cast<txNameTest*>(step->getNodeTest()))
                 ->mLocalName != nsGkAtoms::_asterisk) {
       *aOutExpr = new txNamedAttributeStep(
           nameTest->mNamespace, nameTest->mPrefix, nameTest->mLocalName);
-      return NS_OK;  // return since we no longer have a step-object.
+      return;  // return since we no longer have a step-object.
     }
   }
 
   // Test for predicates that can be combined into the nodetest
   Expr* pred;
   while ((pred = step->getSubExprAt(0)) &&
          !pred->canReturnType(Expr::NUMBER_RESULT) &&
          !pred->isSensitiveTo(Expr::NODESET_CONTEXT)) {
     txNodeTest* predTest = new txPredicatedNodeTest(step->getNodeTest(), pred);
     step->dropFirst();
     step->setNodeTest(predTest);
   }
-
-  return NS_OK;
 }
 
-nsresult txXPathOptimizer::optimizePath(Expr* aInExpr, Expr** aOutExpr) {
+void txXPathOptimizer::optimizePath(Expr* aInExpr, Expr** aOutExpr) {
   PathExpr* path = static_cast<PathExpr*>(aInExpr);
 
   uint32_t i;
   Expr* subExpr;
   // look for steps like "//foo" that can be turned into "/descendant::foo"
   // and "//." that can be turned into "/descendant-or-self::node()"
   for (i = 0; (subExpr = path->getSubExprAt(i)); ++i) {
     if (path->getPathOpAt(i) == PathExpr::DESCENDANT_OP &&
@@ -168,35 +165,32 @@ nsresult txXPathOptimizer::optimizePath(
         // We have a '.' as first step followed by a single '/'.
 
         // Check if there are only two steps. If so, return the second
         // as resulting expression.
         if (!path->getSubExprAt(2)) {
           *aOutExpr = path->getSubExprAt(1);
           path->setSubExprAt(1, nullptr);
 
-          return NS_OK;
+          return;
         }
 
         // Just delete the '.' step and leave the rest of the PathExpr
         path->deleteExprAt(0);
       }
     }
   }
-
-  return NS_OK;
 }
 
-nsresult txXPathOptimizer::optimizeUnion(Expr* aInExpr, Expr** aOutExpr) {
+void txXPathOptimizer::optimizeUnion(Expr* aInExpr, Expr** aOutExpr) {
   UnionExpr* uni = static_cast<UnionExpr*>(aInExpr);
 
   // Check for expressions like "foo | bar" and
   // "descendant::foo | descendant::bar"
 
-  nsresult rv;
   uint32_t current;
   Expr* subExpr;
   for (current = 0; (subExpr = uni->getSubExprAt(current)); ++current) {
     if (subExpr->getType() != Expr::LOCATIONSTEP_EXPR ||
         subExpr->getSubExprAt(0)) {
       continue;
     }
 
@@ -217,40 +211,36 @@ nsresult txXPathOptimizer::optimizeUnion
       LocationStep* step = static_cast<LocationStep*>(subExpr);
       if (step->getAxisIdentifier() != axis) {
         continue;
       }
 
       // Create a txUnionNodeTest if needed
       if (!unionTest) {
         UniquePtr<txNodeTest> owner(unionTest = new txUnionNodeTest);
-        rv = unionTest->addNodeTest(currentStep->getNodeTest());
-        NS_ENSURE_SUCCESS(rv, rv);
+        unionTest->addNodeTest(currentStep->getNodeTest());
 
         currentStep->setNodeTest(unionTest);
         Unused << owner.release();
       }
 
       // Merge the nodetest into the union
-      rv = unionTest->addNodeTest(step->getNodeTest());
-      NS_ENSURE_SUCCESS(rv, rv);
+      unionTest->addNodeTest(step->getNodeTest());
 
       step->setNodeTest(nullptr);
 
       // Remove the step from the UnionExpr
       uni->deleteExprAt(i);
       --i;
     }
 
     // Check if all expressions were merged into a single step. If so,
     // return the step as the new expression.
     if (unionTest && current == 0 && !uni->getSubExprAt(1)) {
       // Make sure the step doesn't get deleted when the UnionExpr is
       uni->setSubExprAt(0, nullptr);
       *aOutExpr = currentStep;
 
       // Return right away since we no longer have a union
-      return NS_OK;
+      return;
     }
   }
-
-  return NS_OK;
 }
--- a/dom/xslt/xpath/txXPathOptimizer.h
+++ b/dom/xslt/xpath/txXPathOptimizer.h
@@ -13,18 +13,18 @@ class Expr;
 class txXPathOptimizer {
  public:
   /**
    * Optimize the given expression.
    * @param aInExpr       Expression to optimize.
    * @param aOutExpr      Resulting expression, null if optimization didn't
    *                      result in a new expression.
    */
-  nsresult optimize(Expr* aInExpr, Expr** aOutExpr);
+  void optimize(Expr* aInExpr, Expr** aOutExpr);
 
  private:
   // Helper methods for optimizing specific classes
-  nsresult optimizeStep(Expr* aInExpr, Expr** aOutExpr);
-  nsresult optimizePath(Expr* aInExpr, Expr** aOutExpr);
-  nsresult optimizeUnion(Expr* aInExpr, Expr** aOutExpr);
+  void optimizeStep(Expr* aInExpr, Expr** aOutExpr);
+  void optimizePath(Expr* aInExpr, Expr** aOutExpr);
+  void optimizeUnion(Expr* aInExpr, Expr** aOutExpr);
 };
 
 #endif
--- a/dom/xslt/xslt/txExecutionState.cpp
+++ b/dom/xslt/xslt/txExecutionState.cpp
@@ -237,25 +237,17 @@ nsresult txExecutionState::getVariable(i
     rv = var->mExpr->evaluate(getEvalContext(), &aResult);
     mLocalVariables = oldVars;
 
     if (NS_FAILED(rv)) {
       popAndDeleteEvalContextUntil(mInitialEvalContext);
       return rv;
     }
   } else {
-    UniquePtr<txRtfHandler> rtfHandler(new txRtfHandler);
-
-    rv = pushResultHandler(rtfHandler.get());
-    if (NS_FAILED(rv)) {
-      popAndDeleteEvalContextUntil(mInitialEvalContext);
-      return rv;
-    }
-
-    Unused << rtfHandler.release();
+    pushResultHandler(new txRtfHandler);
 
     txInstruction* prevInstr = mNextInstruction;
     // set return to nullptr to stop execution
     mNextInstruction = nullptr;
     rv = runTemplate(var->mFirstInstruction.get());
     if (NS_FAILED(rv)) {
       popAndDeleteEvalContextUntil(mInitialEvalContext);
       return rv;
@@ -266,17 +258,18 @@ nsresult txExecutionState::getVariable(i
     if (NS_FAILED(rv)) {
       popAndDeleteEvalContextUntil(mInitialEvalContext);
       return rv;
     }
 
     popTemplateRule();
 
     mNextInstruction = prevInstr;
-    rtfHandler = WrapUnique((txRtfHandler*)popResultHandler());
+    UniquePtr<txRtfHandler> rtfHandler(
+        static_cast<txRtfHandler*>(popResultHandler()));
     rv = rtfHandler->getAsRTF(&aResult);
     if (NS_FAILED(rv)) {
       popAndDeleteEvalContextUntil(mInitialEvalContext);
       return rv;
     }
   }
   popEvalContext();
 
@@ -300,52 +293,39 @@ nsresult txExecutionState::isStripSpaceA
 void* txExecutionState::getPrivateContext() { return this; }
 
 txResultRecycler* txExecutionState::recycler() { return mRecycler; }
 
 void txExecutionState::receiveError(const nsAString& aMsg, nsresult aRes) {
   // XXX implement me
 }
 
-nsresult txExecutionState::pushEvalContext(txIEvalContext* aContext) {
-  nsresult rv = mEvalContextStack.push(mEvalContext);
-  NS_ENSURE_SUCCESS(rv, rv);
-
+void txExecutionState::pushEvalContext(txIEvalContext* aContext) {
+  mEvalContextStack.push(mEvalContext);
   mEvalContext = aContext;
-
-  return NS_OK;
 }
 
 txIEvalContext* txExecutionState::popEvalContext() {
   txIEvalContext* prev = mEvalContext;
   mEvalContext = (txIEvalContext*)mEvalContextStack.pop();
 
   return prev;
 }
 
-nsresult txExecutionState::pushBool(bool aBool) {
-  // XXX(Bug 1631371) Check if this should use a fallible operation as it
-  // pretended earlier, or change the return type to void.
-  mBoolStack.AppendElement(aBool);
-  return NS_OK;
-}
+void txExecutionState::pushBool(bool aBool) { mBoolStack.AppendElement(aBool); }
 
 bool txExecutionState::popBool() {
   NS_ASSERTION(mBoolStack.Length(), "popping from empty stack");
 
   return mBoolStack.IsEmpty() ? false : mBoolStack.PopLastElement();
 }
 
-nsresult txExecutionState::pushResultHandler(txAXMLEventHandler* aHandler) {
-  nsresult rv = mResultHandlerStack.push(mResultHandler);
-  NS_ENSURE_SUCCESS(rv, rv);
-
+void txExecutionState::pushResultHandler(txAXMLEventHandler* aHandler) {
+  mResultHandlerStack.push(mResultHandler);
   mResultHandler = aHandler;
-
-  return NS_OK;
 }
 
 txAXMLEventHandler* txExecutionState::popResultHandler() {
   txAXMLEventHandler* oldHandler = mResultHandler;
   mResultHandler = (txAXMLEventHandler*)mResultHandlerStack.pop();
 
   return oldHandler;
 }
@@ -423,21 +403,18 @@ txInstruction* txExecutionState::getNext
 
   return instr;
 }
 
 nsresult txExecutionState::runTemplate(txInstruction* aTemplate) {
   NS_ENSURE_TRUE(++mRecursionDepth < kMaxRecursionDepth,
                  NS_ERROR_XSLT_BAD_RECURSION);
 
-  nsresult rv = mLocalVarsStack.push(mLocalVariables);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = mReturnStack.push(mNextInstruction);
-  NS_ENSURE_SUCCESS(rv, rv);
+  mLocalVarsStack.push(mLocalVariables);
+  mReturnStack.push(mNextInstruction);
 
   mLocalVariables = nullptr;
   mNextInstruction = aTemplate;
 
   return NS_OK;
 }
 
 void txExecutionState::gotoInstruction(txInstruction* aNext) {
--- a/dom/xslt/xslt/txExecutionState.h
+++ b/dom/xslt/xslt/txExecutionState.h
@@ -76,29 +76,29 @@ class txExecutionState : public txIMatch
    public:
     txStylesheet::ImportFrame* mFrame;
     int32_t mModeNsId;
     RefPtr<nsAtom> mModeLocalName;
     RefPtr<txParameterMap> mParams;
   };
 
   // Stack functions
-  nsresult pushEvalContext(txIEvalContext* aContext);
+  void pushEvalContext(txIEvalContext* aContext);
   txIEvalContext* popEvalContext();
 
   /**
    * Helper that deletes all entries before |aContext| and then
    * pops it off the stack. The caller must delete |aContext| if
    * desired.
    */
   void popAndDeleteEvalContextUntil(txIEvalContext* aContext);
 
-  nsresult pushBool(bool aBool);
+  void pushBool(bool aBool);
   bool popBool();
-  nsresult pushResultHandler(txAXMLEventHandler* aHandler);
+  void pushResultHandler(txAXMLEventHandler* aHandler);
   txAXMLEventHandler* popResultHandler();
   void pushTemplateRule(txStylesheet::ImportFrame* aFrame,
                         const txExpandedName& aMode, txParameterMap* aParams);
   void popTemplateRule();
   void pushParamMap(txParameterMap* aParams);
   already_AddRefed<txParameterMap> popParamMap();
 
   // state-getting functions
--- a/dom/xslt/xslt/txInstructions.cpp
+++ b/dom/xslt/xslt/txInstructions.cpp
@@ -16,16 +16,17 @@
 #include "txNodeSetContext.h"
 #include "txNodeSorter.h"
 #include "txRtfHandler.h"
 #include "txStringUtils.h"
 #include "txStylesheet.h"
 #include "txTextHandler.h"
 #include "txXSLTNumber.h"
 
+using mozilla::MakeUnique;
 using mozilla::UniquePtr;
 
 nsresult txApplyDefaultElementTemplate::execute(txExecutionState& aEs) {
   txExecutionState::TemplateRule* rule = aEs.getCurrentTemplateRule();
   txExpandedName mode(rule->mModeNsId, rule->mModeLocalName);
   txStylesheet::ImportFrame* frame = 0;
   txInstruction* templ;
   nsresult rv =
@@ -286,32 +287,30 @@ nsresult txCopy::execute(txExecutionStat
 
   switch (txXPathNodeUtils::getNodeType(node)) {
     case txXPathNodeType::DOCUMENT_NODE:
     case txXPathNodeType::DOCUMENT_FRAGMENT_NODE: {
       // "close" current element to ensure that no attributes are added
       rv = aEs.mResultHandler->characters(u""_ns, false);
       NS_ENSURE_SUCCESS(rv, rv);
 
-      rv = aEs.pushBool(false);
-      NS_ENSURE_SUCCESS(rv, rv);
+      aEs.pushBool(false);
 
       break;
     }
     case txXPathNodeType::ELEMENT_NODE: {
       RefPtr<nsAtom> localName = txXPathNodeUtils::getLocalName(node);
       rv = aEs.mResultHandler->startElement(
           txXPathNodeUtils::getPrefix(node), localName, nullptr,
           txXPathNodeUtils::getNamespaceID(node));
       NS_ENSURE_SUCCESS(rv, rv);
 
       // XXX copy namespace nodes once we have them
 
-      rv = aEs.pushBool(true);
-      NS_ENSURE_SUCCESS(rv, rv);
+      aEs.pushBool(true);
 
       break;
     }
     default: {
       rv = copyNode(node, aEs);
       NS_ENSURE_SUCCESS(rv, rv);
 
       aEs.gotoInstruction(mBailTarget);
@@ -542,78 +541,59 @@ nsresult txPushNewContext::execute(txExe
                                sort.mDataTypeExpr.get(), sort.mOrderExpr.get(),
                                sort.mCaseOrderExpr.get(), aEs.getEvalContext());
     NS_ENSURE_SUCCESS(rv, rv);
   }
   RefPtr<txNodeSet> sortedNodes;
   rv = sorter.sortNodeSet(nodes, &aEs, getter_AddRefs(sortedNodes));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  txNodeSetContext* context = new txNodeSetContext(sortedNodes, &aEs);
-  NS_ENSURE_TRUE(context, NS_ERROR_OUT_OF_MEMORY);
-
+  auto context = MakeUnique<txNodeSetContext>(sortedNodes, &aEs);
   context->next();
 
-  rv = aEs.pushEvalContext(context);
-  if (NS_FAILED(rv)) {
-    delete context;
-    return rv;
-  }
+  aEs.pushEvalContext(context.release());
 
   return NS_OK;
 }
 
-nsresult txPushNewContext::addSort(UniquePtr<Expr>&& aSelectExpr,
-                                   UniquePtr<Expr>&& aLangExpr,
-                                   UniquePtr<Expr>&& aDataTypeExpr,
-                                   UniquePtr<Expr>&& aOrderExpr,
-                                   UniquePtr<Expr>&& aCaseOrderExpr) {
-  if (SortKey* key = mSortKeys.AppendElement()) {
-    // workaround for not triggering the Copy Constructor
-    key->mSelectExpr = std::move(aSelectExpr);
-    key->mLangExpr = std::move(aLangExpr);
-    key->mDataTypeExpr = std::move(aDataTypeExpr);
-    key->mOrderExpr = std::move(aOrderExpr);
-    key->mCaseOrderExpr = std::move(aCaseOrderExpr);
-    return NS_OK;
-  }
-  return NS_ERROR_OUT_OF_MEMORY;
+void txPushNewContext::addSort(UniquePtr<Expr>&& aSelectExpr,
+                               UniquePtr<Expr>&& aLangExpr,
+                               UniquePtr<Expr>&& aDataTypeExpr,
+                               UniquePtr<Expr>&& aOrderExpr,
+                               UniquePtr<Expr>&& aCaseOrderExpr) {
+  SortKey* key = mSortKeys.AppendElement();
+  // workaround for not triggering the Copy Constructor
+  key->mSelectExpr = std::move(aSelectExpr);
+  key->mLangExpr = std::move(aLangExpr);
+  key->mDataTypeExpr = std::move(aDataTypeExpr);
+  key->mOrderExpr = std::move(aOrderExpr);
+  key->mCaseOrderExpr = std::move(aCaseOrderExpr);
 }
 
 nsresult txPushNullTemplateRule::execute(txExecutionState& aEs) {
   aEs.pushTemplateRule(nullptr, txExpandedName(), nullptr);
   return NS_OK;
 }
 
 nsresult txPushParams::execute(txExecutionState& aEs) {
   aEs.pushParamMap(nullptr);
   return NS_OK;
 }
 
 nsresult txPushRTFHandler::execute(txExecutionState& aEs) {
-  txAXMLEventHandler* handler = new txRtfHandler;
-  nsresult rv = aEs.pushResultHandler(handler);
-  if (NS_FAILED(rv)) {
-    delete handler;
-    return rv;
-  }
+  aEs.pushResultHandler(new txRtfHandler);
 
   return NS_OK;
 }
 
 txPushStringHandler::txPushStringHandler(bool aOnlyText)
     : mOnlyText(aOnlyText) {}
 
 nsresult txPushStringHandler::execute(txExecutionState& aEs) {
-  txAXMLEventHandler* handler = new txTextHandler(mOnlyText);
-  nsresult rv = aEs.pushResultHandler(handler);
-  if (NS_FAILED(rv)) {
-    delete handler;
-    return rv;
-  }
+  aEs.pushResultHandler(new txTextHandler(mOnlyText));
 
   return NS_OK;
 }
 
 txRemoveVariable::txRemoveVariable(const txExpandedName& aName)
     : mName(aName) {}
 
 nsresult txRemoveVariable::execute(txExecutionState& aEs) {
@@ -725,18 +705,17 @@ nsresult txStartElement::execute(txExecu
   if (rv == NS_ERROR_XSLT_BAD_NODE_NAME) {
     success = false;
     // we call characters with an empty string to "close" any element to
     // make sure that no attributes are added
     rv = aEs.mResultHandler->characters(u""_ns, false);
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = aEs.pushBool(success);
-  NS_ENSURE_SUCCESS(rv, rv);
+  aEs.pushBool(success);
 
   return NS_OK;
 }
 
 txStartLREElement::txStartLREElement(int32_t aNamespaceID, nsAtom* aLocalName,
                                      nsAtom* aPrefix)
     : mNamespaceID(aNamespaceID), mLocalName(aLocalName), mPrefix(aPrefix) {
   if (aNamespaceID == kNameSpaceID_None) {
@@ -744,18 +723,17 @@ txStartLREElement::txStartLREElement(int
   }
 }
 
 nsresult txStartLREElement::execute(txExecutionState& aEs) {
   nsresult rv = aEs.mResultHandler->startElement(
       mPrefix, mLocalName, mLowercaseLocalName, mNamespaceID);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = aEs.pushBool(true);
-  NS_ENSURE_SUCCESS(rv, rv);
+  aEs.pushBool(true);
 
   return NS_OK;
 }
 
 txText::txText(const nsAString& aStr, bool aDOE) : mStr(aStr), mDOE(aDOE) {}
 
 nsresult txText::execute(txExecutionState& aEs) {
   return aEs.mResultHandler->characters(mStr, mDOE);
--- a/dom/xslt/xslt/txInstructions.h
+++ b/dom/xslt/xslt/txInstructions.h
@@ -224,21 +224,21 @@ class txProcessingInstruction : public t
 
 class txPushNewContext : public txInstruction {
  public:
   explicit txPushNewContext(mozilla::UniquePtr<Expr>&& aSelect);
   ~txPushNewContext();
 
   TX_DECL_TXINSTRUCTION
 
-  nsresult addSort(mozilla::UniquePtr<Expr>&& aSelectExpr,
-                   mozilla::UniquePtr<Expr>&& aLangExpr,
-                   mozilla::UniquePtr<Expr>&& aDataTypeExpr,
-                   mozilla::UniquePtr<Expr>&& aOrderExpr,
-                   mozilla::UniquePtr<Expr>&& aCaseOrderExpr);
+  void addSort(mozilla::UniquePtr<Expr>&& aSelectExpr,
+               mozilla::UniquePtr<Expr>&& aLangExpr,
+               mozilla::UniquePtr<Expr>&& aDataTypeExpr,
+               mozilla::UniquePtr<Expr>&& aOrderExpr,
+               mozilla::UniquePtr<Expr>&& aCaseOrderExpr);
 
   struct SortKey {
     mozilla::UniquePtr<Expr> mSelectExpr;
     mozilla::UniquePtr<Expr> mLangExpr;
     mozilla::UniquePtr<Expr> mDataTypeExpr;
     mozilla::UniquePtr<Expr> mOrderExpr;
     mozilla::UniquePtr<Expr> mCaseOrderExpr;
   };
--- a/dom/xslt/xslt/txKeyFunctionCall.cpp
+++ b/dom/xslt/xslt/txKeyFunctionCall.cpp
@@ -295,25 +295,21 @@ nsresult txXSLKey::testNode(const txXPat
   nsAutoString val;
   uint32_t currKey, numKeys = mKeys.Length();
   for (currKey = 0; currKey < numKeys; ++currKey) {
     bool matched;
     nsresult rv = mKeys[currKey].matchPattern->matches(aNode, &aEs, matched);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (matched) {
-      txSingleNodeContext* evalContext = new txSingleNodeContext(aNode, &aEs);
-      NS_ENSURE_TRUE(evalContext, NS_ERROR_OUT_OF_MEMORY);
-
-      nsresult rv = aEs.pushEvalContext(evalContext);
-      NS_ENSURE_SUCCESS(rv, rv);
+      aEs.pushEvalContext(new txSingleNodeContext(aNode, &aEs));
 
       RefPtr<txAExprResult> exprResult;
-      rv = mKeys[currKey].useExpr->evaluate(evalContext,
-                                            getter_AddRefs(exprResult));
+      nsresult rv = mKeys[currKey].useExpr->evaluate(
+          aEs.getEvalContext(), getter_AddRefs(exprResult));
 
       delete aEs.popEvalContext();
       NS_ENSURE_SUCCESS(rv, rv);
 
       if (exprResult->getResultType() == txAExprResult::NODESET) {
         txNodeSet* res =
             static_cast<txNodeSet*>(static_cast<txAExprResult*>(exprResult));
         int32_t i;
--- a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
+++ b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
@@ -1,14 +1,13 @@
 /* -*- Mode: C++; tab-width: 4; 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 "nsCOMArray.h"
 #include "nsIAuthPrompt.h"
 #include "mozilla/dom/Document.h"
 #include "nsIExpatSink.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsILoadGroup.h"
 #include "nsIParser.h"
 #include "nsCharsetSource.h"
 #include "nsIRequestObserver.h"
@@ -420,17 +419,16 @@ nsresult txCompileObserver::startLoad(ns
       MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
   }
 
   nsCOMPtr<nsIParser> parser = do_CreateInstance(kCParserCID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   RefPtr<txStylesheetSink> sink = new txStylesheetSink(aCompiler, parser);
-  NS_ENSURE_TRUE(sink, NS_ERROR_OUT_OF_MEMORY);
 
   channel->SetNotificationCallbacks(sink);
 
   parser->SetCommand(kLoadAsData);
   parser->SetContentSink(sink);
   parser->Parse(aUri);
 
   return channel->AsyncOpen(sink);
@@ -442,21 +440,19 @@ nsresult TX_LoadSheet(nsIURI* aUri, txMo
   nsIPrincipal* principal = aLoaderDocument->NodePrincipal();
 
   nsAutoCString spec;
   aUri->GetSpec(spec);
   MOZ_LOG(txLog::xslt, LogLevel::Info, ("TX_LoadSheet: %s\n", spec.get()));
 
   RefPtr<txCompileObserver> observer =
       new txCompileObserver(aProcessor, aLoaderDocument);
-  NS_ENSURE_TRUE(observer, NS_ERROR_OUT_OF_MEMORY);
 
   RefPtr<txStylesheetCompiler> compiler = new txStylesheetCompiler(
       NS_ConvertUTF8toUTF16(spec), aReferrerPolicy, observer);
-  NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY);
 
   return observer->startLoad(aUri, compiler, principal, aReferrerPolicy);
 }
 
 /**
  * handling DOM->txStylesheet
  * Observer needs to do synchronous loads.
  */
@@ -606,21 +602,19 @@ nsresult TX_CompileStylesheet(nsINode* a
   nsCOMPtr<nsIURI> uri;
   NS_GetURIWithoutRef(docUri, getter_AddRefs(uri));
   NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
 
   uri->GetSpec(spec);
   NS_ConvertUTF8toUTF16 stylesheetURI(spec);
 
   RefPtr<txSyncCompileObserver> obs = new txSyncCompileObserver(aProcessor);
-  NS_ENSURE_TRUE(obs, NS_ERROR_OUT_OF_MEMORY);
 
   RefPtr<txStylesheetCompiler> compiler =
       new txStylesheetCompiler(stylesheetURI, doc->GetReferrerPolicy(), obs);
-  NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY);
 
   compiler->setBaseURI(baseURI);
 
   nsresult rv = handleNode(aNode, compiler);
   if (NS_FAILED(rv)) {
     compiler->cancel(rv);
     return rv;
   }
--- a/dom/xslt/xslt/txMozillaTextOutput.cpp
+++ b/dom/xslt/xslt/txMozillaTextOutput.cpp
@@ -159,17 +159,17 @@ nsresult txMozillaTextOutput::createResu
   }
 
   // Create the content
 
   // When transforming into a non-displayed document (i.e. when there is no
   // observer) we only create a transformiix:result root element.
   if (!observer) {
     int32_t namespaceID;
-    rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(
+    rv = nsNameSpaceManager::GetInstance()->RegisterNameSpace(
         nsLiteralString(kTXNameSpaceURI), namespaceID);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mTextParent =
         mDocument->CreateElem(nsDependentAtomString(nsGkAtoms::result),
                               nsGkAtoms::transformiix, namespaceID);
 
     ErrorResult error;
--- a/dom/xslt/xslt/txMozillaXMLOutput.cpp
+++ b/dom/xslt/xslt/txMozillaXMLOutput.cpp
@@ -251,35 +251,33 @@ nsresult txMozillaXMLOutput::endElement(
   NS_ASSERTION(mCurrentNode->IsElement(), "borked mCurrentNode");
   NS_ENSURE_TRUE(mCurrentNode->IsElement(), NS_ERROR_UNEXPECTED);
 
   Element* element = mCurrentNode->AsElement();
 
   // Handle html-elements
   if (!mNoFixup) {
     if (element->IsHTMLElement()) {
-      rv = endHTMLElement(element);
-      NS_ENSURE_SUCCESS(rv, rv);
+      endHTMLElement(element);
     }
 
     // Handle elements that are different when parser-created
     if (nsIContent::RequiresDoneCreatingElement(
             element->NodeInfo()->NamespaceID(),
             element->NodeInfo()->NameAtom())) {
       element->DoneCreatingElement();
     } else if (element->IsSVGElement(nsGkAtoms::script) ||
                element->IsHTMLElement(nsGkAtoms::script)) {
       nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(element);
       if (sele) {
         bool block = sele->AttemptToExecute();
         // If the act of insertion evaluated the script, we're fine.
         // Else, add this script element to the array of loading scripts.
         if (block) {
-          rv = mNotifier->AddScriptElement(sele);
-          NS_ENSURE_SUCCESS(rv, rv);
+          mNotifier->AddScriptElement(sele);
         }
       } else {
         MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled,
                    "Script elements need to implement nsIScriptElement and SVG "
                    "wasn't disabled.");
       }
     } else if (nsIContent::RequiresDoneAddingChildren(
                    element->NodeInfo()->NamespaceID(),
@@ -297,21 +295,21 @@ nsresult txMozillaXMLOutput::endElement(
           updateOrError.unwrap().ShouldBlock()) {
         mNotifier->AddPendingStylesheet();
       }
     }
   }
 
   // Add the element to the tree if it wasn't added before and take one step
   // up the tree
-  uint32_t last = mCurrentNodeStack.Count() - 1;
-  NS_ASSERTION(last != (uint32_t)-1, "empty stack");
-
-  nsCOMPtr<nsINode> parent = mCurrentNodeStack.SafeObjectAt(last);
-  mCurrentNodeStack.RemoveObjectAt(last);
+  MOZ_ASSERT(!mCurrentNodeStack.IsEmpty(), "empty stack");
+  nsCOMPtr<nsINode> parent;
+  if (!mCurrentNodeStack.IsEmpty()) {
+    parent = mCurrentNodeStack.PopLastElement();
+  }
 
   if (mCurrentNode == mNonAddedNode) {
     if (parent == mDocument) {
       NS_ASSERTION(!mRootContentCreated,
                    "Parent to add to shouldn't be a document if we "
                    "have a root content");
       mRootContentCreated = true;
     }
@@ -466,22 +464,19 @@ nsresult txMozillaXMLOutput::startElemen
     ++mBadChildLevel;
     MOZ_LOG(txLog::xslt, LogLevel::Debug,
             ("startElement, mBadChildLevel = %d\n", mBadChildLevel));
     return NS_OK;
   }
 
   ++mTreeDepth;
 
-  rv = mTableStateStack.push(NS_INT32_TO_PTR(mTableState));
-  NS_ENSURE_SUCCESS(rv, rv);
+  mTableStateStack.push(NS_INT32_TO_PTR(mTableState));
 
-  if (!mCurrentNodeStack.AppendObject(mCurrentNode)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
+  mCurrentNodeStack.AppendElement(mCurrentNode);
 
   mTableState = NORMAL;
   mOpenedElementIsHTML = false;
 
   // Create the element
   RefPtr<NodeInfo> ni = mNodeInfoManager->GetNodeInfo(
       aLocalName, aPrefix, aNsID, nsINode::ELEMENT_NODE);
 
@@ -566,17 +561,17 @@ nsresult txMozillaXMLOutput::closePrevio
   return NS_OK;
 }
 
 nsresult txMozillaXMLOutput::createTxWrapper() {
   NS_ASSERTION(mDocument == mCurrentNode,
                "creating wrapper when document isn't parent");
 
   int32_t namespaceID;
-  nsresult rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(
+  nsresult rv = nsNameSpaceManager::GetInstance()->RegisterNameSpace(
       nsLiteralString(kTXNameSpaceURI), namespaceID);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<Element> wrapper =
       mDocument->CreateElem(nsDependentAtomString(nsGkAtoms::result),
                             nsGkAtoms::transformiix, namespaceID);
 
 #ifdef DEBUG
@@ -608,39 +603,38 @@ nsresult txMozillaXMLOutput::createTxWra
       wrapper->AppendChildTo(childContent, true, error);
       if (error.Failed()) {
         return error.StealNSResult();
       }
       break;
     }
   }
 
-  if (!mCurrentNodeStack.AppendObject(wrapper)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
+  mCurrentNodeStack.AppendElement(wrapper);
   mCurrentNode = wrapper;
   mRootContentCreated = true;
   NS_ASSERTION(rootLocation == mDocument->GetChildCount(),
                "Incorrect root location");
   ErrorResult error;
   mDocument->AppendChildTo(wrapper, true, error);
   return error.StealNSResult();
 }
 
 nsresult txMozillaXMLOutput::startHTMLElement(nsIContent* aElement,
                                               bool aIsHTML) {
   nsresult rv = NS_OK;
 
   if ((!aElement->IsHTMLElement(nsGkAtoms::tr) || !aIsHTML) &&
       NS_PTR_TO_INT32(mTableStateStack.peek()) == ADDED_TBODY) {
-    uint32_t last = mCurrentNodeStack.Count() - 1;
-    NS_ASSERTION(last != (uint32_t)-1, "empty stack");
-
-    mCurrentNode = mCurrentNodeStack.SafeObjectAt(last);
-    mCurrentNodeStack.RemoveObjectAt(last);
+    MOZ_ASSERT(!mCurrentNodeStack.IsEmpty(), "empty stack");
+    if (mCurrentNodeStack.IsEmpty()) {
+      mCurrentNode = nullptr;
+    } else {
+      mCurrentNode = mCurrentNodeStack.PopLastElement();
+    }
     mTableStateStack.pop();
   }
 
   if (aElement->IsHTMLElement(nsGkAtoms::table) && aIsHTML) {
     mTableState = TABLE;
   } else if (aElement->IsHTMLElement(nsGkAtoms::tr) && aIsHTML &&
              NS_PTR_TO_INT32(mTableStateStack.peek()) == TABLE) {
     RefPtr<Element> tbody;
@@ -648,23 +642,19 @@ nsresult txMozillaXMLOutput::startHTMLEl
     NS_ENSURE_SUCCESS(rv, rv);
 
     ErrorResult error;
     mCurrentNode->AppendChildTo(tbody, true, error);
     if (error.Failed()) {
       return error.StealNSResult();
     }
 
-    rv = mTableStateStack.push(NS_INT32_TO_PTR(ADDED_TBODY));
-    NS_ENSURE_SUCCESS(rv, rv);
+    mTableStateStack.push(NS_INT32_TO_PTR(ADDED_TBODY));
 
-    if (!mCurrentNodeStack.AppendObject(tbody)) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-
+    mCurrentNodeStack.AppendElement(tbody);
     mCurrentNode = tbody;
   } else if (aElement->IsHTMLElement(nsGkAtoms::head) &&
              mOutputFormat.mMethod == eHTMLOutput) {
     // Insert META tag, according to spec, 16.2, like
     // <META http-equiv="Content-Type" content="text/html; charset=EUC-JP">
     RefPtr<Element> meta;
     rv = createHTMLElement(nsGkAtoms::meta, getter_AddRefs(meta));
     NS_ENSURE_SUCCESS(rv, rv);
@@ -688,47 +678,48 @@ nsresult txMozillaXMLOutput::startHTMLEl
     if (error.Failed()) {
       return error.StealNSResult();
     }
   }
 
   return NS_OK;
 }
 
-nsresult txMozillaXMLOutput::endHTMLElement(nsIContent* aElement) {
+void txMozillaXMLOutput::endHTMLElement(nsIContent* aElement) {
   if (mTableState == ADDED_TBODY) {
     NS_ASSERTION(aElement->IsHTMLElement(nsGkAtoms::tbody),
                  "Element flagged as added tbody isn't a tbody");
-    uint32_t last = mCurrentNodeStack.Count() - 1;
-    NS_ASSERTION(last != (uint32_t)-1, "empty stack");
-
-    mCurrentNode = mCurrentNodeStack.SafeObjectAt(last);
-    mCurrentNodeStack.RemoveObjectAt(last);
+    MOZ_ASSERT(!mCurrentNodeStack.IsEmpty(), "empty stack");
+    if (mCurrentNodeStack.IsEmpty()) {
+      mCurrentNode = nullptr;
+    } else {
+      mCurrentNode = mCurrentNodeStack.PopLastElement();
+    }
     mTableState =
         static_cast<TableState>(NS_PTR_TO_INT32(mTableStateStack.pop()));
 
-    return NS_OK;
-  } else if (mCreatingNewDocument && aElement->IsHTMLElement(nsGkAtoms::meta)) {
+    return;
+  }
+
+  if (mCreatingNewDocument && aElement->IsHTMLElement(nsGkAtoms::meta)) {
     // handle HTTP-EQUIV data
     nsAutoString httpEquiv;
     aElement->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv,
                                    httpEquiv);
     if (!httpEquiv.IsEmpty()) {
       nsAutoString value;
       aElement->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::content,
                                      value);
       if (!value.IsEmpty()) {
         nsContentUtils::ASCIIToLower(httpEquiv);
         RefPtr<nsAtom> header = NS_Atomize(httpEquiv);
         processHTTPEquiv(header, value);
       }
     }
   }
-
-  return NS_OK;
 }
 
 void txMozillaXMLOutput::processHTTPEquiv(nsAtom* aHeader,
                                           const nsString& aValue) {
   // For now we only handle "refresh". There's a longer list in
   // HTMLContentSink::ProcessHeaderData
   if (aHeader == nsGkAtoms::refresh)
     LossyCopyUTF16toASCII(aValue, mRefreshString);
@@ -888,28 +879,28 @@ txTransformNotifier::~txTransformNotifie
 NS_IMPL_ISUPPORTS(txTransformNotifier, nsIScriptLoaderObserver,
                   nsICSSLoaderObserver)
 
 NS_IMETHODIMP
 txTransformNotifier::ScriptAvailable(nsresult aResult,
                                      nsIScriptElement* aElement,
                                      bool aIsInlineClassicScript, nsIURI* aURI,
                                      int32_t aLineNo) {
-  if (NS_FAILED(aResult) && mScriptElements.RemoveObject(aElement)) {
+  if (NS_FAILED(aResult) && mScriptElements.RemoveElement(aElement)) {
     SignalTransformEnd();
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 txTransformNotifier::ScriptEvaluated(nsresult aResult,
                                      nsIScriptElement* aElement,
                                      bool aIsInline) {
-  if (mScriptElements.RemoveObject(aElement)) {
+  if (mScriptElements.RemoveElement(aElement)) {
     SignalTransformEnd();
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 txTransformNotifier::StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred,
@@ -929,19 +920,18 @@ txTransformNotifier::StyleSheetLoaded(St
 
   return NS_OK;
 }
 
 void txTransformNotifier::Init(nsITransformObserver* aObserver) {
   mObserver = aObserver;
 }
 
-nsresult txTransformNotifier::AddScriptElement(nsIScriptElement* aElement) {
-  return mScriptElements.AppendObject(aElement) ? NS_OK
-                                                : NS_ERROR_OUT_OF_MEMORY;
+void txTransformNotifier::AddScriptElement(nsIScriptElement* aElement) {
+  mScriptElements.AppendElement(aElement);
 }
 
 void txTransformNotifier::AddPendingStylesheet() { ++mPendingStylesheetCount; }
 
 void txTransformNotifier::OnTransformEnd(nsresult aResult) {
   mInTransform = false;
   SignalTransformEnd(aResult);
 }
@@ -953,17 +943,17 @@ nsresult txTransformNotifier::SetOutputD
 
   // Notify the contentsink that the document is created
   return mObserver->OnDocumentCreated(mDocument);
 }
 
 void txTransformNotifier::SignalTransformEnd(nsresult aResult) {
   if (mInTransform ||
       (NS_SUCCEEDED(aResult) &&
-       (mScriptElements.Count() > 0 || mPendingStylesheetCount > 0))) {
+       (!mScriptElements.IsEmpty() || mPendingStylesheetCount > 0))) {
     return;
   }
 
   // mPendingStylesheetCount is nonzero at this point only if aResult is an
   // error.  Set it to 0 so we won't reenter this code when we stop the
   // CSSLoader.
   mPendingStylesheetCount = 0;
   mScriptElements.Clear();
--- a/dom/xslt/xslt/txMozillaXMLOutput.h
+++ b/dom/xslt/xslt/txMozillaXMLOutput.h
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef TRANSFRMX_MOZILLA_XML_OUTPUT_H
 #define TRANSFRMX_MOZILLA_XML_OUTPUT_H
 
 #include "txXMLEventHandler.h"
 #include "nsIScriptLoaderObserver.h"
 #include "txOutputFormat.h"
-#include "nsCOMArray.h"
+#include "nsTArray.h"
 #include "nsCOMPtr.h"
 #include "nsICSSLoaderObserver.h"
 #include "txStack.h"
 #include "mozilla/Attributes.h"
 
 class nsIContent;
 class nsAtom;
 class nsITransformObserver;
@@ -37,29 +37,29 @@ class txTransformNotifier final : public
   NS_DECL_ISUPPORTS
   NS_DECL_NSISCRIPTLOADEROBSERVER
 
   // nsICSSLoaderObserver
   NS_IMETHOD StyleSheetLoaded(mozilla::StyleSheet* aSheet, bool aWasDeferred,
                               nsresult aStatus) override;
 
   void Init(nsITransformObserver* aObserver);
-  nsresult AddScriptElement(nsIScriptElement* aElement);
+  void AddScriptElement(nsIScriptElement* aElement);
   void AddPendingStylesheet();
   void OnTransformEnd(nsresult aResult = NS_OK);
   void OnTransformStart();
   nsresult SetOutputDocument(mozilla::dom::Document* aDocument);
 
  private:
   ~txTransformNotifier();
   void SignalTransformEnd(nsresult aResult = NS_OK);
 
   nsCOMPtr<mozilla::dom::Document> mDocument;
   nsCOMPtr<nsITransformObserver> mObserver;
-  nsCOMArray<nsIScriptElement> mScriptElements;
+  nsTArray<nsCOMPtr<nsIScriptElement>> mScriptElements;
   uint32_t mPendingStylesheetCount;
   bool mInTransform;
 };
 
 class txMozillaXMLOutput : public txAOutputXMLEventHandler {
  public:
   txMozillaXMLOutput(txOutputFormat* aFormat, nsITransformObserver* aObserver);
   txMozillaXMLOutput(txOutputFormat* aFormat,
@@ -73,17 +73,17 @@ class txMozillaXMLOutput : public txAOut
 
   nsresult createResultDocument(const nsAString& aName, int32_t aNsID,
                                 mozilla::dom::Document* aSourceDocument,
                                 bool aLoadedAsData);
 
  private:
   nsresult createTxWrapper();
   nsresult startHTMLElement(nsIContent* aElement, bool aXHTML);
-  nsresult endHTMLElement(nsIContent* aElement);
+  void endHTMLElement(nsIContent* aElement);
   void processHTTPEquiv(nsAtom* aHeader, const nsString& aValue);
   nsresult createHTMLElement(nsAtom* aName, mozilla::dom::Element** aResult);
 
   nsresult attributeInternal(nsAtom* aPrefix, nsAtom* aLocalName, int32_t aNsID,
                              const nsString& aValue);
   nsresult startElementInternal(nsAtom* aPrefix, nsAtom* aLocalName,
                                 int32_t aNsID);
 
@@ -91,17 +91,17 @@ class txMozillaXMLOutput : public txAOut
   nsCOMPtr<nsINode> mCurrentNode;  // This is updated once an element is
                                    // 'closed' (i.e. once we're done
                                    // adding attributes to it).
                                    // until then the opened element is
                                    // kept in mOpenedElement
   nsCOMPtr<mozilla::dom::Element> mOpenedElement;
   RefPtr<nsNodeInfoManager> mNodeInfoManager;
 
-  nsCOMArray<nsINode> mCurrentNodeStack;
+  nsTArray<nsCOMPtr<nsINode>> mCurrentNodeStack;
 
   nsCOMPtr<nsIContent> mNonAddedNode;
 
   RefPtr<txTransformNotifier> mNotifier;
 
   uint32_t mTreeDepth, mBadChildLevel;
   nsCString mRefreshString;
 
--- a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp
+++ b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp
@@ -21,16 +21,17 @@
 #include "txXSLTProcessor.h"
 #include "nsIPrincipal.h"
 #include "nsThreadUtils.h"
 #include "jsapi.h"
 #include "txExprParser.h"
 #include "nsErrorService.h"
 #include "nsJSUtils.h"
 #include "nsIXPConnect.h"
+#include "nsNameSpaceManager.h"
 #include "nsVariant.h"
 #include "nsTextNode.h"
 #include "mozilla/Components.h"
 #include "mozilla/dom/DocumentFragment.h"
 #include "mozilla/dom/XSLTProcessorBinding.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
@@ -177,17 +178,16 @@ nsresult txToFragmentHandlerFactory::cre
       break;
     }
 
     case eTextOutput: {
       *aHandler = new txMozillaTextOutput(mFragment);
       break;
     }
   }
-  NS_ENSURE_TRUE(*aHandler, NS_ERROR_OUT_OF_MEMORY);
   return NS_OK;
 }
 
 nsresult txToFragmentHandlerFactory::createHandlerWith(
     txOutputFormat* aFormat, const nsAString& aName, int32_t aNsID,
     txAXMLEventHandler** aHandler) {
   *aHandler = nullptr;
   NS_ASSERTION(aFormat->mMethod != eMethodNotSet,
@@ -416,29 +416,28 @@ txMozillaXSLTProcessor::AddXSLTParam(con
     rv = expr->evaluate(&paramContext, getter_AddRefs(value));
     NS_ENSURE_SUCCESS(rv, rv);
   } else {
     value = new StringResult(aValue, nullptr);
   }
 
   RefPtr<nsAtom> name = NS_Atomize(aName);
   int32_t nsId = kNameSpaceID_Unknown;
-  rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespace, nsId);
+  rv = nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespace, nsId);
   NS_ENSURE_SUCCESS(rv, rv);
 
   txExpandedName varName(nsId, name);
   txVariable* var = static_cast<txVariable*>(mVariables.get(varName));
   if (var) {
     var->setValue(value);
 
     return NS_OK;
   }
 
   var = new txVariable(value);
-  NS_ENSURE_TRUE(var, NS_ERROR_OUT_OF_MEMORY);
 
   return mVariables.add(varName, var);
 }
 
 class nsTransformBlockerEvent : public mozilla::Runnable {
  public:
   RefPtr<txMozillaXSLTProcessor> mProcessor;
 
@@ -806,18 +805,18 @@ nsresult txMozillaXSLTProcessor::SetPara
     }
 
     default: {
       return NS_ERROR_FAILURE;
     }
   }
 
   int32_t nsId = kNameSpaceID_Unknown;
-  nsresult rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(
-      aNamespaceURI, nsId);
+  nsresult rv =
+      nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespaceURI, nsId);
   NS_ENSURE_SUCCESS(rv, rv);
   RefPtr<nsAtom> localName = NS_Atomize(aLocalName);
   txExpandedName varName(nsId, localName);
 
   txVariable* var = static_cast<txVariable*>(mVariables.get(varName));
   if (var) {
     var->setValue(value);
     return NS_OK;
@@ -826,18 +825,18 @@ nsresult txMozillaXSLTProcessor::SetPara
   var = new txVariable(value);
   return mVariables.add(varName, var);
 }
 
 already_AddRefed<nsIVariant> txMozillaXSLTProcessor::GetParameter(
     const nsAString& aNamespaceURI, const nsAString& aLocalName,
     ErrorResult& aRv) {
   int32_t nsId = kNameSpaceID_Unknown;
-  nsresult rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(
-      aNamespaceURI, nsId);
+  nsresult rv =
+      nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespaceURI, nsId);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aRv.Throw(rv);
     return nullptr;
   }
   RefPtr<nsAtom> localName = NS_Atomize(aLocalName);
   txExpandedName varName(nsId, localName);
 
   txVariable* var = static_cast<txVariable*>(mVariables.get(varName));
@@ -853,18 +852,18 @@ already_AddRefed<nsIVariant> txMozillaXS
   }
   return result.forget();
 }
 
 void txMozillaXSLTProcessor::RemoveParameter(const nsAString& aNamespaceURI,
                                              const nsAString& aLocalName,
                                              ErrorResult& aRv) {
   int32_t nsId = kNameSpaceID_Unknown;
-  nsresult rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(
-      aNamespaceURI, nsId);
+  nsresult rv =
+      nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespaceURI, nsId);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aRv.Throw(rv);
     return;
   }
   RefPtr<nsAtom> localName = NS_Atomize(aLocalName);
   txExpandedName varName(nsId, localName);
 
   mVariables.remove(varName);
@@ -1211,36 +1210,29 @@ nsresult txVariable::Convert(nsIVariant*
       if (node) {
         UniquePtr<txXPathNode> xpathNode(
             txXPathNativeNode::createXPathNode(node));
         if (!xpathNode) {
           return NS_ERROR_FAILURE;
         }
 
         *aResult = new txNodeSet(*xpathNode, nullptr);
-        if (!*aResult) {
-          return NS_ERROR_OUT_OF_MEMORY;
-        }
-
         NS_ADDREF(*aResult);
 
         return NS_OK;
       }
 
       nsCOMPtr<nsIXPathResult> xpathResult = do_QueryInterface(supports);
       if (xpathResult) {
         return xpathResult->GetExprResult(aResult);
       }
 
       nsCOMPtr<nsINodeList> nodeList = do_QueryInterface(supports);
       if (nodeList) {
         RefPtr<txNodeSet> nodeSet = new txNodeSet(nullptr);
-        if (!nodeSet) {
-          return NS_ERROR_OUT_OF_MEMORY;
-        }
 
         uint32_t length = nodeList->Length();
 
         uint32_t i;
         for (i = 0; i < length; ++i) {
           UniquePtr<txXPathNode> xpathNode(
               txXPathNativeNode::createXPathNode(nodeList->Item(i)));
           if (!xpathNode) {
--- a/dom/xslt/xslt/txNodeSorter.cpp
+++ b/dom/xslt/xslt/txNodeSorter.cpp
@@ -11,16 +11,17 @@
 #include "txExpr.h"
 #include "txStringUtils.h"
 #include "nsQuickSort.h"
 
 #include "mozilla/CheckedInt.h"
 #include "mozilla/UniquePtrExtensions.h"
 
 using mozilla::CheckedUint32;
+using mozilla::MakeUnique;
 using mozilla::MakeUniqueFallible;
 using mozilla::UniquePtr;
 
 /*
  * Sorts Nodes as specified by the W3C XSLT 1.0 Recommendation
  */
 
 txNodeSorter::txNodeSorter() : mNKeys(0) {}
@@ -119,22 +120,16 @@ nsresult txNodeSorter::sortNodeSet(txNod
   }
 
   *aResult = nullptr;
 
   RefPtr<txNodeSet> sortedNodes;
   nsresult rv = aEs->recycler()->getNodeSet(getter_AddRefs(sortedNodes));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  txNodeSetContext* evalContext = new txNodeSetContext(aNodes, aEs);
-  NS_ENSURE_TRUE(evalContext, NS_ERROR_OUT_OF_MEMORY);
-
-  rv = aEs->pushEvalContext(evalContext);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   // Create and set up memoryblock for sort-values and indexarray
   CheckedUint32 len = aNodes->size();
   CheckedUint32 numSortValues = len * mNKeys;
   CheckedUint32 sortValuesSize = numSortValues * sizeof(txObject*);
   if (!sortValuesSize.isValid()) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
@@ -145,22 +140,27 @@ nsresult txNodeSorter::sortNodeSet(txNod
   }
 
   uint32_t i;
   for (i = 0; i < len.value(); ++i) {
     indexes[i] = i;
   }
   memset(sortValues.get(), 0, sortValuesSize.value());
 
+  auto nodeSetContext = MakeUnique<txNodeSetContext>(aNodes, aEs);
+
   // Sort the indexarray
   SortData sortData;
   sortData.mNodeSorter = this;
-  sortData.mContext = evalContext;
+  sortData.mContext = nodeSetContext.get();
   sortData.mSortValues = sortValues.get();
   sortData.mRv = NS_OK;
+
+  aEs->pushEvalContext(nodeSetContext.release());
+
   NS_QuickSort(indexes.get(), len.value(), sizeof(uint32_t), compareNodes,
                &sortData);
 
   // Delete these here so we don't have to deal with them at every possible
   // failurepoint
   for (i = 0; i < numSortValues.value(); ++i) {
     delete sortValues[i];
   }
--- a/dom/xslt/xslt/txPatternOptimizer.cpp
+++ b/dom/xslt/xslt/txPatternOptimizer.cpp
@@ -1,71 +1,65 @@
 /* -*- Mode: C++; tab-width: 4; 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 "txPatternOptimizer.h"
 #include "txXSLTPatterns.h"
 
-nsresult txPatternOptimizer::optimize(txPattern* aInPattern,
-                                      txPattern** aOutPattern) {
+void txPatternOptimizer::optimize(txPattern* aInPattern,
+                                  txPattern** aOutPattern) {
   *aOutPattern = nullptr;
-  nsresult rv = NS_OK;
 
   // First optimize sub expressions
   uint32_t i = 0;
   Expr* subExpr;
   while ((subExpr = aInPattern->getSubExprAt(i))) {
     Expr* newExpr = nullptr;
-    rv = mXPathOptimizer.optimize(subExpr, &newExpr);
-    NS_ENSURE_SUCCESS(rv, rv);
+    mXPathOptimizer.optimize(subExpr, &newExpr);
     if (newExpr) {
       delete subExpr;
       aInPattern->setSubExprAt(i, newExpr);
     }
 
     ++i;
   }
 
   // Then optimize sub patterns
   txPattern* subPattern;
   i = 0;
   while ((subPattern = aInPattern->getSubPatternAt(i))) {
     txPattern* newPattern = nullptr;
-    rv = optimize(subPattern, &newPattern);
-    NS_ENSURE_SUCCESS(rv, rv);
+    optimize(subPattern, &newPattern);
     if (newPattern) {
       delete subPattern;
       aInPattern->setSubPatternAt(i, newPattern);
     }
 
     ++i;
   }
 
   // Finally see if current pattern can be optimized
   switch (aInPattern->getType()) {
     case txPattern::STEP_PATTERN:
-      return optimizeStep(aInPattern, aOutPattern);
+      optimizeStep(aInPattern, aOutPattern);
+      return;
 
     default:
       break;
   }
-
-  return NS_OK;
 }
 
-nsresult txPatternOptimizer::optimizeStep(txPattern* aInPattern,
-                                          txPattern** aOutPattern) {
+void txPatternOptimizer::optimizeStep(txPattern* aInPattern,
+                                      txPattern** aOutPattern) {
   txStepPattern* step = static_cast<txStepPattern*>(aInPattern);
 
   // Test for predicates that can be combined into the nodetest
   Expr* pred;
   while ((pred = step->getSubExprAt(0)) &&
          !pred->canReturnType(Expr::NUMBER_RESULT) &&
          !pred->isSensitiveTo(Expr::NODESET_CONTEXT)) {
     txNodeTest* predTest = new txPredicatedNodeTest(step->getNodeTest(), pred);
     step->dropFirst();
     step->setNodeTest(predTest);
   }
-
-  return NS_OK;
 }
--- a/dom/xslt/xslt/txPatternOptimizer.h
+++ b/dom/xslt/xslt/txPatternOptimizer.h
@@ -13,18 +13,18 @@ class txPattern;
 class txPatternOptimizer {
  public:
   /**
    * Optimize the given pattern.
    * @param aInPattern    Pattern to optimize.
    * @param aOutPattern   Resulting pattern, null if optimization didn't
    *                      result in a new pattern.
    */
-  nsresult optimize(txPattern* aInPattern, txPattern** aOutPattern);
+  void optimize(txPattern* aInPattern, txPattern** aOutPattern);
 
  private:
   // Helper methods for optimizing specific classes
-  nsresult optimizeStep(txPattern* aInPattern, txPattern** aOutPattern);
+  void optimizeStep(txPattern* aInPattern, txPattern** aOutPattern);
 
   txXPathOptimizer mXPathOptimizer;
 };
 
 #endif  // txPatternOptimizer_h__
--- a/dom/xslt/xslt/txPatternParser.cpp
+++ b/dom/xslt/xslt/txPatternParser.cpp
@@ -29,18 +29,17 @@ nsresult txPatternParser::createPattern(
   rv = createUnionPattern(lexer, aContext, *getter_Transfers(pattern));
   if (NS_FAILED(rv)) {
     // XXX error report parsing error
     return rv;
   }
 
   txPatternOptimizer optimizer;
   txPattern* newPattern = nullptr;
-  rv = optimizer.optimize(pattern.get(), &newPattern);
-  NS_ENSURE_SUCCESS(rv, rv);
+  optimizer.optimize(pattern.get(), &newPattern);
 
   *aResult = newPattern ? newPattern : pattern.release();
 
   return NS_OK;
 }
 
 nsresult txPatternParser::createUnionPattern(txExprLexer& aLexer,
                                              txIParseContext* aContext,
@@ -58,40 +57,26 @@ nsresult txPatternParser::createUnionPat
   }
 
   if (type != Token::UNION_OP) {
     delete locPath;
     return NS_ERROR_XPATH_PARSE_FAILURE;
   }
 
   txUnionPattern* unionPattern = new txUnionPattern();
-  rv = unionPattern->addPattern(locPath);
-#if 0  // XXX addPattern can't fail yet, it doesn't check for mem
-    if (NS_FAILED(rv)) {
-        delete unionPattern;
-        delete locPath;
-        return rv;
-    }
-#endif
+  unionPattern->addPattern(locPath);
 
   aLexer.nextToken();
   do {
     rv = createLocPathPattern(aLexer, aContext, locPath);
     if (NS_FAILED(rv)) {
       delete unionPattern;
       return rv;
     }
-    rv = unionPattern->addPattern(locPath);
-#if 0  // XXX addPattern can't fail yet, it doesn't check for mem
-        if (NS_FAILED(rv)) {
-            delete unionPattern;
-            delete locPath;
-            return rv;
-        }
-#endif
+    unionPattern->addPattern(locPath);
     type = aLexer.nextToken()->mType;
   } while (type == Token::UNION_OP);
 
   if (type != Token::END) {
     delete unionPattern;
     return NS_ERROR_XPATH_PARSE_FAILURE;
   }
 
@@ -153,47 +138,31 @@ nsresult txPatternParser::createLocPathP
 
   pathPattern = new txLocPathPattern();
   if (isAbsolute) {
     txRootPattern* root = new txRootPattern();
 #ifdef TX_TO_STRING
     root->setSerialize(false);
 #endif
 
-    rv = pathPattern->addStep(root, isChild);
-    if (NS_FAILED(rv)) {
-      delete stepPattern;
-      delete pathPattern;
-      delete root;
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
+    pathPattern->addStep(root, isChild);
   }
 
-  rv = pathPattern->addStep(stepPattern, isChild);
-  if (NS_FAILED(rv)) {
-    delete stepPattern;
-    delete pathPattern;
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
+  pathPattern->addStep(stepPattern, isChild);
   stepPattern = 0;  // stepPattern is part of pathPattern now
 
   while (type == Token::PARENT_OP || type == Token::ANCESTOR_OP) {
     isChild = type == Token::PARENT_OP;
     aLexer.nextToken();
     rv = createStepPattern(aLexer, aContext, stepPattern);
     if (NS_FAILED(rv)) {
       delete pathPattern;
       return rv;
     }
-    rv = pathPattern->addStep(stepPattern, isChild);
-    if (NS_FAILED(rv)) {
-      delete stepPattern;
-      delete pathPattern;
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
+    pathPattern->addStep(stepPattern, isChild);
     stepPattern = 0;  // stepPattern is part of pathPattern now
     type = aLexer.peek()->mType;
   }
   aPattern = pathPattern;
   return rv;
 }
 
 nsresult txPatternParser::createIdPattern(txExprLexer& aLexer,
--- a/dom/xslt/xslt/txStylesheet.cpp
+++ b/dom/xslt/xslt/txStylesheet.cpp
@@ -305,20 +305,17 @@ nsresult txStylesheet::doneCompiling() {
 
           break;
         }
       }
       delete item;
       itemIter.remove();  // remove() moves to the previous
       itemIter.next();
     }
-    // XXX(Bug 1631371) Check if this should use a fallible operation as it
-    // pretended earlier.
     mStripSpaceTests.AppendElements(frameStripSpaceTests);
-
     frameStripSpaceTests.Clear();
   }
 
   if (!mDecimalFormats.get(txExpandedName())) {
     UniquePtr<txDecimalFormat> format(new txDecimalFormat);
     rv = mDecimalFormats.add(txExpandedName(), format.get());
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -349,17 +346,17 @@ nsresult txStylesheet::addTemplate(txTem
     return NS_OK;
   }
 
   // get the txList for the right mode
   nsTArray<MatchableTemplate>* templates =
       aImportFrame->mMatchableTemplates.get(aTemplate->mMode);
 
   if (!templates) {
-    UniquePtr<nsTArray<MatchableTemplate> > newList(
+    UniquePtr<nsTArray<MatchableTemplate>> newList(
         new nsTArray<MatchableTemplate>);
     nsresult rv =
         aImportFrame->mMatchableTemplates.set(aTemplate->mMode, newList.get());
     NS_ENSURE_SUCCESS(rv, rv);
 
     templates = newList.release();
   }
 
@@ -385,18 +382,16 @@ nsresult txStylesheet::addTemplate(txTem
     uint32_t i, len = templates->Length();
     for (i = 0; i < len; ++i) {
       if (priority > (*templates)[i].mPriority) {
         break;
       }
     }
 
     MatchableTemplate* nt = templates->InsertElementAt(i);
-    NS_ENSURE_TRUE(nt, NS_ERROR_OUT_OF_MEMORY);
-
     nt->mFirstInstruction = instr;
     nt->mMatch = std::move(simple);
     nt->mPriority = priority;
 
     if (unionPattern) {
       simple = WrapUnique(unionPattern->getSubPatternAt(unionPos));
       if (simple) {
         unionPattern->setSubPatternAt(unionPos, nullptr);
@@ -437,20 +432,17 @@ nsresult txStylesheet::addStripSpace(
     txStripSpaceTest* sst = aStripSpaceItem->mStripSpaceTests[testCount - 1];
     double priority = sst->getDefaultPriority();
     int32_t i, frameCount = aFrameStripSpaceTests.Length();
     for (i = 0; i < frameCount; ++i) {
       if (aFrameStripSpaceTests[i]->getDefaultPriority() < priority) {
         break;
       }
     }
-    // XXX(Bug 1631371) Check if this should use a fallible operation as it
-    // pretended earlier.
     aFrameStripSpaceTests.InsertElementAt(i, sst);
-
     aStripSpaceItem->mStripSpaceTests.RemoveElementAt(testCount - 1);
   }
 
   return NS_OK;
 }
 
 nsresult txStylesheet::addAttributeSet(txAttributeSetItem* aAttributeSetItem) {
   nsresult rv = NS_OK;
--- a/dom/xslt/xslt/txStylesheetCompileHandlers.cpp
+++ b/dom/xslt/xslt/txStylesheetCompileHandlers.cpp
@@ -41,17 +41,17 @@ txHandlerTable* gTxParamHandler = 0;
 txHandlerTable* gTxImportHandler = 0;
 txHandlerTable* gTxAttributeSetHandler = 0;
 txHandlerTable* gTxFallbackHandler = 0;
 
 static nsresult txFnStartLRE(int32_t aNamespaceID, nsAtom* aLocalName,
                              nsAtom* aPrefix, txStylesheetAttr* aAttributes,
                              int32_t aAttrCount,
                              txStylesheetCompilerState& aState);
-static nsresult txFnEndLRE(txStylesheetCompilerState& aState);
+static void txFnEndLRE(txStylesheetCompilerState& aState);
 
 #define TX_RETURN_IF_WHITESPACE(_str, _state)           \
   do {                                                  \
     if (!_state.mElementContext->mPreserveWhitespace && \
         XMLUtils::isWhitespace(_str)) {                 \
       return NS_OK;                                     \
     }                                                   \
   } while (0)
@@ -91,18 +91,17 @@ static nsresult parseUseAttrSets(txStyle
   }
 
   nsWhitespaceTokenizer tok(attr->mValue);
   while (tok.hasMoreTokens()) {
     txExpandedName name;
     rv = name.init(tok.nextToken(), aState.mElementContext->mMappings, false);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    UniquePtr<txInstruction> instr(new txInsertAttrSet(name));
-    aState.addInstruction(std::move(instr));
+    aState.addInstruction(MakeUnique<txInsertAttrSet>(name));
   }
   return NS_OK;
 }
 
 static nsresult parseExcludeResultPrefixes(txStylesheetAttr* aAttributes,
                                            int32_t aAttrCount,
                                            int32_t aNamespaceID) {
   txStylesheetAttr* attr = nullptr;
@@ -300,16 +299,26 @@ static nsresult getCharAttr(txStylesheet
   } else if (aRequired || !aState.fcp()) {
     // XXX ErrorReport: not a character
     return NS_ERROR_XSLT_PARSE_FAILURE;
   }
 
   return NS_OK;
 }
 
+static void pushInstruction(txStylesheetCompilerState& aState,
+                            UniquePtr<txInstruction> aInstruction) {
+  aState.pushObject(aInstruction.release());
+}
+
+template <class T = txInstruction>
+static UniquePtr<T> popInstruction(txStylesheetCompilerState& aState) {
+  return UniquePtr<T>(static_cast<T*>(aState.popObject()));
+}
+
 /**
  * Ignore and error handlers
  */
 static nsresult txFnTextIgnore(const nsAString& aStr,
                                txStylesheetCompilerState& aState) {
   return NS_OK;
 }
 
@@ -334,48 +343,46 @@ static nsresult txFnStartElementIgnore(i
                                        txStylesheetCompilerState& aState) {
   if (!aState.fcp()) {
     clearAttributes(aAttributes, aAttrCount);
   }
 
   return NS_OK;
 }
 
-static nsresult txFnEndElementIgnore(txStylesheetCompilerState& aState) {
-  return NS_OK;
-}
+static void txFnEndElementIgnore(txStylesheetCompilerState& aState) {}
 
 static nsresult txFnStartElementSetIgnore(int32_t aNamespaceID,
                                           nsAtom* aLocalName, nsAtom* aPrefix,
                                           txStylesheetAttr* aAttributes,
                                           int32_t aAttrCount,
                                           txStylesheetCompilerState& aState) {
   if (!aState.fcp()) {
     clearAttributes(aAttributes, aAttrCount);
   }
 
-  return aState.pushHandlerTable(gTxIgnoreHandler);
+  aState.pushHandlerTable(gTxIgnoreHandler);
+
+  return NS_OK;
 }
 
-static nsresult txFnEndElementSetIgnore(txStylesheetCompilerState& aState) {
+static void txFnEndElementSetIgnore(txStylesheetCompilerState& aState) {
   aState.popHandlerTable();
-  return NS_OK;
 }
 
 static nsresult txFnStartElementError(int32_t aNamespaceID, nsAtom* aLocalName,
                                       nsAtom* aPrefix,
                                       txStylesheetAttr* aAttributes,
                                       int32_t aAttrCount,
                                       txStylesheetCompilerState& aState) {
   return NS_ERROR_XSLT_PARSE_FAILURE;
 }
 
-static nsresult txFnEndElementError(txStylesheetCompilerState& aState) {
-  NS_ERROR("txFnEndElementError shouldn't be called");
-  return NS_ERROR_XSLT_PARSE_FAILURE;
+static void txFnEndElementError(txStylesheetCompilerState& aState) {
+  MOZ_CRASH("txFnEndElementError shouldn't be called");
 }
 
 /**
  * Root handlers
  */
 static nsresult txFnStartStylesheet(int32_t aNamespaceID, nsAtom* aLocalName,
                                     nsAtom* aPrefix,
                                     txStylesheetAttr* aAttributes,
@@ -391,22 +398,23 @@ static nsresult txFnStartStylesheet(int3
 
   rv = parseExcludeResultPrefixes(aAttributes, aAttrCount, kNameSpaceID_None);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
                     nsGkAtoms::version, true, &attr);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  return aState.pushHandlerTable(gTxImportHandler);
+  aState.pushHandlerTable(gTxImportHandler);
+
+  return NS_OK;
 }
 
-static nsresult txFnEndStylesheet(txStylesheetCompilerState& aState) {
+static void txFnEndStylesheet(txStylesheetCompilerState& aState) {
   aState.popHandlerTable();
-  return NS_OK;
 }
 
 static nsresult txFnStartElementContinueTopLevel(
     int32_t aNamespaceID, nsAtom* aLocalName, nsAtom* aPrefix,
     txStylesheetAttr* aAttributes, int32_t aAttrCount,
     txStylesheetCompilerState& aState) {
   aState.mHandlerTable = gTxTopHandler;
 
@@ -425,39 +433,32 @@ static nsresult txFnStartLREStylesheet(i
 
   txExpandedName nullExpr;
   double prio = UnspecifiedNaN<double>();
 
   UniquePtr<txPattern> match(new txRootPattern());
   UniquePtr<txTemplateItem> templ(
       new txTemplateItem(std::move(match), nullExpr, nullExpr, prio));
   aState.openInstructionContainer(templ.get());
-  aState.addToplevelItem(templ.get());
-
-  Unused << templ.release();
-
-  rv = aState.pushHandlerTable(gTxTemplateHandler);
-  NS_ENSURE_SUCCESS(rv, rv);
+  aState.addToplevelItem(templ.release());
+
+  aState.pushHandlerTable(gTxTemplateHandler);
 
   return txFnStartLRE(aNamespaceID, aLocalName, aPrefix, aAttributes,
                       aAttrCount, aState);
 }
 
-static nsresult txFnEndLREStylesheet(txStylesheetCompilerState& aState) {
-  nsresult rv = txFnEndLRE(aState);
-  NS_ENSURE_SUCCESS(rv, rv);
+static void txFnEndLREStylesheet(txStylesheetCompilerState& aState) {
+  txFnEndLRE(aState);
 
   aState.popHandlerTable();
 
-  UniquePtr<txInstruction> instr(new txReturn());
-  aState.addInstruction(std::move(instr));
+  aState.addInstruction(MakeUnique<txReturn>());
 
   aState.closeInstructionContainer();
-
-  return NS_OK;
 }
 
 static nsresult txFnStartEmbed(int32_t aNamespaceID, nsAtom* aLocalName,
                                nsAtom* aPrefix, txStylesheetAttr* aAttributes,
                                int32_t aAttrCount,
                                txStylesheetCompilerState& aState) {
   if (!aState.handleEmbeddedSheet()) {
     return NS_OK;
@@ -466,44 +467,44 @@ static nsresult txFnStartEmbed(int32_t a
       (aLocalName != nsGkAtoms::stylesheet &&
        aLocalName != nsGkAtoms::transform)) {
     return NS_ERROR_XSLT_PARSE_FAILURE;
   }
   return txFnStartStylesheet(aNamespaceID, aLocalName, aPrefix, aAttributes,
                              aAttrCount, aState);
 }
 
-static nsresult txFnEndEmbed(txStylesheetCompilerState& aState) {
+static void txFnEndEmbed(txStylesheetCompilerState& aState) {
   if (!aState.handleEmbeddedSheet()) {
-    return NS_OK;
+    return;
   }
-  nsresult rv = txFnEndStylesheet(aState);
+  txFnEndStylesheet(aState);
   aState.doneEmbedding();
-  return rv;
 }
 
 /**
  * Top handlers
  */
 static nsresult txFnStartOtherTop(int32_t aNamespaceID, nsAtom* aLocalName,
                                   nsAtom* aPrefix,
                                   txStylesheetAttr* aAttributes,
                                   int32_t aAttrCount,
                                   txStylesheetCompilerState& aState) {
   if (aNamespaceID == kNameSpaceID_None ||
       (aNamespaceID == kNameSpaceID_XSLT && !aState.fcp())) {
     return NS_ERROR_XSLT_PARSE_FAILURE;
   }
 
-  return aState.pushHandlerTable(gTxIgnoreHandler);
+  aState.pushHandlerTable(gTxIgnoreHandler);
+
+  return NS_OK;
 }
 
-static nsresult txFnEndOtherTop(txStylesheetCompilerState& aState) {
+static void txFnEndOtherTop(txStylesheetCompilerState& aState) {
   aState.popHandlerTable();
-  return NS_OK;
 }
 
 // xsl:attribute-set
 static nsresult txFnStartAttributeSet(int32_t aNamespaceID, nsAtom* aLocalName,
                                       nsAtom* aPrefix,
                                       txStylesheetAttr* aAttributes,
                                       int32_t aAttrCount,
                                       txStylesheetCompilerState& aState) {
@@ -511,35 +512,32 @@ static nsresult txFnStartAttributeSet(in
   txExpandedName name;
   rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::name, true, aState,
                     name);
   NS_ENSURE_SUCCESS(rv, rv);
 
   UniquePtr<txAttributeSetItem> attrSet(new txAttributeSetItem(name));
   aState.openInstructionContainer(attrSet.get());
 
-  aState.addToplevelItem(attrSet.get());
-
-  Unused << attrSet.release();
+  aState.addToplevelItem(attrSet.release());
 
   rv = parseUseAttrSets(aAttributes, aAttrCount, false, aState);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  return aState.pushHandlerTable(gTxAttributeSetHandler);
+  aState.pushHandlerTable(gTxAttributeSetHandler);
+
+  return NS_OK;
 }
 
-static nsresult txFnEndAttributeSet(txStylesheetCompilerState& aState) {
+static void txFnEndAttributeSet(txStylesheetCompilerState& aState) {
   aState.popHandlerTable();
 
-  UniquePtr<txInstruction> instr(new txReturn());
-  aState.addInstruction(std::move(instr));
+  aState.addInstruction(MakeUnique<txReturn>());
 
   aState.closeInstructionContainer();
-
-  return NS_OK;
 }
 
 // xsl:decimal-format
 static nsresult txFnStartDecimalFormat(int32_t aNamespaceID, nsAtom* aLocalName,
                                        nsAtom* aPrefix,
                                        txStylesheetAttr* aAttributes,
                                        int32_t aAttrCount,
                                        txStylesheetCompilerState& aState) {
@@ -597,79 +595,78 @@ static nsresult txFnStartDecimalFormat(i
 
   rv = getCharAttr(aAttributes, aAttrCount, nsGkAtoms::patternSeparator, false,
                    aState, format->mPatternSeparator);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aState.mStylesheet->addDecimalFormat(name, std::move(format));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  return aState.pushHandlerTable(gTxIgnoreHandler);
-}
-
-static nsresult txFnEndDecimalFormat(txStylesheetCompilerState& aState) {
-  aState.popHandlerTable();
+  aState.pushHandlerTable(gTxIgnoreHandler);
 
   return NS_OK;
 }
 
+static void txFnEndDecimalFormat(txStylesheetCompilerState& aState) {
+  aState.popHandlerTable();
+}
+
 // xsl:import
 static nsresult txFnStartImport(int32_t aNamespaceID, nsAtom* aLocalName,
                                 nsAtom* aPrefix, txStylesheetAttr* aAttributes,
                                 int32_t aAttrCount,
                                 txStylesheetCompilerState& aState) {
   UniquePtr<txImportItem> import(new txImportItem);
   import->mFrame = MakeUnique<txStylesheet::ImportFrame>();
-  aState.addToplevelItem(import.get());
-
-  txImportItem* importPtr = import.release();
+  txStylesheet::ImportFrame* frame = import->mFrame.get();
+  aState.addToplevelItem(import.release());
 
   txStylesheetAttr* attr = nullptr;
   nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
                              nsGkAtoms::href, true, &attr);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoString absUri;
   URIUtils::resolveHref(attr->mValue, aState.mElementContext->mBaseURI, absUri);
-  rv = aState.loadImportedStylesheet(absUri, importPtr->mFrame.get());
+  rv = aState.loadImportedStylesheet(absUri, frame);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  return aState.pushHandlerTable(gTxIgnoreHandler);
-}
-
-static nsresult txFnEndImport(txStylesheetCompilerState& aState) {
-  aState.popHandlerTable();
+  aState.pushHandlerTable(gTxIgnoreHandler);
 
   return NS_OK;
 }
 
+static void txFnEndImport(txStylesheetCompilerState& aState) {
+  aState.popHandlerTable();
+}
+
 // xsl:include
 static nsresult txFnStartInclude(int32_t aNamespaceID, nsAtom* aLocalName,
                                  nsAtom* aPrefix, txStylesheetAttr* aAttributes,
                                  int32_t aAttrCount,
                                  txStylesheetCompilerState& aState) {
   txStylesheetAttr* attr = nullptr;
   nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
                              nsGkAtoms::href, true, &attr);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoString absUri;
   URIUtils::resolveHref(attr->mValue, aState.mElementContext->mBaseURI, absUri);
   rv = aState.loadIncludedStylesheet(absUri);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  return aState.pushHandlerTable(gTxIgnoreHandler);
-}
-
-static nsresult txFnEndInclude(txStylesheetCompilerState& aState) {
-  aState.popHandlerTable();
+  aState.pushHandlerTable(gTxIgnoreHandler);
 
   return NS_OK;
 }
 
+static void txFnEndInclude(txStylesheetCompilerState& aState) {
+  aState.popHandlerTable();
+}
+
 // xsl:key
 static nsresult txFnStartKey(int32_t aNamespaceID, nsAtom* aLocalName,
                              nsAtom* aPrefix, txStylesheetAttr* aAttributes,
                              int32_t aAttrCount,
                              txStylesheetCompilerState& aState) {
   nsresult rv = NS_OK;
   txExpandedName name;
   rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::name, true, aState,
@@ -687,25 +684,25 @@ static nsresult txFnStartKey(int32_t aNa
   rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::use, true, aState, use);
   NS_ENSURE_SUCCESS(rv, rv);
 
   aState.mDisAllowed = 0;
 
   rv = aState.mStylesheet->addKey(name, std::move(match), std::move(use));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  return aState.pushHandlerTable(gTxIgnoreHandler);
-}
-
-static nsresult txFnEndKey(txStylesheetCompilerState& aState) {
-  aState.popHandlerTable();
+  aState.pushHandlerTable(gTxIgnoreHandler);
 
   return NS_OK;
 }
 
+static void txFnEndKey(txStylesheetCompilerState& aState) {
+  aState.popHandlerTable();
+}
+
 // xsl:namespace-alias
 static nsresult txFnStartNamespaceAlias(int32_t aNamespaceID,
                                         nsAtom* aLocalName, nsAtom* aPrefix,
                                         txStylesheetAttr* aAttributes,
                                         int32_t aAttrCount,
                                         txStylesheetCompilerState& aState) {
   txStylesheetAttr* attr = nullptr;
   nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
@@ -713,25 +710,25 @@ static nsresult txFnStartNamespaceAlias(
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
                     nsGkAtoms::resultPrefix, true, &attr);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // XXX Needs to be implemented.
 
-  return aState.pushHandlerTable(gTxIgnoreHandler);
-}
-
-static nsresult txFnEndNamespaceAlias(txStylesheetCompilerState& aState) {
-  aState.popHandlerTable();
+  aState.pushHandlerTable(gTxIgnoreHandler);
 
   return NS_OK;
 }
 
+static void txFnEndNamespaceAlias(txStylesheetCompilerState& aState) {
+  aState.popHandlerTable();
+}
+
 // xsl:output
 static nsresult txFnStartOutput(int32_t aNamespaceID, nsAtom* aLocalName,
                                 nsAtom* aPrefix, txStylesheetAttr* aAttributes,
                                 int32_t aAttrCount,
                                 txStylesheetCompilerState& aState) {
   nsresult rv = NS_OK;
 
   UniquePtr<txOutputItem> item(new txOutputItem);
@@ -810,25 +807,25 @@ static nsresult txFnStartOutput(int32_t 
   getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None, nsGkAtoms::mediaType,
                false, &attr);
   if (attr) {
     item->mFormat.mMediaType = attr->mValue;
   }
 
   aState.addToplevelItem(item.release());
 
-  return aState.pushHandlerTable(gTxIgnoreHandler);
-}
-
-static nsresult txFnEndOutput(txStylesheetCompilerState& aState) {
-  aState.popHandlerTable();
+  aState.pushHandlerTable(gTxIgnoreHandler);
 
   return NS_OK;
 }
 
+static void txFnEndOutput(txStylesheetCompilerState& aState) {
+  aState.popHandlerTable();
+}
+
 // xsl:strip-space/xsl:preserve-space
 static nsresult txFnStartStripSpace(int32_t aNamespaceID, nsAtom* aLocalName,
                                     nsAtom* aPrefix,
                                     txStylesheetAttr* aAttributes,
                                     int32_t aAttrCount,
                                     txStylesheetCompilerState& aState) {
   txStylesheetAttr* attr = nullptr;
   nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
@@ -871,35 +868,31 @@ static nsresult txFnStartStripSpace(int3
         prefix = localName;
       }
       localName = nsGkAtoms::_asterisk;
     }
     if (prefix) {
       ns = aState.mElementContext->mMappings->lookupNamespace(prefix);
       NS_ENSURE_TRUE(ns != kNameSpaceID_Unknown, NS_ERROR_FAILURE);
     }
-    UniquePtr<txStripSpaceTest> sst(
+    stripItem->addStripSpaceTest(
         new txStripSpaceTest(prefix, localName, ns, strip));
-    rv = stripItem->addStripSpaceTest(sst.get());
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    Unused << sst.release();
   }
 
   aState.addToplevelItem(stripItem.release());
 
-  return aState.pushHandlerTable(gTxIgnoreHandler);
-}
-
-static nsresult txFnEndStripSpace(txStylesheetCompilerState& aState) {
-  aState.popHandlerTable();
+  aState.pushHandlerTable(gTxIgnoreHandler);
 
   return NS_OK;
 }
 
+static void txFnEndStripSpace(txStylesheetCompilerState& aState) {
+  aState.popHandlerTable();
+}
+
 // xsl:template
 static nsresult txFnStartTemplate(int32_t aNamespaceID, nsAtom* aLocalName,
                                   nsAtom* aPrefix,
                                   txStylesheetAttr* aAttributes,
                                   int32_t aAttrCount,
                                   txStylesheetCompilerState& aState) {
   nsresult rv = NS_OK;
   txExpandedName name;
@@ -922,28 +915,27 @@ static nsresult txFnStartTemplate(int32_
                       aState, match);
   NS_ENSURE_SUCCESS(rv, rv);
 
   UniquePtr<txTemplateItem> templ(
       new txTemplateItem(std::move(match), name, mode, prio));
   aState.openInstructionContainer(templ.get());
   aState.addToplevelItem(templ.release());
 
-  return aState.pushHandlerTable(gTxParamHandler);
+  aState.pushHandlerTable(gTxParamHandler);
+
+  return NS_OK;
 }
 
-static nsresult txFnEndTemplate(txStylesheetCompilerState& aState) {
+static void txFnEndTemplate(txStylesheetCompilerState& aState) {
   aState.popHandlerTable();
 
-  UniquePtr<txInstruction> instr(new txReturn());
-  aState.addInstruction(std::move(instr));
+  aState.addInstruction(MakeUnique<txReturn>());
 
   aState.closeInstructionContainer();
-
-  return NS_OK;
 }
 
 // xsl:variable, xsl:param
 static nsresult txFnStartTopVariable(int32_t aNamespaceID, nsAtom* aLocalName,
                                      nsAtom* aPrefix,
                                      txStylesheetAttr* aAttributes,
                                      int32_t aAttrCount,
                                      txStylesheetCompilerState& aState) {
@@ -956,52 +948,46 @@ static nsresult txFnStartTopVariable(int
   UniquePtr<Expr> select;
   rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select, false, aState,
                    select);
   NS_ENSURE_SUCCESS(rv, rv);
 
   UniquePtr<txVariableItem> var(new txVariableItem(
       name, std::move(select), aLocalName == nsGkAtoms::param));
   aState.openInstructionContainer(var.get());
-  rv = aState.pushPtr(var.get(), aState.eVariableItem);
-  NS_ENSURE_SUCCESS(rv, rv);
+  aState.pushPtr(var.get(), aState.eVariableItem);
 
   if (var->mValue) {
     // XXX should be gTxErrorHandler?
-    rv = aState.pushHandlerTable(gTxIgnoreHandler);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aState.pushHandlerTable(gTxIgnoreHandler);
   } else {
-    rv = aState.pushHandlerTable(gTxTopVariableHandler);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aState.pushHandlerTable(gTxTopVariableHandler);
   }
 
   aState.addToplevelItem(var.release());
 
   return NS_OK;
 }
 
-static nsresult txFnEndTopVariable(txStylesheetCompilerState& aState) {
+static void txFnEndTopVariable(txStylesheetCompilerState& aState) {
   txHandlerTable* prev = aState.mHandlerTable;
   aState.popHandlerTable();
   txVariableItem* var =
       static_cast<txVariableItem*>(aState.popPtr(aState.eVariableItem));
 
   if (prev == gTxTopVariableHandler) {
     // No children were found.
     NS_ASSERTION(!var->mValue, "There shouldn't be a select-expression here");
     var->mValue = MakeUnique<txLiteralExpr>(u""_ns);
   } else if (!var->mValue) {
     // If we don't have a select-expression there mush be children.
-    UniquePtr<txInstruction> instr(new txReturn());
-    aState.addInstruction(std::move(instr));
+    aState.addInstruction(MakeUnique<txReturn>());
   }
 
   aState.closeInstructionContainer();
-
-  return NS_OK;
 }
 
 static nsresult txFnStartElementStartTopVar(int32_t aNamespaceID,
                                             nsAtom* aLocalName, nsAtom* aPrefix,
                                             txStylesheetAttr* aAttributes,
                                             int32_t aAttrCount,
                                             txStylesheetCompilerState& aState) {
   aState.mHandlerTable = gTxTemplateHandler;
@@ -1032,19 +1018,18 @@ static nsresult txFnTextStartTopVar(cons
   txEndElement
 */
 static nsresult txFnStartLRE(int32_t aNamespaceID, nsAtom* aLocalName,
                              nsAtom* aPrefix, txStylesheetAttr* aAttributes,
                              int32_t aAttrCount,
                              txStylesheetCompilerState& aState) {
   nsresult rv = NS_OK;
 
-  UniquePtr<txInstruction> instr(
-      new txStartLREElement(aNamespaceID, aLocalName, aPrefix));
-  aState.addInstruction(std::move(instr));
+  aState.addInstruction(
+      MakeUnique<txStartLREElement>(aNamespaceID, aLocalName, aPrefix));
 
   rv = parseExcludeResultPrefixes(aAttributes, aAttrCount, kNameSpaceID_XSLT);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = parseUseAttrSets(aAttributes, aAttrCount, true, aState);
   NS_ENSURE_SUCCESS(rv, rv);
 
   txStylesheetAttr* attr = nullptr;
@@ -1059,72 +1044,64 @@ static nsresult txFnStartLRE(int32_t aNa
 
       continue;
     }
 
     UniquePtr<Expr> avt;
     rv = txExprParser::createAVT(attr->mValue, &aState, getter_Transfers(avt));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    instr = MakeUnique<txLREAttribute>(attr->mNamespaceID, attr->mLocalName,
-                                       attr->mPrefix, std::move(avt));
-    aState.addInstruction(std::move(instr));
+    aState.addInstruction(MakeUnique<txLREAttribute>(
+        attr->mNamespaceID, attr->mLocalName, attr->mPrefix, std::move(avt)));
   }
 
   return NS_OK;
 }
 
-static nsresult txFnEndLRE(txStylesheetCompilerState& aState) {
-  UniquePtr<txInstruction> instr(new txEndElement);
-  aState.addInstruction(std::move(instr));
-
-  return NS_OK;
+static void txFnEndLRE(txStylesheetCompilerState& aState) {
+  aState.addInstruction(MakeUnique<txEndElement>());
 }
 
 /*
   "LRE text"
 
   txText
 */
 static nsresult txFnText(const nsAString& aStr,
                          txStylesheetCompilerState& aState) {
   TX_RETURN_IF_WHITESPACE(aStr, aState);
 
-  UniquePtr<txInstruction> instr(new txText(aStr, false));
-  aState.addInstruction(std::move(instr));
+  aState.addInstruction(MakeUnique<txText>(aStr, false));
 
   return NS_OK;
 }
 
 /*
   xsl:apply-imports
 
   txApplyImportsStart
   txApplyImportsEnd
 */
 static nsresult txFnStartApplyImports(int32_t aNamespaceID, nsAtom* aLocalName,
                                       nsAtom* aPrefix,
                                       txStylesheetAttr* aAttributes,
                                       int32_t aAttrCount,
                                       txStylesheetCompilerState& aState) {
-  UniquePtr<txInstruction> instr(new txApplyImportsStart);
-  aState.addInstruction(std::move(instr));
-
-  instr = MakeUnique<txApplyImportsEnd>();
-  aState.addInstruction(std::move(instr));
-
-  return aState.pushHandlerTable(gTxIgnoreHandler);
-}
-
-static nsresult txFnEndApplyImports(txStylesheetCompilerState& aState) {
-  aState.popHandlerTable();
+  aState.addInstruction(MakeUnique<txApplyImportsStart>());
+  aState.addInstruction(MakeUnique<txApplyImportsEnd>());
+
+  aState.pushHandlerTable(gTxIgnoreHandler);
 
   return NS_OK;
 }
 
+static void txFnEndApplyImports(txStylesheetCompilerState& aState) {
+  aState.popHandlerTable();
+}
+
 /*
   xsl:apply-templates
 
   txPushParams
   [params]
   txPushNewContext    -+   (holds <xsl:sort>s)
   txApplyTemplate <-+  |
   txLoopNodeSet    -+  |
@@ -1132,169 +1109,137 @@ static nsresult txFnEndApplyImports(txSt
 */
 static nsresult txFnStartApplyTemplates(int32_t aNamespaceID,
                                         nsAtom* aLocalName, nsAtom* aPrefix,
                                         txStylesheetAttr* aAttributes,
                                         int32_t aAttrCount,
                                         txStylesheetCompilerState& aState) {
   nsresult rv = NS_OK;
 
-  UniquePtr<txInstruction> instr(new txPushParams);
-  aState.addInstruction(std::move(instr));
+  aState.addInstruction(MakeUnique<txPushParams>());
 
   txExpandedName mode;
   rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::mode, false, aState,
                     mode);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  instr = MakeUnique<txApplyTemplates>(mode);
-  rv = aState.pushObject(instr.get());
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  Unused << instr.release();
+  pushInstruction(aState, MakeUnique<txApplyTemplates>(mode));
 
   UniquePtr<Expr> select;
   rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select, false, aState,
                    select);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!select) {
     UniquePtr<txNodeTest> nt(new txNodeTypeTest(txNodeTypeTest::NODE_TYPE));
     select = MakeUnique<LocationStep>(nt.release(), LocationStep::CHILD_AXIS);
   }
 
   UniquePtr<txPushNewContext> pushcontext(
       new txPushNewContext(std::move(select)));
-  rv = aState.pushSorter(pushcontext.get());
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aState.pushObject(pushcontext.get());
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  Unused << pushcontext.release();
-
-  return aState.pushHandlerTable(gTxApplyTemplatesHandler);
+  aState.pushSorter(pushcontext.get());
+  pushInstruction(aState, std::move(pushcontext));
+
+  aState.pushHandlerTable(gTxApplyTemplatesHandler);
+
+  return NS_OK;
 }
 
-static nsresult txFnEndApplyTemplates(txStylesheetCompilerState& aState) {
+static void txFnEndApplyTemplates(txStylesheetCompilerState& aState) {
   aState.popHandlerTable();
 
   txPushNewContext* pushcontext =
-      static_cast<txPushNewContext*>(aState.popObject());
-  UniquePtr<txInstruction> instr(pushcontext);  // txPushNewContext
-  aState.addInstruction(std::move(instr));
+      aState.addInstruction(popInstruction<txPushNewContext>(aState));
 
   aState.popSorter();
 
-  instr = WrapUnique(
-      static_cast<txInstruction*>(aState.popObject()));  // txApplyTemplates
-  UniquePtr<txLoopNodeSet> loop(new txLoopNodeSet(instr.get()));
-  aState.addInstruction(std::move(instr));
-
-  instr = std::move(loop);
-  aState.addInstruction(std::move(instr));
-
-  instr = MakeUnique<txPopParams>();
-  pushcontext->mBailTarget = instr.get();
-  aState.addInstruction(std::move(instr));
-
-  return NS_OK;
+  // txApplyTemplates
+  txInstruction* instr = aState.addInstruction(popInstruction(aState));
+  aState.addInstruction(MakeUnique<txLoopNodeSet>(instr));
+
+  pushcontext->mBailTarget = aState.addInstruction(MakeUnique<txPopParams>());
 }
 
 /*
   xsl:attribute
 
   txPushStringHandler
   [children]
   txAttribute
 */
 static nsresult txFnStartAttribute(int32_t aNamespaceID, nsAtom* aLocalName,
                                    nsAtom* aPrefix,
                                    txStylesheetAttr* aAttributes,
                                    int32_t aAttrCount,
                                    txStylesheetCompilerState& aState) {
   nsresult rv = NS_OK;
 
-  UniquePtr<txInstruction> instr(new txPushStringHandler(true));
-  aState.addInstruction(std::move(instr));
+  aState.addInstruction(MakeUnique<txPushStringHandler>(true));
 
   UniquePtr<Expr> name;
   rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::name, true, aState, name);
   NS_ENSURE_SUCCESS(rv, rv);
 
   UniquePtr<Expr> nspace;
   rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::_namespace, false, aState,
                   nspace);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  instr = MakeUnique<txAttribute>(std::move(name), std::move(nspace),
-                                  aState.mElementContext->mMappings);
-  rv = aState.pushObject(instr.get());
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  Unused << instr.release();
+  pushInstruction(aState,
+                  MakeUnique<txAttribute>(std::move(name), std::move(nspace),
+                                          aState.mElementContext->mMappings));
 
   // We need to push the template-handler since the current might be
   // the attributeset-handler
-  return aState.pushHandlerTable(gTxTemplateHandler);
-}
-
-static nsresult txFnEndAttribute(txStylesheetCompilerState& aState) {
-  aState.popHandlerTable();
-  UniquePtr<txInstruction> instr(
-      static_cast<txInstruction*>(aState.popObject()));
-  aState.addInstruction(std::move(instr));
+  aState.pushHandlerTable(gTxTemplateHandler);
 
   return NS_OK;
 }
 
+static void txFnEndAttribute(txStylesheetCompilerState& aState) {
+  aState.popHandlerTable();
+  aState.addInstruction(popInstruction(aState));
+}
+
 /*
   xsl:call-template
 
   txPushParams
   [params]
   txCallTemplate
   txPopParams
 */
 static nsresult txFnStartCallTemplate(int32_t aNamespaceID, nsAtom* aLocalName,
                                       nsAtom* aPrefix,
                                       txStylesheetAttr* aAttributes,
                                       int32_t aAttrCount,
                                       txStylesheetCompilerState& aState) {
   nsresult rv = NS_OK;
 
-  UniquePtr<txInstruction> instr(new txPushParams);
-  aState.addInstruction(std::move(instr));
+  aState.addInstruction(MakeUnique<txPushParams>());
 
   txExpandedName name;
   rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::name, true, aState,
                     name);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  instr = MakeUnique<txCallTemplate>(name);
-  rv = aState.pushObject(instr.get());
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  Unused << instr.release();
-
-  return aState.pushHandlerTable(gTxCallTemplateHandler);
+  pushInstruction(aState, MakeUnique<txCallTemplate>(name));
+
+  aState.pushHandlerTable(gTxCallTemplateHandler);
+
+  return NS_OK;
 }
 
-static nsresult txFnEndCallTemplate(txStylesheetCompilerState& aState) {
+static void txFnEndCallTemplate(txStylesheetCompilerState& aState) {
   aState.popHandlerTable();
 
   // txCallTemplate
-  UniquePtr<txInstruction> instr(
-      static_cast<txInstruction*>(aState.popObject()));
-  aState.addInstruction(std::move(instr));
-
-  instr = MakeUnique<txPopParams>();
-  aState.addInstruction(std::move(instr));
-
-  return NS_OK;
+  aState.addInstruction(popInstruction(aState));
+
+  aState.addInstruction(MakeUnique<txPopParams>());
 }
 
 /*
   xsl:choose
 
   txCondotionalGoto      --+        \
   [children]               |         | one for each xsl:when
   txGoTo           --+     |        /
@@ -1305,96 +1250,77 @@ static nsresult txFnEndCallTemplate(txSt
                      |          |
   [children]         |        <-+      for the xsl:otherwise, if there is one
                    <-+
 */
 static nsresult txFnStartChoose(int32_t aNamespaceID, nsAtom* aLocalName,
                                 nsAtom* aPrefix, txStylesheetAttr* aAttributes,
                                 int32_t aAttrCount,
                                 txStylesheetCompilerState& aState) {
-  nsresult rv = aState.pushChooseGotoList();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return aState.pushHandlerTable(gTxChooseHandler);
+  aState.pushChooseGotoList();
+
+  aState.pushHandlerTable(gTxChooseHandler);
+
+  return NS_OK;
 }
 
-static nsresult txFnEndChoose(txStylesheetCompilerState& aState) {
-  nsresult rv = NS_OK;
+static void txFnEndChoose(txStylesheetCompilerState& aState) {
   aState.popHandlerTable();
   txListIterator iter(aState.mChooseGotoList.get());
   txGoTo* gotoinstr;
   while ((gotoinstr = static_cast<txGoTo*>(iter.next()))) {
-    rv = aState.addGotoTarget(&gotoinstr->mTarget);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aState.addGotoTarget(&gotoinstr->mTarget);
   }
 
   aState.popChooseGotoList();
-
-  return NS_OK;
 }
 
 /*
   xsl:comment
 
   txPushStringHandler
   [children]
   txComment
 */
 static nsresult txFnStartComment(int32_t aNamespaceID, nsAtom* aLocalName,
                                  nsAtom* aPrefix, txStylesheetAttr* aAttributes,
                                  int32_t aAttrCount,
                                  txStylesheetCompilerState& aState) {
-  UniquePtr<txInstruction> instr(new txPushStringHandler(true));
-  aState.addInstruction(std::move(instr));
+  aState.addInstruction(MakeUnique<txPushStringHandler>(true));
 
   return NS_OK;
 }
 
-static nsresult txFnEndComment(txStylesheetCompilerState& aState) {
-  UniquePtr<txInstruction> instr(new txComment);
-  aState.addInstruction(std::move(instr));
-
-  return NS_OK;
+static void txFnEndComment(txStylesheetCompilerState& aState) {
+  aState.addInstruction(MakeUnique<txComment>());
 }
 
 /*
   xsl:copy
 
   txCopy          -+
   txInsertAttrSet  |     one for each qname in use-attribute-sets
   [children]       |
   txEndElement     |
                  <-+
 */
 static nsresult txFnStartCopy(int32_t aNamespaceID, nsAtom* aLocalName,
                               nsAtom* aPrefix, txStylesheetAttr* aAttributes,
                               int32_t aAttrCount,
                               txStylesheetCompilerState& aState) {
-  UniquePtr<txCopy> copy(new txCopy);
-  nsresult rv = aState.pushPtr(copy.get(), aState.eCopy);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  UniquePtr<txInstruction> instr(copy.release());
-  aState.addInstruction(std::move(instr));
-
-  rv = parseUseAttrSets(aAttributes, aAttrCount, false, aState);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
+  aState.pushPtr(aState.addInstruction(MakeUnique<txCopy>()), aState.eCopy);
+
+  return parseUseAttrSets(aAttributes, aAttrCount, false, aState);
 }
 
-static nsresult txFnEndCopy(txStylesheetCompilerState& aState) {
-  UniquePtr<txInstruction> instr(new txEndElement);
-  aState.addInstruction(std::move(instr));
+static void txFnEndCopy(txStylesheetCompilerState& aState) {
+  aState.addInstruction(MakeUnique<txEndElement>());
 
   txCopy* copy = static_cast<txCopy*>(aState.popPtr(aState.eCopy));
-  nsresult rv = aState.addGotoTarget(&copy->mBailTarget);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
+  aState.addGotoTarget(&copy->mBailTarget);
 }
 
 /*
   xsl:copy-of
 
   txCopyOf
 */
 static nsresult txFnStartCopyOf(int32_t aNamespaceID, nsAtom* aLocalName,
@@ -1403,25 +1329,25 @@ static nsresult txFnStartCopyOf(int32_t 
                                 txStylesheetCompilerState& aState) {
   nsresult rv = NS_OK;
 
   UniquePtr<Expr> select;
   rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select, true, aState,
                    select);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  UniquePtr<txInstruction> instr(new txCopyOf(std::move(select)));
-  aState.addInstruction(std::move(instr));
-
-  return aState.pushHandlerTable(gTxIgnoreHandler);
+  aState.addInstruction(MakeUnique<txCopyOf>(std::move(select)));
+
+  aState.pushHandlerTable(gTxIgnoreHandler);
+
+  return NS_OK;
 }
 
-static nsresult txFnEndCopyOf(txStylesheetCompilerState& aState) {
+static void txFnEndCopyOf(txStylesheetCompilerState& aState) {
   aState.popHandlerTable();
-  return NS_OK;
 }
 
 /*
   xsl:element
 
   txStartElement
   txInsertAttrSet        one for each qname in use-attribute-sets
   [children]
@@ -1437,54 +1363,51 @@ static nsresult txFnStartElement(int32_t
   rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::name, true, aState, name);
   NS_ENSURE_SUCCESS(rv, rv);
 
   UniquePtr<Expr> nspace;
   rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::_namespace, false, aState,
                   nspace);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  UniquePtr<txInstruction> instr(new txStartElement(
+  aState.addInstruction(MakeUnique<txStartElement>(
       std::move(name), std::move(nspace), aState.mElementContext->mMappings));
-  aState.addInstruction(std::move(instr));
 
   rv = parseUseAttrSets(aAttributes, aAttrCount, false, aState);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
-static nsresult txFnEndElement(txStylesheetCompilerState& aState) {
-  UniquePtr<txInstruction> instr(new txEndElement);
-  aState.addInstruction(std::move(instr));
-
-  return NS_OK;
+static void txFnEndElement(txStylesheetCompilerState& aState) {
+  aState.addInstruction(MakeUnique<txEndElement>());
 }
 
 /*
     xsl:fallback
 
     [children]
 */
 static nsresult txFnStartFallback(int32_t aNamespaceID, nsAtom* aLocalName,
                                   nsAtom* aPrefix,
                                   txStylesheetAttr* aAttributes,
                                   int32_t aAttrCount,
                                   txStylesheetCompilerState& aState) {
   aState.mSearchingForFallback = false;
 
-  return aState.pushHandlerTable(gTxTemplateHandler);
+  aState.pushHandlerTable(gTxTemplateHandler);
+
+  return NS_OK;
 }
 
-static nsresult txFnEndFallback(txStylesheetCompilerState& aState) {
+static void txFnEndFallback(txStylesheetCompilerState& aState) {
   aState.popHandlerTable();
 
   NS_ASSERTION(!aState.mSearchingForFallback,
                "bad nesting of unknown-instruction and fallback handlers");
-  return NS_OK;
 }
 
 /*
   xsl:for-each
 
   txPushNewContext            -+    (holds <xsl:sort>s)
   txPushNullTemplateRule  <-+  |
   [children]                |  |
@@ -1497,52 +1420,42 @@ static nsresult txFnStartForEach(int32_t
                                  txStylesheetCompilerState& aState) {
   nsresult rv = NS_OK;
 
   UniquePtr<Expr> select;
   rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select, true, aState,
                    select);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  UniquePtr<txPushNewContext> pushcontext(
-      new txPushNewContext(std::move(select)));
-  rv = aState.pushPtr(pushcontext.get(), aState.ePushNewContext);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aState.pushSorter(pushcontext.get());
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  UniquePtr<txInstruction> instr(pushcontext.release());
-  aState.addInstruction(std::move(instr));
-
-  instr = MakeUnique<txPushNullTemplateRule>();
-  rv = aState.pushPtr(instr.get(), aState.ePushNullTemplateRule);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  aState.addInstruction(std::move(instr));
-
-  return aState.pushHandlerTable(gTxForEachHandler);
+  txPushNewContext* pushcontext =
+      aState.addInstruction(MakeUnique<txPushNewContext>(std::move(select)));
+  aState.pushPtr(pushcontext, aState.ePushNewContext);
+  aState.pushSorter(pushcontext);
+
+  aState.pushPtr(aState.addInstruction(MakeUnique<txPushNullTemplateRule>()),
+                 aState.ePushNullTemplateRule);
+
+  aState.pushHandlerTable(gTxForEachHandler);
+
+  return NS_OK;
 }
 
-static nsresult txFnEndForEach(txStylesheetCompilerState& aState) {
+static void txFnEndForEach(txStylesheetCompilerState& aState) {
   aState.popHandlerTable();
 
   // This is a txPushNullTemplateRule
   txInstruction* pnullrule =
       static_cast<txInstruction*>(aState.popPtr(aState.ePushNullTemplateRule));
 
-  UniquePtr<txInstruction> instr(new txLoopNodeSet(pnullrule));
-  aState.addInstruction(std::move(instr));
+  aState.addInstruction(MakeUnique<txLoopNodeSet>(pnullrule));
 
   aState.popSorter();
   txPushNewContext* pushcontext =
       static_cast<txPushNewContext*>(aState.popPtr(aState.ePushNewContext));
   aState.addGotoTarget(&pushcontext->mBailTarget);
-
-  return NS_OK;
 }
 
 static nsresult txFnStartElementContinueTemplate(
     int32_t aNamespaceID, nsAtom* aLocalName, nsAtom* aPrefix,
     txStylesheetAttr* aAttributes, int32_t aAttrCount,
     txStylesheetCompilerState& aState) {
   aState.mHandlerTable = gTxTemplateHandler;
 
@@ -1571,67 +1484,54 @@ static nsresult txFnStartIf(int32_t aNam
                             txStylesheetCompilerState& aState) {
   nsresult rv = NS_OK;
 
   UniquePtr<Expr> test;
   rv =
       getExprAttr(aAttributes, aAttrCount, nsGkAtoms::test, true, aState, test);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  UniquePtr<txConditionalGoto> condGoto(
-      new txConditionalGoto(std::move(test), nullptr));
-  rv = aState.pushPtr(condGoto.get(), aState.eConditionalGoto);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  UniquePtr<txInstruction> instr(condGoto.release());
-  aState.addInstruction(std::move(instr));
+  aState.pushPtr(aState.addInstruction(
+                     MakeUnique<txConditionalGoto>(std::move(test), nullptr)),
+                 aState.eConditionalGoto);
 
   return NS_OK;
 }
 
-static nsresult txFnEndIf(txStylesheetCompilerState& aState) {
+static void txFnEndIf(txStylesheetCompilerState& aState) {
   txConditionalGoto* condGoto =
       static_cast<txConditionalGoto*>(aState.popPtr(aState.eConditionalGoto));
-  return aState.addGotoTarget(&condGoto->mTarget);
+  aState.addGotoTarget(&condGoto->mTarget);
 }
 
 /*
   xsl:message
 
   txPushStringHandler
   [children]
   txMessage
 */
 static nsresult txFnStartMessage(int32_t aNamespaceID, nsAtom* aLocalName,
                                  nsAtom* aPrefix, txStylesheetAttr* aAttributes,
                                  int32_t aAttrCount,
                                  txStylesheetCompilerState& aState) {
-  UniquePtr<txInstruction> instr(new txPushStringHandler(false));
-  aState.addInstruction(std::move(instr));
+  aState.addInstruction(MakeUnique<txPushStringHandler>(false));
 
   txThreeState term;
   nsresult rv = getYesNoAttr(aAttributes, aAttrCount, nsGkAtoms::terminate,
                              false, aState, term);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  instr = MakeUnique<txMessage>(term == eTrue);
-  rv = aState.pushObject(instr.get());
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  Unused << instr.release();
+  pushInstruction(aState, MakeUnique<txMessage>(term == eTrue));
 
   return NS_OK;
 }
 
-static nsresult txFnEndMessage(txStylesheetCompilerState& aState) {
-  UniquePtr<txInstruction> instr(
-      static_cast<txInstruction*>(aState.popObject()));
-  aState.addInstruction(std::move(instr));
-
-  return NS_OK;
+static void txFnEndMessage(txStylesheetCompilerState& aState) {
+  aState.addInstruction(popInstruction(aState));
 }
 
 /*
   xsl:number
 
   txNumber
 */
 static nsresult txFnStartNumber(int32_t aNamespaceID, nsAtom* aLocalName,
@@ -1689,49 +1589,48 @@ static nsresult txFnStartNumber(int32_t 
                   aState, groupingSeparator);
   NS_ENSURE_SUCCESS(rv, rv);
 
   UniquePtr<Expr> groupingSize;
   rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::groupingSize, false,
                   aState, groupingSize);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  UniquePtr<txInstruction> instr(
-      new txNumber(level, std::move(count), std::move(from), std::move(value),
-                   std::move(format), std::move(groupingSeparator),
-                   std::move(groupingSize)));
-  aState.addInstruction(std::move(instr));
-
-  return aState.pushHandlerTable(gTxIgnoreHandler);
-}
-
-static nsresult txFnEndNumber(txStylesheetCompilerState& aState) {
-  aState.popHandlerTable();
+  aState.addInstruction(MakeUnique<txNumber>(
+      level, std::move(count), std::move(from), std::move(value),
+      std::move(format), std::move(groupingSeparator),
+      std::move(groupingSize)));
+
+  aState.pushHandlerTable(gTxIgnoreHandler);
 
   return NS_OK;
 }
 
+static void txFnEndNumber(txStylesheetCompilerState& aState) {
+  aState.popHandlerTable();
+}
+
 /*
     xsl:otherwise
 
     (see xsl:choose)
 */
 static nsresult txFnStartOtherwise(int32_t aNamespaceID, nsAtom* aLocalName,
                                    nsAtom* aPrefix,
                                    txStylesheetAttr* aAttributes,
                                    int32_t aAttrCount,
                                    txStylesheetCompilerState& aState) {
-  return aState.pushHandlerTable(gTxTemplateHandler);
+  aState.pushHandlerTable(gTxTemplateHandler);
+
+  return NS_OK;
 }
 
-static nsresult txFnEndOtherwise(txStylesheetCompilerState& aState) {
+static void txFnEndOtherwise(txStylesheetCompilerState& aState) {
   aState.popHandlerTable();
   aState.mHandlerTable = gTxIgnoreHandler;  // XXX should be gTxErrorHandler
-
-  return NS_OK;
 }
 
 /*
     xsl:param
 
     txCheckParam    --+
     txPushRTFHandler  |  --- (for RTF-parameters)
     [children]        |  /
@@ -1744,106 +1643,83 @@ static nsresult txFnStartParam(int32_t a
                                txStylesheetCompilerState& aState) {
   nsresult rv = NS_OK;
 
   txExpandedName name;
   rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::name, true, aState,
                     name);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  UniquePtr<txCheckParam> checkParam(new txCheckParam(name));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aState.pushPtr(checkParam.get(), aState.eCheckParam);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  UniquePtr<txInstruction> instr(checkParam.release());
-  aState.addInstruction(std::move(instr));
+  aState.pushPtr(aState.addInstruction(MakeUnique<txCheckParam>(name)),
+                 aState.eCheckParam);
 
   UniquePtr<Expr> select;
   rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select, false, aState,
                    select);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  UniquePtr<txSetVariable> var(new txSetVariable(name, std::move(select)));
+  UniquePtr<txSetVariable> var =
+      MakeUnique<txSetVariable>(name, std::move(select));
   if (var->mValue) {
     // XXX should be gTxErrorHandler?
-    rv = aState.pushHandlerTable(gTxIgnoreHandler);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aState.pushHandlerTable(gTxIgnoreHandler);
   } else {
-    rv = aState.pushHandlerTable(gTxVariableHandler);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aState.pushHandlerTable(gTxVariableHandler);
   }
 
-  rv = aState.pushObject(var.get());
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  Unused << var.release();
+  pushInstruction(aState, std::move(var));
 
   return NS_OK;
 }
 
-static nsresult txFnEndParam(txStylesheetCompilerState& aState) {
-  UniquePtr<txSetVariable> var(static_cast<txSetVariable*>(aState.popObject()));
+static void txFnEndParam(txStylesheetCompilerState& aState) {
+  UniquePtr<txSetVariable> var = popInstruction<txSetVariable>(aState);
   txHandlerTable* prev = aState.mHandlerTable;
   aState.popHandlerTable();
 
   if (prev == gTxVariableHandler) {
     // No children were found.
     NS_ASSERTION(!var->mValue, "There shouldn't be a select-expression here");
     var->mValue = MakeUnique<txLiteralExpr>(u""_ns);
   }
 
-  nsresult rv = aState.addVariable(var->mName);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  UniquePtr<txInstruction> instr(var.release());
-  aState.addInstruction(std::move(instr));
+  aState.addVariable(var->mName);
+
+  aState.addInstruction(std::move(var));
 
   txCheckParam* checkParam =
       static_cast<txCheckParam*>(aState.popPtr(aState.eCheckParam));
   aState.addGotoTarget(&checkParam->mBailTarget);
-
-  return NS_OK;
 }
 
 /*
   xsl:processing-instruction
 
   txPushStringHandler
   [children]
   txProcessingInstruction
 */
 static nsresult txFnStartPI(int32_t aNamespaceID, nsAtom* aLocalName,
                             nsAtom* aPrefix, txStylesheetAttr* aAttributes,
                             int32_t aAttrCount,
                             txStylesheetCompilerState& aState) {
-  UniquePtr<txInstruction> instr(new txPushStringHandler(true));
-  aState.addInstruction(std::move(instr));
+  aState.addInstruction(MakeUnique<txPushStringHandler>(true));
 
   UniquePtr<Expr> name;
   nsresult rv =
       getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::name, true, aState, name);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  instr = MakeUnique<txProcessingInstruction>(std::move(name));
-  rv = aState.pushObject(instr.get());
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  Unused << instr.release();
+  pushInstruction(aState, MakeUnique<txProcessingInstruction>(std::move(name)));
 
   return NS_OK;
 }
 
-static nsresult txFnEndPI(txStylesheetCompilerState& aState) {
-  UniquePtr<txInstruction> instr(
-      static_cast<txInstruction*>(aState.popObject()));
-  aState.addInstruction(std::move(instr));
-
-  return NS_OK;
+static void txFnEndPI(txStylesheetCompilerState& aState) {
+  aState.addInstruction(popInstruction(aState));
 }
 
 /*
     xsl:sort
 
     (no instructions)
 */
 static nsresult txFnStartSort(int32_t aNamespaceID, nsAtom* aLocalName,
@@ -1877,30 +1753,29 @@ static nsresult txFnStartSort(int32_t aN
                   order);
   NS_ENSURE_SUCCESS(rv, rv);
 
   UniquePtr<Expr> caseOrder;
   rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::caseOrder, false, aState,
                   caseOrder);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = aState.mSorter->addSort(std::move(select), std::move(lang),
-                               std::move(dataType), std::move(order),
-                               std::move(caseOrder));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return aState.pushHandlerTable(gTxIgnoreHandler);
-}
-
-static nsresult txFnEndSort(txStylesheetCompilerState& aState) {
-  aState.popHandlerTable();
+  aState.mSorter->addSort(std::move(select), std::move(lang),
+                          std::move(dataType), std::move(order),
+                          std::move(caseOrder));
+
+  aState.pushHandlerTable(gTxIgnoreHandler);
 
   return NS_OK;
 }
 
+static void txFnEndSort(txStylesheetCompilerState& aState) {
+  aState.popHandlerTable();
+}
+
 /*
   xsl:text
 
   [children]     (only txText)
 */
 static nsresult txFnStartText(int32_t aNamespaceID, nsAtom* aLocalName,
                               nsAtom* aPrefix, txStylesheetAttr* aAttributes,
                               int32_t aAttrCount,
@@ -1910,29 +1785,29 @@ static nsresult txFnStartText(int32_t aN
   nsresult rv = NS_OK;
   txThreeState doe;
   rv = getYesNoAttr(aAttributes, aAttrCount, nsGkAtoms::disableOutputEscaping,
                     false, aState, doe);
   NS_ENSURE_SUCCESS(rv, rv);
 
   aState.mDOE = doe == eTrue;
 
-  return aState.pushHandlerTable(gTxTextHandler);
+  aState.pushHandlerTable(gTxTextHandler);
+
+  return NS_OK;
 }
 
-static nsresult txFnEndText(txStylesheetCompilerState& aState) {
+static void txFnEndText(txStylesheetCompilerState& aState) {
   aState.mDOE = false;
   aState.popHandlerTable();
-  return NS_OK;
 }
 
 static nsresult txFnTextText(const nsAString& aStr,
                              txStylesheetCompilerState& aState) {
-  UniquePtr<txInstruction> instr(new txText(aStr, aState.mDOE));
-  aState.addInstruction(std::move(instr));
+  aState.addInstruction(MakeUnique<txText>(aStr, aState.mDOE));
 
   return NS_OK;
 }
 
 /*
   xsl:value-of
 
   txValueOf
@@ -1948,26 +1823,25 @@ static nsresult txFnStartValueOf(int32_t
                     false, aState, doe);
   NS_ENSURE_SUCCESS(rv, rv);
 
   UniquePtr<Expr> select;
   rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select, true, aState,
                    select);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  UniquePtr<txInstruction> instr(
-      new txValueOf(std::move(select), doe == eTrue));
-  aState.addInstruction(std::move(instr));
-
-  return aState.pushHandlerTable(gTxIgnoreHandler);
+  aState.addInstruction(MakeUnique<txValueOf>(std::move(select), doe == eTrue));
+
+  aState.pushHandlerTable(gTxIgnoreHandler);
+
+  return NS_OK;
 }
 
-static nsresult txFnEndValueOf(txStylesheetCompilerState& aState) {
+static void txFnEndValueOf(txStylesheetCompilerState& aState) {
   aState.popHandlerTable();
-  return NS_OK;
 }
 
 /*
     xsl:variable
 
     txPushRTFHandler     --- (for RTF-parameters)
     [children]           /
     txSetVariable
@@ -1984,74 +1858,64 @@ static nsresult txFnStartVariable(int32_
                     name);
   NS_ENSURE_SUCCESS(rv, rv);
 
   UniquePtr<Expr> select;
   rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select, false, aState,
                    select);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  UniquePtr<txSetVariable> var(new txSetVariable(name, std::move(select)));
+  UniquePtr<txSetVariable> var =
+      MakeUnique<txSetVariable>(name, std::move(select));
   if (var->mValue) {
     // XXX should be gTxErrorHandler?
-    rv = aState.pushHandlerTable(gTxIgnoreHandler);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aState.pushHandlerTable(gTxIgnoreHandler);
   } else {
-    rv = aState.pushHandlerTable(gTxVariableHandler);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aState.pushHandlerTable(gTxVariableHandler);
   }
 
-  rv = aState.pushObject(var.get());
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  Unused << var.release();
+  pushInstruction(aState, std::move(var));
 
   return NS_OK;
 }
 
-static nsresult txFnEndVariable(txStylesheetCompilerState& aState) {
-  UniquePtr<txSetVariable> var(static_cast<txSetVariable*>(aState.popObject()));
+static void txFnEndVariable(txStylesheetCompilerState& aState) {
+  UniquePtr<txSetVariable> var = popInstruction<txSetVariable>(aState);
 
   txHandlerTable* prev = aState.mHandlerTable;
   aState.popHandlerTable();
 
   if (prev == gTxVariableHandler) {
     // No children were found.
     NS_ASSERTION(!var->mValue, "There shouldn't be a select-expression here");
     var->mValue = MakeUnique<txLiteralExpr>(u""_ns);
   }
 
-  nsresult rv = aState.addVariable(var->mName);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  UniquePtr<txInstruction> instr(var.release());
-  aState.addInstruction(std::move(instr));
-
-  return NS_OK;
+  aState.addVariable(var->mName);
+
+  aState.addInstruction(std::move(var));
 }
 
 static nsresult txFnStartElementStartRTF(int32_t aNamespaceID,
                                          nsAtom* aLocalName, nsAtom* aPrefix,
                                          txStylesheetAttr* aAttributes,
                                          int32_t aAttrCount,
                                          txStylesheetCompilerState& aState) {
-  UniquePtr<txInstruction> instr(new txPushRTFHandler);
-  aState.addInstruction(std::move(instr));
+  aState.addInstruction(MakeUnique<txPushRTFHandler>());
 
   aState.mHandlerTable = gTxTemplateHandler;
 
   return NS_XSLT_GET_NEW_HANDLER;
 }
 
 static nsresult txFnTextStartRTF(const nsAString& aStr,
                                  txStylesheetCompilerState& aState) {
   TX_RETURN_IF_WHITESPACE(aStr, aState);
 
-  UniquePtr<txInstruction> instr(new txPushRTFHandler);
-  aState.addInstruction(std::move(instr));
+  aState.addInstruction(MakeUnique<txPushRTFHandler>());
 
   aState.mHandlerTable = gTxTemplateHandler;
 
   return NS_XSLT_GET_NEW_HANDLER;
 }
 
 /*
     xsl:when
@@ -2064,41 +1928,33 @@ static nsresult txFnStartWhen(int32_t aN
                               txStylesheetCompilerState& aState) {
   nsresult rv = NS_OK;
 
   UniquePtr<Expr> test;
   rv =
       getExprAttr(aAttributes, aAttrCount, nsGkAtoms::test, true, aState, test);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  UniquePtr<txConditionalGoto> condGoto(
-      new txConditionalGoto(std::move(test), nullptr));
-  rv = aState.pushPtr(condGoto.get(), aState.eConditionalGoto);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  UniquePtr<txInstruction> instr(condGoto.release());
-  aState.addInstruction(std::move(instr));
-
-  return aState.pushHandlerTable(gTxTemplateHandler);
+  aState.pushPtr(aState.addInstruction(
+                     MakeUnique<txConditionalGoto>(std::move(test), nullptr)),
+                 aState.eConditionalGoto);
+
+  aState.pushHandlerTable(gTxTemplateHandler);
+
+  return NS_OK;
 }
 
-static nsresult txFnEndWhen(txStylesheetCompilerState& aState) {
+static void txFnEndWhen(txStylesheetCompilerState& aState) {
   aState.popHandlerTable();
-  UniquePtr<txGoTo> gotoinstr(new txGoTo(nullptr));
-  aState.mChooseGotoList->add(gotoinstr.get());
-
-  UniquePtr<txInstruction> instr(gotoinstr.release());
-  aState.addInstruction(std::move(instr));
+  aState.mChooseGotoList->add(
+      aState.addInstruction(MakeUnique<txGoTo>(nullptr)));
 
   txConditionalGoto* condGoto =
       static_cast<txConditionalGoto*>(aState.popPtr(aState.eConditionalGoto));
-  nsresult rv = aState.addGotoTarget(&condGoto->mTarget);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
+  aState.addGotoTarget(&condGoto->mTarget);
 }
 
 /*
     xsl:with-param
 
     txPushRTFHandler   -- for RTF-parameters
     [children]         /
     txSetParam
@@ -2115,49 +1971,41 @@ static nsresult txFnStartWithParam(int32
                     name);
   NS_ENSURE_SUCCESS(rv, rv);
 
   UniquePtr<Expr> select;
   rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select, false, aState,
                    select);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  UniquePtr<txSetParam> var(new txSetParam(name, std::move(select)));
+  UniquePtr<txSetParam> var = MakeUnique<txSetParam>(name, std::move(select));
   if (var->mValue) {
     // XXX should be gTxErrorHandler?
-    rv = aState.pushHandlerTable(gTxIgnoreHandler);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aState.pushHandlerTable(gTxIgnoreHandler);
   } else {
-    rv = aState.pushHandlerTable(gTxVariableHandler);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aState.pushHandlerTable(gTxVariableHandler);
   }
 
-  rv = aState.pushObject(var.get());
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  Unused << var.release();
+  pushInstruction(aState, std::move(var));
 
   return NS_OK;
 }
 
-static nsresult txFnEndWithParam(txStylesheetCompilerState& aState) {
-  UniquePtr<txSetParam> var(static_cast<txSetParam*>(aState.popObject()));
+static void txFnEndWithParam(txStylesheetCompilerState& aState) {
+  UniquePtr<txSetParam> var = popInstruction<txSetParam>(aState);
   txHandlerTable* prev = aState.mHandlerTable;
   aState.popHandlerTable();
 
   if (prev == gTxVariableHandler) {
     // No children were found.
     NS_ASSERTION(!var->mValue, "There shouldn't be a select-expression here");
     var->mValue = MakeUnique<txLiteralExpr>(u""_ns);
   }
 
-  UniquePtr<txInstruction> instr(var.release());
-  aState.addInstruction(std::move(instr));
-
-  return NS_OK;
+  aState.addInstruction(std::move(var));
 }
 
 /*
     Unknown instruction
 
     [fallbacks]           if one or more xsl:fallbacks are found
     or
     txErrorInstruction    otherwise
@@ -2171,30 +2019,29 @@ static nsresult txFnStartUnknownInstruct
                "bad nesting of unknown-instruction and fallback handlers");
 
   if (aNamespaceID == kNameSpaceID_XSLT && !aState.fcp()) {
     return NS_ERROR_XSLT_PARSE_FAILURE;
   }
 
   aState.mSearchingForFallback = true;
 
-  return aState.pushHandlerTable(gTxFallbackHandler);
+  aState.pushHandlerTable(gTxFallbackHandler);
+
+  return NS_OK;
 }
 
-static nsresult txFnEndUnknownInstruction(txStylesheetCompilerState& aState) {
+static void txFnEndUnknownInstruction(txStylesheetCompilerState& aState) {
   aState.popHandlerTable();
 
   if (aState.mSearchingForFallback) {
-    UniquePtr<txInstruction> instr(new txErrorInstruction());
-    aState.addInstruction(std::move(instr));
+    aState.addInstruction(MakeUnique<txErrorInstruction>());
   }
 
   aState.mSearchingForFallback = false;
-
-  return NS_OK;
 }
 
 /**
  * Table Datas
  */
 
 struct txHandlerTableData {
   txElementHandler mOtherHandler;
--- a/dom/xslt/xslt/txStylesheetCompileHandlers.h
+++ b/dom/xslt/xslt/txStylesheetCompileHandlers.h
@@ -13,17 +13,17 @@
 struct txStylesheetAttr;
 class txStylesheetCompilerState;
 
 using HandleStartFn = nsresult (*)(int32_t aNamespaceID, nsAtom* aLocalName,
                                    nsAtom* aPrefix,
                                    txStylesheetAttr* aAttributes,
                                    int32_t aAttrCount,
                                    txStylesheetCompilerState& aState);
-using HandleEndFn = nsresult (*)(txStylesheetCompilerState& aState);
+using HandleEndFn = void (*)(txStylesheetCompilerState& aState);
 using HandleTextFn = nsresult (*)(const nsAString& aStr,
                                   txStylesheetCompilerState& aState);
 
 struct txElementHandler {
   int32_t mNamespaceID;
   const char* mLocalName;
   HandleStartFn mStartFunction;
   HandleEndFn mEndFunction;
--- a/dom/xslt/xslt/txStylesheetCompiler.cpp
+++ b/dom/xslt/xslt/txStylesheetCompiler.cpp
@@ -156,17 +156,17 @@ nsresult txStylesheetCompiler::startElem
 }
 
 nsresult txStylesheetCompiler::startElementInternal(
     int32_t aNamespaceID, nsAtom* aLocalName, nsAtom* aPrefix,
     txStylesheetAttr* aAttributes, int32_t aAttrCount) {
   nsresult rv = NS_OK;
   int32_t i;
   for (i = mInScopeVariables.Length() - 1; i >= 0; --i) {
-    ++mInScopeVariables[i]->mLevel;
+    ++mInScopeVariables[i].mLevel;
   }
 
   // Update the elementcontext if we have special attributes
   for (i = 0; i < aAttrCount; ++i) {
     txStylesheetAttr* attr = aAttributes + i;
 
     // id
     if (mEmbedStatus == eNeedEmbed && attr->mLocalName == nsGkAtoms::id &&
@@ -208,18 +208,16 @@ nsresult txStylesheetCompiler::startElem
       while (tok.hasMoreTokens()) {
         int32_t namespaceID =
             mElementContext->mMappings->lookupNamespaceWithDefault(
                 tok.nextToken());
 
         if (namespaceID == kNameSpaceID_Unknown)
           return NS_ERROR_XSLT_PARSE_FAILURE;
 
-        // XXX(Bug 1631371) Check if this should use a fallible operation as it
-        // pretended earlier.
         mElementContext->mInstructionNamespaces.AppendElement(namespaceID);
       }
 
       attr->mLocalName = nullptr;
     }
 
     // version
     if ((attr->mNamespaceID == kNameSpaceID_XSLT &&
@@ -269,18 +267,17 @@ nsresult txStylesheetCompiler::startElem
                               (aNamespaceID == kNameSpaceID_XSLT &&
                                attr.mNamespaceID == kNameSpaceID_None))) {
         // XXX ErrorReport: unknown attribute
         return NS_ERROR_XSLT_PARSE_FAILURE;
       }
     }
   }
 
-  rv = pushPtr(const_cast<txElementHandler*>(handler), eElementHandler);
-  NS_ENSURE_SUCCESS(rv, rv);
+  pushPtr(const_cast<txElementHandler*>(handler), eElementHandler);
 
   mElementContext->mDepth++;
 
   return NS_OK;
 }
 
 nsresult txStylesheetCompiler::endElement() {
   if (NS_FAILED(mStatus)) {
@@ -289,30 +286,27 @@ nsresult txStylesheetCompiler::endElemen
     return NS_OK;
   }
 
   nsresult rv = flushCharacters();
   NS_ENSURE_SUCCESS(rv, rv);
 
   int32_t i;
   for (i = mInScopeVariables.Length() - 1; i >= 0; --i) {
-    txInScopeVariable* var = mInScopeVariables[i];
-    if (!--(var->mLevel)) {
-      UniquePtr<txInstruction> instr(new txRemoveVariable(var->mName));
-      addInstruction(std::move(instr));
+    txInScopeVariable& var = mInScopeVariables[i];
+    if (!--(var.mLevel)) {
+      addInstruction(MakeUnique<txRemoveVariable>(var.mName));
 
       mInScopeVariables.RemoveElementAt(i);
-      delete var;
     }
   }
 
   const txElementHandler* handler = const_cast<const txElementHandler*>(
       static_cast<txElementHandler*>(popPtr(eElementHandler)));
-  rv = (handler->mEndFunction)(*this);
-  NS_ENSURE_SUCCESS(rv, rv);
+  (handler->mEndFunction)(*this);
 
   if (!--mElementContext->mDepth) {
     // this will delete the old object
     mElementContext = WrapUnique(static_cast<txElementContext*>(popObject()));
   }
 
   return NS_OK;
 }
@@ -414,20 +408,17 @@ nsresult txStylesheetCompiler::flushChar
 
 nsresult txStylesheetCompiler::ensureNewElementContext() {
   // Do we already have a new context?
   if (!mElementContext->mDepth) {
     return NS_OK;
   }
 
   UniquePtr<txElementContext> context(new txElementContext(*mElementContext));
-  nsresult rv = pushObject(mElementContext.get());
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  Unused << mElementContext.release();
+  pushObject(mElementContext.release());
   mElementContext = std::move(context);
 
   return NS_OK;
 }
 
 nsresult txStylesheetCompiler::maybeDoneCompiling() {
   if (!mDoneWithThisStylesheet || !mChildCompilerList.IsEmpty()) {
     return NS_OK;
@@ -506,92 +497,72 @@ nsresult txStylesheetCompilerState::init
 
     mToplevelIterator =
         txListIterator(&mStylesheet->mRootFrame->mToplevelItems);
     mToplevelIterator.next();  // go to the end of the list
     mIsTopCompiler = true;
   }
 
   mElementContext = MakeUnique<txElementContext>(aStylesheetURI);
-  NS_ENSURE_TRUE(mElementContext->mMappings, NS_ERROR_OUT_OF_MEMORY);
 
   // Push the "old" txElementContext
-  rv = pushObject(0);
-  NS_ENSURE_SUCCESS(rv, rv);
+  pushObject(nullptr);
 
   return NS_OK;
 }
 
 txStylesheetCompilerState::~txStylesheetCompilerState() {
   while (!mObjectStack.isEmpty()) {
     delete popObject();
   }
-
-  int32_t i;
-  for (i = mInScopeVariables.Length() - 1; i >= 0; --i) {
-    delete mInScopeVariables[i];
-  }
 }
 
-nsresult txStylesheetCompilerState::pushHandlerTable(txHandlerTable* aTable) {
-  nsresult rv = pushPtr(mHandlerTable, eHandlerTable);
-  NS_ENSURE_SUCCESS(rv, rv);
-
+void txStylesheetCompilerState::pushHandlerTable(txHandlerTable* aTable) {
+  pushPtr(mHandlerTable, eHandlerTable);
   mHandlerTable = aTable;
-
-  return NS_OK;
 }
 
 void txStylesheetCompilerState::popHandlerTable() {
   mHandlerTable = static_cast<txHandlerTable*>(popPtr(eHandlerTable));
 }
 
-nsresult txStylesheetCompilerState::pushSorter(txPushNewContext* aSorter) {
-  nsresult rv = pushPtr(mSorter, ePushNewContext);
-  NS_ENSURE_SUCCESS(rv, rv);
-
+void txStylesheetCompilerState::pushSorter(txPushNewContext* aSorter) {
+  pushPtr(mSorter, ePushNewContext);
   mSorter = aSorter;
-
-  return NS_OK;
 }
 
 void txStylesheetCompilerState::popSorter() {
   mSorter = static_cast<txPushNewContext*>(popPtr(ePushNewContext));
 }
 
-nsresult txStylesheetCompilerState::pushChooseGotoList() {
-  nsresult rv = pushObject(mChooseGotoList.get());
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  Unused << mChooseGotoList.release();
+void txStylesheetCompilerState::pushChooseGotoList() {
+  pushObject(mChooseGotoList.release());
   mChooseGotoList = MakeUnique<txList>();
-
-  return NS_OK;
 }
 
 void txStylesheetCompilerState::popChooseGotoList() {
   // this will delete the old value
   mChooseGotoList = WrapUnique(static_cast<txList*>(popObject()));
 }
 
-nsresult txStylesheetCompilerState::pushObject(txObject* aObject) {
-  return mObjectStack.push(aObject);
+void txStylesheetCompilerState::pushObject(txObject* aObject) {
+  mObjectStack.push(aObject);
 }
 
 txObject* txStylesheetCompilerState::popObject() {
   return static_cast<txObject*>(mObjectStack.pop());
 }
 
-nsresult txStylesheetCompilerState::pushPtr(void* aPtr, enumStackType aType) {
+void txStylesheetCompilerState::pushPtr(void* aPtr, enumStackType aType) {
 #ifdef TX_DEBUG_STACK
   MOZ_LOG(txLog::xslt, LogLevel::Debug,
           ("pushPtr: 0x%x type %u\n", aPtr, aType));
 #endif
   mTypeStack.AppendElement(aType);
-  return mOtherStack.push(aPtr);
+  mOtherStack.push(aPtr);
 }
 
 void* txStylesheetCompilerState::popPtr(enumStackType aType) {
   if (mTypeStack.IsEmpty()) {
     MOZ_CRASH("Attempt to pop when type stack is empty");
   }
 
   enumStackType type = mTypeStack.PopLastElement();
@@ -622,61 +593,59 @@ nsresult txStylesheetCompilerState::open
 }
 
 void txStylesheetCompilerState::closeInstructionContainer() {
   NS_ASSERTION(mGotoTargetPointers.IsEmpty(),
                "GotoTargets still exists, did you forget to add txReturn?");
   mNextInstrPtr = 0;
 }
 
-void txStylesheetCompilerState::addInstruction(
+txInstruction* txStylesheetCompilerState::addInstruction(
     UniquePtr<txInstruction>&& aInstruction) {
   MOZ_ASSERT(mNextInstrPtr, "adding instruction outside container");
 
   txInstruction* newInstr = aInstruction.get();
 
   *mNextInstrPtr = std::move(aInstruction);
   mNextInstrPtr = &newInstr->mNext;
 
   uint32_t i, count = mGotoTargetPointers.Length();
   for (i = 0; i < count; ++i) {
     *mGotoTargetPointers[i] = newInstr;
   }
   mGotoTargetPointers.Clear();
+
+  return newInstr;
 }
 
 nsresult txStylesheetCompilerState::loadIncludedStylesheet(
     const nsAString& aURI) {
   MOZ_LOG(txLog::xslt, LogLevel::Info,
           ("CompilerState::loadIncludedStylesheet: %s\n",
            NS_LossyConvertUTF16toASCII(aURI).get()));
   if (mStylesheetURI.Equals(aURI)) {
     return NS_ERROR_XSLT_LOAD_RECURSION;
   }
   NS_ENSURE_TRUE(mObserver, NS_ERROR_NOT_IMPLEMENTED);
 
   UniquePtr<txToplevelItem> item(new txDummyItem);
-  NS_ENSURE_TRUE(item, NS_ERROR_OUT_OF_MEMORY);
 
   mToplevelIterator.addBefore(item.release());
 
   // step back to the dummy-item
   mToplevelIterator.previous();
 
   txACompileObserver* observer = static_cast<txStylesheetCompiler*>(this);
 
   RefPtr<txStylesheetCompiler> compiler = new txStylesheetCompiler(
       aURI, mStylesheet, &mToplevelIterator, mReferrerPolicy, observer);
-  NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY);
 
   // step forward before calling the observer in case of syncronous loading
   mToplevelIterator.next();
 
-  // XXX(Bug 1631371) Check if this should use a fallible operation as it
-  // pretended earlier.
   mChildCompilerList.AppendElement(compiler);
 
   nsresult rv =
       mObserver->loadURI(aURI, mStylesheetURI, mReferrerPolicy, compiler);
   if (NS_FAILED(rv)) {
     mChildCompilerList.RemoveElement(compiler);
   }
 
@@ -695,45 +664,34 @@ nsresult txStylesheetCompilerState::load
 
   txListIterator iter(&aFrame->mToplevelItems);
   iter.next();  // go to the end of the list
 
   txACompileObserver* observer = static_cast<txStylesheetCompiler*>(this);
 
   RefPtr<txStylesheetCompiler> compiler = new txStylesheetCompiler(
       aURI, mStylesheet, &iter, mReferrerPolicy, observer);
-  NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY);
 
-  // XXX(Bug 1631371) Check if this should use a fallible operation as it
-  // pretended earlier.
   mChildCompilerList.AppendElement(compiler);
 
   nsresult rv =
       mObserver->loadURI(aURI, mStylesheetURI, mReferrerPolicy, compiler);
   if (NS_FAILED(rv)) {
     mChildCompilerList.RemoveElement(compiler);
   }
 
   return rv;
 }
 
-nsresult txStylesheetCompilerState::addGotoTarget(
-    txInstruction** aTargetPointer) {
-  // XXX(Bug 1631371) Check if this should use a fallible operation as it
-  // pretended earlier, or change the return type to void.
+void txStylesheetCompilerState::addGotoTarget(txInstruction** aTargetPointer) {
   mGotoTargetPointers.AppendElement(aTargetPointer);
-  return NS_OK;
 }
 
-nsresult txStylesheetCompilerState::addVariable(const txExpandedName& aName) {
-  txInScopeVariable* var = new txInScopeVariable(aName);
-  // XXX(Bug 1631371) Check if this should use a fallible operation as it
-  // pretended earlier, or change the return type to void.
-  mInScopeVariables.AppendElement(var);
-  return NS_OK;
+void txStylesheetCompilerState::addVariable(const txExpandedName& aName) {
+  mInScopeVariables.AppendElement(aName);
 }
 
 nsresult txStylesheetCompilerState::resolveNamespacePrefix(nsAtom* aPrefix,
                                                            int32_t& aID) {
   NS_ASSERTION(aPrefix && aPrefix != nsGkAtoms::_empty,
                "caller should handle default namespace ''");
   aID = mElementContext->mMappings->lookupNamespace(aPrefix);
   return (aID != kNameSpaceID_Unknown) ? NS_OK : NS_ERROR_FAILURE;
--- a/dom/xslt/xslt/txStylesheetCompiler.h
+++ b/dom/xslt/xslt/txStylesheetCompiler.h
@@ -20,17 +20,16 @@ extern bool TX_XSLTFunctionAvailable(nsA
 class txHandlerTable;
 class txElementContext;
 class txInstructionContainer;
 class txInstruction;
 class txNamespaceMap;
 class txToplevelItem;
 class txPushNewContext;
 class txStylesheetCompiler;
-class txInScopeVariable;
 
 class txElementContext : public txObject {
  public:
   explicit txElementContext(const nsAString& aBaseURI);
   txElementContext(const txElementContext& aOther);
 
   bool mPreserveWhitespace;
   bool mForwardsCompatibleParsing;
@@ -58,16 +57,24 @@ class txACompileObserver {
 #define TX_DECL_ACOMPILEOBSERVER                                          \
   nsresult loadURI(const nsAString& aUri, const nsAString& aReferrerUri,  \
                    ReferrerPolicy aReferrerPolicy,                        \
                    txStylesheetCompiler* aCompiler) override;             \
   void onDoneCompiling(txStylesheetCompiler* aCompiler, nsresult aResult, \
                        const char16_t* aErrorText = nullptr,              \
                        const char16_t* aParam = nullptr) override;
 
+class txInScopeVariable {
+ public:
+  explicit txInScopeVariable(const txExpandedName& aName)
+      : mName(aName), mLevel(1) {}
+  txExpandedName mName;
+  int32_t mLevel;
+};
+
 class txStylesheetCompilerState : public txIParseContext {
  public:
   explicit txStylesheetCompilerState(txACompileObserver* aObserver);
   ~txStylesheetCompilerState();
 
   nsresult init(const nsAString& aStylesheetURI, ReferrerPolicy aReferrerPolicy,
                 txStylesheet* aStylesheet, txListIterator* aInsertPosition);
 
@@ -82,39 +89,45 @@ class txStylesheetCompilerState : public
     eVariableItem,
     eCopy,
     eInstruction,
     ePushNewContext,
     eConditionalGoto,
     eCheckParam,
     ePushNullTemplateRule
   };
-  nsresult pushHandlerTable(txHandlerTable* aTable);
+  void pushHandlerTable(txHandlerTable* aTable);
   void popHandlerTable();
-  nsresult pushSorter(txPushNewContext* aSorter);
+  void pushSorter(txPushNewContext* aSorter);
   void popSorter();
-  nsresult pushChooseGotoList();
+  void pushChooseGotoList();
   void popChooseGotoList();
-  nsresult pushObject(txObject* aObject);
+  void pushObject(txObject* aObject);
   txObject* popObject();
-  nsresult pushPtr(void* aPtr, enumStackType aType);
+  void pushPtr(void* aPtr, enumStackType aType);
   void* popPtr(enumStackType aType);
 
   // stylesheet functions
   void addToplevelItem(txToplevelItem* aItem);
   nsresult openInstructionContainer(txInstructionContainer* aContainer);
   void closeInstructionContainer();
-  void addInstruction(mozilla::UniquePtr<txInstruction>&& aInstruction);
+  txInstruction* addInstruction(
+      mozilla::UniquePtr<txInstruction>&& aInstruction);
+  template <class T>
+  T* addInstruction(mozilla::UniquePtr<T> aInstruction) {
+    return static_cast<T*>(addInstruction(
+        mozilla::UniquePtr<txInstruction>(std::move(aInstruction))));
+  }
   nsresult loadIncludedStylesheet(const nsAString& aURI);
   nsresult loadImportedStylesheet(const nsAString& aURI,
                                   txStylesheet::ImportFrame* aFrame);
 
   // misc
-  nsresult addGotoTarget(txInstruction** aTargetPointer);
-  nsresult addVariable(const txExpandedName& aName);
+  void addGotoTarget(txInstruction** aTargetPointer);
+  void addVariable(const txExpandedName& aName);
 
   // txIParseContext
   nsresult resolveNamespacePrefix(nsAtom* aPrefix, int32_t& aID) override;
   nsresult resolveFunctionCall(nsAtom* aName, int32_t aID,
                                FunctionCall** aFunction) override;
   bool caseInsensitiveNameTests() override;
 
   /**
@@ -138,17 +151,17 @@ class txStylesheetCompilerState : public
   txPushNewContext* mSorter;
   mozilla::UniquePtr<txList> mChooseGotoList;
   bool mDOE;
   bool mSearchingForFallback;
   uint16_t mDisAllowed;
 
  protected:
   RefPtr<txACompileObserver> mObserver;
-  nsTArray<txInScopeVariable*> mInScopeVariables;
+  nsTArray<txInScopeVariable> mInScopeVariables;
   nsTArray<txStylesheetCompiler*> mChildCompilerList;
   // embed info, target information is the ID
   nsString mTarget;
   enum { eNoEmbed, eNeedEmbed, eInEmbed, eHasEmbed } mEmbedStatus;
   nsString mStylesheetURI;
   bool mIsTopCompiler;
   bool mDoneWithThisStylesheet;
   txStack mObjectStack;
@@ -213,17 +226,9 @@ class txStylesheetCompiler final : priva
   nsresult flushCharacters();
   nsresult ensureNewElementContext();
   nsresult maybeDoneCompiling();
 
   nsString mCharacters;
   nsresult mStatus;
 };
 
-class txInScopeVariable {
- public:
-  explicit txInScopeVariable(const txExpandedName& aName)
-      : mName(aName), mLevel(1) {}
-  txExpandedName mName;
-  int32_t mLevel;
-};
-
 #endif
--- a/dom/xslt/xslt/txToplevelItems.cpp
+++ b/dom/xslt/xslt/txToplevelItems.cpp
@@ -22,22 +22,18 @@ TX_IMPL_GETTYPE(txStripSpaceItem, txTopl
 
 txStripSpaceItem::~txStripSpaceItem() {
   int32_t i, count = mStripSpaceTests.Length();
   for (i = 0; i < count; ++i) {
     delete mStripSpaceTests[i];
   }
 }
 
-nsresult txStripSpaceItem::addStripSpaceTest(
-    txStripSpaceTest* aStripSpaceTest) {
-  // XXX(Bug 1631371) Check if this should use a fallible operation as it
-  // pretended earlier, or change the return type to void.
+void txStripSpaceItem::addStripSpaceTest(txStripSpaceTest* aStripSpaceTest) {
   mStripSpaceTests.AppendElement(aStripSpaceTest);
-  return NS_OK;
 }
 
 TX_IMPL_GETTYPE(txTemplateItem, txToplevelItem::templ)
 
 txTemplateItem::txTemplateItem(UniquePtr<txPattern>&& aMatch,
                                const txExpandedName& aName,
                                const txExpandedName& aMode, double aPrio)
     : mMatch(std::move(aMatch)), mName(aName), mMode(aMode), mPrio(aPrio) {}
--- a/dom/xslt/xslt/txToplevelItems.h
+++ b/dom/xslt/xslt/txToplevelItems.h
@@ -77,17 +77,17 @@ class txDummyItem : public txToplevelIte
 
 // xsl:strip-space and xsl:preserve-space
 class txStripSpaceItem : public txToplevelItem {
  public:
   ~txStripSpaceItem();
 
   TX_DECL_TOPLEVELITEM
 
-  nsresult addStripSpaceTest(txStripSpaceTest* aStripSpaceTest);
+  void addStripSpaceTest(txStripSpaceTest* aStripSpaceTest);
 
   nsTArray<txStripSpaceTest*> mStripSpaceTests;
 };
 
 // xsl:template
 class txTemplateItem : public txInstructionContainer {
  public:
   txTemplateItem(mozilla::UniquePtr<txPattern>&& aMatch,
--- a/dom/xslt/xslt/txXSLTPatterns.cpp
+++ b/dom/xslt/xslt/txXSLTPatterns.cpp
@@ -87,24 +87,20 @@ void txUnionPattern::toString(nsAString&
 
 /*
  * LocationPathPattern
  *
  * a list of step patterns, can start with id or key
  * (dealt with by the parser)
  */
 
-nsresult txLocPathPattern::addStep(txPattern* aPattern, bool isChild) {
+void txLocPathPattern::addStep(txPattern* aPattern, bool isChild) {
   Step* step = mSteps.AppendElement();
-  if (!step) return NS_ERROR_OUT_OF_MEMORY;
-
   step->pattern = WrapUnique(aPattern);
   step->isChild = isChild;
-
-  return NS_OK;
 }
 
 nsresult txLocPathPattern::matches(const txXPathNode& aNode,
                                    txIMatchContext* aContext, bool& aMatched) {
   NS_ASSERTION(mSteps.Length() > 1, "Internal error");
 
   /*
    * The idea is to split up a path into blocks separated by descendant
--- a/dom/xslt/xslt/txXSLTPatterns.h
+++ b/dom/xslt/xslt/txXSLTPatterns.h
@@ -97,33 +97,30 @@ class txPattern {
 #define TX_IMPL_PATTERN_STUBS_NO_SUB_PATTERN(_class)                    \
   txPattern* _class::getSubPatternAt(uint32_t aPos) { return nullptr; } \
   void _class::setSubPatternAt(uint32_t aPos, txPattern* aPattern) {    \
     MOZ_ASSERT_UNREACHABLE("setting bad subexpression index");          \
   }
 
 class txUnionPattern : public txPattern {
  public:
-  nsresult addPattern(txPattern* aPattern) {
-    // XXX(Bug 1631371) Check if this should use a fallible operation as it
-    // pretended earlier, or change the return type to void.
+  void addPattern(txPattern* aPattern) {
     mLocPathPatterns.AppendElement(aPattern);
-    return NS_OK;
   }
 
   TX_DECL_PATTERN;
   Type getType() override;
 
  private:
   txOwningArray<txPattern> mLocPathPatterns;
 };
 
 class txLocPathPattern : public txPattern {
  public:
-  nsresult addStep(txPattern* aPattern, bool isChild);
+  void addStep(txPattern* aPattern, bool isChild);
 
   TX_DECL_PATTERN;
 
  private:
   class Step {
    public:
     mozilla::UniquePtr<txPattern> pattern;
     bool isChild;
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -744,16 +744,31 @@ void APZCTreeManager::SampleForWebRender
             .TransformPoint(ParentLayerPoint(0, 0));
 
     if (Maybe<CompositionPayload> payload = apzc->NotifyScrollSampling()) {
       if (wrBridgeParent && aVsyncId) {
         wrBridgeParent->AddPendingScrollPayload(*payload, *aVsyncId);
       }
     }
 
+    if (StaticPrefs::apz_test_logging_enabled()) {
+      MutexAutoLock lock(mTestDataLock);
+
+      ScrollableLayerGuid guid = apzc->GetGuid();
+      auto it = mTestData.find(guid.mLayersId);
+      if (it != mTestData.end()) {
+        it->second->RecordSampledResult(
+            apzc->GetCurrentAsyncScrollOffsetInCssPixels(
+                AsyncPanZoomController::eForCompositing),
+            (aSampleTime.Time() - TimeStamp::ProcessCreation(nullptr))
+                .ToMicroseconds(),
+            guid.mLayersId, guid.mScrollId);
+      }
+    }
+
     if (Maybe<uint64_t> zoomAnimationId = apzc->GetZoomAnimationId()) {
       // for now we only support zooming on root content APZCs
       MOZ_ASSERT(apzc->IsRootContent());
 
       LayoutDeviceToParentLayerScale zoom = apzc->GetCurrentPinchZoomScale(
           AsyncPanZoomController::eForCompositing);
 
       AsyncTransform asyncVisualTransform = apzc->GetCurrentAsyncTransform(
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -5059,16 +5059,18 @@ void AsyncPanZoomController::NotifyLayer
     mScrollMetadata.SetDisregardedDirection(
         aScrollMetadata.GetDisregardedDirection());
     mScrollMetadata.SetOverscrollBehavior(
         aScrollMetadata.GetOverscrollBehavior());
   }
 
   bool scrollOffsetUpdated = false;
   bool smoothScrollRequested = false;
+  bool didCancelAnimation = false;
+  Maybe<CSSPoint> cumulativeRelativeDelta;
   for (const auto& scrollUpdate : aScrollMetadata.GetScrollUpdates()) {
     APZC_LOG("%p processing scroll update %s\n", this,
              ToString(scrollUpdate).c_str());
     if (!(Metrics().GetScrollGeneration() < scrollUpdate.GetGeneration())) {
       // This is stale, let's ignore it
       APZC_LOG("%p scrollupdate generation stale, dropping\n", this);
       continue;
     }
@@ -5142,17 +5144,16 @@ void AsyncPanZoomController::NotifyLayer
     // eRestore type).
     if (nsLayoutUtils::CanScrollOriginClobberApz(scrollUpdate.GetOrigin()) &&
         aLayerMetrics.GetVisualScrollUpdateType() !=
             FrameMetrics::eMainThread) {
       ignoreVisualUpdate = true;
     }
 
     Maybe<CSSPoint> relativeDelta;
-
     if (scrollUpdate.GetType() == ScrollUpdateType::Relative) {
       APZC_LOG(
           "%p relative updating scroll offset from %s by %s\n", this,
           ToString(Metrics().GetVisualScrollOffset()).c_str(),
           ToString(scrollUpdate.GetDestination() - scrollUpdate.GetSource())
               .c_str());
 
       scrollOffsetUpdated = true;
@@ -5209,30 +5210,47 @@ void AsyncPanZoomController::NotifyLayer
         // We get a NewScrollFrame update for newly created scroll frames. Only
         // if this was not a NewScrollFrame update or the offset changed do we
         // request repaint. This is important so that we don't request repaint
         // for every new content and set a full display port on it.
         scrollOffsetUpdated = true;
       }
     }
 
+    if (relativeDelta) {
+      cumulativeRelativeDelta =
+          !cumulativeRelativeDelta
+              ? relativeDelta
+              : Some(*cumulativeRelativeDelta + *relativeDelta);
+    } else {
+      // If the scroll update is not relative, clobber the cumulative delta,
+      // i.e. later updates win.
+      cumulativeRelativeDelta.reset();
+    }
+
     // If an animation is underway, tell it about the scroll offset update.
     // Some animations can handle some scroll offset updates and continue
     // running. Those that can't will return false, and we cancel them.
     if (ShouldCancelAnimationForScrollUpdate(relativeDelta)) {
       // Cancel the animation (which might also trigger a repaint request)
       // after we update the scroll offset above. Otherwise we can be left
       // in a state where things are out of sync.
       CancelAnimation();
+      didCancelAnimation = true;
     }
   }
 
   if (scrollOffsetUpdated) {
     for (auto& sampledState : mSampledState) {
-      sampledState.UpdateScrollProperties(Metrics());
+      if (!didCancelAnimation && cumulativeRelativeDelta.isSome()) {
+        sampledState.UpdateScrollPropertiesWithRelativeDelta(
+            Metrics(), *cumulativeRelativeDelta);
+      } else {
+        sampledState.UpdateScrollProperties(Metrics());
+      }
     }
 
     // Because of the scroll generation update, any inflight paint requests
     // are going to be ignored by layout, and so mExpectedGeckoMetrics becomes
     // incorrect for the purposes of calculating the LD transform. To correct
     // this we need to update mExpectedGeckoMetrics to be the last thing we
     // know was painted by Gecko.
     mExpectedGeckoMetrics.UpdateFrom(aLayerMetrics);
--- a/gfx/layers/apz/src/SampledAPZCState.cpp
+++ b/gfx/layers/apz/src/SampledAPZCState.cpp
@@ -44,32 +44,34 @@ Maybe<CompositionPayload> SampledAPZCSta
   return std::move(mScrollPayload);
 }
 
 void SampledAPZCState::UpdateScrollProperties(const FrameMetrics& aMetrics) {
   mLayoutViewport = aMetrics.GetLayoutViewport();
   mVisualScrollOffset = aMetrics.GetVisualScrollOffset();
 }
 
+void SampledAPZCState::UpdateScrollPropertiesWithRelativeDelta(
+    const FrameMetrics& aMetrics, const CSSPoint& aRelativeDelta) {
+  mVisualScrollOffset += aRelativeDelta;
+  KeepLayoutViewportEnclosingVisualViewport(aMetrics);
+}
+
 void SampledAPZCState::UpdateZoomProperties(const FrameMetrics& aMetrics) {
   mZoom = aMetrics.GetZoom();
 }
 
 void SampledAPZCState::ClampVisualScrollOffset(const FrameMetrics& aMetrics) {
   // Make sure that we use the local mZoom to do these calculations, because the
   // one on aMetrics might be newer.
   CSSRect scrollRange = FrameMetrics::CalculateScrollRange(
       aMetrics.GetScrollableRect(), aMetrics.GetCompositionBounds(), mZoom);
   mVisualScrollOffset = scrollRange.ClampPoint(mVisualScrollOffset);
 
-  FrameMetrics::KeepLayoutViewportEnclosingVisualViewport(
-      CSSRect(mVisualScrollOffset,
-              FrameMetrics::CalculateCompositedSizeInCssPixels(
-                  aMetrics.GetCompositionBounds(), mZoom)),
-      aMetrics.GetScrollableRect(), mLayoutViewport);
+  KeepLayoutViewportEnclosingVisualViewport(aMetrics);
 }
 
 void SampledAPZCState::ZoomBy(float aScale) { mZoom.scale *= aScale; }
 
 void SampledAPZCState::RemoveFractionalAsyncDelta() {
   // This function is a performance hack. With non-WebRender, having small
   // fractional deltas between the layout offset and scroll offset on
   // container layers can trigger the creation of a temporary surface during
@@ -88,10 +90,19 @@ void SampledAPZCState::RemoveFractionalA
   ParentLayerPoint paintedOffset = mLayoutViewport.TopLeft() * mZoom;
   ParentLayerPoint asyncOffset = mVisualScrollOffset * mZoom;
   if (FuzzyEqualsAdditive(paintedOffset.x, asyncOffset.x, COORDINATE_EPSILON) &&
       FuzzyEqualsAdditive(paintedOffset.y, asyncOffset.y, COORDINATE_EPSILON)) {
     mVisualScrollOffset = mLayoutViewport.TopLeft();
   }
 }
 
+void SampledAPZCState::KeepLayoutViewportEnclosingVisualViewport(
+    const FrameMetrics& aMetrics) {
+  FrameMetrics::KeepLayoutViewportEnclosingVisualViewport(
+      CSSRect(mVisualScrollOffset,
+              FrameMetrics::CalculateCompositedSizeInCssPixels(
+                  aMetrics.GetCompositionBounds(), mZoom)),
+      aMetrics.GetScrollableRect(), mLayoutViewport);
+}
+
 }  // namespace layers
 }  // namespace mozilla
--- a/gfx/layers/apz/src/SampledAPZCState.h
+++ b/gfx/layers/apz/src/SampledAPZCState.h
@@ -24,16 +24,19 @@ class SampledAPZCState {
   bool operator!=(const SampledAPZCState& aOther) const;
 
   CSSRect GetLayoutViewport() const { return mLayoutViewport; }
   CSSPoint GetVisualScrollOffset() const { return mVisualScrollOffset; }
   CSSToParentLayerScale GetZoom() const { return mZoom; }
   Maybe<CompositionPayload> TakeScrollPayload();
 
   void UpdateScrollProperties(const FrameMetrics& aMetrics);
+  void UpdateScrollPropertiesWithRelativeDelta(const FrameMetrics& aMetrics,
+                                               const CSSPoint& aRelativeDelta);
+
   void UpdateZoomProperties(const FrameMetrics& aMetrics);
 
   /**
    * Re-clamp mVisualScrollOffset to the scroll range specified by the provided
    * metrics. This only needs to be called if the scroll offset changes
    * outside of AsyncPanZoomController::SampleCompositedAsyncTransform().
    * It also recalculates mLayoutViewport so that it continues to enclose
    * the visual viewport. This only needs to be called if the
@@ -48,14 +51,18 @@ class SampledAPZCState {
   // in |Metrics()| at the time this class was constructed.
   CSSRect mLayoutViewport;
   CSSPoint mVisualScrollOffset;
   CSSToParentLayerScale mZoom;
   // An optional payload that rides along with the sampled state.
   Maybe<CompositionPayload> mScrollPayload;
 
   void RemoveFractionalAsyncDelta();
+  // A handy wrapper to call
+  // FrameMetrics::KeepLayoutViewportEnclosingVisualViewport with this
+  // SampledAPZCState and the given |aMetrics|.
+  void KeepLayoutViewportEnclosingVisualViewport(const FrameMetrics& aMetrics);
 };
 
 }  // namespace layers
 }  // namespace mozilla
 
 #endif  // mozilla_layers_SampledAPZCState_h
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/test/mochitest/helper_relative_scroll_smoothness.html
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/paint_listener.js"></script>
+<script src="apz_test_utils.js"></script>
+<title>What happens if main thread scrolls?</title>
+<style>
+html, body { margin: 0; }
+
+html {
+  background:
+    repeating-linear-gradient(45deg, transparent 0, transparent 100px, rgba(0,0,0,0.1) 0, rgba(0,0,0,0.1) 200px),
+    repeating-linear-gradient(-45deg, transparent 0, transparent 100px, rgba(0,0,0,0.1) 0, rgba(0,0,0,0.1) 200px),
+    repeating-linear-gradient(to bottom, transparent 0, transparent 500px, rgba(0,0,0,0.4) 0, rgba(0,0,0,0.4) 1000px),
+    repeating-linear-gradient(to bottom, hsl(0, 60%, 80%), hsl(0, 60%, 80%) 200px, hsl(70, 60%, 80%) 0, hsl(70, 60%, 80%) 400px, hsl(140, 60%, 80%) 0, hsl(140, 60%, 80%) 600px, hsl(210, 60%, 80%) 0, hsl(210, 60%, 80%) 800px),
+    white;
+  background-size:
+    283px 283px,
+    283px 283px,
+    100px 1000px,
+    100px 800px;
+}
+
+body {
+  height: 10000px;
+}
+</style>
+
+<script>
+var intervalId;
+// Start periodic content expansions after we get a scroll event triggered by
+// a key press in test() function below, otherwise we may have same scroll
+// offsets caused by this script before we start scrolling.
+window.addEventListener("scroll",  () => {
+  var offset = 0;
+  var initialBodyHeight = 10000;
+  intervalId = setInterval(() => {
+    // "Add content" at the top. We do this by making the body longer and adjusting the background position.
+    offset += 10;
+    document.documentElement.style.backgroundPosition = `0px ${offset}px`;
+    document.body.style.height = `${initialBodyHeight + offset}px`;
+
+    window.scrollBy(0, 10);
+
+    // Simulate some jank.
+    var freezeDurationInMilliseconds = 100;
+    var startTime = Date.now();
+    while (Date.now() - startTime < freezeDurationInMilliseconds) {} // eslint-disable-line no-empty
+  }, 300);
+}, { once: true });
+
+
+function collectRootScrollOffsets() {
+  let data = SpecialPowers.DOMWindowUtils.getCompositorAPZTestData();
+  let sampledResults = data.sampledResults;
+
+  const layersId = SpecialPowers.DOMWindowUtils.getLayersId();
+  const scrollId = SpecialPowers.DOMWindowUtils.getViewId(document.scrollingElement);
+
+  return sampledResults.filter(
+    result => SpecialPowers.wrap(result).layersId == layersId &&
+              SpecialPowers.wrap(result).scrollId == scrollId
+  );
+}
+
+async function test() {
+  // Once this content starts scrolling, it triggers a 100ms jank every 300ms so
+  // sending arrow down keys for 1500ms will cause some jank.
+  const timeAtStart = performance.now();
+  while (performance.now() - timeAtStart < 1500) {
+    synthesizeKey("KEY_ArrowDown");
+    await promiseFrame(window);
+  }
+
+  // Stop the periodic expansions.
+  clearInterval(intervalId);
+
+  const records = collectRootScrollOffsets();
+
+  let previousRecord = { scrollOffsetY: 0, sampledTimeStamp: 0 };
+  for (const record of records) {
+    // Ignore offsets before scrolling.
+    if (record.scrollOffsetY == 0) {
+      continue;
+    }
+    ok(
+      record.scrollOffsetY > previousRecord.scrollOffsetY,
+      "scroll offset should be strictly monotonically increasing" +
+      "previous offset: " + previousRecord.scrollOffsetY +
+      ", offset: " + record.scrollOffsetY
+    );
+    ok(
+      record.sampledTimeStamp > previousRecord.sampledTimeStamp,
+      "sampled time stamp should be strictly monotonically increasing" +
+      "previous timestamp: " + previousRecord.sampledTimeStamp +
+      ", timestamp: " + record.sampledTimeStamp
+    );
+    previousRecord = record;
+  }
+}
+
+waitUntilApzStable()
+.then(test)
+.then(subtestDone, subtestFailed);
+
+</script>
--- a/gfx/layers/apz/test/mochitest/test_group_keyboard.html
+++ b/gfx/layers/apz/test/mochitest/test_group_keyboard.html
@@ -7,16 +7,26 @@
   <script type="application/javascript" src="apz_test_utils.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript">
 
 var subtests = [
   {"file": "helper_key_scroll.html", prefs: [["apz.test.logging_enabled", true],
                                              ["test.events.async.enabled", true]]},
   {"file": "helper_bug1674935.html", prefs: []},
+  {"file": "helper_relative_scroll_smoothness.html",
+   prefs: [
+    ["apz.test.logging_enabled", true],
+    // Use a longer animation duration to avoid the situation that the
+    // animation stops accidentally in between each arrow down key press.
+    // If the situation happens, scroll offsets will not change at the moment.
+    ["general.smoothScroll.lines.durationMaxMS", 1500],
+    ["general.smoothScroll.lines.durationMinMS", 1500]
+   ]
+  },
 ];
 
     if (isKeyApzEnabled()) {
       SimpleTest.waitForExplicitFinish();
       window.onload = function() {
         runSubtestsSeriallyInFreshWindows(subtests)
         .then(SimpleTest.finish, SimpleTest.finishWithFailure);
       };
--- a/gfx/layers/apz/testutil/APZTestData.cpp
+++ b/gfx/layers/apz/testutil/APZTestData.cpp
@@ -46,16 +46,18 @@ struct APZTestDataToJSConverter {
 
   static void ConvertAPZTestData(const APZTestData& aFrom,
                                  dom::APZTestData& aOutTo) {
     ConvertMap(aFrom.mPaints, aOutTo.mPaints.Construct(), ConvertBucket);
     ConvertMap(aFrom.mRepaintRequests, aOutTo.mRepaintRequests.Construct(),
                ConvertBucket);
     ConvertList(aFrom.mHitResults, aOutTo.mHitResults.Construct(),
                 ConvertHitResult);
+    ConvertList(aFrom.mSampledResults, aOutTo.mSampledResults.Construct(),
+                ConvertSampledResult);
     ConvertMap(aFrom.mAdditionalData, aOutTo.mAdditionalData.Construct(),
                ConvertAdditionalDataEntry);
   }
 
   static void ConvertBucket(const SequenceNumber& aKey,
                             const APZTestData::Bucket& aValue,
                             dom::APZBucket& aOutKeyValuePair) {
     aOutKeyValuePair.mSequenceNumber.Construct() = aKey;
@@ -95,16 +97,25 @@ struct APZTestDataToJSConverter {
                       std::numeric_limits<uint16_t>::digits,
                   "CompositorHitTestFlags MAX value have to be less than "
                   "number of bits in uint16_t");
     aOutHitResult.mHitResult.Construct() =
         static_cast<uint16_t>(aResult.result.serialize());
     aOutHitResult.mLayersId.Construct() = aResult.layersId.mId;
     aOutHitResult.mScrollId.Construct() = aResult.scrollId;
   }
+
+  static void ConvertSampledResult(const APZTestData::SampledResult& aResult,
+                                   dom::APZSampledResult& aOutSampledResult) {
+    aOutSampledResult.mScrollOffsetX.Construct() = aResult.scrollOffset.x;
+    aOutSampledResult.mScrollOffsetY.Construct() = aResult.scrollOffset.y;
+    aOutSampledResult.mLayersId.Construct() = aResult.layersId.mId;
+    aOutSampledResult.mScrollId.Construct() = aResult.scrollId;
+    aOutSampledResult.mSampledTimeStamp.Construct() = aResult.sampledTimeStamp;
+  }
 };
 
 bool APZTestData::ToJS(JS::MutableHandleValue aOutValue,
                        JSContext* aContext) const {
   dom::APZTestData result;
   APZTestDataToJSConverter::ConvertAPZTestData(*this, result);
   return dom::ToJSValue(aContext, result, aOutValue);
 }
--- a/gfx/layers/apz/testutil/APZTestData.h
+++ b/gfx/layers/apz/testutil/APZTestData.h
@@ -4,17 +4,18 @@
  * 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_layers_APZTestData_h
 #define mozilla_layers_APZTestData_h
 
 #include <map>
 
-#include "nsDebug.h"  // for NS_WARNING
+#include "nsDebug.h"                // for NS_WARNING
+#include "nsDOMNavigationTiming.h"  // for DOMHighResTimeStamp
 #include "nsTArray.h"
 #include "mozilla/Assertions.h"       // for MOZ_ASSERT
 #include "mozilla/DebugOnly.h"        // for DebugOnly
 #include "mozilla/GfxMessageUtils.h"  // for ParamTraits specializations
 #include "mozilla/StaticPrefs_apz.h"
 #include "mozilla/ToString.h"  // for ToString
 #include "mozilla/gfx/CompositorHitTestInfo.h"
 #include "mozilla/layers/LayersMessageUtils.h"  // for ParamTraits specializations
@@ -74,16 +75,22 @@ class APZTestData {
                                     const std::string& aValue) {
     LogTestDataImpl(mRepaintRequests, aSequenceNumber, aScrollId, aKey, aValue);
   }
   void RecordHitResult(const ScreenPoint& aPoint,
                        const mozilla::gfx::CompositorHitTestInfo& aResult,
                        const LayersId& aLayersId, const ViewID& aScrollId) {
     mHitResults.AppendElement(HitResult{aPoint, aResult, aLayersId, aScrollId});
   }
+  void RecordSampledResult(const CSSPoint& aScrollOffset,
+                           DOMHighResTimeStamp aSampledTimeStamp,
+                           const LayersId& aLayersId, const ViewID& aScrollId) {
+    mSampledResults.AppendElement(
+        SampledResult{aScrollOffset, aSampledTimeStamp, aLayersId, aScrollId});
+  }
   void RecordAdditionalData(const std::string& aKey,
                             const std::string& aValue) {
     mAdditionalData[aKey] = aValue;
   }
 
   // Convert this object to a JS representation.
   bool ToJS(JS::MutableHandleValue aOutValue, JSContext* aContext) const;
 
@@ -96,21 +103,28 @@ class APZTestData {
   typedef std::map<SequenceNumber, Bucket> DataStoreBase;
   struct DataStore : DataStoreBase {};
   struct HitResult {
     ScreenPoint point;
     mozilla::gfx::CompositorHitTestInfo result;
     LayersId layersId;
     ViewID scrollId;
   };
+  struct SampledResult {
+    CSSPoint scrollOffset;
+    DOMHighResTimeStamp sampledTimeStamp;
+    LayersId layersId;
+    ViewID scrollId;
+  };
 
  private:
   DataStore mPaints;
   DataStore mRepaintRequests;
   CopyableTArray<HitResult> mHitResults;
+  CopyableTArray<SampledResult> mSampledResults;
   // Additional free-form data that's not grouped paint or scroll frame.
   std::map<std::string, std::string> mAdditionalData;
 
   void LogTestDataImpl(DataStore& aDataStore, SequenceNumber aSequenceNumber,
                        ViewID aScrollId, const std::string& aKey,
                        const std::string& aValue) {
     auto bucketIterator = aDataStore.find(aSequenceNumber);
     if (bucketIterator == aDataStore.end()) {
@@ -165,24 +179,26 @@ namespace IPC {
 template <>
 struct ParamTraits<mozilla::layers::APZTestData> {
   typedef mozilla::layers::APZTestData paramType;
 
   static void Write(Message* aMsg, const paramType& aParam) {
     WriteParam(aMsg, aParam.mPaints);
     WriteParam(aMsg, aParam.mRepaintRequests);
     WriteParam(aMsg, aParam.mHitResults);
+    WriteParam(aMsg, aParam.mSampledResults);
     WriteParam(aMsg, aParam.mAdditionalData);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter,
                    paramType* aResult) {
     return (ReadParam(aMsg, aIter, &aResult->mPaints) &&
             ReadParam(aMsg, aIter, &aResult->mRepaintRequests) &&
             ReadParam(aMsg, aIter, &aResult->mHitResults) &&
+            ReadParam(aMsg, aIter, &aResult->mSampledResults) &&
             ReadParam(aMsg, aIter, &aResult->mAdditionalData));
   }
 };
 
 template <>
 struct ParamTraits<mozilla::layers::APZTestData::ScrollFrameData>
     : ParamTraits<mozilla::layers::APZTestData::ScrollFrameDataBase> {};
 
@@ -209,11 +225,31 @@ struct ParamTraits<mozilla::layers::APZT
                    paramType* aResult) {
     return (ReadParam(aMsg, aIter, &aResult->point) &&
             ReadParam(aMsg, aIter, &aResult->result) &&
             ReadParam(aMsg, aIter, &aResult->layersId) &&
             ReadParam(aMsg, aIter, &aResult->scrollId));
   }
 };
 
+template <>
+struct ParamTraits<mozilla::layers::APZTestData::SampledResult> {
+  typedef mozilla::layers::APZTestData::SampledResult paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam) {
+    WriteParam(aMsg, aParam.scrollOffset);
+    WriteParam(aMsg, aParam.sampledTimeStamp);
+    WriteParam(aMsg, aParam.layersId);
+    WriteParam(aMsg, aParam.scrollId);
+  }
+
+  static bool Read(const Message* aMsg, PickleIterator* aIter,
+                   paramType* aResult) {
+    return (ReadParam(aMsg, aIter, &aResult->scrollOffset) &&
+            ReadParam(aMsg, aIter, &aResult->sampledTimeStamp) &&
+            ReadParam(aMsg, aIter, &aResult->layersId) &&
+            ReadParam(aMsg, aIter, &aResult->scrollId));
+  }
+};
+
 }  // namespace IPC
 
 #endif /* mozilla_layers_APZTestData_h */
--- a/js/moz.configure
+++ b/js/moz.configure
@@ -1121,8 +1121,30 @@ set_define(
     "ENABLE_WASM_EXCEPTIONS", depends_if("--enable-wasm-exceptions")(lambda x: True)
 )
 
 set_define(
     "_WASI_EMULATED_PROCESS_CLOCKS",
     True,
     when=depends(target)(lambda t: t.os == "WASI"),
 )
+
+# Enable change-array-by-copy
+# ===================================================
+def use_change_array_by_copy():
+    return False
+
+
+option(
+    "--enable-change-array-by-copy",
+    default=use_change_array_by_copy(),
+    help="{Enable|Disable} change-array-by-copy method pref/command-line option (disabled by default)",
+)
+
+
+@depends("--enable-change-array-by-copy")
+def enable_change_array_by_copy(value):
+    if value:
+        return True
+
+
+set_config("ENABLE_CHANGE_ARRAY_BY_COPY", enable_change_array_by_copy)
+set_define("ENABLE_CHANGE_ARRAY_BY_COPY", enable_change_array_by_copy)
--- a/js/public/ContextOptions.h
+++ b/js/public/ContextOptions.h
@@ -46,16 +46,19 @@ class JS_PUBLIC_API ContextOptions {
         strictMode_(false),
 #ifdef JS_ENABLE_SMOOSH
         trackNotImplemented_(false),
         trySmoosh_(false),
 #endif
         fuzzing_(false),
         privateClassFields_(false),
         privateClassMethods_(false),
+ #ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+        changeArrayByCopy_(false),
+ #endif
         ergonomicBrandChecks_(false) {
   }
   // clang-format on
 
   bool asmJS() const { return asmJS_; }
   ContextOptions& setAsmJS(bool flag) {
     asmJS_ = flag;
     return *this;
@@ -156,16 +159,24 @@ class JS_PUBLIC_API ContextOptions {
   }
 
   bool ergonomicBrandChecks() const { return ergonomicBrandChecks_; }
   ContextOptions& setErgnomicBrandChecks(bool enabled) {
     ergonomicBrandChecks_ = enabled;
     return *this;
   }
 
+#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+  bool changeArrayByCopy() const { return changeArrayByCopy_; }
+  ContextOptions& setChangeArrayByCopy(bool enabled) {
+    changeArrayByCopy_ = enabled;
+    return *this;
+  }
+#endif
+
   bool classStaticBlocks() const { return classStaticBlocks_; }
   ContextOptions& setClassStaticBlocks(bool enabled) {
     classStaticBlocks_ = enabled;
     return *this;
   }
 
   // Override to allow disabling the eval restriction security checks for
   // this context.
@@ -271,16 +282,19 @@ class JS_PUBLIC_API ContextOptions {
   bool strictMode_ : 1;
 #ifdef JS_ENABLE_SMOOSH
   bool trackNotImplemented_ : 1;
   bool trySmoosh_ : 1;
 #endif
   bool fuzzing_ : 1;
   bool privateClassFields_ : 1;
   bool privateClassMethods_ : 1;
+#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+  bool changeArrayByCopy_ : 1;
+#endif
   bool ergonomicBrandChecks_ : 1;
   bool classStaticBlocks_ : 1;
 };
 
 JS_PUBLIC_API ContextOptions& ContextOptionsRef(JSContext* cx);
 
 }  // namespace JS
 
--- a/js/public/friend/ErrorNumbers.msg
+++ b/js/public/friend/ErrorNumbers.msg
@@ -52,16 +52,17 @@
 // clang-format off
 MSG_DEF(JSMSG_NOT_AN_ERROR,            0, JSEXN_ERR, "<Error #0 is reserved>")
 MSG_DEF(JSMSG_NOT_DEFINED,             1, JSEXN_REFERENCEERR, "{0} is not defined")
 MSG_DEF(JSMSG_MORE_ARGS_NEEDED,        4, JSEXN_TYPEERR, "{0}: At least {1} argument{2} required, but only {3} passed")
 MSG_DEF(JSMSG_INCOMPATIBLE_PROTO,      3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}")
 MSG_DEF(JSMSG_INCOMPATIBLE_PROTO2,     3, JSEXN_TYPEERR, "{0}.prototype[{1}] called on incompatible {2}")
 MSG_DEF(JSMSG_NO_CONSTRUCTOR,          1, JSEXN_TYPEERR, "{0} has no constructor")
 MSG_DEF(JSMSG_BAD_SORT_ARG,            0, JSEXN_TYPEERR, "invalid Array.prototype.sort argument")
+MSG_DEF(JSMSG_BAD_WITHSORTED_ARG,      0, JSEXN_TYPEERR, "non-function passed to Array.prototype.withSorted")
 MSG_DEF(JSMSG_READ_ONLY,               1, JSEXN_TYPEERR, "{0} is read-only")
 MSG_DEF(JSMSG_CANT_DELETE,             1, JSEXN_TYPEERR, "property {0} is non-configurable and can't be deleted")
 MSG_DEF(JSMSG_CANT_TRUNCATE_ARRAY,     0, JSEXN_TYPEERR, "can't delete non-configurable array element")
 MSG_DEF(JSMSG_NOT_FUNCTION,            1, JSEXN_TYPEERR, "{0} is not a function")
 MSG_DEF(JSMSG_NOT_CONSTRUCTOR,         1, JSEXN_TYPEERR, "{0} is not a constructor")
 MSG_DEF(JSMSG_BOGUS_CONSTRUCTOR,       1, JSEXN_TYPEERR, "{0} constructor can't be used directly")
 MSG_DEF(JSMSG_CANT_CONVERT_TO,         2, JSEXN_TYPEERR, "can't convert {0} to {1}")
 MSG_DEF(JSMSG_TOPRIMITIVE_NOT_CALLABLE, 2, JSEXN_TYPEERR, "can't convert {0} to {1}: its [Symbol.toPrimitive] property is not a function")
--- a/js/src/builtin/Array.cpp
+++ b/js/src/builtin/Array.cpp
@@ -23,16 +23,17 @@
 #include "gc/Allocator.h"
 #include "jit/InlinableNatives.h"
 #include "js/CallAndConstruct.h"  // JS::Construct, JS::IsCallable, JS::IsConstructor
 #include "js/Class.h"
 #include "js/Conversions.h"
 #include "js/experimental/JitInfo.h"  // JSJitGetterOp, JSJitInfo
 #include "js/friend/ErrorMessages.h"  // js::GetErrorMessage, JSMSG_*
 #include "js/friend/StackLimits.h"    // js::AutoCheckRecursionLimit
+#include "js/PropertyAndElement.h"    // JS_DefineFunctions
 #include "js/PropertySpec.h"
 #include "util/Poison.h"
 #include "util/StringBuffer.h"
 #include "util/Text.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/Interpreter.h"
 #include "vm/Iteration.h"
 #include "vm/JSAtom.h"
@@ -2764,16 +2765,79 @@ static bool CopyArrayElements(JSContext*
 
     if (!hole && !DefineArrayElement(cx, result, i, value)) {
       return false;
     }
   }
   return true;
 }
 
+/* Helpers for array_splice_impl() and array_with_spliced()
+ *
+ * Initialize variables common to splice() and withSpliced()
+ * GetActualStart() returns the index at which to start deleting elements.
+ * GetItemCount() returns the number of new elements being added.
+ * GetActualDeleteCount:() returns the number of elements being deleted.
+ *
+ */
+static bool GetActualStart(JSContext* cx, const CallArgs& args, uint64_t len,
+                           uint64_t* result) {
+  double relativeStart;
+  if (!ToInteger(cx, args.get(0), &relativeStart)) {
+    return false;
+  }
+  if (relativeStart < 0) {
+    *result = uint64_t(std::max(double(len) + relativeStart, 0.0));
+  } else {
+    *result = uint64_t(std::min(relativeStart, double(len)));
+  }
+  return true;
+}
+
+static uint32_t GetItemCount(const CallArgs& args) {
+  if (args.length() < 2) {
+    return 0;
+  }
+  return (args.length() - 2);
+}
+
+static bool GetActualDeleteCount(JSContext* cx, const CallArgs& args,
+                                 HandleObject obj, uint64_t len,
+                                 uint64_t actualStart, uint64_t itemCount,
+                                 uint64_t* result) {
+  if (args.length() < 1) {
+    *result = 0;
+  } else if (args.length() < 2) {
+    *result = len - actualStart;
+  } else {
+    double deleteCount;
+    if (!ToInteger(cx, args.get(1), &deleteCount)) {
+      return false;
+    }
+    *result = uint64_t(std::min(std::max(0.0, deleteCount),
+                                double(len) - double(actualStart)));
+
+    if (double(len + itemCount - *result) >= DOUBLE_INTEGRAL_PRECISION_LIMIT) {
+      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+                                JSMSG_TOO_LONG_ARRAY);
+      return false;
+    }
+  }
+  MOZ_ASSERT(actualStart + *result <= len);
+
+  if (IsArraySpecies(cx, obj)) {
+    if (*result > UINT32_MAX) {
+      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+                                JSMSG_BAD_ARRAY_LENGTH);
+      return false;
+    }
+  }
+  return true;
+}
+
 static bool array_splice_impl(JSContext* cx, unsigned argc, Value* vp,
                               bool returnValueIsUsed) {
   AutoGeckoProfilerEntry pseudoFrame(
       cx, "Array.prototype.splice", JS::ProfilingCategoryPair::JS,
       uint32_t(ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
   CallArgs args = CallArgsFromVp(argc, vp);
 
   /* Step 1. */
@@ -2783,206 +2847,167 @@ static bool array_splice_impl(JSContext*
   }
 
   /* Step 2. */
   uint64_t len;
   if (!GetLengthPropertyInlined(cx, obj, &len)) {
     return false;
   }
 
-  /* Step 3. */
-  double relativeStart;
-  if (!ToInteger(cx, args.get(0), &relativeStart)) {
-    return false;
-  }
-
-  /* Step 4. */
+  /* Steps 3-6. */
+  /* actualStart is the index after which elements will be
+     deleted and/or new elements will be added */
   uint64_t actualStart;
-  if (relativeStart < 0) {
-    actualStart = std::max(len + relativeStart, 0.0);
-  } else {
-    actualStart = std::min(relativeStart, double(len));
-  }
-
-  /* Step 5. */
+  if (!GetActualStart(cx, args, len, &actualStart)) {
+    return false;
+  }
+
+  /* Steps 7-10.*/
+  /* itemCount is the number of elements being added */
+  uint32_t itemCount = GetItemCount(args);
+
+  /* actualDeleteCount is the number of elements being deleted */
   uint64_t actualDeleteCount;
-  if (args.length() == 0) {
-    /* Step 5.b. */
-    actualDeleteCount = 0;
-  } else if (args.length() == 1) {
-    /* Step 6.b. */
-    actualDeleteCount = len - actualStart;
-  } else {
-    /* Steps 7.b. */
-    double deleteCountDouble;
-    if (!ToInteger(cx, args[1], &deleteCountDouble)) {
-      return false;
-    }
-
-    /* Step 7.c. */
-    actualDeleteCount =
-        std::min(std::max(deleteCountDouble, 0.0), double(len - actualStart));
-
-    /* Step 8. */
-    uint32_t insertCount = args.length() - 2;
-    if (len + insertCount - actualDeleteCount >=
-        DOUBLE_INTEGRAL_PRECISION_LIMIT) {
-      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
-                                JSMSG_TOO_LONG_ARRAY);
-      return false;
-    }
-  }
-
-  MOZ_ASSERT(actualStart + actualDeleteCount <= len);
+  if (!GetActualDeleteCount(cx, args, obj, len, actualStart, itemCount,
+                            &actualDeleteCount)) {
+    return false;
+  }
 
   RootedObject arr(cx);
   if (IsArraySpecies(cx, obj)) {
-    if (actualDeleteCount > UINT32_MAX) {
-      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
-                                JSMSG_BAD_ARRAY_LENGTH);
-      return false;
-    }
     uint32_t count = uint32_t(actualDeleteCount);
 
     if (CanOptimizeForDenseStorage<ArrayAccess::Read>(obj,
                                                       actualStart + count)) {
       MOZ_ASSERT(actualStart <= UINT32_MAX,
                  "if actualStart + count <= UINT32_MAX, then actualStart <= "
                  "UINT32_MAX");
       if (returnValueIsUsed) {
-        /* Steps 9-12. */
+        /* Steps 11-13. */
         arr = CopyDenseArrayElements(cx, obj.as<NativeObject>(),
                                      uint32_t(actualStart), count);
         if (!arr) {
           return false;
         }
       }
     } else {
-      /* Step 9. */
+      /* Step 11. */
       arr = NewDenseFullyAllocatedArray(cx, count);
       if (!arr) {
         return false;
       }
 
-      /* Steps 10-11. */
+      /* Steps 12-13. */
       if (!CopyArrayElements(cx, obj, actualStart, count,
                              arr.as<ArrayObject>())) {
         return false;
       }
-
-      /* Step 12 (implicit). */
     }
   } else {
-    /* Steps 9. */
+    /* Step 11. */
     if (!ArraySpeciesCreate(cx, obj, actualDeleteCount, &arr)) {
       return false;
     }
 
-    /* Steps 10, 11, 11.d. */
+    /* Steps 12-13. */
     RootedValue fromValue(cx);
     for (uint64_t k = 0; k < actualDeleteCount; k++) {
-      /* Step 11.a (implicit). */
-
       if (!CheckForInterrupt(cx)) {
         return false;
       }
 
-      /* Steps 11.b, 11.c.i. */
+      /* Steps 13.b, 13.c.i. */
       bool hole;
       if (!HasAndGetElement(cx, obj, actualStart + k, &hole, &fromValue)) {
         return false;
       }
 
-      /* Step 11.c. */
+      /* Step 13.c. */
       if (!hole) {
-        /* Step 11.c.ii. */
+        /* Step 13.c.ii. */
         if (!DefineArrayElement(cx, arr, k, fromValue)) {
           return false;
         }
       }
     }
 
-    /* Step 12. */
+    /* Step 14. */
     if (!SetLengthProperty(cx, arr, actualDeleteCount)) {
       return false;
     }
   }
 
-  /* Step 14. */
-  uint32_t itemCount = (args.length() >= 2) ? (args.length() - 2) : 0;
+  /* Step 15. */
   uint64_t finalLength = len - actualDeleteCount + itemCount;
 
   if (itemCount < actualDeleteCount) {
-    /* Step 15: the array is being shrunk. */
+    /* Step 16: the array is being shrunk. */
     uint64_t sourceIndex = actualStart + actualDeleteCount;
     uint64_t targetIndex = actualStart + itemCount;
 
     if (CanOptimizeForDenseStorage<ArrayAccess::Write>(obj, len)) {
       MOZ_ASSERT(sourceIndex <= len && targetIndex <= len && len <= UINT32_MAX,
                  "sourceIndex and targetIndex are uint32 array indices");
       MOZ_ASSERT(finalLength < len, "finalLength is strictly less than len");
       MOZ_ASSERT(obj->is<NativeObject>());
 
-      /* Steps 15.a-b. */
+      /* Step 16.b. */
       HandleArrayObject arr = obj.as<ArrayObject>();
       if (targetIndex != 0 || !arr->tryShiftDenseElements(sourceIndex)) {
         arr->moveDenseElements(uint32_t(targetIndex), uint32_t(sourceIndex),
                                uint32_t(len - sourceIndex));
       }
 
-      /* Steps 15.c-d. */
+      /* Steps 20. */
       SetInitializedLength(cx, arr, finalLength);
     } else {
       /*
        * This is all very slow if the length is very large. We don't yet
        * have the ability to iterate in sorted order, so we just do the
        * pessimistic thing and let CheckForInterrupt handle the
        * fallout.
        */
 
-      /* Steps 15.a-b. */
+      /* Step 16. */
       RootedValue fromValue(cx);
       for (uint64_t from = sourceIndex, to = targetIndex; from < len;
            from++, to++) {
         /* Steps 15.b.i-ii (implicit). */
 
         if (!CheckForInterrupt(cx)) {
           return false;
         }
 
-        /* Steps 15.b.iii, 15.b.iv.1. */
+        /* Steps 16.b.iii-v */
         bool hole;
         if (!HasAndGetElement(cx, obj, from, &hole, &fromValue)) {
           return false;
         }
 
-        /* Steps 15.b.iv. */
         if (hole) {
-          /* Steps 15.b.v.1. */
           if (!DeletePropertyOrThrow(cx, obj, to)) {
             return false;
           }
         } else {
-          /* Step 15.b.iv.2. */
           if (!SetArrayElement(cx, obj, to, fromValue)) {
             return false;
           }
         }
       }
 
-      /* Steps 15.c-d. */
+      /* Step 16d. */
       if (!DeletePropertiesOrThrow(cx, obj, len, finalLength)) {
         return false;
       }
     }
   } else if (itemCount > actualDeleteCount) {
     MOZ_ASSERT(actualDeleteCount <= UINT32_MAX);
     uint32_t deleteCount = uint32_t(actualDeleteCount);
 
-    /* Step 16. */
+    /* Step 17. */
 
     // Fast path for when we can simply extend and move the dense elements.
     auto extendElements = [len, itemCount, deleteCount](JSContext* cx,
                                                         HandleObject obj) {
       if (!obj->is<ArrayObject>()) {
         return DenseElementResult::Incomplete;
       }
       if (len > UINT32_MAX) {
@@ -3028,85 +3053,290 @@ static bool array_splice_impl(JSContext*
                  "and |actualStart <= len - actualDeleteCount| are both true");
       uint32_t start = uint32_t(actualStart);
       uint32_t length = uint32_t(len);
 
       HandleArrayObject arr = obj.as<ArrayObject>();
       arr->moveDenseElements(start + itemCount, start + deleteCount,
                              length - (start + deleteCount));
 
-      /* Steps 16.a-b. */
+      /* Step 20. */
       SetInitializedLength(cx, arr, finalLength);
     } else {
       MOZ_ASSERT(res == DenseElementResult::Incomplete);
 
       RootedValue fromValue(cx);
       for (uint64_t k = len - actualDeleteCount; k > actualStart; k--) {
         if (!CheckForInterrupt(cx)) {
           return false;
         }
 
-        /* Step 16.b.i. */
+        /* Step 17.b.i. */
         uint64_t from = k + actualDeleteCount - 1;
 
-        /* Step 16.b.ii. */
+        /* Step 17.b.ii. */
         uint64_t to = k + itemCount - 1;
 
-        /* Steps 16.b.iii, 16.b.iv.1. */
+        /* Steps 17.b.iii, 17.b.iv.1. */
         bool hole;
         if (!HasAndGetElement(cx, obj, from, &hole, &fromValue)) {
           return false;
         }
 
-        /* Steps 16.b.iv. */
+        /* Steps 17.b.iv. */
         if (hole) {
-          /* Step 16.b.v.1. */
+          /* Step 17.b.v.1. */
           if (!DeletePropertyOrThrow(cx, obj, to)) {
             return false;
           }
         } else {
-          /* Step 16.b.iv.2. */
+          /* Step 17.b.iv.2. */
           if (!SetArrayElement(cx, obj, to, fromValue)) {
             return false;
           }
         }
       }
     }
   }
 
-  /* Step 13 (reordered). */
   Value* items = args.array() + 2;
 
-  /* Steps 17-18. */
+  /* Steps 18-19. */
   if (!SetArrayElements(cx, obj, actualStart, itemCount, items)) {
     return false;
   }
 
-  /* Step 19. */
-  if (!SetLengthProperty(cx, obj, finalLength)) {
-    return false;
-  }
-
   /* Step 20. */
+  if (!SetLengthProperty(cx, obj, finalLength)) {
+    return false;
+  }
+
+  /* Step 21. */
   if (returnValueIsUsed) {
     args.rval().setObject(*arr);
   }
 
   return true;
 }
 
 /* ES 2016 draft Mar 25, 2016 22.1.3.26. */
 static bool array_splice(JSContext* cx, unsigned argc, Value* vp) {
   return array_splice_impl(cx, argc, vp, true);
 }
 
 static bool array_splice_noRetVal(JSContext* cx, unsigned argc, Value* vp) {
   return array_splice_impl(cx, argc, vp, false);
 }
 
+#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+
+static ArrayObject* NewDenseArray(JSContext* cx, const CallArgs& args,
+                                  uint64_t len) {
+  RootedObject proto(cx);
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Array, &proto)) {
+    return nullptr;
+  }
+  return NewDensePartlyAllocatedArrayWithProto(cx, len, proto);
+}
+
+/* Proposal
+ * https://github.com/tc39/proposal-change-array-by-copy
+ * Array.prototype.withSpliced()
+ */
+static bool array_with_spliced(JSContext* cx, unsigned argc, Value* vp) {
+  /* Currently doesn't use the optimizations array_splice() uses for
+   * dense arrays
+   */
+
+  AutoGeckoProfilerEntry pseudoFrame(
+      cx, "Array.prototype.withSpliced", JS::ProfilingCategoryPair::JS,
+      uint32_t(ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
+
+  CallArgs args = CallArgsFromVp(argc, vp);
+
+  /* Step 1. */
+  RootedObject obj(cx, ToObject(cx, args.thisv()));
+  if (!obj) {
+    return false;
+  }
+
+  /* Step 2. */
+  uint64_t len;
+  if (!GetLengthPropertyInlined(cx, obj, &len)) {
+    return false;
+  }
+
+  /* Steps 3-6. */
+  /* actualStart is the index after which elements will be
+   * deleted and/or new elements will be added
+   */
+  uint64_t actualStart;
+  if (!GetActualStart(cx, args, len, &actualStart)) {
+    return false;
+  }
+
+  // insertCount is the number of elements being added
+  uint32_t insertCount = GetItemCount(args);
+
+  // actualDeleteCount is the number of elements being deleted
+  uint64_t actualDeleteCount;
+  if (!GetActualDeleteCount(cx, args, obj, len, actualStart, insertCount,
+                            &actualDeleteCount)) {
+    return false;
+  }
+
+  /* Step 10. */
+  uint64_t newLen = len + insertCount - actualDeleteCount;
+
+  /* Step 11. */
+  RootedObject A(cx, NewDenseArray(cx, args, newLen));
+  if (!A) {
+    return false;
+  }
+
+  /* Steps 12-13. */
+  // Copy everything before start
+  uint64_t k = 0;
+  while (k < actualStart) {
+    RootedValue kValue(cx);
+    if (!GetArrayElement(cx, obj, k, &kValue)) {
+      return false;
+    }
+    if (!SetArrayElement(cx, A, k, kValue)) {
+      return false;
+    }
+    k++;
+  }
+
+  // result array now contains all elements before start
+
+  /* Steps 14-15.*/
+  // Copy new items
+  Value* items = args.array() + 2;
+
+  if (!SetArrayElements(cx, A, actualStart, insertCount, items)) {
+    return false;
+  }
+  k += insertCount;
+
+  /* Step 16. */
+  // Copy items after new items
+  while (k < newLen) {
+    uint64_t from = k + actualDeleteCount - insertCount;
+    RootedValue fromValue(cx);
+    if (!GetArrayElement(cx, obj, from, &fromValue)) {
+      return false;
+    }
+    if (!SetArrayElement(cx, A, k, fromValue)) {
+      return false;
+    }
+    k++;
+  }
+
+  /* Step 17. */
+  args.rval().setObject(*A);
+
+  return true;
+}
+
+bool IsIntegralNumber(JSContext* cx, HandleValue v, bool* result) {
+  double d;
+  if (!ToNumber(cx, v, &d)) {
+    return false;
+  }
+
+  if (mozilla::IsNaN(d) || !mozilla::IsFinite(d)) {
+    *result = false;
+    return true;
+  }
+
+  double integer = trunc(d);
+  *result = d - integer == 0;
+  return true;
+}
+
+/* Proposal
+ * https://github.com/tc39/proposal-change-array-by-copy
+ * Array.prototype.withAt()
+ */
+static bool array_with_at(JSContext* cx, unsigned argc, Value* vp) {
+  CallArgs args = CallArgsFromVp(argc, vp);
+
+  /* Step 1. */
+  RootedObject obj(cx, ToObject(cx, args.thisv()));
+  if (!obj) {
+    return false;
+  }
+
+  /* Step 2. */
+  uint64_t len;
+  if (!GetLengthPropertyInlined(cx, obj, &len)) {
+    return false;
+  }
+
+  /* Step 3. */
+  int64_t index;
+  bool result;
+  if (!IsIntegralNumber(cx, args.get(0), &result)) {
+    return false;
+  }
+
+  if (!result) {
+    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
+    return false;
+  }
+  if (!ToInt64(cx, args.get(0), &index)) {
+    return false;
+  }
+  /* Step 4. */
+  if (index >= int64_t(len)) {
+    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
+    return false;
+  }
+
+  /* Steps 5-6. */
+  int64_t actualIndex = index;
+  if (index < 0) {
+    actualIndex = int64_t(len + index);
+  }
+
+  /* Step 7. */
+  if (actualIndex < 0) {
+    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
+    return false;
+  }
+  // actualIndex must be non-negative at this point
+
+  /* Step 8 */
+  RootedObject A(cx, NewDenseArray(cx, args, len));
+  if (!A) {
+    return false;
+  }
+
+  /* Steps 9-10. */
+  for (uint64_t k = 0; k < len; k++) {
+    RootedValue fromValue(cx);
+    if (k == uint64_t(actualIndex)) {
+      fromValue = args.get(1);
+    } else {
+      if (!GetArrayElement(cx, obj, k, &fromValue)) {
+        return false;
+      }
+    }
+    if (!SetArrayElement(cx, A, k, fromValue)) {
+      return false;
+    }
+  }
+
+  /* Step 11. */
+  args.rval().setObject(*A);
+  return true;
+}
+#endif
+
 struct SortComparatorIndexes {
   bool operator()(uint32_t a, uint32_t b, bool* lessOrEqualp) {
     *lessOrEqualp = (a <= b);
     return true;
   }
 };
 
 // Returns all indexed properties in the range [begin, end) found on |obj| or
@@ -3630,16 +3860,26 @@ static const JSFunctionSpec array_method
     JS_SELF_HOSTED_FN("flatMap", "ArrayFlatMap", 1, 0),
     JS_SELF_HOSTED_FN("flat", "ArrayFlat", 0, 0),
 
     /* Proposal */
     JS_SELF_HOSTED_FN("at", "ArrayAt", 1, 0),
 
     JS_FS_END};
 
+#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+static const JSFunctionSpec change_array_by_copy_methods[] = {
+    JS_SELF_HOSTED_FN("withReversed", "ArrayWithReversed", 0, 0),
+    JS_SELF_HOSTED_FN("withSorted", "ArrayWithSorted", 1, 0),
+    JS_FN("withSpliced", array_with_spliced, 2, 0),
+    JS_FN("withAt", array_with_at, 2, 0),
+
+    JS_FS_END};
+#endif
+
 static const JSFunctionSpec array_static_methods[] = {
     JS_INLINABLE_FN("isArray", array_isArray, 1, 0, ArrayIsArray),
     JS_SELF_HOSTED_FN("from", "ArrayFrom", 3, 0), JS_FN("of", array_of, 0, 0),
 
     JS_FS_END};
 
 const JSPropertySpec array_static_props[] = {
     JS_SELF_HOSTED_SYM_GET(species, "$ArraySpecies", 0), JS_PS_END};
@@ -3879,16 +4119,31 @@ static bool array_proto_finish(JSContext
       !DefineDataProperty(cx, unscopables, cx->names().flat, value) ||
       !DefineDataProperty(cx, unscopables, cx->names().flatMap, value) ||
       !DefineDataProperty(cx, unscopables, cx->names().includes, value) ||
       !DefineDataProperty(cx, unscopables, cx->names().keys, value) ||
       !DefineDataProperty(cx, unscopables, cx->names().values, value)) {
     return false;
   }
 
+#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+  if (cx->options().changeArrayByCopy()) {
+    if (!DefineDataProperty(cx, unscopables, cx->names().withAt, value) ||
+        !DefineDataProperty(cx, unscopables, cx->names().withReversed, value) ||
+        !DefineDataProperty(cx, unscopables, cx->names().withSorted, value) ||
+        !DefineDataProperty(cx, unscopables, cx->names().withSpliced, value)) {
+      return false;
+    }
+
+    if (!JS_DefineFunctions(cx, proto, change_array_by_copy_methods)) {
+      return false;
+    }
+  }
+#endif
+
   RootedId id(cx, SYMBOL_TO_JSID(
                       cx->wellKnownSymbols().get(JS::SymbolCode::unscopables)));
   value.setObject(*unscopables);
   return DefineDataProperty(cx, proto, id, value, JSPROP_READONLY);
 }
 
 static const JSClassOps ArrayObjectClassOps = {
     array_addProperty,  // addProperty
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -147,24 +147,28 @@ function ArraySome(callbackfn/*, thisArg
     return false;
 }
 // Inlining this enables inlining of the callback function.
 SetIsInlinableLargeFunction(ArraySome);
 
 // ES2018 draft rev 3bbc87cd1b9d3bf64c3e68ca2fe9c5a3f2c304c0
 // 22.1.3.25 Array.prototype.sort ( comparefn )
 function ArraySort(comparefn) {
+    return SortArray(this, comparefn);
+}
+
+function SortArray(obj, comparefn) {
     // Step 1.
     if (comparefn !== undefined) {
         if (!IsCallable(comparefn))
             ThrowTypeError(JSMSG_BAD_SORT_ARG);
     }
 
     // Step 2.
-    var O = ToObject(this);
+    var O = ToObject(obj);
 
     // First try to sort the array in native code, if that fails, indicated by
     // returning |false| from ArrayNativeSort, sort it in self-hosted code.
     if (callFunction(ArrayNativeSort, O, comparefn))
         return O;
 
     // Step 3.
     var len = ToLength(O.length);
@@ -1177,8 +1181,72 @@ function ArrayAt(index) {
         return undefined;
     }
 
     // Step 7.
     return O[k];
 }
 // This function is only barely too long for normal inlining.
 SetIsInlinableLargeFunction(ArrayAt);
+
+#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+
+// https://github.com/tc39/proposal-change-array-by-copy
+// Array.prototype.withReversed()
+function ArrayWithReversed() {
+
+    /* Step 1. */
+    var O = ToObject(this);
+
+    /* Step 2. */
+    var len = ToLength(O.length);
+
+    /* Step 3. */
+    var A = std_Array(len);
+
+    /* Steps 4-5. */
+    for (var k = 0; k < len; k++) {
+        /* Step 5a. */
+        var from = len - k - 1;
+        /* Step 5b - not necessary. */
+        /* Step 5c. */
+        var fromValue = O[from];
+        /* Step 5d. */
+        DefineDataProperty(A, k, fromValue);
+    }
+
+    /* Step 6. */
+    return A;
+}
+
+// https://github.com/tc39/proposal-change-array-by-copy
+// Array.prototype.withSorted()
+function ArrayWithSorted(comparefn) {
+
+    /* Step 1. */
+
+    if (comparefn !== undefined && !IsCallable(comparefn)) {
+        ThrowTypeError(JSMSG_BAD_WITHSORTED_ARG);
+    }
+
+    /* Step 2. */
+    var O = ToObject(this);
+
+    /* Step 3. */
+    var len = ToLength(O.length);
+
+    /* Step 4. */
+    var items = std_Array(len);
+
+    /* Steps 5-6. */
+    for(var k = 0; k < len; k++) {
+        DefineDataProperty(items, k, O[k]);
+    }
+
+    /* Step 7. */
+    SortArray(items, comparefn);
+
+    /* Steps 8-10 unnecessary */
+    /* Step 11. */
+    return items;
+}
+
+#endif
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -207,16 +207,24 @@ static bool GetRealmConfiguration(JSCont
 
   bool offThreadParseGlobal = js::UseOffThreadParseGlobal();
   if (!JS_SetProperty(
           cx, info, "offThreadParseGlobal",
           offThreadParseGlobal ? TrueHandleValue : FalseHandleValue)) {
     return false;
   }
 
+#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+  bool changeArrayByCopy = cx->options().changeArrayByCopy();
+  if (!JS_SetProperty(cx, info, "enableChangeArrayByCopy",
+                      changeArrayByCopy ? TrueHandleValue : FalseHandleValue)) {
+    return false;
+  }
+#endif
+
   args.rval().setObject(*info);
   return true;
 }
 
 static bool GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   RootedObject info(cx, JS_NewPlainObject(cx));
   if (!info) {
@@ -518,16 +526,25 @@ static bool GetBuildConfiguration(JSCont
     return false;
   }
 
   value.setInt32(sizeof(void*));
   if (!JS_SetProperty(cx, info, "pointer-byte-size", value)) {
     return false;
   }
 
+#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+  value = BooleanValue(true);
+#else
+  value = BooleanValue(false);
+#endif
+  if (!JS_SetProperty(cx, info, "change-array-by-copy", value)) {
+    return false;
+  }
+
   args.rval().setObject(*info);
   return true;
 }
 
 static bool IsLCovEnabled(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   args.rval().setBoolean(coverage::IsLCovEnabled());
   return true;
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -1774,8 +1774,196 @@ function SharedArrayBufferSlice(start, e
         ThrowTypeError(JSMSG_SHORT_SHARED_ARRAY_BUFFER_RETURNED, newLen, actualLen);
 
     // Steps 16-18.
     SharedArrayBufferCopyData(newObj, 0, O, first, newLen, isWrapped);
 
     // Step 19.
     return newObj;
 }
+
+#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+
+// https://github.com/tc39/proposal-change-array-by-copy
+// TypedArray.prototype.withReversed()
+function TypedArrayWithReversed() {
+    /* Step 2. */
+    if (!IsObject(this) || !IsTypedArray(this)) {
+        return callFunction(CallTypedArrayMethodIfWrapped, this, "TypedArrayWithReversed");
+    }
+
+    // Step 1.
+    var O = this;
+
+    /* Step 3. */
+    var len = TypedArrayLength(O);
+
+    /* Step 4. */
+    var A = TypedArraySpeciesCreateWithLength(O, len);
+
+    /* Steps 5-6. */
+    for (var k = 0; k < len; k++) {
+        var from = len - k - 1;
+        var fromValue = O[from];
+        DefineDataProperty(A, k, fromValue);
+    }
+
+    /* Step 7. */
+    return A;
+}
+
+// ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
+// 10.4.5.9 IsValidIntegerIndex ( O, index )
+function isValidIntegerIndex(a, index) {
+    return (!IsDetachedBuffer(ViewedArrayBufferIfReified(a))
+            && Number_isInteger(index)
+            && !SameValue(index, -0)
+            && index >= 0
+            && index < TypedArrayLength(a));
+}
+
+// https://github.com/tc39/proposal-change-array-by-copy
+// TypedArray.prototype.withAt()
+function TypedArrayWithAt(index, value) {
+
+    /* Step 2. */
+    if (!IsObject(this) || !IsTypedArray(this)) {
+        return callFunction(CallTypedArrayMethodIfWrapped, this, "TypedArrayWithAt", index, value);
+    }
+
+    // Step 1.
+    var O = this;
+
+    /* Step 3. */
+    var len = TypedArrayLength(O);
+
+    /* Step 4. */
+    if (!Number_isInteger(index)) {
+        ThrowRangeError(JSMSG_BAD_INDEX);
+    }
+
+    /* Steps 5-6. */
+    var actualIndex = index < 0 ? (len + index) : index;
+
+    /* Step 7. */
+    if (!isValidIntegerIndex(O, actualIndex)) {
+        ThrowRangeError(JSMSG_BAD_INDEX);
+    }
+
+    /* Step 8. */
+    var A = TypedArraySpeciesCreateWithLength(O, len);
+
+    /* Steps 9-10. */
+    for (var k = 0; k < len; k++) {
+        var fromValue = k == actualIndex ? value : O[k];
+        DefineDataProperty(A, k, fromValue);
+    }
+
+    /* Step 11. */
+    return A;
+}
+
+// https://github.com/tc39/proposal-change-array-by-copy
+// TypedArray.prototype.withSorted()
+function TypedArrayWithSorted(comparefn) {
+    // Step 3.
+    if (!IsObject(this) || !IsTypedArray(this)) {
+        return callFunction(CallTypedArrayMethodIfWrapped, this, "TypedArrayWithSorted", comparefn);
+    }
+
+    // Step 1.
+    if (comparefn !== undefined) {
+        if (!IsCallable(comparefn)) {
+            ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, comparefn));
+        }
+    }
+
+    // Step 2.
+    var O = this;
+
+    // Step 4.
+    var len = TypedArrayLength(O);
+
+    var A = TypedArraySpeciesCreateWithLength(O, len);
+    for(var k = 0; k < len; k++) {
+        A[k] = O[k];
+    }
+    return callFunction(CallTypedArrayMethodIfWrapped, A, comparefn, "TypedArraySort");
+}
+
+// https://github.com/tc39/proposal-change-array-by-copy
+// TypedArray.prototype.withSpliced()
+function TypedArrayWithSpliced(start, deleteCount, ...items) {
+    /* Step 2. */
+    if (!IsObject(this) || !IsTypedArray(this)) {
+        return callFunction(CallTypedArrayMethodIfWrapped, this, "TypedArrayWithSpliced", start, deleteCount, items);
+    }
+
+    // Step 1.
+    var O = this;
+
+    // Step 3.
+    var len = TypedArrayLength(O);
+
+    // Step 4.
+    var relativeStart = ToInteger(start);
+
+    // Step 5.
+    var actualStart;
+    if (!Global_isFinite(relativeStart) && relativeStart < 0) {
+        actualStart = 0;
+    } else if (relativeStart < 0) {
+        // Step 6.
+        actualStart = std_Math_max(len + relativeStart, 0);
+    } else {
+        // Step 7.
+        actualStart = std_Math_min(relativeStart, len);
+    }
+
+    var insertCount;
+    var actualDeleteCount;
+    // Step 8.
+    if (start === undefined) {
+        insertCount = 0;
+        actualDeleteCount = 0;
+    } else if (deleteCount === undefined) {
+        // Step 9.
+        insertCount = 0;
+        actualDeleteCount = len - actualStart;
+    } else {
+        // Step 10.
+        insertCount = items === undefined ? 0 : items.length;
+        var dc = ToInteger(deleteCount);
+        actualDeleteCount = std_Math_min(len - actualStart, std_Math_max(0, dc));
+    }
+
+    // Step 11.
+    var newLen = len + insertCount - actualDeleteCount;
+
+    // Step 12.
+    var A = TypedArraySpeciesCreateWithLength(O, newLen);
+
+    // Steps 13-14
+    // Copy all the items before actualStart
+    for(var k = 0; k < actualStart; k++) {
+        var kValue = O[k];
+        DefineDataProperty(A, k, kValue);
+    }
+
+    // Step 15.
+    // Copy all the new items.
+    var k = actualStart;
+    for(var i = 0; i < insertCount; i++) {
+        DefineDataProperty(A, k++, items[i]);
+    }
+
+    // Step 16.
+    // Copy all the items after the deleted / added items
+    while(k < newLen) {
+        var from = k + actualDeleteCount - insertCount;
+        var fromValue = O[from];
+        DefineDataProperty(A, k++, fromValue);
+    }
+
+    // Step 17.
+    return A;
+}
+#endif
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/change-array-by-copy.js
@@ -0,0 +1,103 @@
+// |jit-test| --enable-change-array-by-copy; skip-if: !getBuildConfiguration()['change-array-by-copy']
+
+load(libdir + 'array-compare.js');
+load(libdir + "asserts.js");
+
+var sequence = [1, 2, 3];
+let reversedSequence = sequence.withReversed();
+assertEq(arraysEqual(sequence, [1, 2, 3]), true);
+assertEq(arraysEqual(reversedSequence, [3, 2, 1]), true);
+
+sequence = [87, 3, 5, 888, 321, 42];
+var sortedSequence = sequence.withSorted((x, y) => (x >= y));
+assertEq(arraysEqual(sequence, [87, 3, 5, 888, 321, 42]), true);
+assertEq(arraysEqual(sortedSequence, [3, 5, 42, 87, 321, 888]), true);
+
+sequence = ["the", "quick", "fox", "jumped", "over", "the", "lazy", "dog"];
+sortedSequence = sequence.withSorted();
+assertEq(arraysEqual(sequence, ["the", "quick", "fox", "jumped", "over", "the", "lazy", "dog"]), true);
+assertEq(arraysEqual(sortedSequence, ["dog", "fox", "jumped", "lazy", "over", "quick", "the", "the"]), true);
+
+/* Test that the correct exception is thrown with a
+   non-function comparefn argument */
+assertThrowsInstanceOf(() => sequence.withSorted([1, 2, 3]), TypeError);
+
+/* withSpliced */
+/* examples from:
+  https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice */
+
+function unchanged(a) {
+    assertEq(arraysEqual(a, ['angel', 'clown', 'mandarin', 'sturgeon']), true);
+}
+
+// Remove no elements before index 2, insert "drum"
+let myFish = ['angel', 'clown', 'mandarin', 'sturgeon']
+var myFishSpliced = myFish.withSpliced(2, 0, 'drum')
+unchanged(myFish);
+assertEq(arraysEqual(myFishSpliced, ['angel', 'clown', 'drum', 'mandarin', 'sturgeon']), true);
+
+
+// Remove no elements before index 2, insert "drum" and "guitar"
+var myFishSpliced = myFish.withSpliced(2, 0, 'drum', 'guitar');
+unchanged(myFish);
+assertEq(arraysEqual(myFishSpliced, ['angel', 'clown', 'drum', 'guitar', 'mandarin', 'sturgeon']), true);
+
+// Remove 1 element at index 3
+let myFish1 = ['angel', 'clown', 'drum', 'mandarin', 'sturgeon']
+myFishSpliced = myFish1.withSpliced(3, 1);
+assertEq(arraysEqual(myFish1, ['angel', 'clown', 'drum', 'mandarin', 'sturgeon']), true);
+assertEq(arraysEqual(myFishSpliced, ['angel', 'clown', 'drum', 'sturgeon']), true);
+
+// Remove 1 element at index 2, and insert 'trumpet'
+let myFish2 = ['angel', 'clown', 'drum', 'sturgeon']
+myFishSpliced = myFish2.withSpliced(2, 1, 'trumpet');
+assertEq(arraysEqual(myFish2, ['angel', 'clown', 'drum', 'sturgeon']), true);
+assertEq(arraysEqual(myFishSpliced, ['angel', 'clown', 'trumpet', 'sturgeon']), true);
+
+// Remove 2 elements at index 0, and insert 'parrot', 'anemone', and 'blue'
+let myFish3 = ['angel', 'clown', 'trumpet', 'sturgeon']
+myFishSpliced = myFish3.withSpliced(0, 2, 'parrot', 'anemone', 'blue');
+assertEq(arraysEqual(myFish3, ['angel', 'clown', 'trumpet', 'sturgeon']), true);
+assertEq(arraysEqual(myFishSpliced, ['parrot', 'anemone', 'blue', 'trumpet', 'sturgeon']), true);
+
+// Remove 2 elements, starting at index 2
+let myFish4 = ['parrot', 'anemone', 'blue', 'trumpet', 'sturgeon']
+myFishSpliced = myFish4.withSpliced(2, 2);
+assertEq(arraysEqual(myFish4, ['parrot', 'anemone', 'blue', 'trumpet', 'sturgeon']), true);
+assertEq(arraysEqual(myFishSpliced, ['parrot', 'anemone', 'sturgeon']), true);
+
+// Remove 1 element from index -2
+myFishSpliced = myFish.withSpliced(-2, 1);
+unchanged(myFish);
+assertEq(arraysEqual(myFishSpliced, ['angel', 'clown', 'sturgeon']), true);
+
+// Remove all elements, starting from index 2
+myFishSpliced = myFish.withSpliced(2);
+unchanged(myFish);
+assertEq(arraysEqual(myFishSpliced, ['angel', 'clown']), true);
+
+/* withAt */
+sequence = [1, 2, 3];
+let seq_withAt = sequence.withAt(1, 42);
+assertEq(arraysEqual(sequence, [1, 2, 3]), true);
+assertEq(arraysEqual(seq_withAt, [1, 42, 3]), true);
+
+/* false/true => index 0/1 */
+assertEq(arraysEqual(sequence.withAt(false, 42), [42, 2, 3]), true);
+assertEq(arraysEqual(sequence.withAt(true, 42), [1, 42, 3]), true);
+
+/* null => 0 */
+assertEq(arraysEqual(sequence.withAt(null, 42), [42, 2, 3]), true);
+/* [] => 0 */
+assertEq(arraysEqual(sequence.withAt([], 42), [42, 2, 3]), true);
+
+assertEq(arraysEqual(sequence.withAt("2", 42), [1, 2, 42]), true);
+
+assertThrowsInstanceOf(() => sequence.withAt(3, 42), RangeError);
+assertThrowsInstanceOf(() => sequence.withAt(5, 42), RangeError);
+assertThrowsInstanceOf(() => sequence.withAt(-10, 42), RangeError);
+assertThrowsInstanceOf(() => sequence.withAt("monkeys", 42), RangeError);
+assertThrowsInstanceOf(() => sequence.withAt(Infinity, 42), RangeError);
+assertThrowsInstanceOf(() => sequence.withAt(undefined, 42), RangeError);
+assertThrowsInstanceOf(() => sequence.withAt(function() {}, 42), RangeError);
+
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/typedarray/typed-array-change-by-copy.js
@@ -0,0 +1,43 @@
+// |jit-test| --enable-change-array-by-copy; skip-if: !getBuildConfiguration()['change-array-by-copy']
+
+load(libdir + 'array-compare.js');
+load(libdir + "asserts.js");
+
+let typedArray123 = new Uint8Array([1, 2, 3]);
+let typedArray12345 = new Uint8Array([1, 2, 3, 4, 5]);
+let typedArray = new Uint8Array([1, 2, 3]);
+let typedArray2 = new Uint8Array([3, 2, 1]);
+
+let a_withAt = typedArray.withAt(1, 42);
+assertEq(arraysEqual(typedArray, new Uint8Array([1, 2, 3])), true);
+assertEq(arraysEqual(a_withAt, new Uint8Array([1, 42, 3])), true);
+
+assertThrowsInstanceOf(() => typedArray.withAt(5, 42), RangeError);
+assertThrowsInstanceOf(() => typedArray.withAt(-10, 42), RangeError);
+assertThrowsInstanceOf(() => typedArray.withAt(-0, 42), RangeError);
+
+let reversedIntArray = typedArray.withReversed();
+assertEq(arraysEqual(typedArray, typedArray123), true);
+assertEq(arraysEqual(reversedIntArray, typedArray2), true);
+
+
+let sortedIntArray = typedArray2.withSorted();
+assertEq(arraysEqual(typedArray2, new Uint8Array([3, 2, 1])), true);
+assertEq(arraysEqual(sortedIntArray, typedArray), true);
+
+let a_withSpliced1 = typedArray.withSpliced();
+assertEq(arraysEqual(typedArray, typedArray123), true);
+assertEq(arraysEqual(a_withSpliced1, typedArray123), true);
+
+let a_withSpliced2 = typedArray.withSpliced(2);
+assertEq(arraysEqual(typedArray, typedArray123), true);
+assertEq(arraysEqual(a_withSpliced2, new Uint8Array([1, 2])), true);
+
+let typedArray3 = new Uint8Array([1, 2, 3, 4, 5]);
+let a_withSpliced3 = typedArray3.withSpliced(1, 2)
+assertEq(arraysEqual(typedArray3, typedArray12345), true);
+assertEq(arraysEqual(a_withSpliced3, new Uint8Array([1, 4, 5])), true);
+
+let a_withSpliced4 = typedArray3.withSpliced(1, 2, 42, 12)
+assertEq(arraysEqual(typedArray3, typedArray12345), true);
+assertEq(arraysEqual(a_withSpliced4, new Uint8Array([1, 42, 12, 4, 5])), true);
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -625,16 +625,19 @@ bool shell::enableWritableStreams = fals
 bool shell::enableReadableStreamPipeTo = false;
 bool shell::enableWeakRefs = false;
 bool shell::enableToSource = false;
 bool shell::enablePropertyErrorMessageFix = false;
 bool shell::enableIteratorHelpers = false;
 bool shell::enablePrivateClassFields = false;
 bool shell::enablePrivateClassMethods = false;
 bool shell::enableErgonomicBrandChecks = true;
+#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+bool shell::enableChangeArrayByCopy = false;
+#endif
 bool shell::useOffThreadParseGlobal = true;
 bool shell::enableClassStaticBlocks = true;
 #ifdef JS_GC_ZEAL
 uint32_t shell::gZealBits = 0;
 uint32_t shell::gZealFrequency = 0;
 #endif
 bool shell::printTiming = false;
 RCFile* shell::gErrFile = nullptr;
@@ -11298,16 +11301,19 @@ static bool SetContextOptions(JSContext*
   enableToSource = !op.getBoolOption("disable-tosource");
   enablePropertyErrorMessageFix =
       !op.getBoolOption("disable-property-error-message-fix");
   enableIteratorHelpers = op.getBoolOption("enable-iterator-helpers");
   enablePrivateClassFields = !op.getBoolOption("disable-private-fields");
   enablePrivateClassMethods = !op.getBoolOption("disable-private-methods");
   enableErgonomicBrandChecks =
       !op.getBoolOption("disable-ergonomic-brand-checks");
+#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+  enableChangeArrayByCopy = op.getBoolOption("enable-change-array-by-copy");
+#endif
   enableClassStaticBlocks = !op.getBoolOption("disable-class-static-blocks");
   useOffThreadParseGlobal = op.getBoolOption("off-thread-parse-global");
   useFdlibmForSinCosTan = op.getBoolOption("use-fdlibm-for-sin-cos-tan");
 
   JS::ContextOptionsRef(cx)
       .setAsmJS(enableAsmJS)
       .setWasm(enableWasm)
       .setWasmForTrustedPrinciples(enableWasm)
@@ -11330,16 +11336,19 @@ static bool SetContextOptions(JSContext*
       .setWasmVerbose(enableWasmVerbose)
       .setTestWasmAwaitTier2(enableTestWasmAwaitTier2)
       .setSourcePragmas(enableSourcePragmas)
       .setAsyncStack(enableAsyncStacks)
       .setAsyncStackCaptureDebuggeeOnly(enableAsyncStackCaptureDebuggeeOnly)
       .setPrivateClassFields(enablePrivateClassFields)
       .setPrivateClassMethods(enablePrivateClassMethods)
       .setErgnomicBrandChecks(enableErgonomicBrandChecks)
+#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+      .setChangeArrayByCopy(enableChangeArrayByCopy)
+#endif
       .setClassStaticBlocks(enableClassStaticBlocks);
 
   JS::SetUseOffThreadParseGlobal(useOffThreadParseGlobal);
   JS::SetUseFdlibmForSinCosTan(useFdlibmForSinCosTan);
 
   // Check --fast-warmup first because it sets default warm-up thresholds. These
   // thresholds can then be overridden below by --ion-eager and other flags.
   if (op.getBoolOption("fast-warmup")) {
@@ -12280,16 +12289,25 @@ int main(int argc, char** argv) {
       !op.addBoolOption('\0', "disable-private-methods",
                         "Disable private class methods") ||
       !op.addBoolOption(
           '\0', "enable-ergonomic-brand-checks",
           "Enable ergonomic brand checks for private class fields (no-op)") ||
       !op.addBoolOption(
           '\0', "disable-ergonomic-brand-checks",
           "Disable ergonomic brand checks for private class fields") ||
+#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+      !op.addBoolOption('\0', "enable-change-array-by-copy",
+                        "Enable change-array-by-copy methods") ||
+      !op.addBoolOption('\0', "disable-change-array-by-copy",
+                        "Disable change-array-by-copy methods") ||
+#else
+      !op.addBoolOption('\0', "enable-change-array-by-copy", "no-op") ||
+      !op.addBoolOption('\0', "disable-change-array-by-copy", "no-op") ||
+#endif
       !op.addBoolOption('\0', "enable-top-level-await",
                         "Enable top-level await") ||
       !op.addBoolOption('\0', "disable-class-static-blocks",
                         "Disable class static blocks") ||
       !op.addBoolOption('\0', "enable-class-static-blocks",
                         "(no-op) Enable class static blocks") ||
       !op.addBoolOption('\0', "off-thread-parse-global",
                         "Use parseGlobal in all off-thread compilation") ||
--- a/js/src/shell/jsshell.h
+++ b/js/src/shell/jsshell.h
@@ -131,16 +131,19 @@ extern bool enableReadableStreamPipeTo;
 extern bool enableWeakRefs;
 extern bool enableToSource;
 extern bool enablePropertyErrorMessageFix;
 extern bool useOffThreadParseGlobal;
 extern bool enableIteratorHelpers;
 extern bool enablePrivateClassFields;
 extern bool enablePrivateClassMethods;
 extern bool enableErgonomicBrandChecks;
+#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+extern bool enableChangeArrayByCopy;
+#endif
 extern bool enableClassStaticBlocks;
 #ifdef JS_GC_ZEAL
 extern uint32_t gZealBits;
 extern uint32_t gZealFrequency;
 #endif
 extern bool printTiming;
 extern RCFile* gErrFile;
 extern RCFile* gOutFile;
--- a/js/src/tests/non262/Array/unscopables.js
+++ b/js/src/tests/non262/Array/unscopables.js
@@ -15,29 +15,41 @@ assertDeepEq(desc2, {
     value: true,
     writable: true,
     enumerable: true,
     configurable: true
 });
 
 let keys = Reflect.ownKeys(Array_unscopables);
 
-assertDeepEq(keys, [
-    "at",
-    "copyWithin",
-    "entries",
-    "fill",
-    "find",
-    "findIndex",
-    "flat",
-    "flatMap",
-    "includes",
-    "keys",
-    "values"
-]);
+let expectedKeys = ["at",
+		    "copyWithin",
+		    "entries",
+		    "fill",
+		    "find",
+		    "findIndex",
+		    "flat",
+		    "flatMap",
+		    "includes",
+		    "keys",
+		    "values"];
+
+if (typeof getBuildConfiguration === "undefined") {
+  var getBuildConfiguration = SpecialPowers.Cu.getJSTestingFunctions().getBuildConfiguration;
+}
+
+if (typeof getRealmConfiguration === "undefined") {
+  var getRealmConfiguration = SpecialPowers.Cu.getJSTestingFunctions().getRealmConfiguration;
+}
+
+if (getBuildConfiguration()['change-array-by-copy'] && getRealmConfiguration().enableChangeArrayByCopy) {
+    expectedKeys.push("withAt", "withReversed", "withSorted", "withSpliced");
+}
+
+assertDeepEq(keys, expectedKeys);
 
 for (let key of keys)
     assertEq(Array_unscopables[key], true);
 
 // Test that it actually works
 assertThrowsInstanceOf(() => {
     with ([]) {
         return entries;
--- a/js/src/tests/user.js
+++ b/js/src/tests/user.js
@@ -29,8 +29,9 @@ user_pref("privacy.trackingprotection.en
 user_pref("privacy.trackingprotection.pbmode.enabled", false);
 user_pref("general.useragent.updates.enabled", false);
 user_pref("browser.webapps.checkForUpdates", 0);
 user_pref("javascript.options.weakrefs", true);
 user_pref("javascript.options.experimental.weakrefs.expose_cleanupSome", true);
 user_pref("javascript.options.experimental.iterator_helpers", true);
 user_pref("javascript.options.experimental.top_level_await", true);
 user_pref("javascript.options.experimental.ergonomic_brand_checks", true);
+user_pref("javascript.options.experimental.enable_change_array_by_copy", false);
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -537,16 +537,20 @@
   MACRO_(WeakSetConstructorInit, WeakSetConstructorInit,                       \
          "WeakSetConstructorInit")                                             \
   MACRO_(WeakSet_add, WeakSet_add, "WeakSet_add")                              \
   MACRO_(week, week, "week")                                                   \
   MACRO_(weekday, weekday, "weekday")                                          \
   MACRO_(weekend, weekend, "weekend")                                          \
   MACRO_(while, while_, "while")                                               \
   MACRO_(with, with, "with")                                                   \
+  MACRO_(withAt, withAt, "withAt")                                             \
+  MACRO_(withReversed, withReversed, "withReversed")                           \
+  MACRO_(withSorted, withSorted, "withSorted")                                 \
+  MACRO_(withSpliced, withSpliced, "withSpliced")                              \
   MACRO_(writable, writable, "writable")                                       \
   MACRO_(write, write, "write")                                                \
   MACRO_(year, year, "year")                                                   \
   MACRO_(yearName, yearName, "yearName")                                       \
   MACRO_(yield, yield, "yield")                                                \
   MACRO_(zero, zero, "zero")                                                   \
   /* Type names must be contiguous and ordered; see js::TypeName. */           \
   MACRO_(undefined, undefined, "undefined")                                    \
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -1982,16 +1982,37 @@ bool TypedArrayObject::copyWithin(JSCont
     JS_SELF_HOSTED_FN("values", "$TypedArrayValues", 0, 0),
     JS_SELF_HOSTED_SYM_FN(iterator, "$TypedArrayValues", 0, 0),
     JS_SELF_HOSTED_FN("includes", "TypedArrayIncludes", 2, 0),
     JS_SELF_HOSTED_FN("toString", "ArrayToString", 0, 0),
     JS_SELF_HOSTED_FN("toLocaleString", "TypedArrayToLocaleString", 2, 0),
     JS_SELF_HOSTED_FN("at", "TypedArrayAt", 1, 0),
     JS_FS_END};
 
+#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+const JSFunctionSpec changeArrayByCopyProtoFunctions[] = {
+    JS_SELF_HOSTED_FN("withReversed", "TypedArrayWithReversed", 0, 0),
+    JS_SELF_HOSTED_FN("withSorted", "TypedArrayWithSorted", 1, 0),
+    JS_SELF_HOSTED_FN("withAt", "TypedArrayWithAt", 2, 0),
+    JS_SELF_HOSTED_FN("withSpliced", "TypedArrayWithSpliced", 3, 0),
+
+    JS_FS_END};
+
+static bool TypedArrayProtoFinish(JSContext* cx, JS::HandleObject ctor,
+                                  JS::HandleObject proto) {
+  if (cx->options().changeArrayByCopy()) {
+    if (!js::DefineFunctions(cx, proto, changeArrayByCopyProtoFunctions,
+                             js::NotIntrinsic)) {
+      return false;
+    }
+  }
+  return true;
+}
+#endif
+
 /* static */ const JSFunctionSpec TypedArrayObject::staticFunctions[] = {
     JS_SELF_HOSTED_FN("from", "TypedArrayStaticFrom", 3, 0),
     JS_SELF_HOSTED_FN("of", "TypedArrayStaticOf", 0, 0), JS_FS_END};
 
 /* static */ const JSPropertySpec TypedArrayObject::staticProperties[] = {
     JS_SELF_HOSTED_SYM_GET(species, "$TypedArraySpecies", 0), JS_PS_END};
 
 static JSObject* CreateSharedTypedArrayPrototype(JSContext* cx,
@@ -2002,17 +2023,21 @@ static JSObject* CreateSharedTypedArrayP
 
 static const ClassSpec TypedArrayObjectSharedTypedArrayPrototypeClassSpec = {
     GenericCreateConstructor<TypedArrayConstructor, 0, gc::AllocKind::FUNCTION>,
     CreateSharedTypedArrayPrototype,
     TypedArrayObject::staticFunctions,
     TypedArrayObject::staticProperties,
     TypedArrayObject::protoFunctions,
     TypedArrayObject::protoAccessors,
+#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+    TypedArrayProtoFinish,
+#else
     nullptr,
+#endif
     ClassSpec::DontDefineConstructor};
 
 /* static */ const JSClass TypedArrayObject::sharedTypedArrayPrototypeClass = {
     "TypedArrayPrototype", JSCLASS_HAS_CACHED_PROTO(JSProto_TypedArray),
     JS_NULL_CLASS_OPS, &TypedArrayObjectSharedTypedArrayPrototypeClassSpec};
 
 namespace {
 
--- a/js/xpconnect/src/XPCJSContext.cpp
+++ b/js/xpconnect/src/XPCJSContext.cpp
@@ -984,16 +984,20 @@ static void ReloadPrefsCallback(const ch
 
   bool privateFieldsEnabled =
       Preferences::GetBool(JS_OPTIONS_DOT_STR "experimental.private_fields");
   bool privateMethodsEnabled =
       Preferences::GetBool(JS_OPTIONS_DOT_STR "experimental.private_methods");
 
   bool ergnomicBrandChecksEnabled = Preferences::GetBool(
       JS_OPTIONS_DOT_STR "experimental.ergonomic_brand_checks");
+#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+  bool enableChangeArrayByCopy = Preferences::GetBool(
+      JS_OPTIONS_DOT_STR "experimental.enable_change_array_by_copy");
+#endif
 
   bool classStaticBlocksEnabled = Preferences::GetBool(
       JS_OPTIONS_DOT_STR "experimental.class_static_blocks");
 
 #ifdef NIGHTLY_BUILD
   sIteratorHelpersEnabled =
       Preferences::GetBool(JS_OPTIONS_DOT_STR "experimental.iterator_helpers");
 #endif
@@ -1037,16 +1041,19 @@ static void ReloadPrefsCallback(const ch
       .setSourcePragmas(useSourcePragmas)
       .setAsyncStack(useAsyncStack)
       .setAsyncStackCaptureDebuggeeOnly(useAsyncStackCaptureDebuggeeOnly)
       .setThrowOnDebuggeeWouldRun(throwOnDebuggeeWouldRun)
       .setDumpStackOnDebuggeeWouldRun(dumpStackOnDebuggeeWouldRun)
       .setPrivateClassFields(privateFieldsEnabled)
       .setPrivateClassMethods(privateMethodsEnabled)
       .setClassStaticBlocks(classStaticBlocksEnabled)
+#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
+      .setChangeArrayByCopy(enableChangeArrayByCopy)
+#endif
       .setErgnomicBrandChecks(ergnomicBrandChecksEnabled);
 
   JS::SetUseFdlibmForSinCosTan(
       Preferences::GetBool(JS_OPTIONS_DOT_STR "use_fdlibm_for_sin_cos_tan") ||
       Preferences::GetBool("privacy.resistFingerprinting"));
 
   nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
   if (xr) {
--- a/js/xpconnect/tests/chrome/chrome.ini
+++ b/js/xpconnect/tests/chrome/chrome.ini
@@ -29,16 +29,17 @@ support-files =
   !/js/xpconnect/tests/mochitest/file_exnstack.html
   !/js/xpconnect/tests/mochitest/file_expandosharing.html
   !/js/xpconnect/tests/mochitest/file_nodelists.html
   !/js/xpconnect/tests/mochitest/file_evalInSandbox.html
   !/js/xpconnect/tests/mochitest/file_xrayic.html
 prefs =
   javascript.options.large_arraybuffers=true
   javascript.options.experimental.ergonomic_brand_checks=true
+  javascript.options.experimental.enable_change_array_by_copy=false
   
 [test_APIExposer.xhtml]
 [test_bug361111.xhtml]
 [test_bug448587.xhtml]
 [test_bug484459.xhtml]
 skip-if = os == 'win' || os == 'mac' || (os == 'linux' && !debug) # bug 1131110, 1255284
 [test_bug500931.xhtml]
 [test_bug503926.xhtml]
--- a/js/xpconnect/tests/mochitest/mochitest.ini
+++ b/js/xpconnect/tests/mochitest/mochitest.ini
@@ -39,16 +39,17 @@ support-files =
   finalizationRegistry_worker.js
   private_field_worker.js
   class_static_worker.js
   bug1681664_helper.js
 prefs =
   javascript.options.weakrefs=true
   javascript.options.experimental.ergonomic_brand_checks=true
   javascript.options.experimental.top_level_await=true
+  javascript.options.experimental.enable_change_array_by_copy=false
 
 [test_bug384632.html]
 [test_bug390488.html]
 [test_bug393269.html]
 [test_bug396851.html]
 [test_bug428021.html]
 [test_bug446584.html]
 [test_bug462428.html]
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -1573,17 +1573,17 @@ already_AddRefed<nsIContent> nsCSSFrameC
           aState, NS_ConvertUTF8toUTF16(item.AsString().AsString()), nullptr);
 
     case Type::Attr: {
       const auto& attr = item.AsAttr();
       RefPtr<nsAtom> attrName = attr.attribute.AsAtom();
       int32_t attrNameSpace = kNameSpaceID_None;
       RefPtr<nsAtom> ns = attr.namespace_url.AsAtom();
       if (!ns->IsEmpty()) {
-        nsresult rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(
+        nsresult rv = nsNameSpaceManager::GetInstance()->RegisterNameSpace(
             ns.forget(), attrNameSpace);
         NS_ENSURE_SUCCESS(rv, nullptr);
       }
 
       if (mDocument->IsHTMLDocument() && aOriginatingElement.IsHTMLElement()) {
         ToLowerCaseASCII(attrName);
       }
 
--- a/layout/docs/css-gap-decorations/Overview.bs
+++ b/layout/docs/css-gap-decorations/Overview.bs
@@ -5,22 +5,24 @@
 -->
 <pre class='metadata'>
 Title: CSS Gap Decorations
 Shortname: css-gap-decorations
 Level: 1
 Status: ED
 Work Status: exploring
 Group: CSSWG
-URL: 
+URL: https://matspalmgren.github.io/css-gap-decorations/Overview.html
 Editor: Mats Palmgren, Mozilla Corporation http://mozilla.com, mats@mozilla.com
 Abstract: This is a proposal to extend <a href="https://drafts.csswg.org/css-align">CSS Box Alignment</a> to support gap decorations.
 Markup Shorthands: biblio yes
 Markup Shorthands: css yes
 Markup Shorthands: dfn yes
+Boilerplate: repository-issue-tracking off
+Issue Tracking: CSSWG github issue #6748 https://github.com/w3c/csswg-drafts/issues/6748
 </pre>
 <pre class="link-defaults">
 spec:css-box-4; type:value; for:<box>; text:margin-box
 spec:css-grid-3; type:dfn; text:masonry axis
 spec:css-grid-2; type:dfn; text:collapsed track
 </pre>
 
 Introduction {#intro}
@@ -405,17 +407,17 @@ The Rule Longitudinal Inset Properties {
                 Examples of rule sizing and inset values.
             </figcaption>
         </figure>
     </aside>
 
     <aside class=example>
         This <a href="examples/grid-longitudinal-002.html">example</a> demonstrates
         that the inset properties can be animated and that they are relative the [=rule containing rectangle=],
-        which itself depends on the <a href="#column-rule-align">rule's alignment</a> in its longitudinal axis.
+        which itself depends on the <a href="#rule-align">rule's alignment</a> in its longitudinal axis.
         Note that the longitudinal insets in this example are definite and not animated. The reason
         they follow the animated lateral position of the rule in the orthogonal axis is that they have
         <a href="#column-rule-align">''column-rule-align/rule'' alignment</a>.
         <figure>
             <video src="media/grid-longitudinal-002.webm" autoplay loop></video>
             <figcaption>
                 Example of rule alignment and animated inset values.
             </figcaption>
@@ -520,17 +522,17 @@ The 'row-rule' Shorthand {#row-rule}
     ISSUE: lots of new possible shorthands... we now have many
     properties (and shorthands) with a ''column-rule'' and ''row-rule'' prefix.
     Should we add shorthands for some of those with a 'rule' prefix to specify
     both axes, like so: 'rule-foo: <<row-rule-foo>> <<column-rule-foo>>?'.
     As usual, we have to be careful with the separator though, to make it
     forward-compatible with any changes we might want to make...
 
 
-Rule Alignment {#column-rule-align}
+Rule Alignment {#rule-align}
 ============================
 
 The 'column-rule-align' and 'row-rule-align' Properties {#column-rule-align}
 --------------------------------------------------
 
     <pre class=propdef>
         Name: column-rule-align, row-rule-align
         Value: [gap | gap-center | gap-over | rule | rule-center | rule-over]{1,2}
@@ -634,17 +636,17 @@ The 'column-rule-edge-align' and 'row-ru
     The alignment points follow the same pattern in the other axis for the row rules.
     In this case the row rule is using the initial values (''column-rule-align/gap'')
     so they align with the inline axis gap edges.
 
     ISSUE: Are there use cases for other box-related edge attachment points?
     e.g. 'padding | padding-center | padding-over | border...'
 
 
-Rule Extent {#column-rule-extent}
+Rule Extent {#rule-extent}
 ==============================
 
 The 'column-rule-extent' and 'row-rule-extent' Properties {#column-rule-extent}
 -------------------------------------------------------------------------------
 
     <pre class=propdef>
         Name: column-rule-extent, row-rule-extent
         Value: [segment | start | end | short | long | all-start | all-end | all-short | all-long ] allow-overlap?
@@ -902,19 +904,19 @@ The 'column-rule-extent' and 'row-rule-e
                the gaps are aligned between all the lines.
 
     Rules are created between adjacent flex lines, and their [=extent sizes=] are controlled by
     the ''row-rule-extent'' values defined as follows:
     <dl dfn-for=row-rule-extent dfn-type=value>
         <dt>segment</dt>
         <dd>behaves as ''row-rule-extent/short''
         <dt>start</dt>
-        <dd>use the [=outer size=] of the items in the flex line on the inline axis start side
+        <dd>use the [=outer size=] of the items in the flex line on the block axis start side
         <dt>end</dt>
-        <dd>use the [=outer size=] of the items in the flex line on the inline axis end side
+        <dd>use the [=outer size=] of the items in the flex line on the block axis end side
         <dt>short</dt>
         <dd>use the [=outer size=] of the [=next flex line item=] which has the smaller size (see detailed algorithm below)
         <dt>long</dt>
         <dd>use the [=outer size=] of the [=next flex line item=] which has the larger size (see detailed algorithm below)
         <dt>all-start</dt>
         <dd>the distance between the start position of the first item to the end position of the last item on the start side flex line
         <dt>all-end</dt>
         <dd>the distance between the start position of the first item to the end position of the last item on the end side flex line
@@ -1097,18 +1099,18 @@ The 'column-rule-extent' and 'row-rule-e
         </figure>
     </aside>
 
 
 
 The Rule Containing Rectangle {#rule-containing-rectangle}
 ==========================================================
 
-    The <dfn>rule containing rectangle</dfn> is formed by the <a href="#column-rule-extent">rule extent</a>
-    and <a href="#column-rule-align">alignment</a> in the [=longitudinal axis=], and by the size of the
+    The <dfn>rule containing rectangle</dfn> is formed by the <a href="#rule-extent">rule extent</a>
+    and <a href="#rule-align">alignment</a> in the [=longitudinal axis=], and by the size of the
     <a href="https://drafts.csswg.org/css-align/#gutter">gutter</a> in the [=lateral axis=].
     (For clarity, the size of the gutter is calculated from the <a href="https://drafts.csswg.org/css-align/#gaps">gap</a>
     properties plus any extra space contributed by <a href="https://drafts.csswg.org/css-align/#distribution-values">alignment distribution</a>
     but does not include any item margins.)
 
     It is important to note that the [=rule containing rectangle's=] size in an axis isn't affected by any of
     the <a href="#column-rule-lateral-inset">inset properties</a> <i>in the same axis</i> as that would lead to a circular
     dependency when resolving inset percentage values.  (The [=rule containing rectangle=] is the percentage basis
@@ -1148,17 +1150,17 @@ The Rule Containing Rectangle {#rule-con
 
 Rule Painting Order {#rule-painting-order}
 ==========================================
 
     Column and row rules are painted in the same layer as the element's border.
     They are painted after (on top of) the element's border.
     All column rules for an element are painted first, then all of its row rules.
     The rules for an axis are painted in the order they were generated by
-    the <a href="#column-rule-extent">rule extent</a> algorithms described above.
+    the <a href="#rule-extent">rule extent</a> algorithms described above.
     Typically from the logical start to the end of the axis.
 
     For table layout, all the <a spec=css-tables>table</a> rules (in both axes)
     are painted before the rules for the row-groups.  The painting order between
     multiple row-groups is whatever the <a href="https://drafts.csswg.org/css-tables">table spec</a>
     specifies.  For an individual row-group, the rules are painted in logical
     start to end order in both axes.
 
@@ -1169,23 +1171,24 @@ Rule Painting Order {#rule-painting-orde
 
 
 Rule Overflow {#rule-overflow}
 ==============================
 
     The column and row rule areas contributes to a fragment's [=ink overflow=].
     Note that they can overflow an fragment's border-box due to negative inset
     values etc.
-    For clarity, none of the properties in this spec affects layout in any way.
-    Column and row rules are purely a painting effect.
 
     <aside class=example>
         Here's an <a href="examples/grid-longitudinal-003.html">example</a> showing
         rules that overflow their container and how they are clipped.
         Both grids have large negative insets to extend the rules outside of the container.
         The right grid has ''overflow: hidden'' which clips its rules at the padding area edge.
         <figure>
             <img src="media/grid-longitudinal-003.png">
             <figcaption>
                 Examples of rule overflow and clipping.
             </figcaption>
         </figure>
     </aside>
+
+    For clarity, none of the properties in this spec affects layout in any way.
+    Column and row rules are purely a painting effect.
--- a/layout/docs/css-gap-decorations/Overview.html
+++ b/layout/docs/css-gap-decorations/Overview.html
@@ -5,16 +5,18 @@
   <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport">
   <meta content="exploring" name="csswg-work-status">
   <meta content="ED" name="w3c-status">
   <meta content="This is a proposal to extend <a href=&quot;https://drafts.csswg.org/css-align&quot;>CSS Box Alignment</a> to support gap decorations." name="abstract">
   <link href="../default.css" rel="stylesheet" type="text/css">
   <link href="../csslogo.ico" rel="shortcut icon" type="image/x-icon">
   <link href="https://www.w3.org/StyleSheets/TR/2016/W3C-ED" rel="stylesheet" type="text/css">
   <meta content="Bikeshed version d7036035b, updated Fri Oct 8 17:07:11 2021 -0700" name="generator">
+  <link href="https://matspalmgren.github.io/css-gap-decorations/Overview.html" rel="canonical">
+  <meta content="c1e56c61b4848a0a5f07159d3f21b96236447c53" name="document-revision">
 <style>/* style-autolinks */
 
 .css.css, .property.property, .descriptor.descriptor {
     color: var(--a-normal-text);
     font-size: inherit;
     font-family: inherit;
 }
 .css::before, .property::before, .descriptor::before {
@@ -696,23 +698,26 @@ dd:not(:last-child) > .wpt-tests-block:n
     c-[vm] { color: #cb4b16 } /* Name.Variable.Magic */
     c-[il] { color: #657b83 } /* Literal.Number.Integer.Long */
 }
 </style>
  <body class="h-entry">
   <div class="head">
    <p data-fill-with="logo"><a class="logo" href="https://www.w3.org/"> <img alt="W3C" height="48" src="https://www.w3.org/StyleSheets/TR/2016/logos/W3C" width="72"> </a> </p>
    <h1 class="p-name no-ref" id="title">CSS Gap Decorations</h1>
-   <h2 class="no-num no-toc no-ref heading settled" id="profile-and-date"><span class="content">Editor’s Draft, <time class="dt-updated" datetime="2021-10-21">21 October 2021</time></span></h2>
+   <h2 class="no-num no-toc no-ref heading settled" id="profile-and-date"><span class="content">Editor’s Draft, <time class="dt-updated" datetime="2021-10-22">22 October 2021</time></span></h2>
    <details>
     <summary>Specification Metadata</summary>
     <div data-fill-with="spec-metadata">
      <dl>
+      <dt>This version:
+      <dd><a class="u-url" href="https://matspalmgren.github.io/css-gap-decorations/Overview.html">https://matspalmgren.github.io/css-gap-decorations/Overview.html</a>
       <dt>Issue Tracking:
       <dd><a href="https://github.com/w3c/csswg-drafts/labels/css-gap-decorations-1">CSSWG Issues Repository</a>
+      <dd><a href="https://github.com/w3c/csswg-drafts/issues/6748">CSSWG github issue #6748</a>
       <dd><a href="#issues-index">Inline In Spec</a>
       <dt class="editor">Editor:
       <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:mats@mozilla.com">Mats Palmgren</a> (<a class="p-org org" href="http://mozilla.com">Mozilla Corporation</a>)
       <dt>Suggest an Edit for this Spec:
       <dd><a href="https://github.com/w3c/csswg-drafts/blob/main/css-gap-decorations-1/Overview.bs">GitHub Editor</a>
      </dl>
     </div>
    </details>
@@ -775,26 +780,26 @@ on screen, on paper, etc.
      </ol>
     <li>
      <a href="#row-rule-props"><span class="secno">4</span> <span class="content">Row Rule Style and Color</span></a>
      <ol class="toc">
       <li><a href="#row-rule-style"><span class="secno">4.1</span> <span class="content">The <span class="property">row-rule-style</span> and <span class="property">row-rule-color</span> Properties</span></a>
       <li><a href="#row-rule"><span class="secno">4.2</span> <span class="content">The <span class="property">row-rule</span> Shorthand</span></a>
      </ol>
     <li>
-     <a href="#column-rule-align"><span class="secno">5</span> <span class="content">Rule Alignment</span></a>
+     <a href="#rule-align"><span class="secno">5</span> <span class="content">Rule Alignment</span></a>
      <ol class="toc">
-      <li><a href="#column-rule-align①"><span class="secno">5.1</span> <span class="content">The <span class="property">column-rule-align</span> and <span class="property">row-rule-align</span> Properties</span></a>
+      <li><a href="#column-rule-align"><span class="secno">5.1</span> <span class="content">The <span class="property">column-rule-align</span> and <span class="property">row-rule-align</span> Properties</span></a>
       <li><a href="#column-rule-edge-align"><span class="secno">5.2</span> <span class="content">The <span class="property">column-rule-edge-align</span> and <span class="property">row-rule-edge-align</span> Properties</span></a>
      </ol>
     <li>
-     <a href="#column-rule-extent"><span class="secno">6</span> <span class="content">Rule Extent</span></a>
+     <a href="#rule-extent"><span class="secno">6</span> <span class="content">Rule Extent</span></a>
      <ol class="toc">
       <li>
-       <a href="#column-rule-extent①"><span class="secno">6.1</span> <span class="content">The <span class="property">column-rule-extent</span> and <span class="property">row-rule-extent</span> Properties</span></a>
+       <a href="#column-rule-extent"><span class="secno">6.1</span> <span class="content">The <span class="property">column-rule-extent</span> and <span class="property">row-rule-extent</span> Properties</span></a>
        <ol class="toc">
         <li>
          <a href="#rule-extent-grid"><span class="secno">6.1.1</span> <span class="content">Grid Containers</span></a>
          <ol class="toc">
           <li><a href="#rule-extent-subgrid"><span class="secno">6.1.1.1</span> <span class="content">Subgrid</span></a>
           <li><a href="#rule-extent-masonry"><span class="secno">6.1.1.2</span> <span class="content">Masonry</span></a>
          </ol>
         <li><a href="#rule-extent-flexbox"><span class="secno">6.1.2</span> <span class="content">Flex Containers</span></a>
@@ -1335,17 +1340,17 @@ on screen, on paper, etc.
     <figure>
       <img height="889" src="media/grid-longitudinal-001.png" width="629"> 
      <figcaption> Examples of rule sizing and inset values. </figcaption>
     </figure>
    </aside>
    <aside class="example" id="example-3020da77">
     <a class="self-link" href="#example-3020da77"></a> This <a href="examples/grid-longitudinal-002.html">example</a> demonstrates
         that the inset properties can be animated and that they are relative the <a data-link-type="dfn" href="#rule-containing-rectangle①" id="ref-for-rule-containing-rectangle①①⓪">rule containing rectangle</a>,
-        which itself depends on the <a href="#column-rule-align">rule’s alignment</a> in its longitudinal axis.
+        which itself depends on the <a href="#rule-align">rule’s alignment</a> in its longitudinal axis.
         Note that the longitudinal insets in this example are definite and not animated. The reason
         they follow the animated lateral position of the rule in the orthogonal axis is that they have <a href="#column-rule-align"><span class="css">rule</span> alignment</a>. 
     <figure>
      <video autoplay loop src="media/grid-longitudinal-002.webm"></video>
      <figcaption> Example of rule alignment and animated inset values. </figcaption>
     </figure>
    </aside>
    <h3 class="heading settled" data-level="3.7" id="column-rule-longitudinal-inset"><span class="secno">3.7. </span><span class="content">The <a class="property" data-link-type="propdesc" href="#propdef-column-rule-longitudinal-inset" id="ref-for-propdef-column-rule-longitudinal-inset">column-rule-longitudinal-inset</a> and <a class="property" data-link-type="propdesc" href="#propdef-row-rule-longitudinal-inset" id="ref-for-propdef-row-rule-longitudinal-inset">row-rule-longitudinal-inset</a> Shorthands</span><a class="self-link" href="#column-rule-longitudinal-inset"></a></h3>
@@ -1603,18 +1608,18 @@ on screen, on paper, etc.
       <td>per grammar 
    </table>
    <p class="issue" id="issue-53073ff7"><a class="self-link" href="#issue-53073ff7"></a> lots of new possible shorthands... we now have many
     properties (and shorthands) with a <span class="css">column-rule</span> and <span class="css">row-rule</span> prefix.
     Should we add shorthands for some of those with a <a class="property" data-link-type="propdesc">rule</a> prefix to specify
     both axes, like so: 'rule-foo: <span class="production">&lt;row-rule-foo></span> <span class="production">&lt;column-rule-foo></span>?'.
     As usual, we have to be careful with the separator though, to make it
     forward-compatible with any changes we might want to make...</p>
-   <h2 class="heading settled" data-level="5" id="column-rule-align"><span class="secno">5. </span><span class="content">Rule Alignment</span><a class="self-link" href="#column-rule-align"></a></h2>
-   <h3 class="heading settled" data-level="5.1" id="column-rule-align①"><span class="secno">5.1. </span><span class="content">The <a class="property" data-link-type="propdesc" href="#propdef-column-rule-align" id="ref-for-propdef-column-rule-align">column-rule-align</a> and <a class="property" data-link-type="propdesc" href="#propdef-row-rule-align" id="ref-for-propdef-row-rule-align">row-rule-align</a> Properties</span><a class="self-link" href="#column-rule-align①"></a></h3>
+   <h2 class="heading settled" data-level="5" id="rule-align"><span class="secno">5. </span><span class="content">Rule Alignment</span><a class="self-link" href="#rule-align"></a></h2>
+   <h3 class="heading settled" data-level="5.1" id="column-rule-align"><span class="secno">5.1. </span><span class="content">The <a class="property" data-link-type="propdesc" href="#propdef-column-rule-align" id="ref-for-propdef-column-rule-align">column-rule-align</a> and <a class="property" data-link-type="propdesc" href="#propdef-row-rule-align" id="ref-for-propdef-row-rule-align">row-rule-align</a> Properties</span><a class="self-link" href="#column-rule-align"></a></h3>
    <table class="def propdef" data-link-for-hint="column-rule-align">
     <tbody>
      <tr>
       <th>Name:
       <td><dfn class="dfn-paneled css" data-dfn-type="property" data-export id="propdef-column-rule-align">column-rule-align</dfn>, <dfn class="dfn-paneled css" data-dfn-type="property" data-export id="propdef-row-rule-align">row-rule-align</dfn>
      <tr class="value">
       <th><a href="https://www.w3.org/TR/css-values/#value-defs">Value:</a>
       <td class="prod">[gap <a data-link-type="grammar" href="https://drafts.csswg.org/css-values-4/#comb-one" id="ref-for-comb-one①②">|</a> gap-center <span id="ref-for-comb-one①③">|</span> gap-over <span id="ref-for-comb-one①④">|</span> rule <span id="ref-for-comb-one①⑤">|</span> rule-center <span id="ref-for-comb-one①⑥">|</span> rule-over]<a data-link-type="grammar" href="https://drafts.csswg.org/css-values-4/#mult-num-range" id="ref-for-mult-num-range①">{1,2}</a> 
@@ -1724,18 +1729,18 @@ on screen, on paper, etc.
     <c- k>row-rule</c-><c- p>:</c-> <c- m>16</c-><c- k>px</c-> solid #7000ff<c- p>;</c->
     <c- k>row-rule-lateral-inset-start</c-><c- p>:</c-> <c- m>30</c-><c- k>px</c-><c- p>;</c->
 </pre>
    <p>The alignment points follow the same pattern in the other axis for the row rules.
     In this case the row rule is using the initial values (<span class="css">gap</span>)
     so they align with the inline axis gap edges.</p>
    <p class="issue" id="issue-13842b6f"><a class="self-link" href="#issue-13842b6f"></a> Are there use cases for other box-related edge attachment points?
     e.g. 'padding | padding-center | padding-over | border...'</p>
-   <h2 class="heading settled" data-level="6" id="column-rule-extent"><span class="secno">6. </span><span class="content">Rule Extent</span><a class="self-link" href="#column-rule-extent"></a></h2>
-   <h3 class="heading settled" data-level="6.1" id="column-rule-extent①"><span class="secno">6.1. </span><span class="content">The <a class="property" data-link-type="propdesc" href="#propdef-column-rule-extent" id="ref-for-propdef-column-rule-extent">column-rule-extent</a> and <a class="property" data-link-type="propdesc" href="#propdef-row-rule-extent" id="ref-for-propdef-row-rule-extent">row-rule-extent</a> Properties</span><a class="self-link" href="#column-rule-extent①"></a></h3>
+   <h2 class="heading settled" data-level="6" id="rule-extent"><span class="secno">6. </span><span class="content">Rule Extent</span><a class="self-link" href="#rule-extent"></a></h2>
+   <h3 class="heading settled" data-level="6.1" id="column-rule-extent"><span class="secno">6.1. </span><span class="content">The <a class="property" data-link-type="propdesc" href="#propdef-column-rule-extent" id="ref-for-propdef-column-rule-extent">column-rule-extent</a> and <a class="property" data-link-type="propdesc" href="#propdef-row-rule-extent" id="ref-for-propdef-row-rule-extent">row-rule-extent</a> Properties</span><a class="self-link" href="#column-rule-extent"></a></h3>
    <table class="def propdef" data-link-for-hint="column-rule-extent">
     <tbody>
      <tr>
       <th>Name:
       <td><dfn class="dfn-paneled css" data-dfn-type="property" data-export id="propdef-column-rule-extent">column-rule-extent</dfn>, <dfn class="dfn-paneled css" data-dfn-type="property" data-export id="propdef-row-rule-extent">row-rule-extent</dfn>
      <tr class="value">
       <th><a href="https://www.w3.org/TR/css-values/#value-defs">Value:</a>
       <td class="prod">[segment <a data-link-type="grammar" href="https://drafts.csswg.org/css-values-4/#comb-one" id="ref-for-comb-one①⑨">|</a> start <span id="ref-for-comb-one②⓪">|</span> end <span id="ref-for-comb-one②①">|</span> short <span id="ref-for-comb-one②②">|</span> long <span id="ref-for-comb-one②③">|</span> all-start <span id="ref-for-comb-one②④">|</span> all-end <span id="ref-for-comb-one②⑤">|</span> all-short <span id="ref-for-comb-one②⑥">|</span> all-long ] allow-overlap<a data-link-type="grammar" href="https://drafts.csswg.org/css-values-4/#mult-opt" id="ref-for-mult-opt⑥">?</a> 
@@ -1947,19 +1952,19 @@ on screen, on paper, etc.
                guaranteed to have the exact same main axis <a data-link-type="dfn" href="https://drafts.csswg.org/css-sizing-3/#outer-size" id="ref-for-outer-size">outer size</a> and align such that
                the gaps are aligned between all the lines.</strong></p>
    <p>Rules are created between adjacent flex lines, and their <a data-link-type="dfn" href="#extent-size" id="ref-for-extent-size①③">extent sizes</a> are controlled by
     the <span class="css">row-rule-extent</span> values defined as follows:</p>
    <dl>
     <dt>segment
     <dd>behaves as <a class="css" data-link-type="maybe" href="#valdef-row-rule-extent-short" id="ref-for-valdef-row-rule-extent-short">short</a> 
     <dt>start
-    <dd>use the <a data-link-type="dfn" href="https://drafts.csswg.org/css-sizing-3/#outer-size" id="ref-for-outer-size①">outer size</a> of the items in the flex line on the inline axis start side 
+    <dd>use the <a data-link-type="dfn" href="https://drafts.csswg.org/css-sizing-3/#outer-size" id="ref-for-outer-size①">outer size</a> of the items in the flex line on the block axis start side 
     <dt>end
-    <dd>use the <a data-link-type="dfn" href="https://drafts.csswg.org/css-sizing-3/#outer-size" id="ref-for-outer-size②">outer size</a> of the items in the flex line on the inline axis end side 
+    <dd>use the <a data-link-type="dfn" href="https://drafts.csswg.org/css-sizing-3/#outer-size" id="ref-for-outer-size②">outer size</a> of the items in the flex line on the block axis end side 
     <dt>short
     <dd>use the <a data-link-type="dfn" href="https://drafts.csswg.org/css-sizing-3/#outer-size" id="ref-for-outer-size③">outer size</a> of the <a data-link-type="dfn" href="#next-flex-line-item" id="ref-for-next-flex-line-item">next flex line item</a> which has the smaller size (see detailed algorithm below) 
     <dt>long
     <dd>use the <a data-link-type="dfn" href="https://drafts.csswg.org/css-sizing-3/#outer-size" id="ref-for-outer-size④">outer size</a> of the <a data-link-type="dfn" href="#next-flex-line-item" id="ref-for-next-flex-line-item①">next flex line item</a> which has the larger size (see detailed algorithm below) 
     <dt>all-start
     <dd>the distance between the start position of the first item to the end position of the last item on the start side flex line 
     <dt>all-end
     <dd>the distance between the start position of the first item to the end position of the last item on the end side flex line 
@@ -2081,17 +2086,17 @@ on screen, on paper, etc.
         'column-span: <a class="production css" data-link-type="type" href="https://drafts.csswg.org/css-values-4/#integer-value" id="ref-for-integer-value">&lt;integer></a>' some time in the future,
         this is how row rules will work: 
     <figure>
       <img height="195" src="media/multicol-colspan-2.png" width="808"> 
      <figcaption> Example of <a class="css" data-link-type="propdesc" href="https://drafts.csswg.org/css-multicol-2/#propdef-column-span" id="ref-for-propdef-column-span">column-span: 2</a> in a multi-column with column and row rules. </figcaption>
     </figure>
    </aside>
    <h2 class="heading settled" data-level="7" id="rule-containing-rectangle"><span class="secno">7. </span><span class="content">The Rule Containing Rectangle</span><a class="self-link" href="#rule-containing-rectangle"></a></h2>
-   <p>The <dfn class="dfn-paneled" data-dfn-type="dfn" data-noexport id="rule-containing-rectangle①">rule containing rectangle</dfn> is formed by the <a href="#column-rule-extent">rule extent</a> and <a href="#column-rule-align">alignment</a> in the <a data-link-type="dfn" href="#longitudinal-axis" id="ref-for-longitudinal-axis⑦">longitudinal axis</a>, and by the size of the <a href="https://drafts.csswg.org/css-align/#gutter">gutter</a> in the <a data-link-type="dfn" href="#lateral-axis" id="ref-for-lateral-axis④">lateral axis</a>.
+   <p>The <dfn class="dfn-paneled" data-dfn-type="dfn" data-noexport id="rule-containing-rectangle①">rule containing rectangle</dfn> is formed by the <a href="#rule-extent">rule extent</a> and <a href="#rule-align">alignment</a> in the <a data-link-type="dfn" href="#longitudinal-axis" id="ref-for-longitudinal-axis⑦">longitudinal axis</a>, and by the size of the <a href="https://drafts.csswg.org/css-align/#gutter">gutter</a> in the <a data-link-type="dfn" href="#lateral-axis" id="ref-for-lateral-axis④">lateral axis</a>.
     (For clarity, the size of the gutter is calculated from the <a href="https://drafts.csswg.org/css-align/#gaps">gap</a> properties plus any extra space contributed by <a href="https://drafts.csswg.org/css-align/#distribution-values">alignment distribution</a> but does not include any item margins.)</p>
    <p>It is important to note that the <a data-link-type="dfn" href="#rule-containing-rectangle①" id="ref-for-rule-containing-rectangle①①④">rule containing rectangle’s</a> size in an axis isn’t affected by any of
     the <a href="#column-rule-lateral-inset">inset properties</a> <i>in the same axis</i> as that would lead to a circular
     dependency when resolving inset percentage values.  (The <span id="ref-for-rule-containing-rectangle①①⑤">rule containing rectangle</span> is the percentage basis
     for all the rule properties which take percentage values.) However, a rule that uses <a class="css" data-link-type="propdesc" href="#propdef-column-rule-align" id="ref-for-propdef-column-rule-align①">column-rule-align: rule | rule-center | rule-over</a> is affected by the <a href="#column-rule-lateral-inset">lateral inset properties</a> of the rule it aligns to in the <i>opposite axis</i>.</p>
    <p>Here’s an illustration of the <a data-link-type="dfn" href="#rule-containing-rectangle①" id="ref-for-rule-containing-rectangle①①⑥">rule containing rectangle</a> (the dashed green rectangle) for the top blue rule.
     This is a 2x2 grid using the default extent, so the <a data-link-type="dfn" href="#extent-size" id="ref-for-extent-size①⑤">extent size</a> is the row’s block size.
     It has the following non-default rule properties:</p>
@@ -2111,41 +2116,41 @@ on screen, on paper, etc.
     we move the bottom edge of the blue rule up by <span class="css">8px</span> with <a class="css" data-link-type="propdesc" href="#propdef-column-rule-longitudinal-inset-end" id="ref-for-propdef-column-rule-longitudinal-inset-end①">column-rule-longitudinal-inset-end: 8px</a>.
     The default <a class="css" data-link-type="propdesc" href="#propdef-column-rule-length" id="ref-for-propdef-column-rule-length①">column-rule-length: auto</a> then fills the resulting area.  If we were to use <span class="css" id="ref-for-propdef-column-rule-length②">column-rule-length: 100%</span> here instead, then the rule would fill the <span id="ref-for-rule-containing-rectangle①①⑧">rule containing rectangle</span> vertically, since that’s its percentage basis. (The end inset would then be ignored since the start inset
     is zero by default so the situation is over-constrained, and we resolve by ignoring the end inset, per the <a href="#rule-sizing">sizing rules</a>.)</p>
    <h2 class="heading settled" data-level="8" id="rule-painting-order"><span class="secno">8. </span><span class="content">Rule Painting Order</span><a class="self-link" href="#rule-painting-order"></a></h2>
    <p>Column and row rules are painted in the same layer as the element’s border.
     They are painted after (on top of) the element’s border.
     All column rules for an element are painted first, then all of its row rules.
     The rules for an axis are painted in the order they were generated by
-    the <a href="#column-rule-extent">rule extent</a> algorithms described above.
+    the <a href="#rule-extent">rule extent</a> algorithms described above.
     Typically from the logical start to the end of the axis.</p>
    <p>For table layout, all the <a data-link-type="dfn" href="https://drafts.csswg.org/css-tables-3/#table" id="ref-for-table①⑦">table</a> rules (in both axes)
     are painted before the rules for the row-groups.  The painting order between
     multiple row-groups is whatever the <a href="https://drafts.csswg.org/css-tables">table spec</a> specifies.  For an individual row-group, the rules are painted in logical
     start to end order in both axes.</p>
    <p>Again, note that for a specific fragment, <strong>all the column rules are painted before all the row rules</strong>,
     the above merely tries to clarify the painting order of the rules for
     a specific axis.</p>
    <h2 class="heading settled" data-level="9" id="rule-overflow"><span class="secno">9. </span><span class="content">Rule Overflow</span><a class="self-link" href="#rule-overflow"></a></h2>
    <p>The column and row rule areas contributes to a fragment’s <a data-link-type="dfn" href="https://drafts.csswg.org/css-overflow-3/#ink-overflow" id="ref-for-ink-overflow">ink overflow</a>.
     Note that they can overflow an fragment’s border-box due to negative inset
-    values etc.
-    For clarity, none of the properties in this spec affects layout in any way.
-    Column and row rules are purely a painting effect.</p>
+    values etc.</p>
    <aside class="example" id="example-13dcb258">
     <a class="self-link" href="#example-13dcb258"></a> Here’s an <a href="examples/grid-longitudinal-003.html">example</a> showing
         rules that overflow their container and how they are clipped.
         Both grids have large negative insets to extend the rules outside of the container.
         The right grid has <a class="css" data-link-type="propdesc" href="https://drafts.csswg.org/css-overflow-3/#propdef-overflow" id="ref-for-propdef-overflow">overflow: hidden</a> which clips its rules at the padding area edge. 
     <figure>
-      <img height="595" src="media/grid-longitudinal-003.png" width="766"> 
+      <img height="693" src="media/grid-longitudinal-003.png" width="760"> 
      <figcaption> Examples of rule overflow and clipping. </figcaption>
     </figure>
    </aside>
+   <p>For clarity, none of the properties in this spec affects layout in any way.
+    Column and row rules are purely a painting effect.</p>
   </main>
   <h2 class="no-ref no-num heading settled" id="w3c-conformance"><span class="content"> Conformance</span><a class="self-link" href="#w3c-conformance"></a></h2>
   <h3 class="no-ref heading settled" id="w3c-conventions"><span class="content"> Document conventions</span><a class="self-link" href="#w3c-conventions"></a></h3>
   <p>Conformance requirements are expressed with a combination of
     descriptive assertions and RFC 2119 terminology. The key words “MUST”,
     “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”,
     “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this
     document are to be interpreted as described in RFC 2119.
@@ -2821,17 +2826,17 @@ on screen, on paper, etc.
   <h2 class="no-num no-ref heading settled" id="references"><span class="content">References</span><a class="self-link" href="#references"></a></h2>
   <h3 class="no-num no-ref heading settled" id="normative"><span class="content">Normative References</span><a class="self-link" href="#normative"></a></h3>
   <dl>
    <dt id="biblio-css-backgrounds-3">[CSS-BACKGROUNDS-3]
    <dd>Bert Bos; Elika Etemad; Brad Kemper. <a href="https://www.w3.org/TR/css-backgrounds-3/"><cite>CSS Backgrounds and Borders Module Level 3</cite></a>. 26 July 2021. CR. URL: <a href="https://www.w3.org/TR/css-backgrounds-3/">https://www.w3.org/TR/css-backgrounds-3/</a>
    <dt id="biblio-css-box-4">[CSS-BOX-4]
    <dd>Elika Etemad. <a href="https://www.w3.org/TR/css-box-4/"><cite>CSS Box Model Module Level 4</cite></a>. 21 April 2020. WD. URL: <a href="https://www.w3.org/TR/css-box-4/">https://www.w3.org/TR/css-box-4/</a>
    <dt id="biblio-css-cascade-5">[CSS-CASCADE-5]
-   <dd>Elika Etemad; Miriam Suzanne; Tab Atkins Jr.. <a href="https://www.w3.org/TR/css-cascade-5/"><cite>CSS Cascading and Inheritance Level 5</cite></a>. 15 October 2021. WD. URL: <a href="https://www.w3.org/TR/css-cascade-5/">https://www.w3.org/TR/css-cascade-5/</a>
+   <dd>Elika Etemad; Miriam Suzanne; Tab Atkins Jr.. <a href="https://www.w3.org/TR/css-cascade-5/"><cite>CSS Cascading and Inheritance Level 5</cite></a>. 29 August 2021. WD. URL: <a href="https://www.w3.org/TR/css-cascade-5/">https://www.w3.org/TR/css-cascade-5/</a>
    <dt id="biblio-css-color-4">[CSS-COLOR-4]
    <dd>Tab Atkins Jr.; Chris Lilley. <a href="https://www.w3.org/TR/css-color-4/"><cite>CSS Color Module Level 4</cite></a>. 1 June 2021. WD. URL: <a href="https://www.w3.org/TR/css-color-4/">https://www.w3.org/TR/css-color-4/</a>
    <dt id="biblio-css-display-3">[CSS-DISPLAY-3]
    <dd>Tab Atkins Jr.; Elika Etemad. <a href="https://www.w3.org/TR/css-display-3/"><cite>CSS Display Module Level 3</cite></a>. 3 September 2021. CR. URL: <a href="https://www.w3.org/TR/css-display-3/">https://www.w3.org/TR/css-display-3/</a>
    <dt id="biblio-css-flexbox-1">[CSS-FLEXBOX-1]
    <dd>Tab Atkins Jr.; et al. <a href="https://www.w3.org/TR/css-flexbox-1/"><cite>CSS Flexible Box Layout Module Level 1</cite></a>. 19 November 2018. CR. URL: <a href="https://www.w3.org/TR/css-flexbox-1/">https://www.w3.org/TR/css-flexbox-1/</a>
    <dt id="biblio-css-grid-2">[CSS-GRID-2]
    <dd>Tab Atkins Jr.; Elika Etemad; Rossen Atanassov. <a href="https://www.w3.org/TR/css-grid-2/"><cite>CSS Grid Layout Module Level 2</cite></a>. 18 December 2020. CR. URL: <a href="https://www.w3.org/TR/css-grid-2/">https://www.w3.org/TR/css-grid-2/</a>
@@ -2843,17 +2848,17 @@ on screen, on paper, etc.
    <dd>Florian Rivoal; Rachel Andrew. <a href="https://www.w3.org/TR/css-multicol-1/"><cite>CSS Multi-column Layout Module Level 1</cite></a>. 12 October 2021. CR. URL: <a href="https://www.w3.org/TR/css-multicol-1/">https://www.w3.org/TR/css-multicol-1/</a>
    <dt id="biblio-css-overflow-3">[CSS-OVERFLOW-3]
    <dd>David Baron; Elika Etemad; Florian Rivoal. <a href="https://www.w3.org/TR/css-overflow-3/"><cite>CSS Overflow Module Level 3</cite></a>. 3 June 2020. WD. URL: <a href="https://www.w3.org/TR/css-overflow-3/">https://www.w3.org/TR/css-overflow-3/</a>
    <dt id="biblio-css-sizing-3">[CSS-SIZING-3]
    <dd>Tab Atkins Jr.; Elika Etemad. <a href="https://www.w3.org/TR/css-sizing-3/"><cite>CSS Box Sizing Module Level 3</cite></a>. 17 March 2021. WD. URL: <a href="https://www.w3.org/TR/css-sizing-3/">https://www.w3.org/TR/css-sizing-3/</a>
    <dt id="biblio-css-tables-3">[CSS-TABLES-3]
    <dd>François Remy; Greg Whitworth; David Baron. <a href="https://www.w3.org/TR/css-tables-3/"><cite>CSS Table Module Level 3</cite></a>. 27 July 2019. WD. URL: <a href="https://www.w3.org/TR/css-tables-3/">https://www.w3.org/TR/css-tables-3/</a>
    <dt id="biblio-css-values-4">[CSS-VALUES-4]
-   <dd>Tab Atkins Jr.; Elika Etemad. <a href="https://www.w3.org/TR/css-values-4/"><cite>CSS Values and Units Module Level 4</cite></a>. 16 October 2021. WD. URL: <a href="https://www.w3.org/TR/css-values-4/">https://www.w3.org/TR/css-values-4/</a>
+   <dd>Tab Atkins Jr.; Elika Etemad. <a href="https://www.w3.org/TR/css-values-4/"><cite>CSS Values and Units Module Level 4</cite></a>. 30 September 2021. WD. URL: <a href="https://www.w3.org/TR/css-values-4/">https://www.w3.org/TR/css-values-4/</a>
    <dt id="biblio-css-writing-modes-4">[CSS-WRITING-MODES-4]
    <dd>Elika Etemad; Koji Ishii. <a href="https://www.w3.org/TR/css-writing-modes-4/"><cite>CSS Writing Modes Level 4</cite></a>. 30 July 2019. CR. URL: <a href="https://www.w3.org/TR/css-writing-modes-4/">https://www.w3.org/TR/css-writing-modes-4/</a>
    <dt id="biblio-rfc2119">[RFC2119]
    <dd>S. Bradner. <a href="https://datatracker.ietf.org/doc/html/rfc2119"><cite>Key words for use in RFCs to Indicate Requirement Levels</cite></a>. March 1997. Best Current Practice. URL: <a href="https://datatracker.ietf.org/doc/html/rfc2119">https://datatracker.ietf.org/doc/html/rfc2119</a>
   </dl>
   <h3 class="no-num no-ref heading settled" id="informative"><span class="content">Informative References</span><a class="self-link" href="#informative"></a></h3>
   <dl>
    <dt id="biblio-css-multicol-2">[CSS-MULTICOL-2]
--- a/layout/docs/css-gap-decorations/examples/grid-longitudinal-003.html
+++ b/layout/docs/css-gap-decorations/examples/grid-longitudinal-003.html
@@ -37,10 +37,10 @@ x {
 pre {
   font-size: 10px;
 }
 </style>
 <body>
 <pre>Both grids have '*-edge-inset: min(-100vw, -100vh)'.
 The right grid has 'overflow: hidden' which clips its rules at the padding edge.</pre>
   <div class="grid test1"><x>1</x><x>2</x><x>3</x><x>4</x></div>
-  <div class="grid test2" style="top:20px "><x>1</x><x>2</x><x>3</x><x>4</x></div>
+  <div class="grid test2" style="top:100px "><x>1</x><x>2</x><x>3</x><x>4</x></div>
 </body>
index d40b06ac875ab4d278811fa0d0a28fd9d0445c5c..25052406549915a4dcf1f8fbaed05a6b59139a8c
GIT binary patch
literal 6875
zc%0o?XH=8fy8aLl6oe=$0#Zh-Fc6CLt_UJ1V?m^=G!-$FP(nYb6s4#L4k9ps$k3$;
z0YXHSB29WP(vePpP?Pfp@11qdnlrPGQ|^zu*GgIW-u>;p-|{@q`z7#)bDBH0b8klw
zWQW#i^$Q5HWf@+1%v<0W3BMg%;bWWKX#+<DVd0>?=#b|x_8|y&u$H>oCD+cWo-WMp
z#lE+5TsK%mo?c{saa%m@dbo8m!_JdhtPDZBXI0I8wa^9g@pE-5{Wk}w0=@Rv#2>`_
zaWm{Xg$lg<A%dIZrGVa1kzC8T+)sH^%A6#Nlk49dRblJtXq)i$ur4}SW9>g{<?MV!
zC#i{UuB91^iJ?b2ZamqEASaj*)iDHN=0%V=dPD$=Aotk*_rvEC9fFeo#pWAK!RFVd
zG@EZQ1)E=+(ro^$Db418KCb$1YZ}MycNSzNM0h8R^C=zS{4j`NQWbU7VEPZYgZucr
zK#^t|#>d7g=Qx+A@~dZ-UzC?Wlv7SrKVV;7;Tg)N`sO$1{_a+O*R%jLAJiY)o?~5q
zZ<W;C))rNE@&!cj9oH|;^V#-JO1_(rm6ZiX&d$!J1$J>nBDFl2M-8=m@7{=rh|8BR
zw>CG|#3*$=g*6SV?Cf4=W@ZwJDkK|;NJxwZ-F(}w%O)ngGuv2MS##gKd6SoS%HA<Y
zg}P4q(voUj_d?EL==6cd?FIIO&B+&eB@yQ6$xls9q&kI}p=Ffv>R7_`^mLbswTDMB
zfj~%2wOL!5%CV|-7=n{jN?hA_Sx-;IAlsrL{*<IuO=Wd;k;lq>RoIbGUIl4I#r+Iw
z5|JL{9v3t3jm2XZU+v>WP8?y`&B^)f>C>kX5msJGZVO{`gB6Y<_7P|^QzIjz3l|(n
zgO-~kQ2qL7U38U&1hX%NLJ`yqx!wM{^fA59r^vC9+9>i!6oxWfsukuiL9!u@*7p_T
zNWP3Ll<94f)^#4k;rh<g-CVX_)D7}PYkHI-E_;y4hpDQf8qZ_&<~IK9u=-vR!%L>7
zeCZdHFX`()!_x_1145(B$L5Etw{G$I^qumZ5(H;q@m>|&`o1F1rcGjEyeWx?89Cv<
zEbC42ure_;yd?lZx;_x9LJ3ed<zpyKGsu~Cos)ncv&;3(Ji`spW+mO5H&EBqtbpkW
ziwomTv7So?l60zLC?@?3<BoicnN?0kM%@NK&8~E8Y|NkE%XMRQ@rL7v2YYmtS6*g;
zrvvU1+{rNtE~19|moDAzE@;r%w2nLJf9{3s&UEYg7=mrrn_@-sMS9h-M;l(N<4I-y
z?3xqt@$r6sem9$5ak0S0)7m;ZIvN{yrISb`Gxw>yCr@^n!$ux078Vt`%=9WLE5jjP
zYK574F19>)u>I?`ty{M`Pj!Z$N%R$9E}Q+pX=a>l5lGuprQ6AqCu?hK;k{wRZwF6|
z+m~Zsr)X$sz!WJlF_dkFL5|hpmzHvxODBSZgFR<UnR<G98b%)M5pK;i!+cM3mZ^L+
zWhhJ+a*@MU)T9tg8mZl!z@`jY8tYAwGenyfyFwhV?c-)aID#?h1Rhv8Iy%~$+(hp4
zrlLcO*XOJ43)Nk)*xbB4sT|zu!gzkK+e8R4wXo2w>y0fNAHsLg`fCY3vMqLUlHum&
zc3AzXs@mq(Er)%G*qmI#p9i7;Z2G4_;*UY~znj{H-XF)xvlZ?1%l9ZwNGP+Z;XSk~
z&`6mtl*o(VYq-7%*9AuJ{i93LIxZxZzs{tCgBm90fn*0r{&#+Q>n);_G-#KTD#nUg
zan;oHZ~IZ<%)vXJ?3u3XQ%I#{-M1Z6?npf|B~ZzIN#|!3T~E&q6_1fF%(K2Zx!_<<
za}_4UA?#oF#c|IDONpMFo6~+KYEoeLdEmoCPfyP(3kN$pvG6nZuU)xvMHcYz!Gj0t
z2gF^bjdQjjabcE*Mn>eBKJRM&9c;AW?Bv9&<c6(!atL7Ln5bx7?XkSv-1X(b(8yY-
zw3HMfCU%59CO>2PAz+?UMF_8wl9F7(3{<F+*Ls0D;uH9mE4t`7rnmUZmoJ)pxR+^Z
zX+Qsbl(j5XKQl(oail%VoSvRu4aLgNE(1eadheb+!*y3QG&PM34I9UE1sPyhp7SIU
zfCv6oOG;y7BXRu(l#b&_jlrAS9T_G?g@uK_0tHZk&&<5=IMPUWWc}wd|FyNXy8=g#
z9zC6Sfo&hcCyFuIP!PVH)}DK_$@}s-4K+12@P=tGm2)VN;|MJ0Xdw%L-{(O(i(&wL
z^<JN=;1vOO*!NuAygVUPnVW{3E-o&jlZ(sC%e@5mii(Odv9#1wma<Qe!RdiXQMxO}
z1UD&8=ar(F5(U6a6oZtM)Sf+iLLjxy-R|*F7UayRIeR$FpN)6B@6|8O$vo1x?GT9d
zKw4%dItScgHA&7-OgvP$;5yZr*YxVFBkk&S;Yc0IQWvJ7@bzoEQeVco-oB-!rKTiZ
zCN(ja>F#i0eTX(nK1)hbvDlqFU2`P;a;9nY3d7~^ckI}~D{CiUi0RC|*?3TMH^LDx
z(}0(`klg(C?c3ywNhKRgU2$=7W2F$A&dyHPnPtkxn!msQU4fsIlatfZum@?&$LHka
z;PERFD$gY>KR%bTxn*NB=;^mfpS-*cl)|lC5F!pCVPP}3@x&)jp196f35Bmt=G4b8
zcIMe6>BdecGF^?gKlOn?UYjA#K*ak>JOu>>#d~YfCCdXJ!-dsQPoF(gA=OBlx*&%I
ztg+LkdU|>nFJ8>$<Kogf90ti`Yim0-GsDlzOZzf8*<Iqf7Q`hvkUs;IX=7^}-0I}y
zl%clu>h<}VCW5%-$ESG5(G0`9l&maqM>q4USNjR%ULGEvhaGhx!NF5KMKY@g-m4#Y
zjPGNF5dR2#>0n}F0{6)6XliO|ZQYyWsR&g4;UQ;2u{&jDlrRQn-Pw0~3Tp}p1SKnX
z@?x8r=EKn#_l$yq_UavP?+tTDuf-P^7ej8Z`bL6=z{>L`72&K)*yj36?=rFT6%Udy
z6qJ{_xj7Dp7i92ZD&vY?OMLxWER3<i^Czf%4vvQL7Xr-h#A@p6Wl)IgETFd8!qSo{
z(M!pYlasSzvZ*bSy``_bg5TR?;C<kYo==~C(9;|K8R;)|)EF(1^;ovEBDl_7r>8^W
zBpad?aq~^ODpTX*_*%#E@^ZHQva{7_qI%S|eaagPO(5^s@8@Sw?t|ERvpKS}vmp)c
zvv6v}W(aN8%`>#w^p`KIpZ)n)S63y7mct*zSvW<H%hQzCU}GW;R|*H4B1DXq-m#!T
z>o7-O0f>P8dY(NSeEuyxM-nFW`ar-Pm%E>;w&^O)z30IcH*|G%fs4Dk+#$nxWbSkq
z*qd8e9Aqtnbfi@^<Tu1VRB7qQHDln!s%$DcVspS+&ByOxfEA7M??^F0MO*(0zzc+x
zofzL6YieqS==T4+uKkSG{{C;Eylxqs1~RKV*^y&?VgvVOVxso*cXj``{W<6t2!G4)
znVT1x?rm>x2O|Xq1+;O&r@lV#!SY}M=Ityj+S=N}!otAHR*>aqn0bA^mz0%lZ)<Do
z>x*5Hiqv`4G(MIDjGmg25kh7Fbpi<8)!7+efbRgQfCI4s0&u^a!@<X=K`7Y+s)TUe
zV^eh=8z0AwM!Pt8F!OsZoOf{{PsK_qEBC@^Y02|kTLPgX=Kv?Mh!kT@O-YIP-XQx%
zLp+zH)zI*;Nr}hGP*oV9IS(Hno3B8mPRZJIQ6`bH`t;bvAeK1#M~n|1KGZ&Q=8U$s
zB#{qP?eg3pK0>zo89FmPUF6s?{K{PR=1@P7<v3brA;HC<=Iu>=ET}1cyS=|sZ4A+&
zsUCMytqgU(|D_gwQLc4`Gzu(%g9Pv<-;0#AE}8!*tl%;oBu%7J)|@6<&&DWr%$408
z8XQKtgGG$qbiZ;q@Nln)5E>oYntUlGHMP1Mj`O~vRvf!BZ%Gepp!j9Xd=w=lt_wgY
z2L=I*B58tj2SXgas>cfzZ{-|O5fLdA1W9}jib|ay&F*`(HO;`K*cDue7!0OnmV8Wu
zD!4<t!S(orgh80z;09u=UU@Ao5+WRMS6Dw|vMV2*W1z1;N@1rhbQOzTC}USC_S$gE
z#b5vM;7F`T;}zQ0N`W=%qZK&Qg@uHq?{wcdOtbF)6nFB-xfcPg(DL-Yu{AP{Sra;d
zMJl~iph|(q5}eMTKY#LM8SqvRBW%2NVsi5K&6|O(D=RCRge5~Qt-vhUNTnOdOi;Ca
z{QPi;#+O=|C9Ahiox1<^8c=MJ^VFHd3u>r)*Omt!qD2j|-_!PFK>++885x218;)gu
zJ9L#6pMISJ01Z>P_w5UiZUdq3ws^}NT>5AcphS7O|1KchredFH%aqwma~3-KocDay
z5l|F?(llVek*sJFP)v}eEA=YW{pp;bY9WqdtiksK%k%ZNbO*!2b#-;bwQ=AD>N8DK
zua#k0lXwMrc_5?b9g3c-3q}}%Q$?Sii3#X^X(sj)*6)%tGi4YY5rGNUiS0;$2x#1C
z4UpvLsDqE6wKX>niCrD|D|^@M)278P=*Opr*0sB_71opO4MUhMNY+r$Z)&vf4)-O5
zol7D_<Tp1j=*EzUTNzdV4(R#aW92`xW<aRwAaNonRXjZC=k#*b->Q2H+~rV?fmE&c
z4n%pcX))abLF@m{g+A2h?k05N<k!>NEMqzj?JV%uSNui?4DEM8Gc9W_O?F7eQ4|*!
z7pb$67@~<+#prQq)1Zz0m1qA&I_sb^8t9f?$}1|+&`o`QcmE+LdTDX-P*_!IY3U`Q
zJ$~1&UHc5&A|xcVEAV|c-m!K&AY{Z%TiYI@H&w*@xGZh7x3oAdj5Qq6j=0^ComfyH
zE0fgR*f>8Js$wP0!_A$NlCob>(Y3d5O99$zW3i1_!Fgd}VW__(7W6p4UkKgdEwp58
zgvK1eh#xof81N4oQZd#{Q-a$_O{956$PQLk1~oB7#cmkw?N=^cda7W~1)}EWO|7J+
z5I`c;rK<XRGrYraie4&!D|J4BCUgM}JF+dI9D$&>`}PBnnL(+H)J8d4EBmwaPtVM-
z`~LLPPXgg*<gU6F6gx4_&ZJ$*x())8Y9PnO$jAr|#Nnt^l`4)S=Ym2)Mk?*x+}(*Q
zBT)j(BlWRVkn;+L5Crk#=H)?}{GP`RlP)Afg&Vg|K>q-(ct~id|FtXn`ka1of^>28
zC|#M@c|1UZ=;XXhpQj6DeMNxz)~#FM;QjPKVeN%09vY&?kx@E_*?Hx6Gn9f>lmXzU
zMeDtRnVFfD5}c}i1_R`W9iOAA#IsQ&n^!MOM6OTe_r*Iw$b1=D1_;EdsVUHqY`#~g
zyYT?FSX%yEw{dlKB~SN6>Kdk-668tS(yl;%D{t4Yn%fIN`BIBwd2P#_k~~7z5DEtj
zlXd#ioZsiAaQyggr7NKHjEs0@c>5suv$J-aDm^?rJcI$<uY+}VmX?v}o7cSfN(U(N
zEa=VRdb=0$PALfqf}Lh<0)kk?;e@5-ur``->B5CwGd((q7if<-a!nyVKo5iko#VY)
zj0I%cvlvJcAO{QxobsX-+Oq__!y#th`T2S47+m>89Rt9~+a6$F@ZEz}K-?;ed5{w6
z>FFCA8wm*s@CBNFxIwJAxyJg^2Ba?h)KHj_Q72WYqZ6X-<8J=(=`mnfle}AcAT380
z%0bz?&k$&hR8BN64^LN-3ufU|K%n{oM<NR?#4@<~A?TPOlWycBB_#n}Tdlc5-b2l3
z;K=KwdiRE%@(A9tr_d?V$=%((W@&mNlNhqMUWsgMZ=dxnYFo7w`1KSHhXZ0-V3Y*j
zfo}Vp3#rb7cVJWMD!NvT_N{-n4pcEe@1V)d?gwotSsSYGFiZTJD%}Ytfy41lax^ab
zF*X(>Fx!ut*xp|<HZ?_{ai*xKXh=s=rX+s~F*sC(viv@fqoEK8DkbIP`O>?i;4)A9
z<=M|QZgT@4wr)8Ay@djtDJj;gv#H53YBVS~7@D4bXa)nN%fviZ$CHBD__kwA=+;@l
zL$;g4($cb}r3J)nkg|#14?jFQlPGFd(%sUs2)w<pxM=BB4P6PRsPPRfBwKd*SE-Aw
zNCMe0d7sl%OcXqsb-~yeIDYl{bM6FytVg^tt^<KGy{-xQ`T5}3{CqOx^`^ibEU&CQ
zz0dDr(z$4;X2@#55<d4yaWWp1$fL9G#J(4y4Ok)hW_RzV!0oxkrf5vbr~Ci=h-R3J
z?ybssGcyeHh-$0--}AH?3CLGJaE;j|*W8~ArTd!?TOM(EgtDPH#<86!AEMn~zm>nj
uVSnuJhyUY$D*g&Dq2x9G==S&?Q0W&K*fgX+?sY?8Xq`Hzo^j%;?>_-{^eM3b
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -437,18 +437,16 @@ class nsTextPaintStyle {
   bool InitSelectionColorsAndShadow();
 
   nsSelectionStyle* GetSelectionStyle(int32_t aIndex);
   void InitSelectionStyle(int32_t aIndex);
 
   // Ensures sufficient contrast between the frame background color and the
   // selection background color, and swaps the selection text and background
   // colors accordingly.
-  // Only used on platforms where mSelectionTextColor !=
-  // NS_SAME_AS_FOREGROUND_COLOR
   bool EnsureSufficientContrast(nscolor* aForeColor, nscolor* aBackColor);
 
   nscolor GetResolvedForeColor(nscolor aColor, nscolor aDefaultForeColor,
                                nscolor aBackColor);
 };
 
 static TextRunUserData* CreateUserData(uint32_t aMappedFlowCount) {
   TextRunUserData* data = static_cast<TextRunUserData*>(moz_xmalloc(
@@ -3833,38 +3831,51 @@ nsTextPaintStyle::nsTextPaintStyle(nsTex
   for (uint32_t i = 0; i < ArrayLength(mSelectionStyle); i++)
     mSelectionStyle[i].mInit = false;
 }
 
 bool nsTextPaintStyle::EnsureSufficientContrast(nscolor* aForeColor,
                                                 nscolor* aBackColor) {
   InitCommonColors();
 
+  const bool sameAsForeground = *aForeColor == NS_SAME_AS_FOREGROUND_COLOR;
+  if (sameAsForeground) {
+    *aForeColor = GetTextColor();
+  }
+
   // If the combination of selection background color and frame background color
   // has sufficient contrast, don't exchange the selection colors.
   //
   // Note we use a different threshold here: mSufficientContrast is for contrast
   // between text and background colors, but since we're diffing two
   // backgrounds, we don't need that much contrast.  We match the heuristic from
   // NS_SUFFICIENT_LUMINOSITY_DIFFERENCE_BG and use 20% of mSufficientContrast.
   const int32_t minLuminosityDifferenceForBackground = mSufficientContrast / 5;
   const int32_t backLuminosityDifference =
       NS_LUMINOSITY_DIFFERENCE(*aBackColor, mFrameBackgroundColor);
   if (backLuminosityDifference >= minLuminosityDifferenceForBackground) {
     return false;
   }
 
   // Otherwise, we should use the higher-contrast color for the selection
   // background color.
+  //
+  // For NS_SAME_AS_FOREGROUND_COLOR we only do this if the background is
+  // totally indistinguishable, that is, if the luminosity difference is 0.
+  if (sameAsForeground && backLuminosityDifference) {
+    return false;
+  }
+
   int32_t foreLuminosityDifference =
       NS_LUMINOSITY_DIFFERENCE(*aForeColor, mFrameBackgroundColor);
   if (backLuminosityDifference < foreLuminosityDifference) {
-    nscolor tmpColor = *aForeColor;
-    *aForeColor = *aBackColor;
-    *aBackColor = tmpColor;
+    std::swap(*aForeColor, *aBackColor);
+    // Ensure foreground color is opaque to guarantee contrast.
+    *aForeColor = NS_RGB(NS_GET_R(*aForeColor), NS_GET_G(*aForeColor),
+                         NS_GET_B(*aForeColor));
     return true;
   }
   return false;
 }
 
 nscolor nsTextPaintStyle::GetTextColor() {
   if (SVGUtils::IsInSVGTextSubtree(mFrame)) {
     if (!mResolveColors) {
@@ -4137,29 +4148,17 @@ bool nsTextPaintStyle::InitSelectionColo
       break;
     }
   }
 
   mSelectionTextColor =
       LookAndFeel::Color(LookAndFeel::ColorID::Highlighttext, mFrame);
 
   if (mResolveColors) {
-    // On MacOS X, only the background color gets set,
-    // the text color remains intact.
-    if (mSelectionTextColor == NS_SAME_AS_FOREGROUND_COLOR) {
-      nscolor frameColor =
-          SVGUtils::IsInSVGTextSubtree(mFrame)
-              ? mFrame->GetVisitedDependentColor(&nsStyleSVG::mFill)
-              : mFrame->GetVisitedDependentColor(
-                    &nsStyleText::mWebkitTextFillColor);
-      mSelectionTextColor =
-          EnsureDifferentColors(frameColor, mSelectionBGColor);
-    } else {
-      EnsureSufficientContrast(&mSelectionTextColor, &mSelectionBGColor);
-    }
+    EnsureSufficientContrast(&mSelectionTextColor, &mSelectionBGColor);
   }
   return true;
 }
 
 nsTextPaintStyle::nsSelectionStyle* nsTextPaintStyle::GetSelectionStyle(
     int32_t aIndex) {
   InitSelectionStyle(aIndex);
   return &mSelectionStyle[aIndex];
@@ -4221,27 +4220,29 @@ void nsTextPaintStyle::InitSelectionStyl
   NS_ASSERTION(backColor != NS_SAME_AS_FOREGROUND_COLOR,
                "backColor cannot be NS_SAME_AS_FOREGROUND_COLOR");
   NS_ASSERTION(backColor != NS_40PERCENT_FOREGROUND_COLOR,
                "backColor cannot be NS_40PERCENT_FOREGROUND_COLOR");
 
   if (mResolveColors) {
     foreColor = GetResolvedForeColor(foreColor, GetTextColor(), backColor);
 
-    if (NS_GET_A(backColor) > 0)
+    if (NS_GET_A(backColor) > 0) {
       EnsureSufficientContrast(&foreColor, &backColor);
+    }
   }
 
   nscolor lineColor;
   float relativeSize;
   uint8_t lineStyle;
   GetSelectionUnderline(mFrame, aIndex, &lineColor, &relativeSize, &lineStyle);
 
-  if (mResolveColors)
+  if (mResolveColors) {
     lineColor = GetResolvedForeColor(lineColor, foreColor, backColor);
+  }
 
   selectionStyle->mTextColor = foreColor;
   selectionStyle->mBGColor = backColor;
   selectionStyle->mUnderlineColor = lineColor;
   selectionStyle->mUnderlineStyle = lineStyle;
   selectionStyle->mUnderlineRelativeSize = relativeSize;
   selectionStyle->mInit = true;
 }
--- a/layout/inspector/InspectorUtils.cpp
+++ b/layout/inspector/InspectorUtils.cpp
@@ -30,16 +30,17 @@
 #include "mozilla/dom/InspectorUtilsBinding.h"
 #include "mozilla/dom/LinkStyle.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "nsCSSProps.h"
 #include "nsCSSValue.h"
 #include "nsColor.h"
 #include "mozilla/ServoStyleSet.h"
 #include "nsLayoutUtils.h"
+#include "nsNameSpaceManager.h"
 #include "nsStyleUtil.h"
 #include "nsQueryObject.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/ServoStyleRuleMap.h"
 #include "mozilla/ServoCSSParser.h"
 #include "mozilla/StaticPrefs_layout.h"
 #include "mozilla/dom/InspectorUtils.h"
 #include "mozilla/dom/InspectorFontFace.h"
@@ -688,18 +689,18 @@ void InspectorUtils::ParseStyleSheet(Glo
 
 bool InspectorUtils::IsCustomElementName(GlobalObject&, const nsAString& aName,
                                          const nsAString& aNamespaceURI) {
   if (aName.IsEmpty()) {
     return false;
   }
 
   int32_t namespaceID;
-  nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
-                                                        namespaceID);
+  nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespaceURI,
+                                                       namespaceID);
 
   RefPtr<nsAtom> nameElt = NS_Atomize(aName);
   return nsContentUtils::IsCustomElementName(nameElt, namespaceID);
 }
 
 bool InspectorUtils::IsElementThemed(GlobalObject&, Element& aElement) {
   // IsThemed will check if the native theme supports the widget using
   // ThemeSupportsWidget which in turn will check that the widget is not
--- a/layout/style/GeckoBindings.cpp
+++ b/layout/style/GeckoBindings.cpp
@@ -807,20 +807,20 @@ static nsAtom* LangValue(Implementor* aE
 }
 
 template <typename Implementor, typename MatchFn>
 static bool DoMatch(Implementor* aElement, nsAtom* aNS, nsAtom* aName,
                     MatchFn aMatch) {
   if (MOZ_LIKELY(aNS)) {
     int32_t ns = aNS == nsGkAtoms::_empty
                      ? kNameSpaceID_None
-                     : nsContentUtils::NameSpaceManager()->GetNameSpaceID(
+                     : nsNameSpaceManager::GetInstance()->GetNameSpaceID(
                            aNS, aElement->IsInChromeDocument());
 
-    MOZ_ASSERT(ns == nsContentUtils::NameSpaceManager()->GetNameSpaceID(
+    MOZ_ASSERT(ns == nsNameSpaceManager::GetInstance()->GetNameSpaceID(
                          aNS, aElement->IsInChromeDocument()));
     NS_ENSURE_TRUE(ns != kNameSpaceID_Unknown, false);
     const nsAttrValue* value = aElement->GetParsedAttr(aName, ns);
     return value && aMatch(value);
   }
 
   // No namespace means any namespace - we have to check them all. :-(
   BorrowedAttrInfo attrInfo;
--- a/layout/svg/SVGImageFrame.cpp
+++ b/layout/svg/SVGImageFrame.cpp
@@ -471,16 +471,19 @@ bool SVGImageFrame::CreateWebRenderComma
   }
 
   if (!mImageContainer) {
     // nothing to draw (yet)
     return true;
   }
 
   uint32_t flags = aDisplayListBuilder->GetImageDecodeFlags();
+  if (mForceSyncDecoding) {
+    flags |= imgIContainer::FLAG_SYNC_DECODE;
+  }
 
   // Compute bounds of the image
   nscoord appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel();
   int32_t appUnitsPerCSSPixel = AppUnitsPerCSSPixel();
 
   float x, y, width, height;
   SVGImageElement* imgElem = static_cast<SVGImageElement*>(GetContent());
   SVGGeometryProperty::ResolveAll<SVGT::X, SVGT::Y, SVGT::Width, SVGT::Height>(
--- a/modules/libpref/init/StaticPrefList.yaml
+++ b/modules/libpref/init/StaticPrefList.yaml
@@ -6083,16 +6083,22 @@
   mirror: always
 
   # Experimental support for the ergonomic brand check proposal.
 - name: javascript.options.experimental.ergonomic_brand_checks
   type: bool
   value: true
   mirror: always
 
+  # Experimental support for change-array-by-copy methods
+- name: javascript.options.experimental.enable_change_array_by_copy
+  type: bool
+  value: false
+  mirror: always
+
   # Experimental support for Top-level Await in JavaScript.
 -   name: javascript.options.experimental.top_level_await
     type: bool
     value: true
     mirror: always
 
 - name: javascript.options.wasm_caching
   type: bool
--- a/netwerk/cookie/CookieService.cpp
+++ b/netwerk/cookie/CookieService.cpp
@@ -1435,18 +1435,16 @@ bool CookieService::ParseAttributes(nsIC
                             equalsFound);
   if (equalsFound) {
     aCookieData.name() = tokenString;
     aCookieData.value() = tokenValue;
   } else {
     aCookieData.value() = tokenString;
   }
 
-  bool sameSiteSet = false;
-
   // extract remaining attributes
   while (cookieStart != cookieEnd && !newCookie) {
     newCookie = GetTokenValue(cookieStart, cookieEnd, tokenString, tokenValue,
                               equalsFound);
 
     // decide which attribute we have, and copy the string
     if (tokenString.LowerCaseEqualsLiteral(kPath)) {
       aCookieData.path() = tokenValue;
@@ -1468,40 +1466,33 @@ bool CookieService::ParseAttributes(nsIC
       // just set the boolean
     } else if (tokenString.LowerCaseEqualsLiteral(kHttpOnly)) {
       aCookieData.isHttpOnly() = true;
 
     } else if (tokenString.LowerCaseEqualsLiteral(kSameSite)) {
       if (tokenValue.LowerCaseEqualsLiteral(kSameSiteLax)) {
         aCookieData.sameSite() = nsICookie::SAMESITE_LAX;
         aCookieData.rawSameSite() = nsICookie::SAMESITE_LAX;
-        sameSiteSet = true;
       } else if (tokenValue.LowerCaseEqualsLiteral(kSameSiteStrict)) {
         aCookieData.sameSite() = nsICookie::SAMESITE_STRICT;
         aCookieData.rawSameSite() = nsICookie::SAMESITE_STRICT;
-        sameSiteSet = true;
       } else if (tokenValue.LowerCaseEqualsLiteral(kSameSiteNone)) {
         aCookieData.sameSite() = nsICookie::SAMESITE_NONE;
         aCookieData.rawSameSite() = nsICookie::SAMESITE_NONE;
-        sameSiteSet = true;
       } else {
         // Reset to defaults if unknown token value (see Bug 1682450)
         SetSameSiteDefaultAttribute(aCookieData, laxByDefault);
-        sameSiteSet = false;
         CookieLogging::LogMessageToConsole(
             aCRC, aHostURI, nsIScriptError::infoFlag, CONSOLE_SAMESITE_CATEGORY,
             "CookieSameSiteValueInvalid2"_ns,
             AutoTArray<nsString, 1>{NS_ConvertUTF8toUTF16(aCookieData.name())});
       }
     }
   }
 
-  Telemetry::Accumulate(Telemetry::COOKIE_SAMESITE_SET_VS_UNSET,
-                        sameSiteSet ? 1 : 0);
-
   // re-assign aCookieHeader, in case we need to process another cookie
   aCookieHeader.Assign(Substring(cookieStart, cookieEnd));
 
   // If same-site is set to 'none' but this is not a secure context, let's abort
   // the parsing.
   if (!aCookieData.isSecure() &&
       aCookieData.sameSite() == nsICookie::SAMESITE_NONE) {
     if (laxByDefault &&
new file mode 100644
--- /dev/null
+++ b/netwerk/docs/http/lifecycle.rst
@@ -0,0 +1,222 @@
+The lifecycle of a HTTP request
+===============================
+
+
+HTTP requests in Firefox go through several steps.  Each piece of the request message and response message become available at certain points.  Extracting that information is a challenge, though.
+
+What is available when
+----------------------
+
++-----------------------+---------------------------------------------------+---------------------------------------+------------------------+-------------------------------+
+| Data                  | When it's available                               | Sample JS code                        | Interfaces             | Test code                     |
++=======================+===================================================+=======================================+========================+===============================+
+| HTTP request method   | *http-on-modify-request* observer notification    | channel.requestMethod                 | nsIHttpChannel_        |                               |
++-----------------------+---------------------------------------------------+---------------------------------------+------------------------+-------------------------------+
+| HTTP request URI      | *http-on-modify-request* observer notification    | channel.URI                           | nsIChannel_            |                               |
++-----------------------+---------------------------------------------------+---------------------------------------+------------------------+-------------------------------+
+| HTTP request headers  | *http-on-modify-request* observer notification    | channel.visitRequestHeaders(visitor)  | nsIHttpChannel_        |                               |
++-----------------------+---------------------------------------------------+---------------------------------------+------------------------+-------------------------------+
+| HTTP request body     | *http-on-modify-request* observer notification    | channel.uploadStream                  | nsIUploadChannel_      |                               |
++-----------------------+---------------------------------------------------+---------------------------------------+------------------------+-------------------------------+
+|| HTTP response status || *http-on-examine-response* observer notification || channel.responseStatus               || nsIHttpChannel_       || test_basic_functionality.js_ |
+||                      ||                                                  || channel.responseStatusText           ||                       ||                              |
++-----------------------+---------------------------------------------------+---------------------------------------+------------------------+-------------------------------+
+| HTTP response headers | *http-on-examine-response* observer notification  | channel.visitResponseHeaders(visitor) | nsIHttpChannel_        |                               |
++-----------------------+---------------------------------------------------+---------------------------------------+------------------------+-------------------------------+
+|| HTTP response body   || *onStopRequest* via stream listener tee          || See below                            || nsITraceableChannel_  || test_traceable_channel.js_   |
+||                      ||                                                  ||                                      || nsIStreamListenerTee_ ||                              |
+||                      ||                                                  ||                                      || nsIPipe_              ||                              |
++-----------------------+---------------------------------------------------+---------------------------------------+------------------------+-------------------------------+
+
+The request: http-on-modify-request
+-----------------------------------
+
+Firefox fires a "http-on-modify-request" observer notification before sending the HTTP request, and this blocks the sending of the request until all observers exit.  This is generally the point at which you can modify the HTTP request headers (hence the name).
+
+Attaching a listener for a request is pretty simple::
+
+  const obs = {
+    QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
+
+    observe: function(channel, topic, data) {
+      if (!(channel instanceof Ci.nsIHttpChannel))
+        return;
+
+      // process the channel's data
+    }
+  }
+
+  const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+  Services.obs.addObserver(observer, "http-on-modify-request", false);
+
+See nsIObserverService_ for the details.
+
+The request method and URI are immediately available at this time.  Request headers are trivially easy to get::
+
+  /**
+   * HTTP header visitor.
+   */
+  class HeaderVisitor {
+    #targetObject;
+
+    constructor(targetObject) {
+      this.#targetObject = targetObject;
+    }
+
+    // nsIHttpHeaderVisitor
+    visitHeader(header, value) {
+      this.#targetObject[header] = value;
+    }
+
+    QueryInterface = ChromeUtils.generateQI(["nsIHttpHeaderVisitor"]);
+  }
+
+  // ...
+  const requestHeaders = {};
+  const visitor = new HeaderVisitor(requestHeaders);
+  channel.visitRequestHeaders(visitor);
+
+This is also the time to set request headers, if you need to.  The method for that on the nsIHttpChannel_ interface is `channel.setRequestHeader(header, value);`
+
+Most HTTP requests don't have a body, as they are GET requests.  POST requests often have them, though.  As the nsIUploadChannel_ documentation indicates, the body of most HTTP requests is available via a seekable stream (nsISeekableStream_).  So you can simply capture the body stream and its current position, to revisit it later.  network-helper.js_ has code to read the request body.
+
+The response: http-on-examine-response
+--------------------------------------
+
+Firefox fires a "http-on-examine-response" observer notification after parsing the HTTP response status and headers, but **before** reading the response body.  Attaching a listener for this phase is also very easy::
+
+  const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+  Services.obs.addObserver(observer, "http-on-examine-response", false);
+
+If you use the same observer for "http-on-modify-request" and "http-on-examine-response", make sure you check the topic argument before interacting with the channel.
+
+The response status is available via the *responseStatus* and *responseStatusText* properties.  The response headers are available via the *visitResponseHeaders* method, and requires the same interface.
+
+The response body: onStopRequest, stream listener tee
+-----------------------------------------------------
+
+During the "http-on-examine-response" notification, the response body is *not* available.  You can, however, use a stream listener tee to *copy* the stream so that the original stream data goes on, and you have a separate input stream you can read from with the same data.
+
+Here's some sample code to illustrate what you need::
+
+  const Pipe = Components.Constructor(
+    "@mozilla.org/pipe;1",
+    "nsIPipe",
+    "init"
+  );
+  const StreamListenerTee = Components.Constructor(
+    "@mozilla.org/network/stream-listener-tee;1",
+    "nsIStreamListenerTee"
+  );
+  const ScriptableStream = Components.Constructor(
+    "@mozilla.org/scriptableinputstream;1",
+    "nsIScriptableInputStream",
+    "init"
+  );
+
+  const obs = {
+    QueryInterface: ChromeUtils.generateQI(["nsIObserver", "nsIRequestObserver"]),
+
+    /** @typedef {WeakMap<nsIHttpChannel, nsIPipe>} */
+    requestToTeePipe: new WeakMap,
+
+    // nsIObserver
+    observe: function(channel, topic, data) {
+      if (!(channel instanceof Ci.nsIHttpChannel))
+        return;
+
+      /* Create input and output streams to take the new data.
+         The 0xffffffff argument is the segment count.
+         It has to be this high because you don't know how much data is coming in the response body.
+
+         As for why these are blocking streams:  I believe this is because there's no actual need to make them non-blocking.
+         The stream processing happens during onStopRequest(), so we have all the data then and the operation can be synchronous.
+         But I could be very wrong on this.
+      */
+      const pipe = new Pipe(false, false, 0, 0xffffffff);
+
+      // Install the stream listener tee to intercept the HTTP body.
+      const tee = new StreamListenerTee;
+      const originalListener = channel.setNewListener(tee);
+      tee.init(originalListener, pipe.outputStream, this);
+
+      this.requestToTeePipe.set(channel, pipe);
+    }
+
+    // nsIRequestObserver
+    onStartRequest: function() {
+      // do nothing
+    }
+
+    // nsIRequestObserver
+    onStopRequest: function(channel, statusCode) {
+      const pipe = this.requestToTeePipe.get(channel);
+
+      // No more data coming in anyway.
+      pipe.outputStream.close();
+      this.requestToTeePipe.delete(channel);
+
+      let length = 0;
+      try {
+        length = pipe.inputStream.available();
+      }
+      catch (e) {
+        if (e.result === Components.results.NS_BASE_STREAM_CLOSED)
+          throw e;
+      }
+
+      let responseBody = "";
+      if (length) {
+        // C++ code doesn't need the scriptable input stream.
+        const sin = new ScriptableStream(pipe.inputStream);
+        responseBody = sin.read(length);
+        sin.close();
+      }
+
+      void(responseBody); // do something with the body
+    }
+  }
+
+test_traceable_channel.js_ does essentially this.
+
+Character encodings and compression
+-----------------------------------
+
+Canceling requests
+------------------
+
+HTTP activity distributor notes
+-------------------------------
+
+URIContentLoader notes
+----------------------
+
+Order of operations
+-------------------
+
+1. The HTTP channel is constructed.
+2. The "http-on-modify-request" observer service notification fires.
+3. If the request has been canceled, exit at this step.
+4. The HTTP channel's request is submitted to the server.  Time passes.
+5. The HTTP channel's response comes in from the server.
+6. The HTTP channel parses the response status and headers.
+7. The "http-on-examine-response" observer service notification fires.
+
+Useful code samples and references
+----------------------------------
+
+- nsIHttpProtocolHandler_ defines a lot of observer topics, and has a lot of details.
+
+.. _nsIHttpChannel: https://searchfox.org/mozilla-central/source/netwerk/protocol/http/nsIHttpChannel.idl
+.. _nsIChannel: https://searchfox.org/mozilla-central/source/netwerk/base/nsIChannel.idl
+.. _nsIUploadChannel: https://searchfox.org/mozilla-central/source/netwerk/base/nsIUploadChannel.idl
+.. _nsITraceableChannel: https://searchfox.org/mozilla-central/source/netwerk/base/nsITraceableChannel.idl
+.. _nsISeekableStream: https://searchfox.org/mozilla-central/source/xpcom/io/nsISeekableStream.idl
+.. _nsIObserverService: https://searchfox.org/mozilla-central/source/xpcom/ds/nsIObserverService.idl
+.. _nsIHttpProtocolHandler: https://searchfox.org/mozilla-central/source/netwerk/protocol/http/nsIHttpProtocolHandler.idl
+.. _nsIStreamListenerTee: https://searchfox.org/mozilla-central/source/netwerk/base/nsIStreamListenerTee.idl
+.. _nsIPipe: https://searchfox.org/mozilla-central/source/xpcom/io/nsIPipe.idl
+
+.. _test_basic_functionality.js: https://searchfox.org/mozilla-central/source/netwerk/test/httpserver/test/test_basic_functionality.js
+.. _test_traceable_channel.js: https://searchfox.org/mozilla-central/source/netwerk/test/unit/test_traceable_channel.js
+.. _network-helper.js: https://searchfox.org/mozilla-central/source/devtools/shared/webconsole/network-helper.js
--- a/netwerk/docs/index.rst
+++ b/netwerk/docs/index.rst
@@ -2,10 +2,11 @@ Networking
 ==========
 
 These linked pages contain design documents for the Networking stack implementation in Gecko. They live in-tree under the 'netwerk/docs' directory.
 
 .. toctree::
    :maxdepth: 1
 
    cache2/doc
+   http/lifecycle
    http/logging
    dns/dns-over-https-trr
--- a/netwerk/protocol/http/Http2Session.cpp
+++ b/netwerk/protocol/http/Http2Session.cpp
@@ -209,18 +209,17 @@ void Http2Session::Shutdown(nsresult aRe
       CloseStream(stream, NS_ERROR_NET_RESET);  // can be restarted
     } else if (stream->RecvdData()) {
       CloseStream(stream, NS_ERROR_NET_PARTIAL_TRANSFER);
     } else if (mGoAwayReason == INADEQUATE_SECURITY) {
       CloseStream(stream, NS_ERROR_NET_INADEQUATE_SECURITY);
     } else if (!mCleanShutdown && (mGoAwayReason != NO_HTTP_ERROR)) {
       CloseStream(stream, NS_ERROR_NET_HTTP2_SENT_GOAWAY);
     } else if (!mCleanShutdown &&
-               (aReason ==
-                psm::GetXPCOMFromNSSError(SSL_ERROR_PROTOCOL_VERSION_ALERT))) {
+               SecurityErrorToBeHandledByTransaction(aReason)) {
       CloseStream(stream, aReason);
     } else {
       CloseStream(stream, NS_ERROR_ABORT);
     }
   }
 }
 
 Http2Session::~Http2Session() {
--- a/netwerk/protocol/http/nsHttp.cpp
+++ b/netwerk/protocol/http/nsHttp.cpp
@@ -17,16 +17,17 @@
 #include "nsCRT.h"
 #include "nsContentUtils.h"
 #include "nsHttpRequestHead.h"
 #include "nsHttpResponseHead.h"
 #include "nsHttpHandler.h"
 #include "nsICacheEntry.h"
 #include "nsIRequest.h"
 #include "nsJSUtils.h"
+#include "sslerr.h"
 #include <errno.h>
 #include <functional>
 #include "nsLiteralString.h"
 #include <string.h>
 
 namespace mozilla {
 namespace net {
 
@@ -983,10 +984,16 @@ SupportedAlpnType IsAlpnSupported(const 
 
   if (aAlpn.LowerCaseEqualsASCII("http/1.1")) {
     return SupportedAlpnType::HTTP_1_1;
   }
 
   return SupportedAlpnType::NOT_SUPPORTED;
 }
 
+bool SecurityErrorToBeHandledByTransaction(nsresult aReason) {
+  return (aReason ==
+          psm::GetXPCOMFromNSSError(SSL_ERROR_PROTOCOL_VERSION_ALERT)) ||
+         (aReason == psm::GetXPCOMFromNSSError(SSL_ERROR_BAD_MAC_ALERT));
+}
+
 }  // namespace net
 }  // namespace mozilla
--- a/netwerk/protocol/http/nsHttp.h
+++ b/netwerk/protocol/http/nsHttp.h
@@ -395,12 +395,14 @@ SupportedAlpnType IsAlpnSupported(const 
 
 static inline bool AllowedErrorForHTTPSRRFallback(nsresult aError) {
   return psm::IsNSSErrorCode(-1 * NS_ERROR_GET_CODE(aError)) ||
          aError == NS_ERROR_NET_RESET ||
          aError == NS_ERROR_CONNECTION_REFUSED ||
          aError == NS_ERROR_UNKNOWN_HOST || aError == NS_ERROR_NET_TIMEOUT;
 }
 
+bool SecurityErrorToBeHandledByTransaction(nsresult aReason);
+
 }  // namespace net
 }  // namespace mozilla
 
 #endif  // nsHttp_h__
--- a/netwerk/protocol/http/nsHttpTransaction.cpp
+++ b/netwerk/protocol/http/nsHttpTransaction.cpp
@@ -1325,18 +1325,17 @@ void nsHttpTransaction::MaybeReportFaile
 
 bool nsHttpTransaction::ShouldRestartOn0RttError(nsresult reason) {
   LOG(
       ("nsHttpTransaction::ShouldRestartOn0RttError [this=%p, "
        "mEarlyDataWasAvailable=%d error=%" PRIx32 "]\n",
        this, mEarlyDataWasAvailable, static_cast<uint32_t>(reason)));
   return StaticPrefs::network_http_early_data_disable_on_error() &&
          mEarlyDataWasAvailable &&
-         (reason ==
-          psm::GetXPCOMFromNSSError(SSL_ERROR_PROTOCOL_VERSION_ALERT));
+         SecurityErrorToBeHandledByTransaction(reason);
 }
 
 void nsHttpTransaction::Close(nsresult reason) {
   LOG(("nsHttpTransaction::Close [this=%p reason=%" PRIx32 "]\n", this,
        static_cast<uint32_t>(reason)));
 
   if (!mClosed) {
     gHttpHandler->ConnMgr()->RemoveActiveTransaction(this);
--- a/python/mozbuild/mozbuild/vendor/rewrite_mozbuild.py
+++ b/python/mozbuild/mozbuild/vendor/rewrite_mozbuild.py
@@ -178,17 +178,17 @@ statistic_
     improvements.
 """
 
 import os
 import re
 import ast
 import sys
 import copy
-import fileinput
+import shutil
 import subprocess
 
 from pprint import pprint
 
 try:
     from mozbuild.frontend.sandbox import alphabetical_sorted
 except Exception:
 
@@ -497,26 +497,30 @@ def mozbuild_file_to_source_assignments(
 
     return (source_assignments, root, code)
 
 
 def unnormalize_filename(normalized_mozbuild_filename, normalized_filename):
     if normalized_filename[0] == "/":
         return normalized_filename
 
-    mozbuild_path = os.path.dirname(normalized_mozbuild_filename) + "/"
+    mozbuild_path = (
+        os.path.dirname(normalized_mozbuild_filename).replace(os.path.sep, "/") + "/"
+    )
     return normalized_filename.replace(mozbuild_path, "")
 
 
 def normalize_filename(normalized_mozbuild_filename, filename):
     if filename[0] == "/":
         return filename
 
-    mozbuild_path = os.path.dirname(normalized_mozbuild_filename)
-    return os.path.join(mozbuild_path, filename)
+    mozbuild_path = os.path.dirname(normalized_mozbuild_filename).replace(
+        os.path.sep, "/"
+    )
+    return os.path.join(mozbuild_path, filename).replace(os.path.sep, "/")
 
 
 def get_mozbuild_file_search_order(
     normalized_filename,
     moz_yaml_dir=None,
     vendoring_dir=None,
     all_mozbuild_filenames_normalized=None,
 ):
@@ -582,17 +586,19 @@ def get_mozbuild_file_search_order(
         # In this situation, the library is vendored in a different place (typically
         # third_party/foo) from the moz.build files.
         subdirectory_path = normalized_filename.replace(vendoring_dir, "")
         test_directory = os.path.join(moz_yaml_dir, subdirectory_path)
     else:
         raise Exception("If moz_yaml_dir or vendoring_dir are specified, both must be")
 
     # Step 1
-    while len(os.path.dirname(test_directory)) > 1:  # While we are not at '/'
+    while (
+        len(os.path.dirname(test_directory).replace(os.path.sep, "/")) > 1
+    ):  # While we are not at '/'
         containing_directory = os.path.dirname(test_directory)
 
         possible_normalized_mozbuild_filename = os.path.join(
             containing_directory, "moz.build"
         )
 
         if not all_mozbuild_filenames_normalized:
             if os.path.isfile(possible_normalized_mozbuild_filename):
@@ -639,18 +645,23 @@ def filenames_directory_is_in_filename_l
     directory of the filename is in the list.
 
     ex:
         f = filenames_directory_is_in_filename_list
         f("foo/bar/a.c", ["foo/b.c"]) -> false
         f("foo/bar/a.c", ["foo/b.c", "foo/bar/c.c"]) -> true
         f("foo/bar/a.c", ["foo/b.c", "foo/bar/baz/d.c"]) -> false
     """
-    path_list = set([os.path.dirname(f) for f in list_of_normalized_filenames])
-    return os.path.dirname(filename_normalized) in path_list
+    path_list = set(
+        [
+            os.path.dirname(f).replace(os.path.sep, "/")
+            for f in list_of_normalized_filenames
+        ]
+    )
+    return os.path.dirname(filename_normalized).replace(os.path.sep, "/") in path_list
 
 
 def find_all_posible_assignments_from_filename(source_assignments, filename_normalized):
     """
     Given a list of source assignments and a normalized filename, narrow the list to assignments
     that contain a file whose directory matches the filename's directory.
     """
     possible_assignments = {}
@@ -715,16 +726,20 @@ def edit_moz_build_file_to_add_file(
     I had _really_ hoped to replace this whole damn thing with something that adds a
     node to the AST, dumps the AST out, and then runs black on the file but there are
     some issues:
       - third party moz.build files (or maybe all moz.build files) aren't always run
         through black
       - dumping the ast out losing comments
     """
 
+    # Make sure that we only write in forward slashes
+    if "\\" in unnormalized_filename_to_add:
+        unnormalized_filename_to_add = unnormalized_filename_to_add.replace("\\", "/")
+
     # add the file into the list, and then sort it in the same way the moz.build validator
     # expects
     unnormalized_list_of_files.append(unnormalized_filename_to_add)
     unnormalized_list_of_files = alphabetical_sorted(unnormalized_list_of_files)
 
     # we're going to add our file by doing a find/replace of an adjacent file in the list
     indx_of_addition = unnormalized_list_of_files.index(unnormalized_filename_to_add)
     indx_of_addition
@@ -740,111 +755,110 @@ def edit_moz_build_file_to_add_file(
     # We will only perform the first replacement. This is because sometimes there's moz.build
     # code like:
     #   SOURCES += ['file.cpp']
     #   SOURCES['file.cpp'].flags += ['-Winline']
     # If we replaced every time we found the target, we would be inserting into that second
     # line.
     did_replace = False
 
-    # FileInput is a strange class that lets you edit a file in-place, but does so by hijacking
-    # stdout, so you just print() the output you want as you go through
-    file = fileinput.FileInput(normalized_mozbuild_filename, inplace=True)
-    for line in file:
-        if not did_replace and find_str in line:
-            did_replace = True
+    with open(normalized_mozbuild_filename, mode="r") as file:
+        with open(normalized_mozbuild_filename + ".new", mode="wb") as output:
+            for line in file:
+                if not did_replace and find_str in line:
+                    did_replace = True
 
-            # Okay, we found the line we need to edit, now we need to be ugly about it
-            # Grab the type of quote used in this moz.build file: single or double
-            quote_type = line[line.index(find_str) - 1]
+                    # Okay, we found the line we need to edit, now we need to be ugly about it
+                    # Grab the type of quote used in this moz.build file: single or double
+                    quote_type = line[line.index(find_str) - 1]
 
-            if "[" not in line:
-                # We'll want to put our new file onto its own line
-                newline_to_add = "\n"
-                # And copy the indentation of the line we're adding adjacent to
-                indent_value = line[0 : line.index(quote_type)]
-            else:
-                # This is frustrating, we have the start of the array here. We aren't
-                # going to be able to indent things onto a newline properly. We're just
-                # going to have to stick it in on the same line.
-                newline_to_add = ""
-                indent_value = ""
+                    if "[" not in line:
+                        # We'll want to put our new file onto its own line
+                        newline_to_add = "\n"
+                        # And copy the indentation of the line we're adding adjacent to
+                        indent_value = line[0 : line.index(quote_type)]
+                    else:
+                        # This is frustrating, we have the start of the array here. We aren't
+                        # going to be able to indent things onto a newline properly. We're just
+                        # going to have to stick it in on the same line.
+                        newline_to_add = ""
+                        indent_value = ""
 
-            find_str = "%s%s%s" % (quote_type, find_str, quote_type)
-            if replace_before:
-                replacement_tuple = (
-                    find_str,
-                    newline_to_add,
-                    indent_value,
-                    quote_type,
-                    unnormalized_filename_to_add,
-                    quote_type,
-                )
-                replace_str = "%s,%s%s%s%s%s" % replacement_tuple
-            else:
-                replacement_tuple = (
-                    quote_type,
-                    unnormalized_filename_to_add,
-                    quote_type,
-                    newline_to_add,
-                    indent_value,
-                    find_str,
-                )
-                replace_str = "%s%s%s,%s%s%s" % replacement_tuple
+                    find_str = "%s%s%s" % (quote_type, find_str, quote_type)
+                    if replace_before:
+                        replacement_tuple = (
+                            find_str,
+                            newline_to_add,
+                            indent_value,
+                            quote_type,
+                            unnormalized_filename_to_add,
+                            quote_type,
+                        )
+                        replace_str = "%s,%s%s%s%s%s" % replacement_tuple
+                    else:
+                        replacement_tuple = (
+                            quote_type,
+                            unnormalized_filename_to_add,
+                            quote_type,
+                            newline_to_add,
+                            indent_value,
+                            find_str,
+                        )
+                        replace_str = "%s%s%s,%s%s%s" % replacement_tuple
 
-            line = line.replace(find_str, replace_str)
+                    line = line.replace(find_str, replace_str)
 
-        print(line, end="")  # line has its own newline on it, don't add a second
-    file.close()
+                output.write((line.rstrip() + "\n").encode("utf-8"))
+
+    shutil.move(normalized_mozbuild_filename + ".new", normalized_mozbuild_filename)
 
 
 def edit_moz_build_file_to_remove_file(
     normalized_mozbuild_filename, unnormalized_filename_to_remove
 ):
     """
     This function edits the moz.build file in-place
     """
 
     simple_file_line = re.compile(
         "^\s*['\"]" + unnormalized_filename_to_remove + "['\"],*$"
     )
     did_replace = False
 
-    # FileInput is a strange class that lets you edit a file in-place, but does so by hijacking
-    # stdout, so you just print() the output you want as you go through
-    file = fileinput.FileInput(normalized_mozbuild_filename, inplace=True)
-    for line in file:
-        if not did_replace and unnormalized_filename_to_remove in line:
-            did_replace = True
+    with open(normalized_mozbuild_filename, mode="r") as file:
+        with open(normalized_mozbuild_filename + ".new", mode="wb") as output:
+            for line in file:
+                if not did_replace and unnormalized_filename_to_remove in line:
+                    did_replace = True
 
-            # If the line consists of just a single source file on it, then we're in the clear
-            # we can just skip this line.
-            if simple_file_line.match(line):
-                # Do not output anything, just keep going.
-                continue
+                    # If the line consists of just a single source file on it, then we're in the
+                    # clear - we can just skip this line.
+                    if simple_file_line.match(line):
+                        # Do not output anything, just keep going.
+                        continue
 
-            # Okay, so the line is a little more complicated.
-            quote_type = line[line.index(unnormalized_filename_to_remove) - 1]
+                    # Okay, so the line is a little more complicated.
+                    quote_type = line[line.index(unnormalized_filename_to_remove) - 1]
 
-            if "[" in line or "]" in line:
-                find_str = "%s%s%s,*" % (
-                    quote_type,
-                    unnormalized_filename_to_remove,
-                    quote_type,
-                )
-                line = re.sub(find_str, "", line)
-            else:
-                raise Exception(
-                    "Got an unusual type of line we're trying to remove a file from:",
-                    line,
-                )
+                    if "[" in line or "]" in line:
+                        find_str = "%s%s%s,*" % (
+                            quote_type,
+                            unnormalized_filename_to_remove,
+                            quote_type,
+                        )
+                        line = re.sub(find_str, "", line)
+                    else:
+                        raise Exception(
+                            "Got an unusual type of line we're trying to remove a file from:",
+                            line,
+                        )
 
-        print(line, end="")
+                output.write((line.rstrip() + "\n").encode("utf-8"))
 
-    file.close()
+    shutil.move(normalized_mozbuild_filename + ".new", normalized_mozbuild_filename)
 
 
 def validate_directory_parameters(moz_yaml_dir, vendoring_dir):
     # Validate the parameters
     assert (moz_yaml_dir, vendoring_dir) == (None, None) or (
         moz_yaml_dir and vendoring_dir
     ), "If either moz_yaml_dir or vendoring_dir are specified, they both must be"
 
@@ -902,19 +916,21 @@ def renormalize_filename(
         normalized_filename_to_act_on = "/" + normalized_filename_to_act_on
     elif moz_yaml_dir and vendoring_dir:
         # To re-normalize it in this case, we:
         #   (a) get the path from gecko_root to the moz.build file we are considering
         #   (b) compute a relative path from that directory to the file we want
         #   (c) because (b) started at the moz.build file's directory, it is not
         #       normalized to the gecko_root. Therefore we need to normalize it by
         #       prepending (a)
-        a = os.path.dirname(normalized_mozbuild_filename)
-        b = os.path.relpath(normalized_filename_to_act_on, start=a)
-        c = os.path.join(a, b)
+        a = os.path.dirname(normalized_mozbuild_filename).replace(os.path.sep, "/")
+        b = os.path.relpath(normalized_filename_to_act_on, start=a).replace(
+            os.path.sep, "/"
+        )
+        c = os.path.join(a, b).replace(os.path.sep, "/")
         normalized_filename_to_act_on = c
 
     return normalized_filename_to_act_on
 
 
 #########################################################
 # PUBLIC API
 #########################################################
@@ -1060,25 +1076,16 @@ def add_file_to_moz_build_file(
             unnormalized_filename_to_add = unnormalize_filename(
                 normalized_mozbuild_filename, normalized_filename_to_add
             )
             unnormalized_list_of_files = [
                 unnormalize_filename(normalized_mozbuild_filename, f)
                 for f in guessed_list_containing_normalized_filenames
             ]
 
-            # unnormalize filenames so we can edit the moz.build file. They rarely use full paths.
-            unnormalized_filename_to_add = unnormalize_filename(
-                normalized_mozbuild_filename, normalized_filename_to_add
-            )
-            unnormalized_list_of_files = [
-                unnormalize_filename(normalized_mozbuild_filename, f)
-                for f in guessed_list_containing_normalized_filenames
-            ]
-
             edit_moz_build_file_to_add_file(
                 normalized_mozbuild_filename,
                 unnormalized_filename_to_add,
                 unnormalized_list_of_files,
             )
             return
 
     raise MozBuildRewriteException(
--- a/python/mozbuild/mozbuild/vendor/vendor_manifest.py
+++ b/python/mozbuild/mozbuild/vendor/vendor_manifest.py
@@ -201,18 +201,18 @@ class VendorManifest(MozbuildObject):
             for r in replacements:
                 if r[0] in l:
                     print("Found " + l)
                     replaced += 1
                     yaml[i] = re.sub(r[0] + " [v\.a-f0-9]+.*$", r[0] + r[1], yaml[i])
 
         assert len(replacements) == replaced
 
-        with open(yaml_file, "w") as f:
-            f.write("".join(yaml))
+        with open(yaml_file, "wb") as f:
+            f.write(("".join(yaml) + "\n").encode("utf-8"))
 
     def update_files(self, revision, yaml_file):
         def get_full_path(path, support_cwd=False):
             if support_cwd and path[0:5] == "{cwd}":
                 path = path.replace("{cwd}", ".")
             elif "{yaml_dir}" in path:
                 path = path.replace("{yaml_dir}", os.path.dirname(yaml_file))
             else:
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-de3db3a55aef
\ No newline at end of file
+NSS_3_72_BETA1
\ No newline at end of file
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/security/nss/coreconf/rules.mk
+++ b/security/nss/coreconf/rules.mk
@@ -372,16 +372,18 @@ endif
 
 define copy_varlist_into_dir_RULE
 ifdef $(2)
 ifneq (,$$(strip $$($(2))))
 $(3)/%: %
 	$$(INSTALL) -m 444 $$^ $(3)