Merge autoland to mozilla-central. a=merge
authorcriss <ccozmuta@mozilla.com>
Thu, 19 May 2022 12:36:17 +0300
changeset 618192 ba856ffe455a3c5275f4255a5c4bce00ba5528d4
parent 618144 e602ffeedb64dca5837700381558bdc070f4a7b3 (current diff)
parent 618191 c2221e86cb617fa2947a9a82c47207569f171823 (diff)
child 618219 12b36415ea9261876f1325eb236fdd6b16b35fdc
push id39718
push userccozmuta@mozilla.com
push dateThu, 19 May 2022 09:37:29 +0000
treeherdermozilla-central@ba856ffe455a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone102.0a1
first release with
nightly linux32
ba856ffe455a / 102.0a1 / 20220519093729 / files
nightly linux64
ba856ffe455a / 102.0a1 / 20220519093729 / files
nightly mac
ba856ffe455a / 102.0a1 / 20220519093729 / files
nightly win32
ba856ffe455a / 102.0a1 / 20220519093729 / files
nightly win64
ba856ffe455a / 102.0a1 / 20220519093729 / 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
third_party/rust/arbitrary/tests/derive.rs
third_party/rust/clap/src/build/app/settings.rs
third_party/rust/clap/src/build/arg/mod.rs
third_party/rust/clap/src/build/arg/regex.rs
third_party/rust/clap/src/build/arg/settings.rs
third_party/rust/clap/src/build/arg/value_hint.rs
third_party/rust/unicode-segmentation/scripts/unicode.py
third_party/rust/unicode-segmentation/scripts/unicode_gen_breaktests.py
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -60,19 +60,19 @@ dependencies = [
  "android_log-sys",
  "env_logger",
  "lazy_static",
  "log",
 ]
 
 [[package]]
 name = "anyhow"
-version = "1.0.52"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3"
+version = "1.0.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc"
 
 [[package]]
 name = "app_services_logger"
 version = "0.1.0"
 dependencies = [
  "cstr",
  "golden_gate",
  "log",
@@ -89,19 +89,19 @@ source = "registry+https://github.com/ru
 checksum = "fc3ec9d4c47b25a5a9e5c848e053640331c7cedb1637434d75db68b79fee8a7f"
 dependencies = [
  "num-traits",
  "serde",
 ]
 
 [[package]]
 name = "arbitrary"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "510c76ecefdceada737ea728f4f9a84bd2e1ef29f1ba555e560940fe279954de"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c38b6b6b79f671c25e1a3e785b7b82d7562ffc9cd3efdc98627e5668a2472490"
 dependencies = [
  "derive_arbitrary",
 ]
 
 [[package]]
 name = "arrayref"
 version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -123,17 +123,17 @@ dependencies = [
 ]
 
 [[package]]
 name = "ash"
 version = "0.37.0+1.3.209"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "006ca68e0f2b03f22d6fa9f2860f85aed430d257fec20f8879b2145e7c7ae1a6"
 dependencies = [
- "libloading 0.7.2",
+ "libloading 0.7.3",
 ]
 
 [[package]]
 name = "ashmem"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b947f77692187a29daa2768b6644e589cef61e7434bb96300197acfb876105ac"
 dependencies = [
@@ -143,19 +143,19 @@ dependencies = [
 
 [[package]]
 name = "async-task"
 version = "4.0.3"
 source = "git+https://github.com/smol-rs/async-task?rev=f6488e35beccb26eb6e85847b02aa78a42cd3d0e#f6488e35beccb26eb6e85847b02aa78a42cd3d0e"
 
 [[package]]
 name = "async-trait"
-version = "0.1.52"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3"
+version = "0.1.53"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600"
 dependencies = [
  "proc-macro2",
  "quote",
  "syn",
 ]
 
 [[package]]
 name = "atomic"
@@ -438,19 +438,19 @@ source = "registry+https://github.com/ru
 checksum = "25c3d626f0280ec39b33a6fc5c6c1067432b4c41e94aee40ded197a6649bf025"
 dependencies = [
  "bitflags",
  "serde",
 ]
 
 [[package]]
 name = "bitreader"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd5bf8a17cdc06d475689f9e9226f4b5bf5610e93cf5c3010a518fe6fb0d97f5"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d84ea71c85d1fe98fe67a9b9988b1695bc24c0b0d3bfb18d4c510f44b4b09941"
 dependencies = [
  "cfg-if 1.0.0",
 ]
 
 [[package]]
 name = "bits"
 version = "0.2.0"
 dependencies = [
@@ -594,19 +594,19 @@ dependencies = [
  "nsstring",
  "rust_cascade",
  "thin-vec",
  "xpcom",
 ]
 
 [[package]]
 name = "cc"
-version = "1.0.72"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
+version = "1.0.73"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
 
 [[package]]
 name = "cert_storage"
 version = "0.0.1"
 dependencies = [
  "base64 0.10.1",
  "byteorder",
  "crossbeam-utils 0.8.8",
@@ -688,23 +688,23 @@ dependencies = [
 [[package]]
 name = "chunky-vec"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bb7bdea464ae038f09197b82430b921c53619fc8d2bcaf7b151013b3ca008017"
 
 [[package]]
 name = "clang-sys"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa66045b9cb23c2e9c1520732030608b02ee07e5cfaa5a521ec15ded7fa24c90"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf6b561dcf059c85bbe388e0a7b0a1469acb3934cc0cfa148613a830629e3049"
 dependencies = [
  "glob",
  "libc",
- "libloading 0.7.2",
+ "libloading 0.7.3",
 ]
 
 [[package]]
 name = "clap"
 version = "3.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375"
 dependencies = [
@@ -758,19 +758,19 @@ dependencies = [
 [[package]]
 name = "copyless"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536"
 
 [[package]]
 name = "core-foundation"
-version = "0.9.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
 dependencies = [
  "core-foundation-sys",
  "libc",
 ]
 
 [[package]]
 name = "core-foundation-sys"
 version = "0.8.3"
@@ -811,19 +811,19 @@ dependencies = [
  "core-foundation",
  "core-graphics",
  "foreign-types",
  "libc",
 ]
 
 [[package]]
 name = "coreaudio-sys"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b7e3347be6a09b46aba228d6608386739fb70beff4f61e07422da87b0bb31fa"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca4679a59dbd8c15f064c012dfe8c1163b9453224238b59bb9328c142b8b248b"
 dependencies = [
  "bindgen",
 ]
 
 [[package]]
 name = "coreaudio-sys-utils"
 version = "0.1.0"
 source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=44eca95823bb57e964cf7b6d9791ed2ccb4b2108#44eca95823bb57e964cf7b6d9791ed2ccb4b2108"
@@ -839,19 +839,19 @@ source = "git+https://github.com/chris-z
 dependencies = [
  "core-foundation",
  "core-foundation-sys",
  "coremidi-sys",
 ]
 
 [[package]]
 name = "coremidi-sys"
-version = "3.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b49674d86f634be42bba110d6b2fa0b047bd5a2bbd02fcba776b56030899f20d"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79a6deed0c97b2d40abbab77e4c97f81d71e162600423382c277dd640019116c"
 dependencies = [
  "core-foundation-sys",
 ]
 
 [[package]]
 name = "cose"
 version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -895,17 +895,17 @@ checksum = "baf9bf1ffffb6ce3d2e5ebc83549
 dependencies = [
  "cranelift-bforest",
  "cranelift-codegen-meta",
  "cranelift-codegen-shared",
  "cranelift-entity",
  "log",
  "regalloc",
  "smallvec",
- "target-lexicon 0.12.2",
+ "target-lexicon 0.12.3",
 ]
 
 [[package]]
 name = "cranelift-codegen-meta"
 version = "0.74.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4cc21936a5a6d07e23849ffe83e5c1f6f50305c074f4b2970ca50c13bf55b821"
 dependencies = [
@@ -929,17 +929,17 @@ checksum = "7d6b4a8bef04f82e4296782646f7
 name = "cranelift-frontend"
 version = "0.74.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c31b783b351f966fce33e3c03498cb116d16d97a8f9978164a60920bd0d3a99c"
 dependencies = [
  "cranelift-codegen",
  "log",
  "smallvec",
- "target-lexicon 0.12.2",
+ "target-lexicon 0.12.3",
 ]
 
 [[package]]
 name = "cranelift-wasm"
 version = "0.74.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "edb6d408e2da77cdbbd65466298d44c86ae71c1785d2ab0d8657753cdb4d9d89"
 dependencies = [
@@ -950,19 +950,19 @@ dependencies = [
  "log",
  "smallvec",
  "thiserror",
  "wasmparser",
 ]
 
 [[package]]
 name = "crc32fast"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
 dependencies = [
  "cfg-if 1.0.0",
 ]
 
 [[package]]
 name = "crossbeam-channel"
 version = "0.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1075,17 +1075,17 @@ dependencies = [
 [[package]]
 name = "cssparser"
 version = "0.29.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "031d29b6d1ea84f63436e45fb6f3c1a3d62dc1650018c53fa7165e108d35d88f"
 dependencies = [
  "cssparser-macros",
  "dtoa-short",
- "itoa",
+ "itoa 0.4.999",
  "matches",
  "phf",
  "proc-macro2",
  "quote",
  "smallvec",
  "syn",
 ]
 
@@ -1096,19 +1096,19 @@ source = "registry+https://github.com/ru
 checksum = "dfae75de57f2b2e85e8768c3ea840fd159c8f33e2b6522c7835b7abac81be16e"
 dependencies = [
  "quote",
  "syn",
 ]
 
 [[package]]
 name = "cstr"
-version = "0.2.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2846d3636dcaff720d311ea8983f5fa7a8288632b2f95145dd4b5819c397fd8"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a60f0dd132e4b67f20fd764d4835d968f666ff1a2f59e432983d168b98424deb"
 dependencies = [
  "proc-macro2",
  "quote",
 ]
 
 [[package]]
 name = "cty"
 version = "0.2.2"
@@ -1184,49 +1184,49 @@ dependencies = [
 ]
 
 [[package]]
 name = "d3d12"
 version = "0.4.1"
 source = "git+https://github.com/gfx-rs/d3d12-rs.git?rev=ffe5e261da0a6cb85332b82ab310abd2a7e849f6#ffe5e261da0a6cb85332b82ab310abd2a7e849f6"
 dependencies = [
  "bitflags",
- "libloading 0.7.2",
+ "libloading 0.7.3",
  "winapi",
 ]
 
 [[package]]
 name = "darling"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
 dependencies = [
  "darling_core",
  "darling_macro",
 ]
 
 [[package]]
 name = "darling_core"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
 dependencies = [
  "fnv",
  "ident_case",
  "proc-macro2",
  "quote",
  "strsim",
  "syn",
 ]
 
 [[package]]
 name = "darling_macro"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
 dependencies = [
  "darling_core",
  "quote",
  "syn",
 ]
 
 [[package]]
 name = "dashmap"
@@ -1267,19 +1267,19 @@ dependencies = [
  "viaduct",
  "winapi",
  "wineventlog",
  "wio",
 ]
 
 [[package]]
 name = "derive_arbitrary"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b24629208e87a2d8b396ff43b15c4afb0a69cea3fbbaa9ed9b92b7c02f0aed73"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "98e23c06c035dac87bd802d98f368df73a7f2cb05a66ffbd1f377e821fac4af9"
 dependencies = [
  "proc-macro2",
  "quote",
  "syn",
 ]
 
 [[package]]
 name = "derive_common"
@@ -1434,28 +1434,28 @@ source = "registry+https://github.com/ru
 checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b"
 dependencies = [
  "cfg-if 1.0.0",
  "packed_simd_2",
 ]
 
 [[package]]
 name = "enumset"
-version = "1.0.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6216d2c19a6fb5f29d1ada1dc7bc4367a8cbf0fa4af5cf12e07b5bbdde6b5b2c"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4799cdb24d48f1f8a7a98d06b7fde65a85a2d1e42b25a889f5406aa1fbefe074"
 dependencies = [
  "enumset_derive",
 ]
 
 [[package]]
 name = "enumset_derive"
-version = "0.5.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6451128aa6655d880755345d085494cf7561a6bee7c8dc821e5d77e6d267ecd4"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea83a3fbdc1d999ccfbcbee717eab36f8edf2d71693a23ce0d7cca19e085304c"
 dependencies = [
  "darling",
  "proc-macro2",
  "quote",
  "syn",
 ]
 
 [[package]]
@@ -1482,30 +1482,30 @@ dependencies = [
 
 [[package]]
 name = "error-support"
 version = "0.1.0"
 source = "git+https://github.com/mozilla/application-services?rev=c51b63595a27a6ef45161012323e0261475c10c9#c51b63595a27a6ef45161012323e0261475c10c9"
 
 [[package]]
 name = "etagere"
-version = "0.2.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5eb66dc3d6bb6b2ab4a12454db6988079311d6443e627bc7e6065f907f556272"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6301151a318f367f392c31395beb1cfba5ccd9abc44d1db0db3a4b27b9601c89"
 dependencies = [
  "euclid",
  "serde",
  "svg_fmt",
 ]
 
 [[package]]
 name = "euclid"
-version = "0.22.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da96828553a086d7b18dcebfc579bd9628b016f86590d7453c115e490fa74b80"
+version = "0.22.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b52c2ef4a78da0ba68fbe1fd920627411096d2ac478f7f4c9f3a54ba6705bade"
 dependencies = [
  "num-traits",
  "serde",
 ]
 
 [[package]]
 name = "fallible-iterator"
 version = "0.2.0"
@@ -1544,19 +1544,19 @@ source = "registry+https://github.com/ru
 checksum = "b12c2c8d7d9f04d7952cc33bac89b7425fb3cf4c44773b06ea49ac3df259ac57"
 dependencies = [
  "comedy",
  "winapi",
 ]
 
 [[package]]
 name = "flate2"
-version = "1.0.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af"
 dependencies = [
  "cfg-if 1.0.0",
  "crc32fast",
  "libc",
  "miniz_oxide",
 ]
 
 [[package]]
@@ -1599,30 +1599,30 @@ dependencies = [
 name = "fluent-fallback"
 version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e0ebe8c34b89a10c8a431de9c0c5c2005b79c438d9a498a028c4e05b88afb3d6"
 dependencies = [
  "async-trait",
  "chunky-vec",
  "fluent-bundle",
- "futures 0.3.19",
+ "futures 0.3.21",
  "once_cell",
  "unic-langid",
 ]
 
 [[package]]
 name = "fluent-ffi"
 version = "0.1.0"
 dependencies = [
  "cstr",
  "fluent",
  "fluent-fallback",
  "fluent-pseudo",
- "futures 0.3.19",
+ "futures 0.3.21",
  "intl-memoizer",
  "l10nregistry",
  "nsstring",
  "thin-vec",
  "unic-langid",
  "xpcom",
 ]
 
@@ -1771,109 +1771,109 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a4
 [[package]]
 name = "futures"
 version = "0.1.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"
 
 [[package]]
 name = "futures"
-version = "0.3.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4"
+version = "0.3.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e"
 dependencies = [
  "futures-channel",
  "futures-core",
  "futures-executor",
  "futures-io",
  "futures-sink",
  "futures-task",
  "futures-util",
 ]
 
 [[package]]
 name = "futures-channel"
-version = "0.3.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b"
+version = "0.3.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
 dependencies = [
  "futures-core",
  "futures-sink",
 ]
 
 [[package]]
 name = "futures-core"
-version = "0.3.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7"
+version = "0.3.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
 
 [[package]]
 name = "futures-cpupool"
 version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
 dependencies = [
  "futures 0.1.31",
  "num_cpus",
 ]
 
 [[package]]
 name = "futures-executor"
-version = "0.3.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a"
+version = "0.3.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6"
 dependencies = [
  "futures-core",
  "futures-task",
  "futures-util",
 ]
 
 [[package]]
 name = "futures-io"
-version = "0.3.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2"
+version = "0.3.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b"
 
 [[package]]
 name = "futures-macro"
-version = "0.3.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c"
+version = "0.3.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512"
 dependencies = [
  "proc-macro2",
  "quote",
  "syn",
 ]
 
 [[package]]
 name = "futures-sink"
-version = "0.3.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508"
+version = "0.3.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
 
 [[package]]
 name = "futures-task"
-version = "0.3.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72"
+version = "0.3.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a"
 
 [[package]]
 name = "futures-util"
-version = "0.3.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164"
+version = "0.3.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a"
 dependencies = [
  "futures-channel",
  "futures-core",
  "futures-io",
  "futures-macro",
  "futures-sink",
  "futures-task",
  "memchr",
- "pin-project-lite 0.2.7",
+ "pin-project-lite 0.2.9",
  "pin-utils",
  "slab",
 ]
 
 [[package]]
 name = "fxhash"
 version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2250,19 +2250,19 @@ dependencies = [
  "storage_variant",
  "sync15-traits",
  "thin-vec",
  "xpcom",
 ]
 
 [[package]]
 name = "gpu-alloc"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e64cbb8d36508d3e19da95e56e196a84f674fc190881f2cc010000798838aa6"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fc59e5f710e310e76e6707f86c561dd646f69a8876da9131703b2f717de818d"
 dependencies = [
  "bitflags",
  "gpu-alloc-types",
 ]
 
 [[package]]
 name = "gpu-alloc-types"
 version = "0.2.0"
@@ -2382,17 +2382,17 @@ checksum = "dfa686283ad6dd069f105e5ab091
 [[package]]
 name = "http"
 version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b"
 dependencies = [
  "bytes 1.1.0",
  "fnv",
- "itoa",
+ "itoa 0.4.999",
 ]
 
 [[package]]
 name = "http-body"
 version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b"
 dependencies = [
@@ -2424,19 +2424,19 @@ dependencies = [
  "nsstring",
  "sfv",
  "thin-vec",
  "xpcom",
 ]
 
 [[package]]
 name = "httparse"
-version = "1.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503"
+version = "1.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c"
 
 [[package]]
 name = "httpdate"
 version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
 
 [[package]]
@@ -2454,17 +2454,17 @@ dependencies = [
  "bytes 0.5.6",
  "futures-channel",
  "futures-core",
  "futures-util",
  "h2",
  "http",
  "http-body",
  "httparse",
- "itoa",
+ "itoa 0.4.999",
  "log",
  "pin-project",
  "socket2",
  "time",
  "tokio 0.2.25",
  "tower-service",
  "want",
 ]
@@ -2595,19 +2595,26 @@ version = "0.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
 dependencies = [
  "either",
 ]
 
 [[package]]
 name = "itoa"
-version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
+version = "0.4.999"
+dependencies = [
+ "itoa 1.0.2",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
 
 [[package]]
 name = "jobserver"
 version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa"
 dependencies = [
  "libc",
@@ -2723,17 +2730,17 @@ dependencies = [
 
 [[package]]
 name = "khronos-egl"
 version = "4.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3"
 dependencies = [
  "libc",
- "libloading 0.7.2",
+ "libloading 0.7.3",
  "pkg-config",
 ]
 
 [[package]]
 name = "khronos_api"
 version = "3.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
@@ -2762,35 +2769,35 @@ dependencies = [
 [[package]]
 name = "l10nregistry"
 version = "0.3.0"
 dependencies = [
  "async-trait",
  "fluent-bundle",
  "fluent-fallback",
  "fluent-testing",
- "futures 0.3.19",
- "pin-project-lite 0.2.7",
+ "futures 0.3.21",
+ "pin-project-lite 0.2.9",
  "replace_with",
  "rustc-hash",
  "serial_test",
  "tokio 1.17.0",
  "unic-langid",
 ]
 
 [[package]]
 name = "l10nregistry-ffi"
 version = "0.1.0"
 dependencies = [
  "async-trait",
  "cstr",
  "fluent",
  "fluent-fallback",
  "fluent-ffi",
- "futures 0.3.19",
+ "futures 0.3.21",
  "futures-channel",
  "l10nregistry",
  "libc",
  "log",
  "moz_task",
  "nserror",
  "nsstring",
  "thin-vec",
@@ -2821,19 +2828,19 @@ checksum = "830d08ce1d1d941e6b30645f1a0e
 [[package]]
 name = "leb128"
 version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
 
 [[package]]
 name = "libc"
-version = "0.2.112"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
+version = "0.2.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
 
 [[package]]
 name = "libdbus-sys"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c185b5b7ad900923ef3a8ff594083d4d9b5aea80bb4f32b8342363138c0d456b"
 dependencies = [
  "pkg-config",
@@ -2846,19 +2853,19 @@ source = "registry+https://github.com/ru
 checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753"
 dependencies = [
  "cc",
  "winapi",
 ]
 
 [[package]]
 name = "libloading"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afe203d669ec979b7128619bae5a63b7b42e9203c1b29146079ee05e2f604b52"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
 dependencies = [
  "cfg-if 1.0.0",
  "winapi",
 ]
 
 [[package]]
 name = "libsqlite3-sys"
 version = "0.20.1"
@@ -2930,17 +2937,17 @@ dependencies = [
 name = "localization-ffi"
 version = "0.1.0"
 dependencies = [
  "async-trait",
  "cstr",
  "fluent",
  "fluent-fallback",
  "fluent-ffi",
- "futures 0.3.19",
+ "futures 0.3.21",
  "futures-channel",
  "l10nregistry",
  "l10nregistry-ffi",
  "moz_task",
  "nserror",
  "nsstring",
  "thin-vec",
  "unic-langid",
@@ -3054,19 +3061,19 @@ dependencies = [
 [[package]]
 name = "memalloc"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "df39d232f5c40b0891c10216992c2f250c054105cb1e56f0fc9032db6203ecc1"
 
 [[package]]
 name = "memchr"
-version = "2.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 
 [[package]]
 name = "memmap2"
 version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "723e3ebdcdc5c023db1df315364573789f8857c11b631a2fdfad7c00f5c046b4"
 dependencies = [
  "libc",
@@ -3142,19 +3149,19 @@ dependencies = [
 [[package]]
 name = "mime"
 version = "0.3.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
 
 [[package]]
 name = "mime_guess"
-version = "2.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212"
+version = "2.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
 dependencies = [
  "mime",
  "unicase",
 ]
 
 [[package]]
 name = "minidump_writer_linux"
 version = "0.1.0"
@@ -3167,22 +3174,21 @@ dependencies = [
  "memoffset 0.5.6",
  "nix",
  "tempfile",
  "thiserror",
 ]
 
 [[package]]
 name = "miniz_oxide"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082"
 dependencies = [
  "adler",
- "autocfg",
 ]
 
 [[package]]
 name = "mio"
 version = "0.6.23"
 dependencies = [
  "cfg-if 0.1.10",
  "fuchsia-zircon",
@@ -3616,19 +3622,19 @@ dependencies = [
 name = "nsstring-gtest"
 version = "0.1.0"
 dependencies = [
  "nsstring",
 ]
 
 [[package]]
 name = "ntapi"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f"
 dependencies = [
  "winapi",
 ]
 
 [[package]]
 name = "num-bigint"
 version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3647,29 +3653,29 @@ checksum = "876a53fff98e03a936a674b29568
 dependencies = [
  "proc-macro2",
  "quote",
  "syn",
 ]
 
 [[package]]
 name = "num-integer"
-version = "0.1.44"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
 dependencies = [
  "autocfg",
  "num-traits",
 ]
 
 [[package]]
 name = "num-traits"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
 dependencies = [
  "autocfg",
 ]
 
 [[package]]
 name = "num_cpus"
 version = "1.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3707,19 +3713,19 @@ dependencies = [
  "goblin",
  "scroll",
  "target-lexicon 0.9.0",
  "uuid",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
 
 [[package]]
 name = "ordered-float"
 version = "1.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3305af35278dd29f46fcdd139e0b1fbfae2153f0e5928b39b035542dd31e37b7"
 dependencies = [
  "num-traits",
@@ -3739,19 +3745,19 @@ dependencies = [
 name = "origin-trials-ffi"
 version = "0.1.0"
 dependencies = [
  "origin-trial-token",
 ]
 
 [[package]]
 name = "os_str_bytes"
-version = "6.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
+version = "6.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "029d8d0b2f198229de29dca79676f2738ff952edf3fde542eb8bf94d8c21b435"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "osclientcerts-static"
 version = "0.1.4"
 dependencies = [
@@ -3948,19 +3954,19 @@ dependencies = [
 [[package]]
 name = "pin-project-lite"
 version = "0.1.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777"
 
 [[package]]
 name = "pin-project-lite"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
 
 [[package]]
 name = "pin-utils"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 
 [[package]]
@@ -3970,19 +3976,19 @@ source = "registry+https://github.com/ru
 checksum = "45712272d3a9d9a26471f6bee1596574d38df0136dd7eb163ed736913dc1f6bf"
 dependencies = [
  "libloading 0.5.2",
  "num-bigint",
 ]
 
 [[package]]
 name = "pkg-config"
-version = "0.3.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
+version = "0.3.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
 
 [[package]]
 name = "plain"
 version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
 
 [[package]]
@@ -4036,19 +4042,19 @@ version = "0.0.1"
 [[package]]
 name = "proc-macro-hack"
 version = "0.5.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.36"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa"
 dependencies = [
  "unicode-xid",
 ]
 
 [[package]]
 name = "processtools"
 version = "0.1.0"
 dependencies = [
@@ -4147,19 +4153,19 @@ dependencies = [
 [[package]]
 name = "quick-error"
 version = "1.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
 
 [[package]]
 name = "quote"
-version = "1.0.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
 name = "rand"
 version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4213,45 +4219,44 @@ dependencies = [
 [[package]]
 name = "range-alloc"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "63e935c45e09cc6dcf00d2f0b2d630a58f4095320223d47fc68918722f0538b6"
 
 [[package]]
 name = "raw-window-handle"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fba75eee94a9d5273a68c9e1e105d9cffe1ef700532325788389e5a83e2522b7"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41"
 dependencies = [
  "cty",
 ]
 
 [[package]]
 name = "rayon"
-version = "1.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
+version = "1.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
 dependencies = [
  "autocfg",
  "crossbeam-deque 0.8.1",
  "either",
  "rayon-core",
 ]
 
 [[package]]
 name = "rayon-core"
-version = "1.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
 dependencies = [
  "crossbeam-channel",
  "crossbeam-deque 0.8.1",
  "crossbeam-utils 0.8.8",
- "lazy_static",
  "num_cpus",
 ]
 
 [[package]]
 name = "redox_syscall"
 version = "0.1.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
@@ -4321,19 +4326,19 @@ checksum = "f1382d1f0a252c4bf97dc20d979a
 [[package]]
 name = "replace_with"
 version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e3a8614ee435691de62bcffcf4a66d91b3594bf1428a5722e79103249a095690"
 
 [[package]]
 name = "ringbuf"
-version = "0.2.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c60f3923939c33e6c543ddbff14d0ee6a407fcd186d560be37282559616adf3"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f65af18d50f789e74aaf23bbb3f65dcd22a3cb6e029b5bced149f6bd57c5c2a2"
 dependencies = [
  "cache-padded",
 ]
 
 [[package]]
 name = "rkv"
 version = "0.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4434,19 +4439,19 @@ dependencies = [
  "byteorder",
  "murmurhash3",
  "rand",
  "sha2",
 ]
 
 [[package]]
 name = "rust_decimal"
-version = "1.20.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0593ce4677e3800ddafb3de917e8397b1348e06e688128ade722d88fbe11ebf"
+version = "1.23.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22dc69eadbf0ee2110b8d20418c0c6edbaefec2811c4963dc17b6344e11fe0f8"
 dependencies = [
  "arrayvec 0.7.2",
  "num-traits",
  "serde",
 ]
 
 [[package]]
 name = "rust_minidump_writer_linux"
@@ -4476,19 +4481,19 @@ version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
 dependencies = [
  "semver",
 ]
 
 [[package]]
 name = "ryu"
-version = "1.0.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
 
 [[package]]
 name = "safemem"
 version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
 
 [[package]]
@@ -4570,104 +4575,105 @@ dependencies = [
 [[package]]
 name = "semver-parser"
 version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
 
 [[package]]
 name = "serde"
-version = "1.0.133"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a"
+version = "1.0.136"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_bytes"
-version = "0.11.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9"
+version = "0.11.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "212e73464ebcde48d723aa02eb270ba62eff38a9b732df31f33f1b4e145f3a54"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.133"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537"
+version = "1.0.136"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
 dependencies = [
  "proc-macro2",
  "quote",
  "syn",
 ]
 
 [[package]]
 name = "serde_json"
 version = "1.0.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527"
 dependencies = [
  "indexmap",
- "itoa",
+ "itoa 0.4.999",
  "ryu",
  "serde",
 ]
 
 [[package]]
 name = "serde_repr"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed"
 dependencies = [
  "proc-macro2",
  "quote",
  "syn",
 ]
 
 [[package]]
 name = "serde_urlencoded"
 version = "0.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97"
 dependencies = [
  "dtoa",
- "itoa",
+ "itoa 0.4.999",
  "serde",
  "url",
 ]
 
 [[package]]
 name = "serde_with"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89d3d595d64120bbbc70b7f6d5ae63298b62a3d9f373ec2f56acf5365ca8a444"
+version = "1.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b44be9227e214a0420707c9ca74c2d4991d9955bae9415a8f93f05cebf561be5"
 dependencies = [
  "serde",
  "serde_with_macros",
 ]
 
 [[package]]
 name = "serde_with_macros"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4070d2c9b9d258465ad1d82aabb985b84cd9a3afa94da25ece5a9938ba5f1606"
-dependencies = [
+version = "1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
+dependencies = [
+ "darling",
  "proc-macro2",
  "quote",
  "syn",
 ]
 
 [[package]]
 name = "serde_yaml"
-version = "0.8.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0"
+version = "0.8.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "707d15895415db6628332b737c838b88c598522e4dc70647e59b72312924aebc"
 dependencies = [
  "indexmap",
  "ryu",
  "serde",
  "yaml-rust",
 ]
 
 [[package]]
@@ -4735,25 +4741,25 @@ dependencies = [
 [[package]]
 name = "shlex"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
 
 [[package]]
 name = "siphasher"
-version = "0.3.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba1eead9e94aa5a2e02de9e7839f96a007f686ae7a1d57c7797774810d24908a"
+version = "0.3.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
 
 [[package]]
 name = "slab"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32"
 
 [[package]]
 name = "slotmap"
 version = "1.100.0"
 
 [[package]]
 name = "smallbitvec"
 version = "2.5.1"
@@ -4873,17 +4879,17 @@ dependencies = [
  "byteorder",
  "cssparser",
  "derive_more",
  "euclid",
  "fxhash",
  "gecko-profiler",
  "indexmap",
  "itertools 0.8.2",
- "itoa",
+ "itoa 0.4.999",
  "lazy_static",
  "log",
  "malloc_size_of",
  "malloc_size_of_derive",
  "matches",
  "mozbuild",
  "new_debug_unreachable",
  "nsstring",
@@ -4967,19 +4973,19 @@ dependencies = [
  "cc",
  "gleam",
  "glsl-to-cxx",
  "webrender_build",
 ]
 
 [[package]]
 name = "syn"
-version = "1.0.85"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7"
+version = "1.0.94"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a07e33e919ebcd69113d5be0e4d70c5707004ff45188910106854f38b960df4a"
 dependencies = [
  "proc-macro2",
  "quote",
  "unicode-xid",
 ]
 
 [[package]]
 name = "sync-guid"
@@ -5021,19 +5027,19 @@ dependencies = [
 [[package]]
 name = "target-lexicon"
 version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6f4c118a7a38378f305a9e111fcb2f7f838c0be324bfb31a77ea04f7f6e684b4"
 
 [[package]]
 name = "target-lexicon"
-version = "0.12.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9bffcddbc2458fa3e6058414599e3c838a022abae82e5c67b4f7f80298d5bff"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7fa7e55043acb85fca6b3c01485a2eeb6b69c5d21002e273c79e465f43b7ac1"
 
 [[package]]
 name = "tempfile"
 version = "3.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
 dependencies = [
  "cfg-if 0.1.10",
@@ -5041,19 +5047,19 @@ dependencies = [
  "rand",
  "redox_syscall",
  "remove_dir_all",
  "winapi",
 ]
 
 [[package]]
 name = "termcolor"
-version = "1.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
 dependencies = [
  "winapi-util",
 ]
 
 [[package]]
 name = "terminal_size"
 version = "0.1.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5075,39 +5081,39 @@ dependencies = [
 [[package]]
 name = "thin-vec"
 version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ceb94bb4b121597e14f054e8c3368afd6e7219a64598037bd480184b456a5df4"
 
 [[package]]
 name = "thiserror"
-version = "1.0.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
+version = "1.0.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
+version = "1.0.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
 dependencies = [
  "proc-macro2",
  "quote",
  "syn",
 ]
 
 [[package]]
 name = "threadbound"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b5b2bd897775cb425729882f0710639eb69f3d784db834ee85941ae9c35bb83"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef6645e1b5481da27f21f74e1b360b83215f5765420881e3d2eefdcd3d1a6de3"
 
 [[package]]
 name = "time"
 version = "0.1.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
 dependencies = [
  "libc",
@@ -5186,17 +5192,17 @@ dependencies = [
 name = "tokio"
 version = "1.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee"
 dependencies = [
  "bytes 1.1.0",
  "memchr",
  "num_cpus",
- "pin-project-lite 0.2.7",
+ "pin-project-lite 0.2.9",
  "tokio-macros",
 ]
 
 [[package]]
 name = "tokio-codec"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b"
@@ -5489,43 +5495,43 @@ version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
 dependencies = [
  "version_check",
 ]
 
 [[package]]
 name = "unicode-bidi"
-version = "0.3.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
 
 [[package]]
 name = "unicode-normalization"
 version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25"
 
 [[package]]
 name = "unicode-segmentation"
-version = "1.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
 
 [[package]]
 name = "unicode-width"
 version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
 
 [[package]]
 name = "unicode-xid"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
 
 [[package]]
 name = "unix_path"
 version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "af8e291873ae77c4c8d9c9b34d0bee68a35b048fb39c263a5155e0e353783eaf"
 dependencies = [
  "unix_str",
@@ -5620,17 +5626,17 @@ dependencies = [
 
 [[package]]
 name = "warp"
 version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0e95175b7a927258ecbb816bdada3cc469cb68593e7940b96a60f4af366a9970"
 dependencies = [
  "bytes 0.5.6",
- "futures 0.3.19",
+ "futures 0.3.21",
  "headers",
  "http",
  "hyper",
  "log",
  "mime",
  "mime_guess",
  "pin-project",
  "scoped-tls",
@@ -5911,17 +5917,17 @@ dependencies = [
  "foreign-types",
  "fxhash",
  "glow",
  "gpu-alloc",
  "gpu-descriptor",
  "inplace_it",
  "js-sys",
  "khronos-egl",
- "libloading 0.7.2",
+ "libloading 0.7.3",
  "log",
  "metal",
  "naga",
  "objc",
  "parking_lot",
  "profiling",
  "range-alloc",
  "raw-window-handle",
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -85,16 +85,19 @@ opt-level = 2
 # stay unused by overriding them with crates that contain enough to build the current
 # code and will fail the build in unwanted cases.
 cmake = { path = "build/rust/cmake" }
 vcpkg = { path = "build/rust/vcpkg" }
 
 # Helper crate for integration in the gecko build system.
 mozbuild = { path = "build/rust/mozbuild" }
 
+# Patch itoa 0.4 to 1.0.
+itoa = { path = "build/rust/itoa" }
+
 # Patch autocfg to hide rustc output. Workaround for https://github.com/cuviper/autocfg/issues/30
 autocfg = { path = "third_party/rust/autocfg" }
 
 # The following overrides point to dummy projects, as a temporary measure until this is resolved:
 # https://github.com/rust-lang/cargo/issues/6179
 js-sys = { path = "build/rust/dummy-web/js-sys" }
 slotmap = { path = "build/rust/dummy-web/slotmap" }
 wasm-bindgen = { path = "build/rust/dummy-web/wasm-bindgen" }
--- a/browser/components/firefoxview/tabs-pickup.js
+++ b/browser/components/firefoxview/tabs-pickup.js
@@ -4,16 +4,17 @@
 
 /* eslint-env mozilla/frame-script */
 
 const { switchToTabHavingURI } = window.docShell.chromeEventHandler.ownerGlobal;
 
 const { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
 );
+const SYNC_TABS_PREF = "services.sync.engine.tabs";
 
 const tabsSetupFlowManager = new (class {
   constructor() {
     this.QueryInterface = ChromeUtils.generateQI(["nsIObserver"]);
 
     this.setupState = new Map();
     this._currentSetupStateName = "";
     this.sync = {};
@@ -23,16 +24,27 @@ const tabsSetupFlowManager = new (class 
       fxAccounts: "resource://gre/modules/FxAccounts.jsm",
     });
     ChromeUtils.defineModuleGetter(
       this.sync,
       "UIState",
       "resource://services-sync/UIState.jsm"
     );
 
+    // this.syncTabsPrefEnabled will track the value of the tabs pref
+    XPCOMUtils.defineLazyPreferenceGetter(
+      this,
+      "syncTabsPrefEnabled",
+      SYNC_TABS_PREF,
+      false,
+      () => {
+        this.maybeUpdateUI();
+      }
+    );
+
     this.registerSetupState({
       uiStateIndex: 0,
       name: "not-signed-in",
       exitConditions: () => {
         return this.fxaSignedIn;
       },
     });
     // TODO: handle offline, sync service not ready or available
@@ -42,32 +54,30 @@ const tabsSetupFlowManager = new (class 
       exitConditions: () => {
         return this.mobileDeviceConnected;
       },
     });
     this.registerSetupState({
       uiStateIndex: 2,
       name: "disabled-tab-sync",
       exitConditions: () => {
-        // Bug 1763139 - Implement the actual logic to advance to next step
-        // This will basically be a check for the pref to enable tab-syncing
-        return false;
+        return this.syncTabsPrefEnabled;
       },
     });
     this.registerSetupState({
       uiStateIndex: 3,
       name: "synced-tabs-not-ready",
       exitConditions: () => {
         // Bug 1763139 - Implement the actual logic to advance to next step
         return false;
       },
     });
     this.registerSetupState({
       uiStateIndex: 4,
-      name: "show-synced-tabs-agreement",
+      name: "show-synced-tabs-loading",
       exitConditions: () => {
         // Bug 1763139 - Implement the actual logic to advance to next step
         return false;
       },
     });
   }
   async initialize(elem) {
     this.elem = elem;
@@ -160,25 +170,24 @@ const tabsSetupFlowManager = new (class 
     );
     switchToTabHavingURI(url, true);
   }
   openSyncPreferences(containerElem) {
     const url = "about:preferences?action=pair#sync";
     switchToTabHavingURI(url, true);
   }
   syncOpenTabs(containerElem) {
-    // Bug 1763139 - Implement the actual logic to advance to next step
-    this.elem.updateSetupState(
-      this.setupState.get("synced-tabs-not-ready").uiStateIndex
-    );
+    // Flip the pref on.
+    // The observer should trigger re-evaluating state and advance to next step
+    this.Services.prefs.setBoolPref(SYNC_TABS_PREF, true);
   }
   confirmSetupComplete(containerElem) {
     // Bug 1763139 - Implement the actual logic to advance to next step
     this.elem.updateSetupState(
-      this.setupState.get("show-synced-tabs-agreement").uiStateIndex
+      this.setupState.get("show-synced-tabs-loading").uiStateIndex
     );
   }
 })();
 
 class TabsPickupContainer extends HTMLElement {
   constructor() {
     super();
     this.manager = null;
--- a/browser/components/firefoxview/tests/browser/browser_setup_state.js
+++ b/browser/components/firefoxview/tests/browser/browser_setup_state.js
@@ -25,59 +25,74 @@ function setupMocks({ fxaDevices = null,
       let target = fxaDevices.find(c => c.id == fxaDeviceId);
       return target ? target.clientRecord : null;
     });
   sandbox.stub(Weave.Service.clientsEngine, "getClientType").returns("desktop");
 
   return sandbox;
 }
 
-function testSetupState(browser, expected) {
+async function waitForVisibleStep(browser, expected) {
   const { document } = browser.contentWindow;
-  for (let [selector, shouldBeVisible] of Object.entries(
-    expected.expectedVisible
-  )) {
-    const elem = document.querySelector(selector);
-    if (shouldBeVisible) {
+
+  const deck = document.querySelector(".sync-setup-container");
+  const nextStepElem = deck.querySelector(expected.expectedVisible);
+  const stepElems = deck.querySelectorAll(".setup-step");
+
+  await BrowserTestUtils.waitForMutationCondition(
+    deck,
+    {
+      attributeFilter: ["selected-view"],
+    },
+    () => {
+      return BrowserTestUtils.is_visible(nextStepElem);
+    }
+  );
+
+  for (let elem of stepElems) {
+    if (elem == nextStepElem) {
       ok(
         BrowserTestUtils.is_visible(elem),
-        `Expected ${selector} to be visible`
+        `Expected ${elem.id || elem.className} to be visible`
       );
     } else {
-      ok(BrowserTestUtils.is_hidden(elem), `Expected ${selector} to be hidden`);
+      ok(
+        BrowserTestUtils.is_hidden(elem),
+        `Expected ${elem.id || elem.className} to be hidden`
+      );
     }
   }
 }
 
 add_setup(async function() {
   await promiseSyncReady();
   // gSync.init() is called in a requestIdleCallback. Force its initialization.
   gSync.init();
 
   const tab = await BrowserTestUtils.openNewForegroundTab(
     gBrowser,
     "about:firefoxview"
   );
   registerCleanupFunction(async function() {
     BrowserTestUtils.removeTab(tab);
+    Services.prefs.clearUserPref("services.sync.engine.tabs");
+  });
+  // set tab sync false so we don't skip setup states
+  await SpecialPowers.pushPrefEnv({
+    set: [["services.sync.engine.tabs", false]],
   });
 });
 
 add_task(async function test_unconfigured_initial_state() {
   const browser = gBrowser.selectedBrowser;
   const sandbox = setupMocks({ state: UIState.STATUS_NOT_CONFIGURED });
 
   Services.obs.notifyObservers(null, UIState.ON_UPDATE);
-  testSetupState(browser, {
-    expectedVisible: {
-      "#tabpickup-steps-view0": true,
-      "#tabpickup-steps-view1": false,
-      "#tabpickup-steps-view2": false,
-      "#tabpickup-steps-view3": false,
-    },
+  await waitForVisibleStep(browser, {
+    expectedVisible: "#tabpickup-steps-view0",
   });
 
   sandbox.restore();
 });
 
 add_task(async function test_signed_in() {
   const browser = gBrowser.selectedBrowser;
   const sandbox = setupMocks({
@@ -86,26 +101,21 @@ add_task(async function test_signed_in()
       {
         id: 1,
         name: "This Device",
         isCurrentDevice: true,
         type: "desktop",
       },
     ],
   });
+  Services.obs.notifyObservers(null, UIState.ON_UPDATE);
+  await waitForVisibleStep(browser, {
+    expectedVisible: "#tabpickup-steps-view1",
+  });
 
-  Services.obs.notifyObservers(null, UIState.ON_UPDATE);
-  testSetupState(browser, {
-    expectedVisible: {
-      "#tabpickup-steps-view0": false,
-      "#tabpickup-steps-view1": true,
-      "#tabpickup-steps-view2": false,
-      "#tabpickup-steps-view3": false,
-    },
-  });
   is(fxAccounts.device.recentDeviceList?.length, 1, "Just 1 device connected");
 
   sandbox.restore();
 });
 
 add_task(async function test_2nd_desktop_connected() {
   const browser = gBrowser.selectedBrowser;
   const sandbox = setupMocks({
@@ -121,24 +131,20 @@ add_task(async function test_2nd_desktop
         id: 2,
         name: "Other Device",
         type: "desktop",
       },
     ],
   });
 
   Services.obs.notifyObservers(null, UIState.ON_UPDATE);
-  testSetupState(browser, {
-    expectedVisible: {
-      "#tabpickup-steps-view0": false,
-      "#tabpickup-steps-view1": true,
-      "#tabpickup-steps-view2": false,
-      "#tabpickup-steps-view3": false,
-    },
+  await waitForVisibleStep(browser, {
+    expectedVisible: "#tabpickup-steps-view1",
   });
+
   is(fxAccounts.device.recentDeviceList?.length, 2, "2 devices connected");
   ok(
     fxAccounts.device.recentDeviceList?.every(
       device => device.type !== "mobile"
     ),
     "No connected device is type:mobile"
   );
 
@@ -158,28 +164,84 @@ add_task(async function test_mobile_conn
       },
       {
         id: 2,
         name: "Other Device",
         type: "mobile",
       },
     ],
   });
+  // ensure tab sync is false so we don't skip onto next step
+  ok(
+    !Services.prefs.getBoolPref("services.sync.engine.tabs", false),
+    "services.sync.engine.tabs is initially false"
+  );
 
   Services.obs.notifyObservers(null, UIState.ON_UPDATE);
-  testSetupState(browser, {
-    expectedVisible: {
-      "#tabpickup-steps-view0": false,
-      "#tabpickup-steps-view1": false,
-      "#tabpickup-steps-view2": true,
-      "#tabpickup-steps-view3": false,
-    },
+  await waitForVisibleStep(browser, {
+    expectedVisible: "#tabpickup-steps-view2",
   });
+
   is(fxAccounts.device.recentDeviceList?.length, 2, "2 devices connected");
   ok(
     fxAccounts.device.recentDeviceList?.some(
       device => device.type !== "mobile"
     ),
     "A connected device is type:mobile"
   );
 
   sandbox.restore();
 });
+
+add_task(async function test_tab_sync_enabled() {
+  const browser = gBrowser.selectedBrowser;
+  const sandbox = setupMocks({
+    state: UIState.STATUS_SIGNED_IN,
+    fxaDevices: [
+      {
+        id: 1,
+        name: "This Device",
+        isCurrentDevice: true,
+        type: "desktop",
+      },
+      {
+        id: 2,
+        name: "Other Device",
+        type: "mobile",
+      },
+    ],
+  });
+  Services.obs.notifyObservers(null, UIState.ON_UPDATE);
+
+  // test initial state, with the pref not enabled
+  await waitForVisibleStep(browser, {
+    expectedVisible: "#tabpickup-steps-view2",
+  });
+
+  // test with the pref toggled on
+  await SpecialPowers.pushPrefEnv({
+    set: [["services.sync.engine.tabs", true]],
+  });
+  await waitForVisibleStep(browser, {
+    expectedVisible: "#tabpickup-steps-view3",
+  });
+
+  // reset and test clicking the action button
+  await SpecialPowers.popPrefEnv();
+  await waitForVisibleStep(browser, {
+    expectedVisible: "#tabpickup-steps-view2",
+  });
+
+  const actionButton = browser.contentWindow.document.querySelector(
+    "#tabpickup-steps-view2 button.primary"
+  );
+  actionButton.click();
+  await waitForVisibleStep(browser, {
+    expectedVisible: "#tabpickup-steps-view3",
+  });
+  ok(
+    Services.prefs.getBoolPref("services.sync.engine.tabs", false),
+    "tab sync pref should be enabled after button click"
+  );
+
+  sandbox.restore();
+  Services.prefs.clearUserPref("services.sync.engine.tabs");
+});
--- a/browser/components/urlbar/UrlbarInput.jsm
+++ b/browser/components/urlbar/UrlbarInput.jsm
@@ -372,32 +372,49 @@ class UrlbarInput {
       value = "";
       valid = true;
     }
 
     const previousUntrimmedValue = this.untrimmedValue;
     const previousSelectionStart = this.selectionStart;
     const previousSelectionEnd = this.selectionEnd;
 
-    let isDifferentValidValue = valid && value != this.untrimmedValue;
     this.value = value;
     this.valueIsTyped = !valid;
     this.removeAttribute("usertyping");
-    if (isDifferentValidValue) {
-      // If the caret is at the end of the input or its position is beyond the
-      // end of the new value, keep it at the end. Otherwise keep its current
-      // position.
-      const isCaretPositionEnd =
-        previousUntrimmedValue.length === previousSelectionEnd ||
-        value.length <= previousSelectionEnd;
-      if (isCaretPositionEnd) {
+
+    if (!this.focused) {
+      // When setURI is called while the input is not focused, reset the caret.
+      this.selectionStart = this.selectionEnd = 0;
+    } else if (value != previousUntrimmedValue) {
+      if (
+        previousSelectionStart != previousSelectionEnd &&
+        value.substring(previousSelectionStart, previousSelectionEnd) ===
+          previousUntrimmedValue.substring(
+            previousSelectionStart,
+            previousSelectionEnd
+          )
+      ) {
+        // If the same text is in the same place as the previously selected text,
+        // the selection is kept.
+        this.selectionStart = previousSelectionStart;
+        this.selectionEnd = previousSelectionEnd;
+      } else if (
+        previousSelectionEnd &&
+        (previousUntrimmedValue.length === previousSelectionEnd ||
+          value.length <= previousSelectionEnd)
+      ) {
+        // If the previous end caret is not 0 and the caret is at the end of the
+        // input or its position is beyond the end of the new value, keep the
+        // position at the end.
         this.selectionStart = this.selectionEnd = value.length;
       } else {
-        this.selectionStart = previousSelectionStart;
-        this.selectionEnd = previousSelectionEnd;
+        // Otherwise clear selection and set the caret position to the previous
+        // caret end position.
+        this.selectionStart = this.selectionEnd = previousSelectionEnd;
       }
     }
 
     // The proxystate must be set before setting search mode below because
     // search mode depends on it.
     this.setPageProxyState(valid ? "valid" : "invalid", dueToTabSwitch);
 
     // If we're switching tabs, restore the tab's search mode.  Otherwise, if
--- a/browser/components/urlbar/tests/browser/browser_caret_position.js
+++ b/browser/components/urlbar/tests/browser/browser_caret_position.js
@@ -61,19 +61,27 @@ add_task(async function setURI() {
       initialSelectionEnd: 20,
       expectedSelectionStart: 20,
       expectedSelectionEnd: 20,
     },
     {
       firstURL: "https://example.com/test",
       secondURL: "https://example.org/test",
       initialSelectionStart: 1,
-      initialSelectionEnd: 20,
+      initialSelectionEnd: 10,
       expectedSelectionStart: 1,
-      expectedSelectionEnd: 20,
+      expectedSelectionEnd: 10,
+    },
+    {
+      firstURL: "https://example.com/test",
+      secondURL: "https://example.org/test",
+      initialSelectionStart: "https://example.".length,
+      initialSelectionEnd: "https://example.c".length,
+      expectedSelectionStart: "https://example.c".length,
+      expectedSelectionEnd: "https://example.c".length,
     },
     {
       firstURL: "https://example.com/test",
       secondURL: "https://example.org/test",
       initialSelectionStart: "https://example.com/test".length,
       initialSelectionEnd: "https://example.com/test".length,
       expectedSelectionStart: "https://example.org/test".length,
       expectedSelectionEnd: "https://example.org/test".length,
@@ -129,74 +137,119 @@ add_task(async function setURI() {
     {
       firstURL: "https://example.com/longer",
       secondURL: "https://example.com/test",
       initialSelectionStart: 0,
       initialSelectionEnd: "https://example.com/longer".length - 1,
       expectedSelectionStart: "https://example.com/test".length,
       expectedSelectionEnd: "https://example.com/test".length,
     },
+    {
+      firstURL: "https://example.com/test",
+      secondURL: "about:blank",
+      initialSelectionStart: 0,
+      initialSelectionEnd: 0,
+      expectedSelectionStart: 0,
+      expectedSelectionEnd: 0,
+    },
+    {
+      firstURL: "https://example.com/test",
+      secondURL: "about:blank",
+      initialSelectionStart: 0,
+      initialSelectionEnd: "https://example.com/test".length,
+      expectedSelectionStart: 0,
+      expectedSelectionEnd: 0,
+    },
+    {
+      firstURL: "https://example.com/test",
+      secondURL: "about:blank",
+      initialSelectionStart: 3,
+      initialSelectionEnd: 4,
+      expectedSelectionStart: 0,
+      expectedSelectionEnd: 0,
+    },
+    {
+      firstURL: "https://example.com/test",
+      secondURL: "about:blank",
+      initialSelectionStart: "https://example.com/test".length,
+      initialSelectionEnd: "https://example.com/test".length,
+      expectedSelectionStart: 0,
+      expectedSelectionEnd: 0,
+    },
+    {
+      firstURL: "about:blank",
+      secondURL: "https://example.com/test",
+      initialSelectionStart: 0,
+      initialSelectionEnd: 0,
+      expectedSelectionStart: 0,
+      expectedSelectionEnd: 0,
+    },
   ];
 
   for (const data of testData) {
     info(
       `Test for ${data.firstURL} -> ${data.secondURL} with initial selection: ${data.initialSelectionStart}, ${data.initialSelectionEnd}`
     );
 
+    info("Check the caret position after setting second URL");
     gURLBar.setURI(makeURI(data.firstURL));
-
     gURLBar.selectionStart = data.initialSelectionStart;
     gURLBar.selectionEnd = data.initialSelectionEnd;
 
+    gURLBar.focus();
     gURLBar.setURI(makeURI(data.secondURL));
-
     Assert.equal(gURLBar.selectionStart, data.expectedSelectionStart);
     Assert.equal(gURLBar.selectionEnd, data.expectedSelectionEnd);
+
+    info("Check the caret position while the input is not focused");
+    gURLBar.setURI(makeURI(data.firstURL));
+    gURLBar.selectionStart = data.initialSelectionStart;
+    gURLBar.selectionEnd = data.initialSelectionEnd;
+
+    gURLBar.blur();
+    gURLBar.setURI(makeURI(data.secondURL));
+    Assert.equal(gURLBar.selectionStart, 0);
+    Assert.equal(gURLBar.selectionEnd, 0);
   }
 });
 
 // Tests that up and down keys move the caret on certain platforms, and that
 // opening the popup doesn't change the caret position.
 add_task(async function navigation() {
-  // Use new window to avoid timeout failure for autocomplete popup happens on Linux TV.
-  const win = await BrowserTestUtils.openNewBrowserWindow();
-
   await UrlbarTestUtils.promiseAutocompleteResultPopup({
-    window: win,
+    window,
     value: "This is a generic sentence",
   });
-  await UrlbarTestUtils.promisePopupClose(win);
+  await UrlbarTestUtils.promisePopupClose(window);
 
   const INITIAL_SELECTION_START = 3;
   const INITIAL_SELECTION_END = 10;
-  win.gURLBar.selectionStart = INITIAL_SELECTION_START;
-  win.gURLBar.selectionEnd = INITIAL_SELECTION_END;
+  gURLBar.selectionStart = INITIAL_SELECTION_START;
+  gURLBar.selectionEnd = INITIAL_SELECTION_END;
 
   if (AppConstants.platform == "macosx" || AppConstants.platform == "linux") {
     await checkCaretMoves(
       "KEY_ArrowDown",
-      win.gURLBar.value.length,
+      gURLBar.value.length,
       "Caret should have moved to the end",
-      win
+      window
     );
-    await checkPopupOpens("KEY_ArrowDown", win);
+    await checkPopupOpens("KEY_ArrowDown", window);
 
     await checkCaretMoves(
       "KEY_ArrowUp",
       0,
       "Caret should have moved to the start",
-      win
+      window
     );
-    await checkPopupOpens("KEY_ArrowUp", win);
+    await checkPopupOpens("KEY_ArrowUp", window);
   } else {
-    await checkPopupOpens("KEY_ArrowDown", win);
-    await checkPopupOpens("KEY_ArrowUp", win);
+    await checkPopupOpens("KEY_ArrowDown", window);
+    await checkPopupOpens("KEY_ArrowUp", window);
   }
-
-  await BrowserTestUtils.closeWindow(win);
 });
 
 async function checkCaretMoves(key, pos, msg, win) {
   checkIfKeyStartsQuery(key, false, win);
   Assert.equal(
     UrlbarTestUtils.isPopupOpen(win),
     false,
     `${key}: Popup shouldn't be open`
--- a/browser/themes/shared/tabs.css
+++ b/browser/themes/shared/tabs.css
@@ -669,16 +669,28 @@
 }
 
 @media (max-width: 500px) {
   .titlebar-spacer[type="post-tabs"] {
     display: none;
   }
 }
 
+/* Firefox View button */
+
+:is(#firefox-view-button, #wrapper-firefox-view-button) + #tabbrowser-tabs {
+  border-inline-start: 1px solid color-mix(in srgb, currentColor 25%, transparent);
+  padding-inline-start: 4px;
+  margin-inline-start: 4px;
+}
+
+:root[privatebrowsingmode=temporary] #firefox-view-button {
+  display: none;
+}
+
 /* Tab bar scroll arrows */
 
 #tabbrowser-arrowscrollbox::part(scrollbutton-up),
 #tabbrowser-arrowscrollbox::part(scrollbutton-down) {
   fill: var(--toolbarbutton-icon-fill);
 }
 
 /* New tab button */
--- a/browser/themes/shared/toolbarbuttons.css
+++ b/browser/themes/shared/toolbarbuttons.css
@@ -77,26 +77,16 @@ toolbar .toolbarbutton-1 {
   padding: 0 var(--toolbarbutton-outer-padding);
   -moz-box-pack: center;
 }
 
 #TabsToolbar .toolbarbutton-1 {
   margin: 0 0 var(--tabs-navbar-shadow-size);
 }
 
-#TabsToolbar #firefox-view-button {
-  border-inline-end: 1px solid color-mix(in srgb, currentColor 25%, transparent);
-  padding-inline-end: 4px;
-  margin-inline-end: 2px;
-}
-
-:root[privatebrowsingmode=temporary] #firefox-view-button {
-  display: none;
-}
-
 #tabbrowser-arrowscrollbox::part(scrollbutton-up),
 #tabbrowser-arrowscrollbox::part(scrollbutton-down) {
   appearance: none;
   background-clip: padding-box;
   border: 4px solid transparent;
   border-radius: calc(var(--tab-border-radius) + 4px);
   margin: 0;
   padding: 0 calc(var(--toolbarbutton-inner-padding) - 6px);
--- a/build/clang-plugin/Checks.inc
+++ b/build/clang-plugin/Checks.inc
@@ -7,16 +7,17 @@
 CHECK(ArithmeticArgChecker, "arithmetic-argument")
 CHECK(AssertAssignmentChecker, "assignment-in-assert")
 CHECK(CanRunScriptChecker, "can-run-script")
 CHECK(DanglingOnTemporaryChecker, "dangling-on-temporary")
 CHECK(ExplicitImplicitChecker, "implicit-constructor")
 CHECK(ExplicitOperatorBoolChecker, "explicit-operator-bool")
 CHECK(JSHandleRootedTypedefChecker, "js-handle-rooted-typedef")
 CHECK(KungFuDeathGripChecker, "kungfu-death-grip")
+CHECK(KnownLiveChecker, "known-live")
 #ifdef TARGET_IS_WINDOWS
 CHECK(LoadLibraryUsageChecker, "load-library-usage")
 CHECK(FopenUsageChecker, "fopen-usage")
 #endif
 CHECK(MustOverrideChecker, "must-override")
 CHECK(MustReturnFromCallerChecker, "must-return-from-caller")
 CHECK(NaNExprChecker, "nan-expr")
 CHECK(NoPrincipalGetURI, "no-principal-geturi")
--- a/build/clang-plugin/ChecksIncludes.inc
+++ b/build/clang-plugin/ChecksIncludes.inc
@@ -12,16 +12,17 @@
 #include "ExplicitImplicitChecker.h"
 #include "ExplicitOperatorBoolChecker.h"
 #ifdef TARGET_IS_WINDOWS
 #include "LoadLibraryUsageChecker.h"
 #include "FopenUsageChecker.h"
 #endif
 #include "JSHandleRootedTypedefChecker.h"
 #include "KungFuDeathGripChecker.h"
+#include "KnownLiveChecker.h"
 #include "MustOverrideChecker.h"
 #include "MustReturnFromCallerChecker.h"
 #include "NaNExprChecker.h"
 #include "NoPrincipalGetURI.h"
 #include "NeedsNoVTableTypeChecker.h"
 #include "NoAddRefReleaseOnReturnChecker.h"
 #include "NoAutoTypeChecker.h"
 #include "NoDuplicateRefCntMemberChecker.h"
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/KnownLiveChecker.cpp
@@ -0,0 +1,35 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "KnownLiveChecker.h"
+#include "CustomMatchers.h"
+
+void KnownLiveChecker::registerMatchers(MatchFinder *AstMatcher) {
+  // Note that this cannot catch mutations after pass-by-reference, and thus no
+  // error for cycle collection macros.
+
+  auto KnownLiveLHS = hasLHS(memberExpr(hasKnownLiveAnnotation()).bind("lhs"));
+  auto ForGeneralFunctions = forFunction(
+      functionDecl(unless(anyOf(cxxConstructorDecl(), cxxDestructorDecl())))
+          .bind("func"));
+
+  auto Matcher =
+      allOf(isAssignmentOperator(), KnownLiveLHS, ForGeneralFunctions);
+
+  AstMatcher->addMatcher(binaryOperator(Matcher), this);
+  AstMatcher->addMatcher(cxxOperatorCallExpr(Matcher), this);
+}
+
+void KnownLiveChecker::check(const MatchFinder::MatchResult &Result) {
+  const char *Error = "MOZ_KNOWN_LIVE members can only be modified by "
+                      "constructors and destructors";
+
+  if (const MemberExpr *Expr = Result.Nodes.getNodeAs<MemberExpr>("lhs")) {
+    diag(Expr->getBeginLoc(), Error, DiagnosticIDs::Error);
+  }
+  if (const CXXOperatorCallExpr *Expr =
+          Result.Nodes.getNodeAs<CXXOperatorCallExpr>("lhs")) {
+    diag(Expr->getBeginLoc(), Error, DiagnosticIDs::Error);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/KnownLiveChecker.h
@@ -0,0 +1,18 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef BUILD_CLANG_PLUGIN_KNOWNLIVECHECKER_H_
+#define BUILD_CLANG_PLUGIN_KNOWNLIVECHECKER_H_
+
+#include "plugin.h"
+
+class KnownLiveChecker : public BaseCheck {
+public:
+  KnownLiveChecker(StringRef CheckName, ContextType *Context = nullptr)
+      : BaseCheck(CheckName, Context) {}
+  void registerMatchers(MatchFinder *AstMatcher) override;
+  void check(const MatchFinder::MatchResult &Result) override;
+};
+
+#endif
--- a/build/clang-plugin/moz.build
+++ b/build/clang-plugin/moz.build
@@ -14,16 +14,17 @@ HOST_SOURCES += [
     "CanRunScriptChecker.cpp",
     "CustomAttributes.cpp",
     "CustomTypeAnnotation.cpp",
     "DanglingOnTemporaryChecker.cpp",
     "DiagnosticsMatcher.cpp",
     "ExplicitImplicitChecker.cpp",
     "ExplicitOperatorBoolChecker.cpp",
     "JSHandleRootedTypedefChecker.cpp",
+    "KnownLiveChecker.cpp",
     "KungFuDeathGripChecker.cpp",
     "MozCheckAction.cpp",
     "MustOverrideChecker.cpp",
     "MustReturnFromCallerChecker.cpp",
     "NaNExprChecker.cpp",
     "NeedsNoVTableTypeChecker.cpp",
     "NoAddRefReleaseOnReturnChecker.cpp",
     "NoAutoTypeChecker.cpp",
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/tests/TestKnownLive.cpp
@@ -0,0 +1,33 @@
+#include <mozilla/RefPtr.h>
+
+#define MOZ_KNOWN_LIVE __attribute__((annotate("moz_known_live")))
+
+class Foo {
+  // dummy refcounting
+public:
+  uint32_t AddRef() { return 0; }
+  uint32_t Release() { return 0; }
+
+private:
+  ~Foo() = default;
+};
+
+class Bar {
+  MOZ_KNOWN_LIVE RefPtr<Foo> mFoo;
+  Bar() : mFoo(new Foo()) {}
+  ~Bar() { mFoo = nullptr; }
+
+  void Baz() {
+    mFoo = nullptr; // expected-error {{MOZ_KNOWN_LIVE members can only be modified by constructors and destructors}}
+  }
+};
+
+class Bar2 {
+  MOZ_KNOWN_LIVE Foo *mFoo;
+  Bar2() : mFoo(new Foo()) {}
+  ~Bar2() { mFoo = nullptr; }
+
+  void Baz() {
+    mFoo = nullptr; // expected-error {{MOZ_KNOWN_LIVE members can only be modified by constructors and destructors}}
+  }
+};
--- a/build/clang-plugin/tests/moz.build
+++ b/build/clang-plugin/tests/moz.build
@@ -13,16 +13,17 @@ SOURCES += [
     "TestCanRunScript.cpp",
     "TestCustomHeap.cpp",
     "TestDanglingOnTemporary.cpp",
     "TestExplicitOperatorBool.cpp",
     "TestGlobalClass.cpp",
     "TestHeapClass.cpp",
     "TestInheritTypeAnnotationsFromTemplateArgs.cpp",
     "TestJSHandleRootedTypedef.cpp",
+    "TestKnownLive.cpp",
     "TestKungFuDeathGrip.cpp",
     "TestMultipleAnnotations.cpp",
     "TestMustOverride.cpp",
     "TestMustReturnFromCaller.cpp",
     "TestNANTestingExpr.cpp",
     "TestNANTestingExprC.c",
     "TestNeedsNoVTableType.cpp",
     "TestNoAddRefReleaseOnReturn.cpp",
new file mode 100644
--- /dev/null
+++ b/build/rust/itoa/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "itoa"
+version = "0.4.999"
+edition = "2018"
+license = "MIT OR Apache-2.0"
+
+[lib]
+path = "lib.rs"
+
+[dependencies]
+itoa = "1.0"
new file mode 100644
--- /dev/null
+++ b/build/rust/itoa/lib.rs
@@ -0,0 +1,25 @@
+// Licensed under the Apache License, Version 2.0
+// <http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <http://opensource.org/licenses/MIT>, at your option.
+
+pub use itoa::*;
+use std::{io, fmt};
+
+// APIs that were in itoa 0.4 but aren't in 1.0.
+
+#[inline]
+pub fn write<W: io::Write, V: Integer>(mut wr: W, value: V) -> io::Result<usize> {
+    let mut buf = Buffer::new();
+    let s = buf.format(value);
+    match wr.write_all(s.as_bytes()) {
+        Ok(()) => Ok(s.len()),
+        Err(e) => Err(e),
+    }
+}
+
+/// Write integer to an `fmt::Write`.
+#[inline]
+pub fn fmt<W: fmt::Write, V: Integer>(mut wr: W, value: V) -> fmt::Result {
+    let mut buf = Buffer::new();
+    wr.write_str(buf.format(value))
+}
--- a/dom/base/nsDeprecatedOperationList.h
+++ b/dom/base/nsDeprecatedOperationList.h
@@ -60,9 +60,11 @@ DEPRECATED_OPERATION(MathML_DeprecatedSc
 DEPRECATED_OPERATION(MathML_DeprecatedScriptsizemultiplierAttribute)
 DEPRECATED_OPERATION(FormSubmissionUntrustedEvent)
 DEPRECATED_OPERATION(ElementSetCapture)
 DEPRECATED_OPERATION(ElementReleaseCapture)
 DEPRECATED_OPERATION(DocumentReleaseCapture)
 DEPRECATED_OPERATION(OffscreenCanvasToBlob)
 DEPRECATED_OPERATION(IDBDatabaseCreateMutableFile)
 DEPRECATED_OPERATION(IDBMutableFileOpen)
+DEPRECATED_OPERATION(MozCurrentTransform)
+DEPRECATED_OPERATION(MozCurrentTransformInverse)
 DEPRECATED_OPERATION(MozPreservesPitchDeprecatedPrefix)
--- a/dom/base/test/test_bug590812.html
+++ b/dom/base/test/test_bug590812.html
@@ -1,36 +1,48 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Test for XML pretty printing, bug 590812</title>
   <script src="/tests/SimpleTest/SimpleTest.js"></script>
   <script src="/tests/SimpleTest/WindowSnapshot.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
-<body onload="runTest()">
+<body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=590812">Mozilla Bug 590812</a>
 <p id="display"></p>
-<iframe src="http://noxul.example.com/tests/dom/base/test/file_bug590812.xml"></iframe>
-<iframe src="file_bug590812.xml"></iframe>
+<iframe id=iframe></iframe>
 <iframe src="file_bug590812-ref.xhtml"></iframe>
 <pre id="test">
 <script class="testbody" type="application/javascript">
 
-SimpleTest.waitForExplicitFinish();
+add_task(async function start() {
+  var noxul = "https://sub1.test1.example.com:443";
+  var yesxul = "https://example.org:443"
+
+  await SpecialPowers.pushPermissions([
+    { type: "allowXULXBL", allow: false, context: noxul },
+    { type: "allowXULXBL", allow: true, context: yesxul }
+  ]);
 
-async function runTest() {
+  var path = "/tests/dom/base/test/file_bug590812.xml";
+  var iframe = $('iframe');
+  iframe.src = noxul + path;
+  await new Promise(resolve => iframe.addEventListener("load", resolve, {once: true}));
   let sNoXUL = await snapshotWindow(window.frames[0], false);
-  let sWithXUL = await snapshotWindow(window.frames[1], false);
-  let sRef = await snapshotWindow(window.frames[2], false);
+
+  iframe.src = yesxul + path;
+  await new Promise(resolve => iframe.addEventListener("load", resolve, {once: true}));
+  let sWithXUL = await snapshotWindow(window.frames[0], false);
+
+  let sRef = await snapshotWindow(window.frames[1], false);
+
   let res;
   ok(compareSnapshots(sNoXUL, sRef, true)[0],
      "noxul domain same as ref");
   ok(compareSnapshots(sWithXUL, sRef, true)[0],
      "xul supporting domain same as ref");
-
-  SimpleTest.finish();
-}
+});
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/base/test/test_bug590870.html
+++ b/dom/base/test/test_bug590870.html
@@ -2,35 +2,43 @@
 <html>
 <!--
 -->
 <head>
   <title>Test for creating XUL elements, bug 590870</title>
   <script src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
-<body onload="gen.next()">
+<body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=590870">Mozilla Bug 590870</a>
 <p id="display"></p>
 <iframe id=iframe></iframe>
 <pre id="test">
 <script class="testbody" type="application/javascript">
 
-SimpleTest.waitForExplicitFinish();
-window.addEventListener("message", function(e) { gen.next(e.data) });
+add_task(async function start() {
+  var noxul = "https://sub1.test1.example.com:443";
+  var yesxul = "https://example.org:443"
 
-var gen = runTest();
+  await SpecialPowers.pushPermissions([
+    { type: "allowXULXBL", allow: false, context: noxul },
+    { type: "allowXULXBL", allow: true, context: yesxul }
+  ]);
 
-function* runTest() {
+  var path = "/tests/dom/base/test/file_bug590870.html";
   var iframe = $('iframe');
-  iframe.src = "http://noxul.example.com/tests/dom/base/test/file_bug590870.html";
-  is((yield), true, "shouldn't be able to create XUL elements");
+
+  iframe.src = noxul + path;
+  await new Promise(resolve => window.addEventListener("message", event => {
+    is(event.data, true, "shouldn't be able to create XUL elements");
+    resolve();
+  }, { once: true } ));
 
-  iframe.src = "file_bug590870.html";
-  is((yield), false, "should be able to create XUL elements");
-
-  SimpleTest.finish();
-}
-
+  iframe.src = yesxul + path;
+  await new Promise(resolve => window.addEventListener("message", event => {
+    is(event.data, false, "should be able to create XUL elements");
+    resolve();
+  }, { once: true } ));
+});
 </script>
 </pre>
 </body>
 </html>
--- a/dom/base/test/test_title.html
+++ b/dom/base/test/test_title.html
@@ -17,18 +17,16 @@
   <iframe id="html2" src="data:text/html,<html><head><title id='t'>Test</title><title>Foo</title></head></html>"></iframe>
   <iframe id="html3" src="data:text/html,<html></html>"></iframe>
   <iframe id="xhtml1" src="data:text/xml,<html xmlns='http://www.w3.org/1999/xhtml'><body><title id='t'>Test</title></body></html>"></iframe>
   <iframe id="xhtml2" src="data:text/xml,<title xmlns='http://www.w3.org/1999/xhtml'>Test</title>"></iframe>
   <iframe id="xhtml3" src="data:text/xml,<title xmlns='http://www.w3.org/1999/xhtml'>Te<div>bogus</div>st</title>"></iframe>
   <iframe id="xhtml4" src="data:text/xml,<html xmlns='http://www.w3.org/1999/xhtml'/>"></iframe>
   <iframe id="xhtml5" src="data:text/xml,<html xmlns='http://www.w3.org/1999/xhtml'><head/></html>"></iframe>
   <iframe id="xhtml6" src="data:text/xml,<html xmlns='http://www.w3.org/1999/xhtml'><head><style/></head></html>"></iframe>
-  <iframe id="xul1" src="file_title.xhtml"></iframe>
-  <iframe id="xul2" src="file_title.xhtml"></iframe>
   <iframe id="svg1" src="data:text/xml,<svg xmlns='http://www.w3.org/2000/svg'><title id='t'>Test</title></svg>"></iframe>
   <iframe id="svg2" src="data:text/xml,<svg xmlns='http://www.w3.org/2000/svg'><title id='t'>Test</title></svg>"></iframe>
 </div>
 <pre id="test">
 <script>
 SimpleTest.waitForExplicitFinish();
 
 function runTests() {
@@ -39,17 +37,16 @@ function runTests() {
   }
 
   testStatic("html1", "Test", "HTML <title>");
   testStatic("html2", "Test", "choose the first HTML <title>");
   testStatic("html3", "", "No title");
   testStatic("xhtml1", "Test", "XHTML <title> in body");
   testStatic("xhtml2", "Test", "XHTML <title> as root element");
   testStatic("xhtml3", "Test", "XHTML <title> containing an element");
-  testStatic("xul1", "Test", "XUL <window> title attribute");
   testStatic("svg1", "Test", "SVG <title>");
 
   SimpleTest.finish();
 }
 </script>
 </pre>
 </body>
 </html>
--- a/dom/canvas/crashtests/1225381-1.html
+++ b/dom/canvas/crashtests/1225381-1.html
@@ -2,16 +2,16 @@
 <html>
 <head>
 <meta charset="UTF-8">
 <script>
 
 function boom() {
     var canvas = document.createElement('canvas');
     var ctx = canvas.getContext('2d');
-    ctx.mozCurrentTransformInverse = [32, -1, 0.8320478957221024, 1.7976931348623157e+308, 512, 0.9012573524148337];
+    ctx.setTransform(new DOMMatrix([32, -1, 0.8320478957221024, 1.7976931348623157e+308, 512, 0.9012573524148337]).invertSelf());
     ctx.fillText("A", 0 ,0);
 }
 
 </script>
 </head>
 <body onload="boom();"></body>
 </html>
--- a/dom/canvas/crashtests/746813-1.html
+++ b/dom/canvas/crashtests/746813-1.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
 <html>
-<body onload="document.getElementById('c').getContext('2d').mozCurrentTransformInverse;">
+<body onload="document.getElementById('c').getContext('2d').getTransform().invertSelf();">
 <canvas id="c" width="772" height="76441"></canvas>
 </body>
 </html>
--- a/dom/canvas/crashtests/916128-1.html
+++ b/dom/canvas/crashtests/916128-1.html
@@ -1,13 +1,13 @@
 <script>
 o0 = document.createElement('canvas');
 (document.body || document.documentElement).appendChild(o0);
 o1 = o0.getContext('2d');
 o2 = document.createElement('img');
 //o2.src = "image2.png";
 o3 = o1.createImageData(0.7409945472006207, 0.8815588599260801);
 o1.save();
-o1.mozCurrentTransform = [0.18777365986904448, 4, 4, -2048, 3, 32];
+o1.setTransform(0.18777365986904448, 4, 4, -2048, 3, 32);
 o0.width = 0.52;
 o1.putImageData(o3, -32, -0.16596290333335356);
 o0.toBlob(function() {}, "video/mp4", 16);
 </script>
deleted file mode 100644
--- a/dom/canvas/test/reftest/mozCurrentTransform-ref.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<canvas id="canvas" width="150" height="150"></canvas>
-
-<script>
-
-var canvas = document.getElementById('canvas');
-var ctx = canvas.getContext('2d');
-ctx.transform(1,0.5,-0.5,1,30,10);
-ctx.fillStyle = '#f00';
-ctx.fillRect(0, 0, 100, 100);
-
-</script>
-</body></html>
deleted file mode 100644
--- a/dom/canvas/test/reftest/mozCurrentTransform.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<!DOCTYPE html>
-<html class="reftest-wait">
-<head>
-<canvas id="canvas" width="150" height="150"></canvas>
-
-<script>
-
-var canvas = document.getElementById('canvas');
-var ctx = canvas.getContext('2d');
-ctx.transform(1,0.5,-0.5,1,30,10);
-setTimeout(function() {
-  var canvas = document.getElementById('canvas');
-  var ctx = canvas.getContext('2d');
-  var transform = ctx.mozCurrentTransform;
-  ctx.mozCurrentTransform = transform;
-  ctx.fillStyle = '#f00';
-  ctx.fillRect(0, 0, 100, 100);
-  document.documentElement.removeAttribute("class");
-}, 10)
-
-</script>
-</body></html>
deleted file mode 100644
--- a/dom/canvas/test/reftest/mozCurrentTransformInverse.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<!DOCTYPE html>
-<html class="reftest-wait">
-<head>
-<canvas id="canvas" width="150" height="150"></canvas>
-
-<script>
-
-var canvas = document.getElementById('canvas');
-var ctx = canvas.getContext('2d');
-ctx.transform(1,0.5,-0.5,1,30,10);
-setTimeout(function() {
-  var canvas = document.getElementById('canvas');
-  var ctx = canvas.getContext('2d');
-  var transform = ctx.mozCurrentTransformInverse;
-  ctx.mozCurrentTransformInverse = transform;
-  ctx.fillStyle = '#f00';
-  ctx.fillRect(0, 0, 100, 100);
-  document.documentElement.removeAttribute("class");
-}, 10)
-
-</script>
-</body></html>
--- a/dom/canvas/test/reftest/reftest.list
+++ b/dom/canvas/test/reftest/reftest.list
@@ -231,20 +231,16 @@ fuzzy(0-1,0-150) == clip-multiple-move-2
 # focus rings
 pref(canvas.focusring.enabled,true) fuzzy(0-1,0-2) skip-if(cocoaWidget||winWidget||gtkWidget) needs-focus == drawFocusIfNeeded.html drawFocusIfNeeded-ref.html
 
 # Check that captureStream() displays in a local video element
 == capturestream.html wrapper.html?green.png
 
 fuzzy-if(azureSkia,0-16,0-2) fuzzy-if(Android,0-3,0-40) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-1) == 1177726-text-stroke-bounds.html 1177726-text-stroke-bounds-ref.html
 
-# Bug 1305963
-== mozCurrentTransform.html mozCurrentTransform-ref.html
-== mozCurrentTransformInverse.html mozCurrentTransform-ref.html
-
 # Bug 1366027
 == clipped-dash-stroke-rect.html clipped-dash-stroke-rect-ref.html
 
 # Bug 1377303
 skip-if(Android) == visible-occluded.html visible-occluded-ref.html
 
 == 1678909-1.html 1678909-1-ref.html
 == 1719886-1.html 1719886-1-ref.html
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -446,8 +446,13 @@ OffscreenCanvasToBlobWarning=OffscreenCa
 IDBDatabaseCreateMutableFileWarning=IDBDatabase.createMutableFile() is deprecated. If this API gets standardized, it will likely do so under the Origin Private File System effort at https://bugzil.la/1748667.
 # LOCALIZATION NOTE: Do not translate "IDBMutableFile.open()"
 IDBMutableFileOpenWarning=IDBMutableFile.open() is deprecated. If this API gets standardized, it will likely do so under the Origin Private File System effort at https://bugzil.la/1748667.
 
 # LOCALIZATION NOTE: Do not translate "InstallTrigger"
 InstallTriggerDeprecatedWarning=InstallTrigger is deprecated and will be removed in the future.
 # LOCALIZATION NOTE: Do not translate "InstallTrigger.install()"
 InstallTriggerInstallDeprecatedWarning=InstallTrigger.install() is deprecated and will be removed in the future. For more help https://extensionworkshop.com/documentation/publish/self-distribution/
+
+# LOCALIZATION NOTE: Do not translate "mozCurrentTransform", "CanvasRenderingContext2D.getTransform()", and "CanvasRenderingContext2D.setTransform()".
+MozCurrentTransformWarning=mozCurrentTransform is deprecated and will be removed in the future. Use CanvasRenderingContext2D.getTransform() or CanvasRenderingContext2D.setTransform() instead.
+# LOCALIZATION NOTE: Do not translate "mozCurrentTransformInverse", "CanvasRenderingContext2D.getTransform()", and "CanvasRenderingContext2D.setTransform()".
+MozCurrentTransformInverseWarning=mozCurrentTransformInverse is deprecated and will be removed in the future. Use CanvasRenderingContext2D.getTransform() or CanvasRenderingContext2D.setTransform() instead.
--- a/dom/quota/scripts/fetch_qm_failures.py
+++ b/dom/quota/scripts/fetch_qm_failures.py
@@ -45,19 +45,17 @@ arrived with our analysis. To accomplish
         "lasteventtime": 1617303855145,
         "rawfile": "./qmrows_until_1617303855145.json"
     }
 ]
 
 lasteventtime is the highest value of event_timeabs we found in our data.
 
 analyze_qm_failures instead needs the rows to be ordered by
-client_id
-    session_id
-        seq
+client_id, session_id, thread_id, submit_timeabs, seq
 Thus we sort the rows accordingly before writing them.
 """
 
 
 def usage():
     print(
         "fetch_qm_faiures.py -k <apikey> -b <minimum build=20210329000000>"
         "-d <days back=1> -l <last event time> -w <workdir=.>"
@@ -120,18 +118,22 @@ p_params = "p_year={:04d}&p_month={:02d}
 print(p_params)
 result = telemetry.query(key, 78691, p_params)
 rows = result["query_result"]["data"]["rows"]
 run["numrows"] = len(rows)
 if run["numrows"] > 0:
     lasteventtime = telemetry.getLastEventTimeAbs(rows)
     run["lasteventtime"] = lasteventtime
     rows.sort(
-        key=lambda row: "{}.{}.{:06d}".format(
-            row["client_id"], row["session_id"], int(row["seq"])
+        key=lambda row: "{}.{}.{}.{}.{:06d}".format(
+            row["client_id"],
+            row["session_id"],
+            row["seq"] >> 32,  # thread_id
+            row["submit_timeabs"],
+            row["seq"] & 0x00000000FFFFFFFF,  # seq,
         ),
         reverse=False,
     )
     outfile = "{}/qmrows_until_{}.json".format(workdir, lasteventtime)
     utils.writeJSONFile(outfile, rows)
     run["rawfile"] = outfile
 else:
     print("No results found, maybe next time.")
--- a/dom/quota/scripts/stackanalysis.py
+++ b/dom/quota/scripts/stackanalysis.py
@@ -115,55 +115,64 @@ def checkAverageFrameTimeDeltas(rows, ma
 # A topmost frame is considered to initiate a new raw stack. We collect all
 # candidates before we actually apply them. This implies, that we should run
 # this function on a "large enough" sample of rows to be more accurate.
 # As a side effect, we mark all rows that are part of a "complete" session
 # (a session, that started within our data scope).
 def collectTopmostFrames(rows):
     prev_cid = "unset"
     prev_sid = "unset"
+    prev_tid = "unset"
     prev_ctx = "unset"
     prev_sev = "ERROR"
     session_complete = False
     after_severity_downgrade = False
     for row in rows:
         cid = row["client_id"]
         sid = row["session_id"]
+        tid = row["seq"] >> 32  # thread_id
         ctx = row["context"]
-        seq = row["seq"]
+        seq = row["seq"] & 0x00000000FFFFFFFF  # seq
         sev = row["severity"]
 
         # If we have a new session, ensure it is complete from start,
         # otherwise we will ignore it entirely.
-        if cid != prev_cid or sid != prev_sid:
+        if cid != prev_cid or sid != prev_sid or tid != prev_tid:
             if seq == 1:
                 session_complete = True
             else:
                 session_complete = False
         row["session_complete"] = session_complete
         if session_complete:
-            # If we change client, session or context, we can be sure to have
+            # If we change client, session, thread or context, we can be sure to have
             # a new topmost frame.
-            if seq == 1 or cid != prev_cid or sid != prev_sid or ctx != prev_ctx:
+            if (
+                seq == 1
+                or cid != prev_cid
+                or sid != prev_sid
+                or tid != prev_tid
+                or ctx != prev_ctx
+            ):
                 addTopmostFrame(row)
                 after_severity_downgrade = False
             # We do not expect a non-error to be ever upgraded to an error
             elif sev == "ERROR" and prev_sev != "ERROR":
                 addTopmostFrame(row)
                 after_severity_downgrade = False
             # If we just had a severity downgrade, we assume that we wanted
             # to break the error propagation after this point and split, too
             elif after_severity_downgrade:
                 addTopmostFrame(row)
                 after_severity_downgrade = False
             elif prev_sev == "ERROR" and sev != "ERROR":
                 after_severity_downgrade = True
 
         prev_cid = cid
         prev_sid = sid
+        prev_tid = tid
         prev_ctx = ctx
         prev_sev = sev
 
     # Should be ms. We've seen quite some runtime between stackframes in the
     # wild. We might want to consider to make this configurable. In general
     # we prefer local context over letting slip through some topmost frame
     # unrecognized, assuming that fixing the issues one by one they will
     # uncover them succesively. This is achieved by a rather high delta value.
--- a/dom/streams/ReadableStream.h
+++ b/dom/streams/ReadableStream.h
@@ -129,17 +129,17 @@ class ReadableStream final : public nsIS
       ErrorResult& aRv);
 
   MOZ_CAN_RUN_SCRIPT void Tee(JSContext* aCx,
                               nsTArray<RefPtr<ReadableStream>>& aResult,
                               ErrorResult& aRv);
 
   // Internal Slots:
  private:
-  MOZ_KNOWN_LIVE RefPtr<ReadableStreamController> mController;
+  RefPtr<ReadableStreamController> mController;
   bool mDisturbed = false;
   RefPtr<ReadableStreamGenericReader> mReader;
   ReaderState mState = ReaderState::Readable;
   JS::Heap<JS::Value> mStoredError;
 
   // Optional Callback for erroring a stream.
   RefPtr<UnderlyingSourceAlgorithmsBase> mAlgorithms;
 
--- a/dom/streams/TransformStream.h
+++ b/dom/streams/TransformStream.h
@@ -70,19 +70,19 @@ class TransformStream final : public nsI
 
  private:
   nsCOMPtr<nsIGlobalObject> mGlobal;
 
   // Internal slots
   // MOZ_KNOWN_LIVE for slots that will never be reassigned
   bool mBackpressure = false;
   RefPtr<Promise> mBackpressureChangePromise;
-  MOZ_KNOWN_LIVE RefPtr<TransformStreamDefaultController> mController;
-  MOZ_KNOWN_LIVE RefPtr<ReadableStream> mReadable;
-  MOZ_KNOWN_LIVE RefPtr<WritableStream> mWritable;
+  RefPtr<TransformStreamDefaultController> mController;
+  RefPtr<ReadableStream> mReadable;
+  RefPtr<WritableStream> mWritable;
 };
 
 MOZ_CAN_RUN_SCRIPT void TransformStreamErrorWritableAndUnblockWrite(
     JSContext* aCx, TransformStream* aStream, JS::Handle<JS::Value> aError,
     ErrorResult& aRv);
 
 MOZ_CAN_RUN_SCRIPT void TransformStreamError(JSContext* aCx,
                                              TransformStream* aStream,
--- a/dom/streams/TransformStreamDefaultController.cpp
+++ b/dom/streams/TransformStreamDefaultController.cpp
@@ -149,17 +149,21 @@ void TransformStreamDefaultController::E
                                              JS::Handle<JS::Value> aError,
                                              ErrorResult& aRv) {
   // Step 1: Perform ? TransformStreamDefaultControllerError(this, e).
 
   // Inlining TransformStreamDefaultControllerError here.
   // https://streams.spec.whatwg.org/#transform-stream-default-controller-error
 
   // Perform ! TransformStreamError(controller.[[stream]], e).
-  TransformStreamError(aCx, mStream, aError, aRv);
+  // mStream is set in initialization step and only modified in cycle
+  // collection.
+  // TODO: Move mStream initialization to a method/constructor and make it
+  // MOZ_KNOWN_LIVE again. (See bug 1769854)
+  TransformStreamError(aCx, MOZ_KnownLive(mStream), aError, aRv);
 }
 
 // https://streams.spec.whatwg.org/#ts-default-controller-terminate
 
 void TransformStreamDefaultController::Terminate(JSContext* aCx,
                                                  ErrorResult& aRv) {
   // Step 1: Perform ? TransformStreamDefaultControllerTerminate(this).
 
--- a/dom/streams/TransformStreamDefaultController.h
+++ b/dom/streams/TransformStreamDefaultController.h
@@ -49,17 +49,17 @@ class TransformStreamDefaultController f
   MOZ_CAN_RUN_SCRIPT void Error(JSContext* aCx, JS::Handle<JS::Value> aError,
                                 ErrorResult& aRv);
   MOZ_CAN_RUN_SCRIPT void Terminate(JSContext* aCx, ErrorResult& aRv);
 
  private:
   nsCOMPtr<nsIGlobalObject> mGlobal;
 
   // Internal slots
-  MOZ_KNOWN_LIVE RefPtr<TransformStream> mStream;
+  RefPtr<TransformStream> mStream;
   RefPtr<TransformerAlgorithms> mTransformerAlgorithms;
 };
 
 void SetUpTransformStreamDefaultControllerFromTransformer(
     JSContext* aCx, TransformStream& aStream,
     JS::Handle<JSObject*> aTransformer, Transformer& aTransformerDict);
 
 }  // namespace mozilla::dom
--- a/dom/streams/WritableStream.h
+++ b/dom/streams/WritableStream.h
@@ -155,17 +155,17 @@ class WritableStream : public nsISupport
                                                      ErrorResult& aRv);
 
   already_AddRefed<WritableStreamDefaultWriter> GetWriter(ErrorResult& aRv);
 
   // Internal Slots:
  private:
   bool mBackpressure = false;
   RefPtr<Promise> mCloseRequest;
-  MOZ_KNOWN_LIVE RefPtr<WritableStreamDefaultController> mController;
+  RefPtr<WritableStreamDefaultController> mController;
   RefPtr<Promise> mInFlightWriteRequest;
   RefPtr<Promise> mInFlightCloseRequest;
 
   // We inline all members of [[pendingAbortRequest]] in this class.
   // The absence (i.e. undefined) of the [[pendingAbortRequest]]
   // is indicated by mPendingAbortRequestPromise = nullptr.
   RefPtr<Promise> mPendingAbortRequestPromise;
   JS::Heap<JS::Value> mPendingAbortRequestReason;
--- a/dom/tests/mochitest/bugs/test_bug396843.html
+++ b/dom/tests/mochitest/bugs/test_bug396843.html
@@ -9,17 +9,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=396843">Mozilla Bug 396843</a>
 <p id="display">
   <iframe src="http://example.org:80/" id="t"></iframe>
 </p>
 <div id="content" style="display: none">
-  
+
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 396843 **/
 SimpleTest.waitForExplicitFinish();
 
 var allNodes = [];
@@ -197,34 +197,31 @@ SVG_TAG("feDiffuseLighting")
 SVG_TAG("feSpecularLighting")
 SVG_TAG("feDisplacementMap")
 SVG_TAG("feImage")
 SVG_TAG("pattern")
 SVG_TAG("mask")
 SVG_TAG("svgSwitch")
 
 // Toss in some other namespaced stuff too, for good measure
-allNodes.push(document.createElementNS(
-               "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
-               "window"));
 allNodes.push(document.createElementNS("http://www.w3.org/1998/Math/MathML",
                                        "math"));
 allNodes.push(document.createElementNS("http://www.w3.org/2001/xml-events",
                                        "testname"));
 allNodes.push(document.createElementNS("bogus.namespace", "testname"));
 
 var XMLDoc = document.implementation.createDocument("", "", null);
 
 // And non-elements
 allNodes.push(document.createTextNode("some text"));
 allNodes.push(document.createComment("some text"));
 allNodes.push(document.createDocumentFragment());
 XMLNodes.push(XMLDoc.createCDATASection("some text"));
 XMLNodes.push(XMLDoc.createProcessingInstruction("PI", "data"));
-               
+
 function runTest() {
   ok(document.nodePrincipal === undefined, "Must not have document principal");
   ok(document.baseURIObject === undefined, "Must not have document base URI");
   ok(document.documentURIObject === undefined, "Must have document URI");
 
   for (var i = 0; i < allNodes.length; ++i) {
     ok(allNodes[i].nodePrincipal === undefined,
        "Unexpected principal appears for " + allNodes[i].nodeName);
--- a/dom/webidl/CanvasRenderingContext2D.webidl
+++ b/dom/webidl/CanvasRenderingContext2D.webidl
@@ -39,19 +39,23 @@ typedef (HTMLOrSVGImageElement or
 [Exposed=Window]
 interface CanvasRenderingContext2D {
 
   // back-reference to the canvas.  Might be null if we're not
   // associated with a canvas.
   readonly attribute HTMLCanvasElement? canvas;
 
   // Mozilla-specific stuff
-  [Throws]
+  [Deprecated="MozCurrentTransform",
+   Pref="dom.mozCurrentTransform.enabled",
+   Throws]
   attribute object mozCurrentTransform; // [ m11, m12, m21, m22, dx, dy ], i.e. row major
-  [Throws]
+  [Deprecated="MozCurrentTransformInverse",
+   Pref="dom.mozCurrentTransform.enabled",
+   Throws]
   attribute object mozCurrentTransformInverse;
 
   [SetterThrows]
   attribute UTF8String mozTextStyle;
 
   // image smoothing mode -- if disabled, images won't be smoothed
   // if scaled.
   [Deprecated="PrefixedImageSmoothingEnabled",
--- a/editor/libeditor/HTMLTableEditor.cpp
+++ b/editor/libeditor/HTMLTableEditor.cpp
@@ -46,18 +46,18 @@ namespace mozilla {
 using namespace dom;
 using EmptyCheckOption = HTMLEditUtils::EmptyCheckOption;
 
 /**
  * Stack based helper class for restoring selection after table edit.
  */
 class MOZ_STACK_CLASS AutoSelectionSetterAfterTableEdit final {
  private:
-  MOZ_KNOWN_LIVE RefPtr<HTMLEditor> mHTMLEditor;
-  MOZ_KNOWN_LIVE RefPtr<Element> mTable;
+  const RefPtr<HTMLEditor> mHTMLEditor;
+  const RefPtr<Element> mTable;
   int32_t mCol, mRow, mDirection, mSelected;
 
  public:
   AutoSelectionSetterAfterTableEdit(HTMLEditor& aHTMLEditor, Element* aTable,
                                     int32_t aRow, int32_t aCol,
                                     int32_t aDirection, bool aSelected)
       : mHTMLEditor(&aHTMLEditor),
         mTable(aTable),
@@ -67,23 +67,16 @@ class MOZ_STACK_CLASS AutoSelectionSette
         mSelected(aSelected) {}
 
   MOZ_CAN_RUN_SCRIPT ~AutoSelectionSetterAfterTableEdit() {
     if (mHTMLEditor) {
       mHTMLEditor->SetSelectionAfterTableEdit(mTable, mRow, mCol, mDirection,
                                               mSelected);
     }
   }
-
-  // This is needed to abort the caret reset in the destructor
-  // when one method yields control to another
-  void CancelSetCaret() {
-    mHTMLEditor = nullptr;
-    mTable = nullptr;
-  }
 };
 
 /******************************************************************************
  * HTMLEditor::CellIndexes
  ******************************************************************************/
 
 void HTMLEditor::CellIndexes::Update(HTMLEditor& aHTMLEditor,
                                      Selection& aSelection) {
--- a/gfx/2d/Matrix.h
+++ b/gfx/2d/Matrix.h
@@ -195,28 +195,36 @@ class BaseMatrix {
   BaseMatrix<T>& PostTranslate(const MatrixPoint& aPoint) {
     return PostTranslate(aPoint.x, aPoint.y);
   }
 
   static BaseMatrix<T> Scaling(T aScaleX, T aScaleY) {
     return BaseMatrix<T>(aScaleX, 0.0f, 0.0f, aScaleY, 0.0f, 0.0f);
   }
 
+  static BaseMatrix<T> Scaling(const BaseMatrixScales<T>& scale) {
+    return Scaling(scale.xScale, scale.yScale);
+  }
+
   /**
    * Similar to PreTranslate, but applies a scale instead of a translation.
    */
   BaseMatrix<T>& PreScale(T aX, T aY) {
     _11 *= aX;
     _12 *= aX;
     _21 *= aY;
     _22 *= aY;
 
     return *this;
   }
 
+  BaseMatrix<T>& PreScale(const BaseMatrixScales<T>& scale) {
+    return PreScale(scale.xScale, scale.yScale);
+  }
+
   /**
    * Similar to PostTranslate, but applies a scale instead of a translation.
    */
   BaseMatrix<T>& PostScale(T aScaleX, T aScaleY) {
     _11 *= aScaleX;
     _12 *= aScaleY;
     _21 *= aScaleX;
     _22 *= aScaleY;
--- a/gfx/2d/ScaleFactors2D.h
+++ b/gfx/2d/ScaleFactors2D.h
@@ -158,16 +158,21 @@ struct BaseScaleFactors2D {
     return BaseScaleFactors2D<Other, Src, T>(aA) * aB;
   }
 
   template <class Other>
   friend BaseScaleFactors2D<Other, Src, T> operator/(
       const ScaleFactor<Other, Dst>& aA, const BaseScaleFactors2D& aB) {
     return BaseScaleFactors2D<Other, Src, T>(aA) / aB;
   }
+
+  static BaseScaleFactors2D<Src, Dst, T> FromUnknownScale(
+      const BaseScaleFactors2D<UnknownUnits, UnknownUnits, T>& scale) {
+    return BaseScaleFactors2D<Src, Dst, T>(scale.xScale, scale.yScale);
+  }
 };
 
 template <class Src, class Dst>
 using ScaleFactors2D = BaseScaleFactors2D<Src, Dst, float>;
 
 template <class Src, class Dst>
 using ScaleFactors2DDouble = BaseScaleFactors2D<Src, Dst, double>;
 
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -722,31 +722,31 @@ AsyncPanZoomController::AsyncPanZoomCont
     GeckoContentController* aGeckoContentController, GestureBehavior aGestures)
     : mLayersId(aLayersId),
       mGeckoContentController(aGeckoContentController),
       mRefPtrMonitor("RefPtrMonitor"),
       // mTreeManager must be initialized before GetFrameTime() is called
       mTreeManager(aTreeManager),
       mRecursiveMutex("AsyncPanZoomController"),
       mLastContentPaintMetrics(mLastContentPaintMetadata.GetMetrics()),
-      mX(this),
-      mY(this),
       mPanDirRestricted(false),
       mPinchLocked(false),
       mPinchEventBuffer(TimeDuration::FromMilliseconds(
           StaticPrefs::apz_pinch_lock_buffer_max_age_AtStartup())),
       mZoomConstraints(false, false,
                        mScrollMetadata.GetMetrics().GetDevPixelsPerCSSPixel() *
                            kViewportMinScale / ParentLayerToScreenScale(1),
                        mScrollMetadata.GetMetrics().GetDevPixelsPerCSSPixel() *
                            kViewportMaxScale / ParentLayerToScreenScale(1)),
       mLastSampleTime(GetFrameTime()),
       mLastCheckerboardReport(GetFrameTime()),
       mOverscrollEffect(MakeUnique<OverscrollEffect>(*this)),
       mState(NOTHING),
+      mX(this),
+      mY(this),
       mNotificationBlockers(0),
       mInputQueue(aInputQueue),
       mPinchPaintTimerSet(false),
       mTestAttributeAppliers(0),
       mTestHasAsyncKeyScrolled(false),
       mCheckerboardEventLock("APZCBELock") {
   if (aGestures == USE_GESTURE_DETECTOR) {
     mGestureEventListener = new GestureEventListener(this);
@@ -1424,17 +1424,17 @@ nsEventStatus AsyncPanZoomController::On
       }
       return nsEventStatus_eIgnore;
 
     case PANNING:
     case PANNING_LOCKED_X:
     case PANNING_LOCKED_Y:
     case PAN_MOMENTUM: {
       MOZ_ASSERT(GetCurrentTouchBlock());
-      EndTouch(aEvent.mTimeStamp);
+      EndTouch(aEvent.mTimeStamp, Axis::ClearAxisLock::Yes);
       return HandleEndOfPan();
     }
     case PINCHING:
       SetState(NOTHING);
       // Scale gesture listener should have handled this.
       NS_WARNING(
           "Gesture listener should have handled pinching in OnTouchEnd.");
       return nsEventStatus_eIgnore;
@@ -1771,17 +1771,17 @@ nsEventStatus AsyncPanZoomController::On
       } else {
         ClearOverscroll();
       }
       // Along with clearing the overscroll, we also want to snap to the nearest
       // snap point as appropriate.
       ScrollSnap(ScrollSnapFlags::IntendedEndPosition);
     } else {
       // when zoom is not allowed
-      EndTouch(aEvent.mTimeStamp);
+      EndTouch(aEvent.mTimeStamp, Axis::ClearAxisLock::Yes);
       if (stateWasPinching) {
         // still pinching
         if (HasReadyTouchBlock()) {
           return HandleEndOfPan();
         }
       }
     }
   }
@@ -2763,17 +2763,19 @@ nsEventStatus AsyncPanZoomController::On
   APZC_LOG_DETAIL("got a pan-end in state %s\n", this,
                   ToString(mState).c_str());
 
   if (aEvent.mPanDisplacement != ScreenPoint{}) {
     // Call into OnPan in order to process the delta included in this event.
     OnPan(aEvent, FingersOnTouchpad::Yes);
   }
 
-  EndTouch(aEvent.mTimeStamp);
+  // Do not unlock the axis lock at the end of a pan gesture. The axis lock
+  // should extend into the momentum scroll.
+  EndTouch(aEvent.mTimeStamp, Axis::ClearAxisLock::No);
 
   // Use HandleEndOfPan for fling on platforms that don't
   // emit momentum events (Gtk).
   if (aEvent.mSimulateMomentum) {
     return HandleEndOfPan();
   }
 
   MOZ_ASSERT(GetCurrentPanGestureBlock());
@@ -3244,23 +3246,39 @@ void AsyncPanZoomController::HandlePanni
         StaticPrefs::apz_axis_lock_breakout_threshold() * GetDPI();
 
     if (fabs(aPanDistance.x) > breakThreshold ||
         fabs(aPanDistance.y) > breakThreshold) {
       if (mState == PANNING_LOCKED_X) {
         if (!apz::IsCloseToHorizontal(
                 angle, StaticPrefs::apz_axis_lock_breakout_angle())) {
           mY.SetAxisLocked(false);
-          SetState(PANNING);
+          // If we are within the breakout angle from the Y axis, lock
+          // onto the Y axis.
+          if (apz::IsCloseToVertical(
+                  angle, StaticPrefs::apz_axis_lock_breakout_angle())) {
+            mX.SetAxisLocked(true);
+            SetState(PANNING_LOCKED_Y);
+          } else {
+            SetState(PANNING);
+          }
         }
       } else if (mState == PANNING_LOCKED_Y) {
         if (!apz::IsCloseToVertical(
                 angle, StaticPrefs::apz_axis_lock_breakout_angle())) {
           mX.SetAxisLocked(false);
-          SetState(PANNING);
+          // If we are within the breakout angle from the X axis, lock
+          // onto the X axis.
+          if (apz::IsCloseToHorizontal(
+                  angle, StaticPrefs::apz_axis_lock_breakout_angle())) {
+            mY.SetAxisLocked(true);
+            SetState(PANNING_LOCKED_X);
+          } else {
+            SetState(PANNING);
+          }
         }
       }
     }
   }
 }
 
 void AsyncPanZoomController::HandlePinchLocking(
     const PinchGestureInput& aEvent) {
@@ -3844,20 +3862,21 @@ void AsyncPanZoomController::RecordScrol
 
 void AsyncPanZoomController::StartTouch(const ParentLayerPoint& aPoint,
                                         TimeStamp aTimestamp) {
   RecursiveMutexAutoLock lock(mRecursiveMutex);
   mX.StartTouch(aPoint.x, aTimestamp);
   mY.StartTouch(aPoint.y, aTimestamp);
 }
 
-void AsyncPanZoomController::EndTouch(TimeStamp aTimestamp) {
+void AsyncPanZoomController::EndTouch(TimeStamp aTimestamp,
+                                      Axis::ClearAxisLock aClearAxisLock) {
   RecursiveMutexAutoLock lock(mRecursiveMutex);
-  mX.EndTouch(aTimestamp);
-  mY.EndTouch(aTimestamp);
+  mX.EndTouch(aTimestamp, aClearAxisLock);
+  mY.EndTouch(aTimestamp, aClearAxisLock);
 }
 
 void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
   ExternalPoint extPoint = GetFirstExternalTouchPoint(aEvent);
   ScreenPoint panVector = PanVector(extPoint);
   HandlePanningUpdate(panVector);
 
   ParentLayerPoint prevTouchPoint(mX.GetPos(), mY.GetPos());
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -880,17 +880,17 @@ class AsyncPanZoomController {
    * Register the start of a touch or pan gesture at the given position and
    * time.
    */
   void StartTouch(const ParentLayerPoint& aPoint, TimeStamp aTimestamp);
 
   /**
    * Register the end of a touch or pan gesture at the given time.
    */
-  void EndTouch(TimeStamp aTimestamp);
+  void EndTouch(TimeStamp aTimestamp, Axis::ClearAxisLock aClearAxisLock);
 
   /**
    * Utility function to send updated FrameMetrics to Gecko so that it can paint
    * the displayport area. Calls into GeckoContentController to do the actual
    * work. This call will use the current metrics. If this function is called
    * from a non-main thread, it will redispatch itself to the main thread, and
    * use the latest metrics during the redispatch.
    */
@@ -934,17 +934,17 @@ class AsyncPanZoomController {
    * to the parent document. This excludes the transient compositor transform.
    * NOTE: This must be converted to LayoutDevicePoint relative to the child
    * document before sending over IPC to a child process.
    */
   Maybe<LayoutDevicePoint> ConvertToGecko(const ScreenIntPoint& aPoint);
 
   enum AxisLockMode {
     FREE,     /* No locking at all */
-    STANDARD, /* Default axis locking mode that remains locked until pan ends*/
+    STANDARD, /* Default axis locking mode that remains locked until pan ends */
     STICKY,   /* Allow lock to be broken, with hysteresis */
   };
 
   static AxisLockMode GetAxisLockMode();
 
   enum PinchLockMode {
     PINCH_FREE,     /* No locking at all */
     PINCH_STANDARD, /* Default pinch locking mode that remains locked until
@@ -1045,19 +1045,16 @@ class AsyncPanZoomController {
   // Samples should be inserted to the "back" of the deque and extracted from
   // the "front".
   std::deque<SampledAPZCState> mSampledState;
 
   // Groups state variables that are specific to a platform.
   // Initialized on first use.
   UniquePtr<PlatformSpecificStateBase> mPlatformSpecificState;
 
-  AxisX mX;
-  AxisY mY;
-
   // This flag is set to true when we are in a axis-locked pan as a result of
   // the touch-action CSS property.
   bool mPanDirRestricted;
 
   // This flag is set to true when we are in a pinch-locked state. ie: user
   // is performing a two-finger pan rather than a pinch gesture
   bool mPinchLocked;
 
@@ -1349,16 +1346,19 @@ class AsyncPanZoomController {
                       */
     AUTOSCROLL,      /* Autoscroll animation. */
     SCROLLBAR_DRAG   /* Async scrollbar drag. */
   };
   // This is in theory protected by |mRecursiveMutex|; that is, it should be
   // held whenever this is updated. In practice though... see bug 897017.
   PanZoomState mState;
 
+  AxisX mX;
+  AxisY mY;
+
   static bool IsPanningState(PanZoomState aState);
 
   /**
    * Returns whether the specified PanZoomState does not need to be reset when
    * a scroll offset update is processed.
    */
   static bool CanHandleScrollOffsetUpdate(PanZoomState aState);
 
--- a/gfx/layers/apz/src/Axis.cpp
+++ b/gfx/layers/apz/src/Axis.cpp
@@ -279,46 +279,49 @@ void Axis::ClearOverscroll() {
 ParentLayerCoord Axis::PanStart() const { return mStartPos; }
 
 ParentLayerCoord Axis::PanDistance() const { return fabs(mPos - mStartPos); }
 
 ParentLayerCoord Axis::PanDistance(ParentLayerCoord aPos) const {
   return fabs(aPos - mStartPos);
 }
 
-void Axis::EndTouch(TimeStamp aTimestamp) {
+void Axis::EndTouch(TimeStamp aTimestamp, ClearAxisLock aClearAxisLock) {
   // mVelocityQueue is controller-thread only
   APZThreadUtils::AssertOnControllerThread();
 
   // If the velocity tracker wasn't able to compute a velocity, zero out
   // the velocity to make sure we don't get a fling based on some old and
   // no-longer-relevant value of mVelocity. Also if the axis is locked then
   // just reset the velocity to 0 since we don't need any velocity to carry
   // into the fling.
   if (mAxisLocked) {
     DoSetVelocity(0);
   } else if (Maybe<float> velocity =
                  mVelocityTracker->ComputeVelocity(aTimestamp)) {
     DoSetVelocity(*velocity);
   } else {
     DoSetVelocity(0);
   }
-  mAxisLocked = false;
+  if (aClearAxisLock == ClearAxisLock::Yes) {
+    mAxisLocked = false;
+  }
   AXIS_LOG("%p|%s ending touch, computed velocity %f\n",
            mAsyncPanZoomController, Name(), DoGetVelocity());
 }
 
 void Axis::CancelGesture() {
   // mVelocityQueue is controller-thread only
   APZThreadUtils::AssertOnControllerThread();
 
   AXIS_LOG("%p|%s cancelling touch, clearing velocity queue\n",
            mAsyncPanZoomController, Name());
   DoSetVelocity(0.0f);
   mVelocityTracker->Clear();
+  SetAxisLocked(false);
 }
 
 bool Axis::CanScroll() const {
   return GetPageLength() - GetCompositionLength() > COORDINATE_EPSILON;
 }
 
 bool Axis::CanScroll(ParentLayerCoord aDelta) const {
   if (!CanScroll() || mAxisLocked) {
--- a/gfx/layers/apz/src/Axis.h
+++ b/gfx/layers/apz/src/Axis.h
@@ -91,20 +91,25 @@ class Axis {
  public:
   /**
    * Notify this Axis that a touch has begun, i.e. the user has put their finger
    * on the screen but has not yet tried to pan.
    */
   void StartTouch(ParentLayerCoord aPos, TimeStamp aTimestamp);
 
   /**
+   * Helper enum class for specifying if EndTouch() should clear the axis lock.
+   */
+  enum class ClearAxisLock { Yes, No };
+
+  /**
    * Notify this Axis that a touch has ended gracefully. This may perform
    * recalculations of the axis velocity.
    */
-  void EndTouch(TimeStamp aTimestamp);
+  void EndTouch(TimeStamp aTimestamp, ClearAxisLock aClearAxisLock);
 
   /**
    * Notify this Axis that the gesture has ended forcefully. Useful for stopping
    * flings when a user puts their finger down in the middle of one (i.e. to
    * stop a previous touch including its fling so that a new one can take its
    * place).
    */
   void CancelGesture();
--- a/gfx/layers/apz/test/gtest/APZTestCommon.h
+++ b/gfx/layers/apz/test/gtest/APZTestCommon.h
@@ -332,30 +332,53 @@ class TestAsyncPanZoomController : publi
     EXPECT_EQ(SMOOTH_SCROLL, mState);
   }
 
   void AssertStateIsSmoothMsdScroll() const {
     RecursiveMutexAutoLock lock(mRecursiveMutex);
     EXPECT_EQ(SMOOTHMSD_SCROLL, mState);
   }
 
-  void AssertNotAxisLocked() const {
+  void AssertStateIsPanningLockedY() {
+    RecursiveMutexAutoLock lock(mRecursiveMutex);
+    EXPECT_EQ(PANNING_LOCKED_Y, mState);
+  }
+
+  void AssertStateIsPanningLockedX() {
+    RecursiveMutexAutoLock lock(mRecursiveMutex);
+    EXPECT_EQ(PANNING_LOCKED_X, mState);
+  }
+
+  void AssertStateIsPanning() {
     RecursiveMutexAutoLock lock(mRecursiveMutex);
     EXPECT_EQ(PANNING, mState);
   }
 
+  void AssertStateIsPanMomentum() {
+    RecursiveMutexAutoLock lock(mRecursiveMutex);
+    EXPECT_EQ(PAN_MOMENTUM, mState);
+  }
+
+  void AssertNotAxisLocked() const {
+    EXPECT_FALSE(mY.IsAxisLocked());
+    EXPECT_FALSE(mX.IsAxisLocked());
+  }
+
   void AssertAxisLocked(ScrollDirection aDirection) const {
-    RecursiveMutexAutoLock lock(mRecursiveMutex);
     switch (aDirection) {
       case ScrollDirection::eHorizontal:
-        EXPECT_EQ(PANNING_LOCKED_X, mState);
+        EXPECT_TRUE(mY.IsAxisLocked());
+        EXPECT_FALSE(mX.IsAxisLocked());
         break;
       case ScrollDirection::eVertical:
-        EXPECT_EQ(PANNING_LOCKED_Y, mState);
+        EXPECT_TRUE(mX.IsAxisLocked());
+        EXPECT_FALSE(mY.IsAxisLocked());
         break;
+      default:
+        FAIL() << "input direction must be either vertical or horizontal";
     }
   }
 
   void AdvanceAnimationsUntilEnd(
       const TimeDuration& aIncrement = TimeDuration::FromMilliseconds(10)) {
     while (AdvanceAnimations(mcc->GetSampleTime())) {
       mcc->AdvanceBy(aIncrement);
     }
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/test/gtest/TestAxisLock.cpp
@@ -0,0 +1,419 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "APZCTreeManagerTester.h"
+#include "APZTestCommon.h"
+
+#include "InputUtils.h"
+#include "gtest/gtest.h"
+
+#include <cmath>
+
+class APZCAxisLockTester : public APZCTreeManagerTester {
+ public:
+  APZCAxisLockTester() { CreateMockHitTester(); }
+
+  UniquePtr<ScopedLayerTreeRegistration> registration;
+
+  RefPtr<TestAsyncPanZoomController> apzc;
+
+  void SetupBasicTest() {
+    const char* treeShape = "x";
+    LayerIntRegion layerVisibleRegion[] = {
+        LayerIntRect(0, 0, 100, 100),
+    };
+    CreateScrollData(treeShape, layerVisibleRegion);
+    SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID,
+                              CSSRect(0, 0, 500, 500));
+
+    registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc);
+
+    UpdateHitTestingTree();
+  }
+
+  void BreakStickyAxisLockTestGesture(ScrollDirections aDirections) {
+    float panX = 0;
+    float panY = 0;
+
+    if (aDirections.contains(ScrollDirection::eVertical)) {
+      panY = 30;
+    }
+    if (aDirections.contains(ScrollDirection::eHorizontal)) {
+      panX = 30;
+    }
+
+    // Kick off the gesture that may lock onto an axis
+    QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+    PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50),
+               ScreenPoint(panX, panY), mcc->Time());
+    mcc->AdvanceByMillis(5);
+    apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+    QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+    PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50),
+               ScreenPoint(panX, panY), mcc->Time());
+  }
+
+  void BreakStickyAxisLockTest(ScrollDirections aDirections) {
+    // Create the gesture for the test.
+    BreakStickyAxisLockTestGesture(aDirections);
+
+    // Based on the scroll direction(s) ensure the state is what we expect.
+    if (aDirections == ScrollDirection::eVertical) {
+      apzc->AssertStateIsPanningLockedY();
+      apzc->AssertAxisLocked(ScrollDirection::eVertical);
+      EXPECT_GT(apzc->GetVelocityVector().y, 0);
+      EXPECT_EQ(apzc->GetVelocityVector().x, 0);
+    } else if (aDirections == ScrollDirection::eHorizontal) {
+      apzc->AssertStateIsPanningLockedX();
+      apzc->AssertAxisLocked(ScrollDirection::eHorizontal);
+      EXPECT_GT(apzc->GetVelocityVector().x, 0);
+      EXPECT_EQ(apzc->GetVelocityVector().y, 0);
+    } else {
+      apzc->AssertStateIsPanning();
+      apzc->AssertNotAxisLocked();
+      EXPECT_GT(apzc->GetVelocityVector().x, 0);
+      EXPECT_GT(apzc->GetVelocityVector().y, 0);
+    }
+
+    // Cleanup for next test.
+    apzc->AdvanceAnimationsUntilEnd();
+  }
+};
+
+TEST_F(APZCAxisLockTester, BasicDominantAxisUse) {
+  SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 1);
+  SCOPED_GFX_PREF_FLOAT("apz.axis_lock.lock_angle", M_PI / 4.0f);
+
+  SetupBasicTest();
+
+  apzc = ApzcOf(root);
+
+  // Kick off the initial gesture that triggers the momentum scroll.
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50),
+             ScreenIntPoint(1, 2), mcc->Time());
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50),
+             ScreenPoint(15, 30), mcc->Time());
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50),
+             ScreenPoint(15, 30), mcc->Time());
+
+  // Should be in a PANNING_LOCKED_Y state with no horizontal velocity.
+  apzc->AssertStateIsPanningLockedY();
+  apzc->AssertAxisLocked(ScrollDirection::eVertical);
+  EXPECT_GT(apzc->GetVelocityVector().y, 0);
+  EXPECT_EQ(apzc->GetVelocityVector().x, 0);
+
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50),
+             ScreenPoint(0, 0), mcc->Time());
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  // Ensure that we have not panned on the horizontal axis.
+  ParentLayerPoint panEndOffset = apzc->GetCurrentAsyncScrollOffset(
+      AsyncPanZoomController::AsyncTransformConsumer::eForHitTesting);
+  EXPECT_EQ(panEndOffset.x, 0);
+
+  // The lock onto the Y axis extends into momentum scroll.
+  apzc->AssertAxisLocked(ScrollDirection::eVertical);
+
+  // Start the momentum scroll.
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, manager,
+             ScreenIntPoint(50, 50), ScreenPoint(30, 90), mcc->Time());
+  mcc->AdvanceByMillis(10);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, manager,
+             ScreenIntPoint(50, 50), ScreenPoint(10, 30), mcc->Time());
+  mcc->AdvanceByMillis(10);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, manager,
+             ScreenIntPoint(50, 50), ScreenPoint(10, 30), mcc->Time());
+  mcc->AdvanceByMillis(10);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  // In momentum locking mode, we should still be locked onto the Y axis.
+  apzc->AssertStateIsPanMomentum();
+  apzc->AssertAxisLocked(ScrollDirection::eVertical);
+  EXPECT_GT(apzc->GetVelocityVector().y, 0);
+  EXPECT_EQ(apzc->GetVelocityVector().x, 0);
+
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, manager,
+             ScreenIntPoint(50, 50), ScreenPoint(0, 0), mcc->Time());
+
+  // After momentum scroll end, ensure we are no longer locked onto an axis.
+  apzc->AssertNotAxisLocked();
+
+  // Wait until the end of the animation and ensure the final state is
+  // reasonable.
+  apzc->AdvanceAnimationsUntilEnd();
+  ParentLayerPoint finalOffset = apzc->GetCurrentAsyncScrollOffset(
+      AsyncPanZoomController::AsyncTransformConsumer::eForHitTesting);
+
+  // Ensure we have scrolled some amount on the Y axis in momentum scroll.
+  EXPECT_GT(finalOffset.y, panEndOffset.y);
+  EXPECT_EQ(finalOffset.x, 0.0f);
+}
+
+TEST_F(APZCAxisLockTester, NewGestureBreaksMomentumAxisLock) {
+  SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 1);
+  SCOPED_GFX_PREF_FLOAT("apz.axis_lock.lock_angle", M_PI / 4.0f);
+
+  SetupBasicTest();
+
+  apzc = ApzcOf(root);
+
+  // Kick off the initial gesture that triggers the momentum scroll.
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50),
+             ScreenIntPoint(2, 1), mcc->Time());
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50),
+             ScreenPoint(30, 15), mcc->Time());
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50),
+             ScreenPoint(30, 15), mcc->Time());
+
+  // Should be in a PANNING_LOCKED_X state with no vertical velocity.
+  apzc->AssertStateIsPanningLockedX();
+  apzc->AssertAxisLocked(ScrollDirection::eHorizontal);
+  EXPECT_GT(apzc->GetVelocityVector().x, 0);
+  EXPECT_EQ(apzc->GetVelocityVector().y, 0);
+
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50),
+             ScreenPoint(0, 0), mcc->Time());
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  // Double check that we have not panned on the vertical axis.
+  ParentLayerPoint panEndOffset = apzc->GetCurrentAsyncScrollOffset(
+      AsyncPanZoomController::AsyncTransformConsumer::eForHitTesting);
+  EXPECT_EQ(panEndOffset.y, 0);
+
+  // Ensure that the axis locks extends into momentum scroll.
+  apzc->AssertAxisLocked(ScrollDirection::eHorizontal);
+
+  // Start the momentum scroll.
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, manager,
+             ScreenIntPoint(50, 50), ScreenPoint(80, 40), mcc->Time());
+  mcc->AdvanceByMillis(10);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, manager,
+             ScreenIntPoint(50, 50), ScreenPoint(20, 10), mcc->Time());
+  mcc->AdvanceByMillis(10);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, manager,
+             ScreenIntPoint(50, 50), ScreenPoint(20, 10), mcc->Time());
+  mcc->AdvanceByMillis(10);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  // In momentum locking mode, we should still be locked onto the X axis.
+  apzc->AssertStateIsPanMomentum();
+  apzc->AssertAxisLocked(ScrollDirection::eHorizontal);
+  EXPECT_GT(apzc->GetVelocityVector().x, 0);
+  EXPECT_EQ(apzc->GetVelocityVector().y, 0);
+
+  ParentLayerPoint beforeBreakOffset = apzc->GetCurrentAsyncScrollOffset(
+      AsyncPanZoomController::AsyncTransformConsumer::eForHitTesting);
+  EXPECT_EQ(beforeBreakOffset.y, 0);
+  // Ensure we have scrolled some amount on the X axis in momentum scroll.
+  EXPECT_GT(beforeBreakOffset.x, panEndOffset.x);
+
+  // Kick off the gesture that breaks the lock onto the X axis.
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50),
+             ScreenIntPoint(1, 2), mcc->Time());
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  ParentLayerPoint afterBreakOffset = apzc->GetCurrentAsyncScrollOffset(
+      AsyncPanZoomController::AsyncTransformConsumer::eForHitTesting);
+
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50),
+             ScreenPoint(15, 30), mcc->Time());
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50),
+             ScreenPoint(15, 30), mcc->Time());
+
+  // The lock onto the X axis should be broken and we now should be locked
+  // onto the Y axis.
+  apzc->AssertStateIsPanningLockedY();
+  apzc->AssertAxisLocked(ScrollDirection::eVertical);
+  EXPECT_GT(apzc->GetVelocityVector().y, 0);
+  EXPECT_EQ(apzc->GetVelocityVector().x, 0);
+
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50),
+             ScreenPoint(0, 0), mcc->Time());
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  // The lock onto the Y axis extends into momentum scroll.
+  apzc->AssertAxisLocked(ScrollDirection::eVertical);
+
+  // Wait until the end of the animation and ensure the final state is
+  // reasonable.
+  apzc->AdvanceAnimationsUntilEnd();
+  ParentLayerPoint finalOffset = apzc->GetCurrentAsyncScrollOffset(
+      AsyncPanZoomController::AsyncTransformConsumer::eForHitTesting);
+
+  EXPECT_GT(finalOffset.y, 0);
+  // Ensure that we did not scroll on the X axis after the vertical scroll
+  // started.
+  EXPECT_EQ(finalOffset.x, afterBreakOffset.x);
+}
+
+TEST_F(APZCAxisLockTester, BreakStickyAxisLock) {
+  SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 2);
+  SCOPED_GFX_PREF_FLOAT("apz.axis_lock.lock_angle", M_PI / 6.0f);
+  SCOPED_GFX_PREF_FLOAT("apz.axis_lock.breakout_angle", M_PI / 6.0f);
+
+  SetupBasicTest();
+
+  apzc = ApzcOf(root);
+
+  // Start a gesture to get us locked onto the Y axis.
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50),
+             ScreenIntPoint(0, 2), mcc->Time());
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  // Ensure that we have locked onto the Y axis.
+  apzc->AssertStateIsPanningLockedY();
+
+  // Test switch to locking onto the X axis.
+  BreakStickyAxisLockTest(ScrollDirection::eHorizontal);
+
+  // Test switch back to locking onto the Y axis.
+  BreakStickyAxisLockTest(ScrollDirection::eVertical);
+
+  // Test breaking all axis locks from a Y axis lock.
+  BreakStickyAxisLockTest(ScrollDirections(ScrollDirection::eHorizontal,
+                                           ScrollDirection::eVertical));
+
+  // Once we're no longer locked onto an axis, there is no way back. Run a
+  // gesture that would normally lock us onto the X axis, but we should stay
+  // in a panning state.
+  BreakStickyAxisLockTestGesture(ScrollDirection::eHorizontal);
+  apzc->AssertStateIsPanning();
+  apzc->AssertNotAxisLocked();
+
+  // End the gesture.
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50),
+             ScreenPoint(0, 0), mcc->Time());
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  // Start a gesture to get us locked onto the X axis.
+  QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+  PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50),
+             ScreenIntPoint(2, 0), mcc->Time());
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+  // Ensure that we have locked onto the X axis.
+  apzc->AssertStateIsPanningLockedX();
+
+  // Test breaking all axis locks from a X axis lock.
+  BreakStickyAxisLockTest(ScrollDirections(ScrollDirection::eHorizontal,
+                                           ScrollDirection::eVertical));
+}
+
+TEST_F(APZCAxisLockTester, TestDominantAxisScrolling) {
+  SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 2);
+  SCOPED_GFX_PREF_FLOAT("apz.axis_lock.lock_angle", M_PI / 4.0f);
+  SCOPED_GFX_PREF_FLOAT("apz.axis_lock.breakout_angle", M_PI / 4.0f);
+
+  int panY;
+  int panX;
+
+  SetupBasicTest();
+
+  apzc = ApzcOf(root);
+
+  ParentLayerPoint lastOffset =
+      apzc->GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForHitTesting);
+
+  // In dominant axis mode, test pan gesture events with varying gesture
+  // angles and ensure that we only pan on one axis.
+  for (panX = 0, panY = 50; panY >= 0; panY -= 10, panX += 10) {
+    // Gesture that should be locked onto one axis
+    QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+    PanGesture(PanGestureInput::PANGESTURE_START, manager,
+               ScreenIntPoint(50, 50), ScreenIntPoint(panX, panY), mcc->Time());
+    mcc->AdvanceByMillis(5);
+    apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+    QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+    PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50),
+               ScreenPoint(panX, panY), mcc->Time());
+    mcc->AdvanceByMillis(5);
+    apzc->AdvanceAnimations(mcc->GetSampleTime());
+
+    QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
+    PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50),
+               ScreenPoint(0, 0), mcc->Time());
+    apzc->AdvanceAnimationsUntilEnd();
+
+    ParentLayerPoint scrollOffset = apzc->GetCurrentAsyncScrollOffset(
+        AsyncPanZoomController::eForHitTesting);
+
+    if (panX > panY) {
+      // If we're closer to the X axis ensure that we moved on the horizontal
+      // axis and there was no movement on the vertical axis.
+      EXPECT_GT(scrollOffset.x, lastOffset.x);
+      EXPECT_EQ(scrollOffset.y, lastOffset.y);
+    } else {
+      // If we're closer to the Y axis ensure that we moved on the vertical
+      // axis and there was no movement on the horizontal axis.
+      EXPECT_GT(scrollOffset.y, lastOffset.y);
+      EXPECT_EQ(scrollOffset.x, lastOffset.x);
+    }
+
+    lastOffset = scrollOffset;
+  }
+}
--- a/gfx/layers/apz/test/gtest/TestGestureDetector.cpp
+++ b/gfx/layers/apz/test/gtest/TestGestureDetector.cpp
@@ -28,16 +28,19 @@ class APZCGestureDetectorTester : public
     fm.SetIsRootContent(true);
     // the visible area of the document in CSS pixels is x=300 y=300 w=50 h=100
     return fm;
   }
 };
 
 #ifndef MOZ_WIDGET_ANDROID  // Currently fails on Android
 TEST_F(APZCGestureDetectorTester, Pan_After_Pinch) {
+  SCOPED_GFX_PREF_FLOAT("apz.axis_lock.lock_angle", M_PI / 6.0f);
+  SCOPED_GFX_PREF_FLOAT("apz.axis_lock.breakout_angle", M_PI / 8.0f);
+
   FrameMetrics originalMetrics = GetPinchableFrameMetrics();
   apzc->SetFrameMetrics(originalMetrics);
 
   MakeApzcZoomable();
 
   // Test parameters
   float zoomAmount = 1.25;
   float pinchLength = 100.0;
--- a/gfx/layers/apz/test/gtest/TestOverscroll.cpp
+++ b/gfx/layers/apz/test/gtest/TestOverscroll.cpp
@@ -790,16 +790,32 @@ TEST_F(APZCOverscrollTester,
   EXPECT_NE(initialOverscrolledTransform._41, currentOverscrolledTransform._41);
   // There is no overscroll on Y axis.
   EXPECT_EQ(currentOverscrolledTransform._42, 0);
   ParentLayerPoint scrollOffset =
       apzc->GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForHitTesting);
   // The scroll offset shouldn't be changed by the overscroll animation.
   EXPECT_EQ(scrollOffset.y, 0);
 
+  // Simple gesture on the Y axis to ensure that we can send a vertical
+  // momentum scroll
+  PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80),
+             ScreenPoint(0, -2), mcc->Time());
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+  PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
+             ScreenPoint(0, 2), mcc->Time());
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+  PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80),
+             ScreenPoint(0, 0), mcc->Time());
+
+  ParentLayerPoint offsetAfterPan =
+      apzc->GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForHitTesting);
+
   PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, apzc,
              ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time());
   EXPECT_TRUE(apzc->IsOverscrolled());
   EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
   // The overscroll amount on both axes shouldn't be changed by this pan
   // momentum start event since the displacement is zero.
   EXPECT_EQ(
       currentOverscrolledTransform._41,
@@ -812,21 +828,22 @@ TEST_F(APZCOverscrollTester,
   apzc->AdvanceAnimations(mcc->GetSampleTime());
   // The overscroll amount should be managed by the overscroll animation.
   EXPECT_NE(
       currentOverscrolledTransform._41,
       apzc->GetOverscrollTransform(AsyncPanZoomController::eForHitTesting)._41);
   scrollOffset =
       apzc->GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForHitTesting);
   // Not yet started scrolling.
-  EXPECT_EQ(scrollOffset.y, 0);
+  EXPECT_EQ(scrollOffset.y, offsetAfterPan.y);
   EXPECT_EQ(scrollOffset.x, 0);
 
   currentOverscrolledTransform =
       apzc->GetOverscrollTransform(AsyncPanZoomController::eForHitTesting);
+
   // Send a long pan momentum.
   PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
              ScreenIntPoint(50, 80), ScreenPoint(0, 200), mcc->Time());
   EXPECT_TRUE(apzc->IsOverscrolled());
   EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
   // The overscroll amount on X axis shouldn't be changed by this momentum pan.
   EXPECT_EQ(
       currentOverscrolledTransform._41,
@@ -1143,16 +1160,32 @@ TEST_F(
   EXPECT_EQ(
       apzc->GetOverscrollTransform(AsyncPanZoomController::eForHitTesting)._42,
       0);
   ParentLayerPoint scrollOffset =
       apzc->GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForHitTesting);
   // The scroll offset shouldn't be changed by the overscroll animation.
   EXPECT_EQ(scrollOffset.y, 50);
 
+  // Simple gesture on the Y axis to ensure that we can send a vertical
+  // momentum scroll
+  PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80),
+             ScreenPoint(0, -2), mcc->Time());
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+  PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
+             ScreenPoint(0, 2), mcc->Time());
+  mcc->AdvanceByMillis(5);
+  apzc->AdvanceAnimations(mcc->GetSampleTime());
+  PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80),
+             ScreenPoint(0, 0), mcc->Time());
+
+  ParentLayerPoint offsetAfterPan =
+      apzc->GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForHitTesting);
+
   PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, apzc,
              ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time());
   EXPECT_TRUE(apzc->IsOverscrolled());
   EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
   // The overscroll amount on both axes shouldn't be changed by this pan
   // momentum start event since the displacement is zero.
   EXPECT_EQ(
       currentOverscrolledTransform._41,
@@ -1165,21 +1198,22 @@ TEST_F(
   apzc->AdvanceAnimations(mcc->GetSampleTime());
   // The overscroll amount should be managed by the overscroll animation.
   EXPECT_NE(
       currentOverscrolledTransform._41,
       apzc->GetOverscrollTransform(AsyncPanZoomController::eForHitTesting)._41);
   scrollOffset =
       apzc->GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForHitTesting);
   // Not yet started scrolling.
-  EXPECT_EQ(scrollOffset.y, 50);
+  EXPECT_EQ(scrollOffset.y, offsetAfterPan.y);
   EXPECT_EQ(scrollOffset.x, 0);
 
   currentOverscrolledTransform =
       apzc->GetOverscrollTransform(AsyncPanZoomController::eForHitTesting);
+
   // Send a long pan momentum.
   PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
              ScreenIntPoint(50, 80), ScreenPoint(0, -200), mcc->Time());
   EXPECT_TRUE(apzc->IsOverscrolled());
   EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
   // The overscroll amount on X axis shouldn't be changed by this momentum pan.
   EXPECT_EQ(
       currentOverscrolledTransform._41,
--- a/gfx/layers/apz/test/gtest/TestScrollHandoff.cpp
+++ b/gfx/layers/apz/test/gtest/TestScrollHandoff.cpp
@@ -190,16 +190,17 @@ class APZScrollHandoffTester : public AP
 
     CreateScrollHandoffLayerTree1();
 
     RefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);
     Pan(childApzc, ScreenIntPoint(10, 60), ScreenIntPoint(15, 90),
         PanOptions::KeepFingerDown | PanOptions::ExactCoordinates);
 
     childApzc->AssertAxisLocked(ScrollDirection::eVertical);
+    childApzc->AssertStateIsPanningLockedY();
   }
 };
 
 class APZScrollHandoffTesterMock : public APZScrollHandoffTester {
  public:
   APZScrollHandoffTesterMock() { CreateMockHitTester(); }
 };
 
--- a/gfx/layers/apz/test/gtest/moz.build
+++ b/gfx/layers/apz/test/gtest/moz.build
@@ -3,16 +3,17 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 UNIFIED_SOURCES += [
     "APZTestAccess.cpp",
     "APZTestCommon.cpp",
     "MockHitTester.cpp",
+    "TestAxisLock.cpp",
     "TestBasic.cpp",
     "TestEventRegions.cpp",
     "TestEventResult.cpp",
     "TestFlingAcceleration.cpp",
     "TestGestureDetector.cpp",
     "TestHitTesting.cpp",
     "TestInputQueue.cpp",
     "TestOverscroll.cpp",
--- a/gfx/layers/wr/StackingContextHelper.cpp
+++ b/gfx/layers/wr/StackingContextHelper.cpp
@@ -38,20 +38,22 @@ static nsSize ComputeDesiredDisplaySizeF
     return LayoutDevicePixel::ToAppUnits(widget->GetClientSize(),
                                          presContext->AppUnitsPerDevPixel());
   }
 
   return presContext->GetVisibleArea().Size();
 }
 
 /* static */
-Size ChooseScale(nsIFrame* aContainerFrame, nsDisplayItem* aContainerItem,
-                 const nsRect& aVisibleRect, float aXScale, float aYScale,
-                 const Matrix& aTransform2d, bool aCanDraw2D) {
-  Size scale;
+MatrixScales ChooseScale(nsIFrame* aContainerFrame,
+                         nsDisplayItem* aContainerItem,
+                         const nsRect& aVisibleRect, float aXScale,
+                         float aYScale, const Matrix& aTransform2d,
+                         bool aCanDraw2D) {
+  MatrixScales scale;
   // XXX Should we do something for 3D transforms?
   if (aCanDraw2D && !aContainerFrame->Combines3DTransformWithAncestors() &&
       !aContainerFrame->HasPerspective()) {
     // If the container's transform is animated off main thread, fix a suitable
     // scale size for animation
     if (aContainerItem &&
         aContainerItem->GetType() == DisplayItemType::TYPE_TRANSFORM &&
         // FIXME: What we need is only transform, rotate, and scale, not
@@ -60,74 +62,72 @@ Size ChooseScale(nsIFrame* aContainerFra
         EffectCompositor::HasAnimationsForCompositor(
             aContainerFrame, DisplayItemType::TYPE_TRANSFORM)) {
       nsSize displaySize =
           ComputeDesiredDisplaySizeForAnimation(aContainerFrame);
       // compute scale using the animation on the container, taking ancestors in
       // to account
       nsSize scaledVisibleSize = nsSize(aVisibleRect.Width() * aXScale,
                                         aVisibleRect.Height() * aYScale);
-      scale = nsLayoutUtils::ComputeSuitableScaleForAnimation(
+      Size size = nsLayoutUtils::ComputeSuitableScaleForAnimation(
           aContainerFrame, scaledVisibleSize, displaySize);
+      scale = MatrixScales(size.width, size.height);
       // multiply by the scale inherited from ancestors--we use a uniform
       // scale factor to prevent blurring when the layer is rotated.
       float incomingScale = std::max(aXScale, aYScale);
-      scale.width *= incomingScale;
-      scale.height *= incomingScale;
+      scale = scale * ScaleFactor<UnknownUnits, UnknownUnits>(incomingScale);
     } else {
       // Scale factors are normalized to a power of 2 to reduce the number of
       // resolution changes
-      scale = aTransform2d.ScaleFactors().ToSize();
+      scale = aTransform2d.ScaleFactors();
       // For frames with a changing scale transform round scale factors up to
       // nearest power-of-2 boundary so that we don't keep having to redraw
       // the content as it scales up and down. Rounding up to nearest
       // power-of-2 boundary ensures we never scale up, only down --- avoiding
       // jaggies. It also ensures we never scale down by more than a factor of
       // 2, avoiding bad downscaling quality.
       Matrix frameTransform;
       if (ActiveLayerTracker::IsScaleSubjectToAnimation(aContainerFrame)) {
-        scale.width = gfxUtils::ClampToScaleFactor(scale.width);
-        scale.height = gfxUtils::ClampToScaleFactor(scale.height);
+        scale.xScale = gfxUtils::ClampToScaleFactor(scale.xScale);
+        scale.yScale = gfxUtils::ClampToScaleFactor(scale.yScale);
 
         // Limit animated scale factors to not grow excessively beyond the
         // display size.
         nsSize maxScale(4, 4);
         if (!aVisibleRect.IsEmpty()) {
           nsSize displaySize =
               ComputeDesiredDisplaySizeForAnimation(aContainerFrame);
           maxScale = Max(maxScale, displaySize / aVisibleRect.Size());
         }
-        if (scale.width > maxScale.width) {
-          scale.width = gfxUtils::ClampToScaleFactor(maxScale.width, true);
+        if (scale.xScale > maxScale.width) {
+          scale.xScale = gfxUtils::ClampToScaleFactor(maxScale.width, true);
         }
-        if (scale.height > maxScale.height) {
-          scale.height = gfxUtils::ClampToScaleFactor(maxScale.height, true);
+        if (scale.yScale > maxScale.height) {
+          scale.yScale = gfxUtils::ClampToScaleFactor(maxScale.height, true);
         }
       } else {
         // XXX Do we need to move nearly-integer values to integers here?
       }
     }
     // If the scale factors are too small, just use 1.0. The content is being
     // scaled out of sight anyway.
-    if (fabs(scale.width) < 1e-8 || fabs(scale.height) < 1e-8) {
-      scale = Size(1.0, 1.0);
+    if (fabs(scale.xScale) < 1e-8 || fabs(scale.yScale) < 1e-8) {
+      scale = MatrixScales(1.0, 1.0);
     }
   } else {
-    scale = Size(1.0, 1.0);
+    scale = MatrixScales(1.0, 1.0);
   }
 
   // Prevent the scale from getting too large, to avoid excessive memory
   // allocation. Usually memory allocation is limited by the visible region,
   // which should be restricted to the display port. But at very large scales
   // the visible region itself can become excessive due to rounding errors.
   // Clamping the scale here prevents that.
-  scale =
-      Size(std::min(scale.width, 32768.0f), std::min(scale.height, 32768.0f));
-
-  return scale;
+  return MatrixScales(std::min(scale.xScale, 32768.0f),
+                      std::min(scale.yScale, 32768.0f));
 }
 
 StackingContextHelper::StackingContextHelper(
     const StackingContextHelper& aParentSC, const ActiveScrolledRoot* aAsr,
     nsIFrame* aContainerFrame, nsDisplayItem* aContainerItem,
     wr::DisplayListBuilder& aBuilder, const wr::StackingContextParams& aParams,
     const LayoutDeviceRect& aBounds)
     : mBuilder(&aBuilder),
@@ -147,42 +147,42 @@ StackingContextHelper::StackingContextHe
     if (canDraw2D &&
         aParams.reference_frame_kind != wr::WrReferenceFrameKind::Perspective &&
         !aContainerFrame->Combines3DTransformWithAncestors()) {
       mInheritedTransform = transform2d * aParentSC.mInheritedTransform;
 
       int32_t apd = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
       nsRect r = LayoutDevicePixel::ToAppUnits(aBounds, apd);
       mScale = ChooseScale(aContainerFrame, aContainerItem, r,
-                           aParentSC.mScale.width, aParentSC.mScale.height,
+                           aParentSC.mScale.xScale, aParentSC.mScale.yScale,
                            mInheritedTransform,
                            /* aCanDraw2D = */ true);
     } else {
-      mScale = gfx::Size(1.0f, 1.0f);
+      mScale = gfx::MatrixScales(1.0f, 1.0f);
       mInheritedTransform = gfx::Matrix::Scaling(1.f, 1.f);
     }
 
     if (aParams.mAnimated) {
-      mSnappingSurfaceTransform =
-          gfx::Matrix::Scaling(mScale.width, mScale.height);
+      mSnappingSurfaceTransform = gfx::Matrix::Scaling(mScale);
     } else {
       mSnappingSurfaceTransform =
           transform2d * aParentSC.mSnappingSurfaceTransform;
     }
 
   } else if (aParams.reference_frame_kind ==
                  wr::WrReferenceFrameKind::Transform &&
              aContainerItem &&
              aContainerItem->GetType() == DisplayItemType::TYPE_ASYNC_ZOOM &&
              aContainerItem->Frame()) {
-    double resolution = aContainerItem->Frame()->PresShell()->GetResolution();
+    float resolution = aContainerItem->Frame()->PresShell()->GetResolution();
     gfx::Matrix transform = gfx::Matrix::Scaling(resolution, resolution);
 
     mInheritedTransform = transform * aParentSC.mInheritedTransform;
-    mScale = resolution * aParentSC.mScale;
+    mScale =
+        ScaleFactor<UnknownUnits, UnknownUnits>(resolution) * aParentSC.mScale;
 
     MOZ_ASSERT(!aParams.mAnimated);
     mSnappingSurfaceTransform = transform * aParentSC.mSnappingSurfaceTransform;
 
   } else if (!aAsr && !aContainerFrame && !aContainerItem &&
              aParams.mRootReferenceFrame) {
     // this is the root stacking context helper
     Scale2D resolution;
@@ -193,30 +193,29 @@ StackingContextHelper::StackingContextHe
                 aParams.mRootReferenceFrame->PresShell())) {
       resolution = browserChild->GetEffectsInfo().mRasterScale;
     }
 
     gfx::Matrix transform =
         gfx::Matrix::Scaling(resolution.xScale, resolution.yScale);
 
     mInheritedTransform = transform * aParentSC.mInheritedTransform;
-    mScale = gfx::Size(aParentSC.mScale.width * resolution.xScale,
-                       aParentSC.mScale.height * resolution.yScale);
+    mScale = aParentSC.mScale * resolution;
 
     MOZ_ASSERT(!aParams.mAnimated);
     mSnappingSurfaceTransform = transform * aParentSC.mSnappingSurfaceTransform;
 
   } else {
     mInheritedTransform = aParentSC.mInheritedTransform;
     mScale = aParentSC.mScale;
   }
 
   auto rasterSpace =
       mRasterizeLocally
-          ? wr::RasterSpace::Local(std::max(mScale.width, mScale.height))
+          ? wr::RasterSpace::Local(std::max(mScale.xScale, mScale.yScale))
           : wr::RasterSpace::Screen();
 
   MOZ_ASSERT(!aParams.clip.IsNone());
   mReferenceFrameId = mBuilder->PushStackingContext(
       aParams, wr::ToLayoutRect(aBounds), rasterSpace);
 
   if (mReferenceFrameId) {
     mSpaceAndClipChainHelper.emplace(aBuilder, mReferenceFrameId.ref());
--- a/gfx/layers/wr/StackingContextHelper.h
+++ b/gfx/layers/wr/StackingContextHelper.h
@@ -39,17 +39,17 @@ class MOZ_RAII StackingContextHelper {
   // the RenderLayer traversal, but don't actually want it to push a stacking
   // context on the display list builder.
   StackingContextHelper();
 
   // Pops the stacking context, if one was pushed during the constructor.
   ~StackingContextHelper();
 
   // Export the inherited scale
-  gfx::Size GetInheritedScale() const { return mScale; }
+  gfx::MatrixScales GetInheritedScale() const { return mScale; }
 
   const gfx::Matrix& GetInheritedTransform() const {
     return mInheritedTransform;
   }
 
   const gfx::Matrix& GetSnappingSurfaceTransform() const {
     return mSnappingSurfaceTransform;
   }
@@ -59,17 +59,17 @@ class MOZ_RAII StackingContextHelper {
 
   bool AffectsClipPositioning() const { return mAffectsClipPositioning; }
   Maybe<wr::WrSpatialId> ReferenceFrameId() const { return mReferenceFrameId; }
 
   const LayoutDevicePoint& GetOrigin() const { return mOrigin; }
 
  private:
   wr::DisplayListBuilder* mBuilder;
-  gfx::Size mScale;
+  gfx::MatrixScales mScale;
   gfx::Matrix mInheritedTransform;
   LayoutDevicePoint mOrigin;
 
   // The "snapping surface" defines the space that we want to snap in.
   // You can think of it as the nearest physical surface.
   // Animated transforms create a new snapping surface, so that changes to their
   // transform don't affect the snapping of their contents. Non-animated
   // transforms do *not* create a new snapping surface, so that for example the
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -301,17 +301,17 @@ struct DIGroup {
   // we ensure that mInvalidRect is contained in mPreservedRect
   LayerIntRect mPreservedRect;
   // mHitTestBounds is the same as mActualBounds except for the bounds
   // of invisible items which are accounted for in the former but not
   // in the latter.
   LayerIntRect mHitTestBounds;
   LayerIntRect mActualBounds;
   int32_t mAppUnitsPerDevPixel;
-  gfx::Size mScale;
+  gfx::MatrixScales mScale;
   ScrollableLayerGuid::ViewID mScrollId;
   CompositorHitTestInfo mHitInfo;
   LayerPoint mResidualOffset;
   LayerIntRect mLayerBounds;  // mGroupBounds converted to Layer space
   // mLayerBounds clipped to the container/parent of the
   // current item being processed.
   LayerIntRect mClippedImageBounds;  // mLayerBounds with the clipping of any
                                      // containers applied
@@ -560,17 +560,17 @@ struct DIGroup {
                 nsDisplayListBuilder* aDisplayListBuilder,
                 wr::DisplayListBuilder& aBuilder,
                 wr::IpcResourceUpdateQueue& aResources, Grouper* aGrouper,
                 nsDisplayList::iterator aStartItem,
                 nsDisplayList::iterator aEndItem) {
     GP("\n\n");
     GP("Begin EndGroup\n");
 
-    LayoutDeviceToLayerScale2D scale(mScale.width, mScale.height);
+    auto scale = LayoutDeviceToLayerScale2D::FromUnknownScale(mScale);
 
     auto hitTestRect = mVisibleRect.Intersect(ViewAs<LayerPixel>(
         mHitTestBounds, PixelCastJustification::LayerIsImage));
     if (!hitTestRect.IsEmpty()) {
       auto deviceHitTestRect =
           (LayerRect(hitTestRect) - mResidualOffset) / scale;
       PushHitTest(aBuilder, deviceHitTestRect);
     }
@@ -643,19 +643,18 @@ struct DIGroup {
 
     RefPtr<gfx::DrawTarget> dummyDt =
         gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
 
     RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(
         recorder, dummyDt, mLayerBounds.ToUnknownRect());
     // Setup the gfxContext
     RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt);
-    context->SetMatrix(
-        Matrix::Scaling(mScale.width, mScale.height)
-            .PostTranslate(mResidualOffset.x, mResidualOffset.y));
+    context->SetMatrix(Matrix::Scaling(mScale).PostTranslate(
+        mResidualOffset.x, mResidualOffset.y));
 
     GP("mInvalidRect: %d %d %d %d\n", mInvalidRect.x, mInvalidRect.y,
        mInvalidRect.width, mInvalidRect.height);
 
     RenderRootStateManager* rootManager =
         aWrManager->GetRenderRootStateManager();
 
     bool empty = aStartItem == aEndItem;
@@ -1293,17 +1292,17 @@ void Grouper::ConstructGroups(nsDisplayL
       }
     }
 
     bool isLast = it.HasNext();
 
     // WebRender's anti-aliasing approximation is not very good under
     // non-uniform scales.
     bool uniformlyScaled =
-        fabs(aGroup->mScale.width - aGroup->mScale.height) < 0.1;
+        fabs(aGroup->mScale.xScale - aGroup->mScale.yScale) < 0.1;
 
     auto activity = IsItemProbablyActive(
         item, aBuilder, aResources, aSc, manager, mDisplayListBuilder,
         encounteredActiveItem, uniformlyScaled);
     auto threshold =
         isFirst || isLast ? ItemActivity::Could : ItemActivity::Should;
 
     if (activity >= threshold) {
@@ -1600,56 +1599,56 @@ void WebRenderCommandBuilder::DoGrouping
   RefPtr<WebRenderGroupData> groupData =
       CreateOrRecycleWebRenderUserData<WebRenderGroupData>(aWrappingItem);
 
   bool snapped;
   nsRect groupBounds =
       aWrappingItem->GetUntransformedBounds(aDisplayListBuilder, &snapped);
   DIGroup& group = groupData->mSubGroup;
 
-  gfx::Size scale = aSc.GetInheritedScale();
-  GP("Inherrited scale %f %f\n", scale.width, scale.height);
+  auto scale = aSc.GetInheritedScale();
+  GP("Inherited scale %f %f\n", scale.xScale, scale.yScale);
 
   auto trans =
       ViewAs<LayerPixel>(aSc.GetSnappingSurfaceTransform().GetTranslation());
   auto snappedTrans = LayerIntPoint::Floor(trans);
   LayerPoint residualOffset = trans - snappedTrans;
 
   auto layerBounds =
-      ScaleToOutsidePixelsOffset(groupBounds, scale.width, scale.height,
+      ScaleToOutsidePixelsOffset(groupBounds, scale.xScale, scale.yScale,
                                  appUnitsPerDevPixel, residualOffset);
 
   const nsRect& untransformedPaintRect =
       aWrappingItem->GetUntransformedPaintRect();
 
   auto visibleRect = ScaleToOutsidePixelsOffset(
-                         untransformedPaintRect, scale.width, scale.height,
+                         untransformedPaintRect, scale.xScale, scale.yScale,
                          appUnitsPerDevPixel, residualOffset)
                          .Intersect(layerBounds);
 
   GP("LayerBounds: %d %d %d %d\n", layerBounds.x, layerBounds.y,
      layerBounds.width, layerBounds.height);
   GP("VisibleRect: %d %d %d %d\n", visibleRect.x, visibleRect.y,
      visibleRect.width, visibleRect.height);
 
-  GP("Inherrited scale %f %f\n", scale.width, scale.height);
+  GP("Inherited scale %f %f\n", scale.xScale, scale.yScale);
 
   group.mInvalidRect.SetEmpty();
   if (group.mAppUnitsPerDevPixel != appUnitsPerDevPixel ||
       group.mScale != scale || group.mResidualOffset != residualOffset) {
     GP("Property change. Deleting blob\n");
 
     if (group.mAppUnitsPerDevPixel != appUnitsPerDevPixel) {
       GP(" App unit change %d -> %d\n", group.mAppUnitsPerDevPixel,
          appUnitsPerDevPixel);
     }
 
     if (group.mScale != scale) {
-      GP(" Scale %f %f -> %f %f\n", group.mScale.width, group.mScale.height,
-         scale.width, scale.height);
+      GP(" Scale %f %f -> %f %f\n", group.mScale.xScale, group.mScale.yScale,
+         scale.xScale, scale.yScale);
     }
 
     if (group.mResidualOffset != residualOffset) {
       GP(" Residual Offset %f %f -> %f %f\n", group.mResidualOffset.x,
          group.mResidualOffset.y, residualOffset.x, residualOffset.y);
     }
 
     group.ClearItems();
@@ -1666,18 +1665,18 @@ void WebRenderCommandBuilder::DoGrouping
   group.mLayerBounds = layerBounds;
   group.mVisibleRect = visibleRect;
   group.mActualBounds = LayerIntRect();
   group.mHitTestBounds = LayerIntRect();
   group.mPreservedRect = group.mVisibleRect.Intersect(group.mLastVisibleRect);
   group.mAppUnitsPerDevPixel = appUnitsPerDevPixel;
   group.mClippedImageBounds = layerBounds;
 
-  g.mTransform = Matrix::Scaling(scale.width, scale.height)
-                     .PostTranslate(residualOffset.x, residualOffset.y);
+  g.mTransform =
+      Matrix::Scaling(scale).PostTranslate(residualOffset.x, residualOffset.y);
   group.mScale = scale;
   group.mScrollId = scrollId;
   g.ConstructGroups(aDisplayListBuilder, this, aBuilder, aResources, &group,
                     aList, aWrappingItem, aSc);
   mClipManager.EndList(aSc);
 }
 
 WebRenderCommandBuilder::WebRenderCommandBuilder(
@@ -2277,17 +2276,17 @@ void WebRenderCommandBuilder::PushInProc
                                      rendering, wr::MixBlendMode::Normal,
                                      !aItem->BackfaceIsHidden());
 }
 
 static void PaintItemByDrawTarget(nsDisplayItem* aItem, gfx::DrawTarget* aDT,
                                   const LayoutDevicePoint& aOffset,
                                   const IntRect& visibleRect,
                                   nsDisplayListBuilder* aDisplayListBuilder,
-                                  const gfx::Size& aScale,
+                                  const gfx::MatrixScales& aScale,
                                   Maybe<gfx::DeviceColor>& aHighlight) {
   MOZ_ASSERT(aDT);
 
   // XXX Why is this ClearRect() needed?
   aDT->ClearRect(Rect(visibleRect));
   RefPtr<gfxContext> context = gfxContext::CreateOrNull(aDT);
   MOZ_ASSERT(context);
 
@@ -2298,19 +2297,18 @@ static void PaintItemByDrawTarget(nsDisp
       MOZ_RELEASE_ASSERT(0);
       break;
     }
     default:
       if (!aItem->AsPaintedDisplayItem()) {
         break;
       }
 
-      context->SetMatrix(context->CurrentMatrix()
-                             .PreScale(aScale.width, aScale.height)
-                             .PreTranslate(-aOffset.x, -aOffset.y));
+      context->SetMatrix(context->CurrentMatrix().PreScale(aScale).PreTranslate(
+          -aOffset.x, -aOffset.y));
       if (aDisplayListBuilder->IsPaintingToWindow()) {
         aItem->Frame()->AddStateBits(NS_FRAME_PAINTED_THEBES);
       }
       aItem->AsPaintedDisplayItem()->Paint(aDisplayListBuilder, context);
       break;
   }
 
   if (aHighlight && aItem->GetType() != DisplayItemType::TYPE_MASK) {
@@ -2425,24 +2423,24 @@ WebRenderCommandBuilder::GenerateFallbac
   const int32_t appUnitsPerDevPixel =
       aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
   auto bounds =
       LayoutDeviceRect::FromAppUnits(paintBounds, appUnitsPerDevPixel);
   if (bounds.IsEmpty()) {
     return nullptr;
   }
 
-  gfx::Size scale = aSc.GetInheritedScale();
-  gfx::Size oldScale = fallbackData->mScale;
+  MatrixScales scale = aSc.GetInheritedScale();
+  MatrixScales oldScale = fallbackData->mScale;
   // We tolerate slight changes in scale so that we don't, for example,
   // rerasterize on MotionMark
-  bool differentScale = gfx::FuzzyEqual(scale.width, oldScale.width, 1e-6f) &&
-                        gfx::FuzzyEqual(scale.height, oldScale.height, 1e-6f);
+  bool differentScale = gfx::FuzzyEqual(scale.xScale, oldScale.xScale, 1e-6f) &&
+                        gfx::FuzzyEqual(scale.yScale, oldScale.yScale, 1e-6f);
 
-  LayoutDeviceToLayerScale2D layerScale(scale.width, scale.height);
+  auto layerScale = LayoutDeviceToLayerScale2D::FromUnknownScale(scale);
 
   auto trans =
       ViewAs<LayerPixel>(aSc.GetSnappingSurfaceTransform().GetTranslation());
   auto snappedTrans = LayerIntPoint::Floor(trans);
   LayerPoint residualOffset = trans - snappedTrans;
 
   nsRegion opaqueRegion = aItem->GetOpaqueRegion(aDisplayListBuilder, &snap);
   wr::OpacityType opacity = opaqueRegion.Contains(paintBounds)
@@ -2455,30 +2453,30 @@ WebRenderCommandBuilder::GenerateFallbac
   // out we'd potentially introduce transparent pixels.
   //
   // Ideally we'd be able to ask an item its bounds in pixels and whether
   // they're all opaque. Unfortunately no such API exists so we currently
   // just hope that we get it right.
   if (aBuilder.GetInheritedOpacity() == 1.0f &&
       opacity == wr::OpacityType::Opaque && snap) {
     dtRect = LayerIntRect::FromUnknownRect(
-        ScaleToNearestPixelsOffset(paintBounds, scale.width, scale.height,
+        ScaleToNearestPixelsOffset(paintBounds, scale.xScale, scale.yScale,
                                    appUnitsPerDevPixel, residualOffset));
 
     visibleRect =
         LayerIntRect::FromUnknownRect(
-            ScaleToNearestPixelsOffset(buildingRect, scale.width, scale.height,
+            ScaleToNearestPixelsOffset(buildingRect, scale.xScale, scale.yScale,
                                        appUnitsPerDevPixel, residualOffset))
             .Intersect(dtRect);
   } else {
-    dtRect = ScaleToOutsidePixelsOffset(paintBounds, scale.width, scale.height,
+    dtRect = ScaleToOutsidePixelsOffset(paintBounds, scale.xScale, scale.yScale,
                                         appUnitsPerDevPixel, residualOffset);
 
     visibleRect =
-        ScaleToOutsidePixelsOffset(buildingRect, scale.width, scale.height,
+        ScaleToOutsidePixelsOffset(buildingRect, scale.xScale, scale.yScale,
                                    appUnitsPerDevPixel, residualOffset)
             .Intersect(dtRect);
   }
 
   auto visibleSize = visibleRect.Size();
   // these rectangles can overflow from scaling so try to
   // catch that with IsEmpty() checks. See bug 1622126.
   if (visibleSize.IsEmpty() || dtRect.IsEmpty()) {
@@ -2696,40 +2694,40 @@ Maybe<wr::ImageMask> WebRenderCommandBui
   }
 
   bool snap;
   nsRect bounds = aMaskItem->GetBounds(aDisplayListBuilder, &snap);
 
   const int32_t appUnitsPerDevPixel =
       aMaskItem->Frame()->PresContext()->AppUnitsPerDevPixel();
 
-  Size scale = aSc.GetInheritedScale();
-  Size oldScale = maskData->mScale;
+  MatrixScales scale = aSc.GetInheritedScale();
+  MatrixScales oldScale = maskData->mScale;
   // This scale determination should probably be done using
   // ChooseScaleAndSetTransform but for now we just fake it.
   // We tolerate slight changes in scale so that we don't, for example,
   // rerasterize on MotionMark
-  bool sameScale = FuzzyEqual(scale.width, oldScale.width, 1e-6f) &&
-                   FuzzyEqual(scale.height, oldScale.height, 1e-6f);
+  bool sameScale = FuzzyEqual(scale.xScale, oldScale.xScale, 1e-6f) &&
+                   FuzzyEqual(scale.yScale, oldScale.yScale, 1e-6f);
 
   LayerIntRect itemRect =
       LayerIntRect::FromUnknownRect(bounds.ScaleToOutsidePixels(
-          scale.width, scale.height, appUnitsPerDevPixel));
+          scale.xScale, scale.yScale, appUnitsPerDevPixel));
 
   LayerIntRect visibleRect =
       LayerIntRect::FromUnknownRect(
           aMaskItem->GetBuildingRect().ScaleToOutsidePixels(
-              scale.width, scale.height, appUnitsPerDevPixel))
+              scale.xScale, scale.yScale, appUnitsPerDevPixel))
           .SafeIntersect(itemRect);
 
   if (visibleRect.IsEmpty()) {
     return Nothing();
   }
 
-  LayoutDeviceToLayerScale2D layerScale(scale.width, scale.height);
+  LayoutDeviceToLayerScale2D layerScale(scale.xScale, scale.yScale);
   LayoutDeviceRect imageRect = LayerRect(visibleRect) / layerScale;
 
   nsPoint maskOffset = aMaskItem->ToReferenceFrame() - bounds.TopLeft();
 
   bool shouldHandleOpacity = aBuilder.GetInheritedOpacity() != 1.0f;
 
   nsRect dirtyRect;
   // If this mask item is being painted for the first time, some members of
@@ -2774,17 +2772,17 @@ Maybe<wr::ImageMask> WebRenderCommandBui
     RefPtr<DrawTarget> dt = Factory::CreateRecordingDrawTarget(
         recorder, dummyDt, IntRect(IntPoint(0, 0), size));
 
     RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt);
     MOZ_ASSERT(context);
 
     context->SetMatrix(context->CurrentMatrix()
                            .PreTranslate(-itemRect.x, -itemRect.y)
-                           .PreScale(scale.width, scale.height));
+                           .PreScale(scale));
 
     bool maskPainted = false;
     bool maskIsComplete = aMaskItem->PaintMask(
         aDisplayListBuilder, context, shouldHandleOpacity, &maskPainted);
     if (!maskPainted) {
       return Nothing();
     }
 
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -108,17 +108,18 @@ bool WebRenderLayerManager::Initialize(
     aError.Assign(hasInitialized
                       ? "FEATURE_FAILURE_WEBRENDER_INITIALIZE_SYNC_POST"_ns
                       : "FEATURE_FAILURE_WEBRENDER_INITIALIZE_SYNC_FIRST"_ns);
     return false;
   }
 
   if (textureFactoryIdentifier.mParentBackend == LayersBackend::LAYERS_NONE ||
       idNamespace.isNothing()) {
-    gfxCriticalNote << "Failed to connect WebRenderBridgeChild. isParent=" << XRE_IsParentProcess();
+    gfxCriticalNote << "Failed to connect WebRenderBridgeChild. isParent="
+                    << XRE_IsParentProcess();
     aError.Append(hasInitialized ? "_POST"_ns : "_FIRST"_ns);
     return false;
   }
 
   WrBridge()->SetWebRenderLayerManager(this);
   WrBridge()->IdentifyTextureHost(textureFactoryIdentifier);
   WrBridge()->SetNamespace(idNamespace.ref());
   *aTextureFactoryIdentifier = textureFactoryIdentifier;
--- a/gfx/layers/wr/WebRenderUserData.h
+++ b/gfx/layers/wr/WebRenderUserData.h
@@ -264,17 +264,17 @@ class WebRenderFallbackData : public Web
   /// into.
   WebRenderImageData* PaintIntoImage();
 
   std::vector<RefPtr<gfx::SourceSurface>> mExternalSurfaces;
   UniquePtr<nsDisplayItemGeometry> mGeometry;
   DisplayItemClip mClip;
   nsRect mBounds;
   nsRect mBuildingRect;
-  gfx::Size mScale;
+  gfx::MatrixScales mScale;
   float mOpacity;
 
  protected:
   void ClearImageKey();
 
   std::vector<RefPtr<gfx::ScaledFont>> mFonts;
   Maybe<wr::BlobImageKey> mBlobKey;
   // When rendering into a blob image, mImageData is null. It is non-null only
@@ -371,17 +371,17 @@ class WebRenderMaskData : public WebRend
   static UserDataType Type() { return UserDataType::eMask; }
 
   Maybe<wr::BlobImageKey> mBlobKey;
   std::vector<RefPtr<gfx::ScaledFont>> mFonts;
   std::vector<RefPtr<gfx::SourceSurface>> mExternalSurfaces;
   LayerIntRect mItemRect;
   nsPoint mMaskOffset;
   nsStyleImageLayers mMaskStyle;
-  gfx::Size mScale;
+  gfx::MatrixScales mScale;
   bool mShouldHandleOpacity;
 };
 
 extern void DestroyWebRenderUserDataTable(WebRenderUserDataTable* aTable);
 
 struct WebRenderUserDataProperty {
   NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(Key, WebRenderUserDataTable,
                                       DestroyWebRenderUserDataTable)
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -6502,19 +6502,19 @@ CSSIntSize nsLayoutUtils::ComputeSizeFor
   if (!gotHeight) {
     imageSize.height =
         nsPresContext::AppUnitsToIntCSSPixels(aFallbackSize.height);
   }
 
   return imageSize;
 }
 
-/* static */ LayerIntRect SnapRectForImage(const gfx::Matrix& aTransform,
-                                           const gfx::Size& aScaleFactors,
-                                           const LayoutDeviceRect& aRect) {
+/* static */ LayerIntRect SnapRectForImage(
+    const gfx::Matrix& aTransform, const gfx::MatrixScales& aScaleFactors,
+    const LayoutDeviceRect& aRect) {
   // Attempt to snap pixels, the same as ComputeSnappedImageDrawingParameters.
   // Any changes to the algorithm here will need to be reflected there.
   bool snapped = false;
   LayerIntRect snapRect;
   if (!aTransform.HasNonAxisAlignedTransform() && aTransform._11 > 0.0 &&
       aTransform._22 > 0.0) {
     gfxRect rect(gfxPoint(aRect.X(), aRect.Y()),
                  gfxSize(aRect.Width(), aRect.Height()));
@@ -6538,20 +6538,18 @@ CSSIntSize nsLayoutUtils::ComputeSizeFor
                       std::max(p1i.y, p3i.y) - snapRect.Y());
       snapped = true;
     }
   }
 
   if (!snapped) {
     // If we couldn't snap directly with the transform, we need to go best
     // effort in layer pixels.
-    snapRect = RoundedToInt(LayerRect(aRect.X() * aScaleFactors.width,
-                                      aRect.Y() * aScaleFactors.height,
-                                      aRect.Width() * aScaleFactors.width,
-                                      aRect.Height() * aScaleFactors.height));
+    snapRect = RoundedToInt(
+        aRect * LayoutDeviceToLayerScale2D::FromUnknownScale(aScaleFactors));
   }
 
   // An empty size is unacceptable so we ensure our suggested size is at least
   // 1 pixel wide/tall.
   if (snapRect.Width() < 1) {
     snapRect.SetWidth(1);
   }
   if (snapRect.Height() < 1) {
@@ -6564,24 +6562,24 @@ CSSIntSize nsLayoutUtils::ComputeSizeFor
 IntSize nsLayoutUtils::ComputeImageContainerDrawingParameters(
     imgIContainer* aImage, nsIFrame* aForFrame,
     const LayoutDeviceRect& aDestRect, const LayoutDeviceRect& aFillRect,
     const StackingContextHelper& aSc, uint32_t aFlags,
     Maybe<SVGImageContext>& aSVGContext, Maybe<ImageIntRegion>& aRegion) {
   MOZ_ASSERT(aImage);
   MOZ_ASSERT(aForFrame);
 
-  gfx::Size scaleFactors = aSc.GetInheritedScale();
+  MatrixScales scaleFactors = aSc.GetInheritedScale();
   SamplingFilter samplingFilter =
       nsLayoutUtils::GetSamplingFilterForFrame(aForFrame);
 
   // Compute our SVG context parameters, if any. Don't replace the viewport
   // size if it was already set, prefer what the caller gave.
   SVGImageContext::MaybeStoreContextPaint(aSVGContext, aForFrame, aImage);
-  if ((scaleFactors.width != 1.0 || scaleFactors.height != 1.0) &&
+  if ((scaleFactors.xScale != 1.0 || scaleFactors.yScale != 1.0) &&
       aImage->GetType() == imgIContainer::TYPE_VECTOR &&
       (!aSVGContext || !aSVGContext->GetViewportSize())) {
     gfxSize gfxDestSize(aDestRect.Width(), aDestRect.Height());
     IntSize viewportSize = aImage->OptimalImageSizeForDest(
         gfxDestSize, imgIContainer::FRAME_CURRENT, samplingFilter, aFlags);
 
     CSSIntSize cssViewportSize(viewportSize.width, viewportSize.height);
     if (!aSVGContext) {
--- a/layout/generic/ReflowInput.cpp
+++ b/layout/generic/ReflowInput.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/ReflowInput.h"
 
 #include <algorithm>
 
 #include "CounterStyleManager.h"
 #include "LayoutLogging.h"
 #include "mozilla/dom/HTMLInputElement.h"
 #include "mozilla/SVGUtils.h"
+#include "mozilla/WritingModes.h"
 #include "nsBlockFrame.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsFlexContainerFrame.h"
 #include "nsFontInflationData.h"
 #include "nsFontMetrics.h"
 #include "nsGkAtoms.h"
 #include "nsGridContainerFrame.h"
 #include "nsIContent.h"
@@ -1174,16 +1175,43 @@ static bool AreAllEarlierInFlowFramesEmp
         return allEmpty;
       }
     }
   }
   *aFound = false;
   return true;
 }
 
+static bool AxisPolarityFlipped(LogicalAxis aThisAxis, WritingMode aThisWm,
+                                WritingMode aOtherWm) {
+  if (MOZ_LIKELY(aThisWm == aOtherWm)) {
+    // Dedicated short circuit for the common case.
+    return false;
+  }
+  LogicalAxis otherAxis = aThisWm.IsOrthogonalTo(aOtherWm)
+                              ? GetOrthogonalAxis(aThisAxis)
+                              : aThisAxis;
+  NS_ASSERTION(
+      aThisWm.PhysicalAxis(aThisAxis) == aOtherWm.PhysicalAxis(otherAxis),
+      "Physical axes must match!");
+  Side thisStartSide =
+      aThisWm.PhysicalSide(MakeLogicalSide(aThisAxis, eLogicalEdgeStart));
+  Side otherStartSide =
+      aOtherWm.PhysicalSide(MakeLogicalSide(otherAxis, eLogicalEdgeStart));
+  return thisStartSide != otherStartSide;
+}
+
+static bool InlinePolarityFlipped(WritingMode aThisWm, WritingMode aOtherWm) {
+  return AxisPolarityFlipped(eLogicalAxisInline, aThisWm, aOtherWm);
+}
+
+static bool BlockPolarityFlipped(WritingMode aThisWm, WritingMode aOtherWm) {
+  return AxisPolarityFlipped(eLogicalAxisBlock, aThisWm, aOtherWm);
+}
+
 // Calculate the position of the hypothetical box that the element would have
 // if it were in the flow.
 // The values returned are relative to the padding edge of the absolute
 // containing block. The writing-mode of the hypothetical box position will
 // have the same block direction as the absolute containing block, but may
 // differ in inline-bidi direction.
 // In the code below, |aCBReflowInput->frame| is the absolute containing block,
 // while |containingBlock| is the nearest block container of the placeholder
@@ -1388,27 +1416,40 @@ void ReflowInput::CalculateHypotheticalP
   nsPoint cbOffset =
       containingBlock->GetOffsetToIgnoringScrolling(aCBReflowInput->mFrame);
 
   nsSize reflowSize = aCBReflowInput->ComputedSizeAsContainerIfConstrained();
   LogicalPoint logCBOffs(wm, cbOffset, reflowSize - containerSize);
   aHypotheticalPos.mIStart += logCBOffs.I(wm);
   aHypotheticalPos.mBStart += logCBOffs.B(wm);
 
+  // If block direction doesn't match (whether orthogonal or antiparallel),
+  // we'll have to convert aHypotheticalPos to be in terms of cbwm.
+  // This upcoming conversion must be taken into account for border offsets.
+  const bool hypotheticalPosWillUseCbwm =
+      cbwm.GetBlockDir() != wm.GetBlockDir();
   // The specified offsets are relative to the absolute containing block's
   // padding edge and our current values are relative to the border edge, so
   // translate.
   const LogicalMargin border = aCBReflowInput->ComputedLogicalBorder(wm);
-  aHypotheticalPos.mIStart -= border.IStart(wm);
-  aHypotheticalPos.mBStart -= border.BStart(wm);
+  if (hypotheticalPosWillUseCbwm && InlinePolarityFlipped(wm, cbwm)) {
+    aHypotheticalPos.mIStart += border.IEnd(wm);
+  } else {
+    aHypotheticalPos.mIStart -= border.IStart(wm);
+  }
 
+  if (hypotheticalPosWillUseCbwm && BlockPolarityFlipped(wm, cbwm)) {
+    aHypotheticalPos.mBStart += border.BEnd(wm);
+  } else {
+    aHypotheticalPos.mBStart -= border.BStart(wm);
+  }
   // At this point, we have computed aHypotheticalPos using the writing mode
   // of the placeholder's containing block.
 
-  if (cbwm.GetBlockDir() != wm.GetBlockDir()) {
+  if (hypotheticalPosWillUseCbwm) {
     // If the block direction we used in calculating aHypotheticalPos does not
     // match the absolute containing block's, we need to convert here so that
     // aHypotheticalPos is usable in relation to the absolute containing block.
     // This requires computing or measuring the abspos frame's block-size,
     // which is not otherwise required/used here (as aHypotheticalPos
     // records only the block-start coordinate).
 
     // This is similar to the inline-size calculation for a replaced
--- a/layout/generic/ScrollSnap.cpp
+++ b/layout/generic/ScrollSnap.cpp
@@ -197,20 +197,22 @@ static void ProcessSnapPositions(CalcSna
     nsRect snappedPort = nsRect(snapPoint, aSnapInfo.mSnapportSize);
     // Ignore snap points if snapping to the point would leave the snap area
     // outside of the snapport.
     // https://drafts.csswg.org/css-scroll-snap-1/#snap-scope
     if (!snappedPort.Intersects(target.mSnapArea)) {
       continue;
     }
 
-    if (target.mSnapPositionX) {
+    if (target.mSnapPositionX &&
+        aSnapInfo.mScrollSnapStrictnessX != StyleScrollSnapStrictness::None) {
       aCalcSnapPoints.AddVerticalEdge(*target.mSnapPositionX);
     }
-    if (target.mSnapPositionY) {
+    if (target.mSnapPositionY &&
+        aSnapInfo.mScrollSnapStrictnessY != StyleScrollSnapStrictness::None) {
       aCalcSnapPoints.AddHorizontalEdge(*target.mSnapPositionY);
     }
   }
 }
 
 Maybe<nsPoint> ScrollSnapUtils::GetSnapPointForDestination(
     const ScrollSnapInfo& aSnapInfo, ScrollUnit aUnit,
     ScrollSnapFlags aSnapFlags, const nsRect& aScrollRange,
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -1355,29 +1355,28 @@ bool nsDisplayRemote::CreateWebRenderCom
 
     // Adjust mItemVisibleRect, which is relative to the reference frame, to be
     // relative to this frame
     nsRect visibleRect = GetBuildingRect() - ToReferenceFrame();
     visibleRect.IntersectRect(visibleRect, destRect);
     visibleRect -= destRect.TopLeft();
 
     // Generate an effects update notifying the browser it is visible
-    gfx::Size scale = aSc.GetInheritedScale();
+    MatrixScales scale = aSc.GetInheritedScale();
 
     ParentLayerToScreenScale2D transformToAncestorScale =
         ParentLayerToParentLayerScale(
             pc->GetPresShell() ? pc->GetPresShell()->GetCumulativeResolution()
                                : 1.f) *
         nsLayoutUtils::GetTransformToAncestorScaleCrossProcessForFrameMetrics(
             mFrame);
 
     aDisplayListBuilder->AddEffectUpdate(
-        remoteBrowser,
-        EffectsInfo::VisibleWithinRect(visibleRect, {scale.width, scale.height},
-                                       transformToAncestorScale));
+        remoteBrowser, EffectsInfo::VisibleWithinRect(
+                           visibleRect, scale, transformToAncestorScale));
 
     // Create a WebRenderRemoteData to notify the RemoteBrowser when it is no
     // longer visible
     RefPtr<WebRenderRemoteData> userData =
         aManager->CommandBuilder()
             .CreateOrRecycleWebRenderUserData<WebRenderRemoteData>(this,
                                                                    nullptr);
     userData->SetRemoteBrowser(remoteBrowser);
--- a/layout/reftests/backgrounds/reftest.list
+++ b/layout/reftests/backgrounds/reftest.list
@@ -104,26 +104,26 @@ fuzzy-if(OSX,0-1,0-324) == background-la
 # background-size results in a different rendering when present.
 != background-size-cover-slice.html background-size-slice.html
 != background-size-cover-clone.html background-size-clone.html
 
 # ...and make sure each rendering with background-size is different from the
 # other
 != background-size-cover-slice.html background-size-cover-clone.html
 
-random-if(OSX==1010) == background-size-monster-ch.html background-size-monster-ref.html # bug 1129300
-random-if(OSX==1010) == background-size-monster-cm.html background-size-monster-ref.html # bug 1129300
-random-if(OSX==1010) == background-size-monster-em.html background-size-monster-ref.html # bug 1129300
-random-if(OSX==1010) == background-size-monster-ex.html background-size-monster-ref.html # bug 1129300
-random-if(OSX==1010) == background-size-monster-inches.html background-size-monster-ref.html # bug 1129300
-random-if(OSX==1010) == background-size-monster-mm.html background-size-monster-ref.html # bug 1129300
-random-if(OSX==1010) == background-size-monster-pc.html background-size-monster-ref.html # bug 1129300
-random-if(OSX==1010) == background-size-monster-pt.html background-size-monster-ref.html # bug 1129300
-random-if(OSX==1010) == background-size-monster-px.html background-size-monster-ref.html # bug 1129300
-random-if(OSX==1010) == background-size-monster-rem.html background-size-monster-ref.html # bug 1129300
+== background-size-monster-ch.html background-size-monster-ref.html # bug 1129300
+== background-size-monster-cm.html background-size-monster-ref.html # bug 1129300
+== background-size-monster-em.html background-size-monster-ref.html # bug 1129300
+== background-size-monster-ex.html background-size-monster-ref.html # bug 1129300
+== background-size-monster-inches.html background-size-monster-ref.html # bug 1129300
+== background-size-monster-mm.html background-size-monster-ref.html # bug 1129300
+== background-size-monster-pc.html background-size-monster-ref.html # bug 1129300
+== background-size-monster-pt.html background-size-monster-ref.html # bug 1129300
+== background-size-monster-px.html background-size-monster-ref.html # bug 1129300
+== background-size-monster-rem.html background-size-monster-ref.html # bug 1129300
 
 fails-if(useDrawSnapshot) == background-size-zoom-repeat.html background-size-zoom-repeat-ref.html # drawSnapshot doesn't deal with zoom properly.
 
 # -moz-default-background-color and -moz-default-color (bug 591341)
 == background-moz-default-background-color.html background-moz-default-background-color-ref.html
 
 == fixed-bg-with-transform-outside-viewport-1.html fixed-bg-with-transform-outside-viewport-ref.html
 fuzzy(0-2,0-83) == fixed-bg-border-radius.html fixed-bg-border-radius-ref.html
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1601,17 +1601,17 @@ fails-if(useDrawSnapshot) == 621253-2-ex
 fails-if(useDrawSnapshot) == 621253-2-internalFilter.html 621253-2-ref.html
 random-if(winWidget) == 621918-1.svg 621918-1-ref.svg # 1-pixel diacritic positioning discrepancy in rotated text (may depend on platform fonts)
 random-if(winWidget) fuzzy-if(geckoview&&!emulator,0-255,0-22) == 621918-2.svg 621918-2-ref.svg # same 1px issue as above
 fuzzy-if(d2d,0-5,0-1) == 622585-1.html 622585-1-ref.html # bug 789402
 fuzzy(0-1,0-40000) == 625409-1.html 625409-1-ref.html
 == 627393-1.html about:blank
 fuzzy(0-1,0-500) == 630835-1.html about:blank
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 631352-1.html 631352-1-ref.html # bug 1392106
-random-if(winWidget||OSX==1010) == 632781-verybig.html 632781-ref.html
+random-if(winWidget) == 632781-verybig.html 632781-ref.html
 == 632781-normalsize.html 632781-ref.html
 fuzzy-if(d2d&&/^Windows\x20NT\x206\.2/.test(http.oscpu),0-1,0-559) fuzzy-if(!isDebugBuild&&gtkWidget&&/^Linux\x20i686/.test(http.oscpu),0-102,0-140) == 633344-1.html 633344-1-ref.html # bug 1103623, Linux32 from GCC update
 fuzzy(0-1,0-500) == 634232-1.html 634232-1-ref.html
 fuzzy(0-3,0-120000) == 635302-1.html 635302-1-ref.html
 fuzzy(0-1,0-68) fuzzy-if(gtkWidget,0-1,0-70) fuzzy-if(!Android,0-2,0-300) == 635373-1.html 635373-1-ref.html
 random-if(d2d) fuzzy-if(winWidget&&!d2d,0-20,0-118) fuzzy-if(!Android,0-2,0-550) == 635373-2.html 635373-2-ref.html
 random-if(d2d) fuzzy-if(winWidget&&!d2d,0-20,0-116) fuzzy-if(!Android,0-2,0-650) == 635373-3.html 635373-3-ref.html
 == 635639-1.html 635639-1-ref.html
--- a/layout/reftests/canvas/ctm-sanity.html
+++ b/layout/reftests/canvas/ctm-sanity.html
@@ -1,83 +1,85 @@
 <html>
 <head>
   <script type="text/javascript">
-
-function assert(cond, msg) { if (!cond) { throw msg; } }
+function assert(cond, msg) {
+  if (!cond) {
+    throw msg;
+  }
+}
 
-function isSameTM(m1, m2) {
-    // XXX this is probably the ugliest possible way to write this function,
-    // but it's intended to be lowest-common-denominator
-    if (!(m1.length === 6 && m1.length === m2.length)) {
-        return false;
-    }
-    for (var i = 0; i < m1.length; ++i) {
-        if (m1[i] !== m2[i]) {
-            return false;
-        }
-    }
-    return true;
-}
+assert.equal = function(m1, m2, msg) {
+  assert(
+    m1.is2D &&
+      m2.is2D &&
+      m1.a === m2.a &&
+      m1.b === m2.b &&
+      m1.c === m2.c &&
+      m1.d === m2.d &&
+      m1.e === m2.e &&
+      m1.f === m2.f,
+    msg
+  );
+};
 
 window.onload = function() {
-    var IM = [ 1, 0, 0, 1, 0, 0 ];
+  var IM = new DOMMatrix([1, 0, 0, 1, 0, 0]);
 
-    try {
-        var ctx = document.getElementById("c1").getContext("2d");
+  try {
+    var ctx = document.getElementById("c1").getContext("2d");
 
-        assert(isSameTM(IM, ctx.mozCurrentTransform),
-               "currentTransform is identity by default");
-        assert(isSameTM(IM, ctx.mozCurrentTransformInverse),
-               "currentTransformInverse is identity by default");
+    assert.equal(ctx.getTransform(), IM, "Transform is identity by default");
+    assert.equal(
+      ctx.getTransform().invertSelf(),
+      IM,
+      "Inverse transform is identity by default"
+    );
+
+    var m = new DOMMatrix([1, 2, 3, 4, 5, 6]);
+    ctx.setTransform(m);
+    assert.equal(ctx.getTransform(), m, "Transform successfully set");
 
-        var m = [ 1, 2, 3, 4, 5, 6 ];
-        ctx.mozCurrentTransform = m;
-        assert(isSameTM(m, ctx.mozCurrentTransform),
-               "currentTransform successfully set");
-        var badVals = [ -1,
-                        "string",
-                        { obj: true },
-                        [ "array of string" ],
-                        [ -1 ],
-                        [ "string", 1, 2, 3, 4, 5 ],
-                        [ { obj: true }, 1, 2, 3, 4, 5 ],
-        ];
-        for (var i = 0; i < badVals.length; ++i) {
-            var error = false;
-            try { ctx.mozCurrentTransform = badVals[i]; }
-            catch(e) { error = true; }
-            assert(error && isSameTM(m, ctx.mozCurrentTransform),
-                   "Expected |currentTransform = "+ badVals[i] +"| to throw exception and not change .currentTransform");
+    var badVals = [
+      ["string"],
+      [-1],
+      ["string", 1, 2, 3, 4, 5],
+      [{ obj: true }, 1, 2, 3, 4, 5],
+    ];
+    for (var i = 0; i < badVals.length; ++i) {
+      try {
+        ctx.setTransform(...badVals[i]);
+      } catch {}
+      assert.equal(
+        ctx.getTransform(),
+        m,
+        "Expected |setTransform(" + badVals[i] + ")| to not change transform"
+      );
+    }
 
-            error = false;
-            try { ctx.mozCurrentTransformInverse = badVals[i]; }
-            catch(e) { error = true; }
-            assert(error && isSameTM(m, ctx.mozCurrentTransform),
-                   "Expected |currentTransformInverse = "+ badVals[i] +"| to throw exception and not change .currentTransform");
-        }
-        ctx.mozCurrentTransform = IM;
+    ctx.setTransform(IM);
+    var noopVals = [
+      [Number.NaN, 1, 2, 3, 4, 5],
+      [Infinity, 1, 2, 3, 4, 5],
+    ];
+    for (var i = 0; i < noopVals.length; ++i) {
+      ctx.setTransform(...noopVals[i]);
+      assert.equal(
+        ctx.getTransform(),
+        IM,
+        "Illegal float values result in a no-op"
+      );
+    }
 
-        var noopVals = [ [ Number.NaN, 1, 2, 3, 4, 5 ],
-                         [ Infinity, 1, 2, 3, 4, 5 ],
-        ];
-        for (var i = 0; i < noopVals.length; ++i) {
-            ctx.mozCurrentTransform = noopVals[i];
-            assert(isSameTM(ctx.mozCurrentTransform, IM),
-                   "Illegal float values result in no-ops (sigh)");
-        }
-        ctx.mozCurrentTransform = IM;
-
-        ctx.setTransform(m[0], m[1], m[2], m[3], m[4], m[5]);
-        assert(isSameTM(ctx.mozCurrentTransform, m),
-               "setTransform() updates currentTransform");
-     } catch (e) {
-        document.body.innerHTML = "FAIL: "+ e.toString();
-        return;
-    }
-    document.body.innerHTML = "Pass";
-}
+    ctx.setTransform(m.a, m.b, m.c, m.d, m.e, m.f);
+    assert.equal(ctx.getTransform(), m, "setTransform() updates transform");
+  } catch (e) {
+    document.body.innerHTML = "FAIL: " + e.toString();
+    return;
+  }
+  document.body.innerHTML = "Pass";
+};
   </script>
 </head>
 <body>
   <div><canvas id="c1" width="300" height="300"></canvas></div>
 </body>
 </html>
--- a/layout/reftests/canvas/ctm-singular-sanity.html
+++ b/layout/reftests/canvas/ctm-singular-sanity.html
@@ -1,53 +1,60 @@
 <html>
 <head>
   <script type="text/javascript">
-
-function assert(cond, msg) { if (!cond) { throw msg; } }
+function assert(cond, msg) {
+  if (!cond) {
+    throw msg;
+  }
+}
 
-function isSameTM(m1, m2) {
-    // XXX this is probably the ugliest possible way to write this function,
-    // but it's intended to be lowest-common-denominator
-    if (!(m1.length === 6 && m1.length === m2.length)) {
-        return false;
-    }
-    for (var i = 0; i < m1.length; ++i) {
-        if (m1[i] !== m2[i]) {
-            return false;
-        }
-    }
-    return true;
-}
+assert.equal = function(m1, m2, msg) {
+  assert(
+    m1.is2D &&
+      m2.is2D &&
+      m1.a === m2.a &&
+      m1.b === m2.b &&
+      m1.c === m2.c &&
+      m1.d === m2.d &&
+      m1.e === m2.e &&
+      m1.f === m2.f,
+    msg
+  );
+};
 
 window.onload = function() {
-    var IM = [ 1, 0, 0, 1, 0, 0 ];
-
-    try {
-        var ctx = document.getElementById("c1").getContext("2d");
+  try {
+    var ctx = document.getElementById("c1").getContext("2d");
 
-        var singular = [ 0, 0, 0, 0, 0, 0 ];
-        ctx.mozCurrentTransform = singular;
-        assert(isSameTM(singular, ctx.mozCurrentTransform),
-               "Expected setting CTM to a singular matrix to work");
-        var inv = ctx.mozCurrentTransformInverse;
-        assert(!isSameTM(inv, inv),
-               "Expected to get back matrix of NaN's from currentTransformInverse");
-        ctx.mozCurrentTransform = IM;
+    var singular = new DOMMatrix([0, 0, 0, 0, 0, 0]);
+    ctx.setTransform(singular);
+    assert.equal(
+      ctx.getTransform(),
+      singular,
+      "Expected setting transform to a singular matrix to work"
+    );
+    var inv = ctx.getTransform().invertSelf();
+    assert(
+      isNaN(inv.a) && isNaN(inv.b) && isNaN(inv.c) && isNaN(inv.d),
+      "Expected to get back matrix of NaN's from inverse transform"
+    );
 
-        var m = [ 1, 2, 3, 4, 5, 6 ];
-        ctx.mozCurrentTransform = m;
-        ctx.mozCurrentTransformInverse = singular;
-        assert(isSameTM(m, ctx.mozCurrentTransform),
-                        "Setting currentTransformInverse to a singular matrix is a no-op");
-        ctx.mozCurrentTransform = IM;
-    } catch (e) {
-        document.body.innerHTML = "FAIL: "+ e.toString();
-        return;
-    }
-    document.body.innerHTML = "Pass";
-}
+    var m = new DOMMatrix([1, 2, 3, 4, 5, 6]);
+    ctx.setTransform(m);
+    ctx.setTransform(singular.invertSelf());
+    assert.equal(
+      ctx.getTransform(),
+      m,
+      "Setting transform to an inverse singular matrix is a no-op"
+    );
+  } catch (e) {
+    document.body.innerHTML = "FAIL: " + e.toString();
+    return;
+  }
+  document.body.innerHTML = "Pass";
+};
   </script>
 </head>
 <body>
   <div><canvas id="c1" width="300" height="300"></canvas></div>
 </body>
 </html>
--- a/layout/reftests/canvas/reftest.list
+++ b/layout/reftests/canvas/reftest.list
@@ -72,17 +72,17 @@ random != text-emoji.html text-emoji-not
 != evenodd-fill-1.html nonzero-fill-1.html
 == evenodd-fill-1.html evenodd-fill-ref.html
 
 == dash-sanity.html data:text/html,<body>Pass
 fuzzy(0-9,0-470) random-if(Android) == dash-1.html dash-1-ref.svg # Bug 668412 (really is android-specific, not IPC-specific)
 
 == ctm-sanity.html data:text/html,<body>Pass
 == ctm-singular-sanity.html data:text/html,<body>Pass
-fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-45) == ctm-1.html ctm-1-ref.html
+pref(dom.mozCurrentTransform.enabled,true) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-45) == ctm-1.html ctm-1-ref.html
 
 == 672646-alpha-radial-gradient.html 672646-alpha-radial-gradient-ref.html
 fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-45) == 674003-alpha-radial-gradient-superlum.html 674003-alpha-radial-gradient-superlum-ref.html
 
 != 693610-1.html 693610-1-notref.html # bug 693610: multiple glyph runs should not be overprinted
 
 == 726951-shadow-clips.html 726951-shadow-clips-ref.html
 
--- a/layout/reftests/css-grid/grid-abspos-items-015-ref.html
+++ b/layout/reftests/css-grid/grid-abspos-items-015-ref.html
@@ -29,61 +29,50 @@ separator { clear:both; display:block; h
   border-style: solid;
   border-width: 1px 3px 5px 7px;
   border-block-start-color: blue;
   border-inline-start-color: lime;
   writing-mode: vertical-lr; direction:rtl;
   z-index:1;
 }
 
-abs1,abs2,abs3,abs4 {
+abs1,abs3,abs4 {
   grid-area: 2 / 2 / 3 / 3;
   position: absolute;
 }
-abs1 { height:97px; top:-12px; left:-30px; background:lime; }
-abs2 { right:-18px; left:3px; background:pink; }
+abs1 { width:20px; height:97px; top:-12px; left:-30px; background:lime; }
 abs3 { top: -20px; left:-35px; right:-18px; background:cyan; }
-abs4 { top:-6px; bottom:-53px; background:silver; }
+abs4 { width:20px; top:-6px; bottom:-53px; background:silver; }
 abs1::before { content:"1";}
-abs2::before { content:"2";}
 abs3::before { content:"3";}
 abs4::before { content:"4";}
 
-
 .hl { writing-mode: horizontal-tb; direction:ltr; }
 .hr { writing-mode: horizontal-tb; direction:rtl; }
 .vl { writing-mode: vertical-lr; }
 .vr { writing-mode: vertical-rl; }
 .vlr { writing-mode: vertical-lr; direction:rtl; }
 .vrl { writing-mode: vertical-rl; direction:ltr; }
 
 .hr abs3 { left:-16px; right:-37px;  }
 .vl abs3, .vr abs3, .vrl abs3, .vlr abs3 { left:-30px; top:-14px; right:-41px; }
 .vr abs3, .vrl abs3 { left:-39px; right:-32px; }
 .vrl abs3 { top:-25px; }
 
-.hl abs2, .hr abs2 { top:-25px; }
-.hl abs2 { left:-43px; }
-.hr abs2 { left:-32px; right:-29px; }
-.vl abs2, .vr abs2, .vrl abs2, .vlr abs2 { left:-38px; right:-41px; }
-.vr abs2, .vrl abs2 { left:-55px; right:-24px; }
-.vrl abs2 { top:-16px; }
-
-.hr abs1 { left: 91px; }
+.hr abs1 { left: 61px; }
 .vl abs1, .vr abs1, .vrl abs1, .vlr abs1 { top:-6px; left:-25px; }
-.vr abs1, .vrl abs1 { left:68px; }
+.vr abs1, .vrl abs1 { left:38px; }
 .vrl abs1 { top:-17px; }
 
 .hl abs4 { left:51px; }
-.hr abs4 { left:10px; }
+.hr abs4 { left:-20px; }
 .vl abs4, .vr abs4, .vrl abs4, .vlr abs4 { top:0px; bottom:-41px; left:-25px; }
-.vr abs4, .vrl abs4 { left:68px; }
+.vr abs4, .vrl abs4 { left:38px; }
 .vrl abs4 { top:-11px; bottom:-30px; }
 
-
 </style>
 </head>
 <body>
 
 <script>
 document.body.style.display="none";
 var wm = [ "hl", "hr", "vl", "vr", "vlr", "vrl" ];
 for (var i = 0; i < wm.length; ++i) {
--- a/layout/reftests/css-grid/grid-abspos-items-015.html
+++ b/layout/reftests/css-grid/grid-abspos-items-015.html
@@ -29,26 +29,27 @@ separator { clear:both; display:block; h
   padding: 3px 5px 7px 9px;
   border-style: solid;
   border-width: 1px 3px 5px 7px;
   border-block-start-color: blue;
   border-inline-start-color: lime;
   writing-mode: vertical-lr; direction:rtl;
 }
 
-abs1,abs2,abs3,abs4 {
+abs1,abs3,abs4 {
   grid-area: 2 / 2 / 3 / 3;
   position: absolute;
+  display: block; /* Avoid bug 1769072 */
 }
-abs1 { top:17px; bottom:2px; background:lime; }
-abs2 { right:13px; left:3px; background:pink; }
+
+/* Specify width or provide enough constraint to avoid bug 1769102 */
+abs1 { width:20px; top:17px; bottom:2px; background:lime; }
 abs3 { right:5px; left:11px; top:9px; background:cyan; }
-abs4 { top:23px; bottom:1px; background:silver; }
+abs4 { width:20px; top:23px; bottom:1px; background:silver; }
 abs1::before { content:"1";}
-abs2::before { content:"2";}
 abs3::before { content:"3";}
 abs4::before { content:"4";}
 
 x {
   grid-area: 2 / 2 / 3 / 3;
 }
 y {
   grid-area: 3 / 3;
--- a/layout/reftests/css-grid/reftest.list
+++ b/layout/reftests/css-grid/reftest.list
@@ -25,17 +25,17 @@ fuzzy(0-180,0-3) == grid-abspos-items-00
 == grid-abspos-items-008.html grid-abspos-items-008-ref.html
 == grid-abspos-items-009.html grid-abspos-items-009-ref.html
 == grid-abspos-items-010.html grid-abspos-items-010-ref.html
 == grid-abspos-items-011.html grid-abspos-items-011-ref.html
 == grid-abspos-items-012.html grid-abspos-items-012-ref.html
 == grid-abspos-items-013.html grid-abspos-items-013-ref.html
 == grid-abspos-items-014.html grid-abspos-items-014-ref.html
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-abspos-items-015.html grid-abspos-items-015-ref.html # Bug 1392106
-random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-abspos-items-016.html grid-abspos-items-015-ref.html # Bug 1392106
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails == grid-abspos-items-016.html grid-abspos-items-015-ref.html # Bug 1392106, 1769072
 == grid-order-abspos-items-001.html grid-order-abspos-items-001-ref.html
 == grid-order-placement-auto-001.html grid-order-placement-auto-001-ref.html
 fuzzy(0-1,0-200) == grid-order-placement-definite-001.html grid-order-placement-definite-001-ref.html
 == grid-placement-definite-implicit-001.html grid-placement-definite-implicit-001-ref.html
 == grid-placement-definite-implicit-002.html grid-placement-definite-implicit-002-ref.html
 fuzzy(0-64,0-1) skip-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)) == grid-placement-auto-implicit-001.html grid-placement-auto-implicit-001-ref.html # win10: bug 1507154
 == grid-placement-abspos-implicit-001.html grid-placement-abspos-implicit-001-ref.html
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == rtl-grid-placement-definite-001.html rtl-grid-placement-definite-001-ref.html # Bug 1392106
--- a/layout/reftests/first-line/reftest.list
+++ b/layout/reftests/first-line/reftest.list
@@ -29,17 +29,17 @@ load stress-10.html # crash test
 == 287088-1.html 287088-1-ref.html
 == 287088-2.html 287088-2-ref.html
 == 403177-1.html 403177-1-ref.html
 == 469227-2.html 469227-2-ref.html
 == 469227-3.html 469227-3-ref.html
 
 random == restyle-inside-first-line.html restyle-inside-first-line-ref.html # bug 1523134
 == font-styles.html font-styles-ref.html
-fuzzy-if(OSX==1010,0-1,0-2) == font-styles-nooverflow.html font-styles-ref.html
+== font-styles-nooverflow.html font-styles-ref.html
 
 == ib-split-1.html ib-split-1-ref.html
 
 == first-line-in-columnset-1.html first-line-in-columnset-1-ref.html
 
 == insertion-in-first-line-1.html insertion-in-first-line-ref.html
 == insertion-in-first-line-2.html insertion-in-first-line-ref.html
 == insertion-in-first-line-3.html insertion-in-first-line-ref.html
--- a/layout/reftests/font-face/reftest.list
+++ b/layout/reftests/font-face/reftest.list
@@ -175,17 +175,17 @@ HTTP(..) == reflow-sanity-delay-1a.html 
 HTTP(..) == reflow-sanity-delay-1b.html reflow-sanity-1-ref.html
 HTTP(..) == reflow-sanity-delay-1c.html reflow-sanity-1-ref.html
 HTTP(..) == reflow-sanity-delay-1-metrics.html reflow-sanity-1-ref.html
 
 HTTP(..) == bug-1481905-cancel-load.html bug-1481905-cancel-load-ref.html
 
 # font-display, with the timeouts extended so that slow (debug) builds have a better chance to keep up
 pref(gfx.downloadable_fonts.fallback_delay,10000) pref(gfx.downloadable_fonts.fallback_delay_short,1000) HTTP(..) == font-display-1.html font-display-1-ref.html # normal font load (~500ms), bug 1392106
-fuzzy-if(OSX==1010,0-3,0-5) HTTP(..) == font-display-2.html font-display-2-ref.html # font load takes 4500ms
+HTTP(..) == font-display-2.html font-display-2-ref.html # font load takes 4500ms
 
 # Testing hack for Meiryo
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == meiryo-en.html meiryo-ja.html # Bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == meiryo-en-bold.html meiryo-ja-bold.html # Bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == meiryo-en-italic.html meiryo-ja-italic.html # Bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == meiryo-en-oblique.html meiryo-ja-oblique.html # Bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == meiryo-en-bolditalic.html meiryo-ja-bolditalic.html # Bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) != meiryo-en-bold.html meiryo-en.html # Bug 1392106
--- a/layout/reftests/font-matching/reftest.list
+++ b/layout/reftests/font-matching/reftest.list
@@ -71,28 +71,28 @@ random-if(/^Windows\x20NT\x206\.1/.test(
 # family names with escaped spaces shouldn't match the names without the spaces
 fails-if(gtkWidget) == familyname-escapedidents.html familyname-escapedidents-ref.html # bug 1309425, bug 1328771
 
 # weight mapping tests
 == normalmedium.html normalmedium-ref.html
 != normalmedium.html normalmedium-notref.html
 
 # Linux fails due to bug 604815
-fuzzy-if(OSX==1010&&browserIsRemote,0-1,0-23) == weightmapping-12.html weightmapping-12-ref.html
+== weightmapping-12.html weightmapping-12-ref.html
 == weightmapping-25.html weightmapping-25-ref.html
 == weightmapping-45.html weightmapping-45-ref.html
 == weightmapping-458.html weightmapping-458-ref.html
 == weightmapping-478.html weightmapping-478-ref.html
 == weightmapping-7.html weightmapping-7-ref.html
-fuzzy-if(OSX==1010,0-1,0-30) == weightmapping-12579.html weightmapping-12579-ref.html
+== weightmapping-12579.html weightmapping-12579-ref.html
 
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == stretchmapping-all.html stretchmapping-all-ref.html # Bug 1392106
 == stretchmapping-reverse.html stretchmapping-reverse-ref.html
-fuzzy-if(OSX==1010&&browserIsRemote,0-1,0-17) fuzzy-if(Android,0-4,0-8) == stretchmapping-35.html stretchmapping-35-ref.html
-fuzzy-if(OSX==1010,0-3,0-5) == stretchmapping-137.html stretchmapping-137-ref.html
+fuzzy-if(Android,0-4,0-8) == stretchmapping-35.html stretchmapping-35-ref.html
+== stretchmapping-137.html stretchmapping-137-ref.html
 
 # test for font-stretch using @font-face
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == font-stretch-1.html font-stretch-1-ref.html # Bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == font-shorthand-stretch-1.html font-stretch-1-ref.html # Bug 1392106
 
 # bug 724231 - applying synthetic styles to a single @font-face font
 # should apply artificial obliquing, not switch to a true styled face
 fails-if(geckoview) != synthetic-style-1.html synthetic-style-1-notref.html # Bug 1558513 for GV
--- a/layout/reftests/forms/placeholder/reftest.list
+++ b/layout/reftests/forms/placeholder/reftest.list
@@ -13,17 +13,17 @@
 == placeholder-1-textarea.html placeholder-visible-textarea-ref.html
 == placeholder-2.html placeholder-visible-ref.html
 == placeholder-2-textarea.html placeholder-visible-textarea-ref.html
 == placeholder-3.html placeholder-overridden-ref.html
 == placeholder-4.html placeholder-overridden-ref.html
 == placeholder-5.html placeholder-visible-ref.html
 
 # This tests assumes that the overflowing placeholder won't eat the padding, which is just not true in some platforms...
-fuzzy-if(winWidget,0-160,0-10) fuzzy-if(Android,0-160,0-41) fuzzy-if(asyncPan&&!layersGPUAccelerated,0-146,0-317) fuzzy-if(OSX==1010&&browserIsRemote,0-1,0-8) == placeholder-6.html placeholder-overflow-ref.html
+fuzzy-if(winWidget,0-160,0-10) fuzzy-if(Android,0-160,0-41) fuzzy-if(asyncPan&&!layersGPUAccelerated,0-146,0-317) == placeholder-6.html placeholder-overflow-ref.html
 
 skip-if(Android&&asyncPan) == placeholder-6-textarea.html placeholder-overflow-textarea-ref.html
 # needs-focus == placeholder-7.html placeholder-focus-ref.html
 # needs-focus == placeholder-8.html placeholder-focus-ref.html
 # needs-focus == placeholder-9.html placeholder-focus-ref.html
 needs-focus == placeholder-10.html placeholder-visible-ref.html
 == placeholder-11.html placeholder-visible-ref.html
 == placeholder-12.html placeholder-visible-ref.html
--- a/layout/reftests/generated-content/reftest.list
+++ b/layout/reftests/generated-content/reftest.list
@@ -1,24 +1,24 @@
 # Almost all tests in this file have fuzz on OS X 10.10 due to bug 1220052.
 
-fuzzy-if(OSX==1010,0-1,0-10) == display-types-01.html display-types-01-ref.html
-fuzzy-if(OSX==1010,0-1,0-10) == dynamic-attr-01.html dynamic-attr-01-ref.html
-fuzzy-if(OSX==1010,0-1,0-10) == dynamic-button-01a.html dynamic-button-01-ref.html
-fuzzy-if(OSX==1010,0-1,0-10) == dynamic-button-01b.html dynamic-button-01-ref.html
-fuzzy-if(OSX==1010,0-1,0-10) == dynamic-fieldset-01a.html dynamic-fieldset-01-ref.html
-fuzzy-if(OSX==1010,0-1,0-10) == dynamic-fieldset-01b.html dynamic-fieldset-01-ref.html
-fuzzy-if(OSX==1010,0-1,0-10) == dynamic-restyle-01.html dynamic-restyle-01-ref.html
-fuzzy-if(OSX==1010,0-1,0-10) == dynamic-table-cell-01a.html dynamic-table-cell-01-ref.html
-fuzzy-if(OSX==1010,0-1,0-10) == dynamic-table-cell-01b.html dynamic-table-cell-01-ref.html
+== display-types-01.html display-types-01-ref.html
+== dynamic-attr-01.html dynamic-attr-01-ref.html
+== dynamic-button-01a.html dynamic-button-01-ref.html
+== dynamic-button-01b.html dynamic-button-01-ref.html
+== dynamic-fieldset-01a.html dynamic-fieldset-01-ref.html
+== dynamic-fieldset-01b.html dynamic-fieldset-01-ref.html
+== dynamic-restyle-01.html dynamic-restyle-01-ref.html
+== dynamic-table-cell-01a.html dynamic-table-cell-01-ref.html
+== dynamic-table-cell-01b.html dynamic-table-cell-01-ref.html
 == dynamic-table-cell-indent.html dynamic-table-cell-indent-ref.html
-fuzzy-if(OSX==1010,0-1,0-10) == floated-01.html floated-01-ref.html
-fuzzy-if(OSX==1010,0-1,0-10) == images-01.html images-01-ref.html
-fuzzy-if(OSX==1010,0-1,0-10) == positioned-01.html positioned-01-ref.html
-fuzzy-if(OSX==1010,0-1,0-10) == quotes-001.xml quotes-001-ref.xml
-fuzzy-if(OSX==1010,0-1,0-10) == table-ignoring-whitespace-01.html table-ignoring-whitespace-01-ref.html
-fuzzy-if(OSX==1010,0-1,0-10) == table-parts-01.html table-parts-01-ref.html
+== floated-01.html floated-01-ref.html
+== images-01.html images-01-ref.html
+== positioned-01.html positioned-01-ref.html
+== quotes-001.xml quotes-001-ref.xml
+== table-ignoring-whitespace-01.html table-ignoring-whitespace-01-ref.html
+== table-parts-01.html table-parts-01-ref.html
 == before-style-sharing.html before-style-sharing-ref.html
 == transitive-style-invalidation.html transitive-style-invalidation-ref.html
 == dynamic-content.html dynamic-content-ref.html
 == generated-content-inherit-001.html generated-content-inherit-001-ref.html
 == dynamic-generated-content-inherit-001.html generated-content-inherit-001-ref.html
 == attr-whitespace.xhtml attr-whitespace-ref.html
\ No newline at end of file
--- a/layout/reftests/selection/reftest.list
+++ b/layout/reftests/selection/reftest.list
@@ -29,17 +29,17 @@ random-if(Android) needs-focus != pseudo
 # These tests uses Highlight and HighlightText color keywords, they are not same as text selection color on Mac.
 random-if(Android) fails-if(cocoaWidget) needs-focus == non-themed-widget.html non-themed-widget-ref.html
 random-if(Android) needs-focus == themed-widget.html themed-widget-ref.html
 == addrange-1.html addrange-ref.html
 fuzzy(0-1,0-1200) == addrange-2.html addrange-ref.html
 == splitText-normalize.html splitText-normalize-ref.html
 == modify-range.html modify-range-ref.html
 == dom-mutations.html dom-mutations-ref.html
-fuzzy-if(OSX==1010,0-9,0-1) fuzzy-if(!OSX,0-1,0-2138) == trailing-space-1.html trailing-space-1-ref.html
+fuzzy-if(!OSX,0-1,0-2138) == trailing-space-1.html trailing-space-1-ref.html
 != invalidation-1-ref.html invalidation-2-ref.html
 == invalidation-1a.html invalidation-1-ref.html
 == invalidation-1b.html invalidation-1-ref.html
 == invalidation-1c.html invalidation-1-ref.html
 == invalidation-1d.html invalidation-1-ref.html
 == invalidation-1e.html invalidation-1-ref.html
 == invalidation-1f.html invalidation-1-ref.html
 == invalidation-2a.html invalidation-2-ref.html
--- a/layout/reftests/svg/as-image/canvas-drawImage-transform-restored-ref.html
+++ b/layout/reftests/svg/as-image/canvas-drawImage-transform-restored-ref.html
@@ -1,16 +1,16 @@
 <html>
   <head>
     <script type="text/javascript">
       function go() {
         var canvas = document.getElementById("canvas");
         var ctx = canvas.getContext("2d");
 
-        ctx.mozCurrentTransform = [2, 0, 0, 2, 0, 0];
+        ctx.setTransform(2, 0, 0, 2, 0, 0);
 
         ctx.fillStyle = "blue";
         ctx.fillRect(20, 20, 50, 50);
       }
     </script>
   </head>
   <body onload="go()">
     <canvas id="canvas" width="200" height="200"></canvas>
--- a/layout/reftests/svg/as-image/canvas-drawImage-transform-restored.html
+++ b/layout/reftests/svg/as-image/canvas-drawImage-transform-restored.html
@@ -1,17 +1,17 @@
 <html>
   <head>
     <title>Test that drawImage() calls don't reset the canvas' transform</title>
     <script type="text/javascript">
       function go() {
         var canvas = document.getElementById("canvas");
         var ctx = canvas.getContext("2d");
 
-        ctx.mozCurrentTransform = [2, 0, 0, 2, 0, 0];
+        ctx.setTransform(2, 0, 0, 2, 0, 0);
 
         // SVG image that draws nothing
         ctx.drawImage(document.getElementById("image"), 0, 0);
 
         // Check that ctx's transform wasn't reset by the drawImage call
         ctx.fillStyle = "blue";
         ctx.fillRect(20, 20, 50, 50);
       }
--- a/layout/reftests/text-decoration/reftest.list
+++ b/layout/reftests/text-decoration/reftest.list
@@ -98,18 +98,18 @@ fuzzy-if(gtkWidget,0-208,0-12) == comple
 == decoration-css21.html decoration-css21-ref.html
 fuzzy-if(cocoaWidget,0-1,0-5) == decoration-color-override-quirks.html decoration-color-override-quirks-ref.html
 == decoration-color-override-standards.html decoration-color-override-standards-ref.html
 != decoration-color-override-standards-ref.html decoration-color-override-quirks-ref.html
 == decoration-css21-block.html decoration-css21-block-ref.html
 != inline-baseline-almost-standards.html inline-baseline-almost-standards-ref.html
 != inline-baseline-quirks.html inline-baseline-quirks-ref.html
 == 676538-1.html 676538-1-ref.html
-fuzzy-if(OSX==1010,0-1,0-4) == underline-button-1.html underline-button-1-ref.html
-fuzzy-if(OSX==1010,0-1,0-2) == underline-button-2.html underline-button-2-ref.html
+== underline-button-1.html underline-button-1-ref.html
+== underline-button-2.html underline-button-2-ref.html
 fuzzy(0-4,0-2) == underline-select-1.html underline-select-1-ref.html
 == underline-select-2.html underline-select-2-ref.html
 == 1133392.html 1133392-ref.html
 != 1159729-offset-adjustment.html 1159729-offset-adjustment-notref.html
 == emphasis-style-dynamic.html emphasis-style-dynamic-ref.html
 == vertical-mode-decorations-1.html vertical-mode-decorations-1-ref.html
 fuzzy-if(Android,0-238,0-36) == vertical-mode-decorations-2.html vertical-mode-decorations-2-ref.html
 != 1415214.html 1415214-notref.html
--- a/layout/reftests/transform-3d/reftest.list
+++ b/layout/reftests/transform-3d/reftest.list
@@ -66,17 +66,17 @@ fuzzy(0-3,0-304) == scroll-perspective-1
 fails-if(!layersGPUAccelerated) fails-if(useDrawSnapshot) fuzzy-if(!useDrawSnapshot,0-29,0-826) == 1035611-1.html 1035611-1-ref.html # Bug 1072898 for !layersGPUAccelerated failures
 fails-if(useDrawSnapshot) != 1157984-1.html about:blank # Bug 1157984
 fuzzy(0-220,0-660) == animate-cube-radians.html animate-cube-radians-ref.html # subpixel AA
 fuzzy(0-240,0-400) fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated,0-16,0-6) == animate-cube-radians-zoom.html animate-cube-radians-zoom-ref.html
 != animate-cube-radians-ref.html animate-cube-radians-zoom-ref.html
 fuzzy(0-240,0-660) == animate-cube-degrees.html animate-cube-degrees-ref.html # subpixel AA
 fuzzy(0-240,0-400) fails-if(useDrawSnapshot) == animate-cube-degrees-zoom.html animate-cube-degrees-zoom-ref.html
 != animate-cube-degrees-ref.html animate-cube-degrees-zoom-ref.html
-fuzzy-if(gtkWidget,0-128,0-100) fuzzy-if(Android||OSX==1010||(gtkWidget&&layersGPUAccelerated),0-143,0-100) fuzzy-if(winWidget||OSX,0-141,0-100) == preserves3d-nested.html preserves3d-nested-ref.html
+fuzzy-if(gtkWidget,0-128,0-100) fuzzy-if(Android||(gtkWidget&&layersGPUAccelerated),0-143,0-100) fuzzy-if(winWidget||OSX,0-141,0-100) == preserves3d-nested.html preserves3d-nested-ref.html
 fuzzy(0-255,0-153) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == animate-preserve3d-parent.html animate-preserve3d-ref.html # intermittently fuzzy on Mac
 fuzzy(0-255,0-153) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == animate-preserve3d-child.html animate-preserve3d-ref.html # intermittently fuzzy on Mac, bug 1461311 for Android
 == animate-backface-hidden.html about:blank
 == 1245450-1.html green-rect.html
 fuzzy(0-1,0-2000) == opacity-preserve3d-1.html opacity-preserve3d-1-ref.html
 fuzzy(0-1,0-15000) == opacity-preserve3d-2.html opacity-preserve3d-2-ref.html
 fuzzy(0-1,0-10000) == opacity-preserve3d-3.html opacity-preserve3d-3-ref.html
 fuzzy(0-1,0-10000) == opacity-preserve3d-4.html opacity-preserve3d-4-ref.html
--- a/modules/libpref/init/StaticPrefList.yaml
+++ b/modules/libpref/init/StaticPrefList.yaml
@@ -336,34 +336,42 @@
 
 - name: apz.autoscroll.enabled
   type: RelaxedAtomicBool
   value: true
   mirror: always
 
 - name: apz.axis_lock.breakout_angle
   type: AtomicFloat
+#if defined(XP_MACOSX) && defined(NIGHTLY_BUILD)
+  value: float(M_PI / 4.0)    # 45 degrees
+#else
   value: float(M_PI / 8.0)    # 22.5 degrees
+#endif
   mirror: always
   include: <cmath>
 
 - name: apz.axis_lock.breakout_threshold
   type: AtomicFloat
   value: 1.0f / 32.0f
   mirror: always
 
 - name: apz.axis_lock.direct_pan_angle
   type: AtomicFloat
   value: float(M_PI / 3.0)    # 60 degrees
   mirror: always
   include: <cmath>
 
 - name: apz.axis_lock.lock_angle
   type: AtomicFloat
+#if defined(XP_MACOSX) && defined(NIGHTLY_BUILD)
+  value: float(M_PI / 4.0)    # 45 degrees
+#else
   value: float(M_PI / 6.0)    # 30 degrees
+#endif
   mirror: always
   include: <cmath>
 
 # Whether to lock touch scrolling to one axis at a time.
 # 0 = FREE (No locking at all)
 # 1 = STANDARD (Once locked, remain locked until scrolling ends)
 # 2 = STICKY (Allow lock to be broken, with hysteresis)
 - name: apz.axis_lock.mode
@@ -1813,16 +1821,22 @@
   type: bool
   value: @IS_NIGHTLY_BUILD@
   mirror: always
 
 #---------------------------------------------------------------------------
 # Prefs starting with "dom."
 #---------------------------------------------------------------------------
 
+# Whether CanvasRenderingContext2D.mozCurrentTransform is enabled.
+- name: dom.mozCurrentTransform.enabled
+  type: bool
+  value: @IS_NOT_EARLY_BETA_OR_EARLIER@
+  mirror: always
+
 # Allow cut/copy
 - name: dom.allow_cut_copy
   type: bool
   value: true
   mirror: always
 
 - name: dom.allow_XUL_XBL_for_file
   type: bool
--- a/python/mozbuild/mozbuild/action/test_archive.py
+++ b/python/mozbuild/mozbuild/action/test_archive.py
@@ -325,16 +325,21 @@ ARCHIVE_FILES = {
             "base": "third_party/python/six",
             "pattern": "six.py",
         },
         {
             "source": buildconfig.topsrcdir,
             "base": "third_party/python/distro",
             "pattern": "distro.py",
         },
+        {
+            "source": buildconfig.topsrcdir,
+            "base": "third_party/python/packaging",
+            "pattern": "**",
+        },
     ],
     "reftest": [
         {"source": buildconfig.topobjdir, "base": "_tests", "pattern": "reftest/**"},
         {
             "source": buildconfig.topobjdir,
             "base": "",
             "pattern": "mozinfo.json",
             "dest": "reftest",
--- a/python/mozbuild/mozbuild/vendor/vendor_rust.py
+++ b/python/mozbuild/mozbuild/vendor/vendor_rust.py
@@ -510,18 +510,22 @@ license file's hash.
         relative_vendor_dir = "third_party/rust"
         vendor_dir = mozpath.join(self.topsrcdir, relative_vendor_dir)
 
         # We use check_call instead of mozprocess to ensure errors are displayed.
         # We do an |update -p| here to regenerate the Cargo.lock file with minimal
         # changes. See bug 1324462
         subprocess.check_call([cargo, "update", "-p", "gkrust"], cwd=self.topsrcdir)
 
-        with open(os.path.join(self.topsrcdir, "Cargo.lock")) as fh:
+        with open(os.path.join(self.topsrcdir, "Cargo.lock")) as fh, open(
+            os.path.join(self.topsrcdir, "Cargo.toml")
+        ) as toml_fh:
             cargo_lock = pytoml.load(fh)
+            cargo_toml = pytoml.load(toml_fh)
+            patches = cargo_toml.get("patch", {}).get("crates-io", {})
             failed = False
             for package in cargo_lock.get("patch", {}).get("unused", []):
                 self.log(
                     logging.ERROR,
                     "unused_patch",
                     {"crate": package["name"]},
                     """Unused patch in top-level Cargo.toml for {crate}.""",
                 )
@@ -544,16 +548,21 @@ license file's hash.
                             "Crate {crate} v{version} must be overridden but isn't "
                             "and comes from {source}.",
                         )
                         failed = True
                 grouped[package["name"]].append(package)
 
             for name, packages in grouped.items():
                 num = len(packages)
+                # Allow to have crates in build/rust that provide older versions
+                # of crates based on newer ones, implying there are at least two
+                # crates with the same name, one of them being under build/rust.
+                if patches.get(name, {}).get("path", "").startswith("build/rust"):
+                    num -= 1
                 expected = TOLERATED_DUPES.get(name, 1)
                 if num > expected:
                     self.log(
                         logging.ERROR,
                         "duplicate_crate",
                         {
                             "crate": name,
                             "num": num,
@@ -575,17 +584,17 @@ license file's hash.
                             "expected": expected,
                             "file": __file__,
                         },
                         "There are {num} different versions of crate {crate} "
                         "(expected {expected}). Please adjust TOLERATED_DUPES in "
                         "{file} to reflect this improvement.",
                     )
                     failed = True
-                elif num < expected:
+                elif num < expected and num > 0:
                     self.log(
                         logging.ERROR,
                         "less_duplicate_crate",
                         {
                             "crate": name,
                             "file": __file__,
                         },
                         "Crate {crate} is not duplicated anymore. "
--- a/taskcluster/scripts/misc/build-gcc-sixgill-plugin-linux.sh
+++ b/taskcluster/scripts/misc/build-gcc-sixgill-plugin-linux.sh
@@ -6,17 +6,17 @@ set -x
 # This script is for building the sixgill GCC plugin for Linux. It relies on
 # the gcc checkout because it needs to recompile gmp and the gcc build script
 # determines the version of gmp to download.
 
 root_dir=$MOZ_FETCHES_DIR
 build_dir=$GECKO_PATH/build
 data_dir=$GECKO_PATH/build/unix/build-gcc
 
-sixgill_rev=dee1cfae08c2
+sixgill_rev=9b7f4a7bf67a
 sixgill_repo=https://hg.mozilla.org/users/sfink_mozilla.com/sixgill
 
 . $data_dir/build-gcc.sh
 
 mkdir $root_dir/gcc-source || true
 pushd $root_dir/gcc-source
 ln -sf ../gmp-source gmp
 ln -sf ../isl-source isl
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-writing-modes/abs-pos-border-offset-002.html.ini
@@ -0,0 +1,3 @@
+[abs-pos-border-offset-002.html]
+  expected: FAIL
+  bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1769799
--- a/testing/web-platform/meta/svg/animations/end-of-time-001-crash.html.ini
+++ b/testing/web-platform/meta/svg/animations/end-of-time-001-crash.html.ini
@@ -1,4 +1,4 @@
 [end-of-time-001-crash.html]
-  expected:
-    if (os == "android") and not debug: [CRASH, TIMEOUT]
-    [TIMEOUT, CRASH]
+  disabled:
+    if os == "linux" and not debug: https://bugzilla.mozilla.org/show_bug.cgi?id=1770058
+  expected: [TIMEOUT, CRASH]
--- a/testing/web-platform/meta/svg/animations/end-of-time-002-crash.html.ini
+++ b/testing/web-platform/meta/svg/animations/end-of-time-002-crash.html.ini
@@ -1,4 +1,4 @@
 [end-of-time-002-crash.html]
-  expected:
-    if (os == "android") and not debug: [CRASH, TIMEOUT]
-    [TIMEOUT, CRASH]
+  disabled:
+    if os == "linux" and not debug: https://bugzilla.mozilla.org/show_bug.cgi?id=1770058
+  expected: [TIMEOUT, CRASH]
--- a/testing/web-platform/meta/websockets/Send-binary-arraybufferview-int8.any.js.ini
+++ b/testing/web-platform/meta/websockets/Send-binary-arraybufferview-int8.any.js.ini
@@ -6,18 +6,16 @@
   expected:
     if (os == "mac") and not debug: [OK, TIMEOUT]
     if (os == "android") and debug and not swgl: [OK, TIMEOUT]
   [Send binary data on a WebSocket - ArrayBufferView - Int8Array - Connection should be closed]
     expected:
       if (os == "android") and not swgl and debug: [PASS, FAIL]
       if (os == "android") and not swgl and not debug: [PASS, FAIL]
       if (os == "mac") and not debug: [PASS, NOTRUN]
-      if (os == "android") and swgl: FAIL
-
 
 [Send-binary-arraybufferview-int8.any.html?wss]
 
 [Send-binary-arraybufferview-int8.any.html]
 
 [Send-binary-arraybufferview-int8.any.worker.html?wpt_flags=h2]
   expected:
     if (os == "android") and not swgl and not debug: [OK, TIMEOUT]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-scroll-snap/ignore-snap-points-orthogonal-to-snap-axis.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<title>Ignore snap points orthogonal to scroll snap axis</title>
+<link rel="help" href="https://drafts.csswg.org/css-scroll-snap/#snap-axis" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+div {
+  position: absolute;
+  margin: 0;
+}
+
+#scroller {
+  height: 500px;
+  width: 500px;
+  overflow: hidden;
+  scroll-snap-type: x mandatory;
+}
+
+#y-target {
+  width: 300px;
+  height: 300px;
+  top: 100px;
+  left: 0;
+  background-color: green;
+  /* align only on y-axis */
+  scroll-snap-align: start none;
+}
+
+#x-target {
+  width: 300px;
+  height: 300px;
+  top: 0;
+  left: 100px;
+  background-color: red;
+  scroll-snap-align: none start;
+}
+
+.area {
+  width: 2000px;
+  height: 2000px;
+}
+</style>
+
+<div id="scroller">
+  <div class="area"></div>
+  <div id="x-target"></div>
+  <div id="y-target"></div>
+</div>
+
+<script>
+test(t => {
+  scroller.scrollTo(0,0);
+  assert_equals(scroller.scrollTop, 0);
+  assert_equals(scroller.scrollLeft, 100);
+}, "Ignore snap points orthogonal to scroll snap axis");
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-writing-modes/abs-pos-border-offset-001-ref.html
@@ -0,0 +1,243 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<style>
+  body { margin: 0; }
+  .cb {
+    position: relative;
+    inline-size: 45px;
+    block-size: 40px;
+    background: lightblue;
+    border: solid gray;
+    border-width: 1px 2px 3px 4px;
+    float: left;
+    margin-right: 5px;
+  }
+  .parent {
+    inline-size: 35px;
+    block-size: 30px;
+    background: orange;
+  }
+  .abspos {
+    inline-size: 20px;
+    block-size: 15px;
+    background: pink;
+  }
+
+  .vrl {
+    writing-mode: vertical-rl;
+  }
+  .vlr {
+    writing-mode: vertical-lr;
+  }
+  .htb {
+    writing-mode: horizontal-tb;
+  }
+
+  .ltr {
+    direction: ltr;
+  }
+  .rtl {
+    direction: rtl;
+  }
+
+  .sep {
+    clear: both;
+    display: block;
+    height: 5px;
+  }
+</style>
+<body>
+  <div class="cb htb ltr">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb ltr">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb ltr">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb ltr">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb ltr">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb ltr">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb htb rtl">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb rtl">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb rtl">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb rtl">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb rtl">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb rtl">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb vlr ltr">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr ltr">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr ltr">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr ltr">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr ltr">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr ltr">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb vlr rtl">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr rtl">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr rtl">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr rtl">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr rtl">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr rtl">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb vrl ltr">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl ltr">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl ltr">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl ltr">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl ltr">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl ltr">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb vrl rtl">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl rtl">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl rtl">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl rtl">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl rtl">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl rtl">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-writing-modes/abs-pos-border-offset-001.html
@@ -0,0 +1,248 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://drafts.csswg.org/css-writing-modes-3/#block-flow">
+<meta name="assert"
+  content="This test checks that absolutely positioned elements are offset correctly in a bordered containing block, in different combinations of writing modes and directions." />
+<link rel="match" href="abs-pos-border-offset-001-ref.html">
+<style>
+  body { margin: 0; }
+  .cb {
+    position: relative;
+    inline-size: 45px;
+    block-size: 40px;
+    background: lightblue;
+    border: solid gray;
+    border-width: 1px 2px 3px 4px;
+    float: left;
+    margin-right: 5px;
+  }
+  .parent {
+    inline-size: 35px;
+    block-size: 30px;
+    background: orange;
+  }
+  .abspos {
+    position: absolute;
+    inline-size: 20px;
+    block-size: 15px;
+    background: pink;
+  }
+
+  .vrl {
+    writing-mode: vertical-rl;
+  }
+  .vlr {
+    writing-mode: vertical-lr;
+  }
+  .htb {
+    writing-mode: horizontal-tb;
+  }
+
+  .ltr {
+    direction: ltr;
+  }
+  .rtl {
+    direction: rtl;
+  }
+
+  .sep {
+    clear: both;
+    display: block;
+    height: 5px;
+  }
+</style>
+<body>
+  <div class="cb htb ltr">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb ltr">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb ltr">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb ltr">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb ltr">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb ltr">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb htb rtl">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb rtl">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb rtl">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb rtl">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb rtl">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb rtl">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb vlr ltr">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr ltr">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr ltr">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr ltr">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr ltr">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr ltr">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb vlr rtl">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr rtl">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr rtl">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr rtl">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr rtl">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr rtl">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb vrl ltr">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl ltr">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl ltr">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl ltr">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl ltr">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl ltr">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb vrl rtl">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl rtl">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl rtl">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl rtl">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl rtl">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl rtl">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-writing-modes/abs-pos-border-offset-002-ref.html
@@ -0,0 +1,397 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<style>
+  body { margin: 0; }
+  .cb {
+    position: relative;
+    inline-size: 45px;
+    block-size: 40px;
+    background: lightblue;
+    border: solid gray;
+    border-width: 1px 2px 3px 4px;
+    float: left;
+    margin-right: 5px;
+  }
+  .parent {
+    inline-size: 35px;
+    block-size: 30px;
+    background: orange;
+  }
+  .abspos {
+    inline-size: 20px;
+    block-size: 15px;
+    background: pink;
+  }
+
+  .vrl {
+    writing-mode: vertical-rl;
+  }
+  .vlr {
+    writing-mode: vertical-lr;
+  }
+  .srl {
+    writing-mode: sideways-rl;
+  }
+  .slr {
+    writing-mode: sideways-lr;
+  }
+  .htb {
+    writing-mode: horizontal-tb;
+  }
+
+  .ltr {
+    direction: ltr;
+  }
+  .rtl {
+    direction: rtl;
+  }
+
+  .sep {
+    clear: both;
+    display: block;
+    height: 5px;
+  }
+</style>
+<body>
+  <div class="cb htb ltr">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb ltr">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb ltr">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb ltr">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb htb rtl">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb rtl">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb rtl">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb rtl">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb vlr ltr">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr ltr">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr ltr">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr ltr">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb vlr rtl">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr rtl">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr rtl">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr rtl">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb vrl ltr">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl ltr">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl ltr">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl ltr">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb vrl rtl">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl rtl">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl rtl">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl rtl">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb slr ltr">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr ltr">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr ltr">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr ltr">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr ltr">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr ltr">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr ltr">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr ltr">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr ltr">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr ltr">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb slr rtl">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr rtl">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr rtl">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr rtl">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr rtl">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr rtl">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr rtl">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr rtl">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr rtl">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr rtl">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb srl ltr">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl ltr">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl ltr">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl ltr">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl ltr">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl ltr">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl ltr">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl ltr">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl ltr">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl ltr">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb srl rtl">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl rtl">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl rtl">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl rtl">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl rtl">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl rtl">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl rtl">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl rtl">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl rtl">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl rtl">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-writing-modes/abs-pos-border-offset-002.html
@@ -0,0 +1,401 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://drafts.csswg.org/css-writing-modes-3/#block-flow">
+<meta name="assert" content="This test checks that absolutely positioned elements are offset correctly in a bordered containing block, in different combinations of sideways writing modes and directions." />
+<link rel="match" href="abs-pos-border-offset-002-ref.html">
+<style>
+  body { margin: 0; }
+  .cb {
+    position: relative;
+    inline-size: 45px;
+    block-size: 40px;
+    background: lightblue;
+    border: solid gray;
+    border-width: 1px 2px 3px 4px;
+    float: left;
+    margin-right: 5px;
+  }
+  .parent {
+    inline-size: 35px;
+    block-size: 30px;
+    background: orange;
+  }
+  .abspos {
+    position: absolute;
+    inline-size: 20px;
+    block-size: 15px;
+    background: pink;
+  }
+
+  .srl {
+    writing-mode: sideways-rl;
+  }
+  .slr {
+    writing-mode: sideways-lr;
+  }
+  .vrl {
+    writing-mode: vertical-rl;
+  }
+  .vlr {
+    writing-mode: vertical-lr;
+  }
+  .htb {
+    writing-mode: horizontal-tb;
+  }
+
+  .ltr {
+    direction: ltr;
+  }
+  .rtl {
+    direction: rtl;
+  }
+
+  .sep {
+    clear: both;
+    display: block;
+    height: 5px;
+  }
+</style>
+<body>
+  <div class="cb htb ltr">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb ltr">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb ltr">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb ltr">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb htb rtl">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb rtl">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb rtl">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb htb rtl">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb vlr ltr">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr ltr">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr ltr">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr ltr">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb vlr rtl">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr rtl">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr rtl">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vlr rtl">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb vrl ltr">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl ltr">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl ltr">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl ltr">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb vrl rtl">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl rtl">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl rtl">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb vrl rtl">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb slr ltr">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr ltr">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr ltr">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr ltr">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr ltr">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr ltr">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr ltr">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr ltr">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr ltr">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr ltr">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb slr rtl">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr rtl">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr rtl">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr rtl">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr rtl">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr rtl">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr rtl">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr rtl">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr rtl">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb slr rtl">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb srl ltr">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl ltr">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl ltr">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl ltr">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl ltr">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl ltr">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl ltr">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl ltr">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl ltr">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl ltr">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+
+  <div class="cb srl rtl">
+    <div class="parent htb ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl rtl">
+    <div class="parent htb rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl rtl">
+    <div class="parent vlr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl rtl">
+    <div class="parent vlr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl rtl">
+    <div class="parent vrl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl rtl">
+    <div class="parent vrl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl rtl">
+    <div class="parent slr ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl rtl">
+    <div class="parent slr rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl rtl">
+    <div class="parent srl ltr">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="cb srl rtl">
+    <div class="parent srl rtl">
+      <div class="abspos"></div>
+    </div>
+  </div>
+  <div class="sep"></div>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-writing-modes/abs-pos-vlr-border-001-ref.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<style>
+  body { margin: 0; }
+  .vert-cb {
+    position: relative;
+    width: 150px;
+    height: 60px;
+    writing-mode: vertical-lr;
+    direction: rtl;
+    background: lightblue;
+    border: solid gray;
+    border-width: 1px 2px 3px 4px;
+    margin-bottom: 2px;
+  }
+  .horiz-parent {
+    width: 120px;
+    height: 100%;
+    box-sizing: border-box;
+    border: solid orange;
+    border-width: 4px 3px 2px 1px;
+    writing-mode: horizontal-tb;
+  }
+  .abspos-equivalent {
+    height: 40px;
+    background: pink;
+    border: solid black;
+    border-width: 2px 1px 4px 3px;
+  }
+</style>
+<body>
+  <div class="vert-cb">
+    <div class="horiz-parent">
+      <div class="abspos-equivalent" style="width: max-content">Hello</div>
+    </div>
+  </div>
+  <div class="vert-cb">
+    <div class="horiz-parent">
+      <div class="abspos-equivalent" style="width: 100px">Hello</div>
+    </div>
+  </div>
+  <div class="vert-cb">
+    <div class="horiz-parent">
+      <canvas class="abspos-equivalent" height="40px" width="100px"></canvas>
+    </div>
+  </div>
+  <div class="vert-cb">
+    <div class="horiz-parent">
+      <img src="broken" class="abspos-equivalent" height="40px" width="100px">
+    </div>
+  </div>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-writing-modes/abs-pos-vlr-border-001.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://drafts.csswg.org/css-writing-modes-3/#block-flow">
+<meta name="assert" content="This test checks that absolutely positioned elements are offset correctly in a containing block with an orthogonal writing mode and that has a border." />
+<link rel="match" href="abs-pos-vlr-border-001-ref.html">
+<style>
+  body { margin: 0; }
+  .vert-cb {
+    position: relative;
+    width: 150px;
+    height: 60px;
+    writing-mode: vertical-lr;
+    direction: rtl;
+    background: lightblue;
+    border: solid gray;
+    border-width: 1px 2px 3px 4px;
+    margin-bottom: 2px;
+  }
+  .horiz-parent {
+    width: 120px;
+    height: 100%;
+    box-sizing: border-box;
+    border: solid orange;
+    border-width: 4px 3px 2px 1px;
+    writing-mode: horizontal-tb;
+  }
+  .abspos {
+    position: absolute;
+    /* Specify a height to work around https://bugzilla.mozilla.org/1769102 */
+    height: 40px;
+    background: pink;
+    border: solid black;
+    border-width: 2px 1px 4px 3px;
+  }
+</style>
+<body>
+  <div class="vert-cb">
+    <div class="horiz-parent">
+      <div class="abspos" style="width: max-content">Hello</div>
+    </div>
+  </div>
+  <div class="vert-cb">
+    <div class="horiz-parent">
+      <div class="abspos" style="width: 100px">Hello</div>
+    </div>
+  </div>
+  <div class="vert-cb">
+    <div class="horiz-parent">
+      <canvas class="abspos" height="40px" width="100px"></canvas>
+    </div>
+  </div>
+  <div class="vert-cb">
+    <div class="horiz-parent">
+      <img src="broken" class="abspos" height="40px" width="100px">
+    </div>
+  </div>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-writing-modes/abs-pos-vlr-padding-001-ref.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<style>
+  body { margin: 0; }
+  .vert-cb {
+    position: relative;
+    width: 150px;
+    height: 60px;
+    writing-mode: vertical-lr;
+    direction: rtl;
+    background: lightblue;
+    padding: 1px 2px 3px 4px;
+    margin-bottom: 2px;
+  }
+  .horiz-parent {
+    width: 120px;
+    height: 100%;
+    box-sizing: border-box;
+    border: solid orange;
+    border-width: 4px 3px 2px 1px;
+    writing-mode: horizontal-tb;
+  }
+  .abspos-equivalent {
+    height: 40px;
+    background: pink;
+    border: solid black;
+    border-width: 2px 1px 4px 3px;
+  }
+</style>
+<body>
+  <div class="vert-cb">
+    <div class="horiz-parent">
+      <div class="abspos-equivalent" style="width: max-content">Hello</div>
+    </div>
+  </div>
+  <div class="vert-cb">
+    <div class="horiz-parent">
+      <div class="abspos-equivalent" style="width: 100px">Hello</div>
+    </div>
+  </div>
+  <div class="vert-cb">
+    <div class="horiz-parent">
+      <canvas class="abspos-equivalent" height="40px" width="100px"></canvas>
+    </div>
+  </div>
+  <div class="vert-cb">
+    <div class="horiz-parent">
+      <img src="broken" class="abspos-equivalent" height="40px" width="100px">
+    </div>
+  </div>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-writing-modes/abs-pos-vlr-padding-001.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://drafts.csswg.org/css-writing-modes-3/#block-flow">
+<meta name="assert" content="This test checks that absolutely positioned elements are offset correctly in a containing block with a different writing mode and that has padding." />
+<link rel="match" href="abs-pos-vlr-padding-001-ref.html">
+<style>
+  body { margin: 0; }
+  .vert-cb {
+    position: relative;
+    width: 150px;
+    height: 60px;
+    writing-mode: vertical-lr;
+    direction: rtl;
+    background: lightblue;
+    padding: 1px 2px 3px 4px;
+    margin-bottom: 2px;
+  }
+  .horiz-parent {
+    width: 120px;
+    height: 100%;
+    box-sizing: border-box;
+    border: solid orange;
+    border-width: 4px 3px 2px 1px;
+    writing-mode: horizontal-tb;
+  }
+  .abspos {
+    position: absolute;
+    /* Specify a height to work around https://bugzilla.mozilla.org/1769102 */
+    height: 40px;
+    background: pink;
+    border: solid black;
+    border-width: 2px 1px 4px 3px;
+  }
+</style>
+<body>
+  <div class="vert-cb">
+    <div class="horiz-parent">
+      <div class="abspos" style="width: max-content">Hello</div>
+    </div>
+  </div>
+  <div class="vert-cb">
+    <div class="horiz-parent">
+      <div class="abspos" style="width: 100px">Hello</div>
+    </div>
+  </div>
+  <div class="vert-cb">
+    <div class="horiz-parent">
+      <canvas class="abspos" height="40px" width="100px"></canvas>
+    </div>
+  </div>
+  <div class="vert-cb">
+    <div class="horiz-parent">
+      <img src="broken" class="abspos" height="40px" width="100px">
+    </div>
+  </div>
+</body>
--- a/third_party/rust/anyhow/.cargo-checksum.json
+++ b/third_party/rust/anyhow/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"ce2fb7f23073f4f0bd58bae44baab86fa6c3d3595f32d28b410ec52394b3f64c","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"f6bffe3676b128afe14aaf91c972d69c37f2e5afe4e02b99a974f7b7393f4cda","build.rs":"b6ee548cb30aba0a4a7ff92379478fcf94ef246b892da8e2134ee2d9575bf08c","rust-toolchain.toml":"6bbb61302978c736b2da03e4fb40e3beab908f85d533ab46fd541e637b5f3e0f","src/backtrace.rs":"5a60bd1fe1717c044c7ab34c062ce6651c0cb08596a5878e391c2755ecac07f9","src/chain.rs":"6edefc5f3c7d69683095862e54e3bb56faba5b3387bf2eeaed429da090007a0a","src/context.rs":"559478ae785ce913523aa21358cc1561ef4b0b95c5c87675a77890364c0162fe","src/ensure.rs":"98b2f4a7923e06cf6558b0a15f39a7c7ff3d36711e217475c6a93690cd58b7a1","src/error.rs":"33a0f6c49d2c5d08b8d027aa930be75ece822331d6e6b28db74520ea69587cbc","src/fmt.rs":"c2d4aad6ce20625a70a7c091e3087b6a2c19a4a87c7a12edb4c98978307245ea","src/kind.rs":"b21b15dbee77d50abe88684a9571b39659076465dd4b1956f366af8fdd26e95a","src/lib.rs":"330286a28b4d4da255db38bc267da17fb03f2333ea26684f82124973ffcaea43","src/macros.rs":"5a735a3fa919de58729be54976678c0a386e8e9af947987f17fd988c531974c7","src/ptr.rs":"f4e28bc9feba1e84160ca9d185008a51b5d72e168e6546f3e942f4258c361e19","src/wrapper.rs":"1229beca67dbd95ca77c9ecce282272acc55276c267c58cb73a75388b4693dda","tests/common/mod.rs":"f9088c2d7afafa64ff730b629272045b776bfafc2f5957508242da630635f2e1","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/drop/mod.rs":"08c3e553c1cc0d2dbd936fc45f4b5b1105057186affd6865e8d261e05f0f0646","tests/test_autotrait.rs":"981e792db353be2f14c7a1cabe43b5f1329c168cb7679077cc2be786a0920d48","tests/test_backtrace.rs":"0e50edbb33b6bd07ba89ff3db72fb7c688ba2a4371fccdbbb20309ab02948b6a","tests/test_boxed.rs":"6b26db0e2eb72afe9af7352ea820837aab90f8d486294616dd5dc34c1b94038c","tests/test_chain.rs":"d5e90e3eba58abc60d241d3aade39e0b8d4006d9a14f3cf015d3d925160b5812","tests/test_context.rs":"8409c53b328562c11e822bd6c3cd17e0d4d50b9bbb8fc3617333fd77303a6a33","tests/test_convert.rs":"7e7a8b4772a427a911014ac4d1083f9519000e786177f898808980dd9bdfde61","tests/test_downcast.rs":"ce8438cb58a1b7f3599740c261f6ef05855127ccde20c83c82db15eaf51c57ad","tests/test_ensure.rs":"f8bc5174219da947e6292891864f35307d5c400fd5690f51d574edaa5e39b8a4","tests/test_ffi.rs":"d0cb4c1d6d9154090982dee72ae3ebe05a5981f976058c3250f1c9da5a45edef","tests/test_fmt.rs":"17572596f257aac9aa2ec4620e292ca6a954128b94772bb948399fab53832e70","tests/test_macros.rs":"3f808b3050fc2b18c5b9058fe71b6b464d70e3658ff9b1daa379cd58c6874296","tests/test_repr.rs":"dbb9b04ddbe1ab31eb5331ea69f05bb3a147299da2275a3d4dcc92947b5591b9","tests/test_source.rs":"b80723cf635a4f8c4df21891b34bfab9ed2b2aa407e7a2f826d24e334cd5f88e","tests/ui/chained-comparison.rs":"6504b03d95b5acc232a7f4defc9f343b2be6733bf475fa0992e8e6545b912bd4","tests/ui/chained-comparison.stderr":"7f1d0a8c251b0ede2d30b3087ec157fc660945c97a642c4a5acf5a14ec58de34","tests/ui/empty-ensure.rs":"ab5bf37c846a0d689f26ce9257a27228411ed64154f9c950f1602d88a355d94b","tests/ui/empty-ensure.stderr":"0fa39de3edadb86382d8cd147c2640771e080338be2f4b067650258e3150f181","tests/ui/no-impl.rs":"fab6cbf2f6ea510b86f567dfb3b7c31250a9fd71ae5d110dbb9188be569ec593","tests/ui/no-impl.stderr":"9d2d9cdf441f1c4a0ccbc4a7433013166425b98cd8dd8738381e8fd070c1aed9","tests/ui/temporary-value.rs":"4dcc96271b2403e6372cf4cfc813445e5ce4365fc6e156b6bc38274098499a70","tests/ui/temporary-value.stderr":"64e448b6759cf51d41b1360307a638452bbe53ffa706f93e4a503b712d7b89a8","tests/ui/wrong-interpolation.rs":"9c44d4674c2dccd27b9dedd03341346ec02d993b41793ee89b5755202e7e367e","tests/ui/wrong-interpolation.stderr":"301e60e2eb9401782c7dc0b3580613a4cb2aafd4cc8065734a630a62e1161aa5"},"package":"84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3"}
\ No newline at end of file
+{"files":{"Cargo.toml":"bb77e71078c35dd4bcf7347f36146d5952addb80749a4f72752421e7c022b9a3","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"f6bffe3676b128afe14aaf91c972d69c37f2e5afe4e02b99a974f7b7393f4cda","build.rs":"b6ee548cb30aba0a4a7ff92379478fcf94ef246b892da8e2134ee2d9575bf08c","rust-toolchain.toml":"6bbb61302978c736b2da03e4fb40e3beab908f85d533ab46fd541e637b5f3e0f","src/backtrace.rs":"5a60bd1fe1717c044c7ab34c062ce6651c0cb08596a5878e391c2755ecac07f9","src/chain.rs":"6edefc5f3c7d69683095862e54e3bb56faba5b3387bf2eeaed429da090007a0a","src/context.rs":"559478ae785ce913523aa21358cc1561ef4b0b95c5c87675a77890364c0162fe","src/ensure.rs":"ba404f1708d41a267f8678858aebefadc8fae717bd5533e5ebb47e219aa44f7e","src/error.rs":"6c5b1357eedd6f2be1fdaee1be645a33e68c945c481d6ff20b98c8fdedea687a","src/fmt.rs":"c2d4aad6ce20625a70a7c091e3087b6a2c19a4a87c7a12edb4c98978307245ea","src/kind.rs":"b21b15dbee77d50abe88684a9571b39659076465dd4b1956f366af8fdd26e95a","src/lib.rs":"8c78c195027482d3403276149fc85bab6ae934c3568357b91b7b399aabf55baf","src/macros.rs":"0381ec8981e5ad1a21c67831bb11d46b8994fc82c4b8b98ad1917f5d83acb359","src/ptr.rs":"f4e28bc9feba1e84160ca9d185008a51b5d72e168e6546f3e942f4258c361e19","src/wrapper.rs":"1229beca67dbd95ca77c9ecce282272acc55276c267c58cb73a75388b4693dda","tests/common/mod.rs":"f9088c2d7afafa64ff730b629272045b776bfafc2f5957508242da630635f2e1","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/drop/mod.rs":"08c3e553c1cc0d2dbd936fc45f4b5b1105057186affd6865e8d261e05f0f0646","tests/test_autotrait.rs":"981e792db353be2f14c7a1cabe43b5f1329c168cb7679077cc2be786a0920d48","tests/test_backtrace.rs":"0e50edbb33b6bd07ba89ff3db72fb7c688ba2a4371fccdbbb20309ab02948b6a","tests/test_boxed.rs":"6b26db0e2eb72afe9af7352ea820837aab90f8d486294616dd5dc34c1b94038c","tests/test_chain.rs":"d5e90e3eba58abc60d241d3aade39e0b8d4006d9a14f3cf015d3d925160b5812","tests/test_context.rs":"8409c53b328562c11e822bd6c3cd17e0d4d50b9bbb8fc3617333fd77303a6a33","tests/test_convert.rs":"7e7a8b4772a427a911014ac4d1083f9519000e786177f898808980dd9bdfde61","tests/test_downcast.rs":"ce8438cb58a1b7f3599740c261f6ef05855127ccde20c83c82db15eaf51c57ad","tests/test_ensure.rs":"bd793da08a4d01b8211646d82bec73468e54f6caf5f520617519a12cbb6659b9","tests/test_ffi.rs":"d0cb4c1d6d9154090982dee72ae3ebe05a5981f976058c3250f1c9da5a45edef","tests/test_fmt.rs":"17572596f257aac9aa2ec4620e292ca6a954128b94772bb948399fab53832e70","tests/test_macros.rs":"3f808b3050fc2b18c5b9058fe71b6b464d70e3658ff9b1daa379cd58c6874296","tests/test_repr.rs":"dbb9b04ddbe1ab31eb5331ea69f05bb3a147299da2275a3d4dcc92947b5591b9","tests/test_source.rs":"b80723cf635a4f8c4df21891b34bfab9ed2b2aa407e7a2f826d24e334cd5f88e","tests/ui/chained-comparison.rs":"6504b03d95b5acc232a7f4defc9f343b2be6733bf475fa0992e8e6545b912bd4","tests/ui/chained-comparison.stderr":"7f1d0a8c251b0ede2d30b3087ec157fc660945c97a642c4a5acf5a14ec58de34","tests/ui/empty-ensure.rs":"ab5bf37c846a0d689f26ce9257a27228411ed64154f9c950f1602d88a355d94b","tests/ui/empty-ensure.stderr":"0fa39de3edadb86382d8cd147c2640771e080338be2f4b067650258e3150f181","tests/ui/must-use.rs":"fb59860b43f673bf4a430a6036ba463e95028844d8dd4243cfe5ebc7f2be582f","tests/ui/must-use.stderr":"4dc15f52c3a186251c948b6a2955b777ed3c88e5da94b887f8ff945b3ecd8cee","tests/ui/no-impl.rs":"fab6cbf2f6ea510b86f567dfb3b7c31250a9fd71ae5d110dbb9188be569ec593","tests/ui/no-impl.stderr":"0af22519410b6420e34d7b5bb387d21951013bdd5faced5fd1eff142742cf68e","tests/ui/temporary-value.rs":"4dcc96271b2403e6372cf4cfc813445e5ce4365fc6e156b6bc38274098499a70","tests/ui/temporary-value.stderr":"64e448b6759cf51d41b1360307a638452bbe53ffa706f93e4a503b712d7b89a8","tests/ui/wrong-interpolation.rs":"9c44d4674c2dccd27b9dedd03341346ec02d993b41793ee89b5755202e7e367e","tests/ui/wrong-interpolation.stderr":"301e60e2eb9401782c7dc0b3580613a4cb2aafd4cc8065734a630a62e1161aa5"},"package":"08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc"}
\ No newline at end of file
--- a/third_party/rust/anyhow/Cargo.toml
+++ b/third_party/rust/anyhow/Cargo.toml
@@ -8,30 +8,36 @@
 # If you are reading this file be aware that the original Cargo.toml
 # will likely look very different (and much more reasonable).
 # See Cargo.toml.orig for the original contents.
 
 [package]
 edition = "2018"
 rust-version = "1.38"
 name = "anyhow"
-version = "1.0.52"
+version = "1.0.57"
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 description = "Flexible concrete Error type built on std::error::Error"
 documentation = "https://docs.rs/anyhow"
 readme = "README.md"
 categories = ["rust-patterns"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/dtolnay/anyhow"
+
 [package.metadata.docs.rs]
-rustdoc-args = ["--cfg", "doc_cfg"]
 targets = ["x86_64-unknown-linux-gnu"]
+rustdoc-args = [
+    "--cfg",
+    "doc_cfg",
+]
+
 [dependencies.backtrace]
 version = "0.3.51"
 optional = true
+
 [dev-dependencies.futures]
 version = "0.3"
 default-features = false
 
 [dev-dependencies.rustversion]
 version = "1.0.6"
 
 [dev-dependencies.syn]
--- a/third_party/rust/anyhow/src/ensure.rs
+++ b/third_party/rust/anyhow/src/ensure.rs
@@ -252,16 +252,20 @@ macro_rules! __parse_ensure {
     (epath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $langle:tt $($dup:tt)*) :: < $($rest:tt)*) => {
         $crate::__parse_ensure!(generic (epath $stack) $bail ($($fuel)*) {($($buf)* $colons $langle) $($parse)*} ($($rest)*) $($rest)*)
     };
 
     (epath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $($dup:tt)*) :: << $($rest:tt)*) => {
         $crate::__parse_ensure!(generic (epath $stack) $bail ($($fuel)*) {($($buf)* $colons <) $($parse)*} (< $($rest)*) < $($rest)*)
     };
 
+    (epath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $($dup:tt)*) :: <- $($rest:tt)*) => {
+        $crate::__parse_ensure!(generic (epath $stack) $bail ($($fuel)*) {($($buf)* $colons <) $($parse)*} (- $($rest)*) - $($rest)*)
+    };
+
     (epath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $($dup:tt)*) :: $ident:ident $($rest:tt)*) => {
         $crate::__parse_ensure!(epath $stack $bail ($($fuel)*) {($($buf)* $colons $ident) $($parse)*} ($($rest)*) $($rest)*)
     };
 
     (epath ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bang:tt $args:tt $($dup:tt)*) ! ($($mac:tt)*) $($rest:tt)*) => {
         $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $bang $args) $($parse)*} ($($rest)*) $($rest)*)
     };
 
@@ -298,16 +302,20 @@ macro_rules! __parse_ensure {
     (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dot:tt $ident:tt $colons:tt $langle:tt $($dup:tt)*) . $i:ident :: < $($rest:tt)*) => {
         $crate::__parse_ensure!(generic (atom $stack) $bail ($($fuel)*) {($($buf)* $dot $ident $colons $langle) $($parse)*} ($($rest)*) $($rest)*)
     };
 
     (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dot:tt $ident:tt $colons:tt $($dup:tt)*) . $i:ident :: << $($rest:tt)*) => {
         $crate::__parse_ensure!(generic (atom $stack) $bail ($($fuel)*) {($($buf)* $dot $ident $colons <) $($parse)*} (< $($rest)*) < $($rest)*)
     };
 
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dot:tt $ident:tt $colons:tt $($dup:tt)*) . $i:ident :: <- $($rest:tt)*) => {
+        $crate::__parse_ensure!(generic (atom $stack) $bail ($($fuel)*) {($($buf)* $dot $ident $colons <) $($parse)*} (- $($rest)*) - $($rest)*)
+    };
+
     (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dot:tt $($dup:tt)*) . $field:ident $($rest:tt)*) => {
         $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $dot $field) $($parse)*} ($($rest)*) $($rest)*)
     };
 
     (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dot:tt $index:tt $($dup:tt)*) . $lit:literal $($rest:tt)*) => {
         $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $dot $index) $($parse)*} ($($rest)*) $($rest)*)
     };
 
@@ -422,24 +430,32 @@ macro_rules! __parse_ensure {
     (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($langle:tt $($dup:tt)*) < $($rest:tt)*) => {
         $crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* $langle) $($parse)*} ($($rest)*) $($rest)*)
     };
 
     (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt << $($rest:tt)*) => {
         $crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* <) $($parse)*} (< $($rest)*) < $($rest)*)
     };
 
+    (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt <- $($rest:tt)*) => {
+        $crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* <) $($parse)*} (- $($rest)*) - $($rest)*)
+    };
+
     (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $langle:tt $($dup:tt)*) :: < $($rest:tt)*) => {
         $crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* $colons $langle) $($parse)*} ($($rest)*) $($rest)*)
     };
 
     (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $($dup:tt)*) :: << $($rest:tt)*) => {
         $crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* $colons <) $($parse)*} (< $($rest)*) < $($rest)*)
     };
 
+    (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $($dup:tt)*) :: <- $($rest:tt)*) => {
+        $crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* $colons <) $($parse)*} (- $($rest)*) - $($rest)*)
+    };
+
     (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $($dup:tt)*) :: $ident:ident $($rest:tt)*) => {
         $crate::__parse_ensure!(tpath $stack $bail ($($fuel)*) {($($buf)* $colons $ident) $($parse)*} ($($rest)*) $($rest)*)
     };
 
     (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($paren:tt $arrow:tt $($dup:tt)*) ($($args:tt)*) -> $($rest:tt)*) => {
         $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $paren $arrow) $($parse)*} ($($rest)*) $($rest)*)
     };
 
@@ -797,22 +813,22 @@ macro_rules! __fallback_ensure {
         if !$cond {
             return $crate::private::Err($crate::Error::msg(
                 $crate::private::concat!("Condition failed: `", $crate::private::stringify!($cond), "`")
             ));
         }
     };
     ($cond:expr, $msg:literal $(,)?) => {
         if !$cond {
-            return $crate::private::Err($crate::anyhow!($msg));
+            return $crate::private::Err($crate::__anyhow!($msg));
         }
     };
     ($cond:expr, $err:expr $(,)?) => {
         if !$cond {
-            return $crate::private::Err($crate::anyhow!($err));
+            return $crate::private::Err($crate::__anyhow!($err));
         }
     };
     ($cond:expr, $fmt:expr, $($arg:tt)*) => {
         if !$cond {
-            return $crate::private::Err($crate::anyhow!($fmt, $($arg)*));
+            return $crate::private::Err($crate::__anyhow!($fmt, $($arg)*));
         }
     };
 }
--- a/third_party/rust/anyhow/src/error.rs
+++ b/third_party/rust/anyhow/src/error.rs
@@ -21,16 +21,17 @@ impl Error {
     /// The error type must be threadsafe and `'static`, so that the `Error`
     /// will be as well.
     ///
     /// If the error type does not provide a backtrace, a backtrace will be
     /// created here to ensure that a backtrace exists.
     #[cfg(feature = "std")]
     #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
     #[cold]
+    #[must_use]
     pub fn new<E>(error: E) -> Self
     where
         E: StdError + Send + Sync + 'static,
     {
         let backtrace = backtrace_if_absent!(error);
         Error::from_std(error, backtrace)
     }
 
@@ -67,16 +68,17 @@ impl Error {
     ///     stream
     ///         .then(ffi::do_some_work) // returns Result<Output, &str>
     ///         .map_err(Error::msg)
     ///         .try_collect()
     ///         .await
     /// }
     /// ```
     #[cold]
+    #[must_use]
     pub fn msg<M>(message: M) -> Self
     where
         M: Display + Debug + Send + Sync + 'static,
     {
         Error::from_adhoc(message, backtrace!())
     }
 
     #[cfg(feature = "std")]
@@ -288,16 +290,17 @@ impl Error {
     ///             "only the first {} lines of {} are valid",
     ///             error.line, path.as_ref().display(),
     ///         );
     ///         anyhow::Error::new(error).context(context)
     ///     })
     /// }
     /// ```
     #[cold]
+    #[must_use]
     pub fn context<C>(self, context: C) -> Self
     where
         C: Display + Send + Sync + 'static,
     {
         let error: ContextError<C, Error> = ContextError {
             context,
             error: self,
         };
--- a/third_party/rust/anyhow/src/lib.rs
+++ b/third_party/rust/anyhow/src/lib.rs
@@ -205,17 +205,17 @@
 //! anyhow = { version = "1.0", default-features = false }
 //! ```
 //!
 //! Since the `?`-based error conversions would normally rely on the
 //! `std::error::Error` trait which is only available through std, no_std mode
 //! will require an explicit `.map_err(Error::msg)` when working with a
 //! non-Anyhow error type inside a function that returns Anyhow's error type.
 
-#![doc(html_root_url = "https://docs.rs/anyhow/1.0.52")]
+#![doc(html_root_url = "https://docs.rs/anyhow/1.0.57")]
 #![cfg_attr(backtrace, feature(backtrace))]
 #![cfg_attr(doc_cfg, feature(doc_cfg))]
 #![cfg_attr(not(feature = "std"), no_std)]
 #![deny(dead_code, unused_imports, unused_mut)]
 #![allow(
     clippy::doc_markdown,
     clippy::enum_glob_use,
     clippy::missing_errors_doc,
@@ -491,16 +491,21 @@ pub type Result<T, E = Error> = core::re
 ///
 /// ```console
 /// Error: Failed to read instrs from ./path/to/instrs.json
 ///
 /// Caused by:
 ///     No such file or directory (os error 2)
 /// ```
 ///
+/// Refer to the [Display representations] documentation for other forms in
+/// which this context chain can be rendered.
+///
+/// [Display representations]: Error#display-representations
+///
 /// <br>
 ///
 /// # Effect on downcasting
 ///
 /// After attaching context of type `C` onto an error of type `E`, the resulting
 /// `anyhow::Error` may be downcast to `C` **or** to `E`.
 ///
 /// That is, in codebases that rely on downcasting, Anyhow's context supports
@@ -658,9 +663,17 @@ pub mod private {
         if let Some(message) = fmt_arguments_as_str {
             // anyhow!("literal"), can downcast to &'static str
             Error::msg(message)
         } else {
             // anyhow!("interpolate {var}"), can downcast to String
             Error::msg(fmt::format(args))
         }
     }
+
+    #[doc(hidden)]
+    #[inline]
+    #[cold]
+    #[must_use]
+    pub fn must_use(error: Error) -> Error {
+        error
+    }
 }
--- a/third_party/rust/anyhow/src/macros.rs
+++ b/third_party/rust/anyhow/src/macros.rs
@@ -45,48 +45,26 @@
 /// #     let depth = 0;
 /// #
 /// if depth > MAX_DEPTH {
 ///     bail!(ScienceError::RecursionLimitExceeded);
 /// }
 /// #     Ok(())
 /// # }
 /// ```
-#[cfg(doc)]
 #[macro_export]
 macro_rules! bail {
     ($msg:literal $(,)?) => {
-        return $crate::private::Err($crate::anyhow!($msg))
+        return $crate::private::Err($crate::__anyhow!($msg))
     };
     ($err:expr $(,)?) => {
-        return $crate::private::Err($crate::anyhow!($err))
+        return $crate::private::Err($crate::__anyhow!($err))
     };
     ($fmt:expr, $($arg:tt)*) => {
-        return $crate::private::Err($crate::anyhow!($fmt, $($arg)*))
-    };
-}
-
-// Workaround for crates that intentionally contained `{}` in an error message
-// prior to https://github.com/dtolnay/anyhow/issues/55 catching the missing
-// format args.
-#[cfg(not(doc))]
-#[macro_export]
-macro_rules! bail {
-    // https://github.com/estk/log4rs/blob/afa0351af56b3bfd1780389700051d7e4d8bbdc9/src/append/rolling_file/policy/compound/roll/fixed_window.rs#L261
-    ("pattern does not contain `{}`") => {
-        return $crate::private::Err($crate::Error::msg("pattern does not contain `{}`"))
-    };
-    ($msg:literal $(,)?) => {
-        return $crate::private::Err($crate::anyhow!($msg))
-    };
-    ($err:expr $(,)?) => {
-        return $crate::private::Err($crate::anyhow!($err))
-    };
-    ($fmt:expr, $($arg:tt)*) => {
-        return $crate::private::Err($crate::anyhow!($fmt, $($arg)*))
+        return $crate::private::Err($crate::__anyhow!($fmt, $($arg)*))
     };
 }
 
 /// Return early with an error if a condition is not satisfied.
 ///
 /// This macro is equivalent to `if !$cond { return
 /// Err(`[`anyhow!($args...)`][anyhow!]`); }`.
 ///
@@ -140,27 +118,27 @@ macro_rules! ensure {
         if !$cond {
             return $crate::private::Err($crate::Error::msg(
                 $crate::private::concat!("Condition failed: `", $crate::private::stringify!($cond), "`")
             ));
         }
     };
     ($cond:expr, $msg:literal $(,)?) => {
         if !$cond {
-            return $crate::private::Err($crate::anyhow!($msg));
+            return $crate::private::Err($crate::__anyhow!($msg));
         }
     };
     ($cond:expr, $err:expr $(,)?) => {
         if !$cond {
-            return $crate::private::Err($crate::anyhow!($err));
+            return $crate::private::Err($crate::__anyhow!($err));
         }
     };
     ($cond:expr, $fmt:expr, $($arg:tt)*) => {
         if !$cond {
-            return $crate::private::Err($crate::anyhow!($fmt, $($arg)*));
+            return $crate::private::Err($crate::__anyhow!($fmt, $($arg)*));
         }
     };
 }
 
 #[cfg(not(doc))]
 #[macro_export]
 macro_rules! ensure {
     ($($tt:tt)*) => {
@@ -201,16 +179,42 @@ macro_rules! ensure {
 ///     }
 ///
 ///     // ...
 ///     # Ok(())
 /// }
 /// ```
 #[macro_export]
 macro_rules! anyhow {
+    ($msg:literal $(,)?) => {
+        $crate::private::must_use({
+            let error = $crate::private::format_err($crate::private::format_args!($msg));
+            error
+        })
+    };
+    ($err:expr $(,)?) => {
+        $crate::private::must_use({
+            use $crate::private::kind::*;
+            let error = match $err {
+                error => (&error).anyhow_kind().new(error),
+            };
+            error
+        })
+    };
+    ($fmt:expr, $($arg:tt)*) => {
+        $crate::Error::msg($crate::private::format!($fmt, $($arg)*))
+    };
+}
+
+// Not public API. This is used in the implementation of some of the other
+// macros, in which the must_use call is not needed because the value is known
+// to be used.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! __anyhow {
     ($msg:literal $(,)?) => ({
         let error = $crate::private::format_err($crate::private::format_args!($msg));
         error
     });
     ($err:expr $(,)?) => ({
         use $crate::private::kind::*;
         let error = match $err {
             error => (&error).anyhow_kind().new(error),
--- a/third_party/rust/anyhow/tests/test_ensure.rs
+++ b/third_party/rust/anyhow/tests/test_ensure.rs
@@ -8,17 +8,18 @@
     clippy::logic_bug,
     clippy::match_bool,
     clippy::never_loop,
     clippy::redundant_closure_call,
     clippy::redundant_pattern_matching,
     clippy::too_many_lines,
     clippy::unit_arg,
     clippy::while_immutable_condition,
-    clippy::zero_ptr
+    clippy::zero_ptr,
+    irrefutable_let_patterns
 )]
 
 use anyhow::{anyhow, ensure, Chain, Error, Result};
 use std::fmt::Debug;
 use std::iter;
 use std::marker::{PhantomData, PhantomData as P};
 use std::ops::Add;
 use std::ptr;
@@ -318,16 +319,28 @@ fn test_path() {
 
     #[rustfmt::skip]
     let test = || Ok(ensure!(Chain::<'static,>::new.t(1) == 2));
     assert_err(
         test,
         "Condition failed: `Chain::<'static>::new.t(1) == 2` (1 vs 2)",
     );
 
+    fn f<const I: isize>() {}
+    let test = || Ok(ensure!(f::<1>() != ()));
+    assert_err(test, "Condition failed: `f::<1>() != ()` (() vs ())");
+    let test = || Ok(ensure!(f::<-1>() != ()));
+    assert_err(test, "Condition failed: `f::<-1>() != ()` (() vs ())");
+
+    fn g<T, const I: isize>() {}
+    let test = || Ok(ensure!(g::<u8, 1>() != ()));
+    assert_err(test, "Condition failed: `g::<u8, 1>() != ()` (() vs ())");
+    let test = || Ok(ensure!(g::<u8, -1>() != ()));
+    assert_err(test, "Condition failed: `g::<u8, -1>() != ()` (() vs ())");
+
     #[derive(PartialOrd, PartialEq, Debug)]
     enum E<'a, T> {
         #[allow(dead_code)]
         T(&'a T),
         U,
     }
 
     #[rustfmt::skip]
@@ -390,17 +403,17 @@ fn test_trailer() {
     assert_err(test, "Condition failed: `(|| 1)() == 2` (1 vs 2)");
 
     let test = || Ok(ensure!(b"hmm"[1] == b'c'));
     assert_err(test, "Condition failed: `b\"hmm\"[1] == b'c'` (109 vs 99)");
 
     let test = || Ok(ensure!(PhantomData::<u8> {} != PhantomData));
     assert_err(
         test,
-        "Condition failed: `PhantomData::<u8>{} != PhantomData` (PhantomData vs PhantomData)",
+        "Condition failed: `PhantomData::<u8> {} != PhantomData` (PhantomData vs PhantomData)",
     );
 
     let result = Ok::<_, Error>(1);
     let test = || Ok(ensure!(result? == 2));
     assert_err(test, "Condition failed: `result? == 2` (1 vs 2)");
 
     let test = || Ok(ensure!((2, 3).1 == 2));
     assert_err(test, "Condition failed: `(2, 3).1 == 2` (3 vs 2)");
@@ -523,17 +536,17 @@ fn test_as() {
     assert_err(
         test,
         "Condition failed: `f as fn() -> () as usize * 0 != 0` (0 vs 0)",
     );
 
     let test = || Ok(ensure!(f as for<'a> fn() as usize * 0 != 0));
     assert_err(
         test,
-        "Condition failed: `f as for<'a>fn() as usize * 0 != 0` (0 vs 0)", // FIXME
+        "Condition failed: `f as for<'a> fn() as usize * 0 != 0` (0 vs 0)",
     );
 
     let test = || Ok(ensure!(f as unsafe fn() as usize * 0 != 0));
     assert_err(
         test,
         "Condition failed: `f as unsafe fn() as usize * 0 != 0` (0 vs 0)",
     );
 
@@ -608,17 +621,17 @@ fn test_pat() {
     assert_err(
         test,
         "Condition failed: `if let ref mut _x @ 0 = 0 { 0 } else { 1 } == 1` (0 vs 1)",
     );
 
     let test = || Ok(ensure!(if let -1..=1 = 0 { 0 } else { 1 } == 1));
     assert_err(
         test,
-        "Condition failed: `if let -1 ..=1 = 0 { 0 } else { 1 } == 1` (0 vs 1)", // FIXME
+        "Condition failed: `if let -1..=1 = 0 { 0 } else { 1 } == 1` (0 vs 1)",
     );
 
     let test = || Ok(ensure!(if let &0 = &0 { 0 } else { 1 } == 1));
     assert_err(
         test,
         "Condition failed: `if let &0 = &0 { 0 } else { 1 } == 1` (0 vs 1)",
     );
 
@@ -651,17 +664,17 @@ fn test_pat() {
         test,
         "Condition failed: `if let [0] = b\"\\0\" { 0 } else { 1 } == 1` (0 vs 1)",
     );
 
     let p = PhantomData::<u8>;
     let test = || Ok(ensure!(if let P::<u8> {} = p { 0 } else { 1 } == 1));
     assert_err(
         test,
-        "Condition failed: `if let P::<u8> {  } = p { 0 } else { 1 } == 1` (0 vs 1)", // FIXME
+        "Condition failed: `if let P::<u8> {} = p { 0 } else { 1 } == 1` (0 vs 1)",
     );
 
     let test = || Ok(ensure!(if let ::std::marker::PhantomData = p {} != ()));
     assert_err(
         test,
         "Condition failed: `if let ::std::marker::PhantomData = p {} != ()` (() vs ())",
     );
 
new file mode 100644
--- /dev/null
+++ b/third_party/rust/anyhow/tests/ui/must-use.rs
@@ -0,0 +1,11 @@
+#![deny(unused_must_use)]
+
+use anyhow::anyhow;
+
+fn main() -> anyhow::Result<()> {
+    if true {
+        // meant to write bail!
+        anyhow!("it failed");
+    }
+    Ok(())
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/anyhow/tests/ui/must-use.stderr
@@ -0,0 +1,12 @@
+error: unused return value of `anyhow::private::must_use` that must be used
+ --> tests/ui/must-use.rs:8:9
+  |
+8 |         anyhow!("it failed");
+  |         ^^^^^^^^^^^^^^^^^^^^
+  |
+note: the lint level is defined here
+ --> tests/ui/must-use.rs:1:9
+  |
+1 | #![deny(unused_must_use)]
+  |         ^^^^^^^^^^^^^^^
+  = note: this error originates in the macro `anyhow` (in Nightly builds, run with -Z macro-backtrace for more info)
--- a/third_party/rust/anyhow/tests/ui/no-impl.stderr
+++ b/third_party/rust/anyhow/tests/ui/no-impl.stderr
@@ -17,17 +17,17 @@ 7   |     let _ = anyhow!(Error);
             `Error: std::fmt::Display`
             which is required by `&Error: anyhow::private::kind::AdhocKind`
             `&Error: Into<anyhow::Error>`
             which is required by `&Error: anyhow::private::kind::TraitKind`
 note: the following traits must be implemented
    --> $RUST/core/src/convert/mod.rs
     |
     | / pub trait Into<T>: Sized {
-    | |     /// Performs the conversion.
+    | |     /// Converts this type into the (usually inferred) input type.
     | |     #[must_use]
     | |     #[stable(feature = "rust1", since = "1.0.0")]
     | |     fn into(self) -> T;
     | | }
     | |_^
     |
    ::: $RUST/core/src/fmt/mod.rs
     |
--- a/third_party/rust/arbitrary/.cargo-checksum.json
+++ b/third_party/rust/arbitrary/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"CHANGELOG.md":"fd809eba6052a6f34ea7bcbad629dd27a09d1aace817269273bcd2c2dd10a36d","Cargo.lock":"1cc33e3427d1f564ec269b0222ff5b2372c082d01bbf3fd2d1b5e821a19f32a9","Cargo.toml":"6b2f8363fc6c07abdcc96cf7b4a7615720d9d7f958a8531e2b0d07e13efa682e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"15656cc11a8331f28c0986b8ab97220d3e76f98e60ed388b5ffad37dfac4710c","README.md":"950e645eba942c01ae12aaf835b23f2b70bcc75c561e663fe483e000d067a57e","examples/derive_enum.rs":"4d399f1805c48780443182aa141be4e3bf773649b118eab245280799e67742f6","publish.sh":"752e221bdd960666b127df15effddd3d789ff3f1762498961fc79ae99f9a27f1","src/error.rs":"88293a722e314bcc05e4836167b49e76520c9b3d7f64d1ae711f7bd29280f480","src/lib.rs":"18ec8d74692260407ec6683a6f5ae0b9e65c9c258c4dc1510e3956b62b54169b","src/size_hint.rs":"9762b183f8277ee4955fe5b22552961744b6237286758161a551f904ef43e3eb","src/unstructured.rs":"ae7e2cbcd216bfd6cfe2a5e64fd405753da73546437ebf567f121f20f634c36e","tests/derive.rs":"6a4aaa87ee08ea2b67e97e7f6fc7c6247ef9a11144b5465a802631ed0ee5465e","tests/path.rs":"a9706f00ce95d5a11652ae926830756d9111837b55073a0bc6a1eadd25033387"},"package":"510c76ecefdceada737ea728f4f9a84bd2e1ef29f1ba555e560940fe279954de"}
\ No newline at end of file
+{"files":{"CHANGELOG.md":"502a4a3f03e0aa6202524862d1bd9ace9386f9888104d9b8071290d30e8ffaee","Cargo.lock":"baf9208d39ffd4c1328f991b2f898b36d893ab30140c1c97ea4bea0f2a7604a6","Cargo.toml":"e8d6b6242ff8378b1f73f1daa2e42ecece6b33df6ae01a7e6e1a0272f835be84","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"15656cc11a8331f28c0986b8ab97220d3e76f98e60ed388b5ffad37dfac4710c","README.md":"950e645eba942c01ae12aaf835b23f2b70bcc75c561e663fe483e000d067a57e","examples/derive_enum.rs":"4d399f1805c48780443182aa141be4e3bf773649b118eab245280799e67742f6","publish.sh":"752e221bdd960666b127df15effddd3d789ff3f1762498961fc79ae99f9a27f1","src/error.rs":"88293a722e314bcc05e4836167b49e76520c9b3d7f64d1ae711f7bd29280f480","src/lib.rs":"18ec8d74692260407ec6683a6f5ae0b9e65c9c258c4dc1510e3956b62b54169b","src/size_hint.rs":"9762b183f8277ee4955fe5b22552961744b6237286758161a551f904ef43e3eb","src/unstructured.rs":"91635cd36da7743758b01d125f21aa90bbf90994c7e26c379c17a8b3ea519a6a","tests/derive.rs":"9a97927c7bf192e6e229d6142cb9cccd8ec7010797a6da41c4a5cfb7c62fc853","tests/path.rs":"a9706f00ce95d5a11652ae926830756d9111837b55073a0bc6a1eadd25033387"},"package":"c38b6b6b79f671c25e1a3e785b7b82d7562ffc9cd3efdc98627e5668a2472490"}
\ No newline at end of file
--- a/third_party/rust/arbitrary/CHANGELOG.md
+++ b/third_party/rust/arbitrary/CHANGELOG.md
@@ -23,16 +23,30 @@ Released YYYY-MM-DD.
 * TODO (or remove section if none)
 
 ### Security
 
 * TODO (or remove section if none)
 
 --------------------------------------------------------------------------------
 
+## 1.1.0
+
+Released 2022-02-09.
+
+### Added
+
+* Added the `Unstructured::ratio` method to generate a boolean that is `true` at
+  the given rate.
+
+* Added the `Unstructured::arbitrary_loop` method to call a function an
+  arbitrary number of times.
+
+--------------------------------------------------------------------------------
+
 ## 1.0.3
 
 Released 2021-11-20.
 
 ### Fixed
 
 * Fixed documentation for `Unstructured::fill_bytes`. We forgot to update this
   way back in [#53](https://github.com/rust-fuzz/arbitrary/pull/53) when the
--- a/third_party/rust/arbitrary/Cargo.lock
+++ b/third_party/rust/arbitrary/Cargo.lock
@@ -1,15 +1,15 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
 version = 3
 
 [[package]]
 name = "arbitrary"
-version = "1.0.3"
+version = "1.1.0"
 dependencies = [
  "derive_arbitrary",
 ]
 
 [[package]]
 name = "derive_arbitrary"
 version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
--- a/third_party/rust/arbitrary/Cargo.toml
+++ b/third_party/rust/arbitrary/Cargo.toml
@@ -7,34 +7,45 @@
 #
 # If you are reading this file be aware that the original Cargo.toml
 # will likely look very different (and much more reasonable).
 # See Cargo.toml.orig for the original contents.
 
 [package]
 edition = "2018"
 name = "arbitrary"
-version = "1.0.3"
-authors = ["The Rust-Fuzz Project Developers", "Nick Fitzgerald <fitzgen@gmail.com>", "Manish Goregaokar <manishsmail@gmail.com>", "Simonas Kazlauskas <arbitrary@kazlauskas.me>", "Brian L. Troutwine <brian@troutwine.us>", "Corey Farwell <coreyf@rwell.org>"]
+version = "1.1.0"
+authors = [
+    "The Rust-Fuzz Project Developers",
+    "Nick Fitzgerald <fitzgen@gmail.com>",
+    "Manish Goregaokar <manishsmail@gmail.com>",
+    "Simonas Kazlauskas <arbitrary@kazlauskas.me>",
+    "Brian L. Troutwine <brian@troutwine.us>",
+    "Corey Farwell <coreyf@rwell.org>",
+]
 description = "The trait for generating structured data from unstructured data"
 documentation = "https://docs.rs/arbitrary/"
 readme = "README.md"
-keywords = ["arbitrary", "testing"]
+keywords = [
+    "arbitrary",
+    "testing",
+]
 categories = ["development-tools::testing"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/rust-fuzz/arbitrary/"
 
 [[example]]
 name = "derive_enum"
 required-features = ["derive"]
 
 [[test]]
 name = "derive"
 path = "./tests/derive.rs"
 required-features = ["derive"]
+
 [dependencies.derive_arbitrary]
 version = "1.0.0"
 optional = true
 
 [dev-dependencies]
 
 [features]
 derive = ["derive_arbitrary"]
--- a/third_party/rust/arbitrary/src/unstructured.rs
+++ b/third_party/rust/arbitrary/src/unstructured.rs
@@ -5,16 +5,17 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
 //! Wrappers around raw, unstructured bytes.
 
 use crate::{Arbitrary, Error, Result};
 use std::marker::PhantomData;
+use std::ops::ControlFlow;
 use std::{mem, ops};
 
 /// A source of unstructured data.
 ///
 /// An `Unstructured` helps `Arbitrary` implementations interpret raw data
 /// (typically provided by a fuzzer) as a "DNA string" that describes how to
 /// construct the `Arbitrary` type. The goal is that a small change to the "DNA
 /// string" (the raw data wrapped by an `Unstructured`) results in a small
@@ -377,16 +378,51 @@ impl<'a> Unstructured<'a> {
     pub fn choose<'b, T>(&mut self, choices: &'b [T]) -> Result<&'b T> {
         if choices.is_empty() {
             return Err(Error::EmptyChoose);
         }
         let idx = self.int_in_range(0..=choices.len() - 1)?;
         Ok(&choices[idx])
     }
 
+    /// Generate a boolean according to the given ratio.
+    ///
+    /// # Panics
+    ///
+    /// Panics when the numerator and denominator do not meet these constraints:
+    ///
+    /// * `0 < numerator <= denominator`
+    ///
+    /// # Example
+    ///
+    /// Generate a boolean that is `true` five sevenths of the time:
+    ///
+    /// ```
+    /// # fn foo() -> arbitrary::Result<()> {
+    /// use arbitrary::Unstructured;
+    ///
+    /// # let my_data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
+    /// let mut u = Unstructured::new(&my_data);
+    ///
+    /// if u.ratio(5, 7)? {
+    ///     // Take this branch 5/7 of the time.
+    /// }
+    /// # Ok(())
+    /// # }
+    /// ```
+    pub fn ratio<T>(&mut self, numerator: T, denominator: T) -> Result<bool>
+    where
+        T: Int,
+    {
+        assert!(T::ZERO < numerator);
+        assert!(numerator <= denominator);
+        let x = self.int_in_range(T::ONE..=denominator)?;
+        Ok(x <= numerator)
+    }
+
     /// Fill a `buffer` with bytes from the underlying raw data.
     ///
     /// This should only be called within an `Arbitrary` implementation. This is
     /// a very low-level operation. You should generally prefer calling nested
     /// `Arbitrary` implementations like `<Vec<u8>>::arbitrary` and
     /// `String::arbitrary` over using this method directly.
     ///
     /// If this `Unstructured` does not have enough underlying data to fill the
@@ -518,16 +554,110 @@ impl<'a> Unstructured<'a> {
         let elem_size = std::cmp::max(1, elem_size);
         let size = self.len() / elem_size;
         Ok(ArbitraryTakeRestIter {
             size,
             u: Some(self),
             _marker: PhantomData,
         })
     }
+
+    /// Call the given function an arbitrary number of times.
+    ///
+    /// The function is given this `Unstructured` so that it can continue to
+    /// generate arbitrary data and structures.
+    ///
+    /// You may optionaly specify minimum and maximum bounds on the number of
+    /// times the function is called.
+    ///
+    /// You may break out of the loop early by returning
+    /// `Ok(std::ops::ControlFlow::Break)`. To continue the loop, return
+    /// `Ok(std::ops::ControlFlow::Continue)`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `min > max`.
+    ///
+    /// # Example
+    ///
+    /// Call a closure that generates an arbitrary type inside a context an
+    /// arbitrary number of times:
+    ///
+    /// ```
+    /// use arbitrary::{Result, Unstructured};
+    /// use std::ops::ControlFlow;
+    ///
+    /// enum Type {
+    ///     /// A boolean type.
+    ///     Bool,
+    ///
+    ///     /// An integer type.
+    ///     Int,
+    ///
+    ///     /// A list of the `i`th type in this type's context.
+    ///     List(usize),
+    /// }
+    ///
+    /// fn arbitrary_types_context(u: &mut Unstructured) -> Result<Vec<Type>> {
+    ///     let mut context = vec![];
+    ///
+    ///     u.arbitrary_loop(Some(10), Some(20), |u| {
+    ///         let num_choices = if context.is_empty() {
+    ///             2
+    ///         } else {
+    ///             3
+    ///         };
+    ///         let ty = match u.int_in_range::<u8>(1..=num_choices)? {
+    ///             1 => Type::Bool,
+    ///             2 => Type::Int,
+    ///             3 => Type::List(u.int_in_range(0..=context.len() - 1)?),
+    ///             _ => unreachable!(),
+    ///         };
+    ///         context.push(ty);
+    ///         Ok(ControlFlow::Continue(()))
+    ///     })?;
+    ///
+    ///     // The number of loop iterations are constrained by the min/max
+    ///     // bounds that we provided.
+    ///     assert!(context.len() >= 10);
+    ///     assert!(context.len() <= 20);
+    ///
+    ///     Ok(context)
+    /// }
+    /// ```
+    pub fn arbitrary_loop(
+        &mut self,
+        min: Option<u32>,
+        max: Option<u32>,
+        mut f: impl FnMut(&mut Self) -> Result<ControlFlow<(), ()>>,
+    ) -> Result<()> {
+        let min = min.unwrap_or(0);
+        let max = max.unwrap_or(u32::MAX);
+        assert!(min <= max);
+
+        for _ in 0..min {
+            match f(self)? {
+                ControlFlow::Continue(_) => continue,
+                ControlFlow::Break(_) => return Ok(()),
+            }
+        }
+
+        for _ in 0..(max - min) {
+            let keep_going = self.arbitrary().unwrap_or(false);
+            if !keep_going {
+                break;
+            }
+            match f(self)? {
+                ControlFlow::Continue(_) => continue,
+                ControlFlow::Break(_) => break,
+            }
+        }
+
+        Ok(())
+    }
 }
 
 /// Utility iterator produced by [`Unstructured::arbitrary_iter`]
 pub struct ArbitraryIter<'a, 'b, ElementType> {
     u: &'b mut Unstructured<'a>,
     _marker: PhantomData<ElementType>,
 }
 
old mode 100644
new mode 100755
--- a/third_party/rust/arbitrary/tests/derive.rs
+++ b/third_party/rust/arbitrary/tests/derive.rs
@@ -159,17 +159,17 @@ struct OneLifetime<'a> {
 #[test]
 fn one_lifetime() {
     // Last byte is used for length
     let raw: Vec<u8> = vec![97, 98, 99, 100, 3];
     let lifetime: OneLifetime = arbitrary_from(&raw);
     assert_eq!("abc", lifetime.alpha);
 
     let (lower, upper) = <OneLifetime as Arbitrary>::size_hint(0);
-    assert_eq!(lower, 8);
+    assert_eq!(lower, std::mem::size_of::<usize>());
     assert_eq!(upper, None);
 }
 
 #[derive(Arbitrary, Debug)]
 struct TwoLifetimes<'a, 'b> {
     alpha: &'a str,
     beta: &'b str,
 }
@@ -178,11 +178,11 @@ struct TwoLifetimes<'a, 'b> {
 fn two_lifetimes() {
     // Last byte is used for length
     let raw: Vec<u8> = vec![97, 98, 99, 100, 101, 102, 103, 3];
     let lifetime: TwoLifetimes = arbitrary_from(&raw);
     assert_eq!("abc", lifetime.alpha);
     assert_eq!("def", lifetime.beta);
 
     let (lower, upper) = <TwoLifetimes as Arbitrary>::size_hint(0);
-    assert_eq!(lower, 16);
+    assert_eq!(lower, std::mem::size_of::<usize>() * 2);
     assert_eq!(upper, None);
 }
--- a/third_party/rust/async-trait/.cargo-checksum.json
+++ b/third_party/rust/async-trait/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"9168c83306a2940b86790578d9d72c23d70bad572bf67ad3def2c8265bd0c270","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"b733a7cddbdc409fcd5fb8eff5fe1d5692b6d1e0364568366a69bb1dd68e232c","build.rs":"e2ca6b6c6f18d5d47cb662083856d1399946bc41a272b30231c31ae8317a3ed0","src/args.rs":"6eed5497db91752b3aae597943c39e769f60406b37055304e69e4699f1f87b15","src/expand.rs":"f1002235c33fc292e6784937c2c64d6e7ba105147b9a82126c830d09b86c1059","src/lib.rs":"51cd49b85c0a7662ef32f30631f1f6a2ce448f18e951725b9d13227b5a596d3e","src/lifetime.rs":"4b94740e2847ef8df128a25d264f0a1bc1d1723ea107fc53849322b98f1e6927","src/parse.rs":"cd9032fe2c6dcf41050b3a59b9fb98eb9700a29bbe2fa011ee2854014c1666b7","src/receiver.rs":"31f5ff929bb6ac061ca3f44d4efac1ca0c60273d54ef8f8f92234a69829dc88d","tests/compiletest.rs":"0a52a44786aea1c299c695bf948b2ed2081e4cc344e5c2cadceab4eb03d0010d","tests/executor/mod.rs":"3cf48614288715f625514a73ae642f649c2635a402a3ad90278bbee116a7234c","tests/test.rs":"df12d6551ce0a8e3416f83fe92686ab2a22fb0a5dadb45499f531c8822c63c3e","tests/ui/bare-trait-object.rs":"4546e8bd6682de11920fa4c768295fed61954484ef0550dfadbc5677b77f29a5","tests/ui/bare-trait-object.stderr":"1df5569f4615620172affeaa86da629623f32a0bb15f790a10c0837bd9da27e6","tests/ui/delimiter-span.rs":"97edf38c804d5e0d4cef6f040dee113d78ff76b08bf8c49586b803caa3ce7f40","tests/ui/delimiter-span.stderr":"0f70f0bda0e86a43e6d6f6980f1ef8a1989c3e32db593bd60f920025a25728d5","tests/ui/lifetime-span.rs":"263de0b98abd0772fe9dc73ced1a71a3b85efb90d2b208226fe35ab9378c5e5a","tests/ui/lifetime-span.stderr":"21ce55872b2a6d57077ada797a5c3ae78a3d218570605a7509951b45afa212b3","tests/ui/missing-async-in-impl.rs":"5a5538d08d11c145211a92af0d8973eee8b21f33b90adda85430805bd3dbbc83","tests/ui/missing-async-in-impl.stderr":"2916bc8a51e25f4dd18eaf433b916d533943eac2c1afbee64e9a89e7b928040d","tests/ui/missing-async-in-trait.rs":"dc67241593f270233ba885df92e59164126416e68d49d8d62edc251666b5db6e","tests/ui/missing-async-in-trait.stderr":"67e66e7b19358830deff3ba01f5d701a9ae05c4e6fa9c081c49c1c75efbb7ade","tests/ui/missing-body.rs":"d06c0da8c6044e7c790b924136f167e2edc0d0d3fa01f23521f3f08ca605929b","tests/ui/missing-body.stderr":"e5ee994398bf8294324d61df02467a4229f68f4113bf5acc004851c03d66ec6a","tests/ui/must-use.rs":"75090c7df984df0996464337f60371d198bd0caf3f9f44b10d1e131f15fd4fca","tests/ui/must-use.stderr":"cd7bf2fe9023021837b2b3e8cc164ffc18900b01cf704c68cde91edd07d65dc8","tests/ui/self-span.rs":"67ddde05907d7014bfb3f2c63d427b1d72d6c4369a9108a4335dac6bee5832b2","tests/ui/self-span.stderr":"7865153d1e41ecdfa64b197901e3bda57bcda0c486bbcf11dc6e9837ceb40b29","tests/ui/send-not-implemented.rs":"affbbe8bc9c3501d3db3a024e06daa9d076f1d142dba290c7aa1ea119daebd19","tests/ui/send-not-implemented.stderr":"01e6800bcabca87306c72269e38d1eac53ef1e8ad9951a9be052b97aff16364d","tests/ui/unreachable.rs":"be0aa7cc129fe42a1fbd85e36b3f08c6a2bd16c90ed2e33fc4c50e40ce085bcd","tests/ui/unreachable.stderr":"73beb71cb74076f2cb45485271de31658cf59f4143e62daa34b9f2a8980ddfcd","tests/ui/unsupported-self.rs":"f7855bc39dab1fd2f533fb2e873a27c3757dcb9fb57001e4b19f58d3dda36d01","tests/ui/unsupported-self.stderr":"64fc5d45cb51330f0a1e85e69a28b69ddda12a109aa6a8ba3eaee1ac58d93b5f"},"package":"061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3"}
\ No newline at end of file
+{"files":{"Cargo.toml":"76c6c7291c8f5b93835ca4f91959f1dd4f85b53316b8de38d46cb571284c88a0","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"b733a7cddbdc409fcd5fb8eff5fe1d5692b6d1e0364568366a69bb1dd68e232c","build.rs":"e2ca6b6c6f18d5d47cb662083856d1399946bc41a272b30231c31ae8317a3ed0","src/args.rs":"6eed5497db91752b3aae597943c39e769f60406b37055304e69e4699f1f87b15","src/expand.rs":"9d3e3c0b810ec679c6caaf5b8c03f36081ec3dea73e46847d83cade4a4c05a8e","src/lib.rs":"51cd49b85c0a7662ef32f30631f1f6a2ce448f18e951725b9d13227b5a596d3e","src/lifetime.rs":"4b94740e2847ef8df128a25d264f0a1bc1d1723ea107fc53849322b98f1e6927","src/parse.rs":"cd9032fe2c6dcf41050b3a59b9fb98eb9700a29bbe2fa011ee2854014c1666b7","src/receiver.rs":"31f5ff929bb6ac061ca3f44d4efac1ca0c60273d54ef8f8f92234a69829dc88d","tests/compiletest.rs":"0a52a44786aea1c299c695bf948b2ed2081e4cc344e5c2cadceab4eb03d0010d","tests/executor/mod.rs":"3cf48614288715f625514a73ae642f649c2635a402a3ad90278bbee116a7234c","tests/test.rs":"df12d6551ce0a8e3416f83fe92686ab2a22fb0a5dadb45499f531c8822c63c3e","tests/ui/bare-trait-object.rs":"4546e8bd6682de11920fa4c768295fed61954484ef0550dfadbc5677b77f29a5","tests/ui/bare-trait-object.stderr":"1978b5afb37c55092b96bb68293f06c924fe82f0a4149e6eda94bbe2c031ee0b","tests/ui/consider-restricting.rs":"bff794222d9324241155568d541e7beac0238b66ce14039b242d4392f4e531b6","tests/ui/consider-restricting.stderr":"a153c5c67905875e5e333ce2ffc7167c75fbe1f258ca985636a15e479821bd72","tests/ui/delimiter-span.rs":"97edf38c804d5e0d4cef6f040dee113d78ff76b08bf8c49586b803caa3ce7f40","tests/ui/delimiter-span.stderr":"0f70f0bda0e86a43e6d6f6980f1ef8a1989c3e32db593bd60f920025a25728d5","tests/ui/lifetime-span.rs":"bbcaa92c2bc08e18cf0c7e9ca1f0bd8080772ebde8b067d819eb2fd662e47b3b","tests/ui/lifetime-span.stderr":"429ef1b63a242b71a904e7a277bb66baf0c600c10eb3c792b380a24e2eca074f","tests/ui/missing-async-in-impl.rs":"5a5538d08d11c145211a92af0d8973eee8b21f33b90adda85430805bd3dbbc83","tests/ui/missing-async-in-impl.stderr":"2916bc8a51e25f4dd18eaf433b916d533943eac2c1afbee64e9a89e7b928040d","tests/ui/missing-async-in-trait.rs":"dc67241593f270233ba885df92e59164126416e68d49d8d62edc251666b5db6e","tests/ui/missing-async-in-trait.stderr":"67e66e7b19358830deff3ba01f5d701a9ae05c4e6fa9c081c49c1c75efbb7ade","tests/ui/missing-body.rs":"d06c0da8c6044e7c790b924136f167e2edc0d0d3fa01f23521f3f08ca605929b","tests/ui/missing-body.stderr":"e5ee994398bf8294324d61df02467a4229f68f4113bf5acc004851c03d66ec6a","tests/ui/must-use.rs":"75090c7df984df0996464337f60371d198bd0caf3f9f44b10d1e131f15fd4fca","tests/ui/must-use.stderr":"cd7bf2fe9023021837b2b3e8cc164ffc18900b01cf704c68cde91edd07d65dc8","tests/ui/self-span.rs":"67ddde05907d7014bfb3f2c63d427b1d72d6c4369a9108a4335dac6bee5832b2","tests/ui/self-span.stderr":"7865153d1e41ecdfa64b197901e3bda57bcda0c486bbcf11dc6e9837ceb40b29","tests/ui/send-not-implemented.rs":"affbbe8bc9c3501d3db3a024e06daa9d076f1d142dba290c7aa1ea119daebd19","tests/ui/send-not-implemented.stderr":"cbe2fefbb02dd9207fb6b459549d626dc51a1aff3ce105c212bc7c07a876ab1a","tests/ui/unreachable.rs":"be0aa7cc129fe42a1fbd85e36b3f08c6a2bd16c90ed2e33fc4c50e40ce085bcd","tests/ui/unreachable.stderr":"73beb71cb74076f2cb45485271de31658cf59f4143e62daa34b9f2a8980ddfcd","tests/ui/unsupported-self.rs":"f7855bc39dab1fd2f533fb2e873a27c3757dcb9fb57001e4b19f58d3dda36d01","tests/ui/unsupported-self.stderr":"64fc5d45cb51330f0a1e85e69a28b69ddda12a109aa6a8ba3eaee1ac58d93b5f"},"package":"ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600"}
\ No newline at end of file
--- a/third_party/rust/async-trait/Cargo.toml
+++ b/third_party/rust/async-trait/Cargo.toml
@@ -8,38 +8,44 @@
 # If you are reading this file be aware that the original Cargo.toml
 # will likely look very different (and much more reasonable).
 # See Cargo.toml.orig for the original contents.
 
 [package]
 edition = "2018"
 rust-version = "1.39"
 name = "async-trait"
-version = "0.1.52"
+version = "0.1.53"
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 description = "Type erasure for async trait methods"
 documentation = "https://docs.rs/async-trait"
 readme = "README.md"
 keywords = ["async"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/dtolnay/async-trait"
+
 [package.metadata.docs.rs]
 targets = ["x86_64-unknown-linux-gnu"]
 
 [lib]
 proc-macro = true
+
 [dependencies.proc-macro2]
 version = "1.0"
 
 [dependencies.quote]
 version = "1.0"
 
 [dependencies.syn]
-version = "1.0.61"
-features = ["full", "visit-mut"]
+version = "1.0.84"
+features = [
+    "full",
+    "visit-mut",
+]
+
 [dev-dependencies.futures]
 version = "0.3"
 
 [dev-dependencies.rustversion]
 version = "1.0"
 
 [dev-dependencies.tracing]
 version = "0.1.14"
--- a/third_party/rust/async-trait/src/expand.rs
+++ b/third_party/rust/async-trait/src/expand.rs
@@ -1,28 +1,23 @@
 use crate::lifetime::CollectLifetimes;
 use crate::parse::Item;
 use crate::receiver::{has_self_in_block, has_self_in_sig, mut_pat, ReplaceSelf};
 use proc_macro2::TokenStream;
 use quote::{format_ident, quote, quote_spanned, ToTokens};
 use std::collections::BTreeSet as Set;
+use std::mem;
 use syn::punctuated::Punctuated;
 use syn::visit_mut::{self, VisitMut};
 use syn::{
-    parse_quote, Attribute, Block, FnArg, GenericParam, Generics, Ident, ImplItem, Lifetime, Pat,
-    PatIdent, Receiver, ReturnType, Signature, Stmt, Token, TraitItem, Type, TypeParamBound,
-    TypePath, WhereClause,
+    parse_quote, parse_quote_spanned, Attribute, Block, FnArg, GenericParam, Generics, Ident,
+    ImplItem, Lifetime, LifetimeDef, Pat, PatIdent, Receiver, ReturnType, Signature, Stmt, Token,
+    TraitItem, Type, TypeParamBound, TypePath, WhereClause,
 };
 
-macro_rules! parse_quote_spanned {
-    ($span:expr=> $($t:tt)*) => {
-        syn::parse2(quote_spanned!($span=> $($t)*)).unwrap()
-    };
-}
-
 impl ToTokens for Item {
     fn to_tokens(&self, tokens: &mut TokenStream) {
         match self {
             Item::Trait(item) => item.to_tokens(tokens),
             Item::Impl(item) => item.to_tokens(tokens),
         }
     }
 }
@@ -35,27 +30,28 @@ enum Context<'a> {
     },
     Impl {
         impl_generics: &'a Generics,
         associated_type_impl_traits: &'a Set<Ident>,
     },
 }
 
 impl Context<'_> {
-    fn lifetimes<'a>(&'a self, used: &'a [Lifetime]) -> impl Iterator<Item = &'a GenericParam> {
+    fn lifetimes<'a>(&'a self, used: &'a [Lifetime]) -> impl Iterator<Item = &'a LifetimeDef> {
         let generics = match self {
             Context::Trait { generics, .. } => generics,
             Context::Impl { impl_generics, .. } => impl_generics,
         };
-        generics.params.iter().filter(move |param| {
+        generics.params.iter().filter_map(move |param| {
             if let GenericParam::Lifetime(param) = param {
-                used.contains(&param.lifetime)
-            } else {
-                false
+                if used.contains(&param.lifetime) {
+                    return Some(param);
+                }
             }
+            None
         })
     }
 }
 
 type Supertraits = Punctuated<TypeParamBound, Token![+]>;
 
 pub fn expand(input: &mut Item, is_local: bool) {
     match input {
@@ -179,41 +175,52 @@ fn transform_sig(
     let mut lifetimes = CollectLifetimes::new("'life", default_span);
     for arg in sig.inputs.iter_mut() {
         match arg {
             FnArg::Receiver(arg) => lifetimes.visit_receiver_mut(arg),
             FnArg::Typed(arg) => lifetimes.visit_type_mut(&mut arg.ty),
         }
     }
 
-    for param in sig
-        .generics
-        .params
-        .iter()
-        .chain(context.lifetimes(&lifetimes.explicit))
-    {
+    for param in &mut sig.generics.params {
         match param {
             GenericParam::Type(param) => {
-                let param = &param.ident;
-                let span = param.span();
+                let param_name = &param.ident;
+                let span = match param.colon_token.take() {
+                    Some(colon_token) => colon_token.span,
+                    None => param_name.span(),
+                };
+                let bounds = mem::replace(&mut param.bounds, Punctuated::new());
                 where_clause_or_default(&mut sig.generics.where_clause)
                     .predicates
-                    .push(parse_quote_spanned!(span=> #param: 'async_trait));
+                    .push(parse_quote_spanned!(span=> #param_name: 'async_trait + #bounds));
             }
             GenericParam::Lifetime(param) => {
-                let param = &param.lifetime;
-                let span = param.span();
+                let param_name = &param.lifetime;
+                let span = match param.colon_token.take() {
+                    Some(colon_token) => colon_token.span,
+                    None => param_name.span(),
+                };
+                let bounds = mem::replace(&mut param.bounds, Punctuated::new());
                 where_clause_or_default(&mut sig.generics.where_clause)
                     .predicates
-                    .push(parse_quote_spanned!(span=> #param: 'async_trait));
+                    .push(parse_quote_spanned!(span=> #param: 'async_trait + #bounds));
             }
             GenericParam::Const(_) => {}
         }
     }
 
+    for param in context.lifetimes(&lifetimes.explicit) {
+        let param = &param.lifetime;
+        let span = param.span();
+        where_clause_or_default(&mut sig.generics.where_clause)
+            .predicates
+            .push(parse_quote_spanned!(span=> #param: 'async_trait));
+    }
+
     if sig.generics.lt_token.is_none() {
         sig.generics.lt_token = Some(Token![<](sig.ident.span()));
     }
     if sig.generics.gt_token.is_none() {
         sig.generics.gt_token = Some(Token![>](sig.paren_token.span));
     }
 
     for elided in lifetimes.elided {
--- a/third_party/rust/async-trait/tests/ui/bare-trait-object.stderr
+++ b/third_party/rust/async-trait/tests/ui/bare-trait-object.stderr
@@ -1,13 +1,18 @@
 error: trait objects without an explicit `dyn` are deprecated
   --> tests/ui/bare-trait-object.rs:11:16
    |
 11 | impl Trait for Send + Sync {
-   |                ^^^^^^^^^^^ help: use `dyn`: `dyn Send + Sync`
+   |                ^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> tests/ui/bare-trait-object.rs:1:9
    |
 1  | #![deny(bare_trait_objects)]
    |         ^^^^^^^^^^^^^^^^^^
    = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+   |
+11 - impl Trait for Send + Sync {
+11 + impl Trait for dyn Send + Sync {
+   |
new file mode 100644
--- /dev/null
+++ b/third_party/rust/async-trait/tests/ui/consider-restricting.rs
@@ -0,0 +1,26 @@
+// https://github.com/rust-lang/rust/issues/93828
+
+use async_trait::async_trait;
+
+pub trait IntoUrl {}
+
+#[async_trait]
+pub trait ClientExt {
+    async fn publish<T: IntoUrl>(&self, url: T);
+}
+
+struct Client;
+
+#[async_trait]
+impl ClientExt for Client {
+    async fn publish<T: IntoUrl>(&self, url: T) {}
+}
+
+struct Client2;
+
+#[async_trait]
+impl ClientExt for Client2 {
+    async fn publish<T>(&self, url: T) {}
+}
+
+fn main() {}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/async-trait/tests/ui/consider-restricting.stderr
@@ -0,0 +1,33 @@
+error: future cannot be sent between threads safely
+  --> tests/ui/consider-restricting.rs:16:49
+   |
+16 |     async fn publish<T: IntoUrl>(&self, url: T) {}
+   |                                                 ^^ future created by async block is not `Send`
+   |
+note: captured value is not `Send`
+  --> tests/ui/consider-restricting.rs:16:41
+   |
+16 |     async fn publish<T: IntoUrl>(&self, url: T) {}
+   |                                         ^^^ has type `T` which is not `Send`
+   = note: required for the cast to the object type `dyn Future<Output = ()> + Send`
+help: consider further restricting this bound
+   |
+16 |     async fn publish<T: IntoUrl + std::marker::Send>(&self, url: T) {}
+   |                                 +++++++++++++++++++
+
+error: future cannot be sent between threads safely
+  --> tests/ui/consider-restricting.rs:23:40
+   |
+23 |     async fn publish<T>(&self, url: T) {}
+   |                                        ^^ future created by async block is not `Send`
+   |
+note: captured value is not `Send`
+  --> tests/ui/consider-restricting.rs:23:32
+   |
+23 |     async fn publish<T>(&self, url: T) {}
+   |                                ^^^ has type `T` which is not `Send`
+   = note: required for the cast to the object type `dyn Future<Output = ()> + Send`
+help: consider further restricting this bound
+   |
+23 |     async fn publish<T + std::marker::Send>(&self, url: T) {}
+   |                        +++++++++++++++++++
--- a/third_party/rust/async-trait/tests/ui/lifetime-span.rs
+++ b/third_party/rust/async-trait/tests/ui/lifetime-span.rs
@@ -5,32 +5,32 @@ struct B;
 
 #[async_trait]
 pub trait Trait<'r> {
     async fn method(&'r self);
 }
 
 #[async_trait]
 impl Trait for A {
-    async fn method(&self) { }
+    async fn method(&self) {}
 }
 
 #[async_trait]
 impl<'r> Trait<'r> for B {
-    async fn method(&self) { }
+    async fn method(&self) {}
 }
 
 #[async_trait]
 pub trait Trait2 {
     async fn method<'r>(&'r self);
 }
 
 #[async_trait]
 impl Trait2 for A {
-    async fn method(&self) { }
+    async fn method(&self) {}
 }
 
 #[async_trait]
 impl<'r> Trait2<'r> for B {
-    async fn method(&'r self) { }
+    async fn method(&'r self) {}
 }
 
 fn main() {}
--- a/third_party/rust/async-trait/tests/ui/lifetime-span.stderr
+++ b/third_party/rust/async-trait/tests/ui/lifetime-span.stderr
@@ -14,35 +14,8 @@ 32 | impl<'r> Trait2<'r> for B {
    |          |
    |          expected 0 lifetime arguments
    |
 note: trait defined here, with 0 lifetime parameters
   --> tests/ui/lifetime-span.rs:22:11
    |
 22 | pub trait Trait2 {
    |           ^^^^^^
-
-error[E0195]: lifetime parameters or bounds on method `method` do not match the trait declaration
-  --> tests/ui/lifetime-span.rs:13:14
-   |
-8  |     async fn method(&'r self);
-   |              ---------------- lifetimes in impl do not match this method in trait
-...
-13 |     async fn method(&self) { }
-   |              ^^^^^^^^^^^^^ lifetimes do not match method in trait
-
-error[E0195]: lifetime parameters or bounds on method `method` do not match the trait declaration
-  --> tests/ui/lifetime-span.rs:18:14
-   |
-8  |     async fn method(&'r self);
-   |              ---------------- lifetimes in impl do not match this method in trait
-...
-18 |     async fn method(&self) { }
-   |              ^^^^^^^^^^^^^ lifetimes do not match method in trait
-
-error[E0195]: lifetime parameters or bounds on method `method` do not match the trait declaration
-  --> tests/ui/lifetime-span.rs:33:14
-   |
-23 |     async fn method<'r>(&'r self);
-   |                    ---- lifetimes in impl do not match this method in trait
-...
-33 |     async fn method(&'r self) { }
-   |              ^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
--- a/third_party/rust/async-trait/tests/ui/send-not-implemented.stderr
+++ b/third_party/rust/async-trait/tests/ui/send-not-implemented.stderr
@@ -4,44 +4,44 @@ error: future cannot be sent between thr
 8  |       async fn test(&self) {
    |  __________________________^
 9  | |         let mutex = Mutex::new(());
 10 | |         let _guard = mutex.lock().unwrap();
 11 | |         f().await;
 12 | |     }
    | |_____^ future created by async block is not `Send`
    |
-   = help: within `impl Future<Output = [async output]>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
+   = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
 note: future is not `Send` as this value is used across an await
-  --> tests/ui/send-not-implemented.rs:11:9
+  --> tests/ui/send-not-implemented.rs:11:12
    |
 10 |         let _guard = mutex.lock().unwrap();
    |             ------ has type `MutexGuard<'_, ()>` which is not `Send`
 11 |         f().await;
-   |         ^^^^^^^^^ await occurs here, with `_guard` maybe used later
+   |            ^^^^^^ await occurs here, with `_guard` maybe used later
 12 |     }
    |     - `_guard` is later dropped here
    = note: required for the cast to the object type `dyn Future<Output = ()> + Send`
 
 error: future cannot be sent between threads safely
   --> tests/ui/send-not-implemented.rs:14:38
    |
 14 |       async fn test_ret(&self) -> bool {
    |  ______________________________________^
 15 | |         let mutex = Mutex::new(());
 16 | |         let _guard = mutex.lock().unwrap();
 17 | |         f().await;
 18 | |         true
 19 | |     }
    | |_____^ future created by async block is not `Send`
    |
-   = help: within `impl Future<Output = [async output]>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
+   = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
 note: future is not `Send` as this value is used across an await
-  --> tests/ui/send-not-implemented.rs:17:9
+  --> tests/ui/send-not-implemented.rs:17:12
    |
 16 |         let _guard = mutex.lock().unwrap();
    |             ------ has type `MutexGuard<'_, ()>` which is not `Send`
 17 |         f().await;
-   |         ^^^^^^^^^ await occurs here, with `_guard` maybe used later
+   |            ^^^^^^ await occurs here, with `_guard` maybe used later
 18 |         true
 19 |     }
    |     - `_guard` is later dropped here
    = note: required for the cast to the object type `dyn Future<Output = bool> + Send`
--- a/third_party/rust/bitreader/.cargo-checksum.json
+++ b/third_party/rust/bitreader/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"28a1d4b7f04f3989f856789ec569d890a91b9dfdc8775ff8cbd4e0c1b2f8f9f2","LICENSE-APACHE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","LICENSE-MIT":"8583712ee2b062ff3d4d6d3e16f19ff0f92bc3a0a4beeec11a81ef00146fbd4f","README.md":"28986de2e8d457e76ae3303d80094697e6ef4ad8da06a4a3178bb1b52bff63d5","src/lib.rs":"250d841ee01b90209c6c4ad304969de145287c6c6588850b95e6f843ec4dd579","src/tests.rs":"5e62c77cfa155fd8affa8ff3c7ea688d80bce6f4956f9956582775ae3adca1a6"},"package":"bd5bf8a17cdc06d475689f9e9226f4b5bf5610e93cf5c3010a518fe6fb0d97f5"}
\ No newline at end of file
+{"files":{"Cargo.toml":"40cf98620ffea71407e2eee1026313c8e2576598c46186d8e7ba00279b5543a6","LICENSE-APACHE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","LICENSE-MIT":"8583712ee2b062ff3d4d6d3e16f19ff0f92bc3a0a4beeec11a81ef00146fbd4f","README.md":"28986de2e8d457e76ae3303d80094697e6ef4ad8da06a4a3178bb1b52bff63d5","src/lib.rs":"6e9c5c337f2503dbd6f505a68bd07386da0421d18f757fab0eec8fd4de29b927","src/tests.rs":"bffb5a76bdc03845a51541b005d23f19a685846cb8311d13777ee71e0b86c56e"},"package":"d84ea71c85d1fe98fe67a9b9988b1695bc24c0b0d3bfb18d4c510f44b4b09941"}
\ No newline at end of file
--- a/third_party/rust/bitreader/Cargo.toml
+++ b/third_party/rust/bitreader/Cargo.toml
@@ -6,17 +6,17 @@
 # to registry (e.g., crates.io) dependencies.
 #
 # If you are reading this file be aware that the original Cargo.toml
 # will likely look very different (and much more reasonable).
 # See Cargo.toml.orig for the original contents.
 
 [package]
 name = "bitreader"
-version = "0.3.5"
+version = "0.3.6"
 authors = ["Ilkka Rauta <ilkka.rauta@gmail.com>"]
 description = "BitReader helps reading individual bits from a slice of bytes.\n\nYou can read \"unusual\" numbers of bits from the byte slice, for example 13 bits\nat once. The reader internally keeps track of position within the buffer.\n"
 homepage = "https://github.com/irauta/bitreader"
 documentation = "https://docs.rs/bitreader"
 keywords = ["bit", "bits", "bitstream"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/irauta/bitreader"
 [dependencies.cfg-if]
--- a/third_party/rust/bitreader/src/lib.rs
+++ b/third_party/rust/bitreader/src/lib.rs
@@ -309,16 +309,19 @@ impl<'a> BitReader<'a> {
     pub fn align(&mut self, alignment_bytes: u32) -> Result<()> {
         let alignment_bits = alignment_bytes as u64 * 8;
         let cur_alignment = self.position % alignment_bits;
         let bits_to_skip = (alignment_bits - cur_alignment) % alignment_bits;
         self.skip(bits_to_skip)
     }
 
     fn read_signed_value(&mut self, bit_count: u8, maximum_count: u8) -> Result<i64> {
+        if bit_count == 0 {
+            return Ok(0);
+        }
         let unsigned = self.read_value(bit_count, maximum_count)?;
         // Fill the bits above the requested bits with all ones or all zeros,
         // depending on the sign bit.
         let sign_bit = unsigned >> (bit_count - 1) & 1;
         let high_bits = if sign_bit == 1 { -1 } else { 0 };
         Ok(high_bits << bit_count | unsigned as i64)
     }
 
--- a/third_party/rust/bitreader/src/tests.rs
+++ b/third_party/rust/bitreader/src/tests.rs
@@ -163,16 +163,17 @@ fn skipping_and_zero_reads() {
         0b1011_0101, 0b1110_1010, 0b1010_1100, 0b0011_0101,
     ];
 
     let mut reader = BitReader::new(bytes);
 
     assert_eq!(reader.read_u8(4).unwrap(), 0b1011);
     // Reading zero bits should be a no-op
     assert_eq!(reader.read_u8(0).unwrap(), 0b0);
+    assert_eq!(reader.read_i8(0).unwrap(), 0b0);
     assert_eq!(reader.read_u8(4).unwrap(), 0b0101);
     reader.skip(3).unwrap(); // 0b111
     assert_eq!(reader.read_u16(10).unwrap(), 0b0101010101);
     assert_eq!(reader.read_u8(3).unwrap(), 0b100);
     reader.skip(4).unwrap(); // 0b0011
     assert_eq!(reader.read_u32(2).unwrap(), 0b01);
     assert_eq!(reader.read_bool().unwrap(), false);
     assert_eq!(reader.read_bool().unwrap(), true);
--- a/third_party/rust/cc/.cargo-checksum.json
+++ b/third_party/rust/cc/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.lock":"736676fe05045947d265711c82c531cb62cdf42b850a87450b4a64b8f67d2f6a","Cargo.toml":"08aaf8589bb95af4aa452ddd1a6ac3948eb1af09b104cd8b8d8d242757f9dad7","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"1fd66e1fe6d618030b9452c667e89d7a31b27331ad831d83b41f9762fd6858d4","src/bin/gcc-shim.rs":"b77907875029494b6288841c3aed2e4939ed40708c7f597fca5c9e2570490ca6","src/com.rs":"bcdaf1c28b71e6ef889c6b08d1ce9d7c0761344a677f523bc4c3cd297957f804","src/lib.rs":"c7c7502f8f1f2f383b54b8a87865c40afb5f9188cc843ba240751096ef21f0f1","src/registry.rs":"3cc1b5a50879fa751572878ae1d0afbfc960c11665258492754b2c8bccb0ff5d","src/setup_config.rs":"7014103587d3382eac599cb76f016e2609b8140970861b2237982d1db24af265","src/vs_instances.rs":"2d3f8278a803b0e7052f4eeb1979b29f963dd0143f4458e2cb5f33c4e5f0963b","src/winapi.rs":"ea8b7edbb9ff87957254f465c2334e714c5d6b3b19a8d757c48ea7ca0881c50c","src/windows_registry.rs":"605779eed30b3e4714457661707e21d99fbedbfab911f9a40afd4aa64ad135bb","tests/cc_env.rs":"e02b3b0824ad039b47e4462c5ef6dbe6c824c28e7953af94a0f28f7b5158042e","tests/cflags.rs":"57f06eb5ce1557e5b4a032d0c4673e18fbe6f8d26c1deb153126e368b96b41b3","tests/cxxflags.rs":"c2c6c6d8a0d7146616fa1caed26876ee7bc9fcfffd525eb4743593cade5f3371","tests/support/mod.rs":"16274867f23871e9b07614eda4c7344da13d1751fed63d4f633857e40be86394","tests/test.rs":"65c073e0e2cf4aa0433066102788e9f57442719e6f32f5ad5248aa7132bb4597"},"package":"22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"}
\ No newline at end of file
+{"files":{"Cargo.lock":"739aae86d1e7096fc84b9a6273cc49635503a4ee87b3a4b6601f569880866b29","Cargo.toml":"ccfa92dd53511178ef95aa87b2dcbdd45e23f9f8a8454e455d7da8e08feab4b5","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"1fd66e1fe6d618030b9452c667e89d7a31b27331ad831d83b41f9762fd6858d4","src/bin/gcc-shim.rs":"b77907875029494b6288841c3aed2e4939ed40708c7f597fca5c9e2570490ca6","src/com.rs":"bcdaf1c28b71e6ef889c6b08d1ce9d7c0761344a677f523bc4c3cd297957f804","src/lib.rs":"38970d678de0efb4b5e2978265daa8a613a1db35fc42e669621b03fc56d5b138","src/registry.rs":"3cc1b5a50879fa751572878ae1d0afbfc960c11665258492754b2c8bccb0ff5d","src/setup_config.rs":"7014103587d3382eac599cb76f016e2609b8140970861b2237982d1db24af265","src/vs_instances.rs":"2d3f8278a803b0e7052f4eeb1979b29f963dd0143f4458e2cb5f33c4e5f0963b","src/winapi.rs":"ea8b7edbb9ff87957254f465c2334e714c5d6b3b19a8d757c48ea7ca0881c50c","src/windows_registry.rs":"4645453198766c7486fc9b8782b06cfd0f94cbbcb3482413173e73234a447518","tests/cc_env.rs":"e02b3b0824ad039b47e4462c5ef6dbe6c824c28e7953af94a0f28f7b5158042e","tests/cflags.rs":"57f06eb5ce1557e5b4a032d0c4673e18fbe6f8d26c1deb153126e368b96b41b3","tests/cxxflags.rs":"c2c6c6d8a0d7146616fa1caed26876ee7bc9fcfffd525eb4743593cade5f3371","tests/support/mod.rs":"a3c8d116973bb16066bf6ec4de5143183f97de7aad085d85f8118a2eaac3e1e0","tests/test.rs":"65c073e0e2cf4aa0433066102788e9f57442719e6f32f5ad5248aa7132bb4597"},"package":"2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"}
\ No newline at end of file
--- a/third_party/rust/cc/Cargo.lock
+++ b/third_party/rust/cc/Cargo.lock
@@ -5,99 +5,60 @@ version = 3
 [[package]]
 name = "bitflags"
 version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "cc"
-version = "1.0.72"
+version = "1.0.73"
 dependencies = [
  "jobserver",
  "tempfile",
 ]
 
 [[package]]
 name = "cfg-if"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
-name = "getrandom"
-version = "0.2.3"
+name = "fastrand"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
+checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
+dependencies = [
+ "instant",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
 dependencies = [
  "cfg-if",
- "libc",
- "wasi",
 ]
 
 [[package]]
 name = "jobserver"
 version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa"
 dependencies = [
  "libc",
 ]
 
 [[package]]
 name = "libc"
-version = "0.2.107"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
-
-[[package]]
-name = "ppv-lite86"
-version = "0.2.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
-
-[[package]]
-name = "rand"
-version = "0.8.4"
+version = "0.2.118"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
-dependencies = [
- "libc",
- "rand_chacha",
- "rand_core",
- "rand_hc",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-dependencies = [
- "ppv-lite86",
- "rand_core",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
-dependencies = [
- "getrandom",
-]
-
-[[package]]
-name = "rand_hc"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
-dependencies = [
- "rand_core",
-]
+checksum = "06e509672465a0504304aa87f9f176f2b2b716ed8fb105ebe5c02dc6dce96a94"
 
 [[package]]
 name = "redox_syscall"
 version = "0.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
 dependencies = [
  "bitflags",
@@ -109,35 +70,29 @@ version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
 dependencies = [
  "winapi",
 ]
 
 [[package]]
 name = "tempfile"
-version = "3.2.0"
+version = "3.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
+checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
 dependencies = [
  "cfg-if",
+ "fastrand",
  "libc",
- "rand",
  "redox_syscall",
  "remove_dir_all",
  "winapi",
 ]
 
 [[package]]
-name = "wasi"
-version = "0.10.2+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
-
-[[package]]
 name = "winapi"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
 dependencies = [
  "winapi-i686-pc-windows-gnu",
  "winapi-x86_64-pc-windows-gnu",
 ]
--- a/third_party/rust/cc/Cargo.toml
+++ b/third_party/rust/cc/Cargo.toml
@@ -7,17 +7,17 @@
 #
 # If you are reading this file be aware that the original Cargo.toml
 # will likely look very different (and much more reasonable).
 # See Cargo.toml.orig for the original contents.
 
 [package]
 edition = "2018"
 name = "cc"
-version = "1.0.72"
+version = "1.0.73"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
 exclude = ["/.github", "/.travis.yml", "/appveyor.yml"]
 description = "A build-time dependency for Cargo build scripts to assist in invoking the native\nC compiler to compile native C code into a static archive to be linked into Rust\ncode.\n"
 homepage = "https://github.com/alexcrichton/cc-rs"
 documentation = "https://docs.rs/cc"
 readme = "README.md"
 keywords = ["build-dependencies"]
 categories = ["development-tools::build-utils"]
--- a/third_party/rust/cc/src/lib.rs
+++ b/third_party/rust/cc/src/lib.rs
@@ -57,17 +57,17 @@
 #![deny(missing_docs)]
 
 use std::collections::HashMap;
 use std::env;
 use std::ffi::{OsStr, OsString};
 use std::fmt::{self, Display};
 use std::fs;
 use std::io::{self, BufRead, BufReader, Read, Write};
-use std::path::{Path, PathBuf};
+use std::path::{Component, Path, PathBuf};
 use std::process::{Child, Command, Stdio};
 use std::sync::{Arc, Mutex};
 use std::thread::{self, JoinHandle};
 
 // These modules are all glue to support reading the MSVC version from
 // the registry and from COM interfaces
 #[cfg(windows)]
 mod registry;
@@ -134,16 +134,18 @@ enum ErrorKind {
     /// Invalid architecture supplied.
     ArchitectureInvalid,
     /// Environment variable not found, with the var in question as extra info.
     EnvVarNotFound,
     /// Error occurred while using external tools (ie: invocation of compiler).
     ToolExecError,
     /// Error occurred due to missing external tools.
     ToolNotFound,
+    /// One of the function arguments failed validation.
+    InvalidArgument,
 }
 
 /// Represents an internal error that occurred, with an explanation.
 #[derive(Clone, Debug)]
 pub struct Error {
     /// Describes the kind of error that occurred.
     kind: ErrorKind,
     /// More explanation of error that occurred.
@@ -403,28 +405,27 @@ impl Build {
     ///     .flag("-ffunction-sections")
     ///     .compile("foo");
     /// ```
     pub fn flag(&mut self, flag: &str) -> &mut Build {
         self.flags.push(flag.to_string());
         self
     }
 
-    /// Add an arbitrary flag to the invocation of the compiler
+    /// Add a flag to the invocation of the ar
     ///
     /// # Example
     ///
     /// ```no_run
     /// cc::Build::new()
     ///     .file("src/foo.c")
     ///     .file("src/bar.c")
     ///     .ar_flag("/NODEFAULTLIB:libc.dll")
     ///     .compile("foo");
     /// ```
-
     pub fn ar_flag(&mut self, flag: &str) -> &mut Build {
         self.ar_flags.push(flag.to_string());
         self
     }
 
     fn ensure_check_file(&self) -> Result<PathBuf, Error> {
         let out_dir = self.get_out_dir()?;
         let src = if self.cuda {
@@ -939,16 +940,27 @@ impl Build {
             .push((a.as_ref().to_owned(), b.as_ref().to_owned()));
         self
     }
 
     /// Run the compiler, generating the file `output`
     ///
     /// This will return a result instead of panicing; see compile() for the complete description.
     pub fn try_compile(&self, output: &str) -> Result<(), Error> {
+        let mut output_components = Path::new(output).components();
+        match (output_components.next(), output_components.next()) {
+            (Some(Component::Normal(_)), None) => {}
+            _ => {
+                return Err(Error::new(
+                    ErrorKind::InvalidArgument,
+                    "argument of `compile` must be a single normal path component",
+                ));
+            }
+        }
+
         let (lib_name, gnu_lib_name) = if output.starts_with("lib") && output.ends_with(".a") {
             (&output[3..output.len() - 2], output.to_owned())
         } else {
             let mut gnu = String::with_capacity(5 + output.len());
             gnu.push_str("lib");
             gnu.push_str(&output);
             gnu.push_str(".a");
             (output, gnu)
@@ -1062,20 +1074,45 @@ impl Build {
             }
         }
 
         Ok(())
     }
 
     /// Run the compiler, generating the file `output`
     ///
-    /// The name `output` should be the name of the library.  For backwards compatibility,
-    /// the `output` may start with `lib` and end with `.a`.  The Rust compiler will create
-    /// the assembly with the lib prefix and .a extension.  MSVC will create a file without prefix,
-    /// ending with `.lib`.
+    /// # Library name
+    ///
+    /// The `output` string argument determines the file name for the compiled
+    /// library. The Rust compiler will create an assembly named "lib"+output+".a".
+    /// MSVC will create a file named output+".lib".
+    ///
+    /// The choice of `output` is close to arbitrary, but:
+    ///
+    /// - must be nonempty,
+    /// - must not contain a path separator (`/`),
+    /// - must be unique across all `compile` invocations made by the same build
+    ///   script.
+    ///
+    /// If your build script compiles a single source file, the base name of
+    /// that source file would usually be reasonable:
+    ///
+    /// ```no_run
+    /// cc::Build::new().file("blobstore.c").compile("blobstore");
+    /// ```
+    ///
+    /// Compiling multiple source files, some people use their crate's name, or
+    /// their crate's name + "-cc".
+    ///
+    /// Otherwise, please use your imagination.
+    ///
+    /// For backwards compatibility, if `output` starts with "lib" *and* ends
+    /// with ".a", a second "lib" prefix and ".a" suffix do not get added on,
+    /// but this usage is deprecated; please omit `lib` and `.a` in the argument
+    /// that you pass.
     ///
     /// # Panics
     ///
     /// Panics if `output` is not formatted correctly or if one of the underlying
     /// compiler commands fails. It can also panic if it fails reading file names
     /// or creating directories.
     pub fn compile(&self, output: &str) {
         if let Err(e) = self.try_compile(output) {
@@ -1561,16 +1598,18 @@ impl Build {
                         cmd.args.push(
                             format!("--target={}", target.replace("riscv32gc", "riscv32")).into(),
                         );
                     } else if target.contains("uefi") {
                         if target.contains("x86_64") {
                             cmd.args.push("--target=x86_64-unknown-windows-gnu".into());
                         } else if target.contains("i686") {
                             cmd.args.push("--target=i686-unknown-windows-gnu".into())
+                        } else if target.contains("aarch64") {
+                            cmd.args.push("--target=aarch64-unknown-windows-gnu".into())
                         }
                     } else {
                         cmd.args.push(format!("--target={}", target).into());
                     }
                 }
             }
             ToolFamily::Msvc { clang_cl } => {
                 // This is an undocumented flag from MSVC but helps with making
@@ -1783,16 +1822,22 @@ impl Build {
                 if target.starts_with("riscv32") || target.starts_with("riscv64") {
                     // get the 32i/32imac/32imc/64gc/64imac/... part
                     let mut parts = target.split('-');
                     if let Some(arch) = parts.next() {
                         let arch = &arch[5..];
                         if target.contains("linux") && arch.starts_with("64") {
                             cmd.args.push(("-march=rv64gc").into());
                             cmd.args.push("-mabi=lp64d".into());
+                        } else if target.contains("freebsd") && arch.starts_with("64") {
+                            cmd.args.push(("-march=rv64gc").into());
+                            cmd.args.push("-mabi=lp64d".into());
+                        } else if target.contains("openbsd") && arch.starts_with("64") {
+                            cmd.args.push(("-march=rv64gc").into());
+                            cmd.args.push("-mabi=lp64d".into());
                         } else if target.contains("linux") && arch.starts_with("32") {
                             cmd.args.push(("-march=rv32gc").into());
                             cmd.args.push("-mabi=ilp32d".into());
                         } else if arch.starts_with("64") {
                             cmd.args.push(("-march=rv".to_owned() + arch).into());
                             cmd.args.push("-mabi=lp64".into());
                         } else {
                             cmd.args.push(("-march=rv".to_owned() + arch).into());
@@ -2496,16 +2541,18 @@ impl Build {
 
     fn prefix_for_target(&self, target: &str) -> Option<String> {
         // CROSS_COMPILE is of the form: "arm-linux-gnueabi-"
         let cc_env = self.getenv("CROSS_COMPILE");
         let cross_compile = cc_env
             .as_ref()
             .map(|s| s.trim_right_matches('-').to_owned());
         cross_compile.or(match &target[..] {
+            "aarch64-pc-windows-gnu" => Some("aarch64-w64-mingw32"),
+            "aarch64-uwp-windows-gnu" => Some("aarch64-w64-mingw32"),
             "aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu"),
             "aarch64-unknown-linux-musl" => Some("aarch64-linux-musl"),
             "aarch64-unknown-netbsd" => Some("aarch64--netbsd"),
             "arm-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"),
             "armv4t-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"),
             "armv5te-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"),
             "armv5te-unknown-linux-musleabi" => Some("arm-linux-gnueabi"),
             "arm-frc-linux-gnueabi" => Some("arm-frc-linux-gnueabi"),
--- a/third_party/rust/cc/src/windows_registry.rs
+++ b/third_party/rust/cc/src/windows_registry.rs
@@ -129,17 +129,19 @@ pub fn find_vs_version() -> Result<VsVer
                  crate\n\
                  ",
                 vers
             )),
         },
         _ => {
             // Check for the presence of a specific registry key
             // that indicates visual studio is installed.
-            if impl_::has_msbuild_version("16.0") {
+            if impl_::has_msbuild_version("17.0") {
+                Ok(VsVers::Vs17)
+            } else if impl_::has_msbuild_version("16.0") {
                 Ok(VsVers::Vs16)
             } else if impl_::has_msbuild_version("15.0") {
                 Ok(VsVers::Vs15)
             } else if impl_::has_msbuild_version("14.0") {
                 Ok(VsVers::Vs14)
             } else if impl_::has_msbuild_version("12.0") {
                 Ok(VsVers::Vs12)
             } else {
@@ -245,37 +247,41 @@ mod impl_ {
                     env::split_paths(&path)
                         .map(|p| p.join(tool))
                         .find(|p| p.exists())
                 })
                 .map(|path| Tool::with_family(path.into(), MSVC_FAMILY))
         }
     }
 
+    fn find_msbuild_vs17(target: &str) -> Option<Tool> {
+        find_tool_in_vs16plus_path(r"MSBuild\Current\Bin\MSBuild.exe", target, "17")
+    }
+
     #[allow(bare_trait_objects)]
-    fn vs16_instances(target: &str) -> Box<Iterator<Item = PathBuf>> {
+    fn vs16plus_instances(target: &str, version: &'static str) -> Box<Iterator<Item = PathBuf>> {
         let instances = if let Some(instances) = vs15plus_instances(target) {
             instances
         } else {
             return Box::new(iter::empty());
         };
-        Box::new(instances.into_iter().filter_map(|instance| {
+        Box::new(instances.into_iter().filter_map(move |instance| {
             let installation_name = instance.installation_name()?;
-            if installation_name.starts_with("VisualStudio/16.") {
+            if installation_name.starts_with(&format!("VisualStudio/{}.", version)) {
                 Some(instance.installation_path()?)
-            } else if installation_name.starts_with("VisualStudioPreview/16.") {
+            } else if installation_name.starts_with(&format!("VisualStudioPreview/{}.", version)) {
                 Some(instance.installation_path()?)
             } else {
                 None
             }
         }))
     }
 
-    fn find_tool_in_vs16_path(tool: &str, target: &str) -> Option<Tool> {
-        vs16_instances(target)
+    fn find_tool_in_vs16plus_path(tool: &str, target: &str, version: &'static str) -> Option<Tool> {
+        vs16plus_instances(target, version)
             .filter_map(|path| {
                 let path = path.join(tool);
                 if !path.is_file() {
                     return None;
                 }
                 let mut tool = Tool::with_family(path, MSVC_FAMILY);
                 if target.contains("x86_64") {
                     tool.env.push(("Platform".into(), "X64".into()));
@@ -284,17 +290,17 @@ mod impl_ {
                     tool.env.push(("Platform".into(), "ARM64".into()));
                 }
                 Some(tool)
             })
             .next()
     }
 
     fn find_msbuild_vs16(target: &str) -> Option<Tool> {
-        find_tool_in_vs16_path(r"MSBuild\Current\Bin\MSBuild.exe", target)
+        find_tool_in_vs16plus_path(r"MSBuild\Current\Bin\MSBuild.exe", target, "16")
     }
 
     // In MSVC 15 (2017) MS once again changed the scheme for locating
     // the tooling.  Now we must go through some COM interfaces, which
     // is super fun for Rust.
     //
     // Note that much of this logic can be found [online] wrt paths, COM, etc.
     //
@@ -658,17 +664,25 @@ mod impl_ {
     // Vcvars finds the correct version of the Windows 10 SDK by looking
     // for the include `um\Windows.h` because sometimes a given version will
     // only have UCRT bits without the rest of the SDK. Since we only care about
     // libraries and not includes, we instead look for `um\x64\kernel32.lib`.
     // Since the 32-bit and 64-bit libraries are always installed together we
     // only need to bother checking x64, making this code a tiny bit simpler.
     // Like we do for the Universal CRT, we sort the possibilities
     // asciibetically to find the newest one as that is what vcvars does.
+    // Before doing that, we check the "WindowsSdkDir" and "WindowsSDKVersion"
+    // environment variables set by vcvars to use the environment sdk version
+    // if one is already configured.
     fn get_sdk10_dir() -> Option<(PathBuf, String)> {
+        if let (Ok(root), Ok(version)) = (env::var("WindowsSdkDir"), env::var("WindowsSDKVersion"))
+        {
+            return Some((root.into(), version.trim_end_matches('\\').to_string()));
+        }
+
         let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0";
         let key = LOCAL_MACHINE.open(key.as_ref()).ok()?;
         let root = key.query_str("InstallationFolder").ok()?;
         let readdir = Path::new(&root).join("lib").read_dir().ok()?;
         let mut dirs = readdir
             .filter_map(|dir| dir.ok())
             .map(|dir| dir.path())
             .collect::<Vec<_>>();
@@ -811,16 +825,21 @@ mod impl_ {
                 }
             }
         }
         max_key
     }
 
     pub fn has_msbuild_version(version: &str) -> bool {
         match version {
+            "17.0" => {
+                find_msbuild_vs17("x86_64-pc-windows-msvc").is_some()
+                    || find_msbuild_vs17("i686-pc-windows-msvc").is_some()
+                    || find_msbuild_vs17("aarch64-pc-windows-msvc").is_some()
+            }
             "16.0" => {
                 find_msbuild_vs16("x86_64-pc-windows-msvc").is_some()
                     || find_msbuild_vs16("i686-pc-windows-msvc").is_some()
                     || find_msbuild_vs16("aarch64-pc-windows-msvc").is_some()
             }
             "15.0" => {
                 find_msbuild_vs15("x86_64-pc-windows-msvc").is_some()
                     || find_msbuild_vs15("i686-pc-windows-msvc").is_some()
--- a/third_party/rust/cc/tests/support/mod.rs
+++ b/third_party/rust/cc/tests/support/mod.rs
@@ -57,23 +57,22 @@ impl Test {
     pub fn msvc() -> Test {
         let mut t = Test::new();
         t.shim("cl").shim("lib.exe");
         t.msvc = true;
         t
     }
 
     pub fn shim(&self, name: &str) -> &Test {
-        link_or_copy(
-            &self.gcc,
-            self.td
-                .path()
-                .join(&format!("{}{}", name, env::consts::EXE_SUFFIX)),
-        )
-        .unwrap();
+        let name = if name.ends_with(env::consts::EXE_SUFFIX) {
+            name.to_string()
+        } else {
+            format!("{}{}", name, env::consts::EXE_SUFFIX)
+        };
+        link_or_copy(&self.gcc, self.td.path().join(name)).unwrap();
         self
     }
 
     pub fn gcc(&self) -> cc::Build {
         let mut cfg = cc::Build::new();
         let target = if self.msvc {
             "x86_64-pc-windows-msvc"
         } else {
--- a/third_party/rust/clang-sys/.cargo-checksum.json
+++ b/third_party/rust/clang-sys/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"CHANGELOG.md":"5a817afc62824048b58af813e5cc6f57bef3def54aef7e1e057d31bec4db300a","Cargo.toml":"4a414d9fb6d427e81408464f42d9e780878b573ed9fd7839d0b5e98fd29f98ce","LICENSE.txt":"3ddf9be5c28fe27dad143a5dc76eea25222ad1dd68934a047064e56ed2fa40c5","README.md":"e1800b83d40b2fe14cee9cf97bdd1e28c1578f30ce946f342321dbcd31e17874","build.rs":"2693b9519440c2341fe51e8eef4ca63de31a93cadc30366e25788e8c3ed0a29a","build/common.rs":"2f2e7de6558d082e6a15549ee9cbce33ed2d31c9622d7d75be6219ff2caa1592","build/dynamic.rs":"566947dce3bacbd1886436134553a0d2a0e377d2fcfd13b06e02a032d3a7f294","build/static.rs":"3cd6931224c2c7b95c03d20c461aff4c1e24ca077647f203f0165626205a4179","clippy.toml":"fcf54943ba571514b244cc098ce08671b4117167733e8107e799d533a12a2195","src/lib.rs":"4bb3b7cf4e31f9b0dc4e9318551531b3a66abe0c07239d6b12aca09d13e664aa","src/link.rs":"38834f7f3e6327b5d94f00c148ab24ba4e89bdfbc219f54690b4a2d9efb23f7b","src/support.rs":"c1fc9bc8f5baf494b0709c5722d8c9e45987323311f54382764fff8c03d8112c","tests/header.h":"1b15a686d1c06561960045a26c25a34d840f26c8246f2f5e630f993b69c7492c","tests/lib.rs":"81a459e9f48e6d384b3fd61e7942e685f7ea39af6574bc2b382a0fbe7820ff65"},"package":"fa66045b9cb23c2e9c1520732030608b02ee07e5cfaa5a521ec15ded7fa24c90"}
\ No newline at end of file
+{"files":{"CHANGELOG.md":"499c57eade3c5b157a5f36412f723aa86da1cf805d330e9c1e5a2bbb85a9f2c7","Cargo.toml":"54313f3bb32a6cc6f65c6fc6e43ca79e0f2599f4d6f28a8410c348721dd1d6c2","LICENSE.txt":"3ddf9be5c28fe27dad143a5dc76eea25222ad1dd68934a047064e56ed2fa40c5","README.md":"e1800b83d40b2fe14cee9cf97bdd1e28c1578f30ce946f342321dbcd31e17874","build.rs":"fbcd7eb0494a38be9e3fda648f91e4be05cad53a4c9faaf4fb8c7be270b1305d","build/common.rs":"7a38220e50c7c208057cb0b5ac13d54152aa4f6bebaea2160b0391adaf518e68","build/dynamic.rs":"84bc5a004dd7fa72a176cf9564db58a517c09870bac9ae6f5169411e1ed7f548","build/static.rs":"15e680b3896d1a83720210de7b72cc2fd2791626721e480c89902595d876eba7","clippy.toml":"fcf54943ba571514b244cc098ce08671b4117167733e8107e799d533a12a2195","src/lib.rs":"e2a78105864d5d49cb1dcafc331a5433cae39e4d39c726030f727d61cb214d7c","src/link.rs":"2fd772f679752a215566460671b159c01324504e7a36b642751fa3e1eca8d42f","src/support.rs":"8e560210d97b8464de7108bbc67c4b09296fb7c25cbc5698bebb6485ba4d637d","tests/header.h":"1b15a686d1c06561960045a26c25a34d840f26c8246f2f5e630f993b69c7492c","tests/lib.rs":"81a459e9f48e6d384b3fd61e7942e685f7ea39af6574bc2b382a0fbe7820ff65"},"package":"bf6b561dcf059c85bbe388e0a7b0a1469acb3934cc0cfa148613a830629e3049"}
\ No newline at end of file
--- a/third_party/rust/clang-sys/CHANGELOG.md
+++ b/third_party/rust/clang-sys/CHANGELOG.md
@@ -1,8 +1,18 @@
+## [1.3.2] - 2022-05-18
+
+### Added
+- Added support for illumos and derivatives
+
+## [1.3.1] - 2022-02-03
+
+### Added
+- Added missing `clang_getToken` function
+
 ## [1.3.0] - 2021-10-31
 
 ### Added
 - Added support for `clang` 13.0.x
 - Added support for `clang` 12.0.x
 - Added support for the Haiku operating system
 
 ## [1.2.2] - 2021-09-02
--- a/third_party/rust/clang-sys/Cargo.toml
+++ b/third_party/rust/clang-sys/Cargo.toml
@@ -6,27 +6,27 @@
 # to registry (e.g., crates.io) dependencies.
 #
 # If you are reading this file be aware that the original Cargo.toml
 # will likely look very different (and much more reasonable).
 # See Cargo.toml.orig for the original contents.
 
 [package]
 name = "clang-sys"
-version = "1.3.0"
+version = "1.3.2"
 authors = ["Kyle Mayes <kyle@mayeses.com>"]
 build = "build.rs"
 links = "clang"
 description = "Rust bindings for libclang."
 documentation = "https://docs.rs/clang-sys"
 readme = "README.md"
 license = "Apache-2.0"
 repository = "https://github.com/KyleMayes/clang-sys"
 [package.metadata.docs.rs]
-features = ["clang_11_0", "runtime"]
+features = ["clang_13_0", "runtime"]
 [dependencies.glob]
 version = "0.3"
 
 [dependencies.libc]
 version = "0.2.39"
 default-features = false
 
 [dependencies.libloading]
--- a/third_party/rust/clang-sys/build.rs
+++ b/third_party/rust/clang-sys/build.rs
@@ -1,28 +1,16 @@
-// Copyright 2016 Kyle Mayes
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
 
-//! Finds `libclang` static or dynamic libraries and links to them.
+//! Finds `libclang` static or shared libraries and links to them.
 //!
 //! # Environment Variables
 //!
 //! This build script can make use of several environment variables to help it
-//! find the required static or dynamic libraries.
+//! find the required static or shared libraries.
 //!
 //! * `LLVM_CONFIG_PATH` - provides a path to an `llvm-config` executable
 //! * `LIBCLANG_PATH` - provides a path to a directory containing a `libclang`
 //!    shared library or a path to a specific `libclang` shared library
 //! * `LIBCLANG_STATIC_PATH` - provides a path to a directory containing LLVM
 //!    and Clang static libraries
 
 #![allow(unused_attributes)]
@@ -31,54 +19,55 @@ extern crate glob;
 
 use std::path::Path;
 
 #[path = "build/common.rs"]
 pub mod common;
 #[path = "build/dynamic.rs"]
 pub mod dynamic;
 #[path = "build/static.rs"]
-pub mod static_;
+pub mod r#static;
 
-/// Copy the file from the supplied source to the supplied destination.
+/// Copies a file.
 #[cfg(feature = "runtime")]
 fn copy(source: &str, destination: &Path) {
     use std::fs::File;
     use std::io::{Read, Write};
 
     let mut string = String::new();
     File::open(source)
         .unwrap()
         .read_to_string(&mut string)
         .unwrap();
     File::create(destination)
         .unwrap()
         .write_all(string.as_bytes())
         .unwrap();
 }
 
-/// Generates the finding and linking code so that it may be used at runtime.
+/// Copies the code used to find and link to `libclang` shared libraries into
+/// the build output directory so that it may be used when linking at runtime.
 #[cfg(feature = "runtime")]
 fn main() {
     use std::env;
 
     if cfg!(feature = "static") {
         panic!("`runtime` and `static` features can't be combined");
     }
 
     let out = env::var("OUT_DIR").unwrap();
     copy("build/common.rs", &Path::new(&out).join("common.rs"));
     copy("build/dynamic.rs", &Path::new(&out).join("dynamic.rs"));
 }
 
-/// Finds and links to the required libraries.
+/// Finds and links to the required libraries dynamically or statically.
 #[cfg(not(feature = "runtime"))]
 fn main() {
     if cfg!(feature = "static") {
-        static_::link();
+        r#static::link();
     } else {
         dynamic::link();
     }
 
     if let Some(output) = common::run_llvm_config(&["--includedir"]) {
         let directory = Path::new(output.trim_end());
         println!("cargo:include={}", directory.display());
     }
--- a/third_party/rust/clang-sys/build/common.rs
+++ b/third_party/rust/clang-sys/build/common.rs
@@ -1,123 +1,52 @@
-// Copyright 2018 Kyle Mayes
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
 
 extern crate glob;
 
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::env;
 use std::path::{Path, PathBuf};
 use std::process::Command;
 
 use glob::{MatchOptions, Pattern};
 
-/// `libclang` directory patterns for FreeBSD and Linux.
-const DIRECTORIES_LINUX: &[&str] = &[
-    "/usr/lib*",
-    "/usr/lib*/*",
-    "/usr/lib*/*/*",
-    "/usr/local/lib*",
-    "/usr/local/lib*/*",
-    "/usr/local/lib*/*/*",
-    "/usr/local/llvm*/lib*",
-];
-
-/// `libclang` directory patterns for macOS.
-const DIRECTORIES_MACOS: &[&str] = &[
-    "/usr/local/opt/llvm*/lib",
-    "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib",
-    "/Library/Developer/CommandLineTools/usr/lib",
-    "/usr/local/opt/llvm*/lib/llvm*/lib",
-];
-
-/// `libclang` directory patterns for Windows.
-const DIRECTORIES_WINDOWS: &[&str] = &[
-    "C:\\LLVM\\lib",
-    "C:\\Program Files*\\LLVM\\lib",
-    "C:\\MSYS*\\MinGW*\\lib",
-    // LLVM + Clang can be installed as a component of Visual Studio.
-    // https://github.com/KyleMayes/clang-sys/issues/121
-    "C:\\Program Files*\\Microsoft Visual Studio\\*\\BuildTools\\VC\\Tools\\Llvm\\**\\bin",
-    // Scoop user installation https://scoop.sh/.
-    // Chocolatey, WinGet and other installers use to the system wide dir listed above
-    "C:\\Users\\*\\scoop\\apps\\llvm\\current\\bin",
-];
-
-/// `libclang` directory patterns for Haiku.
-const DIRECTORIES_HAIKU: &[&str] = &[
-    "/boot/system/lib",
-    "/boot/system/develop/lib",
-    "/boot/system/non-packaged/lib",
-    "/boot/system/non-packaged/develop/lib",
-    "/boot/home/config/non-packaged/lib",
-    "/boot/home/config/non-packaged/develop/lib",
-];
+//================================================
+// Commands
+//================================================
 
 thread_local! {
-    /// The errors encountered when attempting to execute console commands.
+    /// The errors encountered by the build script while executing commands.
     static COMMAND_ERRORS: RefCell<HashMap<String, Vec<String>>> = RefCell::default();
 }
 
-/// Executes the supplied console command, returning the `stdout` output if the
-/// command was successfully executed.
-fn run_command(name: &str, command: &str, arguments: &[&str]) -> Option<String> {
-    macro_rules! error {
-        ($error:expr) => {{
-            COMMAND_ERRORS.with(|e| {
-                e.borrow_mut()
-                    .entry(name.into())
-                    .or_insert_with(Vec::new)
-                    .push(format!(
-                        "couldn't execute `{} {}` ({})",
-                        command,
-                        arguments.join(" "),
-                        $error,
-                    ))
-            });
-        }};
-    }
-
-    let output = match Command::new(command).args(arguments).output() {
-        Ok(output) => output,
-        Err(error) => {
-            error!(format!("error: {}", error));
-            return None;
-        }
-    };
-
-    if !output.status.success() {
-        error!(format!("exit code: {}", output.status));
-        return None;
-    }
-
-    Some(String::from_utf8_lossy(&output.stdout).into_owned())
+/// Adds an error encountered by the build script while executing a command.
+fn add_command_error(name: &str, path: &str, arguments: &[&str], message: String) {
+    COMMAND_ERRORS.with(|e| {
+        e.borrow_mut()
+            .entry(name.into())
+            .or_insert_with(Vec::new)
+            .push(format!(
+                "couldn't execute `{} {}` (path={}) ({})",
+                name,
+                arguments.join(" "),
+                path,
+                message,
+            ))
+    });
 }
 
-/// Executes `llvm-config`, returning the `stdout` output if the command was
-/// successfully executed.
-pub fn run_llvm_config(arguments: &[&str]) -> Option<String> {
-    let path = env::var("LLVM_CONFIG_PATH").unwrap_or_else(|_| "llvm-config".into());
-    run_command("llvm-config", &path, arguments)
-}
-
-/// A struct that prints errors encountered when attempting to execute console
-/// commands on drop if not discarded.
+/// A struct that prints the errors encountered by the build script while
+/// executing commands when dropped (unless explictly discarded).
+///
+/// This is handy because we only want to print these errors when the build
+/// script fails to link to an instance of `libclang`. For example, if
+/// `llvm-config` couldn't be executed but an instance of `libclang` was found
+/// anyway we don't want to pollute the build output with irrelevant errors.
 #[derive(Default)]
 pub struct CommandErrorPrinter {
     discard: bool,
 }
 
 impl CommandErrorPrinter {
     pub fn discard(mut self) {
         self.discard = true;
@@ -157,141 +86,234 @@ impl Drop for CommandErrorPrinter {
                     .map(|e| format!("\"{}\"", e))
                     .collect::<Vec<_>>()
                     .join("\n  "),
             )
         }
     }
 }
 
-/// Returns the paths to and the filenames of the files matching the supplied
-/// filename patterns in the supplied directory.
+/// Executes a command and returns the `stdout` output if the command was
+/// successfully executed (errors are added to `COMMAND_ERRORS`).
+fn run_command(name: &str, path: &str, arguments: &[&str]) -> Option<String> {
+    let output =