Merge autoland to mozilla-central. a=merge
authorSandor Molnar <smolnar@mozilla.com>
Thu, 16 Sep 2021 18:58:41 +0300
changeset 592155 d952541c136fa93474dc3f3d76f4afcd86100f2e
parent 592130 fd6f4fa5ed1806add34bf8995eed2d4baf22381b (current diff)
parent 592154 7617df50b420a09e9fba0080b2a3d6bf49287566 (diff)
child 592192 237e5ddeef92c5b446ea5a571efe3c05d50a386c
push id38793
push usersmolnar@mozilla.com
push dateThu, 16 Sep 2021 16:00:08 +0000
treeherdermozilla-central@d952541c136f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone94.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge autoland to mozilla-central. a=merge
docshell/base/nsDocShell.cpp
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -72,16 +72,25 @@ version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fc3ec9d4c47b25a5a9e5c848e053640331c7cedb1637434d75db68b79fee8a7f"
 dependencies = [
  "num-traits",
  "serde",
 ]
 
 [[package]]
+name = "arbitrary"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "237430fd6ed3740afe94eefcc278ae21e050285be882804e0d6e8695f0c94691"
+dependencies = [
+ "derive_arbitrary",
+]
+
+[[package]]
 name = "arrayref"
 version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
 
 [[package]]
 name = "arrayvec"
 version = "0.5.2"
@@ -1151,16 +1160,27 @@ dependencies = [
  "url",
  "viaduct",
  "winapi",
  "wineventlog",
  "wio",
 ]
 
 [[package]]
