Merge mozilla-inbound to mozilla-central. a=merge
authorDorel Luca <dluca@mozilla.com>
Tue, 02 Jul 2019 12:38:01 +0300
changeset 540570 a15e5a44b7ed0a285c92839055efd83671b49552
parent 540515 9525f0cc6ca1bae213239c542b7a6642f05c1f8e (current diff)
parent 540566 f9bf5e4b0b4f48302d560afb5307d57fbbab7c73 (diff)
child 540571 f0ee392901d3cfc696ef1e2aecb1d8e8e77d8ee6
child 540600 4b1b5ac830370c57e2cd5050fae28471e749990f
push id11529
push userarchaeopteryx@coole-files.de
push dateThu, 04 Jul 2019 15:22:33 +0000
treeherdermozilla-beta@ebb510a784b8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone69.0a1
first release with
nightly linux32
a15e5a44b7ed / 69.0a1 / 20190702093917 / files
nightly linux64
a15e5a44b7ed / 69.0a1 / 20190702093917 / files
nightly mac
a15e5a44b7ed / 69.0a1 / 20190702093917 / files
nightly win32
a15e5a44b7ed / 69.0a1 / 20190702093917 / files
nightly win64
a15e5a44b7ed / 69.0a1 / 20190702093917 / 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 mozilla-inbound to mozilla-central. a=merge
dom/base/nsDOMWindowList.cpp
dom/base/nsDOMWindowList.h
js/src/wasm/cranelift/src/baldrapi.rs
js/src/wasm/cranelift/src/baldrdash.rs
js/src/wasm/cranelift/src/cpu.rs
testing/mochitest/nested_setup.js
testing/specialpowers/content/MozillaLogger.js
testing/specialpowers/content/SpecialPowersObserver.jsm
testing/specialpowers/content/SpecialPowersObserverAPI.js
testing/specialpowers/content/specialpowers.js
testing/specialpowers/content/specialpowersAPI.js
testing/specialpowers/content/specialpowersFrameScript.js
--- a/.cargo/config.in
+++ b/.cargo/config.in
@@ -19,13 +19,13 @@ replace-with = "vendored-sources"
 
 [source."https://github.com/rust-lang-nursery/packed_simd"]
 git = "https://github.com/hsivonen/packed_simd"
 branch = "rust_1_32"
 replace-with = "vendored-sources"
 
 [source."https://github.com/CraneStation/Cranelift"]
 git = "https://github.com/CraneStation/Cranelift"
-rev = "475aa632fea5360c6f8c4cc1f26e3ee0369385ef"
+rev = "e455f6ae0f3577ceb210c0ce167181c33c133a69"
 replace-with = "vendored-sources"
 
 [source.vendored-sources]
 directory = '@top_srcdir@/third_party/rust'
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -192,18 +192,18 @@ dependencies = [
  "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "baldrdash"
 version = "0.1.0"
 dependencies = [
  "bindgen 0.49.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "cranelift-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef)",
- "cranelift-wasm 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef)",
+ "cranelift-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69)",
+ "cranelift-wasm 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69)",
  "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "base64"
 version = "0.9.3"
@@ -608,70 +608,70 @@ version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cose 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cranelift-bforest"
 version = "0.30.0"
-source = "git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef#475aa632fea5360c6f8c4cc1f26e3ee0369385ef"
-dependencies = [
- "cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef)",
+source = "git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69#e455f6ae0f3577ceb210c0ce167181c33c133a69"
+dependencies = [
+ "cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69)",
 ]
 
 [[package]]
 name = "cranelift-codegen"
 version = "0.30.0"
-source = "git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef#475aa632fea5360c6f8c4cc1f26e3ee0369385ef"
-dependencies = [
- "cranelift-bforest 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef)",
- "cranelift-codegen-meta 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef)",
- "cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef)",
+source = "git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69#e455f6ae0f3577ceb210c0ce167181c33c133a69"
+dependencies = [
+ "cranelift-bforest 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69)",
+ "cranelift-codegen-meta 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69)",
+ "cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69)",
  "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cranelift-codegen-meta"
 version = "0.30.0"
-source = "git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef#475aa632fea5360c6f8c4cc1f26e3ee0369385ef"
-dependencies = [
- "cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef)",
+source = "git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69#e455f6ae0f3577ceb210c0ce167181c33c133a69"
+dependencies = [
+ "cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69)",
 ]
 
 [[package]]
 name = "cranelift-entity"
 version = "0.30.0"
-source = "git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef#475aa632fea5360c6f8c4cc1f26e3ee0369385ef"
+source = "git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69#e455f6ae0f3577ceb210c0ce167181c33c133a69"
 
 [[package]]
 name = "cranelift-frontend"
 version = "0.30.0"
-source = "git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef#475aa632fea5360c6f8c4cc1f26e3ee0369385ef"
-dependencies = [
- "cranelift-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef)",
+source = "git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69#e455f6ae0f3577ceb210c0ce167181c33c133a69"
+dependencies = [
+ "cranelift-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cranelift-wasm"
 version = "0.30.0"
-source = "git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef#475aa632fea5360c6f8c4cc1f26e3ee0369385ef"
-dependencies = [
- "cranelift-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef)",
- "cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef)",
- "cranelift-frontend 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef)",
+source = "git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69#e455f6ae0f3577ceb210c0ce167181c33c133a69"
+dependencies = [
+ "cranelift-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69)",
+ "cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69)",
+ "cranelift-frontend 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69)",
  "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasmparser 0.31.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "crc"
 version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3535,17 +3535,17 @@ dependencies = [
  "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-threadpool 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "tungstenite 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "urlencoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "wasmparser"
-version = "0.29.2"
+version = "0.31.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "webdriver"
 version = "0.39.0"
 dependencies = [
  "base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3882,22 +3882,22 @@ dependencies = [
 "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
 "checksum cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1465f8134efa296b4c19db34d909637cb2bf0f7aaf21299e23e18fa29ac557cf"
 "checksum core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4e2640d6d0bf22e82bed1b73c6aef8d5dd31e5abe6666c57e6d45e2649f4f887"
 "checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
 "checksum core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)" = "62ceafe1622ffc9a332199096841d0ff9912ec8cf8f9cde01e254a7d5217cd10"
 "checksum core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f46450d6f2397261af420b4ccce23807add2e45fa206410a03d66fb7f050ae"
 "checksum cose 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72fa26cb151d3ae4b70f63d67d0fed57ce04220feafafbae7f503bef7aae590d"
 "checksum cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "49726015ab0ca765144fcca61e4a7a543a16b795a777fa53f554da2fffff9a94"
-"checksum cranelift-bforest 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef)" = "<none>"
-"checksum cranelift-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef)" = "<none>"
-"checksum cranelift-codegen-meta 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef)" = "<none>"
-"checksum cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef)" = "<none>"
-"checksum cranelift-frontend 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef)" = "<none>"
-"checksum cranelift-wasm 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=475aa632fea5360c6f8c4cc1f26e3ee0369385ef)" = "<none>"
+"checksum cranelift-bforest 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69)" = "<none>"
+"checksum cranelift-codegen 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69)" = "<none>"
+"checksum cranelift-codegen-meta 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69)" = "<none>"
+"checksum cranelift-entity 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69)" = "<none>"
+"checksum cranelift-frontend 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69)" = "<none>"
+"checksum cranelift-wasm 0.30.0 (git+https://github.com/CraneStation/Cranelift?rev=e455f6ae0f3577ceb210c0ce167181c33c133a69)" = "<none>"
 "checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7"
 "checksum crossbeam-channel 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8d4f5844607ce8da3fff431e7dba56cda8bfcc570aa50bee36adba8a32b8cad7"
 "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
 "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13"
 "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
 "checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4"
 "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
 "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c"
@@ -4153,17 +4153,17 @@ dependencies = [
 "checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a"
 "checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b"
 "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
 "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
 "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
 "checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369"
 "checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3"
 "checksum warp 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a120bf7041d4381a5429c4e6d12633bfb874c968a78ec3a3563e9ca6e12d6"
-"checksum wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)" = "981a8797cf89762e0233ec45fae731cb79a4dfaee12d9f0fe6cee01e4ac58d00"
+"checksum wasmparser 0.31.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6f324afc05fd8282bbc49dae854a1c20f74aeff10a575b5a43453d1864db97"
 "checksum weedle 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "26a4c67f132386d965390b8a734d5d10adbcd30eb5cc74bd9229af8b83f10044"
 "checksum which 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4be6cfa54dab45266e98b5d7be2f8ce959ddd49abd141a05d52dce4b07f803bb"
 "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
 "checksum winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)" = "<none>"
 "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
 "checksum winapi-i686-pc-windows-gnu 0.4.0 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)" = "<none>"
 "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)" = "<none>"
 "checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767"
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -59,13 +59,13 @@ codegen-units = 1
 [patch.crates-io]
 libudev-sys = { path = "dom/webauthn/libudev-sys" }
 serde_derive = { git = "https://github.com/servo/serde", branch = "deserialize_from_enums10" }
 winapi = { git = "https://github.com/froydnj/winapi-rs", branch = "aarch64" }
 packed_simd = { git = "https://github.com/hsivonen/packed_simd", branch = "rust_1_32" }
 
 [patch.crates-io.cranelift-codegen]
 git = "https://github.com/CraneStation/Cranelift"
-rev = "475aa632fea5360c6f8c4cc1f26e3ee0369385ef"
+rev = "e455f6ae0f3577ceb210c0ce167181c33c133a69"
 
 [patch.crates-io.cranelift-wasm]
 git = "https://github.com/CraneStation/Cranelift"
-rev = "475aa632fea5360c6f8c4cc1f26e3ee0369385ef"
+rev = "e455f6ae0f3577ceb210c0ce167181c33c133a69"
--- a/js/src/wasm/cranelift/Cargo.toml
+++ b/js/src/wasm/cranelift/Cargo.toml
@@ -1,12 +1,13 @@
 [package]
 name = "baldrdash"
 version = "0.1.0"
 authors = ["The Spidermonkey and Cranelift developers"]
+edition = "2018"
 
 [lib]
 crate-type = ["rlib"]
 name = "baldrdash"
 
 [dependencies]
 # The build system redirects the versions of cranelift-codegen and
 # cranelift-wasm to pinned commits. If you want to update Cranelift in Gecko,
--- a/js/src/wasm/cranelift/baldrapi.h
+++ b/js/src/wasm/cranelift/baldrapi.h
@@ -16,17 +16,17 @@
  * limitations under the License.
  */
 
 // This is an ADT-style C API to the WebAssembly per-function compilation state,
 // allowing Rust to access constant metadata and produce output.
 //
 // This file is input to Rust's bindgen, so as to create primitive APIs for the
 // Cranelift pipeline to access compilation metadata. The actual Rust API then
-// wraps these primitive APIs.  See src/baldrdash.rs.
+// wraps these primitive APIs.  See src/bindings/mod.rs.
 //
 // This file can be included in SpiderMonkey's C++ code, where all the prefixes
 // must be obeyed.  The purpose of the prefixes is to avoid type confusion.  See
 // js/src/wasm/WasmCraneliftCompile.cpp.
 
 #ifndef wasm_cranelift_baldrapi_h
 #define wasm_cranelift_baldrapi_h
 
--- a/js/src/wasm/cranelift/build.rs
+++ b/js/src/wasm/cranelift/build.rs
@@ -12,17 +12,17 @@
  * 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.
  */
 
 //! Build script for the Baldr <-> Cranelift bindings.
 //!
 //! This file is executed by cargo when this crate is built. It generates the
-//! `$OUT_DIR/bindings.rs` file which is then included by `src/baldrapi.rs`.
+//! `$OUT_DIR/bindings.rs` file which is then included by `src/bindings/low_level.rs`.
 
 extern crate bindgen;
 
 use std::env;
 use std::fs::File;
 use std::io::prelude::*;
 use std::path::PathBuf;
 
rename from js/src/wasm/cranelift/src/baldrapi.rs
rename to js/src/wasm/cranelift/src/bindings/low_level.rs
--- a/js/src/wasm/cranelift/src/baldrapi.rs
+++ b/js/src/wasm/cranelift/src/bindings/low_level.rs
@@ -15,93 +15,14 @@
 
 //! This module exports the bindings generated by bindgen form the baldrapi.h file.
 //!
 //! The Baldr API consists of a set of C functions and some associated types.
 
 #![allow(non_upper_case_globals)]
 #![allow(non_camel_case_types)]
 #![allow(non_snake_case)]
+
 // We need to allow dead code because the Rustc compiler complains about variants never being
 // constructed in TypeCode, which is true because these values come from C++.
 #![allow(dead_code)]
 
-use cranelift_codegen::binemit::CodeOffset;
-use cranelift_codegen::entity::EntityRef;
-use cranelift_codegen::ir::SourceLoc;
-use cranelift_wasm::FuncIndex;
-
-use compile::CompiledFunc;
-
 include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
-
-impl CraneliftFuncCompileInput {
-    pub fn bytecode(&self) -> &[u8] {
-        use std::slice;
-        unsafe { slice::from_raw_parts(self.bytecode, self.bytecodeSize) }
-    }
-}
-
-impl CraneliftCompiledFunc {
-    pub fn reset(&mut self, compiled_func: &CompiledFunc) {
-        self.numMetadata = compiled_func.metadata.len();
-        self.metadatas = compiled_func.metadata.as_ptr();
-
-        self.framePushed = compiled_func.frame_pushed as usize;
-        self.containsCalls = compiled_func.contains_calls;
-
-        self.code = compiled_func.code_buffer.as_ptr();
-        self.codeSize = compiled_func.code_size as usize;
-        self.jumptablesSize = compiled_func.jumptables_size as usize;
-        self.rodataSize = compiled_func.rodata_size as usize;
-        self.totalSize = compiled_func.code_buffer.len();
-
-        self.numRodataRelocs = compiled_func.rodata_relocs.len();
-        self.rodataRelocs = compiled_func.rodata_relocs.as_ptr();
-    }
-}
-
-impl CraneliftMetadataEntry {
-    pub fn direct_call(code_offset: CodeOffset, func_index: FuncIndex, srcloc: SourceLoc) -> Self {
-        Self {
-            which: CraneliftMetadataEntry_Which_DirectCall,
-            codeOffset: code_offset,
-            moduleBytecodeOffset: srcloc.bits(),
-            extra: func_index.index(),
-        }
-    }
-
-    pub fn indirect_call(code_offset: CodeOffset, srcloc: SourceLoc) -> Self {
-        Self {
-            which: CraneliftMetadataEntry_Which_IndirectCall,
-            codeOffset: code_offset,
-            moduleBytecodeOffset: srcloc.bits(),
-            extra: 0,
-        }
-    }
-
-    pub fn trap(code_offset: CodeOffset, srcloc: SourceLoc, which: Trap) -> Self {
-        Self {
-            which: CraneliftMetadataEntry_Which_Trap,
-            codeOffset: code_offset,
-            moduleBytecodeOffset: srcloc.bits(),
-            extra: which as usize,
-        }
-    }
-
-    pub fn memory_access(code_offset: CodeOffset, srcloc: SourceLoc) -> Self {
-        Self {
-            which: CraneliftMetadataEntry_Which_MemoryAccess,
-            codeOffset: code_offset,
-            moduleBytecodeOffset: srcloc.bits(),
-            extra: 0,
-        }
-    }
-
-    pub fn symbolic_access(code_offset: CodeOffset, sym: BD_SymbolicAddress) -> Self {
-        Self {
-            which: CraneliftMetadataEntry_Which_SymbolicAccess,
-            codeOffset: code_offset,
-            moduleBytecodeOffset: 0,
-            extra: sym as usize,
-        }
-    }
-}
rename from js/src/wasm/cranelift/src/baldrdash.rs
rename to js/src/wasm/cranelift/src/bindings/mod.rs
--- a/js/src/wasm/cranelift/src/baldrdash.rs
+++ b/js/src/wasm/cranelift/src/bindings/mod.rs
@@ -8,42 +8,43 @@
  *
  * 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.
  */
 
-// Safe wrappers to the low-level ABI.  This re-exports all types in
-// baldrapi but none of the functions.
+// Safe wrappers to the low-level ABI.  This re-exports all types in low_level but none of the
+// functions.
 
+use std::{mem, slice};
+
+use cranelift_codegen::binemit::CodeOffset;
 use cranelift_codegen::cursor::FuncCursor;
 use cranelift_codegen::entity::EntityRef;
 use cranelift_codegen::ir::immediates::{Ieee32, Ieee64};
-use cranelift_codegen::ir::{self, InstBuilder};
+use cranelift_codegen::ir::{self, InstBuilder, SourceLoc};
 use cranelift_wasm::{FuncIndex, GlobalIndex, SignatureIndex, TableIndex, WasmResult};
 
-use std::mem;
-use std::slice;
+use crate::compile;
+use crate::utils::BasicError;
 
-use baldrapi;
-use baldrapi::BD_ValType as ValType;
-use baldrapi::CraneliftModuleEnvironment;
-use baldrapi::TypeCode;
+use self::low_level::*;
 
-use utils::BasicError;
+pub use self::low_level::BD_SymbolicAddress as SymbolicAddress;
+pub use self::low_level::CraneliftCompiledFunc as CompiledFunc;
+pub use self::low_level::CraneliftFuncCompileInput as FuncCompileInput;
+pub use self::low_level::CraneliftMetadataEntry as MetadataEntry;
+pub use self::low_level::CraneliftModuleEnvironment as LowLevelModuleEnvironment;
+pub use self::low_level::CraneliftStaticEnvironment as StaticEnvironment;
+pub use self::low_level::FuncTypeIdDescKind;
+pub use self::low_level::Trap;
 
-pub use baldrapi::BD_SymbolicAddress as SymbolicAddress;
-pub use baldrapi::CraneliftCompiledFunc as CompiledFunc;
-pub use baldrapi::CraneliftFuncCompileInput as FuncCompileInput;
-pub use baldrapi::CraneliftMetadataEntry as MetadataEntry;
-pub use baldrapi::CraneliftStaticEnvironment as StaticEnvironment;
-pub use baldrapi::FuncTypeIdDescKind;
-pub use baldrapi::Trap;
+mod low_level;
 
 /// Converts a `TypeCode` into the equivalent Cranelift type, if it's a known type, or an error
 /// otherwise.
 #[inline]
 fn typecode_to_type(type_code: TypeCode) -> WasmResult<Option<ir::Type>> {
     match type_code {
         TypeCode::I32 => Ok(Some(ir::types::I32)),
         TypeCode::I64 => Ok(Some(ir::types::I64)),
@@ -57,140 +58,214 @@ fn typecode_to_type(type_code: TypeCode)
 /// Convert a non-void `TypeCode` into the equivalent Cranelift type.
 #[inline]
 fn typecode_to_nonvoid_type(type_code: TypeCode) -> WasmResult<ir::Type> {
     Ok(typecode_to_type(type_code)?.expect("unexpected void type"))
 }
 
 /// Convert a `TypeCode` into the equivalent Cranelift type.
 #[inline]
-fn valtype_to_type(val_type: ValType) -> WasmResult<ir::Type> {
-    let type_code = unsafe { baldrapi::env_unpack(val_type) };
+fn valtype_to_type(val_type: BD_ValType) -> WasmResult<ir::Type> {
+    let type_code = unsafe { low_level::env_unpack(val_type) };
     typecode_to_nonvoid_type(type_code)
 }
 
 /// Convert a u32 into a `BD_SymbolicAddress`.
 impl From<u32> for SymbolicAddress {
     fn from(x: u32) -> SymbolicAddress {
         assert!(x < SymbolicAddress::Limit as u32);
         unsafe { mem::transmute(x) }
     }
 }
 
 #[derive(Clone, Copy)]
-pub struct GlobalDesc(*const baldrapi::GlobalDesc);
+pub struct GlobalDesc(*const low_level::GlobalDesc);
 
 impl GlobalDesc {
     pub fn value_type(self) -> WasmResult<ir::Type> {
-        let type_code = unsafe { baldrapi::global_type(self.0) };
+        let type_code = unsafe { low_level::global_type(self.0) };
         typecode_to_nonvoid_type(type_code)
     }
 
     pub fn is_constant(self) -> bool {
-        unsafe { baldrapi::global_isConstant(self.0) }
+        unsafe { low_level::global_isConstant(self.0) }
     }
 
     pub fn is_indirect(self) -> bool {
-        unsafe { baldrapi::global_isIndirect(self.0) }
+        unsafe { low_level::global_isIndirect(self.0) }
     }
 
     /// Insert an instruction at `pos` that materialized the constant value.
     pub fn emit_constant(self, pos: &mut FuncCursor) -> WasmResult<ir::Value> {
         unsafe {
-            let v = baldrapi::global_constantValue(self.0);
+            let v = low_level::global_constantValue(self.0);
             match v.t {
                 TypeCode::I32 => Ok(pos.ins().iconst(ir::types::I32, i64::from(v.u.i32))),
                 TypeCode::I64 => Ok(pos.ins().iconst(ir::types::I64, v.u.i64)),
                 TypeCode::F32 => Ok(pos.ins().f32const(Ieee32::with_bits(v.u.i32 as u32))),
                 TypeCode::F64 => Ok(pos.ins().f64const(Ieee64::with_bits(v.u.i64 as u64))),
                 _ => Err(BasicError::new(format!("unexpected type: {}", v.t as u64)).into()),
             }
         }
     }
 
     /// Get the offset from the `WasmTlsReg` to the memory representing this global variable.
     pub fn tls_offset(self) -> usize {
-        unsafe { baldrapi::global_tlsOffset(self.0) }
+        unsafe { low_level::global_tlsOffset(self.0) }
     }
 }
 
 #[derive(Clone, Copy)]
-pub struct TableDesc(*const baldrapi::TableDesc);
+pub struct TableDesc(*const low_level::TableDesc);
 
 impl TableDesc {
     /// Get the offset from the `WasmTlsReg` to the `wasm::TableTls` representing this table.
     pub fn tls_offset(self) -> usize {
-        unsafe { baldrapi::table_tlsOffset(self.0) }
+        unsafe { low_level::table_tlsOffset(self.0) }
     }
 }
 
 #[derive(Clone, Copy)]
-pub struct FuncTypeWithId(*const baldrapi::FuncTypeWithId);
+pub struct FuncTypeWithId(*const low_level::FuncTypeWithId);
 
 impl FuncTypeWithId {
     pub fn args<'a>(self) -> WasmResult<Vec<ir::Type>> {
-        let num_args = unsafe { baldrapi::funcType_numArgs(self.0) };
+        let num_args = unsafe { low_level::funcType_numArgs(self.0) };
         // The `funcType_args` callback crashes when there are no arguments. Also note that
         // `slice::from_raw_parts()` requires a non-null pointer for empty slices.
         // TODO: We should get all the parts of a signature in a single callback that returns a
         // struct.
         if num_args == 0 {
             Ok(Vec::new())
         } else {
-            let args = unsafe { slice::from_raw_parts(baldrapi::funcType_args(self.0), num_args) };
+            let args = unsafe { slice::from_raw_parts(low_level::funcType_args(self.0), num_args) };
             let mut ret = Vec::new();
             for &arg in args {
                 ret.push(valtype_to_type(arg)?);
             }
             Ok(ret)
         }
     }
 
     pub fn ret_type(self) -> WasmResult<Option<ir::Type>> {
-        let type_code = unsafe { baldrapi::funcType_retType(self.0) };
+        let type_code = unsafe { low_level::funcType_retType(self.0) };
         typecode_to_type(type_code)
     }
 
     pub fn id_kind(self) -> FuncTypeIdDescKind {
-        unsafe { baldrapi::funcType_idKind(self.0) }
+        unsafe { low_level::funcType_idKind(self.0) }
     }
 
     pub fn id_immediate(self) -> usize {
-        unsafe { baldrapi::funcType_idImmediate(self.0) }
+        unsafe { low_level::funcType_idImmediate(self.0) }
     }
 
     pub fn id_tls_offset(self) -> usize {
-        unsafe { baldrapi::funcType_idTlsOffset(self.0) }
+        unsafe { low_level::funcType_idTlsOffset(self.0) }
     }
 }
 
 /// Thin wrapper for the CraneliftModuleEnvironment structure.
 
 pub struct ModuleEnvironment<'a> {
     env: &'a CraneliftModuleEnvironment,
 }
 
 impl<'a> ModuleEnvironment<'a> {
     pub fn new(env: &'a CraneliftModuleEnvironment) -> Self {
         Self { env }
     }
     pub fn function_signature(&self, func_index: FuncIndex) -> FuncTypeWithId {
-        FuncTypeWithId(unsafe { baldrapi::env_function_signature(self.env, func_index.index()) })
+        FuncTypeWithId(unsafe { low_level::env_function_signature(self.env, func_index.index()) })
     }
     pub fn func_import_tls_offset(&self, func_index: FuncIndex) -> usize {
-        unsafe { baldrapi::env_func_import_tls_offset(self.env, func_index.index()) }
+        unsafe { low_level::env_func_import_tls_offset(self.env, func_index.index()) }
     }
     pub fn func_is_import(&self, func_index: FuncIndex) -> bool {
-        unsafe { baldrapi::env_func_is_import(self.env, func_index.index()) }
+        unsafe { low_level::env_func_is_import(self.env, func_index.index()) }
     }
     pub fn signature(&self, sig_index: SignatureIndex) -> FuncTypeWithId {
-        FuncTypeWithId(unsafe { baldrapi::env_signature(self.env, sig_index.index()) })
+        FuncTypeWithId(unsafe { low_level::env_signature(self.env, sig_index.index()) })
     }
     pub fn table(&self, table_index: TableIndex) -> TableDesc {
-        TableDesc(unsafe { baldrapi::env_table(self.env, table_index.index()) })
+        TableDesc(unsafe { low_level::env_table(self.env, table_index.index()) })
     }
     pub fn global(&self, global_index: GlobalIndex) -> GlobalDesc {
-        GlobalDesc(unsafe { baldrapi::env_global(self.env, global_index.index()) })
+        GlobalDesc(unsafe { low_level::env_global(self.env, global_index.index()) })
     }
     pub fn min_memory_length(&self) -> i64 {
         i64::from(self.env.min_memory_length)
     }
 }
+
+/// Extra methods for some C++ wrappers.
+
+impl FuncCompileInput {
+    pub fn bytecode(&self) -> &[u8] {
+        unsafe { slice::from_raw_parts(self.bytecode, self.bytecodeSize) }
+    }
+}
+
+impl CompiledFunc {
+    pub fn reset(&mut self, compiled_func: &compile::CompiledFunc) {
+        self.numMetadata = compiled_func.metadata.len();
+        self.metadatas = compiled_func.metadata.as_ptr();
+
+        self.framePushed = compiled_func.frame_pushed as usize;
+        self.containsCalls = compiled_func.contains_calls;
+
+        self.code = compiled_func.code_buffer.as_ptr();
+        self.codeSize = compiled_func.code_size as usize;
+        self.jumptablesSize = compiled_func.jumptables_size as usize;
+        self.rodataSize = compiled_func.rodata_size as usize;
+        self.totalSize = compiled_func.code_buffer.len();
+
+        self.numRodataRelocs = compiled_func.rodata_relocs.len();
+        self.rodataRelocs = compiled_func.rodata_relocs.as_ptr();
+    }
+}
+
+impl MetadataEntry {
+    pub fn direct_call(code_offset: CodeOffset, func_index: FuncIndex, srcloc: SourceLoc) -> Self {
+        Self {
+            which: CraneliftMetadataEntry_Which_DirectCall,
+            codeOffset: code_offset,
+            moduleBytecodeOffset: srcloc.bits(),
+            extra: func_index.index(),
+        }
+    }
+
+    pub fn indirect_call(code_offset: CodeOffset, srcloc: SourceLoc) -> Self {
+        Self {
+            which: CraneliftMetadataEntry_Which_IndirectCall,
+            codeOffset: code_offset,
+            moduleBytecodeOffset: srcloc.bits(),
+            extra: 0,
+        }
+    }
+
+    pub fn trap(code_offset: CodeOffset, srcloc: SourceLoc, which: Trap) -> Self {
+        Self {
+            which: CraneliftMetadataEntry_Which_Trap,
+            codeOffset: code_offset,
+            moduleBytecodeOffset: srcloc.bits(),
+            extra: which as usize,
+        }
+    }
+
+    pub fn memory_access(code_offset: CodeOffset, srcloc: SourceLoc) -> Self {
+        Self {
+            which: CraneliftMetadataEntry_Which_MemoryAccess,
+            codeOffset: code_offset,
+            moduleBytecodeOffset: srcloc.bits(),
+            extra: 0,
+        }
+    }
+
+    pub fn symbolic_access(code_offset: CodeOffset, sym: SymbolicAddress) -> Self {
+        Self {
+            which: CraneliftMetadataEntry_Which_SymbolicAccess,
+            codeOffset: code_offset,
+            moduleBytecodeOffset: 0,
+            extra: sym as usize,
+        }
+    }
+}
--- a/js/src/wasm/cranelift/src/compile.rs
+++ b/js/src/wasm/cranelift/src/compile.rs
@@ -13,42 +13,44 @@
  * limitations under the License.
  */
 
 //! Cranelift WebAssembly function compiler.
 //!
 //! This module defines the `compile()` function which uses Cranelift to compile a single
 //! WebAssembly function.
 
-use baldrdash as bd;
-use cpu::make_isa;
+use std::fmt;
+use std::mem;
+
 use cranelift_codegen::binemit::{Addend, CodeInfo, CodeOffset, NullTrapSink, Reloc, RelocSink};
 use cranelift_codegen::entity::EntityRef;
 use cranelift_codegen::ir;
 use cranelift_codegen::ir::stackslot::StackSize;
 use cranelift_codegen::isa::TargetIsa;
 use cranelift_codegen::CodegenResult;
 use cranelift_codegen::Context;
 use cranelift_wasm::{FuncIndex, FuncTranslator, WasmResult};
-use std::fmt;
-use std::mem;
-use utils::DashResult;
-use wasm2clif::{init_sig, native_pointer_size, TransEnv};
+
+use crate::bindings;
+use crate::isa::make_isa;
+use crate::utils::DashResult;
+use crate::wasm2clif::{init_sig, native_pointer_size, TransEnv};
 
 // Namespace for user-defined functions.
 const USER_FUNCTION_NAMESPACE: u32 = 0;
 
 // Namespace for builtins functions that are translated to symbolic accesses in Spidermonkey.
 const SYMBOLIC_FUNCTION_NAMESPACE: u32 = 1;
 
 /// The result of a function's compilation: code + metadata.
 pub struct CompiledFunc {
     pub frame_pushed: StackSize,
     pub contains_calls: bool,
-    pub metadata: Vec<bd::MetadataEntry>,
+    pub metadata: Vec<bindings::MetadataEntry>,
     // rodata_relocs is Vec<CodeOffset>, but u32 is C++-friendlier
     pub rodata_relocs: Vec<u32>,
     // TODO(bbouvier) should just be a pointer into the masm buffer
     pub code_buffer: Vec<u8>,
     pub code_size: CodeOffset,
     pub jumptables_size: CodeOffset,
     pub rodata_size: CodeOffset,
 }
@@ -77,28 +79,28 @@ impl CompiledFunc {
         self.jumptables_size = 0;
         self.rodata_size = 0;
     }
 }
 
 /// A batch compiler holds on to data structures that can be recycled for multiple function
 /// compilations.
 pub struct BatchCompiler<'a, 'b> {
-    static_environ: &'a bd::StaticEnvironment,
-    environ: bd::ModuleEnvironment<'b>,
+    static_environ: &'a bindings::StaticEnvironment,
+    environ: bindings::ModuleEnvironment<'b>,
     isa: Box<dyn TargetIsa>,
     context: Context,
     trans: FuncTranslator,
     pub current_func: CompiledFunc,
 }
 
 impl<'a, 'b> BatchCompiler<'a, 'b> {
     pub fn new(
-        static_environ: &'a bd::StaticEnvironment,
-        environ: bd::ModuleEnvironment<'b>,
+        static_environ: &'a bindings::StaticEnvironment,
+        environ: bindings::ModuleEnvironment<'b>,
     ) -> DashResult<Self> {
         // TODO: The target ISA could be shared by multiple batch compilers across threads.
         Ok(BatchCompiler {
             static_environ,
             environ,
             isa: make_isa(static_environ)?,
             context: Context::new(),
             trans: FuncTranslator::new(),
@@ -110,18 +112,18 @@ impl<'a, 'b> BatchCompiler<'a, 'b> {
         let info = self.context.compile(&*self.isa)?;
         debug!("Optimized wasm function IR: {}", self);
         self.binemit(info)
     }
 
     /// Translate the WebAssembly code to Cranelift IR.
     pub fn translate_wasm(
         &mut self,
-        func: &bd::FuncCompileInput,
-    ) -> WasmResult<bd::FuncTypeWithId> {
+        func: &bindings::FuncCompileInput,
+    ) -> WasmResult<bindings::FuncTypeWithId> {
         self.context.clear();
 
         // Set up the signature before translating the WebAssembly byte code.
         // The translator refers to it.
         let index = FuncIndex::new(func.index as usize);
         let wsig = init_sig(&mut self.context.func.signature, &self.environ, index)?;
         self.context.func.name = wasm_function_name(index);
 
@@ -139,17 +141,20 @@ impl<'a, 'b> BatchCompiler<'a, 'b> {
     }
 
     /// Emit binary machine code to `emitter`.
     fn binemit(&mut self, info: CodeInfo) -> CodegenResult<()> {
         let total_size = info.total_size as usize;
         let frame_pushed = self.frame_pushed();
         let contains_calls = self.contains_calls();
 
-        info!("Emitting {} bytes, frame_pushed={}\n.", total_size, frame_pushed);
+        info!(
+            "Emitting {} bytes, frame_pushed={}\n.",
+            total_size, frame_pushed
+        );
 
         self.current_func.reset(frame_pushed, contains_calls);
 
         // Generate metadata about function calls and traps now that the emitter knows where the
         // Cranelift code is going to end up.
         let mut metadata = mem::replace(&mut self.current_func.metadata, vec![]);
         self.emit_metadata(&mut metadata);
         mem::swap(&mut metadata, &mut self.current_func.metadata);
@@ -157,23 +162,27 @@ impl<'a, 'b> BatchCompiler<'a, 'b> {
         // TODO: If we can get a pointer into `size` pre-allocated bytes of memory, we wouldn't
         // have to allocate and copy here.
         // TODO(bbouvier) try to get this pointer from the C++ caller, with an unlikely callback to
         // C++ if the remaining size is smaller than  needed.
         if self.current_func.code_buffer.len() < total_size {
             let current_size = self.current_func.code_buffer.len();
             // There's no way to do a proper uninitialized reserve, so first reserve and then
             // unsafely set the final size.
-            self.current_func.code_buffer.reserve(total_size - current_size);
+            self.current_func
+                .code_buffer
+                .reserve(total_size - current_size);
             unsafe { self.current_func.code_buffer.set_len(total_size) };
         }
 
         {
-            let emit_env = &mut EmitEnv::new(&mut self.current_func.metadata,
-                                             &mut self.current_func.rodata_relocs);
+            let emit_env = &mut EmitEnv::new(
+                &mut self.current_func.metadata,
+                &mut self.current_func.rodata_relocs,
+            );
             let mut trap_sink = NullTrapSink {};
             unsafe {
                 let code_buffer = &mut self.current_func.code_buffer;
                 self.context.emit_to_memory(
                     &*self.isa,
                     code_buffer.as_mut_ptr(),
                     emit_env,
                     &mut trap_sink,
@@ -224,17 +233,17 @@ impl<'a, 'b> BatchCompiler<'a, 'b> {
 
     /// Emit metadata by scanning the compiled function before `emit_to_memory`.
     ///
     /// - All call sites need metadata: direct, indirect, symbolic.
     /// - All explicit traps must be registered.
     ///
     /// We don't get enough callbacks through the `RelocSink` trait to generate all the metadata we
     /// need.
-    fn emit_metadata(&self, metadata: &mut Vec<bd::MetadataEntry>) {
+    fn emit_metadata(&self, metadata: &mut Vec<bindings::MetadataEntry>) {
         let encinfo = self.isa.encoding_info();
         let func = &self.context.func;
         for ebb in func.layout.ebbs() {
             for (offset, inst, inst_size) in func.inst_offsets(ebb, &encinfo) {
                 let opcode = func.dfg[inst].opcode();
                 match opcode {
                     ir::Opcode::Call => self.call_metadata(metadata, inst, offset + inst_size),
                     ir::Opcode::CallIndirect => {
@@ -263,17 +272,17 @@ impl<'a, 'b> BatchCompiler<'a, 'b> {
                     | ir::Opcode::Istore8Complex
                     | ir::Opcode::Istore16
                     | ir::Opcode::Istore16Complex
                     | ir::Opcode::Istore32
                     | ir::Opcode::Istore32Complex => self.memory_metadata(metadata, inst, offset),
 
                     // Instructions that are not going to trap in our use, even though their opcode
                     // says they can.
-                    ir::Opcode::Spill | ir::Opcode::Fill => {}
+                    ir::Opcode::Spill | ir::Opcode::Fill | ir::Opcode::JumpTableEntry => {}
 
                     _ if BatchCompiler::platform_specific_ignores_metadata(opcode) => {}
 
                     _ => {
                         debug_assert!(!opcode.is_call(), "Missed call opcode");
                         debug_assert!(
                             !opcode.can_trap(),
                             "Missed trap: {}",
@@ -306,17 +315,17 @@ impl<'a, 'b> BatchCompiler<'a, 'b> {
                 .display_inst(inst, Some(self.isa.as_ref()))
         );
         srcloc
     }
 
     /// Emit metadata for direct call `inst`.
     fn call_metadata(
         &self,
-        metadata: &mut Vec<bd::MetadataEntry>,
+        metadata: &mut Vec<bindings::MetadataEntry>,
         inst: ir::Inst,
         ret_addr: CodeOffset,
     ) {
         let func = &self.context.func;
 
         // This is a direct call, so the callee should be a non-imported wasm
         // function. We register both the call site *and* the target for relocation.
         let callee = match func.dfg[inst] {
@@ -327,47 +336,47 @@ impl<'a, 'b> BatchCompiler<'a, 'b> {
         let func_index = match *callee {
             ir::ExternalName::User {
                 namespace: USER_FUNCTION_NAMESPACE,
                 index,
             } => FuncIndex::new(index as usize),
             _ => panic!("Direct call to {} unsupported", callee),
         };
 
-        metadata.push(bd::MetadataEntry::direct_call(
+        metadata.push(bindings::MetadataEntry::direct_call(
             ret_addr,
             func_index,
             self.srcloc(inst),
         ));
     }
 
     /// Emit metadata for indirect call `inst`.
     fn indirect_call_metadata(
         &self,
-        metadata: &mut Vec<bd::MetadataEntry>,
+        metadata: &mut Vec<bindings::MetadataEntry>,
         inst: ir::Inst,
         ret_addr: CodeOffset,
     ) {
         // A call_indirect instruction can represent either a table call or a far call to a runtime
         // function. The CallSiteDesc::Kind enum does distinguish between the two, but it is not
         // clear that the information is used anywhere. For now, we won't bother distinguishing
         // them, and mark all calls as `Kind::Dynamic`.
         //
         // If we do need to make a distinction in the future, it is probably easiest to add a
         // `call_far` instruction to Cranelift that encodes like an indirect call, but includes the
         // callee like a direct call.
-        metadata.push(bd::MetadataEntry::indirect_call(
+        metadata.push(bindings::MetadataEntry::indirect_call(
             ret_addr,
             self.srcloc(inst),
         ));
     }
 
     fn trap_metadata(
         &self,
-        metadata: &mut Vec<bd::MetadataEntry>,
+        metadata: &mut Vec<bindings::MetadataEntry>,
         inst: ir::Inst,
         offset: CodeOffset,
     ) {
         let func = &self.context.func;
         let (code, trap_offset) = match func.dfg[inst] {
             ir::InstructionData::Trap { code, .. } => (code, 0),
             ir::InstructionData::IntCondTrap { code, .. }
             | ir::InstructionData::FloatCondTrap { code, .. } => {
@@ -375,40 +384,40 @@ impl<'a, 'b> BatchCompiler<'a, 'b> {
                 // The actual trap happens on the ud2 instruction.
                 (code, 2)
             }
             _ => panic!("Bad format for trap"),
         };
 
         // Translate the trap code into one of BaldrMonkey's trap codes.
         let bd_trap = match code {
-            ir::TrapCode::StackOverflow => bd::Trap::StackOverflow,
-            ir::TrapCode::HeapOutOfBounds => bd::Trap::OutOfBounds,
-            ir::TrapCode::OutOfBounds => bd::Trap::OutOfBounds,
-            ir::TrapCode::TableOutOfBounds => bd::Trap::OutOfBounds,
-            ir::TrapCode::IndirectCallToNull => bd::Trap::IndirectCallToNull,
-            ir::TrapCode::BadSignature => bd::Trap::IndirectCallBadSig,
-            ir::TrapCode::IntegerOverflow => bd::Trap::IntegerOverflow,
-            ir::TrapCode::IntegerDivisionByZero => bd::Trap::IntegerDivideByZero,
-            ir::TrapCode::BadConversionToInteger => bd::Trap::InvalidConversionToInteger,
-            ir::TrapCode::Interrupt => bd::Trap::CheckInterrupt,
-            ir::TrapCode::UnreachableCodeReached => bd::Trap::Unreachable,
+            ir::TrapCode::StackOverflow => bindings::Trap::StackOverflow,
+            ir::TrapCode::HeapOutOfBounds => bindings::Trap::OutOfBounds,
+            ir::TrapCode::OutOfBounds => bindings::Trap::OutOfBounds,
+            ir::TrapCode::TableOutOfBounds => bindings::Trap::OutOfBounds,
+            ir::TrapCode::IndirectCallToNull => bindings::Trap::IndirectCallToNull,
+            ir::TrapCode::BadSignature => bindings::Trap::IndirectCallBadSig,
+            ir::TrapCode::IntegerOverflow => bindings::Trap::IntegerOverflow,
+            ir::TrapCode::IntegerDivisionByZero => bindings::Trap::IntegerDivideByZero,
+            ir::TrapCode::BadConversionToInteger => bindings::Trap::InvalidConversionToInteger,
+            ir::TrapCode::Interrupt => bindings::Trap::CheckInterrupt,
+            ir::TrapCode::UnreachableCodeReached => bindings::Trap::Unreachable,
             ir::TrapCode::User(_) => panic!("Uncovered trap code {}", code),
         };
 
-        metadata.push(bd::MetadataEntry::trap(
+        metadata.push(bindings::MetadataEntry::trap(
             offset + trap_offset,
             self.srcloc(inst),
             bd_trap,
         ));
     }
 
     fn memory_metadata(
         &self,
-        metadata: &mut Vec<bd::MetadataEntry>,
+        metadata: &mut Vec<bindings::MetadataEntry>,
         inst: ir::Inst,
         offset: CodeOffset,
     ) {
         let func = &self.context.func;
         let memflags = match func.dfg[inst] {
             ir::InstructionData::Load { flags, .. }
             | ir::InstructionData::LoadComplex { flags, .. }
             | ir::InstructionData::Store { flags, .. }
@@ -418,17 +427,20 @@ impl<'a, 'b> BatchCompiler<'a, 'b> {
 
         // Some load/store instructions may be accessing VM data structures instead of the
         // WebAssembly heap. These are tagged with `notrap` since their trapping is not part of
         // the semantics, i.e. that would be a bug.
         if memflags.notrap() {
             return;
         }
 
-        metadata.push(bd::MetadataEntry::memory_access(offset, self.srcloc(inst)));
+        metadata.push(bindings::MetadataEntry::memory_access(
+            offset,
+            self.srcloc(inst),
+        ));
     }
 }
 
 impl<'a, 'b> fmt::Display for BatchCompiler<'a, 'b> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "{}", self.context.func.display(self.isa.as_ref()))
     }
 }
@@ -437,33 +449,38 @@ impl<'a, 'b> fmt::Display for BatchCompi
 pub fn wasm_function_name(func: FuncIndex) -> ir::ExternalName {
     ir::ExternalName::User {
         namespace: USER_FUNCTION_NAMESPACE,
         index: func.index() as u32,
     }
 }
 
 /// Create a Cranelift function name representing a builtin function.
-pub fn symbolic_function_name(sym: bd::SymbolicAddress) -> ir::ExternalName {
+pub fn symbolic_function_name(sym: bindings::SymbolicAddress) -> ir::ExternalName {
     ir::ExternalName::User {
         namespace: SYMBOLIC_FUNCTION_NAMESPACE,
         index: sym as u32,
     }
 }
 
 /// References joined so we can implement `RelocSink`.
 struct EmitEnv<'a> {
-    metadata: &'a mut Vec<bd::MetadataEntry>,
-    rodata_relocs: &'a mut Vec<CodeOffset>
+    metadata: &'a mut Vec<bindings::MetadataEntry>,
+    rodata_relocs: &'a mut Vec<CodeOffset>,
 }
 
 impl<'a> EmitEnv<'a> {
-    pub fn new(metadata: &'a mut Vec<bd::MetadataEntry>, rodata_relocs: &'a mut Vec<CodeOffset>)
-               -> EmitEnv<'a> {
-        EmitEnv { metadata, rodata_relocs }
+    pub fn new(
+        metadata: &'a mut Vec<bindings::MetadataEntry>,
+        rodata_relocs: &'a mut Vec<CodeOffset>,
+    ) -> EmitEnv<'a> {
+        EmitEnv {
+            metadata,
+            rodata_relocs,
+        }
     }
 }
 
 impl<'a> RelocSink for EmitEnv<'a> {
     fn reloc_ebb(&mut self, _offset: CodeOffset, _reloc: Reloc, _ebb_offset: CodeOffset) {
         unimplemented!();
     }
 
@@ -488,38 +505,38 @@ impl<'a> RelocSink for EmitEnv<'a> {
                 index,
             } => {
                 // This is a symbolic function reference encoded by `symbolic_function_name()`.
                 let sym = index.into();
 
                 // The symbolic access patch address points *after* the stored pointer.
                 let offset = offset + native_pointer_size() as u32;
                 self.metadata
-                    .push(bd::MetadataEntry::symbolic_access(offset, sym));
+                    .push(bindings::MetadataEntry::symbolic_access(offset, sym));
             }
 
             ir::ExternalName::LibCall(call) => {
                 let sym = match call {
-                    ir::LibCall::CeilF32 => bd::SymbolicAddress::CeilF32,
-                    ir::LibCall::CeilF64 => bd::SymbolicAddress::CeilF64,
-                    ir::LibCall::FloorF32 => bd::SymbolicAddress::FloorF32,
-                    ir::LibCall::FloorF64 => bd::SymbolicAddress::FloorF64,
-                    ir::LibCall::NearestF32 => bd::SymbolicAddress::NearestF32,
-                    ir::LibCall::NearestF64 => bd::SymbolicAddress::NearestF64,
-                    ir::LibCall::TruncF32 => bd::SymbolicAddress::TruncF32,
-                    ir::LibCall::TruncF64 => bd::SymbolicAddress::TruncF64,
+                    ir::LibCall::CeilF32 => bindings::SymbolicAddress::CeilF32,
+                    ir::LibCall::CeilF64 => bindings::SymbolicAddress::CeilF64,
+                    ir::LibCall::FloorF32 => bindings::SymbolicAddress::FloorF32,
+                    ir::LibCall::FloorF64 => bindings::SymbolicAddress::FloorF64,
+                    ir::LibCall::NearestF32 => bindings::SymbolicAddress::NearestF32,
+                    ir::LibCall::NearestF64 => bindings::SymbolicAddress::NearestF64,
+                    ir::LibCall::TruncF32 => bindings::SymbolicAddress::TruncF32,
+                    ir::LibCall::TruncF64 => bindings::SymbolicAddress::TruncF64,
                     _ => {
                         panic!("Don't understand external {}", name);
                     }
                 };
 
                 // The symbolic access patch address points *after* the stored pointer.
                 let offset = offset + native_pointer_size() as u32;
                 self.metadata
-                    .push(bd::MetadataEntry::symbolic_access(offset, sym));
+                    .push(bindings::MetadataEntry::symbolic_access(offset, sym));
             }
             _ => {
                 panic!("Don't understand external {}", name);
             }
         }
     }
 
     fn reloc_jt(&mut self, offset: CodeOffset, reloc: Reloc, _jt: ir::JumpTable) {
rename from js/src/wasm/cranelift/src/cpu.rs
rename to js/src/wasm/cranelift/src/isa.rs
--- a/js/src/wasm/cranelift/src/cpu.rs
+++ b/js/src/wasm/cranelift/src/isa.rs
@@ -16,84 +16,90 @@
 //! CPU detection and configuration of Cranelift's `TargetISA`.
 //!
 //! This module deals with the configuration of Cranelift to generate code for the current CPU that
 //! is compatible with the SpiderMonkey JIT.
 //!
 //! The main entry point is the `make_isa()` function which allocates a configured `TargetISA`
 //! object.
 
+use std::env;
+
 use cranelift_codegen::isa;
 use cranelift_codegen::settings::{self, Configurable};
-use std::str::FromStr;
-use utils::{BasicError, DashResult};
 
-use baldrdash::StaticEnvironment;
+use crate::bindings::StaticEnvironment;
+use crate::utils::{BasicError, DashResult};
 
 impl From<isa::LookupError> for BasicError {
     fn from(err: isa::LookupError) -> BasicError {
         BasicError::new(err.to_string())
     }
 }
 
 impl From<settings::SetError> for BasicError {
     fn from(err: settings::SetError) -> BasicError {
         BasicError::new(err.to_string())
     }
 }
 
-/// Allocate a `TargetISA` object that can be used to generate code for the CPU we're running on.
-///
-/// TODO: SM runs on more than x86 chips. Support them.
-///
-/// # Errors
-///
-/// This function fails if Cranelift has not been compiled with support for the current CPU.
-pub fn make_isa(env: &StaticEnvironment) -> DashResult<Box<dyn isa::TargetIsa>> {
-    // Start with the ISA-independent settings.
-    let shared_flags = make_shared_flags().expect("Cranelift configuration error");
+struct EnvVariableFlags<'env> {
+    opt_level: Option<&'env str>,
+    jump_tables: Option<bool>,
+}
+
+#[inline]
+fn str_to_bool(value: &str) -> bool {
+    value == "true" || value == "on" || value == "yes" || value == "1"
+}
+
+impl<'env> EnvVariableFlags<'env> {
+    fn parse(input: &'env Result<String, env::VarError>) -> Option<Self> {
+        let input = match input {
+            Ok(input) => input.as_str(),
+            Err(_) => return None,
+        };
+
+        let mut flags = EnvVariableFlags {
+            opt_level: None,
+            jump_tables: None,
+        };
 
-    // We can use `#[cfg(target_arch = "...")]` to conditionally compile code per ISA.
-    let mut ib = isa::lookup(triple!("x86_64-unknown-unknown")).map_err(BasicError::from)?;
+        for entry in input.split(",") {
+            if let Some(equals_index) = entry.find("=") {
+                let (key, value) = entry.split_at(equals_index);
+
+                // value starts with the =, remove it.
+                let value = &value[1..];
 
-    if !env.hasSse2 {
-        return Err("SSE2 is mandatory for Baldrdash!".into());
-    }
-    if env.hasSse3 {
-        ib.enable("has_sse3").map_err(BasicError::from)?;
+                match key {
+                    "opt_level" => {
+                        // Invalid values will be reported by Cranelift.
+                        flags.opt_level = Some(value);
+                    }
+                    "jump_tables" => {
+                        flags.jump_tables = Some(str_to_bool(value));
+                    }
+                    _ => {
+                        warn!("Unknown setting with key {}", key);
+                    }
+                }
+            } else {
+                warn!("Missing = in pair: {}", entry);
+            }
+        }
+
+        Some(flags)
     }
-    if env.hasSse41 {
-        ib.enable("has_sse41").map_err(BasicError::from)?;
-    }
-    if env.hasSse42 {
-        ib.enable("has_sse42").map_err(BasicError::from)?;
-    }
-    if env.hasPopcnt {
-        ib.enable("has_popcnt").map_err(BasicError::from)?;
-    }
-    if env.hasAvx {
-        ib.enable("has_avx").map_err(BasicError::from)?;
-    }
-    if env.hasBmi1 {
-        ib.enable("has_bmi1").map_err(BasicError::from)?;
-    }
-    if env.hasBmi2 {
-        ib.enable("has_bmi2").map_err(BasicError::from)?;
-    }
-    if env.hasLzcnt {
-        ib.enable("has_lzcnt").map_err(BasicError::from)?;
-    }
-
-    Ok(ib.finish(shared_flags))
 }
 
 /// Create a `Flags` object for the shared settings.
 ///
 /// This only fails if one of Cranelift's settings has been removed or renamed.
-fn make_shared_flags() -> settings::SetResult<settings::Flags> {
+fn make_shared_flags(env_flags: &Option<EnvVariableFlags>) -> settings::SetResult<settings::Flags> {
     let mut sb = settings::builder();
 
     // We don't install SIGFPE handlers, but depend on explicit traps around divisions.
     sb.enable("avoid_div_traps")?;
 
     // Cranelift needs to know how many words are pushed by `GenerateFunctionPrologue` so it can
     // compute frame pointer offsets accurately.
     //
@@ -111,16 +117,85 @@ fn make_shared_flags() -> settings::SetR
     // as it's quite slow.
     if !cfg!(debug_assertions) {
         sb.set("enable_verifier", "false")?;
     }
 
     // Baldrdash does its own stack overflow checks, so we don't need Cranelift doing any for us.
     sb.set("probestack_enabled", "false")?;
 
-    // Let's optimize for speed.
-    sb.set("opt_level", "best")?;
+    // Let's optimize for speed by default.
+    let opt_level = match env_flags {
+        Some(env_flags) => env_flags.opt_level,
+        None => None,
+    }
+    .unwrap_or("best");
+    sb.set("opt_level", opt_level)?;
 
-    // TODO: Enable jump tables (requires emitting readonly data separately from text).
-    sb.set("jump_tables_enabled", "true")?;
+    // Enable jump tables by default.
+    let jump_tables_enabled = match env_flags {
+        Some(env_flags) => env_flags.jump_tables,
+        None => None,
+    }
+    .unwrap_or(true);
+    sb.set(
+        "jump_tables_enabled",
+        if jump_tables_enabled { "true" } else { "false" },
+    )?;
 
     Ok(settings::Flags::new(sb))
 }
+
+#[cfg(feature = "cranelift_x86")]
+fn make_isa_specific(env: &StaticEnvironment) -> DashResult<isa::Builder> {
+    use std::str::FromStr; // for the triple! macro below.
+
+    let mut ib = isa::lookup(triple!("x86_64-unknown-unknown")).map_err(BasicError::from)?;
+
+    if !env.hasSse2 {
+        return Err("SSE2 is mandatory for Baldrdash!".into());
+    }
+
+    if env.hasSse3 {
+        ib.enable("has_sse3").map_err(BasicError::from)?;
+    }
+    if env.hasSse41 {
+        ib.enable("has_sse41").map_err(BasicError::from)?;
+    }
+    if env.hasSse42 {
+        ib.enable("has_sse42").map_err(BasicError::from)?;
+    }
+    if env.hasPopcnt {
+        ib.enable("has_popcnt").map_err(BasicError::from)?;
+    }
+    if env.hasAvx {
+        ib.enable("has_avx").map_err(BasicError::from)?;
+    }
+    if env.hasBmi1 {
+        ib.enable("has_bmi1").map_err(BasicError::from)?;
+    }
+    if env.hasBmi2 {
+        ib.enable("has_bmi2").map_err(BasicError::from)?;
+    }
+    if env.hasLzcnt {
+        ib.enable("has_lzcnt").map_err(BasicError::from)?;
+    }
+
+    Ok(ib)
+}
+
+/// TODO: SM runs on more than x86 chips. Support them.
+#[cfg(not(feature = "cranelift_x86"))]
+fn make_isa_specific(_env: &StaticEnvironment) -> DashResult<isa::Builder> {
+    Err("Platform not supported yet!".into())
+}
+
+/// Allocate a `TargetISA` object that can be used to generate code for the CPU we're running on.
+pub fn make_isa(env: &StaticEnvironment) -> DashResult<Box<dyn isa::TargetIsa>> {
+    // Parse flags defined by the environment variable.
+    let env_flags_str = std::env::var("CRANELIFT_FLAGS");
+    let env_flags = EnvVariableFlags::parse(&env_flags_str);
+
+    // Start with the ISA-independent settings.
+    let shared_flags = make_shared_flags(&env_flags).map_err(BasicError::from)?;
+    let ib = make_isa_specific(env)?;
+    Ok(ib.finish(shared_flags))
+}
--- a/js/src/wasm/cranelift/src/lib.rs
+++ b/js/src/wasm/cranelift/src/lib.rs
@@ -8,35 +8,34 @@
  *
  * 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.
  */
 
-extern crate cranelift_codegen;
-extern crate cranelift_wasm;
+#[cfg(feature = "cranelift_x86")]
 #[macro_use]
 extern crate target_lexicon;
+
 #[macro_use]
 extern crate log;
-extern crate env_logger;
 
-mod baldrapi; // Low-level C API, ignore this.
-mod baldrdash; // High-level Rust API, use this.
+mod bindings; // High-level bindings for C++ data structures.
 mod compile; // Cranelift function compiler.
-mod cpu; // CPU detection and `TargetISA` configuration.
+mod isa; // `TargetISA` configuration.
 mod utils; // Helpers for other source files.
 mod wasm2clif; // WebAssembly to Cranelift translation callbacks.
 
-use baldrdash::{CompiledFunc, FuncCompileInput, ModuleEnvironment, StaticEnvironment};
-use compile::BatchCompiler;
 use std::ptr;
 
+use crate::bindings::{CompiledFunc, FuncCompileInput, ModuleEnvironment, StaticEnvironment};
+use crate::compile::BatchCompiler;
+
 #[no_mangle]
 pub extern "C" fn cranelift_initialize() {
     // Gecko might set a logger before we do, which is all fine; try to initialize ours, and reset
     // the FilterLevel env_logger::try_init might have set to what it was in case of initialization
     // failure
     let filter = log::max_level();
     match env_logger::try_init() {
         Ok(_) => {}
@@ -47,17 +46,17 @@ pub extern "C" fn cranelift_initialize()
 }
 
 /// Allocate a compiler for a module environment and return an opaque handle.
 ///
 /// This is declared in `clifapi.h`.
 #[no_mangle]
 pub unsafe extern "C" fn cranelift_compiler_create<'a, 'b>(
     static_env: *const StaticEnvironment,
-    env: *const baldrapi::CraneliftModuleEnvironment,
+    env: *const bindings::LowLevelModuleEnvironment,
 ) -> *mut BatchCompiler<'a, 'b> {
     let env = env.as_ref().unwrap();
     let static_env = static_env.as_ref().unwrap();
     match BatchCompiler::new(static_env, ModuleEnvironment::new(env)) {
         Ok(compiler) => Box::into_raw(Box::new(compiler)),
         Err(err) => {
             error!("When constructing the batch compiler: {}", err);
             ptr::null_mut()
--- a/js/src/wasm/cranelift/src/wasm2clif.rs
+++ b/js/src/wasm/cranelift/src/wasm2clif.rs
@@ -13,30 +13,32 @@
  * limitations under the License.
  */
 
 //! This module deals with the translation of WebAssembly binary functions to Cranelift IR.
 //!
 //! The code here deals with adapting the `cranelift_wasm` module to the specifics of BaldrMonkey's
 //! internal data structures.
 
-use baldrdash as bd;
-use compile::{symbolic_function_name, wasm_function_name};
+use std::collections::HashMap;
+
 use cranelift_codegen::cursor::{Cursor, FuncCursor};
 use cranelift_codegen::entity::{EntityRef, PrimaryMap, SecondaryMap};
 use cranelift_codegen::ir;
 use cranelift_codegen::ir::condcodes::IntCC;
 use cranelift_codegen::ir::InstBuilder;
 use cranelift_codegen::isa::{CallConv, TargetFrontendConfig, TargetIsa};
 use cranelift_codegen::packed_option::PackedOption;
 use cranelift_wasm::{
     FuncEnvironment, FuncIndex, GlobalIndex, GlobalVariable, MemoryIndex, ReturnMode,
     SignatureIndex, TableIndex, WasmError, WasmResult,
 };
-use std::collections::HashMap;
+
+use crate::bindings;
+use crate::compile::{symbolic_function_name, wasm_function_name};
 
 /// Get the integer type used for representing pointers on this platform.
 fn native_pointer_type() -> ir::Type {
     if cfg!(target_pointer_width = "64") {
         ir::types::I64
     } else {
         ir::types::I32
     }
@@ -63,17 +65,17 @@ fn imm64(offset: usize) -> ir::immediate
 }
 
 /// Convert a usize offset into a `Uimm64`.
 fn uimm64(offset: usize) -> ir::immediates::Uimm64 {
     (offset as u64).into()
 }
 
 /// Initialize a `Signature` from a wasm signature.
-fn init_sig_from_wsig(sig: &mut ir::Signature, wsig: bd::FuncTypeWithId) -> WasmResult<()> {
+fn init_sig_from_wsig(sig: &mut ir::Signature, wsig: bindings::FuncTypeWithId) -> WasmResult<()> {
     sig.clear(CallConv::Baldrdash);
     for arg in wsig.args()? {
         sig.params.push(ir::AbiParam::new(arg));
     }
 
     if let Some(ret_type) = wsig.ret_type()? {
         let ret = match ret_type {
             // Spidermonkey requires i32 returns to have their high 32 bits
@@ -92,29 +94,29 @@ fn init_sig_from_wsig(sig: &mut ir::Sign
     ));
 
     Ok(())
 }
 
 /// Initialize the signature `sig` to match the function with `index` in `env`.
 pub fn init_sig(
     sig: &mut ir::Signature,
-    env: &bd::ModuleEnvironment,
+    env: &bindings::ModuleEnvironment,
     func_index: FuncIndex,
-) -> WasmResult<bd::FuncTypeWithId> {
+) -> WasmResult<bindings::FuncTypeWithId> {
     let wsig = env.function_signature(func_index);
     init_sig_from_wsig(sig, wsig)?;
     Ok(wsig)
 }
 
 /// A `TargetIsa` and `ModuleEnvironment` joined so we can implement `FuncEnvironment`.
 pub struct TransEnv<'a, 'b, 'c> {
     isa: &'a dyn TargetIsa,
-    env: &'b bd::ModuleEnvironment<'b>,
-    static_env: &'c bd::StaticEnvironment,
+    env: &'b bindings::ModuleEnvironment<'b>,
+    static_env: &'c bindings::StaticEnvironment,
 
     /// Information about the function pointer tables `self.env` knowns about. Indexed by table
     /// index.
     tables: PrimaryMap<TableIndex, TableInfo>,
 
     /// For those signatures whose ID is stored in a global, keep track of the globals we have
     /// created so far.
     ///
@@ -151,18 +153,18 @@ pub struct TransEnv<'a, 'b, 'c> {
 
     /// The address of the `realm` field in the `wasm::TlsData` struct.
     realm_addr: PackedOption<ir::GlobalValue>,
 }
 
 impl<'a, 'b, 'c> TransEnv<'a, 'b, 'c> {
     pub fn new(
         isa: &'a dyn TargetIsa,
-        env: &'b bd::ModuleEnvironment,
-        static_env: &'c bd::StaticEnvironment,
+        env: &'b bindings::ModuleEnvironment,
+        static_env: &'c bindings::StaticEnvironment,
     ) -> Self {
         TransEnv {
             isa,
             env,
             static_env,
             tables: PrimaryMap::new(),
             signatures: HashMap::new(),
             func_gvs: SecondaryMap::new(),
@@ -271,17 +273,17 @@ impl<'a, 'b, 'c> TransEnv<'a, 'b, 'c> {
         pos.ins().load(ir::types::I32, ir::MemFlags::new(), ga, 0)
     }
 
     /// Get a `FuncRef` for the given symbolic address.
     /// Uses the closure to create the signature if necessary.
     fn symbolic_funcref<MKSIG: FnOnce() -> ir::Signature>(
         &mut self,
         func: &mut ir::Function,
-        sym: bd::SymbolicAddress,
+        sym: bindings::SymbolicAddress,
         make_sig: MKSIG,
     ) -> (ir::FuncRef, ir::SigRef) {
         let symidx = sym as usize;
         if let Some(fnref) = self.symbolic[symidx].expand() {
             return (fnref, func.dfg.ext_funcs[fnref].signature);
         }
 
         // We need to allocate a signature and func-ref.
@@ -481,17 +483,17 @@ impl<'a, 'b, 'c> FuncEnvironment for Tra
         &mut self,
         func: &mut ir::Function,
         index: SignatureIndex,
     ) -> WasmResult<ir::SigRef> {
         let mut sigdata = ir::Signature::new(CallConv::Baldrdash);
         let wsig = self.env.signature(index);
         init_sig_from_wsig(&mut sigdata, wsig)?;
 
-        if wsig.id_kind() != bd::FuncTypeIdDescKind::None {
+        if wsig.id_kind() != bindings::FuncTypeIdDescKind::None {
             // A signature to be used for an indirect call also takes a signature id.
             sigdata.params.push(ir::AbiParam::special(
                 native_pointer_type(),
                 ir::ArgumentPurpose::SignatureId,
             ));
         }
 
         Ok(func.import_signature(sigdata))
@@ -559,23 +561,23 @@ impl<'a, 'b, 'c> FuncEnvironment for Tra
             return Err(WasmError::Unsupported("only one wasm table supported"));
         }
         let wtable = self.get_table(pos.func, table_index);
 
         // Follows `MacroAssembler::wasmCallIndirect`:
 
         // 1. Materialize the signature ID.
         let sigid_value = match wsig.id_kind() {
-            bd::FuncTypeIdDescKind::None => None,
-            bd::FuncTypeIdDescKind::Immediate => {
+            bindings::FuncTypeIdDescKind::None => None,
+            bindings::FuncTypeIdDescKind::Immediate => {
                 // The signature is represented as an immediate pointer-sized value.
                 let imm = wsig.id_immediate() as i64;
                 Some(pos.ins().iconst(native_pointer_type(), imm))
             }
-            bd::FuncTypeIdDescKind::Global => {
+            bindings::FuncTypeIdDescKind::Global => {
                 let gv = self.sig_global(pos.func, wsig.id_tls_offset());
                 let addr = pos.ins().global_value(native_pointer_type(), gv);
                 Some(
                     pos.ins()
                         .load(native_pointer_type(), ir::MemFlags::new(), addr, 0),
                 )
             }
         };
@@ -711,17 +713,17 @@ impl<'a, 'b, 'c> FuncEnvironment for Tra
         mut pos: FuncCursor,
         _index: MemoryIndex,
         _heap: ir::Heap,
         val: ir::Value,
     ) -> WasmResult<ir::Value> {
         // We emit a call to `uint32_t memoryGrow_i32(Instance* instance, uint32_t delta)` via a
         // stub.
         let (fnref, sigref) =
-            self.symbolic_funcref(pos.func, bd::SymbolicAddress::MemoryGrow, || {
+            self.symbolic_funcref(pos.func, bindings::SymbolicAddress::MemoryGrow, || {
                 let mut sig = ir::Signature::new(CallConv::Baldrdash);
                 sig.params.push(ir::AbiParam::new(native_pointer_type()));
                 sig.params.push(ir::AbiParam::new(ir::types::I32).uext());
                 sig.params.push(ir::AbiParam::special(
                     native_pointer_type(),
                     ir::ArgumentPurpose::VMContext,
                 ));
                 sig.returns.push(ir::AbiParam::new(ir::types::I32).uext());
@@ -747,17 +749,17 @@ impl<'a, 'b, 'c> FuncEnvironment for Tra
     fn translate_memory_size(
         &mut self,
         mut pos: FuncCursor,
         _index: MemoryIndex,
         _heap: ir::Heap,
     ) -> WasmResult<ir::Value> {
         // We emit a call to `uint32_t memorySize_i32(Instance* instance)` via a stub.
         let (fnref, sigref) =
-            self.symbolic_funcref(pos.func, bd::SymbolicAddress::MemorySize, || {
+            self.symbolic_funcref(pos.func, bindings::SymbolicAddress::MemorySize, || {
                 let mut sig = ir::Signature::new(CallConv::Baldrdash);
                 sig.params.push(ir::AbiParam::new(native_pointer_type()));
                 sig.params.push(ir::AbiParam::special(
                     native_pointer_type(),
                     ir::ArgumentPurpose::VMContext,
                 ));
                 sig.returns.push(ir::AbiParam::new(ir::types::I32).uext());
                 sig
@@ -795,17 +797,21 @@ struct TableInfo {
     ///
     /// 0: Unsigned 32-bit table length.
     /// n: Pointer to table (n = sizeof(void*))
     pub global: ir::GlobalValue,
 }
 
 impl TableInfo {
     /// Create a TableInfo and its global variable in `func`.
-    pub fn new(wtab: bd::TableDesc, func: &mut ir::Function, vmctx: ir::GlobalValue) -> TableInfo {
+    pub fn new(
+        wtab: bindings::TableDesc,
+        func: &mut ir::Function,
+        vmctx: ir::GlobalValue,
+    ) -> TableInfo {
         // Create the global variable.
         let offset = wtab.tls_offset();
         assert!(offset < i32::max_value() as usize);
         let offset = imm64(offset);
         let global = func.create_global_value(ir::GlobalValueData::IAddImm {
             base: vmctx,
             offset,
             global_type: native_pointer_type(),
--- a/security/nss/Makefile
+++ b/security/nss/Makefile
@@ -81,26 +81,24 @@ ifdef USE_DEBUG_RTL
 NSPR_CONFIGURE_OPTS += --enable-debug-rtl
 endif
 ifdef USE_STATIC_RTL
 NSPR_CONFIGURE_OPTS += --enable-static-rtl
 endif
 ifdef NS_USE_GCC
 NSPR_CONFIGURE_ENV = CC=gcc CXX=g++
 endif
+# Make sure to remove -arch arguments. NSPR can't handle that.
+remove_arch = $(filter-out __REMOVEME%,$(subst $(NULL) -arch , __REMOVEME,$(1)))
 ifdef CC
-NSPR_CONFIGURE_ENV = CC="$(CC)"
+NSPR_CONFIGURE_ENV = CC="$(call remove_arch,$(CC))"
 endif
 ifdef CCC
-NSPR_CONFIGURE_ENV += CXX="$(CCC)"
+NSPR_CONFIGURE_ENV += CXX="$(call remove_arch,$(CCC))"
 endif
-# Remove -arch definitions. NSPR can't handle that.
-NSPR_CONFIGURE_ENV := $(filter-out -arch x86_64,$(NSPR_CONFIGURE_ENV))
-NSPR_CONFIGURE_ENV := $(filter-out -arch i386,$(NSPR_CONFIGURE_ENV))
-NSPR_CONFIGURE_ENV := $(filter-out -arch ppc,$(NSPR_CONFIGURE_ENV))
 
 #
 # Some pwd commands on Windows (for example, the pwd
 # command in Cygwin) return a pathname that begins
 # with a (forward) slash.  When such a pathname is
 # passed to Windows build tools (for example, cl), it
 # is mistaken as a command-line option.  If that is the case,
 # we use a relative pathname as NSPR's prefix on Windows.
@@ -152,9 +150,8 @@ clean_docs:
 
 nss_RelEng_bld: import all
 
 package:
 	$(MAKE) -C pkg publish
 
 latest:
 	echo $(OBJDIR_NAME) > $(CORE_DEPTH)/../dist/latest
-
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-0c5d37301637
+NSS_3_45_BETA1
--- a/security/nss/automation/abi-check/expected-report-libssl3.so.txt
+++ b/security/nss/automation/abi-check/expected-report-libssl3.so.txt
@@ -0,0 +1,22 @@
+
+2 functions with some indirect sub-type change:
+
+  [C]'function SECStatus SSL_ConfigServerCert(PRFileDesc*, CERTCertificate*, SECKEYPrivateKey*, const SSLExtraServerCertData*, unsigned int)' at sslcert.c:640:1 has some indirect sub-type changes:
+    parameter 4 of type 'const SSLExtraServerCertData*' has sub-type changes:
+      in pointed to type 'const SSLExtraServerCertData':
+        in unqualified underlying type 'typedef SSLExtraServerCertData' at sslt.h:291:1:
+          underlying type 'struct SSLExtraServerCertDataStr' at sslt.h:256:1 changed:
+            type size changed from 256 to 384 (in bits)
+            2 data member insertions:
+              'const SECItem* SSLExtraServerCertDataStr::delegCred', at offset 256 (in bits) at sslt.h:283:1
+              'const SECKEYPrivateKey* SSLExtraServerCertDataStr::delegCredPrivKey', at offset 320 (in bits) at sslt.h:290:1
+
+  [C]'function SECStatus SSL_GetChannelInfo(PRFileDesc*, SSLChannelInfo*, PRUintn)' at sslinfo.c:13:1 has some indirect sub-type changes:
+    parameter 2 of type 'SSLChannelInfo*' has sub-type changes:
+      in pointed to type 'typedef SSLChannelInfo' at sslt.h:357:1:
+        underlying type 'struct SSLChannelInfoStr' at sslt.h:272:1 changed:
+          type size hasn't changed
+          1 data member insertion:
+            'PRBool SSLChannelInfoStr::peerDelegCred', at offset 928 (in bits) at sslt.h:353:1
+
+
--- a/security/nss/cmd/selfserv/selfserv.c
+++ b/security/nss/cmd/selfserv/selfserv.c
@@ -1921,17 +1921,17 @@ server_main(
         }
     }
 
     /* This uses the legacy certificate API.  See mySSLSNISocketConfig() for the
      * new, prefered API. */
     for (i = 0; i < certNicknameIndex; i++) {
         if (cert[i] != NULL) {
             const SSLExtraServerCertData ocspData = {
-                ssl_auth_null, NULL, certStatus[i], NULL
+                ssl_auth_null, NULL, certStatus[i], NULL, NULL, NULL
             };
 
             secStatus = SSL_ConfigServerCert(model_sock, cert[i],
                                              privKey[i], &ocspData,
                                              sizeof(ocspData));
             if (secStatus != SECSuccess)
                 errExit("SSL_ConfigServerCert");
         }
--- a/security/nss/cmd/tstclnt/tstclnt.c
+++ b/security/nss/cmd/tstclnt/tstclnt.c
@@ -208,16 +208,19 @@ printSecurityInfo(PRFileDesc *fd)
                 csa->len);
     }
     scts = SSL_PeerSignedCertTimestamps(fd);
     if (scts && scts->len) {
         fprintf(stderr, "Received a Signed Certificate Timestamp of length"
                         " %u\n",
                 scts->len);
     }
+    if (channel.peerDelegCred) {
+        fprintf(stderr, "Received a Delegated Credential\n");
+    }
 }
 
 static void
 PrintUsageHeader()
 {
     fprintf(stderr,
             "Usage:  %s -h host [-a 1st_hs_name ] [-a 2nd_hs_name ] [-p port]\n"
             "  [-D | -d certdir] [-C] [-b | -R root-module] \n"
@@ -267,16 +270,17 @@ PrintParameterUsage()
     fprintf(stderr, "%-20s Verbose progress reporting.\n", "-v");
     fprintf(stderr, "%-20s Ping the server and then exit.\n", "-q");
     fprintf(stderr, "%-20s Timeout for server ping (default: no timeout).\n", "-t seconds");
     fprintf(stderr, "%-20s Renegotiate N times (resuming session if N>1).\n", "-r N");
     fprintf(stderr, "%-20s Enable the session ticket extension.\n", "-u");
     fprintf(stderr, "%-20s Enable false start.\n", "-g");
     fprintf(stderr, "%-20s Enable the cert_status extension (OCSP stapling).\n", "-T");
     fprintf(stderr, "%-20s Enable the signed_certificate_timestamp extension.\n", "-U");
+    fprintf(stderr, "%-20s Enable the delegated credentials extension.\n", "-B");
     fprintf(stderr, "%-20s Require fresh revocation info from side channel.\n"
                     "%-20s -F once means: require for server cert only\n"
                     "%-20s -F twice means: require for intermediates, too\n"
                     "%-20s (Connect, handshake with server, disable dynamic download\n"
                     "%-20s  of OCSP/CRL, verify cert using CERT_PKIXVerifyCert.)\n"
                     "%-20s Exit code:\n"
                     "%-20s 0: have fresh and valid revocation data, status good\n"
                     "%-20s 1: cert failed to verify, prior to revocation checking\n"
@@ -988,16 +992,17 @@ PRBool enableAltServerHello = PR_FALSE;
 PRBool useDTLS = PR_FALSE;
 PRBool actAsServer = PR_FALSE;
 PRBool stopAfterHandshake = PR_FALSE;
 PRBool requestToExit = PR_FALSE;
 char *versionString = NULL;
 PRBool handshakeComplete = PR_FALSE;
 char *encryptedSNIKeys = NULL;
 PRBool enablePostHandshakeAuth = PR_FALSE;
+PRBool enableDelegatedCredentials = PR_FALSE;
 
 static int
 writeBytesToServer(PRFileDesc *s, const PRUint8 *buf, int nb)
 {
     SECStatus rv;
     const PRUint8 *bufp = buf;
     PRPollDesc pollDesc;
 
@@ -1360,16 +1365,24 @@ run()
     /* enable cert status (OCSP stapling). */
     rv = SSL_OptionSet(s, SSL_ENABLE_OCSP_STAPLING, enableCertStatus);
     if (rv != SECSuccess) {
         SECU_PrintError(progName, "error enabling cert status (OCSP stapling)");
         error = 1;
         goto done;
     }
 
+    /* enable negotiation of delegated credentials (draft-ietf-tls-subcerts) */
+    rv = SSL_OptionSet(s, SSL_ENABLE_DELEGATED_CREDENTIALS, enableDelegatedCredentials);
+    if (rv != SECSuccess) {
+        SECU_PrintError(progName, "error enabling delegated credentials");
+        error = 1;
+        goto done;
+    }
+
     /* enable extended master secret mode */
     if (enableExtendedMasterSecret) {
         rv = SSL_OptionSet(s, SSL_ENABLE_EXTENDED_MASTER_SECRET, PR_TRUE);
         if (rv != SECSuccess) {
             SECU_PrintError(progName, "error enabling extended master secret");
             error = 1;
             goto done;
         }
@@ -1710,22 +1723,21 @@ main(int argc, char **argv)
     tmp = PR_GetEnvSecure("NSS_DEBUG_TIMEOUT");
     if (tmp && tmp[0]) {
         int sec = PORT_Atoi(tmp);
         if (sec > 0) {
             maxInterval = PR_SecondsToInterval(sec);
         }
     }
 
-    /* Note: 'B' was used in the past but removed in 3.28
-     *       'z' was removed in 3.39
+    /* Note: 'z' was removed in 3.39
      * Please leave some time before reusing these.
      */
     optstate = PL_CreateOptState(argc, argv,
-                                 "46A:CDEFGHI:J:KL:M:N:OP:QR:STUV:W:X:YZa:bc:d:fgh:m:n:op:qr:st:uvw:");
+                                 "46A:BCDEFGHI:J:KL:M:N:OP:QR:STUV:W:X:YZa:bc:d:fgh:m:n:op:qr:st:uvw:");
     while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
         switch (optstate->option) {
             case '?':
             default:
                 Usage();
                 break;
 
             case '4':
@@ -1738,16 +1750,20 @@ main(int argc, char **argv)
                 if (!allowIPv6)
                     Usage();
                 break;
 
             case 'A':
                 requestFile = PORT_Strdup(optstate->value);
                 break;
 
+            case 'B':
+                enableDelegatedCredentials = PR_TRUE;
+                break;
+
             case 'C':
                 ++dumpServerChain;
                 break;
 
             case 'D':
                 openDB = PR_FALSE;
                 break;
 
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/security/nss/gtests/ssl_gtest/manifest.mn
+++ b/security/nss/gtests/ssl_gtest/manifest.mn
@@ -49,16 +49,17 @@ CPPSRCS = \
       ssl_versionpolicy_unittest.cc \
       selfencrypt_unittest.cc \
       test_io.cc \
       tls_agent.cc \
       tls_connect.cc \
       tls_hkdf_unittest.cc \
       tls_filter.cc \
       tls_protect.cc \
+      tls_subcerts_unittest.cc \
       tls_esni_unittest.cc \
       $(SSLKEYLOGFILE_FILES) \
       $(NULL)
 
 INCLUDES += -I$(CORE_DEPTH)/gtests/google_test/gtest/include \
             -I$(CORE_DEPTH)/gtests/common \
             -I$(CORE_DEPTH)/cpputil
 
--- a/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
@@ -1317,21 +1317,21 @@ TEST_P(TlsConnectGeneric, AuthFailImmedi
   client_->SetAuthCertificateCallback(AuthCompleteFail);
 
   StartConnect();
   ConnectExpectAlert(client_, kTlsAlertBadCertificate);
   client_->CheckErrorCode(SSL_ERROR_BAD_CERTIFICATE);
 }
 
 static const SSLExtraServerCertData ServerCertDataRsaPkcs1Decrypt = {
-    ssl_auth_rsa_decrypt, nullptr, nullptr, nullptr};
+    ssl_auth_rsa_decrypt, nullptr, nullptr, nullptr, nullptr, nullptr};
 static const SSLExtraServerCertData ServerCertDataRsaPkcs1Sign = {
-    ssl_auth_rsa_sign, nullptr, nullptr, nullptr};
+    ssl_auth_rsa_sign, nullptr, nullptr, nullptr, nullptr, nullptr};
 static const SSLExtraServerCertData ServerCertDataRsaPss = {
-    ssl_auth_rsa_pss, nullptr, nullptr, nullptr};
+    ssl_auth_rsa_pss, nullptr, nullptr, nullptr, nullptr, nullptr};
 
 // Test RSA cert with usage=[signature, encipherment].
 TEST_F(TlsAgentStreamTestServer, ConfigureCertRsaPkcs1SignAndKEX) {
   Reset(TlsAgent::kServerRsa);
 
   PRFileDesc* ssl_fd = agent_->ssl_fd();
   EXPECT_TRUE(SSLInt_HasCertWithAuthType(ssl_fd, ssl_auth_rsa_decrypt));
   EXPECT_TRUE(SSLInt_HasCertWithAuthType(ssl_fd, ssl_auth_rsa_sign));
--- a/security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc
@@ -59,18 +59,18 @@ class SignedCertificateTimestampsExtract
   std::unique_ptr<DataBuffer> auth_timestamps_;
   std::unique_ptr<DataBuffer> handshake_timestamps_;
 };
 
 static const uint8_t kSctValue[] = {0x01, 0x23, 0x45, 0x67, 0x89};
 static const SECItem kSctItem = {siBuffer, const_cast<uint8_t*>(kSctValue),
                                  sizeof(kSctValue)};
 static const DataBuffer kSctBuffer(kSctValue, sizeof(kSctValue));
-static const SSLExtraServerCertData kExtraSctData = {ssl_auth_null, nullptr,
-                                                     nullptr, &kSctItem};
+static const SSLExtraServerCertData kExtraSctData = {
+    ssl_auth_null, nullptr, nullptr, &kSctItem, nullptr, nullptr};
 
 // Test timestamps extraction during a successful handshake.
 TEST_P(TlsConnectGenericPre13, SignedCertificateTimestampsLegacy) {
   EnsureTlsSetup();
 
   // We have to use the legacy API consistently here for configuring certs.
   // Also, this doesn't work in TLS 1.3 because this only configures the SCT for
   // RSA decrypt and PKCS#1 signing, not PSS.
@@ -142,18 +142,18 @@ static SECStatus CheckNoOCSP(TlsAgent* a
 
 static const uint8_t kOcspValue1[] = {1, 2, 3, 4, 5, 6};
 static const uint8_t kOcspValue2[] = {7, 8, 9};
 static const SECItem kOcspItems[] = {
     {siBuffer, const_cast<uint8_t*>(kOcspValue1), sizeof(kOcspValue1)},
     {siBuffer, const_cast<uint8_t*>(kOcspValue2), sizeof(kOcspValue2)}};
 static const SECItemArray kOcspResponses = {const_cast<SECItem*>(kOcspItems),
                                             PR_ARRAY_SIZE(kOcspItems)};
-const static SSLExtraServerCertData kOcspExtraData = {ssl_auth_null, nullptr,
-                                                      &kOcspResponses, nullptr};
+const static SSLExtraServerCertData kOcspExtraData = {
+    ssl_auth_null, nullptr, &kOcspResponses, nullptr, nullptr, nullptr};
 
 TEST_P(TlsConnectGeneric, NoOcsp) {
   EnsureTlsSetup();
   client_->SetAuthCertificateCallback(CheckNoOCSP);
   Connect();
 }
 
 // The client doesn't get OCSP stapling unless it asks.
@@ -219,17 +219,17 @@ TEST_P(TlsConnectGeneric, OcspHugeSucces
 
   uint8_t hugeOcspValue[16385];
   memset(hugeOcspValue, 0xa1, sizeof(hugeOcspValue));
   const SECItem hugeOcspItems[] = {
       {siBuffer, const_cast<uint8_t*>(hugeOcspValue), sizeof(hugeOcspValue)}};
   const SECItemArray hugeOcspResponses = {const_cast<SECItem*>(hugeOcspItems),
                                           PR_ARRAY_SIZE(hugeOcspItems)};
   const SSLExtraServerCertData hugeOcspExtraData = {
-      ssl_auth_null, nullptr, &hugeOcspResponses, nullptr};
+      ssl_auth_null, nullptr, &hugeOcspResponses, nullptr, nullptr, nullptr};
 
   // The value should be available during the AuthCertificateCallback
   client_->SetAuthCertificateCallback([&](TlsAgent* agent, bool checksig,
                                           bool isServer) -> SECStatus {
     const SECItemArray* ocsp = SSL_PeerStapledOCSPResponses(agent->ssl_fd());
     if (!ocsp) {
       return SECFailure;
     }
--- a/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
+++ b/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
@@ -49,17 +49,18 @@
         'ssl_version_unittest.cc',
         'ssl_versionpolicy_unittest.cc',
         'test_io.cc',
         'tls_agent.cc',
         'tls_connect.cc',
         'tls_filter.cc',
         'tls_hkdf_unittest.cc',
         'tls_esni_unittest.cc',
-        'tls_protect.cc'
+        'tls_protect.cc',
+        'tls_subcerts_unittest.cc'
       ],
       'dependencies': [
         '<(DEPTH)/exports.gyp:nss_exports',
         '<(DEPTH)/lib/util/util.gyp:nssutil3',
         '<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
         '<(DEPTH)/lib/smime/smime.gyp:smime',
         '<(DEPTH)/lib/ssl/ssl.gyp:ssl',
         '<(DEPTH)/lib/nss/nss.gyp:nss_static',
--- a/security/nss/gtests/ssl_gtest/tls_agent.cc
+++ b/security/nss/gtests/ssl_gtest/tls_agent.cc
@@ -42,16 +42,17 @@ const std::string TlsAgent::kServerRsaSi
 const std::string TlsAgent::kServerRsaPss = "rsa_pss";
 const std::string TlsAgent::kServerRsaDecrypt = "rsa_decrypt";
 const std::string TlsAgent::kServerEcdsa256 = "ecdsa256";
 const std::string TlsAgent::kServerEcdsa384 = "ecdsa384";
 const std::string TlsAgent::kServerEcdsa521 = "ecdsa521";
 const std::string TlsAgent::kServerEcdhRsa = "ecdh_rsa";
 const std::string TlsAgent::kServerEcdhEcdsa = "ecdh_ecdsa";
 const std::string TlsAgent::kServerDsa = "dsa";
+const std::string TlsAgent::kDelegatorEcdsa256 = "delegator_ecdsa256";
 
 static const uint8_t kCannedTls13ServerHello[] = {
     0x03, 0x03, 0x9c, 0xbc, 0x14, 0x9b, 0x0e, 0x2e, 0xfa, 0x0d, 0xf3,
     0xf0, 0x5c, 0x70, 0x7a, 0xe0, 0xd1, 0x9b, 0x3e, 0x5a, 0x44, 0x6b,
     0xdf, 0xe5, 0xc2, 0x28, 0x64, 0xf7, 0x00, 0xc1, 0x9c, 0x08, 0x76,
     0x08, 0x00, 0x13, 0x01, 0x00, 0x00, 0x2e, 0x00, 0x33, 0x00, 0x24,
     0x00, 0x1d, 0x00, 0x20, 0xc2, 0xcf, 0x23, 0x17, 0x64, 0x23, 0x03,
     0xf0, 0xfb, 0x45, 0x98, 0x26, 0xd1, 0x65, 0x24, 0xa1, 0x6c, 0xa9,
@@ -132,16 +133,69 @@ void TlsAgent::SetState(State s) {
 
   priv->reset(PK11_FindKeyByAnyCert(cert->get(), nullptr));
   EXPECT_NE(nullptr, priv->get());
   if (!priv->get()) return false;
 
   return true;
 }
 
+// Loads a key pair from the certificate identified by |id|.
+/*static*/ bool TlsAgent::LoadKeyPairFromCert(const std::string& name,
+                                              ScopedSECKEYPublicKey* pub,
+                                              ScopedSECKEYPrivateKey* priv) {
+  ScopedCERTCertificate cert;
+  if (!TlsAgent::LoadCertificate(name, &cert, priv)) {
+    return false;
+  }
+
+  pub->reset(SECKEY_ExtractPublicKey(&cert->subjectPublicKeyInfo));
+  if (!pub->get()) {
+    return false;
+  }
+
+  return true;
+}
+
+void TlsAgent::DelegateCredential(const std::string& name,
+                                  const ScopedSECKEYPublicKey& dc_pub,
+                                  SSLSignatureScheme dc_cert_verify_alg,
+                                  PRUint32 dc_valid_for, PRTime now,
+                                  SECItem* dc) {
+  ScopedCERTCertificate cert;
+  ScopedSECKEYPrivateKey certPriv;
+  EXPECT_TRUE(TlsAgent::LoadCertificate(name, &cert, &certPriv));
+  EXPECT_EQ(SECSuccess,
+            SSL_DelegateCredential(cert.get(), certPriv.get(), dc_pub.get(),
+                                   dc_cert_verify_alg, dc_valid_for, now, dc));
+}
+
+void TlsAgent::EnableDelegatedCredentials() {
+  ASSERT_TRUE(EnsureTlsSetup());
+  SetOption(SSL_ENABLE_DELEGATED_CREDENTIALS, PR_TRUE);
+}
+
+void TlsAgent::AddDelegatedCredential(const std::string& dc_name,
+                                      SSLSignatureScheme dc_cert_verify_alg,
+                                      PRUint32 dc_valid_for, PRTime now) {
+  ASSERT_TRUE(EnsureTlsSetup());
+
+  ScopedSECKEYPublicKey pub;
+  ScopedSECKEYPrivateKey priv;
+  EXPECT_TRUE(TlsAgent::LoadKeyPairFromCert(dc_name, &pub, &priv));
+
+  StackSECItem dc;
+  TlsAgent::DelegateCredential(name_, pub, dc_cert_verify_alg, dc_valid_for,
+                               now, &dc);
+
+  SSLExtraServerCertData extra_data = {ssl_auth_null, nullptr, nullptr,
+                                       nullptr,       &dc,     priv.get()};
+  EXPECT_TRUE(ConfigServerCert(name_, true, &extra_data));
+}
+
 bool TlsAgent::ConfigServerCert(const std::string& id, bool updateKeyBits,
                                 const SSLExtraServerCertData* serverCertData) {
   ScopedCERTCertificate cert;
   ScopedSECKEYPrivateKey priv;
   if (!TlsAgent::LoadCertificate(id, &cert, &priv)) {
     return false;
   }
 
@@ -313,16 +367,20 @@ bool TlsAgent::GetPeerChainLength(size_t
 
   return true;
 }
 
 void TlsAgent::CheckCipherSuite(uint16_t suite) {
   EXPECT_EQ(csinfo_.cipherSuite, suite);
 }
 
+void TlsAgent::CheckPeerDelegCred(bool expected) {
+  EXPECT_EQ(expected, info_.peerDelegCred);
+}
+
 void TlsAgent::RequestClientAuth(bool requireAuth) {
   ASSERT_EQ(SERVER, role_);
 
   SetOption(SSL_REQUEST_CERTIFICATE, PR_TRUE);
   SetOption(SSL_REQUIRE_CERTIFICATE, requireAuth ? PR_TRUE : PR_FALSE);
 
   EXPECT_EQ(SECSuccess, SSL_AuthCertificateHook(
                             ssl_fd(), &TlsAgent::ClientAuthenticated, this));
--- a/security/nss/gtests/ssl_gtest/tls_agent.h
+++ b/security/nss/gtests/ssl_gtest/tls_agent.h
@@ -71,16 +71,17 @@ class TlsAgent : public PollTarget {
   static const std::string kServerRsaPss;
   static const std::string kServerRsaDecrypt;
   static const std::string kServerEcdsa256;
   static const std::string kServerEcdsa384;
   static const std::string kServerEcdsa521;
   static const std::string kServerEcdhEcdsa;
   static const std::string kServerEcdhRsa;
   static const std::string kServerDsa;
+  static const std::string kDelegatorEcdsa256;  // draft-ietf-tls-subcerts
 
   TlsAgent(const std::string& name, Role role, SSLProtocolVariant variant);
   virtual ~TlsAgent();
 
   void SetPeer(std::shared_ptr<TlsAgent>& peer) {
     adapter_->SetPeer(peer->adapter_);
   }
 
@@ -108,16 +109,36 @@ class TlsAgent : public PollTarget {
   void PrepareForRenegotiate();
   // Prepares for renegotiation, then actually triggers it.
   void StartRenegotiate();
   void SetAntiReplayContext(ScopedSSLAntiReplayContext& ctx);
 
   static bool LoadCertificate(const std::string& name,
                               ScopedCERTCertificate* cert,
                               ScopedSECKEYPrivateKey* priv);
+  static bool LoadKeyPairFromCert(const std::string& name,
+                                  ScopedSECKEYPublicKey* pub,
+                                  ScopedSECKEYPrivateKey* priv);
+
+  // Delegated credentials.
+  //
+  // Generate a delegated credential and sign it using the certificate
+  // associated with |name|.
+  static void DelegateCredential(const std::string& name,
+                                 const ScopedSECKEYPublicKey& dcPub,
+                                 SSLSignatureScheme dcCertVerifyAlg,
+                                 PRUint32 dcValidFor, PRTime now, SECItem* dc);
+  // Indicate support for the delegated credentials extension.
+  void EnableDelegatedCredentials();
+  // Generate and configure a delegated credential to use in the handshake with
+  // clients that support this extension..
+  void AddDelegatedCredential(const std::string& dc_name,
+                              SSLSignatureScheme dcCertVerifyAlg,
+                              PRUint32 dcValidFor, PRTime now);
+
   bool ConfigServerCert(const std::string& name, bool updateKeyBits = false,
                         const SSLExtraServerCertData* serverCertData = nullptr);
   bool ConfigServerCertWithChain(const std::string& name);
   bool EnsureTlsSetup(PRFileDesc* modelSocket = nullptr);
 
   void SetupClientAuth();
   void RequestClientAuth(bool requireAuth);
 
@@ -158,16 +179,17 @@ class TlsAgent : public PollTarget {
   void CheckExtendedMasterSecret(bool expected);
   void CheckEarlyDataAccepted(bool expected);
   void SetDowngradeCheckVersion(uint16_t version);
   void CheckSecretsDestroyed();
   void ConfigNamedGroups(const std::vector<SSLNamedGroup>& groups);
   void DisableECDHEServerKeyReuse();
   bool GetPeerChainLength(size_t* count);
   void CheckCipherSuite(uint16_t cipher_suite);
+  void CheckPeerDelegCred(bool expected);
   void SetResumptionTokenCallback();
   bool MaybeSetResumptionToken();
   void SetResumptionToken(const std::vector<uint8_t>& resumption_token) {
     resumption_token_ = resumption_token;
   }
   const std::vector<uint8_t>& GetResumptionToken() const {
     return resumption_token_;
   }
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/tls_subcerts_unittest.cc
@@ -0,0 +1,238 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=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 <ctime>
+
+#include "secerr.h"
+#include "ssl.h"
+
+#include "gtest_utils.h"
+#include "tls_agent.h"
+#include "tls_connect.h"
+
+namespace nss_test {
+
+const std::string kDelegatorId = TlsAgent::kDelegatorEcdsa256;
+const std::string kDCId = TlsAgent::kServerEcdsa256;
+const SSLSignatureScheme kDCScheme = ssl_sig_ecdsa_secp256r1_sha256;
+const PRUint32 kDCValidFor = 60 * 60 * 24 * 7 /* 1 week (seconds */;
+
+// Attempt to configure a DC when either the DC or DC private key is missing.
+TEST_P(TlsConnectTls13, DCNotConfigured) {
+  // Load and delegate the credential.
+  ScopedSECKEYPublicKey pub;
+  ScopedSECKEYPrivateKey priv;
+  EXPECT_TRUE(TlsAgent::LoadKeyPairFromCert(kDCId, &pub, &priv));
+
+  StackSECItem dc;
+  TlsAgent::DelegateCredential(kDelegatorId, pub, kDCScheme, kDCValidFor, now(),
+                               &dc);
+
+  // Attempt to install the certificate and DC with a missing DC private key.
+  EnsureTlsSetup();
+  SSLExtraServerCertData extra_data_missing_dc_priv_key = {
+      ssl_auth_null, nullptr, nullptr, nullptr, &dc, nullptr};
+  EXPECT_FALSE(server_->ConfigServerCert(kDelegatorId, true,
+                                         &extra_data_missing_dc_priv_key));
+
+  // Attempt to install the certificate and with only the DC private key.
+  EnsureTlsSetup();
+  SSLExtraServerCertData extra_data_missing_dc = {
+      ssl_auth_null, nullptr, nullptr, nullptr, nullptr, priv.get()};
+  EXPECT_FALSE(
+      server_->ConfigServerCert(kDelegatorId, true, &extra_data_missing_dc));
+}
+
+// Connected with ECDSA-P256.
+TEST_P(TlsConnectTls13, DCConnectEcdsaP256) {
+  Reset(kDelegatorId);
+  client_->EnableDelegatedCredentials();
+  server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
+
+  auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
+      client_, ssl_delegated_credentials_xtn);
+  Connect();
+
+  EXPECT_TRUE(cfilter->captured());
+  client_->CheckPeerDelegCred(true);
+}
+
+// Connected with ECDSA-P521.
+TEST_P(TlsConnectTls13, DCConnectEcdsaP521) {
+  Reset(kDelegatorId);
+  client_->EnableDelegatedCredentials();
+  server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521,
+                                  ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor,
+                                  now());
+  client_->EnableDelegatedCredentials();
+
+  auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
+      client_, ssl_delegated_credentials_xtn);
+  Connect();
+
+  EXPECT_TRUE(cfilter->captured());
+  client_->CheckPeerDelegCred(true);
+}
+
+// Connected with RSA-PSS.
+TEST_P(TlsConnectTls13, DCConnectRsaPss) {
+  Reset(kDelegatorId);
+  client_->EnableDelegatedCredentials();
+  server_->AddDelegatedCredential(
+      TlsAgent::kServerRsaPss, ssl_sig_rsa_pss_rsae_sha256, kDCValidFor, now());
+
+  auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
+      client_, ssl_delegated_credentials_xtn);
+  Connect();
+
+  EXPECT_TRUE(cfilter->captured());
+  client_->CheckPeerDelegCred(true);
+}
+
+// Aborted because of incorrect DC signature algorithm indication.
+TEST_P(TlsConnectTls13, DCAbortBadExpectedCertVerifyAlg) {
+  Reset(kDelegatorId);
+  client_->EnableDelegatedCredentials();
+  server_->AddDelegatedCredential(TlsAgent::kServerEcdsa256,
+                                  ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor,
+                                  now());
+  ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+}
+
+// Aborted because of invalid DC signature.
+TEST_P(TlsConnectTls13, DCABortBadSignature) {
+  Reset(kDelegatorId);
+  EnsureTlsSetup();
+  client_->EnableDelegatedCredentials();
+
+  ScopedSECKEYPublicKey pub;
+  ScopedSECKEYPrivateKey priv;
+  EXPECT_TRUE(TlsAgent::LoadKeyPairFromCert(kDCId, &pub, &priv));
+
+  StackSECItem dc;
+  TlsAgent::DelegateCredential(kDelegatorId, pub, kDCScheme, kDCValidFor, now(),
+                               &dc);
+
+  // Flip the first bit of the DC so that the signature is invalid.
+  dc.data[0] ^= 0x01;
+
+  SSLExtraServerCertData extra_data = {ssl_auth_null, nullptr, nullptr,
+                                       nullptr,       &dc,     priv.get()};
+  EXPECT_TRUE(server_->ConfigServerCert(kDelegatorId, true, &extra_data));
+
+  ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+}
+
+// Aborted because of expired DC.
+TEST_P(TlsConnectTls13, DCAbortExpired) {
+  Reset(kDelegatorId);
+  server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
+  client_->EnableDelegatedCredentials();
+  // When the client checks the time, it will be at least one second after the
+  // DC expired.
+  AdvanceTime((static_cast<PRTime>(kDCValidFor) + 1) * PR_USEC_PER_SEC);
+  ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+}
+
+// Aborted because of invalid key usage.
+TEST_P(TlsConnectTls13, DCAbortBadKeyUsage) {
+  // The sever does not have the delegationUsage extension.
+  Reset(TlsAgent::kServerEcdsa256);
+  client_->EnableDelegatedCredentials();
+  server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
+  ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+}
+
+// Connected without DC because of no client indication.
+TEST_P(TlsConnectTls13, DCConnectNoClientSupport) {
+  Reset(kDelegatorId);
+  server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
+
+  auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
+      client_, ssl_delegated_credentials_xtn);
+  Connect();
+
+  EXPECT_FALSE(cfilter->captured());
+  client_->CheckPeerDelegCred(false);
+}
+
+// Connected without DC because of no server DC.
+TEST_P(TlsConnectTls13, DCConnectNoServerSupport) {
+  Reset(kDelegatorId);
+  client_->EnableDelegatedCredentials();
+
+  auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
+      client_, ssl_delegated_credentials_xtn);
+  Connect();
+
+  EXPECT_TRUE(cfilter->captured());
+  client_->CheckPeerDelegCred(false);
+}
+
+// Connected without DC because client doesn't support TLS 1.3.
+TEST_P(TlsConnectTls13, DCConnectClientNoTls13) {
+  Reset(kDelegatorId);
+  client_->EnableDelegatedCredentials();
+  server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
+
+  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+                           SSL_LIBRARY_VERSION_TLS_1_2);
+  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+                           SSL_LIBRARY_VERSION_TLS_1_3);
+
+  auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
+      client_, ssl_delegated_credentials_xtn);
+  Connect();
+
+  // Should fallback to TLS 1.2 and not negotiate a DC.
+  EXPECT_FALSE(cfilter->captured());
+  client_->CheckPeerDelegCred(false);
+}
+
+// Connected without DC because server doesn't support TLS 1.3.
+TEST_P(TlsConnectTls13, DCConnectServerNoTls13) {
+  Reset(kDelegatorId);
+  client_->EnableDelegatedCredentials();
+  server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
+
+  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+                           SSL_LIBRARY_VERSION_TLS_1_3);
+  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+                           SSL_LIBRARY_VERSION_TLS_1_2);
+
+  auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
+      client_, ssl_delegated_credentials_xtn);
+  Connect();
+
+  // Should fallback to TLS 1.2 and not negotiate a DC. The client will still
+  // send the indication because it supports 1.3.
+  EXPECT_TRUE(cfilter->captured());
+  client_->CheckPeerDelegCred(false);
+}
+
+// Connected without DC because client doesn't support the signature scheme.
+TEST_P(TlsConnectTls13, DCConnectExpectedCertVerifyAlgNotSupported) {
+  Reset(kDelegatorId);
+  client_->EnableDelegatedCredentials();
+  static const SSLSignatureScheme kClientSchemes[] = {
+      ssl_sig_ecdsa_secp256r1_sha256,
+  };
+  client_->SetSignatureSchemes(kClientSchemes, PR_ARRAY_SIZE(kClientSchemes));
+
+  server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521,
+                                  ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor,
+                                  now());
+
+  auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
+      client_, ssl_delegated_credentials_xtn);
+  Connect();
+
+  // Client sends indication, but the server doesn't send a DC.
+  EXPECT_TRUE(cfilter->captured());
+  client_->CheckPeerDelegCred(false);
+}
+
+}  // namespace nss_test
--- a/security/nss/help.txt
+++ b/security/nss/help.txt
@@ -1,10 +1,10 @@
 Usage: build.sh [-h] [-c|-cc] [-v] [-j <n>] [--gyp|-g] [--opt|-o]
-                [-t <x64|x86|...>|--target=<x64|x86|...>]
+                [-t <x64|ia32|...>|--target=<x64|ia32|...>]
                 [--clang|--gcc|--msvc] [--scan-build[=dir]] [--disable-tests]
                 [--pprof] [--asan] [--msan] [--ubsan[=bool,shift,...]
                 [--fuzz[=tls|oss]] [--sancov[=edge|bb|func|...]]
                 [--emit-llvm] [--no-zdefs] [--static] [--ct-verif]
                 [--nspr|--with-nspr=<include>:<lib>|--system-nspr]
                 [--system-sqlite] [--enable-fips] [--enable-libpkix]
                 [--mozpkix-only] [-D<gyp-option>]
 
@@ -14,17 +14,17 @@ NSS build tool options:
 
     -h               display this help and exit
     -c               clean before build
     -cc              clean without building
     -v               verbose build
     -j <n>           run at most <n> concurrent jobs
     --gyp|-g         force a rerun of gyp
     --opt|-o         do an opt build
-    --target|-t      specify target architecture (e.g., x86, x64, aarch64)
+    --target|-t      specify target architecture (e.g., ia32, x64, aarch64)
     --clang          build with clang and clang++
     --gcc            build with gcc and g++
     --msvc           build with MSVC
     --scan-build     run the build with scan-build
                      --scan-build=<dir> sets the output path for scan-build
     --disable-tests  don't build tests and corresponding cmdline utils
     --pprof          build with gperftool support
     --asan           enable address sanitizer
--- a/security/nss/lib/ssl/manifest.mn
+++ b/security/nss/lib/ssl/manifest.mn
@@ -52,15 +52,16 @@ CSRCS = \
         tls13exthandle.c \
         tls13hashstate.c \
         tls13hkdf.c \
         tls13replay.c \
         sslcert.c \
         sslgrp.c \
         sslprimitive.c \
         tls13esni.c \
+        tls13subcerts.c \
         $(NULL)
 
 LIBRARY_NAME = ssl
 LIBRARY_VERSION = 3
 
 # This part of the code, including all sub-dirs, can be optimized for size
 export ALLOW_OPT_CODE_SIZE = 1
--- a/security/nss/lib/ssl/ssl.gyp
+++ b/security/nss/lib/ssl/ssl.gyp
@@ -44,16 +44,17 @@
         'ssltrace.c',
         'sslver.c',
         'tls13con.c',
         'tls13esni.c',
         'tls13exthandle.c',
         'tls13hashstate.c',
         'tls13hkdf.c',
         'tls13replay.c',
+        'tls13subcerts.c',
       ],
       'conditions': [
         [ 'OS=="win"', {
           'sources': [
             'win32err.c',
           ],
           'defines': [
             'IN_LIBSSL',
--- a/security/nss/lib/ssl/ssl.h
+++ b/security/nss/lib/ssl/ssl.h
@@ -305,16 +305,32 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRF
  * messages after handshake.
  *
  * This option applies only to clients.  For a server, the
  * SSL_SendCertificateRequest can be used to request post-handshake
  * authentication.
  */
 #define SSL_ENABLE_POST_HANDSHAKE_AUTH 39
 
+/* Enables the delegated credentials extension (draft-ietf-tls-subcerts). When
+ * enabled, a client that supports TLS 1.3 will indicate willingness to
+ * negotiate a delegated credential (DC).
+ *
+ * If support is indicated, the peer may use a DC to authenticate itself. The DC
+ * is sent as an extension to the peer's end-entity certificate; the end-entity
+ * certificate is used to verify the DC, which in turn is used to verify the
+ * handshake. DCs effectively extend the certificate chain by one, but only
+ * within the context of TLS. Once issued, DCs can't be revoked; in order to
+ * mitigate the damage in case the secret key is compromised, the DC is only
+ * valid for a short time (days, hours, or even minutes).
+ *
+ * This library implements draft-03 of the protocol spec.
+ */
+#define SSL_ENABLE_DELEGATED_CREDENTIALS 40
+
 #ifdef SSL_DEPRECATED_FUNCTION
 /* Old deprecated function names */
 SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRIntn on);
 SSL_IMPORT SECStatus SSL_EnableDefault(int option, PRIntn on);
 #endif
 
 /* Set (and get) options for sockets and defaults for newly created sockets.
  *
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -1021,36 +1021,34 @@ ssl3_GetNewRandom(SSL3Random random)
 
     rv = PK11_GenerateRandom(random, SSL3_RANDOM_LENGTH);
     if (rv != SECSuccess) {
         ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE);
     }
     return rv;
 }
 
-/* Called by ssl3_SendServerKeyExchange and ssl3_SendCertificateVerify */
-SECStatus
-ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash, SECKEYPrivateKey *key,
-                SECItem *buf)
+SECStatus
+ssl3_SignHashesWithPrivKey(SSL3Hashes *hash, SECKEYPrivateKey *key,
+                           SSLSignatureScheme scheme, PRBool isTls, SECItem *buf)
 {
     SECStatus rv = SECFailure;
     PRBool doDerEncode = PR_FALSE;
-    PRBool isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0);
-    PRBool useRsaPss = ssl_IsRsaPssSignatureScheme(ss->ssl3.hs.signatureScheme);
+    PRBool useRsaPss = ssl_IsRsaPssSignatureScheme(scheme);
     SECItem hashItem;
 
     buf->data = NULL;
 
     switch (SECKEY_GetPrivateKeyType(key)) {
         case rsaKey:
             hashItem.data = hash->u.raw;
             hashItem.len = hash->len;
             break;
         case dsaKey:
-            doDerEncode = isTLS;
+            doDerEncode = isTls;
             /* ssl_hash_none is used to specify the MD5/SHA1 concatenated hash.
              * In that case, we use just the SHA1 part. */
             if (hash->hashAlg == ssl_hash_none) {
                 hashItem.data = hash->u.s.sha;
                 hashItem.len = sizeof(hash->u.s.sha);
             } else {
                 hashItem.data = hash->u.raw;
                 hashItem.len = hash->len;
@@ -1117,48 +1115,66 @@ ssl3_SignHashes(sslSocket *ss, SSL3Hashe
         if (rv == SECSuccess) {
             PORT_Free(buf->data); /* discard unencoded signature. */
             *buf = derSig;        /* give caller encoded signature. */
         } else if (derSig.data) {
             PORT_Free(derSig.data);
         }
     }
 
-    if (ss->sec.isServer) {
-        ss->sec.signatureScheme = ss->ssl3.hs.signatureScheme;
-        ss->sec.authType =
-            ssl_SignatureSchemeToAuthType(ss->ssl3.hs.signatureScheme);
-    }
     PRINT_BUF(60, (NULL, "signed hashes", (unsigned char *)buf->data, buf->len));
 done:
     if (rv != SECSuccess && buf->data) {
         PORT_Free(buf->data);
         buf->data = NULL;
     }
     return rv;
 }
 
-/* Called from ssl3_HandleServerKeyExchange, ssl3_HandleCertificateVerify */
-SECStatus
-ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme, SSL3Hashes *hash,
-                        SECItem *buf)
+/* Called by ssl3_SendServerKeyExchange and ssl3_SendCertificateVerify */
+SECStatus
+ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash, SECKEYPrivateKey *key,
+                SECItem *buf)
+{
+    SECStatus rv = SECFailure;
+    PRBool isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0);
+    SSLSignatureScheme scheme = ss->ssl3.hs.signatureScheme;
+
+    rv = ssl3_SignHashesWithPrivKey(hash, key, scheme, isTLS, buf);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    if (ss->sec.isServer) {
+        ss->sec.signatureScheme = scheme;
+        ss->sec.authType = ssl_SignatureSchemeToAuthType(scheme);
+    }
+
+    return SECSuccess;
+}
+
+/* Called from ssl3_VerifySignedHashes and tls13_HandleCertificateVerify. */
+SECStatus
+ssl3_VerifySignedHashesWithSpki(sslSocket *ss, CERTSubjectPublicKeyInfo *spki,
+                                SSLSignatureScheme scheme,
+                                SSL3Hashes *hash, SECItem *buf)
 {
     SECKEYPublicKey *key;
     SECItem *signature = NULL;
     SECStatus rv = SECFailure;
     SECItem hashItem;
     SECOidTag encAlg;
     SECOidTag hashAlg;
     void *pwArg = ss->pkcs11PinArg;
     PRBool isRsaPssScheme = ssl_IsRsaPssSignatureScheme(scheme);
 
     PRINT_BUF(60, (NULL, "check signed hashes",
                    buf->data, buf->len));
 
-    key = CERT_ExtractPublicKey(ss->sec.peerCert);
+    key = SECKEY_ExtractPublicKey(spki);
     if (key == NULL) {
         ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
         return SECFailure;
     }
 
     hashAlg = ssl3_HashTypeToOID(hash->hashAlg);
     switch (SECKEY_GetPublicKeyType(key)) {
         case rsaKey:
@@ -1268,16 +1284,26 @@ loser:
     SECKEY_DestroyPublicKey(key);
 #ifdef UNSAFE_FUZZER_MODE
     rv = SECSuccess;
     PORT_SetError(0);
 #endif
     return rv;
 }
 
+/* Called from ssl3_HandleServerKeyExchange, ssl3_HandleCertificateVerify */
+SECStatus
+ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme, SSL3Hashes *hash,
+                        SECItem *buf)
+{
+    CERTSubjectPublicKeyInfo *spki = &ss->sec.peerCert->subjectPublicKeyInfo;
+    return ssl3_VerifySignedHashesWithSpki(
+        ss, spki, scheme, hash, buf);
+}
+
 /* Caller must set hiLevel error code. */
 /* Called from ssl3_ComputeDHKeyHash
  * which are called from ssl3_HandleServerKeyExchange.
  *
  * hashAlg: ssl_hash_none indicates the pre-1.2, MD5/SHA1 combination hash.
  */
 SECStatus
 ssl3_ComputeCommonKeyHash(SSLHashType hashAlg,
@@ -4108,17 +4134,17 @@ ssl_SignatureSchemeValid(SSLSignatureSch
         /* With TLS 1.3, EC keys should have been selected based on calling
          * ssl_SignatureSchemeFromSpki(), reject them otherwise. */
         return spkiOid != SEC_OID_ANSIX962_EC_PUBLIC_KEY;
     }
     return PR_TRUE;
 }
 
 static SECStatus
-ssl_SignatureSchemeFromPssSpki(CERTSubjectPublicKeyInfo *spki,
+ssl_SignatureSchemeFromPssSpki(const CERTSubjectPublicKeyInfo *spki,
                                SSLSignatureScheme *scheme)
 {
     SECKEYRSAPSSParams pssParam = { 0 };
     PORTCheapArenaPool arena;
     SECStatus rv;
 
     /* The key doesn't have parameters, boo. */
     if (!spki->algorithm.parameters.len) {
@@ -4156,17 +4182,17 @@ ssl_SignatureSchemeFromPssSpki(CERTSubje
 
 loser:
     PORT_DestroyCheapArena(&arena);
     PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
     return SECFailure;
 }
 
 static SECStatus
-ssl_SignatureSchemeFromEcSpki(CERTSubjectPublicKeyInfo *spki,
+ssl_SignatureSchemeFromEcSpki(const CERTSubjectPublicKeyInfo *spki,
                               SSLSignatureScheme *scheme)
 {
     const sslNamedGroupDef *group;
     SECKEYPublicKey *key;
 
     key = SECKEY_ExtractPublicKey(spki);
     if (!key) {
         PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
@@ -4193,18 +4219,18 @@ ssl_SignatureSchemeFromEcSpki(CERTSubjec
     }
     PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
     return SECFailure;
 }
 
 /* Newer signature schemes are designed so that a single SPKI can be used with
  * that scheme.  This determines that scheme from the SPKI. If the SPKI doesn't
  * have a single scheme, |*scheme| is set to ssl_sig_none. */
-static SECStatus
-ssl_SignatureSchemeFromSpki(CERTSubjectPublicKeyInfo *spki,
+SECStatus
+ssl_SignatureSchemeFromSpki(const CERTSubjectPublicKeyInfo *spki,
                             PRBool isTls13, SSLSignatureScheme *scheme)
 {
     SECOidTag spkiOid = SECOID_GetAlgorithmTag(&spki->algorithm);
 
     if (spkiOid == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) {
         return ssl_SignatureSchemeFromPssSpki(spki, scheme);
     }
 
@@ -4214,18 +4240,18 @@ ssl_SignatureSchemeFromSpki(CERTSubjectP
     if (isTls13 && spkiOid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) {
         return ssl_SignatureSchemeFromEcSpki(spki, scheme);
     }
 
     *scheme = ssl_sig_none;
     return SECSuccess;
 }
 
-static PRBool
-ssl_SignatureSchemeEnabled(sslSocket *ss, SSLSignatureScheme scheme)
+PRBool
+ssl_SignatureSchemeEnabled(const sslSocket *ss, SSLSignatureScheme scheme)
 {
     unsigned int i;
     for (i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
         if (scheme == ss->ssl3.signatureSchemes[i]) {
             return PR_TRUE;
         }
     }
     return PR_FALSE;
@@ -4245,45 +4271,44 @@ ssl_SignatureKeyMatchesSpkiOid(const ssl
             return keaDef->signKeyType == ecKey;
         default:
             break;
     }
     return PR_FALSE;
 }
 
 /* ssl3_CheckSignatureSchemeConsistency checks that the signature algorithm
- * identifier in |scheme| is consistent with the public key in |cert|. It also
+ * identifier in |scheme| is consistent with the public key in |spki|. It also
  * checks the hash algorithm against the configured signature algorithms.  If
  * all the tests pass, SECSuccess is returned. Otherwise, PORT_SetError is
  * called and SECFailure is returned. */
 SECStatus
 ssl_CheckSignatureSchemeConsistency(sslSocket *ss, SSLSignatureScheme scheme,
-                                    CERTCertificate *cert)
+                                    CERTSubjectPublicKeyInfo *spki)
 {
     SSLSignatureScheme spkiScheme;
     PRBool isTLS13 = ss->version == SSL_LIBRARY_VERSION_TLS_1_3;
     SECOidTag spkiOid;
     SECStatus rv;
 
-    rv = ssl_SignatureSchemeFromSpki(&cert->subjectPublicKeyInfo, isTLS13,
-                                     &spkiScheme);
+    rv = ssl_SignatureSchemeFromSpki(spki, isTLS13, &spkiScheme);
     if (rv != SECSuccess) {
         return SECFailure;
     }
     if (spkiScheme != ssl_sig_none) {
         /* The SPKI in the certificate can only be used for a single scheme. */
         if (spkiScheme != scheme ||
             !ssl_SignatureSchemeEnabled(ss, scheme)) {
             PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
             return SECFailure;
         }
         return SECSuccess;
     }
 
-    spkiOid = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm);
+    spkiOid = SECOID_GetAlgorithmTag(&spki->algorithm);
 
     /* If we're a client, check that the signature algorithm matches the signing
      * key type of the cipher suite. */
     if (!isTLS13 && !ss->sec.isServer) {
         if (!ssl_SignatureKeyMatchesSpkiOid(ss->ssl3.hs.kea_def, spkiOid)) {
             PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
             return SECFailure;
         }
@@ -6075,17 +6100,17 @@ ssl3_SendClientKeyExchange(sslSocket *ss
     SSL_TRC(3, ("%d: SSL3[%d]: DONE sending client_key_exchange",
                 SSL_GETPID(), ss->fd));
 
     SECKEY_DestroyPublicKey(serverKey);
     return rv; /* err code already set. */
 }
 
 /* Used by ssl_PickSignatureScheme(). */
-static PRBool
+PRBool
 ssl_CanUseSignatureScheme(SSLSignatureScheme scheme,
                           const SSLSignatureScheme *peerSchemes,
                           unsigned int peerSchemeCount,
                           PRBool requireSha1,
                           PRBool slotDoesPss)
 {
     SSLHashType hashType;
     SECOidTag hashOID;
@@ -6119,75 +6144,86 @@ ssl_CanUseSignatureScheme(SSLSignatureSc
         if (peerSchemes[i] == scheme) {
             return PR_TRUE;
         }
     }
     return PR_FALSE;
 }
 
 SECStatus
+ssl_PrivateKeySupportsRsaPss(SECKEYPrivateKey *privKey,
+                             PRBool *supportsRsaPss)
+{
+    PK11SlotInfo *slot;
+    slot = PK11_GetSlotFromPrivateKey(privKey);
+    if (!slot) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    *supportsRsaPss = PK11_DoesMechanism(slot, auth_alg_defs[ssl_auth_rsa_pss]);
+    PK11_FreeSlot(slot);
+    return SECSuccess;
+}
+
+SECStatus
 ssl_PickSignatureScheme(sslSocket *ss,
                         CERTCertificate *cert,
                         SECKEYPublicKey *pubKey,
                         SECKEYPrivateKey *privKey,
                         const SSLSignatureScheme *peerSchemes,
                         unsigned int peerSchemeCount,
                         PRBool requireSha1)
 {
     unsigned int i;
-    PK11SlotInfo *slot;
-    PRBool slotDoesPss;
+    PRBool doesRsaPss;
     PRBool isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3;
     SECStatus rv;
     SSLSignatureScheme scheme;
     SECOidTag spkiOid;
 
     /* We can't require SHA-1 in TLS 1.3. */
     PORT_Assert(!(requireSha1 && isTLS13));
     if (!pubKey || !privKey) {
         PORT_Assert(0);
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
-    slot = PK11_GetSlotFromPrivateKey(privKey);
-    if (!slot) {
-        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-        return SECFailure;
-    }
-    slotDoesPss = PK11_DoesMechanism(slot, auth_alg_defs[ssl_auth_rsa_pss]);
-    PK11_FreeSlot(slot);
+    rv = ssl_PrivateKeySupportsRsaPss(privKey, &doesRsaPss);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
 
     /* If the certificate SPKI indicates a single scheme, don't search. */
     rv = ssl_SignatureSchemeFromSpki(&cert->subjectPublicKeyInfo,
                                      isTLS13, &scheme);
     if (rv != SECSuccess) {
         return SECFailure;
     }
     if (scheme != ssl_sig_none) {
         if (!ssl_SignatureSchemeEnabled(ss, scheme) ||
             !ssl_CanUseSignatureScheme(scheme, peerSchemes, peerSchemeCount,
-                                       requireSha1, slotDoesPss)) {
+                                       requireSha1, doesRsaPss)) {
             PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
             return SECFailure;
         }
         ss->ssl3.hs.signatureScheme = scheme;
         return SECSuccess;
     }
 
     spkiOid = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm);
 
     /* Now we have to search based on the key type. Go through our preferred
      * schemes in order and find the first that can be used. */
     for (i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
         scheme = ss->ssl3.signatureSchemes[i];
 
         if (ssl_SignatureSchemeValid(scheme, spkiOid, isTLS13) &&
             ssl_CanUseSignatureScheme(scheme, peerSchemes, peerSchemeCount,
-                                      requireSha1, slotDoesPss)) {
+                                      requireSha1, doesRsaPss)) {
             ss->ssl3.hs.signatureScheme = scheme;
             return SECSuccess;
         }
     }
 
     PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
     return SECFailure;
 }
@@ -7068,18 +7104,18 @@ ssl_HandleDHServerKeyExchange(sslSocket 
         goto alert_loser;
     }
 
     if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
         rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme);
         if (rv != SECSuccess) {
             goto alert_loser; /* malformed or unsupported. */
         }
-        rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme,
-                                                 ss->sec.peerCert);
+        rv = ssl_CheckSignatureSchemeConsistency(
+            ss, sigScheme, &ss->sec.peerCert->subjectPublicKeyInfo);
         if (rv != SECSuccess) {
             goto alert_loser;
         }
         hashAlg = ssl_SignatureSchemeToHashType(sigScheme);
     } else {
         /* Use ssl_hash_none to represent the MD5+SHA1 combo. */
         hashAlg = ssl_hash_none;
         sigScheme = ssl_sig_none;
@@ -9774,18 +9810,18 @@ ssl3_HandleCertificateVerify(sslSocket *
     PORT_Assert(ss->ssl3.prSpec->version <= SSL_LIBRARY_VERSION_TLS_1_2);
 
     if (ss->ssl3.prSpec->version == SSL_LIBRARY_VERSION_TLS_1_2) {
         PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_record);
         rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme);
         if (rv != SECSuccess) {
             goto loser; /* malformed or unsupported. */
         }
-        rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme,
-                                                 ss->sec.peerCert);
+        rv = ssl_CheckSignatureSchemeConsistency(
+            ss, sigScheme, &ss->sec.peerCert->subjectPublicKeyInfo);
         if (rv != SECSuccess) {
             errCode = PORT_GetError();
             desc = illegal_parameter;
             goto alert_loser;
         }
 
         rv = ssl3_ComputeHandshakeHash(ss->ssl3.hs.messages.buf,
                                        ss->ssl3.hs.messages.len,
--- a/security/nss/lib/ssl/ssl3ecc.c
+++ b/security/nss/lib/ssl/ssl3ecc.c
@@ -543,18 +543,18 @@ ssl3_HandleECDHServerKeyExchange(sslSock
 
     PORT_Assert(ss->ssl3.prSpec->version <= SSL_LIBRARY_VERSION_TLS_1_2);
     if (ss->ssl3.prSpec->version == SSL_LIBRARY_VERSION_TLS_1_2) {
         rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme);
         if (rv != SECSuccess) {
             errCode = PORT_GetError();
             goto alert_loser; /* malformed or unsupported. */
         }
-        rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme,
-                                                 ss->sec.peerCert);
+        rv = ssl_CheckSignatureSchemeConsistency(
+            ss, sigScheme, &ss->sec.peerCert->subjectPublicKeyInfo);
         if (rv != SECSuccess) {
             errCode = PORT_GetError();
             goto alert_loser;
         }
         hashAlg = ssl_SignatureSchemeToHashType(sigScheme);
     } else {
         /* Use ssl_hash_none to represent the MD5+SHA1 combo. */
         hashAlg = ssl_hash_none;
--- a/security/nss/lib/ssl/ssl3ext.c
+++ b/security/nss/lib/ssl/ssl3ext.c
@@ -11,16 +11,17 @@
 #include "nssrenam.h"
 #include "nss.h"
 #include "ssl.h"
 #include "sslimpl.h"
 #include "sslproto.h"
 #include "ssl3exthandle.h"
 #include "tls13err.h"
 #include "tls13exthandle.h"
+#include "tls13subcerts.h"
 
 /* Callback function that handles a received extension. */
 typedef SECStatus (*ssl3ExtensionHandlerFunc)(const sslSocket *ss,
                                               TLSExtensionData *xtnData,
                                               SECItem *data);
 
 /* Row in a table of hello extension handlers. */
 typedef struct {
@@ -40,16 +41,17 @@ static const ssl3ExtensionHandler client
     { ssl_session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn },
     { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
     { ssl_app_layer_protocol_xtn, &ssl3_ServerHandleAppProtoXtn },
     { ssl_use_srtp_xtn, &ssl3_ServerHandleUseSRTPXtn },
     { ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn },
     { ssl_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn },
     { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn },
     { ssl_signed_cert_timestamp_xtn, &ssl3_ServerHandleSignedCertTimestampXtn },
+    { ssl_delegated_credentials_xtn, &tls13_ServerHandleDelegatedCredentialsXtn },
     { ssl_tls13_key_share_xtn, &tls13_ServerHandleKeyShareXtn },
     { ssl_tls13_pre_shared_key_xtn, &tls13_ServerHandlePreSharedKeyXtn },
     { ssl_tls13_early_data_xtn, &tls13_ServerHandleEarlyDataXtn },
     { ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ServerHandlePskModesXtn },
     { ssl_tls13_cookie_xtn, &tls13_ServerHandleCookieXtn },
     { ssl_tls13_encrypted_sni_xtn, &tls13_ServerHandleEsniXtn },
     { ssl_tls13_post_handshake_auth_xtn, &tls13_ServerHandlePostHandshakeAuthXtn },
     { ssl_record_size_limit_xtn, &ssl_HandleRecordSizeLimitXtn },
@@ -91,16 +93,17 @@ static const ssl3ExtensionHandler newSes
       &tls13_ClientHandleTicketEarlyDataXtn },
     { 0, NULL }
 };
 
 /* This table is used by the client to handle server certificates in TLS 1.3 */
 static const ssl3ExtensionHandler serverCertificateHandlers[] = {
     { ssl_signed_cert_timestamp_xtn, &ssl3_ClientHandleSignedCertTimestampXtn },
     { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn },
+    { ssl_delegated_credentials_xtn, &tls13_ClientHandleDelegatedCredentialsXtn },
     { 0, NULL }
 };
 
 static const ssl3ExtensionHandler certificateRequestHandlers[] = {
     { ssl_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn },
     { ssl_tls13_certificate_authorities_xtn,
       &tls13_ClientHandleCertAuthoritiesXtn },
     { 0, NULL }
@@ -122,16 +125,17 @@ static const sslExtensionBuilder clientH
       { ssl_extended_master_secret_xtn, &ssl3_SendExtendedMasterSecretXtn },
       { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn },
       { ssl_supported_groups_xtn, &ssl_SendSupportedGroupsXtn },
       { ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn },
       { ssl_session_ticket_xtn, &ssl3_ClientSendSessionTicketXtn },
       { ssl_app_layer_protocol_xtn, &ssl3_ClientSendAppProtoXtn },
       { ssl_use_srtp_xtn, &ssl3_ClientSendUseSRTPXtn },
       { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn },
+      { ssl_delegated_credentials_xtn, &tls13_ClientSendDelegatedCredentialsXtn },
       { ssl_signed_cert_timestamp_xtn, &ssl3_ClientSendSignedCertTimestampXtn },
       { ssl_tls13_key_share_xtn, &tls13_ClientSendKeyShareXtn },
       { ssl_tls13_early_data_xtn, &tls13_ClientSendEarlyDataXtn },
       /* Some servers (e.g. WebSphere Application Server 7.0 and Tomcat) will
        * time out or terminate the connection if the last extension in the
        * client hello is empty. They are not intolerant of TLS 1.2, so list
        * signature_algorithms at the end. See bug 1243641. */
       { ssl_tls13_supported_versions_xtn, &tls13_ClientSendSupportedVersionsXtn },
@@ -165,16 +169,17 @@ static const sslExtensionBuilder tls13_h
 };
 
 static const struct {
     SSLExtensionType type;
     SSLExtensionSupport support;
 } ssl_supported_extensions[] = {
     { ssl_server_name_xtn, ssl_ext_native_only },
     { ssl_cert_status_xtn, ssl_ext_native },
+    { ssl_delegated_credentials_xtn, ssl_ext_native },
     { ssl_supported_groups_xtn, ssl_ext_native_only },
     { ssl_ec_point_formats_xtn, ssl_ext_native },
     { ssl_signature_algorithms_xtn, ssl_ext_native_only },
     { ssl_use_srtp_xtn, ssl_ext_native },
     { ssl_app_layer_protocol_xtn, ssl_ext_native_only },
     { ssl_signed_cert_timestamp_xtn, ssl_ext_native },
     { ssl_padding_xtn, ssl_ext_native },
     { ssl_extended_master_secret_xtn, ssl_ext_native_only },
@@ -946,16 +951,19 @@ ssl3_InitExtensionData(TLSExtensionData 
         ++advertisedMax; /* For the RI SCSV, which we also track. */
     }
     for (cursor = PR_NEXT_LINK(&ss->extensionHooks);
          cursor != &ss->extensionHooks;
          cursor = PR_NEXT_LINK(cursor)) {
         ++advertisedMax;
     }
     xtnData->advertised = PORT_ZNewArray(PRUint16, advertisedMax);
+    xtnData->peerDelegCred = NULL;
+    xtnData->peerRequestedDelegCred = PR_FALSE;
+    xtnData->sendingDelegCredToPeer = PR_FALSE;
 }
 
 void
 ssl3_DestroyExtensionData(TLSExtensionData *xtnData)
 {
     ssl3_FreeSniNameArray(xtnData);
     PORT_Free(xtnData->sigSchemes);
     SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE);
@@ -964,16 +972,17 @@ ssl3_DestroyExtensionData(TLSExtensionDa
     SECITEM_FreeItem(&xtnData->applicationToken, PR_FALSE);
     if (xtnData->certReqAuthorities.arena) {
         PORT_FreeArena(xtnData->certReqAuthorities.arena, PR_FALSE);
         xtnData->certReqAuthorities.arena = NULL;
     }
     PORT_Free(xtnData->advertised);
     ssl_FreeEphemeralKeyPair(xtnData->esniPrivateKey);
     SECITEM_FreeItem(&xtnData->keyShareExtension, PR_FALSE);
+    tls13_DestroyDelegatedCredential(xtnData->peerDelegCred);
 }
 
 /* Free everything that has been allocated and then reset back to
  * the starting state. */
 void
 ssl3_ResetExtensionData(TLSExtensionData *xtnData, const sslSocket *ss)
 {
     ssl3_DestroyExtensionData(xtnData);
--- a/security/nss/lib/ssl/ssl3ext.h
+++ b/security/nss/lib/ssl/ssl3ext.h
@@ -106,16 +106,29 @@ struct TLSExtensionDataStr {
 
     /* ESNI working state */
     SECItem keyShareExtension;
     ssl3CipherSuite esniSuite;
     sslEphemeralKeyPair *esniPrivateKey;
     /* Pointer into |ss->esniKeys->keyShares| */
     TLS13KeyShareEntry *peerEsniShare;
     PRUint8 esniNonce[TLS13_ESNI_NONCE_SIZE];
+
+    /* Delegated credentials.
+     *
+     * The delegated credential sent by the peer. Set by
+     * |tls13_ReadDelegatedCredential|.
+     */
+    sslDelegatedCredential *peerDelegCred;
+    /* Whether the peer requested a delegated credential. */
+    PRBool peerRequestedDelegCred;
+    /* Whether the host is committed to using a delegated credential. Set by
+     * |tls13_MaybeSetDelegatedCredential|.
+     */
+    PRBool sendingDelegCredToPeer;
 };
 
 typedef struct TLSExtensionStr {
     PRCList link;  /* The linked list link */
     PRUint16 type; /* Extension type */
     SECItem data;  /* Pointers into the handshake data. */
 } TLSExtension;
 
--- a/security/nss/lib/ssl/sslcert.c
+++ b/security/nss/lib/ssl/sslcert.c
@@ -3,20 +3,21 @@
  * SSL server certificate configuration functions.
  *
  * 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 "ssl.h"
 #include "sslimpl.h"
-#include "secoid.h"   /* for SECOID_GetAlgorithmTag */
-#include "pk11func.h" /* for PK11_ReferenceSlot */
-#include "nss.h"      /* for NSS_RegisterShutdown */
-#include "prinit.h"   /* for PR_CallOnceWithArg */
+#include "secoid.h"        /* for SECOID_GetAlgorithmTag */
+#include "pk11func.h"      /* for PK11_ReferenceSlot */
+#include "nss.h"           /* for NSS_RegisterShutdown */
+#include "prinit.h"        /* for PR_CallOnceWithArg */
+#include "tls13subcerts.h" /* for tls13_ReadDelegatedCredential */
 
 /* This global item is used only in servers.  It is is initialized by
  * SSL_ConfigSecureServer(), and is used in ssl3_SendCertificateRequest().
  */
 static struct {
     PRCallOnceType setup;
     CERTDistNames *names;
 } ssl_server_ca_list;
@@ -97,16 +98,18 @@ ssl_NewServerCert()
         return NULL;
     }
     sc->authTypes = 0;
     sc->namedCurve = NULL;
     sc->serverCert = NULL;
     sc->serverCertChain = NULL;
     sc->certStatusArray = NULL;
     sc->signedCertTimestamps.len = 0;
+    sc->delegCred.len = 0;
+    sc->delegCredKeyPair = NULL;
     return sc;
 }
 
 sslServerCert *
 ssl_CopyServerCert(const sslServerCert *oc)
 {
     sslServerCert *sc;
 
@@ -143,18 +146,27 @@ ssl_CopyServerCert(const sslServerCert *
         sc->certStatusArray = SECITEM_DupArray(NULL, oc->certStatusArray);
         if (!sc->certStatusArray)
             goto loser;
     } else {
         sc->certStatusArray = NULL;
     }
 
     if (SECITEM_CopyItem(NULL, &sc->signedCertTimestamps,
-                         &oc->signedCertTimestamps) != SECSuccess)
+                         &oc->signedCertTimestamps) != SECSuccess) {
+        goto loser;
+    }
+
+    if (SECITEM_CopyItem(NULL, &sc->delegCred, &oc->delegCred) != SECSuccess) {
         goto loser;
+    }
+    if (oc->delegCredKeyPair) {
+        sc->delegCredKeyPair = ssl_GetKeyPairRef(oc->delegCredKeyPair);
+    }
+
     return sc;
 loser:
     ssl_FreeServerCert(sc);
     return NULL;
 }
 
 void
 ssl_FreeServerCert(sslServerCert *sc)
@@ -173,16 +185,22 @@ ssl_FreeServerCert(sslServerCert *sc)
         ssl_FreeKeyPair(sc->serverKeyPair);
     }
     if (sc->certStatusArray) {
         SECITEM_FreeArray(sc->certStatusArray, PR_TRUE);
     }
     if (sc->signedCertTimestamps.len) {
         SECITEM_FreeItem(&sc->signedCertTimestamps, PR_FALSE);
     }
+    if (sc->delegCred.len) {
+        SECITEM_FreeItem(&sc->delegCred, PR_FALSE);
+    }
+    if (sc->delegCredKeyPair) {
+        ssl_FreeKeyPair(sc->delegCredKeyPair);
+    }
     PORT_ZFree(sc, sizeof(*sc));
 }
 
 const sslServerCert *
 ssl_FindServerCert(const sslSocket *ss, SSLAuthType authType,
                    const sslNamedGroupDef *namedCurve)
 {
     PRCList *cursor;
@@ -304,16 +322,89 @@ ssl_PopulateSignedCertTimestamps(sslServ
     }
     if (signedCertTimestamps && signedCertTimestamps->len) {
         return SECITEM_CopyItem(NULL, &sc->signedCertTimestamps,
                                 signedCertTimestamps);
     }
     return SECSuccess;
 }
 
+/* Installs the given delegated credential (DC) and DC private key into the
+ * certificate.
+ *
+ * It's the caller's responsibility to ensure that the DC is well-formed and
+ * that the DC public key matches the DC private key.
+ */
+static SECStatus
+ssl_PopulateDelegatedCredential(sslServerCert *sc,
+                                const SECItem *delegCred,
+                                const SECKEYPrivateKey *delegCredPrivKey)
+{
+    sslDelegatedCredential *dc = NULL;
+
+    if (sc->delegCred.len) {
+        SECITEM_FreeItem(&sc->delegCred, PR_FALSE);
+    }
+
+    if (sc->delegCredKeyPair) {
+        ssl_FreeKeyPair(sc->delegCredKeyPair);
+        sc->delegCredKeyPair = NULL;
+    }
+
+    /* Both the DC and its private are present. */
+    if (delegCred && delegCredPrivKey) {
+        SECStatus rv;
+        SECKEYPublicKey *pub;
+        SECKEYPrivateKey *priv;
+
+        if (!delegCred->data || delegCred->len == 0) {
+            PORT_SetError(SEC_ERROR_INVALID_ARGS);
+            goto loser;
+        }
+
+        /* Parse the DC. */
+        rv = tls13_ReadDelegatedCredential(delegCred->data, delegCred->len, &dc);
+        if (rv != SECSuccess) {
+            goto loser;
+        }
+
+        /* Make a copy of the DC. */
+        rv = SECITEM_CopyItem(NULL, &sc->delegCred, delegCred);
+        if (rv != SECSuccess) {
+            goto loser;
+        }
+
+        /* Make a copy of the DC private key. */
+        priv = SECKEY_CopyPrivateKey(delegCredPrivKey);
+        if (!priv) {
+            goto loser;
+        }
+
+        /* parse public key from the DC. */
+        pub = SECKEY_ExtractPublicKey(dc->spki);
+        if (!pub) {
+            goto loser;
+        }
+
+        sc->delegCredKeyPair = ssl_NewKeyPair(priv, pub);
+
+        /* Attempting to configure either the DC or DC private key, but not both. */
+    } else if (delegCred || delegCredPrivKey) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        goto loser;
+    }
+
+    tls13_DestroyDelegatedCredential(dc);
+    return SECSuccess;
+
+loser:
+    tls13_DestroyDelegatedCredential(dc);
+    return SECFailure;
+}
+
 /* Find any existing certificates that overlap with the new certificate and
  * either remove any supported authentication types that overlap with the new
  * certificate or - if they have no types left - remove them entirely. */
 static void
 ssl_ClearMatchingCerts(sslSocket *ss, sslAuthTypeMask authTypes,
                        const sslNamedGroupDef *namedCurve)
 {
     PRCList *cursor = PR_NEXT_LINK(&ss->serverCerts);
@@ -374,16 +465,22 @@ ssl_ConfigCert(sslSocket *ss, sslAuthTyp
     rv = ssl_PopulateOCSPResponses(sc, data->stapledOCSPResponses);
     if (rv != SECSuccess) {
         goto loser;
     }
     rv = ssl_PopulateSignedCertTimestamps(sc, data->signedCertTimestamps);
     if (rv != SECSuccess) {
         goto loser;
     }
+    rv = ssl_PopulateDelegatedCredential(sc, data->delegCred,
+                                         data->delegCredPrivKey);
+    if (rv != SECSuccess) {
+        error_code = PORT_GetError();
+        goto loser;
+    }
     ssl_ClearMatchingCerts(ss, sc->authTypes, sc->namedCurve);
     PR_APPEND_LINK(&sc->link, &ss->serverCerts);
     return SECSuccess;
 
 loser:
     ssl_FreeServerCert(sc);
     PORT_SetError(error_code);
     return SECFailure;
@@ -543,17 +640,17 @@ SECStatus
 SSL_ConfigServerCert(PRFileDesc *fd, CERTCertificate *cert,
                      SECKEYPrivateKey *key,
                      const SSLExtraServerCertData *data, unsigned int data_len)
 {
     sslSocket *ss;
     sslKeyPair *keyPair;
     SECStatus rv;
     SSLExtraServerCertData dataCopy = {
-        ssl_auth_null, NULL, NULL, NULL
+        ssl_auth_null, NULL, NULL, NULL, NULL, NULL
     };
     sslAuthTypeMask authTypes;
 
     ss = ssl_FindSocket(fd);
     if (!ss) {
         return SECFailure;
     }
 
--- a/security/nss/lib/ssl/sslcert.h
+++ b/security/nss/lib/ssl/sslcert.h
@@ -36,16 +36,23 @@ typedef struct sslServerCertStr {
     unsigned int serverKeyBits;
     /* Each certificate needs its own status. */
     SECItemArray *certStatusArray;
     /* Serialized signed certificate timestamps to be sent to the client
     ** in a TLS extension (server only). Each certificate needs its own
     ** timestamps item.
     */
     SECItem signedCertTimestamps;
+
+    /* The delegated credential (DC) to send to clients who indicate support for
+     * the ietf-draft-tls-subcerts extension.
+     */
+    SECItem delegCred;
+    /* The key pair used to sign the handshake when serving a DC. */
+    sslKeyPair *delegCredKeyPair;
 } sslServerCert;
 
 #define SSL_CERT_IS(c, t) ((c)->authTypes & (1 << (t)))
 #define SSL_CERT_IS_ONLY(c, t) ((c)->authTypes == (1 << (t)))
 #define SSL_CERT_IS_EC(c)                         \
     ((c)->authTypes & ((1 << ssl_auth_ecdsa) |    \
                        (1 << ssl_auth_ecdh_rsa) | \
                        (1 << ssl_auth_ecdh_ecdsa)))
--- a/security/nss/lib/ssl/sslerr.h
+++ b/security/nss/lib/ssl/sslerr.h
@@ -265,15 +265,19 @@ typedef enum {
     SSL_ERROR_RX_MALFORMED_DTLS_ACK = (SSL_ERROR_BASE + 174),
     SSL_ERROR_DH_KEY_TOO_LONG = (SSL_ERROR_BASE + 175),
     SSL_ERROR_RX_MALFORMED_ESNI_KEYS = (SSL_ERROR_BASE + 176),
     SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION = (SSL_ERROR_BASE + 177),
     SSL_ERROR_MISSING_ESNI_EXTENSION = (SSL_ERROR_BASE + 178),
     SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE = (SSL_ERROR_BASE + 179),
     SSL_ERROR_MISSING_POST_HANDSHAKE_AUTH_EXTENSION = (SSL_ERROR_BASE + 180),
     SSL_ERROR_RX_CERTIFICATE_REQUIRED_ALERT = (SSL_ERROR_BASE + 181),
+    SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH = (SSL_ERROR_BASE + 182),
+    SSL_ERROR_DC_BAD_SIGNATURE = (SSL_ERROR_BASE + 183),
+    SSL_ERROR_DC_INVALID_KEY_USAGE = (SSL_ERROR_BASE + 184),
+    SSL_ERROR_DC_EXPIRED = (SSL_ERROR_BASE + 185),
     SSL_ERROR_END_OF_LIST   /* let the c compiler determine the value of this. */
 } SSLErrorCodes;
 #endif /* NO_SECURITY_ERROR_ENUM */
 
 /* clang-format on */
 
 #endif /* __SSL_ERR_H_ */
--- a/security/nss/lib/ssl/sslexp.h
+++ b/security/nss/lib/ssl/sslexp.h
@@ -752,16 +752,46 @@ typedef struct SSLAeadContextStr SSLAead
  * function to NULL to use PR_Now().*/
 typedef PRTime(PR_CALLBACK *SSLTimeFunc)(void *arg);
 
 #define SSL_SetTimeFunc(fd, f, arg)                                      \
     SSL_EXPERIMENTAL_API("SSL_SetTimeFunc",                              \
                          (PRFileDesc * _fd, SSLTimeFunc _f, void *_arg), \
                          (fd, f, arg))
 
+/* Create a delegated credential (DC) for the draft-ietf-tls-subcerts extension
+ * using the given certificate |cert| and its signing key |certPriv| and write
+ * the serialized DC to |out|. The
+ * parameters are:
+ *  - the DC public key |dcPub|;
+ *  - the DC signature scheme |dcCertVerifyAlg|, used to verify the handshake.
+ *  - the DC time-to-live |dcValidFor|, the number of seconds from now for which
+ *    the DC should be valid; and
+ *  - the current time |now|.
+ *
+ *  The signing algorithm used to verify the DC signature is deduced from
+ *  |cert|.
+ *
+ *  It's the caller's responsibility to ensure the input parameters are all
+ *  valid. This procedure is meant primarily for testing; for this purpose it is
+ *  useful to do no validation.
+ */
+#define SSL_DelegateCredential(cert, certPriv, dcPub, dcCertVerifyAlg,        \
+                               dcValidFor, now, out)                          \
+    SSL_EXPERIMENTAL_API("SSL_DelegateCredential",                            \
+                         (const CERTCertificate *_cert,                       \
+                          const SECKEYPrivateKey *_certPriv,                  \
+                          const SECKEYPublicKey *_dcPub,                      \
+                          SSLSignatureScheme _dcCertVerifyAlg,                \
+                          PRUint32 _dcValidFor,                               \
+                          PRTime _now,                                        \
+                          SECItem *_out),                                     \
+                         (cert, certPriv, dcPub, dcCertVerifyAlg, dcValidFor, \
+                          now, out))
+
 /* Deprecated experimental APIs */
 #define SSL_UseAltServerHelloType(fd, enable) SSL_DEPRECATED_EXPERIMENTAL_API
 #define SSL_SetupAntiReplay(a, b, c) SSL_DEPRECATED_EXPERIMENTAL_API
 #define SSL_InitAntiReplay(a, b, c) SSL_DEPRECATED_EXPERIMENTAL_API
 
 SEC_END_PROTOS
 
 #endif /* __sslexp_h_ */
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -32,16 +32,17 @@
 #include "prclist.h"
 #include "private/pprthred.h"
 
 #include "sslt.h" /* for some formerly private types, now public */
 
 typedef struct sslSocketStr sslSocket;
 typedef struct sslNamedGroupDefStr sslNamedGroupDef;
 typedef struct sslEsniKeysStr sslEsniKeys;
+typedef struct sslDelegatedCredentialStr sslDelegatedCredential;
 typedef struct sslEphemeralKeyPairStr sslEphemeralKeyPair;
 typedef struct TLS13KeyShareEntryStr TLS13KeyShareEntry;
 
 #include "sslencode.h"
 #include "sslexp.h"
 #include "ssl3ext.h"
 #include "sslspec.h"
 
@@ -274,16 +275,17 @@ typedef struct sslOptionsStr {
     unsigned int enableSignedCertTimestamps : 1;
     unsigned int requireDHENamedGroups : 1;
     unsigned int enable0RttData : 1;
     unsigned int enableTls13CompatMode : 1;
     unsigned int enableDtlsShortHeader : 1;
     unsigned int enableHelloDowngradeCheck : 1;
     unsigned int enableV2CompatibleHello : 1;
     unsigned int enablePostHandshakeAuth : 1;
+    unsigned int enableDelegatedCredentials : 1;
 } sslOptions;
 
 typedef enum { sslHandshakingUndetermined = 0,
                sslHandshakingAsClient,
                sslHandshakingAsServer
 } sslHandshakingType;
 
 #define SSL_LOCK_RANK_SPEC 255
@@ -1460,16 +1462,21 @@ extern sslEphemeralKeyPair *ssl_LookupEp
     sslSocket *ss, const sslNamedGroupDef *groupDef);
 extern PRBool ssl_HaveEphemeralKeyPair(const sslSocket *ss,
                                        const sslNamedGroupDef *groupDef);
 extern void ssl_FreeEphemeralKeyPairs(sslSocket *ss);
 
 extern SECStatus ssl_AppendPaddedDHKeyShare(sslBuffer *buf,
                                             const SECKEYPublicKey *pubKey,
                                             PRBool appendLength);
+extern PRBool ssl_CanUseSignatureScheme(SSLSignatureScheme scheme,
+                                        const SSLSignatureScheme *peerSchemes,
+                                        unsigned int peerSchemeCount,
+                                        PRBool requireSha1,
+                                        PRBool slotDoesPss);
 extern const ssl3DHParams *ssl_GetDHEParams(const sslNamedGroupDef *groupDef);
 extern SECStatus ssl_SelectDHEGroup(sslSocket *ss,
                                     const sslNamedGroupDef **groupDef);
 extern SECStatus ssl_CreateDHEKeyPair(const sslNamedGroupDef *groupDef,
                                       const ssl3DHParams *params,
                                       sslEphemeralKeyPair **keyPair);
 extern PRBool ssl_IsValidDHEShare(const SECItem *dh_p, const SECItem *dh_Ys);
 extern SECStatus ssl_ValidateDHENamedGroup(sslSocket *ss,
@@ -1556,28 +1563,43 @@ extern SECStatus ssl3_ConsumeHandshakeNu
                                              PRUint32 bytes, PRUint8 **b,
                                              PRUint32 *length);
 extern SECStatus ssl3_ConsumeHandshakeNumber64(sslSocket *ss, PRUint64 *num,
                                                PRUint32 bytes, PRUint8 **b,
                                                PRUint32 *length);
 extern SECStatus ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i,
                                                PRUint32 bytes, PRUint8 **b,
                                                PRUint32 *length);
+extern SECStatus ssl_SignatureSchemeFromSpki(const CERTSubjectPublicKeyInfo *spki,
+                                             PRBool isTls13,
+                                             SSLSignatureScheme *scheme);
+extern PRBool ssl_SignatureSchemeEnabled(const sslSocket *ss,
+                                         SSLSignatureScheme scheme);
 extern PRBool ssl_IsSupportedSignatureScheme(SSLSignatureScheme scheme);
 extern SECStatus ssl_CheckSignatureSchemeConsistency(
-    sslSocket *ss, SSLSignatureScheme scheme, CERTCertificate *cert);
+    sslSocket *ss, SSLSignatureScheme scheme, CERTSubjectPublicKeyInfo *spki);
 extern SECStatus ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena,
                                            SSLSignatureScheme **schemesOut,
                                            unsigned int *numSchemesOut,
                                            unsigned char **b,
                                            unsigned int *len);
 extern SECStatus ssl_ConsumeSignatureScheme(
     sslSocket *ss, PRUint8 **b, PRUint32 *length, SSLSignatureScheme *out);
+extern SECStatus ssl3_SignHashesWithPrivKey(SSL3Hashes *hash,
+                                            SECKEYPrivateKey *key,
+                                            SSLSignatureScheme scheme,
+                                            PRBool isTls,
+                                            SECItem *buf);
 extern SECStatus ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash,
                                  SECKEYPrivateKey *key, SECItem *buf);
+extern SECStatus ssl3_VerifySignedHashesWithSpki(sslSocket *ss,
+                                                 CERTSubjectPublicKeyInfo *spki,
+                                                 SSLSignatureScheme scheme,
+                                                 SSL3Hashes *hash,
+                                                 SECItem *buf);
 extern SECStatus ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme,
                                          SSL3Hashes *hash, SECItem *buf);
 extern SECStatus ssl3_CacheWrappedSecret(sslSocket *ss, sslSessionID *sid,
                                          PK11SymKey *secret);
 extern void ssl3_FreeSniNameArray(TLSExtensionData *xtnData);
 
 /* Hello Extension related routines. */
 extern void ssl3_SetSIDSessionTicket(sslSessionID *sid,
@@ -1691,16 +1713,18 @@ SECStatus ssl3_FillInCachedSID(sslSocket
                                PK11SymKey *secret);
 const ssl3CipherSuiteDef *ssl_LookupCipherSuiteDef(ssl3CipherSuite suite);
 const ssl3CipherSuiteCfg *ssl_LookupCipherSuiteCfg(ssl3CipherSuite suite,
                                                    const ssl3CipherSuiteCfg *suites);
 PRBool ssl3_CipherSuiteAllowedForVersionRange(ssl3CipherSuite cipherSuite,
                                               const SSLVersionRange *vrange);
 
 SECStatus ssl3_SelectServerCert(sslSocket *ss);
+SECStatus ssl_PrivateKeySupportsRsaPss(SECKEYPrivateKey *privKey,
+                                       PRBool *supportsRsaPss);
 SECStatus ssl_PickSignatureScheme(sslSocket *ss,
                                   CERTCertificate *cert,
                                   SECKEYPublicKey *pubKey,
                                   SECKEYPrivateKey *privKey,
                                   const SSLSignatureScheme *peerSchemes,
                                   unsigned int peerSchemeCount,
                                   PRBool requireSha1);
 SECOidTag ssl3_HashTypeToOID(SSLHashType hashType);
--- a/security/nss/lib/ssl/sslinfo.c
+++ b/security/nss/lib/ssl/sslinfo.c
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "pk11pub.h"
 #include "ssl.h"
 #include "sslimpl.h"
 #include "sslproto.h"
 #include "tls13hkdf.h"
+#include "tls13subcerts.h"
 
 SECStatus
 SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
 {
     sslSocket *ss;
     SSLChannelInfo inf;
     sslSessionID *sid;
 
@@ -74,16 +75,17 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLCh
         inf.authKeyBits = ss->sec.authKeyBits;
         inf.signatureScheme = ss->sec.signatureScheme;
         /* If this is a resumed session, signatureScheme isn't set in ss->sec.
          * Use the signature scheme from the previous handshake. */
         if (inf.signatureScheme == ssl_sig_none && sid->sigScheme) {
             inf.signatureScheme = sid->sigScheme;
         }
         inf.resumed = ss->statelessResume || ss->ssl3.hs.isResuming;
+        inf.peerDelegCred = tls13_IsVerifyingWithDelegatedCredential(ss);
 
         if (sid) {
             unsigned int sidLen;
 
             inf.creationTime = sid->creationTime / PR_USEC_PER_SEC;
             inf.lastAccessTime = sid->lastAccessTime / PR_USEC_PER_SEC;
             inf.expirationTime = sid->expirationTime / PR_USEC_PER_SEC;
             inf.extendedMasterSecretUsed =
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -15,16 +15,17 @@
 #include "sslimpl.h"
 #include "sslproto.h"
 #include "nspr.h"
 #include "private/pprio.h"
 #include "nss.h"
 #include "pk11pqg.h"
 #include "pk11pub.h"
 #include "tls13esni.h"
+#include "tls13subcerts.h"
 
 static const sslSocketOps ssl_default_ops = { /* No SSL. */
                                               ssl_DefConnect,
                                               NULL,
                                               ssl_DefBind,
                                               ssl_DefListen,
                                               ssl_DefShutdown,
                                               ssl_DefClose,
@@ -70,16 +71,17 @@ static sslOptions ssl_defaults = {
     .noLocks = PR_FALSE,
     .enableSessionTickets = PR_FALSE,
     .enableDeflate = PR_FALSE,
     .enableRenegotiation = SSL_RENEGOTIATE_REQUIRES_XTN,
     .requireSafeNegotiation = PR_FALSE,
     .enableFalseStart = PR_FALSE,
     .cbcRandomIV = PR_TRUE,
     .enableOCSPStapling = PR_FALSE,
+    .enableDelegatedCredentials = PR_FALSE,
     .enableALPN = PR_TRUE,
     .reuseServerECDHEKey = PR_TRUE,
     .enableFallbackSCSV = PR_FALSE,
     .enableServerDhe = PR_TRUE,
     .enableExtendedMS = PR_FALSE,
     .enableSignedCertTimestamps = PR_FALSE,
     .requireDHENamedGroups = PR_FALSE,
     .enable0RttData = PR_FALSE,
@@ -788,16 +790,20 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 wh
         case SSL_CBC_RANDOM_IV:
             ss->opt.cbcRandomIV = val;
             break;
 
         case SSL_ENABLE_OCSP_STAPLING:
             ss->opt.enableOCSPStapling = val;
             break;
 
+        case SSL_ENABLE_DELEGATED_CREDENTIALS:
+            ss->opt.enableDelegatedCredentials = val;
+            break;
+
         case SSL_ENABLE_NPN:
             break;
 
         case SSL_ENABLE_ALPN:
             ss->opt.enableALPN = val;
             break;
 
         case SSL_REUSE_SERVER_ECDHE_KEY:
@@ -958,16 +964,19 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 wh
             val = ss->opt.enableFalseStart;
             break;
         case SSL_CBC_RANDOM_IV:
             val = ss->opt.cbcRandomIV;
             break;
         case SSL_ENABLE_OCSP_STAPLING:
             val = ss->opt.enableOCSPStapling;
             break;
+        case SSL_ENABLE_DELEGATED_CREDENTIALS:
+            val = ss->opt.enableDelegatedCredentials;
+            break;
         case SSL_ENABLE_NPN:
             val = PR_FALSE;
             break;
         case SSL_ENABLE_ALPN:
             val = ss->opt.enableALPN;
             break;
         case SSL_REUSE_SERVER_ECDHE_KEY:
             val = ss->opt.reuseServerECDHEKey;
@@ -1096,16 +1105,19 @@ SSL_OptionGetDefault(PRInt32 which, PRIn
             val = ssl_defaults.enableFalseStart;
             break;
         case SSL_CBC_RANDOM_IV:
             val = ssl_defaults.cbcRandomIV;
             break;
         case SSL_ENABLE_OCSP_STAPLING:
             val = ssl_defaults.enableOCSPStapling;
             break;
+        case SSL_ENABLE_DELEGATED_CREDENTIALS:
+            val = ssl_defaults.enableDelegatedCredentials;
+            break;
         case SSL_ENABLE_NPN:
             val = PR_FALSE;
             break;
         case SSL_ENABLE_ALPN:
             val = ssl_defaults.enableALPN;
             break;
         case SSL_REUSE_SERVER_ECDHE_KEY:
             val = ssl_defaults.reuseServerECDHEKey;
@@ -1286,16 +1298,20 @@ SSL_OptionSetDefault(PRInt32 which, PRIn
         case SSL_CBC_RANDOM_IV:
             ssl_defaults.cbcRandomIV = val;
             break;
 
         case SSL_ENABLE_OCSP_STAPLING:
             ssl_defaults.enableOCSPStapling = val;
             break;
 
+        case SSL_ENABLE_DELEGATED_CREDENTIALS:
+            ssl_defaults.enableDelegatedCredentials = val;
+            break;
+
         case SSL_ENABLE_NPN:
             break;
 
         case SSL_ENABLE_ALPN:
             ssl_defaults.enableALPN = val;
             break;
 
         case SSL_REUSE_SERVER_ECDHE_KEY:
@@ -4084,16 +4100,17 @@ SSL_CanBypass(CERTCertificate *cert, SEC
 struct {
     const char *const name;
     void *function;
 } ssl_experimental_functions[] = {
 #ifndef SSL_DISABLE_EXPERIMENTAL_API
     EXP(AeadDecrypt),
     EXP(AeadEncrypt),
     EXP(CreateAntiReplayContext),
+    EXP(DelegateCredential),
     EXP(DestroyAead),
     EXP(DestroyResumptionTokenInfo),
     EXP(EnableESNI),
     EXP(EncodeESNIKeys),
     EXP(GetCurrentEpoch),
     EXP(GetExtensionSupport),
     EXP(GetResumptionTokenInfo),
     EXP(HelloRetryRequestCallback),
--- a/security/nss/lib/ssl/sslt.h
+++ b/security/nss/lib/ssl/sslt.h
@@ -4,19 +4,20 @@
  *
  * 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 __sslt_h_
 #define __sslt_h_
 
+#include "certt.h"
+#include "keyhi.h"
 #include "prtypes.h"
 #include "secitem.h"
-#include "certt.h"
 
 typedef enum {
     ssl_hs_hello_request = 0,
     ssl_hs_client_hello = 1,
     ssl_hs_server_hello = 2,
     ssl_hs_hello_verify_request = 3,
     ssl_hs_new_session_ticket = 4,
     ssl_hs_end_of_early_data = 5,
@@ -262,16 +263,36 @@ typedef struct SSLExtraServerCertDataStr
     /* The remainder of the certificate chain. */
     const CERTCertificateList* certChain;
     /* A set of one or more stapled OCSP responses for the certificate.  This is
      * used to generate the OCSP stapling answer provided by the server. */
     const SECItemArray* stapledOCSPResponses;
     /* A serialized sign_certificate_timestamp extension, used to answer
      * requests from clients for this data. */
     const SECItem* signedCertTimestamps;
+
+    /* Delegated credentials.
+     *
+     * A serialized delegated credential (DC) to use for authentication to peers
+     * who indicate support for this extension (ietf-drafts-tls-subcerts). DCs
+     * are used opportunistically if (1) the client indicates support, (2) TLS
+     * 1.3 or higher is negotiated, and (3) the selected certificate is
+     * configured with a DC.
+     *
+     * Note that it's the caller's responsibility to ensure that the DC is
+     * well-formed.
+     */
+    const SECItem* delegCred;
+
+    /* The secret key corresponding to the |delegCred|.
+     *
+     * Note that it's the caller's responsibility to ensure that this matches
+     * the DC public key.
+     */
+    const SECKEYPrivateKey* delegCredPrivKey;
 } SSLExtraServerCertData;
 
 typedef struct SSLChannelInfoStr {
     /* On return, SSL_GetChannelInfo sets |length| to the smaller of
      * the |len| argument and the length of the struct used by NSS.
      * Callers must ensure the application uses a version of NSS that
      * isn't older than the version used at compile time. */
     PRUint32 length;
@@ -321,16 +342,21 @@ typedef struct SSLChannelInfoStr {
     /* The following fields were added in NSS 3.34. */
     /* When the session was resumed this holds the key exchange group of the
      * original handshake. */
     SSLNamedGroup originalKeaGroup;
     /* This field is PR_TRUE when the session is resumed and PR_FALSE
      * otherwise. */
     PRBool resumed;
 
+    /* Indicates whether the peer used a delegated credential (DC) for
+     * authentication.
+     */
+    PRBool peerDelegCred;
+
     /* When adding new fields to this structure, please document the
      * NSS version in which they were added. */
 } SSLChannelInfo;
 
 /* Preliminary channel info */
 #define ssl_preinfo_version (1U << 0)
 #define ssl_preinfo_cipher_suite (1U << 1)
 #define ssl_preinfo_0rtt_cipher_suite (1U << 2)
@@ -471,16 +497,17 @@ typedef enum {
     ssl_tls13_psk_key_exchange_modes_xtn = 45,
     ssl_tls13_ticket_early_data_info_xtn = 46, /* Deprecated. */
     ssl_tls13_certificate_authorities_xtn = 47,
     ssl_tls13_post_handshake_auth_xtn = 49,
     ssl_signature_algorithms_cert_xtn = 50,
     ssl_tls13_key_share_xtn = 51,
     ssl_next_proto_nego_xtn = 13172, /* Deprecated. */
     ssl_renegotiation_info_xtn = 0xff01,
+    ssl_delegated_credentials_xtn = 0xff02,
     ssl_tls13_short_header_xtn = 0xff03, /* Deprecated. */
     ssl_tls13_encrypted_sni_xtn = 0xffce,
 } SSLExtensionType;
 
 /* This is the old name for the supported_groups extensions. */
 #define ssl_elliptic_curves_xtn ssl_supported_groups_xtn
 
 /* SSL_MAX_EXTENSIONS includes the maximum number of extensions that are
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -19,16 +19,17 @@
 #include "sslerr.h"
 #include "ssl3exthandle.h"
 #include "tls13hkdf.h"
 #include "tls13con.h"
 #include "tls13err.h"
 #include "tls13esni.h"
 #include "tls13exthandle.h"
 #include "tls13hashstate.h"
+#include "tls13subcerts.h"
 
 static SECStatus tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
                                      SSLSecretDirection install,
                                      PRBool deleteSecret);
 static SECStatus tls13_AESGCM(const ssl3KeyMaterial *keys,
                               PRBool doDecrypt,
                               unsigned char *out,
                               unsigned int *outlen,
@@ -1584,16 +1585,30 @@ tls13_SelectServerCert(sslSocket *ss)
                                      cert->serverKeyPair->pubKey,
                                      cert->serverKeyPair->privKey,
                                      ss->xtnData.sigSchemes,
                                      ss->xtnData.numSigSchemes,
                                      PR_FALSE);
         if (rv == SECSuccess) {
             /* Found one. */
             ss->sec.serverCert = cert;
+
+            /* If we can use a delegated credential (DC) for authentication in
+             * the current handshake, then commit to using it now. We'll send a
+             * DC as an extension and use the DC private key to sign the
+             * handshake.
+             *
+             * This sets the signature scheme to be the signature scheme
+             * indicated by the DC.
+             */
+            rv = tls13_MaybeSetDelegatedCredential(ss);
+            if (rv != SECSuccess) {
+                return SECFailure; /* Failure indicates an internal error. */
+            }
+
             ss->sec.authType = ss->ssl3.hs.kea_def_mutable.authKeyType =
                 ssl_SignatureSchemeToAuthType(ss->ssl3.hs.signatureScheme);
             ss->sec.authKeyBits = cert->serverKeyBits;
             return SECSuccess;
         }
     }
 
     FATAL_ERROR(ss, SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM,
@@ -2615,17 +2630,24 @@ tls13_SendEncryptedServerSequence(sslSoc
     if (ss->ssl3.hs.signatureScheme != ssl_sig_none) {
         SECKEYPrivateKey *svrPrivKey;
 
         rv = tls13_SendCertificate(ss);
         if (rv != SECSuccess) {
             return SECFailure; /* error code is set. */
         }
 
-        svrPrivKey = ss->sec.serverCert->serverKeyPair->privKey;
+        if (tls13_IsSigningWithDelegatedCredential(ss)) {
+            SSL_TRC(3, ("%d: TLS13[%d]: Signing with delegated credential",
+                        SSL_GETPID(), ss->fd));
+            svrPrivKey = ss->sec.serverCert->delegCredKeyPair->privKey;
+        } else {
+            svrPrivKey = ss->sec.serverCert->serverKeyPair->privKey;
+        }
+
         rv = tls13_SendCertificateVerify(ss, svrPrivKey);
         if (rv != SECSuccess) {
             return SECFailure; /* err code is set. */
         }
     }
 
     rv = tls13_SendFinished(ss, ss->ssl3.hs.serverHsTrafficSecret);
     if (rv != SECSuccess) {
@@ -4115,16 +4137,18 @@ done:
 
 /* Called from tls13_CompleteHandleHandshakeMessage() when it has deciphered a complete
  * tls13 CertificateVerify message
  * Caller must hold Handshake and RecvBuf locks.
  */
 SECStatus
 tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
 {
+    sslDelegatedCredential *dc = ss->xtnData.peerDelegCred;
+    CERTSubjectPublicKeyInfo *spki = NULL;
     SECItem signed_hash = { siBuffer, NULL, 0 };
     SECStatus rv;
     SSLSignatureScheme sigScheme;
     SSLHashType hashAlg;
     SSL3Hashes tbsHash;
     SSL3Hashes hashes;
 
     SSL_TRC(3, ("%d: TLS13[%d]: handle certificate_verify handshake",
@@ -4154,17 +4178,48 @@ tls13_HandleCertificateVerify(sslSocket 
     }
 
     rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_VERIFY, illegal_parameter);
         return SECFailure;
     }
 
-    rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme, ss->sec.peerCert);
+    /* Set the |spki| used to verify the handshake. When verifying with a
+     * delegated credential (DC), this corresponds to the DC public key;
+     * otherwise it correspond to the public key of the peer's end-entity
+     * certificate.
+     */
+    if (tls13_IsVerifyingWithDelegatedCredential(ss)) {
+        /* DelegatedCredential.cred.expected_cert_verify_algorithm is expected
+         * to match CertificateVerify.scheme.
+         */
+        if (sigScheme != dc->expectedCertVerifyAlg) {
+            FATAL_ERROR(ss, SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH, illegal_parameter);
+            return SECFailure;
+        }
+
+        /* Verify the DC has three steps: (1) use the peer's end-entity
+         * certificate to verify DelegatedCredential.signature, (2) check that
+         * the certificate has the correct key usage, and (3) check that the DC
+         * hasn't expired.
+         */
+        rv = tls13_VerifyDelegatedCredential(ss, dc);
+        if (rv != SECSuccess) { /* Calls FATAL_ERROR() */
+            return SECFailure;
+        }
+
+        SSL_TRC(3, ("%d: TLS13[%d]: Verifying with delegated credential",
+                    SSL_GETPID(), ss->fd));
+        spki = dc->spki;
+    } else {
+        spki = &ss->sec.peerCert->subjectPublicKeyInfo;
+    }
+
+    rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme, spki);
     if (rv != SECSuccess) {
         /* Error set already */
         FATAL_ERROR(ss, PORT_GetError(), illegal_parameter);
         return SECFailure;
     }
     hashAlg = ssl_SignatureSchemeToHashType(sigScheme);
 
     rv = tls13_AddContextToHashes(ss, &hashes, hashAlg, PR_FALSE, &tbsHash);
@@ -4179,17 +4234,18 @@ tls13_HandleCertificateVerify(sslSocket 
         return SECFailure;
     }
 
     if (length != 0) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_VERIFY, decode_error);
         return SECFailure;
     }
 
-    rv = ssl3_VerifySignedHashes(ss, sigScheme, &tbsHash, &signed_hash);
+    rv = ssl3_VerifySignedHashesWithSpki(
+        ss, spki, sigScheme, &tbsHash, &signed_hash);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, PORT_GetError(), decrypt_error);
         return SECFailure;
     }
 
     /* Set the auth type. */
     if (!ss->sec.isServer) {
         ss->sec.authType = ssl_SignatureSchemeToAuthType(sigScheme);
@@ -5133,16 +5189,17 @@ static const struct {
     { ssl_tls13_pre_shared_key_xtn, _M2(client_hello, server_hello) },
     { ssl_tls13_psk_key_exchange_modes_xtn, _M1(client_hello) },
     { ssl_tls13_early_data_xtn, _M3(client_hello, encrypted_extensions,
                                     new_session_ticket) },
     { ssl_signed_cert_timestamp_xtn, _M3(client_hello, certificate_request,
                                          certificate) },
     { ssl_cert_status_xtn, _M3(client_hello, certificate_request,
                                certificate) },
+    { ssl_delegated_credentials_xtn, _M2(client_hello, certificate) },
     { ssl_tls13_cookie_xtn, _M2(client_hello, hello_retry_request) },
     { ssl_tls13_certificate_authorities_xtn, _M1(certificate_request) },
     { ssl_tls13_supported_versions_xtn, _M3(client_hello, server_hello,
                                             hello_retry_request) },
     { ssl_record_size_limit_xtn, _M2(client_hello, encrypted_extensions) },
     { ssl_tls13_encrypted_sni_xtn, _M2(client_hello, encrypted_extensions) },
     { ssl_tls13_post_handshake_auth_xtn, _M1(client_hello) }
 };
--- a/security/nss/lib/ssl/tls13exthandle.c
+++ b/security/nss/lib/ssl/tls13exthandle.c
@@ -9,16 +9,17 @@
 #include "ssl.h"
 #include "sslproto.h"
 #include "sslimpl.h"
 #include "pk11pub.h"
 #include "ssl3ext.h"
 #include "ssl3exthandle.h"
 #include "tls13esni.h"
 #include "tls13exthandle.h"
+#include "tls13subcerts.h"
 
 SECStatus
 tls13_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                  sslBuffer *buf, PRBool *added)
 {
     const sslServerCert *serverCert = ss->sec.serverCert;
     const SECItem *item;
     SECStatus rv;
@@ -1395,8 +1396,99 @@ tls13_ClientCheckEsniXtn(sslSocket *ss)
                               ss->xtnData.esniNonce,
                               sizeof(ss->xtnData.esniNonce))) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION, illegal_parameter);
         return SECFailure;
     }
 
     return SECSuccess;
 }
+
+/* Indicates support for the delegated credentials extension. This should be
+ * hooked while processing the ClientHello.
+ */
+SECStatus
+tls13_ClientSendDelegatedCredentialsXtn(const sslSocket *ss,
+                                        TLSExtensionData *xtnData,
+                                        sslBuffer *buf, PRBool *added)
+{
+    /* Only send the extension if support is enabled and the client can
+     * negotiate TLS 1.3.
+     */
+    if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3 ||
+        !ss->opt.enableDelegatedCredentials) {
+        return SECSuccess;
+    }
+
+    *added = PR_TRUE;
+    return SECSuccess;
+}
+
+/* Parses the delegated credential (DC) offered by the server. This should be
+ * hooked while processing the server's CertificateVerify.
+ *
+ * Only the DC sent with the end-entity certificate is to be parsed. This is
+ * ensured by |tls13_HandleCertificateEntry|, which only processes extensions
+ * for the first certificate in the chain.
+ */
+SECStatus
+tls13_ClientHandleDelegatedCredentialsXtn(const sslSocket *ss,
+                                          TLSExtensionData *xtnData,
+                                          SECItem *data)
+{
+    if (!ss->opt.enableDelegatedCredentials ||
+        ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+        ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
+        PORT_SetError(SSL_ERROR_RX_UNEXPECTED_EXTENSION);
+        return SECFailure;
+    }
+
+    SECStatus rv = tls13_ReadDelegatedCredential(data->data, data->len,
+                                                 &xtnData->peerDelegCred);
+    if (rv != SECSuccess) {
+        return SECFailure; /* code already set */
+    }
+
+    xtnData->negotiated[xtnData->numNegotiated++] =
+        ssl_delegated_credentials_xtn;
+    return SECSuccess;
+}
+
+/* Adds the DC extension if we're committed to authenticating with a DC. */
+static SECStatus
+tls13_ServerSendDelegatedCredentialsXtn(const sslSocket *ss,
+                                        TLSExtensionData *xtnData,
+                                        sslBuffer *buf, PRBool *added)
+{
+    if (tls13_IsSigningWithDelegatedCredential(ss)) {
+        const SECItem *dc = &ss->sec.serverCert->delegCred;
+
+        if (tls13_IsSigningWithDelegatedCredential(ss)) {
+            SECStatus rv;
+            rv = sslBuffer_Append(buf, dc->data, dc->len);
+            if (rv != SECSuccess) {
+                return SECFailure;
+            }
+        }
+
+        *added = PR_TRUE;
+        return SECSuccess;
+    }
+
+    return SECSuccess;
+}
+
+/* The client has indicated support of DCs. We can't act on this information
+ * until we've committed to signing with a DC, so just set a callback for
+ * sending the DC extension later. */
+SECStatus
+tls13_ServerHandleDelegatedCredentialsXtn(const sslSocket *ss,
+                                          TLSExtensionData *xtnData,
+                                          SECItem *data)
+{
+    xtnData->peerRequestedDelegCred = PR_TRUE;
+    xtnData->negotiated[xtnData->numNegotiated++] =
+        ssl_delegated_credentials_xtn;
+
+    return ssl3_RegisterExtensionSender(
+        ss, xtnData, ssl_delegated_credentials_xtn,
+        tls13_ServerSendDelegatedCredentialsXtn);
+}
--- a/security/nss/lib/ssl/tls13exthandle.h
+++ b/security/nss/lib/ssl/tls13exthandle.h
@@ -94,10 +94,19 @@ SECStatus tls13_ServerHandleEsniXtn(cons
                                     SECItem *data);
 SECStatus tls13_ClientCheckEsniXtn(sslSocket *ss);
 SECStatus tls13_ClientSendPostHandshakeAuthXtn(const sslSocket *ss,
                                                TLSExtensionData *xtnData,
                                                sslBuffer *buf, PRBool *added);
 SECStatus tls13_ServerHandlePostHandshakeAuthXtn(const sslSocket *ss,
                                                  TLSExtensionData *xtnData,
                                                  SECItem *data);
+SECStatus tls13_ClientHandleDelegatedCredentialsXtn(const sslSocket *ss,
+                                                    TLSExtensionData *xtnData,
+                                                    SECItem *data);
+SECStatus tls13_ClientSendDelegatedCredentialsXtn(const sslSocket *ss,
+                                                  TLSExtensionData *xtnData,
+                                                  sslBuffer *buf, PRBool *added);
+SECStatus tls13_ServerHandleDelegatedCredentialsXtn(const sslSocket *ss,
+                                                    TLSExtensionData *xtnData,
+                                                    SECItem *data);
 
 #endif
new file mode 100644
--- /dev/null
+++ b/security/nss/lib/ssl/tls13subcerts.c
@@ -0,0 +1,594 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 "nss.h"
+#include "pk11func.h"
+#include "secder.h"
+#include "ssl.h"
+#include "sslproto.h"
+#include "sslimpl.h"
+#include "ssl3exthandle.h"
+#include "tls13exthandle.h"
+#include "tls13hkdf.h"
+#include "tls13subcerts.h"
+
+/* Parses the delegated credential (DC) from the raw extension |b| of length
+ * |length|. Memory for the DC is allocated and set to |*dcp|.
+ *
+ * It's the caller's responsibility to invoke |tls13_DestroyDelegatedCredential|
+ * when this data is no longer needed.
+ */
+SECStatus
+tls13_ReadDelegatedCredential(PRUint8 *b, PRUint32 length,
+                              sslDelegatedCredential **dcp)
+{
+    sslDelegatedCredential *dc = NULL;
+    SECStatus rv;
+    PRUint64 n;
+    sslReadBuffer tmp;
+    sslReader rdr = SSL_READER(b, length);
+
+    PORT_Assert(!*dcp);
+
+    dc = PORT_ZNew(sslDelegatedCredential);
+    if (!dc) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        goto loser;
+    }
+
+    /* Read the valid_time field of DelegatedCredential.cred. */
+    rv = sslRead_ReadNumber(&rdr, 4, &n);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+    dc->validTime = n;
+
+    /* Read the expected_cert_verify_algorithm field of
+     * DelegatedCredential.cred. */
+    rv = sslRead_ReadNumber(&rdr, 2, &n);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+    dc->expectedCertVerifyAlg = n;
+
+    /* Read the ASN1_subjectPublicKeyInfo field of DelegatedCredential.cred. */
+    rv = sslRead_ReadVariable(&rdr, 3, &tmp);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+    rv = SECITEM_MakeItem(NULL, &dc->derSpki, tmp.buf, tmp.len);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+    /* Parse the DER-encoded SubjectPublicKeyInfo. */
+    dc->spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&dc->derSpki);
+    if (!dc->spki) {
+        goto loser;
+    }
+
+    /* Read the algorithm field of the DelegatedCredential. */
+    rv = sslRead_ReadNumber(&rdr, 2, &n);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+    dc->alg = n;
+
+    /* Read the signature field of the DelegatedCredential. */
+    rv = sslRead_ReadVariable(&rdr, 2, &tmp);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+    rv = SECITEM_MakeItem(NULL, &dc->signature, tmp.buf, tmp.len);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+    /* There should be nothing left to read. */
+    if (SSL_READER_REMAINING(&rdr) > 0) {
+        goto loser;
+    }
+
+    *dcp = dc;
+    return SECSuccess;
+
+loser:
+    tls13_DestroyDelegatedCredential(dc);
+    *dcp = NULL;
+    return SECFailure;
+}
+
+/* Frees |dc| from the heap. */
+void
+tls13_DestroyDelegatedCredential(sslDelegatedCredential *dc)
+{
+    if (!dc) {
+        return;
+    }
+
+    SECKEY_DestroySubjectPublicKeyInfo(dc->spki);
+    SECITEM_FreeItem(&dc->derSpki, PR_FALSE);
+    SECITEM_FreeItem(&dc->signature, PR_FALSE);
+    PORT_ZFree(dc, sizeof(sslDelegatedCredential));
+}
+
+/* Sets |*certVerifyAlg| to the expected_cert_verify_algorithm field from the
+ * serialized DC |in|. Returns SECSuccess upon success; SECFailure indicates a
+ * decoding failure or the input wasn't long enough.
+ */
+static SECStatus
+tls13_GetExpectedCertVerifyAlg(SECItem in, SSLSignatureScheme *certVerifyAlg)
+{
+    SECStatus rv;
+    PRUint64 n;
+    sslReader rdr = SSL_READER(in.data, in.len);
+
+    if (in.len < 6) { /* Buffer too short to contain the first two params. */
+        return SECFailure;
+    }
+
+    rv = sslRead_ReadNumber(&rdr, 4, &n);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    rv = sslRead_ReadNumber(&rdr, 2, &n);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+    *certVerifyAlg = n;
+
+    return SECSuccess;
+}
+
+/* Returns PR_TRUE if the host is verifying the handshake with a DC. */
+PRBool
+tls13_IsVerifyingWithDelegatedCredential(const sslSocket *ss)
+{
+    /* As of draft-ietf-subcerts-03, only the server may authenticate itself
+     * with a DC.
+     */
+    if (ss->sec.isServer ||
+        !ss->opt.enableDelegatedCredentials ||
+        !ss->xtnData.peerDelegCred) {
+        return PR_FALSE;
+    }
+
+    return PR_TRUE;
+}
+
+/* Returns PR_TRUE if the host is signing the handshake with a DC. */
+PRBool
+tls13_IsSigningWithDelegatedCredential(const sslSocket *ss)
+{
+    if (!ss->sec.isServer ||
+        !ss->xtnData.sendingDelegCredToPeer ||
+        !ss->xtnData.peerRequestedDelegCred) {
+        return PR_FALSE;
+    }
+
+    return PR_TRUE;
+}
+
+/* Commits to authenticating with a DC if all of the following conditions hold:
+ *  - the negotiated protocol is TLS 1.3 or newer;
+ *  - the selected certificate has a DC configured;
+ *  - the peer has indicated support for this extension;
+ *  - the peer has indicated support for the DC signature scheme; and
+ *  - the host supports the DC signature scheme.
+ *
+ * It's the caller's responsibility to ensure that the version has been
+ * negotiated and the certificate has been selected.
+ */
+SECStatus
+tls13_MaybeSetDelegatedCredential(sslSocket *ss)
+{
+    SECStatus rv;
+    PRBool doesRsaPss;
+    SECKEYPrivateKey *priv;
+    SSLSignatureScheme scheme;
+
+    /* Assert that the host is the server (as of draft-ietf-subcerts-03, only
+     * the server may authenticate itself with a DC), the certificate has been
+     * chosen, TLS 1.3 or higher has been negotiated, and that the set of
+     * signature schemes supported by the client is known.
+     */
+    PORT_Assert(ss->sec.isServer);
+    PORT_Assert(ss->sec.serverCert);
+    PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
+    PORT_Assert(ss->xtnData.sigSchemes);
+
+    /* Check that the peer has indicated support and that a DC has been
+     * configured for the selected certificate.
+     */
+    if (!ss->xtnData.peerRequestedDelegCred ||
+        !ss->sec.serverCert->delegCred.len ||
+        !ss->sec.serverCert->delegCredKeyPair) {
+        return SECSuccess;
+    }
+
+    /* Check that the host and peer both support the signing algorithm used with
+     * the DC.
+     */
+    rv = tls13_GetExpectedCertVerifyAlg(ss->sec.serverCert->delegCred,
+                                        &scheme);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    priv = ss->sec.serverCert->delegCredKeyPair->privKey;
+    rv = ssl_PrivateKeySupportsRsaPss(priv, &doesRsaPss);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    if (!ssl_SignatureSchemeEnabled(ss, scheme) ||
+        !ssl_CanUseSignatureScheme(scheme,
+                                   ss->xtnData.sigSchemes,
+                                   ss->xtnData.numSigSchemes,
+                                   PR_FALSE /* requireSha1 */,
+                                   doesRsaPss)) {
+        return SECSuccess;
+    }
+
+    /* Commit to sending a DC and set the handshake signature scheme to the
+     * indicated algorithm.
+     */
+    ss->xtnData.sendingDelegCredToPeer = PR_TRUE;
+    ss->ssl3.hs.signatureScheme = scheme;
+    return SECSuccess;
+}
+
+/* Serializes the DC up to the signature. */
+static SECStatus
+tls13_AppendCredentialParams(sslBuffer *buf, sslDelegatedCredential *dc)
+{
+    SECStatus rv;
+    rv = sslBuffer_AppendNumber(buf, dc->validTime, 4);
+    if (rv != SECSuccess) {
+        return SECFailure; /* Error set by caller. */
+    }
+
+    rv = sslBuffer_AppendNumber(buf, dc->expectedCertVerifyAlg, 2);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    rv = sslBuffer_AppendVariable(buf, dc->derSpki.data, dc->derSpki.len, 3);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    rv = sslBuffer_AppendNumber(buf, dc->alg, 2);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    return SECSuccess;
+}
+
+/* Serializes the DC signature. */
+static SECStatus
+tls13_AppendCredentialSignature(sslBuffer *buf, sslDelegatedCredential *dc)
+{
+    SECStatus rv;
+    rv = sslBuffer_AppendVariable(buf, dc->signature.data,
+                                  dc->signature.len, 2);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    return SECSuccess;
+}
+
+/* Hashes the message used to sign/verify the DC. */
+static SECStatus
+tls13_HashCredentialSignatureMessage(SSL3Hashes *hash,
+                                     SSLSignatureScheme scheme,
+                                     const CERTCertificate *cert,
+                                     const sslBuffer *dcBuf)
+{
+    SECStatus rv;
+    PK11Context *ctx = NULL;
+    unsigned int hashLen;
+
+    /* Set up hash context. */
+    hash->hashAlg = ssl_SignatureSchemeToHashType(scheme);
+    ctx = PK11_CreateDigestContext(ssl3_HashTypeToOID(hash->hashAlg));
+    if (!ctx) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        goto loser;
+    }
+
+    static const PRUint8 kCtxStrPadding[64] = {
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    };
+
+    static const PRUint8 kCtxStr[] = "TLS, server delegated credentials";
+
+    /* Hash the message signed by the peer. */
+    rv = SECSuccess;
+    rv |= PK11_DigestBegin(ctx);
+    rv |= PK11_DigestOp(ctx, kCtxStrPadding, sizeof kCtxStrPadding);
+    rv |= PK11_DigestOp(ctx, kCtxStr, 1 /* 0-byte */ + strlen((const char *)kCtxStr));
+    rv |= PK11_DigestOp(ctx, cert->derCert.data, cert->derCert.len);
+    rv |= PK11_DigestOp(ctx, dcBuf->buf, dcBuf->len);
+    rv |= PK11_DigestFinal(ctx, hash->u.raw, &hashLen, sizeof hash->u.raw);
+    if (rv != SECSuccess) {
+        PORT_SetError(SSL_ERROR_SHA_DIGEST_FAILURE);
+        goto loser;
+    }
+
+    hash->len = hashLen;
+    if (ctx) {
+        PK11_DestroyContext(ctx, PR_TRUE);
+    }
+    return SECSuccess;
+
+loser:
+    if (ctx) {
+        PK11_DestroyContext(ctx, PR_TRUE);
+    }
+    return SECFailure;
+}
+
+/* Verifies the DC signature. */
+static SECStatus
+tls13_VerifyCredentialSignature(sslSocket *ss, sslDelegatedCredential *dc)
+{
+    SECStatus rv = SECSuccess;
+    SSL3Hashes hash;
+    sslBuffer dcBuf = SSL_BUFFER_EMPTY;
+    CERTCertificate *cert = ss->sec.peerCert;
+
+    /* Serialize the DC parameters. */
+    rv = tls13_AppendCredentialParams(&dcBuf, dc);
+    if (rv != SECSuccess) {
+        goto loser; /* Error set by caller. */
+    }
+
+    /* Hash the message that was signed by the delegator. */
+    rv = tls13_HashCredentialSignatureMessage(&hash, dc->alg, cert, &dcBuf);
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, PORT_GetError(), internal_error);
+        goto loser;
+    }
+
+    /* Verify the signature of the message. */
+    rv = ssl3_VerifySignedHashesWithSpki(
+        ss, &cert->subjectPublicKeyInfo, dc->alg, &hash, &dc->signature);
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, SSL_ERROR_DC_BAD_SIGNATURE, illegal_parameter);
+        goto loser;
+    }
+
+    sslBuffer_Clear(&dcBuf);
+    return SECSuccess;
+
+loser:
+    sslBuffer_Clear(&dcBuf);
+    return SECFailure;
+}
+
+/* Checks that the peer's end-entity certificate has the correct key usage. */
+static SECStatus
+tls13_CheckCertDelegationUsage(sslSocket *ss)
+{
+    int i;
+    PRBool found;
+    CERTCertExtension *ext;
+    SECItem delegUsageOid = { siBuffer, NULL, 0 };
+    const CERTCertificate *cert = ss->sec.peerCert;
+
+    /* 1.3.6.1.4.1.44363.44, as defined in draft-ietf-tls-subcerts. */
+    static unsigned char kDelegationUsageOid[] = {
+        0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xda, 0x4b, 0x2c,
+    };
+
+    delegUsageOid.data = kDelegationUsageOid;
+    delegUsageOid.len = sizeof kDelegationUsageOid;
+
+    /* The certificate must have the delegationUsage extension that authorizes
+     * it to negotiate delegated credentials.
+     */
+    found = PR_FALSE;
+    for (i = 0; cert->extensions[i] != NULL; i++) {
+        ext = cert->extensions[i];
+        if (SECITEM_CompareItem(&ext->id, &delegUsageOid) == SECEqual) {
+            found = PR_TRUE;
+            break;
+        }
+    }
+
+    /* The certificate must also have the digitalSignature keyUsage set. */
+    if (!found ||
+        !cert->keyUsagePresent ||
+        !(cert->keyUsage & KU_DIGITAL_SIGNATURE)) {
+        FATAL_ERROR(ss, SSL_ERROR_DC_INVALID_KEY_USAGE, illegal_parameter);
+        return SECFailure;
+    }
+
+    return SECSuccess;
+}
+
+static SECStatus
+tls13_CheckCredentialExpiration(sslSocket *ss, sslDelegatedCredential *dc)
+{
+    SECStatus rv;
+    PRTime start, end /* microseconds */;
+    CERTCertificate *cert = ss->sec.peerCert;
+
+    rv = DER_DecodeTimeChoice(&start, &cert->validity.notBefore);
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, PORT_GetError(), internal_error);
+        return SECFailure;
+    }
+
+    end = start + ((PRTime)dc->validTime * PR_USEC_PER_SEC);
+    if (ssl_Time(ss) > end) {
+        FATAL_ERROR(ss, SSL_ERROR_DC_EXPIRED, illegal_parameter);
+        return SECFailure;
+    }
+
+    return SECSuccess;
+}
+
+/* Returns SECSucces if |dc| is a DC for the current handshake; otherwise it
+ * returns SECFailure. A valid DC meets three requirements: (1) the signature
+ * was produced by the peer's end-entity certificate, (2) the end-entity
+ * certificate must have the correct key usage, and (3) the DC must not be
+ * expired.
+ *
+ * This function calls FATAL_ERROR() when an error occurs.
+ */
+SECStatus
+tls13_VerifyDelegatedCredential(sslSocket *ss,
+                                sslDelegatedCredential *dc)
+{
+    SECStatus rv;
+    PRTime start;
+    PRExplodedTime end;
+    CERTCertificate *cert = ss->sec.peerCert;
+    char endStr[256];
+
+    rv = DER_DecodeTimeChoice(&start, &cert->validity.notBefore);
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, PORT_GetError(), internal_error);
+        return SECFailure;
+    }
+
+    PR_ExplodeTime(start + (dc->validTime * PR_USEC_PER_SEC),
+                   PR_GMTParameters, &end);
+    if (PR_FormatTime(endStr, sizeof(endStr), "%a %b %d %H:%M:%S %Y", &end)) {
+        SSL_TRC(20, ("%d: TLS13[%d]: Received delegated credential (expires %s)",
+                     SSL_GETPID(), ss->fd, endStr));
+    } else {
+        SSL_TRC(20, ("%d: TLS13[%d]: Received delegated credential",
+                     SSL_GETPID(), ss->fd));
+    }
+
+    rv = SECSuccess;
+    rv |= tls13_VerifyCredentialSignature(ss, dc);
+    rv |= tls13_CheckCertDelegationUsage(ss);
+    rv |= tls13_CheckCredentialExpiration(ss, dc);
+    return rv;
+}
+
+/* Returns a serialized DC with the given parameters.
+ *
+ * Note that this function is meant primarily for testing. In particular, it
+ * DOES NOT verify any of the following:
+ *  - |certPriv| is the private key corresponding to |cert|;
+ *  - that |checkCertKeyUsage(cert) == SECSuccess|;
+ *  - |dcCertVerifyAlg| is consistent with |dcPub|;
+ *  - |dcValidFor| is less than 7 days (the maximum permitted by the spec); or
+ *  - validTime doesn't overflow a PRUint32.
+ *
+ * These conditions are things we want to test for, which is why we allow them
+ * here. A real API for creating DCs would want to explicitly check ALL of these
+ * conditions are met.
+ */
+SECStatus
+SSLExp_DelegateCredential(const CERTCertificate *cert,
+                          const SECKEYPrivateKey *certPriv,
+                          const SECKEYPublicKey *dcPub,
+                          SSLSignatureScheme dcCertVerifyAlg,
+                          PRUint32 dcValidFor,
+                          PRTime now,
+                          SECItem *out)
+{
+    SECStatus rv;
+    SSL3Hashes hash;
+    SECItem *tmp = NULL;
+    SECKEYPrivateKey *tmpPriv = NULL;
+    sslDelegatedCredential *dc = NULL;
+    sslBuffer dcBuf = SSL_BUFFER_EMPTY;
+
+    dc = PORT_ZNew(sslDelegatedCredential);
+    if (!dc) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        goto loser;
+    }
+
+    /* Serialize the DC parameters. */
+    PRTime start;
+    rv = DER_DecodeTimeChoice(&start, &cert->validity.notBefore);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+    dc->validTime = ((now - start) / PR_USEC_PER_SEC) + dcValidFor;
+    dc->expectedCertVerifyAlg = dcCertVerifyAlg;
+
+    tmp = SECKEY_EncodeDERSubjectPublicKeyInfo(dcPub);
+    if (!tmp) {
+        goto loser;
+    }
+    /* Transfer |tmp| into |dc->derSpki|. */
+    dc->derSpki.type = tmp->type;
+    dc->derSpki.data = tmp->data;
+    dc->derSpki.len = tmp->len;
+    PORT_Free(tmp);
+
+    rv = ssl_SignatureSchemeFromSpki(&cert->subjectPublicKeyInfo,
+                                     PR_TRUE /* isTls13 */, &dc->alg);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+    PORT_Assert(dc->alg != ssl_sig_none);
+
+    rv = tls13_AppendCredentialParams(&dcBuf, dc);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+    /* Hash signature message. */
+    rv = tls13_HashCredentialSignatureMessage(&hash, dc->alg, cert, &dcBuf);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+    /* Sign the hash with the delegation key.
+     *
+     * The PK11 API discards const qualifiers, so we have to make a copy of
+     * |certPriv| and pass the copy to |ssl3_SignHashesWithPrivKey|.
+     */
+    tmpPriv = SECKEY_CopyPrivateKey(certPriv);
+    rv = ssl3_SignHashesWithPrivKey(&hash, tmpPriv, dc->alg,
+                                    PR_TRUE /* isTls */, &dc->signature);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+    /* Serialize the DC signature. */
+    rv = tls13_AppendCredentialSignature(&dcBuf, dc);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+    /* Copy the serialized DC to |out|. */
+    rv = SECITEM_MakeItem(NULL, out, dcBuf.buf, dcBuf.len);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+    SECKEY_DestroyPrivateKey(tmpPriv);
+    tls13_DestroyDelegatedCredential(dc);
+    sslBuffer_Clear(&dcBuf);
+    return SECSuccess;
+
+loser:
+    SECKEY_DestroyPrivateKey(tmpPriv);
+    tls13_DestroyDelegatedCredential(dc);
+    sslBuffer_Clear(&dcBuf);
+    return SECFailure;
+}
new file mode 100644
--- /dev/null
+++ b/security/nss/lib/ssl/tls13subcerts.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is PRIVATE to SSL.
+ *
+ * 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 __tls13subcerts_h_
+#define __tls13subcerts_h_
+
+struct sslDelegatedCredentialStr {
+    /* The number of seconds for which the delegated credential (DC) is valid
+     * following the notBefore parameter of the delegation certificate.
+     */
+    PRUint32 validTime;
+
+    /* The signature algorithm of the DC public key. This expected to the same
+     * as CertificateVerify.scheme.
+     */
+    SSLSignatureScheme expectedCertVerifyAlg;
+
+    /* The DER-encoded SubjectPublicKeyInfo, the DC public key.
+     */
+    SECItem derSpki;
+
+    /* The decoded SubjectPublicKeyInfo parsed from |derSpki|. */
+    CERTSubjectPublicKeyInfo *spki;
+
+    /* The signature algorithm used to verify the DC signature. */
+    SSLSignatureScheme alg;
+
+    /* The DC signature. */
+    SECItem signature;
+};
+
+SECStatus tls13_ReadDelegatedCredential(PRUint8 *b,
+                                        PRUint32 length,
+                                        sslDelegatedCredential **dcp);
+void tls13_DestroyDelegatedCredential(sslDelegatedCredential *dc);
+
+PRBool tls13_IsVerifyingWithDelegatedCredential(const sslSocket *ss);
+PRBool tls13_IsSigningWithDelegatedCredential(const sslSocket *ss);
+SECStatus tls13_MaybeSetDelegatedCredential(sslSocket *ss);
+SECStatus tls13_VerifyDelegatedCredential(sslSocket *ss,
+                                          sslDelegatedCredential *dc);
+
+SECStatus SSLExp_DelegateCredential(const CERTCertificate *cert,
+                                    const SECKEYPrivateKey *certPriv,
+                                    const SECKEYPublicKey *dcPub,
+                                    SSLSignatureScheme dcCertVerifyAlg,
+                                    PRUint32 dcValidFor,
+                                    PRTime now,
+                                    SECItem *out);
+
+#endif
--- a/security/nss/tests/common/certsetup.sh
+++ b/security/nss/tests/common/certsetup.sh
@@ -41,16 +41,21 @@ make_cert() {
     p384) type_args=(-q secp384r1);type=ec ;;
     p521) type_args=(-q secp521r1);type=ec ;;
     rsa_ca) type_args=(-g 1024);trust='CT,CT,CT';type=rsa ;;
     rsa_chain) type_args=(-g 1024);sign=(-c rsa_ca);type=rsa;;
     rsapss_ca) type_args=(-g 1024 --pss);trust='CT,CT,CT';type=rsa ;;
     rsapss_chain) type_args=(-g 1024);sign=(-c rsa_pss_ca);type=rsa;;
     rsa_ca_rsapss_chain) type_args=(-g 1024 --pss-sign);sign=(-c rsa_ca);type=rsa;;
     ecdh_rsa) type_args=(-q nistp256);sign=(-c rsa_ca);type=ec ;;
+    delegator_p256)
+        touch empty.txt
+        type_args=(-q nistp256 --extGeneric 1.3.6.1.4.1.44363.44:not-critical:empty.txt)
+        type=ec
+        ;;
   esac
   msg="create certificate: $@"
   shift 2
   counter=$(($counter + 1))
   certscript $@ | ${BINDIR}/certutil -S \
     -z "$R_NOISE_FILE" -d "$PROFILEDIR" \
     -n $name -s "CN=$name" -t "$trust" "${sign[@]}" -m "$counter" \
     -w -2 -v 120 -k "$type" "${type_args[@]}" "${sighash[@]}" -1 -2
--- a/security/nss/tests/ssl_gtests/ssl_gtests.sh
+++ b/security/nss/tests/ssl_gtests/ssl_gtests.sh
@@ -52,16 +52,17 @@ ssl_gtest_certs() {
   make_cert ecdh_ecdsa p256 kex
   make_cert rsa_ca rsa_ca ca
   make_cert rsa_chain rsa_chain sign
   make_cert rsa_pss_ca rsapss_ca ca
   make_cert rsa_pss_chain rsapss_chain sign
   make_cert rsa_ca_rsa_pss_chain rsa_ca_rsapss_chain sign
   make_cert ecdh_rsa ecdh_rsa kex
   make_cert dsa dsa sign
+  make_cert delegator_ecdsa256 delegator_p256 sign
 }
 
 ############################## ssl_gtest_init ##########################
 # local shell function to initialize this script
 ########################################################################
 ssl_gtest_init()
 {
   SCRIPTNAME=ssl_gtest.sh      # sourced - $0 would point to all.sh
--- a/third_party/rust/cranelift-bforest/.cargo-checksum.json
+++ b/third_party/rust/cranelift-bforest/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"4fb2be5a108736ec2eeb257fd9c90d7e4384321e34eaef0fc7c5517a8e096650","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"af367c67340fa7f6fb9a35b0aa637dcf303957f7ae7427a5f4f6356801c8bb04","src/lib.rs":"1b23abbfe5850a4cd77ae6ae5dcfc2f678ef36b4032fd7496f2b333c51e63301","src/map.rs":"5d891d62814941e19dfc88ff36538efa3da5479f3f97de8219a6f610c9a1ee32","src/node.rs":"e620c64e78488035f11723b14892c7986c06ad37dc5b115a35a453ff1ae66ca3","src/path.rs":"4868e59ff67db1c504747e4b7e202dd20c9da4cbd73d9fa82d53e5f3406dbb78","src/pool.rs":"6090f8c0e0da16ebee0e31bca66392d0075b3aff529d30d4e716fa20cd0aef99","src/set.rs":"b411158f813a310c7a6c337d4ada3bf0a021088c443875dc25233415dcbe0633"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"4fb2be5a108736ec2eeb257fd9c90d7e4384321e34eaef0fc7c5517a8e096650","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"af367c67340fa7f6fb9a35b0aa637dcf303957f7ae7427a5f4f6356801c8bb04","src/lib.rs":"1b23abbfe5850a4cd77ae6ae5dcfc2f678ef36b4032fd7496f2b333c51e63301","src/map.rs":"5d891d62814941e19dfc88ff36538efa3da5479f3f97de8219a6f610c9a1ee32","src/node.rs":"e620c64e78488035f11723b14892c7986c06ad37dc5b115a35a453ff1ae66ca3","src/path.rs":"a86ee1c882c173e8af96fd53a416a0fb485dd3f045ac590ef313a9d9ecf90f56","src/pool.rs":"6090f8c0e0da16ebee0e31bca66392d0075b3aff529d30d4e716fa20cd0aef99","src/set.rs":"b411158f813a310c7a6c337d4ada3bf0a021088c443875dc25233415dcbe0633"},"package":null}
\ No newline at end of file
--- a/third_party/rust/cranelift-bforest/src/path.rs
+++ b/third_party/rust/cranelift-bforest/src/path.rs
@@ -44,17 +44,17 @@ impl<F: Forest> Path<F> {
     /// - A key between the stored keys of adjacent leaf nodes returns a path to one beyond the
     ///   last entry of the first of the leaf nodes.
     ///
     pub fn find(
         &mut self,
         key: F::Key,
         root: Node,
         pool: &NodePool<F>,
-        comp: &Comparator<F::Key>,
+        comp: &dyn Comparator<F::Key>,
     ) -> Option<F::Value> {
         let mut node = root;
         for level in 0.. {
             self.size = level + 1;
             self.node[level] = node;
             match pool[node] {
                 NodeData::Inner { size, keys, tree } => {
                     // Invariant: `tree[i]` contains keys smaller than
--- a/third_party/rust/cranelift-codegen-meta/.cargo-checksum.json
+++ b/third_party/rust/cranelift-codegen-meta/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"253c80832ab598570d604ae8a8108ea9835b8eef8d9b9645408ed025ce3b574a","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/cdsl/ast.rs":"170f0526c73e4ebdd22cf25290607b6610e9e3fe0b1d79ee38962085f878d2e4","src/cdsl/cpu_modes.rs":"57c40621115a58faa7af1c729ecaf8cda01c2b143008bde6d8c70885e7c3fd75","src/cdsl/formats.rs":"8eaee84c9c574e7a2ab73b4bf63b97c1cea3ffce0a477f1701e75a7a523ada57","src/cdsl/instructions.rs":"dd734b1ff0750ec09a06e5746338f479ae97eb122dc64dba37b656ab5ae79ebd","src/cdsl/isa.rs":"569bf078c68c800fbd36fde1b52e0371747f6249252655e2dc4715d4e975be40","src/cdsl/mod.rs":"86149f101e1b00a9623028dcd779ad66b6a67f0f67b423c5ac88cd96dabdd227","src/cdsl/operands.rs":"1cda258798d861c4f467783b5c70c1202a57f554861017eead6477af2ee34063","src/cdsl/regs.rs":"049d299c63a757aad7adb7945b3919bd62c9204348a4f8b9727ca84fecbf3115","src/cdsl/settings.rs":"b6b1653b486fb4b86aaab59328a959cf784cb4b61b3216fe7acebe0490849642","src/cdsl/type_inference.rs":"2771631701c150e077c5dcf705c8ae8705944d86ab945ae9e7adc82f3ca5447a","src/cdsl/types.rs":"4cc1f20eb8383fdee6a9e7ca0f7758e563a4fb715056b5edbd4db72f8dfd471b","src/cdsl/typevar.rs":"7249fcd7c3cd3645e8489c73595bd5327bedc499bd7bc87f2a68e241fba329c3","src/cdsl/xform.rs":"005bd2fca7f8b737c605a75a0f44f2d70f0138e67f3013343ced81f639dce8bb","src/constant_hash.rs":"b8acd3f8712a4999819d9d9beced2938d9940a5748ba016c182f1132d97eefab","src/error.rs":"5110a4e3c1e97396ba02d9f5abbb8af4b586f0cc4d33a5c2473f1718cc4bef05","src/gen_inst.rs":"94e71181683f022fdcc55abf487a20be5d4dd51fe3092345b6bc4e2bde04441b","src/gen_legalizer.rs":"8c525a42df0b8283c445a1abd5376682500b49ee8033bc66575f8e14f29f4de3","src/gen_registers.rs":"a544a2b91fafe08639e39e50bea0892fda89fe2f6eaf111b2d5f3e98e4d07b86","src/gen_settings.rs":"4469bf496f9539835fce3cd9743ac0fbc270b3029b0e6c949f406e790685199c","src/gen_types.rs":"3935da6c6a53f9332e06f74bc3a46270656b4d4231ad28ed2648d7b1d2774e90","src/isa/arm32/mod.rs":"54e88d89644c5cee61cdc8315f1d77b01c232dc322c52f6e244cef9e7688a3ad","src/isa/arm64/mod.rs":"c5169b92c1bcb562649a48b7880033f542c9affa73274d23b3817e4ac83942fe","src/isa/mod.rs":"fce60d19dd3c099ebee3ac5ae64a2bee363f13da9ff5a4960d3c1a0bee71d29a","src/isa/riscv/mod.rs":"2da05e3974ef0b72431c9fdda14314890f72500b94def1d74cdf5e74bd950bc0","src/isa/x86/instructions.rs":"ad88f311fd51f341f7dfe395f98d8805ea55e1c86d1a89272ed999f5ae8dc3f0","src/isa/x86/legalize.rs":"251af731b2514fead08e27e812ca44dc674a41bd4a9637d9d919259497961961","src/isa/x86/mod.rs":"14715e552eedfeae1693a416bb82bda2156b31cd4b306e07530a3c1acdc17125","src/isa/x86/registers.rs":"c0bc60336a8c8b7b4db92dc623e9419a60af14dd6252f0b19e227e46f7166178","src/isa/x86/settings.rs":"1a74b3d1ef5e99e0b7c75528b9fd5afbb3394979615b005b43b72108757a9886","src/lib.rs":"8c9364c6fce73c158abfb7c88ecff01dc608a05c250e89df9bec3082773cde6d","src/shared/entities.rs":"80b8ff57a09c7b2f9dab755abbcc2738317de474776fe1de0d2a581310aa9af8","src/shared/formats.rs":"20908b1048c5e71a185de6b6ded79cdff2c26ddb38ba7b134b7a27f37e8324f3","src/shared/immediates.rs":"804c4c9ffa2fe55d90279ee158aaa6bd6c7f0c604d63d7457a98e82269cec9a7","src/shared/instructions.rs":"4222d17a9a8be083cc729715527290ca22c8ebe1f9679812a5237025a0479dcd","src/shared/legalize.rs":"e3ed83c004afd088bedad0db6664983bfc15149fb99d7d28dea535b2ff48d761","src/shared/mod.rs":"6e30631fe2ba19d819330ea14d29cce4910b435f030e706be2fc94af23b88d71","src/shared/settings.rs":"42c2c5b6f5fdef090c35760c5920d5013afe4ddc472ee9cc37eb6d8ddaae2906","src/shared/types.rs":"158d73840185e6aa8385463bbf6568efdda0c8de8284cf6b4e565f425ec5d921","src/srcgen.rs":"79fee2f603b33f76f7c9c8b9452c745a363d732c40c0814d84001ff3ef805677","src/unique_table.rs":"90b7203b29241a1ede70f0a3e50d96799e0b41d8f7455170d6ffb127f87f3cc3"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"253c80832ab598570d604ae8a8108ea9835b8eef8d9b9645408ed025ce3b574a","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/cdsl/ast.rs":"170f0526c73e4ebdd22cf25290607b6610e9e3fe0b1d79ee38962085f878d2e4","src/cdsl/cpu_modes.rs":"57c40621115a58faa7af1c729ecaf8cda01c2b143008bde6d8c70885e7c3fd75","src/cdsl/formats.rs":"8eaee84c9c574e7a2ab73b4bf63b97c1cea3ffce0a477f1701e75a7a523ada57","src/cdsl/instructions.rs":"dd734b1ff0750ec09a06e5746338f479ae97eb122dc64dba37b656ab5ae79ebd","src/cdsl/isa.rs":"569bf078c68c800fbd36fde1b52e0371747f6249252655e2dc4715d4e975be40","src/cdsl/mod.rs":"86149f101e1b00a9623028dcd779ad66b6a67f0f67b423c5ac88cd96dabdd227","src/cdsl/operands.rs":"1cda258798d861c4f467783b5c70c1202a57f554861017eead6477af2ee34063","src/cdsl/regs.rs":"049d299c63a757aad7adb7945b3919bd62c9204348a4f8b9727ca84fecbf3115","src/cdsl/settings.rs":"b6b1653b486fb4b86aaab59328a959cf784cb4b61b3216fe7acebe0490849642","src/cdsl/type_inference.rs":"2771631701c150e077c5dcf705c8ae8705944d86ab945ae9e7adc82f3ca5447a","src/cdsl/types.rs":"4cc1f20eb8383fdee6a9e7ca0f7758e563a4fb715056b5edbd4db72f8dfd471b","src/cdsl/typevar.rs":"7249fcd7c3cd3645e8489c73595bd5327bedc499bd7bc87f2a68e241fba329c3","src/cdsl/xform.rs":"005bd2fca7f8b737c605a75a0f44f2d70f0138e67f3013343ced81f639dce8bb","src/constant_hash.rs":"b8acd3f8712a4999819d9d9beced2938d9940a5748ba016c182f1132d97eefab","src/error.rs":"5110a4e3c1e97396ba02d9f5abbb8af4b586f0cc4d33a5c2473f1718cc4bef05","src/gen_inst.rs":"94e71181683f022fdcc55abf487a20be5d4dd51fe3092345b6bc4e2bde04441b","src/gen_legalizer.rs":"368ea72fe2d253f7d4d7548ae449fde875781e43ce0ecb9a604765595e387cc2","src/gen_registers.rs":"a544a2b91fafe08639e39e50bea0892fda89fe2f6eaf111b2d5f3e98e4d07b86","src/gen_settings.rs":"4469bf496f9539835fce3cd9743ac0fbc270b3029b0e6c949f406e790685199c","src/gen_types.rs":"3935da6c6a53f9332e06f74bc3a46270656b4d4231ad28ed2648d7b1d2774e90","src/isa/arm32/mod.rs":"54e88d89644c5cee61cdc8315f1d77b01c232dc322c52f6e244cef9e7688a3ad","src/isa/arm64/mod.rs":"c5169b92c1bcb562649a48b7880033f542c9affa73274d23b3817e4ac83942fe","src/isa/mod.rs":"fce60d19dd3c099ebee3ac5ae64a2bee363f13da9ff5a4960d3c1a0bee71d29a","src/isa/riscv/mod.rs":"2da05e3974ef0b72431c9fdda14314890f72500b94def1d74cdf5e74bd950bc0","src/isa/x86/instructions.rs":"ad88f311fd51f341f7dfe395f98d8805ea55e1c86d1a89272ed999f5ae8dc3f0","src/isa/x86/legalize.rs":"251af731b2514fead08e27e812ca44dc674a41bd4a9637d9d919259497961961","src/isa/x86/mod.rs":"14715e552eedfeae1693a416bb82bda2156b31cd4b306e07530a3c1acdc17125","src/isa/x86/registers.rs":"c0bc60336a8c8b7b4db92dc623e9419a60af14dd6252f0b19e227e46f7166178","src/isa/x86/settings.rs":"1a74b3d1ef5e99e0b7c75528b9fd5afbb3394979615b005b43b72108757a9886","src/lib.rs":"8c9364c6fce73c158abfb7c88ecff01dc608a05c250e89df9bec3082773cde6d","src/shared/entities.rs":"80b8ff57a09c7b2f9dab755abbcc2738317de474776fe1de0d2a581310aa9af8","src/shared/formats.rs":"20908b1048c5e71a185de6b6ded79cdff2c26ddb38ba7b134b7a27f37e8324f3","src/shared/immediates.rs":"804c4c9ffa2fe55d90279ee158aaa6bd6c7f0c604d63d7457a98e82269cec9a7","src/shared/instructions.rs":"85f74df59fb0564613055df2173699e61d9e711fb481015635de47c5286690fd","src/shared/legalize.rs":"e3ed83c004afd088bedad0db6664983bfc15149fb99d7d28dea535b2ff48d761","src/shared/mod.rs":"6e30631fe2ba19d819330ea14d29cce4910b435f030e706be2fc94af23b88d71","src/shared/settings.rs":"42c2c5b6f5fdef090c35760c5920d5013afe4ddc472ee9cc37eb6d8ddaae2906","src/shared/types.rs":"158d73840185e6aa8385463bbf6568efdda0c8de8284cf6b4e565f425ec5d921","src/srcgen.rs":"79fee2f603b33f76f7c9c8b9452c745a363d732c40c0814d84001ff3ef805677","src/unique_table.rs":"90b7203b29241a1ede70f0a3e50d96799e0b41d8f7455170d6ffb127f87f3cc3"},"package":null}
\ No newline at end of file
--- a/third_party/rust/cranelift-codegen-meta/src/gen_legalizer.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/gen_legalizer.rs
@@ -405,17 +405,17 @@ fn gen_transform_group<'a>(
     fmt.line("#[allow(unused_variables,unused_assignments,non_snake_case)]");
 
     // Function arguments.
     fmtln!(fmt, "pub fn {}(", group.name);
     fmt.indent(|fmt| {
         fmt.line("inst: crate::ir::Inst,");
         fmt.line("func: &mut crate::ir::Function,");
         fmt.line("cfg: &mut crate::flowgraph::ControlFlowGraph,");
-        fmt.line("isa: &crate::isa::TargetIsa,");
+        fmt.line("isa: &dyn crate::isa::TargetIsa,");
     });
     fmtln!(fmt, ") -> bool {");
 
     // Function body.
     fmt.indent(|fmt| {
         fmt.line("use crate::ir::InstBuilder;");
         fmt.line("use crate::cursor::{Cursor, FuncCursor};");
         fmt.line("let mut pos = FuncCursor::new(func).at_inst(inst);");
--- a/third_party/rust/cranelift-codegen-meta/src/shared/instructions.rs
+++ b/third_party/rust/cranelift-codegen-meta/src/shared/instructions.rs
@@ -304,17 +304,18 @@ pub fn define(
     ``addr`` with a specific ``Size``. The retrieved entry may need to be
     decoded after loading, depending upon the jump table type used.
 
     Currently, the only type supported is entries which are relative to the
     base of the jump table.
     "#,
         )
         .operands_in(vec![x, addr, Size, JT])
-        .operands_out(vec![entry]),
+        .operands_out(vec![entry])
+        .can_load(true),
     );
 
     ig.push(
         Inst::new(
             "jump_table_base",
             r#"
     Get the absolute base address of a jump table.
 
--- a/third_party/rust/cranelift-codegen/.cargo-checksum.json
+++ b/third_party/rust/cranelift-codegen/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"9e1e9d197a2fcdb9bfd3c32a7608ab772ed4301aa0b9f2e60b73c98f542ac760","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"e5127227a7db4a8aa92fa6613ed71801025790e696bb41b0323fb7f3c6f7495a","build.rs":"7c0919d12ff966e0c400e7cfa0a555b2e50ede20c0dfb4f4401e35a828134ea9","meta-python/base/__init__.py":"4fac8bb055541dc964383bb04223bae6dfbfe348abf5e23f83655966cbb4aa8f","meta-python/base/entities.py":"f956b8ba863cd26f6867e13c1b2db3c202e9b07c48c1e43a9c2b41ad0deb8922","meta-python/base/formats.py":"6f8cf7cbdfb613acfd4ba3a8e4a9a173cbaa8afd254f03218c5f01daa1078d6c","meta-python/base/immediates.py":"f42682d86bda7b569ec2fc2debd9036355999e61caaa9fbf8307e0be8a164814","meta-python/base/instructions.py":"560a9e86f658d7627c596e992919f696cf6275dbb5de47aa9bf09ec3dec789f8","meta-python/base/legalize.py":"beddc21c03ffba30a509a6df28ad87e3162cf8c60debd036082e32f3c732b7d2","meta-python/base/predicates.py":"53a5a9a37021a9762f0faec9f9e3c5b713411d47dd9192423cfe0f7a61916809","meta-python/base/semantics.py":"b90cbca9a143676ac37496c83634a66a83360248e4505ff7bda12b0d454efd92","meta-python/base/settings.py":"97fca9ddaab347f50f1594c93283f8f474e53a7232eae65949f56a6a702c2bba","meta-python/base/types.py":"9616d6fe4cab050827ab02eeb9843eacebbb8f7555521f504b5ee2ddf7214fdb","meta-python/build.py":"254a7fb51f6025c54f5b08135b83ffadfc2e6c02cb8c3078fdd06c0eff4b91da","meta-python/cdsl/__init__.py":"b534ec129a0e517f0d13313c2b4bb3a345d3e5b62693a31d8d42c80a219e39fa","meta-python/cdsl/ast.py":"8509f15eaaaf2fed2bec93eba19d313d37c2ddd70d1399a491a394206cbfabe4","meta-python/cdsl/formats.py":"fedfeaec754b40d6a9cc92b827976782c615d8eab1c7f47f6b47510cbef585f4","meta-python/cdsl/instructions.py":"50fe9329a56e6294a27306aad7be22c88a5b5ef42c3b030ec59218167157f62f","meta-python/cdsl/isa.py":"dc530a4dd5642e3379398dfc8a90ad6ae1692302de63851370bdfa8abf4cdce0","meta-python/cdsl/operands.py":"e24914eae4059b88781bf5a5d7a14ecf98b10a701ed6cf6e88d15981b2ccbfdf","meta-python/cdsl/predicates.py":"fe2dc6e78ff6d4bcb6b1d5448ded343ede0f03b96a965a11aef0f5bbe7bb8f56","meta-python/cdsl/registers.py":"939dafd1b8976a6cd456c9a5e4b374af81fafb9da979ea3a1f6d14e4645914a6","meta-python/cdsl/settings.py":"400d853a815f64c0294d0c0e03d3c514942760faa8b06152b1078a92ddb9f62c","meta-python/cdsl/test_ast.py":"947e934e2862445a158bf266dff58a8c88aae31fb34a7f823309ee58a15c5393","meta-python/cdsl/test_package.py":"ffa53d20e023ecb89137294bb13614f4de9b09e1bf05d9772131570bf78f7987","meta-python/cdsl/test_ti.py":"04656e2da99ec37875f91172bb2fa423da1ee27bf523a4d41af311ea22492d1b","meta-python/cdsl/test_typevar.py":"768bf3c35481950264ad6fd7059a532ac62b121ac439983bb4fe1ae76a1d1248","meta-python/cdsl/test_xform.py":"ddb6633c7941bbf68570701cb887a81d6b4b27f4bc45eabccf2ce287ad9b77e9","meta-python/cdsl/ti.py":"566e91f0bb3ebacd5abf9f5a663caee69706c2e829dee1ed735d229198689f76","meta-python/cdsl/types.py":"adee4bbc1a9478288fa4b53ee1edeb5ee3296dba2c70bfbe01e923895064999e","meta-python/cdsl/typevar.py":"b5669934eddaf5b9cc0c27b966e2566b5f669f1c5a345f005960930fb499097e","meta-python/cdsl/xform.py":"bf200b711570b905f0fb30611ba64f131f98593060eedbe5575054cca4928593","meta-python/check.sh":"707cda14534882e8d4593f93c056390560394c9bc8a687e99f10a56d7b09cb92","meta-python/constant_hash.py":"c752e6dadf3a9a5bd00c978e85ab27a20c49138a1ccdc6fc9a1904797a4bfe48","meta-python/gen_binemit.py":"76472fb199a330b934ba9ad0a1bbacfb52f0eae7c9a66d83f0d7890970323a2d","meta-python/gen_build_deps.py":"53bbdd591c91f8e28da95e4da02c9299a01a32d8be6a0c7490b6b7c60a4fbebe","meta-python/gen_encoding.py":"471c5f4ecf24a2a173864c62a48920e5fbe1aacd2229b3eb4483637570bb26b2","meta-python/isa/__init__.py":"e499c1206cd095a926fa0ca7eb9d0a50a802ed71c8eb7598e5d3a0f939c8ada5","meta-python/isa/arm32/__init__.py":"eecba73231aa398ded7304690bdba3450dc163afd4360f1b0ad02a28e2380363","meta-python/isa/arm32/defs.py":"01c41dbd7406c624e26229df6befa0992194bddcc7d11e8f6174abfe2b33bf61","meta-python/isa/arm32/registers.py":"c03ca6435828ad5f262049e42f1f71bcf74903831f85daa92c3f322a6c1050ea","meta-python/isa/arm32/settings.py":"afd5a04a9d029f578d6f62dc7c539191886cc9f9dea15d65fc66bf37a63b8814","meta-python/isa/arm64/__init__.py":"f6877253cf786d7ee972881e7d9b3c78c11e6b024e4e227487340dd01d0c44e4","meta-python/isa/arm64/defs.py":"797c5bb6d11fc7a44afe67476136dbd11c40f5e13a1c8f52f9f96be4441677b2","meta-python/isa/arm64/registers.py":"9bdd06edaa382be96042e1ac36d63137e73292292b61dcf4becb7d1428130317","meta-python/isa/arm64/settings.py":"f7b1f8733e775ea8005372ee35f1c2a627b3a69d722e837295599e4cf1f5eb43","meta-python/isa/riscv/__init__.py":"c11607c9eef0bc2707daa3edd4174e934c7a0dcc8ce90cee2c9292a85b1ac596","meta-python/isa/riscv/defs.py":"e73740055c4fb123c45453fc149a807e9720466de848022d5375049bdcfc311c","meta-python/isa/riscv/encodings.py":"ecaad5ea98273ade1cb10606354e893342c495bb48771df50121f789566d7be6","meta-python/isa/riscv/recipes.py":"3852e5b7aa6995fa721ba91744a0470343ce1834651e7b9cc97b5d69af7dfdc5","meta-python/isa/riscv/registers.py":"ef9aca3a6ec2b08ee8f5952186d232861b64a919b671b41911a365e7672b01bd","meta-python/isa/riscv/settings.py":"dfe29722d67be0620a70e08cfb802829a26f5fd339a9342a8ac2dd419daf8a85","meta-python/isa/x86/__init__.py":"ad579de68ea7bf5dc2bce0e3a6f09e7978b1697f1afec8a5ce5dc591136e590d","meta-python/isa/x86/defs.py":"b5eb7889b6f5e5b221ed3923d0137bbb1566c55b5961448cc39e4ea2f13cf4b7","meta-python/isa/x86/encodings.py":"6dff12042c50bca59b891e6b1e70a34e12ecc83194efbf02e42ea7071da8f4f7","meta-python/isa/x86/instructions.py":"530cde78e6b9f6e4ea2192985f4c5c77a987cdc19001d50fb47fa8e36a62f52e","meta-python/isa/x86/legalize.py":"1375ded072c29459e7c0e40ecb02f28d5395d9d8c603eb70e338b2bf2991c9cd","meta-python/isa/x86/recipes.py":"5dc66c8e0d0ac3aff05dfe42822b4711c677d52177f9753b50daa73eeee4b690","meta-python/isa/x86/registers.py":"ff934491d07ec6b51fbfd454b865a7c7c191ffbd31b1804615735266b120f4b2","meta-python/isa/x86/settings.py":"7ef2e43521b9b11e90a93c1c60946e65d420ecf6e15ba17f933c7a24a5124e5b","meta-python/mypy.ini":"5ec2f7cc0bbc4fd0435643d6b72e715bd9568a3a0fe14c043f9e559c405b66fb","meta-python/semantics/__init__.py":"c9dd72fde0ab020d3328dde532d92b39e438e4147930e41df7613c27727e11eb","meta-python/semantics/elaborate.py":"3a3fbba83a6818c2d1ce236fd0413111380875a0307f7a5f4b5dd66d8ef714b1","meta-python/semantics/macros.py":"b218c52e1bd4f019dc14a27d315b4f3405a10e5bdc6f2523fe709c8faf91b418","meta-python/semantics/primitives.py":"4e5eb0c90fcc295686732c8c66ad7a793997645c9a676c97babf06823fd2b60d","meta-python/semantics/smtlib.py":"48ef80320f21682860bbf5f79f18739f1d10f0b1fe581ebb05541e90dc2f2f4f","meta-python/semantics/test_elaborate.py":"3a4c850a7385007422c7549661b211903cd1dd1606dad7a86262ae27e697bca6","meta-python/srcgen.py":"999557d683e808a2ca90688c489ec4aff65798f44ac321ecf7de34d307261913","meta-python/stubs/z3/__init__.pyi":"6aaeb80f783b29c4364dee21da45f6df041c0a4807189a15777ee5447f6515dc","meta-python/stubs/z3/z3core.pyi":"c01a41d468e07cc4f8b405c292ed7f8c82bc1077f8b82dfde1e474577ade3335","meta-python/stubs/z3/z3types.pyi":"30009c951af99b9028d47cd4cabae95ff9742b77b690bd8dd63f6b7dba580759","meta-python/test_constant_hash.py":"157cf4f8964e0f04c041ffd349e889ce565b144453436690578c5d03c3a60216","meta-python/test_srcgen.py":"d6d7775e19a5b2621360c00eb6d92dfcb4568e49220993e0ceaac9628dbfd661","meta-python/unique_table.py":"5bd500667430c15f6ae586603d8612fb3bda07b072e40d86286e08392bdc3127","src/abi.rs":"76ee030cf0780fe63ccbf855b1161f215e3e2991cb9abe71ca9aff25e5f1dbc2","src/binemit/memorysink.rs":"25c02b556782598e83a7a59f4a2c47a8cfede21388e6640a87f1af1092a570ea","src/binemit/mod.rs":"ed63c382e6f58a9f7417d8913c15387f88d511a4ef02cba191c341496db50863","src/binemit/relaxation.rs":"6d8a993c224bedf283ca61af62caa4d4bf58e889b0997c59d5ad1fec78ce562d","src/binemit/shrink.rs":"45434d5fb17804f5199f5fa80fd96aedaeac1ca3824766236eb16b6b529155b4","src/bitset.rs":"d57a79058a31b094b4bbe9d34876a5543286df1e08b5ceadfd05a9efc5a3b1ce","src/cfg_printer.rs":"69b4f16132c886ef0b883c8b78b59d041ceec3c8b96dd8015e990ac06733ce91","src/constant_hash.rs":"330e8289789ee351d0abeaf4b5e859b8db8772306e0820d34864fc9905d53b38","src/context.rs":"573beb0e83268bdd1dddf0b477d6dbafe6915d37a6d6b9a61dd582f3c22d2406","src/cursor.rs":"dcce946ad85d8fc2f1c9cc885ae8a0440c37d9e512606fb8a518aaffcc6d6f8f","src/dbg.rs":"1898d94cff0975815eb348651702e95c8f2f63886501d3b7043ee75668480472","src/dce.rs":"d8ab7c0cac0416f9d75afdacc60ba02e532361ec927c3f8bd171b1a53ec8b31a","src/divconst_magic_numbers.rs":"09691389c9055bef7a0cfd5d77fbfeba4be468d05d981d4de088516a94b8b28e","src/dominator_tree.rs":"7ee4114026011b11d49e48c5a9202970bafe3b22c2074f7c1390b98ebb2edb7a","src/flowgraph.rs":"bf520026c32c5454554d0b078b64a78bd44f3c0f4f198eddf71bcfd78cc963a3","src/fx.rs":"8a5d07487906d8316a179e826fcd817a92a4860686256a6fd9d78ba47c63f330","src/ir/builder.rs":"1a12c57f4168fa3c2fcf6be2f19d0d377eee40f24ae4390e6ba9d954f85a8a3e","src/ir/condcodes.rs":"5247c8d849e1372d2a22379c33a4a88226ec6187be18ca6f2c4e0f315d812aa8","src/ir/dfg.rs":"f5cb672656c7e56185544c3ff7f60f8a4b7b9f172d9a9920144616bc165d5928","src/ir/entities.rs":"8bae1166b59afd38953e7d9154ae141c979ab77153b9512f45db7b82a256fdf4","src/ir/extfunc.rs":"9806734eeb480724481128d8c1de78a3b1f80f1214c20f24131196a0df137872","src/ir/extname.rs":"ed2c0b52cdaecc7f0ba9a894ef9fffe139e09b520e43dcd6f0c887a3d41a31ac","src/ir/function.rs":"91bda86993e6f664ba3fef8da286d0efe34b17d7e77cec692e09cf014c81b6e5","src/ir/globalvalue.rs":"1f6125788a9a5c118716f87fd72e85009d2e0a7f4c13b2a7904be8c7412ee4eb","src/ir/heap.rs":"a59d3e5901412b53c0b53a8cdf10765ff5921de9c410ae9acea226c89827df3c","src/ir/immediates.rs":"029a8aa905e6fd0f3334e17a28e73ac36684df2ca0829dcae0158ea8cf64ca8c","src/ir/instructions.rs":"2180de1d127ab5878c5743d8e096d551edb973e0ff1d373c4239c32e7981364c","src/ir/jumptable.rs":"7764abc9aa027a5a89d22059b360372bd9a19686887c5a7830f7637d6f188e1e","src/ir/layout.rs":"bb45eefde16ac9423f637dfcc2796ae7b955a97f38a55f23a19cc45da5decce1","src/ir/libcall.rs":"55fd77f6e32370812a271f4fd5d9817c03904733be79d49e17e2683fe516e30e","src/ir/memflags.rs":"dbcf3798ab66dc764b73fb7f139a621c54cc6bcc683f1f70a33ed7e8c3486bfd","src/ir/mod.rs":"37685305acb21dc24896e5d7977784988fe723c09bdf8ab8cc7830ccabd76a11","src/ir/progpoint.rs":"49433f22bd6ff3a96ad0733ff612f3617b312e4492b6b663187141966f6aa701","src/ir/sourceloc.rs":"37ef5fd8cef1de99620797d7d5aba3630e737171853c8471495c685dafac19b6","src/ir/stackslot.rs":"2f54359339837bb1d0d817d3af21bb4b1b050c31703885dfaced29f6e41153c2","src/ir/table.rs":"dcc3b663a989b2b084402b08dc9a0e928dbd052e194a46a1886cc6f0cf1a5f2c","src/ir/trapcode.rs":"59e223193617b8c1043ddd3a907c6131f2987e8fe0965ebfd9f7c056c064b7c5","src/ir/types.rs":"1f644beba2c797f7bd89378d930c3eca1491ec5f82c4715945ac63a0a5754473","src/ir/valueloc.rs":"4c676c2d21d75611ef922a230ee82846afb565ce0f55bc71e33c70e1a1d92a07","src/isa/arm32/abi.rs":"74775c5f1eb95764e46815fa8b31891416a616fdd212972eb77aead43b3345a9","src/isa/arm32/binemit.rs":"52b2f4b3c6d8683ed6963c1f53907ac57b6aab7cc149464c9a12d6875aa3b5c6","src/isa/arm32/enc_tables.rs":"b5b7f2fdcaf1d1878a357c54ab757e94f0d06e5bd391ac5d876e96f5b30d6b7a","src/isa/arm32/mod.rs":"24492cfe9120a3ebb199b1d0a0b58425c58970bae32349b3cf2dd390ce51e62f","src/isa/arm32/registers.rs":"254b568a02480f46bb4967a24a438390231014258f0c159f0a41dbafe8e66d56","src/isa/arm32/settings.rs":"188f3cc445168b472b488e73b011e83edd31ac17e3841dacda07a55ccf923468","src/isa/arm64/abi.rs":"52353ed2e2133dacddaad70a876ecebb9c179c19b911ffa823b5b89d3ee7a17c","src/isa/arm64/binemit.rs":"4465cceb68d03ae4d0fdf188c9b86870fb57b3617d67f0bb7d476e5afb581e81","src/isa/arm64/enc_tables.rs":"8c829c544daeed9adc8458891614a0be6f149e775bd22651465f2c165d4a9e56","src/isa/arm64/mod.rs":"f9ca60e7407b69595cb4ef42103ed079e7bcb40546f11d944ddcfc6a04a7fd11","src/isa/arm64/registers.rs":"308cfcfd9ff2191d7656e7350bb36e41803664eb86ae490fb4b4d3549b25b6a2","src/isa/arm64/settings.rs":"0dff47e995e5d9740deb0116b59e91fbcb725a7fa1bdbd802bf83c13381b17f7","src/isa/call_conv.rs":"833ac811ff78ab8d3a5052165e76c51c6da7686020d95462c18074750fb790ed","src/isa/constraints.rs":"bddb5c68e56b122a53d8be215e41d22ccf8c4563630b1486e6eb31c0d3337565","src/isa/enc_tables.rs":"3497f3d701f21d6f952424abf31515fde9e67aea1cde26236c9ee8b033c61ae6","src/isa/encoding.rs":"7ea5b4400530172f96e263561682886ea6c67e706398d44a83933ef7f0ac98a5","src/isa/mod.rs":"40ab1c6d86f903a88bc7ef83b7cdcbee0eedbfdf7112fb7a6749c0c8cc9ee42c","src/isa/registers.rs":"4a91d4888df5eeed1802f34c43a42b82aaf1f9928a58329b0cbc9c3c57c75485","src/isa/riscv/abi.rs":"36557b91ad16a1344c80fbb16a62b46eac88500d76cb9ebcd4eae224dd67b2de","src/isa/riscv/binemit.rs":"0bd76b005b53b71bdb59057a20671fbcd8ab1c37d767bfd4ab0a92d05e192d9a","src/isa/riscv/enc_tables.rs":"ab73c80fef6b1256fbd3c0e1bdd8e43a20f7d132a32236f6bfc028e9003adfe0","src/isa/riscv/mod.rs":"377dfc7dc9940d284b21bf3d2433916dd9c3df79cce172a2a75ef572dcafe98f","src/isa/riscv/registers.rs":"666c2abe1a93db5f1573d1603db6c13c37f3fc877c0c93b64d1b971921bfa950","src/isa/riscv/settings.rs":"d018d23418ff3fb98571bcdeeddde3277bf213b4b8ac1e55b6573e128b3931ce","src/isa/stack.rs":"d023c57feb944c94c4dc8b7138dcbc9d37ff18ca23c23d83e9bab3c88299ffa0","src/isa/x86/abi.rs":"98092944de6b8a8171f1c7d24a63d23ee6dc77a5b4048be113582c5362ac0158","src/isa/x86/binemit.rs":"9b7a3a5aacbf382145ac39c2bfd767bdfa92a8d0447a84dcc19672f1db34d047","src/isa/x86/enc_tables.rs":"7f710f042a2be316f6540515b8838df84f26af3a7c5b290a9cafdf36ef92f0a0","src/isa/x86/mod.rs":"15488d60a950aa4cb75afb63d42d4524e1fcea3b77c7c160e2cb862ec2236a92","src/isa/x86/registers.rs":"bed70bbe1f56f3ef03ea7cd1bea68eb911913cb4c8b93167e044dfc639f7f461","src/isa/x86/settings.rs":"cd8f8c5255663f6e247f0634088b16b53d785ee8c62cb5c0926b3d27597c12ff","src/iterators.rs":"f85f52d3fa707a0eb974c92215b3e976923ce8f9481219f7812e0f2869c2bd37","src/legalizer/boundary.rs":"435707e84b5e406843238d27f5cc4886f4ae37e2c4d25a749e189a378b3af632","src/legalizer/call.rs":"6a82a9daeba5f452a7db0c47dcc43829b119b0652961bc2aa336b809c3f34ef1","src/legalizer/globalvalue.rs":"896f59dc5b8c4a5aee45e3f59211066f214d3ab9142865d80ad6610633363ac9","src/legalizer/heap.rs":"6e13c96f364de71c507aec330d991862a8f925947bb1ffbf1c1493c546c5aacd","src/legalizer/libcall.rs":"6e58da5e1c2419192a3393debc6e9714df9728e59e1740ff569e8a9c0daa40d5","src/legalizer/mod.rs":"7df6ed89a80c9dab7f6e3ddbedcb1c4bcc86c3c6e5bdc3e71e51d5322cb1ce52","src/legalizer/split.rs":"13fe4d2cecea166ecdc1ebb11f5254374ee170518f1a61de7ac0a921bc8fb25d","src/legalizer/table.rs":"d6e09f8340ca597fdb13f86021e5c53bd3161dc4258effc56c1f6d9be7b819ec","src/lib.rs":"1e3a026f3ab6a1d133722227f1f9b8d2cd214e576e31c6c68d252326984dafc5","src/licm.rs":"a4b482c995daf0ecf928a525747316760986a42234331554ae68fe9ef8c7145e","src/loop_analysis.rs":"58fc3cc0e700f05e3131ff1b16ff975d4f32a68c790f095d8445bd300356d3c0","src/nan_canonicalization.rs":"9619bb5554791bd1be75ecd98564d6c9f5b65132bc07c5c4d8c210cd79b66f82","src/partition_slice.rs":"bc13504e7658aab565918d965a0b67e941eb572e583870571bc6dbb2b9aad272","src/postopt.rs":"f3af3f27496de14e4e65b7efb0748ca11edff8fedd7b57d680b310de5156aa62","src/predicates.rs":"44bbc09ae0c7d5b54c05eb6061b062e92d1893edc7dda43ae2bccfedc6bb25e3","src/print_errors.rs":"aaa01084e1655f086d958c7e3b54b0ff6345f96aac06e0f65d7330a15ea2fe27","src/ref_slice.rs":"421a61323c11858a596d50220487f399e1bcedeff0e8d1b716dd4b3531eb01a5","src/regalloc/affinity.rs":"66ee6b9789ec207393c318b14177e1439a54f197b13ebefdb0c4ab77acf38c00","src/regalloc/coalescing.rs":"881c8be32eb4d4b34cf208d0dba3e18b8469bc19f19aa7120514c801562392d3","src/regalloc/coloring.rs":"72bef8b5e3425c805d62cf2329acd29510f1be0886ee73308b69938cf2de203f","src/regalloc/context.rs":"b358a31a6e914502d88a4f1fdad20fc66d1b07a7bdb0213001a94c9335875937","src/regalloc/diversion.rs":"d46d733f6d00a8f536d5c7c8b8fc6f348c3d0605dd0ee77e1d8359367ba53347","src/regalloc/live_value_tracker.rs":"28823003dc72e8a4702776a8ab5ffd878712700a272b64376b0de2022e0ee31a","src/regalloc/liveness.rs":"d2d227a0e6074b2d6ca7d564cf60bc1b565697f4502d1943f5ea3993275fbbf9","src/regalloc/liverange.rs":"7a28454e5f70d570db439b966a01ead759b65eb65c5845f9c58bf2f230a5f2ab","src/regalloc/mod.rs":"6254df639f9289fd578e01b7dca99bc9c9e3c6680c6d031405e8df8d0cff31ad","src/regalloc/pressure.rs":"c9d1098266c5b8b89eff84a55be3bc4838b70416c2446edf57f5257a6232d059","src/regalloc/register_set.rs":"bc58f93f22f0adbe43260fe20c6089be1fca64f5bcc4acff85dc0a5ec5b61937","src/regalloc/reload.rs":"6f82976e779967f3fd492445b6c1f645f69a3a14ab1688e7cfc1f49b8b025f05","src/regalloc/solver.rs":"e2a6d2782d213676dec9781aeb5a37806e092d6daac3249a6cd4d4c92a9d117f","src/regalloc/spilling.rs":"f21ae054e6546b0cd774a94bb301517ba341b985223b6db36e6c9ba995eecfd8","src/regalloc/virtregs.rs":"e5c8da6860ba9495f9396621530347e1dd6fc5b2fae2eb23c171ea77429356f1","src/result.rs":"c10354d615f93caa446c3c8c49d6ba3af762816af470f9c4accf04315cce9753","src/scoped_hash_map.rs":"5afafb3a4039094c3a2aad1582354220d21f399aa50046e7f4a1259e1976597e","src/settings.rs":"3d60acb7eff7f1681f3b23a1a10f067461c35008b94d3a022eaf9e27d9706f09","src/simple_gvn.rs":"c8feb380d4831badc59aa1e65efeafa6702711585817fe5f6b31de6b265fac24","src/simple_preopt.rs":"d2800d1345dc02e2ff5ef5c8b3d1bf9fcaee8f62e78df9f1681338ffc780d520","src/stack_layout.rs":"c5de271e296fc424f1a30017620bc88500369c8e553fef6e95beccb9c6640e7c","src/timing.rs":"a6808943eec68f5d3ff32132d40c07c142e6aa8073473561573a013978883e4f","src/topo_order.rs":"b01ed68a7300691f41ac434e58a5267b10a8b4a7056d65035e24aa8a6722122a","src/unreachable_code.rs":"40cc71a02887ee4065c76ce96dda0a363a8cc134ec784fe5ed1f276db76596ce","src/value_label.rs":"20741ee3fd6fbd48e018d57342fee2414707f35ae77c779ea4a350c65a39b4a4","src/verifier/cssa.rs":"e3e1d77b763c0ba82d3b59ab5b4667fd3152d5a08be50b58b0c82f86376bb062","src/verifier/flags.rs":"f4ba0e0c13fd643bdbec6466219a25a33993a6e170debb48497a859d9f79d914","src/verifier/liveness.rs":"2631037bafa88659bc47d2174e261f5acb1702ca522722a597fa28e474994d79","src/verifier/locations.rs":"9623bbc2d2f86f36893eebe60330fd51b99c9f9c8e5162c61cc89ab221e75b5a","src/verifier/mod.rs":"10c22e51a0c2f73db4a44d8c458361a8af0024e18e47458cb064dc80f51fe07f","src/write.rs":"c672f1fe00cce47ebbb7e33d60df88f80e36b02a2e3c37b0a0c4027e8dec301f"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"9e1e9d197a2fcdb9bfd3c32a7608ab772ed4301aa0b9f2e60b73c98f542ac760","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"e5127227a7db4a8aa92fa6613ed71801025790e696bb41b0323fb7f3c6f7495a","build.rs":"7c0919d12ff966e0c400e7cfa0a555b2e50ede20c0dfb4f4401e35a828134ea9","meta-python/base/__init__.py":"4fac8bb055541dc964383bb04223bae6dfbfe348abf5e23f83655966cbb4aa8f","meta-python/base/entities.py":"f956b8ba863cd26f6867e13c1b2db3c202e9b07c48c1e43a9c2b41ad0deb8922","meta-python/base/formats.py":"6f8cf7cbdfb613acfd4ba3a8e4a9a173cbaa8afd254f03218c5f01daa1078d6c","meta-python/base/immediates.py":"f42682d86bda7b569ec2fc2debd9036355999e61caaa9fbf8307e0be8a164814","meta-python/base/instructions.py":"797dc0c47dd0ea1698201695ff2b5d3c7e8a7aca94396c2685189d9cc53b1419","meta-python/base/legalize.py":"beddc21c03ffba30a509a6df28ad87e3162cf8c60debd036082e32f3c732b7d2","meta-python/base/predicates.py":"53a5a9a37021a9762f0faec9f9e3c5b713411d47dd9192423cfe0f7a61916809","meta-python/base/semantics.py":"b90cbca9a143676ac37496c83634a66a83360248e4505ff7bda12b0d454efd92","meta-python/base/settings.py":"97fca9ddaab347f50f1594c93283f8f474e53a7232eae65949f56a6a702c2bba","meta-python/base/types.py":"9616d6fe4cab050827ab02eeb9843eacebbb8f7555521f504b5ee2ddf7214fdb","meta-python/build.py":"254a7fb51f6025c54f5b08135b83ffadfc2e6c02cb8c3078fdd06c0eff4b91da","meta-python/cdsl/__init__.py":"b534ec129a0e517f0d13313c2b4bb3a345d3e5b62693a31d8d42c80a219e39fa","meta-python/cdsl/ast.py":"8509f15eaaaf2fed2bec93eba19d313d37c2ddd70d1399a491a394206cbfabe4","meta-python/cdsl/formats.py":"fedfeaec754b40d6a9cc92b827976782c615d8eab1c7f47f6b47510cbef585f4","meta-python/cdsl/instructions.py":"50fe9329a56e6294a27306aad7be22c88a5b5ef42c3b030ec59218167157f62f","meta-python/cdsl/isa.py":"dc530a4dd5642e3379398dfc8a90ad6ae1692302de63851370bdfa8abf4cdce0","meta-python/cdsl/operands.py":"e24914eae4059b88781bf5a5d7a14ecf98b10a701ed6cf6e88d15981b2ccbfdf","meta-python/cdsl/predicates.py":"fe2dc6e78ff6d4bcb6b1d5448ded343ede0f03b96a965a11aef0f5bbe7bb8f56","meta-python/cdsl/registers.py":"939dafd1b8976a6cd456c9a5e4b374af81fafb9da979ea3a1f6d14e4645914a6","meta-python/cdsl/settings.py":"400d853a815f64c0294d0c0e03d3c514942760faa8b06152b1078a92ddb9f62c","meta-python/cdsl/test_ast.py":"947e934e2862445a158bf266dff58a8c88aae31fb34a7f823309ee58a15c5393","meta-python/cdsl/test_package.py":"ffa53d20e023ecb89137294bb13614f4de9b09e1bf05d9772131570bf78f7987","meta-python/cdsl/test_ti.py":"04656e2da99ec37875f91172bb2fa423da1ee27bf523a4d41af311ea22492d1b","meta-python/cdsl/test_typevar.py":"768bf3c35481950264ad6fd7059a532ac62b121ac439983bb4fe1ae76a1d1248","meta-python/cdsl/test_xform.py":"ddb6633c7941bbf68570701cb887a81d6b4b27f4bc45eabccf2ce287ad9b77e9","meta-python/cdsl/ti.py":"566e91f0bb3ebacd5abf9f5a663caee69706c2e829dee1ed735d229198689f76","meta-python/cdsl/types.py":"adee4bbc1a9478288fa4b53ee1edeb5ee3296dba2c70bfbe01e923895064999e","meta-python/cdsl/typevar.py":"b5669934eddaf5b9cc0c27b966e2566b5f669f1c5a345f005960930fb499097e","meta-python/cdsl/xform.py":"bf200b711570b905f0fb30611ba64f131f98593060eedbe5575054cca4928593","meta-python/check.sh":"707cda14534882e8d4593f93c056390560394c9bc8a687e99f10a56d7b09cb92","meta-python/constant_hash.py":"c752e6dadf3a9a5bd00c978e85ab27a20c49138a1ccdc6fc9a1904797a4bfe48","meta-python/gen_binemit.py":"76472fb199a330b934ba9ad0a1bbacfb52f0eae7c9a66d83f0d7890970323a2d","meta-python/gen_build_deps.py":"53bbdd591c91f8e28da95e4da02c9299a01a32d8be6a0c7490b6b7c60a4fbebe","meta-python/gen_encoding.py":"471c5f4ecf24a2a173864c62a48920e5fbe1aacd2229b3eb4483637570bb26b2","meta-python/isa/__init__.py":"e499c1206cd095a926fa0ca7eb9d0a50a802ed71c8eb7598e5d3a0f939c8ada5","meta-python/isa/arm32/__init__.py":"eecba73231aa398ded7304690bdba3450dc163afd4360f1b0ad02a28e2380363","meta-python/isa/arm32/defs.py":"01c41dbd7406c624e26229df6befa0992194bddcc7d11e8f6174abfe2b33bf61","meta-python/isa/arm32/registers.py":"c03ca6435828ad5f262049e42f1f71bcf74903831f85daa92c3f322a6c1050ea","meta-python/isa/arm32/settings.py":"afd5a04a9d029f578d6f62dc7c539191886cc9f9dea15d65fc66bf37a63b8814","meta-python/isa/arm64/__init__.py":"f6877253cf786d7ee972881e7d9b3c78c11e6b024e4e227487340dd01d0c44e4","meta-python/isa/arm64/defs.py":"797c5bb6d11fc7a44afe67476136dbd11c40f5e13a1c8f52f9f96be4441677b2","meta-python/isa/arm64/registers.py":"9bdd06edaa382be96042e1ac36d63137e73292292b61dcf4becb7d1428130317","meta-python/isa/arm64/settings.py":"f7b1f8733e775ea8005372ee35f1c2a627b3a69d722e837295599e4cf1f5eb43","meta-python/isa/riscv/__init__.py":"c11607c9eef0bc2707daa3edd4174e934c7a0dcc8ce90cee2c9292a85b1ac596","meta-python/isa/riscv/defs.py":"e73740055c4fb123c45453fc149a807e9720466de848022d5375049bdcfc311c","meta-python/isa/riscv/encodings.py":"2f890f47d8ee13141c45b1126dd8cb1dfdcde96df03208ce19e96ea3ae53c5d2","meta-python/isa/riscv/recipes.py":"57eb830d0e01858c7f01cda71a26854eb8f69cb46aae6456873766e1e0a40389","meta-python/isa/riscv/registers.py":"ef9aca3a6ec2b08ee8f5952186d232861b64a919b671b41911a365e7672b01bd","meta-python/isa/riscv/settings.py":"dfe29722d67be0620a70e08cfb802829a26f5fd339a9342a8ac2dd419daf8a85","meta-python/isa/x86/__init__.py":"ad579de68ea7bf5dc2bce0e3a6f09e7978b1697f1afec8a5ce5dc591136e590d","meta-python/isa/x86/defs.py":"b5eb7889b6f5e5b221ed3923d0137bbb1566c55b5961448cc39e4ea2f13cf4b7","meta-python/isa/x86/encodings.py":"0130a8eb7e7415f538fd9ee5b15eea008b1cad609325fd7399750b402e5fc916","meta-python/isa/x86/instructions.py":"530cde78e6b9f6e4ea2192985f4c5c77a987cdc19001d50fb47fa8e36a62f52e","meta-python/isa/x86/legalize.py":"1375ded072c29459e7c0e40ecb02f28d5395d9d8c603eb70e338b2bf2991c9cd","meta-python/isa/x86/recipes.py":"5dc66c8e0d0ac3aff05dfe42822b4711c677d52177f9753b50daa73eeee4b690","meta-python/isa/x86/registers.py":"ff934491d07ec6b51fbfd454b865a7c7c191ffbd31b1804615735266b120f4b2","meta-python/isa/x86/settings.py":"7ef2e43521b9b11e90a93c1c60946e65d420ecf6e15ba17f933c7a24a5124e5b","meta-python/mypy.ini":"5ec2f7cc0bbc4fd0435643d6b72e715bd9568a3a0fe14c043f9e559c405b66fb","meta-python/semantics/__init__.py":"c9dd72fde0ab020d3328dde532d92b39e438e4147930e41df7613c27727e11eb","meta-python/semantics/elaborate.py":"3a3fbba83a6818c2d1ce236fd0413111380875a0307f7a5f4b5dd66d8ef714b1","meta-python/semantics/macros.py":"b218c52e1bd4f019dc14a27d315b4f3405a10e5bdc6f2523fe709c8faf91b418","meta-python/semantics/primitives.py":"4e5eb0c90fcc295686732c8c66ad7a793997645c9a676c97babf06823fd2b60d","meta-python/semantics/smtlib.py":"48ef80320f21682860bbf5f79f18739f1d10f0b1fe581ebb05541e90dc2f2f4f","meta-python/semantics/test_elaborate.py":"3a4c850a7385007422c7549661b211903cd1dd1606dad7a86262ae27e697bca6","meta-python/srcgen.py":"999557d683e808a2ca90688c489ec4aff65798f44ac321ecf7de34d307261913","meta-python/stubs/z3/__init__.pyi":"6aaeb80f783b29c4364dee21da45f6df041c0a4807189a15777ee5447f6515dc","meta-python/stubs/z3/z3core.pyi":"c01a41d468e07cc4f8b405c292ed7f8c82bc1077f8b82dfde1e474577ade3335","meta-python/stubs/z3/z3types.pyi":"30009c951af99b9028d47cd4cabae95ff9742b77b690bd8dd63f6b7dba580759","meta-python/test_constant_hash.py":"157cf4f8964e0f04c041ffd349e889ce565b144453436690578c5d03c3a60216","meta-python/test_srcgen.py":"d6d7775e19a5b2621360c00eb6d92dfcb4568e49220993e0ceaac9628dbfd661","meta-python/unique_table.py":"5bd500667430c15f6ae586603d8612fb3bda07b072e40d86286e08392bdc3127","src/abi.rs":"76ee030cf0780fe63ccbf855b1161f215e3e2991cb9abe71ca9aff25e5f1dbc2","src/binemit/memorysink.rs":"3ac1d77f178dabe3b2201735f9c7aa577fcc680424ad9ed435736b76fe583dfa","src/binemit/mod.rs":"ed63c382e6f58a9f7417d8913c15387f88d511a4ef02cba191c341496db50863","src/binemit/relaxation.rs":"697c4041b7e9605dd09b93be389cc18d54666ce16637383f2916a35788df32c9","src/binemit/shrink.rs":"63384c0eee75f0c0260cc385d7eb097dc67c85432f37dd28115a27fb17cfc3c9","src/bitset.rs":"d57a79058a31b094b4bbe9d34876a5543286df1e08b5ceadfd05a9efc5a3b1ce","src/cfg_printer.rs":"d285f1ce7d960089b9c28a3ab280bb1e6b3026f9f23ec0fac6b1a170b504d164","src/constant_hash.rs":"330e8289789ee351d0abeaf4b5e859b8db8772306e0820d34864fc9905d53b38","src/context.rs":"cf97e03ee2a5eaba6dd84208b937664a825e778aa49da34f5311b1f1c9a70a53","src/cursor.rs":"6643149791795257bd6bd8ce184dcb32e8aec835bd57711facfbe1f645c0d89e","src/dbg.rs":"1898d94cff0975815eb348651702e95c8f2f63886501d3b7043ee75668480472","src/dce.rs":"d8ab7c0cac0416f9d75afdacc60ba02e532361ec927c3f8bd171b1a53ec8b31a","src/divconst_magic_numbers.rs":"09691389c9055bef7a0cfd5d77fbfeba4be468d05d981d4de088516a94b8b28e","src/dominator_tree.rs":"7ee4114026011b11d49e48c5a9202970bafe3b22c2074f7c1390b98ebb2edb7a","src/flowgraph.rs":"bf520026c32c5454554d0b078b64a78bd44f3c0f4f198eddf71bcfd78cc963a3","src/fx.rs":"8a5d07487906d8316a179e826fcd817a92a4860686256a6fd9d78ba47c63f330","src/ir/builder.rs":"1a12c57f4168fa3c2fcf6be2f19d0d377eee40f24ae4390e6ba9d954f85a8a3e","src/ir/condcodes.rs":"5247c8d849e1372d2a22379c33a4a88226ec6187be18ca6f2c4e0f315d812aa8","src/ir/dfg.rs":"caa494cc32dbf27e87e5cfe3ed13e0116bf0f94f436cdeca75a59fe4b047b181","src/ir/entities.rs":"48a6fa7e43bd2d53bf7900e456fd80103088e16148e6ca859f71f0250df90ede","src/ir/extfunc.rs":"9806734eeb480724481128d8c1de78a3b1f80f1214c20f24131196a0df137872","src/ir/extname.rs":"ed2c0b52cdaecc7f0ba9a894ef9fffe139e09b520e43dcd6f0c887a3d41a31ac","src/ir/function.rs":"af8f8e09a2482865d8bd9be9f475fa5627c9a6886c2675286a47597fa54fcecd","src/ir/globalvalue.rs":"906d29f3d4190b811f66fc549c4e0408bdd2807eac98e33c0b3d5c2b876acc02","src/ir/heap.rs":"a59d3e5901412b53c0b53a8cdf10765ff5921de9c410ae9acea226c89827df3c","src/ir/immediates.rs":"029a8aa905e6fd0f3334e17a28e73ac36684df2ca0829dcae0158ea8cf64ca8c","src/ir/instructions.rs":"2180de1d127ab5878c5743d8e096d551edb973e0ff1d373c4239c32e7981364c","src/ir/jumptable.rs":"7764abc9aa027a5a89d22059b360372bd9a19686887c5a7830f7637d6f188e1e","src/ir/layout.rs":"bb45eefde16ac9423f637dfcc2796ae7b955a97f38a55f23a19cc45da5decce1","src/ir/libcall.rs":"413c46df13831c7d453ce2c833b2fa913f88f548bb6d840e55b716224e0b5499","src/ir/memflags.rs":"dbcf3798ab66dc764b73fb7f139a621c54cc6bcc683f1f70a33ed7e8c3486bfd","src/ir/mod.rs":"37685305acb21dc24896e5d7977784988fe723c09bdf8ab8cc7830ccabd76a11","src/ir/progpoint.rs":"49433f22bd6ff3a96ad0733ff612f3617b312e4492b6b663187141966f6aa701","src/ir/sourceloc.rs":"37ef5fd8cef1de99620797d7d5aba3630e737171853c8471495c685dafac19b6","src/ir/stackslot.rs":"2f54359339837bb1d0d817d3af21bb4b1b050c31703885dfaced29f6e41153c2","src/ir/table.rs":"dcc3b663a989b2b084402b08dc9a0e928dbd052e194a46a1886cc6f0cf1a5f2c","src/ir/trapcode.rs":"59e223193617b8c1043ddd3a907c6131f2987e8fe0965ebfd9f7c056c064b7c5","src/ir/types.rs":"1f644beba2c797f7bd89378d930c3eca1491ec5f82c4715945ac63a0a5754473","src/ir/valueloc.rs":"4c676c2d21d75611ef922a230ee82846afb565ce0f55bc71e33c70e1a1d92a07","src/isa/arm32/abi.rs":"74775c5f1eb95764e46815fa8b31891416a616fdd212972eb77aead43b3345a9","src/isa/arm32/binemit.rs":"52b2f4b3c6d8683ed6963c1f53907ac57b6aab7cc149464c9a12d6875aa3b5c6","src/isa/arm32/enc_tables.rs":"b5b7f2fdcaf1d1878a357c54ab757e94f0d06e5bd391ac5d876e96f5b30d6b7a","src/isa/arm32/mod.rs":"239eb819224af2c2edaa44355f5491cbab780b7427289a607162f5e0df500da8","src/isa/arm32/registers.rs":"254b568a02480f46bb4967a24a438390231014258f0c159f0a41dbafe8e66d56","src/isa/arm32/settings.rs":"188f3cc445168b472b488e73b011e83edd31ac17e3841dacda07a55ccf923468","src/isa/arm64/abi.rs":"52353ed2e2133dacddaad70a876ecebb9c179c19b911ffa823b5b89d3ee7a17c","src/isa/arm64/binemit.rs":"4465cceb68d03ae4d0fdf188c9b86870fb57b3617d67f0bb7d476e5afb581e81","src/isa/arm64/enc_tables.rs":"8c829c544daeed9adc8458891614a0be6f149e775bd22651465f2c165d4a9e56","src/isa/arm64/mod.rs":"46bc796d3420b252b7af843d60e16e0f51de524b0842c6e6fe1adcbadbb70752","src/isa/arm64/registers.rs":"308cfcfd9ff2191d7656e7350bb36e41803664eb86ae490fb4b4d3549b25b6a2","src/isa/arm64/settings.rs":"0dff47e995e5d9740deb0116b59e91fbcb725a7fa1bdbd802bf83c13381b17f7","src/isa/call_conv.rs":"833ac811ff78ab8d3a5052165e76c51c6da7686020d95462c18074750fb790ed","src/isa/constraints.rs":"bddb5c68e56b122a53d8be215e41d22ccf8c4563630b1486e6eb31c0d3337565","src/isa/enc_tables.rs":"3497f3d701f21d6f952424abf31515fde9e67aea1cde26236c9ee8b033c61ae6","src/isa/encoding.rs":"7ea5b4400530172f96e263561682886ea6c67e706398d44a83933ef7f0ac98a5","src/isa/mod.rs":"d9019b94d415113c782202a48d6c79d333fa6591539771cdc19e6dbee0047041","src/isa/registers.rs":"4a91d4888df5eeed1802f34c43a42b82aaf1f9928a58329b0cbc9c3c57c75485","src/isa/riscv/abi.rs":"36557b91ad16a1344c80fbb16a62b46eac88500d76cb9ebcd4eae224dd67b2de","src/isa/riscv/binemit.rs":"0bd76b005b53b71bdb59057a20671fbcd8ab1c37d767bfd4ab0a92d05e192d9a","src/isa/riscv/enc_tables.rs":"ab73c80fef6b1256fbd3c0e1bdd8e43a20f7d132a32236f6bfc028e9003adfe0","src/isa/riscv/mod.rs":"44932e33e3a6090bebe3c77e0237378d7808c61a331a7cc84ea22ec2f7f52ccb","src/isa/riscv/registers.rs":"666c2abe1a93db5f1573d1603db6c13c37f3fc877c0c93b64d1b971921bfa950","src/isa/riscv/settings.rs":"d018d23418ff3fb98571bcdeeddde3277bf213b4b8ac1e55b6573e128b3931ce","src/isa/stack.rs":"d023c57feb944c94c4dc8b7138dcbc9d37ff18ca23c23d83e9bab3c88299ffa0","src/isa/x86/abi.rs":"c36d9143f018af42c8c19f44e91510ccbcfa7be927357aff20ebd357de185fca","src/isa/x86/binemit.rs":"9b7a3a5aacbf382145ac39c2bfd767bdfa92a8d0447a84dcc19672f1db34d047","src/isa/x86/enc_tables.rs":"073fd2b33c412575e651d696c438429e53601a782d200470ffb86ee8249ac6b5","src/isa/x86/mod.rs":"c813127526b450f806b74837551deb0e7faae1e3cf74e618a4120c90eae59156","src/isa/x86/registers.rs":"bed70bbe1f56f3ef03ea7cd1bea68eb911913cb4c8b93167e044dfc639f7f461","src/isa/x86/settings.rs":"cd8f8c5255663f6e247f0634088b16b53d785ee8c62cb5c0926b3d27597c12ff","src/iterators.rs":"f85f52d3fa707a0eb974c92215b3e976923ce8f9481219f7812e0f2869c2bd37","src/legalizer/boundary.rs":"70a6819cbb116f07d0a09f8e5b0e2fe91145f423ad02e10225f8879ff4e61351","src/legalizer/call.rs":"be6074c64c1a00e5e81159dd94c8401fef62205b22c15e07e0c56cf922554d00","src/legalizer/globalvalue.rs":"59ab09a0faf593c7f228500b3fd3bacfc0412bdcb2864ec3621aa65adc4a5693","src/legalizer/heap.rs":"b83dc83a5876b024db058023692f71d8f910f6b212f34200e9bcf61a19daeb8e","src/legalizer/libcall.rs":"5c5a79709322a6562496c30af775ad255b27af67f7541fc1615f7deb891f8cff","src/legalizer/mod.rs":"d7ac361390308b605ee02d12d9bd6c0d46e36cf852115c0a71ddd88e8c7bd2bd","src/legalizer/split.rs":"13fe4d2cecea166ecdc1ebb11f5254374ee170518f1a61de7ac0a921bc8fb25d","src/legalizer/table.rs":"c36d03525312e3191aba8ee00c26a87c1ea200f9a9a0370f0cc84eeacff71786","src/lib.rs":"1e3a026f3ab6a1d133722227f1f9b8d2cd214e576e31c6c68d252326984dafc5","src/licm.rs":"1c14deeb4c86ef7bde39b16758825a774156609359724583ff8788be658abd8e","src/loop_analysis.rs":"58fc3cc0e700f05e3131ff1b16ff975d4f32a68c790f095d8445bd300356d3c0","src/nan_canonicalization.rs":"9619bb5554791bd1be75ecd98564d6c9f5b65132bc07c5c4d8c210cd79b66f82","src/partition_slice.rs":"bc13504e7658aab565918d965a0b67e941eb572e583870571bc6dbb2b9aad272","src/postopt.rs":"d4c487f0299fb905bb5a5822e38dea6f70afa4d4577288988b5bec8660bc1ba0","src/predicates.rs":"44bbc09ae0c7d5b54c05eb6061b062e92d1893edc7dda43ae2bccfedc6bb25e3","src/print_errors.rs":"3fbd77a01b5404a4bbcf2970e44299ad33948c71f4014d92026415daa8325314","src/ref_slice.rs":"421a61323c11858a596d50220487f399e1bcedeff0e8d1b716dd4b3531eb01a5","src/regalloc/affinity.rs":"19cec5495c8bddc1fcc8f3c8659d527a5a3ea373ffcc130e3fbd5b462ef15930","src/regalloc/coalescing.rs":"d83be1c1067eb56f2f8f16380450a327d6495b4c6f1f489ded68271c055aec07","src/regalloc/coloring.rs":"cd64fdf547e1c1a1ddcdf345d27b4ec6dfeaf6d34f69cab70082fb2b47c8e860","src/regalloc/context.rs":"e08cbd0dabaee5d9f78e8c6e3750ef61489c6517da7521043cad8dbb23f31581","src/regalloc/diversion.rs":"d46d733f6d00a8f536d5c7c8b8fc6f348c3d0605dd0ee77e1d8359367ba53347","src/regalloc/live_value_tracker.rs":"28823003dc72e8a4702776a8ab5ffd878712700a272b64376b0de2022e0ee31a","src/regalloc/liveness.rs":"a59673fda65d1e3c0e5b3f4468686d05a389c877bee7b10323264595c3c54677","src/regalloc/liverange.rs":"7a28454e5f70d570db439b966a01ead759b65eb65c5845f9c58bf2f230a5f2ab","src/regalloc/mod.rs":"6254df639f9289fd578e01b7dca99bc9c9e3c6680c6d031405e8df8d0cff31ad","src/regalloc/pressure.rs":"04738e95418f0f858885dfc45183efc3dfb59c8d2ad2fd88bbd9a73a62907730","src/regalloc/register_set.rs":"bc58f93f22f0adbe43260fe20c6089be1fca64f5bcc4acff85dc0a5ec5b61937","src/regalloc/reload.rs":"ccccb716a694b53103bd4d55efb2323e788c1127469233c17b648fa06baa67b1","src/regalloc/solver.rs":"43eebe2ae7f7e8b5510d161428152503ec37661f5083a36d925b4a247e1bd28a","src/regalloc/spilling.rs":"dff4af64409c9a1db7697423576826c3920c26c892fbdde89ee31c680d672e03","src/regalloc/virtregs.rs":"e5c8da6860ba9495f9396621530347e1dd6fc5b2fae2eb23c171ea77429356f1","src/result.rs":"c10354d615f93caa446c3c8c49d6ba3af762816af470f9c4accf04315cce9753","src/scoped_hash_map.rs":"5afafb3a4039094c3a2aad1582354220d21f399aa50046e7f4a1259e1976597e","src/settings.rs":"263d88ef1f976ecb5ee5656d95e77ca9cc49d91e9865f44d040d070a41a1bbfb","src/simple_gvn.rs":"c8feb380d4831badc59aa1e65efeafa6702711585817fe5f6b31de6b265fac24","src/simple_preopt.rs":"d2800d1345dc02e2ff5ef5c8b3d1bf9fcaee8f62e78df9f1681338ffc780d520","src/stack_layout.rs":"c5de271e296fc424f1a30017620bc88500369c8e553fef6e95beccb9c6640e7c","src/timing.rs":"a6808943eec68f5d3ff32132d40c07c142e6aa8073473561573a013978883e4f","src/topo_order.rs":"b01ed68a7300691f41ac434e58a5267b10a8b4a7056d65035e24aa8a6722122a","src/unreachable_code.rs":"40cc71a02887ee4065c76ce96dda0a363a8cc134ec784fe5ed1f276db76596ce","src/value_label.rs":"b860f1a5a35fbd562d9cce4ac38852139bd4f1d7425cda53c2529b0a361bd21c","src/verifier/cssa.rs":"e3e1d77b763c0ba82d3b59ab5b4667fd3152d5a08be50b58b0c82f86376bb062","src/verifier/flags.rs":"cac8ba7ed5fe621eaa425112b931423cb5f3523d580fcf0b7536deb252e96186","src/verifier/liveness.rs":"ac3413b464ee8b5aa5928bee724799b9a1e0cbbdce433c819b9d870483ed070a","src/verifier/locations.rs":"04635edc12bc741a23c9318611aac4abcb42f01effbebee6d858f108f9393a44","src/verifier/mod.rs":"a0ee43ae2f160936ab5ed05c6cea7111bd175aebe4058850060bfb5e1ded8a29","src/write.rs":"e067ac97dffcace67545525c631d6df6930e96700019a1e4723f98e31333fc9a"},"package":null}
\ No newline at end of file
--- a/third_party/rust/cranelift-codegen/meta-python/base/instructions.py
+++ b/third_party/rust/cranelift-codegen/meta-python/base/instructions.py
@@ -159,17 +159,17 @@ jump_table_entry = Instruction(
 
     Load a serialized ``entry`` from a jump table ``JT`` at a given index
     ``addr`` with a specific ``Size``. The retrieved entry may need to be
     decoded after loading, depending upon the jump table type used.
 
     Currently, the only type supported is entries which are relative to the
     base of the jump table.
     """,
-    ins=(x, addr, Size, JT), outs=entry)
+    ins=(x, addr, Size, JT), outs=entry, can_load=True)
 
 jump_table_base = Instruction(
     'jump_table_base', r"""
     Get the absolute base address of a jump table.
 
     This is used for jump tables wherein the entries are stored relative to
     the base of jump table. In order to use these, generated code should first
     load an entry using ``jump_table_entry``, then use this instruction to add
--- a/third_party/rust/cranelift-codegen/meta-python/isa/riscv/encodings.py
+++ b/third_party/rust/cranelift-codegen/meta-python/isa/riscv/encodings.py
@@ -1,19 +1,20 @@
 """
 RISC-V Encodings.
 """
 from __future__ import absolute_import
 from base import instructions as base
+from base import types
 from base.immediates import intcc
 from .defs import RV32, RV64
 from .recipes import OPIMM, OPIMM32, OP, OP32, LUI, BRANCH, JALR, JAL
 from .recipes import LOAD, STORE
 from .recipes import R, Rshamt, Ricmp, Ii, Iz, Iicmp, Iret, Icall, Icopy
-from .recipes import U, UJ, UJcall, SB, SBzero, GPsp, GPfi, Irmov
+from .recipes import U, UJ, UJcall, SB, SBzero, GPsp, GPfi, Irmov, stacknull
 from .settings import use_m
 from cdsl.ast import Var
 from base.legalize import narrow, expand
 
 RV32.legalize_monomorphic(expand)
 RV32.legalize_type(
         default=narrow,
         i32=expand,
@@ -155,8 +156,14 @@ RV64.enc(base.copy.i32, Icopy, OPIMM32(0
 RV32.enc(base.regmove.i32, Irmov, OPIMM(0b000))
 RV64.enc(base.regmove.i64, Irmov, OPIMM(0b000))
 RV64.enc(base.regmove.i32, Irmov, OPIMM32(0b000))
 
 RV32.enc(base.copy.b1, Icopy, OPIMM(0b000))
 RV64.enc(base.copy.b1, Icopy, OPIMM(0b000))
 RV32.enc(base.regmove.b1, Irmov, OPIMM(0b000))
 RV64.enc(base.regmove.b1, Irmov, OPIMM(0b000))
+
+# Stack-slot-to-the-same-stack-slot copy, which is guaranteed to turn
+# into a no-op.
+for ty in [types.i64, types.i32, types.i16, types.i8, types.f64, types.f32]:
+    RV64.enc(base.copy_nop.bind(ty), stacknull, 0)
+    RV32.enc(base.copy_nop.bind(ty), stacknull, 0)
--- a/third_party/rust/cranelift-codegen/meta-python/isa/riscv/recipes.py
+++ b/third_party/rust/cranelift-codegen/meta-python/isa/riscv/recipes.py
@@ -218,8 +218,13 @@ GPsp = EncRecipe(
         ins=GPR, outs=Stack(GPR),
         emit='unimplemented!();')
 
 # Fill of a GPR.
 GPfi = EncRecipe(
         'GPfi', Unary, base_size=4,
         ins=Stack(GPR), outs=GPR,
         emit='unimplemented!();')
+
+# Stack-slot-to-the-same-stack-slot copy, which is guaranteed to turn
+# into a no-op.
+stacknull = EncRecipe('stacknull', Unary, base_size=0,
+                      ins=Stack(GPR), outs=Stack(GPR), emit='')
--- a/third_party/rust/cranelift-codegen/meta-python/isa/x86/encodings.py
+++ b/third_party/rust/cranelift-codegen/meta-python/isa/x86/encodings.py
@@ -337,21 +337,33 @@ enc_x86_64(x86.pop.i64, r.popq, 0x58)
 
 # Copy Special
 # For x86-64, only define REX forms for now, since we can't describe the
 # special regunit immediate operands with the current constraint language.
 X86_64.enc(base.copy_special, *r.copysp.rex(0x89, w=1))
 X86_32.enc(base.copy_special, *r.copysp(0x89))
 
 # Stack-slot-to-the-same-stack-slot copy, which is guaranteed to turn
-# into a no-op.
-X86_64.enc(base.copy_nop.i64, r.stacknull, 0)
-X86_64.enc(base.copy_nop.i32, r.stacknull, 0)
-X86_64.enc(base.copy_nop.f64, r.stacknull, 0)
-X86_64.enc(base.copy_nop.f32, r.stacknull, 0)
+# into a no-op.  Ideally we could to make this encoding available for
+# all types, and write `base.copy_nop.any`, but it appears that the
+# controlling type variable must not polymorphic.  So we make do with
+# the following limited set, and guard the generating transformation in
+# regalloc/reload.rs accordingly.
+#
+# The same encoding is generated for both the 64- and 32-bit architectures.
+# Note that we can't use `enc_both` here, because that attempts to create a
+# variant with a REX prefix in the 64-bit-architecture case.  But since
+# there's no actual instruction for the REX prefix to modify the meaning of,
+# it will modify the meaning of whatever instruction happens to follow this
+# one, which is obviously wrong.  Note also that we can and indeed *must*
+# claim that there's a 64-bit encoding for the 32-bit arch case, even though
+# no such single instruction actually exists for the 32-bit arch case.
+for ty in [types.i64, types.i32, types.i16, types.i8, types.f64, types.f32]:
+    X86_64.enc(base.copy_nop.bind(ty), r.stacknull, 0)
+    X86_32.enc(base.copy_nop.bind(ty), r.stacknull, 0)
 
 # Adjust SP down by a dynamic value (or up, with a negative operand).
 X86_32.enc(base.adjust_sp_down.i32, *r.adjustsp(0x29))
 X86_64.enc(base.adjust_sp_down.i64, *r.adjustsp.rex(0x29, w=1))
 
 # Adjust SP up by an immediate (or down, with a negative immediate)
 X86_32.enc(base.adjust_sp_up_imm, *r.adjustsp_ib(0x83))
 X86_32.enc(base.adjust_sp_up_imm, *r.adjustsp_id(0x81))
--- a/third_party/rust/cranelift-codegen/src/binemit/memorysink.rs
+++ b/third_party/rust/cranelift-codegen/src/binemit/memorysink.rs
@@ -29,28 +29,32 @@ use core::ptr::write_unaligned;
 ///
 /// Note that `MemoryCodeSink` writes multi-byte values in the native byte order of the host. This
 /// is not the right thing to do for cross compilation.
 pub struct MemoryCodeSink<'a> {
     /// Pointer to start of sink's preallocated memory.
     data: *mut u8,
     /// Offset is isize because its major consumer needs it in that form.
     offset: isize,
-    relocs: &'a mut RelocSink,
-    traps: &'a mut TrapSink,
+    relocs: &'a mut dyn RelocSink,
+    traps: &'a mut dyn TrapSink,
     /// Information about the generated code and read-only data.
     pub info: CodeInfo,
 }
 
 impl<'a> MemoryCodeSink<'a> {
     /// Create a new memory code sink that writes a function to the memory pointed to by `data`.
     ///
     /// This function is unsafe since `MemoryCodeSink` does not perform bounds checking on the
     /// memory buffer, and it can't guarantee that the `data` pointer is valid.
-    pub unsafe fn new(data: *mut u8, relocs: &'a mut RelocSink, traps: &'a mut TrapSink) -> Self {
+    pub unsafe fn new(
+        data: *mut u8,
+        relocs: &'a mut dyn RelocSink,
+        traps: &'a mut dyn TrapSink,
+    ) -> Self {
         Self {
             data,
             offset: 0,
             info: CodeInfo {
                 code_size: 0,
                 jumptables_size: 0,
                 rodata_size: 0,
                 total_size: 0,
@@ -137,17 +141,17 @@ impl<'a> CodeSink for MemoryCodeSink<'a>
         self.info.code_size = self.offset();
     }
 
     fn begin_rodata(&mut self) {
         self.info.jumptables_size = self.offset() - self.info.code_size;
     }
 
     fn end_codegen(&mut self) {
-        self.info.rodata_size = self.offset() - self.info.jumptables_size;
+        self.info.rodata_size = self.offset() - (self.info.jumptables_size + self.info.code_size);
         self.info.total_size = self.offset();
     }
 }
 
 /// A `TrapSink` implementation that does nothing, which is convenient when
 /// compiling code that does not rely on trapping semantics.
 pub struct NullTrapSink {}
 
--- a/third_party/rust/cranelift-codegen/src/binemit/relaxation.rs
+++ b/third_party/rust/cranelift-codegen/src/binemit/relaxation.rs
@@ -35,17 +35,17 @@ use crate::iterators::IteratorExtras;
 use crate::regalloc::RegDiversions;
 use crate::timing;
 use crate::CodegenResult;
 use log::debug;
 
 /// Relax branches and compute the final layout of EBB headers in `func`.
 ///
 /// Fill in the `func.offsets` table so the function is ready for binary emission.
-pub fn relax_branches(func: &mut Function, isa: &TargetIsa) -> CodegenResult<CodeInfo> {
+pub fn relax_branches(func: &mut Function, isa: &dyn TargetIsa) -> CodegenResult<CodeInfo> {
     let _tt = timing::relax_branches();
 
     let encinfo = isa.encoding_info();
 
     // Clear all offsets so we can recognize EBBs that haven't been visited yet.
     func.offsets.clear();
     func.offsets.resize(func.dfg.num_ebbs());
 
@@ -169,17 +169,17 @@ fn fallthroughs(func: &mut Function) {
 /// Return the size of the replacement instructions up to and including the location where `cur` is
 /// left.
 fn relax_branch(
     cur: &mut FuncCursor,
     divert: &RegDiversions,
     offset: CodeOffset,
     dest_offset: CodeOffset,
     encinfo: &EncInfo,
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
 ) -> CodeOffset {
     let inst = cur.current_inst().unwrap();
     debug!(
         "Relaxing [{}] {} for {:#x}-{:#x} range",
         encinfo.display(cur.func.encodings[inst]),
         cur.func.dfg.display_inst(inst, isa),
         offset,
         dest_offset
--- a/third_party/rust/cranelift-codegen/src/binemit/shrink.rs
+++ b/third_party/rust/cranelift-codegen/src/binemit/shrink.rs
@@ -8,17 +8,17 @@
 use crate::ir::instructions::InstructionData;
 use crate::ir::Function;
 use crate::isa::TargetIsa;
 use crate::regalloc::RegDiversions;
 use crate::timing;
 use log::debug;
 
 /// Pick the smallest valid encodings for instructions.
-pub fn shrink_instructions(func: &mut Function, isa: &TargetIsa) {
+pub fn shrink_instructions(func: &mut Function, isa: &dyn TargetIsa) {
     let _tt = timing::shrink_instructions();
 
     let encinfo = isa.encoding_info();
     let mut divert = RegDiversions::new();
 
     for ebb in func.layout.ebbs() {
         divert.clear();
         for inst in func.layout.ebb_insts(ebb) {
--- a/third_party/rust/cranelift-codegen/src/cfg_printer.rs
+++ b/third_party/rust/cranelift-codegen/src/cfg_printer.rs
@@ -18,32 +18,32 @@ impl<'a> CFGPrinter<'a> {
     pub fn new(func: &'a Function) -> Self {
         Self {
             func,
             cfg: ControlFlowGraph::with_function(func),
         }
     }
 
     /// Write the CFG for this function to `w`.
-    pub fn write(&self, w: &mut Write) -> Result {
+    pub fn write(&self, w: &mut dyn Write) -> Result {
         self.header(w)?;
         self.ebb_nodes(w)?;
         self.cfg_connections(w)?;
         writeln!(w, "}}")
     }
 
-    fn header(&self, w: &mut Write) -> Result {
+    fn header(&self, w: &mut dyn Write) -> Result {
         writeln!(w, "digraph \"{}\" {{", self.func.name)?;
         if let Some(entry) = self.func.layout.entry_block() {
             writeln!(w, "    {{rank=min; {}}}", entry)?;
         }
         Ok(())
     }
 
-    fn ebb_nodes(&self, w: &mut Write) -> Result {
+    fn ebb_nodes(&self, w: &mut dyn Write) -> Result {
         for ebb in &self.func.layout {
             write!(w, "    {} [shape=record, label=\"{{{}", ebb, ebb)?;
             // Add all outgoing branch instructions to the label.
             for inst in self.func.layout.ebb_insts(ebb) {
                 let idata = &self.func.dfg[inst];
                 match idata.analyze_branch(&self.func.dfg.value_lists) {
                     BranchInfo::SingleDest(dest, _) => {
                         write!(w, " | <{}>{} {}", inst, idata.opcode(), dest)?
@@ -57,17 +57,17 @@ impl<'a> CFGPrinter<'a> {
                     BranchInfo::NotABranch => {}
                 }
             }
             writeln!(w, "}}\"]")?
         }
         Ok(())
     }
 
-    fn cfg_connections(&self, w: &mut Write) -> Result {
+    fn cfg_connections(&self, w: &mut dyn Write) -> Result {
         for ebb in &self.func.layout {
             for BasicBlock { ebb: parent, inst } in self.cfg.pred_iter(ebb) {
                 writeln!(w, "    {}:{} -> {}", parent, inst, ebb)?;
             }
         }
         Ok(())
     }
 }
--- a/third_party/rust/cranelift-codegen/src/context.rs
+++ b/third_party/rust/cranelift-codegen/src/context.rs
@@ -91,20 +91,20 @@ impl Context {
     /// into `relocs`.
     ///
     /// This function calls `compile` and `emit_to_memory`, taking care to resize `mem` as
     /// needed, so it provides a safe interface.
     ///
     /// Returns information about the function's code and read-only data.
     pub fn compile_and_emit(
         &mut self,
-        isa: &TargetIsa,
+        isa: &dyn TargetIsa,
         mem: &mut Vec<u8>,
-        relocs: &mut RelocSink,
-        traps: &mut TrapSink,
+        relocs: &mut dyn RelocSink,
+        traps: &mut dyn TrapSink,
     ) -> CodegenResult<CodeInfo> {
         let info = self.compile(isa)?;
         let old_len = mem.len();
         mem.resize(old_len + info.total_size as usize, 0);
         let new_info =
             unsafe { self.emit_to_memory(isa, mem.as_mut_ptr().add(old_len), relocs, traps) };
         debug_assert!(new_info == info);
         Ok(info)
@@ -112,17 +112,17 @@ impl Context {
 
     /// Compile the function.
     ///
     /// Run the function through all the passes necessary to generate code for the target ISA
     /// represented by `isa`. This does not include the final step of emitting machine code into a
     /// code sink.
     ///
     /// Returns information about the function's code and read-only data.
-    pub fn compile(&mut self, isa: &TargetIsa) -> CodegenResult<CodeInfo> {
+    pub fn compile(&mut self, isa: &dyn TargetIsa) -> CodegenResult<CodeInfo> {
         let _tt = timing::compile();
         self.verify_if(isa)?;
 
         self.compute_cfg();
         if isa.flags().opt_level() != OptLevel::Fastest {
             self.preopt(isa)?;
         }
         if isa.flags().enable_nan_canonicalization() {
@@ -159,20 +159,20 @@ impl Context {
     /// The machine code is not relocated. Instead, any relocations are emitted into `relocs`.
     ///
     /// This function is unsafe since it does not perform bounds checking on the memory buffer,
     /// and it can't guarantee that the `mem` pointer is valid.
     ///
     /// Returns information about the emitted code and data.
     pub unsafe fn emit_to_memory(
         &self,
-        isa: &TargetIsa,
+        isa: &dyn TargetIsa,
         mem: *mut u8,
-        relocs: &mut RelocSink,
-        traps: &mut TrapSink,
+        relocs: &mut dyn RelocSink,
+        traps: &mut dyn TrapSink,
     ) -> CodeInfo {
         let _tt = timing::binemit();
         let mut sink = MemoryCodeSink::new(mem, relocs, traps);
         isa.emit_function_to_memory(&self.func, &mut sink);
         sink.info
     }
 
     /// Run the verifier on the function.
@@ -194,67 +194,67 @@ impl Context {
         let fisa = fisa.into();
         if fisa.flags.enable_verifier() {
             self.verify(fisa)?;
         }
         Ok(())
     }
 
     /// Run the locations verifier on the function.
-    pub fn verify_locations(&self, isa: &TargetIsa) -> VerifierResult<()> {
+    pub fn verify_locations(&self, isa: &dyn TargetIsa) -> VerifierResult<()> {
         let mut errors = VerifierErrors::default();
         let _ = verify_locations(isa, &self.func, None, &mut errors);
 
         if errors.is_empty() {
             Ok(())
         } else {
             Err(errors)
         }
     }
 
     /// Run the locations verifier only if the `enable_verifier` setting is true.
-    pub fn verify_locations_if(&self, isa: &TargetIsa) -> CodegenResult<()> {
+    pub fn verify_locations_if(&self, isa: &dyn TargetIsa) -> CodegenResult<()> {
         if isa.flags().enable_verifier() {
             self.verify_locations(isa)?;
         }
         Ok(())
     }
 
     /// Perform dead-code elimination on the function.
     pub fn dce<'a, FOI: Into<FlagsOrIsa<'a>>>(&mut self, fisa: FOI) -> CodegenResult<()> {
         do_dce(&mut self.func, &mut self.domtree);
         self.verify_if(fisa)?;
         Ok(())
     }
 
     /// Perform pre-legalization rewrites on the function.
-    pub fn preopt(&mut self, isa: &TargetIsa) -> CodegenResult<()> {
+    pub fn preopt(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
         do_preopt(&mut self.func, &mut self.cfg);
         self.verify_if(isa)?;
         Ok(())
     }
 
     /// Perform NaN canonicalizing rewrites on the function.
-    pub fn canonicalize_nans(&mut self, isa: &TargetIsa) -> CodegenResult<()> {
+    pub fn canonicalize_nans(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
         do_nan_canonicalization(&mut self.func);
         self.verify_if(isa)
     }
 
     /// Run the legalizer for `isa` on the function.
-    pub fn legalize(&mut self, isa: &TargetIsa) -> CodegenResult<()> {
+    pub fn legalize(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
         // Legalization invalidates the domtree and loop_analysis by mutating the CFG.
         // TODO: Avoid doing this when legalization doesn't actually mutate the CFG.
         self.domtree.clear();
         self.loop_analysis.clear();
         legalize_function(&mut self.func, &mut self.cfg, isa);
         self.verify_if(isa)
     }
 
     /// Perform post-legalization rewrites on the function.
-    pub fn postopt(&mut self, isa: &TargetIsa) -> CodegenResult<()> {
+    pub fn postopt(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
         do_postopt(&mut self.func, isa);
         self.verify_if(isa)?;
         Ok(())
     }
 
     /// Compute the control flow graph.
     pub fn compute_cfg(&mut self) {
         self.cfg.compute(&self.func)
@@ -279,17 +279,17 @@ impl Context {
 
     /// Perform simple GVN on the function.
     pub fn simple_gvn<'a, FOI: Into<FlagsOrIsa<'a>>>(&mut self, fisa: FOI) -> CodegenResult<()> {
         do_simple_gvn(&mut self.func, &mut self.domtree);
         self.verify_if(fisa)
     }
 
     /// Perform LICM on the function.
-    pub fn licm(&mut self, isa: &TargetIsa) -> CodegenResult<()> {
+    pub fn licm(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
         do_licm(
             isa,
             &mut self.func,
             &mut self.cfg,
             &mut self.domtree,
             &mut self.loop_analysis,
         );
         self.verify_if(isa)
@@ -300,47 +300,50 @@ impl Context {
     where
         FOI: Into<FlagsOrIsa<'a>>,
     {
         eliminate_unreachable_code(&mut self.func, &mut self.cfg, &self.domtree);
         self.verify_if(fisa)
     }
 
     /// Run the register allocator.
-    pub fn regalloc(&mut self, isa: &TargetIsa) -> CodegenResult<()> {
+    pub fn regalloc(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
         self.regalloc
             .run(isa, &mut self.func, &self.cfg, &mut self.domtree)
     }
 
     /// Insert prologue and epilogues after computing the stack frame layout.
-    pub fn prologue_epilogue(&mut self, isa: &TargetIsa) -> CodegenResult<()> {
+    pub fn prologue_epilogue(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
         isa.prologue_epilogue(&mut self.func)?;
         self.verify_if(isa)?;
         self.verify_locations_if(isa)?;
         Ok(())
     }
 
     /// Run the instruction shrinking pass.
-    pub fn shrink_instructions(&mut self, isa: &TargetIsa) -> CodegenResult<()> {
+    pub fn shrink_instructions(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
         shrink_instructions(&mut self.func, isa);
         self.verify_if(isa)?;
         self.verify_locations_if(isa)?;
         Ok(())
     }
 
     /// Run the branch relaxation pass and return information about the function's code and
     /// read-only data.
-    pub fn relax_branches(&mut self, isa: &TargetIsa) -> CodegenResult<CodeInfo> {
+    pub fn relax_branches(&mut self, isa: &dyn TargetIsa) -> CodegenResult<CodeInfo> {
         let info = relax_branches(&mut self.func, isa)?;
         self.verify_if(isa)?;
         self.verify_locations_if(isa)?;
         Ok(info)
     }
 
     /// Builds ranges and location for specified value labels.
-    pub fn build_value_labels_ranges(&self, isa: &TargetIsa) -> CodegenResult<ValueLabelsRanges> {
+    pub fn build_value_labels_ranges(
+        &self,
+        isa: &dyn TargetIsa,
+    ) -> CodegenResult<ValueLabelsRanges> {
         Ok(build_value_labels_ranges::<ComparableSourceLoc>(
             &self.func,
             &self.regalloc,
             isa,
         ))
     }
 }
--- a/third_party/rust/cranelift-codegen/src/cursor.rs
+++ b/third_party/rust/cranelift-codegen/src/cursor.rs
@@ -652,22 +652,22 @@ pub struct EncCursor<'f> {
     pos: CursorPosition,
     srcloc: ir::SourceLoc,
     built_inst: Option<ir::Inst>,
 
     /// The referenced function.
     pub func: &'f mut ir::Function,
 
     /// The target ISA that will be used to encode instructions.
-    pub isa: &'f TargetIsa,
+    pub isa: &'f dyn TargetIsa,
 }
 
 impl<'f> EncCursor<'f> {
     /// Create a new `EncCursor` pointing nowhere.
-    pub fn new(func: &'f mut ir::Function, isa: &'f TargetIsa) -> Self {
+    pub fn new(func: &'f mut ir::Function, isa: &'f dyn TargetIsa) -> Self {
         Self {
             pos: CursorPosition::Nowhere,
             srcloc: Default::default(),
             built_inst: None,
             func,
             isa,
         }
     }
--- a/third_party/rust/cranelift-codegen/src/ir/dfg.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/dfg.rs
@@ -421,17 +421,17 @@ impl DataFlowGraph {
     /// multiple results, also call `make_inst_results` to allocate value table entries.
     pub fn make_inst(&mut self, data: InstructionData) -> Inst {
         let n = self.num_insts() + 1;
         self.results.resize(n);
         self.insts.push(data)
     }
 
     /// Returns an object that displays `inst`.
-    pub fn display_inst<'a, I: Into<Option<&'a TargetIsa>>>(
+    pub fn display_inst<'a, I: Into<Option<&'a dyn TargetIsa>>>(
         &'a self,
         inst: Inst,
         isa: I,
     ) -> DisplayInst<'a> {
         DisplayInst(self, isa.into(), inst)
     }
 
     /// Get all value arguments on `inst` as a slice.
@@ -904,17 +904,17 @@ impl EbbData {
     fn new() -> Self {
         Self {
             params: ValueList::new(),
         }
     }
 }
 
 /// Object that can display an instruction.
-pub struct DisplayInst<'a>(&'a DataFlowGraph, Option<&'a TargetIsa>, Inst);
+pub struct DisplayInst<'a>(&'a DataFlowGraph, Option<&'a dyn TargetIsa>, Inst);
 
 impl<'a> fmt::Display for DisplayInst<'a> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let dfg = self.0;
         let isa = self.1;
         let inst = self.2;
 
         if let Some((first, rest)) = dfg.inst_results(inst).split_first() {
--- a/third_party/rust/cranelift-codegen/src/ir/entities.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/entities.rs
@@ -233,17 +233,17 @@ impl fmt::Display for AnyEntity {
             AnyEntity::Heap(r) => r.fmt(f),
             AnyEntity::Table(r) => r.fmt(f),
         }
     }
 }
 
 impl fmt::Debug for AnyEntity {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        (self as &fmt::Display).fmt(f)
+        (self as &dyn fmt::Display).fmt(f)
     }
 }
 
 impl From<Ebb> for AnyEntity {
     fn from(r: Ebb) -> Self {
         AnyEntity::Ebb(r)
     }
 }
--- a/third_party/rust/cranelift-codegen/src/ir/function.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/function.rs
@@ -150,17 +150,20 @@ impl Function {
     }
 
     /// Declares a table accessible to the function.
     pub fn create_table(&mut self, data: TableData) -> Table {
         self.tables.push(data)
     }
 
     /// Return an object that can display this function with correct ISA-specific annotations.
-    pub fn display<'a, I: Into<Option<&'a TargetIsa>>>(&'a self, isa: I) -> DisplayFunction<'a> {
+    pub fn display<'a, I: Into<Option<&'a dyn TargetIsa>>>(
+        &'a self,
+        isa: I,
+    ) -> DisplayFunction<'a> {
         DisplayFunction(self, isa.into().into())
     }
 
     /// Return an object that can display this function with correct ISA-specific annotations.
     pub fn display_with<'a>(
         &'a self,
         annotations: DisplayFunctionAnnotations<'a>,
     ) -> DisplayFunction<'a> {
@@ -197,53 +200,53 @@ impl Function {
             divert: RegDiversions::new(),
             encodings: &self.encodings,
             offset: self.offsets[ebb],
             iter: self.layout.ebb_insts(ebb),
         }
     }
 
     /// Wrapper around `encode` which assigns `inst` the resulting encoding.
-    pub fn update_encoding(&mut self, inst: ir::Inst, isa: &TargetIsa) -> Result<(), Legalize> {
+    pub fn update_encoding(&mut self, inst: ir::Inst, isa: &dyn TargetIsa) -> Result<(), Legalize> {
         self.encode(inst, isa).map(|e| self.encodings[inst] = e)
     }
 
     /// Wrapper around `TargetIsa::encode` for encoding an existing instruction
     /// in the `Function`.
-    pub fn encode(&self, inst: ir::Inst, isa: &TargetIsa) -> Result<Encoding, Legalize> {
+    pub fn encode(&self, inst: ir::Inst, isa: &dyn TargetIsa) -> Result<Encoding, Legalize> {
         isa.encode(&self, &self.dfg[inst], self.dfg.ctrl_typevar(inst))
     }
 
     /// Starts collection of debug information.
     pub fn collect_debug_info(&mut self) {
         self.dfg.collect_debug_info();
     }
 }
 
 /// Additional annotations for function display.
 pub struct DisplayFunctionAnnotations<'a> {
     /// Enable ISA annotations.
-    pub isa: Option<&'a TargetIsa>,
+    pub isa: Option<&'a dyn TargetIsa>,
 
     /// Enable value labels annotations.
     pub value_ranges: Option<&'a ValueLabelsRanges>,
 }
 
 impl<'a> DisplayFunctionAnnotations<'a> {
     /// Create a DisplayFunctionAnnotations with all fields set to None.
     pub fn default() -> Self {
         DisplayFunctionAnnotations {
             isa: None,
             value_ranges: None,
         }
     }
 }
 
-impl<'a> From<Option<&'a TargetIsa>> for DisplayFunctionAnnotations<'a> {
-    fn from(isa: Option<&'a TargetIsa>) -> DisplayFunctionAnnotations {
+impl<'a> From<Option<&'a dyn TargetIsa>> for DisplayFunctionAnnotations<'a> {
+    fn from(isa: Option<&'a dyn TargetIsa>) -> DisplayFunctionAnnotations {
         DisplayFunctionAnnotations {
             isa,
             value_ranges: None,
         }
     }
 }
 
 /// Wrapper type capable of displaying a `Function` with correct ISA annotations.
--- a/third_party/rust/cranelift-codegen/src/ir/globalvalue.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/globalvalue.rs
@@ -71,17 +71,17 @@ impl GlobalValueData {
     pub fn symbol_name(&self) -> &ExternalName {
         match *self {
             GlobalValueData::Symbol { ref name, .. } => name,
             _ => panic!("only symbols have names"),
         }
     }
 
     /// Return the type of this global.
-    pub fn global_type(&self, isa: &TargetIsa) -> Type {
+    pub fn global_type(&self, isa: &dyn TargetIsa) -> Type {
         match *self {
             GlobalValueData::VMContext { .. } | GlobalValueData::Symbol { .. } => {
                 isa.pointer_type()
             }
             GlobalValueData::IAddImm { global_type, .. }
             | GlobalValueData::Load { global_type, .. } => global_type,
         }
     }
--- a/third_party/rust/cranelift-codegen/src/ir/libcall.rs
+++ b/third_party/rust/cranelift-codegen/src/ir/libcall.rs
@@ -102,29 +102,29 @@ impl LibCall {
 /// Get a function reference for `libcall` in `func`, following the signature
 /// for `inst`.
 ///
 /// If there is an existing reference, use it, otherwise make a new one.
 pub fn get_libcall_funcref(
     libcall: LibCall,
     func: &mut Function,
     inst: Inst,
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
 ) -> FuncRef {
     find_funcref(libcall, func).unwrap_or_else(|| make_funcref_for_inst(libcall, func, inst, isa))
 }
 
 /// Get a function reference for the probestack function in `func`.
 ///
 /// If there is an existing reference, use it, otherwise make a new one.
 pub fn get_probestack_funcref(
     func: &mut Function,
     reg_type: Type,
     arg_reg: RegUnit,
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
 ) -> FuncRef {
     find_funcref(LibCall::Probestack, func)
         .unwrap_or_else(|| make_funcref_for_probestack(func, reg_type, arg_reg, isa))
 }
 
 /// Get the existing function reference for `libcall` in `func` if it exists.
 fn find_funcref(libcall: LibCall, func: &Function) -> Option<FuncRef> {
     // We're assuming that all libcall function decls are at the end.
@@ -142,47 +142,52 @@ fn find_funcref(libcall: LibCall, func: 
     None
 }
 
 /// Create a funcref for `LibCall::Probestack`.
 fn make_funcref_for_probestack(
     func: &mut Function,
     reg_type: Type,
     arg_reg: RegUnit,
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
 ) -> FuncRef {
     let mut sig = Signature::new(CallConv::Probestack);
     let rax = AbiParam::special_reg(reg_type, ArgumentPurpose::Normal, arg_reg);
     sig.params.push(rax);
     if !isa.flags().probestack_func_adjusts_sp() {
         sig.returns.push(rax);
     }
     make_funcref(LibCall::Probestack, func, sig, isa)
 }
 
 /// Create a funcref for `libcall` with a signature matching `inst`.
 fn make_funcref_for_inst(
     libcall: LibCall,
     func: &mut Function,
     inst: Inst,
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
 ) -> FuncRef {
     let mut sig = Signature::new(isa.default_call_conv());
     for &v in func.dfg.inst_args(inst) {
         sig.params.push(AbiParam::new(func.dfg.value_type(v)));
     }
     for &v in func.dfg.inst_results(inst) {
         sig.returns.push(AbiParam::new(func.dfg.value_type(v)));
     }
 
     make_funcref(libcall, func, sig, isa)
 }
 
 /// Create a funcref for `libcall`.
-fn make_funcref(libcall: LibCall, func: &mut Function, sig: Signature, isa: &TargetIsa) -> FuncRef {
+fn make_funcref(
+    libcall: LibCall,
+    func: &mut Function,
+    sig: Signature,
+    isa: &dyn TargetIsa,
+) -> FuncRef {
     let sigref = func.import_signature(sig);
 
     func.import_function(ExtFuncData {
         name: ExternalName::LibCall(libcall),
         signature: sigref,
         colocated: isa.flags().colocated_libcalls(),
     })
 }
--- a/third_party/rust/cranelift-codegen/src/isa/arm32/mod.rs
+++ b/third_party/rust/cranelift-codegen/src/isa/arm32/mod.rs
@@ -35,17 +35,17 @@ pub fn isa_builder(triple: Triple) -> Is
         constructor: isa_constructor,
     }
 }
 
 fn isa_constructor(
     triple: Triple,
     shared_flags: shared_settings::Flags,
     builder: shared_settings::Builder,
-) -> Box<TargetIsa> {
+) -> Box<dyn TargetIsa> {
     let level1 = match triple.architecture {
         Architecture::Thumbv6m | Architecture::Thumbv7em | Architecture::Thumbv7m => {
             &enc_tables::LEVEL1_T32[..]
         }
         Architecture::Arm
         | Architecture::Armv4t
         | Architecture::Armv5te
         | Architecture::Armv7
@@ -114,17 +114,17 @@ impl TargetIsa for Isa {
     }
 
     #[cfg(feature = "testing_hooks")]
     fn emit_inst(
         &self,
         func: &ir::Function,
         inst: ir::Inst,
         divert: &mut regalloc::RegDiversions,
-        sink: &mut CodeSink,
+        sink: &mut dyn CodeSink,
     ) {
         binemit::emit_inst(func, inst, divert, sink)
     }
 
     fn emit_function_to_memory(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
         emit_function(func, binemit::emit_inst, sink)
     }
 }
--- a/third_party/rust/cranelift-codegen/src/isa/arm64/mod.rs
+++ b/third_party/rust/cranelift-codegen/src/isa/arm64/mod.rs
@@ -34,17 +34,17 @@ pub fn isa_builder(triple: Triple) -> Is
         constructor: isa_constructor,
     }
 }
 
 fn isa_constructor(
     triple: Triple,
     shared_flags: shared_settings::Flags,
     builder: shared_settings::Builder,
-) -> Box<TargetIsa> {
+) -> Box<dyn TargetIsa> {
     Box::new(Isa {
         triple,
         isa_flags: settings::Flags::new(&shared_flags, builder),
         shared_flags,
     })
 }
 
 impl TargetIsa for Isa {
@@ -101,17 +101,17 @@ impl TargetIsa for Isa {
     }
 
     #[cfg(feature = "testing_hooks")]
     fn emit_inst(
         &self,
         func: &ir::Function,
         inst: ir::Inst,
         divert: &mut regalloc::RegDiversions,
-        sink: &mut CodeSink,
+        sink: &mut dyn CodeSink,
     ) {
         binemit::emit_inst(func, inst, divert, sink)
     }
 
     fn emit_function_to_memory(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
         emit_function(func, binemit::emit_inst, sink)
     }
 }
--- a/third_party/rust/cranelift-codegen/src/isa/mod.rs
+++ b/third_party/rust/cranelift-codegen/src/isa/mod.rs
@@ -136,23 +136,23 @@ pub enum LookupError {
     Unsupported,
 }
 
 /// Builder for a `TargetIsa`.
 /// Modify the ISA-specific settings before creating the `TargetIsa` trait object with `finish`.
 pub struct Builder {
     triple: Triple,
     setup: settings::Builder,
-    constructor: fn(Triple, settings::Flags, settings::Builder) -> Box<TargetIsa>,
+    constructor: fn(Triple, settings::Flags, settings::Builder) -> Box<dyn TargetIsa>,
 }
 
 impl Builder {
     /// Combine the ISA-specific settings with the provided ISA-independent settings and allocate a
     /// fully configured `TargetIsa` trait object.
-    pub fn finish(self, shared_flags: settings::Flags) -> Box<TargetIsa> {
+    pub fn finish(self, shared_flags: settings::Flags) -> Box<dyn TargetIsa> {
         (self.constructor)(self.triple, shared_flags, self.setup)
     }
 }
 
 impl settings::Configurable for Builder {
     fn set(&mut self, name: &str, value: &str) -> SetResult<()> {
         self.setup.set(name, value)
     }
@@ -162,17 +162,17 @@ impl settings::Configurable for Builder 
     }
 }
 
 /// After determining that an instruction doesn't have an encoding, how should we proceed to
 /// legalize it?
 ///
 /// The `Encodings` iterator returns a legalization function to call.
 pub type Legalize =
-    fn(ir::Inst, &mut ir::Function, &mut flowgraph::ControlFlowGraph, &TargetIsa) -> bool;
+    fn(ir::Inst, &mut ir::Function, &mut flowgraph::ControlFlowGraph, &dyn TargetIsa) -> bool;
 
 /// This struct provides information that a frontend may need to know about a target to
 /// produce Cranelift IR for the target.
 #[derive(Clone, Copy)]
 pub struct TargetFrontendConfig {
     /// The default calling convention of the target.
     pub default_call_conv: CallConv,
 
@@ -362,14 +362,14 @@ pub trait TargetIsa: fmt::Display + Sync
     /// This function is under the "testing_hooks" feature, and is only suitable for use by
     /// test harnesses. It increases code size, and is inefficient.
     #[cfg(feature = "testing_hooks")]
     fn emit_inst(
         &self,
         func: &ir::Function,
         inst: ir::Inst,
         divert: &mut regalloc::RegDiversions,
-        sink: &mut binemit::CodeSink,
+        sink: &mut dyn binemit::CodeSink,
     );
 
     /// Emit a whole function into memory.
     fn emit_function_to_memory(&self, func: &ir::Function, sink: &mut binemit::MemoryCodeSink);
 }
--- a/third_party/rust/cranelift-codegen/src/isa/riscv/mod.rs
+++ b/third_party/rust/cranelift-codegen/src/isa/riscv/mod.rs
@@ -35,17 +35,17 @@ pub fn isa_builder(triple: Triple) -> Is
         constructor: isa_constructor,
     }
 }
 
 fn isa_constructor(
     triple: Triple,
     shared_flags: shared_settings::Flags,
     builder: shared_settings::Builder,
-) -> Box<TargetIsa> {
+) -> Box<dyn TargetIsa> {
     let level1 = match triple.pointer_width().unwrap() {
         PointerWidth::U16 => panic!("16-bit RISC-V unrecognized"),
         PointerWidth::U32 => &enc_tables::LEVEL1_RV32[..],
         PointerWidth::U64 => &enc_tables::LEVEL1_RV64[..],
     };
     Box::new(Isa {
         triple,
         isa_flags: settings::Flags::new(&shared_flags, builder),
@@ -108,17 +108,17 @@ impl TargetIsa for Isa {
     }
 
     #[cfg(feature = "testing_hooks")]
     fn emit_inst(
         &self,
         func: &ir::Function,
         inst: ir::Inst,
         divert: &mut regalloc::RegDiversions,
-        sink: &mut CodeSink,
+        sink: &mut dyn CodeSink,
     ) {
         binemit::emit_inst(func, inst, divert, sink)
     }
 
     fn emit_function_to_memory(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
         emit_function(func, binemit::emit_inst, sink)
     }
 }
@@ -128,17 +128,17 @@ mod tests {
     use crate::ir::{immediates, types};
     use crate::ir::{Function, InstructionData, Opcode};
     use crate::isa;
     use crate::settings::{self, Configurable};
     use core::str::FromStr;
     use std::string::{String, ToString};
     use target_lexicon::triple;
 
-    fn encstr(isa: &isa::TargetIsa, enc: Result<isa::Encoding, isa::Legalize>) -> String {
+    fn encstr(isa: &dyn isa::TargetIsa, enc: Result<isa::Encoding, isa::Legalize>) -> String {
         match enc {
             Ok(e) => isa.encoding_info().display(e).to_string(),
             Err(_) => "no encoding".to_string(),
         }
     }
 
     #[test]
     fn test_64bitenc() {
--- a/third_party/rust/cranelift-codegen/src/isa/x86/abi.rs
+++ b/third_party/rust/cranelift-codegen/src/isa/x86/abi.rs
@@ -194,17 +194,17 @@ pub fn allocatable_registers(_func: &ir:
             regs.take(FPR, FPR.unit(i));
         }
     }
 
     regs
 }
 
 /// Get the set of callee-saved registers.
-fn callee_saved_gprs(isa: &TargetIsa, call_conv: CallConv) -> &'static [RU] {
+fn callee_saved_gprs(isa: &dyn TargetIsa, call_conv: CallConv) -> &'static [RU] {
     match isa.triple().pointer_width().unwrap() {
         PointerWidth::U16 => panic!(),
         PointerWidth::U32 => &[RU::rbx, RU::rsi, RU::rdi],
         PointerWidth::U64 => {
             if call_conv == CallConv::WindowsFastcall {
                 // "registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15 are considered nonvolatile
                 //  and must be saved and restored by a function that uses them."
                 // as per https://msdn.microsoft.com/en-us/library/6t169e9c.aspx
@@ -222,17 +222,17 @@ fn callee_saved_gprs(isa: &TargetIsa, ca
             } else {
                 &[RU::rbx, RU::r12, RU::r13, RU::r14, RU::r15]
             }
         }
     }
 }
 
 /// Get the set of callee-saved registers that are used.
-fn callee_saved_gprs_used(isa: &TargetIsa, func: &ir::Function) -> RegisterSet {
+fn callee_saved_gprs_used(isa: &dyn TargetIsa, func: &ir::Function) -> RegisterSet {
     let mut all_callee_saved = RegisterSet::empty();
     for reg in callee_saved_gprs(isa, func.signature.call_conv) {
         all_callee_saved.free(GPR, *reg as RegUnit);
     }
 
     let mut used = RegisterSet::empty();
     for value_loc in func.locations.values() {
         // Note that `value_loc` here contains only a single unit of a potentially multi-unit
@@ -264,29 +264,29 @@ fn callee_saved_gprs_used(isa: &TargetIs
             }
         }
     }
 
     used.intersect(&all_callee_saved);
     used
 }
 
-pub fn prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> CodegenResult<()> {
+pub fn prologue_epilogue(func: &mut ir::Function, isa: &dyn TargetIsa) -> CodegenResult<()> {
     match func.signature.call_conv {
         // For now, just translate fast and cold as system_v.
         CallConv::Fast | CallConv::Cold | CallConv::SystemV => {
             system_v_prologue_epilogue(func, isa)
         }
         CallConv::WindowsFastcall => fastcall_prologue_epilogue(func, isa),
         CallConv::Baldrdash => baldrdash_prologue_epilogue(func, isa),
         CallConv::Probestack => unimplemented!("probestack calling convention"),
     }
 }
 
-fn baldrdash_prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> CodegenResult<()> {
+fn baldrdash_prologue_epilogue(func: &mut ir::Function, isa: &dyn TargetIsa) -> CodegenResult<()> {
     debug_assert!(
         !isa.flags().probestack_enabled(),
         "baldrdash does not expect cranelift to emit stack probes"
     );
 
     // Baldrdash on 32-bit x86 always aligns its stack pointer to 16 bytes.
     let stack_align = 16;
     let word_size = StackSize::from(isa.pointer_bytes());
@@ -297,17 +297,17 @@ fn baldrdash_prologue_epilogue(func: &mu
     func.stack_slots.push(ss);
 
     layout_stack(&mut func.stack_slots, stack_align)?;
     Ok(())
 }
 
 /// Implementation of the fastcall-based Win64 calling convention described at [1]
 /// [1] https://msdn.microsoft.com/en-us/library/ms235286.aspx
-fn fastcall_prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> CodegenResult<()> {
+fn fastcall_prologue_epilogue(func: &mut ir::Function, isa: &dyn TargetIsa) -> CodegenResult<()> {
     if isa.triple().pointer_width().unwrap() != PointerWidth::U64 {
         panic!("TODO: windows-fastcall: x86-32 not implemented yet");
     }
 
     // [1] "The primary exceptions are the stack pointer and malloc or alloca memory,
     // which are aligned to 16 bytes in order to aid performance"
     let stack_align = 16;
 
@@ -369,17 +369,17 @@ fn fastcall_prologue_epilogue(func: &mut
     // Reset the cursor and insert the epilogue
     let mut pos = pos.at_position(CursorPosition::Nowhere);
     insert_common_epilogues(&mut pos, local_stack_size, reg_type, &csrs);
 
     Ok(())
 }
 
 /// Insert a System V-compatible prologue and epilogue.
-fn system_v_prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> CodegenResult<()> {
+fn system_v_prologue_epilogue(func: &mut ir::Function, isa: &dyn TargetIsa) -> CodegenResult<()> {
     // The original 32-bit x86 ELF ABI had a 4-byte aligned stack pointer, but
     // newer versions use a 16-byte aligned stack pointer.
     let stack_align = 16;
     let pointer_width = isa.triple().pointer_width().unwrap();
     let word_size = pointer_width.bytes() as usize;
     let reg_type = ir::Type::int(u16::from(pointer_width.bits())).unwrap();
 
     let csrs = callee_saved_gprs_used(isa, func);
@@ -430,17 +430,17 @@ fn system_v_prologue_epilogue(func: &mut
 
 /// Insert the prologue for a given function.
 /// This is used by common calling conventions such as System V.
 fn insert_common_prologue(
     pos: &mut EncCursor,
     stack_size: i64,
     reg_type: ir::types::Type,
     csrs: &RegisterSet,
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
 ) {
     if stack_size > 0 {
         // Check if there is a special stack limit parameter. If so insert stack check.
         if let Some(stack_limit_arg) = pos.func.special_param(ArgumentPurpose::StackLimit) {
             // Total stack size is the size of all stack area used by the function, including
             // pushed CSRs, frame pointer.
             // Also, the size of a return address, implicitly pushed by a x86 `call` instruction,
             // also should be accounted for.
--- a/third_party/rust/cranelift-codegen/src/isa/x86/enc_tables.rs
+++ b/third_party/rust/cranelift-codegen/src/isa/x86/enc_tables.rs
@@ -110,17 +110,17 @@ fn maybe_iconst_imm(pos: &FuncCursor, va
     }
 }
 
 /// Expand the `sdiv` and `srem` instructions using `x86_sdivmodx`.
 fn expand_sdivrem(
     inst: ir::Inst,
     func: &mut ir::Function,
     cfg: &mut ControlFlowGraph,
-    isa: &isa::TargetIsa,
+    isa: &dyn isa::TargetIsa,
 ) {
     let (x, y, is_srem) = match func.dfg[inst] {
         ir::InstructionData::Binary {
             opcode: ir::Opcode::Sdiv,
             args,
         } => (args[0], args[1], false),
         ir::InstructionData::Binary {
             opcode: ir::Opcode::Srem,
@@ -220,17 +220,17 @@ fn expand_sdivrem(
     cfg.recompute_ebb(pos.func, done);
 }
 
 /// Expand the `udiv` and `urem` instructions using `x86_udivmodx`.
 fn expand_udivrem(
     inst: ir::Inst,
     func: &mut ir::Function,
     _cfg: &mut ControlFlowGraph,
-    isa: &isa::TargetIsa,
+    isa: &dyn isa::TargetIsa,
 ) {
     let (x, y, is_urem) = match func.dfg[inst] {
         ir::InstructionData::Binary {
             opcode: ir::Opcode::Udiv,
             args,
         } => (args[0], args[1], false),
         ir::InstructionData::Binary {
             opcode: ir::Opcode::Urem,
@@ -273,17 +273,17 @@ fn expand_udivrem(
 }
 
 /// Expand the `fmin` and `fmax` instructions using the x86 `x86_fmin` and `x86_fmax`
 /// instructions.
 fn expand_minmax(
     inst: ir::Inst,
     func: &mut ir::Function,
     cfg: &mut ControlFlowGraph,
-    _isa: &isa::TargetIsa,
+    _isa: &dyn isa::TargetIsa,
 ) {
     let (x, y, x86_opc, bitwise_opc) = match func.dfg[inst] {
         ir::InstructionData::Binary {
             opcode: ir::Opcode::Fmin,
             args,
         } => (args[0], args[1], ir::Opcode::X86Fmin, ir::Opcode::Bor),
         ir::InstructionData::Binary {
             opcode: ir::Opcode::Fmax,
@@ -365,17 +365,17 @@ fn expand_minmax(
 }
 
 /// x86 has no unsigned-to-float conversions. We handle the easy case of zero-extending i32 to
 /// i64 with a pattern, the rest needs more code.
 fn expand_fcvt_from_uint(
     inst: ir::Inst,
     func: &mut ir::Function,
     cfg: &mut ControlFlowGraph,
-    _isa: &isa::TargetIsa,
+    _isa: &dyn isa::TargetIsa,
 ) {
     let x;
     match func.dfg[inst] {
         ir::InstructionData::Unary {
             opcode: ir::Opcode::FcvtFromUint,
             arg,
         } => x = arg,
         _ => panic!("Need fcvt_from_uint: {}", func.dfg.display_inst(inst, None)),
@@ -436,17 +436,17 @@ fn expand_fcvt_from_uint(
     cfg.recompute_ebb(pos.func, neg_ebb);
     cfg.recompute_ebb(pos.func, done);
 }
 
 fn expand_fcvt_to_sint(
     inst: ir::Inst,
     func: &mut ir::Function,
     cfg: &mut ControlFlowGraph,
-    _isa: &isa::TargetIsa,
+    _isa: &dyn isa::TargetIsa,
 ) {
     use crate::ir::immediates::{Ieee32, Ieee64};
 
     let x = match func.dfg[inst] {
         ir::InstructionData::Unary {
             opcode: ir::Opcode::FcvtToSint,
             arg,
         } => arg,
@@ -531,17 +531,17 @@ fn expand_fcvt_to_sint(
     cfg.recompute_ebb(pos.func, old_ebb);
     cfg.recompute_ebb(pos.func, done);
 }
 
 fn expand_fcvt_to_sint_sat(
     inst: ir::Inst,
     func: &mut ir::Function,
     cfg: &mut ControlFlowGraph,
-    _isa: &isa::TargetIsa,
+    _isa: &dyn isa::TargetIsa,
 ) {
     use crate::ir::immediates::{Ieee32, Ieee64};
 
     let x = match func.dfg[inst] {
         ir::InstructionData::Unary {
             opcode: ir::Opcode::FcvtToSintSat,
             arg,
         } => arg,
@@ -650,17 +650,17 @@ fn expand_fcvt_to_sint_sat(
     cfg.recompute_ebb(pos.func, old_ebb);
     cfg.recompute_ebb(pos.func, done_ebb);
 }
 
 fn expand_fcvt_to_uint(
     inst: ir::Inst,
     func: &mut ir::Function,
     cfg: &mut ControlFlowGraph,
-    _isa: &isa::TargetIsa,
+    _isa: &dyn isa::TargetIsa,
 ) {
     use crate::ir::immediates::{Ieee32, Ieee64};
 
     let x = match func.dfg[inst] {
         ir::InstructionData::Unary {
             opcode: ir::Opcode::FcvtToUint,
             arg,
         } => arg,
@@ -731,17 +731,17 @@ fn expand_fcvt_to_uint(
     cfg.recompute_ebb(pos.func, large);
     cfg.recompute_ebb(pos.func, done);
 }
 
 fn expand_fcvt_to_uint_sat(
     inst: ir::Inst,
     func: &mut ir::Function,
     cfg: &mut ControlFlowGraph,
-    _isa: &isa::TargetIsa,
+    _isa: &dyn isa::TargetIsa,
 ) {
     use crate::ir::immediates::{Ieee32, Ieee64};
 
     let x = match func.dfg[inst] {
         ir::InstructionData::Unary {
             opcode: ir::Opcode::FcvtToUintSat,
             arg,
         } => arg,
--- a/third_party/rust/cranelift-codegen/src/isa/x86/mod.rs
+++ b/third_party/rust/cranelift-codegen/src/isa/x86/mod.rs
@@ -37,17 +37,17 @@ pub fn isa_builder(triple: Triple) -> Is
         constructor: isa_constructor,
     }
 }
 
 fn isa_constructor(
     triple: Triple,
     shared_flags: shared_settings::Flags,
     builder: shared_settings::Builder,
-) -> Box<TargetIsa> {
+) -> Box<dyn TargetIsa> {
     let level1 = match triple.pointer_width().unwrap() {
         PointerWidth::U16 => unimplemented!("x86-16"),
         PointerWidth::U32 => &enc_tables::LEVEL1_I32[..],
         PointerWidth::U64 => &enc_tables::LEVEL1_I64[..],
     };
     Box::new(Isa {
         triple,
         isa_flags: settings::Flags::new(&shared_flags, builder),
@@ -118,17 +118,17 @@ impl TargetIsa for Isa {
     }
 
     #[cfg(feature = "testing_hooks")]
     fn emit_inst(
         &self,
         func: &ir::Function,
         inst: ir::Inst,
         divert: &mut regalloc::RegDiversions,
-        sink: &mut CodeSink,
+        sink: &mut dyn CodeSink,
     ) {
         binemit::emit_inst(func, inst, divert, sink)
     }
 
     fn emit_function_to_memory(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
         emit_function(func, binemit::emit_inst, sink)
     }
 
--- a/third_party/rust/cranelift-codegen/src/legalizer/boundary.rs
+++ b/third_party/rust/cranelift-codegen/src/legalizer/boundary.rs
@@ -30,38 +30,38 @@ use crate::legalizer::split::{isplit, vs
 use log::debug;
 use std::vec::Vec;
 
 /// Legalize all the function signatures in `func`.
 ///
 /// This changes all signatures to be ABI-compliant with full `ArgumentLoc` annotations. It doesn't
 /// change the entry block arguments, calls, or return instructions, so this can leave the function
 /// in a state with type discrepancies.
-pub fn legalize_signatures(func: &mut Function, isa: &TargetIsa) {
+pub fn legalize_signatures(func: &mut Function, isa: &dyn TargetIsa) {
     legalize_signature(&mut func.signature, true, isa);
     for sig_data in func.dfg.signatures.values_mut() {
         legalize_signature(sig_data, false, isa);
     }
 
     if let Some(entry) = func.layout.entry_block() {
         legalize_entry_params(func, entry);
         spill_entry_params(func, entry);
     }
 }
 
 /// Legalize the libcall signature, which we may generate on the fly after
 /// `legalize_signatures` has been called.
-pub fn legalize_libcall_signature(signature: &mut Signature, isa: &TargetIsa) {
+pub fn legalize_libcall_signature(signature: &mut Signature, isa: &dyn TargetIsa) {
     legalize_signature(signature, false, isa);
 }
 
 /// Legalize the given signature.
 ///
 /// `current` is true if this is the signature for the current function.
-fn legalize_signature(signature: &mut Signature, current: bool, isa: &TargetIsa) {
+fn legalize_signature(signature: &mut Signature, current: bool, isa: &dyn TargetIsa) {
     isa.legalize_signature(signature, current);
 }
 
 /// Legalize the entry block parameters after `func`'s signature has been legalized.
 ///
 /// The legalized signature may contain more parameters than the original signature, and the
 /// parameter types have been changed. This function goes through the parameters of the entry EBB
 /// and replaces them with parameters of the right type for the ABI.
--- a/third_party/rust/cranelift-codegen/src/legalizer/call.rs
+++ b/third_party/rust/cranelift-codegen/src/legalizer/call.rs
@@ -9,17 +9,17 @@ use crate::ir::{self, InstBuilder};
 use crate::isa::TargetIsa;
 
 /// Expand a `call` instruction. This lowers it to a `call_indirect`, which
 /// is only done if the ABI doesn't support direct calls.
 pub fn expand_call(
     inst: ir::Inst,
     func: &mut ir::Function,
     _cfg: &mut ControlFlowGraph,
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
 ) {
     // Unpack the instruction.
     let (func_ref, old_args) = match func.dfg[inst] {
         ir::InstructionData::Call {
             opcode,
             ref args,
             func_ref,
         } => {
--- a/third_party/rust/cranelift-codegen/src/legalizer/globalvalue.rs
+++ b/third_party/rust/cranelift-codegen/src/legalizer/globalvalue.rs
@@ -8,17 +8,17 @@ use crate::flowgraph::ControlFlowGraph;
 use crate::ir::{self, InstBuilder};
 use crate::isa::TargetIsa;
 
 /// Expand a `global_value` instruction according to the definition of the global value.
 pub fn expand_global_value(
     inst: ir::Inst,
     func: &mut ir::Function,
     _cfg: &mut ControlFlowGraph,
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
 ) {
     // Unpack the instruction.
     let gv = match func.dfg[inst] {
         ir::InstructionData::UnaryGlobalValue {
             opcode,
             global_value,
         } => {
             debug_assert_eq!(opcode, ir::Opcode::GlobalValue);
@@ -85,17 +85,17 @@ fn iadd_imm_addr(
 /// Expand a `global_value` instruction for a load global.
 fn load_addr(
     inst: ir::Inst,
     func: &mut ir::Function,
     base: ir::GlobalValue,
     offset: ir::immediates::Offset32,
     global_type: ir::Type,
     readonly: bool,
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
 ) {
     // We need to load a pointer from the `base` global value, so insert a new `global_value`
     // instruction. This depends on the iterative legalization loop. Note that the IR verifier
     // detects any cycles in the `load` globals.
     let ptr_ty = isa.pointer_type();
     let mut pos = FuncCursor::new(func).at_inst(inst);
     pos.use_srcloc(inst);
 
@@ -118,12 +118,12 @@ fn load_addr(
     // Perform the load.
     pos.func
         .dfg
         .replace(inst)
         .load(global_type, mflags, base_addr, offset);
 }
 
 /// Expand a `global_value` instruction for a symbolic name global.
-fn symbol(inst: ir::Inst, func: &mut ir::Function, gv: ir::GlobalValue, isa: &TargetIsa) {
+fn symbol(inst: ir::Inst, func: &mut ir::Function, gv: ir::GlobalValue, isa: &dyn TargetIsa) {
     let ptr_ty = isa.pointer_type();
     func.dfg.replace(inst).symbol_value(ptr_ty, gv);
 }
--- a/third_party/rust/cranelift-codegen/src/legalizer/heap.rs
+++ b/third_party/rust/cranelift-codegen/src/legalizer/heap.rs
@@ -9,17 +9,17 @@ use crate::ir::condcodes::IntCC;
 use crate::ir::{self, InstBuilder};
 use crate::isa::TargetIsa;
 
 /// Expand a `heap_addr` instruction according to the definition of the heap.
 pub fn expand_heap_addr(
     inst: ir::Inst,
     func: &mut ir::Function,
     cfg: &mut ControlFlowGraph,
-    _isa: &TargetIsa,
+    _isa: &dyn TargetIsa,
 ) {
     // Unpack the instruction.
     let (heap, offset, access_size) = match func.dfg[inst] {
         ir::InstructionData::HeapAddr {
             opcode,
             heap,
             arg,
             imm,
--- a/third_party/rust/cranelift-codegen/src/legalizer/libcall.rs
+++ b/third_party/rust/cranelift-codegen/src/legalizer/libcall.rs
@@ -2,17 +2,17 @@
 
 use crate::ir;
 use crate::ir::{get_libcall_funcref, InstBuilder};
 use crate::isa::TargetIsa;
 use crate::legalizer::boundary::legalize_libcall_signature;
 use std::vec::Vec;
 
 /// Try to expand `inst` as a library call, returning true is successful.
-pub fn expand_as_libcall(inst: ir::Inst, func: &mut ir::Function, isa: &TargetIsa) -> bool {
+pub fn expand_as_libcall(inst: ir::Inst, func: &mut ir::Function, isa: &dyn TargetIsa) -> bool {
     // Does the opcode/ctrl_type combo even have a well-known runtime library name.
     let libcall = match ir::LibCall::for_inst(func.dfg[inst].opcode(), func.dfg.ctrl_typevar(inst))
     {
         Some(lc) => lc,
         None => return false,
     };
 
     // Now we convert `inst` to a call. First save the arguments.
--- a/third_party/rust/cranelift-codegen/src/legalizer/mod.rs
+++ b/third_party/rust/cranelift-codegen/src/legalizer/mod.rs
@@ -36,17 +36,17 @@ use self::libcall::expand_as_libcall;
 use self::table::expand_table_addr;
 
 /// Legalize `inst` for `isa`. Return true if any changes to the code were
 /// made; return false if the instruction was successfully encoded as is.
 fn legalize_inst(
     inst: ir::Inst,
     pos: &mut FuncCursor,
     cfg: &mut ControlFlowGraph,
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
 ) -> bool {
     let opcode = pos.func.dfg[inst].opcode();
 
     // Check for ABI boundaries that need to be converted to the legalized signature.
     if opcode.is_call() {
         if boundary::handle_call_abi(inst, pos.func, cfg) {
             return true;
         }
@@ -78,17 +78,17 @@ fn legalize_inst(
     }
 }
 
 /// Legalize `func` for `isa`.
 ///
 /// - Transform any instructions that don't have a legal representation in `isa`.
 /// - Fill out `func.encodings`.
 ///
-pub fn legalize_function(func: &mut ir::Function, cfg: &mut ControlFlowGraph, isa: &TargetIsa) {
+pub fn legalize_function(func: &mut ir::Function, cfg: &mut ControlFlowGraph, isa: &dyn TargetIsa) {
     let _tt = timing::legalize();
     debug_assert!(cfg.is_valid());
 
     boundary::legalize_signatures(func, isa);
 
     func.encodings.resize(func.dfg.num_insts());
 
     let mut pos = FuncCursor::new(func);
@@ -124,17 +124,17 @@ pub fn legalize_function(func: &mut ir::
 include!(concat!(env!("OUT_DIR"), "/legalizer.rs"));
 
 /// Custom expansion for conditional trap instructions.
 /// TODO: Add CFG support to the Python patterns so we won't have to do this.
 fn expand_cond_trap(
     inst: ir::Inst,
     func: &mut ir::Function,
     cfg: &mut ControlFlowGraph,
-    _isa: &TargetIsa,
+    _isa: &dyn TargetIsa,
 ) {
     // Parse the instruction.
     let trapz;
     let (arg, code) = match func.dfg[inst] {
         ir::InstructionData::CondTrap { opcode, arg, code } => {
             // We want to branch *over* an unconditional trap.
             trapz = match opcode {
                 ir::Opcode::Trapz => true,
@@ -174,31 +174,31 @@ fn expand_cond_trap(
     cfg.recompute_ebb(pos.func, new_ebb);
 }
 
 /// Jump tables.
 fn expand_br_table(
     inst: ir::Inst,
     func: &mut ir::Function,
     cfg: &mut ControlFlowGraph,
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
 ) {
     if isa.flags().jump_tables_enabled() {
         expand_br_table_jt(inst, func, cfg, isa);
     } else {
         expand_br_table_conds(inst, func, cfg, isa);
     }
 }
 
 /// Expand br_table to jump table.
 fn expand_br_table_jt(
     inst: ir::Inst,
     func: &mut ir::Function,
     cfg: &mut ControlFlowGraph,
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
 ) {
     use crate::ir::condcodes::IntCC;
 
     let (arg, default_ebb, table) = match func.dfg[inst] {
         ir::InstructionData::BranchTable {
             opcode: ir::Opcode::BrTable,
             arg,
             destination,
@@ -234,17 +234,17 @@ fn expand_br_table_jt(
     cfg.recompute_ebb(pos.func, ebb);
 }
 
 /// Expand br_table to series of conditionals.
 fn expand_br_table_conds(
     inst: ir::Inst,
     func: &mut ir::Function,
     cfg: &mut ControlFlowGraph,
-    _isa: &TargetIsa,
+    _isa: &dyn TargetIsa,
 ) {
     use crate::ir::condcodes::IntCC;
 
     let (arg, default_ebb, table) = match func.dfg[inst] {
         ir::InstructionData::BranchTable {
             opcode: ir::Opcode::BrTable,
             arg,
             destination,
@@ -275,17 +275,17 @@ fn expand_br_table_conds(
 /// Expand the select instruction.
 ///
 /// Conditional moves are available in some ISAs for some register classes. The remaining selects
 /// are handled by a branch.
 fn expand_select(
     inst: ir::Inst,
     func: &mut ir::Function,
     cfg: &mut ControlFlowGraph,
-    _isa: &TargetIsa,
+    _isa: &dyn TargetIsa,
 ) {
     let (ctrl, tval, fval) = match func.dfg[inst] {
         ir::InstructionData::Ternary {
             opcode: ir::Opcode::Select,
             args,
         } => (args[0], args[1], args[2]),
         _ => panic!("Expected select: {}", func.dfg.display_inst(inst, None)),
     };
@@ -310,17 +310,17 @@ fn expand_select(
     cfg.recompute_ebb(pos.func, new_ebb);
     cfg.recompute_ebb(pos.func, old_ebb);
 }
 
 fn expand_br_icmp(
     inst: ir::Inst,
     func: &mut ir::Function,
     cfg: &mut ControlFlowGraph,
-    _isa: &TargetIsa,
+    _isa: &dyn TargetIsa,
 ) {
     let (cond, a, b, destination, ebb_args) = match func.dfg[inst] {
         ir::InstructionData::BranchIcmp {
             cond,
             destination,
             ref args,
             ..
         } => (
@@ -345,17 +345,17 @@ fn expand_br_icmp(
     cfg.recompute_ebb(pos.func, old_ebb);
 }
 
 /// Expand illegal `f32const` and `f64const` instructions.
 fn expand_fconst(
     inst: ir::Inst,
     func: &mut ir::Function,
     _cfg: &mut ControlFlowGraph,
-    _isa: &TargetIsa,
+    _isa: &dyn TargetIsa,
 ) {
     let ty = func.dfg.value_type(func.dfg.first_result(inst));
     debug_assert!(!ty.is_vector(), "Only scalar fconst supported: {}", ty);
 
     // In the future, we may want to generate constant pool entries for these constants, but for
     // now use an `iconst` and a bit cast.
     let mut pos = FuncCursor::new(func).at_inst(inst);
     pos.use_srcloc(inst);
@@ -373,17 +373,17 @@ fn expand_fconst(
     pos.func.dfg.replace(inst).bitcast(ty, ival);
 }
 
 /// Expand illegal `stack_load` instructions.
 fn expand_stack_load(
     inst: ir::Inst,
     func: &mut ir::Function,
     _cfg: &mut ControlFlowGraph,
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
 ) {
     let ty = func.dfg.value_type(func.dfg.first_result(inst));
     let addr_ty = isa.pointer_type();
 
     let mut pos = FuncCursor::new(func).at_inst(inst);
     pos.use_srcloc(inst);
 
     let (stack_slot, offset) = match pos.func.dfg[inst] {
@@ -405,17 +405,17 @@ fn expand_stack_load(
     pos.func.dfg.replace(inst).load(ty, mflags, addr, 0);
 }
 
 /// Expand illegal `stack_store` instructions.
 fn expand_stack_store(
     inst: ir::Inst,
     func: &mut ir::Function,
     _cfg: &mut ControlFlowGraph,
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
 ) {
     let addr_ty = isa.pointer_type();
 
     let mut pos = FuncCursor::new(func).at_inst(inst);
     pos.use_srcloc(inst);
 
     let (val, stack_slot, offset) = match pos.func.dfg[inst] {
         ir::InstructionData::StackStore {
--- a/third_party/rust/cranelift-codegen/src/legalizer/table.rs
+++ b/third_party/rust/cranelift-codegen/src/legalizer/table.rs
@@ -10,17 +10,17 @@ use crate::ir::immediates::Offset32;
 use crate::ir::{self, InstBuilder};
 use crate::isa::TargetIsa;
 
 /// Expand a `table_addr` instruction according to the definition of the table.
 pub fn expand_table_addr(
     inst: ir::Inst,
     func: &mut ir::Function,
     _cfg: &mut ControlFlowGraph,
-    _isa: &TargetIsa,
+    _isa: &dyn TargetIsa,
 ) {
     // Unpack the instruction.
     let (table, index, element_offset) = match func.dfg[inst] {
         ir::InstructionData::TableAddr {
             opcode,
             table,
             arg,
             offset,
--- a/third_party/rust/cranelift-codegen/src/licm.rs
+++ b/third_party/rust/cranelift-codegen/src/licm.rs
@@ -12,17 +12,17 @@ use crate::isa::TargetIsa;
 use crate::loop_analysis::{Loop, LoopAnalysis};
 use crate::timing;
 use std::vec::Vec;
 
 /// Performs the LICM pass by detecting loops within the CFG and moving
 /// loop-invariant instructions out of them.
 /// Changes the CFG and domtree in-place during the operation.
 pub fn do_licm(
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
     func: &mut Function,
     cfg: &mut ControlFlowGraph,
     domtree: &mut DominatorTree,
     loop_analysis: &mut LoopAnalysis,
 ) {
     let _tt = timing::licm();
     debug_assert!(cfg.is_valid());
     debug_assert!(domtree.is_valid());
@@ -59,17 +59,17 @@ pub fn do_licm(
     // We have to recompute the domtree to account for the changes
     cfg.compute(func);
     domtree.compute(func, cfg);
 }
 
 // Insert a pre-header before the header, modifying the function layout and CFG to reflect it.
 // A jump instruction to the header is placed at the end of the pre-header.
 fn create_pre_header(
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
     header: Ebb,
     func: &mut Function,
     cfg: &mut ControlFlowGraph,
     domtree: &DominatorTree,
 ) -> Ebb {
     let pool = &mut ListPool::<Value>::new();
     let header_args_values: Vec<Value> = func.dfg.ebb_params(header).into_iter().cloned().collect();
     let header_args_types: Vec<Type> = header_args_values
--- a/third_party/rust/cranelift-codegen/src/postopt.rs
+++ b/third_party/rust/cranelift-codegen/src/postopt.rs
@@ -40,17 +40,17 @@ enum CmpBrKind {
 /// in integer registers.
 ///
 /// For example, optimize icmp/fcmp brz/brnz sequences into ifcmp/ffcmp brif/brff
 /// sequences.
 fn optimize_cpu_flags(
     pos: &mut EncCursor,
     inst: Inst,
     last_flags_clobber: Option<Inst>,
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
 ) {
     // Look for compare and branch patterns.
     // This code could be considerably simplified with non-lexical lifetimes.
     let info = match pos.func.dfg[inst] {
         InstructionData::Branch {
             opcode,
             destination,
             ref args,
@@ -174,17 +174,17 @@ struct MemOpInfo {
     opcode: Opcode,
     itype: Type,
     arg: Value,
     st_arg: Option<Value>,
     flags: MemFlags,
     offset: Offset32,
 }
 
-fn optimize_complex_addresses(pos: &mut EncCursor, inst: Inst, isa: &TargetIsa) {
+fn optimize_complex_addresses(pos: &mut EncCursor, inst: Inst, isa: &dyn TargetIsa) {
     // Look for simple loads and stores we can optimize.
     let info = match pos.func.dfg[inst] {
         InstructionData::Load {
             opcode,
             arg,
             flags,
             offset,
         } => MemOpInfo {
@@ -352,17 +352,17 @@ fn optimize_complex_addresses(pos: &mut 
     let ok = pos.func.update_encoding(inst, isa).is_ok();
     debug_assert!(ok);
 }
 
 //----------------------------------------------------------------------
 //
 // The main post-opt pass.
 
-pub fn do_postopt(func: &mut Function, isa: &TargetIsa) {
+pub fn do_postopt(func: &mut Function, isa: &dyn TargetIsa) {
     let _tt = timing::postopt();
     let mut pos = EncCursor::new(func, isa);
     while let Some(_ebb) = pos.next_ebb() {
         let mut last_flags_clobber = None;
         while let Some(inst) = pos.next_inst() {
             if isa.uses_cpu_flags() {
                 // Optimize instructions to make use of flags.
                 optimize_cpu_flags(&mut pos, inst, last_flags_clobber, isa);
--- a/third_party/rust/cranelift-codegen/src/print_errors.rs
+++ b/third_party/rust/cranelift-codegen/src/print_errors.rs
@@ -12,18 +12,18 @@ use core::fmt;
 use core::fmt::Write;
 use std::boxed::Box;
 use std::string::{String, ToString};
 use std::vec::Vec;
 
 /// Pretty-print a verifier error.
 pub fn pretty_verifier_error<'a>(
     func: &ir::Function,
-    isa: Option<&TargetIsa>,
-    func_w: Option<Box<FuncWriter + 'a>>,
+    isa: Option<&dyn TargetIsa>,
+    func_w: Option<Box<dyn FuncWriter + 'a>>,
     errors: VerifierErrors,
 ) -> String {
     let mut errors = errors.0;
     let mut w = String::new();
     let num_errors = errors.len();
 
     decorate_function(
         &mut PrettyVerifierError(func_w.unwrap_or_else(|| Box::new(PlainWriter)), &mut errors),
@@ -39,61 +39,61 @@ pub fn pretty_verifier_error<'a>(
         num_errors,
         if num_errors == 1 { "" } else { "s" }
     )
     .unwrap();
 
     w
 }
 
-struct PrettyVerifierError<'a>(Box<FuncWriter + 'a>, &'a mut Vec<VerifierError>);
+struct PrettyVerifierError<'a>(Box<dyn FuncWriter + 'a>, &'a mut Vec<VerifierError>);
 
 impl<'a> FuncWriter for PrettyVerifierError<'a> {
     fn write_ebb_header(
         &mut self,
-        w: &mut Write,
+        w: &mut dyn Write,
         func: &Function,
-        isa: Option<&TargetIsa>,
+        isa: Option<&dyn TargetIsa>,
         ebb: Ebb,
         indent: usize,
     ) -> fmt::Result {
         pretty_ebb_header_error(w, func, isa, ebb, indent, &mut *self.0, self.1)
     }
 
     fn write_instruction(
         &mut self,
-        w: &mut Write,
+        w: &mut dyn Write,
         func: &Function,
         aliases: &SecondaryMap<Value, Vec<Value>>,
-        isa: Option<&TargetIsa>,
+        isa: Option<&dyn TargetIsa>,
         inst: Inst,
         indent: usize,
     ) -> fmt::Result {
         pretty_instruction_error(w, func, aliases, isa, inst, indent, &mut *self.0, self.1)
     }
 
     fn write_entity_definition(
         &mut self,
-        w: &mut Write,
+        w: &mut dyn Write,
         func: &Function,
         entity: AnyEntity,
-        value: &fmt::Display,
+        value: &dyn fmt::Display,
     ) -> fmt::Result {
         pretty_preamble_error(w, func, entity, value, &mut *self.0, self.1)
     }
 }
 
 /// Pretty-print a function verifier error for a given EBB.
 fn pretty_ebb_header_error(
-    w: &mut Write,
+    w: &mut dyn Write,
     func: &Function,
-    isa: Option<&TargetIsa>,
+    isa: Option<&dyn TargetIsa>,
     cur_ebb: Ebb,
     indent: usize,
-    func_w: &mut FuncWriter,
+    func_w: &mut dyn FuncWriter,
     errors: &mut Vec<VerifierError>,
 ) -> fmt::Result {
     let mut s = String::new();
     func_w.write_ebb_header(&mut s, func, isa, cur_ebb, indent)?;
     write!(w, "{}", s)?;
 
     // TODO: Use drain_filter here when it gets stabilized
     let mut i = 0;
@@ -116,23 +116,23 @@ fn pretty_ebb_header_error(
         w.write_char('\n')?;
     }
 
     Ok(())
 }
 
 /// Pretty-print a function verifier error for a given instruction.
 fn pretty_instruction_error(
-    w: &mut Write,
+    w: &mut dyn Write,
     func: &Function,
     aliases: &SecondaryMap<Value, Vec<Value>>,
-    isa: Option<&TargetIsa>,
+    isa: Option<&dyn TargetIsa>,
     cur_inst: Inst,
     indent: usize,
-    func_w: &mut FuncWriter,
+    func_w: &mut dyn FuncWriter,
     errors: &mut Vec<VerifierError>,
 ) -> fmt::Result {
     let mut s = String::new();
     func_w.write_instruction(&mut s, func, aliases, isa, cur_inst, indent)?;
     write!(w, "{}", s)?;
 
     // TODO: Use drain_filter here when it gets stabilized
     let mut i = 0;
@@ -154,21 +154,21 @@ fn pretty_instruction_error(
     if printed_error {
         w.write_char('\n')?;
     }
 
     Ok(())
 }
 
 fn pretty_preamble_error(
-    w: &mut Write,
+    w: &mut dyn Write,
     func: &Function,
     entity: AnyEntity,
-    value: &fmt::Display,
-    func_w: &mut FuncWriter,
+    value: &dyn fmt::Display,
+    func_w: &mut dyn FuncWriter,
     errors: &mut Vec<VerifierError>,
 ) -> fmt::Result {
     let mut s = String::new();
     func_w.write_entity_definition(&mut s, func, entity, value)?;
     write!(w, "{}", s)?;
 
     // TODO: Use drain_filter here when it gets stabilized
     let mut i = 0;
@@ -190,38 +190,38 @@ fn pretty_preamble_error(
         w.write_char('\n')?;
     }
 
     Ok(())
 }
 
 /// Prints:
 ///    ;   ^~~~~~
-fn print_arrow(w: &mut Write, entity: &str) -> fmt::Result {
+fn print_arrow(w: &mut dyn Write, entity: &str) -> fmt::Result {
     write!(w, ";")?;
 
     let indent = entity.len() - entity.trim_start().len();
     if indent != 0 {
         write!(w, "{1:0$}^", indent - 1, "")?;
     }
 
     for _ in 0..entity.trim().len() - 1 {
         write!(w, "~")?;
     }
 
     writeln!(w)
 }
 
 /// Prints:
 ///    ; error: [ERROR BODY]
-fn print_error(w: &mut Write, err: VerifierError) -> fmt::Result {
+fn print_error(w: &mut dyn Write, err: VerifierError) -> fmt::Result {
     writeln!(w, "; error: {}", err.to_string())?;
     Ok(())
 }
 
 /// Pretty-print a Cranelift error.
-pub fn pretty_error(func: &ir::Function, isa: Option<&TargetIsa>, err: CodegenError) -> String {
+pub fn pretty_error(func: &ir::Function, isa: Option<&dyn TargetIsa>, err: CodegenError) -> String {
     if let CodegenError::Verifier(e) = err {
         pretty_verifier_error(func, isa, None, e)
     } else {
         err.to_string()
     }
 }
--- a/third_party/rust/cranelift-codegen/src/regalloc/affinity.rs
+++ b/third_party/rust/cranelift-codegen/src/regalloc/affinity.rs
@@ -43,17 +43,17 @@ impl Affinity {
         if constraint.kind == ConstraintKind::Stack {
             Affinity::Stack
         } else {
             Affinity::Reg(constraint.regclass.into())
         }
     }
 
     /// Create an affinity that matches an ABI argument for `isa`.
-    pub fn abi(arg: &AbiParam, isa: &TargetIsa) -> Self {
+    pub fn abi(arg: &AbiParam, isa: &dyn TargetIsa) -> Self {
         match arg.location {
             ArgumentLoc::Unassigned => Affinity::Unassigned,
             ArgumentLoc::Reg(_) => Affinity::Reg(isa.regclass_for_abi_type(arg.value_type).into()),
             ArgumentLoc::Stack(_) => Affinity::Stack,
         }
     }
 
     /// Is this the `Unassigned` affinity?
--- a/third_party/rust/cranelift-codegen/src/regalloc/coalescing.rs
+++ b/third_party/rust/cranelift-codegen/src/regalloc/coalescing.rs
@@ -61,17 +61,17 @@ pub struct Coalescing {
     vcopies: VirtualCopies,
     values: Vec<Value>,
     predecessors: Vec<Inst>,
     backedges: Vec<Inst>,
 }
 
 /// One-shot context created once per invocation.
 struct Context<'a> {
-    isa: &'a TargetIsa,
+    isa: &'a dyn TargetIsa,
     encinfo: EncInfo,
 
     func: &'a mut Function,
     cfg: &'a ControlFlowGraph,
     domtree: &'a DominatorTree,
     preorder: &'a DominatorTreePreorder,
     liveness: &'a mut Liveness,
     virtregs: &'a mut VirtRegs,
@@ -103,17 +103,17 @@ impl Coalescing {
         self.values.clear();
         self.predecessors.clear();
         self.backedges.clear();
     }
 
     /// Convert `func` to Conventional SSA form and build virtual registers in the process.
     pub fn conventional_ssa(
         &mut self,
-        isa: &TargetIsa,
+        isa: &dyn TargetIsa,
         func: &mut Function,
         cfg: &ControlFlowGraph,
         domtree: &DominatorTree,
         liveness: &mut Liveness,
         virtregs: &mut VirtRegs,
     ) {
         let _tt = timing::ra_cssa();
         debug!("Coalescing for:\n{}", func.display(isa));
--- a/third_party/rust/cranelift-codegen/src/regalloc/coloring.rs
+++ b/third_party/rust/cranelift-codegen/src/regalloc/coloring.rs
@@ -113,17 +113,17 @@ impl Coloring {
     pub fn clear(&mut self) {
         self.divert.clear();
         self.solver.clear();
     }
 
     /// Run the coloring algorithm over `func`.
     pub fn run(
         &mut self,
-        isa: &TargetIsa,
+        isa: &dyn TargetIsa,
         func: &mut Function,
         domtree: &DominatorTree,
         liveness: &mut Liveness,
         tracker: &mut LiveValueTracker,
     ) {
         let _tt = timing::ra_coloring();
         debug!("Coloring for:\n{}", func.display(isa));
         let mut ctx = Context {
--- a/third_party/rust/cranelift-codegen/src/regalloc/context.rs
+++ b/third_party/rust/cranelift-codegen/src/regalloc/context.rs
@@ -70,17 +70,17 @@ impl Context {
     }
 
     /// Allocate registers in `func`.
     ///
     /// After register allocation, all values in `func` have been assigned to a register or stack
     /// location that is consistent with instruction encoding constraints.
     pub fn run(
         &mut self,
-        isa: &TargetIsa,
+        isa: &dyn TargetIsa,
         func: &mut Function,
         cfg: &ControlFlowGraph,
         domtree: &mut DominatorTree,
     ) -> CodegenResult<()> {
         let _tt = timing::regalloc();
         debug_assert!(domtree.is_valid());
 
         let mut errors = VerifierErrors::default();
--- a/third_party/rust/cranelift-codegen/src/regalloc/liveness.rs
+++ b/third_party/rust/cranelift-codegen/src/regalloc/liveness.rs
@@ -190,17 +190,17 @@ use std::vec::Vec;
 /// A set of live ranges, indexed by value number.
 type LiveRangeSet = SparseMap<Value, LiveRange>;
 
 /// Get a mutable reference to the live range for `value`.
 /// Create it if necessary.
 fn get_or_create<'a>(
     lrset: &'a mut LiveRangeSet,
     value: Value,
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
     func: &Function,
     encinfo: &EncInfo,
 ) -> &'a mut LiveRange {
     // It would be better to use `get_mut()` here, but that leads to borrow checker fighting
     // which can probably only be resolved by non-lexical lifetimes.
     // https://github.com/rust-lang/rfcs/issues/811
     if lrset.get(value).is_none() {
         // Create a live range for value. We need the program point that defines it.
@@ -384,17 +384,17 @@ impl Liveness {
     /// Change the affinity of `value` to `Stack` and return the previous affinity.
     pub fn spill(&mut self, value: Value) -> Affinity {
         let lr = self.ranges.get_mut(value).expect("Value has no live range");
         mem::replace(&mut lr.affinity, Affinity::Stack)
     }
 
     /// Compute the live ranges of all SSA values used in `func`.
     /// This clears out any existing analysis stored in this data structure.
-    pub fn compute(&mut self, isa: &TargetIsa, func: &mut Function, cfg: &ControlFlowGraph) {
+    pub fn compute(&mut self, isa: &dyn TargetIsa, func: &mut Function, cfg: &ControlFlowGraph) {
         let _tt = timing::ra_liveness();
         self.ranges.clear();
 
         // Get ISA data structures used for computing live range affinities.
         let encinfo = isa.encoding_info();
         let reginfo = isa.register_info();
 
         // The liveness computation needs to visit all uses, but the order doesn't matter.
--- a/third_party/rust/cranelift-codegen/src/regalloc/pressure.rs
+++ b/third_party/rust/cranelift-codegen/src/regalloc/pressure.rs
@@ -276,30 +276,30 @@ mod tests {
     use crate::isa::{RegClass, TargetIsa};
     use crate::regalloc::RegisterSet;
     use core::borrow::Borrow;
     use core::str::FromStr;
     use std::boxed::Box;
     use target_lexicon::triple;
 
     // Make an arm32 `TargetIsa`, if possible.
-    fn arm32() -> Option<Box<TargetIsa>> {
+    fn arm32() -> Option<Box<dyn TargetIsa>> {
         use crate::isa;
         use crate::settings;
 
         let shared_builder = settings::builder();
         let shared_flags = settings::Flags::new(shared_builder);
 
         isa::lookup(triple!("arm"))
             .ok()
             .map(|b| b.finish(shared_flags))
     }
 
     // Get a register class by name.
-    fn rc_by_name(isa: &TargetIsa, name: &str) -> RegClass {
+    fn rc_by_name(isa: &dyn TargetIsa, name: &str) -> RegClass {
         isa.register_info()
             .classes
             .iter()
             .find(|rc| rc.name == name)
             .expect("Can't find named register class.")
     }
 
     #[test]
--- a/third_party/rust/cranelift-codegen/src/regalloc/reload.rs
+++ b/third_party/rust/cranelift-codegen/src/regalloc/reload.rs
@@ -60,17 +60,17 @@ impl Reload {
     pub fn clear(&mut self) {
         self.candidates.clear();
         self.reloads.clear();
     }
 
     /// Run the reload algorithm over `func`.
     pub fn run(
         &mut self,
-        isa: &TargetIsa,
+        isa: &dyn TargetIsa,
         func: &mut Function,
         domtree: &DominatorTree,
         liveness: &mut Liveness,
         topo: &mut TopoOrder,
         tracker: &mut LiveValueTracker,
     ) {
         let _tt = timing::ra_reload();
         debug!("Reload for:\n{}", func.display(isa));
@@ -217,28 +217,39 @@ impl<'a> Context<'a> {
         // has a zero-length encoding, so will disappear at emission time.
         if let InstructionData::Unary {
             opcode: Opcode::Copy,
             arg,
         } = self.cur.func.dfg[inst]
         {
             let dst_vals = self.cur.func.dfg.inst_results(inst);
             if dst_vals.len() == 1 {
+                let dst_val = dst_vals[0];
                 let can_transform = match (
                     self.cur.func.locations[arg],
-                    self.cur.func.locations[dst_vals[0]],
+                    self.cur.func.locations[dst_val],
                 ) {
-                    (ValueLoc::Stack(src_slot), ValueLoc::Stack(dst_slot)) => src_slot == dst_slot,
+                    (ValueLoc::Stack(src_slot), ValueLoc::Stack(dst_slot)) => {
+                        src_slot == dst_slot && {
+                            let src_ty = self.cur.func.dfg.value_type(arg);
+                            let dst_ty = self.cur.func.dfg.value_type(dst_val);
+                            debug_assert!(src_ty == dst_ty);
+                            // This limits the transformation to copies of the
+                            // types: I64 I32 I16 I8 F64 and F32, since that's
+                            // the set of `copy_nop` encodings available.
+                            src_ty.is_int() || src_ty.is_float()
+                        }
+                    }
                     _ => false,
                 };
                 if can_transform {
                     // Convert the instruction into a `copy_nop`.
                     self.cur.func.dfg.replace(inst).copy_nop(arg);
                     let ok = self.cur.func.update_encoding(inst, self.cur.isa).is_ok();
-                    debug_assert!(ok);
+                    debug_assert!(ok, "copy_nop encoding missing for this type");
 
                     // And move on to the next insn.
                     self.reloads.clear();
                     let _ = tracker.process_inst(inst, &self.cur.func.dfg, self.liveness);
                     self.cur.next_inst();
                     self.candidates.clear();
                     return;
                 }
@@ -450,17 +461,17 @@ impl<'a> Context<'a> {
 
 /// Find reload candidates in the instruction's ABI variable arguments. This handles both
 /// return values and call arguments.
 fn handle_abi_args(
     candidates: &mut Vec<ReloadCandidate>,
     abi_types: &[AbiParam],
     var_args: &[Value],
     offset: usize,
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
     liveness: &Liveness,
 ) {
     debug_assert_eq!(abi_types.len(), var_args.len());
     for ((abi, &arg), argidx) in abi_types.iter().zip(var_args).zip(offset..) {
         if abi.location.is_reg() {
             let lv = liveness.get(arg).expect("Missing live range for ABI arg");
             if lv.affinity.is_stack() {
                 candidates.push(ReloadCandidate {
--- a/third_party/rust/cranelift-codegen/src/regalloc/solver.rs
+++ b/third_party/rust/cranelift-codegen/src/regalloc/solver.rs
@@ -401,17 +401,17 @@ impl fmt::Display for Move {
                 rc.info.display_regunit(to)
             ),
         }
     }
 }
 
 impl fmt::Debug for Move {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let as_display: &fmt::Display = self;
+        let as_display: &dyn fmt::Display = self;
         as_display.fmt(f)
     }
 }
 
 /// Constraint solver for register allocation around a single instruction.
 ///
 /// Start by programming in the instruction constraints.
 ///
@@ -1134,17 +1134,17 @@ mod tests {
     use crate::ir::Value;
     use crate::isa::{RegClass, RegInfo, RegUnit, TargetIsa};
     use crate::regalloc::RegisterSet;
     use core::str::FromStr;
     use std::boxed::Box;
     use target_lexicon::triple;
 
     // Make an arm32 `TargetIsa`, if possible.
-    fn arm32() -> Option<Box<TargetIsa>> {
+    fn arm32() -> Option<Box<dyn TargetIsa>> {
         use crate::isa;
         use crate::settings;
 
         let shared_builder = settings::builder();
         let shared_flags = settings::Flags::new(shared_builder);
 
         isa::lookup(triple!("arm"))
             .ok()
--- a/third_party/rust/cranelift-codegen/src/regalloc/spilling.rs
+++ b/third_party/rust/cranelift-codegen/src/regalloc/spilling.rs
@@ -86,17 +86,17 @@ impl Spilling {
     pub fn clear(&mut self) {
         self.spills.clear();
         self.reg_uses.clear();
     }
 
     /// Run the spilling algorithm over `func`.
     pub fn run(
         &mut self,
-        isa: &TargetIsa,
+        isa: &dyn TargetIsa,
         func: &mut Function,
         domtree: &DominatorTree,
         liveness: &mut Liveness,
         virtregs: &VirtRegs,
         topo: &mut TopoOrder,
         tracker: &mut LiveValueTracker,
     ) {
         let _tt = timing::ra_spilling();
--- a/third_party/rust/cranelift-codegen/src/settings.rs
+++ b/third_party/rust/cranelift-codegen/src/settings.rs
@@ -341,27 +341,27 @@ include!(concat!(env!("OUT_DIR"), "/sett
 /// A few passes need to access the flags but only optionally a target ISA. The `FlagsOrIsa`
 /// wrapper can be used to pass either, and extract the flags so they are always accessible.
 #[derive(Clone, Copy)]
 pub struct FlagsOrIsa<'a> {
     /// Flags are always present.
     pub flags: &'a Flags,
 
     /// The ISA may not be present.
-    pub isa: Option<&'a TargetIsa>,
+    pub isa: Option<&'a dyn TargetIsa>,
 }
 
 impl<'a> From<&'a Flags> for FlagsOrIsa<'a> {
     fn from(flags: &'a Flags) -> FlagsOrIsa {
         FlagsOrIsa { flags, isa: None }
     }
 }
 
-impl<'a> From<&'a TargetIsa> for FlagsOrIsa<'a> {
-    fn from(isa: &'a TargetIsa) -> FlagsOrIsa {
+impl<'a> From<&'a dyn TargetIsa> for FlagsOrIsa<'a> {
+    fn from(isa: &'a dyn TargetIsa) -> FlagsOrIsa {
         FlagsOrIsa {
             flags: isa.flags(),
             isa: Some(isa),
         }
     }
 }
 
 #[cfg(test)]
--- a/third_party/rust/cranelift-codegen/src/value_label.rs
+++ b/third_party/rust/cranelift-codegen/src/value_label.rs
@@ -76,17 +76,17 @@ where
     sorted
 }
 
 /// Builds ranges and location for specified value labels.
 /// The labels specified at DataFlowGraph's values_labels collection.
 pub fn build_value_labels_ranges<T>(
     func: &Function,
     regalloc: &Context,
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
 ) -> ValueLabelsRanges
 where
     T: From<SourceLoc> + Deref<Target = SourceLoc> + Ord + Copy,
 {
     let values_labels = build_value_labels_index::<T>(func);
 
     let mut ebbs = func.layout.ebbs().collect::<Vec<_>>();
     ebbs.sort_by_key(|ebb| func.offsets[*ebb]); // Ensure inst offsets always increase
--- a/third_party/rust/cranelift-codegen/src/verifier/flags.rs
+++ b/third_party/rust/cranelift-codegen/src/verifier/flags.rs
@@ -19,17 +19,17 @@ use crate::verifier::{VerifierErrors, Ve
 ///
 /// - At most one flags value can be live at a time.
 /// - A flags value can not be live across an instruction that clobbers the flags.
 ///
 ///
 pub fn verify_flags(
     func: &ir::Function,
     cfg: &ControlFlowGraph,
-    isa: Option<&isa::TargetIsa>,
+    isa: Option<&dyn isa::TargetIsa>,
     errors: &mut VerifierErrors,
 ) -> VerifierStepResult<()> {
     let _tt = timing::verify_flags();
     let mut verifier = FlagsVerifier {
         func,
         cfg,
         encinfo: isa.map(|isa| isa.encoding_info()),
         livein: SecondaryMap::new(),
--- a/third_party/rust/cranelift-codegen/src/verifier/liveness.rs
+++ b/third_party/rust/cranelift-codegen/src/verifier/liveness.rs
@@ -18,17 +18,17 @@ use core::cmp::Ordering;
 /// - The live range def point must match where the value is defined.
 /// - The live range must reach all uses.
 /// - When a live range is live-in to an EBB, it must be live at all the predecessors.
 /// - The live range affinity must be compatible with encoding constraints.
 ///
 /// We don't verify that live ranges are minimal. This would require recomputing live ranges for
 /// all values.
 pub fn verify_liveness(
-    isa: &TargetIsa,
+    isa: &dyn TargetIsa,
     func: &Function,
     cfg: &ControlFlowGraph,
     liveness: &Liveness,
     errors: &mut VerifierErrors,
 ) -> VerifierStepResult<()> {
     let _tt = timing::verify_liveness();
     let verifier = LivenessVerifier {
         isa,
@@ -37,17 +37,17 @@ pub fn verify_liveness(
         liveness,
     };
     verifier.check_ebbs(errors)?;
     verifier.check_insts(errors)?;
     Ok(())
 }
 
 struct LivenessVerifier<'a> {
-    isa: &'a TargetIsa,
+    isa: &'a dyn TargetIsa,
     func: &'a Function,
     cfg: &'a ControlFlowGraph,
     liveness: &'a Liveness,
 }
 
 impl<'a> LivenessVerifier<'a> {
     /// Check all EBB arguments.
     fn check_ebbs(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
--- a/third_party/rust/cranelift-codegen/src/verifier/locations.rs
+++ b/third_party/rust/cranelift-codegen/src/verifier/locations.rs
@@ -14,17 +14,17 @@ use crate::verifier::{VerifierErrors, Ve
 /// instruction encoding recipes.
 ///
 /// Values can be temporarily diverted to a different location by using the `regmove`, `regspill`,
 /// and `regfill` instructions, but only inside an EBB.
 ///
 /// If a liveness analysis is provided, it is used to verify that there are no active register
 /// diversions across control flow edges.
 pub fn verify_locations(
-    isa: &isa::TargetIsa,
+    isa: &dyn isa::TargetIsa,
     func: &ir::Function,
     liveness: Option<&Liveness>,
     errors: &mut VerifierErrors,
 ) -> VerifierStepResult<()> {
     let _tt = timing::verify_locations();
     let verifier = LocationVerifier {
         isa,
         func,
@@ -32,17 +32,17 @@ pub fn verify_locations(
         encinfo: isa.encoding_info(),
         liveness,
     };
     verifier.check_constraints(errors)?;
     Ok(())
 }
 
 struct LocationVerifier<'a> {
-    isa: &'a isa::TargetIsa,
+    isa: &'a dyn isa::TargetIsa,
     func: &'a ir::Function,
     reginfo: isa::RegInfo,
     encinfo: isa::EncInfo,
     liveness: Option<&'a Liveness>,
 }
 
 impl<'a> LocationVerifier<'a> {
     /// Check that the assigned value locations match the operand constraints of their uses.
--- a/third_party/rust/cranelift-codegen/src/verifier/mod.rs
+++ b/third_party/rust/cranelift-codegen/src/verifier/mod.rs
@@ -261,17 +261,17 @@ pub fn verify_context<'a, FOI: Into<Flag
     }
     verifier.run(errors)
 }
 
 struct Verifier<'a> {
     func: &'a Function,
     expected_cfg: ControlFlowGraph,
     expected_domtree: DominatorTree,
-    isa: Option<&'a TargetIsa>,
+    isa: Option<&'a dyn TargetIsa>,
 }
 
 impl<'a> Verifier<'a> {
     pub fn new(func: &'a Function, fisa: FlagsOrIsa<'a>) -> Self {
         let expected_cfg = ControlFlowGraph::with_function(func);
         let expected_domtree = DominatorTree::with_function(func, &expected_cfg);
         Self {
             func,
@@ -575,17 +575,17 @@ impl<'a> Verifier<'a> {
                     "argument {} -> {} is not attached",
                     arg,
                     original
                 );
             }
         }
 
         for &res in self.func.dfg.inst_results(inst) {
-            self.verify_inst_result(inst, res, errors).is_ok();
+            self.verify_inst_result(inst, res, errors)?;
         }
 
         match self.func.dfg[inst] {
             MultiAry { ref args, .. } => {
                 self.verify_value_list(inst, args, errors)?;
             }
             Jump {
                 destination,
@@ -1068,21 +1068,21 @@ impl<'a> Verifier<'a> {
             ctrl_type
         } else {
             // Non-polymorphic instructions don't check the controlling type variable, so `Option`
             // is unnecessary and we can just make it `INVALID`.
             types::INVALID
         };
 
         // Typechecking instructions is never fatal
-        self.typecheck_results(inst, ctrl_type, errors).is_ok();
-        self.typecheck_fixed_args(inst, ctrl_type, errors).is_ok();
-        self.typecheck_variable_args(inst, errors).is_ok();
-        self.typecheck_return(inst, errors).is_ok();
-        self.typecheck_special(inst, ctrl_type, errors).is_ok();
+        let _ = self.typecheck_results(inst, ctrl_type, errors);
+        let _ = self.typecheck_fixed_args(inst, ctrl_type, errors);
+        let _ = self.typecheck_variable_args(inst, errors);
+        let _ = self.typecheck_return(inst, errors);
+        let _ = self.typecheck_special(inst, ctrl_type, errors);
 
         // Misuses of copy_nop instructions are fatal
         self.typecheck_copy_nop(inst, errors)?;
 
         Ok(())
     }
 
     fn typecheck_results(
--- a/third_party/rust/cranelift-codegen/src/write.rs
+++ b/third_party/rust/cranelift-codegen/src/write.rs
@@ -17,48 +17,48 @@ use std::collections::HashSet;
 use std::string::String;
 use std::vec::Vec;
 
 /// A `FuncWriter` used to decorate functions during printing.
 pub trait FuncWriter {
     /// Write the extended basic block header for the current function.
     fn write_ebb_header(
         &mut self,
-        w: &mut Write,
+        w: &mut dyn Write,
         func: &Function,
-        isa: Option<&TargetIsa>,
+        isa: Option<&dyn TargetIsa>,
         ebb: Ebb,
         indent: usize,
     ) -> fmt::Result;
 
     /// Write the given `inst` to `w`.
     fn write_instruction(
         &mut self,
-        w: &mut Write,
+        w: &mut dyn Write,
         func: &Function,
         aliases: &SecondaryMap<Value, Vec<Value>>,
-        isa: Option<&TargetIsa>,
+        isa: Option<&dyn TargetIsa>,
         inst: Inst,
         indent: usize,
     ) -> fmt::Result;
 
     /// Write the preamble to `w`. By default, this uses `write_entity_definition`.
     fn write_preamble(
         &mut self,
-        w: &mut Write,
+        w: &mut dyn Write,
         func: &Function,
         regs: Option<&RegInfo>,
     ) -> Result<bool, fmt::Error> {
         self.super_preamble(w, func, regs)
     }
 
     /// Default impl of `write_preamble`
     fn super_preamble(
         &mut self,
-        w: &mut Write,
+        w: &mut dyn Write,
         func: &Function,
         regs: Option<&RegInfo>,
     ) -> Result<bool, fmt::Error> {
         let mut any = false;
 
         for (ss, slot) in func.stack_slots.iter() {
             any = true;
             self.write_entity_definition(w, func, ss.into(), slot)?;
@@ -103,69 +103,69 @@ pub trait FuncWriter {
         }
 
         Ok(any)
     }
 
     /// Write an entity definition defined in the preamble to `w`.
     fn write_entity_definition(
         &mut self,
-        w: &mut Write,
+        w: &mut dyn Write,
         func: &Function,
         entity: AnyEntity,
-        value: &fmt::Display,
+        value: &dyn fmt::Display,
     ) -> fmt::Result {
         self.super_entity_definition(w, func, entity, value)
     }
 
     /// Default impl of `write_entity_definition`
     #[allow(unused_variables)]
     fn super_entity_definition(
         &mut self,
-        w: &mut Write,
+        w: &mut dyn Write,
         func: &Function,
         entity: AnyEntity,
-        value: &fmt::Display,
+        value: &dyn fmt::Display,
     ) -> fmt::Result {
         writeln!(w, "    {} = {}", entity, value)
     }
 }
 
 /// A `PlainWriter` that doesn't decorate the function.
 pub struct PlainWriter;
 
 impl FuncWriter for PlainWriter {
     fn write_instruction(
         &mut self,
-        w: &mut Write,
+        w: &mut dyn Write,
         func: &Function,
         aliases: &SecondaryMap<Value, Vec<Value>>,
-        isa: Option<&TargetIsa>,
+        isa: Option<&dyn TargetIsa>,
         inst: Inst,
         indent: usize,
     ) -> fmt::Result {
         write_instruction(w, func, aliases, isa, inst, indent)
     }
 
     fn write_ebb_header(
         &mut self,
-        w: &mut Write,
+        w: &mut dyn Write,
         func: &Function,
-        isa: Option<&TargetIsa>,
+        isa: Option<&dyn TargetIsa>,
         ebb: Ebb,
         indent: usize,
     ) -> fmt::Result {
         write_ebb_header(w, func, isa, ebb, indent)
     }
 }
 
 /// Write `func` to `w` as equivalent text.
 /// Use `isa` to emit ISA-dependent annotations.
 pub fn write_function(
-    w: &mut Write,
+    w: &mut dyn Write,
     func: &Function,
     annotations: &DisplayFunctionAnnotations,
 ) -> fmt::Result {
     decorate_function(&mut PlainWriter, w, func, annotations)
 }
 
 /// Create a reverse-alias map from a value to all aliases having that value as a direct target
 fn alias_map(func: &Function) -> SecondaryMap<Value, Vec<Value>> {
@@ -179,17 +179,17 @@ fn alias_map(func: &Function) -> Seconda
     aliases
 }
 
 /// Writes `func` to `w` as text.
 /// write_function_plain is passed as 'closure' to print instructions as text.
 /// pretty_function_error is passed as 'closure' to add error decoration.
 pub fn decorate_function<FW: FuncWriter>(
     func_w: &mut FW,
-    w: &mut Write,
+    w: &mut dyn Write,
     func: &Function,
     annotations: &DisplayFunctionAnnotations,
 ) -> fmt::Result {
     let regs = annotations.isa.map(TargetIsa::register_info);
     let regs = regs.as_ref();
 
     write!(w, "function ")?;
     write_spec(w, func, regs)?;
@@ -205,44 +205,49 @@ pub fn decorate_function<FW: FuncWriter>
     }
     writeln!(w, "}}")
 }
 
 //----------------------------------------------------------------------
 //
 // Function spec.
 
-fn write_spec(w: &mut Write, func: &Function, regs: Option<&RegInfo>) -> fmt::Result {
+fn write_spec(w: &mut dyn Write, func: &Function, regs: Option<&RegInfo>) -> fmt::Result {
     write!(w, "{}{}", func.name, func.signature.display(regs))
 }
 
 //----------------------------------------------------------------------
 //
 // Basic blocks
 
-fn write_arg(w: &mut Write, func: &Function, regs: Option<&RegInfo>, arg: Value) -> fmt::Result {
+fn write_arg(
+    w: &mut dyn Write,
+    func: &Function,
+    regs: Option<&RegInfo>,
+    arg: Value,
+) -> fmt::Result {
     write!(w, "{}: {}", arg, func.dfg.value_type(arg))?;
     let loc = func.locations[arg];
     if loc.is_assigned() {
         write!(w, " [{}]", loc.display(regs))?
     }
 
     Ok(())
 }
 
 /// Write out the basic block header, outdented:
 ///
 ///    ebb1:
 ///    ebb1(v1: i32):
 ///    ebb10(v4: f64, v5: b1):
 ///
 pub fn write_ebb_header(
-    w: &mut Write,
+    w: &mut dyn Write,
     func: &Function,
-    isa: Option<&TargetIsa>,
+    isa: Option<&dyn TargetIsa>,
     ebb: Ebb,
     indent: usize,
 ) -> fmt::Result {
     // The `indent` is the instruction indentation. EBB headers are 4 spaces out from that.
     write!(w, "{1:0$}{2}", indent - 4, "", ebb)?;
 
     let regs = isa.map(TargetIsa::register_info);
     let regs = regs.as_ref();
@@ -258,26 +263,26 @@ pub fn write_ebb_header(
     // Remaining arguments.
     for arg in args {
         write!(w, ", ")?;
         write_arg(w, func, regs, arg)?;
     }
     writeln!(w, "):")
 }
 
-fn write_valueloc(w: &mut Write, loc: &ValueLoc, regs: &RegInfo) -> fmt::Result {
+fn write_valueloc(w: &mut dyn Write, loc: &ValueLoc, regs: &RegInfo) -> fmt::Result {
     match loc {
         ValueLoc::Reg(r) => write!(w, "{}", regs.display_regunit(*r)),
         ValueLoc::Stack(ss) => write!(w, "{}", ss),
         ValueLoc::Unassigned => write!(w, "?"),
     }
 }
 
 fn write_value_range_markers(
-    w: &mut Write,
+    w: &mut dyn Write,
     val_ranges: &ValueLabelsRanges,
     regs: &RegInfo,
     offset: u32,
     indent: usize,
 ) -> fmt::Result {
     let mut result = String::new();
     let mut shown = HashSet::new();
     for (val, rng) in val_ranges {
@@ -301,17 +306,17 @@ fn write_value_range_markers(
     if result.len() > 0 {
         writeln!(w, ";{1:0$}; {2}", indent + 24, "", result)?;
     }
     Ok(())
 }
 
 fn decorate_ebb<FW: FuncWriter>(
     func_w: &mut FW,
-    w: &mut Write,
+    w: &mut dyn Write,
     func: &Function,
     aliases: &SecondaryMap<Value, Vec<Value>>,
     annotations: &DisplayFunctionAnnotations,
     ebb: Ebb,
 ) -> fmt::Result {
     // Indent all instructions if any encodings are present.
     let indent = if func.encodings.is_empty() && func.srclocs.is_empty() {
         4
@@ -380,37 +385,37 @@ fn type_suffix(func: &Function, inst: In
         !rtype.is_invalid(),
         "Polymorphic instruction must produce a result"
     );
     Some(rtype)
 }
 
 /// Write out any aliases to the given target, including indirect aliases
 fn write_value_aliases(
-    w: &mut Write,
+    w: &mut dyn Write,
     aliases: &SecondaryMap<Value, Vec<Value>>,
     target: Value,
     indent: usize,
 ) -> fmt::Result {
     let mut todo_stack = vec![target];
     while let Some(target) = todo_stack.pop() {
         for &a in &aliases[target] {
             writeln!(w, "{1:0$}{2} -> {3}", indent, "", a, target)?;
             todo_stack.push(a);
         }
     }
 
     Ok(())
 }
 
 fn write_instruction(
-    w: &mut Write,
+    w: &mut dyn Write,
     func: &Function,
     aliases: &SecondaryMap<Value, Vec<Value>>,
-    isa: Option<&TargetIsa>,
+    isa: Option<&dyn TargetIsa>,
     inst: Inst,
     indent: usize,
 ) -> fmt::Result {
     // Prefix containing source location, encoding, and value locations.
     let mut s = String::with_capacity(16);
 
     // Source location goes first.
     let srcloc = func.srclocs[inst];
@@ -467,19 +472,19 @@ fn write_instruction(
     for r in func.dfg.inst_results(inst) {
         write_value_aliases(w, aliases, *r, indent)?;
     }
     Ok(())
 }
 
 /// Write the operands of `inst` to `w` with a prepended space.
 pub fn write_operands(
-    w: &mut Write,
+    w: &mut dyn Write,
     dfg: &DataFlowGraph,
-    isa: Option<&TargetIsa>,
+    isa: Option<&dyn TargetIsa>,
     inst: Inst,
 ) -> fmt::Result {
     let pool = &dfg.value_lists;
     use crate::ir::instructions::InstructionData::*;
     match dfg[inst] {
         Unary { arg, .. } => write!(w, " {}", arg),
         UnaryImm { imm, .. } => write!(w, " {}", imm),
         UnaryIeee32 { imm, .. } => write!(w, " {}", imm),
@@ -682,17 +687,17 @@ pub fn write_operands(
         } => write!(w, " {} {}, {}", cond, arg, code),
         FloatCondTrap {
             cond, arg, code, ..
         } => write!(w, " {} {}, {}", cond, arg, code),
     }
 }
 
 /// Write EBB args using optional parantheses.
-fn write_ebb_args(w: &mut Write, args: &[Value]) -> fmt::Result {
+fn write_ebb_args(w: &mut dyn Write, args: &[Value]) -> fmt::Result {
     if args.is_empty() {
         Ok(())
     } else {
         write!(w, "({})", DisplayValues(args))
     }
 }
 
 /// Displayable slice of values.
--- a/third_party/rust/cranelift-entity/.cargo-checksum.json
+++ b/third_party/rust/cranelift-entity/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"48e037bea5be27018e3f98bfba7ca7b0af1322c2083c69a137ab3320cd64b9fb","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"96ceffbfd88fb06e3b41aa4d3087cffbbf8441d04eba7ab09662a72ab600a321","src/boxed_slice.rs":"687428ee0442013c0d5962dd78d0964830233bc4cb19aa530d30da0f1dc437a9","src/iter.rs":"4a4d3309fe9aad14fd7702f02459f4277b4ddb50dba700e58dcc75665ffebfb3","src/keys.rs":"b8c2fba26dee15bf3d1880bb2b41e8d66fe1428d242ee6d9fd30ee94bbd0407d","src/lib.rs":"139fc0eeed2e8cde2b82b8b7402e8c7cd079a9fbbf1ec692622e5ad0c10d9faf","src/list.rs":"fc3decc81bcef92e106aae53e586a0ef21d70916fa53a48f7b813c5da44b8dc2","src/map.rs":"f35031459aca446734726c132c0a571482f1ec2ca8221b352d2e18c74950e977","src/packed_option.rs":"9d47f5b8302ee685c096817e376144e363507d1c77ef562d3ae4dbddae568195","src/primary.rs":"e95e4b2ed36413d80c4c0dcfc19dcf8a9f52e34467aaec196c774fd639747028","src/set.rs":"ec0ff7a9ee674c90ff9d06ea1fd4ab05039369146c2d259f476c6f612417933f","src/sparse.rs":"cf345a81d69a5dddaed4778b6aaaf06c70da2c1fd4cd21e366ed6ca5906ffdab"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"48e037bea5be27018e3f98bfba7ca7b0af1322c2083c69a137ab3320cd64b9fb","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"96ceffbfd88fb06e3b41aa4d3087cffbbf8441d04eba7ab09662a72ab600a321","src/boxed_slice.rs":"687428ee0442013c0d5962dd78d0964830233bc4cb19aa530d30da0f1dc437a9","src/iter.rs":"4a4d3309fe9aad14fd7702f02459f4277b4ddb50dba700e58dcc75665ffebfb3","src/keys.rs":"b8c2fba26dee15bf3d1880bb2b41e8d66fe1428d242ee6d9fd30ee94bbd0407d","src/lib.rs":"f83cdc6c4a2cd0d75e85c355ee2c8b19b25194c86468c2285bde1f725656062f","src/list.rs":"fc3decc81bcef92e106aae53e586a0ef21d70916fa53a48f7b813c5da44b8dc2","src/map.rs":"f35031459aca446734726c132c0a571482f1ec2ca8221b352d2e18c74950e977","src/packed_option.rs":"9d47f5b8302ee685c096817e376144e363507d1c77ef562d3ae4dbddae568195","src/primary.rs":"e95e4b2ed36413d80c4c0dcfc19dcf8a9f52e34467aaec196c774fd639747028","src/set.rs":"ec0ff7a9ee674c90ff9d06ea1fd4ab05039369146c2d259f476c6f612417933f","src/sparse.rs":"cf345a81d69a5dddaed4778b6aaaf06c70da2c1fd4cd21e366ed6ca5906ffdab"},"package":null}
\ No newline at end of file
--- a/third_party/rust/cranelift-entity/src/lib.rs
+++ b/third_party/rust/cranelift-entity/src/lib.rs
@@ -121,17 +121,17 @@ macro_rules! entity_impl {
         impl $crate::__core::fmt::Display for $entity {
             fn fmt(&self, f: &mut $crate::__core::fmt::Formatter) -> $crate::__core::fmt::Result {
                 write!(f, concat!($display_prefix, "{}"), self.0)
             }
         }
 
         impl $crate::__core::fmt::Debug for $entity {
             fn fmt(&self, f: &mut $crate::__core::fmt::Formatter) -> $crate::__core::fmt::Result {
-                (self as &$crate::__core::fmt::Display).fmt(f)
+                (self as &dyn $crate::__core::fmt::Display).fmt(f)
             }
         }
     };
 }
 
 pub mod packed_option;
 
 mod boxed_slice;
--- a/third_party/rust/cranelift-frontend/.cargo-checksum.json
+++ b/third_party/rust/cranelift-frontend/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"c92f07d9959d10331c6b4770a4db12f706927a18897dfed45472abcd6e58190e","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"dea43e8044284df50f8b8772e9b48ba8b109b45c74111ff73619775d57ad8d67","src/frontend.rs":"149ccdd1fdbdff42693720b14f9077dfbaa5c54ad6cae097d68756678a7486e2","src/lib.rs":"1cc2e7aaffa45bccea9e59fcc9d9c5d295a9f7adacd6bd55933834e20e969aef","src/ssa.rs":"88cb07071943f3e72a91c91afb58960689b4d9c56352b3bb7cd5d69288066190","src/switch.rs":"b8f337966b540254feb5f979b4a146f5ef69ae199864da6332c9d7513ff3ec8b","src/variable.rs":"f082efaa4b2d3c5eb48f6344149408074e1e15cb581f7a63f549313c7a1037be"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"c92f07d9959d10331c6b4770a4db12f706927a18897dfed45472abcd6e58190e","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"dea43e8044284df50f8b8772e9b48ba8b109b45c74111ff73619775d57ad8d67","src/frontend.rs":"f2fcd908b6a3c9b4a925702a578c9b2f0c6af6ed53cfc3cd7070b6fa3b7d58cb","src/lib.rs":"1cc2e7aaffa45bccea9e59fcc9d9c5d295a9f7adacd6bd55933834e20e969aef","src/ssa.rs":"88cb07071943f3e72a91c91afb58960689b4d9c56352b3bb7cd5d69288066190","src/switch.rs":"b8f337966b540254feb5f979b4a146f5ef69ae199864da6332c9d7513ff3ec8b","src/variable.rs":"f082efaa4b2d3c5eb48f6344149408074e1e15cb581f7a63f549313c7a1037be"},"package":null}
\ No newline at end of file
--- a/third_party/rust/cranelift-frontend/src/frontend.rs
+++ b/third_party/rust/cranelift-frontend/src/frontend.rs
@@ -566,17 +566,17 @@ impl<'a> FunctionBuilder<'a> {
         self.func_ctx.ebbs[self.position.ebb.unwrap()].filled
     }
 
     /// Returns a displayable object for the function as it is.
     ///
     /// Useful for debug purposes. Use it with `None` for standard printing.
     // Clippy thinks the lifetime that follows is needless, but rustc needs it
     #[cfg_attr(feature = "cargo-clippy", allow(clippy::needless_lifetimes))]
-    pub fn display<'b, I: Into<Option<&'b TargetIsa>>>(&'b self, isa: I) -> DisplayFunction {
+    pub fn display<'b, I: Into<Option<&'b dyn TargetIsa>>>(&'b self, isa: I) -> DisplayFunction {
         self.func.display(isa)
     }
 }
 
 /// Helper functions
 impl<'a> FunctionBuilder<'a> {
     /// Calls libc.memcpy
     ///
--- a/third_party/rust/cranelift-wasm/.cargo-checksum.json
+++ b/third_party/rust/cranelift-wasm/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"6065884c733b5e4ae101f38771c52bff0ba7b9984bf9438dde102aa68e4b9b5c","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"87679cdb53e8cbec3b1aa45afb2124727c1c059f8bd10363d27daf318a9f9a36","src/code_translator.rs":"56a399a242c9b59c25104e5c3faa81d289d0d441d17617a20b0061fbd9297aa3","src/environ/dummy.rs":"ee4d8d4924b4b04027f8af07968d5098ecd72ee62b53622d30334d1a38b227b8","src/environ/mod.rs":"617c147485038dfd797ab0ea71b4cfa9574d95d5d5b1ca362c6b7b6a462cf577","src/environ/spec.rs":"f45b20f6f9e60d94eb13829168ce8f7078ac61282689d43f58e1fccf9815d488","src/func_translator.rs":"07e1ebda4949f744e7d7b5a679bf1951fbefd807a0f0748231353cf1ef536d82","src/lib.rs":"0897b0270e746961db3d4dc74e5f766aced0ef23f870399aa9e685f1ec62ea83","src/module_translator.rs":"ac54c24aaa3775f72ccd16d1781be648bb0e83ea83909f933d07e86ef1879213","src/sections_translator.rs":"b7313a25c4e95917f8e87103fa8613166b25c040933979a0ff293c89eb3f99dc","src/state.rs":"9e4f67900439f6aa18cfa3f16c694487374ddf42530db4504bccab0ebc360c96","src/translation_utils.rs":"72ccd5bed655f1a215873218d004b087f692b0d060af0f57773b961b75214cac","tests/wasm_testsuite.rs":"9b4e008587c61377cf38f9d0e4635418ee38e32a865db8da5dfc6e0fae047436"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"1988715f39ef56d0e40ffcb2ffde965a1753a8ed15375e8a30fccabba16bd701","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"87679cdb53e8cbec3b1aa45afb2124727c1c059f8bd10363d27daf318a9f9a36","src/code_translator.rs":"77040f6e49784aafce63a04057a3464651ed7a817ba055226d40ef5755914989","src/environ/dummy.rs":"ee4d8d4924b4b04027f8af07968d5098ecd72ee62b53622d30334d1a38b227b8","src/environ/mod.rs":"617c147485038dfd797ab0ea71b4cfa9574d95d5d5b1ca362c6b7b6a462cf577","src/environ/spec.rs":"f45b20f6f9e60d94eb13829168ce8f7078ac61282689d43f58e1fccf9815d488","src/func_translator.rs":"07e1ebda4949f744e7d7b5a679bf1951fbefd807a0f0748231353cf1ef536d82","src/lib.rs":"0897b0270e746961db3d4dc74e5f766aced0ef23f870399aa9e685f1ec62ea83","src/module_translator.rs":"2345a4ee009eb59a90898795f939b9c7b241604a44abb27278610257cce84156","src/sections_translator.rs":"8ad698652ec7741feea8c10badfd6891d27d9b5b2b06819b08ec009afa584e81","src/state.rs":"9e4f67900439f6aa18cfa3f16c694487374ddf42530db4504bccab0ebc360c96","src/translation_utils.rs":"cb6b1ab91b4dd4739e5282989c61e6778cd1150319c8c7466b32f6ecc5db7afe","tests/wasm_testsuite.rs":"9b4e008587c61377cf38f9d0e4635418ee38e32a865db8da5dfc6e0fae047436"},"package":null}
\ No newline at end of file
--- a/third_party/rust/cranelift-wasm/Cargo.toml
+++ b/third_party/rust/cranelift-wasm/Cargo.toml
@@ -6,17 +6,17 @@ description = "Translator from WebAssemb
 repository = "https://github.com/CraneStation/cranelift"
 license = "Apache-2.0 WITH LLVM-exception"
 categories = ["no-std", "wasm"]
 readme = "README.md"
 keywords = ["webassembly", "wasm"]
 edition = "2018"
 
 [dependencies]
-wasmparser = { version = "0.29.2", default-features = false }
+wasmparser = { version = "0.31.0", default-features = false }
 cranelift-codegen = { path = "../cranelift-codegen", version = "0.30.0", default-features = false }
 cranelift-entity = { path = "../cranelift-entity", version = "0.30.0", default-features = false }
 cranelift-frontend = { path = "../cranelift-frontend", version = "0.30.0", default-features = false }
 hashmap_core = { version = "0.1.9", optional = true }
 failure = { version = "0.1.1", default-features = false, features = ["derive"] }
 failure_derive = { version = "0.1.1", default-features = false }
 log = { version = "0.4.6", default-features = false }
 
--- a/third_party/rust/cranelift-wasm/src/code_translator.rs
+++ b/third_party/rust/cranelift-wasm/src/code_translator.rs
@@ -20,17 +20,19 @@
 //! - `call_indirect` has to translate the function index into the address of where this
 //!    is;
 //!
 //! That is why `translate_function_body` takes an object having the `WasmRuntime` trait as
 //! argument.
 use super::{hash_map, HashMap};
 use crate::environ::{FuncEnvironment, GlobalVariable, ReturnMode, WasmError, WasmResult};
 use crate::state::{ControlStackFrame, TranslationState};
-use crate::translation_utils::{f32_translation, f64_translation, num_return_values, type_to_type};
+use crate::translation_utils::{
+    blocktype_to_type, f32_translation, f64_translation, num_return_values,
+};
 use crate::translation_utils::{FuncIndex, MemoryIndex, SignatureIndex, TableIndex};
 use core::{i32, u32};
 use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
 use cranelift_codegen::ir::types::*;
 use cranelift_codegen::ir::{self, InstBuilder, JumpTableData, MemFlags, ValueLabel};
 use cranelift_codegen::packed_option::ReservedValue;
 use cranelift_frontend::{FunctionBuilder, Variable};
 use wasmparser::{MemoryImmediate, Operator};
@@ -125,25 +127,25 @@ pub fn translate_operator<FE: FuncEnviro
          *
          *  The `End` instruction pops the last control frame from the control stack, seals
          *  the destination block (since `br` instructions targeting it only appear inside the
          *  block and have already been translated) and modify the value stack to use the
          *  possible `Ebb`'s arguments values.
          ***********************************************************************************/
         Operator::Block { ty } => {
             let next = builder.create_ebb();
-            if let Ok(ty_cre) = type_to_type(ty) {
+            if let Ok(ty_cre) = blocktype_to_type(ty) {
                 builder.append_ebb_param(next, ty_cre);
             }
             state.push_block(next, num_return_values(ty));
         }
         Operator::Loop { ty } => {
             let loop_body = builder.create_ebb();
             let next = builder.create_ebb();
-            if let Ok(ty_cre) = type_to_type(ty) {
+            if let Ok(ty_cre) = blocktype_to_type(ty) {
                 builder.append_ebb_param(next, ty_cre);
             }
             builder.ins().jump(loop_body, &[]);
             state.push_loop(loop_body, next, num_return_values(ty));
             builder.switch_to_block(loop_body);
             environ.translate_loop_header(builder.cursor())?;
         }
         Operator::If { ty } => {
@@ -151,17 +153,17 @@ pub fn translate_operator<FE: FuncEnviro
             let if_not = builder.create_ebb();
             let jump_inst = builder.ins().brz(val, if_not, &[]);
             // Here we append an argument to an Ebb targeted by an argumentless jump instruction
             // But in fact there are two cases:
             // - either the If does not have a Else clause, in that case ty = EmptyBlock
             //   and we add nothing;
             // - either the If have an Else clause, in that case the destination of this jump
             //   instruction will be changed later when we translate the Else operator.
-            if let Ok(ty_cre) = type_to_type(ty) {
+            if let Ok(ty_cre) = blocktype_to_type(ty) {
                 builder.append_ebb_param(if_not, ty_cre);
             }
             state.push_if(jump_inst, if_not, num_return_values(ty));
         }
         Operator::Else => {
             // We take the control frame pushed by the if, use its ebb as the else body
             // and push a new control frame with a new ebb for the code after the if/then/else
             // At the end of the then clause we jump to the destination
--- a/third_party/rust/cranelift-wasm/src/module_translator.rs
+++ b/third_party/rust/cranelift-wasm/src/module_translator.rs
@@ -8,17 +8,17 @@ use crate::sections_translator::{
 };
 use cranelift_codegen::timing;
 use wasmparser::{ModuleReader, SectionCode};
 
 /// Translate a sequence of bytes forming a valid Wasm binary into a list of valid Cranelift IR
 /// [`Function`](../codegen/ir/function/struct.Function.html).
 pub fn translate_module<'data>(
     data: &'data [u8],
-    environ: &mut ModuleEnvironment<'data>,
+    environ: &mut dyn ModuleEnvironment<'data>,
 ) -> WasmResult<()> {
     let _tt = timing::wasm_translate_module();
     let mut reader = ModuleReader::new(data)?;
 
     reader.skip_custom_sections()?;
     if reader.eof() {
         return Ok(());
     }
--- a/third_party/rust/cranelift-wasm/src/sections_translator.rs
+++ b/third_party/rust/cranelift-wasm/src/sections_translator.rs
@@ -1,13 +1,13 @@
 //! Helper functions to gather information for each of the non-function sections of a
 //! WebAssembly module.
 //!
-//! The code of theses helper function is straightforward since it is only about reading metadata
-//! about linear memories, tables, globals, etc. and storing them for later use.
+//! The code of these helper functions is straightforward since they only read metadata
+//! about linear memories, tables, globals, etc. and store them for later use.
 //!
 //! The special case of the initialize expressions for table elements offsets or global variables
 //! is handled, according to the semantics of WebAssembly, to only specific expressions that are
 //! interpreted on the fly.
 use crate::environ::{ModuleEnvironment, WasmResult};
 use crate::translation_utils::{
     type_to_type, FuncIndex, Global, GlobalIndex, GlobalInit, Memory, MemoryIndex, SignatureIndex,
     Table, TableElementType, TableIndex,
@@ -22,17 +22,17 @@ use wasmparser::{
     FunctionSectionReader, GlobalSectionReader, GlobalType, ImportSectionEntryType,
     ImportSectionReader, MemorySectionReader, MemoryType, Operator, TableSectionReader,
     TypeSectionReader,
 };
 
 /// Parses the Type section of the wasm module.
 pub fn parse_type_section(
     types: TypeSectionReader,
-    environ: &mut ModuleEnvironment,
+    environ: &mut dyn ModuleEnvironment,
 ) -> WasmResult<()> {
     environ.reserve_signatures(types.get_count());
 
     for entry in types {
         match entry? {
             FuncType {
                 form: wasmparser::Type::Func,
                 ref params,
@@ -55,17 +55,17 @@ pub fn parse_type_section(
         }
     }
     Ok(())
 }
 
 /// Parses the Import section of the wasm module.
 pub fn parse_import_section<'data>(
     imports: ImportSectionReader<'data>,
-    environ: &mut ModuleEnvironment<'data>,
+    environ: &mut dyn ModuleEnvironment<'data>,
 ) -> WasmResult<()> {
     environ.reserve_imports(imports.get_count());
 
     for entry in imports {
         let import = entry?;
         let module_name = import.module;
         let field_name = import.field;
 
@@ -117,32 +117,32 @@ pub fn parse_import_section<'data>(
 
     environ.finish_imports();
     Ok(())
 }
 
 /// Parses the Function section of the wasm module.
 pub fn parse_function_section(
     functions: FunctionSectionReader,
-    environ: &mut ModuleEnvironment,
+    environ: &mut dyn ModuleEnvironment,
 ) -> WasmResult<()> {
     environ.reserve_func_types(functions.get_count());
 
     for entry in functions {
         let sigindex = entry?;
         environ.declare_func_type(SignatureIndex::from_u32(sigindex));
     }
 
     Ok(())
 }
 
 /// Parses the Table section of the wasm module.
 pub fn parse_table_section(
     tables: TableSectionReader,
-    environ: &mut ModuleEnvironment,
+    environ: &mut dyn ModuleEnvironment,
 ) -> WasmResult<()> {
     environ.reserve_tables(tables.get_count());
 
     for entry in tables {
         let table = entry?;
         environ.declare_table(Table {
             ty: match type_to_type(table.element_type) {
                 Ok(t) => TableElementType::Val(t),
@@ -154,17 +154,17 @@ pub fn parse_table_section(
     }
 
     Ok(())
 }
 
 /// Parses the Memory section of the wasm module.
 pub fn parse_memory_section(
     memories: MemorySectionReader,
-    environ: &mut ModuleEnvironment,
+    environ: &mut dyn ModuleEnvironment,
 ) -> WasmResult<()> {
     environ.reserve_memories(memories.get_count());
 
     for entry in memories {
         let memory = entry?;
         environ.declare_memory(Memory {
             minimum: memory.limits.initial,
             maximum: memory.limits.maximum,
@@ -173,17 +173,17 @@ pub fn parse_memory_section(
     }
 
     Ok(())
 }
 
 /// Parses the Global section of the wasm module.
 pub fn parse_global_section(
     globals: GlobalSectionReader,
-    environ: &mut ModuleEnvironment,
+    environ: &mut dyn ModuleEnvironment,
 ) -> WasmResult<()> {
     environ.reserve_globals(globals.get_count());
 
     for entry in globals {
         let wasmparser::Global {
             ty: GlobalType {
                 content_type,
                 mutable,
@@ -210,17 +210,17 @@ pub fn parse_global_section(
     }
 
     Ok(())
 }
 
 /// Parses the Export section of the wasm module.
 pub fn parse_export_section<'data>(
     exports: ExportSectionReader<'data>,
-    environ: &mut ModuleEnvironment<'data>,
+    environ: &mut dyn ModuleEnvironment<'data>,
 ) -> WasmResult<()> {
     environ.reserve_exports(exports.get_count());
 
     for entry in exports {
         let Export {
             field,
             ref kind,
             index,
@@ -238,25 +238,25 @@ pub fn parse_export_section<'data>(
         }
     }
 
     environ.finish_exports();
     Ok(())
 }
 
 /// Parses the Start section of the wasm module.
-pub fn parse_start_section(index: u32, environ: &mut ModuleEnvironment) -> WasmResult<()> {
+pub fn parse_start_section(index: u32, environ: &mut dyn ModuleEnvironment) -> WasmResult<()> {
     environ.declare_start_func(FuncIndex::from_u32(index));
     Ok(())
 }
 
 /// Parses the Element section of the wasm module.
 pub fn parse_element_section<'data>(
     elements: ElementSectionReader<'data>,
-    environ: &mut ModuleEnvironment,
+    environ: &mut dyn ModuleEnvironment,
 ) -> WasmResult<()> {
     environ.reserve_table_elements(elements.get_count());
 
     for entry in elements {
         let Element { kind, items } = entry?;
         if let ElementKind::Active {
             table_index,
             init_expr,
@@ -287,31 +287,31 @@ pub fn parse_element_section<'data>(
         }
     }
     Ok(())
 }
 
 /// Parses the Code section of the wasm module.
 pub fn parse_code_section<'data>(
     code: CodeSectionReader<'data>,
-    environ: &mut ModuleEnvironment<'data>,
+    environ: &mut dyn ModuleEnvironment<'data>,
 ) -> WasmResult<()> {
     for body in code {
         let mut reader = body?.get_binary_reader();
         let size = reader.bytes_remaining();
         let offset = reader.original_position();
         environ.define_function_body(reader.read_bytes(size)?, offset)?;
     }
     Ok(())
 }
 
 /// Parses the Data section of the wasm module.
 pub fn parse_data_section<'data>(
     data: DataSectionReader<'data>,
-    environ: &mut ModuleEnvironment<'data>,
+    environ: &mut dyn ModuleEnvironment<'data>,
 ) -> WasmResult<()> {
     environ.reserve_data_initializers(data.get_count());
 
     for entry in data {
         let Data { kind, data } = entry?;
         if let DataKind::Active {
             memory_index,
             init_expr,
--- a/third_party/rust/cranelift-wasm/src/translation_utils.rs
+++ b/third_party/rust/cranelift-wasm/src/translation_utils.rs
@@ -114,35 +114,46 @@ pub fn type_to_type(ty: wasmparser::Type
         wasmparser::Type::I32 => ir::types::I32,
         wasmparser::Type::I64 => ir::types::I64,
         wasmparser::Type::F32 => ir::types::F32,
         wasmparser::Type::F64 => ir::types::F64,
         _ => return Err(()),
     })
 }
 
+/// Helper function translating wasmparser block signatures to Cranelift types when possible.
+pub fn blocktype_to_type(ty: wasmparser::TypeOrFuncType) -> Result<ir::Type, ()> {
+    match ty {
+        wasmparser::TypeOrFuncType::Type(ty) => type_to_type(ty),
+        wasmparser::TypeOrFuncType::FuncType(_) => unimplemented!("multi-value block signatures"),
+    }
+}
+
 /// Turns a `wasmparser` `f32` into a `Cranelift` one.
 pub fn f32_translation(x: wasmparser::Ieee32) -> ir::immediates::Ieee32 {
     ir::immediates::Ieee32::with_bits(x.bits())
 }
 
 /// Turns a `wasmparser` `f64` into a `Cranelift` one.
 pub fn f64_translation(x: wasmparser::Ieee64) -> ir::immediates::Ieee64 {
     ir::immediates::Ieee64::with_bits(x.bits())
 }
 
 /// Translate a `wasmparser` type into its `Cranelift` equivalent, when possible
-pub fn num_return_values(ty: wasmparser::Type) -> usize {
+pub fn num_return_values(ty: wasmparser::TypeOrFuncType) -> usize {
     match ty {
-        wasmparser::Type::EmptyBlockType => 0,
-        wasmparser::Type::I32
-        | wasmparser::Type::F32
-        | wasmparser::Type::I64
-        | wasmparser::Type::F64 => 1,
-        _ => panic!("unsupported return value type"),
+        wasmparser::TypeOrFuncType::Type(ty) => match ty {
+            wasmparser::Type::EmptyBlockType => 0,
+            wasmparser::Type::I32
+            | wasmparser::Type::F32
+            | wasmparser::Type::I64
+            | wasmparser::Type::F64 => 1,
+            _ => panic!("unsupported return value type"),
+        },
+        wasmparser::TypeOrFuncType::FuncType(_) => unimplemented!("multi-value block signatures"),
     }
 }
 
 /// Special VMContext value label. It is tracked as 0xffff_fffe label.
 pub fn get_vmctx_value_label() -> ir::ValueLabel {
     const VMCTX_LABEL: u32 = 0xffff_fffe;
     ir::ValueLabel::from_u32(VMCTX_LABEL)
 }
--- a/third_party/rust/wasmparser/.cargo-checksum.json
+++ b/third_party/rust/wasmparser/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"6f05ad46e7a84c8ae06ee90f29bb874acb68074a88aa31838554b9f9c07cd405","LICENSE":"a6c48161a09acc75a0e25503bab66a731eb5fba5392ed4bb4743e4ba5085327a","README.md":"13ea373a411dfa7371cd994736289bb000db51957da92315fecbcc9fe7dcab92","examples/dump.rs":"fdebf1af451d06691d011ba7220f3f9a483b2c54a851f06b610aaa5fcb3832df","examples/simple.rs":"c79ae542913e72cfcd03711543d173b2e8f62783e6c206459953bdb94dbb8c0c","format-all.sh":"6b02a40629ef3d2c0b9671222582a6217d526317a41262ae06c7a95de53bcbeb","src/binary_reader.rs":"e8d58f2ab57123955c680e9c9e790aec8e8a36732a77349bcdbadd7d8faf1c7d","src/lib.rs":"2fae91a32fe51183d5f9d4aab48665a0e617d6127a2031d6aaf4aa257e76dca1","src/limits.rs":"2cf22e266c2828d68bb521485b8bd604a2ecb7a023204d7874b3da5837ec44f9","src/parser.rs":"40624c94c125446b0c6106e7590b35c58df2a6ceafc85a72bb013eef2018eb58","src/primitives.rs":"4627647982376ea8519f931f09108d04c7080cf6b2a4b2d85e559ba7cfb6ad70","src/readers/code_section.rs":"2034c399b76428ac993c22f551f3c541b132d8b4ccc74e34f0043e25534d107b","src/readers/data_count_section.rs":"27ef37517b6beac21245008b14b5416b851c52d0af8e2ae85c1456674e1c9a9e","src/readers/data_section.rs":"e7e2a539d2d3049d4a8f68df9ea2f21d97e7061657bbd91845e1df3e9c1f2ebc","src/readers/element_section.rs":"e31e1d819c0b10acf58b8975238554245defe36db1c3206683b056c52978fb21","src/readers/export_section.rs":"7c74f7a11406a95c162f6ad4f77aafd0b1eee309f33b69f06bea12b23925e143","src/readers/function_section.rs":"57c0479ba8d7f61908ed74e86cbc26553fdd6d2d952f032ce29385a39f82efd3","src/readers/global_section.rs":"5fa18bed0fffadcc2dbdcbaedbe4e4398992fd1ce9e611b0319333a7681082ac","src/readers/import_section.rs":"1db4bf7290d04783d5cf526050d025b15a1daaf2bd97fca1a92ecb873d48f641","src/readers/init_expr.rs":"7020c80013dad4518a5f969c3ab4d624b46d778f03e632871cf343964f63441c","src/readers/linking_section.rs":"9df71f3ee5356f0d273c099212213353080001e261ca697caddf6b847fb5af09","src/readers/memory_section.rs":"83212f86cfc40d18fb392e9234c880afdf443f4af38a727ba346f9c740ef8718","src/readers/mod.rs":"13822fff4190b72f6ae14e29635d2c148a38ee972e148eb99a4688b0309bc2c9","src/readers/module.rs":"66473e7077b3d77ed01ed58d2796c8de7afdb2b90f2b0669c06fa90ca1b3434e","src/readers/name_section.rs":"297f57393d5fef745ec265438108aa6eb7ed2762c03c3beb539493612442f3da","src/readers/operators.rs":"da43ee8afcb0c1d6e7f1e19e8a10143101f0c598b1e533a394c7397f43881a82","src/readers/producers_section.rs":"674f402fc4545c94487f827153871b37adab44ed5eff4070a436eb18e514023a","src/readers/reloc_section.rs":"0ef818a8b83a4542c4c29c23642436a92d3e7c37bc0248e817ed5a9d65ec38ce","src/readers/section_reader.rs":"3d2260449fa0455d710ba6d97810372ec36cba70722c10dd236c3a18ca0eb56f","src/readers/sourcemappingurl_section.rs":"ababe84d51e4817ad19f827aa2b5239578e7f202e5ec06dd688b618885138434","src/readers/start_section.rs":"3eeae00e1aa0fcb2e0d93b7b0eaac30a60d3f1431c71c589cd3f73adb363d532","src/readers/table_section.rs":"e564876825a7b31df2b5dc850279b523e26dc50a08da935cc8d635a49e809951","src/readers/type_section.rs":"2fa33a7b793f3bfa01c259b5dbc38633b7343931886ab41f0cb96dd78db3bf6e","src/tests.rs":"ca486d82ffaa31370534d7d1475c0603f0e9d4888d3d07287b9d5458e6d11156","src/validator.rs":"ec0d1368f3b7833ff6d6178db50e3ffc6b2878d1d6ddab37728fdf21e8256896","test-all.sh":"ff894f4e5e34389ad6ef697bd4ade28a2483dd456eabba8b757945546568f4c9","test-no_std.sh":"f8bc939b378fe618b7ec6297152708e7c8740858eb94e5756464934a38796b8c"},"package":"981a8797cf89762e0233ec45fae731cb79a4dfaee12d9f0fe6cee01e4ac58d00"}
\ No newline at end of file
+{"files":{"Cargo.toml":"83c9345be6b7ac1c67bf7aa61e82fb440c299277dd02817a86e7dac7ba3ac7fa","LICENSE":"a6c48161a09acc75a0e25503bab66a731eb5fba5392ed4bb4743e4ba5085327a","README.md":"13ea373a411dfa7371cd994736289bb000db51957da92315fecbcc9fe7dcab92","benches/benchmark.rs":"25caa5e42e88412fdc443cdf1e870b100c9bf5e2907bbfd75f077757be3090bc","compare-master.sh":"165490eab36ef4eceb2913a6c5cdeff479a05e1e0119a7f4551b03dbcda51ad4","examples/dump.rs":"de2bbdba75e21b9ff92b32697b3d9941f8695b8f7e3a8dee8fc5d7f4c3a0649c","examples/simple.rs":"c79ae542913e72cfcd03711543d173b2e8f62783e6c206459953bdb94dbb8c0c","format-all.sh":"6b02a40629ef3d2c0b9671222582a6217d526317a41262ae06c7a95de53bcbeb","src/binary_reader.rs":"e523ef680480c5a106e0238b1fa4eb77ecaabc2652b65d5dc0f683ee0eed66d7","src/lib.rs":"bc786f619be99366d838c8837416c9008fa15beb873395e8b9ab98579a6b1c18","src/limits.rs":"4e4f9b7ed1d26e7a6727e36b136015cd9f4e38f596b3c8f82236789f45905cae","src/operators_validator.rs":"be295f7529ba863884a10d3236ee3e39c2b4b138ae5a1343b15612a367cd99ca","src/parser.rs":"9b1ab93de63117cfc43900cc99c9912dcd307b347ca982eb4e307331edab4ca2","src/primitives.rs":"9f1417b9dba839c548d9afd94488be7c1d179d243cfeca4f8b10c9805995af62","src/readers/code_section.rs":"2034c399b76428ac993c22f551f3c541b132d8b4ccc74e34f0043e25534d107b","src/readers/data_count_section.rs":"27ef37517b6beac21245008b14b5416b851c52d0af8e2ae85c1456674e1c9a9e","src/readers/data_section.rs":"e7e2a539d2d3049d4a8f68df9ea2f21d97e7061657bbd91845e1df3e9c1f2ebc","src/readers/element_section.rs":"e31e1d819c0b10acf58b8975238554245defe36db1c3206683b056c52978fb21","src/readers/export_section.rs":"7c74f7a11406a95c162f6ad4f77aafd0b1eee309f33b69f06bea12b23925e143","src/readers/function_section.rs":"57c0479ba8d7f61908ed74e86cbc26553fdd6d2d952f032ce29385a39f82efd3","src/readers/global_section.rs":"5fa18bed0fffadcc2dbdcbaedbe4e4398992fd1ce9e611b0319333a7681082ac","src/readers/import_section.rs":"1db4bf7290d04783d5cf526050d025b15a1daaf2bd97fca1a92ecb873d48f641","src/readers/init_expr.rs":"7020c80013dad4518a5f969c3ab4d624b46d778f03e632871cf343964f63441c","src/readers/linking_section.rs":"9df71f3ee5356f0d273c099212213353080001e261ca697caddf6b847fb5af09","src/readers/memory_section.rs":"83212f86cfc40d18fb392e9234c880afdf443f4af38a727ba346f9c740ef8718","src/readers/mod.rs":"13822fff4190b72f6ae14e29635d2c148a38ee972e148eb99a4688b0309bc2c9","src/readers/module.rs":"66473e7077b3d77ed01ed58d2796c8de7afdb2b90f2b0669c06fa90ca1b3434e","src/readers/name_section.rs":"297f57393d5fef745ec265438108aa6eb7ed2762c03c3beb539493612442f3da","src/readers/operators.rs":"da43ee8afcb0c1d6e7f1e19e8a10143101f0c598b1e533a394c7397f43881a82","src/readers/producers_section.rs":"674f402fc4545c94487f827153871b37adab44ed5eff4070a436eb18e514023a","src/readers/reloc_section.rs":"0ef818a8b83a4542c4c29c23642436a92d3e7c37bc0248e817ed5a9d65ec38ce","src/readers/section_reader.rs":"3d2260449fa0455d710ba6d97810372ec36cba70722c10dd236c3a18ca0eb56f","src/readers/sourcemappingurl_section.rs":"ababe84d51e4817ad19f827aa2b5239578e7f202e5ec06dd688b618885138434","src/readers/start_section.rs":"3eeae00e1aa0fcb2e0d93b7b0eaac30a60d3f1431c71c589cd3f73adb363d532","src/readers/table_section.rs":"e564876825a7b31df2b5dc850279b523e26dc50a08da935cc8d635a49e809951","src/readers/type_section.rs":"2fa33a7b793f3bfa01c259b5dbc38633b7343931886ab41f0cb96dd78db3bf6e","src/tests.rs":"927ed18fc70cf340a02b3e2f7f535a062003fcc3d6f66857093c431b88054dd3","src/validator.rs":"592db08da9b2f6a6cd658faac06d737434de98a09fd8bdc125e7a3c7f003d008","test-all.sh":"ff894f4e5e34389ad6ef697bd4ade28a2483dd456eabba8b757945546568f4c9","test-no_std.sh":"f8bc939b378fe618b7ec6297152708e7c8740858eb94e5756464934a38796b8c"},"package":"8a6f324afc05fd8282bbc49dae854a1c20f74aeff10a575b5a43453d1864db97"}
\ No newline at end of file
--- a/third_party/rust/wasmparser/Cargo.toml
+++ b/third_party/rust/wasmparser/Cargo.toml
@@ -1,31 +1,37 @@
 # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
 #
 # When uploading crates to the registry Cargo will automatically
 # "normalize" Cargo.toml files for maximal compatibility
 # with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g. crates.io) dependencies
+# to registry (e.g., crates.io) dependencies
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "wasmparser"
-version = "0.29.2"
+version = "0.31.1"
 authors = ["Yury Delendik <ydelendik@mozilla.com>"]
 exclude = ["fuzz/**/*", "tests/**/*"]
 description = "A simple event-driven library for parsing WebAssembly binary files.\n"
 keywords = ["parser", "WebAssembly", "wasm"]
 license = "Apache-2.0 WITH LLVM-exception"
 repository = "https://github.com/yurydelendik/wasmparser.rs"
+
+[[bench]]
+name = "benchmark"
+harness = false
 [dependencies.hashmap_core]
-version = "0.1.9"
+version = "0.1.10"
 optional = true
+[dev-dependencies.criterion]
+version = "0.2"
 
 [features]
 core = ["hashmap_core"]
 default = ["std"]
 std = []
 [badges.travis-ci]
 repository = "yurydelendik/wasmparser.rs"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/wasmparser/benches/benchmark.rs
@@ -0,0 +1,99 @@
+pub fn read_file_data(path: &PathBuf) -> Vec<u8> {
+    let mut data = Vec::new();
+    let mut f = File::open(path).ok().unwrap();
+    f.read_to_end(&mut data).unwrap();
+    data
+}
+
+const VALIDATOR_CONFIG: Option<ValidatingParserConfig> = Some(ValidatingParserConfig {
+    operator_config: OperatorValidatorConfig {
+        enable_threads: true,
+        enable_reference_types: true,
+        enable_simd: true,
+        enable_bulk_memory: true,
+    },
+    mutable_global_imports: true,
+});
+
+#[macro_use]
+extern crate criterion;
+extern crate wasmparser;
+
+use criterion::Criterion;
+use wasmparser::{
+    validate, OperatorValidatorConfig, Parser, ParserState, ValidatingParser,
+    ValidatingParserConfig, WasmDecoder,
+};
+
+use std::fs::{read_dir, File};
+use std::io::Read;
+use std::path::PathBuf;
+
+fn read_all_wasm<'a, T>(mut d: T)
+where
+    T: WasmDecoder<'a>,
+{
+    loop {
+        match *d.read() {
+            ParserState::Error(e) => panic!("unexpected error {:?}", e),
+            ParserState::EndWasm => return,
+            _ => (),
+        }
+    }
+}
+
+fn it_works_benchmark(c: &mut Criterion) {
+    let mut data: Vec<Vec<u8>> = vec![];
+    for entry in read_dir("tests").unwrap() {
+        let dir = entry.unwrap();
+        if !dir.file_type().unwrap().is_file() {
+            continue;
+        }
+        data.push(read_file_data(&dir.path()));
+    }
+    c.bench_function("it works benchmark", move |b| {
+        for d in &mut data {
+            b.iter(|| read_all_wasm(Parser::new(d.as_slice())));
+        }
+    });
+}
+
+fn validator_not_fails_benchmark(c: &mut Criterion) {
+    let mut data: Vec<Vec<u8>> = vec![];
+    for entry in read_dir("tests").unwrap() {
+        let dir = entry.unwrap();
+        if !dir.file_type().unwrap().is_file() {
+            continue;
+        }
+        data.push(read_file_data(&dir.path()));
+    }
+    c.bench_function("validator no fails benchmark", move |b| {
+        for d in &mut data {
+            b.iter(|| read_all_wasm(ValidatingParser::new(d.as_slice(), VALIDATOR_CONFIG)));
+        }
+    });
+}
+
+fn validate_benchmark(c: &mut Criterion) {
+    let mut data: Vec<Vec<u8>> = vec![vec![]];
+    for entry in read_dir("tests").unwrap() {
+        let dir = entry.unwrap();
+        if !dir.file_type().unwrap().is_file() {
+            continue;
+        }
+        data.push(read_file_data(&dir.path()));
+    }
+    c.bench_function("validate benchmark", move |b| {
+        for d in &mut data {
+            b.iter(|| validate(&d, VALIDATOR_CONFIG));
+        }
+    });
+}
+
+criterion_group!(
+    benchmark,
+    it_works_benchmark,
+    validator_not_fails_benchmark,
+    validate_benchmark
+);
+criterion_main!(benchmark);
new file mode 100755
--- /dev/null
+++ b/third_party/rust/wasmparser/compare-master.sh
@@ -0,0 +1,12 @@
+#/bin/bash
+
+# record current bench results
+cargo bench --bench benchmark -- --noplot --save-baseline after
+
+# switch to master and record its bench results
+git checkout master && \
+cargo bench --bench benchmark -- --noplot --save-baseline before
+
+# compare
+cargo install critcmp --force && \
+critcmp before after
--- a/third_party/rust/wasmparser/examples/dump.rs
+++ b/third_party/rust/wasmparser/examples/dump.rs
@@ -14,16 +14,17 @@ fn main() {
     if args.len() != 2 {
         println!("Usage: {} in.wasm", args[0]);
         return;
     }
 
     let buf: Vec<u8> = read_wasm(&args[1]).unwrap();
     let mut parser = Parser::new(&buf);
     loop {
+        print!("0x{:08x}\t", parser.current_position());
         let state = parser.read();
         match *state {
             ParserState::ExportSectionEntry {
                 field,
                 ref kind,
                 index,
             } => {
                 println!(
--- a/third_party/rust/wasmparser/src/binary_reader.rs
+++ b/third_party/rust/wasmparser/src/binary_reader.rs
@@ -20,17 +20,17 @@ use std::vec::Vec;
 use limits::{
     MAX_WASM_FUNCTION_LOCALS, MAX_WASM_FUNCTION_PARAMS, MAX_WASM_FUNCTION_RETURNS,
     MAX_WASM_FUNCTION_SIZE, MAX_WASM_STRING_SIZE,
 };
 
 use primitives::{
     BinaryReaderError, BrTable, CustomSectionKind, ExternalKind, FuncType, GlobalType, Ieee32,
     Ieee64, LinkingType, MemoryImmediate, MemoryType, NameType, Operator, RelocType,
-    ResizableLimits, Result, SIMDLineIndex, SectionCode, TableType, Type, V128,
+    ResizableLimits, Result, SIMDLineIndex, SectionCode, TableType, Type, TypeOrFuncType, V128,
 };
 
 const MAX_WASM_BR_TABLE_SIZE: usize = MAX_WASM_FUNCTION_SIZE;
 
 fn is_name(name: &str, expected: &'static str) -> bool {
     name == expected
 }
 
@@ -244,17 +244,17 @@ impl<'a> BinaryReader<'a> {
         }
         let mut params: Vec<Type> = Vec::with_capacity(params_len);
         for _ in 0..params_len {
             params.push(self.read_type()?);
         }
         let returns_len = self.read_var_u32()? as usize;
         if returns_len > MAX_WASM_FUNCTION_RETURNS {
             return Err(BinaryReaderError {
-                message: "function params size is out of bound",
+                message: "function returns size is out of bound",
                 offset: self.original_position() - 1,
             });
         }
         let mut returns: Vec<Type> = Vec::with_capacity(returns_len);
         for _ in 0..returns_len {
             returns.push(self.read_type()?);
         }
         Ok(FuncType {
@@ -512,16 +512,33 @@ impl<'a> BinaryReader<'a> {
             if (byte & 0x80) == 0 {
                 break;
             }
         }
         let ashift = 32 - shift;
         Ok((result << ashift) >> ashift)
     }
 
+    pub fn read_var_s33(&mut self) -> Result<i64> {
+        // Note: this is not quite spec compliant, in that it doesn't enforce
+        // that the number is encoded in ceil(N / 7) bytes. We should make a
+        // generic-over-N decoding function and replace all the various
+        // `read_var_{i,s}NN` methods with calls to instantiations of that.
+
+        let n = self.read_var_i64()?;
+        if n > (1 << 33 - 1) {
+            Err(BinaryReaderError {
+                message: "Invalid var_s33",
+                offset: self.original_position() - 1,
+            })
+        } else {
+            Ok(n)
+        }
+    }
+
     pub fn read_var_i64(&mut self) -> Result<i64> {
         let mut result: i64 = 0;
         let mut shift = 0;
         loop {
             let byte = self.read_u8()?;
             result |= i64::from(byte & 0x7F) << shift;
             if shift >= 57 {
                 let continuation_bit = (byte & 0x80) != 0;
@@ -785,29 +802,46 @@ impl<'a> BinaryReader<'a> {
                 return Err(BinaryReaderError {
                     message: "Unknown 0xFE opcode",
                     offset: self.original_position() - 1,
                 });
             }
         })
     }
 
+    fn read_blocktype(&mut self) -> Result<TypeOrFuncType> {
+        let position = self.position;
+        if let Ok(ty) = self.read_type() {
+            Ok(TypeOrFuncType::Type(ty))
+        } else {
+            self.position = position;
+            let idx = self.read_var_s33()?;
+            if idx < 0 || idx > (::std::u32::MAX as i64) {
+                return Err(BinaryReaderError {
+                    message: "invalid function type",
+                    offset: position,
+                });
+            }
+            Ok(TypeOrFuncType::FuncType(idx as u32))
+        }
+    }
+
     pub fn read_operator(&mut self) -> Result<Operator<'a>> {
         let code = self.read_u8()? as u8;
         Ok(match code {
             0x00 => Operator::Unreachable,
             0x01 => Operator::Nop,
             0x02 => Operator::Block {
-                ty: self.read_type()?,
+                ty: self.read_blocktype()?,
             },
             0x03 => Operator::Loop {
-                ty: self.read_type()?,
+                ty: self.read_blocktype()?,
             },
             0x04 => Operator::If {
-                ty: self.read_type()?,
+                ty: self.read_blocktype()?,
             },
             0x05 => Operator::Else,
             0x0b => Operator::End,
             0x0c => Operator::Br {
                 relative_depth: self.read_var_u32()?,
             },
             0x0d => Operator::BrIf {
                 relative_depth: self.read_var_u32()?,
--- a/third_party/rust/wasmparser/src/lib.rs
+++ b/third_party/rust/wasmparser/src/lib.rs
@@ -19,17 +19,16 @@
 //! The parser library reports events as they happend and only stores
 //! parsing information for a brief period of time, making it very fast
 //! and memory-efficient. The event-driven model, however, has some drawbacks.
 //! If you need random access to the entire WebAssembly data-structure,
 //! this is not the right library for you. You could however, build such
 //! a data-structure using this library.
 
 #![cfg_attr(not(feature = "std"), no_std)]
-#![cfg_attr(not(feature = "std"), feature(alloc))]
 
 #[cfg(not(feature = "std"))]
 extern crate hashmap_core;
 
 #[cfg(not(feature = "std"))]
 #[macro_use]
 extern crate alloc;
 
@@ -61,24 +60,27 @@ pub use primitives::NameType;
 pub use primitives::Naming;
 pub use primitives::Operator;
 pub use primitives::RelocType;
 pub use primitives::ResizableLimits;
 pub use primitives::Result;
 pub use primitives::SectionCode;
 pub use primitives::TableType;
 pub use primitives::Type;
+pub use primitives::TypeOrFuncType;
 pub use primitives::V128;
 
 pub use validator::validate;
-pub use validator::OperatorValidatorConfig;
+pub use validator::validate_function_body;
 pub use validator::ValidatingOperatorParser;
 pub use validator::ValidatingParser;
 pub use validator::ValidatingParserConfig;
-pub use validator::WasmModuleResources;
+
+pub use operators_validator::OperatorValidatorConfig;
+pub use operators_validator::WasmModuleResources;
 
 pub use readers::CodeSectionReader;
 pub use readers::Data;
 pub use readers::DataKind;
 pub use readers::DataSectionReader;
 pub use readers::Element;
 pub use readers::ElementItems;
 pub use readers::ElementItemsReader;
@@ -111,22 +113,23 @@ pub use readers::SectionIterator;
 pub use readers::SectionIteratorLimited;
 pub use readers::SectionReader;
 pub use readers::SectionWithLimitedItems;
 pub use readers::TableSectionReader;
 pub use readers::TypeSectionReader;
 
 mod binary_reader;
 mod limits;
+mod operators_validator;
 mod parser;
 mod primitives;
 mod readers;
 mod tests;
 mod validator;
 
 #[cfg(not(feature = "std"))]
 mod std {
-    pub use alloc::{boxed, vec};
+    pub use alloc::{boxed, string, vec};
     pub use core::*;
     pub mod collections {
         pub use hashmap_core::HashSet;
     }
 }
--- a/third_party/rust/wasmparser/src/limits.rs
+++ b/third_party/rust/wasmparser/src/limits.rs
@@ -22,14 +22,13 @@ pub const _MAX_WASM_EXPORTS: usize = 100
 pub const MAX_WASM_GLOBALS: usize = 1000000;
 pub const _MAX_WASM_DATA_SEGMENTS: usize = 100000;
 pub const MAX_WASM_MEMORY_PAGES: usize = 65536;
 pub const MAX_WASM_STRING_SIZE: usize = 100000;
 pub const _MAX_WASM_MODULE_SIZE: usize = 1024 * 1024 * 1024; //= 1 GiB
 pub const MAX_WASM_FUNCTION_SIZE: usize = 128 * 1024;
 pub const MAX_WASM_FUNCTION_LOCALS: usize = 50000;
 pub const MAX_WASM_FUNCTION_PARAMS: usize = 1000;
-pub const _MAX_WASM_FUNCTION_MULTI_RETURNS: usize = 1000;
-pub const MAX_WASM_FUNCTION_RETURNS: usize = 1;
+pub const MAX_WASM_FUNCTION_RETURNS: usize = 1000;
 pub const _MAX_WASM_TABLE_SIZE: usize = 10000000;
 pub const MAX_WASM_TABLE_ENTRIES: usize = 10000000;
 pub const MAX_WASM_TABLES: usize = 1;
 pub const MAX_WASM_MEMORIES: usize = 1;
new file mode 100644
--- /dev/null
+++ b/third_party/rust/wasmparser/src/operators_validator.rs
@@ -0,0 +1,1577 @@
+/* Copyright 2019 Mozilla Foundation
+ *
+ * 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.
+ */
+
+use std::cmp::min;
+use std::result;
+use std::str;
+use std::vec::Vec;
+
+use primitives::{
+    FuncType, GlobalType, MemoryImmediate, MemoryType, Operator, SIMDLineIndex, TableType, Type,
+    TypeOrFuncType,
+};
+
+/// Test if `subtype` is a subtype of `supertype`.
+fn is_subtype_supertype(subtype: Type, supertype: Type) -> bool {
+    match supertype {
+        Type::AnyRef => subtype == Type::AnyRef || subtype == Type::AnyFunc,
+        _ => subtype == supertype,
+    }
+}
+
+#[derive(Debug)]
+struct BlockState {
+    start_types: Vec<Type>,
+    return_types: Vec<Type>,
+    stack_starts_at: usize,
+    jump_to_top: bool,
+    is_else_allowed: bool,
+    is_dead_code: bool,
+    polymorphic_values: Option<usize>,
+}
+
+impl BlockState {
+    fn is_stack_polymorphic(&self) -> bool {
+        self.polymorphic_values.is_some()
+    }
+}
+
+#[derive(Debug)]
+struct FuncState {
+    local_types: Vec<Type>,
+    blocks: Vec<BlockState>,
+    stack_types: Vec<Type>,
+    end_function: bool,
+}
+
+impl FuncState {
+    fn block_at(&self, depth: usize) -> &BlockState {
+        assert!(depth < self.blocks.len());
+        &self.blocks[self.blocks.len() - 1 - depth]
+    }
+    fn last_block(&self) -> &BlockState {
+        self.blocks.last().unwrap()
+    }
+    fn assert_stack_type_at(&self, index: usize, expected: Type) -> bool {
+        let stack_starts_at = self.last_block().stack_starts_at;
+        if self.last_block().is_stack_polymorphic()
+            && stack_starts_at + index >= self.stack_types.len()
+        {
+            return true;
+        }
+        assert!(stack_starts_at + index < self.stack_types.len());
+        is_subtype_supertype(
+            self.stack_types[self.stack_types.len() - 1 - index],
+            expected,
+        )
+    }
+    fn assert_block_stack_len(&self, depth: usize, minimal_len: usize) -> bool {
+        assert!(depth < self.blocks.len());
+        let blocks_end = self.blocks.len();
+        let block_offset = blocks_end - 1 - depth;
+        for i in block_offset..blocks_end {
+            if self.blocks[i].is_stack_polymorphic() {
+                return true;
+            }
+        }
+        let block_starts_at = self.blocks[block_offset].stack_starts_at;
+        self.stack_types.len() >= block_starts_at + minimal_len
+    }
+    fn assert_last_block_stack_len_exact(&self, len: usize) -> bool {
+        let block_starts_at = self.last_block().stack_starts_at;
+        if self.last_block().is_stack_polymorphic() {
+            let polymorphic_values = self.last_block().polymorphic_values.unwrap();
+            self.stack_types.len() + polymorphic_values <= block_starts_at + len
+        } else {
+            self.stack_types.len() == block_starts_at + len
+        }
+    }
+    fn remove_frame_stack_types(&mut self, remove_count: usize) -> OperatorValidatorResult<()> {
+        if remove_count == 0 {
+            return Ok(());
+        }
+        let last_block = self.blocks.last_mut().unwrap();
+        if last_block.is_stack_polymorphic() {
+            let len = self.stack_types.len();
+            let remove_non_polymorphic = len
+                .checked_sub(last_block.stack_starts_at)
+                .ok_or("invalid block signature")?
+                .min(remove_count);
+            self.stack_types.truncate(len - remove_non_polymorphic);
+            let polymorphic_values = last_block.polymorphic_values.unwrap();
+            let remove_polymorphic = min(remove_count - remove_non_polymorphic, polymorphic_values);
+            last_block.polymorphic_values = Some(polymorphic_values - remove_polymorphic);
+        } else {
+            assert!(self.stack_types.len() >= last_block.stack_starts_at + remove_count);
+            let keep = self.stack_types.len() - remove_count;
+            self.stack_types.truncate(keep);
+        }
+        Ok(())
+    }
+    fn push_block(
+        &mut self,
+        ty: TypeOrFuncType,
+        block_type: BlockType,
+        resources: &dyn WasmModuleResources,
+    ) -> OperatorValidatorResult<()> {
+        let (start_types, return_types) = match ty {
+            TypeOrFuncType::Type(Type::EmptyBlockType) => (vec![], vec![]),
+            TypeOrFuncType::Type(ty) => (vec![], vec![ty]),
+            TypeOrFuncType::FuncType(idx) => {
+                let ty = &resources.types()[idx as usize];
+                (ty.params.clone().into_vec(), ty.returns.clone().into_vec())
+            }
+        };
+        if block_type == BlockType::If {
+            self.stack_types.pop();
+        }
+        for (i, ty) in start_types.iter().rev().enumerate() {
+            if !self.assert_stack_type_at(i, *ty) {
+                return Err("stack operand type mismatch");
+            }
+        }
+        let stack_starts_at = self.stack_types.len() - start_types.len();
+        self.blocks.push(BlockState {
+            start_types,
+            return_types,
+            stack_starts_at,
+            jump_to_top: block_type == BlockType::Loop,
+            is_else_allowed: block_type == BlockType::If,
+            is_dead_code: false,
+            polymorphic_values: None,
+        });
+        Ok(())
+    }
+    fn pop_block(&mut self) {
+        assert!(self.blocks.len() > 1);
+        let last_block = self.blocks.pop().unwrap();
+        if last_block.is_stack_polymorphic() {
+            assert!(
+                self.stack_types.len()
+                    <= last_block.return_types.len() + last_block.stack_starts_at
+            );
+        } else {
+            assert!(
+                self.stack_types.len()
+                    == last_block.return_types.len() + last_block.stack_starts_at
+            );
+        }
+        let keep = last_block.stack_starts_at;
+        self.stack_types.truncate(keep);
+        self.stack_types.extend_from_slice(&last_block.return_types);
+    }
+    fn reset_block(&mut self) {
+        assert!(self.last_block().is_else_allowed);
+        let last_block = self.blocks.last_mut().unwrap();
+        let keep = last_block.stack_starts_at;
+        self.stack_types.truncate(keep);
+        self.stack_types
+            .extend(last_block.start_types.iter().cloned());
+        last_block.is_else_allowed = false;
+        last_block.polymorphic_values = None;
+    }
+    fn change_frame(&mut self, remove_count: usize) -> OperatorValidatorResult<()> {
+        self.remove_frame_stack_types(remove_count)
+    }
+    fn change_frame_with_type(
+        &mut self,
+        remove_count: usize,
+        ty: Type,
+    ) -> OperatorValidatorResult<()> {
+        self.remove_frame_stack_types(remove_count)?;
+        self.stack_types.push(ty);
+        Ok(())
+    }
+    fn change_frame_with_types(
+        &mut self,
+        remove_count: usize,
+        new_items: &[Type],
+    ) -> OperatorValidatorResult<()> {
+        self.remove_frame_stack_types(remove_count)?;
+        if new_items.is_empty() {
+            return Ok(());
+        }
+        self.stack_types.extend_from_slice(new_items);
+        Ok(())
+    }
+    fn change_frame_to_exact_types_from(&mut self, depth: usize) -> OperatorValidatorResult<()> {
+        let types = self.block_at(depth).return_types.clone();
+        let last_block = self.blocks.last_mut().unwrap();
+        let keep = last_block.stack_starts_at;
+        self.stack_types.truncate(keep);
+        self.stack_types.extend_from_slice(&types);
+        last_block.polymorphic_values = None;
+        Ok(())
+    }
+    fn change_frame_after_select(&mut self, ty: Option<Type>) -> OperatorValidatorResult<()> {
+        self.remove_frame_stack_types(3)?;
+        if ty.is_none() {
+            let last_block = self.blocks.last_mut().unwrap();
+            assert!(last_block.is_stack_polymorphic());
+            last_block.polymorphic_values = Some(last_block.polymorphic_values.unwrap() + 1);
+            return Ok(());
+        }
+        self.stack_types.push(ty.unwrap());
+        Ok(())
+    }
+    fn start_dead_code(&mut self) {
+        let last_block = self.blocks.last_mut().unwrap();
+        let keep = last_block.stack_starts_at;
+        self.stack_types.truncate(keep);
+        last_block.is_dead_code = true;
+        last_block.polymorphic_values = Some(0);
+    }
+    fn end_function(&mut self) {
+        self.end_function = true;
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+enum BlockType {
+    Block,
+    Loop,
+    If,
+}
+
+pub trait WasmModuleResources {
+    fn types(&self) -> &[FuncType];
+    fn tables(&self) -> &[TableType];
+    fn memories(&self) -> &[MemoryType];
+    fn globals(&self) -> &[GlobalType];
+    fn func_type_indices(&self) -> &[u32];
+    fn element_count(&self) -> u32;
+    fn data_count(&self) -> u32;
+}
+
+pub enum FunctionEnd {
+    No,
+    Yes,
+}
+
+type OperatorValidatorResult<T> = result::Result<T, &'static str>;
+
+#[derive(Copy, Clone, Debug)]
+pub struct OperatorValidatorConfig {
+    pub enable_threads: bool,
+    pub enable_reference_types: bool,
+    pub enable_simd: bool,
+    pub enable_bulk_memory: bool,
+    pub enable_multi_value: bool,
+}
+
+pub(crate) const DEFAULT_OPERATOR_VALIDATOR_CONFIG: OperatorValidatorConfig =
+    OperatorValidatorConfig {
+        enable_threads: false,
+        enable_reference_types: false,
+        enable_simd: false,
+        enable_bulk_memory: false,
+        enable_multi_value: false,
+    };
+
+#[derive(Debug)]
+pub(crate) struct OperatorValidator {
+    func_state: FuncState,
+    config: OperatorValidatorConfig,
+}
+
+impl OperatorValidator {
+    pub fn new(
+        func_type: &FuncType,
+        locals: &[(u32, Type)],
+        config: OperatorValidatorConfig,
+    ) -> OperatorValidator {
+        let mut local_types = Vec::new();
+        local_types.extend_from_slice(&*func_type.params);
+        for local in locals {
+            for _ in 0..local.0 {
+                local_types.push(local.1);
+            }
+        }
+
+        let mut blocks = Vec::new();
+        let mut last_returns = Vec::new();
+        last_returns.extend_from_slice(&*func_type.returns);
+        blocks.push(BlockState {
+            start_types: vec![],
+            return_types: last_returns,
+            stack_starts_at: 0,
+            jump_to_top: false,
+            is_else_allowed: false,
+            is_dead_code: false,
+            polymorphic_values: None,
+        });
+
+        OperatorValidator {
+            func_state: FuncState {
+                local_types,
+                blocks,
+                stack_types: Vec::new(),
+                end_function: false,
+            },
+            config,
+        }
+    }
+
+    pub fn is_dead_code(&self) -> bool {
+        self.func_state.last_block().is_dead_code
+    }
+
+    fn check_frame_size(&self, require_count: usize) -> OperatorValidatorResult<()> {
+        if !self.func_state.assert_block_stack_len(0, require_count) {
+            Err("not enough operands")
+        } else {
+            Ok(())
+        }
+    }
+
+    fn check_operands_1(&self, operand: Type) -> OperatorValidatorResult<()> {
+        self.check_frame_size(1)?;
+        if !self.func_state.assert_stack_type_at(0, operand) {
+            return Err("stack operand type mismatch");
+        }
+        Ok(())
+    }
+
+    fn check_operands_2(&self, operand1: Type, operand2: Type) -> OperatorValidatorResult<()> {
+        self.check_frame_size(2)?;
+        if !self.func_state.assert_stack_type_at(1, operand1) {
+            return Err("stack operand type mismatch");
+        }
+        if !self.func_state.assert_stack_type_at(0, operand2) {
+            return Err("stack operand type mismatch");
+        }
+        Ok(())
+    }
+
+    fn check_operands(&self, expected_types: &[Type]) -> OperatorValidatorResult<()> {
+        let len = expected_types.len();
+        self.check_frame_size(len)?;
+        for i in 0..len {
+            if !self
+                .func_state
+                .assert_stack_type_at(len - 1 - i, expected_types[i])
+            {
+                return Err("stack operand type mismatch");
+            }
+        }
+        Ok(())
+    }
+
+    fn check_block_return_types(
+        &self,
+        block: &BlockState,
+        reserve_items: usize,
+    ) -> OperatorValidatorResult<()> {
+        if !self.config.enable_multi_value && block.return_types.len() > 1 {
+            return Err("blocks, loops, and ifs may only return at most one \
+                        value when multi-value is not enabled");
+        }
+        let len = block.return_types.len();
+        for i in 0..len {
+            if !self
+                .func_state
+                .assert_stack_type_at(len - 1 - i + reserve_items, block.return_types[i])
+            {
+                return Err("stack item type does not match block item type");
+            }
+        }
+        Ok(())
+    }
+
+    fn check_block_return(&self) -> OperatorValidatorResult<()> {
+        let len = self.func_state.last_block().return_types.len();
+        if !self.func_state.assert_last_block_stack_len_exact(len) {
+            return Err("stack size does not match block type");
+        }
+        self.check_block_return_types(self.func_state.last_block(), 0)
+    }
+
+    fn check_jump_from_block(
+        &self,
+        relative_depth: u32,
+        reserve_items: usize,
+    ) -> OperatorValidatorResult<()> {
+        if relative_depth as usize >= self.func_state.blocks.len() {
+            return Err("invalid block depth");
+        }
+        let block = self.func_state.block_at(relative_depth as usize);
+        if block.jump_to_top {
+            if !self.func_state.assert_block_stack_len(0, reserve_items) {
+                return Err("stack size does not match target loop type");
+            }
+            return Ok(());
+        }
+
+        let len = block.return_types.len();
+        if !self
+            .func_state
+            .assert_block_stack_len(0, len + reserve_items)
+        {
+            return Err("stack size does not match target block type");
+        }
+        self.check_block_return_types(block, reserve_items)
+    }
+
+    fn match_block_return(&self, depth1: u32, depth2: u32) -> OperatorValidatorResult<()> {
+        if depth1 as usize >= self.func_state.blocks.len() {
+            return Err("invalid block depth");
+        }
+        if depth2 as usize >= self.func_state.blocks.len() {
+            return Err("invalid block depth");
+        }
+        let block1 = self.func_state.block_at(depth1 as usize);
+        let block2 = self.func_state.block_at(depth2 as usize);
+        let return_types1 = &block1.return_types;
+        let return_types2 = &block2.return_types;
+        if block1.jump_to_top || block2.jump_to_top {
+            if block1.jump_to_top {
+                if !block2.jump_to_top && !return_types2.is_empty() {
+                    return Err("block types do not match");
+                }
+            } else if !return_types1.is_empty() {
+                return Err("block types do not match");
+            }
+        } else if *return_types1 != *return_types2 {
+            return Err("block types do not match");
+        }
+        Ok(())
+    }
+
+    fn check_memory_index(
+        &self,
+        memory_index: u32,
+        resources: &dyn WasmModuleResources,
+    ) -> OperatorValidatorResult<()> {
+        if memory_index as usize >= resources.memories().len() {
+            return Err("no liner memories are present");
+        }
+        Ok(())
+    }
+
+    fn check_shared_memory_index(
+        &self,
+        memory_index: u32,
+        resources: &dyn WasmModuleResources,
+    ) -> OperatorValidatorResult<()> {
+        if memory_index as usize >= resources.memories().len() {
+            return Err("no liner memories are present");
+        }
+        if !resources.memories()[memory_index as usize].shared {
+            return Err("atomic accesses require shared memory");
+        }
+        Ok(())
+    }
+
+    fn check_memarg(
+        &self,
+        memarg: &MemoryImmediate,
+        max_align: u32,
+        resources: &dyn WasmModuleResources,
+    ) -> OperatorValidatorResult<()> {
+        self.check_memory_index(0, resources)?;
+        let align = memarg.flags;
+        if align > max_align {
+            return Err("align is required to be at most the number of accessed bytes");
+        }
+        Ok(())
+    }
+
+    fn check_threads_enabled(&self) -> OperatorValidatorResult<()> {
+        if !self.config.enable_threads {
+            return Err("threads support is not enabled");
+        }
+        Ok(())
+    }
+
+    fn check_reference_types_enabled(&self) -> OperatorValidatorResult<()> {
+        if !self.config.enable_reference_types {
+            return Err("reference types support is not enabled");
+        }
+        Ok(())
+    }
+
+    fn check_simd_enabled(&self) -> OperatorValidatorResult<()> {
+        if !self.config.enable_simd {
+            return Err("SIMD support is not enabled");
+        }
+        Ok(())
+    }
+
+    fn check_bulk_memory_enabled(&self) -> OperatorValidatorResult<()> {
+        if !self.config.enable_bulk_memory {
+            return Err("bulk memory support is not enabled");
+        }
+        Ok(())
+    }
+
+    fn check_shared_memarg_wo_align(
+        &self,
+        _: &MemoryImmediate,
+        resources: &dyn WasmModuleResources,
+    ) -> OperatorValidatorResult<()> {
+        self.check_shared_memory_index(0, resources)?;
+        Ok(())
+    }
+
+    fn check_simd_line_index(&self, index: SIMDLineIndex, max: u8) -> OperatorValidatorResult<()> {
+        if index >= max {
+            return Err("SIMD index out of bounds");
+        }
+        Ok(())
+    }
+
+    fn check_block_type(
+        &self,
+        ty: TypeOrFuncType,
+        resources: &dyn WasmModuleResources,
+    ) -> OperatorValidatorResult<()> {
+        match ty {
+            TypeOrFuncType::Type(Type::EmptyBlockType)
+            | TypeOrFuncType::Type(Type::I32)
+            | TypeOrFuncType::Type(Type::I64)
+            | TypeOrFuncType::Type(Type::F32)
+            | TypeOrFuncType::Type(Type::F64) => Ok(()),
+            TypeOrFuncType::FuncType(idx) => {
+                let idx = idx as usize;
+                let types = resources.types();
+                if idx >= types.len() {
+                    return Err("type index out of bounds");
+                }
+                Ok(())
+            }
+            _ => Err("invalid block return type"),
+        }
+    }
+
+    fn check_select(&self) -> OperatorValidatorResult<Option<Type>> {
+        self.check_frame_size(3)?;
+        let func_state = &self.func_state;
+        let last_block = func_state.last_block();
+        Ok(if last_block.is_stack_polymorphic() {
+            match func_state.stack_types.len() - last_block.stack_starts_at {
+                0 => None,
+                1 => {
+                    self.check_operands_1(Type::I32)?;
+                    None
+                }
+                2 => {
+                    self.check_operands_1(Type::I32)?;
+                    Some(func_state.stack_types[func_state.stack_types.len() - 2])
+                }
+                _ => {
+                    let ty = func_state.stack_types[func_state.stack_types.len() - 3];
+                    self.check_operands_2(ty, Type::I32)?;
+                    Some(ty)
+                }
+            }
+        } else {
+            let ty = func_state.stack_types[func_state.stack_types.len() - 3];
+            self.check_operands_2(ty, Type::I32)?;
+            Some(ty)
+        })
+    }
+
+    pub(crate) fn process_operator(
+        &mut self,
+        operator: &Operator,
+        resources: &dyn WasmModuleResources,
+    ) -> OperatorValidatorResult<FunctionEnd> {
+        if self.func_state.end_function {
+            return Err("unexpected operator");
+        }
+        match *operator {
+            Operator::Unreachable => self.func_state.start_dead_code(),
+            Operator::Nop => (),
+            Operator::Block { ty } => {
+                self.check_block_type(ty, resources)?;
+                self.func_state
+                    .push_block(ty, BlockType::Block, resources)?;
+            }
+            Operator::Loop { ty } => {
+                self.check_block_type(ty, resources)?;
+                self.func_state.push_block(ty, BlockType::Loop, resources)?;
+            }
+            Operator::If { ty } => {
+                self.check_block_type(ty, resources)?;
+                self.check_operands_1(Type::I32)?;
+                self.func_state.push_block(ty, BlockType::If, resources)?;
+            }
+            Operator::Else => {
+                if !self.func_state.last_block().is_else_allowed {
+                    return Err("unexpected else: if block is not started");
+                }
+                self.check_block_return()?;
+                self.func_state.reset_block()
+            }
+            Operator::End => {
+                self.check_block_return()?;
+                if self.func_state.blocks.len() == 1 {
+                    self.func_state.end_function();
+                    return Ok(FunctionEnd::Yes);
+                }
+                if {
+                    let last_block = &self.func_state.last_block();
+                    last_block.is_else_allowed && !last_block.return_types.is_empty()
+                } {
+                    return Err("else is expected: if block has type");
+                }
+                self.func_state.pop_block()
+            }
+            Operator::Br { relative_depth } => {
+                self.check_jump_from_block(relative_depth, 0)?;
+                self.func_state.start_dead_code()
+            }
+            Operator::BrIf { relative_depth } => {
+                self.check_operands_1(Type::I32)?;
+                self.check_jump_from_block(relative_depth, 1)?;
+                if self.func_state.last_block().is_stack_polymorphic() {
+                    self.func_state
+                        .change_frame_to_exact_types_from(relative_depth as usize)?;
+                } else {
+                    self.func_state.change_frame(1)?;
+                }
+            }
+            Operator::BrTable { ref table } => {
+                self.check_operands_1(Type::I32)?;
+                let mut depth0: Option<u32> = None;
+                for relative_depth in table {
+                    if depth0.is_none() {
+                        self.check_jump_from_block(relative_depth, 1)?;
+                        depth0 = Some(relative_depth);
+                        continue;
+                    }
+                    self.match_block_return(relative_depth, depth0.unwrap())?;
+                }
+                self.func_state.start_dead_code()
+            }
+            Operator::Return => {
+                let depth = (self.func_state.blocks.len() - 1) as u32;
+                self.check_jump_from_block(depth, 0)?;
+                self.func_state.start_dead_code()
+            }
+            Operator::Call { function_index } => {
+                if function_index as usize >= resources.func_type_indices().len() {
+                    return Err("function index out of bounds");
+                }
+                let type_index = resources.func_type_indices()[function_index as usize];
+                let ty = &resources.types()[type_index as usize];
+                self.check_operands(&ty.params)?;
+                self.func_state
+                    .change_frame_with_types(ty.params.len(), &ty.returns)?;
+            }
+            Operator::CallIndirect { index, table_index } => {
+                if table_index as usize >= resources.tables().len() {
+                    return Err("table index out of bounds");
+                }
+                if index as usize >= resources.types().len() {
+                    return Err("type index out of bounds");
+                }
+                let ty = &resources.types()[index as usize];
+                let mut types = Vec::with_capacity(ty.params.len() + 1);
+                types.extend_from_slice(&ty.params);
+                types.push(Type::I32);
+                self.check_operands(&types)?;
+                self.func_state
+                    .change_frame_with_types(ty.params.len() + 1, &ty.returns)?;
+            }
+            Operator::Drop => {
+                self.check_frame_size(1)?;
+                self.func_state.change_frame(1)?;
+            }
+            Operator::Select => {
+                let ty = self.check_select()?;
+                self.func_state.change_frame_after_select(ty)?;
+            }
+            Operator::GetLocal { local_index } => {
+                if local_index as usize >= self.func_state.local_types.len() {
+                    return Err("local index out of bounds");
+                }
+                let local_type = self.func_state.local_types[local_index as usize];
+                self.func_state.change_frame_with_type(0, local_type)?;
+            }
+            Operator::SetLocal { local_index } => {
+                if local_index as usize >= self.func_state.local_types.len() {
+                    return Err("local index out of bounds");
+                }
+                let local_type = self.func_state.local_types[local_index as usize];
+                self.check_operands_1(local_type)?;
+                self.func_state.change_frame(1)?;
+            }
+            Operator::TeeLocal { local_index } => {
+                if local_index as usize >= self.func_state.local_types.len() {
+                    return Err("local index out of bounds");
+                }
+                let local_type = self.func_state.local_types[local_index as usize];
+                self.check_operands_1(local_type)?;
+                self.func_state.change_frame_with_type(1, local_type)?;
+            }
+            Operator::GetGlobal { global_index } => {
+                if global_index as usize >= resources.globals().len() {
+                    return Err("global index out of bounds");
+                }
+                let ty = &resources.globals()[global_index as usize];
+                self.func_state.change_frame_with_type(0, ty.content_type)?;
+            }
+            Operator::SetGlobal { global_index } => {
+                if global_index as usize >= resources.globals().len() {
+                    return Err("global index out of bounds");
+                }
+                let ty = &resources.globals()[global_index as usize];
+                // FIXME
+                //    if !ty.mutable {
+                //        return self.create_error("global expected to be mutable");
+                //    }
+                self.check_operands_1(ty.content_type)?;
+                self.func_state.change_frame(1)?;
+            }
+            Operator::I32Load { ref memarg } => {
+                self.check_memarg(memarg, 2, resources)?;
+                self.check_operands_1(Type::I32)?;
+                self.func_state.change_frame_with_type(1, Type::I32)?;
+            }
+            Operator::I64Load { ref memarg } => {
+                self.check_memarg(memarg, 3, resources)?;
+                self.check_operands_1(Type::I32)?;
+                self.func_state.change_frame_with_type(1, Type::I64)?;
+            }
+            Operator::F32Load { ref memarg } => {
+                self.check_memarg(memarg, 2, resources)?;
+                self.check_operands_1(Type::I32)?;
+                self.func_state.change_frame_with_type(1, Type::F32)?;
+            }
+            Operator::F64Load { ref memarg } => {
+                self.check_memarg(memarg, 3, resources)?;
+                self.check_operands_1(Type::I32)?;
+                self.func_state.change_frame_with_type(1, Type::F64)?;
+            }
+            Operator::I32Load8S { ref memarg } => {
+                self.check_memarg(memarg, 0, resources)?;
+                self.check_operands_1(Type::I32)?;
+                self.func_state.change_frame_with_type(1, Type::I32)?;
+            }
+            Operator::I32Load8U { ref memarg } => {
+                self.check_memarg(memarg, 0, resources)?;
+                self.check_operands_1(Type::I32)?;
+                self.func_state.change_frame_with_type(1, Type::I32)?;
+            }
+            Operator::I32Load16S { ref memarg } => {
+                self.check_memarg(memarg, 1, resources)?;
+                self.check_operands_1(Type::I32)?;
+                self.func_state.change_frame_with_type(1, Type::I32)?;
+            }
+            Operator::I32Load16U { ref memarg } => {
+                self.check_memarg(memarg, 1, resources)?;
+                self.check_operands_1(Type::I32)?;
+                self.func_state.change_frame_with_type(1, Type::I32)?;
+            }
+            Operator::I64Load8S { ref memarg } => {
+                self.check_memarg(memarg, 0, resources)?;
+                self.check_operands_1(Type::I32)?;
+                self.func_state.change_frame_with_type(1, Type::I64)?;
+            }
+            Operator::I64Load8U { ref memarg } => {
+                self.check_memarg(memarg, 0, resources)?;
+                self.check_operands_1(Type::I32)?;
+                self.func_state.change_frame_with_type(1, Type::I64)?;
+            }
+            Operator::I64Load16S { ref memarg } => {
+                self.check_memarg(memarg, 1, resources)?;
+                self.check_operands_1(Type::I32)?;
+                self.func_state.change_frame_with_type(1, Type::I64)?;
+            }
+            Operator::I64Load16U { ref memarg } => {
+                self.check_memarg(memarg, 1, resources)?;
+                self.check_operands_1(Type::I32)?;
+                self.func_state.change_frame_with_type(1, Type::I64)?;
+            }
+            Operator::I64Load32S { ref memarg } => {
+                self.check_memarg(memarg, 2, resources)?;
+                self.check_operands_1(Type::I32)?;
+                self.func_state.change_frame_with_type(1, Type::I64)?;
+            }
+            Operator::I64Load32U { ref memarg } => {
+                self.check_memarg(memarg, 2, resources)?;
+                self.check_operands_1(Type::I32)?;
+                self.func_state.change_frame_with_type(1, Type::I64)?;
+            }
+            Operator::I32Store { ref memarg } => {
+                self.check_memarg(memarg, 2, resources)?;
+                self.check_operands_2(Type::I32, Type::I32)?;
+                self.func_state.change_frame(2)?;
+            }
+            Operator::I64Store { ref memarg } => {
+                self.check_memarg(memarg, 3, resources)?;
+                self.check_operands_2(Type::I32, Type::I64)?;
+                self.func_state.change_frame(2)?;
+            }
+            Operator::F32Store { ref memarg } => {
+                self.check_memarg(memarg, 2, resources)?;
+                self.check_operands_2(Type::I32, Type::F32)?;
+                self.func_state.change_frame(2)?;
+            }
+            Operator::F64Store { ref memarg } => {
+                self.check_memarg(memarg, 3, resources)?;
+                self.check_operands_2(Type::I32, Type::F64)?;
+                self.func_state.change_frame(2)?;
+            }
+            Operator::I32Store8 { ref memarg } => {
+                self.check_memarg(memarg, 0, resources)?;
+                self.check_operands_2(Type::I32, Type::I32)?;
+                self.func_state.change_frame(2)?;
+            }
+            Operator::I32Store16 { ref memarg } => {
+                self.check_memarg(memarg, 1, resources)?;
+                self.check_operands_2(Type::I32, Type::I32)?;
+                self.func_state.change_frame(2)?;
+            }
+            Operator::I64Store8 { ref memarg } => {
+                self.check_memarg(memarg, 0, resources)?;
+                self.check_operands_2(Type::I32, Type::I64)?;
+                self.func_state.change_frame(2)?;
+            }
+            Operator::I64Store16 { ref memarg } => {
+                self.check_memarg(memarg, 1, resources)?;
+                self.check_operands_2(Type::I32, Type::I64)?;
+                self.func_state.change_frame(2)?;
+            }
+            Operator::I64Store32 { ref memarg } => {
+                self.check_memarg(memarg, 2, resources)?;
+                self.check_operands_2(Type::I32, Type::I64)?;
+