Merge autoland to mozilla-central. a=merge
authorMihai Alexandru Michis <malexandru@mozilla.com>
Sat, 31 Aug 2019 00:53:31 +0300
changeset 554780 cae93ef1993e02a136ef64d974856071b905997f
parent 554779 8d251dd4a9bebaa3e72a23d795122d4b12097ffc (current diff)
parent 554689 5882c5dd07f443554b2ec47fd78f5e6212e548b0 (diff)
child 554788 282a30908d52b22f4602eaeba1677d2fe666a46d
child 554792 56db66978b427e18362c3d1d733f7fcb61d2912e
push id2165
push userffxbld-merge
push dateMon, 14 Oct 2019 16:30:58 +0000
treeherdermozilla-release@0eae18af659f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone70.0a1
first release with
nightly linux32
cae93ef1993e / 70.0a1 / 20190830215433 / files
nightly linux64
cae93ef1993e / 70.0a1 / 20190830215433 / files
nightly mac
cae93ef1993e / 70.0a1 / 20190830215433 / files
nightly win32
cae93ef1993e / 70.0a1 / 20190830215433 / files
nightly win64
cae93ef1993e / 70.0a1 / 20190830215433 / 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/.cargo/config
+++ b/.cargo/config
@@ -20,17 +20,17 @@ replace-with = "vendored-sources"
 [source."https://github.com/NikVolf/tokio-named-pipes"]
 branch = "stable"
 git = "https://github.com/NikVolf/tokio-named-pipes"
 replace-with = "vendored-sources"
 
 [source."https://github.com/CraneStation/Cranelift"]
 git = "https://github.com/CraneStation/Cranelift"
 replace-with = "vendored-sources"
-rev = "164f91a1f473e582e18e48d056c51787d9a1c24d"
+rev = "fc88520b88bcaad4e4a92f28a5e17347af20edbd"
 
 [source.crates-io]
 replace-with = "vendored-sources"
 
 # Take advantage of the fact that cargo will treat lines starting with #
 # as comments to add preprocessing directives for when this file is included
 # from .cargo/config.in.
 #define REPLACE_NAME vendored-sources
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -193,18 +193,18 @@ dependencies = [
  "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "baldrdash"
 version = "0.1.0"
 dependencies = [
  "bindgen 0.51.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cranelift-codegen 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d)",
- "cranelift-wasm 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d)",
+ "cranelift-codegen 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)",
+ "cranelift-wasm 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)",
  "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "base64"
 version = "0.9.3"
@@ -606,66 +606,66 @@ version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cose 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cranelift-bforest"
 version = "0.40.0"
-source = "git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d#164f91a1f473e582e18e48d056c51787d9a1c24d"
-dependencies = [
- "cranelift-entity 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d)",
+source = "git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd#fc88520b88bcaad4e4a92f28a5e17347af20edbd"
+dependencies = [
+ "cranelift-entity 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)",
 ]
 
 [[package]]
 name = "cranelift-codegen"
 version = "0.40.0"
-source = "git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d#164f91a1f473e582e18e48d056c51787d9a1c24d"
-dependencies = [
- "cranelift-bforest 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d)",
- "cranelift-codegen-meta 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d)",
- "cranelift-entity 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d)",
+source = "git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd#fc88520b88bcaad4e4a92f28a5e17347af20edbd"
+dependencies = [
+ "cranelift-bforest 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)",
+ "cranelift-codegen-meta 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)",
+ "cranelift-entity 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)",
  "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cranelift-codegen-meta"
 version = "0.40.0"
-source = "git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d#164f91a1f473e582e18e48d056c51787d9a1c24d"
-dependencies = [
- "cranelift-entity 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d)",
+source = "git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd#fc88520b88bcaad4e4a92f28a5e17347af20edbd"
+dependencies = [
+ "cranelift-entity 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)",
 ]
 
 [[package]]
 name = "cranelift-entity"
 version = "0.40.0"
-source = "git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d#164f91a1f473e582e18e48d056c51787d9a1c24d"
+source = "git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd#fc88520b88bcaad4e4a92f28a5e17347af20edbd"
 
 [[package]]
 name = "cranelift-frontend"
 version = "0.40.0"
-source = "git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d#164f91a1f473e582e18e48d056c51787d9a1c24d"
-dependencies = [
- "cranelift-codegen 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d)",
+source = "git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd#fc88520b88bcaad4e4a92f28a5e17347af20edbd"
+dependencies = [
+ "cranelift-codegen 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cranelift-wasm"
 version = "0.40.0"
-source = "git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d#164f91a1f473e582e18e48d056c51787d9a1c24d"
-dependencies = [
- "cranelift-codegen 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d)",
- "cranelift-entity 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d)",
- "cranelift-frontend 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d)",
+source = "git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd#fc88520b88bcaad4e4a92f28a5e17347af20edbd"
+dependencies = [
+ "cranelift-codegen 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)",
+ "cranelift-entity 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)",
+ "cranelift-frontend 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)",
  "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "wasmparser 0.37.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "crc"
@@ -3912,22 +3912,22 @@ dependencies = [
 "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
 "checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5"
 "checksum core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4e2640d6d0bf22e82bed1b73c6aef8d5dd31e5abe6666c57e6d45e2649f4f887"
 "checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
 "checksum core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)" = "62ceafe1622ffc9a332199096841d0ff9912ec8cf8f9cde01e254a7d5217cd10"
 "checksum core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f46450d6f2397261af420b4ccce23807add2e45fa206410a03d66fb7f050ae"
 "checksum cose 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72fa26cb151d3ae4b70f63d67d0fed57ce04220feafafbae7f503bef7aae590d"
 "checksum cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "49726015ab0ca765144fcca61e4a7a543a16b795a777fa53f554da2fffff9a94"
-"checksum cranelift-bforest 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d)" = "<none>"
-"checksum cranelift-codegen 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d)" = "<none>"
-"checksum cranelift-codegen-meta 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d)" = "<none>"
-"checksum cranelift-entity 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d)" = "<none>"
-"checksum cranelift-frontend 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d)" = "<none>"
-"checksum cranelift-wasm 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=164f91a1f473e582e18e48d056c51787d9a1c24d)" = "<none>"
+"checksum cranelift-bforest 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)" = "<none>"
+"checksum cranelift-codegen 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)" = "<none>"
+"checksum cranelift-codegen-meta 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)" = "<none>"
+"checksum cranelift-entity 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)" = "<none>"
+"checksum cranelift-frontend 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)" = "<none>"
+"checksum cranelift-wasm 0.40.0 (git+https://github.com/CraneStation/Cranelift?rev=fc88520b88bcaad4e4a92f28a5e17347af20edbd)" = "<none>"
 "checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7"
 "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
 "checksum crossbeam-channel 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8d4f5844607ce8da3fff431e7dba56cda8bfcc570aa50bee36adba8a32b8cad7"
 "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13"
 "checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4"
 "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
 "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c"
 "checksum cssparser 0.25.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a921abc45ea75c2c817d951caeda31b94539d09a6b5e8d58a857b3b35c9c3894"
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -58,16 +58,16 @@ codegen-units = 1
 
 [patch.crates-io]
 libudev-sys = { path = "dom/webauthn/libudev-sys" }
 winapi = { git = "https://github.com/froydnj/winapi-rs", branch = "aarch64" }
 packed_simd = { git = "https://github.com/hsivonen/packed_simd", branch = "rust_1_32" }
 
 [patch.crates-io.cranelift-codegen]
 git = "https://github.com/CraneStation/Cranelift"
-rev = "164f91a1f473e582e18e48d056c51787d9a1c24d"
+rev = "fc88520b88bcaad4e4a92f28a5e17347af20edbd"
 
 [patch.crates-io.cranelift-wasm]
 git = "https://github.com/CraneStation/Cranelift"
-rev = "164f91a1f473e582e18e48d056c51787d9a1c24d"
+rev = "fc88520b88bcaad4e4a92f28a5e17347af20edbd"
 
 [patch.crates-io.coreaudio-sys]
 path = "third_party/rust/coreaudio-sys"
--- a/browser/app/winlauncher/moz.build
+++ b/browser/app/winlauncher/moz.build
@@ -61,8 +61,11 @@ if CONFIG['MOZ_LAUNCHER_PROCESS']:
     UNIFIED_SOURCES += [
         '/toolkit/xre/LauncherRegistryInfo.cpp',
         '/toolkit/xre/WinTokenUtils.cpp',
     ]
     for var in ('MOZ_APP_BASENAME', 'MOZ_APP_VENDOR'):
         DEFINES[var] = '"%s"' % CONFIG[var]
 
 DisableStlWrapping()
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Launcher Process')
--- a/browser/base/content/browser-siteProtections.js
+++ b/browser/base/content/browser-siteProtections.js
@@ -660,30 +660,46 @@ var ThirdPartyCookies = {
       (state & Ci.nsIWebProgressListener.STATE_COOKIES_BLOCKED_ALL) != 0 ||
       (state & Ci.nsIWebProgressListener.STATE_COOKIES_BLOCKED_BY_PERMISSION) !=
         0 ||
       (state & Ci.nsIWebProgressListener.STATE_COOKIES_BLOCKED_FOREIGN) != 0
     );
   },
 
   isDetected(state) {
-    return (state & Ci.nsIWebProgressListener.STATE_COOKIES_LOADED) != 0;
+    if (this.behaviorPref == Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER) {
+      // We don't have a state that specifically represents loaded tracker cookies,
+      // so use loaded tracking content as a proxy - it's not perfect but it
+      // yields fewer false-positives than the generic loaded cookies state.
+      return (
+        (state & Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT) != 0
+      );
+    }
+
+    // We don't have any proxies for the other cookie behaviors unfortunately.
+    return (
+      this.isBlocking(state) ||
+      (state & Ci.nsIWebProgressListener.STATE_COOKIES_LOADED) != 0
+    );
   },
 
   async updateSubView() {
     let contentBlockingLog = await gBrowser.selectedBrowser.getContentBlockingLog();
     contentBlockingLog = JSON.parse(contentBlockingLog);
 
     let categories = this._processContentBlockingLog(contentBlockingLog);
 
     this.subViewList.textContent = "";
 
     for (let category of ["firstParty", "trackers", "thirdParty"]) {
       let itemsToShow;
-      if (category == "trackers" && gProtectionsHandler.hasException) {
+      if (
+        category == "trackers" &&
+        (gProtectionsHandler.hasException || !this.enabled)
+      ) {
         itemsToShow = categories[category];
       } else {
         itemsToShow = categories[category].filter(
           info => !info.isAllowed || info.hasException
         );
       }
 
       if (!itemsToShow.length) {
@@ -1283,16 +1299,34 @@ var gProtectionsHandler = {
     ));
   },
   get _protectionsPopupTPSwitch() {
     delete this._protectionsPopupTPSwitch;
     return (this._protectionsPopupTPSwitch = document.getElementById(
       "protections-popup-tp-switch"
     ));
   },
+  get _protectionsPopupBlockingHeader() {
+    delete this._protectionsPopupBlockingHeader;
+    return (this._protectionsPopupBlockingHeader = document.getElementById(
+      "protections-popup-blocking-section-header"
+    ));
+  },
+  get _protectionsPopupNotBlockingHeader() {
+    delete this._protectionsPopupNotBlockingHeader;
+    return (this._protectionsPopupNotBlockingHeader = document.getElementById(
+      "protections-popup-not-blocking-section-header"
+    ));
+  },
+  get _protectionsPopupNotFoundHeader() {
+    delete this._protectionsPopupNotFoundHeader;
+    return (this._protectionsPopupNotFoundHeader = document.getElementById(
+      "protections-popup-not-found-section-header"
+    ));
+  },
   get _protectionsPopupSettingsButton() {
     delete this._protectionsPopupSettingsButton;
     return (this._protectionsPopupSettingsButton = document.getElementById(
       "protections-popup-settings-button"
     ));
   },
   get _protectionsPopupFooter() {
     delete this._protectionsPopupFooter;
@@ -1400,20 +1434,21 @@ var gProtectionsHandler = {
   // with at least the following two properties:
   //  - enabled: Whether the blocker is currently turned on.
   //  - isDetected(state): Given a content blocking state, whether the blocker has
   //                       either allowed or blocked elements.
   //  - categoryItem: The DOM item that represents the entry in the category list.
   //
   // It may also contain an init() and uninit() function, which will be called
   // on gProtectionsHandler.init() and gProtectionsHandler.uninit().
+  // The buttons in the protections panel will appear in the same order as this array.
   blockers: [
-    TrackingProtection,
     SocialTracking,
     ThirdPartyCookies,
+    TrackingProtection,
     Fingerprinting,
     Cryptomining,
   ],
 
   init() {
     this.animatedIcon.addEventListener("animationend", () =>
       this.iconBox.removeAttribute("animate")
     );
@@ -1479,64 +1514,44 @@ var gProtectionsHandler = {
     switchToTabHavingURI("about:protections", true, {
       replaceQueryString: true,
       relatedToCurrent,
       triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
     });
   },
 
   async showTrackersSubview(event) {
-    if (event.target.classList.contains("notFound")) {
-      return;
-    }
-
     await TrackingProtection.updateSubView();
     this._protectionsPopupMultiView.showSubView(
       "protections-popup-trackersView"
     );
   },
 
   async showSocialblockerSubview(event) {
-    if (event.target.classList.contains("notFound")) {
-      return;
-    }
-
     await SocialTracking.updateSubView();
     this._protectionsPopupMultiView.showSubView(
       "protections-popup-socialblockView"
     );
   },
 
   async showCookiesSubview(event) {
-    if (event.target.classList.contains("notFound")) {
-      return;
-    }
-
     await ThirdPartyCookies.updateSubView();
     this._protectionsPopupMultiView.showSubView(
       "protections-popup-cookiesView"
     );
   },
 
   async showFingerprintersSubview(event) {
-    if (event.target.classList.contains("notFound")) {
-      return;
-    }
-
     await Fingerprinting.updateSubView();
     this._protectionsPopupMultiView.showSubView(
       "protections-popup-fingerprintersView"
     );
   },
 
   async showCryptominersSubview(event) {
-    if (event.target.classList.contains("notFound")) {
-      return;
-    }
-
     await Cryptomining.updateSubView();
     this._protectionsPopupMultiView.showSubView(
       "protections-popup-cryptominersView"
     );
   },
 
   recordClick(object, value = null) {
     Services.telemetry.recordEvent(
@@ -1592,16 +1607,18 @@ var gProtectionsHandler = {
         "open",
         "true"
       );
 
       // Insert the info message if needed. This will be shown once and then
       // remain collapsed.
       ToolbarPanelHub.insertProtectionPanelMessage(event);
 
+      this.reorderCategoryItems();
+
       if (!event.target.hasAttribute("toast")) {
         Services.telemetry.recordEvent(
           "security.ui.protectionspopup",
           "open",
           "protections_popup"
         );
       }
     }
@@ -1713,16 +1730,21 @@ var gProtectionsHandler = {
       // runs on tab switch, so we can avoid associating the data with the document directly.
       blocker.activated = blocker.isBlocking(event);
       let detected = blocker.isDetected(event);
       blocker.categoryItem.classList.toggle("notFound", !detected);
       anyDetected = anyDetected || detected;
       anyBlocking = anyBlocking || blocker.activated;
     }
 
+    this._categoryItemOrderInvalidated = true;
+    if (this._protectionsPopup.state == "open") {
+      this.reorderCategoryItems();
+    }
+
     if (anyDetected) {
       this.noTrackersDetectedDescription.hidden = true;
     }
 
     // Check whether the user has added an exception for this site.
     let hasException = ContentBlockingAllowList.includes(
       gBrowser.selectedBrowser
     );
@@ -1902,16 +1924,74 @@ var gProtectionsHandler = {
         ])
       );
     }
 
     // Update the tooltip of the blocked tracker counter.
     this.maybeUpdateEarliestRecordedDateTooltip();
   },
 
+  /*
+   * This function sorts the category items into the Blocked/Allowed/None Detected
+   * sections. It's called immediately in onContentBlockingEvent if the popup
+   * is presently open. Otherwise, the next time the popup is shown.
+   */
+  reorderCategoryItems() {
+    if (!this._categoryItemOrderInvalidated) {
+      return;
+    }
+
+    delete this._categoryItemOrderInvalidated;
+
+    // Hide all the headers to start with.
+    this._protectionsPopupBlockingHeader.hidden = true;
+    this._protectionsPopupNotBlockingHeader.hidden = true;
+    this._protectionsPopupNotFoundHeader.hidden = true;
+
+    for (let { categoryItem } of this.blockers) {
+      if (categoryItem.classList.contains("notFound")) {
+        // Add the item to the bottom of the list. This will be under
+        // the "None Detected" section.
+        categoryItem.parentNode.insertAdjacentElement(
+          "beforeend",
+          categoryItem
+        );
+        categoryItem.setAttribute("disabled", true);
+        // We have an undetected category, show the header.
+        this._protectionsPopupNotFoundHeader.hidden = false;
+        continue;
+      }
+
+      // Clear the disabled attribute in case we are moving the item out of
+      // "None Detected"
+      categoryItem.removeAttribute("disabled");
+
+      if (categoryItem.classList.contains("blocked") && !this.hasException) {
+        // Add the item just above the "Allowed" section - this will be the
+        // bottom of the "Blocked" section.
+        categoryItem.parentNode.insertBefore(
+          categoryItem,
+          this._protectionsPopupNotBlockingHeader
+        );
+        // We have a blocking category, show the header.
+        this._protectionsPopupBlockingHeader.hidden = false;
+        continue;
+      }
+
+      // Add the item just above the "None Detected" section - this will be the
+      // bottom of the "Allowed" section.
+      categoryItem.parentNode.insertBefore(
+        categoryItem,
+        this._protectionsPopupNotFoundHeader
+      );
+      // We have an allowing category, show the header.
+      this._protectionsPopupNotBlockingHeader.hidden = false;
+    }
+  },
+
   disableForCurrentPage(shouldReload = true) {
     ContentBlockingAllowList.add(gBrowser.selectedBrowser);
     if (shouldReload) {
       PanelMultiView.hidePopup(this._protectionsPopup);
       BrowserReload();
     }
   },
 
--- a/browser/base/content/browser.xhtml
+++ b/browser/base/content/browser.xhtml
@@ -264,17 +264,17 @@
            type="arrow"
            orient="vertical"
            ignorekeys="true"
            hidden="true"
            tabspecific="true"
            aria-labelledby="editBookmarkPanelTitle">
       <box class="panel-header">
         <label id="editBookmarkPanelTitle"/>
-        <toolbarbutton id="editBookmarkPanelInfoButton" class="panel-info-button" oncommand="StarUI.toggleRecommendation();" >
+        <toolbarbutton tabindex="0" id="editBookmarkPanelInfoButton" class="panel-info-button" oncommand="StarUI.toggleRecommendation();" >
           <image/>
         </toolbarbutton>
       </box>
       <html:div id="editBookmarkPanelInfoArea">
         <html:div id="editBookmarkPanelRecommendation"></html:div>
         <html:div id="editBookmarkPanelFaviconContainer">
           <html:img id="editBookmarkPanelFavicon"/>
         </html:div>
@@ -1057,32 +1057,16 @@
                          role="button"/>
                   <hbox id="star-button-animatable-box">
                     <image id="star-button-animatable-image"
                            role="presentation"/>
                   </hbox>
                 </hbox>
               </hbox>
             </hbox>
-            <vbox class="urlbarView"
-                  role="group"
-                  tooltip="aHTMLTooltip"
-                  hidden="true">
-              <html:div class="urlbarView-body-outer">
-                <html:div class="urlbarView-body-inner">
-                  <html:div id="urlbar-results"
-                            class="urlbarView-results"
-                            role="listbox"/>
-                </html:div>
-              </html:div>
-              <hbox class="search-one-offs"
-                    compact="true"
-                    includecurrentengine="true"
-                    disabletab="true"/>
-            </vbox>
           </hbox>
           <toolbartabstop/>
         </toolbaritem>
 
         <toolbarspring cui-areatype="toolbar" class="chromeclass-toolbar-additional"/>
 
         <!-- This is a placeholder for the Downloads Indicator.  It is visible
              during the customization of the toolbar, in the palette, and before
--- a/browser/base/content/test/siteProtections/browser_protections_UI.js
+++ b/browser/base/content/test/siteProtections/browser_protections_UI.js
@@ -539,18 +539,18 @@ add_task(async function testSubViewTelem
     ["protections-popup-category-socialblock", "social"],
     ["protections-popup-category-cookies", "cookies"],
     ["protections-popup-category-cryptominers", "cryptominers"],
     ["protections-popup-category-fingerprinters", "fingerprinters"],
   ].map(item => [document.getElementById(item[0]), item[1]]);
 
   for (let [item, telemetryId] of items) {
     await BrowserTestUtils.withNewTab("http://www.example.com", async () => {
+      item.classList.remove("notFound"); // Force visible for test
       await openProtectionsPanel();
-      item.classList.remove("notFound"); // Force visible for test
       let viewShownEvent = BrowserTestUtils.waitForEvent(
         gProtectionsHandler._protectionsPopupMultiView,
         "ViewShown"
       );
       item.click();
       let panelView = (await viewShownEvent).originalTarget;
       checkClickTelemetry(telemetryId);
       let prefsTabPromise = BrowserTestUtils.waitForNewTab(
--- a/browser/base/content/test/trackingUI/browser_trackingUI_cookies_subview.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_cookies_subview.js
@@ -33,17 +33,17 @@ add_task(async function setup() {
  * [7] - integer indicating number of expected cookie list items
  *       after loading a cookie-setting first party URL in an iframe
  */
 async function assertSitesListed(testCase) {
   let sitesListedTestCases = [
     [true, false, false, 4, 1, 1, 1, 1],
     [true, true, false, 5, 1, 1, 2, 2],
     [true, true, true, 6, 2, 2, 3, 3],
-    [false, false, false, 3, 0, 0, 0, 0],
+    [false, false, false, 3, 1, 1, 1, 1],
   ];
   let [
     trackersBlocked,
     thirdPartyBlocked,
     firstPartyBlocked,
     contentBlockingEventCount,
     listHeaderCount,
     cookieItemsCount1,
--- a/browser/components/aboutconfig/content/aboutconfig.css
+++ b/browser/components/aboutconfig/content/aboutconfig.css
@@ -66,16 +66,18 @@ body.config-warning {
   background-color: transparent;
   opacity: .7;
 }
 
 #prefs {
   background-color: var(--in-content-box-background);
   color: var(--in-content-text-color);
   margin: 10px;
+  table-layout: fixed;
+  width: calc(100% - 20px);
   min-width: 644px;
   /* To stay consistent with about:preferences (664px - 20px margin). */
   border: 1px solid var(--in-content-box-border-color);
   border-radius: 2px;
   border-spacing: 0;
 }
 
 #prefs > tr.odd {
@@ -102,44 +104,45 @@ body.config-warning {
 
 #prefs > tr.locked:dir(rtl) {
   background-position-x: right 9px;
 }
 
 #prefs > tr > td,
 #prefs > tr > th {
   padding: 4px;
-  width: 50%;
   font-weight: inherit;
 }
 
 #prefs > tr > th {
   text-align: unset;
   padding-inline-start: 30px;
 }
 
 #prefs > tr.deleted > th {
   font-weight: bold;
   opacity: 0.4;
 }
 
 #prefs > tr > td.cell-edit,
 #prefs > tr > td.cell-reset {
+  width: 40px;
   padding: 0;
 }
 
 .cell-value {
   overflow-wrap: anywhere;
   white-space: pre-wrap;
   word-break: break-all;
 }
 
 td.cell-value > form > input[type="text"],
 td.cell-value > form > input[type="number"] {
   -moz-appearance: textfield;
+  margin: 0;
   width: 100%;
   box-sizing: border-box;
 }
 
 .button-add,
 .button-save,
 .button-edit,
 .button-toggle,
--- a/browser/components/controlcenter/content/protectionsPanel.inc.xul
+++ b/browser/components/controlcenter/content/protectionsPanel.inc.xul
@@ -58,63 +58,65 @@
       <!-- Tracking Protection Section -->
       <vbox id="tracking-protection-container" class="protections-popup-section">
         <description id="protections-popup-no-trackers-found-description">&protections.noTrackersFound.description;</description>
         <tooltip id="protections-popup-not-blocking-why-etp-on-tooltip">&protections.notBlocking.why.etpOn.tooltip;</tooltip>
         <tooltip id="protections-popup-not-blocking-why-etp-off-tooltip">&protections.notBlocking.why.etpOff.tooltip;</tooltip>
         <vbox id="protections-popup-content" flex="1">
           <vbox id="protections-popup-category-list">
             <toolbarbutton id="protections-popup-category-tracking-protection"
-                           onclick="gProtectionsHandler.showTrackersSubview(event); gProtectionsHandler.recordClick('trackers');"
+                           oncommand="gProtectionsHandler.showTrackersSubview(event); gProtectionsHandler.recordClick('trackers');"
                            class="protections-popup-category" align="center"
                            wrap="true">
               <image class="protections-popup-category-icon tracking-protection-icon"/>
               <label flex="1" class="protections-popup-category-label">&contentBlocking.trackingProtection4.label;</label>
             </toolbarbutton>
             <toolbarbutton id="protections-popup-category-socialblock"
-                           onclick="gProtectionsHandler.showSocialblockerSubview(event); gProtectionsHandler.recordClick('social');"
+                           oncommand="gProtectionsHandler.showSocialblockerSubview(event); gProtectionsHandler.recordClick('social');"
                            class="protections-popup-category" align="center">
               <image class="protections-popup-category-icon socialblock-icon"/>
               <label flex="1"
               class="protections-popup-category-label">&contentBlocking.socialblock.label;</label>
             </toolbarbutton>
             <toolbarbutton id="protections-popup-category-cookies"
-                           onclick="gProtectionsHandler.showCookiesSubview(event); gProtectionsHandler.recordClick('cookies');"
+                           oncommand="gProtectionsHandler.showCookiesSubview(event); gProtectionsHandler.recordClick('cookies');"
                            class="protections-popup-category" align="center"
                            wrap="true">
               <image class="protections-popup-category-icon thirdpartycookies-icon"/>
               <label flex="1" id="protections-popup-cookies-category-label-disabled"
                      class="protections-popup-category-label">&contentBlocking.cookies2.label;</label>
               <label flex="1" id="protections-popup-cookies-category-label-enabled"
                      class="protections-popup-category-label"
                      hidden="true"></label>
             </toolbarbutton>
             <toolbarbutton id="protections-popup-category-cryptominers"
-                           onclick="gProtectionsHandler.showCryptominersSubview(event); gProtectionsHandler.recordClick('cryptominers');"
+                           oncommand="gProtectionsHandler.showCryptominersSubview(event); gProtectionsHandler.recordClick('cryptominers');"
                            class="protections-popup-category" align="center"
                            wrap="true">
               <image class="protections-popup-category-icon cryptominers-icon"/>
               <label flex="1" class="protections-popup-category-label">&contentBlocking.cryptominers.label;</label>
             </toolbarbutton>
             <toolbarbutton id="protections-popup-category-fingerprinters"
-                           onclick="gProtectionsHandler.showFingerprintersSubview(event); gProtectionsHandler.recordClick('fingerprinters');"
+                           oncommand="gProtectionsHandler.showFingerprintersSubview(event); gProtectionsHandler.recordClick('fingerprinters');"
                            class="protections-popup-category" align="center"
                            wrap="true">
               <image class="protections-popup-category-icon fingerprinters-icon"/>
               <label flex="1" class="protections-popup-category-label">&contentBlocking.fingerprinters.label;</label>
             </toolbarbutton>
             <description id="protections-popup-blocking-section-header"
                          role="heading"
                          aria-level="2">&protections.blocking2.label;</description>
-            <hbox id="protections-popup-not-blocking-section-header">
-              <description id="protections-popup-not-blocking-section-description">&protections.notBlocking2.label;</description>
+            <hbox id="protections-popup-not-blocking-section-header" flex="1">
+              <description id="protections-popup-not-blocking-section-description" flex="1">&protections.notBlocking2.label;</description>
               <label id="protections-popup-not-blocking-section-why"
                      class="text-link"
                      onmouseover="document.getElementById(event.target.tooltip).openPopup(event.target);"
-                     onmouseout="document.getElementById(event.target.tooltip).hidePopup()">&protections.notBlocking.why.label;</label>
+                     onfocus="document.getElementById(event.target.tooltip).openPopup(event.target);"
+                     onmouseout="document.getElementById(event.target.tooltip).hidePopup()"
+                     onblur="document.getElementById(event.target.tooltip).hidePopup()">&protections.notBlocking.why.label;</label>
             </hbox>
             <description id="protections-popup-not-found-section-header"
                          role="heading"
                          aria-level="2">&protections.notFound.label;</description>
           </vbox>
         </vbox>
       </vbox>
 
--- a/browser/components/protections/content/lockwise-card.js
+++ b/browser/components/protections/content/lockwise-card.js
@@ -142,17 +142,17 @@ export default class LockwiseCard {
     const textEl = syncedDevicesText.querySelector("span");
     if (syncedDevices) {
       textEl.setAttribute(
         "data-l10n-args",
         JSON.stringify({ count: syncedDevices })
       );
       textEl.setAttribute("data-l10n-id", "lockwise-sync-status");
     } else {
-      textEl.setAttribute("data-l10n-id", "lockwise-sync-not-syncing");
+      textEl.setAttribute("data-l10n-id", "lockwise-sync-not-syncing-devices");
     }
     // Display the link for enabling sync if no synced devices are detected.
     if (syncedDevices === 0) {
       const syncLink = this.doc.getElementById("turn-on-sync");
       syncLink.classList.remove("hidden");
     } else {
       const manageDevicesLink = this.doc.getElementById("manage-devices");
       manageDevicesLink.href = MANAGE_DEVICES_URL;
--- a/browser/components/protections/content/monitor-card.js
+++ b/browser/components/protections/content/monitor-card.js
@@ -70,27 +70,30 @@ export default class MonitorClass {
     const headerContent = this.doc.querySelector(
       "#monitor-header-content span"
     );
     const monitorCard = this.doc.querySelector(".card.monitor-card");
     if (numLogins > 0 && !monitorData.error) {
       monitorCard.classList.add("has-logins");
       headerContent.setAttribute(
         "data-l10n-id",
-        "monitor-header-content-logged-in"
+        "monitor-header-content-signed-in"
       );
       this.renderContentForUserWithLogins(monitorData);
     } else {
       monitorCard.classList.add("no-logins");
       const signUpForMonitorLink = this.doc.getElementById(
         "sign-up-for-monitor-link"
       );
       signUpForMonitorLink.href = this.buildMonitorUrl(monitorData.userEmail);
       signUpForMonitorLink.setAttribute("data-l10n-id", "monitor-sign-up");
-      headerContent.setAttribute("data-l10n-id", "monitor-header-content");
+      headerContent.setAttribute(
+        "data-l10n-id",
+        "monitor-header-content-no-account"
+      );
       signUpForMonitorLink.addEventListener("click", () => {
         this.doc.sendTelemetryEvent("click", "mtr_signup_button");
       });
     }
   }
 
   /**
    * Builds the appropriate URL that takes the user to the Monitor website's
@@ -133,34 +136,37 @@ export default class MonitorClass {
       "info-monitored-addresses"
     );
     infoMonitoredAddresses.setAttribute(
       "data-l10n-args",
       JSON.stringify({ count: monitorData.monitoredEmails })
     );
     infoMonitoredAddresses.setAttribute(
       "data-l10n-id",
-      "info-monitored-addresses"
+      "info-monitored-emails"
     );
 
     const infoKnownBreaches = this.doc.getElementById("info-known-breaches");
     infoKnownBreaches.setAttribute(
       "data-l10n-args",
       JSON.stringify({ count: monitorData.numBreaches })
     );
-    infoKnownBreaches.setAttribute("data-l10n-id", "info-known-breaches");
+    infoKnownBreaches.setAttribute("data-l10n-id", "info-known-breaches-found");
 
     const infoExposedPasswords = this.doc.getElementById(
       "info-exposed-passwords"
     );
     infoExposedPasswords.setAttribute(
       "data-l10n-args",
       JSON.stringify({ count: monitorData.passwords })
     );
-    infoExposedPasswords.setAttribute("data-l10n-id", "info-exposed-passwords");
+    infoExposedPasswords.setAttribute(
+      "data-l10n-id",
+      "info-exposed-passwords-found"
+    );
 
     // Display Lockwise section if there are any potential breached logins to report.
     if (monitorData.potentiallyBreachedLogins > 0) {
       const lockwiseSection = this.doc.querySelector(
         ".monitor-breached-passwords"
       );
       const exposedLockwisePasswords = this.doc.querySelector(
         "span[data-type='breached-lockwise-passwords']"
--- a/browser/components/protections/content/protections.html
+++ b/browser/components/protections/content/protections.html
@@ -80,17 +80,17 @@
                 <div id="cookie" class="tab-content">
                   <p id="cookieTitle" class="content-title" data-l10n-id="cookie-tab-title"></p>
                   <p id="cookieContent" data-l10n-id="cookie-tab-content">
                     <a target="_blank" id="cookie-link" data-l10n-name="learn-more-link"></a>
                   </p>
                 </div>
                 <div id="tracker" class="tab-content">
                   <p id="trackerTitle" class="content-title" data-l10n-id="tracker-tab-title"></p>
-                  <p id="trackerContent" data-l10n-id="tracker-tab-content">
+                  <p id="trackerContent" data-l10n-id="tracker-tab-description">
                     <a target="_blank" id="tracker-link" data-l10n-name="learn-more-link"></a>
                   </p>
                 </div>
                 <div id="fingerprinter" class="tab-content">
                   <p id="fingerprinterTitle" class="content-title" data-l10n-id="fingerprinter-tab-title"></p>
                   <p id="fingerprinterContent" data-l10n-id="fingerprinter-tab-content">
                     <a target="_blank" id="fingerprinter-link" data-l10n-name="learn-more-link"></a>
                   </p>
@@ -180,17 +180,17 @@
           <div class="wrapper">
             <h2 id="lockwise-title" class="card-title">
               <!-- Insert Lockwise card title here. -->
             </h2>
             <p id="lockwise-header-content" class="content">
               <!-- Insert Lockwise header content here. -->
             </p>
           </div>
-          <button id="open-about-logins-button" class="primary" data-l10n-id="open-about-logins-button" data-l10n-title="go-to-saved-logins"></button>
+          <button id="open-about-logins-button" class="primary" data-l10n-id="about-logins-view-logins-button" data-l10n-title="go-to-saved-logins"></button>
         </div>
         <div class="card-body hidden">
           <div id="lockwise-body-content" class="body-wrapper">
             <div class="no-logins hidden">
                 <img class="lockwise-mobile-app-icon" src="chrome://browser/content/logos/lockwise-mobile-app.svg"/>
                 <span data-l10n-id="lockwise-no-logins-content">
                   <a target="_blank" id="lockwise-inline-link" data-l10n-name="lockwise-inline-link" href=""></a>
                 </span>
--- a/browser/components/protections/content/protections.js
+++ b/browser/components/protections/content/protections.js
@@ -76,17 +76,17 @@ document.addEventListener("DOMContentLoa
       ? new Date(data.earliestDate).getTime() + hoursInMS12
       : Date.now();
 
     let summary = document.getElementById("graph-total-summary");
     summary.setAttribute(
       "data-l10n-args",
       JSON.stringify({ count: data.sumEvents, earliestDate: dateInMS })
     );
-    summary.setAttribute("data-l10n-id", "graph-total-summary");
+    summary.setAttribute("data-l10n-id", "graph-total-tracker-summary");
 
     // Set a default top size for the height of the graph bars so that small
     // numbers don't fill the whole graph.
     let largest = 100;
     if (largest < data.largest) {
       largest = data.largest;
     }
     let weekCount = 0;
--- a/browser/components/protections/test/browser/browser_protections_lockwise.js
+++ b/browser/components/protections/test/browser/browser_protections_lockwise.js
@@ -119,17 +119,17 @@ add_task(async function() {
     info("Also check that content for no synced devices is correct.");
     is(
       numberOfSyncedDevices.textContent,
       0,
       "Zero synced devices are displayed."
     );
     is(
       syncedDevicesStatusText.getAttribute("data-l10n-id"),
-      "lockwise-sync-not-syncing",
+      "lockwise-sync-not-syncing-devices",
       "Not syncing to other devices."
     );
 
     info("Check that the link to turn on sync is visible.");
     ok(ContentTaskUtils.is_visible(syncLink), "Sync link is visible.");
   });
 
   info(
--- a/browser/components/protections/test/browser/browser_protections_monitor.js
+++ b/browser/components/protections/test/browser/browser_protections_monitor.js
@@ -88,17 +88,17 @@ add_task(async function() {
     const cardBody = content.document.querySelector(".monitor-card .card-body");
 
     ok(
       ContentTaskUtils.is_visible(cardBody),
       "Card body is shown for users monitor data."
     );
     is(
       hasLoginsHeaderContent.textContent,
-      "Firefox Monitor warns you if your info has appeared in a known data breach",
+      "Firefox Monitor warns you if your info has appeared in a known data breach.",
       "Header content for user with monitor data is correct"
     );
 
     info("Make sure correct numbers for monitor stats are displayed.");
     const emails = content.document.querySelector(
       ".monitor-stat span[data-type='stored-emails']"
     );
     const passwords = content.document.querySelector(
@@ -208,18 +208,13 @@ async function checkNoLoginsContentIsDis
     const cardBody = content.document.querySelector(".monitor-card .card-body");
 
     ok(
       ContentTaskUtils.is_hidden(cardBody),
       "Card body is hidden for users with no logins."
     );
     is(
       noLoginsHeaderContent.getAttribute("data-l10n-id"),
-      "monitor-header-content",
-      "Header content for user with no logins is correct"
-    );
-    is(
-      noLoginsHeaderContent.getAttribute("data-l10n-id"),
-      "monitor-header-content",
+      "monitor-header-content-no-account",
       "Header content for user with no logins is correct"
     );
   });
 }
--- a/browser/components/search/content/search-one-offs.js
+++ b/browser/components/search/content/search-one-offs.js
@@ -109,21 +109,19 @@ class SearchOneOffs {
     this.addEventListener("contextmenu", this);
 
     // Prevent popup events from the context menu from reaching the autocomplete
     // binding (or other listeners).
     let listener = aEvent => aEvent.stopPropagation();
     this.contextMenuPopup.addEventListener("popupshowing", listener);
     this.contextMenuPopup.addEventListener("popuphiding", listener);
     this.contextMenuPopup.addEventListener("popupshown", aEvent => {
-      this._ignoreMouseEvents = true;
       aEvent.stopPropagation();
     });
     this.contextMenuPopup.addEventListener("popuphidden", aEvent => {
-      this._ignoreMouseEvents = false;
       aEvent.stopPropagation();
     });
 
     // Add weak referenced observers to invalidate our cached list of engines.
     this.QueryInterface = ChromeUtils.generateQI([
       Ci.nsIObserver,
       Ci.nsISupportsWeakReference,
     ]);
@@ -298,17 +296,28 @@ class SearchOneOffs {
     let previousButton = this._selectedButton;
     if (previousButton) {
       previousButton.removeAttribute("selected");
     }
     if (val) {
       val.setAttribute("selected", "true");
     }
     this._selectedButton = val;
-    this._updateStateForButton(null);
+
+    if (this.textbox) {
+      if (val) {
+        this.textbox.setAttribute("aria-activedescendant", val.id);
+      } else {
+        let active = this.textbox.getAttribute("aria-activedescendant");
+        if (active && active.includes("-engine-one-off-item-")) {
+          this.textbox.removeAttribute("aria-activedescendant");
+        }
+      }
+    }
+
     if (val && !val.engine) {
       // If the button doesn't have an engine, then clear the popup's
       // selection to indicate that pressing Return while the button is
       // selected will do the button's command, not search.
       this.selectedAutocompleteIndex = -1;
     }
     let event = new CustomEvent("SelectedOneOffButtonChanged", {
       previousSelectedButton: previousButton,
@@ -644,39 +653,16 @@ class SearchOneOffs {
     return name.replace(/ /g, "-");
   }
 
   _buttonForEngine(engine) {
     let id = this._buttonIDForEngine(engine);
     return document.getElementById(id);
   }
 
-  /**
-   * Updates the popup and textbox for the currently selected or moused-over
-   * button.
-   *
-   * @param {DOMElement} mousedOverButton
-   *        The currently moused-over button, or null if there isn't one.
-   */
-  _updateStateForButton(mousedOverButton) {
-    let button = mousedOverButton;
-
-    // If there's no moused-over button, then the one-offs should reflect
-    // the selected button, if any.
-    button = button || this.selectedButton;
-
-    if (this.textbox) {
-      if (!button) {
-        this.textbox.removeAttribute("aria-activedescendant");
-      } else {
-        this.textbox.setAttribute("aria-activedescendant", button.id);
-      }
-    }
-  }
-
   getSelectableButtons(aIncludeNonEngineButtons) {
     let buttons = [];
     for (
       let oneOff = this.buttons.firstElementChild;
       oneOff;
       oneOff = oneOff.nextElementSibling
     ) {
       buttons.push(oneOff);
@@ -1075,67 +1061,33 @@ class SearchOneOffs {
     let target = event.originalTarget;
 
     // Handle mouseover on the add-engine menu button and its popup items.
     if (
       (target.localName == "menuitem" &&
         target.classList.contains("addengine-item")) ||
       target.classList.contains("addengine-menu-button")
     ) {
-      let menuButton = this.querySelector(".addengine-menu-button");
-      this._updateStateForButton(menuButton);
       this._addEngineMenuShouldBeOpen = true;
       this._resetAddEngineMenuTimeout();
-      return;
-    }
-
-    if (target.localName != "button") {
-      return;
-    }
-
-    // Ignore mouse events when the context menu is open.
-    if (this._ignoreMouseEvents) {
-      return;
-    }
-
-    let isOneOff = target.classList.contains("searchbar-engine-one-off-item");
-    if (
-      isOneOff ||
-      target.classList.contains("addengine-item") ||
-      target.classList.contains("search-setting-button")
-    ) {
-      this._updateStateForButton(target);
     }
   }
 
   _on_mouseout(event) {
     let target = event.originalTarget;
 
     // Handle mouseout on the add-engine menu button and its popup items.
     if (
       (target.localName == "menuitem" &&
         target.classList.contains("addengine-item")) ||
       target.classList.contains("addengine-menu-button")
     ) {
-      this._updateStateForButton(null);
       this._addEngineMenuShouldBeOpen = false;
       this._resetAddEngineMenuTimeout();
-      return;
     }
-
-    if (target.localName != "button") {
-      return;
-    }
-
-    // Don't update the mouseover state if the context menu is open.
-    if (this._ignoreMouseEvents) {
-      return;
-    }
-
-    this._updateStateForButton(null);
   }
 
   _on_click(event) {
     if (event.button == 2) {
       return; // ignore right clicks.
     }
 
     let button = event.originalTarget;
--- a/browser/components/search/extensions/engines.json
+++ b/browser/components/search/extensions/engines.json
@@ -1,12 +1,12 @@
 {
   "data": [
     {
-      "engineName": "google",
+      "engineName": "Google",
       "orderHint": 1000,
       "webExtensionId": "google@search.mozilla.org",
       "webExtensionVersion": "1.0",
       "searchUrlGetExtraCodes": "client=firefox-b-d",
       "appliesTo": [{
         "included": { "everywhere": true },
         "default": "yes"
       }, {
@@ -28,17 +28,17 @@
         "default": "no"
       }, {
         "included": { "regions": ["us"] },
         "searchUrlGetExtraCodes": "client=firefox-b-1-d"
       }],
       "aliases": ["@google"]
     },
     {
-      "engineName": "bing",
+      "engineName": "Bing",
       "webExtensionId": "bing@search.mozilla.org",
       "webExtensionVersion": "1.0",
       "appliesTo": [{
         "included": {
           "locales": {
             "matches": [
               "ach", "af", "an", "ar", "ast", "az", "ca", "cak", "da", "de",
               "dsb", "el", "eo", "es-CL", "es-ES",
@@ -52,32 +52,32 @@
             ],
             "startsWith": ["bn", "en"]
           }
         }
       }],
       "aliases": ["@bing"]
     },
     {
-      "engineName": "baidu",
+      "engineName": "\u767E\u5EA6",
       "webExtensionId": "baidu@search.mozilla.org",
       "webExtensionVersion": "1.0",
       "appliesTo": [{
         "included": { "locales": { "matches": ["zh-CN"] } }
       }, {
         "included": {
           "regions": ["cn"],
           "locales": { "matches": ["zh-CN"] }
         },
         "default": "yes"
       }],
       "aliases": ["@\u767E\u5EA6", "@baidu"]
     },
     {
-      "engineName": "amazon",
+      "engineName": "Amazon.com",
       "orderHint": 500,
       "webExtensionId": "amazondotcom@search.mozilla.org",
       "webExtensionVersion": "1.1",
       "appliesTo": [{
         "included": {
           "locales": {
             "matches": [
               "ach", "af", "ar", "az", "bg", "cak", "en-US", "eo",
@@ -96,137 +96,150 @@
               "es-AR", "fa", "gn", "hy-AM", "ia", "is", "ka", "km",
               "lt", "mk", "ms", "my", "ro", "si", "th", "tl",
               "trs", "uz"
             ]
           }
         },
         "webExtensionId": "amazon@search.mozilla.org",
         "webExtensionVersion": "1.1",
-        "webExtensionLocale": "au"
+        "webExtensionLocale": "au",
+        "engineName": "Amazon.com.au"
       }, {
         "included": {
           "regions": ["ca"],
           "locales": {
             "matches": [
               "ach", "af", "ar", "az", "bg", "cak", "en-US", "eo",
               "es-AR", "fa", "gn", "hy-AM", "ia", "is", "ka", "km",
               "lt", "mk", "ms", "my", "ro", "si", "th", "tl",
               "trs", "uz"
             ]
           }
         },
         "webExtensionId": "amazon@search.mozilla.org",
         "webExtensionVersion": "1.1",
-        "webExtensionLocale": "ca"
+        "webExtensionLocale": "ca",
+        "engineName": "Amazon.ca"
       }, {
         "included": {
           "regions": ["fr"],
           "locales": {
             "matches": [
               "ach", "af", "ar", "az", "bg", "cak", "en-US", "eo",
               "es-AR", "fa", "gn", "hy-AM", "ia", "is", "ka", "km",
               "lt", "mk", "ms", "my", "ro", "si", "th", "tl",
               "trs", "uz"
             ]
           }
         },
         "webExtensionId": "amazon@search.mozilla.org",
         "webExtensionVersion": "1.1",
-        "webExtensionLocale": "france"
+        "webExtensionLocale": "france",
+        "engineName": "Amazon.fr"
       }, {
         "included": {
           "regions": ["gb"],
           "locales": {
             "matches": [
               "ach", "af", "ar", "az", "bg", "cak", "en-US", "eo",
               "es-AR", "fa", "gn", "hy-AM", "ia", "is", "ka", "km",
               "lt", "mk", "ms", "my", "ro", "si", "th", "tl",
               "trs", "uz"
             ]
           }
         },
         "webExtensionId": "amazon@search.mozilla.org",
         "webExtensionVersion": "1.1",
-        "webExtensionLocale": "en-GB"
+        "webExtensionLocale": "en-GB",
+        "engineName": "Amazon.co.uk"
       }],
       "aliases": ["amazon"]
     },
     {
-      "engineName": "amazon",
+      "engineName": "Amazon",
       "orderHint": 500,
       "webExtensionId": "amazon@search.mozilla.org",
       "webExtensionVersion": "1.1",
       "appliesTo": [{
         "included": {
           "locales": { "matches": [
             "as", "bn", "bn-IN", "kn", "gu-IN", "mai", "ml", "mr",
             "or", "pa-IN", "ta", "te", "ur"
           ]}
         },
-        "webExtensionLocale": "in"
+        "webExtensionLocale": "in",
+        "engineName": "Amazon.in"
       }, {
         "included": {
           "locales": { "matches": ["br", "ff", "fr", "son", "wo"] }
         },
-        "webExtensionLocale": "france"
+        "webExtensionLocale": "france",
+        "engineName": "Amazon.fr"
       }, {
         "included": {
           "regions": ["ca"],
           "locales": { "matches": ["br", "ff", "fr", "son", "wo"] }
         },
-        "webExtensionLocale": "ca"
+        "webExtensionLocale": "ca",
+        "engineName": "Amazon.ca"
       }, {
         "included": { "locales": { "matches": ["en-CA"] } },
-        "webExtensionLocale": "ca"
+        "webExtensionLocale": "ca",
+        "engineName": "Amazon.ca"
       }, {
         "included": { "locales": { "matches": ["ja-JP-mac", "ja"] } },
-        "webExtensionLocale": "jp"
+        "webExtensionLocale": "jp",
+        "engineName": "Amazon.jp"
       }, {
         "included": { "locales": { "matches": ["it", "lij"] } },
-        "webExtensionLocale": "it"
+        "webExtensionLocale": "it",
+        "engineName": "Amazon.it"
       }, {
         "included": { "locales": { "matches": ["de", "dsb", "hsb"] } },
-        "webExtensionLocale": "de"
+        "webExtensionLocale": "de",
+        "engineName": "Amazon.de"
       }, {
         "included": {
           "locales": {
             "matches": [
               "cy", "da", "el", "en-GB", "eu", "ga-IE", "gd", "gl", "hr",
               "nb-NO", "nn-NO", "pt-PT", "sq", "sr"
             ]
           }
         },
-        "webExtensionLocale": "en-GB"
+        "webExtensionLocale": "en-GB",
+        "engineName": "Amazon.co.uk"
       }, {
         "included": {
           "regions": ["au"],
           "locales": {
             "matches": [
               "cy", "da", "el", "en-GB", "eu", "ga-IE", "gd", "gl", "hr",
               "nb-NO", "nn-NO", "pt-PT", "sq", "sr"
             ]
           }
         },
-        "webExtensionLocale": "au"
+        "webExtensionLocale": "au",
+        "engineName": "Amazon.au"
       }],
       "aliases": ["amazon"]
     },
     {
-      "engineName": "amazon",
+      "engineName": "\u4E9A\u9A6C\u900A",
       "orderHint": 500,
       "webExtensionId": "amazondotcn@search.mozilla.org",
       "webExtensionVersion": "1.0",
       "appliesTo": [{
         "included": { "locales": { "matches": ["zh-CN"] } }
       }],
       "aliases": ["amazon"]
     },
     {
-      "engineName": "ebay",
+      "engineName": "eBay",
       "orderHint": 500,
       "webExtensionId": "ebay@search.mozilla.org",
       "webExtensionVersion": "1.0",
       "appliesTo": [{
         "included": { "locales": { "matches": ["en-US"] } },
         "excluded": { "regions": ["ru", "tr", "by", "kz"] }
       }, {
         "included": {
@@ -322,27 +335,27 @@
         "webExtensionLocale": "it"
       }, {
         "included": { "locales": { "matches": ["rm"] }},
         "webExtensionLocale": "ch"
       }],
       "aliases": ["@ebay"]
     },
     {
-      "engineName": "ddg",
+      "engineName": "DuckDuckGo",
       "orderHint": 500,
       "webExtensionId": "ddg@search.mozilla.org",
       "webExtensionVersion": "1.0",
       "appliesTo": [{
         "included": { "everywhere": true }
       }],
       "aliases": ["@duckduckgo", "@ddg"]
     },
     {
-      "engineName": "yandex",
+      "engineName": "Yandex",
       "webExtensionId": "yandex@search.mozilla.org",
       "webExtensionVersion": "1.0",
       "appliesTo": [{
         "default": "yes",
         "included": {
           "regions": ["ru", "tr", "by", "kz"],
           "locales": {
             "matches": ["ru", "tr", "be", "kk"],
@@ -350,23 +363,26 @@
           }
         },
         "webExtensionLocale": "en"
       }, {
         "included": { "locales": { "matches": ["az"] }},
         "webExtensionLocale": "az"
       }, {
         "included": { "locales": { "matches": ["be"] }},
-        "webExtensionLocale": "by"
+        "webExtensionLocale": "by",
+        "engineName": "\u044F\u043D\u0434\u0435\u043A\u0441"
       }, {
         "included": { "locales": { "matches": ["kk"] }},
-        "webExtensionLocale": "kk"
+        "webExtensionLocale": "kk",
+        "engineName": "\u044F\u043D\u0434\u0435\u043A\u0441"
       }, {
         "included": { "locales": { "matches": ["ru"] }},
-        "webExtensionLocale": "ru"
+        "webExtensionLocale": "ru",
+        "engineName": "\u044F\u043D\u0434\u0435\u043A\u0441"
       }, {
         "included": { "locales": { "matches": ["tr"] }},
         "webExtensionLocale": "tr"
       }],
       "aliases": ["@\u044F\u043D\u0434\u0435\u043A\u0441", "@yandex"]
     },
     {
       "engineName": "allaannonser-sv-SE",
--- a/browser/components/search/test/browser/browser.ini
+++ b/browser/components/search/test/browser/browser.ini
@@ -33,17 +33,16 @@ skip-if = verify && debug && os == 'win'
 [browser_eBay.js]
 [browser_google.js]
 [browser_google_behavior.js]
 [browser_healthreport.js]
 skip-if = (verify && debug && (os == 'win' || os == 'linux'))
 [browser_hiddenOneOffs_cleanup.js]
 [browser_hiddenOneOffs_diacritics.js]
 [browser_oneOffContextMenu.js]
-skip-if = verify
 [browser_oneOffContextMenu_setDefault.js]
 [browser_private_search_perwindowpb.js]
 [browser_searchbar_openpopup.js]
 skip-if = os == "linux" # Linux has different focus behaviours.
 [browser_searchbar_keyboard_navigation.js]
 [browser_searchbar_smallpanel_keyboard_navigation.js]
 [browser_searchEngine_behaviors.js]
 [browser_searchTelemetry.js]
--- a/browser/components/urlbar/UrlbarInput.jsm
+++ b/browser/components/urlbar/UrlbarInput.jsm
@@ -49,16 +49,38 @@ class UrlbarInput {
    *   Intended for use in unit tests only.
    */
   constructor(options = {}) {
     this.textbox = options.textbox;
 
     this.window = this.textbox.ownerGlobal;
     this.document = this.window.document;
     this.window.addEventListener("unload", this);
+
+    // Create the panel to contain results.
+    this.textbox.appendChild(
+      this.window.MozXULElement.parseXULToFragment(`
+        <vbox class="urlbarView"
+              role="group"
+              tooltip="aHTMLTooltip"
+              hidden="true">
+          <html:div class="urlbarView-body-outer">
+            <html:div class="urlbarView-body-inner">
+              <html:div id="urlbar-results"
+                        class="urlbarView-results"
+                        role="listbox"/>
+            </html:div>
+          </html:div>
+          <hbox class="search-one-offs"
+                compact="true"
+                includecurrentengine="true"
+                disabletab="true"/>
+        </vbox>
+      `)
+    );
     this.panel = this.textbox.querySelector(".urlbarView");
 
     this.megabar = UrlbarPrefs.get("megabar");
     if (this.megabar) {
       this.textbox.classList.add("megabar");
     }
 
     this.controller =
@@ -204,16 +226,17 @@ class UrlbarInput {
    */
   uninit() {
     this.window.removeEventListener("unload", this);
     for (let name of this._inputFieldEvents) {
       this.removeEventListener(name, this);
     }
     this.dropmarker.removeEventListener("mousedown", this);
 
+    this.view.panel.remove();
     this.endLayoutBreakout(true);
 
     // When uninit is called due to exiting the browser's customize mode,
     // this.inputField.controllers is not the original list of controllers, and
     // it doesn't contain CopyCutController.  That's why removeCopyCutController
     // must be called when entering customize mode.  If uninit ends up getting
     // called by something else though, try to remove the controller now.
     try {
--- a/browser/config/mozconfigs/linux64/code-coverage
+++ b/browser/config/mozconfigs/linux64/code-coverage
@@ -7,11 +7,12 @@ TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
 ac_add_options --disable-install-strip
 ac_add_options --disable-elf-hack
 ac_add_options --disable-sandbox
 ac_add_options --disable-dmd
 ac_add_options --disable-profiling
 ac_add_options --disable-warnings-as-errors
 ac_add_options --enable-coverage
 
-export LDFLAGS="--coverage -L$MOZ_FETCHES_DIR/clang/lib/clang/8.0.1/lib/linux/"
+CLANG_LIB_DIR="$(cd $MOZ_FETCHES_DIR/clang/lib/clang/* && cd lib/linux && pwd)"
+export LDFLAGS="--coverage -L$CLANG_LIB_DIR"
 export LIBS="-lclang_rt.profile-x86_64"
 export RUSTFLAGS="-Ccodegen-units=1 -Zprofile -Zno-landing-pads -Clink-dead-code -Coverflow-checks=off"
--- a/browser/config/mozconfigs/macosx64/code-coverage
+++ b/browser/config/mozconfigs/macosx64/code-coverage
@@ -3,11 +3,12 @@
 unset MOZ_LTO
 
 TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
 
 ac_add_options --disable-sandbox
 ac_add_options --disable-warnings-as-errors
 ac_add_options --enable-coverage
 
-export LDFLAGS="-coverage -L$MOZ_FETCHES_DIR/clang/lib/clang/8.0.1/lib/darwin/"
+CLANG_LIB_DIR="$(cd $MOZ_FETCHES_DIR/clang/lib/clang/* && cd lib/darwin && pwd)"
+export LDFLAGS="-coverage -L$CLANG_LIB_DIR"
 export LIBS="-lclang_rt.profile_osx"
 export RUSTFLAGS="-Ccodegen-units=1 -Zprofile -Zno-landing-pads -Clink-dead-code -Coverflow-checks=off"
--- a/browser/locales/en-US/browser/protections.ftl
+++ b/browser/locales/en-US/browser/protections.ftl
@@ -1,28 +1,28 @@
 # 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/.
 
 # Variables:
 #   $count (Number) - Number of tracking events blocked.
 graph-week-summary =
   { $count ->
-     [one] { -brand-short-name } blocked  { $count } tracker over the past week
+     [one] { -brand-short-name } blocked { $count } tracker over the past week
     *[other] { -brand-short-name } blocked { $count } trackers over the past week
   }
 
 # Variables:
 #   $count (Number) - Number of tracking events blocked.
 #   $earliestDate (Number) - Unix timestamp in ms, representing a date. The
 # earliest date recorded in the database.
-graph-total-summary =
+graph-total-tracker-summary =
   { $count ->
-     [one] { $count } tracker blocked since { DATETIME($earliestDate, day: "numeric", month: "long", year: "numeric") }
-    *[other] { $count } trackers blocked since { DATETIME($earliestDate, day: "numeric", month: "long", year: "numeric") }
+     [one] <b>{ $count }</b> tracker blocked since { DATETIME($earliestDate, day: "numeric", month: "long", year: "numeric") }
+    *[other] <b>{ $count }</b> trackers blocked since { DATETIME($earliestDate, day: "numeric", month: "long", year: "numeric") }
   }
 
 # The terminology used to refer to categories of Content Blocking is also used in chrome/browser/browser.properties and should be translated consistently.
 # "Standard" in this case is an adjective, meaning "default" or "normal".
 # The category name in the <b> tag will be bold.
 protection-header-details-standard = Protection Level is set to <b>Standard</b>
 protection-header-details-strict = Protection Level is set to <b>Strict</b>
 protection-header-details-custom = Protection Level is set to <b>Custom</b>
@@ -41,29 +41,29 @@ graph-legend-description = A graph conta
 
 social-tab-title = Social Media Trackers
 social-tab-contant = Social networks place trackers on other websites to follow what you do, see, and watch online. This allows social media companies to learn more about you beyond what you share on your social media profiles. <a data-l10n-name="learn-more-link">Learn more</a>
 
 cookie-tab-title = Cross-Site Tracking Cookies
 cookie-tab-content = These cookies follow you from site to site to gather data about what you do online. They are set by third parties such as advertisers and analytics companies. Blocking cross-site tracking cookies reduces the number of ads that follow you around. <a data-l10n-name="learn-more-link">Learn more</a>
 
 tracker-tab-title = Tracking Content
-tracker-tab-content = Websites may load external ads, videos, and other content that contain tracking code. Blocking tracking content can help sites load faster, but some buttons, forms, and login fields might not work. <a data-l10n-name="learn-more-link">Learn more</a>
+tracker-tab-description = Websites may load external ads, videos, and other content with tracking code. Blocking tracking content can help sites load faster, but some buttons, forms, and login fields might not work. <a data-l10n-name="learn-more-link">Learn more</a>
 
 fingerprinter-tab-title = Fingerprinters
 fingerprinter-tab-content = Fingerprinters collect settings from your browser and computer to create a profile of you. Using this digital fingerprint, they can track you across different websites. <a data-l10n-name="learn-more-link">Learn more</a>
 
 cryptominer-tab-title = Cryptominers
 cryptominer-tab-content = Cryptominers use your system’s computing power to mine digital money. Cryptomining scripts drain your battery, slow down your computer, and can increase your energy bill. <a data-l10n-name="learn-more-link">Learn more</a>
 
 lockwise-title = Never forget a password again
 lockwise-title-logged-in = { -lockwise-brand-name }
 lockwise-header-content = { -lockwise-brand-name } securely stores your passwords in your browser.
 lockwise-header-content-logged-in = Securely store and sync your passwords to all your devices.
-open-about-logins-button = Open in { -brand-short-name }
+about-logins-view-logins-button = View Logins
 lockwise-no-logins-content = Get the <a data-l10n-name="lockwise-inline-link">{ -lockwise-brand-name }</a> app to take your passwords everywhere.
 
 # This string is displayed after a large numeral that indicates the total number
 # of email addresses being monitored. Don’t add $count to
 # your localization, because it would result in the number showing twice.
 lockwise-passwords-stored =
   { $count ->
      [one] Password stored securely <a data-l10n-name="lockwise-how-it-works">How it works</a>
@@ -77,50 +77,50 @@ manage-devices = Manage devices
 
 # Variables:
 #   $count (Number) - Number of devices connected with sync.
 lockwise-sync-status =
   { $count ->
      [one] Syncing to { $count } other device
     *[other] Syncing to { $count } other devices
   }
-lockwise-sync-not-syncing = Not syncing to other devices.
+lockwise-sync-not-syncing-devices = Not syncing to other devices
 
 monitor-title = Look out for data breaches
 monitor-link = How it works
-monitor-header-content = Check { -monitor-brand-name } to see if you’ve been part of a data breach and get alerts about new breaches.
-monitor-header-content-logged-in = { -monitor-brand-name } warns you if your info has appeared in a known data breach
+monitor-header-content-no-account = Check { -monitor-brand-name } to see if you’ve been part of a known data breach, and get alerts about new breaches.
+monitor-header-content-signed-in = { -monitor-brand-name } warns you if your info has appeared in a known data breach.
 monitor-sign-up = Sign Up for Breach Alerts
 auto-scan = Automatically scanned today
 
 # This string is displayed after a large numeral that indicates the total number
 # of email addresses being monitored. Don’t add $count to
 # your localization, because it would result in the number showing twice.
-info-monitored-addresses =
+info-monitored-emails =
   { $count ->
-     [one] Email address being monitored.
-    *[other] Email addresses being monitored.
+     [one] Email address being monitored
+    *[other] Email addresses being monitored
   }
 
 # This string is displayed after a large numeral that indicates the total number
 # of known data breaches. Don’t add $count to
 # your localization, because it would result in the number showing twice.
-info-known-breaches =
+info-known-breaches-found =
   { $count ->
-     [one] Known data breach has exposed your information.
-    *[other] Known data breaches have exposed your information.
+     [one] Known data breach has exposed your information
+    *[other] Known data breaches have exposed your information
   }
 
 # This string is displayed after a large numeral that indicates the total number
 # of exposed passwords. Don’t add $count to
 # your localization, because it would result in the number showing twice.
-info-exposed-passwords =
+info-exposed-passwords-found =
   { $count ->
-     [one] Password exposed across all breaches.
-    *[other] Passwords exposed across all breaches.
+     [one] Password exposed across all breaches
+    *[other] Passwords exposed across all breaches
   }
 
 full-report-link = View full report on <a data-l10n-name="monitor-inline-link">{ -monitor-brand-name }</a>
 
 # This string is displayed after a large numeral that indicates the total number
 # of saved logins which may have been exposed. Don’t add $count to
 # your localization, because it would result in the number showing twice.
 password-warning =
--- a/browser/themes/shared/controlcenter/panel.inc.css
+++ b/browser/themes/shared/controlcenter/panel.inc.css
@@ -672,17 +672,16 @@ description#identity-popup-content-verif
 }
 
 #protections-popup-blocking-section-header,
 #protections-popup-not-blocking-section-header,
 #protections-popup-not-found-section-header {
   margin: 0;
   padding: var(--vertical-section-padding) var(--horizontal-padding);
   color: #737373;
-  display: none;
 }
 
 :root[lwt-popup-brighttext] #protections-popup-no-trackers-found-description,
 :root[lwt-popup-brighttext] #protections-popup-blocking-section-header,
 :root[lwt-popup-brighttext] #protections-popup-not-blocking-section-header {
   color: #f9f9fa;
 }
 
@@ -694,139 +693,53 @@ description#identity-popup-content-verif
  * with five different category items distributed between them at runtime.
  * To achieve this, we use a grid layout with 12 rows: one row for each header
  * label and five rows in each section for the items.
  * Items with the "blocked" class are assigned rows 2-6, and those without
  * are assigned rows 8-12, with the headers taking rows 1 and 7.
  */
 
 #protections-popup-category-list {
-  display: grid;
   padding: 0;
   margin: 0;
 }
 
 #protections-popup-no-trackers-found-description:not([hidden]) ~ #protections-popup-content {
   display: none;
 }
 
-#protections-popup-blocking-section-header,
-#protections-popup-not-blocking-section-header,
-#protections-popup-not-found-section-header {
-  display: none;
-}
-
-#protections-popup-blocking-section-header {
-  grid-row: 1;
-}
-
-#protections-popup:not([hasException]) .protections-popup-category.blocked:not(.notFound) ~ #protections-popup-blocking-section-header,
-.protections-popup-category.notFound ~ #protections-popup-not-found-section-header,
-.protections-popup-category:not(.blocked):not(.notFound) ~ #protections-popup-not-blocking-section-header,
-#protections-popup[hasException] .protections-popup-category:not(.notFound) ~ #protections-popup-not-blocking-section-header {
-  display: flex;
-}
-
-#protections-popup:not([hasException]) #protections-popup-category-socialblock.blocked {
-  grid-row: 2;
-}
-
-#protections-popup:not([hasException]) #protections-popup-category-cookies.blocked {
-  grid-row: 3;
-}
-
-#protections-popup:not([hasException]) #protections-popup-category-tracking-protection.blocked {
-  grid-row: 4;
-}
-
-#protections-popup:not([hasException]) #protections-popup-category-fingerprinters.blocked {
-  grid-row: 5;
-}
-
-#protections-popup:not([hasException]) #protections-popup-category-cryptominers.blocked {
-  grid-row: 6;
-}
-
-#protections-popup-not-blocking-section-header {
-  grid-row: 7;
-}
-
 #protections-popup-not-blocking-section-description {
   flex: -moz-available;
   margin: 0;
 }
 
 #protections-popup-not-blocking-section-why {
   margin: 0;
 }
 
 #protections-popup-not-blocking-section-why:hover {
   background-color: var(--arrowpanel-dimmed);
   outline: 4px solid var(--arrowpanel-dimmed);
   text-decoration: none;
 }
 
-#protections-popup-category-socialblock {
-  grid-row: 8;
-}
-
-#protections-popup-category-cookies {
-  grid-row: 9;
-}
-
-#protections-popup-category-tracking-protection {
-  grid-row: 10;
-}
-
-#protections-popup-category-fingerprinters {
-  grid-row: 11;
-}
-
-#protections-popup-category-cryptominers {
-  grid-row: 12;
-}
-
-#protections-popup-not-found-section-header {
-  grid-row: 13;
-}
-
 .protections-popup-category.notFound {
   color: var(--panel-disabled-color);
   fill: var(--panel-disabled-color);
 }
 
 .protections-popup-category.notFound:hover {
   background: none;
 }
 
 /* Hide the arrow for not found items */
 .protections-popup-category.notFound::after {
   display: none;
 }
 
-#protections-popup-category-socialblock.notFound {
-  grid-row: 14 !important;
-}
-
-#protections-popup-category-cookies.notFound {
-  grid-row: 15 !important;
-}
-
-#protections-popup-category-tracking-protection.notFound {
-  grid-row: 16 !important;
-}
-
-#protections-popup-category-fingerprinters.notFound {
-  grid-row: 17 !important;
-}
-
-#protections-popup-category-cryptominers.notFound {
-  grid-row: 18 !important;
-}
-
 .tracking-protection-icon {
   list-style-image: url(chrome://browser/skin/controlcenter/tracker-image.svg);
 }
 
 .socialblock-icon {
   list-style-image: url(chrome://browser/skin/controlcenter/socialblock.svg);
 }
 
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -1859,16 +1859,20 @@ toolbarpaletteitem[place="menu-panel"] >
 
 #PanelUI-whatsNew .whatsNew-message::before {
   content: "";
   display: block;
   height: 1px;
   background: var(--panel-separator-color);
 }
 
+#PanelUI-whatsNew .whatsNew-message:last-child {
+  border-bottom: none;
+}
+
 #PanelUI-whatsNew .whatsNew-message-date {
   font-size: 11px;
   margin: 0 -12px;
   margin-top: -1px; /* Hide the border separator between messages */
   padding: 6px 16px;
   background: var(--toolbar-bgcolor);
 }
 
--- a/browser/themes/shared/places/editBookmarkPanel.inc.css
+++ b/browser/themes/shared/places/editBookmarkPanel.inc.css
@@ -20,16 +20,21 @@
 .panel-info-button[checked] {
   background-color: var(--toolbarbutton-active-background);
 }
 
 .panel-info-button:hover {
   background-color: var(--toolbarbutton-hover-background);
 }
 
+.panel-info-button:focus {
+  background-color: var(--toolbarbutton-hover-background);
+  box-shadow: var(--focus-ring-box-shadow);
+}
+
 .panel-info-button > image {
   list-style-image: url(chrome://browser/skin/identity-icon.svg);
   -moz-context-properties: fill, fill-opacity;
   fill: currentColor;
   fill-opacity: var(--toolbarbutton-icon-fill-opacity);
   padding: 2px;
 }
 
--- a/build/gen_automation.py
+++ b/build/gen_automation.py
@@ -1,13 +1,13 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distibuted with this
-# file, You can obtain one at http://mozilla.og/MPL/2.0/.
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import sys
 import buildconfig
 from mozbuild.preprocessor import Preprocessor
 
 
 def main(output, input_file):
     pp = Preprocessor()
--- a/build/gen_symverscript.py
+++ b/build/gen_symverscript.py
@@ -1,13 +1,13 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distibuted with this
-# file, You can obtain one at http://mozilla.og/MPL/2.0/.
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import sys
 from mozbuild.preprocessor import Preprocessor
 
 
 def main(output, input_file, version):
     pp = Preprocessor()
     pp.context.update({
--- a/devtools/client/debugger/moz.build
+++ b/devtools/client/debugger/moz.build
@@ -13,8 +13,12 @@ include('../shared/build/node-templates.
 
 BROWSER_CHROME_MANIFESTS += [
   'test/mochitest/browser.ini',
 ]
 
 DevToolsModules(
     'panel.js',
 )
+
+with Files('**'):
+    BUG_COMPONENT = ('DevTools', 'Debugger')
+
--- a/devtools/client/inspector/components/InspectorTabPanel.css
+++ b/devtools/client/inspector/components/InspectorTabPanel.css
@@ -1,14 +1,8 @@
 /* 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/. */
 
-.devtools-inspector-tab-frame {
-  border: none;
-  height: 100%;
-  width: 100%;
-}
-
 .devtools-inspector-tab-panel {
   width: 100%;
   height: 100%;
 }
--- a/devtools/client/inspector/index.xhtml
+++ b/devtools/client/inspector/index.xhtml
@@ -134,17 +134,13 @@
 
         <div id="computed-container">
           <div id="computed-container-focusable" tabindex="-1">
             <div id="computed-property-container" class="devtools-monospace" tabindex="0" dir="ltr"></div>
             <div id="computed-no-results" class="devtools-sidepanel-no-result" hidden="" data-localization="content=inspector.noProperties"></div>
           </div>
         </div>
       </div>
-
-      <div id="sidebar-panel-animationinspector" class="theme-sidebar inspector-tabpanel">
-        <iframe class="devtools-inspector-tab-frame"></iframe>
-      </div>
     </div>
 
   </div>
 </body>
 </html>
--- a/devtools/client/netmonitor/src/components/websockets/Toolbar.js
+++ b/devtools/client/netmonitor/src/components/websockets/Toolbar.js
@@ -47,16 +47,21 @@ class Toolbar extends Component {
       searchboxRef: PropTypes.object.isRequired,
       toggleFrameFilterType: PropTypes.func.isRequired,
       clearFrames: PropTypes.func.isRequired,
       setFrameFilterText: PropTypes.func.isRequired,
       frameFilterType: PropTypes.string.isRequired,
     };
   }
 
+  componentWillUnmount() {
+    const { setFrameFilterText } = this.props;
+    setFrameFilterText("");
+  }
+
   /**
    * Render a separator.
    */
   renderSeparator() {
     return span({ className: "devtools-separator" });
   }
 
   /**
--- a/devtools/client/netmonitor/test/browser.ini
+++ b/devtools/client/netmonitor/test/browser.ini
@@ -233,8 +233,11 @@ skip-if = (os == 'win' && os_version == 
 [browser_net_truncate.js]
 [browser_net_view-source-debugger.js]
 [browser_net_waterfall-click.js]
 [browser_net_websocket_stacks.js]
 [browser_net_worker_stacks.js]
 [browser_net_ws-basic.js]
 [browser_net_ws-clear.js]
 [browser_net_ws-filter-dropdown.js]
+[browser_net_ws-limit-payload.js]
+[browser_net_ws-limit-frames.js]
+[browser_net-ws-filter-freetext.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/browser_net-ws-filter-freetext.js
@@ -0,0 +1,100 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Test that WS connection is established successfully and filtering messages using freetext works correctly.
+ */
+
+add_task(async function() {
+  await SpecialPowers.pushPrefEnv({
+    set: [["devtools.netmonitor.features.webSockets", true]],
+  });
+  const { tab, monitor } = await initNetMonitor(WS_PAGE_URL);
+  info("Starting test... ");
+
+  const { document, store, windowRequire } = monitor.panelWin;
+  const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
+  const { getDisplayedFrames } = windowRequire(
+    "devtools/client/netmonitor/src/selectors/web-sockets"
+  );
+
+  store.dispatch(Actions.batchEnable(false));
+
+  // Wait for WS connection(s) to be established + send messages
+  await ContentTask.spawn(tab.linkedBrowser, {}, async () => {
+    await content.wrappedJSObject.openConnection(3);
+    await content.wrappedJSObject.openConnection(1);
+  });
+
+  const requests = document.querySelectorAll(".request-list-item");
+  is(requests.length, 2, "There should be two requests");
+
+  // Wait for all sent/received messages to be displayed in DevTools
+  wait = waitForDOM(
+    document,
+    "#messages-panel .ws-frames-list-table .ws-frame-list-item",
+    6
+  );
+
+  // Select the first request
+  EventUtils.sendMouseEvent({ type: "mousedown" }, requests[0]);
+
+  // Click on the "Messages" panel
+  EventUtils.sendMouseEvent(
+    { type: "click" },
+    document.querySelector("#messages-tab")
+  );
+  await wait;
+
+  // Get all messages present in the "Messages" panel
+  const frames = document.querySelectorAll(
+    "#messages-panel .ws-frames-list-table .ws-frame-list-item"
+  );
+
+  // Check expected results
+  is(frames.length, 6, "There should be six frames");
+
+  // Fill filter input with text and check displayed messages
+  const type = string => {
+    for (const ch of string) {
+      EventUtils.synthesizeKey(ch, {}, monitor.panelWin);
+    }
+  };
+  const filterInput = document.querySelector(
+    "#messages-panel .devtools-filterinput"
+  );
+  filterInput.focus();
+  type("Payload 2");
+
+  // Wait till the text filter is applied.
+  await waitUntil(() => getDisplayedFrames(store.getState()).length == 2);
+
+  const filteredFrames = document.querySelectorAll(
+    "#messages-panel .ws-frames-list-table .ws-frame-list-item"
+  );
+  is(filteredFrames.length, 2, "There should be two frames");
+
+  // Select the second request and check that the filter input is cleared
+  EventUtils.sendMouseEvent({ type: "mousedown" }, requests[1]);
+  // Wait till the text filter is applied. There should be two frames rendered
+  await waitUntil(
+    () =>
+      document.querySelectorAll(
+        "#messages-panel .ws-frames-list-table .ws-frame-list-item"
+      ).length == 2
+  );
+  const secondRequestFrames = document.querySelectorAll(
+    "#messages-panel .ws-frames-list-table .ws-frame-list-item"
+  );
+  is(secondRequestFrames.length, 2, "There should be two frames");
+  is(filterInput.value, "", "The filter input is cleared");
+
+  // Close WS connection
+  await ContentTask.spawn(tab.linkedBrowser, {}, async () => {
+    await content.wrappedJSObject.closeConnection();
+  });
+
+  await teardown(monitor);
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/browser_net_ws-limit-frames.js
@@ -0,0 +1,64 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Test that WS connection is established successfully and the truncated message notification displays correctly.
+ */
+
+add_task(async function() {
+  await pushPref("devtools.netmonitor.features.webSockets", true);
+
+  // Set WS frames limit to a lower value for testing
+  await pushPref("devtools.netmonitor.ws.displayed-frames.limit", 30);
+
+  const { tab, monitor } = await initNetMonitor(WS_PAGE_URL);
+  info("Starting test... ");
+
+  const { document, store, windowRequire } = monitor.panelWin;
+  const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
+
+  store.dispatch(Actions.batchEnable(false));
+
+  // Wait for WS connections to be established + send messages
+  await ContentTask.spawn(tab.linkedBrowser, {}, async () => {
+    await content.wrappedJSObject.openConnection(20);
+  });
+
+  const requests = document.querySelectorAll(".request-list-item");
+  is(requests.length, 1, "There should be one request");
+
+  // Wait for truncated message notification to appear
+  wait = waitForDOM(document, "#messages-panel .truncated-message");
+
+  // Select the first request
+  EventUtils.sendMouseEvent({ type: "mousedown" }, requests[0]);
+
+  // Click on the "Messages" panel
+  EventUtils.sendMouseEvent(
+    { type: "click" },
+    document.querySelector("#messages-tab")
+  );
+  await wait;
+
+  // Get all messages present in the "Messages" panel
+  const frames = document.querySelectorAll(
+    "#messages-panel .ws-frames-list-table .ws-frame-list-item"
+  );
+
+  // Check expected results
+  is(frames.length, 30, "There should be thirty frames");
+  is(
+    document.querySelectorAll("#messages-panel .truncated-message").length,
+    1,
+    "Truncated message notification is shown"
+  );
+
+  // Close WS connection
+  await ContentTask.spawn(tab.linkedBrowser, {}, async () => {
+    await content.wrappedJSObject.closeConnection();
+  });
+
+  await teardown(monitor);
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/browser_net_ws-limit-payload.js
@@ -0,0 +1,81 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Test that WS connection is established successfully and the truncated payload is correct.
+ */
+
+add_task(async function() {
+  await pushPref("devtools.netmonitor.features.webSockets", true);
+
+  // Set WS frame payload limit to a lower value for testing
+  await pushPref("devtools.netmonitor.ws.messageDataLimit", 100);
+
+  const { tab, monitor } = await initNetMonitor(WS_PAGE_URL);
+  info("Starting test... ");
+
+  const { document, store, windowRequire } = monitor.panelWin;
+  const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
+
+  store.dispatch(Actions.batchEnable(false));
+
+  // Wait for WS connections to be established + send messages
+  await ContentTask.spawn(tab.linkedBrowser, {}, async () => {
+    await content.wrappedJSObject.openConnection(0);
+    content.wrappedJSObject.sendData(new Array(10 * 11).toString()); // > 100B payload
+  });
+
+  const requests = document.querySelectorAll(".request-list-item");
+  is(requests.length, 1, "There should be one request");
+
+  // Wait for all sent/received messages to be displayed in DevTools
+  wait = waitForDOM(
+    document,
+    "#messages-panel .ws-frames-list-table .ws-frame-list-item",
+    2
+  );
+
+  // Select the first request
+  EventUtils.sendMouseEvent({ type: "mousedown" }, requests[0]);
+
+  // Click on the "Messages" panel
+  EventUtils.sendMouseEvent(
+    { type: "click" },
+    document.querySelector("#messages-tab")
+  );
+  await wait;
+
+  // Get all messages present in the "Messages" panel
+  const frames = document.querySelectorAll(
+    "#messages-panel .ws-frames-list-table .ws-frame-list-item"
+  );
+
+  // Check expected results
+  is(frames.length, 2, "There should be two frames");
+
+  // Wait for next tick to do async stuff (The FramePayload component uses the async function getFramePayload)
+  await waitForTick();
+  EventUtils.sendMouseEvent({ type: "mousedown" }, frames[0]);
+
+  await waitForDOM(document, "#messages-panel .truncated-data-message");
+
+  ok(
+    document.querySelector("#messages-panel .truncated-data-message"),
+    "Truncated data header shown"
+  );
+  is(
+    document.querySelector("#messages-panel .ws-frame-rawData-payload")
+      .textContent.length,
+    100,
+    "Payload size is kept to the limit"
+  );
+
+  // Close WS connection
+  await ContentTask.spawn(tab.linkedBrowser, {}, async () => {
+    await content.wrappedJSObject.closeConnection();
+  });
+
+  await teardown(monitor);
+});
--- a/devtools/client/netmonitor/test/html_ws-test-page.html
+++ b/devtools/client/netmonitor/test/html_ws-test-page.html
@@ -7,17 +7,17 @@
     <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
     <meta http-equiv="Pragma" content="no-cache" />
     <meta http-equiv="Expires" content="0" />
     <title>WebSocket Inspection Test Page</title>
   </head>
   <body>
     <h1>WebSocket Inspection Test Page</h1>
     <script type="text/javascript">
-      /* exported openConnection, closeConnection */
+      /* exported openConnection, closeConnection, sendData */
       "use strict";
 
       let ws;
       function openConnection(numFramesToSend) {
         return new Promise(resolve => {
           ws = new WebSocket(
             "ws://mochi.test:8888/browser/devtools/client/netmonitor/test/file_ws_backend");
 
@@ -33,11 +33,15 @@
       function closeConnection() {
         return new Promise(resolve => {
           ws.onclose = e => {
             resolve();
           }
           ws.close();
         })
       }
+
+      function sendData(payload) {
+        ws.send(payload);
+      }
     </script>
   </body>
 </html>
--- a/devtools/client/themes/inspector.css
+++ b/devtools/client/themes/inspector.css
@@ -186,14 +186,8 @@ iframe {
   flex: 1;
   min-height: 0;
 }
 
 #markup-box > iframe {
   height: 100%;
   width: 100%;
 }
-
-/* Animation inspector */
-#sidebar-panel-animationinspector {
-  height: 100%;
-  width: 100%;
-}
--- a/devtools/client/webconsole/actions/messages.js
+++ b/devtools/client/webconsole/actions/messages.js
@@ -17,17 +17,17 @@ const {
   NETWORK_MESSAGE_UPDATE,
   NETWORK_UPDATE_REQUEST,
   MESSAGES_CLEAR,
   MESSAGES_CLEAR_LOGPOINT,
   MESSAGE_OPEN,
   MESSAGE_CLOSE,
   MESSAGE_TYPE,
   MESSAGE_UPDATE_PAYLOAD,
-  PAUSED_EXCECUTION_POINT,
+  PAUSED_EXECUTION_POINT,
   PRIVATE_MESSAGES_CLEAR,
 } = require("../constants");
 
 const defaultIdGenerator = new IdGenerator();
 
 function messagesAdd(packets, idGenerator = null) {
   if (idGenerator == null) {
     idGenerator = defaultIdGenerator;
@@ -63,17 +63,17 @@ function messagesClearLogpoint(logpointI
   return {
     type: MESSAGES_CLEAR_LOGPOINT,
     logpointId,
   };
 }
 
 function setPauseExecutionPoint(executionPoint) {
   return {
-    type: PAUSED_EXCECUTION_POINT,
+    type: PAUSED_EXECUTION_POINT,
     executionPoint,
   };
 }
 
 function privateMessagesClear() {
   return {
     type: PRIVATE_MESSAGES_CLEAR,
   };
--- a/devtools/client/webconsole/constants.js
+++ b/devtools/client/webconsole/constants.js
@@ -39,17 +39,17 @@ const actionTypes = {
   SHOW_CONTENT_MESSAGES_TOGGLE: "SHOW_CONTENT_MESSAGES_TOGGLE",
   SIDEBAR_CLOSE: "SIDEBAR_CLOSE",
   SPLIT_CONSOLE_CLOSE_BUTTON_TOGGLE: "SPLIT_CONSOLE_CLOSE_BUTTON_TOGGLE",
   TIMESTAMPS_TOGGLE: "TIMESTAMPS_TOGGLE",
   UPDATE_HISTORY_POSITION: "UPDATE_HISTORY_POSITION",
   REVERSE_SEARCH_INPUT_CHANGE: "REVERSE_SEARCH_INPUT_CHANGE",
   REVERSE_SEARCH_NEXT: "REVERSE_SEARCH_NEXT",
   REVERSE_SEARCH_BACK: "REVERSE_SEARCH_BACK",
-  PAUSED_EXCECUTION_POINT: "PAUSED_EXCECUTION_POINT",
+  PAUSED_EXECUTION_POINT: "PAUSED_EXECUTION_POINT",
   WARNING_GROUPS_TOGGLE: "WARNING_GROUPS_TOGGLE",
   WILL_NAVIGATE: "WILL_NAVIGATE",
   EDITOR_SET_WIDTH: "EDITOR_SET_WIDTH",
 };
 
 const prefs = {
   PREFS: {
     // Filter preferences only have the suffix since they can be used either for the
--- a/devtools/client/webconsole/reducers/messages.js
+++ b/devtools/client/webconsole/reducers/messages.js
@@ -370,17 +370,24 @@ function messages(
     groupsById,
     visibleMessages,
   } = state;
 
   const { logLimit } = prefsState;
 
   let newState;
   switch (action.type) {
-    case constants.PAUSED_EXCECUTION_POINT:
+    case constants.PAUSED_EXECUTION_POINT:
+      if (
+        state.pausedExecutionPoint &&
+        action.executionPoint &&
+        pointEquals(state.pausedExecutionPoint, action.executionPoint)
+      ) {
+        return state;
+      }
       return { ...state, pausedExecutionPoint: action.executionPoint };
     case constants.MESSAGES_ADD:
       // Preemptively remove messages that will never be rendered
       const list = [];
       let prunableCount = 0;
       let lastMessageRepeatId = -1;
       for (let i = action.messages.length - 1; i >= 0; i--) {
         const message = action.messages[i];
--- a/devtools/client/webreplay/mochitest/browser_dbg_rr_console_warp-03.js
+++ b/devtools/client/webreplay/mochitest/browser_dbg_rr_console_warp-03.js
@@ -14,36 +14,123 @@ const BrowserTest = {
   BrowserTestUtils,
 };
 
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/webconsole/test/browser/head.js",
   BrowserTest
 );
 
+async function checkMessageObjectContents(msg, expected, expandList = []) {
+  const oi = msg.querySelector(".tree");
+  const node = oi.querySelector(".tree-node");
+  BrowserTest.expandObjectInspectorNode(node);
+
+  for (const label of expandList) {
+    const labelNode = await waitFor(() =>
+      BrowserTest.findObjectInspectorNode(oi, label)
+    );
+    BrowserTest.expandObjectInspectorNode(labelNode);
+  }
+
+  const properties = await waitFor(() => {
+    const nodes = BrowserTest.getObjectInspectorNodes(oi);
+    if (nodes && nodes.length > 1) {
+      return [...nodes].map(n => n.textContent);
+    }
+    return null;
+  });
+
+  expected.forEach(s => {
+    ok(properties.find(v => v.includes(s)), `Object contents include "${s}"`);
+  });
+}
+
 // Test evaluating various expressions in the console after time warping.
 add_task(async function() {
-  const dbg = await attachRecordingDebugger("doc_rr_error.html", {
+  const dbg = await attachRecordingDebugger("doc_rr_objects.html", {
     waitForRecording: true,
   });
 
-  const { toolbox } = dbg;
+  const { threadFront, toolbox } = dbg;
   const console = await toolbox.selectTool("webconsole");
   const hud = console.hud;
 
-  await warpToMessage(hud, dbg, "Number 5");
+  await warpToMessage(hud, dbg, "Done");
+
+  const requests = await threadFront.debuggerRequests();
+
+  requests.forEach(({ request, stack }) => {
+    if (request.type != "pauseData") {
+      dump(`Unexpected debugger request stack:\n${stack}\n`);
+      ok(false, `Unexpected debugger request while paused: ${request.type}`);
+    }
+  });
 
   BrowserTest.execute(hud, "Error('helo')");
-  await waitFor(() => findMessage(hud, "helo"));
+  await waitForMessage(hud, "helo");
 
   BrowserTest.execute(
     hud,
     `
 function f() {
   throw Error("there");
 }
 f();
 `
   );
   await BrowserTest.checkMessageStack(hud, "Error: there", [3, 5]);
 
+  let msg;
+
+  BrowserTest.execute(hud, "Array(1, 2, 3)");
+  msg = await waitForMessage(hud, "Array(3) [ 1, 2, 3 ]");
+  await checkMessageObjectContents(msg, ["0: 1", "1: 2", "2: 3", "length: 3"]);
+
+  BrowserTest.execute(hud, "new Uint8Array([1, 2, 3, 4])");
+  msg = await waitForMessage(hud, "Uint8Array(4) [ 1, 2, 3, 4 ]");
+  await checkMessageObjectContents(msg, [
+    "0: 1",
+    "1: 2",
+    "2: 3",
+    "3: 4",
+    "byteLength: 4",
+    "byteOffset: 0",
+  ]);
+
+  BrowserTest.execute(hud, `RegExp("abc", "g")`);
+  msg = await waitForMessage(hud, "/abc/g");
+  await checkMessageObjectContents(msg, ["global: true", `source: "abc"`]);
+
+  BrowserTest.execute(hud, "new Set([1, 2, 3])");
+  msg = await waitForMessage(hud, "Set(3) [ 1, 2, 3 ]");
+  await checkMessageObjectContents(
+    msg,
+    ["0: 1", "1: 2", "2: 3", "size: 3"],
+    ["<entries>"]
+  );
+
+  BrowserTest.execute(hud, "new Map([[1, {a:1}], [2, {b:2}]])");
+  msg = await waitForMessage(hud, "Map { 1 → {…}, 2 → {…} }");
+  await checkMessageObjectContents(
+    msg,
+    ["0: 1 → Object { … }", "1: 2 → Object { … }", "size: 2"],
+    ["<entries>"]
+  );
+
+  BrowserTest.execute(hud, "new WeakSet([{a:1}, {b:2}])");
+  msg = await waitForMessage(hud, "WeakSet [ {…}, {…} ]");
+  await checkMessageObjectContents(
+    msg,
+    ["0: Object { … }", "1: Object { … }"],
+    ["<entries>"]
+  );
+
+  BrowserTest.execute(hud, "new WeakMap([[{a:1},{b:1}], [{a:2},{b:2}]])");
+  msg = await waitForMessage(hud, "WeakMap { {…} → {…}, {…} → {…} }");
+  await checkMessageObjectContents(
+    msg,
+    ["0: Object { … } → Object { … }", "1: Object { … } → Object { … }"],
+    ["<entries>"]
+  );
+
   await shutdownDebugger(dbg);
 });
new file mode 100644
--- /dev/null
+++ b/devtools/client/webreplay/mochitest/examples/doc_rr_objects.html
@@ -0,0 +1,38 @@
+<div id="foo">BAR</div>
+<script>
+const cpmm = SpecialPowers.Services.cpmm;
+function recordingFinished() {
+  cpmm.sendAsyncMessage("RecordingFinished");
+}
+
+function foo() {
+// Create various objects which the debugger must be able to show in the scopes
+// pane using only the pause data, i.e. without additional debugger requests.
+// Not performing debugger requests allows the debugger to finish updating the
+// UI using cached pause data, and without any replaying process actually being
+// at the point where we are pausing.
+var a = Array();
+var b = new Uint8Array(20);
+var c = new Set([{a:0},{b:1}]);
+var d = new Map([[{a:0},{b:1}]]);
+var e = new WeakSet();
+var f = new WeakMap();
+var g = { a:0 };
+for (let i = 0; i < 20; i++) {
+  a.push(i);
+  b[i] = i;
+  c.add(i);
+  d.set(i, i + 1);
+  e.add({ i });
+  f.set({ i }, { j: i + 1 });
+  g[`a${i}`] = i;
+}
+var h = /abc/gi;
+var i = new Date();
+var j = RangeError();
+var k = document.getElementById("foo");
+console.log("Done");
+window.setTimeout(recordingFinished);
+}
+foo();
+</script>
--- a/devtools/client/webreplay/mochitest/head.js
+++ b/devtools/client/webreplay/mochitest/head.js
@@ -106,32 +106,37 @@ function newRecordingFile() {
   const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
   return OS.Path.join(
     OS.Constants.Path.tmpDir,
     "MochitestRecording" + Math.round(Math.random() * 1000000000)
   );
 }
 
 function findMessage(hud, text, selector = ".message") {
-  return findMessages(hud, text, selector)[0];
+  const messages = findMessages(hud, text, selector);
+  return messages ? messages[0] : null;
 }
 
 function findMessages(hud, text, selector = ".message") {
   const messages = hud.ui.outputNode.querySelectorAll(selector);
   const elements = Array.prototype.filter.call(messages, el =>
     el.textContent.includes(text)
   );
 
   if (elements.length == 0) {
     return null;
   }
 
   return elements;
 }
 
+function waitForMessage(hud, text, selector = ".message") {
+  return waitUntilPredicate(() => findMessage(hud, text, selector));
+}
+
 function waitForMessages(hud, text, selector = ".message") {
   return waitUntilPredicate(() => findMessages(hud, text, selector));
 }
 
 async function waitForMessageCount(hud, text, length, selector = ".message") {
   let messages;
   await waitUntil(() => {
     messages = findMessages(hud, text, selector);
--- a/devtools/server/actors/object.js
+++ b/devtools/server/actors/object.js
@@ -425,23 +425,16 @@ const proto = {
     let level = 0,
       i = 0;
 
     // Do not search safe getters in unsafe objects.
     if (!DevToolsUtils.isSafeDebuggerObject(obj)) {
       return safeGetterValues;
     }
 
-    // Do not search for safe getters while replaying. While this would be nice
-    // to support, it involves a lot of back-and-forth between processes and
-    // would be better to do entirely in the replaying process.
-    if (isReplaying) {
-      return safeGetterValues;
-    }
-
     // Most objects don't have any safe getters but inherit some from their
     // prototype. Avoid calling getOwnPropertyNames on objects that may have
     // many properties like Array, strings or js objects. That to avoid
     // freezing firefox when doing so.
     if (isArray(this.obj) || ["Object", "String"].includes(this.obj.class)) {
       obj = obj.proto;
       level++;
     }
--- a/devtools/server/actors/object/previewers.js
+++ b/devtools/server/actors/object/previewers.js
@@ -132,29 +132,26 @@ const previewers = {
       }
 
       return true;
     },
   ],
 
   RegExp: [
     function({ obj, hooks }, grip) {
-      const str = DevToolsUtils.callPropertyOnObject(obj, "toString");
-      if (typeof str != "string") {
-        return false;
-      }
+      const str = ObjectUtils.getRegExpString(obj);
 
       grip.displayString = hooks.createValueGrip(str);
       return true;
     },
   ],
 
   Date: [
     function({ obj, hooks }, grip) {
-      const time = DevToolsUtils.callPropertyOnObject(obj, "getTime");
+      const time = ObjectUtils.getDateTime(obj);
       if (typeof time != "number") {
         return false;
       }
 
       grip.preview = {
         timestamp: hooks.createValueGrip(time),
       };
       return true;
@@ -207,46 +204,43 @@ const previewers = {
       }
 
       return true;
     },
   ],
 
   Set: [
     function(objectActor, grip) {
-      const size = DevToolsUtils.getProperty(objectActor.obj, "size");
-      if (typeof size != "number") {
-        return false;
-      }
+      const size = ObjectUtils.getContainerSize(objectActor.obj);
 
       grip.preview = {
         kind: "ArrayLike",
         length: size,
       };
 
       // Avoid recursive object grips.
       if (objectActor.hooks.getGripDepth() > 1) {
         return true;
       }
 
       const items = (grip.preview.items = []);
-      for (const item of PropertyIterators.enumSetEntries(objectActor)) {
+      for (const item of PropertyIterators.enumSetEntries(objectActor, /* forPreview */ true)) {
         items.push(item);
         if (items.length == OBJECT_PREVIEW_MAX_ITEMS) {
           break;
         }
       }
 
       return true;
     },
   ],
 
   WeakSet: [
     function(objectActor, grip) {
-      const enumEntries = PropertyIterators.enumWeakSetEntries(objectActor);
+      const enumEntries = PropertyIterators.enumWeakSetEntries(objectActor, /* forPreview */ true);
 
       grip.preview = {
         kind: "ArrayLike",
         length: enumEntries.size,
       };
 
       // Avoid recursive object grips.
       if (objectActor.hooks.getGripDepth() > 1) {
@@ -262,45 +256,42 @@ const previewers = {
       }
 
       return true;
     },
   ],
 
   Map: [
     function(objectActor, grip) {
-      const size = DevToolsUtils.getProperty(objectActor.obj, "size");
-      if (typeof size != "number") {
-        return false;
-      }
+      const size = ObjectUtils.getContainerSize(objectActor.obj);
 
       grip.preview = {
         kind: "MapLike",
         size: size,
       };
 
       if (objectActor.hooks.getGripDepth() > 1) {
         return true;
       }
 
       const entries = (grip.preview.entries = []);
-      for (const entry of PropertyIterators.enumMapEntries(objectActor)) {
+      for (const entry of PropertyIterators.enumMapEntries(objectActor, /* forPreview */ true)) {
         entries.push(entry);
         if (entries.length == OBJECT_PREVIEW_MAX_ITEMS) {
           break;
         }
       }
 
       return true;
     },
   ],
 
   WeakMap: [
     function(objectActor, grip) {
-      const enumEntries = PropertyIterators.enumWeakMapEntries(objectActor);
+      const enumEntries = PropertyIterators.enumWeakMapEntries(objectActor, /* forPreview */ true);
 
       grip.preview = {
         kind: "MapLike",
         size: enumEntries.size,
       };
 
       if (objectActor.hooks.getGripDepth() > 1) {
         return true;
@@ -516,17 +507,20 @@ function GenericObject(
       )
     );
 
     if (++i == OBJECT_PREVIEW_MAX_ITEMS) {
       break;
     }
   }
 
-  if (i < OBJECT_PREVIEW_MAX_ITEMS) {
+  // Do not search for safe getters when generating previews while replaying.
+  // This involves a lot of back-and-forth communication which we don't want to
+  // incur while previewing objects.
+  if (i < OBJECT_PREVIEW_MAX_ITEMS && !isReplaying) {
     preview.safeGetterValues = objectActor._findSafeGetterValues(
       Object.keys(preview.ownProperties),
       OBJECT_PREVIEW_MAX_ITEMS - i
     );
   }
 
   return true;
 }
@@ -543,63 +537,43 @@ previewers.Object = [
       kind: "ArrayLike",
       length: ObjectUtils.getArrayLength(obj),
     };
 
     if (hooks.getGripDepth() > 1) {
       return true;
     }
 
-    const raw = obj.unsafeDereference();
-
-    // The raw object will be null/unavailable when interacting with a
-    // replaying execution, and Cu is unavailable in workers. In either case we
-    // do not need to worry about xrays.
-    if (raw && !isWorker) {
-      const global = Cu.getGlobalForObject(DebuggerServer);
-      const classProto = global[obj.class].prototype;
-      // The Xray machinery for TypedArrays denies indexed access on the grounds
-      // that it's slow, and advises callers to do a structured clone instead.
-      const safeView = Cu.cloneInto(
-        classProto.subarray.call(raw, 0, OBJECT_PREVIEW_MAX_ITEMS),
-        global
-      );
-      const items = (grip.preview.items = []);
-      for (let i = 0; i < safeView.length; i++) {
-        items.push(safeView[i]);
+    const previewLength = Math.min(OBJECT_PREVIEW_MAX_ITEMS, grip.preview.length);
+    grip.preview.items = [];
+    for (let i = 0; i < previewLength; i++) {
+      const desc = obj.getOwnPropertyDescriptor(i);
+      if (!desc) {
+        break;
       }
+      grip.preview.items.push(desc.value);
     }
 
     return true;
   },
 
   function Error({ obj, hooks }, grip) {
     switch (obj.class) {
       case "Error":
       case "EvalError":
       case "RangeError":
       case "ReferenceError":
       case "SyntaxError":
       case "TypeError":
       case "URIError":
-        const name = DevToolsUtils.getProperty(obj, "name");
-        const msg = DevToolsUtils.getProperty(obj, "message");
-        const stack = DevToolsUtils.getProperty(obj, "stack");
-        const fileName = DevToolsUtils.getProperty(obj, "fileName");
-        const lineNumber = DevToolsUtils.getProperty(obj, "lineNumber");
-        const columnNumber = DevToolsUtils.getProperty(obj, "columnNumber");
-        grip.preview = {
-          kind: "Error",
-          name: hooks.createValueGrip(name),
-          message: hooks.createValueGrip(msg),
-          stack: hooks.createValueGrip(stack),
-          fileName: hooks.createValueGrip(fileName),
-          lineNumber: hooks.createValueGrip(lineNumber),
-          columnNumber: hooks.createValueGrip(columnNumber),
-        };
+        grip.preview = { kind: "Error" };
+        const properties = ObjectUtils.getErrorProperties(obj);
+        Object.keys(properties).forEach(p => {
+          grip.preview[p] = hooks.createValueGrip(properties[p]);
+        });
         return true;
       default:
         return false;
     }
   },
 
   function CSSMediaRule({ obj, hooks }, grip, rawObj) {
     if (isWorker || !rawObj || obj.class != "CSSMediaRule") {
--- a/devtools/server/actors/object/property-iterator.js
+++ b/devtools/server/actors/object/property-iterator.js
@@ -251,52 +251,59 @@ function enumObjectProperties(objectActo
         desc.getterValue = getterValue;
         desc.getterPrototypeLevel = getterPrototypeLevel;
       }
       return desc;
     },
   };
 }
 
-function enumMapEntries(objectActor) {
+function getMapEntries(obj, forPreview) {
+  if (isReplaying) {
+    return obj.containerContents(forPreview);
+  }
+
   // Iterating over a Map via .entries goes through various intermediate
   // objects - an Iterator object, then a 2-element Array object, then the
   // actual values we care about. We don't have Xrays to Iterator objects,
   // so we get Opaque wrappers for them. And even though we have Xrays to
   // Arrays, the semantics often deny access to the entires based on the
   // nature of the values. So we need waive Xrays for the iterator object
   // and the tupes, and then re-apply them on the underlying values until
   // we fix bug 1023984.
   //
   // Even then though, we might want to continue waiving Xrays here for the
   // same reason we do so for Arrays above - this filtering behavior is likely
   // to be more confusing than beneficial in the case of Object previews.
-  const raw = objectActor.obj.unsafeDereference();
-  const iterator = objectActor.obj.makeDebuggeeValue(
+  const raw = obj.unsafeDereference();
+  const iterator = obj.makeDebuggeeValue(
     waiveXrays(Map.prototype.keys.call(raw))
   );
-  const keys = [...DevToolsUtils.makeDebuggeeIterator(iterator)].map(k =>
-    waiveXrays(ObjectUtils.unwrapDebuggeeValue(k))
-  );
-  const getValue = key => Map.prototype.get.call(raw, key);
+  return [...DevToolsUtils.makeDebuggeeIterator(iterator)].map(k => {
+    const key = waiveXrays(ObjectUtils.unwrapDebuggeeValue(k))
+    const value = Map.prototype.get.call(raw, key);
+    return [key, value];
+  });
+}
+
+function enumMapEntries(objectActor, forPreview = false) {
+  const entries = getMapEntries(objectActor.obj, forPreview);
 
   return {
     [Symbol.iterator]: function*() {
-      for (const key of keys) {
-        const value = getValue(key);
+      for (const [key, value] of entries) {
         yield [key, value].map(val => gripFromEntry(objectActor, val));
       }
     },
-    size: keys.length,
+    size: entries.length,
     propertyName(index) {
       return index;
     },
     propertyDescription(index) {
-      const key = keys[index];
-      const val = getValue(key);
+      const [key, val] = entries[index];
       return {
         enumerable: true,
         value: {
           type: "mapEntry",
           preview: {
             key: gripFromEntry(objectActor, key),
             value: gripFromEntry(objectActor, val),
           },
@@ -339,78 +346,90 @@ function enumStorageEntries(objectActor)
             value: gripFromEntry(objectActor, val),
           },
         },
       };
     },
   };
 }
 
-function enumWeakMapEntries(objectActor) {
+function getWeakMapEntries(obj, forPreview) {
+  if (isReplaying) {
+    return obj.containerContents(forPreview);
+  }
+
   // We currently lack XrayWrappers for WeakMap, so when we iterate over
   // the values, the temporary iterator objects get created in the target
   // compartment. However, we _do_ have Xrays to Object now, so we end up
   // Xraying those temporary objects, and filtering access to |it.value|
   // based on whether or not it's Xrayable and/or callable, which breaks
   // the for/of iteration.
   //
   // This code is designed to handle untrusted objects, so we can safely
   // waive Xrays on the iterable, and relying on the Debugger machinery to
   // make sure we handle the resulting objects carefully.
-  const raw = objectActor.obj.unsafeDereference();
+  const raw = obj.unsafeDereference();
   const keys = waiveXrays(ChromeUtils.nondeterministicGetWeakMapKeys(raw));
 
-  const values = [];
-  for (const k of keys) {
-    values.push(WeakMap.prototype.get.call(raw, k));
-  }
+  return keys.map(k => [k, WeakMap.prototype.get.call(raw, k)]);
+}
+
+function enumWeakMapEntries(objectActor, forPreview = false) {
+  const entries = getWeakMapEntries(objectActor.obj, forPreview);
 
   return {
     [Symbol.iterator]: function*() {
-      for (let i = 0; i < keys.length; i++) {
-        yield [keys[i], values[i]].map(val => gripFromEntry(objectActor, val));
+      for (let i = 0; i < entries.length; i++) {
+        yield entries[i].map(val => gripFromEntry(objectActor, val));
       }
     },
-    size: keys.length,
+    size: entries.length,
     propertyName(index) {
       return index;
     },
     propertyDescription(index) {
-      const key = keys[index];
-      const val = values[index];
+      const [key, val] = entries[index];
       return {
         enumerable: true,
         value: {
           type: "mapEntry",
           preview: {
             key: gripFromEntry(objectActor, key),
             value: gripFromEntry(objectActor, val),
           },
         },
       };
     },
   };
 }
 
-function enumSetEntries(objectActor) {
+function getSetValues(obj, forPreview) {
+  if (isReplaying) {
+    return obj.containerContents(forPreview);
+  }
+
   // We currently lack XrayWrappers for Set, so when we iterate over
   // the values, the temporary iterator objects get created in the target
   // compartment. However, we _do_ have Xrays to Object now, so we end up
   // Xraying those temporary objects, and filtering access to |it.value|
   // based on whether or not it's Xrayable and/or callable, which breaks
   // the for/of iteration.
   //
   // This code is designed to handle untrusted objects, so we can safely
   // waive Xrays on the iterable, and relying on the Debugger machinery to
   // make sure we handle the resulting objects carefully.
-  const raw = objectActor.obj.unsafeDereference();
-  const iterator = objectActor.obj.makeDebuggeeValue(
+  const raw = obj.unsafeDereference();
+  const iterator = obj.makeDebuggeeValue(
     waiveXrays(Set.prototype.values.call(raw))
   );
-  const values = [...DevToolsUtils.makeDebuggeeIterator(iterator)].map(v =>
+  return [...DevToolsUtils.makeDebuggeeIterator(iterator)];
+}
+
+function enumSetEntries(objectActor, forPreview = false) {
+  const values = getSetValues(objectActor.obj, forPreview).map(v =>
     waiveXrays(ObjectUtils.unwrapDebuggeeValue(v))
   );
 
   return {
     [Symbol.iterator]: function*() {
       for (const item of values) {
         yield gripFromEntry(objectActor, item);
       }
@@ -424,29 +443,37 @@ function enumSetEntries(objectActor) {
       return {
         enumerable: true,
         value: gripFromEntry(objectActor, val),
       };
     },
   };
 }
 
-function enumWeakSetEntries(objectActor) {
+function getWeakSetEntries(obj, forPreview) {
+  if (isReplaying) {
+    return obj.containerContents(forPreview);
+  }
+
   // We currently lack XrayWrappers for WeakSet, so when we iterate over
   // the values, the temporary iterator objects get created in the target
   // compartment. However, we _do_ have Xrays to Object now, so we end up
   // Xraying those temporary objects, and filtering access to |it.value|
   // based on whether or not it's Xrayable and/or callable, which breaks
   // the for/of iteration.
   //
   // This code is designed to handle untrusted objects, so we can safely
   // waive Xrays on the iterable, and relying on the Debugger machinery to
   // make sure we handle the resulting objects carefully.
-  const raw = objectActor.obj.unsafeDereference();
-  const keys = waiveXrays(ChromeUtils.nondeterministicGetWeakSetKeys(raw));
+  const raw = obj.unsafeDereference();
+  return waiveXrays(ChromeUtils.nondeterministicGetWeakSetKeys(raw));
+}
+
+function enumWeakSetEntries(objectActor, forPreview = false) {
+  const keys = getWeakSetEntries(objectActor.obj, forPreview);
 
   return {
     [Symbol.iterator]: function*() {
       for (const item of keys) {
         yield gripFromEntry(objectActor, item);
       }
     },
     size: keys.length,
--- a/devtools/server/actors/object/utils.js
+++ b/devtools/server/actors/object/utils.js
@@ -198,25 +198,50 @@ function getArrayLength(object) {
     throw new Error("Expected an array, got a " + object.class);
   }
 
   // Real arrays have a reliable `length` own property.
   if (object.class === "Array") {
     return DevToolsUtils.getProperty(object, "length");
   }
 
+  // When replaying, we use a special API to get typed array lengths. We can't
+  // invoke getters on the proxy returned by unsafeDereference().
+  if (isReplaying) {
+    return object.getTypedArrayLength();
+  }
+
   // For typed arrays, `DevToolsUtils.getProperty` is not reliable because the `length`
   // getter could be shadowed by an own property, and `getOwnPropertyNames` is
   // unnecessarily slow. Obtain the `length` getter safely and call it manually.
   const typedProto = Object.getPrototypeOf(Uint8Array.prototype);
   const getter = Object.getOwnPropertyDescriptor(typedProto, "length").get;
   return getter.call(object.unsafeDereference());
 }
 
 /**
+ * Returns the number of elements in a Set or Map.
+ *
+ * @param object Debugger.Object
+ *        The debuggee object of the Set or Map.
+ * @return Number
+ */
+function getContainerSize(object) {
+  if (object.class != "Set" && object.class != "Map") {
+    throw new Error(`Expected a set/map, got a ${object.class}`);
+  }
+
+  if (isReplaying) {
+    return object.getContainerSize();
+  }
+
+  return DevToolsUtils.getProperty(object, "size");
+}
+
+/**
  * Returns true if the parameter is suitable to be an array index.
  *
  * @param str String
  * @return Boolean
  */
 function isArrayIndex(str) {
   // Transform the parameter to a 32-bit unsigned integer.
   const num = str >>> 0;
@@ -249,21 +274,60 @@ function isStorage(object) {
  */
 function getStorageLength(object) {
   if (!isStorage(object)) {
     throw new Error("Expected a storage object, got a " + object.class);
   }
   return DevToolsUtils.getProperty(object, "length");
 }
 
+// Get the string representation of a Debugger.Object for a RegExp.
+function getRegExpString(object) {
+  if (isReplaying) {
+    return object.getRegExpString();
+  }
+
+  return DevToolsUtils.callPropertyOnObject(object, "toString");
+}
+
+// Get the time associated with a Debugger.Object for a Date.
+function getDateTime(object) {
+  if (isReplaying) {
+    return object.getDateTime();
+  }
+
+  return DevToolsUtils.callPropertyOnObject(object, "getTime");
+}
+
+// Get the properties of a Debugger.Object for an Error which are needed to
+// preview the object.
+function getErrorProperties(object) {
+  if (isReplaying) {
+    return object.getErrorProperties();
+  }
+
+  return {
+    name: DevToolsUtils.getProperty(object, "name"),
+    message: DevToolsUtils.getProperty(object, "message"),
+    stack: DevToolsUtils.getProperty(object, "stack"),
+    fileName: DevToolsUtils.getProperty(object, "fileName"),
+    lineNumber: DevToolsUtils.getProperty(object, "lineNumber"),
+    columnNumber: DevToolsUtils.getProperty(object, "columnNumber"),
+  };
+}
+
 module.exports = {
   getPromiseState,
   makeDebuggeeValueIfNeeded,
   unwrapDebuggeeValue,
   createValueGrip,
   stringIsLong,
   isTypedArray,
   isArray,
   isStorage,
   getArrayLength,
   getStorageLength,
+  getContainerSize,
   isArrayIndex,
+  getRegExpString,
+  getDateTime,
+  getErrorProperties,
 };
--- a/devtools/server/actors/replay/control.js
+++ b/devtools/server/actors/replay/control.js
@@ -1028,16 +1028,23 @@ let gPauseMode = PauseModes.RUNNING;
 // In PAUSED or ARRIVING modes, the point we are paused at or sending the active
 // child to.
 let gPausePoint = null;
 
 // In PAUSED mode, any debugger requests that have been sent to the child.
 // In ARRIVING mode, the requests must be sent once the child arrives.
 const gDebuggerRequests = [];
 
+function addDebuggerRequest(request) {
+  gDebuggerRequests.push({
+    request,
+    stack: Error().stack,
+  });
+}
+
 function setPauseState(mode, point, child) {
   assert(mode);
   const idString = child ? ` #${child.id}` : "";
   dumpv(`SetPauseState ${mode} ${JSON.stringify(point)}${idString}`);
 
   gPauseMode = mode;
   gPausePoint = point;
   gActiveChild = child;
@@ -1072,17 +1079,17 @@ function sendActiveChildToPausePoint() {
       if (pointEquals(gActiveChild.pausePoint(), gPausePoint)) {
         setPauseState(PauseModes.PAUSED, gPausePoint, gActiveChild);
 
         // Send any debugger requests the child is considered to have received.
         if (gDebuggerRequests.length) {
           gActiveChild.sendManifest({
             contents: {
               kind: "batchDebuggerRequest",
-              requests: gDebuggerRequests,
+              requests: gDebuggerRequests.map(r => r.request),
             },
             onFinished(finishData) {
               assert(!finishData || !finishData.restoredCheckpoint);
             },
           });
         }
       } else {
         maybeReachPoint(gActiveChild, gPausePoint);
@@ -1818,17 +1825,17 @@ const gControl = {
       return { unhandledDivergence: true };
     }
 
     if (data.divergedFromRecording) {
       // Remember whether the child diverged from the recording.
       gActiveChild.divergedFromRecording = true;
     }
 
-    gDebuggerRequests.push(request);
+    addDebuggerRequest(request);
     return data.response;
   },
 
   // Synchronously send a debugger request to the main child, which will always
   // be at the end of the recording and can receive requests even when the
   // active child is not currently paused.
   sendRequestMainChild(request) {
     gMainChild.waitUntilPaused(true);
@@ -1855,25 +1862,29 @@ const gControl = {
       gLastFlushCheckpoint,
       checkpoint => findLogpointHits(checkpoint, logpoint)
     );
   },
 
   unscannedRegions,
   cachedPoints,
 
+  debuggerRequests() {
+    return gDebuggerRequests;
+  },
+
   getPauseData() {
     // If the child has not arrived at the pause point yet, see if there is
     // cached pause data for this point already which we can immediately return.
     if (gPauseMode == PauseModes.ARRIVING && !gDebuggerRequests.length) {
       const data = maybeGetPauseData(gPausePoint);
       if (data) {
         // After the child pauses, it will need to generate the pause data so
         // that any referenced objects will be instantiated.
-        gDebuggerRequests.push({ type: "pauseData" });
+        addDebuggerRequest({ type: "pauseData" });
         return data;
       }
     }
     gControl.maybeSwitchToReplayingChild();
     return gControl.sendRequest({ type: "pauseData" });
   },
 
   repaint() {
--- a/devtools/server/actors/replay/debugger.js
+++ b/devtools/server/actors/replay/debugger.js
@@ -115,16 +115,20 @@ ReplayDebugger.prototype = {
   replayUnscannedRegions() {
     return this._control.unscannedRegions();
   },
 
   replayCachedPoints() {
     return this._control.cachedPoints();
   },
 
+  replayDebuggerRequests() {
+    return this._control.debuggerRequests();
+  },
+
   addDebuggee() {},
   removeAllDebuggees() {},
 
   replayingContent(url) {
     return this._sendRequestMainChild({ type: "getContent", url });
   },
 
   _processResponse(request, response, divergeResponse) {
@@ -1031,23 +1035,25 @@ ReplayDebuggerFrame.prototype = {
 // ReplayDebuggerObject
 ///////////////////////////////////////////////////////////////////////////////
 
 function ReplayDebuggerObject(dbg, data) {
   this._dbg = dbg;
   this._data = data;
   this._preview = null;
   this._properties = null;
+  this._containerContents = null;
 }
 
 ReplayDebuggerObject.prototype = {
   _invalidate() {
     this._data = null;
     this._preview = null;
     this._properties = null;
+    this._containerContents = null;
   },
 
   toString() {
     const id = this._data ? this._data.id : "INVALID";
     return `ReplayDebugger.Object #${id}`;
   },
 
   get callable() {
@@ -1125,16 +1131,17 @@ ReplayDebuggerObject.prototype = {
   },
 
   getOwnPropertySymbols() {
     // Symbol properties are not handled yet.
     return [];
   },
 
   getOwnPropertyDescriptor(name) {
+    name = name.toString();
     if (this._preview) {
       if (this._preview.enumerableOwnProperties) {
         const desc = this._preview.enumerableOwnProperties.get(name);
         if (desc) {
           return this._convertPropertyDescriptor(desc);
         }
       }
       if (name == "length") {
@@ -1173,16 +1180,39 @@ ReplayDebuggerObject.prototype = {
       rv.get = this._dbg._getObject(desc.get);
     }
     if ("set" in desc) {
       rv.set = this._dbg._getObject(desc.set);
     }
     return rv;
   },
 
+  containerContents(forPreview = false) {
+    let contents;
+    if (forPreview && this._preview && this._preview.containerContents) {
+      contents = this._preview.containerContents;
+    } else {
+      if (!this._containerContents) {
+        const id = this._data.id;
+        this._containerContents = this._dbg._sendRequestAllowDiverge(
+          { type: "getObjectContainerContents", id },
+          []
+        );
+      }
+      contents = this._containerContents;
+    }
+    return contents.map(value => {
+      // Watch for [key, value] pairs in maps.
+      if (value.length == 2) {
+        return value.map(v => this._dbg._convertValue(v));
+      }
+      return this._dbg._convertValue(value);
+    });
+  },
+
   unwrap() {
     if (!this.isProxy) {
       return this;
     }
     return this._dbg._convertValue(this._data.proxyUnwrapped);
   },
 
   get proxyTarget() {
@@ -1251,17 +1281,41 @@ ReplayDebuggerObject.prototype = {
   },
   get isPromise() {
     NYI();
   },
   asEnvironment: NYI,
   executeInGlobal: NYI,
   executeInGlobalWithBindings: NYI,
 
-  makeDebuggeeValue: NotAllowed,
+  getTypedArrayLength() {
+    return this._data.typedArrayLength;
+  },
+
+  getContainerSize() {
+    return this._data.containerSize;
+  },
+
+  getRegExpString() {
+    return this._data.regExpString;
+  },
+
+  getDateTime() {
+    return this._data.dateTime;
+  },
+
+  getErrorProperties() {
+    return this._data.errorProperties;
+  },
+
+  makeDebuggeeValue(obj) {
+    assert(obj instanceof ReplayDebuggerObject);
+    return obj;
+  },
+
   preventExtensions: NotAllowed,
   seal: NotAllowed,
   freeze: NotAllowed,
   defineProperty: NotAllowed,
   defineProperties: NotAllowed,
   deleteProperty: NotAllowed,
   forceLexicalInitializationByName: NotAllowed,
 };
--- a/devtools/server/actors/replay/replay.js
+++ b/devtools/server/actors/replay/replay.js
@@ -1288,16 +1288,17 @@ function unknownObjectProperties(why) {
       desc: {
         value: why,
         enumerable: true,
       },
     },
   ];
 }
 
+// eslint-disable-next-line complexity
 function getObjectData(id) {
   const object = gPausedObjects.getObject(id);
   if (object instanceof Debugger.Object) {
     const rv = {
       id,
       kind: "Object",
       callable: object.callable,
       isBoundFunction: object.isBoundFunction,
@@ -1333,16 +1334,66 @@ function getObjectData(id) {
       rv.errorNotes = object.errorNotes;
     }
     if (object.errorLineNumber) {
       rv.errorLineNumber = object.errorLineNumber;
     }
     if (object.errorColumnNumber) {
       rv.errorColumnNumber = object.errorColumnNumber;
     }
+
+    const raw = object.unsafeDereference();
+    switch (object.class) {
+      case "Uint8Array":
+      case "Uint8ClampedArray":
+      case "Uint16Array":
+      case "Uint32Array":
+      case "Int8Array":
+      case "Int16Array":
+      case "Int32Array":
+      case "Float32Array":
+      case "Float64Array": {
+        const typedProto = Object.getPrototypeOf(Uint8Array.prototype);
+        const { get } = Object.getOwnPropertyDescriptor(typedProto, "length");
+        rv.typedArrayLength = get.call(raw);
+        break;
+      }
+      case "Set": {
+        const { get } = Object.getOwnPropertyDescriptor(Set.prototype, "size");
+        rv.containerSize = get.call(raw);
+        break;
+      }
+      case "Map": {
+        const { get } = Object.getOwnPropertyDescriptor(Map.prototype, "size");
+        rv.containerSize = get.call(raw);
+        break;
+      }
+      case "RegExp":
+        rv.regExpString = RegExp.prototype.toString.call(raw);
+        break;
+      case "Date":
+        rv.dateTime = Date.prototype.getTime.call(raw);
+        break;
+      case "Error":
+      case "EvalError":
+      case "RangeError":
+      case "ReferenceError":
+      case "SyntaxError":
+      case "TypeError":
+      case "URIError":
+        rv.errorProperties = {
+          name: raw.name,
+          message: raw.message,
+          stack: raw.stack,
+          fileName: raw.fileName,
+          lineNumber: raw.lineNumber,
+          columnNumber: raw.columnNumber,
+        };
+        break;
+    }
     return rv;
   }
   if (object instanceof Debugger.Environment) {
     return {
       id,
       kind: "Environment",
       type: object.type,
       parent: getObjectId(object.parent),
@@ -1379,16 +1430,46 @@ function getObjectProperties(object) {
     if ("set" in desc) {
       desc.set = getObjectId(desc.set);
     }
     rv[name] = desc;
   });
   return rv;
 }
 
+function getObjectContainerContents(object) {
+  const raw = object.unsafeDereference();
+  switch (object.class) {
+    case "Set": {
+      const iter = Cu.waiveXrays(Set.prototype.values.call(raw));
+      return [...iter].map(v => convertValue(makeDebuggeeValue(v)));
+    }
+    case "Map": {
+      const iter = Cu.waiveXrays(Map.prototype.entries.call(raw));
+      return [...iter].map(([k, v]) => [
+        convertValue(makeDebuggeeValue(k)),
+        convertValue(makeDebuggeeValue(v)),
+      ]);
+    }
+    case "WeakSet": {
+      const keys = ChromeUtils.nondeterministicGetWeakSetKeys(raw);
+      return keys.map(k => convertValue(makeDebuggeeValue(Cu.waiveXrays(k))));
+    }
+    case "WeakMap": {
+      const keys = ChromeUtils.nondeterministicGetWeakMapKeys(raw);
+      return keys.map(k => [
+        convertValue(makeDebuggeeValue(k)),
+        convertValue(makeDebuggeeValue(WeakMap.prototype.get.call(raw, k))),
+      ]);
+    }
+    default:
+      return null;
+  }
+}
+
 function getEnvironmentNames(env) {
   try {
     const names = env.names();
 
     return names.map(name => {
       return { name, value: convertValue(env.getVariable(name)) };
     });
   } catch (e) {
@@ -1502,31 +1583,51 @@ function getPauseData() {
           enumerableOwnProperties[name] = desc;
           addPropertyDescriptor(desc, false);
           if (++enumerablePropertyCount == OBJECT_PREVIEW_MAX_ITEMS) {
             break;
           }
         }
       }
       preview.enumerableOwnProperties = enumerableOwnProperties;
+
+      // The server is interested in at most OBJECT_PREVIEW_MAX_ITEMS items in
+      // set and map containers.
+      const containerContents = getObjectContainerContents(object);
+      if (containerContents) {
+        preview.containerContents = containerContents.slice(
+          0,
+          OBJECT_PREVIEW_MAX_ITEMS
+        );
+        preview.containerContents.forEach(v => addContainerValue(v));
+      }
     }
   }
 
   function addPropertyDescriptor(desc, includeProperties) {
     if (desc.value) {
       addValue(desc.value, includeProperties);
     }
     if (desc.get) {
       addObject(desc.get, includeProperties);
     }
     if (desc.set) {
       addObject(desc.set, includeProperties);
     }
   }
 
+  function addContainerValue(value) {
+    // Watch for [key, value] pairs in maps.
+    if (value.length == 2) {
+      value.forEach(v => addValue(v));
+    } else {
+      addValue(value);
+    }
+  }
+
   function addEnvironment(id) {
     if (!id || rv.environments[id]) {
       return;
     }
 
     const env = gPausedObjects.getObject(id);
     assert(env instanceof Debugger.Environment);
 
@@ -1643,16 +1744,21 @@ const gRequestHandlers = {
   },
 
   getObjectProperties(request) {
     divergeFromRecording();
     const object = gPausedObjects.getObject(request.id);
     return getObjectProperties(object);
   },
 
+  getObjectContainerContents(request) {
+    const object = gPausedObjects.getObject(request.id);
+    return getObjectContainerContents(object);
+  },
+
   objectApply(request) {
     divergeFromRecording();
     const obj = gPausedObjects.getObject(request.id);
     const thisv = convertValueFromParent(request.thisv);
     const args = request.args.map(v => convertValueFromParent(v));
     const rv = obj.apply(thisv, args);
     return convertCompletionValue(rv);
   },
--- a/devtools/server/actors/thread.js
+++ b/devtools/server/actors/thread.js
@@ -2122,16 +2122,20 @@ const ThreadActor = ActorClassWithSpec(t
       breakpoints: this.breakpointActorMap.listKeys(),
     };
   },
 
   logLocation: function(prefix, frame) {
     const loc = this.sources.getFrameLocation(frame);
     dump(`${prefix} (${loc.line}, ${loc.column})\n`);
   },
+
+  debuggerRequests() {
+    return this.dbg.replayDebuggerRequests();
+  },
 });
 
 Object.assign(ThreadActor.prototype.requestTypes, {
   attach: ThreadActor.prototype.onAttach,
   detach: ThreadActor.prototype.onDetach,
   reconfigure: ThreadActor.prototype.onReconfigure,
   resume: ThreadActor.prototype.onResume,
   frames: ThreadActor.prototype.onFrames,
--- a/devtools/shared/specs/thread.js
+++ b/devtools/shared/specs/thread.js
@@ -149,12 +149,19 @@ const threadSpec = generateActorSpec({
       },
     },
     pauseOnExceptions: {
       request: {
         pauseOnExceptions: Arg(0, "string"),
         ignoreCaughtExceptions: Arg(1, "string"),
       },
     },
+
+    // For testing.
+    debuggerRequests: {
+      response: {
+        value: RetVal("array:json"),
+      },
+    },
   },
 });
 
 exports.threadSpec = threadSpec;
new file mode 100644
--- /dev/null
+++ b/dom/base/crashtests/1577191.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<script>
+  function start () {
+    const frame = document.createElement('frame')
+    document.documentElement.appendChild(frame)
+    const o1 = document.createElement('c')
+    o1.insertBefore(frame, o1.childNodes[0])
+    SpecialPowers.gc();
+    const xhr = new XMLHttpRequest()
+    xhr.open('P', '', false)
+    xhr.send()
+  }
+
+  document.addEventListener('DOMContentLoaded', start)
+</script>
--- a/dom/base/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -247,8 +247,9 @@ load 1516289.html
 load 1516560.html
 load 1528675.html
 load 1566310.html
 load structured_clone_container_throws.html
 load xhr_empty_datauri.html
 load xhr_html_nullresponse.html
 load xhr-with-pagehide-1.html
 pref(layout.css.resizeobserver.enabled,true) load 1555786.html
+load 1577191.html
--- a/dom/cache/CacheStorage.cpp
+++ b/dom/cache/CacheStorage.cpp
@@ -26,16 +26,17 @@
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
 #include "mozilla/StaticPrefs_dom.h"
 #include "nsContentUtils.h"
 #include "mozilla/dom/Document.h"
 #include "nsIGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
+#include "nsMixedContentBlocker.h"
 #include "nsURLParsers.h"
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
 using mozilla::ErrorResult;
 using mozilla::Unused;
@@ -127,18 +128,17 @@ bool IsTrusted(const PrincipalInfo& aPri
                                  &hostPos, &hostLen,
                                  nullptr);  // ignore port
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
 
   nsDependentCSubstring hostname(url + authPos + hostPos, hostLen);
 
-  return hostname.EqualsLiteral("localhost") ||
-         hostname.EqualsLiteral("127.0.0.1") || hostname.EqualsLiteral("::1");
+  return nsMixedContentBlocker::IsPotentiallyTrustworthyLoopbackHost(hostname);
 }
 
 }  // namespace
 
 // static
 already_AddRefed<CacheStorage> CacheStorage::CreateOnMainThread(
     Namespace aNamespace, nsIGlobalObject* aGlobal, nsIPrincipal* aPrincipal,
     bool aForceTrustedOrigin, ErrorResult& aRv) {
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -354,16 +354,24 @@ class AdjustedTargetForFilter {
 
     if (mSourceGraphicRect.IsEmpty()) {
       // The filter might not make any use of the source graphic. We need to
       // create a DrawTarget that we can return from DT() anyway, so we'll
       // just use a 1x1-sized one.
       mSourceGraphicRect.SizeTo(1, 1);
     }
 
+    if (!mFinalTarget->CanCreateSimilarDrawTarget(mSourceGraphicRect.Size(),
+                                                  SurfaceFormat::B8G8R8A8)) {
+      mTarget = mFinalTarget;
+      mCtx = nullptr;
+      mFinalTarget = nullptr;
+      return;
+    }
+
     mTarget = mFinalTarget->CreateSimilarDrawTarget(mSourceGraphicRect.Size(),
                                                     SurfaceFormat::B8G8R8A8);
 
     if (mTarget) {
       // See bug 1524554.
       mTarget->ClearRect(gfx::Rect());
     }
 
@@ -476,16 +484,24 @@ class AdjustedTargetForShadow {
     // easier to execute the actual blur on hardware, and shouldn't affect
     // the amount of pixels that need to be touched.
     gfx::Rect bounds = aBounds;
     int32_t blurRadius = state.ShadowBlurRadius();
     bounds.Inflate(blurRadius);
     bounds.RoundOut();
     bounds.ToIntRect(&mTempRect);
 
+    if (!mFinalTarget->CanCreateSimilarDrawTarget(mTempRect.Size(),
+                                                  SurfaceFormat::B8G8R8A8)) {
+      mTarget = mFinalTarget;
+      mCtx = nullptr;
+      mFinalTarget = nullptr;
+      return;
+    }
+
     mTarget = mFinalTarget->CreateShadowDrawTarget(
         mTempRect.Size(), SurfaceFormat::B8G8R8A8, mSigma);
 
     if (mTarget) {
       // See bug 1524554.
       mTarget->ClearRect(gfx::Rect());
     }
 
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -479,17 +479,16 @@ class HTMLMediaElement::MediaStreamRende
     mRendering = false;
 
     if (!mGraphTimeDummy) {
       return;
     }
 
     mWatchManager.Unwatch(mGraphTimeDummy->mStream->Graph()->CurrentTime(),
                           &MediaStreamRenderer::UpdateGraphTime);
-    mGraphTimeOffset = Nothing();
 
     for (const auto& t : mAudioTracks) {
       if (t) {
         t->AsAudioStreamTrack()->RemoveAudioOutput(mAudioOutputKey);
       }
     }
 
     if (mVideoTrack) {
@@ -631,19 +630,18 @@ class HTMLMediaElement::MediaStreamRende
   // when the first track is added, never unset.
   RefPtr<SharedDummyStream> mGraphTimeDummy;
 
   // Watchable that relays the graph's currentTime updates to the media element
   // only while we're rendering. This is the current time of the rendering in
   // GraphTime units.
   Watchable<GraphTime> mGraphTime = {0, "MediaStreamRenderer::mGraphTime"};
 
-  // Nothing while we're not rendering. While rendering, the current GraphTime
-  // at the time when rendering was Start()ed, possibly delayed until the first
-  // track appeared.
+  // Nothing until a track has been added. Then, the current GraphTime at the
+  // time when we were last Start()ed.
   Maybe<GraphTime> mGraphTimeOffset;
 
   // Currently enabled (and rendered) audio tracks.
   nsTArray<WeakPtr<MediaStreamTrack>> mAudioTracks;
 
   // Currently selected (and rendered) video track.
   WeakPtr<MediaStreamTrack> mVideoTrack;
 };
@@ -3334,18 +3332,17 @@ already_AddRefed<DOMMediaStream> HTMLMed
     // mAudioCaptured tells the user that the audio played by this media element
     // is being routed to the captureStreams *instead* of being played to
     // speakers.
     mAudioCaptured = true;
   }
 
   if (mDecoder) {
     out->mCapturingDecoder = true;
-    mDecoder->AddOutputStream(
-        out->mStream, out->mGraphKeepAliveDummyStream->mStream->Graph());
+    mDecoder->AddOutputStream(out->mStream, out->mGraphKeepAliveDummyStream);
   } else if (mSrcStream) {
     out->mCapturingMediaStream = true;
   }
 
   if (mReadyState == HAVE_NOTHING) {
     // Do not expose the tracks until we have metadata.
     RefPtr<DOMMediaStream> result = out->mStream;
     return result.forget();
@@ -4047,24 +4044,16 @@ void HTMLMediaElement::ReleaseAudioWakeL
     mWakeLock->Unlock(rv);
     rv.SuppressException();
     mWakeLock = nullptr;
   }
 }
 
 void HTMLMediaElement::WakeLockRelease() { ReleaseAudioWakeLockIfExists(); }
 
-HTMLMediaElement::SharedDummyStream::SharedDummyStream(MediaStream* aStream)
-    : mStream(aStream) {
-  mStream->Suspend();
-}
-HTMLMediaElement::SharedDummyStream::~SharedDummyStream() {
-  mStream->Destroy();
-}
-
 HTMLMediaElement::OutputMediaStream::OutputMediaStream()
     : mFinishWhenEnded(false),
       mCapturingAudioOnly(false),
       mCapturingDecoder(false),
       mCapturingMediaStream(false) {}
 
 HTMLMediaElement::OutputMediaStream::~OutputMediaStream() = default;
 
@@ -4660,18 +4649,17 @@ nsresult HTMLMediaElement::FinishDecoder
 
   for (OutputMediaStream& ms : mOutputStreams) {
     if (ms.mCapturingMediaStream) {
       MOZ_ASSERT(!ms.mCapturingDecoder);
       continue;
     }
 
     ms.mCapturingDecoder = true;
-    aDecoder->AddOutputStream(ms.mStream,
-                              ms.mGraphKeepAliveDummyStream->mStream->Graph());
+    aDecoder->AddOutputStream(ms.mStream, ms.mGraphKeepAliveDummyStream);
   }
 
   if (mMediaKeys) {
     if (mMediaKeys->GetCDMProxy()) {
       mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
     } else {
       // CDM must have crashed.
       ShutdownDecoder();
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -49,18 +49,18 @@ class ChannelMediaDecoder;
 class DecoderDoctorDiagnostics;
 class DOMMediaStream;
 class ErrorResult;
 class MediaResource;
 class MediaDecoder;
 class MediaInputPort;
 class MediaStream;
 class MediaStreamGraph;
-class MediaStreamGraphImpl;
 class MediaStreamWindowCapturer;
+struct SharedDummyStream;
 class VideoFrameContainer;
 namespace dom {
 class MediaKeys;
 class TextTrack;
 class TimeRanges;
 class WakeLock;
 class MediaStreamTrack;
 class MediaStreamTrackSource;
@@ -737,25 +737,16 @@ class HTMLMediaElement : public nsGeneri
   class FirstFrameListener;
   class ShutdownObserver;
   class StreamCaptureTrackSource;
 
   MediaDecoderOwner::NextFrameStatus NextFrameStatus();
 
   void SetDecoder(MediaDecoder* aDecoder);
 
-  struct SharedDummyStream {
-    NS_INLINE_DECL_REFCOUNTING(SharedDummyStream)
-    explicit SharedDummyStream(MediaStream* aStream);
-    const RefPtr<MediaStream> mStream;
-
-   private:
-    ~SharedDummyStream();
-  };
-
   // Holds references to the DOM wrappers for the MediaStreams that we're
   // writing to.
   struct OutputMediaStream {
     OutputMediaStream();
     ~OutputMediaStream();
 
     RefPtr<DOMMediaStream> mStream;
     // Dummy stream to keep mGraph from shutting down when MediaDecoder shuts
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -234,21 +234,21 @@ void MediaDecoder::SetVolume(double aVol
 
 RefPtr<GenericPromise> MediaDecoder::SetSink(AudioDeviceInfo* aSink) {
   MOZ_ASSERT(NS_IsMainThread());
   AbstractThread::AutoEnter context(AbstractMainThread());
   return GetStateMachine()->InvokeSetSink(aSink);
 }
 
 void MediaDecoder::AddOutputStream(DOMMediaStream* aStream,
-                                   MediaStreamGraph* aGraph) {
+                                   SharedDummyStream* aDummyStream) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load().");
   AbstractThread::AutoEnter context(AbstractMainThread());
-  mDecoderStateMachine->EnsureOutputStreamManager(aGraph);
+  mDecoderStateMachine->EnsureOutputStreamManager(aDummyStream);
   if (mInfo) {
     mDecoderStateMachine->EnsureOutputStreamManagerHasTracks(*mInfo);
   }
   mDecoderStateMachine->AddOutputStream(aStream);
 }
 
 void MediaDecoder::RemoveOutputStream(DOMMediaStream* aStream) {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -43,17 +43,17 @@ class MediaMemoryInfo;
 class AbstractThread;
 class DOMMediaStream;
 class DecoderBenchmark;
 class FrameStatistics;
 class VideoFrameContainer;
 class MediaFormatReader;
 class MediaDecoderStateMachine;
 struct MediaPlaybackEvent;
-class MediaStreamGraph;
+struct SharedDummyStream;
 
 enum class Visibility : uint8_t;
 
 // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
 // GetTickCount() and conflicts with MediaDecoder::GetCurrentTime
 // implementation.
 #  ifdef GetCurrentTime
 #    undef GetCurrentTime
@@ -171,17 +171,18 @@ class MediaDecoder : public DecoderDocto
   // is used as the input for each ProcessedMediaStream created by calls to
   // captureStream(UntilEnded). Seeking creates a new source stream, as does
   // replaying after the input as ended. In the latter case, the new source is
   // not connected to streams created by captureStreamUntilEnded.
 
   // Add an output stream. All decoder output will be sent to the stream.
   // The stream is initially blocked. The decoder is responsible for unblocking
   // it while it is playing back.
-  void AddOutputStream(DOMMediaStream* aStream, MediaStreamGraph* aGraph);
+  void AddOutputStream(DOMMediaStream* aStream,
+                       SharedDummyStream* aDummyStream);
   // Remove an output stream added with AddOutputStream.
   void RemoveOutputStream(DOMMediaStream* aStream);
 
   // Update the principal for any output streams and their tracks.
   void SetOutputStreamPrincipal(nsIPrincipal* aPrincipal);
 
   // Return the duration of the video in seconds.
   virtual double GetDuration();
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -3771,23 +3771,23 @@ void MediaDecoderStateMachine::RemoveOut
         });
     nsresult rv = OwnerThread()->Dispatch(r.forget());
     MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
     Unused << rv;
   }
 }
 
 void MediaDecoderStateMachine::EnsureOutputStreamManager(
-    MediaStreamGraph* aGraph) {
+    SharedDummyStream* aDummyStream) {
   MOZ_ASSERT(NS_IsMainThread());
   if (mOutputStreamManager) {
     return;
   }
-  mOutputStreamManager = new OutputStreamManager(aGraph, mOutputStreamPrincipal,
-                                                 mAbstractMainThread);
+  mOutputStreamManager = new OutputStreamManager(
+      aDummyStream, mOutputStreamPrincipal, mAbstractMainThread);
 }
 
 void MediaDecoderStateMachine::EnsureOutputStreamManagerHasTracks(
     const MediaInfo& aLoadedInfo) {
   MOZ_ASSERT(NS_IsMainThread());
   if (!mOutputStreamManager) {
     return;
   }
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -183,17 +183,17 @@ class MediaDecoderStateMachine
   // Returns the state machine task queue.
   TaskQueue* OwnerThread() const { return mTaskQueue; }
 
   RefPtr<GenericPromise> RequestDebugInfo(
       dom::MediaDecoderStateMachineDebugInfo& aInfo);
 
   void SetOutputStreamPrincipal(nsIPrincipal* aPrincipal);
   // If an OutputStreamManager does not exist, one will be created.
-  void EnsureOutputStreamManager(MediaStreamGraph* aGraph);
+  void EnsureOutputStreamManager(SharedDummyStream* aDummyStream);
   // If an OutputStreamManager exists, tracks matching aLoadedInfo will be
   // created unless they already exist in the manager.
   void EnsureOutputStreamManagerHasTracks(const MediaInfo& aLoadedInfo);
   // Add an output stream to the output stream manager. The manager must have
   // been created through EnsureOutputStreamManager() before this.
   void AddOutputStream(DOMMediaStream* aStream);
   // Remove an output stream added with AddOutputStream. If the last output
   // stream was removed, we will also tear down the OutputStreamManager.
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -2929,17 +2929,17 @@ void MediaInputPort::Init() {
   LOG(LogLevel::Debug, ("%p: Adding MediaInputPort %p (from %p to %p)",
                         mSource->GraphImpl(), this, mSource, mDest));
   // Only connect the port if it wasn't disconnected on allocation.
   if (mSource) {
     mSource->AddConsumer(this);
     mDest->AddInput(this);
   }
   // mPortCount decremented via MediaInputPort::Destroy's message
-  ++mDest->GraphImpl()->mPortCount;
+  ++mGraph->mPortCount;
 }
 
 void MediaInputPort::Disconnect() {
   GraphImpl()->AssertOnGraphThreadOrNotRunning();
   NS_ASSERTION(!mSource == !mDest,
                "mSource must either both be null or both non-null");
   if (!mSource) return;
 
--- a/dom/media/MediaStreamGraph.h
+++ b/dom/media/MediaStreamGraph.h
@@ -821,16 +821,35 @@ class SourceMediaStream : public MediaSt
   // protected by mMutex
   nsTArray<TrackData> mUpdateTracks;
   nsTArray<TrackData> mPendingTracks;
   nsTArray<TrackBound<DirectMediaStreamTrackListener>> mDirectTrackListeners;
   bool mFinishPending;
 };
 
 /**
+ * A ref-counted wrapper of a MediaStream that allows multiple users to share a
+ * reference to the same MediaStream with the purpose of being guaranteed that
+ * the graph it is in is kept alive.
+ *
+ * Automatically suspended on creation and destroyed on destruction. Main thread
+ * only.
+ */
+struct SharedDummyStream {
+  NS_INLINE_DECL_REFCOUNTING(SharedDummyStream)
+  explicit SharedDummyStream(MediaStream* aStream) : mStream(aStream) {
+    mStream->Suspend();
+  }
+  const RefPtr<MediaStream> mStream;
+
+ private:
+  ~SharedDummyStream() { mStream->Destroy(); }
+};
+
+/**
  * The blocking mode decides how a track should be blocked in a MediaInputPort.
  */
 enum class BlockingMode {
   /**
    * BlockingMode CREATION blocks the source track from being created
    * in the destination. It'll end if it already exists.
    */
   CREATION,
--- a/dom/media/MediaStreamTrack.cpp
+++ b/dom/media/MediaStreamTrack.cpp
@@ -183,32 +183,42 @@ class MediaStreamTrack::TrackSink : publ
 
 MediaStreamTrack::MediaStreamTrack(nsPIDOMWindowInner* aWindow,
                                    MediaStream* aInputStream, TrackID aTrackID,
                                    MediaStreamTrackSource* aSource,
                                    MediaStreamTrackState aReadyState,
                                    const MediaTrackConstraints& aConstraints)
     : mWindow(aWindow),
       mInputStream(aInputStream),
-      mStream(aReadyState == MediaStreamTrackState::Live
-                  ? mInputStream->Graph()->CreateTrackUnionStream()
-                  : nullptr),
-      mPort(mStream ? mStream->AllocateInputPort(mInputStream) : nullptr),
       mTrackID(aTrackID),
       mSource(aSource),
       mSink(MakeUnique<TrackSink>(this)),
       mPrincipal(aSource->GetPrincipal()),
       mReadyState(aReadyState),
       mEnabled(true),
       mMuted(false),
       mConstraints(aConstraints) {
   if (!Ended()) {
-    MOZ_DIAGNOSTIC_ASSERT(!mInputStream->IsDestroyed());
     GetSource().RegisterSink(mSink.get());
 
+    // Even if the input stream is destroyed we need mStream so that methods
+    // like AddListener still work. Keeping the number of paths to a minimum
+    // also helps prevent bugs elsewhere. We'll be ended through the
+    // MediaStreamTrackSource soon enough.
+    auto graph = mInputStream->IsDestroyed()
+                     ? MediaStreamGraph::GetInstanceIfExists(
+                           mWindow, mInputStream->GraphRate())
+                     : mInputStream->Graph();
+    MOZ_DIAGNOSTIC_ASSERT(graph,
+                          "A destroyed input stream is only expected when "
+                          "cloning, but since we're live there must be another "
+                          "live track that is keeping the graph alive");
+
+    mStream = graph->CreateTrackUnionStream();
+    mPort = mStream->AllocateInputPort(mInputStream);
     mMSGListener = new MSGListener(this);
     AddListener(mMSGListener);
   }
 
   nsresult rv;
   nsCOMPtr<nsIUUIDGenerator> uuidgen =
       do_GetService("@mozilla.org/uuid-generator;1", &rv);
 
--- a/dom/media/MediaStreamTrack.h
+++ b/dom/media/MediaStreamTrack.h
@@ -616,20 +616,21 @@ class MediaStreamTrack : public DOMEvent
 
   // We need this to track our parent object.
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
 
   // The input MediaStream assigned us by the data producer.
   // Owned by the producer.
   const RefPtr<MediaStream> mInputStream;
   // The MediaStream representing this MediaStreamTrack in the MediaStreamGraph.
-  // Valid until we end. Owned by us.
+  // Set on construction if we're live. Valid until we end. Owned by us.
   RefPtr<ProcessedMediaStream> mStream;
-  // The MediaInputPort connecting mInputStream to mStream. Valid until we end.
-  // Owned by us.
+  // The MediaInputPort connecting mInputStream to mStream. Set on construction
+  // if mInputStream is non-destroyed and we're live. Valid until we end. Owned
+  // by us.
   RefPtr<MediaInputPort> mPort;
   // The TrackID of this track in mInputStream and mStream.
   const TrackID mTrackID;
   RefPtr<MediaStreamTrackSource> mSource;
   const UniquePtr<TrackSink> mSink;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsIPrincipal> mPendingPrincipal;
   RefPtr<MSGListener> mMSGListener;
--- a/dom/media/mediasink/OutputStreamManager.cpp
+++ b/dom/media/mediasink/OutputStreamManager.cpp
@@ -152,27 +152,26 @@ void OutputStreamData::SetPrincipal(nsIP
       continue;
     }
     DecodedStreamTrackSource& source =
         static_cast<DecodedStreamTrackSource&>(track->GetSource());
     source.SetPrincipal(aPrincipal);
   }
 }
 
-OutputStreamManager::OutputStreamManager(MediaStreamGraph* aGraph,
+OutputStreamManager::OutputStreamManager(SharedDummyStream* aDummyStream,
                                          nsIPrincipal* aPrincipal,
                                          AbstractThread* aAbstractMainThread)
     : mAbstractMainThread(aAbstractMainThread),
-      mDummyStream(aGraph->CreateSourceStream()),
+      mDummyStream(aDummyStream),
       mPrincipalHandle(
           aAbstractMainThread,
           aPrincipal ? MakePrincipalHandle(aPrincipal) : PRINCIPAL_HANDLE_NONE,
           "OutputStreamManager::mPrincipalHandle (Canonical)") {
   MOZ_ASSERT(NS_IsMainThread());
-  mDummyStream->Suspend();
 }
 
 void OutputStreamManager::Add(DOMMediaStream* aDOMStream) {
   MOZ_ASSERT(NS_IsMainThread());
 
   LOG(LogLevel::Info, "Adding MediaStream %p", aDOMStream);
 
   OutputStreamData* p = mStreams
@@ -245,17 +244,17 @@ size_t OutputStreamManager::NumberOfTrac
 
 already_AddRefed<SourceMediaStream> OutputStreamManager::AddTrack(
     MediaSegment::Type aType) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!HasTrackType(aType),
              "Cannot have two tracks of the same type at the same time");
 
   RefPtr<SourceMediaStream> stream =
-      mDummyStream->Graph()->CreateSourceStream();
+      mDummyStream->mStream->Graph()->CreateSourceStream();
   if (!mPlaying) {
     stream->Suspend();
   }
 
   LOG(LogLevel::Info, "Adding %s track sourced by stream %p",
       aType == MediaSegment::AUDIO ? "audio" : "video", stream.get());
 
   mLiveTracks.AppendElement(MakeUnique<LiveTrack>(stream, aType));
@@ -343,13 +342,13 @@ void OutputStreamManager::SetPlaying(boo
       lt->mSourceStream->Resume();
       lt->mEverPlayed = true;
     } else {
       lt->mSourceStream->Suspend();
     }
   }
 }
 
-OutputStreamManager::~OutputStreamManager() { mDummyStream->Destroy(); }
+OutputStreamManager::~OutputStreamManager() = default;
 
 #undef LOG
 
 }  // namespace mozilla
--- a/dom/media/mediasink/OutputStreamManager.h
+++ b/dom/media/mediasink/OutputStreamManager.h
@@ -54,17 +54,17 @@ class OutputStreamData {
   // Tracks that have been added and not yet removed.
   nsTArray<WeakPtr<dom::MediaStreamTrack>> mTracks;
 };
 
 class OutputStreamManager {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OutputStreamManager);
 
  public:
-  OutputStreamManager(MediaStreamGraph* aGraph, nsIPrincipal* aPrincipal,
+  OutputStreamManager(SharedDummyStream* aDummyStream, nsIPrincipal* aPrincipal,
                       AbstractThread* aAbstractMainThread);
   // Add the output stream to the collection.
   void Add(DOMMediaStream* aDOMStream);
   // Remove the output stream from the collection.
   void Remove(DOMMediaStream* aDOMStream);
   // Returns true if there's a live track of the given type.
   bool HasTrackType(MediaSegment::Type aType);
   // Returns true if the given streams are sourcing all currently live tracks.
@@ -148,17 +148,17 @@ class OutputStreamManager {
   };
 
   // Goes through mStreams and removes any entries that have been destroyed.
   void AutoRemoveDestroyedStreams();
 
   // Remove tracks sourced from aStream from all output streams.
   void RemoveTrack(SourceMediaStream* aStream);
 
-  const RefPtr<SourceMediaStream> mDummyStream;
+  const RefPtr<SharedDummyStream> mDummyStream;
   nsTArray<UniquePtr<OutputStreamData>> mStreams;
   nsTArray<UniquePtr<LiveTrack>> mLiveTracks;
   Canonical<PrincipalHandle> mPrincipalHandle;
   bool mPlaying = false;
 };
 
 }  // namespace mozilla
 
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/crashtests/1576938.html
@@ -0,0 +1,16 @@
+<html class="reftest-wait">
+<head>
+<script>
+async function start () {
+  const peer = new RTCPeerConnection()
+  await peer.createOffer({'offerToReceiveVideo': true})
+  const receiver = peer.getReceivers()[0]
+  peer.close()
+  receiver.track.clone()
+  document.documentElement.removeAttribute("class")
+}
+
+document.addEventListener('DOMContentLoaded', start)
+</script>
+</head>
+</html>
--- a/dom/media/tests/crashtests/crashtests.list
+++ b/dom/media/tests/crashtests/crashtests.list
@@ -26,10 +26,11 @@ load 1453030.html
 load 1468451.html
 skip-if(Android) load 1490700.html # No screenshare on Android
 load 1505957.html
 load 1509442.html
 load 1511130.html
 load 1510848.html
 load 1516292.html
 skip-if(Android) pref(media.getusermedia.browser.enabled,true) load 1560207.html # No tabshare on Android
+load 1576938.html
 skip-if(Android) pref(media.getusermedia.audiocapture.enabled,true) load 1573536.html
 skip-if(!Android) pref(media.getusermedia.audiocapture.enabled,true) pref(media.navigator.permission.device,false) load 1573536.html # media.navigator.permission.device is mobile-only, so other platforms fail to set it (Bug 1350948)
--- a/dom/security/nsMixedContentBlocker.cpp
+++ b/dom/security/nsMixedContentBlocker.cpp
@@ -35,16 +35,17 @@
 #include "nsISiteSecurityService.h"
 #include "prnetdb.h"
 
 #include "mozilla/Logging.h"
 #include "mozilla/StaticPrefs_dom.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/ipc/URIUtils.h"
+#include "mozilla/net/DNS.h"
 
 using namespace mozilla;
 
 enum nsMixedContentBlockerMessageType { eBlocked = 0x00, eUserOverride = 0x01 };
 
 // Is mixed script blocking (fonts, plugin content, scripts, stylesheets,
 // iframes, websockets, XHR) enabled?
 bool nsMixedContentBlocker::sBlockMixedScript = false;
@@ -368,19 +369,40 @@ nsMixedContentBlocker::ShouldLoad(nsIURI
                                 nsILoadInfo::BLOCKING_REASON_MIXED_BLOCKED);
   }
 
   return rv;
 }
 
 bool nsMixedContentBlocker::IsPotentiallyTrustworthyLoopbackHost(
     const nsACString& aAsciiHost) {
-  return aAsciiHost.EqualsLiteral("127.0.0.1") ||
-         aAsciiHost.EqualsLiteral("::1") ||
-         aAsciiHost.EqualsLiteral("localhost");
+  if (aAsciiHost.EqualsLiteral("::1") ||
+      aAsciiHost.EqualsLiteral("localhost")) {
+    return true;
+  }
+
+  PRNetAddr tempAddr;
+  memset(&tempAddr, 0, sizeof(PRNetAddr));
+
+  if (PR_StringToNetAddr(PromiseFlatCString(aAsciiHost).get(), &tempAddr) !=
+      PR_SUCCESS) {
+    return false;
+  }
+
+  using namespace mozilla::net;
+  NetAddr addr;
+  PRNetAddrToNetAddr(&tempAddr, &addr);
+
+  // Step 4 of
+  // https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy says
+  // we should only consider [::1]/128 as a potentially trustworthy IPv6
+  // address, whereas for IPv4 127.0.0.1/8 are considered as potentially
+  // trustworthy.  We already handled "[::1]" above, so all that's remained to
+  // handle here are IPv4 loopback addresses.
+  return IsIPAddrV4(&addr) && IsLoopBackAddress(&addr);
 }
 
 bool nsMixedContentBlocker::IsPotentiallyTrustworthyLoopbackURL(nsIURI* aURL) {
   nsAutoCString asciiHost;
   nsresult rv = aURL->GetAsciiHost(asciiHost);
   NS_ENSURE_SUCCESS(rv, false);
   return IsPotentiallyTrustworthyLoopbackHost(asciiHost);
 }
--- a/dom/security/test/general/mochitest.ini
+++ b/dom/security/test/general/mochitest.ini
@@ -42,17 +42,16 @@ skip-if = toolkit == 'android' # intermi
 skip-if = toolkit == 'android'
 [test_allow_opening_data_json.html]
 skip-if = toolkit == 'android'
 [test_block_subresource_redir_to_data.html]
 [test_same_site_cookies_subrequest.html]
 [test_same_site_cookies_toplevel_nav.html]
 skip-if = fission # Crashes: @ mozilla::dom::ContentParent::CommonCreateWindow(mozilla::dom::PBrowserParent*, bool, unsigned int const&, bool const&, bool const&, bool const&, nsIURI*, nsTString<char> const&, float const&, unsigned long, nsTString<char16_t> const&, nsresult&, nsCOMPtr<nsIRemoteTab>&, bool*, int&, nsIPrincipal*, nsIReferrerInfo*, bool, nsIContentSecurityPolicy*)
 [test_same_site_cookies_cross_origin_context.html]
-fail-if = fission
 [test_same_site_cookies_from_script.html]
 [test_same_site_cookies_redirect.html]
 [test_same_site_cookies_toplevel_set_cookie.html]
 skip-if = fission
 [test_same_site_cookies_iframe.html]
 skip-if = fission # Fails intermittently under Fission
 [test_same_site_cookies_about.html]
 skip-if = fission # Fails intermittently under Fission
--- a/dom/security/test/gtest/TestSecureContext.cpp
+++ b/dom/security/test/gtest/TestSecureContext.cpp
@@ -36,16 +36,24 @@ TEST(SecureContext, IsOriginPotentiallyT
       {"ws://example.com/", false},
       {"wss://example.com/", true},
       {"file:///xyzzy", true},
       {"ftp://example.com", false},
       {"about:config", false},
       {"http://localhost", true},
       {"http://xyzzy.localhost", false},
       {"http://127.0.0.1", true},
+      {"http://127.0.0.2", true},
+      {"http://127.1.0.1", true},
+      {"http://128.0.0.1", false},
+      {"http://[::1]", true},
+      {"http://[::ffff:127.0.0.1]", false},
+      {"http://[::ffff:127.0.0.2]", false},
+      {"http://[::ffff:7f00:1]", false},
+      {"http://[::ffff:7f00:2]", false},
       {"resource://xyzzy", true},
       {"moz-extension://xyzzy", true},
       {"data:data:text/plain;charset=utf-8;base64,eHl6enk=", false},
       {"blob://unique-id", false},
       {"mailto:foo@bar.com", false},
       {"moz-icon://example.com", false},
       {"javascript:42", false},
   };
--- a/dom/tests/mochitest/whatwg/mochitest.ini
+++ b/dom/tests/mochitest/whatwg/mochitest.ini
@@ -20,25 +20,30 @@ support-files =
 [test_document_scripts.html]
 [test_MessageEvent_dispatchToOther.html]
 [test_MessageEvent.html]
 [test_postMessage_basehref.html]
 [test_postMessage_closed.html]
 skip-if = toolkit == 'android' #bug 894914 - wrong data - got FAIL, expected message
 [test_postMessage_hash.html]
 [test_postMessage.html]
+skip-if = fission # Timeouts
 [test_postMessage_idn.xhtml]
+skip-if = fission # Timeouts
 [test_postMessage_joined.html]
+skip-if = fission # Timeouts
 [test_postMessage_onOther.html]
 skip-if = fission #Bug 1571273
 [test_postMessage_origin.xhtml]
+skip-if = fission # Timeouts
 [test_postMessage_override.html]
 skip-if = fission
 [test_postMessage_special.xhtml]
 [test_postMessage_structured_clone.html]
 skip-if = fission #Bug 1570918
 [test_postMessage_throw.html]
 [test_postMessage_transfer.html]
 skip-if = fission #Bug 1571208
 [test_postMessage_userpass.html]
+skip-if = fission # Timeouts
 [test_bug500328.html]
 skip-if = true || toolkit=='android' # bug 696306, #TIMED_OUT android
 support-files = file_bug500328_1.html file_bug500328_2.html
--- a/gfx/2d/DrawTargetRecording.cpp
+++ b/gfx/2d/DrawTargetRecording.cpp
@@ -634,23 +634,27 @@ void DrawTargetRecording::FlushItem(cons
 
 void DrawTargetRecording::EnsurePatternDependenciesStored(
     const Pattern& aPattern) {
   switch (aPattern.GetType()) {
     case PatternType::COLOR:
       // No dependencies here.
       return;
     case PatternType::LINEAR_GRADIENT: {
-      MOZ_ASSERT(mRecorder->HasStoredObject(
-          static_cast<const LinearGradientPattern*>(&aPattern)->mStops));
+      MOZ_ASSERT_IF(
+          static_cast<const LinearGradientPattern*>(&aPattern)->mStops,
+          mRecorder->HasStoredObject(
+              static_cast<const LinearGradientPattern*>(&aPattern)->mStops));
       return;
     }
     case PatternType::RADIAL_GRADIENT: {
-      MOZ_ASSERT(mRecorder->HasStoredObject(
-          static_cast<const RadialGradientPattern*>(&aPattern)->mStops));
+      MOZ_ASSERT_IF(
+          static_cast<const LinearGradientPattern*>(&aPattern)->mStops,
+          mRecorder->HasStoredObject(
+              static_cast<const RadialGradientPattern*>(&aPattern)->mStops));
       return;
     }
     case PatternType::SURFACE: {
       const SurfacePattern* pat = static_cast<const SurfacePattern*>(&aPattern);
       EnsureSurfaceStoredRecording(mRecorder, pat->mSurface,
                                    "EnsurePatternDependenciesStored");
       return;
     }
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -1593,17 +1593,19 @@ already_AddRefed<DrawTarget> DrawTargetS
   if (!target->Init(aSize, aFormat)) {
     return nullptr;
   }
   return target.forget();
 }
 
 bool DrawTargetSkia::CanCreateSimilarDrawTarget(const IntSize& aSize,
                                                 SurfaceFormat aFormat) const {
-  return size_t(std::max(aSize.width, aSize.height)) < GetMaxSurfaceSize();
+  auto minmaxPair = std::minmax(aSize.width, aSize.height);
+  return minmaxPair.first >= 0 &&
+         size_t(minmaxPair.second) < GetMaxSurfaceSize();
 }
 
 RefPtr<DrawTarget> DrawTargetSkia::CreateClippedDrawTarget(
     const Rect& aBounds, SurfaceFormat aFormat) {
   SkIRect clipBounds;
 
   RefPtr<DrawTarget> result;
   // Doing this save()/restore() dance is wasteful
--- a/gfx/2d/InlineTranslator.h
+++ b/gfx/2d/InlineTranslator.h
@@ -59,18 +59,25 @@ class InlineTranslator : public Translat
 
   FilterNode* LookupFilterNode(ReferencePtr aRefPtr) final {
     FilterNode* result = mFilterNodes.GetWeak(aRefPtr);
     MOZ_ASSERT(result);
     return result;
   }
 
   GradientStops* LookupGradientStops(ReferencePtr aRefPtr) final {
-    GradientStops* result = mGradientStops.GetWeak(aRefPtr);
-    MOZ_ASSERT(result);
+    DebugOnly<bool> found;
+    GradientStops* result = mGradientStops.GetWeak(aRefPtr
+#if defined(DEBUG)
+                                                   ,
+                                                   &found
+#endif
+    );
+    // GradientStops can be null in some circumstances.
+    MOZ_ASSERT(found);
     return result;
   }
 
   ScaledFont* LookupScaledFont(ReferencePtr aRefPtr) final {
     ScaledFont* result = mScaledFonts.GetWeak(aRefPtr);
     MOZ_ASSERT(result);
     return result;
   }
--- a/gfx/2d/RecordedEventImpl.h
+++ b/gfx/2d/RecordedEventImpl.h
@@ -2088,28 +2088,30 @@ struct GenericPattern {
         return mPattern;
       }
       case PatternType::LINEAR_GRADIENT: {
         LinearGradientPatternStorage* storage =
             reinterpret_cast<LinearGradientPatternStorage*>(
                 &mStorage->mStorage);
         mPattern = new (mLinGradPat) LinearGradientPattern(
             storage->mBegin, storage->mEnd,
-            mTranslator->LookupGradientStops(storage->mStops),
+            storage->mStops ? mTranslator->LookupGradientStops(storage->mStops)
+                            : nullptr,
             storage->mMatrix);
         return mPattern;
       }
       case PatternType::RADIAL_GRADIENT: {
         RadialGradientPatternStorage* storage =
             reinterpret_cast<RadialGradientPatternStorage*>(
                 &mStorage->mStorage);
         mPattern = new (mRadGradPat) RadialGradientPattern(
             storage->mCenter1, storage->mCenter2, storage->mRadius1,
             storage->mRadius2,
-            mTranslator->LookupGradientStops(storage->mStops),
+            storage->mStops ? mTranslator->LookupGradientStops(storage->mStops)
+                            : nullptr,
             storage->mMatrix);
         return mPattern;
       }
       default:
         return new (mColPat) ColorPattern(Color());
     }
 
     return mPattern;
--- a/gfx/thebes/SharedFontList.cpp
+++ b/gfx/thebes/SharedFontList.cpp
@@ -752,17 +752,26 @@ Family* FontList::FindFamily(const nsCSt
 #ifdef XP_WIN
   // For Windows only, because of how DWrite munges font family names in some
   // cases (see
   // https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/02/24/90/36/WPF%20Font%20Selection%20Model.pdf
   // and discussion on the OpenType list), try stripping any known "regular"
   // style name from the end of the requested family name.
   // After the deferred font loader has finished, this is no longer needed as
   // the "real" family names will have been found in AliasFamilies() above.
-  if (!header.mAliasCount && aName.Contains(' ')) {
+  if (aName.Contains(' ')) {
+    auto pfl = gfxPlatformFontList::PlatformFontList();
+    if (header.mAliasCount) {
+      // Aliases have been fully loaded by the parent process, so just discard
+      // any stray mAliasTable and mLocalNameTable entries from earlier calls
+      // to this code, and return.
+      pfl->mAliasTable.Clear();
+      pfl->mLocalNameTable.Clear();
+      return nullptr;
+    }
     const nsLiteralCString kStyleSuffixes[] = {
         nsLiteralCString(" book"),   nsLiteralCString(" medium"),
         nsLiteralCString(" normal"), nsLiteralCString(" regular"),
         nsLiteralCString(" roman"),  nsLiteralCString(" upright")};
     for (const auto& styleName : kStyleSuffixes) {
       if (StringEndsWith(aName, styleName)) {
         // See if we have a known family that matches the "base" family name
         // with trailing style-name element stripped off.
@@ -771,20 +780,24 @@ Family* FontList::FindFamily(const nsCSt
         families = Families();
         if (BinarySearchIf(families, 0, header.mFamilyCount,
                            FamilyNameComparator(this, strippedName), &match)) {
           // If so, this may be a possible family to satisfy the search; check
           // if the extended family name was actually found as an alternate
           // (either it's already in mAliasTable, or it gets added there when
           // we call ReadFaceNamesForFamily on this candidate).
           Family* candidateFamily = &families[match];
-          auto pfl = gfxPlatformFontList::PlatformFontList();
           if (pfl->mAliasTable.Lookup(aName)) {
             return candidateFamily;
           }
+          // Note that ReadFaceNamesForFamily may store entries in mAliasTable
+          // (and mLocalNameTable), but if this is happening in a content
+          // process (which is the common case) those entries will not be saved
+          // into the shared font list; they're just used here until the "real"
+          // alias list is ready, then discarded.
           pfl->ReadFaceNamesForFamily(candidateFamily, false);
           if (pfl->mAliasTable.Lookup(aName)) {
             return candidateFamily;
           }
         }
         break;
       }
     }
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -395,16 +395,19 @@ nsresult gfxPlatformFontList::InitFontLi
   gfxFontCache* fontCache = gfxFontCache::GetCache();
   if (fontCache) {
     fontCache->AgeAllGenerations();
     fontCache->FlushShapedWordCaches();
   }
 
   gfxPlatform::PurgeSkiaFontCache();
 
+  mAliasTable.Clear();
+  mLocalNameTable.Clear();
+
   CancelInitOtherFamilyNamesTask();
   MutexAutoLock lock(mFontFamiliesMutex);
   mFontFamilies.Clear();
   mOtherFamilyNames.Clear();
   mOtherFamilyNamesInitialized = false;
 
   if (mExtraNames) {
     mExtraNames->mFullnames.Clear();
@@ -2112,17 +2115,17 @@ void gfxPlatformFontList::InitOtherFamil
 }
 
 void gfxPlatformFontList::CancelInitOtherFamilyNamesTask() {
   if (mPendingOtherFamilyNameTask) {
     mPendingOtherFamilyNameTask->Cancel();
     mPendingOtherFamilyNameTask = nullptr;
   }
   auto list = SharedFontList();
-  if (list) {
+  if (list && XRE_IsParentProcess()) {
     bool forceReflow = false;
     if (!mAliasTable.IsEmpty()) {
       list->SetAliases(mAliasTable);
       mAliasTable.Clear();
       forceReflow = true;
     }
     if (mLocalNameTable.Count()) {
       list->SetLocalNames(mLocalNameTable);
--- a/gfx/wr/webrender/src/util.rs
+++ b/gfx/wr/webrender/src/util.rs
@@ -820,17 +820,17 @@ pub fn project_rect<F, T>(
         transform.transform_point2d_homogeneous(rect.origin),
         transform.transform_point2d_homogeneous(rect.top_right()),
         transform.transform_point2d_homogeneous(rect.bottom_left()),
         transform.transform_point2d_homogeneous(rect.bottom_right()),
     ];
 
     // Note: we only do the full frustum collision when the polygon approaches the camera plane.
     // Otherwise, it will be clamped to the screen bounds anyway.
-    if homogens.iter().any(|h| h.w <= 0.0) {
+    if homogens.iter().any(|h| h.w <= 0.0 || h.w.is_nan()) {
         let mut clipper = Clipper::new();
         let polygon = Polygon::from_rect(*rect, 1);
 
         let planes = match Clipper::frustum_planes(
             transform,
             Some(*bounds),
         ) {
             Ok(planes) => planes,
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,3 +1,3 @@
 org.gradle.parallel=true
 org.gradle.daemon=true
-org.gradle.jvmargs=-Xmx4608M
+org.gradle.jvmargs=-Xmx6656M
--- a/js/moz.configure
+++ b/js/moz.configure
@@ -497,16 +497,31 @@ def default_wasm_reftypes(is_nightly):
 js_option('--enable-wasm-reftypes',
           default=default_wasm_reftypes,
           help='{Enable|Disable} WebAssembly reference types')
 
 set_config('ENABLE_WASM_REFTYPES', depends_if('--enable-wasm-reftypes')(lambda x: True))
 set_define('ENABLE_WASM_REFTYPES', depends_if('--enable-wasm-reftypes')(lambda x: True))
 
 
+# Support for WebAssembly I64/BigInt conversion
+# ===========================================================================
+
+@depends(milestone.is_nightly)
+def default_wasm_bigint(is_nightly):
+    return is_nightly
+
+js_option('--enable-wasm-bigint',
+          default=default_wasm_bigint,
+          help='{Enable|Disable} WebAssembly I64/BigInt conversion')
+
+set_config('ENABLE_WASM_BIGINT', depends_if('--enable-wasm-bigint')(lambda x: True))
+set_define('ENABLE_WASM_BIGINT', depends_if('--enable-wasm-bigint')(lambda x: True))
+
+
 # Support for WebAssembly GC.
 # ===========================
 
 @depends(milestone.is_nightly, '--enable-wasm-reftypes')
 def default_wasm_gc(is_nightly, reftypes):
     if reftypes and is_nightly:
         return True
 
--- a/js/src/frontend/BinASTTokenReaderContext.cpp
+++ b/js/src/frontend/BinASTTokenReaderContext.cpp
@@ -19,24 +19,29 @@
 #include "js/Vector.h"               // js::Vector
 #include "util/StringBuffer.h"       // StringBuffer
 #include "vm/JSAtom.h"               // AtomizeWTF8Chars
 #include "vm/JSScript.h"             // ScriptSource
 
 namespace js {
 namespace frontend {
 
+#ifdef BINAST_CX_MAGIC_HEADER  // Context 0.1 doesn't implement the planned
+                               // magic header.
+
 // The magic header, at the start of every binjs file.
 const char CX_MAGIC_HEADER[] =
     "\x89"
     "BJS\r\n\0\n";
 
 // The latest format version understood by this tokenizer.
 const uint32_t MAGIC_FORMAT_VERSION = 2;
 
+#endif  // BINAST_CX_MAGIC_HEADER
+
 // The maximal length of a single Huffman code, in bits.
 //
 // Hardcoded in the format.
 const uint8_t MAX_CODE_BIT_LENGTH = 20;
 
 // The maximal length of a Huffman prefix.
 //
 // This is distinct from MAX_CODE_BIT_LENGTH as we commonly load
@@ -811,23 +816,25 @@ JS::Result<Ok> BinASTTokenReaderContext:
 
   return Ok();
 }
 
 JS::Result<Ok> BinASTTokenReaderContext::readHeader() {
   // Check that we don't call this function twice.
   MOZ_ASSERT(!posBeforeTree_);
 
+#if BINAST_CX_MAGIC_HEADER
   // Read global headers.
   MOZ_TRY(readConst(CX_MAGIC_HEADER));
   BINJS_MOZ_TRY_DECL(version, readVarU32<Compression::No>());
 
   if (version != MAGIC_FORMAT_VERSION) {
     return raiseError("Format version not implemented");
   }
+#endif  // BINAST_CX_MAGIC_HEADER
 
   MOZ_TRY(readStringPrelude());
   MOZ_TRY(readHuffmanPrelude());
 
   return raiseError("Not Yet Implemented");
 }
 
 JS::Result<Ok> BinASTTokenReaderContext::readStringPrelude() {
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -4309,23 +4309,25 @@ CodeOffset MacroAssembler::nopPatchableT
 }
 
 void MacroAssembler::patchNopToCall(uint8_t* call, uint8_t* target) {
   uint8_t* inst = call - 4;
   MOZ_ASSERT(reinterpret_cast<Instruction*>(inst)->is<InstBLImm>() ||
              reinterpret_cast<Instruction*>(inst)->is<InstNOP>());
 
   new (inst) InstBLImm(BOffImm(target - inst), Assembler::Always);
+  AutoFlushICache::flush(uintptr_t(inst), 4);
 }
 
 void MacroAssembler::patchCallToNop(uint8_t* call) {
   uint8_t* inst = call - 4;
   MOZ_ASSERT(reinterpret_cast<Instruction*>(inst)->is<InstBLImm>() ||
              reinterpret_cast<Instruction*>(inst)->is<InstNOP>());
   new (inst) InstNOP();
+  AutoFlushICache::flush(uintptr_t(inst), 4);
 }
 
 void MacroAssembler::pushReturnAddress() { push(lr); }
 
 void MacroAssembler::popReturnAddress() { pop(lr); }
 
 // ===============================================================
 // ABI function calls.
--- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
+++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
@@ -1495,21 +1495,23 @@ CodeOffset MacroAssembler::nopPatchableT
   return CodeOffset(currentOffset());
 }
 
 void MacroAssembler::patchNopToCall(uint8_t* call, uint8_t* target) {
 #ifdef JS_CODEGEN_MIPS64
   Instruction* inst = (Instruction*)call - 6 /* six nops */;
   Assembler::WriteLoad64Instructions(inst, ScratchRegister, (uint64_t)target);
   inst[4] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr);
+  AutoFlushICache::flush(uintptr_t(inst), 6 * 4);
 #else
   Instruction* inst = (Instruction*)call - 4 /* four nops */;
   Assembler::WriteLuiOriInstructions(inst, &inst[1], ScratchRegister,
                                      (uint32_t)target);
   inst[2] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr);
+  AutoFlushICache::flush(uintptr_t(inst), 4 * 4);
 #endif
 }
 
 void MacroAssembler::patchCallToNop(uint8_t* call) {
 #ifdef JS_CODEGEN_MIPS64
   Instruction* inst = (Instruction*)call - 6 /* six nops */;
 #else
   Instruction* inst = (Instruction*)call - 4 /* four nops */;
@@ -1517,16 +1519,19 @@ void MacroAssembler::patchCallToNop(uint
 
   inst[0].makeNop();
   inst[1].makeNop();
   inst[2].makeNop();
   inst[3].makeNop();
 #ifdef JS_CODEGEN_MIPS64
   inst[4].makeNop();
   inst[5].makeNop();
+  AutoFlushICache::flush(uintptr_t(inst), 6 * 4);
+#else
+  AutoFlushICache::flush(uintptr_t(inst), 4 * 4);
 #endif
 }
 
 void MacroAssembler::pushReturnAddress() { push(ra); }
 
 void MacroAssembler::popReturnAddress() { pop(ra); }
 
 // ===============================================================
--- a/js/src/wasm/cranelift/src/compile.rs
+++ b/js/src/wasm/cranelift/src/compile.rs
@@ -20,18 +20,17 @@
 
 use std::fmt;
 use std::mem;
 
 use cranelift_codegen::binemit::{
     Addend, CodeInfo, CodeOffset, NullStackmapSink, NullTrapSink, Reloc, RelocSink,
 };
 use cranelift_codegen::entity::EntityRef;
-use cranelift_codegen::ir;
-use cranelift_codegen::ir::stackslot::StackSize;
+use cranelift_codegen::ir::{self, constant::ConstantOffset, stackslot::StackSize};
 use cranelift_codegen::isa::TargetIsa;
 use cranelift_codegen::CodegenResult;
 use cranelift_codegen::Context;
 use cranelift_wasm::{FuncIndex, FuncTranslator, WasmResult};
 
 use crate::bindings;
 use crate::isa::make_isa;
 use crate::utils::DashResult;
@@ -537,25 +536,35 @@ impl<'a> RelocSink for EmitEnv<'a> {
                     }
                 };
 
                 // The symbolic access patch address points *after* the stored pointer.
                 let offset = offset + native_pointer_size() as u32;
                 self.metadata
                     .push(bindings::MetadataEntry::symbolic_access(offset, sym));
             }
+
             _ => {
                 panic!("Don't understand external {}", name);
             }
         }
     }
 
     fn reloc_jt(&mut self, offset: CodeOffset, reloc: Reloc, _jt: ir::JumpTable) {
         match reloc {
             Reloc::X86PCRelRodata4 => {
                 self.rodata_relocs.push(offset);
             }
             _ => {
                 panic!("Unhandled/unexpected reloc type");
             }
         }
     }
+
+    fn reloc_constant(
+        &mut self,
+        _offset: CodeOffset,
+        _reloc: Reloc,
+        _constant_pool_offset: ConstantOffset,
+    ) {
+        unimplemented!("constant pools NYI");
+    }
 }
--- a/layout/generic/ReflowInput.cpp
+++ b/layout/generic/ReflowInput.cpp
@@ -1404,17 +1404,17 @@ void ReflowInput::CalculateHypotheticalP
       NS_ASSERTION(iter.GetContainer() == blockFrame,
                    "Found placeholder in wrong block!");
       nsBlockFrame::LineIterator lineBox = iter.GetLine();
 
       // How we determine the hypothetical box depends on whether the element
       // would have been inline-level or block-level
       LogicalRect lineBounds = lineBox->GetBounds().ConvertTo(
           wm, lineBox->mWritingMode, lineBox->mContainerSize);
-      if (mStyleDisplay->IsOriginalDisplayInlineOutsideStyle()) {
+      if (mStyleDisplay->IsOriginalDisplayInlineOutside()) {
         // Use the block-start of the inline box which the placeholder lives in
         // as the hypothetical box's block-start.
         aHypotheticalPos.mBStart = lineBounds.BStart(wm) + blockOffset.B(wm);
       } else {
         // The element would have been block-level which means it would
         // be below the line containing the placeholder frame, unless
         // all the frames before it are empty.  In that case, it would
         // have been just before this line.
@@ -1471,17 +1471,17 @@ void ReflowInput::CalculateHypotheticalP
     // like a XUL box, etc.
     // Just use the placeholder's block-offset
     aHypotheticalPos.mBStart = placeholderOffset.B(wm);
   }
 
   // Second, determine the hypothetical box's mIStart.
   // How we determine the hypothetical box depends on whether the element
   // would have been inline-level or block-level
-  if (mStyleDisplay->IsOriginalDisplayInlineOutsideStyle() ||
+  if (mStyleDisplay->IsOriginalDisplayInlineOutside() ||
       mFlags.mIOffsetsNeedCSSAlign) {
     // The placeholder represents the IStart edge of the hypothetical box.
     // (Or if mFlags.mIOffsetsNeedCSSAlign is set, it represents the IStart
     // edge of the Alignment Container.)
     aHypotheticalPos.mIStart = placeholderOffset.I(wm);
   } else {
     aHypotheticalPos.mIStart = blockIStartContentEdge;
   }
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -894,27 +894,20 @@ bool nsComputedDOMStyle::NeedsToFlushLay
       // layout for themed frames.
       return PaddingNeedsUsedValue(style->StylePadding()->mPadding.Get(side),
                                    *style);
     }
     case eCSSProperty_margin_top:
     case eCSSProperty_margin_right:
     case eCSSProperty_margin_bottom:
     case eCSSProperty_margin_left: {
-      // NOTE(emilio): We could do the commented out thing below, but it is not
-      // clear whether it's correct. It does change behavior and cause a new
-      // test to _pass_. But it's unclear whether it is the right thing, see:
-      //
-      // https://github.com/w3c/csswg-drafts/issues/2328
-      //
-      // Bug 1570759 tracks maybe changing the behavior here.
-      //
-      // Side side = SideForPaddingOrMarginOrInsetProperty(aPropID);
-      // return !style->StyleMargin()->mMargin.Get(side).ConvertsToLength();
-      return true;
+      // NOTE(emilio): This is dubious, but matches other browsers.
+      // See https://github.com/w3c/csswg-drafts/issues/2328
+      Side side = SideForPaddingOrMarginOrInsetProperty(aPropID);
+      return !style->StyleMargin()->mMargin.Get(side).ConvertsToLength();
     }
     default:
       return false;
   }
 }
 
 void nsComputedDOMStyle::Flush(Document& aDocument, FlushType aFlushType) {
   MOZ_ASSERT(mElement->IsInComposedDoc());
@@ -2221,17 +2214,17 @@ already_AddRefed<CSSValue> nsComputedDOM
   return val.forget();
 }
 
 already_AddRefed<CSSValue> nsComputedDOMStyle::GetMarginWidthFor(
     mozilla::Side aSide) {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   auto& margin = StyleMargin()->mMargin.Get(aSide);
-  if (!mInnerFrame) {
+  if (!mInnerFrame || margin.ConvertsToLength()) {
     SetValueToLengthPercentageOrAuto(val, margin, false);
   } else {
     AssertFlushedPendingReflows();
 
     // For tables, GetUsedMargin always returns an empty margin, so we
     // should read the margin from the table wrapper frame instead.
     val->SetAppUnits(mOuterFrame->GetUsedMargin().Side(aSide));
     NS_ASSERTION(mOuterFrame == mInnerFrame ||
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1659,17 +1659,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
            mozilla::StyleDisplay::RubyText == aDisplay ||
            mozilla::StyleDisplay::RubyTextContainer == aDisplay;
   }
 
   bool IsInlineOutsideStyle() const {
     return IsDisplayTypeInlineOutside(mDisplay);
   }
 
-  bool IsOriginalDisplayInlineOutsideStyle() const {
+  bool IsOriginalDisplayInlineOutside() const {
     return IsDisplayTypeInlineOutside(mOriginalDisplay);
   }
 
   bool IsInnerTableStyle() const {
     return DisplayOutside() == mozilla::StyleDisplayOutside::InternalTable;
   }
 
   bool IsInternalTableStyleExceptCell() const {
@@ -1801,18 +1801,16 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   // These are defined in nsStyleStructInlines.h.
 
   // The aContextFrame argument on each of these is the frame this
   // style struct is for.  If the frame is for SVG text, the return
   // value will be massaged to be something that makes sense for
   // SVG text.
   inline bool IsBlockOutside(const nsIFrame* aContextFrame) const;
   inline bool IsInlineOutside(const nsIFrame* aContextFrame) const;
-  inline bool IsOriginalDisplayInlineOutside(
-      const nsIFrame* aContextFrame) const;
   inline mozilla::StyleDisplay GetDisplay(const nsIFrame* aContextFrame) const;
   inline bool IsFloating(const nsIFrame* aContextFrame) const;
   inline bool IsRelativelyPositioned(const nsIFrame* aContextFrame) const;
   inline bool IsStickyPositioned(const nsIFrame* aContextFrame) const;
   inline bool IsAbsolutelyPositioned(const nsIFrame* aContextFrame) const;
 
   // These methods are defined in nsStyleStructInlines.h.
 
--- a/layout/style/nsStyleStructInlines.h
+++ b/layout/style/nsStyleStructInlines.h
@@ -67,26 +67,16 @@ bool nsStyleDisplay::IsInlineOutside(con
   NS_ASSERTION(aContextFrame->StyleDisplay() == this,
                "unexpected aContextFrame");
   if (nsSVGUtils::IsInSVGTextSubtree(aContextFrame)) {
     return !aContextFrame->IsBlockFrame();
   }
   return IsInlineOutsideStyle();
 }
 
-bool nsStyleDisplay::IsOriginalDisplayInlineOutside(
-    const nsIFrame* aContextFrame) const {
-  NS_ASSERTION(aContextFrame->StyleDisplay() == this,
-               "unexpected aContextFrame");
-  if (nsSVGUtils::IsInSVGTextSubtree(aContextFrame)) {
-    return !aContextFrame->IsBlockFrame();
-  }
-  return IsOriginalDisplayInlineOutsideStyle();
-}
-
 mozilla::StyleDisplay nsStyleDisplay::GetDisplay(
     const nsIFrame* aContextFrame) const {
   NS_ASSERTION(aContextFrame->StyleDisplay() == this,
                "unexpected aContextFrame");
   if (nsSVGUtils::IsInSVGTextSubtree(aContextFrame) &&
       mDisplay != mozilla::StyleDisplay::None) {
     return aContextFrame->IsBlockFrame() ? mozilla::StyleDisplay::Block
                                          : mozilla::StyleDisplay::Inline;
--- a/layout/style/test/mochitest.ini
+++ b/layout/style/test/mochitest.ini
@@ -48,16 +48,17 @@ support-files =
   visited_image_loading.sjs
   visited-lying-inner.html
   visited-pref-iframe.html
   xbl_bindings.xml
 
 [test_acid3_test46.html]
 [test_addSheet.html]
 support-files = additional_sheets_helper.html
+[test_user_sheet_shadow_dom.html]
 [test_additional_sheets.html]
 support-files = additional_sheets_helper.html
 [test_align_justify_computed_values.html]
 [test_all_shorthand.html]
 [test_animations.html]
 skip-if = (toolkit == 'android')
 [test_animations_async_tests.html]
 support-files = Ahem.ttf file_animations_async_tests.html
new file mode 100644
--- /dev/null
+++ b/layout/style/test/test_user_sheet_shadow_dom.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<title>Test for bug 1576229 - Nodes in Shadow DOM react properly to dynamic changes in user sheets</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<div></div>
+<span id="host" style="display: block"></span>
+<script>
+const gIOService = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
+  .getService(SpecialPowers.Ci.nsIIOService)
+
+const gSSService = SpecialPowers.Cc["@mozilla.org/content/style-sheet-service;1"]
+  .getService(SpecialPowers.Ci.nsIStyleSheetService);
+
+const windowUtils = SpecialPowers.getDOMWindowUtils(window);
+
+function loadUserSheet(style) {
+  const uri = gIOService.newURI("data:text/css," + style);
+  windowUtils.loadSheet(uri, windowUtils.USER_SHEET);
+}
+
+SimpleTest.waitForExplicitFinish();
+
+onload = function() {
+  loadUserSheet(`
+    div {
+      width: 100px;
+      height: 100px;
+      background-color: red;
+    }
+    .foo {
+      background-color: green;
+    }
+  `);
+  let host = document.querySelector("#host");
+  host.attachShadow({ mode: "open" }).innerHTML = `
+    <div></div>
+  `;
+  let light = document.querySelector('div');
+  let shadow = host.shadowRoot.querySelector('div');
+  is(getComputedStyle(light).backgroundColor, "rgb(255, 0, 0)", "User sheet works in light DOM");
+  is(getComputedStyle(shadow).backgroundColor, "rgb(255, 0, 0)", "User sheet works in shadow DOM");
+  light.classList.add("foo");
+  shadow.classList.add("foo");
+  is(getComputedStyle(light).backgroundColor, "rgb(0, 128, 0)", "Dynamic change for user sheet works in light DOM");
+  is(getComputedStyle(shadow).backgroundColor, "rgb(0, 128, 0)", "Dynamic change for user sheet works in shadow DOM");
+  SimpleTest.finish();
+}
+</script>
--- a/layout/style/test/test_value_computation.html
+++ b/layout/style/test/test_value_computation.html
@@ -8,22 +8,16 @@
   <script type="text/javascript" src="property_database.js"></script>
   <style type="text/css" id="stylesheet"></style>
   <style type="text/css">
   /* For 'width', 'height', etc., need a constant size container. */
   #display { width: 500px; height: 200px }
   </style>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="text/javascript">
-  var numAssertions = 9;
-
-  // these are from the additional margin-inline-{start,end} tests
-  numAssertions += 2;
-
-  SimpleTest.expectAssertions(numAssertions);
   SimpleTest.waitForExplicitFinish();
   SimpleTest.requestLongerTimeout(2);
 
   var load_count = 0;
   function load_done() {
     if (++load_count == 3)
       run_tests();
   }
--- a/mach
+++ b/mach
@@ -21,17 +21,16 @@ py2commands="
     browsertime
     build
     build-backend
     buildsymbols
     busted
     cargo
     check-spidermonkey
     clang-format
-    clobber
     compare-locales
     compileflags
     configure
     cppunittest
     cramtest
     crashtest
     devtools-css-db
     doc
--- a/mobile/android/app/build.gradle
+++ b/mobile/android/app/build.gradle
@@ -45,17 +45,17 @@ android {
     }
 
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_1_8
         targetCompatibility JavaVersion.VERSION_1_8
     }
 
     dexOptions {
-        javaMaxHeapSize "4g"
+        javaMaxHeapSize "6g"
         jumboMode = true
     }
 
     lintOptions {
         abortOnError true
     }
 
     buildTypes {
--- a/mobile/android/config/mozconfigs/common
+++ b/mobile/android/config/mozconfigs/common
@@ -25,16 +25,19 @@ ac_add_options --with-android-sdk="$MOZ_
 ac_add_options --with-gradle="$MOZ_FETCHES_DIR/android-gradle-dependencies/gradle-dist/bin/gradle"
 export GRADLE_MAVEN_REPOSITORIES="file://$MOZ_FETCHES_DIR/android-gradle-dependencies/google","file://$MOZ_FETCHES_DIR/android-gradle-dependencies/jcenter","file://$MOZ_FETCHES_DIR/android-gradle-dependencies/gradle-plugins"
 
 if [ -z "$NO_NDK" -a -z "$USE_ARTIFACT" ]; then
     # We use our own clang instead of the NDK's clang.
     CC="$MOZ_FETCHES_DIR/clang/bin/clang"
     CXX="$MOZ_FETCHES_DIR/clang/bin/clang++"
     ac_add_options --with-android-ndk="$MOZ_FETCHES_DIR/android-ndk"
+    # Make sure that any host binaries we build use whatever libraries clang
+    # linked against, rather than what's on the system.
+    mk_add_options "export LD_LIBRARY_PATH=$MOZ_FETCHES_DIR/clang/lib"
     # Enable static analysis plugin
     export ENABLE_CLANG_PLUGIN=1
 fi
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 
 ac_add_options --with-google-safebrowsing-api-keyfile=/builds/sb-gapi.data
 ac_add_options --with-google-location-service-api-keyfile=/builds/gls-gapi.data
--- a/mobile/android/geckoview/build.gradle
+++ b/mobile/android/geckoview/build.gradle
@@ -125,17 +125,17 @@ android {
     project.configureProductFlavors()
 
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_1_8
         targetCompatibility JavaVersion.VERSION_1_8
     }
 
     dexOptions {
-        javaMaxHeapSize "4g"
+        javaMaxHeapSize "6g"
     }
 
     lintOptions {
         abortOnError false
     }
 
     sourceSets {
         main {
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/GeckoJarReader.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/GeckoJarReader.java
@@ -18,18 +18,20 @@ import org.mozilla.geckoview.BuildConfig
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.net.URLDecoder;
 import java.util.Stack;
 
 /* Reads out of a multiple level deep jar file such as
  *  jar:jar:file:///data/app/org.mozilla.fennec.apk!/omni.ja!/chrome/chrome/content/branding/favicon32.png
  */
 public final class GeckoJarReader {
     private static final String LOGTAG = "GeckoJarReader";
 
@@ -189,16 +191,21 @@ public final class GeckoJarReader {
     private static InputStream getStream(final NativeZip zip, final Stack<String> jarUrls,
                                          final String origUrl) {
         InputStream inputStream = null;
 
         NativeZip currentZip = zip;
         // loop through children jar files until we reach the innermost one
         while (!jarUrls.empty()) {
             String fileName = jarUrls.pop();
+            try {
+                fileName = URLDecoder.decode(fileName, "UTF-8");
+            } catch (UnsupportedEncodingException e) {
+                // UTF-8 is always supported
+            }
 
             if (inputStream != null) {
                 // intermediate NativeZips and InputStreams will be garbage collected.
                 try {
                     currentZip = new NativeZip(inputStream);
                 } catch (IllegalArgumentException e) {
                     String description = "!!! BUG 849589 !!! origUrl=" + origUrl;
                     Log.e(LOGTAG, description, e);
--- a/mobile/android/geckoview_example/build.gradle
+++ b/mobile/android/geckoview_example/build.gradle
@@ -17,16 +17,20 @@ android {
         versionName "1.0"
     }
 
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_1_8
         targetCompatibility JavaVersion.VERSION_1_8
     }
 
+    dexOptions {
+        javaMaxHeapSize "6g"
+    }
+
     buildTypes {
         release {
             minifyEnabled false
             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
         }
     }
 
     // By default the android plugins ignores folders that start with `_`, but
--- a/mobile/android/gradle/dotgradle-offline/gradle.properties
+++ b/mobile/android/gradle/dotgradle-offline/gradle.properties
@@ -1,4 +1,4 @@
 // Per https://docs.gradle.org/current/userguide/build_environment.html, this
 // overrides the gradle.properties in topsrcdir.
 org.gradle.daemon=false
-org.gradle.jvmargs=-Xmx4608M
+org.gradle.jvmargs=-Xmx6656M
--- a/mobile/android/gradle/dotgradle-online/gradle.properties
+++ b/mobile/android/gradle/dotgradle-online/gradle.properties
@@ -1,4 +1,4 @@
 // Per https://docs.gradle.org/current/userguide/build_environment.html, this
 // overrides the gradle.properties in topsrcdir.
 org.gradle.daemon=false
-org.gradle.jvmargs=-Xmx4608M
+org.gradle.jvmargs=-Xmx6656M
--- a/netwerk/dns/DNS.cpp
+++ b/netwerk/dns/DNS.cpp
@@ -135,17 +135,19 @@ bool NetAddrToString(const NetAddr* addr
     return true;
   }
 #endif
   return false;
 }
 
 bool IsLoopBackAddress(const NetAddr* addr) {
   if (addr->raw.family == AF_INET) {
-    return (addr->inet.ip == htonl(INADDR_LOOPBACK));
+    // Consider 127.0.0.1/8 as loopback
+    uint32_t ipv4Addr = ntohl(addr->inet.ip);
+    return (ipv4Addr >> 24) == 127;
   }
   if (addr->raw.family == AF_INET6) {
     if (IPv6ADDR_IS_LOOPBACK(&addr->inet6.ip)) {
       return true;
     }
     if (IPv6ADDR_IS_V4MAPPED(&addr->inet6.ip) &&
         IPv6ADDR_V4MAPPED_TO_IPADDR(&addr->inet6.ip) ==
             htonl(INADDR_LOOPBACK)) {
@@ -167,16 +169,18 @@ bool IsIPAddrAny(const NetAddr* addr) {
     if (IPv6ADDR_IS_V4MAPPED(&addr->inet6.ip) &&
         IPv6ADDR_V4MAPPED_TO_IPADDR(&addr->inet6.ip) == htonl(INADDR_ANY)) {
       return true;
     }
   }
   return false;
 }
 
+bool IsIPAddrV4(const NetAddr* addr) { return addr->raw.family == AF_INET; }
+
 bool IsIPAddrV4Mapped(const NetAddr* addr) {
   if (addr->raw.family == AF_INET6) {
     return IPv6ADDR_IS_V4MAPPED(&addr->inet6.ip);
   }
   return false;
 }
 
 bool IsIPAddrLocal(const NetAddr* addr) {
--- a/netwerk/dns/DNS.h
+++ b/netwerk/dns/DNS.h
@@ -168,16 +168,18 @@ void PRNetAddrToNetAddr(const PRNetAddr*
 void NetAddrToPRNetAddr(const NetAddr* addr, PRNetAddr* prAddr);
 
 bool NetAddrToString(const NetAddr* addr, char* buf, uint32_t bufSize);
 
 bool IsLoopBackAddress(const NetAddr* addr);
 
 bool IsIPAddrAny(const NetAddr* addr);
 
+bool IsIPAddrV4(const NetAddr* addr);
+
 bool IsIPAddrV4Mapped(const NetAddr* addr);
 
 bool IsIPAddrLocal(const NetAddr* addr);
 
 bool IsIPAddrShared(const NetAddr* addr);
 
 nsresult GetPort(const NetAddr* aAddr, uint16_t* aResult);
 
--- a/python/mozbuild/mozbuild/controller/clobber.py
+++ b/python/mozbuild/mozbuild/controller/clobber.py
@@ -103,17 +103,17 @@ class Clobberer(object):
             return False
 
     def collect_subdirs(self, root, exclude):
         """Gathers a list of subdirectories excluding specified items."""
         paths = []
         try:
             for p in os.listdir(root):
                 if p not in exclude:
-                    paths.append(os.path.join(root, p).encode('utf-8'))
+                    paths.append(os.path.join(root, p))
         except OSError as e:
             if e.errno != errno.ENOENT:
                 raise
 
         return paths
 
     def delete_dirs(self, root, paths_to_delete):
         """Deletes the given subdirectories in an optimal way."""
--- a/python/mozbuild/mozbuild/gen_test_backend.py
+++ b/python/mozbuild/mozbuild/gen_test_backend.py
@@ -1,14 +1,15 @@
 # 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/.
 
 from __future__ import absolute_import, print_function
 
+import os
 import sys
 
 from mozbuild.backend.test_manifest import TestManifestBackend
 from mozbuild.base import BuildEnvironmentNotFoundException, MozbuildObject
 from mozbuild.frontend.emitter import TreeMetadataEmitter
 from mozbuild.frontend.reader import BuildReader, EmptyConfig
 import mozpack.path as mozpath
 
@@ -17,16 +18,20 @@ def gen_test_backend():
     build_obj = MozbuildObject.from_environment()
     try:
         config = build_obj.config_environment
     except BuildEnvironmentNotFoundException:
         # Create a stub config.status file, since the TestManifest backend needs
         # to be re-created if configure runs. If the file doesn't exist,
         # mozbuild continually thinks the TestManifest backend is out of date
         # and tries to regenerate it.
+
+        if not os.path.isdir(build_obj.topobjdir):
+            os.makedirs(build_obj.topobjdir)
+
         config_status = mozpath.join(build_obj.topobjdir, 'config.status')
         open(config_status, 'w').close()
 
         print("No build detected, test metadata may be incomplete.")
 
         # If 'JS_STANDALONE' is set, tests that don't require an objdir won't
         # be picked up due to bug 1345209.
         substs = EmptyConfig.default_substs
--- a/python/mozbuild/mozbuild/telemetry.py
+++ b/python/mozbuild/mozbuild/telemetry.py
@@ -86,17 +86,17 @@ schema = Schema({
 
 def get_client_id(state_dir):
     '''
     Get a client id, which is a UUID, from a file in the state directory. If the file doesn't
     exist, generate a UUID and save it to a file.
     '''
     path = os.path.join(state_dir, 'telemetry_client_id.json')
     if os.path.exists(path):
-        with open(path, 'rb') as f:
+        with open(path, 'r') as f:
             return json.load(f)['client_id']
     import uuid
     # uuid4 is random, other uuid types may include identifiers from the local system.
     client_id = str(uuid.uuid4())
     with open(path, 'wb') as f:
         json.dump({'client_id': client_id}, f)
     return client_id
 
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-NSS_3_46_BETA2
+NSS_3_46_RTM
--- 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/lib/nss/nss.h
+++ b/security/nss/lib/nss/nss.h
@@ -17,22 +17,22 @@
 
 /*
  * NSS's major version, minor version, patch level, build number, and whether
  * this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
  */
-#define NSS_VERSION "3.46" _NSS_CUSTOMIZED " Beta"
+#define NSS_VERSION "3.46" _NSS_CUSTOMIZED
 #define NSS_VMAJOR 3
 #define NSS_VMINOR 46
 #define NSS_VPATCH 0
 #define NSS_VBUILD 0
-#define NSS_BETA PR_TRUE
+#define NSS_BETA PR_FALSE
 
 #ifndef RC_INVOKED
 
 #include "seccomon.h"
 
 typedef struct NSSInitParametersStr NSSInitParameters;
 
 /*
--- a/security/nss/lib/softoken/softkver.h
+++ b/security/nss/lib/softoken/softkver.h
@@ -12,16 +12,16 @@
 
 /*
  * Softoken's major version, minor version, patch level, build number,
  * and whether this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
  */
-#define SOFTOKEN_VERSION "3.46" SOFTOKEN_ECC_STRING " Beta"
+#define SOFTOKEN_VERSION "3.46" SOFTOKEN_ECC_STRING
 #define SOFTOKEN_VMAJOR 3
 #define SOFTOKEN_VMINOR 46
 #define SOFTOKEN_VPATCH 0
 #define SOFTOKEN_VBUILD 0
-#define SOFTOKEN_BETA PR_TRUE
+#define SOFTOKEN_BETA PR_FALSE
 
 #endif /* _SOFTKVER_H_ */
--- a/security/nss/lib/util/nssutil.h
+++ b/security/nss/lib/util/nssutil.h
@@ -14,22 +14,22 @@
 
 /*
  * NSS utilities's major version, minor version, patch level, build number,
  * and whether this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
  */
-#define NSSUTIL_VERSION "3.46 Beta"
+#define NSSUTIL_VERSION "3.46"
 #define NSSUTIL_VMAJOR 3
 #define NSSUTIL_VMINOR 46
 #define NSSUTIL_VPATCH 0
 #define NSSUTIL_VBUILD 0
-#define NSSUTIL_BETA PR_TRUE
+#define NSSUTIL_BETA PR_FALSE
 
 SEC_BEGIN_PROTOS
 
 /*
  * Returns a const string of the UTIL library version.
  */
 extern const char *NSSUTIL_GetVersion(void);
 
--- a/servo/components/style/invalidation/element/state_and_attributes.rs
+++ b/servo/components/style/invalidation/element/state_and_attributes.rs
@@ -11,17 +11,17 @@ use crate::dom::TElement;
 use crate::element_state::ElementState;
 use crate::invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper};
 use crate::invalidation::element::invalidation_map::*;
 use crate::invalidation::element::invalidator::{DescendantInvalidationLists, InvalidationVector};
 use crate::invalidation::element::invalidator::{Invalidation, InvalidationProcessor};
 use crate::invalidation::element::restyle_hints::RestyleHint;
 use crate::selector_map::SelectorMap;
 use crate::selector_parser::Snapshot;
-use crate::stylesheets::origin::{Origin, OriginSet};
+use crate::stylesheets::origin::OriginSet;
 use crate::{Atom, WeakAtom};
 use selectors::attr::CaseSensitivity;
 use selectors::matching::matches_selector;
 use selectors::matching::{MatchingContext, MatchingMode, VisitedHandlingMode};
 use selectors::NthIndexCache;
 use smallvec::SmallVec;
 
 /// The collector implementation.
@@ -241,17 +241,17 @@ where
                 classes_removed: &classes_removed,
                 classes_added: &classes_added,
                 descendant_invalidations,
                 sibling_invalidations,
                 invalidates_self: false,
             };
 
             let document_origins = if !matches_document_author_rules {
-                Origin::UserAgent.into()
+                OriginSet::ORIGIN_USER_AGENT | OriginSet::ORIGIN_USER
             } else {
                 OriginSet::all()
             };
 
             for (cascade_data, origin) in self.shared_context.stylist.iter_origins() {
                 if document_origins.contains(origin.into()) {
                     collector
                         .collect_dependencies_in_invalidation_map(cascade_data.invalidation_map());
--- a/taskcluster/ci/config.yml
+++ b/taskcluster/ci/config.yml
@@ -131,16 +131,17 @@ treeherder:
         'cpp': 'C/C++ checks'
         'pedantic': 'pedantic checks'
         'text': 'Check on texts'
         'misc': 'Misc checks'
         'js': 'JavaScript checks'
         'py': 'Python checks'
         'java': 'Java checks'
         'SS': 'Shadow scheduler'
+        'test-info': 'Test manifest skip/fail information'
 
 index:
     products:
         - 'firefox'
         - 'fennec'
         - 'mobile'
         - 'static-analysis'
         - 'devedition'
--- a/taskcluster/ci/source-test/file-metadata.yml
+++ b/taskcluster/ci/source-test/file-metadata.yml
@@ -1,33 +1,46 @@
 # 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/.
 ---
 job-defaults:
     platform: lint/opt
     treeherder:
-        kind: test
+        kind: other
         tier: 1
     worker-type: t-linux-xlarge
     worker:
+        artifacts:
+            - type: directory
+              path: /builds/worker/artifacts
+              name: public
         docker-image: {in-tree: "lint"}
         max-run-time: 1800
+    run:
+        using: mach
 
 bugzilla-components:
     description: Generate metadata about source files and Bugzilla
     treeherder:
         symbol: Bugzilla
     index:
         product: source
         job-name: source-bugzilla-info
     run:
-        using: mach
         mach: file-info bugzilla-automation /builds/worker/artifacts
     worker:
-        artifacts:
-            - type: directory
-              path: /builds/worker/artifacts
-              name: public
         max-run-time: 2700
     when:
         files-changed:
-            - '**'
+            - "**"
+
+test-info-fission:
+    description: Generate test manifest metadata for fission
+    treeherder:
+        symbol: test-info(fission)
+        tier: 2
+    index:
+        product: source
+        job-name: test-info-fission
+    run-on-projects: ['mozilla-central']
+    run:
+        mach: test-info report --show-tests --show-summary --filter-keys=fail-if,skip-if --filter-values='(?<!!)fission' --output-file /builds/worker/artifacts/test-info-fission.json
--- a/taskcluster/ci/source-test/mozlint.yml
+++ b/taskcluster/ci/source-test/mozlint.yml
@@ -4,16 +4,17 @@
 ---
 job-defaults:
     always-target: true
     attributes:
         code-review: true
     treeherder:
         kind: test
         tier: 1
+    platform: lint/opt
     worker-type: t-linux-xlarge
     worker:
         docker-image: {in-tree: "lint"}
         max-run-time: 1800
         artifacts:
             - type: file
               name: public/code-review/mozlint.json
               path: /builds/worker/mozlint.json
@@ -26,17 +27,16 @@ job-defaults:
     when:
         files-changed:
             # Other misc lint related files.
             - 'python/mozlint/**'
             - 'tools/lint/**'
 
 codespell:
     description: Checks for misspellings in text files
-    platform: lint/opt
     treeherder:
         symbol: text(spell)
     run:
         mach: lint -l codespell -f treeherder -f json:/builds/worker/mozlint.json
     when:
         files-changed:
             - '**/*.js'
             - '**/*.jsm'
@@ -50,30 +50,28 @@ codespell:
             - '**/*.configure'
             - '**/*.py'
             - '**/*.properties'
             - '**/*.rst'
             - '**/*.ftl'
 
 cpp-virtual-final:
     description: lint C++ virtual function declarations
-    platform: lint/opt
     treeherder:
         symbol: cpp(Cvf)
     run:
         mach: lint -l cpp-virtual-final -f treeherder -f json:/builds/worker/mozlint.json
     when:
         files-changed:
             - '**/*.cpp'
             - '**/*.h'
             - '**/*.mm'
 
 eslint:
     description: JS lint check
-    platform: lint/opt
     treeherder:
         symbol: js(ES)
     run:
         using: run-task
         cwd: '{checkout}'
         command: >
             cp -r /build/node_modules_eslint node_modules &&
             ln -s ../tools/lint/eslint/eslint-plugin-mozilla node_modules &&
@@ -90,135 +88,149 @@ eslint:
             - '**/*.xml'
             # Run when eslint policies change.
             - '**/.eslintignore'
             - '**/*eslintrc*'
             # The plugin implementing custom checks.
             - 'tools/lint/eslint/eslint-plugin-mozilla/**'
             - 'tools/lint/eslint/eslint-plugin-spidermonkey-js/**'
 
+license:
+    description: Check for license blocks in source files.
+    treeherder:
+        symbol: pedantic(license)
+    run:
+        mach: lint -l license -f treeherder -f json:/builds/worker/mozlint.json
+    when:
+        files-changed:
+            - '**/*.c'
+            - '**/*.cc'
+            - '**/*.cpp'
+            - '**/*.h'
+            - '**/*.html'
+            - '**/*.js'
+            - '**/*.jsm'
+            - '**/*.jsx'
+            - '**/*.m'
+            - '**/*.mm'
+            - '**/*.py'
+            - '**/*.rs'
+            - '**/*.xhtml'
+            - '**/*.xml'
+            - '**/*.xul'
+
 mingw-cap:
     description: lint for MinGW Capitalization issues
-    platform: lint/opt
     treeherder:
         symbol: misc(mingw)
     run:
         mach: lint -l mingw-capitalization -f treeherder -f json:/builds/worker/mozlint.json
     when:
         files-changed:
             - '**/*.cpp'
             - '**/*.cc'
             - '**/*.c'
             - '**/*.h'
 
 py-compat:
     description: lint for python 2/3 compatibility issues
-    platform: lint/opt
     treeherder:
         symbol: py(py-compat)
     run:
         mach: lint -l py2 -l py3 -f treeherder -f json:/builds/worker/mozlint.json
     when:
         files-changed:
             - '**/*.py'
             - '**/.flake8'
 
 py-flake8:
     description: flake8 run over the gecko codebase
-    platform: lint/opt
     treeherder:
         symbol: py(f8)
     run:
         mach: lint -l flake8 -f treeherder -f json:/builds/worker/mozlint.json
     when:
         files-changed:
             - '**/*.py'
             - '**/.flake8'
             # moz.configure files are also Python files.
             - '**/*.configure'
 
 test-manifest:
     description: lint test manifests
-    platform: lint/opt
     treeherder:
         symbol: misc(tm)
     run:
         mach: lint -l test-disable -f treeherder -f json:/builds/worker/mozlint.json
     when:
         files-changed:
             - '**/*.ini'
             - 'python/mozlint/**'
             - 'tools/lint/**'
 
 wptlint-gecko:
     description: web-platform-tests linter
-    platform: lint/opt
     treeherder:
         symbol: misc(W)
     run:
         mach: lint -l wpt -f treeherder -f json:/builds/worker/mozlint.json
     when:
         files-changed:
             - 'testing/web-platform/tests/**'
             - 'testing/web-platform/mozilla/tests/**'
 
 yaml:
     description: yamllint run over the gecko codebase
-    platform: lint/opt
     treeherder:
         symbol: pedantic(yaml)
     run:
         mach: lint -l yaml -f treeherder -f json:/builds/worker/mozlint.json
     when:
         files-changed:
             - '**/*.yml'
             - '**/*.yaml'
             - '**/.ymllint'
 
 rst:
     description: rst lint run over the gecko codebase
-    platform: lint/opt
     treeherder:
         symbol: text(rst)
     run:
         mach: lint -l rst -f treeherder -f json:/builds/worker/mozlint.json
     when:
         files-changed:
             - '**/*.rst'
 
 shellcheck:
     description: shellcheck run over the gecko codebase
-    platform: lint/opt
     treeherder:
         symbol: misc(shell)
     run:
         mach: lint -l shellcheck -f treeherder -f json:/builds/worker/mozlint.json
     when:
         files-changed:
             - '**/*.sh'
 
 
 localization:
     description: l10n tests for strings with errors and conflicts with cross-channel
-    platform: lint/opt
     treeherder:
         symbol: text(l1nt)
     run:
         mach: lint -l l10n -f treeherder
     when:
         files-changed:
             - '**/locales/en-US/**'
             - '**/l10n.toml'
             - 'third_party/python/compare-locales/**'
             - 'third_party/python/fluent/**'
 
 
 rustfmt:
     description: rustfmt on the Rust code
-    platform: lint/opt
     treeherder:
         symbol: misc(rustfmt)
     run:
         mach: lint -l rustfmt -f treeherder -f json:/builds/worker/mozlint.json
     when:
         files-changed:
             - '**/*.rs'
 
--- a/testing/mach_commands.py
+++ b/testing/mach_commands.py
@@ -1336,16 +1336,21 @@ class TestInfoCommand(MachCommandBase):
             by_component['summary']['components'] = len(component_set)
             by_component['summary']['manifests'] = manifest_count
             by_component['summary']['tests'] = test_count
             by_component['summary']['failed tests'] = failed_count
             by_component['summary']['skipped tests'] = skipped_count
 
         json_report = json.dumps(by_component, indent=2, sort_keys=True)
         if output_file:
+            output_file = os.path.abspath(output_file)
+            output_dir = os.path.dirname(output_file)
+            if not os.path.isdir(output_dir):
+                os.makedirs(output_dir)
+
             with open(output_file, 'w') as f:
                 f.write(json_report)
         else:
             print(json_report)
 
 
 @CommandProvider
 class RustTests(MachCommandBase):
--- a/testing/web-platform/meta/css/css-box/parsing/margin-computed.html.ini
+++ b/testing/web-platform/meta/css/css-box/parsing/margin-computed.html.ini
@@ -1,15 +1,12 @@
 [margin-computed.html]
   [Property margin value '10px' computes to '10px']
     expected: FAIL
 
-  [Property margin-right value '20px' computes to '20px']
-    expected: FAIL
-
   [Property margin value '30%' computes to '60px']
     expected: FAIL
 
   [Property margin value '10px 20px 30px 40px' computes to '10px 20px 30px 40px']
     expected: FAIL
 
   [Property margin value 'calc(0.5em + 10px)' computes to '30px']
     expected: FAIL
--- a/testing/web-platform/tests/css/css-box/parsing/margin-computed.html
+++ b/testing/web-platform/tests/css/css-box/parsing/margin-computed.html
@@ -18,20 +18,29 @@
   }
 </style>
 </head>
 <body>
 <div id="parent">
   <div id="target"></div>
 </div>
 <script>
+const target = document.getElementById("target");
+
 test_computed_value("margin", "10px");
 test_computed_value("margin", "10px 20px 30px 40px");
 test_computed_value("margin", "calc(0.5em + 10px)", "30px");
 test_computed_value("margin", "30%", "60px");
 
+// Since what should the margin be in presence of other margins is a bit
+// unclear (https://github.com/w3c/csswg-drafts/issues/2328), reset the margin
+// before testing.
+target.style.margin = "0";
 test_computed_value("margin-top", "10px");
+target.style.margin = "0";
 test_computed_value("margin-right", "20px");
+target.style.margin = "0";
 test_computed_value("margin-bottom", "30px");
+target.style.margin = "0";
 test_computed_value("margin-left", "40px");
 </script>
 </body>
 </html>
--- a/third_party/rust/cranelift-codegen-meta/.cargo-checksum.json
+++ b/third_party/rust/cranelift-codegen-meta/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"2ef029c7de319de8f2007c17a7b5baeddd980f37b8cc84197bad5332f6c97d9a","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/cdsl/ast.rs":"1c9bf45110e47710ea160f30b3f3b00b531a8d91ff365bae856dd9d44b928253","src/cdsl/cpu_modes.rs":"7c59ae347d6f9c769d6356fe49c8406934153eefa59d9bf37c182474fcbb9715","src/cdsl/encodings.rs":"da6fa16c95fe4a586c2d00ef4ccf79b4b0f64cd8923b3ca5a5a527da1e799a4f","src/cdsl/formats.rs":"811dcf12f6e9c5be72f18543675ff52c3996edd029064bd0643f878d2ceca3bd","src/cdsl/instructions.rs":"0e702c6d005ce209b46e9f883d02725acbc018bb90f8402c26c71b6bf61a42ed","src/cdsl/isa.rs":"9b6030a935f69b07726d239c23a78d654566785f1fed61ccefdaf7d4f0a97d0e","src/cdsl/mod.rs":"c85f62a7d8d6bedc81c673b8d02be01181f79f272dbc0325a76d52e7eec732e8","src/cdsl/operands.rs":"1cda258798d861c4f467783b5c70c1202a57f554861017eead6477af2ee34063","src/cdsl/recipes.rs":"9f50f29f243f2ed8dbca3ef8b2722e9671bc164b2956254a95ed62641315eab7","src/cdsl/regs.rs":"8a92798a92b2c34c5e572e03602454c72a896d31ac301f15f43d17c101d4da6e","src/cdsl/settings.rs":"7da3c5a9df8e47ed6ca7f1d820e28eae45e783f3759f6c55730d2f17d88f1013","src/cdsl/type_inference.rs":"695d4fd2720f43569a52f29998bd92562951f0b4e7844cc0a239640e0c7d0b0f","src/cdsl/types.rs":"3418eb1f5d77fd3ba586b089c0d77ee45f4e581b1a6e06ec4feeddd9d2589239","src/cdsl/typevar.rs":"c66b14b43baba2e7940b74ada263ab65455c2f46cc06de3990e88d790bb061d0","src/cdsl/xform.rs":"64e9b70ef1265c0331ee9d71c1a1f33dba3f6975b1639385c34d68456cda0e0e","src/constant_hash.rs":"66d6f42c1e98cd4dbc95009997dc00256b57c11d2c2d9eac63b33e458c68a56f","src/default_map.rs":"8bbd6f4d9f93ef2126538cda633e6d9c80a5c7dc79b8d5a759c8be1fe2dbc605","src/error.rs":"5110a4e3c1e97396ba02d9f5abbb8af4b586f0cc4d33a5c2473f1718cc4bef05","src/gen_binemit.rs":"51d661541c6226d2ed8f4724813f66effd6124af9af89c66137a8b55edd950fd","src/gen_encodings.rs":"024b6ea8086fa1559333245753e909f306adeab7c8dfdc915610877413cba585","src/gen_inst.rs":"e3a54b53f4a3d2d98474094d0d662c4ba66c594f876f68562e9ba6ddc2d71226","src/gen_legalizer.rs":"e02c9f49ba9fa2bb04dbf3137011d5457c187fbdffab971b0be01693c4b83a9b","src/gen_registers.rs":"a544a2b91fafe08639e39e50bea0892fda89fe2f6eaf111b2d5f3e98e4d07b86","src/gen_settings.rs":"765ca86fa735342c1875021c34a92cbc39836ba3ad1c12aa615204372a1f7b61","src/gen_types.rs":"c062eaf3a2ed7368b87213922906107bbaec184fe821184a34dacb4e5b0fc3dc","src/isa/arm32/mod.rs":"a2500871fb270e5624f5561f24fe510f08708cdca2ab1c3163848b67694f7a7a","src/isa/arm64/mod.rs":"dc210e8dc9f179d87d2c5a72d7795a9e34bb30afb91c8053c362d43635629d19","src/isa/mod.rs":"fce60d19dd3c099ebee3ac5ae64a2bee363f13da9ff5a4960d3c1a0bee71d29a","src/isa/riscv/encodings.rs":"d53f80b2f166e19945c0c2c89a988a1b26d393f571212a09c5abcd9e694e4857","src/isa/riscv/mod.rs":"895492f0f379cfb02aba1cbb9759dc489bbb4d51ec40759af9f4d71c45c17a86","src/isa/riscv/recipes.rs":"8edffb212f1e5174c3e148a49311f2b7e2a1ac79a5b1ea9b641d4f88aa1c3040","src/isa/x86/encodings.rs":"37ea803b62dc4bcec2b9eee65366aa2f2fb3bfddd220ab926dc691a832b2392a","src/isa/x86/instructions.rs":"eea5fa7dd804d435dfdf289fc47f4bcc77db8dfce068d78d0a428155604b9626","src/isa/x86/legalize.rs":"192d7b9dc61e967165e43bc6da424316868a576b35aad2455c4465733c0d56b8","src/isa/x86/mod.rs":"6ed9f102238c1cb9029ec953e37629767438580cf9df8b4f2d1eace75ecd86fc","src/isa/x86/recipes.rs":"28543b64e2b0476fe84ccedb9bbc0ebec8592ecc756329f6a57197be9d58c0da","src/isa/x86/registers.rs":"c0bc60336a8c8b7b4db92dc623e9419a60af14dd6252f0b19e227e46f7166178","src/isa/x86/settings.rs":"134386d3719d8559a4df1a304c76b350cfaf79877d9894b95630c80e7b72fb50","src/lib.rs":"bc458358fd81d092f368b243d07682259dbed7a336b1eed5bcdf5228368289e9","src/shared/entities.rs":"80b8ff57a09c7b2f9dab755abbcc2738317de474776fe1de0d2a581310aa9af8","src/shared/formats.rs":"ae566a4970d7067165618d2a24a3a46444e21f8a2ac1cff767b2f70420fc2bae","src/shared/immediates.rs":"804c4c9ffa2fe55d90279ee158aaa6bd6c7f0c604d63d7457a98e82269cec9a7","src/shared/instructions.rs":"b2d8dbc2503ec3dfa8101ecddc34126e852b9e397f6ea11e5a5ecf3d8d7d27ae","src/shared/legalize.rs":"1c32c28f603b11f89e1ba9c4d301b0b8036fd81254d227836202b84573a9a446","src/shared/mod.rs":"f5bb50d8292e46380afdd83a320cb5d6021e1483741e67b1e277053c28f9b943","src/shared/settings.rs":"e2696406c7c699e125fc629d6634c75cedf96ca76871fe4e9c0adbe03eead037","src/shared/types.rs":"9d08f21523867acb89d23ce6ac60681babb0a141068c0a54948491df6644a2f3","src/srcgen.rs":"79fee2f603b33f76f7c9c8b9452c745a363d732c40c0814d84001ff3ef805677","src/unique_table.rs":"90b7203b29241a1ede70f0a3e50d96799e0b41d8f7455170d6ffb127f87f3cc3"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"2ef029c7de319de8f2007c17a7b5baeddd980f37b8cc84197bad5332f6c97d9a","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/cdsl/ast.rs":"1c9bf45110e47710ea160f30b3f3b00b531a8d91ff365bae856dd9d44b928253","src/cdsl/cpu_modes.rs":"7c59ae347d6f9c769d6356fe49c8406934153eefa59d9bf37c182474fcbb9715","src/cdsl/encodings.rs":"da6fa16c95fe4a586c2d00ef4ccf79b4b0f64cd8923b3ca5a5a527da1e799a4f","src/cdsl/formats.rs":"811dcf12f6e9c5be72f18543675ff52c3996edd029064bd0643f878d2ceca3bd","src/cdsl/instructions.rs":"0e702c6d005ce209b46e9f883d02725acbc018bb90f8402c26c71b6bf61a42ed","src/cdsl/isa.rs":"9b6030a935f69b07726d239c23a78d654566785f1fed61ccefdaf7d4f0a97d0e","src/cdsl/mod.rs":"c85f62a7d8d6bedc81c673b8d02be01181f79f272dbc0325a76d52e7eec732e8","src/cdsl/operands.rs":"1cda258798d861c4f467783b5c70c1202a57f554861017eead6477af2ee34063","src/cdsl/recipes.rs":"9f50f29f243f2ed8dbca3ef8b2722e9671bc164b2956254a95ed62641315eab7","src/cdsl/regs.rs":"8a92798a92b2c34c5e572e03602454c72a896d31ac301f15f43d17c101d4da6e","src/cdsl/settings.rs":"7da3c5a9df8e47ed6ca7f1d820e28eae45e783f3759f6c55730d2f17d88f1013","src/cdsl/type_inference.rs":"695d4fd2720f43569a52f29998bd92562951f0b4e7844cc0a239640e0c7d0b0f","src/cdsl/types.rs":"3418eb1f5d77fd3ba586b089c0d77ee45f4e581b1a6e06ec4feeddd9d2589239","src/cdsl/typevar.rs":"c66b14b43baba2e7940b74ada263ab65455c2f46cc06de3990e88d790bb061d0","src/cdsl/xform.rs":"64e9b70ef1265c0331ee9d71c1a1f33dba3f6975b1639385c34d68456cda0e0e","src/constant_hash.rs":"66d6f42c1e98cd4dbc95009997dc00256b57c11d2c2d9eac63b33e458c68a56f","src/default_map.rs":"8bbd6f4d9f93ef2126538cda633e6d9c80a5c7dc79b8d5a759c8be1fe2dbc605","src/error.rs":"5110a4e3c1e97396ba02d9f5abbb8af4b586f0cc4d33a5c2473f1718cc4bef05","src/gen_binemit.rs":"80c27e9c66d2ac3dc8a41cc545f046bd4297ba6530805539e86461984fd2667d","src/gen_encodings.rs":"9fb5ebe9a926ad7d45614c3bcfce0f0cadea3477f3e9bea45dfa63baf947e73f","src/gen_inst.rs":"e3a54b53f4a3d2d98474094d0d662c4ba66c594f876f68562e9ba6ddc2d71226","src/gen_legalizer.rs":"e02c9f49ba9fa2bb04dbf3137011d5457c187fbdffab971b0be01693c4b83a9b","src/gen_registers.rs":"a544a2b91fafe08639e39e50bea0892fda89fe2f6eaf111b2d5f3e98e4d07b86","src/gen_settings.rs":"765ca86fa735342c1875021c34a92cbc39836ba3ad1c12aa615204372a1f7b61","src/gen_types.rs":"c062eaf3a2ed7368b87213922906107bbaec184fe821184a34dacb4e5b0fc3dc","src/isa/arm32/mod.rs":"a2500871fb270e5624f5561f24fe510f08708cdca2ab1c3163848b67694f7a7a","src/isa/arm64/mod.rs":"dc210e8dc9f179d87d2c5a72d7795a9e34bb30afb91c8053c362d43635629d19","src/isa/mod.rs":"fce60d19dd3c099ebee3ac5ae64a2bee363f13da9ff5a4960d3c1a0bee71d29a","src/isa/riscv/encodings.rs":"d53f80b2f166e19945c0c2c89a988a1b26d393f571212a09c5abcd9e694e4857","src/isa/riscv/mod.rs":"895492f0f379cfb02aba1cbb9759dc489bbb4d51ec40759af9f4d71c45c17a86","src/isa/riscv/recipes.rs":"8edffb212f1e5174c3e148a49311f2b7e2a1ac79a5b1ea9b641d4f88aa1c3040","src/isa/x86/encodings.rs":"9bdb43f7bb9d639f4cf073e3865a0ad03d98de45b91d637716365dc0c85abbd7","src/isa/x86/instructions.rs":"eea5fa7dd804d435dfdf289fc47f4bcc77db8dfce068d78d0a428155604b9626","src/isa/x86/legalize.rs":"192d7b9dc61e967165e43bc6da424316868a576b35aad2455c4465733c0d56b8","src/isa/x86/mod.rs":"6ed9f102238c1cb9029ec953e37629767438580cf9df8b4f2d1eace75ecd86fc","src/isa/x86/recipes.rs":"e3d6d95bc56c92c83985fd6f20415e04b5da89270ba6069e6d1410bc3c720d7a","src/isa/x86/registers.rs":"c0bc60336a8c8b7b4db92dc623e9419a60af14dd6252f0b19e227e46f7166178","src/isa/x86/settings.rs":"4e84ff135d6f21595bbd8f56d2e561abd3c123566f2332ac93bb4a9c627f0c00","src/lib.rs":"bc458358fd81d092f368b243d07682259dbed7a336b1eed5bcdf5228368289e9","src/shared/entities.rs":"80b8ff57a09c7b2f9dab755abbcc2738317de474776fe1de0d2a581310aa9af8","src/shared/formats.rs":"9c51381b531576c577a92abba9f825a8b60aaaedba53f39d2ea3be879987a466","src/shared/immediates.rs":"9a83d69734d06279bb20050c0f610caf06322d3cb11591cdd0ebf8724274b792","src/shared/instructions.rs":"029791f400bdb0cbdfa9d1ac544063d69c473e2ceecda3ab3e9b483579a53395","src/shared/legalize.rs":"1c32c28f603b11f89e1ba9c4d301b0b8036fd81254d227836202b84573a9a446","src/shared/mod.rs":"f5bb50d8292e46380afdd83a320cb5d6021e1483741e67b1e277053c28f9b943","src/shared/settings.rs":"e2696406c7c699e125fc629d6634c75cedf96ca76871fe4e9c0adbe03eead037","src/shared/types.rs":"9d08f21523867acb89d23ce6ac60681babb0a141068c0a54948491df6644a2f3","src/srcgen.rs":"79fee2f603b33f76f7c9c8b9452c745a363d732c40c0814d84001ff3ef805677","src/unique_table.rs":"90b7203b29241a1ede70f0a3e50d96799e0b41d8f7455170d6ffb127f87f3cc3"},"package":null}
\ No newline at end of file
--- a/third_party/rust/cranelift-codegen-meta/src/gen_binemit.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/gen_binemit.rs
@@ -132,17 +132,17 @@ fn unwrap_values(
                 fmtln!(fmt, "let {} = StackRef::masked(", v);
                 fmt.indent(|fmt| {
                     fmtln!(
                         fmt,
                         "divert.stack({}[{}], &func.locations),",
                         values_slice,
                         i
                     );
-                    fmt.line(format!("{}, ", stack.stack_base_mask()));
+                    fmt.line(format!("{},", stack.stack_base_mask()));
                     fmt.line("&func.stack_slots,");
                 });
                 fmt.line(").unwrap();");
             }
             _ => {}
         }
     }
     varlist
--- a/third_party/rust/cranelift-codegen-meta/src/gen_encodings.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/gen_encodings.rs
@@ -137,16 +137,17 @@ fn emit_instp(instp: &InstructionPredica
 /// Emit private functions for checking recipe predicates as well as a static `RECIPE_PREDICATES`
 /// array indexed by recipe number.
 ///
 /// A recipe predicate is a combination of an ISA predicate and an instruction predicate. Many
 /// recipes have identical predicates.
 fn emit_recipe_predicates(isa: &TargetIsa, fmt: &mut Formatter) {
     let mut predicate_names = HashMap::new();
 
+    fmt.comment(format!("{} recipe predicates.", isa.name));
     for recipe in isa.recipes.values() {
         let (isap, instp) = match (&recipe.isa_predicate, &recipe.inst_predicate) {
             (None, None) => continue,
             (isap, instp) if predicate_names.contains_key(&(isap, instp)) => continue,
             (isap, instp) => (isap, instp),
         };
 
         let func_name = format!("recipe_predicate_{}", recipe.name.to_lowercase());
@@ -172,74 +173,98 @@ fn emit_recipe_predicates(isa: &TargetIs
                     fmtln!(fmt, "isap.test({}) &&", isap);
                     emit_instp(instp, /* has func */ false, fmt);
                 }
                 _ => panic!("skipped above"),
             }
         });
         fmtln!(fmt, "}");
     }
+    fmt.empty_line();
 
     // Generate the static table.
+    fmt.doc_comment(format!(
+        r#"{} recipe predicate table.
+
+        One entry per recipe, set to Some only when the recipe is guarded by a predicate."#,
+        isa.name
+    ));
     fmtln!(
         fmt,
         "pub static RECIPE_PREDICATES: [RecipePredicate; {}] = [",
         isa.recipes.len()
     );
     fmt.indent(|fmt| {
         for recipe in isa.recipes.values() {
             match (&recipe.isa_predicate, &recipe.inst_predicate) {
                 (None, None) => fmt.line("None,"),
                 key => fmtln!(fmt, "Some({}),", predicate_names.get(&key).unwrap()),
             }
         }
     });
     fmtln!(fmt, "];");
+    fmt.empty_line();
 }
 
 /// Emit private functions for matching instruction predicates as well as a static
 /// `INST_PREDICATES` array indexed by predicate number.
 fn emit_inst_predicates(isa: &TargetIsa, fmt: &mut Formatter) {
+    fmt.comment(format!("{} instruction predicates.", isa.name));
     for (id, instp) in isa.encodings_predicates.iter() {
         fmtln!(fmt, "fn inst_predicate_{}(func: &crate::ir::Function, inst: &crate::ir::InstructionData) -> bool {{", id.index());
         fmt.indent(|fmt| {
             emit_instp(instp, /* has func */ true, fmt);
         });
         fmtln!(fmt, "}");
     }
+    fmt.empty_line();
 
     // Generate the static table.
+    fmt.doc_comment(format!(
+        r#"{} instruction predicate table.
+
+        One entry per instruction predicate, so the encoding bytecode can embed indexes into this
+        table."#,
+        isa.name
+    ));
     fmtln!(
         fmt,
         "pub static INST_PREDICATES: [InstPredicate; {}] = [",
         isa.encodings_predicates.len()
     );
     fmt.indent(|fmt| {
         for id in isa.encodings_predicates.keys() {
             fmtln!(fmt, "inst_predicate_{},", id.index());
         }
     });
     fmtln!(fmt, "];");
+    fmt.empty_line();
 }
 
 /// Emit a table of encoding recipe names keyed by recipe number.
 ///
 /// This is used for pretty-printing encodings.
 fn emit_recipe_names(isa: &TargetIsa, fmt: &mut Formatter) {
+    fmt.doc_comment(format!(
+        r#"{} recipe names, using the same recipe index spaces as the one specified by the
+        corresponding binemit file."#,
+        isa.name
+    ));
     fmtln!(
         fmt,
         "static RECIPE_NAMES: [&str; {}] = [",
         isa.recipes.len()
     );
     fmt.indent(|fmt| {
         for recipe in isa.recipes.values() {
             fmtln!(fmt, r#""{}","#, recipe.name);
         }
     });
     fmtln!(fmt, "];");
+    fmt.empty_line();
 }
 
 /// Returns a set of all the registers involved in fixed register constraints.
 fn get_fixed_registers(operands_in: &Vec<OperandConstraint>) -> HashSet<Register> {
     HashSet::from_iter(
         operands_in
             .iter()
             .map(|constraint| {
@@ -348,16 +373,22 @@ fn emit_operand_constraints(
     });
     fmtln!(fmt, "],");
 }
 
 /// Emit a table of encoding recipe operand constraints keyed by recipe number.
 ///
 /// These are used by the register allocator to pick registers that can be properly encoded.
 fn emit_recipe_constraints(isa: &TargetIsa, fmt: &mut Formatter) {
+    fmt.doc_comment(format!(
+        r#"{} recipe constraints list, using the same recipe index spaces as the one
+        specified by the corresponding binemit file. These constraints are used by register
+        allocation to select the right location to use for input and output values."#,
+        isa.name
+    ));
     fmtln!(
         fmt,
         "static RECIPE_CONSTRAINTS: [RecipeConstraints; {}] = [",
         isa.recipes.len()
     );
     fmt.indent(|fmt| {
         for recipe in isa.recipes.values() {
             // Compute a mapping of tied operands in both directions (input tied to outputs and
@@ -432,20 +463,27 @@ fn emit_recipe_constraints(isa: &TargetI
                         "false"
                     }
                 );
             });
             fmt.line("},");
         }
     });
     fmtln!(fmt, "];");
+    fmt.empty_line();
 }
 
 /// Emit a table of encoding recipe code size information.
 fn emit_recipe_sizing(isa: &TargetIsa, fmt: &mut Formatter) {
+    fmt.doc_comment(format!(
+        r#"{} recipe sizing descriptors, using the same recipe index spaces as the one
+        specified by the corresponding binemit file. These are used to compute the final size of an
+        instruction, as well as to compute the range of branches."#,
+        isa.name
+    ));
     fmtln!(
         fmt,
         "static RECIPE_SIZING: [RecipeSizing; {}] = [",
         isa.recipes.len()
     );
     fmt.indent(|fmt| {
         for recipe in isa.recipes.values() {
             fmt.comment(format!("Code size information for recipe {}:", recipe.name));
@@ -463,16 +501,17 @@ fn emit_recipe_sizing(isa: &TargetIsa, f
                 } else {
                     fmt.line("branch_range: None,");
                 }
             });
             fmt.line("},");
         }
     });
     fmtln!(fmt, "];");
+    fmt.empty_line();
 }
 
 /// Level 1 table mapping types to `Level2` objects.
 struct Level1Table<'cpu_mode> {
     cpu_mode: &'cpu_mode CpuMode,
     legalize_code: TransformGroupIndex,
 
     table_map: HashMap<Option<ValueType>, usize>,
@@ -873,17 +912,17 @@ fn encode_level2_hashtables<'a>(
     level2_hashtables: &mut Vec<Option<Level2HashTableEntry>>,
     level2_doc: &mut HashMap<usize, Vec<String>>,
 ) {
     for level2 in level1.l2tables() {
         level2.layout_hashtable(level2_hashtables, level2_doc);
     }
 }
 
-fn emit_tables(defs: &SharedDefinitions, isa: &TargetIsa, fmt: &mut Formatter) {
+fn emit_encoding_tables(defs: &SharedDefinitions, isa: &TargetIsa, fmt: &mut Formatter) {
     // Level 1 tables, one per CPU mode.
     let mut level1_tables: HashMap<&'static str, Level1Table> = HashMap::new();
 
     // Single table containing all the level2 hash tables.
     let mut level2_hashtables = Vec::new();
     let mut level2_doc: HashMap<usize, Vec<String>> = HashMap::new();
 
     // Tables for encoding lists with comments.
@@ -918,16 +957,23 @@ fn emit_tables(defs: &SharedDefinitions,
             "u32"
         }
     };
 
     let level1_offset_type = offset_type(level2_hashtables.len());
     let level2_offset_type = offset_type(enc_lists.len());
 
     // Emit encoding lists.
+    fmt.doc_comment(
+        format!(r#"{} encoding lists.
+
+        This contains the entire encodings bytecode for every single instruction; the encodings
+        interpreter knows where to start from thanks to the initial lookup in the level 1 and level 2
+        table entries below."#, isa.name)
+    );
     fmtln!(fmt, "pub static ENCLISTS: [u16; {}] = [", enc_lists.len());
     fmt.indent(|fmt| {
         let mut line = Vec::new();
         for (index, entry) in enc_lists.iter().enumerate() {
             if let Some(comments) = enc_lists_doc.get(&index) {
                 if !line.is_empty() {
                     fmtln!(fmt, "{},", line.join(", "));
                     line.clear();
@@ -938,18 +984,27 @@ fn emit_tables(defs: &SharedDefinitions,
             }
             line.push(format!("{:#06x}", entry));
         }
         if !line.is_empty() {
             fmtln!(fmt, "{},", line.join(", "));
         }
     });
     fmtln!(fmt, "];");
+    fmt.empty_line();
 
     // Emit the full concatenation of level 2 hash tables.
+    fmt.doc_comment(format!(
+        r#"{} level 2 hash tables.
+
+        This hash table, keyed by instruction opcode, contains all the starting offsets for the
+        encodings interpreter, for all the CPU modes. It is jumped to after a lookup on the
+        instruction's controlling type in the level 1 hash table."#,
+        isa.name
+    ));
     fmtln!(
         fmt,
         "pub static LEVEL2: [Level2Entry<{}>; {}] = [",
         level2_offset_type,
         level2_hashtables.len()
     );
     fmt.indent(|fmt| {
         for (offset, entry) in level2_hashtables.iter().enumerate() {
@@ -966,32 +1021,43 @@ fn emit_tables(defs: &SharedDefinitions,
                     entry.offset
                 );
             } else {
                 fmt.line("Level2Entry { opcode: None, offset: 0 },");
             }
         }
     });
     fmtln!(fmt, "];");
+    fmt.empty_line();
 
     // Emit a level 1 hash table for each CPU mode.
     for cpu_mode in &isa.cpu_modes {
         let level1 = &level1_tables.get(cpu_mode.name).unwrap();
         let hash_table = generate_table(
             level1.table_vec.iter(),
             level1.table_vec.len(),
             |level2_table| {
                 if let Some(typ) = &level2_table.typ {
                     typ.number().expect("type without a number") as usize
                 } else {
                     0
                 }
             },
         );
 
+        fmt.doc_comment(format!(
+            r#"{} level 1 hash table for the CPU mode {}.
+
+            This hash table, keyed by instruction controlling type, contains all the level 2
+            hash-tables offsets for the given CPU mode, as well as a legalization identifier indicating
+            which legalization scheme to apply when the instruction doesn't have any valid encoding for
+            this CPU mode.
+        "#,
+            isa.name, cpu_mode.name
+        ));
         fmtln!(
             fmt,
             "pub static LEVEL1_{}: [Level1Entry<{}>; {}] = [",
             cpu_mode.name.to_uppercase(),
             level1_offset_type,
             hash_table.len()
         );
         fmt.indent(|fmt| {
@@ -1028,27 +1094,28 @@ fn emit_tables(defs: &SharedDefinitions,
                 // Proper level 2 hash table.
                 let l2l = (level2.hash_table_len.unwrap() as f64).log2() as i32;
                 assert!(l2l > 0, "Level2 hash table was too small.");
                 fmtln!(fmt, "Level1Entry {{ ty: {}, log2len: {}, offset: {:#08x}, legalize: {} }}, // {}",
                        typ_name, l2l, level2.hash_table_offset.unwrap(), legalize_code, legalize_comment);
             }
         });
         fmtln!(fmt, "];");
+        fmt.empty_line();
     }
 }
 
 fn gen_isa(defs: &SharedDefinitions, isa: &TargetIsa, fmt: &mut Formatter) {
     // Make the `RECIPE_PREDICATES` table.
     emit_recipe_predicates(isa, fmt);
 
     // Make the `INST_PREDICATES` table.
     emit_inst_predicates(isa, fmt);
 
-    emit_tables(defs, isa, fmt);
+    emit_encoding_tables(defs, isa, fmt);
 
     emit_recipe_names(isa, fmt);
     emit_recipe_constraints(isa, fmt);
     emit_recipe_sizing(isa, fmt);
 
     // Finally, tie it all together in an `EncInfo`.
     fmt.line("pub static INFO: isa::EncInfo = isa::EncInfo {");
     fmt.indent(|fmt| {
--- a/third_party/rust/cranelift-codegen-meta/src/isa/x86/encodings.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/isa/x86/encodings.rs
@@ -265,39 +265,39 @@ impl PerCpuModeEncodings {
             self.enc64(inst.clone().bind(I64).bind_any(), template.clone().rex());
             self.enc64(inst.clone().bind(I64).bind_any(), template);
         }
     }
 
     /// Add the same encoding to both X86_32 and X86_64; assumes configuration (e.g. REX, operand binding) has already happened
     fn enc_32_64_maybe_isap(
         &mut self,
-        inst: BoundInstruction,
+        inst: impl Clone + Into<InstSpec>,
         template: Template,
         isap: Option<SettingPredicateNumber>,
     ) {
         self.enc32_maybe_isap(inst.clone(), template.clone(), isap);
         self.enc64_maybe_isap(inst, template, isap);
     }
 
     fn enc32_maybe_isap(
         &mut self,
-        inst: BoundInstruction,
+        inst: impl Into<InstSpec>,
         template: Template,
         isap: Option<SettingPredicateNumber>,
     ) {
         match isap {
             None => self.enc32(inst, template),
             Some(isap) => self.enc32_isap(inst, template, isap),
         }
     }
 
     fn enc64_maybe_isap(
         &mut self,
-        inst: BoundInstruction,
+        inst: impl Into<InstSpec>,
         template: Template,
         isap: Option<SettingPredicateNumber>,
     ) {
         match isap {
             None => self.enc64(inst, template),
             Some(isap) => self.enc64_isap(inst, template, isap),
         }
     }
@@ -427,16 +427,17 @@ pub fn define(
     let uload16 = shared.by_name("uload16");
     let uload16_complex = shared.by_name("uload16_complex");
     let uload32 = shared.by_name("uload32");
     let uload32_complex = shared.by_name("uload32_complex");
     let uload8 = shared.by_name("uload8");
     let uload8_complex = shared.by_name("uload8_complex");
     let ushr = shared.by_name("ushr");
     let ushr_imm = shared.by_name("ushr_imm");
+    let vconst = shared.by_name("vconst");
     let x86_bsf = x86.by_name("x86_bsf");
     let x86_bsr = x86.by_name("x86_bsr");
     let x86_cvtt2si = x86.by_name("x86_cvtt2si");
     let x86_fmax = x86.by_name("x86_fmax");
     let x86_fmin = x86.by_name("x86_fmin");
     let x86_pop = x86.by_name("x86_pop");
     let x86_pshufd = x86.by_name("x86_pshufd");
     let x86_pshufb = x86.by_name("x86_pshufb");
@@ -573,29 +574,31 @@ pub fn define(
     let rec_trapff = r.recipe("trapff");
     let rec_u_id = r.template("u_id");
     let rec_umr = r.template("umr");
     let rec_umr_reg_to_ssa = r.template("umr_reg_to_ssa");
     let rec_ur = r.template("ur");
     let rec_urm = r.template("urm");
     let rec_urm_noflags = r.template("urm_noflags");
     let rec_urm_noflags_abcd = r.template("urm_noflags_abcd");
+    let rec_vconst = r.template("vconst");
 
     // Predicates shorthands.
     let all_ones_funcaddrs_and_not_is_pic =
         settings.predicate_by_name("all_ones_funcaddrs_and_not_is_pic");
     let is_pic = settings.predicate_by_name("is_pic");
     let not_all_ones_funcaddrs_and_not_is_pic =
         settings.predicate_by_name("not_all_ones_funcaddrs_and_not_is_pic");
     let not_is_pic = settings.predicate_by_name("not_is_pic");
     let use_popcnt = settings.predicate_by_name("use_popcnt");
     let use_lzcnt = settings.predicate_by_name("use_lzcnt");
     let use_bmi1 = settings.predicate_by_name("use_bmi1");
-    let use_ssse3 = settings.predicate_by_name("use_ssse3");
     let use_sse41 = settings.predicate_by_name("use_sse41");
+    let use_ssse3_simd = settings.predicate_by_name("use_ssse3_simd");
+    let use_sse41_simd = settings.predicate_by_name("use_sse41_simd");
 
     // Definitions.
     let mut e = PerCpuModeEncodings::new();
 
     e.enc_i32_i64(iadd, rec_rr.opcodes(vec![0x01]));
     e.enc_i32_i64(isub, rec_rr.opcodes(vec![0x29]));
     e.enc_i32_i64(band, rec_rr.opcodes(vec![0x21]));
     e.enc_i32_i64(bor, rec_rr.opcodes(vec![0x09]));
@@ -1689,18 +1692,18 @@ pub fn define(
     // SIMD splat: before x86 can use vector data, it must be moved to XMM registers; see
     // legalize.rs for how this is done; once there, x86_pshuf* (below) is used for broadcasting the
     // value across the register
 
     // PSHUFB, 8-bit shuffle using two XMM registers
     for ty in ValueType::all_lane_types().filter(|t| t.lane_bits() == 8) {
         let instruction = x86_pshufb.bind_vector_from_lane(ty, sse_vector_size);
         let template = rec_fa.nonrex().opcodes(vec![0x66, 0x0f, 0x38, 00]);
-        e.enc32_isap(instruction.clone(), template.clone(), use_ssse3);
-        e.enc64_isap(instruction, template, use_ssse3);
+        e.enc32_isap(instruction.clone(), template.clone(), use_ssse3_simd);
+        e.enc64_isap(instruction, template, use_ssse3_simd);
     }
 
     // PSHUFD, 32-bit shuffle using one XMM register and a u8 immediate
     for ty in ValueType::all_lane_types().filter(|t| t.lane_bits() == 32) {
         let instruction = x86_pshufd.bind_vector_from_lane(ty, sse_vector_size);
         let template = rec_r_ib_unsigned_fpr
             .nonrex()
             .opcodes(vec![0x66, 0x0f, 0x70]);
@@ -1721,20 +1724,20 @@ pub fn define(
             e.enc32(instruction.clone(), template.clone());
         }
         e.enc_x86_64(instruction, template);
     }
 
     // SIMD insertlane
     let mut insertlane_mapping: HashMap<u64, (Vec<u8>, Option<SettingPredicateNumber>)> =
         HashMap::new();
-    insertlane_mapping.insert(8, (vec![0x66, 0x0f, 0x3a, 0x20], Some(use_sse41))); // PINSRB
+    insertlane_mapping.insert(8, (vec![0x66, 0x0f, 0x3a, 0x20], Some(use_sse41_simd))); // PINSRB
     insertlane_mapping.insert(16, (vec![0x66, 0x0f, 0xc4], None)); // PINSRW from SSE2
-    insertlane_mapping.insert(32, (vec![0x66, 0x0f, 0x3a, 0x22], Some(use_sse41))); // PINSRD
-    insertlane_mapping.insert(64, (vec![0x66, 0x0f, 0x3a, 0x22], Some(use_sse41))); // PINSRQ, only x86_64
+    insertlane_mapping.insert(32, (vec![0x66, 0x0f, 0x3a, 0x22], Some(use_sse41_simd))); // PINSRD
+    insertlane_mapping.insert(64, (vec![0x66, 0x0f, 0x3a, 0x22], Some(use_sse41_simd))); // PINSRQ, only x86_64
 
     for ty in ValueType::all_lane_types() {
         if let Some((opcode, isap)) = insertlane_mapping.get(&ty.lane_bits()) {
             let instruction = insertlane.bind_vector_from_lane(ty, sse_vector_size);
             let template = rec_r_ib_unsigned_r.opcodes(opcode.clone());
             if ty.lane_bits() < 64 {
                 e.enc_32_64_maybe_isap(instruction, template.nonrex(), isap.clone());
             } else {
@@ -1742,20 +1745,20 @@ pub fn define(
                 e.enc64_maybe_isap(instruction, template.rex().w(), isap.clone());
             }
         }
     }
 
     // SIMD extractlane
     let mut extractlane_mapping: HashMap<u64, (Vec<u8>, Option<SettingPredicateNumber>)> =
         HashMap::new();
-    extractlane_mapping.insert(8, (vec![0x66, 0x0f, 0x3a, 0x14], Some(use_sse41))); // PEXTRB
+    extractlane_mapping.insert(8, (vec![0x66, 0x0f, 0x3a, 0x14], Some(use_sse41_simd))); // PEXTRB
     extractlane_mapping.insert(16, (vec![0x66, 0x0f, 0xc5], None)); // PEXTRW from zSSE2, SSE4.1 has a PEXTRW that can move to reg/m16 but the opcode is four bytes
-    extractlane_mapping.insert(32, (vec![0x66, 0x0f, 0x3a, 0x16], Some(use_sse41))); // PEXTRD
-    extractlane_mapping.insert(64, (vec![0x66, 0x0f, 0x3a, 0x16], Some(use_sse41))); // PEXTRQ, only x86_64
+    extractlane_mapping.insert(32, (vec![0x66, 0x0f, 0x3a, 0x16], Some(use_sse41_simd))); // PEXTRD
+    extractlane_mapping.insert(64, (vec![0x66, 0x0f, 0x3a, 0x16], Some(use_sse41_simd))); // PEXTRQ, only x86_64
 
     for ty in ValueType::all_lane_types() {
         if let Some((opcode, isap)) = extractlane_mapping.get(&ty.lane_bits()) {
             let instruction = extractlane.bind_vector_from_lane(ty, sse_vector_size);
             let template = rec_r_ib_unsigned_gpr.opcodes(opcode.clone());
             if ty.lane_bits() < 64 {
                 e.enc_32_64_maybe_isap(instruction, template.nonrex(), isap.clone());
             } else {
@@ -1779,16 +1782,28 @@ pub fn define(
             let instruction = raw_bitcast
                 .bind_vector_from_lane(to_type, sse_vector_size)
                 .bind_vector_from_lane(from_type, sse_vector_size);
             e.enc32_rec(instruction.clone(), rec_null_fpr, 0);
             e.enc64_rec(instruction, rec_null_fpr, 0);
         }
     }
 
+    // SIMD vconst using MOVUPS
+    // TODO it would be ideal if eventually this became the more efficient MOVAPS but we would have
+    // to guarantee that the constants are aligned when emitted and there is currently no mechanism
+    // for that; alternately, constants could be loaded into XMM registers using a sequence like:
+    // MOVQ + MOVHPD + MOVQ + MOVLPD (this allows the constants to be immediates instead of stored
+    // in memory) but some performance measurements are needed.
+    for ty in ValueType::all_lane_types().filter(|t| t.lane_bits() >= 8) {
+        let instruction = vconst.bind_vector_from_lane(ty, sse_vector_size);
+        let template = rec_vconst.nonrex().opcodes(vec![0x0f, 0x10]);
+        e.enc_32_64_maybe_isap(instruction, template, None); // from SSE
+    }
+
     // Reference type instructions
 
     // Null references implemented as iconst 0.
     e.enc32(null.bind_ref(R32), rec_pu_id_ref.opcodes(vec![0xb8]));
 
     e.enc64(null.bind_ref(R64), rec_pu_id_ref.rex().opcodes(vec![0xb8]));
     e.enc64(null.bind_ref(R64), rec_pu_id_ref.opcodes(vec![0xb8]));
 
--- a/third_party/rust/cranelift-codegen-meta/src/isa/x86/recipes.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/isa/x86/recipes.rs
@@ -394,16 +394,17 @@ pub fn define<'shared>(
     let f_ternary = formats.by_name("Ternary");
     let f_trap = formats.by_name("Trap");
     let f_unary = formats.by_name("Unary");
     let f_unary_bool = formats.by_name("UnaryBool");
     let f_unary_global_value = formats.by_name("UnaryGlobalValue");
     let f_unary_ieee32 = formats.by_name("UnaryIeee32");
     let f_unary_ieee64 = formats.by_name("UnaryIeee64");
     let f_unary_imm = formats.by_name("UnaryImm");
+    let f_unary_imm128 = formats.by_name("UnaryImm128");
 
     // Predicates shorthands.
     let use_sse41 = settings.predicate_by_name("use_sse41");
 
     // Definitions.
     let mut recipes = RecipeGroup::new(formats, regs);
 
     // A null unary instruction that takes a GPR register. Can be used for identity copies and
@@ -2378,16 +2379,29 @@ pub fn define<'shared>(
                         modrm_sib(out_reg0, sink);
                         sib(imm.trailing_zeros() as u8, in_reg0, in_reg1, sink);
                     }
                 "#,
             ),
     );
 
     recipes.add_template_recipe(
+        EncodingRecipeBuilder::new("vconst", f_unary_imm128, 5)
+            .operands_out(vec![fpr])
+            .clobbers_flags(false)
+            .emit(
+                r#"
+                    {{PUT_OP}}(bits, rex2(0, out_reg0), sink);
+                    modrm_riprel(out_reg0, sink);
+                    const_disp4(imm, func, sink);
+                "#,
+            ),
+    );
+
+    recipes.add_template_recipe(
         EncodingRecipeBuilder::new("jt_base", f_branch_table_base, 5)
             .operands_out(vec![gpr])
             .clobbers_flags(false)
             .emit(
                 r#"
                     {{PUT_OP}}(bits, rex2(0, out_reg0), sink);
                     modrm_riprel(out_reg0, sink);
 
--- a/third_party/rust/cranelift-codegen-meta/src/isa/x86/settings.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/isa/x86/settings.rs
@@ -27,22 +27,33 @@ pub fn define(shared: &SettingGroup) -> 
     let has_lzcnt = settings.add_bool(
         "has_lzcnt",
         "LZCNT: CPUID.EAX=80000001H:ECX.LZCNT[bit 5]",
         false,
     );
 
     let shared_enable_simd = shared.get_bool("enable_simd");
 
-    settings.add_predicate("use_ssse3", predicate!(shared_enable_simd && has_ssse3));
-    settings.add_predicate("use_sse41", predicate!(shared_enable_simd && has_sse41));
+    settings.add_predicate("use_ssse3", predicate!(has_ssse3));
+    settings.add_predicate("use_sse41", predicate!(has_sse41));
+    settings.add_predicate("use_sse42", predicate!(has_sse41 && has_sse42));
+
     settings.add_predicate(
-        "use_sse42",
+        "use_ssse3_simd",
+        predicate!(shared_enable_simd && has_ssse3),
+    );
+    settings.add_predicate(
+        "use_sse41_simd",
+        predicate!(shared_enable_simd && has_sse41),
+    );
+    settings.add_predicate(
+        "use_sse42_simd",
         predicate!(shared_enable_simd && has_sse41 && has_sse42),
     );
+
     settings.add_predicate("use_popcnt", predicate!(has_popcnt && has_sse42));
     settings.add_predicate("use_bmi1", predicate!(has_bmi1));
     settings.add_predicate("use_lzcnt", predicate!(has_lzcnt));
 
     // Some shared boolean values are used in x86 instruction predicates, so we need to group them
     // in the same TargetIsa, for compabitibity with code generated by meta-python.
     // TODO Once all the meta generation code has been migrated from Python to Rust, we can put it
     // back in the shared SettingGroup, and use it in x86 instruction predicates.
--- a/third_party/rust/cranelift-codegen-meta/src/shared/formats.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/shared/formats.rs
@@ -1,15 +1,16 @@
 use crate::cdsl::formats::{FormatRegistry, InstructionFormatBuilder as Builder};
 use crate::shared::OperandKinds;
 
 pub fn define(immediates: &OperandKinds, entities: &OperandKinds) -> FormatRegistry {
     // Shorthands for immediates.
     let uimm8 = immediates.by_name("uimm8");
     let uimm32 = immediates.by_name("uimm32");
+    let uimm128 = immediates.by_name("uimm128");
     let imm64 = immediates.by_name("imm64");
     let ieee32 = immediates.by_name("ieee32");
     let ieee64 = immediates.by_name("ieee64");
     let boolean = immediates.by_name("boolean");
     let intcc = immediates.by_name("intcc");
     let floatcc = immediates.by_name("floatcc");
     let memflags = immediates.by_name("memflags");
     let offset32 = immediates.by_name("offset32");
@@ -25,16 +26,17 @@ pub fn define(immediates: &OperandKinds,
     let stack_slot = entities.by_name("stack_slot");
     let heap = entities.by_name("heap");
     let table = entities.by_name("table");
 
     let mut registry = FormatRegistry::new();
 
     registry.insert(Builder::new("Unary").value());
     registry.insert(Builder::new("UnaryImm").imm(imm64));
+    registry.insert(Builder::new("UnaryImm128").imm(uimm128));
     registry.insert(Builder::new("UnaryIeee32").imm(ieee32));
     registry.insert(Builder::new("UnaryIeee64").imm(ieee64));
     registry.insert(Builder::new("UnaryBool").imm(boolean));
     registry.insert(Builder::new("UnaryGlobalValue").imm(global_value));
 
     registry.insert(Builder::new("Binary").value().value());
     registry.insert(Builder::new("BinaryImm").value().imm(imm64));
 
--- a/third_party/rust/cranelift-codegen-meta/src/shared/immediates.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/shared/immediates.rs
@@ -24,16 +24,26 @@ pub fn define() -> Vec<OperandKind> {
     kinds.push(uimm8);
 
     // An unsigned 32-bit immediate integer operand.
     let uimm32 = Builder::new_imm("uimm32")
         .doc("A 32-bit immediate unsigned integer.")
         .build();
     kinds.push(uimm32);
 
+    // An unsigned 128-bit immediate integer operand.
+    //
+    // This operand is used to pass entire 128-bit vectors as immediates to
+    // instructions like const.
+    let uimm128 = Builder::new_imm("uimm128")
+        .doc("A 128-bit immediate unsigned integer.")
+        .rust_type("ir::Constant")
+        .build();
+    kinds.push(uimm128);
+
     // A 32-bit immediate signed offset.
     //
     // This is used to represent an immediate address offset in load/store
     // instructions.
     let offset32 = Builder::new_imm("offset32")
         .doc("A 32-bit immediate signed offset.")
         .default_member("offset")
         .build();
--- a/third_party/rust/cranelift-codegen-meta/src/shared/instructions.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/shared/instructions.rs
@@ -25,16 +25,17 @@ pub fn define(
 
     // Operand kind shorthands.
     let intcc = immediates.by_name("intcc");
     let floatcc = immediates.by_name("floatcc");
     let trapcode = immediates.by_name("trapcode");
     let uimm8 = immediates.by_name("uimm8");
     let uimm32 = immediates.by_name("uimm32");
     let imm64 = immediates.by_name("imm64");
+    let uimm128 = immediates.by_name("uimm128");
     let offset32 = immediates.by_name("offset32");
     let memflags = immediates.by_name("memflags");
     let ieee32 = immediates.by_name("ieee32");
     let ieee64 = immediates.by_name("ieee64");
     let boolean = immediates.by_name("boolean");
     let regunit = immediates.by_name("regunit");
 
     let ebb = entities.by_name("ebb");
@@ -1083,16 +1084,32 @@ pub fn define(
         Create a scalar boolean SSA value with an immediate constant value, or
         a boolean vector where all the lanes have the same value.
         "#,
         )
         .operands_in(vec![N])
         .operands_out(vec![a]),
     );
 
+    let N = &operand_doc("N", uimm128, "The 16 immediate bytes of a 128-bit vector");
+    let a = &operand_doc("a", TxN, "A constant vector value");
+
+    ig.push(
+        Inst::new(
+            "vconst",
+            r#"
+        SIMD vector constant.
+
+        Construct a vector with the given immediate bytes.
+        "#,
+        )
+        .operands_in(vec![N])
+        .operands_out(vec![a]),
+    );
+
     let a = &operand_doc("a", Ref, "A constant reference null value");
 
     ig.push(
         Inst::new(
             "null",
             r#"
         Null constant value for reference types.
 
--- a/third_party/rust/cranelift-codegen/.cargo-checksum.json
+++ b/third_party/rust/cranelift-codegen/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"f797893f65d711c9e0df429ec0b85816c3526e87f0d6baa3300bc5d667f36d20","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"e5127227a7db4a8aa92fa6613ed71801025790e696bb41b0323fb7f3c6f7495a","build.rs":"8587e8557a046dc858f7662f63f1fa54e57ff92ed87b30fbcdfce6feafda9d60","src/abi.rs":"76ee030cf0780fe63ccbf855b1161f215e3e2991cb9abe71ca9aff25e5f1dbc2","src/binemit/memorysink.rs":"bf90f397b4c696e2fc49f27f866fe267727c2c8950dffbc8aac6f4a09bafbf20","src/binemit/mod.rs":"498f84442badcc753b0cae2f8153a3ba93d35a3af8d397c2dd183780f13bf42d","src/binemit/relaxation.rs":"3fbd14c98807e23da337bf1e658e077ab2e6aca585b663ab041a6fe1a0875cec","src/binemit/shrink.rs":"79a2dcca2633c8449d49bf7cfb1e2fe14b46753a4d52ef412078c53d7742fe86","src/binemit/stackmap.rs":"da3187d96d21b14927279061ccaba4c880d0ad7169b83bd32c1381d45a39af70","src/bitset.rs":"d57a79058a31b094b4bbe9d34876a5543286df1e08b5ceadfd05a9efc5a3b1ce","src/cfg_printer.rs":"a84dee96d8c6f4775b8ba022243cf1c0bcf847c6d7ec532698cfd331655aa453","src/constant_hash.rs":"77eb898f7b0a4ae3b8165a03c25fcd23ce9c1d0cd32c793fa6cb31666ce27eb1","src/context.rs":"ee09647590a7a583c37df398fe3eb51dca034a5aca4e164288c9f7ed2b30274e","src/cursor.rs":"874d1c7ef6e114d6ae47e0a1f92da7c5cec2e555597558042a3b214da7bc5fe4","src/dbg.rs":"1898d94cff0975815eb348651702e95c8f2f63886501d3b7043ee75668480472","src/dce.rs":"d8ab7c0cac0416f9d75afdacc60ba02e532361ec927c3f8bd171b1a53ec8b31a","src/divconst_magic_numbers.rs":"09691389c9055bef7a0cfd5d77fbfeba4be468d05d981d4de088516a94b8b28e","src/dominator_tree.rs":"7ee4114026011b11d49e48c5a9202970bafe3b22c2074f7c1390b98ebb2edb7a","src/flowgraph.rs":"c975c05949017f0b2efeff85bf82017b6a5779ed92e25f13742aeea76ca95c52","src/fx.rs":"8a5d07487906d8316a179e826fcd817a92a4860686256a6fd9d78ba47c63f330","src/ir/builder.rs":"6f111f2a65dfe27633dcec918f74b767277131a72cd94b7bec2e1ef5c4308d5b","src/ir/condcodes.rs":"5247c8d849e1372d2a22379c33a4a88226ec6187be18ca6f2c4e0f315d812aa8","src/ir/dfg.rs":"632f7bec7d2ac63a4f6bb4c5fb4141b9845d6172e82c40c023a733606935549b","src/ir/entities.rs":"5da0d988588d36c0997c7f6208d37b90be5a36816a7a8df46306b244e0b97219","src/ir/extfunc.rs":"f26200741eb91be0d9a72a7aea194fd28f78696754ed9c26e88c8dd277ecd082","src/ir/extname.rs":"ed2c0b52cdaecc7f0ba9a894ef9fffe139e09b520e43dcd6f0c887a3d41a31ac","src/ir/function.rs":"68b1ed2a262c691d4459501feb6358e6cb96663b32796c67e94a3f14a146fdd0","src/ir/globalvalue.rs":"906d29f3d4190b811f66fc549c4e0408bdd2807eac98e33c0b3d5c2b876acc02","src/ir/heap.rs":"a59d3e5901412b53c0b53a8cdf10765ff5921de9c410ae9acea226c89827df3c","src/ir/immediates.rs":"2b2ed4df22ccddbec85be96efea8f5afd21dafe6cd90f08b25aa7746529be06c","src/ir/instructions.rs":"7fe853efeb0379486d7878f7925962144ce208d230107d83e5a9165997a07587","src/ir/jumptable.rs":"7764abc9aa027a5a89d22059b360372bd9a19686887c5a7830f7637d6f188e1e","src/ir/layout.rs":"bb45eefde16ac9423f637dfcc2796ae7b955a97f38a55f23a19cc45da5decce1","src/ir/libcall.rs":"64eeae70e767424ddc8dd01167dc56019df45c3fba5c96bf05fa0d3d7670f344","src/ir/memflags.rs":"dbcf3798ab66dc764b73fb7f139a621c54cc6bcc683f1f70a33ed7e8c3486bfd","src/ir/mod.rs":"bb92d69a52e75e9fec4060ed33239d9194d6ff1514d37ec51f5e64223810ecd0","src/ir/progpoint.rs":"49433f22bd6ff3a96ad0733ff612f3617b312e4492b6b663187141966f6aa701","src/ir/sourceloc.rs":"e1442572958b138f7637a14b662200ea9f729a513b77108be2a39745d8c2a0d5","src/ir/stackslot.rs":"a116aec3d41fcb570044584d06c97e21fc65d68b31f921ab6b5d7a2daddb614b","src/ir/table.rs":"dcc3b663a989b2b084402b08dc9a0e928dbd052e194a46a1886cc6f0cf1a5f2c","src/ir/trapcode.rs":"59e223193617b8c1043ddd3a907c6131f2987e8fe0965ebfd9f7c056c064b7c5","src/ir/types.rs":"3828c0ff0aee4c101135dcbf0a9a39cd8d89cc9f9d52ca0ce7a42d549a9a4a50","src/ir/valueloc.rs":"1bf764fde5ff8140fa2b59f0192086ed17e9ba7018c74719788b74fc5ca05636","src/isa/arm32/abi.rs":"74775c5f1eb95764e46815fa8b31891416a616fdd212972eb77aead43b3345a9","src/isa/arm32/binemit.rs":"eecd7296c27d2520db8e86dd462833ecf06afd33548b03ae676c02454cdd13c2","src/isa/arm32/enc_tables.rs":"e94b12af802de59484cab1124d2ac8a88d08433f6e1a476724ed0403f4b5967f","src/isa/arm32/mod.rs":"1e02aef8ad188d347a17a7ecce42a9064b2d46ac2a5d246bf9b5cd44180a9b60","src/isa/arm32/registers.rs":"254b568a02480f46bb4967a24a438390231014258f0c159f0a41dbafe8e66d56","src/isa/arm32/settings.rs":"2314460f885c24f9571d640f9737a8e0b7d20ca02bcda1127f878fd3891c0529","src/isa/arm64/abi.rs":"52353ed2e2133dacddaad70a876ecebb9c179c19b911ffa823b5b89d3ee7a17c","src/isa/arm64/binemit.rs":"3afbb78f6d9ae5614d908023f84b774c0493c8757ad86fd8301baf0928bb0104","src/isa/arm64/enc_tables.rs":"73fedf7da610a982e37c76e5211dbce880f77841b71c678b0dab2b9e7217cb7c","src/isa/arm64/mod.rs":"49b7f398ec8baa2802a283f780bd039e2a630591e74cf1dddc8d9147345c2816","src/isa/arm64/registers.rs":"308cfcfd9ff2191d7656e7350bb36e41803664eb86ae490fb4b4d3549b25b6a2","src/isa/arm64/settings.rs":"5405ce3560b7ba0705ef525c706eb9f1593e901e1767b837c012084397639042","src/isa/call_conv.rs":"46a03271aed9cb38f87f2d0301721725f99a4f513ee77e39931ea338f13aa0f7","src/isa/constraints.rs":"bddb5c68e56b122a53d8be215e41d22ccf8c4563630b1486e6eb31c0d3337565","src/isa/enc_tables.rs":"382e714f9500afc292c563cb66d4c963d6787e58f197b1db242db7a099c22b9a","src/isa/encoding.rs":"7ea5b4400530172f96e263561682886ea6c67e706398d44a83933ef7f0ac98a5","src/isa/mod.rs":"cb5e4ffba5575d23b8ec5897393a5e2d7eb3259397f76a47e717b41340879de1","src/isa/registers.rs":"2050f34d87dd6e8a3d1cefc6248383ac5a888ec9b6766359edd883714ef03bda","src/isa/riscv/abi.rs":"36557b91ad16a1344c80fbb16a62b46eac88500d76cb9ebcd4eae224dd67b2de","src/isa/riscv/binemit.rs":"264d223da311d4482ebf2f55438b665c67b163058251bc78173c76ba983a31ef","src/isa/riscv/enc_tables.rs":"8491f2082b24c7dedeb7c36cfd913bf9aeaa0a4c8fc754166e9285f4ae002f40","src/isa/riscv/mod.rs":"41136889df9512d8311f8c015cf3f654557a17d784a17fcefeb0afa2f0ec3674","src/isa/riscv/registers.rs":"666c2abe1a93db5f1573d1603db6c13c37f3fc877c0c93b64d1b971921bfa950","src/isa/riscv/settings.rs":"f6362769e9bc5be0c12b091e414ce924b0d2053b05b0ae88fef118cb8c68761e","src/isa/stack.rs":"5d30e2e19662ff3b3a641888bbb29640094ccd51b9a73368a056352afee46320","src/isa/x86/abi.rs":"52df0eb35643a721d2d1acbee550b2194a4407205a340acd139e8e717dfc2801","src/isa/x86/binemit.rs":"24b89af26bcea26955306ad910c72747264e5eccd347bd05761cd151b3258a95","src/isa/x86/enc_tables.rs":"b67d453834e0fdcc2885dfe359502755514c9190a8699bae2c4b5026f1ab4017","src/isa/x86/mod.rs":"77879d642905156885b8f502a6b53423dea8a33cf465d74326049a658c8118d8","src/isa/x86/registers.rs":"bed70bbe1f56f3ef03ea7cd1bea68eb911913cb4c8b93167e044dfc639f7f461","src/isa/x86/settings.rs":"d3e403db3507830f79bcc976c17340b57052cf1b50877fcf1a79549f2a054458","src/iterators.rs":"f85f52d3fa707a0eb974c92215b3e976923ce8f9481219f7812e0f2869c2bd37","src/legalizer/boundary.rs":"70a6819cbb116f07d0a09f8e5b0e2fe91145f423ad02e10225f8879ff4e61351","src/legalizer/call.rs":"be6074c64c1a00e5e81159dd94c8401fef62205b22c15e07e0c56cf922554d00","src/legalizer/globalvalue.rs":"59ab09a0faf593c7f228500b3fd3bacfc0412bdcb2864ec3621aa65adc4a5693","src/legalizer/heap.rs":"b83dc83a5876b024db058023692f71d8f910f6b212f34200e9bcf61a19daeb8e","src/legalizer/libcall.rs":"875daf54ac05114e50eba801b25b2c201351e9f6c276ba0358b356498c54d1c6","src/legalizer/mod.rs":"aef4a458f3ab26239e8ac18c0c20791875fbd21e02085fa130be057e5f899a68","src/legalizer/split.rs":"13fe4d2cecea166ecdc1ebb11f5254374ee170518f1a61de7ac0a921bc8fb25d","src/legalizer/table.rs":"c36d03525312e3191aba8ee00c26a87c1ea200f9a9a0370f0cc84eeacff71786","src/lib.rs":"49ad98df2949c815d717e5a076a8654994fe5b71a7b639b058cb86c2183067fd","src/licm.rs":"07534926e2986c01e3b76a2faf2336f5b96411f06d93d44d74e991f76265e29d","src/loop_analysis.rs":"58fc3cc0e700f05e3131ff1b16ff975d4f32a68c790f095d8445bd300356d3c0","src/nan_canonicalization.rs":"9619bb5554791bd1be75ecd98564d6c9f5b65132bc07c5c4d8c210cd79b66f82","src/partition_slice.rs":"bc13504e7658aab565918d965a0b67e941eb572e583870571bc6dbb2b9aad272","src/postopt.rs":"d4c487f0299fb905bb5a5822e38dea6f70afa4d4577288988b5bec8660bc1ba0","src/predicates.rs":"2d62e2f25a6c4327e75716a5f3508edf810c4957d0b20d855ed5a865359c8dfb","src/print_errors.rs":"3fbd77a01b5404a4bbcf2970e44299ad33948c71f4014d92026415daa8325314","src/redundant_reload_remover.rs":"3b2e49280375c9294fb7e190a8b02ef4fcef05ffcf1cb9e6e583cdc8e484bde1","src/ref_slice.rs":"421a61323c11858a596d50220487f399e1bcedeff0e8d1b716dd4b3531eb01a5","src/regalloc/affinity.rs":"19cec5495c8bddc1fcc8f3c8659d527a5a3ea373ffcc130e3fbd5b462ef15930","src/regalloc/coalescing.rs":"d83be1c1067eb56f2f8f16380450a327d6495b4c6f1f489ded68271c055aec07","src/regalloc/coloring.rs":"45fa9a5f19f790f6bcee66ed3d578144712f8f6f19f564b5b84323f63353a8f7","src/regalloc/context.rs":"25e67e8562bbf757e3198d3a70c56d7b9fc5c86e1ada54cd556aac4144ec7ef2","src/regalloc/diversion.rs":"d46d733f6d00a8f536d5c7c8b8fc6f348c3d0605dd0ee77e1d8359367ba53347","src/regalloc/live_value_tracker.rs":"28823003dc72e8a4702776a8ab5ffd878712700a272b64376b0de2022e0ee31a","src/regalloc/liveness.rs":"a59673fda65d1e3c0e5b3f4468686d05a389c877bee7b10323264595c3c54677","src/regalloc/liverange.rs":"7a28454e5f70d570db439b966a01ead759b65eb65c5845f9c58bf2f230a5f2ab","src/regalloc/mod.rs":"594e059f9f2cbb1e1e2d45ec080c7544c3549bf8b309e6a1b30fcb36b8d7810e","src/regalloc/pressure.rs":"04738e95418f0f858885dfc45183efc3dfb59c8d2ad2fd88bbd9a73a62907730","src/regalloc/register_set.rs":"a816187bc0ca7e0fd9464fde9a37cdeaf09c5f5e7b10faee0eb12f6873034e1c","src/regalloc/reload.rs":"ccccb716a694b53103bd4d55efb2323e788c1127469233c17b648fa06baa67b1","src/regalloc/safepoint.rs":"93a4f963990298a2f2d64148c72859a4a0d5d3176b404834ab743b756882bf56","src/regalloc/solver.rs":"0787ddf732fae9112fb905d6a1dc0c29673800985e67bd57d900426269847e7b","src/regalloc/spilling.rs":"dff4af64409c9a1db7697423576826c3920c26c892fbdde89ee31c680d672e03","src/regalloc/virtregs.rs":"e5c8da6860ba9495f9396621530347e1dd6fc5b2fae2eb23c171ea77429356f1","src/result.rs":"c10354d615f93caa446c3c8c49d6ba3af762816af470f9c4accf04315cce9753","src/scoped_hash_map.rs":"5afafb3a4039094c3a2aad1582354220d21f399aa50046e7f4a1259e1976597e","src/settings.rs":"6c86c3d9b7b9a6424010c08cf6649d405edea5c1955645fa8ec43b9d6f22c3cb","src/simple_gvn.rs":"c8feb380d4831badc59aa1e65efeafa6702711585817fe5f6b31de6b265fac24","src/simple_preopt.rs":"9ee5b9deff729ee6b5b7111a15897f989ff26b9316848fcd5c22930df857467a","src/stack_layout.rs":"c5de271e296fc424f1a30017620bc88500369c8e553fef6e95beccb9c6640e7c","src/timing.rs":"a6808943eec68f5d3ff32132d40c07c142e6aa8073473561573a013978883e4f","src/topo_order.rs":"b01ed68a7300691f41ac434e58a5267b10a8b4a7056d65035e24aa8a6722122a","src/unreachable_code.rs":"40cc71a02887ee4065c76ce96dda0a363a8cc134ec784fe5ed1f276db76596ce","src/value_label.rs":"b81376e0b79252de8dff19d003bcdae210c0848229e63e7682b0148bbcde5961","src/verifier/cssa.rs":"e3e1d77b763c0ba82d3b59ab5b4667fd3152d5a08be50b58b0c82f86376bb062","src/verifier/flags.rs":"cac8ba7ed5fe621eaa425112b931423cb5f3523d580fcf0b7536deb252e96186","src/verifier/liveness.rs":"ac3413b464ee8b5aa5928bee724799b9a1e0cbbdce433c819b9d870483ed070a","src/verifier/locations.rs":"04635edc12bc741a23c9318611aac4abcb42f01effbebee6d858f108f9393a44","src/verifier/mod.rs":"768548894baa6a518244f526ba4b5160c1c3230868f5eeaa376a3f5d98b41df7","src/write.rs":"9abbf2fd10a8611b546f987a11194678fb40d6869fded363b020e5f35a3b4943"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"f797893f65d711c9e0df429ec0b85816c3526e87f0d6baa3300bc5d667f36d20","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"e5127227a7db4a8aa92fa6613ed71801025790e696bb41b0323fb7f3c6f7495a","build.rs":"8587e8557a046dc858f7662f63f1fa54e57ff92ed87b30fbcdfce6feafda9d60","src/abi.rs":"76ee030cf0780fe63ccbf855b1161f215e3e2991cb9abe71ca9aff25e5f1dbc2","src/binemit/memorysink.rs":"da415b20c563e636bcccaafb43dbdb77d6c48f9c205b16229865abb1afa40964","src/binemit/mod.rs":"b05271c3b1d4e44c2f8f9fe0669778775d33e9dda4c70101ddc420275286e72c","src/binemit/relaxation.rs":"1d61f9e9eef5f81b1649aa3918f821d870d712ee5a56b02a18c704d43d344ace","src/binemit/shrink.rs":"79a2dcca2633c8449d49bf7cfb1e2fe14b46753a4d52ef412078c53d7742fe86","src/binemit/stackmap.rs":"da3187d96d21b14927279061ccaba4c880d0ad7169b83bd32c1381d45a39af70","src/bitset.rs":"d57a79058a31b094b4bbe9d34876a5543286df1e08b5ceadfd05a9efc5a3b1ce","src/cfg_printer.rs":"a84dee96d8c6f4775b8ba022243cf1c0bcf847c6d7ec532698cfd331655aa453","src/constant_hash.rs":"77eb898f7b0a4ae3b8165a03c25fcd23ce9c1d0cd32c793fa6cb31666ce27eb1","src/context.rs":"ee09647590a7a583c37df398fe3eb51dca034a5aca4e164288c9f7ed2b30274e","src/cursor.rs":"874d1c7ef6e114d6ae47e0a1f92da7c5cec2e555597558042a3b214da7bc5fe4","src/dbg.rs":"1898d94cff0975815eb348651702e95c8f2f63886501d3b7043ee75668480472","src/dce.rs":"d8ab7c0cac0416f9d75afdacc60ba02e532361ec927c3f8bd171b1a53ec8b31a","src/divconst_magic_numbers.rs":"09691389c9055bef7a0cfd5d77fbfeba4be468d05d981d4de088516a94b8b28e","src/dominator_tree.rs":"7ee4114026011b11d49e48c5a9202970bafe3b22c2074f7c1390b98ebb2edb7a","src/flowgraph.rs":"c975c05949017f0b2efeff85bf82017b6a5779ed92e25f13742aeea76ca95c52","src/fx.rs":"8a5d07487906d8316a179e826fcd817a92a4860686256a6fd9d78ba47c63f330","src/ir/builder.rs":"6f111f2a65dfe27633dcec918f74b767277131a72cd94b7bec2e1ef5c4308d5b","src/ir/condcodes.rs":"5247c8d849e1372d2a22379c33a4a88226ec6187be18ca6f2c4e0f315d812aa8","src/ir/constant.rs":"cffcc1817b4881b87731d59f33f434ffe9be769c0604e3069b1c5e8ee0ebd7d1","src/ir/dfg.rs":"ad5a597584966c3202774bd3cd8bbf3138c474b8fb89347855915b6f4edc8ae8","src/ir/entities.rs":"976f51a1e704b63b0bc701eb814b10ec8eee373d8f93ee73ceeeaeeea2c5b821","src/ir/extfunc.rs":"f26200741eb91be0d9a72a7aea194fd28f78696754ed9c26e88c8dd277ecd082","src/ir/extname.rs":"ed2c0b52cdaecc7f0ba9a894ef9fffe139e09b520e43dcd6f0c887a3d41a31ac","src/ir/function.rs":"01dd3b9c7e95324a5683f3d9edb8f272c5e551c0eb84673ca3bf6740e9707b8e","src/ir/globalvalue.rs":"906d29f3d4190b811f66fc549c4e0408bdd2807eac98e33c0b3d5c2b876acc02","src/ir/heap.rs":"a59d3e5901412b53c0b53a8cdf10765ff5921de9c410ae9acea226c89827df3c","src/ir/immediates.rs":"90e5c07d25d093b084adc3c086c8aeddc4c380aa0a1f67c82c59aec9adb00915","src/ir/instructions.rs":"7fe853efeb0379486d7878f7925962144ce208d230107d83e5a9165997a07587","src/ir/jumptable.rs":"7764abc9aa027a5a89d22059b360372bd9a19686887c5a7830f7637d6f188e1e","src/ir/layout.rs":"bb45eefde16ac9423f637dfcc2796ae7b955a97f38a55f23a19cc45da5decce1","src/ir/libcall.rs":"64eeae70e767424ddc8dd01167dc56019df45c3fba5c96bf05fa0d3d7670f344","src/ir/memflags.rs":"dbcf3798ab66dc764b73fb7f139a621c54cc6bcc683f1f70a33ed7e8c3486bfd","src/ir/mod.rs":"7590a2035a6f88a830e6c440d3c5a22102e921445806d04627e46ee42d82d167","src/ir/progpoint.rs":"49433f22bd6ff3a96ad0733ff612f3617b312e4492b6b663187141966f6aa701","src/ir/sourceloc.rs":"e1442572958b138f7637a14b662200ea9f729a513b77108be2a39745d8c2a0d5","src/ir/stackslot.rs":"a116aec3d41fcb570044584d06c97e21fc65d68b31f921ab6b5d7a2daddb614b","src/ir/table.rs":"dcc3b663a989b2b084402b08dc9a0e928dbd052e194a46a1886cc6f0cf1a5f2c","src/ir/trapcode.rs":"59e223193617b8c1043ddd3a907c6131f2987e8fe0965ebfd9f7c056c064b7c5","src/ir/types.rs":"3828c0ff0aee4c101135dcbf0a9a39cd8d89cc9f9d52ca0ce7a42d549a9a4a50","src/ir/valueloc.rs":"1bf764fde5ff8140fa2b59f0192086ed17e9ba7018c74719788b74fc5ca05636","src/isa/arm32/abi.rs":"74775c5f1eb95764e46815fa8b31891416a616fdd212972eb77aead43b3345a9","src/isa/arm32/binemit.rs":"eecd7296c27d2520db8e86dd462833ecf06afd33548b03ae676c02454cdd13c2","src/isa/arm32/enc_tables.rs":"e94b12af802de59484cab1124d2ac8a88d08433f6e1a476724ed0403f4b5967f","src/isa/arm32/mod.rs":"1e02aef8ad188d347a17a7ecce42a9064b2d46ac2a5d246bf9b5cd44180a9b60","src/isa/arm32/registers.rs":"254b568a02480f46bb4967a24a438390231014258f0c159f0a41dbafe8e66d56","src/isa/arm32/settings.rs":"2314460f885c24f9571d640f9737a8e0b7d20ca02bcda1127f878fd3891c0529","src/isa/arm64/abi.rs":"52353ed2e2133dacddaad70a876ecebb9c179c19b911ffa823b5b89d3ee7a17c","src/isa/arm64/binemit.rs":"3afbb78f6d9ae5614d908023f84b774c0493c8757ad86fd8301baf0928bb0104","src/isa/arm64/enc_tables.rs":"73fedf7da610a982e37c76e5211dbce880f77841b71c678b0dab2b9e7217cb7c","src/isa/arm64/mod.rs":"49b7f398ec8baa2802a283f780bd039e2a630591e74cf1dddc8d9147345c2816","src/isa/arm64/registers.rs":"308cfcfd9ff2191d7656e7350bb36e41803664eb86ae490fb4b4d3549b25b6a2","src/isa/arm64/settings.rs":"5405ce3560b7ba0705ef525c706eb9f1593e901e1767b837c012084397639042","src/isa/call_conv.rs":"46a03271aed9cb38f87f2d0301721725f99a4f513ee77e39931ea338f13aa0f7","src/isa/constraints.rs":"bddb5c68e56b122a53d8be215e41d22ccf8c4563630b1486e6eb31c0d3337565","src/isa/enc_tables.rs":"382e714f9500afc292c563cb66d4c963d6787e58f197b1db242db7a099c22b9a","src/isa/encoding.rs":"7ea5b4400530172f96e263561682886ea6c67e706398d44a83933ef7f0ac98a5","src/isa/mod.rs":"cb5e4ffba5575d23b8ec5897393a5e2d7eb3259397f76a47e717b41340879de1","src/isa/registers.rs":"2050f34d87dd6e8a3d1cefc6248383ac5a888ec9b6766359edd883714ef03bda","src/isa/riscv/abi.rs":"36557b91ad16a1344c80fbb16a62b46eac88500d76cb9ebcd4eae224dd67b2de","src/isa/riscv/binemit.rs":"264d223da311d4482ebf2f55438b665c67b163058251bc78173c76ba983a31ef","src/isa/riscv/enc_tables.rs":"8491f2082b24c7dedeb7c36cfd913bf9aeaa0a4c8fc754166e9285f4ae002f40","src/isa/riscv/mod.rs":"41136889df9512d8311f8c015cf3f654557a17d784a17fcefeb0afa2f0ec3674","src/isa/riscv/registers.rs":"666c2abe1a93db5f1573d1603db6c13c37f3fc877c0c93b64d1b971921bfa950","src/isa/riscv/settings.rs":"f6362769e9bc5be0c12b091e414ce924b0d2053b05b0ae88fef118cb8c68761e","src/isa/stack.rs":"5d30e2e19662ff3b3a641888bbb29640094ccd51b9a73368a056352afee46320","src/isa/x86/abi.rs":"52df0eb35643a721d2d1acbee550b2194a4407205a340acd139e8e717dfc2801","src/isa/x86/binemit.rs":"66fb00826397a5c6c99b9ef6b9daedaec0753d4e87279e2ecbca81863bc4309c","src/isa/x86/enc_tables.rs":"b67d453834e0fdcc2885dfe359502755514c9190a8699bae2c4b5026f1ab4017","src/isa/x86/mod.rs":"77879d642905156885b8f502a6b53423dea8a33cf465d74326049a658c8118d8","src/isa/x86/registers.rs":"bed70bbe1f56f3ef03ea7cd1bea68eb911913cb4c8b93167e044dfc639f7f461","src/isa/x86/settings.rs":"d3e403db3507830f79bcc976c17340b57052cf1b50877fcf1a79549f2a054458","src/iterators.rs":"f85f52d3fa707a0eb974c92215b3e976923ce8f9481219f7812e0f2869c2bd37","src/legalizer/boundary.rs":"70a6819cbb116f07d0a09f8e5b0e2fe91145f423ad02e10225f8879ff4e61351","src/legalizer/call.rs":"be6074c64c1a00e5e81159dd94c8401fef62205b22c15e07e0c56cf922554d00","src/legalizer/globalvalue.rs":"59ab09a0faf593c7f228500b3fd3bacfc0412bdcb2864ec3621aa65adc4a5693","src/legalizer/heap.rs":"b83dc83a5876b024db058023692f71d8f910f6b212f34200e9bcf61a19daeb8e","src/legalizer/libcall.rs":"875daf54ac05114e50eba801b25b2c201351e9f6c276ba0358b356498c54d1c6","src/legalizer/mod.rs":"aef4a458f3ab26239e8ac18c0c20791875fbd21e02085fa130be057e5f899a68","src/legalizer/split.rs":"13fe4d2cecea166ecdc1ebb11f5254374ee170518f1a61de7ac0a921bc8fb25d","src/legalizer/table.rs":"c36d03525312e3191aba8ee00c26a87c1ea200f9a9a0370f0cc84eeacff71786","src/lib.rs":"49ad98df2949c815d717e5a076a8654994fe5b71a7b639b058cb86c2183067fd","src/licm.rs":"07534926e2986c01e3b76a2faf2336f5b96411f06d93d44d74e991f76265e29d","src/loop_analysis.rs":"58fc3cc0e700f05e3131ff1b16ff975d4f32a68c790f095d8445bd300356d3c0","src/nan_canonicalization.rs":"9619bb5554791bd1be75ecd98564d6c9f5b65132bc07c5c4d8c210cd79b66f82","src/partition_slice.rs":"bc13504e7658aab565918d965a0b67e941eb572e583870571bc6dbb2b9aad272","src/postopt.rs":"d4c487f0299fb905bb5a5822e38dea6f70afa4d4577288988b5bec8660bc1ba0","src/predicates.rs":"2d62e2f25a6c4327e75716a5f3508edf810c4957d0b20d855ed5a865359c8dfb","src/print_errors.rs":"3fbd77a01b5404a4bbcf2970e44299ad33948c71f4014d92026415daa8325314","src/redundant_reload_remover.rs":"3b2e49280375c9294fb7e190a8b02ef4fcef05ffcf1cb9e6e583cdc8e484bde1","src/ref_slice.rs":"421a61323c11858a596d50220487f399e1bcedeff0e8d1b716dd4b3531eb01a5","src/regalloc/affinity.rs":"19cec5495c8bddc1fcc8f3c8659d527a5a3ea373ffcc130e3fbd5b462ef15930","src/regalloc/coalescing.rs":"d83be1c1067eb56f2f8f16380450a327d6495b4c6f1f489ded68271c055aec07","src/regalloc/coloring.rs":"45fa9a5f19f790f6bcee66ed3d578144712f8f6f19f564b5b84323f63353a8f7","src/regalloc/context.rs":"25e67e8562bbf757e3198d3a70c56d7b9fc5c86e1ada54cd556aac4144ec7ef2","src/regalloc/diversion.rs":"d46d733f6d00a8f536d5c7c8b8fc6f348c3d0605dd0ee77e1d8359367ba53347","src/regalloc/live_value_tracker.rs":"28823003dc72e8a4702776a8ab5ffd878712700a272b64376b0de2022e0ee31a","src/regalloc/liveness.rs":"a59673fda65d1e3c0e5b3f4468686d05a389c877bee7b10323264595c3c54677","src/regalloc/liverange.rs":"7a28454e5f70d570db439b966a01ead759b65eb65c5845f9c58bf2f230a5f2ab","src/regalloc/mod.rs":"594e059f9f2cbb1e1e2d45ec080c7544c3549bf8b309e6a1b30fcb36b8d7810e","src/regalloc/pressure.rs":"04738e95418f0f858885dfc45183efc3dfb59c8d2ad2fd88bbd9a73a62907730","src/regalloc/register_set.rs":"a816187bc0ca7e0fd9464fde9a37cdeaf09c5f5e7b10faee0eb12f6873034e1c","src/regalloc/reload.rs":"ccccb716a694b53103bd4d55efb2323e788c1127469233c17b648fa06baa67b1","src/regalloc/safepoint.rs":"93a4f963990298a2f2d64148c72859a4a0d5d3176b404834ab743b756882bf56","src/regalloc/solver.rs":"0787ddf732fae9112fb905d6a1dc0c29673800985e67bd57d900426269847e7b","src/regalloc/spilling.rs":"dff4af64409c9a1db7697423576826c3920c26c892fbdde89ee31c680d672e03","src/regalloc/virtregs.rs":"e5c8da6860ba9495f9396621530347e1dd6fc5b2fae2eb23c171ea77429356f1","src/result.rs":"c10354d615f93caa446c3c8c49d6ba3af762816af470f9c4accf04315cce9753","src/scoped_hash_map.rs":"5afafb3a4039094c3a2aad1582354220d21f399aa50046e7f4a1259e1976597e","src/settings.rs":"6c86c3d9b7b9a6424010c08cf6649d405edea5c1955645fa8ec43b9d6f22c3cb","src/simple_gvn.rs":"c8feb380d4831badc59aa1e65efeafa6702711585817fe5f6b31de6b265fac24","src/simple_preopt.rs":"9ee5b9deff729ee6b5b7111a15897f989ff26b9316848fcd5c22930df857467a","src/stack_layout.rs":"c5de271e296fc424f1a30017620bc88500369c8e553fef6e95beccb9c6640e7c","src/timing.rs":"a6808943eec68f5d3ff32132d40c07c142e6aa8073473561573a013978883e4f","src/topo_order.rs":"b01ed68a7300691f41ac434e58a5267b10a8b4a7056d65035e24aa8a6722122a","src/unreachable_code.rs":"40cc71a02887ee4065c76ce96dda0a363a8cc134ec784fe5ed1f276db76596ce","src/value_label.rs":"b81376e0b79252de8dff19d003bcdae210c0848229e63e7682b0148bbcde5961","src/verifier/cssa.rs":"e3e1d77b763c0ba82d3b59ab5b4667fd3152d5a08be50b58b0c82f86376bb062","src/verifier/flags.rs":"cac8ba7ed5fe621eaa425112b931423cb5f3523d580fcf0b7536deb252e96186","src/verifier/liveness.rs":"ac3413b464ee8b5aa5928bee724799b9a1e0cbbdce433c819b9d870483ed070a","src/verifier/locations.rs":"04635edc12bc741a23c9318611aac4abcb42f01effbebee6d858f108f9393a44","src/verifier/mod.rs":"4d013e70bdc90743637fb91a8f3d32790c25aeff168219d147431c02c44f37b7","src/write.rs":"35dff9d0f5ed74779e536cbc6b1de7381cec521a0c54f6d8513041d118bbfc4b"},"package":null}
\ No newline at end of file
--- a/third_party/rust/cranelift-codegen/src/binemit/memorysink.rs
+++ b/third_party/rust/cranelift-codegen/src/binemit/memorysink.rs
@@ -11,17 +11,17 @@
 //! The `MemoryCodeSink` type fixes the performance problem because it is a type known to
 //! `TargetIsa` so it can specialize its machine code generation for the type. The trade-off is
 //! that a `MemoryCodeSink` will always write binary machine code to raw memory. It forwards any
 //! relocations to a `RelocSink` trait object. Relocations are less frequent than the
 //! `CodeSink::put*` methods, so the performance impact of the virtual callbacks is less severe.
 use super::{Addend, CodeInfo, CodeOffset, CodeSink, Reloc};
 use crate::binemit::stackmap::Stackmap;
 use crate::ir::entities::Value;
-use crate::ir::{ExternalName, Function, JumpTable, SourceLoc, TrapCode};
+use crate::ir::{ConstantOffset, ExternalName, Function, JumpTable, SourceLoc, TrapCode};
 use crate::isa::TargetIsa;
 use core::ptr::write_unaligned;
 
 /// A `CodeSink` that writes binary machine code directly into memory.
 ///
 /// A `MemoryCodeSink` object should be used when emitting a Cranelift IR function into executable
 /// memory. It writes machine code directly to a raw pointer without any bounds checking, so make
 /// sure to allocate enough memory for the whole function. The number of bytes required is returned
@@ -73,16 +73,19 @@ impl<'a> MemoryCodeSink<'a> {
 /// A trait for receiving relocations for code that is emitted directly into memory.
 pub trait RelocSink {
     /// Add a relocation referencing an EBB at the current offset.
     fn reloc_ebb(&mut self, _: CodeOffset, _: Reloc, _: CodeOffset);
 
     /// Add a relocation referencing an external symbol at the current offset.
     fn reloc_external(&mut self, _: CodeOffset, _: Reloc, _: &ExternalName, _: Addend);
 
+    /// Add a relocation referencing a constant.
+    fn reloc_constant(&mut self, _: CodeOffset, _: Reloc, _: ConstantOffset);
+
     /// Add a relocation referencing a jump table.
     fn reloc_jt(&mut self, _: CodeOffset, _: Reloc, _: JumpTable);
 }
 
 /// A trait for receiving trap codes and offsets.
 ///
 /// If you don't need information about possible traps, you can use the
 /// [`NullTrapSink`](NullTrapSink) implementation.
@@ -127,16 +130,21 @@ impl<'a> CodeSink for MemoryCodeSink<'a>
         self.relocs.reloc_ebb(ofs, rel, ebb_offset);
     }
 
     fn reloc_external(&mut self, rel: Reloc, name: &ExternalName, addend: Addend) {
         let ofs = self.offset();
         self.relocs.reloc_external(ofs, rel, name, addend);
     }
 
+    fn reloc_constant(&mut self, rel: Reloc, constant_offset: ConstantOffset) {
+        let ofs = self.offset();
+        self.relocs.reloc_constant(ofs, rel, constant_offset);
+    }
+
     fn reloc_jt(&mut self, rel: Reloc, jt: JumpTable) {
         let ofs = self.offset();
         self.relocs.reloc_jt(ofs, rel, jt);
     }
 
     fn trap(&mut self, code: TrapCode, srcloc: SourceLoc) {
         let ofs = self.offset();
         self.traps.trap(ofs, srcloc, code);
@@ -164,16 +172,17 @@ impl<'a> CodeSink for MemoryCodeSink<'a>
 
 /// A `RelocSink` implementation that does nothing, which is convenient when
 /// compiling code that does not relocate anything.
 pub struct NullRelocSink {}
 
 impl RelocSink for NullRelocSink {
     fn reloc_ebb(&mut self, _: u32, _: Reloc, _: u32) {}
     fn reloc_external(&mut self, _: u32, _: Reloc, _: &ExternalName, _: i64) {}
+    fn reloc_constant(&mut self, _: CodeOffset, _: Reloc, _: ConstantOffset) {}
     fn reloc_jt(&mut self, _: u32, _: Reloc, _: JumpTable) {}
 }
 
 /// A `TrapSink` implementation that does nothing, which is convenient when
 /// compiling code that does not rely on trapping semantics.
 pub struct NullTrapSink {}
 
 impl TrapSink for NullTrapSink {
--- a/third_party/rust/cranelift-codegen/src/binemit/mod.rs
+++ b/third_party/rust/cranelift-codegen/src/binemit/mod.rs
@@ -11,17 +11,17 @@ mod stackmap;
 pub use self::memorysink::{
     MemoryCodeSink, NullRelocSink, NullStackmapSink, NullTrapSink, RelocSink, StackmapSink,
     TrapSink,
 };
 pub use self::relaxation::relax_branches;
 pub use self::shrink::shrink_instructions;
 pub use self::stackmap::Stackmap;
 use crate::ir::entities::Value;
-use crate::ir::{ExternalName, Function, Inst, JumpTable, SourceLoc, TrapCode};
+use crate::ir::{ConstantOffset, ExternalName, Function, Inst, JumpTable, SourceLoc, TrapCode};
 use crate::isa::TargetIsa;
 pub use crate::regalloc::RegDiversions;
 use core::fmt;
 #[cfg(feature = "enable-serde")]
 use serde::{Deserialize, Serialize};
 
 /// Offset in bytes from the beginning of the function.
 ///
@@ -129,16 +129,19 @@ pub trait CodeSink {
 
     /// Add a relocation referencing an EBB at the current offset.
     fn reloc_ebb(&mut self, _: Reloc, _: CodeOffset);
 
     /// Add a relocation referencing an external symbol plus the addend at the current offset.
     fn reloc_external(&mut self, _: Reloc, _: &ExternalName, _: Addend);
 
     /// Add a relocation referencing a jump table.
+    fn reloc_constant(&mut self, _: Reloc, _: ConstantOffset);
+
+    /// Add a relocation referencing a jump table.
     fn reloc_jt(&mut self, _: Reloc, _: JumpTable);
 
     /// Add trap information for the current offset.
     fn trap(&mut self, _: TrapCode, _: SourceLoc);
 
     /// Machine code output is complete, jump table data may follow.
     fn begin_jumptables(&mut self);
 
@@ -187,12 +190,18 @@ where
         let jt_offset = func.jt_offsets[jt];
         for ebb in jt_data.iter() {
             let rel_offset: i32 = func.offsets[*ebb] as i32 - jt_offset as i32;
             sink.put4(rel_offset as u32)
         }
     }
 
     sink.begin_rodata();
-    // TODO: No read-only data (constant pools) at this time.
+
+    // output constants
+    for (_, constant_data) in func.dfg.constants.iter() {
+        for byte in constant_data.iter() {
+            sink.put1(*byte)
+        }
+    }
 
     sink.end_codegen();
 }
--- a/third_party/rust/cranelift-codegen/src/binemit/relaxation.rs
+++ b/third_party/rust/cranelift-codegen/src/binemit/relaxation.rs
@@ -32,16 +32,17 @@ use crate::cursor::{Cursor, FuncCursor};
 use crate::dominator_tree::DominatorTree;
 use crate::flowgraph::ControlFlowGraph;
 use crate::ir::{Function, InstructionData, Opcode};
 use crate::isa::{EncInfo, TargetIsa};
 use crate::iterators::IteratorExtras;
 use crate::regalloc::RegDiversions;
 use crate::timing;
 use crate::CodegenResult;
+use core::convert::TryFrom;
 use log::debug;
 
 #[cfg(feature = "basic-blocks")]
 use crate::ir::{Ebb, Inst, Value, ValueList};
 
 /// Relax branches and compute the final layout of EBB headers in `func`.
 ///
 /// Fill in the `func.offsets` table so the function is ready for binary emission.
@@ -130,17 +131,21 @@ pub fn relax_branches(
         // TODO: this should be computed based on the min size needed to hold
         //        the furthest branch.
         offset += jt_data.len() as u32 * 4;
     }
 
     let jumptables_size = offset - jumptables;
     let rodata = offset;
 
-    // TODO: Once we have constant pools we'll do some processing here to update offset.
+    for constant in func.dfg.constants.entries_mut() {
+        constant.set_offset(offset);
+        offset +=
+            u32::try_from(constant.len()).expect("Constants must have a length that fits in a u32")
+    }
 
     let rodata_size = offset - rodata;
 
     Ok(CodeInfo {
         code_size,
         jumptables_size,
         rodata_size,
         total_size: offset,
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cranelift-codegen/src/ir/constant.rs
@@ -0,0 +1,220 @@
+//! Constants
+//!
+//! The constant pool defined here allows cranelift to avoid emitting the same constant multiple
+//! times. As constants are inserted in the pool, a handle is returned; the handle is a cranelift
+//! Entity. Inserting the same data multiple times will always return the same handle. Future work
+//! could include: ensuring alignment of constants within the pool, bucketing constants by size.
+
+use crate::ir::Constant;
+use cranelift_entity::EntityRef;
+use std::collections::{BTreeMap, HashMap};
+use std::vec::Vec;
+
+/// This type describes the actual constant data.
+pub type ConstantData = Vec<u8>;
+
+/// This type describes an offset in bytes within a constant pool.
+pub type ConstantOffset = u32;
+
+/// Inner type for storing data and offset together in the constant pool. The offset is optional
+/// because it must be set relative to the function code size (i.e. constants are emitted after the
+/// function body); because the function is not yet compiled when constants are inserted,
+/// [`set_offset`](crate::ir::ConstantPool::set_offset) must be called once a constant's
+/// offset from the beginning of the function is known (see
+/// [`relaxation.rs`](crate::binemit::relaxation)).
+#[derive(Clone)]
+pub struct ConstantPoolEntry {
+    data: ConstantData,
+    offset: Option<ConstantOffset>,
+}
+
+impl ConstantPoolEntry {
+    fn new(data: ConstantData) -> Self {
+        ConstantPoolEntry { data, offset: None }
+    }
+
+    /// Return the size of the constant at this entry.
+    pub fn len(&self) -> usize {
+        self.data.len()
+    }
+
+    /// Assign a new offset to the constant at this entry.
+    pub fn set_offset(&mut self, offset: ConstantOffset) {
+        self.offset = Some(offset)
+    }
+}
+
+/// Maintains the mapping between a constant handle (i.e.
+/// [`Constant`](crate::ir::Constant)) and its constant data (i.e.
+/// [`ConstantData`](crate::ir::ConstantData)).
+#[derive(Clone)]
+pub struct ConstantPool {
+    /// This mapping maintains the insertion order as long as Constants are created with sequentially increasing integers.
+    handles_to_values: BTreeMap<Constant, ConstantPoolEntry>,
+    /// This mapping is unordered (no need for lexicographic ordering) but allows us to map constant data back to handles.
+    values_to_handles: HashMap<ConstantData, Constant>,
+}
+
+impl ConstantPool {
+    /// Create a new constant pool instance.
+    pub fn new() -> Self {
+        ConstantPool {
+            handles_to_values: BTreeMap::new(),
+            values_to_handles: HashMap::new(),
+        }
+    }
+
+    /// Empty the constant pool of all data.
+    pub fn clear(&mut self) {
+        self.handles_to_values.clear();
+        self.values_to_handles.clear();
+    }
+
+    /// Insert constant data into the pool, returning a handle for later referencing; when constant
+    /// data is inserted that is a duplicate of previous constant data, the existing handle will be
+    /// returned.
+    pub fn insert(&mut self, constant_value: ConstantData) -> Constant {
+        if self.values_to_handles.contains_key(&constant_value) {
+            self.values_to_handles
+                .get(&constant_value)
+                .expect("A constant handle must have a corresponding constant value; this is an implementation error in ConstantPool")
+                .clone()
+        } else {
+            let constant_handle = Constant::new(self.len());
+            self.values_to_handles
+                .insert(constant_value.clone(), constant_handle.clone());
+            self.handles_to_values.insert(
+                constant_handle.clone(),
+                ConstantPoolEntry::new(constant_value),
+            );
+            constant_handle
+        }
+    }
+
+    /// Retrieve the constant data given a handle.
+    pub fn get(&self, constant_handle: Constant) -> &ConstantData {
+        assert!(self.handles_to_values.contains_key(&constant_handle));
+        &self.handles_to_values
+            .get(&constant_handle)
+            .expect("A constant handle must have a corresponding constant value; was a constant handle created outside of the pool?")
+            .data
+    }
+
+    /// Assign an offset to a given constant, where the offset is the number of bytes from the
+    /// beginning of the function to the beginning of the constant data inside the pool.
+    pub fn set_offset(&mut self, constant_handle: Constant, constant_offset: ConstantOffset) {
+        assert!(self.handles_to_values.contains_key(&constant_handle), "A constant handle must have already been inserted into the pool; perhaps a constant pool was created outside of the pool?");
+        self.handles_to_values
+            .entry(constant_handle)
+            .and_modify(|e| e.offset = Some(constant_offset));
+    }
+
+    /// Retrieve the offset of a given constant, where the offset is the number of bytes from the
+    /// beginning of the function to the beginning of the constant data inside the pool.
+    pub fn get_offset(&self, constant_handle: Constant) -> ConstantOffset {
+        self.handles_to_values.get(&constant_handle)
+            .expect("A constant handle must have a corresponding constant value; was a constant handle created outside of the pool?")
+            .offset
+            .expect("A constant offset has not yet been set; verify that `set_offset` has been called before this point")
+    }
+
+    /// Iterate over the constants in insertion order.
+    pub fn iter(&self) -> impl Iterator<Item = (&Constant, &ConstantData)> {
+        self.handles_to_values.iter().map(|(h, e)| (h, &e.data))
+    }
+
+    /// Iterate over mutable entries in the constant pool in insertion order.
+    pub fn entries_mut(&mut self) -> impl Iterator<Item = &mut ConstantPoolEntry> {
+        self.handles_to_values.values_mut()
+    }
+
+    /// Return the number of constants in the pool.
+    pub fn len(&self) -> usize {
+        self.handles_to_values.len()
+    }
+
+    /// Return the combined size of all of the constant values in the pool.
+    pub fn byte_size(&self) -> usize {
+        self.values_to_handles.keys().map(|c| c.len()).sum()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn empty() {
+        let sut = ConstantPool::new();
+        assert_eq!(sut.len(), 0);
+    }
+
+    #[test]
+    fn insert() {
+        let mut sut = ConstantPool::new();
+        sut.insert(vec![1, 2, 3]);
+        sut.insert(vec![4, 5, 6]);
+        assert_eq!(sut.len(), 2);
+    }
+
+    #[test]
+    fn insert_duplicate() {
+        let mut sut = ConstantPool::new();
+        let a = sut.insert(vec![1, 2, 3]);
+        sut.insert(vec![4, 5, 6]);
+        let b = sut.insert(vec![1, 2, 3]);
+        assert_eq!(a, b);
+    }
+
+    #[test]
+    fn clear() {
+        let mut sut = ConstantPool::new();
+        sut.insert(vec![1, 2, 3]);
+        assert_eq!(sut.len(), 1);
+
+        sut.clear();
+        assert_eq!(sut.len(), 0);
+    }
+
+    #[test]
+    fn iteration_order() {
+        let mut sut = ConstantPool::new();
+        sut.insert(vec![1, 2, 3]);
+        sut.insert(vec![4, 5, 6]);
+        sut.insert(vec![1, 2, 3]);
+        let data = sut.iter().map(|(_, v)| v).collect::<Vec<&ConstantData>>();
+        assert_eq!(data, vec![&vec![1, 2, 3], &vec![4, 5, 6]]);
+    }
+
+    #[test]
+    fn get() {
+        let mut sut = ConstantPool::new();
+        let data = vec![1, 2, 3];
+        let handle = sut.insert(data.clone());
+        assert_eq!(sut.get(handle), &data);
+    }
+
+    #[test]
+    #[should_panic]
+    fn get_nonexistent_constant() {
+        let sut = ConstantPool::new();
+        let a = Constant::with_number(42).unwrap();
+        sut.get(a); // panics, only use constants returned by ConstantPool
+    }
+
+    #[test]
+    fn get_offset() {
+        let mut sut = ConstantPool::new();
+        let a = sut.insert(vec![1]);
+        sut.set_offset(a, 42);
+        assert_eq!(sut.get_offset(a), 42)
+    }
+
+    #[test]
+    #[should_panic]
+    fn get_nonexistent_offset() {
+        let mut sut = ConstantPool::new();
+        let a = sut.insert(vec![1]);
+        sut.get_offset(a); // panics, set_offset should have been called
+    }
+}
--- a/third_party/rust/cranelift-codegen/src/ir/dfg.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/dfg.rs
@@ -1,16 +1,16 @@
 //! Data flow graph tracking Instructions, Values, and EBBs.
 
 use crate::entity::{self, PrimaryMap, SecondaryMap};
 use crate::ir;
 use crate::ir::builder::ReplaceBuilder;
 use crate::ir::extfunc::ExtFuncData;
 use crate::ir::instructions::{BranchInfo, CallInfo, InstructionData};
-use crate::ir::types;
+use crate::ir::{types, ConstantPool};
 use crate::ir::{
     Ebb, FuncRef, Inst, SigRef, Signature, Type, Value, ValueLabelAssignments, ValueList,
     ValueListPool,
 };
 use crate::isa::TargetIsa;
 use crate::packed_option::ReservedValue;
 use crate::write::write_operands;
 use core::fmt;
@@ -62,43 +62,48 @@ pub struct DataFlowGraph {
     /// well as the external function references.
     pub signatures: PrimaryMap<SigRef, Signature>,
 
     /// External function references. These are functions that can be called directly.
     pub ext_funcs: PrimaryMap<FuncRef, ExtFuncData>,
 
     /// Saves Value labels.
     pub values_labels: Option<HashMap<Value, ValueLabelAssignments>>,
+
+    /// Constants used within the function
+    pub constants: ConstantPool,
 }
 
 impl DataFlowGraph {
     /// Create a new empty `DataFlowGraph`.
     pub fn new() -> Self {
         Self {
             insts: PrimaryMap::new(),
             results: SecondaryMap::new(),
             ebbs: PrimaryMap::new(),
             value_lists: ValueListPool::new(),
             values: PrimaryMap::new(),
             signatures: PrimaryMap::new(),
             ext_funcs: PrimaryMap::new(),
             values_labels: None,
+            constants: ConstantPool::new(),
         }
     }
 
     /// Clear everything.
     pub fn clear(&mut self) {
         self.insts.clear();
         self.results.clear();
         self.ebbs.clear();
         self.value_lists.clear();
         self.values.clear();
         self.signatures.clear();
         self.ext_funcs.clear();
         self.values_labels = None;
+        self.constants.clear()
     }
 
     /// Get the total number of instructions created in this function, whether they are currently
     /// inserted in the layout or not.
     ///
     /// This is intended for use with `SecondaryMap::with_capacity`.
     pub fn num_insts(&self) -> usize {
         self.insts.len()
--- a/third_party/rust/cranelift-codegen/src/ir/entities.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/entities.rs
@@ -99,16 +99,34 @@ impl GlobalValue {
         if n < u32::MAX {
             Some(GlobalValue(n))
         } else {
             None
         }
     }
 }
 
+/// An opaque reference to a constant
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
+pub struct Constant(u32);
+entity_impl!(Constant, "const");
+
+impl Constant {
+    /// Create a const reference from its number.
+    ///
+    /// This method is for use by the parser.
+    pub fn with_number(n: u32) -> Option<Self> {
+        if n < u32::MAX {
+            Some(Constant(n))
+        } else {
+            None
+        }
+    }
+}
+
 /// An opaque reference to a jump table.
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
 pub struct JumpTable(u32);
 entity_impl!(JumpTable, "jt");
 
 impl JumpTable {
     /// Create a new jump table reference from its number.
@@ -190,17 +208,17 @@ impl Table {
         if n < u32::MAX {
             Some(Table(n))
         } else {
             None
         }
     }
 }
 
-/// A reference to any of the entities defined in this module.
+/// A reference to any of the entities defined in this module that can appear in CLIF IR.
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub enum AnyEntity {
     /// The whole function.
     Function,
     /// An extended basic block.
     Ebb(Ebb),
     /// An instruction.
     Inst(Inst),
@@ -326,9 +344,15 @@ mod tests {
         use crate::packed_option::PackedOption;
         use core::mem;
         // This is the whole point of `PackedOption`.
         assert_eq!(
             mem::size_of::<Value>(),
             mem::size_of::<PackedOption<Value>>()
         );
     }
+
+    #[test]
+    fn constant_with_number() {
+        assert_eq!(Constant::with_number(0).unwrap().to_string(), "const0");
+        assert_eq!(Constant::with_number(1).unwrap().to_string(), "const1");
+    }
 }
--- a/third_party/rust/cranelift-codegen/src/ir/function.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/function.rs
@@ -108,16 +108,17 @@ impl Function {
         self.heaps.clear();
         self.tables.clear();
         self.jump_tables.clear();
         self.dfg.clear();
         self.layout.clear();
         self.encodings.clear();
         self.locations.clear();
         self.offsets.clear();
+        self.jt_offsets.clear();
         self.srclocs.clear();
     }
 
     /// Create a new empty, anonymous function with a Fast calling convention.
     pub fn new() -> Self {
         Self::with_name_signature(ExternalName::default(), Signature::new(CallConv::Fast))
     }
 
--- a/third_party/rust/cranelift-codegen/src/ir/immediates.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/immediates.rs
@@ -259,16 +259,84 @@ impl FromStr for Uimm32 {
                 Ok(Uimm32(x as u32))
             } else {
                 Err("Uimm32 out of range")
             }
         })
     }
 }
 
+/// A 128-bit unsigned integer immediate operand.
+///
+/// This is used as an immediate value in SIMD instructions
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
+pub struct Uimm128(pub [u8; 16]);
+
+impl Display for Uimm128 {
+    // print a 128-bit vector in hexadecimal, e.g. 0x000102030405060708090a0b0c0d0e0f
+    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+        write!(f, "0x")?;
+        let mut anything_written = false;
+        for &b in self.0.iter().rev() {
+            if b == 0 && !anything_written {
+                continue;
+            } else {
+                anything_written = true;
+                write!(f, "{:02x}", b)?;
+            }
+        }
+        if !anything_written {
+            write!(f, "00")?;
+        }
+        Ok(())
+    }
+}
+
+impl From<u64> for Uimm128 {
+    fn from(x: u64) -> Self {
+        let mut buffer: [u8; 16] = [0; 16]; // zero-fill
+        (0..8).for_each(|byte| buffer[byte] = (x >> (byte as u64 * 8) & 0xff) as u8); // insert each byte from the u64 into v in little-endian order
+        Uimm128(buffer)
+    }
+}
+
+impl From<&[u8]> for Uimm128 {
+    fn from(slice: &[u8]) -> Self {
+        assert_eq!(slice.len(), 16);
+        let mut buffer = [0; 16];
+        buffer.copy_from_slice(slice);
+        Uimm128(buffer)
+    }
+}
+
+impl FromStr for Uimm128 {
+    type Err = &'static str;
+
+    // parse a 128-bit vector from a hexadecimal string, formatted as above
+    fn from_str(s: &str) -> Result<Self, &'static str> {
+        if s.len() <= 2 || &s[0..2] != "0x" {
+            Err("Expected a hexadecimal string, e.g. 0x1234")
+        } else if s.len() % 2 != 0 {
+            Err("Hexadecimal string must have an even number of digits")
+        } else if s.len() > 34 {
+            Err("Hexadecimal string has too many digits to fit in a 128-bit vector")
+        } else {
+            let mut buffer = [0; 16]; // zero-fill
+            let start_at = s.len() / 2 - 1;
+            for i in (2..s.len()).step_by(2) {
+                let byte = u8::from_str_radix(&s[i..i + 2], 16)
+                    .or_else(|_| Err("Unable to parse as hexadecimal"))?;
+                let position = start_at - (i / 2);
+                buffer[position] = byte;
+            }
+            Ok(Uimm128(buffer))
+        }
+    }
+}
+
 /// 32-bit signed immediate offset.
 ///
 /// This is used to encode an immediate offset for load/store instructions. All supported ISAs have
 /// a maximum load/store offset that fits in an `i32`.
 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
 pub struct Offset32(i32);
 
 impl Offset32 {
@@ -880,16 +948,64 @@ mod tests {
         parse_err::<Uimm64>("-0", "Invalid character in decimal number");
         parse_err::<Uimm64>("-1", "Invalid character in decimal number");
 
         // Hex count overflow.
         parse_err::<Uimm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits");
     }
 
     #[test]
+    fn format_uimm128() {
+        assert_eq!(Uimm128::from(0).to_string(), "0x00");
+        assert_eq!(Uimm128::from(42).to_string(), "0x2a");
+        assert_eq!(Uimm128::from(3735928559).to_string(), "0xdeadbeef");
+        assert_eq!(
+            Uimm128::from(0x0102030405060708).to_string(),
+            "0x0102030405060708"
+        );
+    }
+
+    #[test]
+    fn parse_uimm128() {
+        parse_ok::<Uimm128>("0x00", "0x00");
+        parse_ok::<Uimm128>("0x00000042", "0x42");
+        parse_ok::<Uimm128>(
+            "0x0102030405060708090a0b0c0d0e0f",
+            "0x0102030405060708090a0b0c0d0e0f",
+        );
+
+        parse_err::<Uimm128>("", "Expected a hexadecimal string, e.g. 0x1234");
+        parse_err::<Uimm128>("0x", "Expected a hexadecimal string, e.g. 0x1234");
+        parse_err::<Uimm128>(
+            "0x042",
+            "Hexadecimal string must have an even number of digits",
+        );
+        parse_err::<Uimm128>(
+            "0x00000000000000000000000000000000000000000000000000",
+            "Hexadecimal string has too many digits to fit in a 128-bit vector",
+        );
+    }
+
+    #[test]
+    fn uimm128_endianness() {
+        assert_eq!(
+            "0x42".parse::<Uimm128>().unwrap().0,
+            [0x42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+        );
+        assert_eq!(
+            "0x00".parse::<Uimm128>().unwrap().0,
+            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+        );
+        assert_eq!(
+            "0x12345678".parse::<Uimm128>().unwrap().0,
+            [0x78, 0x56, 0x34, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+        )
+    }
+
+    #[test]
     fn format_offset32() {
         assert_eq!(Offset32(0).to_string(), "");
         assert_eq!(Offset32(1).to_string(), "+1");
         assert_eq!(Offset32(-1).to_string(), "-1");
         assert_eq!(Offset32(9999).to_string(), "+9999");
         assert_eq!(Offset32(10000).to_string(), "+0x2710");
         assert_eq!(Offset32(-9999).to_string(), "-9999");
         assert_eq!(Offset32(-10000).to_string(), "-0x2710");
--- a/third_party/rust/cranelift-codegen/src/ir/mod.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/mod.rs
@@ -1,12 +1,13 @@
 //! Representation of Cranelift IR functions.
 
 mod builder;
 pub mod condcodes;
+pub mod constant;
 pub mod dfg;
 pub mod entities;
 mod extfunc;
 mod extname;
 pub mod function;
 mod globalvalue;
 mod heap;
 pub mod immediates;
@@ -22,19 +23,20 @@ mod table;
 mod trapcode;
 pub mod types;
 mod valueloc;
 
 #[cfg(feature = "enable-serde")]
 use serde::{Deserialize, Serialize};
 
 pub use crate::ir::builder::{InsertBuilder, InstBuilder, InstBuilderBase, InstInserterBase};
+pub use crate::ir::constant::{ConstantData, ConstantOffset, ConstantPool};
 pub use crate::ir::dfg::{DataFlowGraph, ValueDef};
 pub use crate::ir::entities::{
-    Ebb, FuncRef, GlobalValue, Heap, Inst, JumpTable, SigRef, StackSlot, Table, Value,
+    Constant, Ebb, FuncRef, GlobalValue, Heap, Inst, JumpTable, SigRef, StackSlot, Table, Value,
 };
 pub use crate::ir::extfunc::{
     AbiParam, ArgumentExtension, ArgumentPurpose, ExtFuncData, Signature,
 };
 pub use crate::ir::extname::ExternalName;
 pub use crate::ir::function::{DisplayFunctionAnnotations, Function};
 pub use crate::ir::globalvalue::GlobalValueData;
 pub use crate::ir::heap::{HeapData, HeapStyle};
--- a/third_party/rust/cranelift-codegen/src/isa/x86/binemit.rs
+++ b/third_party/rust/cranelift-codegen/src/isa/x86/binemit.rs
@@ -1,15 +1,15 @@
 //! Emitting binary x86 machine code.
 
 use super::enc_tables::{needs_offset, needs_sib_byte};
 use super::registers::RU;
 use crate::binemit::{bad_encoding, CodeSink, Reloc};
 use crate::ir::condcodes::{CondCode, FloatCC, IntCC};
-use crate::ir::{Ebb, Function, Inst, InstructionData, JumpTable, Opcode, TrapCode};
+use crate::ir::{Constant, Ebb, Function, Inst, InstructionData, JumpTable, Opcode, TrapCode};
 use crate::isa::{RegUnit, StackBase, StackBaseMask, StackRef, TargetIsa};
 use crate::regalloc::RegDiversions;
 
 include!(concat!(env!("OUT_DIR"), "/binemit-x86.rs"));
 
 // Convert a stack base to the corresponding register.
 fn stk_base(base: StackBase) -> RegUnit {
     let ru = match base {
@@ -336,8 +336,16 @@ fn disp4<CS: CodeSink + ?Sized>(destinat
 }
 
 /// Emit a four-byte displacement to jump table `jt`.
 fn jt_disp4<CS: CodeSink + ?Sized>(jt: JumpTable, func: &Function, sink: &mut CS) {
     let delta = func.jt_offsets[jt].wrapping_sub(sink.offset() + 4);
     sink.put4(delta);
     sink.reloc_jt(Reloc::X86PCRelRodata4, jt);
 }
+
+/// Emit a four-byte displacement to `constant`
+fn const_disp4<CS: CodeSink + ?Sized>(constant: Constant, func: &Function, sink: &mut CS) {
+    let offset = func.dfg.constants.get_offset(constant);
+    let delta = offset.wrapping_sub(sink.offset() + 4);
+    sink.put4(delta);
+    sink.reloc_constant(Reloc::X86PCRelRodata4, offset);
+}
--- a/third_party/rust/cranelift-codegen/src/verifier/mod.rs
+++ b/third_party/rust/cranelift-codegen/src/verifier/mod.rs
@@ -674,16 +674,17 @@ impl<'a> Verifier<'a> {
             }
             StoreComplex { ref args, .. } => {
                 self.verify_value_list(inst, args, errors)?;
             }
 
             // Exhaustive list so we can't forget to add new formats
             Unary { .. }
             | UnaryImm { .. }
+            | UnaryImm128 { .. }
             | UnaryIeee32 { .. }
             | UnaryIeee64 { .. }
             | UnaryBool { .. }
             | Binary { .. }
             | BinaryImm { .. }
             | Ternary { .. }
             | InsertLane { .. }
             | ExtractLane { .. }
--- a/third_party/rust/cranelift-codegen/src/write.rs
+++ b/third_party/rust/cranelift-codegen/src/write.rs
@@ -1,15 +1,16 @@
 //! Converting Cranelift IR to text.
 //!
 //! The `write` module provides the `write_function` function which converts an IR `Function` to an
 //! equivalent textual form. This textual form can be read back by the `cranelift-reader` crate.
 
 use crate::entity::SecondaryMap;
 use crate::ir::entities::AnyEntity;
+use crate::ir::immediates::Uimm128;
 use crate::ir::{
     DataFlowGraph, DisplayFunctionAnnotations, Ebb, Function, Inst, SigRef, Type, Value, ValueDef,
     ValueLoc,
 };
 use crate::isa::{RegInfo, TargetIsa};
 use crate::packed_option::ReservedValue;
 use crate::value_label::ValueLabelsRanges;
 use core::fmt::{self, Write};
@@ -482,16 +483,21 @@ pub fn write_operands(
     isa: Option<&dyn TargetIsa>,
     inst: Inst,
 ) -> fmt::Result {
     let pool = &dfg.value_lists;
     use crate::ir::instructions::InstructionData::*;
     match dfg[inst] {
         Unary { arg, .. } => write!(w, " {}", arg),
         UnaryImm { imm, .. } => write!(w, " {}", imm),
+        UnaryImm128 { imm, .. } => {
+            let data = dfg.constants.get(imm);
+            let uimm128 = Uimm128::from(&data[..]);
+            write!(w, " {}", uimm128)
+        }
         UnaryIeee32 { imm, .. } => write!(w, " {}", imm),
         UnaryIeee64 { imm, .. } => write!(w, " {}", imm),
         UnaryBool { imm, .. } => write!(w, " {}", imm),
         UnaryGlobalValue { global_value, .. } => write!(w, " {}", global_value),
         Binary { args, .. } => write!(w, " {}, {}", args[0], args[1]),
         BinaryImm { arg, imm, .. } => write!(w, " {}, {}", arg, imm),
         Ternary { args, .. } => write!(w, " {}, {}, {}", args[0], args[1], args[2]),
         MultiAry { ref args, .. } => {
--- a/third_party/rust/cranelift-wasm/.cargo-checksum.json
+++ b/third_party/rust/cranelift-wasm/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"0acc3911c582b0f38099b4694d7600e6d5bb59a701c0b71144ba4cdd0ee2babf","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"87679cdb53e8cbec3b1aa45afb2124727c1c059f8bd10363d27daf318a9f9a36","src/code_translator.rs":"ec67a88ce22cc456d3bd9c410bcf15982b196688374d06f2c1f633c838cb138d","src/environ/dummy.rs":"cca4a867849e82d3fe6793d306d24e89080198e74a58947085edbc12aab2a4ff","src/environ/mod.rs":"b046f5344a1017357c1ee9d661d2193e0247327df293436fa1381a0f45f80584","src/environ/spec.rs":"5f92d6da837267f85543f2700b658b4fb80052816f77d9fbfaa6e511d1ca3116","src/func_translator.rs":"2f1a80ede583cb14cfc2714c1d96855d6d0fdc5e044e092b0257179cd118d876","src/lib.rs":"4664114c8f4c174bea6c0385d36f29198fc9b01a8503308c7d75ea094987744b","src/module_translator.rs":"8f23a0e17c512b6fcb19fc3f19b41aebce6bde51923e812ddd326409ac967efd","src/sections_translator.rs":"cab0e57e173cf752a8ada6cff74abb364c3191a9c3341e5c686d750f51c83995","src/state.rs":"fc2a8d468b4b681d9262fdb8762f3300ffce709cb0b2e48f3835a5b9164e7c93","src/translation_utils.rs":"134ab514ba2a21cca88d603419cf233ffa00f671c8552fd3262a8cd85d3bb97d","tests/wasm_testsuite.rs":"9b4e008587c61377cf38f9d0e4635418ee38e32a865db8da5dfc6e0fae047436"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"0acc3911c582b0f38099b4694d7600e6d5bb59a701c0b71144ba4cdd0ee2babf","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"87679cdb53e8cbec3b1aa45afb2124727c1c059f8bd10363d27daf318a9f9a36","src/code_translator.rs":"1a830b7a75c868246ee6a648187da60fd60b3620bc47c3dfaa716c2712765def","src/environ/dummy.rs":"cca4a867849e82d3fe6793d306d24e89080198e74a58947085edbc12aab2a4ff","src/environ/mod.rs":"b046f5344a1017357c1ee9d661d2193e0247327df293436fa1381a0f45f80584","src/environ/spec.rs":"5f92d6da837267f85543f2700b658b4fb80052816f77d9fbfaa6e511d1ca3116","src/func_translator.rs":"2f1a80ede583cb14cfc2714c1d96855d6d0fdc5e044e092b0257179cd118d876","src/lib.rs":"4664114c8f4c174bea6c0385d36f29198fc9b01a8503308c7d75ea094987744b","src/module_translator.rs":"8f23a0e17c512b6fcb19fc3f19b41aebce6bde51923e812ddd326409ac967efd","src/sections_translator.rs":"cab0e57e173cf752a8ada6cff74abb364c3191a9c3341e5c686d750f51c83995","src/state.rs":"fc2a8d468b4b681d9262fdb8762f3300ffce709cb0b2e48f3835a5b9164e7c93","src/translation_utils.rs":"134ab514ba2a21cca88d603419cf233ffa00f671c8552fd3262a8cd85d3bb97d","tests/wasm_testsuite.rs":"9e01f9053516ce6a411449aaf41438867fc83c83d45cdbe5e84a9a34d4a1ca02"},"package":null}
\ No newline at end of file
--- a/third_party/rust/cranelift-wasm/src/code_translator.rs
+++ b/third_party/rust/cranelift-wasm/src/code_translator.rs
@@ -28,17 +28,17 @@ use crate::state::{ControlStackFrame, Tr
 use crate::translation_utils::{
     blocktype_to_type, f32_translation, f64_translation, num_return_values,
 };
 use crate::translation_utils::{FuncIndex, MemoryIndex, SignatureIndex, TableIndex};
 use crate::wasm_unsupported;
 use core::{i32, u32};
 use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
 use cranelift_codegen::ir::types::*;
-use cranelift_codegen::ir::{self, InstBuilder, JumpTableData, MemFlags, ValueLabel};
+use cranelift_codegen::ir::{self, InstBuilder, JumpTableData, MemFlags, Value, ValueLabel};
 use cranelift_codegen::packed_option::ReservedValue;
 use cranelift_frontend::{FunctionBuilder, Variable};
 use wasmparser::{MemoryImmediate, Operator};
 
 // Clippy warns about "flags: _" but its important to document that the flags field is ignored
 #[cfg_attr(feature = "cargo-clippy", allow(clippy::unneeded_field_pattern))]
 /// Translates wasm operators into Cranelift IR instructions. Returns `true` if it inserted
 /// a return.
@@ -917,40 +917,65 @@ pub fn translate_operator<FE: FuncEnviro
         | Operator::ElemDrop { .. }
         | Operator::TableCopy
         | Operator::TableGet { .. }
         | Operator::TableSet { .. }
         | Operator::TableGrow { .. }
         | Operator::TableSize { .. } => {
             wasm_unsupported!("proposed bulk memory operator {:?}", op);
         }
+        Operator::V128Const { value } => {
+            let handle = builder.func.dfg.constants.insert(value.bytes().to_vec());
+            let value = builder.ins().vconst(I8X16, handle);
+            // the v128.const is typed in CLIF as a I8x16 but raw_bitcast to a different type before use
+            state.push1(value)
+        }
+        Operator::I8x16Splat
+        | Operator::I16x8Splat
+        | Operator::I32x4Splat
+        | Operator::I64x2Splat
+        | Operator::F32x4Splat
+        | Operator::F64x2Splat => {
+            let value_to_splat = state.pop1();
+            let ty = type_of(op);
+            let splatted = builder.ins().splat(ty, value_to_splat);
+            state.push1(splatted)
+        }
+        Operator::I32x4ExtractLane { lane }
+        | Operator::I64x2ExtractLane { lane }
+        | Operator::F32x4ExtractLane { lane }
+        | Operator::F64x2ExtractLane { lane } => {
+            let vector = optionally_bitcast_vector(state.pop1(), type_of(op), builder);
+            state.push1(builder.ins().extractlane(vector, lane.clone()))
+        }
+        Operator::I8x16ReplaceLane { lane }
+        | Operator::I16x8ReplaceLane { lane }
+        | Operator::I32x4ReplaceLane { lane }
+        | Operator::I64x2ReplaceLane { lane }
+        | Operator::F32x4ReplaceLane { lane }
+        | Operator::F64x2ReplaceLane { lane } => {
+            let (vector, replacement_value) = state.pop2();
+            let original_vector_type = builder.func.dfg.value_type(vector);
+            let vector = optionally_bitcast_vector(vector, type_of(op), builder);
+            let replaced_vector = builder
+                .ins()
+                .insertlane(vector, lane.clone(), replacement_value);
+            state.push1(optionally_bitcast_vector(
+                replaced_vector,
+                original_vector_type,
+                builder,
+            ))
+        }
         Operator::V128Load { .. }
         | Operator::V128Store { .. }
-        | Operator::V128Const { .. }
-        | Operator::V8x16Shuffle { .. }
-        | Operator::I8x16Splat
         | Operator::I8x16ExtractLaneS { .. }
         | Operator::I8x16ExtractLaneU { .. }
-        | Operator::I8x16ReplaceLane { .. }
-        | Operator::I16x8Splat
         | Operator::I16x8ExtractLaneS { .. }
         | Operator::I16x8ExtractLaneU { .. }
-        | Operator::I16x8ReplaceLane { .. }
-        | Operator::I32x4Splat
-        | Operator::I32x4ExtractLane { .. }
-        | Operator::I32x4ReplaceLane { .. }
-        | Operator::I64x2Splat
-        | Operator::I64x2ExtractLane { .. }
-        | Operator::I64x2ReplaceLane { .. }
-        | Operator::F32x4Splat
-        | Operator::F32x4ExtractLane { .. }
-        | Operator::F32x4ReplaceLane { .. }
-        | Operator::F64x2Splat
-        | Operator::F64x2ExtractLane { .. }
-        | Operator::F64x2ReplaceLane { .. }
+        | Operator::V8x16Shuffle { .. }
         | Operator::I8x16Eq
         | Operator::I8x16Ne
         | Operator::I8x16LtS
         | Operator::I8x16LtU
         | Operator::I8x16GtS
         | Operator::I8x16GtU
         | Operator::I8x16LeS
         | Operator::I8x16LeU
@@ -1286,8 +1311,179 @@ fn translate_br_if_args(
         } else {
             frame.num_return_values()
         };
         (return_count, frame.br_destination())
     };
     let inputs = state.peekn(return_count);
     (br_destination, inputs)
 }
+
+/// Determine the returned value type of a WebAssembly operator
+fn type_of(operator: &Operator) -> Type {
+    match operator {
+        Operator::V128Load { .. }
+        | Operator::V128Store { .. }
+        | Operator::V128Const { .. }
+        | Operator::V128Not
+        | Operator::V128And
+        | Operator::V128Or
+        | Operator::V128Xor
+        | Operator::V128Bitselect => I8X16, // default type representing V128
+
+        Operator::V8x16Shuffle { .. }
+        | Operator::I8x16Splat
+        | Operator::I8x16ExtractLaneS { .. }
+        | Operator::I8x16ExtractLaneU { .. }
+        | Operator::I8x16ReplaceLane { .. }
+        | Operator::I8x16Eq
+        | Operator::I8x16Ne
+        | Operator::I8x16LtS
+        | Operator::I8x16LtU
+        | Operator::I8x16GtS
+        | Operator::I8x16GtU
+        | Operator::I8x16LeS
+        | Operator::I8x16LeU
+        | Operator::I8x16GeS
+        | Operator::I8x16GeU
+        | Operator::I8x16Neg
+        | Operator::I8x16AnyTrue
+        | Operator::I8x16AllTrue
+        | Operator::I8x16Shl
+        | Operator::I8x16ShrS
+        | Operator::I8x16ShrU
+        | Operator::I8x16Add
+        | Operator::I8x16AddSaturateS
+        | Operator::I8x16AddSaturateU
+        | Operator::I8x16Sub
+        | Operator::I8x16SubSaturateS
+        | Operator::I8x16SubSaturateU
+        | Operator::I8x16Mul => I8X16,
+
+        Operator::I16x8Splat
+        | Operator::I16x8ExtractLaneS { .. }
+        | Operator::I16x8ExtractLaneU { .. }
+        | Operator::I16x8ReplaceLane { .. }
+        | Operator::I16x8Eq
+        | Operator::I16x8Ne
+        | Operator::I16x8LtS
+        | Operator::I16x8LtU
+        | Operator::I16x8GtS
+        | Operator::I16x8GtU
+        | Operator::I16x8LeS
+        | Operator::I16x8LeU
+        | Operator::I16x8GeS
+        | Operator::I16x8GeU
+        | Operator::I16x8Neg
+        | Operator::I16x8AnyTrue
+        | Operator::I16x8AllTrue
+        | Operator::I16x8Shl
+        | Operator::I16x8ShrS
+        | Operator::I16x8ShrU
+        | Operator::I16x8Add
+        | Operator::I16x8AddSaturateS
+        | Operator::I16x8AddSaturateU
+        | Operator::I16x8Sub
+        | Operator::I16x8SubSaturateS
+        | Operator::I16x8SubSaturateU
+        | Operator::I16x8Mul => I16X8,
+
+        Operator::I32x4Splat
+        | Operator::I32x4ExtractLane { .. }
+        | Operator::I32x4ReplaceLane { .. }
+        | Operator::I32x4Eq
+        | Operator::I32x4Ne
+        | Operator::I32x4LtS
+        | Operator::I32x4LtU
+        | Operator::I32x4GtS
+        | Operator::I32x4GtU
+        | Operator::I32x4LeS
+        | Operator::I32x4LeU
+        | Operator::I32x4GeS
+        | Operator::I32x4GeU
+        | Operator::I32x4Neg
+        | Operator::I32x4AnyTrue
+        | Operator::I32x4AllTrue
+        | Operator::I32x4Shl
+        | Operator::I32x4ShrS
+        | Operator::I32x4ShrU
+        | Operator::I32x4Add
+        | Operator::I32x4Sub
+        | Operator::I32x4Mul
+        | Operator::F32x4ConvertSI32x4
+        | Operator::F32x4ConvertUI32x4 => I32X4,
+
+        Operator::I64x2Splat
+        | Operator::I64x2ExtractLane { .. }
+        | Operator::I64x2ReplaceLane { .. }
+        | Operator::I64x2Neg
+        | Operator::I64x2AnyTrue
+        | Operator::I64x2AllTrue
+        | Operator::I64x2Shl
+        | Operator::I64x2ShrS
+        | Operator::I64x2ShrU
+        | Operator::I64x2Add
+        | Operator::I64x2Sub
+        | Operator::F64x2ConvertSI64x2
+        | Operator::F64x2ConvertUI64x2 => I64X2,
+
+        Operator::F32x4Splat
+        | Operator::F32x4ExtractLane { .. }
+        | Operator::F32x4ReplaceLane { .. }
+        | Operator::F32x4Eq
+        | Operator::F32x4Ne
+        | Operator::F32x4Lt
+        | Operator::F32x4Gt
+        | Operator::F32x4Le
+        | Operator::F32x4Ge
+        | Operator::F32x4Abs
+        | Operator::F32x4Neg
+        | Operator::F32x4Sqrt
+        | Operator::F32x4Add
+        | Operator::F32x4Sub
+        | Operator::F32x4Mul
+        | Operator::F32x4Div
+        | Operator::F32x4Min
+        | Operator::F32x4Max
+        | Operator::I32x4TruncSF32x4Sat
+        | Operator::I32x4TruncUF32x4Sat => F32X4,
+
+        Operator::F64x2Splat
+        | Operator::F64x2ExtractLane { .. }
+        | Operator::F64x2ReplaceLane { .. }
+        | Operator::F64x2Eq
+        | Operator::F64x2Ne
+        | Operator::F64x2Lt
+        | Operator::F64x2Gt
+        | Operator::F64x2Le
+        | Operator::F64x2Ge
+        | Operator::F64x2Abs
+        | Operator::F64x2Neg
+        | Operator::F64x2Sqrt
+        | Operator::F64x2Add
+        | Operator::F64x2Sub
+        | Operator::F64x2Mul
+        | Operator::F64x2Div
+        | Operator::F64x2Min
+        | Operator::F64x2Max
+        | Operator::I64x2TruncSF64x2Sat
+        | Operator::I64x2TruncUF64x2Sat => F64X2,
+
+        _ => unimplemented!(
+            "Currently only the SIMD instructions are translated to their return type: {:?}",
+            operator
+        ),
+    }
+}
+
+/// Some SIMD operations only operate on I8X16 in CLIF; this will convert them to that type by
+/// adding a raw_bitcast if necessary
+fn optionally_bitcast_vector(
+    value: Value,
+    needed_type: Type,
+    builder: &mut FunctionBuilder,
+) -> Value {
+    if builder.func.dfg.value_type(value) != needed_type {
+        builder.ins().raw_bitcast(needed_type, value)
+    } else {
+        value
+    }
+}
--- a/third_party/rust/cranelift-wasm/tests/wasm_testsuite.rs
+++ b/third_party/rust/cranelift-wasm/tests/wasm_testsuite.rs
@@ -5,17 +5,17 @@ use cranelift_codegen::verifier;
 use cranelift_wasm::{translate_module, DummyEnvironment, ReturnMode};
 use std::fs;
 use std::fs::File;
 use std::io;
 use std::io::prelude::*;
 use std::path::Path;
 use std::str::FromStr;
 use target_lexicon::triple;
-use wabt::wat2wasm;
+use wabt::{wat2wasm_with_features, Features};
 
 #[test]
 fn testsuite() {
     let mut paths: Vec<_> = fs::read_dir("../wasmtests")
         .unwrap()
         .map(|r| r.unwrap())
         .filter(|p| {
             // Ignore files starting with `.`, which could be editor temporary files
@@ -48,25 +48,27 @@ fn use_fallthrough_return() {
 fn read_file(path: &Path) -> io::Result<Vec<u8>> {
     let mut buf: Vec<u8> = Vec::new();
     let mut file = File::open(path)?;
     file.read_to_end(&mut buf)?;
     Ok(buf)
 }
 
 fn handle_module(path: &Path, flags: &Flags, return_mode: ReturnMode) {
+    let mut features = Features::new();
+    features.enable_all();
     let data = match path.extension() {
         None => {
             panic!("the file extension is not wasm or wat");
         }
         Some(ext) => match ext.to_str() {
             Some("wasm") => read_file(path).expect("error reading wasm file"),
             Some("wat") => {
                 let wat = read_file(path).expect("error reading wat file");
-                match wat2wasm(&wat) {
+                match wat2wasm_with_features(&wat, features) {
                     Ok(wasm) => wasm,
                     Err(e) => {
                         panic!("error converting wat to wasm: {:?}", e);
                     }
                 }
             }
             None | Some(&_) => panic!("the file extension for {:?} is not wasm or wat", path),
         },
--- a/toolkit/components/antitracking/test/browser/browser.ini
+++ b/toolkit/components/antitracking/test/browser/browser.ini
@@ -38,17 +38,17 @@ support-files =
   !/browser/base/content/test/general/head.js
 
 [browser_allowListNotifications.js]
 skip-if = serviceworker_e10s
 support-files = subResources.sjs
 [browser_addonHostPermissionIgnoredInTP.js]
 skip-if = fission
 [browser_allowListSeparationInPrivateAndNormalWindows.js]
-skip-if = os == "mac" && !debug # Bug 1503778
+skip-if = os == "mac" && !debug || fission # Bug 1503778, 1577362
 [browser_backgroundImageAssertion.js]
 [browser_blockingCookies.js]
 skip-if = fission
 [browser_blockingDOMCache.js]
 skip-if = fission
 [browser_blockingIndexedDb.js]
 skip-if = fission || (os == "linux" && asan)
 [browser_blockingIndexedDbInWorkers.js]
--- a/toolkit/components/extensions/parent/ext-contextualIdentities.js
+++ b/toolkit/components/extensions/parent/ext-contextualIdentities.js
@@ -114,19 +114,20 @@ const convertIdentityFromObserver = wrap
   return result;
 };
 
 ExtensionPreferencesManager.addSetting(CONTAINERS_ENABLED_SETTING_NAME, {
   prefNames: Object.keys(CONTAINER_PREF_INSTALL_DEFAULTS),
 
   setCallback(value) {
     if (value !== true) {
-      return Object.assign(CONTAINER_PREF_INSTALL_DEFAULTS, {
+      return {
+        ...CONTAINER_PREF_INSTALL_DEFAULTS,
         "privacy.userContext.extension": value,
-      });
+      };
     }
 
     let prefs = {};
     for (let pref of this.prefNames) {
       prefs[pref] = undefined;
     }
     return prefs;
   },
--- a/toolkit/components/search/SearchEngineSelector.jsm
+++ b/toolkit/components/search/SearchEngineSelector.jsm
@@ -91,16 +91,19 @@ class SearchEngineSelector {
     });
 
     let result = { engines };
 
     if (privateEngine) {
       result.privateDefault = privateEngine.engineName;
     }
 
+    if (SearchUtils.loggingEnabled) {
+      log("fetchEngineConfiguration: " + JSON.stringify(result));
+    }
     return result;
   }
 
   _sort(a, b) {
     return this._sortIndex(b) - this._sortIndex(a);
   }
 
   /**
--- a/toolkit/components/search/SearchService.jsm
+++ b/toolkit/components/search/SearchService.jsm
@@ -16,16 +16,17 @@ XPCOMUtils.defineLazyModuleGetters(this,
   AddonManager: "resource://gre/modules/AddonManager.jsm",
   clearTimeout: "resource://gre/modules/Timer.jsm",
   DeferredTask: "resource://gre/modules/DeferredTask.jsm",
   ExtensionParent: "resource://gre/modules/ExtensionParent.jsm",
   getVerificationHash: "resource://gre/modules/SearchEngine.jsm",
   OS: "resource://gre/modules/osfile.jsm",
   IgnoreLists: "resource://gre/modules/IgnoreLists.jsm",
   SearchEngine: "resource://gre/modules/SearchEngine.jsm",
+  SearchEngineSelector: "resource://gre/modules/SearchEngineSelector.jsm",
   SearchStaticData: "resource://gre/modules/SearchStaticData.jsm",
   SearchUtils: "resource://gre/modules/SearchUtils.jsm",
   Services: "resource://gre/modules/Services.jsm",
   setTimeout: "resource://gre/modules/Timer.jsm",
 });
 
 XPCOMUtils.defineLazyServiceGetters(this, {
   gEnvironment: ["@mozilla.org/process/environment;1", "nsIEnvironment"],
@@ -40,16 +41,23 @@ XPCOMUtils.defineLazyPreferenceGetter(
 
 XPCOMUtils.defineLazyPreferenceGetter(
   this,
   "gGeoSpecificDefaultsEnabled",
   SearchUtils.BROWSER_SEARCH_PREF + "geoSpecificDefaults",
   false
 );
 
+XPCOMUtils.defineLazyPreferenceGetter(
+  this,
+  "gModernConfig",
+  SearchUtils.BROWSER_SEARCH_PREF + "modernConfig",
+  false
+);
+
 // Can't use defineLazyPreferenceGetter because we want the value
 // from the default branch
 XPCOMUtils.defineLazyGetter(this, "distroID", () => {
   return Services.prefs.getDefaultBranch("distribution.").getCharPref("id", "");
 });
 
 // A text encoder to UTF8, used whenever we commit the cache to disk.
 XPCOMUtils.defineLazyGetter(this, "gEncoder", function() {
@@ -140,17 +148,17 @@ var ensureKnownRegion = async function(s
   // If we have a region already stored in our prefs we trust it.
   let region = Services.prefs.getCharPref("browser.search.region", "");
   try {
     if (!region) {
       // We don't have it cached, so fetch it. fetchRegion() will call
       // storeRegion if it gets a result (even if that happens after the
       // promise resolves) and fetchRegionDefault.
       await fetchRegion(ss);
-    } else if (gGeoSpecificDefaultsEnabled) {
+    } else if (gGeoSpecificDefaultsEnabled && !gModernConfig) {
       // The territory default we have already fetched may have expired.
       let expired = (ss.getGlobalAttr("searchDefaultExpir") || 0) <= Date.now();
       // If we have a default engine or a list of visible default engines
       // saved, the hashes should be valid, verify them now so that we can
       // refetch if they have been tampered with.
       let defaultEngine = ss.getVerifiedGlobalAttr("searchDefault");
       let visibleDefaultEngines = ss.getVerifiedGlobalAttr(
         "visibleDefaultEngines"
@@ -331,17 +339,17 @@ function fetchRegion(ss) {
         // so there's nothing else to do.
         if (timerId == null) {
           return;
         }
         clearTimeout(timerId);
         resolve();
       };
 
-      if (result && gGeoSpecificDefaultsEnabled) {
+      if (result && gGeoSpecificDefaultsEnabled && !gModernConfig) {
         fetchRegionDefault(ss)
           .then(callback)
           .catch(err => {
             Cu.reportError(err);
             callback();
           });
       } else {
         callback();
@@ -1108,21 +1116,24 @@ SearchService.prototype = {
     for (let loadDir of distDirs) {
       let enginesFromDir = await this._loadEnginesFromDir(loadDir);
       enginesFromDir.forEach(this._addEngineToStore, this);
     }
     if (AppConstants.platform == "android") {
       let enginesFromURLs = await this._loadFromChromeURLs(engines, isReload);
       enginesFromURLs.forEach(this._addEngineToStore, this);
     } else {
-      let engineList = this._enginesToLocales(engines);
-      for (let [id, locales] of engineList) {
-        await this.ensureBuiltinExtension(id, locales);
+      if (gModernConfig) {
+        await this._loadEnginesFromConfig(engines);
+      } else {
+        let engineList = this._enginesToLocales(engines);
+        for (let [id, locales] of engineList) {
+          await this.ensureBuiltinExtension(id, locales);
+        }
       }
-
       SearchUtils.log(
         "_loadEngines: loading " +
           this._startupExtensions.size +
           " engines reported by AddonManager startup"
       );
       for (let extension of this._startupExtensions) {
         await this._installExtensionEngine(extension, [DEFAULT_TAG], true);
       }
@@ -1133,16 +1144,29 @@ SearchService.prototype = {
     );
     this._loadEnginesFromCache(cache, true);
 
     this._loadEnginesMetadataFromCache(cache);
 
     SearchUtils.log("_loadEngines: done using rebuilt cache");
   },
 
+  async _loadEnginesFromConfig(engineConfigs) {
+    for (let config of engineConfigs) {
+      // TODO: Support multiple locales per engine
+      // https://bugzilla.mozilla.org/show_bug.cgi?id=1575555
+      SearchUtils.log("_loadEnginesFromConfig: " + JSON.stringify(config));
+      let locales =
+        "webExtensionLocale" in config
+          ? [config.webExtensionLocale]
+          : [DEFAULT_TAG];
+      await this.ensureBuiltinExtension(config.webExtensionId, locales);
+    }
+  },
+
   /**
    * Ensures a built in search WebExtension is installed, installing
    * it if necessary.
    *
    * @param {string} id
    *   The WebExtension ID.
    * @param {Array<string>} locales
    *   An array of locales to use for the WebExtension. If more than
@@ -1216,17 +1240,17 @@ SearchService.prototype = {
 
   /**
    * Reloads engines asynchronously, but only when the service has already been
    * initialized.
    */
   async _maybeReloadEngines() {
     // There's no point in already reloading the list of engines, when the service
     // hasn't even initialized yet.
-    if (!gInitialized) {
+    if (!gInitialized || gModernConfig) {
       return;
     }
 
     // Before we read the cache file, first make sure all pending tasks are clear.
     if (this._batchTask) {
       let task = this._batchTask;
       this._batchTask = null;
       await task.finalize();
@@ -1617,23 +1641,50 @@ SearchService.prototype = {
         engines.push(engine);
       } catch (ex) {
         SearchUtils.log("_loadFromChromeURLs: failed to load engine: " + ex);
       }
     }
     return engines;
   },
 
+  async _findEngineSelectorEngines() {
+    SearchUtils.log("_findEngineSelectorEngines: init");
+
+    let engineSelector = new SearchEngineSelector();
+    let locale = Services.locale.appLocaleAsBCP47;
+    // TODO: engineSelector needs to support default region, we cant
+    // just use "us" as a default region.
+    // https://bugzilla.mozilla.org/show_bug.cgi?id=1575554
+    let region = Services.prefs.getCharPref("browser.search.region", "us");
+
+    await engineSelector.init();
+    let { engines, privateDefault } = engineSelector.fetchEngineConfiguration(
+      region,
+      locale
+    );
+
+    this._searchDefault = engines[0].engineName;
+    this._searchOrder = engines.map(e => e.engineName);
+    if (privateDefault) {
+      this._searchPrivateDefault = privateDefault;
+    }
+    return engines;
+  },
+
   /**
    * Loads the list of engines from list.json
    *
    * @returns {Array<string>}
    *   Returns an array of engine names.
    */
   async _findEngines() {
+    if (gModernConfig) {
+      return this._findEngineSelectorEngines();
+    }
     SearchUtils.log("_findEngines: looking for engines in list.json");
 
     let chan = SearchUtils.makeChannel(this._listJSONURL);
     if (!chan) {
       SearchUtils.log(
         "_findEngines: " + this._listJSONURL + " isn't registered"
       );
       return [];
--- a/toolkit/components/search/SearchUtils.jsm
+++ b/toolkit/components/search/SearchUtils.jsm
@@ -13,23 +13,16 @@ const { XPCOMUtils } = ChromeUtils.impor
 );
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   Services: "resource://gre/modules/Services.jsm",
 });
 
 const BROWSER_SEARCH_PREF = "browser.search.";
 
-XPCOMUtils.defineLazyPreferenceGetter(
-  this,
-  "loggingEnabled",
-  BROWSER_SEARCH_PREF + "log",
-  false
-);
-
 var SearchUtils = {
   APP_SEARCH_PREFIX: "resource://search-plugins/",
 
   BROWSER_SEARCH_PREF,
 
   /**
    * Topic used for events involving the service itself.
    */
@@ -90,17 +83,17 @@ var SearchUtils = {
 
   /**
    * Outputs text to the JavaScript console as well as to stdout.
    *
    * @param {string} text
    *   The message to log.
    */
   log(text) {
-    if (loggingEnabled) {
+    if (SearchUtils.loggingEnabled) {
       dump("*** Search: " + text + "\n");
       Services.console.logStringMessage(text);
     }
   },
 
   /**
    * Logs the failure message (if browser.search.log is enabled) and throws.
    * @param {string} message
@@ -147,8 +140,15 @@ var SearchUtils = {
         Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
         Ci.nsIContentPolicy.TYPE_OTHER
       );
     } catch (ex) {}
 
     return null;
   },
 };
+
+XPCOMUtils.defineLazyPreferenceGetter(
+  SearchUtils,
+  "loggingEnabled",
+  BROWSER_SEARCH_PREF + "log",
+  false
+);
--- a/toolkit/components/search/moz.build
+++ b/toolkit/components/search/moz.build
@@ -22,30 +22,30 @@ XPIDL_MODULE = 'toolkit_search'
 
 if CONFIG['MOZ_BUILD_APP'] in ['browser', 'mobile/android', 'xulrunner']:
     EXTRA_JS_MODULES += [
         'Sidebar.jsm',
     ]
 
 EXTRA_JS_MODULES += [
     'SearchEngine.jsm',
+    'SearchEngineSelector.jsm',
     'SearchService.jsm',
     'SearchStaticData.jsm',
     'SearchSuggestionController.jsm',
     'SearchSuggestions.jsm',
     'SearchUtils.jsm',
 ]
 
 EXTRA_COMPONENTS += [
     'toolkitsearch.manifest',
 ]
 
 XPCOM_MANIFESTS += [
     'components.conf',
 ]
 
 TESTING_JS_MODULES += [
-    'SearchEngineSelector.jsm',
     'tests/SearchTestUtils.jsm',
 ]
 
 with Files('**'):
     BUG_COMPONENT = ('Firefox', 'Search')
--- a/toolkit/components/search/tests/xpcshell/searchconfigs/head_searchconfig.js
+++ b/toolkit/components/search/tests/xpcshell/searchconfigs/head_searchconfig.js
@@ -14,17 +14,17 @@ const { XPCOMUtils } = ChromeUtils.impor
   "resource://gre/modules/XPCOMUtils.jsm"
 );
 XPCOMUtils.defineLazyModuleGetters(this, {
   AddonManager: "resource://gre/modules/AddonManager.jsm",
   AddonTestUtils: "resource://testing-common/AddonTestUtils.jsm",
   ObjectUtils: "resource://gre/modules/ObjectUtils.jsm",
   OS: "resource://gre/modules/osfile.jsm",
   SearchEngine: "resource://gre/modules/SearchEngine.jsm",
-  SearchEngineSelector: "resource://testing-common/SearchEngineSelector.jsm",
+  SearchEngineSelector: "resource://gre/modules/SearchEngineSelector.jsm",
   SearchTestUtils: "resource://testing-common/SearchTestUtils.jsm",
   SearchUtils: "resource://gre/modules/SearchUtils.jsm",
   Services: "resource://gre/modules/Services.jsm",
 });
 
 const GLOBAL_SCOPE = this;
 
 const URLTYPE_SUGGEST_JSON = "application/x-suggestions+json";
--- a/toolkit/components/search/tests/xpcshell/test_engine_selector.js
+++ b/toolkit/components/search/tests/xpcshell/test_engine_selector.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
  *    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 XPCOMUtils.defineLazyModuleGetters(this, {
-  SearchEngineSelector: "resource://testing-common/SearchEngineSelector.jsm",
+  SearchEngineSelector: "resource://gre/modules/SearchEngineSelector.jsm",
 });
 
 const CONFIG_URL =
   "data:application/json," +
   JSON.stringify({
     data: [
       {
         engineName: "aol",
--- a/toolkit/crashreporter/tools/symbolstore.py
+++ b/toolkit/crashreporter/tools/symbolstore.py
@@ -835,31 +835,41 @@ class Dumper_Mac(Dumper):
         print("Running Mac pre-processing on file: %s" % (file,),
               file=sys.stderr)
 
         dsymbundle = file + ".dSYM"
         if os.path.exists(dsymbundle):
             shutil.rmtree(dsymbundle)
         dsymutil = buildconfig.substs['DSYMUTIL']
         # dsymutil takes --arch=foo instead of -a foo like everything else
-        try:
-            cmd = ([dsymutil] +
-                   [a.replace('-a ', '--arch=') for a in self.archs if a] +
-                   [file])
-            print(' '.join(cmd), file=sys.stderr)
-            subprocess.check_call(cmd, stdout=open(os.devnull, 'w'))
-        except subprocess.CalledProcessError as e:
-            print('Error running dsymutil: %s' % str(e), file=sys.stderr)
-            raise
+        cmd = ([dsymutil] +
+               [a.replace('-a ', '--arch=') for a in self.archs if a] +
+               [file])
+        print(' '.join(cmd), file=sys.stderr)
+
+        dsymutil_proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+                                         stderr=subprocess.PIPE)
+        dsymout, dsymerr = dsymutil_proc.communicate()
+        if dsymutil_proc.returncode != 0:
+            raise RuntimeError('Error running dsymutil: %s' % dsymerr)
 
+        # Regular dsymutil won't produce a .dSYM for files without symbols.
         if not os.path.exists(dsymbundle):
-            # dsymutil won't produce a .dSYM for files without symbols
             print("No symbols found in file: %s" % (file,), file=sys.stderr)
             return False
 
+        # llvm-dsymutil will produce a .dSYM for files without debug
+        # symbols, but only warns you in the output and doesn't actually
+        # fail.  We don't want to run dump_syms on such bundles, because
+        # asserts will fire in debug mode and who knows what will happen
+        # in release.
+        if 'warning: no debug symbols in' in dsymerr:
+            print(dsymerr, file=sys.stderr)
+            return False
+
         elapsed = time.time() - t_start
         print('Finished processing %s in %.2fs' % (file, elapsed),
               file=sys.stderr)
         return dsymbundle
 
     def CopyDebug(self, file, debug_file, guid, code_file, code_id):
         """ProcessFile has already produced a dSYM bundle, so we should just
         copy that to the destination directory. However, we'll package it
--- a/tools/lint/license.yml
+++ b/tools/lint/license.yml
@@ -1,32 +1,120 @@
 ---
 license:
     description: License Check
     include:
         - .
     exclude:
+        # These paths need to be triaged.
+        - accessible/jsat/Constants.jsm
+        - build/pgo/js-input
+        - build/workspace-hack/src/lib.rs
         - browser/app/blocklist.xml
         - browser/components/pocket/
+        - browser/components/shell/ScreenshotChild.jsm
+        - browser/extensions/webcompat/about-compat/aboutCompat.html
+        - browser/extensions/webcompat/injections/js
+        - config/external/ffi/preprocess_libffi_asm.py
+        - config/external/ffi/subst_header.py
         - config/external/nspr/_pl_bld.h
         - config/external/nspr/_pr_bld.h
+        - config/system_header_util.py
+        - devtools/client/debugger/bin
+        - devtools/client/debugger/dist
+        - devtools/client/jsonview/lib/require.js
+        - devtools/client/shared
+        - devtools/server/actors/utils/shapes-utils.js
+        - devtools/shared
+        - docshell/resources/content/netError.js
+        - dom/manifest/Manifest.jsm
+        - dom/manifest/ManifestIcons.jsm
         - gfx/2d/MMIHelpers.h
         - gfx/2d/ShadersD2D1.h
+        - gfx/angle/update-angle.py
+        - gfx/angle/vendor_from_git.py
+        - gfx/layers/layerviewer/index.html
+        - gfx/layers/layerviewer/layerTreeView.js
         - gfx/layers/protobuf/LayerScopePacket.pb.cc
         - gfx/layers/protobuf/LayerScopePacket.pb.h
         - gfx/thebes/CJKCompatSVS.cpp
+        - gfx/webrender_bindings/src/bindings.rs
+        - gfx/webrender_bindings/src/moz2d_renderer.rs
+        - gfx/webrender_bindings/src/program_cache.rs
+        - intl/l10n/L10nRegistry.jsm
+        - ipc/ipdl/ipdl/cxx/code.py
+        - js/rust/src
+        - js/src/builtin/Classes.js
+        - js/src/builtin/RegExpGlobalReplaceOpt.h.js
+        - js/src/builtin/RegExpLocalReplaceOpt.h.js
+        - js/src/builtin/TypedObject.js
+        - js/src/frontend/align_stack_comment.py
+        - js/src/frontend/binast/src/main.rs
+        - js/src/frontend/binast/src/refgraph.rs
         - js/src/builtin/intl/TimeZoneDataGenerated.h
+        - js/src/devtools
+        - js/src/gdb
         - js/src/irregexp/RegExpCharacters-inl.h
         - js/src/irregexp/RegExpCharacters.cpp
+        - js/src/lib.rs
+        - js/src/vm/jsopcode.py
+        - js/src/vm/make_opcode_doc.py
+        - js/xpconnect/loader/script_cache.py
+        - layout/style/tools/cleanup_computed_getters.py
+        - layout/style/tools/cleanup_keywords.py
+        - layout/style/tools/cleanup_ktables.py
+        - media/audioipc
         - media/libdav1d/vcs_version.h
+        - media/mtransport/mdns_service/mdns_service.h
+        - media/webrtc/signaling/src/sdp
+        - mobile/android/app/lint.xml
+        - mobile/android/app/src/main/AndroidManifest.xml
+        - mobile/android/app/src/main/res
+        - mobile/android/branding
+        - mobile/android/chrome/content/ExtensionPermissions.js
+        - mobile/android/components/extensions
+        - mobile/android/extensions/webcompat
+        - mobile/android/geckoview/src/main/AndroidManifest.xml
+        - mobile/android/geckoview/src/main/res/drawable/ic_generic_file.xml
+        - mobile/android/geckoview_example/src/main
+        - mobile/android/services/src/main/res
+        - modules/libpref/greprefs.js
         - mozglue/android/NativeCrypto.h
+        - netwerk/base/rust-helper/src/lib.rs
+        - parser/html/java/named-character-references.html
+        - python/l10n/convert_xul_to_fluent
+        - python/mozboot/support/ConEmu.xml
+        - python/mozbuild/mozbuild/action/tooltool.py
+        - python/mozbuild/mozbuild/artifact_commands.py
+        - python/mozbuild/mozbuild/export_telemetry_schema.py
+        - python/mozbuild/mozpack/hg.py
+        - python/mozrelease/mozrelease
+        - security/generate_certdata.py
+        - security/mac/hardenedruntime/developer.entitlements.xml
+        - security/mac/hardenedruntime/production.entitlements.xml
+        - services/sync/modules-testing/fxa_utils.js
+        - servo/components/hashglobe/src/alloc.rs
+        - servo/components/hashglobe/src/shim.rs
+        - taskcluster/docker/firefox-snap/extract_locales_from_l10n_json.py
+        - taskcluster/docker/index-task/insert-indexes.js
+        - taskcluster/scripts/misc/android-gradle-dependencies/nexus.xml
+        - taskcluster/scripts/misc/repack_rust.py
+        - taskcluster/taskgraph/util/declarative_artifacts.py
+        - taskcluster/taskgraph/util/partners.py
         - toolkit/components/reputationservice/chromium/chrome/common/safe_browsing/csd.pb.cc
         - toolkit/components/reputationservice/chromium/chrome/common/safe_browsing/csd.pb.h
         - toolkit/mozapps/update/updater/crctable.h
+        - tools/lint/eslint/eslint-plugin-mozilla/lib/configs
+        - xpcom/base/ErrorList.py
+        - xpcom/components/gen_static_components.py
+        - xpcom/ds/HTMLAtoms.py
+        - xpcom/idl-parser/setup.py
         - xpcom/io/crc32c.h
+        - xpcom/rust/gkrust_utils/src/lib.rs
+        - xpcom/rust/nserror/src/lib.rs
     extensions:
         - .c
         - .cc
         - .cpp
         - .h
         - .html
         - .js
         - .jsm
--- a/tools/rewriting/ThirdPartyPaths.txt
+++ b/tools/rewriting/ThirdPartyPaths.txt
@@ -1,16 +1,17 @@
+build/pymake
 browser/components/newtab/logs/
 browser/components/newtab/node_modules/
 browser/components/newtab/vendor/
 browser/components/translation/cld2/
 browser/extensions/screenshots/build/raven.js
 devtools/client/aboutdebugging/test/jest/node_modules/
 devtools/client/application/test/components/node_modules/
-devtools/client/debugger/flow-typed/npm/
+devtools/client/debugger/flow-typed/
 devtools/client/debugger/node_modules/
 devtools/client/shared/build/babel.js
 devtools/client/shared/sourceeditor/codemirror/
 devtools/client/shared/sourceeditor/tern/
 devtools/client/shared/vendor/
 devtools/shared/jsbeautify/
 devtools/shared/heapsnapshot/CoreDump.pb.cc
 devtools/shared/heapsnapshot/CoreDump.pb.h
@@ -93,17 +94,18 @@ media/libvpx/
 media/libwebp/
 media/libyuv/
 media/mtransport/third_party/
 media/openmax_dl/
 media/openmax_il/
 media/webrtc/signaling/src/sdp/sipcc/
 media/webrtc/trunk/
 mfbt/double-conversion/double-conversion/
-mfbt/lz4.*
+mfbt/lz4.c
+mfbt/lz4.h
 mobile/android/geckoview/src/thirdparty/
 mobile/android/thirdparty/
 modules/brotli/
 modules/fdlibm/
 modules/freetype2/
 modules/woff2/
 modules/xz-embedded/
 modules/zlib/
@@ -129,17 +131,16 @@ testing/web-platform/tests/tools/third_p
 testing/xpcshell/node-ip/
 testing/xpcshell/dns-packet/
 third_party/
 toolkit/components/certviewer/content/vendor/
 toolkit/components/jsoncpp/
 toolkit/components/normandy/vendor/
 toolkit/components/protobuf/
 toolkit/components/url-classifier/chromium/
-toolkit/components/url-classifier/protobuf/
 toolkit/components/utils/mozjexl.js
 toolkit/crashreporter/breakpad-client/
 toolkit/crashreporter/google-breakpad/
 toolkit/recordreplay/udis86/
 tools/fuzzing/libfuzzer/
 tools/profiler/core/vtune/
 xpcom/build/mach_override.c
 xpcom/build/mach_override.h