+name = "derive_arbitrary"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f1281ee141df08871db9fe261ab5312179eac32d1e314134ceaa8dd7c042f5a"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
 name = "derive_common"
 version = "0.0.1"
 dependencies = [
  "darling",
  "proc-macro2",
  "quote",
  "syn",
  "synstructure",
@@ -2062,16 +2082,25 @@ name = "glslopt"
 version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "74a3f5c04450dfdadb4b08f6e5ee6f5110f674de1acbd6199bfec68392a8cbaf"
 dependencies = [
  "cc",
 ]
 
 [[package]]
+name = "gluesmith"
+version = "0.1.0"
+dependencies = [
+ "arbitrary",
+ "libc",
+ "wasm-smith",
+]
+
+[[package]]
 name = "goblin"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3081214398d39e4bd7f2c1975f0488ed04614ffdd976c6fc7a0708278552c0da"
 dependencies = [
  "log",
  "plain",
  "scroll",
@@ -2542,16 +2571,17 @@ dependencies = [
 
 [[package]]
 name = "jsrust_shared"
 version = "0.1.0"
 dependencies = [
  "baldrdash",
  "encoding_c",
  "encoding_c_mem",
+ "gluesmith",
  "mozglue-static",
  "mozilla-central-workspace-hack",
  "smoosh",
 ]
 
 [[package]]
 name = "khronos-egl"
 version = "4.1.0"
@@ -5405,16 +5435,37 @@ source = "registry+https://github.com/ru
 checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
 
 [[package]]
 name = "wasm-bindgen"
 version = "0.2.100"
 source = "git+https://github.com/kvark/dummy-web#5731e569d865a1ebaf116f48dad781f355a99243"
 
 [[package]]
+name = "wasm-encoder"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2caacc74c68c74f0008c4055cdf509c43e623775eaf73323bb818dcf666ed9bd"
+dependencies = [
+ "leb128",
+]
+
+[[package]]
+name = "wasm-smith"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b05fb86fe9042112d9659e3f56736b8ad4122023e568e5c55184677c84f66c9"
+dependencies = [
+ "arbitrary",
+ "indexmap",
+ "leb128",
+ "wasm-encoder",
+]
+
+[[package]]
 name = "wasmparser"
 version = "0.78.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "52144d4c78e5cf8b055ceab8e5fa22814ce4315d6002ad32cfd914f37c12fd65"
 
 [[package]]
 name = "wast"
 version = "37.0.0"
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1777,32 +1777,35 @@ pref("browser.contentblocking.state-part
 //     "stp": social tracking protection enabled
 //     "-stp": social tracking protection disabled
 //   Level 2 Tracking list:
 //     "lvl2": Level 2 tracking list enabled
 //     "-lvl2": Level 2 tracking list disabled
 //   Restrict relaxing default referrer policy:
 //     "rp": Restrict relaxing default referrer policy enabled
 //     "-rp": Restrict relaxing default referrer policy disabled
+//   OCSP cache partitioning:
+//     "ocsp": OCSP cache partitioning enabled
+//     "-ocsp": OCSP cache partitioning disabled
 //   Cookie behavior:
 //     "cookieBehavior0": cookie behaviour BEHAVIOR_ACCEPT
 //     "cookieBehavior1": cookie behaviour BEHAVIOR_REJECT_FOREIGN
 //     "cookieBehavior2": cookie behaviour BEHAVIOR_REJECT
 //     "cookieBehavior3": cookie behaviour BEHAVIOR_LIMIT_FOREIGN
 //     "cookieBehavior4": cookie behaviour BEHAVIOR_REJECT_TRACKER
 //     "cookieBehavior5": cookie behaviour BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN
 //   Cookie behavior for private windows:
 //     "cookieBehaviorPBM0": cookie behaviour BEHAVIOR_ACCEPT
 //     "cookieBehaviorPBM1": cookie behaviour BEHAVIOR_REJECT_FOREIGN
 //     "cookieBehaviorPBM2": cookie behaviour BEHAVIOR_REJECT
 //     "cookieBehaviorPBM3": cookie behaviour BEHAVIOR_LIMIT_FOREIGN
 //     "cookieBehaviorPBM4": cookie behaviour BEHAVIOR_REJECT_TRACKER
 //     "cookieBehaviorPBM5": cookie behaviour BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN
 // One value from each section must be included in the browser.contentblocking.features.strict pref.
-pref("browser.contentblocking.features.strict", "tp,tpPrivate,cookieBehavior5,cookieBehaviorPBM5,cm,fp,stp,lvl2,rp");
+pref("browser.contentblocking.features.strict", "tp,tpPrivate,cookieBehavior5,cookieBehaviorPBM5,cm,fp,stp,lvl2,rp,ocsp");
 
 // Hide the "Change Block List" link for trackers/tracking content in the custom
 // Content Blocking/ETP panel. By default, it will not be visible. There is also
 // an UI migration in place to set this pref to true if a user has a custom block
 // lists enabled.
 pref("browser.contentblocking.customBlockList.preferences.ui.enabled", false);
 
 pref("browser.contentblocking.reportBreakage.url", "https://tracking-protection-issues.herokuapp.com/new");
--- a/browser/components/BrowserGlue.jsm
+++ b/browser/components/BrowserGlue.jsm
@@ -1317,16 +1317,20 @@ BrowserGlue.prototype = {
       "network.cookie.cookieBehavior.pbmode",
       this._matchCBCategory
     );
     Services.prefs.removeObserver(
       "network.http.referer.disallowCrossSiteRelaxingDefault",
       this._matchCBCategory
     );
     Services.prefs.removeObserver(
+      "privacy.partition.network_state.ocsp_cache",
+      this._matchCBCategory
+    );
+    Services.prefs.removeObserver(
       ContentBlockingCategoriesPrefs.PREF_CB_CATEGORY,
       this._updateCBCategory
     );
     Services.prefs.removeObserver(
       "privacy.trackingprotection",
       this._setPrefExpectations
     );
     Services.prefs.removeObserver(
@@ -1762,16 +1766,20 @@ BrowserGlue.prototype = {
       "network.cookie.cookieBehavior.pbmode",
       this._matchCBCategory
     );
     Services.prefs.addObserver(
       "network.http.referer.disallowCrossSiteRelaxingDefault",
       this._matchCBCategory
     );
     Services.prefs.addObserver(
+      "privacy.partition.network_state.ocsp_cache",
+      this._matchCBCategory
+    );
+    Services.prefs.addObserver(
       ContentBlockingCategoriesPrefs.PREF_CB_CATEGORY,
       this._updateCBCategory
     );
     Services.prefs.addObserver(
       "media.autoplay.default",
       this._updateAutoplayPref
     );
     Services.prefs.addObserver(
@@ -4365,27 +4373,29 @@ var ContentBlockingCategoriesPrefs = {
         "network.cookie.cookieBehavior.pbmode": null,
         "privacy.trackingprotection.pbmode.enabled": null,
         "privacy.trackingprotection.enabled": null,
         "privacy.trackingprotection.socialtracking.enabled": null,
         "privacy.trackingprotection.fingerprinting.enabled": null,
         "privacy.trackingprotection.cryptomining.enabled": null,
         "privacy.annotate_channels.strict_list.enabled": null,
         "network.http.referer.disallowCrossSiteRelaxingDefault": null,
+        "privacy.partition.network_state.ocsp_cache": null,
       },
       standard: {
         "network.cookie.cookieBehavior": null,
         "network.cookie.cookieBehavior.pbmode": null,
         "privacy.trackingprotection.pbmode.enabled": null,
         "privacy.trackingprotection.enabled": null,
         "privacy.trackingprotection.socialtracking.enabled": null,
         "privacy.trackingprotection.fingerprinting.enabled": null,
         "privacy.trackingprotection.cryptomining.enabled": null,
         "privacy.annotate_channels.strict_list.enabled": null,
         "network.http.referer.disallowCrossSiteRelaxingDefault": null,
+        "privacy.partition.network_state.ocsp_cache": null,
       },
     };
     let type = "strict";
     let rulesArray = Services.prefs
       .getStringPref(this.PREF_STRICT_DEF)
       .split(",");
     for (let item of rulesArray) {
       switch (item) {
@@ -4454,16 +4464,26 @@ var ContentBlockingCategoriesPrefs = {
             "network.http.referer.disallowCrossSiteRelaxingDefault"
           ] = true;
           break;
         case "-rp":
           this.CATEGORY_PREFS[type][
             "network.http.referer.disallowCrossSiteRelaxingDefault"
           ] = false;
           break;
+        case "ocsp":
+          this.CATEGORY_PREFS[type][
+            "privacy.partition.network_state.ocsp_cache"
+          ] = true;
+          break;
+        case "-ocsp":
+          this.CATEGORY_PREFS[type][
+            "privacy.partition.network_state.ocsp_cache"
+          ] = false;
+          break;
         case "cookieBehavior0":
           this.CATEGORY_PREFS[type]["network.cookie.cookieBehavior"] =
             Ci.nsICookieService.BEHAVIOR_ACCEPT;
           break;
         case "cookieBehavior1":
           this.CATEGORY_PREFS[type]["network.cookie.cookieBehavior"] =
             Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN;
           break;
--- a/browser/components/preferences/tests/browser_contentblocking.js
+++ b/browser/components/preferences/tests/browser_contentblocking.js
@@ -11,16 +11,17 @@ const TP_PBM_PREF = "privacy.trackingpro
 const NCB_PREF = "network.cookie.cookieBehavior";
 const NCBP_PREF = "network.cookie.cookieBehavior.pbmode";
 const CAT_PREF = "browser.contentblocking.category";
 const FP_PREF = "privacy.trackingprotection.fingerprinting.enabled";
 const STP_PREF = "privacy.trackingprotection.socialtracking.enabled";
 const CM_PREF = "privacy.trackingprotection.cryptomining.enabled";
 const LEVEL2_PREF = "privacy.annotate_channels.strict_list.enabled";
 const REFERRER_PREF = "network.http.referer.disallowCrossSiteRelaxingDefault";
+const OCSP_PREF = "privacy.partition.network_state.ocsp_cache";
 const PREF_TEST_NOTIFICATIONS =
   "browser.safebrowsing.test-notifications.enabled";
 const STRICT_PREF = "browser.contentblocking.features.strict";
 const PRIVACY_PAGE = "about:preferences#privacy";
 const ISOLATE_UI_PREF =
   "browser.contentblocking.reject-and-isolate-cookies.preferences.ui.enabled";
 const FPI_PREF = "privacy.firstparty.isolate";
 
@@ -312,16 +313,17 @@ add_task(async function testContentBlock
     [TP_PBM_PREF]: null,
     [NCB_PREF]: null,
     [NCBP_PREF]: null,
     [FP_PREF]: null,
     [STP_PREF]: null,
     [CM_PREF]: null,
     [LEVEL2_PREF]: null,
     [REFERRER_PREF]: null,
+    [OCSP_PREF]: null,
   };
 
   for (let pref in prefs) {
     Services.prefs.clearUserPref(pref);
     switch (Services.prefs.getPrefType(pref)) {
       case Services.prefs.PREF_BOOL:
         prefs[pref] = Services.prefs.getBoolPref(pref);
         break;
@@ -352,16 +354,17 @@ add_task(async function testContentBlock
   Services.prefs.setBoolPref(
     LEVEL2_PREF,
     !Services.prefs.getBoolPref(LEVEL2_PREF)
   );
   Services.prefs.setBoolPref(
     REFERRER_PREF,
     !Services.prefs.getBoolPref(REFERRER_PREF)
   );
+  Services.prefs.setBoolPref(OCSP_PREF, !Services.prefs.getBoolPref(OCSP_PREF));
 
   for (let pref in prefs) {
     switch (Services.prefs.getPrefType(pref)) {
       case Services.prefs.PREF_BOOL:
         // Account for prefs that may have retained their default value
         if (Services.prefs.getBoolPref(pref) != prefs[pref]) {
           ok(
             Services.prefs.prefHasUserValue(pref),
@@ -414,16 +417,17 @@ add_task(async function testContentBlock
 });
 
 // Tests that the content blocking "Strict" category radio sets the prefs to the expected values.
 add_task(async function testContentBlockingStrictCategory() {
   Services.prefs.setBoolPref(TP_PREF, false);
   Services.prefs.setBoolPref(TP_PBM_PREF, false);
   Services.prefs.setBoolPref(LEVEL2_PREF, false);
   Services.prefs.setBoolPref(REFERRER_PREF, false);
+  Services.prefs.setBoolPref(OCSP_PREF, false);
   Services.prefs.setIntPref(
     NCB_PREF,
     Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN
   );
   Services.prefs.setIntPref(
     NCBP_PREF,
     Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN
   );
@@ -536,16 +540,30 @@ add_task(async function testContentBlock
         break;
       case "-rp":
         is(
           Services.prefs.getBoolPref(REFERRER_PREF),
           false,
           `${REFERRER_PREF} has been set to false`
         );
         break;
+      case "ocsp":
+        is(
+          Services.prefs.getBoolPref(OCSP_PREF),
+          true,
+          `${OCSP_PREF} has been set to true`
+        );
+        break;
+      case "-ocsp":
+        is(
+          Services.prefs.getBoolPref(OCSP_PREF),
+          false,
+          `${OCSP_PREF} has been set to false`
+        );
+        break;
       case "cookieBehavior0":
         is(
           Services.prefs.getIntPref(NCB_PREF),
           Ci.nsICookieService.BEHAVIOR_ACCEPT,
           `${NCB_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_ACCEPT}`
         );
         break;
       case "cookieBehavior1":
@@ -640,16 +658,17 @@ add_task(async function testContentBlock
     TP_PREF,
     TP_PBM_PREF,
     NCB_PREF,
     NCBP_PREF,
     FP_PREF,
     STP_PREF,
     CM_PREF,
     REFERRER_PREF,
+    OCSP_PREF,
   ];
 
   await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
   let doc = gBrowser.contentDocument;
   let strictRadioOption = doc.getElementById("strictRadio");
   let standardRadioOption = doc.getElementById("standardRadio");
   let customRadioOption = doc.getElementById("customRadio");
   let defaults = new Preferences({ defaultBranch: true });
@@ -687,16 +706,17 @@ add_task(async function testContentBlock
   // Changing the following prefs should necessarily set CAT_PREF to "custom"
   for (let pref of [
     FP_PREF,
     STP_PREF,
     CM_PREF,
     TP_PREF,
     TP_PBM_PREF,
     REFERRER_PREF,
+    OCSP_PREF,
   ]) {
     Services.prefs.setBoolPref(pref, !Services.prefs.getBoolPref(pref));
     await TestUtils.waitForCondition(
       () => Services.prefs.getStringPref(CAT_PREF) == "custom"
     );
     is(
       Services.prefs.getStringPref(CAT_PREF),
       "custom",
--- a/browser/components/preferences/tests/browser_contentblocking_categories.js
+++ b/browser/components/preferences/tests/browser_contentblocking_categories.js
@@ -14,16 +14,17 @@ const TP_PBM_PREF = "privacy.trackingpro
 const NCB_PREF = "network.cookie.cookieBehavior";
 const NCBP_PREF = "network.cookie.cookieBehavior.pbmode";
 const CAT_PREF = "browser.contentblocking.category";
 const FP_PREF = "privacy.trackingprotection.fingerprinting.enabled";
 const CM_PREF = "privacy.trackingprotection.cryptomining.enabled";
 const STP_PREF = "privacy.trackingprotection.socialtracking.enabled";
 const LEVEL2_PREF = "privacy.annotate_channels.strict_list.enabled";
 const REFERRER_PREF = "network.http.referer.disallowCrossSiteRelaxingDefault";
+const OCSP_PREF = "privacy.partition.network_state.ocsp_cache";
 const STRICT_DEF_PREF = "browser.contentblocking.features.strict";
 
 // Tests that the content blocking standard category definition is based on the default settings of
 // the content blocking prefs.
 // Changing the definition does not remove the user from the category.
 add_task(async function testContentBlockingStandardDefinition() {
   Services.prefs.setStringPref(CAT_PREF, "strict");
   Services.prefs.setStringPref(CAT_PREF, "standard");
@@ -64,27 +65,32 @@ add_task(async function testContentBlock
   ok(
     !Services.prefs.prefHasUserValue(LEVEL2_PREF),
     `${LEVEL2_PREF} pref has the default value`
   );
   ok(
     !Services.prefs.prefHasUserValue(REFERRER_PREF),
     `${REFERRER_PREF} pref has the default value`
   );
+  ok(
+    !Services.prefs.prefHasUserValue(OCSP_PREF),
+    `${OCSP_PREF} pref has the default value`
+  );
 
   let defaults = Services.prefs.getDefaultBranch("");
   let originalTP = defaults.getBoolPref(TP_PREF);
   let originalTPPBM = defaults.getBoolPref(TP_PBM_PREF);
   let originalFP = defaults.getBoolPref(FP_PREF);
   let originalCM = defaults.getBoolPref(CM_PREF);
   let originalSTP = defaults.getBoolPref(STP_PREF);
   let originalNCB = defaults.getIntPref(NCB_PREF);
   let originalNCBP = defaults.getIntPref(NCBP_PREF);
   let originalLEVEL2 = defaults.getBoolPref(LEVEL2_PREF);
   let originalREFERRER = defaults.getBoolPref(REFERRER_PREF);
+  let originalOCSP = defaults.getBoolPref(OCSP_PREF);
 
   let nonDefaultNCB;
   switch (originalNCB) {
     case Ci.nsICookieService.BEHAVIOR_ACCEPT:
       nonDefaultNCB = Ci.nsICookieService.BEHAVIOR_REJECT;
       break;
     default:
       nonDefaultNCB = Ci.nsICookieService.BEHAVIOR_ACCEPT;
@@ -104,16 +110,17 @@ add_task(async function testContentBlock
   defaults.setBoolPref(TP_PREF, !originalTP);
   defaults.setBoolPref(TP_PBM_PREF, !originalTPPBM);
   defaults.setBoolPref(FP_PREF, !originalFP);
   defaults.setBoolPref(CM_PREF, !originalCM);
   defaults.setBoolPref(CM_PREF, !originalSTP);
   defaults.setIntPref(NCB_PREF, !originalNCB);
   defaults.setBoolPref(LEVEL2_PREF, !originalLEVEL2);
   defaults.setBoolPref(REFERRER_PREF, !originalREFERRER);
+  defaults.setBoolPref(OCSP_PREF, !originalOCSP);
 
   ok(
     !Services.prefs.prefHasUserValue(TP_PREF),
     `${TP_PREF} pref has the default value`
   );
   ok(
     !Services.prefs.prefHasUserValue(TP_PBM_PREF),
     `${TP_PBM_PREF} pref has the default value`
@@ -141,54 +148,59 @@ add_task(async function testContentBlock
   ok(
     !Services.prefs.prefHasUserValue(LEVEL2_PREF),
     `${LEVEL2_PREF} pref has the default value`
   );
   ok(
     !Services.prefs.prefHasUserValue(REFERRER_PREF),
     `${REFERRER_PREF} pref has the default value`
   );
+  ok(
+    !Services.prefs.prefHasUserValue(OCSP_PREF),
+    `${OCSP_PREF} pref has the default value`
+  );
 
   // cleanup
   defaults.setIntPref(NCB_PREF, originalNCB);
   defaults.setBoolPref(TP_PREF, originalTP);
   defaults.setBoolPref(TP_PBM_PREF, originalTPPBM);
   defaults.setBoolPref(FP_PREF, originalFP);
   defaults.setBoolPref(CM_PREF, originalCM);
   defaults.setBoolPref(STP_PREF, originalSTP);
   defaults.setIntPref(NCB_PREF, originalNCB);
   defaults.setIntPref(NCBP_PREF, originalNCBP);
   defaults.setBoolPref(LEVEL2_PREF, originalLEVEL2);
   defaults.setBoolPref(REFERRER_PREF, originalREFERRER);
+  defaults.setBoolPref(OCSP_PREF, originalOCSP);
 });
 
 // Tests that the content blocking strict category definition changes the behavior
 // of the strict category pref and all prefs it controls.
 // Changing the definition does not remove the user from the category.
 add_task(async function testContentBlockingStrictDefinition() {
   let defaults = Services.prefs.getDefaultBranch("");
   let originalStrictPref = defaults.getStringPref(STRICT_DEF_PREF);
   defaults.setStringPref(
     STRICT_DEF_PREF,
-    "tp,tpPrivate,fp,cm,cookieBehavior0,cookieBehaviorPBM0,stp,lvl2,rp"
+    "tp,tpPrivate,fp,cm,cookieBehavior0,cookieBehaviorPBM0,stp,lvl2,rp,ocsp"
   );
   Services.prefs.setStringPref(CAT_PREF, "strict");
   is(
     Services.prefs.getStringPref(CAT_PREF),
     "strict",
     `${CAT_PREF} has changed to strict`
   );
 
   ok(
     !Services.prefs.prefHasUserValue(STRICT_DEF_PREF),
     `We changed the default value of ${STRICT_DEF_PREF}`
   );
   is(
     Services.prefs.getStringPref(STRICT_DEF_PREF),
-    "tp,tpPrivate,fp,cm,cookieBehavior0,cookieBehaviorPBM0,stp,lvl2,rp",
+    "tp,tpPrivate,fp,cm,cookieBehavior0,cookieBehaviorPBM0,stp,lvl2,rp,ocsp",
     `${STRICT_DEF_PREF} changed to what we set.`
   );
 
   is(
     Services.prefs.getBoolPref(TP_PREF),
     true,
     `${TP_PREF} pref has been set to true`
   );
@@ -227,16 +239,21 @@ add_task(async function testContentBlock
     true,
     `${LEVEL2_PREF} pref has been set to true`
   );
   is(
     Services.prefs.getBoolPref(REFERRER_PREF),
     true,
     `${REFERRER_PREF} pref has been set to true`
   );
+  is(
+    Services.prefs.getBoolPref(OCSP_PREF),
+    true,
+    `${OCSP_PREF} pref has been set to true`
+  );
 
   // Note, if a pref is not listed it will use the default value, however this is only meant as a
   // backup if a mistake is made. The UI will not respond correctly.
   defaults.setStringPref(STRICT_DEF_PREF, "");
   ok(
     !Services.prefs.prefHasUserValue(TP_PREF),
     `${TP_PREF} pref has the default value`
   );
@@ -267,20 +284,24 @@ add_task(async function testContentBlock
   ok(
     !Services.prefs.prefHasUserValue(LEVEL2_PREF),
     `${LEVEL2_PREF} pref has the default value`
   );
   ok(
     !Services.prefs.prefHasUserValue(REFERRER_PREF),
     `${REFERRER_PREF} pref has the default value`
   );
+  ok(
+    !Services.prefs.prefHasUserValue(OCSP_PREF),
+    `${OCSP_PREF} pref has the default value`
+  );
 
   defaults.setStringPref(
     STRICT_DEF_PREF,
-    "-tpPrivate,-fp,-cm,-tp,cookieBehavior3,cookieBehaviorPBM2,-stp,-lvl2,-rp"
+    "-tpPrivate,-fp,-cm,-tp,cookieBehavior3,cookieBehaviorPBM2,-stp,-lvl2,-rp,-ocsp"
   );
   is(
     Services.prefs.getBoolPref(TP_PREF),
     false,
     `${TP_PREF} pref has been set to false`
   );
   is(
     Services.prefs.getBoolPref(TP_PBM_PREF),
@@ -317,13 +338,18 @@ add_task(async function testContentBlock
     false,
     `${LEVEL2_PREF} pref has been set to false`
   );
   is(
     Services.prefs.getBoolPref(REFERRER_PREF),
     false,
     `${REFERRER_PREF} pref has been set to false`
   );
+  is(
+    Services.prefs.getBoolPref(OCSP_PREF),
+    false,
+    `${OCSP_PREF} pref has been set to false`
+  );
 
   // cleanup
   defaults.setStringPref(STRICT_DEF_PREF, originalStrictPref);
   Services.prefs.setStringPref(CAT_PREF, "standard");
 });
--- a/browser/components/preferences/tests/browser_statePartitioning_PBM_strings.js
+++ b/browser/components/preferences/tests/browser_statePartitioning_PBM_strings.js
@@ -101,24 +101,24 @@ add_task(async function runTests() {
     Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN,
     false
   );
 
   // Test if the cookie blocking info is hidden for strict mode if
   // cookieBehaviors both are BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN in
   // the strict feature value.
   await testCookieBlockingInfoStrict(
-    "tp,tpPrivate,cookieBehavior5,cookieBehaviorPBM5,cm,fp,stp,lvl2,rp",
+    "tp,tpPrivate,cookieBehavior5,cookieBehaviorPBM5,cm,fp,stp,lvl2,rp,ocsp",
     false
   );
 
   // Test if the cookie blocking info is shown for strict mode if the regular
   // cookieBehavior is BEHAVIOR_REJECT_TRACKER and the private cookieBehavior is
   // BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN
   await testCookieBlockingInfoStrict(
-    "tp,tpPrivate,cookieBehavior4,cookieBehaviorPBM5,cm,fp,stp,lvl2,rp",
+    "tp,tpPrivate,cookieBehavior4,cookieBehaviorPBM5,cm,fp,stp,lvl2,rp,ocsp",
     true
   );
 
   defaults.setIntPref(COOKIE_BEHAVIOR_PREF, originalCookieBehavior);
   defaults.setIntPref(COOKIE_BEHAVIOR_PBM_PREF, originalCookieBehaviorPBM);
   await SpecialPowers.popPrefEnv();
 });
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -3655,16 +3655,18 @@ nsDocShell::DisplayLoadError(nsresult aE
         error = "corruptedContentErrorv2";
         break;
       case NS_ERROR_NET_INADEQUATE_SECURITY:
         // Server negotiated bad TLS for HTTP/2.
         error = "inadequateSecurityError";
         addHostPort = true;
         break;
       case NS_ERROR_BLOCKED_BY_POLICY:
+      case NS_ERROR_DOM_COOP_FAILED:
+      case NS_ERROR_DOM_COEP_FAILED:
         // Page blocked by policy
         error = "blockedByPolicy";
         break;
       case NS_ERROR_NET_HTTP2_SENT_GOAWAY:
       case NS_ERROR_NET_HTTP3_PROTOCOL_ERROR:
         // HTTP/2 or HTTP/3 stack detected a protocol error
         error = "networkProtocolError";
         break;
@@ -6143,17 +6145,19 @@ nsresult nsDocShell::FilterStatusForErro
        aStatus == NS_ERROR_CONNECTION_REFUSED ||
        aStatus == NS_ERROR_UNKNOWN_PROXY_HOST ||
        aStatus == NS_ERROR_PROXY_CONNECTION_REFUSED ||
        aStatus == NS_ERROR_PROXY_FORBIDDEN ||
        aStatus == NS_ERROR_PROXY_NOT_IMPLEMENTED ||
        aStatus == NS_ERROR_PROXY_AUTHENTICATION_FAILED ||
        aStatus == NS_ERROR_PROXY_TOO_MANY_REQUESTS ||
        aStatus == NS_ERROR_MALFORMED_URI ||
-       aStatus == NS_ERROR_BLOCKED_BY_POLICY) &&
+       aStatus == NS_ERROR_BLOCKED_BY_POLICY ||
+       aStatus == NS_ERROR_DOM_COOP_FAILED ||
+       aStatus == NS_ERROR_DOM_COEP_FAILED) &&
       (aIsTopFrame || aUseErrorPages)) {
     return aStatus;
   }
 
   if (aStatus == NS_ERROR_NET_TIMEOUT ||
       aStatus == NS_ERROR_NET_TIMEOUT_EXTERNAL ||
       aStatus == NS_ERROR_PROXY_GATEWAY_TIMEOUT ||
       aStatus == NS_ERROR_REDIRECT_LOOP ||
--- a/dom/html/test/test_bug448166.html
+++ b/dom/html/test/test_bug448166.html
@@ -1,14 +1,15 @@
 <!DOCTYPE HTML>
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=448166
 -->
 <head>
+  <meta charset="utf-8" />
   <title>Test for Bug 448166</title>
   <script src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=448166">Mozilla Bug 448166</a>
 <p id="display">
   <a id="test" href="http://www.moz&#xdc00;illa.org">should not be Mozilla</a>
@@ -18,18 +19,21 @@ https://bugzilla.mozilla.org/show_bug.cg
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 448166 **/
 isnot($("test").href, "http://www.mozilla.org/",
       "Should notice unpaired surrogate");
-is($("test").href, "http://www.xn--mozilla-2e14b.org/",
-      "Should replace unpaired surrogate with replacement char");
+is($("test").href, "http://www.moz�illa.org",
+      "URL parser fails. Href returns original input string");
+
+SimpleTest.doesThrow(() => { new URL($("test").href);}, "URL parser rejects input");
+
 is($("control").href, "http://www.mozilla.org/",
       "Just making sure .href works");
 
 </script>
 </pre>
 </body>
 </html>
 
new file mode 100644
--- /dev/null
+++ b/js/src/fuzz-tests/gluesmith/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "gluesmith"
+version = "0.1.0"
+authors = ["Christian Holler"]
+license = "MPL 2.0"
+
+[dependencies]
+wasm-smith = "0.7.2"
+arbitrary = { version = "1.0.0", features = ["derive"] }
+libc = "0.2"
new file mode 100644
--- /dev/null
+++ b/js/src/fuzz-tests/gluesmith/moz.build
@@ -0,0 +1,15 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+FINAL_LIBRARY = "js"
+
+# Includes should be relative to parent path
+LOCAL_INCLUDES += ["!../..", "../.."]
+
+include("../../js-config.mozbuild")
+include("../../js-cxxflags.mozbuild")
+
+DIRS += ["../../rust"]
new file mode 100644
--- /dev/null
+++ b/js/src/fuzz-tests/gluesmith/src/lib.rs
@@ -0,0 +1,52 @@
+/* Copyright 2021 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.
+ */
+
+extern crate arbitrary;
+extern crate wasm_smith;
+
+use arbitrary::{Arbitrary, Unstructured};
+use wasm_smith::Module;
+
+use std::ptr;
+
+#[no_mangle]
+pub unsafe extern "C" fn gluesmith(
+    data: *mut u8,
+    len: usize,
+    out: *mut u8,
+    maxlen: usize,
+) -> usize {
+    let buf: &[u8] = std::slice::from_raw_parts(data, len);
+
+    let mut u = Unstructured::new(buf);
+
+    let module = match Module::arbitrary(&mut u) {
+        Ok(m) => m,
+        Err(_e) => return 0,
+    };
+
+    let wasm_bytes = module.to_bytes();
+
+    let src_len = wasm_bytes.len();
+
+    if src_len > maxlen {
+        return 0;
+    }
+
+    let src_ptr = wasm_bytes.as_ptr();
+    ptr::copy_nonoverlapping(src_ptr, out, src_len);
+
+    return src_len;
+}
--- a/js/src/fuzz-tests/moz.build
+++ b/js/src/fuzz-tests/moz.build
@@ -34,13 +34,14 @@ if CONFIG["FUZZING"]:
 
 if CONFIG["FUZZING_INTERFACES"]:
     USE_LIBS += [
         "static:fuzzer",
     ]
 
 USE_LIBS += [
     "static:js",
+    "static:jsrust",
 ]
 
 DEFINES["topsrcdir"] = "%s/js/src" % TOPSRCDIR
 
 REQUIRES_UNIFIED_BUILD = True
--- a/js/src/fuzz-tests/testWasm.cpp
+++ b/js/src/fuzz-tests/testWasm.cpp
@@ -25,25 +25,35 @@
 
 using namespace js;
 using namespace js::wasm;
 
 // These are defined and pre-initialized by the harness (in tests.cpp).
 extern JS::PersistentRootedObject gGlobal;
 extern JSContext* gCx;
 
+static bool gIsWasmSmith = false;
+extern "C" {
+size_t gluesmith(uint8_t* data, size_t size, uint8_t* out, size_t maxsize);
+}
+
 static int testWasmInit(int* argc, char*** argv) {
   if (!wasm::HasSupport(gCx) ||
       !GlobalObject::getOrCreateConstructor(gCx, JSProto_WebAssembly)) {
     MOZ_CRASH("Failed to initialize wasm support");
   }
 
   return 0;
 }
 
+static int testWasmSmithInit(int* argc, char*** argv) {
+  gIsWasmSmith = true;
+  return testWasmInit(argc, argv);
+}
+
 static bool emptyNativeFunction(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   args.rval().setUndefined();
   return true;
 }
 
 static bool callExportedFunc(HandleFunction func,
                              MutableHandleValue lastReturnVal) {
@@ -119,32 +129,51 @@ static int testWasmFuzz(const uint8_t* b
   // Store the last return value so we can pass it in as an argument during
   // the next call (which can be on another module as well).
   RootedValue lastReturnVal(gCx);
 
   while (size - currentIndex >= MINIMUM_MODULE_SIZE + 1) {
     // Ensure we have no lingering exceptions from previous modules
     gCx->clearPendingException();
 
-    unsigned char moduleLen = buf[currentIndex];
-    currentIndex++;
+    uint16_t moduleLen;
+    if (gIsWasmSmith) {
+      // Jump over the optByte. Unlike with the regular format, for
+      // wasm-smith we are fixing this and use byte 0 as opt-byte.
+      // Eventually this will also be changed for the regular format.
+      if (!currentIndex) {
+        currentIndex++;
+      }
+
+      // Caller ensures the structural soundness of the input here
+      moduleLen = *((uint16_t*)&buf[currentIndex]);
+      currentIndex += 2;
+    } else {
+      moduleLen = buf[currentIndex];
+      currentIndex++;
+    }
 
     if (size - currentIndex < moduleLen) {
       moduleLen = size - currentIndex;
     }
 
     if (moduleLen < MINIMUM_MODULE_SIZE) {
       continue;
     }
 
-    if (currentIndex == 1) {
+    if (currentIndex == 1 || (gIsWasmSmith && currentIndex == 3)) {
       // If this is the first module we are reading, we use the first
       // few bytes to tweak some settings. These are fixed anyway and
       // overwritten later on.
-      uint8_t optByte = (uint8_t)buf[currentIndex];
+      uint8_t optByte;
+      if (gIsWasmSmith) {
+        optByte = (uint8_t)buf[0];
+      } else {
+        optByte = (uint8_t)buf[currentIndex];
+      }
 
       // Note that IonPlatformSupport() and CraneliftPlatformSupport() do not
       // take into account whether those compilers support particular features
       // that may have been enabled.
       bool enableWasmBaseline = ((optByte & 0xF0) == (1 << 7));
       bool enableWasmOptimizing = false;
 #ifdef ENABLE_WASM_CRANELIFT
       // Cranelift->Ion transition
@@ -193,16 +222,25 @@ static int testWasmFuzz(const uint8_t* b
 #endif
           .setTestWasmAwaitTier2(enableWasmAwaitTier2);
     }
 
     // Expected header for a valid WebAssembly module
     uint32_t magic_header = 0x6d736100;
     uint32_t magic_version = 0x1;
 
+    if (gIsWasmSmith) {
+      // When using wasm-smith, magic values should already be there.
+      // Checking this to make sure the data passed is sane.
+      MOZ_RELEASE_ASSERT(*(uint32_t*)(&buf[currentIndex]) == magic_header,
+                         "Magic header mismatch!");
+      MOZ_RELEASE_ASSERT(*(uint32_t*)(&buf[currentIndex + 4]) == magic_version,
+                         "Magic version mismatch!");
+    }
+
     // We just skip over the first 8 bytes now because we fill them
     // with `magic_header` and `magic_version` anyway.
     currentIndex += 8;
     moduleLen -= 8;
 
     RootedWasmInstanceObject instanceObj(gCx);
 
     MutableBytes bytecode = gCx->new_<ShareableBytes>();
@@ -446,9 +484,73 @@ static int testWasmFuzz(const uint8_t* b
         }
       }
     }
   }
 
   return 0;
 }
 
+static int testWasmSmithFuzz(const uint8_t* buf, size_t size) {
+  // Define maximum sizes for the input to wasm-smith as well
+  // as the resulting modules. The input to output size factor
+  // of wasm-smith is somewhat variable but a factor of 4 seems
+  // to roughly work out. The logic below also assumes that these
+  // are powers of 2.
+  const size_t maxInputSize = 1024;
+  const size_t maxModuleSize = 4096;
+
+  size_t maxModules = size / maxInputSize + 1;
+
+  // We need 1 leading byte for options and 2 bytes for size per module
+  uint8_t* out =
+      new uint8_t[1 + maxModules * (maxModuleSize + sizeof(uint16_t))];
+
+  auto deleteGuard = mozilla::MakeScopeExit([&] { delete[] out; });
+
+  // Copy the opt-byte.
+  out[0] = buf[0];
+
+  size_t outIndex = 1;
+  size_t currentIndex = 1;
+
+  while (currentIndex < size) {
+    size_t remaining = size - currentIndex;
+
+    // We need to have at least a size and some byte to read.
+    if (remaining <= sizeof(uint16_t)) {
+      break;
+    }
+
+    // Determine size of the next input, limited to `maxInputSize`.
+    uint16_t inSize =
+        (*((uint16_t*)&buf[currentIndex]) & (maxInputSize - 1)) + 1;
+    remaining -= sizeof(uint16_t);
+    currentIndex += sizeof(uint16_t);
+
+    // Cap to remaining bytes.
+    inSize = remaining >= inSize ? inSize : remaining;
+
+    size_t outSize =
+        gluesmith((uint8_t*)&buf[currentIndex], inSize,
+                  out + outIndex + sizeof(uint16_t), maxModuleSize);
+
+    if (!outSize) {
+      break;
+    }
+
+    currentIndex += inSize;
+
+    // Write the size of the resulting module to our output buffer.
+    *(uint16_t*)(&out[outIndex]) = (uint16_t)outSize;
+    outIndex += sizeof(uint16_t) + outSize;
+  }
+
+  // If we lack at least one module, don't do anything.
+  if (outIndex == 1) {
+    return 0;
+  }
+
+  return testWasmFuzz(out, outIndex);
+}
+
 MOZ_FUZZING_INTERFACE_RAW(testWasmInit, testWasmFuzz, Wasm);
+MOZ_FUZZING_INTERFACE_RAW(testWasmSmithInit, testWasmSmithFuzz, WasmSmith);
--- a/js/src/gc/ArenaList.h
+++ b/js/src/gc/ArenaList.h
@@ -335,20 +335,20 @@ class ArenaLists {
   bool relocateArenas(Arena*& relocatedListOut, JS::GCReason reason,
                       js::SliceBudget& sliceBudget, gcstats::Statistics& stats);
 
   void queueForegroundObjectsForSweep(JSFreeOp* fop);
   void queueForegroundThingsForSweep();
 
   Arena* takeSweptEmptyArenas();
 
-  bool foregroundFinalize(JSFreeOp* fop, AllocKind thingKind,
-                          js::SliceBudget& sliceBudget,
-                          SortedArenaList& sweepList);
-  static void backgroundFinalize(JSFreeOp* fop, Arena* listHead, Arena** empty);
+  void setIncrementalSweptArenas(AllocKind kind, SortedArenaList& arenas);
+  void clearIncrementalSweptArenas();
+
+  void mergeFinalizedArenas(AllocKind thingKind, SortedArenaList& finalizedArenas);
 
   void setParallelAllocEnabled(bool enabled);
   void setParallelUnmarkEnabled(bool enabled);
 
   inline void mergeNewArenasInMarkPhase();
 
   void checkGCStateNotInUse();
   void checkSweepStateNotInUse();
@@ -374,22 +374,18 @@ class ArenaLists {
   }
 
   Arena*& arenasToSweep(AllocKind i) { return arenasToSweep_.ref()[i]; }
   Arena* arenasToSweep(AllocKind i) const { return arenasToSweep_.ref()[i]; }
 
   inline JSRuntime* runtime();
   inline JSRuntime* runtimeFromAnyThread();
 
-  inline void queueForForegroundSweep(JSFreeOp* fop,
-                                      const FinalizePhase& phase);
-  inline void queueForBackgroundSweep(JSFreeOp* fop,
-                                      const FinalizePhase& phase);
-  inline void queueForForegroundSweep(AllocKind thingKind);
-  inline void queueForBackgroundSweep(AllocKind thingKind);
+  void queueForForegroundSweep(AllocKind thingKind);
+  void queueForBackgroundSweep(AllocKind thingKind);
 
   TenuredCell* refillFreeListAndAllocate(FreeLists& freeLists,
                                          AllocKind thingKind,
                                          ShouldCheckThresholds checkThresholds);
 
   void addNewArena(Arena* arena, AllocKind thingKind);
 
   friend class GCRuntime;
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -1585,59 +1585,57 @@ bool GCRuntime::shouldCompact() {
          !IsCurrentlyAnimating(rt->lastAnimationTime, TimeStamp::Now());
 }
 
 bool GCRuntime::isCompactingGCEnabled() const {
   return compactingEnabled &&
          rt->mainContextFromOwnThread()->compactingDisabledCount == 0;
 }
 
-void ArenaLists::queueForForegroundSweep(JSFreeOp* fop,
-                                         const FinalizePhase& phase) {
-  gcstats::AutoPhase ap(fop->runtime()->gc.stats(), phase.statsPhase);
+void GCRuntime::queueForForegroundSweep(Zone* zone, JSFreeOp* fop,
+                                        const FinalizePhase& phase) {
+  gcstats::AutoPhase ap(stats(), phase.statsPhase);
   for (auto kind : phase.kinds) {
-    queueForForegroundSweep(kind);
+    zone->arenas.queueForForegroundSweep(kind);
   }
 }
 
 void ArenaLists::queueForForegroundSweep(AllocKind thingKind) {
   MOZ_ASSERT(!IsBackgroundFinalized(thingKind));
   MOZ_ASSERT(concurrentUse(thingKind) == ConcurrentUse::None);
   MOZ_ASSERT(!arenasToSweep(thingKind));
 
   arenasToSweep(thingKind) = arenaList(thingKind).head();
   arenaList(thingKind).clear();
 }
 
-void ArenaLists::queueForBackgroundSweep(JSFreeOp* fop,
-                                         const FinalizePhase& phase) {
-  gcstats::AutoPhase ap(fop->runtime()->gc.stats(), phase.statsPhase);
+void GCRuntime::queueForBackgroundSweep(Zone* zone, JSFreeOp* fop,
+                                        const FinalizePhase& phase) {
+  gcstats::AutoPhase ap(stats(), phase.statsPhase);
   for (auto kind : phase.kinds) {
-    queueForBackgroundSweep(kind);
-  }
-}
-
-inline void ArenaLists::queueForBackgroundSweep(AllocKind thingKind) {
+    zone->arenas.queueForBackgroundSweep(kind);
+  }
+}
+
+void ArenaLists::queueForBackgroundSweep(AllocKind thingKind) {
   MOZ_ASSERT(IsBackgroundFinalized(thingKind));
   MOZ_ASSERT(concurrentUse(thingKind) == ConcurrentUse::None);
 
-  ArenaList* al = &arenaList(thingKind);
-  arenasToSweep(thingKind) = al->head();
+  arenasToSweep(thingKind) = arenaList(thingKind).head();
   arenaList(thingKind).clear();
 
   if (arenasToSweep(thingKind)) {
     concurrentUse(thingKind) = ConcurrentUse::BackgroundFinalize;
   } else {
     arenaList(thingKind) = std::move(newArenasInMarkPhase(thingKind));
   }
 }
 
-/*static*/
-void ArenaLists::backgroundFinalize(JSFreeOp* fop, Arena* listHead,
-                                    Arena** empty) {
+void GCRuntime::backgroundFinalize(JSFreeOp* fop, Arena* listHead,
+                                   Arena** empty) {
   MOZ_ASSERT(listHead);
   MOZ_ASSERT(empty);
 
   AllocKind thingKind = listHead->getAllocKind();
   Zone* zone = listHead->zone;
 
   size_t thingsPerArena = Arena::thingsPerArena(thingKind);
   SortedArenaList finalizedSorted(thingsPerArena);
@@ -1648,42 +1646,47 @@ void ArenaLists::backgroundFinalize(JSFr
 
   finalizedSorted.extractEmpty(empty);
 
   // When arenas are queued for background finalization, all arenas are moved to
   // arenasToSweep, leaving the arena list empty. However, new arenas may be
   // allocated before background finalization finishes; now that finalization is
   // complete, we want to merge these lists back together.
   ArenaLists* lists = &zone->arenas;
-  ArenaList& al = lists->arenaList(thingKind);
-
-  // Flatten |finalizedSorted| into a regular ArenaList.
-  ArenaList finalized = finalizedSorted.toArenaList();
 
   // We must take the GC lock to be able to safely modify the ArenaList;
   // however, this does not by itself make the changes visible to all threads,
   // as not all threads take the GC lock to read the ArenaLists.
   // That safety is provided by the ReleaseAcquire memory ordering of the
   // background finalize state, which we explicitly set as the final step.
   {
-    AutoLockGC lock(lists->runtimeFromAnyThread());
+    AutoLockGC lock(rt);
     MOZ_ASSERT(lists->concurrentUse(thingKind) ==
-               ConcurrentUse::BackgroundFinalize);
-
-    // Join |al| and |finalized| into a single list.
-    ArenaList allocatedDuringSweep = std::move(al);
-    al = std::move(finalized);
-    al.insertListWithCursorAtEnd(lists->newArenasInMarkPhase(thingKind));
-    al.insertListWithCursorAtEnd(allocatedDuringSweep);
-
-    lists->newArenasInMarkPhase(thingKind).clear();
+               ArenaLists::ConcurrentUse::BackgroundFinalize);
+    lists->mergeFinalizedArenas(thingKind, finalizedSorted);
     lists->arenasToSweep(thingKind) = nullptr;
   }
 
-  lists->concurrentUse(thingKind) = ConcurrentUse::None;
+  lists->concurrentUse(thingKind) = ArenaLists::ConcurrentUse::None;
+}
+
+// After finalizing arenas, merge the following to get the final state of an
+// arena list:
+//  - arenas allocated during marking
+//  - arenas allocated during sweeping
+//  - finalized arenas
+void ArenaLists::mergeFinalizedArenas(AllocKind thingKind, SortedArenaList& finalizedArenas) {
+  ArenaList& arenas = arenaList(thingKind);
+
+  ArenaList allocatedDuringSweep = std::move(arenas);
+  arenas = finalizedArenas.toArenaList();
+  arenas.insertListWithCursorAtEnd(newArenasInMarkPhase(thingKind));
+  arenas.insertListWithCursorAtEnd(allocatedDuringSweep);
+
+  newArenasInMarkPhase(thingKind).clear();
 }
 
 void ArenaLists::queueForegroundThingsForSweep() {
   gcCompactPropMapArenasToUpdate = arenasToSweep(AllocKind::COMPACT_PROP_MAP);
   gcNormalPropMapArenasToUpdate = arenasToSweep(AllocKind::NORMAL_PROP_MAP);
 }
 
 SliceBudget::SliceBudget(TimeBudget time, int64_t stepsPerTimeCheckArg)
@@ -2095,17 +2098,17 @@ void GCRuntime::sweepBackgroundThings(Zo
 
     // We must finalize thing kinds in the order specified by
     // BackgroundFinalizePhases.
     for (auto phase : BackgroundFinalizePhases) {
       for (auto kind : phase.kinds) {
         Arena* arenas = zone->arenas.arenasToSweep(kind);
         MOZ_RELEASE_ASSERT(uintptr_t(arenas) != uintptr_t(-1));
         if (arenas) {
-          ArenaLists::backgroundFinalize(&fop, arenas, &emptyArenas);
+          backgroundFinalize(&fop, arenas, &emptyArenas);
         }
       }
     }
 
     // Release any arenas that are now empty.
     //
     // Empty arenas are only released after everything has been finalized so
     // that it's still possible to get a thing's zone after the thing has been
@@ -4194,20 +4197,20 @@ IncrementalProgress GCRuntime::beginSwee
   // parallel with that. This triggers a read barrier and can add marking work
   // for zones that are still marking.
   sweepFinalizationRegistriesOnMainThread();
 
   // Queue all GC things in all zones for sweeping, either on the foreground
   // or on the background thread.
 
   for (SweepGroupZonesIter zone(this); !zone.done(); zone.next()) {
-    zone->arenas.queueForForegroundSweep(fop, ForegroundObjectFinalizePhase);
-    zone->arenas.queueForForegroundSweep(fop, ForegroundNonObjectFinalizePhase);
+    queueForForegroundSweep(zone, fop, ForegroundObjectFinalizePhase);
+    queueForForegroundSweep(zone, fop, ForegroundNonObjectFinalizePhase);
     for (const auto& phase : BackgroundFinalizePhases) {
-      zone->arenas.queueForBackgroundSweep(fop, phase);
+      queueForBackgroundSweep(zone, fop, phase);
     }
 
     zone->arenas.queueForegroundThingsForSweep();
   }
 
   MOZ_ASSERT(!sweepZone);
 
   safeToYield = true;
@@ -4335,51 +4338,37 @@ void GCRuntime::beginSweepPhase(JS::GCRe
   AssertNoWrappersInGrayList(rt);
   dropStringWrappers();
 
   groupZonesForSweeping(reason);
 
   sweepActions->assertFinished();
 }
 
-bool ArenaLists::foregroundFinalize(JSFreeOp* fop, AllocKind thingKind,
-                                    SliceBudget& sliceBudget,
-                                    SortedArenaList& sweepList) {
-  checkNoArenasToUpdateForKind(thingKind);
-
-  // Arenas are released for use for new allocations as soon as the finalizers
-  // for that allocation kind have run. This means that a cell's finalizer can
-  // safely use IsAboutToBeFinalized to check other cells of the same alloc
-  // kind, but not of different alloc kinds: the other arena may have already
-  // had new objects allocated in it, and since we allocate black,
-  // IsAboutToBeFinalized will return false even though the referent we intended
-  // to check is long gone.
-  if (!FinalizeArenas(fop, &arenasToSweep(thingKind), sweepList, thingKind,
-                      sliceBudget)) {
+bool GCRuntime::foregroundFinalize(JSFreeOp* fop, Zone* zone,
+                                   AllocKind thingKind,
+                                   SliceBudget& sliceBudget,
+                                   SortedArenaList& sweepList) {
+  ArenaLists& lists = zone->arenas;
+  lists.checkNoArenasToUpdateForKind(thingKind);
+
+  // Non-empty arenas are reused for use for new allocations as soon as the
+  // finalizers for that allocation kind have run. Empty arenas are only
+  // released when everything in the zone has been swept (see
+  // GCRuntime::sweepBackgroundThings for more details).
+  if (!FinalizeArenas(fop, &lists.arenasToSweep(thingKind), sweepList,
+                      thingKind, sliceBudget)) {
     // Copy the current contents of sweepList so that ArenaIter can find them.
-    incrementalSweptArenaKind = thingKind;
-    incrementalSweptArenas.ref().clear();
-    incrementalSweptArenas = sweepList.toArenaList();
+    lists.setIncrementalSweptArenas(thingKind, sweepList);
     return false;
   }
 
-  // Clear the list of swept arenas now these are moving back to the main arena
-  // lists.
-  incrementalSweptArenaKind = AllocKind::LIMIT;
-  incrementalSweptArenas.ref().clear();
-
-  sweepList.extractEmpty(&savedEmptyArenas.ref());
-
-  ArenaList& al = arenaList(thingKind);
-  ArenaList allocatedDuringSweep = std::move(al);
-  al = sweepList.toArenaList();
-  al.insertListWithCursorAtEnd(newArenasInMarkPhase(thingKind));
-  al.insertListWithCursorAtEnd(allocatedDuringSweep);
-
-  newArenasInMarkPhase(thingKind).clear();
+  sweepList.extractEmpty(&lists.savedEmptyArenas.ref());
+  lists.mergeFinalizedArenas(thingKind, sweepList);
+  lists.clearIncrementalSweptArenas();
 
   return true;
 }
 
 BackgroundMarkTask::BackgroundMarkTask(GCRuntime* gc)
     : GCParallelTask(gc, gcstats::PhaseKind::SWEEP_MARK),
       budget(SliceBudget::unlimited()) {}
 
@@ -4586,18 +4575,17 @@ IncrementalProgress GCRuntime::finalizeA
 
   // Set the number of things per arena for this AllocKind.
   size_t thingsPerArena = Arena::thingsPerArena(sweepAllocKind);
   auto& sweepList = incrementalSweepList.ref();
   sweepList.setThingsPerArena(thingsPerArena);
 
   AutoSetThreadIsSweeping threadIsSweeping(sweepZone);
 
-  if (!sweepZone->arenas.foregroundFinalize(fop, sweepAllocKind, budget,
-                                            sweepList)) {
+  if (!foregroundFinalize(fop, sweepZone, sweepAllocKind, budget, sweepList)) {
     return NotFinished;
   }
 
   // Reset the slots of the sweep list that we used.
   sweepList.reset(thingsPerArena);
 
   return Finished;
 }
--- a/js/src/gc/GCAPI.cpp
+++ b/js/src/gc/GCAPI.cpp
@@ -513,16 +513,39 @@ static bool MinorGCCountGetter(JSContext
 }
 
 static bool GCSliceCountGetter(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   args.rval().setNumber(double(cx->runtime()->gc.gcSliceCount()));
   return true;
 }
 
+static bool GCCompartmentCount(JSContext* cx, unsigned argc, Value* vp) {
+  CallArgs args = CallArgsFromVp(argc, vp);
+  size_t count = 0;
+  for (ZonesIter zone(cx->runtime(), WithAtoms); !zone.done(); zone.next()) {
+    count += zone->compartments().length();
+  }
+
+  args.rval().setNumber(double(count));
+  return true;
+}
+
+static bool GCLastStartReason(JSContext* cx, unsigned argc, Value* vp) {
+  CallArgs args = CallArgsFromVp(argc, vp);
+  const char* reason = ExplainGCReason(cx->runtime()->gc.lastStartReason());
+  RootedString str(cx, JS_NewStringCopyZ(cx, reason));
+  if (!str) {
+    return false;
+  }
+
+  args.rval().setString(str);
+  return true;
+}
+
 static bool ZoneGCBytesGetter(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   args.rval().setNumber(double(cx->zone()->gcHeapSize.bytes()));
   return true;
 }
 
 static bool ZoneGCTriggerBytesGetter(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
@@ -580,17 +603,19 @@ JSObject* NewMemoryInfoObject(JSContext*
     JSNative getter;
   } getters[] = {{"gcBytes", GCBytesGetter},
                  {"gcMaxBytes", GCMaxBytesGetter},
                  {"mallocBytes", MallocBytesGetter},
                  {"gcIsHighFrequencyMode", GCHighFreqGetter},
                  {"gcNumber", GCNumberGetter},
                  {"majorGCCount", MajorGCCountGetter},
                  {"minorGCCount", MinorGCCountGetter},
-                 {"sliceCount", GCSliceCountGetter}};
+                 {"sliceCount", GCSliceCountGetter},
+                 {"compartmentCount", GCCompartmentCount},
+                 {"lastStartReason", GCLastStartReason}};
 
   for (auto pair : getters) {
     JSNative getter = pair.getter;
 
 #ifdef DEBUG
     if (js::SupportDifferentialTesting()) {
       getter = DummyGetter;
     }
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -616,16 +616,18 @@ class GCRuntime {
 
   void mergeRealms(JS::Realm* source, JS::Realm* target);
 
   // WeakRefs
   bool registerWeakRef(HandleObject target, HandleObject weakRef);
   bool unregisterWeakRefWrapper(JSObject* wrapper);
   void traceKeptObjects(JSTracer* trc);
 
+  JS::GCReason lastStartReason() const { return initialReason; }
+
  private:
   enum IncrementalResult { ResetIncremental = 0, Ok };
 
   TriggerResult checkHeapThreshold(Zone* zone, const HeapSize& heapSize,
                                    const HeapThreshold& heapThreshold);
 
   void updateGCThresholdsAfterCollection(const AutoLockGC& lock);
   void updateAllGCStartThresholds(const AutoLockGC& lock);
@@ -769,16 +771,21 @@ class GCRuntime {
   void getNextSweepGroup();
   IncrementalProgress markGrayRootsInCurrentGroup(JSFreeOp* fop,
                                                   SliceBudget& budget);
   IncrementalProgress markGray(JSFreeOp* fop, SliceBudget& budget);
   IncrementalProgress endMarkingSweepGroup(JSFreeOp* fop, SliceBudget& budget);
   void markIncomingGrayCrossCompartmentPointers();
   IncrementalProgress beginSweepingSweepGroup(JSFreeOp* fop,
                                               SliceBudget& budget);
+  void queueForForegroundSweep(Zone* zone, JSFreeOp* fop,
+                               const FinalizePhase& phase);
+  void queueForBackgroundSweep(Zone* zone, JSFreeOp* fop,
+                               const FinalizePhase& phase);
+
   IncrementalProgress markDuringSweeping(JSFreeOp* fop, SliceBudget& budget);
   void updateAtomsBitmap();
   void sweepCCWrappers();
   void sweepMisc();
   void sweepCompressionTasks();
   void sweepWeakMaps();
   void sweepUniqueIds();
   void sweepDebuggerOnMainThread(JSFreeOp* fop);
@@ -788,28 +795,32 @@ class GCRuntime {
   void queueFinalizationRegistryForCleanup(FinalizationQueueObject* queue);
   void sweepWeakRefs();
   IncrementalProgress endSweepingSweepGroup(JSFreeOp* fop, SliceBudget& budget);
   IncrementalProgress performSweepActions(SliceBudget& sliceBudget);
   void startSweepingAtomsTable();
   IncrementalProgress sweepAtomsTable(JSFreeOp* fop, SliceBudget& budget);
   IncrementalProgress sweepWeakCaches(JSFreeOp* fop, SliceBudget& budget);
   IncrementalProgress finalizeAllocKind(JSFreeOp* fop, SliceBudget& budget);
+  bool foregroundFinalize(JSFreeOp* fop, Zone* zone, AllocKind thingKind,
+                          js::SliceBudget& sliceBudget,
+                          SortedArenaList& sweepList);
   IncrementalProgress sweepPropMapTree(JSFreeOp* fop, SliceBudget& budget);
   void endSweepPhase(bool lastGC);
   bool allCCVisibleZonesWereCollected();
   void sweepZones(JSFreeOp* fop, bool destroyingRuntime);
   void startDecommit();
   void decommitFreeArenas(const bool& canel, AutoLockGC& lock);
   void decommitFreeArenasWithoutUnlocking(const AutoLockGC& lock);
   void queueZonesAndStartBackgroundSweep(ZoneList& zones);
   void sweepFromBackgroundThread(AutoLockHelperThreadState& lock);
   void startBackgroundFree();
   void freeFromBackgroundThread(AutoLockHelperThreadState& lock);
   void sweepBackgroundThings(ZoneList& zones);
+  void backgroundFinalize(JSFreeOp* fop, Arena* listHead, Arena** empty);
   void assertBackgroundSweepingFinished();
 
   // Compacting GC. Implemented in Compacting.cpp.
   bool shouldCompact();
   void beginCompactPhase();
   IncrementalProgress compactPhase(JS::GCReason reason,
                                    SliceBudget& sliceBudget,
                                    AutoGCSession& session);
--- a/js/src/gc/Heap.cpp
+++ b/js/src/gc/Heap.cpp
@@ -236,16 +236,28 @@ ArenaLists::~ArenaLists() {
 }
 
 Arena* ArenaLists::takeSweptEmptyArenas() {
   Arena* arenas = savedEmptyArenas;
   savedEmptyArenas = nullptr;
   return arenas;
 }
 
+void ArenaLists::setIncrementalSweptArenas(AllocKind kind,
+                                           SortedArenaList& arenas) {
+  incrementalSweptArenaKind = kind;
+  incrementalSweptArenas.ref().clear();
+  incrementalSweptArenas = arenas.toArenaList();
+}
+
+void ArenaLists::clearIncrementalSweptArenas() {
+  incrementalSweptArenaKind = AllocKind::LIMIT;
+  incrementalSweptArenas.ref().clear();
+}
+
 void ArenaLists::checkGCStateNotInUse() {
   // Called before and after collection to check the state is as expected.
 #ifdef DEBUG
   checkSweepStateNotInUse();
   for (auto i : AllAllocKinds()) {
     MOZ_ASSERT(newArenasInMarkPhase(i).isEmpty());
   }
 #endif
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/compartment-revived-gc.js
@@ -0,0 +1,133 @@
+// Test 'compartment revived' GCs, where we do an extra GC if there are
+// compartments which we expected to die but were kept alive.
+
+// A global used as the destination for transplants.
+let transplantTargetGlobal = newGlobal();
+
+function didCompartmentRevivedGC() {
+  return performance.mozMemory.gc.lastStartReason === "COMPARTMENT_REVIVED";
+}
+
+function compartmentCount() {
+  let r = performance.mozMemory.gc.compartmentCount;
+  return r;
+}
+
+function startIncrementalGC() {
+  startgc(1);
+  while (gcstate() === "Prepare") {
+    gcslice(100, {dontStart: true});
+  }
+  assertEq(gcstate(), "Mark");
+}
+
+function finishIncrementalGC() {
+  while (gcstate() !== "NotActive") {
+    gcslice(100, {dontStart: true});
+  }
+  assertEq(gcstate(), "NotActive");
+}
+
+// Create a new compartment and global and return the global.
+function createCompartment() {
+  return newGlobal({newCompartment: true});
+}
+
+// Create a transplantable object and create a wrapper to it from a new
+// compartment. Return a function to transplant the target object.
+function createTransplantableWrapperTarget(wrapperGlobal) {
+  let {object: target, transplant} = transplantableObject();
+  wrapperGlobal.wrapper = target;
+  return transplant;
+}
+
+// Transplant an object to a new global by calling the transplant
+// function. This remaps all wrappers pointing to the target object,
+// potentially keeping dead compartments alive.
+function transplantTargetAndRemapWrappers(transplant) {
+  transplant(transplantTargetGlobal);
+}
+
+// Test no compartment revived GC triggered in normal cases.
+function testNormal() {
+  gc();
+  assertEq(didCompartmentRevivedGC(), false);
+
+  startIncrementalGC();
+  finishIncrementalGC();
+  assertEq(didCompartmentRevivedGC(), false);
+
+  let initialCount = compartmentCount();
+  createCompartment();
+  startIncrementalGC();
+  finishIncrementalGC();
+  assertEq(compartmentCount(), initialCount);
+}
+
+// Test compartment revived GC is triggered by wrapper remapping.
+function testCompartmentRevived1() {
+  let initialCount = compartmentCount();
+  let compartment = createCompartment();
+  let transplant = createTransplantableWrapperTarget(compartment);
+  compartment = null;
+
+  startIncrementalGC();
+  transplantTargetAndRemapWrappers(transplant);
+  finishIncrementalGC();
+
+  assertEq(didCompartmentRevivedGC(), true);
+  assertEq(compartmentCount(), initialCount);
+}
+
+// Test no compartment revived GC is triggered for compartments transitively
+// kept alive by black roots.
+function testCompartmentRevived2() {
+  let initialCount = compartmentCount();
+  let compartment = createCompartment();
+  let transplant = createTransplantableWrapperTarget(compartment);
+  let liveCompartment = createCompartment();
+  liveCompartment.wrapper = compartment;
+  compartment = null;
+
+  startIncrementalGC();
+  transplantTargetAndRemapWrappers(transplant);
+  finishIncrementalGC();
+
+  assertEq(didCompartmentRevivedGC(), false);
+  assertEq(compartmentCount(), initialCount + 2);
+
+  liveCompartment = null;
+  gc();
+
+  assertEq(compartmentCount(), initialCount);
+}
+
+// Test no compartment revived GC is triggered for compartments transitively
+// kept alive by gray roots.
+function testCompartmentRevived3() {
+  let initialCount = compartmentCount();
+  let compartment = createCompartment();
+  let transplant = createTransplantableWrapperTarget(compartment);
+  let liveCompartment = createCompartment();
+  liveCompartment.wrapper = compartment;
+  liveCompartment.eval('grayRoot()[0] = this');
+  liveCompartment = null;
+  gc();
+
+  startIncrementalGC();
+  transplantTargetAndRemapWrappers(transplant);
+  finishIncrementalGC();
+
+  assertEq(didCompartmentRevivedGC(), false);
+  assertEq(compartmentCount(), initialCount + 2);
+
+  // There's no easy way to clear gray roots for a compartment we don't have
+  // any reference to.
+}
+
+gczeal(0);
+
+testNormal();
+testCompartmentRevived1();
+testCompartmentRevived2();
+testCompartmentRevived3();
--- a/js/src/jit/BaselineCodeGen.cpp
+++ b/js/src/jit/BaselineCodeGen.cpp
@@ -4824,32 +4824,38 @@ bool BaselineCodeGen<Handler>::emit_Push
   using Fn = bool (*)(JSContext*, BaselineFrame*, Handle<ClassBodyScope*>);
   return callVM<Fn, jit::PushClassBodyEnv>();
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_PopLexicalEnv() {
   frame.syncStack(0);
 
-  masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
-
-  auto ifDebuggee = [this]() {
+  Register scratch1 = R0.scratchReg();
+
+  auto ifDebuggee = [this, scratch1]() {
+    masm.loadBaselineFramePtr(BaselineFrameReg, scratch1);
+
     prepareVMCall();
     pushBytecodePCArg();
-    pushArg(R0.scratchReg());
+    pushArg(scratch1);
 
     using Fn = bool (*)(JSContext*, BaselineFrame*, jsbytecode*);
     return callVM<Fn, jit::DebugLeaveThenPopLexicalEnv>();
   };
-  auto ifNotDebuggee = [this]() {
-    prepareVMCall();
-    pushArg(R0.scratchReg());
-
-    using Fn = bool (*)(JSContext*, BaselineFrame*);
-    return callVM<Fn, jit::PopLexicalEnv>();
+  auto ifNotDebuggee = [this, scratch1]() {
+    Register scratch2 = R1.scratchReg();
+    masm.loadPtr(frame.addressOfEnvironmentChain(), scratch1);
+    masm.debugAssertObjectHasClass(scratch1, scratch2,
+                                   &LexicalEnvironmentObject::class_);
+    Address enclosingAddr(scratch1,
+                          EnvironmentObject::offsetOfEnclosingEnvironment());
+    masm.unboxObject(enclosingAddr, scratch1);
+    masm.storePtr(scratch1, frame.addressOfEnvironmentChain());
+    return true;
   };
   return emitDebugInstrumentation(ifDebuggee, mozilla::Some(ifNotDebuggee));
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_FreshenLexicalEnv() {
   frame.syncStack(0);
 
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -4180,16 +4180,27 @@ void MacroAssembler::debugAssertObjHasFi
   branchTest32(Assembler::NonZero,
                Address(scratch, Shape::offsetOfImmutableFlags()),
                Imm32(Shape::fixedSlotsMask()), &hasFixedSlots);
   assumeUnreachable("Expected a fixed slot");
   bind(&hasFixedSlots);
 #endif
 }
 
+void MacroAssembler::debugAssertObjectHasClass(Register obj, Register scratch,
+                                               const JSClass* clasp) {
+#ifdef DEBUG
+  Label done;
+  branchTestObjClassNoSpectreMitigations(Assembler::Equal, obj, clasp, scratch,
+                                         &done);
+  assumeUnreachable("Class check failed");
+  bind(&done);
+#endif
+}
+
 void MacroAssembler::branchArrayIsNotPacked(Register array, Register temp1,
                                             Register temp2, Label* label) {
   loadPtr(Address(array, NativeObject::offsetOfElements()), temp1);
 
   // Test length == initializedLength.
   Label done;
   Address initLength(temp1, ObjectElements::offsetOfInitializedLength());
   load32(Address(temp1, ObjectElements::offsetOfLength()), temp2);
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -4647,16 +4647,19 @@ class MacroAssembler : public MacroAssem
                                const Address& dest);
 
   void memoryBarrierBefore(const Synchronization& sync);
   void memoryBarrierAfter(const Synchronization& sync);
 
   void debugAssertIsObject(const ValueOperand& val);
   void debugAssertObjHasFixedSlots(Register obj, Register scratch);
 
+  void debugAssertObjectHasClass(Register obj, Register scratch,
+                                 const JSClass* clasp);
+
   void branchArrayIsNotPacked(Register array, Register temp1, Register temp2,
                               Label* label);
 
   void setIsPackedArray(Register obj, Register output, Register temp);
 
   void packedArrayPop(Register array, ValueOperand output, Register temp1,
                       Register temp2, Label* fail);
   void packedArrayShift(Register array, ValueOperand output, Register temp1,
--- a/js/src/jit/VMFunctionList-inl.h
+++ b/js/src/jit/VMFunctionList-inl.h
@@ -209,17 +209,16 @@ namespace jit {
   _(NewTypedArrayWithTemplateAndLength,                                        \
     js::NewTypedArrayWithTemplateAndLength)                                    \
   _(NormalSuspend, js::jit::NormalSuspend)                                     \
   _(NumberToString, js::NumberToString<CanGC>)                                 \
   _(ObjectCreateWithTemplate, js::ObjectCreateWithTemplate)                    \
   _(ObjectWithProtoOperation, js::ObjectWithProtoOperation)                    \
   _(OnDebuggerStatement, js::jit::OnDebuggerStatement)                         \
   _(OptimizeSpreadCall, js::OptimizeSpreadCall)                                \
-  _(PopLexicalEnv, js::jit::PopLexicalEnv)                                     \
   _(ProcessCallSiteObjOperation, js::ProcessCallSiteObjOperation)              \
   _(ProxyGetProperty, js::ProxyGetProperty)                                    \
   _(ProxyGetPropertyByValue, js::ProxyGetPropertyByValue)                      \
   _(ProxyHas, js::ProxyHas)                                                    \
   _(ProxyHasOwn, js::ProxyHasOwn)                                              \
   _(ProxySetProperty, js::ProxySetProperty)                                    \
   _(ProxySetPropertyByValue, js::ProxySetPropertyByValue)                      \
   _(PushClassBodyEnv, js::jit::PushClassBodyEnv)                               \
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1487,21 +1487,16 @@ bool GlobalHasLiveOnDebuggerStatement(JS
          DebugAPI::hasDebuggerStatementHook(cx->global());
 }
 
 bool PushLexicalEnv(JSContext* cx, BaselineFrame* frame,
                     Handle<LexicalScope*> scope) {
   return frame->pushLexicalEnvironment(cx, scope);
 }
 
-bool PopLexicalEnv(JSContext* cx, BaselineFrame* frame) {
-  frame->popOffEnvironmentChain<ScopedLexicalEnvironmentObject>();
-  return true;
-}
-
 bool DebugLeaveThenPopLexicalEnv(JSContext* cx, BaselineFrame* frame,
                                  jsbytecode* pc) {
   MOZ_ALWAYS_TRUE(DebugLeaveLexicalEnv(cx, frame, pc));
   frame->popOffEnvironmentChain<ScopedLexicalEnvironmentObject>();
   return true;
 }
 
 bool FreshenLexicalEnv(JSContext* cx, BaselineFrame* frame) {
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -473,17 +473,16 @@ JSObject* InitRestParameter(JSContext* c
 [[nodiscard]] bool EnterWith(JSContext* cx, BaselineFrame* frame,
                              HandleValue val, Handle<WithScope*> templ);
 [[nodiscard]] bool LeaveWith(JSContext* cx, BaselineFrame* frame);
 
 [[nodiscard]] bool PushLexicalEnv(JSContext* cx, BaselineFrame* frame,
                                   Handle<LexicalScope*> scope);
 [[nodiscard]] bool PushClassBodyEnv(JSContext* cx, BaselineFrame* frame,
                                     Handle<ClassBodyScope*> scope);
-[[nodiscard]] bool PopLexicalEnv(JSContext* cx, BaselineFrame* frame);
 [[nodiscard]] bool DebugLeaveThenPopLexicalEnv(JSContext* cx,
                                                BaselineFrame* frame,
                                                jsbytecode* pc);
 [[nodiscard]] bool FreshenLexicalEnv(JSContext* cx, BaselineFrame* frame);
 [[nodiscard]] bool DebugLeaveThenFreshenLexicalEnv(JSContext* cx,
                                                    BaselineFrame* frame,
                                                    jsbytecode* pc);
 [[nodiscard]] bool RecreateLexicalEnv(JSContext* cx, BaselineFrame* frame);
--- a/js/src/rust/Cargo.toml
+++ b/js/src/rust/Cargo.toml
@@ -11,15 +11,16 @@ path = "lib.rs"
 [features]
 cranelift_x86 = ['jsrust_shared/cranelift_x86']
 cranelift_arm32 = ['jsrust_shared/cranelift_arm32']
 cranelift_arm64 = ['jsrust_shared/cranelift_arm64']
 cranelift_none = ['jsrust_shared/cranelift_none']
 moz_memory = ['mozglue-static/moz_memory']
 simd-accel = ['jsrust_shared/simd-accel']
 smoosh = ['jsrust_shared/smoosh']
+gluesmith = ['jsrust_shared/gluesmith']
 
 [dependencies]
 jsrust_shared = { path = "./shared" }
 # Workaround for https://github.com/rust-lang/rust/issues/58393
 mozglue-static = { path = "../../../mozglue/static/rust" }
 wat = { version = "1.0.39" }
 wasmparser = { version = "0.78.2" }
--- a/js/src/rust/moz.build
+++ b/js/src/rust/moz.build
@@ -14,16 +14,19 @@ if CONFIG["ENABLE_WASM_CRANELIFT"]:
     elif CONFIG["JS_CODEGEN_ARM64"]:
         features += ["cranelift_arm64"]
     else:
         features += ["cranelift_none"]
 
 if CONFIG["MOZ_RUST_SIMD"]:
     features += ["simd-accel"]
 
+if CONFIG["FUZZING_INTERFACES"]:
+    features += ["gluesmith"]
+
 if CONFIG["JS_ENABLE_SMOOSH"]:
     features += ["smoosh"]
 
 if CONFIG["MOZ_MEMORY"]:
     features += ["moz_memory"]
 
 RustLibrary("jsrust", features)
 
--- a/js/src/rust/shared/Cargo.toml
+++ b/js/src/rust/shared/Cargo.toml
@@ -10,16 +10,17 @@ path = "lib.rs"
 
 [dependencies]
 baldrdash = { path = "../../wasm/cranelift", optional = true }
 encoding_c = "0.9.5"
 encoding_c_mem = "0.2.4"
 smoosh = { path = "../../frontend/smoosh", optional = true }
 mozilla-central-workspace-hack = { path = "../../../../build/workspace-hack" }
 mozglue-static = { path = "../../../../mozglue/static/rust" }
+gluesmith = { path = "../../fuzz-tests/gluesmith", optional = true }
 
 [features]
 cranelift_x86 = ['baldrdash/cranelift_x86']
 cranelift_arm32 = ['baldrdash/cranelift_arm32']
 cranelift_arm64 = ['baldrdash/cranelift_arm64']
 cranelift_none = ['baldrdash/cranelift_none']
 simd-accel = ['encoding_c/simd-accel']
 
--- a/js/src/rust/shared/lib.rs
+++ b/js/src/rust/shared/lib.rs
@@ -16,8 +16,11 @@
 extern crate baldrdash;
 
 extern crate encoding_c;
 extern crate encoding_c_mem;
 extern crate mozglue_static;
 
 #[cfg(feature = "smoosh")]
 extern crate smoosh;
+
+#[cfg(feature = "gluesmith")]
+extern crate gluesmith;
--- a/js/src/wasm/WasmCraneliftCompile.cpp
+++ b/js/src/wasm/WasmCraneliftCompile.cpp
@@ -516,16 +516,18 @@ bool wasm::CraneliftCompileFunctions(con
   MOZ_ASSERT(compilerEnv.tier() == Tier::Optimized);
   MOZ_ASSERT(compilerEnv.debug() == DebugEnabled::False);
   MOZ_ASSERT(compilerEnv.optimizedBackend() == OptimizedBackend::Cranelift);
   MOZ_ASSERT(!moduleEnv.isAsmJS());
 
   TempAllocator alloc(&lifo);
   JitContext jitContext(&alloc);
   WasmMacroAssembler masm(alloc, moduleEnv);
+  AutoCreatedBy acb(masm, "wasm::CraneliftCompileFunctions");
+
   MOZ_ASSERT(IsCompilingWasm());
 
   // Swap in already-allocated empty vectors to avoid malloc/free.
   MOZ_ASSERT(code->empty());
 
   CraneliftReusableData reusableContext;
   if (!code->swapCranelift(masm, reusableContext)) {
     return false;
--- a/modules/libpref/init/StaticPrefList.yaml
+++ b/modules/libpref/init/StaticPrefList.yaml
@@ -10501,16 +10501,28 @@
   value: true
   mirror: always
 
 - name: privacy.partition.network_state
   type: RelaxedAtomicBool
   value: true
   mirror: always
 
+# Partition the OCSP cache by the partitionKey.
+- name: privacy.partition.network_state.ocsp_cache
+  type: RelaxedAtomicBool
+  value: @IS_NIGHTLY_BUILD@
+  mirror: always
+
+# Partition the OCSP cache by the partitionKey for private browsing mode.
+- name: privacy.partition.network_state.ocsp_cache.pbmode
+  type: RelaxedAtomicBool
+  value: true
+  mirror: always
+
 - name: privacy.partition.bloburl_per_agent_cluster
   type: RelaxedAtomicBool
   value: false
   mirror: always
 
 - name: privacy.window.name.update.enabled
   type: bool
   value: true
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4290,16 +4290,25 @@ pref("dom.clients.openwindow_favors_same
 // If `true`, about:processes shows in-process subframes.
 pref("toolkit.aboutProcesses.showAllSubframes", false);
 // If `true`, about:processes shows thread information.
 #ifdef NIGHTLY_BUILD
   pref("toolkit.aboutProcesses.showThreads", true);
 #else
   pref("toolkit.aboutProcesses.showThreads", false);
 #endif
+// If `true`, about:processes will offer to profile processes.
+#ifdef NIGHTLY_BUILD
+  pref("toolkit.aboutProcesses.showProfilerIcons", true);
+#else
+  pref("toolkit.aboutProcesses.showProfilerIcons", false);
+#endif
+// Time in seconds between when the profiler is started and when the
+// profile is captured.
+pref("toolkit.aboutProcesses.profileDuration", 5);
 
 // When a crash happens, whether to include heap regions of the crash context
 // in the minidump. Enabled by default on nightly and aurora.
 #ifdef RELEASE_OR_BETA
   pref("toolkit.crashreporter.include_context_heap", false);
 #else
   pref("toolkit.crashreporter.include_context_heap", true);
 #endif
--- a/netwerk/base/nsIOService.cpp
+++ b/netwerk/base/nsIOService.cpp
@@ -215,16 +215,17 @@ static const char* gCallbackPrefsForSock
     NETWORK_DNS_PREF,
     "network.ssl_tokens_cache_enabled",
     "network.send_ODA_to_content_directly",
     "network.trr.",
     "doh-rollout.",
     "network.dns.disableIPv6",
     "network.dns.skipTRR-when-parental-control-enabled",
     "network.offline-mirrors-connectivity",
+    "network.disable-localhost-when-offline",
     nullptr,
 };
 
 static const char* gCallbackSecurityPrefs[] = {
     // Note the prefs listed below should be in sync with the code in
     // HandleTLSPrefChange().
     "security.tls.version.min",
     "security.tls.version.max",
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -594,53 +594,61 @@ nsresult nsStandardURL::NormalizeIPv4(co
 
   uint8_t ipSegments[4];
   NetworkEndian::writeUint32(ipSegments, ipv4);
   result = nsPrintfCString("%d.%d.%d.%d", ipSegments[0], ipSegments[1],
                            ipSegments[2], ipSegments[3]);
   return NS_OK;
 }
 
-nsresult nsStandardURL::NormalizeIDN(const nsACString& host,
-                                     nsCString& result) {
-  // If host is ACE, then convert to UTF-8.  Else, if host is already UTF-8,
-  // then make sure it is normalized per IDN.
-
-  // this function returns true if normalization succeeds.
-
+nsresult nsStandardURL::NormalizeIDN(const nsCString& host, nsCString& result) {
   result.Truncate();
+  mDisplayHost.Truncate();
   nsresult rv;
 
   if (!gIDN) {
     return NS_ERROR_UNEXPECTED;
   }
 
-  bool isAscii;
-  nsAutoCString normalized;
-  rv = gIDN->ConvertToDisplayIDN(host, &isAscii, normalized);
+  // If the input is ASCII, and not ACE encoded, then there's no processing
+  // needed. This is needed because we want to allow ascii labels longer than
+  // 64 characters for some schemes.
+  bool isACE = false;
+  if (IsAscii(host) && NS_SUCCEEDED(gIDN->IsACE(host, &isACE)) && !isACE) {
+    mCheckedIfHostA = true;
+    result = host;
+    return NS_OK;
+  }
+
+  // Even if it's already ACE, we must still call ConvertUTF8toACE in order
+  // for the input normalization to take place.
+  rv = gIDN->ConvertUTF8toACE(host, result);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
-  // The result is ASCII. No need to convert to ACE.
-  if (isAscii) {
-    result = normalized;
+  // If the ASCII representation doesn't contain the xn-- token then we don't
+  // need to call ConvertToDisplayIDN as that would not change anything.
+  if (!StringBeginsWith(result, "xn--"_ns) &&
+      result.Find(".xn--"_ns) == kNotFound) {
     mCheckedIfHostA = true;
-    mDisplayHost.Truncate();
     return NS_OK;
   }
 
-  rv = gIDN->ConvertUTF8toACE(normalized, result);
+  bool isAscii = true;
+  nsAutoCString displayHost;
+  rv = gIDN->ConvertToDisplayIDN(result, &isAscii, displayHost);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   mCheckedIfHostA = true;
-  mDisplayHost = normalized;
-
+  if (!isAscii) {
+    mDisplayHost = displayHost;
+  }
   return NS_OK;
 }
 
 bool nsStandardURL::ValidIPv6orHostname(const char* host, uint32_t length) {
   if (!host || !*host) {
     // Should not be NULL or empty string
     return false;
   }
--- a/netwerk/base/nsStandardURL.h
+++ b/netwerk/base/nsStandardURL.h
@@ -179,17 +179,17 @@ class nsStandardURL : public nsIFileURL,
   int32_t Port() { return mPort == -1 ? mDefaultPort : mPort; }
 
   void ReplacePortInSpec(int32_t aNewPort);
   void Clear();
   void InvalidateCache(bool invalidateCachedFile = true);
 
   bool ValidIPv6orHostname(const char* host, uint32_t length);
   static bool IsValidOfBase(unsigned char c, const uint32_t base);
-  nsresult NormalizeIDN(const nsACString& host, nsCString& result);
+  nsresult NormalizeIDN(const nsCString& host, nsCString& result);
   nsresult CheckIfHostIsAscii();
   void CoalescePath(netCoalesceFlags coalesceFlag, char* path);
 
   uint32_t AppendSegmentToBuf(char*, uint32_t, const char*,
                               const URLSegment& input, URLSegment& output,
                               const nsCString* esc = nullptr,
                               bool useEsc = false, int32_t* diff = nullptr);
   uint32_t AppendToBuf(char*, uint32_t, const char*, uint32_t);
--- a/netwerk/dns/nsIDNService.cpp
+++ b/netwerk/dns/nsIDNService.cpp
@@ -207,17 +207,23 @@ nsresult nsIDNService::IDNA2008StringPre
     --outLen;
   }
   ICUUtils::AssignUCharArrayToString(outputBuffer, outLen, output);
 
   if (flag == eStringPrepIgnoreErrors) {
     return NS_OK;
   }
 
-  if (info.errors != 0) {
+  uint32_t ignoredErrors = 0;
+  if (flag == eStringPrepForDNS) {
+    ignoredErrors = UIDNA_ERROR_LEADING_HYPHEN | UIDNA_ERROR_TRAILING_HYPHEN |
+                    UIDNA_ERROR_HYPHEN_3_4;
+  }
+
+  if ((info.errors & ~ignoredErrors) != 0) {
     if (flag == eStringPrepForDNS) {
       output.Truncate();
     }
     rv = NS_ERROR_MALFORMED_URI;
   }
 
   return rv;
 }
@@ -320,26 +326,35 @@ nsresult nsIDNService::ACEtoUTF8(const n
       _retval.Append(decodedBuf);
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsIDNService::IsACE(const nsACString& input, bool* _retval) {
-  const char* data = input.BeginReading();
-  uint32_t dataLen = input.Length();
-
   // look for the ACE prefix in the input string.  it may occur
   // at the beginning of any segment in the domain name.  for
   // example: "www.xn--ENCODED.com"
 
-  const char* p = PL_strncasestr(data, kACEPrefix, dataLen);
+  if (!IsAscii(input)) {
+    *_retval = false;
+    return NS_OK;
+  }
 
-  *_retval = p && (p == data || *(p - 1) == '.');
+  auto stringContains = [](const nsACString& haystack,
+                           const nsACString& needle) {
+    return std::search(haystack.BeginReading(), haystack.EndReading(),
+                       needle.BeginReading(),
+                       needle.EndReading()) != haystack.EndReading();
+  };
+
+  *_retval = StringBeginsWith(input, "xn--"_ns) ||
+             (!input.IsEmpty() && input[0] != '.' &&
+              stringContains(input, ".xn--"_ns));
   return NS_OK;
 }
 
 NS_IMETHODIMP nsIDNService::Normalize(const nsACString& input,
                                       nsACString& output) {
   // protect against bogus input
   NS_ENSURE_TRUE(IsUtf8(input), NS_ERROR_UNEXPECTED);
 
--- a/netwerk/locales/en-US/necko.properties
+++ b/netwerk/locales/en-US/necko.properties
@@ -25,16 +25,18 @@ DirColSize=Size
 DirColMTime=Last Modified
 DirFileLabel=File:
 
 SuperfluousAuth=You are about to log in to the site “%1$S” with the username “%2$S”, but the website does not require authentication. This may be an attempt to trick you.\n\nIs “%1$S” the site you want to visit?
 AutomaticAuth=You are about to log in to the site “%1$S” with the username “%2$S”.
 
 TrackerUriBlocked=The resource at “%1$S” was blocked because content blocking is enabled.
 UnsafeUriBlocked=The resource at “%1$S” was blocked by Safe Browsing.
+# LOCALIZATION NOTE (CORPBlocked): %1$S is the URL of the blocked resource. %2$S is the URL of the MDN page about CORP.
+CORPBlocked=The resource at “%1$S” was blocked due to its Cross-Origin-Resource-Policy header (or lack thereof). See %2$S
 CookieBlockedByPermission=Request to access cookies or storage on “%1$S” was blocked because of custom cookie permission.
 CookieBlockedTracker=Request to access cookie or storage on “%1$S” was blocked because it came from a tracker and content blocking is enabled.
 CookieBlockedAll=Request to access cookie or storage on “%1$S” was blocked because we are blocking all storage access requests.
 CookieBlockedForeign=Request to access cookie or storage on “%1$S” was blocked because we are blocking all third-party storage access requests and content blocking is enabled.
 # As part of dynamic state partitioning, third-party resources might be limited to "partitioned" storage access that is separate from the first-party context.
 # This allows e.g. cookies to still be set, and prevents tracking without totally blocking storage access. This message is shown in the web console when this happens
 # to inform developers that their storage is isolated.
 CookiePartitionedForeign2=Partitioned cookie or storage access was provided to “%1$S” because it is loaded in the third-party context and dynamic state partitioning is enabled.
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -2207,17 +2207,17 @@ nsresult HttpBaseChannel::ProcessCrossOr
   }
 
   // https://mikewest.github.io/corpp/#abstract-opdef-process-navigation-response
   if (mLoadInfo->GetExternalContentPolicyType() ==
           ExtContentPolicy::TYPE_SUBDOCUMENT &&
       mLoadInfo->GetLoadingEmbedderPolicy() !=
           nsILoadInfo::EMBEDDER_POLICY_NULL &&
       resultPolicy != nsILoadInfo::EMBEDDER_POLICY_REQUIRE_CORP) {
-    return NS_ERROR_BLOCKED_BY_POLICY;
+    return NS_ERROR_DOM_COEP_FAILED;
   }
 
   return NS_OK;
 }
 
 // https://mikewest.github.io/corpp/#corp-check
 nsresult HttpBaseChannel::ProcessCrossOriginResourcePolicyHeader() {
   // Fetch 4.5.9
@@ -2435,17 +2435,17 @@ nsresult HttpBaseChannel::ComputeCrossOr
 
   // If bc's popup sandboxing flag set is not empty and potentialCOOP is
   // non-null, then navigate bc to a network error and abort these steps.
   if (resultPolicy != nsILoadInfo::OPENER_POLICY_UNSAFE_NONE &&
       mLoadInfo->GetSandboxFlags()) {
     LOG((
         "HttpBaseChannel::ComputeCrossOriginOpenerPolicyMismatch network error "
         "for non empty sandboxing and non null COOP"));
-    return NS_ERROR_BLOCKED_BY_POLICY;
+    return NS_ERROR_DOM_COOP_FAILED;
   }
 
   // In xpcshell-tests we don't always have a current window global
   RefPtr<mozilla::dom::WindowGlobalParent> currentWindowGlobal =
       ctx->Canonical()->GetCurrentWindowGlobal();
   if (!currentWindowGlobal) {
     return NS_OK;
   }
@@ -2498,16 +2498,28 @@ nsresult HttpBaseChannel::ComputeCrossOr
   if (!currentWindowGlobal->IsInitialDocument()) {
     StoreHasCrossOriginOpenerPolicyMismatch(true);
     return NS_OK;
   }
 
   return NS_OK;
 }
 
+nsresult HttpBaseChannel::ProcessCrossOriginSecurityHeaders() {
+  nsresult rv = ProcessCrossOriginEmbedderPolicyHeader();
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = ProcessCrossOriginResourcePolicyHeader();
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  return ComputeCrossOriginOpenerPolicyMismatch();
+}
+
 enum class Report { Error, Warning };
 
 // Helper Function to report messages to the console when the loaded
 // script had a wrong MIME type.
 void ReportMimeTypeMismatch(HttpBaseChannel* aChannel, const char* aMessageName,
                             nsIURI* aURI, const nsACString& aContentType,
                             Report report) {
   NS_ConvertUTF8toUTF16 spec(aURI->GetSpecOrDefault());
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -604,16 +604,18 @@ class HttpBaseChannel : public nsHashPro
   bool IsBrowsingContextDiscarded() const;
 
   nsresult ProcessCrossOriginEmbedderPolicyHeader();
 
   nsresult ProcessCrossOriginResourcePolicyHeader();
 
   nsresult ComputeCrossOriginOpenerPolicyMismatch();
 
+  nsresult ProcessCrossOriginSecurityHeaders();
+
   nsresult ValidateMIMEType();
 
   bool EnsureOpaqueResponseIsAllowed();
 
   Result<bool, nsresult> EnsureOpaqueResponseIsAllowedAfterSniff();
 
   bool Http3Allowed() const;
 
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -1005,16 +1005,18 @@ void HttpChannelChild::DoOnStopRequest(n
       NS_ENSURE_SUCCESS_VOID(rv);
 
       UrlClassifierCommon::SetBlockedContent(this, aChannelStatus, list,
                                              provider, fullhash);
     }
   };
   checkForBlockedContent();
 
+  MaybeLogCOEPError(aChannelStatus);
+
   // See bug 1587686. If the redirect setup is not completed, the post-redirect
   // channel will be not opened and mListener will be null.
   MOZ_ASSERT(mListener || !LoadWasOpened());
   if (!mListener) {
     return;
   }
 
   MOZ_ASSERT(!LoadOnStopRequestCalled(),
@@ -2971,16 +2973,38 @@ HttpChannelChild::LogMimeTypeMismatch(co
   params.AppendElement(aContentType);
   nsContentUtils::ReportToConsole(
       aWarning ? nsIScriptError::warningFlag : nsIScriptError::errorFlag,
       "MIMEMISMATCH"_ns, doc, nsContentUtils::eSECURITY_PROPERTIES,
       nsCString(aMessageName).get(), params);
   return NS_OK;
 }
 
+nsresult HttpChannelChild::MaybeLogCOEPError(nsresult aStatus) {
+  if (aStatus == NS_ERROR_DOM_CORP_FAILED) {
+    RefPtr<Document> doc;
+    mLoadInfo->GetLoadingDocument(getter_AddRefs(doc));
+
+    nsAutoCString url;
+    mURI->GetSpec(url);
+
+    AutoTArray<nsString, 2> params;
+    params.AppendElement(NS_ConvertUTF8toUTF16(url));
+    // The MDN URL intentionally ends with a # so the webconsole linkification
+    // doesn't ignore the final ) of the URL
+    params.AppendElement(
+        u"https://developer.mozilla.org/docs/Web/HTTP/Cross-Origin_Resource_Policy_(CORP)#"_ns);
+    nsContentUtils::ReportToConsole(nsIScriptError::errorFlag, "COEP"_ns, doc,
+                                    nsContentUtils::eNECKO_PROPERTIES,
+                                    "CORPBlocked", params);
+  }
+
+  return NS_OK;
+}
+
 nsresult HttpChannelChild::CrossProcessRedirectFinished(nsresult aStatus) {
   if (!CanSend()) {
     return NS_BINDING_FAILED;
   }
 
   if (!mCanceled && NS_SUCCEEDED(mStatus)) {
     mStatus = aStatus;
   }
--- a/netwerk/protocol/http/HttpChannelChild.h
+++ b/netwerk/protocol/http/HttpChannelChild.h
@@ -252,16 +252,18 @@ class HttpChannelChild final : public PH
   // Try send DeletingChannel message to parent side. Dispatch an async task to
   // main thread if invoking on non-main thread.
   void TrySendDeletingChannel();
 
   // Try invoke Cancel if on main thread, or prepend a CancelEvent in mEventQ to
   // ensure Cacnel is processed before any other channel events.
   void CancelOnMainThread(nsresult aRv);
 
+  nsresult MaybeLogCOEPError(nsresult aStatus);
+
  private:
   // this section is for main-thread-only object
   // all the references need to be proxy released on main thread.
   nsCOMPtr<nsIChildChannel> mRedirectChannelChild;
 
   // Proxy release all members above on main thread.
   void ReleaseMainThreadOnlyReferences();
 
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -2071,43 +2071,28 @@ void nsHttpChannel::AsyncContinueProcess
     // If we're continuing asynchronously, we need to cancel the request
     // ourselves.
     Unused << Cancel(rv);
   }
 }
 
 nsresult nsHttpChannel::ContinueProcessResponse1() {
   MOZ_ASSERT(!mCallOnResume, "How did that happen?");
-  nsresult rv;
+  nsresult rv = NS_OK;
 
   if (mSuspendCount) {
     LOG(("Waiting until resume to finish processing response [this=%p]\n",
          this));
     mCallOnResume = [](nsHttpChannel* self) {
       self->AsyncContinueProcessResponse();
       return NS_OK;
     };
     return NS_OK;
   }
 
-  rv = ProcessCrossOriginResourcePolicyHeader();
-  if (NS_FAILED(rv)) {
-    mStatus = NS_ERROR_DOM_CORP_FAILED;
-    HandleAsyncAbort();
-    return NS_OK;
-  }
-
-  rv = ComputeCrossOriginOpenerPolicyMismatch();
-  if (rv == NS_ERROR_BLOCKED_BY_POLICY) {
-    // this navigates the doc's browsing context to a network error.
-    mStatus = NS_ERROR_BLOCKED_BY_POLICY;
-    HandleAsyncAbort();
-    return NS_OK;
-  }
-
   // Check if request was cancelled during http-on-examine-response.
   if (mCanceled) {
     return CallOnStartRequest();
   }
 
   uint32_t httpStatus = mResponseHead->Status();
 
   // STS, Cookies and Alt-Service should not be handled on proxy failure.
@@ -2160,23 +2145,16 @@ nsresult nsHttpChannel::ContinueProcessR
     rv = mAuthProvider->Disconnect(NS_ERROR_ABORT);
     if (NS_FAILED(rv)) {
       LOG(("  Disconnect failed (%08x)", static_cast<uint32_t>(rv)));
     }
     mAuthProvider = nullptr;
     LOG(("  continuation state has been reset"));
   }
 
-  rv = ProcessCrossOriginEmbedderPolicyHeader();
-  if (NS_FAILED(rv)) {
-    mStatus = NS_ERROR_BLOCKED_BY_POLICY;
-    HandleAsyncAbort();
-    return NS_OK;
-  }
-
   // No process switch needed, continue as normal.
   return ContinueProcessResponse2(rv);
 }
 
 nsresult nsHttpChannel::ContinueProcessResponse2(nsresult rv) {
   if (NS_FAILED(rv) && !mCanceled) {
     // The process switch failed, cancel this channel.
     Cancel(rv);
@@ -2542,16 +2520,23 @@ nsresult nsHttpChannel::ContinueProcessN
   if (NS_FAILED(rv)) {
     // Fill the failure status here, we have failed to fall back, thus we
     // have to report our status as failed.
     mStatus = rv;
     DoNotifyListener();
     return rv;
   }
 
+  rv = ProcessCrossOriginSecurityHeaders();
+  if (NS_FAILED(rv)) {
+    mStatus = rv;
+    HandleAsyncAbort();
+    return rv;
+  }
+
   // if we're here, then any byte-range requests failed to result in a partial
   // response.  we must clear this flag to prevent BufferPartialContent from
   // being called inside our OnDataAvailable (see bug 136678).
   StoreCachedContentIsPartial(false);
 
   ClearBogusContentEncodingIfNeeded();
 
   UpdateInhibitPersistentCachingFlag();
@@ -5049,16 +5034,23 @@ nsresult nsHttpChannel::SetupReplacement
 
   return NS_OK;
 }
 
 nsresult nsHttpChannel::AsyncProcessRedirection(uint32_t redirectType) {
   LOG(("nsHttpChannel::AsyncProcessRedirection [this=%p type=%u]\n", this,
        redirectType));
 
+  nsresult rv = ProcessCrossOriginSecurityHeaders();
+  if (NS_FAILED(rv)) {
+    mStatus = rv;
+    HandleAsyncAbort();
+    return rv;
+  }
+
   nsAutoCString location;
 
   // if a location header was not given, then we can't perform the redirect,
   // so just carry on as though this were a normal response.
   if (NS_FAILED(mResponseHead->GetHeader(nsHttp::Location, location))) {
     return NS_ERROR_FAILURE;
   }
 
@@ -5075,17 +5067,17 @@ nsresult nsHttpChannel::AsyncProcessRedi
     location = locationBuf;
   }
 
   mRedirectType = redirectType;
 
   LOG(("redirecting to: %s [redirection-limit=%u]\n", location.get(),
        uint32_t(mRedirectionLimit)));
 
-  nsresult rv = CreateNewURI(location.get(), getter_AddRefs(mRedirectURI));
+  rv = CreateNewURI(location.get(), getter_AddRefs(mRedirectURI));
 
   if (NS_FAILED(rv)) {
     LOG(("Invalid URI for redirect: Location: %s\n", location.get()));
     return NS_ERROR_CORRUPTED_CONTENT;
   }
 
   // Perform the URL query string stripping for redirects. We will only strip
   // the query string if it is redirecting to a third-party URI in the top
@@ -6864,39 +6856,21 @@ nsHttpChannel::OnStartRequest(nsIRequest
   }
 
   // avoid crashing if mListener happens to be null...
   if (!mListener) {
     MOZ_ASSERT_UNREACHABLE("mListener is null");
     return NS_OK;
   }
 
-  rv = ProcessCrossOriginEmbedderPolicyHeader();
+  rv = ProcessCrossOriginSecurityHeaders();
   if (NS_FAILED(rv)) {
-    mStatus = NS_ERROR_BLOCKED_BY_POLICY;
-    HandleAsyncAbort();
-    return NS_OK;
-  }
-
-  rv = ProcessCrossOriginResourcePolicyHeader();
-  if (NS_FAILED(rv)) {
-    mStatus = NS_ERROR_DOM_CORP_FAILED;
+    mStatus = rv;
     HandleAsyncAbort();
-    return NS_OK;
-  }
-
-  // before we check for redirects, check if the load should be shifted into a
-  // new process.
-  rv = ComputeCrossOriginOpenerPolicyMismatch();
-
-  if (rv == NS_ERROR_BLOCKED_BY_POLICY) {
-    // this navigates the doc's browsing context to a network error.
-    mStatus = NS_ERROR_BLOCKED_BY_POLICY;
-    HandleAsyncAbort();
-    return NS_OK;
+    return rv;
   }
 
   // No process change is needed, so continue on to ContinueOnStartRequest1.
   return ContinueOnStartRequest1(rv);
 }
 
 nsresult nsHttpChannel::ContinueOnStartRequest1(nsresult result) {
   nsresult rv;
--- a/netwerk/test/unit/test_bug412457.js
+++ b/netwerk/test/unit/test_bug412457.js
@@ -19,17 +19,17 @@ function run_test() {
   // UTF-8, so IDNA fails, and 0x80 is illegal in DNS too.
   Assert.throws(
     () => {
       newURI = newURI
         .mutate()
         .setSpec("http://%80.com")
         .finalize();
     },
-    /NS_ERROR_UNEXPECTED/,
+    /NS_ERROR_MALFORMED_URI/,
     "illegal UTF character"
   );
 
   // test parsing URL with all possible host terminators
   newURI = newURI
     .mutate()
     .setSpec("http://example.com?foo")
     .finalize();
--- a/netwerk/test/unit/test_standardurl.js
+++ b/netwerk/test/unit/test_standardurl.js
@@ -1159,17 +1159,17 @@ add_test(function test_idna_host() {
 
 add_test(
   { skip_if: () => AppConstants.MOZ_APP_NAME == "thunderbird" },
   function test_bug1517025() {
     Assert.throws(
       () => {
         stringToURL("https://b%9a/");
       },
-      /NS_ERROR_UNEXPECTED/,
+      /NS_ERROR_MALFORMED_URI/,
       "bad URI"
     );
 
     Assert.throws(
       () => {
         stringToURL("https://b%9ª/");
       },
       /NS_ERROR_MALFORMED_URI/,
--- a/security/certverifier/OCSPCache.cpp
+++ b/security/certverifier/OCSPCache.cpp
@@ -23,16 +23,17 @@
  */
 
 #include "OCSPCache.h"
 
 #include <limits>
 
 #include "NSSCertDBTrustDomain.h"
 #include "pk11pub.h"
+#include "mozilla/StaticPrefs_privacy.h"
 #include "mozpkix/pkixnss.h"
 #include "ScopedNSSTypes.h"
 #include "secerr.h"
 
 extern mozilla::LazyLogModule gCertVerifierLog;
 
 using namespace mozilla::pkix;
 
@@ -58,18 +59,21 @@ static SECStatus DigestLength(UniquePK11
 // Let derIssuer be the DER encoding of the issuer of certID.
 // Let derPublicKey be the DER encoding of the public key of certID.
 // Let serialNumber be the bytes of the serial number of certID.
 // Let serialNumberLen be the number of bytes of serialNumber.
 // Let firstPartyDomain be the first party domain of originAttributes.
 // It is only non-empty when "privacy.firstParty.isolate" is enabled, in order
 // to isolate OCSP cache by first party.
 // Let firstPartyDomainLen be the number of bytes of firstPartyDomain.
+// Let partitionKey be the partition key of originAttributes.
+// Let partitionKeyLen be the number of bytes of partitionKey.
 // The value calculated is SHA384(derIssuer || derPublicKey || serialNumberLen
-// || serialNumber || firstPartyDomainLen || firstPartyDomain).
+// || serialNumber || firstPartyDomainLen || firstPartyDomain || partitionKeyLen
+// || partitionKey).
 // Because the DER encodings include the length of the data encoded, and we also
 // include the length of serialNumber and originAttributes, there do not exist
 // A(derIssuerA, derPublicKeyA, serialNumberLenA, serialNumberA,
 // originAttributesLenA, originAttributesA) and B(derIssuerB, derPublicKeyB,
 // serialNumberLenB, serialNumberB, originAttributesLenB, originAttributesB)
 // such that the concatenation of each tuple results in the same string of
 // bytes but where each part in A is not equal to its counterpart in B. This is
 // important because as a result it is computationally infeasible to find
@@ -103,27 +107,46 @@ static SECStatus CertIDHash(SHA384Buffer
     return rv;
   }
   rv = PK11_DigestOp(context.get(), certIDSerialNumber.data,
                      certIDSerialNumber.len);
   if (rv != SECSuccess) {
     return rv;
   }
 
-  // OCSP should not be isolated by containers.
-  NS_ConvertUTF16toUTF8 firstPartyDomain(originAttributes.mFirstPartyDomain);
-  if (!firstPartyDomain.IsEmpty()) {
-    rv = DigestLength(context, firstPartyDomain.Length());
+  auto populateOriginAttributesKey = [&context](const nsString& aKey) {
+    NS_ConvertUTF16toUTF8 key(aKey);
+
+    if (key.IsEmpty()) {
+      return SECSuccess;
+    }
+
+    SECStatus rv = DigestLength(context, key.Length());
     if (rv != SECSuccess) {
       return rv;
     }
-    rv =
-        PK11_DigestOp(context.get(),
-                      BitwiseCast<const unsigned char*>(firstPartyDomain.get()),
-                      firstPartyDomain.Length());
+
+    return PK11_DigestOp(context.get(),
+                         BitwiseCast<const unsigned char*>(key.get()),
+                         key.Length());
+  };
+
+  // OCSP should be isolated by firstPartyDomain and partitionKey, but not
+  // by containers.
+  rv = populateOriginAttributesKey(originAttributes.mFirstPartyDomain);
+  if (rv != SECSuccess) {
+    return rv;
+  }
+
+  bool isolateByPartitionKey =
+      originAttributes.mPrivateBrowsingId > 0
+          ? StaticPrefs::privacy_partition_network_state_ocsp_cache_pbmode()
+          : StaticPrefs::privacy_partition_network_state_ocsp_cache();
+  if (isolateByPartitionKey) {
+    rv = populateOriginAttributesKey(originAttributes.mPartitionKey);
     if (rv != SECSuccess) {
       return rv;
     }
   }
   uint32_t outLen = 0;
   rv = PK11_DigestFinal(context.get(), buf, &outLen, SHA384_LENGTH);
   if (outLen != SHA384_LENGTH) {
     return SECFailure;
@@ -169,19 +192,21 @@ bool OCSPCache::FindInternal(const CertI
       return true;
     }
   }
   return false;
 }
 
 static inline void LogWithCertID(const char* aMessage, const CertID& aCertID,
                                  const OriginAttributes& aOriginAttributes) {
-  NS_ConvertUTF16toUTF8 firstPartyDomain(aOriginAttributes.mFirstPartyDomain);
+  nsAutoString info = u"firstPartyDomain: "_ns +
+                      aOriginAttributes.mFirstPartyDomain +
+                      u", partitionKey: "_ns + aOriginAttributes.mPartitionKey;
   MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
-          (aMessage, &aCertID, firstPartyDomain.get()));
+          (aMessage, &aCertID, NS_ConvertUTF16toUTF8(info).get()));
 }
 
 void OCSPCache::MakeMostRecentlyUsed(size_t aIndex,
                                      const MutexAutoLock& /* aProofOfLock */) {
   Entry* entry = mEntries[aIndex];
   // Since mEntries is sorted with the most-recently-used entry at the end,
   // aIndex is likely to be near the end, so this is likely to be fast.
   mEntries.erase(mEntries.begin() + aIndex);
--- a/security/manager/ssl/tests/gtest/OCSPCacheTest.cpp
+++ b/security/manager/ssl/tests/gtest/OCSPCacheTest.cpp
@@ -4,16 +4,17 @@
  * 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 "CertVerifier.h"
 #include "OCSPCache.h"
 #include "gtest/gtest.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/Casting.h"
+#include "mozilla/Preferences.h"
 #include "mozilla/Sprintf.h"
 #include "nss.h"
 #include "mozpkix/pkixtypes.h"
 #include "mozpkix/test/pkixtestutil.h"
 #include "prerr.h"
 #include "secerr.h"
 
 using namespace mozilla::pkix;
@@ -299,23 +300,58 @@ TEST_F(psm_OCSPCacheTest, NetworkFailure
   ASSERT_TRUE(cache.Get(certID, OriginAttributes(), resultOut, timeOut));
   ASSERT_EQ(Result::ERROR_REVOKED_CERTIFICATE, resultOut);
   ASSERT_EQ(TimeFromElapsedSecondsAD(600), timeOut);
 }
 
 TEST_F(psm_OCSPCacheTest, TestOriginAttributes) {
   CertID certID(fakeIssuer1, fakeKey000, fakeSerial0000);
 
+  // We test two attributes, firstPartyDomain and partitionKey, respectively
+  // because we don't have entries that have both attributes set because the two
+  // features that use these attributes are mutually exclusive.
+
+  // Set pref for OCSP cache network partitioning.
+  mozilla::Preferences::SetBool("privacy.partition.network_state.ocsp_cache",
+                                true);
+
   SCOPED_TRACE("");
   OriginAttributes attrs;
   attrs.mFirstPartyDomain.AssignLiteral("foo.com");
   PutAndGet(cache, certID, Success, now, attrs);
 
   Result resultOut;
   Time timeOut(Time::uninitialized);
   attrs.mFirstPartyDomain.AssignLiteral("bar.com");
   ASSERT_FALSE(cache.Get(certID, attrs, resultOut, timeOut));
 
-  // OCSP cache should not be isolated by containers.
+  // OCSP cache should not be isolated by containers for firstPartyDomain.
   attrs.mUserContextId = 1;
   attrs.mFirstPartyDomain.AssignLiteral("foo.com");
   ASSERT_TRUE(cache.Get(certID, attrs, resultOut, timeOut));
+
+  // Clear originAttributes.
+  attrs.mUserContextId = 0;
+  attrs.mFirstPartyDomain.Truncate();
+
+  // Add OCSP cache for the partitionKey.
+  attrs.mPartitionKey.AssignLiteral("(https,foo.com)");
+  PutAndGet(cache, certID, Success, now, attrs);
+
+  // Check cache entry for the partitionKey.
+  attrs.mPartitionKey.AssignLiteral("(https,foo.com)");
+  ASSERT_TRUE(cache.Get(certID, attrs, resultOut, timeOut));
+
+  // OCSP cache entry should not exist for the other partitionKey.
+  attrs.mPartitionKey.AssignLiteral("(https,bar.com)");
+  ASSERT_FALSE(cache.Get(certID, attrs, resultOut, timeOut));
+
+  // OCSP cache should not be isolated by containers for partitonKey.
+  attrs.mUserContextId = 1;
+  attrs.mPartitionKey.AssignLiteral("(https,foo.com)");
+  ASSERT_TRUE(cache.Get(certID, attrs, resultOut, timeOut));
+
+  // OCSP cache should not exist for the OAs which has both attributes set.
+  attrs.mUserContextId = 0;
+  attrs.mFirstPartyDomain.AssignLiteral("foo.com");
+  attrs.mPartitionKey.AssignLiteral("(https,foo.com)");
+  ASSERT_FALSE(cache.Get(certID, attrs, resultOut, timeOut));
 }
--- a/security/manager/ssl/tests/unit/test_ocsp_caching.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_caching.js
@@ -398,9 +398,99 @@ function add_tests() {
 
   // ---------------------------------------------------------------------------
 
   // Reset state
   add_test(function() {
     clearOCSPCache();
     run_next_test();
   });
+
+  // This test makes sure that OCSP cache are isolated by partitionKey.
+
+  add_test(function() {
+    Services.prefs.setBoolPref(
+      "privacy.partition.network_state.ocsp_cache",
+      true
+    );
+    run_next_test();
+  });
+
+  // A good OCSP response will be cached.
+  add_ocsp_test(
+    "ocsp-stapling-none.example.com",
+    PRErrorCodeSuccess,
+    [respondWithGoodOCSP],
+    "No stapled response (partitionKey = (https,foo.com)) -> a fetch " +
+      "should have been attempted",
+    { partitionKey: "(https,foo.com)" }
+  );
+
+  // The cache will prevent a fetch from happening.
+  add_ocsp_test(
+    "ocsp-stapling-none.example.com",
+    PRErrorCodeSuccess,
+    [],
+    "Noted OCSP server failure (partitionKey = (https,foo.com)) -> a " +
+      "fetch should not have been attempted",
+    { partitionKey: "(https,foo.com)" }
+  );
+
+  // Using a different partitionKey should result in a fetch.
+  add_ocsp_test(
+    "ocsp-stapling-none.example.com",
+    PRErrorCodeSuccess,
+    [respondWithGoodOCSP],
+    "Noted OCSP server failure (partitionKey = (https,bar.com)) -> a " +
+      "fetch should have been attempted",
+    { partitionKey: "(https,bar.com)" }
+  );
+
+  // ---------------------------------------------------------------------------
+
+  // Reset state
+  add_test(function() {
+    Services.prefs.clearUserPref("privacy.partition.network_state.ocsp_cache");
+    clearOCSPCache();
+    run_next_test();
+  });
+
+  // This test makes sure that OCSP cache are isolated by partitionKey in
+  // private mode.
+
+  // A good OCSP response will be cached.
+  add_ocsp_test(
+    "ocsp-stapling-none.example.com",
+    PRErrorCodeSuccess,
+    [respondWithGoodOCSP],
+    "No stapled response (partitionKey = (https,foo.com)) -> a fetch " +
+      "should have been attempted",
+    { partitionKey: "(https,foo.com)", privateBrowsingId: 1 }
+  );
+
+  // The cache will prevent a fetch from happening.
+  add_ocsp_test(
+    "ocsp-stapling-none.example.com",
+    PRErrorCodeSuccess,
+    [],
+    "Noted OCSP server failure (partitionKey = (https,foo.com)) -> a " +
+      "fetch should not have been attempted",
+    { partitionKey: "(https,foo.com)", privateBrowsingId: 1 }
+  );
+
+  // Using a different partitionKey should result in a fetch.
+  add_ocsp_test(
+    "ocsp-stapling-none.example.com",
+    PRErrorCodeSuccess,
+    [respondWithGoodOCSP],
+    "Noted OCSP server failure (partitionKey = (https,bar.com)) -> a " +
+      "fetch should have been attempted",
+    { partitionKey: "(https,bar.com)", privateBrowsingId: 1 }
+  );
+
+  // ---------------------------------------------------------------------------
+
+  // Reset state
+  add_test(function() {
+    clearOCSPCache();
+    run_next_test();
+  });
 }
--- a/testing/geckodriver/CHANGES.md
+++ b/testing/geckodriver/CHANGES.md
@@ -1,15 +1,15 @@
 Change log
 ==========
 
 All notable changes to this program are documented in this file.
 
-0.30.0  (2021-09-15)
---------------------
+0.30.0  (2021-09-16, `d372710b98a6`)
+------------------------------------
 
 ### Known problems
 
 - _macOS 10.15 (Catalina) and later:_
 
   Due to the requirement from Apple that all programs must be
   notarized, geckodriver will not work on Catalina if you manually
   download it through another notarized program, such as Firefox.
--- a/testing/web-platform/meta/url/a-element-xhtml.xhtml.ini
+++ b/testing/web-platform/meta/url/a-element-xhtml.xhtml.ini
@@ -141,22 +141,16 @@
     expected: FAIL
 
   [Parsing: <http://www.@pple.com> against <about:blank>]
     expected: FAIL
 
   [Parsing: <file:..> against <http://www.example.com/test>]
     expected: FAIL
 
-  [Parsing: <http://﷐zyx.com> against <http://other.com/>]
-    expected: FAIL
-
-  [Parsing: <http://%ef%b7%90zyx.com> against <http://other.com/>]
-    expected: FAIL
-
   [Parsing: <http://192.168.0.257> against <http://other.com/>]
     expected: FAIL
 
   [Parsing: <#> against <test:test>]
     expected: FAIL
 
   [Parsing: <#x> against <mailto:x@x.com>]
     expected: FAIL
@@ -276,22 +270,16 @@
     expected: FAIL
 
   [Parsing: <file://example%/> against <about:blank>]
     expected: FAIL
 
   [Parsing: <file://[example\]/> against <about:blank>]
     expected: FAIL
 
-  [Parsing: <https://�> against <about:blank>]
-    expected: FAIL
-
-  [Parsing: <https://%EF%BF%BD> against <about:blank>]
-    expected: FAIL
-
   [Parsing: <sc://\x00/> against <about:blank>]
     expected: FAIL
 
   [Parsing: <sc:// /> against <about:blank>]
     expected: FAIL
 
   [Parsing: <sc://%/> against <about:blank>]
     expected: FAIL
@@ -493,22 +481,16 @@
     expected: FAIL
 
   [Parsing: <sc://ñ#x> against <about:blank>]
     expected: FAIL
 
   [Parsing: <x> against <sc://ñ>]
     expected: FAIL
 
-  [Parsing: <http://﷐zyx.com> against <http://other.com/>]
-    expected: FAIL
-
-  [Parsing: <https://�> against <about:blank>]
-    expected: FAIL
-
   [Parsing: <data:test# »> against <about:blank>]
     expected: FAIL
 
   [Parsing: <wow:￿> against <about:blank>]
     expected: FAIL
 
   [Parsing: <sc://ñ?x> against <about:blank>]
     expected: FAIL
--- a/testing/web-platform/meta/url/a-element.html.ini
+++ b/testing/web-platform/meta/url/a-element.html.ini
@@ -138,22 +138,16 @@
     expected: FAIL
 
   [Parsing: <http::b@www.example.com> against <about:blank>]
     expected: FAIL
 
   [Parsing: <http://www.@pple.com> against <about:blank>]
     expected: FAIL
 
-  [Parsing: <http://﷐zyx.com> against <http://other.com/>]
-    expected: FAIL
-
-  [Parsing: <http://%ef%b7%90zyx.com> against <http://other.com/>]
-    expected: FAIL
-
   [Parsing: <http://192.168.0.257> against <http://other.com/>]
     expected: FAIL
 
   [Parsing: <#> against <test:test>]
     expected: FAIL
 
   [Parsing: <#x> against <mailto:x@x.com>]
     expected: FAIL
@@ -276,22 +270,16 @@
     expected: FAIL
 
   [Parsing: <file://example%/> against <about:blank>]
     expected: FAIL
 
   [Parsing: <file://[example\]/> against <about:blank>]
     expected: FAIL
 
-  [Parsing: <https://�> against <about:blank>]
-    expected: FAIL
-
-  [Parsing: <https://%EF%BF%BD> against <about:blank>]
-    expected: FAIL
-
   [Parsing: <sc://\x00/> against <about:blank>]
     expected: FAIL
 
   [Parsing: <sc:// /> against <about:blank>]
     expected: FAIL
 
   [Parsing: <sc://%/> against <about:blank>]
     expected: FAIL
@@ -493,22 +481,16 @@
     expected: FAIL
 
   [Parsing: <sc://ñ#x> against <about:blank>]
     expected: FAIL
 
   [Parsing: <x> against <sc://ñ>]
     expected: FAIL
 
-  [Parsing: <http://﷐zyx.com> against <http://other.com/>]
-    expected: FAIL
-
-  [Parsing: <https://�> against <about:blank>]
-    expected: FAIL
-
   [Parsing: <data:test# »> against <about:blank>]
     expected: FAIL
 
   [Parsing: <sc://ñ?x> against <about:blank>]
     expected: FAIL
 
   [Parsing: <?x> against <sc://ñ>]
     expected: FAIL
@@ -526,22 +508,16 @@
     expected: FAIL
 
   [Parsing: <sc://ñ#x> against <about:blank>]
     expected: FAIL
 
   [Parsing: <x> against <sc://ñ>]
     expected: FAIL
 
-  [Parsing: <http://﷐zyx.com> against <http://other.com/>]
-    expected: FAIL
-
-  [Parsing: <https://�> against <about:blank>]
-    expected: FAIL
-
   [Parsing: <data:test# »> against <about:blank>]
     expected: FAIL
 
   [Parsing: <wow:￿> against <about:blank>]
     expected: FAIL
 
   [Parsing: <sc://ñ?x> against <about:blank>]
     expected: FAIL
--- a/testing/web-platform/meta/url/failure.html.ini
+++ b/testing/web-platform/meta/url/failure.html.ini
@@ -43,37 +43,19 @@
     expected: FAIL
 
   [Location's href: http://a:b@/www.example.com should throw]
     expected: FAIL
 
   [Location's href: http://@:www.example.com should throw]
     expected: FAIL
 
-  [URL's href: https://� should throw]
-    expected: FAIL
-
-  [XHR: https://� should throw]
-    expected: FAIL
-
-  [sendBeacon(): https://� should throw]
-    expected: FAIL
-
   [Location's href: https://� should throw]
     expected: FAIL
 
-  [URL's href: https://%EF%BF%BD should throw]
-    expected: FAIL
-
-  [XHR: https://%EF%BF%BD should throw]
-    expected: FAIL
-
-  [sendBeacon(): https://%EF%BF%BD should throw]
-    expected: FAIL
-
   [Location's href: https://%EF%BF%BD should throw]
     expected: FAIL
 
   [Location's href: https://x x:12 should throw]
     expected: FAIL
 
   [Location's href: http://[www.google.com\]/ should throw]
     expected: FAIL
@@ -154,37 +136,25 @@
     expected: FAIL
 
   [XHR: sc://\]/ should throw]
     expected: FAIL
 
   [Location's href: sc://\]/ should throw]
     expected: FAIL
 
-  [XHR: ftp://example.com%80/ should throw]
-    expected: FAIL
-
   [Location's href: ftp://example.com%80/ should throw]
     expected: FAIL
 
-  [XHR: ftp://example.com%A0/ should throw]
-    expected: FAIL
-
   [Location's href: ftp://example.com%A0/ should throw]
     expected: FAIL
 
-  [XHR: https://example.com%80/ should throw]
-    expected: FAIL
-
   [Location's href: https://example.com%80/ should throw]
     expected: FAIL
 
-  [XHR: https://example.com%A0/ should throw]
-    expected: FAIL
-
   [Location's href: https://example.com%A0/ should throw]
     expected: FAIL
 
   [Location's href: https://[0::0::0\] should throw]
     expected: FAIL
 
   [Location's href: https://[0:.0\] should throw]
     expected: FAIL
@@ -226,22 +196,16 @@
     expected: FAIL
 
   [window.open(): file://example%/ should throw]
     expected: FAIL
 
   [window.open(): file://[example\]/ should throw]
     expected: FAIL
 
-  [window.open(): https://� should throw]
-    expected: FAIL
-
-  [window.open(): https://%EF%BF%BD should throw]
-    expected: FAIL
-
   [window.open(): sc://\x00/ should throw]
     expected: FAIL
 
   [window.open(): sc:// / should throw]
     expected: FAIL
 
   [window.open(): sc://@/ should throw]
     expected: FAIL
@@ -307,22 +271,16 @@
     expected: FAIL
 
   [URL's constructor's base argument: file://example%/ should throw]
     expected: FAIL
 
   [URL's constructor's base argument: file://[example\]/ should throw]
     expected: FAIL
 
-  [URL's constructor's base argument: https://� should throw]
-    expected: FAIL
-
-  [URL's constructor's base argument: https://%EF%BF%BD should throw]
-    expected: FAIL
-
   [URL's constructor's base argument: sc://\x00/ should throw]
     expected: FAIL
 
   [URL's constructor's base argument: sc:// / should throw]
     expected: FAIL
 
   [URL's constructor's base argument: sc://@/ should throw]
     expected: FAIL
@@ -349,52 +307,22 @@
     expected: FAIL
 
   [URL's constructor's base argument: https://256.0.0.1/test should throw]
     expected: FAIL
 
   [URL's constructor's base argument: non-special://[:80/ should throw]
     expected: FAIL
 
-  [sendBeacon(): https://� should throw]
-    expected: FAIL
-
-  [window.open(): https://� should throw]
-    expected: FAIL
-
   [Location's href: https://� should throw]
     expected: FAIL
 
-  [XHR: https://� should throw]
-    expected: FAIL
-
-  [URL's constructor's base argument: https://� should throw]
-    expected: FAIL
-
-  [URL's href: https://� should throw]
-    expected: FAIL
-
-  [sendBeacon(): https://� should throw]
-    expected: FAIL
-
-  [window.open(): https://� should throw]
-    expected: FAIL
-
   [Location's href: https://� should throw]
     expected: FAIL
 
-  [XHR: https://� should throw]
-    expected: FAIL
-
-  [URL's constructor's base argument: https://� should throw]
-    expected: FAIL
-
-  [URL's href: https://� should throw]
-    expected: FAIL
-
   [URL's constructor's base argument: file://xn--/p should throw]
     expected: FAIL
 
   [window.open(): file://xn--/p should throw]
     expected: FAIL
 
   [URL's href: file://%C2%AD/p should throw]
     expected: FAIL
--- a/testing/web-platform/meta/url/toascii.window.js.ini
+++ b/testing/web-platform/meta/url/toascii.window.js.ini
@@ -75,43 +75,16 @@
     expected: FAIL
 
   [xn--a.β (using <area>.host)]
     expected: FAIL
 
   [xn--a.β (using <area>.hostname)]
     expected: FAIL
 
-  [‍.example (using URL)]
-    expected: FAIL
-
-  [‍.example (using URL.host)]
-    expected: FAIL
-
-  [‍.example (using URL.hostname)]
-    expected: FAIL
-
-  [‍.example (using <a>)]
-    expected: FAIL
-
-  [‍.example (using <a>.host)]
-    expected: FAIL
-
-  [‍.example (using <a>.hostname)]
-    expected: FAIL
-
-  [‍.example (using <area>)]
-    expected: FAIL
-
-  [‍.example (using <area>.host)]
-    expected: FAIL
-
-  [‍.example (using <area>.hostname)]
-    expected: FAIL
-
   [xn--1ug.example (using URL)]
     expected: FAIL
 
   [xn--1ug.example (using URL.host)]
     expected: FAIL
 
   [xn--1ug.example (using URL.hostname)]
     expected: FAIL
@@ -129,43 +102,16 @@
     expected: FAIL
 
   [xn--1ug.example (using <area>.host)]
     expected: FAIL
 
   [xn--1ug.example (using <area>.hostname)]
     expected: FAIL
 
-  [يa (using URL)]
-    expected: FAIL
-
-  [يa (using URL.host)]
-    expected: FAIL
-
-  [يa (using URL.hostname)]
-    expected: FAIL
-
-  [يa (using <a>)]
-    expected: FAIL
-
-  [يa (using <a>.host)]
-    expected: FAIL
-
-  [يa (using <a>.hostname)]
-    expected: FAIL
-
-  [يa (using <area>)]
-    expected: FAIL
-
-  [يa (using <area>.host)]
-    expected: FAIL
-
-  [يa (using <area>.hostname)]
-    expected: FAIL
-
   [xn--a-yoc (using URL)]
     expected: FAIL
 
   [xn--a-yoc (using URL.host)]
     expected: FAIL
 
   [xn--a-yoc (using URL.hostname)]
     expected: FAIL
@@ -183,43 +129,16 @@
     expected: FAIL
 
   [xn--a-yoc (using <area>.host)]
     expected: FAIL
 
   [xn--a-yoc (using <area>.hostname)]
     expected: FAIL
 
-  [�.com (using URL)]
-    expected: FAIL
-
-  [�.com (using URL.host)]
-    expected: FAIL
-
-  [�.com (using URL.hostname)]
-    expected: FAIL
-
-  [�.com (using <a>)]
-    expected: FAIL
-
-  [�.com (using <a>.host)]
-    expected: FAIL
-
-  [�.com (using <a>.hostname)]
-    expected: FAIL
-
-  [�.com (using <area>)]
-    expected: FAIL
-
-  [�.com (using <area>.host)]
-    expected: FAIL
-
-  [�.com (using <area>.hostname)]
-    expected: FAIL
-
   [xn--zn7c.com (using URL)]
     expected: FAIL
 
   [xn--zn7c.com (using URL.host)]
     expected: FAIL
 
   [xn--zn7c.com (using URL.hostname)]
     expected: FAIL
@@ -344,9 +263,8 @@
   [xn-- (using URL)]
     expected: FAIL
 
   [xn-- (using <area>.host)]
     expected: FAIL
 
   [xn-- (using URL.host)]
     expected: FAIL
-
--- a/testing/web-platform/meta/url/url-constructor.any.js.ini
+++ b/testing/web-platform/meta/url/url-constructor.any.js.ini
@@ -75,28 +75,16 @@
     expected: FAIL
 
   [Parsing: <http://www.@pple.com> against <about:blank>]
     expected: FAIL
 
   [Parsing: <file:..> against <http://www.example.com/test>]
     expected: FAIL
 
-  [Parsing: <http://﷐zyx.com> against <http://other.com/>]
-    expected: FAIL
-
-  [Parsing: <http://%ef%b7%90zyx.com> against <http://other.com/>]
-    expected: FAIL
-
-  [Parsing: <https://�> against <about:blank>]
-    expected: FAIL
-
-  [Parsing: <https://%EF%BF%BD> against <about:blank>]
-    expected: FAIL
-
   [Parsing: <sc://faß.ExAmPlE/> against <about:blank>]
     expected: FAIL
 
   [Parsing: <http://192.168.0.257> against <http://other.com/>]
     expected: FAIL
 
   [Parsing: <notspecial://host/?'> against <about:blank>]
     expected: FAIL
@@ -683,28 +671,16 @@
     expected: FAIL
 
   [Parsing: <http://www.@pple.com> against <about:blank>]
     expected: FAIL
 
   [Parsing: <file:..> against <http://www.example.com/test>]
     expected: FAIL
 
-  [Parsing: <http://﷐zyx.com> against <http://other.com/>]
-    expected: FAIL
-
-  [Parsing: <http://%ef%b7%90zyx.com> against <http://other.com/>]
-    expected: FAIL
-
-  [Parsing: <https://�> against <about:blank>]
-    expected: FAIL
-
-  [Parsing: <https://%EF%BF%BD> against <about:blank>]
-    expected: FAIL
-
   [Parsing: <sc://faß.ExAmPlE/> against <about:blank>]
     expected: FAIL
 
   [Parsing: <http://192.168.0.257> against <http://other.com/>]
     expected: FAIL
 
   [Parsing: <notspecial://host/?'> against <about:blank>]
     expected: FAIL
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-embedder-policy/require-corp-cached-images.https.html
@@ -0,0 +1,73 @@
+<!doctype html>
+<html>
+<title> Images on a page Cross-Origin-Embedder-Policy: require-corp should load the same from the cache or network</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+
+function remote(path) {
+  const REMOTE_ORIGIN = get_host_info().HTTPS_REMOTE_ORIGIN;
+  return new URL(path, REMOTE_ORIGIN);
+}
+
+//
+// This test loads a same-orign iframe resources/load_corp_images.html with
+// Cross-Origin-Embedder-Policy: require-corp
+// The iframe loads two cross origin images, one with a
+// Cross-Origin-Resource-Policy: cross-origin header, and one without.
+// We expect the image with the header to load successfully and the one without
+// to fail to load.
+// After the first load we then reload the iframe, with the same expectations
+// for the image loads when they are loaded from the cache.
+//
+
+const image_path = "/html/cross-origin-embedder-policy/resources/corp-image.py";
+
+let EXPECTED_LOADS = {
+  [`NETWORK-${remote(image_path)}`]: false,
+  [`NETWORK-${remote(image_path)}?corp-cross-origin=1`]: true,
+  [`CACHED-${remote(image_path)}`]: false,
+  [`CACHED-${remote(image_path)}?corp-cross-origin=1`]: true,
+}
+
+let TESTS = {};
+for (let t in EXPECTED_LOADS) {
+  TESTS[t] = async_test(t);
+}
+
+window.addEventListener("load", async () => {
+  let iframe = document.createElement("iframe");
+  let firstRun = true;
+  let t = async_test("main_test");
+  await new Promise((resolve, reject) => {
+    iframe.src = "resources/load-corp-images.html";
+    iframe.onload = () => { resolve() };
+    iframe.onerror = (e) => { reject(); };
+    window.addEventListener("message", (event) => {
+      // After the first done event we reload the iframe.
+      if (event.data.done) {
+        if (firstRun) {
+          firstRun = false;
+          iframe.contentWindow.location.reload();
+        } else {
+          // After the second done event the test is finished.
+          t.done();
+        }
+      } else {
+        // Check that each image either loads or doesn't based on the expectations
+        let testName = `${firstRun ? "NETWORK-" : "CACHED-"}${event.data.src}`;
+        let test = TESTS[testName];
+        test.step(() => {
+          assert_equals(event.data.loaded, EXPECTED_LOADS[testName], `${firstRun ? "NETWORK" : "CACHED"} load of ${event.data.src} should ${EXPECTED_LOADS[testName] ? "" : "not"} succeed`);
+        });
+        test.done();
+      }
+    }, false);
+    document.body.appendChild(iframe);
+  })
+});
+
+
+</script>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-embedder-policy/require-corp-cached-images.https.html.headers
@@ -0,0 +1,1 @@
+Cross-Origin-Embedder-Policy: require-corp
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-embedder-policy/resources/corp-image.py
@@ -0,0 +1,27 @@
+import json
+import base64
+
+# A 1x1 PNG image.
+# Source: https://commons.wikimedia.org/wiki/File:1x1.png (Public Domain)
+IMAGE = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII="
+
+def main(request, response):
+    response.headers.set(b'Access-Control-Allow-Origin', b'*')
+    response.headers.set(b'Access-Control-Allow-Methods', b'OPTIONS, GET, POST')
+    response.headers.set(b'Access-Control-Allow-Headers', b'Content-Type')
+
+    response.headers.set(b"Cache-Control", b"max-age=3600");
+    # CORS preflight
+    if request.method == u'OPTIONS':
+        return u''
+
+    if b'some-etag' == request.headers.get(b"If-None-Match", None):
+        response.status = 304
+        return u''
+
+    if request.GET.first(b"corp-cross-origin", default=b""):
+        response.headers.set(b'Cross-Origin-Resource-Policy', b'cross-origin')
+
+    response.headers.set(b'Etag', b'some-etag')
+    response.headers.set(b'Content-Type', b'image/png')
+    return base64.b64decode(IMAGE)
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-embedder-policy/resources/load-corp-images.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<html>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+
+function remote(path) {
+  const REMOTE_ORIGIN = get_host_info().HTTPS_REMOTE_ORIGIN;
+  return new URL(path, REMOTE_ORIGIN);
+}
+
+const image_path = "/html/cross-origin-embedder-policy/resources/corp-image.py";
+
+window.addEventListener("load", async () => {
+  await new Promise(resolve => {
+    let img = document.createElement("img");
+    img.src = remote(image_path);
+    img.onload = () => { window.parent.postMessage({loaded: true, src: img.src}, "*"); resolve(); };
+    img.onerror = (e) => { window.parent.postMessage({loaded: false, src: img.src}, "*"); resolve(); };
+    document.body.appendChild(img);
+  });
+
+  await new Promise(resolve => {
+    let img = document.createElement("img");
+    img.src = remote(image_path + "?corp-cross-origin=1");
+    img.onload = () => { window.parent.postMessage({loaded: true, src: img.src}, "*"); resolve(); };
+    img.onerror = (e) => { window.parent.postMessage({loaded: false, src: img.src}, "*"); resolve(); };
+    document.body.appendChild(img);
+  });
+
+  window.parent.postMessage({done: true}, "*")
+});
+
+</script>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-embedder-policy/resources/load-corp-images.html.headers
@@ -0,0 +1,1 @@
+cross-origin-embedder-policy: require-corp
new file mode 100644
--- /dev/null
+++ b/third_party/rust/arbitrary/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{"CHANGELOG.md":"edf3c8b74500275d5c9136f23c82eadf5356d4e804ef629ac5d15842e6859897","Cargo.lock":"7c30080ec598ac111d312a1e1ace0df52e346dd70ebce305df876906324810bb","Cargo.toml":"1bc1fc9183477e937309eb3c3d25a4aea2973bb858cac84b119a243d0a787be3","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"15656cc11a8331f28c0986b8ab97220d3e76f98e60ed388b5ffad37dfac4710c","README.md":"950e645eba942c01ae12aaf835b23f2b70bcc75c561e663fe483e000d067a57e","examples/derive_enum.rs":"4d399f1805c48780443182aa141be4e3bf773649b118eab245280799e67742f6","publish.sh":"752e221bdd960666b127df15effddd3d789ff3f1762498961fc79ae99f9a27f1","src/error.rs":"88293a722e314bcc05e4836167b49e76520c9b3d7f64d1ae711f7bd29280f480","src/lib.rs":"78ad87737c6f5cdf38f1f2ed797587c6e258739397f21109d3a969f0ee33a140","src/size_hint.rs":"9762b183f8277ee4955fe5b22552961744b6237286758161a551f904ef43e3eb","src/unstructured.rs":"990a08e3037c9cecf7395deecc27fd8c99ec27c8d80c6b5f85c2aca75b629d6e","tests/derive.rs":"6a4aaa87ee08ea2b67e97e7f6fc7c6247ef9a11144b5465a802631ed0ee5465e","tests/path.rs":"a9706f00ce95d5a11652ae926830756d9111837b55073a0bc6a1eadd25033387"},"package":"237430fd6ed3740afe94eefcc278ae21e050285be882804e0d6e8695f0c94691"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/arbitrary/CHANGELOG.md
@@ -0,0 +1,298 @@
+## Unreleased
+
+Released YYYY-MM-DD.
+
+### Added
+
+* TODO (or remove section if none)
+
+### Changed
+
+* TODO (or remove section if none)
+
+### Deprecated
+
+* TODO (or remove section if none)
+
+### Removed
+
+* TODO (or remove section if none)
+
+### Fixed
+
+* TODO (or remove section if none)
+
+### Security
+
+* TODO (or remove section if none)
+
+## 1.0.1
+
+Released 2021-05-20.
+
+### Added
+
+* `Arbitrary` impls for `NonZeroX` types [#79](https://github.com/rust-fuzz/arbitrary/pull/79)
+* `Arbitrary` impls for all arrays using const generics [#55](https://github.com/rust-fuzz/arbitrary/pull/55)
+* `Arbitrary` impls for `Ipv4Addr` and `Ipv6Addr` [#84](https://github.com/rust-fuzz/arbitrary/pull/84)
+
+### Fixed
+
+* Use fewer bytes for `Unstructured::int_in_range()` [#80](https://github.com/rust-fuzz/arbitrary/pull/80)
+* Use correct range for `char` generation [#83](https://github.com/rust-fuzz/arbitrary/pull/83)
+
+--------------------------------------------------------------------------------
+
+## 1.0.0
+
+Released 2020-02-24.
+
+See 1.0.0-rc1 and 1.0.0-rc2 for changes since 0.4.7, which was the last main
+line release.
+
+--------------------------------------------------------------------------------
+
+## 1.0.0-rc2
+
+Released 2021-02-09.
+
+### Added
+
+* The `Arbitrary` trait is now implemented for `&[u8]`. [#67](https://github.com/rust-fuzz/arbitrary/pull/67)
+
+### Changed
+
+* Rename `Unstructured#get_bytes` to `Unstructured#bytes`. [#70](https://github.com/rust-fuzz/arbitrary/pull/70)
+* Passing an empty slice of choices to `Unstructured#choose` returns an error. Previously it would panic. [71](https://github.com/rust-fuzz/arbitrary/pull/71)
+
+--------------------------------------------------------------------------------
+
+## 1.0.0-rc1
+
+Released 2020-11-25.
+
+### Added
+
+* The `Arbitrary` trait is now implemented for `&str`. [#63](https://github.com/rust-fuzz/arbitrary/pull/63)
+
+### Changed
+
+* The `Arbitrary` trait now has a lifetime parameter, allowing `Arbitrary` implementations that borrow from the raw input (e.g. the new `&str` implementaton). The `derive(Arbitrary)` macro also supports deriving `Arbitrary` on types with lifetimes now. [#63](https://github.com/rust-fuzz/arbitrary/pull/63)
+
+### Removed
+
+* The `shrink` method on the `Arbitrary` trait has been removed.
+
+  We have found that, in practice, using [internal reduction](https://drmaciver.github.io/papers/reduction-via-generation-preview.pdf) via approaches like `cargo fuzz tmin`, where the raw input bytes are reduced rather than the `T: Arbitrary` type constructed from those raw bytes, has the best efficiency-to-maintenance ratio. To the best of our knowledge, no one is relying on or using the `Arbitrary::shrink` method. If you *are* using and relying on the `Arbitrary::shrink` method, please reach out by [dropping a comment here](https://github.com/rust-fuzz/arbitrary/issues/62) and explaining how you're using it and what your use case is. We'll figure out what the best solution is, including potentially adding shrinking functionality back to the `arbitrary` crate.
+
+--------------------------------------------------------------------------------
+
+## 0.4.7
+
+Released 2020-10-14.
+
+### Added
+
+* Added an optimization to avoid unnecessarily consuming bytes from the
+  underlying data when there is only one possible choice in
+  `Unstructured::{int_in_range, choose, etc..}`.
+
+* Added license files to the derive crate.
+
+### Changed
+
+* The `Arbitrary` implementation for `std::time::Duration` should now be faster
+  and produce durations with a more-uniform distribution of nanoseconds.
+
+--------------------------------------------------------------------------------
+
+## 0.4.6
+
+Released 2020-08-22.
+
+### Added
+
+* Added the `Unstructured::peek_bytes` method.
+
+### Changed
+
+* Test case reduction via `cargo fuzz tmin` should be much more effective at
+  reducing the sizes of collections now. (See
+  [#53](https://github.com/rust-fuzz/arbitrary/pull/53) and the commit messages
+  for details.)
+
+* Fuzzing with mutation-based fuzzers (like libFuzzer) should be more efficient
+  now. (See [#53](https://github.com/rust-fuzz/arbitrary/pull/53) and the commit
+  messages for details)
+
+--------------------------------------------------------------------------------
+
+## 0.4.5
+
+Released 2020-06-18.
+
+### Added
+
+* Implement `Arbitrary` for zero length arrays.
+* Implement `Arbitrary` for `Range` and `RangeInclusive`.
+
+--------------------------------------------------------------------------------
+
+## 0.4.4
+
+Released 2020-04-29.
+
+### Fixed
+
+* Fixed the custom derive for enums when used via its full path (like
+  `#[derive(arbitrary::Arbitrary)]` rather than like `#[derive(Arbitrary)]`).
+
+
+## 0.4.3
+
+Released 2020-04-28.
+
+### Fixed
+
+* Fixed the custom derive when used via its full path (like
+  `#[derive(arbitrary::Arbitrary)]` rather than like `#[derive(Arbitrary)]`).
+
+--------------------------------------------------------------------------------
+
+## 0.4.2
+
+Released 2020-04-17.
+
+### Changed
+
+* We forgot to release a new version of the `derive_arbitrary` crate last
+  release. This release fixes that and so the `synstructure` dependency is
+  finally actually removed in the cargo releases.
+
+--------------------------------------------------------------------------------
+
+## 0.4.1
+
+Released 2020-03-18.
+
+### Removed
+
+* Removed an internal dependency on the `synstructure` crate when the `derive`
+  feature is enabled. This should not have any visible downstream effects other
+  than faster build times!
+
+--------------------------------------------------------------------------------
+
+## 0.4.0
+
+Released 2020-01-22.
+
+This is technically a breaking change, but we expect that nearly everyone should
+be able to upgrade without any compilation errors. The only exception is if you
+were implementing the `Arbitrary::size_hint` method by hand. If so, see the
+"changed" section below and the [API docs for
+`Arbitrary::shrink`](https://docs.rs/arbitrary/0.4.0/arbitrary/trait.Arbitrary.html#method.size_hint)
+for details.
+
+### Added
+
+* Added [the `arbitary::size_hint::recursion_guard` helper
+  function][recursion_guard] for guarding against infinite recursion in
+  `size_hint` implementations for recursive types.
+
+### Changed
+
+* The `Arbitrary::size_hint` signature now takes a `depth: usize`
+  parameter. This should be passed along unmodified to any nested calls of other
+  `size_hint` methods. If you're implementing `size_hint` for a recursive type
+  (like a linked list or tree) or a generic type with type parameters, you
+  should use [the new `arbitrary::size_hint::recursion_guard` helper
+  function][recursion_guard].
+
+### Fixed
+
+* Fixed infinite recursion in generated `size_hint` implementations
+  from `#[derive(Arbitrary)]` for recursive types.
+
+[recursion_guard]: https://docs.rs/arbitrary/0.4.0/arbitrary/size_hint/fn.recursion_guard.html
+
+--------------------------------------------------------------------------------
+
+## 0.3.2
+
+Released 2020-01-16.
+
+### Changed
+
+* Updated the custom derive's dependencies.
+
+--------------------------------------------------------------------------------
+
+## 0.3.2
+
+Released 2020-01-15.
+
+### Fixed
+
+* Fixed an over-eager assertion condition in `Unstructured::int_in_range` that
+  would incorrectly trigger when given valid ranges of length one.
+
+--------------------------------------------------------------------------------
+
+## 0.3.1
+
+Released 2020-01-14.
+
+### Fixed
+
+* Fixed some links and version numbers in README.
+
+--------------------------------------------------------------------------------
+
+## 0.3.0
+
+Released 2020-01-14.
+
+### Added
+
+* Added the `"derive"` cargo feature, to enable `#[derive(Arbitrary)]` for
+  custom types. Enabling this feature re-exports functionality from the
+  `derive_arbitrary` crate.
+* The custom derive for `Arbitrary` implements the shrink method for you now.
+* All implementations of `Arbitrary` for `std` types implement shrinking now.
+* Added the `Arbitrary::arbitrary_take_rest` method allows an `Arbitrary`
+  implementation to consume all of the rest of the remaining raw input. It has a
+  default implementation that forwards to `Arbitrary::arbitrary` and the custom
+  derive creates a smart implementation for your custom types.
+* Added the `Arbitrary::size_hint` method for hinting how many raw bytes an
+  implementation needs to construct itself. This has a default implementation,
+  but the custom derive creates a smart implementation for your custom types.
+* Added the `Unstructured::choose` method to choose one thing among a set of
+  choices.
+* Added the `Unstructured::arbitrary_len` method to get an arbitrary length for
+  a collection of some arbitrary type.
+* Added the `Unstructured::arbitrary_iter` method to create an iterator of
+  arbitrary instance of some type.
+
+### Changed
+
+* The `Arbitrary` trait was simplified a bit.
+* `Unstructured` is a concrete type now, not a trait.
+* Switched to Rust 2018 edition.
+
+### Removed
+
+* `RingBuffer` and `FiniteBuffer` are removed. Use `Unstructured` instead.
+
+### Fixed
+
+* Better `Arbitrary` implementation for `char`.
+* Better `Arbitrary` implementation for `String`.
+
+--------------------------------------------------------------------------------
+
+## 0.2.0
+
+--------------------------------------------------------------------------------
+
+## 0.1.0
new file mode 100644
--- /dev/null
+++ b/third_party/rust/arbitrary/Cargo.lock
@@ -0,0 +1,56 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "arbitrary"
+version = "1.0.1"
+dependencies = [
+ "derive_arbitrary",
+]
+
+[[package]]
+name = "derive_arbitrary"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df89dd0d075dea5cc5fdd6d5df6b8a61172a710b3efac1d6bdb9dd8b78f82c1a"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.72"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/arbitrary/Cargo.toml
@@ -0,0 +1,41 @@
+# 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
+#
+# 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]
+edition = "2018"
+name = "arbitrary"
+version = "1.0.1"
+authors = ["The Rust-Fuzz Project Developers", "Nick Fitzgerald <fitzgen@gmail.com>", "Manish Goregaokar <manishsmail@gmail.com>", "Simonas Kazlauskas <arbitrary@kazlauskas.me>", "Brian L. Troutwine <brian@troutwine.us>", "Corey Farwell <coreyf@rwell.org>"]
+description = "The trait for generating structured data from unstructured data"
+documentation = "https://docs.rs/arbitrary/"
+readme = "README.md"
+keywords = ["arbitrary", "testing"]
+categories = ["development-tools::testing"]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/rust-fuzz/arbitrary/"
+
+[[example]]
+name = "derive_enum"
+required-features = ["derive"]
+
+[[test]]
+name = "derive"
+path = "./tests/derive.rs"
+required-features = ["derive"]
+[dependencies.derive_arbitrary]
+version = "1.0.0"
+optional = true
+
+[dev-dependencies]
+
+[features]
+derive = ["derive_arbitrary"]
new file mode 100644
--- /dev/null
+++ b/third_party/rust/arbitrary/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+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.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/arbitrary/LICENSE-MIT
@@ -0,0 +1,27 @@
+MIT License
+
+Copyright (c) 2019 Manish Goregaokar
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/arbitrary/README.md
@@ -0,0 +1,96 @@
+<div align="center">
+
+  <h1><code>Arbitrary</code></h1>
+
+  <p><strong>The trait for generating structured data from arbitrary, unstructured input.</strong></p>
+
+  <img alt="GitHub Actions Status" src="https://github.com/rust-fuzz/rust_arbitrary/workflows/Rust/badge.svg"/>
+
+</div>
+
+## About
+
+The `Arbitrary` crate lets you construct arbitrary instances of a type.
+
+This crate is primarily intended to be combined with a fuzzer like [libFuzzer
+and `cargo-fuzz`](https://github.com/rust-fuzz/cargo-fuzz) or
+[AFL](https://github.com/rust-fuzz/afl.rs), and to help you turn the raw,
+untyped byte buffers that they produce into well-typed, valid, structured
+values. This allows you to combine structure-aware test case generation with
+coverage-guided, mutation-based fuzzers.
+
+## Documentation
+
+[**Read the API documentation on `docs.rs`!**](https://docs.rs/arbitrary)
+
+## Example
+
+Say you're writing a color conversion library, and you have an `Rgb` struct to
+represent RGB colors. You might want to implement `Arbitrary` for `Rgb` so that
+you could take arbitrary `Rgb` instances in a test function that asserts some
+property (for example, asserting that RGB converted to HSL and converted back to
+RGB always ends up exactly where we started).
+
+### Automatically Deriving `Arbitrary`
+
+Automatically deriving the `Arbitrary` trait is the recommended way to implement
+`Arbitrary` for your types.
+
+Automatically deriving `Arbitrary` requires you to enable the `"derive"` cargo
+feature:
+
+```toml
+# Cargo.toml
+
+[dependencies]
+arbitrary = { version = "1", features = ["derive"] }
+```
+
+And then you can simply add `#[derive(Arbitrary)]` annotations to your types:
+
+```rust
+// rgb.rs
+
+use arbitrary::Arbitrary;
+
+#[derive(Arbitrary)]
+pub struct Rgb {
+    pub r: u8,
+    pub g: u8,
+    pub b: u8,
+}
+```
+
+### Implementing `Arbitrary` By Hand
+
+Alternatively, you can write an `Arbitrary` implementation by hand:
+
+```rust
+// rgb.rs
+
+use arbitrary::{Arbitrary, Result, Unstructured};
+
+#[derive(Copy, Clone, Debug)]
+pub struct Rgb {
+    pub r: u8,
+    pub g: u8,
+    pub b: u8,
+}
+
+impl<'a> Arbitrary<'a> for Rgb {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        let r = u8::arbitrary(u)?;
+        let g = u8::arbitrary(u)?;
+        let b = u8::arbitrary(u)?;
+        Ok(Rgb { r, g, b })
+    }
+}
+```
+
+## License
+
+Licensed under dual MIT or Apache-2.0 at your choice.
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in this project by you, as defined in the Apache-2.0 license,
+shall be dual licensed as above, without any additional terms or conditions.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/arbitrary/examples/derive_enum.rs
@@ -0,0 +1,23 @@
+//! A simple example of deriving the `Arbitrary` trait for an `enum`.
+//!
+//! Note that this requires enabling the "derive" cargo feature.
+
+use arbitrary::{Arbitrary, Unstructured};
+
+#[derive(Arbitrary, Debug)]
+enum MyEnum {
+    UnitVariant,
+    TupleVariant(bool, u32),
+    StructVariant { x: i8, y: (u8, i32) },
+}
+
+fn main() {
+    let raw = b"This is some raw, unstructured data!";
+
+    let mut unstructured = Unstructured::new(raw);
+
+    let instance = MyEnum::arbitrary(&mut unstructured)
+        .expect("`unstructured` has enough underlying data to create all variants of `MyEnum`");
+
+    println!("Here is an arbitrary enum: {:?}", instance);
+}
new file mode 100755
--- /dev/null
+++ b/third_party/rust/arbitrary/publish.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+set -eux
+
+cd $(dirname $0)/derive
+
+cargo publish
+
+cd ..
+
+# Let the crates.io index figure out we've published `derive_arbitrary` already.
+sleep 5
+
+cargo publish
new file mode 100644
--- /dev/null
+++ b/third_party/rust/arbitrary/src/error.rs
@@ -0,0 +1,40 @@
+use std::{error, fmt};
+
+/// An enumeration of buffer creation errors
+#[derive(Debug, Clone, Copy)]
+#[non_exhaustive]
+pub enum Error {
+    /// No choices were provided to the Unstructured::choose call
+    EmptyChoose,
+    /// There was not enough underlying data to fulfill some request for raw
+    /// bytes.
+    NotEnoughData,
+    /// The input bytes were not of the right format
+    IncorrectFormat,
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Error::EmptyChoose => write!(
+                f,
+                "`arbitrary::Unstructured::choose` must be given a non-empty set of choices"
+            ),
+            Error::NotEnoughData => write!(
+                f,
+                "There is not enough underlying raw data to construct an `Arbitrary` instance"
+            ),
+            Error::IncorrectFormat => write!(
+                f,
+                "The raw data is not of the correct format to construct this type"
+            ),
+        }
+    }
+}
+
+impl error::Error for Error {}
+
+/// A `Result` with the error type fixed as `arbitrary::Error`.
+///
+/// Either an `Ok(T)` or `Err(arbitrary::Error)`.
+pub type Result<T> = std::result::Result<T, Error>;
new file mode 100644
--- /dev/null
+++ b/third_party/rust/arbitrary/src/lib.rs
@@ -0,0 +1,1191 @@
+// Copyright © 2019 The Rust Fuzz Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The `Arbitrary` trait crate.
+//!
+//! This trait provides an [`Arbitrary`](./trait.Arbitrary.html) trait to
+//! produce well-typed, structured values, from raw, byte buffers. It is
+//! generally intended to be used with fuzzers like AFL or libFuzzer. See the
+//! [`Arbitrary`](./trait.Arbitrary.html) trait's documentation for details on
+//! automatically deriving, implementing, and/or using the trait.
+
+#![deny(bad_style)]
+#![deny(missing_docs)]
+#![deny(future_incompatible)]
+#![deny(nonstandard_style)]
+#![deny(rust_2018_compatibility)]
+#![deny(rust_2018_idioms)]
+#![deny(unused)]
+
+#[cfg(feature = "derive_arbitrary")]
+pub use derive_arbitrary::*;
+
+mod error;
+pub use error::*;
+
+pub mod unstructured;
+#[doc(inline)]
+pub use unstructured::Unstructured;
+
+pub mod size_hint;
+
+use core::cell::{Cell, RefCell, UnsafeCell};
+use core::iter;
+use core::mem;
+use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
+use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
+use core::ops::{Range, RangeBounds, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive};
+use core::str;
+use core::time::Duration;
+use std::borrow::{Cow, ToOwned};
+use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque};
+use std::ffi::{CString, OsString};
+use std::net::{Ipv4Addr, Ipv6Addr};
+use std::path::PathBuf;
+use std::rc::Rc;
+use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize};
+use std::sync::{Arc, Mutex};
+
+/// Generate arbitrary structured values from raw, unstructured data.
+///
+/// The `Arbitrary` trait allows you to generate valid structured values, like
+/// `HashMap`s, or ASTs, or `MyTomlConfig`, or any other data structure from
+/// raw, unstructured bytes provided by a fuzzer.
+///
+/// # Deriving `Arbitrary`
+///
+/// Automatically deriving the `Arbitrary` trait is the recommended way to
+/// implement `Arbitrary` for your types.
+///
+/// Using the custom derive requires that you enable the `"derive"` cargo
+/// feature in your `Cargo.toml`:
+///
+/// ```toml
+/// [dependencies]
+/// arbitrary = { version = "1", features = ["derive"] }
+/// ```
+///
+/// Then, you add the `#[derive(Arbitrary)]` annotation to your `struct` or
+/// `enum` type definition:
+///
+/// ```
+/// # #[cfg(feature = "derive")] mod foo {
+/// use arbitrary::Arbitrary;
+/// use std::collections::HashSet;
+///
+/// #[derive(Arbitrary)]
+/// pub struct AddressBook {
+///     friends: HashSet<Friend>,
+/// }
+///
+/// #[derive(Arbitrary, Hash, Eq, PartialEq)]
+/// pub enum Friend {
+///     Buddy { name: String },
+///     Pal { age: usize },
+/// }
+/// # }
+/// ```
+///
+/// Every member of the `struct` or `enum` must also implement `Arbitrary`.
+///
+/// # Implementing `Arbitrary` By Hand
+///
+/// Implementing `Arbitrary` mostly involves nested calls to other `Arbitrary`
+/// arbitrary implementations for each of your `struct` or `enum`'s members. But
+/// sometimes you need some amount of raw data, or you need to generate a
+/// variably-sized collection type, or you something of that sort. The
+/// [`Unstructured`][crate::Unstructured] type helps you with these tasks.
+///
+/// ```
+/// # #[cfg(feature = "derive")] mod foo {
+/// # pub struct MyCollection<T> { _t: std::marker::PhantomData<T> }
+/// # impl<T> MyCollection<T> {
+/// #     pub fn new() -> Self { MyCollection { _t: std::marker::PhantomData } }
+/// #     pub fn insert(&mut self, element: T) {}
+/// # }
+/// use arbitrary::{Arbitrary, Result, Unstructured};
+///
+/// impl<'a, T> Arbitrary<'a> for MyCollection<T>
+/// where
+///     T: Arbitrary<'a>,
+/// {
+///     fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+///         // Get an iterator of arbitrary `T`s.
+///         let iter = u.arbitrary_iter::<T>()?;
+///
+///         // And then create a collection!
+///         let mut my_collection = MyCollection::new();
+///         for elem_result in iter {
+///             let elem = elem_result?;
+///             my_collection.insert(elem);
+///         }
+///
+///         Ok(my_collection)
+///     }
+/// }
+/// # }
+/// ```
+pub trait Arbitrary<'a>: Sized {
+    /// Generate an arbitrary value of `Self` from the given unstructured data.
+    ///
+    /// Calling `Arbitrary::arbitrary` requires that you have some raw data,
+    /// perhaps given to you by a fuzzer like AFL or libFuzzer. You wrap this
+    /// raw data in an `Unstructured`, and then you can call `<MyType as
+    /// Arbitrary>::arbitrary` to construct an arbitrary instance of `MyType`
+    /// from that unstuctured data.
+    ///
+    /// Implementation may return an error if there is not enough data to
+    /// construct a full instance of `Self`. This is generally OK: it is better
+    /// to exit early and get the fuzzer to provide more input data, than it is
+    /// to generate default values in place of the missing data, which would
+    /// bias the distribution of generated values, and ultimately make fuzzing
+    /// less efficient.
+    ///
+    /// ```
+    /// # #[cfg(feature = "derive")] fn foo() {
+    /// use arbitrary::{Arbitrary, Unstructured};
+    ///
+    /// #[derive(Arbitrary)]
+    /// pub struct MyType {
+    ///     // ...
+    /// }
+    ///
+    /// // Get the raw data from the fuzzer or wherever else.
+    /// # let get_raw_data_from_fuzzer = || &[];
+    /// let raw_data: &[u8] = get_raw_data_from_fuzzer();
+    ///
+    /// // Wrap that raw data in an `Unstructured`.
+    /// let mut unstructured = Unstructured::new(raw_data);
+    ///
+    /// // Generate an arbitrary instance of `MyType` and do stuff with it.
+    /// if let Ok(value) = MyType::arbitrary(&mut unstructured) {
+    /// #   let do_stuff = |_| {};
+    ///     do_stuff(value);
+    /// }
+    /// # }
+    /// ```
+    ///
+    /// See also the documentation for [`Unstructured`][crate::Unstructured].
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self>;
+
+    /// Generate an arbitrary value of `Self` from the entirety of the given unstructured data.
+    ///
+    /// This is similar to Arbitrary::arbitrary, however it assumes that it is the
+    /// last consumer of the given data, and is thus able to consume it all if it needs.
+    /// See also the documentation for [`Unstructured`][crate::Unstructured].
+    fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result<Self> {
+        Self::arbitrary(&mut u)
+    }
+
+    /// Get a size hint for how many bytes out of an `Unstructured` this type
+    /// needs to construct itself.
+    ///
+    /// This is useful for determining how many elements we should insert when
+    /// creating an arbitrary collection.
+    ///
+    /// The return value is similar to
+    /// [`Iterator::size_hint`][iterator-size-hint]: it returns a tuple where
+    /// the first element is a lower bound on the number of bytes required, and
+    /// the second element is an optional upper bound.
+    ///
+    /// The default implementation return `(0, None)` which is correct for any
+    /// type, but not ultimately that useful. Using `#[derive(Arbitrary)]` will
+    /// create a better implementation. If you are writing an `Arbitrary`
+    /// implementation by hand, and your type can be part of a dynamically sized
+    /// collection (such as `Vec`), you are strongly encouraged to override this
+    /// default with a better implementation. The
+    /// [`size_hint`][crate::size_hint] module will help with this task.
+    ///
+    /// ## The `depth` Parameter
+    ///
+    /// If you 100% know that the type you are implementing `Arbitrary` for is
+    /// not a recursive type, or your implementation is not transitively calling
+    /// any other `size_hint` methods, you can ignore the `depth` parameter.
+    /// Note that if you are implementing `Arbitrary` for a generic type, you
+    /// cannot guarantee the lack of type recursion!
+    ///
+    /// Otherwise, you need to use
+    /// [`arbitrary::size_hint::recursion_guard(depth)`][crate::size_hint::recursion_guard]
+    /// to prevent potential infinite recursion when calculating size hints for
+    /// potentially recursive types:
+    ///
+    /// ```
+    /// use arbitrary::{Arbitrary, Unstructured, size_hint};
+    ///
+    /// // This can potentially be a recursive type if `L` or `R` contain
+    /// // something like `Box<Option<MyEither<L, R>>>`!
+    /// enum MyEither<L, R> {
+    ///     Left(L),
+    ///     Right(R),
+    /// }
+    ///
+    /// impl<'a, L, R> Arbitrary<'a> for MyEither<L, R>
+    /// where
+    ///     L: Arbitrary<'a>,
+    ///     R: Arbitrary<'a>,
+    /// {
+    ///     fn arbitrary(u: &mut Unstructured) -> arbitrary::Result<Self> {
+    ///         // ...
+    /// #       unimplemented!()
+    ///     }
+    ///
+    ///     fn size_hint(depth: usize) -> (usize, Option<usize>) {
+    ///         // Protect against potential infinite recursion with
+    ///         // `recursion_guard`.
+    ///         size_hint::recursion_guard(depth, |depth| {
+    ///             // If we aren't too deep, then `recursion_guard` calls
+    ///             // this closure, which implements the natural size hint.
+    ///             // Don't forget to use the new `depth` in all nested
+    ///             // `size_hint` calls! We recommend shadowing the
+    ///             // parameter, like what is done here, so that you can't
+    ///             // accidentally use the wrong depth.
+    ///             size_hint::or(
+    ///                 <L as Arbitrary>::size_hint(depth),
+    ///                 <R as Arbitrary>::size_hint(depth),
+    ///             )
+    ///         })
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// [iterator-size-hint]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.size_hint
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        let _ = depth;
+        (0, None)
+    }
+}
+
+impl<'a> Arbitrary<'a> for () {
+    fn arbitrary(_: &mut Unstructured<'a>) -> Result<Self> {
+        Ok(())
+    }
+
+    #[inline]
+    fn size_hint(_depth: usize) -> (usize, Option<usize>) {
+        (0, Some(0))
+    }
+}
+
+impl<'a> Arbitrary<'a> for bool {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        Ok(<u8 as Arbitrary<'a>>::arbitrary(u)? & 1 == 1)
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        <u8 as Arbitrary<'a>>::size_hint(depth)
+    }
+}
+
+macro_rules! impl_arbitrary_for_integers {
+    ( $( $ty:ty: $unsigned:ty; )* ) => {
+        $(
+            impl<'a> Arbitrary<'a> for $ty {
+                fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+                    let mut buf = [0; mem::size_of::<$ty>()];
+                    u.fill_buffer(&mut buf)?;
+                    let mut x: $unsigned = 0;
+                    for i in 0..mem::size_of::<$ty>() {
+                        x |= buf[i] as $unsigned << (i * 8);
+                    }
+                    Ok(x as $ty)
+                }
+
+                #[inline]
+                fn size_hint(_depth: usize) -> (usize, Option<usize>) {
+                    let n = mem::size_of::<$ty>();
+                    (n, Some(n))
+                }
+
+            }
+        )*
+    }
+}
+
+impl_arbitrary_for_integers! {
+    u8: u8;
+    u16: u16;
+    u32: u32;
+    u64: u64;
+    u128: u128;
+    usize: usize;
+    i8: u8;
+    i16: u16;
+    i32: u32;
+    i64: u64;
+    i128: u128;
+    isize: usize;
+}
+
+macro_rules! impl_arbitrary_for_floats {
+    ( $( $ty:ident : $unsigned:ty; )* ) => {
+        $(
+            impl<'a> Arbitrary<'a> for $ty {
+                fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+                    Ok(Self::from_bits(<$unsigned as Arbitrary<'a>>::arbitrary(u)?))
+                }
+
+                #[inline]
+                fn size_hint(depth: usize) -> (usize, Option<usize>) {
+                    <$unsigned as Arbitrary<'a>>::size_hint(depth)
+                }
+            }
+        )*
+    }
+}
+
+impl_arbitrary_for_floats! {
+    f32: u32;
+    f64: u64;
+}
+
+impl<'a> Arbitrary<'a> for char {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        use std::char;
+        // The highest unicode code point is 0x11_FFFF
+        const CHAR_END: u32 = 0x11_0000;
+        // The size of the surrogate blocks
+        const SURROGATES_START: u32 = 0xD800;
+        let mut c = <u32 as Arbitrary<'a>>::arbitrary(u)? % CHAR_END;
+        if let Some(c) = char::from_u32(c) {
+            Ok(c)
+        } else {
+            // We found a surrogate, wrap and try again
+            c -= SURROGATES_START;
+            Ok(char::from_u32(c)
+                .expect("Generated character should be valid! This is a bug in arbitrary-rs"))
+        }
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        <u32 as Arbitrary<'a>>::size_hint(depth)
+    }
+}
+
+impl<'a> Arbitrary<'a> for AtomicBool {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        Arbitrary::arbitrary(u).map(Self::new)
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        <bool as Arbitrary<'a>>::size_hint(depth)
+    }
+}
+
+impl<'a> Arbitrary<'a> for AtomicIsize {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        Arbitrary::arbitrary(u).map(Self::new)
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        <isize as Arbitrary<'a>>::size_hint(depth)
+    }
+}
+
+impl<'a> Arbitrary<'a> for AtomicUsize {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        Arbitrary::arbitrary(u).map(Self::new)
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        <usize as Arbitrary<'a>>::size_hint(depth)
+    }
+}
+
+macro_rules! impl_range {
+    (
+        $range:ty,
+        $value_closure:expr,
+        $value_ty:ty,
+        $fun:ident($fun_closure:expr),
+        $size_hint_closure:expr
+    ) => {
+        impl<'a, A> Arbitrary<'a> for $range
+        where
+            A: Arbitrary<'a> + Clone + PartialOrd,
+        {
+            fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+                let value: $value_ty = Arbitrary::arbitrary(u)?;
+                Ok($fun(value, $fun_closure))
+            }
+
+            #[inline]
+            fn size_hint(depth: usize) -> (usize, Option<usize>) {
+                $size_hint_closure(depth)
+            }
+        }
+    };
+}
+
+impl_range!(
+    Range<A>,
+    |r: &Range<A>| (r.start.clone(), r.end.clone()),
+    (A, A),
+    bounded_range(|(a, b)| a..b),
+    |depth| crate::size_hint::and(
+        <A as Arbitrary>::size_hint(depth),
+        <A as Arbitrary>::size_hint(depth)
+    )
+);
+impl_range!(
+    RangeFrom<A>,
+    |r: &RangeFrom<A>| r.start.clone(),
+    A,
+    unbounded_range(|a| a..),
+    |depth| <A as Arbitrary>::size_hint(depth)
+);
+impl_range!(
+    RangeInclusive<A>,
+    |r: &RangeInclusive<A>| (r.start().clone(), r.end().clone()),
+    (A, A),
+    bounded_range(|(a, b)| a..=b),
+    |depth| crate::size_hint::and(
+        <A as Arbitrary>::size_hint(depth),
+        <A as Arbitrary>::size_hint(depth)
+    )
+);
+impl_range!(
+    RangeTo<A>,
+    |r: &RangeTo<A>| r.end.clone(),
+    A,
+    unbounded_range(|b| ..b),
+    |depth| <A as Arbitrary>::size_hint(depth)
+);
+impl_range!(
+    RangeToInclusive<A>,
+    |r: &RangeToInclusive<A>| r.end.clone(),
+    A,
+    unbounded_range(|b| ..=b),
+    |depth| <A as Arbitrary>::size_hint(depth)
+);
+
+pub(crate) fn bounded_range<CB, I, R>(bounds: (I, I), cb: CB) -> R
+where
+    CB: Fn((I, I)) -> R,
+    I: PartialOrd,
+    R: RangeBounds<I>,
+{
+    let (mut start, mut end) = bounds;
+    if start > end {
+        mem::swap(&mut start, &mut end);
+    }
+    cb((start, end))
+}
+
+pub(crate) fn unbounded_range<CB, I, R>(bound: I, cb: CB) -> R
+where
+    CB: Fn(I) -> R,
+    R: RangeBounds<I>,
+{
+    cb(bound)
+}
+
+impl<'a> Arbitrary<'a> for Duration {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        Ok(Self::new(
+            <u64 as Arbitrary>::arbitrary(u)?,
+            u.int_in_range(0..=999_999_999)?,
+        ))
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        crate::size_hint::and(
+            <u64 as Arbitrary>::size_hint(depth),
+            <u32 as Arbitrary>::size_hint(depth),
+        )
+    }
+}
+
+impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Option<A> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        Ok(if <bool as Arbitrary<'a>>::arbitrary(u)? {
+            Some(Arbitrary::arbitrary(u)?)
+        } else {
+            None
+        })
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        crate::size_hint::and(
+            <bool as Arbitrary>::size_hint(depth),
+            crate::size_hint::or((0, Some(0)), <A as Arbitrary>::size_hint(depth)),
+        )
+    }
+}
+
+impl<'a, A: Arbitrary<'a>, B: Arbitrary<'a>> Arbitrary<'a> for std::result::Result<A, B> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        Ok(if <bool as Arbitrary<'a>>::arbitrary(u)? {
+            Ok(<A as Arbitrary>::arbitrary(u)?)
+        } else {
+            Err(<B as Arbitrary>::arbitrary(u)?)
+        })
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        crate::size_hint::and(
+            <bool as Arbitrary>::size_hint(depth),
+            crate::size_hint::or(
+                <A as Arbitrary>::size_hint(depth),
+                <B as Arbitrary>::size_hint(depth),
+            ),
+        )
+    }
+}
+
+macro_rules! arbitrary_tuple {
+    () => {};
+    ($last: ident $($xs: ident)*) => {
+        arbitrary_tuple!($($xs)*);
+
+        impl<'a, $($xs: Arbitrary<'a>,)* $last: Arbitrary<'a>> Arbitrary<'a> for ($($xs,)* $last,) {
+            fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+                Ok(($($xs::arbitrary(u)?,)* Arbitrary::arbitrary(u)?,))
+            }
+
+            #[allow(unused_mut, non_snake_case)]
+            fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result<Self> {
+                $(let $xs = $xs::arbitrary(&mut u)?;)*
+                let $last = $last::arbitrary_take_rest(u)?;
+                Ok(($($xs,)* $last,))
+            }
+
+            #[inline]
+            fn size_hint(depth: usize) -> (usize, Option<usize>) {
+                crate::size_hint::and_all(&[
+                    <$last as Arbitrary>::size_hint(depth),
+                    $( <$xs as Arbitrary>::size_hint(depth) ),*
+                ])
+            }
+        }
+    };
+}
+arbitrary_tuple!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z);
+
+// Helper to safely create arrays since the standard library doesn't
+// provide one yet. Shouldn't be necessary in the future.
+struct ArrayGuard<T, const N: usize> {
+    dst: *mut T,
+    initialized: usize,
+}
+
+impl<T, const N: usize> Drop for ArrayGuard<T, N> {
+    fn drop(&mut self) {
+        debug_assert!(self.initialized <= N);
+        let initialized_part = core::ptr::slice_from_raw_parts_mut(self.dst, self.initialized);
+        unsafe {
+            core::ptr::drop_in_place(initialized_part);
+        }
+    }
+}
+
+fn create_array<F, T, const N: usize>(mut cb: F) -> [T; N]
+where
+    F: FnMut(usize) -> T,
+{
+    let mut array: mem::MaybeUninit<[T; N]> = mem::MaybeUninit::uninit();
+    let array_ptr = array.as_mut_ptr();
+    let dst = array_ptr as _;
+    let mut guard: ArrayGuard<T, N> = ArrayGuard {
+        dst,
+        initialized: 0,
+    };
+    unsafe {
+        for (idx, value_ptr) in (&mut *array.as_mut_ptr()).iter_mut().enumerate() {
+            core::ptr::write(value_ptr, cb(idx));
+            guard.initialized += 1;
+        }
+        mem::forget(guard);
+        array.assume_init()
+    }
+}
+
+fn try_create_array<F, T, const N: usize>(mut cb: F) -> Result<[T; N]>
+where
+    F: FnMut(usize) -> Result<T>,
+{
+    let mut array: mem::MaybeUninit<[T; N]> = mem::MaybeUninit::uninit();
+    let array_ptr = array.as_mut_ptr();
+    let dst = array_ptr as _;
+    let mut guard: ArrayGuard<T, N> = ArrayGuard {
+        dst,
+        initialized: 0,
+    };
+    unsafe {
+        for (idx, value_ptr) in (&mut *array.as_mut_ptr()).iter_mut().enumerate() {
+            core::ptr::write(value_ptr, cb(idx)?);
+            guard.initialized += 1;
+        }
+        mem::forget(guard);
+        Ok(array.assume_init())
+    }
+}
+
+impl<'a, T, const N: usize> Arbitrary<'a> for [T; N]
+where
+    T: Arbitrary<'a>,
+{
+    #[inline]
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        try_create_array(|_| <T as Arbitrary<'a>>::arbitrary(u))
+    }
+
+    #[inline]
+    fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result<Self> {
+        let mut array = Self::arbitrary(&mut u)?;
+        if let Some(last) = array.last_mut() {
+            *last = Arbitrary::arbitrary_take_rest(u)?;
+        }
+        Ok(array)
+    }
+
+    #[inline]
+    fn size_hint(d: usize) -> (usize, Option<usize>) {
+        crate::size_hint::and_all(&create_array::<_, (usize, Option<usize>), N>(|_| {
+            <T as Arbitrary>::size_hint(d)
+        }))
+    }
+}
+
+impl<'a> Arbitrary<'a> for &'a [u8] {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        let len = u.arbitrary_len::<u8>()?;
+        u.bytes(len)
+    }
+
+    fn arbitrary_take_rest(u: Unstructured<'a>) -> Result<Self> {
+        Ok(u.take_rest())
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        <usize as Arbitrary>::size_hint(depth)
+    }
+}
+
+impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Vec<A> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        u.arbitrary_iter()?.collect()
+    }
+
+    fn arbitrary_take_rest(u: Unstructured<'a>) -> Result<Self> {
+        u.arbitrary_take_rest_iter()?.collect()
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        crate::size_hint::and(<usize as Arbitrary>::size_hint(depth), (0, None))
+    }
+}
+
+impl<'a, K: Arbitrary<'a> + Ord, V: Arbitrary<'a>> Arbitrary<'a> for BTreeMap<K, V> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        u.arbitrary_iter()?.collect()
+    }
+
+    fn arbitrary_take_rest(u: Unstructured<'a>) -> Result<Self> {
+        u.arbitrary_take_rest_iter()?.collect()
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        crate::size_hint::and(<usize as Arbitrary>::size_hint(depth), (0, None))
+    }
+}
+
+impl<'a, A: Arbitrary<'a> + Ord> Arbitrary<'a> for BTreeSet<A> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        u.arbitrary_iter()?.collect()
+    }
+
+    fn arbitrary_take_rest(u: Unstructured<'a>) -> Result<Self> {
+        u.arbitrary_take_rest_iter()?.collect()
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        crate::size_hint::and(<usize as Arbitrary>::size_hint(depth), (0, None))
+    }
+}
+
+impl<'a, A: Arbitrary<'a> + Ord> Arbitrary<'a> for BinaryHeap<A> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        u.arbitrary_iter()?.collect()
+    }
+
+    fn arbitrary_take_rest(u: Unstructured<'a>) -> Result<Self> {
+        u.arbitrary_take_rest_iter()?.collect()
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        crate::size_hint::and(<usize as Arbitrary>::size_hint(depth), (0, None))
+    }
+}
+
+impl<'a, K: Arbitrary<'a> + Eq + ::std::hash::Hash, V: Arbitrary<'a>> Arbitrary<'a>
+    for HashMap<K, V>
+{
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        u.arbitrary_iter()?.collect()
+    }
+
+    fn arbitrary_take_rest(u: Unstructured<'a>) -> Result<Self> {
+        u.arbitrary_take_rest_iter()?.collect()
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        crate::size_hint::and(<usize as Arbitrary>::size_hint(depth), (0, None))
+    }
+}
+
+impl<'a, A: Arbitrary<'a> + Eq + ::std::hash::Hash> Arbitrary<'a> for HashSet<A> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        u.arbitrary_iter()?.collect()
+    }
+
+    fn arbitrary_take_rest(u: Unstructured<'a>) -> Result<Self> {
+        u.arbitrary_take_rest_iter()?.collect()
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        crate::size_hint::and(<usize as Arbitrary>::size_hint(depth), (0, None))
+    }
+}
+
+impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for LinkedList<A> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        u.arbitrary_iter()?.collect()
+    }
+
+    fn arbitrary_take_rest(u: Unstructured<'a>) -> Result<Self> {
+        u.arbitrary_take_rest_iter()?.collect()
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        crate::size_hint::and(<usize as Arbitrary>::size_hint(depth), (0, None))
+    }
+}
+
+impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for VecDeque<A> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        u.arbitrary_iter()?.collect()
+    }
+
+    fn arbitrary_take_rest(u: Unstructured<'a>) -> Result<Self> {
+        u.arbitrary_take_rest_iter()?.collect()
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        crate::size_hint::and(<usize as Arbitrary>::size_hint(depth), (0, None))
+    }
+}
+
+impl<'a, A> Arbitrary<'a> for Cow<'a, A>
+where
+    A: ToOwned + ?Sized,
+    <A as ToOwned>::Owned: Arbitrary<'a>,
+{
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        Arbitrary::arbitrary(u).map(Cow::Owned)
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        crate::size_hint::recursion_guard(depth, |depth| {
+            <<A as ToOwned>::Owned as Arbitrary>::size_hint(depth)
+        })
+    }
+}
+
+impl<'a> Arbitrary<'a> for &'a str {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        let size = u.arbitrary_len::<u8>()?;
+        match str::from_utf8(&u.peek_bytes(size).unwrap()) {
+            Ok(s) => {
+                u.bytes(size).unwrap();
+                Ok(s)
+            }
+            Err(e) => {
+                let i = e.valid_up_to();
+                let valid = u.bytes(i).unwrap();
+                let s = unsafe {
+                    debug_assert!(str::from_utf8(valid).is_ok());
+                    str::from_utf8_unchecked(valid)
+                };
+                Ok(s)
+            }
+        }
+    }
+
+    fn arbitrary_take_rest(u: Unstructured<'a>) -> Result<Self> {
+        let bytes = u.take_rest();
+        str::from_utf8(bytes)
+            .map_err(|_| Error::IncorrectFormat)
+            .map(Into::into)
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        crate::size_hint::and(<usize as Arbitrary>::size_hint(depth), (0, None))
+    }
+}
+
+impl<'a> Arbitrary<'a> for String {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        <&str as Arbitrary>::arbitrary(u).map(Into::into)
+    }
+
+    fn arbitrary_take_rest(u: Unstructured<'a>) -> Result<Self> {
+        <&str as Arbitrary>::arbitrary_take_rest(u).map(Into::into)
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        <&str as Arbitrary>::size_hint(depth)
+    }
+}
+
+impl<'a> Arbitrary<'a> for CString {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        <Vec<u8> as Arbitrary>::arbitrary(u).map(|mut x| {
+            x.retain(|&c| c != 0);
+            Self::new(x).unwrap()
+        })
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        <Vec<u8> as Arbitrary>::size_hint(depth)
+    }
+}
+
+impl<'a> Arbitrary<'a> for OsString {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        <String as Arbitrary>::arbitrary(u).map(From::from)
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        <String as Arbitrary>::size_hint(depth)
+    }
+}
+
+impl<'a> Arbitrary<'a> for PathBuf {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        <OsString as Arbitrary>::arbitrary(u).map(From::from)
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        <OsString as Arbitrary>::size_hint(depth)
+    }
+}
+
+impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Box<A> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        Arbitrary::arbitrary(u).map(Self::new)
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        crate::size_hint::recursion_guard(depth, <A as Arbitrary>::size_hint)
+    }
+}
+
+impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Box<[A]> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        <Vec<A> as Arbitrary>::arbitrary(u).map(|x| x.into_boxed_slice())
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        <Vec<A> as Arbitrary>::size_hint(depth)
+    }
+}
+
+impl<'a> Arbitrary<'a> for Box<str> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        <String as Arbitrary>::arbitrary(u).map(|x| x.into_boxed_str())
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        <String as Arbitrary>::size_hint(depth)
+    }
+}
+
+// impl Arbitrary for Box<CStr> {
+//     fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self> {
+//         <CString as Arbitrary>::arbitrary(u).map(|x| x.into_boxed_c_str())
+//     }
+// }
+
+// impl Arbitrary for Box<OsStr> {
+//     fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self> {
+//         <OsString as Arbitrary>::arbitrary(u).map(|x| x.into_boxed_osstr())
+//
+//     }
+// }
+
+impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Arc<A> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        Arbitrary::arbitrary(u).map(Self::new)
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        crate::size_hint::recursion_guard(depth, <A as Arbitrary>::size_hint)
+    }
+}
+
+impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Rc<A> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        Arbitrary::arbitrary(u).map(Self::new)
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        crate::size_hint::recursion_guard(depth, <A as Arbitrary>::size_hint)
+    }
+}
+
+impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Cell<A> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        Arbitrary::arbitrary(u).map(Self::new)
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        <A as Arbitrary<'a>>::size_hint(depth)
+    }
+}
+
+impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for RefCell<A> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        Arbitrary::arbitrary(u).map(Self::new)
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        <A as Arbitrary<'a>>::size_hint(depth)
+    }
+}
+
+impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for UnsafeCell<A> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        Arbitrary::arbitrary(u).map(Self::new)
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        <A as Arbitrary<'a>>::size_hint(depth)
+    }
+}
+
+impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Mutex<A> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        Arbitrary::arbitrary(u).map(Self::new)
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        <A as Arbitrary<'a>>::size_hint(depth)
+    }
+}
+
+impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for iter::Empty<A> {
+    fn arbitrary(_: &mut Unstructured<'a>) -> Result<Self> {
+        Ok(iter::empty())
+    }
+
+    #[inline]
+    fn size_hint(_depth: usize) -> (usize, Option<usize>) {
+        (0, Some(0))
+    }
+}
+
+impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for ::std::marker::PhantomData<A> {
+    fn arbitrary(_: &mut Unstructured<'a>) -> Result<Self> {
+        Ok(::std::marker::PhantomData)
+    }
+
+    #[inline]
+    fn size_hint(_depth: usize) -> (usize, Option<usize>) {
+        (0, Some(0))
+    }
+}
+
+impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for ::std::num::Wrapping<A> {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        Arbitrary::arbitrary(u).map(::std::num::Wrapping)
+    }
+
+    #[inline]
+    fn size_hint(depth: usize) -> (usize, Option<usize>) {
+        <A as Arbitrary<'a>>::size_hint(depth)
+    }
+}
+
+macro_rules! implement_nonzero_int {
+    ($nonzero:ty, $int:ty) => {
+        impl<'a> Arbitrary<'a> for $nonzero {
+            fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+                match Self::new(<$int as Arbitrary<'a>>::arbitrary(u)?) {
+                    Some(n) => Ok(n),
+                    None => Err(Error::IncorrectFormat),
+                }
+            }
+
+            #[inline]
+            fn size_hint(depth: usize) -> (usize, Option<usize>) {
+                <$int as Arbitrary<'a>>::size_hint(depth)
+            }
+        }
+    };
+}
+
+implement_nonzero_int! { NonZeroI8, i8 }
+implement_nonzero_int! { NonZeroI16, i16 }
+implement_nonzero_int! { NonZeroI32, i32 }
+implement_nonzero_int! { NonZeroI64, i64 }
+implement_nonzero_int! { NonZeroI128, i128 }
+implement_nonzero_int! { NonZeroIsize, isize }
+implement_nonzero_int! { NonZeroU8, u8 }
+implement_nonzero_int! { NonZeroU16, u16 }
+implement_nonzero_int! { NonZeroU32, u32 }
+implement_nonzero_int! { NonZeroU64, u64 }
+implement_nonzero_int! { NonZeroU128, u128 }
+implement_nonzero_int! { NonZeroUsize, usize }
+
+impl<'a> Arbitrary<'a> for Ipv4Addr {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        Ok(Ipv4Addr::from(u32::arbitrary(u)?))
+    }
+
+    #[inline]
+    fn size_hint(_depth: usize) -> (usize, Option<usize>) {
+        (4, Some(4))
+    }
+}
+
+impl<'a> Arbitrary<'a> for Ipv6Addr {
+    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+        Ok(Ipv6Addr::from(u128::arbitrary(u)?))
+    }
+
+    #[inline]
+    fn size_hint(_depth: usize) -> (usize, Option<usize>) {
+        (16, Some(16))
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn finite_buffer_fill_buffer() {
+        let x = [1, 2, 3, 4];
+        let mut rb = Unstructured::new(&x);
+        let mut z = [0; 2];
+        rb.fill_buffer(&mut z).unwrap();
+        assert_eq!(z, [1, 2]);
+        rb.fill_buffer(&mut z).unwrap();
+        assert_eq!(z, [3, 4]);
+        rb.fill_buffer(&mut z).unwrap();
+        assert_eq!(z, [0, 0]);
+    }
+
+    #[test]
+    fn arbitrary_for_integers() {
+        let x = [1, 2, 3, 4];
+        let mut buf = Unstructured::new(&x);
+        let expected = 1 | (2 << 8) | (3 << 16) | (4 << 24);
+        let actual = i32::arbitrary(&mut buf).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn arbitrary_for_bytes() {
+        let x = [1, 2, 3, 4, 4];
+        let mut buf = Unstructured::new(&x);
+        let expected = &[1, 2, 3, 4];
+        let actual = <&[u8] as Arbitrary>::arbitrary(&mut buf).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn arbitrary_take_rest_for_bytes() {
+        let x = [1, 2, 3, 4];
+        let buf = Unstructured::new(&x);
+        let expected = &[1, 2, 3, 4];
+        let actual = <&[u8] as Arbitrary>::arbitrary_take_rest(buf).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn arbitrary_collection() {
+        let x = [
+            1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8,
+        ];
+        assert_eq!(
+            Vec::<u8>::arbitrary(&mut Unstructured::new(&x)).unwrap(),
+            &[2, 4, 6, 8, 1]
+        );
+        assert_eq!(
+            Vec::<u32>::arbitrary(&mut Unstructured::new(&x)).unwrap(),
+            &[84148994]
+        );
+        assert_eq!(
+            String::arbitrary(&mut Unstructured::new(&x)).unwrap(),
+            "\x01\x02\x03\x04\x05\x06\x07\x08"
+        );
+    }
+
+    #[test]
+    fn arbitrary_take_rest() {
+        let x = [1, 2, 3, 4];
+        assert_eq!(
+            Vec::<u8>::arbitrary_take_rest(Unstructured::new(&x)).unwrap(),
+            &[1, 2, 3, 4]
+        );
+        assert_eq!(
+            Vec::<u32>::arbitrary_take_rest(Unstructured::new(&x)).unwrap(),
+            &[0x4030201]
+        );
+        assert_eq!(
+            String::arbitrary_take_rest(Unstructured::new(&x)).unwrap(),
+            "\x01\x02\x03\x04"
+        );
+    }
+
+    #[test]
+    fn size_hint_for_tuples() {
+        assert_eq!(
+            (7, Some(7)),
+            <(bool, u16, i32) as Arbitrary<'_>>::size_hint(0)
+        );
+        assert_eq!(
+            (1 + mem::size_of::<usize>(), None),
+            <(u8, Vec<u8>) as Arbitrary>::size_hint(0)
+        );
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/arbitrary/src/size_hint.rs
@@ -0,0 +1,124 @@
+//! Utilities for working with and combining the results of
+//! [`Arbitrary::size_hint`][crate::Arbitrary::size_hint].
+
+/// Protects against potential infinite recursion when calculating size hints
+/// due to indirect type recursion.
+///
+/// When the depth is not too deep, calls `f` with `depth + 1` to calculate the
+/// size hint.
+///
+/// Otherwise, returns the default size hint: `(0, None)`.
+#[inline]
+pub fn recursion_guard(
+    depth: usize,
+    f: impl FnOnce(usize) -> (usize, Option<usize>),
+) -> (usize, Option<usize>) {
+    const MAX_DEPTH: usize = 20;
+    if depth > MAX_DEPTH {
+        (0, None)
+    } else {
+        f(depth + 1)
+    }
+}
+
+/// Take the sum of the `lhs` and `rhs` size hints.
+#[inline]
+pub fn and(lhs: (usize, Option<usize>), rhs: (usize, Option<usize>)) -> (usize, Option<usize>) {
+    let lower = lhs.0 + rhs.0;
+    let upper = lhs.1.and_then(|lhs| rhs.1.map(|rhs| lhs + rhs));
+    (lower, upper)
+}
+
+/// Take the sum of all of the given size hints.
+///
+/// If `hints` is empty, returns `(0, Some(0))`, aka the size of consuming
+/// nothing.
+#[inline]
+pub fn and_all(hints: &[(usize, Option<usize>)]) -> (usize, Option<usize>) {
+    hints.iter().copied().fold((0, Some(0)), and)
+}
+
+/// Take the minimum of the lower bounds and maximum of the upper bounds in the
+/// `lhs` and `rhs` size hints.
+#[inline]
+pub fn or(lhs: (usize, Option<usize>), rhs: (usize, Option<usize>)) -> (usize, Option<usize>) {
+    let lower = std::cmp::min(lhs.0, rhs.0);
+    let upper = lhs
+        .1
+        .and_then(|lhs| rhs.1.map(|rhs| std::cmp::max(lhs, rhs)));
+    (lower, upper)
+}
+
+/// Take the maximum of the `lhs` and `rhs` size hints.
+///
+/// If `hints` is empty, returns `(0, Some(0))`, aka the size of consuming
+/// nothing.
+#[inline]
+pub fn or_all(hints: &[(usize, Option<usize>)]) -> (usize, Option<usize>) {
+    if let Some(head) = hints.first().copied() {
+        hints[1..].iter().copied().fold(head, or)
+    } else {
+        (0, Some(0))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    #[test]
+    fn and() {
+        assert_eq!((5, Some(5)), super::and((2, Some(2)), (3, Some(3))));
+        assert_eq!((5, None), super::and((2, Some(2)), (3, None)));
+        assert_eq!((5, None), super::and((2, None), (3, Some(3))));
+        assert_eq!((5, None), super::and((2, None), (3, None)));
+    }
+
+    #[test]
+    fn or() {
+        assert_eq!((2, Some(3)), super::or((2, Some(2)), (3, Some(3))));
+        assert_eq!((2, None), super::or((2, Some(2)), (3, None)));
+        assert_eq!((2, None), super::or((2, None), (3, Some(3))));
+        assert_eq!((2, None), super::or((2, None), (3, None)));
+    }
+
+    #[test]
+    fn and_all() {
+        assert_eq!((0, Some(0)), super::and_all(&[]));
+        assert_eq!(
+            (7, Some(7)),
+            super::and_all(&[(1, Some(1)), (2, Some(2)), (4, Some(4))])
+        );
+        assert_eq!(
+            (7, None),
+            super::and_all(&[(1, Some(1)), (2, Some(2)), (4, None)])
+        );
+        assert_eq!(
+            (7, None),
+            super::and_all(&[(1, Some(1)), (2, None), (4, Some(4))])
+        );
+        assert_eq!(
+            (7, None),
+            super::and_all(&[(1, None), (2, Some(2)), (4, Some(4))])
+        );
+    }
+
+    #[test]
+    fn or_all() {
+        assert_eq!((0, Some(0)), super::or_all(&[]));
+        assert_eq!(
+            (1, Some(4)),
+            super::or_all(&[(1, Some(1)), (2, Some(2)), (4, Some(4))])
+        );
+        assert_eq!(
+            (1, None),
+            super::or_all(&[(1, Some(1)), (2, Some(2)), (4, None)])
+        );
+        assert_eq!(
+            (1, None),
+            super::or_all(&[(1, Some(1)), (2, None), (4, Some(4))])
+        );
+        assert_eq!(
+            (1, None),
+            super::or_all(&[(1, None), (2, Some(2)), (4, Some(4))])
+        );
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/arbitrary/src/unstructured.rs
@@ -0,0 +1,714 @@
+// Copyright © 2019 The Rust Fuzz Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Wrappers around raw, unstructured bytes.
+
+use crate::{Arbitrary, Error, Result};
+use std::marker::PhantomData;
+use std::{mem, ops};
+
+/// A source of unstructured data.
+///
+/// An `Unstructured` helps `Arbitrary` implementations interpret raw data
+/// (typically provided by a fuzzer) as a "DNA string" that describes how to
+/// construct the `Arbitrary` type. The goal is that a small change to the "DNA
+/// string" (the raw data wrapped by an `Unstructured`) results in a small
+/// change to the generated `Arbitrary` instance. This helps a fuzzer
+/// efficiently explore the `Arbitrary`'s input space.
+///
+/// `Unstructured` is deterministic: given the same raw data, the same series of
+/// API calls will return the same results (modulo system resource constraints,
+/// like running out of memory). However, `Unstructured` does not guarantee
+/// anything beyond that: it makes not guarantee that it will yield bytes from
+/// the underlying data in any particular order.
+///
+/// You shouldn't generally need to use an `Unstructured` unless you are writing
+/// a custom `Arbitrary` implementation by hand, instead of deriving it. Mostly,
+/// you should just be passing it through to nested `Arbitrary::arbitrary`
+/// calls.
+///
+/// # Example
+///
+/// Imagine you were writing a color conversion crate. You might want to write
+/// fuzz tests that take a random RGB color and assert various properties, run
+/// functions and make sure nothing panics, etc.
+///
+/// Below is what translating the fuzzer's raw input into an `Unstructured` and
+/// using that to generate an arbitrary RGB color might look like:
+///
+/// ```
+/// # #[cfg(feature = "derive")] fn foo() {
+/// use arbitrary::{Arbitrary, Unstructured};
+///
+/// /// An RGB color.
+/// #[derive(Arbitrary)]
+/// pub struct Rgb {
+///     r: u8,
+///     g: u8,
+///     b: u8,
+/// }
+///
+/// // Get the raw bytes from the fuzzer.
+/// #   let get_input_from_fuzzer = || &[];
+/// let raw_data: &[u8] = get_input_from_fuzzer();
+///
+/// // Wrap it in an `Unstructured`.
+/// let mut unstructured = Unstructured::new(raw_data);
+///
+/// // Generate an `Rgb` color and run our checks.
+/// if let Ok(rgb) = Rgb::arbitrary(&mut unstructured) {
+/// #   let run_my_color_conversion_checks = |_| {};
+///     run_my_color_conversion_checks(rgb);
+/// }
+/// # }
+/// ```
+pub struct Unstructured<'a> {
+    data: &'a [u8],
+}
+
+impl<'a> Unstructured<'a> {
+    /// Create a new `Unstructured` from the given raw data.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use arbitrary::Unstructured;
+    ///
+    /// let u = Unstructured::new(&[1, 2, 3, 4]);
+    /// ```
+    pub fn new(data: &'a [u8]) -> Self {
+        Unstructured { data }
+    }
+
+    /// Get the number of remaining bytes of underlying data that are still
+    /// available.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use arbitrary::{Arbitrary, Unstructured};
+    ///
+    /// let mut u = Unstructured::new(&[1, 2, 3]);
+    ///
+    /// // Initially have three bytes of data.
+    /// assert_eq!(u.len(), 3);
+    ///
+    /// // Generating a `bool` consumes one byte from the underlying data, so
+    /// // we are left with two bytes afterwards.
+    /// let _ = bool::arbitrary(&mut u);
+    /// assert_eq!(u.len(), 2);
+    /// ```
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.data.len()
+    }
+
+    /// Is the underlying unstructured data exhausted?
+    ///
+    /// `unstructured.is_empty()` is the same as `unstructured.len() == 0`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use arbitrary::{Arbitrary, Unstructured};
+    ///
+    /// let mut u = Unstructured::new(&[1, 2, 3, 4]);
+    ///
+    /// // Initially, we are not empty.
+    /// assert!(!u.is_empty());
+    ///
+    /// // Generating a `u32` consumes all four bytes of the underlying data, so
+    /// // we become empty afterwards.
+    /// let _ = u32::arbitrary(&mut u);
+    /// assert!(u.is_empty());
+    /// ```
+    #[inline]
+    pub fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Generate an arbitrary instance of `A`.
+    ///
+    /// This is simply a helper method that is equivalent to `<A as
+    /// Arbitrary>::arbitrary(self)`. This helper is a little bit more concise,
+    /// and can be used in situations where Rust's type inference will figure
+    /// out what `A` should be.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # #[cfg(feature="derive")] fn foo() -> arbitrary::Result<()> {
+    /// use arbitrary::{Arbitrary, Unstructured};
+    ///
+    /// #[derive(Arbitrary)]
+    /// struct MyType {
+    ///     // ...
+    /// }
+    ///
+    /// fn do_stuff(value: MyType) {
+    /// #   let _ = value;
+    ///     // ...
+    /// }
+    ///
+    /// let mut u = Unstructured::new(&[1, 2, 3, 4]);
+    ///
+    /// // Rust's type inference can figure out that `value` should be of type
+    /// // `MyType` here:
+    /// let value = u.arbitrary()?;
+    /// do_stuff(value);
+    /// # Ok(()) }
+    /// ```
+    pub fn arbitrary<A>(&mut self) -> Result<A>
+    where
+        A: Arbitrary<'a>,
+    {
+        <A as Arbitrary<'a>>::arbitrary(self)
+    }
+
+    /// Get the number of elements to insert when building up a collection of
+    /// arbitrary `ElementType`s.
+    ///
+    /// This uses the [`<ElementType as
+    /// Arbitrary>::size_hint`][crate::Arbitrary::size_hint] method to smartly
+    /// choose a length such that we most likely have enough underlying bytes to
+    /// construct that many arbitrary `ElementType`s.
+    ///
+    /// This should only be called within an `Arbitrary` implementation.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use arbitrary::{Arbitrary, Result, Unstructured};
+    /// # pub struct MyCollection<T> { _t: std::marker::PhantomData<T> }
+    /// # impl<T> MyCollection<T> {
+    /// #     pub fn with_capacity(capacity: usize) -> Self { MyCollection { _t: std::marker::PhantomData } }
+    /// #     pub fn insert(&mut self, element: T) {}
+    /// # }
+    ///
+    /// impl<'a, T> Arbitrary<'a> for MyCollection<T>
+    /// where
+    ///     T: Arbitrary<'a>,
+    /// {
+    ///     fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+    ///         // Get the number of `T`s we should insert into our collection.
+    ///         let len = u.arbitrary_len::<T>()?;
+    ///
+    ///         // And then create a collection of that length!
+    ///         let mut my_collection = MyCollection::with_capacity(len);
+    ///         for _ in 0..len {
+    ///             let element = T::arbitrary(u)?;
+    ///             my_collection.insert(element);
+    ///         }
+    ///
+    ///         Ok(my_collection)
+    ///     }
+    /// }
+    /// ```
+    pub fn arbitrary_len<ElementType>(&mut self) -> Result<usize>
+    where
+        ElementType: Arbitrary<'a>,
+    {
+        let byte_size = self.arbitrary_byte_size()?;
+        let (lower, upper) = <ElementType as Arbitrary>::size_hint(0);
+        let elem_size = upper.unwrap_or_else(|| lower * 2);
+        let elem_size = std::cmp::max(1, elem_size);
+        Ok(byte_size / elem_size)
+    }
+
+    fn arbitrary_byte_size(&mut self) -> Result<usize> {
+        if self.data.is_empty() {
+            Ok(0)
+        } else if self.data.len() == 1 {
+            self.data = &[];
+            Ok(0)
+        } else {
+            // Take lengths from the end of the data, since the `libFuzzer` folks
+            // found that this lets fuzzers more efficiently explore the input
+            // space.
+            //
+            // https://github.com/rust-fuzz/libfuzzer-sys/blob/0c450753/libfuzzer/utils/FuzzedDataProvider.h#L92-L97
+
+            // We only consume as many bytes as necessary to cover the entire
+            // range of the byte string.
+            let len = if self.data.len() <= std::u8::MAX as usize + 1 {
+                let bytes = 1;
+                let max_size = self.data.len() - bytes;
+                let (rest, for_size) = self.data.split_at(max_size);
+                self.data = rest;
+                Self::int_in_range_impl(0..=max_size as u8, for_size.iter().copied())?.0 as usize
+            } else if self.data.len() <= std::u16::MAX as usize + 1 {
+                let bytes = 2;
+                let max_size = self.data.len() - bytes;
+                let (rest, for_size) = self.data.split_at(max_size);
+                self.data = rest;
+                Self::int_in_range_impl(0..=max_size as u16, for_size.iter().copied())?.0 as usize
+            } else if self.data.len() <= std::u32::MAX as usize + 1 {
+                let bytes = 4;
+                let max_size = self.data.len() - bytes;
+                let (rest, for_size) = self.data.split_at(max_size);
+                self.data = rest;
+                Self::int_in_range_impl(0..=max_size as u32, for_size.iter().copied())?.0 as usize
+            } else {
+                let bytes = 8;
+                let max_size = self.data.len() - bytes;
+                let (rest, for_size) = self.data.split_at(max_size);
+                self.data = rest;
+                Self::int_in_range_impl(0..=max_size as u64, for_size.iter().copied())?.0 as usize
+            };
+
+            Ok(len)
+        }
+    }
+
+    /// Generate an integer within the given range.
+    ///
+    /// Do not use this to generate the size of a collection. Use
+    /// `arbitrary_len` instead.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `range.start >= range.end`. That is, the given range must be
+    /// non-empty.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use arbitrary::{Arbitrary, Unstructured};
+    ///
+    /// let mut u = Unstructured::new(&[1, 2, 3, 4]);
+    ///
+    /// let x: i32 = u.int_in_range(-5_000..=-1_000)
+    ///     .expect("constructed `u` with enough bytes to generate an `i32`");
+    ///
+    /// assert!(-5_000 <= x);
+    /// assert!(x <= -1_000);
+    /// ```
+    pub fn int_in_range<T>(&mut self, range: ops::RangeInclusive<T>) -> Result<T>
+    where
+        T: Int,
+    {
+        let (result, bytes_consumed) = Self::int_in_range_impl(range, self.data.iter().cloned())?;
+        self.data = &self.data[bytes_consumed..];
+        Ok(result)
+    }
+
+    fn int_in_range_impl<T>(
+        range: ops::RangeInclusive<T>,
+        mut bytes: impl Iterator<Item = u8>,
+    ) -> Result<(T, usize)>
+    where
+        T: Int,
+    {
+        let start = range.start();
+        let end = range.end();
+        assert!(
+            start <= end,
+            "`arbitrary::Unstructured::int_in_range` requires a non-empty range"
+        );
+
+        // When there is only one possible choice, don't waste any entropy from
+        // the underlying data.
+        if start == end {
+            return Ok((*start, 0));
+        }
+
+        let range: T::Widest = end.as_widest() - start.as_widest();
+        let mut result = T::Widest::ZERO;
+        let mut offset: usize = 0;
+
+        while offset < mem::size_of::<T>()
+            && (range >> T::Widest::from_usize(offset * 8)) > T::Widest::ZERO
+        {
+            let byte = bytes.next().ok_or(Error::NotEnoughData)?;
+            result = (result << 8) | T::Widest::from_u8(byte);
+            offset += 1;
+        }
+
+        // Avoid division by zero.
+        if let Some(range) = range.checked_add(T::Widest::ONE) {
+            result = result % range;
+        }
+
+        Ok((
+            T::from_widest(start.as_widest().wrapping_add(result)),
+            offset,
+        ))
+    }
+
+    /// Choose one of the given choices.
+    ///
+    /// This should only be used inside of `Arbitrary` implementations.
+    ///
+    /// Returns an error if there is not enough underlying data to make a
+    /// choice or if no choices are provided.
+    ///
+    /// # Examples
+    ///
+    /// Selecting from an array of choices:
+    ///
+    /// ```
+    /// use arbitrary::Unstructured;
+    ///
+    /// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
+    /// let choices = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
+    ///
+    /// let choice = u.choose(&choices).unwrap();
+    ///
+    /// println!("chose {}", choice);
+    /// ```
+    ///
+    /// An error is returned if no choices are provided:
+    ///
+    /// ```
+    /// use arbitrary::Unstructured;
+    ///
+    /// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
+    /// let choices: [char; 0] = [];
+    ///
+    /// let result = u.choose(&choices);
+    ///
+    /// assert!(result.is_err());
+    /// ```
+    pub fn choose<'b, T>(&mut self, choices: &'b [T]) -> Result<&'b T> {
+        if choices.is_empty() {
+            return Err(Error::EmptyChoose);
+        }
+        let idx = self.int_in_range(0..=choices.len() - 1)?;
+        Ok(&choices[idx])
+    }
+
+    /// Fill a `buffer` with bytes from the underlying raw data.
+    ///
+    /// This should only be called within an `Arbitrary` implementation. This is
+    /// a very low-level operation. You should generally prefer calling nested
+    /// `Arbitrary` implementations like `<Vec<u8>>::arbitrary` and
+    /// `String::arbitrary` over using this method directly.
+    ///
+    /// If this `Unstructured` does not have enough data to fill the whole
+    /// `buffer`, an error is returned.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use arbitrary::Unstructured;
+    ///
+    /// let mut u = Unstructured::new(&[1, 2, 3, 4]);
+    ///
+    /// let mut buf = [0; 2];
+    /// assert!(u.fill_buffer(&mut buf).is_ok());
+    /// assert!(u.fill_buffer(&mut buf).is_ok());
+    /// ```
+    pub fn fill_buffer(&mut self, buffer: &mut [u8]) -> Result<()> {
+        let n = std::cmp::min(buffer.len(), self.data.len());
+        buffer[..n].copy_from_slice(&self.data[..n]);
+        for byte in buffer[n..].iter_mut() {
+            *byte = 0;
+        }
+        self.data = &self.data[n..];
+        Ok(())
+    }
+
+    /// Provide `size` bytes from the underlying raw data.
+    ///
+    /// This should only be called within an `Arbitrary` implementation. This is
+    /// a very low-level operation. You should generally prefer calling nested
+    /// `Arbitrary` implementations like `<Vec<u8>>::arbitrary` and
+    /// `String::arbitrary` over using this method directly.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use arbitrary::Unstructured;
+    ///
+    /// let mut u = Unstructured::new(&[1, 2, 3, 4]);
+    ///
+    /// assert!(u.bytes(2).unwrap() == &[1, 2]);
+    /// assert!(u.bytes(2).unwrap() == &[3, 4]);
+    /// ```
+    pub fn bytes(&mut self, size: usize) -> Result<&'a [u8]> {
+        if self.data.len() < size {
+            return Err(Error::NotEnoughData);
+        }
+
+        let (for_buf, rest) = self.data.split_at(size);
+        self.data = rest;
+        Ok(for_buf)
+    }
+
+    /// Peek at `size` number of bytes of the underlying raw input.
+    ///
+    /// Does not consume the bytes, only peeks at them.
+    ///
+    /// Returns `None` if there are not `size` bytes left in the underlying raw
+    /// input.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use arbitrary::Unstructured;
+    ///
+    /// let u = Unstructured::new(&[1, 2, 3]);
+    ///
+    /// assert_eq!(u.peek_bytes(0).unwrap(), []);
+    /// assert_eq!(u.peek_bytes(1).unwrap(), [1]);
+    /// assert_eq!(u.peek_bytes(2).unwrap(), [1, 2]);
+    /// assert_eq!(u.peek_bytes(3).unwrap(), [1, 2, 3]);
+    ///
+    /// assert!(u.peek_bytes(4).is_none());
+    /// ```
+    pub fn peek_bytes(&self, size: usize) -> Option<&'a [u8]> {
+        self.data.get(..size)
+    }
+
+    /// Consume all of the rest of the remaining underlying bytes.
+    ///
+    /// Returns a slice of all the remaining, unconsumed bytes.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use arbitrary::Unstructured;
+    ///
+    /// let mut u = Unstructured::new(&[1, 2, 3]);
+    ///
+    /// let mut remaining = u.take_rest();
+    ///
+    /// assert_eq!(remaining, [1, 2, 3]);
+    /// ```
+    pub fn take_rest(mut self) -> &'a [u8] {
+        mem::replace(&mut self.data, &[])
+    }
+
+    /// Provide an iterator over elements for constructing a collection
+    ///
+    /// This is useful for implementing [`Arbitrary::arbitrary`] on collections
+    /// since the implementation is simply `u.arbitrary_iter()?.collect()`
+    pub fn arbitrary_iter<'b, ElementType: Arbitrary<'a>>(
+        &'b mut self,
+    ) -> Result<ArbitraryIter<'a, 'b, ElementType>> {
+        Ok(ArbitraryIter {
+            u: &mut *self,
+            _marker: PhantomData,
+        })
+    }
+
+    /// Provide an iterator over elements for constructing a collection from
+    /// all the remaining bytes.
+    ///
+    /// This is useful for implementing [`Arbitrary::arbitrary_take_rest`] on collections
+    /// since the implementation is simply `u.arbitrary_take_rest_iter()?.collect()`
+    pub fn arbitrary_take_rest_iter<ElementType: Arbitrary<'a>>(
+        self,
+    ) -> Result<ArbitraryTakeRestIter<'a, ElementType>> {
+        let (lower, upper) = ElementType::size_hint(0);
+
+        let elem_size = upper.unwrap_or(lower * 2);
+        let elem_size = std::cmp::max(1, elem_size);
+        let size = self.len() / elem_size;
+        Ok(ArbitraryTakeRestIter {
+            size,
+            u: Some(self),
+            _marker: PhantomData,
+        })
+    }
+}
+
+/// Utility iterator produced by [`Unstructured::arbitrary_iter`]
+pub struct ArbitraryIter<'a, 'b, ElementType> {
+    u: &'b mut Unstructured<'a>,
+    _marker: PhantomData<ElementType>,
+}
+
+impl<'a, 'b, ElementType: Arbitrary<'a>> Iterator for ArbitraryIter<'a, 'b, ElementType> {
+    type Item = Result<ElementType>;
+    fn next(&mut self) -> Option<Result<ElementType>> {
+        let keep_going = self.u.arbitrary().unwrap_or(false);
+        if keep_going {
+            Some(Arbitrary::arbitrary(self.u))
+        } else {
+            None
+        }
+    }
+}
+
+/// Utility iterator produced by [`Unstructured::arbitrary_take_rest_iter`]
+pub struct ArbitraryTakeRestIter<'a, ElementType> {
+    u: Option<Unstructured<'a>>,
+    size: usize,
+    _marker: PhantomData<ElementType>,
+}
+
+impl<'a, ElementType: Arbitrary<'a>> Iterator for ArbitraryTakeRestIter<'a, ElementType> {
+    type Item = Result<ElementType>;
+    fn next(&mut self) -> Option<Result<ElementType>> {
+        if let Some(mut u) = self.u.take() {
+            if self.size == 1 {
+                Some(Arbitrary::arbitrary_take_rest(u))
+            } else if self.size == 0 {
+                None
+            } else {
+                self.size -= 1;
+                let ret = Arbitrary::arbitrary(&mut u);
+                self.u = Some(u);
+                Some(ret)
+            }
+        } else {
+            None
+        }
+    }
+}
+
+/// A trait that is implemented for all of the primitive integers:
+///
+/// * `u8`
+/// * `u16`
+/// * `u32`
+/// * `u64`
+/// * `u128`
+/// * `usize`
+/// * `i8`
+/// * `i16`
+/// * `i32`
+/// * `i64`
+/// * `i128`
+/// * `isize`
+///
+/// Don't implement this trait yourself.
+pub trait Int:
+    Copy
+    + PartialOrd
+    + Ord
+    + ops::Sub<Self, Output = Self>
+    + ops::Rem<Self, Output = Self>
+    + ops::Shr<Self, Output = Self>
+    + ops::Shl<usize, Output = Self>
+    + ops::BitOr<Self, Output = Self>
+{
+    #[doc(hidden)]
+    type Widest: Int;
+
+    #[doc(hidden)]
+    const ZERO: Self;
+
+    #[doc(hidden)]
+    const ONE: Self;
+
+    #[doc(hidden)]
+    fn as_widest(self) -> Self::Widest;
+
+    #[doc(hidden)]
+    fn from_widest(w: Self::Widest) -> Self;
+
+    #[doc(hidden)]
+    fn from_u8(b: u8) -> Self;
+
+    #[doc(hidden)]
+    fn from_usize(u: usize) -> Self;
+
+    #[doc(hidden)]
+    fn checked_add(self, rhs: Self) -> Option<Self>;
+
+    #[doc(hidden)]
+    fn wrapping_add(self, rhs: Self) -> Self;
+}
+
+macro_rules! impl_int {
+    ( $( $ty:ty : $widest:ty ; )* ) => {
+        $(
+            impl Int for $ty {
+                type Widest = $widest;
+
+                const ZERO: Self = 0;
+
+                const ONE: Self = 1;
+
+                fn as_widest(self) -> Self::Widest {
+                    self as $widest
+                }
+
+                fn from_widest(w: Self::Widest) -> Self {
+                    let x = <$ty>::max_value().as_widest();
+                    (w % x) as Self
+                }
+
+                fn from_u8(b: u8) -> Self {
+                    b as Self
+                }
+
+                fn from_usize(u: usize) -> Self {
+                    u as Self
+                }
+
+                fn checked_add(self, rhs: Self) -> Option<Self> {
+                    <$ty>::checked_add(self, rhs)
+                }
+
+                fn wrapping_add(self, rhs: Self) -> Self {
+                    <$ty>::wrapping_add(self, rhs)
+                }
+            }
+        )*
+    }
+}
+
+impl_int! {
+    u8: u128;
+    u16: u128;
+    u32: u128;
+    u64: u128;
+    u128: u128;
+    usize: u128;
+    i8: i128;
+    i16: i128;
+    i32: i128;
+    i64: i128;
+    i128: i128;
+    isize: i128;
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_byte_size() {
+        let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 6]);
+        // Should take one byte off the end
+        assert_eq!(u.arbitrary_byte_size().unwrap(), 6);
+        assert_eq!(u.len(), 9);
+        let mut v = vec![];
+        v.resize(260, 0);
+        v.push(1);
+        v.push(4);
+        let mut u = Unstructured::new(&v);
+        // Should read two bytes off the end
+        assert_eq!(u.arbitrary_byte_size().unwrap(), 0x104);
+        assert_eq!(u.len(), 260);
+    }
+
+    #[test]
+    fn int_in_range_of_one() {
+        let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 6]);
+        let x = u.int_in_range(0..=0).unwrap();
+        assert_eq!(x, 0);
+        let choice = *u.choose(&[42]).unwrap();
+        assert_eq!(choice, 42)
+    }
+
+    #[test]
+    fn int_in_range_uses_minimal_amount_of_bytes() {
+        let mut u = Unstructured::new(&[1]);
+        u.int_in_range::<u8>(0..=u8::MAX).unwrap();
+
+        let mut u = Unstructured::new(&[1]);
+        u.int_in_range::<u32>(0..=u8::MAX as u32).unwrap();
+
+        let mut u = Unstructured::new(&[1]);
+        u.int_in_range::<u32>(0..=u8::MAX as u32 + 1).unwrap_err();
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/arbitrary/tests/derive.rs
@@ -0,0 +1,188 @@
+#![cfg(feature = "derive")]
+
+use arbitrary::*;
+
+fn arbitrary_from<'a, T: Arbitrary<'a>>(input: &'a [u8]) -> T {
+    let mut buf = Unstructured::new(input);
+    T::arbitrary(&mut buf).expect("can create arbitrary instance OK")
+}
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Arbitrary)]
+pub struct Rgb {
+    pub r: u8,
+    pub g: u8,
+    pub b: u8,
+}
+
+#[test]
+fn struct_with_named_fields() {
+    let rgb: Rgb = arbitrary_from(&[4, 5, 6]);
+    assert_eq!(rgb.r, 4);
+    assert_eq!(rgb.g, 5);
+    assert_eq!(rgb.b, 6);
+
+    assert_eq!((3, Some(3)), <Rgb as Arbitrary>::size_hint(0));
+}
+
+#[derive(Copy, Clone, Debug, Arbitrary)]
+struct MyTupleStruct(u8, bool);
+
+#[test]
+fn tuple_struct() {
+    let s: MyTupleStruct = arbitrary_from(&[43, 42]);
+    assert_eq!(s.0, 43);
+    assert_eq!(s.1, false);
+
+    let s: MyTupleStruct = arbitrary_from(&[42, 43]);
+    assert_eq!(s.0, 42);
+    assert_eq!(s.1, true);
+
+    assert_eq!((2, Some(2)), <MyTupleStruct as Arbitrary>::size_hint(0));
+}
+
+#[derive(Clone, Debug, Arbitrary)]
+struct EndingInVec(u8, bool, u32, Vec<u16>);
+#[derive(Clone, Debug, Arbitrary)]
+struct EndingInString(u8, bool, u32, String);
+
+#[test]
+fn test_take_rest() {
+    let bytes = [1, 1, 1, 2, 3, 4, 5, 6, 7, 8];
+    let s1 = EndingInVec::arbitrary_take_rest(Unstructured::new(&bytes)).unwrap();
+    let s2 = EndingInString::arbitrary_take_rest(Unstructured::new(&bytes)).unwrap();
+    assert_eq!(s1.0, 1);
+    assert_eq!(s2.0, 1);
+    assert_eq!(s1.1, true);
+    assert_eq!(s2.1, true);
+    assert_eq!(s1.2, 0x4030201);
+    assert_eq!(s2.2, 0x4030201);
+    assert_eq!(s1.3, vec![0x605, 0x807]);
+    assert_eq!(s2.3, "\x05\x06\x07\x08");
+}
+
+#[derive(Copy, Clone, Debug, Arbitrary)]
+enum MyEnum {
+    Unit,
+    Tuple(u8, u16),
+    Struct { a: u32, b: (bool, u64) },
+}
+
+#[test]
+fn derive_enum() {
+    let mut raw = vec![
+        // The choice of which enum variant takes 4 bytes.
+        1, 2, 3, 4,
+        // And then we need up to 13 bytes for creating `MyEnum::Struct`, the
+        // largest variant.
+        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+    ];
+
+    let mut saw_unit = false;
+    let mut saw_tuple = false;
+    let mut saw_struct = false;
+
+    for i in 0..=255 {
+        // Choose different variants each iteration.
+        for el in &mut raw[..4] {
+            *el = i;
+        }
+
+        let e: MyEnum = arbitrary_from(&raw);
+
+        match e {
+            MyEnum::Unit => {
+                saw_unit = true;
+            }
+            MyEnum::Tuple(a, b) => {
+                saw_tuple = true;
+                assert_eq!(a, arbitrary_from(&raw[4..5]));
+                assert_eq!(b, arbitrary_from(&raw[5..]));
+            }
+            MyEnum::Struct { a, b } => {
+                saw_struct = true;
+                assert_eq!(a, arbitrary_from(&raw[4..8]));
+                assert_eq!(b, arbitrary_from(&raw[8..]));
+            }
+        }
+    }
+
+    assert!(saw_unit);
+    assert!(saw_tuple);
+    assert!(saw_struct);
+
+    assert_eq!((4, Some(17)), <MyEnum as Arbitrary>::size_hint(0));
+}
+
+#[derive(Arbitrary, Debug)]
+enum RecursiveTree {
+    Leaf,
+    Node {
+        left: Box<RecursiveTree>,
+        right: Box<RecursiveTree>,
+    },
+}
+
+#[test]
+fn recursive() {
+    let raw = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
+    let _rec: RecursiveTree = arbitrary_from(&raw);
+
+    let (lower, upper) = <RecursiveTree as Arbitrary>::size_hint(0);
+    assert_eq!(lower, 4, "need a u32 for the discriminant at minimum");
+    assert!(
+        upper.is_none(),
+        "potentially infinitely recursive, so no upper bound"
+    );
+}
+
+#[derive(Arbitrary, Debug)]
+struct Generic<T> {
+    inner: T,
+}
+
+#[test]
+fn generics() {
+    let raw = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
+    let gen: Generic<bool> = arbitrary_from(&raw);
+    assert!(gen.inner);
+
+    let (lower, upper) = <Generic<u32> as Arbitrary>::size_hint(0);
+    assert_eq!(lower, 4);
+    assert_eq!(upper, Some(4));
+}
+
+#[derive(Arbitrary, Debug)]
+struct OneLifetime<'a> {
+    alpha: &'a str,
+}
+
+#[test]
+fn one_lifetime() {
+    // Last byte is used for length
+    let raw: Vec<u8> = vec![97, 98, 99, 100, 3];
+    let lifetime: OneLifetime = arbitrary_from(&raw);
+    assert_eq!("abc", lifetime.alpha);
+
+    let (lower, upper) = <OneLifetime as Arbitrary>::size_hint(0);
+    assert_eq!(lower, 8);
+    assert_eq!(upper, None);
+}
+
+#[derive(Arbitrary, Debug)]
+struct TwoLifetimes<'a, 'b> {
+    alpha: &'a str,
+    beta: &'b str,
+}
+
+#[test]
+fn two_lifetimes() {
+    // Last byte is used for length
+    let raw: Vec<u8> = vec![97, 98, 99, 100, 101, 102, 103, 3];
+    let lifetime: TwoLifetimes = arbitrary_from(&raw);
+    assert_eq!("abc", lifetime.alpha);
+    assert_eq!("def", lifetime.beta);
+
+    let (lower, upper) = <TwoLifetimes as Arbitrary>::size_hint(0);
+    assert_eq!(lower, 16);
+    assert_eq!(upper, None);
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/arbitrary/tests/path.rs
@@ -0,0 +1,29 @@
+#![cfg(feature = "derive")]
+
+// Regression test for ensuring the derives work without Arbitrary being imported
+
+#[derive(arbitrary::Arbitrary, Clone, Debug)]
+pub struct Struct {
+    x: u8,
+    y: u8,
+}
+
+#[derive(arbitrary::Arbitrary, Clone, Debug)]
+pub struct Tuple(u8);
+
+#[derive(arbitrary::Arbitrary, Clone, Debug)]
+pub struct Unit(u8);
+
+#[derive(arbitrary::Arbitrary, Clone, Debug)]
+pub enum Enum {
+    X(u8),
+    Y(u8),
+}
+
+#[derive(arbitrary::Arbitrary, Clone, Debug)]
+struct EndingInVec(u8, bool, u32, Vec<u16>);
+
+#[derive(arbitrary::Arbitrary, Debug)]
+struct Generic<T> {
+    inner: T,
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/derive_arbitrary/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{"Cargo.toml":"0e723b19ec2f6d2ef9c0252720c70cad769c76349815721bce064c621e89a11e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"15656cc11a8331f28c0986b8ab97220d3e76f98e60ed388b5ffad37dfac4710c","README.md":"7059db284b2016ba7355c63a2b14eb732c7b8952286ff1bc4fdde605018a39c4","src/lib.rs":"cdff09ae28184bc4bab1ff751ab9ea228c650463d4a08b359588efbae9d932f1"},"package":"5f1281ee141df08871db9fe261ab5312179eac32d1e314134ceaa8dd7c042f5a"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/derive_arbitrary/Cargo.toml
@@ -0,0 +1,36 @@
+# 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
+#
+# 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]
+edition = "2018"
+name = "derive_arbitrary"
+version = "1.0.1"
+authors = ["The Rust-Fuzz Project Developers", "Nick Fitzgerald <fitzgen@gmail.com>", "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", "Corey Farwell <coreyf@rwell.org>"]
+description = "Derives arbitrary traits"
+documentation = "https://docs.rs/arbitrary/"
+readme = "README.md"
+keywords = ["arbitrary", "testing", "derive", "macro"]
+categories = ["development-tools::testing"]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/rust-fuzz/arbitrary"
+
+[lib]
+proc_macro = true
+[dependencies.proc-macro2]
+version = "1.0"
+
+[dependencies.quote]
+version = "1.0"
+
+[dependencies.syn]
+version = "1.0"
+features = ["derive"]
new file mode 100644
--- /dev/null
+++ b/third_party/rust/derive_arbitrary/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+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.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/derive_arbitrary/LICENSE-MIT
@@ -0,0 +1,27 @@
+MIT License
+
+Copyright (c) 2019 Manish Goregaokar
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/derive_arbitrary/README.md
@@ -0,0 +1,7 @@
+# `#[derive(Arbitrary)]`
+
+This crate implements support for automatically deriving [the `Arbitrary`
+trait](https://docs.rs/arbitrary/*/arbitrary/trait.Arbitrary.html).
+
+Don't depend on this crate directly, though. Instead, enable the `"derive"`
+feature of the `arbitrary` crate.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/derive_arbitrary/src/lib.rs
@@ -0,0 +1,196 @@
+extern crate proc_macro;
+
+use proc_macro2::{Span, TokenStream};
+use quote::quote;
+use syn::*;
+
+static ARBITRARY_LIFETIME_NAME: &str = "'arbitrary";
+
+#[proc_macro_derive(Arbitrary)]
+pub fn derive_arbitrary(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let input = syn::parse_macro_input!(tokens as syn::DeriveInput);
+    let (lifetime_without_bounds, lifetime_with_bounds) =
+        build_arbitrary_lifetime(input.generics.clone());
+
+    let arbitrary_method = gen_arbitrary_method(&input, lifetime_without_bounds.clone());
+    let size_hint_method = gen_size_hint_method(&input);
+    let name = input.ident;
+    // Add a bound `T: Arbitrary` to every type parameter T.
+    let generics = add_trait_bounds(input.generics, lifetime_without_bounds.clone());
+
+    // Build ImplGeneric with a lifetime (https://github.com/dtolnay/syn/issues/90)
+    let mut generics_with_lifetime = generics.clone();
+    generics_with_lifetime
+        .params
+        .push(GenericParam::Lifetime(lifetime_with_bounds));
+    let (impl_generics, _, _) = generics_with_lifetime.split_for_impl();
+
+    // Build TypeGenerics and WhereClause without a lifetime
+    let (_, ty_generics, where_clause) = generics.split_for_impl();
+
+    (quote! {
+        impl #impl_generics arbitrary::Arbitrary<#lifetime_without_bounds> for #name #ty_generics #where_clause {
+            #arbitrary_method
+            #size_hint_method
+        }
+    })
+    .into()
+}
+
+// Returns: (lifetime without bounds, lifetime with bounds)
+// Example: ("'arbitrary", "'arbitrary: 'a + 'b")
+fn build_arbitrary_lifetime(generics: Generics) -> (LifetimeDef, LifetimeDef) {
+    let lifetime_without_bounds =
+        LifetimeDef::new(Lifetime::new(ARBITRARY_LIFETIME_NAME, Span::call_site()));
+    let mut lifetime_with_bounds = lifetime_without_bounds.clone();
+
+    for param in generics.params.iter() {
+        if let GenericParam::Lifetime(lifetime_def) = param {
+            lifetime_with_bounds
+                .bounds
+                .push(lifetime_def.lifetime.clone());
+        }
+    }
+
+    (lifetime_without_bounds, lifetime_with_bounds)
+}
+
+// Add a bound `T: Arbitrary` to every type parameter T.
+fn add_trait_bounds(mut generics: Generics, lifetime: LifetimeDef) -> Generics {
+    for param in generics.params.iter_mut() {
+        if let GenericParam::Type(type_param) = param {
+            type_param
+                .bounds
+                .push(parse_quote!(arbitrary::Arbitrary<#lifetime>));
+        }
+    }
+    generics
+}
+
+fn gen_arbitrary_method(input: &DeriveInput, lifetime: LifetimeDef) -> TokenStream {
+    let ident = &input.ident;
+    let arbitrary_structlike = |fields| {
+        let arbitrary = construct(fields, |_, _| quote!(arbitrary::Arbitrary::arbitrary(u)?));
+        let arbitrary_take_rest = construct_take_rest(fields);
+        quote! {
+            fn arbitrary(u: &mut arbitrary::Unstructured<#lifetime>) -> arbitrary::Result<Self> {
+                Ok(#ident #arbitrary)
+            }
+
+            fn arbitrary_take_rest(mut u: arbitrary::Unstructured<#lifetime>) -> arbitrary::Result<Self> {
+                Ok(#ident #arbitrary_take_rest)
+            }
+        }
+    };
+    match &input.data {
+        Data::Struct(data) => arbitrary_structlike(&data.fields),
+        Data::Union(data) => arbitrary_structlike(&Fields::Named(data.fields.clone())),
+        Data::Enum(data) => {
+            let variants = data.variants.iter().enumerate().map(|(i, variant)| {
+                let idx = i as u64;
+                let ctor = construct(&variant.fields, |_, _| {
+                    quote!(arbitrary::Arbitrary::arbitrary(u)?)
+                });
+                let variant_name = &variant.ident;
+                quote! { #idx => #ident::#variant_name #ctor }
+            });
+            let variants_take_rest = data.variants.iter().enumerate().map(|(i, variant)| {
+                let idx = i as u64;
+                let ctor = construct_take_rest(&variant.fields);
+                let variant_name = &variant.ident;
+                quote! { #idx => #ident::#variant_name #ctor }
+            });
+            let count = data.variants.len() as u64;
+            quote! {
+                fn arbitrary(u: &mut arbitrary::Unstructured<#lifetime>) -> arbitrary::Result<Self> {
+                    // Use a multiply + shift to generate a ranged random number
+                    // with slight bias. For details, see:
+                    // https://lemire.me/blog/2016/06/30/fast-random-shuffling
+                    Ok(match (u64::from(<u32 as arbitrary::Arbitrary>::arbitrary(u)?) * #count) >> 32 {
+                        #(#variants,)*
+                        _ => unreachable!()
+                    })
+                }
+
+                fn arbitrary_take_rest(mut u: arbitrary::Unstructured<#lifetime>) -> arbitrary::Result<Self> {
+                    // Use a multiply + shift to generate a ranged random number
+                    // with slight bias. For details, see:
+                    // https://lemire.me/blog/2016/06/30/fast-random-shuffling
+                    Ok(match (u64::from(<u32 as arbitrary::Arbitrary>::arbitrary(&mut u)?) * #count) >> 32 {
+                        #(#variants_take_rest,)*
+                        _ => unreachable!()
+                    })
+                }
+            }
+        }
+    }
+}
+
+fn construct(fields: &Fields, ctor: impl Fn(usize, &Field) -> TokenStream) -> TokenStream {
+    match fields {
+        Fields::Named(names) => {
+            let names = names.named.iter().enumerate().map(|(i, f)| {
+                let name = f.ident.as_ref().unwrap();
+                let ctor = ctor(i, f);
+                quote! { #name: #ctor }
+            });
+            quote! { { #(#names,)* } }
+        }
+        Fields::Unnamed(names) => {
+            let names = names.unnamed.iter().enumerate().map(|(i, f)| {
+                let ctor = ctor(i, f);
+                quote! { #ctor }
+            });
+            quote! { ( #(#names),* ) }
+        }
+        Fields::Unit => quote!(),
+    }
+}
+
+fn construct_take_rest(fields: &Fields) -> TokenStream {
+    construct(fields, |idx, _| {
+        if idx + 1 == fields.len() {
+            quote! { arbitrary::Arbitrary::arbitrary_take_rest(u)? }
+        } else {
+            quote! { arbitrary::Arbitrary::arbitrary(&mut u)? }
+        }
+    })
+}
+
+fn gen_size_hint_method(input: &DeriveInput) -> TokenStream {
+    let size_hint_fields = |fields: &Fields| {
+        let tys = fields.iter().map(|f| &f.ty);
+        quote! {
+            arbitrary::size_hint::and_all(&[
+                #( <#tys as arbitrary::Arbitrary>::size_hint(depth) ),*
+            ])
+        }
+    };
+    let size_hint_structlike = |fields: &Fields| {
+        let hint = size_hint_fields(fields);
+        quote! {
+            #[inline]
+            fn size_hint(depth: usize) -> (usize, Option<usize>) {
+                arbitrary::size_hint::recursion_guard(depth, |depth| #hint)
+            }
+        }
+    };
+    match &input.data {
+        Data::Struct(data) => size_hint_structlike(&data.fields),
+        Data::Union(data) => size_hint_structlike(&Fields::Named(data.fields.clone())),
+        Data::Enum(data) => {
+            let variants = data.variants.iter().map(|v| size_hint_fields(&v.fields));
+            quote! {
+                #[inline]
+                fn size_hint(depth: usize) -> (usize, Option<usize>) {
+                    arbitrary::size_hint::and(
+                        <u32 as arbitrary::Arbitrary>::size_hint(depth),
+                        arbitrary::size_hint::recursion_guard(depth, |depth| {
+                            arbitrary::size_hint::or_all(&[ #( #variants ),* ])
+                        }),
+                    )
+                }
+            }
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/wasm-encoder/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{"Cargo.toml":"aed5fe39e7e69c8fa0aed88e1ec320b7b947321dbaa001329a3d07aec37106d5","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"8d8b48c8ed202bd18494ed37678a0712688909bc350e5423fc18d70447e31f56","src/aliases.rs":"13dfd1947ad7285c1bab5b2bd14703e0e0a9392519e4a3a709a6d160751dfd80","src/code.rs":"84dbc269ab1dca363b7b40a6dd4f8fc6d64e0fac6f56daa5fcab7ba0fd85cfc8","src/custom.rs":"0926d7c9b8418c316b2478abced1ddc0cf88f25c68c4c320e90fff237a033dd1","src/data.rs":"e89f9297f0e5cf2b784c59f445d6f2e7901eaaf7897731f4ef6282672fe7ae70","src/elements.rs":"8c68d1e0b176c643ba4d49705043d68ae063dfe7b790bbc2d0d8edf931981c16","src/encoders.rs":"c721ac7ad3080da42ff3e7397007e44471d1e47a8de117fbde7ab799b75d10a6","src/exports.rs":"4ef5ae7daa5f082499913538d88c4ad61ff293c7f5c4c414adb900a514ff361a","src/functions.rs":"e433d9199bad8c75609202a4282797e594002e3610d803e5732989f7b5edc2a6","src/globals.rs":"bb033493914c1c321f19fd3c974f174c13f877659ae7aae31a664790d839276a","src/imports.rs":"563184465211d7381f86d2040cc26a2322296fc966f0ba02251163a54100b8d4","src/instances.rs":"d790933204e530e1264a289ef2090193d19006d082fbeba37a204b2f811d10df","src/lib.rs":"91f84effdbe8f4dbeb8f3faa26c2b4979e6ee5ebc7683aba7a7784c7e79823c3","src/linking.rs":"830516e338fbe79dad86eab3476944bb810af57b3d1a3f215d3770327d379d9e","src/memories.rs":"950285bcf52e4dd6647b1efda05280a3c93c966ff0da33695e2da187dbff4a12","src/modules.rs":"9d92969c27f0fd59efa14c7bf9ac7b96c951c379de3f85907b387184dd571f3a","src/start.rs":"a2466aba18cd194dbd17ac9103f63639f8538cba765891f07b410107b752bafd","src/tables.rs":"6102a61c69046f826ca8cd4738120c7988f3b639d667ad453b9e1af9052c513e","src/types.rs":"9d268a4437922f607f23703b94b0ada05f6266b6c08a362fd4674649b3e68976","tests/linking.rs":"43025bd4a1270a6a925f421ba728e0ad180ac8e5ea6cb80f2fc443153a5c4ec4"},"package":"2caacc74c68c74f0008c4055cdf509c43e623775eaf73323bb818dcf666ed9bd"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/wasm-encoder/Cargo.toml
@@ -0,0 +1,30 @@
+# 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
+#
+# 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]
+edition = "2018"
+name = "wasm-encoder"
+version = "0.6.0"
+authors = ["Nick Fitzgerald <fitzgen@gmail.com>"]
+description = "A low-level WebAssembly encoder.\n"
+homepage = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder"
+documentation = "https://docs.rs/wasm-encoder"
+readme = "README.md"
+license = "Apache-2.0 WITH LLVM-exception"
+repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder"
+[dependencies.leb128]
+version = "0.2.4"
+[dev-dependencies.anyhow]
+version = "1.0.38"
+
+[dev-dependencies.tempfile]
+version = "3.2.0"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/wasm-encoder/LICENSE
@@ -0,0 +1,220 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
+
+
+--- LLVM Exceptions to the Apache 2.0 License ----
+
+As an exception, if, as a result of your compiling your source code, portions
+of this Software are embedded into an Object form of such source code, you
+may redistribute such embedded portions in such Object form without complying
+with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
+
+In addition, if you combine or link compiled forms of this Software with
+software that is licensed under the GPLv2 ("Combined Software") and if a
+court of competent jurisdiction determines that the patent provision (Section
+3), the indemnity provision (Section 9) or other Section of the License
+conflicts with the conditions of the GPLv2, you may retroactively and
+prospectively choose to deem waived or otherwise exclude such Section(s) of
+the License, but only in their entirety and only with respect to the Combined
+Software.
+
new file mode 100644
--- /dev/null
+++ b/third_party/rust/wasm-encoder/README.md
@@ -0,0 +1,81 @@
+<div align="center">
+  <h1><code>wasm-encoder</code></h1>
+
+<strong>A <a href="https://bytecodealliance.org/">Bytecode Alliance</a> project</strong>
+
+  <p>
+    <strong>A WebAssembly encoder for Rust.</strong>
+  </p>
+
+  <p>
+    <a href="https://crates.io/crates/wasm-encoder"><img src="https://img.shields.io/crates/v/wasm-encoder.svg?style=flat-square" alt="Crates.io version" /></a>
+    <a href="https://crates.io/crates/wasm-encoder"><img src="https://img.shields.io/crates/d/wasm-encoder.svg?style=flat-square" alt="Download" /></a>
+    <a href="https://docs.rs/wasm-encoder/"><img src="https://img.shields.io/static/v1?label=docs&message=wasm-encoder&color=blue&style=flat-square" alt="docs.rs docs" /></a>
+  </p>
+</div>
+
+## Usage
+
+Add this to your `Cargo.toml`:
+
+```toml
+[dependencies]
+wasm-encoder = "0.3"
+```
+
+And then you can encode WebAssembly binaries via:
+
+```rust
+use wasm_encoder::{
+    CodeSection, Export, ExportSection, Function, FunctionSection, Instruction,
+    Module, TypeSection, ValType,
+};
+
+let mut module = Module::new();
+
+// Encode the type section.
+let mut types = TypeSection::new();
+let params = vec![ValType::I32, ValType::I32];
+let results = vec![ValType::I32];
+types.function(params, results);
+module.section(&types);
+
+// Encode the function section.
+let mut functions = FunctionSection::new();
+let type_index = 0;
+functions.function(type_index);
+module.section(&functions);
+
+// Encode the export section.
+let mut exports = ExportSection::new();
+exports.export("f", Export::Function(0));
+module.section(&exports);
+
+// Encode the code section.
+let mut codes = CodeSection::new();
+let locals = vec![];
+let mut f = Function::new(locals);
+f.instruction(Instruction::LocalGet(0));
+f.instruction(Instruction::LocalGet(1));
+f.instruction(Instruction::I32Add);
+f.instruction(Instruction::End);
+codes.function(&f);
+module.section(&codes);
+
+// Extract the encoded Wasm bytes for this module.
+let wasm_bytes = module.finish();
+
+// We generated a valid Wasm module!
+assert!(wasmparser::validate(&wasm_bytes).is_ok());
+```
+
+# License
+
+This project is licensed under the Apache 2.0 license with the LLVM exception.
+See [LICENSE](LICENSE) for more details.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in this project by you, as defined in the Apache-2.0 license,
+shall be licensed as above, without any additional terms or conditions.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/aliases.rs
@@ -0,0 +1,97 @@
+use super::*;
+
+/// An encoder for the alias section.
+///
+/// Note that this is part of the [module linking proposal][proposal] and is not
+/// currently part of stable WebAssembly.
+///
+/// [proposal]: https://github.com/webassembly/module-linking
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{Module, AliasSection, ItemKind};
+///
+/// let mut aliases = AliasSection::new();
+/// aliases.outer_type(0, 2);
+/// aliases.instance_export(0, ItemKind::Function, "foo");
+///
+/// let mut module = Module::new();
+/// module.section(&aliases);
+///
+/// let wasm_bytes = module.finish();
+/// ```
+#[derive(Clone, Debug)]
+pub struct AliasSection {
+    bytes: Vec<u8>,
+    num_added: u32,
+}
+
+impl AliasSection {
+    /// Construct a new alias section encoder.
+    pub fn new() -> AliasSection {
+        AliasSection {
+            bytes: vec![],
+            num_added: 0,
+        }
+    }
+
+    /// How many aliases have been defined inside this section so far?
+    pub fn len(&self) -> u32 {
+        self.num_added
+    }
+
+    /// Define an alias that references the export of a defined instance.
+    pub fn instance_export(
+        &mut self,
+        instance: u32,
+        kind: crate::ItemKind,
+        name: &str,
+    ) -> &mut Self {
+        self.bytes.push(0x00);
+        self.bytes.extend(encoders::u32(instance));
+        self.bytes.push(kind as u8);
+        self.bytes.extend(encoders::str(name));
+        self.num_added += 1;
+        self
+    }
+
+    /// Define an alias that references an outer module's type.
+    pub fn outer_type(&mut self, depth: u32, ty: u32) -> &mut Self {
+        self.bytes.push(0x01);
+        self.bytes.extend(encoders::u32(depth));
+        self.bytes.push(0x07);
+        self.bytes.extend(encoders::u32(ty));
+        self.num_added += 1;
+        self
+    }
+
+    /// Define an alias that references an outer module's module.
+    pub fn outer_module(&mut self, depth: u32, module: u32) -> &mut Self {
+        self.bytes.push(0x01);
+        self.bytes.extend(encoders::u32(depth));
+        self.bytes.push(ItemKind::Module as u8);
+        self.bytes.extend(encoders::u32(module));
+        self.num_added += 1;
+        self
+    }
+}
+
+impl Section for AliasSection {
+    fn id(&self) -> u8 {
+        SectionId::Alias.into()
+    }
+
+    fn encode<S>(&self, sink: &mut S)
+    where
+        S: Extend<u8>,
+    {
+        let num_added = encoders::u32(self.num_added);
+        let n = num_added.len();
+        sink.extend(
+            encoders::u32(u32::try_from(n + self.bytes.len()).unwrap())
+                .chain(num_added)
+                .chain(self.bytes.iter().copied()),
+        );
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/code.rs
@@ -0,0 +1,2116 @@
+use super::*;
+
+/// An encoder for the code section.
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{
+///     CodeSection, Function, FunctionSection, Instruction, Module,
+///     TypeSection, ValType
+/// };
+///
+/// let mut types = TypeSection::new();
+/// types.function(vec![], vec![ValType::I32]);
+///
+/// let mut functions = FunctionSection::new();
+/// let type_index = 0;
+/// functions.function(type_index);
+///
+/// let locals = vec![];
+/// let mut func = Function::new(locals);
+/// func.instruction(Instruction::I32Const(42));
+/// let mut code = CodeSection::new();
+/// code.function(&func);
+///
+/// let mut module = Module::new();
+/// module
+///     .section(&types)
+///     .section(&functions)
+///     .section(&code);
+///
+/// let wasm_bytes = module.finish();
+/// ```
+#[derive(Clone, Debug)]
+pub struct CodeSection {
+    bytes: Vec<u8>,
+    num_added: u32,
+}
+
+impl CodeSection {
+    /// Create a new code section encoder.
+    pub fn new() -> CodeSection {
+        CodeSection {
+            bytes: vec![],
+            num_added: 0,
+        }
+    }
+
+    /// How many function bodies have been defined inside this section so far?
+    pub fn len(&self) -> u32 {
+        self.num_added
+    }
+
+    /// Write a function body into this code section.
+    pub fn function(&mut self, func: &Function) -> &mut Self {
+        func.encode(&mut self.bytes);
+        self.num_added += 1;
+        self
+    }
+}
+
+impl Section for CodeSection {
+    fn id(&self) -> u8 {
+        SectionId::Code.into()
+    }
+
+    fn encode<S>(&self, sink: &mut S)
+    where
+        S: Extend<u8>,
+    {
+        let num_added = encoders::u32(self.num_added);
+        let n = num_added.len();
+        sink.extend(
+            encoders::u32(u32::try_from(n + self.bytes.len()).unwrap())
+                .chain(num_added)
+                .chain(self.bytes.iter().copied()),
+        );
+    }
+}
+
+/// An encoder for a function body within the code section.
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{CodeSection, Function, Instruction};
+///
+/// // Define the function body for:
+/// //
+/// //     (func (param i32 i32) (result i32)
+/// //       local.get 0
+/// //       local.get 1
+/// //       i32.add)
+/// let locals = vec![];
+/// let mut func = Function::new(locals);
+/// func.instruction(Instruction::LocalGet(0));
+/// func.instruction(Instruction::LocalGet(1));
+/// func.instruction(Instruction::I32Add);
+///
+/// // Add our function to the code section.
+/// let mut code = CodeSection::new();
+/// code.function(&func);
+/// ```
+#[derive(Clone, Debug)]
+pub struct Function {
+    bytes: Vec<u8>,
+}
+
+impl Function {
+    /// Create a new function body with the given locals.
+    pub fn new<L>(locals: L) -> Self
+    where
+        L: IntoIterator<Item = (u32, ValType)>,
+        L::IntoIter: ExactSizeIterator,
+    {
+        let locals = locals.into_iter();
+        let mut bytes = vec![];
+        bytes.extend(encoders::u32(u32::try_from(locals.len()).unwrap()));
+        for (count, ty) in locals {
+            bytes.extend(encoders::u32(count));
+            bytes.push(ty.into());
+        }
+        Function { bytes }
+    }
+
+    /// Write an instruction into this function body.
+    pub fn instruction(&mut self, instruction: Instruction) -> &mut Self {
+        instruction.encode(&mut self.bytes);
+        self
+    }
+
+    /// Add raw bytes to this function's body.
+    pub fn raw<B>(&mut self, bytes: B) -> &mut Self
+    where
+        B: IntoIterator<Item = u8>,
+    {
+        self.bytes.extend(bytes);
+        self
+    }
+
+    fn encode(&self, bytes: &mut Vec<u8>) {
+        bytes.extend(
+            encoders::u32(u32::try_from(self.bytes.len()).unwrap())
+                .chain(self.bytes.iter().copied()),
+        );
+    }
+}
+
+/// The immediate for a memory instruction.
+#[derive(Clone, Copy, Debug)]
+pub struct MemArg {
+    /// A static offset to add to the instruction's dynamic address operand.
+    ///
+    /// This is a `u64` field for the memory64 proposal, but 32-bit memories
+    /// limit offsets to at most `u32::MAX` bytes. This will be encoded as a LEB
+    /// but it won't generate a valid module if an offset is specified which is
+    /// larger than the maximum size of the index space for the memory indicated
+    /// by `memory_index`.
+    pub offset: u64,
+    /// The expected alignment of the instruction's dynamic address operand
+    /// (expressed the exponent of a power of two).
+    pub align: u32,
+    /// The index of the memory this instruction is operating upon.
+    pub memory_index: u32,
+}
+
+impl MemArg {
+    fn encode(&self, bytes: &mut Vec<u8>) {
+        if self.memory_index == 0 {
+            bytes.extend(encoders::u32(self.align));
+            bytes.extend(encoders::u64(self.offset));
+        } else {
+            bytes.extend(encoders::u32(self.align | (1 << 6)));
+            bytes.extend(encoders::u64(self.offset));
+            bytes.extend(encoders::u32(self.memory_index));
+        }
+    }
+}
+
+/// Describe an unchecked SIMD lane index.
+pub type Lane = u8;
+
+/// The type for a `block`/`if`/`loop`.
+#[derive(Clone, Copy, Debug)]
+pub enum BlockType {
+    /// `[] -> []`
+    Empty,
+    /// `[] -> [t]`
+    Result(ValType),
+    /// The `n`th function type.
+    FunctionType(u32),
+}
+
+impl BlockType {
+    fn encode(&self, bytes: &mut Vec<u8>) {
+        match *self {
+            BlockType::Empty => bytes.push(0x40),
+            BlockType::Result(ty) => bytes.push(ty.into()),
+            BlockType::FunctionType(f) => bytes.extend(encoders::s33(f.into())),
+        }
+    }
+}
+
+/// WebAssembly instructions.
+#[derive(Clone, Copy, Debug)]
+#[non_exhaustive]
+#[allow(missing_docs, non_camel_case_types)]
+pub enum Instruction<'a> {
+    // Control instructions.
+    Unreachable,
+    Nop,
+    Block(BlockType),
+    Loop(BlockType),
+    If(BlockType),
+    Else,
+    End,
+    Br(u32),
+    BrIf(u32),
+    BrTable(&'a [u32], u32),
+    Return,
+    Call(u32),
+    CallIndirect { ty: u32, table: u32 },
+
+    // Parametric instructions.
+    Drop,
+    Select,
+
+    // Variable instructions.
+    LocalGet(u32),
+    LocalSet(u32),
+    LocalTee(u32),
+    GlobalGet(u32),
+    GlobalSet(u32),
+
+    // Memory instructions.
+    I32Load(MemArg),
+    I64Load(MemArg),
+    F32Load(MemArg),
+    F64Load(MemArg),
+    I32Load8_S(MemArg),
+    I32Load8_U(MemArg),
+    I32Load16_S(MemArg),
+    I32Load16_U(MemArg),
+    I64Load8_S(MemArg),
+    I64Load8_U(MemArg),
+    I64Load16_S(MemArg),
+    I64Load16_U(MemArg),
+    I64Load32_S(MemArg),
+    I64Load32_U(MemArg),
+    I32Store(MemArg),
+    I64Store(MemArg),
+    F32Store(MemArg),
+    F64Store(MemArg),
+    I32Store8(MemArg),
+    I32Store16(MemArg),
+    I64Store8(MemArg),
+    I64Store16(MemArg),
+    I64Store32(MemArg),
+    MemorySize(u32),
+    MemoryGrow(u32),
+    MemoryInit { mem: u32, data: u32 },
+    DataDrop(u32),
+    MemoryCopy { src: u32, dst: u32 },
+    MemoryFill(u32),
+
+    // Numeric instructions.
+    I32Const(i32),
+    I64Const(i64),
+    F32Const(f32),
+    F64Const(f64),
+    I32Eqz,
+    I32Eq,
+    I32Neq,
+    I32LtS,
+    I32LtU,
+    I32GtS,
+    I32GtU,
+    I32LeS,
+    I32LeU,
+    I32GeS,
+    I32GeU,
+    I64Eqz,
+    I64Eq,
+    I64Neq,
+    I64LtS,
+    I64LtU,
+    I64GtS,
+    I64GtU,
+    I64LeS,
+    I64LeU,
+    I64GeS,
+    I64GeU,
+    F32Eq,
+    F32Neq,
+    F32Lt,
+    F32Gt,
+    F32Le,
+    F32Ge,
+    F64Eq,
+    F64Neq,
+    F64Lt,
+    F64Gt,
+    F64Le,
+    F64Ge,
+    I32Clz,
+    I32Ctz,
+    I32Popcnt,
+    I32Add,
+    I32Sub,
+    I32Mul,
+    I32DivS,
+    I32DivU,
+    I32RemS,
+    I32RemU,
+    I32And,
+    I32Or,
+    I32Xor,
+    I32Shl,
+    I32ShrS,
+    I32ShrU,
+    I32Rotl,
+    I32Rotr,
+    I64Clz,
+    I64Ctz,
+    I64Popcnt,
+    I64Add,
+    I64Sub,
+    I64Mul,
+    I64DivS,
+    I64DivU,
+    I64RemS,
+    I64RemU,
+    I64And,
+    I64Or,
+    I64Xor,
+    I64Shl,
+    I64ShrS,
+    I64ShrU,
+    I64Rotl,
+    I64Rotr,
+    F32Abs,
+    F32Neg,
+    F32Ceil,
+    F32Floor,
+    F32Trunc,
+    F32Nearest,
+    F32Sqrt,
+    F32Add,
+    F32Sub,
+    F32Mul,
+    F32Div,
+    F32Min,
+    F32Max,
+    F32Copysign,
+    F64Abs,
+    F64Neg,
+    F64Ceil,
+    F64Floor,
+    F64Trunc,
+    F64Nearest,
+    F64Sqrt,
+    F64Add,
+    F64Sub,
+    F64Mul,
+    F64Div,
+    F64Min,
+    F64Max,
+    F64Copysign,
+    I32WrapI64,
+    I32TruncF32S,
+    I32TruncF32U,
+    I32TruncF64S,
+    I32TruncF64U,
+    I64ExtendI32S,
+    I64ExtendI32U,
+    I64TruncF32S,
+    I64TruncF32U,
+    I64TruncF64S,
+    I64TruncF64U,
+    F32ConvertI32S,
+    F32ConvertI32U,
+    F32ConvertI64S,
+    F32ConvertI64U,
+    F32DemoteF64,
+    F64ConvertI32S,
+    F64ConvertI32U,
+    F64ConvertI64S,
+    F64ConvertI64U,
+    F64PromoteF32,
+    I32ReinterpretF32,
+    I64ReinterpretF64,
+    F32ReinterpretI32,
+    F64ReinterpretI64,
+    I32Extend8S,
+    I32Extend16S,
+    I64Extend8S,
+    I64Extend16S,
+    I64Extend32S,
+    I32TruncSatF32S,
+    I32TruncSatF32U,
+    I32TruncSatF64S,
+    I32TruncSatF64U,
+    I64TruncSatF32S,
+    I64TruncSatF32U,
+    I64TruncSatF64S,
+    I64TruncSatF64U,
+
+    // Reference types instructions.
+    TypedSelect(ValType),
+    RefNull(ValType),
+    RefIsNull,
+    RefFunc(u32),
+
+    // Bulk memory instructions.
+    TableInit { segment: u32, table: u32 },
+    ElemDrop { segment: u32 },
+    TableFill { table: u32 },
+    TableSet { table: u32 },
+    TableGet { table: u32 },
+    TableGrow { table: u32 },
+    TableSize { table: u32 },
+    TableCopy { src: u32, dst: u32 },
+
+    // SIMD instructions.
+    V128Load { memarg: MemArg },
+    V128Load8x8S { memarg: MemArg },
+    V128Load8x8U { memarg: MemArg },
+    V128Load16x4S { memarg: MemArg },
+    V128Load16x4U { memarg: MemArg },
+    V128Load32x2S { memarg: MemArg },
+    V128Load32x2U { memarg: MemArg },
+    V128Load8Splat { memarg: MemArg },
+    V128Load16Splat { memarg: MemArg },
+    V128Load32Splat { memarg: MemArg },
+    V128Load64Splat { memarg: MemArg },
+    V128Load32Zero { memarg: MemArg },
+    V128Load64Zero { memarg: MemArg },
+    V128Store { memarg: MemArg },
+    V128Load8Lane { memarg: MemArg, lane: Lane },
+    V128Load16Lane { memarg: MemArg, lane: Lane },
+    V128Load32Lane { memarg: MemArg, lane: Lane },
+    V128Load64Lane { memarg: MemArg, lane: Lane },
+    V128Store8Lane { memarg: MemArg, lane: Lane },
+    V128Store16Lane { memarg: MemArg, lane: Lane },
+    V128Store32Lane { memarg: MemArg, lane: Lane },
+    V128Store64Lane { memarg: MemArg, lane: Lane },
+    V128Const(i128),
+    I8x16Shuffle { lanes: [Lane; 16] },
+    I8x16ExtractLaneS { lane: Lane },
+    I8x16ExtractLaneU { lane: Lane },
+    I8x16ReplaceLane { lane: Lane },
+    I16x8ExtractLaneS { lane: Lane },
+    I16x8ExtractLaneU { lane: Lane },
+    I16x8ReplaceLane { lane: Lane },
+    I32x4ExtractLane { lane: Lane },
+    I32x4ReplaceLane { lane: Lane },
+    I64x2ExtractLane { lane: Lane },
+    I64x2ReplaceLane { lane: Lane },
+    F32x4ExtractLane { lane: Lane },
+    F32x4ReplaceLane { lane: Lane },
+    F64x2ExtractLane { lane: Lane },
+    F64x2ReplaceLane { lane: Lane },
+    I8x16Swizzle,
+    I8x16Splat,
+    I16x8Splat,
+    I32x4Splat,
+    I64x2Splat,
+    F32x4Splat,
+    F64x2Splat,
+    I8x16Eq,
+    I8x16Ne,
+    I8x16LtS,
+    I8x16LtU,
+    I8x16GtS,
+    I8x16GtU,
+    I8x16LeS,
+    I8x16LeU,
+    I8x16GeS,
+    I8x16GeU,
+    I16x8Eq,
+    I16x8Ne,
+    I16x8LtS,
+    I16x8LtU,
+    I16x8GtS,
+    I16x8GtU,
+    I16x8LeS,
+    I16x8LeU,
+    I16x8GeS,
+    I16x8GeU,
+    I32x4Eq,
+    I32x4Ne,
+    I32x4LtS,
+    I32x4LtU,
+    I32x4GtS,
+    I32x4GtU,
+    I32x4LeS,
+    I32x4LeU,
+    I32x4GeS,
+    I32x4GeU,
+    I64x2Eq,
+    I64x2Ne,
+    I64x2LtS,
+    I64x2GtS,
+    I64x2LeS,
+    I64x2GeS,
+    F32x4Eq,
+    F32x4Ne,
+    F32x4Lt,
+    F32x4Gt,
+    F32x4Le,
+    F32x4Ge,
+    F64x2Eq,
+    F64x2Ne,
+    F64x2Lt,
+    F64x2Gt,
+    F64x2Le,
+    F64x2Ge,
+    V128Not,
+    V128And,
+    V128AndNot,
+    V128Or,
+    V128Xor,
+    V128Bitselect,
+    V128AnyTrue,
+    I8x16Abs,
+    I8x16Neg,
+    I8x16Popcnt,
+    I8x16AllTrue,
+    I8x16Bitmask,
+    I8x16NarrowI16x8S,
+    I8x16NarrowI16x8U,
+    I8x16Shl,
+    I8x16ShrS,
+    I8x16ShrU,
+    I8x16Add,
+    I8x16AddSatS,
+    I8x16AddSatU,
+    I8x16Sub,
+    I8x16SubSatS,
+    I8x16SubSatU,
+    I8x16MinS,
+    I8x16MinU,
+    I8x16MaxS,
+    I8x16MaxU,
+    I8x16RoundingAverageU,
+    I16x8ExtAddPairwiseI8x16S,
+    I16x8ExtAddPairwiseI8x16U,
+    I16x8Abs,
+    I16x8Neg,
+    I16x8Q15MulrSatS,
+    I16x8AllTrue,
+    I16x8Bitmask,
+    I16x8NarrowI32x4S,
+    I16x8NarrowI32x4U,
+    I16x8ExtendLowI8x16S,
+    I16x8ExtendHighI8x16S,
+    I16x8ExtendLowI8x16U,
+    I16x8ExtendHighI8x16U,
+    I16x8Shl,
+    I16x8ShrS,
+    I16x8ShrU,
+    I16x8Add,
+    I16x8AddSatS,
+    I16x8AddSatU,
+    I16x8Sub,
+    I16x8SubSatS,
+    I16x8SubSatU,
+    I16x8Mul,
+    I16x8MinS,
+    I16x8MinU,
+    I16x8MaxS,
+    I16x8MaxU,
+    I16x8RoundingAverageU,
+    I16x8ExtMulLowI8x16S,
+    I16x8ExtMulHighI8x16S,
+    I16x8ExtMulLowI8x16U,
+    I16x8ExtMulHighI8x16U,
+    I32x4ExtAddPairwiseI16x8S,
+    I32x4ExtAddPairwiseI16x8U,
+    I32x4Abs,
+    I32x4Neg,
+    I32x4AllTrue,
+    I32x4Bitmask,
+    I32x4ExtendLowI16x8S,
+    I32x4ExtendHighI16x8S,
+    I32x4ExtendLowI16x8U,
+    I32x4ExtendHighI16x8U,
+    I32x4Shl,
+    I32x4ShrS,
+    I32x4ShrU,
+    I32x4Add,
+    I32x4Sub,
+    I32x4Mul,
+    I32x4MinS,
+    I32x4MinU,
+    I32x4MaxS,
+    I32x4MaxU,
+    I32x4DotI16x8S,
+    I32x4ExtMulLowI16x8S,
+    I32x4ExtMulHighI16x8S,
+    I32x4ExtMulLowI16x8U,
+    I32x4ExtMulHighI16x8U,
+    I64x2Abs,
+    I64x2Neg,
+    I64x2AllTrue,
+    I64x2Bitmask,
+    I64x2ExtendLowI32x4S,
+    I64x2ExtendHighI32x4S,
+    I64x2ExtendLowI32x4U,
+    I64x2ExtendHighI32x4U,
+    I64x2Shl,
+    I64x2ShrS,
+    I64x2ShrU,
+    I64x2Add,
+    I64x2Sub,
+    I64x2Mul,
+    I64x2ExtMulLowI32x4S,
+    I64x2ExtMulHighI32x4S,
+    I64x2ExtMulLowI32x4U,
+    I64x2ExtMulHighI32x4U,
+    F32x4Ceil,
+    F32x4Floor,
+    F32x4Trunc,
+    F32x4Nearest,
+    F32x4Abs,
+    F32x4Neg,
+    F32x4Sqrt,
+    F32x4Add,
+    F32x4Sub,
+    F32x4Mul,
+    F32x4Div,
+    F32x4Min,
+    F32x4Max,
+    F32x4PMin,
+    F32x4PMax,
+    F64x2Ceil,
+    F64x2Floor,
+    F64x2Trunc,
+    F64x2Nearest,
+    F64x2Abs,
+    F64x2Neg,
+    F64x2Sqrt,
+    F64x2Add,
+    F64x2Sub,
+    F64x2Mul,
+    F64x2Div,
+    F64x2Min,
+    F64x2Max,
+    F64x2PMin,
+    F64x2PMax,
+    I32x4TruncSatF32x4S,
+    I32x4TruncSatF32x4U,
+    F32x4ConvertI32x4S,
+    F32x4ConvertI32x4U,
+    I32x4TruncSatF64x2SZero,
+    I32x4TruncSatF64x2UZero,
+    F64x2ConvertLowI32x4S,
+    F64x2ConvertLowI32x4U,
+    F32x4DemoteF64x2Zero,
+    F64x2PromoteLowF32x4,
+}
+
+impl Instruction<'_> {
+    pub(crate) fn encode(&self, bytes: &mut Vec<u8>) {
+        match *self {
+            // Control instructions.
+            Instruction::Unreachable => bytes.push(0x00),
+            Instruction::Nop => bytes.push(0x01),
+            Instruction::Block(bt) => {
+                bytes.push(0x02);
+                bt.encode(bytes);
+            }
+            Instruction::Loop(bt) => {
+                bytes.push(0x03);
+                bt.encode(bytes);
+            }
+            Instruction::If(bt) => {
+                bytes.push(0x04);
+                bt.encode(bytes);
+            }
+            Instruction::Else => bytes.push(0x05),
+            Instruction::End => bytes.push(0x0B),
+            Instruction::Br(l) => {
+                bytes.push(0x0C);
+                bytes.extend(encoders::u32(l));
+            }
+            Instruction::BrIf(l) => {
+                bytes.push(0x0D);
+                bytes.extend(encoders::u32(l));
+            }
+            Instruction::BrTable(ls, l) => {
+                bytes.push(0x0E);
+                bytes.extend(encoders::u32(u32::try_from(ls.len()).unwrap()));
+                for l in ls {
+                    bytes.extend(encoders::u32(*l));
+                }
+                bytes.extend(encoders::u32(l));
+            }
+            Instruction::Return => bytes.push(0x0F),
+            Instruction::Call(f) => {
+                bytes.push(0x10);
+                bytes.extend(encoders::u32(f));
+            }
+            Instruction::CallIndirect { ty, table } => {
+                bytes.push(0x11);
+                bytes.extend(encoders::u32(ty));
+                bytes.extend(encoders::u32(table));
+            }
+
+            // Parametric instructions.
+            Instruction::Drop => bytes.push(0x1A),
+            Instruction::Select => bytes.push(0x1B),
+            Instruction::TypedSelect(ty) => {
+                bytes.push(0x1c);
+                bytes.extend(encoders::u32(1));
+                bytes.push(ty.into());
+            }
+
+            // Variable instructions.
+            Instruction::LocalGet(l) => {
+                bytes.push(0x20);
+                bytes.extend(encoders::u32(l));
+            }
+            Instruction::LocalSet(l) => {
+                bytes.push(0x21);
+                bytes.extend(encoders::u32(l));
+            }
+            Instruction::LocalTee(l) => {
+                bytes.push(0x22);
+                bytes.extend(encoders::u32(l));
+            }
+            Instruction::GlobalGet(g) => {
+                bytes.push(0x23);
+                bytes.extend(encoders::u32(g));
+            }
+            Instruction::GlobalSet(g) => {
+                bytes.push(0x24);
+                bytes.extend(encoders::u32(g));
+            }
+            Instruction::TableGet { table } => {
+                bytes.push(0x25);
+                bytes.extend(encoders::u32(table));
+            }
+            Instruction::TableSet { table } => {
+                bytes.push(0x26);
+                bytes.extend(encoders::u32(table));
+            }
+
+            // Memory instructions.
+            Instruction::I32Load(m) => {
+                bytes.push(0x28);
+                m.encode(bytes);
+            }
+            Instruction::I64Load(m) => {
+                bytes.push(0x29);
+                m.encode(bytes);
+            }
+            Instruction::F32Load(m) => {
+                bytes.push(0x2A);
+                m.encode(bytes);
+            }
+            Instruction::F64Load(m) => {
+                bytes.push(0x2B);
+                m.encode(bytes);
+            }
+            Instruction::I32Load8_S(m) => {
+                bytes.push(0x2C);
+                m.encode(bytes);
+            }
+            Instruction::I32Load8_U(m) => {
+                bytes.push(0x2D);
+                m.encode(bytes);
+            }
+            Instruction::I32Load16_S(m) => {
+                bytes.push(0x2E);
+                m.encode(bytes);
+            }
+            Instruction::I32Load16_U(m) => {
+                bytes.push(0x2F);
+                m.encode(bytes);
+            }
+            Instruction::I64Load8_S(m) => {
+                bytes.push(0x30);
+                m.encode(bytes);
+            }
+            Instruction::I64Load8_U(m) => {
+                bytes.push(0x31);
+                m.encode(bytes);
+            }
+            Instruction::I64Load16_S(m) => {
+                bytes.push(0x32);
+                m.encode(bytes);
+            }
+            Instruction::I64Load16_U(m) => {
+                bytes.push(0x33);
+                m.encode(bytes);
+            }
+            Instruction::I64Load32_S(m) => {
+                bytes.push(0x34);
+                m.encode(bytes);
+            }
+            Instruction::I64Load32_U(m) => {
+                bytes.push(0x35);
+                m.encode(bytes);
+            }
+            Instruction::I32Store(m) => {
+                bytes.push(0x36);
+                m.encode(bytes);
+            }
+            Instruction::I64Store(m) => {
+                bytes.push(0x37);
+                m.encode(bytes);
+            }
+            Instruction::F32Store(m) => {
+                bytes.push(0x38);
+                m.encode(bytes);
+            }
+            Instruction::F64Store(m) => {
+                bytes.push(0x39);
+                m.encode(bytes);
+            }
+            Instruction::I32Store8(m) => {
+                bytes.push(0x3A);
+                m.encode(bytes);
+            }
+            Instruction::I32Store16(m) => {
+                bytes.push(0x3B);
+                m.encode(bytes);
+            }
+            Instruction::I64Store8(m) => {
+                bytes.push(0x3C);
+                m.encode(bytes);
+            }
+            Instruction::I64Store16(m) => {
+                bytes.push(0x3D);
+                m.encode(bytes);
+            }
+            Instruction::I64Store32(m) => {
+                bytes.push(0x3E);
+                m.encode(bytes);
+            }
+            Instruction::MemorySize(i) => {
+                bytes.push(0x3F);
+                bytes.extend(encoders::u32(i));
+            }
+            Instruction::MemoryGrow(i) => {
+                bytes.push(0x40);
+                bytes.extend(encoders::u32(i));
+            }
+            Instruction::MemoryInit { mem, data } => {
+                bytes.push(0xfc);
+                bytes.extend(encoders::u32(8));
+                bytes.extend(encoders::u32(data));
+                bytes.extend(encoders::u32(mem));
+            }
+            Instruction::DataDrop(data) => {
+                bytes.push(0xfc);
+                bytes.extend(encoders::u32(9));
+                bytes.extend(encoders::u32(data));
+            }
+            Instruction::MemoryCopy { src, dst } => {
+                bytes.push(0xfc);
+                bytes.extend(encoders::u32(10));
+                bytes.extend(encoders::u32(dst));
+                bytes.extend(encoders::u32(src));
+            }
+            Instruction::MemoryFill(mem) => {
+                bytes.push(0xfc);
+                bytes.extend(encoders::u32(11));
+                bytes.extend(encoders::u32(mem));
+            }
+
+            // Numeric instructions.
+            Instruction::I32Const(x) => {
+                bytes.push(0x41);
+                bytes.extend(encoders::s32(x));
+            }
+            Instruction::I64Const(x) => {
+                bytes.push(0x42);
+                bytes.extend(encoders::s64(x));
+            }
+            Instruction::F32Const(x) => {
+                bytes.push(0x43);
+                let x = x.to_bits();
+                bytes.extend(x.to_le_bytes().iter().copied());
+            }
+            Instruction::F64Const(x) => {
+                bytes.push(0x44);
+                let x = x.to_bits();
+                bytes.extend(x.to_le_bytes().iter().copied());
+            }
+            Instruction::I32Eqz => bytes.push(0x45),
+            Instruction::I32Eq => bytes.push(0x46),
+            Instruction::I32Neq => bytes.push(0x47),
+            Instruction::I32LtS => bytes.push(0x48),
+            Instruction::I32LtU => bytes.push(0x49),
+            Instruction::I32GtS => bytes.push(0x4A),
+            Instruction::I32GtU => bytes.push(0x4B),
+            Instruction::I32LeS => bytes.push(0x4C),
+            Instruction::I32LeU => bytes.push(0x4D),
+            Instruction::I32GeS => bytes.push(0x4E),
+            Instruction::I32GeU => bytes.push(0x4F),
+            Instruction::I64Eqz => bytes.push(0x50),
+            Instruction::I64Eq => bytes.push(0x51),
+            Instruction::I64Neq => bytes.push(0x52),
+            Instruction::I64LtS => bytes.push(0x53),
+            Instruction::I64LtU => bytes.push(0x54),
+            Instruction::I64GtS => bytes.push(0x55),
+            Instruction::I64GtU => bytes.push(0x56),
+            Instruction::I64LeS => bytes.push(0x57),
+            Instruction::I64LeU => bytes.push(0x58),
+            Instruction::I64GeS => bytes.push(0x59),
+            Instruction::I64GeU => bytes.push(0x5A),
+            Instruction::F32Eq => bytes.push(0x5B),
+            Instruction::F32Neq => bytes.push(0x5C),
+            Instruction::F32Lt => bytes.push(0x5D),
+            Instruction::F32Gt => bytes.push(0x5E),
+            Instruction::F32Le => bytes.push(0x5F),
+            Instruction::F32Ge => bytes.push(0x60),
+            Instruction::F64Eq => bytes.push(0x61),
+            Instruction::F64Neq => bytes.push(0x62),
+            Instruction::F64Lt => bytes.push(0x63),
+            Instruction::F64Gt => bytes.push(0x64),
+            Instruction::F64Le => bytes.push(0x65),
+            Instruction::F64Ge => bytes.push(0x66),
+            Instruction::I32Clz => bytes.push(0x67),
+            Instruction::I32Ctz => bytes.push(0x68),
+            Instruction::I32Popcnt => bytes.push(0x69),
+            Instruction::I32Add => bytes.push(0x6A),
+            Instruction::I32Sub => bytes.push(0x6B),
+            Instruction::I32Mul => bytes.push(0x6C),
+            Instruction::I32DivS => bytes.push(0x6D),
+            Instruction::I32DivU => bytes.push(0x6E),
+            Instruction::I32RemS => bytes.push(0x6F),
+            Instruction::I32RemU => bytes.push(0x70),
+            Instruction::I32And => bytes.push(0x71),
+            Instruction::I32Or => bytes.push(0x72),
+            Instruction::I32Xor => bytes.push(0x73),
+            Instruction::I32Shl => bytes.push(0x74),
+            Instruction::I32ShrS => bytes.push(0x75),
+            Instruction::I32ShrU => bytes.push(0x76),
+            Instruction::I32Rotl => bytes.push(0x77),
+            Instruction::I32Rotr => bytes.push(0x78),
+            Instruction::I64Clz => bytes.push(0x79),
+            Instruction::I64Ctz => bytes.push(0x7A),
+            Instruction::I64Popcnt => bytes.push(0x7B),
+            Instruction::I64Add => bytes.push(0x7C),
+            Instruction::I64Sub => bytes.push(0x7D),
+            Instruction::I64Mul => bytes.push(0x7E),
+            Instruction::I64DivS => bytes.push(0x7F),
+            Instruction::I64DivU => bytes.push(0x80),
+            Instruction::I64RemS => bytes.push(0x81),
+            Instruction::I64RemU => bytes.push(0x82),
+            Instruction::I64And => bytes.push(0x83),
+            Instruction::I64Or => bytes.push(0x84),
+            Instruction::I64Xor => bytes.push(0x85),
+            Instruction::I64Shl => bytes.push(0x86),
+            Instruction::I64ShrS => bytes.push(0x87),
+            Instruction::I64ShrU => bytes.push(0x88),
+            Instruction::I64Rotl => bytes.push(0x89),
+            Instruction::I64Rotr => bytes.push(0x8A),
+            Instruction::F32Abs => bytes.push(0x8B),
+            Instruction::F32Neg => bytes.push(0x8C),
+            Instruction::F32Ceil => bytes.push(0x8D),
+            Instruction::F32Floor => bytes.push(0x8E),
+            Instruction::F32Trunc => bytes.push(0x8F),
+            Instruction::F32Nearest => bytes.push(0x90),
+            Instruction::F32Sqrt => bytes.push(0x91),
+            Instruction::F32Add => bytes.push(0x92),
+            Instruction::F32Sub => bytes.push(0x93),
+            Instruction::F32Mul => bytes.push(0x94),
+            Instruction::F32Div => bytes.push(0x95),
+            Instruction::F32Min => bytes.push(0x96),
+            Instruction::F32Max => bytes.push(0x97),
+            Instruction::F32Copysign => bytes.push(0x98),
+            Instruction::F64Abs => bytes.push(0x99),
+            Instruction::F64Neg => bytes.push(0x9A),
+            Instruction::F64Ceil => bytes.push(0x9B),
+            Instruction::F64Floor => bytes.push(0x9C),
+            Instruction::F64Trunc => bytes.push(0x9D),
+            Instruction::F64Nearest => bytes.push(0x9E),
+            Instruction::F64Sqrt => bytes.push(0x9F),
+            Instruction::F64Add => bytes.push(0xA0),
+            Instruction::F64Sub => bytes.push(0xA1),
+            Instruction::F64Mul => bytes.push(0xA2),
+            Instruction::F64Div => bytes.push(0xA3),
+            Instruction::F64Min => bytes.push(0xA4),
+            Instruction::F64Max => bytes.push(0xA5),
+            Instruction::F64Copysign => bytes.push(0xA6),
+            Instruction::I32WrapI64 => bytes.push(0xA7),
+            Instruction::I32TruncF32S => bytes.push(0xA8),
+            Instruction::I32TruncF32U => bytes.push(0xA9),
+            Instruction::I32TruncF64S => bytes.push(0xAA),
+            Instruction::I32TruncF64U => bytes.push(0xAB),
+            Instruction::I64ExtendI32S => bytes.push(0xAC),
+            Instruction::I64ExtendI32U => bytes.push(0xAD),
+            Instruction::I64TruncF32S => bytes.push(0xAE),
+            Instruction::I64TruncF32U => bytes.push(0xAF),
+            Instruction::I64TruncF64S => bytes.push(0xB0),
+            Instruction::I64TruncF64U => bytes.push(0xB1),
+            Instruction::F32ConvertI32S => bytes.push(0xB2),
+            Instruction::F32ConvertI32U => bytes.push(0xB3),
+            Instruction::F32ConvertI64S => bytes.push(0xB4),
+            Instruction::F32ConvertI64U => bytes.push(0xB5),
+            Instruction::F32DemoteF64 => bytes.push(0xB6),
+            Instruction::F64ConvertI32S => bytes.push(0xB7),
+            Instruction::F64ConvertI32U => bytes.push(0xB8),
+            Instruction::F64ConvertI64S => bytes.push(0xB9),
+            Instruction::F64ConvertI64U => bytes.push(0xBA),
+            Instruction::F64PromoteF32 => bytes.push(0xBB),
+            Instruction::I32ReinterpretF32 => bytes.push(0xBC),
+            Instruction::I64ReinterpretF64 => bytes.push(0xBD),
+            Instruction::F32ReinterpretI32 => bytes.push(0xBE),
+            Instruction::F64ReinterpretI64 => bytes.push(0xBF),
+            Instruction::I32Extend8S => bytes.push(0xC0),
+            Instruction::I32Extend16S => bytes.push(0xC1),
+            Instruction::I64Extend8S => bytes.push(0xC2),
+            Instruction::I64Extend16S => bytes.push(0xC3),
+            Instruction::I64Extend32S => bytes.push(0xC4),
+
+            Instruction::I32TruncSatF32S => {
+                bytes.push(0xFC);
+                bytes.extend(encoders::u32(0));
+            }
+            Instruction::I32TruncSatF32U => {
+                bytes.push(0xFC);
+                bytes.extend(encoders::u32(1));
+            }
+            Instruction::I32TruncSatF64S => {
+                bytes.push(0xFC);
+                bytes.extend(encoders::u32(2));
+            }
+            Instruction::I32TruncSatF64U => {
+                bytes.push(0xFC);
+                bytes.extend(encoders::u32(3));
+            }
+            Instruction::I64TruncSatF32S => {
+                bytes.push(0xFC);
+                bytes.extend(encoders::u32(4));
+            }
+            Instruction::I64TruncSatF32U => {
+                bytes.push(0xFC);
+                bytes.extend(encoders::u32(5));
+            }
+            Instruction::I64TruncSatF64S => {
+                bytes.push(0xFC);
+                bytes.extend(encoders::u32(6));
+            }
+            Instruction::I64TruncSatF64U => {
+                bytes.push(0xFC);
+                bytes.extend(encoders::u32(7));
+            }
+
+            // Reference types instructions.
+            Instruction::RefNull(ty) => {
+                bytes.push(0xd0);
+                bytes.push(ty.into());
+            }
+            Instruction::RefIsNull => bytes.push(0xd1),
+            Instruction::RefFunc(f) => {
+                bytes.push(0xd2);
+                bytes.extend(encoders::u32(f));
+            }
+
+            // Bulk memory instructions.
+            Instruction::TableInit { segment, table } => {
+                bytes.push(0xfc);
+                bytes.extend(encoders::u32(0x0c));
+                bytes.extend(encoders::u32(segment));
+                bytes.extend(encoders::u32(table));
+            }
+            Instruction::ElemDrop { segment } => {
+                bytes.push(0xfc);
+                bytes.extend(encoders::u32(0x0d));
+                bytes.extend(encoders::u32(segment));
+            }
+            Instruction::TableCopy { src, dst } => {
+                bytes.push(0xfc);
+                bytes.extend(encoders::u32(0x0e));
+                bytes.extend(encoders::u32(dst));
+                bytes.extend(encoders::u32(src));
+            }
+            Instruction::TableGrow { table } => {
+                bytes.push(0xfc);
+                bytes.extend(encoders::u32(0x0f));
+                bytes.extend(encoders::u32(table));
+            }
+            Instruction::TableSize { table } => {
+                bytes.push(0xfc);
+                bytes.extend(encoders::u32(0x10));
+                bytes.extend(encoders::u32(table));
+            }
+            Instruction::TableFill { table } => {
+                bytes.push(0xfc);
+                bytes.extend(encoders::u32(0x11));
+                bytes.extend(encoders::u32(table));
+            }
+
+            // SIMD instructions.
+            Instruction::V128Load { memarg } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x00));
+                memarg.encode(bytes);
+            }
+            Instruction::V128Load8x8S { memarg } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x01));
+                memarg.encode(bytes);
+            }
+            Instruction::V128Load8x8U { memarg } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x02));
+                memarg.encode(bytes);
+            }
+            Instruction::V128Load16x4S { memarg } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x03));
+                memarg.encode(bytes);
+            }
+            Instruction::V128Load16x4U { memarg } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x04));
+                memarg.encode(bytes);
+            }
+            Instruction::V128Load32x2S { memarg } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x05));
+                memarg.encode(bytes);
+            }
+            Instruction::V128Load32x2U { memarg } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x06));
+                memarg.encode(bytes);
+            }
+            Instruction::V128Load8Splat { memarg } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x07));
+                memarg.encode(bytes);
+            }
+            Instruction::V128Load16Splat { memarg } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x08));
+                memarg.encode(bytes);
+            }
+            Instruction::V128Load32Splat { memarg } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x09));
+                memarg.encode(bytes);
+            }
+            Instruction::V128Load64Splat { memarg } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x0A));
+                memarg.encode(bytes);
+            }
+            Instruction::V128Store { memarg } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x0B));
+                memarg.encode(bytes);
+            }
+            Instruction::V128Const(x) => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x0C));
+                bytes.extend(x.to_le_bytes().iter().copied());
+            }
+            Instruction::I8x16Shuffle { lanes } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x0D));
+                assert!(lanes.iter().all(|l: &u8| *l < 32));
+                bytes.extend(lanes.iter().copied());
+            }
+            Instruction::I8x16Swizzle => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x0E));
+            }
+            Instruction::I8x16Splat => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x0F));
+            }
+            Instruction::I16x8Splat => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x10));
+            }
+            Instruction::I32x4Splat => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x11));
+            }
+            Instruction::I64x2Splat => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x12));
+            }
+            Instruction::F32x4Splat => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x13));
+            }
+            Instruction::F64x2Splat => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x14));
+            }
+            Instruction::I8x16ExtractLaneS { lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x15));
+                assert!(lane < 16);
+                bytes.push(lane);
+            }
+            Instruction::I8x16ExtractLaneU { lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x16));
+                assert!(lane < 16);
+                bytes.push(lane);
+            }
+            Instruction::I8x16ReplaceLane { lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x17));
+                assert!(lane < 16);
+                bytes.push(lane);
+            }
+            Instruction::I16x8ExtractLaneS { lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x18));
+                assert!(lane < 8);
+                bytes.push(lane);
+            }
+            Instruction::I16x8ExtractLaneU { lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x19));
+                assert!(lane < 8);
+                bytes.push(lane);
+            }
+            Instruction::I16x8ReplaceLane { lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x1A));
+                assert!(lane < 8);
+                bytes.push(lane);
+            }
+            Instruction::I32x4ExtractLane { lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x1B));
+                assert!(lane < 4);
+                bytes.push(lane);
+            }
+            Instruction::I32x4ReplaceLane { lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x1C));
+                assert!(lane < 4);
+                bytes.push(lane);
+            }
+            Instruction::I64x2ExtractLane { lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x1D));
+                assert!(lane < 2);
+                bytes.push(lane);
+            }
+            Instruction::I64x2ReplaceLane { lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x1E));
+                assert!(lane < 2);
+                bytes.push(lane);
+            }
+            Instruction::F32x4ExtractLane { lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x1F));
+                assert!(lane < 4);
+                bytes.push(lane);
+            }
+            Instruction::F32x4ReplaceLane { lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x20));
+                assert!(lane < 4);
+                bytes.push(lane);
+            }
+            Instruction::F64x2ExtractLane { lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x21));
+                assert!(lane < 2);
+                bytes.push(lane);
+            }
+            Instruction::F64x2ReplaceLane { lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x22));
+                assert!(lane < 2);
+                bytes.push(lane);
+            }
+
+            Instruction::I8x16Eq => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x23));
+            }
+            Instruction::I8x16Ne => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x24));
+            }
+            Instruction::I8x16LtS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x25));
+            }
+            Instruction::I8x16LtU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x26));
+            }
+            Instruction::I8x16GtS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x27));
+            }
+            Instruction::I8x16GtU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x28));
+            }
+            Instruction::I8x16LeS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x29));
+            }
+            Instruction::I8x16LeU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x2A));
+            }
+            Instruction::I8x16GeS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x2B));
+            }
+            Instruction::I8x16GeU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x2C));
+            }
+            Instruction::I16x8Eq => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x2D));
+            }
+            Instruction::I16x8Ne => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x2E));
+            }
+            Instruction::I16x8LtS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x2F));
+            }
+            Instruction::I16x8LtU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x30));
+            }
+            Instruction::I16x8GtS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x31));
+            }
+            Instruction::I16x8GtU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x32));
+            }
+            Instruction::I16x8LeS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x33));
+            }
+            Instruction::I16x8LeU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x34));
+            }
+            Instruction::I16x8GeS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x35));
+            }
+            Instruction::I16x8GeU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x36));
+            }
+            Instruction::I32x4Eq => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x37));
+            }
+            Instruction::I32x4Ne => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x38));
+            }
+            Instruction::I32x4LtS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x39));
+            }
+            Instruction::I32x4LtU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x3A));
+            }
+            Instruction::I32x4GtS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x3B));
+            }
+            Instruction::I32x4GtU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x3C));
+            }
+            Instruction::I32x4LeS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x3D));
+            }
+            Instruction::I32x4LeU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x3E));
+            }
+            Instruction::I32x4GeS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x3F));
+            }
+            Instruction::I32x4GeU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x40));
+            }
+            Instruction::F32x4Eq => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x41));
+            }
+            Instruction::F32x4Ne => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x42));
+            }
+            Instruction::F32x4Lt => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x43));
+            }
+            Instruction::F32x4Gt => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x44));
+            }
+            Instruction::F32x4Le => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x45));
+            }
+            Instruction::F32x4Ge => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x46));
+            }
+            Instruction::F64x2Eq => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x47));
+            }
+            Instruction::F64x2Ne => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x48));
+            }
+            Instruction::F64x2Lt => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x49));
+            }
+            Instruction::F64x2Gt => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x4A));
+            }
+            Instruction::F64x2Le => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x4B));
+            }
+            Instruction::F64x2Ge => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x4C));
+            }
+            Instruction::V128Not => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x4D));
+            }
+            Instruction::V128And => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x4E));
+            }
+            Instruction::V128AndNot => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x4F));
+            }
+            Instruction::V128Or => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x50));
+            }
+            Instruction::V128Xor => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x51));
+            }
+            Instruction::V128Bitselect => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x52));
+            }
+            Instruction::V128AnyTrue => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x53));
+            }
+            Instruction::I8x16Abs => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x60));
+            }
+            Instruction::I8x16Neg => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x61));
+            }
+            Instruction::I8x16Popcnt => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x62));
+            }
+            Instruction::I8x16AllTrue => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x63));
+            }
+            Instruction::I8x16Bitmask => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x64));
+            }
+            Instruction::I8x16NarrowI16x8S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x65));
+            }
+            Instruction::I8x16NarrowI16x8U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x66));
+            }
+            Instruction::I8x16Shl => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x6b));
+            }
+            Instruction::I8x16ShrS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x6c));
+            }
+            Instruction::I8x16ShrU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x6d));
+            }
+            Instruction::I8x16Add => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x6e));
+            }
+            Instruction::I8x16AddSatS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x6f));
+            }
+            Instruction::I8x16AddSatU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x70));
+            }
+            Instruction::I8x16Sub => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x71));
+            }
+            Instruction::I8x16SubSatS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x72));
+            }
+            Instruction::I8x16SubSatU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x73));
+            }
+            Instruction::I8x16MinS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x76));
+            }
+            Instruction::I8x16MinU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x77));
+            }
+            Instruction::I8x16MaxS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x78));
+            }
+            Instruction::I8x16MaxU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x79));
+            }
+            Instruction::I8x16RoundingAverageU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x7B));
+            }
+            Instruction::I16x8ExtAddPairwiseI8x16S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x7C));
+            }
+            Instruction::I16x8ExtAddPairwiseI8x16U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x7D));
+            }
+            Instruction::I32x4ExtAddPairwiseI16x8S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x7E));
+            }
+            Instruction::I32x4ExtAddPairwiseI16x8U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x7F));
+            }
+            Instruction::I16x8Abs => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x80));
+            }
+            Instruction::I16x8Neg => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x81));
+            }
+            Instruction::I16x8Q15MulrSatS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x82));
+            }
+            Instruction::I16x8AllTrue => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x83));
+            }
+            Instruction::I16x8Bitmask => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x84));
+            }
+            Instruction::I16x8NarrowI32x4S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x85));
+            }
+            Instruction::I16x8NarrowI32x4U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x86));
+            }
+            Instruction::I16x8ExtendLowI8x16S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x87));
+            }
+            Instruction::I16x8ExtendHighI8x16S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x88));
+            }
+            Instruction::I16x8ExtendLowI8x16U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x89));
+            }
+            Instruction::I16x8ExtendHighI8x16U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x8A));
+            }
+            Instruction::I16x8Shl => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x8B));
+            }
+            Instruction::I16x8ShrS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x8C));
+            }
+            Instruction::I16x8ShrU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x8D));
+            }
+            Instruction::I16x8Add => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x8E));
+            }
+            Instruction::I16x8AddSatS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x8F));
+            }
+            Instruction::I16x8AddSatU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x90));
+            }
+            Instruction::I16x8Sub => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x91));
+            }
+            Instruction::I16x8SubSatS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x92));
+            }
+            Instruction::I16x8SubSatU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x93));
+            }
+            Instruction::I16x8Mul => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x95));
+            }
+            Instruction::I16x8MinS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x96));
+            }
+            Instruction::I16x8MinU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x97));
+            }
+            Instruction::I16x8MaxS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x98));
+            }
+            Instruction::I16x8MaxU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x99));
+            }
+            Instruction::I16x8RoundingAverageU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x9B));
+            }
+            Instruction::I16x8ExtMulLowI8x16S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x9C));
+            }
+            Instruction::I16x8ExtMulHighI8x16S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x9D));
+            }
+            Instruction::I16x8ExtMulLowI8x16U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x9E));
+            }
+            Instruction::I16x8ExtMulHighI8x16U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x9F));
+            }
+            Instruction::I32x4Abs => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xA0));
+            }
+            Instruction::I32x4Neg => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xA1));
+            }
+            Instruction::I32x4AllTrue => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xA3));
+            }
+            Instruction::I32x4Bitmask => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xA4));
+            }
+            Instruction::I32x4ExtendLowI16x8S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xA7));
+            }
+            Instruction::I32x4ExtendHighI16x8S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xA8));
+            }
+            Instruction::I32x4ExtendLowI16x8U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xA9));
+            }
+            Instruction::I32x4ExtendHighI16x8U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xAA));
+            }
+            Instruction::I32x4Shl => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xAB));
+            }
+            Instruction::I32x4ShrS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xAC));
+            }
+            Instruction::I32x4ShrU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xAD));
+            }
+            Instruction::I32x4Add => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xAE));
+            }
+            Instruction::I32x4Sub => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xB1));
+            }
+            Instruction::I32x4Mul => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xB5));
+            }
+            Instruction::I32x4MinS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xB6));
+            }
+            Instruction::I32x4MinU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xB7));
+            }
+            Instruction::I32x4MaxS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xB8));
+            }
+            Instruction::I32x4MaxU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xB9));
+            }
+            Instruction::I32x4DotI16x8S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xBA));
+            }
+            Instruction::I32x4ExtMulLowI16x8S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xBC));
+            }
+            Instruction::I32x4ExtMulHighI16x8S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xBD));
+            }
+            Instruction::I32x4ExtMulLowI16x8U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xBE));
+            }
+            Instruction::I32x4ExtMulHighI16x8U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xBF));
+            }
+            Instruction::I64x2Abs => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xC0));
+            }
+            Instruction::I64x2Neg => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xC1));
+            }
+            Instruction::I64x2AllTrue => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xC3));
+            }
+            Instruction::I64x2Bitmask => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xC4));
+            }
+            Instruction::I64x2ExtendLowI32x4S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xC7));
+            }
+            Instruction::I64x2ExtendHighI32x4S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xC8));
+            }
+            Instruction::I64x2ExtendLowI32x4U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xC9));
+            }
+            Instruction::I64x2ExtendHighI32x4U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xCA));
+            }
+            Instruction::I64x2Shl => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xCB));
+            }
+            Instruction::I64x2ShrS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xCC));
+            }
+            Instruction::I64x2ShrU => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xCD));
+            }
+            Instruction::I64x2Add => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xCE));
+            }
+            Instruction::I64x2Sub => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xD1));
+            }
+            Instruction::I64x2Mul => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xD5));
+            }
+            Instruction::I64x2ExtMulLowI32x4S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xDC));
+            }
+            Instruction::I64x2ExtMulHighI32x4S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xDD));
+            }
+            Instruction::I64x2ExtMulLowI32x4U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xDE));
+            }
+            Instruction::I64x2ExtMulHighI32x4U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xDF));
+            }
+            Instruction::F32x4Ceil => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x67));
+            }
+            Instruction::F32x4Floor => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x68));
+            }
+            Instruction::F32x4Trunc => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x69));
+            }
+            Instruction::F32x4Nearest => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x6A));
+            }
+            Instruction::F32x4Abs => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xE0));
+            }
+            Instruction::F32x4Neg => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xE1));
+            }
+            Instruction::F32x4Sqrt => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xE3));
+            }
+            Instruction::F32x4Add => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xE4));
+            }
+            Instruction::F32x4Sub => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xE5));
+            }
+            Instruction::F32x4Mul => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xE6));
+            }
+            Instruction::F32x4Div => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xE7));
+            }
+            Instruction::F32x4Min => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xE8));
+            }
+            Instruction::F32x4Max => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xE9));
+            }
+            Instruction::F32x4PMin => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xEA));
+            }
+            Instruction::F32x4PMax => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xEB));
+            }
+            Instruction::F64x2Ceil => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x74));
+            }
+            Instruction::F64x2Floor => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x75));
+            }
+            Instruction::F64x2Trunc => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x7A));
+            }
+            Instruction::F64x2Nearest => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x94));
+            }
+            Instruction::F64x2Abs => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xEC));
+            }
+            Instruction::F64x2Neg => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xED));
+            }
+            Instruction::F64x2Sqrt => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xEF));
+            }
+            Instruction::F64x2Add => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xF0));
+            }
+            Instruction::F64x2Sub => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xF1));
+            }
+            Instruction::F64x2Mul => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xF2));
+            }
+            Instruction::F64x2Div => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xF3));
+            }
+            Instruction::F64x2Min => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xF4));
+            }
+            Instruction::F64x2Max => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xF5));
+            }
+            Instruction::F64x2PMin => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xF6));
+            }
+            Instruction::F64x2PMax => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xF7));
+            }
+            Instruction::I32x4TruncSatF32x4S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xF8));
+            }
+            Instruction::I32x4TruncSatF32x4U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xF9));
+            }
+            Instruction::F32x4ConvertI32x4S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xFA));
+            }
+            Instruction::F32x4ConvertI32x4U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xFB));
+            }
+            Instruction::I32x4TruncSatF64x2SZero => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xFC));
+            }
+            Instruction::I32x4TruncSatF64x2UZero => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xFD));
+            }
+            Instruction::F64x2ConvertLowI32x4S => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xFE));
+            }
+            Instruction::F64x2ConvertLowI32x4U => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xFF));
+            }
+            Instruction::F32x4DemoteF64x2Zero => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x5E));
+            }
+            Instruction::F64x2PromoteLowF32x4 => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x5F));
+            }
+            Instruction::V128Load32Zero { memarg } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x5C));
+                memarg.encode(bytes);
+            }
+            Instruction::V128Load64Zero { memarg } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x5D));
+                memarg.encode(bytes);
+            }
+            Instruction::V128Load8Lane { memarg, lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x54));
+                memarg.encode(bytes);
+                assert!(lane < 16);
+                bytes.push(lane);
+            }
+            Instruction::V128Load16Lane { memarg, lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x55));
+                memarg.encode(bytes);
+                assert!(lane < 8);
+                bytes.push(lane);
+            }
+            Instruction::V128Load32Lane { memarg, lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x56));
+                memarg.encode(bytes);
+                assert!(lane < 4);
+                bytes.push(lane);
+            }
+            Instruction::V128Load64Lane { memarg, lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x57));
+                memarg.encode(bytes);
+                assert!(lane < 2);
+                bytes.push(lane);
+            }
+            Instruction::V128Store8Lane { memarg, lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x58));
+                memarg.encode(bytes);
+                assert!(lane < 16);
+                bytes.push(lane);
+            }
+            Instruction::V128Store16Lane { memarg, lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x59));
+                memarg.encode(bytes);
+                assert!(lane < 8);
+                bytes.push(lane);
+            }
+            Instruction::V128Store32Lane { memarg, lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x5A));
+                memarg.encode(bytes);
+                assert!(lane < 4);
+                bytes.push(lane);
+            }
+            Instruction::V128Store64Lane { memarg, lane } => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0x5B));
+                memarg.encode(bytes);
+                assert!(lane < 2);
+                bytes.push(lane);
+            }
+            Instruction::I64x2Eq => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xD6));
+            }
+            Instruction::I64x2Ne => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xD7));
+            }
+            Instruction::I64x2LtS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xD8));
+            }
+            Instruction::I64x2GtS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xD9));
+            }
+            Instruction::I64x2LeS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xDD));
+            }
+            Instruction::I64x2GeS => {
+                bytes.push(0xFD);
+                bytes.extend(encoders::u32(0xDB));
+            }
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/custom.rs
@@ -0,0 +1,59 @@
+use super::*;
+
+/// A custom section holding arbitrary data.
+#[derive(Clone, Debug)]
+pub struct CustomSection<'a> {
+    /// The name of this custom section.
+    pub name: &'a str,
+    /// This custom section's data.
+    pub data: &'a [u8],
+}
+
+impl Section for CustomSection<'_> {
+    fn id(&self) -> u8 {
+        SectionId::Custom.into()
+    }
+
+    fn encode<S>(&self, sink: &mut S)
+    where
+        S: Extend<u8>,
+    {
+        let name_len = encoders::u32(u32::try_from(self.name.len()).unwrap());
+        let n = name_len.len();
+
+        sink.extend(
+            encoders::u32(u32::try_from(n + self.name.len() + self.data.len()).unwrap())
+                .chain(name_len)
+                .chain(self.name.as_bytes().iter().copied())
+                .chain(self.data.iter().copied()),
+        );
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_custom_section() {
+        let custom = CustomSection {
+            name: "test",
+            data: &[11, 22, 33, 44],
+        };
+
+        let mut encoded = vec![];
+        custom.encode(&mut encoded);
+
+        #[rustfmt::skip]
+        assert_eq!(encoded, vec![
+            // LEB128 length of section.
+            9,
+            // LEB128 length of name.
+            4,
+            // Name.
+            b't', b'e', b's', b't',
+            // Data.
+            11, 22, 33, 44,
+        ]);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/data.rs
@@ -0,0 +1,190 @@
+use super::*;
+
+/// An encoder for the data section.
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{
+///     DataSection, Instruction, MemorySection, MemoryType,
+///     Module,
+/// };
+///
+/// let mut memory = MemorySection::new();
+/// memory.memory(MemoryType {
+///     minimum: 1,
+///     maximum: None,
+///     memory64: false,
+/// });
+///
+/// let mut data = DataSection::new();
+/// let memory_index = 0;
+/// let offset = Instruction::I32Const(42);
+/// let segment_data = b"hello";
+/// data.active(memory_index, offset, segment_data.iter().copied());
+///
+/// let mut module = Module::new();
+/// module
+///     .section(&memory)
+///     .section(&data);
+///
+/// let wasm_bytes = module.finish();
+/// ```
+#[derive(Clone, Debug)]
+pub struct DataSection {
+    bytes: Vec<u8>,
+    num_added: u32,
+}
+
+/// A segment in the data section.
+#[derive(Clone, Copy, Debug)]
+pub struct DataSegment<'a, D> {
+    /// This data segment's mode.
+    pub mode: DataSegmentMode<'a>,
+    /// This data segment's data.
+    pub data: D,
+}
+
+/// A data segment's mode.
+#[derive(Clone, Copy, Debug)]
+pub enum DataSegmentMode<'a> {
+    /// An active data segment.
+    Active {
+        /// The memory this segment applies to.
+        memory_index: u32,
+        /// The offset where this segment's data is initialized at.
+        offset: Instruction<'a>,
+    },
+    /// A passive data segment.
+    ///
+    /// Passive data segments are part of the bulk memory proposal.
+    Passive,
+}
+
+impl DataSection {
+    /// Create a new data section encoder.
+    pub fn new() -> DataSection {
+        DataSection {
+            bytes: vec![],
+            num_added: 0,
+        }
+    }
+
+    /// How many segments have been defined inside this section so far?
+    pub fn len(&self) -> u32 {
+        self.num_added
+    }
+
+    /// Define an active data segment.
+    pub fn segment<D>(&mut self, segment: DataSegment<D>) -> &mut Self
+    where
+        D: IntoIterator<Item = u8>,
+        D::IntoIter: ExactSizeIterator,
+    {
+        match segment.mode {
+            DataSegmentMode::Passive => {
+                self.bytes.push(0x01);
+            }
+            DataSegmentMode::Active {
+                memory_index: 0,
+                offset,
+            } => {
+                self.bytes.push(0x00);
+                offset.encode(&mut self.bytes);
+                Instruction::End.encode(&mut self.bytes);
+            }
+            DataSegmentMode::Active {
+                memory_index,
+                offset,
+            } => {
+                self.bytes.push(0x02);
+                self.bytes.extend(encoders::u32(memory_index));
+                offset.encode(&mut self.bytes);
+                Instruction::End.encode(&mut self.bytes);
+            }
+        }
+
+        let data = segment.data.into_iter();
+        self.bytes
+            .extend(encoders::u32(u32::try_from(data.len()).unwrap()));
+        self.bytes.extend(data);
+
+        self.num_added += 1;
+        self
+    }
+
+    /// Define an active data segment.
+    pub fn active<'a, D>(
+        &mut self,
+        memory_index: u32,
+        offset: Instruction<'a>,
+        data: D,
+    ) -> &mut Self
+    where
+        D: IntoIterator<Item = u8>,
+        D::IntoIter: ExactSizeIterator,
+    {
+        self.segment(DataSegment {
+            mode: DataSegmentMode::Active {
+                memory_index,
+                offset,
+            },
+            data,
+        })
+    }
+
+    /// Define a passive data segment.
+    ///
+    /// Passive data segments are part of the bulk memory proposal.
+    pub fn passive<'a, D>(&mut self, data: D) -> &mut Self
+    where
+        D: IntoIterator<Item = u8>,
+        D::IntoIter: ExactSizeIterator,
+    {
+        self.segment(DataSegment {
+            mode: DataSegmentMode::Passive,
+            data,
+        })
+    }
+}
+
+impl Section for DataSection {
+    fn id(&self) -> u8 {
+        SectionId::Data.into()
+    }
+
+    fn encode<S>(&self, sink: &mut S)
+    where
+        S: Extend<u8>,
+    {
+        let num_added = encoders::u32(self.num_added);
+        let n = num_added.len();
+        sink.extend(
+            encoders::u32(u32::try_from(n + self.bytes.len()).unwrap())
+                .chain(num_added)
+                .chain(self.bytes.iter().copied()),
+        );
+    }
+}
+
+/// An encoder for the data count section.
+#[derive(Clone, Copy, Debug)]
+pub struct DataCountSection {
+    /// The number of segments in the data section.
+    pub count: u32,
+}
+
+impl Section for DataCountSection {
+    fn id(&self) -> u8 {
+        SectionId::DataCount.into()
+    }
+
+    fn encode<S>(&self, sink: &mut S)
+    where
+        S: Extend<u8>,
+    {
+        let count = encoders::u32(self.count);
+        let n = count.len();
+        sink.extend(encoders::u32(u32::try_from(n).unwrap()).chain(count));
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/elements.rs
@@ -0,0 +1,239 @@
+use super::*;
+
+/// An encoder for the element section.
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{
+///     Elements, ElementSection, Instruction, Module, TableSection, TableType,
+///     ValType,
+/// };
+///
+/// let mut tables = TableSection::new();
+/// tables.table(TableType {
+///     element_type: ValType::FuncRef,
+///     minimum: 128,
+///     maximum: None,
+/// });
+///
+/// let mut elements = ElementSection::new();
+/// let table_index = 0;
+/// let offset = Instruction::I32Const(42);
+/// let element_type = ValType::FuncRef;
+/// let functions = Elements::Functions(&[
+///     // Function indices...
+/// ]);
+/// elements.active(Some(table_index), offset, element_type, functions);
+///
+/// let mut module = Module::new();
+/// module
+///     .section(&tables)
+///     .section(&elements);
+///
+/// let wasm_bytes = module.finish();
+/// ```
+#[derive(Clone, Debug)]
+pub struct ElementSection {
+    bytes: Vec<u8>,
+    num_added: u32,
+}
+
+/// A sequence of elements in a segment in the element section.
+#[derive(Clone, Copy, Debug)]
+pub enum Elements<'a> {
+    /// A sequences of references to functions by their indices.
+    Functions(&'a [u32]),
+    /// A sequence of reference expressions.
+    Expressions(&'a [Element]),
+}
+
+/// An element in a segment in the element section.
+#[derive(Clone, Copy, Debug)]
+pub enum Element {
+    /// A null reference.
+    Null,
+    /// A `ref.func n`.
+    Func(u32),
+}
+
+/// An element segment's mode.
+#[derive(Clone, Copy, Debug)]
+pub enum ElementMode<'a> {
+    /// A passive element segment.
+    ///
+    /// Passive segments are part of the bulk memory proposal.
+    Passive,
+    /// A declared element segment.
+    ///
+    /// Declared segments are part of the bulk memory proposal.
+    Declared,
+    /// An active element segment.
+    Active {
+        /// The table index.
+        ///
+        /// `None` is implicitly table `0`. Non-`None` tables are part of the
+        /// reference types proposal.
+        table: Option<u32>,
+        /// The offset within the table to place this segment.
+        offset: Instruction<'a>,
+    },
+}
+
+/// An element segment in the element section.
+#[derive(Clone, Copy, Debug)]
+pub struct ElementSegment<'a> {
+    /// The element segment's mode.
+    pub mode: ElementMode<'a>,
+    /// The element segment's type.
+    pub element_type: ValType,
+    /// This segment's elements.
+    pub elements: Elements<'a>,
+}
+
+impl ElementSection {
+    /// Create a new element section encoder.
+    pub fn new() -> ElementSection {
+        ElementSection {
+            bytes: vec![],
+            num_added: 0,
+        }
+    }
+
+    /// How many segments have been defined inside this section so far?
+    pub fn len(&self) -> u32 {
+        self.num_added
+    }
+
+    /// Define an element segment.
+    pub fn segment<'a>(&mut self, segment: ElementSegment<'a>) -> &mut Self {
+        let expr_bit = match segment.elements {
+            Elements::Expressions(_) => 0b100,
+            Elements::Functions(_) => 0b000,
+        };
+        match &segment.mode {
+            ElementMode::Active {
+                table: None,
+                offset,
+            } => {
+                self.bytes.extend(encoders::u32(0x00 | expr_bit));
+                offset.encode(&mut self.bytes);
+                Instruction::End.encode(&mut self.bytes);
+            }
+            ElementMode::Passive => {
+                self.bytes.extend(encoders::u32(0x01 | expr_bit));
+                if expr_bit == 0 {
+                    self.bytes.push(0x00); // elemkind == funcref
+                } else {
+                    self.bytes.push(segment.element_type.into());
+                }
+            }
+            ElementMode::Active {
+                table: Some(i),
+                offset,
+            } => {
+                self.bytes.extend(encoders::u32(0x02 | expr_bit));
+                self.bytes.extend(encoders::u32(*i));
+                offset.encode(&mut self.bytes);
+                Instruction::End.encode(&mut self.bytes);
+                if expr_bit == 0 {
+                    self.bytes.push(0x00); // elemkind == funcref
+                } else {
+                    self.bytes.push(segment.element_type.into());
+                }
+            }
+            ElementMode::Declared => {