commit 6b06723196a8d53591e3c9799f4933dced19c3a1 parent 9d9152894ee3114c73fac0682c3273b74f180dc8 Author: Yury Delendik <ydelendik@mozilla.com> Date: Thu, 18 Dec 2025 14:23:11 +0000 Bug 2003861 - Update wasm-tools to version 0.243. r=rhunt,supply-chain-reviewers,bvisness Differential Revision: https://phabricator.services.mozilla.com/D274974 Diffstat:
141 files changed, 16698 insertions(+), 8394 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock @@ -7776,9 +7776,9 @@ version = "0.2.100" [[package]] name = "wasm-encoder" -version = "0.225.0" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f7eac0445cac73bcf09e6a97f83248d64356dccf9f2b100199769b6b42464e5" +checksum = "c55db9c896d70bd9fa535ce83cd4e1f2ec3726b0edd2142079f594fc3be1cb35" dependencies = [ "leb128fmt", "wasmparser", @@ -7786,9 +7786,9 @@ dependencies = [ [[package]] name = "wasm-smith" -version = "0.225.0" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d93c23413c233bc0bd7bb14cae607b0c1b6731527fd7ad6e166b6eaa11aecd2b" +checksum = "119b7dd7690868543d344025ee894271d9c66fa00d5c1cd233a5c72eb7a2ea03" dependencies = [ "anyhow", "arbitrary", @@ -7798,9 +7798,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.225.0" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36e5456165f81e64cb9908a0fe9b9d852c2c74582aa3fe2be3c2da57f937d3ae" +checksum = "f6d8db401b0528ec316dfbe579e6ab4152d61739cfe076706d2009127970159d" dependencies = [ "bitflags 2.9.0", "indexmap", @@ -7809,9 +7809,9 @@ dependencies = [ [[package]] name = "wast" -version = "225.0.0" +version = "243.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61496027ff707f9fa9e0b22c34ec163eb7adb1070df565e32a9180a76e4300b" +checksum = "df21d01c2d91e46cb7a221d79e58a2d210ea02020d57c092e79255cc2999ca7f" dependencies = [ "bumpalo", "leb128fmt", diff --git a/js/src/fuzz-tests/gluesmith/Cargo.toml b/js/src/fuzz-tests/gluesmith/Cargo.toml @@ -6,6 +6,6 @@ authors = ["Christian Holler"] license = "MPL-2.0" [dependencies] -wasm-smith = "0.225.0" +wasm-smith = "0.243.0" arbitrary = { version = "1.0.0", features = ["derive"] } libc = "0.2" diff --git a/js/src/jit-test/etc/wasm/generate-spectests/wast2js/Cargo.toml b/js/src/jit-test/etc/wasm/generate-spectests/wast2js/Cargo.toml @@ -8,5 +8,5 @@ edition = "2018" [dependencies] anyhow = "1.0.19" -wast = "229.0.0" +wast = "243.0.0" regex = "1.11.1" diff --git a/js/src/jit-test/tests/wasm/gc/structs.js b/js/src/jit-test/tests/wasm/gc/structs.js @@ -573,7 +573,7 @@ assertErrorMessage(() => wasmEvalText(` (type $f (func (param i32) (result i32))) (func (type 0) (param i32) (result i32) (unreachable))) `), -WebAssembly.CompileError, /signature index references non-signature/); +SyntaxError, /not a function type/); // Can't set immutable fields from JS diff --git a/js/src/jit-test/tests/wasm/start.js b/js/src/jit-test/tests/wasm/start.js @@ -1,7 +1,7 @@ -assertErrorMessage(() => wasmEvalText('(module (func) (start 0) (start 0))'), SyntaxError, /wasm text error/); assertErrorMessage(() => wasmEvalText('(module (func) (start $unknown))'), SyntaxError, /failed to find/); wasmFailValidateText('(module (func) (start 1))', /unknown start function/); +wasmFailValidateText('(module (func) (start 0) (start 0))', /unknown section before code section/); wasmFailValidateText('(module (func (param i32)) (start 0))', /must be nullary/); wasmFailValidateText('(module (func (param i32) (param f32)) (start 0))', /must be nullary/); wasmFailValidateText('(module (func (param i32) (param f32) (param f64)) (start 0))', /must be nullary/); diff --git a/js/src/rust/Cargo.toml b/js/src/rust/Cargo.toml @@ -21,4 +21,4 @@ mozilla-central-workspace-hack = { version = "0.1", features = ["jsrust"], optio jsrust_shared = { path = "./shared" } # Workaround for https://github.com/rust-lang/rust/issues/58393 mozglue-static = { path = "../../../mozglue/static/rust" } -wast = "225.0.0" +wast = "243.0.0" diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml @@ -6770,6 +6770,11 @@ who = "Ryan Hunt <rhunt@eqrion.net>" criteria = "safe-to-run" delta = "0.11.7 -> 0.11.8" +[[audits.wasm-smith]] +who = "Yury Delendik <ydelendik@mozilla.com>" +criteria = "safe-to-run" +delta = "0.227.1 -> 0.243.0" + [[audits.wasmparser]] who = "Ryan Hunt <rhunt@eqrion.net>" criteria = "safe-to-deploy" diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock @@ -865,26 +865,26 @@ user-login = "alexcrichton" user-name = "Alex Crichton" [[publisher.wasm-encoder]] -version = "0.225.0" -when = "2025-02-04" +version = "0.236.0" +when = "2025-07-28" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasm-smith]] -version = "0.225.0" -when = "2025-02-04" +version = "0.227.1" +when = "2025-03-07" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasmparser]] -version = "0.225.0" -when = "2025-02-04" +version = "0.236.0" +when = "2025-07-28" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wast]] -version = "225.0.0" -when = "2025-02-04" +version = "236.0.0" +when = "2025-07-28" user-id = 73222 user-login = "wasmtime-publish" @@ -1588,6 +1588,132 @@ This crate has no unsafe code and does not use `std::*`. Skimming the crate it does not attempt to out of the bounds of what it's already supposed to be doing. """ +[[audits.bytecode-alliance.audits.wasm-encoder]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "0.236.0 -> 0.237.0" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wasm-encoder]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "0.237.0 -> 0.238.1" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wasm-encoder]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "0.238.1 -> 0.239.0" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wasm-encoder]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "0.239.0 -> 0.240.0" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wasm-encoder]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "0.240.0 -> 0.241.2" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wasm-encoder]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "0.241.2 -> 0.242.0" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wasm-encoder]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "0.242.0 -> 0.243.0" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wasmparser]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "0.236.0 -> 0.237.0" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wasmparser]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "0.237.0 -> 0.238.1" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wasmparser]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "0.238.1 -> 0.239.0" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wasmparser]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "0.239.0 -> 0.240.0" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wasmparser]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "0.240.0 -> 0.241.2" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wasmparser]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "0.241.2 -> 0.242.0" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wasmparser]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "0.242.0 -> 0.243.0" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wast]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "236.0.0 -> 237.0.0" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wast]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "237.0.0 -> 238.0.1" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wast]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "238.0.1 -> 239.0.0" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wast]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "239.0.0 -> 240.0.0" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wast]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "240.0.0 -> 241.0.2" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wast]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "241.0.2 -> 242.0.0" +notes = "The Bytecode Alliance is the author of this crate" + +[[audits.bytecode-alliance.audits.wast]] +who = "Alex Crichton <alex@alexcrichton.com>" +criteria = "safe-to-deploy" +delta = "242.0.0 -> 243.0.0" +notes = "The Bytecode Alliance is the author of this crate" + [[audits.embark-studios.wildcard-audits.presser]] who = "Gray Olson <opensource@embark-studios.com>" criteria = "safe-to-deploy" diff --git a/third_party/rust/wasm-encoder/.cargo-checksum.json b/third_party/rust/wasm-encoder/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"946a18953d4cb1dc9200b4fcb8d90643455477cf1d334ec4ac2aecbe5ed062e4","Cargo.toml":"62c7966020f84b7d38b82b6a19865ee7d63b00258c8de41e50c4bb98a6a4be7d","README.md":"058d5f387672724a53b0946ccaa0d29c0d2cfa46268c8f06d61866edc8faa3f8","build.rs":"ba7ab1735d3642c53562d1223a6eb54c2392e619ade3005e0deee3fc4229feea","src/component.rs":"992de8b4a14190f0a7d65aca8de28a37207fadb31a55e90e4e1bc4565eb38e08","src/component/aliases.rs":"0e54c4f7eedf7b9fa5230cfdb7699ead19209089b43be97339e877eca047d3ce","src/component/builder.rs":"3a389afbc2cf5b2d7bf2d2488849408a58f92aae5a4f4e1488f89a044950a2ab","src/component/canonicals.rs":"a19f377b01a7fa450d4bb4081388f36a8aede9bde85f63b38a0009b8af4cd2c7","src/component/components.rs":"8f21463b58cf06246085a055c363c4aca58a896e6b3cf2e4bc9ee4198b31fa8f","src/component/exports.rs":"e1a99b16385e0e398379a886dd74318d05ed22ffaa5d6cd22887abd590862435","src/component/imports.rs":"ae34b0906eae37324a85fbf907c543a67bd2f57e0aaa3dc06ccb3297c9bcf5f9","src/component/instances.rs":"050d7ad89885ef30cb3f042d634af71ac56a71c82f7ceed725d2f0ebc3ff0c8d","src/component/modules.rs":"2b5aa5add7b0e0c3f792cd48a2e7e5f9b145bd7330f7b4ba8b3f3af2205e4f9b","src/component/names.rs":"8d77710315dbbc5f95e75139e1098f38ee6836b929dbbd3cde7b3048f6c7f3cc","src/component/start.rs":"adcb7a8ec26f7a29caf474c2657ea7bfa40e53cccfe517e91b804e4bee7a8089","src/component/types.rs":"e4f8e3cf91500d6fe00c396f48be70e7d0f0b49879ca968b1814b49628b30bc7","src/core.rs":"a6a6ab4cc72ca3cb0c0f9e9580e65e6e3dcf7bd39ef8ebb13cb2e269408e4c6d","src/core/branch_hints.rs":"e329f13763a2ac2937a9a37e18a3018643d0c1c836e0c18f9e7466ea254eb9c8","src/core/code.rs":"f4e626500b3d1e21fc48d46048bf2c40e652fd30dd8be4d24982b228d0fbcad2","src/core/custom.rs":"2124e2fa0dc4598a21c45317f3047646bd8bb87374f03ba274f04128fa8cef13","src/core/data.rs":"38f852fc26341985598587808882b59e72e20cb4f411b63dd9dae8b428a1f4e9","src/core/dump.rs":"89cbf1e154f51fdc3ceed5df99d2fa7d9f3c7845730e235f8b0dfa1730e5b407","src/core/elements.rs":"d7020b03c2b130927433845cfbd08d85878f92c7847336625622667b65957fd8","src/core/exports.rs":"f307c5e72005eab08efcd34ed8b545c0a743fb6520765968bd832e124857b5a0","src/core/functions.rs":"9cc4e80efcfbc337abc42038e6e4fa8bb11fe8f3df0544826cb9ecb71458e294","src/core/globals.rs":"f99abf631af67fb04d8becfeba7f34860c62a38d63a0a0aaa3b2c3a4a4c54241","src/core/imports.rs":"6b94e76df1e7119317d53a55c2e4c09461e94880769a613b0706b14bcc61ea46","src/core/linking.rs":"f83cda8f2926735be1e5c28409afe442bc1af94c24ddea2d6449712511afa391","src/core/memories.rs":"d97dd645d5ce78ebeb4ca1763fb77c53a711ee2b598e699e372837af15e21475","src/core/names.rs":"28e43120452f82ab574038c5f8e57ef9bb3ab82b5b8147f99ccd84cda0436372","src/core/producers.rs":"4ce134f6eed15eb319df777c7e2f9ed5a5e5868c32a84bf8229110aceaf6f80b","src/core/start.rs":"90662bb2af6f9e2319f617274651223e272c5886c12d20c7e04f771dd2af8c00","src/core/tables.rs":"a0d972947ec974bb810d140552feebcf6eed8e5aa03b8044ff51535469d2ee00","src/core/tags.rs":"12822611a3948ef14504f1c24031daacbd38e8afd307fdd4793dc98ed20dfb9b","src/core/types.rs":"b979568e0fdffd2d9da2965efce875e043c306721e6f51edd8affc77580aea90","src/lib.rs":"a80bd8827d5de029f13d9f901a26fc4d170b404507ab070983217575a1f48c13","src/raw.rs":"5813a426bcef495f89c4744e0cca1fe20db3150998ce591d7b3c01dc30ca9e13","src/reencode.rs":"3ed3d9b649431deb47ceca78599d2751a67790a5976ba7632d1b02a2e1edc33a","src/reencode/component.rs":"bee122522360e6390e70bfa2eefc4cbcaf9b0068185bb67e89983afd0f1aade3"},"package":"6f7eac0445cac73bcf09e6a97f83248d64356dccf9f2b100199769b6b42464e5"} -\ No newline at end of file +{"files":{"Cargo.lock":"ba58e13d8798305b6e5f4ca9e258eedcec9e40572bc43f11e076cc83d7973b16","Cargo.toml":"512619513f803eb4fa47303f73c29a17b5034d56537a3cb25beb419280573d38","README.md":"c65cc523cd46516311fca22c82284fa0979a4638aa1cb7a02268856f43a017a8","build.rs":"ba7ab1735d3642c53562d1223a6eb54c2392e619ade3005e0deee3fc4229feea","src/component.rs":"992de8b4a14190f0a7d65aca8de28a37207fadb31a55e90e4e1bc4565eb38e08","src/component/aliases.rs":"686100ebe50004fecfc0d99467bea4ea28a222d683eb1b746653fd334dbac92e","src/component/builder.rs":"5fe26e9d06817de0399c5862199471a74ca759f27c2d00c2ec087f56e2830fc9","src/component/canonicals.rs":"3c18cd07d13e73f6027241563786deee8829f39fa8109ae7025ea097357a467c","src/component/components.rs":"8f21463b58cf06246085a055c363c4aca58a896e6b3cf2e4bc9ee4198b31fa8f","src/component/exports.rs":"de627907c12170a0f54e3ef9907a5d852ccff597f6a0bd6efe625714c2be09a6","src/component/imports.rs":"c6aac83b734faa352ab9b1cd6ce6f4f7e3ee66cdb545892f74eff8f4d4d9e401","src/component/instances.rs":"a88158647c3563f5a59e3797c493549622f737cd4b28f34bdd055afebe22f9ad","src/component/modules.rs":"2b5aa5add7b0e0c3f792cd48a2e7e5f9b145bd7330f7b4ba8b3f3af2205e4f9b","src/component/names.rs":"3ae30371d6434730b3e7fe62bc0401c6ea4770d29194dfd2d03751ce02038f14","src/component/start.rs":"adcb7a8ec26f7a29caf474c2657ea7bfa40e53cccfe517e91b804e4bee7a8089","src/component/types.rs":"5d6c75477535de35edbd6ca3e30d20ed30403293f3263016aad7c1db97cd0486","src/core.rs":"f160cb63ebfc932b754ac1b053af9979911f27837b31e2983635a60a9eb8db2c","src/core/branch_hints.rs":"cf897a5e852e7d54456bad08fa4b0cfb4ce22d3ffd81bea966d3babe1ead0d1b","src/core/code.rs":"7b16e463a9c99341f924276ec6d3454f7088188757018e4a7988c50e8ca6a8b8","src/core/custom.rs":"0b890bf723b1c36666a91c81dcc038d97accd3a144ebb376f8fccafbd9245390","src/core/data.rs":"daddfd16fc4d48a1e7e30a45692beb35605b5e7dfc5cc6a0cf8a3c4af6186f4b","src/core/dump.rs":"bb1c9eb1a30ff30124c96a3b30aa6aaf84e35c52d22fc69395313cf234d7ae78","src/core/elements.rs":"af86d9753c7b6a99ee6f8fa14d6c30e8d70d4c66ea8c767571409b9f17281b6c","src/core/exports.rs":"0192d49fe212a49c49c7f30f7e33d05223ce86e36a12f5eccbc9559e56613f46","src/core/functions.rs":"b709633764dab1da900afe888f63a246fe86951314ab61c676d5c62c4eebe38f","src/core/globals.rs":"52096365d4985be9fd7f296ea423933529b43028179d923eb8dfe3cd96ae9a87","src/core/imports.rs":"65a47b4f0ee9a105a741c1a6397c78c41802c2542a9413dfa4e6ab1c409f84f0","src/core/instructions.rs":"b655917ce6afe6186ad93749fb4e62ffc39a6eebf9daaab59c90a10523c397b8","src/core/linking.rs":"ef62831b6464f66cc6fdb2cf4f104bb61d734b51deac0c00dedf259b9b9f4ac0","src/core/memories.rs":"a6652a5948d11722790401910a3fb6e551246401e9f636447c7a98a3cce1df63","src/core/names.rs":"8815d22178379712e472d6446e9b7b06e0adc91aed6282d91b7a6b814172202f","src/core/producers.rs":"4ce134f6eed15eb319df777c7e2f9ed5a5e5868c32a84bf8229110aceaf6f80b","src/core/start.rs":"58968f4ddfc2b3ded079838df394d450075a261eb76f43c0c54ac15e33e7fe21","src/core/tables.rs":"5d3524f539cb03f555485dc4da7b44bf61aeb19d9b15fcb96d365d01266e2b3e","src/core/tags.rs":"29d18182f4ed035b2f2f0a2390ff0c2d51e434250cbcff062a3cf8b40c27ba13","src/core/types.rs":"fc4ecc8a10f0e1d45c4184d2bd0316db60afbccf02874e931126866f4ef3f62a","src/lib.rs":"71a1f77f892a29fb5fbf7fad48415b76cad0c4c9b815de234f797ed2555a43fb","src/raw.rs":"5813a426bcef495f89c4744e0cca1fe20db3150998ce591d7b3c01dc30ca9e13","src/reencode.rs":"d1a97ef4758fe58a1d798c18895ede5d8fb74c58461b0b64846a60dd86a1fb8b","src/reencode/component.rs":"824114c8c805da5e67a184aed233461d20823dd435d1932a2cc8aaf287dccc0a"},"package":"c55db9c896d70bd9fa535ce83cd4e1f2ec3726b0edd2142079f594fc3be1cb35"} +\ No newline at end of file diff --git a/third_party/rust/wasm-encoder/Cargo.lock b/third_party/rust/wasm-encoder/Cargo.lock @@ -4,55 +4,67 @@ version = 3 [[package]] name = "anyhow" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] name = "fastrand" -version = "2.1.1" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "getrandom" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi", +] [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" [[package]] name = "indexmap" -version = "2.7.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", "hashbrown", @@ -66,49 +78,55 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rustix" -version = "0.38.37" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "semver" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "tempfile" -version = "3.13.0" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ - "cfg-if", "fastrand", + "getrandom", "once_cell", "rustix", "windows-sys 0.59.0", @@ -124,8 +142,17 @@ dependencies = [ ] [[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] name = "wasm-encoder" -version = "0.225.0" +version = "0.243.0" dependencies = [ "anyhow", "leb128fmt", @@ -136,9 +163,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.225.0" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36e5456165f81e64cb9908a0fe9b9d852c2c74582aa3fe2be3c2da57f937d3ae" +checksum = "f6d8db401b0528ec316dfbe579e6ab4152d61739cfe076706d2009127970159d" dependencies = [ "bitflags", "indexmap", @@ -147,9 +174,9 @@ dependencies = [ [[package]] name = "wasmprinter" -version = "0.225.0" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c32de8f41929f40bb595d1309549c58bbe1b43b05627fe42517e23a50230e0a" +checksum = "eb2b6035559e146114c29a909a3232928ee488d6507a1504d8934e8607b36d7b" dependencies = [ "anyhow", "termcolor", @@ -167,20 +194,20 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.52.0" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets", + "windows-targets 0.53.2", ] [[package]] @@ -189,14 +216,30 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] @@ -206,43 +249,100 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] diff --git a/third_party/rust/wasm-encoder/Cargo.toml b/third_party/rust/wasm-encoder/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.76.0" name = "wasm-encoder" -version = "0.225.0" +version = "0.243.0" authors = ["Nick Fitzgerald <fitzgen@gmail.com>"] build = "build.rs" autolib = false @@ -33,6 +33,14 @@ repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wa [package.metadata.docs.rs] all-features = true +[features] +component-model = ["wasmparser?/component-model"] +default = [ + "std", + "component-model", +] +std = ["wasmparser?/std"] + [lib] name = "wasm_encoder" path = "src/lib.rs" @@ -42,7 +50,7 @@ version = "0.1.0" default-features = false [dependencies.wasmparser] -version = "0.225.0" +version = "0.243.0" features = [ "simd", "simd", @@ -57,21 +65,18 @@ version = "1.0.58" version = "3.2.0" [dev-dependencies.wasmprinter] -version = "0.225.0" +version = "0.243.0" default-features = false -[features] -component-model = ["wasmparser?/component-model"] -default = [ - "std", - "component-model", -] -std = ["wasmparser?/std"] - [lints.clippy] +allow_attributes_without_reason = "warn" clone_on_copy = "warn" manual_strip = "warn" map_clone = "warn" +uninlined_format_args = "warn" +unnecessary_cast = "warn" +unnecessary_fallible_conversions = "warn" +unnecessary_mut_passed = "warn" unnecessary_to_owned = "warn" [lints.clippy.all] @@ -79,4 +84,22 @@ level = "allow" priority = -1 [lints.rust] +deprecated-safe-2024 = "warn" +keyword_idents_2024 = "warn" +missing-unsafe-on-extern = "warn" +rust-2024-guarded-string-incompatible-syntax = "warn" +rust-2024-incompatible-pat = "warn" +rust-2024-prelude-collisions = "warn" +unsafe-attr-outside-unsafe = "warn" +unsafe-op-in-unsafe-fn = "warn" unsafe_code = "deny" +unstable_features = "warn" +unused-lifetimes = "warn" +unused-macro-rules = "warn" +unused_extern_crates = "warn" +unused_import_braces = "warn" + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = ["cfg(fuzzing)"] diff --git a/third_party/rust/wasm-encoder/README.md b/third_party/rust/wasm-encoder/README.md @@ -26,7 +26,7 @@ And then you can encode WebAssembly binaries via: ```rust use wasm_encoder::{ - CodeSection, ExportKind, ExportSection, Function, FunctionSection, Instruction, + CodeSection, ExportKind, ExportSection, Function, FunctionSection, Module, TypeSection, ValType, }; @@ -54,10 +54,11 @@ module.section(&exports); 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); +f.instructions() + .local_get(0) + .local_get(1) + .i32_add() + .end(); codes.function(&f); module.section(&codes); diff --git a/third_party/rust/wasm-encoder/src/component/aliases.rs b/third_party/rust/wasm-encoder/src/component/aliases.rs @@ -1,6 +1,6 @@ use super::{COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, CORE_TYPE_SORT, TYPE_SORT}; use crate::{ - encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind, + ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind, encode_section, }; use alloc::vec::Vec; diff --git a/third_party/rust/wasm-encoder/src/component/builder.rs b/third_party/rust/wasm-encoder/src/component/builder.rs @@ -1,5 +1,6 @@ use crate::component::*; -use crate::{ExportKind, Module, RawSection, ValType}; +use crate::{ExportKind, Module, NameMap, RawSection, ValType}; +use alloc::format; use alloc::vec::Vec; use core::mem; @@ -24,87 +25,134 @@ pub struct ComponentBuilder { last_section: LastSection, // Core index spaces - core_modules: u32, - core_funcs: u32, - core_types: u32, - core_memories: u32, - core_tables: u32, - core_instances: u32, - core_tags: u32, - core_globals: u32, + core_modules: Namespace, + core_funcs: Namespace, + core_types: Namespace, + core_memories: Namespace, + core_tables: Namespace, + core_instances: Namespace, + core_tags: Namespace, + core_globals: Namespace, // Component index spaces - funcs: u32, - instances: u32, - types: u32, - components: u32, - values: u32, + funcs: Namespace, + instances: Namespace, + types: Namespace, + components: Namespace, + values: Namespace, } impl ComponentBuilder { /// Returns the current number of core modules. pub fn core_module_count(&self) -> u32 { - self.core_modules + self.core_modules.count } /// Returns the current number of core funcs. pub fn core_func_count(&self) -> u32 { - self.core_funcs + self.core_funcs.count } /// Returns the current number of core types. pub fn core_type_count(&self) -> u32 { - self.core_types + self.core_types.count } /// Returns the current number of core memories. pub fn core_memory_count(&self) -> u32 { - self.core_memories + self.core_memories.count } /// Returns the current number of core tables. pub fn core_table_count(&self) -> u32 { - self.core_tables + self.core_tables.count } /// Returns the current number of core instances. pub fn core_instance_count(&self) -> u32 { - self.core_instances + self.core_instances.count } /// Returns the current number of core tags. pub fn core_tag_count(&self) -> u32 { - self.core_tags + self.core_tags.count } /// Returns the current number of core globals. pub fn core_global_count(&self) -> u32 { - self.core_globals + self.core_globals.count } /// Returns the current number of component funcs. pub fn func_count(&self) -> u32 { - self.funcs + self.funcs.count } /// Returns the current number of component instances. pub fn instance_count(&self) -> u32 { - self.instances + self.instances.count } /// Returns the current number of component values. pub fn value_count(&self) -> u32 { - self.values + self.values.count } /// Returns the current number of components. pub fn component_count(&self) -> u32 { - self.components + self.components.count } /// Returns the current number of component types. pub fn type_count(&self) -> u32 { - self.types + self.types.count + } + + /// Add all debug names registered to the component. + pub fn append_names(&mut self) { + let mut names = ComponentNameSection::new(); + if !self.core_funcs.names.is_empty() { + names.core_funcs(&self.core_funcs.names); + } + if !self.core_tables.names.is_empty() { + names.core_tables(&self.core_tables.names); + } + if !self.core_memories.names.is_empty() { + names.core_memories(&self.core_memories.names); + } + if !self.core_globals.names.is_empty() { + names.core_globals(&self.core_globals.names); + } + if !self.core_tags.names.is_empty() { + names.core_tags(&self.core_tags.names); + } + if !self.core_types.names.is_empty() { + names.core_types(&self.core_types.names); + } + if !self.core_modules.names.is_empty() { + names.core_modules(&self.core_modules.names); + } + if !self.core_instances.names.is_empty() { + names.core_instances(&self.core_instances.names); + } + if !self.instances.names.is_empty() { + names.instances(&self.instances.names); + } + if !self.funcs.names.is_empty() { + names.funcs(&self.funcs.names); + } + if !self.types.names.is_empty() { + names.types(&self.types.names); + } + if !self.components.names.is_empty() { + names.components(&self.components.names); + } + if !self.instances.names.is_empty() { + names.instances(&self.instances.names); + } + if !names.is_empty() { + self.custom_section(&names.as_custom()); + } } /// Completes this component and returns the binary encoding of the entire @@ -115,81 +163,95 @@ impl ComponentBuilder { } /// Encodes a core wasm `Module` into this component, returning its index. - pub fn core_module(&mut self, module: &Module) -> u32 { + pub fn core_module(&mut self, debug_name: Option<&str>, module: &Module) -> u32 { self.flush(); self.component.section(&ModuleSection(module)); - inc(&mut self.core_modules) + self.core_modules.add(debug_name) } /// Encodes a core wasm `module` into this component, returning its index. - pub fn core_module_raw(&mut self, module: &[u8]) -> u32 { + pub fn core_module_raw(&mut self, debug_name: Option<&str>, module: &[u8]) -> u32 { self.flush(); self.component.section(&RawSection { id: ComponentSectionId::CoreModule.into(), data: module, }); - inc(&mut self.core_modules) + self.core_modules.add(debug_name) } /// Instantiates a core wasm module at `module_index` with the `args` /// provided. /// - /// Returns the index of the core wasm instance crated. - pub fn core_instantiate<'a, A>(&mut self, module_index: u32, args: A) -> u32 + /// Returns the index of the core wasm instance created. + pub fn core_instantiate<'a, A>( + &mut self, + debug_name: Option<&str>, + module_index: u32, + args: A, + ) -> u32 where A: IntoIterator<Item = (&'a str, ModuleArg)>, A::IntoIter: ExactSizeIterator, { self.instances().instantiate(module_index, args); - inc(&mut self.core_instances) + self.core_instances.add(debug_name) } /// Creates a new core wasm instance from the `exports` provided. /// - /// Returns the index of the core wasm instance crated. - pub fn core_instantiate_exports<'a, E>(&mut self, exports: E) -> u32 + /// Returns the index of the core wasm instance created. + pub fn core_instantiate_exports<'a, E>(&mut self, debug_name: Option<&str>, exports: E) -> u32 where E: IntoIterator<Item = (&'a str, ExportKind, u32)>, E::IntoIter: ExactSizeIterator, { self.instances().export_items(exports); - inc(&mut self.core_instances) + self.core_instances.add(debug_name) } /// Creates a new aliased item where the core `instance` specified has its /// export `name` aliased out with the `kind` specified. /// - /// Returns the index of the item crated. - pub fn core_alias_export(&mut self, instance: u32, name: &str, kind: ExportKind) -> u32 { - self.alias(Alias::CoreInstanceExport { - instance, - kind, - name, - }) + /// Returns the index of the item created. + pub fn core_alias_export( + &mut self, + debug_name: Option<&str>, + instance: u32, + name: &str, + kind: ExportKind, + ) -> u32 { + self.alias( + debug_name, + Alias::CoreInstanceExport { + instance, + kind, + name, + }, + ) } /// Adds a new alias to this component - pub fn alias(&mut self, alias: Alias<'_>) -> u32 { + pub fn alias(&mut self, debug_name: Option<&str>, alias: Alias<'_>) -> u32 { self.aliases().alias(alias); match alias { - Alias::InstanceExport { kind, .. } => self.inc_kind(kind), - Alias::CoreInstanceExport { kind, .. } => self.inc_core_kind(kind), + Alias::InstanceExport { kind, .. } => self.inc_kind(debug_name, kind), + Alias::CoreInstanceExport { kind, .. } => self.inc_core_kind(debug_name, kind), Alias::Outer { kind: ComponentOuterAliasKind::Type, .. - } => inc(&mut self.types), + } => self.types.add(debug_name), Alias::Outer { kind: ComponentOuterAliasKind::CoreModule, .. - } => inc(&mut self.core_modules), + } => self.core_modules.add(debug_name), Alias::Outer { kind: ComponentOuterAliasKind::Component, .. - } => inc(&mut self.components), + } => self.components.add(debug_name), Alias::Outer { kind: ComponentOuterAliasKind::CoreType, .. - } => inc(&mut self.core_types), + } => self.core_types.add(debug_name), } } @@ -200,31 +262,34 @@ impl ComponentBuilder { /// /// Returns the index of the new item defined. pub fn alias_export(&mut self, instance: u32, name: &str, kind: ComponentExportKind) -> u32 { - self.alias(Alias::InstanceExport { - instance, - kind, - name, - }) + self.alias( + Some(name), + Alias::InstanceExport { + instance, + kind, + name, + }, + ) } - fn inc_kind(&mut self, kind: ComponentExportKind) -> u32 { + fn inc_kind(&mut self, debug_name: Option<&str>, kind: ComponentExportKind) -> u32 { match kind { - ComponentExportKind::Func => inc(&mut self.funcs), - ComponentExportKind::Module => inc(&mut self.core_modules), - ComponentExportKind::Type => inc(&mut self.types), - ComponentExportKind::Component => inc(&mut self.components), - ComponentExportKind::Instance => inc(&mut self.instances), - ComponentExportKind::Value => inc(&mut self.values), + ComponentExportKind::Func => self.funcs.add(debug_name), + ComponentExportKind::Module => self.core_modules.add(debug_name), + ComponentExportKind::Type => self.types.add(debug_name), + ComponentExportKind::Component => self.components.add(debug_name), + ComponentExportKind::Instance => self.instances.add(debug_name), + ComponentExportKind::Value => self.values.add(debug_name), } } - fn inc_core_kind(&mut self, kind: ExportKind) -> u32 { + fn inc_core_kind(&mut self, debug_name: Option<&str>, kind: ExportKind) -> u32 { match kind { - ExportKind::Func => inc(&mut self.core_funcs), - ExportKind::Table => inc(&mut self.core_tables), - ExportKind::Memory => inc(&mut self.core_memories), - ExportKind::Global => inc(&mut self.core_globals), - ExportKind::Tag => inc(&mut self.core_tags), + ExportKind::Func => self.core_funcs.add(debug_name), + ExportKind::Table => self.core_tables.add(debug_name), + ExportKind::Memory => self.core_memories.add(debug_name), + ExportKind::Global => self.core_globals.add(debug_name), + ExportKind::Tag => self.core_tags.add(debug_name), } } @@ -232,38 +297,44 @@ impl ComponentBuilder { /// using the `options` provided. /// /// Returns the index of the core wasm function created. - pub fn lower_func<O>(&mut self, func_index: u32, options: O) -> u32 + pub fn lower_func<O>(&mut self, debug_name: Option<&str>, func_index: u32, options: O) -> u32 where O: IntoIterator<Item = CanonicalOption>, O::IntoIter: ExactSizeIterator, { self.canonical_functions().lower(func_index, options); - inc(&mut self.core_funcs) + self.core_funcs.add(debug_name) } /// Lifts the core wasm `core_func_index` function with the component /// function type `type_index` and `options`. /// /// Returns the index of the component function created. - pub fn lift_func<O>(&mut self, core_func_index: u32, type_index: u32, options: O) -> u32 + pub fn lift_func<O>( + &mut self, + debug_name: Option<&str>, + core_func_index: u32, + type_index: u32, + options: O, + ) -> u32 where O: IntoIterator<Item = CanonicalOption>, O::IntoIter: ExactSizeIterator, { self.canonical_functions() .lift(core_func_index, type_index, options); - inc(&mut self.funcs) + self.funcs.add(debug_name) } /// Imports a new item into this component with the `name` and `ty` specified. pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> u32 { let ret = match &ty { - ComponentTypeRef::Instance(_) => inc(&mut self.instances), - ComponentTypeRef::Func(_) => inc(&mut self.funcs), - ComponentTypeRef::Type(..) => inc(&mut self.types), - ComponentTypeRef::Component(_) => inc(&mut self.components), - ComponentTypeRef::Module(_) => inc(&mut self.core_modules), - ComponentTypeRef::Value(_) => inc(&mut self.values), + ComponentTypeRef::Instance(_) => self.instances.add(Some(name)), + ComponentTypeRef::Func(_) => self.funcs.add(Some(name)), + ComponentTypeRef::Type(..) => self.types.add(Some(name)), + ComponentTypeRef::Component(_) => self.components.add(Some(name)), + ComponentTypeRef::Module(_) => self.core_modules.add(Some(name)), + ComponentTypeRef::Value(_) => self.values.add(Some(name)), }; self.imports().import(name, ty); ret @@ -282,69 +353,85 @@ impl ComponentBuilder { ty: Option<ComponentTypeRef>, ) -> u32 { self.exports().export(name, kind, idx, ty); - self.inc_kind(kind) + self.inc_kind(Some(name), kind) } /// Creates a new encoder for the next core type in this component. - pub fn core_type(&mut self) -> (u32, ComponentCoreTypeEncoder<'_>) { - (inc(&mut self.core_types), self.core_types().ty()) + pub fn core_type(&mut self, debug_name: Option<&str>) -> (u32, ComponentCoreTypeEncoder<'_>) { + (self.core_types.add(debug_name), self.core_types().ty()) } /// Creates a new encoder for the next type in this component. - pub fn ty(&mut self) -> (u32, ComponentTypeEncoder<'_>) { - (inc(&mut self.types), self.types().ty()) + pub fn ty(&mut self, debug_name: Option<&str>) -> (u32, ComponentTypeEncoder<'_>) { + (self.types.add(debug_name), self.types().ty()) } /// Creates a new instance type within this component. - pub fn type_instance(&mut self, ty: &InstanceType) -> u32 { + pub fn type_instance(&mut self, debug_name: Option<&str>, ty: &InstanceType) -> u32 { self.types().instance(ty); - inc(&mut self.types) + self.types.add(debug_name) } /// Creates a new component type within this component. - pub fn type_component(&mut self, ty: &ComponentType) -> u32 { + pub fn type_component(&mut self, debug_name: Option<&str>, ty: &ComponentType) -> u32 { self.types().component(ty); - inc(&mut self.types) + self.types.add(debug_name) } /// Creates a new defined component type within this component. - pub fn type_defined(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) { - (inc(&mut self.types), self.types().defined_type()) + pub fn type_defined( + &mut self, + debug_name: Option<&str>, + ) -> (u32, ComponentDefinedTypeEncoder<'_>) { + (self.types.add(debug_name), self.types().defined_type()) } /// Creates a new component function type within this component. - pub fn type_function(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) { - (inc(&mut self.types), self.types().function()) + pub fn type_function( + &mut self, + debug_name: Option<&str>, + ) -> (u32, ComponentFuncTypeEncoder<'_>) { + (self.types.add(debug_name), self.types().function()) } /// Declares a new resource type within this component. - pub fn type_resource(&mut self, rep: ValType, dtor: Option<u32>) -> u32 { + pub fn type_resource( + &mut self, + debug_name: Option<&str>, + rep: ValType, + dtor: Option<u32>, + ) -> u32 { self.types().resource(rep, dtor); - inc(&mut self.types) + self.types.add(debug_name) } /// Defines a new subcomponent of this component. - pub fn component(&mut self, mut builder: ComponentBuilder) -> u32 { + pub fn component(&mut self, debug_name: Option<&str>, mut builder: ComponentBuilder) -> u32 { builder.flush(); self.flush(); self.component .section(&NestedComponentSection(&builder.component)); - inc(&mut self.components) + self.components.add(debug_name) } /// Defines a new subcomponent of this component. - pub fn component_raw(&mut self, data: &[u8]) -> u32 { + pub fn component_raw(&mut self, debug_name: Option<&str>, data: &[u8]) -> u32 { let raw_section = RawSection { id: ComponentSectionId::Component.into(), data, }; self.flush(); self.component.section(&raw_section); - inc(&mut self.components) + self.components.add(debug_name) } /// Instantiates the `component_index` specified with the `args` specified. - pub fn instantiate<A, S>(&mut self, component_index: u32, args: A) -> u32 + pub fn instantiate<A, S>( + &mut self, + debug_name: Option<&str>, + component_index: u32, + args: A, + ) -> u32 where A: IntoIterator<Item = (S, ComponentExportKind, u32)>, A::IntoIter: ExactSizeIterator, @@ -352,79 +439,113 @@ impl ComponentBuilder { { self.component_instances() .instantiate(component_index, args); - inc(&mut self.instances) + self.instances.add(debug_name) } /// Declares a new `resource.drop` intrinsic. pub fn resource_drop(&mut self, ty: u32) -> u32 { self.canonical_functions().resource_drop(ty); - inc(&mut self.core_funcs) + self.core_funcs.add(Some("resource.drop")) + } + + /// Declares a new `resource.drop` intrinsic. + pub fn resource_drop_async(&mut self, ty: u32) -> u32 { + self.canonical_functions().resource_drop_async(ty); + self.core_funcs.add(Some("resource.drop async")) } /// Declares a new `resource.new` intrinsic. pub fn resource_new(&mut self, ty: u32) -> u32 { self.canonical_functions().resource_new(ty); - inc(&mut self.core_funcs) + self.core_funcs.add(Some("resource.new")) } /// Declares a new `resource.rep` intrinsic. pub fn resource_rep(&mut self, ty: u32) -> u32 { self.canonical_functions().resource_rep(ty); - inc(&mut self.core_funcs) + self.core_funcs.add(Some("resource.rep")) } - /// Declares a new `thread.spawn` intrinsic. - pub fn thread_spawn(&mut self, ty: u32) -> u32 { - self.canonical_functions().thread_spawn(ty); - inc(&mut self.core_funcs) + /// Declares a new `thread.spawn_ref` intrinsic. + pub fn thread_spawn_ref(&mut self, ty: u32) -> u32 { + self.canonical_functions().thread_spawn_ref(ty); + self.core_funcs.add(Some("thread.spawn-ref")) } - /// Declares a new `thread.hw_concurrency` intrinsic. - pub fn thread_hw_concurrency(&mut self) -> u32 { - self.canonical_functions().thread_hw_concurrency(); - inc(&mut self.core_funcs) + /// Declares a new `thread.available_parallelism` intrinsic. + pub fn thread_available_parallelism(&mut self) -> u32 { + self.canonical_functions().thread_available_parallelism(); + self.core_funcs.add(Some("thread.available-parallelism")) } - /// Declares a new `task.backpressure` intrinsic. - pub fn task_backpressure(&mut self) -> u32 { - self.canonical_functions().task_backpressure(); - inc(&mut self.core_funcs) + /// Declares a new `backpressure.set` intrinsic. + pub fn backpressure_set(&mut self) -> u32 { + self.canonical_functions().backpressure_set(); + self.core_funcs.add(Some("backpressure.set")) + } + + /// Declares a new `backpressure.inc` intrinsic. + pub fn backpressure_inc(&mut self) -> u32 { + self.canonical_functions().backpressure_inc(); + self.core_funcs.add(Some("backpressure.inc")) + } + + /// Declares a new `backpressure.dec` intrinsic. + pub fn backpressure_dec(&mut self) -> u32 { + self.canonical_functions().backpressure_dec(); + self.core_funcs.add(Some("backpressure.dec")) } /// Declares a new `task.return` intrinsic. - pub fn task_return(&mut self, ty: Option<impl Into<ComponentValType>>) -> u32 { - self.canonical_functions().task_return(ty); - inc(&mut self.core_funcs) + pub fn task_return<O>(&mut self, ty: Option<ComponentValType>, options: O) -> u32 + where + O: IntoIterator<Item = CanonicalOption>, + O::IntoIter: ExactSizeIterator, + { + self.canonical_functions().task_return(ty, options); + self.core_funcs.add(Some("task.return")) + } + + /// Declares a new `task.cancel` intrinsic. + pub fn task_cancel(&mut self) -> u32 { + self.canonical_functions().task_cancel(); + self.core_funcs.add(Some("task.cancel")) } - /// Declares a new `task.wait` intrinsic. - pub fn task_wait(&mut self, async_: bool, memory: u32) -> u32 { - self.canonical_functions().task_wait(async_, memory); - inc(&mut self.core_funcs) + /// Declares a new `context.get` intrinsic. + pub fn context_get(&mut self, i: u32) -> u32 { + self.canonical_functions().context_get(i); + self.core_funcs.add(Some(&format!("context.get {i}"))) } - /// Declares a new `task.poll` intrinsic. - pub fn task_poll(&mut self, async_: bool, memory: u32) -> u32 { - self.canonical_functions().task_poll(async_, memory); - inc(&mut self.core_funcs) + /// Declares a new `context.set` intrinsic. + pub fn context_set(&mut self, i: u32) -> u32 { + self.canonical_functions().context_set(i); + self.core_funcs.add(Some(&format!("context.set {i}"))) } - /// Declares a new `task.yield` intrinsic. - pub fn task_yield(&mut self, async_: bool) -> u32 { - self.canonical_functions().task_yield(async_); - inc(&mut self.core_funcs) + /// Declares a new `thread.yield` intrinsic. + pub fn thread_yield(&mut self, cancellable: bool) -> u32 { + self.canonical_functions().thread_yield(cancellable); + self.core_funcs.add(Some("thread.yield")) } /// Declares a new `subtask.drop` intrinsic. pub fn subtask_drop(&mut self) -> u32 { self.canonical_functions().subtask_drop(); - inc(&mut self.core_funcs) + self.core_funcs.add(Some("subtask.drop")) + } + + /// Declares a new `subtask.cancel` intrinsic. + pub fn subtask_cancel(&mut self, async_: bool) -> u32 { + self.canonical_functions().subtask_cancel(async_); + self.core_funcs.add(Some("subtask.cancel")) } /// Declares a new `stream.new` intrinsic. pub fn stream_new(&mut self, ty: u32) -> u32 { self.canonical_functions().stream_new(ty); - inc(&mut self.core_funcs) + self.core_funcs.add(Some("stream.new")) } /// Declares a new `stream.read` intrinsic. @@ -434,7 +555,7 @@ impl ComponentBuilder { O::IntoIter: ExactSizeIterator, { self.canonical_functions().stream_read(ty, options); - inc(&mut self.core_funcs) + self.core_funcs.add(Some("stream.read")) } /// Declares a new `stream.write` intrinsic. @@ -444,37 +565,37 @@ impl ComponentBuilder { O::IntoIter: ExactSizeIterator, { self.canonical_functions().stream_write(ty, options); - inc(&mut self.core_funcs) + self.core_funcs.add(Some("stream.write")) } /// Declares a new `stream.cancel-read` intrinsic. pub fn stream_cancel_read(&mut self, ty: u32, async_: bool) -> u32 { self.canonical_functions().stream_cancel_read(ty, async_); - inc(&mut self.core_funcs) + self.core_funcs.add(Some("stream.cancel-read")) } /// Declares a new `stream.cancel-write` intrinsic. pub fn stream_cancel_write(&mut self, ty: u32, async_: bool) -> u32 { self.canonical_functions().stream_cancel_write(ty, async_); - inc(&mut self.core_funcs) + self.core_funcs.add(Some("stream.cancel-write")) } - /// Declares a new `stream.close-readable` intrinsic. - pub fn stream_close_readable(&mut self, ty: u32) -> u32 { - self.canonical_functions().stream_close_readable(ty); - inc(&mut self.core_funcs) + /// Declares a new `stream.drop-readable` intrinsic. + pub fn stream_drop_readable(&mut self, ty: u32) -> u32 { + self.canonical_functions().stream_drop_readable(ty); + self.core_funcs.add(Some("stream.drop-readable")) } - /// Declares a new `stream.close-writable` intrinsic. - pub fn stream_close_writable(&mut self, ty: u32) -> u32 { - self.canonical_functions().stream_close_writable(ty); - inc(&mut self.core_funcs) + /// Declares a new `stream.drop-writable` intrinsic. + pub fn stream_drop_writable(&mut self, ty: u32) -> u32 { + self.canonical_functions().stream_drop_writable(ty); + self.core_funcs.add(Some("stream.drop-writable")) } /// Declares a new `future.new` intrinsic. pub fn future_new(&mut self, ty: u32) -> u32 { self.canonical_functions().future_new(ty); - inc(&mut self.core_funcs) + self.core_funcs.add(Some("future.new")) } /// Declares a new `future.read` intrinsic. @@ -484,7 +605,7 @@ impl ComponentBuilder { O::IntoIter: ExactSizeIterator, { self.canonical_functions().future_read(ty, options); - inc(&mut self.core_funcs) + self.core_funcs.add(Some("future.read")) } /// Declares a new `future.write` intrinsic. @@ -494,31 +615,31 @@ impl ComponentBuilder { O::IntoIter: ExactSizeIterator, { self.canonical_functions().future_write(ty, options); - inc(&mut self.core_funcs) + self.core_funcs.add(Some("future.write")) } /// Declares a new `future.cancel-read` intrinsic. pub fn future_cancel_read(&mut self, ty: u32, async_: bool) -> u32 { self.canonical_functions().future_cancel_read(ty, async_); - inc(&mut self.core_funcs) + self.core_funcs.add(Some("future.cancel-read")) } /// Declares a new `future.cancel-write` intrinsic. pub fn future_cancel_write(&mut self, ty: u32, async_: bool) -> u32 { self.canonical_functions().future_cancel_write(ty, async_); - inc(&mut self.core_funcs) + self.core_funcs.add(Some("future.cancel-write")) } - /// Declares a new `future.close-readable` intrinsic. - pub fn future_close_readable(&mut self, ty: u32) -> u32 { - self.canonical_functions().future_close_readable(ty); - inc(&mut self.core_funcs) + /// Declares a new `future.drop-readable` intrinsic. + pub fn future_drop_readable(&mut self, ty: u32) -> u32 { + self.canonical_functions().future_drop_readable(ty); + self.core_funcs.add(Some("future.drop-readable")) } - /// Declares a new `future.close-writable` intrinsic. - pub fn future_close_writable(&mut self, ty: u32) -> u32 { - self.canonical_functions().future_close_writable(ty); - inc(&mut self.core_funcs) + /// Declares a new `future.drop-writable` intrinsic. + pub fn future_drop_writable(&mut self, ty: u32) -> u32 { + self.canonical_functions().future_drop_writable(ty); + self.core_funcs.add(Some("future.drop-writable")) } /// Declares a new `error-context.new` intrinsic. @@ -528,7 +649,7 @@ impl ComponentBuilder { O::IntoIter: ExactSizeIterator, { self.canonical_functions().error_context_new(options); - inc(&mut self.core_funcs) + self.core_funcs.add(Some("error-context.new")) } /// Declares a new `error-context.debug-message` intrinsic. @@ -539,13 +660,82 @@ impl ComponentBuilder { { self.canonical_functions() .error_context_debug_message(options); - inc(&mut self.core_funcs) + self.core_funcs.add(Some("error-context.debug-message")) } /// Declares a new `error-context.drop` intrinsic. pub fn error_context_drop(&mut self) -> u32 { self.canonical_functions().error_context_drop(); - inc(&mut self.core_funcs) + self.core_funcs.add(Some("error-context.drop")) + } + + /// Declares a new `waitable-set.new` intrinsic. + pub fn waitable_set_new(&mut self) -> u32 { + self.canonical_functions().waitable_set_new(); + self.core_funcs.add(Some("waitable-set.new")) + } + + /// Declares a new `waitable-set.wait` intrinsic. + pub fn waitable_set_wait(&mut self, cancellable: bool, memory: u32) -> u32 { + self.canonical_functions() + .waitable_set_wait(cancellable, memory); + self.core_funcs.add(Some("waitable-set.wait")) + } + + /// Declares a new `waitable-set.poll` intrinsic. + pub fn waitable_set_poll(&mut self, cancellable: bool, memory: u32) -> u32 { + self.canonical_functions() + .waitable_set_poll(cancellable, memory); + self.core_funcs.add(Some("waitable-set.poll")) + } + + /// Declares a new `waitable-set.drop` intrinsic. + pub fn waitable_set_drop(&mut self) -> u32 { + self.canonical_functions().waitable_set_drop(); + self.core_funcs.add(Some("waitable-set.drop")) + } + + /// Declares a new `waitable.join` intrinsic. + pub fn waitable_join(&mut self) -> u32 { + self.canonical_functions().waitable_join(); + self.core_funcs.add(Some("waitable.join")) + } + + /// Declares a new `thread.index` intrinsic. + pub fn thread_index(&mut self) -> u32 { + self.canonical_functions().thread_index(); + self.core_funcs.add(Some("thread.index")) + } + + /// Declares a new `thread.new-indirect` intrinsic. + pub fn thread_new_indirect(&mut self, func_ty_idx: u32, table_index: u32) -> u32 { + self.canonical_functions() + .thread_new_indirect(func_ty_idx, table_index); + self.core_funcs.add(Some("thread.new-indirect")) + } + + /// Declares a new `thread.switch-to` intrinsic. + pub fn thread_switch_to(&mut self, cancellable: bool) -> u32 { + self.canonical_functions().thread_switch_to(cancellable); + self.core_funcs.add(Some("thread.switch-to")) + } + + /// Declares a new `thread.suspend` intrinsic. + pub fn thread_suspend(&mut self, cancellable: bool) -> u32 { + self.canonical_functions().thread_suspend(cancellable); + self.core_funcs.add(Some("thread.suspend")) + } + + /// Declares a new `thread.resume-later` intrinsic. + pub fn thread_resume_later(&mut self) -> u32 { + self.canonical_functions().thread_resume_later(); + self.core_funcs.add(Some("thread.resume-later")) + } + + /// Declares a new `thread.yield-to` intrinsic. + pub fn thread_yield_to(&mut self, cancellable: bool) -> u32 { + self.canonical_functions().thread_yield_to(cancellable); + self.core_funcs.add(Some("thread.yield-to")) } /// Adds a new custom section to this component. @@ -624,8 +814,19 @@ section_accessors! { core_types => CoreTypeSection } -fn inc(idx: &mut u32) -> u32 { - let ret = *idx; - *idx += 1; - ret +#[derive(Debug, Default)] +struct Namespace { + count: u32, + names: NameMap, +} + +impl Namespace { + fn add(&mut self, name: Option<&str>) -> u32 { + let ret = self.count; + self.count += 1; + if let Some(name) = name { + self.names.append(ret, name); + } + ret + } } diff --git a/third_party/rust/wasm-encoder/src/component/canonicals.rs b/third_party/rust/wasm-encoder/src/component/canonicals.rs @@ -1,4 +1,4 @@ -use crate::{encode_section, ComponentSection, ComponentSectionId, ComponentValType, Encode}; +use crate::{ComponentSection, ComponentSectionId, ComponentValType, Encode, encode_section}; use alloc::vec::Vec; /// Represents options for canonical function definitions. @@ -27,6 +27,10 @@ pub enum CanonicalOption { /// The function to use if the async lifting of a function should receive task/stream/future progress events /// using a callback. Callback(u32), + /// The core function type to lower a component function into. + CoreType(u32), + /// Use the GC variant of the canonical ABI. + Gc, } impl Encode for CanonicalOption { @@ -54,6 +58,13 @@ impl Encode for CanonicalOption { sink.push(0x07); idx.encode(sink); } + Self::CoreType(idx) => { + sink.push(0x08); + idx.encode(sink); + } + Self::Gc => { + sink.push(0x09); + } } } } @@ -101,14 +112,10 @@ impl CanonicalFunctionSection { O: IntoIterator<Item = CanonicalOption>, O::IntoIter: ExactSizeIterator, { - let options = options.into_iter(); self.bytes.push(0x00); self.bytes.push(0x00); core_func_index.encode(&mut self.bytes); - options.len().encode(&mut self.bytes); - for option in options { - option.encode(&mut self.bytes); - } + self.encode_options(options); type_index.encode(&mut self.bytes); self.num_added += 1; self @@ -120,14 +127,10 @@ impl CanonicalFunctionSection { O: IntoIterator<Item = CanonicalOption>, O::IntoIter: ExactSizeIterator, { - let options = options.into_iter(); self.bytes.push(0x01); self.bytes.push(0x00); func_index.encode(&mut self.bytes); - options.len().encode(&mut self.bytes); - for option in options { - option.encode(&mut self.bytes); - } + self.encode_options(options); self.num_added += 1; self } @@ -149,6 +152,14 @@ impl CanonicalFunctionSection { self } + /// Defines a function which will drop the specified type of handle. + pub fn resource_drop_async(&mut self, ty_index: u32) -> &mut Self { + self.bytes.push(0x07); + ty_index.encode(&mut self.bytes); + self.num_added += 1; + self + } + /// Defines a function which will return the representation of the specified /// resource type. pub fn resource_rep(&mut self, ty_index: u32) -> &mut Self { @@ -158,19 +169,29 @@ impl CanonicalFunctionSection { self } - /// Defines a function which will spawns a new thread by invoking a shared + /// Defines a function which will spawn a new thread by invoking a shared /// function of type `ty_index`. - pub fn thread_spawn(&mut self, ty_index: u32) -> &mut Self { - self.bytes.push(0x05); + pub fn thread_spawn_ref(&mut self, ty_index: u32) -> &mut Self { + self.bytes.push(0x40); ty_index.encode(&mut self.bytes); self.num_added += 1; self } + /// Defines a function which will spawn a new thread by invoking a shared + /// function indirectly through a `funcref` table. + pub fn thread_spawn_indirect(&mut self, ty_index: u32, table_index: u32) -> &mut Self { + self.bytes.push(0x41); + ty_index.encode(&mut self.bytes); + table_index.encode(&mut self.bytes); + self.num_added += 1; + self + } + /// Defines a function which will return the number of threads that can be /// expected to execute concurrently. - pub fn thread_hw_concurrency(&mut self) -> &mut Self { - self.bytes.push(0x06); + pub fn thread_available_parallelism(&mut self) -> &mut Self { + self.bytes.push(0x42); self.num_added += 1; self } @@ -179,49 +200,64 @@ impl CanonicalFunctionSection { /// backpressure for the caller's instance. When backpressure is enabled, /// the host must not start any new calls to that instance until /// backpressure is disabled. - pub fn task_backpressure(&mut self) -> &mut Self { + pub fn backpressure_set(&mut self) -> &mut Self { self.bytes.push(0x08); self.num_added += 1; self } + /// Defines a function which tells the host to increment the backpressure + /// counter. + pub fn backpressure_inc(&mut self) -> &mut Self { + self.bytes.push(0x24); + self.num_added += 1; + self + } + + /// Defines a function which tells the host to decrement the backpressure + /// counter. + pub fn backpressure_dec(&mut self) -> &mut Self { + self.bytes.push(0x25); + self.num_added += 1; + self + } + /// Defines a function which returns a result to the caller of a lifted /// export function. This allows the callee to continue executing after /// returning a result. - pub fn task_return(&mut self, ty: Option<impl Into<ComponentValType>>) -> &mut Self { + pub fn task_return<O>(&mut self, ty: Option<ComponentValType>, options: O) -> &mut Self + where + O: IntoIterator<Item = CanonicalOption>, + O::IntoIter: ExactSizeIterator, + { self.bytes.push(0x09); - if let Some(ty) = ty { - self.bytes.push(0x00); - ty.into().encode(&mut self.bytes); - } else { - self.bytes.push(0x01); - 0_usize.encode(&mut self.bytes); - } + crate::encode_resultlist(&mut self.bytes, ty); + self.encode_options(options); self.num_added += 1; self } - /// Defines a function which waits for at least one outstanding async - /// task/stream/future to make progress, returning the first such event. - /// - /// If `async_` is true, the caller instance may be reentered. - pub fn task_wait(&mut self, async_: bool, memory: u32) -> &mut Self { + /// Defines a function to acknowledge cancellation of the current task. + pub fn task_cancel(&mut self) -> &mut Self { + self.bytes.push(0x05); + self.num_added += 1; + self + } + + /// Defines a new `context.get` intrinsic of the ith slot. + pub fn context_get(&mut self, i: u32) -> &mut Self { self.bytes.push(0x0a); - self.bytes.push(if async_ { 1 } else { 0 }); - memory.encode(&mut self.bytes); + self.bytes.push(0x7f); + i.encode(&mut self.bytes); self.num_added += 1; self } - /// Defines a function which checks whether any outstanding async - /// task/stream/future has made progress. Unlike `task.wait`, this does not - /// block and may return nothing if no such event has occurred. - /// - /// If `async_` is true, the caller instance may be reentered. - pub fn task_poll(&mut self, async_: bool, memory: u32) -> &mut Self { + /// Defines a new `context.set` intrinsic of the ith slot. + pub fn context_set(&mut self, i: u32) -> &mut Self { self.bytes.push(0x0b); - self.bytes.push(if async_ { 1 } else { 0 }); - memory.encode(&mut self.bytes); + self.bytes.push(0x7f); + i.encode(&mut self.bytes); self.num_added += 1; self } @@ -229,10 +265,10 @@ impl CanonicalFunctionSection { /// Defines a function which yields control to the host so that other tasks /// are able to make progress, if any. /// - /// If `async_` is true, the caller instance may be reentered. - pub fn task_yield(&mut self, async_: bool) -> &mut Self { + /// If `cancellable` is true, the caller instance may be reentered. + pub fn thread_yield(&mut self, cancellable: bool) -> &mut Self { self.bytes.push(0x0c); - self.bytes.push(if async_ { 1 } else { 0 }); + self.bytes.push(if cancellable { 1 } else { 0 }); self.num_added += 1; self } @@ -244,6 +280,14 @@ impl CanonicalFunctionSection { self } + /// Defines a function to cancel an in-progress task. + pub fn subtask_cancel(&mut self, async_: bool) -> &mut Self { + self.bytes.push(0x06); + self.bytes.push(if async_ { 1 } else { 0 }); + self.num_added += 1; + self + } + /// Defines a function to create a new `stream` handle of the specified /// type. pub fn stream_new(&mut self, ty: u32) -> &mut Self { @@ -261,11 +305,7 @@ impl CanonicalFunctionSection { { self.bytes.push(0x0f); ty.encode(&mut self.bytes); - let options = options.into_iter(); - options.len().encode(&mut self.bytes); - for option in options { - option.encode(&mut self.bytes); - } + self.encode_options(options); self.num_added += 1; self } @@ -278,11 +318,7 @@ impl CanonicalFunctionSection { { self.bytes.push(0x10); ty.encode(&mut self.bytes); - let options = options.into_iter(); - options.len().encode(&mut self.bytes); - for option in options { - option.encode(&mut self.bytes); - } + self.encode_options(options); self.num_added += 1; self } @@ -307,18 +343,18 @@ impl CanonicalFunctionSection { self } - /// Defines a function to close the readable end of a `stream` of the + /// Defines a function to drop the readable end of a `stream` of the /// specified type. - pub fn stream_close_readable(&mut self, ty: u32) -> &mut Self { + pub fn stream_drop_readable(&mut self, ty: u32) -> &mut Self { self.bytes.push(0x13); ty.encode(&mut self.bytes); self.num_added += 1; self } - /// Defines a function to close the writable end of a `stream` of the + /// Defines a function to drop the writable end of a `stream` of the /// specified type. - pub fn stream_close_writable(&mut self, ty: u32) -> &mut Self { + pub fn stream_drop_writable(&mut self, ty: u32) -> &mut Self { self.bytes.push(0x14); ty.encode(&mut self.bytes); self.num_added += 1; @@ -342,11 +378,7 @@ impl CanonicalFunctionSection { { self.bytes.push(0x16); ty.encode(&mut self.bytes); - let options = options.into_iter(); - options.len().encode(&mut self.bytes); - for option in options { - option.encode(&mut self.bytes); - } + self.encode_options(options); self.num_added += 1; self } @@ -359,11 +391,7 @@ impl CanonicalFunctionSection { { self.bytes.push(0x17); ty.encode(&mut self.bytes); - let options = options.into_iter(); - options.len().encode(&mut self.bytes); - for option in options { - option.encode(&mut self.bytes); - } + self.encode_options(options); self.num_added += 1; self } @@ -388,18 +416,18 @@ impl CanonicalFunctionSection { self } - /// Defines a function to close the readable end of a `future` of the + /// Defines a function to drop the readable end of a `future` of the /// specified type. - pub fn future_close_readable(&mut self, ty: u32) -> &mut Self { + pub fn future_drop_readable(&mut self, ty: u32) -> &mut Self { self.bytes.push(0x1a); ty.encode(&mut self.bytes); self.num_added += 1; self } - /// Defines a function to close the writable end of a `future` of the + /// Defines a function to drop the writable end of a `future` of the /// specified type. - pub fn future_close_writable(&mut self, ty: u32) -> &mut Self { + pub fn future_drop_writable(&mut self, ty: u32) -> &mut Self { self.bytes.push(0x1b); ty.encode(&mut self.bytes); self.num_added += 1; @@ -414,11 +442,7 @@ impl CanonicalFunctionSection { O::IntoIter: ExactSizeIterator, { self.bytes.push(0x1c); - let options = options.into_iter(); - options.len().encode(&mut self.bytes); - for option in options { - option.encode(&mut self.bytes); - } + self.encode_options(options); self.num_added += 1; self } @@ -434,11 +458,7 @@ impl CanonicalFunctionSection { O::IntoIter: ExactSizeIterator, { self.bytes.push(0x1d); - let options = options.into_iter(); - options.len().encode(&mut self.bytes); - for option in options { - option.encode(&mut self.bytes); - } + self.encode_options(options); self.num_added += 1; self } @@ -449,6 +469,116 @@ impl CanonicalFunctionSection { self.num_added += 1; self } + + /// Declare a new `waitable-set.new` intrinsic, used to create a + /// `waitable-set` pseudo-resource. + pub fn waitable_set_new(&mut self) -> &mut Self { + self.bytes.push(0x1f); + self.num_added += 1; + self + } + + /// Declare a new `waitable-set.wait` intrinsic, used to block on a + /// `waitable-set`. + pub fn waitable_set_wait(&mut self, async_: bool, memory: u32) -> &mut Self { + self.bytes.push(0x20); + self.bytes.push(if async_ { 1 } else { 0 }); + memory.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Declare a new `waitable-set.wait` intrinsic, used to check, without + /// blocking, if anything in a `waitable-set` is ready. + pub fn waitable_set_poll(&mut self, async_: bool, memory: u32) -> &mut Self { + self.bytes.push(0x21); + self.bytes.push(if async_ { 1 } else { 0 }); + memory.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Declare a new `waitable-set.drop` intrinsic, used to dispose a + /// `waitable-set` pseudo-resource. + pub fn waitable_set_drop(&mut self) -> &mut Self { + self.bytes.push(0x22); + self.num_added += 1; + self + } + + /// Declare a new `waitable.join` intrinsic, used to add an item to a + /// `waitable-set`. + pub fn waitable_join(&mut self) -> &mut Self { + self.bytes.push(0x23); + self.num_added += 1; + self + } + + /// Declare a new `thread.index` intrinsic, used to get the index of the + /// current thread. + pub fn thread_index(&mut self) -> &mut Self { + self.bytes.push(0x26); + self.num_added += 1; + self + } + + /// Declare a new `thread.new-indirect` intrinsic, used to create a new + /// thread by invoking a function indirectly through a `funcref` table. + pub fn thread_new_indirect(&mut self, ty_index: u32, table_index: u32) -> &mut Self { + self.bytes.push(0x27); + ty_index.encode(&mut self.bytes); + table_index.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Declare a new `thread.switch-to` intrinsic, used to switch execution to + /// another thread. + pub fn thread_switch_to(&mut self, cancellable: bool) -> &mut Self { + self.bytes.push(0x28); + self.bytes.push(if cancellable { 1 } else { 0 }); + self.num_added += 1; + self + } + + /// Declare a new `thread.suspend` intrinsic, used to suspend execution of + /// the current thread. + pub fn thread_suspend(&mut self, cancellable: bool) -> &mut Self { + self.bytes.push(0x29); + self.bytes.push(if cancellable { 1 } else { 0 }); + self.num_added += 1; + self + } + + /// Declare a new `thread.resume-later` intrinsic, used to resume execution + /// of the given thread. + pub fn thread_resume_later(&mut self) -> &mut Self { + self.bytes.push(0x2a); + self.num_added += 1; + self + } + + /// Declare a new `thread.yield-to` intrinsic, used to yield execution to + /// a given thread. + pub fn thread_yield_to(&mut self, cancellable: bool) -> &mut Self { + self.bytes.push(0x2b); + self.bytes.push(if cancellable { 1 } else { 0 }); + self.num_added += 1; + self + } + + fn encode_options<O>(&mut self, options: O) -> &mut Self + where + O: IntoIterator<Item = CanonicalOption>, + O::IntoIter: ExactSizeIterator, + { + let options = options.into_iter(); + options.len().encode(&mut self.bytes); + for option in options { + option.encode(&mut self.bytes); + } + self + } } impl Encode for CanonicalFunctionSection { diff --git a/third_party/rust/wasm-encoder/src/component/exports.rs b/third_party/rust/wasm-encoder/src/component/exports.rs @@ -2,7 +2,7 @@ use super::{ COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, FUNCTION_SORT, INSTANCE_SORT, TYPE_SORT, VALUE_SORT, }; -use crate::{encode_section, ComponentSection, ComponentSectionId, ComponentTypeRef, Encode}; +use crate::{ComponentSection, ComponentSectionId, ComponentTypeRef, Encode, encode_section}; use alloc::vec::Vec; /// Represents the kind of an export from a WebAssembly component. diff --git a/third_party/rust/wasm-encoder/src/component/imports.rs b/third_party/rust/wasm-encoder/src/component/imports.rs @@ -1,6 +1,6 @@ use crate::{ - encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, ComponentValType, - Encode, + ComponentExportKind, ComponentSection, ComponentSectionId, ComponentValType, Encode, + encode_section, }; use alloc::vec::Vec; @@ -96,7 +96,7 @@ impl Encode for ComponentTypeRef { /// ("b", PrimitiveValType::String) /// ] /// ) -/// .result(PrimitiveValType::String); +/// .result(Some(PrimitiveValType::String.into())); /// /// // This imports a function named `f` with the type defined above /// let mut imports = ComponentImportSection::new(); diff --git a/third_party/rust/wasm-encoder/src/component/instances.rs b/third_party/rust/wasm-encoder/src/component/instances.rs @@ -1,6 +1,6 @@ use super::CORE_INSTANCE_SORT; use crate::{ - encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind, + ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind, encode_section, }; use alloc::vec::Vec; diff --git a/third_party/rust/wasm-encoder/src/component/names.rs b/third_party/rust/wasm-encoder/src/component/names.rs @@ -2,7 +2,7 @@ use alloc::borrow::Cow; use alloc::vec::Vec; use super::*; -use crate::{encoding_size, ExportKind, NameMap, SectionId}; +use crate::{ExportKind, NameMap, SectionId, encoding_size}; /// Encoding for the `component-name` custom section which assigns /// human-readable names to items within a component. @@ -57,6 +57,12 @@ impl ComponentNameSection { self.core_decls(ExportKind::Global as u8, names) } + /// Appends a decls name subsection to name core tags within the + /// component. + pub fn core_tags(&mut self, names: &NameMap) { + self.core_decls(ExportKind::Tag as u8, names) + } + /// Appends a decls name subsection to name core types within the /// component. pub fn core_types(&mut self, names: &NameMap) { diff --git a/third_party/rust/wasm-encoder/src/component/types.rs b/third_party/rust/wasm-encoder/src/component/types.rs @@ -1,7 +1,7 @@ use super::CORE_TYPE_SORT; use crate::{ - encode_section, Alias, ComponentExportKind, ComponentOuterAliasKind, ComponentSection, - ComponentSectionId, ComponentTypeRef, CoreTypeEncoder, Encode, EntityType, ValType, + Alias, ComponentExportKind, ComponentOuterAliasKind, ComponentSection, ComponentSectionId, + ComponentTypeRef, CoreTypeEncoder, Encode, EntityType, ValType, encode_section, }; use alloc::vec::Vec; @@ -33,7 +33,7 @@ impl ModuleType { /// /// The returned encoder must be used before adding another definition. #[must_use = "the encoder must be used to encode the type"] - pub fn ty(&mut self) -> CoreTypeEncoder { + pub fn ty(&mut self) -> CoreTypeEncoder<'_> { self.bytes.push(0x01); self.num_added += 1; self.types_added += 1; @@ -178,7 +178,7 @@ impl ComponentType { /// /// The returned encoder must be used before adding another definition. #[must_use = "the encoder must be used to encode the type"] - pub fn core_type(&mut self) -> ComponentCoreTypeEncoder { + pub fn core_type(&mut self) -> ComponentCoreTypeEncoder<'_> { self.bytes.push(0x00); self.num_added += 1; self.core_types_added += 1; @@ -189,7 +189,7 @@ impl ComponentType { /// /// The returned encoder must be used before adding another definition. #[must_use = "the encoder must be used to encode the type"] - pub fn ty(&mut self) -> ComponentTypeEncoder { + pub fn ty(&mut self) -> ComponentTypeEncoder<'_> { self.bytes.push(0x01); self.num_added += 1; self.types_added += 1; @@ -291,7 +291,7 @@ impl InstanceType { /// /// The returned encoder must be used before adding another definition. #[must_use = "the encoder must be used to encode the type"] - pub fn core_type(&mut self) -> ComponentCoreTypeEncoder { + pub fn core_type(&mut self) -> ComponentCoreTypeEncoder<'_> { self.0.core_type() } @@ -299,7 +299,7 @@ impl InstanceType { /// /// The returned encoder must be used before adding another definition. #[must_use = "the encoder must be used to encode the type"] - pub fn ty(&mut self) -> ComponentTypeEncoder { + pub fn ty(&mut self) -> ComponentTypeEncoder<'_> { self.0.ty() } @@ -353,6 +353,7 @@ impl Encode for InstanceType { /// Used to encode component function types. #[derive(Debug)] pub struct ComponentFuncTypeEncoder<'a> { + async_encoded: bool, params_encoded: bool, results_encoded: bool, sink: &'a mut Vec<u8>, @@ -360,14 +361,36 @@ pub struct ComponentFuncTypeEncoder<'a> { impl<'a> ComponentFuncTypeEncoder<'a> { fn new(sink: &'a mut Vec<u8>) -> Self { - sink.push(0x40); Self { + async_encoded: false, params_encoded: false, results_encoded: false, sink, } } + /// Indicates whether this is an `async` function or not. + /// + /// If this function is not invoked then the function type will not be + /// `async`. + /// + /// # Panics + /// + /// This method will panic if parameters or results have already been + /// encoded. + pub fn async_(&mut self, is_async: bool) -> &mut Self { + assert!(!self.params_encoded); + assert!(!self.results_encoded); + assert!(!self.async_encoded); + self.async_encoded = true; + if is_async { + self.sink.push(0x43); + } else { + self.sink.push(0x40); + } + self + } + /// Defines named parameters. /// /// Parameters must be defined before defining results. @@ -383,6 +406,9 @@ impl<'a> ComponentFuncTypeEncoder<'a> { T: Into<ComponentValType>, { assert!(!self.params_encoded); + if !self.async_encoded { + self.async_(false); + } self.params_encoded = true; let params = params.into_iter(); params.len().encode(self.sink); @@ -401,40 +427,26 @@ impl<'a> ComponentFuncTypeEncoder<'a> { /// /// This method will panic if the function is called twice, called before /// the `params` method, or called in addition to the `results` method. - pub fn result(&mut self, ty: impl Into<ComponentValType>) -> &mut Self { + pub fn result(&mut self, ty: Option<ComponentValType>) -> &mut Self { + assert!(self.async_encoded); assert!(self.params_encoded); assert!(!self.results_encoded); self.results_encoded = true; - self.sink.push(0x00); - ty.into().encode(self.sink); + encode_resultlist(self.sink, ty); self } +} - /// Defines named results. - /// - /// This method cannot be used with `result`. - /// - /// # Panics - /// - /// This method will panic if the function is called twice, called before - /// the `params` method, or called in addition to the `result` method. - pub fn results<'b, R, T>(&mut self, results: R) -> &mut Self - where - R: IntoIterator<Item = (&'b str, T)>, - R::IntoIter: ExactSizeIterator, - T: Into<ComponentValType>, - { - assert!(self.params_encoded); - assert!(!self.results_encoded); - self.results_encoded = true; - self.sink.push(0x01); - let results = results.into_iter(); - results.len().encode(self.sink); - for (name, ty) in results { - name.encode(self.sink); - ty.into().encode(self.sink); +pub(crate) fn encode_resultlist(sink: &mut Vec<u8>, ty: Option<ComponentValType>) { + match ty { + Some(ty) => { + sink.push(0x00); + ty.encode(sink); + } + None => { + sink.push(0x01); + sink.push(0x00); } - self } } @@ -509,6 +521,8 @@ pub enum PrimitiveValType { Char, /// The type is a string. String, + /// Type for `error-context` added with async support in the component model. + ErrorContext, } impl Encode for PrimitiveValType { @@ -527,6 +541,7 @@ impl Encode for PrimitiveValType { Self::F64 => 0x75, Self::Char => 0x74, Self::String => 0x73, + Self::ErrorContext => 0x64, }); } } @@ -605,6 +620,13 @@ impl ComponentDefinedTypeEncoder<'_> { ty.into().encode(self.0); } + /// Define a fixed size list type. + pub fn fixed_size_list(self, ty: impl Into<ComponentValType>, elements: u32) { + self.0.push(0x67); + ty.into().encode(self.0); + elements.encode(self.0); + } + /// Define a tuple type. pub fn tuple<I, T>(self, types: I) where @@ -675,7 +697,7 @@ impl ComponentDefinedTypeEncoder<'_> { /// Define a `future` type with the specified payload. pub fn future(self, payload: Option<ComponentValType>) { - self.0.push(0x67); + self.0.push(0x65); payload.encode(self.0); } @@ -684,11 +706,6 @@ impl ComponentDefinedTypeEncoder<'_> { self.0.push(0x66); payload.encode(self.0); } - - /// Define the `error-context` type. - pub fn error_context(self) { - self.0.push(0x65); - } } /// An encoder for the type section of WebAssembly components. @@ -709,7 +726,7 @@ impl ComponentDefinedTypeEncoder<'_> { /// ("b", PrimitiveValType::String) /// ] /// ) -/// .result(PrimitiveValType::String); +/// .result(Some(PrimitiveValType::String.into())); /// /// let mut component = Component::new(); /// component.section(&types); diff --git a/third_party/rust/wasm-encoder/src/core.rs b/third_party/rust/wasm-encoder/src/core.rs @@ -8,6 +8,7 @@ mod exports; mod functions; mod globals; mod imports; +mod instructions; mod linking; mod memories; mod names; @@ -27,6 +28,7 @@ pub use exports::*; pub use functions::*; pub use globals::*; pub use imports::*; +pub use instructions::*; pub use linking::*; pub use memories::*; pub use names::*; @@ -44,6 +46,7 @@ pub(crate) const CORE_TABLE_SORT: u8 = 0x01; pub(crate) const CORE_MEMORY_SORT: u8 = 0x02; pub(crate) const CORE_GLOBAL_SORT: u8 = 0x03; pub(crate) const CORE_TAG_SORT: u8 = 0x04; +pub(crate) const CORE_FUNCTION_EXACT_SORT: u8 = 0x20; /// A WebAssembly module section. /// diff --git a/third_party/rust/wasm-encoder/src/core/branch_hints.rs b/third_party/rust/wasm-encoder/src/core/branch_hints.rs @@ -25,11 +25,12 @@ use alloc::vec::Vec; /// let mut code = CodeSection::new(); /// let mut body = Function::new([]); /// -/// body.instruction(&Instruction::I32Const(1)); +/// body.instructions().i32_const(1); /// let if_offset = body.byte_len(); -/// body.instruction(&Instruction::If(BlockType::Empty)); -/// body.instruction(&Instruction::End); -/// body.instruction(&Instruction::End); +/// body.instructions() +/// .if_(BlockType::Empty) +/// .end() +/// .end(); /// code.function(&body); /// /// let mut hints = BranchHints::new(); diff --git a/third_party/rust/wasm-encoder/src/core/code.rs b/third_party/rust/wasm-encoder/src/core/code.rs @@ -1,4 +1,6 @@ -use crate::{encode_section, Encode, HeapType, RefType, Section, SectionId, ValType}; +use crate::{ + Encode, HeapType, InstructionSink, RefType, Section, SectionId, ValType, encode_section, +}; use alloc::borrow::Cow; use alloc::vec; use alloc::vec::Vec; @@ -11,7 +13,7 @@ use alloc::vec::Vec; /// /// ``` /// use wasm_encoder::{ -/// CodeSection, Function, FunctionSection, Instruction, Module, +/// CodeSection, Function, FunctionSection, Module, /// TypeSection, ValType /// }; /// @@ -24,7 +26,7 @@ use alloc::vec::Vec; /// /// let locals = vec![]; /// let mut func = Function::new(locals); -/// func.instruction(&Instruction::I32Const(42)); +/// func.instructions().i32_const(42); /// let mut code = CodeSection::new(); /// code.function(&func); /// @@ -124,7 +126,7 @@ impl Section for CodeSection { /// # Example /// /// ``` -/// use wasm_encoder::{CodeSection, Function, Instruction}; +/// use wasm_encoder::{CodeSection, Function}; /// /// // Define the function body for: /// // @@ -134,9 +136,10 @@ impl Section for CodeSection { /// // 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); +/// func.instructions() +/// .local_get(0) +/// .local_get(1) +/// .i32_add(); /// /// // Add our function to the code section. /// let mut code = CodeSection::new(); @@ -216,6 +219,11 @@ impl Function { Function::new(locals_collected) } + /// Get an instruction encoder for this function body. + pub fn instructions(&mut self) -> InstructionSink<'_> { + InstructionSink::new(&mut self.bytes) + } + /// Write an instruction into this function body. pub fn instruction(&mut self, instruction: &Instruction) -> &mut Self { instruction.encode(&mut self.bytes); @@ -264,9 +272,9 @@ impl Function { /// For example: /// /// ``` - /// # use wasm_encoder::{CodeSection, Function, Instruction}; + /// # use wasm_encoder::{CodeSection, Function}; /// let mut f = Function::new([]); - /// f.instruction(&Instruction::End); + /// f.instructions().end(); /// let bytes = f.into_raw_body(); /// // (save `bytes` somewhere for later use) /// let mut code = CodeSection::new(); @@ -286,6 +294,82 @@ impl Encode for Function { } } +/// An IEEE binary32 immediate floating point value, represented as a u32 +/// containing the bit pattern. +/// +/// All bit patterns are allowed. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct Ieee32(pub(crate) u32); + +impl Ieee32 { + /// Creates a new Ieee32 + pub fn new(bits: u32) -> Self { + Ieee32(bits) + } + + /// Gets the underlying bits of the 32-bit float. + pub fn bits(self) -> u32 { + self.0 + } +} + +impl From<f32> for Ieee32 { + fn from(value: f32) -> Self { + Ieee32(u32::from_le_bytes(value.to_le_bytes())) + } +} + +impl From<Ieee32> for f32 { + fn from(bits: Ieee32) -> f32 { + f32::from_bits(bits.bits()) + } +} + +impl Encode for Ieee32 { + fn encode(&self, sink: &mut Vec<u8>) { + let bits = self.bits(); + sink.extend(bits.to_le_bytes()) + } +} + +/// An IEEE binary64 immediate floating point value, represented as a u64 +/// containing the bit pattern. +/// +/// All bit patterns are allowed. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct Ieee64(pub(crate) u64); + +impl Ieee64 { + /// Creates a new Ieee64 + pub fn new(bits: u64) -> Self { + Ieee64(bits) + } + + /// Gets the underlying bits of the 64-bit float. + pub fn bits(self) -> u64 { + self.0 + } +} + +impl From<f64> for Ieee64 { + fn from(value: f64) -> Self { + Ieee64(u64::from_le_bytes(value.to_le_bytes())) + } +} + +impl From<Ieee64> for f64 { + fn from(bits: Ieee64) -> f64 { + f64::from_bits(bits.bits()) + } +} + +impl Encode for Ieee64 { + fn encode(&self, sink: &mut Vec<u8>) { + let bits = self.bits(); + sink.extend(bits.to_le_bytes()) + } +} + /// The immediate for a memory instruction. #[derive(Clone, Copy, Debug)] pub struct MemArg { @@ -463,8 +547,8 @@ pub enum Instruction<'a> { // Numeric instructions. I32Const(i32), I64Const(i64), - F32Const(f32), - F64Const(f64), + F32Const(Ieee32), + F64Const(Ieee64), I32Eqz, I32Eq, I32Ne, @@ -604,6 +688,7 @@ pub enum Instruction<'a> { // Reference types instructions. TypedSelect(ValType), + TypedSelectMulti(Cow<'a, [ValType]>), RefNull(HeapType), RefIsNull, RefFunc(u32), @@ -629,6 +714,8 @@ pub enum Instruction<'a> { struct_type_index: u32, field_index: u32, }, + StructNewDesc(u32), + StructNewDefaultDesc(u32), ArrayNew(u32), ArrayNewDefault(u32), @@ -1231,2557 +1318,866 @@ pub enum Instruction<'a> { I64Sub128, I64MulWideS, I64MulWideU, + + RefGetDesc(u32), + RefCastDescNonNull(HeapType), + RefCastDescNullable(HeapType), + BrOnCastDesc { + relative_depth: u32, + from_ref_type: RefType, + to_ref_type: RefType, + }, + BrOnCastDescFail { + relative_depth: u32, + from_ref_type: RefType, + to_ref_type: RefType, + }, } impl Encode for Instruction<'_> { - fn encode(&self, sink: &mut Vec<u8>) { + fn encode(&self, bytes: &mut Vec<u8>) { + let mut sink = InstructionSink::new(bytes); match *self { // Control instructions. - Instruction::Unreachable => sink.push(0x00), - Instruction::Nop => sink.push(0x01), - Instruction::Block(bt) => { - sink.push(0x02); - bt.encode(sink); - } - Instruction::Loop(bt) => { - sink.push(0x03); - bt.encode(sink); - } - Instruction::If(bt) => { - sink.push(0x04); - bt.encode(sink); - } - Instruction::Else => sink.push(0x05), - Instruction::Try(bt) => { - sink.push(0x06); - bt.encode(sink); - } - Instruction::Catch(t) => { - sink.push(0x07); - t.encode(sink); - } - Instruction::Throw(t) => { - sink.push(0x08); - t.encode(sink); - } - Instruction::Rethrow(l) => { - sink.push(0x09); - l.encode(sink); - } - Instruction::ThrowRef => { - sink.push(0x0A); - } - Instruction::End => sink.push(0x0B), - Instruction::Br(l) => { - sink.push(0x0C); - l.encode(sink); - } - Instruction::BrIf(l) => { - sink.push(0x0D); - l.encode(sink); - } - Instruction::BrTable(ref ls, l) => { - sink.push(0x0E); - ls.encode(sink); - l.encode(sink); - } - Instruction::BrOnNull(l) => { - sink.push(0xD5); - l.encode(sink); - } - Instruction::BrOnNonNull(l) => { - sink.push(0xD6); - l.encode(sink); - } - Instruction::Return => sink.push(0x0F), - Instruction::Call(f) => { - sink.push(0x10); - f.encode(sink); - } - Instruction::CallRef(ty) => { - sink.push(0x14); - ty.encode(sink); - } + Instruction::Unreachable => sink.unreachable(), + Instruction::Nop => sink.nop(), + Instruction::Block(bt) => sink.block(bt), + Instruction::Loop(bt) => sink.loop_(bt), + Instruction::If(bt) => sink.if_(bt), + Instruction::Else => sink.else_(), + Instruction::Try(bt) => sink.try_(bt), + Instruction::Catch(t) => sink.catch(t), + Instruction::Throw(t) => sink.throw(t), + Instruction::Rethrow(l) => sink.rethrow(l), + Instruction::ThrowRef => sink.throw_ref(), + Instruction::End => sink.end(), + Instruction::Br(l) => sink.br(l), + Instruction::BrIf(l) => sink.br_if(l), + Instruction::BrTable(ref ls, l) => sink.br_table(ls.iter().copied(), l), + Instruction::BrOnNull(l) => sink.br_on_null(l), + Instruction::BrOnNonNull(l) => sink.br_on_non_null(l), + Instruction::Return => sink.return_(), + Instruction::Call(f) => sink.call(f), + Instruction::CallRef(ty) => sink.call_ref(ty), Instruction::CallIndirect { type_index, table_index, - } => { - sink.push(0x11); - type_index.encode(sink); - table_index.encode(sink); - } - Instruction::ReturnCallRef(ty) => { - sink.push(0x15); - ty.encode(sink); - } + } => sink.call_indirect(table_index, type_index), + Instruction::ReturnCallRef(ty) => sink.return_call_ref(ty), - Instruction::ReturnCall(f) => { - sink.push(0x12); - f.encode(sink); - } + Instruction::ReturnCall(f) => sink.return_call(f), Instruction::ReturnCallIndirect { type_index, table_index, - } => { - sink.push(0x13); - type_index.encode(sink); - table_index.encode(sink); - } - Instruction::Delegate(l) => { - sink.push(0x18); - l.encode(sink); - } - Instruction::CatchAll => { - sink.push(0x19); - } + } => sink.return_call_indirect(table_index, type_index), + Instruction::Delegate(l) => sink.delegate(l), + Instruction::CatchAll => sink.catch_all(), // Parametric instructions. - Instruction::Drop => sink.push(0x1A), - Instruction::Select => sink.push(0x1B), - Instruction::TypedSelect(ty) => { - sink.push(0x1c); - [ty].encode(sink); - } + Instruction::Drop => sink.drop(), + Instruction::Select => sink.select(), + Instruction::TypedSelect(ty) => sink.typed_select(ty), + Instruction::TypedSelectMulti(ref tys) => sink.typed_select_multi(tys.as_ref()), - Instruction::TryTable(ty, ref catches) => { - sink.push(0x1f); - ty.encode(sink); - catches.encode(sink); - } + Instruction::TryTable(ty, ref catches) => sink.try_table(ty, catches.iter().cloned()), // Variable instructions. - Instruction::LocalGet(l) => { - sink.push(0x20); - l.encode(sink); - } - Instruction::LocalSet(l) => { - sink.push(0x21); - l.encode(sink); - } - Instruction::LocalTee(l) => { - sink.push(0x22); - l.encode(sink); - } - Instruction::GlobalGet(g) => { - sink.push(0x23); - g.encode(sink); - } - Instruction::GlobalSet(g) => { - sink.push(0x24); - g.encode(sink); - } - Instruction::TableGet(table) => { - sink.push(0x25); - table.encode(sink); - } - Instruction::TableSet(table) => { - sink.push(0x26); - table.encode(sink); - } + Instruction::LocalGet(l) => sink.local_get(l), + Instruction::LocalSet(l) => sink.local_set(l), + Instruction::LocalTee(l) => sink.local_tee(l), + Instruction::GlobalGet(g) => sink.global_get(g), + Instruction::GlobalSet(g) => sink.global_set(g), + Instruction::TableGet(table) => sink.table_get(table), + Instruction::TableSet(table) => sink.table_set(table), // Memory instructions. - Instruction::I32Load(m) => { - sink.push(0x28); - m.encode(sink); - } - Instruction::I64Load(m) => { - sink.push(0x29); - m.encode(sink); - } - Instruction::F32Load(m) => { - sink.push(0x2A); - m.encode(sink); - } - Instruction::F64Load(m) => { - sink.push(0x2B); - m.encode(sink); - } - Instruction::I32Load8S(m) => { - sink.push(0x2C); - m.encode(sink); - } - Instruction::I32Load8U(m) => { - sink.push(0x2D); - m.encode(sink); - } - Instruction::I32Load16S(m) => { - sink.push(0x2E); - m.encode(sink); - } - Instruction::I32Load16U(m) => { - sink.push(0x2F); - m.encode(sink); - } - Instruction::I64Load8S(m) => { - sink.push(0x30); - m.encode(sink); - } - Instruction::I64Load8U(m) => { - sink.push(0x31); - m.encode(sink); - } - Instruction::I64Load16S(m) => { - sink.push(0x32); - m.encode(sink); - } - Instruction::I64Load16U(m) => { - sink.push(0x33); - m.encode(sink); - } - Instruction::I64Load32S(m) => { - sink.push(0x34); - m.encode(sink); - } - Instruction::I64Load32U(m) => { - sink.push(0x35); - m.encode(sink); - } - Instruction::I32Store(m) => { - sink.push(0x36); - m.encode(sink); - } - Instruction::I64Store(m) => { - sink.push(0x37); - m.encode(sink); - } - Instruction::F32Store(m) => { - sink.push(0x38); - m.encode(sink); - } - Instruction::F64Store(m) => { - sink.push(0x39); - m.encode(sink); - } - Instruction::I32Store8(m) => { - sink.push(0x3A); - m.encode(sink); - } - Instruction::I32Store16(m) => { - sink.push(0x3B); - m.encode(sink); - } - Instruction::I64Store8(m) => { - sink.push(0x3C); - m.encode(sink); - } - Instruction::I64Store16(m) => { - sink.push(0x3D); - m.encode(sink); - } - Instruction::I64Store32(m) => { - sink.push(0x3E); - m.encode(sink); - } - Instruction::MemorySize(i) => { - sink.push(0x3F); - i.encode(sink); - } - Instruction::MemoryGrow(i) => { - sink.push(0x40); - i.encode(sink); - } - Instruction::MemoryInit { mem, data_index } => { - sink.push(0xfc); - sink.push(0x08); - data_index.encode(sink); - mem.encode(sink); - } - Instruction::DataDrop(data) => { - sink.push(0xfc); - sink.push(0x09); - data.encode(sink); - } - Instruction::MemoryCopy { src_mem, dst_mem } => { - sink.push(0xfc); - sink.push(0x0a); - dst_mem.encode(sink); - src_mem.encode(sink); - } - Instruction::MemoryFill(mem) => { - sink.push(0xfc); - sink.push(0x0b); - mem.encode(sink); - } - Instruction::MemoryDiscard(mem) => { - sink.push(0xfc); - sink.push(0x12); - mem.encode(sink); - } + Instruction::I32Load(m) => sink.i32_load(m), + Instruction::I64Load(m) => sink.i64_load(m), + Instruction::F32Load(m) => sink.f32_load(m), + Instruction::F64Load(m) => sink.f64_load(m), + Instruction::I32Load8S(m) => sink.i32_load8_s(m), + Instruction::I32Load8U(m) => sink.i32_load8_u(m), + Instruction::I32Load16S(m) => sink.i32_load16_s(m), + Instruction::I32Load16U(m) => sink.i32_load16_u(m), + Instruction::I64Load8S(m) => sink.i64_load8_s(m), + Instruction::I64Load8U(m) => sink.i64_load8_u(m), + Instruction::I64Load16S(m) => sink.i64_load16_s(m), + Instruction::I64Load16U(m) => sink.i64_load16_u(m), + Instruction::I64Load32S(m) => sink.i64_load32_s(m), + Instruction::I64Load32U(m) => sink.i64_load32_u(m), + Instruction::I32Store(m) => sink.i32_store(m), + Instruction::I64Store(m) => sink.i64_store(m), + Instruction::F32Store(m) => sink.f32_store(m), + Instruction::F64Store(m) => sink.f64_store(m), + Instruction::I32Store8(m) => sink.i32_store8(m), + Instruction::I32Store16(m) => sink.i32_store16(m), + Instruction::I64Store8(m) => sink.i64_store8(m), + Instruction::I64Store16(m) => sink.i64_store16(m), + Instruction::I64Store32(m) => sink.i64_store32(m), + Instruction::MemorySize(i) => sink.memory_size(i), + Instruction::MemoryGrow(i) => sink.memory_grow(i), + Instruction::MemoryInit { mem, data_index } => sink.memory_init(mem, data_index), + Instruction::DataDrop(data) => sink.data_drop(data), + Instruction::MemoryCopy { src_mem, dst_mem } => sink.memory_copy(dst_mem, src_mem), + Instruction::MemoryFill(mem) => sink.memory_fill(mem), + Instruction::MemoryDiscard(mem) => sink.memory_discard(mem), // Numeric instructions. - Instruction::I32Const(x) => { - sink.push(0x41); - x.encode(sink); - } - Instruction::I64Const(x) => { - sink.push(0x42); - x.encode(sink); - } - Instruction::F32Const(x) => { - sink.push(0x43); - let x = x.to_bits(); - sink.extend(x.to_le_bytes().iter().copied()); - } - Instruction::F64Const(x) => { - sink.push(0x44); - let x = x.to_bits(); - sink.extend(x.to_le_bytes().iter().copied()); - } - Instruction::I32Eqz => sink.push(0x45), - Instruction::I32Eq => sink.push(0x46), - Instruction::I32Ne => sink.push(0x47), - Instruction::I32LtS => sink.push(0x48), - Instruction::I32LtU => sink.push(0x49), - Instruction::I32GtS => sink.push(0x4A), - Instruction::I32GtU => sink.push(0x4B), - Instruction::I32LeS => sink.push(0x4C), - Instruction::I32LeU => sink.push(0x4D), - Instruction::I32GeS => sink.push(0x4E), - Instruction::I32GeU => sink.push(0x4F), - Instruction::I64Eqz => sink.push(0x50), - Instruction::I64Eq => sink.push(0x51), - Instruction::I64Ne => sink.push(0x52), - Instruction::I64LtS => sink.push(0x53), - Instruction::I64LtU => sink.push(0x54), - Instruction::I64GtS => sink.push(0x55), - Instruction::I64GtU => sink.push(0x56), - Instruction::I64LeS => sink.push(0x57), - Instruction::I64LeU => sink.push(0x58), - Instruction::I64GeS => sink.push(0x59), - Instruction::I64GeU => sink.push(0x5A), - Instruction::F32Eq => sink.push(0x5B), - Instruction::F32Ne => sink.push(0x5C), - Instruction::F32Lt => sink.push(0x5D), - Instruction::F32Gt => sink.push(0x5E), - Instruction::F32Le => sink.push(0x5F), - Instruction::F32Ge => sink.push(0x60), - Instruction::F64Eq => sink.push(0x61), - Instruction::F64Ne => sink.push(0x62), - Instruction::F64Lt => sink.push(0x63), - Instruction::F64Gt => sink.push(0x64), - Instruction::F64Le => sink.push(0x65), - Instruction::F64Ge => sink.push(0x66), - Instruction::I32Clz => sink.push(0x67), - Instruction::I32Ctz => sink.push(0x68), - Instruction::I32Popcnt => sink.push(0x69), - Instruction::I32Add => sink.push(0x6A), - Instruction::I32Sub => sink.push(0x6B), - Instruction::I32Mul => sink.push(0x6C), - Instruction::I32DivS => sink.push(0x6D), - Instruction::I32DivU => sink.push(0x6E), - Instruction::I32RemS => sink.push(0x6F), - Instruction::I32RemU => sink.push(0x70), - Instruction::I32And => sink.push(0x71), - Instruction::I32Or => sink.push(0x72), - Instruction::I32Xor => sink.push(0x73), - Instruction::I32Shl => sink.push(0x74), - Instruction::I32ShrS => sink.push(0x75), - Instruction::I32ShrU => sink.push(0x76), - Instruction::I32Rotl => sink.push(0x77), - Instruction::I32Rotr => sink.push(0x78), - Instruction::I64Clz => sink.push(0x79), - Instruction::I64Ctz => sink.push(0x7A), - Instruction::I64Popcnt => sink.push(0x7B), - Instruction::I64Add => sink.push(0x7C), - Instruction::I64Sub => sink.push(0x7D), - Instruction::I64Mul => sink.push(0x7E), - Instruction::I64DivS => sink.push(0x7F), - Instruction::I64DivU => sink.push(0x80), - Instruction::I64RemS => sink.push(0x81), - Instruction::I64RemU => sink.push(0x82), - Instruction::I64And => sink.push(0x83), - Instruction::I64Or => sink.push(0x84), - Instruction::I64Xor => sink.push(0x85), - Instruction::I64Shl => sink.push(0x86), - Instruction::I64ShrS => sink.push(0x87), - Instruction::I64ShrU => sink.push(0x88), - Instruction::I64Rotl => sink.push(0x89), - Instruction::I64Rotr => sink.push(0x8A), - Instruction::F32Abs => sink.push(0x8B), - Instruction::F32Neg => sink.push(0x8C), - Instruction::F32Ceil => sink.push(0x8D), - Instruction::F32Floor => sink.push(0x8E), - Instruction::F32Trunc => sink.push(0x8F), - Instruction::F32Nearest => sink.push(0x90), - Instruction::F32Sqrt => sink.push(0x91), - Instruction::F32Add => sink.push(0x92), - Instruction::F32Sub => sink.push(0x93), - Instruction::F32Mul => sink.push(0x94), - Instruction::F32Div => sink.push(0x95), - Instruction::F32Min => sink.push(0x96), - Instruction::F32Max => sink.push(0x97), - Instruction::F32Copysign => sink.push(0x98), - Instruction::F64Abs => sink.push(0x99), - Instruction::F64Neg => sink.push(0x9A), - Instruction::F64Ceil => sink.push(0x9B), - Instruction::F64Floor => sink.push(0x9C), - Instruction::F64Trunc => sink.push(0x9D), - Instruction::F64Nearest => sink.push(0x9E), - Instruction::F64Sqrt => sink.push(0x9F), - Instruction::F64Add => sink.push(0xA0), - Instruction::F64Sub => sink.push(0xA1), - Instruction::F64Mul => sink.push(0xA2), - Instruction::F64Div => sink.push(0xA3), - Instruction::F64Min => sink.push(0xA4), - Instruction::F64Max => sink.push(0xA5), - Instruction::F64Copysign => sink.push(0xA6), - Instruction::I32WrapI64 => sink.push(0xA7), - Instruction::I32TruncF32S => sink.push(0xA8), - Instruction::I32TruncF32U => sink.push(0xA9), - Instruction::I32TruncF64S => sink.push(0xAA), - Instruction::I32TruncF64U => sink.push(0xAB), - Instruction::I64ExtendI32S => sink.push(0xAC), - Instruction::I64ExtendI32U => sink.push(0xAD), - Instruction::I64TruncF32S => sink.push(0xAE), - Instruction::I64TruncF32U => sink.push(0xAF), - Instruction::I64TruncF64S => sink.push(0xB0), - Instruction::I64TruncF64U => sink.push(0xB1), - Instruction::F32ConvertI32S => sink.push(0xB2), - Instruction::F32ConvertI32U => sink.push(0xB3), - Instruction::F32ConvertI64S => sink.push(0xB4), - Instruction::F32ConvertI64U => sink.push(0xB5), - Instruction::F32DemoteF64 => sink.push(0xB6), - Instruction::F64ConvertI32S => sink.push(0xB7), - Instruction::F64ConvertI32U => sink.push(0xB8), - Instruction::F64ConvertI64S => sink.push(0xB9), - Instruction::F64ConvertI64U => sink.push(0xBA), - Instruction::F64PromoteF32 => sink.push(0xBB), - Instruction::I32ReinterpretF32 => sink.push(0xBC), - Instruction::I64ReinterpretF64 => sink.push(0xBD), - Instruction::F32ReinterpretI32 => sink.push(0xBE), - Instruction::F64ReinterpretI64 => sink.push(0xBF), - Instruction::I32Extend8S => sink.push(0xC0), - Instruction::I32Extend16S => sink.push(0xC1), - Instruction::I64Extend8S => sink.push(0xC2), - Instruction::I64Extend16S => sink.push(0xC3), - Instruction::I64Extend32S => sink.push(0xC4), - - Instruction::I32TruncSatF32S => { - sink.push(0xFC); - sink.push(0x00); - } - Instruction::I32TruncSatF32U => { - sink.push(0xFC); - sink.push(0x01); - } - Instruction::I32TruncSatF64S => { - sink.push(0xFC); - sink.push(0x02); - } - Instruction::I32TruncSatF64U => { - sink.push(0xFC); - sink.push(0x03); - } - Instruction::I64TruncSatF32S => { - sink.push(0xFC); - sink.push(0x04); - } - Instruction::I64TruncSatF32U => { - sink.push(0xFC); - sink.push(0x05); - } - Instruction::I64TruncSatF64S => { - sink.push(0xFC); - sink.push(0x06); - } - Instruction::I64TruncSatF64U => { - sink.push(0xFC); - sink.push(0x07); - } + Instruction::I32Const(x) => sink.i32_const(x), + Instruction::I64Const(x) => sink.i64_const(x), + Instruction::F32Const(x) => sink.f32_const(x), + Instruction::F64Const(x) => sink.f64_const(x), + Instruction::I32Eqz => sink.i32_eqz(), + Instruction::I32Eq => sink.i32_eq(), + Instruction::I32Ne => sink.i32_ne(), + Instruction::I32LtS => sink.i32_lt_s(), + Instruction::I32LtU => sink.i32_lt_u(), + Instruction::I32GtS => sink.i32_gt_s(), + Instruction::I32GtU => sink.i32_gt_u(), + Instruction::I32LeS => sink.i32_le_s(), + Instruction::I32LeU => sink.i32_le_u(), + Instruction::I32GeS => sink.i32_ge_s(), + Instruction::I32GeU => sink.i32_ge_u(), + Instruction::I64Eqz => sink.i64_eqz(), + Instruction::I64Eq => sink.i64_eq(), + Instruction::I64Ne => sink.i64_ne(), + Instruction::I64LtS => sink.i64_lt_s(), + Instruction::I64LtU => sink.i64_lt_u(), + Instruction::I64GtS => sink.i64_gt_s(), + Instruction::I64GtU => sink.i64_gt_u(), + Instruction::I64LeS => sink.i64_le_s(), + Instruction::I64LeU => sink.i64_le_u(), + Instruction::I64GeS => sink.i64_ge_s(), + Instruction::I64GeU => sink.i64_ge_u(), + Instruction::F32Eq => sink.f32_eq(), + Instruction::F32Ne => sink.f32_ne(), + Instruction::F32Lt => sink.f32_lt(), + Instruction::F32Gt => sink.f32_gt(), + Instruction::F32Le => sink.f32_le(), + Instruction::F32Ge => sink.f32_ge(), + Instruction::F64Eq => sink.f64_eq(), + Instruction::F64Ne => sink.f64_ne(), + Instruction::F64Lt => sink.f64_lt(), + Instruction::F64Gt => sink.f64_gt(), + Instruction::F64Le => sink.f64_le(), + Instruction::F64Ge => sink.f64_ge(), + Instruction::I32Clz => sink.i32_clz(), + Instruction::I32Ctz => sink.i32_ctz(), + Instruction::I32Popcnt => sink.i32_popcnt(), + Instruction::I32Add => sink.i32_add(), + Instruction::I32Sub => sink.i32_sub(), + Instruction::I32Mul => sink.i32_mul(), + Instruction::I32DivS => sink.i32_div_s(), + Instruction::I32DivU => sink.i32_div_u(), + Instruction::I32RemS => sink.i32_rem_s(), + Instruction::I32RemU => sink.i32_rem_u(), + Instruction::I32And => sink.i32_and(), + Instruction::I32Or => sink.i32_or(), + Instruction::I32Xor => sink.i32_xor(), + Instruction::I32Shl => sink.i32_shl(), + Instruction::I32ShrS => sink.i32_shr_s(), + Instruction::I32ShrU => sink.i32_shr_u(), + Instruction::I32Rotl => sink.i32_rotl(), + Instruction::I32Rotr => sink.i32_rotr(), + Instruction::I64Clz => sink.i64_clz(), + Instruction::I64Ctz => sink.i64_ctz(), + Instruction::I64Popcnt => sink.i64_popcnt(), + Instruction::I64Add => sink.i64_add(), + Instruction::I64Sub => sink.i64_sub(), + Instruction::I64Mul => sink.i64_mul(), + Instruction::I64DivS => sink.i64_div_s(), + Instruction::I64DivU => sink.i64_div_u(), + Instruction::I64RemS => sink.i64_rem_s(), + Instruction::I64RemU => sink.i64_rem_u(), + Instruction::I64And => sink.i64_and(), + Instruction::I64Or => sink.i64_or(), + Instruction::I64Xor => sink.i64_xor(), + Instruction::I64Shl => sink.i64_shl(), + Instruction::I64ShrS => sink.i64_shr_s(), + Instruction::I64ShrU => sink.i64_shr_u(), + Instruction::I64Rotl => sink.i64_rotl(), + Instruction::I64Rotr => sink.i64_rotr(), + Instruction::F32Abs => sink.f32_abs(), + Instruction::F32Neg => sink.f32_neg(), + Instruction::F32Ceil => sink.f32_ceil(), + Instruction::F32Floor => sink.f32_floor(), + Instruction::F32Trunc => sink.f32_trunc(), + Instruction::F32Nearest => sink.f32_nearest(), + Instruction::F32Sqrt => sink.f32_sqrt(), + Instruction::F32Add => sink.f32_add(), + Instruction::F32Sub => sink.f32_sub(), + Instruction::F32Mul => sink.f32_mul(), + Instruction::F32Div => sink.f32_div(), + Instruction::F32Min => sink.f32_min(), + Instruction::F32Max => sink.f32_max(), + Instruction::F32Copysign => sink.f32_copysign(), + Instruction::F64Abs => sink.f64_abs(), + Instruction::F64Neg => sink.f64_neg(), + Instruction::F64Ceil => sink.f64_ceil(), + Instruction::F64Floor => sink.f64_floor(), + Instruction::F64Trunc => sink.f64_trunc(), + Instruction::F64Nearest => sink.f64_nearest(), + Instruction::F64Sqrt => sink.f64_sqrt(), + Instruction::F64Add => sink.f64_add(), + Instruction::F64Sub => sink.f64_sub(), + Instruction::F64Mul => sink.f64_mul(), + Instruction::F64Div => sink.f64_div(), + Instruction::F64Min => sink.f64_min(), + Instruction::F64Max => sink.f64_max(), + Instruction::F64Copysign => sink.f64_copysign(), + Instruction::I32WrapI64 => sink.i32_wrap_i64(), + Instruction::I32TruncF32S => sink.i32_trunc_f32_s(), + Instruction::I32TruncF32U => sink.i32_trunc_f32_u(), + Instruction::I32TruncF64S => sink.i32_trunc_f64_s(), + Instruction::I32TruncF64U => sink.i32_trunc_f64_u(), + Instruction::I64ExtendI32S => sink.i64_extend_i32_s(), + Instruction::I64ExtendI32U => sink.i64_extend_i32_u(), + Instruction::I64TruncF32S => sink.i64_trunc_f32_s(), + Instruction::I64TruncF32U => sink.i64_trunc_f32_u(), + Instruction::I64TruncF64S => sink.i64_trunc_f64_s(), + Instruction::I64TruncF64U => sink.i64_trunc_f64_u(), + Instruction::F32ConvertI32S => sink.f32_convert_i32_s(), + Instruction::F32ConvertI32U => sink.f32_convert_i32_u(), + Instruction::F32ConvertI64S => sink.f32_convert_i64_s(), + Instruction::F32ConvertI64U => sink.f32_convert_i64_u(), + Instruction::F32DemoteF64 => sink.f32_demote_f64(), + Instruction::F64ConvertI32S => sink.f64_convert_i32_s(), + Instruction::F64ConvertI32U => sink.f64_convert_i32_u(), + Instruction::F64ConvertI64S => sink.f64_convert_i64_s(), + Instruction::F64ConvertI64U => sink.f64_convert_i64_u(), + Instruction::F64PromoteF32 => sink.f64_promote_f32(), + Instruction::I32ReinterpretF32 => sink.i32_reinterpret_f32(), + Instruction::I64ReinterpretF64 => sink.i64_reinterpret_f64(), + Instruction::F32ReinterpretI32 => sink.f32_reinterpret_i32(), + Instruction::F64ReinterpretI64 => sink.f64_reinterpret_i64(), + Instruction::I32Extend8S => sink.i32_extend8_s(), + Instruction::I32Extend16S => sink.i32_extend16_s(), + Instruction::I64Extend8S => sink.i64_extend8_s(), + Instruction::I64Extend16S => sink.i64_extend16_s(), + Instruction::I64Extend32S => sink.i64_extend32_s(), + + Instruction::I32TruncSatF32S => sink.i32_trunc_sat_f32_s(), + Instruction::I32TruncSatF32U => sink.i32_trunc_sat_f32_u(), + Instruction::I32TruncSatF64S => sink.i32_trunc_sat_f64_s(), + Instruction::I32TruncSatF64U => sink.i32_trunc_sat_f64_u(), + Instruction::I64TruncSatF32S => sink.i64_trunc_sat_f32_s(), + Instruction::I64TruncSatF32U => sink.i64_trunc_sat_f32_u(), + Instruction::I64TruncSatF64S => sink.i64_trunc_sat_f64_s(), + Instruction::I64TruncSatF64U => sink.i64_trunc_sat_f64_u(), // Reference types instructions. - Instruction::RefNull(ty) => { - sink.push(0xd0); - ty.encode(sink); - } - Instruction::RefIsNull => sink.push(0xd1), - Instruction::RefFunc(f) => { - sink.push(0xd2); - f.encode(sink); - } - Instruction::RefEq => sink.push(0xd3), - Instruction::RefAsNonNull => sink.push(0xd4), + Instruction::RefNull(ty) => sink.ref_null(ty), + Instruction::RefIsNull => sink.ref_is_null(), + Instruction::RefFunc(f) => sink.ref_func(f), + Instruction::RefEq => sink.ref_eq(), + Instruction::RefAsNonNull => sink.ref_as_non_null(), // GC instructions. - Instruction::StructNew(type_index) => { - sink.push(0xfb); - sink.push(0x00); - type_index.encode(sink); - } - Instruction::StructNewDefault(type_index) => { - sink.push(0xfb); - sink.push(0x01); - type_index.encode(sink); - } + Instruction::StructNew(type_index) => sink.struct_new(type_index), + Instruction::StructNewDefault(type_index) => sink.struct_new_default(type_index), Instruction::StructGet { struct_type_index, field_index, - } => { - sink.push(0xfb); - sink.push(0x02); - struct_type_index.encode(sink); - field_index.encode(sink); - } + } => sink.struct_get(struct_type_index, field_index), Instruction::StructGetS { struct_type_index, field_index, - } => { - sink.push(0xfb); - sink.push(0x03); - struct_type_index.encode(sink); - field_index.encode(sink); - } + } => sink.struct_get_s(struct_type_index, field_index), Instruction::StructGetU { struct_type_index, field_index, - } => { - sink.push(0xfb); - sink.push(0x04); - struct_type_index.encode(sink); - field_index.encode(sink); - } + } => sink.struct_get_u(struct_type_index, field_index), Instruction::StructSet { struct_type_index, field_index, - } => { - sink.push(0xfb); - sink.push(0x05); - struct_type_index.encode(sink); - field_index.encode(sink); - } - Instruction::ArrayNew(type_index) => { - sink.push(0xfb); - sink.push(0x06); - type_index.encode(sink); - } - Instruction::ArrayNewDefault(type_index) => { - sink.push(0xfb); - sink.push(0x07); - type_index.encode(sink); + } => sink.struct_set(struct_type_index, field_index), + Instruction::StructNewDesc(type_index) => sink.struct_new_desc(type_index), + Instruction::StructNewDefaultDesc(type_index) => { + sink.struct_new_default_desc(type_index) } + Instruction::ArrayNew(type_index) => sink.array_new(type_index), + Instruction::ArrayNewDefault(type_index) => sink.array_new_default(type_index), Instruction::ArrayNewFixed { array_type_index, array_size, - } => { - sink.push(0xfb); - sink.push(0x08); - array_type_index.encode(sink); - array_size.encode(sink); - } + } => sink.array_new_fixed(array_type_index, array_size), Instruction::ArrayNewData { array_type_index, array_data_index, - } => { - sink.push(0xfb); - sink.push(0x09); - array_type_index.encode(sink); - array_data_index.encode(sink); - } + } => sink.array_new_data(array_type_index, array_data_index), Instruction::ArrayNewElem { array_type_index, array_elem_index, - } => { - sink.push(0xfb); - sink.push(0x0a); - array_type_index.encode(sink); - array_elem_index.encode(sink); - } - Instruction::ArrayGet(type_index) => { - sink.push(0xfb); - sink.push(0x0b); - type_index.encode(sink); - } - Instruction::ArrayGetS(type_index) => { - sink.push(0xfb); - sink.push(0x0c); - type_index.encode(sink); - } - Instruction::ArrayGetU(type_index) => { - sink.push(0xfb); - sink.push(0x0d); - type_index.encode(sink); - } - Instruction::ArraySet(type_index) => { - sink.push(0xfb); - sink.push(0x0e); - type_index.encode(sink); - } - Instruction::ArrayLen => { - sink.push(0xfb); - sink.push(0x0f); - } - Instruction::ArrayFill(type_index) => { - sink.push(0xfb); - sink.push(0x10); - type_index.encode(sink); - } + } => sink.array_new_elem(array_type_index, array_elem_index), + Instruction::ArrayGet(type_index) => sink.array_get(type_index), + Instruction::ArrayGetS(type_index) => sink.array_get_s(type_index), + Instruction::ArrayGetU(type_index) => sink.array_get_u(type_index), + Instruction::ArraySet(type_index) => sink.array_set(type_index), + Instruction::ArrayLen => sink.array_len(), + Instruction::ArrayFill(type_index) => sink.array_fill(type_index), Instruction::ArrayCopy { array_type_index_dst, array_type_index_src, - } => { - sink.push(0xfb); - sink.push(0x11); - array_type_index_dst.encode(sink); - array_type_index_src.encode(sink); - } + } => sink.array_copy(array_type_index_dst, array_type_index_src), Instruction::ArrayInitData { array_type_index, array_data_index, - } => { - sink.push(0xfb); - sink.push(0x12); - array_type_index.encode(sink); - array_data_index.encode(sink); - } + } => sink.array_init_data(array_type_index, array_data_index), Instruction::ArrayInitElem { array_type_index, array_elem_index, - } => { - sink.push(0xfb); - sink.push(0x13); - array_type_index.encode(sink); - array_elem_index.encode(sink); - } - Instruction::RefTestNonNull(heap_type) => { - sink.push(0xfb); - sink.push(0x14); - heap_type.encode(sink); - } - Instruction::RefTestNullable(heap_type) => { - sink.push(0xfb); - sink.push(0x15); - heap_type.encode(sink); - } - Instruction::RefCastNonNull(heap_type) => { - sink.push(0xfb); - sink.push(0x16); - heap_type.encode(sink); - } - Instruction::RefCastNullable(heap_type) => { - sink.push(0xfb); - sink.push(0x17); - heap_type.encode(sink); - } + } => sink.array_init_elem(array_type_index, array_elem_index), + Instruction::RefTestNonNull(heap_type) => sink.ref_test_non_null(heap_type), + Instruction::RefTestNullable(heap_type) => sink.ref_test_nullable(heap_type), + Instruction::RefCastNonNull(heap_type) => sink.ref_cast_non_null(heap_type), + Instruction::RefCastNullable(heap_type) => sink.ref_cast_nullable(heap_type), Instruction::BrOnCast { relative_depth, from_ref_type, to_ref_type, - } => { - sink.push(0xfb); - sink.push(0x18); - let cast_flags = - (from_ref_type.nullable as u8) | ((to_ref_type.nullable as u8) << 1); - sink.push(cast_flags); - relative_depth.encode(sink); - from_ref_type.heap_type.encode(sink); - to_ref_type.heap_type.encode(sink); - } + } => sink.br_on_cast(relative_depth, from_ref_type, to_ref_type), Instruction::BrOnCastFail { relative_depth, from_ref_type, to_ref_type, - } => { - sink.push(0xfb); - sink.push(0x19); - let cast_flags = - (from_ref_type.nullable as u8) | ((to_ref_type.nullable as u8) << 1); - sink.push(cast_flags); - relative_depth.encode(sink); - from_ref_type.heap_type.encode(sink); - to_ref_type.heap_type.encode(sink); - } - Instruction::AnyConvertExtern => { - sink.push(0xfb); - sink.push(0x1a); - } - Instruction::ExternConvertAny => { - sink.push(0xfb); - sink.push(0x1b); - } - Instruction::RefI31 => { - sink.push(0xfb); - sink.push(0x1c); - } - Instruction::I31GetS => { - sink.push(0xfb); - sink.push(0x1d); - } - Instruction::I31GetU => { - sink.push(0xfb); - sink.push(0x1e); - } + } => sink.br_on_cast_fail(relative_depth, from_ref_type, to_ref_type), + Instruction::AnyConvertExtern => sink.any_convert_extern(), + Instruction::ExternConvertAny => sink.extern_convert_any(), + Instruction::RefI31 => sink.ref_i31(), + Instruction::I31GetS => sink.i31_get_s(), + Instruction::I31GetU => sink.i31_get_u(), // Bulk memory instructions. - Instruction::TableInit { elem_index, table } => { - sink.push(0xfc); - sink.push(0x0c); - elem_index.encode(sink); - table.encode(sink); - } - Instruction::ElemDrop(segment) => { - sink.push(0xfc); - sink.push(0x0d); - segment.encode(sink); - } + Instruction::TableInit { elem_index, table } => sink.table_init(table, elem_index), + Instruction::ElemDrop(segment) => sink.elem_drop(segment), Instruction::TableCopy { src_table, dst_table, - } => { - sink.push(0xfc); - sink.push(0x0e); - dst_table.encode(sink); - src_table.encode(sink); - } - Instruction::TableGrow(table) => { - sink.push(0xfc); - sink.push(0x0f); - table.encode(sink); - } - Instruction::TableSize(table) => { - sink.push(0xfc); - sink.push(0x10); - table.encode(sink); - } - Instruction::TableFill(table) => { - sink.push(0xfc); - sink.push(0x11); - table.encode(sink); - } + } => sink.table_copy(dst_table, src_table), + Instruction::TableGrow(table) => sink.table_grow(table), + Instruction::TableSize(table) => sink.table_size(table), + Instruction::TableFill(table) => sink.table_fill(table), // SIMD instructions. - Instruction::V128Load(memarg) => { - sink.push(0xFD); - 0x00u32.encode(sink); - memarg.encode(sink); - } - Instruction::V128Load8x8S(memarg) => { - sink.push(0xFD); - 0x01u32.encode(sink); - memarg.encode(sink); - } - Instruction::V128Load8x8U(memarg) => { - sink.push(0xFD); - 0x02u32.encode(sink); - memarg.encode(sink); - } - Instruction::V128Load16x4S(memarg) => { - sink.push(0xFD); - 0x03u32.encode(sink); - memarg.encode(sink); - } - Instruction::V128Load16x4U(memarg) => { - sink.push(0xFD); - 0x04u32.encode(sink); - memarg.encode(sink); - } - Instruction::V128Load32x2S(memarg) => { - sink.push(0xFD); - 0x05u32.encode(sink); - memarg.encode(sink); - } - Instruction::V128Load32x2U(memarg) => { - sink.push(0xFD); - 0x06u32.encode(sink); - memarg.encode(sink); - } - Instruction::V128Load8Splat(memarg) => { - sink.push(0xFD); - 0x07u32.encode(sink); - memarg.encode(sink); - } - Instruction::V128Load16Splat(memarg) => { - sink.push(0xFD); - 0x08u32.encode(sink); - memarg.encode(sink); - } - Instruction::V128Load32Splat(memarg) => { - sink.push(0xFD); - 0x09u32.encode(sink); - memarg.encode(sink); - } - Instruction::V128Load64Splat(memarg) => { - sink.push(0xFD); - 0x0Au32.encode(sink); - memarg.encode(sink); - } - Instruction::V128Store(memarg) => { - sink.push(0xFD); - 0x0Bu32.encode(sink); - memarg.encode(sink); - } - Instruction::V128Const(x) => { - sink.push(0xFD); - 0x0Cu32.encode(sink); - sink.extend(x.to_le_bytes().iter().copied()); - } - Instruction::I8x16Shuffle(lanes) => { - sink.push(0xFD); - 0x0Du32.encode(sink); - assert!(lanes.iter().all(|l: &u8| *l < 32)); - sink.extend(lanes.iter().copied()); - } - Instruction::I8x16Swizzle => { - sink.push(0xFD); - 0x0Eu32.encode(sink); - } - Instruction::I8x16Splat => { - sink.push(0xFD); - 0x0Fu32.encode(sink); - } - Instruction::I16x8Splat => { - sink.push(0xFD); - 0x10u32.encode(sink); - } - Instruction::I32x4Splat => { - sink.push(0xFD); - 0x11u32.encode(sink); - } - Instruction::I64x2Splat => { - sink.push(0xFD); - 0x12u32.encode(sink); - } - Instruction::F32x4Splat => { - sink.push(0xFD); - 0x13u32.encode(sink); - } - Instruction::F64x2Splat => { - sink.push(0xFD); - 0x14u32.encode(sink); - } - Instruction::I8x16ExtractLaneS(lane) => { - sink.push(0xFD); - 0x15u32.encode(sink); - assert!(lane < 16); - sink.push(lane); - } - Instruction::I8x16ExtractLaneU(lane) => { - sink.push(0xFD); - 0x16u32.encode(sink); - assert!(lane < 16); - sink.push(lane); - } - Instruction::I8x16ReplaceLane(lane) => { - sink.push(0xFD); - 0x17u32.encode(sink); - assert!(lane < 16); - sink.push(lane); - } - Instruction::I16x8ExtractLaneS(lane) => { - sink.push(0xFD); - 0x18u32.encode(sink); - assert!(lane < 8); - sink.push(lane); - } - Instruction::I16x8ExtractLaneU(lane) => { - sink.push(0xFD); - 0x19u32.encode(sink); - assert!(lane < 8); - sink.push(lane); - } - Instruction::I16x8ReplaceLane(lane) => { - sink.push(0xFD); - 0x1Au32.encode(sink); - assert!(lane < 8); - sink.push(lane); - } - Instruction::I32x4ExtractLane(lane) => { - sink.push(0xFD); - 0x1Bu32.encode(sink); - assert!(lane < 4); - sink.push(lane); - } - Instruction::I32x4ReplaceLane(lane) => { - sink.push(0xFD); - 0x1Cu32.encode(sink); - assert!(lane < 4); - sink.push(lane); - } - Instruction::I64x2ExtractLane(lane) => { - sink.push(0xFD); - 0x1Du32.encode(sink); - assert!(lane < 2); - sink.push(lane); - } - Instruction::I64x2ReplaceLane(lane) => { - sink.push(0xFD); - 0x1Eu32.encode(sink); - assert!(lane < 2); - sink.push(lane); - } - Instruction::F32x4ExtractLane(lane) => { - sink.push(0xFD); - 0x1Fu32.encode(sink); - assert!(lane < 4); - sink.push(lane); - } - Instruction::F32x4ReplaceLane(lane) => { - sink.push(0xFD); - 0x20u32.encode(sink); - assert!(lane < 4); - sink.push(lane); - } - Instruction::F64x2ExtractLane(lane) => { - sink.push(0xFD); - 0x21u32.encode(sink); - assert!(lane < 2); - sink.push(lane); - } - Instruction::F64x2ReplaceLane(lane) => { - sink.push(0xFD); - 0x22u32.encode(sink); - assert!(lane < 2); - sink.push(lane); - } - - Instruction::I8x16Eq => { - sink.push(0xFD); - 0x23u32.encode(sink); - } - Instruction::I8x16Ne => { - sink.push(0xFD); - 0x24u32.encode(sink); - } - Instruction::I8x16LtS => { - sink.push(0xFD); - 0x25u32.encode(sink); - } - Instruction::I8x16LtU => { - sink.push(0xFD); - 0x26u32.encode(sink); - } - Instruction::I8x16GtS => { - sink.push(0xFD); - 0x27u32.encode(sink); - } - Instruction::I8x16GtU => { - sink.push(0xFD); - 0x28u32.encode(sink); - } - Instruction::I8x16LeS => { - sink.push(0xFD); - 0x29u32.encode(sink); - } - Instruction::I8x16LeU => { - sink.push(0xFD); - 0x2Au32.encode(sink); - } - Instruction::I8x16GeS => { - sink.push(0xFD); - 0x2Bu32.encode(sink); - } - Instruction::I8x16GeU => { - sink.push(0xFD); - 0x2Cu32.encode(sink); - } - Instruction::I16x8Eq => { - sink.push(0xFD); - 0x2Du32.encode(sink); - } - Instruction::I16x8Ne => { - sink.push(0xFD); - 0x2Eu32.encode(sink); - } - Instruction::I16x8LtS => { - sink.push(0xFD); - 0x2Fu32.encode(sink); - } - Instruction::I16x8LtU => { - sink.push(0xFD); - 0x30u32.encode(sink); - } - Instruction::I16x8GtS => { - sink.push(0xFD); - 0x31u32.encode(sink); - } - Instruction::I16x8GtU => { - sink.push(0xFD); - 0x32u32.encode(sink); - } - Instruction::I16x8LeS => { - sink.push(0xFD); - 0x33u32.encode(sink); - } - Instruction::I16x8LeU => { - sink.push(0xFD); - 0x34u32.encode(sink); - } - Instruction::I16x8GeS => { - sink.push(0xFD); - 0x35u32.encode(sink); - } - Instruction::I16x8GeU => { - sink.push(0xFD); - 0x36u32.encode(sink); - } - Instruction::I32x4Eq => { - sink.push(0xFD); - 0x37u32.encode(sink); - } - Instruction::I32x4Ne => { - sink.push(0xFD); - 0x38u32.encode(sink); - } - Instruction::I32x4LtS => { - sink.push(0xFD); - 0x39u32.encode(sink); - } - Instruction::I32x4LtU => { - sink.push(0xFD); - 0x3Au32.encode(sink); - } - Instruction::I32x4GtS => { - sink.push(0xFD); - 0x3Bu32.encode(sink); - } - Instruction::I32x4GtU => { - sink.push(0xFD); - 0x3Cu32.encode(sink); - } - Instruction::I32x4LeS => { - sink.push(0xFD); - 0x3Du32.encode(sink); - } - Instruction::I32x4LeU => { - sink.push(0xFD); - 0x3Eu32.encode(sink); - } - Instruction::I32x4GeS => { - sink.push(0xFD); - 0x3Fu32.encode(sink); - } - Instruction::I32x4GeU => { - sink.push(0xFD); - 0x40u32.encode(sink); - } - Instruction::F32x4Eq => { - sink.push(0xFD); - 0x41u32.encode(sink); - } - Instruction::F32x4Ne => { - sink.push(0xFD); - 0x42u32.encode(sink); - } - Instruction::F32x4Lt => { - sink.push(0xFD); - 0x43u32.encode(sink); - } - Instruction::F32x4Gt => { - sink.push(0xFD); - 0x44u32.encode(sink); - } - Instruction::F32x4Le => { - sink.push(0xFD); - 0x45u32.encode(sink); - } - Instruction::F32x4Ge => { - sink.push(0xFD); - 0x46u32.encode(sink); - } - Instruction::F64x2Eq => { - sink.push(0xFD); - 0x47u32.encode(sink); - } - Instruction::F64x2Ne => { - sink.push(0xFD); - 0x48u32.encode(sink); - } - Instruction::F64x2Lt => { - sink.push(0xFD); - 0x49u32.encode(sink); - } - Instruction::F64x2Gt => { - sink.push(0xFD); - 0x4Au32.encode(sink); - } - Instruction::F64x2Le => { - sink.push(0xFD); - 0x4Bu32.encode(sink); - } - Instruction::F64x2Ge => { - sink.push(0xFD); - 0x4Cu32.encode(sink); - } - Instruction::V128Not => { - sink.push(0xFD); - 0x4Du32.encode(sink); - } - Instruction::V128And => { - sink.push(0xFD); - 0x4Eu32.encode(sink); - } - Instruction::V128AndNot => { - sink.push(0xFD); - 0x4Fu32.encode(sink); - } - Instruction::V128Or => { - sink.push(0xFD); - 0x50u32.encode(sink); - } - Instruction::V128Xor => { - sink.push(0xFD); - 0x51u32.encode(sink); - } - Instruction::V128Bitselect => { - sink.push(0xFD); - 0x52u32.encode(sink); - } - Instruction::V128AnyTrue => { - sink.push(0xFD); - 0x53u32.encode(sink); - } - Instruction::I8x16Abs => { - sink.push(0xFD); - 0x60u32.encode(sink); - } - Instruction::I8x16Neg => { - sink.push(0xFD); - 0x61u32.encode(sink); - } - Instruction::I8x16Popcnt => { - sink.push(0xFD); - 0x62u32.encode(sink); - } - Instruction::I8x16AllTrue => { - sink.push(0xFD); - 0x63u32.encode(sink); - } - Instruction::I8x16Bitmask => { - sink.push(0xFD); - 0x64u32.encode(sink); - } - Instruction::I8x16NarrowI16x8S => { - sink.push(0xFD); - 0x65u32.encode(sink); - } - Instruction::I8x16NarrowI16x8U => { - sink.push(0xFD); - 0x66u32.encode(sink); - } - Instruction::I8x16Shl => { - sink.push(0xFD); - 0x6bu32.encode(sink); - } - Instruction::I8x16ShrS => { - sink.push(0xFD); - 0x6cu32.encode(sink); - } - Instruction::I8x16ShrU => { - sink.push(0xFD); - 0x6du32.encode(sink); - } - Instruction::I8x16Add => { - sink.push(0xFD); - 0x6eu32.encode(sink); - } - Instruction::I8x16AddSatS => { - sink.push(0xFD); - 0x6fu32.encode(sink); - } - Instruction::I8x16AddSatU => { - sink.push(0xFD); - 0x70u32.encode(sink); - } - Instruction::I8x16Sub => { - sink.push(0xFD); - 0x71u32.encode(sink); - } - Instruction::I8x16SubSatS => { - sink.push(0xFD); - 0x72u32.encode(sink); - } - Instruction::I8x16SubSatU => { - sink.push(0xFD); - 0x73u32.encode(sink); - } - Instruction::I8x16MinS => { - sink.push(0xFD); - 0x76u32.encode(sink); - } - Instruction::I8x16MinU => { - sink.push(0xFD); - 0x77u32.encode(sink); - } - Instruction::I8x16MaxS => { - sink.push(0xFD); - 0x78u32.encode(sink); - } - Instruction::I8x16MaxU => { - sink.push(0xFD); - 0x79u32.encode(sink); - } - Instruction::I8x16AvgrU => { - sink.push(0xFD); - 0x7Bu32.encode(sink); - } - Instruction::I16x8ExtAddPairwiseI8x16S => { - sink.push(0xFD); - 0x7Cu32.encode(sink); - } - Instruction::I16x8ExtAddPairwiseI8x16U => { - sink.push(0xFD); - 0x7Du32.encode(sink); - } - Instruction::I32x4ExtAddPairwiseI16x8S => { - sink.push(0xFD); - 0x7Eu32.encode(sink); - } - Instruction::I32x4ExtAddPairwiseI16x8U => { - sink.push(0xFD); - 0x7Fu32.encode(sink); - } - Instruction::I16x8Abs => { - sink.push(0xFD); - 0x80u32.encode(sink); - } - Instruction::I16x8Neg => { - sink.push(0xFD); - 0x81u32.encode(sink); - } - Instruction::I16x8Q15MulrSatS => { - sink.push(0xFD); - 0x82u32.encode(sink); - } - Instruction::I16x8AllTrue => { - sink.push(0xFD); - 0x83u32.encode(sink); - } - Instruction::I16x8Bitmask => { - sink.push(0xFD); - 0x84u32.encode(sink); - } - Instruction::I16x8NarrowI32x4S => { - sink.push(0xFD); - 0x85u32.encode(sink); - } - Instruction::I16x8NarrowI32x4U => { - sink.push(0xFD); - 0x86u32.encode(sink); - } - Instruction::I16x8ExtendLowI8x16S => { - sink.push(0xFD); - 0x87u32.encode(sink); - } - Instruction::I16x8ExtendHighI8x16S => { - sink.push(0xFD); - 0x88u32.encode(sink); - } - Instruction::I16x8ExtendLowI8x16U => { - sink.push(0xFD); - 0x89u32.encode(sink); - } - Instruction::I16x8ExtendHighI8x16U => { - sink.push(0xFD); - 0x8Au32.encode(sink); - } - Instruction::I16x8Shl => { - sink.push(0xFD); - 0x8Bu32.encode(sink); - } - Instruction::I16x8ShrS => { - sink.push(0xFD); - 0x8Cu32.encode(sink); - } - Instruction::I16x8ShrU => { - sink.push(0xFD); - 0x8Du32.encode(sink); - } - Instruction::I16x8Add => { - sink.push(0xFD); - 0x8Eu32.encode(sink); - } - Instruction::I16x8AddSatS => { - sink.push(0xFD); - 0x8Fu32.encode(sink); - } - Instruction::I16x8AddSatU => { - sink.push(0xFD); - 0x90u32.encode(sink); - } - Instruction::I16x8Sub => { - sink.push(0xFD); - 0x91u32.encode(sink); - } - Instruction::I16x8SubSatS => { - sink.push(0xFD); - 0x92u32.encode(sink); - } - Instruction::I16x8SubSatU => { - sink.push(0xFD); - 0x93u32.encode(sink); - } - Instruction::I16x8Mul => { - sink.push(0xFD); - 0x95u32.encode(sink); - } - Instruction::I16x8MinS => { - sink.push(0xFD); - 0x96u32.encode(sink); - } - Instruction::I16x8MinU => { - sink.push(0xFD); - 0x97u32.encode(sink); - } - Instruction::I16x8MaxS => { - sink.push(0xFD); - 0x98u32.encode(sink); - } - Instruction::I16x8MaxU => { - sink.push(0xFD); - 0x99u32.encode(sink); - } - Instruction::I16x8AvgrU => { - sink.push(0xFD); - 0x9Bu32.encode(sink); - } - Instruction::I16x8ExtMulLowI8x16S => { - sink.push(0xFD); - 0x9Cu32.encode(sink); - } - Instruction::I16x8ExtMulHighI8x16S => { - sink.push(0xFD); - 0x9Du32.encode(sink); - } - Instruction::I16x8ExtMulLowI8x16U => { - sink.push(0xFD); - 0x9Eu32.encode(sink); - } - Instruction::I16x8ExtMulHighI8x16U => { - sink.push(0xFD); - 0x9Fu32.encode(sink); - } - Instruction::I32x4Abs => { - sink.push(0xFD); - 0xA0u32.encode(sink); - } - Instruction::I32x4Neg => { - sink.push(0xFD); - 0xA1u32.encode(sink); - } - Instruction::I32x4AllTrue => { - sink.push(0xFD); - 0xA3u32.encode(sink); - } - Instruction::I32x4Bitmask => { - sink.push(0xFD); - 0xA4u32.encode(sink); - } - Instruction::I32x4ExtendLowI16x8S => { - sink.push(0xFD); - 0xA7u32.encode(sink); - } - Instruction::I32x4ExtendHighI16x8S => { - sink.push(0xFD); - 0xA8u32.encode(sink); - } - Instruction::I32x4ExtendLowI16x8U => { - sink.push(0xFD); - 0xA9u32.encode(sink); - } - Instruction::I32x4ExtendHighI16x8U => { - sink.push(0xFD); - 0xAAu32.encode(sink); - } - Instruction::I32x4Shl => { - sink.push(0xFD); - 0xABu32.encode(sink); - } - Instruction::I32x4ShrS => { - sink.push(0xFD); - 0xACu32.encode(sink); - } - Instruction::I32x4ShrU => { - sink.push(0xFD); - 0xADu32.encode(sink); - } - Instruction::I32x4Add => { - sink.push(0xFD); - 0xAEu32.encode(sink); - } - Instruction::I32x4Sub => { - sink.push(0xFD); - 0xB1u32.encode(sink); - } - Instruction::I32x4Mul => { - sink.push(0xFD); - 0xB5u32.encode(sink); - } - Instruction::I32x4MinS => { - sink.push(0xFD); - 0xB6u32.encode(sink); - } - Instruction::I32x4MinU => { - sink.push(0xFD); - 0xB7u32.encode(sink); - } - Instruction::I32x4MaxS => { - sink.push(0xFD); - 0xB8u32.encode(sink); - } - Instruction::I32x4MaxU => { - sink.push(0xFD); - 0xB9u32.encode(sink); - } - Instruction::I32x4DotI16x8S => { - sink.push(0xFD); - 0xBAu32.encode(sink); - } - Instruction::I32x4ExtMulLowI16x8S => { - sink.push(0xFD); - 0xBCu32.encode(sink); - } - Instruction::I32x4ExtMulHighI16x8S => { - sink.push(0xFD); - 0xBDu32.encode(sink); - } - Instruction::I32x4ExtMulLowI16x8U => { - sink.push(0xFD); - 0xBEu32.encode(sink); - } - Instruction::I32x4ExtMulHighI16x8U => { - sink.push(0xFD); - 0xBFu32.encode(sink); - } - Instruction::I64x2Abs => { - sink.push(0xFD); - 0xC0u32.encode(sink); - } - Instruction::I64x2Neg => { - sink.push(0xFD); - 0xC1u32.encode(sink); - } - Instruction::I64x2AllTrue => { - sink.push(0xFD); - 0xC3u32.encode(sink); - } - Instruction::I64x2Bitmask => { - sink.push(0xFD); - 0xC4u32.encode(sink); - } - Instruction::I64x2ExtendLowI32x4S => { - sink.push(0xFD); - 0xC7u32.encode(sink); - } - Instruction::I64x2ExtendHighI32x4S => { - sink.push(0xFD); - 0xC8u32.encode(sink); - } - Instruction::I64x2ExtendLowI32x4U => { - sink.push(0xFD); - 0xC9u32.encode(sink); - } - Instruction::I64x2ExtendHighI32x4U => { - sink.push(0xFD); - 0xCAu32.encode(sink); - } - Instruction::I64x2Shl => { - sink.push(0xFD); - 0xCBu32.encode(sink); - } - Instruction::I64x2ShrS => { - sink.push(0xFD); - 0xCCu32.encode(sink); - } - Instruction::I64x2ShrU => { - sink.push(0xFD); - 0xCDu32.encode(sink); - } - Instruction::I64x2Add => { - sink.push(0xFD); - 0xCEu32.encode(sink); - } - Instruction::I64x2Sub => { - sink.push(0xFD); - 0xD1u32.encode(sink); - } - Instruction::I64x2Mul => { - sink.push(0xFD); - 0xD5u32.encode(sink); - } - Instruction::I64x2ExtMulLowI32x4S => { - sink.push(0xFD); - 0xDCu32.encode(sink); - } - Instruction::I64x2ExtMulHighI32x4S => { - sink.push(0xFD); - 0xDDu32.encode(sink); - } - Instruction::I64x2ExtMulLowI32x4U => { - sink.push(0xFD); - 0xDEu32.encode(sink); - } - Instruction::I64x2ExtMulHighI32x4U => { - sink.push(0xFD); - 0xDFu32.encode(sink); - } - Instruction::F32x4Ceil => { - sink.push(0xFD); - 0x67u32.encode(sink); - } - Instruction::F32x4Floor => { - sink.push(0xFD); - 0x68u32.encode(sink); - } - Instruction::F32x4Trunc => { - sink.push(0xFD); - 0x69u32.encode(sink); - } - Instruction::F32x4Nearest => { - sink.push(0xFD); - 0x6Au32.encode(sink); - } - Instruction::F32x4Abs => { - sink.push(0xFD); - 0xE0u32.encode(sink); - } - Instruction::F32x4Neg => { - sink.push(0xFD); - 0xE1u32.encode(sink); - } - Instruction::F32x4Sqrt => { - sink.push(0xFD); - 0xE3u32.encode(sink); - } - Instruction::F32x4Add => { - sink.push(0xFD); - 0xE4u32.encode(sink); - } - Instruction::F32x4Sub => { - sink.push(0xFD); - 0xE5u32.encode(sink); - } - Instruction::F32x4Mul => { - sink.push(0xFD); - 0xE6u32.encode(sink); - } - Instruction::F32x4Div => { - sink.push(0xFD); - 0xE7u32.encode(sink); - } - Instruction::F32x4Min => { - sink.push(0xFD); - 0xE8u32.encode(sink); - } - Instruction::F32x4Max => { - sink.push(0xFD); - 0xE9u32.encode(sink); - } - Instruction::F32x4PMin => { - sink.push(0xFD); - 0xEAu32.encode(sink); - } - Instruction::F32x4PMax => { - sink.push(0xFD); - 0xEBu32.encode(sink); - } - Instruction::F64x2Ceil => { - sink.push(0xFD); - 0x74u32.encode(sink); - } - Instruction::F64x2Floor => { - sink.push(0xFD); - 0x75u32.encode(sink); - } - Instruction::F64x2Trunc => { - sink.push(0xFD); - 0x7Au32.encode(sink); - } - Instruction::F64x2Nearest => { - sink.push(0xFD); - 0x94u32.encode(sink); - } - Instruction::F64x2Abs => { - sink.push(0xFD); - 0xECu32.encode(sink); - } - Instruction::F64x2Neg => { - sink.push(0xFD); - 0xEDu32.encode(sink); - } - Instruction::F64x2Sqrt => { - sink.push(0xFD); - 0xEFu32.encode(sink); - } - Instruction::F64x2Add => { - sink.push(0xFD); - 0xF0u32.encode(sink); - } - Instruction::F64x2Sub => { - sink.push(0xFD); - 0xF1u32.encode(sink); - } - Instruction::F64x2Mul => { - sink.push(0xFD); - 0xF2u32.encode(sink); - } - Instruction::F64x2Div => { - sink.push(0xFD); - 0xF3u32.encode(sink); - } - Instruction::F64x2Min => { - sink.push(0xFD); - 0xF4u32.encode(sink); - } - Instruction::F64x2Max => { - sink.push(0xFD); - 0xF5u32.encode(sink); - } - Instruction::F64x2PMin => { - sink.push(0xFD); - 0xF6u32.encode(sink); - } - Instruction::F64x2PMax => { - sink.push(0xFD); - 0xF7u32.encode(sink); - } - Instruction::I32x4TruncSatF32x4S => { - sink.push(0xFD); - 0xF8u32.encode(sink); - } - Instruction::I32x4TruncSatF32x4U => { - sink.push(0xFD); - 0xF9u32.encode(sink); - } - Instruction::F32x4ConvertI32x4S => { - sink.push(0xFD); - 0xFAu32.encode(sink); - } - Instruction::F32x4ConvertI32x4U => { - sink.push(0xFD); - 0xFBu32.encode(sink); - } - Instruction::I32x4TruncSatF64x2SZero => { - sink.push(0xFD); - 0xFCu32.encode(sink); - } - Instruction::I32x4TruncSatF64x2UZero => { - sink.push(0xFD); - 0xFDu32.encode(sink); - } - Instruction::F64x2ConvertLowI32x4S => { - sink.push(0xFD); - 0xFEu32.encode(sink); - } - Instruction::F64x2ConvertLowI32x4U => { - sink.push(0xFD); - 0xFFu32.encode(sink); - } - Instruction::F32x4DemoteF64x2Zero => { - sink.push(0xFD); - 0x5Eu32.encode(sink); - } - Instruction::F64x2PromoteLowF32x4 => { - sink.push(0xFD); - 0x5Fu32.encode(sink); - } - Instruction::V128Load32Zero(memarg) => { - sink.push(0xFD); - 0x5Cu32.encode(sink); - memarg.encode(sink); - } - Instruction::V128Load64Zero(memarg) => { - sink.push(0xFD); - 0x5Du32.encode(sink); - memarg.encode(sink); - } - Instruction::V128Load8Lane { memarg, lane } => { - sink.push(0xFD); - 0x54u32.encode(sink); - memarg.encode(sink); - assert!(lane < 16); - sink.push(lane); - } - Instruction::V128Load16Lane { memarg, lane } => { - sink.push(0xFD); - 0x55u32.encode(sink); - memarg.encode(sink); - assert!(lane < 8); - sink.push(lane); - } - Instruction::V128Load32Lane { memarg, lane } => { - sink.push(0xFD); - 0x56u32.encode(sink); - memarg.encode(sink); - assert!(lane < 4); - sink.push(lane); - } - Instruction::V128Load64Lane { memarg, lane } => { - sink.push(0xFD); - 0x57u32.encode(sink); - memarg.encode(sink); - assert!(lane < 2); - sink.push(lane); - } - Instruction::V128Store8Lane { memarg, lane } => { - sink.push(0xFD); - 0x58u32.encode(sink); - memarg.encode(sink); - assert!(lane < 16); - sink.push(lane); - } - Instruction::V128Store16Lane { memarg, lane } => { - sink.push(0xFD); - 0x59u32.encode(sink); - memarg.encode(sink); - assert!(lane < 8); - sink.push(lane); - } - Instruction::V128Store32Lane { memarg, lane } => { - sink.push(0xFD); - 0x5Au32.encode(sink); - memarg.encode(sink); - assert!(lane < 4); - sink.push(lane); - } - Instruction::V128Store64Lane { memarg, lane } => { - sink.push(0xFD); - 0x5Bu32.encode(sink); - memarg.encode(sink); - assert!(lane < 2); - sink.push(lane); - } - Instruction::I64x2Eq => { - sink.push(0xFD); - 0xD6u32.encode(sink); - } - Instruction::I64x2Ne => { - sink.push(0xFD); - 0xD7u32.encode(sink); - } - Instruction::I64x2LtS => { - sink.push(0xFD); - 0xD8u32.encode(sink); - } - Instruction::I64x2GtS => { - sink.push(0xFD); - 0xD9u32.encode(sink); - } - Instruction::I64x2LeS => { - sink.push(0xFD); - 0xDAu32.encode(sink); - } - Instruction::I64x2GeS => { - sink.push(0xFD); - 0xDBu32.encode(sink); - } - Instruction::I8x16RelaxedSwizzle => { - sink.push(0xFD); - 0x100u32.encode(sink); - } - Instruction::I32x4RelaxedTruncF32x4S => { - sink.push(0xFD); - 0x101u32.encode(sink); - } - Instruction::I32x4RelaxedTruncF32x4U => { - sink.push(0xFD); - 0x102u32.encode(sink); - } - Instruction::I32x4RelaxedTruncF64x2SZero => { - sink.push(0xFD); - 0x103u32.encode(sink); - } - Instruction::I32x4RelaxedTruncF64x2UZero => { - sink.push(0xFD); - 0x104u32.encode(sink); - } - Instruction::F32x4RelaxedMadd => { - sink.push(0xFD); - 0x105u32.encode(sink); - } - Instruction::F32x4RelaxedNmadd => { - sink.push(0xFD); - 0x106u32.encode(sink); - } - Instruction::F64x2RelaxedMadd => { - sink.push(0xFD); - 0x107u32.encode(sink); - } - Instruction::F64x2RelaxedNmadd => { - sink.push(0xFD); - 0x108u32.encode(sink); - } - Instruction::I8x16RelaxedLaneselect => { - sink.push(0xFD); - 0x109u32.encode(sink); - } - Instruction::I16x8RelaxedLaneselect => { - sink.push(0xFD); - 0x10Au32.encode(sink); - } - Instruction::I32x4RelaxedLaneselect => { - sink.push(0xFD); - 0x10Bu32.encode(sink); - } - Instruction::I64x2RelaxedLaneselect => { - sink.push(0xFD); - 0x10Cu32.encode(sink); - } - Instruction::F32x4RelaxedMin => { - sink.push(0xFD); - 0x10Du32.encode(sink); - } - Instruction::F32x4RelaxedMax => { - sink.push(0xFD); - 0x10Eu32.encode(sink); - } - Instruction::F64x2RelaxedMin => { - sink.push(0xFD); - 0x10Fu32.encode(sink); - } - Instruction::F64x2RelaxedMax => { - sink.push(0xFD); - 0x110u32.encode(sink); - } - Instruction::I16x8RelaxedQ15mulrS => { - sink.push(0xFD); - 0x111u32.encode(sink); - } - Instruction::I16x8RelaxedDotI8x16I7x16S => { - sink.push(0xFD); - 0x112u32.encode(sink); - } - Instruction::I32x4RelaxedDotI8x16I7x16AddS => { - sink.push(0xFD); - 0x113u32.encode(sink); + Instruction::V128Load(memarg) => sink.v128_load(memarg), + Instruction::V128Load8x8S(memarg) => sink.v128_load8x8_s(memarg), + Instruction::V128Load8x8U(memarg) => sink.v128_load8x8_u(memarg), + Instruction::V128Load16x4S(memarg) => sink.v128_load16x4_s(memarg), + Instruction::V128Load16x4U(memarg) => sink.v128_load16x4_u(memarg), + Instruction::V128Load32x2S(memarg) => sink.v128_load32x2_s(memarg), + Instruction::V128Load32x2U(memarg) => sink.v128_load32x2_u(memarg), + Instruction::V128Load8Splat(memarg) => sink.v128_load8_splat(memarg), + Instruction::V128Load16Splat(memarg) => sink.v128_load16_splat(memarg), + Instruction::V128Load32Splat(memarg) => sink.v128_load32_splat(memarg), + Instruction::V128Load64Splat(memarg) => sink.v128_load64_splat(memarg), + Instruction::V128Store(memarg) => sink.v128_store(memarg), + Instruction::V128Const(x) => sink.v128_const(x), + Instruction::I8x16Shuffle(lanes) => sink.i8x16_shuffle(lanes), + Instruction::I8x16Swizzle => sink.i8x16_swizzle(), + Instruction::I8x16Splat => sink.i8x16_splat(), + Instruction::I16x8Splat => sink.i16x8_splat(), + Instruction::I32x4Splat => sink.i32x4_splat(), + Instruction::I64x2Splat => sink.i64x2_splat(), + Instruction::F32x4Splat => sink.f32x4_splat(), + Instruction::F64x2Splat => sink.f64x2_splat(), + Instruction::I8x16ExtractLaneS(lane) => sink.i8x16_extract_lane_s(lane), + Instruction::I8x16ExtractLaneU(lane) => sink.i8x16_extract_lane_u(lane), + Instruction::I8x16ReplaceLane(lane) => sink.i8x16_replace_lane(lane), + Instruction::I16x8ExtractLaneS(lane) => sink.i16x8_extract_lane_s(lane), + Instruction::I16x8ExtractLaneU(lane) => sink.i16x8_extract_lane_u(lane), + Instruction::I16x8ReplaceLane(lane) => sink.i16x8_replace_lane(lane), + Instruction::I32x4ExtractLane(lane) => sink.i32x4_extract_lane(lane), + Instruction::I32x4ReplaceLane(lane) => sink.i32x4_replace_lane(lane), + Instruction::I64x2ExtractLane(lane) => sink.i64x2_extract_lane(lane), + Instruction::I64x2ReplaceLane(lane) => sink.i64x2_replace_lane(lane), + Instruction::F32x4ExtractLane(lane) => sink.f32x4_extract_lane(lane), + Instruction::F32x4ReplaceLane(lane) => sink.f32x4_replace_lane(lane), + Instruction::F64x2ExtractLane(lane) => sink.f64x2_extract_lane(lane), + Instruction::F64x2ReplaceLane(lane) => sink.f64x2_replace_lane(lane), + + Instruction::I8x16Eq => sink.i8x16_eq(), + Instruction::I8x16Ne => sink.i8x16_ne(), + Instruction::I8x16LtS => sink.i8x16_lt_s(), + Instruction::I8x16LtU => sink.i8x16_lt_u(), + Instruction::I8x16GtS => sink.i8x16_gt_s(), + Instruction::I8x16GtU => sink.i8x16_gt_u(), + Instruction::I8x16LeS => sink.i8x16_le_s(), + Instruction::I8x16LeU => sink.i8x16_le_u(), + Instruction::I8x16GeS => sink.i8x16_ge_s(), + Instruction::I8x16GeU => sink.i8x16_ge_u(), + Instruction::I16x8Eq => sink.i16x8_eq(), + Instruction::I16x8Ne => sink.i16x8_ne(), + Instruction::I16x8LtS => sink.i16x8_lt_s(), + Instruction::I16x8LtU => sink.i16x8_lt_u(), + Instruction::I16x8GtS => sink.i16x8_gt_s(), + Instruction::I16x8GtU => sink.i16x8_gt_u(), + Instruction::I16x8LeS => sink.i16x8_le_s(), + Instruction::I16x8LeU => sink.i16x8_le_u(), + Instruction::I16x8GeS => sink.i16x8_ge_s(), + Instruction::I16x8GeU => sink.i16x8_ge_u(), + Instruction::I32x4Eq => sink.i32x4_eq(), + Instruction::I32x4Ne => sink.i32x4_ne(), + Instruction::I32x4LtS => sink.i32x4_lt_s(), + Instruction::I32x4LtU => sink.i32x4_lt_u(), + Instruction::I32x4GtS => sink.i32x4_gt_s(), + Instruction::I32x4GtU => sink.i32x4_gt_u(), + Instruction::I32x4LeS => sink.i32x4_le_s(), + Instruction::I32x4LeU => sink.i32x4_le_u(), + Instruction::I32x4GeS => sink.i32x4_ge_s(), + Instruction::I32x4GeU => sink.i32x4_ge_u(), + Instruction::F32x4Eq => sink.f32x4_eq(), + Instruction::F32x4Ne => sink.f32x4_ne(), + Instruction::F32x4Lt => sink.f32x4_lt(), + Instruction::F32x4Gt => sink.f32x4_gt(), + Instruction::F32x4Le => sink.f32x4_le(), + Instruction::F32x4Ge => sink.f32x4_ge(), + Instruction::F64x2Eq => sink.f64x2_eq(), + Instruction::F64x2Ne => sink.f64x2_ne(), + Instruction::F64x2Lt => sink.f64x2_lt(), + Instruction::F64x2Gt => sink.f64x2_gt(), + Instruction::F64x2Le => sink.f64x2_le(), + Instruction::F64x2Ge => sink.f64x2_ge(), + Instruction::V128Not => sink.v128_not(), + Instruction::V128And => sink.v128_and(), + Instruction::V128AndNot => sink.v128_andnot(), + Instruction::V128Or => sink.v128_or(), + Instruction::V128Xor => sink.v128_xor(), + Instruction::V128Bitselect => sink.v128_bitselect(), + Instruction::V128AnyTrue => sink.v128_any_true(), + Instruction::I8x16Abs => sink.i8x16_abs(), + Instruction::I8x16Neg => sink.i8x16_neg(), + Instruction::I8x16Popcnt => sink.i8x16_popcnt(), + Instruction::I8x16AllTrue => sink.i8x16_all_true(), + Instruction::I8x16Bitmask => sink.i8x16_bitmask(), + Instruction::I8x16NarrowI16x8S => sink.i8x16_narrow_i16x8_s(), + Instruction::I8x16NarrowI16x8U => sink.i8x16_narrow_i16x8_u(), + Instruction::I8x16Shl => sink.i8x16_shl(), + Instruction::I8x16ShrS => sink.i8x16_shr_s(), + Instruction::I8x16ShrU => sink.i8x16_shr_u(), + Instruction::I8x16Add => sink.i8x16_add(), + Instruction::I8x16AddSatS => sink.i8x16_add_sat_s(), + Instruction::I8x16AddSatU => sink.i8x16_add_sat_u(), + Instruction::I8x16Sub => sink.i8x16_sub(), + Instruction::I8x16SubSatS => sink.i8x16_sub_sat_s(), + Instruction::I8x16SubSatU => sink.i8x16_sub_sat_u(), + Instruction::I8x16MinS => sink.i8x16_min_s(), + Instruction::I8x16MinU => sink.i8x16_min_u(), + Instruction::I8x16MaxS => sink.i8x16_max_s(), + Instruction::I8x16MaxU => sink.i8x16_max_u(), + Instruction::I8x16AvgrU => sink.i8x16_avgr_u(), + Instruction::I16x8ExtAddPairwiseI8x16S => sink.i16x8_extadd_pairwise_i8x16_s(), + Instruction::I16x8ExtAddPairwiseI8x16U => sink.i16x8_extadd_pairwise_i8x16_u(), + Instruction::I32x4ExtAddPairwiseI16x8S => sink.i32x4_extadd_pairwise_i16x8_s(), + Instruction::I32x4ExtAddPairwiseI16x8U => sink.i32x4_extadd_pairwise_i16x8_u(), + Instruction::I16x8Abs => sink.i16x8_abs(), + Instruction::I16x8Neg => sink.i16x8_neg(), + Instruction::I16x8Q15MulrSatS => sink.i16x8_q15mulr_sat_s(), + Instruction::I16x8AllTrue => sink.i16x8_all_true(), + Instruction::I16x8Bitmask => sink.i16x8_bitmask(), + Instruction::I16x8NarrowI32x4S => sink.i16x8_narrow_i32x4_s(), + Instruction::I16x8NarrowI32x4U => sink.i16x8_narrow_i32x4_u(), + Instruction::I16x8ExtendLowI8x16S => sink.i16x8_extend_low_i8x16_s(), + Instruction::I16x8ExtendHighI8x16S => sink.i16x8_extend_high_i8x16_s(), + Instruction::I16x8ExtendLowI8x16U => sink.i16x8_extend_low_i8x16_u(), + Instruction::I16x8ExtendHighI8x16U => sink.i16x8_extend_high_i8x16_u(), + Instruction::I16x8Shl => sink.i16x8_shl(), + Instruction::I16x8ShrS => sink.i16x8_shr_s(), + Instruction::I16x8ShrU => sink.i16x8_shr_u(), + Instruction::I16x8Add => sink.i16x8_add(), + Instruction::I16x8AddSatS => sink.i16x8_add_sat_s(), + Instruction::I16x8AddSatU => sink.i16x8_add_sat_u(), + Instruction::I16x8Sub => sink.i16x8_sub(), + Instruction::I16x8SubSatS => sink.i16x8_sub_sat_s(), + Instruction::I16x8SubSatU => sink.i16x8_sub_sat_u(), + Instruction::I16x8Mul => sink.i16x8_mul(), + Instruction::I16x8MinS => sink.i16x8_min_s(), + Instruction::I16x8MinU => sink.i16x8_min_u(), + Instruction::I16x8MaxS => sink.i16x8_max_s(), + Instruction::I16x8MaxU => sink.i16x8_max_u(), + Instruction::I16x8AvgrU => sink.i16x8_avgr_u(), + Instruction::I16x8ExtMulLowI8x16S => sink.i16x8_extmul_low_i8x16_s(), + Instruction::I16x8ExtMulHighI8x16S => sink.i16x8_extmul_high_i8x16_s(), + Instruction::I16x8ExtMulLowI8x16U => sink.i16x8_extmul_low_i8x16_u(), + Instruction::I16x8ExtMulHighI8x16U => sink.i16x8_extmul_high_i8x16_u(), + Instruction::I32x4Abs => sink.i32x4_abs(), + Instruction::I32x4Neg => sink.i32x4_neg(), + Instruction::I32x4AllTrue => sink.i32x4_all_true(), + Instruction::I32x4Bitmask => sink.i32x4_bitmask(), + Instruction::I32x4ExtendLowI16x8S => sink.i32x4_extend_low_i16x8_s(), + Instruction::I32x4ExtendHighI16x8S => sink.i32x4_extend_high_i16x8_s(), + Instruction::I32x4ExtendLowI16x8U => sink.i32x4_extend_low_i16x8_u(), + Instruction::I32x4ExtendHighI16x8U => sink.i32x4_extend_high_i16x8_u(), + Instruction::I32x4Shl => sink.i32x4_shl(), + Instruction::I32x4ShrS => sink.i32x4_shr_s(), + Instruction::I32x4ShrU => sink.i32x4_shr_u(), + Instruction::I32x4Add => sink.i32x4_add(), + Instruction::I32x4Sub => sink.i32x4_sub(), + Instruction::I32x4Mul => sink.i32x4_mul(), + Instruction::I32x4MinS => sink.i32x4_min_s(), + Instruction::I32x4MinU => sink.i32x4_min_u(), + Instruction::I32x4MaxS => sink.i32x4_max_s(), + Instruction::I32x4MaxU => sink.i32x4_max_u(), + Instruction::I32x4DotI16x8S => sink.i32x4_dot_i16x8_s(), + Instruction::I32x4ExtMulLowI16x8S => sink.i32x4_extmul_low_i16x8_s(), + Instruction::I32x4ExtMulHighI16x8S => sink.i32x4_extmul_high_i16x8_s(), + Instruction::I32x4ExtMulLowI16x8U => sink.i32x4_extmul_low_i16x8_u(), + Instruction::I32x4ExtMulHighI16x8U => sink.i32x4_extmul_high_i16x8_u(), + Instruction::I64x2Abs => sink.i64x2_abs(), + Instruction::I64x2Neg => sink.i64x2_neg(), + Instruction::I64x2AllTrue => sink.i64x2_all_true(), + Instruction::I64x2Bitmask => sink.i64x2_bitmask(), + Instruction::I64x2ExtendLowI32x4S => sink.i64x2_extend_low_i32x4_s(), + Instruction::I64x2ExtendHighI32x4S => sink.i64x2_extend_high_i32x4_s(), + Instruction::I64x2ExtendLowI32x4U => sink.i64x2_extend_low_i32x4_u(), + Instruction::I64x2ExtendHighI32x4U => sink.i64x2_extend_high_i32x4_u(), + Instruction::I64x2Shl => sink.i64x2_shl(), + Instruction::I64x2ShrS => sink.i64x2_shr_s(), + Instruction::I64x2ShrU => sink.i64x2_shr_u(), + Instruction::I64x2Add => sink.i64x2_add(), + Instruction::I64x2Sub => sink.i64x2_sub(), + Instruction::I64x2Mul => sink.i64x2_mul(), + Instruction::I64x2ExtMulLowI32x4S => sink.i64x2_extmul_low_i32x4_s(), + Instruction::I64x2ExtMulHighI32x4S => sink.i64x2_extmul_high_i32x4_s(), + Instruction::I64x2ExtMulLowI32x4U => sink.i64x2_extmul_low_i32x4_u(), + Instruction::I64x2ExtMulHighI32x4U => sink.i64x2_extmul_high_i32x4_u(), + Instruction::F32x4Ceil => sink.f32x4_ceil(), + Instruction::F32x4Floor => sink.f32x4_floor(), + Instruction::F32x4Trunc => sink.f32x4_trunc(), + Instruction::F32x4Nearest => sink.f32x4_nearest(), + Instruction::F32x4Abs => sink.f32x4_abs(), + Instruction::F32x4Neg => sink.f32x4_neg(), + Instruction::F32x4Sqrt => sink.f32x4_sqrt(), + Instruction::F32x4Add => sink.f32x4_add(), + Instruction::F32x4Sub => sink.f32x4_sub(), + Instruction::F32x4Mul => sink.f32x4_mul(), + Instruction::F32x4Div => sink.f32x4_div(), + Instruction::F32x4Min => sink.f32x4_min(), + Instruction::F32x4Max => sink.f32x4_max(), + Instruction::F32x4PMin => sink.f32x4_pmin(), + Instruction::F32x4PMax => sink.f32x4_pmax(), + Instruction::F64x2Ceil => sink.f64x2_ceil(), + Instruction::F64x2Floor => sink.f64x2_floor(), + Instruction::F64x2Trunc => sink.f64x2_trunc(), + Instruction::F64x2Nearest => sink.f64x2_nearest(), + Instruction::F64x2Abs => sink.f64x2_abs(), + Instruction::F64x2Neg => sink.f64x2_neg(), + Instruction::F64x2Sqrt => sink.f64x2_sqrt(), + Instruction::F64x2Add => sink.f64x2_add(), + Instruction::F64x2Sub => sink.f64x2_sub(), + Instruction::F64x2Mul => sink.f64x2_mul(), + Instruction::F64x2Div => sink.f64x2_div(), + Instruction::F64x2Min => sink.f64x2_min(), + Instruction::F64x2Max => sink.f64x2_max(), + Instruction::F64x2PMin => sink.f64x2_pmin(), + Instruction::F64x2PMax => sink.f64x2_pmax(), + Instruction::I32x4TruncSatF32x4S => sink.i32x4_trunc_sat_f32x4_s(), + Instruction::I32x4TruncSatF32x4U => sink.i32x4_trunc_sat_f32x4_u(), + Instruction::F32x4ConvertI32x4S => sink.f32x4_convert_i32x4_s(), + Instruction::F32x4ConvertI32x4U => sink.f32x4_convert_i32x4_u(), + Instruction::I32x4TruncSatF64x2SZero => sink.i32x4_trunc_sat_f64x2_s_zero(), + Instruction::I32x4TruncSatF64x2UZero => sink.i32x4_trunc_sat_f64x2_u_zero(), + Instruction::F64x2ConvertLowI32x4S => sink.f64x2_convert_low_i32x4_s(), + Instruction::F64x2ConvertLowI32x4U => sink.f64x2_convert_low_i32x4_u(), + Instruction::F32x4DemoteF64x2Zero => sink.f32x4_demote_f64x2_zero(), + Instruction::F64x2PromoteLowF32x4 => sink.f64x2_promote_low_f32x4(), + Instruction::V128Load32Zero(memarg) => sink.v128_load32_zero(memarg), + Instruction::V128Load64Zero(memarg) => sink.v128_load64_zero(memarg), + Instruction::V128Load8Lane { memarg, lane } => sink.v128_load8_lane(memarg, lane), + Instruction::V128Load16Lane { memarg, lane } => sink.v128_load16_lane(memarg, lane), + Instruction::V128Load32Lane { memarg, lane } => sink.v128_load32_lane(memarg, lane), + Instruction::V128Load64Lane { memarg, lane } => sink.v128_load64_lane(memarg, lane), + Instruction::V128Store8Lane { memarg, lane } => sink.v128_store8_lane(memarg, lane), + Instruction::V128Store16Lane { memarg, lane } => sink.v128_store16_lane(memarg, lane), + Instruction::V128Store32Lane { memarg, lane } => sink.v128_store32_lane(memarg, lane), + Instruction::V128Store64Lane { memarg, lane } => sink.v128_store64_lane(memarg, lane), + Instruction::I64x2Eq => sink.i64x2_eq(), + Instruction::I64x2Ne => sink.i64x2_ne(), + Instruction::I64x2LtS => sink.i64x2_lt_s(), + Instruction::I64x2GtS => sink.i64x2_gt_s(), + Instruction::I64x2LeS => sink.i64x2_le_s(), + Instruction::I64x2GeS => sink.i64x2_ge_s(), + Instruction::I8x16RelaxedSwizzle => sink.i8x16_relaxed_swizzle(), + Instruction::I32x4RelaxedTruncF32x4S => sink.i32x4_relaxed_trunc_f32x4_s(), + Instruction::I32x4RelaxedTruncF32x4U => sink.i32x4_relaxed_trunc_f32x4_u(), + Instruction::I32x4RelaxedTruncF64x2SZero => sink.i32x4_relaxed_trunc_f64x2_s_zero(), + Instruction::I32x4RelaxedTruncF64x2UZero => sink.i32x4_relaxed_trunc_f64x2_u_zero(), + Instruction::F32x4RelaxedMadd => sink.f32x4_relaxed_madd(), + Instruction::F32x4RelaxedNmadd => sink.f32x4_relaxed_nmadd(), + Instruction::F64x2RelaxedMadd => sink.f64x2_relaxed_madd(), + Instruction::F64x2RelaxedNmadd => sink.f64x2_relaxed_nmadd(), + Instruction::I8x16RelaxedLaneselect => sink.i8x16_relaxed_laneselect(), + Instruction::I16x8RelaxedLaneselect => sink.i16x8_relaxed_laneselect(), + Instruction::I32x4RelaxedLaneselect => sink.i32x4_relaxed_laneselect(), + Instruction::I64x2RelaxedLaneselect => sink.i64x2_relaxed_laneselect(), + Instruction::F32x4RelaxedMin => sink.f32x4_relaxed_min(), + Instruction::F32x4RelaxedMax => sink.f32x4_relaxed_max(), + Instruction::F64x2RelaxedMin => sink.f64x2_relaxed_min(), + Instruction::F64x2RelaxedMax => sink.f64x2_relaxed_max(), + Instruction::I16x8RelaxedQ15mulrS => sink.i16x8_relaxed_q15mulr_s(), + Instruction::I16x8RelaxedDotI8x16I7x16S => sink.i16x8_relaxed_dot_i8x16_i7x16_s(), + Instruction::I32x4RelaxedDotI8x16I7x16AddS => { + sink.i32x4_relaxed_dot_i8x16_i7x16_add_s() } // Atomic instructions from the thread proposal - Instruction::MemoryAtomicNotify(memarg) => { - sink.push(0xFE); - sink.push(0x00); - memarg.encode(sink); - } - Instruction::MemoryAtomicWait32(memarg) => { - sink.push(0xFE); - sink.push(0x01); - memarg.encode(sink); - } - Instruction::MemoryAtomicWait64(memarg) => { - sink.push(0xFE); - sink.push(0x02); - memarg.encode(sink); - } - Instruction::AtomicFence => { - sink.push(0xFE); - sink.push(0x03); - sink.push(0x00); - } - Instruction::I32AtomicLoad(memarg) => { - sink.push(0xFE); - sink.push(0x10); - memarg.encode(sink); - } - Instruction::I64AtomicLoad(memarg) => { - sink.push(0xFE); - sink.push(0x11); - memarg.encode(sink); - } - Instruction::I32AtomicLoad8U(memarg) => { - sink.push(0xFE); - sink.push(0x12); - memarg.encode(sink); - } - Instruction::I32AtomicLoad16U(memarg) => { - sink.push(0xFE); - sink.push(0x13); - memarg.encode(sink); - } - Instruction::I64AtomicLoad8U(memarg) => { - sink.push(0xFE); - sink.push(0x14); - memarg.encode(sink); - } - Instruction::I64AtomicLoad16U(memarg) => { - sink.push(0xFE); - sink.push(0x15); - memarg.encode(sink); - } - Instruction::I64AtomicLoad32U(memarg) => { - sink.push(0xFE); - sink.push(0x16); - memarg.encode(sink); - } - Instruction::I32AtomicStore(memarg) => { - sink.push(0xFE); - sink.push(0x17); - memarg.encode(sink); - } - Instruction::I64AtomicStore(memarg) => { - sink.push(0xFE); - sink.push(0x18); - memarg.encode(sink); - } - Instruction::I32AtomicStore8(memarg) => { - sink.push(0xFE); - sink.push(0x19); - memarg.encode(sink); - } - Instruction::I32AtomicStore16(memarg) => { - sink.push(0xFE); - sink.push(0x1A); - memarg.encode(sink); - } - Instruction::I64AtomicStore8(memarg) => { - sink.push(0xFE); - sink.push(0x1B); - memarg.encode(sink); - } - Instruction::I64AtomicStore16(memarg) => { - sink.push(0xFE); - sink.push(0x1C); - memarg.encode(sink); - } - Instruction::I64AtomicStore32(memarg) => { - sink.push(0xFE); - sink.push(0x1D); - memarg.encode(sink); - } - Instruction::I32AtomicRmwAdd(memarg) => { - sink.push(0xFE); - sink.push(0x1E); - memarg.encode(sink); - } - Instruction::I64AtomicRmwAdd(memarg) => { - sink.push(0xFE); - sink.push(0x1F); - memarg.encode(sink); - } - Instruction::I32AtomicRmw8AddU(memarg) => { - sink.push(0xFE); - sink.push(0x20); - memarg.encode(sink); - } - Instruction::I32AtomicRmw16AddU(memarg) => { - sink.push(0xFE); - sink.push(0x21); - memarg.encode(sink); - } - Instruction::I64AtomicRmw8AddU(memarg) => { - sink.push(0xFE); - sink.push(0x22); - memarg.encode(sink); - } - Instruction::I64AtomicRmw16AddU(memarg) => { - sink.push(0xFE); - sink.push(0x23); - memarg.encode(sink); - } - Instruction::I64AtomicRmw32AddU(memarg) => { - sink.push(0xFE); - sink.push(0x24); - memarg.encode(sink); - } - Instruction::I32AtomicRmwSub(memarg) => { - sink.push(0xFE); - sink.push(0x25); - memarg.encode(sink); - } - Instruction::I64AtomicRmwSub(memarg) => { - sink.push(0xFE); - sink.push(0x26); - memarg.encode(sink); - } - Instruction::I32AtomicRmw8SubU(memarg) => { - sink.push(0xFE); - sink.push(0x27); - memarg.encode(sink); - } - Instruction::I32AtomicRmw16SubU(memarg) => { - sink.push(0xFE); - sink.push(0x28); - memarg.encode(sink); - } - Instruction::I64AtomicRmw8SubU(memarg) => { - sink.push(0xFE); - sink.push(0x29); - memarg.encode(sink); - } - Instruction::I64AtomicRmw16SubU(memarg) => { - sink.push(0xFE); - sink.push(0x2A); - memarg.encode(sink); - } - Instruction::I64AtomicRmw32SubU(memarg) => { - sink.push(0xFE); - sink.push(0x2B); - memarg.encode(sink); - } - Instruction::I32AtomicRmwAnd(memarg) => { - sink.push(0xFE); - sink.push(0x2C); - memarg.encode(sink); - } - Instruction::I64AtomicRmwAnd(memarg) => { - sink.push(0xFE); - sink.push(0x2D); - memarg.encode(sink); - } - Instruction::I32AtomicRmw8AndU(memarg) => { - sink.push(0xFE); - sink.push(0x2E); - memarg.encode(sink); - } - Instruction::I32AtomicRmw16AndU(memarg) => { - sink.push(0xFE); - sink.push(0x2F); - memarg.encode(sink); - } - Instruction::I64AtomicRmw8AndU(memarg) => { - sink.push(0xFE); - sink.push(0x30); - memarg.encode(sink); - } - Instruction::I64AtomicRmw16AndU(memarg) => { - sink.push(0xFE); - sink.push(0x31); - memarg.encode(sink); - } - Instruction::I64AtomicRmw32AndU(memarg) => { - sink.push(0xFE); - sink.push(0x32); - memarg.encode(sink); - } - Instruction::I32AtomicRmwOr(memarg) => { - sink.push(0xFE); - sink.push(0x33); - memarg.encode(sink); - } - Instruction::I64AtomicRmwOr(memarg) => { - sink.push(0xFE); - sink.push(0x34); - memarg.encode(sink); - } - Instruction::I32AtomicRmw8OrU(memarg) => { - sink.push(0xFE); - sink.push(0x35); - memarg.encode(sink); - } - Instruction::I32AtomicRmw16OrU(memarg) => { - sink.push(0xFE); - sink.push(0x36); - memarg.encode(sink); - } - Instruction::I64AtomicRmw8OrU(memarg) => { - sink.push(0xFE); - sink.push(0x37); - memarg.encode(sink); - } - Instruction::I64AtomicRmw16OrU(memarg) => { - sink.push(0xFE); - sink.push(0x38); - memarg.encode(sink); - } - Instruction::I64AtomicRmw32OrU(memarg) => { - sink.push(0xFE); - sink.push(0x39); - memarg.encode(sink); - } - Instruction::I32AtomicRmwXor(memarg) => { - sink.push(0xFE); - sink.push(0x3A); - memarg.encode(sink); - } - Instruction::I64AtomicRmwXor(memarg) => { - sink.push(0xFE); - sink.push(0x3B); - memarg.encode(sink); - } - Instruction::I32AtomicRmw8XorU(memarg) => { - sink.push(0xFE); - sink.push(0x3C); - memarg.encode(sink); - } - Instruction::I32AtomicRmw16XorU(memarg) => { - sink.push(0xFE); - sink.push(0x3D); - memarg.encode(sink); - } - Instruction::I64AtomicRmw8XorU(memarg) => { - sink.push(0xFE); - sink.push(0x3E); - memarg.encode(sink); - } - Instruction::I64AtomicRmw16XorU(memarg) => { - sink.push(0xFE); - sink.push(0x3F); - memarg.encode(sink); - } - Instruction::I64AtomicRmw32XorU(memarg) => { - sink.push(0xFE); - sink.push(0x40); - memarg.encode(sink); - } - Instruction::I32AtomicRmwXchg(memarg) => { - sink.push(0xFE); - sink.push(0x41); - memarg.encode(sink); - } - Instruction::I64AtomicRmwXchg(memarg) => { - sink.push(0xFE); - sink.push(0x42); - memarg.encode(sink); - } - Instruction::I32AtomicRmw8XchgU(memarg) => { - sink.push(0xFE); - sink.push(0x43); - memarg.encode(sink); - } - Instruction::I32AtomicRmw16XchgU(memarg) => { - sink.push(0xFE); - sink.push(0x44); - memarg.encode(sink); - } - Instruction::I64AtomicRmw8XchgU(memarg) => { - sink.push(0xFE); - sink.push(0x45); - memarg.encode(sink); - } - Instruction::I64AtomicRmw16XchgU(memarg) => { - sink.push(0xFE); - sink.push(0x46); - memarg.encode(sink); - } - Instruction::I64AtomicRmw32XchgU(memarg) => { - sink.push(0xFE); - sink.push(0x47); - memarg.encode(sink); - } - Instruction::I32AtomicRmwCmpxchg(memarg) => { - sink.push(0xFE); - sink.push(0x48); - memarg.encode(sink); - } - Instruction::I64AtomicRmwCmpxchg(memarg) => { - sink.push(0xFE); - sink.push(0x49); - memarg.encode(sink); - } - Instruction::I32AtomicRmw8CmpxchgU(memarg) => { - sink.push(0xFE); - sink.push(0x4A); - memarg.encode(sink); - } - Instruction::I32AtomicRmw16CmpxchgU(memarg) => { - sink.push(0xFE); - sink.push(0x4B); - memarg.encode(sink); - } - Instruction::I64AtomicRmw8CmpxchgU(memarg) => { - sink.push(0xFE); - sink.push(0x4C); - memarg.encode(sink); - } - Instruction::I64AtomicRmw16CmpxchgU(memarg) => { - sink.push(0xFE); - sink.push(0x4D); - memarg.encode(sink); - } - Instruction::I64AtomicRmw32CmpxchgU(memarg) => { - sink.push(0xFE); - sink.push(0x4E); - memarg.encode(sink); - } + Instruction::MemoryAtomicNotify(memarg) => sink.memory_atomic_notify(memarg), + Instruction::MemoryAtomicWait32(memarg) => sink.memory_atomic_wait32(memarg), + Instruction::MemoryAtomicWait64(memarg) => sink.memory_atomic_wait64(memarg), + Instruction::AtomicFence => sink.atomic_fence(), + Instruction::I32AtomicLoad(memarg) => sink.i32_atomic_load(memarg), + Instruction::I64AtomicLoad(memarg) => sink.i64_atomic_load(memarg), + Instruction::I32AtomicLoad8U(memarg) => sink.i32_atomic_load8_u(memarg), + Instruction::I32AtomicLoad16U(memarg) => sink.i32_atomic_load16_u(memarg), + Instruction::I64AtomicLoad8U(memarg) => sink.i64_atomic_load8_u(memarg), + Instruction::I64AtomicLoad16U(memarg) => sink.i64_atomic_load16_u(memarg), + Instruction::I64AtomicLoad32U(memarg) => sink.i64_atomic_load32_u(memarg), + Instruction::I32AtomicStore(memarg) => sink.i32_atomic_store(memarg), + Instruction::I64AtomicStore(memarg) => sink.i64_atomic_store(memarg), + Instruction::I32AtomicStore8(memarg) => sink.i32_atomic_store8(memarg), + Instruction::I32AtomicStore16(memarg) => sink.i32_atomic_store16(memarg), + Instruction::I64AtomicStore8(memarg) => sink.i64_atomic_store8(memarg), + Instruction::I64AtomicStore16(memarg) => sink.i64_atomic_store16(memarg), + Instruction::I64AtomicStore32(memarg) => sink.i64_atomic_store32(memarg), + Instruction::I32AtomicRmwAdd(memarg) => sink.i32_atomic_rmw_add(memarg), + Instruction::I64AtomicRmwAdd(memarg) => sink.i64_atomic_rmw_add(memarg), + Instruction::I32AtomicRmw8AddU(memarg) => sink.i32_atomic_rmw8_add_u(memarg), + Instruction::I32AtomicRmw16AddU(memarg) => sink.i32_atomic_rmw16_add_u(memarg), + Instruction::I64AtomicRmw8AddU(memarg) => sink.i64_atomic_rmw8_add_u(memarg), + Instruction::I64AtomicRmw16AddU(memarg) => sink.i64_atomic_rmw16_add_u(memarg), + Instruction::I64AtomicRmw32AddU(memarg) => sink.i64_atomic_rmw32_add_u(memarg), + Instruction::I32AtomicRmwSub(memarg) => sink.i32_atomic_rmw_sub(memarg), + Instruction::I64AtomicRmwSub(memarg) => sink.i64_atomic_rmw_sub(memarg), + Instruction::I32AtomicRmw8SubU(memarg) => sink.i32_atomic_rmw8_sub_u(memarg), + Instruction::I32AtomicRmw16SubU(memarg) => sink.i32_atomic_rmw16_sub_u(memarg), + Instruction::I64AtomicRmw8SubU(memarg) => sink.i64_atomic_rmw8_sub_u(memarg), + Instruction::I64AtomicRmw16SubU(memarg) => sink.i64_atomic_rmw16_sub_u(memarg), + Instruction::I64AtomicRmw32SubU(memarg) => sink.i64_atomic_rmw32_sub_u(memarg), + Instruction::I32AtomicRmwAnd(memarg) => sink.i32_atomic_rmw_and(memarg), + Instruction::I64AtomicRmwAnd(memarg) => sink.i64_atomic_rmw_and(memarg), + Instruction::I32AtomicRmw8AndU(memarg) => sink.i32_atomic_rmw8_and_u(memarg), + Instruction::I32AtomicRmw16AndU(memarg) => sink.i32_atomic_rmw16_and_u(memarg), + Instruction::I64AtomicRmw8AndU(memarg) => sink.i64_atomic_rmw8_and_u(memarg), + Instruction::I64AtomicRmw16AndU(memarg) => sink.i64_atomic_rmw16_and_u(memarg), + Instruction::I64AtomicRmw32AndU(memarg) => sink.i64_atomic_rmw32_and_u(memarg), + Instruction::I32AtomicRmwOr(memarg) => sink.i32_atomic_rmw_or(memarg), + Instruction::I64AtomicRmwOr(memarg) => sink.i64_atomic_rmw_or(memarg), + Instruction::I32AtomicRmw8OrU(memarg) => sink.i32_atomic_rmw8_or_u(memarg), + Instruction::I32AtomicRmw16OrU(memarg) => sink.i32_atomic_rmw16_or_u(memarg), + Instruction::I64AtomicRmw8OrU(memarg) => sink.i64_atomic_rmw8_or_u(memarg), + Instruction::I64AtomicRmw16OrU(memarg) => sink.i64_atomic_rmw16_or_u(memarg), + Instruction::I64AtomicRmw32OrU(memarg) => sink.i64_atomic_rmw32_or_u(memarg), + Instruction::I32AtomicRmwXor(memarg) => sink.i32_atomic_rmw_xor(memarg), + Instruction::I64AtomicRmwXor(memarg) => sink.i64_atomic_rmw_xor(memarg), + Instruction::I32AtomicRmw8XorU(memarg) => sink.i32_atomic_rmw8_xor_u(memarg), + Instruction::I32AtomicRmw16XorU(memarg) => sink.i32_atomic_rmw16_xor_u(memarg), + Instruction::I64AtomicRmw8XorU(memarg) => sink.i64_atomic_rmw8_xor_u(memarg), + Instruction::I64AtomicRmw16XorU(memarg) => sink.i64_atomic_rmw16_xor_u(memarg), + Instruction::I64AtomicRmw32XorU(memarg) => sink.i64_atomic_rmw32_xor_u(memarg), + Instruction::I32AtomicRmwXchg(memarg) => sink.i32_atomic_rmw_xchg(memarg), + Instruction::I64AtomicRmwXchg(memarg) => sink.i64_atomic_rmw_xchg(memarg), + Instruction::I32AtomicRmw8XchgU(memarg) => sink.i32_atomic_rmw8_xchg_u(memarg), + Instruction::I32AtomicRmw16XchgU(memarg) => sink.i32_atomic_rmw16_xchg_u(memarg), + Instruction::I64AtomicRmw8XchgU(memarg) => sink.i64_atomic_rmw8_xchg_u(memarg), + Instruction::I64AtomicRmw16XchgU(memarg) => sink.i64_atomic_rmw16_xchg_u(memarg), + Instruction::I64AtomicRmw32XchgU(memarg) => sink.i64_atomic_rmw32_xchg_u(memarg), + Instruction::I32AtomicRmwCmpxchg(memarg) => sink.i32_atomic_rmw_cmpxchg(memarg), + Instruction::I64AtomicRmwCmpxchg(memarg) => sink.i64_atomic_rmw_cmpxchg(memarg), + Instruction::I32AtomicRmw8CmpxchgU(memarg) => sink.i32_atomic_rmw8_cmpxchg_u(memarg), + Instruction::I32AtomicRmw16CmpxchgU(memarg) => sink.i32_atomic_rmw16_cmpxchg_u(memarg), + Instruction::I64AtomicRmw8CmpxchgU(memarg) => sink.i64_atomic_rmw8_cmpxchg_u(memarg), + Instruction::I64AtomicRmw16CmpxchgU(memarg) => sink.i64_atomic_rmw16_cmpxchg_u(memarg), + Instruction::I64AtomicRmw32CmpxchgU(memarg) => sink.i64_atomic_rmw32_cmpxchg_u(memarg), // Atomic instructions from the shared-everything-threads proposal Instruction::GlobalAtomicGet { ordering, global_index, - } => { - sink.push(0xFE); - sink.push(0x4F); - ordering.encode(sink); - global_index.encode(sink); - } + } => sink.global_atomic_get(ordering, global_index), Instruction::GlobalAtomicSet { ordering, global_index, - } => { - sink.push(0xFE); - sink.push(0x50); - ordering.encode(sink); - global_index.encode(sink); - } + } => sink.global_atomic_set(ordering, global_index), Instruction::GlobalAtomicRmwAdd { ordering, global_index, - } => { - sink.push(0xFE); - sink.push(0x51); - ordering.encode(sink); - global_index.encode(sink); - } + } => sink.global_atomic_rmw_add(ordering, global_index), Instruction::GlobalAtomicRmwSub { ordering, global_index, - } => { - sink.push(0xFE); - sink.push(0x52); - ordering.encode(sink); - global_index.encode(sink); - } + } => sink.global_atomic_rmw_sub(ordering, global_index), Instruction::GlobalAtomicRmwAnd { ordering, global_index, - } => { - sink.push(0xFE); - sink.push(0x53); - ordering.encode(sink); - global_index.encode(sink); - } + } => sink.global_atomic_rmw_and(ordering, global_index), Instruction::GlobalAtomicRmwOr { ordering, global_index, - } => { - sink.push(0xFE); - sink.push(0x54); - ordering.encode(sink); - global_index.encode(sink); - } + } => sink.global_atomic_rmw_or(ordering, global_index), Instruction::GlobalAtomicRmwXor { ordering, global_index, - } => { - sink.push(0xFE); - sink.push(0x55); - ordering.encode(sink); - global_index.encode(sink); - } + } => sink.global_atomic_rmw_xor(ordering, global_index), Instruction::GlobalAtomicRmwXchg { ordering, global_index, - } => { - sink.push(0xFE); - sink.push(0x56); - ordering.encode(sink); - global_index.encode(sink); - } + } => sink.global_atomic_rmw_xchg(ordering, global_index), Instruction::GlobalAtomicRmwCmpxchg { ordering, global_index, - } => { - sink.push(0xFE); - sink.push(0x57); - ordering.encode(sink); - global_index.encode(sink); - } + } => sink.global_atomic_rmw_cmpxchg(ordering, global_index), Instruction::TableAtomicGet { ordering, table_index, - } => { - sink.push(0xFE); - sink.push(0x58); - ordering.encode(sink); - table_index.encode(sink); - } + } => sink.table_atomic_get(ordering, table_index), Instruction::TableAtomicSet { ordering, table_index, - } => { - sink.push(0xFE); - sink.push(0x59); - ordering.encode(sink); - table_index.encode(sink); - } + } => sink.table_atomic_set(ordering, table_index), Instruction::TableAtomicRmwXchg { ordering, table_index, - } => { - sink.push(0xFE); - sink.push(0x5A); - ordering.encode(sink); - table_index.encode(sink); - } + } => sink.table_atomic_rmw_xchg(ordering, table_index), Instruction::TableAtomicRmwCmpxchg { ordering, table_index, - } => { - sink.push(0xFE); - sink.push(0x5B); - ordering.encode(sink); - table_index.encode(sink); - } + } => sink.table_atomic_rmw_cmpxchg(ordering, table_index), Instruction::StructAtomicGet { ordering, struct_type_index, field_index, - } => { - sink.push(0xFE); - sink.push(0x5C); - ordering.encode(sink); - struct_type_index.encode(sink); - field_index.encode(sink); - } + } => sink.struct_atomic_get(ordering, struct_type_index, field_index), Instruction::StructAtomicGetS { ordering, struct_type_index, field_index, - } => { - sink.push(0xFE); - sink.push(0x5D); - ordering.encode(sink); - struct_type_index.encode(sink); - field_index.encode(sink); - } + } => sink.struct_atomic_get_s(ordering, struct_type_index, field_index), Instruction::StructAtomicGetU { ordering, struct_type_index, field_index, - } => { - sink.push(0xFE); - sink.push(0x5E); - ordering.encode(sink); - struct_type_index.encode(sink); - field_index.encode(sink); - } + } => sink.struct_atomic_get_u(ordering, struct_type_index, field_index), Instruction::StructAtomicSet { ordering, struct_type_index, field_index, - } => { - sink.push(0xFE); - sink.push(0x5F); - ordering.encode(sink); - struct_type_index.encode(sink); - field_index.encode(sink); - } + } => sink.struct_atomic_set(ordering, struct_type_index, field_index), Instruction::StructAtomicRmwAdd { ordering, struct_type_index, field_index, - } => { - sink.push(0xFE); - sink.push(0x60); - ordering.encode(sink); - struct_type_index.encode(sink); - field_index.encode(sink); - } + } => sink.struct_atomic_rmw_add(ordering, struct_type_index, field_index), Instruction::StructAtomicRmwSub { ordering, struct_type_index, field_index, - } => { - sink.push(0xFE); - sink.push(0x61); - ordering.encode(sink); - struct_type_index.encode(sink); - field_index.encode(sink); - } + } => sink.struct_atomic_rmw_sub(ordering, struct_type_index, field_index), Instruction::StructAtomicRmwAnd { ordering, struct_type_index, field_index, - } => { - sink.push(0xFE); - sink.push(0x62); - ordering.encode(sink); - struct_type_index.encode(sink); - field_index.encode(sink); - } + } => sink.struct_atomic_rmw_and(ordering, struct_type_index, field_index), Instruction::StructAtomicRmwOr { ordering, struct_type_index, field_index, - } => { - sink.push(0xFE); - sink.push(0x63); - ordering.encode(sink); - struct_type_index.encode(sink); - field_index.encode(sink); - } + } => sink.struct_atomic_rmw_or(ordering, struct_type_index, field_index), Instruction::StructAtomicRmwXor { ordering, struct_type_index, field_index, - } => { - sink.push(0xFE); - sink.push(0x64); - ordering.encode(sink); - struct_type_index.encode(sink); - field_index.encode(sink); - } + } => sink.struct_atomic_rmw_xor(ordering, struct_type_index, field_index), Instruction::StructAtomicRmwXchg { ordering, struct_type_index, field_index, - } => { - sink.push(0xFE); - sink.push(0x65); - ordering.encode(sink); - struct_type_index.encode(sink); - field_index.encode(sink); - } + } => sink.struct_atomic_rmw_xchg(ordering, struct_type_index, field_index), Instruction::StructAtomicRmwCmpxchg { ordering, struct_type_index, field_index, - } => { - sink.push(0xFE); - sink.push(0x66); - ordering.encode(sink); - struct_type_index.encode(sink); - field_index.encode(sink); - } + } => sink.struct_atomic_rmw_cmpxchg(ordering, struct_type_index, field_index), Instruction::ArrayAtomicGet { ordering, array_type_index, - } => { - sink.push(0xFE); - sink.push(0x67); - ordering.encode(sink); - array_type_index.encode(sink); - } + } => sink.array_atomic_get(ordering, array_type_index), Instruction::ArrayAtomicGetS { ordering, array_type_index, - } => { - sink.push(0xFE); - sink.push(0x68); - ordering.encode(sink); - array_type_index.encode(sink); - } + } => sink.array_atomic_get_s(ordering, array_type_index), Instruction::ArrayAtomicGetU { ordering, array_type_index, - } => { - sink.push(0xFE); - sink.push(0x69); - ordering.encode(sink); - array_type_index.encode(sink); - } + } => sink.array_atomic_get_u(ordering, array_type_index), Instruction::ArrayAtomicSet { ordering, array_type_index, - } => { - sink.push(0xFE); - sink.push(0x6A); - ordering.encode(sink); - array_type_index.encode(sink); - } + } => sink.array_atomic_set(ordering, array_type_index), Instruction::ArrayAtomicRmwAdd { ordering, array_type_index, - } => { - sink.push(0xFE); - sink.push(0x6B); - ordering.encode(sink); - array_type_index.encode(sink); - } + } => sink.array_atomic_rmw_add(ordering, array_type_index), Instruction::ArrayAtomicRmwSub { ordering, array_type_index, - } => { - sink.push(0xFE); - sink.push(0x6C); - ordering.encode(sink); - array_type_index.encode(sink); - } + } => sink.array_atomic_rmw_sub(ordering, array_type_index), Instruction::ArrayAtomicRmwAnd { ordering, array_type_index, - } => { - sink.push(0xFE); - sink.push(0x6D); - ordering.encode(sink); - array_type_index.encode(sink); - } + } => sink.array_atomic_rmw_and(ordering, array_type_index), Instruction::ArrayAtomicRmwOr { ordering, array_type_index, - } => { - sink.push(0xFE); - sink.push(0x6E); - ordering.encode(sink); - array_type_index.encode(sink); - } + } => sink.array_atomic_rmw_or(ordering, array_type_index), Instruction::ArrayAtomicRmwXor { ordering, array_type_index, - } => { - sink.push(0xFE); - sink.push(0x6F); - ordering.encode(sink); - array_type_index.encode(sink); - } + } => sink.array_atomic_rmw_xor(ordering, array_type_index), Instruction::ArrayAtomicRmwXchg { ordering, array_type_index, - } => { - sink.push(0xFE); - sink.push(0x70); - ordering.encode(sink); - array_type_index.encode(sink); - } + } => sink.array_atomic_rmw_xchg(ordering, array_type_index), Instruction::ArrayAtomicRmwCmpxchg { ordering, array_type_index, - } => { - sink.push(0xFE); - sink.push(0x71); - ordering.encode(sink); - array_type_index.encode(sink); - } - Instruction::RefI31Shared => { - sink.push(0xFE); - sink.push(0x72); - } - Instruction::ContNew(type_index) => { - sink.push(0xE0); - type_index.encode(sink); - } + } => sink.array_atomic_rmw_cmpxchg(ordering, array_type_index), + Instruction::RefI31Shared => sink.ref_i31_shared(), + Instruction::ContNew(type_index) => sink.cont_new(type_index), Instruction::ContBind { argument_index, result_index, - } => { - sink.push(0xE1); - argument_index.encode(sink); - result_index.encode(sink); - } - Instruction::Suspend(tag_index) => { - sink.push(0xE2); - tag_index.encode(sink); - } + } => sink.cont_bind(argument_index, result_index), + Instruction::Suspend(tag_index) => sink.suspend(tag_index), Instruction::Resume { cont_type_index, ref resume_table, - } => { - sink.push(0xE3); - cont_type_index.encode(sink); - resume_table.encode(sink); - } + } => sink.resume(cont_type_index, resume_table.iter().cloned()), Instruction::ResumeThrow { cont_type_index, tag_index, ref resume_table, - } => { - sink.push(0xE4); - cont_type_index.encode(sink); - tag_index.encode(sink); - resume_table.encode(sink); - } + } => sink.resume_throw(cont_type_index, tag_index, resume_table.iter().cloned()), Instruction::Switch { cont_type_index, tag_index, - } => { - sink.push(0xE5); - cont_type_index.encode(sink); - tag_index.encode(sink); - } - Instruction::I64Add128 => { - sink.push(0xFC); - 19u32.encode(sink); - } - Instruction::I64Sub128 => { - sink.push(0xFC); - 20u32.encode(sink); - } - Instruction::I64MulWideS => { - sink.push(0xFC); - 21u32.encode(sink); - } - Instruction::I64MulWideU => { - sink.push(0xFC); - 22u32.encode(sink); - } - } + } => sink.switch(cont_type_index, tag_index), + Instruction::I64Add128 => sink.i64_add128(), + Instruction::I64Sub128 => sink.i64_sub128(), + Instruction::I64MulWideS => sink.i64_mul_wide_s(), + Instruction::I64MulWideU => sink.i64_mul_wide_u(), + Instruction::RefGetDesc(type_index) => sink.ref_get_desc(type_index), + Instruction::RefCastDescNonNull(hty) => sink.ref_cast_desc_non_null(hty), + Instruction::RefCastDescNullable(hty) => sink.ref_cast_desc_nullable(hty), + Instruction::BrOnCastDesc { + relative_depth, + from_ref_type, + to_ref_type, + } => sink.br_on_cast_desc(relative_depth, from_ref_type, to_ref_type), + Instruction::BrOnCastDescFail { + relative_depth, + from_ref_type, + to_ref_type, + } => sink.br_on_cast_desc_fail(relative_depth, from_ref_type, to_ref_type), + }; } } @@ -3872,125 +2268,131 @@ impl ConstExpr { Self { bytes } } - fn new_insn(insn: Instruction) -> Self { + fn new<F>(f: F) -> Self + where + for<'a, 'b> F: FnOnce(&'a mut InstructionSink<'b>) -> &'a mut InstructionSink<'b>, + { let mut bytes = vec![]; - insn.encode(&mut bytes); + f(&mut InstructionSink::new(&mut bytes)); Self { bytes } } - fn with_insn(mut self, insn: Instruction) -> Self { - insn.encode(&mut self.bytes); + fn with<F>(mut self, f: F) -> Self + where + for<'a, 'b> F: FnOnce(&'a mut InstructionSink<'b>) -> &'a mut InstructionSink<'b>, + { + f(&mut InstructionSink::new(&mut self.bytes)); self } /// Create a constant expression containing a single `global.get` instruction. pub fn global_get(index: u32) -> Self { - Self::new_insn(Instruction::GlobalGet(index)) + Self::new(|insn| insn.global_get(index)) } /// Create a constant expression containing a single `ref.null` instruction. pub fn ref_null(ty: HeapType) -> Self { - Self::new_insn(Instruction::RefNull(ty)) + Self::new(|insn| insn.ref_null(ty)) } /// Create a constant expression containing a single `ref.func` instruction. pub fn ref_func(func: u32) -> Self { - Self::new_insn(Instruction::RefFunc(func)) + Self::new(|insn| insn.ref_func(func)) } /// Create a constant expression containing a single `i32.const` instruction. pub fn i32_const(value: i32) -> Self { - Self::new_insn(Instruction::I32Const(value)) + Self::new(|insn| insn.i32_const(value)) } /// Create a constant expression containing a single `i64.const` instruction. pub fn i64_const(value: i64) -> Self { - Self::new_insn(Instruction::I64Const(value)) + Self::new(|insn| insn.i64_const(value)) } /// Create a constant expression containing a single `f32.const` instruction. - pub fn f32_const(value: f32) -> Self { - Self::new_insn(Instruction::F32Const(value)) + pub fn f32_const(value: Ieee32) -> Self { + Self::new(|insn| insn.f32_const(value)) } /// Create a constant expression containing a single `f64.const` instruction. - pub fn f64_const(value: f64) -> Self { - Self::new_insn(Instruction::F64Const(value)) + pub fn f64_const(value: Ieee64) -> Self { + Self::new(|insn| insn.f64_const(value)) } /// Create a constant expression containing a single `v128.const` instruction. pub fn v128_const(value: i128) -> Self { - Self::new_insn(Instruction::V128Const(value)) + Self::new(|insn| insn.v128_const(value)) } /// Add a `global.get` instruction to this constant expression. pub fn with_global_get(self, index: u32) -> Self { - self.with_insn(Instruction::GlobalGet(index)) + self.with(|insn| insn.global_get(index)) } /// Add a `ref.null` instruction to this constant expression. pub fn with_ref_null(self, ty: HeapType) -> Self { - self.with_insn(Instruction::RefNull(ty)) + self.with(|insn| insn.ref_null(ty)) } /// Add a `ref.func` instruction to this constant expression. pub fn with_ref_func(self, func: u32) -> Self { - self.with_insn(Instruction::RefFunc(func)) + self.with(|insn| insn.ref_func(func)) } /// Add an `i32.const` instruction to this constant expression. pub fn with_i32_const(self, value: i32) -> Self { - self.with_insn(Instruction::I32Const(value)) + self.with(|insn| insn.i32_const(value)) } /// Add an `i64.const` instruction to this constant expression. pub fn with_i64_const(self, value: i64) -> Self { - self.with_insn(Instruction::I64Const(value)) + self.with(|insn| insn.i64_const(value)) } /// Add a `f32.const` instruction to this constant expression. - pub fn with_f32_const(self, value: f32) -> Self { - self.with_insn(Instruction::F32Const(value)) + pub fn with_f32_const(self, value: Ieee32) -> Self { + self.with(|insn| insn.f32_const(value)) } /// Add a `f64.const` instruction to this constant expression. - pub fn with_f64_const(self, value: f64) -> Self { - self.with_insn(Instruction::F64Const(value)) + pub fn with_f64_const(self, value: Ieee64) -> Self { + self.with(|insn| insn.f64_const(value)) } /// Add a `v128.const` instruction to this constant expression. pub fn with_v128_const(self, value: i128) -> Self { - self.with_insn(Instruction::V128Const(value)) + self.with(|insn| insn.v128_const(value)) } /// Add an `i32.add` instruction to this constant expression. pub fn with_i32_add(self) -> Self { - self.with_insn(Instruction::I32Add) + self.with(|insn| insn.i32_add()) } /// Add an `i32.sub` instruction to this constant expression. pub fn with_i32_sub(self) -> Self { - self.with_insn(Instruction::I32Sub) + self.with(|insn| insn.i32_sub()) } /// Add an `i32.mul` instruction to this constant expression. pub fn with_i32_mul(self) -> Self { - self.with_insn(Instruction::I32Mul) + self.with(|insn| insn.i32_mul()) } /// Add an `i64.add` instruction to this constant expression. pub fn with_i64_add(self) -> Self { - self.with_insn(Instruction::I64Add) + self.with(|insn| insn.i64_add()) } /// Add an `i64.sub` instruction to this constant expression. pub fn with_i64_sub(self) -> Self { - self.with_insn(Instruction::I64Sub) + self.with(|insn| insn.i64_sub()) } /// Add an `i64.mul` instruction to this constant expression. pub fn with_i64_mul(self) -> Self { - self.with_insn(Instruction::I64Mul) + self.with(|insn| insn.i64_mul()) } /// Returns the function, if any, referenced by this global. @@ -4008,7 +2410,7 @@ impl ConstExpr { impl Encode for ConstExpr { fn encode(&self, sink: &mut Vec<u8>) { sink.extend(&self.bytes); - Instruction::End.encode(sink); + InstructionSink::new(sink).end(); } } @@ -4046,7 +2448,7 @@ mod tests { use super::*; let mut f = Function::new([(1, ValType::I32), (1, ValType::F32)]); - f.instruction(&Instruction::End); + f.instructions().end(); let mut code_from_func = CodeSection::new(); code_from_func.function(&f); let bytes = f.into_raw_body(); diff --git a/third_party/rust/wasm-encoder/src/core/custom.rs b/third_party/rust/wasm-encoder/src/core/custom.rs @@ -1,4 +1,4 @@ -use crate::{encoding_size, Encode, Section, SectionId}; +use crate::{Encode, Section, SectionId, encoding_size}; use alloc::borrow::Cow; use alloc::vec::Vec; diff --git a/third_party/rust/wasm-encoder/src/core/data.rs b/third_party/rust/wasm-encoder/src/core/data.rs @@ -1,4 +1,4 @@ -use crate::{encode_section, encoding_size, ConstExpr, Encode, Section, SectionId}; +use crate::{ConstExpr, Encode, Section, SectionId, encode_section, encoding_size}; use alloc::vec::Vec; /// An encoder for the data section. diff --git a/third_party/rust/wasm-encoder/src/core/dump.rs b/third_party/rust/wasm-encoder/src/core/dump.rs @@ -1,4 +1,4 @@ -use crate::{CustomSection, Encode, Section}; +use crate::{CustomSection, Encode, Ieee32, Ieee64, Section}; use alloc::borrow::Cow; use alloc::string::String; use alloc::vec; @@ -305,9 +305,9 @@ pub enum CoreDumpValue { /// An i64 value I64(i64), /// An f32 value - F32(f32), + F32(Ieee32), /// An f64 value - F64(f64), + F64(Ieee64), } impl Encode for CoreDumpValue { diff --git a/third_party/rust/wasm-encoder/src/core/elements.rs b/third_party/rust/wasm-encoder/src/core/elements.rs @@ -1,4 +1,4 @@ -use crate::{encode_section, ConstExpr, Encode, RefType, Section, SectionId}; +use crate::{ConstExpr, Encode, RefType, Section, SectionId, encode_section}; use alloc::borrow::Cow; use alloc::vec::Vec; diff --git a/third_party/rust/wasm-encoder/src/core/exports.rs b/third_party/rust/wasm-encoder/src/core/exports.rs @@ -1,7 +1,7 @@ use super::{ CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT, CORE_TABLE_SORT, CORE_TAG_SORT, }; -use crate::{encode_section, Encode, Section, SectionId}; +use crate::{Encode, Section, SectionId, encode_section}; use alloc::vec::Vec; /// Represents the kind of an export from a WebAssembly module. diff --git a/third_party/rust/wasm-encoder/src/core/functions.rs b/third_party/rust/wasm-encoder/src/core/functions.rs @@ -1,4 +1,4 @@ -use crate::{encode_section, Encode, Section, SectionId}; +use crate::{Encode, Section, SectionId, encode_section}; use alloc::vec::Vec; /// An encoder for the function section of WebAssembly modules. diff --git a/third_party/rust/wasm-encoder/src/core/globals.rs b/third_party/rust/wasm-encoder/src/core/globals.rs @@ -1,4 +1,4 @@ -use crate::{encode_section, ConstExpr, Encode, Section, SectionId, ValType}; +use crate::{ConstExpr, Encode, Section, SectionId, ValType, encode_section}; use alloc::vec::Vec; /// An encoder for the global section. diff --git a/third_party/rust/wasm-encoder/src/core/imports.rs b/third_party/rust/wasm-encoder/src/core/imports.rs @@ -1,6 +1,7 @@ use crate::{ - encode_section, Encode, GlobalType, MemoryType, Section, SectionId, TableType, TagType, - CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT, CORE_TABLE_SORT, CORE_TAG_SORT, + CORE_FUNCTION_EXACT_SORT, CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT, + CORE_TABLE_SORT, CORE_TAG_SORT, Encode, GlobalType, MemoryType, Section, SectionId, TableType, + TagType, encode_section, }; use alloc::vec::Vec; @@ -21,14 +22,22 @@ pub enum EntityType { /// /// This variant is used with the exception handling proposal. Tag(TagType), + /// A function exact type. + /// + /// The value is an index into the types section. + FunctionExact(u32), } impl Encode for EntityType { fn encode(&self, sink: &mut Vec<u8>) { match self { - Self::Function(i) => { + Self::Function(f) => { sink.push(CORE_FUNCTION_SORT); - i.encode(sink); + f.encode(sink); + } + Self::FunctionExact(f) => { + sink.push(CORE_FUNCTION_EXACT_SORT); + f.encode(sink); } Self::Table(t) => { sink.push(CORE_TABLE_SORT); diff --git a/third_party/rust/wasm-encoder/src/core/instructions.rs b/third_party/rust/wasm-encoder/src/core/instructions.rs @@ -0,0 +1,4686 @@ +#[allow(unused_imports)] +use crate::Instruction; +use crate::{ + BlockType, Catch, Encode, Handle, HeapType, Ieee32, Ieee64, Lane, MemArg, Ordering, RefType, + ValType, encode_vec, +}; +use alloc::vec::Vec; + +/// An encoder for Wasm instructions. +#[derive(Debug)] +pub struct InstructionSink<'a> { + sink: &'a mut Vec<u8>, +} + +impl<'a> InstructionSink<'a> { + /// Create an instruction encoder pointing to the given byte sink. + pub fn new(sink: &'a mut Vec<u8>) -> Self { + Self { sink } + } + + // Control instructions. + + /// Encode [`Instruction::Unreachable`]. + pub fn unreachable(&mut self) -> &mut Self { + self.sink.push(0x00); + self + } + + /// Encode [`Instruction::Nop`]. + pub fn nop(&mut self) -> &mut Self { + self.sink.push(0x01); + self + } + + /// Encode [`Instruction::Block`]. + pub fn block(&mut self, bt: BlockType) -> &mut Self { + self.sink.push(0x02); + bt.encode(self.sink); + self + } + + /// Encode [`Instruction::Loop`]. + pub fn loop_(&mut self, bt: BlockType) -> &mut Self { + self.sink.push(0x03); + bt.encode(self.sink); + self + } + + /// Encode [`Instruction::If`]. + pub fn if_(&mut self, bt: BlockType) -> &mut Self { + self.sink.push(0x04); + bt.encode(self.sink); + self + } + + /// Encode [`Instruction::Else`]. + pub fn else_(&mut self) -> &mut Self { + self.sink.push(0x05); + self + } + + /// Encode [`Instruction::End`]. + pub fn end(&mut self) -> &mut Self { + self.sink.push(0x0B); + self + } + + /// Encode [`Instruction::Br`]. + pub fn br(&mut self, l: u32) -> &mut Self { + self.sink.push(0x0C); + l.encode(self.sink); + self + } + + /// Encode [`Instruction::BrIf`]. + pub fn br_if(&mut self, l: u32) -> &mut Self { + self.sink.push(0x0D); + l.encode(self.sink); + self + } + + /// Encode [`Instruction::BrTable`]. + pub fn br_table<V: IntoIterator<Item = u32>>(&mut self, ls: V, l: u32) -> &mut Self + where + V::IntoIter: ExactSizeIterator, + { + self.sink.push(0x0E); + encode_vec(ls, self.sink); + l.encode(self.sink); + self + } + + /// Encode [`Instruction::BrOnNull`]. + pub fn br_on_null(&mut self, l: u32) -> &mut Self { + self.sink.push(0xD5); + l.encode(self.sink); + self + } + + /// Encode [`Instruction::BrOnNonNull`]. + pub fn br_on_non_null(&mut self, l: u32) -> &mut Self { + self.sink.push(0xD6); + l.encode(self.sink); + self + } + + /// Encode [`Instruction::Return`]. + pub fn return_(&mut self) -> &mut Self { + self.sink.push(0x0F); + self + } + + /// Encode [`Instruction::Call`]. + pub fn call(&mut self, f: u32) -> &mut Self { + self.sink.push(0x10); + f.encode(self.sink); + self + } + + /// Encode [`Instruction::CallRef`]. + pub fn call_ref(&mut self, ty: u32) -> &mut Self { + self.sink.push(0x14); + ty.encode(self.sink); + self + } + + /// Encode [`Instruction::CallIndirect`]. + pub fn call_indirect(&mut self, table_index: u32, type_index: u32) -> &mut Self { + self.sink.push(0x11); + type_index.encode(self.sink); + table_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ReturnCallRef`]. + pub fn return_call_ref(&mut self, ty: u32) -> &mut Self { + self.sink.push(0x15); + ty.encode(self.sink); + self + } + + /// Encode [`Instruction::ReturnCall`]. + pub fn return_call(&mut self, f: u32) -> &mut Self { + self.sink.push(0x12); + f.encode(self.sink); + self + } + + /// Encode [`Instruction::ReturnCallIndirect`]. + pub fn return_call_indirect(&mut self, table_index: u32, type_index: u32) -> &mut Self { + self.sink.push(0x13); + type_index.encode(self.sink); + table_index.encode(self.sink); + self + } + + /// Encode [`Instruction::TryTable`]. + pub fn try_table<V: IntoIterator<Item = Catch>>( + &mut self, + ty: BlockType, + catches: V, + ) -> &mut Self + where + V::IntoIter: ExactSizeIterator, + { + self.sink.push(0x1f); + ty.encode(self.sink); + encode_vec(catches, self.sink); + self + } + + /// Encode [`Instruction::Throw`]. + pub fn throw(&mut self, t: u32) -> &mut Self { + self.sink.push(0x08); + t.encode(self.sink); + self + } + + /// Encode [`Instruction::ThrowRef`]. + pub fn throw_ref(&mut self) -> &mut Self { + self.sink.push(0x0A); + self + } + + // Deprecated exception-handling instructions + + /// Encode [`Instruction::Try`]. + pub fn try_(&mut self, bt: BlockType) -> &mut Self { + self.sink.push(0x06); + bt.encode(self.sink); + self + } + + /// Encode [`Instruction::Delegate`]. + pub fn delegate(&mut self, l: u32) -> &mut Self { + self.sink.push(0x18); + l.encode(self.sink); + self + } + + /// Encode [`Instruction::Catch`]. + pub fn catch(&mut self, t: u32) -> &mut Self { + self.sink.push(0x07); + t.encode(self.sink); + self + } + + /// Encode [`Instruction::CatchAll`]. + pub fn catch_all(&mut self) -> &mut Self { + self.sink.push(0x19); + self + } + + /// Encode [`Instruction::Rethrow`]. + pub fn rethrow(&mut self, l: u32) -> &mut Self { + self.sink.push(0x09); + l.encode(self.sink); + self + } + + // Parametric instructions. + + /// Encode [`Instruction::Drop`]. + pub fn drop(&mut self) -> &mut Self { + self.sink.push(0x1A); + self + } + + /// Encode [`Instruction::Select`]. + pub fn select(&mut self) -> &mut Self { + self.sink.push(0x1B); + self + } + + // Variable instructions. + + /// Encode [`Instruction::LocalGet`]. + pub fn local_get(&mut self, l: u32) -> &mut Self { + self.sink.push(0x20); + l.encode(self.sink); + self + } + + /// Encode [`Instruction::LocalSet`]. + pub fn local_set(&mut self, l: u32) -> &mut Self { + self.sink.push(0x21); + l.encode(self.sink); + self + } + + /// Encode [`Instruction::LocalTee`]. + pub fn local_tee(&mut self, l: u32) -> &mut Self { + self.sink.push(0x22); + l.encode(self.sink); + self + } + + /// Encode [`Instruction::GlobalGet`]. + pub fn global_get(&mut self, g: u32) -> &mut Self { + self.sink.push(0x23); + g.encode(self.sink); + self + } + + /// Encode [`Instruction::GlobalSet`]. + pub fn global_set(&mut self, g: u32) -> &mut Self { + self.sink.push(0x24); + g.encode(self.sink); + self + } + + // Memory instructions. + + /// Encode [`Instruction::I32Load`]. + pub fn i32_load(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x28); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::I64Load`]. + pub fn i64_load(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x29); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::F32Load`]. + pub fn f32_load(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x2A); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::F64Load`]. + pub fn f64_load(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x2B); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::I32Load8S`]. + pub fn i32_load8_s(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x2C); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::I32Load8U`]. + pub fn i32_load8_u(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x2D); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::I32Load16S`]. + pub fn i32_load16_s(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x2E); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::I32Load16U`]. + pub fn i32_load16_u(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x2F); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::I64Load8S`]. + pub fn i64_load8_s(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x30); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::I64Load8U`]. + pub fn i64_load8_u(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x31); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::I64Load16S`]. + pub fn i64_load16_s(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x32); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::I64Load16U`]. + pub fn i64_load16_u(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x33); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::I64Load32S`]. + pub fn i64_load32_s(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x34); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::I64Load32U`]. + pub fn i64_load32_u(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x35); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::I32Store`]. + pub fn i32_store(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x36); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::I64Store`]. + pub fn i64_store(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x37); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::F32Store`]. + pub fn f32_store(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x38); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::F64Store`]. + pub fn f64_store(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x39); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::I32Store8`]. + pub fn i32_store8(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x3A); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::I32Store16`]. + pub fn i32_store16(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x3B); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::I64Store8`]. + pub fn i64_store8(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x3C); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::I64Store16`]. + pub fn i64_store16(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x3D); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::I64Store32`]. + pub fn i64_store32(&mut self, m: MemArg) -> &mut Self { + self.sink.push(0x3E); + m.encode(self.sink); + self + } + + /// Encode [`Instruction::MemorySize`]. + pub fn memory_size(&mut self, i: u32) -> &mut Self { + self.sink.push(0x3F); + i.encode(self.sink); + self + } + + /// Encode [`Instruction::MemoryGrow`]. + pub fn memory_grow(&mut self, i: u32) -> &mut Self { + self.sink.push(0x40); + i.encode(self.sink); + self + } + + /// Encode [`Instruction::MemoryInit`]. + pub fn memory_init(&mut self, mem: u32, data_index: u32) -> &mut Self { + self.sink.push(0xfc); + self.sink.push(0x08); + data_index.encode(self.sink); + mem.encode(self.sink); + self + } + + /// Encode [`Instruction::DataDrop`]. + pub fn data_drop(&mut self, data: u32) -> &mut Self { + self.sink.push(0xfc); + self.sink.push(0x09); + data.encode(self.sink); + self + } + + /// Encode [`Instruction::MemoryCopy`]. + pub fn memory_copy(&mut self, dst_mem: u32, src_mem: u32) -> &mut Self { + self.sink.push(0xfc); + self.sink.push(0x0a); + dst_mem.encode(self.sink); + src_mem.encode(self.sink); + self + } + + /// Encode [`Instruction::MemoryFill`]. + pub fn memory_fill(&mut self, mem: u32) -> &mut Self { + self.sink.push(0xfc); + self.sink.push(0x0b); + mem.encode(self.sink); + self + } + + /// Encode [`Instruction::MemoryDiscard`]. + pub fn memory_discard(&mut self, mem: u32) -> &mut Self { + self.sink.push(0xfc); + self.sink.push(0x12); + mem.encode(self.sink); + self + } + + // Numeric instructions. + + /// Encode [`Instruction::I32Const`]. + pub fn i32_const(&mut self, x: i32) -> &mut Self { + self.sink.push(0x41); + x.encode(self.sink); + self + } + + /// Encode [`Instruction::I64Const`]. + pub fn i64_const(&mut self, x: i64) -> &mut Self { + self.sink.push(0x42); + x.encode(self.sink); + self + } + + /// Encode [`Instruction::F32Const`]. + pub fn f32_const(&mut self, x: Ieee32) -> &mut Self { + self.sink.push(0x43); + let x = x.bits(); + self.sink.extend(x.to_le_bytes().iter().copied()); + self + } + + /// Encode [`Instruction::F64Const`]. + pub fn f64_const(&mut self, x: Ieee64) -> &mut Self { + self.sink.push(0x44); + let x = x.bits(); + self.sink.extend(x.to_le_bytes().iter().copied()); + self + } + + /// Encode [`Instruction::I32Eqz`]. + pub fn i32_eqz(&mut self) -> &mut Self { + self.sink.push(0x45); + self + } + + /// Encode [`Instruction::I32Eq`]. + pub fn i32_eq(&mut self) -> &mut Self { + self.sink.push(0x46); + self + } + + /// Encode [`Instruction::I32Ne`]. + pub fn i32_ne(&mut self) -> &mut Self { + self.sink.push(0x47); + self + } + + /// Encode [`Instruction::I32LtS`]. + pub fn i32_lt_s(&mut self) -> &mut Self { + self.sink.push(0x48); + self + } + + /// Encode [`Instruction::I32LtU`]. + pub fn i32_lt_u(&mut self) -> &mut Self { + self.sink.push(0x49); + self + } + + /// Encode [`Instruction::I32GtS`]. + pub fn i32_gt_s(&mut self) -> &mut Self { + self.sink.push(0x4A); + self + } + + /// Encode [`Instruction::I32GtU`]. + pub fn i32_gt_u(&mut self) -> &mut Self { + self.sink.push(0x4B); + self + } + + /// Encode [`Instruction::I32LeS`]. + pub fn i32_le_s(&mut self) -> &mut Self { + self.sink.push(0x4C); + self + } + + /// Encode [`Instruction::I32LeU`]. + pub fn i32_le_u(&mut self) -> &mut Self { + self.sink.push(0x4D); + self + } + + /// Encode [`Instruction::I32GeS`]. + pub fn i32_ge_s(&mut self) -> &mut Self { + self.sink.push(0x4E); + self + } + + /// Encode [`Instruction::I32GeU`]. + pub fn i32_ge_u(&mut self) -> &mut Self { + self.sink.push(0x4F); + self + } + + /// Encode [`Instruction::I64Eqz`]. + pub fn i64_eqz(&mut self) -> &mut Self { + self.sink.push(0x50); + self + } + + /// Encode [`Instruction::I64Eq`]. + pub fn i64_eq(&mut self) -> &mut Self { + self.sink.push(0x51); + self + } + + /// Encode [`Instruction::I64Ne`]. + pub fn i64_ne(&mut self) -> &mut Self { + self.sink.push(0x52); + self + } + + /// Encode [`Instruction::I64LtS`]. + pub fn i64_lt_s(&mut self) -> &mut Self { + self.sink.push(0x53); + self + } + + /// Encode [`Instruction::I64LtU`]. + pub fn i64_lt_u(&mut self) -> &mut Self { + self.sink.push(0x54); + self + } + + /// Encode [`Instruction::I64GtS`]. + pub fn i64_gt_s(&mut self) -> &mut Self { + self.sink.push(0x55); + self + } + + /// Encode [`Instruction::I64GtU`]. + pub fn i64_gt_u(&mut self) -> &mut Self { + self.sink.push(0x56); + self + } + + /// Encode [`Instruction::I64LeS`]. + pub fn i64_le_s(&mut self) -> &mut Self { + self.sink.push(0x57); + self + } + + /// Encode [`Instruction::I64LeU`]. + pub fn i64_le_u(&mut self) -> &mut Self { + self.sink.push(0x58); + self + } + + /// Encode [`Instruction::I64GeS`]. + pub fn i64_ge_s(&mut self) -> &mut Self { + self.sink.push(0x59); + self + } + + /// Encode [`Instruction::I64GeU`]. + pub fn i64_ge_u(&mut self) -> &mut Self { + self.sink.push(0x5A); + self + } + + /// Encode [`Instruction::F32Eq`]. + pub fn f32_eq(&mut self) -> &mut Self { + self.sink.push(0x5B); + self + } + + /// Encode [`Instruction::F32Ne`]. + pub fn f32_ne(&mut self) -> &mut Self { + self.sink.push(0x5C); + self + } + + /// Encode [`Instruction::F32Lt`]. + pub fn f32_lt(&mut self) -> &mut Self { + self.sink.push(0x5D); + self + } + + /// Encode [`Instruction::F32Gt`]. + pub fn f32_gt(&mut self) -> &mut Self { + self.sink.push(0x5E); + self + } + + /// Encode [`Instruction::F32Le`]. + pub fn f32_le(&mut self) -> &mut Self { + self.sink.push(0x5F); + self + } + + /// Encode [`Instruction::F32Ge`]. + pub fn f32_ge(&mut self) -> &mut Self { + self.sink.push(0x60); + self + } + + /// Encode [`Instruction::F64Eq`]. + pub fn f64_eq(&mut self) -> &mut Self { + self.sink.push(0x61); + self + } + + /// Encode [`Instruction::F64Ne`]. + pub fn f64_ne(&mut self) -> &mut Self { + self.sink.push(0x62); + self + } + + /// Encode [`Instruction::F64Lt`]. + pub fn f64_lt(&mut self) -> &mut Self { + self.sink.push(0x63); + self + } + + /// Encode [`Instruction::F64Gt`]. + pub fn f64_gt(&mut self) -> &mut Self { + self.sink.push(0x64); + self + } + + /// Encode [`Instruction::F64Le`]. + pub fn f64_le(&mut self) -> &mut Self { + self.sink.push(0x65); + self + } + + /// Encode [`Instruction::F64Ge`]. + pub fn f64_ge(&mut self) -> &mut Self { + self.sink.push(0x66); + self + } + + /// Encode [`Instruction::I32Clz`]. + pub fn i32_clz(&mut self) -> &mut Self { + self.sink.push(0x67); + self + } + + /// Encode [`Instruction::I32Ctz`]. + pub fn i32_ctz(&mut self) -> &mut Self { + self.sink.push(0x68); + self + } + + /// Encode [`Instruction::I32Popcnt`]. + pub fn i32_popcnt(&mut self) -> &mut Self { + self.sink.push(0x69); + self + } + + /// Encode [`Instruction::I32Add`]. + pub fn i32_add(&mut self) -> &mut Self { + self.sink.push(0x6A); + self + } + + /// Encode [`Instruction::I32Sub`]. + pub fn i32_sub(&mut self) -> &mut Self { + self.sink.push(0x6B); + self + } + + /// Encode [`Instruction::I32Mul`]. + pub fn i32_mul(&mut self) -> &mut Self { + self.sink.push(0x6C); + self + } + + /// Encode [`Instruction::I32DivS`]. + pub fn i32_div_s(&mut self) -> &mut Self { + self.sink.push(0x6D); + self + } + + /// Encode [`Instruction::I32DivU`]. + pub fn i32_div_u(&mut self) -> &mut Self { + self.sink.push(0x6E); + self + } + + /// Encode [`Instruction::I32RemS`]. + pub fn i32_rem_s(&mut self) -> &mut Self { + self.sink.push(0x6F); + self + } + + /// Encode [`Instruction::I32RemU`]. + pub fn i32_rem_u(&mut self) -> &mut Self { + self.sink.push(0x70); + self + } + + /// Encode [`Instruction::I32And`]. + pub fn i32_and(&mut self) -> &mut Self { + self.sink.push(0x71); + self + } + + /// Encode [`Instruction::I32Or`]. + pub fn i32_or(&mut self) -> &mut Self { + self.sink.push(0x72); + self + } + + /// Encode [`Instruction::I32Xor`]. + pub fn i32_xor(&mut self) -> &mut Self { + self.sink.push(0x73); + self + } + + /// Encode [`Instruction::I32Shl`]. + pub fn i32_shl(&mut self) -> &mut Self { + self.sink.push(0x74); + self + } + + /// Encode [`Instruction::I32ShrS`]. + pub fn i32_shr_s(&mut self) -> &mut Self { + self.sink.push(0x75); + self + } + + /// Encode [`Instruction::I32ShrU`]. + pub fn i32_shr_u(&mut self) -> &mut Self { + self.sink.push(0x76); + self + } + + /// Encode [`Instruction::I32Rotl`]. + pub fn i32_rotl(&mut self) -> &mut Self { + self.sink.push(0x77); + self + } + + /// Encode [`Instruction::I32Rotr`]. + pub fn i32_rotr(&mut self) -> &mut Self { + self.sink.push(0x78); + self + } + + /// Encode [`Instruction::I64Clz`]. + pub fn i64_clz(&mut self) -> &mut Self { + self.sink.push(0x79); + self + } + + /// Encode [`Instruction::I64Ctz`]. + pub fn i64_ctz(&mut self) -> &mut Self { + self.sink.push(0x7A); + self + } + + /// Encode [`Instruction::I64Popcnt`]. + pub fn i64_popcnt(&mut self) -> &mut Self { + self.sink.push(0x7B); + self + } + + /// Encode [`Instruction::I64Add`]. + pub fn i64_add(&mut self) -> &mut Self { + self.sink.push(0x7C); + self + } + + /// Encode [`Instruction::I64Sub`]. + pub fn i64_sub(&mut self) -> &mut Self { + self.sink.push(0x7D); + self + } + + /// Encode [`Instruction::I64Mul`]. + pub fn i64_mul(&mut self) -> &mut Self { + self.sink.push(0x7E); + self + } + + /// Encode [`Instruction::I64DivS`]. + pub fn i64_div_s(&mut self) -> &mut Self { + self.sink.push(0x7F); + self + } + + /// Encode [`Instruction::I64DivU`]. + pub fn i64_div_u(&mut self) -> &mut Self { + self.sink.push(0x80); + self + } + + /// Encode [`Instruction::I64RemS`]. + pub fn i64_rem_s(&mut self) -> &mut Self { + self.sink.push(0x81); + self + } + + /// Encode [`Instruction::I64RemU`]. + pub fn i64_rem_u(&mut self) -> &mut Self { + self.sink.push(0x82); + self + } + + /// Encode [`Instruction::I64And`]. + pub fn i64_and(&mut self) -> &mut Self { + self.sink.push(0x83); + self + } + + /// Encode [`Instruction::I64Or`]. + pub fn i64_or(&mut self) -> &mut Self { + self.sink.push(0x84); + self + } + + /// Encode [`Instruction::I64Xor`]. + pub fn i64_xor(&mut self) -> &mut Self { + self.sink.push(0x85); + self + } + + /// Encode [`Instruction::I64Shl`]. + pub fn i64_shl(&mut self) -> &mut Self { + self.sink.push(0x86); + self + } + + /// Encode [`Instruction::I64ShrS`]. + pub fn i64_shr_s(&mut self) -> &mut Self { + self.sink.push(0x87); + self + } + + /// Encode [`Instruction::I64ShrU`]. + pub fn i64_shr_u(&mut self) -> &mut Self { + self.sink.push(0x88); + self + } + + /// Encode [`Instruction::I64Rotl`]. + pub fn i64_rotl(&mut self) -> &mut Self { + self.sink.push(0x89); + self + } + + /// Encode [`Instruction::I64Rotr`]. + pub fn i64_rotr(&mut self) -> &mut Self { + self.sink.push(0x8A); + self + } + + /// Encode [`Instruction::F32Abs`]. + pub fn f32_abs(&mut self) -> &mut Self { + self.sink.push(0x8B); + self + } + + /// Encode [`Instruction::F32Neg`]. + pub fn f32_neg(&mut self) -> &mut Self { + self.sink.push(0x8C); + self + } + + /// Encode [`Instruction::F32Ceil`]. + pub fn f32_ceil(&mut self) -> &mut Self { + self.sink.push(0x8D); + self + } + + /// Encode [`Instruction::F32Floor`]. + pub fn f32_floor(&mut self) -> &mut Self { + self.sink.push(0x8E); + self + } + + /// Encode [`Instruction::F32Trunc`]. + pub fn f32_trunc(&mut self) -> &mut Self { + self.sink.push(0x8F); + self + } + + /// Encode [`Instruction::F32Nearest`]. + pub fn f32_nearest(&mut self) -> &mut Self { + self.sink.push(0x90); + self + } + + /// Encode [`Instruction::F32Sqrt`]. + pub fn f32_sqrt(&mut self) -> &mut Self { + self.sink.push(0x91); + self + } + + /// Encode [`Instruction::F32Add`]. + pub fn f32_add(&mut self) -> &mut Self { + self.sink.push(0x92); + self + } + + /// Encode [`Instruction::F32Sub`]. + pub fn f32_sub(&mut self) -> &mut Self { + self.sink.push(0x93); + self + } + + /// Encode [`Instruction::F32Mul`]. + pub fn f32_mul(&mut self) -> &mut Self { + self.sink.push(0x94); + self + } + + /// Encode [`Instruction::F32Div`]. + pub fn f32_div(&mut self) -> &mut Self { + self.sink.push(0x95); + self + } + + /// Encode [`Instruction::F32Min`]. + pub fn f32_min(&mut self) -> &mut Self { + self.sink.push(0x96); + self + } + + /// Encode [`Instruction::F32Max`]. + pub fn f32_max(&mut self) -> &mut Self { + self.sink.push(0x97); + self + } + + /// Encode [`Instruction::F32Copysign`]. + pub fn f32_copysign(&mut self) -> &mut Self { + self.sink.push(0x98); + self + } + + /// Encode [`Instruction::F64Abs`]. + pub fn f64_abs(&mut self) -> &mut Self { + self.sink.push(0x99); + self + } + + /// Encode [`Instruction::F64Neg`]. + pub fn f64_neg(&mut self) -> &mut Self { + self.sink.push(0x9A); + self + } + + /// Encode [`Instruction::F64Ceil`]. + pub fn f64_ceil(&mut self) -> &mut Self { + self.sink.push(0x9B); + self + } + + /// Encode [`Instruction::F64Floor`]. + pub fn f64_floor(&mut self) -> &mut Self { + self.sink.push(0x9C); + self + } + + /// Encode [`Instruction::F64Trunc`]. + pub fn f64_trunc(&mut self) -> &mut Self { + self.sink.push(0x9D); + self + } + + /// Encode [`Instruction::F64Nearest`]. + pub fn f64_nearest(&mut self) -> &mut Self { + self.sink.push(0x9E); + self + } + + /// Encode [`Instruction::F64Sqrt`]. + pub fn f64_sqrt(&mut self) -> &mut Self { + self.sink.push(0x9F); + self + } + + /// Encode [`Instruction::F64Add`]. + pub fn f64_add(&mut self) -> &mut Self { + self.sink.push(0xA0); + self + } + + /// Encode [`Instruction::F64Sub`]. + pub fn f64_sub(&mut self) -> &mut Self { + self.sink.push(0xA1); + self + } + + /// Encode [`Instruction::F64Mul`]. + pub fn f64_mul(&mut self) -> &mut Self { + self.sink.push(0xA2); + self + } + + /// Encode [`Instruction::F64Div`]. + pub fn f64_div(&mut self) -> &mut Self { + self.sink.push(0xA3); + self + } + + /// Encode [`Instruction::F64Min`]. + pub fn f64_min(&mut self) -> &mut Self { + self.sink.push(0xA4); + self + } + + /// Encode [`Instruction::F64Max`]. + pub fn f64_max(&mut self) -> &mut Self { + self.sink.push(0xA5); + self + } + + /// Encode [`Instruction::F64Copysign`]. + pub fn f64_copysign(&mut self) -> &mut Self { + self.sink.push(0xA6); + self + } + + /// Encode [`Instruction::I32WrapI64`]. + pub fn i32_wrap_i64(&mut self) -> &mut Self { + self.sink.push(0xA7); + self + } + + /// Encode [`Instruction::I32TruncF32S`]. + pub fn i32_trunc_f32_s(&mut self) -> &mut Self { + self.sink.push(0xA8); + self + } + + /// Encode [`Instruction::I32TruncF32U`]. + pub fn i32_trunc_f32_u(&mut self) -> &mut Self { + self.sink.push(0xA9); + self + } + + /// Encode [`Instruction::I32TruncF64S`]. + pub fn i32_trunc_f64_s(&mut self) -> &mut Self { + self.sink.push(0xAA); + self + } + + /// Encode [`Instruction::I32TruncF64U`]. + pub fn i32_trunc_f64_u(&mut self) -> &mut Self { + self.sink.push(0xAB); + self + } + + /// Encode [`Instruction::I64ExtendI32S`]. + pub fn i64_extend_i32_s(&mut self) -> &mut Self { + self.sink.push(0xAC); + self + } + + /// Encode [`Instruction::I64ExtendI32U`]. + pub fn i64_extend_i32_u(&mut self) -> &mut Self { + self.sink.push(0xAD); + self + } + + /// Encode [`Instruction::I64TruncF32S`]. + pub fn i64_trunc_f32_s(&mut self) -> &mut Self { + self.sink.push(0xAE); + self + } + + /// Encode [`Instruction::I64TruncF32U`]. + pub fn i64_trunc_f32_u(&mut self) -> &mut Self { + self.sink.push(0xAF); + self + } + + /// Encode [`Instruction::I64TruncF64S`]. + pub fn i64_trunc_f64_s(&mut self) -> &mut Self { + self.sink.push(0xB0); + self + } + + /// Encode [`Instruction::I64TruncF64U`]. + pub fn i64_trunc_f64_u(&mut self) -> &mut Self { + self.sink.push(0xB1); + self + } + + /// Encode [`Instruction::F32ConvertI32S`]. + pub fn f32_convert_i32_s(&mut self) -> &mut Self { + self.sink.push(0xB2); + self + } + + /// Encode [`Instruction::F32ConvertI32U`]. + pub fn f32_convert_i32_u(&mut self) -> &mut Self { + self.sink.push(0xB3); + self + } + + /// Encode [`Instruction::F32ConvertI64S`]. + pub fn f32_convert_i64_s(&mut self) -> &mut Self { + self.sink.push(0xB4); + self + } + + /// Encode [`Instruction::F32ConvertI64U`]. + pub fn f32_convert_i64_u(&mut self) -> &mut Self { + self.sink.push(0xB5); + self + } + + /// Encode [`Instruction::F32DemoteF64`]. + pub fn f32_demote_f64(&mut self) -> &mut Self { + self.sink.push(0xB6); + self + } + + /// Encode [`Instruction::F64ConvertI32S`]. + pub fn f64_convert_i32_s(&mut self) -> &mut Self { + self.sink.push(0xB7); + self + } + + /// Encode [`Instruction::F64ConvertI32U`]. + pub fn f64_convert_i32_u(&mut self) -> &mut Self { + self.sink.push(0xB8); + self + } + + /// Encode [`Instruction::F64ConvertI64S`]. + pub fn f64_convert_i64_s(&mut self) -> &mut Self { + self.sink.push(0xB9); + self + } + + /// Encode [`Instruction::F64ConvertI64U`]. + pub fn f64_convert_i64_u(&mut self) -> &mut Self { + self.sink.push(0xBA); + self + } + + /// Encode [`Instruction::F64PromoteF32`]. + pub fn f64_promote_f32(&mut self) -> &mut Self { + self.sink.push(0xBB); + self + } + + /// Encode [`Instruction::I32ReinterpretF32`]. + pub fn i32_reinterpret_f32(&mut self) -> &mut Self { + self.sink.push(0xBC); + self + } + + /// Encode [`Instruction::I64ReinterpretF64`]. + pub fn i64_reinterpret_f64(&mut self) -> &mut Self { + self.sink.push(0xBD); + self + } + + /// Encode [`Instruction::F32ReinterpretI32`]. + pub fn f32_reinterpret_i32(&mut self) -> &mut Self { + self.sink.push(0xBE); + self + } + + /// Encode [`Instruction::F64ReinterpretI64`]. + pub fn f64_reinterpret_i64(&mut self) -> &mut Self { + self.sink.push(0xBF); + self + } + + /// Encode [`Instruction::I32Extend8S`]. + pub fn i32_extend8_s(&mut self) -> &mut Self { + self.sink.push(0xC0); + self + } + + /// Encode [`Instruction::I32Extend16S`]. + pub fn i32_extend16_s(&mut self) -> &mut Self { + self.sink.push(0xC1); + self + } + + /// Encode [`Instruction::I64Extend8S`]. + pub fn i64_extend8_s(&mut self) -> &mut Self { + self.sink.push(0xC2); + self + } + + /// Encode [`Instruction::I64Extend16S`]. + pub fn i64_extend16_s(&mut self) -> &mut Self { + self.sink.push(0xC3); + self + } + + /// Encode [`Instruction::I64Extend32S`]. + pub fn i64_extend32_s(&mut self) -> &mut Self { + self.sink.push(0xC4); + self + } + + /// Encode [`Instruction::I32TruncSatF32S`]. + pub fn i32_trunc_sat_f32_s(&mut self) -> &mut Self { + self.sink.push(0xFC); + self.sink.push(0x00); + self + } + + /// Encode [`Instruction::I32TruncSatF32U`]. + pub fn i32_trunc_sat_f32_u(&mut self) -> &mut Self { + self.sink.push(0xFC); + self.sink.push(0x01); + self + } + + /// Encode [`Instruction::I32TruncSatF64S`]. + pub fn i32_trunc_sat_f64_s(&mut self) -> &mut Self { + self.sink.push(0xFC); + self.sink.push(0x02); + self + } + + /// Encode [`Instruction::I32TruncSatF64U`]. + pub fn i32_trunc_sat_f64_u(&mut self) -> &mut Self { + self.sink.push(0xFC); + self.sink.push(0x03); + self + } + + /// Encode [`Instruction::I64TruncSatF32S`]. + pub fn i64_trunc_sat_f32_s(&mut self) -> &mut Self { + self.sink.push(0xFC); + self.sink.push(0x04); + self + } + + /// Encode [`Instruction::I64TruncSatF32U`]. + pub fn i64_trunc_sat_f32_u(&mut self) -> &mut Self { + self.sink.push(0xFC); + self.sink.push(0x05); + self + } + + /// Encode [`Instruction::I64TruncSatF64S`]. + pub fn i64_trunc_sat_f64_s(&mut self) -> &mut Self { + self.sink.push(0xFC); + self.sink.push(0x06); + self + } + + /// Encode [`Instruction::I64TruncSatF64U`]. + pub fn i64_trunc_sat_f64_u(&mut self) -> &mut Self { + self.sink.push(0xFC); + self.sink.push(0x07); + self + } + + // Reference types instructions. + + /// Encode [`Instruction::TypedSelect`]. + pub fn typed_select(&mut self, ty: ValType) -> &mut Self { + self.sink.push(0x1c); + [ty].encode(self.sink); + self + } + + /// Encode [`Instruction::TypedSelect`] with multiple results (currently invalid). + pub fn typed_select_multi(&mut self, tys: &[ValType]) -> &mut Self { + self.sink.push(0x1c); + tys.encode(self.sink); + self + } + + /// Encode [`Instruction::RefNull`]. + pub fn ref_null(&mut self, ty: HeapType) -> &mut Self { + self.sink.push(0xd0); + ty.encode(self.sink); + self + } + + /// Encode [`Instruction::RefIsNull`]. + pub fn ref_is_null(&mut self) -> &mut Self { + self.sink.push(0xd1); + self + } + + /// Encode [`Instruction::RefFunc`]. + pub fn ref_func(&mut self, f: u32) -> &mut Self { + self.sink.push(0xd2); + f.encode(self.sink); + self + } + + /// Encode [`Instruction::RefEq`]. + pub fn ref_eq(&mut self) -> &mut Self { + self.sink.push(0xd3); + self + } + + /// Encode [`Instruction::RefAsNonNull`]. + pub fn ref_as_non_null(&mut self) -> &mut Self { + self.sink.push(0xd4); + self + } + + // GC types instructions. + + /// Encode [`Instruction::StructNew`]. + pub fn struct_new(&mut self, type_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x00); + type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::StructNewDefault`]. + pub fn struct_new_default(&mut self, type_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x01); + type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::StructGet`]. + pub fn struct_get(&mut self, struct_type_index: u32, field_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x02); + struct_type_index.encode(self.sink); + field_index.encode(self.sink); + self + } + + /// Encode [`Instruction::StructGetS`]. + pub fn struct_get_s(&mut self, struct_type_index: u32, field_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x03); + struct_type_index.encode(self.sink); + field_index.encode(self.sink); + self + } + + /// Encode [`Instruction::StructGetU`]. + pub fn struct_get_u(&mut self, struct_type_index: u32, field_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x04); + struct_type_index.encode(self.sink); + field_index.encode(self.sink); + self + } + + /// Encode [`Instruction::StructSet`]. + pub fn struct_set(&mut self, struct_type_index: u32, field_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x05); + struct_type_index.encode(self.sink); + field_index.encode(self.sink); + self + } + + /// Encode [`Instruction::StructNewDesc`]. + pub fn struct_new_desc(&mut self, type_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x20); + type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::StructNewDefaultDesc`]. + pub fn struct_new_default_desc(&mut self, type_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x21); + type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayNew`]. + pub fn array_new(&mut self, type_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x06); + type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayNewDefault`]. + pub fn array_new_default(&mut self, type_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x07); + type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayNewFixed`]. + pub fn array_new_fixed(&mut self, array_type_index: u32, array_size: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x08); + array_type_index.encode(self.sink); + array_size.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayNewData`]. + pub fn array_new_data(&mut self, array_type_index: u32, array_data_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x09); + array_type_index.encode(self.sink); + array_data_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayNewElem`]. + pub fn array_new_elem(&mut self, array_type_index: u32, array_elem_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x0a); + array_type_index.encode(self.sink); + array_elem_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayGet`]. + pub fn array_get(&mut self, type_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x0b); + type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayGetS`]. + pub fn array_get_s(&mut self, type_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x0c); + type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayGetU`]. + pub fn array_get_u(&mut self, type_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x0d); + type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArraySet`]. + pub fn array_set(&mut self, type_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x0e); + type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayLen`]. + pub fn array_len(&mut self) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x0f); + self + } + + /// Encode [`Instruction::ArrayFill`]. + pub fn array_fill(&mut self, type_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x10); + type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayCopy`]. + pub fn array_copy( + &mut self, + array_type_index_dst: u32, + array_type_index_src: u32, + ) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x11); + array_type_index_dst.encode(self.sink); + array_type_index_src.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayInitData`]. + pub fn array_init_data(&mut self, array_type_index: u32, array_data_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x12); + array_type_index.encode(self.sink); + array_data_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayInitElem`]. + pub fn array_init_elem(&mut self, array_type_index: u32, array_elem_index: u32) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x13); + array_type_index.encode(self.sink); + array_elem_index.encode(self.sink); + self + } + + /// Encode [`Instruction::RefTestNonNull`]. + pub fn ref_test_non_null(&mut self, heap_type: HeapType) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x14); + heap_type.encode(self.sink); + self + } + + /// Encode [`Instruction::RefTestNullable`]. + pub fn ref_test_nullable(&mut self, heap_type: HeapType) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x15); + heap_type.encode(self.sink); + self + } + + /// Encode [`Instruction::RefCastNonNull`]. + pub fn ref_cast_non_null(&mut self, heap_type: HeapType) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x16); + heap_type.encode(self.sink); + self + } + + /// Encode [`Instruction::RefCastNullable`]. + pub fn ref_cast_nullable(&mut self, heap_type: HeapType) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x17); + heap_type.encode(self.sink); + self + } + + /// Encode [`Instruction::BrOnCast`]. + pub fn br_on_cast( + &mut self, + relative_depth: u32, + from_ref_type: RefType, + to_ref_type: RefType, + ) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x18); + let cast_flags = (from_ref_type.nullable as u8) | ((to_ref_type.nullable as u8) << 1); + self.sink.push(cast_flags); + relative_depth.encode(self.sink); + from_ref_type.heap_type.encode(self.sink); + to_ref_type.heap_type.encode(self.sink); + self + } + + /// Encode [`Instruction::BrOnCastFail`]. + pub fn br_on_cast_fail( + &mut self, + relative_depth: u32, + from_ref_type: RefType, + to_ref_type: RefType, + ) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x19); + let cast_flags = (from_ref_type.nullable as u8) | ((to_ref_type.nullable as u8) << 1); + self.sink.push(cast_flags); + relative_depth.encode(self.sink); + from_ref_type.heap_type.encode(self.sink); + to_ref_type.heap_type.encode(self.sink); + self + } + + /// Encode [`Instruction::AnyConvertExtern`]. + pub fn any_convert_extern(&mut self) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x1a); + self + } + + /// Encode [`Instruction::ExternConvertAny`]. + pub fn extern_convert_any(&mut self) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x1b); + self + } + + /// Encode [`Instruction::RefI31`]. + pub fn ref_i31(&mut self) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x1c); + self + } + + /// Encode [`Instruction::I31GetS`]. + pub fn i31_get_s(&mut self) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x1d); + self + } + + /// Encode [`Instruction::I31GetU`]. + pub fn i31_get_u(&mut self) -> &mut Self { + self.sink.push(0xfb); + self.sink.push(0x1e); + self + } + + // Bulk memory instructions. + + /// Encode [`Instruction::TableInit`]. + pub fn table_init(&mut self, table: u32, elem_index: u32) -> &mut Self { + self.sink.push(0xfc); + self.sink.push(0x0c); + elem_index.encode(self.sink); + table.encode(self.sink); + self + } + + /// Encode [`Instruction::ElemDrop`]. + pub fn elem_drop(&mut self, segment: u32) -> &mut Self { + self.sink.push(0xfc); + self.sink.push(0x0d); + segment.encode(self.sink); + self + } + + /// Encode [`Instruction::TableFill`]. + pub fn table_fill(&mut self, table: u32) -> &mut Self { + self.sink.push(0xfc); + self.sink.push(0x11); + table.encode(self.sink); + self + } + + /// Encode [`Instruction::TableSet`]. + pub fn table_set(&mut self, table: u32) -> &mut Self { + self.sink.push(0x26); + table.encode(self.sink); + self + } + + /// Encode [`Instruction::TableGet`]. + pub fn table_get(&mut self, table: u32) -> &mut Self { + self.sink.push(0x25); + table.encode(self.sink); + self + } + + /// Encode [`Instruction::TableGrow`]. + pub fn table_grow(&mut self, table: u32) -> &mut Self { + self.sink.push(0xfc); + self.sink.push(0x0f); + table.encode(self.sink); + self + } + + /// Encode [`Instruction::TableSize`]. + pub fn table_size(&mut self, table: u32) -> &mut Self { + self.sink.push(0xfc); + self.sink.push(0x10); + table.encode(self.sink); + self + } + + /// Encode [`Instruction::TableCopy`]. + pub fn table_copy(&mut self, dst_table: u32, src_table: u32) -> &mut Self { + self.sink.push(0xfc); + self.sink.push(0x0e); + dst_table.encode(self.sink); + src_table.encode(self.sink); + self + } + + // SIMD instructions. + + /// Encode [`Instruction::V128Load`]. + pub fn v128_load(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFD); + 0x00u32.encode(self.sink); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::V128Load8x8S`]. + pub fn v128_load8x8_s(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFD); + 0x01u32.encode(self.sink); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::V128Load8x8U`]. + pub fn v128_load8x8_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFD); + 0x02u32.encode(self.sink); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::V128Load16x4S`]. + pub fn v128_load16x4_s(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFD); + 0x03u32.encode(self.sink); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::V128Load16x4U`]. + pub fn v128_load16x4_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFD); + 0x04u32.encode(self.sink); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::V128Load32x2S`]. + pub fn v128_load32x2_s(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFD); + 0x05u32.encode(self.sink); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::V128Load32x2U`]. + pub fn v128_load32x2_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFD); + 0x06u32.encode(self.sink); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::V128Load8Splat`]. + pub fn v128_load8_splat(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFD); + 0x07u32.encode(self.sink); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::V128Load16Splat`]. + pub fn v128_load16_splat(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFD); + 0x08u32.encode(self.sink); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::V128Load32Splat`]. + pub fn v128_load32_splat(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFD); + 0x09u32.encode(self.sink); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::V128Load64Splat`]. + pub fn v128_load64_splat(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFD); + 0x0Au32.encode(self.sink); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::V128Load32Zero`]. + pub fn v128_load32_zero(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFD); + 0x5Cu32.encode(self.sink); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::V128Load64Zero`]. + pub fn v128_load64_zero(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFD); + 0x5Du32.encode(self.sink); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::V128Store`]. + pub fn v128_store(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFD); + 0x0Bu32.encode(self.sink); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::V128Load8Lane`]. + pub fn v128_load8_lane(&mut self, memarg: MemArg, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x54u32.encode(self.sink); + memarg.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::V128Load16Lane`]. + pub fn v128_load16_lane(&mut self, memarg: MemArg, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x55u32.encode(self.sink); + memarg.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::V128Load32Lane`]. + pub fn v128_load32_lane(&mut self, memarg: MemArg, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x56u32.encode(self.sink); + memarg.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::V128Load64Lane`]. + pub fn v128_load64_lane(&mut self, memarg: MemArg, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x57u32.encode(self.sink); + memarg.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::V128Store8Lane`]. + pub fn v128_store8_lane(&mut self, memarg: MemArg, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x58u32.encode(self.sink); + memarg.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::V128Store16Lane`]. + pub fn v128_store16_lane(&mut self, memarg: MemArg, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x59u32.encode(self.sink); + memarg.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::V128Store32Lane`]. + pub fn v128_store32_lane(&mut self, memarg: MemArg, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x5Au32.encode(self.sink); + memarg.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::V128Store64Lane`]. + pub fn v128_store64_lane(&mut self, memarg: MemArg, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x5Bu32.encode(self.sink); + memarg.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::V128Const`]. + pub fn v128_const(&mut self, x: i128) -> &mut Self { + self.sink.push(0xFD); + 0x0Cu32.encode(self.sink); + self.sink.extend(x.to_le_bytes().iter().copied()); + self + } + + /// Encode [`Instruction::I8x16Shuffle`]. + pub fn i8x16_shuffle(&mut self, lanes: [Lane; 16]) -> &mut Self { + self.sink.push(0xFD); + 0x0Du32.encode(self.sink); + self.sink.extend(lanes.iter().copied()); + self + } + + /// Encode [`Instruction::I8x16ExtractLaneS`]. + pub fn i8x16_extract_lane_s(&mut self, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x15u32.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::I8x16ExtractLaneU`]. + pub fn i8x16_extract_lane_u(&mut self, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x16u32.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::I8x16ReplaceLane`]. + pub fn i8x16_replace_lane(&mut self, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x17u32.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::I16x8ExtractLaneS`]. + pub fn i16x8_extract_lane_s(&mut self, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x18u32.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::I16x8ExtractLaneU`]. + pub fn i16x8_extract_lane_u(&mut self, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x19u32.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::I16x8ReplaceLane`]. + pub fn i16x8_replace_lane(&mut self, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x1Au32.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::I32x4ExtractLane`]. + pub fn i32x4_extract_lane(&mut self, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x1Bu32.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::I32x4ReplaceLane`]. + pub fn i32x4_replace_lane(&mut self, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x1Cu32.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::I64x2ExtractLane`]. + pub fn i64x2_extract_lane(&mut self, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x1Du32.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::I64x2ReplaceLane`]. + pub fn i64x2_replace_lane(&mut self, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x1Eu32.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::F32x4ExtractLane`]. + pub fn f32x4_extract_lane(&mut self, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x1Fu32.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::F32x4ReplaceLane`]. + pub fn f32x4_replace_lane(&mut self, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x20u32.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::F64x2ExtractLane`]. + pub fn f64x2_extract_lane(&mut self, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x21u32.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::F64x2ReplaceLane`]. + pub fn f64x2_replace_lane(&mut self, lane: Lane) -> &mut Self { + self.sink.push(0xFD); + 0x22u32.encode(self.sink); + self.sink.push(lane); + self + } + + /// Encode [`Instruction::I8x16Swizzle`]. + pub fn i8x16_swizzle(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x0Eu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16Splat`]. + pub fn i8x16_splat(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x0Fu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8Splat`]. + pub fn i16x8_splat(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x10u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4Splat`]. + pub fn i32x4_splat(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x11u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2Splat`]. + pub fn i64x2_splat(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x12u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Splat`]. + pub fn f32x4_splat(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x13u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Splat`]. + pub fn f64x2_splat(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x14u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16Eq`]. + pub fn i8x16_eq(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x23u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16Ne`]. + pub fn i8x16_ne(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x24u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16LtS`]. + pub fn i8x16_lt_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x25u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16LtU`]. + pub fn i8x16_lt_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x26u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16GtS`]. + pub fn i8x16_gt_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x27u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16GtU`]. + pub fn i8x16_gt_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x28u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16LeS`]. + pub fn i8x16_le_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x29u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16LeU`]. + pub fn i8x16_le_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x2Au32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16GeS`]. + pub fn i8x16_ge_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x2Bu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16GeU`]. + pub fn i8x16_ge_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x2Cu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8Eq`]. + pub fn i16x8_eq(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x2Du32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8Ne`]. + pub fn i16x8_ne(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x2Eu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8LtS`]. + pub fn i16x8_lt_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x2Fu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8LtU`]. + pub fn i16x8_lt_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x30u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8GtS`]. + pub fn i16x8_gt_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x31u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8GtU`]. + pub fn i16x8_gt_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x32u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8LeS`]. + pub fn i16x8_le_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x33u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8LeU`]. + pub fn i16x8_le_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x34u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8GeS`]. + pub fn i16x8_ge_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x35u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8GeU`]. + pub fn i16x8_ge_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x36u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4Eq`]. + pub fn i32x4_eq(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x37u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4Ne`]. + pub fn i32x4_ne(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x38u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4LtS`]. + pub fn i32x4_lt_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x39u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4LtU`]. + pub fn i32x4_lt_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x3Au32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4GtS`]. + pub fn i32x4_gt_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x3Bu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4GtU`]. + pub fn i32x4_gt_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x3Cu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4LeS`]. + pub fn i32x4_le_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x3Du32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4LeU`]. + pub fn i32x4_le_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x3Eu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4GeS`]. + pub fn i32x4_ge_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x3Fu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4GeU`]. + pub fn i32x4_ge_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x40u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2Eq`]. + pub fn i64x2_eq(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xD6u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2Ne`]. + pub fn i64x2_ne(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xD7u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2LtS`]. + pub fn i64x2_lt_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xD8u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2GtS`]. + pub fn i64x2_gt_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xD9u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2LeS`]. + pub fn i64x2_le_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xDAu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2GeS`]. + pub fn i64x2_ge_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xDBu32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Eq`]. + pub fn f32x4_eq(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x41u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Ne`]. + pub fn f32x4_ne(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x42u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Lt`]. + pub fn f32x4_lt(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x43u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Gt`]. + pub fn f32x4_gt(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x44u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Le`]. + pub fn f32x4_le(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x45u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Ge`]. + pub fn f32x4_ge(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x46u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Eq`]. + pub fn f64x2_eq(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x47u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Ne`]. + pub fn f64x2_ne(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x48u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Lt`]. + pub fn f64x2_lt(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x49u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Gt`]. + pub fn f64x2_gt(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x4Au32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Le`]. + pub fn f64x2_le(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x4Bu32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Ge`]. + pub fn f64x2_ge(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x4Cu32.encode(self.sink); + self + } + + /// Encode [`Instruction::V128Not`]. + pub fn v128_not(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x4Du32.encode(self.sink); + self + } + + /// Encode [`Instruction::V128And`]. + pub fn v128_and(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x4Eu32.encode(self.sink); + self + } + + /// Encode [`Instruction::V128AndNot`]. + pub fn v128_andnot(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x4Fu32.encode(self.sink); + self + } + + /// Encode [`Instruction::V128Or`]. + pub fn v128_or(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x50u32.encode(self.sink); + self + } + + /// Encode [`Instruction::V128Xor`]. + pub fn v128_xor(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x51u32.encode(self.sink); + self + } + + /// Encode [`Instruction::V128Bitselect`]. + pub fn v128_bitselect(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x52u32.encode(self.sink); + self + } + + /// Encode [`Instruction::V128AnyTrue`]. + pub fn v128_any_true(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x53u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16Abs`]. + pub fn i8x16_abs(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x60u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16Neg`]. + pub fn i8x16_neg(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x61u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16Popcnt`]. + pub fn i8x16_popcnt(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x62u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16AllTrue`]. + pub fn i8x16_all_true(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x63u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16Bitmask`]. + pub fn i8x16_bitmask(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x64u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16NarrowI16x8S`]. + pub fn i8x16_narrow_i16x8_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x65u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16NarrowI16x8U`]. + pub fn i8x16_narrow_i16x8_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x66u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16Shl`]. + pub fn i8x16_shl(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x6bu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16ShrS`]. + pub fn i8x16_shr_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x6cu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16ShrU`]. + pub fn i8x16_shr_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x6du32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16Add`]. + pub fn i8x16_add(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x6eu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16AddSatS`]. + pub fn i8x16_add_sat_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x6fu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16AddSatU`]. + pub fn i8x16_add_sat_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x70u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16Sub`]. + pub fn i8x16_sub(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x71u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16SubSatS`]. + pub fn i8x16_sub_sat_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x72u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16SubSatU`]. + pub fn i8x16_sub_sat_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x73u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16MinS`]. + pub fn i8x16_min_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x76u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16MinU`]. + pub fn i8x16_min_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x77u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16MaxS`]. + pub fn i8x16_max_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x78u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16MaxU`]. + pub fn i8x16_max_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x79u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16AvgrU`]. + pub fn i8x16_avgr_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x7Bu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8ExtAddPairwiseI8x16S`]. + pub fn i16x8_extadd_pairwise_i8x16_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x7Cu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8ExtAddPairwiseI8x16U`]. + pub fn i16x8_extadd_pairwise_i8x16_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x7Du32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8Abs`]. + pub fn i16x8_abs(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x80u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8Neg`]. + pub fn i16x8_neg(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x81u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8Q15MulrSatS`]. + pub fn i16x8_q15mulr_sat_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x82u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8AllTrue`]. + pub fn i16x8_all_true(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x83u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8Bitmask`]. + pub fn i16x8_bitmask(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x84u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8NarrowI32x4S`]. + pub fn i16x8_narrow_i32x4_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x85u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8NarrowI32x4U`]. + pub fn i16x8_narrow_i32x4_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x86u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8ExtendLowI8x16S`]. + pub fn i16x8_extend_low_i8x16_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x87u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8ExtendHighI8x16S`]. + pub fn i16x8_extend_high_i8x16_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x88u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8ExtendLowI8x16U`]. + pub fn i16x8_extend_low_i8x16_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x89u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8ExtendHighI8x16U`]. + pub fn i16x8_extend_high_i8x16_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x8Au32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8Shl`]. + pub fn i16x8_shl(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x8Bu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8ShrS`]. + pub fn i16x8_shr_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x8Cu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8ShrU`]. + pub fn i16x8_shr_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x8Du32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8Add`]. + pub fn i16x8_add(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x8Eu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8AddSatS`]. + pub fn i16x8_add_sat_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x8Fu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8AddSatU`]. + pub fn i16x8_add_sat_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x90u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8Sub`]. + pub fn i16x8_sub(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x91u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8SubSatS`]. + pub fn i16x8_sub_sat_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x92u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8SubSatU`]. + pub fn i16x8_sub_sat_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x93u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8Mul`]. + pub fn i16x8_mul(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x95u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8MinS`]. + pub fn i16x8_min_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x96u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8MinU`]. + pub fn i16x8_min_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x97u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8MaxS`]. + pub fn i16x8_max_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x98u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8MaxU`]. + pub fn i16x8_max_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x99u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8AvgrU`]. + pub fn i16x8_avgr_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x9Bu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8ExtMulLowI8x16S`]. + pub fn i16x8_extmul_low_i8x16_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x9Cu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8ExtMulHighI8x16S`]. + pub fn i16x8_extmul_high_i8x16_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x9Du32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8ExtMulLowI8x16U`]. + pub fn i16x8_extmul_low_i8x16_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x9Eu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8ExtMulHighI8x16U`]. + pub fn i16x8_extmul_high_i8x16_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x9Fu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4ExtAddPairwiseI16x8S`]. + pub fn i32x4_extadd_pairwise_i16x8_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x7Eu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4ExtAddPairwiseI16x8U`]. + pub fn i32x4_extadd_pairwise_i16x8_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x7Fu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4Abs`]. + pub fn i32x4_abs(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xA0u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4Neg`]. + pub fn i32x4_neg(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xA1u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4AllTrue`]. + pub fn i32x4_all_true(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xA3u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4Bitmask`]. + pub fn i32x4_bitmask(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xA4u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4ExtendLowI16x8S`]. + pub fn i32x4_extend_low_i16x8_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xA7u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4ExtendHighI16x8S`]. + pub fn i32x4_extend_high_i16x8_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xA8u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4ExtendLowI16x8U`]. + pub fn i32x4_extend_low_i16x8_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xA9u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4ExtendHighI16x8U`]. + pub fn i32x4_extend_high_i16x8_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xAAu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4Shl`]. + pub fn i32x4_shl(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xABu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4ShrS`]. + pub fn i32x4_shr_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xACu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4ShrU`]. + pub fn i32x4_shr_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xADu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4Add`]. + pub fn i32x4_add(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xAEu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4Sub`]. + pub fn i32x4_sub(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xB1u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4Mul`]. + pub fn i32x4_mul(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xB5u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4MinS`]. + pub fn i32x4_min_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xB6u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4MinU`]. + pub fn i32x4_min_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xB7u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4MaxS`]. + pub fn i32x4_max_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xB8u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4MaxU`]. + pub fn i32x4_max_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xB9u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4DotI16x8S`]. + pub fn i32x4_dot_i16x8_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xBAu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4ExtMulLowI16x8S`]. + pub fn i32x4_extmul_low_i16x8_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xBCu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4ExtMulHighI16x8S`]. + pub fn i32x4_extmul_high_i16x8_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xBDu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4ExtMulLowI16x8U`]. + pub fn i32x4_extmul_low_i16x8_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xBEu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4ExtMulHighI16x8U`]. + pub fn i32x4_extmul_high_i16x8_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xBFu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2Abs`]. + pub fn i64x2_abs(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xC0u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2Neg`]. + pub fn i64x2_neg(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xC1u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2AllTrue`]. + pub fn i64x2_all_true(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xC3u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2Bitmask`]. + pub fn i64x2_bitmask(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xC4u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2ExtendLowI32x4S`]. + pub fn i64x2_extend_low_i32x4_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xC7u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2ExtendHighI32x4S`]. + pub fn i64x2_extend_high_i32x4_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xC8u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2ExtendLowI32x4U`]. + pub fn i64x2_extend_low_i32x4_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xC9u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2ExtendHighI32x4U`]. + pub fn i64x2_extend_high_i32x4_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xCAu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2Shl`]. + pub fn i64x2_shl(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xCBu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2ShrS`]. + pub fn i64x2_shr_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xCCu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2ShrU`]. + pub fn i64x2_shr_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xCDu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2Add`]. + pub fn i64x2_add(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xCEu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2Sub`]. + pub fn i64x2_sub(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xD1u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2Mul`]. + pub fn i64x2_mul(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xD5u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2ExtMulLowI32x4S`]. + pub fn i64x2_extmul_low_i32x4_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xDCu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2ExtMulHighI32x4S`]. + pub fn i64x2_extmul_high_i32x4_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xDDu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2ExtMulLowI32x4U`]. + pub fn i64x2_extmul_low_i32x4_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xDEu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2ExtMulHighI32x4U`]. + pub fn i64x2_extmul_high_i32x4_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xDFu32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Ceil`]. + pub fn f32x4_ceil(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x67u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Floor`]. + pub fn f32x4_floor(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x68u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Trunc`]. + pub fn f32x4_trunc(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x69u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Nearest`]. + pub fn f32x4_nearest(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x6Au32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Abs`]. + pub fn f32x4_abs(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xE0u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Neg`]. + pub fn f32x4_neg(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xE1u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Sqrt`]. + pub fn f32x4_sqrt(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xE3u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Add`]. + pub fn f32x4_add(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xE4u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Sub`]. + pub fn f32x4_sub(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xE5u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Mul`]. + pub fn f32x4_mul(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xE6u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Div`]. + pub fn f32x4_div(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xE7u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Min`]. + pub fn f32x4_min(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xE8u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4Max`]. + pub fn f32x4_max(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xE9u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4PMin`]. + pub fn f32x4_pmin(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xEAu32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4PMax`]. + pub fn f32x4_pmax(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xEBu32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Ceil`]. + pub fn f64x2_ceil(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x74u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Floor`]. + pub fn f64x2_floor(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x75u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Trunc`]. + pub fn f64x2_trunc(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x7Au32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Nearest`]. + pub fn f64x2_nearest(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x94u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Abs`]. + pub fn f64x2_abs(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xECu32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Neg`]. + pub fn f64x2_neg(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xEDu32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Sqrt`]. + pub fn f64x2_sqrt(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xEFu32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Add`]. + pub fn f64x2_add(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xF0u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Sub`]. + pub fn f64x2_sub(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xF1u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Mul`]. + pub fn f64x2_mul(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xF2u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Div`]. + pub fn f64x2_div(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xF3u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Min`]. + pub fn f64x2_min(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xF4u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2Max`]. + pub fn f64x2_max(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xF5u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2PMin`]. + pub fn f64x2_pmin(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xF6u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2PMax`]. + pub fn f64x2_pmax(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xF7u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4TruncSatF32x4S`]. + pub fn i32x4_trunc_sat_f32x4_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xF8u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4TruncSatF32x4U`]. + pub fn i32x4_trunc_sat_f32x4_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xF9u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4ConvertI32x4S`]. + pub fn f32x4_convert_i32x4_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xFAu32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4ConvertI32x4U`]. + pub fn f32x4_convert_i32x4_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xFBu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4TruncSatF64x2SZero`]. + pub fn i32x4_trunc_sat_f64x2_s_zero(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xFCu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4TruncSatF64x2UZero`]. + pub fn i32x4_trunc_sat_f64x2_u_zero(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xFDu32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2ConvertLowI32x4S`]. + pub fn f64x2_convert_low_i32x4_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xFEu32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2ConvertLowI32x4U`]. + pub fn f64x2_convert_low_i32x4_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0xFFu32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4DemoteF64x2Zero`]. + pub fn f32x4_demote_f64x2_zero(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x5Eu32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2PromoteLowF32x4`]. + pub fn f64x2_promote_low_f32x4(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x5Fu32.encode(self.sink); + self + } + + // Relaxed simd proposal + + /// Encode [`Instruction::I8x16RelaxedSwizzle`]. + pub fn i8x16_relaxed_swizzle(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x100u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4RelaxedTruncF32x4S`]. + pub fn i32x4_relaxed_trunc_f32x4_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x101u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4RelaxedTruncF32x4U`]. + pub fn i32x4_relaxed_trunc_f32x4_u(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x102u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4RelaxedTruncF64x2SZero`]. + pub fn i32x4_relaxed_trunc_f64x2_s_zero(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x103u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4RelaxedTruncF64x2UZero`]. + pub fn i32x4_relaxed_trunc_f64x2_u_zero(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x104u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4RelaxedMadd`]. + pub fn f32x4_relaxed_madd(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x105u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4RelaxedNmadd`]. + pub fn f32x4_relaxed_nmadd(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x106u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2RelaxedMadd`]. + pub fn f64x2_relaxed_madd(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x107u32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2RelaxedNmadd`]. + pub fn f64x2_relaxed_nmadd(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x108u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I8x16RelaxedLaneselect`]. + pub fn i8x16_relaxed_laneselect(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x109u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8RelaxedLaneselect`]. + pub fn i16x8_relaxed_laneselect(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x10Au32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4RelaxedLaneselect`]. + pub fn i32x4_relaxed_laneselect(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x10Bu32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64x2RelaxedLaneselect`]. + pub fn i64x2_relaxed_laneselect(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x10Cu32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4RelaxedMin`]. + pub fn f32x4_relaxed_min(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x10Du32.encode(self.sink); + self + } + + /// Encode [`Instruction::F32x4RelaxedMax`]. + pub fn f32x4_relaxed_max(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x10Eu32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2RelaxedMin`]. + pub fn f64x2_relaxed_min(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x10Fu32.encode(self.sink); + self + } + + /// Encode [`Instruction::F64x2RelaxedMax`]. + pub fn f64x2_relaxed_max(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x110u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8RelaxedQ15mulrS`]. + pub fn i16x8_relaxed_q15mulr_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x111u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I16x8RelaxedDotI8x16I7x16S`]. + pub fn i16x8_relaxed_dot_i8x16_i7x16_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x112u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I32x4RelaxedDotI8x16I7x16AddS`]. + pub fn i32x4_relaxed_dot_i8x16_i7x16_add_s(&mut self) -> &mut Self { + self.sink.push(0xFD); + 0x113u32.encode(self.sink); + self + } + + // Atomic instructions (the threads proposal) + + /// Encode [`Instruction::MemoryAtomicNotify`]. + pub fn memory_atomic_notify(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x00); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::MemoryAtomicWait32`]. + pub fn memory_atomic_wait32(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x01); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::MemoryAtomicWait64`]. + pub fn memory_atomic_wait64(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x02); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::AtomicFence`]. + pub fn atomic_fence(&mut self) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x03); + self.sink.push(0x00); + self + } + + /// Encode [`Instruction::I32AtomicLoad`]. + pub fn i32_atomic_load(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x10); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicLoad`]. + pub fn i64_atomic_load(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x11); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicLoad8U`]. + pub fn i32_atomic_load8_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x12); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicLoad16U`]. + pub fn i32_atomic_load16_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x13); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicLoad8U`]. + pub fn i64_atomic_load8_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x14); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicLoad16U`]. + pub fn i64_atomic_load16_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x15); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicLoad32U`]. + pub fn i64_atomic_load32_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x16); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicStore`]. + pub fn i32_atomic_store(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x17); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicStore`]. + pub fn i64_atomic_store(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x18); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicStore8`]. + pub fn i32_atomic_store8(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x19); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicStore16`]. + pub fn i32_atomic_store16(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x1A); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicStore8`]. + pub fn i64_atomic_store8(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x1B); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicStore16`]. + pub fn i64_atomic_store16(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x1C); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicStore32`]. + pub fn i64_atomic_store32(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x1D); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmwAdd`]. + pub fn i32_atomic_rmw_add(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x1E); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmwAdd`]. + pub fn i64_atomic_rmw_add(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x1F); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmw8AddU`]. + pub fn i32_atomic_rmw8_add_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x20); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmw16AddU`]. + pub fn i32_atomic_rmw16_add_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x21); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw8AddU`]. + pub fn i64_atomic_rmw8_add_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x22); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw16AddU`]. + pub fn i64_atomic_rmw16_add_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x23); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw32AddU`]. + pub fn i64_atomic_rmw32_add_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x24); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmwSub`]. + pub fn i32_atomic_rmw_sub(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x25); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmwSub`]. + pub fn i64_atomic_rmw_sub(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x26); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmw8SubU`]. + pub fn i32_atomic_rmw8_sub_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x27); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmw16SubU`]. + pub fn i32_atomic_rmw16_sub_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x28); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw8SubU`]. + pub fn i64_atomic_rmw8_sub_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x29); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw16SubU`]. + pub fn i64_atomic_rmw16_sub_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x2A); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw32SubU`]. + pub fn i64_atomic_rmw32_sub_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x2B); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmwAnd`]. + pub fn i32_atomic_rmw_and(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x2C); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmwAnd`]. + pub fn i64_atomic_rmw_and(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x2D); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmw8AndU`]. + pub fn i32_atomic_rmw8_and_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x2E); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmw16AndU`]. + pub fn i32_atomic_rmw16_and_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x2F); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw8AndU`]. + pub fn i64_atomic_rmw8_and_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x30); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw16AndU`]. + pub fn i64_atomic_rmw16_and_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x31); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw32AndU`]. + pub fn i64_atomic_rmw32_and_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x32); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmwOr`]. + pub fn i32_atomic_rmw_or(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x33); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmwOr`]. + pub fn i64_atomic_rmw_or(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x34); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmw8OrU`]. + pub fn i32_atomic_rmw8_or_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x35); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmw16OrU`]. + pub fn i32_atomic_rmw16_or_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x36); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw8OrU`]. + pub fn i64_atomic_rmw8_or_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x37); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw16OrU`]. + pub fn i64_atomic_rmw16_or_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x38); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw32OrU`]. + pub fn i64_atomic_rmw32_or_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x39); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmwXor`]. + pub fn i32_atomic_rmw_xor(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x3A); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmwXor`]. + pub fn i64_atomic_rmw_xor(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x3B); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmw8XorU`]. + pub fn i32_atomic_rmw8_xor_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x3C); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmw16XorU`]. + pub fn i32_atomic_rmw16_xor_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x3D); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw8XorU`]. + pub fn i64_atomic_rmw8_xor_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x3E); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw16XorU`]. + pub fn i64_atomic_rmw16_xor_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x3F); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw32XorU`]. + pub fn i64_atomic_rmw32_xor_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x40); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmwXchg`]. + pub fn i32_atomic_rmw_xchg(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x41); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmwXchg`]. + pub fn i64_atomic_rmw_xchg(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x42); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmw8XchgU`]. + pub fn i32_atomic_rmw8_xchg_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x43); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmw16XchgU`]. + pub fn i32_atomic_rmw16_xchg_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x44); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw8XchgU`]. + pub fn i64_atomic_rmw8_xchg_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x45); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw16XchgU`]. + pub fn i64_atomic_rmw16_xchg_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x46); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw32XchgU`]. + pub fn i64_atomic_rmw32_xchg_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x47); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmwCmpxchg`]. + pub fn i32_atomic_rmw_cmpxchg(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x48); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmwCmpxchg`]. + pub fn i64_atomic_rmw_cmpxchg(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x49); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmw8CmpxchgU`]. + pub fn i32_atomic_rmw8_cmpxchg_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x4A); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I32AtomicRmw16CmpxchgU`]. + pub fn i32_atomic_rmw16_cmpxchg_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x4B); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw8CmpxchgU`]. + pub fn i64_atomic_rmw8_cmpxchg_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x4C); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw16CmpxchgU`]. + pub fn i64_atomic_rmw16_cmpxchg_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x4D); + memarg.encode(self.sink); + self + } + + /// Encode [`Instruction::I64AtomicRmw32CmpxchgU`]. + pub fn i64_atomic_rmw32_cmpxchg_u(&mut self, memarg: MemArg) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x4E); + memarg.encode(self.sink); + self + } + + // More atomic instructions (the shared-everything-threads proposal) + + /// Encode [`Instruction::GlobalAtomicGet`]. + pub fn global_atomic_get(&mut self, ordering: Ordering, global_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x4F); + ordering.encode(self.sink); + global_index.encode(self.sink); + self + } + + /// Encode [`Instruction::GlobalAtomicSet`]. + pub fn global_atomic_set(&mut self, ordering: Ordering, global_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x50); + ordering.encode(self.sink); + global_index.encode(self.sink); + self + } + + /// Encode [`Instruction::GlobalAtomicRmwAdd`]. + pub fn global_atomic_rmw_add(&mut self, ordering: Ordering, global_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x51); + ordering.encode(self.sink); + global_index.encode(self.sink); + self + } + + /// Encode [`Instruction::GlobalAtomicRmwSub`]. + pub fn global_atomic_rmw_sub(&mut self, ordering: Ordering, global_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x52); + ordering.encode(self.sink); + global_index.encode(self.sink); + self + } + + /// Encode [`Instruction::GlobalAtomicRmwAnd`]. + pub fn global_atomic_rmw_and(&mut self, ordering: Ordering, global_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x53); + ordering.encode(self.sink); + global_index.encode(self.sink); + self + } + + /// Encode [`Instruction::GlobalAtomicRmwOr`]. + pub fn global_atomic_rmw_or(&mut self, ordering: Ordering, global_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x54); + ordering.encode(self.sink); + global_index.encode(self.sink); + self + } + + /// Encode [`Instruction::GlobalAtomicRmwXor`]. + pub fn global_atomic_rmw_xor(&mut self, ordering: Ordering, global_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x55); + ordering.encode(self.sink); + global_index.encode(self.sink); + self + } + + /// Encode [`Instruction::GlobalAtomicRmwXchg`]. + pub fn global_atomic_rmw_xchg(&mut self, ordering: Ordering, global_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x56); + ordering.encode(self.sink); + global_index.encode(self.sink); + self + } + + /// Encode [`Instruction::GlobalAtomicRmwCmpxchg`]. + pub fn global_atomic_rmw_cmpxchg( + &mut self, + ordering: Ordering, + global_index: u32, + ) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x57); + ordering.encode(self.sink); + global_index.encode(self.sink); + self + } + + /// Encode [`Instruction::TableAtomicGet`]. + pub fn table_atomic_get(&mut self, ordering: Ordering, table_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x58); + ordering.encode(self.sink); + table_index.encode(self.sink); + self + } + + /// Encode [`Instruction::TableAtomicSet`]. + pub fn table_atomic_set(&mut self, ordering: Ordering, table_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x59); + ordering.encode(self.sink); + table_index.encode(self.sink); + self + } + + /// Encode [`Instruction::TableAtomicRmwXchg`]. + pub fn table_atomic_rmw_xchg(&mut self, ordering: Ordering, table_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x5A); + ordering.encode(self.sink); + table_index.encode(self.sink); + self + } + + /// Encode [`Instruction::TableAtomicRmwCmpxchg`]. + pub fn table_atomic_rmw_cmpxchg(&mut self, ordering: Ordering, table_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x5B); + ordering.encode(self.sink); + table_index.encode(self.sink); + self + } + + /// Encode [`Instruction::StructAtomicGet`]. + pub fn struct_atomic_get( + &mut self, + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x5C); + ordering.encode(self.sink); + struct_type_index.encode(self.sink); + field_index.encode(self.sink); + self + } + + /// Encode [`Instruction::StructAtomicGetS`]. + pub fn struct_atomic_get_s( + &mut self, + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x5D); + ordering.encode(self.sink); + struct_type_index.encode(self.sink); + field_index.encode(self.sink); + self + } + + /// Encode [`Instruction::StructAtomicGetU`]. + pub fn struct_atomic_get_u( + &mut self, + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x5E); + ordering.encode(self.sink); + struct_type_index.encode(self.sink); + field_index.encode(self.sink); + self + } + + /// Encode [`Instruction::StructAtomicSet`]. + pub fn struct_atomic_set( + &mut self, + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x5F); + ordering.encode(self.sink); + struct_type_index.encode(self.sink); + field_index.encode(self.sink); + self + } + + /// Encode [`Instruction::StructAtomicRmwAdd`]. + pub fn struct_atomic_rmw_add( + &mut self, + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x60); + ordering.encode(self.sink); + struct_type_index.encode(self.sink); + field_index.encode(self.sink); + self + } + + /// Encode [`Instruction::StructAtomicRmwSub`]. + pub fn struct_atomic_rmw_sub( + &mut self, + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x61); + ordering.encode(self.sink); + struct_type_index.encode(self.sink); + field_index.encode(self.sink); + self + } + + /// Encode [`Instruction::StructAtomicRmwAnd`]. + pub fn struct_atomic_rmw_and( + &mut self, + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x62); + ordering.encode(self.sink); + struct_type_index.encode(self.sink); + field_index.encode(self.sink); + self + } + + /// Encode [`Instruction::StructAtomicRmwOr`]. + pub fn struct_atomic_rmw_or( + &mut self, + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x63); + ordering.encode(self.sink); + struct_type_index.encode(self.sink); + field_index.encode(self.sink); + self + } + + /// Encode [`Instruction::StructAtomicRmwXor`]. + pub fn struct_atomic_rmw_xor( + &mut self, + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x64); + ordering.encode(self.sink); + struct_type_index.encode(self.sink); + field_index.encode(self.sink); + self + } + + /// Encode [`Instruction::StructAtomicRmwXchg`]. + pub fn struct_atomic_rmw_xchg( + &mut self, + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x65); + ordering.encode(self.sink); + struct_type_index.encode(self.sink); + field_index.encode(self.sink); + self + } + + /// Encode [`Instruction::StructAtomicRmwCmpxchg`]. + pub fn struct_atomic_rmw_cmpxchg( + &mut self, + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x66); + ordering.encode(self.sink); + struct_type_index.encode(self.sink); + field_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayAtomicGet`]. + pub fn array_atomic_get(&mut self, ordering: Ordering, array_type_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x67); + ordering.encode(self.sink); + array_type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayAtomicGetS`]. + pub fn array_atomic_get_s(&mut self, ordering: Ordering, array_type_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x68); + ordering.encode(self.sink); + array_type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayAtomicGetU`]. + pub fn array_atomic_get_u(&mut self, ordering: Ordering, array_type_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x69); + ordering.encode(self.sink); + array_type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayAtomicSet`]. + pub fn array_atomic_set(&mut self, ordering: Ordering, array_type_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x6A); + ordering.encode(self.sink); + array_type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayAtomicRmwAdd`]. + pub fn array_atomic_rmw_add(&mut self, ordering: Ordering, array_type_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x6B); + ordering.encode(self.sink); + array_type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayAtomicRmwSub`]. + pub fn array_atomic_rmw_sub(&mut self, ordering: Ordering, array_type_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x6C); + ordering.encode(self.sink); + array_type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayAtomicRmwAnd`]. + pub fn array_atomic_rmw_and(&mut self, ordering: Ordering, array_type_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x6D); + ordering.encode(self.sink); + array_type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayAtomicRmwOr`]. + pub fn array_atomic_rmw_or(&mut self, ordering: Ordering, array_type_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x6E); + ordering.encode(self.sink); + array_type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayAtomicRmwXor`]. + pub fn array_atomic_rmw_xor(&mut self, ordering: Ordering, array_type_index: u32) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x6F); + ordering.encode(self.sink); + array_type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayAtomicRmwXchg`]. + pub fn array_atomic_rmw_xchg( + &mut self, + ordering: Ordering, + array_type_index: u32, + ) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x70); + ordering.encode(self.sink); + array_type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ArrayAtomicRmwCmpxchg`]. + pub fn array_atomic_rmw_cmpxchg( + &mut self, + ordering: Ordering, + array_type_index: u32, + ) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x71); + ordering.encode(self.sink); + array_type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::RefI31Shared`]. + pub fn ref_i31_shared(&mut self) -> &mut Self { + self.sink.push(0xFE); + self.sink.push(0x72); + self + } + + // Stack switching + + /// Encode [`Instruction::ContNew`]. + pub fn cont_new(&mut self, type_index: u32) -> &mut Self { + self.sink.push(0xE0); + type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::ContBind`]. + pub fn cont_bind(&mut self, argument_index: u32, result_index: u32) -> &mut Self { + self.sink.push(0xE1); + argument_index.encode(self.sink); + result_index.encode(self.sink); + self + } + + /// Encode [`Instruction::Suspend`]. + pub fn suspend(&mut self, tag_index: u32) -> &mut Self { + self.sink.push(0xE2); + tag_index.encode(self.sink); + self + } + + /// Encode [`Instruction::Resume`]. + pub fn resume<V: IntoIterator<Item = Handle>>( + &mut self, + cont_type_index: u32, + resume_table: V, + ) -> &mut Self + where + V::IntoIter: ExactSizeIterator, + { + self.sink.push(0xE3); + cont_type_index.encode(self.sink); + encode_vec(resume_table, self.sink); + self + } + + /// Encode [`Instruction::ResumeThrow`]. + pub fn resume_throw<V: IntoIterator<Item = Handle>>( + &mut self, + cont_type_index: u32, + tag_index: u32, + resume_table: V, + ) -> &mut Self + where + V::IntoIter: ExactSizeIterator, + { + self.sink.push(0xE4); + cont_type_index.encode(self.sink); + tag_index.encode(self.sink); + encode_vec(resume_table, self.sink); + self + } + + /// Encode [`Instruction::Switch`]. + pub fn switch(&mut self, cont_type_index: u32, tag_index: u32) -> &mut Self { + self.sink.push(0xE5); + cont_type_index.encode(self.sink); + tag_index.encode(self.sink); + self + } + + // Wide Arithmetic + + /// Encode [`Instruction::I64Add128`]. + pub fn i64_add128(&mut self) -> &mut Self { + self.sink.push(0xFC); + 19u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64Sub128`]. + pub fn i64_sub128(&mut self) -> &mut Self { + self.sink.push(0xFC); + 20u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64MulWideS`]. + pub fn i64_mul_wide_s(&mut self) -> &mut Self { + self.sink.push(0xFC); + 21u32.encode(self.sink); + self + } + + /// Encode [`Instruction::I64MulWideU`]. + pub fn i64_mul_wide_u(&mut self) -> &mut Self { + self.sink.push(0xFC); + 22u32.encode(self.sink); + self + } + + /// Encode [`Instruction::RefGetDesc`]. + pub fn ref_get_desc(&mut self, type_index: u32) -> &mut Self { + self.sink.push(0xFB); + 34u32.encode(self.sink); + type_index.encode(self.sink); + self + } + + /// Encode [`Instruction::RefCastDescNonNull`]. + pub fn ref_cast_desc_non_null(&mut self, ht: HeapType) -> &mut Self { + self.sink.push(0xFB); + 35u32.encode(self.sink); + ht.encode(self.sink); + self + } + + /// Encode [`Instruction::RefCastDescNullable`]. + pub fn ref_cast_desc_nullable(&mut self, ht: HeapType) -> &mut Self { + self.sink.push(0xFB); + 36u32.encode(self.sink); + ht.encode(self.sink); + self + } + + /// Encode [`Instruction::BrOnCastDesc`]. + pub fn br_on_cast_desc( + &mut self, + relative_depth: u32, + from_ref_type: RefType, + to_ref_type: RefType, + ) -> &mut Self { + self.sink.push(0xFB); + 37u32.encode(self.sink); + let cast_flags = (from_ref_type.nullable as u8) | ((to_ref_type.nullable as u8) << 1); + self.sink.push(cast_flags); + relative_depth.encode(self.sink); + from_ref_type.heap_type.encode(self.sink); + to_ref_type.heap_type.encode(self.sink); + self + } + + /// Encode [`Instruction::BrOnCastDescFail`]. + pub fn br_on_cast_desc_fail( + &mut self, + relative_depth: u32, + from_ref_type: RefType, + to_ref_type: RefType, + ) -> &mut Self { + self.sink.push(0xFB); + 38u32.encode(self.sink); + let cast_flags = (from_ref_type.nullable as u8) | ((to_ref_type.nullable as u8) << 1); + self.sink.push(cast_flags); + relative_depth.encode(self.sink); + from_ref_type.heap_type.encode(self.sink); + to_ref_type.heap_type.encode(self.sink); + self + } +} diff --git a/third_party/rust/wasm-encoder/src/core/linking.rs b/third_party/rust/wasm-encoder/src/core/linking.rs @@ -1,4 +1,4 @@ -use crate::{encode_section, CustomSection, Encode, Section, SectionId}; +use crate::{CustomSection, Encode, Section, SectionId, encode_section}; use alloc::borrow::Cow; use alloc::vec; use alloc::vec::Vec; diff --git a/third_party/rust/wasm-encoder/src/core/memories.rs b/third_party/rust/wasm-encoder/src/core/memories.rs @@ -1,4 +1,4 @@ -use crate::{encode_section, Encode, Section, SectionId}; +use crate::{Encode, Section, SectionId, encode_section}; use alloc::vec::Vec; /// An encoder for the memory section. diff --git a/third_party/rust/wasm-encoder/src/core/names.rs b/third_party/rust/wasm-encoder/src/core/names.rs @@ -1,4 +1,4 @@ -use crate::{encoding_size, CustomSection, Encode, Section, SectionId}; +use crate::{CustomSection, Encode, Section, SectionId, encoding_size}; use alloc::borrow::Cow; use alloc::vec; use alloc::vec::Vec; diff --git a/third_party/rust/wasm-encoder/src/core/start.rs b/third_party/rust/wasm-encoder/src/core/start.rs @@ -1,4 +1,4 @@ -use crate::{encoding_size, Encode, Section, SectionId}; +use crate::{Encode, Section, SectionId, encoding_size}; use alloc::vec::Vec; /// An encoder for the start section of WebAssembly modules. diff --git a/third_party/rust/wasm-encoder/src/core/tables.rs b/third_party/rust/wasm-encoder/src/core/tables.rs @@ -1,4 +1,4 @@ -use crate::{encode_section, ConstExpr, Encode, RefType, Section, SectionId, ValType}; +use crate::{ConstExpr, Encode, RefType, Section, SectionId, ValType, encode_section}; use alloc::vec::Vec; /// An encoder for the table section. diff --git a/third_party/rust/wasm-encoder/src/core/tags.rs b/third_party/rust/wasm-encoder/src/core/tags.rs @@ -1,4 +1,4 @@ -use crate::{encode_section, Encode, Section, SectionId}; +use crate::{Encode, Section, SectionId, encode_section}; use alloc::vec::Vec; /// An encoder for the tag section. diff --git a/third_party/rust/wasm-encoder/src/core/types.rs b/third_party/rust/wasm-encoder/src/core/types.rs @@ -1,4 +1,4 @@ -use crate::{encode_section, Encode, Section, SectionId}; +use crate::{Encode, Section, SectionId, encode_section}; use alloc::boxed::Box; use alloc::vec::Vec; @@ -22,6 +22,10 @@ pub struct CompositeType { /// Whether the type is shared. This is part of the /// shared-everything-threads proposal. pub shared: bool, + /// Optional descriptor attribute. + pub descriptor: Option<u32>, + /// Optional describes attribute. + pub describes: Option<u32>, } /// A [`CompositeType`] can contain one of these types. @@ -362,6 +366,8 @@ pub enum HeapType { /// A concrete Wasm-defined type at the given index. Concrete(u32), + /// An exact type. + Exact(u32), } impl HeapType { @@ -402,6 +408,11 @@ impl Encode for HeapType { // Note that this is encoded as a signed type rather than unsigned // as it's decoded as an s33 HeapType::Concrete(i) => i64::from(*i).encode(sink), + // Exact type is u32 + HeapType::Exact(i) => { + sink.push(0x62); + u32::from(*i).encode(sink) + } } } } @@ -529,7 +540,7 @@ impl TypeSection { /// Encode a function type in this type section. #[must_use = "the encoder must be used to encode the type"] - pub fn ty(&mut self) -> CoreTypeEncoder { + pub fn ty(&mut self) -> CoreTypeEncoder<'_> { self.num_added += 1; CoreTypeEncoder { bytes: &mut self.bytes, @@ -635,6 +646,11 @@ impl<'a> CoreTypeEncoder<'a> { } } + /// Define a continuation type in this subsection + pub fn cont(mut self, ty: &ContType) { + self.encode_cont(ty) + } + fn encode_cont(&mut self, ty: &ContType) { self.bytes.push(0x5d); i64::from(ty.0).encode(self.bytes); @@ -664,6 +680,14 @@ impl<'a> CoreTypeEncoder<'a> { if ty.composite_type.shared { self.bytes.push(0x65); } + if let Some(index) = ty.composite_type.describes { + self.bytes.push(0x4c); + index.encode(self.bytes); + } + if let Some(index) = ty.composite_type.descriptor { + self.bytes.push(0x4d); + index.encode(self.bytes); + } match &ty.composite_type.inner { CompositeInnerType::Func(ty) => { self.encode_function(ty.params().iter().copied(), ty.results().iter().copied()) @@ -710,6 +734,8 @@ mod tests { composite_type: CompositeType { inner: CompositeInnerType::Func(FuncType::new([], [])), shared: false, + descriptor: None, + describes: None, }, }); diff --git a/third_party/rust/wasm-encoder/src/lib.rs b/third_party/rust/wasm-encoder/src/lib.rs @@ -26,7 +26,7 @@ //! //! ``` //! use wasm_encoder::{ -//! CodeSection, ExportKind, ExportSection, Function, FunctionSection, Instruction, +//! CodeSection, ExportKind, ExportSection, Function, FunctionSection, //! Module, TypeSection, ValType, //! }; //! @@ -54,10 +54,11 @@ //! 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); +//! f.instructions() +//! .local_get(0) +//! .local_get(1) +//! .i32_add() +//! .end(); //! codes.function(&f); //! module.section(&codes); //! @@ -68,7 +69,7 @@ //! assert!(wasmparser::validate(&wasm_bytes).is_ok()); //! ``` -#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(docsrs, feature(doc_cfg))] #![no_std] #![deny(missing_docs, missing_debug_implementations)] @@ -161,20 +162,6 @@ impl Encode for i64 { } } -impl Encode for f32 { - fn encode(&self, sink: &mut Vec<u8>) { - let bits = self.to_bits(); - sink.extend(bits.to_le_bytes()) - } -} - -impl Encode for f64 { - fn encode(&self, sink: &mut Vec<u8>) { - let bits = self.to_bits(); - sink.extend(bits.to_le_bytes()) - } -} - fn encode_vec<T, V>(elements: V, sink: &mut Vec<u8>) where T: Encode, diff --git a/third_party/rust/wasm-encoder/src/reencode.rs b/third_party/rust/wasm-encoder/src/reencode.rs @@ -17,40 +17,43 @@ mod component; #[cfg(feature = "component-model")] pub use self::component::*; +#[cfg(feature = "wasmparser")] +use alloc::vec::Vec; + #[allow(missing_docs)] // FIXME pub trait Reencode { type Error; - fn data_index(&mut self, data: u32) -> u32 { - utils::data_index(self, data) + fn data_index(&mut self, data: u32) -> Result<u32, Error<Self::Error>> { + Ok(utils::data_index(self, data)) } - fn element_index(&mut self, element: u32) -> u32 { - utils::element_index(self, element) + fn element_index(&mut self, element: u32) -> Result<u32, Error<Self::Error>> { + Ok(utils::element_index(self, element)) } - fn function_index(&mut self, func: u32) -> u32 { - utils::function_index(self, func) + fn function_index(&mut self, func: u32) -> Result<u32, Error<Self::Error>> { + Ok(utils::function_index(self, func)) } - fn global_index(&mut self, global: u32) -> u32 { - utils::global_index(self, global) + fn global_index(&mut self, global: u32) -> Result<u32, Error<Self::Error>> { + Ok(utils::global_index(self, global)) } - fn memory_index(&mut self, memory: u32) -> u32 { - utils::memory_index(self, memory) + fn memory_index(&mut self, memory: u32) -> Result<u32, Error<Self::Error>> { + Ok(utils::memory_index(self, memory)) } - fn table_index(&mut self, table: u32) -> u32 { - utils::table_index(self, table) + fn table_index(&mut self, table: u32) -> Result<u32, Error<Self::Error>> { + Ok(utils::table_index(self, table)) } - fn tag_index(&mut self, tag: u32) -> u32 { - utils::tag_index(self, tag) + fn tag_index(&mut self, tag: u32) -> Result<u32, Error<Self::Error>> { + Ok(utils::tag_index(self, tag)) } - fn type_index(&mut self, ty: u32) -> u32 { - utils::type_index(self, ty) + fn type_index(&mut self, ty: u32) -> Result<u32, Error<Self::Error>> { + Ok(utils::type_index(self, ty)) } fn type_index_unpacked( @@ -60,9 +63,15 @@ pub trait Reencode { utils::type_index_unpacked(self, ty) } - fn external_index(&mut self, kind: wasmparser::ExternalKind, index: u32) -> u32 { + fn external_index( + &mut self, + kind: wasmparser::ExternalKind, + index: u32, + ) -> Result<u32, Error<Self::Error>> { match kind { - wasmparser::ExternalKind::Func => self.function_index(index), + wasmparser::ExternalKind::Func | wasmparser::ExternalKind::FuncExact => { + self.function_index(index) + } wasmparser::ExternalKind::Table => self.table_index(index), wasmparser::ExternalKind::Memory => self.memory_index(index), wasmparser::ExternalKind::Global => self.global_index(index), @@ -73,8 +82,8 @@ pub trait Reencode { fn abstract_heap_type( &mut self, value: wasmparser::AbstractHeapType, - ) -> crate::AbstractHeapType { - utils::abstract_heap_type(self, value) + ) -> Result<crate::AbstractHeapType, Error<Self::Error>> { + Ok(utils::abstract_heap_type(self, value)) } fn array_type( @@ -98,7 +107,7 @@ pub trait Reencode { utils::const_expr(self, const_expr) } - fn catch(&mut self, arg: wasmparser::Catch) -> crate::Catch { + fn catch(&mut self, arg: wasmparser::Catch) -> Result<crate::Catch, Error<Self::Error>> { utils::catch(self, arg) } @@ -116,8 +125,11 @@ pub trait Reencode { utils::entity_type(self, type_ref) } - fn export_kind(&mut self, external_kind: wasmparser::ExternalKind) -> crate::ExportKind { - utils::export_kind(self, external_kind) + fn export_kind( + &mut self, + external_kind: wasmparser::ExternalKind, + ) -> Result<crate::ExportKind, Error<Self::Error>> { + Ok(utils::export_kind(self, external_kind)) } fn field_type( @@ -148,7 +160,7 @@ pub trait Reencode { utils::global_type(self, global_ty) } - fn handle(&mut self, on: wasmparser::Handle) -> crate::Handle { + fn handle(&mut self, on: wasmparser::Handle) -> Result<crate::Handle, Error<Self::Error>> { utils::handle(self, on) } @@ -166,16 +178,30 @@ pub trait Reencode { utils::instruction(self, arg) } - fn memory_type(&mut self, memory_ty: wasmparser::MemoryType) -> crate::MemoryType { - utils::memory_type(self, memory_ty) + fn memory_type( + &mut self, + memory_ty: wasmparser::MemoryType, + ) -> Result<crate::MemoryType, Error<Self::Error>> { + Ok(utils::memory_type(self, memory_ty)) + } + + fn ieee32_arg(&mut self, arg: wasmparser::Ieee32) -> Result<crate::Ieee32, Error<Self::Error>> { + Ok(utils::ieee32_arg(self, arg)) + } + + fn ieee64_arg(&mut self, arg: wasmparser::Ieee64) -> Result<crate::Ieee64, Error<Self::Error>> { + Ok(utils::ieee64_arg(self, arg)) } - fn mem_arg(&mut self, arg: wasmparser::MemArg) -> crate::MemArg { + fn mem_arg(&mut self, arg: wasmparser::MemArg) -> Result<crate::MemArg, Error<Self::Error>> { utils::mem_arg(self, arg) } - fn ordering(&mut self, arg: wasmparser::Ordering) -> crate::Ordering { - utils::ordering(self, arg) + fn ordering( + &mut self, + arg: wasmparser::Ordering, + ) -> Result<crate::Ordering, Error<Self::Error>> { + Ok(utils::ordering(self, arg)) } fn ref_type( @@ -213,11 +239,17 @@ pub trait Reencode { utils::table_type(self, table_ty) } - fn tag_kind(&mut self, kind: wasmparser::TagKind) -> crate::TagKind { - utils::tag_kind(self, kind) + fn tag_kind( + &mut self, + kind: wasmparser::TagKind, + ) -> Result<crate::TagKind, Error<Self::Error>> { + Ok(utils::tag_kind(self, kind)) } - fn tag_type(&mut self, tag_ty: wasmparser::TagType) -> crate::TagType { + fn tag_type( + &mut self, + tag_ty: wasmparser::TagType, + ) -> Result<crate::TagType, Error<Self::Error>> { utils::tag_type(self, tag_ty) } @@ -228,6 +260,16 @@ pub trait Reencode { utils::val_type(self, val_ty) } + fn val_types( + &mut self, + val_tys: Vec<wasmparser::ValType>, + ) -> Result<Vec<crate::ValType>, Error<Self::Error>> { + val_tys + .iter() + .map(|ty| utils::val_type(self, *ty)) + .collect() + } + /// Parses the input `section` given from the `wasmparser` crate and /// adds the custom section to the `module`. fn parse_custom_section( @@ -243,8 +285,8 @@ pub trait Reencode { fn custom_section<'a>( &mut self, section: wasmparser::CustomSectionReader<'a>, - ) -> crate::CustomSection<'a> { - utils::custom_section(self, section) + ) -> Result<crate::CustomSection<'a>, Error<Self::Error>> { + Ok(utils::custom_section(self, section)) } /// Parses the input `section` given from the `wasmparser` crate and adds @@ -341,7 +383,11 @@ pub trait Reencode { /// Parses the single [`wasmparser::Export`] provided and adds it to the /// `exports` section. - fn parse_export(&mut self, exports: &mut crate::ExportSection, export: wasmparser::Export<'_>) { + fn parse_export( + &mut self, + exports: &mut crate::ExportSection, + export: wasmparser::Export<'_>, + ) -> Result<(), Error<Self::Error>> { utils::parse_export(self, exports, export) } @@ -512,11 +558,11 @@ pub trait Reencode { utils::parse_custom_name_subsection(self, names, section) } - fn data_count(&mut self, count: u32) -> u32 { - count + fn data_count(&mut self, count: u32) -> Result<u32, Error<Self::Error>> { + Ok(count) } - fn start_section(&mut self, start: u32) -> u32 { + fn start_section(&mut self, start: u32) -> Result<u32, Error<Self::Error>> { self.function_index(start) } } @@ -533,9 +579,9 @@ pub enum Error<E = Infallible> { InvalidConstExpr, /// The code section size listed was not valid for the wasm binary provided. InvalidCodeSectionSize, - /// There was a section that does not belong into a core wasm module. + /// There was a section that does not belong in a core wasm module. UnexpectedNonCoreModuleSection, - /// There was a section that does not belong into a compoennt module. + /// There was a section that does not belong in a component module. UnexpectedNonComponentSection, /// A core type definition was found in a component that's not supported. UnsupportedCoreTypeInComponent, @@ -561,11 +607,11 @@ impl<E: core::fmt::Display> core::fmt::Display for Error<E> { Self::InvalidConstExpr => write!(fmt, "The const expression was invalid"), Self::UnexpectedNonCoreModuleSection => write!( fmt, - "There was a section that does not belong into a core wasm module" + "There was a section that does not belong in a core wasm module" ), Self::UnexpectedNonComponentSection => write!( fmt, - "There was a section that does not belong into a component" + "There was a section that does not belong in a component" ), Self::CanonicalizedHeapTypeReference => write!( fmt, @@ -632,7 +678,7 @@ pub mod utils { // accounting for various offsets. Then create a // `CodeSectionReader` (which notably the payload does not // give us here) and recurse with that. This means that - // users overridding `parse_code_section` always get that + // users overriding `parse_code_section` always get that // function called. let orig_offset = parser.offset() as usize; let get_original_section = |range: Range<usize>| { @@ -648,7 +694,7 @@ pub mod utils { .. } => (), wasmparser::Payload::Version { .. } => { - return Err(Error::UnexpectedNonCoreModuleSection) + return Err(Error::UnexpectedNonCoreModuleSection); } wasmparser::Payload::TypeSection(section) => { handle_intersperse_section_hook( @@ -746,7 +792,7 @@ pub mod utils { Some(crate::SectionId::Start), )?; module.section(&crate::StartSection { - function_index: reencoder.start_section(func), + function_index: reencoder.start_section(func)?, }); } wasmparser::Payload::ElementSection(section) => { @@ -767,7 +813,7 @@ pub mod utils { &mut last_section, Some(crate::SectionId::DataCount), )?; - let count = reencoder.data_count(count); + let count = reencoder.data_count(count)?; module.section(&crate::DataCountSection { count }); } wasmparser::Payload::DataSection(section) => { @@ -794,7 +840,7 @@ pub mod utils { // accounting for various offsets. Then create a // `CodeSectionReader` (which notably the payload does not // give us here) and recurse with that. This means that - // users overridding `parse_code_section` always get that + // users overriding `parse_code_section` always get that // function called. let section = get_original_section(range.clone())?; let reader = wasmparser::BinaryReader::new(section, range.start); @@ -820,7 +866,7 @@ pub mod utils { | wasmparser::Payload::ComponentStartSection { .. } | wasmparser::Payload::ComponentImportSection(_) | wasmparser::Payload::ComponentExportSection(_) => { - return Err(Error::UnexpectedNonCoreModuleSection) + return Err(Error::UnexpectedNonCoreModuleSection); } wasmparser::Payload::CustomSection(section) => { reencoder.parse_custom_section(module, section)?; @@ -872,15 +918,29 @@ pub mod utils { memory } + pub fn ieee32_arg<T: ?Sized + Reencode>( + _reencoder: &mut T, + arg: wasmparser::Ieee32, + ) -> crate::Ieee32 { + crate::Ieee32(arg.bits()) + } + + pub fn ieee64_arg<T: ?Sized + Reencode>( + _reencoder: &mut T, + arg: wasmparser::Ieee64, + ) -> crate::Ieee64 { + crate::Ieee64(arg.bits()) + } + pub fn mem_arg<T: ?Sized + Reencode>( reencoder: &mut T, arg: wasmparser::MemArg, - ) -> crate::MemArg { - crate::MemArg { + ) -> Result<crate::MemArg, Error<T::Error>> { + Ok(crate::MemArg { offset: arg.offset, align: arg.align.into(), - memory_index: reencoder.memory_index(arg.memory), - } + memory_index: reencoder.memory_index(arg.memory)?, + }) } pub fn ordering<T: ?Sized + Reencode>( @@ -901,34 +961,37 @@ pub mod utils { tag } - pub fn catch<T: ?Sized + Reencode>(reencoder: &mut T, arg: wasmparser::Catch) -> crate::Catch { - match arg { + pub fn catch<T: ?Sized + Reencode>( + reencoder: &mut T, + arg: wasmparser::Catch, + ) -> Result<crate::Catch, Error<T::Error>> { + Ok(match arg { wasmparser::Catch::One { tag, label } => crate::Catch::One { - tag: reencoder.tag_index(tag), + tag: reencoder.tag_index(tag)?, label, }, wasmparser::Catch::OneRef { tag, label } => crate::Catch::OneRef { - tag: reencoder.tag_index(tag), + tag: reencoder.tag_index(tag)?, label, }, wasmparser::Catch::All { label } => crate::Catch::All { label }, wasmparser::Catch::AllRef { label } => crate::Catch::AllRef { label }, - } + }) } pub fn handle<T: ?Sized + Reencode>( reencoder: &mut T, arg: wasmparser::Handle, - ) -> crate::Handle { - match arg { + ) -> Result<crate::Handle, Error<T::Error>> { + Ok(match arg { wasmparser::Handle::OnLabel { tag, label } => crate::Handle::OnLabel { - tag: reencoder.tag_index(tag), + tag: reencoder.tag_index(tag)?, label, }, wasmparser::Handle::OnSwitch { tag } => crate::Handle::OnSwitch { - tag: reencoder.tag_index(tag), + tag: reencoder.tag_index(tag)?, }, - } + }) } /// Parses the input `section` given from the `wasmparser` crate and @@ -943,7 +1006,7 @@ pub mod utils { module.section(&reencoder.custom_name_section(name)?); } _ => { - module.section(&reencoder.custom_section(section)); + module.section(&reencoder.custom_section(section)?); } } Ok(()) @@ -966,7 +1029,9 @@ pub mod utils { external_kind: wasmparser::ExternalKind, ) -> crate::ExportKind { match external_kind { - wasmparser::ExternalKind::Func => crate::ExportKind::Func, + wasmparser::ExternalKind::Func | wasmparser::ExternalKind::FuncExact => { + crate::ExportKind::Func + } wasmparser::ExternalKind::Table => crate::ExportKind::Table, wasmparser::ExternalKind::Memory => crate::ExportKind::Memory, wasmparser::ExternalKind::Global => crate::ExportKind::Global, @@ -1005,18 +1070,18 @@ pub mod utils { ty: wasmparser::UnpackedIndex, ) -> Result<u32, Error<T::Error>> { ty.as_module_index() - .map(|ty| reencoder.type_index(ty)) .ok_or(Error::CanonicalizedHeapTypeReference) + .and_then(|ty| reencoder.type_index(ty)) } pub fn tag_type<T: ?Sized + Reencode>( reencoder: &mut T, tag_ty: wasmparser::TagType, - ) -> crate::TagType { - crate::TagType { - kind: reencoder.tag_kind(tag_ty.kind), - func_type_idx: reencoder.type_index(tag_ty.func_type_idx), - } + ) -> Result<crate::TagType, Error<T::Error>> { + Ok(crate::TagType { + kind: reencoder.tag_kind(tag_ty.kind)?, + func_type_idx: reencoder.type_index(tag_ty.func_type_idx)?, + }) } pub fn abstract_heap_type<T: ?Sized + Reencode>( @@ -1109,6 +1174,14 @@ pub mod utils { Ok(crate::CompositeType { inner, shared: composite_ty.shared, + descriptor: composite_ty + .descriptor_idx + .map(|i| reencoder.type_index_unpacked(i.unpack())) + .transpose()?, + describes: composite_ty + .describes_idx + .map(|i| reencoder.type_index_unpacked(i.unpack())) + .transpose()?, }) } @@ -1208,9 +1281,12 @@ pub mod utils { wasmparser::HeapType::Concrete(i) => { crate::HeapType::Concrete(reencoder.type_index_unpacked(i)?) } + wasmparser::HeapType::Exact(i) => { + crate::HeapType::Exact(reencoder.type_index_unpacked(i)?) + } wasmparser::HeapType::Abstract { shared, ty } => crate::HeapType::Abstract { shared, - ty: reencoder.abstract_heap_type(ty), + ty: reencoder.abstract_heap_type(ty)?, }, }) } @@ -1268,7 +1344,7 @@ pub mod utils { ) -> Result<(), Error<T::Error>> { for tag in section { let tag = tag?; - tags.tag(reencoder.tag_type(tag)); + tags.tag(reencoder.tag_type(tag)?); } Ok(()) } @@ -1281,7 +1357,7 @@ pub mod utils { section: wasmparser::ExportSectionReader<'_>, ) -> Result<(), Error<T::Error>> { for export in section { - reencoder.parse_export(exports, export?); + reencoder.parse_export(exports, export?)?; } Ok(()) } @@ -1292,12 +1368,13 @@ pub mod utils { reencoder: &mut T, exports: &mut crate::ExportSection, export: wasmparser::Export<'_>, - ) { + ) -> Result<(), Error<T::Error>> { exports.export( export.name, - reencoder.export_kind(export.kind), - reencoder.external_index(export.kind, export.index), + reencoder.export_kind(export.kind)?, + reencoder.external_index(export.kind, export.index)?, ); + Ok(()) } /// Parses the input `section` given from the `wasmparser` crate and adds @@ -1343,11 +1420,14 @@ pub mod utils { type_ref: wasmparser::TypeRef, ) -> Result<crate::EntityType, Error<T::Error>> { Ok(match type_ref { - wasmparser::TypeRef::Func(i) => crate::EntityType::Function(reencoder.type_index(i)), + wasmparser::TypeRef::Func(i) => crate::EntityType::Function(reencoder.type_index(i)?), + wasmparser::TypeRef::FuncExact(i) => { + crate::EntityType::FunctionExact(reencoder.type_index(i)?) + } wasmparser::TypeRef::Table(t) => crate::EntityType::Table(reencoder.table_type(t)?), - wasmparser::TypeRef::Memory(m) => crate::EntityType::Memory(reencoder.memory_type(m)), + wasmparser::TypeRef::Memory(m) => crate::EntityType::Memory(reencoder.memory_type(m)?), wasmparser::TypeRef::Global(g) => crate::EntityType::Global(reencoder.global_type(g)?), - wasmparser::TypeRef::Tag(t) => crate::EntityType::Tag(reencoder.tag_type(t)), + wasmparser::TypeRef::Tag(t) => crate::EntityType::Tag(reencoder.tag_type(t)?), }) } @@ -1388,7 +1468,7 @@ pub mod utils { ) -> Result<(), Error<T::Error>> { for memory in section { let memory = memory?; - memories.memory(reencoder.memory_type(memory)); + memories.memory(reencoder.memory_type(memory)?); } Ok(()) } @@ -1401,7 +1481,7 @@ pub mod utils { section: wasmparser::FunctionSectionReader<'_>, ) -> Result<(), Error<T::Error>> { for func in section { - functions.function(reencoder.type_index(func?)); + functions.function(reencoder.type_index(func?)?); } Ok(()) } @@ -1430,7 +1510,7 @@ pub mod utils { memory_index, offset_expr, } => data.active( - reencoder.memory_index(memory_index), + reencoder.memory_index(memory_index)?, &reencoder.const_expr(offset_expr)?, datum.data.iter().copied(), ), @@ -1474,7 +1554,10 @@ pub mod utils { // preserve this encoding and keep it at `None`. Otherwise if // the result is nonzero or it was previously nonzero then keep // that encoding too. - match (table_index, reencoder.table_index(table_index.unwrap_or(0))) { + match ( + table_index, + reencoder.table_index(table_index.unwrap_or(0))?, + ) { (None, 0) => None, (_, n) => Some(n), }, @@ -1495,7 +1578,7 @@ pub mod utils { wasmparser::ElementItems::Functions(f) => { let mut funcs = Vec::new(); for func in f { - funcs.push(reencoder.function_index(func?)); + funcs.push(reencoder.function_index(func?)?); } crate::Elements::Functions(funcs.into()) } @@ -1547,7 +1630,7 @@ pub mod utils { match arg { wasmparser::BlockType::Empty => Ok(crate::BlockType::Empty), wasmparser::BlockType::FuncType(n) => { - Ok(crate::BlockType::FunctionType(reencoder.type_index(n))) + Ok(crate::BlockType::FunctionType(reencoder.type_index(n)?)) } wasmparser::BlockType::Type(t) => Ok(crate::BlockType::Result(reencoder.val_type(t)?)), } @@ -1558,6 +1641,7 @@ pub mod utils { arg: wasmparser::Operator<'a>, ) -> Result<crate::Instruction<'a>, Error<T::Error>> { use crate::Instruction; + use alloc::borrow::Cow; macro_rules! translate { ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => { @@ -1577,25 +1661,25 @@ pub mod utils { // This case is used to map, based on the name of the field, from the // wasmparser payload type to the wasm-encoder payload type through // `Translator` as applicable. - (map $arg:ident tag_index) => (reencoder.tag_index($arg)); - (map $arg:ident function_index) => (reencoder.function_index($arg)); - (map $arg:ident table) => (reencoder.table_index($arg)); - (map $arg:ident table_index) => (reencoder.table_index($arg)); - (map $arg:ident dst_table) => (reencoder.table_index($arg)); - (map $arg:ident src_table) => (reencoder.table_index($arg)); - (map $arg:ident type_index) => (reencoder.type_index($arg)); - (map $arg:ident array_type_index) => (reencoder.type_index($arg)); - (map $arg:ident array_type_index_dst) => (reencoder.type_index($arg)); - (map $arg:ident array_type_index_src) => (reencoder.type_index($arg)); - (map $arg:ident struct_type_index) => (reencoder.type_index($arg)); - (map $arg:ident global_index) => (reencoder.global_index($arg)); - (map $arg:ident mem) => (reencoder.memory_index($arg)); - (map $arg:ident src_mem) => (reencoder.memory_index($arg)); - (map $arg:ident dst_mem) => (reencoder.memory_index($arg)); - (map $arg:ident data_index) => (reencoder.data_index($arg)); - (map $arg:ident elem_index) => (reencoder.element_index($arg)); - (map $arg:ident array_data_index) => (reencoder.data_index($arg)); - (map $arg:ident array_elem_index) => (reencoder.element_index($arg)); + (map $arg:ident tag_index) => (reencoder.tag_index($arg)?); + (map $arg:ident function_index) => (reencoder.function_index($arg)?); + (map $arg:ident table) => (reencoder.table_index($arg)?); + (map $arg:ident table_index) => (reencoder.table_index($arg)?); + (map $arg:ident dst_table) => (reencoder.table_index($arg)?); + (map $arg:ident src_table) => (reencoder.table_index($arg)?); + (map $arg:ident type_index) => (reencoder.type_index($arg)?); + (map $arg:ident array_type_index) => (reencoder.type_index($arg)?); + (map $arg:ident array_type_index_dst) => (reencoder.type_index($arg)?); + (map $arg:ident array_type_index_src) => (reencoder.type_index($arg)?); + (map $arg:ident struct_type_index) => (reencoder.type_index($arg)?); + (map $arg:ident global_index) => (reencoder.global_index($arg)?); + (map $arg:ident mem) => (reencoder.memory_index($arg)?); + (map $arg:ident src_mem) => (reencoder.memory_index($arg)?); + (map $arg:ident dst_mem) => (reencoder.memory_index($arg)?); + (map $arg:ident data_index) => (reencoder.data_index($arg)?); + (map $arg:ident elem_index) => (reencoder.element_index($arg)?); + (map $arg:ident array_data_index) => (reencoder.data_index($arg)?); + (map $arg:ident array_elem_index) => (reencoder.element_index($arg)?); (map $arg:ident blockty) => (reencoder.block_type($arg)?); (map $arg:ident relative_depth) => ($arg); (map $arg:ident targets) => (( @@ -1606,11 +1690,12 @@ pub mod utils { $arg.default(), )); (map $arg:ident ty) => (reencoder.val_type($arg)?); + (map $arg:ident tys) => (reencoder.val_types($arg)?); (map $arg:ident hty) => (reencoder.heap_type($arg)?); (map $arg:ident from_ref_type) => (reencoder.ref_type($arg)?); (map $arg:ident to_ref_type) => (reencoder.ref_type($arg)?); - (map $arg:ident memarg) => (reencoder.mem_arg($arg)); - (map $arg:ident ordering) => (reencoder.ordering($arg)); + (map $arg:ident memarg) => (reencoder.mem_arg($arg)?); + (map $arg:ident ordering) => (reencoder.ordering($arg)?); (map $arg:ident local_index) => ($arg); (map $arg:ident value) => ($arg); (map $arg:ident lane) => ($arg); @@ -1618,11 +1703,14 @@ pub mod utils { (map $arg:ident array_size) => ($arg); (map $arg:ident field_index) => ($arg); (map $arg:ident try_table) => ($arg); - (map $arg:ident argument_index) => (reencoder.type_index($arg)); - (map $arg:ident result_index) => (reencoder.type_index($arg)); - (map $arg:ident cont_type_index) => (reencoder.type_index($arg)); + (map $arg:ident argument_index) => (reencoder.type_index($arg)?); + (map $arg:ident result_index) => (reencoder.type_index($arg)?); + (map $arg:ident cont_type_index) => (reencoder.type_index($arg)?); (map $arg:ident resume_table) => (( - $arg.handlers.into_iter().map(|h| reencoder.handle(h)).collect::<Vec<_>>().into() + $arg.handlers.into_iter() + .map(|h| reencoder.handle(h)) + .collect::<Result<Vec<_>, _>>()? + .into() )); // This case takes the arguments of a wasmparser instruction and creates @@ -1631,13 +1719,17 @@ pub mod utils { // wasm-encoder. (build $op:ident) => (Instruction::$op); (build BrTable $arg:ident) => (Instruction::BrTable($arg.0, $arg.1)); + (build TypedSelectMulti $arg:ident) => (Instruction::TypedSelectMulti(Cow::from($arg))); (build I32Const $arg:ident) => (Instruction::I32Const($arg)); (build I64Const $arg:ident) => (Instruction::I64Const($arg)); - (build F32Const $arg:ident) => (Instruction::F32Const(f32::from_bits($arg.bits()))); - (build F64Const $arg:ident) => (Instruction::F64Const(f64::from_bits($arg.bits()))); + (build F32Const $arg:ident) => (Instruction::F32Const($arg.into())); + (build F64Const $arg:ident) => (Instruction::F64Const($arg.into())); (build V128Const $arg:ident) => (Instruction::V128Const($arg.i128())); (build TryTable $table:ident) => (Instruction::TryTable(reencoder.block_type($table.ty)?, { - $table.catches.into_iter().map(|c| reencoder.catch(c)).collect::<Vec<_>>().into() + $table.catches.into_iter() + .map(|c| reencoder.catch(c)) + .collect::<Result<Vec<_>, _>>()? + .into() })); (build $op:ident $arg:ident) => (Instruction::$op($arg)); (build $op:ident $($arg:ident)*) => (Instruction::$op { $($arg),* }); @@ -1767,40 +1859,56 @@ pub mod utils { Ok(()) } - pub fn name_map( + pub fn name_map<E>( map: wasmparser::NameMap<'_>, - mut map_index: impl FnMut(u32) -> u32, - ) -> wasmparser::Result<crate::NameMap> { + mut map_index: impl FnMut(u32) -> Result<u32, Error<E>>, + ) -> Result<crate::NameMap, Error<E>> { let mut ret = crate::NameMap::new(); for naming in map { let naming = naming?; - ret.append(map_index(naming.index), naming.name); + ret.append(map_index(naming.index)?, naming.name); } Ok(ret) } - pub fn indirect_name_map( + pub fn indirect_name_map<E>( map: wasmparser::IndirectNameMap<'_>, - mut map_index: impl FnMut(u32) -> u32, - ) -> wasmparser::Result<crate::IndirectNameMap> { + mut map_index: impl FnMut(u32) -> Result<u32, Error<E>>, + ) -> Result<crate::IndirectNameMap, Error<E>> { let mut ret = crate::IndirectNameMap::new(); for naming in map { let naming = naming?; - ret.append(map_index(naming.index), &name_map(naming.names, |i| i)?); + ret.append( + map_index(naming.index)?, + &name_map(naming.names, |i| Ok(i))?, + ); } Ok(ret) } } -impl From<wasmparser::MemArg> for crate::MemArg { - fn from(arg: wasmparser::MemArg) -> Self { +impl From<wasmparser::Ieee32> for crate::Ieee32 { + fn from(arg: wasmparser::Ieee32) -> Self { + utils::ieee32_arg(&mut RoundtripReencoder, arg) + } +} + +impl From<wasmparser::Ieee64> for crate::Ieee64 { + fn from(arg: wasmparser::Ieee64) -> Self { + utils::ieee64_arg(&mut RoundtripReencoder, arg) + } +} + +impl TryFrom<wasmparser::MemArg> for crate::MemArg { + type Error = Error; + fn try_from(arg: wasmparser::MemArg) -> Result<Self, Self::Error> { RoundtripReencoder.mem_arg(arg) } } impl From<wasmparser::Ordering> for crate::Ordering { fn from(arg: wasmparser::Ordering) -> Self { - RoundtripReencoder.ordering(arg) + utils::ordering(&mut RoundtripReencoder, arg) } } @@ -1820,8 +1928,10 @@ impl<'a> TryFrom<wasmparser::Operator<'a>> for crate::Instruction<'a> { } } -impl From<wasmparser::Catch> for crate::Catch { - fn from(arg: wasmparser::Catch) -> Self { +impl TryFrom<wasmparser::Catch> for crate::Catch { + type Error = Error; + + fn try_from(arg: wasmparser::Catch) -> Result<Self, Self::Error> { RoundtripReencoder.catch(arg) } } @@ -1836,13 +1946,13 @@ impl<'a> TryFrom<wasmparser::ConstExpr<'a>> for crate::ConstExpr { impl<'a> From<wasmparser::CustomSectionReader<'a>> for crate::CustomSection<'a> { fn from(section: wasmparser::CustomSectionReader<'a>) -> Self { - RoundtripReencoder.custom_section(section) + utils::custom_section(&mut RoundtripReencoder, section) } } impl From<wasmparser::ExternalKind> for crate::ExportKind { fn from(external_kind: wasmparser::ExternalKind) -> Self { - RoundtripReencoder.export_kind(external_kind) + utils::export_kind(&mut RoundtripReencoder, external_kind) } } @@ -1854,8 +1964,9 @@ impl TryFrom<wasmparser::GlobalType> for crate::GlobalType { } } -impl From<wasmparser::Handle> for crate::Handle { - fn from(arg: wasmparser::Handle) -> Self { +impl TryFrom<wasmparser::Handle> for crate::Handle { + type Error = Error; + fn try_from(arg: wasmparser::Handle) -> Result<Self, Self::Error> { RoundtripReencoder.handle(arg) } } @@ -1870,7 +1981,7 @@ impl TryFrom<wasmparser::TypeRef> for crate::EntityType { impl From<wasmparser::MemoryType> for crate::MemoryType { fn from(memory_ty: wasmparser::MemoryType) -> Self { - RoundtripReencoder.memory_type(memory_ty) + utils::memory_type(&mut RoundtripReencoder, memory_ty) } } @@ -1884,12 +1995,13 @@ impl TryFrom<wasmparser::TableType> for crate::TableType { impl From<wasmparser::TagKind> for crate::TagKind { fn from(kind: wasmparser::TagKind) -> Self { - RoundtripReencoder.tag_kind(kind) + utils::tag_kind(&mut RoundtripReencoder, kind) } } -impl From<wasmparser::TagType> for crate::TagType { - fn from(tag_ty: wasmparser::TagType) -> Self { +impl TryFrom<wasmparser::TagType> for crate::TagType { + type Error = Error; + fn try_from(tag_ty: wasmparser::TagType) -> Result<Self, Self::Error> { RoundtripReencoder.tag_type(tag_ty) } } @@ -1976,6 +2088,6 @@ impl TryFrom<wasmparser::HeapType> for crate::HeapType { impl From<wasmparser::AbstractHeapType> for crate::AbstractHeapType { fn from(value: wasmparser::AbstractHeapType) -> Self { - RoundtripReencoder.abstract_heap_type(value) + utils::abstract_heap_type(&mut RoundtripReencoder, value) } } diff --git a/third_party/rust/wasm-encoder/src/reencode/component.rs b/third_party/rust/wasm-encoder/src/reencode/component.rs @@ -1,5 +1,6 @@ use crate::reencode::{Error, Reencode, RoundtripReencoder}; use alloc::boxed::Box; +use core::convert::Infallible; #[allow(missing_docs)] // FIXME pub trait ReencodeComponent: Reencode { @@ -31,7 +32,7 @@ pub trait ReencodeComponent: Reencode { ty } - fn outer_type_index(&mut self, count: u32, ty: u32) -> u32 { + fn outer_type_index(&mut self, count: u32, ty: u32) -> Result<u32, Error<Self::Error>> { let _ = count; self.type_index(ty) } @@ -321,7 +322,7 @@ pub trait ReencodeComponent: Reencode { fn component_type_ref( &mut self, ty: wasmparser::ComponentTypeRef, - ) -> crate::component::ComponentTypeRef { + ) -> Result<crate::component::ComponentTypeRef, Error<Self::Error>> { component_utils::component_type_ref(self, ty) } @@ -360,7 +361,7 @@ pub trait ReencodeComponent: Reencode { fn canonical_option( &mut self, ty: wasmparser::CanonicalOption, - ) -> crate::component::CanonicalOption { + ) -> Result<crate::component::CanonicalOption, Error<Self::Error>> { component_utils::canonical_option(self, ty) } @@ -435,7 +436,7 @@ pub mod component_utils { .. } => (), wasmparser::Payload::Version { .. } => { - return Err(Error::UnexpectedNonComponentSection) + return Err(Error::UnexpectedNonComponentSection); } wasmparser::Payload::TypeSection(_) | wasmparser::Payload::ImportSection(_) @@ -451,7 +452,7 @@ pub mod component_utils { | wasmparser::Payload::DataSection(_) | wasmparser::Payload::CodeSectionStart { .. } | wasmparser::Payload::CodeSectionEntry(_) => { - return Err(Error::UnexpectedNonComponentSection) + return Err(Error::UnexpectedNonComponentSection); } wasmparser::Payload::ComponentTypeSection(section) => { let mut types = crate::ComponentTypeSection::new(); @@ -582,7 +583,7 @@ pub mod component_utils { component.section(&reencoder.custom_component_name_section(name)?); } _ => { - component.section(&reencoder.custom_section(section)); + component.section(&reencoder.custom_section(section)?); } } Ok(()) @@ -621,7 +622,7 @@ pub mod component_utils { } wasmparser::ComponentType::Resource { rep, dtor } => { let rep = reencoder.val_type(rep)?; - let dtor = dtor.map(|i| reencoder.function_index(i)); + let dtor = dtor.map(|i| reencoder.function_index(i)).transpose()?; dst.resource(rep, dtor); } } @@ -659,7 +660,7 @@ pub mod component_utils { Ok(()) } wasmparser::InstanceTypeDeclaration::Export { name, ty } => { - let ty = reencoder.component_type_ref(ty); + let ty = reencoder.component_type_ref(ty)?; instance.export(name.0, ty); Ok(()) } @@ -713,12 +714,12 @@ pub mod component_utils { Ok(()) } wasmparser::ComponentTypeDeclaration::Export { name, ty } => { - let ty = reencoder.component_type_ref(ty); + let ty = reencoder.component_type_ref(ty)?; component.export(name.0, ty); Ok(()) } wasmparser::ComponentTypeDeclaration::Import(import) => { - let ty = reencoder.component_type_ref(import.ty); + let ty = reencoder.component_type_ref(import.ty)?; component.import(import.name.0, ty); Ok(()) } @@ -730,23 +731,14 @@ pub mod component_utils { mut func: crate::ComponentFuncTypeEncoder<'_>, ty: wasmparser::ComponentFuncType<'_>, ) -> Result<(), Error<T::Error>> { + func.async_(ty.async_); func.params( Vec::from(ty.params) .into_iter() .map(|(name, ty)| (name, reencoder.component_val_type(ty))), ); - match ty.results { - wasmparser::ComponentFuncResult::Unnamed(ty) => { - func.result(reencoder.component_val_type(ty)); - } - wasmparser::ComponentFuncResult::Named(list) => { - func.results( - Vec::from(list) - .into_iter() - .map(|(name, ty)| (name, reencoder.component_val_type(ty))), - ); - } - } + let result = ty.result.map(|ty| reencoder.component_val_type(ty)); + func.result(result); Ok(()) } @@ -777,6 +769,9 @@ pub mod component_utils { wasmparser::ComponentDefinedType::List(t) => { defined.list(reencoder.component_val_type(t)); } + wasmparser::ComponentDefinedType::FixedSizeList(t, elements) => { + defined.fixed_size_list(reencoder.component_val_type(t), elements); + } wasmparser::ComponentDefinedType::Tuple(t) => { defined.tuple(t.iter().map(|t| reencoder.component_val_type(*t))); } @@ -806,7 +801,6 @@ pub mod component_utils { wasmparser::ComponentDefinedType::Stream(t) => { defined.stream(t.map(|t| reencoder.component_val_type(t))); } - wasmparser::ComponentDefinedType::ErrorContext => defined.error_context(), } Ok(()) } @@ -841,7 +835,7 @@ pub mod component_utils { count, index, } => { - let index = reencoder.outer_type_index(count, index); + let index = reencoder.outer_type_index(count, index)?; module.alias_outer_core_type(count, index); } wasmparser::ModuleTypeDeclaration::Import(import) => { @@ -886,7 +880,7 @@ pub mod component_utils { reencoder.outer_module_index(count, index) } wasmparser::ComponentOuterAliasKind::CoreType => { - reencoder.outer_type_index(count, index) + reencoder.outer_type_index(count, index)? } wasmparser::ComponentOuterAliasKind::Type => { reencoder.outer_component_type_index(count, index) @@ -906,7 +900,7 @@ pub mod component_utils { ) -> Result<(), Error<T::Error>> { for import in section { let import = import?; - imports.import(import.name.0, reencoder.component_type_ref(import.ty)); + imports.import(import.name.0, reencoder.component_type_ref(import.ty)?); } Ok(()) } @@ -933,20 +927,24 @@ pub mod component_utils { type_index, options, } => { - let func = reencoder.function_index(core_func_index); + let func = reencoder.function_index(core_func_index)?; let ty = reencoder.component_type_index(type_index); - section.lift( - func, - ty, - options.iter().map(|o| reencoder.canonical_option(*o)), - ); + let options = options + .iter() + .map(|o| reencoder.canonical_option(*o)) + .collect::<Result<Vec<_>, _>>()?; + section.lift(func, ty, options); } wasmparser::CanonicalFunction::Lower { func_index, options, } => { let func = reencoder.component_func_index(func_index); - section.lower(func, options.iter().map(|o| reencoder.canonical_option(*o))); + let options = options + .iter() + .map(|o| reencoder.canonical_option(*o)) + .collect::<Result<Vec<_>, _>>()?; + section.lower(func, options); } wasmparser::CanonicalFunction::ResourceNew { resource } => { let resource = reencoder.component_type_index(resource); @@ -956,49 +954,79 @@ pub mod component_utils { let resource = reencoder.component_type_index(resource); section.resource_drop(resource); } + wasmparser::CanonicalFunction::ResourceDropAsync { resource } => { + let resource = reencoder.component_type_index(resource); + section.resource_drop_async(resource); + } wasmparser::CanonicalFunction::ResourceRep { resource } => { let resource = reencoder.component_type_index(resource); section.resource_rep(resource); } - wasmparser::CanonicalFunction::ThreadSpawn { func_ty_index } => { - let func_ty = reencoder.type_index(func_ty_index); - section.thread_spawn(func_ty); + wasmparser::CanonicalFunction::ThreadSpawnRef { func_ty_index } => { + let func_ty = reencoder.type_index(func_ty_index)?; + section.thread_spawn_ref(func_ty); + } + wasmparser::CanonicalFunction::ThreadSpawnIndirect { + func_ty_index, + table_index, + } => { + let func_ty = reencoder.type_index(func_ty_index)?; + let table_index = reencoder.table_index(table_index)?; + section.thread_spawn_indirect(func_ty, table_index); + } + wasmparser::CanonicalFunction::ThreadAvailableParallelism => { + section.thread_available_parallelism(); + } + wasmparser::CanonicalFunction::BackpressureSet => { + section.backpressure_set(); } - wasmparser::CanonicalFunction::ThreadHwConcurrency => { - section.thread_hw_concurrency(); + wasmparser::CanonicalFunction::BackpressureInc => { + section.backpressure_inc(); } - wasmparser::CanonicalFunction::TaskBackpressure => { - section.task_backpressure(); + wasmparser::CanonicalFunction::BackpressureDec => { + section.backpressure_dec(); } - wasmparser::CanonicalFunction::TaskReturn { result } => { - section.task_return(result.map(|ty| reencoder.component_val_type(ty))); + wasmparser::CanonicalFunction::TaskReturn { result, options } => { + let options = options + .iter() + .map(|o| reencoder.canonical_option(*o)) + .collect::<Result<Vec<_>, _>>()?; + section.task_return(result.map(|ty| reencoder.component_val_type(ty)), options); } - wasmparser::CanonicalFunction::TaskWait { async_, memory } => { - section.task_wait(async_, reencoder.memory_index(memory)); + wasmparser::CanonicalFunction::TaskCancel => { + section.task_cancel(); } - wasmparser::CanonicalFunction::TaskPoll { async_, memory } => { - section.task_poll(async_, reencoder.memory_index(memory)); + wasmparser::CanonicalFunction::ContextGet(i) => { + section.context_get(i); } - wasmparser::CanonicalFunction::TaskYield { async_ } => { - section.task_yield(async_); + wasmparser::CanonicalFunction::ContextSet(i) => { + section.context_set(i); + } + wasmparser::CanonicalFunction::ThreadYield { cancellable } => { + section.thread_yield(cancellable); } wasmparser::CanonicalFunction::SubtaskDrop => { section.subtask_drop(); } + wasmparser::CanonicalFunction::SubtaskCancel { async_ } => { + section.subtask_cancel(async_); + } wasmparser::CanonicalFunction::StreamNew { ty } => { section.stream_new(reencoder.component_type_index(ty)); } wasmparser::CanonicalFunction::StreamRead { ty, options } => { - section.stream_read( - reencoder.component_type_index(ty), - options.iter().map(|o| reencoder.canonical_option(*o)), - ); + let options = options + .iter() + .map(|o| reencoder.canonical_option(*o)) + .collect::<Result<Vec<_>, _>>()?; + section.stream_read(reencoder.component_type_index(ty), options); } wasmparser::CanonicalFunction::StreamWrite { ty, options } => { - section.stream_write( - reencoder.component_type_index(ty), - options.iter().map(|o| reencoder.canonical_option(*o)), - ); + let options = options + .iter() + .map(|o| reencoder.canonical_option(*o)) + .collect::<Result<Vec<_>, _>>()?; + section.stream_write(reencoder.component_type_index(ty), options); } wasmparser::CanonicalFunction::StreamCancelRead { ty, async_ } => { section.stream_cancel_read(ty, async_); @@ -1006,26 +1034,28 @@ pub mod component_utils { wasmparser::CanonicalFunction::StreamCancelWrite { ty, async_ } => { section.stream_cancel_write(ty, async_); } - wasmparser::CanonicalFunction::StreamCloseReadable { ty } => { - section.stream_close_readable(reencoder.component_type_index(ty)); + wasmparser::CanonicalFunction::StreamDropReadable { ty } => { + section.stream_drop_readable(reencoder.component_type_index(ty)); } - wasmparser::CanonicalFunction::StreamCloseWritable { ty } => { - section.stream_close_writable(reencoder.component_type_index(ty)); + wasmparser::CanonicalFunction::StreamDropWritable { ty } => { + section.stream_drop_writable(reencoder.component_type_index(ty)); } wasmparser::CanonicalFunction::FutureNew { ty } => { section.future_new(reencoder.component_type_index(ty)); } wasmparser::CanonicalFunction::FutureRead { ty, options } => { - section.future_read( - reencoder.component_type_index(ty), - options.iter().map(|o| reencoder.canonical_option(*o)), - ); + let options = options + .iter() + .map(|o| reencoder.canonical_option(*o)) + .collect::<Result<Vec<_>, _>>()?; + section.future_read(reencoder.component_type_index(ty), options); } wasmparser::CanonicalFunction::FutureWrite { ty, options } => { - section.future_write( - reencoder.component_type_index(ty), - options.iter().map(|o| reencoder.canonical_option(*o)), - ); + let options = options + .iter() + .map(|o| reencoder.canonical_option(*o)) + .collect::<Result<Vec<_>, _>>()?; + section.future_write(reencoder.component_type_index(ty), options); } wasmparser::CanonicalFunction::FutureCancelRead { ty, async_ } => { section.future_cancel_read(ty, async_); @@ -1033,23 +1063,73 @@ pub mod component_utils { wasmparser::CanonicalFunction::FutureCancelWrite { ty, async_ } => { section.future_cancel_write(ty, async_); } - wasmparser::CanonicalFunction::FutureCloseReadable { ty } => { - section.future_close_readable(reencoder.component_type_index(ty)); + wasmparser::CanonicalFunction::FutureDropReadable { ty } => { + section.future_drop_readable(reencoder.component_type_index(ty)); } - wasmparser::CanonicalFunction::FutureCloseWritable { ty } => { - section.future_close_writable(reencoder.component_type_index(ty)); + wasmparser::CanonicalFunction::FutureDropWritable { ty } => { + section.future_drop_writable(reencoder.component_type_index(ty)); } wasmparser::CanonicalFunction::ErrorContextNew { options } => { - section.error_context_new(options.iter().map(|o| reencoder.canonical_option(*o))); + let options = options + .iter() + .map(|o| reencoder.canonical_option(*o)) + .collect::<Result<Vec<_>, _>>()?; + section.error_context_new(options); } wasmparser::CanonicalFunction::ErrorContextDebugMessage { options } => { - section.error_context_debug_message( - options.iter().map(|o| reencoder.canonical_option(*o)), - ); + let options = options + .iter() + .map(|o| reencoder.canonical_option(*o)) + .collect::<Result<Vec<_>, _>>()?; + section.error_context_debug_message(options); } wasmparser::CanonicalFunction::ErrorContextDrop => { section.error_context_drop(); } + wasmparser::CanonicalFunction::WaitableSetNew => { + section.waitable_set_new(); + } + wasmparser::CanonicalFunction::WaitableSetWait { + cancellable, + memory, + } => { + section.waitable_set_wait(cancellable, reencoder.memory_index(memory)?); + } + wasmparser::CanonicalFunction::WaitableSetPoll { + cancellable, + memory, + } => { + section.waitable_set_poll(cancellable, reencoder.memory_index(memory)?); + } + wasmparser::CanonicalFunction::WaitableSetDrop => { + section.waitable_set_drop(); + } + wasmparser::CanonicalFunction::WaitableJoin => { + section.waitable_join(); + } + wasmparser::CanonicalFunction::ThreadIndex => { + section.thread_index(); + } + wasmparser::CanonicalFunction::ThreadNewIndirect { + func_ty_index, + table_index, + } => { + let func_ty = reencoder.type_index(func_ty_index)?; + let table_index = reencoder.table_index(table_index)?; + section.thread_new_indirect(func_ty, table_index); + } + wasmparser::CanonicalFunction::ThreadSwitchTo { cancellable } => { + section.thread_switch_to(cancellable); + } + wasmparser::CanonicalFunction::ThreadSuspend { cancellable } => { + section.thread_suspend(cancellable); + } + wasmparser::CanonicalFunction::ThreadResumeLater => { + section.thread_resume_later(); + } + wasmparser::CanonicalFunction::ThreadYieldTo { cancellable } => { + section.thread_yield_to(cancellable); + } } Ok(()) } @@ -1139,13 +1219,17 @@ pub mod component_utils { ); } wasmparser::Instance::FromExports(exports) => { - instances.export_items(exports.iter().map(|export| { - ( - export.name, - reencoder.export_kind(export.kind), - reencoder.external_index(export.kind, export.index), - ) - })); + let exports = exports + .iter() + .map(|export| { + Ok(( + export.name, + reencoder.export_kind(export.kind)?, + reencoder.external_index(export.kind, export.index)?, + )) + }) + .collect::<Result<Vec<_>, Error<T::Error>>>()?; + instances.export_items(exports); } } Ok(()) @@ -1182,7 +1266,10 @@ pub mod component_utils { export.name.0, export.kind.into(), reencoder.component_external_index(export.kind, export.index), - export.ty.map(|t| reencoder.component_type_ref(t)), + export + .ty + .map(|t| reencoder.component_type_ref(t)) + .transpose()?, ); Ok(()) } @@ -1207,10 +1294,10 @@ pub mod component_utils { pub fn component_type_ref<T: ?Sized + ReencodeComponent>( reencoder: &mut T, ty: wasmparser::ComponentTypeRef, - ) -> crate::component::ComponentTypeRef { - match ty { + ) -> Result<crate::component::ComponentTypeRef, Error<T::Error>> { + Ok(match ty { wasmparser::ComponentTypeRef::Module(u) => { - crate::component::ComponentTypeRef::Module(reencoder.type_index(u)) + crate::component::ComponentTypeRef::Module(reencoder.type_index(u)?) } wasmparser::ComponentTypeRef::Func(u) => { crate::component::ComponentTypeRef::Func(reencoder.component_type_index(u)) @@ -1227,7 +1314,7 @@ pub mod component_utils { wasmparser::ComponentTypeRef::Component(u) => { crate::component::ComponentTypeRef::Component(reencoder.component_type_index(u)) } - } + }) } pub fn component_primitive_val_type<T: ?Sized + ReencodeComponent>( @@ -1248,6 +1335,9 @@ pub mod component_utils { wasmparser::PrimitiveValType::F64 => crate::component::PrimitiveValType::F64, wasmparser::PrimitiveValType::Char => crate::component::PrimitiveValType::Char, wasmparser::PrimitiveValType::String => crate::component::PrimitiveValType::String, + wasmparser::PrimitiveValType::ErrorContext => { + crate::component::PrimitiveValType::ErrorContext + } } } @@ -1316,27 +1406,31 @@ pub mod component_utils { pub fn canonical_option<T: ?Sized + ReencodeComponent>( reencoder: &mut T, ty: wasmparser::CanonicalOption, - ) -> crate::component::CanonicalOption { - match ty { + ) -> Result<crate::component::CanonicalOption, Error<T::Error>> { + Ok(match ty { wasmparser::CanonicalOption::UTF8 => crate::component::CanonicalOption::UTF8, wasmparser::CanonicalOption::UTF16 => crate::component::CanonicalOption::UTF16, wasmparser::CanonicalOption::CompactUTF16 => { crate::component::CanonicalOption::CompactUTF16 } wasmparser::CanonicalOption::Memory(u) => { - crate::component::CanonicalOption::Memory(reencoder.memory_index(u)) + crate::component::CanonicalOption::Memory(reencoder.memory_index(u)?) } wasmparser::CanonicalOption::Realloc(u) => { - crate::component::CanonicalOption::Realloc(reencoder.function_index(u)) + crate::component::CanonicalOption::Realloc(reencoder.function_index(u)?) } wasmparser::CanonicalOption::PostReturn(u) => { - crate::component::CanonicalOption::PostReturn(reencoder.function_index(u)) + crate::component::CanonicalOption::PostReturn(reencoder.function_index(u)?) } wasmparser::CanonicalOption::Async => crate::component::CanonicalOption::Async, wasmparser::CanonicalOption::Callback(u) => { - crate::component::CanonicalOption::Callback(reencoder.function_index(u)) + crate::component::CanonicalOption::Callback(reencoder.function_index(u)?) } - } + wasmparser::CanonicalOption::CoreType(u) => { + crate::component::CanonicalOption::CoreType(reencoder.type_index(u)?) + } + wasmparser::CanonicalOption::Gc => crate::component::CanonicalOption::Gc, + }) } pub fn custom_component_name_section<T: ?Sized + ReencodeComponent>( @@ -1371,29 +1465,34 @@ pub mod component_utils { wasmparser::ComponentName::CoreTables(map) => { names.core_tables(&name_map(map, |i| reencoder.table_index(i))?); } + wasmparser::ComponentName::CoreTags(map) => { + names.core_tags(&name_map(map, |i| reencoder.tag_index(i))?); + } wasmparser::ComponentName::CoreModules(map) => { - names.core_modules(&name_map(map, |i| reencoder.module_index(i))?); + names.core_modules(&name_map(map, |i| Ok(reencoder.module_index(i)))?); } wasmparser::ComponentName::CoreInstances(map) => { - names.core_instances(&name_map(map, |i| reencoder.instance_index(i))?); + names.core_instances(&name_map(map, |i| Ok(reencoder.instance_index(i)))?); } wasmparser::ComponentName::CoreTypes(map) => { names.core_types(&name_map(map, |i| reencoder.type_index(i))?); } wasmparser::ComponentName::Types(map) => { - names.types(&name_map(map, |i| reencoder.component_type_index(i))?); + names.types(&name_map(map, |i| Ok(reencoder.component_type_index(i)))?); } wasmparser::ComponentName::Instances(map) => { - names.instances(&name_map(map, |i| reencoder.component_instance_index(i))?); + names.instances(&name_map(map, |i| { + Ok(reencoder.component_instance_index(i)) + })?); } wasmparser::ComponentName::Components(map) => { - names.components(&name_map(map, |i| reencoder.component_index(i))?); + names.components(&name_map(map, |i| Ok(reencoder.component_index(i)))?); } wasmparser::ComponentName::Funcs(map) => { - names.funcs(&name_map(map, |i| reencoder.component_func_index(i))?); + names.funcs(&name_map(map, |i| Ok(reencoder.component_func_index(i)))?); } wasmparser::ComponentName::Values(map) => { - names.values(&name_map(map, |i| reencoder.component_value_index(i))?); + names.values(&name_map(map, |i| Ok(reencoder.component_value_index(i)))?); } wasmparser::ComponentName::Unknown { ty, data, .. } => { names.raw(ty, data); @@ -1417,7 +1516,7 @@ impl From<wasmparser::TypeBounds> for crate::TypeBounds { impl From<wasmparser::CanonicalOption> for crate::CanonicalOption { fn from(opt: wasmparser::CanonicalOption) -> Self { - RoundtripReencoder.canonical_option(opt) + Result::<_, Error<Infallible>>::unwrap(RoundtripReencoder.canonical_option(opt)) } } @@ -1435,7 +1534,7 @@ impl From<wasmparser::ComponentOuterAliasKind> for crate::ComponentOuterAliasKin impl From<wasmparser::ComponentTypeRef> for crate::ComponentTypeRef { fn from(ty: wasmparser::ComponentTypeRef) -> Self { - RoundtripReencoder.component_type_ref(ty) + Result::<_, Error<Infallible>>::unwrap(RoundtripReencoder.component_type_ref(ty)) } } diff --git a/third_party/rust/wasm-smith/.cargo-checksum.json b/third_party/rust/wasm-smith/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"559556b2b63bd4f2512a2f6d80d8bb17289fa00b38f14aa26f9a5145ec294d1c","Cargo.toml":"483cd4e144275d0f848ce885fe76edfd4dcbcb886011fbd72a520161703b3048","README.md":"e7b2a96cf39834aa19aed7cad8658e33445cdec7c4957658ba39e3b82cc4254b","benches/corpus.rs":"2df29556be0799f0cb1f32c8d0ae5ba0c4b9815cf4d59a8b71744d926c0693a0","src/component.rs":"99a97ea23fb0ae6ce192802f92f518da835aa919194ca081af874873675ad05b","src/component/encode.rs":"b96eaa64b61eb2adf9cd5c134fc7660cb6931b9d1e66067b82749b917e28eab5","src/config.rs":"37355af3f51bd331237dcf8d3abede697d252616d38ca043d7a2876eca308c68","src/core.rs":"820120981ed3d79bbc68a94c1fd4e6042845602edac21bd34c018f66aff9667d","src/core/code_builder.rs":"c649c3c976c0adc3232411af95d1659175c62b7cbfcbcb0f0f90c0a879086613","src/core/code_builder/no_traps.rs":"14dab911427934dd6394b36eea9761c8722c47611b3ebf9fde1d54bebd7c4e55","src/core/encode.rs":"d305654e8777fe729f84e63d4bc72faa86b926a4a4ba74f64a944c9210e9e430","src/core/terminate.rs":"e07fe450c1fee58726bace161c5747a6f01539e8b2937724064cc7370562555c","src/lib.rs":"b8b7aa4a298a2e6820f072992a03999936099c4f3c81a6b58e581fe718e914bd","tests/available_imports.rs":"27c464644b4b848cfe6cf5eda89f2e971bab8148631aeaf1a5e4b1b86daf166d","tests/common/mod.rs":"3381b3ac480115f463332fd1361146880ec857c00691e0f91a4d3056c715bd0e","tests/component.rs":"2c360858cdd270e2ee46333d8de8df3a1d3521a3bcb7246bc9a4f85b0539df0f","tests/core.rs":"5ae8d189ff5282856d9d4d830c16ba104a11c9ec98335d8b0a64ea634ff6c47a","tests/exports.rs":"a767e6f8eb80a23d430864213df72711b0c453020391b71df07a2f24c34bd514"},"package":"d93c23413c233bc0bd7bb14cae607b0c1b6731527fd7ad6e166b6eaa11aecd2b"} -\ No newline at end of file +{"files":{"Cargo.lock":"021db6ba92067f19b2e783f666a41162f3bb8845d8ec1e46eaf24b6e4043438b","Cargo.toml":"5dc54cb71ca80f81777719943a6d3d6d136a6f8338dd73cef03811ec198f426e","README.md":"e688e3c121e7eaf851e689c611248ed52c55f561edaf27d31edb7934e351963b","benches/corpus.rs":"2ba06766908f2bde01dc7e4545b70979ea7268806a73c1cdda4affc4ca59efa8","src/component.rs":"c1cabcc531366cc820596bf482102750c29a88596371e2cb01d0c51772402f3c","src/component/encode.rs":"9b5a8dfec9815c7598c1bedc6a069f89f7dea9ff70b9a28b2328e173982dfd89","src/config.rs":"89127a8cabc41fdd49e9f22fc5a9f6ab021d901898aa732b890b08eb0cd0293b","src/core.rs":"4192e27509325f15572a65708368da50471542d5725713aac735915aef141129","src/core/code_builder.rs":"66be67ca533d265a0be85efac139a9251816492e9d6d29429dd5b81278ce5ea2","src/core/code_builder/no_traps.rs":"b502ce3179349a57fdb817c68dfdce569f75cf587cb5c06be99275c563a386d5","src/core/encode.rs":"0b13d7f67d2cf82c56dfc6d8e5f3ebb6df0eac683e3a3cec8dd6e043407c48e3","src/core/terminate.rs":"5b362bf47463ad0ed05df80fa7f3a99f9983697f02d2ad97b7e4c74f024b0a36","src/lib.rs":"b0b180a3849312eb415f0ee10ac193544da66c29ddc8ab43adb84aad29ba7e5f","tests/available_imports.rs":"0f5d5de27f47df1f56115a59bd4b9bbe066de150b4bcec86af8748795cb9e94c","tests/common/mod.rs":"50e7f9a63a7c1bc65d6b2253a0b253d0dd6da6c3870303e858dddeab1b883f77","tests/component.rs":"d9ade851973dc4744a02ac5afb543692393bf03f3572aeceafc2bf12e564dffb","tests/core.rs":"7981c68958944456f99262438a9785922a152adabfe9e22d4531bc2f54ce316e","tests/exports.rs":"49bb78d41cdd47d09935b58ab1e496a6a2e250c3f13b5bc110b489d98058d840","tests/module_shape.rs":"6185505001f6b7b1d1ea9c35c85e567bd43fd25387cfe723443709b35e0af201"},"package":"119b7dd7690868543d344025ee894271d9c66fa00d5c1cd233a5c72eb7a2ea03"} +\ No newline at end of file diff --git a/third_party/rust/wasm-smith/Cargo.lock b/third_party/rust/wasm-smith/Cargo.lock @@ -19,9 +19,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" dependencies = [ "anstyle", "anstyle-parse", @@ -34,76 +34,71 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" dependencies = [ - "windows-sys 0.52.0", + "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "once_cell_polyfill", + "windows-sys", ] [[package]] name = "anyhow" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" dependencies = [ "derive_arbitrary", ] [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "byteorder" -version = "1.5.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cast" @@ -113,9 +108,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.1.28" +version = "1.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1" +checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" dependencies = [ "jobserver", "libc", @@ -124,9 +119,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "ciborium" @@ -157,9 +152,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.19" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", "clap_derive", @@ -167,9 +162,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.19" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstream", "anstyle", @@ -179,9 +174,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" dependencies = [ "heck", "proc-macro2", @@ -191,15 +186,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "criterion" @@ -237,15 +232,15 @@ dependencies = [ [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "derive_arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", @@ -254,33 +249,34 @@ dependencies = [ [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "flagset" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec" +checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe" dependencies = [ "serde", ] [[package]] name = "getrandom" -version = "0.2.15" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", + "r-efi", "wasi", ] @@ -296,9 +292,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" [[package]] name = "heck" @@ -308,15 +304,15 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "indexmap" -version = "2.7.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", "hashbrown", @@ -324,13 +320,13 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -350,16 +346,17 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom", "libc", ] @@ -371,26 +368,25 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libfuzzer-sys" -version = "0.4.7" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" +checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404" dependencies = [ "arbitrary", "cc", - "once_cell", ] [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "num-traits" @@ -403,59 +399,70 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] name = "oorandom" -version = "11.1.4" +version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] [[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] name = "rand" -version = "0.8.5" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ - "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" -version = "0.3.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", "rand_core", @@ -463,18 +470,18 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.4" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ "getrandom", ] [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -484,9 +491,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -501,9 +508,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -516,24 +523,34 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "serde" -version = "1.0.217" +version = "1.0.222" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "aab69e3f5be1836a1fe0aca0b286e5a5b38f262d6c9e8acd2247818751fcc8fb" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.222" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f8ebec5eea07db7df9342aa712db2138f019d9ab3454a60a680579a6f841b80" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.222" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "b5f61630fe26d0ff555e6c37dc445ab2f15871c8a11ace3cf471b3195d3e4f49" dependencies = [ "proc-macro2", "quote", @@ -542,9 +559,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -566,9 +583,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.87" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -596,15 +613,15 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-width" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" [[package]] name = "utf8parse" @@ -624,15 +641,18 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] [[package]] name = "wasm-encoder" -version = "0.225.0" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f7eac0445cac73bcf09e6a97f83248d64356dccf9f2b100199769b6b42464e5" +checksum = "c55db9c896d70bd9fa535ce83cd4e1f2ec3726b0edd2142079f594fc3be1cb35" dependencies = [ "leb128fmt", "wasmparser", @@ -640,7 +660,7 @@ dependencies = [ [[package]] name = "wasm-smith" -version = "0.225.0" +version = "0.243.0" dependencies = [ "anyhow", "arbitrary", @@ -659,9 +679,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.225.0" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36e5456165f81e64cb9908a0fe9b9d852c2c74582aa3fe2be3c2da57f937d3ae" +checksum = "f6d8db401b0528ec316dfbe579e6ab4152d61739cfe076706d2009127970159d" dependencies = [ "bitflags", "indexmap", @@ -670,9 +690,9 @@ dependencies = [ [[package]] name = "wasmprinter" -version = "0.225.0" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c32de8f41929f40bb595d1309549c58bbe1b43b05627fe42517e23a50230e0a" +checksum = "eb2b6035559e146114c29a909a3232928ee488d6507a1504d8934e8607b36d7b" dependencies = [ "anyhow", "termcolor", @@ -681,9 +701,9 @@ dependencies = [ [[package]] name = "wast" -version = "225.0.0" +version = "243.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61496027ff707f9fa9e0b22c34ec163eb7adb1070df565e32a9180a76e4300b" +checksum = "df21d01c2d91e46cb7a221d79e58a2d210ea02020d57c092e79255cc2999ca7f" dependencies = [ "bumpalo", "leb128fmt", @@ -694,9 +714,9 @@ dependencies = [ [[package]] name = "wat" -version = "1.225.0" +version = "1.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e72a33942234fd0794bcdac30e43b448de3187512414267678e511c6755f11" +checksum = "226a9a91cd80a50449312fef0c75c23478fcecfcc4092bdebe1dc8e760ef521b" dependencies = [ "wast", ] @@ -707,16 +727,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", + "windows-sys", ] [[package]] @@ -793,20 +804,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ - "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", diff --git a/third_party/rust/wasm-smith/Cargo.toml b/third_party/rust/wasm-smith/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.76.0" name = "wasm-smith" -version = "0.225.0" +version = "0.243.0" authors = ["Nick Fitzgerald <fitzgen@gmail.com>"] build = false exclude = ["/benches/corpus"] @@ -37,6 +37,25 @@ repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wa [package.metadata.docs.rs] all-features = true +[features] +_internal_cli = [ + "clap", + "serde", + "dep:wasmparser", + "dep:wat", +] +component-model = ["wasm-encoder/component-model"] +serde = [ + "dep:serde", + "dep:serde_derive", + "flagset/serde", + "dep:wat", +] +wasmparser = [ + "dep:wasmparser", + "wasm-encoder/wasmparser", +] + [lib] name = "wasm_smith" path = "src/lib.rs" @@ -57,6 +76,10 @@ path = "tests/core.rs" name = "exports" path = "tests/exports.rs" +[[test]] +name = "module_shape" +path = "tests/module_shape.rs" + [[bench]] name = "corpus" path = "benches/corpus.rs" @@ -88,12 +111,12 @@ version = "1.0.166" optional = true [dependencies.wasm-encoder] -version = "0.225.0" +version = "0.243.0" features = ["std"] default-features = false [dependencies.wasmparser] -version = "0.225.0" +version = "0.243.0" features = [ "simd", "std", @@ -105,7 +128,7 @@ optional = true default-features = false [dependencies.wat] -version = "1.225.0" +version = "1.243.0" optional = true default-features = false @@ -114,11 +137,11 @@ version = "0.5.1" default-features = false [dev-dependencies.rand] -version = "0.8.4" +version = "0.9.1" features = ["small_rng"] [dev-dependencies.wasmparser] -version = "0.225.0" +version = "0.243.0" features = [ "simd", "std", @@ -129,35 +152,25 @@ features = [ default-features = false [dev-dependencies.wasmprinter] -version = "0.225.0" +version = "0.243.0" default-features = false [dev-dependencies.wat] -version = "1.225.0" +version = "1.243.0" default-features = false -[features] -_internal_cli = [ - "clap", - "flagset/serde", - "serde", - "serde_derive", - "wasmparser", - "wat", -] -component-model = ["wasm-encoder/component-model"] -wasmparser = [ - "dep:wasmparser", - "wasm-encoder/wasmparser", -] - [target.'cfg(not(target_family = "wasm"))'.dev-dependencies.libfuzzer-sys] version = "0.4.0" [lints.clippy] +allow_attributes_without_reason = "warn" clone_on_copy = "warn" manual_strip = "warn" map_clone = "warn" +uninlined_format_args = "warn" +unnecessary_cast = "warn" +unnecessary_fallible_conversions = "warn" +unnecessary_mut_passed = "warn" unnecessary_to_owned = "warn" [lints.clippy.all] @@ -165,4 +178,22 @@ level = "allow" priority = -1 [lints.rust] +deprecated-safe-2024 = "warn" +keyword_idents_2024 = "warn" +missing-unsafe-on-extern = "warn" +rust-2024-guarded-string-incompatible-syntax = "warn" +rust-2024-incompatible-pat = "warn" +rust-2024-prelude-collisions = "warn" +unsafe-attr-outside-unsafe = "warn" +unsafe-op-in-unsafe-fn = "warn" unsafe_code = "deny" +unstable_features = "warn" +unused-lifetimes = "warn" +unused-macro-rules = "warn" +unused_extern_crates = "warn" +unused_import_braces = "warn" + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = ["cfg(fuzzing)"] diff --git a/third_party/rust/wasm-smith/README.md b/third_party/rust/wasm-smith/README.md @@ -2,7 +2,7 @@ **A WebAssembly test case generator.** -[](https://docs.rs/wasm-smith/) +[ [](https://crates.io/crates/wasm-smith) [](https://crates.io/crates/wasm-smith) diff --git a/third_party/rust/wasm-smith/benches/corpus.rs b/third_party/rust/wasm-smith/benches/corpus.rs @@ -1,5 +1,6 @@ use arbitrary::{Arbitrary, Unstructured}; -use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use criterion::{Criterion, criterion_group, criterion_main}; +use std::hint::black_box; use wasm_smith::Module; pub fn benchmark_corpus(c: &mut Criterion) { diff --git a/third_party/rust/wasm-smith/src/component.rs b/third_party/rust/wasm-smith/src/component.rs @@ -4,7 +4,7 @@ // FIXME(#1000): component support in `wasm-smith` is a work in progress. #![allow(unused_variables, dead_code)] -use crate::{arbitrary_loop, Config}; +use crate::{Config, arbitrary_loop}; use arbitrary::{Arbitrary, Result, Unstructured}; use std::collections::BTreeMap; use std::{ @@ -22,7 +22,7 @@ mod encode; /// Construct instances of this type with [the `Arbitrary` /// trait](https://docs.rs/arbitrary/*/arbitrary/trait.Arbitrary.html). /// -/// [component]: https://github.com/WebAssembly/component-model/blob/ast-and-binary/design/MVP/Explainer.md +/// [component]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md /// /// ## Configured Generated Components /// @@ -1784,7 +1784,7 @@ fn canonical_abi_for(func_ty: &FuncType) -> Rc<crate::core::FuncType> { PrimitiveValType::S64 | PrimitiveValType::U64 => ValType::I64, PrimitiveValType::F32 => ValType::F32, PrimitiveValType::F64 => ValType::F64, - PrimitiveValType::String => { + PrimitiveValType::String | PrimitiveValType::ErrorContext => { unimplemented!("non-scalar types are not supported yet") } }, @@ -2067,7 +2067,7 @@ fn is_scalar(ty: &ComponentValType) -> bool { | PrimitiveValType::F32 | PrimitiveValType::F64 | PrimitiveValType::Char => true, - PrimitiveValType::String => false, + PrimitiveValType::String | PrimitiveValType::ErrorContext => false, }, ComponentValType::Type(_) => false, } diff --git a/third_party/rust/wasm-smith/src/component/encode.rs b/third_party/rust/wasm-smith/src/component/encode.rs @@ -172,17 +172,7 @@ impl Type { let mut f = enc.function(); f.params(func_ty.params.iter().map(|(name, ty)| (name.as_str(), *ty))); - - if let Some(ty) = func_ty.unnamed_result_ty() { - f.result(ty); - } else { - f.results( - func_ty - .results - .iter() - .map(|(name, ty)| (name.as_deref().unwrap(), *ty)), - ); - } + f.result(func_ty.unnamed_result_ty()); } Self::Component(comp_ty) => { let mut enc_comp_ty = wasm_encoder::ComponentType::new(); diff --git a/third_party/rust/wasm-smith/src/config.rs b/third_party/rust/wasm-smith/src/config.rs @@ -1,6 +1,7 @@ //! Configuring the shape of generated Wasm modules. use crate::InstructionKinds; +use anyhow::bail; use arbitrary::{Arbitrary, Result, Unstructured}; macro_rules! define_config { @@ -54,7 +55,7 @@ macro_rules! define_config { /// module. The implementation (e.g. function bodies, global /// initializers) of each export in the generated module will be /// random and unrelated to the implementation in the provided - /// module. Only globals and functions are supported. + /// module. /// /// /// Defaults to `None` which means arbitrary exports will be @@ -72,12 +73,13 @@ macro_rules! define_config { /// /// # Module Limits /// - /// All types, functions, globals, and exports that are needed to - /// provide the required exports will be generated, even if it - /// causes the resulting module to exceed the limits defined in - /// [`Self::max_type_size`], [`Self::max_types`], - /// [`Self::max_funcs`], [`Self::max_globals`], or - /// [`Self::max_exports`]. + /// All types, functions, globals, memories, tables, tags, and exports + /// that are needed to provide the required exports will be generated, + /// even if it causes the resulting module to exceed the limits defined + /// in [`Self::max_type_size`], [`Self::max_types`], + /// [`Self::max_funcs`], [`Self::max_globals`], + /// [`Self::max_memories`], [`Self::max_tables`], + /// [`Self::max_tags`], or [`Self::max_exports`]. /// /// # Example /// @@ -89,11 +91,55 @@ macro_rules! define_config { /// (module /// (func (export "foo") (param i32) (result i64) unreachable) /// (global (export "bar") f32 f32.const 0) + /// (memory (export "baz") 1 10) + /// (table (export "qux") 5 10 (ref null extern)) + /// (tag (export "quux") (param f32)) /// ) /// "#)); /// ``` pub exports: Option<Vec<u8>>, + /// If provided, the generated module will have imports and exports + /// with exactly the same names and types as those in the provided + /// WebAssembly module. + /// + /// Defaults to `None` which means arbitrary imports and exports will be + /// generated. + /// + /// Note that [`Self::available_imports`] and [`Self::exports`] are + /// ignored when `module_shape` is enabled. + /// + /// The provided value must be a valid binary encoding of a + /// WebAssembly module. `wasm-smith` will panic if the module cannot + /// be parsed. + /// + /// # Module Limits + /// + /// All types, functions, globals, memories, tables, tags, imports, and exports + /// that are needed to provide the required imports and exports will be generated, + /// even if it causes the resulting module to exceed the limits defined in + /// [`Self::max_type_size`], [`Self::max_types`], [`Self::max_funcs`], + /// [`Self::max_globals`], [`Self::max_memories`], [`Self::max_tables`], + /// [`Self::max_tags`], [`Self::max_imports`], or [`Self::max_exports`]. + /// + /// # Example + /// + /// As for [`Self::available_imports`] and [`Self::exports`], the + /// `wat` crate can be used to provide a human-readable description of the + /// module shape: + /// + /// ```rust + /// Some(wat::parse_str(r#" + /// (module + /// (import "env" "ping" (func (param i32))) + /// (import "env" "memory" (memory 1)) + /// (func (export "foo") (param anyref) (result structref) unreachable) + /// (global (export "bar") arrayref (ref.null array)) + /// ) + /// "#)); + /// ``` + pub module_shape: Option<Vec<u8>>, + $( $(#[$field_attr])* pub $field: $field_ty, @@ -105,6 +151,7 @@ macro_rules! define_config { Config { available_imports: None, exports: None, + module_shape: None, $( $field: $default, @@ -113,10 +160,11 @@ macro_rules! define_config { } } - #[cfg(feature = "_internal_cli")] #[doc(hidden)] - #[derive(Clone, Debug, Default, clap::Parser, serde_derive::Deserialize)] - #[serde(rename_all = "kebab-case", deny_unknown_fields)] + #[derive(Clone, Debug, Default)] + #[cfg_attr(feature = "clap", derive(clap::Parser))] + #[cfg_attr(feature = "serde", derive(serde_derive::Deserialize, serde_derive::Serialize))] + #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case", deny_unknown_fields))] pub struct InternalOptionalConfig { /// The imports that may be used when generating the module. /// @@ -139,7 +187,7 @@ macro_rules! define_config { /// module. The implementation (e.g. function bodies, global /// initializers) of each export in the generated module will be /// random and unrelated to the implementation in the provided - /// module. Only globals and functions are supported. + /// module. /// /// Defaults to `None` which means arbitrary exports will be /// generated. @@ -156,16 +204,42 @@ macro_rules! define_config { /// /// # Module Limits /// - /// All types, functions, globals, and exports that are needed to - /// provide the required exports will be generated, even if it - /// causes the resulting module to exceed the limits defined in - /// [`Self::max_type_size`], [`Self::max_types`], - /// [`Self::max_funcs`], [`Self::max_globals`], or - /// [`Self::max_exports`]. + /// All types, functions, globals, memories, tables, tags, and exports + /// that are needed to provide the required exports will be generated, + /// even if it causes the resulting module to exceed the limits defined + /// in [`Self::max_type_size`], [`Self::max_types`], + /// [`Self::max_funcs`], [`Self::max_globals`], + /// [`Self::max_memories`], [`Self::max_tables`], + /// [`Self::max_tags`], or [`Self::max_exports`]. /// #[cfg_attr(feature = "clap", clap(long))] exports: Option<std::path::PathBuf>, + /// If provided, the generated module will have imports and exports + /// with exactly the same names and types as those in the provided + /// WebAssembly module. + /// + /// Defaults to `None` which means arbitrary imports and exports will be + /// generated. + /// + /// Note that [`Self::available_imports`] and [`Self::exports`] are + /// ignored when `module_shape` is enabled. + /// + /// The provided value must be a valid binary encoding of a + /// WebAssembly module. `wasm-smith` will panic if the module cannot + /// be parsed. + /// + /// # Module Limits + /// + /// All types, functions, globals, memories, tables, tags, imports, and exports + /// that are needed to provide the required imports and exports will be generated, + /// even if it causes the resulting module to exceed the limits defined in + /// [`Self::max_type_size`], [`Self::max_types`], [`Self::max_funcs`], + /// [`Self::max_globals`], [`Self::max_memories`], [`Self::max_tables`], + /// [`Self::max_tags`], [`Self::max_imports`], or [`Self::max_exports`]. + #[cfg_attr(feature = "clap", clap(long))] + module_shape: Option<std::path::PathBuf>, + $( $(#[$field_attr])* #[cfg_attr(feature = "clap", clap(long))] @@ -173,12 +247,12 @@ macro_rules! define_config { )* } - #[cfg(feature = "_internal_cli")] impl InternalOptionalConfig { pub fn or(self, other: Self) -> Self { Self { available_imports: self.available_imports.or(other.available_imports), exports: self.exports.or(other.exports), + module_shape: self.module_shape.or(other.module_shape), $( $field: self.$field.or(other.$field), @@ -187,7 +261,7 @@ macro_rules! define_config { } } - #[cfg(feature = "_internal_cli")] + #[cfg(feature = "serde")] impl TryFrom<InternalOptionalConfig> for Config { type Error = anyhow::Error; fn try_from(config: InternalOptionalConfig) -> anyhow::Result<Config> { @@ -207,6 +281,13 @@ macro_rules! define_config { } else { None }, + module_shape: if let Some(file) = config + .module_shape + .as_ref() { + Some(wat::parse_file(file)?) + } else { + None + }, $( $field: config.$field.unwrap_or(default.$field), @@ -214,6 +295,27 @@ macro_rules! define_config { }) } } + + impl TryFrom<&Config> for InternalOptionalConfig { + type Error = anyhow::Error; + fn try_from(config: &Config) -> anyhow::Result<InternalOptionalConfig> { + if config.available_imports.is_some() { + bail!("cannot serialize configuration with `available_imports`"); + } + if config.exports.is_some() { + bail!("cannot serialize configuration with `exports`"); + } + if config.module_shape.is_some() { + bail!("cannot serialize configuration with `module_shape`"); + } + Ok(InternalOptionalConfig { + available_imports: None, + exports: None, + module_shape: None, + $( $field: Some(config.$field.clone()), )* + }) + } + } } } @@ -326,6 +428,12 @@ define_config! { /// Defaults to `true`. pub gc_enabled: bool = true, + /// Determines whether the custom descriptors proposal is enabled when + /// generating a Wasm module. + /// + /// Defaults to `true`. + pub custom_descriptors_enabled: bool = false, + /// Determines whether the custom-page-sizes proposal is enabled when /// generating a Wasm module. /// @@ -654,7 +762,10 @@ define_config! { /// /// The default is `(90, 9, 1)`. #[derive(Clone, Debug)] -#[cfg_attr(feature = "serde_derive", derive(serde_derive::Deserialize))] +#[cfg_attr( + feature = "serde", + derive(serde_derive::Deserialize, serde_derive::Serialize) +)] pub struct MemoryOffsetChoices(pub u32, pub u32, pub u32); impl Default for MemoryOffsetChoices { @@ -663,7 +774,6 @@ impl Default for MemoryOffsetChoices { } } -#[cfg(feature = "_internal_cli")] impl std::str::FromStr for MemoryOffsetChoices { type Err = String; fn from_str(s: &str) -> Result<Self, Self::Err> { @@ -763,6 +873,7 @@ impl<'a> Arbitrary<'a> for Config { canonicalize_nans: false, available_imports: None, exports: None, + module_shape: None, export_everything: false, generate_custom_sections: false, allow_invalid_funcs: false, @@ -771,6 +882,7 @@ impl<'a> Arbitrary<'a> for Config { custom_page_sizes_enabled: false, wide_arithmetic_enabled: false, shared_everything_threads_enabled: false, + custom_descriptors_enabled: false, }; config.sanitize(); Ok(config) @@ -803,6 +915,7 @@ impl Config { // also disable shared-everything-threads. if !self.gc_enabled { self.shared_everything_threads_enabled = false; + self.custom_descriptors_enabled = false; } // If simd is disabled then disable all relaxed simd instructions as @@ -816,6 +929,12 @@ impl Config { if !self.threads_enabled { self.shared_everything_threads_enabled = false; } + + // If module_shape is present then disable available_imports and exports. + if self.module_shape.is_some() { + self.available_imports = None; + self.exports = None; + } } /// Returns the set of features that are necessary for validating against @@ -861,7 +980,41 @@ impl Config { ); features.set(WasmFeatures::EXTENDED_CONST, self.extended_const_enabled); features.set(WasmFeatures::WIDE_ARITHMETIC, self.wide_arithmetic_enabled); + features.set( + WasmFeatures::CUSTOM_DESCRIPTORS, + self.custom_descriptors_enabled, + ); features } } + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for Config { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::de::Deserializer<'de>, + { + use serde::de::Error; + + match Config::try_from(InternalOptionalConfig::deserialize(deserializer)?) { + Ok(config) => Ok(config), + Err(e) => Err(D::Error::custom(e)), + } + } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for Config { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + use serde::ser::Error; + + match InternalOptionalConfig::try_from(self) { + Ok(result) => result.serialize(serializer), + Err(e) => Err(S::Error::custom(e)), + } + } +} diff --git a/third_party/rust/wasm-smith/src/core.rs b/third_party/rust/wasm-smith/src/core.rs @@ -4,10 +4,10 @@ mod code_builder; pub(crate) mod encode; mod terminate; -use crate::{arbitrary_loop, limited_string, unique_string, Config}; +use crate::{Config, arbitrary_loop, limited_string, unique_string}; use arbitrary::{Arbitrary, Result, Unstructured}; use code_builder::CodeBuilderAllocations; -use flagset::{flags, FlagSet}; +use flagset::{FlagSet, flags}; use std::collections::{HashMap, HashSet}; use std::fmt; use std::mem; @@ -260,6 +260,9 @@ pub(crate) struct SubType { pub(crate) is_final: bool, pub(crate) supertype: Option<u32>, pub(crate) composite_type: CompositeType, + /// How "deep" this subtype's supertype hierarchy is. The base case is 1 and + /// if `supertype` is present it's `1 + supertype.depth`. + depth: u32, } impl SubType { @@ -280,6 +283,8 @@ impl SubType { pub(crate) struct CompositeType { pub inner: CompositeInnerType, pub shared: bool, + pub descriptor: Option<u32>, + pub describes: Option<u32>, } impl CompositeType { @@ -288,6 +293,8 @@ impl CompositeType { Self { inner: CompositeInnerType::Func(func), shared, + descriptor: None, + describes: None, } } @@ -325,6 +332,8 @@ impl From<&CompositeType> for wasm_encoder::CompositeType { wasm_encoder::CompositeType { shared: ty.shared, inner, + descriptor: ty.descriptor, + describes: ty.describes, } } } @@ -438,15 +447,22 @@ impl Module { fn build(&mut self, u: &mut Unstructured) -> Result<()> { self.valtypes = configured_valtypes(&self.config); + let mut generate_arbitrary_imports = true; + let mut generate_arbitrary_exports = true; + if self.imports_exports_from_module_shape(u)? { + generate_arbitrary_imports = false; + generate_arbitrary_exports = false; + } // We attempt to figure out our available imports *before* creating the types section here, // because the types for the imports are already well-known (specified by the user) and we // must have those populated for all function/etc. imports, no matter what. // // This can affect the available capacity for types and such. if self.arbitrary_imports_from_available(u)? { - self.arbitrary_types(u)?; - } else { - self.arbitrary_types(u)?; + generate_arbitrary_imports = false; + } + self.arbitrary_types(u)?; + if generate_arbitrary_imports { self.arbitrary_imports(u)?; } @@ -457,9 +473,12 @@ impl Module { self.arbitrary_tables(u)?; self.arbitrary_memories(u)?; self.arbitrary_globals(u)?; - if !self.required_exports(u)? { + if self.required_exports(u)? { + generate_arbitrary_exports = false; + } + if generate_arbitrary_exports { self.arbitrary_exports(u)?; - }; + } self.should_encode_types = !self.types.is_empty() || u.arbitrary()?; self.arbitrary_start(u)?; self.arbitrary_elems(u)?; @@ -519,7 +538,8 @@ impl Module { } } - (HT::Concrete(a), HT::Abstract { shared, ty }) => { + (HT::Concrete(a), HT::Abstract { shared, ty }) + | (HT::Exact(a), HT::Abstract { shared, ty }) => { let a_ty = &self.ty(a).composite_type; if a_ty.shared != shared { return false; @@ -533,7 +553,8 @@ impl Module { } } - (HT::Abstract { shared, ty }, HT::Concrete(b)) => { + (HT::Abstract { shared, ty }, HT::Concrete(b)) + | (HT::Abstract { shared, ty }, HT::Exact(b)) => { let b_ty = &self.ty(b).composite_type; if shared != b_ty.shared { return false; @@ -545,7 +566,7 @@ impl Module { } } - (HT::Concrete(mut a), HT::Concrete(b)) => loop { + (HT::Concrete(mut a), HT::Concrete(b)) | (HT::Exact(mut a), HT::Concrete(b)) => loop { if a == b { return true; } @@ -555,6 +576,10 @@ impl Module { return false; } }, + + (HT::Concrete(a), HT::Exact(b)) | (HT::Exact(a), HT::Exact(b)) => { + return a == b; + } } } @@ -591,7 +616,15 @@ impl Module { }; list.push(index); - if !ty.is_final { + // Calculate the recursive depth of this type, and if it's beneath a + // threshold then allow future types to subtype this one. Otherwise this + // can no longer be subtyped so despite this not being final don't add + // it to the `can_subtype` list. + // + // Note that this limit is intentinally a bit less than the wasm-defined + // maximum of 63. + const MAX_SUBTYPING_DEPTH: u32 = 60; + if !ty.is_final && ty.depth < MAX_SUBTYPING_DEPTH { self.can_subtype.push(index); } @@ -677,11 +710,14 @@ impl Module { let composite_type = CompositeType { inner: CompositeInnerType::Func(func_type), shared, + descriptor: None, + describes: None, }; return Ok(SubType { is_final: true, supertype: None, composite_type, + depth: 1, }); } @@ -692,6 +728,7 @@ impl Module { is_final: u.arbitrary()?, supertype: None, composite_type: self.arbitrary_composite_type(u)?, + depth: 1, }) } } @@ -718,6 +755,7 @@ impl Module { is_final: u.arbitrary()?, supertype: Some(supertype), composite_type, + depth: 1 + self.types[supertype as usize].depth, }) } @@ -846,6 +884,12 @@ impl Module { if let Some(subs) = self.super_to_sub_types.get(&idx) { choices.extend(subs.iter().copied().map(HT::Concrete)); } + if self.config.custom_descriptors_enabled { + choices.push(HT::Exact(idx)); + if let Some(subs) = self.super_to_sub_types.get(&idx) { + choices.extend(subs.iter().copied().map(HT::Concrete)); + } + } match self .types .get(usize::try_from(idx).unwrap()) @@ -868,6 +912,7 @@ impl Module { } } } + HT::Exact(_) => (), } Ok(*u.choose(&choices)?) } @@ -1012,6 +1057,7 @@ impl Module { idx = supertype; } } + HT::Exact(_) => (), } Ok(*u.choose(&choices)?) } @@ -1024,6 +1070,8 @@ impl Module { return Ok(CompositeType { shared, inner: CT::Func(self.propagate_shared(shared, |m| m.arbitrary_func_type(u))?), + descriptor: None, + describes: None, }); } @@ -1033,14 +1081,20 @@ impl Module { inner: CT::Array(ArrayType( self.propagate_shared(shared, |m| m.arbitrary_field_type(u))?, )), + descriptor: None, + describes: None, }), 1 => Ok(CompositeType { shared, inner: CT::Func(self.propagate_shared(shared, |m| m.arbitrary_func_type(u))?), + descriptor: None, + describes: None, }), 2 => Ok(CompositeType { shared, inner: CT::Struct(self.propagate_shared(shared, |m| m.arbitrary_struct_type(u))?), + descriptor: None, // TODO generate descriptor info when custom_descriptors_enabled + describes: None, }), _ => unreachable!(), } @@ -1168,6 +1222,291 @@ impl Module { self.memories.len() < self.config.max_memories } + fn imports_exports_from_module_shape(&mut self, u: &mut Unstructured) -> Result<bool> { + let example_module = if let Some(wasm) = self.config.module_shape.clone() { + wasm + } else { + return Ok(false); + }; + + #[cfg(feature = "wasmparser")] + { + self._imports_exports_from_module_shape(u, &example_module)?; + Ok(true) + } + #[cfg(not(feature = "wasmparser"))] + { + let _ = (example_module, u); + panic!("support for `module_shape` was disabled at compile time"); + } + } + + #[cfg(feature = "wasmparser")] + fn _imports_exports_from_module_shape( + &mut self, + u: &mut Unstructured, + example_module: &[u8], + ) -> Result<()> { + // First, we validate the module-by-example and extract the required types, imports + // and exports. Besides, we also extract the functions, tags, tables, memories and + // globals that are necessary for generating the exports. + let mut available_funcs: Vec<u32> = Vec::new(); + let mut available_tags: Vec<wasmparser::TagType> = Vec::new(); + let mut available_tables: Vec<wasmparser::TableType> = Vec::new(); + let mut available_globals: Vec<wasmparser::GlobalType> = Vec::new(); + let mut available_memories: Vec<wasmparser::MemoryType> = Vec::new(); + + let mut required_types: Vec<SubType> = Vec::new(); + let mut required_recgrps: Vec<usize> = Vec::new(); + let mut required_imports: Vec<wasmparser::Import> = Vec::new(); + let mut required_exports: Vec<wasmparser::Export> = Vec::new(); + let mut validator = wasmparser::Validator::new(); + validator + .validate_all(example_module) + .expect("Failed to validate `module_shape` module"); + for payload in wasmparser::Parser::new(0).parse_all(&example_module) { + match payload.expect("could not parse the `module_shape` module") { + wasmparser::Payload::TypeSection(type_reader) => { + for recgrp in type_reader { + let recgrp = recgrp.expect("could not read recursive group"); + required_recgrps.push(recgrp.types().len()); + for subtype in recgrp.into_types() { + let mut subtype: SubType = subtype.try_into().unwrap(); + if let Some(supertype_idx) = subtype.supertype { + subtype.depth = required_types[supertype_idx as usize].depth + 1; + } + required_types.push(subtype); + } + } + } + wasmparser::Payload::ImportSection(import_reader) => { + for im in import_reader { + let im = im.expect("could not read import"); + required_imports.push(im); + } + } + wasmparser::Payload::ExportSection(export_reader) => { + for ex in export_reader { + let ex = ex.expect("could not read export"); + required_exports.push(ex); + } + } + wasmparser::Payload::FunctionSection(function_reader) => { + for func in function_reader { + let func = func.expect("could not read function"); + available_funcs.push(func); + } + } + wasmparser::Payload::TagSection(tag_reader) => { + for tag in tag_reader { + let tag = tag.expect("could not read tag"); + available_tags.push(tag); + } + } + wasmparser::Payload::TableSection(table_reader) => { + for table in table_reader { + let table = table.expect("could not read table"); + available_tables.push(table.ty); + } + } + wasmparser::Payload::MemorySection(memory_reader) => { + for memory in memory_reader { + let memory = memory.expect("could not read memory"); + available_memories.push(memory); + } + } + wasmparser::Payload::GlobalSection(global_reader) => { + for global in global_reader { + let global = global.expect("could not read global"); + available_globals.push(global.ty); + } + } + _ => {} + } + } + + // Next, we copy all the types from the module-by-example into current module. This is necessary + // to ensure that the current module has all the types it needs to type-check correctly. + let mut recgrp_start_idx = self.types.len(); + for size in required_recgrps { + self.rec_groups + .push(recgrp_start_idx..recgrp_start_idx + size); + recgrp_start_idx += size; + } + for ty in &required_types { + self.add_type(ty.clone()); + } + + // We then generate import entries which refer to the imported types. Additionally, we add the + // imported items to their corresponding vectors here, ensuring that exports reference the + // correct items. + let mut imported_funcs: Vec<u32> = Vec::new(); + let mut imported_tags: Vec<wasmparser::TagType> = Vec::new(); + let mut imported_tables: Vec<wasmparser::TableType> = Vec::new(); + let mut imported_globals: Vec<wasmparser::GlobalType> = Vec::new(); + let mut imported_memories: Vec<wasmparser::MemoryType> = Vec::new(); + let mut new_imports = Vec::with_capacity(required_imports.len()); + for import in required_imports { + let entity_type = match &import.ty { + wasmparser::TypeRef::Func(sig_idx) => { + imported_funcs.push(*sig_idx); + match required_types.get(*sig_idx as usize) { + None => panic!("signature index refers to a type out of bounds"), + Some(ty) => match &ty.composite_type.inner { + CompositeInnerType::Func(func_type) => { + let entity = EntityType::Func(*sig_idx, Rc::clone(func_type)); + self.funcs.push((*sig_idx, Rc::clone(func_type))); + entity + } + _ => panic!("a function type is required for function import"), + }, + } + } + + wasmparser::TypeRef::FuncExact(_) => panic!("Unexpected func_exact import"), + + wasmparser::TypeRef::Tag(wasmparser::TagType { + kind, + func_type_idx, + }) => { + imported_tags.push(wasmparser::TagType { + kind: *kind, + func_type_idx: *func_type_idx, + }); + match required_types.get(*func_type_idx as usize) { + None => { + panic!("function type index for tag refers to a type out of bounds") + } + Some(ty) => match &ty.composite_type.inner { + CompositeInnerType::Func(func_type) => { + let tag_type = TagType { + func_type_idx: *func_type_idx, + func_type: Rc::clone(func_type), + }; + let entity = EntityType::Tag(tag_type.clone()); + self.tags.push(tag_type); + entity + } + _ => panic!("a function type is required for tag import"), + }, + } + } + + wasmparser::TypeRef::Table(table_ty) => { + imported_tables.push(*table_ty); + let table_ty = TableType::try_from(*table_ty).unwrap(); + let entity = EntityType::Table(table_ty); + self.tables.push(table_ty); + entity + } + + wasmparser::TypeRef::Memory(memory_ty) => { + imported_memories.push(*memory_ty); + let memory_ty = MemoryType::from(*memory_ty); + let entity = EntityType::Memory(memory_ty); + self.memories.push(memory_ty); + entity + } + + wasmparser::TypeRef::Global(global_ty) => { + imported_globals.push(*global_ty); + let global_ty = GlobalType::try_from(*global_ty).unwrap(); + let entity = EntityType::Global(global_ty); + self.globals.push(global_ty); + entity + } + }; + new_imports.push(Import { + module: import.module.to_string(), + field: import.name.to_string(), + entity_type, + }); + self.num_imports += 1; + } + self.imports.extend(new_imports); + available_tags.splice(0..0, imported_tags); + available_funcs.splice(0..0, imported_funcs); + available_tables.splice(0..0, imported_tables); + available_globals.splice(0..0, imported_globals); + available_memories.splice(0..0, imported_memories); + + // Next, we generate export entries which refer to the export specifications. + for export in required_exports { + let index = match export.kind { + wasmparser::ExternalKind::Func | wasmparser::ExternalKind::FuncExact => { + match available_funcs.get(export.index as usize) { + None => panic!("function index out of bounds"), + Some(sig_idx) => match required_types.get(*sig_idx as usize) { + None => panic!("signature index refers to a type out of bounds"), + Some(ty) => match &ty.composite_type.inner { + CompositeInnerType::Func(func_type) => { + let func_index = self.funcs.len() as u32; + self.funcs.push((*sig_idx, Rc::clone(func_type))); + self.num_defined_funcs += 1; + func_index + } + _ => panic!("a function type is required for function export"), + }, + }, + } + } + + wasmparser::ExternalKind::Tag => match available_tags.get(export.index as usize) { + None => panic!("tag index out of bounds"), + Some(wasmparser::TagType { func_type_idx, .. }) => { + match required_types.get(*func_type_idx as usize) { + None => { + panic!("function type index for tag refers to a type out of bounds") + } + Some(ty) => match &ty.composite_type.inner { + CompositeInnerType::Func(func_type) => { + let tag_index = self.tags.len() as u32; + self.tags.push(TagType { + func_type_idx: *func_type_idx, + func_type: Rc::clone(func_type), + }); + self.num_defined_tags += 1; + tag_index + } + _ => panic!("a function type is required for tag export"), + }, + } + } + }, + + wasmparser::ExternalKind::Table => { + match available_tables.get(export.index as usize) { + None => panic!("table index out of bounds"), + Some(ty) => { + self.add_arbitrary_table_of_type((*ty).try_into().unwrap(), u)? + } + } + } + + wasmparser::ExternalKind::Memory => { + match available_memories.get(export.index as usize) { + None => panic!("memory index out of bounds"), + Some(ty) => self.add_arbitrary_memory_of_type((*ty).into())?, + } + } + + wasmparser::ExternalKind::Global => { + match available_globals.get(export.index as usize) { + None => panic!("global index out of bounds"), + Some(ty) => { + self.add_arbitrary_global_of_type((*ty).try_into().unwrap(), u)? + } + } + } + }; + self.exports + .push((export.name.to_string(), export.kind.into(), index)); + self.export_names.insert(export.name.to_string()); + } + + Ok(()) + } + fn arbitrary_imports(&mut self, u: &mut Unstructured) -> Result<()> { if self.config.max_type_size < self.type_size { return Ok(()); @@ -1296,18 +1635,29 @@ impl Module { // First, parse the module-by-example to collect the types and imports. // // `available_types` will map from a signature index (which is the same as the index into - // this vector) as it appears in the parsed code, to the type itself as well as to the - // index in our newly generated module. Initially the option is `None` and will become a - // `Some` when we encounter an import that uses this signature in the next portion of this - // function. See also the `make_func_type` closure below. - let mut available_types = Vec::new(); + // this vector) as it appears in the parsed code, to the type itself. We copy all the types + // from module-by-example into the module being constructed for the sake of simplicity + // and for this reason, [`Self::config::max_types`] may be surpassed. + let mut new_recgrps = Vec::<usize>::new(); + let mut available_types = Vec::<SubType>::new(); let mut available_imports = Vec::<wasmparser::Import>::new(); + let mut validator = wasmparser::Validator::new(); + validator + .validate_all(example_module) + .expect("Failed to validate `module_shape` module"); for payload in wasmparser::Parser::new(0).parse_all(&example_module) { match payload.expect("could not parse the available import payload") { wasmparser::Payload::TypeSection(type_reader) => { - for ty in type_reader.into_iter_err_on_gc_types() { - let ty = ty.expect("could not parse type section"); - available_types.push((ty, None)); + for recgrp in type_reader { + let recgrp = recgrp.expect("could not read recursive group"); + new_recgrps.push(recgrp.types().len()); + for subtype in recgrp.into_types() { + let mut subtype: SubType = subtype.try_into().unwrap(); + if let Some(supertype_idx) = subtype.supertype { + subtype.depth = available_types[supertype_idx as usize].depth + 1; + } + available_types.push(subtype); + } } } wasmparser::Payload::ImportSection(import_reader) => { @@ -1326,93 +1676,62 @@ impl Module { } } - // In this function we need to place imported function/tag types in the types section and - // generate import entries (which refer to said types) at the same time. - let max_types = self.config.max_types; - let multi_value_enabled = self.config.multi_value_enabled; + // We then generate import entries which refer to the imported types. Since this function + // is called at the very beginning of the module generation process and all types from the + // module-by-example are copied into the current module, no further adjustments are needed + // for type indices. let mut new_imports = Vec::with_capacity(available_imports.len()); - let first_type_index = self.types.len(); - let mut new_types = Vec::<SubType>::new(); - - // Returns the index to the translated type in the to-be type section, and the reference to - // the type itself. - let mut make_func_type = |module: &Self, parsed_sig_idx: u32| { - let serialized_sig_idx = match available_types.get_mut(parsed_sig_idx as usize) { - None => panic!("signature index refers to a type out of bounds"), - Some((_, Some(idx))) => *idx as usize, - Some((func_type, index_store)) => { - let multi_value_required = func_type.results().len() > 1; - let new_index = first_type_index + new_types.len(); - if new_index >= max_types || (multi_value_required && !multi_value_enabled) { - return None; - } - let func_type = Rc::new(FuncType { - params: func_type - .params() - .iter() - .map(|t| (*t).try_into().unwrap()) - .collect(), - results: func_type - .results() - .iter() - .map(|t| (*t).try_into().unwrap()) - .collect(), - }); - index_store.replace(new_index as u32); - let shared = module.arbitrary_shared(u).ok()?; - new_types.push(SubType { - is_final: true, - supertype: None, - composite_type: CompositeType::new_func(Rc::clone(&func_type), shared), - }); - new_index - } - }; - match &new_types[serialized_sig_idx - first_type_index] - .composite_type - .inner - { - CompositeInnerType::Func(f) => Some((serialized_sig_idx as u32, Rc::clone(f))), - _ => unimplemented!(), - } - }; - for import in available_imports { let type_size_budget = self.config.max_type_size - self.type_size; let entity_type = match &import.ty { wasmparser::TypeRef::Func(sig_idx) => { if self.funcs.len() >= self.config.max_funcs { continue; - } else if let Some((sig_idx, func_type)) = make_func_type(&self, *sig_idx) { - let entity = EntityType::Func(sig_idx as u32, Rc::clone(&func_type)); - if type_size_budget < entity.size() { - continue; - } - self.funcs.push((sig_idx, func_type)); - entity } else { - continue; + match available_types.get(*sig_idx as usize) { + None => panic!("signature index refers to a type out of bounds"), + Some(ty) => match &ty.composite_type.inner { + CompositeInnerType::Func(func_type) => { + let entity = EntityType::Func(*sig_idx, Rc::clone(func_type)); + if type_size_budget < entity.size() { + continue; + } + self.funcs.push((*sig_idx, Rc::clone(func_type))); + entity + } + _ => panic!("a function type is required for function import"), + }, + } } } + wasmparser::TypeRef::FuncExact(_) => panic!("Unexpected func_exact import"), + wasmparser::TypeRef::Tag(wasmparser::TagType { func_type_idx, .. }) => { let can_add_tag = self.tags.len() < self.config.max_tags; if !self.config.exceptions_enabled || !can_add_tag { continue; - } else if let Some((sig_idx, func_type)) = make_func_type(&self, *func_type_idx) - { - let tag_type = TagType { - func_type_idx: sig_idx, - func_type, - }; - let entity = EntityType::Tag(tag_type.clone()); - if type_size_budget < entity.size() { - continue; - } - self.tags.push(tag_type); - entity } else { - continue; + match available_types.get(*func_type_idx as usize) { + None => { + panic!("function type index for tag refers to a type out of bounds") + } + Some(ty) => match &ty.composite_type.inner { + CompositeInnerType::Func(func_type) => { + let tag_type = TagType { + func_type_idx: *func_type_idx, + func_type: Rc::clone(func_type), + }; + let entity = EntityType::Tag(tag_type.clone()); + if type_size_budget < entity.size() { + continue; + } + self.tags.push(tag_type); + entity + } + _ => panic!("a function type is required for tag import"), + }, + } } } @@ -1429,7 +1748,7 @@ impl Module { } wasmparser::TypeRef::Memory(memory_ty) => { - let memory_ty = MemoryType::try_from(*memory_ty).unwrap(); + let memory_ty = MemoryType::from(*memory_ty); let entity = EntityType::Memory(memory_ty); let type_size = entity.size(); if type_size_budget < type_size || !self.can_add_local_or_import_memory() { @@ -1441,7 +1760,7 @@ impl Module { } wasmparser::TypeRef::Global(global_ty) => { - let global_ty = (*global_ty).try_into().unwrap(); + let global_ty = GlobalType::try_from(*global_ty).unwrap(); let entity = EntityType::Global(global_ty); let type_size = entity.size(); if type_size_budget < type_size || !self.can_add_local_or_import_global() { @@ -1461,8 +1780,13 @@ impl Module { } // Finally, add the entities we just generated. - for ty in new_types { - self.rec_groups.push(self.types.len()..self.types.len() + 1); + let mut recgrp_start_idx = self.types.len(); + for size in new_recgrps { + self.rec_groups + .push(recgrp_start_idx..recgrp_start_idx + size); + recgrp_start_idx += size; + } + for ty in available_types { self.add_type(ty); } self.imports.extend(new_imports); @@ -1635,15 +1959,13 @@ impl Module { arbitrary_loop( u, self.config.min_tables as usize, - self.config.max_tables as usize, + self.config.max_tables, |u| { if !self.can_add_local_or_import_table() { return Ok(false); } let ty = arbitrary_table_type(u, self.config(), Some(self))?; - let init = self.arbitrary_table_init(u, ty.element_type)?; - self.defined_tables.push(init); - self.tables.push(ty); + self.add_arbitrary_table_of_type(ty, u)?; Ok(true) }, ) @@ -1668,7 +1990,9 @@ impl Module { if ty.nullable && u.arbitrary()? { return Ok(None); } - let expr = self.arbitrary_const_expr(ValType::Ref(ty), u)?; + // Only imported globals are allowed in the constant initialization + // expressions for tables. + let expr = self.arbitrary_const_expr(ValType::Ref(ty), u, false)?; Ok(Some(expr)) } @@ -1676,13 +2000,13 @@ impl Module { arbitrary_loop( u, self.config.min_memories as usize, - self.config.max_memories as usize, + self.config.max_memories, |u| { if !self.can_add_local_or_import_memory() { return Ok(false); } - self.num_defined_memories += 1; - self.memories.push(arbitrary_memtype(u, self.config())?); + let ty = arbitrary_memtype(u, self.config())?; + self.add_arbitrary_memory_of_type(ty)?; Ok(true) }, ) @@ -1694,22 +2018,44 @@ impl Module { ty: GlobalType, u: &mut Unstructured, ) -> Result<u32> { - let expr = self.arbitrary_const_expr(ty.val_type, u)?; + let expr = self.arbitrary_const_expr(ty.val_type, u, true)?; let global_idx = self.globals.len() as u32; self.globals.push(ty); self.defined_globals.push((global_idx, expr)); Ok(global_idx) } + /// Add a new memory of the given type and return its memory index. + fn add_arbitrary_memory_of_type(&mut self, ty: MemoryType) -> Result<u32> { + let memory_idx = self.memories.len() as u32; + self.num_defined_memories += 1; + self.memories.push(ty); + Ok(memory_idx) + } + + /// Add a new table of the given type and return its table index. + fn add_arbitrary_table_of_type(&mut self, ty: TableType, u: &mut Unstructured) -> Result<u32> { + let expr = self.arbitrary_table_init(u, ty.element_type)?; + let table_idx = self.tables.len() as u32; + self.tables.push(ty); + self.defined_tables.push(expr); + Ok(table_idx) + } + /// Generates an arbitrary constant expression of the type `ty`. - fn arbitrary_const_expr(&mut self, ty: ValType, u: &mut Unstructured) -> Result<ConstExpr> { + fn arbitrary_const_expr( + &mut self, + ty: ValType, + u: &mut Unstructured, + allow_defined_globals: bool, + ) -> Result<ConstExpr> { let mut choices = mem::take(&mut self.const_expr_choices); choices.clear(); // MVP wasm can `global.get` any immutable imported global in a // constant expression, and the GC proposal enables this for all // globals, so make all matching globals a candidate. - for i in self.globals_for_const_expr(ty) { + for i in self.globals_for_const_expr(ty, allow_defined_globals) { choices.push(Box::new(move |_, _| Ok(ConstExpr::global_get(i)))); } @@ -1730,8 +2076,12 @@ impl Module { choices.push(Box::new(arbitrary_extended_const)); } } - ValType::F32 => choices.push(Box::new(|u, _| Ok(ConstExpr::f32_const(u.arbitrary()?)))), - ValType::F64 => choices.push(Box::new(|u, _| Ok(ConstExpr::f64_const(u.arbitrary()?)))), + ValType::F32 => choices.push(Box::new(|u, _| { + Ok(ConstExpr::f32_const(u.arbitrary::<f32>()?.into())) + })), + ValType::F64 => choices.push(Box::new(|u, _| { + Ok(ConstExpr::f64_const(u.arbitrary::<f64>()?.into())) + })), ValType::V128 => { choices.push(Box::new(|u, _| Ok(ConstExpr::v128_const(u.arbitrary()?)))) } @@ -1901,80 +2251,95 @@ impl Module { // For each export, add necessary prerequisites to the module. let exports_types = exports_types.as_ref(); + let check_and_get_func_type = + |id: wasmparser::types::CoreTypeId| -> (Rc<FuncType>, SubType) { + let subtype = exports_types.get(id).unwrap_or_else(|| { + panic!("Unable to get subtype for {id:?} in `exports` Wasm") + }); + match &subtype.composite_type.inner { + wasmparser::CompositeInnerType::Func(func_type) => { + assert!( + subtype.is_final, + "Subtype {subtype:?} from `exports` Wasm is not final" + ); + assert!( + subtype.supertype_idx.is_none(), + "Subtype {subtype:?} from `exports` Wasm has non-empty supertype" + ); + let func_type = Rc::new(FuncType { + params: func_type + .params() + .iter() + .copied() + .map(|t| t.try_into().unwrap()) + .collect(), + results: func_type + .results() + .iter() + .copied() + .map(|t| t.try_into().unwrap()) + .collect(), + }); + let subtype = SubType { + is_final: true, + supertype: None, + depth: 1, + composite_type: CompositeType::new_func( + Rc::clone(&func_type), + subtype.composite_type.shared, + ), + }; + (func_type, subtype) + } + _ => panic!( + "Unable to handle type {:?} from `exports` Wasm", + subtype.composite_type + ), + } + }; for export in required_exports { let new_index = match exports_types .entity_type_from_export(&export) .unwrap_or_else(|| { - panic!( - "Unable to get type from export {:?} in `exports` Wasm", - export, - ) + panic!("Unable to get type from export {export:?} in `exports` Wasm",) }) { // For functions, add the type and a function with that type. wasmparser::types::EntityType::Func(id) => { - let subtype = exports_types.get(id).unwrap_or_else(|| { - panic!( - "Unable to get subtype for function {:?} in `exports` Wasm", - id - ) - }); - match &subtype.composite_type.inner { - wasmparser::CompositeInnerType::Func(func_type) => { - assert!( - subtype.is_final, - "Subtype {:?} from `exports` Wasm is not final", - subtype - ); - assert!( - subtype.supertype_idx.is_none(), - "Subtype {:?} from `exports` Wasm has non-empty supertype", - subtype - ); - let new_type = Rc::new(FuncType { - params: func_type - .params() - .iter() - .copied() - .map(|t| t.try_into().unwrap()) - .collect(), - results: func_type - .results() - .iter() - .copied() - .map(|t| t.try_into().unwrap()) - .collect(), - }); - self.rec_groups.push(self.types.len()..self.types.len() + 1); - let type_index = self.add_type(SubType { - is_final: true, - supertype: None, - composite_type: CompositeType::new_func( - Rc::clone(&new_type), - subtype.composite_type.shared, - ), - }); - let func_index = self.funcs.len() as u32; - self.funcs.push((type_index, new_type)); - self.num_defined_funcs += 1; - func_index - } - _ => panic!( - "Unable to handle type {:?} from `exports` Wasm", - subtype.composite_type - ), - } + let (func_type, subtype) = check_and_get_func_type(id); + self.rec_groups.push(self.types.len()..self.types.len() + 1); + let type_index = self.add_type(subtype); + let func_index = self.funcs.len() as u32; + self.funcs.push((type_index, func_type)); + self.num_defined_funcs += 1; + func_index } // For globals, add a new global. wasmparser::types::EntityType::Global(global_type) => { self.add_arbitrary_global_of_type(global_type.try_into().unwrap(), u)? } - wasmparser::types::EntityType::Table(_) - | wasmparser::types::EntityType::Memory(_) - | wasmparser::types::EntityType::Tag(_) => { - panic!( - "Config `exports` has an export of type {:?} which cannot yet be handled.", - export.kind - ) + // For memories, add a new memory. + wasmparser::types::EntityType::Memory(memory_type) => { + self.add_arbitrary_memory_of_type(memory_type.into())? + } + // For tables, add a new table. + wasmparser::types::EntityType::Table(table_type) => { + self.add_arbitrary_table_of_type(table_type.try_into().unwrap(), u)? + } + // For tags, add the type. + wasmparser::types::EntityType::Tag(id) => { + let (func_type, subtype) = check_and_get_func_type(id); + self.rec_groups.push(self.types.len()..self.types.len() + 1); + let type_index = self.add_type(subtype); + let tag_index = self.tags.len() as u32; + self.tags.push(TagType { + func_type_idx: type_index, + func_type: func_type, + }); + self.num_defined_tags += 1; + tag_index + } + wasmparser::types::EntityType::FuncExact(_) => { + panic!("Unexpected func_export: {export:?}",); } }; self.exports @@ -2069,7 +2434,7 @@ impl Module { return Ok(()); } - let mut choices = Vec::with_capacity(self.funcs.len() as usize); + let mut choices = Vec::with_capacity(self.funcs.len()); for (func_idx, ty) in self.funcs() { if ty.params.is_empty() && ty.results.is_empty() { @@ -2090,10 +2455,10 @@ impl Module { let mut global_i32 = vec![]; let mut global_i64 = vec![]; if !self.config.disallow_traps { - for i in self.globals_for_const_expr(ValType::I32) { + for i in self.globals_for_const_expr(ValType::I32, true) { global_i32.push(i); } - for i in self.globals_for_const_expr(ValType::I64) { + for i in self.globals_for_const_expr(ValType::I64, true) { global_i64.push(i); } } @@ -2252,7 +2617,7 @@ impl Module { } else { let mut init = vec![]; arbitrary_loop(u, self.config.min_elements, max, |u| { - init.push(self.arbitrary_const_expr(ValType::Ref(ty), u)?); + init.push(self.arbitrary_const_expr(ValType::Ref(ty), u, true)?); Ok(true) })?; Elements::Expressions(init) @@ -2268,7 +2633,10 @@ impl Module { self.compute_interesting_values(); self.code.reserve(self.num_defined_funcs); - let mut allocs = CodeBuilderAllocations::new(self, self.config.exports.is_some()); + let mut allocs = CodeBuilderAllocations::new( + self, + self.config.exports.is_some() || self.config.module_shape.is_some(), + ); for (idx, ty) in self.funcs[self.funcs.len() - self.num_defined_funcs..].iter() { let shared = self.is_shared_type(*idx); let body = self.arbitrary_func_body(u, ty, &mut allocs, shared)?; @@ -2337,10 +2705,10 @@ impl Module { )) })); if !self.config.disallow_traps { - for i in self.globals_for_const_expr(ValType::I32) { + for i in self.globals_for_const_expr(ValType::I32, true) { choices32.push(Box::new(move |_, _, _| Ok(Offset::Global(i)))); } - for i in self.globals_for_const_expr(ValType::I64) { + for i in self.globals_for_const_expr(ValType::I64, true) { choices64.push(Box::new(move |_, _, _| Ok(Offset::Global(i)))); } } @@ -2430,11 +2798,15 @@ impl Module { /// Returns an iterator of all globals which can be used in constant /// expressions for a value of type `ty` specified. - fn globals_for_const_expr(&self, ty: ValType) -> impl Iterator<Item = u32> + '_ { + fn globals_for_const_expr( + &self, + ty: ValType, + allow_defined_globals: bool, + ) -> impl Iterator<Item = u32> + '_ { // Before the GC proposal only imported globals could be referenced, but // the GC proposal relaxed this feature to allow any global. let num_imported_globals = self.globals.len() - self.defined_globals.len(); - let max_global = if self.config.gc_enabled { + let max_global = if self.config.gc_enabled && allow_defined_globals { self.globals.len() } else { num_imported_globals @@ -2596,14 +2968,14 @@ impl Module { u.arbitrary()? })), ValType::F32 => Ok(Instruction::F32Const(if u.arbitrary()? { - f32::from_bits(*u.choose(&self.interesting_values32)?) + f32::from_bits(*u.choose(&self.interesting_values32)?).into() } else { - u.arbitrary()? + u.arbitrary::<f32>()?.into() })), ValType::F64 => Ok(Instruction::F64Const(if u.arbitrary()? { - f64::from_bits(*u.choose(&self.interesting_values64)?) + f64::from_bits(*u.choose(&self.interesting_values64)?).into() } else { - u.arbitrary()? + u.arbitrary::<f64>()?.into() })), ValType::V128 => Ok(Instruction::V128Const(if u.arbitrary()? { let upper = (*u.choose(&self.interesting_values64)? as i128) << 64; @@ -2637,7 +3009,9 @@ impl Module { fn is_shared_ref_type(&self, ty: RefType) -> bool { match ty.heap_type { HeapType::Abstract { shared, .. } => shared, - HeapType::Concrete(i) => self.types[i as usize].composite_type.shared, + HeapType::Concrete(i) | HeapType::Exact(i) => { + self.types[i as usize].composite_type.shared + } } } @@ -2783,7 +3157,7 @@ pub(crate) fn arbitrary_memtype(u: &mut Unstructured, config: &Config) -> Result // Can only fail when we have a custom page size of 1 byte and a // memory size of `2**64 == u64::MAX + 1`. In this case, just // saturate to `u64::MAX`. - .unwrap_or(u64::MAX as u64) + .unwrap_or(u64::MAX) } else { u32::try_from(config.max_memory32_bytes >> page_size_log2.unwrap_or(16)) // Similar case as above, but while we could represent `2**32` in our @@ -2930,18 +3304,18 @@ fn gradually_grow(u: &mut Unstructured, min: u64, max_inbounds: u64, max: u64) - ) -> f64 { assert!(!value.is_nan(), "{}", value); assert!(value.is_finite(), "{}", value); - assert!(in_low < in_high, "{} < {}", in_low, in_high); - assert!(out_low < out_high, "{} < {}", out_low, out_high); - assert!(value >= in_low, "{} >= {}", value, in_low); - assert!(value <= in_high, "{} <= {}", value, in_high); + assert!(in_low < in_high, "{in_low} < {in_high}"); + assert!(out_low < out_high, "{out_low} < {out_high}"); + assert!(value >= in_low, "{value} >= {in_low}"); + assert!(value <= in_high, "{value} <= {in_high}"); let dividend = out_high - out_low; let divisor = in_high - in_low; let slope = dividend / divisor; let result = out_low + (slope * (value - in_low)); - assert!(result >= out_low, "{} >= {}", result, out_low); - assert!(result <= out_high, "{} <= {}", result, out_high); + assert!(result >= out_low, "{result} >= {out_low}"); + assert!(result <= out_high, "{result} <= {out_high}"); result } } @@ -3000,7 +3374,10 @@ impl EntityType { /// assert!(kinds.contains(InstructionKind::Memory)); /// ``` #[derive(Clone, Copy, Debug, Default)] -#[cfg_attr(feature = "serde_derive", derive(serde_derive::Deserialize))] +#[cfg_attr( + feature = "serde", + derive(serde_derive::Deserialize, serde_derive::Serialize) +)] pub struct InstructionKinds(pub(crate) FlagSet<InstructionKind>); impl InstructionKinds { @@ -3092,7 +3469,85 @@ impl FromStr for InstructionKind { "memory_non_float" => Ok(InstructionKind::MemoryInt), "memory" => Ok(InstructionKind::Memory), "control" => Ok(InstructionKind::Control), - _ => Err(format!("unknown instruction kind: {}", s)), + _ => Err(format!("unknown instruction kind: {s}")), } } } + +// Conversions from `wasmparser` to `wasm-smith`. Currently, only type conversions +// have been implemented. +#[cfg(feature = "wasmparser")] +impl TryFrom<wasmparser::FuncType> for FuncType { + type Error = (); + + fn try_from(value: wasmparser::FuncType) -> Result<Self, Self::Error> { + Ok(FuncType { + params: value + .params() + .iter() + .copied() + .map(|ty| ty.try_into().map_err(|_| ())) + .collect::<Result<Vec<_>, _>>()?, + results: value + .results() + .iter() + .copied() + .map(|ty| ty.try_into().map_err(|_| ())) + .collect::<Result<Vec<_>, _>>()?, + }) + } +} + +#[cfg(feature = "wasmparser")] +impl TryFrom<wasmparser::CompositeType> for CompositeType { + type Error = (); + + fn try_from(value: wasmparser::CompositeType) -> Result<Self, Self::Error> { + let inner_type = match value.inner { + wasmparser::CompositeInnerType::Func(func_type) => { + CompositeInnerType::Func(Rc::new(func_type.try_into()?)) + } + wasmparser::CompositeInnerType::Array(array_type) => { + CompositeInnerType::Array(array_type.try_into().map_err(|_| ())?) + } + wasmparser::CompositeInnerType::Struct(struct_type) => { + CompositeInnerType::Struct(struct_type.try_into().map_err(|_| ())?) + } + wasmparser::CompositeInnerType::Cont(_) => { + panic!("continuation type is not supported by wasm-smith currently.") + } + }; + + Ok(CompositeType { + inner: inner_type, + shared: value.shared, + descriptor: value + .descriptor_idx + .map(|idx| idx.as_module_index().ok_or(())) + .transpose()?, + describes: value + .describes_idx + .map(|idx| idx.as_module_index().ok_or(())) + .transpose()?, + }) + } +} + +#[cfg(feature = "wasmparser")] +impl TryFrom<wasmparser::SubType> for SubType { + type Error = (); + + fn try_from(value: wasmparser::SubType) -> Result<Self, Self::Error> { + Ok(SubType { + is_final: value.is_final, + supertype: value + .supertype_idx + .map(|idx| idx.as_module_index().ok_or(())) + .transpose()?, + composite_type: value.composite_type.try_into()?, + // We cannot determine the depth of current subtype here, set it to 1 + // temporarily and fix it later. + depth: 1, + }) + } +} diff --git a/third_party/rust/wasm-smith/src/core/code_builder.rs b/third_party/rust/wasm-smith/src/core/code_builder.rs @@ -2,7 +2,7 @@ use super::{ CompositeInnerType, Elements, FuncType, Instruction, InstructionKind::*, InstructionKinds, Module, ValType, }; -use crate::{unique_string, MemoryOffsetChoices}; +use crate::{MemoryOffsetChoices, unique_string}; use arbitrary::{Result, Unstructured}; use std::collections::{BTreeMap, BTreeSet}; use std::rc::Rc; @@ -594,6 +594,74 @@ instructions! { (Some(wide_arithmetic_binop128_on_stack), i64_sub128, NumericInt), (Some(wide_arithmetic_mul_wide_on_stack), i64_mul_wide_s, NumericInt), (Some(wide_arithmetic_mul_wide_on_stack), i64_mul_wide_u, NumericInt), + // Atomic instructions + (Some(atomic_load_valid), i32_atomic_load, MemoryInt), + (Some(atomic_load_valid), i64_atomic_load, MemoryInt), + (Some(atomic_load_valid), i32_atomic_load8_u,MemoryInt), + (Some(atomic_load_valid), i64_atomic_load8_u, MemoryInt), + (Some(atomic_load_valid), i32_atomic_load16_u, MemoryInt), + (Some(atomic_load_valid), i64_atomic_load16_u, MemoryInt), + (Some(atomic_load_valid), i64_atomic_load32_u, MemoryInt), + (Some(i32_atomic_store_valid), i32_atomic_store, MemoryInt), + (Some(i64_atomic_store_valid), i64_atomic_store, MemoryInt), + (Some(i32_atomic_store_valid), i32_atomic_store8, MemoryInt), + (Some(i64_atomic_store_valid), i64_atomic_store8, MemoryInt), + (Some(i32_atomic_store_valid), i32_atomic_store16, MemoryInt), + (Some(i64_atomic_store_valid), i64_atomic_store16, MemoryInt), + (Some(i64_atomic_store_valid), i64_atomic_store32, MemoryInt), + (Some(i32_atomic_rmw_atop_valid), i32_atomic_rmw_add, MemoryInt), + (Some(i32_atomic_rmw_atop_valid), i32_atomic_rmw_sub, MemoryInt), + (Some(i32_atomic_rmw_atop_valid), i32_atomic_rmw_and, MemoryInt), + (Some(i32_atomic_rmw_atop_valid), i32_atomic_rmw_or, MemoryInt), + (Some(i32_atomic_rmw_atop_valid), i32_atomic_rmw_xor, MemoryInt), + (Some(i32_atomic_rmw_atop_valid), i32_atomic_rmw_xchg, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw_add, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw_sub, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw_and, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw_or, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw_xor, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw_xchg, MemoryInt), + (Some(i32_atomic_rmw_atop_valid), i32_atomic_rmw8_add_u, MemoryInt), + (Some(i32_atomic_rmw_atop_valid), i32_atomic_rmw8_sub_u, MemoryInt), + (Some(i32_atomic_rmw_atop_valid), i32_atomic_rmw8_and_u, MemoryInt), + (Some(i32_atomic_rmw_atop_valid), i32_atomic_rmw8_or_u, MemoryInt), + (Some(i32_atomic_rmw_atop_valid), i32_atomic_rmw8_xor_u, MemoryInt), + (Some(i32_atomic_rmw_atop_valid), i32_atomic_rmw8_xchg_u, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw8_add_u, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw8_sub_u, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw8_and_u, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw8_or_u, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw8_xor_u, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw8_xchg_u, MemoryInt), + (Some(i32_atomic_rmw_atop_valid), i32_atomic_rmw16_add_u, MemoryInt), + (Some(i32_atomic_rmw_atop_valid), i32_atomic_rmw16_sub_u, MemoryInt), + (Some(i32_atomic_rmw_atop_valid), i32_atomic_rmw16_and_u, MemoryInt), + (Some(i32_atomic_rmw_atop_valid), i32_atomic_rmw16_or_u, MemoryInt), + (Some(i32_atomic_rmw_atop_valid), i32_atomic_rmw16_xor_u, MemoryInt), + (Some(i32_atomic_rmw_atop_valid), i32_atomic_rmw16_xchg_u, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw16_add_u, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw16_sub_u, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw16_and_u, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw16_or_u, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw16_xor_u, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw16_xchg_u, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw32_add_u, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw32_sub_u, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw32_and_u, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw32_or_u, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw32_xor_u, MemoryInt), + (Some(i64_atomic_rmw_atop_valid), i64_atomic_rmw32_xchg_u, MemoryInt), + (Some(i32_atomic_rmw_cmpxchg_valid), i32_atomic_rmw_cmpxchg, MemoryInt), + (Some(i64_atomic_rmw_cmpxchg_valid), i64_atomic_rmw_cmpxchg, MemoryInt), + (Some(i32_atomic_rmw_cmpxchg_valid), i32_atomic_rmw8_cmpxchg_u, MemoryInt), + (Some(i64_atomic_rmw_cmpxchg_valid), i64_atomic_rmw8_cmpxchg_u, MemoryInt), + (Some(i32_atomic_rmw_cmpxchg_valid), i32_atomic_rmw16_cmpxchg_u, MemoryInt), + (Some(i64_atomic_rmw_cmpxchg_valid), i64_atomic_rmw16_cmpxchg_u, MemoryInt), + (Some(i64_atomic_rmw_cmpxchg_valid), i64_atomic_rmw32_cmpxchg_u, MemoryInt), + (Some(atomic_notify_valid), atomic_notify, MemoryInt), + (Some(atomic_wait32_valid), atomic_wait32, MemoryInt), + (Some(atomic_wait64_valid), atomic_wait64, MemoryInt), + (Some(atomic_instruction_valid), atomic_fence, MemoryInt), } pub(crate) struct CodeBuilderAllocations { @@ -1233,7 +1301,7 @@ impl CodeBuilder<'_> { if module.config.multi_value_enabled { for (i, ty) in module.func_types() { if self.types_on_stack(module, &ty.params) { - options.push(Box::new(move |_| Ok(BlockType::FunctionType(i as u32)))); + options.push(Box::new(move |_| Ok(BlockType::FunctionType(i)))); } } } @@ -1379,8 +1447,8 @@ impl CodeBuilder<'_> { const CANON_64BIT_NAN: u64 = 0b0111111111111000000000000000000000000000000000000000000000000000; ins.push(match ty { - Float::F32 => Instruction::F32Const(f32::from_bits(CANON_32BIT_NAN)), - Float::F64 => Instruction::F64Const(f64::from_bits(CANON_64BIT_NAN)), + Float::F32 => Instruction::F32Const(f32::from_bits(CANON_32BIT_NAN).into()), + Float::F64 => Instruction::F64Const(f64::from_bits(CANON_64BIT_NAN).into()), Float::F32x4 => { let nan = CANON_32BIT_NAN as i128; let nan = nan | (nan << 32) | (nan << 64) | (nan << 96); @@ -1729,7 +1797,7 @@ fn try_table( let mut catches = Vec::new(); if catch_options.len() > 0 { for _ in 0..u.int_in_range(0..=10)? { - catches.push(u.choose(&mut catch_options)?(u, builder)?); + catches.push(u.choose(&catch_options)?(u, builder)?); } } @@ -2004,7 +2072,7 @@ fn call( let (func_idx, ty) = module.funcs().nth(candidates[i] as usize).unwrap(); builder.pop_operands(module, &ty.params); builder.push_operands(&ty.results); - instructions.push(Instruction::Call(func_idx as u32)); + instructions.push(Instruction::Call(func_idx)); Ok(()) } @@ -2105,7 +2173,7 @@ fn call_indirect( builder.pop_operands(module, &ty.params); builder.push_operands(&ty.results); instructions.push(Instruction::CallIndirect { - type_index: *type_idx as u32, + type_index: { *type_idx }, table_index: table, }); Ok(()) @@ -2159,7 +2227,7 @@ fn return_call( let (func_idx, ty) = module.funcs().nth(candidates[i] as usize).unwrap(); builder.pop_operands(module, &ty.params); builder.push_operands(&ty.results); - instructions.push(Instruction::ReturnCall(func_idx as u32)); + instructions.push(Instruction::ReturnCall(func_idx)); Ok(()) } @@ -2242,7 +2310,7 @@ fn return_call_indirect( builder.pop_operands(module, &ty.params); builder.push_operands(&ty.results); instructions.push(Instruction::ReturnCallIndirect { - type_index: *type_idx as u32, + type_index: { *type_idx }, table_index: table, }); Ok(()) @@ -2277,7 +2345,7 @@ fn throw( // Tags have no results, throwing cannot return assert!(tag_type.func_type.results.len() == 0); builder.pop_operands(module, &tag_type.func_type.params); - instructions.push(Instruction::Throw(tag_idx as u32)); + instructions.push(Instruction::Throw(tag_idx)); Ok(()) } @@ -5685,7 +5753,7 @@ fn table_get( let idx = *u.choose(candidates)?; let ty = module.tables[idx as usize].element_type; builder.push_operands(&[ty.into()]); - instructions.push(Instruction::TableGet(idx as u32)); + instructions.push(Instruction::TableGet(idx)); Ok(()) } @@ -7333,3 +7401,260 @@ fn i64_mul_wide_u( instructions.push(Instruction::I64MulWideU); Ok(()) } + +#[inline] +fn atomic_instruction_valid(module: &Module, _builder: &mut CodeBuilder) -> bool { + module.config.threads_enabled +} + +#[inline] +fn atomic_load_valid(module: &Module, builder: &mut CodeBuilder) -> bool { + atomic_instruction_valid(module, builder) && have_memory_and_offset(module, builder) +} + +#[inline] +fn i32_atomic_store_valid(module: &Module, builder: &mut CodeBuilder) -> bool { + atomic_instruction_valid(module, builder) && i32_store_valid(module, builder) +} + +#[inline] +fn i64_atomic_store_valid(module: &Module, builder: &mut CodeBuilder) -> bool { + atomic_instruction_valid(module, builder) && i64_store_valid(module, builder) +} + +#[inline] +fn atomic_stack_op_valid( + module: &Module, + builder: &mut CodeBuilder, + stack_types: &[ValType], +) -> bool { + atomic_instruction_valid(module, builder) + && builder.types_on_stack(module, stack_types) + && ((builder.allocs.memory32.len() > 0 + && builder.type_on_stack_at(module, stack_types.len(), ValType::I32)) + || (builder.allocs.memory64.len() > 0 + && builder.type_on_stack_at(module, stack_types.len(), ValType::I64))) +} + +#[inline] +fn i32_atomic_rmw_atop_valid(module: &Module, builder: &mut CodeBuilder) -> bool { + atomic_stack_op_valid(module, builder, &[ValType::I32]) +} + +#[inline] +fn i64_atomic_rmw_atop_valid(module: &Module, builder: &mut CodeBuilder) -> bool { + atomic_stack_op_valid(module, builder, &[ValType::I64]) +} + +#[inline] +fn i32_atomic_rmw_cmpxchg_valid(module: &Module, builder: &mut CodeBuilder) -> bool { + atomic_stack_op_valid(module, builder, &[ValType::I32, ValType::I32]) +} + +#[inline] +fn i64_atomic_rmw_cmpxchg_valid(module: &Module, builder: &mut CodeBuilder) -> bool { + atomic_stack_op_valid(module, builder, &[ValType::I64, ValType::I64]) +} + +#[inline] +fn atomic_notify_valid(module: &Module, builder: &mut CodeBuilder) -> bool { + atomic_stack_op_valid(module, builder, &[ValType::I32]) +} + +#[inline] +fn atomic_wait32_valid(module: &Module, builder: &mut CodeBuilder) -> bool { + atomic_stack_op_valid(module, builder, &[ValType::I32, ValType::I64]) +} + +#[inline] +fn atomic_wait64_valid(module: &Module, builder: &mut CodeBuilder) -> bool { + atomic_stack_op_valid(module, builder, &[ValType::I64, ValType::I64]) +} + +macro_rules! atomic_load { + ($instr:ident, $valtype:ident, $fn_name:ident, [$($memarg_align:expr),*]) => { + fn $fn_name( + u: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec<Instruction>, + ) -> Result<()> { + let memarg = mem_arg(u, module, builder, &[$($memarg_align),*])?; + builder.push_operands(&[ValType::$valtype]); + instructions.push(Instruction::$instr(memarg)); + Ok(()) + } + }; +} + +macro_rules! atomic_store { + ($instr:ident, $valtype:ident, $fn_name:ident, [$($memarg_align:expr),*]) => { + fn $fn_name( + u: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec<Instruction>, + ) -> Result<()> { + builder.pop_operands(module, &[ValType::$valtype]); + let memarg = mem_arg(u, module, builder, &[$($memarg_align),*])?; + instructions.push(Instruction::$instr(memarg)); + Ok(()) + } + }; +} + +macro_rules! atomic_rmw_atop { + ($valtype:ident, $instr:ident, $fn_name:ident, [$($memarg_align:expr),*]) => { + fn $fn_name( + u: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec<Instruction>, + ) -> Result<()> { + builder.pop_operands(module, &[ValType::$valtype]); + let memarg = mem_arg(u, module, builder, &[$($memarg_align),*])?; + builder.push_operands(&[ValType::$valtype]); + instructions.push(Instruction::$instr(memarg)); + Ok(()) + } + }; +} + +macro_rules! atomic_rmw_cmpxchg { + ($valtype:ident, $instr:ident, $fn_name:ident, [$($memarg_align:expr),*]) => { + fn $fn_name( + u: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec<Instruction>, + ) -> Result<()> { + builder.pop_operands(module, &[ValType::$valtype, ValType::$valtype]); + let memarg = mem_arg(u, module, builder, &[$($memarg_align),*])?; + builder.push_operands(&[ValType::$valtype]); + instructions.push(Instruction::$instr(memarg)); + Ok(()) + } + }; +} + +atomic_load!(I32AtomicLoad, I32, i32_atomic_load, [2]); +atomic_load!(I64AtomicLoad, I64, i64_atomic_load, [3]); +atomic_load!(I32AtomicLoad8U, I32, i32_atomic_load8_u, [0]); +atomic_load!(I64AtomicLoad8U, I64, i64_atomic_load8_u, [0]); +atomic_load!(I32AtomicLoad16U, I32, i32_atomic_load16_u, [1]); +atomic_load!(I64AtomicLoad16U, I64, i64_atomic_load16_u, [1]); +atomic_load!(I64AtomicLoad32U, I64, i64_atomic_load32_u, [2]); + +atomic_store!(I32AtomicStore, I32, i32_atomic_store, [2]); +atomic_store!(I64AtomicStore, I64, i64_atomic_store, [3]); +atomic_store!(I32AtomicStore8, I32, i32_atomic_store8, [0]); +atomic_store!(I64AtomicStore8, I64, i64_atomic_store8, [0]); +atomic_store!(I32AtomicStore16, I32, i32_atomic_store16, [1]); +atomic_store!(I64AtomicStore16, I64, i64_atomic_store16, [1]); +atomic_store!(I64AtomicStore32, I64, i64_atomic_store32, [2]); + +atomic_rmw_atop!(I32, I32AtomicRmwAdd, i32_atomic_rmw_add, [2]); +atomic_rmw_atop!(I32, I32AtomicRmwSub, i32_atomic_rmw_sub, [2]); +atomic_rmw_atop!(I32, I32AtomicRmwAnd, i32_atomic_rmw_and, [2]); +atomic_rmw_atop!(I32, I32AtomicRmwOr, i32_atomic_rmw_or, [2]); +atomic_rmw_atop!(I32, I32AtomicRmwXor, i32_atomic_rmw_xor, [2]); +atomic_rmw_atop!(I32, I32AtomicRmwXchg, i32_atomic_rmw_xchg, [2]); + +atomic_rmw_atop!(I64, I64AtomicRmwAdd, i64_atomic_rmw_add, [3]); +atomic_rmw_atop!(I64, I64AtomicRmwSub, i64_atomic_rmw_sub, [3]); +atomic_rmw_atop!(I64, I64AtomicRmwAnd, i64_atomic_rmw_and, [3]); +atomic_rmw_atop!(I64, I64AtomicRmwOr, i64_atomic_rmw_or, [3]); +atomic_rmw_atop!(I64, I64AtomicRmwXor, i64_atomic_rmw_xor, [3]); +atomic_rmw_atop!(I64, I64AtomicRmwXchg, i64_atomic_rmw_xchg, [3]); + +atomic_rmw_atop!(I32, I32AtomicRmw8AddU, i32_atomic_rmw8_add_u, [0]); +atomic_rmw_atop!(I32, I32AtomicRmw8SubU, i32_atomic_rmw8_sub_u, [0]); +atomic_rmw_atop!(I32, I32AtomicRmw8AndU, i32_atomic_rmw8_and_u, [0]); +atomic_rmw_atop!(I32, I32AtomicRmw8OrU, i32_atomic_rmw8_or_u, [0]); +atomic_rmw_atop!(I32, I32AtomicRmw8XorU, i32_atomic_rmw8_xor_u, [0]); +atomic_rmw_atop!(I32, I32AtomicRmw8XchgU, i32_atomic_rmw8_xchg_u, [0]); + +atomic_rmw_atop!(I64, I64AtomicRmw8AddU, i64_atomic_rmw8_add_u, [0]); +atomic_rmw_atop!(I64, I64AtomicRmw8SubU, i64_atomic_rmw8_sub_u, [0]); +atomic_rmw_atop!(I64, I64AtomicRmw8AndU, i64_atomic_rmw8_and_u, [0]); +atomic_rmw_atop!(I64, I64AtomicRmw8OrU, i64_atomic_rmw8_or_u, [0]); +atomic_rmw_atop!(I64, I64AtomicRmw8XorU, i64_atomic_rmw8_xor_u, [0]); +atomic_rmw_atop!(I64, I64AtomicRmw8XchgU, i64_atomic_rmw8_xchg_u, [0]); + +atomic_rmw_atop!(I32, I32AtomicRmw16AddU, i32_atomic_rmw16_add_u, [1]); +atomic_rmw_atop!(I32, I32AtomicRmw16SubU, i32_atomic_rmw16_sub_u, [1]); +atomic_rmw_atop!(I32, I32AtomicRmw16AndU, i32_atomic_rmw16_and_u, [1]); +atomic_rmw_atop!(I32, I32AtomicRmw16OrU, i32_atomic_rmw16_or_u, [1]); +atomic_rmw_atop!(I32, I32AtomicRmw16XorU, i32_atomic_rmw16_xor_u, [1]); +atomic_rmw_atop!(I32, I32AtomicRmw16XchgU, i32_atomic_rmw16_xchg_u, [1]); + +atomic_rmw_atop!(I64, I64AtomicRmw16AddU, i64_atomic_rmw16_add_u, [1]); +atomic_rmw_atop!(I64, I64AtomicRmw16SubU, i64_atomic_rmw16_sub_u, [1]); +atomic_rmw_atop!(I64, I64AtomicRmw16AndU, i64_atomic_rmw16_and_u, [1]); +atomic_rmw_atop!(I64, I64AtomicRmw16OrU, i64_atomic_rmw16_or_u, [1]); +atomic_rmw_atop!(I64, I64AtomicRmw16XorU, i64_atomic_rmw16_xor_u, [1]); +atomic_rmw_atop!(I64, I64AtomicRmw16XchgU, i64_atomic_rmw16_xchg_u, [1]); + +atomic_rmw_atop!(I64, I64AtomicRmw32AddU, i64_atomic_rmw32_add_u, [2]); +atomic_rmw_atop!(I64, I64AtomicRmw32SubU, i64_atomic_rmw32_sub_u, [2]); +atomic_rmw_atop!(I64, I64AtomicRmw32AndU, i64_atomic_rmw32_and_u, [2]); +atomic_rmw_atop!(I64, I64AtomicRmw32OrU, i64_atomic_rmw32_or_u, [2]); +atomic_rmw_atop!(I64, I64AtomicRmw32XorU, i64_atomic_rmw32_xor_u, [2]); +atomic_rmw_atop!(I64, I64AtomicRmw32XchgU, i64_atomic_rmw32_xchg_u, [2]); + +atomic_rmw_cmpxchg!(I32, I32AtomicRmwCmpxchg, i32_atomic_rmw_cmpxchg, [2]); +atomic_rmw_cmpxchg!(I64, I64AtomicRmwCmpxchg, i64_atomic_rmw_cmpxchg, [3]); +atomic_rmw_cmpxchg!(I32, I32AtomicRmw8CmpxchgU, i32_atomic_rmw8_cmpxchg_u, [0]); +atomic_rmw_cmpxchg!(I64, I64AtomicRmw8CmpxchgU, i64_atomic_rmw8_cmpxchg_u, [0]); +atomic_rmw_cmpxchg!(I32, I32AtomicRmw16CmpxchgU, i32_atomic_rmw16_cmpxchg_u, [1]); +atomic_rmw_cmpxchg!(I64, I64AtomicRmw16CmpxchgU, i64_atomic_rmw16_cmpxchg_u, [1]); +atomic_rmw_cmpxchg!(I64, I64AtomicRmw32CmpxchgU, i64_atomic_rmw32_cmpxchg_u, [2]); + +fn atomic_notify( + u: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec<Instruction>, +) -> Result<()> { + builder.pop_operands(module, &[ValType::I32]); + let memarg = mem_arg(u, module, builder, &[2])?; + builder.push_operands(&[ValType::I32]); + instructions.push(Instruction::MemoryAtomicNotify(memarg)); + Ok(()) +} + +fn atomic_wait32( + u: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec<Instruction>, +) -> Result<()> { + builder.pop_operands(module, &[ValType::I32, ValType::I64]); + let memarg = mem_arg(u, module, builder, &[2])?; + builder.push_operands(&[ValType::I32]); + instructions.push(Instruction::MemoryAtomicWait32(memarg)); + Ok(()) +} + +fn atomic_wait64( + u: &mut Unstructured, + module: &Module, + builder: &mut CodeBuilder, + instructions: &mut Vec<Instruction>, +) -> Result<()> { + builder.pop_operands(module, &[ValType::I64, ValType::I64]); + let memarg = mem_arg(u, module, builder, &[3])?; + builder.push_operands(&[ValType::I32]); + instructions.push(Instruction::MemoryAtomicWait64(memarg)); + Ok(()) +} + +fn atomic_fence( + _u: &mut Unstructured, + _module: &Module, + _builder: &mut CodeBuilder, + instructions: &mut Vec<Instruction>, +) -> Result<()> { + instructions.push(Instruction::AtomicFence); + Ok(()) +} diff --git a/third_party/rust/wasm-smith/src/core/code_builder/no_traps.rs b/third_party/rust/wasm-smith/src/core/code_builder/no_traps.rs @@ -402,8 +402,8 @@ fn dummy_value_inst<'a>(ty: ValType) -> Instruction<'a> { match ty { ValType::I32 => Instruction::I32Const(0), ValType::I64 => Instruction::I64Const(0), - ValType::F32 => Instruction::F32Const(0.0), - ValType::F64 => Instruction::F64Const(0.0), + ValType::F32 => Instruction::F32Const(0.0.into()), + ValType::F64 => Instruction::F64Const(0.0.into()), ValType::V128 => Instruction::V128Const(0), ValType::Ref(ty) => { assert!(ty.nullable); @@ -466,14 +466,14 @@ fn min_input_const_for_trunc<'a>(inst: &Instruction) -> Instruction<'a> { // This is the minimum float value that is representable as as i32 let min_f32_as_i32 = -2_147_483_500f32; match inst { - Instruction::I32TruncF32S => Instruction::F32Const(min_f32_as_i32), - Instruction::I32TruncF32U => Instruction::F32Const(0.0), - Instruction::I64TruncF32S => Instruction::F32Const(min_f32), - Instruction::I64TruncF32U => Instruction::F32Const(0.0), - Instruction::I32TruncF64S => Instruction::F64Const(i32::MIN as f64), - Instruction::I32TruncF64U => Instruction::F64Const(0.0), - Instruction::I64TruncF64S => Instruction::F64Const(min_f64), - Instruction::I64TruncF64U => Instruction::F64Const(0.0), + Instruction::I32TruncF32S => Instruction::F32Const(min_f32_as_i32.into()), + Instruction::I32TruncF32U => Instruction::F32Const(0.0.into()), + Instruction::I64TruncF32S => Instruction::F32Const(min_f32.into()), + Instruction::I64TruncF32U => Instruction::F32Const(0.0.into()), + Instruction::I32TruncF64S => Instruction::F64Const((i32::MIN as f64).into()), + Instruction::I32TruncF64U => Instruction::F64Const(0.0.into()), + Instruction::I64TruncF64S => Instruction::F64Const(min_f64.into()), + Instruction::I64TruncF64U => Instruction::F64Const(0.0.into()), _ => panic!("not a trunc instruction"), } } @@ -487,16 +487,16 @@ fn max_input_const_for_trunc<'a>(inst: &Instruction) -> Instruction<'a> { let max_f32_as_i32 = 2_147_483_500f32; match inst { Instruction::I32TruncF32S | Instruction::I32TruncF32U => { - Instruction::F32Const(max_f32_as_i32) + Instruction::F32Const(max_f32_as_i32.into()) } Instruction::I64TruncF32S | Instruction::I64TruncF32U => { - Instruction::F32Const(max_f32_as_i64) + Instruction::F32Const(max_f32_as_i64.into()) } Instruction::I32TruncF64S | Instruction::I32TruncF64U => { - Instruction::F64Const(i32::MAX as f64) + Instruction::F64Const((i32::MAX as f64).into()) } Instruction::I64TruncF64S | Instruction::I64TruncF64U => { - Instruction::F64Const(max_f64_as_i64) + Instruction::F64Const(max_f64_as_i64.into()) } _ => panic!("not a trunc instruction"), } @@ -624,16 +624,16 @@ fn flt_gt_inst<'a>(ty: ValType) -> Instruction<'a> { fn flt_inf_const_inst<'a>(ty: ValType) -> Instruction<'a> { match ty { - ValType::F32 => Instruction::F32Const(f32::INFINITY), - ValType::F64 => Instruction::F64Const(f64::INFINITY), + ValType::F32 => Instruction::F32Const(f32::INFINITY.into()), + ValType::F64 => Instruction::F64Const(f64::INFINITY.into()), _ => panic!("not a float type"), } } fn flt_neg_inf_const_inst<'a>(ty: ValType) -> Instruction<'a> { match ty { - ValType::F32 => Instruction::F32Const(f32::NEG_INFINITY), - ValType::F64 => Instruction::F64Const(f64::NEG_INFINITY), + ValType::F32 => Instruction::F32Const(f32::NEG_INFINITY.into()), + ValType::F64 => Instruction::F64Const(f64::NEG_INFINITY.into()), _ => panic!("not a float type"), } } diff --git a/third_party/rust/wasm-smith/src/core/encode.rs b/third_party/rust/wasm-smith/src/core/encode.rs @@ -218,7 +218,7 @@ impl Module { for instr in instrs { func.instruction(instr); } - func.instruction(&wasm_encoder::Instruction::End); + func.instructions().end(); } Instructions::Arbitrary(body) => { func.raw(body.iter().copied()); diff --git a/third_party/rust/wasm-smith/src/core/terminate.rs b/third_party/rust/wasm-smith/src/core/terminate.rs @@ -1,5 +1,5 @@ use super::*; -use anyhow::{bail, Result}; +use anyhow::{Result, bail}; impl Module { /// Ensure that all of this Wasm module's functions will terminate when diff --git a/third_party/rust/wasm-smith/src/lib.rs b/third_party/rust/wasm-smith/src/lib.rs @@ -24,6 +24,7 @@ //! //! #![no_main] //! +//! # #[cfg(not(target_family = "wasm"))] mod x { //! use libfuzzer_sys::fuzz_target; //! use wasm_smith::Module; //! @@ -32,6 +33,7 @@ //! //! // Your code here... //! }); +//! # } //! ``` //! //! Finally, start fuzzing: @@ -41,7 +43,7 @@ //! ``` //! //! > **Note:** For a real world example, also check out [the `validate` fuzz -//! > target](https://github.com/fitzgen/wasm-smith/blob/main/fuzz/fuzz_targets/validate.rs) +//! > target](https://github.com/bytecodealliance/wasm-tools/blob/main/fuzz/src/validate.rs) //! > defined in this repository. Using the `wasmparser` crate, it checks that //! > every module generated by `wasm-smith` validates successfully. //! @@ -50,10 +52,10 @@ //! The design and implementation strategy of wasm-smith is outlined in //! [this article](https://fitzgeraldnick.com/2020/08/24/writing-a-test-case-generator.html). -#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(docsrs, feature(doc_cfg))] #![deny(missing_docs, missing_debug_implementations)] // Needed for the `instructions!` macro in `src/code_builder.rs`. -#![recursion_limit = "512"] +#![recursion_limit = "1024"] #[cfg(feature = "component-model")] mod component; @@ -68,7 +70,7 @@ pub use config::{Config, MemoryOffsetChoices}; use std::{collections::HashSet, fmt::Write, str}; use wasm_encoder::MemoryType; -#[cfg(feature = "_internal_cli")] +#[doc(hidden)] pub use config::InternalOptionalConfig; pub(crate) fn page_size(mem: &MemoryType) -> u32 { @@ -148,27 +150,27 @@ pub(crate) fn unique_kebab_string( ) -> Result<String> { let size = std::cmp::min(u.arbitrary_len::<u8>()?, max_size); let mut name = String::with_capacity(size); - let mut require_alpha = true; - for _ in 0..size { + let mut empty_segment = true; + for i in 0..size { name.push(match u.int_in_range::<u8>(0..=36)? { x if (0..26).contains(&x) => { - require_alpha = false; + empty_segment = false; (b'a' + x) as char } x if (26..36).contains(&x) => { - if require_alpha { - require_alpha = false; + empty_segment = false; + if i == 0 { (b'a' + (x - 26)) as char } else { (b'0' + (x - 26)) as char } } x if x == 36 => { - if require_alpha { - require_alpha = false; + if empty_segment { + empty_segment = false; 'a' } else { - require_alpha = true; + empty_segment = true; '-' } } diff --git a/third_party/rust/wasm-smith/tests/available_imports.rs b/third_party/rust/wasm-smith/tests/available_imports.rs @@ -1,7 +1,7 @@ #![cfg(feature = "wasmparser")] -use arbitrary::{Arbitrary, Unstructured}; -use rand::{rngs::SmallRng, RngCore, SeedableRng}; +use arbitrary::Unstructured; +use rand::{RngCore, SeedableRng, rngs::SmallRng}; use std::collections::HashMap; use wasm_smith::{Config, Module}; use wasmparser::Validator; @@ -38,8 +38,16 @@ fn smoke_test_imports_config() { if let wasmparser::Payload::TypeSection(rdr) = payload { // Gather the signature types to later check function types // against. - for ty in rdr.into_iter_err_on_gc_types() { - sig_types.push(ty.unwrap()); + for recgrp in rdr { + let recgrp = recgrp.unwrap(); + for subtype in recgrp.into_types() { + match subtype.composite_type.inner { + wasmparser::CompositeInnerType::Func(func_type) => { + sig_types.push(Some(func_type)) + } + _ => sig_types.push(None), + } + } } } else if let wasmparser::Payload::ImportSection(rdr) = payload { // Read out imports, checking that they all are within the @@ -51,7 +59,7 @@ fn smoke_test_imports_config() { use AvailableImportKind as I; let entry = imports_seen.get_mut(&(import.module, import.name)); match (entry, &import.ty) { - (Some((true, _)), _) => panic!("duplicate import of {:?}", import), + (Some((true, _)), _) => panic!("duplicate import of {import:?}"), (Some((seen, I::Memory)), TypeRef::Memory(_)) => *seen = true, (Some((seen, I::Global(t))), TypeRef::Global(gt)) if *t == gt.content_type => @@ -64,24 +72,29 @@ fn smoke_test_imports_config() { *seen = true } (Some((seen, I::Func(p, r))), TypeRef::Func(sig_idx)) - if sig_types[*sig_idx as usize].params() == *p - && sig_types[*sig_idx as usize].results() == *r => + if sig_types[*sig_idx as usize].clone().unwrap().params() == *p + && sig_types[*sig_idx as usize].clone().unwrap().results() + == *r => { *seen = true } ( Some((seen, I::Tag(p))), TypeRef::Tag(wasmparser::TagType { func_type_idx, .. }), - ) if sig_types[*func_type_idx as usize].params() == *p - && sig_types[*func_type_idx as usize].results().is_empty() => + ) if sig_types[*func_type_idx as usize].clone().unwrap().params() + == *p + && sig_types[*func_type_idx as usize] + .clone() + .unwrap() + .results() + .is_empty() => { *seen = true } - (Some((_, expected)), _) => panic!( - "import {:?} type mismatch, expected: {:?}", - import, expected - ), - (None, _) => panic!("import of an unknown entity: {:?}", import), + (Some((_, expected)), _) => { + panic!("import {import:?} type mismatch, expected: {expected:?}") + } + (None, _) => panic!("import of an unknown entity: {import:?}"), } } } @@ -109,8 +122,8 @@ fn smoke_test_imports_config() { #[derive(Debug)] enum AvailableImportKind { - Func(&'static [ValType], &'static [ValType]), - Tag(&'static [ValType]), + Func(Vec<ValType>, Vec<ValType>), + Tag(Vec<ValType>), Global(ValType), Table(ValType), Memory, @@ -122,28 +135,43 @@ fn import_config( Config, Vec<(&'static str, &'static str, AvailableImportKind)>, ) { - let mut config = Config::arbitrary(u).expect("arbitrary swarm"); - config.gc_enabled = false; + let mut config = Config::default(); config.exceptions_enabled = u.arbitrary().expect("exceptions enabled for swarm"); let available = { - use {AvailableImportKind::*, ValType::*}; + use { + AvailableImportKind::*, + ValType::*, + wasmparser::{PackedIndex, RefType}, + }; vec![ - ("env", "pi", Func(&[I32], &[])), - ("env", "pi2", Func(&[I32], &[])), - ("env", "pipi2", Func(&[I32, I32], &[])), - ("env", "po", Func(&[], &[I32])), - ("env", "pipo", Func(&[I32], &[I32])), - ("env", "popo", Func(&[], &[I32, I32])), + ("env", "pi", Func(vec![I32], vec![])), + ("env", "pi2", Func(vec![I32], vec![])), + ("env", "pipi2", Func(vec![I32, I32], vec![])), + ("env", "po", Func(vec![], vec![I32])), + ("env", "pipo", Func(vec![I32], vec![I32])), + ("env", "popo", Func(vec![], vec![I32, I32])), ("env", "mem", Memory), ("env", "tbl", Table(ValType::FUNCREF)), ("vars", "g", Global(I64)), - ("tags", "tag1", Tag(&[I32])), + ("tags", "tag1", Tag(vec![I32])), + ( + "tags", + "tag2", + Tag(vec![Ref(RefType::concrete( + true, + PackedIndex::from_module_index(0).unwrap(), + ))]), + ), ] }; config.available_imports = Some( wat::parse_str( r#" (module + (rec + (type $s0 (array (ref $s1))) + (type $s1 (array (ref $s0))) + ) (import "env" "pi" (func (param i32))) (import "env" "pi2" (func (param i32))) (import "env" "pipi2" (func (param i32 i32))) @@ -154,6 +182,7 @@ fn import_config( (import "env" "tbl" (table 1 16 funcref)) (import "vars" "g" (global i64)) (import "tags" "tag1" (tag (param i32))) + (import "tags" "tag2" (tag (param (ref null $s0)))) ) "#, ) diff --git a/third_party/rust/wasm-smith/tests/common/mod.rs b/third_party/rust/wasm-smith/tests/common/mod.rs @@ -1,4 +1,4 @@ -use wasmparser::{types::Types, Validator}; +use wasmparser::{Validator, types::Types}; pub fn validate(validator: &mut Validator, bytes: &[u8]) -> Types { let err = match validator.validate_all(bytes) { @@ -11,5 +11,5 @@ pub fn validate(validator: &mut Validator, bytes: &[u8]) -> Types { eprintln!("Writing WAT to `test.wat`"); drop(std::fs::write("test.wat", &text)); } - panic!("wasm failed to validate: {}", err); + panic!("wasm failed to validate: {err}"); } diff --git a/third_party/rust/wasm-smith/tests/component.rs b/third_party/rust/wasm-smith/tests/component.rs @@ -1,7 +1,7 @@ #![cfg(feature = "component-model")] use arbitrary::{Arbitrary, Unstructured}; -use rand::{rngs::SmallRng, RngCore, SeedableRng}; +use rand::{RngCore, SeedableRng, rngs::SmallRng}; use wasm_smith::Component; #[test] @@ -27,8 +27,7 @@ fn smoke_test_component() { std::fs::write("component.wasm", &component).unwrap(); panic!( "generated component should be valid; failing binary written \ - to `component.wasm`. Error: {}", - e + to `component.wasm`. Error: {e}" ); } } diff --git a/third_party/rust/wasm-smith/tests/core.rs b/third_party/rust/wasm-smith/tests/core.rs @@ -1,5 +1,5 @@ use arbitrary::{Arbitrary, Unstructured}; -use rand::{rngs::SmallRng, RngCore, SeedableRng}; +use rand::{RngCore, SeedableRng, rngs::SmallRng}; use wasm_smith::{Config, Module}; use wasmparser::{Validator, WasmFeatures}; @@ -167,6 +167,25 @@ fn smoke_test_reference_types() { } #[test] +fn smoke_test_threads() { + let mut rng = SmallRng::seed_from_u64(0); + let mut buf = vec![0; 2048]; + for _ in 0..1024 { + rng.fill_bytes(&mut buf); + let mut u = Unstructured::new(&buf); + let config = Config { + threads_enabled: true, + ..Config::default() + }; + if let Ok(module) = Module::new(config, &mut u) { + let wasm_bytes = module.to_bytes(); + let mut validator = Validator::new_with_features(WasmFeatures::all()); + validate(&mut validator, &wasm_bytes); + } + } +} + +#[test] fn smoke_test_wasm_gc() { let mut rng = SmallRng::seed_from_u64(0); let mut buf = vec![0; 2048]; diff --git a/third_party/rust/wasm-smith/tests/exports.rs b/third_party/rust/wasm-smith/tests/exports.rs @@ -1,10 +1,11 @@ #![cfg(feature = "wasmparser")] -use arbitrary::{Arbitrary, Unstructured}; -use rand::{rngs::SmallRng, RngCore, SeedableRng}; +use arbitrary::Unstructured; +use rand::{RngCore, SeedableRng, rngs::SmallRng}; use wasm_smith::{Config, Module}; use wasmparser::{ - types::EntityType, CompositeType, FuncType, GlobalType, Parser, Validator, WasmFeatures, + CompositeType, FuncType, GlobalType, MemoryType, Parser, TableType, Validator, WasmFeatures, + types::EntityType, }; mod common; @@ -14,6 +15,9 @@ use common::validate; enum ExportType { Func(FuncType), Global(GlobalType), + Memory(MemoryType), + Table(TableType), + Tag(FuncType), } #[test] @@ -65,14 +69,26 @@ fn smoke_test_export_with_imports() { (module (import "" "foo" (func (param i32))) (import "" "bar" (global (mut f32))) + (import "" "mem" (memory 5)) + (import "" "baz" (table 1 10 funcref)) + (import "" "qux" (tag (param i32 f64))) (func (param i64) unreachable) (global i32 (i32.const 0)) + (memory 10) + (table 10 (ref null any)) + (tag (param f32 v128)) (export "a" (func 0)) (export "b" (global 0)) - (export "c" (func 1)) - (export "d" (global 1)) + (export "c" (memory 0)) + (export "d" (table 0)) + (export "e" (tag 0)) + (export "f" (func 1)) + (export "g" (global 1)) + (export "h" (memory 1)) + (export "i" (table 1)) + (export "j" (tag 1)) ) - "#; + "#; smoke_test_exports(test, 21) } @@ -92,12 +108,25 @@ fn smoke_test_with_mutable_global_exports() { smoke_test_exports(test, 22) } -fn get_func_and_global_exports(features: WasmFeatures, module: &[u8]) -> Vec<(String, ExportType)> { +#[test] +fn smoke_test_all_exports() { + let test = r#" + (module + (func (export "foo") (param i32) (result i64) unreachable) + (global (export "bar") f32 f32.const 0) + (memory (export "baz") 1 10) + (table (export "qux") 5 10 (ref null extern)) + (tag (export "quux") (param f32)) + ) + "#; + smoke_test_exports(test, 23); +} + +fn get_exports(features: WasmFeatures, module: &[u8]) -> Vec<(String, ExportType)> { let mut validator = Validator::new_with_features(features); let types = validate(&mut validator, module); let types = types.as_ref(); let mut exports = vec![]; - for payload in Parser::new(0).parse_all(module) { let payload = payload.unwrap(); if let wasmparser::Payload::ExportSection(rdr) = payload { @@ -113,17 +142,35 @@ fn get_func_and_global_exports(features: WasmFeatures, module: &[u8]) -> Vec<(St .. } = &sub_type.composite_type else { - panic!("Expected Func CompositeType, but found {:?}", sub_type); + panic!("Expected Func CompositeType, but found {sub_type:?}"); }; exports .push((export.name.to_string(), ExportType::Func(func_type.clone()))); } EntityType::Global(global_type) => { - exports.push((export.name.to_string(), ExportType::Global(global_type))) + exports.push((export.name.to_string(), ExportType::Global(global_type))); + } + EntityType::Memory(memory_type) => { + exports.push((export.name.to_string(), ExportType::Memory(memory_type))); } - other => { - panic!("Unexpected entity type {:?}", other) + EntityType::Table(table_type) => { + exports.push((export.name.to_string(), ExportType::Table(table_type))); + } + EntityType::Tag(core_id) => { + let sub_type = types.get(core_id).expect("Failed to lookup core id"); + assert!(sub_type.is_final); + assert!(sub_type.supertype_idx.is_none()); + let CompositeType { + inner: wasmparser::CompositeInnerType::Func(func_type), + .. + } = &sub_type.composite_type + else { + panic!("Expected Func CompositeType, but found {sub_type:?}"); + }; + assert!(func_type.results().is_empty()); + exports.push((export.name.to_string(), ExportType::Tag(func_type.clone()))); } + EntityType::FuncExact(_) => panic!("Unexpected func_exact in export"), } } } @@ -135,20 +182,22 @@ fn smoke_test_exports(exports_test_case: &str, seed: u64) { let mut rng = SmallRng::seed_from_u64(seed); let mut buf = vec![0; 512]; let wasm = wat::parse_str(exports_test_case).unwrap(); - let expected_exports = get_func_and_global_exports(WasmFeatures::default(), &wasm); + let expected_exports = get_exports(WasmFeatures::default(), &wasm); for _ in 0..1024 { rng.fill_bytes(&mut buf); let mut u = Unstructured::new(&buf); - let mut config = Config::arbitrary(&mut u).expect("arbitrary config"); + // Enable all standardized proposals. + let mut config = Config::default(); + config.max_memories = u.int_in_range(2..=5).unwrap(); config.exports = Some(wasm.clone()); let features = config.features(); let module = Module::new(config, &mut u).unwrap(); let wasm_bytes = module.to_bytes(); - let generated_exports = get_func_and_global_exports(features, &wasm_bytes); + let generated_exports = get_exports(features, &wasm_bytes); assert_eq!(expected_exports, generated_exports); } } diff --git a/third_party/rust/wasm-smith/tests/module_shape.rs b/third_party/rust/wasm-smith/tests/module_shape.rs @@ -0,0 +1,130 @@ +#![cfg(feature = "wasmparser")] + +use arbitrary::Unstructured; +use rand::{RngCore, SeedableRng, rngs::SmallRng}; +use wasm_smith::{Config, Module}; +use wasmparser::{Parser, Validator, WasmFeatures, types::EntityType}; + +mod common; +use common::validate; + +#[derive(Debug, PartialEq)] +struct WasmExport(String, EntityType); +#[derive(Debug, PartialEq)] +struct WasmImport(String, String, EntityType); + +#[test] +fn smoke_test_module_shape_with_gc_types() { + let test = r#" + (module + (rec + (type $t0 (func (param i32 (ref null $t1)) (result (ref null $t0)))) + (type $t1 (func (param i64 (ref null $t0)))) + ) + (rec + (type $t2 (sub (struct (field i8)))) + (type $t3 (sub $t2 (struct (field i8) (field i16)))) + (type $t4 (sub final $t3 (struct (field i8) (field i16) (field (ref null $t0))))) + ) + (rec + (type $t5 (sub (array (ref null $t2)))) + (type $t6 (sub final $t5 (array (ref null $t3)))) + ) + (import "env" "fun" (func (type $t0))) + (import "env" "tbl" (table i32 1 10 (ref null $t2))) + (import "env" "mem" (memory 5 10)) + (import "env" "glb" (global (ref null $t4))) + (import "env" "tag" (tag (type $t1))) + (func (export "f") (type $t0) unreachable) + (table (export "t") i64 10 100 (ref null $t2) struct.new_default $t2) + (memory (export "m") 10 15) + (export "tt" (tag 0)) + (export "g" (global 0)) + ) + "#; + smoke_test_imports_exports(test, 42); +} + +#[test] +fn smoke_test_module_shape_without_gc_types() { + let test = r#" + (module + (import "env" "fun" (func (param i32))) + (import "env" "tag" (tag (param externref))) + (import "env" "mem" (memory 1 10)) + (import "env" "tbl" (table i64 10 10 funcref)) + (import "env" "glb" (global (mut v128))) + (func (export "f") (param i32) (result i64) unreachable) + (memory (export "m") 10) + (global (export "g") f64 f64.const 0.0) + (table (export "t") 15 20 externref) + (export "tt" (tag 0)) + ) + "#; + smoke_test_imports_exports(test, 43); +} + +fn get_imports_exports( + features: WasmFeatures, + module: &[u8], +) -> (Vec<WasmImport>, Vec<WasmExport>) { + let mut validator = Validator::new_with_features(features); + let types = validate(&mut validator, module); + let types = types.as_ref(); + let mut imports = vec![]; + let mut exports = vec![]; + for payload in Parser::new(0).parse_all(module) { + let payload = payload.unwrap(); + match payload { + wasmparser::Payload::ImportSection(ir) => { + for import in ir { + let import = import.unwrap(); + imports.push(WasmImport( + import.module.to_string(), + import.name.to_string(), + types.entity_type_from_import(&import).unwrap(), + )); + } + } + wasmparser::Payload::ExportSection(er) => { + for export in er { + let export = export.unwrap(); + exports.push(WasmExport( + export.name.to_string(), + types.entity_type_from_export(&export).unwrap(), + )); + } + } + _ => {} + } + } + (imports, exports) +} + +fn smoke_test_imports_exports(module_shape_test_case: &str, seed: u64) { + let mut rng = SmallRng::seed_from_u64(seed); + let mut buf = vec![0; 512]; + let wasm = wat::parse_str(module_shape_test_case).unwrap(); + let (expected_imports, expected_exports) = get_imports_exports(WasmFeatures::default(), &wasm); + + for _ in 0..1024 { + rng.fill_bytes(&mut buf); + let mut u = Unstructured::new(&buf); + + // Enable all standardized proposals. + let mut config = Config::default(); + config.max_memories = u.int_in_range(2..=5).unwrap(); + config.module_shape = Some(wasm.clone()); + + let features = config.features(); + let module = Module::new(config, &mut u).unwrap(); + let wasm_bytes = module.to_bytes(); + + // The generated and expected imports/exports should share the same CoreTypeId, since + // we copy all types, imports, and exports from the module-shape module into the target + // module at the start of generation. + let (generated_imports, generated_exports) = get_imports_exports(features, &wasm_bytes); + assert_eq!(expected_imports, generated_imports); + assert_eq!(expected_exports, generated_exports); + } +} diff --git a/third_party/rust/wasmparser/.cargo-checksum.json b/third_party/rust/wasmparser/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"0b51fe44ed9bdb45b9a22dfde1b870b68c94ca404037e565988f4e47ba12208b","Cargo.toml":"30c213df4a8ef23b427daa0d9e4a9e5104e8d5deb79de63baeeed9c407a7ce36","README.md":"aabf3b5930893b2a89d0114d8cd97e9b980f3c6f758b960484e06b69a504b823","benches/benchmark.rs":"efbd81a618aecebe56dba02d799135defa5320d67b656cd7668c5d9467637ae3","build.rs":"ba7ab1735d3642c53562d1223a6eb54c2392e619ade3005e0deee3fc4229feea","examples/simple.rs":"e9eb076367cc0932e2a32651372defa4a27ef800f47fad28c0ef840ba8ea7e08","src/arity.rs":"ea30dc6d2b96943312138fb09ef3254e0ff2c6bb170142bcb274cc07c528dd39","src/binary_reader.rs":"3fc22e9641fd210b8fbaa1fc77bebf3dc30c3f0f7c5d26840a9a60f3cd8e9dad","src/binary_reader/simd.rs":"0f39732b8f720ecb3dbfcf2ede7bdf0b5474f10f9af6d14f452d266b35a16291","src/collections/hash.rs":"4146765fe03ff2e3456ad713283713c8614d9605a0f9c22c710b95508de7da89","src/collections/index_map.rs":"0df16027b0e9b1422a6d35f4a6bb6859b5e9fe734600d0db6aaa2f96e7c46270","src/collections/index_map/detail.rs":"3c28f01e8d1fd202f8d27f30fddd3e303b18e8e79599fffc75a2ed299c7a1144","src/collections/index_map/tests.rs":"7761fda67a871bcef24579f0cbe4762e40fb8e7ca5147c67187da510c545c016","src/collections/index_set.rs":"f53bcbfbbeccd9bf62406f08565f5ac57af58cf962484a91d4efcd7431d37310","src/collections/map.rs":"f239038e622dd95eb5ee5dbbfb67cd0e4cafe18c750cc0c46b1013809e0ec643","src/collections/mod.rs":"b80b8f49039ef403b9515c994aa2512db5dc905f083c876a41d8ca705d7add6e","src/collections/set.rs":"b9680f5c2f0cb7c52a935ce80f1ec3f5c6239913c1b621556f289a708e0f373b","src/features.rs":"cc1d40f30287b694b8f001f2b35fb5afe8d65ef453896e7c4956827a895dc5a1","src/lib.rs":"031c0f7eb877b93d06313d614a8fdf787ce68d4c403af2e323b327484258bee8","src/limits.rs":"14999cb2156648727b36a18667420173993ff73b8bc270897a5e9c340b210b00","src/parser.rs":"1d33ffc6e44e89fd9986cad933338078d9a82b36af14d1ef6d0790b3acdfe83b","src/readers.rs":"bf43b91c1ad97d9d67eaa8fc63381428dc300c97b21ce1ede89ab6b628625da7","src/readers/component.rs":"c259628ca3f09ff904f7e920aeec261b657f7a197c99b520a6a7d3e918b9fb3b","src/readers/component/aliases.rs":"feb6d4d9cb5f3ed446a6ec0a529633bf389418129e357513f09409adff799628","src/readers/component/canonicals.rs":"8f6c0809c8d1769d25045b492c24b9e730aa224a1181ae56d40f1ec843a018c5","src/readers/component/exports.rs":"1ad13434edd7021f6cebe3ac1388dfbebfdb5bf5a345236e4a1078a9e3c6594b","src/readers/component/imports.rs":"575b35bbb1c4a7679a5973b47f497e3ba2215baeb97465711ce192a25805787c","src/readers/component/instances.rs":"8ab1254ce1e66528d37a61bcde4cabb2c7c87ccc2740be03d539c064ed544d29","src/readers/component/names.rs":"4d4a965159bc5a2e788f5b1848700be5b5a7b9137b67bc14d7c692acb1f95765","src/readers/component/start.rs":"9c37d1eea486ee951547a328693bcf9f2a27f48e2207478daf23c1cd9e9f95f3","src/readers/component/types.rs":"e0065d441026d90dae0fc221cf7e541e881cd4ea97efe55215d2a265b8718b02","src/readers/core.rs":"f77e1eb46e1d05abeabb9be2bd7bdd66acadfc4c651912f2a67b7e5f7d29d041","src/readers/core/branch_hinting.rs":"29210720e08e3a558fd96ac857038c9b87732a265ff1bfbd7f0bf3312ea3e949","src/readers/core/code.rs":"6bb975fa57f1453a38a325caa5985a030a95d986632ba9f8ab53bb1adabb9ce2","src/readers/core/coredumps.rs":"149c964c1536e9485930ae75089e9fb7393b0bdf50707d8edb813a0654fb7677","src/readers/core/custom.rs":"f3c965fcd044576a2c0f3ee87c78e4f9f345ce87899a76d609e5a8709f5d7d9e","src/readers/core/data.rs":"da78898a19accca90f05ee762cf3388c0f8a40a3d60cb78acaa3f0eb71a0cb3c","src/readers/core/dylink0.rs":"bd3de09ccd7a9b1dc1aacc3d4ebd7a70d31978c634c864aa2ca08a381ef24318","src/readers/core/elements.rs":"aa36b4b9fae50b51b6cc97baf68a522c4a1e382b3085022876a43e9c95db0658","src/readers/core/exports.rs":"302080640759838918650ad7c3f8c15867fe10e0ca2e5d280b026bde691a98cf","src/readers/core/functions.rs":"b5bbc7f7b7a429187376f63c695a9f1cbf92e515dba840ac876fa60f7290da34","src/readers/core/globals.rs":"c9ab071baa741c62625b6351c7d1d4b307e7e6142ef5fb70688202effde37a23","src/readers/core/imports.rs":"6b1f0e9856b4f375ae94815c16e59f82177b21fb52de3326be401107a7fb9f93","src/readers/core/init.rs":"7effaec7f0161661a9f21f8d3173ceb6bc270af2feb2be4e8eb0d2ca75e0f727","src/readers/core/linking.rs":"9a330b8a6b4d378a452e2671e089dc2041bd1cdda8f0fd4dddc5bca54783456b","src/readers/core/memories.rs":"1db19b6bf640bb150be1ac84bf852687567f8c93d53f0ec66c47ab607676a4d9","src/readers/core/names.rs":"722dc47fcd523fb75987ae501fb893002978b207e31b3bc054901e66737540f6","src/readers/core/operators.rs":"0b136f2f20ae323b6d02a9bf69b38a188ff7577d6fe7bcc4d28e8254b2aecfd5","src/readers/core/producers.rs":"1114cd29823c8a9ebfbe373975cfa52140782867b6b4c0fa342ee64c4040bd51","src/readers/core/reloc.rs":"3a4b0dc5700ae0df2943dc1e38c6113d091cd23b634cde42dfabb6119eddeb49","src/readers/core/tables.rs":"003903b2bc53da78a2b70743470ab094b14c329d2c7052251d48933e53800d67","src/readers/core/tags.rs":"c1dcfeb973195da9708549bcc2df4dd8ff282fe802c15a603bebc8a856f70949","src/readers/core/types.rs":"6bcc62beb4ffbb2da00411aefcf5d4c45dcbf369fbacbc93f2de89f1f091860b","src/readers/core/types/matches.rs":"8d6be9e33b82fbd765dc7d9a2600d6050c5b2987dc3fef3619595eea16399534","src/resources.rs":"22cac01b9b60443569e67828c122b0967f39f9c3ff8dbf51b00b90d3f3266e62","src/validator.rs":"8e2a3ac52b34f00b5072d22315744398ee6d7350b262da885a9a94d119e23370","src/validator/component.rs":"e4a70e2516dcebcc60f4d53df87013f190414862e07d319e397c2d8306dc918a","src/validator/component_types.rs":"ad012fa454f7f7f91ee4ffa36a2a0766cdc64072cabaad04afcb30e6be4e6861","src/validator/core.rs":"01d17a7615b60f815cd00db5ae878119af884afa53a1d4fc58165a87945c0e70","src/validator/core/canonical.rs":"742fc1ad958c7a7d8c9ebe47f240c135efdb677074a74148b006f0cb3a47bf20","src/validator/func.rs":"47ce73385635acff7e1533afec434fbc7547fd076387e786572323c600b3f8fa","src/validator/names.rs":"51500968e4611fabe217909466851ff5ffa5d43360d8a39ad290a57e1976c8c8","src/validator/operators.rs":"fbead971e7ba70fe05b9d483953f55cacd014f78d72bd28cc77d190a39faa8cf","src/validator/operators/simd.rs":"3ca2e637fde24241d2a4697863a19aa3e6b42084a506e0657df68f0864509877","src/validator/types.rs":"471f0085f2b41ad5f20928734eb5e4646d729a1daa2554d80fa2f08ecace7c78","tests/big-module.rs":"4c58174eca883df7ddbbcf870b4d86d9f62ae5c76be4fa7529649f24a1a756f6"},"package":"36e5456165f81e64cb9908a0fe9b9d852c2c74582aa3fe2be3c2da57f937d3ae"} -\ No newline at end of file +{"files":{"Cargo.lock":"ac744ad468f52a3c0a5c3b038a2507b5f7c50f59f77dd4e3cbc320914f2281b5","Cargo.toml":"3a4a30f00e72637b3f60587347b5114f1a1dd03d70832c163f3de3529ff4bb5e","README.md":"aabf3b5930893b2a89d0114d8cd97e9b980f3c6f758b960484e06b69a504b823","benches/benchmark.rs":"c69fd76e74644188f25d03beac288f094b22735db58daf00019f812f9400f604","build.rs":"ba7ab1735d3642c53562d1223a6eb54c2392e619ade3005e0deee3fc4229feea","examples/simple.rs":"e9eb076367cc0932e2a32651372defa4a27ef800f47fad28c0ef840ba8ea7e08","src/arity.rs":"6f34da680d7d79b1606aceb460bb4b06565904821e992c69aad5bcab271321d1","src/binary_reader.rs":"ea15e559c30dcf3b062eeb5b53490878a178ad1de24e3995cc51ffcf6411a6bb","src/collections/hash.rs":"4146765fe03ff2e3456ad713283713c8614d9605a0f9c22c710b95508de7da89","src/collections/index_map.rs":"70823e5d27ca3abd193e0f18a163e3cbcef6f969b212b870b439b341278f1c32","src/collections/index_map/detail.rs":"2e9c56ff3ebf0473704b8bf304d8cca4dd39fa6c5973e06b5493a45332bb656a","src/collections/index_map/tests.rs":"7761fda67a871bcef24579f0cbe4762e40fb8e7ca5147c67187da510c545c016","src/collections/index_set.rs":"f53bcbfbbeccd9bf62406f08565f5ac57af58cf962484a91d4efcd7431d37310","src/collections/map.rs":"f239038e622dd95eb5ee5dbbfb67cd0e4cafe18c750cc0c46b1013809e0ec643","src/collections/mod.rs":"b80b8f49039ef403b9515c994aa2512db5dc905f083c876a41d8ca705d7add6e","src/collections/set.rs":"b9680f5c2f0cb7c52a935ce80f1ec3f5c6239913c1b621556f289a708e0f373b","src/features.rs":"ce740b75433ea5799a73432105badb2fcc800665259756e08e20ac4c9bd278d8","src/lib.rs":"1a3d8c79f116527f3c4dcb4e256758acfe3096e87d96f4ec27bbcbd10b587ddf","src/limits.rs":"ac608007fb4e7c45c99159230230e0ab35739055980259920e3e4ad71b87ed61","src/parser.rs":"8abb0c08909f78418eb8a1a48b96185cdab67817afc5793dd1da7f87e57404ff","src/readers.rs":"bf43b91c1ad97d9d67eaa8fc63381428dc300c97b21ce1ede89ab6b628625da7","src/readers/component.rs":"c259628ca3f09ff904f7e920aeec261b657f7a197c99b520a6a7d3e918b9fb3b","src/readers/component/aliases.rs":"97398d9fdcb7b4227b8bb68a6677ebf09c62f6a43b9aa7591b37a2413848e759","src/readers/component/canonicals.rs":"b476941a7bed1ace8f8deb557cff33d123ef7f635713d883e217965d9323e064","src/readers/component/exports.rs":"de6482715680b63fc0969225b6c634c5f5c2fa5b763511628a313af4748df347","src/readers/component/imports.rs":"8d2947817bd1a91956d33a8e723f5af325f73cc6eb2903264a6dd594b3deeb46","src/readers/component/instances.rs":"8ab1254ce1e66528d37a61bcde4cabb2c7c87ccc2740be03d539c064ed544d29","src/readers/component/names.rs":"1bfdffe04b15760ab573359c864ead0c45a0afe42811d16af535d9e19125daa6","src/readers/component/start.rs":"9c37d1eea486ee951547a328693bcf9f2a27f48e2207478daf23c1cd9e9f95f3","src/readers/component/types.rs":"f6b9ffb164059eac56160bfb67060378f961696959541020f16b015470814afa","src/readers/core.rs":"f77e1eb46e1d05abeabb9be2bd7bdd66acadfc4c651912f2a67b7e5f7d29d041","src/readers/core/branch_hinting.rs":"29210720e08e3a558fd96ac857038c9b87732a265ff1bfbd7f0bf3312ea3e949","src/readers/core/code.rs":"96b4f12b666576100bfa9807e087792ec96b4d315317475180c086f18fe86b4d","src/readers/core/coredumps.rs":"75c1c5ad6a85cb90bc39eb4b22b22a512f5ee98b363565f7262c1c176a10bbef","src/readers/core/custom.rs":"f3c965fcd044576a2c0f3ee87c78e4f9f345ce87899a76d609e5a8709f5d7d9e","src/readers/core/data.rs":"da78898a19accca90f05ee762cf3388c0f8a40a3d60cb78acaa3f0eb71a0cb3c","src/readers/core/dylink0.rs":"c92d75e417eb444673408c00311da3f59427b6f966009f4830be8b518a8bda21","src/readers/core/elements.rs":"16342061fef1f04b68b99db7767e11608fec2922f07831df60922d6a9500e2dc","src/readers/core/exports.rs":"dd13793edf9edcbb857288c5adb273a8231ead5dbad2e39d0f9abd23ed189151","src/readers/core/functions.rs":"b5bbc7f7b7a429187376f63c695a9f1cbf92e515dba840ac876fa60f7290da34","src/readers/core/globals.rs":"19ea22f5c4ae3c1d6d4c62dbd163c503f05117210fa4b029094a1927e2c30b7a","src/readers/core/imports.rs":"5d11c8ea2328bf556d57587b2ee5756c818ba01ede87a8158b37811d55e71931","src/readers/core/init.rs":"53831f0d4b9e6c4de65816363787b863ce49850b32a821bd4b3891889b2e3ba6","src/readers/core/linking.rs":"02b1eb463b516fff4fa9f1ba06c623dd8e6b2ea3e632669415074d9ee4ac9968","src/readers/core/memories.rs":"a36d626d167569ee28feddbbfacd5d4211834bb2c8c3c522251a28ca15d229c0","src/readers/core/names.rs":"722dc47fcd523fb75987ae501fb893002978b207e31b3bc054901e66737540f6","src/readers/core/operators.rs":"8536dc584ce3769e6ac3aaa6ac636d65acb4aa681180f53564774657843a5b4a","src/readers/core/producers.rs":"25bbdd1385d26ba4dbc0814c516834f2ab7c0aad697a576b714d3dbe8dc2d7cc","src/readers/core/reloc.rs":"244f29411a0e4cceb09e0a9b9ec05a64bcc2d2c0f783f23227f33f91d2fbee3f","src/readers/core/tables.rs":"a0b3676cdd7c8a5f56ba7fcc0e5c0b3079755dc932e00caf5c37af176288d602","src/readers/core/tags.rs":"c1dcfeb973195da9708549bcc2df4dd8ff282fe802c15a603bebc8a856f70949","src/readers/core/types.rs":"6083a67298dcd9ab48e76b06a92f694fdb46c91b99433c853e8be6935c3867f6","src/readers/core/types/matches.rs":"0df58b38f94f3281b91d1edbb568b9b1d3484ea717fcbc8e353459447ded2d13","src/resources.rs":"eaf203d9b99e167ead8fc8ed8861851bdc1288bc5fe6c435f1ee7cf69e8f9fa5","src/validator.rs":"36814cb46fd8b89530a6138708a195bb86f0f763d8cc7ed2cb8e3fe0db88c541","src/validator/component.rs":"589f0de8626a086442cd5c370195efd5d2ebaca462ee5b2eeb2fe59262df2901","src/validator/component_types.rs":"06e4a1b72e0b0cfc53253e65cabea3590376bbfa39e39cde1446c8ca12f0d3ce","src/validator/core.rs":"748c9f8a432cb3118229825e59d58d3d4faa7d13679fc79ad7205705c1d0d13e","src/validator/core/canonical.rs":"4316d75a9d730fd631815046a34ab4b97f1bba5161cdca130bb5fb3f865c64a5","src/validator/func.rs":"eb8109fc85295d35d7b30d343404c995c6314600086e533f5b85e6a9c1ad7de4","src/validator/names.rs":"8f75bef3ac6d1a3d025c8a74743b63820e67ae0f6779ca3e5254d1e0f6e9394a","src/validator/operators.rs":"88fec45af8c85404c6f9ff946379e3f90804ff86633a9adc81ac56d4cdb113f1","src/validator/operators/simd.rs":"a338d3f82be1246a14cb96e5d99a99de0c728256703be36e4caf8142042693a2","src/validator/types.rs":"a9031f544a36c42befc346a5bb3363fe030581777a6ae2b4898bf65cd40401d6","tests/big-module.rs":"114d250505a2a3daf2e778bd4b2c14b7fc6b6be842055fa6b9389167fa430dca"},"package":"f6d8db401b0528ec316dfbe579e6ab4152d61739cfe076706d2009127970159d"} +\ No newline at end of file diff --git a/third_party/rust/wasmparser/Cargo.lock b/third_party/rust/wasmparser/Cargo.lock @@ -19,9 +19,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" dependencies = [ "anstyle", "anstyle-parse", @@ -34,55 +34,56 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" dependencies = [ - "windows-sys 0.52.0", + "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "once_cell_polyfill", + "windows-sys", ] [[package]] name = "anyhow" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "cast" @@ -92,9 +93,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "ciborium" @@ -125,18 +126,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.19" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.19" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstyle", "clap_lex", @@ -144,15 +145,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "criterion" @@ -190,9 +191,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -209,27 +210,27 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "env_filter" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", "regex", @@ -237,28 +238,28 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.5" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" dependencies = [ "anstream", "anstyle", "env_filter", - "humantime", + "jiff", "log", ] [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "foldhash" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "half" @@ -272,9 +273,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ "foldhash", "serde", @@ -282,21 +283,15 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "indexmap" -version = "2.7.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", "hashbrown", @@ -305,13 +300,13 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -331,27 +326,51 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jiff" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "libc" -version = "0.2.159" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "log" -version = "0.4.22" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "num-traits" @@ -364,30 +383,51 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] name = "oorandom" -version = "11.1.4" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + +[[package]] +name = "portable-atomic" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -414,9 +454,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -426,9 +466,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -443,9 +483,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -458,24 +498,34 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "serde" -version = "1.0.217" +version = "1.0.222" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "aab69e3f5be1836a1fe0aca0b286e5a5b38f262d6c9e8acd2247818751fcc8fb" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.222" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f8ebec5eea07db7df9342aa712db2138f019d9ab3454a60a680579a6f841b80" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.222" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "b5f61630fe26d0ff555e6c37dc445ab2f15871c8a11ace3cf471b3195d3e4f49" dependencies = [ "proc-macro2", "quote", @@ -484,9 +534,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -496,9 +546,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -517,9 +567,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "utf8parse" @@ -539,7 +589,7 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.225.0" +version = "0.243.0" dependencies = [ "anyhow", "bitflags", @@ -560,16 +610,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", + "windows-sys", ] [[package]] diff --git a/third_party/rust/wasmparser/Cargo.toml b/third_party/rust/wasmparser/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.76.0" name = "wasmparser" -version = "0.225.0" +version = "0.243.0" authors = ["Yury Delendik <ydelendik@mozilla.com>"] build = "build.rs" exclude = ["benches/*.wasm"] @@ -38,6 +38,32 @@ repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wa [package.metadata.docs.rs] all-features = true +[features] +component-model = ["dep:semver"] +default = [ + "std", + "validate", + "serde", + "features", + "component-model", + "hash-collections", + "simd", +] +features = [] +hash-collections = [ + "dep:hashbrown", + "dep:indexmap", +] +prefer-btree-collections = [] +serde = [ + "dep:serde", + "indexmap?/serde", + "hashbrown?/serde", +] +simd = [] +std = ["indexmap?/std"] +validate = [] + [lib] name = "wasmparser" path = "src/lib.rs" @@ -99,36 +125,15 @@ version = "1.13.0" [dev-dependencies.rayon] version = "1.3" -[features] -component-model = ["dep:semver"] -default = [ - "std", - "validate", - "serde", - "features", - "component-model", - "hash-collections", - "simd", -] -features = [] -hash-collections = [ - "dep:hashbrown", - "dep:indexmap", -] -prefer-btree-collections = [] -serde = [ - "dep:serde", - "indexmap?/serde", - "hashbrown?/serde", -] -simd = [] -std = ["indexmap?/std"] -validate = [] - [lints.clippy] +allow_attributes_without_reason = "warn" clone_on_copy = "warn" manual_strip = "warn" map_clone = "warn" +uninlined_format_args = "warn" +unnecessary_cast = "warn" +unnecessary_fallible_conversions = "warn" +unnecessary_mut_passed = "warn" unnecessary_to_owned = "warn" [lints.clippy.all] @@ -136,4 +141,22 @@ level = "allow" priority = -1 [lints.rust] +deprecated-safe-2024 = "warn" +keyword_idents_2024 = "warn" +missing-unsafe-on-extern = "warn" +rust-2024-guarded-string-incompatible-syntax = "warn" +rust-2024-incompatible-pat = "warn" +rust-2024-prelude-collisions = "warn" +unsafe-attr-outside-unsafe = "warn" +unsafe-op-in-unsafe-fn = "warn" unsafe_code = "deny" +unstable_features = "warn" +unused-lifetimes = "warn" +unused-macro-rules = "warn" +unused_extern_crates = "warn" +unused_import_braces = "warn" + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = ["cfg(fuzzing)"] diff --git a/third_party/rust/wasmparser/benches/benchmark.rs b/third_party/rust/wasmparser/benches/benchmark.rs @@ -1,11 +1,15 @@ use anyhow::Result; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{Criterion, criterion_group, criterion_main}; use once_cell::unsync::Lazy; use std::fs; +use std::mem; use std::path::Path; use std::path::PathBuf; use wasmparser::VisitSimdOperator; -use wasmparser::{DataKind, ElementKind, Parser, Payload, Validator, VisitOperator, WasmFeatures}; +use wasmparser::{ + BinaryReader, DataKind, ElementKind, OperatorsReader, Parser, Payload, Validator, + VisitOperator, WasmFeatures, +}; /// A benchmark input. pub struct BenchmarkInput { @@ -80,6 +84,17 @@ fn collect_test_files(path: &Path, list: &mut Vec<BenchmarkInput>) -> Result<()> /// so that we can report better errors in case of failures. fn read_all_wasm(wasm: &[u8]) -> Result<()> { use Payload::*; + let mut allocs = wasmparser::OperatorsReaderAllocations::default(); + let mut read_expr = |reader: BinaryReader<'_>| -> Result<_> { + let mut ops = OperatorsReader::new_with_allocs(reader, mem::take(&mut allocs)); + + while !ops.eof() { + ops.visit_operator(&mut NopVisit)?; + } + ops.finish()?; + allocs = ops.into_allocations(); + Ok(()) + }; for item in Parser::new(0).parse_all(wasm) { match item? { TypeSection(s) => { @@ -114,9 +129,7 @@ fn read_all_wasm(wasm: &[u8]) -> Result<()> { } GlobalSection(s) => { for item in s { - for op in item?.init_expr.get_operators_reader() { - op?; - } + read_expr(item?.init_expr.get_binary_reader())?; } } ExportSection(s) => { @@ -128,9 +141,7 @@ fn read_all_wasm(wasm: &[u8]) -> Result<()> { for item in s { let item = item?; if let ElementKind::Active { offset_expr, .. } = item.kind { - for op in offset_expr.get_operators_reader() { - op?; - } + read_expr(offset_expr.get_binary_reader())?; } match item.items { wasmparser::ElementItems::Functions(r) => { @@ -150,21 +161,16 @@ fn read_all_wasm(wasm: &[u8]) -> Result<()> { for item in s { let item = item?; if let DataKind::Active { offset_expr, .. } = item.kind { - for op in offset_expr.get_operators_reader() { - op?; - } + read_expr(offset_expr.get_binary_reader())?; } } } CodeSectionEntry(body) => { - let mut reader = body.get_binary_reader(); - for _ in 0..reader.read_var_u32()? { - reader.read_var_u32()?; - reader.read::<wasmparser::ValType>()?; - } - while !reader.eof() { - reader.visit_operator(&mut NopVisit)?; + let mut locals = body.get_locals_reader()?.into_iter(); + for item in locals.by_ref() { + let _ = item?; } + read_expr(locals.into_binary_reader_for_operators())?; } // Component sections diff --git a/third_party/rust/wasmparser/src/arity.rs b/third_party/rust/wasmparser/src/arity.rs @@ -13,9 +13,10 @@ * limitations under the License. */ +use crate::prelude::*; use crate::{ - BinaryReader, BinaryReaderError, BlockType, CompositeInnerType, ContType, FrameKind, FuncType, - Operator, RefType, Result, SubType, + BlockType, BrTable, CompositeInnerType, ContType, FrameKind, FuncType, Operator, RefType, + ResumeTable, SubType, TryTable, ValType, }; /// To compute the arity (param and result counts) of "variable-arity" @@ -69,176 +70,15 @@ pub trait ModuleArity { } } -impl BinaryReader<'_> { - /// Read the next operator and compute its arity (param and result counts) - pub fn operator_arity(&self, module: &impl ModuleArity) -> Result<(u32, u32)> { - self.clone() - .read_operator()? - .operator_arity(module) - .ok_or_else(|| { - BinaryReaderError::new("operator arity is unknown", self.original_position()) - }) - } -} - -/// The operator_arity macro interprets the annotations in the for_each_operator macro -/// to compute the arity of each operator. It needs access to a ModuleArity implementation. -macro_rules! operator_arity { - (arity $self:ident $({ $($arg:ident: $argty:ty),* })? arity $($ann:tt)*) => { - { - let params = (|| -> Option<(i32, i32)> { operator_arity!(params $self { $($($arg: $argty),*)? } $($ann)*) })(); - let results = (|| -> Option<(i32, i32)> { operator_arity!(results $self { $($($arg: $argty),*)? } $($ann)*) })(); - match (params, results) { - (Some((a,_)), Some((_,d))) if a >= 0 && d >= 0 => (Some((a as u32, d as u32))), - _ => None, - } - } - }; - - (arity $self:ident $({ $($arg:ident: $argty:ty),* })? $cat:ident $($ann:tt)*) => { - Some(operator_arity!(fixed $cat $($ann)*)) - }; - - (params $self:ident { $($arg:ident: $argty:ty),* } ~ $cat:ident $($tokens:tt)*) => { { let (a, b) = operator_arity!(count $self { $($arg: $argty),* } $cat)?; - let (c, d) = operator_arity!(params $self { $($arg: $argty),* } $($tokens)*)?; - Some((b as i32 + c as i32, a as i32 + d as i32)) } }; - (params $self:ident { $($arg:ident: $argty:ty),* } $val:literal $($tokens:tt)*) => { { let rest = operator_arity!(params $self { $($arg: $argty),* } $($tokens)*)?; - Some(($val + rest.0, $val + rest.1)) } }; - (params $self:ident { $($arg:ident: $argty:ty),* } $cat:ident $($tokens:tt)*) => { { let (a, b) = operator_arity!(count $self { $($arg: $argty),* } $cat)?; - let (c, d) = operator_arity!(params $self { $($arg: $argty),* } $($tokens)*)?; - Some((a as i32 + c as i32, b as i32 + d as i32)) } }; - (params $self:ident { $($arg:ident: $argty:ty),* } -> $($tokens:tt)*) => { Some((0, 0)) }; - (params $self:ident { $($arg:ident: $argty:ty),* }) => { Some((0, 0)) }; - - (results $self:ident { $($arg:ident: $argty:ty),* } ~ $($tokens:tt)*) => { operator_arity!(results $self { $($arg: $argty),* } $($tokens)*) }; - (results $self:ident { $($arg:ident: $argty:ty),* } $val:literal $($tokens:tt)*) => { operator_arity!(results $self { $($arg: $argty),* } $($tokens)*) }; - (results $self:ident { $($arg:ident: $argty:ty),* } $cat:ident $($tokens:tt)*) => { operator_arity!(results $self { $($arg: $argty),* } $($tokens)*) }; - (results $self:ident { $($arg:ident: $argty:ty),* } -> $($tokens:tt)*) => { operator_arity!(params $self { $($arg: $argty),* } $($tokens)*) }; - - (count $self:ident { $tag_index:ident: $_:ty } tag) => {{ - operator_arity!(tag_index $tag_index); - $self.tag_type_arity($tag_index) - }}; - - (count $self:ident { $_1:ident: $_2:ty, $tag_index:ident: $($_3:tt)* } tag) => { operator_arity!(count $self { $tag_index: _ } tag) }; - - (count $self:ident { $func_index:ident: $_:ty } func) => {{ - operator_arity!(func_index $func_index); - $self.sub_type_arity($self.sub_type_at($self.type_index_of_function($func_index)?)?) - }}; - - (count $self:ident { $type_index:ident: $($_:tt)* } type) => {{ - operator_arity!(type_index $type_index); - $self.sub_type_arity($self.sub_type_at($type_index)?) - }}; - - (count $self:ident { $type_index:ident: $($_:tt)* } switch) => {{ - operator_arity!(type_index $type_index); - let st = &$self.sub_type_at($type_index)?.composite_type.inner; - if let CompositeInnerType::Cont(ct) = &st { - let last_param = $self.func_type_of_cont_type(ct)?.params().last()?; - $self.sub_type_arity($self.sub_type_of_ref_type(&last_param.as_reference_type()?)?) - } else { - None - } - }}; - - (count $self:ident { $type1_index:ident: $t1:ty, $type2_index:ident: $t2:ty } type_diff) => {{ - operator_arity!(type_index $type1_index); - operator_arity!(type_index $type2_index); - let a = $self.sub_type_arity($self.sub_type_at($type1_index)?)?; - let b = $self.sub_type_arity($self.sub_type_at($type2_index)?)?; - Some((a.0.checked_sub(b.0)?, a.1.checked_sub(b.1)?)) - }}; - - (count $self:ident { $arg1:ident: $argty:ty, $size:ident: $sizety:ty } size) => {{ - operator_arity!(size_value $size); - Some(($size, $size)) - }}; - - (count $self:ident { $depth:ident: $($_:tt)* } br) => {{ - operator_arity!(depth $depth); - let (ty, kind) = $self.label_block($depth)?; - let (params, results) = $self.block_type_arity(ty)?; - let n = match kind { - FrameKind::Loop => params, - _ => results, - }; - Some((n, n)) - }}; - - (count $self:ident { $($_:ident: $__:ty),* } ret) => {{ - let (ty, _) = $self.control_stack_height().checked_sub(1) - .and_then(|x| $self.label_block(x))?; - $self.block_type_arity(ty) - }}; - - (count $self:ident { $blockty:ident: $($_:tt)* } block) => {{ - operator_arity!(blockty $blockty); - $self.block_type_arity($blockty) - }}; - - (count $self:ident {} implicit_else) => {{ - let (ty, kind) = $self.label_block(0)?; - let (params, results) = $self.block_type_arity(ty)?; - Some(match kind { - FrameKind::If => (results, params), - _ => (0, 0), - }) - }}; - - (count $self:ident { $($_: ident: $__:ty),* } end) => {{ - let (ty, _) = $self.label_block(0)?; - $self.block_type_arity(ty) - }}; - - (count $self:ident { $try_table:ident: $($_:tt)* } try_table) => {{ - operator_arity!(try_table $try_table); - $self.block_type_arity($try_table.ty) - }}; - - (count $self:ident { $br_table:ident: $($_:tt)* } br_table) => {{ - operator_arity!(br_table $br_table); - let relative_depth: u32 = $br_table.default(); - operator_arity!(count $self { relative_depth: u32 } br) - }}; - - (tag_index tag_index $($_:tt)*) => {}; - (func_index function_index $($_:tt)*) => {}; - (type_index type_index $($_:tt)*) => {}; - (type_index struct_type_index $($_:tt)*) => {}; - (type_index argument_index $($_:tt)*) => {}; - (type_index result_index $($_:tt)*) => {}; - (type_index cont_type_index $($_:tt)*) => {}; - (size_value array_size $($_:tt)*) => {}; - (depth relative_depth $($_:tt)*) => {}; - (blockty blockty $($_:tt)*) => {}; - (try_table try_table $($_:tt)*) => {}; - (br_table targets $($_:tt)*) => {}; - - (fixed load lane $($_:tt)*) => {(2, 1)}; - (fixed load $($_:tt)*) => {(1, 1)}; - (fixed store $($_:tt)*) => {(2, 0)}; - (fixed test $($_:tt)*) => {(1, 1)}; - (fixed unary $($_:tt)*) => {(1, 1)}; - (fixed binary $($_:tt)*) => {(2, 1)}; - (fixed cmp $($_:tt)*) => {(2, 1)}; - (fixed shift $($_:tt)*) => {(2, 1)}; - (fixed splat $($_:tt)*) => {(1, 1)}; - (fixed ternary $($_:tt)*) => {(3, 1)}; - (fixed conversion $($_:tt)*) => {(1, 1)}; - (fixed push $($_:tt)*) => {(0, 1)}; - (fixed extract $($_:tt)*) => {(1, 1)}; - (fixed replace $($_:tt)*) => {(2, 1)}; - (fixed atomic rmw array $($_:tt)*) => {(3, 1)}; - (fixed atomic rmw $($_:tt)*) => {(2, 1)}; - (fixed atomic cmpxchg $($_:tt)*) => {(3, 1)}; -} - impl Operator<'_> { /// Compute the arity (param and result counts) of the operator, given /// an impl ModuleArity, which stores the necessary module state. pub fn operator_arity(&self, module: &impl ModuleArity) -> Option<(u32, u32)> { + #[cfg_attr(not(feature = "simd"), allow(unused_macro_rules))] + macro_rules! operator_arity { + ($visit:ident $args:tt arity $a:tt -> $b:tt) => (Some(($a, $b))); + ($visit:ident { $($args:ident)* } arity custom) => ($visit(module, $($args),*)); + } macro_rules! define_arity { ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*) )*) => ( match self.clone() { @@ -247,7 +87,7 @@ impl Operator<'_> { $( $(let _ = $arg;)* )? - operator_arity!(arity module $({ $($arg: $argty),* })? $($ann)*) + operator_arity!($visit {$( $($arg)* )?} $($ann)*) } )* } @@ -256,3 +96,223 @@ impl Operator<'_> { crate::for_each_operator!(define_arity) } } + +fn visit_block(module: &dyn ModuleArity, block: BlockType) -> Option<(u32, u32)> { + let (params, _) = module.block_type_arity(block)?; + Some((params, params)) +} + +fn visit_loop(module: &dyn ModuleArity, block: BlockType) -> Option<(u32, u32)> { + visit_block(module, block) +} + +fn visit_if(module: &dyn ModuleArity, block: BlockType) -> Option<(u32, u32)> { + let (params, results) = visit_block(module, block)?; + Some((params + 1, results)) +} + +fn visit_else(module: &dyn ModuleArity) -> Option<(u32, u32)> { + let (ty, _kind) = module.label_block(0)?; + let (params, results) = module.block_type_arity(ty)?; + Some((results, params)) +} + +fn visit_end(module: &dyn ModuleArity) -> Option<(u32, u32)> { + let (ty, _kind) = module.label_block(0)?; + let (_params, results) = module.block_type_arity(ty)?; + Some((results, results)) +} + +fn visit_br(module: &dyn ModuleArity, depth: u32) -> Option<(u32, u32)> { + let (ty, kind) = module.label_block(depth)?; + let (params, results) = module.block_type_arity(ty)?; + let n = match kind { + FrameKind::Loop => params, + _ => results, + }; + Some((n, 0)) +} + +fn visit_br_if(module: &dyn ModuleArity, depth: u32) -> Option<(u32, u32)> { + let (params, _) = visit_br(module, depth)?; + Some((params + 1, params)) +} + +fn visit_br_table(module: &dyn ModuleArity, table: BrTable<'_>) -> Option<(u32, u32)> { + let (params, results) = visit_br(module, table.default())?; + Some((params + 1, results)) +} + +fn visit_return(module: &dyn ModuleArity) -> Option<(u32, u32)> { + let height = module.control_stack_height().checked_sub(1)?; + let (ty, _) = module.label_block(height)?; + let (_, results) = module.block_type_arity(ty)?; + Some((results, 0)) +} + +fn visit_call(module: &dyn ModuleArity, func: u32) -> Option<(u32, u32)> { + module.sub_type_arity(module.sub_type_at(module.type_index_of_function(func)?)?) +} + +fn visit_call_indirect(module: &dyn ModuleArity, ty: u32, _table: u32) -> Option<(u32, u32)> { + let (params, results) = module.sub_type_arity(module.sub_type_at(ty)?)?; + Some((params + 1, results)) +} + +fn visit_struct_new(module: &dyn ModuleArity, ty: u32) -> Option<(u32, u32)> { + let ty = module.sub_type_at(ty)?; + let (params, _results) = module.sub_type_arity(ty)?; + Some((params, 1)) +} + +fn visit_struct_new_desc(module: &dyn ModuleArity, ty: u32) -> Option<(u32, u32)> { + let ty = module.sub_type_at(ty)?; + let (params, _results) = module.sub_type_arity(ty)?; + Some((params + 1, 1)) +} + +fn visit_array_new_fixed(_module: &dyn ModuleArity, _ty: u32, size: u32) -> Option<(u32, u32)> { + Some((size, 1)) +} + +fn visit_br_on_cast( + module: &dyn ModuleArity, + depth: u32, + _from: RefType, + _to: RefType, +) -> Option<(u32, u32)> { + let (params, _) = visit_br(module, depth)?; + Some((params, params)) +} + +fn visit_br_on_cast_fail( + module: &dyn ModuleArity, + depth: u32, + _from: RefType, + _to: RefType, +) -> Option<(u32, u32)> { + let (params, _) = visit_br(module, depth)?; + Some((params, params)) +} + +fn visit_typed_select_multi(_module: &dyn ModuleArity, tys: Vec<ValType>) -> Option<(u32, u32)> { + let len = u32::try_from(tys.len()).unwrap(); + Some((1 + 2 * len, len)) +} + +fn visit_return_call(module: &dyn ModuleArity, func: u32) -> Option<(u32, u32)> { + let (params, _) = visit_call(module, func)?; + Some((params, 0)) +} + +fn visit_return_call_indirect(module: &dyn ModuleArity, ty: u32, table: u32) -> Option<(u32, u32)> { + let (params, _) = visit_call_indirect(module, ty, table)?; + Some((params, 0)) +} + +fn visit_try_table(module: &dyn ModuleArity, table: TryTable) -> Option<(u32, u32)> { + let (params, _) = module.block_type_arity(table.ty)?; + Some((params, params)) +} + +fn visit_throw(module: &dyn ModuleArity, tag: u32) -> Option<(u32, u32)> { + let (params, _) = module.tag_type_arity(tag)?; + Some((params, 0)) +} + +fn visit_try(module: &dyn ModuleArity, ty: BlockType) -> Option<(u32, u32)> { + visit_block(module, ty) +} + +fn visit_catch(module: &dyn ModuleArity, tag: u32) -> Option<(u32, u32)> { + let (params, _) = visit_end(module)?; + let (tag_params, _) = module.tag_type_arity(tag)?; + Some((params, tag_params)) +} + +fn visit_delegate(module: &dyn ModuleArity, _depth: u32) -> Option<(u32, u32)> { + visit_end(module) +} + +fn visit_catch_all(module: &dyn ModuleArity) -> Option<(u32, u32)> { + let (params, _) = visit_end(module)?; + Some((params, 0)) +} + +fn visit_call_ref(module: &dyn ModuleArity, ty: u32) -> Option<(u32, u32)> { + let (params, results) = module.sub_type_arity(module.sub_type_at(ty)?)?; + Some((params + 1, results)) +} + +fn visit_return_call_ref(module: &dyn ModuleArity, ty: u32) -> Option<(u32, u32)> { + let (params, _) = visit_call_ref(module, ty)?; + Some((params, 0)) +} + +fn visit_br_on_null(module: &dyn ModuleArity, depth: u32) -> Option<(u32, u32)> { + let (params, _results) = visit_br(module, depth)?; + Some((params + 1, params + 1)) +} + +fn visit_br_on_non_null(module: &dyn ModuleArity, depth: u32) -> Option<(u32, u32)> { + let (params, _results) = visit_br(module, depth)?; + Some((params, params.checked_sub(1)?)) +} + +fn visit_cont_bind(module: &dyn ModuleArity, arg: u32, result: u32) -> Option<(u32, u32)> { + let (arg_params, _) = module.sub_type_arity(module.sub_type_at(arg)?)?; + let (result_params, _) = module.sub_type_arity(module.sub_type_at(result)?)?; + Some((arg_params.checked_sub(result_params)? + 1, 1)) +} + +fn visit_suspend(module: &dyn ModuleArity, tag: u32) -> Option<(u32, u32)> { + module.tag_type_arity(tag) +} + +fn visit_resume(module: &dyn ModuleArity, cont: u32, _table: ResumeTable) -> Option<(u32, u32)> { + let (params, results) = module.sub_type_arity(module.sub_type_at(cont)?)?; + Some((params + 1, results)) +} + +fn visit_resume_throw( + module: &dyn ModuleArity, + cont: u32, + tag: u32, + _table: ResumeTable, +) -> Option<(u32, u32)> { + let (params, _) = module.tag_type_arity(tag)?; + let (_, results) = module.sub_type_arity(module.sub_type_at(cont)?)?; + Some((params + 1, results)) +} + +fn visit_switch(module: &dyn ModuleArity, cont: u32, _tag: u32) -> Option<(u32, u32)> { + let (params, _) = module.sub_type_arity(module.sub_type_at(cont)?)?; + let st = &module.sub_type_at(cont)?.composite_type.inner; + let CompositeInnerType::Cont(ct) = &st else { + return None; + }; + let last_param = module.func_type_of_cont_type(ct)?.params().last()?; + let (cont_params, _) = + module.sub_type_arity(module.sub_type_of_ref_type(&last_param.as_reference_type()?)?)?; + Some((params, cont_params)) +} + +fn visit_br_on_cast_desc( + module: &dyn ModuleArity, + depth: u32, + _from: RefType, + _to: RefType, +) -> Option<(u32, u32)> { + let (params, _) = visit_br(module, depth)?; + Some((params + 1, params)) +} + +fn visit_br_on_cast_desc_fail( + module: &dyn ModuleArity, + depth: u32, + _from: RefType, + _to: RefType, +) -> Option<(u32, u32)> { + let (params, _) = visit_br(module, depth)?; + Some((params + 1, params)) +} diff --git a/third_party/rust/wasmparser/src/binary_reader.rs b/third_party/rust/wasmparser/src/binary_reader.rs @@ -13,9 +13,6 @@ * limitations under the License. */ -#[cfg(feature = "simd")] -mod simd; - use crate::prelude::*; use crate::{limits::*, *}; use core::fmt; @@ -159,7 +156,7 @@ impl<'a> BinaryReader<'a> { /// The returned binary reader will have all features known to this crate /// enabled. To reject binaries that aren't valid unless a certain feature /// is enabled use the [`BinaryReader::new_features`] constructor instead. - pub fn new(data: &[u8], original_offset: usize) -> BinaryReader { + pub fn new(data: &[u8], original_offset: usize) -> BinaryReader<'_> { BinaryReader { buffer: data, position: 0, @@ -178,7 +175,7 @@ impl<'a> BinaryReader<'a> { /// /// The `features` argument provided controls which WebAssembly features are /// active when parsing this data. Wasm features typically don't affect - /// parsing too too much and are generally more applicable during + /// parsing too much and are generally more applicable during /// validation, but features and proposals will often reinterpret /// previously-invalid constructs as now-valid things meaning something /// slightly different. This means that invalid bytes before a feature may @@ -204,7 +201,7 @@ impl<'a> BinaryReader<'a> { data: &[u8], original_offset: usize, features: WasmFeatures, - ) -> BinaryReader { + ) -> BinaryReader<'_> { BinaryReader { buffer: data, position: 0, @@ -310,6 +307,7 @@ impl<'a> BinaryReader<'a> { 0x02 => Ok(ExternalKind::Memory), 0x03 => Ok(ExternalKind::Global), 0x04 => Ok(ExternalKind::Tag), + 0x20 => Ok(ExternalKind::FuncExact), x => Err(Self::invalid_leading_byte_error(x, "external kind", offset)), } } @@ -348,65 +346,6 @@ impl<'a> BinaryReader<'a> { }) } - fn read_memarg(&mut self, max_align: u8) -> Result<MemArg> { - let flags_pos = self.original_position(); - let mut flags = self.read_var_u32()?; - - let memory = if self.multi_memory() && flags & (1 << 6) != 0 { - flags ^= 1 << 6; - self.read_var_u32()? - } else { - 0 - }; - let align = if flags >= (1 << 6) { - return Err(BinaryReaderError::new( - "malformed memop alignment: alignment too large", - flags_pos, - )); - } else { - flags as u8 - }; - let offset = if self.memory64() { - self.read_var_u64()? - } else { - u64::from(self.read_var_u32()?) - }; - Ok(MemArg { - align, - max_align, - offset, - memory, - }) - } - - fn read_ordering(&mut self) -> Result<Ordering> { - let byte = self.read_var_u32()?; - match byte { - 0 => Ok(Ordering::SeqCst), - 1 => Ok(Ordering::AcqRel), - x => Err(BinaryReaderError::new( - &format!("invalid atomic consistency ordering {}", x), - self.original_position() - 1, - )), - } - } - - fn read_br_table(&mut self) -> Result<BrTable<'a>> { - let cnt = self.read_size(MAX_WASM_BR_TABLE_SIZE, "br_table")?; - let reader = self.skip(|reader| { - for _ in 0..cnt { - reader.read_var_u32()?; - } - Ok(()) - })?; - let default = self.read_var_u32()?; - Ok(BrTable { - reader, - cnt: cnt as u32, - default, - }) - } - /// Returns whether the `BinaryReader` has reached the end of the file. #[inline] pub fn eof(&self) -> bool { @@ -798,6 +737,11 @@ impl<'a> BinaryReader<'a> { Ok(self.buffer[self.position]) } + pub(crate) fn peek_bytes(&self, len: usize) -> Result<&[u8]> { + self.ensure_has_bytes(len)?; + Ok(&self.buffer[self.position..(self.position + len)]) + } + pub(crate) fn read_block_type(&mut self) -> Result<BlockType> { let b = self.peek()?; @@ -838,66 +782,173 @@ impl<'a> BinaryReader<'a> { } } - /// Visit the next available operator with the specified [`VisitOperator`] instance. - /// - /// Note that this does not implicitly propagate any additional information such as instruction - /// offsets. In order to do so, consider storing such data within the visitor before visiting. - /// - /// # Errors - /// - /// If `BinaryReader` has less bytes remaining than required to parse the `Operator`. - /// - /// # Examples - /// - /// Store an offset for use in diagnostics or any other purposes: - /// - /// ``` - /// # use wasmparser::{BinaryReader, VisitOperator, Result, for_each_visit_operator}; - /// - /// pub fn dump(mut reader: BinaryReader) -> Result<()> { - /// let mut visitor = Dumper { offset: 0 }; - /// while !reader.eof() { - /// visitor.offset = reader.original_position(); - /// reader.visit_operator(&mut visitor)?; - /// } - /// Ok(()) - /// } - /// - /// struct Dumper { - /// offset: usize - /// } - /// - /// macro_rules! define_visit_operator { - /// ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => { - /// $( - /// fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output { - /// println!("{}: {}", self.offset, stringify!($visit)); - /// } - /// )* - /// } - /// } - /// - /// impl<'a> VisitOperator<'a> for Dumper { - /// type Output = (); - /// for_each_visit_operator!(define_visit_operator); - /// } + /// Returns whether there is an `end` opcode followed by eof remaining in + /// this reader. + pub fn is_end_then_eof(&self) -> bool { + self.remaining_buffer() == &[0x0b] + } + + pub(crate) fn read_header_version(&mut self) -> Result<u32> { + let magic_number = self.read_bytes(4)?; + if magic_number != WASM_MAGIC_NUMBER { + return Err(BinaryReaderError::new( + format!( + "magic header not detected: bad magic number - expected={WASM_MAGIC_NUMBER:#x?} actual={magic_number:#x?}" + ), + self.original_position() - 4, + )); + } + self.read_u32() + } +} + +// See documentation on `BinaryReader::features` for more on what's going on +// here. +macro_rules! define_feature_accessor { + ($feature:ident = $default:expr) => { + impl BinaryReader<'_> { + #[inline] + #[allow(dead_code)] + pub(crate) fn $feature(&self) -> bool { + #[cfg(feature = "features")] + { + self.features.$feature() + } + #[cfg(not(feature = "features"))] + { + true + } + } + } + }; +} + +super::features::foreach_wasm_feature!(define_feature_accessor); + +/// Iterator returned from [`BinaryReader::read_iter`]. +pub struct BinaryReaderIter<'a, 'me, T: FromReader<'a>> { + remaining: usize, + pub(crate) reader: &'me mut BinaryReader<'a>, + _marker: marker::PhantomData<T>, +} + +impl<'a, T> Iterator for BinaryReaderIter<'a, '_, T> +where + T: FromReader<'a>, +{ + type Item = Result<T>; + + fn next(&mut self) -> Option<Result<T>> { + if self.remaining == 0 { + None + } else { + let ret = self.reader.read::<T>(); + if ret.is_err() { + self.remaining = 0; + } else { + self.remaining -= 1; + } + Some(ret) + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.remaining, Some(self.remaining)) + } +} + +impl<'a, T> Drop for BinaryReaderIter<'a, '_, T> +where + T: FromReader<'a>, +{ + fn drop(&mut self) { + while self.next().is_some() { + // ... + } + } +} + +impl<'a> BinaryReader<'a> { + /// Function that must be called after the last opcode in an expression (instruction sequence) + /// has been processed. Returns an error if there is extra data after the operators. + pub fn finish_expression(&self, stack: &impl FrameStack) -> Result<()> { + if stack.current_frame().is_some() { + bail!( + self.original_position(), + "control frames remain at end of function body or expression" + ); + } + if !self.eof() { + bail!( + self.original_position(), + "unexpected data at the end of operators" + ); + } + Ok(()) + } + + #[inline] + fn expect_frame(&mut self, stack: &impl FrameStack, k: FrameKind, found: &str) -> Result<()> { + if stack.current_frame() == Some(k) { + return Ok(()); + } + bail!( + self.original_position(), + "`{}` found outside `{:?}` block", + found, + k + ); + } + + /// Visit the next available operator with the specified [`VisitOperator`] instance + /// that is also a [`FrameStack`]. /// - /// ``` + /// See the documentation for [`OperatorsReader::visit_operator`] for a version that + /// does not require the visitor to implement [`FrameStack`]. pub fn visit_operator<T>(&mut self, visitor: &mut T) -> Result<<T as VisitOperator<'a>>::Output> where - T: VisitOperator<'a>, + T: VisitOperator<'a> + FrameStack, { + if visitor.current_frame().is_none() { + bail!( + self.original_position(), + "operators remaining after end of function body or expression" + ); + } let pos = self.original_position(); - let code = self.read_u8()? as u8; + let code = self.read_u8()?; Ok(match code { 0x00 => visitor.visit_unreachable(), 0x01 => visitor.visit_nop(), 0x02 => visitor.visit_block(self.read_block_type()?), 0x03 => visitor.visit_loop(self.read_block_type()?), 0x04 => visitor.visit_if(self.read_block_type()?), - 0x05 => visitor.visit_else(), - 0x06 => visitor.visit_try(self.read_block_type()?), - 0x07 => visitor.visit_catch(self.read_var_u32()?), + 0x05 => { + self.expect_frame(visitor, FrameKind::If, "else")?; + visitor.visit_else() + } + 0x06 => { + if !self.legacy_exceptions() { + bail!( + pos, + "legacy_exceptions feature required for try instruction" + ); + } + visitor.visit_try(self.read_block_type()?) + } + 0x07 => { + if !self.legacy_exceptions() { + bail!( + pos, + "legacy_exceptions feature required for catch instruction" + ); + } + match self.expect_frame(visitor, FrameKind::LegacyCatch, "catch") { + Ok(()) => (), + Err(_) => self.expect_frame(visitor, FrameKind::LegacyTry, "catch")?, + } + visitor.visit_catch(self.read_var_u32()?) + } 0x08 => visitor.visit_throw(self.read_var_u32()?), 0x09 => visitor.visit_rethrow(self.read_var_u32()?), 0x0a => visitor.visit_throw_ref(), @@ -909,26 +960,44 @@ impl<'a> BinaryReader<'a> { 0x10 => visitor.visit_call(self.read_var_u32()?), 0x11 => { let index = self.read_var_u32()?; - let table = self.read_table_index_or_zero_if_not_reference_types()?; + let table = self.read_call_indirect_table_immediate()?; visitor.visit_call_indirect(index, table) } 0x12 => visitor.visit_return_call(self.read_var_u32()?), 0x13 => visitor.visit_return_call_indirect(self.read_var_u32()?, self.read_var_u32()?), 0x14 => visitor.visit_call_ref(self.read()?), 0x15 => visitor.visit_return_call_ref(self.read()?), - 0x18 => visitor.visit_delegate(self.read_var_u32()?), - 0x19 => visitor.visit_catch_all(), + 0x18 => { + self.expect_frame(visitor, FrameKind::LegacyTry, "delegate")?; + visitor.visit_delegate(self.read_var_u32()?) + } + 0x19 => { + if !self.legacy_exceptions() { + bail!( + pos, + "legacy_exceptions feature required for catch_all instruction" + ); + } + match self.expect_frame(visitor, FrameKind::LegacyCatch, "catch_all") { + Ok(()) => (), + Err(_) => self.expect_frame(visitor, FrameKind::LegacyTry, "catch_all")?, + } + visitor.visit_catch_all() + } 0x1a => visitor.visit_drop(), 0x1b => visitor.visit_select(), 0x1c => { - let results = self.read_var_u32()?; - if results != 1 { - return Err(BinaryReaderError::new( - "invalid result arity", - self.position, - )); + let result_count = self.read_size(MAX_WASM_SELECT_RESULT_SIZE, "select types")?; + if result_count == 1 { + visitor.visit_typed_select(self.read()?) + } else { + let mut results = Vec::new(); + results.reserve_exact(result_count); + for _ in 0..result_count { + results.push(self.read()?); + } + visitor.visit_typed_select_multi(results) } - visitor.visit_typed_select(self.read()?) } 0x1f => visitor.visit_try_table(self.read()?), @@ -1294,6 +1363,64 @@ impl<'a> BinaryReader<'a> { 0x1d => visitor.visit_i31_get_s(), 0x1e => visitor.visit_i31_get_u(), + 0x20 => { + let type_index = self.read_var_u32()?; + visitor.visit_struct_new_desc(type_index) + } + 0x21 => { + let type_index = self.read_var_u32()?; + visitor.visit_struct_new_default_desc(type_index) + } + 0x22 => visitor.visit_ref_get_desc(self.read()?), + 0x23 => visitor.visit_ref_cast_desc_non_null(self.read()?), + 0x24 => visitor.visit_ref_cast_desc_nullable(self.read()?), + 0x25 => { + let pos = self.original_position(); + let cast_flags = self.read_u8()?; + let relative_depth = self.read_var_u32()?; + let (from_type_nullable, to_type_nullable) = match cast_flags { + 0b00 => (false, false), + 0b01 => (true, false), + 0b10 => (false, true), + 0b11 => (true, true), + _ => bail!(pos, "invalid cast flags: {cast_flags:08b}"), + }; + let from_heap_type = self.read()?; + let from_ref_type = + RefType::new(from_type_nullable, from_heap_type).ok_or_else(|| { + format_err!(pos, "implementation error: type index too large") + })?; + let to_heap_type = self.read()?; + let to_ref_type = + RefType::new(to_type_nullable, to_heap_type).ok_or_else(|| { + format_err!(pos, "implementation error: type index too large") + })?; + visitor.visit_br_on_cast_desc(relative_depth, from_ref_type, to_ref_type) + } + 0x26 => { + let pos = self.original_position(); + let cast_flags = self.read_u8()?; + let relative_depth = self.read_var_u32()?; + let (from_type_nullable, to_type_nullable) = match cast_flags { + 0 => (false, false), + 1 => (true, false), + 2 => (false, true), + 3 => (true, true), + _ => bail!(pos, "invalid cast flags: {cast_flags:08b}"), + }; + let from_heap_type = self.read()?; + let from_ref_type = + RefType::new(from_type_nullable, from_heap_type).ok_or_else(|| { + format_err!(pos, "implementation error: type index too large") + })?; + let to_heap_type = self.read()?; + let to_ref_type = + RefType::new(to_type_nullable, to_heap_type).ok_or_else(|| { + format_err!(pos, "implementation error: type index too large") + })?; + visitor.visit_br_on_cast_desc_fail(relative_depth, from_ref_type, to_ref_type) + } + _ => bail!(pos, "unknown 0xfb subopcode: 0x{code:x}"), }) } @@ -1378,6 +1505,323 @@ impl<'a> BinaryReader<'a> { }) } + #[cfg(feature = "simd")] + pub(super) fn visit_0xfd_operator<T>( + &mut self, + pos: usize, + visitor: &mut T, + ) -> Result<<T as VisitOperator<'a>>::Output> + where + T: VisitSimdOperator<'a>, + { + let code = self.read_var_u32()?; + Ok(match code { + 0x00 => visitor.visit_v128_load(self.read_memarg(4)?), + 0x01 => visitor.visit_v128_load8x8_s(self.read_memarg(3)?), + 0x02 => visitor.visit_v128_load8x8_u(self.read_memarg(3)?), + 0x03 => visitor.visit_v128_load16x4_s(self.read_memarg(3)?), + 0x04 => visitor.visit_v128_load16x4_u(self.read_memarg(3)?), + 0x05 => visitor.visit_v128_load32x2_s(self.read_memarg(3)?), + 0x06 => visitor.visit_v128_load32x2_u(self.read_memarg(3)?), + 0x07 => visitor.visit_v128_load8_splat(self.read_memarg(0)?), + 0x08 => visitor.visit_v128_load16_splat(self.read_memarg(1)?), + 0x09 => visitor.visit_v128_load32_splat(self.read_memarg(2)?), + 0x0a => visitor.visit_v128_load64_splat(self.read_memarg(3)?), + + 0x0b => visitor.visit_v128_store(self.read_memarg(4)?), + 0x0c => visitor.visit_v128_const(self.read_v128()?), + 0x0d => { + let mut lanes: [u8; 16] = [0; 16]; + for lane in &mut lanes { + *lane = self.read_lane_index()? + } + visitor.visit_i8x16_shuffle(lanes) + } + + 0x0e => visitor.visit_i8x16_swizzle(), + 0x0f => visitor.visit_i8x16_splat(), + 0x10 => visitor.visit_i16x8_splat(), + 0x11 => visitor.visit_i32x4_splat(), + 0x12 => visitor.visit_i64x2_splat(), + 0x13 => visitor.visit_f32x4_splat(), + 0x14 => visitor.visit_f64x2_splat(), + + 0x15 => visitor.visit_i8x16_extract_lane_s(self.read_lane_index()?), + 0x16 => visitor.visit_i8x16_extract_lane_u(self.read_lane_index()?), + 0x17 => visitor.visit_i8x16_replace_lane(self.read_lane_index()?), + 0x18 => visitor.visit_i16x8_extract_lane_s(self.read_lane_index()?), + 0x19 => visitor.visit_i16x8_extract_lane_u(self.read_lane_index()?), + 0x1a => visitor.visit_i16x8_replace_lane(self.read_lane_index()?), + 0x1b => visitor.visit_i32x4_extract_lane(self.read_lane_index()?), + + 0x1c => visitor.visit_i32x4_replace_lane(self.read_lane_index()?), + 0x1d => visitor.visit_i64x2_extract_lane(self.read_lane_index()?), + 0x1e => visitor.visit_i64x2_replace_lane(self.read_lane_index()?), + 0x1f => visitor.visit_f32x4_extract_lane(self.read_lane_index()?), + 0x20 => visitor.visit_f32x4_replace_lane(self.read_lane_index()?), + 0x21 => visitor.visit_f64x2_extract_lane(self.read_lane_index()?), + 0x22 => visitor.visit_f64x2_replace_lane(self.read_lane_index()?), + + 0x23 => visitor.visit_i8x16_eq(), + 0x24 => visitor.visit_i8x16_ne(), + 0x25 => visitor.visit_i8x16_lt_s(), + 0x26 => visitor.visit_i8x16_lt_u(), + 0x27 => visitor.visit_i8x16_gt_s(), + 0x28 => visitor.visit_i8x16_gt_u(), + 0x29 => visitor.visit_i8x16_le_s(), + 0x2a => visitor.visit_i8x16_le_u(), + 0x2b => visitor.visit_i8x16_ge_s(), + 0x2c => visitor.visit_i8x16_ge_u(), + 0x2d => visitor.visit_i16x8_eq(), + 0x2e => visitor.visit_i16x8_ne(), + 0x2f => visitor.visit_i16x8_lt_s(), + 0x30 => visitor.visit_i16x8_lt_u(), + 0x31 => visitor.visit_i16x8_gt_s(), + 0x32 => visitor.visit_i16x8_gt_u(), + 0x33 => visitor.visit_i16x8_le_s(), + 0x34 => visitor.visit_i16x8_le_u(), + 0x35 => visitor.visit_i16x8_ge_s(), + 0x36 => visitor.visit_i16x8_ge_u(), + 0x37 => visitor.visit_i32x4_eq(), + 0x38 => visitor.visit_i32x4_ne(), + 0x39 => visitor.visit_i32x4_lt_s(), + 0x3a => visitor.visit_i32x4_lt_u(), + 0x3b => visitor.visit_i32x4_gt_s(), + 0x3c => visitor.visit_i32x4_gt_u(), + 0x3d => visitor.visit_i32x4_le_s(), + 0x3e => visitor.visit_i32x4_le_u(), + 0x3f => visitor.visit_i32x4_ge_s(), + 0x40 => visitor.visit_i32x4_ge_u(), + 0x41 => visitor.visit_f32x4_eq(), + 0x42 => visitor.visit_f32x4_ne(), + 0x43 => visitor.visit_f32x4_lt(), + 0x44 => visitor.visit_f32x4_gt(), + 0x45 => visitor.visit_f32x4_le(), + 0x46 => visitor.visit_f32x4_ge(), + 0x47 => visitor.visit_f64x2_eq(), + 0x48 => visitor.visit_f64x2_ne(), + 0x49 => visitor.visit_f64x2_lt(), + 0x4a => visitor.visit_f64x2_gt(), + 0x4b => visitor.visit_f64x2_le(), + 0x4c => visitor.visit_f64x2_ge(), + 0x4d => visitor.visit_v128_not(), + 0x4e => visitor.visit_v128_and(), + 0x4f => visitor.visit_v128_andnot(), + 0x50 => visitor.visit_v128_or(), + 0x51 => visitor.visit_v128_xor(), + 0x52 => visitor.visit_v128_bitselect(), + 0x53 => visitor.visit_v128_any_true(), + + 0x54 => { + let memarg = self.read_memarg(0)?; + let lane = self.read_lane_index()?; + visitor.visit_v128_load8_lane(memarg, lane) + } + 0x55 => { + let memarg = self.read_memarg(1)?; + let lane = self.read_lane_index()?; + visitor.visit_v128_load16_lane(memarg, lane) + } + 0x56 => { + let memarg = self.read_memarg(2)?; + let lane = self.read_lane_index()?; + visitor.visit_v128_load32_lane(memarg, lane) + } + 0x57 => { + let memarg = self.read_memarg(3)?; + let lane = self.read_lane_index()?; + visitor.visit_v128_load64_lane(memarg, lane) + } + 0x58 => { + let memarg = self.read_memarg(0)?; + let lane = self.read_lane_index()?; + visitor.visit_v128_store8_lane(memarg, lane) + } + 0x59 => { + let memarg = self.read_memarg(1)?; + let lane = self.read_lane_index()?; + visitor.visit_v128_store16_lane(memarg, lane) + } + 0x5a => { + let memarg = self.read_memarg(2)?; + let lane = self.read_lane_index()?; + visitor.visit_v128_store32_lane(memarg, lane) + } + 0x5b => { + let memarg = self.read_memarg(3)?; + let lane = self.read_lane_index()?; + visitor.visit_v128_store64_lane(memarg, lane) + } + + 0x5c => visitor.visit_v128_load32_zero(self.read_memarg(2)?), + 0x5d => visitor.visit_v128_load64_zero(self.read_memarg(3)?), + 0x5e => visitor.visit_f32x4_demote_f64x2_zero(), + 0x5f => visitor.visit_f64x2_promote_low_f32x4(), + 0x60 => visitor.visit_i8x16_abs(), + 0x61 => visitor.visit_i8x16_neg(), + 0x62 => visitor.visit_i8x16_popcnt(), + 0x63 => visitor.visit_i8x16_all_true(), + 0x64 => visitor.visit_i8x16_bitmask(), + 0x65 => visitor.visit_i8x16_narrow_i16x8_s(), + 0x66 => visitor.visit_i8x16_narrow_i16x8_u(), + 0x67 => visitor.visit_f32x4_ceil(), + 0x68 => visitor.visit_f32x4_floor(), + 0x69 => visitor.visit_f32x4_trunc(), + 0x6a => visitor.visit_f32x4_nearest(), + 0x6b => visitor.visit_i8x16_shl(), + 0x6c => visitor.visit_i8x16_shr_s(), + 0x6d => visitor.visit_i8x16_shr_u(), + 0x6e => visitor.visit_i8x16_add(), + 0x6f => visitor.visit_i8x16_add_sat_s(), + 0x70 => visitor.visit_i8x16_add_sat_u(), + 0x71 => visitor.visit_i8x16_sub(), + 0x72 => visitor.visit_i8x16_sub_sat_s(), + 0x73 => visitor.visit_i8x16_sub_sat_u(), + 0x74 => visitor.visit_f64x2_ceil(), + 0x75 => visitor.visit_f64x2_floor(), + 0x76 => visitor.visit_i8x16_min_s(), + 0x77 => visitor.visit_i8x16_min_u(), + 0x78 => visitor.visit_i8x16_max_s(), + 0x79 => visitor.visit_i8x16_max_u(), + 0x7a => visitor.visit_f64x2_trunc(), + 0x7b => visitor.visit_i8x16_avgr_u(), + 0x7c => visitor.visit_i16x8_extadd_pairwise_i8x16_s(), + 0x7d => visitor.visit_i16x8_extadd_pairwise_i8x16_u(), + 0x7e => visitor.visit_i32x4_extadd_pairwise_i16x8_s(), + 0x7f => visitor.visit_i32x4_extadd_pairwise_i16x8_u(), + 0x80 => visitor.visit_i16x8_abs(), + 0x81 => visitor.visit_i16x8_neg(), + 0x82 => visitor.visit_i16x8_q15mulr_sat_s(), + 0x83 => visitor.visit_i16x8_all_true(), + 0x84 => visitor.visit_i16x8_bitmask(), + 0x85 => visitor.visit_i16x8_narrow_i32x4_s(), + 0x86 => visitor.visit_i16x8_narrow_i32x4_u(), + 0x87 => visitor.visit_i16x8_extend_low_i8x16_s(), + 0x88 => visitor.visit_i16x8_extend_high_i8x16_s(), + 0x89 => visitor.visit_i16x8_extend_low_i8x16_u(), + 0x8a => visitor.visit_i16x8_extend_high_i8x16_u(), + 0x8b => visitor.visit_i16x8_shl(), + 0x8c => visitor.visit_i16x8_shr_s(), + 0x8d => visitor.visit_i16x8_shr_u(), + 0x8e => visitor.visit_i16x8_add(), + 0x8f => visitor.visit_i16x8_add_sat_s(), + 0x90 => visitor.visit_i16x8_add_sat_u(), + 0x91 => visitor.visit_i16x8_sub(), + 0x92 => visitor.visit_i16x8_sub_sat_s(), + 0x93 => visitor.visit_i16x8_sub_sat_u(), + 0x94 => visitor.visit_f64x2_nearest(), + 0x95 => visitor.visit_i16x8_mul(), + 0x96 => visitor.visit_i16x8_min_s(), + 0x97 => visitor.visit_i16x8_min_u(), + 0x98 => visitor.visit_i16x8_max_s(), + 0x99 => visitor.visit_i16x8_max_u(), + 0x9b => visitor.visit_i16x8_avgr_u(), + 0x9c => visitor.visit_i16x8_extmul_low_i8x16_s(), + 0x9d => visitor.visit_i16x8_extmul_high_i8x16_s(), + 0x9e => visitor.visit_i16x8_extmul_low_i8x16_u(), + 0x9f => visitor.visit_i16x8_extmul_high_i8x16_u(), + 0xa0 => visitor.visit_i32x4_abs(), + 0xa1 => visitor.visit_i32x4_neg(), + 0xa3 => visitor.visit_i32x4_all_true(), + 0xa4 => visitor.visit_i32x4_bitmask(), + 0xa7 => visitor.visit_i32x4_extend_low_i16x8_s(), + 0xa8 => visitor.visit_i32x4_extend_high_i16x8_s(), + 0xa9 => visitor.visit_i32x4_extend_low_i16x8_u(), + 0xaa => visitor.visit_i32x4_extend_high_i16x8_u(), + 0xab => visitor.visit_i32x4_shl(), + 0xac => visitor.visit_i32x4_shr_s(), + 0xad => visitor.visit_i32x4_shr_u(), + 0xae => visitor.visit_i32x4_add(), + 0xb1 => visitor.visit_i32x4_sub(), + 0xb5 => visitor.visit_i32x4_mul(), + 0xb6 => visitor.visit_i32x4_min_s(), + 0xb7 => visitor.visit_i32x4_min_u(), + 0xb8 => visitor.visit_i32x4_max_s(), + 0xb9 => visitor.visit_i32x4_max_u(), + 0xba => visitor.visit_i32x4_dot_i16x8_s(), + 0xbc => visitor.visit_i32x4_extmul_low_i16x8_s(), + 0xbd => visitor.visit_i32x4_extmul_high_i16x8_s(), + 0xbe => visitor.visit_i32x4_extmul_low_i16x8_u(), + 0xbf => visitor.visit_i32x4_extmul_high_i16x8_u(), + 0xc0 => visitor.visit_i64x2_abs(), + 0xc1 => visitor.visit_i64x2_neg(), + 0xc3 => visitor.visit_i64x2_all_true(), + 0xc4 => visitor.visit_i64x2_bitmask(), + 0xc7 => visitor.visit_i64x2_extend_low_i32x4_s(), + 0xc8 => visitor.visit_i64x2_extend_high_i32x4_s(), + 0xc9 => visitor.visit_i64x2_extend_low_i32x4_u(), + 0xca => visitor.visit_i64x2_extend_high_i32x4_u(), + 0xcb => visitor.visit_i64x2_shl(), + 0xcc => visitor.visit_i64x2_shr_s(), + 0xcd => visitor.visit_i64x2_shr_u(), + 0xce => visitor.visit_i64x2_add(), + 0xd1 => visitor.visit_i64x2_sub(), + 0xd5 => visitor.visit_i64x2_mul(), + 0xd6 => visitor.visit_i64x2_eq(), + 0xd7 => visitor.visit_i64x2_ne(), + 0xd8 => visitor.visit_i64x2_lt_s(), + 0xd9 => visitor.visit_i64x2_gt_s(), + 0xda => visitor.visit_i64x2_le_s(), + 0xdb => visitor.visit_i64x2_ge_s(), + 0xdc => visitor.visit_i64x2_extmul_low_i32x4_s(), + 0xdd => visitor.visit_i64x2_extmul_high_i32x4_s(), + 0xde => visitor.visit_i64x2_extmul_low_i32x4_u(), + 0xdf => visitor.visit_i64x2_extmul_high_i32x4_u(), + 0xe0 => visitor.visit_f32x4_abs(), + 0xe1 => visitor.visit_f32x4_neg(), + 0xe3 => visitor.visit_f32x4_sqrt(), + 0xe4 => visitor.visit_f32x4_add(), + 0xe5 => visitor.visit_f32x4_sub(), + 0xe6 => visitor.visit_f32x4_mul(), + 0xe7 => visitor.visit_f32x4_div(), + 0xe8 => visitor.visit_f32x4_min(), + 0xe9 => visitor.visit_f32x4_max(), + 0xea => visitor.visit_f32x4_pmin(), + 0xeb => visitor.visit_f32x4_pmax(), + 0xec => visitor.visit_f64x2_abs(), + 0xed => visitor.visit_f64x2_neg(), + 0xef => visitor.visit_f64x2_sqrt(), + 0xf0 => visitor.visit_f64x2_add(), + 0xf1 => visitor.visit_f64x2_sub(), + 0xf2 => visitor.visit_f64x2_mul(), + 0xf3 => visitor.visit_f64x2_div(), + 0xf4 => visitor.visit_f64x2_min(), + 0xf5 => visitor.visit_f64x2_max(), + 0xf6 => visitor.visit_f64x2_pmin(), + 0xf7 => visitor.visit_f64x2_pmax(), + 0xf8 => visitor.visit_i32x4_trunc_sat_f32x4_s(), + 0xf9 => visitor.visit_i32x4_trunc_sat_f32x4_u(), + 0xfa => visitor.visit_f32x4_convert_i32x4_s(), + 0xfb => visitor.visit_f32x4_convert_i32x4_u(), + 0xfc => visitor.visit_i32x4_trunc_sat_f64x2_s_zero(), + 0xfd => visitor.visit_i32x4_trunc_sat_f64x2_u_zero(), + 0xfe => visitor.visit_f64x2_convert_low_i32x4_s(), + 0xff => visitor.visit_f64x2_convert_low_i32x4_u(), + 0x100 => visitor.visit_i8x16_relaxed_swizzle(), + 0x101 => visitor.visit_i32x4_relaxed_trunc_f32x4_s(), + 0x102 => visitor.visit_i32x4_relaxed_trunc_f32x4_u(), + 0x103 => visitor.visit_i32x4_relaxed_trunc_f64x2_s_zero(), + 0x104 => visitor.visit_i32x4_relaxed_trunc_f64x2_u_zero(), + 0x105 => visitor.visit_f32x4_relaxed_madd(), + 0x106 => visitor.visit_f32x4_relaxed_nmadd(), + 0x107 => visitor.visit_f64x2_relaxed_madd(), + 0x108 => visitor.visit_f64x2_relaxed_nmadd(), + 0x109 => visitor.visit_i8x16_relaxed_laneselect(), + 0x10a => visitor.visit_i16x8_relaxed_laneselect(), + 0x10b => visitor.visit_i32x4_relaxed_laneselect(), + 0x10c => visitor.visit_i64x2_relaxed_laneselect(), + 0x10d => visitor.visit_f32x4_relaxed_min(), + 0x10e => visitor.visit_f32x4_relaxed_max(), + 0x10f => visitor.visit_f64x2_relaxed_min(), + 0x110 => visitor.visit_f64x2_relaxed_max(), + 0x111 => visitor.visit_i16x8_relaxed_q15mulr_s(), + 0x112 => visitor.visit_i16x8_relaxed_dot_i8x16_i7x16_s(), + 0x113 => visitor.visit_i32x4_relaxed_dot_i8x16_i7x16_add_s(), + + _ => bail!(pos, "unknown 0xfd subopcode: 0x{code:x}"), + }) + } + fn visit_0xfe_operator<T>( &mut self, pos: usize, @@ -1567,32 +2011,68 @@ impl<'a> BinaryReader<'a> { }) } - /// Reads the next available `Operator`. - /// - /// # Errors - /// - /// If `BinaryReader` has less bytes remaining than required to parse - /// the `Operator`. - pub fn read_operator(&mut self) -> Result<Operator<'a>> { - self.visit_operator(&mut OperatorFactory::new()) - } + fn read_memarg(&mut self, max_align: u8) -> Result<MemArg> { + let flags_pos = self.original_position(); + let mut flags = self.read_var_u32()?; - /// Returns whether there is an `end` opcode followed by eof remaining in - /// this reader. - pub fn is_end_then_eof(&self) -> bool { - self.remaining_buffer() == &[0x0b] + let memory = if self.multi_memory() && flags & (1 << 6) != 0 { + flags ^= 1 << 6; + self.read_var_u32()? + } else { + 0 + }; + let max_flag_bits = if self.multi_memory() { 6 } else { 5 }; + if flags >= (1 << max_flag_bits) { + return Err(BinaryReaderError::new( + "malformed memop alignment: alignment too large", + flags_pos, + )); + } + let align = flags as u8; + let offset = if self.memory64() { + self.read_var_u64()? + } else { + u64::from(self.read_var_u32()?) + }; + Ok(MemArg { + align, + max_align, + offset, + memory, + }) } - #[cfg(feature = "simd")] - fn read_lane_index(&mut self, max: u8) -> Result<u8> { - let index = self.read_u8()?; - if index >= max { - return Err(BinaryReaderError::new( - "invalid lane index", + fn read_ordering(&mut self) -> Result<Ordering> { + let byte = self.read_var_u32()?; + match byte { + 0 => Ok(Ordering::SeqCst), + 1 => Ok(Ordering::AcqRel), + x => Err(BinaryReaderError::new( + &format!("invalid atomic consistency ordering {x}"), self.original_position() - 1, - )); + )), } - Ok(index) + } + + fn read_br_table(&mut self) -> Result<BrTable<'a>> { + let cnt = self.read_size(MAX_WASM_BR_TABLE_SIZE, "br_table")?; + let reader = self.skip(|reader| { + for _ in 0..cnt { + reader.read_var_u32()?; + } + Ok(()) + })?; + let default = self.read_var_u32()?; + Ok(BrTable { + reader, + cnt: cnt as u32, + default, + }) + } + + #[cfg(feature = "simd")] + fn read_lane_index(&mut self) -> Result<u8> { + self.read_u8() } #[cfg(feature = "simd")] @@ -1602,26 +2082,6 @@ impl<'a> BinaryReader<'a> { Ok(V128(bytes)) } - pub(crate) fn read_header_version(&mut self) -> Result<u32> { - let magic_number = self.read_bytes(4)?; - if magic_number != WASM_MAGIC_NUMBER { - return Err(BinaryReaderError::new( - format!("magic header not detected: bad magic number - expected={WASM_MAGIC_NUMBER:#x?} actual={magic_number:#x?}"), - self.original_position() - 4, - )); - } - self.read_u32() - } - - pub(crate) fn skip_const_expr(&mut self) -> Result<()> { - // TODO add skip_operator() method and/or validate ConstExpr operators. - loop { - if let Operator::End = self.read_operator()? { - return Ok(()); - } - } - } - fn read_memory_index_or_zero_if_not_multi_memory(&mut self) -> Result<u32> { if self.multi_memory() { self.read_var_u32() @@ -1635,221 +2095,19 @@ impl<'a> BinaryReader<'a> { } } - fn read_table_index_or_zero_if_not_reference_types(&mut self) -> Result<u32> { - if self.reference_types() { - self.read_var_u32() - } else { - // Before reference types this byte was required to be a single zero - // byte, not a LEB-encoded zero, so require a precise zero byte. - match self.read_u8()? { - 0 => Ok(0), - _ => bail!(self.original_position() - 1, "zero byte expected"), - } - } - } -} - -// See documentation on `BinaryReader::features` for more on what's going on -// here. -macro_rules! define_feature_accessor { - ($feature:ident = $default:expr) => { - impl BinaryReader<'_> { - #[inline] - #[allow(dead_code)] - pub(crate) fn $feature(&self) -> bool { - #[cfg(feature = "features")] - { - self.features.$feature() - } - #[cfg(not(feature = "features"))] - { - true - } - } - } - }; -} - -super::features::foreach_wasm_feature!(define_feature_accessor); - -impl<'a> BrTable<'a> { - /// Returns the number of `br_table` entries, not including the default - /// label - pub fn len(&self) -> u32 { - self.cnt - } - - /// Returns whether `BrTable` doesn't have any labels apart from the default one. - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Returns the default target of this `br_table` instruction. - pub fn default(&self) -> u32 { - self.default - } - - /// Returns the list of targets that this `br_table` instruction will be - /// jumping to. - /// - /// This method will return an iterator which parses each target of this - /// `br_table` except the default target. The returned iterator will - /// yield `self.len()` elements. - /// - /// # Examples - /// - /// ```rust - /// use wasmparser::{BinaryReader, Operator}; - /// - /// let buf = [0x0e, 0x02, 0x01, 0x02, 0x00]; - /// let mut reader = BinaryReader::new(&buf, 0); - /// let op = reader.read_operator().unwrap(); - /// if let Operator::BrTable { targets } = op { - /// let targets = targets.targets().collect::<Result<Vec<_>, _>>().unwrap(); - /// assert_eq!(targets, [1, 2]); - /// } - /// ``` - pub fn targets(&self) -> BrTableTargets { - BrTableTargets { - reader: self.reader.clone(), - remaining: self.cnt, - } - } -} - -/// An iterator over the targets of a [`BrTable`]. -/// -/// # Note -/// -/// This iterator parses each target of the underlying `br_table` -/// except for the default target. -/// The iterator will yield exactly as many targets as the `br_table` has. -pub struct BrTableTargets<'a> { - reader: crate::BinaryReader<'a>, - remaining: u32, -} - -impl<'a> Iterator for BrTableTargets<'a> { - type Item = Result<u32>; - - fn size_hint(&self) -> (usize, Option<usize>) { - let remaining = usize::try_from(self.remaining).unwrap_or_else(|error| { - panic!("could not convert remaining `u32` into `usize`: {}", error) - }); - (remaining, Some(remaining)) - } - - fn next(&mut self) -> Option<Self::Item> { - if self.remaining == 0 { - if !self.reader.eof() { - return Some(Err(BinaryReaderError::new( - "trailing data in br_table", - self.reader.original_position(), - ))); - } - return None; - } - self.remaining -= 1; - Some(self.reader.read_var_u32()) - } -} - -impl fmt::Debug for BrTable<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut f = f.debug_struct("BrTable"); - f.field("count", &self.cnt); - f.field("default", &self.default); - match self.targets().collect::<Result<Vec<_>>>() { - Ok(targets) => { - f.field("targets", &targets); - } - Err(_) => { - f.field("reader", &self.reader); - } - } - f.finish() - } -} - -/// A factory to construct [`Operator`] instances via the [`VisitOperator`] trait. -struct OperatorFactory<'a> { - marker: core::marker::PhantomData<fn() -> &'a ()>, -} - -impl<'a> OperatorFactory<'a> { - /// Creates a new [`OperatorFactory`]. - fn new() -> Self { - Self { - marker: core::marker::PhantomData, + fn read_call_indirect_table_immediate(&mut self) -> Result<u32> { + // If the `call_indirect_overlong` feature is enabled, then read this + // immediate as a LEB. This feature is enabled as part of the + // `reference_types` feature or the `lime1` feature. + if self.call_indirect_overlong() { + return self.read_var_u32(); } - } -} -macro_rules! define_visit_operator { - ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => { - $( - fn $visit(&mut self $($(,$arg: $argty)*)?) -> Operator<'a> { - Operator::$op $({ $($arg),* })? - } - )* - } -} - -impl<'a> VisitOperator<'a> for OperatorFactory<'a> { - type Output = Operator<'a>; - - #[cfg(feature = "simd")] - fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = Self::Output>> { - Some(self) - } - - crate::for_each_visit_operator!(define_visit_operator); -} - -#[cfg(feature = "simd")] -impl<'a> VisitSimdOperator<'a> for OperatorFactory<'a> { - crate::for_each_visit_simd_operator!(define_visit_operator); -} - -/// Iterator returned from [`BinaryReader::read_iter`]. -pub struct BinaryReaderIter<'a, 'me, T: FromReader<'a>> { - remaining: usize, - pub(crate) reader: &'me mut BinaryReader<'a>, - _marker: marker::PhantomData<T>, -} - -impl<'a, T> Iterator for BinaryReaderIter<'a, '_, T> -where - T: FromReader<'a>, -{ - type Item = Result<T>; - - fn next(&mut self) -> Option<Result<T>> { - if self.remaining == 0 { - None - } else { - let ret = self.reader.read::<T>(); - if ret.is_err() { - self.remaining = 0; - } else { - self.remaining -= 1; - } - Some(ret) - } - } - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.remaining, Some(self.remaining)) - } -} - -impl<'a, T> Drop for BinaryReaderIter<'a, '_, T> -where - T: FromReader<'a>, -{ - fn drop(&mut self) { - while self.next().is_some() { - // ... + // Before reference types this byte was required to be a single zero + // byte, not a LEB-encoded zero, so require a precise zero byte. + match self.read_u8()? { + 0 => Ok(0), + _ => bail!(self.original_position() - 1, "zero byte expected"), } } } diff --git a/third_party/rust/wasmparser/src/binary_reader/simd.rs b/third_party/rust/wasmparser/src/binary_reader/simd.rs @@ -1,320 +0,0 @@ -use super::BinaryReader; -use crate::{Result, VisitOperator, VisitSimdOperator}; - -impl<'a> BinaryReader<'a> { - pub(super) fn visit_0xfd_operator<T>( - &mut self, - pos: usize, - visitor: &mut T, - ) -> Result<<T as VisitOperator<'a>>::Output> - where - T: VisitSimdOperator<'a>, - { - let code = self.read_var_u32()?; - Ok(match code { - 0x00 => visitor.visit_v128_load(self.read_memarg(4)?), - 0x01 => visitor.visit_v128_load8x8_s(self.read_memarg(3)?), - 0x02 => visitor.visit_v128_load8x8_u(self.read_memarg(3)?), - 0x03 => visitor.visit_v128_load16x4_s(self.read_memarg(3)?), - 0x04 => visitor.visit_v128_load16x4_u(self.read_memarg(3)?), - 0x05 => visitor.visit_v128_load32x2_s(self.read_memarg(3)?), - 0x06 => visitor.visit_v128_load32x2_u(self.read_memarg(3)?), - 0x07 => visitor.visit_v128_load8_splat(self.read_memarg(0)?), - 0x08 => visitor.visit_v128_load16_splat(self.read_memarg(1)?), - 0x09 => visitor.visit_v128_load32_splat(self.read_memarg(2)?), - 0x0a => visitor.visit_v128_load64_splat(self.read_memarg(3)?), - - 0x0b => visitor.visit_v128_store(self.read_memarg(4)?), - 0x0c => visitor.visit_v128_const(self.read_v128()?), - 0x0d => { - let mut lanes: [u8; 16] = [0; 16]; - for lane in &mut lanes { - *lane = self.read_lane_index(32)? - } - visitor.visit_i8x16_shuffle(lanes) - } - - 0x0e => visitor.visit_i8x16_swizzle(), - 0x0f => visitor.visit_i8x16_splat(), - 0x10 => visitor.visit_i16x8_splat(), - 0x11 => visitor.visit_i32x4_splat(), - 0x12 => visitor.visit_i64x2_splat(), - 0x13 => visitor.visit_f32x4_splat(), - 0x14 => visitor.visit_f64x2_splat(), - - 0x15 => visitor.visit_i8x16_extract_lane_s(self.read_lane_index(16)?), - 0x16 => visitor.visit_i8x16_extract_lane_u(self.read_lane_index(16)?), - 0x17 => visitor.visit_i8x16_replace_lane(self.read_lane_index(16)?), - 0x18 => visitor.visit_i16x8_extract_lane_s(self.read_lane_index(8)?), - 0x19 => visitor.visit_i16x8_extract_lane_u(self.read_lane_index(8)?), - 0x1a => visitor.visit_i16x8_replace_lane(self.read_lane_index(8)?), - 0x1b => visitor.visit_i32x4_extract_lane(self.read_lane_index(4)?), - - 0x1c => visitor.visit_i32x4_replace_lane(self.read_lane_index(4)?), - 0x1d => visitor.visit_i64x2_extract_lane(self.read_lane_index(2)?), - 0x1e => visitor.visit_i64x2_replace_lane(self.read_lane_index(2)?), - 0x1f => visitor.visit_f32x4_extract_lane(self.read_lane_index(4)?), - 0x20 => visitor.visit_f32x4_replace_lane(self.read_lane_index(4)?), - 0x21 => visitor.visit_f64x2_extract_lane(self.read_lane_index(2)?), - 0x22 => visitor.visit_f64x2_replace_lane(self.read_lane_index(2)?), - - 0x23 => visitor.visit_i8x16_eq(), - 0x24 => visitor.visit_i8x16_ne(), - 0x25 => visitor.visit_i8x16_lt_s(), - 0x26 => visitor.visit_i8x16_lt_u(), - 0x27 => visitor.visit_i8x16_gt_s(), - 0x28 => visitor.visit_i8x16_gt_u(), - 0x29 => visitor.visit_i8x16_le_s(), - 0x2a => visitor.visit_i8x16_le_u(), - 0x2b => visitor.visit_i8x16_ge_s(), - 0x2c => visitor.visit_i8x16_ge_u(), - 0x2d => visitor.visit_i16x8_eq(), - 0x2e => visitor.visit_i16x8_ne(), - 0x2f => visitor.visit_i16x8_lt_s(), - 0x30 => visitor.visit_i16x8_lt_u(), - 0x31 => visitor.visit_i16x8_gt_s(), - 0x32 => visitor.visit_i16x8_gt_u(), - 0x33 => visitor.visit_i16x8_le_s(), - 0x34 => visitor.visit_i16x8_le_u(), - 0x35 => visitor.visit_i16x8_ge_s(), - 0x36 => visitor.visit_i16x8_ge_u(), - 0x37 => visitor.visit_i32x4_eq(), - 0x38 => visitor.visit_i32x4_ne(), - 0x39 => visitor.visit_i32x4_lt_s(), - 0x3a => visitor.visit_i32x4_lt_u(), - 0x3b => visitor.visit_i32x4_gt_s(), - 0x3c => visitor.visit_i32x4_gt_u(), - 0x3d => visitor.visit_i32x4_le_s(), - 0x3e => visitor.visit_i32x4_le_u(), - 0x3f => visitor.visit_i32x4_ge_s(), - 0x40 => visitor.visit_i32x4_ge_u(), - 0x41 => visitor.visit_f32x4_eq(), - 0x42 => visitor.visit_f32x4_ne(), - 0x43 => visitor.visit_f32x4_lt(), - 0x44 => visitor.visit_f32x4_gt(), - 0x45 => visitor.visit_f32x4_le(), - 0x46 => visitor.visit_f32x4_ge(), - 0x47 => visitor.visit_f64x2_eq(), - 0x48 => visitor.visit_f64x2_ne(), - 0x49 => visitor.visit_f64x2_lt(), - 0x4a => visitor.visit_f64x2_gt(), - 0x4b => visitor.visit_f64x2_le(), - 0x4c => visitor.visit_f64x2_ge(), - 0x4d => visitor.visit_v128_not(), - 0x4e => visitor.visit_v128_and(), - 0x4f => visitor.visit_v128_andnot(), - 0x50 => visitor.visit_v128_or(), - 0x51 => visitor.visit_v128_xor(), - 0x52 => visitor.visit_v128_bitselect(), - 0x53 => visitor.visit_v128_any_true(), - - 0x54 => { - let memarg = self.read_memarg(0)?; - let lane = self.read_lane_index(16)?; - visitor.visit_v128_load8_lane(memarg, lane) - } - 0x55 => { - let memarg = self.read_memarg(1)?; - let lane = self.read_lane_index(8)?; - visitor.visit_v128_load16_lane(memarg, lane) - } - 0x56 => { - let memarg = self.read_memarg(2)?; - let lane = self.read_lane_index(4)?; - visitor.visit_v128_load32_lane(memarg, lane) - } - 0x57 => { - let memarg = self.read_memarg(3)?; - let lane = self.read_lane_index(2)?; - visitor.visit_v128_load64_lane(memarg, lane) - } - 0x58 => { - let memarg = self.read_memarg(0)?; - let lane = self.read_lane_index(16)?; - visitor.visit_v128_store8_lane(memarg, lane) - } - 0x59 => { - let memarg = self.read_memarg(1)?; - let lane = self.read_lane_index(8)?; - visitor.visit_v128_store16_lane(memarg, lane) - } - 0x5a => { - let memarg = self.read_memarg(2)?; - let lane = self.read_lane_index(4)?; - visitor.visit_v128_store32_lane(memarg, lane) - } - 0x5b => { - let memarg = self.read_memarg(3)?; - let lane = self.read_lane_index(2)?; - visitor.visit_v128_store64_lane(memarg, lane) - } - - 0x5c => visitor.visit_v128_load32_zero(self.read_memarg(2)?), - 0x5d => visitor.visit_v128_load64_zero(self.read_memarg(3)?), - 0x5e => visitor.visit_f32x4_demote_f64x2_zero(), - 0x5f => visitor.visit_f64x2_promote_low_f32x4(), - 0x60 => visitor.visit_i8x16_abs(), - 0x61 => visitor.visit_i8x16_neg(), - 0x62 => visitor.visit_i8x16_popcnt(), - 0x63 => visitor.visit_i8x16_all_true(), - 0x64 => visitor.visit_i8x16_bitmask(), - 0x65 => visitor.visit_i8x16_narrow_i16x8_s(), - 0x66 => visitor.visit_i8x16_narrow_i16x8_u(), - 0x67 => visitor.visit_f32x4_ceil(), - 0x68 => visitor.visit_f32x4_floor(), - 0x69 => visitor.visit_f32x4_trunc(), - 0x6a => visitor.visit_f32x4_nearest(), - 0x6b => visitor.visit_i8x16_shl(), - 0x6c => visitor.visit_i8x16_shr_s(), - 0x6d => visitor.visit_i8x16_shr_u(), - 0x6e => visitor.visit_i8x16_add(), - 0x6f => visitor.visit_i8x16_add_sat_s(), - 0x70 => visitor.visit_i8x16_add_sat_u(), - 0x71 => visitor.visit_i8x16_sub(), - 0x72 => visitor.visit_i8x16_sub_sat_s(), - 0x73 => visitor.visit_i8x16_sub_sat_u(), - 0x74 => visitor.visit_f64x2_ceil(), - 0x75 => visitor.visit_f64x2_floor(), - 0x76 => visitor.visit_i8x16_min_s(), - 0x77 => visitor.visit_i8x16_min_u(), - 0x78 => visitor.visit_i8x16_max_s(), - 0x79 => visitor.visit_i8x16_max_u(), - 0x7a => visitor.visit_f64x2_trunc(), - 0x7b => visitor.visit_i8x16_avgr_u(), - 0x7c => visitor.visit_i16x8_extadd_pairwise_i8x16_s(), - 0x7d => visitor.visit_i16x8_extadd_pairwise_i8x16_u(), - 0x7e => visitor.visit_i32x4_extadd_pairwise_i16x8_s(), - 0x7f => visitor.visit_i32x4_extadd_pairwise_i16x8_u(), - 0x80 => visitor.visit_i16x8_abs(), - 0x81 => visitor.visit_i16x8_neg(), - 0x82 => visitor.visit_i16x8_q15mulr_sat_s(), - 0x83 => visitor.visit_i16x8_all_true(), - 0x84 => visitor.visit_i16x8_bitmask(), - 0x85 => visitor.visit_i16x8_narrow_i32x4_s(), - 0x86 => visitor.visit_i16x8_narrow_i32x4_u(), - 0x87 => visitor.visit_i16x8_extend_low_i8x16_s(), - 0x88 => visitor.visit_i16x8_extend_high_i8x16_s(), - 0x89 => visitor.visit_i16x8_extend_low_i8x16_u(), - 0x8a => visitor.visit_i16x8_extend_high_i8x16_u(), - 0x8b => visitor.visit_i16x8_shl(), - 0x8c => visitor.visit_i16x8_shr_s(), - 0x8d => visitor.visit_i16x8_shr_u(), - 0x8e => visitor.visit_i16x8_add(), - 0x8f => visitor.visit_i16x8_add_sat_s(), - 0x90 => visitor.visit_i16x8_add_sat_u(), - 0x91 => visitor.visit_i16x8_sub(), - 0x92 => visitor.visit_i16x8_sub_sat_s(), - 0x93 => visitor.visit_i16x8_sub_sat_u(), - 0x94 => visitor.visit_f64x2_nearest(), - 0x95 => visitor.visit_i16x8_mul(), - 0x96 => visitor.visit_i16x8_min_s(), - 0x97 => visitor.visit_i16x8_min_u(), - 0x98 => visitor.visit_i16x8_max_s(), - 0x99 => visitor.visit_i16x8_max_u(), - 0x9b => visitor.visit_i16x8_avgr_u(), - 0x9c => visitor.visit_i16x8_extmul_low_i8x16_s(), - 0x9d => visitor.visit_i16x8_extmul_high_i8x16_s(), - 0x9e => visitor.visit_i16x8_extmul_low_i8x16_u(), - 0x9f => visitor.visit_i16x8_extmul_high_i8x16_u(), - 0xa0 => visitor.visit_i32x4_abs(), - 0xa1 => visitor.visit_i32x4_neg(), - 0xa3 => visitor.visit_i32x4_all_true(), - 0xa4 => visitor.visit_i32x4_bitmask(), - 0xa7 => visitor.visit_i32x4_extend_low_i16x8_s(), - 0xa8 => visitor.visit_i32x4_extend_high_i16x8_s(), - 0xa9 => visitor.visit_i32x4_extend_low_i16x8_u(), - 0xaa => visitor.visit_i32x4_extend_high_i16x8_u(), - 0xab => visitor.visit_i32x4_shl(), - 0xac => visitor.visit_i32x4_shr_s(), - 0xad => visitor.visit_i32x4_shr_u(), - 0xae => visitor.visit_i32x4_add(), - 0xb1 => visitor.visit_i32x4_sub(), - 0xb5 => visitor.visit_i32x4_mul(), - 0xb6 => visitor.visit_i32x4_min_s(), - 0xb7 => visitor.visit_i32x4_min_u(), - 0xb8 => visitor.visit_i32x4_max_s(), - 0xb9 => visitor.visit_i32x4_max_u(), - 0xba => visitor.visit_i32x4_dot_i16x8_s(), - 0xbc => visitor.visit_i32x4_extmul_low_i16x8_s(), - 0xbd => visitor.visit_i32x4_extmul_high_i16x8_s(), - 0xbe => visitor.visit_i32x4_extmul_low_i16x8_u(), - 0xbf => visitor.visit_i32x4_extmul_high_i16x8_u(), - 0xc0 => visitor.visit_i64x2_abs(), - 0xc1 => visitor.visit_i64x2_neg(), - 0xc3 => visitor.visit_i64x2_all_true(), - 0xc4 => visitor.visit_i64x2_bitmask(), - 0xc7 => visitor.visit_i64x2_extend_low_i32x4_s(), - 0xc8 => visitor.visit_i64x2_extend_high_i32x4_s(), - 0xc9 => visitor.visit_i64x2_extend_low_i32x4_u(), - 0xca => visitor.visit_i64x2_extend_high_i32x4_u(), - 0xcb => visitor.visit_i64x2_shl(), - 0xcc => visitor.visit_i64x2_shr_s(), - 0xcd => visitor.visit_i64x2_shr_u(), - 0xce => visitor.visit_i64x2_add(), - 0xd1 => visitor.visit_i64x2_sub(), - 0xd5 => visitor.visit_i64x2_mul(), - 0xd6 => visitor.visit_i64x2_eq(), - 0xd7 => visitor.visit_i64x2_ne(), - 0xd8 => visitor.visit_i64x2_lt_s(), - 0xd9 => visitor.visit_i64x2_gt_s(), - 0xda => visitor.visit_i64x2_le_s(), - 0xdb => visitor.visit_i64x2_ge_s(), - 0xdc => visitor.visit_i64x2_extmul_low_i32x4_s(), - 0xdd => visitor.visit_i64x2_extmul_high_i32x4_s(), - 0xde => visitor.visit_i64x2_extmul_low_i32x4_u(), - 0xdf => visitor.visit_i64x2_extmul_high_i32x4_u(), - 0xe0 => visitor.visit_f32x4_abs(), - 0xe1 => visitor.visit_f32x4_neg(), - 0xe3 => visitor.visit_f32x4_sqrt(), - 0xe4 => visitor.visit_f32x4_add(), - 0xe5 => visitor.visit_f32x4_sub(), - 0xe6 => visitor.visit_f32x4_mul(), - 0xe7 => visitor.visit_f32x4_div(), - 0xe8 => visitor.visit_f32x4_min(), - 0xe9 => visitor.visit_f32x4_max(), - 0xea => visitor.visit_f32x4_pmin(), - 0xeb => visitor.visit_f32x4_pmax(), - 0xec => visitor.visit_f64x2_abs(), - 0xed => visitor.visit_f64x2_neg(), - 0xef => visitor.visit_f64x2_sqrt(), - 0xf0 => visitor.visit_f64x2_add(), - 0xf1 => visitor.visit_f64x2_sub(), - 0xf2 => visitor.visit_f64x2_mul(), - 0xf3 => visitor.visit_f64x2_div(), - 0xf4 => visitor.visit_f64x2_min(), - 0xf5 => visitor.visit_f64x2_max(), - 0xf6 => visitor.visit_f64x2_pmin(), - 0xf7 => visitor.visit_f64x2_pmax(), - 0xf8 => visitor.visit_i32x4_trunc_sat_f32x4_s(), - 0xf9 => visitor.visit_i32x4_trunc_sat_f32x4_u(), - 0xfa => visitor.visit_f32x4_convert_i32x4_s(), - 0xfb => visitor.visit_f32x4_convert_i32x4_u(), - 0xfc => visitor.visit_i32x4_trunc_sat_f64x2_s_zero(), - 0xfd => visitor.visit_i32x4_trunc_sat_f64x2_u_zero(), - 0xfe => visitor.visit_f64x2_convert_low_i32x4_s(), - 0xff => visitor.visit_f64x2_convert_low_i32x4_u(), - 0x100 => visitor.visit_i8x16_relaxed_swizzle(), - 0x101 => visitor.visit_i32x4_relaxed_trunc_f32x4_s(), - 0x102 => visitor.visit_i32x4_relaxed_trunc_f32x4_u(), - 0x103 => visitor.visit_i32x4_relaxed_trunc_f64x2_s_zero(), - 0x104 => visitor.visit_i32x4_relaxed_trunc_f64x2_u_zero(), - 0x105 => visitor.visit_f32x4_relaxed_madd(), - 0x106 => visitor.visit_f32x4_relaxed_nmadd(), - 0x107 => visitor.visit_f64x2_relaxed_madd(), - 0x108 => visitor.visit_f64x2_relaxed_nmadd(), - 0x109 => visitor.visit_i8x16_relaxed_laneselect(), - 0x10a => visitor.visit_i16x8_relaxed_laneselect(), - 0x10b => visitor.visit_i32x4_relaxed_laneselect(), - 0x10c => visitor.visit_i64x2_relaxed_laneselect(), - 0x10d => visitor.visit_f32x4_relaxed_min(), - 0x10e => visitor.visit_f32x4_relaxed_max(), - 0x10f => visitor.visit_f64x2_relaxed_min(), - 0x110 => visitor.visit_f64x2_relaxed_max(), - 0x111 => visitor.visit_i16x8_relaxed_q15mulr_s(), - 0x112 => visitor.visit_i16x8_relaxed_dot_i8x16_i7x16_s(), - 0x113 => visitor.visit_i32x4_relaxed_dot_i8x16_i7x16_add_s(), - - _ => bail!(pos, "unknown 0xfd subopcode: 0x{code:x}"), - }) - } -} diff --git a/third_party/rust/wasmparser/src/collections/index_map.rs b/third_party/rust/wasmparser/src/collections/index_map.rs @@ -491,7 +491,7 @@ pub struct IntoIter<K, V> { inner: detail::IntoIterImpl<K, V>, } -impl<'a, K, V> Iterator for IntoIter<K, V> { +impl<K, V> Iterator for IntoIter<K, V> { type Item = (K, V); #[inline] @@ -505,14 +505,14 @@ impl<'a, K, V> Iterator for IntoIter<K, V> { } } -impl<'a, K, V> ExactSizeIterator for IntoIter<K, V> { +impl<K, V> ExactSizeIterator for IntoIter<K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } -impl<'a, K, V> FusedIterator for IntoIter<K, V> {} +impl<K, V> FusedIterator for IntoIter<K, V> {} /// An iterator over the keys of a [`IndexMap`]. #[derive(Debug, Clone)] diff --git a/third_party/rust/wasmparser/src/collections/index_map/detail.rs b/third_party/rust/wasmparser/src/collections/index_map/detail.rs @@ -39,7 +39,7 @@ mod impls { pub use self::impls::*; -use alloc::collections::{btree_map, BTreeMap}; +use alloc::collections::{BTreeMap, btree_map}; use alloc::vec::IntoIter as VecIntoIter; use alloc::vec::Vec; use core::borrow::Borrow; @@ -298,7 +298,7 @@ impl<K, V> IndexMap<K, V> { } /// Gets the given key’s corresponding entry in the map for in-place manipulation. - pub fn entry(&mut self, key: K) -> Entry<K, V> + pub fn entry(&mut self, key: K) -> Entry<'_, K, V> where K: Ord + Clone, { @@ -399,35 +399,35 @@ impl<K, V> IndexMap<K, V> { } /// Gets an iterator over the entries of the map, sorted by key. - pub fn iter(&self) -> Iter<K, V> { + pub fn iter(&self) -> Iter<'_, K, V> { Iter { iter: self.slots.iter(), } } /// Gets a mutable iterator over the entries of the map, sorted by key. - pub fn iter_mut(&mut self) -> IterMut<K, V> { + pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { IterMut { iter: self.slots.iter_mut(), } } /// Gets an iterator over the values of the map, in order by key. - pub fn keys(&self) -> Keys<K, V> { + pub fn keys(&self) -> Keys<'_, K, V> { Keys { iter: self.slots.iter(), } } /// Gets an iterator over the values of the map, in order by key. - pub fn values(&self) -> Values<K, V> { + pub fn values(&self) -> Values<'_, K, V> { Values { iter: self.slots.iter(), } } /// Gets a mutable iterator over the values of the map, in order by key. - pub fn values_mut(&mut self) -> ValuesMut<K, V> { + pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> { ValuesMut { iter: self.slots.iter_mut(), } diff --git a/third_party/rust/wasmparser/src/features.rs b/third_party/rust/wasmparser/src/features.rs @@ -139,7 +139,7 @@ define_wasm_features! { /// has any associated constants. When `features` are disabled all values /// for proposals are fixed at compile time to their defaults. #[derive(Hash, Debug, Copy, Clone, Eq, PartialEq)] - pub struct WasmFeatures: u32 { + pub struct WasmFeatures: u64 { /// The WebAssembly `mutable-global` proposal. pub mutable_global: MUTABLE_GLOBAL(1) = true; /// The WebAssembly `saturating-float-to-int` proposal. @@ -147,11 +147,28 @@ define_wasm_features! { /// The WebAssembly `sign-extension-ops` proposal. pub sign_extension: SIGN_EXTENSION(1 << 2) = true; /// The WebAssembly reference types proposal. - pub reference_types: REFERENCE_TYPES(1 << 3) = true; + // + // Note that this is two bits, one for the proposal itself and one which + // is the overlong call-indirect encoding. This is split across two bits + // since the "lime1" feature set below only encompasses some of this + // feature, not all of it. Enabling reference types always enabled + // call-indirect-overlong, but not vice-versa. + // + // Also note that this goes against the recommendation of the + // `bitflags!` macro since the lone `1 << 3` bit here doesn't actually + // correspond to any named flag. That means it's possible to technically + // create a `WasmFeatures` that only has the `1 << 3` bit set, which + // doesn't actually mean anything, but that in theory shouldn't be too + // harmful and is esoteric enough we don't have to worry much about it. + pub reference_types: REFERENCE_TYPES((1 << 3) | Self::CALL_INDIRECT_OVERLONG.bits()) = true; /// The WebAssembly multi-value proposal. pub multi_value: MULTI_VALUE(1 << 4) = true; /// The WebAssembly bulk memory operations proposal. - pub bulk_memory: BULK_MEMORY(1 << 5) = true; + // + // Note that this proposal is split in two the same way + // `REFERENCE_TYPES` is split above. See more words there for why and + // rationale. + pub bulk_memory: BULK_MEMORY((1 << 5) | Self::BULK_MEMORY_OPT.bits()) = true; /// The WebAssembly SIMD proposal. pub simd: SIMD(1 << 6) = true; /// The WebAssembly Relaxed SIMD proposal. @@ -193,21 +210,13 @@ define_wasm_features! { /// The WebAssembly [custom-page-sizes /// proposal](https://github.com/WebAssembly/custom-page-sizes). pub custom_page_sizes: CUSTOM_PAGE_SIZES(1 << 20) = false; - /// Support for the `value` type in the component model proposal. - pub component_model_values: COMPONENT_MODEL_VALUES(1 << 21) = false; - /// Support for the nested namespaces and projects in component model names. - pub component_model_nested_names: COMPONENT_MODEL_NESTED_NAMES(1 << 22) = false; - /// Support for more than 32 flags per-type in the component model. - pub component_model_more_flags: COMPONENT_MODEL_MORE_FLAGS(1 << 23) = false; - /// Support for multiple return values in a component model function. - pub component_model_multiple_returns: COMPONENT_MODEL_MULTIPLE_RETURNS(1 << 24) = false; /// The WebAssembly legacy exception handling proposal (phase 1) /// /// # Note /// /// Support this feature as long as all leading browsers also support it /// <https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/legacy/Exceptions.md> - pub legacy_exceptions: LEGACY_EXCEPTIONS(1 << 25) = false; + pub legacy_exceptions: LEGACY_EXCEPTIONS(1 << 23) = false; /// Whether or not gc types are enabled. /// /// This feature does not correspond to any WebAssembly proposal nor @@ -224,13 +233,76 @@ define_wasm_features! { /// Note that the `funcref` and `exnref` types are not gated by this /// feature. Those are expected to not require a full garbage collector /// so are not gated by this. - pub gc_types: GC_TYPES(1 << 26) = true; + pub gc_types: GC_TYPES(1 << 24) = true; /// The WebAssembly [stack-switching proposal](https://github.com/WebAssembly/stack-switching). - pub stack_switching: STACK_SWITCHING(1 << 27) = false; + pub stack_switching: STACK_SWITCHING(1 << 25) = false; /// The WebAssembly [wide-arithmetic proposal](https://github.com/WebAssembly/wide-arithmetic). - pub wide_arithmetic: WIDE_ARITHMETIC(1 << 28) = false; + pub wide_arithmetic: WIDE_ARITHMETIC(1 << 26) = false; + + /// Support for the `value` type in the component model proposal. + /// + /// Corresponds to the 🪙 character in + /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>. + pub cm_values: CM_VALUES(1 << 21) = false; + /// Support for the nested namespaces and projects in component model names. + /// + /// Corresponds to the 🪺 character in + /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>. + pub cm_nested_names: CM_NESTED_NAMES(1 << 22) = false; /// Support for component model async lift/lower ABI, as well as streams, futures, and errors. - pub component_model_async: COMPONENT_MODEL_ASYNC(1 << 29) = false; + /// + /// Corresponds to the 🔀 character in + /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>. + pub cm_async: CM_ASYNC(1 << 27) = false; + /// Gates the "stackful ABI" in the component model async proposal. + /// + /// Corresponds to the 🚟 character in + /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>. + pub cm_async_stackful: CM_ASYNC_STACKFUL(1 << 28) = false; + /// Gates some intrinsics being marked with `async` in the component + /// model async proposal. + /// + /// Corresponds to the 🚝 character in + /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>. + pub cm_async_builtins: CM_ASYNC_BUILTINS(1 << 29) = false; + /// Support for threading in the component model proposal. + /// + /// Corresponds to the 🧵 character in + /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>. + pub cm_threading: CM_THREADING(1 << 30) = false; + /// Gates some intrinsics being marked with `error-context` in the component + /// model async proposal. + /// + /// Corresponds to the 📝 character in + /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>. + pub cm_error_context: CM_ERROR_CONTEXT(1 << 31) = false; + /// Support for fixed size lists + /// + /// Corresponds to the 🔧 character in + /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>. + pub cm_fixed_size_list: CM_FIXED_SIZE_LIST(1 << 32) = false; + /// Support for Wasm GC in the component model proposal. + /// + /// Corresponds to the 🛸 character in + /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>. + pub cm_gc: CM_GC(1 << 33) = false; + + /// Subset of the reference-types WebAssembly proposal which only + /// encompasses the leb-encoding of the table immediate to the + /// `call_indirect` instruction, enabling over-long encodings of an + /// integer for example. + /// + /// This is a subcomponent of the "lime1" feature. + pub call_indirect_overlong: CALL_INDIRECT_OVERLONG(1 << 34) = true; + + /// Subset of the bulk-memory proposal covering just the `memory.copy` + /// and `memory.fill` instructions. + /// + /// This is a subcomponent of the "lime1" feature. + pub bulk_memory_opt: BULK_MEMORY_OPT(1 << 35) = true; + + // Custom descriptors proposal. + pub custom_descriptors: CUSTOM_DESCRIPTORS(1 << 36) = false; } } @@ -287,6 +359,23 @@ impl WasmFeatures { .union(WasmFeatures::THREADS) .union(WasmFeatures::EXCEPTIONS) .union(WasmFeatures::MEMORY64); + + /// The feature set associated with the "lime1" set of features. + /// + /// Here "lime1" stands for "linear memory version 1" and is a stable set of + /// features agreed on by both producers and consumers which is more than + /// the MVP but does not include some more weighty engine features such as + /// reference types, gc, etc. + /// + /// <https://github.com/WebAssembly/tool-conventions/blob/main/Lime.md> + #[cfg(feature = "features")] + pub const LIME1: WasmFeatures = WasmFeatures::WASM1 + .union(WasmFeatures::MULTI_VALUE) + .union(WasmFeatures::SIGN_EXTENSION) + .union(WasmFeatures::SATURATING_FLOAT_TO_INT) + .union(WasmFeatures::BULK_MEMORY_OPT) + .union(WasmFeatures::EXTENDED_CONST) + .union(WasmFeatures::CALL_INDIRECT_OVERLONG); } #[cfg(feature = "features")] diff --git a/third_party/rust/wasmparser/src/lib.rs b/third_party/rust/wasmparser/src/lib.rs @@ -28,7 +28,7 @@ #![deny(missing_docs)] #![no_std] -#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(docsrs, feature(doc_cfg))] extern crate alloc; #[cfg(feature = "std")] @@ -73,17 +73,17 @@ macro_rules! _for_each_operator_group { @mvp { Unreachable => visit_unreachable (arity 0 -> 0) Nop => visit_nop (arity 0 -> 0) - Block { blockty: $crate::BlockType } => visit_block (arity block -> ~block) - Loop { blockty: $crate::BlockType } => visit_loop (arity block -> ~block) - If { blockty: $crate::BlockType } => visit_if (arity 1 block -> ~block) - Else => visit_else (arity ~end -> ~end) - End => visit_end (arity implicit_else ~end -> implicit_else end) - Br { relative_depth: u32 } => visit_br (arity br -> 0) - BrIf { relative_depth: u32 } => visit_br_if (arity 1 br -> br) - BrTable { targets: $crate::BrTable<'a> } => visit_br_table (arity 1 br_table -> 0) - Return => visit_return (arity ~ret -> 0) - Call { function_index: u32 } => visit_call (arity func -> func) - CallIndirect { type_index: u32, table_index: u32 } => visit_call_indirect (arity 1 type -> type) + Block { blockty: $crate::BlockType } => visit_block (arity custom) + Loop { blockty: $crate::BlockType } => visit_loop (arity custom) + If { blockty: $crate::BlockType } => visit_if (arity custom) + Else => visit_else (arity custom) + End => visit_end (arity custom) + Br { relative_depth: u32 } => visit_br (arity custom) + BrIf { relative_depth: u32 } => visit_br_if (arity custom) + BrTable { targets: $crate::BrTable<'a> } => visit_br_table (arity custom) + Return => visit_return (arity custom) + Call { function_index: u32 } => visit_call (arity custom) + CallIndirect { type_index: u32, table_index: u32 } => visit_call_indirect (arity custom) Drop => visit_drop (arity 1 -> 0) Select => visit_select (arity 3 -> 1) LocalGet { local_index: u32 } => visit_local_get (arity 0 -> 1) @@ -91,166 +91,166 @@ macro_rules! _for_each_operator_group { LocalTee { local_index: u32 } => visit_local_tee (arity 1 -> 1) GlobalGet { global_index: u32 } => visit_global_get (arity 0 -> 1) GlobalSet { global_index: u32 } => visit_global_set (arity 1 -> 0) - I32Load { memarg: $crate::MemArg } => visit_i32_load (load i32) - I64Load { memarg: $crate::MemArg } => visit_i64_load (load i64) - F32Load { memarg: $crate::MemArg } => visit_f32_load (load f32) - F64Load { memarg: $crate::MemArg } => visit_f64_load (load f64) - I32Load8S { memarg: $crate::MemArg } => visit_i32_load8_s (load i32) - I32Load8U { memarg: $crate::MemArg } => visit_i32_load8_u (load i32) - I32Load16S { memarg: $crate::MemArg } => visit_i32_load16_s (load i32) - I32Load16U { memarg: $crate::MemArg } => visit_i32_load16_u (load i32) - I64Load8S { memarg: $crate::MemArg } => visit_i64_load8_s (load i64) - I64Load8U { memarg: $crate::MemArg } => visit_i64_load8_u (load i64) - I64Load16S { memarg: $crate::MemArg } => visit_i64_load16_s (load i64) - I64Load16U { memarg: $crate::MemArg } => visit_i64_load16_u (load i64) - I64Load32S { memarg: $crate::MemArg } => visit_i64_load32_s (load i64) - I64Load32U { memarg: $crate::MemArg } => visit_i64_load32_u (load i64) - I32Store { memarg: $crate::MemArg } => visit_i32_store (store i32) - I64Store { memarg: $crate::MemArg } => visit_i64_store (store i64) - F32Store { memarg: $crate::MemArg } => visit_f32_store (store f32) - F64Store { memarg: $crate::MemArg } => visit_f64_store (store f64) - I32Store8 { memarg: $crate::MemArg } => visit_i32_store8 (store i32) - I32Store16 { memarg: $crate::MemArg } => visit_i32_store16 (store i32) - I64Store8 { memarg: $crate::MemArg } => visit_i64_store8 (store i64) - I64Store16 { memarg: $crate::MemArg } => visit_i64_store16 (store i64) - I64Store32 { memarg: $crate::MemArg } => visit_i64_store32 (store i64) + I32Load { memarg: $crate::MemArg } => visit_i32_load (arity 1 -> 1) + I64Load { memarg: $crate::MemArg } => visit_i64_load (arity 1 -> 1) + F32Load { memarg: $crate::MemArg } => visit_f32_load (arity 1 -> 1) + F64Load { memarg: $crate::MemArg } => visit_f64_load (arity 1 -> 1) + I32Load8S { memarg: $crate::MemArg } => visit_i32_load8_s (arity 1 -> 1) + I32Load8U { memarg: $crate::MemArg } => visit_i32_load8_u (arity 1 -> 1) + I32Load16S { memarg: $crate::MemArg } => visit_i32_load16_s (arity 1 -> 1) + I32Load16U { memarg: $crate::MemArg } => visit_i32_load16_u (arity 1 -> 1) + I64Load8S { memarg: $crate::MemArg } => visit_i64_load8_s (arity 1 -> 1) + I64Load8U { memarg: $crate::MemArg } => visit_i64_load8_u (arity 1 -> 1) + I64Load16S { memarg: $crate::MemArg } => visit_i64_load16_s (arity 1 -> 1) + I64Load16U { memarg: $crate::MemArg } => visit_i64_load16_u (arity 1 -> 1) + I64Load32S { memarg: $crate::MemArg } => visit_i64_load32_s (arity 1 -> 1) + I64Load32U { memarg: $crate::MemArg } => visit_i64_load32_u (arity 1 -> 1) + I32Store { memarg: $crate::MemArg } => visit_i32_store (arity 2 -> 0) + I64Store { memarg: $crate::MemArg } => visit_i64_store (arity 2 -> 0) + F32Store { memarg: $crate::MemArg } => visit_f32_store (arity 2 -> 0) + F64Store { memarg: $crate::MemArg } => visit_f64_store (arity 2 -> 0) + I32Store8 { memarg: $crate::MemArg } => visit_i32_store8 (arity 2 -> 0) + I32Store16 { memarg: $crate::MemArg } => visit_i32_store16 (arity 2 -> 0) + I64Store8 { memarg: $crate::MemArg } => visit_i64_store8 (arity 2 -> 0) + I64Store16 { memarg: $crate::MemArg } => visit_i64_store16 (arity 2 -> 0) + I64Store32 { memarg: $crate::MemArg } => visit_i64_store32 (arity 2 -> 0) MemorySize { mem: u32 } => visit_memory_size (arity 0 -> 1) MemoryGrow { mem: u32 } => visit_memory_grow (arity 1 -> 1) - I32Const { value: i32 } => visit_i32_const (push i32) - I64Const { value: i64 } => visit_i64_const (push i64) - F32Const { value: $crate::Ieee32 } => visit_f32_const (push f32) - F64Const { value: $crate::Ieee64 } => visit_f64_const (push f64) - I32Eqz => visit_i32_eqz (test i32) - I32Eq => visit_i32_eq (cmp i32) - I32Ne => visit_i32_ne (cmp i32) - I32LtS => visit_i32_lt_s (cmp i32) - I32LtU => visit_i32_lt_u (cmp i32) - I32GtS => visit_i32_gt_s (cmp i32) - I32GtU => visit_i32_gt_u (cmp i32) - I32LeS => visit_i32_le_s (cmp i32) - I32LeU => visit_i32_le_u (cmp i32) - I32GeS => visit_i32_ge_s (cmp i32) - I32GeU => visit_i32_ge_u (cmp i32) - I64Eqz => visit_i64_eqz (test i64) - I64Eq => visit_i64_eq (cmp i64) - I64Ne => visit_i64_ne (cmp i64) - I64LtS => visit_i64_lt_s (cmp i64) - I64LtU => visit_i64_lt_u (cmp i64) - I64GtS => visit_i64_gt_s (cmp i64) - I64GtU => visit_i64_gt_u (cmp i64) - I64LeS => visit_i64_le_s (cmp i64) - I64LeU => visit_i64_le_u (cmp i64) - I64GeS => visit_i64_ge_s (cmp i64) - I64GeU => visit_i64_ge_u (cmp i64) - F32Eq => visit_f32_eq (cmp f32) - F32Ne => visit_f32_ne (cmp f32) - F32Lt => visit_f32_lt (cmp f32) - F32Gt => visit_f32_gt (cmp f32) - F32Le => visit_f32_le (cmp f32) - F32Ge => visit_f32_ge (cmp f32) - F64Eq => visit_f64_eq (cmp f64) - F64Ne => visit_f64_ne (cmp f64) - F64Lt => visit_f64_lt (cmp f64) - F64Gt => visit_f64_gt (cmp f64) - F64Le => visit_f64_le (cmp f64) - F64Ge => visit_f64_ge (cmp f64) - I32Clz => visit_i32_clz (unary i32) - I32Ctz => visit_i32_ctz (unary i32) - I32Popcnt => visit_i32_popcnt (unary i32) - I32Add => visit_i32_add (binary i32) - I32Sub => visit_i32_sub (binary i32) - I32Mul => visit_i32_mul (binary i32) - I32DivS => visit_i32_div_s (binary i32) - I32DivU => visit_i32_div_u (binary i32) - I32RemS => visit_i32_rem_s (binary i32) - I32RemU => visit_i32_rem_u (binary i32) - I32And => visit_i32_and (binary i32) - I32Or => visit_i32_or (binary i32) - I32Xor => visit_i32_xor (binary i32) - I32Shl => visit_i32_shl (binary i32) - I32ShrS => visit_i32_shr_s (binary i32) - I32ShrU => visit_i32_shr_u (binary i32) - I32Rotl => visit_i32_rotl (binary i32) - I32Rotr => visit_i32_rotr (binary i32) - I64Clz => visit_i64_clz (unary i64) - I64Ctz => visit_i64_ctz (unary i64) - I64Popcnt => visit_i64_popcnt (unary i64) - I64Add => visit_i64_add (binary i64) - I64Sub => visit_i64_sub (binary i64) - I64Mul => visit_i64_mul (binary i64) - I64DivS => visit_i64_div_s (binary i64) - I64DivU => visit_i64_div_u (binary i64) - I64RemS => visit_i64_rem_s (binary i64) - I64RemU => visit_i64_rem_u (binary i64) - I64And => visit_i64_and (binary i64) - I64Or => visit_i64_or (binary i64) - I64Xor => visit_i64_xor (binary i64) - I64Shl => visit_i64_shl (binary i64) - I64ShrS => visit_i64_shr_s (binary i64) - I64ShrU => visit_i64_shr_u (binary i64) - I64Rotl => visit_i64_rotl (binary i64) - I64Rotr => visit_i64_rotr (binary i64) - F32Abs => visit_f32_abs (unary f32) - F32Neg => visit_f32_neg (unary f32) - F32Ceil => visit_f32_ceil (unary f32) - F32Floor => visit_f32_floor (unary f32) - F32Trunc => visit_f32_trunc (unary f32) - F32Nearest => visit_f32_nearest (unary f32) - F32Sqrt => visit_f32_sqrt (unary f32) - F32Add => visit_f32_add (binary f32) - F32Sub => visit_f32_sub (binary f32) - F32Mul => visit_f32_mul (binary f32) - F32Div => visit_f32_div (binary f32) - F32Min => visit_f32_min (binary f32) - F32Max => visit_f32_max (binary f32) - F32Copysign => visit_f32_copysign (binary f32) - F64Abs => visit_f64_abs (unary f64) - F64Neg => visit_f64_neg (unary f64) - F64Ceil => visit_f64_ceil (unary f64) - F64Floor => visit_f64_floor (unary f64) - F64Trunc => visit_f64_trunc (unary f64) - F64Nearest => visit_f64_nearest (unary f64) - F64Sqrt => visit_f64_sqrt (unary f64) - F64Add => visit_f64_add (binary f64) - F64Sub => visit_f64_sub (binary f64) - F64Mul => visit_f64_mul (binary f64) - F64Div => visit_f64_div (binary f64) - F64Min => visit_f64_min (binary f64) - F64Max => visit_f64_max (binary f64) - F64Copysign => visit_f64_copysign (binary f64) - I32WrapI64 => visit_i32_wrap_i64 (conversion i32 i64) - I32TruncF32S => visit_i32_trunc_f32_s (conversion i32 f32) - I32TruncF32U => visit_i32_trunc_f32_u (conversion i32 f32) - I32TruncF64S => visit_i32_trunc_f64_s (conversion i32 f64) - I32TruncF64U => visit_i32_trunc_f64_u (conversion i32 f64) - I64ExtendI32S => visit_i64_extend_i32_s (conversion i64 i32) - I64ExtendI32U => visit_i64_extend_i32_u (conversion i64 i32) - I64TruncF32S => visit_i64_trunc_f32_s (conversion i64 f32) - I64TruncF32U => visit_i64_trunc_f32_u (conversion i64 f32) - I64TruncF64S => visit_i64_trunc_f64_s (conversion i64 f64) - I64TruncF64U => visit_i64_trunc_f64_u (conversion i64 f64) - F32ConvertI32S => visit_f32_convert_i32_s (conversion f32 i32) - F32ConvertI32U => visit_f32_convert_i32_u (conversion f32 i32) - F32ConvertI64S => visit_f32_convert_i64_s (conversion f32 i64) - F32ConvertI64U => visit_f32_convert_i64_u (conversion f32 i64) - F32DemoteF64 => visit_f32_demote_f64 (conversion f32 f64) - F64ConvertI32S => visit_f64_convert_i32_s (conversion f64 i32) - F64ConvertI32U => visit_f64_convert_i32_u (conversion f64 i32) - F64ConvertI64S => visit_f64_convert_i64_s (conversion f64 i64) - F64ConvertI64U => visit_f64_convert_i64_u (conversion f64 i64) - F64PromoteF32 => visit_f64_promote_f32 (conversion f64 f32) - I32ReinterpretF32 => visit_i32_reinterpret_f32 (conversion i32 f32) - I64ReinterpretF64 => visit_i64_reinterpret_f64 (conversion i64 f64) - F32ReinterpretI32 => visit_f32_reinterpret_i32 (conversion f32 i32) - F64ReinterpretI64 => visit_f64_reinterpret_i64 (conversion f64 i64) + I32Const { value: i32 } => visit_i32_const (arity 0 -> 1) + I64Const { value: i64 } => visit_i64_const (arity 0 -> 1) + F32Const { value: $crate::Ieee32 } => visit_f32_const (arity 0 -> 1) + F64Const { value: $crate::Ieee64 } => visit_f64_const (arity 0 -> 1) + I32Eqz => visit_i32_eqz (arity 1 -> 1) + I32Eq => visit_i32_eq (arity 2 -> 1) + I32Ne => visit_i32_ne (arity 2 -> 1) + I32LtS => visit_i32_lt_s (arity 2 -> 1) + I32LtU => visit_i32_lt_u (arity 2 -> 1) + I32GtS => visit_i32_gt_s (arity 2 -> 1) + I32GtU => visit_i32_gt_u (arity 2 -> 1) + I32LeS => visit_i32_le_s (arity 2 -> 1) + I32LeU => visit_i32_le_u (arity 2 -> 1) + I32GeS => visit_i32_ge_s (arity 2 -> 1) + I32GeU => visit_i32_ge_u (arity 2 -> 1) + I64Eqz => visit_i64_eqz (arity 1 -> 1) + I64Eq => visit_i64_eq (arity 2 -> 1) + I64Ne => visit_i64_ne (arity 2 -> 1) + I64LtS => visit_i64_lt_s (arity 2 -> 1) + I64LtU => visit_i64_lt_u (arity 2 -> 1) + I64GtS => visit_i64_gt_s (arity 2 -> 1) + I64GtU => visit_i64_gt_u (arity 2 -> 1) + I64LeS => visit_i64_le_s (arity 2 -> 1) + I64LeU => visit_i64_le_u (arity 2 -> 1) + I64GeS => visit_i64_ge_s (arity 2 -> 1) + I64GeU => visit_i64_ge_u (arity 2 -> 1) + F32Eq => visit_f32_eq (arity 2 -> 1) + F32Ne => visit_f32_ne (arity 2 -> 1) + F32Lt => visit_f32_lt (arity 2 -> 1) + F32Gt => visit_f32_gt (arity 2 -> 1) + F32Le => visit_f32_le (arity 2 -> 1) + F32Ge => visit_f32_ge (arity 2 -> 1) + F64Eq => visit_f64_eq (arity 2 -> 1) + F64Ne => visit_f64_ne (arity 2 -> 1) + F64Lt => visit_f64_lt (arity 2 -> 1) + F64Gt => visit_f64_gt (arity 2 -> 1) + F64Le => visit_f64_le (arity 2 -> 1) + F64Ge => visit_f64_ge (arity 2 -> 1) + I32Clz => visit_i32_clz (arity 1 -> 1) + I32Ctz => visit_i32_ctz (arity 1 -> 1) + I32Popcnt => visit_i32_popcnt (arity 1 -> 1) + I32Add => visit_i32_add (arity 2 -> 1) + I32Sub => visit_i32_sub (arity 2 -> 1) + I32Mul => visit_i32_mul (arity 2 -> 1) + I32DivS => visit_i32_div_s (arity 2 -> 1) + I32DivU => visit_i32_div_u (arity 2 -> 1) + I32RemS => visit_i32_rem_s (arity 2 -> 1) + I32RemU => visit_i32_rem_u (arity 2 -> 1) + I32And => visit_i32_and (arity 2 -> 1) + I32Or => visit_i32_or (arity 2 -> 1) + I32Xor => visit_i32_xor (arity 2 -> 1) + I32Shl => visit_i32_shl (arity 2 -> 1) + I32ShrS => visit_i32_shr_s (arity 2 -> 1) + I32ShrU => visit_i32_shr_u (arity 2 -> 1) + I32Rotl => visit_i32_rotl (arity 2 -> 1) + I32Rotr => visit_i32_rotr (arity 2 -> 1) + I64Clz => visit_i64_clz (arity 1 -> 1) + I64Ctz => visit_i64_ctz (arity 1 -> 1) + I64Popcnt => visit_i64_popcnt (arity 1 -> 1) + I64Add => visit_i64_add (arity 2 -> 1) + I64Sub => visit_i64_sub (arity 2 -> 1) + I64Mul => visit_i64_mul (arity 2 -> 1) + I64DivS => visit_i64_div_s (arity 2 -> 1) + I64DivU => visit_i64_div_u (arity 2 -> 1) + I64RemS => visit_i64_rem_s (arity 2 -> 1) + I64RemU => visit_i64_rem_u (arity 2 -> 1) + I64And => visit_i64_and (arity 2 -> 1) + I64Or => visit_i64_or (arity 2 -> 1) + I64Xor => visit_i64_xor (arity 2 -> 1) + I64Shl => visit_i64_shl (arity 2 -> 1) + I64ShrS => visit_i64_shr_s (arity 2 -> 1) + I64ShrU => visit_i64_shr_u (arity 2 -> 1) + I64Rotl => visit_i64_rotl (arity 2 -> 1) + I64Rotr => visit_i64_rotr (arity 2 -> 1) + F32Abs => visit_f32_abs (arity 1 -> 1) + F32Neg => visit_f32_neg (arity 1 -> 1) + F32Ceil => visit_f32_ceil (arity 1 -> 1) + F32Floor => visit_f32_floor (arity 1 -> 1) + F32Trunc => visit_f32_trunc (arity 1 -> 1) + F32Nearest => visit_f32_nearest (arity 1 -> 1) + F32Sqrt => visit_f32_sqrt (arity 1 -> 1) + F32Add => visit_f32_add (arity 2 -> 1) + F32Sub => visit_f32_sub (arity 2 -> 1) + F32Mul => visit_f32_mul (arity 2 -> 1) + F32Div => visit_f32_div (arity 2 -> 1) + F32Min => visit_f32_min (arity 2 -> 1) + F32Max => visit_f32_max (arity 2 -> 1) + F32Copysign => visit_f32_copysign (arity 2 -> 1) + F64Abs => visit_f64_abs (arity 1 -> 1) + F64Neg => visit_f64_neg (arity 1 -> 1) + F64Ceil => visit_f64_ceil (arity 1 -> 1) + F64Floor => visit_f64_floor (arity 1 -> 1) + F64Trunc => visit_f64_trunc (arity 1 -> 1) + F64Nearest => visit_f64_nearest (arity 1 -> 1) + F64Sqrt => visit_f64_sqrt (arity 1 -> 1) + F64Add => visit_f64_add (arity 2 -> 1) + F64Sub => visit_f64_sub (arity 2 -> 1) + F64Mul => visit_f64_mul (arity 2 -> 1) + F64Div => visit_f64_div (arity 2 -> 1) + F64Min => visit_f64_min (arity 2 -> 1) + F64Max => visit_f64_max (arity 2 -> 1) + F64Copysign => visit_f64_copysign (arity 2 -> 1) + I32WrapI64 => visit_i32_wrap_i64 (arity 1 -> 1) + I32TruncF32S => visit_i32_trunc_f32_s (arity 1 -> 1) + I32TruncF32U => visit_i32_trunc_f32_u (arity 1 -> 1) + I32TruncF64S => visit_i32_trunc_f64_s (arity 1 -> 1) + I32TruncF64U => visit_i32_trunc_f64_u (arity 1 -> 1) + I64ExtendI32S => visit_i64_extend_i32_s (arity 1 -> 1) + I64ExtendI32U => visit_i64_extend_i32_u (arity 1 -> 1) + I64TruncF32S => visit_i64_trunc_f32_s (arity 1 -> 1) + I64TruncF32U => visit_i64_trunc_f32_u (arity 1 -> 1) + I64TruncF64S => visit_i64_trunc_f64_s (arity 1 -> 1) + I64TruncF64U => visit_i64_trunc_f64_u (arity 1 -> 1) + F32ConvertI32S => visit_f32_convert_i32_s (arity 1 -> 1) + F32ConvertI32U => visit_f32_convert_i32_u (arity 1 -> 1) + F32ConvertI64S => visit_f32_convert_i64_s (arity 1 -> 1) + F32ConvertI64U => visit_f32_convert_i64_u (arity 1 -> 1) + F32DemoteF64 => visit_f32_demote_f64 (arity 1 -> 1) + F64ConvertI32S => visit_f64_convert_i32_s (arity 1 -> 1) + F64ConvertI32U => visit_f64_convert_i32_u (arity 1 -> 1) + F64ConvertI64S => visit_f64_convert_i64_s (arity 1 -> 1) + F64ConvertI64U => visit_f64_convert_i64_u (arity 1 -> 1) + F64PromoteF32 => visit_f64_promote_f32 (arity 1 -> 1) + I32ReinterpretF32 => visit_i32_reinterpret_f32 (arity 1 -> 1) + I64ReinterpretF64 => visit_i64_reinterpret_f64 (arity 1 -> 1) + F32ReinterpretI32 => visit_f32_reinterpret_i32 (arity 1 -> 1) + F64ReinterpretI64 => visit_f64_reinterpret_i64 (arity 1 -> 1) } @sign_extension { - I32Extend8S => visit_i32_extend8_s (unary i32) - I32Extend16S => visit_i32_extend16_s (unary i32) - I64Extend8S => visit_i64_extend8_s (unary i64) - I64Extend16S => visit_i64_extend16_s (unary i64) - I64Extend32S => visit_i64_extend32_s (unary i64) + I32Extend8S => visit_i32_extend8_s (arity 1 -> 1) + I32Extend16S => visit_i32_extend16_s (arity 1 -> 1) + I64Extend8S => visit_i64_extend8_s (arity 1 -> 1) + I64Extend16S => visit_i64_extend16_s (arity 1 -> 1) + I64Extend32S => visit_i64_extend32_s (arity 1 -> 1) } // 0xFB prefixed operators @@ -258,7 +258,7 @@ macro_rules! _for_each_operator_group { // http://github.com/WebAssembly/gc @gc { RefEq => visit_ref_eq (arity 2 -> 1) - StructNew { struct_type_index: u32 } => visit_struct_new (arity type -> 1) + StructNew { struct_type_index: u32 } => visit_struct_new (arity custom) StructNewDefault { struct_type_index: u32 } => visit_struct_new_default (arity 0 -> 1) StructGet { struct_type_index: u32, field_index: u32 } => visit_struct_get (arity 1 -> 1) StructGetS { struct_type_index: u32, field_index: u32 } => visit_struct_get_s (arity 1 -> 1) @@ -266,7 +266,7 @@ macro_rules! _for_each_operator_group { StructSet { struct_type_index: u32, field_index: u32 } => visit_struct_set (arity 2 -> 0) ArrayNew { array_type_index: u32 } => visit_array_new (arity 2 -> 1) ArrayNewDefault { array_type_index: u32 } => visit_array_new_default (arity 1 -> 1) - ArrayNewFixed { array_type_index: u32, array_size: u32 } => visit_array_new_fixed (arity size -> 1) + ArrayNewFixed { array_type_index: u32, array_size: u32 } => visit_array_new_fixed (arity custom) ArrayNewData { array_type_index: u32, array_data_index: u32 } => visit_array_new_data (arity 2 -> 1) ArrayNewElem { array_type_index: u32, array_elem_index: u32 } => visit_array_new_elem (arity 2 -> 1) ArrayGet { array_type_index: u32 } => visit_array_get (arity 2 -> 1) @@ -286,12 +286,12 @@ macro_rules! _for_each_operator_group { relative_depth: u32, from_ref_type: $crate::RefType, to_ref_type: $crate::RefType - } => visit_br_on_cast (arity br -> br) + } => visit_br_on_cast (arity custom) BrOnCastFail { relative_depth: u32, from_ref_type: $crate::RefType, to_ref_type: $crate::RefType - } => visit_br_on_cast_fail (arity br -> br) + } => visit_br_on_cast_fail (arity custom) AnyConvertExtern => visit_any_convert_extern (arity 1 -> 1) ExternConvertAny => visit_extern_convert_any (arity 1 -> 1) RefI31 => visit_ref_i31 (arity 1 -> 1) @@ -299,18 +299,36 @@ macro_rules! _for_each_operator_group { I31GetU => visit_i31_get_u (arity 1 -> 1) } + @custom_descriptors { + StructNewDesc { struct_type_index: u32 } => visit_struct_new_desc (arity custom) + StructNewDefaultDesc { struct_type_index: u32 } => visit_struct_new_default_desc (arity 1 -> 1) + RefGetDesc { type_index: u32 } => visit_ref_get_desc (arity 1 -> 1) + RefCastDescNonNull { hty: $crate::HeapType } => visit_ref_cast_desc_non_null (arity 2 -> 1) + RefCastDescNullable { hty: $crate::HeapType } => visit_ref_cast_desc_nullable (arity 2 -> 1) + BrOnCastDesc { + relative_depth: u32, + from_ref_type: $crate::RefType, + to_ref_type: $crate::RefType + } => visit_br_on_cast_desc (arity custom) + BrOnCastDescFail { + relative_depth: u32, + from_ref_type: $crate::RefType, + to_ref_type: $crate::RefType + } => visit_br_on_cast_desc_fail (arity custom) + } + // 0xFC operators // Non-trapping Float-to-int Conversions // https://github.com/WebAssembly/nontrapping-float-to-int-conversions @saturating_float_to_int { - I32TruncSatF32S => visit_i32_trunc_sat_f32_s (conversion i32 f32) - I32TruncSatF32U => visit_i32_trunc_sat_f32_u (conversion i32 f32) - I32TruncSatF64S => visit_i32_trunc_sat_f64_s (conversion i32 f64) - I32TruncSatF64U => visit_i32_trunc_sat_f64_u (conversion i32 f64) - I64TruncSatF32S => visit_i64_trunc_sat_f32_s (conversion i64 f32) - I64TruncSatF32U => visit_i64_trunc_sat_f32_u (conversion i64 f32) - I64TruncSatF64S => visit_i64_trunc_sat_f64_s (conversion i64 f64) - I64TruncSatF64U => visit_i64_trunc_sat_f64_u (conversion i64 f64) + I32TruncSatF32S => visit_i32_trunc_sat_f32_s (arity 1 -> 1) + I32TruncSatF32U => visit_i32_trunc_sat_f32_u (arity 1 -> 1) + I32TruncSatF64S => visit_i32_trunc_sat_f64_s (arity 1 -> 1) + I32TruncSatF64U => visit_i32_trunc_sat_f64_u (arity 1 -> 1) + I64TruncSatF32S => visit_i64_trunc_sat_f32_s (arity 1 -> 1) + I64TruncSatF32U => visit_i64_trunc_sat_f32_u (arity 1 -> 1) + I64TruncSatF64S => visit_i64_trunc_sat_f64_s (arity 1 -> 1) + I64TruncSatF64U => visit_i64_trunc_sat_f64_u (arity 1 -> 1) } // 0xFC prefixed operators @@ -331,6 +349,8 @@ macro_rules! _for_each_operator_group { // https://github.com/WebAssembly/reference-types @reference_types { TypedSelect { ty: $crate::ValType } => visit_typed_select (arity 3 -> 1) + // multi-result select is currently invalid, but can be parsed and printed + TypedSelectMulti { tys: Vec<$crate::ValType> } => visit_typed_select_multi (arity custom) RefNull { hty: $crate::HeapType } => visit_ref_null (arity 0 -> 1) RefIsNull => visit_ref_is_null (arity 1 -> 1) RefFunc { function_index: u32 } => visit_ref_func (arity 0 -> 1) @@ -344,8 +364,8 @@ macro_rules! _for_each_operator_group { // Wasm tail-call proposal // https://github.com/WebAssembly/tail-call @tail_call { - ReturnCall { function_index: u32 } => visit_return_call (arity func -> 0) - ReturnCallIndirect { type_index: u32, table_index: u32 } => visit_return_call_indirect (arity 1 type -> 0) + ReturnCall { function_index: u32 } => visit_return_call (arity custom) + ReturnCallIndirect { type_index: u32, table_index: u32 } => visit_return_call_indirect (arity custom) } // OxFC prefixed operators @@ -359,73 +379,73 @@ macro_rules! _for_each_operator_group { // threads // https://github.com/WebAssembly/threads @threads { - MemoryAtomicNotify { memarg: $crate::MemArg } => visit_memory_atomic_notify (atomic rmw i32) + MemoryAtomicNotify { memarg: $crate::MemArg } => visit_memory_atomic_notify (arity 2 -> 1) MemoryAtomicWait32 { memarg: $crate::MemArg } => visit_memory_atomic_wait32 (arity 3 -> 1) MemoryAtomicWait64 { memarg: $crate::MemArg } => visit_memory_atomic_wait64 (arity 3 -> 1) AtomicFence => visit_atomic_fence (arity 0 -> 0) - I32AtomicLoad { memarg: $crate::MemArg } => visit_i32_atomic_load (load atomic i32) - I64AtomicLoad { memarg: $crate::MemArg } => visit_i64_atomic_load (load atomic i64) - I32AtomicLoad8U { memarg: $crate::MemArg } => visit_i32_atomic_load8_u (load atomic i32) - I32AtomicLoad16U { memarg: $crate::MemArg } => visit_i32_atomic_load16_u (load atomic i32) - I64AtomicLoad8U { memarg: $crate::MemArg } => visit_i64_atomic_load8_u (load atomic i64) - I64AtomicLoad16U { memarg: $crate::MemArg } => visit_i64_atomic_load16_u (load atomic i64) - I64AtomicLoad32U { memarg: $crate::MemArg } => visit_i64_atomic_load32_u (load atomic i64) - I32AtomicStore { memarg: $crate::MemArg } => visit_i32_atomic_store (store atomic i32) - I64AtomicStore { memarg: $crate::MemArg } => visit_i64_atomic_store (store atomic i64) - I32AtomicStore8 { memarg: $crate::MemArg } => visit_i32_atomic_store8 (store atomic i32) - I32AtomicStore16 { memarg: $crate::MemArg } => visit_i32_atomic_store16 (store atomic i32) - I64AtomicStore8 { memarg: $crate::MemArg } => visit_i64_atomic_store8 (store atomic i64) - I64AtomicStore16 { memarg: $crate::MemArg } => visit_i64_atomic_store16 (store atomic i64) - I64AtomicStore32 { memarg: $crate::MemArg } => visit_i64_atomic_store32 (store atomic i64) - I32AtomicRmwAdd { memarg: $crate::MemArg } => visit_i32_atomic_rmw_add (atomic rmw i32) - I64AtomicRmwAdd { memarg: $crate::MemArg } => visit_i64_atomic_rmw_add (atomic rmw i64) - I32AtomicRmw8AddU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_add_u (atomic rmw i32) - I32AtomicRmw16AddU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_add_u (atomic rmw i32) - I64AtomicRmw8AddU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_add_u (atomic rmw i64) - I64AtomicRmw16AddU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_add_u (atomic rmw i64) - I64AtomicRmw32AddU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_add_u (atomic rmw i64) - I32AtomicRmwSub { memarg: $crate::MemArg } => visit_i32_atomic_rmw_sub (atomic rmw i32) - I64AtomicRmwSub { memarg: $crate::MemArg } => visit_i64_atomic_rmw_sub (atomic rmw i64) - I32AtomicRmw8SubU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_sub_u (atomic rmw i32) - I32AtomicRmw16SubU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_sub_u (atomic rmw i32) - I64AtomicRmw8SubU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_sub_u (atomic rmw i64) - I64AtomicRmw16SubU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_sub_u (atomic rmw i64) - I64AtomicRmw32SubU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_sub_u (atomic rmw i64) - I32AtomicRmwAnd { memarg: $crate::MemArg } => visit_i32_atomic_rmw_and (atomic rmw i32) - I64AtomicRmwAnd { memarg: $crate::MemArg } => visit_i64_atomic_rmw_and (atomic rmw i64) - I32AtomicRmw8AndU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_and_u (atomic rmw i32) - I32AtomicRmw16AndU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_and_u (atomic rmw i32) - I64AtomicRmw8AndU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_and_u (atomic rmw i64) - I64AtomicRmw16AndU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_and_u (atomic rmw i64) - I64AtomicRmw32AndU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_and_u (atomic rmw i64) - I32AtomicRmwOr { memarg: $crate::MemArg } => visit_i32_atomic_rmw_or (atomic rmw i32) - I64AtomicRmwOr { memarg: $crate::MemArg } => visit_i64_atomic_rmw_or (atomic rmw i64) - I32AtomicRmw8OrU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_or_u (atomic rmw i32) - I32AtomicRmw16OrU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_or_u (atomic rmw i32) - I64AtomicRmw8OrU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_or_u (atomic rmw i64) - I64AtomicRmw16OrU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_or_u (atomic rmw i64) - I64AtomicRmw32OrU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_or_u (atomic rmw i64) - I32AtomicRmwXor { memarg: $crate::MemArg } => visit_i32_atomic_rmw_xor (atomic rmw i32) - I64AtomicRmwXor { memarg: $crate::MemArg } => visit_i64_atomic_rmw_xor (atomic rmw i64) - I32AtomicRmw8XorU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_xor_u (atomic rmw i32) - I32AtomicRmw16XorU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_xor_u (atomic rmw i32) - I64AtomicRmw8XorU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_xor_u (atomic rmw i64) - I64AtomicRmw16XorU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_xor_u (atomic rmw i64) - I64AtomicRmw32XorU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_xor_u (atomic rmw i64) - I32AtomicRmwXchg { memarg: $crate::MemArg } => visit_i32_atomic_rmw_xchg (atomic rmw i32) - I64AtomicRmwXchg { memarg: $crate::MemArg } => visit_i64_atomic_rmw_xchg (atomic rmw i64) - I32AtomicRmw8XchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_xchg_u (atomic rmw i32) - I32AtomicRmw16XchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_xchg_u (atomic rmw i32) - I64AtomicRmw8XchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_xchg_u (atomic rmw i64) - I64AtomicRmw16XchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_xchg_u (atomic rmw i64) - I64AtomicRmw32XchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_xchg_u (atomic rmw i64) - I32AtomicRmwCmpxchg { memarg: $crate::MemArg } => visit_i32_atomic_rmw_cmpxchg (atomic cmpxchg i32) - I64AtomicRmwCmpxchg { memarg: $crate::MemArg } => visit_i64_atomic_rmw_cmpxchg (atomic cmpxchg i64) - I32AtomicRmw8CmpxchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_cmpxchg_u (atomic cmpxchg i32) - I32AtomicRmw16CmpxchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_cmpxchg_u (atomic cmpxchg i32) - I64AtomicRmw8CmpxchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_cmpxchg_u (atomic cmpxchg i64) - I64AtomicRmw16CmpxchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_cmpxchg_u (atomic cmpxchg i64) - I64AtomicRmw32CmpxchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_cmpxchg_u (atomic cmpxchg i64) + I32AtomicLoad { memarg: $crate::MemArg } => visit_i32_atomic_load (arity 1 -> 1) + I64AtomicLoad { memarg: $crate::MemArg } => visit_i64_atomic_load (arity 1 -> 1) + I32AtomicLoad8U { memarg: $crate::MemArg } => visit_i32_atomic_load8_u (arity 1 -> 1) + I32AtomicLoad16U { memarg: $crate::MemArg } => visit_i32_atomic_load16_u (arity 1 -> 1) + I64AtomicLoad8U { memarg: $crate::MemArg } => visit_i64_atomic_load8_u (arity 1 -> 1) + I64AtomicLoad16U { memarg: $crate::MemArg } => visit_i64_atomic_load16_u (arity 1 -> 1) + I64AtomicLoad32U { memarg: $crate::MemArg } => visit_i64_atomic_load32_u (arity 1 -> 1) + I32AtomicStore { memarg: $crate::MemArg } => visit_i32_atomic_store (arity 2 -> 0) + I64AtomicStore { memarg: $crate::MemArg } => visit_i64_atomic_store (arity 2 -> 0) + I32AtomicStore8 { memarg: $crate::MemArg } => visit_i32_atomic_store8 (arity 2 -> 0) + I32AtomicStore16 { memarg: $crate::MemArg } => visit_i32_atomic_store16 (arity 2 -> 0) + I64AtomicStore8 { memarg: $crate::MemArg } => visit_i64_atomic_store8 (arity 2 -> 0) + I64AtomicStore16 { memarg: $crate::MemArg } => visit_i64_atomic_store16 (arity 2 -> 0) + I64AtomicStore32 { memarg: $crate::MemArg } => visit_i64_atomic_store32 (arity 2 -> 0) + I32AtomicRmwAdd { memarg: $crate::MemArg } => visit_i32_atomic_rmw_add (arity 2 -> 1) + I64AtomicRmwAdd { memarg: $crate::MemArg } => visit_i64_atomic_rmw_add (arity 2 -> 1) + I32AtomicRmw8AddU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_add_u (arity 2 -> 1) + I32AtomicRmw16AddU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_add_u (arity 2 -> 1) + I64AtomicRmw8AddU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_add_u (arity 2 -> 1) + I64AtomicRmw16AddU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_add_u (arity 2 -> 1) + I64AtomicRmw32AddU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_add_u (arity 2 -> 1) + I32AtomicRmwSub { memarg: $crate::MemArg } => visit_i32_atomic_rmw_sub (arity 2 -> 1) + I64AtomicRmwSub { memarg: $crate::MemArg } => visit_i64_atomic_rmw_sub (arity 2 -> 1) + I32AtomicRmw8SubU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_sub_u (arity 2 -> 1) + I32AtomicRmw16SubU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_sub_u (arity 2 -> 1) + I64AtomicRmw8SubU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_sub_u (arity 2 -> 1) + I64AtomicRmw16SubU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_sub_u (arity 2 -> 1) + I64AtomicRmw32SubU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_sub_u (arity 2 -> 1) + I32AtomicRmwAnd { memarg: $crate::MemArg } => visit_i32_atomic_rmw_and (arity 2 -> 1) + I64AtomicRmwAnd { memarg: $crate::MemArg } => visit_i64_atomic_rmw_and (arity 2 -> 1) + I32AtomicRmw8AndU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_and_u (arity 2 -> 1) + I32AtomicRmw16AndU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_and_u (arity 2 -> 1) + I64AtomicRmw8AndU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_and_u (arity 2 -> 1) + I64AtomicRmw16AndU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_and_u (arity 2 -> 1) + I64AtomicRmw32AndU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_and_u (arity 2 -> 1) + I32AtomicRmwOr { memarg: $crate::MemArg } => visit_i32_atomic_rmw_or (arity 2 -> 1) + I64AtomicRmwOr { memarg: $crate::MemArg } => visit_i64_atomic_rmw_or (arity 2 -> 1) + I32AtomicRmw8OrU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_or_u (arity 2 -> 1) + I32AtomicRmw16OrU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_or_u (arity 2 -> 1) + I64AtomicRmw8OrU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_or_u (arity 2 -> 1) + I64AtomicRmw16OrU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_or_u (arity 2 -> 1) + I64AtomicRmw32OrU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_or_u (arity 2 -> 1) + I32AtomicRmwXor { memarg: $crate::MemArg } => visit_i32_atomic_rmw_xor (arity 2 -> 1) + I64AtomicRmwXor { memarg: $crate::MemArg } => visit_i64_atomic_rmw_xor (arity 2 -> 1) + I32AtomicRmw8XorU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_xor_u (arity 2 -> 1) + I32AtomicRmw16XorU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_xor_u (arity 2 -> 1) + I64AtomicRmw8XorU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_xor_u (arity 2 -> 1) + I64AtomicRmw16XorU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_xor_u (arity 2 -> 1) + I64AtomicRmw32XorU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_xor_u (arity 2 -> 1) + I32AtomicRmwXchg { memarg: $crate::MemArg } => visit_i32_atomic_rmw_xchg (arity 2 -> 1) + I64AtomicRmwXchg { memarg: $crate::MemArg } => visit_i64_atomic_rmw_xchg (arity 2 -> 1) + I32AtomicRmw8XchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_xchg_u (arity 2 -> 1) + I32AtomicRmw16XchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_xchg_u (arity 2 -> 1) + I64AtomicRmw8XchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_xchg_u (arity 2 -> 1) + I64AtomicRmw16XchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_xchg_u (arity 2 -> 1) + I64AtomicRmw32XchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_xchg_u (arity 2 -> 1) + I32AtomicRmwCmpxchg { memarg: $crate::MemArg } => visit_i32_atomic_rmw_cmpxchg (arity 3 -> 1) + I64AtomicRmwCmpxchg { memarg: $crate::MemArg } => visit_i64_atomic_rmw_cmpxchg (arity 3 -> 1) + I32AtomicRmw8CmpxchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_cmpxchg_u (arity 3 -> 1) + I32AtomicRmw16CmpxchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_cmpxchg_u (arity 3 -> 1) + I64AtomicRmw8CmpxchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_cmpxchg_u (arity 3 -> 1) + I64AtomicRmw16CmpxchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_cmpxchg_u (arity 3 -> 1) + I64AtomicRmw32CmpxchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_cmpxchg_u (arity 3 -> 1) } // 0xFD operators @@ -433,281 +453,281 @@ macro_rules! _for_each_operator_group { // - https://github.com/webassembly/simd // - https://webassembly.github.io/simd/core/binary/instructions.html @simd { - V128Load { memarg: $crate::MemArg } => visit_v128_load (load v128) - V128Load8x8S { memarg: $crate::MemArg } => visit_v128_load8x8_s (load v128) - V128Load8x8U { memarg: $crate::MemArg } => visit_v128_load8x8_u (load v128) - V128Load16x4S { memarg: $crate::MemArg } => visit_v128_load16x4_s (load v128) - V128Load16x4U { memarg: $crate::MemArg } => visit_v128_load16x4_u (load v128) - V128Load32x2S { memarg: $crate::MemArg } => visit_v128_load32x2_s (load v128) - V128Load32x2U { memarg: $crate::MemArg } => visit_v128_load32x2_u (load v128) - V128Load8Splat { memarg: $crate::MemArg } => visit_v128_load8_splat (load v128) - V128Load16Splat { memarg: $crate::MemArg } => visit_v128_load16_splat (load v128) - V128Load32Splat { memarg: $crate::MemArg } => visit_v128_load32_splat (load v128) - V128Load64Splat { memarg: $crate::MemArg } => visit_v128_load64_splat (load v128) - V128Load32Zero { memarg: $crate::MemArg } => visit_v128_load32_zero (load v128) - V128Load64Zero { memarg: $crate::MemArg } => visit_v128_load64_zero (load v128) - V128Store { memarg: $crate::MemArg } => visit_v128_store (store v128) - V128Load8Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load8_lane (load lane 16) - V128Load16Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load16_lane (load lane 8) - V128Load32Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load32_lane (load lane 4) - V128Load64Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load64_lane (load lane 2) - V128Store8Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store8_lane (store lane 16) - V128Store16Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store16_lane (store lane 8) - V128Store32Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store32_lane (store lane 4) - V128Store64Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store64_lane (store lane 2) - V128Const { value: $crate::V128 } => visit_v128_const (push v128) + V128Load { memarg: $crate::MemArg } => visit_v128_load (arity 1 -> 1) + V128Load8x8S { memarg: $crate::MemArg } => visit_v128_load8x8_s (arity 1 -> 1) + V128Load8x8U { memarg: $crate::MemArg } => visit_v128_load8x8_u (arity 1 -> 1) + V128Load16x4S { memarg: $crate::MemArg } => visit_v128_load16x4_s (arity 1 -> 1) + V128Load16x4U { memarg: $crate::MemArg } => visit_v128_load16x4_u (arity 1 -> 1) + V128Load32x2S { memarg: $crate::MemArg } => visit_v128_load32x2_s (arity 1 -> 1) + V128Load32x2U { memarg: $crate::MemArg } => visit_v128_load32x2_u (arity 1 -> 1) + V128Load8Splat { memarg: $crate::MemArg } => visit_v128_load8_splat (arity 1 -> 1) + V128Load16Splat { memarg: $crate::MemArg } => visit_v128_load16_splat (arity 1 -> 1) + V128Load32Splat { memarg: $crate::MemArg } => visit_v128_load32_splat (arity 1 -> 1) + V128Load64Splat { memarg: $crate::MemArg } => visit_v128_load64_splat (arity 1 -> 1) + V128Load32Zero { memarg: $crate::MemArg } => visit_v128_load32_zero (arity 1 -> 1) + V128Load64Zero { memarg: $crate::MemArg } => visit_v128_load64_zero (arity 1 -> 1) + V128Store { memarg: $crate::MemArg } => visit_v128_store (arity 2 -> 0) + V128Load8Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load8_lane (arity 2 -> 1) + V128Load16Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load16_lane (arity 2 -> 1) + V128Load32Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load32_lane (arity 2 -> 1) + V128Load64Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load64_lane (arity 2 -> 1) + V128Store8Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store8_lane (arity 2 -> 0) + V128Store16Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store16_lane (arity 2 -> 0) + V128Store32Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store32_lane (arity 2 -> 0) + V128Store64Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store64_lane (arity 2 -> 0) + V128Const { value: $crate::V128 } => visit_v128_const (arity 0 -> 1) I8x16Shuffle { lanes: [u8; 16] } => visit_i8x16_shuffle (arity 2 -> 1) - I8x16ExtractLaneS { lane: u8 } => visit_i8x16_extract_lane_s (extract i32 16) - I8x16ExtractLaneU { lane: u8 } => visit_i8x16_extract_lane_u (extract i32 16) - I8x16ReplaceLane { lane: u8 } => visit_i8x16_replace_lane (replace i32 16) - I16x8ExtractLaneS { lane: u8 } => visit_i16x8_extract_lane_s (extract i32 8) - I16x8ExtractLaneU { lane: u8 } => visit_i16x8_extract_lane_u (extract i32 8) - I16x8ReplaceLane { lane: u8 } => visit_i16x8_replace_lane (replace i32 8) - I32x4ExtractLane { lane: u8 } => visit_i32x4_extract_lane (extract i32 4) - I32x4ReplaceLane { lane: u8 } => visit_i32x4_replace_lane (replace i32 4) - I64x2ExtractLane { lane: u8 } => visit_i64x2_extract_lane (extract i64 2) - I64x2ReplaceLane { lane: u8 } => visit_i64x2_replace_lane (replace i64 2) - F32x4ExtractLane { lane: u8 } => visit_f32x4_extract_lane (extract f32 4) - F32x4ReplaceLane { lane: u8 } => visit_f32x4_replace_lane (replace f32 4) - F64x2ExtractLane { lane: u8 } => visit_f64x2_extract_lane (extract f64 2) - F64x2ReplaceLane { lane: u8 } => visit_f64x2_replace_lane (replace f64 2) - I8x16Swizzle => visit_i8x16_swizzle (binary v128) - I8x16Splat => visit_i8x16_splat (splat i32) - I16x8Splat => visit_i16x8_splat (splat i32) - I32x4Splat => visit_i32x4_splat (splat i32) - I64x2Splat => visit_i64x2_splat (splat i64) - F32x4Splat => visit_f32x4_splat (splat f32) - F64x2Splat => visit_f64x2_splat (splat f64) - I8x16Eq => visit_i8x16_eq (binary v128) - I8x16Ne => visit_i8x16_ne (binary v128) - I8x16LtS => visit_i8x16_lt_s (binary v128) - I8x16LtU => visit_i8x16_lt_u (binary v128) - I8x16GtS => visit_i8x16_gt_s (binary v128) - I8x16GtU => visit_i8x16_gt_u (binary v128) - I8x16LeS => visit_i8x16_le_s (binary v128) - I8x16LeU => visit_i8x16_le_u (binary v128) - I8x16GeS => visit_i8x16_ge_s (binary v128) - I8x16GeU => visit_i8x16_ge_u (binary v128) - I16x8Eq => visit_i16x8_eq (binary v128) - I16x8Ne => visit_i16x8_ne (binary v128) - I16x8LtS => visit_i16x8_lt_s (binary v128) - I16x8LtU => visit_i16x8_lt_u (binary v128) - I16x8GtS => visit_i16x8_gt_s (binary v128) - I16x8GtU => visit_i16x8_gt_u (binary v128) - I16x8LeS => visit_i16x8_le_s (binary v128) - I16x8LeU => visit_i16x8_le_u (binary v128) - I16x8GeS => visit_i16x8_ge_s (binary v128) - I16x8GeU => visit_i16x8_ge_u (binary v128) - I32x4Eq => visit_i32x4_eq (binary v128) - I32x4Ne => visit_i32x4_ne (binary v128) - I32x4LtS => visit_i32x4_lt_s (binary v128) - I32x4LtU => visit_i32x4_lt_u (binary v128) - I32x4GtS => visit_i32x4_gt_s (binary v128) - I32x4GtU => visit_i32x4_gt_u (binary v128) - I32x4LeS => visit_i32x4_le_s (binary v128) - I32x4LeU => visit_i32x4_le_u (binary v128) - I32x4GeS => visit_i32x4_ge_s (binary v128) - I32x4GeU => visit_i32x4_ge_u (binary v128) - I64x2Eq => visit_i64x2_eq (binary v128) - I64x2Ne => visit_i64x2_ne (binary v128) - I64x2LtS => visit_i64x2_lt_s (binary v128) - I64x2GtS => visit_i64x2_gt_s (binary v128) - I64x2LeS => visit_i64x2_le_s (binary v128) - I64x2GeS => visit_i64x2_ge_s (binary v128) - F32x4Eq => visit_f32x4_eq (binary v128f) - F32x4Ne => visit_f32x4_ne (binary v128f) - F32x4Lt => visit_f32x4_lt (binary v128f) - F32x4Gt => visit_f32x4_gt (binary v128f) - F32x4Le => visit_f32x4_le (binary v128f) - F32x4Ge => visit_f32x4_ge (binary v128f) - F64x2Eq => visit_f64x2_eq (binary v128f) - F64x2Ne => visit_f64x2_ne (binary v128f) - F64x2Lt => visit_f64x2_lt (binary v128f) - F64x2Gt => visit_f64x2_gt (binary v128f) - F64x2Le => visit_f64x2_le (binary v128f) - F64x2Ge => visit_f64x2_ge (binary v128f) - V128Not => visit_v128_not (unary v128) - V128And => visit_v128_and (binary v128) - V128AndNot => visit_v128_andnot (binary v128) - V128Or => visit_v128_or (binary v128) - V128Xor => visit_v128_xor (binary v128) - V128Bitselect => visit_v128_bitselect (ternary v128) - V128AnyTrue => visit_v128_any_true (test v128) - I8x16Abs => visit_i8x16_abs (unary v128) - I8x16Neg => visit_i8x16_neg (unary v128) - I8x16Popcnt => visit_i8x16_popcnt (unary v128) - I8x16AllTrue => visit_i8x16_all_true (test v128) - I8x16Bitmask => visit_i8x16_bitmask (test v128) - I8x16NarrowI16x8S => visit_i8x16_narrow_i16x8_s (binary v128) - I8x16NarrowI16x8U => visit_i8x16_narrow_i16x8_u (binary v128) - I8x16Shl => visit_i8x16_shl (shift v128) - I8x16ShrS => visit_i8x16_shr_s (shift v128) - I8x16ShrU => visit_i8x16_shr_u (shift v128) - I8x16Add => visit_i8x16_add (binary v128) - I8x16AddSatS => visit_i8x16_add_sat_s (binary v128) - I8x16AddSatU => visit_i8x16_add_sat_u (binary v128) - I8x16Sub => visit_i8x16_sub (binary v128) - I8x16SubSatS => visit_i8x16_sub_sat_s (binary v128) - I8x16SubSatU => visit_i8x16_sub_sat_u (binary v128) - I8x16MinS => visit_i8x16_min_s (binary v128) - I8x16MinU => visit_i8x16_min_u (binary v128) - I8x16MaxS => visit_i8x16_max_s (binary v128) - I8x16MaxU => visit_i8x16_max_u (binary v128) - I8x16AvgrU => visit_i8x16_avgr_u (binary v128) - I16x8ExtAddPairwiseI8x16S => visit_i16x8_extadd_pairwise_i8x16_s (unary v128) - I16x8ExtAddPairwiseI8x16U => visit_i16x8_extadd_pairwise_i8x16_u (unary v128) - I16x8Abs => visit_i16x8_abs (unary v128) - I16x8Neg => visit_i16x8_neg (unary v128) - I16x8Q15MulrSatS => visit_i16x8_q15mulr_sat_s (binary v128) - I16x8AllTrue => visit_i16x8_all_true (test v128) - I16x8Bitmask => visit_i16x8_bitmask (test v128) - I16x8NarrowI32x4S => visit_i16x8_narrow_i32x4_s (binary v128) - I16x8NarrowI32x4U => visit_i16x8_narrow_i32x4_u (binary v128) - I16x8ExtendLowI8x16S => visit_i16x8_extend_low_i8x16_s (unary v128) - I16x8ExtendHighI8x16S => visit_i16x8_extend_high_i8x16_s (unary v128) - I16x8ExtendLowI8x16U => visit_i16x8_extend_low_i8x16_u (unary v128) - I16x8ExtendHighI8x16U => visit_i16x8_extend_high_i8x16_u (unary v128) - I16x8Shl => visit_i16x8_shl (shift v128) - I16x8ShrS => visit_i16x8_shr_s (shift v128) - I16x8ShrU => visit_i16x8_shr_u (shift v128) - I16x8Add => visit_i16x8_add (binary v128) - I16x8AddSatS => visit_i16x8_add_sat_s (binary v128) - I16x8AddSatU => visit_i16x8_add_sat_u (binary v128) - I16x8Sub => visit_i16x8_sub (binary v128) - I16x8SubSatS => visit_i16x8_sub_sat_s (binary v128) - I16x8SubSatU => visit_i16x8_sub_sat_u (binary v128) - I16x8Mul => visit_i16x8_mul (binary v128) - I16x8MinS => visit_i16x8_min_s (binary v128) - I16x8MinU => visit_i16x8_min_u (binary v128) - I16x8MaxS => visit_i16x8_max_s (binary v128) - I16x8MaxU => visit_i16x8_max_u (binary v128) - I16x8AvgrU => visit_i16x8_avgr_u (binary v128) - I16x8ExtMulLowI8x16S => visit_i16x8_extmul_low_i8x16_s (binary v128) - I16x8ExtMulHighI8x16S => visit_i16x8_extmul_high_i8x16_s (binary v128) - I16x8ExtMulLowI8x16U => visit_i16x8_extmul_low_i8x16_u (binary v128) - I16x8ExtMulHighI8x16U => visit_i16x8_extmul_high_i8x16_u (binary v128) - I32x4ExtAddPairwiseI16x8S => visit_i32x4_extadd_pairwise_i16x8_s (unary v128) - I32x4ExtAddPairwiseI16x8U => visit_i32x4_extadd_pairwise_i16x8_u (unary v128) - I32x4Abs => visit_i32x4_abs (unary v128) - I32x4Neg => visit_i32x4_neg (unary v128) - I32x4AllTrue => visit_i32x4_all_true (test v128) - I32x4Bitmask => visit_i32x4_bitmask (test v128) - I32x4ExtendLowI16x8S => visit_i32x4_extend_low_i16x8_s (unary v128) - I32x4ExtendHighI16x8S => visit_i32x4_extend_high_i16x8_s (unary v128) - I32x4ExtendLowI16x8U => visit_i32x4_extend_low_i16x8_u (unary v128) - I32x4ExtendHighI16x8U => visit_i32x4_extend_high_i16x8_u (unary v128) - I32x4Shl => visit_i32x4_shl (shift v128) - I32x4ShrS => visit_i32x4_shr_s (shift v128) - I32x4ShrU => visit_i32x4_shr_u (shift v128) - I32x4Add => visit_i32x4_add (binary v128) - I32x4Sub => visit_i32x4_sub (binary v128) - I32x4Mul => visit_i32x4_mul (binary v128) - I32x4MinS => visit_i32x4_min_s (binary v128) - I32x4MinU => visit_i32x4_min_u (binary v128) - I32x4MaxS => visit_i32x4_max_s (binary v128) - I32x4MaxU => visit_i32x4_max_u (binary v128) - I32x4DotI16x8S => visit_i32x4_dot_i16x8_s (binary v128) - I32x4ExtMulLowI16x8S => visit_i32x4_extmul_low_i16x8_s (binary v128) - I32x4ExtMulHighI16x8S => visit_i32x4_extmul_high_i16x8_s (binary v128) - I32x4ExtMulLowI16x8U => visit_i32x4_extmul_low_i16x8_u (binary v128) - I32x4ExtMulHighI16x8U => visit_i32x4_extmul_high_i16x8_u (binary v128) - I64x2Abs => visit_i64x2_abs (unary v128) - I64x2Neg => visit_i64x2_neg (unary v128) - I64x2AllTrue => visit_i64x2_all_true (test v128) - I64x2Bitmask => visit_i64x2_bitmask (test v128) - I64x2ExtendLowI32x4S => visit_i64x2_extend_low_i32x4_s (unary v128) - I64x2ExtendHighI32x4S => visit_i64x2_extend_high_i32x4_s (unary v128) - I64x2ExtendLowI32x4U => visit_i64x2_extend_low_i32x4_u (unary v128) - I64x2ExtendHighI32x4U => visit_i64x2_extend_high_i32x4_u (unary v128) - I64x2Shl => visit_i64x2_shl (shift v128) - I64x2ShrS => visit_i64x2_shr_s (shift v128) - I64x2ShrU => visit_i64x2_shr_u (shift v128) - I64x2Add => visit_i64x2_add (binary v128) - I64x2Sub => visit_i64x2_sub (binary v128) - I64x2Mul => visit_i64x2_mul (binary v128) - I64x2ExtMulLowI32x4S => visit_i64x2_extmul_low_i32x4_s (binary v128) - I64x2ExtMulHighI32x4S => visit_i64x2_extmul_high_i32x4_s (binary v128) - I64x2ExtMulLowI32x4U => visit_i64x2_extmul_low_i32x4_u (binary v128) - I64x2ExtMulHighI32x4U => visit_i64x2_extmul_high_i32x4_u (binary v128) - F32x4Ceil => visit_f32x4_ceil (unary v128f) - F32x4Floor => visit_f32x4_floor (unary v128f) - F32x4Trunc => visit_f32x4_trunc (unary v128f) - F32x4Nearest => visit_f32x4_nearest (unary v128f) - F32x4Abs => visit_f32x4_abs (unary v128f) - F32x4Neg => visit_f32x4_neg (unary v128f) - F32x4Sqrt => visit_f32x4_sqrt (unary v128f) - F32x4Add => visit_f32x4_add (binary v128f) - F32x4Sub => visit_f32x4_sub (binary v128f) - F32x4Mul => visit_f32x4_mul (binary v128f) - F32x4Div => visit_f32x4_div (binary v128f) - F32x4Min => visit_f32x4_min (binary v128f) - F32x4Max => visit_f32x4_max (binary v128f) - F32x4PMin => visit_f32x4_pmin (binary v128f) - F32x4PMax => visit_f32x4_pmax (binary v128f) - F64x2Ceil => visit_f64x2_ceil (unary v128f) - F64x2Floor => visit_f64x2_floor (unary v128f) - F64x2Trunc => visit_f64x2_trunc (unary v128f) - F64x2Nearest => visit_f64x2_nearest (unary v128f) - F64x2Abs => visit_f64x2_abs (unary v128f) - F64x2Neg => visit_f64x2_neg (unary v128f) - F64x2Sqrt => visit_f64x2_sqrt (unary v128f) - F64x2Add => visit_f64x2_add (binary v128f) - F64x2Sub => visit_f64x2_sub (binary v128f) - F64x2Mul => visit_f64x2_mul (binary v128f) - F64x2Div => visit_f64x2_div (binary v128f) - F64x2Min => visit_f64x2_min (binary v128f) - F64x2Max => visit_f64x2_max (binary v128f) - F64x2PMin => visit_f64x2_pmin (binary v128f) - F64x2PMax => visit_f64x2_pmax (binary v128f) - I32x4TruncSatF32x4S => visit_i32x4_trunc_sat_f32x4_s (unary v128f) - I32x4TruncSatF32x4U => visit_i32x4_trunc_sat_f32x4_u (unary v128f) - F32x4ConvertI32x4S => visit_f32x4_convert_i32x4_s (unary v128f) - F32x4ConvertI32x4U => visit_f32x4_convert_i32x4_u (unary v128f) - I32x4TruncSatF64x2SZero => visit_i32x4_trunc_sat_f64x2_s_zero (unary v128f) - I32x4TruncSatF64x2UZero => visit_i32x4_trunc_sat_f64x2_u_zero (unary v128f) - F64x2ConvertLowI32x4S => visit_f64x2_convert_low_i32x4_s (unary v128f) - F64x2ConvertLowI32x4U => visit_f64x2_convert_low_i32x4_u (unary v128f) - F32x4DemoteF64x2Zero => visit_f32x4_demote_f64x2_zero (unary v128f) - F64x2PromoteLowF32x4 => visit_f64x2_promote_low_f32x4 (unary v128f) + I8x16ExtractLaneS { lane: u8 } => visit_i8x16_extract_lane_s (arity 1 -> 1) + I8x16ExtractLaneU { lane: u8 } => visit_i8x16_extract_lane_u (arity 1 -> 1) + I8x16ReplaceLane { lane: u8 } => visit_i8x16_replace_lane (arity 2 -> 1) + I16x8ExtractLaneS { lane: u8 } => visit_i16x8_extract_lane_s (arity 1 -> 1) + I16x8ExtractLaneU { lane: u8 } => visit_i16x8_extract_lane_u (arity 1 -> 1) + I16x8ReplaceLane { lane: u8 } => visit_i16x8_replace_lane (arity 2 -> 1) + I32x4ExtractLane { lane: u8 } => visit_i32x4_extract_lane (arity 1 -> 1) + I32x4ReplaceLane { lane: u8 } => visit_i32x4_replace_lane (arity 2 -> 1) + I64x2ExtractLane { lane: u8 } => visit_i64x2_extract_lane (arity 1 -> 1) + I64x2ReplaceLane { lane: u8 } => visit_i64x2_replace_lane (arity 2 -> 1) + F32x4ExtractLane { lane: u8 } => visit_f32x4_extract_lane (arity 1 -> 1) + F32x4ReplaceLane { lane: u8 } => visit_f32x4_replace_lane (arity 2 -> 1) + F64x2ExtractLane { lane: u8 } => visit_f64x2_extract_lane (arity 1 -> 1) + F64x2ReplaceLane { lane: u8 } => visit_f64x2_replace_lane (arity 2 -> 1) + I8x16Swizzle => visit_i8x16_swizzle (arity 2 -> 1) + I8x16Splat => visit_i8x16_splat (arity 1 -> 1) + I16x8Splat => visit_i16x8_splat (arity 1 -> 1) + I32x4Splat => visit_i32x4_splat (arity 1 -> 1) + I64x2Splat => visit_i64x2_splat (arity 1 -> 1) + F32x4Splat => visit_f32x4_splat (arity 1 -> 1) + F64x2Splat => visit_f64x2_splat (arity 1 -> 1) + I8x16Eq => visit_i8x16_eq (arity 2 -> 1) + I8x16Ne => visit_i8x16_ne (arity 2 -> 1) + I8x16LtS => visit_i8x16_lt_s (arity 2 -> 1) + I8x16LtU => visit_i8x16_lt_u (arity 2 -> 1) + I8x16GtS => visit_i8x16_gt_s (arity 2 -> 1) + I8x16GtU => visit_i8x16_gt_u (arity 2 -> 1) + I8x16LeS => visit_i8x16_le_s (arity 2 -> 1) + I8x16LeU => visit_i8x16_le_u (arity 2 -> 1) + I8x16GeS => visit_i8x16_ge_s (arity 2 -> 1) + I8x16GeU => visit_i8x16_ge_u (arity 2 -> 1) + I16x8Eq => visit_i16x8_eq (arity 2 -> 1) + I16x8Ne => visit_i16x8_ne (arity 2 -> 1) + I16x8LtS => visit_i16x8_lt_s (arity 2 -> 1) + I16x8LtU => visit_i16x8_lt_u (arity 2 -> 1) + I16x8GtS => visit_i16x8_gt_s (arity 2 -> 1) + I16x8GtU => visit_i16x8_gt_u (arity 2 -> 1) + I16x8LeS => visit_i16x8_le_s (arity 2 -> 1) + I16x8LeU => visit_i16x8_le_u (arity 2 -> 1) + I16x8GeS => visit_i16x8_ge_s (arity 2 -> 1) + I16x8GeU => visit_i16x8_ge_u (arity 2 -> 1) + I32x4Eq => visit_i32x4_eq (arity 2 -> 1) + I32x4Ne => visit_i32x4_ne (arity 2 -> 1) + I32x4LtS => visit_i32x4_lt_s (arity 2 -> 1) + I32x4LtU => visit_i32x4_lt_u (arity 2 -> 1) + I32x4GtS => visit_i32x4_gt_s (arity 2 -> 1) + I32x4GtU => visit_i32x4_gt_u (arity 2 -> 1) + I32x4LeS => visit_i32x4_le_s (arity 2 -> 1) + I32x4LeU => visit_i32x4_le_u (arity 2 -> 1) + I32x4GeS => visit_i32x4_ge_s (arity 2 -> 1) + I32x4GeU => visit_i32x4_ge_u (arity 2 -> 1) + I64x2Eq => visit_i64x2_eq (arity 2 -> 1) + I64x2Ne => visit_i64x2_ne (arity 2 -> 1) + I64x2LtS => visit_i64x2_lt_s (arity 2 -> 1) + I64x2GtS => visit_i64x2_gt_s (arity 2 -> 1) + I64x2LeS => visit_i64x2_le_s (arity 2 -> 1) + I64x2GeS => visit_i64x2_ge_s (arity 2 -> 1) + F32x4Eq => visit_f32x4_eq (arity 2 -> 1) + F32x4Ne => visit_f32x4_ne (arity 2 -> 1) + F32x4Lt => visit_f32x4_lt (arity 2 -> 1) + F32x4Gt => visit_f32x4_gt (arity 2 -> 1) + F32x4Le => visit_f32x4_le (arity 2 -> 1) + F32x4Ge => visit_f32x4_ge (arity 2 -> 1) + F64x2Eq => visit_f64x2_eq (arity 2 -> 1) + F64x2Ne => visit_f64x2_ne (arity 2 -> 1) + F64x2Lt => visit_f64x2_lt (arity 2 -> 1) + F64x2Gt => visit_f64x2_gt (arity 2 -> 1) + F64x2Le => visit_f64x2_le (arity 2 -> 1) + F64x2Ge => visit_f64x2_ge (arity 2 -> 1) + V128Not => visit_v128_not (arity 1 -> 1) + V128And => visit_v128_and (arity 2 -> 1) + V128AndNot => visit_v128_andnot (arity 2 -> 1) + V128Or => visit_v128_or (arity 2 -> 1) + V128Xor => visit_v128_xor (arity 2 -> 1) + V128Bitselect => visit_v128_bitselect (arity 3 -> 1) + V128AnyTrue => visit_v128_any_true (arity 1 -> 1) + I8x16Abs => visit_i8x16_abs (arity 1 -> 1) + I8x16Neg => visit_i8x16_neg (arity 1 -> 1) + I8x16Popcnt => visit_i8x16_popcnt (arity 1 -> 1) + I8x16AllTrue => visit_i8x16_all_true (arity 1 -> 1) + I8x16Bitmask => visit_i8x16_bitmask (arity 1 -> 1) + I8x16NarrowI16x8S => visit_i8x16_narrow_i16x8_s (arity 2 -> 1) + I8x16NarrowI16x8U => visit_i8x16_narrow_i16x8_u (arity 2 -> 1) + I8x16Shl => visit_i8x16_shl (arity 2 -> 1) + I8x16ShrS => visit_i8x16_shr_s (arity 2 -> 1) + I8x16ShrU => visit_i8x16_shr_u (arity 2 -> 1) + I8x16Add => visit_i8x16_add (arity 2 -> 1) + I8x16AddSatS => visit_i8x16_add_sat_s (arity 2 -> 1) + I8x16AddSatU => visit_i8x16_add_sat_u (arity 2 -> 1) + I8x16Sub => visit_i8x16_sub (arity 2 -> 1) + I8x16SubSatS => visit_i8x16_sub_sat_s (arity 2 -> 1) + I8x16SubSatU => visit_i8x16_sub_sat_u (arity 2 -> 1) + I8x16MinS => visit_i8x16_min_s (arity 2 -> 1) + I8x16MinU => visit_i8x16_min_u (arity 2 -> 1) + I8x16MaxS => visit_i8x16_max_s (arity 2 -> 1) + I8x16MaxU => visit_i8x16_max_u (arity 2 -> 1) + I8x16AvgrU => visit_i8x16_avgr_u (arity 2 -> 1) + I16x8ExtAddPairwiseI8x16S => visit_i16x8_extadd_pairwise_i8x16_s (arity 1 -> 1) + I16x8ExtAddPairwiseI8x16U => visit_i16x8_extadd_pairwise_i8x16_u (arity 1 -> 1) + I16x8Abs => visit_i16x8_abs (arity 1 -> 1) + I16x8Neg => visit_i16x8_neg (arity 1 -> 1) + I16x8Q15MulrSatS => visit_i16x8_q15mulr_sat_s (arity 2 -> 1) + I16x8AllTrue => visit_i16x8_all_true (arity 1 -> 1) + I16x8Bitmask => visit_i16x8_bitmask (arity 1 -> 1) + I16x8NarrowI32x4S => visit_i16x8_narrow_i32x4_s (arity 2 -> 1) + I16x8NarrowI32x4U => visit_i16x8_narrow_i32x4_u (arity 2 -> 1) + I16x8ExtendLowI8x16S => visit_i16x8_extend_low_i8x16_s (arity 1 -> 1) + I16x8ExtendHighI8x16S => visit_i16x8_extend_high_i8x16_s (arity 1 -> 1) + I16x8ExtendLowI8x16U => visit_i16x8_extend_low_i8x16_u (arity 1 -> 1) + I16x8ExtendHighI8x16U => visit_i16x8_extend_high_i8x16_u (arity 1 -> 1) + I16x8Shl => visit_i16x8_shl (arity 2 -> 1) + I16x8ShrS => visit_i16x8_shr_s (arity 2 -> 1) + I16x8ShrU => visit_i16x8_shr_u (arity 2 -> 1) + I16x8Add => visit_i16x8_add (arity 2 -> 1) + I16x8AddSatS => visit_i16x8_add_sat_s (arity 2 -> 1) + I16x8AddSatU => visit_i16x8_add_sat_u (arity 2 -> 1) + I16x8Sub => visit_i16x8_sub (arity 2 -> 1) + I16x8SubSatS => visit_i16x8_sub_sat_s (arity 2 -> 1) + I16x8SubSatU => visit_i16x8_sub_sat_u (arity 2 -> 1) + I16x8Mul => visit_i16x8_mul (arity 2 -> 1) + I16x8MinS => visit_i16x8_min_s (arity 2 -> 1) + I16x8MinU => visit_i16x8_min_u (arity 2 -> 1) + I16x8MaxS => visit_i16x8_max_s (arity 2 -> 1) + I16x8MaxU => visit_i16x8_max_u (arity 2 -> 1) + I16x8AvgrU => visit_i16x8_avgr_u (arity 2 -> 1) + I16x8ExtMulLowI8x16S => visit_i16x8_extmul_low_i8x16_s (arity 2 -> 1) + I16x8ExtMulHighI8x16S => visit_i16x8_extmul_high_i8x16_s (arity 2 -> 1) + I16x8ExtMulLowI8x16U => visit_i16x8_extmul_low_i8x16_u (arity 2 -> 1) + I16x8ExtMulHighI8x16U => visit_i16x8_extmul_high_i8x16_u (arity 2 -> 1) + I32x4ExtAddPairwiseI16x8S => visit_i32x4_extadd_pairwise_i16x8_s (arity 1 -> 1) + I32x4ExtAddPairwiseI16x8U => visit_i32x4_extadd_pairwise_i16x8_u (arity 1 -> 1) + I32x4Abs => visit_i32x4_abs (arity 1 -> 1) + I32x4Neg => visit_i32x4_neg (arity 1 -> 1) + I32x4AllTrue => visit_i32x4_all_true (arity 1 -> 1) + I32x4Bitmask => visit_i32x4_bitmask (arity 1 -> 1) + I32x4ExtendLowI16x8S => visit_i32x4_extend_low_i16x8_s (arity 1 -> 1) + I32x4ExtendHighI16x8S => visit_i32x4_extend_high_i16x8_s (arity 1 -> 1) + I32x4ExtendLowI16x8U => visit_i32x4_extend_low_i16x8_u (arity 1 -> 1) + I32x4ExtendHighI16x8U => visit_i32x4_extend_high_i16x8_u (arity 1 -> 1) + I32x4Shl => visit_i32x4_shl (arity 2 -> 1) + I32x4ShrS => visit_i32x4_shr_s (arity 2 -> 1) + I32x4ShrU => visit_i32x4_shr_u (arity 2 -> 1) + I32x4Add => visit_i32x4_add (arity 2 -> 1) + I32x4Sub => visit_i32x4_sub (arity 2 -> 1) + I32x4Mul => visit_i32x4_mul (arity 2 -> 1) + I32x4MinS => visit_i32x4_min_s (arity 2 -> 1) + I32x4MinU => visit_i32x4_min_u (arity 2 -> 1) + I32x4MaxS => visit_i32x4_max_s (arity 2 -> 1) + I32x4MaxU => visit_i32x4_max_u (arity 2 -> 1) + I32x4DotI16x8S => visit_i32x4_dot_i16x8_s (arity 2 -> 1) + I32x4ExtMulLowI16x8S => visit_i32x4_extmul_low_i16x8_s (arity 2 -> 1) + I32x4ExtMulHighI16x8S => visit_i32x4_extmul_high_i16x8_s (arity 2 -> 1) + I32x4ExtMulLowI16x8U => visit_i32x4_extmul_low_i16x8_u (arity 2 -> 1) + I32x4ExtMulHighI16x8U => visit_i32x4_extmul_high_i16x8_u (arity 2 -> 1) + I64x2Abs => visit_i64x2_abs (arity 1 -> 1) + I64x2Neg => visit_i64x2_neg (arity 1 -> 1) + I64x2AllTrue => visit_i64x2_all_true (arity 1 -> 1) + I64x2Bitmask => visit_i64x2_bitmask (arity 1 -> 1) + I64x2ExtendLowI32x4S => visit_i64x2_extend_low_i32x4_s (arity 1 -> 1) + I64x2ExtendHighI32x4S => visit_i64x2_extend_high_i32x4_s (arity 1 -> 1) + I64x2ExtendLowI32x4U => visit_i64x2_extend_low_i32x4_u (arity 1 -> 1) + I64x2ExtendHighI32x4U => visit_i64x2_extend_high_i32x4_u (arity 1 -> 1) + I64x2Shl => visit_i64x2_shl (arity 2 -> 1) + I64x2ShrS => visit_i64x2_shr_s (arity 2 -> 1) + I64x2ShrU => visit_i64x2_shr_u (arity 2 -> 1) + I64x2Add => visit_i64x2_add (arity 2 -> 1) + I64x2Sub => visit_i64x2_sub (arity 2 -> 1) + I64x2Mul => visit_i64x2_mul (arity 2 -> 1) + I64x2ExtMulLowI32x4S => visit_i64x2_extmul_low_i32x4_s (arity 2 -> 1) + I64x2ExtMulHighI32x4S => visit_i64x2_extmul_high_i32x4_s (arity 2 -> 1) + I64x2ExtMulLowI32x4U => visit_i64x2_extmul_low_i32x4_u (arity 2 -> 1) + I64x2ExtMulHighI32x4U => visit_i64x2_extmul_high_i32x4_u (arity 2 -> 1) + F32x4Ceil => visit_f32x4_ceil (arity 1 -> 1) + F32x4Floor => visit_f32x4_floor (arity 1 -> 1) + F32x4Trunc => visit_f32x4_trunc (arity 1 -> 1) + F32x4Nearest => visit_f32x4_nearest (arity 1 -> 1) + F32x4Abs => visit_f32x4_abs (arity 1 -> 1) + F32x4Neg => visit_f32x4_neg (arity 1 -> 1) + F32x4Sqrt => visit_f32x4_sqrt (arity 1 -> 1) + F32x4Add => visit_f32x4_add (arity 2 -> 1) + F32x4Sub => visit_f32x4_sub (arity 2 -> 1) + F32x4Mul => visit_f32x4_mul (arity 2 -> 1) + F32x4Div => visit_f32x4_div (arity 2 -> 1) + F32x4Min => visit_f32x4_min (arity 2 -> 1) + F32x4Max => visit_f32x4_max (arity 2 -> 1) + F32x4PMin => visit_f32x4_pmin (arity 2 -> 1) + F32x4PMax => visit_f32x4_pmax (arity 2 -> 1) + F64x2Ceil => visit_f64x2_ceil (arity 1 -> 1) + F64x2Floor => visit_f64x2_floor (arity 1 -> 1) + F64x2Trunc => visit_f64x2_trunc (arity 1 -> 1) + F64x2Nearest => visit_f64x2_nearest (arity 1 -> 1) + F64x2Abs => visit_f64x2_abs (arity 1 -> 1) + F64x2Neg => visit_f64x2_neg (arity 1 -> 1) + F64x2Sqrt => visit_f64x2_sqrt (arity 1 -> 1) + F64x2Add => visit_f64x2_add (arity 2 -> 1) + F64x2Sub => visit_f64x2_sub (arity 2 -> 1) + F64x2Mul => visit_f64x2_mul (arity 2 -> 1) + F64x2Div => visit_f64x2_div (arity 2 -> 1) + F64x2Min => visit_f64x2_min (arity 2 -> 1) + F64x2Max => visit_f64x2_max (arity 2 -> 1) + F64x2PMin => visit_f64x2_pmin (arity 2 -> 1) + F64x2PMax => visit_f64x2_pmax (arity 2 -> 1) + I32x4TruncSatF32x4S => visit_i32x4_trunc_sat_f32x4_s (arity 1 -> 1) + I32x4TruncSatF32x4U => visit_i32x4_trunc_sat_f32x4_u (arity 1 -> 1) + F32x4ConvertI32x4S => visit_f32x4_convert_i32x4_s (arity 1 -> 1) + F32x4ConvertI32x4U => visit_f32x4_convert_i32x4_u (arity 1 -> 1) + I32x4TruncSatF64x2SZero => visit_i32x4_trunc_sat_f64x2_s_zero (arity 1 -> 1) + I32x4TruncSatF64x2UZero => visit_i32x4_trunc_sat_f64x2_u_zero (arity 1 -> 1) + F64x2ConvertLowI32x4S => visit_f64x2_convert_low_i32x4_s (arity 1 -> 1) + F64x2ConvertLowI32x4U => visit_f64x2_convert_low_i32x4_u (arity 1 -> 1) + F32x4DemoteF64x2Zero => visit_f32x4_demote_f64x2_zero (arity 1 -> 1) + F64x2PromoteLowF32x4 => visit_f64x2_promote_low_f32x4 (arity 1 -> 1) } // Relaxed SIMD operators // https://github.com/WebAssembly/relaxed-simd @relaxed_simd { - I8x16RelaxedSwizzle => visit_i8x16_relaxed_swizzle (binary v128) - I32x4RelaxedTruncF32x4S => visit_i32x4_relaxed_trunc_f32x4_s (unary v128) - I32x4RelaxedTruncF32x4U => visit_i32x4_relaxed_trunc_f32x4_u (unary v128) - I32x4RelaxedTruncF64x2SZero => visit_i32x4_relaxed_trunc_f64x2_s_zero (unary v128) - I32x4RelaxedTruncF64x2UZero => visit_i32x4_relaxed_trunc_f64x2_u_zero (unary v128) - F32x4RelaxedMadd => visit_f32x4_relaxed_madd (ternary v128) - F32x4RelaxedNmadd => visit_f32x4_relaxed_nmadd (ternary v128) - F64x2RelaxedMadd => visit_f64x2_relaxed_madd (ternary v128) - F64x2RelaxedNmadd => visit_f64x2_relaxed_nmadd (ternary v128) - I8x16RelaxedLaneselect => visit_i8x16_relaxed_laneselect (ternary v128) - I16x8RelaxedLaneselect => visit_i16x8_relaxed_laneselect (ternary v128) - I32x4RelaxedLaneselect => visit_i32x4_relaxed_laneselect (ternary v128) - I64x2RelaxedLaneselect => visit_i64x2_relaxed_laneselect (ternary v128) - F32x4RelaxedMin => visit_f32x4_relaxed_min (binary v128) - F32x4RelaxedMax => visit_f32x4_relaxed_max (binary v128) - F64x2RelaxedMin => visit_f64x2_relaxed_min (binary v128) - F64x2RelaxedMax => visit_f64x2_relaxed_max (binary v128) - I16x8RelaxedQ15mulrS => visit_i16x8_relaxed_q15mulr_s (binary v128) - I16x8RelaxedDotI8x16I7x16S => visit_i16x8_relaxed_dot_i8x16_i7x16_s (binary v128) - I32x4RelaxedDotI8x16I7x16AddS => visit_i32x4_relaxed_dot_i8x16_i7x16_add_s (ternary v128) + I8x16RelaxedSwizzle => visit_i8x16_relaxed_swizzle (arity 2 -> 1) + I32x4RelaxedTruncF32x4S => visit_i32x4_relaxed_trunc_f32x4_s (arity 1 -> 1) + I32x4RelaxedTruncF32x4U => visit_i32x4_relaxed_trunc_f32x4_u (arity 1 -> 1) + I32x4RelaxedTruncF64x2SZero => visit_i32x4_relaxed_trunc_f64x2_s_zero (arity 1 -> 1) + I32x4RelaxedTruncF64x2UZero => visit_i32x4_relaxed_trunc_f64x2_u_zero (arity 1 -> 1) + F32x4RelaxedMadd => visit_f32x4_relaxed_madd (arity 3 -> 1) + F32x4RelaxedNmadd => visit_f32x4_relaxed_nmadd (arity 3 -> 1) + F64x2RelaxedMadd => visit_f64x2_relaxed_madd (arity 3 -> 1) + F64x2RelaxedNmadd => visit_f64x2_relaxed_nmadd (arity 3 -> 1) + I8x16RelaxedLaneselect => visit_i8x16_relaxed_laneselect (arity 3 -> 1) + I16x8RelaxedLaneselect => visit_i16x8_relaxed_laneselect (arity 3 -> 1) + I32x4RelaxedLaneselect => visit_i32x4_relaxed_laneselect (arity 3 -> 1) + I64x2RelaxedLaneselect => visit_i64x2_relaxed_laneselect (arity 3 -> 1) + F32x4RelaxedMin => visit_f32x4_relaxed_min (arity 2 -> 1) + F32x4RelaxedMax => visit_f32x4_relaxed_max (arity 2 -> 1) + F64x2RelaxedMin => visit_f64x2_relaxed_min (arity 2 -> 1) + F64x2RelaxedMax => visit_f64x2_relaxed_max (arity 2 -> 1) + I16x8RelaxedQ15mulrS => visit_i16x8_relaxed_q15mulr_s (arity 2 -> 1) + I16x8RelaxedDotI8x16I7x16S => visit_i16x8_relaxed_dot_i8x16_i7x16_s (arity 2 -> 1) + I32x4RelaxedDotI8x16I7x16AddS => visit_i32x4_relaxed_dot_i8x16_i7x16_add_s (arity 3 -> 1) } @exceptions { - TryTable { try_table: $crate::TryTable } => visit_try_table (arity try_table -> ~try_table) - Throw { tag_index: u32 } => visit_throw (arity tag -> 0) + TryTable { try_table: $crate::TryTable } => visit_try_table (arity custom) + Throw { tag_index: u32 } => visit_throw (arity custom) ThrowRef => visit_throw_ref (arity 1 -> 0) } // Deprecated old instructions from the exceptions proposal @legacy_exceptions { - Try { blockty: $crate::BlockType } => visit_try (arity block -> ~block) - Catch { tag_index: u32 } => visit_catch (arity ~end -> ~tag) + Try { blockty: $crate::BlockType } => visit_try (arity custom) + Catch { tag_index: u32 } => visit_catch (arity custom) Rethrow { relative_depth: u32 } => visit_rethrow (arity 0 -> 0) - Delegate { relative_depth: u32 } => visit_delegate (arity ~end -> end) - CatchAll => visit_catch_all (arity ~end -> 0) + Delegate { relative_depth: u32 } => visit_delegate (arity custom) + CatchAll => visit_catch_all (arity custom) } // Also 0xFE prefixed operators @@ -716,11 +736,11 @@ macro_rules! _for_each_operator_group { @shared_everything_threads { GlobalAtomicGet { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_get (arity 0 -> 1) GlobalAtomicSet { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_set (arity 1 -> 0) - GlobalAtomicRmwAdd { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_add (unary atomic global) - GlobalAtomicRmwSub { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_sub (unary atomic global) - GlobalAtomicRmwAnd { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_and (unary atomic global) - GlobalAtomicRmwOr { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_or (unary atomic global) - GlobalAtomicRmwXor { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_xor (unary atomic global) + GlobalAtomicRmwAdd { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_add (arity 1 -> 1) + GlobalAtomicRmwSub { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_sub (arity 1 -> 1) + GlobalAtomicRmwAnd { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_and (arity 1 -> 1) + GlobalAtomicRmwOr { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_or (arity 1 -> 1) + GlobalAtomicRmwXor { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_xor (arity 1 -> 1) GlobalAtomicRmwXchg { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_xchg (arity 1 -> 1) GlobalAtomicRmwCmpxchg { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_cmpxchg (arity 2 -> 1) TableAtomicGet { ordering: $crate::Ordering, table_index: u32 } => visit_table_atomic_get (arity 1 -> 1) @@ -731,22 +751,22 @@ macro_rules! _for_each_operator_group { StructAtomicGetS { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_get_s (arity 1 -> 1) StructAtomicGetU { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_get_u (arity 1 -> 1) StructAtomicSet { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_set (arity 2 -> 0) - StructAtomicRmwAdd { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_add (atomic rmw struct add) - StructAtomicRmwSub { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_sub (atomic rmw struct sub) - StructAtomicRmwAnd { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_and (atomic rmw struct and) - StructAtomicRmwOr { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_or (atomic rmw struct or) - StructAtomicRmwXor { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_xor (atomic rmw struct xor) + StructAtomicRmwAdd { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_add (arity 2 -> 1) + StructAtomicRmwSub { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_sub (arity 2 -> 1) + StructAtomicRmwAnd { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_and (arity 2 -> 1) + StructAtomicRmwOr { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_or (arity 2 -> 1) + StructAtomicRmwXor { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_xor (arity 2 -> 1) StructAtomicRmwXchg { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_xchg (arity 2 -> 1) StructAtomicRmwCmpxchg { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_cmpxchg (arity 3 -> 1) ArrayAtomicGet { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_get (arity 2 -> 1) ArrayAtomicGetS { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_get_s (arity 2 -> 1) ArrayAtomicGetU { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_get_u (arity 2 -> 1) ArrayAtomicSet { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_set (arity 3 -> 0) - ArrayAtomicRmwAdd { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_add (atomic rmw array add) - ArrayAtomicRmwSub { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_sub (atomic rmw array sub) - ArrayAtomicRmwAnd { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_and (atomic rmw array and) - ArrayAtomicRmwOr { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_or (atomic rmw array or) - ArrayAtomicRmwXor { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_xor (atomic rmw array xor) + ArrayAtomicRmwAdd { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_add (arity 3 -> 1) + ArrayAtomicRmwSub { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_sub (arity 3 -> 1) + ArrayAtomicRmwAnd { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_and (arity 3 -> 1) + ArrayAtomicRmwOr { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_or (arity 3 -> 1) + ArrayAtomicRmwXor { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_xor (arity 3 -> 1) ArrayAtomicRmwXchg { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_xchg (arity 3 -> 1) ArrayAtomicRmwCmpxchg { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_cmpxchg (arity 4 -> 1) RefI31Shared => visit_ref_i31_shared (arity 1 -> 1) @@ -754,21 +774,21 @@ macro_rules! _for_each_operator_group { // Typed Function references @function_references { - CallRef { type_index: u32 } => visit_call_ref (arity 1 type -> type) - ReturnCallRef { type_index: u32 } => visit_return_call_ref (arity 1 type -> 0) + CallRef { type_index: u32 } => visit_call_ref (arity custom) + ReturnCallRef { type_index: u32 } => visit_return_call_ref (arity custom) RefAsNonNull => visit_ref_as_non_null (arity 1 -> 1) - BrOnNull { relative_depth: u32 } => visit_br_on_null (arity 1 br -> 1 br) - BrOnNonNull { relative_depth: u32 } => visit_br_on_non_null (arity br -> br -1) + BrOnNull { relative_depth: u32 } => visit_br_on_null (arity custom) + BrOnNonNull { relative_depth: u32 } => visit_br_on_non_null (arity custom) } // Stack switching @stack_switching { ContNew { cont_type_index: u32 } => visit_cont_new (arity 1 -> 1) - ContBind { argument_index: u32, result_index: u32 } => visit_cont_bind (arity type_diff 1 -> 1) - Suspend { tag_index: u32 } => visit_suspend (arity tag -> tag) - Resume { cont_type_index: u32, resume_table: $crate::ResumeTable } => visit_resume (arity 1 type -> type) - ResumeThrow { cont_type_index: u32, tag_index: u32, resume_table: $crate::ResumeTable } => visit_resume_throw (arity 1 tag -> type) - Switch { cont_type_index: u32, tag_index: u32 } => visit_switch (arity type -> ~switch) + ContBind { argument_index: u32, result_index: u32 } => visit_cont_bind (arity custom) + Suspend { tag_index: u32 } => visit_suspend (arity custom) + Resume { cont_type_index: u32, resume_table: $crate::ResumeTable } => visit_resume (arity custom) + ResumeThrow { cont_type_index: u32, tag_index: u32, resume_table: $crate::ResumeTable } => visit_resume_throw (arity custom) + Switch { cont_type_index: u32, tag_index: u32 } => visit_switch (arity custom) } @wide_arithmetic { @@ -954,6 +974,7 @@ _for_each_operator_group!(define_for_each_simd_operator); /// - `@gc`: [Wasm `gc` proposal] /// - `@stack_switching`: [Wasm `stack-switching` proposal] /// - `@wide_arithmetic`: [Wasm `wide-arithmetic` proposal] +/// - `@custom_descriptors` : [Wasm `custom-descriptors` proposal] /// /// [Wasm `exception-handling` proposal]: /// https://github.com/WebAssembly/exception-handling @@ -1187,7 +1208,7 @@ pub use _for_each_operator_impl as for_each_operator; /// } /// } /// # // to get this example to compile another macro is used here to define -/// # // visit methods for all mvp oeprators. +/// # // visit methods for all mvp operators. /// # macro_rules! visit_mvp { /// # ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => { /// # $( @@ -1284,6 +1305,15 @@ macro_rules! bail { ($($arg:tt)*) => {return Err(format_err!($($arg)*))} } +#[cfg(all(feature = "component-model", feature = "validate"))] // Only used in component-model code right now. +macro_rules! ensure { + ($cond:expr, $($arg:tt)*) => { + if !$cond { + bail!($($arg)*); + } + } +} + pub use crate::arity::*; pub use crate::binary_reader::{BinaryReader, BinaryReaderError, Result}; pub use crate::features::*; diff --git a/third_party/rust/wasmparser/src/limits.rs b/third_party/rust/wasmparser/src/limits.rs @@ -17,6 +17,8 @@ // The following limits are imposed by wasmparser on WebAssembly modules. // The limits are agreed upon with other engines for consistency. +// +// See https://webassembly.github.io/spec/js-api/#limits for details. pub const MAX_WASM_TYPES: usize = 1_000_000; pub const MAX_WASM_SUPERTYPES: usize = 1; pub const MAX_WASM_FUNCTIONS: usize = 1_000_000; @@ -26,8 +28,8 @@ pub const MAX_WASM_GLOBALS: usize = 1_000_000; pub const MAX_WASM_ELEMENT_SEGMENTS: usize = 100_000; pub const MAX_WASM_DATA_SEGMENTS: usize = 100_000; pub const MAX_WASM_STRING_SIZE: usize = 100_000; -pub const MAX_WASM_FUNCTION_SIZE: usize = 128 * 1024; -pub const MAX_WASM_FUNCTION_LOCALS: usize = 50000; +pub const MAX_WASM_FUNCTION_SIZE: usize = 7_654_321; +pub const MAX_WASM_FUNCTION_LOCALS: u32 = 50000; pub const MAX_WASM_FUNCTION_PARAMS: usize = 1000; pub const MAX_WASM_FUNCTION_RETURNS: usize = 1000; pub const _MAX_WASM_TABLE_SIZE: usize = 10_000_000; @@ -41,13 +43,14 @@ pub const MAX_WASM_CATCHES: usize = 10_000; pub const MAX_WASM_SUBTYPING_DEPTH: usize = 63; pub const MAX_WASM_HANDLERS: usize = 10_000; pub const MAX_WASM_TYPE_SIZE: u32 = 1_000_000; +pub const MAX_WASM_SELECT_RESULT_SIZE: usize = 10; // values other than 1 are currently invalid pub const DEFAULT_WASM_PAGE_SIZE: u64 = 1 << 16; pub fn max_wasm_memory32_pages(page_size: u64) -> u64 { assert!(page_size.is_power_of_two()); assert!(page_size <= DEFAULT_WASM_PAGE_SIZE); - (1 << 32) / page_size + u32::try_from((1_u128 << 32) / u128::from(page_size)).unwrap_or(u32::MAX) as u64 } pub fn max_wasm_memory64_pages(page_size: u64) -> u64 { @@ -64,8 +67,8 @@ pub use self::component_limits::*; mod component_limits { pub const MAX_WASM_MODULE_SIZE: usize = 1024 * 1024 * 1024; //= 1 GiB pub const MAX_WASM_MODULE_TYPE_DECLS: usize = 100_000; - pub const MAX_WASM_COMPONENT_TYPE_DECLS: usize = 100_000; - pub const MAX_WASM_INSTANCE_TYPE_DECLS: usize = 100_000; + pub const MAX_WASM_COMPONENT_TYPE_DECLS: usize = 1_000_000; + pub const MAX_WASM_INSTANCE_TYPE_DECLS: usize = 1_000_000; pub const MAX_WASM_RECORD_FIELDS: usize = 10_000; pub const MAX_WASM_VARIANT_CASES: usize = 10_000; pub const MAX_WASM_TUPLE_TYPES: usize = 10_000; diff --git a/third_party/rust/wasmparser/src/parser.rs b/third_party/rust/wasmparser/src/parser.rs @@ -1,19 +1,19 @@ -use crate::binary_reader::WASM_MAGIC_NUMBER; -use crate::prelude::*; #[cfg(feature = "features")] use crate::WasmFeatures; -#[cfg(feature = "component-model")] -use crate::{ - limits::MAX_WASM_MODULE_SIZE, ComponentCanonicalSectionReader, ComponentExportSectionReader, - ComponentImportSectionReader, ComponentInstanceSectionReader, ComponentStartFunction, - ComponentTypeSectionReader, CoreTypeSectionReader, InstanceSectionReader, SectionLimited, -}; +use crate::binary_reader::WASM_MAGIC_NUMBER; +use crate::prelude::*; use crate::{ BinaryReader, BinaryReaderError, CustomSectionReader, DataSectionReader, ElementSectionReader, ExportSectionReader, FromReader, FunctionBody, FunctionSectionReader, GlobalSectionReader, ImportSectionReader, MemorySectionReader, Result, TableSectionReader, TagSectionReader, TypeSectionReader, }; +#[cfg(feature = "component-model")] +use crate::{ + ComponentCanonicalSectionReader, ComponentExportSectionReader, ComponentImportSectionReader, + ComponentInstanceSectionReader, ComponentStartFunction, ComponentTypeSectionReader, + CoreTypeSectionReader, InstanceSectionReader, SectionLimited, limits::MAX_WASM_MODULE_SIZE, +}; use core::fmt; use core::iter; use core::ops::Range; @@ -42,6 +42,39 @@ pub enum Encoding { Component, } +#[derive(Debug, Clone, Default)] +struct ParserCounts { + function_entries: Option<u32>, + code_entries: Option<u32>, + data_entries: Option<u32>, + data_count: Option<u32>, + #[cfg(feature = "component-model")] + component_start_sections: bool, +} + +// Section order for WebAssembly modules. +// +// Component sections are unordered and allow for duplicates, +// so this isn't used for components. +#[derive(Copy, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug)] +pub(crate) enum Order { + #[default] + Initial, + Type, + Import, + Function, + Table, + Memory, + Tag, + Global, + Export, + Start, + Element, + DataCount, + Code, + Data, +} + /// An incremental parser of a binary WebAssembly module or component. /// /// This type is intended to be used to incrementally parse a WebAssembly module @@ -59,6 +92,8 @@ pub struct Parser { encoding: Encoding, #[cfg(feature = "features")] features: WasmFeatures, + counts: ParserCounts, + order: (Order, u64), } #[derive(Debug, Clone)] @@ -373,6 +408,8 @@ impl Parser { encoding: Encoding::Module, #[cfg(feature = "features")] features: WasmFeatures::all(), + counts: ParserCounts::default(), + order: (Order::default(), offset), } } @@ -627,6 +664,22 @@ impl Parser { } } + fn update_order(&mut self, order: Order, pos: usize) -> Result<()> { + let pos_u64 = usize_to_u64(pos); + if self.encoding == Encoding::Module { + match self.order { + (last_order, last_pos) if last_order >= order && last_pos < pos_u64 => { + bail!(pos, "section out of order") + } + _ => (), + } + } + + self.order = (order, pos_u64); + + Ok(()) + } + fn parse_reader<'a>( &mut self, reader: &mut BinaryReader<'a>, @@ -638,12 +691,12 @@ impl Parser { State::Header => { let start = reader.original_position(); let header_version = reader.read_header_version()?; - self.encoding = match (header_version >> 16) as u16 { - KIND_MODULE => Encoding::Module, - KIND_COMPONENT => Encoding::Component, + let num = header_version as u16; + self.encoding = match (num, (header_version >> 16) as u16) { + (WASM_MODULE_VERSION, KIND_MODULE) => Encoding::Module, + (WASM_COMPONENT_VERSION, KIND_COMPONENT) => Encoding::Component, _ => bail!(start + 4, "unknown binary version: {header_version:#10x}"), }; - let num = header_version as u16; self.state = State::SectionStart; Ok(Version { num, @@ -656,9 +709,27 @@ impl Parser { // that means we reached the end of the data since it's // just a bunch of sections concatenated after the header. if eof && reader.bytes_remaining() == 0 { + self.check_function_code_counts(reader.original_position())?; + self.check_data_count(reader.original_position())?; return Ok(Payload::End(reader.original_position())); } + // Corrupted binaries containing multiple modules or + // components will fail because a section can never start with + // the magic number: 0 is custom section, 'a' is section len + // of 97, `s` is section name string len of 115, at which + // point validation will fail because name string is bigger + // than section. Report a better error instead: + match reader.peek_bytes(4) { + Ok(peek) if peek == WASM_MAGIC_NUMBER => { + return Err(BinaryReaderError::new( + "expected section, got wasm magic number", + reader.original_position(), + )); + } + _ => {} + } + let id_pos = reader.original_position(); let id = reader.read_u8()?; if id & 0x80 != 0 { @@ -683,41 +754,58 @@ impl Parser { } match (self.encoding, id) { - // Sections for both modules and components. + // Custom sections for both modules and components. (_, 0) => section(reader, len, CustomSectionReader::new, CustomSection), // Module sections (Encoding::Module, TYPE_SECTION) => { + self.update_order(Order::Type, reader.original_position())?; section(reader, len, TypeSectionReader::new, TypeSection) } (Encoding::Module, IMPORT_SECTION) => { + self.update_order(Order::Import, reader.original_position())?; section(reader, len, ImportSectionReader::new, ImportSection) } (Encoding::Module, FUNCTION_SECTION) => { - section(reader, len, FunctionSectionReader::new, FunctionSection) + self.update_order(Order::Function, reader.original_position())?; + let s = section(reader, len, FunctionSectionReader::new, FunctionSection)?; + match &s { + FunctionSection(f) => self.counts.function_entries = Some(f.count()), + _ => unreachable!(), + } + Ok(s) } (Encoding::Module, TABLE_SECTION) => { + self.update_order(Order::Table, reader.original_position())?; section(reader, len, TableSectionReader::new, TableSection) } (Encoding::Module, MEMORY_SECTION) => { + self.update_order(Order::Memory, reader.original_position())?; section(reader, len, MemorySectionReader::new, MemorySection) } (Encoding::Module, GLOBAL_SECTION) => { + self.update_order(Order::Global, reader.original_position())?; section(reader, len, GlobalSectionReader::new, GlobalSection) } (Encoding::Module, EXPORT_SECTION) => { + self.update_order(Order::Export, reader.original_position())?; section(reader, len, ExportSectionReader::new, ExportSection) } (Encoding::Module, START_SECTION) => { + self.update_order(Order::Start, reader.original_position())?; let (func, range) = single_item(reader, len, "start")?; Ok(StartSection { func, range }) } (Encoding::Module, ELEMENT_SECTION) => { + self.update_order(Order::Element, reader.original_position())?; section(reader, len, ElementSectionReader::new, ElementSection) } (Encoding::Module, CODE_SECTION) => { + self.update_order(Order::Code, reader.original_position())?; let start = reader.original_position(); let count = delimited(reader, &mut len, |r| r.read_var_u32())?; + self.counts.code_entries = Some(count); + self.check_function_code_counts(start)?; let range = start..reader.original_position() + len as usize; self.state = State::FunctionBody { remaining: count, @@ -730,13 +818,23 @@ impl Parser { }) } (Encoding::Module, DATA_SECTION) => { - section(reader, len, DataSectionReader::new, DataSection) + self.update_order(Order::Data, reader.original_position())?; + let s = section(reader, len, DataSectionReader::new, DataSection)?; + match &s { + DataSection(d) => self.counts.data_entries = Some(d.count()), + _ => unreachable!(), + } + self.check_data_count(reader.original_position())?; + Ok(s) } (Encoding::Module, DATA_COUNT_SECTION) => { + self.update_order(Order::DataCount, reader.original_position())?; let (count, range) = single_item(reader, len, "data count")?; + self.counts.data_count = Some(count); Ok(DataCountSection { count, range }) } (Encoding::Module, TAG_SECTION) => { + self.update_order(Order::Tag, reader.original_position())?; section(reader, len, TagSectionReader::new, TagSection) } @@ -810,6 +908,15 @@ impl Parser { ), #[cfg(feature = "component-model")] (Encoding::Component, COMPONENT_START_SECTION) => { + match self.counts.component_start_sections { + false => self.counts.component_start_sections = true, + true => { + bail!( + reader.original_position(), + "component cannot have more than one start function" + ) + } + } let (start, range) = single_item(reader, len, "component start")?; Ok(ComponentStartSection { start, range }) } @@ -976,7 +1083,7 @@ impl Parser { /// /// # parse(&b"\0asm\x01\0\0\0"[..]).unwrap(); /// ``` - pub fn parse_all(self, mut data: &[u8]) -> impl Iterator<Item = Result<Payload>> { + pub fn parse_all(self, mut data: &[u8]) -> impl Iterator<Item = Result<Payload<'_>>> { let mut stack = Vec::new(); let mut cur = self; let mut done = false; @@ -1082,6 +1189,35 @@ impl Parser { self.max_size -= u64::from(skip); self.state = State::SectionStart; } + + fn check_function_code_counts(&self, pos: usize) -> Result<()> { + match (self.counts.function_entries, self.counts.code_entries) { + (Some(n), Some(m)) if n != m => { + bail!(pos, "function and code section have inconsistent lengths") + } + (Some(n), None) if n > 0 => bail!( + pos, + "function section has non-zero count but code section is absent" + ), + (None, Some(m)) if m > 0 => bail!( + pos, + "function section is absent but code section has non-zero count" + ), + _ => Ok(()), + } + } + + fn check_data_count(&self, pos: usize) -> Result<()> { + match (self.counts.data_count, self.counts.data_entries) { + (Some(n), Some(m)) if n != m => { + bail!(pos, "data count and data section have inconsistent lengths") + } + (Some(n), None) if n > 0 => { + bail!(pos, "data count is non-zero but data section is absent") + } + _ => Ok(()), + } + } } fn usize_to_u64(a: usize) -> u64 { @@ -1594,6 +1730,13 @@ mod tests { ); let mut p = parser_after_header(); assert_matches!( + p.parse(&[3, 2, 1, 0], false), + Ok(Chunk::Parsed { + consumed: 4, + payload: Payload::FunctionSection { .. }, + }), + ); + assert_matches!( p.parse(&[10, 2, 1, 0], false), Ok(Chunk::Parsed { consumed: 3, @@ -1611,7 +1754,7 @@ mod tests { p.parse(&[], true), Ok(Chunk::Parsed { consumed: 0, - payload: Payload::End(12), + payload: Payload::End(16), }), ); @@ -1619,6 +1762,13 @@ mod tests { // the section is too small let mut p = parser_after_header(); assert_matches!( + p.parse(&[3, 2, 1, 0], false), + Ok(Chunk::Parsed { + consumed: 4, + payload: Payload::FunctionSection { .. }, + }), + ); + assert_matches!( p.parse(&[10, 1, 1], false), Ok(Chunk::Parsed { consumed: 3, @@ -1633,6 +1783,13 @@ mod tests { // section with 2 functions but section is cut off let mut p = parser_after_header(); assert_matches!( + p.parse(&[3, 2, 2, 0], false), + Ok(Chunk::Parsed { + consumed: 4, + payload: Payload::FunctionSection { .. }, + }), + ); + assert_matches!( p.parse(&[10, 2, 2], false), Ok(Chunk::Parsed { consumed: 3, @@ -1655,6 +1812,13 @@ mod tests { // trailing data is bad let mut p = parser_after_header(); assert_matches!( + p.parse(&[3, 2, 1, 0], false), + Ok(Chunk::Parsed { + consumed: 4, + payload: Payload::FunctionSection { .. }, + }), + ); + assert_matches!( p.parse(&[10, 3, 1], false), Ok(Chunk::Parsed { consumed: 3, @@ -1685,7 +1849,7 @@ mod tests { consumed: 2, payload: Payload::ModuleSection { parser, .. }, }) => parser, - other => panic!("bad parse {:?}", other), + other => panic!("bad parse {other:?}"), }; // Parse the header of the submodule with the sub-parser. @@ -1736,7 +1900,7 @@ mod tests { consumed: 2, payload: Payload::ModuleSection { parser, .. }, }) => parser, - other => panic!("bad parse {:?}", other), + other => panic!("bad parse {other:?}"), }; // use 8 bytes to parse the header, leaving 2 remaining bytes in our diff --git a/third_party/rust/wasmparser/src/readers/component/aliases.rs b/third_party/rust/wasmparser/src/readers/component/aliases.rs @@ -103,7 +103,7 @@ fn component_outer_alias_kind_from_bytes( x, "component outer alias kind", offset + 1, - )) + )); } }, 0x03 => ComponentOuterAliasKind::Type, @@ -113,7 +113,7 @@ fn component_outer_alias_kind_from_bytes( x, "component outer alias kind", offset, - )) + )); } }) } diff --git a/third_party/rust/wasmparser/src/readers/component/canonicals.rs b/third_party/rust/wasmparser/src/readers/component/canonicals.rs @@ -1,8 +1,6 @@ use crate::limits::MAX_WASM_CANONICAL_OPTIONS; use crate::prelude::*; -use crate::{ - BinaryReader, BinaryReaderError, ComponentValType, FromReader, Result, SectionLimited, -}; +use crate::{BinaryReader, ComponentValType, FromReader, Result, SectionLimited}; /// Represents options for component functions. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -30,6 +28,10 @@ pub enum CanonicalOption { /// The function to use if the async lifting of a function should receive task/stream/future progress events /// using a callback. Callback(u32), + /// The core function type to lower this component function to. + CoreType(u32), + /// Use the GC version of the canonical ABI. + Gc, } /// Represents a canonical function in a WebAssembly component. @@ -61,6 +63,11 @@ pub enum CanonicalFunction { /// The type index of the resource that's being dropped. resource: u32, }, + /// Same as `ResourceDrop`, but implements the `async` ABI. + ResourceDropAsync { + /// The type index of the resource that's being dropped. + resource: u32, + }, /// A function which returns the underlying i32-based representation of the /// specified resource. ResourceRep { @@ -68,48 +75,59 @@ pub enum CanonicalFunction { resource: u32, }, /// A function which spawns a new thread by invoking the shared function. - ThreadSpawn { - /// The index of the function to spawn. + ThreadSpawnRef { + /// The index of the function type to spawn. + func_ty_index: u32, + }, + /// A function which spawns a new thread by invoking the shared function + /// passed as an index into a `funcref` table. + ThreadSpawnIndirect { + /// The index of the function type to spawn. func_ty_index: u32, + /// The index of the table to use for the indirect spawn. + table_index: u32, }, /// A function which returns the number of threads that can be expected to /// execute concurrently - ThreadHwConcurrency, + ThreadAvailableParallelism, /// A function which tells the host to enable or disable backpressure for /// the caller's instance. - TaskBackpressure, + BackpressureSet, + /// A function which tells the host to enable backpressure by incrementing + /// the component's counter by 1. + BackpressureInc, + /// A function which tells the host to disable backpressure by decrementing + /// the component's counter by 1. + BackpressureDec, /// A function which returns a result to the caller of a lifted export /// function. This allows the callee to continue executing after returning /// a result. TaskReturn { /// The result type, if any. result: Option<ComponentValType>, + /// The canonical options for the function. + options: Box<[CanonicalOption]>, }, - /// A function which waits for at least one outstanding async - /// task/stream/future to make progress, returning the first such event. - TaskWait { - /// If `true`, indicates the caller instance maybe reentered. - async_: bool, - /// Memory to use when storing the event. - memory: u32, - }, - /// A function which checks whether any outstanding async task/stream/future - /// has made progress. Unlike `task.wait`, this does not block and may - /// return nothing if no such event has occurred. - TaskPoll { - /// If `true`, indicates the caller instance maybe reentered. - async_: bool, - /// Memory to use when storing the event, if any. - memory: u32, - }, + /// A function to acknowledge cancellation of the current task. + TaskCancel, + /// A `context.get` intrinsic for the `i`th slot of task-local storage. + ContextGet(u32), + /// A `context.set` intrinsic for the `i`th slot of task-local storage. + ContextSet(u32), /// A function which yields control to the host so that other tasks are able /// to make progress, if any. - TaskYield { + ThreadYield { /// If `true`, indicates the caller instance maybe reentered. - async_: bool, + cancellable: bool, }, /// A function to drop a specified task which has completed. SubtaskDrop, + /// A function to cancel an in-progress task. + SubtaskCancel { + /// If `false`, block until cancellation completes rather than return + /// `BLOCKED`. + async_: bool, + }, /// A function to create a new `stream` handle of the specified type. StreamNew { /// The `stream` type to instantiate. @@ -149,15 +167,15 @@ pub enum CanonicalFunction { /// `BLOCKED`. async_: bool, }, - /// A function to close the readable end of a `stream` of the specified + /// A function to drop the readable end of a `stream` of the specified /// type. - StreamCloseReadable { + StreamDropReadable { /// The `stream` type to expect. ty: u32, }, - /// A function to close the writable end of a `stream` of the specified + /// A function to drop the writable end of a `stream` of the specified /// type. - StreamCloseWritable { + StreamDropWritable { /// The `stream` type to expect. ty: u32, }, @@ -200,15 +218,15 @@ pub enum CanonicalFunction { /// `BLOCKED`. async_: bool, }, - /// A function to close the readable end of a `future` of the specified + /// A function to drop the readable end of a `future` of the specified /// type. - FutureCloseReadable { + FutureDropReadable { /// The `future` type to expect. ty: u32, }, - /// A function to close the writable end of a `future` of the specified + /// A function to drop the writable end of a `future` of the specified /// type. - FutureCloseWritable { + FutureDropWritable { /// The `future` type to expect. ty: u32, }, @@ -228,6 +246,54 @@ pub enum CanonicalFunction { }, /// A function to drop a specified `error-context`. ErrorContextDrop, + /// A function to create a new `waitable-set`. + WaitableSetNew, + /// A function to block on the next item within a `waitable-set`. + WaitableSetWait { + /// Whether or not the guest can be reentered while calling this + /// function. + cancellable: bool, + /// Which memory the results of this operation are stored in. + memory: u32, + }, + /// A function to check if any items are ready within a `waitable-set`. + WaitableSetPoll { + /// Whether or not the guest can be reentered while calling this + /// function. + cancellable: bool, + /// Which memory the results of this operation are stored in. + memory: u32, + }, + /// A function to drop a `waitable-set`. + WaitableSetDrop, + /// A function to add an item to a `waitable-set`. + WaitableJoin, + /// A function to get the index of the current thread. + ThreadIndex, + /// A function to create a new thread with the specified start function. + ThreadNewIndirect { + /// The index of the function type to use as the start function. + func_ty_index: u32, + /// The index of the table to use. + table_index: u32, + }, + /// A function to suspend the current thread and switch to the given thread. + ThreadSwitchTo { + /// Whether or not the thread can be cancelled while awaiting resumption. + cancellable: bool, + }, + /// A function to suspend the current thread, immediately yielding to any transitive async-lowered calling component. + ThreadSuspend { + /// Whether or not the thread can be cancelled while suspended. + cancellable: bool, + }, + /// A function to schedule the given thread to be resumed later. + ThreadResumeLater, + /// A function to suspend the current thread and switch to the given thread. + ThreadYieldTo { + /// Whether or not the thread can be cancelled while yielding. + cancellable: bool, + }, } /// A reader for the canonical section of a WebAssembly component. @@ -237,26 +303,17 @@ impl<'a> FromReader<'a> for CanonicalFunction { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<CanonicalFunction> { Ok(match reader.read_u8()? { 0x00 => match reader.read_u8()? { - 0x00 => { - let core_func_index = reader.read_var_u32()?; - let options = reader - .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? - .collect::<Result<_>>()?; - let type_index = reader.read_var_u32()?; - CanonicalFunction::Lift { - core_func_index, - options, - type_index, - } - } + 0x00 => CanonicalFunction::Lift { + core_func_index: reader.read_var_u32()?, + options: read_opts(reader)?, + type_index: reader.read_var_u32()?, + }, x => return reader.invalid_leading_byte(x, "canonical function lift"), }, 0x01 => match reader.read_u8()? { 0x00 => CanonicalFunction::Lower { func_index: reader.read_var_u32()?, - options: reader - .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? - .collect::<Result<_>>()?, + options: read_opts(reader)?, }, x => return reader.invalid_leading_byte(x, "canonical function lower"), }, @@ -266,54 +323,39 @@ impl<'a> FromReader<'a> for CanonicalFunction { 0x03 => CanonicalFunction::ResourceDrop { resource: reader.read()?, }, - 0x04 => CanonicalFunction::ResourceRep { + 0x07 => CanonicalFunction::ResourceDropAsync { resource: reader.read()?, }, - 0x05 => CanonicalFunction::ThreadSpawn { - func_ty_index: reader.read()?, + 0x04 => CanonicalFunction::ResourceRep { + resource: reader.read()?, }, - 0x06 => CanonicalFunction::ThreadHwConcurrency, - 0x08 => CanonicalFunction::TaskBackpressure, + 0x08 => CanonicalFunction::BackpressureSet, + 0x24 => CanonicalFunction::BackpressureInc, + 0x25 => CanonicalFunction::BackpressureDec, 0x09 => CanonicalFunction::TaskReturn { - result: match reader.read_u8()? { - 0x00 => Some(reader.read()?), - 0x01 => { - if reader.read_u8()? == 0 { - None - } else { - return Err(BinaryReaderError::new( - "named results not allowed for `task.return` intrinsic", - reader.original_position() - 2, - )); - } - } - x => return reader.invalid_leading_byte(x, "`task.return` result"), - }, + result: crate::read_resultlist(reader)?, + options: read_opts(reader)?, }, - 0x0a => CanonicalFunction::TaskWait { - async_: reader.read()?, - memory: reader.read()?, + 0x0a => match reader.read_u8()? { + 0x7f => CanonicalFunction::ContextGet(reader.read_var_u32()?), + x => return reader.invalid_leading_byte(x, "context.get intrinsic type"), }, - 0x0b => CanonicalFunction::TaskPoll { - async_: reader.read()?, - memory: reader.read()?, + 0x0b => match reader.read_u8()? { + 0x7f => CanonicalFunction::ContextSet(reader.read_var_u32()?), + x => return reader.invalid_leading_byte(x, "context.set intrinsic type"), }, - 0x0c => CanonicalFunction::TaskYield { - async_: reader.read()?, + 0x0c => CanonicalFunction::ThreadYield { + cancellable: reader.read()?, }, 0x0d => CanonicalFunction::SubtaskDrop, 0x0e => CanonicalFunction::StreamNew { ty: reader.read()? }, 0x0f => CanonicalFunction::StreamRead { ty: reader.read()?, - options: reader - .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? - .collect::<Result<_>>()?, + options: read_opts(reader)?, }, 0x10 => CanonicalFunction::StreamWrite { ty: reader.read()?, - options: reader - .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? - .collect::<Result<_>>()?, + options: read_opts(reader)?, }, 0x11 => CanonicalFunction::StreamCancelRead { ty: reader.read()?, @@ -323,20 +365,16 @@ impl<'a> FromReader<'a> for CanonicalFunction { ty: reader.read()?, async_: reader.read()?, }, - 0x13 => CanonicalFunction::StreamCloseReadable { ty: reader.read()? }, - 0x14 => CanonicalFunction::StreamCloseWritable { ty: reader.read()? }, + 0x13 => CanonicalFunction::StreamDropReadable { ty: reader.read()? }, + 0x14 => CanonicalFunction::StreamDropWritable { ty: reader.read()? }, 0x15 => CanonicalFunction::FutureNew { ty: reader.read()? }, 0x16 => CanonicalFunction::FutureRead { ty: reader.read()?, - options: reader - .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? - .collect::<Result<_>>()?, + options: read_opts(reader)?, }, 0x17 => CanonicalFunction::FutureWrite { ty: reader.read()?, - options: reader - .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? - .collect::<Result<_>>()?, + options: read_opts(reader)?, }, 0x18 => CanonicalFunction::FutureCancelRead { ty: reader.read()?, @@ -346,24 +384,65 @@ impl<'a> FromReader<'a> for CanonicalFunction { ty: reader.read()?, async_: reader.read()?, }, - 0x1a => CanonicalFunction::FutureCloseReadable { ty: reader.read()? }, - 0x1b => CanonicalFunction::FutureCloseWritable { ty: reader.read()? }, + 0x1a => CanonicalFunction::FutureDropReadable { ty: reader.read()? }, + 0x1b => CanonicalFunction::FutureDropWritable { ty: reader.read()? }, 0x1c => CanonicalFunction::ErrorContextNew { - options: reader - .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? - .collect::<Result<_>>()?, + options: read_opts(reader)?, }, 0x1d => CanonicalFunction::ErrorContextDebugMessage { - options: reader - .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? - .collect::<Result<_>>()?, + options: read_opts(reader)?, }, 0x1e => CanonicalFunction::ErrorContextDrop, + + 0x1f => CanonicalFunction::WaitableSetNew, + 0x20 => CanonicalFunction::WaitableSetWait { + cancellable: reader.read()?, + memory: reader.read()?, + }, + 0x21 => CanonicalFunction::WaitableSetPoll { + cancellable: reader.read()?, + memory: reader.read()?, + }, + 0x22 => CanonicalFunction::WaitableSetDrop, + 0x23 => CanonicalFunction::WaitableJoin, + 0x26 => CanonicalFunction::ThreadIndex, + 0x27 => CanonicalFunction::ThreadNewIndirect { + func_ty_index: reader.read()?, + table_index: reader.read()?, + }, + 0x28 => CanonicalFunction::ThreadSwitchTo { + cancellable: reader.read()?, + }, + 0x29 => CanonicalFunction::ThreadSuspend { + cancellable: reader.read()?, + }, + 0x2a => CanonicalFunction::ThreadResumeLater, + 0x2b => CanonicalFunction::ThreadYieldTo { + cancellable: reader.read()?, + }, + 0x06 => CanonicalFunction::SubtaskCancel { + async_: reader.read()?, + }, + 0x05 => CanonicalFunction::TaskCancel, + 0x40 => CanonicalFunction::ThreadSpawnRef { + func_ty_index: reader.read()?, + }, + 0x41 => CanonicalFunction::ThreadSpawnIndirect { + func_ty_index: reader.read()?, + table_index: reader.read()?, + }, + 0x42 => CanonicalFunction::ThreadAvailableParallelism, x => return reader.invalid_leading_byte(x, "canonical function"), }) } } +fn read_opts(reader: &mut BinaryReader<'_>) -> Result<Box<[CanonicalOption]>> { + reader + .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? + .collect::<Result<_>>() +} + impl<'a> FromReader<'a> for CanonicalOption { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { Ok(match reader.read_u8()? { @@ -375,6 +454,8 @@ impl<'a> FromReader<'a> for CanonicalOption { 0x05 => CanonicalOption::PostReturn(reader.read_var_u32()?), 0x06 => CanonicalOption::Async, 0x07 => CanonicalOption::Callback(reader.read_var_u32()?), + 0x08 => CanonicalOption::CoreType(reader.read_var_u32()?), + 0x09 => CanonicalOption::Gc, x => return reader.invalid_leading_byte(x, "canonical option"), }) } diff --git a/third_party/rust/wasmparser/src/readers/component/exports.rs b/third_party/rust/wasmparser/src/readers/component/exports.rs @@ -31,7 +31,7 @@ impl ComponentExternalKind { x, "component external kind", offset + 1, - )) + )); } }, 0x01 => ComponentExternalKind::Func, @@ -44,7 +44,7 @@ impl ComponentExternalKind { x, "component external kind", offset, - )) + )); } }) } @@ -93,7 +93,7 @@ impl<'a> FromReader<'a> for ComponentExport<'a> { other, "optional component export type", reader.original_position() - 1, - )) + )); } }, }) diff --git a/third_party/rust/wasmparser/src/readers/component/imports.rs b/third_party/rust/wasmparser/src/readers/component/imports.rs @@ -66,7 +66,7 @@ impl<'a> FromReader<'a> for ComponentTypeRef { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { Ok(match reader.read()? { ComponentExternalKind::Module => ComponentTypeRef::Module(reader.read()?), - ComponentExternalKind::Func => ComponentTypeRef::Func(reader.read()?), + ComponentExternalKind::Func => ComponentTypeRef::Func(reader.read_var_u32()?), ComponentExternalKind::Value => ComponentTypeRef::Value(reader.read()?), ComponentExternalKind::Type => ComponentTypeRef::Type(reader.read()?), ComponentExternalKind::Instance => ComponentTypeRef::Instance(reader.read()?), diff --git a/third_party/rust/wasmparser/src/readers/component/names.rs b/third_party/rust/wasmparser/src/readers/component/names.rs @@ -2,7 +2,7 @@ use crate::{BinaryReader, BinaryReaderError, NameMap, Result, Subsection, Subsec use core::ops::Range; /// Type used to iterate and parse the contents of the `component-name` custom -/// section in compnents, similar to the `name` section of core modules. +/// section in components, similar to the `name` section of core modules. pub type ComponentNameSectionReader<'a> = Subsections<'a, ComponentName<'a>>; /// Represents a name read from the names custom section. @@ -17,6 +17,7 @@ pub enum ComponentName<'a> { CoreGlobals(NameMap<'a>), CoreMemories(NameMap<'a>), CoreTables(NameMap<'a>), + CoreTags(NameMap<'a>), CoreModules(NameMap<'a>), CoreInstances(NameMap<'a>), CoreTypes(NameMap<'a>), @@ -44,7 +45,7 @@ impl<'a> Subsection<'a> for ComponentName<'a> { let offset = reader.original_position(); Ok(match id { 0 => { - let name = reader.read_string()?; + let name = reader.read_unlimited_string()?; if !reader.eof() { return Err(BinaryReaderError::new( "trailing data at the end of a name", @@ -63,6 +64,7 @@ impl<'a> Subsection<'a> for ComponentName<'a> { 0x01 => ComponentName::CoreTables, 0x02 => ComponentName::CoreMemories, 0x03 => ComponentName::CoreGlobals, + 0x04 => ComponentName::CoreTags, 0x10 => ComponentName::CoreTypes, 0x11 => ComponentName::CoreModules, 0x12 => ComponentName::CoreInstances, diff --git a/third_party/rust/wasmparser/src/readers/component/types.rs b/third_party/rust/wasmparser/src/readers/component/types.rs @@ -1,9 +1,8 @@ use crate::limits::*; use crate::prelude::*; -use crate::RecGroup; use crate::{ BinaryReader, ComponentAlias, ComponentExportName, ComponentImport, ComponentTypeRef, - FromReader, Import, Result, SectionLimited, TypeRef, ValType, + FromReader, Import, RecGroup, Result, SectionLimited, TypeRef, ValType, }; use core::fmt; @@ -185,6 +184,9 @@ pub enum PrimitiveValType { Char, /// The type is a string. String, + /// The error-context type. (added with the async proposal for the component + /// model) + ErrorContext, } impl PrimitiveValType { @@ -203,6 +205,7 @@ impl PrimitiveValType { 0x75 => PrimitiveValType::F64, 0x74 => PrimitiveValType::Char, 0x73 => PrimitiveValType::String, + 0x64 => PrimitiveValType::ErrorContext, _ => return None, }) } @@ -241,6 +244,7 @@ impl fmt::Display for PrimitiveValType { F64 => "f64", Char => "char", String => "string", + ErrorContext => "error-context", }; s.fmt(f) } @@ -278,12 +282,16 @@ impl<'a> FromReader<'a> for ComponentType<'a> { b => return reader.invalid_leading_byte(b, "resource destructor"), }, }, - 0x40 => { + byte @ (0x40 | 0x43) => { let params = reader .read_iter(MAX_WASM_FUNCTION_PARAMS, "component function parameters")? .collect::<Result<_>>()?; - let results = reader.read()?; - ComponentType::Func(ComponentFuncType { params, results }) + let result = read_resultlist(reader)?; + ComponentType::Func(ComponentFuncType { + async_: byte == 0x43, + params, + result, + }) } 0x41 => ComponentType::Component( reader @@ -380,74 +388,26 @@ impl<'a> FromReader<'a> for InstanceTypeDeclaration<'a> { } } -/// Represents the result type of a component function. -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum ComponentFuncResult<'a> { - /// The function returns a singular, unnamed type. - Unnamed(ComponentValType), - /// The function returns zero or more named types. - Named(Box<[(&'a str, ComponentValType)]>), -} - -impl<'a> FromReader<'a> for ComponentFuncResult<'a> { - fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { - Ok(match reader.read_u8()? { - 0x00 => ComponentFuncResult::Unnamed(reader.read()?), - 0x01 => ComponentFuncResult::Named( - reader - .read_iter(MAX_WASM_FUNCTION_RETURNS, "component function results")? - .collect::<Result<_>>()?, - ), - x => return reader.invalid_leading_byte(x, "component function results"), - }) - } -} - -impl ComponentFuncResult<'_> { - /// Gets the count of types returned by the function. - pub fn type_count(&self) -> usize { - match self { - Self::Unnamed(_) => 1, - Self::Named(vec) => vec.len(), - } - } - - /// Iterates over the types returned by the function. - pub fn iter(&self) -> impl Iterator<Item = (Option<&str>, &ComponentValType)> { - enum Either<L, R> { - Left(L), - Right(R), - } - - impl<L, R> Iterator for Either<L, R> - where - L: Iterator, - R: Iterator<Item = L::Item>, - { - type Item = L::Item; - - fn next(&mut self) -> Option<Self::Item> { - match self { - Either::Left(l) => l.next(), - Either::Right(r) => r.next(), - } - } - } - - match self { - Self::Unnamed(ty) => Either::Left(core::iter::once(ty).map(|ty| (None, ty))), - Self::Named(vec) => Either::Right(vec.iter().map(|(n, ty)| (Some(*n), ty))), - } - } -} - /// Represents a type of a function in a WebAssembly component. #[derive(Debug, Clone, Eq, PartialEq)] pub struct ComponentFuncType<'a> { + /// Whether or not this is an async function. + pub async_: bool, /// The function parameters. pub params: Box<[(&'a str, ComponentValType)]>, /// The function result. - pub results: ComponentFuncResult<'a>, + pub result: Option<ComponentValType>, +} + +pub(crate) fn read_resultlist(reader: &mut BinaryReader<'_>) -> Result<Option<ComponentValType>> { + match reader.read_u8()? { + 0x00 => Ok(Some(reader.read()?)), + 0x01 => match reader.read_u8()? { + 0x00 => Ok(None), + x => return reader.invalid_leading_byte(x, "number of results"), + }, + x => return reader.invalid_leading_byte(x, "component function results"), + } } /// Represents a case in a variant type. @@ -486,6 +446,8 @@ pub enum ComponentDefinedType<'a> { Variant(Box<[VariantCase<'a>]>), /// The type is a list of the given value type. List(ComponentValType), + /// The type is a fixed size list of the given value type. + FixedSizeList(ComponentValType, u32), /// The type is a tuple of the given value types. Tuple(Box<[ComponentValType]>), /// The type is flags with the given names. @@ -509,8 +471,6 @@ pub enum ComponentDefinedType<'a> { Future(Option<ComponentValType>), /// A stream type with the specified payload type. Stream(Option<ComponentValType>), - /// The error-context type. - ErrorContext, } impl<'a> ComponentDefinedType<'a> { @@ -550,9 +510,9 @@ impl<'a> ComponentDefinedType<'a> { }, 0x69 => ComponentDefinedType::Own(reader.read()?), 0x68 => ComponentDefinedType::Borrow(reader.read()?), - 0x67 => ComponentDefinedType::Future(reader.read()?), + 0x67 => ComponentDefinedType::FixedSizeList(reader.read()?, reader.read_var_u32()?), 0x66 => ComponentDefinedType::Stream(reader.read()?), - 0x65 => ComponentDefinedType::ErrorContext, + 0x65 => ComponentDefinedType::Future(reader.read()?), x => return reader.invalid_leading_byte(x, "component defined type"), }) } diff --git a/third_party/rust/wasmparser/src/readers/core/code.rs b/third_party/rust/wasmparser/src/readers/core/code.rs @@ -48,15 +48,27 @@ impl<'a> FunctionBody<'a> { /// Gets the locals reader for this function body. pub fn get_locals_reader(&self) -> Result<LocalsReader<'a>> { let mut reader = self.reader.clone(); - let count = reader.read_var_u32()?; - Ok(LocalsReader { reader, count }) + let declaration_count = reader.read_var_u32()?; + Ok(LocalsReader { + reader, + declaration_count, + total_count: 0, + }) } - /// Gets the operators reader for this function body. - pub fn get_operators_reader(&self) -> Result<OperatorsReader<'a>> { + /// Gets a binary reader for this function body, after skipping locals. + pub fn get_binary_reader_for_operators(&self) -> Result<BinaryReader<'a>> { let mut reader = self.reader.clone(); Self::skip_locals(&mut reader)?; - Ok(OperatorsReader::new(reader)) + Ok(reader) + } + + /// Uses [`FunctionBody::get_binary_reader_for_operators`] and then converts + /// that to an [`OperatorsReader`]. + pub fn get_operators_reader(&self) -> Result<OperatorsReader<'a>> { + Ok(OperatorsReader::new( + self.get_binary_reader_for_operators()?, + )) } /// Gets the range of the function body. @@ -75,20 +87,21 @@ impl<'a> FunctionBody<'a> { impl<'a> FromReader<'a> for FunctionBody<'a> { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { let reader = reader.read_reader()?; - Ok(FunctionBody { reader }) + Ok(FunctionBody::new(reader)) } } /// A reader for a function body's locals. pub struct LocalsReader<'a> { reader: BinaryReader<'a>, - count: u32, + declaration_count: u32, + total_count: u32, } impl<'a> LocalsReader<'a> { - /// Gets the count of locals in the function body. + /// Gets the count of locals declarations in the function body. pub fn get_count(&self) -> u32 { - self.count + self.declaration_count } /// Gets the original position of the reader. @@ -99,16 +112,25 @@ impl<'a> LocalsReader<'a> { /// Reads an item from the reader. pub fn read(&mut self) -> Result<(u32, ValType)> { let count = self.reader.read()?; + match self.total_count.checked_add(count) { + Some(total) => self.total_count = total, + None => bail!(self.reader.original_position(), "too many locals"), + } let value_type = self.reader.read()?; Ok((count, value_type)) } + + /// Gets the binary reader from this LocalsReader + pub fn get_binary_reader(self) -> BinaryReader<'a> { + self.reader + } } impl<'a> IntoIterator for LocalsReader<'a> { type Item = Result<(u32, ValType)>; type IntoIter = LocalsIterator<'a>; fn into_iter(self) -> Self::IntoIter { - let count = self.count; + let count = self.declaration_count; LocalsIterator { reader: self, left: count, @@ -140,3 +162,16 @@ impl<'a> Iterator for LocalsIterator<'a> { (count, Some(count)) } } + +impl<'a> LocalsIterator<'a> { + /// After reading the locals, the BinaryReader is ready to read the operators. + pub fn into_binary_reader_for_operators(self) -> BinaryReader<'a> { + debug_assert!(self.err || self.left == 0); + self.reader.get_binary_reader() + } + + /// After reading the locals, the BinaryReader is ready to read the operators. + pub fn into_operators_reader(self) -> OperatorsReader<'a> { + OperatorsReader::new(self.reader.get_binary_reader()) + } +} diff --git a/third_party/rust/wasmparser/src/readers/core/coredumps.rs b/third_party/rust/wasmparser/src/readers/core/coredumps.rs @@ -1,5 +1,5 @@ -use crate::prelude::*; use crate::{BinaryReader, FromReader, Result}; +use crate::{Ieee32, Ieee64, prelude::*}; /// The data portion of a custom section representing a core dump. Per the /// tool-conventions repo, this section just specifies the executable name that @@ -29,7 +29,7 @@ impl<'a> CoreDumpSection<'a> { if reader.read_u8()? != 0 { bail!(pos, "invalid start byte for core dump name"); } - let name = reader.read_string()?; + let name = reader.read_unlimited_string()?; if !reader.eof() { bail!( reader.original_position(), @@ -69,7 +69,7 @@ impl<'a> CoreDumpModulesSection<'a> { if reader.read_u8()? != 0 { bail!(pos, "invalid start byte for coremodule"); } - modules.push(reader.read_string()?); + modules.push(reader.read_unlimited_string()?); } if !reader.eof() { bail!( @@ -181,7 +181,7 @@ impl<'a> CoreDumpStackSection<'a> { if reader.read_u8()? != 0 { bail!(pos, "invalid start byte for core dump stack name"); } - let name = reader.read_string()?; + let name = reader.read_unlimited_string()?; let mut frames = vec![]; for _ in 0..reader.read_var_u32()? { frames.push(CoreDumpStackFrame::from_reader(&mut reader)?); @@ -254,9 +254,9 @@ pub enum CoreDumpValue { /// An i64 value I64(i64), /// An f32 value - F32(f32), + F32(Ieee32), /// An f64 value - F64(f64), + F64(Ieee64), } impl<'a> FromReader<'a> for CoreDumpValue { @@ -266,12 +266,8 @@ impl<'a> FromReader<'a> for CoreDumpValue { 0x01 => Ok(CoreDumpValue::Missing), 0x7F => Ok(CoreDumpValue::I32(reader.read_var_i32()?)), 0x7E => Ok(CoreDumpValue::I64(reader.read_var_i64()?)), - 0x7D => Ok(CoreDumpValue::F32(f32::from_bits( - reader.read_f32()?.bits(), - ))), - 0x7C => Ok(CoreDumpValue::F64(f64::from_bits( - reader.read_f64()?.bits(), - ))), + 0x7D => Ok(CoreDumpValue::F32(reader.read_f32()?)), + 0x7C => Ok(CoreDumpValue::F64(reader.read_f64()?)), _ => bail!(pos, "invalid CoreDumpValue type"), } } diff --git a/third_party/rust/wasmparser/src/readers/core/dylink0.rs b/third_party/rust/wasmparser/src/readers/core/dylink0.rs @@ -12,6 +12,7 @@ const WASM_DYLINK_MEM_INFO: u8 = 1; const WASM_DYLINK_NEEDED: u8 = 2; const WASM_DYLINK_EXPORT_INFO: u8 = 3; const WASM_DYLINK_IMPORT_INFO: u8 = 4; +const WASM_DYLINK_RUNTIME_PATH: u8 = 5; /// Represents a `WASM_DYLINK_MEM_INFO` field #[derive(Debug, Copy, Clone)] @@ -56,6 +57,7 @@ pub enum Dylink0Subsection<'a> { Needed(Vec<&'a str>), ExportInfo(Vec<ExportInfo<'a>>), ImportInfo(Vec<ImportInfo<'a>>), + RuntimePath(Vec<&'a str>), Unknown { ty: u8, data: &'a [u8], @@ -76,14 +78,14 @@ impl<'a> Subsection<'a> for Dylink0Subsection<'a> { }), WASM_DYLINK_NEEDED => Self::Needed( (0..reader.read_var_u32()?) - .map(|_| reader.read_string()) + .map(|_| reader.read_unlimited_string()) .collect::<Result<_, _>>()?, ), WASM_DYLINK_EXPORT_INFO => Self::ExportInfo( (0..reader.read_var_u32()?) .map(|_| { Ok(ExportInfo { - name: reader.read_string()?, + name: reader.read_unlimited_string()?, flags: reader.read()?, }) }) @@ -93,13 +95,18 @@ impl<'a> Subsection<'a> for Dylink0Subsection<'a> { (0..reader.read_var_u32()?) .map(|_| { Ok(ImportInfo { - module: reader.read_string()?, - field: reader.read_string()?, + module: reader.read_unlimited_string()?, + field: reader.read_unlimited_string()?, flags: reader.read()?, }) }) .collect::<Result<_, _>>()?, ), + WASM_DYLINK_RUNTIME_PATH => Self::RuntimePath( + (0..reader.read_var_u32()?) + .map(|_| reader.read_unlimited_string()) + .collect::<Result<_, _>>()?, + ), ty => Self::Unknown { ty, data, diff --git a/third_party/rust/wasmparser/src/readers/core/elements.rs b/third_party/rust/wasmparser/src/readers/core/elements.rs @@ -14,8 +14,8 @@ */ use crate::{ - BinaryReader, BinaryReaderError, ConstExpr, ExternalKind, FromReader, RefType, Result, - SectionLimited, + BinaryReader, BinaryReaderError, ConstExpr, ExternalKind, FromReader, OperatorsReader, + OperatorsReaderAllocations, RefType, Result, SectionLimited, }; use core::ops::Range; @@ -120,9 +120,16 @@ impl<'a> FromReader<'a> for Element<'a> { // FIXME(#188) ideally wouldn't have to do skips here let data = reader.skip(|reader| { let items_count = reader.read_var_u32()?; + let mut allocs = OperatorsReaderAllocations::default(); if exprs { for _ in 0..items_count { - reader.skip_const_expr()?; + let mut ops = OperatorsReader::new_with_allocs( + reader.clone(), + core::mem::take(&mut allocs), + ); + ops.skip_const_expr()?; + *reader = ops.get_binary_reader(); + allocs = ops.into_allocations(); } } else { for _ in 0..items_count { diff --git a/third_party/rust/wasmparser/src/readers/core/exports.rs b/third_party/rust/wasmparser/src/readers/core/exports.rs @@ -33,6 +33,8 @@ pub enum ExternalKind { Global, /// The external kind is a tag. Tag, + /// The external kind is a function with the exact type. + FuncExact, } /// Represents an export in a WebAssembly module. @@ -50,7 +52,15 @@ impl<'a> FromReader<'a> for Export<'a> { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { Ok(Export { name: reader.read_string()?, - kind: reader.read()?, + kind: match reader.read()? { + ExternalKind::FuncExact => { + bail!( + reader.original_position(), + "Exact type is not allowed in the exports", + ); + } + x => x, + }, index: reader.read_var_u32()?, }) } diff --git a/third_party/rust/wasmparser/src/readers/core/globals.rs b/third_party/rust/wasmparser/src/readers/core/globals.rs @@ -39,18 +39,8 @@ impl<'a> FromReader<'a> for GlobalType { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { let content_type = reader.read()?; let flags = reader.read_u8()?; - if reader.shared_everything_threads() { - if flags > 0b11 { - bail!(reader.original_position() - 1, "malformed global flags") - } - } else { - if flags > 0b1 { - bail!( - reader.original_position() - 1, - "malformed mutability -- or shared globals \ - require the shared-everything-threads proposal" - ) - } + if flags > 0b11 { + bail!(reader.original_position() - 1, "malformed global flags") } Ok(GlobalType { content_type, diff --git a/third_party/rust/wasmparser/src/readers/core/imports.rs b/third_party/rust/wasmparser/src/readers/core/imports.rs @@ -22,8 +22,6 @@ use crate::{ #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum TypeRef { /// The type is a function. - /// - /// The value is an index into the type section. Func(u32), /// The type is a table. Table(TableType), @@ -37,6 +35,8 @@ pub enum TypeRef { /// /// The value is an index in the types index space. Tag(TagType), + /// The type is a function. + FuncExact(u32), } /// Represents an import in a WebAssembly module. @@ -67,6 +67,7 @@ impl<'a> FromReader<'a> for TypeRef { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { Ok(match reader.read()? { ExternalKind::Func => TypeRef::Func(reader.read_var_u32()?), + ExternalKind::FuncExact => TypeRef::FuncExact(reader.read_var_u32()?), ExternalKind::Table => TypeRef::Table(reader.read()?), ExternalKind::Memory => TypeRef::Memory(reader.read()?), ExternalKind::Global => TypeRef::Global(reader.read()?), diff --git a/third_party/rust/wasmparser/src/readers/core/init.rs b/third_party/rust/wasmparser/src/readers/core/init.rs @@ -41,7 +41,7 @@ impl<'a> ConstExpr<'a> { self.reader.clone() } - /// Gets an operators reader for the initialization expression. + /// Gets an operators parser for the initialization expression. pub fn get_operators_reader(&self) -> OperatorsReader<'a> { OperatorsReader::new(self.get_binary_reader()) } @@ -50,7 +50,12 @@ impl<'a> ConstExpr<'a> { impl<'a> FromReader<'a> for ConstExpr<'a> { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { // FIXME(#188) ideally shouldn't need to skip here - let reader = reader.skip(|r| r.skip_const_expr())?; + let reader = reader.skip(|reader| { + let mut ops = OperatorsReader::new(reader.clone()); + ops.skip_const_expr()?; + *reader = ops.get_binary_reader(); + Ok(()) + })?; Ok(ConstExpr { reader }) } } diff --git a/third_party/rust/wasmparser/src/readers/core/linking.rs b/third_party/rust/wasmparser/src/readers/core/linking.rs @@ -93,7 +93,7 @@ pub struct Segment<'a> { impl<'a> FromReader<'a> for Segment<'a> { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { - let name = reader.read_string()?; + let name = reader.read_unlimited_string()?; let alignment = reader.read_var_u32()?; let flags = reader.read()?; Ok(Self { @@ -143,7 +143,7 @@ pub struct Comdat<'a> { impl<'a> FromReader<'a> for Comdat<'a> { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { - let name = reader.read_string()?; + let name = reader.read_unlimited_string()?; let flags = reader.read_var_u32()?; // FIXME(#188) ideally shouldn't need to skip here let symbols = reader.skip(|reader| { @@ -299,7 +299,7 @@ impl<'a> FromReader<'a> for SymbolInfo<'a> { SYMTAB_FUNCTION | SYMTAB_GLOBAL | SYMTAB_EVENT | SYMTAB_TABLE => { let index = reader.read_var_u32()?; let name = match defined || explicit_name { - true => Some(reader.read_string()?), + true => Some(reader.read_unlimited_string()?), false => None, }; Ok(match kind { @@ -311,7 +311,7 @@ impl<'a> FromReader<'a> for SymbolInfo<'a> { }) } SYMTAB_DATA => { - let name = reader.read_string()?; + let name = reader.read_unlimited_string()?; let data = match defined { true => Some(reader.read()?), false => None, @@ -410,7 +410,7 @@ impl<'a> LinkingSectionReader<'a> { let version = reader.read_var_u32()?; if version != 2 { return Err(BinaryReaderError::new( - format!("unsupported linking section version: {}", version), + format!("unsupported linking section version: {version}"), offset, )); } diff --git a/third_party/rust/wasmparser/src/readers/core/memories.rs b/third_party/rust/wasmparser/src/readers/core/memories.rs @@ -35,20 +35,24 @@ impl<'a> FromReader<'a> for MemoryType { Ok(MemoryType { memory64, shared, - initial: if memory64 { + initial: if reader.memory64() { reader.read_var_u64()? } else { reader.read_var_u32()?.into() }, maximum: if !has_max { None - } else if memory64 { + } else if reader.memory64() { Some(reader.read_var_u64()?) } else { Some(reader.read_var_u32()?.into()) }, page_size_log2: if has_page_size { - Some(reader.read_var_u32()?) + let val = reader.read_var_u32()?; + if val >= 64 { + bail!(pos, "invalid custom page size"); + } + Some(val) } else { None }, diff --git a/third_party/rust/wasmparser/src/readers/core/operators.rs b/third_party/rust/wasmparser/src/readers/core/operators.rs @@ -16,6 +16,7 @@ use crate::limits::{MAX_WASM_CATCHES, MAX_WASM_HANDLERS}; use crate::prelude::*; use crate::{BinaryReader, BinaryReaderError, FromReader, Result, ValType}; +use core::{fmt, mem}; /// Represents a block type. #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -111,6 +112,105 @@ impl PartialEq<Self> for BrTable<'_> { impl Eq for BrTable<'_> {} +impl<'a> BrTable<'a> { + /// Returns the number of `br_table` entries, not including the default + /// label + pub fn len(&self) -> u32 { + self.cnt + } + + /// Returns whether `BrTable` doesn't have any labels apart from the default one. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the default target of this `br_table` instruction. + pub fn default(&self) -> u32 { + self.default + } + + /// Returns the list of targets that this `br_table` instruction will be + /// jumping to. + /// + /// This method will return an iterator which parses each target of this + /// `br_table` except the default target. The returned iterator will + /// yield `self.len()` elements. + /// + /// # Examples + /// + /// ```rust + /// use wasmparser::{BinaryReader, OperatorsReader, Operator}; + /// + /// let buf = [0x0e, 0x02, 0x01, 0x02, 0x00]; + /// let mut reader = OperatorsReader::new(BinaryReader::new(&buf, 0)); + /// let op = reader.read().unwrap(); + /// if let Operator::BrTable { targets } = op { + /// let targets = targets.targets().collect::<Result<Vec<_>, _>>().unwrap(); + /// assert_eq!(targets, [1, 2]); + /// } + /// ``` + pub fn targets(&self) -> BrTableTargets<'_> { + BrTableTargets { + reader: self.reader.clone(), + remaining: self.cnt, + } + } +} + +/// An iterator over the targets of a [`BrTable`]. +/// +/// # Note +/// +/// This iterator parses each target of the underlying `br_table` +/// except for the default target. +/// The iterator will yield exactly as many targets as the `br_table` has. +pub struct BrTableTargets<'a> { + reader: crate::BinaryReader<'a>, + remaining: u32, +} + +impl<'a> Iterator for BrTableTargets<'a> { + type Item = Result<u32>; + + fn size_hint(&self) -> (usize, Option<usize>) { + let remaining = usize::try_from(self.remaining).unwrap_or_else(|error| { + panic!("could not convert remaining `u32` into `usize`: {error}") + }); + (remaining, Some(remaining)) + } + + fn next(&mut self) -> Option<Self::Item> { + if self.remaining == 0 { + if !self.reader.eof() { + return Some(Err(BinaryReaderError::new( + "trailing data in br_table", + self.reader.original_position(), + ))); + } + return None; + } + self.remaining -= 1; + Some(self.reader.read_var_u32()) + } +} + +impl fmt::Debug for BrTable<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut f = f.debug_struct("BrTable"); + f.field("count", &self.cnt); + f.field("default", &self.default); + match self.targets().collect::<Result<Vec<_>>>() { + Ok(targets) => { + f.field("targets", &targets); + } + Err(_) => { + f.field("reader", &self.reader); + } + } + f.finish() + } +} + /// An IEEE binary32 immediate floating point value, represented as a u32 /// containing the bit pattern. /// @@ -230,15 +330,131 @@ macro_rules! define_operator { } crate::for_each_operator!(define_operator); -/// A reader for a core WebAssembly function's operators. +/// A trait representing the stack of frames within a function. +/// +/// The [`BinaryReader::visit_operator`] and +/// [`OperatorsReaders`](crate::OperatorsReader) type use +/// information about the current frame kind to enforce the syntactic +/// requirements of the binary format. +pub trait FrameStack { + /// The current frame kind. + fn current_frame(&self) -> Option<FrameKind>; +} + +/// The Wasm control stack for the [`OperatorsReader`]. +#[derive(Debug, Default, Clone)] +pub struct ControlStack { + /// All frames on the control stack exclusing the top-most frame. + frames: Vec<FrameKind>, + /// The top-most frame on the control stack if any. + top: Option<FrameKind>, +} + +impl ControlStack { + /// Resets `self` but keeps heap allocations. + pub fn clear(&mut self) { + self.frames.clear(); + self.top = None; + } + + /// Returns `true` if `self` is empty. + #[inline] + pub fn is_empty(&self) -> bool { + self.top.is_none() + } + + /// Pushes the `frame` to `self`. + #[inline] + pub fn push(&mut self, frame: FrameKind) { + if let Some(old_top) = self.top.replace(frame) { + self.frames.push(old_top); + } + } + + /// Pops the top-most [`FrameKind`] from `self`. + pub fn pop(&mut self) -> Option<FrameKind> { + mem::replace(&mut self.top, self.frames.pop()) + } + + /// Returns the top-mot [`FrameKind`]. + #[inline] + pub fn last(&self) -> Option<FrameKind> { + self.top + } +} + +/// Adapters from VisitOperators to FrameStacks +struct FrameStackAdapter<'a, T> { + stack: &'a mut ControlStack, + visitor: &'a mut T, +} + +impl<T> FrameStack for FrameStackAdapter<'_, T> { + fn current_frame(&self) -> Option<FrameKind> { + self.stack.last() + } +} + +struct SingleFrameAdapter<'a, T> { + current_frame: FrameKind, + visitor: &'a mut T, +} + +impl<T> FrameStack for SingleFrameAdapter<'_, T> { + fn current_frame(&self) -> Option<FrameKind> { + Some(self.current_frame) + } +} + +/// A reader for a core WebAssembly function's operators. The [`OperatorsReader`] internally +/// maintains a stack of the kinds of frames within an expression or function body. +/// This is necessary to enforce the syntactic requirements of the binary format. +/// The BinaryReader can also be used to read the operators by providing an external [`FrameStack`] instance. #[derive(Clone)] pub struct OperatorsReader<'a> { reader: BinaryReader<'a>, + stack: ControlStack, } +/// External handle to the internal allocations used by the OperatorsReader +/// +/// This is created with either the `Default` implementation or with +/// [`OperatorsReader::into_allocations`]. It is then passed as an argument to +/// [`OperatorsReader::new`] to provide a means of reusing allocations +/// between each expression or function body. +#[derive(Default)] +pub struct OperatorsReaderAllocations(ControlStack); + impl<'a> OperatorsReader<'a> { - pub(crate) fn new(reader: BinaryReader<'a>) -> OperatorsReader<'a> { - OperatorsReader { reader } + /// Creates a new reader for an expression (instruction sequence). + /// + /// This method, in conjunction with [`OperatorsReader::into_allocations`], + /// provides a means to reuse allocations across reading each + /// individual expression or function body. Note that it is also sufficient + /// to call this method with `Default::default()` if no prior allocations are + /// available. + pub fn new(reader: BinaryReader<'a>) -> Self { + Self::new_with_allocs(reader, Default::default()) + } + + /// Same as [`OperatorsReader::new`] except that the + /// [`OperatorsReaderAllocations`] can be specified here to amortize the + /// cost of them over multiple readers. + pub fn new_with_allocs( + reader: BinaryReader<'a>, + mut allocs: OperatorsReaderAllocations, + ) -> Self { + allocs.0.clear(); + allocs.0.push(FrameKind::Block); + Self { + reader, + stack: allocs.0, + } + } + + /// Get binary reader + pub fn get_binary_reader(&self) -> BinaryReader<'a> { + self.reader.clone() } /// Determines if the reader is at the end of the operators. @@ -251,22 +467,92 @@ impl<'a> OperatorsReader<'a> { self.reader.original_position() } - /// Ensures the reader is at the end. + /// Returns whether there is an `end` opcode followed by eof remaining in + /// this reader. + pub fn is_end_then_eof(&self) -> bool { + self.reader.is_end_then_eof() + } + + /// Consumes this reader and returns the underlying allocations that + /// were used to store the frame stack. /// - /// This function returns an error if there is extra data after the operators. - pub fn ensure_end(&self) -> Result<()> { - if self.eof() { - return Ok(()); - } - Err(BinaryReaderError::new( - "unexpected data at the end of operators", - self.reader.original_position(), - )) + /// The returned value here can be paired with + /// [`OperatorsReader::new`] to reuse the allocations already + /// created by this reader. + pub fn into_allocations(self) -> OperatorsReaderAllocations { + OperatorsReaderAllocations(self.stack) } - /// Reads an operator from the reader. + /// Reads the next available `Operator`. + /// + /// # Errors + /// + /// If `OperatorsReader` has less bytes remaining than required to parse + /// the `Operator`, or if the input is malformed. pub fn read(&mut self) -> Result<Operator<'a>> { - self.reader.read_operator() + self.visit_operator(&mut OperatorFactory) + } + + /// Visit the next available operator with the specified [`VisitOperator`] instance. + /// + /// Note that this does not implicitly propagate any additional information such as instruction + /// offsets. In order to do so, consider storing such data within the visitor before visiting. + /// + /// # Errors + /// + /// If `OperatorsReader` has less bytes remaining than required to parse the `Operator`, + /// or if the input is malformed. + /// + /// # Examples + /// + /// Store an offset for use in diagnostics or any other purposes: + /// + /// ``` + /// # use wasmparser::{OperatorsReader, VisitOperator, Result, for_each_visit_operator}; + /// + /// pub fn dump(mut reader: OperatorsReader) -> Result<()> { + /// let mut visitor = Dumper { offset: 0 }; + /// while !reader.eof() { + /// visitor.offset = reader.original_position(); + /// reader.visit_operator(&mut visitor)?; + /// } + /// Ok(()) + /// } + /// + /// struct Dumper { + /// offset: usize + /// } + /// + /// macro_rules! define_visit_operator { + /// ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => { + /// $( + /// fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output { + /// println!("{}: {}", self.offset, stringify!($visit)); + /// } + /// )* + /// } + /// } + /// + /// impl<'a> VisitOperator<'a> for Dumper { + /// type Output = (); + /// for_each_visit_operator!(define_visit_operator); + /// } + /// + /// ``` + pub fn visit_operator<T>(&mut self, visitor: &mut T) -> Result<<T as VisitOperator<'a>>::Output> + where + T: VisitOperator<'a>, + { + self.reader.visit_operator(&mut FrameStackAdapter { + stack: &mut self.stack, + visitor, + }) + } + + /// Reads an operator with its offset. + pub fn read_with_offset(&mut self) -> Result<(Operator<'a>, usize)> { + let pos = self.reader.original_position(); + Ok((self.read()?, pos)) } /// Converts to an iterator of operators paired with offsets. @@ -277,31 +563,34 @@ impl<'a> OperatorsReader<'a> { } } - /// Reads an operator with its offset. - pub fn read_with_offset(&mut self) -> Result<(Operator<'a>, usize)> { - let pos = self.reader.original_position(); - Ok((self.read()?, pos)) + pub(crate) fn skip_const_expr(&mut self) -> Result<()> { + // TODO add skip_operator() method and/or validate ConstExpr operators. + loop { + if let Operator::End = self.read()? { + if self.current_frame().is_some() { + bail!( + self.original_position(), + "control frames remain at end of expression" + ); + } + return Ok(()); + } + } } - /// Visit a single operator with the specified [`VisitOperator`] instance. + /// Function that must be called after the last opcode has been processed. /// - /// See [`BinaryReader::visit_operator`] for more information. - pub fn visit_operator<T>(&mut self, visitor: &mut T) -> Result<<T as VisitOperator<'a>>::Output> - where - T: VisitOperator<'a>, - { - self.reader.visit_operator(visitor) - } - - /// Gets a binary reader from this operators reader. - pub fn get_binary_reader(&self) -> BinaryReader<'a> { - self.reader.clone() + /// This function returns an error if there is extra data after the operators. + /// It does *not* check the binary format requirement that if the data count + /// section is absent, a data index may not occur in the code section. + pub fn finish(&self) -> Result<()> { + self.reader.finish_expression(self) } +} - /// Returns whether there is an `end` opcode followed by eof remaining in - /// this reader. - pub fn is_end_then_eof(&self) -> bool { - self.reader.is_end_then_eof() +impl<'a> FrameStack for OperatorsReader<'a> { + fn current_frame(&self) -> Option<FrameKind> { + self.stack.last() } } @@ -343,6 +632,14 @@ pub struct OperatorsIterator<'a> { err: bool, } +impl<'a> OperatorsIterator<'a> { + /// Consumes this iterator and returns the underlying allocations. + /// See [`OperatorsReader::into_allocations`]. + pub fn into_allocations(self) -> OperatorsReaderAllocations { + self.reader.into_allocations() + } +} + impl<'a> Iterator for OperatorsIterator<'a> { type Item = Result<Operator<'a>>; @@ -362,6 +659,14 @@ pub struct OperatorsIteratorWithOffsets<'a> { err: bool, } +impl<'a> OperatorsIteratorWithOffsets<'a> { + /// Consumes this iterator and returns the underlying allocations. + /// See [`OperatorsReader::into_allocations`]. + pub fn into_allocations(self) -> OperatorsReaderAllocations { + self.reader.into_allocations() + } +} + impl<'a> Iterator for OperatorsIteratorWithOffsets<'a> { type Item = Result<(Operator<'a>, usize)>; @@ -650,3 +955,151 @@ impl<'a> FromReader<'a> for Handle { }) } } + +/// A factory to construct [`Operator`] instances via the [`VisitOperator`] trait. +struct OperatorFactory; + +macro_rules! define_visit_operator { + ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => { + $( + fn $visit(&mut self $($(,$arg: $argty)*)?) -> Operator<'a> { + Operator::$op $({ $($arg),* })? + } + )* + } +} + +impl<'a> VisitOperator<'a> for OperatorFactory { + type Output = Operator<'a>; + + #[cfg(feature = "simd")] + fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = Self::Output>> { + Some(self) + } + + crate::for_each_visit_operator!(define_visit_operator); +} + +#[cfg(feature = "simd")] +impl<'a> VisitSimdOperator<'a> for OperatorFactory { + crate::for_each_visit_simd_operator!(define_visit_operator); +} + +macro_rules! define_visit_operator_stack_adapter { + ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => { + $( + fn $visit(&mut self $($(,$arg: $argty)*)?) -> T::Output { + define_visit_operator_stack_adapter!(@visit self $visit $($($arg,)*)?) + } + )* + }; + + (@visit $self:ident visit_block $($rest:tt)*) => {{ + $self.stack.push(FrameKind::Block); + $self.visitor.visit_block( $($rest)* ) + }}; + + (@visit $self:ident visit_loop $($rest:tt)*) => {{ + $self.stack.push(FrameKind::Loop); + $self.visitor.visit_loop( $($rest)* ) + }}; + + (@visit $self:ident visit_if $($rest:tt)*) => {{ + $self.stack.push(FrameKind::If); + $self.visitor.visit_if( $($rest)* ) + }}; + + (@visit $self:ident visit_else $($rest:tt)*) => {{ + $self.stack.pop(); + $self.stack.push(FrameKind::Else); + $self.visitor.visit_else( $($rest)* ) + }}; + + (@visit $self:ident visit_try $($rest:tt)*) => {{ + $self.stack.push(FrameKind::LegacyTry); + $self.visitor.visit_try( $($rest)* ) + }}; + + (@visit $self:ident visit_catch $($rest:tt)*) => {{ + $self.stack.pop(); + $self.stack.push(FrameKind::LegacyCatch); + $self.visitor.visit_catch( $($rest)* ) + }}; + + (@visit $self:ident visit_catch_all $($rest:tt)*) => {{ + $self.stack.pop(); + $self.stack.push(FrameKind::LegacyCatchAll); + $self.visitor.visit_catch_all( $($rest)* ) + }}; + + (@visit $self:ident visit_try_table $($rest:tt)*) => {{ + $self.stack.push(FrameKind::TryTable); + $self.visitor.visit_try_table( $($rest)* ) + }}; + + (@visit $self:ident visit_delegate $($rest:tt)*) => {{ + $self.stack.pop(); + $self.visitor.visit_delegate( $($rest)* ) + }}; + + (@visit $self:ident visit_end $($rest:tt)*) => {{ + $self.stack.pop(); + $self.visitor.visit_end( $($rest)* ) + }}; + + (@visit $self:ident $visit:ident $($rest:tt)*) => { + $self.visitor.$visit( $($rest)* ) + }; +} + +impl<'a, T: VisitOperator<'a>> VisitOperator<'a> for FrameStackAdapter<'_, T> { + type Output = T::Output; + + #[cfg(feature = "simd")] + fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = Self::Output>> { + self.visitor.simd_visitor() + } + + crate::for_each_visit_operator!(define_visit_operator_stack_adapter); +} + +macro_rules! define_passthrough_visit_operator { + ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => { + $( + fn $visit(&mut self $($(,$arg: $argty)*)?) -> T::Output { + self.visitor.$visit( $($($arg,)*)? ) + } + )* + }; +} + +impl<'a, T: VisitOperator<'a>> VisitOperator<'a> for SingleFrameAdapter<'_, T> { + type Output = T::Output; + + #[cfg(feature = "simd")] + fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = Self::Output>> { + self.visitor.simd_visitor() + } + + crate::for_each_visit_operator!(define_passthrough_visit_operator); +} + +impl<'a> BinaryReader<'a> { + /// Peeks at the next available `Operator`, given a borrowed `FrameStack`. + /// + /// # Errors + /// + /// If `BinaryReader` has less bytes remaining than required to parse + /// the `Operator`, or if the input is malformed. + pub fn peek_operator<T: FrameStack>(&self, stack: &T) -> Result<Operator<'a>> { + self.clone().visit_operator(&mut SingleFrameAdapter { + current_frame: stack.current_frame().ok_or_else(|| { + format_err!( + self.original_position(), + "operators remaining after end of function body or expression" + ) + })?, + visitor: &mut OperatorFactory, + }) + } +} diff --git a/third_party/rust/wasmparser/src/readers/core/producers.rs b/third_party/rust/wasmparser/src/readers/core/producers.rs @@ -46,7 +46,7 @@ pub struct ProducersField<'a> { impl<'a> FromReader<'a> for ProducersField<'a> { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { let offset = reader.original_position(); - let name = reader.read_string()?; + let name = reader.read_unlimited_string()?; match name { "language" | "sdk" | "processed-by" => {} _ => bail!(offset, "invalid producers field name: `{name}`"), @@ -77,8 +77,8 @@ pub struct ProducersFieldValue<'a> { impl<'a> FromReader<'a> for ProducersFieldValue<'a> { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { - let name = reader.read_string()?; - let version = reader.read_string()?; + let name = reader.read_unlimited_string()?; + let version = reader.read_unlimited_string()?; Ok(ProducersFieldValue { name, version }) } } diff --git a/third_party/rust/wasmparser/src/readers/core/reloc.rs b/third_party/rust/wasmparser/src/readers/core/reloc.rs @@ -128,7 +128,7 @@ back_to_enum! { MemoryAddrRelSleb = 11, /// A function address (table index) relative to the __table_base wasm - /// global. Used in position indepenent code (-fPIC) where absolute + /// global. Used in position independent code (-fPIC) where absolute /// function addresses are not known at link time. TableIndexRelSleb = 12, @@ -229,7 +229,7 @@ pub struct RelocationEntry { /// Relocation entry type. pub ty: RelocationType, /// Offset in bytes from the start of the section indicated by - /// `RelocSectionReader::section` targetted by this relocation. + /// `RelocSectionReader::section` targeted by this relocation. pub offset: u32, /// Index in the symbol table contained in the linking section that /// corresponds to the value at `offset`. @@ -241,7 +241,7 @@ pub struct RelocationEntry { impl RelocationEntry { /// Byte range relative to the start of the section indicated by - /// `RelocSectionReader::section` targetted by this relocation. + /// `RelocSectionReader::section` targeted by this relocation. pub fn relocation_range(&self) -> Range<usize> { (self.offset as usize)..(self.offset as usize + self.ty.extent()) } diff --git a/third_party/rust/wasmparser/src/readers/core/tables.rs b/third_party/rust/wasmparser/src/readers/core/tables.rs @@ -74,17 +74,18 @@ impl<'a> FromReader<'a> for TableType { let has_max = (flags & 0b001) != 0; let shared = (flags & 0b010) != 0; let table64 = (flags & 0b100) != 0; + Ok(TableType { element_type, table64, - initial: if table64 { + initial: if reader.memory64() { reader.read_var_u64()? } else { reader.read_var_u32()?.into() }, maximum: if !has_max { None - } else if table64 { + } else if reader.memory64() { Some(reader.read_var_u64()?) } else { Some(reader.read_var_u32()?.into()) diff --git a/third_party/rust/wasmparser/src/readers/core/types.rs b/third_party/rust/wasmparser/src/readers/core/types.rs @@ -489,6 +489,8 @@ impl SubType { composite_type: CompositeType { inner: CompositeInnerType::Func(signature), shared, + descriptor_idx: None, + describes_idx: None, }, } } @@ -523,6 +525,12 @@ impl SubType { if let Some(idx) = &mut self.supertype_idx { f(idx)?; } + if let Some(idx) = &mut self.composite_type.descriptor_idx { + f(idx)?; + } + if let Some(idx) = &mut self.composite_type.describes_idx { + f(idx)?; + } match &mut self.composite_type.inner { CompositeInnerType::Func(ty) => { for ty in ty.params_mut() { @@ -548,16 +556,6 @@ impl SubType { } } -/// Represents a composite type in a WebAssembly module. -#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct CompositeType { - /// The type defined inside the composite type. - pub inner: CompositeInnerType, - /// Is the composite type shared? This is part of the - /// shared-everything-threads proposal. - pub shared: bool, -} - /// A [`CompositeType`] can contain one of these types. #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum CompositeInnerType { @@ -571,18 +569,37 @@ pub enum CompositeInnerType { Cont(ContType), } +impl fmt::Display for CompositeInnerType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CompositeInnerType::Func(ty) => write!(f, "{ty}"), + CompositeInnerType::Array(ty) => write!(f, "{ty}"), + CompositeInnerType::Struct(ty) => write!(f, "{ty}"), + CompositeInnerType::Cont(ty) => write!(f, "{ty}"), + } + } +} + +/// Represents a composite type in a WebAssembly module. +#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct CompositeType { + /// The type defined inside the composite type. + pub inner: CompositeInnerType, + /// Is the composite type shared? This is part of the + /// shared-everything-threads proposal. + pub shared: bool, + /// The descriptor type. + pub descriptor_idx: Option<PackedIndex>, + /// The descriptor for type. + pub describes_idx: Option<PackedIndex>, +} + impl fmt::Display for CompositeType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use CompositeInnerType::*; if self.shared { write!(f, "(shared ")?; } - match self.inner { - Array(_) => write!(f, "(array ...)"), - Func(_) => write!(f, "(func ...)"), - Struct(_) => write!(f, "(struct ...)"), - Cont(_) => write!(f, "(cont ...)"), - }?; + write!(f, "{}", self.inner)?; if self.shared { write!(f, ")")?; } @@ -642,6 +659,28 @@ impl fmt::Debug for FuncType { } } +impl fmt::Display for FuncType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(func")?; + if self.params().len() > 0 { + write!(f, " (param")?; + for p in self.params() { + write!(f, " {p}")?; + } + write!(f, ")")?; + } + if self.results().len() > 0 { + write!(f, " (result")?; + for p in self.results() { + write!(f, " {p}")?; + } + write!(f, ")")?; + } + write!(f, ")")?; + Ok(()) + } +} + impl FuncType { /// Creates a new [`FuncType`] from the given `params` and `results`. pub fn new<P, R>(params: P, results: R) -> Self @@ -698,35 +737,18 @@ impl FuncType { pub(crate) fn results_mut(&mut self) -> &mut [ValType] { &mut self.params_results[self.len_params..] } - - #[cfg(all(feature = "validate", feature = "component-model"))] - pub(crate) fn desc(&self) -> String { - use core::fmt::Write; - - let mut s = String::new(); - s.push_str("["); - for (i, param) in self.params().iter().enumerate() { - if i > 0 { - s.push_str(" "); - } - write!(s, "{param}").unwrap(); - } - s.push_str("] -> ["); - for (i, result) in self.results().iter().enumerate() { - if i > 0 { - s.push_str(" "); - } - write!(s, "{result}").unwrap(); - } - s.push_str("]"); - s - } } /// Represents a type of an array in a WebAssembly module. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct ArrayType(pub FieldType); +impl fmt::Display for ArrayType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(array {})", self.0) + } +} + /// Represents a field type of an array or a struct. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct FieldType { @@ -736,6 +758,16 @@ pub struct FieldType { pub mutable: bool, } +impl fmt::Display for FieldType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.mutable { + write!(f, "(mut {})", self.element_type) + } else { + fmt::Display::fmt(&self.element_type, f) + } + } +} + impl FieldType { /// Maps any `UnpackedIndex` via the specified closure. #[cfg(feature = "validate")] @@ -798,10 +830,27 @@ pub struct StructType { pub fields: Box<[FieldType]>, } +impl fmt::Display for StructType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(struct")?; + for field in self.fields.iter() { + write!(f, " {field}")?; + } + write!(f, ")")?; + Ok(()) + } +} + /// Represents a type of a continuation in a WebAssembly module. #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct ContType(pub PackedIndex); +impl fmt::Display for ContType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(cont {})", self.0) + } +} + impl ContType { /// Maps any `UnpackedIndex` via the specified closure. #[cfg(feature = "validate")] @@ -899,7 +948,11 @@ impl ValType { ValType::Ref(r) => { if let Some(mut idx) = r.type_index() { map(&mut idx)?; - *r = RefType::concrete(r.is_nullable(), idx); + *r = if r.is_exact_type_ref() { + RefType::exact(r.is_nullable(), idx) + } else { + RefType::concrete(r.is_nullable(), idx) + } } } ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => {} @@ -919,14 +972,14 @@ impl ValType { /// The GC proposal introduces heap types: any, eq, i31, struct, array, /// nofunc, noextern, none. // -// RefType is a bit-packed enum that fits in a `u24` aka `[u8; 3]`. Note that +// RefType is a bit-packed enum that fits in a u32. Note that // its content is opaque (and subject to change), but its API is stable. // // It has the following internal structure: // // ``` -// [nullable:u1 concrete==1:u1 index:u22] -// [nullable:u1 concrete==0:u1 shared:u1 abstype:u4 (unused):u17] +// [concrete==1:u1 exact:u1 nullable:u1 index:u22] +// [concrete==0:u1 (unused):u1 nullable:u1 shared:u1 abstype:u4 (unused):u17] // ``` // // Where @@ -937,6 +990,8 @@ impl ValType { // index (encoded in a following bit-packing section) or of a known fixed // type, // +// - `exact` determites if the ref is of an exact type, +// // - `index` is the type index, // // - `shared` determines if the ref is shared, but only if it is not concrete in @@ -966,7 +1021,7 @@ impl ValType { // 0000 = none // ``` #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct RefType([u8; 3]); +pub struct RefType(u32); impl fmt::Debug for RefType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -979,22 +1034,25 @@ impl fmt::Debug for RefType { let name = ty.as_str(nullable); match (nullable, shared) { // Print the shortened form if nullable; i.e., `*ref`. - (true, true) => write!(f, "(shared {}ref)", name), - (true, false) => write!(f, "{}ref", name), + (true, true) => write!(f, "(shared {name}ref)"), + (true, false) => write!(f, "{name}ref"), // Print the long form otherwise; i.e., `(ref *)`. - (false, true) => write!(f, "(ref (shared {}))", name), - (false, false) => write!(f, "(ref {})", name), + (false, true) => write!(f, "(ref (shared {name}))"), + (false, false) => write!(f, "(ref {name})"), } } // Handle concrete types separately; they always use the long form // and don't show `shared`-ness. HeapType::Concrete(index) => { if self.is_nullable() { - write!(f, "(ref null {})", index) + write!(f, "(ref null {index})") } else { - write!(f, "(ref {})", index) + write!(f, "(ref {index})") } } + HeapType::Exact(index) => { + write!(f, "(ref (exact {index}))") + } } } } @@ -1028,8 +1086,9 @@ fn can_fit_max_wasm_types_in_ref_type() { impl RefType { // These bits are valid for all `RefType`s. - const NULLABLE_BIT: u32 = 1 << 23; - const CONCRETE_BIT: u32 = 1 << 22; + const CONCRETE_BIT: u32 = 1 << 24; + const EXACT_BIT: u32 = 1 << 23; + const NULLABLE_BIT: u32 = 1 << 22; // The `abstype` field is valid only when `concrete == 0`. const SHARED_BIT: u32 = 1 << 21; @@ -1149,25 +1208,14 @@ impl RefType { index & Self::INDEX_MASK == index } - const fn u24_to_u32(bytes: [u8; 3]) -> u32 { - let expanded_bytes = [bytes[0], bytes[1], bytes[2], 0]; - u32::from_le_bytes(expanded_bytes) - } - - const fn u32_to_u24(x: u32) -> [u8; 3] { - let bytes = x.to_le_bytes(); - debug_assert!(bytes[3] == 0); - [bytes[0], bytes[1], bytes[2]] - } - #[inline] const fn as_u32(&self) -> u32 { - Self::u24_to_u32(self.0) + self.0 } #[inline] const fn from_u32(x: u32) -> Self { - debug_assert!(x & (0b11111111 << 24) == 0); + debug_assert!(x & (0b1111111 << 25) == 0); // Either concrete or it must be a known abstract type. debug_assert!( @@ -1191,7 +1239,7 @@ impl RefType { ) ); - RefType(Self::u32_to_u24(x)) + RefType(x) } /// Create a reference to a concrete Wasm-defined type at the given @@ -1206,6 +1254,14 @@ impl RefType { RefType::from_u32(nullable32 | Self::CONCRETE_BIT | index) } + /// Create a reference to exact type. + pub fn exact(nullable: bool, index: PackedIndex) -> Self { + let index: u32 = PackedIndex::to_u32(index); + debug_assert!(Self::can_represent_type_index(index)); + let nullable32 = Self::NULLABLE_BIT * nullable as u32; + RefType::from_u32(nullable32 | Self::EXACT_BIT | Self::CONCRETE_BIT | index) + } + /// Create a new `RefType`. /// /// Returns `None` when the heap type's type index (if any) is beyond this @@ -1214,6 +1270,7 @@ impl RefType { let base32 = Self::NULLABLE_BIT * (nullable as u32); match heap_type { HeapType::Concrete(index) => Some(RefType::concrete(nullable, index.pack()?)), + HeapType::Exact(index) => Some(RefType::exact(nullable, index.pack()?)), HeapType::Abstract { shared, ty } => { use AbstractHeapType::*; let base32 = base32 | (Self::SHARED_BIT * (shared as u32)); @@ -1257,6 +1314,11 @@ impl RefType { self.as_u32() & Self::CONCRETE_BIT != 0 } + /// Is this an exact reference to a type? + pub const fn is_exact_type_ref(&self) -> bool { + !self.as_u32() & (Self::EXACT_BIT | Self::CONCRETE_BIT) == 0 + } + /// If this is a reference to a concrete Wasm-defined type, get its /// type index. pub fn type_index(&self) -> Option<PackedIndex> { @@ -1303,6 +1365,11 @@ impl RefType { !self.is_concrete_type_ref() && self.abstype() == Self::CONT_ABSTYPE } + /// Is this none type? + pub const fn is_none_ref(&self) -> bool { + !self.is_concrete_type_ref() && self.abstype() == Self::NONE_ABSTYPE + } + /// Is this ref type nullable? pub const fn is_nullable(&self) -> bool { self.as_u32() & Self::NULLABLE_BIT != 0 @@ -1331,7 +1398,11 @@ impl RefType { pub fn heap_type(&self) -> HeapType { let s = self.as_u32(); if self.is_concrete_type_ref() { - HeapType::Concrete(self.type_index().unwrap().unpack()) + if !self.is_exact_type_ref() { + HeapType::Concrete(self.type_index().unwrap().unpack()) + } else { + HeapType::Exact(self.type_index().unwrap().unpack()) + } } else { use AbstractHeapType::*; let shared = s & Self::SHARED_BIT != 0; @@ -1434,6 +1505,13 @@ impl RefType { "(ref $type)" } } + HeapType::Exact(_) => { + if nullable { + "(ref null (exact $type))" + } else { + "(ref (exact $type))" + } + } } } } @@ -1454,6 +1532,10 @@ pub enum HeapType { /// /// Introduced in the function-references proposal. Concrete(UnpackedIndex), + /// An exact, user-defined type. + /// + /// Introduced in the custom-descriptors proposal. + Exact(UnpackedIndex), } impl HeapType { @@ -1675,6 +1757,7 @@ impl<'a> FromReader<'a> for ValType { // | 0x65 | -27 | shared $t | shared-everything proposal | // | 0x64 | -28 | ref $t | gc proposal, prefix byte | // | 0x63 | -29 | ref null $t | gc proposal, prefix byte | + // | 0x62 | -30 | exact $t | custom descriptor proposal | // | 0x60 | -32 | func $t | prefix byte | // | 0x5f | -33 | struct $t | gc proposal, prefix byte | // | 0x5e | -34 | array $t | gc proposal, prefix byte | @@ -1737,6 +1820,7 @@ impl<'a> FromReader<'a> for RefType { RefType::new(nullable, reader.read()?) .ok_or_else(|| crate::BinaryReaderError::new("type index too large", pos)) } + 0x62 => Err(crate::BinaryReaderError::new("unexpected exact type", pos)), _ => { // Reclassify errors as invalid reference types here because // that's the "root" of what was being parsed rather than @@ -1783,6 +1867,11 @@ impl<'a> FromReader<'a> for HeapType { let ty = reader.read()?; Ok(HeapType::Abstract { shared: true, ty }) } + 0x62 => { + reader.read_u8()?; + let idx = reader.read_var_u32()?; + Ok(HeapType::Exact(UnpackedIndex::Module(idx))) + } _ => { // Reclassify errors as "invalid heap type" here because // that's the "root" of what was being parsed rather than @@ -1822,7 +1911,7 @@ impl<'a> FromReader<'a> for AbstractHeapType { return Err(BinaryReaderError::invalid( "invalid abstract heap type", reader.original_position() - 1, - )) + )); } } } @@ -1990,6 +2079,28 @@ fn read_composite_type( } else { (false, opcode) }; + let (describes_idx, opcode) = if opcode == 0x4c { + let idx = PackedIndex::from_module_index(reader.read_var_u32()?).ok_or_else(|| { + BinaryReaderError::new( + "type index greater than implementation limits", + reader.original_position(), + ) + })?; + (Some(idx), reader.read_u8()?) + } else { + (None, opcode) + }; + let (descriptor_idx, opcode) = if opcode == 0x4d { + let idx = PackedIndex::from_module_index(reader.read_var_u32()?).ok_or_else(|| { + BinaryReaderError::new( + "type index greater than implementation limits", + reader.original_position(), + ) + })?; + (Some(idx), reader.read_u8()?) + } else { + (None, opcode) + }; let inner = match opcode { 0x60 => CompositeInnerType::Func(reader.read()?), 0x5e => CompositeInnerType::Array(reader.read()?), @@ -1997,7 +2108,12 @@ fn read_composite_type( 0x5d => CompositeInnerType::Cont(reader.read()?), x => return reader.invalid_leading_byte(x, "type"), }; - Ok(CompositeType { shared, inner }) + Ok(CompositeType { + shared, + inner, + descriptor_idx, + describes_idx, + }) } impl<'a> FromReader<'a> for RecGroup { diff --git a/third_party/rust/wasmparser/src/readers/core/types/matches.rs b/third_party/rust/wasmparser/src/readers/core/types/matches.rs @@ -13,9 +13,9 @@ //! don't need to match again; we just look at the declarations from now on. use crate::{ - types::{CoreTypeId, RecGroupId, TypeList}, ArrayType, CompositeInnerType, CompositeType, ContType, FieldType, FuncType, RefType, StorageType, StructType, SubType, ValType, + types::{CoreTypeId, RecGroupId, TypeList}, }; /// Wasm type matching. diff --git a/third_party/rust/wasmparser/src/resources.rs b/third_party/rust/wasmparser/src/resources.rs @@ -14,8 +14,8 @@ */ use crate::{ - types::CoreTypeId, BinaryReaderError, FuncType, GlobalType, HeapType, MemoryType, RefType, - SubType, TableType, ValType, WasmFeatures, + BinaryReaderError, FuncType, GlobalType, HeapType, MemoryType, RefType, SubType, TableType, + ValType, WasmFeatures, types::CoreTypeId, }; /// Types that qualify as Wasm validation database. @@ -129,6 +129,9 @@ pub trait WasmModuleResources { /// Returns whether the function index is referenced in the module anywhere /// outside of the start/function sections. fn is_function_referenced(&self, idx: u32) -> bool; + + /// Returns whether the function defined with the exact type. + fn has_function_exact_type(&self, idx: u32) -> bool; } impl<T> WasmModuleResources for &'_ T @@ -183,6 +186,9 @@ where fn is_function_referenced(&self, idx: u32) -> bool { T::is_function_referenced(self, idx) } + fn has_function_exact_type(&self, idx: u32) -> bool { + T::has_function_exact_type(self, idx) + } } impl<T> WasmModuleResources for alloc::sync::Arc<T> @@ -252,4 +258,8 @@ where fn is_function_referenced(&self, idx: u32) -> bool { T::is_function_referenced(self, idx) } + + fn has_function_exact_type(&self, idx: u32) -> bool { + T::has_function_exact_type(self, idx) + } } diff --git a/third_party/rust/wasmparser/src/validator.rs b/third_party/rust/wasmparser/src/validator.rs @@ -15,8 +15,9 @@ use crate::prelude::*; use crate::{ - limits::*, AbstractHeapType, BinaryReaderError, Encoding, FromReader, FunctionBody, HeapType, - Parser, Payload, RefType, Result, SectionLimited, ValType, WasmFeatures, WASM_MODULE_VERSION, + AbstractHeapType, BinaryReaderError, Encoding, FromReader, FunctionBody, HeapType, Parser, + Payload, RefType, Result, SectionLimited, ValType, WASM_MODULE_VERSION, WasmFeatures, + limits::*, }; use ::core::mem; use ::core::ops::Range; @@ -276,6 +277,15 @@ impl WasmFeatures { Err("function references required for index reference types") } } + HeapType::Exact(_) => { + // Exact types were introduced wit hthe custom descriptors + // proposal. + if self.custom_descriptors() { + Ok(()) + } else { + Err("custom descriptors required for exact reference types") + } + } HeapType::Abstract { shared, ty } => { use AbstractHeapType::*; if shared && !self.shared_everything_threads() { @@ -318,7 +328,9 @@ impl WasmFeatures { if self.exceptions() { Ok(()) } else { - Err("exception refs not supported without the exception handling feature") + Err( + "exception refs not supported without the exception handling feature", + ) } } @@ -327,7 +339,9 @@ impl WasmFeatures { if self.stack_switching() { Ok(()) } else { - Err("continuation refs not supported without the stack switching feature") + Err( + "continuation refs not supported without the stack switching feature", + ) } } } @@ -346,7 +360,7 @@ pub enum ValidPayload<'a> { /// This result indicates that the specified parser should be used instead /// of the currently-used parser until this returned one ends. Parser(Parser), - /// A function was found to be validate. + /// A function was found to be validated. Func(FuncToValidate<ValidatorResources>, FunctionBody<'a>), /// The end payload was validated and the types known to the validator /// are provided. @@ -391,6 +405,14 @@ impl Validator { /// [`CoreTypeId`][crate::types::CoreTypeId]) for the same types that are /// defined multiple times across different modules and components. /// + /// # Panics + /// + /// This function will panic if the validator was mid-way through + /// validating a binary. Validation must complete entirely or not have + /// started at all for this method to be called. + /// + /// # Examples + /// /// ``` /// fn foo() -> anyhow::Result<()> { /// use wasmparser::Validator; @@ -440,7 +462,7 @@ impl Validator { // they are using the same validation context, even after resetting. id: _, - // Don't mess with `types`, we specifically want to reuse canonicalizations. + // Don't mess with `types`, we specifically want to reuse canonicalization. types: _, // Also leave features as they are. While this is perhaps not @@ -458,7 +480,7 @@ impl Validator { } = self; assert!( - matches!(state, State::End), + matches!(state, State::End) || matches!(state, State::Unparsed(None)), "cannot reset a validator that did not successfully complete validation" ); assert!(module.is_none()); @@ -525,7 +547,7 @@ impl Validator { /// get the types of the component containing that module/component. /// /// Returns `None` if there is no module/component that many levels up. - pub fn types(&self, mut level: usize) -> Option<TypesRef> { + pub fn types(&self, mut level: usize) -> Option<TypesRef<'_>> { if let Some(module) = &self.module { if level == 0 { return Some(TypesRef::from_module(self.id, &self.types, &module.module)); @@ -580,10 +602,10 @@ impl Validator { ElementSection(s) => self.element_section(s)?, DataCountSection { count, range } => self.data_count_section(*count, range)?, CodeSectionStart { - count, + count: _, range, size: _, - } => self.code_section_start(*count, range)?, + } => self.code_section_start(range)?, CodeSectionEntry(body) => { let func_validator = self.code_section_entry(body)?; return Ok(ValidPayload::Func(func_validator, body.clone())); @@ -657,7 +679,7 @@ impl Validator { return Err(BinaryReaderError::new( "wasm version header out of order", range.start, - )) + )); } } @@ -665,7 +687,7 @@ impl Validator { Encoding::Module => { if num == WASM_MODULE_VERSION { assert!(self.module.is_none()); - self.module = Some(ModuleState::default()); + self.module = Some(ModuleState::new(self.features)); State::Module } else { bail!(range.start, "unknown binary version: {num:#x}"); @@ -683,7 +705,7 @@ impl Validator { #[cfg(feature = "component-model")] if num == crate::WASM_COMPONENT_VERSION { self.components - .push(ComponentState::new(ComponentKind::Component)); + .push(ComponentState::new(ComponentKind::Component, self.features)); State::Component } else if num < crate::WASM_COMPONENT_VERSION { bail!(range.start, "unsupported component version: {num:#x}"); @@ -705,10 +727,9 @@ impl Validator { /// Validates [`Payload::TypeSection`](crate::Payload). pub fn type_section(&mut self, section: &crate::TypeSectionReader<'_>) -> Result<()> { self.process_module_section( - Order::Type, section, "type", - |state, _, _types, count, offset| { + |state, _types, count, offset| { check_max( state.module.types.len(), count, @@ -719,11 +740,11 @@ impl Validator { state.module.assert_mut().types.reserve(count as usize); Ok(()) }, - |state, features, types, rec_group, offset| { + |state, types, rec_group, offset| { state .module .assert_mut() - .add_types(rec_group, features, types, offset, true)?; + .add_types(rec_group, types, offset, true)?; Ok(()) }, ) @@ -734,10 +755,9 @@ impl Validator { /// This method should only be called when parsing a module. pub fn import_section(&mut self, section: &crate::ImportSectionReader<'_>) -> Result<()> { self.process_module_section( - Order::Import, section, "import", - |state, _, _, count, offset| { + |state, _, count, offset| { check_max( state.module.imports.len(), count, @@ -748,11 +768,8 @@ impl Validator { state.module.assert_mut().imports.reserve(count as usize); Ok(()) }, - |state, features, types, import, offset| { - state - .module - .assert_mut() - .add_import(import, features, types, offset) + |state, types, import, offset| { + state.module.assert_mut().add_import(import, types, offset) }, ) } @@ -762,10 +779,9 @@ impl Validator { /// This method should only be called when parsing a module. pub fn function_section(&mut self, section: &crate::FunctionSectionReader<'_>) -> Result<()> { self.process_module_section( - Order::Function, section, "function", - |state, _, _, count, offset| { + |state, _, count, offset| { check_max( state.module.functions.len(), count, @@ -774,11 +790,9 @@ impl Validator { offset, )?; state.module.assert_mut().functions.reserve(count as usize); - debug_assert!(state.expected_code_bodies.is_none()); - state.expected_code_bodies = Some(count); Ok(()) }, - |state, _, types, ty, offset| state.module.assert_mut().add_function(ty, types, offset), + |state, types, ty, offset| state.module.assert_mut().add_function(ty, types, offset), ) } @@ -786,23 +800,21 @@ impl Validator { /// /// This method should only be called when parsing a module. pub fn table_section(&mut self, section: &crate::TableSectionReader<'_>) -> Result<()> { - let features = self.features; self.process_module_section( - Order::Table, section, "table", - |state, _, _, count, offset| { + |state, _, count, offset| { check_max( state.module.tables.len(), count, - state.module.max_tables(&features), + state.module.max_tables(), "tables", offset, )?; state.module.assert_mut().tables.reserve(count as usize); Ok(()) }, - |state, features, types, table, offset| state.add_table(table, features, types, offset), + |state, types, table, offset| state.add_table(table, types, offset), ) } @@ -811,23 +823,20 @@ impl Validator { /// This method should only be called when parsing a module. pub fn memory_section(&mut self, section: &crate::MemorySectionReader<'_>) -> Result<()> { self.process_module_section( - Order::Memory, section, "memory", - |state, features, _, count, offset| { + |state, _, count, offset| { check_max( state.module.memories.len(), count, - state.module.max_memories(features), + state.module.max_memories(), "memories", offset, )?; state.module.assert_mut().memories.reserve(count as usize); Ok(()) }, - |state, features, _, ty, offset| { - state.module.assert_mut().add_memory(ty, features, offset) - }, + |state, _, ty, offset| state.module.assert_mut().add_memory(ty, offset), ) } @@ -841,12 +850,10 @@ impl Validator { section.range().start, )); } - self.process_module_section( - Order::Tag, section, "tag", - |state, _, _, count, offset| { + |state, _, count, offset| { check_max( state.module.tags.len(), count, @@ -857,12 +864,7 @@ impl Validator { state.module.assert_mut().tags.reserve(count as usize); Ok(()) }, - |state, features, types, ty, offset| { - state - .module - .assert_mut() - .add_tag(ty, features, types, offset) - }, + |state, types, ty, offset| state.module.assert_mut().add_tag(ty, types, offset), ) } @@ -871,10 +873,9 @@ impl Validator { /// This method should only be called when parsing a module. pub fn global_section(&mut self, section: &crate::GlobalSectionReader<'_>) -> Result<()> { self.process_module_section( - Order::Global, section, "global", - |state, _, _, count, offset| { + |state, _, count, offset| { check_max( state.module.globals.len(), count, @@ -885,9 +886,7 @@ impl Validator { state.module.assert_mut().globals.reserve(count as usize); Ok(()) }, - |state, features, types, global, offset| { - state.add_global(global, features, types, offset) - }, + |state, types, global, offset| state.add_global(global, types, offset), ) } @@ -896,10 +895,9 @@ impl Validator { /// This method should only be called when parsing a module. pub fn export_section(&mut self, section: &crate::ExportSectionReader<'_>) -> Result<()> { self.process_module_section( - Order::Export, section, "export", - |state, _, _, count, offset| { + |state, _, count, offset| { check_max( state.module.exports.len(), count, @@ -910,13 +908,10 @@ impl Validator { state.module.assert_mut().exports.reserve(count as usize); Ok(()) }, - |state, features, types, e, offset| { + |state, types, e, offset| { let state = state.module.assert_mut(); let ty = state.export_to_entity_type(&e, offset)?; - state.add_export( - e.name, ty, features, offset, false, /* checked above */ - types, - ) + state.add_export(e.name, ty, offset, false /* checked above */, types) }, ) } @@ -928,7 +923,6 @@ impl Validator { let offset = range.start; self.state.ensure_module("start", offset)?; let state = self.module.as_mut().unwrap(); - state.update_order(Order::Start, offset)?; let ty = state.module.get_func_type(func, &self.types, offset)?; if !ty.params().is_empty() || !ty.results().is_empty() { @@ -946,10 +940,9 @@ impl Validator { /// This method should only be called when parsing a module. pub fn element_section(&mut self, section: &crate::ElementSectionReader<'_>) -> Result<()> { self.process_module_section( - Order::Element, section, "element", - |state, _, _, count, offset| { + |state, _, count, offset| { check_max( state.module.element_types.len(), count, @@ -964,9 +957,7 @@ impl Validator { .reserve(count as usize); Ok(()) }, - |state, features, types, e, offset| { - state.add_element_segment(e, features, types, offset) - }, + |state, types, e, offset| state.add_element_segment(e, types, offset), ) } @@ -978,7 +969,6 @@ impl Validator { self.state.ensure_module("data count", offset)?; let state = self.module.as_mut().unwrap(); - state.update_order(Order::DataCount, offset)?; if count > MAX_WASM_DATA_SEGMENTS as u32 { return Err(BinaryReaderError::new( @@ -994,31 +984,11 @@ impl Validator { /// Validates [`Payload::CodeSectionStart`](crate::Payload). /// /// This method should only be called when parsing a module. - pub fn code_section_start(&mut self, count: u32, range: &Range<usize>) -> Result<()> { + pub fn code_section_start(&mut self, range: &Range<usize>) -> Result<()> { let offset = range.start; self.state.ensure_module("code", offset)?; let state = self.module.as_mut().unwrap(); - state.update_order(Order::Code, offset)?; - - match state.expected_code_bodies.take() { - Some(n) if n == count => {} - Some(_) => { - return Err(BinaryReaderError::new( - "function and code section have inconsistent lengths", - offset, - )); - } - // empty code sections are allowed even if the function section is - // missing - None if count == 0 => {} - None => { - return Err(BinaryReaderError::new( - "code section without function section", - offset, - )) - } - } // Take a snapshot of the types when we start the code section. state.module.assert_mut().snapshot = Some(Arc::new(self.types.commit())); @@ -1045,10 +1015,18 @@ impl Validator { ) -> Result<FuncToValidate<ValidatorResources>> { let offset = body.range().start; self.state.ensure_module("code", offset)?; + check_max( + 0, + u32::try_from(body.range().len()) + .expect("usize already validated to u32 during section-length decoding"), + MAX_WASM_FUNCTION_SIZE, + "function body size", + offset, + )?; let state = self.module.as_mut().unwrap(); - let (index, ty) = state.next_code_index_and_type(offset)?; + let (index, ty) = state.next_code_index_and_type(); Ok(FuncToValidate { index, ty, @@ -1062,14 +1040,12 @@ impl Validator { /// This method should only be called when parsing a module. pub fn data_section(&mut self, section: &crate::DataSectionReader<'_>) -> Result<()> { self.process_module_section( - Order::Data, section, "data", - |state, _, _, count, offset| { - state.data_segment_count = count; + |_, _, count, offset| { check_max(0, count, MAX_WASM_DATA_SEGMENTS, "data segments", offset) }, - |state, features, types, d, offset| state.add_data_segment(d, features, types, offset), + |state, types, d, offset| state.add_data_segment(d, types, offset), ) } @@ -1117,7 +1093,7 @@ impl Validator { current.core_instances.reserve(count as usize); Ok(()) }, - |components, types, _, instance, offset| { + |components, types, _features, instance, offset| { components .last_mut() .unwrap() @@ -1140,9 +1116,9 @@ impl Validator { current.core_types.reserve(count as usize); Ok(()) }, - |components, types, features, ty, offset| { + |components, types, _features, ty, offset| { ComponentState::add_core_type( - components, ty, features, types, offset, false, /* checked above */ + components, ty, types, offset, false, /* checked above */ ) }, ) @@ -1195,11 +1171,11 @@ impl Validator { current.instances.reserve(count as usize); Ok(()) }, - |components, types, features, instance, offset| { + |components, types, _features, instance, offset| { components .last_mut() .unwrap() - .add_instance(instance, features, types, offset) + .add_instance(instance, types, offset) }, ) } @@ -1216,8 +1192,8 @@ impl Validator { section, "alias", |_, _, _, _| Ok(()), // maximums checked via `add_alias` - |components, types, features, alias, offset| -> Result<(), BinaryReaderError> { - ComponentState::add_alias(components, alias, features, types, offset) + |components, types, _features, alias, offset| -> Result<(), BinaryReaderError> { + ComponentState::add_alias(components, alias, types, offset) }, ) } @@ -1239,9 +1215,9 @@ impl Validator { current.types.reserve(count as usize); Ok(()) }, - |components, types, features, ty, offset| { + |components, types, _features, ty, offset| { ComponentState::add_type( - components, ty, features, types, offset, false, /* checked above */ + components, ty, types, offset, false, /* checked above */ ) }, ) @@ -1270,115 +1246,9 @@ impl Validator { current.funcs.reserve(count as usize); Ok(()) }, - |components, types, features, func, offset| { + |components, types, _features, func, offset| { let current = components.last_mut().unwrap(); - match func { - crate::CanonicalFunction::Lift { - core_func_index, - type_index, - options, - } => current.lift_function( - core_func_index, - type_index, - options.into_vec(), - types, - offset, - features, - ), - crate::CanonicalFunction::Lower { - func_index, - options, - } => current.lower_function( - func_index, - options.into_vec(), - types, - offset, - features, - ), - crate::CanonicalFunction::ResourceNew { resource } => { - current.resource_new(resource, types, offset) - } - crate::CanonicalFunction::ResourceDrop { resource } => { - current.resource_drop(resource, types, offset) - } - crate::CanonicalFunction::ResourceRep { resource } => { - current.resource_rep(resource, types, offset) - } - crate::CanonicalFunction::ThreadSpawn { func_ty_index } => { - current.thread_spawn(func_ty_index, types, offset, features) - } - crate::CanonicalFunction::ThreadHwConcurrency => { - current.thread_hw_concurrency(types, offset, features) - } - crate::CanonicalFunction::TaskBackpressure => { - current.task_backpressure(types, offset, features) - } - crate::CanonicalFunction::TaskReturn { result } => { - current.task_return(&result, types, offset, features) - } - crate::CanonicalFunction::TaskWait { async_, memory } => { - current.task_wait(async_, memory, types, offset, features) - } - crate::CanonicalFunction::TaskPoll { async_, memory } => { - current.task_poll(async_, memory, types, offset, features) - } - crate::CanonicalFunction::TaskYield { async_ } => { - current.task_yield(async_, types, offset, features) - } - crate::CanonicalFunction::SubtaskDrop => { - current.subtask_drop(types, offset, features) - } - crate::CanonicalFunction::StreamNew { ty } => { - current.stream_new(ty, types, offset, features) - } - crate::CanonicalFunction::StreamRead { ty, options } => { - current.stream_read(ty, options.into_vec(), types, offset, features) - } - crate::CanonicalFunction::StreamWrite { ty, options } => { - current.stream_write(ty, options.into_vec(), types, offset, features) - } - crate::CanonicalFunction::StreamCancelRead { ty, async_ } => { - current.stream_cancel_read(ty, async_, types, offset, features) - } - crate::CanonicalFunction::StreamCancelWrite { ty, async_ } => { - current.stream_cancel_write(ty, async_, types, offset, features) - } - crate::CanonicalFunction::StreamCloseReadable { ty } => { - current.stream_close_readable(ty, types, offset, features) - } - crate::CanonicalFunction::StreamCloseWritable { ty } => { - current.stream_close_writable(ty, types, offset, features) - } - crate::CanonicalFunction::FutureNew { ty } => { - current.future_new(ty, types, offset, features) - } - crate::CanonicalFunction::FutureRead { ty, options } => { - current.future_read(ty, options.into_vec(), types, offset, features) - } - crate::CanonicalFunction::FutureWrite { ty, options } => { - current.future_write(ty, options.into_vec(), types, offset, features) - } - crate::CanonicalFunction::FutureCancelRead { ty, async_ } => { - current.future_cancel_read(ty, async_, types, offset, features) - } - crate::CanonicalFunction::FutureCancelWrite { ty, async_ } => { - current.future_cancel_write(ty, async_, types, offset, features) - } - crate::CanonicalFunction::FutureCloseReadable { ty } => { - current.future_close_readable(ty, types, offset, features) - } - crate::CanonicalFunction::FutureCloseWritable { ty } => { - current.future_close_writable(ty, types, offset, features) - } - crate::CanonicalFunction::ErrorContextNew { options } => { - current.error_context_new(options.into_vec(), types, offset, features) - } - crate::CanonicalFunction::ErrorContextDebugMessage { options } => current - .error_context_debug_message(options.into_vec(), types, offset, features), - crate::CanonicalFunction::ErrorContextDrop => { - current.error_context_drop(types, offset, features) - } - } + current.canonical_function(func, types, offset) }, ) } @@ -1398,7 +1268,6 @@ impl Validator { f.func_index, &f.arguments, f.results, - &self.features, &mut self.types, range.start, ) @@ -1416,11 +1285,11 @@ impl Validator { section, "import", |_, _, _, _| Ok(()), // add_import will check limits - |components, types, features, import, offset| { + |components, types, _features, import, offset| { components .last_mut() .unwrap() - .add_import(import, features, types, offset) + .add_import(import, types, offset) }, ) } @@ -1448,13 +1317,12 @@ impl Validator { current.exports.reserve(count as usize); Ok(()) }, - |components, types, features, export, offset| { + |components, types, _features, export, offset| { let current = components.last_mut().unwrap(); - let ty = current.export_to_entity_type(&export, features, types, offset)?; + let ty = current.export_to_entity_type(&export, types, offset)?; current.add_export( export.name, ty, - features, types, offset, false, /* checked above */ @@ -1485,7 +1353,6 @@ impl Validator { )), State::Module => { let mut state = self.module.take().unwrap(); - state.validate_end(offset)?; // If there's a parent component, we'll add a module to the parent state // and continue to validate the component @@ -1516,7 +1383,7 @@ impl Validator { // If there's a parent component, pop the stack, add it to the parent, // and continue to validate the component - let ty = component.finish(&mut self.types, offset)?; + let ty = component.finish(&self.types, offset)?; if let Some(parent) = self.components.last_mut() { parent.add_component(ty, &mut self.types)?; self.state = State::Component; @@ -1533,23 +1400,10 @@ impl Validator { fn process_module_section<'a, T>( &mut self, - order: Order, section: &SectionLimited<'a, T>, name: &str, - validate_section: impl FnOnce( - &mut ModuleState, - &WasmFeatures, - &mut TypeAlloc, - u32, - usize, - ) -> Result<()>, - mut validate_item: impl FnMut( - &mut ModuleState, - &WasmFeatures, - &mut TypeAlloc, - T, - usize, - ) -> Result<()>, + validate_section: impl FnOnce(&mut ModuleState, &mut TypeAlloc, u32, usize) -> Result<()>, + mut validate_item: impl FnMut(&mut ModuleState, &mut TypeAlloc, T, usize) -> Result<()>, ) -> Result<()> where T: FromReader<'a>, @@ -1558,19 +1412,12 @@ impl Validator { self.state.ensure_module(name, offset)?; let state = self.module.as_mut().unwrap(); - state.update_order(order, offset)?; - validate_section( - state, - &self.features, - &mut self.types, - section.count(), - offset, - )?; + validate_section(state, &mut self.types, section.count(), offset)?; for item in section.clone().into_iter_with_offsets() { let (offset, item) = item?; - validate_item(state, &self.features, &mut self.types, item, offset)?; + validate_item(state, &mut self.types, item, offset)?; } Ok(()) @@ -1600,13 +1447,6 @@ impl Validator { { let offset = section.range().start; - if !self.features.component_model() { - return Err(BinaryReaderError::new( - "component model feature is not enabled", - offset, - )); - } - self.state.ensure_component(name, offset)?; validate_section( &mut self.components, @@ -1792,4 +1632,9 @@ mod tests { Ok(()) } + + #[test] + fn reset_fresh_validator() { + Validator::new().reset(); + } } diff --git a/third_party/rust/wasmparser/src/validator/component.rs b/third_party/rust/wasmparser/src/validator/component.rs @@ -7,8 +7,8 @@ use super::{ ComponentCoreModuleTypeId, ComponentCoreTypeId, ComponentDefinedType, ComponentDefinedTypeId, ComponentEntityType, ComponentFuncType, ComponentFuncTypeId, ComponentInstanceType, ComponentInstanceTypeId, ComponentType, ComponentTypeId, - ComponentValType, Context, CoreInstanceTypeKind, InstanceType, LoweringInfo, ModuleType, - RecordType, Remap, Remapping, ResourceId, SubtypeCx, TupleType, VariantCase, VariantType, + ComponentValType, Context, CoreInstanceTypeKind, InstanceType, ModuleType, RecordType, + Remap, Remapping, ResourceId, SubtypeCx, TupleType, VariantCase, VariantType, }, core::{InternRecGroup, Module}, types::{CoreTypeId, EntityType, TypeAlloc, TypeInfo, TypeList}, @@ -18,10 +18,10 @@ use crate::limits::*; use crate::prelude::*; use crate::validator::names::{ComponentName, ComponentNameKind, KebabStr, KebabString}; use crate::{ - BinaryReaderError, CanonicalOption, ComponentExportName, ComponentExternalKind, - ComponentOuterAliasKind, ComponentTypeRef, CompositeInnerType, ExternalKind, FuncType, - GlobalType, InstantiationArgKind, MemoryType, PackedIndex, RefType, Result, SubType, TableType, - TypeBounds, ValType, WasmFeatures, + BinaryReaderError, CanonicalFunction, CanonicalOption, ComponentExportName, + ComponentExternalKind, ComponentOuterAliasKind, ComponentTypeRef, CompositeInnerType, + ExternalKind, FuncType, GlobalType, InstantiationArgKind, MemoryType, PackedIndex, RefType, + Result, SubType, TableType, TypeBounds, ValType, WasmFeatures, }; use core::mem; @@ -42,6 +42,7 @@ pub(crate) struct ComponentState { /// Whether this state is a concrete component, an instance type, or a /// component type. kind: ComponentKind, + features: WasmFeatures, // Core index spaces pub core_types: Vec<ComponentCoreTypeId>, @@ -206,10 +207,235 @@ impl ExternKind { } } +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub(crate) enum StringEncoding { + #[default] + Utf8, + Utf16, + CompactUtf16, +} + +impl core::fmt::Display for StringEncoding { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(match self { + Self::Utf8 => "utf8", + Self::Utf16 => "utf16", + Self::CompactUtf16 => "latin1-utf16", + }) + } +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub(crate) enum Concurrency { + /// Synchronous. + #[default] + Sync, + + /// Asynchronous. + Async { + /// When present, this is the function index of the async callback. When + /// omitted, we are either using stack-switching based asynchrony or are + /// in an operation that does not support the `callback` option (like + /// lowering). + callback: Option<u32>, + }, +} + +impl Concurrency { + pub(crate) fn is_sync(&self) -> bool { + matches!(self, Self::Sync) + } + + pub(crate) fn is_async(&self) -> bool { + !self.is_sync() + } +} + +#[derive(Clone, Copy)] +pub(crate) struct CanonicalOptions { + pub(crate) string_encoding: StringEncoding, + pub(crate) memory: Option<u32>, + pub(crate) realloc: Option<u32>, + pub(crate) post_return: Option<u32>, + pub(crate) concurrency: Concurrency, + pub(crate) core_type: Option<CoreTypeId>, + pub(crate) gc: bool, +} + +impl CanonicalOptions { + pub(crate) fn require_sync(&self, offset: usize, where_: &str) -> Result<&Self> { + if !self.concurrency.is_sync() { + bail!(offset, "cannot specify `async` option on `{where_}`") + } + Ok(self) + } + + pub(crate) fn require_memory(&self, offset: usize) -> Result<&Self> { + if self.memory.is_none() { + bail!(offset, "canonical option `memory` is required"); + } + Ok(self) + } + + pub(crate) fn require_realloc(&self, offset: usize) -> Result<&Self> { + // Memory is always required when `realloc` is required. + self.require_memory(offset)?; + + if self.realloc.is_none() { + bail!(offset, "canonical option `realloc` is required") + } + + Ok(self) + } + + pub(crate) fn require_memory_if( + &self, + offset: usize, + when: impl Fn() -> bool, + ) -> Result<&Self> { + if self.memory.is_none() && when() { + self.require_memory(offset)?; + } + Ok(self) + } + + pub(crate) fn require_realloc_if( + &self, + offset: usize, + when: impl Fn() -> bool, + ) -> Result<&Self> { + if self.realloc.is_none() && when() { + self.require_realloc(offset)?; + } + Ok(self) + } + + pub(crate) fn check_lower(&self, offset: usize) -> Result<&Self> { + if self.post_return.is_some() { + bail!( + offset, + "canonical option `post-return` cannot be specified for lowerings" + ); + } + + if let Concurrency::Async { callback: Some(_) } = self.concurrency { + bail!( + offset, + "canonical option `callback` cannot be specified for lowerings" + ); + } + + if self.gc && self.core_type.is_none() { + bail!( + offset, + "cannot specify `gc` without also specifying a `core-type` for lowerings" + ) + } + + Ok(self) + } + + pub(crate) fn check_lift( + &mut self, + types: &TypeList, + state: &ComponentState, + core_ty_id: CoreTypeId, + offset: usize, + ) -> Result<&Self> { + debug_assert!(matches!( + types[core_ty_id].composite_type.inner, + CompositeInnerType::Func(_) + )); + + if let Some(idx) = self.post_return { + let post_return_func_ty = types[state.core_function_at(idx, offset)?].unwrap_func(); + let core_ty = types[core_ty_id].unwrap_func(); + if post_return_func_ty.params() != core_ty.results() + || !post_return_func_ty.results().is_empty() + { + bail!( + offset, + "canonical option `post-return` uses a core function with an incorrect signature" + ); + } + } + + match self.concurrency { + Concurrency::Sync => {} + + Concurrency::Async { callback: None } if !state.features.cm_async_stackful() => { + bail!( + offset, + "requires the component model async stackful feature" + ) + } + Concurrency::Async { callback: None } => {} + + Concurrency::Async { + callback: Some(idx), + } => { + let func_ty = types[state.core_function_at(idx, offset)?].unwrap_func(); + if func_ty.params() != [ValType::I32; 3] && func_ty.params() != [ValType::I32] { + return Err(BinaryReaderError::new( + "canonical option `callback` uses a core function with an incorrect signature", + offset, + )); + } + } + } + + if self.core_type.is_some() { + bail!( + offset, + "canonical option `core-type` is not allowed in `canon lift`" + ) + } + self.core_type = Some(core_ty_id); + + Ok(self) + } + + pub(crate) fn check_core_type( + &self, + types: &mut TypeAlloc, + actual: FuncType, + offset: usize, + ) -> Result<CoreTypeId> { + if let Some(declared_id) = self.core_type { + let declared = types[declared_id].unwrap_func(); + + if actual.params() != declared.params() { + bail!( + offset, + "declared core type has `{:?}` parameter types, but actual lowering has \ + `{:?}` parameter types", + declared.params(), + actual.params(), + ); + } + + if actual.results() != declared.results() { + bail!( + offset, + "declared core type has `{:?}` result types, but actual lowering has \ + `{:?}` result types", + declared.results(), + actual.results(), + ); + } + + Ok(declared_id) + } else { + Ok(types.intern_func_type(actual, offset)) + } + } +} + impl ComponentState { - pub fn new(kind: ComponentKind) -> Self { + pub fn new(kind: ComponentKind, features: WasmFeatures) -> Self { Self { kind, + features, core_types: Default::default(), core_modules: Default::default(), core_instances: Default::default(), @@ -254,7 +480,6 @@ impl ComponentState { pub fn add_core_type( components: &mut [Self], ty: crate::CoreType, - features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, check_limit: bool, @@ -265,16 +490,10 @@ impl ComponentState { } match ty { crate::CoreType::Rec(rec) => { - current.canonicalize_and_intern_rec_group(features, types, rec, offset)?; + current.canonicalize_and_intern_rec_group(types, rec, offset)?; } crate::CoreType::Module(decls) => { - let mod_ty = Self::create_module_type( - components, - decls.into_vec(), - features, - types, - offset, - )?; + let mod_ty = Self::create_module_type(components, decls.into_vec(), types, offset)?; let id = ComponentCoreTypeId::Module(types.push_ty(mod_ty)); components.last_mut().unwrap().core_types.push(id); } @@ -329,7 +548,6 @@ impl ComponentState { pub fn add_type( components: &mut Vec<Self>, ty: crate::ComponentType, - features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, check_limit: bool, @@ -342,31 +560,19 @@ impl ComponentState { let id = match ty { crate::ComponentType::Defined(ty) => { - let ty = current(components).create_defined_type(ty, types, features, offset)?; + let ty = current(components).create_defined_type(ty, types, offset)?; types.push(ty).into() } crate::ComponentType::Func(ty) => { - let ty = current(components).create_function_type(ty, types, features, offset)?; + let ty = current(components).create_function_type(ty, types, offset)?; types.push(ty).into() } crate::ComponentType::Component(decls) => { - let ty = Self::create_component_type( - components, - decls.into_vec(), - features, - types, - offset, - )?; + let ty = Self::create_component_type(components, decls.into_vec(), types, offset)?; types.push(ty).into() } crate::ComponentType::Instance(decls) => { - let ty = Self::create_instance_type( - components, - decls.into_vec(), - features, - types, - offset, - )?; + let ty = Self::create_instance_type(components, decls.into_vec(), types, offset)?; types.push(ty).into() } crate::ComponentType::Resource { rep, dtor } => { @@ -422,15 +628,13 @@ impl ComponentState { pub fn add_import( &mut self, import: crate::ComponentImport, - features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result<()> { - let mut entity = self.check_type_ref(&import.ty, features, types, offset)?; + let mut entity = self.check_type_ref(&import.ty, types, offset)?; self.add_entity( &mut entity, Some((import.name.0, ExternKind::Import)), - features, types, offset, )?; @@ -443,7 +647,7 @@ impl ComponentState { &mut self.import_names, &mut self.imports, &mut self.type_info, - features, + &self.features, )?; Ok(()) } @@ -452,7 +656,6 @@ impl ComponentState { &mut self, ty: &mut ComponentEntityType, name_and_kind: Option<(&str, ExternKind)>, - features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result<()> { @@ -480,7 +683,7 @@ impl ComponentState { (self.function_count(), MAX_WASM_FUNCTIONS, "functions") } ComponentEntityType::Value(ty) => { - self.check_value_support(features, offset)?; + self.check_value_support(offset)?; let value_used = match kind { Some(ExternKind::Import) | None => false, Some(ExternKind::Export) => true, @@ -721,8 +924,7 @@ impl ComponentState { // named. ComponentDefinedType::Primitive(_) | ComponentDefinedType::Flags(_) - | ComponentDefinedType::Enum(_) - | ComponentDefinedType::ErrorContext => true, + | ComponentDefinedType::Enum(_) => true, // Referenced types of all these aggregates must all be // named. @@ -746,9 +948,9 @@ impl ComponentState { .map(|t| types.type_named_valtype(t, set)) .unwrap_or(true) } - ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => { - types.type_named_valtype(ty, set) - } + ComponentDefinedType::List(ty) + | ComponentDefinedType::FixedSizeList(ty, _) + | ComponentDefinedType::Option(ty) => types.type_named_valtype(ty, set), // The resource referred to by own/borrow must be named. ComponentDefinedType::Own(id) | ComponentDefinedType::Borrow(id) => { @@ -777,7 +979,7 @@ impl ComponentState { ty.params .iter() .map(|(_, ty)| ty) - .chain(ty.results.iter().map(|(_, ty)| ty)) + .chain(&ty.result) .all(|ty| types.type_named_valtype(ty, set)) } @@ -923,7 +1125,6 @@ impl ComponentState { &mut self, name: ComponentExportName<'_>, mut ty: ComponentEntityType, - features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, check_limit: bool, @@ -931,13 +1132,7 @@ impl ComponentState { if check_limit { check_max(self.exports.len(), 1, MAX_WASM_EXPORTS, "exports", offset)?; } - self.add_entity( - &mut ty, - Some((name.0, ExternKind::Export)), - features, - types, - offset, - )?; + self.add_entity(&mut ty, Some((name.0, ExternKind::Export)), types, offset)?; self.toplevel_exported_resources.validate_extern( name.0, ExternKind::Export, @@ -947,151 +1142,262 @@ impl ComponentState { &mut self.export_names, &mut self.exports, &mut self.type_info, - features, + &self.features, )?; Ok(()) } - pub fn lift_function( + pub fn canonical_function( + &mut self, + func: CanonicalFunction, + types: &mut TypeAlloc, + offset: usize, + ) -> Result<()> { + match func { + CanonicalFunction::Lift { + core_func_index, + type_index, + options, + } => self.lift_function(core_func_index, type_index, &options, types, offset), + CanonicalFunction::Lower { + func_index, + options, + } => self.lower_function(func_index, &options, types, offset), + CanonicalFunction::ResourceNew { resource } => { + self.resource_new(resource, types, offset) + } + CanonicalFunction::ResourceDrop { resource } => { + self.resource_drop(resource, types, offset) + } + CanonicalFunction::ResourceDropAsync { resource } => { + self.resource_drop_async(resource, types, offset) + } + CanonicalFunction::ResourceRep { resource } => { + self.resource_rep(resource, types, offset) + } + CanonicalFunction::ThreadSpawnRef { func_ty_index } => { + self.thread_spawn_ref(func_ty_index, types, offset) + } + CanonicalFunction::ThreadSpawnIndirect { + func_ty_index, + table_index, + } => self.thread_spawn_indirect(func_ty_index, table_index, types, offset), + CanonicalFunction::ThreadAvailableParallelism => { + self.thread_available_parallelism(types, offset) + } + CanonicalFunction::BackpressureSet => self.backpressure_set(types, offset), + CanonicalFunction::BackpressureInc => self.backpressure_inc(types, offset), + CanonicalFunction::BackpressureDec => self.backpressure_dec(types, offset), + CanonicalFunction::TaskReturn { result, options } => { + self.task_return(&result, &options, types, offset) + } + CanonicalFunction::TaskCancel => self.task_cancel(types, offset), + CanonicalFunction::ContextGet(i) => self.context_get(i, types, offset), + CanonicalFunction::ContextSet(i) => self.context_set(i, types, offset), + CanonicalFunction::ThreadYield { cancellable } => { + self.thread_yield(cancellable, types, offset) + } + CanonicalFunction::SubtaskDrop => self.subtask_drop(types, offset), + CanonicalFunction::SubtaskCancel { async_ } => { + self.subtask_cancel(async_, types, offset) + } + CanonicalFunction::StreamNew { ty } => self.stream_new(ty, types, offset), + CanonicalFunction::StreamRead { ty, options } => { + self.stream_read(ty, &options, types, offset) + } + CanonicalFunction::StreamWrite { ty, options } => { + self.stream_write(ty, &options, types, offset) + } + CanonicalFunction::StreamCancelRead { ty, async_ } => { + self.stream_cancel_read(ty, async_, types, offset) + } + CanonicalFunction::StreamCancelWrite { ty, async_ } => { + self.stream_cancel_write(ty, async_, types, offset) + } + CanonicalFunction::StreamDropReadable { ty } => { + self.stream_drop_readable(ty, types, offset) + } + CanonicalFunction::StreamDropWritable { ty } => { + self.stream_drop_writable(ty, types, offset) + } + CanonicalFunction::FutureNew { ty } => self.future_new(ty, types, offset), + CanonicalFunction::FutureRead { ty, options } => { + self.future_read(ty, &options, types, offset) + } + CanonicalFunction::FutureWrite { ty, options } => { + self.future_write(ty, options.into_vec(), types, offset) + } + CanonicalFunction::FutureCancelRead { ty, async_ } => { + self.future_cancel_read(ty, async_, types, offset) + } + CanonicalFunction::FutureCancelWrite { ty, async_ } => { + self.future_cancel_write(ty, async_, types, offset) + } + CanonicalFunction::FutureDropReadable { ty } => { + self.future_drop_readable(ty, types, offset) + } + CanonicalFunction::FutureDropWritable { ty } => { + self.future_drop_writable(ty, types, offset) + } + CanonicalFunction::ErrorContextNew { options } => { + self.error_context_new(options.into_vec(), types, offset) + } + CanonicalFunction::ErrorContextDebugMessage { options } => { + self.error_context_debug_message(options.into_vec(), types, offset) + } + CanonicalFunction::ErrorContextDrop => self.error_context_drop(types, offset), + CanonicalFunction::WaitableSetNew => self.waitable_set_new(types, offset), + CanonicalFunction::WaitableSetWait { + cancellable, + memory, + } => self.waitable_set_wait(cancellable, memory, types, offset), + CanonicalFunction::WaitableSetPoll { + cancellable, + memory, + } => self.waitable_set_poll(cancellable, memory, types, offset), + CanonicalFunction::WaitableSetDrop => self.waitable_set_drop(types, offset), + CanonicalFunction::WaitableJoin => self.waitable_join(types, offset), + CanonicalFunction::ThreadIndex => self.thread_index(types, offset), + CanonicalFunction::ThreadNewIndirect { + func_ty_index, + table_index, + } => self.thread_new_indirect(func_ty_index, table_index, types, offset), + CanonicalFunction::ThreadSwitchTo { cancellable } => { + self.thread_switch_to(cancellable, types, offset) + } + CanonicalFunction::ThreadSuspend { cancellable } => { + self.thread_suspend(cancellable, types, offset) + } + CanonicalFunction::ThreadResumeLater => self.thread_resume_later(types, offset), + + CanonicalFunction::ThreadYieldTo { cancellable } => { + self.thread_yield_to(cancellable, types, offset) + } + } + } + + fn lift_function( &mut self, core_func_index: u32, type_index: u32, - options: Vec<CanonicalOption>, - types: &TypeList, + options: &[CanonicalOption], + types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { let ty = self.function_type_at(type_index, types, offset)?; - let core_ty = types[self.core_function_at(core_func_index, offset)?].unwrap_func(); + let core_ty_id = self.core_function_at(core_func_index, offset)?; // Lifting a function is for an export, so match the expected canonical ABI // export signature - let info = ty.lower( - types, - if options.contains(&CanonicalOption::Async) { - if options - .iter() - .any(|v| matches!(v, CanonicalOption::Callback(_))) - { - Abi::LiftAsync - } else { - Abi::LiftAsyncStackful - } - } else { - Abi::LiftSync - }, - ); - self.check_options( - Some(core_ty), - &info, - &options, - types, - offset, - features, - true, - )?; + let mut options = self.check_options(types, options, offset)?; + options.check_lift(types, self, core_ty_id, offset)?; + let func_ty = ty.lower(types, &options, Abi::Lift, offset)?; + let lowered_core_ty_id = func_ty.intern(types, offset); + + if core_ty_id == lowered_core_ty_id { + self.funcs + .push(self.types[type_index as usize].unwrap_func()); + return Ok(()); + } + + let ty = types[core_ty_id].unwrap_func(); + let lowered_ty = types[lowered_core_ty_id].unwrap_func(); - if core_ty.params() != info.params.as_slice() { + if lowered_ty.params() != ty.params() { bail!( offset, - "lowered parameter types `{:?}` do not match parameter types \ - `{:?}` of core function {core_func_index}", - info.params.as_slice(), - core_ty.params(), + "lowered parameter types `{:?}` do not match parameter types `{:?}` of \ + core function {core_func_index}", + lowered_ty.params(), + ty.params() ); } - if core_ty.results() != info.results.as_slice() { + if lowered_ty.results() != ty.results() { bail!( offset, - "lowered result types `{:?}` do not match result types \ - `{:?}` of core function {core_func_index}", - info.results.as_slice(), - core_ty.results() + "lowered result types `{:?}` do not match result types `{:?}` of \ + core function {core_func_index}", + lowered_ty.results(), + ty.results() ); } - self.funcs - .push(self.types[type_index as usize].unwrap_func()); - - Ok(()) + // Otherwise, must be different rec groups or subtyping (which isn't + // supported yet) or something. + bail!( + offset, + "lowered function type `{:?}` does not match type `{:?}` of \ + core function {core_func_index}", + types[lowered_core_ty_id], + types[core_ty_id], + ); } - pub fn lower_function( + fn lower_function( &mut self, func_index: u32, - options: Vec<CanonicalOption>, + options: &[CanonicalOption], types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { let ty = &types[self.function_at(func_index, offset)?]; // Lowering a function is for an import, so use a function type that matches // the expected canonical ABI import signature. - let info = ty.lower( - types, - if options.contains(&CanonicalOption::Async) { - Abi::LowerAsync - } else { - Abi::LowerSync - }, - ); - - self.check_options(None, &info, &options, types, offset, features, true)?; - - let id = types.intern_func_type(info.into_func_type(), offset); - self.core_funcs.push(id); + let options = self.check_options(types, options, offset)?; + options.check_lower(offset)?; + let func_ty = ty.lower(types, &options, Abi::Lower, offset)?; + let ty_id = func_ty.intern(types, offset); + self.core_funcs.push(ty_id); Ok(()) } - pub fn resource_new( - &mut self, - resource: u32, - types: &mut TypeAlloc, - offset: usize, - ) -> Result<()> { + fn resource_new(&mut self, resource: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> { let rep = self.check_local_resource(resource, types, offset)?; let id = types.intern_func_type(FuncType::new([rep], [ValType::I32]), offset); self.core_funcs.push(id); Ok(()) } - pub fn resource_drop( - &mut self, - resource: u32, - types: &mut TypeAlloc, - offset: usize, - ) -> Result<()> { + fn resource_drop(&mut self, resource: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> { self.resource_at(resource, types, offset)?; let id = types.intern_func_type(FuncType::new([ValType::I32], []), offset); self.core_funcs.push(id); Ok(()) } - pub fn resource_rep( + fn resource_drop_async( &mut self, resource: u32, types: &mut TypeAlloc, offset: usize, ) -> Result<()> { + if !self.features.cm_async_builtins() { + bail!( + offset, + "`resource.drop` as `async` requires the component model async builtins feature" + ) + } + self.resource_at(resource, types, offset)?; + let id = types.intern_func_type(FuncType::new([ValType::I32], []), offset); + self.core_funcs.push(id); + Ok(()) + } + + fn resource_rep(&mut self, resource: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> { let rep = self.check_local_resource(resource, types, offset)?; let id = types.intern_func_type(FuncType::new([ValType::I32], [rep]), offset); self.core_funcs.push(id); Ok(()) } - pub fn task_backpressure( - &mut self, - types: &mut TypeAlloc, - offset: usize, - features: &WasmFeatures, - ) -> Result<()> { - if !features.component_model_async() { + fn backpressure_set(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.cm_async() { bail!( offset, - "`task.backpressure` requires the component model async feature" + "`backpressure.set` requires the component model async feature" ) } @@ -1100,21 +1406,48 @@ impl ComponentState { Ok(()) } - pub fn task_return( + fn backpressure_inc(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.cm_async() { + bail!( + offset, + "`backpressure.inc` requires the component model async feature" + ) + } + + self.core_funcs + .push(types.intern_func_type(FuncType::new([], []), offset)); + Ok(()) + } + + fn backpressure_dec(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.cm_async() { + bail!( + offset, + "`backpressure.dec` requires the component model async feature" + ) + } + + self.core_funcs + .push(types.intern_func_type(FuncType::new([], []), offset)); + Ok(()) + } + + fn task_return( &mut self, result: &Option<crate::ComponentValType>, + options: &[CanonicalOption], types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.component_model_async() { + if !self.features.cm_async() { bail!( offset, "`task.return` requires the component model async feature" ) } - let info = ComponentFuncType { + let func_ty = ComponentFuncType { + async_: false, info: TypeInfo::new(), params: result .iter() @@ -1132,87 +1465,113 @@ impl ComponentState { )) }) .collect::<Result<_>>()?, - results: Box::new([]), + result: None, + }; + + let options = self.check_options(types, options, offset)?; + if options.realloc.is_some() { + bail!(offset, "cannot specify `realloc` option on `task.return`") + } + if options.post_return.is_some() { + bail!( + offset, + "cannot specify `post-return` option on `task.return`" + ) } - .lower(types, Abi::LiftSync); + options.check_lower(offset)?; + options.require_sync(offset, "task.return")?; - assert!(info.results.iter().next().is_none()); + let func_ty = func_ty.lower(types, &options, Abi::Lower, offset)?; + let ty_id = func_ty.intern(types, offset); - self.core_funcs - .push(types.intern_func_type(FuncType::new(info.params.iter(), []), offset)); + self.core_funcs.push(ty_id); Ok(()) } - pub fn task_wait( - &mut self, - _async_: bool, - memory: u32, - types: &mut TypeAlloc, - offset: usize, - features: &WasmFeatures, - ) -> Result<()> { - if !features.component_model_async() { + fn task_cancel(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.cm_async() { bail!( offset, - "`task.wait` requires the component model async feature" + "`task.cancel` requires the component model async feature" ) } - self.memory_at(memory, offset)?; - self.core_funcs - .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset)); + .push(types.intern_func_type(FuncType::new([], []), offset)); Ok(()) } - pub fn task_poll( - &mut self, - _async_: bool, - memory: u32, - types: &mut TypeAlloc, + fn validate_context_immediate( + &self, + immediate: u32, + operation: &str, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.component_model_async() { + if !self.features.cm_threading() && immediate > 0 { + bail!(offset, "`{operation}` immediate must be zero: {immediate}") + } else if immediate > 1 { bail!( offset, - "`task.poll` requires the component model async feature" + "`{operation}` immediate must be zero or one: {immediate}" ) } + Ok(()) + } + + fn context_get(&mut self, i: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.cm_async() { + bail!( + offset, + "`context.get` requires the component model async feature" + ) + } + self.validate_context_immediate(i, "context.get", offset)?; - self.memory_at(memory, offset)?; - self.core_funcs - .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset)); + .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset)); Ok(()) } - pub fn task_yield( - &mut self, - _async_: bool, - types: &mut TypeAlloc, - offset: usize, - features: &WasmFeatures, - ) -> Result<()> { - if !features.component_model_async() { + fn context_set(&mut self, i: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.cm_async() { bail!( offset, - "`task.yield` requires the component model async feature" + "`context.set` requires the component model async feature" ) } + self.validate_context_immediate(i, "context.set", offset)?; self.core_funcs - .push(types.intern_func_type(FuncType::new([], []), offset)); + .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset)); Ok(()) } - pub fn subtask_drop( + fn thread_yield( &mut self, + cancellable: bool, types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.component_model_async() { + if !self.features.cm_async() { + bail!( + offset, + "`thread.yield` requires the component model async feature" + ) + } + if cancellable && !self.features.cm_async_stackful() { + bail!( + offset, + "cancellable `thread.yield` requires the component model async stackful feature" + ) + } + + self.core_funcs + .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset)); + Ok(()) + } + + fn subtask_drop(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.cm_async() { bail!( offset, "`subtask.drop` requires the component model async feature" @@ -1224,14 +1583,27 @@ impl ComponentState { Ok(()) } - pub fn stream_new( - &mut self, - ty: u32, - types: &mut TypeAlloc, - offset: usize, - features: &WasmFeatures, - ) -> Result<()> { - if !features.component_model_async() { + fn subtask_cancel(&mut self, async_: bool, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.cm_async() { + bail!( + offset, + "`subtask.cancel` requires the component model async feature" + ) + } + if async_ && !self.features.cm_async_builtins() { + bail!( + offset, + "async `subtask.cancel` requires the component model async builtins feature" + ) + } + + self.core_funcs + .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset)); + Ok(()) + } + + fn stream_new(&mut self, ty: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.cm_async() { bail!( offset, "`stream.new` requires the component model async feature" @@ -1244,19 +1616,18 @@ impl ComponentState { }; self.core_funcs - .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset)); + .push(types.intern_func_type(FuncType::new([], [ValType::I64]), offset)); Ok(()) } - pub fn stream_read( + fn stream_read( &mut self, ty: u32, - options: Vec<CanonicalOption>, + options: &[CanonicalOption], types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.component_model_async() { + if !self.features.cm_async() { bail!( offset, "`stream.read` requires the component model async feature" @@ -1264,31 +1635,33 @@ impl ComponentState { } let ty = self.defined_type_at(ty, offset)?; - let ComponentDefinedType::Stream(payload_type) = &types[ty] else { + let ComponentDefinedType::Stream(elem_ty) = &types[ty] else { bail!(offset, "`stream.read` requires a stream type") }; - let mut info = LoweringInfo::default(); - info.requires_memory = true; - info.requires_realloc = payload_type - .map(|ty| ty.contains_ptr(types)) - .unwrap_or_default(); - self.check_options(None, &info, &options, types, offset, features, true)?; + let ty_id = self + .check_options(types, options, offset)? + .require_memory(offset)? + .require_realloc_if(offset, || elem_ty.is_some_and(|ty| ty.contains_ptr(types)))? + .check_lower(offset)? + .check_core_type( + types, + FuncType::new([ValType::I32; 3], [ValType::I32]), + offset, + )?; - self.core_funcs - .push(types.intern_func_type(FuncType::new([ValType::I32; 3], [ValType::I32]), offset)); + self.core_funcs.push(ty_id); Ok(()) } - pub fn stream_write( + fn stream_write( &mut self, ty: u32, - options: Vec<CanonicalOption>, + options: &[CanonicalOption], types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.component_model_async() { + if !self.features.cm_async() { bail!( offset, "`stream.write` requires the component model async feature" @@ -1300,30 +1673,39 @@ impl ComponentState { bail!(offset, "`stream.write` requires a stream type") }; - let mut info = LoweringInfo::default(); - info.requires_memory = true; - info.requires_realloc = false; - self.check_options(None, &info, &options, types, offset, features, true)?; + let ty_id = self + .check_options(types, options, offset)? + .require_memory(offset)? + .check_lower(offset)? + .check_core_type( + types, + FuncType::new([ValType::I32; 3], [ValType::I32]), + offset, + )?; - self.core_funcs - .push(types.intern_func_type(FuncType::new([ValType::I32; 3], [ValType::I32]), offset)); + self.core_funcs.push(ty_id); Ok(()) } - pub fn stream_cancel_read( + fn stream_cancel_read( &mut self, ty: u32, - _async_: bool, + cancellable: bool, types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.component_model_async() { + if !self.features.cm_async() { bail!( offset, "`stream.cancel-read` requires the component model async feature" ) } + if cancellable && !self.features.cm_async_builtins() { + bail!( + offset, + "async `stream.cancel-read` requires the component model async builtins feature" + ) + } let ty = self.defined_type_at(ty, offset)?; let ComponentDefinedType::Stream(_) = &types[ty] else { @@ -1335,20 +1717,25 @@ impl ComponentState { Ok(()) } - pub fn stream_cancel_write( + fn stream_cancel_write( &mut self, ty: u32, - _async_: bool, + cancellable: bool, types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.component_model_async() { + if !self.features.cm_async() { bail!( offset, "`stream.cancel-write` requires the component model async feature" ) } + if cancellable && !self.features.cm_async_builtins() { + bail!( + offset, + "async `stream.cancel-write` requires the component model async builtins feature" + ) + } let ty = self.defined_type_at(ty, offset)?; let ComponentDefinedType::Stream(_) = &types[ty] else { @@ -1360,23 +1747,22 @@ impl ComponentState { Ok(()) } - pub fn stream_close_readable( + fn stream_drop_readable( &mut self, ty: u32, types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.component_model_async() { + if !self.features.cm_async() { bail!( offset, - "`stream.close-readable` requires the component model async feature" + "`stream.drop-readable` requires the component model async feature" ) } let ty = self.defined_type_at(ty, offset)?; let ComponentDefinedType::Stream(_) = &types[ty] else { - bail!(offset, "`stream.close-readable` requires a stream type") + bail!(offset, "`stream.drop-readable` requires a stream type") }; self.core_funcs @@ -1384,38 +1770,31 @@ impl ComponentState { Ok(()) } - pub fn stream_close_writable( + fn stream_drop_writable( &mut self, ty: u32, types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.component_model_async() { + if !self.features.cm_async() { bail!( offset, - "`stream.close-writable` requires the component model async feature" + "`stream.drop-writable` requires the component model async feature" ) } let ty = self.defined_type_at(ty, offset)?; let ComponentDefinedType::Stream(_) = &types[ty] else { - bail!(offset, "`stream.close-writable` requires a stream type") + bail!(offset, "`stream.drop-writable` requires a stream type") }; self.core_funcs - .push(types.intern_func_type(FuncType::new([ValType::I32; 2], []), offset)); + .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset)); Ok(()) } - pub fn future_new( - &mut self, - ty: u32, - types: &mut TypeAlloc, - offset: usize, - features: &WasmFeatures, - ) -> Result<()> { - if !features.component_model_async() { + fn future_new(&mut self, ty: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.cm_async() { bail!( offset, "`future.new` requires the component model async feature" @@ -1428,19 +1807,18 @@ impl ComponentState { }; self.core_funcs - .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset)); + .push(types.intern_func_type(FuncType::new([], [ValType::I64]), offset)); Ok(()) } - pub fn future_read( + fn future_read( &mut self, ty: u32, - options: Vec<CanonicalOption>, + options: &[CanonicalOption], types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.component_model_async() { + if !self.features.cm_async() { bail!( offset, "`future.read` requires the component model async feature" @@ -1448,31 +1826,33 @@ impl ComponentState { } let ty = self.defined_type_at(ty, offset)?; - let ComponentDefinedType::Future(payload_type) = &types[ty] else { + let ComponentDefinedType::Future(elem_ty) = &types[ty] else { bail!(offset, "`future.read` requires a future type") }; - let mut info = LoweringInfo::default(); - info.requires_memory = true; - info.requires_realloc = payload_type - .map(|ty| ty.contains_ptr(types)) - .unwrap_or_default(); - self.check_options(None, &info, &options, types, offset, features, true)?; + let ty_id = self + .check_options(types, options, offset)? + .require_memory_if(offset, || elem_ty.is_some())? + .require_realloc_if(offset, || elem_ty.is_some_and(|ty| ty.contains_ptr(types)))? + .check_lower(offset)? + .check_core_type( + types, + FuncType::new([ValType::I32; 2], [ValType::I32]), + offset, + )?; - self.core_funcs - .push(types.intern_func_type(FuncType::new([ValType::I32; 2], [ValType::I32]), offset)); + self.core_funcs.push(ty_id); Ok(()) } - pub fn future_write( + fn future_write( &mut self, ty: u32, options: Vec<CanonicalOption>, types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.component_model_async() { + if !self.features.cm_async() { bail!( offset, "`future.write` requires the component model async feature" @@ -1480,34 +1860,42 @@ impl ComponentState { } let ty = self.defined_type_at(ty, offset)?; - let ComponentDefinedType::Future(_) = &types[ty] else { + let ComponentDefinedType::Future(elem_ty) = &types[ty] else { bail!(offset, "`future.write` requires a future type") }; - let mut info = LoweringInfo::default(); - info.requires_memory = true; - info.requires_realloc = false; - self.check_options(None, &info, &options, types, offset, features, true)?; + let ty_id = self + .check_options(types, &options, offset)? + .require_memory_if(offset, || elem_ty.is_some())? + .check_core_type( + types, + FuncType::new([ValType::I32; 2], [ValType::I32]), + offset, + )?; - self.core_funcs - .push(types.intern_func_type(FuncType::new([ValType::I32; 2], [ValType::I32]), offset)); + self.core_funcs.push(ty_id); Ok(()) } - pub fn future_cancel_read( + fn future_cancel_read( &mut self, ty: u32, - _async_: bool, + cancellable: bool, types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.component_model_async() { + if !self.features.cm_async() { bail!( offset, "`future.cancel-read` requires the component model async feature" ) } + if cancellable && !self.features.cm_async_builtins() { + bail!( + offset, + "async `future.cancel-read` requires the component model async builtins feature" + ) + } let ty = self.defined_type_at(ty, offset)?; let ComponentDefinedType::Future(_) = &types[ty] else { @@ -1519,20 +1907,25 @@ impl ComponentState { Ok(()) } - pub fn future_cancel_write( + fn future_cancel_write( &mut self, ty: u32, - _async_: bool, + cancellable: bool, types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.component_model_async() { + if !self.features.cm_async() { bail!( offset, "`future.cancel-write` requires the component model async feature" ) } + if cancellable && !self.features.cm_async_builtins() { + bail!( + offset, + "async `future.cancel-write` requires the component model async builtins feature" + ) + } let ty = self.defined_type_at(ty, offset)?; let ComponentDefinedType::Future(_) = &types[ty] else { @@ -1544,23 +1937,22 @@ impl ComponentState { Ok(()) } - pub fn future_close_readable( + fn future_drop_readable( &mut self, ty: u32, types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.component_model_async() { + if !self.features.cm_async() { bail!( offset, - "`future.close-readable` requires the component model async feature" + "`future.drop-readable` requires the component model async feature" ) } let ty = self.defined_type_at(ty, offset)?; let ComponentDefinedType::Future(_) = &types[ty] else { - bail!(offset, "`future.close-readable` requires a future type") + bail!(offset, "`future.drop-readable` requires a future type") }; self.core_funcs @@ -1568,93 +1960,321 @@ impl ComponentState { Ok(()) } - pub fn future_close_writable( + fn future_drop_writable( &mut self, ty: u32, types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.component_model_async() { + if !self.features.cm_async() { bail!( offset, - "`future.close-writable` requires the component model async feature" + "`future.drop-writable` requires the component model async feature" ) } let ty = self.defined_type_at(ty, offset)?; let ComponentDefinedType::Future(_) = &types[ty] else { - bail!(offset, "`future.close-writable` requires a future type") + bail!(offset, "`future.drop-writable` requires a future type") }; self.core_funcs - .push(types.intern_func_type(FuncType::new([ValType::I32; 2], []), offset)); + .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset)); Ok(()) } - pub fn error_context_new( + fn error_context_new( &mut self, options: Vec<CanonicalOption>, types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.component_model_async() { + if !self.features.cm_error_context() { + bail!( + offset, + "`error-context.new` requires the component model error-context feature" + ) + } + + let ty_id = self + .check_options(types, &options, offset)? + .require_memory(offset)? + .require_sync(offset, "error-context.new")? + .check_lower(offset)? + .check_core_type( + types, + FuncType::new([ValType::I32; 2], [ValType::I32]), + offset, + )?; + + self.core_funcs.push(ty_id); + Ok(()) + } + + fn error_context_debug_message( + &mut self, + options: Vec<CanonicalOption>, + types: &mut TypeAlloc, + offset: usize, + ) -> Result<()> { + if !self.features.cm_error_context() { + bail!( + offset, + "`error-context.debug-message` requires the component model error-context feature" + ) + } + + let ty_id = self + .check_options(types, &options, offset)? + .require_memory(offset)? + .require_realloc(offset)? + .require_sync(offset, "error-context.debug-message")? + .check_lower(offset)? + .check_core_type(types, FuncType::new([ValType::I32; 2], []), offset)?; + + self.core_funcs.push(ty_id); + Ok(()) + } + + fn error_context_drop(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.cm_error_context() { + bail!( + offset, + "`error-context.drop` requires the component model error-context feature" + ) + } + + self.core_funcs + .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset)); + Ok(()) + } + + fn waitable_set_new(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.cm_async() { + bail!( + offset, + "`waitable-set.new` requires the component model async feature" + ) + } + + self.core_funcs + .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset)); + Ok(()) + } + + fn waitable_set_wait( + &mut self, + cancellable: bool, + memory: u32, + types: &mut TypeAlloc, + offset: usize, + ) -> Result<()> { + if !self.features.cm_async() { + bail!( + offset, + "`waitable-set.wait` requires the component model async feature" + ) + } + if cancellable && !self.features.cm_async_stackful() { + bail!( + offset, + "cancellable `waitable-set.wait` requires the component model async stackful feature" + ) + } + + self.cabi_memory_at(memory, offset)?; + + self.core_funcs + .push(types.intern_func_type(FuncType::new([ValType::I32; 2], [ValType::I32]), offset)); + Ok(()) + } + + fn waitable_set_poll( + &mut self, + cancellable: bool, + memory: u32, + types: &mut TypeAlloc, + offset: usize, + ) -> Result<()> { + if !self.features.cm_async() { + bail!( + offset, + "`waitable-set.poll` requires the component model async feature" + ) + } + if cancellable && !self.features.cm_async_stackful() { + bail!( + offset, + "cancellable `waitable-set.poll` requires the component model async stackful feature" + ) + } + + self.cabi_memory_at(memory, offset)?; + + self.core_funcs + .push(types.intern_func_type(FuncType::new([ValType::I32; 2], [ValType::I32]), offset)); + Ok(()) + } + + fn waitable_set_drop(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.cm_async() { + bail!( + offset, + "`waitable-set.drop` requires the component model async feature" + ) + } + + self.core_funcs + .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset)); + Ok(()) + } + + fn waitable_join(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.cm_async() { + bail!( + offset, + "`waitable.join` requires the component model async feature" + ) + } + + self.core_funcs + .push(types.intern_func_type(FuncType::new([ValType::I32; 2], []), offset)); + Ok(()) + } + + fn thread_index(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.cm_threading() { + bail!( + offset, + "`thread.index` requires the component model threading feature" + ) + } + + self.core_funcs + .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset)); + Ok(()) + } + + fn thread_new_indirect( + &mut self, + func_ty_index: u32, + table_index: u32, + types: &mut TypeAlloc, + offset: usize, + ) -> Result<()> { + if !self.features.cm_threading() { + bail!( + offset, + "`thread.new-indirect` requires the component model threading feature" + ) + } + + let core_type_id = match self.core_type_at(func_ty_index, offset)? { + ComponentCoreTypeId::Sub(c) => c, + ComponentCoreTypeId::Module(_) => bail!(offset, "expected a core function type"), + }; + let sub_ty = &types[core_type_id]; + match &sub_ty.composite_type.inner { + CompositeInnerType::Func(func_ty) => { + if func_ty.params() != [ValType::I32] { + bail!( + offset, + "start function must take a single `i32` argument (currently)" + ); + } + if func_ty.results() != [] { + bail!(offset, "start function must not return any values"); + } + } + _ => bail!(offset, "start type must be a function"), + } + + let table = self.table_at(table_index, offset)?; + + SubtypeCx::table_type( + table, + &TableType { + initial: 0, + maximum: None, + table64: false, + shared: false, + element_type: RefType::FUNCREF, + }, + offset, + ) + .map_err(|mut e| { + e.add_context("table is not a 32-bit table of (ref null (func))".into()); + e + })?; + + self.core_funcs.push(types.intern_func_type( + FuncType::new([ValType::I32, ValType::I32], [ValType::I32]), + offset, + )); + Ok(()) + } + + fn thread_switch_to( + &mut self, + _cancellable: bool, + types: &mut TypeAlloc, + offset: usize, + ) -> Result<()> { + if !self.features.cm_threading() { bail!( offset, - "`error-context.new` requires the component model async feature" + "`thread.switch_to` requires the component model threading feature" ) } - let mut info = LoweringInfo::default(); - info.requires_memory = true; - info.requires_realloc = false; - self.check_options(None, &info, &options, types, offset, features, false)?; - self.core_funcs - .push(types.intern_func_type(FuncType::new([ValType::I32; 2], [ValType::I32]), offset)); + .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset)); Ok(()) } - pub fn error_context_debug_message( + fn thread_suspend( &mut self, - options: Vec<CanonicalOption>, + _cancellable: bool, types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.component_model_async() { + if !self.features.cm_threading() { bail!( offset, - "`error-context.debug-message` requires the component model async feature" + "`thread.suspend` requires the component model threading feature" ) } + self.core_funcs + .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset)); + Ok(()) + } - let mut info = LoweringInfo::default(); - info.requires_memory = true; - info.requires_realloc = true; - self.check_options(None, &info, &options, types, offset, features, false)?; - + fn thread_resume_later(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.cm_threading() { + bail!( + offset, + "`thread.resume_later` requires the component model threading feature" + ) + } self.core_funcs - .push(types.intern_func_type(FuncType::new([ValType::I32; 2], []), offset)); + .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset)); Ok(()) } - pub fn error_context_drop( + fn thread_yield_to( &mut self, + _cancellable: bool, types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.component_model_async() { + if !self.features.cm_threading() { bail!( offset, - "`error-context.drop` requires the component model async feature" + "`thread.yield_to` requires the component model threading feature" ) } - self.core_funcs - .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset)); + .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset)); Ok(()) } @@ -1682,21 +2302,94 @@ impl ComponentState { bail!(offset, "type index {} is not a resource type", idx) } - pub fn thread_spawn( + fn thread_spawn_ref( &mut self, func_ty_index: u32, types: &mut TypeAlloc, offset: usize, - features: &WasmFeatures, ) -> Result<()> { - if !features.shared_everything_threads() { + if !self.features.shared_everything_threads() { + bail!( + offset, + "`thread.spawn-ref` requires the shared-everything-threads proposal" + ) + } + let core_type_id = self.validate_spawn_type(func_ty_index, types, offset)?; + + // Insert the core function. + let packed_index = PackedIndex::from_id(core_type_id).ok_or_else(|| { + format_err!(offset, "implementation limit: too many types in `TypeList`") + })?; + let start_func_ref = RefType::concrete(true, packed_index); + let func_ty = FuncType::new([ValType::Ref(start_func_ref), ValType::I32], [ValType::I32]); + let core_ty = SubType::func(func_ty, true); + let id = types.intern_sub_type(core_ty, offset); + self.core_funcs.push(id); + + Ok(()) + } + + fn thread_spawn_indirect( + &mut self, + func_ty_index: u32, + table_index: u32, + types: &mut TypeAlloc, + offset: usize, + ) -> Result<()> { + if !self.features.shared_everything_threads() { bail!( offset, - "`thread.spawn` requires the shared-everything-threads proposal" + "`thread.spawn-indirect` requires the shared-everything-threads proposal" ) } + let _ = self.validate_spawn_type(func_ty_index, types, offset)?; + + // Check this much like `call_indirect` (see + // `OperatorValidatorTemp::check_call_indirect_ty`), but loosen the + // table type restrictions to just a `funcref`. See the component model + // for more details: + // https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#-canon-threadspawn-indirect. + let table = self.table_at(table_index, offset)?; + + SubtypeCx::table_type( + table, + &TableType { + initial: 0, + maximum: None, + table64: false, + shared: true, + element_type: RefType::FUNCREF + .shared() + .expect("a funcref can always be shared"), + }, + offset, + ) + .map_err(|mut e| { + e.add_context("table is not a 32-bit shared table of (ref null (shared func))".into()); + e + })?; + + // Insert the core function. + let func_ty = FuncType::new([ValType::I32, ValType::I32], [ValType::I32]); + let core_ty = SubType::func(func_ty, true); + let id = types.intern_sub_type(core_ty, offset); + self.core_funcs.push(id); - // Validate the type accepted by `thread.spawn`. + Ok(()) + } + + /// Validates the type of a `thread.spawn*` instruction. + /// + /// This is currently limited to shared functions with the signature `[i32] + /// -> []`. See component model [explanation] for more details. + /// + /// [explanation]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#-canon-threadspawn-ref + fn validate_spawn_type( + &self, + func_ty_index: u32, + types: &TypeAlloc, + offset: usize, + ) -> Result<CoreTypeId> { let core_type_id = match self.core_type_at(func_ty_index, offset)? { ComponentCoreTypeId::Sub(c) => c, ComponentCoreTypeId::Module(_) => bail!(offset, "expected a core function type"), @@ -1719,30 +2412,14 @@ impl ComponentState { } _ => bail!(offset, "spawn type must be a function"), } - - // Insert the core function. - let packed_index = PackedIndex::from_id(core_type_id).ok_or_else(|| { - format_err!(offset, "implementation limit: too many types in `TypeList`") - })?; - let start_func_ref = RefType::concrete(true, packed_index); - let func_ty = FuncType::new([ValType::Ref(start_func_ref), ValType::I32], [ValType::I32]); - let core_ty = SubType::func(func_ty, true); - let id = types.intern_sub_type(core_ty, offset); - self.core_funcs.push(id); - - Ok(()) + Ok(core_type_id) } - pub fn thread_hw_concurrency( - &mut self, - types: &mut TypeAlloc, - offset: usize, - features: &WasmFeatures, - ) -> Result<()> { - if !features.shared_everything_threads() { + fn thread_available_parallelism(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.shared_everything_threads() { bail!( offset, - "`thread.hw_concurrency` requires the shared-everything-threads proposal" + "`thread.available_parallelism` requires the shared-everything-threads proposal" ) } @@ -1763,7 +2440,6 @@ impl ComponentState { pub fn add_instance( &mut self, instance: crate::ComponentInstance, - features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result<()> { @@ -1771,15 +2447,9 @@ impl ComponentState { crate::ComponentInstance::Instantiate { component_index, args, - } => self.instantiate_component( - component_index, - args.into_vec(), - features, - types, - offset, - )?, + } => self.instantiate_component(component_index, args.into_vec(), types, offset)?, crate::ComponentInstance::FromExports(exports) => { - self.instantiate_component_exports(exports.into_vec(), features, types, offset)? + self.instantiate_component_exports(exports.into_vec(), types, offset)? } }; @@ -1791,7 +2461,6 @@ impl ComponentState { pub fn add_alias( components: &mut [Self], alias: crate::ComponentAlias, - features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result<()> { @@ -1804,7 +2473,6 @@ impl ComponentState { instance_index, kind, name, - features, types, offset, ), @@ -1841,11 +2509,10 @@ impl ComponentState { func_index: u32, args: &[u32], results: u32, - features: &WasmFeatures, types: &mut TypeList, offset: usize, ) -> Result<()> { - if !features.component_model_values() { + if !self.features.cm_values() { bail!( offset, "support for component model `value`s is not enabled" @@ -1869,12 +2536,12 @@ impl ComponentState { ); } - if ft.results.len() as u32 != results { + if u32::from(ft.result.is_some()) != results { bail!( offset, "component start function has a result count of {results} \ but the function type has a result count of {type_results}", - type_results = ft.results.len(), + type_results = u32::from(ft.result.is_some()), ); } @@ -1887,8 +2554,8 @@ impl ComponentState { })?; } - for (_, ty) in ft.results.iter() { - self.values.push((*ty, false)); + if let Some(ty) = ft.result { + self.values.push((ty, false)); } self.has_start = true; @@ -1898,14 +2565,10 @@ impl ComponentState { fn check_options( &self, - core_ty: Option<&FuncType>, - info: &LoweringInfo, - options: &[CanonicalOption], types: &TypeList, + options: &[CanonicalOption], offset: usize, - features: &WasmFeatures, - allow_async: bool, - ) -> Result<()> { + ) -> Result<CanonicalOptions> { fn display(option: CanonicalOption) -> &'static str { match option { CanonicalOption::UTF8 => "utf8", @@ -1916,6 +2579,8 @@ impl ComponentState { CanonicalOption::PostReturn(_) => "post-return", CanonicalOption::Async => "async", CanonicalOption::Callback(_) => "callback", + CanonicalOption::CoreType(_) => "core-type", + CanonicalOption::Gc => "gc", } } @@ -1923,8 +2588,10 @@ impl ComponentState { let mut memory = None; let mut realloc = None; let mut post_return = None; - let mut async_ = false; + let mut is_async = false; let mut callback = None; + let mut core_type = None; + let mut gc = false; for option in options { match option { @@ -1933,35 +2600,42 @@ impl ComponentState { Some(existing) => { bail!( offset, - "canonical encoding option `{}` conflicts with option `{}`", - display(existing), + "canonical encoding option `{existing}` conflicts with option `{}`", display(*option), ) } - None => encoding = Some(*option), + None => { + encoding = Some(match option { + CanonicalOption::UTF8 => StringEncoding::Utf8, + CanonicalOption::UTF16 => StringEncoding::Utf16, + CanonicalOption::CompactUTF16 => StringEncoding::CompactUtf16, + _ => unreachable!(), + }); + } } } CanonicalOption::Memory(idx) => { memory = match memory { None => { - self.memory_at(*idx, offset)?; + self.cabi_memory_at(*idx, offset)?; Some(*idx) } Some(_) => { return Err(BinaryReaderError::new( "canonical option `memory` is specified more than once", offset, - )) + )); } } } CanonicalOption::Realloc(idx) => { realloc = match realloc { None => { - let ty = types[self.core_function_at(*idx, offset)?].unwrap_func(); - if ty.params() + let ty_id = self.core_function_at(*idx, offset)?; + let func_ty = types[ty_id].unwrap_func(); + if func_ty.params() != [ValType::I32, ValType::I32, ValType::I32, ValType::I32] - || ty.results() != [ValType::I32] + || func_ty.results() != [ValType::I32] { return Err(BinaryReaderError::new( "canonical option `realloc` uses a core function with an incorrect signature", @@ -1974,122 +2648,139 @@ impl ComponentState { return Err(BinaryReaderError::new( "canonical option `realloc` is specified more than once", offset, - )) + )); } } } CanonicalOption::PostReturn(idx) => { post_return = match post_return { - None => { - let core_ty = core_ty.ok_or_else(|| { - BinaryReaderError::new( - "canonical option `post-return` cannot be specified for lowerings", - offset, - ) - })?; - - let ty = types[self.core_function_at(*idx, offset)?].unwrap_func(); - - if ty.params() != core_ty.results() || !ty.results().is_empty() { - return Err(BinaryReaderError::new( - "canonical option `post-return` uses a core function with an incorrect signature", - offset, - )); - } - Some(*idx) - } + None => Some(*idx), Some(_) => { return Err(BinaryReaderError::new( "canonical option `post-return` is specified more than once", offset, - )) + )); } } } CanonicalOption::Async => { - if async_ { + if is_async { return Err(BinaryReaderError::new( "canonical option `async` is specified more than once", offset, )); } else { - if !features.component_model_async() { + if !self.features.cm_async() { bail!( offset, "canonical option `async` requires the component model async feature" ); } - async_ = true; + is_async = true; } } CanonicalOption::Callback(idx) => { callback = match callback { + None => Some(*idx), + Some(_) => { + return Err(BinaryReaderError::new( + "canonical option `callback` is specified more than once", + offset, + )); + } + } + } + CanonicalOption::CoreType(idx) => { + core_type = match core_type { None => { - if core_ty.is_none() { - return Err(BinaryReaderError::new( - "canonical option `callback` cannot be specified for lowerings", + if !self.features.cm_gc() { + bail!( offset, - )); + "canonical option `core type` requires the component model gc feature" + ) } - - let ty = types[self.core_function_at(*idx, offset)?].unwrap_func(); - - if ty.params() != [ValType::I32; 4] && ty.params() != [ValType::I32] { - return Err(BinaryReaderError::new( - "canonical option `callback` uses a core function with an incorrect signature", - offset, - )); + let ty = match self.core_type_at(*idx, offset)? { + ComponentCoreTypeId::Sub(ty) => ty, + ComponentCoreTypeId::Module(_) => { + return Err(BinaryReaderError::new( + "canonical option `core type` must reference a core function \ + type", + offset, + )); + } + }; + match &types[ty].composite_type.inner { + CompositeInnerType::Func(_) => {} + CompositeInnerType::Array(_) + | CompositeInnerType::Struct(_) + | CompositeInnerType::Cont(_) => { + return Err(BinaryReaderError::new( + "canonical option `core type` must reference a core function \ + type", + offset, + )); + } } - Some(*idx) + Some(ty) } Some(_) => { return Err(BinaryReaderError::new( - "canonical option `callback` is specified more than once", + "canonical option `core type` is specified more than once", offset, - )) + )); } + }; + } + CanonicalOption::Gc => { + if gc { + return Err(BinaryReaderError::new( + "canonical option `gc` is specified more than once", + offset, + )); + } + if !self.features.cm_gc() { + return Err(BinaryReaderError::new( + "canonical option `gc` requires the `cm-gc` feature", + offset, + )); } + gc = true; } } } - if async_ && !allow_async { - bail!(offset, "async option not allowed here") - } - - if callback.is_some() && !async_ { - bail!(offset, "cannot specify callback without lifting async") - } - - if post_return.is_some() && async_ { - bail!( - offset, - "cannot specify post-return function when lifting async" - ) - } + let string_encoding = encoding.unwrap_or_default(); - if info.requires_memory && memory.is_none() { - return Err(BinaryReaderError::new( - "canonical option `memory` is required", - offset, - )); - } + let concurrency = match (is_async, callback, post_return.is_some()) { + (false, Some(_), _) => { + bail!(offset, "cannot specify callback without async") + } + (true, _, true) => { + bail!(offset, "cannot specify post-return function in async") + } + (false, None, _) => Concurrency::Sync, + (true, callback, false) => Concurrency::Async { callback }, + }; - if info.requires_realloc && realloc.is_none() { - return Err(BinaryReaderError::new( - "canonical option `realloc` is required", - offset, - )); + if !gc && core_type.is_some() { + bail!(offset, "cannot specify `core-type` without `gc`") } - Ok(()) + Ok(CanonicalOptions { + string_encoding, + memory, + realloc, + post_return, + concurrency, + core_type, + gc, + }) } fn check_type_ref( &mut self, ty: &ComponentTypeRef, - features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result<ComponentEntityType> { @@ -2111,7 +2802,7 @@ impl ComponentState { } } ComponentTypeRef::Value(ty) => { - self.check_value_support(features, offset)?; + self.check_value_support(offset)?; let ty = match ty { crate::ComponentValType::Primitive(ty) => ComponentValType::Primitive(*ty), crate::ComponentValType::Type(index) => { @@ -2155,7 +2846,6 @@ impl ComponentState { pub fn export_to_entity_type( &mut self, export: &crate::ComponentExport, - features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result<ComponentEntityType> { @@ -2167,7 +2857,7 @@ impl ComponentState { ComponentEntityType::Func(self.function_at(export.index, offset)?) } ComponentExternalKind::Value => { - self.check_value_support(features, offset)?; + self.check_value_support(offset)?; ComponentEntityType::Value(*self.value_at(export.index, offset)?) } ComponentExternalKind::Type => { @@ -2187,7 +2877,7 @@ impl ComponentState { }; let ascribed = match &export.ty { - Some(ty) => self.check_type_ref(ty, features, types, offset)?, + Some(ty) => self.check_type_ref(ty, types, offset)?, None => return Ok(actual), }; @@ -2201,20 +2891,19 @@ impl ComponentState { fn create_module_type( components: &[Self], decls: Vec<crate::ModuleTypeDeclaration>, - features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result<ModuleType> { - let mut state = Module::default(); + let mut state = Module::new(components[0].features); for decl in decls { match decl { crate::ModuleTypeDeclaration::Type(rec) => { - state.add_types(rec, features, types, offset, true)?; + state.add_types(rec, types, offset, true)?; } crate::ModuleTypeDeclaration::Export { name, mut ty } => { - let ty = state.check_type_ref(&mut ty, features, types, offset)?; - state.add_export(name, ty, features, offset, true, types)?; + let ty = state.check_type_ref(&mut ty, types, offset)?; + state.add_export(name, ty, offset, true, types)?; } crate::ModuleTypeDeclaration::OuterAlias { kind, count, index } => { match kind { @@ -2244,7 +2933,7 @@ impl ComponentState { } } crate::ModuleTypeDeclaration::Import(import) => { - state.add_import(import, features, types, offset)?; + state.add_import(import, types, offset)?; } } } @@ -2261,33 +2950,33 @@ impl ComponentState { fn create_component_type( components: &mut Vec<Self>, decls: Vec<crate::ComponentTypeDeclaration>, - features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result<ComponentType> { - components.push(ComponentState::new(ComponentKind::ComponentType)); + let features = components[0].features; + components.push(ComponentState::new(ComponentKind::ComponentType, features)); for decl in decls { match decl { crate::ComponentTypeDeclaration::CoreType(ty) => { - Self::add_core_type(components, ty, features, types, offset, true)?; + Self::add_core_type(components, ty, types, offset, true)?; } crate::ComponentTypeDeclaration::Type(ty) => { - Self::add_type(components, ty, features, types, offset, true)?; + Self::add_type(components, ty, types, offset, true)?; } crate::ComponentTypeDeclaration::Export { name, ty } => { let current = components.last_mut().unwrap(); - let ty = current.check_type_ref(&ty, features, types, offset)?; - current.add_export(name, ty, features, types, offset, true)?; + let ty = current.check_type_ref(&ty, types, offset)?; + current.add_export(name, ty, types, offset, true)?; } crate::ComponentTypeDeclaration::Import(import) => { components .last_mut() .unwrap() - .add_import(import, features, types, offset)?; + .add_import(import, types, offset)?; } crate::ComponentTypeDeclaration::Alias(alias) => { - Self::add_alias(components, alias, features, types, offset)?; + Self::add_alias(components, alias, types, offset)?; } }; } @@ -2298,27 +2987,27 @@ impl ComponentState { fn create_instance_type( components: &mut Vec<Self>, decls: Vec<crate::InstanceTypeDeclaration>, - features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result<ComponentInstanceType> { - components.push(ComponentState::new(ComponentKind::InstanceType)); + let features = components[0].features; + components.push(ComponentState::new(ComponentKind::InstanceType, features)); for decl in decls { match decl { crate::InstanceTypeDeclaration::CoreType(ty) => { - Self::add_core_type(components, ty, features, types, offset, true)?; + Self::add_core_type(components, ty, types, offset, true)?; } crate::InstanceTypeDeclaration::Type(ty) => { - Self::add_type(components, ty, features, types, offset, true)?; + Self::add_type(components, ty, types, offset, true)?; } crate::InstanceTypeDeclaration::Export { name, ty } => { let current = components.last_mut().unwrap(); - let ty = current.check_type_ref(&ty, features, types, offset)?; - current.add_export(name, ty, features, types, offset, true)?; + let ty = current.check_type_ref(&ty, types, offset)?; + current.add_export(name, ty, types, offset, true)?; } crate::InstanceTypeDeclaration::Alias(alias) => { - Self::add_alias(components, alias, features, types, offset)?; + Self::add_alias(components, alias, types, offset)?; } }; } @@ -2359,21 +3048,22 @@ impl ComponentState { &self, ty: crate::ComponentFuncType, types: &TypeList, - features: &WasmFeatures, offset: usize, ) -> Result<ComponentFuncType> { let mut info = TypeInfo::new(); - if ty.results.type_count() > 1 && !features.component_model_multiple_returns() { + if ty.async_ && !self.features.cm_async() { bail!( offset, - "multiple returns on a function is now a gated feature \ - -- https://github.com/WebAssembly/component-model/pull/368" + "async component functions require the component model async feature" ); } let mut set = Set::default(); - set.reserve(core::cmp::max(ty.params.len(), ty.results.type_count())); + set.reserve(core::cmp::max( + ty.params.len(), + usize::from(ty.result.is_some()), + )); let params = ty .params @@ -2396,39 +3086,24 @@ impl ComponentState { set.clear(); - let results = ty - .results - .iter() - .map(|(name, ty)| { - let name = name - .map(|name| { - let name = to_kebab_str(name, "function result", offset)?; - if !set.insert(name) { - bail!( - offset, - "function result name `{name}` conflicts with previous result name `{prev}`", - prev = set.get(name).unwrap(), - ); - } - - Ok(name.to_owned()) - }) - .transpose()?; - - let ty = self.create_component_val_type(*ty, offset)?; + let result = ty + .result + .map(|ty| { + let ty = self.create_component_val_type(ty, offset)?; let ty_info = ty.info(types); if ty_info.contains_borrow() { bail!(offset, "function result cannot contain a `borrow` type"); } info.combine(ty.info(types), offset)?; - Ok((name, ty)) + Ok(ty) }) - .collect::<Result<_>>()?; + .transpose()?; Ok(ComponentFuncType { + async_: ty.async_, info, params, - results, + result, }) } @@ -2513,7 +3188,6 @@ impl ComponentState { &mut self, component_index: u32, component_args: Vec<crate::ComponentInstantiationArg>, - features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result<ComponentInstanceTypeId> { @@ -2536,7 +3210,7 @@ impl ComponentState { ComponentEntityType::Func(self.function_at(component_arg.index, offset)?) } ComponentExternalKind::Value => { - self.check_value_support(features, offset)?; + self.check_value_support(offset)?; ComponentEntityType::Value(*self.value_at(component_arg.index, offset)?) } ComponentExternalKind::Type => { @@ -2608,7 +3282,7 @@ impl ComponentState { // component X" since in such a situation the type of all // instantiations would be the same, which they aren't. // - // This sort of subtelty comes up quite frequently for resources. + // This sort of subtlety comes up quite frequently for resources. // This file contains references to `imported_resources` and // `defined_resources` for example which refer to the formal // nature of components and their abstract variables. Specifically @@ -2781,7 +3455,6 @@ impl ComponentState { fn instantiate_component_exports( &mut self, exports: Vec<crate::ComponentExport>, - features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result<ComponentInstanceTypeId> { @@ -2824,7 +3497,7 @@ impl ComponentState { ComponentEntityType::Func(self.function_at(export.index, offset)?) } ComponentExternalKind::Value => { - self.check_value_support(features, offset)?; + self.check_value_support(offset)?; ComponentEntityType::Value(*self.value_at(export.index, offset)?) } ComponentExternalKind::Type => { @@ -2857,7 +3530,7 @@ impl ComponentState { &mut export_names, &mut inst_exports, &mut info, - features, + &self.features, )?; } @@ -2928,7 +3601,7 @@ impl ComponentState { let mut inst_exports = IndexMap::default(); for export in exports { match export.kind { - ExternalKind::Func => { + ExternalKind::Func | ExternalKind::FuncExact => { insert_export( types, export.name, @@ -2964,14 +3637,19 @@ impl ComponentState { offset, )?; } - ExternalKind::Tag => insert_export( - types, - export.name, - EntityType::Tag(self.core_function_at(export.index, offset)?), - &mut inst_exports, - &mut info, - offset, - )?, + ExternalKind::Tag => { + if !self.features.exceptions() { + bail!(offset, "exceptions proposal not enabled"); + } + insert_export( + types, + export.name, + EntityType::Tag(self.tag_at(export.index, offset)?), + &mut inst_exports, + &mut info, + offset, + )? + } } } @@ -3007,7 +3685,7 @@ impl ComponentState { } match kind { - ExternalKind::Func => { + ExternalKind::Func | ExternalKind::FuncExact => { check_max( self.function_count(), 1, @@ -3026,20 +3704,6 @@ impl ComponentState { offset, )?; push_module_export!(EntityType::Table, core_tables, "table"); - - let ty = self.core_tables.last().unwrap(); - if ty.table64 { - bail!( - offset, - "64-bit tables are not compatible with components yet" - ); - } - if ty.shared { - bail!( - offset, - "shared tables are not compatible with components yet" - ); - } } ExternalKind::Memory => { check_max( @@ -3050,20 +3714,6 @@ impl ComponentState { offset, )?; push_module_export!(EntityType::Memory, core_memories, "memory"); - - let ty = self.core_memories.last().unwrap(); - if ty.memory64 { - bail!( - offset, - "64-bit linear memories are not compatible with components yet" - ); - } - if ty.shared { - bail!( - offset, - "shared linear memories are not compatible with components yet" - ); - } } ExternalKind::Global => { check_max( @@ -3076,6 +3726,9 @@ impl ComponentState { push_module_export!(EntityType::Global, core_globals, "global"); } ExternalKind::Tag => { + if !self.features.exceptions() { + bail!(offset, "exceptions proposal not enabled"); + } check_max( self.core_tags.len(), 1, @@ -3095,12 +3748,11 @@ impl ComponentState { instance_index: u32, kind: ComponentExternalKind, name: &str, - features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result<()> { if let ComponentExternalKind::Value = kind { - self.check_value_support(features, offset)?; + self.check_value_support(offset)?; } let mut ty = match types[self.instance_at(instance_index, offset)?] .exports @@ -3135,7 +3787,7 @@ impl ComponentState { ); } - self.add_entity(&mut ty, None, features, types, offset)?; + self.add_entity(&mut ty, None, types, offset)?; Ok(()) } @@ -3263,11 +3915,13 @@ impl ComponentState { &self, ty: crate::ComponentDefinedType, types: &TypeList, - features: &WasmFeatures, offset: usize, ) -> Result<ComponentDefinedType> { match ty { - crate::ComponentDefinedType::Primitive(ty) => Ok(ComponentDefinedType::Primitive(ty)), + crate::ComponentDefinedType::Primitive(ty) => { + self.check_primitive_type(ty, offset)?; + Ok(ComponentDefinedType::Primitive(ty)) + } crate::ComponentDefinedType::Record(fields) => { self.create_record_type(fields.as_ref(), types, offset) } @@ -3277,11 +3931,26 @@ impl ComponentState { crate::ComponentDefinedType::List(ty) => Ok(ComponentDefinedType::List( self.create_component_val_type(ty, offset)?, )), + crate::ComponentDefinedType::FixedSizeList(ty, elements) => { + if !self.features.cm_fixed_size_list() { + bail!( + offset, + "Fixed size lists require the component model fixed size list feature" + ) + } + if elements < 1 { + bail!(offset, "Fixed size lists must have more than zero elements") + } + Ok(ComponentDefinedType::FixedSizeList( + self.create_component_val_type(ty, offset)?, + elements, + )) + } crate::ComponentDefinedType::Tuple(tys) => { self.create_tuple_type(tys.as_ref(), types, offset) } crate::ComponentDefinedType::Flags(names) => { - self.create_flags_type(names.as_ref(), features, offset) + self.create_flags_type(names.as_ref(), offset) } crate::ComponentDefinedType::Enum(cases) => { self.create_enum_type(cases.as_ref(), offset) @@ -3303,15 +3972,30 @@ impl ComponentState { crate::ComponentDefinedType::Borrow(idx) => Ok(ComponentDefinedType::Borrow( self.resource_at(idx, types, offset)?, )), - crate::ComponentDefinedType::Future(ty) => Ok(ComponentDefinedType::Future( - ty.map(|ty| self.create_component_val_type(ty, offset)) - .transpose()?, - )), - crate::ComponentDefinedType::Stream(ty) => Ok(ComponentDefinedType::Stream( - ty.map(|ty| self.create_component_val_type(ty, offset)) - .transpose()?, - )), - crate::ComponentDefinedType::ErrorContext => Ok(ComponentDefinedType::ErrorContext), + crate::ComponentDefinedType::Future(ty) => { + if !self.features.cm_async() { + bail!( + offset, + "`future` requires the component model async feature" + ) + } + Ok(ComponentDefinedType::Future( + ty.map(|ty| self.create_component_val_type(ty, offset)) + .transpose()?, + )) + } + crate::ComponentDefinedType::Stream(ty) => { + if !self.features.cm_async() { + bail!( + offset, + "`stream` requires the component model async feature" + ) + } + Ok(ComponentDefinedType::Stream( + ty.map(|ty| self.create_component_val_type(ty, offset)) + .transpose()?, + )) + } } } @@ -3442,12 +4126,7 @@ impl ComponentState { Ok(ComponentDefinedType::Tuple(TupleType { info, types })) } - fn create_flags_type( - &self, - names: &[&str], - features: &WasmFeatures, - offset: usize, - ) -> Result<ComponentDefinedType> { + fn create_flags_type(&self, names: &[&str], offset: usize) -> Result<ComponentDefinedType> { let mut names_set = IndexSet::default(); names_set.reserve(names.len()); @@ -3455,14 +4134,8 @@ impl ComponentState { bail!(offset, "flags must have at least one entry"); } - if names.len() > 32 && !features.component_model_more_flags() { - bail!( - offset, - "cannot have more than 32 flags; this was previously \ - accepted and if this is required for your project please \ - leave a comment on \ - https://github.com/WebAssembly/component-model/issues/370" - ); + if names.len() > 32 { + bail!(offset, "cannot have more than 32 flags"); } for name in names { @@ -3514,7 +4187,10 @@ impl ComponentState { offset: usize, ) -> Result<ComponentValType> { Ok(match ty { - crate::ComponentValType::Primitive(pt) => ComponentValType::Primitive(pt), + crate::ComponentValType::Primitive(pt) => { + self.check_primitive_type(pt, offset)?; + ComponentValType::Primitive(pt) + } crate::ComponentValType::Type(idx) => { ComponentValType::Type(self.defined_type_at(idx, offset)?) } @@ -3660,6 +4336,37 @@ impl ComponentState { } } + fn tag_at(&self, idx: u32, offset: usize) -> Result<CoreTypeId> { + match self.core_tags.get(idx as usize) { + Some(t) => Ok(*t), + None => bail!(offset, "unknown tag {idx}: tag index out of bounds"), + } + } + + /// Validates that the linear memory at `idx` is valid to use as a canonical + /// ABI memory. + /// + /// At this time this requires that the memory is a plain 32-bit linear + /// memory. Notably this disallows shared memory and 64-bit linear memories. + fn cabi_memory_at(&self, idx: u32, offset: usize) -> Result<()> { + let ty = self.memory_at(idx, offset)?; + SubtypeCx::memory_type( + ty, + &MemoryType { + initial: 0, + maximum: None, + memory64: false, + shared: false, + page_size_log2: None, + }, + offset, + ) + .map_err(|mut e| { + e.add_context("canonical ABI memory is not a 32-bit linear memory".into()); + e + }) + } + /// Completes the translation of this component, performing final /// validation of its structure. /// @@ -3760,8 +4467,8 @@ impl ComponentState { Ok(ty) } - fn check_value_support(&self, features: &WasmFeatures, offset: usize) -> Result<()> { - if !features.component_model_values() { + fn check_value_support(&self, offset: usize) -> Result<()> { + if !self.features.cm_values() { bail!( offset, "support for component model `value`s is not enabled" @@ -3769,9 +4476,23 @@ impl ComponentState { } Ok(()) } + + fn check_primitive_type(&self, ty: crate::PrimitiveValType, offset: usize) -> Result<()> { + if ty == crate::PrimitiveValType::ErrorContext && !self.features.cm_error_context() { + bail!( + offset, + "`error-context` requires the component model error-context feature" + ) + } + Ok(()) + } } impl InternRecGroup for ComponentState { + fn features(&self) -> &WasmFeatures { + &self.features + } + fn add_type_id(&mut self, id: CoreTypeId) { self.core_types.push(ComponentCoreTypeId::Sub(id)); } @@ -3886,6 +4607,7 @@ impl ComponentNameContext { }; Ok(&types[id]) }; + match name.kind() { // No validation necessary for these styles of names ComponentNameKind::Label(_) @@ -3894,24 +4616,38 @@ impl ComponentNameContext { | ComponentNameKind::Dependency(_) | ComponentNameKind::Hash(_) => {} - // Constructors must return `(own $resource)` and the `$resource` - // must be named within this context to match `rname` + // Constructors must return `(own $resource)` or + // `(result (own $Tresource))` and the `$resource` must be named + // within this context to match `rname`. ComponentNameKind::Constructor(rname) => { let ty = func()?; - if ty.results.len() != 1 { - bail!(offset, "function should return one value"); + if ty.async_ { + bail!(offset, "constructor function cannot be async"); } - let ty = ty.results[0].1; + let ty = match ty.result { + Some(result) => result, + None => bail!(offset, "function should return one value"), + }; let resource = match ty { ComponentValType::Primitive(_) => None, ComponentValType::Type(ty) => match &types[ty] { ComponentDefinedType::Own(id) => Some(id), + ComponentDefinedType::Result { + ok: Some(ComponentValType::Type(ok)), + .. + } => match &types[*ok] { + ComponentDefinedType::Own(id) => Some(id), + _ => None, + }, _ => None, }, }; let resource = match resource { Some(id) => id, - None => bail!(offset, "function should return `(own $T)`"), + None => bail!( + offset, + "function should return `(own $T)` or `(result (own $T))`" + ), }; self.validate_resource_name(*resource, rname, offset)?; } diff --git a/third_party/rust/wasmparser/src/validator/component_types.rs b/third_party/rust/wasmparser/src/validator/component_types.rs @@ -1,13 +1,18 @@ //! Types relating to type information provided by validation. use super::component::ExternKind; -use crate::prelude::*; +use super::{CanonicalOptions, Concurrency}; +use crate::validator::StringEncoding; use crate::validator::names::KebabString; use crate::validator::types::{ CoreTypeId, EntityType, SnapshotList, TypeAlloc, TypeData, TypeIdentifier, TypeInfo, TypeList, Types, TypesKind, TypesRef, TypesRefKind, }; -use crate::{BinaryReaderError, FuncType, PrimitiveValType, Result, ValType}; +use crate::{AbstractHeapType, CompositeInnerType, HeapType, RefType, StorageType, prelude::*}; +use crate::{ + BinaryReaderError, FuncType, MemoryType, PrimitiveValType, Result, TableType, ValType, +}; +use core::fmt; use core::ops::Index; use core::sync::atomic::{AtomicUsize, Ordering}; use core::{ @@ -21,6 +26,9 @@ use core::{ /// Functions that exceed this limit will instead pass parameters indirectly from /// linear memory via a single pointer parameter. const MAX_FLAT_FUNC_PARAMS: usize = 16; +/// The maximum number of parameters in the canonical ABI that can be passed by +/// value in async function imports/exports. +const MAX_FLAT_ASYNC_PARAMS: usize = 4; /// The maximum number of results in the canonical ABI that can be returned by a function. /// /// Functions that exceed this limit have their results written to linear memory via an @@ -63,7 +71,13 @@ impl LoweredTypes { } } - fn push(&mut self, ty: ValType) -> bool { + #[track_caller] + fn assert_push(&mut self, ty: ValType) { + assert!(self.try_push(ty)); + } + + #[must_use = "value is not actually pushed when maxed"] + fn try_push(&mut self, ty: ValType) -> bool { if self.maxed() { return false; } @@ -86,15 +100,21 @@ impl LoweredTypes { } } -/// Represents information about a component function type lowering. -pub(crate) struct LoweringInfo { - pub(crate) params: LoweredTypes, - pub(crate) results: LoweredTypes, - pub(crate) requires_memory: bool, - pub(crate) requires_realloc: bool, +impl fmt::Debug for LoweredTypes { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_slice().fmt(f) + } } -impl LoweringInfo { +/// Represents a component function type's in-progress lowering into a core +/// type. +#[derive(Debug)] +struct LoweredSignature { + params: LoweredTypes, + results: LoweredTypes, +} + +impl LoweredSignature { pub(crate) fn into_func_type(self) -> FuncType { FuncType::new( self.params.as_slice().iter().copied(), @@ -103,13 +123,181 @@ impl LoweringInfo { } } -impl Default for LoweringInfo { +impl Default for LoweredSignature { fn default() -> Self { Self { params: LoweredTypes::new(MAX_FLAT_FUNC_PARAMS), results: LoweredTypes::new(MAX_FLAT_FUNC_RESULTS), - requires_memory: false, - requires_realloc: false, + } + } +} + +impl PrimitiveValType { + pub(crate) fn lower_gc( + &self, + types: &TypeList, + _abi: Abi, + options: &CanonicalOptions, + offset: usize, + core: ArgOrField, + ) -> Result<()> { + match (self, core) { + ( + PrimitiveValType::Bool, + ArgOrField::Field(StorageType::I8) | ArgOrField::Arg(ValType::I32), + ) => Ok(()), + (PrimitiveValType::Bool, ArgOrField::Arg(_)) => bail!( + offset, + "expected to lower component `bool` type to core `i32` type, found `{core}`" + ), + (PrimitiveValType::Bool, ArgOrField::Field(_)) => bail!( + offset, + "expected to lower component `bool` type to core `i8` type, found `{core}`" + ), + + ( + PrimitiveValType::S8, + ArgOrField::Field(StorageType::I8) | ArgOrField::Arg(ValType::I32), + ) => Ok(()), + (PrimitiveValType::S8, ArgOrField::Arg(_)) => bail!( + offset, + "expected to lower component `s8` type to core `i32` type, found `{core}`" + ), + (PrimitiveValType::S8, ArgOrField::Field(_)) => bail!( + offset, + "expected to lower component `s8` type to core `i8` type, found `{core}`" + ), + + ( + PrimitiveValType::U8, + ArgOrField::Field(StorageType::I8) | ArgOrField::Arg(ValType::I32), + ) => Ok(()), + (PrimitiveValType::U8, ArgOrField::Arg(_)) => bail!( + offset, + "expected to lower component `u8` type to core `i32` type, found `{core}`" + ), + (PrimitiveValType::U8, ArgOrField::Field(_)) => bail!( + offset, + "expected to lower component `u8` type to core `i8` type, found `{core}`" + ), + + ( + PrimitiveValType::S16, + ArgOrField::Field(StorageType::I16) | ArgOrField::Arg(ValType::I32), + ) => Ok(()), + (PrimitiveValType::S16, ArgOrField::Arg(_)) => bail!( + offset, + "expected to lower component `s16` type to core `i32` type, found `{core}`" + ), + (PrimitiveValType::S16, ArgOrField::Field(_)) => bail!( + offset, + "expected to lower component `s16` type to core `i16` type, found `{core}`" + ), + + ( + PrimitiveValType::U16, + ArgOrField::Field(StorageType::I16) | ArgOrField::Arg(ValType::I32), + ) => Ok(()), + (PrimitiveValType::U16, ArgOrField::Arg(_)) => bail!( + offset, + "expected to lower component `u16` type to core `i32` type, found `{core}`" + ), + (PrimitiveValType::U16, ArgOrField::Field(_)) => bail!( + offset, + "expected to lower component `u16` type to core `i16` type, found `{core}`" + ), + + (PrimitiveValType::S32, _) if core.as_val_type() == Some(ValType::I32) => Ok(()), + (PrimitiveValType::S32, _) => bail!( + offset, + "expected to lower component `s32` type to core `i32` type, found `{core}`" + ), + + (PrimitiveValType::U32, _) if core.as_val_type() == Some(ValType::I32) => Ok(()), + (PrimitiveValType::U32, _) => bail!( + offset, + "expected to lower component `u32` type to core `i32` type, found `{core}`" + ), + + (PrimitiveValType::S64, _) if core.as_val_type() == Some(ValType::I64) => Ok(()), + (PrimitiveValType::S64, _) => bail!( + offset, + "expected to lower component `s64` type to core `i64` type, found `{core}`" + ), + + (PrimitiveValType::U64, _) if core.as_val_type() == Some(ValType::I64) => Ok(()), + (PrimitiveValType::U64, _) => bail!( + offset, + "expected to lower component `u64` type to core `i64` type, found `{core}`" + ), + + (PrimitiveValType::F32, _) if core.as_val_type() == Some(ValType::F32) => Ok(()), + (PrimitiveValType::F32, _) => bail!( + offset, + "expected to lower component `f32` type to core `f32` type, found `{core}`" + ), + + (PrimitiveValType::F64, _) if core.as_val_type() == Some(ValType::F64) => Ok(()), + (PrimitiveValType::F64, _) => bail!( + offset, + "expected to lower component `f64` type to core `f64` type, found `{core}`" + ), + + (PrimitiveValType::Char, _) if core.as_val_type() == Some(ValType::I32) => Ok(()), + (PrimitiveValType::Char, _) => bail!( + offset, + "expected to lower component `char` type to core `i32` type, found `{core}`" + ), + + (PrimitiveValType::String, _) => { + let type_mismatch_err = || { + let expected = match options.string_encoding { + StringEncoding::Utf8 | StringEncoding::CompactUtf16 => { + "(ref null? (array (mut? i8)))" + } + StringEncoding::Utf16 => "(ref null? (array (mut? i16)))", + }; + bail!( + offset, + "expected to lower component `string` type to core `{expected}` \ + type, found `{core}`" + ) + }; + + match core.as_concrete_ref() { + Some(id) => match types[id].composite_type.inner { + CompositeInnerType::Array(ty) => { + match (options.string_encoding, ty.0.element_type) { + ( + StringEncoding::Utf8 | StringEncoding::CompactUtf16, + StorageType::I8, + ) + | (StringEncoding::Utf16, StorageType::I16) => Ok(()), + _ => type_mismatch_err(), + } + } + _ => type_mismatch_err(), + }, + _ => type_mismatch_err(), + } + } + + (PrimitiveValType::ErrorContext, _) => { + if let Some(r) = core.as_ref_type() { + if let HeapType::Abstract { + shared: _, + ty: AbstractHeapType::Extern, + } = r.heap_type() + { + return Ok(()); + } + } + bail!( + offset, + "expected to lower component `error-context` type into core `(ref null? extern)` type, but \ + found `{core}`", + ) + } } } } @@ -123,12 +311,13 @@ fn push_primitive_wasm_types(ty: &PrimitiveValType, lowered_types: &mut LoweredT | PrimitiveValType::U16 | PrimitiveValType::S32 | PrimitiveValType::U32 - | PrimitiveValType::Char => lowered_types.push(ValType::I32), - PrimitiveValType::S64 | PrimitiveValType::U64 => lowered_types.push(ValType::I64), - PrimitiveValType::F32 => lowered_types.push(ValType::F32), - PrimitiveValType::F64 => lowered_types.push(ValType::F64), + | PrimitiveValType::Char + | PrimitiveValType::ErrorContext => lowered_types.try_push(ValType::I32), + PrimitiveValType::S64 | PrimitiveValType::U64 => lowered_types.try_push(ValType::I64), + PrimitiveValType::F32 => lowered_types.try_push(ValType::F32), + PrimitiveValType::F64 => lowered_types.try_push(ValType::F64), PrimitiveValType::String => { - lowered_types.push(ValType::I32) && lowered_types.push(ValType::I32) + lowered_types.try_push(ValType::I32) && lowered_types.try_push(ValType::I32) } } } @@ -525,7 +714,7 @@ pub enum ComponentValType { impl TypeData for ComponentValType { type Id = ComponentValueTypeId; - + const IS_CORE_SUB_TYPE: bool = false; fn type_info(&self, types: &TypeList) -> TypeInfo { match self { ComponentValType::Primitive(_) => TypeInfo::new(), @@ -555,6 +744,20 @@ impl ComponentValType { Self::Type(id) => types[*id].type_info(types), } } + + fn lower_gc( + &self, + types: &TypeList, + abi: Abi, + options: &CanonicalOptions, + offset: usize, + core: ArgOrField, + ) -> Result<()> { + match self { + ComponentValType::Primitive(ty) => ty.lower_gc(types, abi, options, offset, core), + ComponentValType::Type(ty) => types[*ty].lower_gc(types, abi, options, offset, core), + } + } } trait ModuleImportKey { @@ -568,22 +771,22 @@ impl<'a> Borrow<dyn ModuleImportKey + 'a> for (String, String) { } } -impl Hash for (dyn ModuleImportKey + '_) { +impl Hash for dyn ModuleImportKey + '_ { fn hash<H: Hasher>(&self, state: &mut H) { self.module().hash(state); self.name().hash(state); } } -impl PartialEq for (dyn ModuleImportKey + '_) { +impl PartialEq for dyn ModuleImportKey + '_ { fn eq(&self, other: &Self) -> bool { self.module() == other.module() && self.name() == other.name() } } -impl Eq for (dyn ModuleImportKey + '_) {} +impl Eq for dyn ModuleImportKey + '_ {} -impl Ord for (dyn ModuleImportKey + '_) { +impl Ord for dyn ModuleImportKey + '_ { fn cmp(&self, other: &Self) -> core::cmp::Ordering { match self.module().cmp(other.module()) { core::cmp::Ordering::Equal => (), @@ -593,7 +796,7 @@ impl Ord for (dyn ModuleImportKey + '_) { } } -impl PartialOrd for (dyn ModuleImportKey + '_) { +impl PartialOrd for dyn ModuleImportKey + '_ { fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { Some(self.cmp(other)) } @@ -632,7 +835,7 @@ pub struct ModuleType { impl TypeData for ModuleType { type Id = ComponentCoreModuleTypeId; - + const IS_CORE_SUB_TYPE: bool = false; fn type_info(&self, _types: &TypeList) -> TypeInfo { self.info } @@ -668,7 +871,7 @@ pub struct InstanceType { impl TypeData for InstanceType { type Id = ComponentCoreInstanceTypeId; - + const IS_CORE_SUB_TYPE: bool = false; fn type_info(&self, _types: &TypeList) -> TypeInfo { self.info } @@ -721,7 +924,13 @@ pub enum ComponentEntityType { impl ComponentEntityType { /// Determines if component entity type `a` is a subtype of `b`. - pub fn is_subtype_of(a: &Self, at: TypesRef, b: &Self, bt: TypesRef) -> bool { + /// + /// # Panics + /// + /// Panics if the two given `TypesRef`s are not associated with the same + /// `Validator`. + pub fn is_subtype_of(a: &Self, at: TypesRef<'_>, b: &Self, bt: TypesRef<'_>) -> bool { + assert_eq!(at.id(), bt.id()); SubtypeCx::new(at.list, bt.list) .component_entity_type(a, b, 0) .is_ok() @@ -776,7 +985,7 @@ pub struct ComponentType { /// `Vec<usize>` payload here. For more information about the indexes see /// the documentation on `ComponentState::imported_resources`. /// - /// This should technically be inferrable from the structure of `imports`, + /// This should technically be inferable from the structure of `imports`, /// but it's stored as an auxiliary set for subtype checking and /// instantiation. /// @@ -808,7 +1017,7 @@ pub struct ComponentType { impl TypeData for ComponentType { type Id = ComponentTypeId; - + const IS_CORE_SUB_TYPE: bool = false; fn type_info(&self, _types: &TypeList) -> TypeInfo { self.info } @@ -866,7 +1075,7 @@ pub struct ComponentInstanceType { impl TypeData for ComponentInstanceType { type Id = ComponentInstanceTypeId; - + const IS_CORE_SUB_TYPE: bool = false; fn type_info(&self, _types: &TypeList) -> TypeInfo { self.info } @@ -877,48 +1086,124 @@ impl TypeData for ComponentInstanceType { pub struct ComponentFuncType { /// Metadata about this function type. pub(crate) info: TypeInfo, + /// Whether or not this is an async function. + pub async_: bool, /// The function parameters. pub params: Box<[(KebabString, ComponentValType)]>, - /// The function's results. - pub results: Box<[(Option<KebabString>, ComponentValType)]>, + /// The function's result. + pub result: Option<ComponentValType>, } impl TypeData for ComponentFuncType { type Id = ComponentFuncTypeId; - + const IS_CORE_SUB_TYPE: bool = false; fn type_info(&self, _types: &TypeList) -> TypeInfo { self.info } } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(crate) enum Abi { - LowerSync, - LowerAsync, - LiftSync, - LiftAsync, - LiftAsyncStackful, + Lift, + Lower, +} + +impl Abi { + fn invert(&self) -> Self { + match self { + Abi::Lift => Abi::Lower, + Abi::Lower => Abi::Lift, + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub(crate) enum ArgOrField { + /// Lifting to, or lowering from, an argument value. + Arg(ValType), + /// Lifting to, or lowering from, a struct field or array element. + Field(StorageType), +} + +impl From<ValType> for ArgOrField { + fn from(v: ValType) -> Self { + Self::Arg(v) + } +} + +impl From<StorageType> for ArgOrField { + fn from(v: StorageType) -> Self { + Self::Field(v) + } +} + +impl core::fmt::Display for ArgOrField { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ArgOrField::Arg(ty) => core::fmt::Display::fmt(ty, f), + ArgOrField::Field(ty) => core::fmt::Display::fmt(ty, f), + } + } +} + +impl ArgOrField { + pub(crate) fn as_val_type(self) -> Option<ValType> { + match self { + ArgOrField::Arg(ty) | ArgOrField::Field(StorageType::Val(ty)) => Some(ty), + _ => None, + } + } + + pub(crate) fn as_ref_type(self) -> Option<RefType> { + self.as_val_type()?.as_reference_type() + } + + pub(crate) fn as_concrete_ref(self) -> Option<CoreTypeId> { + match self.as_ref_type()?.heap_type() { + HeapType::Abstract { .. } => None, + HeapType::Concrete(idx) | HeapType::Exact(idx) => { + let id = idx + .as_core_type_id() + .expect("validation only sees core type ids"); + Some(id) + } + } + } +} + +pub(crate) enum LoweredFuncType { + New(FuncType), + Existing(CoreTypeId), +} + +impl LoweredFuncType { + pub(crate) fn intern(self, types: &mut TypeAlloc, offset: usize) -> CoreTypeId { + match self { + LoweredFuncType::New(ty) => types.intern_func_type(ty, offset), + LoweredFuncType::Existing(id) => id, + } + } } impl ComponentFuncType { /// Lowers the component function type to core parameter and result types for the /// canonical ABI. - pub(crate) fn lower(&self, types: &TypeList, abi: Abi) -> LoweringInfo { - let mut info = LoweringInfo::default(); + pub(crate) fn lower( + &self, + types: &TypeList, + options: &CanonicalOptions, + abi: Abi, + offset: usize, + ) -> Result<LoweredFuncType> { + let mut sig = LoweredSignature::default(); - let is_lower = match abi { - Abi::LowerAsync => { - for _ in 0..2 { - info.params.push(ValType::I32); - } - info.results.push(ValType::I32); - info.requires_memory = true; - info.requires_realloc = self.results.iter().any(|(_, ty)| ty.contains_ptr(types)); - return info; - } - Abi::LowerSync => true, - Abi::LiftSync | Abi::LiftAsync | Abi::LiftAsyncStackful => false, - }; + if options.gc { + return self.lower_gc(types, abi, options, offset); + } + + if abi == Abi::Lower && options.concurrency.is_async() { + sig.params.max = MAX_FLAT_ASYNC_PARAMS; + } for (_, ty) in self.params.iter() { // Check to see if `ty` has a pointer somewhere in it, needed for @@ -927,69 +1212,132 @@ impl ComponentFuncType { // lifted functions must specify `realloc` as well. Lifted functions // gain their memory requirement through the final clause of this // function. - if is_lower { - if !info.requires_memory { - info.requires_memory = ty.contains_ptr(types); + match abi { + Abi::Lower => { + options.require_memory_if(offset, || ty.contains_ptr(types))?; } - } else { - if !info.requires_realloc { - info.requires_realloc = ty.contains_ptr(types); + Abi::Lift => { + options.require_realloc_if(offset, || ty.contains_ptr(types))?; } } - if !ty.push_wasm_types(types, &mut info.params) { + if !ty.push_wasm_types(types, &mut sig.params) { // Too many parameters to pass directly // Function will have a single pointer parameter to pass the arguments // via linear memory - info.params.clear(); - assert!(info.params.push(ValType::I32)); - info.requires_memory = true; + sig.params.clear(); + assert!(sig.params.try_push(ValType::I32)); + options.require_memory(offset)?; // We need realloc as well when lifting a function - if !is_lower { - info.requires_realloc = true; + if let Abi::Lift = abi { + options.require_realloc(offset)?; } break; } } - match abi { - Abi::LowerAsync => unreachable!(), - Abi::LowerSync | Abi::LiftSync => { - for (_, ty) in self.results.iter() { + match (abi, options.concurrency) { + (Abi::Lower | Abi::Lift, Concurrency::Sync) => { + if let Some(ty) = &self.result { // Results of lowered functions that contains pointers must be // allocated by the callee meaning that realloc is required. // Results of lifted function are allocated by the guest which // means that no realloc option is necessary. - if is_lower && !info.requires_realloc { - info.requires_realloc = ty.contains_ptr(types); - } - - if !ty.push_wasm_types(types, &mut info.results) { - // Too many results to return directly, either a retptr parameter will be used (import) - // or a single pointer will be returned (export) - info.results.clear(); - if is_lower { - info.params.max = MAX_LOWERED_TYPES; - assert!(info.params.push(ValType::I32)); - } else { - assert!(info.results.push(ValType::I32)); + options.require_realloc_if(offset, || { + abi == Abi::Lower && ty.contains_ptr(types) + })?; + + if !ty.push_wasm_types(types, &mut sig.results) { + // Too many results to return directly, either a retptr + // parameter will be used (import) or a single pointer + // will be returned (export). + sig.results.clear(); + options.require_memory(offset)?; + match abi { + Abi::Lower => { + sig.params.max = MAX_LOWERED_TYPES; + assert!(sig.params.try_push(ValType::I32)); + } + Abi::Lift => { + assert!(sig.results.try_push(ValType::I32)); + } } - info.requires_memory = true; - break; } } } - Abi::LiftAsync => { - info.results.push(ValType::I32); + (Abi::Lower, Concurrency::Async { callback: _ }) => { + if self.result.is_some() { + sig.params.max = MAX_LOWERED_TYPES; + sig.params.assert_push(ValType::I32); + options.require_memory(offset)?; + } + sig.results.assert_push(ValType::I32); + } + (Abi::Lift, Concurrency::Async { callback }) => { + if let Some(ty) = &self.result { + // The result of an async lift will be returned via a call + // to `task.return` rather than the lifted function itself. + // Here we require a memory if either the return type + // contains a pointer or has a flattened form that exceeds + // `MAX_FLAT_FUNC_PARAMS`. + // + // Note that the return type itself has no effect on the + // expected core signature of the lifted function. + + let overflow = + !ty.push_wasm_types(types, &mut LoweredTypes::new(MAX_FLAT_FUNC_PARAMS)); + + options.require_memory_if(offset, || overflow || ty.contains_ptr(types))?; + } + if callback.is_some() { + sig.results.assert_push(ValType::I32); + } } - Abi::LiftAsyncStackful => {} } - // Memory is always required when realloc is required - info.requires_memory |= info.requires_realloc; + Ok(LoweredFuncType::New(sig.into_func_type())) + } - info + fn lower_gc( + &self, + types: &TypeList, + abi: Abi, + options: &CanonicalOptions, + offset: usize, + ) -> Result<LoweredFuncType> { + let core_type_id = options.core_type.unwrap(); + let core_func_ty = types[core_type_id].unwrap_func(); + + ensure!( + core_func_ty.params().len() == self.params.len(), + offset, + "declared `core-type` has {} parameters, but component function has {} parameters", + core_func_ty.params().len(), + self.params.len(), + ); + for (core, (_name, comp)) in core_func_ty.params().iter().zip(self.params.iter()) { + comp.lower_gc(types, abi.invert(), options, offset, (*core).into())?; + } + + ensure!( + core_func_ty.results().len() == usize::from(self.result.is_some()), + offset, + "declared `core-type` has {} results, but component function has {} results", + core_func_ty.results().len(), + usize::from(self.result.is_some()), + ); + if let Some(result) = self.result { + result.lower_gc( + types, + abi, + options, + offset, + core_func_ty.results()[0].into(), + )?; + } + + Ok(LoweredFuncType::Existing(core_type_id)) } } @@ -1011,6 +1359,27 @@ pub struct RecordType { pub fields: IndexMap<KebabString, ComponentValType>, } +impl RecordType { + fn lower_gc( + &self, + types: &TypeList, + abi: Abi, + options: &CanonicalOptions, + offset: usize, + core: ArgOrField, + ) -> Result<()> { + lower_gc_product_type( + self.fields.values(), + types, + abi, + options, + offset, + core, + "record", + ) + } +} + /// Represents a variant type. #[derive(Debug, Clone)] pub struct VariantType { @@ -1020,6 +1389,44 @@ pub struct VariantType { pub cases: IndexMap<KebabString, VariantCase>, } +impl VariantType { + fn lower_gc( + &self, + types: &TypeList, + abi: Abi, + options: &CanonicalOptions, + offset: usize, + core: ArgOrField, + ) -> Result<()> { + lower_gc_sum_type(types, abi, options, offset, core, "variant") + } +} + +/// Common helper for lowering sum types (variants, options, and results) to +/// core GC types. +fn lower_gc_sum_type( + types: &TypeList, + _abi: Abi, + _options: &CanonicalOptions, + offset: usize, + core: ArgOrField, + kind: &str, +) -> Result<()> { + if let Some(id) = core.as_concrete_ref() { + if let CompositeInnerType::Struct(ty) = &types[id].composite_type.inner { + if ty.fields.is_empty() { + return Ok(()); + } + } + } + + bail!( + offset, + "expected to lower component `{kind}` type to core `(ref null? (struct))`, \ + but found `{core}`", + ) +} + /// Represents a tuple type. #[derive(Debug, Clone)] pub struct TupleType { @@ -1029,6 +1436,27 @@ pub struct TupleType { pub types: Box<[ComponentValType]>, } +impl TupleType { + fn lower_gc( + &self, + types: &TypeList, + abi: Abi, + options: &CanonicalOptions, + offset: usize, + core: ArgOrField, + ) -> Result<()> { + lower_gc_product_type( + self.types.iter(), + types, + abi, + options, + offset, + core, + "tuple", + ) + } +} + /// Represents a component defined type. #[derive(Debug, Clone)] pub enum ComponentDefinedType { @@ -1040,6 +1468,8 @@ pub enum ComponentDefinedType { Variant(VariantType), /// The type is a list. List(ComponentValType), + /// The type is a fixed size list. + FixedSizeList(ComponentValType, u32), /// The type is a tuple. Tuple(TupleType), /// The type is a set of flags. @@ -1063,13 +1493,11 @@ pub enum ComponentDefinedType { Future(Option<ComponentValType>), /// A stream type with the specified payload type. Stream(Option<ComponentValType>), - /// The error-context type. - ErrorContext, } impl TypeData for ComponentDefinedType { type Id = ComponentDefinedTypeId; - + const IS_CORE_SUB_TYPE: bool = false; fn type_info(&self, types: &TypeList) -> TypeInfo { match self { Self::Primitive(_) @@ -1077,13 +1505,12 @@ impl TypeData for ComponentDefinedType { | Self::Enum(_) | Self::Own(_) | Self::Future(_) - | Self::Stream(_) - | Self::ErrorContext => TypeInfo::new(), + | Self::Stream(_) => TypeInfo::new(), Self::Borrow(_) => TypeInfo::borrow(), Self::Record(r) => r.info, Self::Variant(v) => v.info, Self::Tuple(t) => t.info, - Self::List(ty) | Self::Option(ty) => ty.info(types), + Self::List(ty) | Self::FixedSizeList(ty, _) | Self::Option(ty) => ty.info(types), Self::Result { ok, err } => { let default = TypeInfo::new(); let mut info = ok.map(|ty| ty.type_info(types)).unwrap_or(default); @@ -1111,9 +1538,8 @@ impl ComponentDefinedType { | Self::Own(_) | Self::Borrow(_) | Self::Future(_) - | Self::Stream(_) - | Self::ErrorContext => false, - Self::Option(ty) => ty.contains_ptr(types), + | Self::Stream(_) => false, + Self::Option(ty) | Self::FixedSizeList(ty, _) => ty.contains_ptr(types), Self::Result { ok, err } => { ok.map(|ty| ty.contains_ptr(types)).unwrap_or(false) || err.map(|ty| ty.contains_ptr(types)).unwrap_or(false) @@ -1133,20 +1559,22 @@ impl ComponentDefinedType { types, lowered_types, ), - Self::List(_) => lowered_types.push(ValType::I32) && lowered_types.push(ValType::I32), + Self::List(_) => { + lowered_types.try_push(ValType::I32) && lowered_types.try_push(ValType::I32) + } + Self::FixedSizeList(ty, length) => { + (0..*length).all(|_n| ty.push_wasm_types(types, lowered_types)) + } Self::Tuple(t) => t .types .iter() .all(|ty| ty.push_wasm_types(types, lowered_types)), Self::Flags(names) => { - (0..(names.len() + 31) / 32).all(|_| lowered_types.push(ValType::I32)) + (0..(names.len() + 31) / 32).all(|_| lowered_types.try_push(ValType::I32)) + } + Self::Enum(_) | Self::Own(_) | Self::Borrow(_) | Self::Future(_) | Self::Stream(_) => { + lowered_types.try_push(ValType::I32) } - Self::Enum(_) - | Self::Own(_) - | Self::Borrow(_) - | Self::Future(_) - | Self::Stream(_) - | Self::ErrorContext => lowered_types.push(ValType::I32), Self::Option(ty) => { Self::push_variant_wasm_types([ty].into_iter(), types, lowered_types) } @@ -1162,7 +1590,7 @@ impl ComponentDefinedType { lowered_types: &mut LoweredTypes, ) -> bool { // Push the discriminant - if !lowered_types.push(ValType::I32) { + if !lowered_types.try_push(ValType::I32) { return false; } @@ -1179,7 +1607,7 @@ impl ComponentDefinedType { match lowered_types.get_mut(start + i) { Some(prev) => *prev = Self::join_types(*prev, ty), None => { - if !lowered_types.push(ty) { + if !lowered_types.try_push(ty) { return false; } } @@ -1211,16 +1639,149 @@ impl ComponentDefinedType { ComponentDefinedType::Flags(_) => "flags", ComponentDefinedType::Option(_) => "option", ComponentDefinedType::List(_) => "list", + ComponentDefinedType::FixedSizeList(_, _) => "fixed size list", ComponentDefinedType::Result { .. } => "result", ComponentDefinedType::Own(_) => "own", ComponentDefinedType::Borrow(_) => "borrow", ComponentDefinedType::Future(_) => "future", ComponentDefinedType::Stream(_) => "stream", - ComponentDefinedType::ErrorContext => "error-context", + } + } + + fn lower_gc( + &self, + types: &TypeList, + abi: Abi, + options: &CanonicalOptions, + offset: usize, + core: ArgOrField, + ) -> Result<()> { + match self { + ComponentDefinedType::Primitive(ty) => ty.lower_gc(types, abi, options, offset, core), + + ComponentDefinedType::Record(ty) => ty.lower_gc(types, abi, options, offset, core), + + ComponentDefinedType::Variant(ty) => ty.lower_gc(types, abi, options, offset, core), + + ComponentDefinedType::List(ty) | ComponentDefinedType::FixedSizeList(ty, _) => { + let id = match core.as_concrete_ref() { + Some(id) => id, + None => bail!( + offset, + "expected to lower component `list` type into `(ref null? (array ...))`, but \ + found `{core}`", + ), + }; + let array_ty = match types[id].composite_type.inner { + CompositeInnerType::Array(ty) => ty, + _ => bail!( + offset, + "expected to lower component `list` type into `(ref null? (array ...))`, but \ + found `{core}`", + ), + }; + ty.lower_gc(types, abi, options, offset, array_ty.0.element_type.into()) + } + + ComponentDefinedType::Tuple(ty) => ty.lower_gc(types, abi, options, offset, core), + + ComponentDefinedType::Flags(flags) => { + assert!(flags.len() <= 32, "required by validation"); + if core.as_val_type() == Some(ValType::I32) { + Ok(()) + } else { + bail!( + offset, + "expected to lower component `flags` type into core `i32` type, but \ + found `{core}`", + ) + } + } + + ComponentDefinedType::Enum(_) => { + if core.as_val_type() == Some(ValType::I32) { + Ok(()) + } else { + bail!( + offset, + "expected to lower component `enum` type into core `i32` type, but \ + found `{core}`", + ) + } + } + + ComponentDefinedType::Option(_) => { + lower_gc_sum_type(types, abi, options, offset, core, "option") + } + + ComponentDefinedType::Result { .. } => { + lower_gc_sum_type(types, abi, options, offset, core, "result") + } + + ComponentDefinedType::Own(_) + | ComponentDefinedType::Borrow(_) + | ComponentDefinedType::Future(_) + | ComponentDefinedType::Stream(_) => { + if let Some(r) = core.as_ref_type() { + if let HeapType::Abstract { + shared: _, + ty: AbstractHeapType::Extern, + } = r.heap_type() + { + return Ok(()); + } + } + bail!( + offset, + "expected to lower component `{}` type into core `(ref null? extern)` type, but \ + found `{core}`", + self.desc() + ) + } } } } +/// Shared helper for lowering component record and tuple types to core GC +/// types. +fn lower_gc_product_type<'a, I>( + fields: I, + types: &TypeList, + abi: Abi, + options: &CanonicalOptions, + offset: usize, + core: ArgOrField, + kind: &str, +) -> core::result::Result<(), BinaryReaderError> +where + I: IntoIterator<Item = &'a ComponentValType>, + I::IntoIter: ExactSizeIterator, +{ + let fields = fields.into_iter(); + let fields_len = fields.len(); + + if let Some(id) = core.as_concrete_ref() { + if let CompositeInnerType::Struct(ty) = &types[id].composite_type.inner { + ensure!( + ty.fields.len() == fields_len, + offset, + "core `struct` has {} fields, but component `{kind}` has {fields_len} fields", + ty.fields.len(), + ); + for (core, comp) in ty.fields.iter().zip(fields) { + comp.lower_gc(types, abi, options, offset, core.element_type.into())?; + } + return Ok(()); + } + } + + bail!( + offset, + "expected to lower component `{kind}` type to core `(ref null? (struct ...))`, \ + but found `{core}`", + ) +} + /// An opaque identifier intended to be used to distinguish whether two /// resource types are equivalent or not. #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Copy)] @@ -1931,8 +2492,7 @@ impl TypeAlloc { match &self[id] { ComponentDefinedType::Primitive(_) | ComponentDefinedType::Flags(_) - | ComponentDefinedType::Enum(_) - | ComponentDefinedType::ErrorContext => {} + | ComponentDefinedType::Enum(_) => {} ComponentDefinedType::Record(r) => { for ty in r.fields.values() { self.free_variables_valtype(ty, set); @@ -1950,7 +2510,9 @@ impl TypeAlloc { } } } - ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => { + ComponentDefinedType::List(ty) + | ComponentDefinedType::FixedSizeList(ty, _) + | ComponentDefinedType::Option(ty) => { self.free_variables_valtype(ty, set); } ComponentDefinedType::Result { ok, err } => { @@ -2024,12 +2586,7 @@ impl TypeAlloc { set: &mut IndexSet<ResourceId>, ) { let i = &self[id]; - for ty in i - .params - .iter() - .map(|(_, ty)| ty) - .chain(i.results.iter().map(|(_, ty)| ty)) - { + for ty in i.params.iter().map(|(_, ty)| ty).chain(&i.result) { self.free_variables_valtype(ty, set); } } @@ -2074,7 +2631,7 @@ impl TypeAlloc { let ty = &self[id]; match ty { // Primitives are always considered named - ComponentDefinedType::Primitive(_) | ComponentDefinedType::ErrorContext => true, + ComponentDefinedType::Primitive(_) => true, // These structures are never allowed to be anonymous, so they // themselves must be named. @@ -2097,9 +2654,9 @@ impl TypeAlloc { .map(|t| self.type_named_valtype(t, set)) .unwrap_or(true) } - ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => { - self.type_named_valtype(ty, set) - } + ComponentDefinedType::List(ty) + | ComponentDefinedType::FixedSizeList(ty, _) + | ComponentDefinedType::Option(ty) => self.type_named_valtype(ty, set), // own/borrow themselves don't have to be named, but the resource // they refer to must be named. @@ -2145,6 +2702,9 @@ where { /// Pushes a new anonymous type within this object, returning an identifier /// which can be used to refer to it. + /// + /// For internal use only! + #[doc(hidden)] fn push_ty<T>(&mut self, ty: T) -> T::Id where T: TypeData; @@ -2266,8 +2826,7 @@ where match &mut tmp { ComponentDefinedType::Primitive(_) | ComponentDefinedType::Flags(_) - | ComponentDefinedType::Enum(_) - | ComponentDefinedType::ErrorContext => {} + | ComponentDefinedType::Enum(_) => {} ComponentDefinedType::Record(r) => { for ty in r.fields.values_mut() { any_changed |= self.remap_valtype(ty, map); @@ -2285,7 +2844,9 @@ where } } } - ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => { + ComponentDefinedType::List(ty) + | ComponentDefinedType::FixedSizeList(ty, _) + | ComponentDefinedType::Option(ty) => { any_changed |= self.remap_valtype(ty, map); } ComponentDefinedType::Result { ok, err } => { @@ -2353,7 +2914,7 @@ where .params .iter_mut() .map(|(_, ty)| ty) - .chain(tmp.results.iter_mut().map(|(_, ty)| ty)) + .chain(&mut tmp.result) { any_changed |= self.remap_valtype(ty, map); } @@ -2473,9 +3034,30 @@ pub struct SubtypeCx<'a> { pub b: SubtypeArena<'a>, } +macro_rules! limits_match { + ($a:expr, $b:expr) => {{ + let a = $a; + let b = $b; + a.initial >= b.initial + && match b.maximum { + Some(b_max) => match a.maximum { + Some(a_max) => a_max <= b_max, + None => false, + }, + None => true, + } + }}; +} + impl<'a> SubtypeCx<'a> { /// Create a new instance with the specified type lists + /// + /// # Panics + /// + /// Panics if the two given `TypesRef`s are not associated with the same + /// `Validator`. pub fn new_with_refs(a: TypesRef<'a>, b: TypesRef<'a>) -> SubtypeCx<'a> { + assert_eq!(a.id(), b.id()); Self::new(a.list, b.list) } @@ -2672,6 +3254,15 @@ impl<'a> SubtypeCx<'a> { let a = &self.a[a]; let b = &self.b[b]; + if a.async_ != b.async_ { + let a_desc = if a.async_ { "async" } else { "sync" }; + let b_desc = if b.async_ { "async" } else { "sync" }; + bail!( + offset, + "expected {a_desc} function, found {b_desc} function", + ); + } + // Note that this intentionally diverges from the upstream // specification in terms of subtyping. This is a full // type-equality check which ensures that the structure of `a` @@ -2710,14 +3301,6 @@ impl<'a> SubtypeCx<'a> { a.params.len(), ); } - if a.results.len() != b.results.len() { - bail!( - offset, - "expected {} results, found {}", - b.results.len(), - a.results.len(), - ); - } for ((an, a), (bn, b)) in a.params.iter().zip(b.params.iter()) { if an != bn { bail!(offset, "expected parameter named `{bn}`, found `{an}`"); @@ -2725,12 +3308,15 @@ impl<'a> SubtypeCx<'a> { self.component_val_type(a, b, offset) .with_context(|| format!("type mismatch in function parameter `{an}`"))?; } - for ((an, a), (bn, b)) in a.results.iter().zip(b.results.iter()) { - if an != bn { - bail!(offset, "mismatched result names"); - } - self.component_val_type(a, b, offset) - .with_context(|| "type mismatch with result type")?; + + match (&a.result, &b.result) { + (Some(a), Some(b)) => self + .component_val_type(a, b, offset) + .with_context(|| "type mismatch with result type")?, + (None, None) => {} + + (Some(_), None) => bail!(offset, "expected a result, found none"), + (None, Some(_)) => bail!(offset, "expected no result, found one"), } Ok(()) } @@ -2998,55 +3584,22 @@ impl<'a> SubtypeCx<'a> { } pub(crate) fn entity_type(&self, a: &EntityType, b: &EntityType, offset: usize) -> Result<()> { - macro_rules! limits_match { - ($a:expr, $b:expr) => {{ - let a = $a; - let b = $b; - a.initial >= b.initial - && match b.maximum { - Some(b_max) => match a.maximum { - Some(a_max) => a_max <= b_max, - None => false, - }, - None => true, - } - }}; - } - match (a, b) { - (EntityType::Func(a), EntityType::Func(b)) => { - self.core_func_type(self.a[*a].unwrap_func(), self.b[*b].unwrap_func(), offset) + (EntityType::Func(a), EntityType::Func(b)) + | (EntityType::FuncExact(a), EntityType::Func(b)) => { + self.core_func_type(*a, *b, offset) } (EntityType::Func(_), b) => bail!(offset, "expected {}, found func", b.desc()), - (EntityType::Table(a), EntityType::Table(b)) => { - if a.element_type != b.element_type { - bail!( - offset, - "expected table element type {}, found {}", - b.element_type, - a.element_type, - ) - } - if limits_match!(a, b) { - Ok(()) - } else { - bail!(offset, "mismatch in table limits") - } + (EntityType::FuncExact(a), EntityType::FuncExact(b)) => { + self.core_func_type(*b, *a, offset)?; + self.core_func_type(*a, *b, offset) } - (EntityType::Table(_), b) => bail!(offset, "expected {}, found table", b.desc()), - (EntityType::Memory(a), EntityType::Memory(b)) => { - if a.shared != b.shared { - bail!(offset, "mismatch in the shared flag for memories") - } - if a.memory64 != b.memory64 { - bail!(offset, "mismatch in index type used for memories") - } - if limits_match!(a, b) { - Ok(()) - } else { - bail!(offset, "mismatch in memory limits") - } + (EntityType::FuncExact(_), b) => { + bail!(offset, "expected {}, found func_exact", b.desc()) } + (EntityType::Table(a), EntityType::Table(b)) => Self::table_type(a, b, offset), + (EntityType::Table(_), b) => bail!(offset, "expected {}, found table", b.desc()), + (EntityType::Memory(a), EntityType::Memory(b)) => Self::memory_type(a, b, offset), (EntityType::Memory(_), b) => bail!(offset, "expected {}, found memory", b.desc()), (EntityType::Global(a), EntityType::Global(b)) => { if a.mutable != b.mutable { @@ -3064,23 +3617,58 @@ impl<'a> SubtypeCx<'a> { } } (EntityType::Global(_), b) => bail!(offset, "expected {}, found global", b.desc()), - (EntityType::Tag(a), EntityType::Tag(b)) => { - self.core_func_type(self.a[*a].unwrap_func(), self.b[*b].unwrap_func(), offset) - } + (EntityType::Tag(a), EntityType::Tag(b)) => self.core_func_type(*a, *b, offset), (EntityType::Tag(_), b) => bail!(offset, "expected {}, found tag", b.desc()), } } - fn core_func_type(&self, a: &FuncType, b: &FuncType, offset: usize) -> Result<()> { - if a == b { + pub(crate) fn table_type(a: &TableType, b: &TableType, offset: usize) -> Result<()> { + if a.element_type != b.element_type { + bail!( + offset, + "expected table element type {}, found {}", + b.element_type, + a.element_type, + ) + } + if a.shared != b.shared { + bail!(offset, "mismatch in the shared flag for tables") + } + if limits_match!(a, b) { + Ok(()) + } else { + bail!(offset, "mismatch in table limits") + } + } + + pub(crate) fn memory_type(a: &MemoryType, b: &MemoryType, offset: usize) -> Result<()> { + if a.shared != b.shared { + bail!(offset, "mismatch in the shared flag for memories") + } + if a.memory64 != b.memory64 { + bail!(offset, "mismatch in index type used for memories") + } + if limits_match!(a, b) { + Ok(()) + } else { + bail!(offset, "mismatch in memory limits") + } + } + + fn core_func_type(&self, a: CoreTypeId, b: CoreTypeId, offset: usize) -> Result<()> { + debug_assert!(self.a.get(a).is_some()); + debug_assert!(self.b.get(b).is_some()); + if self.a.id_is_subtype(a, b) { + debug_assert!(self.a.get(b).is_some()); + debug_assert!(self.b.get(a).is_some()); Ok(()) } else { bail!( offset, "expected: {}\n\ found: {}", - b.desc(), - a.desc(), + self.b[b], + self.a[a], ) } } @@ -3172,6 +3760,14 @@ impl<'a> SubtypeCx<'a> { (Variant(_), b) => bail!(offset, "expected {}, found variant", b.desc()), (List(a), List(b)) | (Option(a), Option(b)) => self.component_val_type(a, b, offset), (List(_), b) => bail!(offset, "expected {}, found list", b.desc()), + (FixedSizeList(a, asize), FixedSizeList(b, bsize)) => { + if asize != bsize { + bail!(offset, "expected fixed size {bsize}, found size {asize}") + } else { + self.component_val_type(a, b, offset) + } + } + (FixedSizeList(_, _), b) => bail!(offset, "expected {}, found list", b.desc()), (Option(_), b) => bail!(offset, "expected {}, found option", b.desc()), (Tuple(a), Tuple(b)) => { if a.types.len() != b.types.len() { @@ -3249,8 +3845,6 @@ impl<'a> SubtypeCx<'a> { (Some(_), None) => bail!(offset, "expected stream type to not be present"), }, (Stream(_), b) => bail!(offset, "expected {}, found stream", b.desc()), - (ErrorContext, ErrorContext) => Ok(()), - (ErrorContext, b) => bail!(offset, "expected {}, found error-context", b.desc()), } } @@ -3324,6 +3918,33 @@ impl<'a> SubtypeArena<'a> { list: TypeList::default(), } } + + fn get<T>(&self, id: T) -> Option<&T::Data> + where + T: TypeIdentifier, + { + let index = id.index(); + if index < T::list(self.types).len() { + self.types.get(id) + } else { + let temp_index = index - T::list(self.types).len(); + let temp_index = u32::try_from(temp_index).unwrap(); + let temp_id = T::from_index(temp_index); + self.list.get(temp_id) + } + } + + /// Is `a == b` or was `a` declared (potentially transitively) to be a + /// subtype of `b`? + fn id_is_subtype(&self, a: CoreTypeId, b: CoreTypeId) -> bool { + self.get(a).is_some() && self.get(b).is_some() && { + // NB: we can query `self.types.id_is_subtype` directly, and ignore + // `self.list`, because `self.list` should never contain core types. + debug_assert!(a.index() < CoreTypeId::list(self.types).len()); + debug_assert!(b.index() < CoreTypeId::list(self.types).len()); + self.types.id_is_subtype(a, b) + } + } } impl<T> Index<T> for SubtypeArena<'_> @@ -3333,15 +3954,7 @@ where type Output = T::Data; fn index(&self, id: T) -> &T::Data { - let index = id.index(); - if index < T::list(self.types).len() { - &self.types[id] - } else { - let temp_index = index - T::list(self.types).len(); - let temp_index = u32::try_from(temp_index).unwrap(); - let temp_id = T::from_index(temp_index); - &self.list[temp_id] - } + self.get(id).unwrap() } } @@ -3350,6 +3963,10 @@ impl Remap for SubtypeArena<'_> { where T: TypeData, { + assert!( + !T::IS_CORE_SUB_TYPE, + "cannot push core sub types into `SubtypeArena`s, that would break type canonicalization" + ); let index = T::Id::list(&self.list).len() + T::Id::list(self.types).len(); let index = u32::try_from(index).unwrap(); self.list.push(ty); diff --git a/third_party/rust/wasmparser/src/validator/core.rs b/third_party/rust/wasmparser/src/validator/core.rs @@ -7,45 +7,21 @@ pub(crate) use canonical::InternRecGroup; use self::arc::MaybeOwned; use super::{ check_max, combine_type_sizes, - operators::{ty_to_str, OperatorValidator, OperatorValidatorAllocations}, + operators::{OperatorValidator, OperatorValidatorAllocations, ty_to_str}, types::{CoreTypeId, EntityType, RecGroupId, TypeAlloc, TypeList}, }; #[cfg(feature = "simd")] use crate::VisitSimdOperator; use crate::{ - limits::*, BinaryReaderError, ConstExpr, Data, DataKind, Element, ElementKind, ExternalKind, - FuncType, Global, GlobalType, HeapType, MemoryType, RecGroup, RefType, Result, SubType, Table, - TableInit, TableType, TagType, TypeRef, UnpackedIndex, ValType, VisitOperator, WasmFeatures, - WasmModuleResources, + BinaryReaderError, ConstExpr, Data, DataKind, Element, ElementKind, ExternalKind, FrameKind, + FrameStack, FuncType, Global, GlobalType, HeapType, MemoryType, RecGroup, RefType, Result, + SubType, Table, TableInit, TableType, TagType, TypeRef, UnpackedIndex, ValType, VisitOperator, + WasmFeatures, WasmModuleResources, limits::*, }; -use crate::{prelude::*, CompositeInnerType}; +use crate::{CompositeInnerType, prelude::*}; use alloc::sync::Arc; use core::mem; -// Section order for WebAssembly modules. -// -// Component sections are unordered and allow for duplicates, -// so this isn't used for components. -#[derive(Copy, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug)] -pub enum Order { - #[default] - Initial, - Type, - Import, - Function, - Table, - Memory, - Tag, - Global, - Export, - Start, - Element, - DataCount, - Code, - Data, -} - -#[derive(Default)] pub(crate) struct ModuleState { /// Internal state that is incrementally built-up for the module being /// validated. This houses type information for all wasm items, like @@ -54,19 +30,6 @@ pub(crate) struct ModuleState { /// mutated to we can clone it cheaply and hand it to sub-validators. pub module: arc::MaybeOwned<Module>, - /// Where we are, order-wise, in the wasm binary. - order: Order, - - /// The number of data segments in the data section (if present). - pub data_segment_count: u32, - - /// The number of functions we expect to be defined in the code section, or - /// basically the length of the function section if it was found. The next - /// index is where we are, in the code section index space, for the next - /// entry in the code section (used to figure out what type is next for the - /// function being validated). - pub expected_code_bodies: Option<u32>, - const_expr_allocs: OperatorValidatorAllocations, /// When parsing the code section, represents the current index in the section. @@ -74,68 +37,36 @@ pub(crate) struct ModuleState { } impl ModuleState { - pub fn update_order(&mut self, order: Order, offset: usize) -> Result<()> { - if self.order >= order { - return Err(BinaryReaderError::new("section out of order", offset)); + pub fn new(features: WasmFeatures) -> ModuleState { + ModuleState { + module: arc::MaybeOwned::new(Module::new(features)), + const_expr_allocs: OperatorValidatorAllocations::default(), + code_section_index: None, } - - self.order = order; - - Ok(()) } - pub fn validate_end(&self, offset: usize) -> Result<()> { - // Ensure that the data count section, if any, was correct. - if let Some(data_count) = self.module.data_count { - if data_count != self.data_segment_count { - return Err(BinaryReaderError::new( - "data count and data section have inconsistent lengths", - offset, - )); - } - } - // Ensure that the function section, if nonzero, was paired with a code - // section with the appropriate length. - if let Some(n) = self.expected_code_bodies { - if n > 0 { - return Err(BinaryReaderError::new( - "function and code section have inconsistent lengths", - offset, - )); - } - } - - Ok(()) - } - - pub fn next_code_index_and_type(&mut self, offset: usize) -> Result<(u32, u32)> { + pub fn next_code_index_and_type(&mut self) -> (u32, u32) { let index = self .code_section_index .get_or_insert(self.module.num_imported_functions as usize); - if *index >= self.module.functions.len() { - return Err(BinaryReaderError::new( - "code section entry exceeds number of functions", - offset, - )); - } + assert!(*index < self.module.functions.len()); let ty = self.module.functions[*index]; *index += 1; - Ok(((*index - 1) as u32, ty)) + ((*index - 1) as u32, ty) } pub fn add_global( &mut self, mut global: Global, - features: &WasmFeatures, types: &TypeList, offset: usize, ) -> Result<()> { self.module - .check_global_type(&mut global.ty, features, types, offset)?; - self.check_const_expr(&global.init_expr, global.ty.content_type, features, types)?; + .check_global_type(&mut global.ty, types, offset)?; + self.check_const_expr(&global.init_expr, global.ty.content_type, types)?; self.module.assert_mut().globals.push(global.ty); Ok(()) } @@ -143,12 +74,10 @@ impl ModuleState { pub fn add_table( &mut self, mut table: Table<'_>, - features: &WasmFeatures, types: &TypeList, offset: usize, ) -> Result<()> { - self.module - .check_table_type(&mut table.ty, features, types, offset)?; + self.module.check_table_type(&mut table.ty, types, offset)?; match &table.init { TableInit::RefNull => { @@ -157,35 +86,37 @@ impl ModuleState { } } TableInit::Expr(expr) => { - if !features.function_references() { + if !self.module.features.function_references() { bail!( offset, "tables with expression initializers require \ the function-references proposal" ); } - self.check_const_expr(expr, table.ty.element_type.into(), features, types)?; + self.check_const_expr(expr, table.ty.element_type.into(), types)?; } } self.module.assert_mut().tables.push(table.ty); Ok(()) } - pub fn add_data_segment( - &mut self, - data: Data, - features: &WasmFeatures, - types: &TypeList, - offset: usize, - ) -> Result<()> { + pub fn add_data_segment(&mut self, data: Data, types: &TypeList, offset: usize) -> Result<()> { match data.kind { - DataKind::Passive => Ok(()), + DataKind::Passive => { + if !self.module.features.bulk_memory() { + bail!( + offset, + "passive data segments require the bulk-memory proposal" + ); + } + Ok(()) + } DataKind::Active { memory_index, offset_expr, } => { let ty = self.module.memory_at(memory_index, offset)?.index_type(); - self.check_const_expr(&offset_expr, ty, features, types) + self.check_const_expr(&offset_expr, ty, types) } } } @@ -193,7 +124,6 @@ impl ModuleState { pub fn add_element_segment( &mut self, mut e: Element, - features: &WasmFeatures, types: &TypeList, offset: usize, ) -> Result<()> { @@ -202,7 +132,7 @@ impl ModuleState { let element_ty = match &mut e.items { crate::ElementItems::Functions(_) => RefType::FUNC, crate::ElementItems::Expressions(ty, _) => { - self.module.check_ref_type(ty, features, offset)?; + self.module.check_ref_type(ty, offset)?; *ty } }; @@ -224,10 +154,10 @@ impl ModuleState { )); } - self.check_const_expr(&offset_expr, table.index_type(), features, types)?; + self.check_const_expr(&offset_expr, table.index_type(), types)?; } ElementKind::Passive | ElementKind::Declared => { - if !features.bulk_memory() { + if !self.module.features.bulk_memory() { return Err(BinaryReaderError::new( "bulk memory must be enabled", offset, @@ -259,7 +189,7 @@ impl ModuleState { crate::ElementItems::Expressions(ty, reader) => { validate_count(reader.count())?; for expr in reader { - self.check_const_expr(&expr?, ValType::Ref(ty), features, types)?; + self.check_const_expr(&expr?, ValType::Ref(ty), types)?; } } } @@ -271,15 +201,13 @@ impl ModuleState { &mut self, expr: &ConstExpr<'_>, expected_ty: ValType, - features: &WasmFeatures, types: &TypeList, ) -> Result<()> { let mut validator = VisitConstOperator { offset: 0, - order: self.order, uninserted_funcref: false, ops: OperatorValidator::new_const_expr( - features, + &self.module.features, expected_ty, mem::take(&mut self.const_expr_allocs), ), @@ -287,15 +215,13 @@ impl ModuleState { types, module: &mut self.module, }, - features, }; - let mut ops = expr.get_operators_reader(); + let mut ops = expr.get_binary_reader(); while !ops.eof() { validator.offset = ops.original_position(); ops.visit_operator(&mut validator)??; } - validator.ops.finish(ops.original_position())?; // See comment in `RefFunc` below for why this is an assert. assert!(!validator.uninserted_funcref); @@ -309,8 +235,6 @@ impl ModuleState { uninserted_funcref: bool, ops: OperatorValidator, resources: OperatorValidatorResources<'a>, - order: Order, - features: &'a WasmFeatures, } impl VisitConstOperator<'_> { @@ -323,38 +247,29 @@ impl ModuleState { Ok(()) } else { Err(BinaryReaderError::new( - format!( - "constant expression required: non-constant operator: {}", - op - ), + format!("constant expression required: non-constant operator: {op}"), self.offset, )) } } fn validate_gc(&mut self, op: &str) -> Result<()> { - if self.features.gc() { + if self.ops.features.gc() { Ok(()) } else { Err(BinaryReaderError::new( - format!( - "constant expression required: non-constant operator: {}", - op - ), + format!("constant expression required: non-constant operator: {op}"), self.offset, )) } } fn validate_shared_everything_threads(&mut self, op: &str) -> Result<()> { - if self.features.shared_everything_threads() { + if self.ops.features.shared_everything_threads() { Ok(()) } else { Err(BinaryReaderError::new( - format!( - "constant expression required: non-constant operator: {}", - op - ), + format!("constant expression required: non-constant operator: {op}"), self.offset, )) } @@ -364,7 +279,7 @@ impl ModuleState { let module = &self.resources.module; let global = module.global_at(index, self.offset)?; - if index >= module.num_imported_globals && !self.features.gc() { + if index >= module.num_imported_globals && !self.ops.features.gc() { return Err(BinaryReaderError::new( "constant expression required: global.get of locally defined global", self.offset, @@ -397,7 +312,7 @@ impl ModuleState { // (aka a fuzz bug) if we somehow forget to emit an error somewhere // else. fn insert_ref_func(&mut self, index: u32) { - if self.order == Order::Data { + if self.resources.module.as_mut().is_none() { self.uninserted_funcref = true; } else { self.resources @@ -416,6 +331,7 @@ impl ModuleState { } } + #[cfg_attr(not(feature = "simd"), allow(unused_macro_rules))] macro_rules! define_visit_operator { ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => { $( @@ -486,6 +402,14 @@ impl ModuleState { $self.validate_gc("struct.new_default")?; $self.validator().visit_struct_new_default($type_index) }}; + (@visit $self:ident visit_struct_new_desc $type_index:ident) => {{ + $self.validate_gc("struct.new_desc")?; + $self.validator().visit_struct_new_desc($type_index) + }}; + (@visit $self:ident visit_struct_new_default_desc $type_index:ident) => {{ + $self.validate_gc("struct.new_default_desc")?; + $self.validator().visit_struct_new_default_desc($type_index) + }}; (@visit $self:ident visit_array_new $type_index:ident) => {{ $self.validate_gc("array.new")?; $self.validator().visit_array_new($type_index) @@ -502,6 +426,14 @@ impl ModuleState { $self.validate_gc("ref.i31")?; $self.validator().visit_ref_i31() }}; + (@visit $self:ident visit_extern_convert_any) => {{ + $self.validate_gc("extern.convert_any")?; + $self.validator().visit_extern_convert_any() + }}; + (@visit $self:ident visit_any_convert_extern) => {{ + $self.validate_gc("any.convert_extern")?; + $self.validator().visit_any_convert_extern() + }}; (@visit $self:ident visit_ref_i31_shared) => {{ $self.validate_shared_everything_threads("ref.i31_shared")?; $self.validator().visit_ref_i31_shared() @@ -542,6 +474,12 @@ impl ModuleState { impl<'a> VisitSimdOperator<'a> for VisitConstOperator<'a> { crate::for_each_visit_simd_operator!(define_visit_operator); } + + impl<'a> FrameStack for VisitConstOperator<'a> { + fn current_frame(&self) -> Option<FrameKind> { + Some(self.ops.get_frame(0)?.kind) + } + } } } @@ -562,18 +500,41 @@ pub(crate) struct Module { pub functions: Vec<u32>, pub tags: Vec<CoreTypeId>, pub function_references: Set<u32>, + pub exact_function_imports: Set<u32>, pub imports: IndexMap<(String, String), Vec<EntityType>>, pub exports: IndexMap<String, EntityType>, pub type_size: u32, num_imported_globals: u32, num_imported_functions: u32, + features: WasmFeatures, } impl Module { + pub fn new(features: WasmFeatures) -> Self { + Self { + snapshot: Default::default(), + types: Default::default(), + tables: Default::default(), + memories: Default::default(), + globals: Default::default(), + element_types: Default::default(), + data_count: Default::default(), + functions: Default::default(), + tags: Default::default(), + function_references: Default::default(), + exact_function_imports: Default::default(), + imports: Default::default(), + exports: Default::default(), + type_size: 1, + num_imported_globals: Default::default(), + num_imported_functions: Default::default(), + features, + } + } + pub(crate) fn add_types( &mut self, rec_group: RecGroup, - features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, check_limit: bool, @@ -587,17 +548,16 @@ impl Module { offset, )?; } - self.canonicalize_and_intern_rec_group(features, types, rec_group, offset) + self.canonicalize_and_intern_rec_group(types, rec_group, offset) } pub fn add_import( &mut self, mut import: crate::Import, - features: &WasmFeatures, types: &TypeList, offset: usize, ) -> Result<()> { - let entity = self.check_type_ref(&mut import.ty, features, types, offset)?; + let entity = self.check_type_ref(&mut import.ty, types, offset)?; let (len, max, desc) = match import.ty { TypeRef::Func(type_index) => { @@ -605,20 +565,27 @@ impl Module { self.num_imported_functions += 1; (self.functions.len(), MAX_WASM_FUNCTIONS, "functions") } + TypeRef::FuncExact(type_index) => { + self.functions.push(type_index); + self.exact_function_imports + .insert(self.num_imported_functions); + self.num_imported_functions += 1; + (self.functions.len(), MAX_WASM_FUNCTIONS, "functions") + } TypeRef::Table(ty) => { self.tables.push(ty); - (self.tables.len(), self.max_tables(features), "tables") + (self.tables.len(), self.max_tables(), "tables") } TypeRef::Memory(ty) => { self.memories.push(ty); - (self.memories.len(), self.max_memories(features), "memories") + (self.memories.len(), self.max_memories(), "memories") } TypeRef::Tag(ty) => { self.tags.push(self.types[ty.func_type_idx as usize]); (self.tags.len(), MAX_WASM_TAGS, "tags") } TypeRef::Global(ty) => { - if !features.mutable_global() && ty.mutable { + if !self.features.mutable_global() && ty.mutable { return Err(BinaryReaderError::new( "mutable global support is not enabled", offset, @@ -646,12 +613,11 @@ impl Module { &mut self, name: &str, ty: EntityType, - features: &WasmFeatures, offset: usize, check_limit: bool, types: &TypeList, ) -> Result<()> { - if !features.mutable_global() { + if !self.features.mutable_global() { if let EntityType::Global(global_type) = ty { if global_type.mutable { return Err(BinaryReaderError::new( @@ -683,25 +649,14 @@ impl Module { Ok(()) } - pub fn add_memory( - &mut self, - ty: MemoryType, - features: &WasmFeatures, - offset: usize, - ) -> Result<()> { - self.check_memory_type(&ty, features, offset)?; + pub fn add_memory(&mut self, ty: MemoryType, offset: usize) -> Result<()> { + self.check_memory_type(&ty, offset)?; self.memories.push(ty); Ok(()) } - pub fn add_tag( - &mut self, - ty: TagType, - features: &WasmFeatures, - types: &TypeList, - offset: usize, - ) -> Result<()> { - self.check_tag_type(&ty, features, types, offset)?; + pub fn add_tag(&mut self, ty: TagType, types: &TypeList, offset: usize) -> Result<()> { + self.check_tag_type(&ty, types, offset)?; self.tags.push(self.types[ty.func_type_idx as usize]); Ok(()) } @@ -730,7 +685,6 @@ impl Module { pub fn check_type_ref( &self, type_ref: &mut TypeRef, - features: &WasmFeatures, types: &TypeList, offset: usize, ) -> Result<EntityType> { @@ -739,78 +693,84 @@ impl Module { self.func_type_at(*type_index, types, offset)?; EntityType::Func(self.types[*type_index as usize]) } + TypeRef::FuncExact(type_index) => { + self.func_type_at(*type_index, types, offset)?; + EntityType::FuncExact(self.types[*type_index as usize]) + } TypeRef::Table(t) => { - self.check_table_type(t, features, types, offset)?; + self.check_table_type(t, types, offset)?; EntityType::Table(*t) } TypeRef::Memory(t) => { - self.check_memory_type(t, features, offset)?; + self.check_memory_type(t, offset)?; EntityType::Memory(*t) } TypeRef::Tag(t) => { - self.check_tag_type(t, features, types, offset)?; + self.check_tag_type(t, types, offset)?; EntityType::Tag(self.types[t.func_type_idx as usize]) } TypeRef::Global(t) => { - self.check_global_type(t, features, types, offset)?; + self.check_global_type(t, types, offset)?; EntityType::Global(*t) } }) } - fn check_table_type( - &self, - ty: &mut TableType, - features: &WasmFeatures, - types: &TypeList, - offset: usize, - ) -> Result<()> { + fn check_table_type(&self, ty: &mut TableType, types: &TypeList, offset: usize) -> Result<()> { // The `funcref` value type is allowed all the way back to the MVP, so // don't check it here. if ty.element_type != RefType::FUNCREF { - self.check_ref_type(&mut ty.element_type, features, offset)? + self.check_ref_type(&mut ty.element_type, offset)? } - if ty.table64 && !features.memory64() { - return Err(BinaryReaderError::new( - "memory64 must be enabled for 64-bit tables", + self.check_limits(ty.initial, ty.maximum, offset)?; + if ty.table64 && !self.features().memory64() { + bail!(offset, "memory64 must be enabled for 64-bit tables"); + } + if ty.shared && !self.features().shared_everything_threads() { + bail!( offset, - )); + "shared tables require the shared-everything-threads proposal" + ); } - self.check_limits(ty.initial, ty.maximum, offset)?; - - if ty.shared { - if !features.shared_everything_threads() { - return Err(BinaryReaderError::new( - "shared tables require the shared-everything-threads proposal", - offset, - )); - } - - if !types.reftype_is_shared(ty.element_type) { - return Err(BinaryReaderError::new( - "shared tables must have a shared element type", - offset, - )); + let true_maximum = if ty.table64 { + u64::MAX + } else { + u32::MAX as u64 + }; + let err = format!("table size must be at most {true_maximum:#x} entries"); + if ty.initial > true_maximum { + return Err(BinaryReaderError::new(err, offset)); + } + if let Some(maximum) = ty.maximum { + if maximum > true_maximum { + return Err(BinaryReaderError::new(err, offset)); } } - + if ty.shared && !types.reftype_is_shared(ty.element_type) { + return Err(BinaryReaderError::new( + "shared tables must have a shared element type", + offset, + )); + } Ok(()) } - fn check_memory_type( - &self, - ty: &MemoryType, - features: &WasmFeatures, - offset: usize, - ) -> Result<()> { + fn check_memory_type(&self, ty: &MemoryType, offset: usize) -> Result<()> { self.check_limits(ty.initial, ty.maximum, offset)?; - let (page_size, page_size_log2) = if let Some(page_size_log2) = ty.page_size_log2 { - if !features.custom_page_sizes() { + + if ty.memory64 && !self.features().memory64() { + bail!(offset, "memory64 must be enabled for 64-bit memories"); + } + if ty.shared && !self.features().threads() { + bail!(offset, "threads must be enabled for shared memories"); + } + + let page_size = if let Some(page_size_log2) = ty.page_size_log2 { + if !self.features().custom_page_sizes() { return Err(BinaryReaderError::new( - "the custom page sizes proposal must be enabled to \ - customize a memory's page size", + "the custom page sizes proposal must be enabled to customize a memory's page size", offset, )); } @@ -822,33 +782,18 @@ impl Module { let page_size = 1_u64 << page_size_log2; debug_assert!(page_size.is_power_of_two()); debug_assert!(page_size == DEFAULT_WASM_PAGE_SIZE || page_size == 1); - (page_size, page_size_log2) + page_size } else { let page_size_log2 = 16; debug_assert_eq!(DEFAULT_WASM_PAGE_SIZE, 1 << page_size_log2); - (DEFAULT_WASM_PAGE_SIZE, page_size_log2) + DEFAULT_WASM_PAGE_SIZE }; - let (true_maximum, err) = if ty.memory64 { - if !features.memory64() { - return Err(BinaryReaderError::new( - "memory64 must be enabled for 64-bit memories", - offset, - )); - } - ( - max_wasm_memory64_pages(page_size), - format!( - "memory size must be at most 2**{} pages", - 64 - page_size_log2 - ), - ) + let true_maximum = if ty.memory64 { + max_wasm_memory64_pages(page_size) } else { - let max = max_wasm_memory32_pages(page_size); - ( - max, - format!("memory size must be at most {max} pages (4GiB)"), - ) + max_wasm_memory32_pages(page_size) }; + let err = format!("memory size must be at most {true_maximum:#x} {page_size}-byte pages"); if ty.initial > true_maximum { return Err(BinaryReaderError::new(err, offset)); } @@ -857,19 +802,11 @@ impl Module { return Err(BinaryReaderError::new(err, offset)); } } - if ty.shared { - if !features.threads() { - return Err(BinaryReaderError::new( - "threads must be enabled for shared memories", - offset, - )); - } - if ty.maximum.is_none() { - return Err(BinaryReaderError::new( - "shared memory must have maximum size", - offset, - )); - } + if ty.shared && ty.maximum.is_none() { + return Err(BinaryReaderError::new( + "shared memory must have maximum size", + offset, + )); } Ok(()) } @@ -896,29 +833,20 @@ impl Module { .collect::<Result<_>>() } - fn check_value_type( - &self, - ty: &mut ValType, - features: &WasmFeatures, - offset: usize, - ) -> Result<()> { + fn check_value_type(&self, ty: &mut ValType, offset: usize) -> Result<()> { // The above only checks the value type for features. // We must check it if it's a reference. match ty { - ValType::Ref(rt) => self.check_ref_type(rt, features, offset), - _ => features + ValType::Ref(rt) => self.check_ref_type(rt, offset), + _ => self + .features .check_value_type(*ty) .map_err(|e| BinaryReaderError::new(e, offset)), } } - fn check_ref_type( - &self, - ty: &mut RefType, - features: &WasmFeatures, - offset: usize, - ) -> Result<()> { - features + fn check_ref_type(&self, ty: &mut RefType, offset: usize) -> Result<()> { + self.features .check_ref_type(*ty) .map_err(|e| BinaryReaderError::new(e, offset))?; let mut hty = ty.heap_type(); @@ -931,7 +859,7 @@ impl Module { // Check that the heap type is valid. let type_index = match ty { HeapType::Abstract { .. } => return Ok(()), - HeapType::Concrete(type_index) => type_index, + HeapType::Concrete(type_index) | HeapType::Exact(type_index) => type_index, }; match type_index { UnpackedIndex::Module(idx) => { @@ -946,21 +874,12 @@ impl Module { } } - fn check_tag_type( - &self, - ty: &TagType, - features: &WasmFeatures, - types: &TypeList, - offset: usize, - ) -> Result<()> { - if !features.exceptions() { - return Err(BinaryReaderError::new( - "exceptions proposal not enabled", - offset, - )); + fn check_tag_type(&self, ty: &TagType, types: &TypeList, offset: usize) -> Result<()> { + if !self.features().exceptions() { + bail!(offset, "exceptions proposal not enabled"); } let ty = self.func_type_at(ty.func_type_idx, types, offset)?; - if !ty.results().is_empty() && !features.stack_switching() { + if !ty.results().is_empty() && !self.features.stack_switching() { return Err(BinaryReaderError::new( "invalid exception type: non-empty tag result type", offset, @@ -972,24 +891,21 @@ impl Module { fn check_global_type( &self, ty: &mut GlobalType, - features: &WasmFeatures, types: &TypeList, offset: usize, ) -> Result<()> { - self.check_value_type(&mut ty.content_type, features, offset)?; - if ty.shared { - if !features.shared_everything_threads() { - return Err(BinaryReaderError::new( - "shared globals require the shared-everything-threads proposal", - offset, - )); - } - if !types.valtype_is_shared(ty.content_type) { - return Err(BinaryReaderError::new( - "shared globals must have a shared value type", - offset, - )); - } + self.check_value_type(&mut ty.content_type, offset)?; + if ty.shared && !self.features.shared_everything_threads() { + bail!( + offset, + "shared globals require the shared-everything-threads proposal" + ); + } + if ty.shared && !types.valtype_is_shared(ty.content_type) { + return Err(BinaryReaderError::new( + "shared globals must have a shared value type", + offset, + )); } Ok(()) } @@ -1009,16 +925,16 @@ impl Module { Ok(()) } - pub fn max_tables(&self, features: &WasmFeatures) -> usize { - if features.reference_types() { + pub fn max_tables(&self) -> usize { + if self.features.reference_types() { MAX_WASM_TABLES } else { 1 } } - pub fn max_memories(&self, features: &WasmFeatures) -> usize { - if features.multi_memory() { + pub fn max_memories(&self) -> usize { + if self.features.multi_memory() { MAX_WASM_MEMORIES } else { 1 @@ -1042,7 +958,7 @@ impl Module { }; Ok(match export.kind { - ExternalKind::Func => { + ExternalKind::Func | ExternalKind::FuncExact => { check("function", export.index, self.functions.len())?; self.function_references.insert(export.index); EntityType::Func(self.types[self.functions[export.index as usize] as usize]) @@ -1113,6 +1029,10 @@ impl Module { } impl InternRecGroup for Module { + fn features(&self) -> &WasmFeatures { + &self.features + } + fn add_type_id(&mut self, id: CoreTypeId) { self.types.push(id); } @@ -1129,28 +1049,6 @@ impl InternRecGroup for Module { } } -impl Default for Module { - fn default() -> Self { - Self { - snapshot: Default::default(), - types: Default::default(), - tables: Default::default(), - memories: Default::default(), - globals: Default::default(), - element_types: Default::default(), - data_count: Default::default(), - functions: Default::default(), - tags: Default::default(), - function_references: Default::default(), - imports: Default::default(), - exports: Default::default(), - type_size: 1, - num_imported_globals: Default::default(), - num_imported_functions: Default::default(), - } - } -} - struct OperatorValidatorResources<'a> { module: &'a mut MaybeOwned<Module>, types: &'a TypeList, @@ -1223,6 +1121,14 @@ impl WasmModuleResources for OperatorValidatorResources<'_> { fn is_function_referenced(&self, idx: u32) -> bool { self.module.function_references.contains(&idx) } + + fn has_function_exact_type(&self, idx: u32) -> bool { + if idx >= self.module.num_imported_functions { + true + } else { + self.module.exact_function_imports.contains(&idx) + } + } } /// The implementation of [`WasmModuleResources`] used by @@ -1303,16 +1209,22 @@ impl WasmModuleResources for ValidatorResources { fn is_function_referenced(&self, idx: u32) -> bool { self.0.function_references.contains(&idx) } + + fn has_function_exact_type(&self, idx: u32) -> bool { + if idx >= self.0.num_imported_functions { + true + } else { + self.0.exact_function_imports.contains(&idx) + } + } } const _: () = { - fn assert_send<T: Send>() {} + const fn assert_send<T: Send>() {} // Assert that `ValidatorResources` is Send so function validation // can be parallelizable - fn assert() { - assert_send::<ValidatorResources>(); - } + assert_send::<ValidatorResources>(); }; mod arc { @@ -1331,8 +1243,14 @@ mod arc { } impl<T> MaybeOwned<T> { + pub fn new(val: T) -> MaybeOwned<T> { + MaybeOwned { + inner: Inner::Owned(val), + } + } + #[inline] - fn as_mut(&mut self) -> Option<&mut T> { + pub(crate) fn as_mut(&mut self) -> Option<&mut T> { match &mut self.inner { Inner::Owned(x) => Some(x), Inner::Shared(_) => None, @@ -1377,9 +1295,7 @@ mod arc { impl<T: Default> Default for MaybeOwned<T> { fn default() -> MaybeOwned<T> { - MaybeOwned { - inner: Inner::Owned(T::default()), - } + MaybeOwned::new(T::default()) } } diff --git a/third_party/rust/wasmparser/src/validator/core/canonical.rs b/third_party/rust/wasmparser/src/validator/core/canonical.rs @@ -69,22 +69,22 @@ use super::{RecGroupId, TypeAlloc, TypeList}; use crate::{ - types::{CoreTypeId, TypeIdentifier}, BinaryReaderError, CompositeInnerType, CompositeType, PackedIndex, RecGroup, Result, StorageType, UnpackedIndex, ValType, WasmFeatures, + types::{CoreTypeId, TypeIdentifier}, }; pub(crate) trait InternRecGroup { fn add_type_id(&mut self, id: CoreTypeId); fn type_id_at(&self, idx: u32, offset: usize) -> Result<CoreTypeId>; fn types_len(&self) -> u32; + fn features(&self) -> &WasmFeatures; /// Canonicalize the rec group and return its id and whether it is a new group /// (we added its types to the `TypeAlloc`) or not (we deduplicated it with an /// existing canonical rec group). fn canonicalize_and_intern_rec_group( &mut self, - features: &WasmFeatures, types: &mut TypeAlloc, mut rec_group: RecGroup, offset: usize, @@ -93,19 +93,17 @@ pub(crate) trait InternRecGroup { Self: Sized, { debug_assert!(rec_group.is_explicit_rec_group() || rec_group.types().len() == 1); - if rec_group.is_explicit_rec_group() && !features.gc() { + if rec_group.is_explicit_rec_group() && !self.features().gc() { bail!( offset, "rec group usage requires `gc` proposal to be enabled" ); } - if features.needs_type_canonicalization() { - TypeCanonicalizer::new(self, offset) - .with_features(features) - .canonicalize_rec_group(&mut rec_group)?; + if self.features().needs_type_canonicalization() { + TypeCanonicalizer::new(self, offset).canonicalize_rec_group(&mut rec_group)?; } - let (is_new, rec_group_id) = - types.intern_canonical_rec_group(features.needs_type_canonicalization(), rec_group); + let (is_new, rec_group_id) = types + .intern_canonical_rec_group(self.features().needs_type_canonicalization(), rec_group); let range = &types[rec_group_id]; let start = range.start.index(); let end = range.end.index(); @@ -116,7 +114,8 @@ pub(crate) trait InternRecGroup { debug_assert!(types.get(id).is_some()); self.add_type_id(id); if is_new { - self.check_subtype(rec_group_id, id, features, types, offset)?; + self.check_subtype(rec_group_id, id, types, offset)?; + self.check_descriptors(rec_group_id, id, types, offset)?; } } @@ -127,16 +126,15 @@ pub(crate) trait InternRecGroup { &mut self, rec_group: RecGroupId, id: CoreTypeId, - features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result<()> { let ty = &types[id]; - if !features.gc() && (!ty.is_final || ty.supertype_idx.is_some()) { + if !self.features().gc() && (!ty.is_final || ty.supertype_idx.is_some()) { bail!(offset, "gc proposal must be enabled to use subtypes"); } - self.check_composite_type(&ty.composite_type, features, &types, offset)?; + self.check_composite_type(&ty.composite_type, &types, offset)?; let depth = if let Some(supertype_index) = ty.supertype_idx { debug_assert!(supertype_index.is_canonical()); @@ -165,13 +163,130 @@ pub(crate) trait InternRecGroup { Ok(()) } + fn check_descriptors( + &mut self, + rec_group: RecGroupId, + id: CoreTypeId, + types: &TypeList, + offset: usize, + ) -> Result<()> { + let ty = &types[id].composite_type; + if ty.descriptor_idx.is_some() || ty.describes_idx.is_some() { + if !self.features().custom_descriptors() { + return Err(BinaryReaderError::new( + "custom descriptors proposal must be enabled to use descriptor and describes", + offset, + )); + } + match &ty.inner { + CompositeInnerType::Struct(_) => (), + _ => { + return Err(BinaryReaderError::new( + if ty.descriptor_idx.is_some() { + "descriptor clause on non-struct type" + } else { + "describes clause on non-struct type" + }, + offset, + )); + } + } + } + + let map_cannonical = |idx: PackedIndex| -> Result<CoreTypeId> { + self.at_packed_index(types, rec_group, idx, offset) + }; + + let descriptor_idx = if let Some(i) = ty.descriptor_idx { + Some(map_cannonical(i)?) + } else { + None + }; + let describes_idx = if let Some(i) = ty.describes_idx { + Some(map_cannonical(i)?) + } else { + None + }; + + if let Some(supertype_index) = types[id].supertype_idx { + debug_assert!(supertype_index.is_canonical()); + let sup_id = map_cannonical(supertype_index)?; + if let Some(descriptor_idx) = descriptor_idx { + if types[sup_id].composite_type.descriptor_idx.is_some() + && (types[descriptor_idx].supertype_idx.is_none() + || (map_cannonical(types[descriptor_idx].supertype_idx.unwrap())? + != map_cannonical( + types[sup_id].composite_type.descriptor_idx.unwrap(), + )?)) + { + bail!( + offset, + "supertype of described type must be described by supertype of descriptor", + ); + } + } else if types[sup_id].composite_type.descriptor_idx.is_some() { + bail!( + offset, + "supertype of type without descriptor cannot have descriptor", + ); + } + match ( + types[id].composite_type.describes_idx, + types[sup_id].composite_type.describes_idx, + ) { + (Some(a), Some(b)) => { + let a_id = self.at_packed_index(types, rec_group, a, offset)?; + if types[a_id].supertype_idx.is_none() + || (map_cannonical(types[a_id].supertype_idx.unwrap())? + != map_cannonical(b)?) + { + bail!(offset, "supertype of descriptor does not match"); + } + } + (None, None) => (), + (None, Some(_)) => { + bail!( + offset, + "supertype of non-descriptor type cannot be a descriptor" + ); + } + (Some(_), None) => { + bail!(offset, "supertype of descriptor must be a descriptor"); + } + } + } + if let Some(descriptor_idx) = descriptor_idx { + let describes_idx = if let Some(i) = types[descriptor_idx].composite_type.describes_idx + { + Some(map_cannonical(i)?) + } else { + None + }; + if describes_idx.is_none() || id != describes_idx.unwrap() { + bail!(offset, "descriptor with no matching describes",); + } + } + if let Some(describes_idx) = describes_idx { + let descriptor_idx = if let Some(i) = types[describes_idx].composite_type.descriptor_idx + { + Some(map_cannonical(i)?) + } else { + None + }; + if descriptor_idx.is_none() || id != descriptor_idx.unwrap() { + bail!(offset, "describes with no matching descriptor",); + } + } + Ok(()) + } + fn check_composite_type( &mut self, ty: &CompositeType, - features: &WasmFeatures, types: &TypeList, offset: usize, ) -> Result<()> { + let features = self.features(); let check = |ty: &ValType, shared: bool| { features .check_value_type(*ty) @@ -305,7 +420,6 @@ enum CanonicalizationMode { pub(crate) struct TypeCanonicalizer<'a> { module: &'a dyn InternRecGroup, - features: Option<&'a WasmFeatures>, rec_group_start: u32, rec_group_len: u32, offset: usize, @@ -323,7 +437,6 @@ impl<'a> TypeCanonicalizer<'a> { Self { module, - features: None, rec_group_start, rec_group_len, offset, @@ -332,14 +445,8 @@ impl<'a> TypeCanonicalizer<'a> { } } - pub fn with_features(&mut self, features: &'a WasmFeatures) -> &mut Self { - debug_assert!(self.features.is_none()); - self.features = Some(features); - self - } - fn allow_gc(&self) -> bool { - self.features.map_or(true, |f| f.gc()) + self.module.features().gc() } fn canonicalize_rec_group(&mut self, rec_group: &mut RecGroup) -> Result<()> { @@ -359,6 +466,12 @@ impl<'a> TypeCanonicalizer<'a> { } } + if let Some(idx) = ty.composite_type.describes_idx.as_mut() { + if idx.as_module_index().map_or(false, |i| i >= type_index) { + bail!(self.offset, "forward describes reference"); + } + } + ty.remap_indices(&mut |idx| self.canonicalize_type_index(idx))?; } @@ -388,14 +501,21 @@ impl<'a> TypeCanonicalizer<'a> { // typed function references proposal, only the GC proposal. debug_assert!(self.allow_gc() || self.rec_group_len == 1); let local = index - self.rec_group_start; - if self.allow_gc() && local < self.rec_group_len { - if let Some(id) = PackedIndex::from_rec_group_index(local) { - *ty = id; - return Ok(()); + if local < self.rec_group_len { + if self.allow_gc() { + if let Some(id) = PackedIndex::from_rec_group_index(local) { + *ty = id; + return Ok(()); + } else { + bail!( + self.offset, + "implementation limit: too many types in a recursion group" + ) + } } else { bail!( self.offset, - "implementation limit: too many types in a recursion group" + "unknown type {index}: type index out of bounds because the GC proposal is disabled" ) } } diff --git a/third_party/rust/wasmparser/src/validator/func.rs b/third_party/rust/wasmparser/src/validator/func.rs @@ -1,6 +1,6 @@ use super::operators::{Frame, OperatorValidator, OperatorValidatorAllocations}; use crate::{BinaryReader, Result, ValType, VisitOperator}; -use crate::{FunctionBody, ModuleArity, Operator, WasmFeatures, WasmModuleResources}; +use crate::{FrameStack, FunctionBody, ModuleArity, Operator, WasmFeatures, WasmModuleResources}; /// Resources necessary to perform validation of a function. /// @@ -63,6 +63,42 @@ pub struct FuncValidator<T> { index: u32, } +impl<T: WasmModuleResources> ModuleArity for FuncValidator<T> { + fn sub_type_at(&self, type_idx: u32) -> Option<&crate::SubType> { + self.resources.sub_type_at(type_idx) + } + + fn tag_type_arity(&self, at: u32) -> Option<(u32, u32)> { + let ty = self.resources.tag_at(at)?; + Some(( + u32::try_from(ty.params().len()).unwrap(), + u32::try_from(ty.results().len()).unwrap(), + )) + } + + fn type_index_of_function(&self, func_idx: u32) -> Option<u32> { + self.resources.type_index_of_function(func_idx) + } + + fn func_type_of_cont_type(&self, cont_ty: &crate::ContType) -> Option<&crate::FuncType> { + let id = cont_ty.0.as_core_type_id()?; + Some(self.resources.sub_type_at_id(id).unwrap_func()) + } + + fn sub_type_of_ref_type(&self, rt: &crate::RefType) -> Option<&crate::SubType> { + let id = rt.type_index()?.as_core_type_id()?; + Some(self.resources.sub_type_at_id(id)) + } + + fn control_stack_height(&self) -> u32 { + u32::try_from(self.validator.control_stack_height()).unwrap() + } + + fn label_block(&self, depth: u32) -> Option<(crate::BlockType, crate::FrameKind)> { + self.validator.jump(depth) + } +} + /// External handle to the internal allocations used during function validation. /// /// This is created with either the `Default` implementation or with @@ -88,13 +124,11 @@ impl<T: WasmModuleResources> FuncValidator<T> { // In a debug build, verify that the validator's pops and pushes to and from // the operand stack match the operator's arity. #[cfg(debug_assertions)] - let (pop_push_snapshot, arity) = ( - self.validator.pop_push_count, - reader - .clone() - .read_operator()? - .operator_arity(&self.visitor(reader.original_position())), - ); + let (ops_before, arity) = { + let op = reader.peek_operator(&self.visitor(reader.original_position()))?; + let arity = op.operator_arity(&self.visitor(reader.original_position())); + (reader.clone(), arity) + }; reader.visit_operator(&mut self.visitor(reader.original_position()))??; @@ -105,16 +139,33 @@ impl<T: WasmModuleResources> FuncValidator<T> { "could not calculate operator arity" ))?; - let pop_count = self.validator.pop_push_count.0 - pop_push_snapshot.0; - let push_count = self.validator.pop_push_count.1 - pop_push_snapshot.1; + // Analyze the log to determine the actual, externally visible + // pop/push count. This allows us to hide the fact that we might + // push and then pop a temporary while validating an + // instruction, which shouldn't be visible from the outside. + let mut pop_count = 0; + let mut push_count = 0; + for op in self.validator.pop_push_log.drain(..) { + match op { + true => push_count += 1, + false if push_count > 0 => push_count -= 1, + false => pop_count += 1, + } + } if pop_count != params || push_count != results { - panic!("arity mismatch in validation. Expecting {} operands popped, {} pushed, but got {} popped, {} pushed.", - params, results, pop_count, push_count); + panic!( + "\ +arity mismatch in validation + operator: {:?} + expected: {params} -> {results} + got {pop_count} -> {push_count}", + ops_before.peek_operator(&self.visitor(ops_before.original_position()))?, + ); } } } - self.finish(reader.original_position()) + reader.finish_expression(&self.visitor(reader.original_position())) } /// Reads the local definitions from the given `BinaryReader`, often sourced @@ -162,18 +213,18 @@ impl<T: WasmModuleResources> FuncValidator<T> { /// pub fn validate<R>(validator: &mut FuncValidator<R>, body: &FunctionBody<'_>) -> Result<()> /// where R: WasmModuleResources /// { - /// let mut operator_reader = body.get_binary_reader(); + /// let mut operator_reader = body.get_binary_reader_for_operators()?; /// while !operator_reader.eof() { /// let mut visitor = validator.visitor(operator_reader.original_position()); /// operator_reader.visit_operator(&mut visitor)??; /// } - /// validator.finish(operator_reader.original_position()) + /// operator_reader.finish_expression(&validator.visitor(operator_reader.original_position())) /// } /// ``` pub fn visitor<'this, 'a: 'this>( &'this mut self, offset: usize, - ) -> impl VisitOperator<'a, Output = Result<()>> + ModuleArity + 'this { + ) -> impl VisitOperator<'a, Output = Result<()>> + ModuleArity + FrameStack + 'this { self.validator.with_resources(&self.resources, offset) } @@ -188,18 +239,6 @@ impl<T: WasmModuleResources> FuncValidator<T> { self.validator.with_resources_simd(&self.resources, offset) } - /// Function that must be called after the last opcode has been processed. - /// - /// This will validate that the function was properly terminated with the - /// `end` opcode. If this function is not called then the function will not - /// be properly validated. - /// - /// The `offset` provided to this function will be used as a position for an - /// error if validation fails. - pub fn finish(&mut self, offset: usize) -> Result<()> { - self.validator.finish(offset) - } - /// Returns the Wasm features enabled for this validator. pub fn features(&self) -> &WasmFeatures { &self.validator.features @@ -283,7 +322,8 @@ impl<T: WasmModuleResources> FuncValidator<T> { mod tests { use super::*; use crate::types::CoreTypeId; - use crate::{HeapType, RefType}; + use crate::{HeapType, Parser, RefType, Validator}; + use alloc::vec::Vec; struct EmptyResources(crate::SubType); @@ -295,6 +335,8 @@ mod tests { composite_type: crate::CompositeType { inner: crate::CompositeInnerType::Func(crate::FuncType::new([], [])), shared: false, + descriptor_idx: None, + describes_idx: None, }, }) } @@ -349,6 +391,9 @@ mod tests { fn is_function_referenced(&self, _idx: u32) -> bool { todo!() } + fn has_function_exact_type(&self, _idx: u32) -> bool { + todo!() + } } #[test] @@ -369,18 +414,200 @@ mod tests { assert_eq!(v.operand_stack_height(), 1); // Entering a new control block does not affect the stack height. - assert!(v - .op( + assert!( + v.op( 1, &Operator::Block { blockty: crate::BlockType::Empty } ) - .is_ok()); + .is_ok() + ); assert_eq!(v.operand_stack_height(), 1); // Pushing another constant value makes use have two values on the stack. assert!(v.op(2, &Operator::I32Const { value: 99 }).is_ok()); assert_eq!(v.operand_stack_height(), 2); } + + fn assert_arity(wat: &str, expected: Vec<Vec<(u32, u32)>>) { + let wasm = wat::parse_str(wat).unwrap(); + assert!(Validator::new().validate_all(&wasm).is_ok()); + + let parser = Parser::new(0); + let mut validator = Validator::new(); + + let mut actual = vec![]; + + for payload in parser.parse_all(&wasm) { + let payload = payload.unwrap(); + match payload { + crate::Payload::CodeSectionEntry(body) => { + let mut arity = vec![]; + let mut func_validator = validator + .code_section_entry(&body) + .unwrap() + .into_validator(FuncValidatorAllocations::default()); + let ops = body.get_operators_reader().unwrap(); + for op in ops.into_iter() { + let op = op.unwrap(); + arity.push( + op.operator_arity(&func_validator) + .expect("valid operators should have arity"), + ); + func_validator.op(usize::MAX, &op).expect("should be valid"); + } + actual.push(arity); + } + p => { + validator.payload(&p).unwrap(); + } + } + } + + assert_eq!(actual, expected); + } + + #[test] + fn arity_smoke_test() { + let wasm = r#" + (module + (type $pair (struct (field i32) (field i32))) + + (func $add (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.add + ) + + (func $f (param i32 i32) (result (ref null $pair)) + local.get 0 + local.get 1 + call $add + if (result (ref null $pair)) + local.get 0 + local.get 1 + struct.new $pair + else + unreachable + i32.add + unreachable + end + ) + ) + "#; + + assert_arity( + wasm, + vec![ + // $add + vec![ + // local.get 0 + (0, 1), + // local.get 1 + (0, 1), + // i32.add + (2, 1), + // end + (1, 1), + ], + // $f + vec![ + // local.get 0 + (0, 1), + // local.get 1 + (0, 1), + // call $add + (2, 1), + // if + (1, 0), + // local.get 0 + (0, 1), + // local.get 1 + (0, 1), + // struct.new $pair + (2, 1), + // else + (1, 0), + // unreachable, + (0, 0), + // i32.add + (2, 1), + // unreachable + (0, 0), + // end + (1, 1), + // implicit end + (1, 1), + ], + ], + ); + } + + #[test] + fn arity_if_no_else_same_params_and_results() { + let wasm = r#" + (module + (func (export "f") (param i64 i32) (result i64) + (local.get 0) + (local.get 1) + ;; If with no else. Same number of params and results. + if (param i64) (result i64) + drop + i64.const -1 + end + ) + ) + "#; + + assert_arity( + wasm, + vec![vec![ + // local.get 0 + (0, 1), + // local.get 1 + (0, 1), + // if + (2, 1), + // drop + (1, 0), + // i64.const -1 + (0, 1), + // end + (1, 1), + // implicit end + (1, 1), + ]], + ); + } + + #[test] + fn arity_br_table() { + let wasm = r#" + (module + (func (export "f") (result i32 i32) + i32.const 0 + i32.const 1 + i32.const 2 + br_table 0 0 + ) + ) + "#; + + assert_arity( + wasm, + vec![vec![ + // i32.const 0 + (0, 1), + // i32.const 1 + (0, 1), + // i32.const 2 + (0, 1), + // br_table + (3, 0), + // implicit end + (2, 2), + ]], + ); + } } diff --git a/third_party/rust/wasmparser/src/validator/names.rs b/third_party/rust/wasmparser/src/validator/names.rs @@ -28,11 +28,7 @@ impl KebabStr { /// Returns `None` if the given string is not a valid kebab string. pub fn new<'a>(s: impl AsRef<str> + 'a) -> Option<&'a Self> { let s = Self::new_unchecked(s); - if s.is_kebab_case() { - Some(s) - } else { - None - } + if s.is_kebab_case() { Some(s) } else { None } } pub(crate) fn new_unchecked<'a>(s: impl AsRef<str> + 'a) -> &'a Self { @@ -57,16 +53,21 @@ impl KebabStr { fn is_kebab_case(&self) -> bool { let mut lower = false; let mut upper = false; + let mut is_first = true; + let mut has_digit = false; for c in self.chars() { match c { 'a'..='z' if !lower && !upper => lower = true, 'A'..='Z' if !lower && !upper => upper = true, + '0'..='9' if !lower && !upper && !is_first => has_digit = true, 'a'..='z' if lower => {} 'A'..='Z' if upper => {} - '0'..='9' if lower || upper => {} - '-' if lower || upper => { + '0'..='9' if lower || upper => has_digit = true, + '-' if lower || upper || has_digit => { lower = false; upper = false; + is_first = false; + has_digit = false; } _ => return false, } @@ -412,26 +413,34 @@ impl ComponentNameKind<'_> { impl Ord for ComponentNameKind<'_> { fn cmp(&self, other: &Self) -> Ordering { - match self.kind().cmp(&other.kind()) { - Ordering::Equal => (), - unequal => return unequal, - } + use ComponentNameKind::*; + match (self, other) { - (ComponentNameKind::Label(lhs), ComponentNameKind::Label(rhs)) => lhs.cmp(rhs), - (ComponentNameKind::Constructor(lhs), ComponentNameKind::Constructor(rhs)) => { - lhs.cmp(rhs) + (Label(lhs), Label(rhs)) => lhs.cmp(rhs), + (Constructor(lhs), Constructor(rhs)) => lhs.cmp(rhs), + (Method(lhs) | Static(lhs), Method(rhs) | Static(rhs)) => lhs.cmp(rhs), + + // `[..]l.l` is equivalent to `l` + (Label(plain), Method(method) | Static(method)) + | (Method(method) | Static(method), Label(plain)) + if *plain == method.resource() && *plain == method.method() => + { + Ordering::Equal } - (ComponentNameKind::Method(lhs), ComponentNameKind::Method(rhs)) => lhs.cmp(rhs), - (ComponentNameKind::Method(lhs), ComponentNameKind::Static(rhs)) => lhs.cmp(rhs), - (ComponentNameKind::Static(lhs), ComponentNameKind::Method(rhs)) => lhs.cmp(rhs), - (ComponentNameKind::Static(lhs), ComponentNameKind::Static(rhs)) => lhs.cmp(rhs), - (ComponentNameKind::Interface(lhs), ComponentNameKind::Interface(rhs)) => lhs.cmp(rhs), - (ComponentNameKind::Dependency(lhs), ComponentNameKind::Dependency(rhs)) => { - lhs.cmp(rhs) - } - (ComponentNameKind::Url(lhs), ComponentNameKind::Url(rhs)) => lhs.cmp(rhs), - (ComponentNameKind::Hash(lhs), ComponentNameKind::Hash(rhs)) => lhs.cmp(rhs), - _ => unreachable!("already compared for different kinds above"), + + (Interface(lhs), Interface(rhs)) => lhs.cmp(rhs), + (Dependency(lhs), Dependency(rhs)) => lhs.cmp(rhs), + (Url(lhs), Url(rhs)) => lhs.cmp(rhs), + (Hash(lhs), Hash(rhs)) => lhs.cmp(rhs), + + (Label(_), _) + | (Constructor(_), _) + | (Method(_), _) + | (Static(_), _) + | (Interface(_), _) + | (Dependency(_), _) + | (Url(_), _) + | (Hash(_), _) => self.kind().cmp(&other.kind()), } } } @@ -448,8 +457,18 @@ impl Hash for ComponentNameKind<'_> { match self { Label(name) => (0u8, name).hash(hasher), Constructor(name) => (1u8, name).hash(hasher), - // for hashing method == static - Method(name) | Static(name) => (2u8, name).hash(hasher), + + Method(name) | Static(name) => { + // `l.l` hashes the same as `l` since they're equal above, + // otherwise everything is hashed as `a.b` with a unique + // prefix. + if name.resource() == name.method() { + (0u8, name.resource()).hash(hasher) + } else { + (2u8, name).hash(hasher) + } + } + Interface(name) => (3u8, name).hash(hasher), Dependency(name) => (4u8, name).hash(hasher), Url(name) => (5u8, name).hash(hasher), @@ -460,32 +479,7 @@ impl Hash for ComponentNameKind<'_> { impl PartialEq for ComponentNameKind<'_> { fn eq(&self, other: &ComponentNameKind<'_>) -> bool { - use ComponentNameKind::*; - match (self, other) { - (Label(a), Label(b)) => a == b, - (Label(_), _) => false, - (Constructor(a), Constructor(b)) => a == b, - (Constructor(_), _) => false, - - // method == static for the purposes of hashing so equate them here - // as well. - (Method(a), Method(b)) - | (Static(a), Static(b)) - | (Method(a), Static(b)) - | (Static(a), Method(b)) => a == b, - - (Method(_), _) => false, - (Static(_), _) => false, - - (Interface(a), Interface(b)) => a == b, - (Interface(_), _) => false, - (Dependency(a), Dependency(b)) => a == b, - (Dependency(_), _) => false, - (Url(a), Url(b)) => a == b, - (Url(_), _) => false, - (Hash(a), Hash(b)) => a == b, - (Hash(_), _) => false, - } + self.cmp(other) == Ordering::Equal } } @@ -496,7 +490,7 @@ impl Eq for ComponentNameKind<'_> {} pub struct ResourceFunc<'a>(&'a str); impl<'a> ResourceFunc<'a> { - /// Returns the the underlying string as `a.b` + /// Returns the underlying string as `a.b` pub fn as_str(&self) -> &'a str { self.0 } @@ -506,6 +500,12 @@ impl<'a> ResourceFunc<'a> { let dot = self.0.find('.').unwrap(); KebabStr::new_unchecked(&self.0[..dot]) } + + /// Returns the method name or the `b` in `a.b` + pub fn method(&self) -> &'a KebabStr { + let dot = self.0.find('.').unwrap(); + KebabStr::new_unchecked(&self.0[dot + 1..]) + } } /// An interface name, stored as `a:b/c@1.2.3` @@ -703,7 +703,7 @@ impl<'a> ComponentNameParser<'a> { self.expect_str(":")?; self.take_lowercase_kebab()?; - if self.features.component_model_nested_names() { + if self.features.cm_nested_names() { // Take the remaining package namespaces and name while self.next.starts_with(':') { self.expect_str(":")?; @@ -716,7 +716,7 @@ impl<'a> ComponentNameParser<'a> { self.expect_str("/")?; self.take_kebab()?; - if self.features.component_model_nested_names() { + if self.features.cm_nested_names() { while self.next.starts_with('/') { self.expect_str("/")?; self.take_kebab()?; @@ -944,7 +944,11 @@ mod tests { assert!(KebabStr::new("¶").is_none()); assert!(KebabStr::new("0").is_none()); assert!(KebabStr::new("a0").is_some()); - assert!(KebabStr::new("a-0").is_none()); + assert!(KebabStr::new("a-0").is_some()); + assert!(KebabStr::new("0-a").is_none()); + assert!(KebabStr::new("a-b--c").is_none()); + assert!(KebabStr::new("a0-000-3d4a-54FF").is_some()); + assert!(KebabStr::new("a0-000-3d4A-54Ff").is_none()); } #[test] @@ -954,6 +958,7 @@ mod tests { assert!(parse_kebab_name("[constructor]a").is_some()); assert!(parse_kebab_name("[method]a").is_none()); assert!(parse_kebab_name("[method]a.b").is_some()); + assert!(parse_kebab_name("[method]a-0.b-1").is_some()); assert!(parse_kebab_name("[method]a.b.c").is_none()); assert!(parse_kebab_name("[static]a.b").is_some()); assert!(parse_kebab_name("[static]a").is_none()); diff --git a/third_party/rust/wasmparser/src/validator/operators.rs b/third_party/rust/wasmparser/src/validator/operators.rs @@ -25,13 +25,15 @@ #[cfg(feature = "simd")] use crate::VisitSimdOperator; use crate::{ - limits::MAX_WASM_FUNCTION_LOCALS, AbstractHeapType, BinaryReaderError, BlockType, BrTable, - Catch, ContType, FieldType, FrameKind, FuncType, GlobalType, Handle, HeapType, Ieee32, Ieee64, - MemArg, ModuleArity, RefType, Result, ResumeTable, StorageType, StructType, SubType, TableType, - TryTable, UnpackedIndex, ValType, VisitOperator, WasmFeatures, WasmModuleResources, + AbstractHeapType, BinaryReaderError, BlockType, BrTable, Catch, ContType, FieldType, FrameKind, + FrameStack, FuncType, GlobalType, Handle, HeapType, Ieee32, Ieee64, MemArg, ModuleArity, + RefType, Result, ResumeTable, StorageType, StructType, SubType, TableType, TryTable, + UnpackedIndex, ValType, VisitOperator, WasmFeatures, WasmModuleResources, + limits::MAX_WASM_FUNCTION_LOCALS, }; -use crate::{prelude::*, CompositeInnerType, Ordering}; +use crate::{CompositeInnerType, Ordering, prelude::*}; use core::ops::{Deref, DerefMut}; +use core::{cmp, iter, mem}; #[cfg(feature = "simd")] mod simd; @@ -52,15 +54,15 @@ pub(crate) struct OperatorValidator { /// The `operands` is the current type stack. operands: Vec<MaybeType>, - /// Offset of the `end` instruction which emptied the `control` stack, which - /// must be the end of the function. - end_which_emptied_control: Option<usize>, - /// Whether validation is happening in a shared context. shared: bool, + /// A trace of all operand push/pop operations performed while validating an + /// opcode. This is then compared to the arity that we report to double + /// check that arity report's correctness. `true` is "push" and `false` is + /// "pop". #[cfg(debug_assertions)] - pub(crate) pop_push_count: (u32, u32), + pub(crate) pop_push_log: Vec<bool>, } /// Captures the initialization of non-defaultable locals. @@ -163,7 +165,7 @@ impl LocalInits { // No science was performed in the creation of this number, feel free to change // it if you so like. -const MAX_LOCALS_TO_TRACK: usize = 50; +const MAX_LOCALS_TO_TRACK: u32 = 50; pub(super) struct Locals { // Total number of locals in the function. @@ -185,7 +187,7 @@ pub(super) struct Locals { // `local.{get,set,tee}`. We do a binary search for the index desired, and // it either lies in a "hole" where the maximum index is specified later, // or it's at the end of the list meaning it's out of bounds. - all: Vec<(u32, ValType)>, + uncached: Vec<(u32, ValType)>, } /// A Wasm control flow block on the control flow stack during Wasm validation. @@ -222,7 +224,7 @@ pub struct OperatorValidatorAllocations { operands: Vec<MaybeType>, local_inits: LocalInits, locals_first: Vec<ValType>, - locals_all: Vec<(u32, ValType)>, + locals_uncached: Vec<(u32, ValType)>, } /// Type storage within the validator. @@ -259,7 +261,7 @@ enum MaybeType<T = ValType> { // current expected size. #[test] fn assert_maybe_type_small() { - assert!(core::mem::size_of::<MaybeType>() == 4); + assert!(core::mem::size_of::<MaybeType>() == 8); } impl core::fmt::Display for MaybeType { @@ -327,7 +329,7 @@ impl OperatorValidator { operands, local_inits, locals_first, - locals_all, + locals_uncached, } = allocs; debug_assert!(popped_types_tmp.is_empty()); debug_assert!(control.is_empty()); @@ -335,22 +337,21 @@ impl OperatorValidator { debug_assert!(local_inits.is_empty()); debug_assert!(local_inits.is_empty()); debug_assert!(locals_first.is_empty()); - debug_assert!(locals_all.is_empty()); + debug_assert!(locals_uncached.is_empty()); OperatorValidator { locals: Locals { num_locals: 0, first: locals_first, - all: locals_all, + uncached: locals_uncached, }, local_inits, features: *features, popped_types_tmp, operands, control, - end_which_emptied_control: None, shared: false, #[cfg(debug_assertions)] - pop_push_count: (0, 0), + pop_push_log: vec![], } } @@ -472,6 +473,17 @@ impl OperatorValidator { self.control.len() } + /// Validates a relative jump to the `depth` specified. + /// + /// Returns the type signature of the block that we're jumping to as well + /// as the kind of block if the jump is valid. Otherwise returns an error. + pub(crate) fn jump(&self, depth: u32) -> Option<(BlockType, FrameKind)> { + assert!(!self.control.is_empty()); + let i = (self.control.len() - 1).checked_sub(depth as usize)?; + let frame = &self.control[i]; + Some((frame.block_type, frame.kind)) + } + pub fn get_frame(&self, depth: usize) -> Option<&Frame> { self.control.iter().rev().nth(depth) } @@ -481,7 +493,7 @@ impl OperatorValidator { &'validator mut self, resources: &'resources T, offset: usize, - ) -> impl VisitOperator<'a, Output = Result<()>> + ModuleArity + 'validator + ) -> impl VisitOperator<'a, Output = Result<()>> + ModuleArity + FrameStack + 'validator where T: WasmModuleResources, 'resources: 'validator, @@ -512,28 +524,6 @@ impl OperatorValidator { }) } - pub fn finish(&mut self, offset: usize) -> Result<()> { - if self.control.last().is_some() { - bail!( - offset, - "control frames remain at end of function: END opcode expected" - ); - } - - // The `end` opcode is one byte which means that the `offset` here - // should point just beyond the `end` opcode which emptied the control - // stack. If not that means more instructions were present after the - // control stack was emptied. - if offset != self.end_which_emptied_control.unwrap() + 1 { - return Err(self.err_beyond_end(offset)); - } - Ok(()) - } - - fn err_beyond_end(&self, offset: usize) -> BinaryReaderError { - format_err!(offset, "operators remaining after end of function") - } - pub fn into_allocations(mut self) -> OperatorValidatorAllocations { fn clear<T>(mut tmp: Vec<T>) -> Vec<T> { tmp.clear(); @@ -548,21 +538,21 @@ impl OperatorValidator { self.local_inits }, locals_first: clear(self.locals.first), - locals_all: clear(self.locals.all), + locals_uncached: clear(self.locals.uncached), } } fn record_pop(&mut self) { #[cfg(debug_assertions)] { - self.pop_push_count.0 += 1; + self.pop_push_log.push(false); } } fn record_push(&mut self) { #[cfg(debug_assertions)] { - self.pop_push_count.1 += 1; + self.pop_push_log.push(true); } } } @@ -598,7 +588,7 @@ where if cfg!(debug_assertions) { match maybe_ty { MaybeType::Known(ValType::Ref(r)) => match r.heap_type() { - HeapType::Concrete(index) => { + HeapType::Concrete(index) | HeapType::Exact(index) => { debug_assert!( matches!(index, UnpackedIndex::Id(_)), "only ref types referencing `CoreTypeId`s can \ @@ -630,6 +620,28 @@ where self.push_operand(ref_ty) } + fn push_exact_ref(&mut self, nullable: bool, type_index: u32) -> Result<()> { + let mut heap_ty = HeapType::Exact(UnpackedIndex::Module(type_index)); + + // Canonicalize the module index into an id. + self.resources.check_heap_type(&mut heap_ty, self.offset)?; + debug_assert!(matches!(heap_ty, HeapType::Exact(UnpackedIndex::Id(_)))); + + let ref_ty = RefType::new(nullable, heap_ty).ok_or_else(|| { + format_err!(self.offset, "implementation limit: type index too large") + })?; + + self.push_operand(ref_ty) + } + + fn push_exact_ref_if_available(&mut self, nullable: bool, type_index: u32) -> Result<()> { + if self.features.custom_descriptors() { + self.push_exact_ref(nullable, type_index) + } else { + self.push_concrete_ref(nullable, type_index) + } + } + fn pop_concrete_ref(&mut self, nullable: bool, type_index: u32) -> Result<MaybeType> { let mut heap_ty = HeapType::Concrete(UnpackedIndex::Module(type_index)); @@ -644,6 +656,27 @@ where self.pop_operand(Some(ref_ty.into())) } + fn pop_concrete_or_exact_ref( + &mut self, + nullable: bool, + type_index: u32, + ) -> Result<(MaybeType, bool)> { + let ty = self.pop_concrete_ref(nullable, type_index)?; + let is_exact = match ty { + MaybeType::Known(ValType::Ref(rt)) if rt.is_exact_type_ref() || rt.is_none_ref() => { + let mut heap_ty = HeapType::Exact(UnpackedIndex::Module(type_index)); + self.resources.check_heap_type(&mut heap_ty, self.offset)?; + let expected = RefType::new(nullable, heap_ty).ok_or_else(|| { + format_err!(self.offset, "implementation limit: type index too large") + })?; + self.resources.is_subtype(rt.into(), expected.into()) + } + MaybeType::Bottom => true, + _ => false, + }; + Ok((ty, is_exact)) + } + /// Pop the given label types, checking that they are indeed present on the /// stack, and then push them back on again. fn pop_push_label_types( @@ -717,10 +750,7 @@ where popped: Option<MaybeType>, ) -> Result<MaybeType> { self.operands.extend(popped); - let control = match self.control.last() { - Some(c) => c, - None => return Err(self.err_beyond_end(self.offset)), - }; + let control = self.control.last().unwrap(); let actual = if self.operands.len() == control.height && control.unreachable { MaybeType::Bottom } else { @@ -804,14 +834,8 @@ where actual: ValType, expected: ValType, ) -> Result<(), BinaryReaderError> { - #[cfg(debug_assertions)] - let tmp = self.pop_push_count; self.push_operand(actual)?; self.pop_operand(Some(expected))?; - #[cfg(debug_assertions)] - { - self.pop_push_count = tmp; - } Ok(()) } @@ -820,21 +844,20 @@ where &mut self, expected_tys: impl PreciseIterator<Item = ValType> + 'resources, ) -> Result<()> { - debug_assert!(self.popped_types_tmp.is_empty()); - self.popped_types_tmp.reserve(expected_tys.len()); - #[cfg(debug_assertions)] - let tmp = self.pop_push_count; + let mut popped_types_tmp = mem::take(&mut self.popped_types_tmp); + debug_assert!(popped_types_tmp.is_empty()); + popped_types_tmp.reserve(expected_tys.len()); + for expected_ty in expected_tys.rev() { let actual_ty = self.pop_operand(Some(expected_ty))?; - self.popped_types_tmp.push(actual_ty); + popped_types_tmp.push(actual_ty); } - for ty in self.inner.popped_types_tmp.drain(..).rev() { - self.inner.operands.push(ty.into()); - } - #[cfg(debug_assertions)] - { - self.pop_push_count = tmp; + for ty in popped_types_tmp.drain(..).rev() { + self.push_operand(ty)?; } + + debug_assert!(self.popped_types_tmp.is_empty()); + self.popped_types_tmp = popped_types_tmp; Ok(()) } @@ -914,10 +937,7 @@ where /// Flags the current control frame as unreachable, additionally truncating /// the currently active operand stack. fn unreachable(&mut self) -> Result<()> { - let control = match self.control.last_mut() { - Some(frame) => frame, - None => return Err(self.err_beyond_end(self.offset)), - }; + let control = self.control.last_mut().unwrap(); control.unreachable = true; let new_height = control.height; self.operands.truncate(new_height); @@ -957,10 +977,7 @@ where fn pop_ctrl(&mut self) -> Result<Frame> { // Read the expected type and expected height of the operand stack the // end of the frame. - let frame = match self.control.last() { - Some(f) => f, - None => return Err(self.err_beyond_end(self.offset)), - }; + let frame = self.control.last().unwrap(); let ty = frame.block_type; let height = frame.height; let init_height = frame.init_height; @@ -992,14 +1009,8 @@ where /// Returns the type signature of the block that we're jumping to as well /// as the kind of block if the jump is valid. Otherwise returns an error. fn jump(&self, depth: u32) -> Result<(BlockType, FrameKind)> { - if self.control.is_empty() { - return Err(self.err_beyond_end(self.offset)); - } - match (self.control.len() - 1).checked_sub(depth as usize) { - Some(i) => { - let frame = &self.control[i]; - Ok((frame.block_type, frame.kind)) - } + match self.inner.jump(depth) { + Some(tup) => Ok(tup), None => bail!(self.offset, "unknown label: branch depth too large"), } } @@ -1020,7 +1031,7 @@ where if memarg.align > memarg.max_align { bail!( self.offset, - "malformed memop alignment: alignment must not be larger than natural" + "invalid memop alignment: alignment must not be larger than natural" ); } if index_ty == ValType::I32 && memarg.offset > u64::from(u32::MAX) { @@ -1105,18 +1116,12 @@ where self.pop_operand(Some(ty))?; } - // Match the results with this function's, but don't include in pop/push counts. - #[cfg(debug_assertions)] - let tmp = self.pop_push_count; + // Match the results with this function's. for &ty in ty.results() { debug_assert_type_indices_are_ids(ty); self.push_operand(ty)?; } self.check_return()?; - #[cfg(debug_assertions)] - { - self.pop_push_count = tmp; - } Ok(()) } @@ -1168,9 +1173,7 @@ where /// Validates a `return` instruction, popping types from the operand /// stack that the function needs. fn check_return(&mut self) -> Result<()> { - if self.control.is_empty() { - return Err(self.err_beyond_end(self.offset)); - } + assert!(!self.control.is_empty()); for ty in self.results(self.control[0].block_type)?.rev() { self.pop_operand(Some(ty))?; } @@ -1181,9 +1184,7 @@ where /// Check that the given type has the same result types as the current /// function's results. fn check_func_type_same_results(&self, callee_ty: &FuncType) -> Result<()> { - if self.control.is_empty() { - return Err(self.err_beyond_end(self.offset)); - } + assert!(!self.control.is_empty()); let caller_rets = self.results(self.control[0].block_type)?; if callee_ty.results().len() != caller_rets.len() || !caller_rets @@ -1333,6 +1334,120 @@ where self.push_operand(sub_ty) } + /// Common helper to check type hierarchy for `br_on_cast` operators. + fn check_br_on_cast_type_hierarchy( + &self, + from_ref_type: RefType, + to_ref_type: RefType, + ) -> Result<()> { + if self.features.custom_descriptors() { + // The constraint C |- rt_2 <: rt_1 on branching cast instructions + // before the custom descriptors proposal is relaxed to the constraint + // that rt_1 and rt_2 share some arbitrary valid supertype rt', i.e. + // that rt_1 and rt_2 must be in the same heap type hierarchy. + let from_ref_type_top = self.resources.top_type(&from_ref_type.heap_type()); + let to_ref_type_top = self.resources.top_type(&to_ref_type.heap_type()); + if from_ref_type_top != to_ref_type_top { + bail!( + self.offset, + "type mismatch: {from_ref_type} and {to_ref_type} have different heap type hierarchies" + ); + } + return Ok(()); + } + + if !self + .resources + .is_subtype(to_ref_type.into(), from_ref_type.into()) + { + bail!( + self.offset, + "type mismatch: expected {from_ref_type}, found {to_ref_type}" + ); + } + Ok(()) + } + + /// Common helper to check descriptor for the specified type. + fn check_descriptor(&self, heap_type: HeapType) -> Result<u32> { + Ok(match heap_type { + HeapType::Exact(idx) | HeapType::Concrete(idx) => { + if let Some(descriptor_idx) = self + .sub_type_at(idx.as_module_index().unwrap())? + .composite_type + .descriptor_idx + { + u32::try_from(crate::validator::types::TypeIdentifier::index( + &descriptor_idx.as_core_type_id().unwrap(), + )) + .unwrap() + } else { + bail!(self.offset, "cast target must have descriptor") + } + } + _ => bail!(self.offset, "unexpected heap type"), + }) + } + + fn check_maybe_exact_descriptor_ref(&mut self, heap_type: HeapType) -> Result<bool> { + let descriptor_idx = self.check_descriptor(heap_type)?; + let (ty, _is_exact) = self.pop_concrete_or_exact_ref(true, descriptor_idx)?; + let is_exact = if let HeapType::Exact(_) = heap_type { + let mut descriptor_ty = HeapType::Exact(UnpackedIndex::Module(descriptor_idx)); + self.resources + .check_heap_type(&mut descriptor_ty, self.offset)?; + let descriptor_ty = ValType::Ref( + RefType::new(true, descriptor_ty) + .expect("existing heap types should be within our limits"), + ); + + match ty { + MaybeType::Known(actual) if !self.resources.is_subtype(actual, descriptor_ty) => { + bail!( + self.offset, + "type mismatch: expected descriptor of exact type {descriptor_ty} found {actual}", + ); + } + _ => (), + } + true + } else { + false + }; + Ok(is_exact) + } + + /// Common helper for both nullable and non-nullable variants of `ref.cast_desc` + /// instructions. + fn check_ref_cast_desc(&mut self, nullable: bool, heap_type: HeapType) -> Result<()> { + let is_exact = self.check_maybe_exact_descriptor_ref(heap_type)?; + + self.check_downcast(nullable, heap_type)?; + + let idx = { + let mut heap_type = heap_type; + self.resources + .check_heap_type(&mut heap_type, self.offset)?; + match heap_type { + HeapType::Concrete(index) | HeapType::Exact(index) => { + index.pack().ok_or_else(|| { + BinaryReaderError::new( + "implementation limit: type index too large", + self.offset, + ) + })? + } + _ => panic!(), + } + }; + + self.push_operand(if is_exact { + RefType::exact(nullable, idx) + } else { + RefType::concrete(nullable, idx) + }) + } + /// Common helper for checking the types of globals accessed with atomic RMW /// instructions, which only allow `i32` and `i64`. fn check_atomic_global_rmw_ty(&self, global_index: u32) -> Result<ValType> { @@ -1625,43 +1740,58 @@ where // Pop the continuation reference. match self.label_types(block.0, block.1)?.last() { Some(ValType::Ref(rt)) if rt.is_concrete_type_ref() => { - let sub_ty = self.resources.sub_type_at_id(rt.type_index().unwrap().as_core_type_id().expect("canonicalized index")); - let new_cont = - if let CompositeInnerType::Cont(cont) = &sub_ty.composite_type.inner { - cont - } else { - bail!(self.offset, "non-continuation type"); - }; + let sub_ty = self.resources.sub_type_at_id( + rt.type_index() + .unwrap() + .as_core_type_id() + .expect("canonicalized index"), + ); + let new_cont = if let CompositeInnerType::Cont(cont) = + &sub_ty.composite_type.inner + { + cont + } else { + bail!(self.offset, "non-continuation type"); + }; let new_func_ty = self.func_type_of_cont_type(&new_cont); // Check that (ts2' -> ts2) <: $ft - if new_func_ty.params().len() != tag_ty.results().len() || !self.is_subtype_many(new_func_ty.params(), tag_ty.results()) - || old_func_ty.results().len() != new_func_ty.results().len() || !self.is_subtype_many(old_func_ty.results(), new_func_ty.results()) { + if new_func_ty.params().len() != tag_ty.results().len() + || !self.is_subtype_many(new_func_ty.params(), tag_ty.results()) + || old_func_ty.results().len() != new_func_ty.results().len() + || !self + .is_subtype_many(old_func_ty.results(), new_func_ty.results()) + { bail!(self.offset, "type mismatch in continuation type") } let expected_nargs = tag_ty.params().len() + 1; - let actual_nargs = self - .label_types(block.0, block.1)? - .len(); + let actual_nargs = self.label_types(block.0, block.1)?.len(); if actual_nargs != expected_nargs { - bail!(self.offset, "type mismatch: expected {expected_nargs} label result(s), but label is annotated with {actual_nargs} results") + bail!( + self.offset, + "type mismatch: expected {expected_nargs} label result(s), but label is annotated with {actual_nargs} results" + ) } - let labeltys = self - .label_types(block.0, block.1)? - .take(expected_nargs - 1); + let labeltys = + self.label_types(block.0, block.1)?.take(expected_nargs - 1); // Check that ts1'' <: ts1'. for (tagty, &lblty) in labeltys.zip(tag_ty.params()) { if !self.resources.is_subtype(lblty, tagty) { - bail!(self.offset, "type mismatch between tag type and label type") + bail!( + self.offset, + "type mismatch between tag type and label type" + ) } } } Some(ty) => { bail!(self.offset, "type mismatch: {}", ty_to_str(ty)) } - _ => bail!(self.offset, - "type mismatch: instruction requires continuation reference type but label has none") + _ => bail!( + self.offset, + "type mismatch: instruction requires continuation reference type but label has none" + ), } } Handle::OnSwitch { tag } => { @@ -1701,6 +1831,13 @@ where self.push_operand(ValType::I64)?; Ok(()) } + + fn check_enabled(&self, flag: bool, desc: &str) -> Result<()> { + if flag { + return Ok(()); + } + bail!(self.offset, "{desc} support is not enabled"); + } } pub fn ty_to_str(ty: ValType) -> &'static str { @@ -1726,28 +1863,27 @@ struct WasmProposalValidator<'validator, 'resources, T>( OperatorValidatorTemp<'validator, 'resources, T>, ); -impl<T> WasmProposalValidator<'_, '_, T> { - fn check_enabled(&self, flag: bool, desc: &str) -> Result<()> { - if flag { - return Ok(()); - } - bail!(self.0.offset, "{desc} support is not enabled"); - } -} - +#[cfg_attr(not(feature = "simd"), allow(unused_macro_rules))] macro_rules! validate_proposal { ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => { $( fn $visit(&mut self $($(,$arg: $argty)*)?) -> Result<()> { - validate_proposal!(validate self $proposal); + validate_proposal!(validate self $proposal / $op); self.0.$visit($( $($arg),* )?) } )* }; - (validate self mvp) => {}; - (validate $self:ident $proposal:ident) => { - $self.check_enabled($self.0.features.$proposal(), validate_proposal!(desc $proposal))? + (validate self mvp / $op:ident) => {}; + + // These opcodes are handled specially below as they were introduced in the + // bulk memory proposal but are gated by the `bulk_memory_opt` + // "sub-proposal". + (validate self $proposal:ident / MemoryFill) => {}; + (validate self $proposal:ident / MemoryCopy) => {}; + + (validate $self:ident $proposal:ident / $op:ident) => { + $self.0.check_enabled($self.0.features.$proposal(), validate_proposal!(desc $proposal))? }; (desc simd) => ("SIMD"); @@ -1766,6 +1902,7 @@ macro_rules! validate_proposal { (desc legacy_exceptions) => ("legacy exceptions"); (desc stack_switching) => ("stack switching"); (desc wide_arithmetic) => ("wide arithmetic"); + (desc custom_descriptors) => ("custom descriptors operations"); } impl<'a, T> VisitOperator<'a> for WasmProposalValidator<'_, '_, T> @@ -1964,10 +2101,8 @@ where for ty in self.results(frame.block_type)? { self.push_operand(ty)?; } - - if self.control.is_empty() && self.end_which_emptied_control.is_none() { + if self.control.is_empty() { assert_ne!(self.offset, 0); - self.end_which_emptied_control = Some(self.offset); } Ok(()) } @@ -2092,6 +2227,10 @@ where self.push_operand(ty)?; Ok(()) } + fn visit_typed_select_multi(&mut self, tys: Vec<ValType>) -> Self::Output { + debug_assert!(tys.len() != 1); + bail!(self.offset, "invalid result arity"); + } fn visit_local_get(&mut self, local_index: u32) -> Self::Output { let ty = self.local(local_index)?; debug_assert_type_indices_are_ids(ty); @@ -2128,7 +2267,10 @@ where let ty = self.global_type_at(global_index)?.content_type; let supertype = RefType::ANYREF.into(); if !(ty == ValType::I32 || ty == ValType::I64 || self.resources.is_subtype(ty, supertype)) { - bail!(self.offset, "invalid type: `global.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`"); + bail!( + self.offset, + "invalid type: `global.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`" + ); } Ok(()) } @@ -2150,7 +2292,10 @@ where let ty = self.global_type_at(global_index)?.content_type; let supertype = RefType::ANYREF.into(); if !(ty == ValType::I32 || ty == ValType::I64 || self.resources.is_subtype(ty, supertype)) { - bail!(self.offset, "invalid type: `global.atomic.set` only allows `i32`, `i64` and subtypes of `anyref`"); + bail!( + self.offset, + "invalid type: `global.atomic.set` only allows `i32`, `i64` and subtypes of `anyref`" + ); } Ok(()) } @@ -2204,7 +2349,10 @@ where || ty == ValType::I64 || self.resources.is_subtype(ty, RefType::ANYREF.into())) { - bail!(self.offset, "invalid type: `global.atomic.rmw.xchg` only allows `i32`, `i64` and subtypes of `anyref`"); + bail!( + self.offset, + "invalid type: `global.atomic.rmw.xchg` only allows `i32`, `i64` and subtypes of `anyref`" + ); } self.check_unary_op(ty) } @@ -2218,7 +2366,10 @@ where || ty == ValType::I64 || self.resources.is_subtype(ty, RefType::EQREF.into())) { - bail!(self.offset, "invalid type: `global.atomic.rmw.cmpxchg` only allows `i32`, `i64` and subtypes of `eqref`"); + bail!( + self.offset, + "invalid type: `global.atomic.rmw.cmpxchg` only allows `i32`, `i64` and subtypes of `eqref`" + ); } self.check_binary_op(ty) } @@ -3069,11 +3220,16 @@ where } let index = UnpackedIndex::Id(type_id); - let ty = ValType::Ref( - RefType::new(false, HeapType::Concrete(index)).ok_or_else(|| { - BinaryReaderError::new("implementation limit: type index too large", self.offset) - })?, - ); + let hty = if self.features.custom_descriptors() + && self.resources.has_function_exact_type(function_index) + { + HeapType::Exact(index) + } else { + HeapType::Concrete(index) + }; + let ty = ValType::Ref(RefType::new(false, hty).ok_or_else(|| { + BinaryReaderError::new("implementation limit: type index too large", self.offset) + })?); self.push_operand(ty)?; Ok(()) } @@ -3111,6 +3267,7 @@ where Ok(()) } fn visit_memory_copy(&mut self, dst: u32, src: u32) -> Self::Output { + self.check_enabled(self.features.bulk_memory_opt(), "bulk memory")?; let dst_ty = self.check_memory_index(dst)?; let src_ty = self.check_memory_index(src)?; @@ -3128,6 +3285,7 @@ where Ok(()) } fn visit_memory_fill(&mut self, mem: u32) -> Self::Output { + self.check_enabled(self.features.bulk_memory_opt(), "bulk memory")?; let ty = self.check_memory_index(mem)?; self.pop_operand(Some(ty))?; self.pop_operand(Some(ValType::I32))?; @@ -3280,14 +3438,32 @@ where Ok(()) } fn visit_struct_new(&mut self, struct_type_index: u32) -> Self::Output { + if let Some(_) = self + .sub_type_at(struct_type_index)? + .composite_type + .descriptor_idx + { + bail!( + self.offset, + "type with descriptor requires descriptor allocation: `struct.new` with type {struct_type_index}" + ); + } + let struct_ty = self.struct_type_at(struct_type_index)?; for ty in struct_ty.fields.iter().rev() { self.pop_operand(Some(ty.element_type.unpack()))?; } - self.push_concrete_ref(false, struct_type_index)?; + self.push_exact_ref_if_available(false, struct_type_index)?; Ok(()) } fn visit_struct_new_default(&mut self, type_index: u32) -> Self::Output { + if let Some(_) = self.sub_type_at(type_index)?.composite_type.descriptor_idx { + bail!( + self.offset, + "type with descriptor requires descriptor allocation: `struct.new_default` with type {type_index}" + ); + } + let ty = self.struct_type_at(type_index)?; for field in ty.fields.iter() { let val_ty = field.element_type.unpack(); @@ -3298,7 +3474,51 @@ where ); } } - self.push_concrete_ref(false, type_index)?; + self.push_exact_ref_if_available(false, type_index)?; + Ok(()) + } + fn visit_struct_new_desc(&mut self, struct_type_index: u32) -> Self::Output { + if let Some(descriptor_idx) = self + .sub_type_at(struct_type_index)? + .composite_type + .descriptor_idx + { + let ty = ValType::Ref(RefType::exact(true, descriptor_idx)); + self.pop_operand(Some(ty))?; + } else { + bail!( + self.offset, + "invalid `struct.new_desc`: type {struct_type_index} is not described" + ); + } + let struct_ty = self.struct_type_at(struct_type_index)?; + for ty in struct_ty.fields.iter().rev() { + self.pop_operand(Some(ty.element_type.unpack()))?; + } + self.push_exact_ref_if_available(false, struct_type_index)?; + Ok(()) + } + fn visit_struct_new_default_desc(&mut self, type_index: u32) -> Self::Output { + if let Some(descriptor_idx) = self.sub_type_at(type_index)?.composite_type.descriptor_idx { + let ty = ValType::Ref(RefType::exact(true, descriptor_idx)); + self.pop_operand(Some(ty))?; + } else { + bail!( + self.offset, + "invalid `struct.new_default_desc`: type {type_index} is not described" + ); + } + let ty = self.struct_type_at(type_index)?; + for field in ty.fields.iter() { + let val_ty = field.element_type.unpack(); + if !val_ty.is_defaultable() { + bail!( + self.offset, + "invalid `struct.new_default`: {val_ty} field is not defaultable" + ); + } + } + self.push_exact_ref_if_available(false, type_index)?; Ok(()) } fn visit_struct_get(&mut self, struct_type_index: u32, field_index: u32) -> Self::Output { @@ -3519,7 +3739,7 @@ where let array_ty = self.array_type_at(type_index)?; self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(array_ty.element_type.unpack()))?; - self.push_concrete_ref(false, type_index) + self.push_exact_ref_if_available(false, type_index) } fn visit_array_new_default(&mut self, type_index: u32) -> Self::Output { let ty = self.array_type_at(type_index)?; @@ -3531,7 +3751,7 @@ where ); } self.pop_operand(Some(ValType::I32))?; - self.push_concrete_ref(false, type_index) + self.push_exact_ref_if_available(false, type_index) } fn visit_array_new_fixed(&mut self, type_index: u32, n: u32) -> Self::Output { let array_ty = self.array_type_at(type_index)?; @@ -3539,7 +3759,7 @@ where for _ in 0..n { self.pop_operand(Some(elem_ty))?; } - self.push_concrete_ref(false, type_index) + self.push_exact_ref_if_available(false, type_index) } fn visit_array_new_data(&mut self, type_index: u32, data_index: u32) -> Self::Output { let array_ty = self.array_type_at(type_index)?; @@ -3554,7 +3774,7 @@ where self.check_data_segment(data_index)?; self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ValType::I32))?; - self.push_concrete_ref(false, type_index) + self.push_exact_ref_if_available(false, type_index) } fn visit_array_new_elem(&mut self, type_index: u32, elem_index: u32) -> Self::Output { let array_ty = self.array_type_at(type_index)?; @@ -3578,7 +3798,7 @@ where } self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ValType::I32))?; - self.push_concrete_ref(false, type_index) + self.push_exact_ref_if_available(false, type_index) } fn visit_array_get(&mut self, type_index: u32) -> Self::Output { let array_ty = self.array_type_at(type_index)?; @@ -3902,15 +4122,7 @@ where self.resources .check_ref_type(&mut to_ref_type, self.offset)?; - if !self - .resources - .is_subtype(to_ref_type.into(), from_ref_type.into()) - { - bail!( - self.offset, - "type mismatch: expected {from_ref_type}, found {to_ref_type}" - ); - } + self.check_br_on_cast_type_hierarchy(from_ref_type, to_ref_type)?; let (block_ty, frame_kind) = self.jump(relative_depth)?; let mut label_types = self.label_types(block_ty, frame_kind)?; @@ -3946,15 +4158,7 @@ where self.resources .check_ref_type(&mut to_ref_type, self.offset)?; - if !self - .resources - .is_subtype(to_ref_type.into(), from_ref_type.into()) - { - bail!( - self.offset, - "type mismatch: expected {from_ref_type}, found {to_ref_type}" - ); - } + self.check_br_on_cast_type_hierarchy(from_ref_type, to_ref_type)?; let (block_ty, frame_kind) = self.jump(relative_depth)?; let mut label_tys = self.label_types(block_ty, frame_kind)?; @@ -4236,6 +4440,107 @@ where fn visit_i64_mul_wide_u(&mut self) -> Result<()> { self.check_i64_mul_wide() } + + fn visit_ref_get_desc(&mut self, type_index: u32) -> Self::Output { + let (_, is_exact) = self.pop_concrete_or_exact_ref(true, type_index)?; + match self.sub_type_at(type_index)?.composite_type.descriptor_idx { + Some(descriptor_idx) => { + let ref_ty = if is_exact { + RefType::exact(false, descriptor_idx) + } else { + RefType::concrete(false, descriptor_idx) + }; + self.push_operand(ref_ty) + } + None => bail!(self.offset, "expected type with descriptor"), + } + } + + fn visit_ref_cast_desc_non_null(&mut self, heap_type: HeapType) -> Self::Output { + self.check_ref_cast_desc(false, heap_type) + } + fn visit_ref_cast_desc_nullable(&mut self, heap_type: HeapType) -> Self::Output { + self.check_ref_cast_desc(true, heap_type) + } + fn visit_br_on_cast_desc( + &mut self, + relative_depth: u32, + mut from_ref_type: RefType, + mut to_ref_type: RefType, + ) -> Self::Output { + let described_ty = to_ref_type.heap_type(); + + self.resources + .check_ref_type(&mut from_ref_type, self.offset)?; + self.resources + .check_ref_type(&mut to_ref_type, self.offset)?; + + self.check_br_on_cast_type_hierarchy(from_ref_type, to_ref_type)?; + + self.check_maybe_exact_descriptor_ref(described_ty)?; + + let (block_ty, frame_kind) = self.jump(relative_depth)?; + let mut label_types = self.label_types(block_ty, frame_kind)?; + + match label_types.next_back() { + Some(label_ty) if self.resources.is_subtype(to_ref_type.into(), label_ty) => { + self.pop_operand(Some(from_ref_type.into()))?; + } + Some(label_ty) => bail!( + self.offset, + "type mismatch: casting to type {to_ref_type}, but it does not match \ + label result type {label_ty}" + ), + None => bail!( + self.offset, + "type mismatch: br_on_cast to label with empty types, must have a reference type" + ), + }; + + self.pop_push_label_types(label_types)?; + let diff_ty = RefType::difference(from_ref_type, to_ref_type); + self.push_operand(diff_ty)?; + Ok(()) + } + fn visit_br_on_cast_desc_fail( + &mut self, + relative_depth: u32, + mut from_ref_type: RefType, + mut to_ref_type: RefType, + ) -> Self::Output { + let described_ty = to_ref_type.heap_type(); + + self.resources + .check_ref_type(&mut from_ref_type, self.offset)?; + self.resources + .check_ref_type(&mut to_ref_type, self.offset)?; + + self.check_br_on_cast_type_hierarchy(from_ref_type, to_ref_type)?; + + self.check_maybe_exact_descriptor_ref(described_ty)?; + + let (block_ty, frame_kind) = self.jump(relative_depth)?; + let mut label_tys = self.label_types(block_ty, frame_kind)?; + + let diff_ty = RefType::difference(from_ref_type, to_ref_type); + match label_tys.next_back() { + Some(label_ty) if self.resources.is_subtype(diff_ty.into(), label_ty) => { + self.pop_operand(Some(from_ref_type.into()))?; + } + Some(label_ty) => bail!( + self.offset, + "type mismatch: expected label result type {label_ty}, found {diff_ty}" + ), + None => bail!( + self.offset, + "type mismatch: expected a reference type, found nothing" + ), + } + + self.pop_push_label_types(label_tys)?; + self.push_operand(to_ref_type)?; + Ok(()) + } } #[derive(Clone, Debug)] @@ -4294,20 +4599,23 @@ impl Locals { /// definition is unsuccessful in case the amount of total variables /// after definition exceeds the allowed maximum number. fn define(&mut self, count: u32, ty: ValType) -> bool { + if count == 0 { + return true; + } + let vacant_first = MAX_LOCALS_TO_TRACK.saturating_sub(self.num_locals); match self.num_locals.checked_add(count) { - Some(n) => self.num_locals = n, + Some(num_locals) if num_locals > MAX_WASM_FUNCTION_LOCALS => return false, None => return false, + Some(num_locals) => self.num_locals = num_locals, + }; + let push_to_first = cmp::min(vacant_first, count); + self.first + .extend(iter::repeat(ty).take(push_to_first as usize)); + let num_uncached = count - push_to_first; + if num_uncached > 0 { + let max_uncached_idx = self.num_locals - 1; + self.uncached.push((max_uncached_idx, ty)); } - if self.num_locals > (MAX_WASM_FUNCTION_LOCALS as u32) { - return false; - } - for _ in 0..count { - if self.first.len() >= MAX_LOCALS_TO_TRACK { - break; - } - self.first.push(ty); - } - self.all.push((self.num_locals - 1, ty)); true } @@ -4326,17 +4634,17 @@ impl Locals { } fn get_bsearch(&self, idx: u32) -> Option<ValType> { - match self.all.binary_search_by_key(&idx, |(idx, _)| *idx) { + match self.uncached.binary_search_by_key(&idx, |(idx, _)| *idx) { // If this index would be inserted at the end of the list, then the // index is out of bounds and we return an error. - Err(i) if i == self.all.len() => None, + Err(i) if i == self.uncached.len() => None, // If `Ok` is returned we found the index exactly, or if `Err` is // returned the position is the one which is the least index // greater that `idx`, which is still the type of `idx` according // to our "compressed" representation. In both cases we access the // list at index `i`. - Ok(i) | Err(i) => Some(self.all[i].1), + Ok(i) | Err(i) => Some(self.uncached[i].1), } } } @@ -4377,3 +4685,12 @@ where self.0.jump(depth).ok() } } + +impl<R> FrameStack for WasmProposalValidator<'_, '_, R> +where + R: WasmModuleResources, +{ + fn current_frame(&self) -> Option<FrameKind> { + Some(self.0.control.last()?.kind) + } +} diff --git a/third_party/rust/wasmparser/src/validator/operators/simd.rs b/third_party/rust/wasmparser/src/validator/operators/simd.rs @@ -1,6 +1,6 @@ use super::OperatorValidatorTemp; use crate::{MemArg, Result, ValType, WasmModuleResources}; -use crate::{VisitSimdOperator, V128}; +use crate::{V128, VisitSimdOperator}; impl<'resources, R> OperatorValidatorTemp<'_, 'resources, R> where diff --git a/third_party/rust/wasmparser/src/validator/types.rs b/third_party/rust/wasmparser/src/validator/types.rs @@ -5,8 +5,8 @@ use super::core::Module; use crate::validator::component::ComponentState; #[cfg(feature = "component-model")] use crate::validator::component_types::{ComponentTypeAlloc, ComponentTypeList}; -use crate::{collections::map::Entry, AbstractHeapType}; -use crate::{prelude::*, CompositeInnerType}; +use crate::{AbstractHeapType, collections::map::Entry}; +use crate::{CompositeInnerType, prelude::*}; use crate::{ Export, ExternalKind, GlobalType, Import, Matches, MemoryType, PackedIndex, RecGroup, RefType, Result, SubType, TableType, TypeRef, UnpackedIndex, ValType, WithRecGroup, @@ -46,12 +46,15 @@ pub trait TypeIdentifier: core::fmt::Debug + Copy + Eq + Sized + 'static { /// A trait shared by all types within a `Types`. /// -/// This is the data that can be retreived by indexing with the associated +/// This is the data that can be retrieved by indexing with the associated /// [`TypeIdentifier`]. pub trait TypeData: core::fmt::Debug { /// The identifier for this type data. type Id: TypeIdentifier<Data = Self>; + /// Is this type a core sub type (or rec group of sub types)? + const IS_CORE_SUB_TYPE: bool; + /// Get the info for this type. #[doc(hidden)] fn type_info(&self, types: &TypeList) -> TypeInfo; @@ -134,7 +137,7 @@ impl TypeIdentifier for CoreTypeId { impl TypeData for SubType { type Id = CoreTypeId; - + const IS_CORE_SUB_TYPE: bool = true; fn type_info(&self, _types: &TypeList) -> TypeInfo { // TODO(#1036): calculate actual size for func, array, struct. let size = 1 + match &self.composite_type.inner { @@ -156,7 +159,7 @@ define_type_id!( impl TypeData for Range<CoreTypeId> { type Id = RecGroupId; - + const IS_CORE_SUB_TYPE: bool = true; fn type_info(&self, _types: &TypeList) -> TypeInfo { let size = self.end.index() - self.start.index(); TypeInfo::core(u32::try_from(size).unwrap()) @@ -245,7 +248,7 @@ impl TypeInfo { } /// The entity type for imports and exports of a module. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum EntityType { /// The entity is a function. Func(CoreTypeId), @@ -257,6 +260,8 @@ pub enum EntityType { Global(GlobalType), /// The entity is a tag. Tag(CoreTypeId), + /// The entity is a function with exact type. + FuncExact(CoreTypeId), } impl EntityType { @@ -268,12 +273,13 @@ impl EntityType { Self::Memory(_) => "memory", Self::Global(_) => "global", Self::Tag(_) => "tag", + Self::FuncExact(_) => "func_exact", } } pub(crate) fn info(&self, types: &TypeList) -> TypeInfo { match self { - Self::Func(id) | Self::Tag(id) => types[*id].type_info(types), + Self::Func(id) | Self::Tag(id) | Self::FuncExact(id) => types[*id].type_info(types), Self::Table(_) | Self::Memory(_) | Self::Global(_) => TypeInfo::new(), } } @@ -544,6 +550,7 @@ impl<'a> TypesRef<'a> { match &self.kind { TypesRefKind::Module(module) => Some(match import.ty { TypeRef::Func(idx) => EntityType::Func(*module.types.get(idx as usize)?), + TypeRef::FuncExact(idx) => EntityType::FuncExact(*module.types.get(idx as usize)?), TypeRef::Table(ty) => EntityType::Table(ty), TypeRef::Memory(ty) => EntityType::Memory(ty), TypeRef::Global(ty) => EntityType::Global(ty), @@ -558,7 +565,7 @@ impl<'a> TypesRef<'a> { pub fn entity_type_from_export(&self, export: &Export) -> Option<EntityType> { match &self.kind { TypesRefKind::Module(module) => Some(match export.kind { - ExternalKind::Func => EntityType::Func( + ExternalKind::Func | ExternalKind::FuncExact => EntityType::Func( module.types[*module.functions.get(export.index as usize)? as usize], ), ExternalKind::Table => { @@ -570,9 +577,7 @@ impl<'a> TypesRef<'a> { ExternalKind::Global => { EntityType::Global(*module.globals.get(export.index as usize)?) } - ExternalKind::Tag => EntityType::Tag( - module.types[*module.functions.get(export.index as usize)? as usize], - ), + ExternalKind::Tag => EntityType::Tag(*module.tags.get(export.index as usize)?), }), #[cfg(feature = "component-model")] TypesRefKind::Component(_) => None, @@ -780,7 +785,13 @@ impl<T> Index<usize> for SnapshotList<T> { #[inline] fn index(&self, index: usize) -> &T { - self.get(index).unwrap() + match self.get(index) { + Some(x) => x, + None => panic!( + "out-of-bounds indexing into `SnapshotList`: index is {index}, but length is {}", + self.len() + ), + } } } @@ -947,7 +958,7 @@ impl TypeList { /// [`Self::intern_canonical_rec_group`]. pub fn intern_sub_type(&mut self, sub_ty: SubType, offset: usize) -> CoreTypeId { let (_is_new, group_id) = - self.intern_canonical_rec_group(false, RecGroup::implicit(offset, sub_ty)); + self.intern_canonical_rec_group(true, RecGroup::implicit(offset, sub_ty)); self[group_id].start } @@ -1129,7 +1140,8 @@ impl TypeList { }, ) => a_shared == b_shared && a_ty.is_subtype_of(b_ty), - (HT::Concrete(a), HT::Abstract { shared, ty }) => { + (HT::Concrete(a), HT::Abstract { shared, ty }) + | (HT::Exact(a), HT::Abstract { shared, ty }) => { let a_ty = &subtype(a_group, a).composite_type; if a_ty.shared != shared { return false; @@ -1146,7 +1158,8 @@ impl TypeList { } } - (HT::Abstract { shared, ty }, HT::Concrete(b)) => { + (HT::Abstract { shared, ty }, HT::Concrete(b)) + | (HT::Abstract { shared, ty }, HT::Exact(b)) => { let b_ty = &subtype(b_group, b).composite_type; if shared != b_ty.shared { return false; @@ -1162,9 +1175,13 @@ impl TypeList { } } - (HT::Concrete(a), HT::Concrete(b)) => { + (HT::Concrete(a), HT::Concrete(b)) | (HT::Exact(a), HT::Concrete(b)) => { self.id_is_subtype(core_type_id(a_group, a), core_type_id(b_group, b)) } + + (HT::Exact(a), HT::Exact(b)) => core_type_id(a_group, a) == core_type_id(b_group, b), + + (HT::Concrete(_), HT::Exact(_)) => false, } } @@ -1199,7 +1216,7 @@ impl TypeList { pub fn reftype_is_shared(&self, ty: RefType) -> bool { match ty.heap_type() { HeapType::Abstract { shared, .. } => shared, - HeapType::Concrete(index) => { + HeapType::Concrete(index) | HeapType::Exact(index) => { self[index.as_core_type_id().unwrap()].composite_type.shared } } @@ -1212,7 +1229,7 @@ impl TypeList { pub fn top_type(&self, heap_type: &HeapType) -> HeapType { use AbstractHeapType::*; match *heap_type { - HeapType::Concrete(idx) => { + HeapType::Concrete(idx) | HeapType::Exact(idx) => { let ty = &self[idx.as_core_type_id().unwrap()].composite_type; let shared = ty.shared; match ty.inner { diff --git a/third_party/rust/wasmparser/tests/big-module.rs b/third_party/rust/wasmparser/tests/big-module.rs @@ -20,9 +20,9 @@ fn big_type_indices() { let mut code = CodeSection::new(); let mut body = Function::new([]); - body.instruction(&Instruction::RefFunc(0)); - body.instruction(&Instruction::Drop); - body.instruction(&Instruction::End); + body.instructions().ref_func(0); + body.instructions().drop(); + body.instructions().end(); code.function(&body); module.section(&code); @@ -32,3 +32,31 @@ fn big_type_indices() { .validate_all(&wasm) .unwrap(); } + +#[test] +fn big_function_body() { + let mut module = Module::new(); + + let mut types = TypeSection::new(); + types.ty().function([], []); + module.section(&types); + let mut funcs = FunctionSection::new(); + funcs.function(0); + module.section(&funcs); + + let mut code = CodeSection::new(); + let mut body = Function::new([]); + // Function body larger than the 7_654_321-byte implementation + // limit. + for _ in 0..8_000_000 { + body.instructions().unreachable(); + } + body.instructions().end(); + code.function(&body); + module.section(&code); + + let wasm = module.finish(); + + let result = wasmparser::Validator::default().validate_all(&wasm); + assert!(result.is_err()); +} diff --git a/third_party/rust/wast/.cargo-checksum.json b/third_party/rust/wast/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"33a9e79a4d299c1b1a269e35e94a03c94ed48ad162db85c9940ad811b5008916","Cargo.toml":"0f167ca9e4a3834e1a4d4d734bb1dd59f942b7d8f80f8bb698f2bed461c101ad","README.md":"5a0d2b894a3ac74ee2be74715a2f22c40a08520cb4ac59183f4e7356f34ac566","src/component.rs":"154cdef2003b1607ab21a50a821b455da854b78d353d573586351c2593ed70a2","src/component/alias.rs":"5ec26333e179dc3778dead489f1273815fe9c1c808ba6a7e60eff54072fad795","src/component/binary.rs":"dd347a772e86c6090cbe7fe6eb513e4f2d79a52717102a0fd08f3db526ca8413","src/component/component.rs":"90002d2dbe9a5665e637c04b81c1cb700025e9389cdae5417fd9b3a2e49f91a1","src/component/custom.rs":"f5b23c34b73a716a986fd999fc8d8c9e24c341e83292088fe83325cd82dab4f5","src/component/expand.rs":"f313d633ca52a1dc79f89fd7ea8016a226f94d997f67da3b2e2463a5362cdddc","src/component/export.rs":"f51e824c839d8bb0884eca509622f376c8cce3335be324b2b25033af6216fd2a","src/component/func.rs":"9a4bacaa40f70a131e72c96af7dff09ca583c0b606eee17a97f58fee235820bc","src/component/import.rs":"add63978787f5bfad1faeb1ce6b121fa60bbcd9a736afd7ae81ddc9f5b031107","src/component/instance.rs":"e550a7ee9af092ae084dd41e2c0ae756b7dca8da4b91d672d90265a6a15dff83","src/component/item_ref.rs":"e9c426ccc0210dc0c37bb0448468f5f4d9e52656b72d4ff0f2dc65c89957fe60","src/component/module.rs":"d27a28199d1dea1c64294a514329a524432319288515b0a0e3091fa7d3a33f74","src/component/resolve.rs":"dbf2df73269ba9f5c5b202d95e4078c985a766a5006b0cab749e480d462c462d","src/component/types.rs":"a0aecb2dde80578e0f029f813619bf9407798ad0cd3c53c4c15192f6b0c0b641","src/component/wast.rs":"aa39db0ea0acd38744dc3cbd35903c9b00b5de90a5bfc8b76e6b6a7581d7c4c0","src/component_disabled.rs":"dde798aabc109d12de7e169bdd67a945274cfec1c1f4d6e097ecac9e5cff23e2","src/core.rs":"c82d7356515f675f9173f9bf5d7c0f4e56ca7a3eebc92b5f95a2d04882ca470c","src/core/binary.rs":"609f752b3ba6cfa9d9604d82d4e87c9ffb5a35984a28f44155b14faaa830369a","src/core/binary/dwarf.rs":"bc0662cbdc58c83abc153490f7c47e2ae5998a1dedf42b7058606ce7edcb04b7","src/core/binary/dwarf_disabled.rs":"182ee888617357835decd08c68fe8dfdef9fe0665ece9b1550794fea9dcb1486","src/core/custom.rs":"edd6044b75d79ec873c28d803fb8dc9a53724f1bba474bcdef2bc77196e0a4d2","src/core/export.rs":"1322a120d9e1dd6f3aa1485ee0bbc4294961028ae8a7584a24170af5823b73b1","src/core/expr.rs":"4bc72bc0fbcbaef216e23e5fc7da1d50becc778c2f1ca9e6ad78d0226b4d3c8a","src/core/func.rs":"4625e75e050a4e3b22fe08e8fc39379e66420f1bbe499b6965d51ae92299823d","src/core/global.rs":"dec0abecadd2fde9298acb729259deba1ef3c4733ae5afcb4fe8cd4a633f5349","src/core/import.rs":"602a13aed2fd5fa63e2562246586546199861df57f304c2906561ab77810cadd","src/core/memory.rs":"bb9a1b6975decf76b410162540aef0b3721902dad36e156b28bc216c81e5f605","src/core/module.rs":"1635ff9d4b4634a0cd18e12df281ce03c8f000edc07aae846d03ce8714f0393e","src/core/resolve/deinline_import_export.rs":"30fc86f65e9a8d743638a8fef2afe38acad5d12f9f8c85a93877a2df579a356f","src/core/resolve/mod.rs":"230283f528eb98b861d331e9fb5bddc3b2baa09e020ea5aa8849dfb970e0e26e","src/core/resolve/names.rs":"8b58bf27a85bf9dd067f0eb223feddbf9b137d8ee74a373d1a28d7f407491615","src/core/resolve/types.rs":"065d97df2dcddfbfb015b0def31c856b1e577b12cdfd1a2c93f7cb008de60439","src/core/table.rs":"4e31c8e187062abece9fd07fe28de730f2b037fa7c25571e7321a30755e0f6ec","src/core/tag.rs":"8a3d4fcdb86dedd68cdaf25abd930ef52a461cf2a0e9393bb9cb6f425afaaf2e","src/core/types.rs":"ca6497c01c581c9e56f12e1af680935a9b1f61c4b64800ad0bb8df512707c29d","src/core/wast.rs":"7d505f0b906a2cd2df79976844a1d1026199fb7aa1d9528e1cc7117ef2d49c43","src/encode.rs":"610c9c4f0da9f6078c68a0164518869bfb6fe8e408b43db8718da0c01cdcf992","src/error.rs":"4526260299c7983696a49ffe30a80139beb0d081fa8f42decc5e3283b361b1cb","src/gensym.rs":"14a9b1d2c24a9d4ce5d99b50d01147de335ae6393292581014f7905d54ec4949","src/lexer.rs":"0a5539092905caa3f2709256305d8f11f6d9dda281722816210f605fb1f90e5f","src/lib.rs":"f5cb6da9ca7e1a345298597e3faffae1040b7a501d2ebbfb67f1bab6d7fb6e58","src/names.rs":"888654ba6c95ee44b0041dd211889ae7a96f1f51e40f09b7246e28c1c497be51","src/parser.rs":"1b65e89ff099549421b2313e63984465785ed3e79fce359a77a4e7d29ba25fe1","src/token.rs":"6c58e1098ece3967690d931799c2359761cc71f47b05ddeec005153092f9fd2c","src/wast.rs":"f28d4475086ac2abd013a541285a51ce6faf1314eea688343b6f483d841824aa","src/wat.rs":"5c2002f4904ce2f33fc547c2d7ee916a56f4551522c7a4b21e34df5d49289374","tests/annotations.rs":"de6ab2a4e15c0bc683482436bed27e37ab45bc374d99f2fcc031c7947506e581","tests/comments.rs":"c068034817774cc94aa06fa09de453132d063335775002aa694fc60889a4ee04","tests/parse-fail.rs":"60cf90f0bb29c5648d803629c2614140be7746c6bc4858e2be318641382f9429","tests/parse-fail/bad-core-func-alias.wat":"b71372064c3fce9d4a616418605040fe5e1356030a709b798b4769d3619cbbfb","tests/parse-fail/bad-core-func-alias.wat.err":"bb63274c26d3a21209bad794767f48372834bdc10cfbebf568a0c65d52803c90","tests/parse-fail/bad-func-alias.wat":"237c07149e1e74afe3b991a1fee6acb63167c1ca8931341614c435000339b887","tests/parse-fail/bad-func-alias.wat.err":"4a4bfc691b06d20fdf71e1dbac04649a52c76787048415599978987d761308fa","tests/parse-fail/bad-index.wat":"d21489daeec3a35327dcc9e2ba2d0acdd05f4aeaff2272cca608fda4d2338497","tests/parse-fail/bad-index.wat.err":"dc11070de0c9160573006ea4e5fa3c4d28e71bc39b24b1938cf6ff3b03ea7154","tests/parse-fail/bad-name.wat":"e5ff5d410007779a0de6609ea4cc693f0e603d36a106b8f5098c1980dd9f8124","tests/parse-fail/bad-name.wat.err":"fb5638476c1b85d9d1919e3dbcb0f16f82d088a4a22d4a0c186d7b8ba6e1902b","tests/parse-fail/bad-name2.wat":"5a6a4d0c19e5f2e48d7cebf361aca9b9000b7ef0c652997b5bd0ffaadbd2ca8a","tests/parse-fail/bad-name2.wat.err":"129707cce45f1e3cfb3e2ca5c702182e16ca5eeb2dbb2edd0710b004a8e194a5","tests/parse-fail/bad-name3.wat":"c19133d738cc84e9174301f27d4050c216bda81c7e9918d03ac792b088f24a05","tests/parse-fail/bad-name3.wat.err":"84ea63d40a619a0782ec6e94fce63921188ab87b1c3875eacae0a371144ed83a","tests/parse-fail/block1.wat":"91e74b5c3b43be692e7a6ae74fbfa674c4b6197299eb61338c4eccf282b18f17","tests/parse-fail/block1.wat.err":"40a083ae496b41dee7002cc6a664c5db0c5e4d904ae03b815773a769c4493fca","tests/parse-fail/block2.wat":"a8c07b4c09d51f10a8ffdf19806586022552398701cd90eb6d09816d45df06e5","tests/parse-fail/block2.wat.err":"33c842ec5dd0f2fdd3a9ce8187dd98b45ceee48c12810802af809d05b9cd25e9","tests/parse-fail/block3.wat":"29739abfbabd7c55f00ddfbbb9ebd818b4a114ef2336d50514f0842f7e075905","tests/parse-fail/block3.wat.err":"fc667ae2e71a260f62a3c7393bc97272e7c0ff38b17594f4370847b8a5019060","tests/parse-fail/confusing-block-comment0.wat":"8f27c9d0d212bbb1862ea89ffd7cbeafde5dfd755d695c1ba696cd520aba1a1d","tests/parse-fail/confusing-block-comment0.wat.err":"b53cbaef7bcec3862c64e09c084b92cd61bd29b954125482b2d083db250cd9e2","tests/parse-fail/confusing-block-comment1.wat":"b1a0447c9a8eaab8938d15cd33bd4adbb8bb69c2d710209b604023991a4347cb","tests/parse-fail/confusing-block-comment1.wat.err":"2fc3b3e4f98416326e1e5ec034026301069b6a98fa24451bc7573e16b8cb3811","tests/parse-fail/confusing-block-comment2.wat":"e3f49c7a388fba81081beb25d87bbd7db0acce5dd8e3eaa04574905ed7ec420c","tests/parse-fail/confusing-block-comment2.wat.err":"2183231d6acd0b5a117f9aea747c3d5c12e758450a6cd74027bb954a3134cf19","tests/parse-fail/confusing-block-comment3.wat":"d83f89c582501eb8833e772b8462c8974984a2f7fbb80b1452dc399fac74e5ed","tests/parse-fail/confusing-block-comment3.wat.err":"8b2096a4833627905c63f49cdabe44be24336646578dcfbdc67e9bfb35cbc601","tests/parse-fail/confusing-block-comment4.wat":"b7c6c68844d918e9ef6dd5ab9c40c7de7b38f04f94fadad630eda4e596f3e0f8","tests/parse-fail/confusing-block-comment4.wat.err":"2f790cc511edfcd89a12c9207901be16039fc1a06a584d73095e77a52f861cd9","tests/parse-fail/confusing-block-comment5.wat":"a159808032638cc914fa80ac4354a68b0af4f435a09cbe3e2d577582e183eb0a","tests/parse-fail/confusing-block-comment5.wat.err":"6fe0d99894307442f83fe93beaa5da706e06c9bdaf8e39d7cbae4c4fffafcb94","tests/parse-fail/confusing-block-comment6.wat":"abe48bcba2587dca98bc80ddde4e813f94fbc8a3538704a0775ea85bca0f8466","tests/parse-fail/confusing-block-comment6.wat.err":"3c97b9bf1112bbb7335d7fe4be5befb6f91eea7bec7dd3e6b543792231003c56","tests/parse-fail/confusing-block-comment7.wat":"e125c416ea5fa0ac35a58295a83a6f345438e2d7ddc6a39bd76c8e89885b3f0e","tests/parse-fail/confusing-block-comment7.wat.err":"5c34528ff2019cd3f0b3df34fd42523c0b66120706321da2c88ec05793478d2e","tests/parse-fail/confusing-block-comment8.wat":"200cc4c0e5af21a25529d7a81633a03642cff807255d6cd72eb45cdccc605cec","tests/parse-fail/confusing-block-comment8.wat.err":"9b81237d150a784b71791eee88fb6264a8bd6412862660f7392945203809e517","tests/parse-fail/confusing-line-comment0.wat":"bcec4c5a1e52b3e392e07c6711c979aa8d7db8baaf2bcdf270ba16d1aa528d26","tests/parse-fail/confusing-line-comment0.wat.err":"41ec5a075dc6b73afe1aec6b3198c5c4ae3a1a900e1610115879058ce034d6f6","tests/parse-fail/confusing-line-comment1.wat":"a2afbcab00ec957dfd9e9bf21fa4238852247b27f0b054f4a00f6b172dddf853","tests/parse-fail/confusing-line-comment1.wat.err":"f19a645e6fb5cbd7a0dd2308732741edcf83dbae0ef62549972029856a9e7fc6","tests/parse-fail/confusing-line-comment2.wat":"7f2a68229d02aac56ec4dfccf139bf2d617a0e89430357b30444dc4239d8aa89","tests/parse-fail/confusing-line-comment2.wat.err":"08add3d33e10e1ab6b4f3ae431f5db61d6f6c0a2b7d6828482a1e51b3a2d3851","tests/parse-fail/confusing-line-comment3.wat":"61173ae54782f6de86685f9555ffb94bbe2cf20b234daf660abb69ba3326f1ff","tests/parse-fail/confusing-line-comment3.wat.err":"4a5333dc02efa3c1eeab9cafa7c707f78abe92defdb01a71d6fe20944e4785f0","tests/parse-fail/confusing-line-comment4.wat":"9ecbbbe82c750e6475af1bfb46fe7a06115e4446a437d19fc08ca3d002f2a1c9","tests/parse-fail/confusing-line-comment4.wat.err":"ddb8aee8006265253b09c313cf5eb5c2dc4da66f502b4f6d3e2e1de77b35aec9","tests/parse-fail/confusing-line-comment5.wat":"8a4c8d342111bc9d37c16dbdf67c52027e1a42632abc9f359b3e4f07a85748b5","tests/parse-fail/confusing-line-comment5.wat.err":"34e368719fc0eab2f1a43c9f8e6f1b31aa9be9f971085d72374e49bde39cbfe5","tests/parse-fail/confusing-line-comment6.wat":"15f0dcdec23736ce92db84b3a7cdfe8689c97f2a7d0b9b0bfb0dcd2675163ed1","tests/parse-fail/confusing-line-comment6.wat.err":"0570be2ede803f071925d249f3858d3a417b5a6d678c9da40fc851d788d12983","tests/parse-fail/confusing-line-comment7.wat":"c7ee59301a701dd52d56cad02df78b0ad3584460bc18efa42ee137fe0c35aef6","tests/parse-fail/confusing-line-comment7.wat.err":"feebbeee8c85d8b3b85cec89435ae18f3ade9f754ca180d747a41406b64ca07a","tests/parse-fail/confusing-line-comment8.wat":"17632a8142154624de88b3cf93516147ed3419d785200bcd7049499eca8e8f04","tests/parse-fail/confusing-line-comment8.wat.err":"9c209285f2295cd2bc999aa7a9534a654932493308ab1f102839ed15a4d04d17","tests/parse-fail/confusing-string0.wat":"497b679b32baddcd6a158f4cadd3d9a9dea3457bac2a8c2c3d4e09b7c2d80842","tests/parse-fail/confusing-string0.wat.err":"cb3d737f2319346675a038716694354cd3b272453daa8a96e32e9861a9277f7b","tests/parse-fail/confusing-string1.wat":"46654cbed1ea6aab5019aef3d20098a391e40dacafa1ad5e83bf4ec384109fce","tests/parse-fail/confusing-string1.wat.err":"de7e7da516dc6c244bd0e4f012577b69f0cacbcc10f727fadb4b50bb04e0e2b4","tests/parse-fail/confusing-string2.wat":"11938f217c14387c05312735130f00c91d9df2d3ff9df7f13395e0f2b81dad54","tests/parse-fail/confusing-string2.wat.err":"e7bd08b146a855d681fefaf9e0576a9c333a2d10044f8e268b916b22a54227c9","tests/parse-fail/confusing-string3.wat":"e0ca4903fcafb9a54a91cf99e5eac95d25c6d2eb67b076f88191ad396f839cb6","tests/parse-fail/confusing-string3.wat.err":"b88d5db9e445c798eb24f95b7661b9c0368934d27ee8208477cd1c99351b939a","tests/parse-fail/confusing-string4.wat":"3ee2aee7f77604d051519c6f1795634469c12e98ae347a98f0c8445eecf1ff3d","tests/parse-fail/confusing-string4.wat.err":"1edc65bb09d8d3eed6ff69e7d9a7a4b5941dc823fa3436fa375657510255f6f4","tests/parse-fail/confusing-string5.wat":"024e50943128840d53f17e31a9b9332ce4f0ee70a847a043015f435b1c3c6e76","tests/parse-fail/confusing-string5.wat.err":"a0f13ec40d596ea2d8b0c4292b0d28775a5116ab7e11d7de88b295d25428c661","tests/parse-fail/confusing-string6.wat":"79cf157e29319800d2652c5a7f3dc90e07ebe2145c9904a70fc12027cdee84b7","tests/parse-fail/confusing-string6.wat.err":"860555e7aa13e3de3639cc2a530d6a42b974b629c4659593e972cbb0f306abae","tests/parse-fail/confusing-string7.wat":"7d8e403766dfb4e569754160d31ed0f9a27f908ed6cff96be43ab3d37f5975d5","tests/parse-fail/confusing-string7.wat.err":"658b6a02ba6d769254485f35c20984e7135d914b4266929963d723f26a40be4a","tests/parse-fail/confusing-string8.wat":"5a9b222e578655d57ee6e9f19bc1ea8e29aa52d652975fac685213444ed6458f","tests/parse-fail/confusing-string8.wat.err":"9a4e1a510330c800a1df7966998ebc3cde931eda20b249e5360f5e9a905dce11","tests/parse-fail/inline1.wat":"4e9767d67207aace2ac5e6f63a30e7510e4aa245ba35420539509e2254470272","tests/parse-fail/inline1.wat.err":"0143017a9825e518baa6009bae2c8d63520051dedd3437705bbe36b038a57f41","tests/parse-fail/newline-in-string.wat":"5c01cf709544ade0a6cdfcc39a3836a3bc018b633dc42a6cd872b6defc763ea7","tests/parse-fail/newline-in-string.wat.err":"1504209cc37a78b2aee778f23eacf78606daf964cf7bff251f5700efcd27ffd7","tests/parse-fail/string1.wat":"620d46d585ce94b382b5fde628c1399f3e562014b7a44af46e92f7bd045ca86e","tests/parse-fail/string1.wat.err":"fc53f3a1c4a65d8f25e5af51dec7699f45cecba114ca9c7871781bc70f664320","tests/parse-fail/string10.wat":"f7409dd45e153a1b11cb23e38f4ed87da12bedde38f8f0ccfe91037b0a4d97bd","tests/parse-fail/string10.wat.err":"ce677db5e37e0ed81ca357ed6b5edb21d85c27303ee194855bea7a88457efb6a","tests/parse-fail/string11.wat":"f6e0400b8c6a2014efa1ac676c567e140d8f86b5f4d5129773e6d67af537b615","tests/parse-fail/string11.wat.err":"4c6a550d29eda38a4e1bf7a589596f11655dc779479d7b8d466cfc53f815a742","tests/parse-fail/string12.wat":"23e30070eef22271651cce096a801fc4f79f3c37343c88bb8d2fc99b32d3b8b9","tests/parse-fail/string12.wat.err":"b5ec59f2996b88b2ee157e22d1774dc3e36fc08ed5bfc621aea830d30f66f586","tests/parse-fail/string13.wat":"81a305b981159ee10e140749ea3220c9edaaff53605e63c21995de47382b5faf","tests/parse-fail/string13.wat.err":"959f26c6b54e0d367b51d11d1addd8a53b5b8ff3caf70ebdd46bbea8ccfa2418","tests/parse-fail/string14.wat":"c45c2cc9f7afbfbd4be8e513106d22f7e5e817091448576c6bdf0701b81d95dd","tests/parse-fail/string14.wat.err":"50b5bccba905ddbe275938edb7ed0b09a5ca53dcdad36a7ff736ce9bc8e7a338","tests/parse-fail/string15.wat":"b5e0d5ade40de53b2d767a132e28376bb8c7a6f6238c4d8c248ae717c41d7f1f","tests/parse-fail/string15.wat.err":"0e9fc502cc90f96d1f592a3f63369fd2a3574bc4a2345a70365dbb76804e870f","tests/parse-fail/string16.wat":"38c3688cee80a9d089d239aa06eb1d27c5364ad2bd270aca57d05997c20aa682","tests/parse-fail/string16.wat.err":"4274b3bbe4df4cf0373619b1fcd082d0c802990817d2aca26ed885168c80e489","tests/parse-fail/string2.wat":"1172964aed31537b8c466d1f045f3e756926e7b221f80b2aff4a9a6721ea0beb","tests/parse-fail/string2.wat.err":"4618d3b20a78a077337eb5d6cae14ac39d9853762f011fbd23cff8921618dbde","tests/parse-fail/string3.wat":"07e0fbcd6270c1db100917c151ee4ac3f935e4ee1b27bce3c453b22b4b74f4d6","tests/parse-fail/string3.wat.err":"08ffc6158a9e030b2e211d53bdb8aeacfd879815c7b284d6a83b030566e35928","tests/parse-fail/string4.wat":"c970da2051b0613bdd1de4664f10424e14f2ebabe604175d4fb9b763b37af577","tests/parse-fail/string4.wat.err":"406706594d305c560fabd66417ad4fc276939990b5e701bd9d13fc223d207219","tests/parse-fail/string5.wat":"386cf314bb05acdaaabdf4da1caf140167271a26bd08bf34c3a7427d4bc4431f","tests/parse-fail/string5.wat.err":"1e56b44a23a37b2b2ad05aa9dd7e1e18191b5cc22151f93bbcf9d618779a57bd","tests/parse-fail/string6.wat":"8f1fe2825ff96f2acee9130a7721f86fcc93c221baa9411bf1fb6f0870d38ccb","tests/parse-fail/string6.wat.err":"d55dfd84d94e893f167ae73b7a080aefb2bfb05cc8a1ec201c4d3066fb8549b4","tests/parse-fail/string7.wat":"b12f8c75313d7f834489d3c353422f90bc945b37139586446eda82e334a97cde","tests/parse-fail/string7.wat.err":"4cee0ca61992c249dd0faaf2529a073cf8deeb36111a3f69b43695e5682560a2","tests/parse-fail/string8.wat":"4c2e0e1f883bb4e8cba9313497ed792130e5848e62bde7716102788d7467be10","tests/parse-fail/string8.wat.err":"840c6def7c60dd7c2b7261549cab435ba78c9b3a937adf6d5d9595ff8af01c91","tests/parse-fail/string9.wat":"2b7670caed2b0688d535de6e4e416f35fa717cfbe096a6cc764a669085c8f52f","tests/parse-fail/string9.wat.err":"37b5a9c3af9631500f31f9e5e3efa821b8d96063c57d60fd01df6be6a5c323e1","tests/parse-fail/unbalanced.wat":"f664fbef53a0308f864ba496d38044eb90482636e32586512939d4930729f3fe","tests/parse-fail/unbalanced.wat.err":"aba579f7b836856e69afe05da8328aabe0643d94e369898e686aa7bb0b07e9c9","tests/recursive.rs":"ad8a2b07bf955121a7c9e326ed35f9b2bc56b440c8cc0bbde24d423a79945c1a"},"package":"c61496027ff707f9fa9e0b22c34ec163eb7adb1070df565e32a9180a76e4300b"} -\ No newline at end of file +{"files":{"Cargo.lock":"f142f10e657ae92445c700d720cf0313631f4e624a42b3281e3574cdb72363bf","Cargo.toml":"04d1bddf1de99260fa1cb4e28110405adc7da7cba08ffdbcba128dca35cb492f","README.md":"5a0d2b894a3ac74ee2be74715a2f22c40a08520cb4ac59183f4e7356f34ac566","src/component.rs":"154cdef2003b1607ab21a50a821b455da854b78d353d573586351c2593ed70a2","src/component/alias.rs":"e332dfa40bd8990c5b38de468e47a10a00390126ae87f713085ae1c126ee6ff9","src/component/binary.rs":"182a6cbee5810be832adf377f6c07953d47448f648ff0ec51a44affc4896f50d","src/component/component.rs":"8115ecb0b97d904eccc1e2dbbe09dbaec7068fb587e4f17d0eba3e15e29d9cf3","src/component/custom.rs":"f5b23c34b73a716a986fd999fc8d8c9e24c341e83292088fe83325cd82dab4f5","src/component/expand.rs":"7f478e73b50adcb641bbef3ab5d5f38414dc69183fc459ad3bd3e025966413ce","src/component/export.rs":"f51e824c839d8bb0884eca509622f376c8cce3335be324b2b25033af6216fd2a","src/component/func.rs":"79aff1085f81d4cc7c1929e38e86c64d12e9631f9cfa97cffd46e3b187000625","src/component/import.rs":"add63978787f5bfad1faeb1ce6b121fa60bbcd9a736afd7ae81ddc9f5b031107","src/component/instance.rs":"e550a7ee9af092ae084dd41e2c0ae756b7dca8da4b91d672d90265a6a15dff83","src/component/item_ref.rs":"e9c426ccc0210dc0c37bb0448468f5f4d9e52656b72d4ff0f2dc65c89957fe60","src/component/module.rs":"d27a28199d1dea1c64294a514329a524432319288515b0a0e3091fa7d3a33f74","src/component/resolve.rs":"b6bdc9b4ade9541a036adcfcaad8d8646d53586e97a3b73abcf7eda831eef149","src/component/types.rs":"c953e544bc08b5d796a2a78c831439126aeebe60f7c3e9b760991a86e1ef69f1","src/component/wast.rs":"aa39db0ea0acd38744dc3cbd35903c9b00b5de90a5bfc8b76e6b6a7581d7c4c0","src/component_disabled.rs":"20e2d9c28efe2ecf14f96f8d8971eddc23d0df9494fb527e79ed64b449f2de72","src/core.rs":"c82d7356515f675f9173f9bf5d7c0f4e56ca7a3eebc92b5f95a2d04882ca470c","src/core/binary.rs":"0053b60f9ccc3acc7a1ed3beffc30b302d2e0cfc841ba09a4bd0c0d6927032e9","src/core/binary/dwarf.rs":"14da9bc6682effdefd079f9934f753e2412f8a5868f29552f50fa5fd30d46400","src/core/binary/dwarf_disabled.rs":"67ad94dd4307fb6af9757f427267193b758b8ca34c3f69bed87a65be04b09c13","src/core/custom.rs":"b3ff3aa5073826b04e0dc0eef80e34bb2c44223fc121e26267de411f45e140b2","src/core/export.rs":"1322a120d9e1dd6f3aa1485ee0bbc4294961028ae8a7584a24170af5823b73b1","src/core/expr.rs":"aea10d2db3275a44682e881be2e689974ebe95662e860afa18ed1a8696599449","src/core/func.rs":"79f66cd890d571aa276ead0a797a57c6ddfee34f10e6ae9a403923c5403c515f","src/core/global.rs":"dec0abecadd2fde9298acb729259deba1ef3c4733ae5afcb4fe8cd4a633f5349","src/core/import.rs":"bf8bdb9789a002073a607e58142fb632ff3098dd4ad5fb1591e8287c0dd26297","src/core/memory.rs":"bb9a1b6975decf76b410162540aef0b3721902dad36e156b28bc216c81e5f605","src/core/module.rs":"7ab120a2b403d4eafc26689387f463086aafd56e5c0afa74c92f2499134ea47b","src/core/resolve/deinline_import_export.rs":"16e79e38da25d7a9f5685fda036fa51a7a0b622aedc708c9029ec54fa35d490f","src/core/resolve/mod.rs":"4d248d3142f4c07021e4cb460ef9e07c77dc0666568a161fa654bb1d6e6c9755","src/core/resolve/names.rs":"603bf2fc2590ca85e60902294b932fc5c3482f91cf1961564541ee34de270868","src/core/resolve/types.rs":"e17246834c94c620e16588720c8b3598202254db0b186a03d852aeab716af863","src/core/table.rs":"4e31c8e187062abece9fd07fe28de730f2b037fa7c25571e7321a30755e0f6ec","src/core/tag.rs":"8a3d4fcdb86dedd68cdaf25abd930ef52a461cf2a0e9393bb9cb6f425afaaf2e","src/core/types.rs":"2becc668864259d5896a9b10ff7df520b6bd7bcb683a0db70416fa3e35fc5fc9","src/core/wast.rs":"a2748b92bb9789cb0314ca973c30d4eb09125cc40a57de916c096124530b397b","src/encode.rs":"610c9c4f0da9f6078c68a0164518869bfb6fe8e408b43db8718da0c01cdcf992","src/error.rs":"d7670875d91283990c5bf596d655602fed8ae8ec276ca256952c64962299c4ac","src/gensym.rs":"14a9b1d2c24a9d4ce5d99b50d01147de335ae6393292581014f7905d54ec4949","src/lexer.rs":"bcf8fb6320e21a34174104d610b9a95a39db100550cc4209c3ca77436456beaf","src/lib.rs":"098ff4793dcb2fe585cdeed505ea5eccc731c6983dccd26ad37867bc7a74a077","src/names.rs":"1f1d1a256c9554bb64efb6e790993708360609f7a31ecf3af0ca5fd9d85471ca","src/parser.rs":"3ba923a416071bf78055e64b8b2812dc7709811109cafc9612b1685f80df01de","src/token.rs":"6c58e1098ece3967690d931799c2359761cc71f47b05ddeec005153092f9fd2c","src/wast.rs":"f28d4475086ac2abd013a541285a51ce6faf1314eea688343b6f483d841824aa","src/wat.rs":"5a4e3f2ad49d6bdca6f2ad1ae2c7ac25dc649398e1c0320edc4419698d232cc6","tests/annotations.rs":"de6ab2a4e15c0bc683482436bed27e37ab45bc374d99f2fcc031c7947506e581","tests/comments.rs":"c068034817774cc94aa06fa09de453132d063335775002aa694fc60889a4ee04","tests/parse-fail.rs":"c13a3aa974429c84ed4423ef00daeb5312c681a1dd93aa6e5ec9c3452a4ea674","tests/parse-fail/bad-core-func-alias.wat":"b71372064c3fce9d4a616418605040fe5e1356030a709b798b4769d3619cbbfb","tests/parse-fail/bad-core-func-alias.wat.err":"bb63274c26d3a21209bad794767f48372834bdc10cfbebf568a0c65d52803c90","tests/parse-fail/bad-func-alias.wat":"237c07149e1e74afe3b991a1fee6acb63167c1ca8931341614c435000339b887","tests/parse-fail/bad-func-alias.wat.err":"4a4bfc691b06d20fdf71e1dbac04649a52c76787048415599978987d761308fa","tests/parse-fail/bad-index.wat":"d21489daeec3a35327dcc9e2ba2d0acdd05f4aeaff2272cca608fda4d2338497","tests/parse-fail/bad-index.wat.err":"dc11070de0c9160573006ea4e5fa3c4d28e71bc39b24b1938cf6ff3b03ea7154","tests/parse-fail/bad-name.wat":"e5ff5d410007779a0de6609ea4cc693f0e603d36a106b8f5098c1980dd9f8124","tests/parse-fail/bad-name.wat.err":"fb5638476c1b85d9d1919e3dbcb0f16f82d088a4a22d4a0c186d7b8ba6e1902b","tests/parse-fail/bad-name2.wat":"5a6a4d0c19e5f2e48d7cebf361aca9b9000b7ef0c652997b5bd0ffaadbd2ca8a","tests/parse-fail/bad-name2.wat.err":"129707cce45f1e3cfb3e2ca5c702182e16ca5eeb2dbb2edd0710b004a8e194a5","tests/parse-fail/bad-name3.wat":"c19133d738cc84e9174301f27d4050c216bda81c7e9918d03ac792b088f24a05","tests/parse-fail/bad-name3.wat.err":"84ea63d40a619a0782ec6e94fce63921188ab87b1c3875eacae0a371144ed83a","tests/parse-fail/block1.wat":"91e74b5c3b43be692e7a6ae74fbfa674c4b6197299eb61338c4eccf282b18f17","tests/parse-fail/block1.wat.err":"40a083ae496b41dee7002cc6a664c5db0c5e4d904ae03b815773a769c4493fca","tests/parse-fail/block2.wat":"a8c07b4c09d51f10a8ffdf19806586022552398701cd90eb6d09816d45df06e5","tests/parse-fail/block2.wat.err":"33c842ec5dd0f2fdd3a9ce8187dd98b45ceee48c12810802af809d05b9cd25e9","tests/parse-fail/block3.wat":"29739abfbabd7c55f00ddfbbb9ebd818b4a114ef2336d50514f0842f7e075905","tests/parse-fail/block3.wat.err":"fc667ae2e71a260f62a3c7393bc97272e7c0ff38b17594f4370847b8a5019060","tests/parse-fail/confusing-block-comment0.wat":"8f27c9d0d212bbb1862ea89ffd7cbeafde5dfd755d695c1ba696cd520aba1a1d","tests/parse-fail/confusing-block-comment0.wat.err":"b53cbaef7bcec3862c64e09c084b92cd61bd29b954125482b2d083db250cd9e2","tests/parse-fail/confusing-block-comment1.wat":"b1a0447c9a8eaab8938d15cd33bd4adbb8bb69c2d710209b604023991a4347cb","tests/parse-fail/confusing-block-comment1.wat.err":"2fc3b3e4f98416326e1e5ec034026301069b6a98fa24451bc7573e16b8cb3811","tests/parse-fail/confusing-block-comment2.wat":"e3f49c7a388fba81081beb25d87bbd7db0acce5dd8e3eaa04574905ed7ec420c","tests/parse-fail/confusing-block-comment2.wat.err":"2183231d6acd0b5a117f9aea747c3d5c12e758450a6cd74027bb954a3134cf19","tests/parse-fail/confusing-block-comment3.wat":"d83f89c582501eb8833e772b8462c8974984a2f7fbb80b1452dc399fac74e5ed","tests/parse-fail/confusing-block-comment3.wat.err":"8b2096a4833627905c63f49cdabe44be24336646578dcfbdc67e9bfb35cbc601","tests/parse-fail/confusing-block-comment4.wat":"b7c6c68844d918e9ef6dd5ab9c40c7de7b38f04f94fadad630eda4e596f3e0f8","tests/parse-fail/confusing-block-comment4.wat.err":"2f790cc511edfcd89a12c9207901be16039fc1a06a584d73095e77a52f861cd9","tests/parse-fail/confusing-block-comment5.wat":"a159808032638cc914fa80ac4354a68b0af4f435a09cbe3e2d577582e183eb0a","tests/parse-fail/confusing-block-comment5.wat.err":"6fe0d99894307442f83fe93beaa5da706e06c9bdaf8e39d7cbae4c4fffafcb94","tests/parse-fail/confusing-block-comment6.wat":"abe48bcba2587dca98bc80ddde4e813f94fbc8a3538704a0775ea85bca0f8466","tests/parse-fail/confusing-block-comment6.wat.err":"3c97b9bf1112bbb7335d7fe4be5befb6f91eea7bec7dd3e6b543792231003c56","tests/parse-fail/confusing-block-comment7.wat":"e125c416ea5fa0ac35a58295a83a6f345438e2d7ddc6a39bd76c8e89885b3f0e","tests/parse-fail/confusing-block-comment7.wat.err":"5c34528ff2019cd3f0b3df34fd42523c0b66120706321da2c88ec05793478d2e","tests/parse-fail/confusing-block-comment8.wat":"200cc4c0e5af21a25529d7a81633a03642cff807255d6cd72eb45cdccc605cec","tests/parse-fail/confusing-block-comment8.wat.err":"9b81237d150a784b71791eee88fb6264a8bd6412862660f7392945203809e517","tests/parse-fail/confusing-line-comment0.wat":"bcec4c5a1e52b3e392e07c6711c979aa8d7db8baaf2bcdf270ba16d1aa528d26","tests/parse-fail/confusing-line-comment0.wat.err":"41ec5a075dc6b73afe1aec6b3198c5c4ae3a1a900e1610115879058ce034d6f6","tests/parse-fail/confusing-line-comment1.wat":"a2afbcab00ec957dfd9e9bf21fa4238852247b27f0b054f4a00f6b172dddf853","tests/parse-fail/confusing-line-comment1.wat.err":"f19a645e6fb5cbd7a0dd2308732741edcf83dbae0ef62549972029856a9e7fc6","tests/parse-fail/confusing-line-comment2.wat":"7f2a68229d02aac56ec4dfccf139bf2d617a0e89430357b30444dc4239d8aa89","tests/parse-fail/confusing-line-comment2.wat.err":"08add3d33e10e1ab6b4f3ae431f5db61d6f6c0a2b7d6828482a1e51b3a2d3851","tests/parse-fail/confusing-line-comment3.wat":"61173ae54782f6de86685f9555ffb94bbe2cf20b234daf660abb69ba3326f1ff","tests/parse-fail/confusing-line-comment3.wat.err":"4a5333dc02efa3c1eeab9cafa7c707f78abe92defdb01a71d6fe20944e4785f0","tests/parse-fail/confusing-line-comment4.wat":"9ecbbbe82c750e6475af1bfb46fe7a06115e4446a437d19fc08ca3d002f2a1c9","tests/parse-fail/confusing-line-comment4.wat.err":"ddb8aee8006265253b09c313cf5eb5c2dc4da66f502b4f6d3e2e1de77b35aec9","tests/parse-fail/confusing-line-comment5.wat":"8a4c8d342111bc9d37c16dbdf67c52027e1a42632abc9f359b3e4f07a85748b5","tests/parse-fail/confusing-line-comment5.wat.err":"34e368719fc0eab2f1a43c9f8e6f1b31aa9be9f971085d72374e49bde39cbfe5","tests/parse-fail/confusing-line-comment6.wat":"15f0dcdec23736ce92db84b3a7cdfe8689c97f2a7d0b9b0bfb0dcd2675163ed1","tests/parse-fail/confusing-line-comment6.wat.err":"0570be2ede803f071925d249f3858d3a417b5a6d678c9da40fc851d788d12983","tests/parse-fail/confusing-line-comment7.wat":"c7ee59301a701dd52d56cad02df78b0ad3584460bc18efa42ee137fe0c35aef6","tests/parse-fail/confusing-line-comment7.wat.err":"feebbeee8c85d8b3b85cec89435ae18f3ade9f754ca180d747a41406b64ca07a","tests/parse-fail/confusing-line-comment8.wat":"17632a8142154624de88b3cf93516147ed3419d785200bcd7049499eca8e8f04","tests/parse-fail/confusing-line-comment8.wat.err":"9c209285f2295cd2bc999aa7a9534a654932493308ab1f102839ed15a4d04d17","tests/parse-fail/confusing-string0.wat":"497b679b32baddcd6a158f4cadd3d9a9dea3457bac2a8c2c3d4e09b7c2d80842","tests/parse-fail/confusing-string0.wat.err":"cb3d737f2319346675a038716694354cd3b272453daa8a96e32e9861a9277f7b","tests/parse-fail/confusing-string1.wat":"46654cbed1ea6aab5019aef3d20098a391e40dacafa1ad5e83bf4ec384109fce","tests/parse-fail/confusing-string1.wat.err":"de7e7da516dc6c244bd0e4f012577b69f0cacbcc10f727fadb4b50bb04e0e2b4","tests/parse-fail/confusing-string2.wat":"11938f217c14387c05312735130f00c91d9df2d3ff9df7f13395e0f2b81dad54","tests/parse-fail/confusing-string2.wat.err":"e7bd08b146a855d681fefaf9e0576a9c333a2d10044f8e268b916b22a54227c9","tests/parse-fail/confusing-string3.wat":"e0ca4903fcafb9a54a91cf99e5eac95d25c6d2eb67b076f88191ad396f839cb6","tests/parse-fail/confusing-string3.wat.err":"b88d5db9e445c798eb24f95b7661b9c0368934d27ee8208477cd1c99351b939a","tests/parse-fail/confusing-string4.wat":"3ee2aee7f77604d051519c6f1795634469c12e98ae347a98f0c8445eecf1ff3d","tests/parse-fail/confusing-string4.wat.err":"1edc65bb09d8d3eed6ff69e7d9a7a4b5941dc823fa3436fa375657510255f6f4","tests/parse-fail/confusing-string5.wat":"024e50943128840d53f17e31a9b9332ce4f0ee70a847a043015f435b1c3c6e76","tests/parse-fail/confusing-string5.wat.err":"a0f13ec40d596ea2d8b0c4292b0d28775a5116ab7e11d7de88b295d25428c661","tests/parse-fail/confusing-string6.wat":"79cf157e29319800d2652c5a7f3dc90e07ebe2145c9904a70fc12027cdee84b7","tests/parse-fail/confusing-string6.wat.err":"860555e7aa13e3de3639cc2a530d6a42b974b629c4659593e972cbb0f306abae","tests/parse-fail/confusing-string7.wat":"7d8e403766dfb4e569754160d31ed0f9a27f908ed6cff96be43ab3d37f5975d5","tests/parse-fail/confusing-string7.wat.err":"658b6a02ba6d769254485f35c20984e7135d914b4266929963d723f26a40be4a","tests/parse-fail/confusing-string8.wat":"5a9b222e578655d57ee6e9f19bc1ea8e29aa52d652975fac685213444ed6458f","tests/parse-fail/confusing-string8.wat.err":"9a4e1a510330c800a1df7966998ebc3cde931eda20b249e5360f5e9a905dce11","tests/parse-fail/inline1.wat":"4e9767d67207aace2ac5e6f63a30e7510e4aa245ba35420539509e2254470272","tests/parse-fail/inline1.wat.err":"0143017a9825e518baa6009bae2c8d63520051dedd3437705bbe36b038a57f41","tests/parse-fail/newline-in-string.wat":"5c01cf709544ade0a6cdfcc39a3836a3bc018b633dc42a6cd872b6defc763ea7","tests/parse-fail/newline-in-string.wat.err":"1504209cc37a78b2aee778f23eacf78606daf964cf7bff251f5700efcd27ffd7","tests/parse-fail/string1.wat":"620d46d585ce94b382b5fde628c1399f3e562014b7a44af46e92f7bd045ca86e","tests/parse-fail/string1.wat.err":"fc53f3a1c4a65d8f25e5af51dec7699f45cecba114ca9c7871781bc70f664320","tests/parse-fail/string10.wat":"f7409dd45e153a1b11cb23e38f4ed87da12bedde38f8f0ccfe91037b0a4d97bd","tests/parse-fail/string10.wat.err":"ce677db5e37e0ed81ca357ed6b5edb21d85c27303ee194855bea7a88457efb6a","tests/parse-fail/string11.wat":"f6e0400b8c6a2014efa1ac676c567e140d8f86b5f4d5129773e6d67af537b615","tests/parse-fail/string11.wat.err":"4c6a550d29eda38a4e1bf7a589596f11655dc779479d7b8d466cfc53f815a742","tests/parse-fail/string12.wat":"23e30070eef22271651cce096a801fc4f79f3c37343c88bb8d2fc99b32d3b8b9","tests/parse-fail/string12.wat.err":"b5ec59f2996b88b2ee157e22d1774dc3e36fc08ed5bfc621aea830d30f66f586","tests/parse-fail/string13.wat":"81a305b981159ee10e140749ea3220c9edaaff53605e63c21995de47382b5faf","tests/parse-fail/string13.wat.err":"959f26c6b54e0d367b51d11d1addd8a53b5b8ff3caf70ebdd46bbea8ccfa2418","tests/parse-fail/string14.wat":"c45c2cc9f7afbfbd4be8e513106d22f7e5e817091448576c6bdf0701b81d95dd","tests/parse-fail/string14.wat.err":"50b5bccba905ddbe275938edb7ed0b09a5ca53dcdad36a7ff736ce9bc8e7a338","tests/parse-fail/string15.wat":"b5e0d5ade40de53b2d767a132e28376bb8c7a6f6238c4d8c248ae717c41d7f1f","tests/parse-fail/string15.wat.err":"0e9fc502cc90f96d1f592a3f63369fd2a3574bc4a2345a70365dbb76804e870f","tests/parse-fail/string16.wat":"38c3688cee80a9d089d239aa06eb1d27c5364ad2bd270aca57d05997c20aa682","tests/parse-fail/string16.wat.err":"4274b3bbe4df4cf0373619b1fcd082d0c802990817d2aca26ed885168c80e489","tests/parse-fail/string2.wat":"1172964aed31537b8c466d1f045f3e756926e7b221f80b2aff4a9a6721ea0beb","tests/parse-fail/string2.wat.err":"4618d3b20a78a077337eb5d6cae14ac39d9853762f011fbd23cff8921618dbde","tests/parse-fail/string3.wat":"07e0fbcd6270c1db100917c151ee4ac3f935e4ee1b27bce3c453b22b4b74f4d6","tests/parse-fail/string3.wat.err":"08ffc6158a9e030b2e211d53bdb8aeacfd879815c7b284d6a83b030566e35928","tests/parse-fail/string4.wat":"c970da2051b0613bdd1de4664f10424e14f2ebabe604175d4fb9b763b37af577","tests/parse-fail/string4.wat.err":"406706594d305c560fabd66417ad4fc276939990b5e701bd9d13fc223d207219","tests/parse-fail/string5.wat":"386cf314bb05acdaaabdf4da1caf140167271a26bd08bf34c3a7427d4bc4431f","tests/parse-fail/string5.wat.err":"1e56b44a23a37b2b2ad05aa9dd7e1e18191b5cc22151f93bbcf9d618779a57bd","tests/parse-fail/string6.wat":"8f1fe2825ff96f2acee9130a7721f86fcc93c221baa9411bf1fb6f0870d38ccb","tests/parse-fail/string6.wat.err":"d55dfd84d94e893f167ae73b7a080aefb2bfb05cc8a1ec201c4d3066fb8549b4","tests/parse-fail/string7.wat":"b12f8c75313d7f834489d3c353422f90bc945b37139586446eda82e334a97cde","tests/parse-fail/string7.wat.err":"4cee0ca61992c249dd0faaf2529a073cf8deeb36111a3f69b43695e5682560a2","tests/parse-fail/string8.wat":"4c2e0e1f883bb4e8cba9313497ed792130e5848e62bde7716102788d7467be10","tests/parse-fail/string8.wat.err":"840c6def7c60dd7c2b7261549cab435ba78c9b3a937adf6d5d9595ff8af01c91","tests/parse-fail/string9.wat":"2b7670caed2b0688d535de6e4e416f35fa717cfbe096a6cc764a669085c8f52f","tests/parse-fail/string9.wat.err":"37b5a9c3af9631500f31f9e5e3efa821b8d96063c57d60fd01df6be6a5c323e1","tests/parse-fail/unbalanced.wat":"f664fbef53a0308f864ba496d38044eb90482636e32586512939d4930729f3fe","tests/parse-fail/unbalanced.wat.err":"aba579f7b836856e69afe05da8328aabe0643d94e369898e686aa7bb0b07e9c9","tests/recursive.rs":"ad8a2b07bf955121a7c9e326ed35f9b2bc56b440c8cc0bbde24d423a79945c1a"},"package":"df21d01c2d91e46cb7a221d79e58a2d210ea02020d57c092e79255cc2999ca7f"} +\ No newline at end of file diff --git a/third_party/rust/wast/Cargo.lock b/third_party/rust/wast/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" dependencies = [ "anstyle", "anstyle-parse", @@ -19,73 +19,68 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" dependencies = [ - "windows-sys 0.52.0", + "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "once_cell_polyfill", + "windows-sys", ] [[package]] name = "anyhow" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "byteorder" -version = "1.5.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "clap" -version = "4.5.19" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", "clap_derive", @@ -93,9 +88,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.19" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstream", "anstyle", @@ -105,9 +100,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" dependencies = [ "heck", "proc-macro2", @@ -117,21 +112,21 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "escape8259" @@ -147,20 +142,21 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "getrandom" -version = "0.2.15" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", + "r-efi", "wasi", ] [[package]] name = "gimli" -version = "0.30.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e1d97fbe9722ba9bbd0c97051c2956e726562b61f86a25a4360398a40edfc9" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" dependencies = [ "fallible-iterator", "indexmap", @@ -169,9 +165,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" [[package]] name = "heck" @@ -180,16 +176,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] name = "indexmap" -version = "2.7.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", "hashbrown", @@ -209,81 +199,82 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libtest-mimic" -version = "0.7.3" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc0bda45ed5b3a2904262c1bb91e526127aa70e7ef3758aba2ef93cf896b9b58" +checksum = "5297962ef19edda4ce33aaa484386e0a5b3d7f2f4e037cbeee00503ef6b29d33" dependencies = [ + "anstream", + "anstyle", "clap", "escape8259", - "termcolor", - "threadpool", ] [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] -name = "num_cpus" -version = "1.16.0" +name = "once_cell_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] [[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] name = "rand" -version = "0.8.5" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ - "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" -version = "0.3.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", "rand_core", @@ -291,18 +282,18 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.4" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ "getrandom", ] [[package]] name = "semver" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "stable_deref_trait" @@ -318,9 +309,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.87" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -328,34 +319,16 @@ dependencies = [ ] [[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", -] - -[[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-width" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" [[package]] name = "utf8parse" @@ -365,15 +338,18 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] [[package]] name = "wasm-encoder" -version = "0.225.0" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f7eac0445cac73bcf09e6a97f83248d64356dccf9f2b100199769b6b42464e5" +checksum = "c55db9c896d70bd9fa535ce83cd4e1f2ec3726b0edd2142079f594fc3be1cb35" dependencies = [ "leb128fmt", "wasmparser", @@ -381,9 +357,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.225.0" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36e5456165f81e64cb9908a0fe9b9d852c2c74582aa3fe2be3c2da57f937d3ae" +checksum = "f6d8db401b0528ec316dfbe579e6ab4152d61739cfe076706d2009127970159d" dependencies = [ "bitflags", "indexmap", @@ -392,7 +368,7 @@ dependencies = [ [[package]] name = "wast" -version = "225.0.0" +version = "243.0.0" dependencies = [ "anyhow", "bumpalo", @@ -406,24 +382,6 @@ dependencies = [ ] [[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -497,20 +455,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ - "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", diff --git a/third_party/rust/wast/Cargo.toml b/third_party/rust/wast/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.76.0" name = "wast" -version = "225.0.0" +version = "243.0.0" authors = ["Alex Crichton <alex@alexcrichton.com>"] build = false autolib = false @@ -33,6 +33,18 @@ repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wa [package.metadata.docs.rs] all-features = true +[features] +component-model = [ + "wasm-module", + "wasm-encoder/component-model", +] +default = [ + "wasm-module", + "component-model", +] +dwarf = ["dep:gimli"] +wasm-module = [] + [lib] name = "wast" path = "src/lib.rs" @@ -58,7 +70,7 @@ path = "tests/recursive.rs" version = "3.14.0" [dependencies.gimli] -version = "0.30.0" +version = "0.31.1" optional = true [dependencies.leb128fmt] @@ -72,7 +84,7 @@ version = "2.4.1" version = "0.2.0" [dependencies.wasm-encoder] -version = "0.225.0" +version = "0.243.0" features = ["std"] default-features = false @@ -80,28 +92,21 @@ default-features = false version = "1.0.58" [dev-dependencies.libtest-mimic] -version = "0.7.0" +version = "0.8.1" [dev-dependencies.rand] -version = "0.8.4" +version = "0.9.1" features = ["small_rng"] -[features] -component-model = [ - "wasm-module", - "wasm-encoder/component-model", -] -default = [ - "wasm-module", - "component-model", -] -dwarf = ["dep:gimli"] -wasm-module = [] - [lints.clippy] +allow_attributes_without_reason = "warn" clone_on_copy = "warn" manual_strip = "warn" map_clone = "warn" +uninlined_format_args = "warn" +unnecessary_cast = "warn" +unnecessary_fallible_conversions = "warn" +unnecessary_mut_passed = "warn" unnecessary_to_owned = "warn" [lints.clippy.all] @@ -109,4 +114,22 @@ level = "allow" priority = -1 [lints.rust] +deprecated-safe-2024 = "warn" +keyword_idents_2024 = "warn" +missing-unsafe-on-extern = "warn" +rust-2024-guarded-string-incompatible-syntax = "warn" +rust-2024-incompatible-pat = "warn" +rust-2024-prelude-collisions = "warn" +unsafe-attr-outside-unsafe = "warn" +unsafe-op-in-unsafe-fn = "warn" unsafe_code = "deny" +unstable_features = "warn" +unused-lifetimes = "warn" +unused-macro-rules = "warn" +unused_extern_crates = "warn" +unused_import_braces = "warn" + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = ["cfg(fuzzing)"] diff --git a/third_party/rust/wast/src/component/alias.rs b/third_party/rust/wast/src/component/alias.rs @@ -53,7 +53,7 @@ impl<'a> Alias<'a> { let mut kind: ComponentOuterAliasKind = parser.parse()?; match kind { ComponentOuterAliasKind::CoreType => { - return Err(parser.error("expected type for outer alias")) + return Err(parser.error("expected type for outer alias")); } ComponentOuterAliasKind::Type => { kind = ComponentOuterAliasKind::CoreType; diff --git a/third_party/rust/wast/src/component/binary.rs b/third_party/rust/wast/src/component/binary.rs @@ -74,13 +74,9 @@ fn encode_type(encoder: ComponentTypeEncoder, ty: &TypeDef) { } TypeDef::Func(f) => { let mut encoder = encoder.function(); + encoder.async_(f.async_); encoder.params(f.params.iter().map(|p| (p.name, &p.ty))); - - if f.results.len() == 1 && f.results[0].name.is_none() { - encoder.result(&f.results[0].ty); - } else { - encoder.results(f.results.iter().map(|r| (r.name.unwrap_or(""), &r.ty))); - } + encoder.result(f.result.as_ref().map(|ty| ty.into())); } TypeDef::Component(c) => { encoder.component(&c.into()); @@ -113,6 +109,9 @@ fn encode_defined_type(encoder: ComponentDefinedTypeEncoder, ty: &ComponentDefin ComponentDefinedType::List(l) => { encoder.list(l.element.as_ref()); } + ComponentDefinedType::FixedSizeList(l) => { + encoder.fixed_size_list(l.element.as_ref(), l.elements); + } ComponentDefinedType::Tuple(t) => { encoder.tuple(t.fields.iter()); } @@ -164,6 +163,7 @@ struct Encoder<'a> { core_type_names: Vec<Option<&'a str>>, core_module_names: Vec<Option<&'a str>>, core_instance_names: Vec<Option<&'a str>>, + core_tag_names: Vec<Option<&'a str>>, func_names: Vec<Option<&'a str>>, value_names: Vec<Option<&'a str>>, type_names: Vec<Option<&'a str>>, @@ -332,133 +332,211 @@ impl<'a> Encoder<'a> { info.opts.iter().map(Into::into), ); } - CanonicalFuncKind::Lower(info) => { - self.core_func_names.push(name); - self.funcs - .lower(info.func.idx.into(), info.opts.iter().map(Into::into)); - } - CanonicalFuncKind::ResourceNew(info) => { - self.core_func_names.push(name); - self.funcs.resource_new(info.ty.into()); - } - CanonicalFuncKind::ResourceDrop(info) => { - self.core_func_names.push(name); - self.funcs.resource_drop(info.ty.into()); - } - CanonicalFuncKind::ResourceRep(info) => { - self.core_func_names.push(name); - self.funcs.resource_rep(info.ty.into()); - } - CanonicalFuncKind::ThreadSpawn(info) => { - self.core_func_names.push(name); - self.funcs.thread_spawn(info.ty.into()); - } - CanonicalFuncKind::ThreadHwConcurrency(_info) => { - self.core_func_names.push(name); - self.funcs.thread_hw_concurrency(); - } - CanonicalFuncKind::TaskBackpressure => { - self.core_func_names.push(name); - self.funcs.task_backpressure(); - } - CanonicalFuncKind::TaskReturn(info) => { - self.core_func_names.push(name); - self.funcs.task_return( - info.result - .as_ref() - .map(|ty| wasm_encoder::ComponentValType::from(ty)), - ); - } - CanonicalFuncKind::TaskWait(info) => { - self.core_func_names.push(name); - self.funcs.task_wait(info.async_, info.memory.idx.into()); - } - CanonicalFuncKind::TaskPoll(info) => { - self.core_func_names.push(name); - self.funcs.task_poll(info.async_, info.memory.idx.into()); - } - CanonicalFuncKind::TaskYield(info) => { - self.core_func_names.push(name); - self.funcs.task_yield(info.async_); - } - CanonicalFuncKind::SubtaskDrop => { - self.core_func_names.push(name); - self.funcs.subtask_drop(); - } - CanonicalFuncKind::StreamNew(info) => { - self.core_func_names.push(name); - self.funcs.stream_new(info.ty.into()); - } - CanonicalFuncKind::StreamRead(info) => { - self.core_func_names.push(name); - self.funcs - .stream_read(info.ty.into(), info.opts.iter().map(Into::into)); - } - CanonicalFuncKind::StreamWrite(info) => { - self.core_func_names.push(name); - self.funcs - .stream_write(info.ty.into(), info.opts.iter().map(Into::into)); - } - CanonicalFuncKind::StreamCancelRead(info) => { - self.core_func_names.push(name); - self.funcs.stream_cancel_read(info.ty.into(), info.async_); - } - CanonicalFuncKind::StreamCancelWrite(info) => { - self.core_func_names.push(name); - self.funcs.stream_cancel_write(info.ty.into(), info.async_); - } - CanonicalFuncKind::StreamCloseReadable(info) => { - self.core_func_names.push(name); - self.funcs.stream_close_readable(info.ty.into()); - } - CanonicalFuncKind::StreamCloseWritable(info) => { - self.core_func_names.push(name); - self.funcs.stream_close_writable(info.ty.into()); - } - CanonicalFuncKind::FutureNew(info) => { - self.core_func_names.push(name); - self.funcs.future_new(info.ty.into()); - } - CanonicalFuncKind::FutureRead(info) => { - self.core_func_names.push(name); - self.funcs - .future_read(info.ty.into(), info.opts.iter().map(Into::into)); - } - CanonicalFuncKind::FutureWrite(info) => { - self.core_func_names.push(name); - self.funcs - .future_write(info.ty.into(), info.opts.iter().map(Into::into)); - } - CanonicalFuncKind::FutureCancelRead(info) => { - self.core_func_names.push(name); - self.funcs.future_cancel_read(info.ty.into(), info.async_); - } - CanonicalFuncKind::FutureCancelWrite(info) => { - self.core_func_names.push(name); - self.funcs.future_cancel_write(info.ty.into(), info.async_); - } - CanonicalFuncKind::FutureCloseReadable(info) => { - self.core_func_names.push(name); - self.funcs.future_close_readable(info.ty.into()); - } - CanonicalFuncKind::FutureCloseWritable(info) => { - self.core_func_names.push(name); - self.funcs.future_close_writable(info.ty.into()); - } - CanonicalFuncKind::ErrorContextNew(info) => { - self.core_func_names.push(name); - self.funcs - .error_context_new(info.opts.iter().map(Into::into)); - } - CanonicalFuncKind::ErrorContextDebugMessage(info) => { - self.core_func_names.push(name); - self.funcs - .error_context_debug_message(info.opts.iter().map(Into::into)); - } - CanonicalFuncKind::ErrorContextDrop => { - self.core_func_names.push(name); - self.funcs.error_context_drop(); - } + CanonicalFuncKind::Core(core) => match core { + CoreFuncKind::Alias(_) => { + panic!("should have been removed during expansion") + } + CoreFuncKind::Lower(info) => { + self.core_func_names.push(name); + self.funcs + .lower(info.func.idx.into(), info.opts.iter().map(Into::into)); + } + CoreFuncKind::ResourceNew(info) => { + self.core_func_names.push(name); + self.funcs.resource_new(info.ty.into()); + } + CoreFuncKind::ResourceDrop(info) => { + self.core_func_names.push(name); + if info.async_ { + self.funcs.resource_drop_async(info.ty.into()); + } else { + self.funcs.resource_drop(info.ty.into()); + } + } + CoreFuncKind::ResourceRep(info) => { + self.core_func_names.push(name); + self.funcs.resource_rep(info.ty.into()); + } + CoreFuncKind::ThreadSpawnRef(info) => { + self.core_func_names.push(name); + self.funcs.thread_spawn_ref(info.ty.into()); + } + CoreFuncKind::ThreadSpawnIndirect(info) => { + self.core_func_names.push(name); + self.funcs + .thread_spawn_indirect(info.ty.into(), info.table.idx.into()); + } + CoreFuncKind::ThreadAvailableParallelism(_info) => { + self.core_func_names.push(name); + self.funcs.thread_available_parallelism(); + } + CoreFuncKind::BackpressureSet => { + self.core_func_names.push(name); + self.funcs.backpressure_set(); + } + CoreFuncKind::BackpressureInc => { + self.core_func_names.push(name); + self.funcs.backpressure_inc(); + } + CoreFuncKind::BackpressureDec => { + self.core_func_names.push(name); + self.funcs.backpressure_dec(); + } + CoreFuncKind::TaskReturn(info) => { + self.core_func_names.push(name); + self.funcs.task_return( + info.result + .as_ref() + .map(|ty| wasm_encoder::ComponentValType::from(ty)), + info.opts.iter().map(Into::into), + ); + } + CoreFuncKind::TaskCancel => { + self.core_func_names.push(name); + self.funcs.task_cancel(); + } + CoreFuncKind::ContextGet(i) => { + self.core_func_names.push(name); + self.funcs.context_get(*i); + } + CoreFuncKind::ContextSet(i) => { + self.core_func_names.push(name); + self.funcs.context_set(*i); + } + CoreFuncKind::ThreadYield(info) => { + self.core_func_names.push(name); + self.funcs.thread_yield(info.cancellable); + } + CoreFuncKind::SubtaskDrop => { + self.core_func_names.push(name); + self.funcs.subtask_drop(); + } + CoreFuncKind::SubtaskCancel(info) => { + self.core_func_names.push(name); + self.funcs.subtask_cancel(info.async_); + } + CoreFuncKind::StreamNew(info) => { + self.core_func_names.push(name); + self.funcs.stream_new(info.ty.into()); + } + CoreFuncKind::StreamRead(info) => { + self.core_func_names.push(name); + self.funcs + .stream_read(info.ty.into(), info.opts.iter().map(Into::into)); + } + CoreFuncKind::StreamWrite(info) => { + self.core_func_names.push(name); + self.funcs + .stream_write(info.ty.into(), info.opts.iter().map(Into::into)); + } + CoreFuncKind::StreamCancelRead(info) => { + self.core_func_names.push(name); + self.funcs.stream_cancel_read(info.ty.into(), info.async_); + } + CoreFuncKind::StreamCancelWrite(info) => { + self.core_func_names.push(name); + self.funcs.stream_cancel_write(info.ty.into(), info.async_); + } + CoreFuncKind::StreamDropReadable(info) => { + self.core_func_names.push(name); + self.funcs.stream_drop_readable(info.ty.into()); + } + CoreFuncKind::StreamDropWritable(info) => { + self.core_func_names.push(name); + self.funcs.stream_drop_writable(info.ty.into()); + } + CoreFuncKind::FutureNew(info) => { + self.core_func_names.push(name); + self.funcs.future_new(info.ty.into()); + } + CoreFuncKind::FutureRead(info) => { + self.core_func_names.push(name); + self.funcs + .future_read(info.ty.into(), info.opts.iter().map(Into::into)); + } + CoreFuncKind::FutureWrite(info) => { + self.core_func_names.push(name); + self.funcs + .future_write(info.ty.into(), info.opts.iter().map(Into::into)); + } + CoreFuncKind::FutureCancelRead(info) => { + self.core_func_names.push(name); + self.funcs.future_cancel_read(info.ty.into(), info.async_); + } + CoreFuncKind::FutureCancelWrite(info) => { + self.core_func_names.push(name); + self.funcs.future_cancel_write(info.ty.into(), info.async_); + } + CoreFuncKind::FutureDropReadable(info) => { + self.core_func_names.push(name); + self.funcs.future_drop_readable(info.ty.into()); + } + CoreFuncKind::FutureDropWritable(info) => { + self.core_func_names.push(name); + self.funcs.future_drop_writable(info.ty.into()); + } + CoreFuncKind::ErrorContextNew(info) => { + self.core_func_names.push(name); + self.funcs + .error_context_new(info.opts.iter().map(Into::into)); + } + CoreFuncKind::ErrorContextDebugMessage(info) => { + self.core_func_names.push(name); + self.funcs + .error_context_debug_message(info.opts.iter().map(Into::into)); + } + CoreFuncKind::ErrorContextDrop => { + self.core_func_names.push(name); + self.funcs.error_context_drop(); + } + CoreFuncKind::WaitableSetNew => { + self.core_func_names.push(name); + self.funcs.waitable_set_new(); + } + CoreFuncKind::WaitableSetWait(info) => { + self.core_func_names.push(name); + self.funcs + .waitable_set_wait(info.async_, info.memory.idx.into()); + } + CoreFuncKind::WaitableSetPoll(info) => { + self.core_func_names.push(name); + self.funcs + .waitable_set_poll(info.async_, info.memory.idx.into()); + } + CoreFuncKind::WaitableSetDrop => { + self.core_func_names.push(name); + self.funcs.waitable_set_drop(); + } + CoreFuncKind::WaitableJoin => { + self.core_func_names.push(name); + self.funcs.waitable_join(); + } + CoreFuncKind::ThreadIndex => { + self.core_func_names.push(name); + self.funcs.thread_index(); + } + CoreFuncKind::ThreadNewIndirect(info) => { + self.core_func_names.push(name); + self.funcs + .thread_new_indirect(info.ty.into(), info.table.idx.into()); + } + CoreFuncKind::ThreadSwitchTo(info) => { + self.core_func_names.push(name); + self.funcs.thread_switch_to(info.cancellable); + } + CoreFuncKind::ThreadSuspend(info) => { + self.core_func_names.push(name); + self.funcs.thread_suspend(info.cancellable); + } + CoreFuncKind::ThreadResumeLater => { + self.core_func_names.push(name); + self.funcs.thread_resume_later(); + } + CoreFuncKind::ThreadYieldTo(info) => { + self.core_func_names.push(name); + self.funcs.thread_yield_to(info.cancellable); + } + }, } self.flush(Some(self.funcs.id())); @@ -576,6 +654,7 @@ impl<'a> Encoder<'a> { funcs(&self.core_table_names, ComponentNameSection::core_tables); funcs(&self.core_memory_names, ComponentNameSection::core_memories); funcs(&self.core_global_names, ComponentNameSection::core_globals); + funcs(&self.core_tag_names, ComponentNameSection::core_tags); funcs(&self.core_type_names, ComponentNameSection::core_types); funcs(&self.core_module_names, ComponentNameSection::core_modules); funcs( @@ -625,7 +704,7 @@ impl<'a> Encoder<'a> { core::ExportKind::Global => &mut self.core_global_names, core::ExportKind::Table => &mut self.core_table_names, core::ExportKind::Memory => &mut self.core_memory_names, - core::ExportKind::Tag => unimplemented!(), + core::ExportKind::Tag => &mut self.core_tag_names, } } @@ -744,6 +823,7 @@ impl From<PrimitiveValType> for wasm_encoder::PrimitiveValType { PrimitiveValType::F64 => Self::F64, PrimitiveValType::Char => Self::Char, PrimitiveValType::String => Self::String, + PrimitiveValType::ErrorContext => Self::ErrorContext, } } } @@ -928,6 +1008,8 @@ impl From<&CanonOpt<'_>> for wasm_encoder::CanonicalOption { CanonOpt::PostReturn(f) => Self::PostReturn(f.idx.into()), CanonOpt::Async => Self::Async, CanonOpt::Callback(f) => Self::Callback(f.idx.into()), + CanonOpt::CoreType(t) => Self::CoreType(t.idx.into()), + CanonOpt::Gc => Self::Gc, } } } diff --git a/third_party/rust/wast/src/component/component.rs b/third_party/rust/wast/src/component/component.rs @@ -90,21 +90,6 @@ impl<'a> Component<'a> { crate::core::EncodeOptions::default().encode_component(self) } - pub(crate) fn validate(&self, parser: Parser<'_>) -> Result<()> { - let mut starts = 0; - if let ComponentKind::Text(fields) = &self.kind { - for item in fields.iter() { - if let ComponentField::Start(_) = item { - starts += 1; - } - } - } - if starts > 1 { - return Err(parser.error("multiple start sections found")); - } - Ok(()) - } - pub(crate) fn parse_without_component_keyword( component_keyword_span: Span, parser: Parser<'a>, @@ -216,6 +201,9 @@ impl<'a> Parse<'a> for ComponentField<'a> { if parser.peek::<kw::start>()? { return Ok(Self::Start(parser.parse()?)); } + if parser.peek::<kw::canon>()? { + return Ok(Self::CanonicalFunc(parser.parse()?)); + } if parser.peek::<annotation::custom>()? { return Ok(Self::Custom(parser.parse()?)); } diff --git a/third_party/rust/wast/src/component/expand.rs b/third_party/rust/wast/src/component/expand.rs @@ -264,39 +264,14 @@ impl<'a> Expander<'a> { CanonicalFuncKind::Lift { ty, .. } => { self.expand_component_type_use(ty); } - CanonicalFuncKind::Lower(_) - | CanonicalFuncKind::ResourceNew(_) - | CanonicalFuncKind::ResourceRep(_) - | CanonicalFuncKind::ResourceDrop(_) - | CanonicalFuncKind::ThreadSpawn(_) - | CanonicalFuncKind::ThreadHwConcurrency(_) - | CanonicalFuncKind::TaskBackpressure - | CanonicalFuncKind::TaskReturn(_) - | CanonicalFuncKind::TaskWait(_) - | CanonicalFuncKind::TaskPoll(_) - | CanonicalFuncKind::TaskYield(_) - | CanonicalFuncKind::SubtaskDrop - | CanonicalFuncKind::StreamNew(_) - | CanonicalFuncKind::StreamRead(_) - | CanonicalFuncKind::StreamWrite(_) - | CanonicalFuncKind::StreamCancelRead(_) - | CanonicalFuncKind::StreamCancelWrite(_) - | CanonicalFuncKind::StreamCloseReadable(_) - | CanonicalFuncKind::StreamCloseWritable(_) - | CanonicalFuncKind::FutureNew(_) - | CanonicalFuncKind::FutureRead(_) - | CanonicalFuncKind::FutureWrite(_) - | CanonicalFuncKind::FutureCancelRead(_) - | CanonicalFuncKind::FutureCancelWrite(_) - | CanonicalFuncKind::FutureCloseReadable(_) - | CanonicalFuncKind::FutureCloseWritable(_) - | CanonicalFuncKind::ErrorContextNew(_) - | CanonicalFuncKind::ErrorContextDebugMessage(_) - | CanonicalFuncKind::ErrorContextDrop => {} + CanonicalFuncKind::Core(func) => { + self.expand_core_func_kind(func); + } } } - fn expand_core_func(&mut self, func: CoreFunc<'a>) -> ComponentField<'a> { + fn expand_core_func(&mut self, mut func: CoreFunc<'a>) -> ComponentField<'a> { + self.expand_core_func_kind(&mut func.kind); match func.kind { CoreFuncKind::Alias(a) => ComponentField::Alias(Alias { span: func.span, @@ -308,192 +283,25 @@ impl<'a> Expander<'a> { kind: core::ExportKind::Func, }, }), - CoreFuncKind::Lower(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::Lower(info), - }), - CoreFuncKind::ResourceNew(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::ResourceNew(info), - }), - CoreFuncKind::ResourceDrop(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::ResourceDrop(info), - }), - CoreFuncKind::ResourceRep(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::ResourceRep(info), - }), - CoreFuncKind::ThreadSpawn(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::ThreadSpawn(info), - }), - CoreFuncKind::ThreadHwConcurrency(info) => { - ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::ThreadHwConcurrency(info), - }) - } - CoreFuncKind::TaskBackpressure => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::TaskBackpressure, - }), - CoreFuncKind::TaskReturn(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::TaskReturn(info), - }), - CoreFuncKind::TaskWait(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::TaskWait(info), - }), - CoreFuncKind::TaskPoll(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::TaskPoll(info), - }), - CoreFuncKind::TaskYield(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::TaskYield(info), - }), - CoreFuncKind::SubtaskDrop => ComponentField::CanonicalFunc(CanonicalFunc { + other => ComponentField::CanonicalFunc(CanonicalFunc { span: func.span, id: func.id, name: func.name, - kind: CanonicalFuncKind::SubtaskDrop, + kind: CanonicalFuncKind::Core(other), }), - CoreFuncKind::StreamNew(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::StreamNew(info), - }), - CoreFuncKind::StreamRead(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::StreamRead(info), - }), - CoreFuncKind::StreamWrite(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::StreamWrite(info), - }), - CoreFuncKind::StreamCancelRead(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::StreamCancelRead(info), - }), - CoreFuncKind::StreamCancelWrite(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::StreamCancelWrite(info), - }), - CoreFuncKind::StreamCloseReadable(info) => { - ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::StreamCloseReadable(info), - }) - } - CoreFuncKind::StreamCloseWritable(info) => { - ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::StreamCloseWritable(info), - }) - } - CoreFuncKind::FutureNew(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::FutureNew(info), - }), - CoreFuncKind::FutureRead(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::FutureRead(info), - }), - CoreFuncKind::FutureWrite(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::FutureWrite(info), - }), - CoreFuncKind::FutureCancelRead(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::FutureCancelRead(info), - }), - CoreFuncKind::FutureCancelWrite(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::FutureCancelWrite(info), - }), - CoreFuncKind::FutureCloseReadable(info) => { - ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::FutureCloseReadable(info), - }) - } - CoreFuncKind::FutureCloseWritable(info) => { - ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::FutureCloseWritable(info), - }) - } - CoreFuncKind::ErrorContextNew(info) => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::ErrorContextNew(info), - }), - CoreFuncKind::ErrorContextDebugMessage(info) => { - ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::ErrorContextDebugMessage(info), - }) + } + } + + fn expand_core_func_kind(&mut self, func: &mut CoreFuncKind<'a>) { + match func { + CoreFuncKind::TaskReturn(f) => { + if let Some(ty) = &mut f.result { + self.expand_component_val_ty(ty); + } } - CoreFuncKind::ErrorContextDrop => ComponentField::CanonicalFunc(CanonicalFunc { - span: func.span, - id: func.id, - name: func.name, - kind: CanonicalFuncKind::ErrorContextDrop, - }), + + // Other core funcs don't need expansion at this time + _ => {} } } @@ -599,8 +407,8 @@ impl<'a> Expander<'a> { self.expand_component_val_ty(&mut param.ty); } - for result in ty.results.iter_mut() { - self.expand_component_val_ty(&mut result.ty); + if let Some(result) = &mut ty.result { + self.expand_component_val_ty(result); } } @@ -645,7 +453,9 @@ impl<'a> Expander<'a> { func_type_to_idx: &mut HashMap<FuncKey<'a>, Index<'a>>, ) { match &mut item.kind { - core::ItemKind::Func(t) | core::ItemKind::Tag(core::TagType::Exception(t)) => { + core::ItemKind::Func(t) + | core::ItemKind::FuncExact(t) + | core::ItemKind::Tag(core::TagType::Exception(t)) => { // If the index is already filled in then this is skipped. if t.index.is_some() { return; @@ -740,8 +550,12 @@ impl<'a> Expander<'a> { } } } - ComponentDefinedType::List(t) => { - self.expand_component_val_ty(&mut t.element); + ComponentDefinedType::List(List { element: t }) + | ComponentDefinedType::FixedSizeList(FixedSizeList { + element: t, + elements: _, + }) => { + self.expand_component_val_ty(t); } ComponentDefinedType::Tuple(t) => { for field in t.fields.iter_mut() { diff --git a/third_party/rust/wast/src/component/func.rs b/third_party/rust/wast/src/component/func.rs @@ -1,6 +1,6 @@ use crate::component::*; use crate::kw; -use crate::parser::{Parse, Parser, Result}; +use crate::parser::{Cursor, Lookahead1, Parse, Parser, Peek, Result}; use crate::token::{Id, Index, LParen, NameAnnotation, Span}; /// A declared core function. @@ -25,7 +25,7 @@ impl<'a> Parse<'a> for CoreFunc<'a> { parser.parse::<kw::func>()?; let id = parser.parse()?; let name = parser.parse()?; - let kind = parser.parse()?; + let kind = parser.parens(|p| p.parse())?; Ok(Self { span, @@ -51,110 +51,175 @@ pub enum CoreFuncKind<'a> { ResourceNew(CanonResourceNew<'a>), ResourceDrop(CanonResourceDrop<'a>), ResourceRep(CanonResourceRep<'a>), - ThreadSpawn(CanonThreadSpawn<'a>), - ThreadHwConcurrency(CanonThreadHwConcurrency), - TaskBackpressure, + ThreadSpawnRef(CanonThreadSpawnRef<'a>), + ThreadSpawnIndirect(CanonThreadSpawnIndirect<'a>), + ThreadAvailableParallelism(CanonThreadAvailableParallelism), + BackpressureSet, + BackpressureInc, + BackpressureDec, TaskReturn(CanonTaskReturn<'a>), - TaskWait(CanonTaskWait<'a>), - TaskPoll(CanonTaskPoll<'a>), - TaskYield(CanonTaskYield), + TaskCancel, + ContextGet(u32), + ContextSet(u32), + ThreadYield(CanonThreadYield), SubtaskDrop, + SubtaskCancel(CanonSubtaskCancel), StreamNew(CanonStreamNew<'a>), StreamRead(CanonStreamRead<'a>), StreamWrite(CanonStreamWrite<'a>), StreamCancelRead(CanonStreamCancelRead<'a>), StreamCancelWrite(CanonStreamCancelWrite<'a>), - StreamCloseReadable(CanonStreamCloseReadable<'a>), - StreamCloseWritable(CanonStreamCloseWritable<'a>), + StreamDropReadable(CanonStreamDropReadable<'a>), + StreamDropWritable(CanonStreamDropWritable<'a>), FutureNew(CanonFutureNew<'a>), FutureRead(CanonFutureRead<'a>), FutureWrite(CanonFutureWrite<'a>), FutureCancelRead(CanonFutureCancelRead<'a>), FutureCancelWrite(CanonFutureCancelWrite<'a>), - FutureCloseReadable(CanonFutureCloseReadable<'a>), - FutureCloseWritable(CanonFutureCloseWritable<'a>), + FutureDropReadable(CanonFutureDropReadable<'a>), + FutureDropWritable(CanonFutureDropWritable<'a>), ErrorContextNew(CanonErrorContextNew<'a>), ErrorContextDebugMessage(CanonErrorContextDebugMessage<'a>), ErrorContextDrop, + WaitableSetNew, + WaitableSetWait(CanonWaitableSetWait<'a>), + WaitableSetPoll(CanonWaitableSetPoll<'a>), + WaitableSetDrop, + WaitableJoin, + ThreadIndex, + ThreadNewIndirect(CanonThreadNewIndirect<'a>), + ThreadSwitchTo(CanonThreadSwitchTo), + ThreadSuspend(CanonThreadSuspend), + ThreadResumeLater, + ThreadYieldTo(CanonThreadYieldTo), } impl<'a> Parse<'a> for CoreFuncKind<'a> { fn parse(parser: Parser<'a>) -> Result<Self> { - parser.parens(|parser| { - let mut l = parser.lookahead1(); - if l.peek::<kw::canon>()? { - parser.parse::<kw::canon>()?; - } else if l.peek::<kw::alias>()? { - return Ok(Self::Alias(parser.parse()?)); - } else { - return Err(l.error()); - } - let mut l = parser.lookahead1(); - if l.peek::<kw::lower>()? { - Ok(CoreFuncKind::Lower(parser.parse()?)) - } else if l.peek::<kw::resource_new>()? { - Ok(CoreFuncKind::ResourceNew(parser.parse()?)) - } else if l.peek::<kw::resource_drop>()? { - Ok(CoreFuncKind::ResourceDrop(parser.parse()?)) - } else if l.peek::<kw::resource_rep>()? { - Ok(CoreFuncKind::ResourceRep(parser.parse()?)) - } else if l.peek::<kw::thread_spawn>()? { - Ok(CoreFuncKind::ThreadSpawn(parser.parse()?)) - } else if l.peek::<kw::thread_hw_concurrency>()? { - Ok(CoreFuncKind::ThreadHwConcurrency(parser.parse()?)) - } else if l.peek::<kw::task_backpressure>()? { - parser.parse::<kw::task_backpressure>()?; - Ok(CoreFuncKind::TaskBackpressure) - } else if l.peek::<kw::task_return>()? { - Ok(CoreFuncKind::TaskReturn(parser.parse()?)) - } else if l.peek::<kw::task_wait>()? { - Ok(CoreFuncKind::TaskWait(parser.parse()?)) - } else if l.peek::<kw::task_poll>()? { - Ok(CoreFuncKind::TaskPoll(parser.parse()?)) - } else if l.peek::<kw::task_yield>()? { - Ok(CoreFuncKind::TaskYield(parser.parse()?)) - } else if l.peek::<kw::subtask_drop>()? { - parser.parse::<kw::subtask_drop>()?; - Ok(CoreFuncKind::SubtaskDrop) - } else if l.peek::<kw::stream_new>()? { - Ok(CoreFuncKind::StreamNew(parser.parse()?)) - } else if l.peek::<kw::stream_read>()? { - Ok(CoreFuncKind::StreamRead(parser.parse()?)) - } else if l.peek::<kw::stream_write>()? { - Ok(CoreFuncKind::StreamWrite(parser.parse()?)) - } else if l.peek::<kw::stream_cancel_read>()? { - Ok(CoreFuncKind::StreamCancelRead(parser.parse()?)) - } else if l.peek::<kw::stream_cancel_write>()? { - Ok(CoreFuncKind::StreamCancelWrite(parser.parse()?)) - } else if l.peek::<kw::stream_close_readable>()? { - Ok(CoreFuncKind::StreamCloseReadable(parser.parse()?)) - } else if l.peek::<kw::stream_close_writable>()? { - Ok(CoreFuncKind::StreamCloseWritable(parser.parse()?)) - } else if l.peek::<kw::future_new>()? { - Ok(CoreFuncKind::FutureNew(parser.parse()?)) - } else if l.peek::<kw::future_read>()? { - Ok(CoreFuncKind::FutureRead(parser.parse()?)) - } else if l.peek::<kw::future_write>()? { - Ok(CoreFuncKind::FutureWrite(parser.parse()?)) - } else if l.peek::<kw::future_cancel_read>()? { - Ok(CoreFuncKind::FutureCancelRead(parser.parse()?)) - } else if l.peek::<kw::future_cancel_write>()? { - Ok(CoreFuncKind::FutureCancelWrite(parser.parse()?)) - } else if l.peek::<kw::future_close_readable>()? { - Ok(CoreFuncKind::FutureCloseReadable(parser.parse()?)) - } else if l.peek::<kw::future_close_writable>()? { - Ok(CoreFuncKind::FutureCloseWritable(parser.parse()?)) - } else if l.peek::<kw::error_context_new>()? { - Ok(CoreFuncKind::ErrorContextNew(parser.parse()?)) - } else if l.peek::<kw::error_context_debug_message>()? { - Ok(CoreFuncKind::ErrorContextDebugMessage(parser.parse()?)) - } else if l.peek::<kw::error_context_drop>()? { - parser.parse::<kw::error_context_drop>()?; - Ok(CoreFuncKind::ErrorContextDrop) - } else { - Err(l.error()) - } - }) + let mut l = parser.lookahead1(); + if l.peek::<kw::canon>()? { + parser.parse::<kw::canon>()?; + } else if l.peek::<kw::alias>()? { + return Ok(Self::Alias(parser.parse()?)); + } else { + return Err(l.error()); + } + + CoreFuncKind::parse_lookahead(parser.lookahead1()) + } +} + +impl<'a> CoreFuncKind<'a> { + fn parse_lookahead(mut l: Lookahead1<'a>) -> Result<CoreFuncKind<'a>> { + let parser = l.parser(); + if l.peek::<kw::lower>()? { + Ok(CoreFuncKind::Lower(parser.parse()?)) + } else if l.peek::<kw::resource_new>()? { + Ok(CoreFuncKind::ResourceNew(parser.parse()?)) + } else if l.peek::<kw::resource_drop>()? { + Ok(CoreFuncKind::ResourceDrop(parser.parse()?)) + } else if l.peek::<kw::resource_rep>()? { + Ok(CoreFuncKind::ResourceRep(parser.parse()?)) + } else if l.peek::<kw::thread_spawn_ref>()? { + Ok(CoreFuncKind::ThreadSpawnRef(parser.parse()?)) + } else if l.peek::<kw::thread_spawn_indirect>()? { + Ok(CoreFuncKind::ThreadSpawnIndirect(parser.parse()?)) + } else if l.peek::<kw::thread_available_parallelism>()? { + Ok(CoreFuncKind::ThreadAvailableParallelism(parser.parse()?)) + } else if l.peek::<kw::backpressure_set>()? { + parser.parse::<kw::backpressure_set>()?; + Ok(CoreFuncKind::BackpressureSet) + } else if l.peek::<kw::backpressure_inc>()? { + parser.parse::<kw::backpressure_inc>()?; + Ok(CoreFuncKind::BackpressureInc) + } else if l.peek::<kw::backpressure_dec>()? { + parser.parse::<kw::backpressure_dec>()?; + Ok(CoreFuncKind::BackpressureDec) + } else if l.peek::<kw::task_return>()? { + Ok(CoreFuncKind::TaskReturn(parser.parse()?)) + } else if l.peek::<kw::task_cancel>()? { + parser.parse::<kw::task_cancel>()?; + Ok(CoreFuncKind::TaskCancel) + } else if l.peek::<kw::context_get>()? { + parser.parse::<kw::context_get>()?; + parser.parse::<kw::i32>()?; + Ok(CoreFuncKind::ContextGet(parser.parse()?)) + } else if l.peek::<kw::context_set>()? { + parser.parse::<kw::context_set>()?; + parser.parse::<kw::i32>()?; + Ok(CoreFuncKind::ContextSet(parser.parse()?)) + } else if l.peek::<kw::thread_yield>()? { + Ok(CoreFuncKind::ThreadYield(parser.parse()?)) + } else if l.peek::<kw::subtask_drop>()? { + parser.parse::<kw::subtask_drop>()?; + Ok(CoreFuncKind::SubtaskDrop) + } else if l.peek::<kw::subtask_cancel>()? { + Ok(CoreFuncKind::SubtaskCancel(parser.parse()?)) + } else if l.peek::<kw::stream_new>()? { + Ok(CoreFuncKind::StreamNew(parser.parse()?)) + } else if l.peek::<kw::stream_read>()? { + Ok(CoreFuncKind::StreamRead(parser.parse()?)) + } else if l.peek::<kw::stream_write>()? { + Ok(CoreFuncKind::StreamWrite(parser.parse()?)) + } else if l.peek::<kw::stream_cancel_read>()? { + Ok(CoreFuncKind::StreamCancelRead(parser.parse()?)) + } else if l.peek::<kw::stream_cancel_write>()? { + Ok(CoreFuncKind::StreamCancelWrite(parser.parse()?)) + } else if l.peek::<kw::stream_drop_readable>()? { + Ok(CoreFuncKind::StreamDropReadable(parser.parse()?)) + } else if l.peek::<kw::stream_drop_writable>()? { + Ok(CoreFuncKind::StreamDropWritable(parser.parse()?)) + } else if l.peek::<kw::future_new>()? { + Ok(CoreFuncKind::FutureNew(parser.parse()?)) + } else if l.peek::<kw::future_read>()? { + Ok(CoreFuncKind::FutureRead(parser.parse()?)) + } else if l.peek::<kw::future_write>()? { + Ok(CoreFuncKind::FutureWrite(parser.parse()?)) + } else if l.peek::<kw::future_cancel_read>()? { + Ok(CoreFuncKind::FutureCancelRead(parser.parse()?)) + } else if l.peek::<kw::future_cancel_write>()? { + Ok(CoreFuncKind::FutureCancelWrite(parser.parse()?)) + } else if l.peek::<kw::future_drop_readable>()? { + Ok(CoreFuncKind::FutureDropReadable(parser.parse()?)) + } else if l.peek::<kw::future_drop_writable>()? { + Ok(CoreFuncKind::FutureDropWritable(parser.parse()?)) + } else if l.peek::<kw::error_context_new>()? { + Ok(CoreFuncKind::ErrorContextNew(parser.parse()?)) + } else if l.peek::<kw::error_context_debug_message>()? { + Ok(CoreFuncKind::ErrorContextDebugMessage(parser.parse()?)) + } else if l.peek::<kw::error_context_drop>()? { + parser.parse::<kw::error_context_drop>()?; + Ok(CoreFuncKind::ErrorContextDrop) + } else if l.peek::<kw::waitable_set_new>()? { + parser.parse::<kw::waitable_set_new>()?; + Ok(CoreFuncKind::WaitableSetNew) + } else if l.peek::<kw::waitable_set_wait>()? { + Ok(CoreFuncKind::WaitableSetWait(parser.parse()?)) + } else if l.peek::<kw::waitable_set_poll>()? { + Ok(CoreFuncKind::WaitableSetPoll(parser.parse()?)) + } else if l.peek::<kw::waitable_set_drop>()? { + parser.parse::<kw::waitable_set_drop>()?; + Ok(CoreFuncKind::WaitableSetDrop) + } else if l.peek::<kw::waitable_join>()? { + parser.parse::<kw::waitable_join>()?; + Ok(CoreFuncKind::WaitableJoin) + } else if l.peek::<kw::thread_index>()? { + parser.parse::<kw::thread_index>()?; + Ok(CoreFuncKind::ThreadIndex) + } else if l.peek::<kw::thread_new_indirect>()? { + Ok(CoreFuncKind::ThreadNewIndirect(parser.parse()?)) + } else if l.peek::<kw::thread_switch_to>()? { + Ok(CoreFuncKind::ThreadSwitchTo(parser.parse()?)) + } else if l.peek::<kw::thread_suspend>()? { + Ok(CoreFuncKind::ThreadSuspend(parser.parse()?)) + } else if l.peek::<kw::thread_resume_later>()? { + parser.parse::<kw::thread_resume_later>()?; + Ok(CoreFuncKind::ThreadResumeLater) + } else if l.peek::<kw::thread_yield_to>()? { + Ok(CoreFuncKind::ThreadYieldTo(parser.parse()?)) + } else { + Err(l.error()) + } } } @@ -264,8 +329,9 @@ pub struct CanonicalFunc<'a> { impl<'a> Parse<'a> for CanonicalFunc<'a> { fn parse(parser: Parser<'a>) -> Result<Self> { let span = parser.parse::<kw::canon>()?.0; + let mut l = parser.lookahead1(); - if parser.peek::<kw::lift>()? { + if l.peek::<kw::lift>()? { let info = parser.parse()?; let (id, name, ty) = parser.parens(|parser| { parser.parse::<kw::func>()?; @@ -281,44 +347,23 @@ impl<'a> Parse<'a> for CanonicalFunc<'a> { name, kind: CanonicalFuncKind::Lift { info, ty }, }) - } else if parser.peek::<kw::lower>()? { - Self::parse_core_func(span, parser, CanonicalFuncKind::Lower) - } else if parser.peek::<kw::resource_new>()? { - Self::parse_core_func(span, parser, CanonicalFuncKind::ResourceNew) - } else if parser.peek::<kw::resource_drop>()? { - Self::parse_core_func(span, parser, CanonicalFuncKind::ResourceDrop) - } else if parser.peek::<kw::resource_rep>()? { - Self::parse_core_func(span, parser, CanonicalFuncKind::ResourceRep) } else { - Err(parser.error("expected `canon lift` or `canon lower`")) - } - } -} - -impl<'a> CanonicalFunc<'a> { - fn parse_core_func<T>( - span: Span, - parser: Parser<'a>, - variant: fn(T) -> CanonicalFuncKind<'a>, - ) -> Result<Self> - where - T: Parse<'a>, - { - let info = parser.parse()?; - let (id, name) = parser.parens(|parser| { - parser.parse::<kw::core>()?; - parser.parse::<kw::func>()?; - let id = parser.parse()?; - let name = parser.parse()?; - Ok((id, name)) - })?; + let kind = CoreFuncKind::parse_lookahead(l)?; + let (id, name) = parser.parens(|parser| { + parser.parse::<kw::core>()?; + parser.parse::<kw::func>()?; + let id = parser.parse()?; + let name = parser.parse()?; + Ok((id, name)) + })?; - Ok(Self { - span, - id, - name, - kind: variant(info), - }) + Ok(Self { + span, + id, + name, + kind: CanonicalFuncKind::Core(kind), + }) + } } } @@ -333,39 +378,10 @@ pub enum CanonicalFuncKind<'a> { /// Information relating to the lifting of the core function. info: CanonLift<'a>, }, - /// A canonical function that is defined in terms of lowering a component function. - Lower(CanonLower<'a>), - - ResourceNew(CanonResourceNew<'a>), - ResourceDrop(CanonResourceDrop<'a>), - ResourceRep(CanonResourceRep<'a>), - ThreadSpawn(CanonThreadSpawn<'a>), - ThreadHwConcurrency(CanonThreadHwConcurrency), - - TaskBackpressure, - TaskReturn(CanonTaskReturn<'a>), - TaskWait(CanonTaskWait<'a>), - TaskPoll(CanonTaskPoll<'a>), - TaskYield(CanonTaskYield), - SubtaskDrop, - StreamNew(CanonStreamNew<'a>), - StreamRead(CanonStreamRead<'a>), - StreamWrite(CanonStreamWrite<'a>), - StreamCancelRead(CanonStreamCancelRead<'a>), - StreamCancelWrite(CanonStreamCancelWrite<'a>), - StreamCloseReadable(CanonStreamCloseReadable<'a>), - StreamCloseWritable(CanonStreamCloseWritable<'a>), - FutureNew(CanonFutureNew<'a>), - FutureRead(CanonFutureRead<'a>), - FutureWrite(CanonFutureWrite<'a>), - FutureCancelRead(CanonFutureCancelRead<'a>), - FutureCancelWrite(CanonFutureCancelWrite<'a>), - FutureCloseReadable(CanonFutureCloseReadable<'a>), - FutureCloseWritable(CanonFutureCloseWritable<'a>), - ErrorContextNew(CanonErrorContextNew<'a>), - ErrorContextDebugMessage(CanonErrorContextDebugMessage<'a>), - ErrorContextDrop, + /// A canonical function that defines a core function, whose variants are + /// delegated to `CoreFuncKind`. + Core(CoreFuncKind<'a>), } /// Information relating to lifting a core function. @@ -461,6 +477,8 @@ impl<'a> Parse<'a> for CanonResourceNew<'a> { pub struct CanonResourceDrop<'a> { /// The resource type that this intrinsic is dropping. pub ty: Index<'a>, + /// Whether or not this function is async + pub async_: bool, } impl<'a> Parse<'a> for CanonResourceDrop<'a> { @@ -469,6 +487,7 @@ impl<'a> Parse<'a> for CanonResourceDrop<'a> { Ok(Self { ty: parser.parse()?, + async_: parser.parse::<Option<kw::r#async>>()?.is_some(), }) } } @@ -490,16 +509,16 @@ impl<'a> Parse<'a> for CanonResourceRep<'a> { } } -/// Information relating to the `thread.spawn` intrinsic. +/// Information relating to the `thread.spawn-ref` intrinsic. #[derive(Debug)] -pub struct CanonThreadSpawn<'a> { +pub struct CanonThreadSpawnRef<'a> { /// The function type that is being spawned. pub ty: Index<'a>, } -impl<'a> Parse<'a> for CanonThreadSpawn<'a> { +impl<'a> Parse<'a> for CanonThreadSpawnRef<'a> { fn parse(parser: Parser<'a>) -> Result<Self> { - parser.parse::<kw::thread_spawn>()?; + parser.parse::<kw::thread_spawn_ref>()?; Ok(Self { ty: parser.parse()?, @@ -507,13 +526,33 @@ impl<'a> Parse<'a> for CanonThreadSpawn<'a> { } } +/// Information relating to the `thread.spawn-indirect` intrinsic. +/// +/// This should look quite similar to parsing of `CallIndirect`. +#[derive(Debug)] +pub struct CanonThreadSpawnIndirect<'a> { + /// The function type that is being spawned. + pub ty: Index<'a>, + /// The table that this spawn is going to be indexing. + pub table: CoreItemRef<'a, kw::table>, +} + +impl<'a> Parse<'a> for CanonThreadSpawnIndirect<'a> { + fn parse(parser: Parser<'a>) -> Result<Self> { + parser.parse::<kw::thread_spawn_indirect>()?; + let ty = parser.parse()?; + let table = parser.parens(|p| p.parse())?; + Ok(Self { ty, table }) + } +} + /// Information relating to the `thread.spawn` intrinsic. #[derive(Debug)] -pub struct CanonThreadHwConcurrency; +pub struct CanonThreadAvailableParallelism; -impl<'a> Parse<'a> for CanonThreadHwConcurrency { +impl<'a> Parse<'a> for CanonThreadAvailableParallelism { fn parse(parser: Parser<'a>) -> Result<Self> { - parser.parse::<kw::thread_hw_concurrency>()?; + parser.parse::<kw::thread_available_parallelism>()?; Ok(Self) } } @@ -523,28 +562,31 @@ impl<'a> Parse<'a> for CanonThreadHwConcurrency { pub struct CanonTaskReturn<'a> { /// The type of the result which may be returned with this intrinsic. pub result: Option<ComponentValType<'a>>, + /// The canonical options for storing values. + pub opts: Vec<CanonOpt<'a>>, } impl<'a> Parse<'a> for CanonTaskReturn<'a> { fn parse(parser: Parser<'a>) -> Result<Self> { parser.parse::<kw::task_return>()?; - let result = if parser.peek2::<kw::result>()? { - Some(parser.parens(|p| { - p.parse::<kw::result>()?.0; - p.parse() - })?) - } else { - None - }; - - Ok(Self { result }) + Ok(Self { + result: if parser.peek2::<kw::result>()? { + Some(parser.parens(|p| { + p.parse::<kw::result>()?.0; + p.parse() + })?) + } else { + None + }, + opts: parser.parse()?, + }) } } -/// Information relating to the `task.wait` intrinsic. +/// Information relating to the `waitable-set.wait` intrinsic. #[derive(Debug)] -pub struct CanonTaskWait<'a> { +pub struct CanonWaitableSetWait<'a> { /// If true, the component instance may be reentered during a call to this /// intrinsic. pub async_: bool, @@ -552,22 +594,19 @@ pub struct CanonTaskWait<'a> { pub memory: CoreItemRef<'a, kw::memory>, } -impl<'a> Parse<'a> for CanonTaskWait<'a> { +impl<'a> Parse<'a> for CanonWaitableSetWait<'a> { fn parse(parser: Parser<'a>) -> Result<Self> { - parser.parse::<kw::task_wait>()?; - let async_ = parser.parse::<Option<kw::r#async>>()?.is_some(); - let memory = parser.parens(|parser| { - let span = parser.parse::<kw::memory>()?.0; - parse_trailing_item_ref(kw::memory(span), parser) - })?; + parser.parse::<kw::waitable_set_wait>()?; + let async_ = parser.parse::<Option<kw::cancellable>>()?.is_some(); + let memory = parser.parens(|p| p.parse())?; Ok(Self { async_, memory }) } } -/// Information relating to the `task.poll` intrinsic. +/// Information relating to the `waitable-set.poll` intrinsic. #[derive(Debug)] -pub struct CanonTaskPoll<'a> { +pub struct CanonWaitableSetPoll<'a> { /// If true, the component instance may be reentered during a call to this /// intrinsic. pub async_: bool, @@ -575,30 +614,44 @@ pub struct CanonTaskPoll<'a> { pub memory: CoreItemRef<'a, kw::memory>, } -impl<'a> Parse<'a> for CanonTaskPoll<'a> { +impl<'a> Parse<'a> for CanonWaitableSetPoll<'a> { fn parse(parser: Parser<'a>) -> Result<Self> { - parser.parse::<kw::task_poll>()?; - let async_ = parser.parse::<Option<kw::r#async>>()?.is_some(); - let memory = parser.parens(|parser| { - let span = parser.parse::<kw::memory>()?.0; - parse_trailing_item_ref(kw::memory(span), parser) - })?; + parser.parse::<kw::waitable_set_poll>()?; + let async_ = parser.parse::<Option<kw::cancellable>>()?.is_some(); + let memory = parser.parens(|p| p.parse())?; Ok(Self { async_, memory }) } } -/// Information relating to the `task.yield` intrinsic. +/// Information relating to the `thread.yield` intrinsic. #[derive(Debug)] -pub struct CanonTaskYield { +pub struct CanonThreadYield { /// If true, the component instance may be reentered during a call to this /// intrinsic. + pub cancellable: bool, +} + +impl<'a> Parse<'a> for CanonThreadYield { + fn parse(parser: Parser<'a>) -> Result<Self> { + parser.parse::<kw::thread_yield>()?; + let cancellable = parser.parse::<Option<kw::cancellable>>()?.is_some(); + + Ok(Self { cancellable }) + } +} + +/// Information relating to the `subtask.cancel` intrinsic. +#[derive(Debug)] +pub struct CanonSubtaskCancel { + /// If false, block until cancel is finished; otherwise return BLOCKED if + /// necessary. pub async_: bool, } -impl<'a> Parse<'a> for CanonTaskYield { +impl<'a> Parse<'a> for CanonSubtaskCancel { fn parse(parser: Parser<'a>) -> Result<Self> { - parser.parse::<kw::task_yield>()?; + parser.parse::<kw::subtask_cancel>()?; let async_ = parser.parse::<Option<kw::r#async>>()?.is_some(); Ok(Self { async_ }) @@ -704,16 +757,16 @@ impl<'a> Parse<'a> for CanonStreamCancelWrite<'a> { } } -/// Information relating to the `stream.close-readable` intrinsic. +/// Information relating to the `stream.drop-readable` intrinsic. #[derive(Debug)] -pub struct CanonStreamCloseReadable<'a> { - /// The stream type to close. +pub struct CanonStreamDropReadable<'a> { + /// The stream type to drop. pub ty: Index<'a>, } -impl<'a> Parse<'a> for CanonStreamCloseReadable<'a> { +impl<'a> Parse<'a> for CanonStreamDropReadable<'a> { fn parse(parser: Parser<'a>) -> Result<Self> { - parser.parse::<kw::stream_close_readable>()?; + parser.parse::<kw::stream_drop_readable>()?; Ok(Self { ty: parser.parse()?, @@ -721,16 +774,16 @@ impl<'a> Parse<'a> for CanonStreamCloseReadable<'a> { } } -/// Information relating to the `stream.close-writable` intrinsic. +/// Information relating to the `stream.drop-writable` intrinsic. #[derive(Debug)] -pub struct CanonStreamCloseWritable<'a> { - /// The stream type to close. +pub struct CanonStreamDropWritable<'a> { + /// The stream type to drop. pub ty: Index<'a>, } -impl<'a> Parse<'a> for CanonStreamCloseWritable<'a> { +impl<'a> Parse<'a> for CanonStreamDropWritable<'a> { fn parse(parser: Parser<'a>) -> Result<Self> { - parser.parse::<kw::stream_close_writable>()?; + parser.parse::<kw::stream_drop_writable>()?; Ok(Self { ty: parser.parse()?, @@ -837,16 +890,16 @@ impl<'a> Parse<'a> for CanonFutureCancelWrite<'a> { } } -/// Information relating to the `future.close-readable` intrinsic. +/// Information relating to the `future.drop-readable` intrinsic. #[derive(Debug)] -pub struct CanonFutureCloseReadable<'a> { - /// The future type to close. +pub struct CanonFutureDropReadable<'a> { + /// The future type to drop. pub ty: Index<'a>, } -impl<'a> Parse<'a> for CanonFutureCloseReadable<'a> { +impl<'a> Parse<'a> for CanonFutureDropReadable<'a> { fn parse(parser: Parser<'a>) -> Result<Self> { - parser.parse::<kw::future_close_readable>()?; + parser.parse::<kw::future_drop_readable>()?; Ok(Self { ty: parser.parse()?, @@ -854,16 +907,16 @@ impl<'a> Parse<'a> for CanonFutureCloseReadable<'a> { } } -/// Information relating to the `future.close-writable` intrinsic. +/// Information relating to the `future.drop-writable` intrinsic. #[derive(Debug)] -pub struct CanonFutureCloseWritable<'a> { - /// The future type to close. +pub struct CanonFutureDropWritable<'a> { + /// The future type to drop. pub ty: Index<'a>, } -impl<'a> Parse<'a> for CanonFutureCloseWritable<'a> { +impl<'a> Parse<'a> for CanonFutureDropWritable<'a> { fn parse(parser: Parser<'a>) -> Result<Self> { - parser.parse::<kw::future_close_writable>()?; + parser.parse::<kw::future_drop_writable>()?; Ok(Self { ty: parser.parse()?, @@ -905,6 +958,67 @@ impl<'a> Parse<'a> for CanonErrorContextDebugMessage<'a> { } } +/// Information relating to the `thread.new-indirect` intrinsic. +#[derive(Debug)] +pub struct CanonThreadNewIndirect<'a> { + /// The function type for the thread start function. + pub ty: Index<'a>, + /// The table to index. + pub table: CoreItemRef<'a, kw::table>, +} + +impl<'a> Parse<'a> for CanonThreadNewIndirect<'a> { + fn parse(parser: Parser<'a>) -> Result<Self> { + parser.parse::<kw::thread_new_indirect>()?; + let ty = parser.parse()?; + let table = parser.parens(|p| p.parse())?; + Ok(Self { ty, table }) + } +} + +/// Information relating to the `thread.switch-to` intrinsic. +#[derive(Debug)] +pub struct CanonThreadSwitchTo { + /// Whether the thread can be cancelled while suspended at this point. + pub cancellable: bool, +} + +impl<'a> Parse<'a> for CanonThreadSwitchTo { + fn parse(parser: Parser<'a>) -> Result<Self> { + parser.parse::<kw::thread_switch_to>()?; + let cancellable = parser.parse::<Option<kw::cancellable>>()?.is_some(); + Ok(Self { cancellable }) + } +} + +/// Information relating to the `thread.suspend` intrinsic. +#[derive(Debug)] +pub struct CanonThreadSuspend { + /// Whether the thread can be cancelled while suspended at this point. + pub cancellable: bool, +} +impl<'a> Parse<'a> for CanonThreadSuspend { + fn parse(parser: Parser<'a>) -> Result<Self> { + parser.parse::<kw::thread_suspend>()?; + let cancellable = parser.parse::<Option<kw::cancellable>>()?.is_some(); + Ok(Self { cancellable }) + } +} + +/// Information relating to the `thread.yield-to` intrinsic. +#[derive(Debug)] +pub struct CanonThreadYieldTo { + /// Whether the thread can be cancelled while yielding at this point. + pub cancellable: bool, +} +impl<'a> Parse<'a> for CanonThreadYieldTo { + fn parse(parser: Parser<'a>) -> Result<Self> { + parser.parse::<kw::thread_yield_to>()?; + let cancellable = parser.parse::<Option<kw::cancellable>>()?.is_some(); + Ok(Self { cancellable }) + } +} + #[derive(Debug)] /// Canonical ABI options. pub enum CanonOpt<'a> { @@ -924,6 +1038,16 @@ pub enum CanonOpt<'a> { Async, /// Use the specified function to deliver async events to stackless coroutines. Callback(CoreItemRef<'a, kw::func>), + /// Lower this component function into the specified core function type. + CoreType(CoreItemRef<'a, kw::r#type>), + /// Use the GC variant of the canonical ABI. + Gc, +} + +impl Default for kw::r#type { + fn default() -> Self { + Self(Span::from_offset(0)) + } } impl<'a> Parse<'a> for CanonOpt<'a> { @@ -941,15 +1065,14 @@ impl<'a> Parse<'a> for CanonOpt<'a> { } else if l.peek::<kw::r#async>()? { parser.parse::<kw::r#async>()?; Ok(Self::Async) + } else if l.peek::<kw::gc>()? { + parser.parse::<kw::gc>()?; + Ok(Self::Gc) } else if l.peek::<LParen>()? { parser.parens(|parser| { let mut l = parser.lookahead1(); if l.peek::<kw::memory>()? { - let span = parser.parse::<kw::memory>()?.0; - Ok(CanonOpt::Memory(parse_trailing_item_ref( - kw::memory(span), - parser, - )?)) + Ok(CanonOpt::Memory(parser.parse()?)) } else if l.peek::<kw::realloc>()? { parser.parse::<kw::realloc>()?; Ok(CanonOpt::Realloc( @@ -965,6 +1088,11 @@ impl<'a> Parse<'a> for CanonOpt<'a> { Ok(CanonOpt::Callback( parser.parse::<IndexOrCoreRef<'_, _>>()?.0, )) + } else if l.peek::<kw::core_type>()? { + parser.parse::<kw::core_type>()?; + Ok(CanonOpt::CoreType( + parser.parse::<IndexOrCoreRef<'_, _>>()?.0, + )) } else { Err(l.error()) } @@ -975,18 +1103,34 @@ impl<'a> Parse<'a> for CanonOpt<'a> { } } -fn parse_trailing_item_ref<T>(kind: T, parser: Parser) -> Result<CoreItemRef<T>> { - Ok(CoreItemRef { - kind, - idx: parser.parse()?, - export_name: parser.parse()?, - }) +impl Peek for CanonOpt<'_> { + fn peek(cursor: Cursor<'_>) -> Result<bool> { + Ok(kw::string_utf8::peek(cursor)? + || kw::string_utf16::peek(cursor)? + || kw::string_latin1_utf16::peek(cursor)? + || kw::r#async::peek(cursor)? + || kw::gc::peek(cursor)? + || match cursor.lparen()? { + Some(next) => { + kw::memory::peek(next)? + || kw::realloc::peek(next)? + || kw::post_return::peek(next)? + || kw::callback::peek(next)? + || kw::core_type::peek(next)? + } + None => false, + }) + } + + fn display() -> &'static str { + "canonical option" + } } impl<'a> Parse<'a> for Vec<CanonOpt<'a>> { fn parse(parser: Parser<'a>) -> Result<Self> { let mut funcs = Vec::new(); - while !parser.is_empty() { + while parser.peek::<CanonOpt<'_>>()? { funcs.push(parser.parse()?); } Ok(funcs) diff --git a/third_party/rust/wast/src/component/resolve.rs b/third_party/rust/wast/src/component/resolve.rs @@ -1,10 +1,10 @@ +use crate::Error; use crate::component::*; -use crate::core::{self, resolve::ResolveCoreType, ValType}; +use crate::core::{self, ValType, resolve::ResolveCoreType}; use crate::kw; use crate::names::Namespace; use crate::token::Span; use crate::token::{Id, Index}; -use crate::Error; /// Resolve the fields of a component and everything nested within it, changing /// `Index::Id` to `Index::Num` and expanding alias syntax sugar. @@ -327,7 +327,7 @@ impl<'a> Resolver<'a> { if depth as usize >= self.stack.len() { return Err(Error::new( span, - format!("outer count of `{}` is too large", depth), + format!("outer count of `{depth}` is too large"), )); } @@ -370,90 +370,117 @@ impl<'a> Resolver<'a> { self.core_item_ref(&mut info.func)?; self.canon_opts(&mut info.opts)?; } - CanonicalFuncKind::Lower(info) => { - self.component_item_ref(&mut info.func)?; - self.canon_opts(&mut info.opts)?; - } - CanonicalFuncKind::ResourceNew(info) => { - self.resolve_ns(&mut info.ty, Ns::Type)?; - } - CanonicalFuncKind::ResourceRep(info) => { - self.resolve_ns(&mut info.ty, Ns::Type)?; - } - CanonicalFuncKind::ResourceDrop(info) => { - self.resolve_ns(&mut info.ty, Ns::Type)?; - } - CanonicalFuncKind::ThreadSpawn(info) => { - self.resolve_ns(&mut info.ty, Ns::CoreType)?; - } - CanonicalFuncKind::ThreadHwConcurrency(_) - | CanonicalFuncKind::TaskBackpressure - | CanonicalFuncKind::TaskYield(_) - | CanonicalFuncKind::SubtaskDrop - | CanonicalFuncKind::ErrorContextDrop => {} - CanonicalFuncKind::TaskReturn(info) => { - if let Some(ty) = &mut info.result { - self.component_val_type(ty)?; + CanonicalFuncKind::Core(core) => match core { + CoreFuncKind::Alias(_) => { + panic!("should have been removed during expansion") } - } - CanonicalFuncKind::TaskWait(info) => { - self.core_item_ref(&mut info.memory)?; - } - CanonicalFuncKind::TaskPoll(info) => { - self.core_item_ref(&mut info.memory)?; - } - CanonicalFuncKind::StreamNew(info) => { - self.resolve_ns(&mut info.ty, Ns::Type)?; - } - CanonicalFuncKind::StreamRead(info) => { - self.resolve_ns(&mut info.ty, Ns::Type)?; - self.canon_opts(&mut info.opts)?; - } - CanonicalFuncKind::StreamWrite(info) => { - self.resolve_ns(&mut info.ty, Ns::Type)?; - self.canon_opts(&mut info.opts)?; - } - CanonicalFuncKind::StreamCancelRead(info) => { - self.resolve_ns(&mut info.ty, Ns::Type)?; - } - CanonicalFuncKind::StreamCancelWrite(info) => { - self.resolve_ns(&mut info.ty, Ns::Type)?; - } - CanonicalFuncKind::StreamCloseReadable(info) => { - self.resolve_ns(&mut info.ty, Ns::Type)?; - } - CanonicalFuncKind::StreamCloseWritable(info) => { - self.resolve_ns(&mut info.ty, Ns::Type)?; - } - CanonicalFuncKind::FutureNew(info) => { - self.resolve_ns(&mut info.ty, Ns::Type)?; - } - CanonicalFuncKind::FutureRead(info) => { - self.resolve_ns(&mut info.ty, Ns::Type)?; - self.canon_opts(&mut info.opts)?; - } - CanonicalFuncKind::FutureWrite(info) => { - self.resolve_ns(&mut info.ty, Ns::Type)?; - self.canon_opts(&mut info.opts)?; - } - CanonicalFuncKind::FutureCancelRead(info) => { - self.resolve_ns(&mut info.ty, Ns::Type)?; - } - CanonicalFuncKind::FutureCancelWrite(info) => { - self.resolve_ns(&mut info.ty, Ns::Type)?; - } - CanonicalFuncKind::FutureCloseReadable(info) => { - self.resolve_ns(&mut info.ty, Ns::Type)?; - } - CanonicalFuncKind::FutureCloseWritable(info) => { - self.resolve_ns(&mut info.ty, Ns::Type)?; - } - CanonicalFuncKind::ErrorContextNew(info) => { - self.canon_opts(&mut info.opts)?; - } - CanonicalFuncKind::ErrorContextDebugMessage(info) => { - self.canon_opts(&mut info.opts)?; - } + CoreFuncKind::Lower(info) => { + self.component_item_ref(&mut info.func)?; + self.canon_opts(&mut info.opts)?; + } + CoreFuncKind::ResourceNew(info) => { + self.resolve_ns(&mut info.ty, Ns::Type)?; + } + CoreFuncKind::ResourceRep(info) => { + self.resolve_ns(&mut info.ty, Ns::Type)?; + } + CoreFuncKind::ResourceDrop(info) => { + self.resolve_ns(&mut info.ty, Ns::Type)?; + } + CoreFuncKind::ThreadSpawnRef(info) => { + self.resolve_ns(&mut info.ty, Ns::CoreType)?; + } + CoreFuncKind::ThreadSpawnIndirect(info) => { + self.resolve_ns(&mut info.ty, Ns::CoreType)?; + self.core_item_ref(&mut info.table)?; + } + CoreFuncKind::ThreadAvailableParallelism(_) + | CoreFuncKind::BackpressureSet + | CoreFuncKind::BackpressureInc + | CoreFuncKind::BackpressureDec + | CoreFuncKind::TaskCancel + | CoreFuncKind::ThreadYield(_) + | CoreFuncKind::SubtaskDrop + | CoreFuncKind::SubtaskCancel(_) + | CoreFuncKind::ErrorContextDrop => {} + CoreFuncKind::TaskReturn(info) => { + if let Some(ty) = &mut info.result { + self.component_val_type(ty)?; + } + self.canon_opts(&mut info.opts)?; + } + CoreFuncKind::ContextGet(_) | CoreFuncKind::ContextSet(_) => {} + CoreFuncKind::StreamNew(info) => { + self.resolve_ns(&mut info.ty, Ns::Type)?; + } + CoreFuncKind::StreamRead(info) => { + self.resolve_ns(&mut info.ty, Ns::Type)?; + self.canon_opts(&mut info.opts)?; + } + CoreFuncKind::StreamWrite(info) => { + self.resolve_ns(&mut info.ty, Ns::Type)?; + self.canon_opts(&mut info.opts)?; + } + CoreFuncKind::StreamCancelRead(info) => { + self.resolve_ns(&mut info.ty, Ns::Type)?; + } + CoreFuncKind::StreamCancelWrite(info) => { + self.resolve_ns(&mut info.ty, Ns::Type)?; + } + CoreFuncKind::StreamDropReadable(info) => { + self.resolve_ns(&mut info.ty, Ns::Type)?; + } + CoreFuncKind::StreamDropWritable(info) => { + self.resolve_ns(&mut info.ty, Ns::Type)?; + } + CoreFuncKind::FutureNew(info) => { + self.resolve_ns(&mut info.ty, Ns::Type)?; + } + CoreFuncKind::FutureRead(info) => { + self.resolve_ns(&mut info.ty, Ns::Type)?; + self.canon_opts(&mut info.opts)?; + } + CoreFuncKind::FutureWrite(info) => { + self.resolve_ns(&mut info.ty, Ns::Type)?; + self.canon_opts(&mut info.opts)?; + } + CoreFuncKind::FutureCancelRead(info) => { + self.resolve_ns(&mut info.ty, Ns::Type)?; + } + CoreFuncKind::FutureCancelWrite(info) => { + self.resolve_ns(&mut info.ty, Ns::Type)?; + } + CoreFuncKind::FutureDropReadable(info) => { + self.resolve_ns(&mut info.ty, Ns::Type)?; + } + CoreFuncKind::FutureDropWritable(info) => { + self.resolve_ns(&mut info.ty, Ns::Type)?; + } + CoreFuncKind::ErrorContextNew(info) => { + self.canon_opts(&mut info.opts)?; + } + CoreFuncKind::ErrorContextDebugMessage(info) => { + self.canon_opts(&mut info.opts)?; + } + CoreFuncKind::WaitableSetNew => {} + CoreFuncKind::WaitableSetWait(info) => { + self.core_item_ref(&mut info.memory)?; + } + CoreFuncKind::WaitableSetPoll(info) => { + self.core_item_ref(&mut info.memory)?; + } + CoreFuncKind::WaitableSetDrop => {} + CoreFuncKind::WaitableJoin => {} + CoreFuncKind::ThreadIndex => {} + CoreFuncKind::ThreadNewIndirect(info) => { + self.resolve_ns(&mut info.ty, Ns::CoreType)?; + self.core_item_ref(&mut info.table)?; + } + CoreFuncKind::ThreadSwitchTo(_) => {} + CoreFuncKind::ThreadSuspend(_) => {} + CoreFuncKind::ThreadResumeLater => {} + CoreFuncKind::ThreadYieldTo(_) => {} + }, } Ok(()) @@ -465,11 +492,13 @@ impl<'a> Resolver<'a> { CanonOpt::StringUtf8 | CanonOpt::StringUtf16 | CanonOpt::StringLatin1Utf16 - | CanonOpt::Async => {} + | CanonOpt::Async + | CanonOpt::Gc => {} CanonOpt::Memory(r) => self.core_item_ref(r)?, CanonOpt::Realloc(r) | CanonOpt::PostReturn(r) | CanonOpt::Callback(r) => { self.core_item_ref(r)? } + CanonOpt::CoreType(t) => self.core_item_ref(t)?, } } @@ -531,8 +560,12 @@ impl<'a> Resolver<'a> { } } } - ComponentDefinedType::List(l) => { - self.component_val_type(&mut l.element)?; + ComponentDefinedType::List(List { element: t }) + | ComponentDefinedType::FixedSizeList(FixedSizeList { + element: t, + elements: _, + }) => { + self.component_val_type(t)?; } ComponentDefinedType::Tuple(t) => { for field in t.fields.iter_mut() { @@ -620,8 +653,8 @@ impl<'a> Resolver<'a> { self.component_val_type(&mut param.ty)?; } - for result in f.results.iter_mut() { - self.component_val_type(&mut result.ty)?; + if let Some(result) = &mut f.result { + self.component_val_type(result)?; } } TypeDef::Component(c) => { @@ -639,7 +672,7 @@ impl<'a> Resolver<'a> { ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => {} ValType::Ref(r) => match &mut r.heap { core::HeapType::Abstract { .. } => {} - core::HeapType::Concrete(id) => { + core::HeapType::Concrete(id) | core::HeapType::Exact(id) => { self.resolve_ns(id, Ns::Type)?; } }, @@ -827,7 +860,21 @@ impl<'a> Resolver<'a> { target: AliasTarget::Outer { outer: Index::Num(depth, span), index: Index::Num(found, span), - kind: ns.into(), + kind: match ns { + Ns::CoreModule => ComponentOuterAliasKind::CoreModule, + Ns::CoreType => ComponentOuterAliasKind::CoreType, + Ns::Type => ComponentOuterAliasKind::Type, + Ns::Component => ComponentOuterAliasKind::Component, + _ => { + return Err(Error::new( + span, + format!( + "outer item `{}` is not a module, type, or component", + id.name(), + ), + )); + } + }, }, }; let local_index = self.current().register_alias(&alias)?; @@ -904,7 +951,9 @@ impl<'a> Resolver<'a> { sig: &mut core::ItemSig<'a>, ) -> Result<(), Error> { match &mut sig.kind { - core::ItemKind::Func(ty) | core::ItemKind::Tag(core::TagType::Exception(ty)) => { + core::ItemKind::Func(ty) + | core::ItemKind::FuncExact(ty) + | core::ItemKind::Tag(core::TagType::Exception(ty)) => { let idx = ty.index.as_mut().expect("index should be filled in"); resolver .stack @@ -959,37 +1008,7 @@ impl<'a> ComponentState<'a> { ComponentField::Type(t) => self.types.register(t.id, "type")?, ComponentField::CanonicalFunc(f) => match &f.kind { CanonicalFuncKind::Lift { .. } => self.funcs.register(f.id, "func")?, - CanonicalFuncKind::Lower(_) - | CanonicalFuncKind::ResourceNew(_) - | CanonicalFuncKind::ResourceRep(_) - | CanonicalFuncKind::ResourceDrop(_) - | CanonicalFuncKind::ThreadSpawn(_) - | CanonicalFuncKind::ThreadHwConcurrency(_) - | CanonicalFuncKind::TaskBackpressure - | CanonicalFuncKind::TaskReturn(_) - | CanonicalFuncKind::TaskWait(_) - | CanonicalFuncKind::TaskPoll(_) - | CanonicalFuncKind::TaskYield(_) - | CanonicalFuncKind::SubtaskDrop - | CanonicalFuncKind::StreamNew(_) - | CanonicalFuncKind::StreamRead(_) - | CanonicalFuncKind::StreamWrite(_) - | CanonicalFuncKind::StreamCancelRead(_) - | CanonicalFuncKind::StreamCancelWrite(_) - | CanonicalFuncKind::StreamCloseReadable(_) - | CanonicalFuncKind::StreamCloseWritable(_) - | CanonicalFuncKind::FutureNew(_) - | CanonicalFuncKind::FutureRead(_) - | CanonicalFuncKind::FutureWrite(_) - | CanonicalFuncKind::FutureCancelRead(_) - | CanonicalFuncKind::FutureCancelWrite(_) - | CanonicalFuncKind::FutureCloseReadable(_) - | CanonicalFuncKind::FutureCloseWritable(_) - | CanonicalFuncKind::ErrorContextNew(_) - | CanonicalFuncKind::ErrorContextDebugMessage(_) - | CanonicalFuncKind::ErrorContextDrop => { - self.core_funcs.register(f.id, "core func")? - } + CanonicalFuncKind::Core(_) => self.core_funcs.register(f.id, "core func")?, }, ComponentField::CoreFunc(_) | ComponentField::Func(_) => { unreachable!("should be expanded already") @@ -1114,6 +1133,7 @@ component_item!(kw::module, CoreModule); core_item!(kw::func, CoreFunc); core_item!(kw::memory, CoreMemory); +core_item!(kw::table, CoreTable); core_item!(kw::r#type, CoreType); core_item!(kw::r#instance, CoreInstance); @@ -1131,18 +1151,6 @@ impl From<Ns> for ComponentExportAliasKind { } } -impl From<Ns> for ComponentOuterAliasKind { - fn from(ns: Ns) -> Self { - match ns { - Ns::CoreModule => Self::CoreModule, - Ns::CoreType => Self::CoreType, - Ns::Type => Self::Type, - Ns::Component => Self::Component, - _ => unreachable!("not an outer alias namespace"), - } - } -} - impl From<Ns> for core::ExportKind { fn from(ns: Ns) -> Self { match ns { diff --git a/third_party/rust/wast/src/component/types.rs b/third_party/rust/wast/src/component/types.rs @@ -238,6 +238,7 @@ pub enum PrimitiveValType { F64, Char, String, + ErrorContext, } impl<'a> Parse<'a> for PrimitiveValType { @@ -288,6 +289,9 @@ impl<'a> Parse<'a> for PrimitiveValType { } else if l.peek::<kw::string>()? { parser.parse::<kw::string>()?; Ok(Self::String) + } else if l.peek::<kw::error_context>()? { + parser.parse::<kw::error_context>()?; + Ok(Self::ErrorContext) } else { Err(l.error()) } @@ -313,6 +317,7 @@ impl Peek for PrimitiveValType { | Some(("float64", _)) | Some(("char", _)) | Some(("string", _)) + | Some(("error-context", _)) )) } @@ -381,6 +386,7 @@ pub enum ComponentDefinedType<'a> { Record(Record<'a>), Variant(Variant<'a>), List(List<'a>), + FixedSizeList(FixedSizeList<'a>), Tuple(Tuple<'a>), Flags(Flags<'a>), Enum(Enum<'a>), @@ -400,7 +406,7 @@ impl<'a> ComponentDefinedType<'a> { } else if l.peek::<kw::variant>()? { Ok(Self::Variant(parser.parse()?)) } else if l.peek::<kw::list>()? { - Ok(Self::List(parser.parse()?)) + parse_list(parser) } else if l.peek::<kw::tuple>()? { Ok(Self::Tuple(parser.parse()?)) } else if l.peek::<kw::flags>()? { @@ -581,12 +587,28 @@ pub struct List<'a> { pub element: Box<ComponentValType<'a>>, } -impl<'a> Parse<'a> for List<'a> { - fn parse(parser: Parser<'a>) -> Result<Self> { - parser.parse::<kw::list>()?; - Ok(Self { - element: Box::new(parser.parse()?), - }) +/// A fixed size list type. +#[derive(Debug)] +pub struct FixedSizeList<'a> { + /// The element type of the array. + pub element: Box<ComponentValType<'a>>, + /// Number of Elements + pub elements: u32, +} + +fn parse_list<'a>(parser: Parser<'a>) -> Result<ComponentDefinedType<'a>> { + parser.parse::<kw::list>()?; + let tp = parser.parse()?; + let elements = parser.parse::<Option<u32>>()?; + if let Some(elements) = elements { + Ok(ComponentDefinedType::FixedSizeList(FixedSizeList { + element: Box::new(tp), + elements, + })) + } else { + Ok(ComponentDefinedType::List(List { + element: Box::new(tp), + })) } } @@ -725,29 +747,36 @@ impl<'a> Parse<'a> for Future<'a> { /// A component function type with parameters and result. #[derive(Debug)] pub struct ComponentFunctionType<'a> { + /// Whether or not this is an `async` fnction. + pub async_: bool, /// The parameters of a function, optionally each having an identifier for /// name resolution and a name for the custom `name` section. pub params: Box<[ComponentFunctionParam<'a>]>, - /// The result of a function, optionally each having an identifier for - /// name resolution and a name for the custom `name` section. - pub results: Box<[ComponentFunctionResult<'a>]>, + /// The result of a function. + pub result: Option<ComponentValType<'a>>, } impl<'a> Parse<'a> for ComponentFunctionType<'a> { fn parse(parser: Parser<'a>) -> Result<Self> { + let async_ = parser.parse::<Option<kw::r#async>>()?.is_some(); let mut params: Vec<ComponentFunctionParam> = Vec::new(); while parser.peek2::<kw::param>()? { params.push(parser.parens(|p| p.parse())?); } - let mut results: Vec<ComponentFunctionResult> = Vec::new(); - while parser.peek2::<kw::result>()? { - results.push(parser.parens(|p| p.parse())?); - } + let result = if parser.peek2::<kw::result>()? { + Some(parser.parens(|p| { + p.parse::<kw::result>()?; + p.parse() + })?) + } else { + None + }; Ok(Self { + async_, params: params.into(), - results: results.into(), + result, }) } } @@ -804,15 +833,8 @@ pub struct ComponentExportType<'a> { impl<'a> Parse<'a> for ComponentExportType<'a> { fn parse(parser: Parser<'a>) -> Result<Self> { let span = parser.parse::<kw::export>()?.0; - let id = parser.parse()?; - let debug_name = parser.parse()?; let name = parser.parse()?; - let item = parser.parens(|p| { - let mut item = p.parse::<ItemSigNoName<'_>>()?.0; - item.id = id; - item.name = debug_name; - Ok(item) - })?; + let item = parser.parens(|p| p.parse())?; Ok(Self { span, name, item }) } } diff --git a/third_party/rust/wast/src/component_disabled.rs b/third_party/rust/wast/src/component_disabled.rs @@ -3,9 +3,6 @@ use crate::parser::{Parse, Parser, Result}; use crate::token::{Id, Span}; -#[derive(Debug)] -enum Uninhabited {} - /// Empty definition of a component that cannot be created. #[derive(Debug)] pub struct Component<'a> { @@ -13,14 +10,6 @@ pub struct Component<'a> { pub span: Span, /// An optional identifier this component is known by pub id: Option<Id<'a>>, - - x: Uninhabited, -} - -impl Component<'_> { - pub(crate) fn validate(&self, _parser: Parser<'_>) -> Result<()> { - match self.x {} - } } impl<'a> Parse<'a> for Component<'a> { diff --git a/third_party/rust/wast/src/core/binary.rs b/third_party/rust/wast/src/core/binary.rs @@ -1,9 +1,9 @@ +use crate::Wat; #[cfg(feature = "component-model")] use crate::component::Component; use crate::core::*; use crate::encode::Encode; use crate::token::*; -use crate::Wat; use std::borrow::Cow; use std::marker; #[cfg(feature = "dwarf")] @@ -161,7 +161,7 @@ pub(crate) fn encode( e.typed_section(&globals); e.typed_section(&exports); e.custom_sections(Before(Start)); - if let Some(start) = start.get(0) { + for start in start { e.wasm.section(&wasm_encoder::StartSection { function_index: start.unwrap_u32(), }); @@ -177,7 +177,7 @@ pub(crate) fn encode( // Prepare to and emit the code section. This is where DWARF may optionally // be emitted depending on configuration settings. Note that `code_section` // will internally emit the branch hints section if necessary. - let names = find_names(module_id, module_name, fields); + let names = find_names(module_id, module_name, fields, &types); let num_import_funcs = imports .iter() .filter(|i| matches!(i.item.kind, ItemKind::Func(..))) @@ -209,6 +209,23 @@ pub(crate) fn encode( } } +fn func_type<'a>(types: &'a [RecOrType<'a>], ty: u32) -> Option<&'a FunctionType<'a>> { + // Iterate through `self.types` which is what was encoded into the + // module and find the function type which gives access to the + // parameters which gives access to their types. + let ty = types + .iter() + .flat_map(|t| match t { + RecOrType::Type(t) => std::slice::from_ref(*t), + RecOrType::Rec(r) => &r.types, + }) + .nth(ty as usize)?; + match &ty.def.kind { + InnerTypeKind::Func(ty) => Some(ty), + _ => None, + } +} + struct Encoder<'a> { wasm: wasm_encoder::Module, customs: &'a [&'a Custom<'a>], @@ -383,6 +400,8 @@ impl TypeDef<'_> { InnerTypeKind::Cont(ct) => Cont(ct.into()), }, shared: self.shared, + descriptor: self.descriptor.map(|i| i.unwrap_u32()), + describes: self.describes.map(|i| i.unwrap_u32()), }; wasm_encoder::SubType { composite_type, @@ -438,6 +457,7 @@ impl From<HeapType<'_>> for wasm_encoder::HeapType { Self::Abstract { shared, ty } } HeapType::Concrete(i) => Self::Concrete(i.unwrap_u32()), + HeapType::Exact(i) => Self::Exact(i.unwrap_u32()), } } } @@ -491,6 +511,7 @@ impl ItemKind<'_> { use wasm_encoder::EntityType as ET; match self { ItemKind::Func(t) => ET::Function(t.unwrap_u32()), + ItemKind::FuncExact(t) => ET::FunctionExact(t.unwrap_u32()), ItemKind::Table(t) => ET::Table(t.to_table_type()), ItemKind::Memory(t) => ET::Memory(t.to_memory_type()), ItemKind::Global(t) => ET::Global(t.to_global_type()), @@ -574,7 +595,7 @@ impl Index<'_> { fn unwrap_u32(&self) -> u32 { match self { Index::Num(n, _) => *n, - Index::Id(n) => panic!("unresolved index in emission: {:?}", n), + Index::Id(n) => panic!("unresolved index in emission: {n:?}"), } } } @@ -729,7 +750,9 @@ impl Func<'_> { ) -> Vec<wasm_encoder::BranchHint> { assert!(self.exports.names.is_empty()); let (expr, locals) = match &self.kind { - FuncKind::Inline { expression, locals } => (expression, locals), + FuncKind::Inline { + expression, locals, .. + } => (expression, locals), _ => panic!("should only have inline functions in emission"), }; @@ -795,7 +818,7 @@ impl Expression<'_> { instr.encode(&mut tmp); } func.raw(tmp.iter().copied()); - func.instruction(&wasm_encoder::Instruction::End); + func.instructions().end(); hints } @@ -973,6 +996,7 @@ fn find_names<'a>( module_id: &Option<Id<'a>>, module_name: &Option<NameAnnotation<'a>>, fields: &[ModuleField<'a>], + types: &'a [RecOrType<'a>], ) -> Names<'a> { fn get_name<'a>(id: &Option<Id<'a>>, name: &Option<NameAnnotation<'a>>) -> Option<&'a str> { name.as_ref().map(|n| n.name).or(id.and_then(|id| { @@ -1003,7 +1027,7 @@ fn find_names<'a>( let (kind, id, name) = match field { ModuleField::Import(i) => ( match i.item.kind { - ItemKind::Func(_) => Name::Func, + ItemKind::Func(_) | ItemKind::FuncExact(_) => Name::Func, ItemKind::Table(_) => Name::Table, ItemKind::Memory(_) => Name::Memory, ItemKind::Global(_) => Name::Global, @@ -1053,19 +1077,40 @@ fn find_names<'a>( let mut label_names = Vec::new(); let mut local_idx = 0; let mut label_idx = 0; + let mut discard_locals = false; - // Consult the inline type listed for local names of parameters. - // This is specifically preserved during the name resolution - // pass, but only for functions, so here we can look at the - // original source's names. if let Some(ty) = &f.ty.inline { + // Consult the inline type listed for local names of parameters. + // This is specifically preserved during the name resolution + // pass, but only for functions, so here we can look at the + // original source's names. for (id, name, _) in ty.params.iter() { if let Some(name) = get_name(id, name) { local_names.push((local_idx, name)); } local_idx += 1; } + } else { + // If the inline type isn't listed then it's either not present + // (e.g. no params or results) or it was referenced by index. + // Either way we've got the index here, so look it up in the + // list of types and see how many parameters this function's + // type has. + let index = match f.ty.index.as_ref().unwrap() { + Index::Num(n, _) => *n, + _ => unreachable!(), + }; + + match func_type(types, index) { + Some(ft) => local_idx = ft.params.len() as u32, + // If the function type index is invalid then skip + // preserving names since we don't know how many parameters + // this function will have so we don't know where to start + // indexing at. + None => discard_locals = true, + } } + if let FuncKind::Inline { locals, expression, .. } = &f.kind @@ -1093,7 +1138,7 @@ fn find_names<'a>( } } } - if local_names.len() > 0 { + if !discard_locals && local_names.len() > 0 { ret.locals.push((*idx, local_names)); } if label_names.len() > 0 { @@ -1392,6 +1437,7 @@ impl Encode for Dylink0Subsection<'_> { Dylink0Subsection::Needed(libs) => libs.encode(e), Dylink0Subsection::ExportInfo(list) => list.encode(e), Dylink0Subsection::ImportInfo(list) => list.encode(e), + Dylink0Subsection::RuntimePath(list) => list.encode(e), } } } @@ -1519,3 +1565,43 @@ impl Encode for BrOnCastFail<'_> { self.to_type.heap.encode(e); } } + +impl Encode for RefCastDesc<'_> { + fn encode(&self, e: &mut Vec<u8>) { + e.push(0xfb); + if self.r#type.nullable { + e.push(0x24); + } else { + e.push(0x23); + } + self.r#type.heap.encode(e); + } +} + +impl Encode for BrOnCastDesc<'_> { + fn encode(&self, e: &mut Vec<u8>) { + e.push(0xfb); + e.push(0x25); + e.push(br_on_cast_flags( + self.from_type.nullable, + self.to_type.nullable, + )); + self.label.encode(e); + self.from_type.heap.encode(e); + self.to_type.heap.encode(e); + } +} + +impl Encode for BrOnCastDescFail<'_> { + fn encode(&self, e: &mut Vec<u8>) { + e.push(0xfb); + e.push(0x26); + e.push(br_on_cast_flags( + self.from_type.nullable, + self.to_type.nullable, + )); + self.label.encode(e); + self.from_type.heap.encode(e); + self.to_type.heap.encode(e); + } +} diff --git a/third_party/rust/wast/src/core/binary/dwarf.rs b/third_party/rust/wast/src/core/binary/dwarf.rs @@ -11,7 +11,7 @@ //! easy/fun to play around with. use crate::core::binary::{EncodeOptions, Encoder, GenerateDwarf, Names, RecOrType}; -use crate::core::{InnerTypeKind, Local, ValType}; +use crate::core::{Local, ValType}; use crate::token::Span; use gimli::write::{ self, Address, AttributeValue, DwarfUnit, Expression, FileId, LineProgram, LineString, @@ -216,19 +216,8 @@ impl<'a> Dwarf<'a> { ty: u32, locals: &[Local<'_>], ) { - // Iterate through `self.types` which is what was encoded into the - // module and find the function type which gives access to the - // parameters which gives access to their types. - let ty = self - .types - .iter() - .flat_map(|t| match t { - RecOrType::Type(t) => std::slice::from_ref(*t), - RecOrType::Rec(r) => &r.types, - }) - .nth(ty as usize); - let ty = match ty.map(|t| &t.def.kind) { - Some(InnerTypeKind::Func(ty)) => ty, + let ty = match super::func_type(self.types, ty) { + Some(ty) => ty, _ => return, }; @@ -565,7 +554,7 @@ mod tests { // incremental update matches the precalculated position. let mut rand = SmallRng::seed_from_u64(102); for _ in 0..1000 { - let pos = rand.gen_range(0..contents.len()); + let pos = rand.random_range(0..contents.len()); dwarf.change_linecol(Span::from_offset(pos)); let (line, col) = precalculated_linecols[pos]; diff --git a/third_party/rust/wast/src/core/binary/dwarf_disabled.rs b/third_party/rust/wast/src/core/binary/dwarf_disabled.rs @@ -1,8 +1,8 @@ //! Dummy version of dwarf emission that does nothing when the compile-time //! feature is disabled. -use crate::core::binary::{EncodeOptions, Encoder, Names, RecOrType}; use crate::core::Local; +use crate::core::binary::{EncodeOptions, Encoder, Names, RecOrType}; use crate::token::Span; pub struct Dwarf<'a> { diff --git a/third_party/rust/wast/src/core/custom.rs b/third_party/rust/wast/src/core/custom.rs @@ -261,6 +261,7 @@ pub enum Dylink0Subsection<'a> { Needed(Vec<&'a str>), ExportInfo(Vec<(&'a str, u32)>), ImportInfo(Vec<(&'a str, &'a str, u32)>), + RuntimePath(Vec<&'a str>), } impl<'a> Parse<'a> for Dylink0<'a> { @@ -335,6 +336,13 @@ impl<'a> Dylink0<'a> { .subsections .push(Dylink0Subsection::ImportInfo(vec![(module, name, flags)])), } + } else if l.peek::<kw::runtime_path>()? { + parser.parse::<kw::runtime_path>()?; + let mut names = Vec::new(); + while !parser.is_empty() { + names.push(parser.parse()?); + } + self.subsections.push(Dylink0Subsection::RuntimePath(names)); } else { return Err(l.error()); } @@ -388,6 +396,7 @@ impl Dylink0Subsection<'_> { Needed(..) => 2, ExportInfo(..) => 3, ImportInfo(..) => 4, + RuntimePath(..) => 5, } } } diff --git a/third_party/rust/wast/src/core/expr.rs b/third_party/rust/wast/src/core/expr.rs @@ -2,7 +2,8 @@ use crate::annotation; use crate::core::*; use crate::encode::Encode; use crate::kw; -use crate::parser::{Cursor, Parse, Parser, Result}; +use crate::lexer::{Lexer, Token, TokenKind}; +use crate::parser::{Parse, Parser, Result}; use crate::token::*; use std::mem; @@ -295,7 +296,7 @@ impl<'a> ExpressionParser<'a> { } } Paren::None => { - return Err(parser.error("expected to continue a folded instruction")) + return Err(parser.error("expected to continue a folded instruction")); } } } @@ -441,7 +442,7 @@ macro_rules! instructions { } impl Encode for Instruction<'_> { - #[allow(non_snake_case)] + #[allow(non_snake_case, unused_lifetimes)] fn encode(&self, v: &mut Vec<u8>) { match self { $( @@ -1201,6 +1202,14 @@ instructions! { I64Sub128 : [0xfc, 20] : "i64.sub128", I64MulWideS : [0xfc, 21] : "i64.mul_wide_s", I64MulWideU : [0xfc, 22] : "i64.mul_wide_u", + + // Custom descriptors + StructNewDesc(Index<'a>) : [0xfb, 32] : "struct.new_desc", + StructNewDefaultDesc(Index<'a>) : [0xfb, 33] : "struct.new_default_desc", + RefGetDesc(Index<'a>): [0xfb, 34] : "ref.get_desc", + RefCastDesc(RefCastDesc<'a>) : [] : "ref.cast_desc", + BrOnCastDesc(Box<BrOnCastDesc<'a>>) : [] : "br_on_cast_desc", + BrOnCastDescFail(Box<BrOnCastDescFail<'a>>) : [] : "br_on_cast_desc_fail", } } @@ -1486,7 +1495,7 @@ pub struct MemArg<'a> { /// /// This is not stored as a log, this is the actual alignment (e.g. 1, 2, 4, /// 8, etc). - pub align: u32, + pub align: u64, /// The offset, in bytes of this access. pub offset: u64, /// The memory index we're accessing @@ -1494,12 +1503,8 @@ pub struct MemArg<'a> { } impl<'a> MemArg<'a> { - fn parse(parser: Parser<'a>, default_align: u32) -> Result<Self> { - fn parse_field<T>( - name: &str, - parser: Parser<'_>, - f: impl FnOnce(Cursor<'_>, &str, u32) -> Result<T>, - ) -> Result<Option<T>> { + fn parse(parser: Parser<'a>, default_align: u64) -> Result<Self> { + fn parse_field(name: &str, parser: Parser<'_>) -> Result<Option<u64>> { parser.step(|c| { let (kw, rest) = match c.keyword()? { Some(p) => p, @@ -1513,35 +1518,34 @@ impl<'a> MemArg<'a> { return Ok((None, c)); } let num = &kw[1..]; - let num = if let Some(stripped) = num.strip_prefix("0x") { - f(c, stripped, 16)? - } else { - f(c, num, 10)? - }; - - Ok((Some(num), rest)) - }) - } - - fn parse_u32(name: &str, parser: Parser<'_>) -> Result<Option<u32>> { - parse_field(name, parser, |c, num, radix| { - u32::from_str_radix(num, radix).map_err(|_| c.error("i32 constant out of range")) - }) - } - - fn parse_u64(name: &str, parser: Parser<'_>) -> Result<Option<u64>> { - parse_field(name, parser, |c, num, radix| { - u64::from_str_radix(num, radix).map_err(|_| c.error("i64 constant out of range")) + let lexer = Lexer::new(num); + let mut pos = 0; + if let Ok(Some( + token @ Token { + kind: TokenKind::Integer(integer_kind), + .. + }, + )) = lexer.parse(&mut pos) + { + let int = token.integer(lexer.input(), integer_kind); + let (s, base) = int.val(); + let value = u64::from_str_radix(s, base); + return match value { + Ok(n) => Ok((Some(n), rest)), + Err(_) => Err(c.error("u64 constant out of range")), + }; + } + Err(c.error("expected u64 integer constant")) }) } let memory = parser .parse::<Option<_>>()? .unwrap_or_else(|| Index::Num(0, parser.prev_span())); - let offset = parse_u64("offset", parser)?.unwrap_or(0); - let align = match parse_u32("align", parser)? { + let offset = parse_field("offset", parser)?.unwrap_or(0); + let align = match parse_field("align", parser)? { Some(n) if !n.is_power_of_two() => { - return Err(parser.error("alignment must be a power of two")) + return Err(parser.error("alignment must be a power of two")); } n => n.unwrap_or(default_align), }; @@ -1564,7 +1568,7 @@ pub struct LoadOrStoreLane<'a> { } impl<'a> LoadOrStoreLane<'a> { - fn parse(parser: Parser<'a>, default_align: u32) -> Result<Self> { + fn parse(parser: Parser<'a>, default_align: u64) -> Result<Self> { // This is sort of funky. The first integer we see could be the lane // index, but it could also be the memory index. To determine what it is // then if we see a second integer we need to look further. @@ -1950,6 +1954,63 @@ impl<'a> Parse<'a> for BrOnCastFail<'a> { } } +/// Extra data associated with the `ref.cast_desc` instruction +#[derive(Debug, Clone)] +pub struct RefCastDesc<'a> { + /// The type to cast to. + pub r#type: RefType<'a>, +} + +impl<'a> Parse<'a> for RefCastDesc<'a> { + fn parse(parser: Parser<'a>) -> Result<Self> { + Ok(RefCastDesc { + r#type: parser.parse()?, + }) + } +} + +/// Extra data associated with the `br_on_cast_desc` instruction +#[derive(Debug, Clone)] +pub struct BrOnCastDesc<'a> { + /// The label to branch to. + pub label: Index<'a>, + /// The type we're casting from. + pub from_type: RefType<'a>, + /// The type we're casting to. + pub to_type: RefType<'a>, +} + +impl<'a> Parse<'a> for BrOnCastDesc<'a> { + fn parse(parser: Parser<'a>) -> Result<Self> { + Ok(BrOnCastDesc { + label: parser.parse()?, + from_type: parser.parse()?, + to_type: parser.parse()?, + }) + } +} + +/// Extra data associated with the `br_on_cast_desc_fail` instruction +#[derive(Debug, Clone)] +pub struct BrOnCastDescFail<'a> { + /// The label to branch to. + pub label: Index<'a>, + /// The type we're casting from. + pub from_type: RefType<'a>, + /// The type we're casting to. + pub to_type: RefType<'a>, +} + +impl<'a> Parse<'a> for BrOnCastDescFail<'a> { + fn parse(parser: Parser<'a>) -> Result<Self> { + Ok(BrOnCastDescFail { + label: parser.parse()?, + from_type: parser.parse()?, + to_type: parser.parse()?, + }) + } +} + /// The memory ordering for atomic instructions. /// /// For an in-depth explanation of memory orderings, see the C++ documentation diff --git a/third_party/rust/wast/src/core/func.rs b/third_party/rust/wast/src/core/func.rs @@ -33,7 +33,7 @@ pub enum FuncKind<'a> { /// ```text /// (func (type 3) (import "foo" "bar")) /// ``` - Import(InlineImport<'a>), + Import(InlineImport<'a>, bool), /// Almost all functions, those defined inline in a wasm module. Inline { @@ -53,7 +53,18 @@ impl<'a> Parse<'a> for Func<'a> { let exports = parser.parse()?; let (ty, kind) = if let Some(import) = parser.parse()? { - (parser.parse()?, FuncKind::Import(import)) + let (ty, exact) = if parser.peek2::<kw::exact>()? { + ( + parser.parens(|p| { + p.parse::<kw::exact>()?; + p.parse() + })?, + true, + ) + } else { + (parser.parse()?, false) + }; + (ty, FuncKind::Import(import, exact)) } else { let ty = parser.parse()?; let locals = Local::parse_remainder(parser)?.into(); @@ -71,8 +82,8 @@ impl<'a> Parse<'a> for Func<'a> { id, name, exports, - ty, kind, + ty, }) } } diff --git a/third_party/rust/wast/src/core/import.rs b/third_party/rust/wast/src/core/import.rs @@ -54,6 +54,7 @@ pub enum ItemKind<'a> { Memory(MemoryType), Global(GlobalType<'a>), Tag(TagType<'a>), + FuncExact(TypeUse<'a, FunctionType<'a>>), } impl<'a> Parse<'a> for ItemSig<'a> { @@ -61,11 +62,21 @@ impl<'a> Parse<'a> for ItemSig<'a> { let mut l = parser.lookahead1(); if l.peek::<kw::func>()? { let span = parser.parse::<kw::func>()?.0; + let id = parser.parse()?; + let name = parser.parse()?; + let kind = if parser.peek2::<kw::exact>()? { + ItemKind::FuncExact(parser.parens(|p| { + p.parse::<kw::exact>()?; + p.parse() + })?) + } else { + ItemKind::Func(parser.parse()?) + }; Ok(ItemSig { span, - id: parser.parse()?, - name: parser.parse()?, - kind: ItemKind::Func(parser.parse()?), + id, + name, + kind, }) } else if l.peek::<kw::table>()? { let span = parser.parse::<kw::table>()?.0; diff --git a/third_party/rust/wast/src/core/module.rs b/third_party/rust/wast/src/core/module.rs @@ -89,21 +89,6 @@ impl<'a> Module<'a> { EncodeOptions::default().encode_module(self) } - pub(crate) fn validate(&self, parser: Parser<'_>) -> Result<()> { - let mut starts = 0; - if let ModuleKind::Text(fields) = &self.kind { - for item in fields.iter() { - if let ModuleField::Start(_) = item { - starts += 1; - } - } - } - if starts > 1 { - return Err(parser.error("multiple start sections found")); - } - Ok(()) - } - pub(crate) fn parse_without_module_keyword( module_keyword_span: Span, parser: Parser<'a>, diff --git a/third_party/rust/wast/src/core/resolve/deinline_import_export.rs b/third_party/rust/wast/src/core/resolve/deinline_import_export.rs @@ -11,7 +11,7 @@ pub fn run(fields: &mut Vec<ModuleField>) { fields.push(export(f.span, name, ExportKind::Func, &mut f.id)); } match f.kind { - FuncKind::Import(import) => { + FuncKind::Import(import, exact) => { item = ModuleField::Import(Import { span: f.span, module: import.module, @@ -20,7 +20,11 @@ pub fn run(fields: &mut Vec<ModuleField>) { span: f.span, id: f.id, name: f.name, - kind: ItemKind::Func(f.ty.clone()), + kind: if exact { + ItemKind::FuncExact(f.ty.clone()) + } else { + ItemKind::Func(f.ty.clone()) + }, }, }); } diff --git a/third_party/rust/wast/src/core/resolve/mod.rs b/third_party/rust/wast/src/core/resolve/mod.rs @@ -1,6 +1,6 @@ use crate::core::*; use crate::token::Index; -use crate::{gensym, Error}; +use crate::{Error, gensym}; mod deinline_import_export; mod names; @@ -38,7 +38,7 @@ pub fn resolve<'a>(fields: &mut Vec<ModuleField<'a>>) -> Result<Names<'a>, Error match field { ModuleField::Import(i) => { if let Some(name) = last { - return Err(Error::new(i.span, format!("import after {}", name))); + return Err(Error::new(i.span, format!("import after {name}"))); } } ModuleField::Memory(_) => last = Some("memory"), diff --git a/third_party/rust/wast/src/core/resolve/names.rs b/third_party/rust/wast/src/core/resolve/names.rs @@ -1,8 +1,8 @@ +use crate::Error; use crate::core::resolve::Ns; use crate::core::*; -use crate::names::{resolve_error, Namespace}; +use crate::names::{Namespace, resolve_error}; use crate::token::{Id, Index}; -use crate::Error; use std::collections::HashMap; pub fn resolve<'a>(fields: &mut Vec<ModuleField<'a>>) -> Result<Resolver<'a>, Error> { @@ -86,7 +86,9 @@ impl<'a> Resolver<'a> { fn register(&mut self, item: &ModuleField<'a>) -> Result<(), Error> { match item { ModuleField::Import(i) => match &i.item.kind { - ItemKind::Func(_) => self.funcs.register(i.item.id, "func")?, + ItemKind::Func(_) | ItemKind::FuncExact(_) => { + self.funcs.register(i.item.id, "func")? + } ItemKind::Memory(_) => self.memories.register(i.item.id, "memory")?, ItemKind::Table(_) => self.tables.register(i.item.id, "table")?, ItemKind::Global(_) => self.globals.register(i.item.id, "global")?, @@ -112,7 +114,7 @@ impl<'a> Resolver<'a> { // These fields don't define any items in any index space. ModuleField::Export(_) | ModuleField::Start(_) | ModuleField::Custom(_) => { - return Ok(()) + return Ok(()); } }; @@ -267,7 +269,7 @@ impl<'a> Resolver<'a> { fn resolve_item_sig(&self, item: &mut ItemSig<'a>) -> Result<(), Error> { match &mut item.kind { - ItemKind::Func(t) | ItemKind::Tag(TagType::Exception(t)) => { + ItemKind::Func(t) | ItemKind::FuncExact(t) | ItemKind::Tag(TagType::Exception(t)) => { self.resolve_type_use(t)?; } ItemKind::Global(t) => self.resolve_valtype(&mut t.ty)?, @@ -673,6 +675,26 @@ impl<'a, 'b> ExprResolver<'a, 'b> { self.resolver.resolve(&mut s.tag_index, Ns::Tag)?; } + StructNewDesc(i) | StructNewDefaultDesc(i) => { + self.resolver.resolve(i, Ns::Type)?; + } + RefGetDesc(i) => { + self.resolver.resolve(i, Ns::Type)?; + } + RefCastDesc(i) => { + self.resolver.resolve_reftype(&mut i.r#type)?; + } + BrOnCastDesc(i) => { + self.resolve_label(&mut i.label)?; + self.resolver.resolve_reftype(&mut i.to_type)?; + self.resolver.resolve_reftype(&mut i.from_type)?; + } + BrOnCastDescFail(i) => { + self.resolve_label(&mut i.label)?; + self.resolver.resolve_reftype(&mut i.to_type)?; + self.resolver.resolve_reftype(&mut i.from_type)?; + } + _ => {} } Ok(()) @@ -748,7 +770,18 @@ impl<'a> TypeReference<'a> for FunctionType<'a> { }; let (params, results) = match cx.type_info.get(n as usize) { Some(TypeInfo::Func { params, results }) => (params, results), - _ => return Ok(()), + Some(_) => { + return Err(Error::new( + idx.span(), + format!("invalid type: not a function type"), + )); + } + _ => { + return Err(Error::new( + idx.span(), + format!("unknown type: type index out of bounds"), + )); + } }; // Here we need to check that the inline type listed (ourselves) matches @@ -802,6 +835,12 @@ pub(crate) trait ResolveCoreType<'a> { if let Some(parent) = &mut ty.parent { self.resolve_type_name(parent)?; } + if let Some(descriptor) = &mut ty.descriptor { + self.resolve_type_name(descriptor)?; + } + if let Some(describes) = &mut ty.describes { + self.resolve_type_name(describes)?; + } match &mut ty.kind { InnerTypeKind::Func(func) => self.resolve_type_func(func), InnerTypeKind::Struct(struct_) => { @@ -842,7 +881,7 @@ pub(crate) trait ResolveCoreType<'a> { fn resolve_heaptype(&mut self, ty: &mut HeapType<'a>) -> Result<(), Error> { match ty { - HeapType::Concrete(i) => { + HeapType::Concrete(i) | HeapType::Exact(i) => { self.resolve_type_name(i)?; } HeapType::Abstract { .. } => {} diff --git a/third_party/rust/wast/src/core/resolve/types.rs b/third_party/rust/wast/src/core/resolve/types.rs @@ -122,7 +122,7 @@ impl<'a> Expander<'a> { fn expand_item_sig(&mut self, item: &mut ItemSig<'a>) { match &mut item.kind { - ItemKind::Func(t) | ItemKind::Tag(TagType::Exception(t)) => { + ItemKind::Func(t) | ItemKind::FuncExact(t) | ItemKind::Tag(TagType::Exception(t)) => { self.expand_type_use(t); } ItemKind::Global(_) | ItemKind::Table(_) | ItemKind::Memory(_) => {} @@ -264,6 +264,8 @@ impl<'a> TypeKey<'a> for FuncKey<'a> { }), shared, parent: None, + descriptor: None, + describes: None, final_type: None, } } diff --git a/third_party/rust/wast/src/core/types.rs b/third_party/rust/wast/src/core/types.rs @@ -1,9 +1,8 @@ +use crate::Error; use crate::core::*; use crate::kw; -use crate::parser::Lookahead1; use crate::parser::{Cursor, Parse, Parser, Peek, Result}; use crate::token::{Id, Index, LParen, NameAnnotation, Span}; -use crate::Error; use std::mem; /// The value types for a wasm module. @@ -18,40 +17,87 @@ pub enum ValType<'a> { Ref(RefType<'a>), } +const VALTYPES: &[(&str, ValType<'static>)] = &[ + ("i32", ValType::I32), + ("i64", ValType::I64), + ("f32", ValType::F32), + ("f64", ValType::F64), + ("v128", ValType::V128), +]; + +const REFTYPE_SHORTHANDS: &[(&str, RefType<'static>)] = &[ + ("funcref", RefType::func()), + ("externref", RefType::r#extern()), + ("exnref", RefType::exn()), + ("contref", RefType::cont()), + ("anyref", RefType::any()), + ("eqref", RefType::eq()), + ("structref", RefType::r#struct()), + ("arrayref", RefType::array()), + ("i31ref", RefType::i31()), + ("nullfuncref", RefType::nullfuncref()), + ("nullexternref", RefType::nullexternref()), + ("nullexnref", RefType::nullexnref()), + ("nullcontref", RefType::nullcontref()), + ("nullref", RefType::nullref()), +]; + +fn type_parse_error(include_valtypes: bool) -> String { + let mut message = format!("unexpected token, expected one of: "); + if include_valtypes { + for (name, _) in VALTYPES.iter() { + message.push_str(&format!("`{name}`, ")); + } + } + for (name, _) in REFTYPE_SHORTHANDS.iter() { + message.push_str(&format!("`{name}`, ")); + } + message.push_str("lparen"); + message +} + +impl<'a> ValType<'a> { + fn parse_shorthand(cursor: Cursor<'a>) -> Result<Option<(ValType<'a>, Cursor<'a>)>> { + if let Some((kw, c)) = cursor.keyword()? { + let iter = VALTYPES.iter().copied().chain( + REFTYPE_SHORTHANDS + .iter() + .map(|(name, ty)| (*name, ValType::Ref(*ty))), + ); + for (name, ty) in iter { + if name == kw { + return Ok(Some((ty, c))); + } + } + } + Ok(None) + } +} + impl<'a> Parse<'a> for ValType<'a> { fn parse(parser: Parser<'a>) -> Result<Self> { - let mut l = parser.lookahead1(); - if l.peek::<kw::i32>()? { - parser.parse::<kw::i32>()?; - Ok(ValType::I32) - } else if l.peek::<kw::i64>()? { - parser.parse::<kw::i64>()?; - Ok(ValType::I64) - } else if l.peek::<kw::f32>()? { - parser.parse::<kw::f32>()?; - Ok(ValType::F32) - } else if l.peek::<kw::f64>()? { - parser.parse::<kw::f64>()?; - Ok(ValType::F64) - } else if l.peek::<kw::v128>()? { - parser.parse::<kw::v128>()?; - Ok(ValType::V128) - } else if l.peek::<RefType>()? { - Ok(ValType::Ref(parser.parse()?)) - } else { - Err(l.error()) + // NB: this isn't using typical `Parser`-style combinators because this + // is a pretty hot function and the traditional recursive-descent style + // isn't the speediest. + let shorthand = parser.step(|cursor| { + if let Some((ty, c)) = ValType::parse_shorthand(cursor)? { + return Ok((Some(ty), c)); + } + Ok((None, cursor)) + })?; + if let Some(shorthand) = shorthand { + return Ok(shorthand); } + if !parser.peek::<LParen>()? { + return Err(parser.error(type_parse_error(true))); + } + Ok(ValType::Ref(parser.parse()?)) } } impl<'a> Peek for ValType<'a> { fn peek(cursor: Cursor<'_>) -> Result<bool> { - Ok(kw::i32::peek(cursor)? - || kw::i64::peek(cursor)? - || kw::f32::peek(cursor)? - || kw::f64::peek(cursor)? - || kw::v128::peek(cursor)? - || RefType::peek(cursor)?) + Ok(ValType::parse_shorthand(cursor)?.is_some() || RefType::peek_ref_or_shared(cursor)?) } fn display() -> &'static str { "valtype" @@ -68,6 +114,9 @@ pub enum HeapType<'a> { /// A reference to a concrete function, struct, or array type defined by /// Wasm: `ref T`. This is part of the function references and GC proposals. Concrete(Index<'a>), + /// A reference to an exact type. + /// This is part of the custom descriptors proposal. + Exact(Index<'a>), } impl<'a> Parse<'a> for HeapType<'a> { @@ -77,11 +126,16 @@ impl<'a> Parse<'a> for HeapType<'a> { Ok(HeapType::Concrete(parser.parse()?)) } else if l.peek::<LParen>()? { parser.parens(|p| { - p.parse::<kw::shared>()?; - Ok(HeapType::Abstract { - shared: true, - ty: p.parse()?, - }) + if l.peek::<kw::exact>()? { + p.parse::<kw::exact>()?; + Ok(HeapType::Exact(p.parse()?)) + } else { + p.parse::<kw::shared>()?; + Ok(HeapType::Abstract { + shared: true, + ty: p.parse()?, + }) + } }) } else if l.peek::<AbstractHeapType>()? { Ok(HeapType::Abstract { @@ -193,7 +247,7 @@ impl<'a> Parse<'a> for AbstractHeapType { } } -impl<'a> Peek for AbstractHeapType { +impl Peek for AbstractHeapType { fn peek(cursor: Cursor<'_>) -> Result<bool> { Ok(kw::func::peek(cursor)? || kw::r#extern::peek(cursor)? @@ -225,7 +279,7 @@ pub struct RefType<'a> { impl<'a> RefType<'a> { /// A `funcref` as an abbreviation for `(ref null func)`. - pub fn func() -> Self { + pub const fn func() -> Self { RefType { nullable: true, heap: HeapType::Abstract { @@ -236,7 +290,7 @@ impl<'a> RefType<'a> { } /// An `externref` as an abbreviation for `(ref null extern)`. - pub fn r#extern() -> Self { + pub const fn r#extern() -> Self { RefType { nullable: true, heap: HeapType::Abstract { @@ -247,7 +301,7 @@ impl<'a> RefType<'a> { } /// An `exnref` as an abbreviation for `(ref null exn)`. - pub fn exn() -> Self { + pub const fn exn() -> Self { RefType { nullable: true, heap: HeapType::Abstract { @@ -258,7 +312,7 @@ impl<'a> RefType<'a> { } /// An `cont` as an abbreviation for `(ref null cont)`. - pub fn cont() -> Self { + pub const fn cont() -> Self { RefType { nullable: true, heap: HeapType::Abstract { @@ -269,7 +323,7 @@ impl<'a> RefType<'a> { } /// An `anyref` as an abbreviation for `(ref null any)`. - pub fn any() -> Self { + pub const fn any() -> Self { RefType { nullable: true, heap: HeapType::Abstract { @@ -280,7 +334,7 @@ impl<'a> RefType<'a> { } /// An `eqref` as an abbreviation for `(ref null eq)`. - pub fn eq() -> Self { + pub const fn eq() -> Self { RefType { nullable: true, heap: HeapType::Abstract { @@ -291,7 +345,7 @@ impl<'a> RefType<'a> { } /// An `structref` as an abbreviation for `(ref null struct)`. - pub fn r#struct() -> Self { + pub const fn r#struct() -> Self { RefType { nullable: true, heap: HeapType::Abstract { @@ -302,7 +356,7 @@ impl<'a> RefType<'a> { } /// An `arrayref` as an abbreviation for `(ref null array)`. - pub fn array() -> Self { + pub const fn array() -> Self { RefType { nullable: true, heap: HeapType::Abstract { @@ -313,7 +367,7 @@ impl<'a> RefType<'a> { } /// An `i31ref` as an abbreviation for `(ref null i31)`. - pub fn i31() -> Self { + pub const fn i31() -> Self { RefType { nullable: true, heap: HeapType::Abstract { @@ -324,7 +378,7 @@ impl<'a> RefType<'a> { } /// A `nullfuncref` as an abbreviation for `(ref null nofunc)`. - pub fn nullfuncref() -> Self { + pub const fn nullfuncref() -> Self { RefType { nullable: true, heap: HeapType::Abstract { @@ -335,7 +389,7 @@ impl<'a> RefType<'a> { } /// A `nullexternref` as an abbreviation for `(ref null noextern)`. - pub fn nullexternref() -> Self { + pub const fn nullexternref() -> Self { RefType { nullable: true, heap: HeapType::Abstract { @@ -346,7 +400,7 @@ impl<'a> RefType<'a> { } /// A `nullref` as an abbreviation for `(ref null none)`. - pub fn nullref() -> Self { + pub const fn nullref() -> Self { RefType { nullable: true, heap: HeapType::Abstract { @@ -357,7 +411,7 @@ impl<'a> RefType<'a> { } /// A `nullexnref` as an abbreviation for `(ref null noexn)`. - pub fn nullexnref() -> Self { + pub const fn nullexnref() -> Self { RefType { nullable: true, heap: HeapType::Abstract { @@ -368,7 +422,7 @@ impl<'a> RefType<'a> { } /// A `nullcontref` as an abbreviation for `(ref null nocont)`. - pub fn nullcontref() -> Self { + pub const fn nullcontref() -> Self { RefType { nullable: true, heap: HeapType::Abstract { @@ -392,131 +446,78 @@ impl<'a> RefType<'a> { } } - /// Helper for checking if shorthand forms of reference types can be parsed - /// next; e.g., `funcref`. - fn peek_shorthand(l: &mut Lookahead1) -> Result<bool> { - Ok(l.peek::<kw::funcref>()? - || l.peek::<kw::externref>()? - || l.peek::<kw::exnref>()? - || l.peek::<kw::anyref>()? - || l.peek::<kw::eqref>()? - || l.peek::<kw::structref>()? - || l.peek::<kw::arrayref>()? - || l.peek::<kw::i31ref>()? - || l.peek::<kw::contref>()? - || l.peek::<kw::nullfuncref>()? - || l.peek::<kw::nullexternref>()? - || l.peek::<kw::nullexnref>()? - || l.peek::<kw::nullref>()? - || l.peek::<kw::nullcontref>()?) + fn peek_ref_or_shared(cursor: Cursor<'a>) -> Result<bool> { + let cursor = match cursor.lparen()? { + Some(c) => c, + None => return Ok(false), + }; + Ok(kw::r#ref::peek(cursor)? || kw::shared::peek(cursor)?) } /// Helper for parsing shorthand forms of reference types; e.g., `funcref`. - fn parse_shorthand(mut l: Lookahead1, parser: Parser<'a>) -> Result<Self> { - if l.peek::<kw::funcref>()? { - parser.parse::<kw::funcref>()?; - Ok(RefType::func()) - } else if l.peek::<kw::externref>()? { - parser.parse::<kw::externref>()?; - Ok(RefType::r#extern()) - } else if l.peek::<kw::exnref>()? { - parser.parse::<kw::exnref>()?; - Ok(RefType::exn()) - } else if l.peek::<kw::contref>()? { - parser.parse::<kw::contref>()?; - Ok(RefType::cont()) - } else if l.peek::<kw::anyref>()? { - parser.parse::<kw::anyref>()?; - Ok(RefType::any()) - } else if l.peek::<kw::eqref>()? { - parser.parse::<kw::eqref>()?; - Ok(RefType::eq()) - } else if l.peek::<kw::structref>()? { - parser.parse::<kw::structref>()?; - Ok(RefType::r#struct()) - } else if l.peek::<kw::arrayref>()? { - parser.parse::<kw::arrayref>()?; - Ok(RefType::array()) - } else if l.peek::<kw::i31ref>()? { - parser.parse::<kw::i31ref>()?; - Ok(RefType::i31()) - } else if l.peek::<kw::nullfuncref>()? { - parser.parse::<kw::nullfuncref>()?; - Ok(RefType::nullfuncref()) - } else if l.peek::<kw::nullexternref>()? { - parser.parse::<kw::nullexternref>()?; - Ok(RefType::nullexternref()) - } else if l.peek::<kw::nullexnref>()? { - parser.parse::<kw::nullexnref>()?; - Ok(RefType::nullexnref()) - } else if l.peek::<kw::nullcontref>()? { - parser.parse::<kw::nullcontref>()?; - Ok(RefType::nullcontref()) - } else if l.peek::<kw::nullref>()? { - parser.parse::<kw::nullref>()?; - Ok(RefType::nullref()) - } else { - Err(l.error()) + fn parse_shorthand(cursor: Cursor<'a>) -> Result<Option<(RefType<'a>, Cursor<'a>)>> { + if let Some((kw, c)) = cursor.keyword()? { + for (name, ty) in REFTYPE_SHORTHANDS.iter().copied() { + if name == kw { + return Ok(Some((ty, c))); + } + } } + Ok(None) } } impl<'a> Parse<'a> for RefType<'a> { fn parse(parser: Parser<'a>) -> Result<Self> { - let mut l = parser.lookahead1(); - if RefType::peek_shorthand(&mut l)? { - // I.e., `*ref`. - RefType::parse_shorthand(l, parser) - } else if l.peek::<LParen>()? { - parser.parens(|p| { - let mut l = parser.lookahead1(); - if l.peek::<kw::r#ref>()? { - // I.e., `(ref null? ...)`. - p.parse::<kw::r#ref>()?; - - let mut nullable = false; - if parser.peek::<kw::null>()? { - parser.parse::<kw::null>()?; - nullable = true; - } - - Ok(RefType { - nullable, - heap: parser.parse()?, - }) - } else if l.peek::<kw::shared>()? { - // I.e., `(shared *ref)`. - p.parse::<kw::shared>()?; - let reftype = RefType::parse_shorthand(l, parser)?; - Ok(reftype.shared().expect("only abstract heap types are used")) - } else { - Err(l.error()) - } - }) - } else { - Err(l.error()) + // NB: this isn't using typical `Parser`-style combinators because + // parsing a reftype is intertwined with parsing a `ValType` which needs + // to be faster-than-average. + let shorthand = parser.step(|cursor| { + if let Some((ty, c)) = RefType::parse_shorthand(cursor)? { + return Ok((Some(ty), c)); + } + Ok((None, cursor)) + })?; + if let Some(shorthand) = shorthand { + return Ok(shorthand); } + if !parser.peek::<LParen>()? { + return Err(parser.error(type_parse_error(false))); + } + parser.parens(|p| { + let mut l = parser.lookahead1(); + if l.peek::<kw::r#ref>()? { + // I.e., `(ref null? ...)`. + p.parse::<kw::r#ref>()?; + + let mut nullable = false; + if parser.peek::<kw::null>()? { + parser.parse::<kw::null>()?; + nullable = true; + } + + Ok(RefType { + nullable, + heap: parser.parse()?, + }) + } else if l.peek::<kw::shared>()? { + // I.e., `(shared *ref)`. + p.parse::<kw::shared>()?; + let reftype = parser.step(|cursor| { + RefType::parse_shorthand(cursor)? + .ok_or_else(|| parser.error(type_parse_error(false))) + })?; + Ok(reftype.shared().expect("only abstract heap types are used")) + } else { + Err(l.error()) + } + }) } } impl<'a> Peek for RefType<'a> { fn peek(cursor: Cursor<'_>) -> Result<bool> { - Ok(kw::funcref::peek(cursor)? - || kw::externref::peek(cursor)? - || kw::exnref::peek(cursor)? - || kw::anyref::peek(cursor)? - || kw::eqref::peek(cursor)? - || kw::structref::peek(cursor)? - || kw::arrayref::peek(cursor)? - || kw::i31ref::peek(cursor)? - || kw::contref::peek(cursor)? - || kw::nullfuncref::peek(cursor)? - || kw::nullexternref::peek(cursor)? - || kw::nullexnref::peek(cursor)? - || kw::nullref::peek(cursor)? - || kw::nullcontref::peek(cursor)? - || (LParen::peek(cursor)? && kw::shared::peek2(cursor)?) - || (LParen::peek(cursor)? && kw::r#ref::peek2(cursor)?)) + Ok(RefType::parse_shorthand(cursor)?.is_some() || RefType::peek_ref_or_shared(cursor)?) } fn display() -> &'static str { "reftype" @@ -957,49 +958,99 @@ pub struct TypeDef<'a> { pub shared: bool, /// The declared parent type of this definition. pub parent: Option<Index<'a>>, + /// The descriptor type. + pub descriptor: Option<Index<'a>>, + /// The descriptor for type. + pub describes: Option<Index<'a>>, /// Whether this type is final or not. By default types are final. pub final_type: Option<bool>, } +fn parse_optional<'a, K: Peek + Parse<'a>, R, T>( + parser: Parser<'a>, + parse: impl FnOnce(Parser<'a>) -> Result<R>, + default: R, + f: impl FnOnce(Parser<'a>, R) -> Result<T>, +) -> Result<T> { + if parser.peek::<K>()? { + parser.parse::<K>()?; + let result: R = parse(parser)?; + parser.parens(|parser: Parser| f(parser, result)) + } else { + f(parser, default) + } +} + +fn expect_parens_close_then_open<'a>(parser: Parser<'a>) -> Result<()> { + parser.step(|cursor| { + let cursor = match cursor.rparen()? { + Some(rest) => rest, + None => return Err(cursor.error("expected `(`")), + }; + match cursor.lparen()? { + Some(rest) => Ok(((), rest)), + None => Err(cursor.error("expected `(`")), + } + }) +} + impl<'a> Parse<'a> for TypeDef<'a> { fn parse(parser: Parser<'a>) -> Result<Self> { let parse_shared_and_kind = |parser: Parser<'a>| { - if parser.peek::<kw::shared>()? { - parser.parse::<kw::shared>()?; - parser.parens(|parser| { + parse_optional::<kw::shared, _, _>( + parser, + |_| Ok(true), + false, + |parser, shared| { + let describes = if parser.peek::<kw::describes>()? { + parser.parse::<kw::describes>()?; + let index = parser.parse::<Index>()?; + expect_parens_close_then_open(parser)?; + Some(index) + } else { + None + }; + let descriptor = if parser.peek::<kw::descriptor>()? { + parser.parse::<kw::descriptor>()?; + let index = parser.parse::<Index>()?; + expect_parens_close_then_open(parser)?; + Some(index) + } else { + None + }; let kind = parser.parse()?; - Ok((true, kind)) - }) - } else { - let kind = parser.parse()?; - Ok((false, kind)) - } + Ok((shared, descriptor, describes, kind)) + }, + ) }; - let (parent, (shared, kind), final_type) = if parser.peek::<kw::sub>()? { - parser.parse::<kw::sub>()?; + let (parent, (shared, descriptor, describes, kind), final_type) = + if parser.peek::<kw::sub>()? { + parser.parse::<kw::sub>()?; - let final_type: Option<bool> = if parser.peek::<kw::r#final>()? { - parser.parse::<kw::r#final>()?; - Some(true) - } else { - Some(false) - }; + let final_type: Option<bool> = if parser.peek::<kw::r#final>()? { + parser.parse::<kw::r#final>()?; + Some(true) + } else { + Some(false) + }; - let parent = if parser.peek::<Index<'a>>()? { - parser.parse()? + let parent = if parser.peek::<Index<'a>>()? { + parser.parse()? + } else { + None + }; + let pair = parser.parens(parse_shared_and_kind)?; + (parent, pair, final_type) } else { - None + (None, parse_shared_and_kind(parser)?, None) }; - let pair = parser.parens(parse_shared_and_kind)?; - (parent, pair, final_type) - } else { - (None, parse_shared_and_kind(parser)?, None) - }; Ok(TypeDef { kind, shared, parent, + descriptor, + describes, final_type, }) } diff --git a/third_party/rust/wast/src/core/wast.rs b/third_party/rust/wast/src/core/wast.rs @@ -1,7 +1,7 @@ use crate::core::{HeapType, V128Const}; use crate::kw; use crate::parser::{Cursor, Parse, Parser, Peek, Result}; -use crate::token::{Index, F32, F64}; +use crate::token::{F32, F64, Index}; /// Expression that can be used inside of `invoke` expressions for core wasm /// functions. diff --git a/third_party/rust/wast/src/error.rs b/third_party/rust/wast/src/error.rs @@ -138,7 +138,7 @@ impl fmt::Display for Error { let text = match &self.inner.text { Some(text) => text, None => { - return write!(f, "{} at byte offset {}", err, self.inner.span.offset); + return write!(f, "{err} at byte offset {}", self.inner.span.offset); } }; let file = self @@ -147,6 +147,14 @@ impl fmt::Display for Error { .as_ref() .and_then(|p| p.to_str()) .unwrap_or("<anon>"); + let col = text.col + 1; + let line = text.line + 1; + + // If the column is too big skip the fancy rendering below and just + // print the raw error. + if col > 500 { + return write!(f, "{err} at {file}:{line}:{col}"); + } write!( f, "\ @@ -155,11 +163,7 @@ impl fmt::Display for Error { | {line:4} | {text} | {marker:>0$}", - text.col + 1, - file = file, - line = text.line + 1, - col = text.col + 1, - err = err, + col, text = text.snippet, marker = "^", ) diff --git a/third_party/rust/wast/src/lexer.rs b/third_party/rust/wast/src/lexer.rs @@ -24,8 +24,8 @@ //! //! [`Lexer`]: crate::lexer::Lexer -use crate::token::Span; use crate::Error; +use crate::token::Span; use std::borrow::Cow; use std::char; use std::fmt; @@ -669,7 +669,7 @@ impl<'a> Lexer<'a> { has_underscores, sign, hex, - })) + })); } } @@ -719,10 +719,7 @@ impl<'a> Lexer<'a> { hex, })); - fn skip_underscores<'a>( - it: &mut slice::Iter<'_, u8>, - good: fn(u8) -> bool, - ) -> Option<bool> { + fn skip_underscores(it: &mut slice::Iter<'_, u8>, good: fn(u8) -> bool) -> Option<bool> { let mut last_underscore = false; let mut has_underscores = false; let first = *it.next()?; @@ -830,10 +827,10 @@ impl<'a> Lexer<'a> { } } c if (c as u32) < 0x20 || c as u32 == 0x7f => { - return Err(LexError::InvalidStringElement(c)) + return Err(LexError::InvalidStringElement(c)); } c if !allow_confusing_unicode && is_confusing_unicode(c) => { - return Err(LexError::ConfusingUnicode(c)) + return Err(LexError::ConfusingUnicode(c)); } c => match &mut state { State::Start => {} @@ -1216,9 +1213,9 @@ impl fmt::Display for LexError { )?, UnexpectedEof => write!(f, "unexpected end-of-file")?, NumberTooBig => f.write_str("number is too big to parse")?, - InvalidUnicodeValue(c) => write!(f, "invalid unicode scalar value 0x{:x}", c)?, + InvalidUnicodeValue(c) => write!(f, "invalid unicode scalar value 0x{c:x}")?, LoneUnderscore => write!(f, "bare underscore in numeric literal")?, - ConfusingUnicode(c) => write!(f, "likely-confusing unicode character found {:?}", c)?, + ConfusingUnicode(c) => write!(f, "likely-confusing unicode character found {c:?}")?, InvalidUtf8Id(_) => write!(f, "malformed UTF-8 encoding of string-based id")?, EmptyId => write!(f, "empty identifier")?, EmptyAnnotation => write!(f, "empty annotation id")?, @@ -1273,7 +1270,7 @@ mod tests { let token = get_token(input); match token.kind { TokenKind::Whitespace => token.src(input), - other => panic!("unexpected {:?}", other), + other => panic!("unexpected {other:?}"), } } assert_eq!(get_whitespace(" "), " "); @@ -1289,7 +1286,7 @@ mod tests { let token = get_token(input); match token.kind { TokenKind::LineComment => token.src(input), - other => panic!("unexpected {:?}", other), + other => panic!("unexpected {other:?}"), } } assert_eq!(get_line_comment(";;"), ";;"); @@ -1307,7 +1304,7 @@ mod tests { let token = get_token(input); match token.kind { TokenKind::BlockComment => token.src(input), - other => panic!("unexpected {:?}", other), + other => panic!("unexpected {other:?}"), } } assert_eq!(get_block_comment("(;;)"), "(;;)"); @@ -1338,7 +1335,7 @@ mod tests { let token = get_token(input); match token.kind { TokenKind::String => token.string(input).to_vec(), - other => panic!("not keyword {:?}", other), + other => panic!("not keyword {other:?}"), } } assert_eq!(&*get_string("\"\""), b""); @@ -1362,7 +1359,7 @@ mod tests { ); for i in 0..=255i32 { - let s = format!("\"\\{:02x}\"", i); + let s = format!("\"\\{i:02x}\""); assert_eq!(&*get_string(&s), &[i as u8]); } } @@ -1373,7 +1370,7 @@ mod tests { let token = get_token(input); match token.kind { TokenKind::Id => token.id(input).unwrap().to_string(), - other => panic!("not id {:?}", other), + other => panic!("not id {other:?}"), } } assert_eq!(get_id("$x"), "x"); @@ -1391,7 +1388,7 @@ mod tests { let token = get_token(input); match token.kind { TokenKind::Annotation => token.annotation(input).unwrap().to_string(), - other => panic!("not annotation {:?}", other), + other => panic!("not annotation {other:?}"), } } assert_eq!(get_annotation("@foo"), "foo"); @@ -1407,7 +1404,7 @@ mod tests { let token = get_token(input); match token.kind { TokenKind::Keyword => token.keyword(input), - other => panic!("not keyword {:?}", other), + other => panic!("not keyword {other:?}"), } } assert_eq!(get_keyword("x"), "x"); @@ -1423,7 +1420,7 @@ mod tests { let token = get_token(input); match token.kind { TokenKind::Reserved => token.reserved(input), - other => panic!("not reserved {:?}", other), + other => panic!("not reserved {other:?}"), } } assert_eq!(get_reserved("^_x "), "^_x"); @@ -1435,7 +1432,7 @@ mod tests { let token = get_token(input); match token.kind { TokenKind::Integer(i) => token.integer(input, i).val.to_string(), - other => panic!("not integer {:?}", other), + other => panic!("not integer {other:?}"), } } assert_eq!(get_integer("1"), "1"); @@ -1455,7 +1452,7 @@ mod tests { let token = get_token(input); match token.kind { TokenKind::Float(f) => token.float(input, f), - other => panic!("not float {:?}", other), + other => panic!("not float {other:?}"), } } assert_eq!( diff --git a/third_party/rust/wast/src/lib.rs b/third_party/rust/wast/src/lib.rs @@ -51,7 +51,7 @@ //! [`LexError`]: lexer::LexError #![deny(missing_docs, rustdoc::broken_intra_doc_links)] -#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(docsrs, feature(doc_cfg))] /// A macro to create a custom keyword parser. /// @@ -416,10 +416,13 @@ pub mod kw { custom_keyword!(data); custom_keyword!(declare); custom_keyword!(delegate); + custom_keyword!(descriptor); + custom_keyword!(describes); custom_keyword!(r#do = "do"); custom_keyword!(dtor); custom_keyword!(elem); custom_keyword!(end); + custom_keyword!(exact); custom_keyword!(tag); custom_keyword!(exn); custom_keyword!(exnref); @@ -544,6 +547,8 @@ pub mod kw { custom_keyword!(post_return = "post-return"); custom_keyword!(with); custom_keyword!(core); + custom_keyword!(core_type = "core-type"); + custom_keyword!(gc); custom_keyword!(true_ = "true"); custom_keyword!(false_ = "false"); custom_keyword!(language); @@ -553,29 +558,33 @@ pub mod kw { custom_keyword!(needed); custom_keyword!(export_info = "export-info"); custom_keyword!(import_info = "import-info"); + custom_keyword!(runtime_path = "runtime-path"); custom_keyword!(thread); - custom_keyword!(thread_spawn = "thread.spawn"); - custom_keyword!(thread_hw_concurrency = "thread.hw_concurrency"); - custom_keyword!(task_backpressure = "task.backpressure"); + custom_keyword!(thread_spawn_ref = "thread.spawn-ref"); + custom_keyword!(thread_spawn_indirect = "thread.spawn-indirect"); + custom_keyword!(thread_available_parallelism = "thread.available_parallelism"); + custom_keyword!(backpressure_set = "backpressure.set"); + custom_keyword!(backpressure_inc = "backpressure.inc"); + custom_keyword!(backpressure_dec = "backpressure.dec"); custom_keyword!(task_return = "task.return"); - custom_keyword!(task_wait = "task.wait"); - custom_keyword!(task_poll = "task.poll"); - custom_keyword!(task_yield = "task.yield"); + custom_keyword!(task_cancel = "task.cancel"); + custom_keyword!(thread_yield = "thread.yield"); custom_keyword!(subtask_drop = "subtask.drop"); + custom_keyword!(subtask_cancel = "subtask.cancel"); custom_keyword!(stream_new = "stream.new"); custom_keyword!(stream_read = "stream.read"); custom_keyword!(stream_write = "stream.write"); custom_keyword!(stream_cancel_read = "stream.cancel-read"); custom_keyword!(stream_cancel_write = "stream.cancel-write"); - custom_keyword!(stream_close_readable = "stream.close-readable"); - custom_keyword!(stream_close_writable = "stream.close-writable"); + custom_keyword!(stream_drop_readable = "stream.drop-readable"); + custom_keyword!(stream_drop_writable = "stream.drop-writable"); custom_keyword!(future_new = "future.new"); custom_keyword!(future_read = "future.read"); custom_keyword!(future_write = "future.write"); custom_keyword!(future_cancel_read = "future.cancel-read"); custom_keyword!(future_cancel_write = "future.cancel-write"); - custom_keyword!(future_close_readable = "future.close-readable"); - custom_keyword!(future_close_writable = "future.close-writable"); + custom_keyword!(future_drop_readable = "future.drop-readable"); + custom_keyword!(future_drop_writable = "future.drop-writable"); custom_keyword!(error_context_new = "error-context.new"); custom_keyword!(error_context_debug_message = "error-context.debug-message"); custom_keyword!(error_context_drop = "error-context.drop"); @@ -585,6 +594,21 @@ pub mod kw { custom_keyword!(callback); custom_keyword!(stream); custom_keyword!(future); + custom_keyword!(error_context = "error-context"); + custom_keyword!(waitable_set_new = "waitable-set.new"); + custom_keyword!(waitable_set_wait = "waitable-set.wait"); + custom_keyword!(waitable_set_poll = "waitable-set.poll"); + custom_keyword!(waitable_set_drop = "waitable-set.drop"); + custom_keyword!(waitable_join = "waitable.join"); + custom_keyword!(context_get = "context.get"); + custom_keyword!(context_set = "context.set"); + custom_keyword!(thread_index = "thread.index"); + custom_keyword!(thread_new_indirect = "thread.new-indirect"); + custom_keyword!(thread_switch_to = "thread.switch-to"); + custom_keyword!(thread_suspend = "thread.suspend"); + custom_keyword!(thread_resume_later = "thread.resume-later"); + custom_keyword!(thread_yield_to = "thread.yield-to"); + custom_keyword!(cancellable); } /// Common annotations used to parse WebAssembly text files. diff --git a/third_party/rust/wast/src/names.rs b/third_party/rust/wast/src/names.rs @@ -1,5 +1,5 @@ -use crate::token::{Id, Index}; use crate::Error; +use crate::token::{Id, Index}; use std::collections::HashMap; #[derive(Default)] @@ -15,7 +15,7 @@ impl<'a> Namespace<'a> { if let Some(_prev) = self.names.insert(name, index) { return Err(Error::new( name.span(), - format!("duplicate {} identifier", desc), + format!("duplicate {desc} identifier"), )); } } @@ -57,8 +57,7 @@ impl<'a> Namespace<'a> { pub fn resolve_error(id: Id<'_>, ns: &str) -> Error { assert!( !id.is_gensym(), - "symbol generated by `wast` itself cannot be resolved {:?}", - id + "symbol generated by `wast` itself cannot be resolved {id:?}" ); Error::new( id.span(), diff --git a/third_party/rust/wast/src/parser.rs b/third_party/rust/wast/src/parser.rs @@ -62,9 +62,9 @@ //! This module is heavily inspired by [`syn`](https://docs.rs/syn) so you can //! likely also draw inspiration from the excellent examples in the `syn` crate. +use crate::Error; use crate::lexer::{Float, Integer, Lexer, Token, TokenKind}; use crate::token::Span; -use crate::Error; use bumpalo::Bump; use std::borrow::Cow; use std::cell::{Cell, RefCell}; @@ -429,7 +429,7 @@ impl ParseBuffer<'_> { match token.kind { // Always skip whitespace and comments. TokenKind::Whitespace | TokenKind::LineComment | TokenKind::BlockComment => { - continue + continue; } // If an lparen is seen then this may be skipped if it's an @@ -1388,7 +1388,7 @@ impl<'a> Cursor<'a> { } } -impl Lookahead1<'_> { +impl<'a> Lookahead1<'a> { /// Attempts to see if `T` is the next token in the [`Parser`] this /// [`Lookahead1`] references. /// @@ -1402,6 +1402,11 @@ impl Lookahead1<'_> { }) } + /// Returns the underlying parser that this lookahead is looking at. + pub fn parser(&self) -> Parser<'a> { + self.parser + } + /// Generates an error message saying that one of the tokens passed to /// [`Lookahead1::peek`] method was expected. /// @@ -1429,7 +1434,7 @@ impl Lookahead1<'_> { } _ => { let join = self.attempts.join(", "); - let message = format!("unexpected token, expected one of: {}", join); + let message = format!("unexpected token, expected one of: {join}"); self.parser.error(&message) } } diff --git a/third_party/rust/wast/src/wat.rs b/third_party/rust/wast/src/wat.rs @@ -17,13 +17,6 @@ pub enum Wat<'a> { } impl Wat<'_> { - fn validate(&self, parser: Parser<'_>) -> Result<()> { - match self { - Wat::Module(m) => m.validate(parser), - Wat::Component(c) => c.validate(parser), - } - } - /// Encodes this `Wat` to binary form. This calls either [`Module::encode`] /// or [`Component::encode`]. pub fn encode(&mut self) -> std::result::Result<Vec<u8>, crate::Error> { @@ -59,7 +52,6 @@ impl<'a> Parse<'a> for Wat<'a> { kind: ModuleKind::Text(fields), }) }; - wat.validate(parser)?; Ok(wat) }) } diff --git a/third_party/rust/wast/tests/parse-fail.rs b/third_party/rust/wast/tests/parse-fail.rs @@ -44,8 +44,7 @@ fn run_test(test: &Path, bless: bool) -> anyhow::Result<()> { .unwrap_or(String::new()) .replace("\r\n", "\n"); - // Compare normalize verisons which handles weirdness like path differences - if normalize(&assert) == normalize(&err) { + if assert == err { return Ok(()); } @@ -55,10 +54,6 @@ fn run_test(test: &Path, bless: bool) -> anyhow::Result<()> { tab(&err), ); - fn normalize(s: &str) -> String { - s.replace("\\", "/") - } - fn tab(s: &str) -> String { s.replace("\n", "\n\t") } @@ -67,14 +62,22 @@ fn run_test(test: &Path, bless: bool) -> anyhow::Result<()> { fn find_tests(path: &Path, tests: &mut Vec<PathBuf>) { for f in path.read_dir().unwrap() { let f = f.unwrap(); + // The .wat.err files contain relative file paths with forward slashes. + // On Windows we need to normalize the paths, otherwise BLESS will + // overwrite all .err files with updated paths. + let path: PathBuf = f + .path() + .to_string_lossy() + .replace(std::path::MAIN_SEPARATOR, "/") + .into(); if f.file_type().unwrap().is_dir() { - find_tests(&f.path(), tests); + find_tests(&path, tests); continue; } - match f.path().extension().and_then(|s| s.to_str()) { + match path.extension().and_then(|s| s.to_str()) { Some("wat") => {} _ => continue, } - tests.push(f.path()); + tests.push(path); } }