wasm-encoder-0.239.0/.cargo_vcs_info.json0000644000000001610000000000100135710ustar { "git": { "sha1": "35f8671bce74190ef0b00ce36c399b053b490374" }, "path_in_vcs": "crates/wasm-encoder" }wasm-encoder-0.239.0/Cargo.lock0000644000000234070000000000100115540ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "anyhow" version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "bitflags" version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "cfg-if" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", "windows-sys 0.60.2", ] [[package]] name = "fastrand" 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 = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", "r-efi", "wasi", ] [[package]] name = "hashbrown" version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" [[package]] name = "indexmap" version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "leb128fmt" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "linux-raw-sys" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" 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 = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", "windows-sys 0.59.0", ] [[package]] name = "semver" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "tempfile" version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", "getrandom", "once_cell", "rustix", "windows-sys 0.59.0", ] [[package]] name = "termcolor" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[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.239.0" dependencies = [ "anyhow", "leb128fmt", "tempfile", "wasmparser", "wasmprinter", ] [[package]] name = "wasmparser" version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" dependencies = [ "bitflags", "indexmap", "semver", ] [[package]] name = "wasmprinter" version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3981f3d51f39f24f5fc90f93049a90f08dbbca8deba602cd46bb8ca67a94718" dependencies = [ "anyhow", "termcolor", "wasmparser", ] [[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.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-sys" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ "windows-targets 0.53.2", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "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]] name = "windows_aarch64_gnullvm" version = "0.52.6" 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", ] wasm-encoder-0.239.0/Cargo.toml0000644000000050150000000000100115720ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.76.0" name = "wasm-encoder" version = "0.239.0" authors = ["Nick Fitzgerald "] build = "build.rs" autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = """ A low-level WebAssembly encoder. """ homepage = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder" documentation = "https://docs.rs/wasm-encoder" readme = "README.md" license = "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT" repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder" [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" [dependencies.leb128fmt] version = "0.1.0" default-features = false [dependencies.wasmparser] version = "0.239.0" features = [ "simd", "simd", ] optional = true default-features = false [dev-dependencies.anyhow] version = "1.0.58" [dev-dependencies.tempfile] version = "3.2.0" [dev-dependencies.wasmprinter] version = "0.239.0" default-features = false [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] 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)"] wasm-encoder-0.239.0/Cargo.toml.orig000064400000000000000000000023101046102023000152460ustar 00000000000000[package] name = "wasm-encoder" version.workspace = true authors = ["Nick Fitzgerald "] edition.workspace = true license.workspace = true readme = "README.md" repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder" homepage = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder" documentation = "https://docs.rs/wasm-encoder" description = """ A low-level WebAssembly encoder. """ rust-version.workspace = true [package.metadata.docs.rs] all-features = true [lints] workspace = true [dependencies] leb128fmt.workspace = true # Enable this dependency to get a bunch of `From for # wasm_encoder::Foo` impls. wasmparser = { optional = true, workspace = true, features = ["simd"] } [dev-dependencies] anyhow = { workspace = true } tempfile = "3.2.0" wasmparser = { path = "../wasmparser" } wasmprinter = { workspace = true } [features] default = ['std', 'component-model'] # A feature which enables implementations of `std::error::Error` as appropriate. std = ["wasmparser?/std"] # On-by-default: conditional support for emitting components in addition to # core modules. component-model = ['wasmparser?/component-model'] wasm-encoder-0.239.0/README.md000064400000000000000000000044441046102023000136500ustar 00000000000000

wasm-encoder

A Bytecode Alliance project

A WebAssembly encoder for Rust.

Crates.io version Download docs.rs docs

## Usage Add `wasm-encoder` to your `Cargo.toml` ```sh $ cargo add wasm-encoder ``` And then you can encode WebAssembly binaries via: ```rust use wasm_encoder::{ CodeSection, ExportKind, ExportSection, Function, FunctionSection, Module, TypeSection, ValType, }; let mut module = Module::new(); // Encode the type section. let mut types = TypeSection::new(); let params = vec![ValType::I32, ValType::I32]; let results = vec![ValType::I32]; types.ty().function(params, results); module.section(&types); // Encode the function section. let mut functions = FunctionSection::new(); let type_index = 0; functions.function(type_index); module.section(&functions); // Encode the export section. let mut exports = ExportSection::new(); exports.export("f", ExportKind::Func, 0); module.section(&exports); // Encode the code section. let mut codes = CodeSection::new(); let locals = vec![]; let mut f = Function::new(locals); f.instructions() .local_get(0) .local_get(1) .i32_add() .end(); codes.function(&f); module.section(&codes); // Extract the encoded Wasm bytes for this module. let wasm_bytes = module.finish(); // We generated a valid Wasm module! assert!(wasmparser::validate(&wasm_bytes).is_ok()); ``` # License This project is licensed under the Apache 2.0 license with the LLVM exception. See [LICENSE](LICENSE) for more details. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be licensed as above, without any additional terms or conditions. wasm-encoder-0.239.0/build.rs000064400000000000000000000015771046102023000140420ustar 00000000000000use std::process::Command; use std::str; fn main() { // Temporary check to see if the rustc version >= 1.81 in which case the // `Error` trait is always available. This is temporary because in the // future the MSRV of this crate will be beyond 1.81 in which case this // build script can be deleted. let minor = rustc_minor_version().unwrap_or(0); if minor >= 81 { println!("cargo:rustc-cfg=core_error"); } if minor >= 80 { println!("cargo:rustc-check-cfg=cfg(core_error)"); } } fn rustc_minor_version() -> Option { let rustc = std::env::var("RUSTC").unwrap(); let output = Command::new(rustc).arg("--version").output().ok()?; let version = str::from_utf8(&output.stdout).ok()?; let mut pieces = version.split('.'); if pieces.next() != Some("rustc 1") { return None; } pieces.next()?.parse().ok() } wasm-encoder-0.239.0/src/component/aliases.rs000064400000000000000000000111421046102023000171420ustar 00000000000000use super::{COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, CORE_TYPE_SORT, TYPE_SORT}; use crate::{ ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind, encode_section, }; use alloc::vec::Vec; /// Represents the kinds of outer aliasable items in a component. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum ComponentOuterAliasKind { /// The alias is to a core module. CoreModule, /// The alias is to a core type. CoreType, /// The alias is to a type. Type, /// The alias is to a component. Component, } impl Encode for ComponentOuterAliasKind { fn encode(&self, sink: &mut Vec) { match self { Self::CoreModule => { sink.push(CORE_SORT); sink.push(CORE_MODULE_SORT); } Self::CoreType => { sink.push(CORE_SORT); sink.push(CORE_TYPE_SORT); } Self::Type => sink.push(TYPE_SORT), Self::Component => sink.push(COMPONENT_SORT), } } } /// An encoder for the alias section of WebAssembly component. /// /// # Example /// /// ```rust /// use wasm_encoder::{Component, Alias, ComponentAliasSection, ComponentExportKind, ComponentOuterAliasKind}; /// /// let mut aliases = ComponentAliasSection::new(); /// aliases.alias(Alias::InstanceExport { instance: 0, kind: ComponentExportKind::Func, name: "f" }); /// aliases.alias(Alias::Outer { count: 0, kind: ComponentOuterAliasKind::Type, index: 1 }); /// /// let mut component = Component::new(); /// component.section(&aliases); /// /// let bytes = component.finish(); /// ``` #[derive(Clone, Debug, Default)] pub struct ComponentAliasSection { bytes: Vec, num_added: u32, } /// Different forms of aliases that can be inserted into a /// [`ComponentAliasSection`]. #[derive(Copy, Clone, Debug)] pub enum Alias<'a> { /// An alias of a component instance export. InstanceExport { /// The index of the component instance that's being aliased from. instance: u32, /// The kind of item that's being extracted from the component /// instance. kind: ComponentExportKind, /// The name of the export that's being aliased. name: &'a str, }, /// Same as `InstanceExport`, but for core instances. #[allow(missing_docs)] CoreInstanceExport { instance: u32, kind: ExportKind, name: &'a str, }, /// Aliasing an item from an outer component. Outer { /// The kind of item being aliased, either a type or a component. kind: ComponentOuterAliasKind, /// Number of levels "up" to go to lookup the index within. Level 0 is /// the current scope and level 1 is the enclosing scope, and so on. count: u32, /// The index of the item to alias within the scope referenced by /// `count`. index: u32, }, } impl ComponentAliasSection { /// Create a new alias section encoder. pub fn new() -> Self { Self::default() } /// The number of aliases in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Define an alias to a component instance's export. pub fn alias(&mut self, alias: Alias<'_>) -> &mut Self { alias.encode(&mut self.bytes); self.num_added += 1; self } } impl Encode for ComponentAliasSection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl ComponentSection for ComponentAliasSection { fn id(&self) -> u8 { ComponentSectionId::Alias.into() } } impl Encode for Alias<'_> { fn encode(&self, sink: &mut Vec) { match self { Alias::InstanceExport { instance, kind, name, } => { kind.encode(sink); sink.push(0x00); instance.encode(sink); name.encode(sink); } Alias::CoreInstanceExport { instance, kind, name, } => { sink.push(CORE_SORT); kind.encode(sink); sink.push(0x01); instance.encode(sink); name.encode(sink); } Alias::Outer { kind, count, index } => { kind.encode(sink); sink.push(0x02); count.encode(sink); index.encode(sink); } } } } wasm-encoder-0.239.0/src/component/builder.rs000064400000000000000000000605361046102023000171620ustar 00000000000000use crate::component::*; use crate::{ExportKind, Module, RawSection, ValType}; use alloc::vec::Vec; use core::mem; /// Convenience type to build a component incrementally and automatically keep /// track of index spaces. /// /// This type is intended to be a wrapper around the [`Component`] encoding type /// which is useful for building it up incrementally over time. This type will /// automatically collect definitions into sections and reports the index of all /// items added by keeping track of indices internally. #[derive(Debug, Default)] pub struct ComponentBuilder { /// The binary component that's being built. component: Component, /// The last section which was appended to during encoding. This type is /// generated by the `section_accessors` macro below. /// /// When something is encoded this is used if it matches the kind of item /// being encoded, otherwise it's "flushed" to the output component and a /// new section is started. 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, // Component index spaces funcs: u32, instances: u32, types: u32, components: u32, values: u32, } impl ComponentBuilder { /// Returns the current number of core modules. pub fn core_module_count(&self) -> u32 { self.core_modules } /// Returns the current number of core funcs. pub fn core_func_count(&self) -> u32 { self.core_funcs } /// Returns the current number of core types. pub fn core_type_count(&self) -> u32 { self.core_types } /// Returns the current number of core memories. pub fn core_memory_count(&self) -> u32 { self.core_memories } /// Returns the current number of core tables. pub fn core_table_count(&self) -> u32 { self.core_tables } /// Returns the current number of core instances. pub fn core_instance_count(&self) -> u32 { self.core_instances } /// Returns the current number of core tags. pub fn core_tag_count(&self) -> u32 { self.core_tags } /// Returns the current number of core globals. pub fn core_global_count(&self) -> u32 { self.core_globals } /// Returns the current number of component funcs. pub fn func_count(&self) -> u32 { self.funcs } /// Returns the current number of component instances. pub fn instance_count(&self) -> u32 { self.instances } /// Returns the current number of component values. pub fn value_count(&self) -> u32 { self.values } /// Returns the current number of components. pub fn component_count(&self) -> u32 { self.components } /// Returns the current number of component types. pub fn type_count(&self) -> u32 { self.types } /// Completes this component and returns the binary encoding of the entire /// component. pub fn finish(mut self) -> Vec { self.flush(); self.component.finish() } /// Encodes a core wasm `Module` into this component, returning its index. pub fn core_module(&mut self, module: &Module) -> u32 { self.flush(); self.component.section(&ModuleSection(module)); inc(&mut self.core_modules) } /// Encodes a core wasm `module` into this component, returning its index. pub fn core_module_raw(&mut self, module: &[u8]) -> u32 { self.flush(); self.component.section(&RawSection { id: ComponentSectionId::CoreModule.into(), data: module, }); inc(&mut self.core_modules) } /// Instantiates a core wasm module at `module_index` with the `args` /// provided. /// /// Returns the index of the core wasm instance created. pub fn core_instantiate<'a, A>(&mut self, module_index: u32, args: A) -> u32 where A: IntoIterator, A::IntoIter: ExactSizeIterator, { self.instances().instantiate(module_index, args); inc(&mut self.core_instances) } /// Creates a new core wasm instance from the `exports` provided. /// /// Returns the index of the core wasm instance created. pub fn core_instantiate_exports<'a, E>(&mut self, exports: E) -> u32 where E: IntoIterator, E::IntoIter: ExactSizeIterator, { self.instances().export_items(exports); inc(&mut self.core_instances) } /// 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 created. pub fn core_alias_export(&mut self, instance: u32, name: &str, kind: ExportKind) -> u32 { self.alias(Alias::CoreInstanceExport { instance, kind, name, }) } /// Adds a new alias to this component pub fn alias(&mut self, 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::Outer { kind: ComponentOuterAliasKind::Type, .. } => inc(&mut self.types), Alias::Outer { kind: ComponentOuterAliasKind::CoreModule, .. } => inc(&mut self.core_modules), Alias::Outer { kind: ComponentOuterAliasKind::Component, .. } => inc(&mut self.components), Alias::Outer { kind: ComponentOuterAliasKind::CoreType, .. } => inc(&mut self.core_types), } } /// Creates an alias to a previous component instance's exported item. /// /// The `instance` provided is the instance to access and the `name` is the /// item to access. /// /// 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, }) } fn inc_kind(&mut self, 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), } } fn inc_core_kind(&mut self, 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), } } /// Lowers the `func_index` component function into a core wasm function /// using the `options` provided. /// /// Returns the index of the core wasm function created. pub fn lower_func(&mut self, func_index: u32, options: O) -> u32 where O: IntoIterator, O::IntoIter: ExactSizeIterator, { self.canonical_functions().lower(func_index, options); inc(&mut self.core_funcs) } /// 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(&mut self, core_func_index: u32, type_index: u32, options: O) -> u32 where O: IntoIterator, O::IntoIter: ExactSizeIterator, { self.canonical_functions() .lift(core_func_index, type_index, options); inc(&mut self.funcs) } /// 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), }; self.imports().import(name, ty); ret } /// Exports a new item from this component with the `name` and `kind` /// specified. /// /// The `idx` is the item to export and the `ty` is an optional type to /// ascribe to the export. pub fn export( &mut self, name: &str, kind: ComponentExportKind, idx: u32, ty: Option, ) -> u32 { self.exports().export(name, kind, idx, ty); self.inc_kind(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()) } /// 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()) } /// Creates a new instance type within this component. pub fn type_instance(&mut self, ty: &InstanceType) -> u32 { self.types().instance(ty); inc(&mut self.types) } /// Creates a new component type within this component. pub fn type_component(&mut self, ty: &ComponentType) -> u32 { self.types().component(ty); inc(&mut self.types) } /// 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()) } /// Creates a new component function type within this component. pub fn type_function(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) { (inc(&mut self.types), self.types().function()) } /// Declares a new resource type within this component. pub fn type_resource(&mut self, rep: ValType, dtor: Option) -> u32 { self.types().resource(rep, dtor); inc(&mut self.types) } /// Defines a new subcomponent of this component. pub fn component(&mut self, mut builder: ComponentBuilder) -> u32 { builder.flush(); self.flush(); self.component .section(&NestedComponentSection(&builder.component)); inc(&mut self.components) } /// Defines a new subcomponent of this component. pub fn component_raw(&mut self, data: &[u8]) -> u32 { let raw_section = RawSection { id: ComponentSectionId::Component.into(), data, }; self.flush(); self.component.section(&raw_section); inc(&mut self.components) } /// Instantiates the `component_index` specified with the `args` specified. pub fn instantiate(&mut self, component_index: u32, args: A) -> u32 where A: IntoIterator, A::IntoIter: ExactSizeIterator, S: AsRef, { self.component_instances() .instantiate(component_index, args); inc(&mut self.instances) } /// 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) } /// Declares a new `resource.drop` intrinsic. pub fn resource_drop_async(&mut self, ty: u32) -> u32 { self.canonical_functions().resource_drop_async(ty); inc(&mut self.core_funcs) } /// 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) } /// 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) } /// Declares a new `thread.spawn_ref` intrinsic. pub fn thread_spawn_ref(&mut self, ty: u32) -> u32 { self.canonical_functions().thread_spawn_ref(ty); 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(); inc(&mut self.core_funcs) } /// Declares a new `backpressure.set` intrinsic. pub fn backpressure_set(&mut self) -> u32 { self.canonical_functions().backpressure_set(); inc(&mut self.core_funcs) } /// Declares a new `backpressure.inc` intrinsic. pub fn backpressure_inc(&mut self) -> u32 { self.canonical_functions().backpressure_inc(); inc(&mut self.core_funcs) } /// Declares a new `backpressure.dec` intrinsic. pub fn backpressure_dec(&mut self) -> u32 { self.canonical_functions().backpressure_dec(); inc(&mut self.core_funcs) } /// Declares a new `task.return` intrinsic. pub fn task_return(&mut self, ty: Option, options: O) -> u32 where O: IntoIterator, O::IntoIter: ExactSizeIterator, { self.canonical_functions().task_return(ty, options); inc(&mut self.core_funcs) } /// Declares a new `task.cancel` intrinsic. pub fn task_cancel(&mut self) -> u32 { self.canonical_functions().task_cancel(); 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); 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); 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); inc(&mut self.core_funcs) } /// Declares a new `subtask.drop` intrinsic. pub fn subtask_drop(&mut self) -> u32 { self.canonical_functions().subtask_drop(); inc(&mut self.core_funcs) } /// Declares a new `subtask.cancel` intrinsic. pub fn subtask_cancel(&mut self, async_: bool) -> u32 { self.canonical_functions().subtask_cancel(async_); inc(&mut self.core_funcs) } /// 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) } /// Declares a new `stream.read` intrinsic. pub fn stream_read(&mut self, ty: u32, options: O) -> u32 where O: IntoIterator, O::IntoIter: ExactSizeIterator, { self.canonical_functions().stream_read(ty, options); inc(&mut self.core_funcs) } /// Declares a new `stream.write` intrinsic. pub fn stream_write(&mut self, ty: u32, options: O) -> u32 where O: IntoIterator, O::IntoIter: ExactSizeIterator, { self.canonical_functions().stream_write(ty, options); inc(&mut self.core_funcs) } /// 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) } /// 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) } /// Declares a new `stream.drop-readable` intrinsic. pub fn stream_drop_readable(&mut self, ty: u32) -> u32 { self.canonical_functions().stream_drop_readable(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); inc(&mut self.core_funcs) } /// 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) } /// Declares a new `future.read` intrinsic. pub fn future_read(&mut self, ty: u32, options: O) -> u32 where O: IntoIterator, O::IntoIter: ExactSizeIterator, { self.canonical_functions().future_read(ty, options); inc(&mut self.core_funcs) } /// Declares a new `future.write` intrinsic. pub fn future_write(&mut self, ty: u32, options: O) -> u32 where O: IntoIterator, O::IntoIter: ExactSizeIterator, { self.canonical_functions().future_write(ty, options); inc(&mut self.core_funcs) } /// 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) } /// 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) } /// Declares a new `future.drop-readable` intrinsic. pub fn future_drop_readable(&mut self, ty: u32) -> u32 { self.canonical_functions().future_drop_readable(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); inc(&mut self.core_funcs) } /// Declares a new `error-context.new` intrinsic. pub fn error_context_new(&mut self, options: O) -> u32 where O: IntoIterator, O::IntoIter: ExactSizeIterator, { self.canonical_functions().error_context_new(options); inc(&mut self.core_funcs) } /// Declares a new `error-context.debug-message` intrinsic. pub fn error_context_debug_message(&mut self, options: O) -> u32 where O: IntoIterator, O::IntoIter: ExactSizeIterator, { self.canonical_functions() .error_context_debug_message(options); inc(&mut self.core_funcs) } /// 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) } /// Declares a new `waitable-set.new` intrinsic. pub fn waitable_set_new(&mut self) -> u32 { self.canonical_functions().waitable_set_new(); inc(&mut self.core_funcs) } /// 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); inc(&mut self.core_funcs) } /// 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); inc(&mut self.core_funcs) } /// Declares a new `waitable-set.drop` intrinsic. pub fn waitable_set_drop(&mut self) -> u32 { self.canonical_functions().waitable_set_drop(); inc(&mut self.core_funcs) } /// Declares a new `waitable.join` intrinsic. pub fn waitable_join(&mut self) -> u32 { self.canonical_functions().waitable_join(); inc(&mut self.core_funcs) } /// Declares a new `thread.index` intrinsic. pub fn thread_index(&mut self) -> u32 { self.canonical_functions().thread_index(); inc(&mut self.core_funcs) } /// 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); inc(&mut self.core_funcs) } /// Declares a new `thread.switch-to` intrinsic. pub fn thread_switch_to(&mut self, cancellable: bool) -> u32 { self.canonical_functions().thread_switch_to(cancellable); inc(&mut self.core_funcs) } /// Declares a new `thread.suspend` intrinsic. pub fn thread_suspend(&mut self, cancellable: bool) -> u32 { self.canonical_functions().thread_suspend(cancellable); inc(&mut self.core_funcs) } /// Declares a new `thread.resume-later` intrinsic. pub fn thread_resume_later(&mut self) -> u32 { self.canonical_functions().thread_resume_later(); inc(&mut self.core_funcs) } /// Declares a new `thread.yield-to` intrinsic. pub fn thread_yield_to(&mut self, cancellable: bool) -> u32 { self.canonical_functions().thread_yield_to(cancellable); inc(&mut self.core_funcs) } /// Adds a new custom section to this component. pub fn custom_section(&mut self, section: &CustomSection<'_>) { self.flush(); self.component.section(section); } /// Adds a new custom section to this component. pub fn raw_custom_section(&mut self, section: &[u8]) { self.flush(); self.component.section(&RawCustomSection(section)); } } // Helper macro to generate methods on `ComponentBuilder` to get specific // section encoders that automatically flush and write out prior sections as // necessary. macro_rules! section_accessors { ($($method:ident => $section:ident)*) => ( #[derive(Debug, Default)] enum LastSection { #[default] None, $($section($section),)* } impl ComponentBuilder { $( fn $method(&mut self) -> &mut $section { match &self.last_section { // The last encoded section matches the section that's // being requested, so no change is necessary. LastSection::$section(_) => {} // Otherwise the last section didn't match this section, // so flush any prior section if needed and start // encoding the desired section of this method. _ => { self.flush(); self.last_section = LastSection::$section($section::new()); } } match &mut self.last_section { LastSection::$section(ret) => ret, _ => unreachable!() } } )* /// Writes out the last section into the final component binary if /// there is a section specified, otherwise does nothing. fn flush(&mut self) { match mem::take(&mut self.last_section) { LastSection::None => {} $( LastSection::$section(section) => { self.component.section(§ion); } )* } } } ) } section_accessors! { component_instances => ComponentInstanceSection instances => InstanceSection canonical_functions => CanonicalFunctionSection aliases => ComponentAliasSection exports => ComponentExportSection imports => ComponentImportSection types => ComponentTypeSection core_types => CoreTypeSection } fn inc(idx: &mut u32) -> u32 { let ret = *idx; *idx += 1; ret } wasm-encoder-0.239.0/src/component/canonicals.rs000064400000000000000000000453471046102023000176510ustar 00000000000000use crate::{ComponentSection, ComponentSectionId, ComponentValType, Encode, encode_section}; use alloc::vec::Vec; /// Represents options for canonical function definitions. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CanonicalOption { /// The string types in the function signature are UTF-8 encoded. UTF8, /// The string types in the function signature are UTF-16 encoded. UTF16, /// The string types in the function signature are compact UTF-16 encoded. CompactUTF16, /// The memory to use if the lifting or lowering of a function requires memory access. /// /// The value is an index to a core memory. Memory(u32), /// The realloc function to use if the lifting or lowering of a function requires memory /// allocation. /// /// The value is an index to a core function of type `(func (param i32 i32 i32 i32) (result i32))`. Realloc(u32), /// The post-return function to use if the lifting of a function requires /// cleanup after the function returns. PostReturn(u32), /// Indicates that specified function should be lifted or lowered using the `async` ABI. Async, /// 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 { fn encode(&self, sink: &mut Vec) { match self { Self::UTF8 => sink.push(0x00), Self::UTF16 => sink.push(0x01), Self::CompactUTF16 => sink.push(0x02), Self::Memory(idx) => { sink.push(0x03); idx.encode(sink); } Self::Realloc(idx) => { sink.push(0x04); idx.encode(sink); } Self::PostReturn(idx) => { sink.push(0x05); idx.encode(sink); } Self::Async => { sink.push(0x06); } Self::Callback(idx) => { sink.push(0x07); idx.encode(sink); } Self::CoreType(idx) => { sink.push(0x08); idx.encode(sink); } Self::Gc => { sink.push(0x09); } } } } /// An encoder for the canonical function section of WebAssembly components. /// /// # Example /// /// ``` /// use wasm_encoder::{Component, CanonicalFunctionSection, CanonicalOption}; /// /// let mut functions = CanonicalFunctionSection::new(); /// functions.lift(0, 0, [CanonicalOption::UTF8]); /// /// let mut component = Component::new(); /// component.section(&functions); /// /// let bytes = component.finish(); /// ``` #[derive(Clone, Debug, Default)] pub struct CanonicalFunctionSection { bytes: Vec, num_added: u32, } impl CanonicalFunctionSection { /// Construct a new component function section encoder. pub fn new() -> Self { Self::default() } /// The number of functions in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Define a function that will lift a core WebAssembly function to the canonical ABI. pub fn lift(&mut self, core_func_index: u32, type_index: u32, options: O) -> &mut Self where O: IntoIterator, O::IntoIter: ExactSizeIterator, { self.bytes.push(0x00); self.bytes.push(0x00); core_func_index.encode(&mut self.bytes); self.encode_options(options); type_index.encode(&mut self.bytes); self.num_added += 1; self } /// Define a function that will lower a canonical ABI function to a core WebAssembly function. pub fn lower(&mut self, func_index: u32, options: O) -> &mut Self where O: IntoIterator, O::IntoIter: ExactSizeIterator, { self.bytes.push(0x01); self.bytes.push(0x00); func_index.encode(&mut self.bytes); self.encode_options(options); self.num_added += 1; self } /// Defines a function which will create an owned handle to the resource /// specified by `ty_index`. pub fn resource_new(&mut self, ty_index: u32) -> &mut Self { self.bytes.push(0x02); ty_index.encode(&mut self.bytes); self.num_added += 1; self } /// Defines a function which will drop the specified type of handle. pub fn resource_drop(&mut self, ty_index: u32) -> &mut Self { self.bytes.push(0x03); ty_index.encode(&mut self.bytes); self.num_added += 1; 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 { self.bytes.push(0x04); 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 of type `ty_index`. 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_available_parallelism(&mut self) -> &mut Self { self.bytes.push(0x42); self.num_added += 1; self } /// Defines a function which tells the host to enable or disable /// 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 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, options: O) -> &mut Self where O: IntoIterator, O::IntoIter: ExactSizeIterator, { self.bytes.push(0x09); crate::encode_resultlist(&mut self.bytes, ty); self.encode_options(options); self.num_added += 1; 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(0x7f); i.encode(&mut self.bytes); self.num_added += 1; 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(0x7f); i.encode(&mut self.bytes); self.num_added += 1; self } /// Defines a function which yields control to the host so that other tasks /// are able to make progress, if any. /// /// 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 cancellable { 1 } else { 0 }); self.num_added += 1; self } /// Defines a function to drop a specified task which has completed. pub fn subtask_drop(&mut self) -> &mut Self { self.bytes.push(0x0d); self.num_added += 1; 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 { self.bytes.push(0x0e); ty.encode(&mut self.bytes); self.num_added += 1; self } /// Defines a function to read from a `stream` of the specified type. pub fn stream_read(&mut self, ty: u32, options: O) -> &mut Self where O: IntoIterator, O::IntoIter: ExactSizeIterator, { self.bytes.push(0x0f); ty.encode(&mut self.bytes); self.encode_options(options); self.num_added += 1; self } /// Defines a function to write to a `stream` of the specified type. pub fn stream_write(&mut self, ty: u32, options: O) -> &mut Self where O: IntoIterator, O::IntoIter: ExactSizeIterator, { self.bytes.push(0x10); ty.encode(&mut self.bytes); self.encode_options(options); self.num_added += 1; self } /// Defines a function to cancel an in-progress read from a `stream` of the /// specified type. pub fn stream_cancel_read(&mut self, ty: u32, async_: bool) -> &mut Self { self.bytes.push(0x11); ty.encode(&mut self.bytes); self.bytes.push(if async_ { 1 } else { 0 }); self.num_added += 1; self } /// Defines a function to cancel an in-progress write to a `stream` of the /// specified type. pub fn stream_cancel_write(&mut self, ty: u32, async_: bool) -> &mut Self { self.bytes.push(0x12); ty.encode(&mut self.bytes); self.bytes.push(if async_ { 1 } else { 0 }); self.num_added += 1; self } /// Defines a function to drop the readable end of a `stream` of the /// specified type. 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 drop the writable end of a `stream` of the /// specified type. pub fn stream_drop_writable(&mut self, ty: u32) -> &mut Self { self.bytes.push(0x14); ty.encode(&mut self.bytes); self.num_added += 1; self } /// Defines a function to create a new `future` handle of the specified /// type. pub fn future_new(&mut self, ty: u32) -> &mut Self { self.bytes.push(0x15); ty.encode(&mut self.bytes); self.num_added += 1; self } /// Defines a function to read from a `future` of the specified type. pub fn future_read(&mut self, ty: u32, options: O) -> &mut Self where O: IntoIterator, O::IntoIter: ExactSizeIterator, { self.bytes.push(0x16); ty.encode(&mut self.bytes); self.encode_options(options); self.num_added += 1; self } /// Defines a function to write to a `future` of the specified type. pub fn future_write(&mut self, ty: u32, options: O) -> &mut Self where O: IntoIterator, O::IntoIter: ExactSizeIterator, { self.bytes.push(0x17); ty.encode(&mut self.bytes); self.encode_options(options); self.num_added += 1; self } /// Defines a function to cancel an in-progress read from a `future` of the /// specified type. pub fn future_cancel_read(&mut self, ty: u32, async_: bool) -> &mut Self { self.bytes.push(0x18); ty.encode(&mut self.bytes); self.bytes.push(if async_ { 1 } else { 0 }); self.num_added += 1; self } /// Defines a function to cancel an in-progress write to a `future` of the /// specified type. pub fn future_cancel_write(&mut self, ty: u32, async_: bool) -> &mut Self { self.bytes.push(0x19); ty.encode(&mut self.bytes); self.bytes.push(if async_ { 1 } else { 0 }); self.num_added += 1; self } /// Defines a function to drop the readable end of a `future` of the /// specified type. 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 drop the writable end of a `future` of the /// specified type. pub fn future_drop_writable(&mut self, ty: u32) -> &mut Self { self.bytes.push(0x1b); ty.encode(&mut self.bytes); self.num_added += 1; self } /// Defines a function to create a new `error-context` with a specified /// debug message. pub fn error_context_new(&mut self, options: O) -> &mut Self where O: IntoIterator, O::IntoIter: ExactSizeIterator, { self.bytes.push(0x1c); self.encode_options(options); self.num_added += 1; self } /// Defines a function to get the debug message for a specified /// `error-context`. /// /// Note that the debug message might not necessarily match what was passed /// to `error-context.new`. pub fn error_context_debug_message(&mut self, options: O) -> &mut Self where O: IntoIterator, O::IntoIter: ExactSizeIterator, { self.bytes.push(0x1d); self.encode_options(options); self.num_added += 1; self } /// Defines a function to drop a specified `error-context`. pub fn error_context_drop(&mut self) -> &mut Self { self.bytes.push(0x1e); 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(&mut self, options: O) -> &mut Self where O: IntoIterator, 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 { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl ComponentSection for CanonicalFunctionSection { fn id(&self) -> u8 { ComponentSectionId::CanonicalFunction.into() } } wasm-encoder-0.239.0/src/component/components.rs000064400000000000000000000014271046102023000177130ustar 00000000000000use crate::{Component, ComponentSection, ComponentSectionId, Encode}; use alloc::vec::Vec; /// An encoder for the component section of WebAssembly components. /// /// # Example /// /// ```rust /// use wasm_encoder::{Component, NestedComponentSection}; /// /// let mut nested = Component::new(); /// let mut component = Component::new(); /// component.section(&NestedComponentSection(&nested)); /// /// let bytes = component.finish(); /// ``` #[derive(Clone, Debug)] pub struct NestedComponentSection<'a>(pub &'a Component); impl Encode for NestedComponentSection<'_> { fn encode(&self, sink: &mut Vec) { self.0.bytes.encode(sink); } } impl ComponentSection for NestedComponentSection<'_> { fn id(&self) -> u8 { ComponentSectionId::Component.into() } } wasm-encoder-0.239.0/src/component/exports.rs000064400000000000000000000065001046102023000172270ustar 00000000000000use super::{ COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, FUNCTION_SORT, INSTANCE_SORT, TYPE_SORT, VALUE_SORT, }; use crate::{ComponentSection, ComponentSectionId, ComponentTypeRef, Encode, encode_section}; use alloc::vec::Vec; /// Represents the kind of an export from a WebAssembly component. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum ComponentExportKind { /// The export is a core module. Module, /// The export is a function. Func, /// The export is a value. Value, /// The export is a type. Type, /// The export is an instance. Instance, /// The export is a component. Component, } impl Encode for ComponentExportKind { fn encode(&self, sink: &mut Vec) { match self { Self::Module => { sink.push(CORE_SORT); sink.push(CORE_MODULE_SORT); } Self::Func => { sink.push(FUNCTION_SORT); } Self::Value => { sink.push(VALUE_SORT); } Self::Type => { sink.push(TYPE_SORT); } Self::Instance => { sink.push(INSTANCE_SORT); } Self::Component => { sink.push(COMPONENT_SORT); } } } } /// An encoder for the export section of WebAssembly component. /// /// # Example /// /// ```rust /// use wasm_encoder::{Component, ComponentExportSection, ComponentExportKind}; /// /// // This exports a function named "foo" /// let mut exports = ComponentExportSection::new(); /// exports.export("foo", ComponentExportKind::Func, 0, None); /// /// let mut component = Component::new(); /// component.section(&exports); /// /// let bytes = component.finish(); /// ``` #[derive(Clone, Debug, Default)] pub struct ComponentExportSection { bytes: Vec, num_added: u32, } impl ComponentExportSection { /// Create a new component export section encoder. pub fn new() -> Self { Self::default() } /// The number of exports in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Define an export in the export section. pub fn export( &mut self, name: &str, kind: ComponentExportKind, index: u32, ty: Option, ) -> &mut Self { crate::encode_component_export_name(&mut self.bytes, name); kind.encode(&mut self.bytes); index.encode(&mut self.bytes); match ty { Some(ty) => { self.bytes.push(0x01); ty.encode(&mut self.bytes); } None => { self.bytes.push(0x00); } } self.num_added += 1; self } } impl Encode for ComponentExportSection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl ComponentSection for ComponentExportSection { fn id(&self) -> u8 { ComponentSectionId::Export.into() } } /// For more information on this see `encode_component_import_name`. pub(crate) fn encode_component_export_name(bytes: &mut Vec, name: &str) { bytes.push(0x00); name.encode(bytes); } wasm-encoder-0.239.0/src/component/imports.rs000064400000000000000000000120671046102023000172250ustar 00000000000000use crate::{ ComponentExportKind, ComponentSection, ComponentSectionId, ComponentValType, Encode, encode_section, }; use alloc::vec::Vec; /// Represents the possible type bounds for type references. #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub enum TypeBounds { /// The type is bounded by equality to the type index specified. Eq(u32), /// This type is a fresh resource type, SubResource, } impl Encode for TypeBounds { fn encode(&self, sink: &mut Vec) { match self { Self::Eq(i) => { sink.push(0x00); i.encode(sink); } Self::SubResource => sink.push(0x01), } } } /// Represents a reference to a type. #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub enum ComponentTypeRef { /// The reference is to a core module type. /// /// The index is expected to be core type index to a core module type. Module(u32), /// The reference is to a function type. /// /// The index is expected to be a type index to a function type. Func(u32), /// The reference is to a value type. Value(ComponentValType), /// The reference is to a bounded type. Type(TypeBounds), /// The reference is to an instance type. /// /// The index is expected to be a type index to an instance type. Instance(u32), /// The reference is to a component type. /// /// The index is expected to be a type index to a component type. Component(u32), } impl ComponentTypeRef { /// Gets the export kind of the reference. pub fn kind(&self) -> ComponentExportKind { match self { Self::Module(_) => ComponentExportKind::Module, Self::Func(_) => ComponentExportKind::Func, Self::Value(_) => ComponentExportKind::Value, Self::Type(..) => ComponentExportKind::Type, Self::Instance(_) => ComponentExportKind::Instance, Self::Component(_) => ComponentExportKind::Component, } } } impl Encode for ComponentTypeRef { fn encode(&self, sink: &mut Vec) { self.kind().encode(sink); match self { Self::Module(idx) | Self::Func(idx) | Self::Instance(idx) | Self::Component(idx) => { idx.encode(sink); } Self::Value(ty) => ty.encode(sink), Self::Type(bounds) => bounds.encode(sink), } } } /// An encoder for the import section of WebAssembly components. /// /// # Example /// /// ```rust /// use wasm_encoder::{Component, ComponentTypeSection, PrimitiveValType, ComponentImportSection, ComponentTypeRef}; /// /// let mut types = ComponentTypeSection::new(); /// /// // Define a function type of `[string, string] -> string`. /// types /// .function() /// .params( /// [ /// ("a", PrimitiveValType::String), /// ("b", PrimitiveValType::String) /// ] /// ) /// .result(Some(PrimitiveValType::String.into())); /// /// // This imports a function named `f` with the type defined above /// let mut imports = ComponentImportSection::new(); /// imports.import("f", ComponentTypeRef::Func(0)); /// /// let mut component = Component::new(); /// component.section(&types); /// component.section(&imports); /// /// let bytes = component.finish(); /// ``` #[derive(Clone, Debug, Default)] pub struct ComponentImportSection { bytes: Vec, num_added: u32, } impl ComponentImportSection { /// Create a new component import section encoder. pub fn new() -> Self { Self::default() } /// The number of imports in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Define an import in the component import section. pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { encode_component_import_name(&mut self.bytes, name); ty.encode(&mut self.bytes); self.num_added += 1; self } } impl Encode for ComponentImportSection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl ComponentSection for ComponentImportSection { fn id(&self) -> u8 { ComponentSectionId::Import.into() } } /// Prior to WebAssembly/component-model#263 import and export names were /// discriminated with a leading byte indicating what kind of import they are. /// After that PR though names are always prefixed with a 0x00 byte. /// /// On 2023-10-28 in bytecodealliance/wasm-tools#1262 was landed to start /// transitioning to "always lead with 0x00". That updated the validator/parser /// to accept either 0x00 or 0x01 but the encoder wasn't updated at the time. /// /// On 2024-09-03 in bytecodealliance/wasm-tools#TODO this encoder was updated /// to always emit 0x00 as a leading byte. /// /// This function corresponds with the `importname'` production in the /// specification. pub(crate) fn encode_component_import_name(bytes: &mut Vec, name: &str) { bytes.push(0x00); name.encode(bytes); } wasm-encoder-0.239.0/src/component/instances.rs000064400000000000000000000127751046102023000175250ustar 00000000000000use super::CORE_INSTANCE_SORT; use crate::{ ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind, encode_section, }; use alloc::vec::Vec; /// Represents an argument to a module instantiation. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum ModuleArg { /// The argument is an instance. Instance(u32), } impl Encode for ModuleArg { fn encode(&self, sink: &mut Vec) { let (sort, idx) = match self { Self::Instance(idx) => (CORE_INSTANCE_SORT, *idx), }; sink.push(sort); idx.encode(sink); } } /// An encoder for the core instance section of WebAssembly components. /// /// # Example /// /// ```rust /// use wasm_encoder::{Component, InstanceSection, ExportKind, ModuleArg}; /// /// let mut instances = InstanceSection::new(); /// instances.export_items([("foo", ExportKind::Func, 0)]); /// instances.instantiate(1, [("foo", ModuleArg::Instance(0))]); /// /// let mut component = Component::new(); /// component.section(&instances); /// /// let bytes = component.finish(); /// ``` #[derive(Clone, Debug, Default)] pub struct InstanceSection { bytes: Vec, num_added: u32, } impl InstanceSection { /// Create a new core instance section encoder. pub fn new() -> Self { Self::default() } /// The number of instances in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Define an instance by instantiating a core module. pub fn instantiate(&mut self, module_index: u32, args: A) -> &mut Self where A: IntoIterator, A::IntoIter: ExactSizeIterator, S: AsRef, { let args = args.into_iter(); self.bytes.push(0x00); module_index.encode(&mut self.bytes); args.len().encode(&mut self.bytes); for (name, arg) in args { name.as_ref().encode(&mut self.bytes); arg.encode(&mut self.bytes); } self.num_added += 1; self } /// Define an instance by exporting core WebAssembly items. pub fn export_items(&mut self, exports: E) -> &mut Self where E: IntoIterator, E::IntoIter: ExactSizeIterator, S: AsRef, { let exports = exports.into_iter(); self.bytes.push(0x01); exports.len().encode(&mut self.bytes); for (name, kind, index) in exports { name.as_ref().encode(&mut self.bytes); kind.encode(&mut self.bytes); index.encode(&mut self.bytes); } self.num_added += 1; self } } impl Encode for InstanceSection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl ComponentSection for InstanceSection { fn id(&self) -> u8 { ComponentSectionId::CoreInstance.into() } } /// An encoder for the instance section of WebAssembly components. /// /// # Example /// /// ```rust /// use wasm_encoder::{Component, ComponentInstanceSection, ComponentExportKind}; /// /// let mut instances = ComponentInstanceSection::new(); /// instances.export_items([("foo", ComponentExportKind::Func, 0)]); /// instances.instantiate(1, [("foo", ComponentExportKind::Instance, 0)]); /// /// let mut component = Component::new(); /// component.section(&instances); /// /// let bytes = component.finish(); /// ``` #[derive(Clone, Debug, Default)] pub struct ComponentInstanceSection { bytes: Vec, num_added: u32, } impl ComponentInstanceSection { /// Create a new instance section encoder. pub fn new() -> Self { Self::default() } /// The number of instances in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Define an instance by instantiating a component. pub fn instantiate(&mut self, component_index: u32, args: A) -> &mut Self where A: IntoIterator, A::IntoIter: ExactSizeIterator, S: AsRef, { let args = args.into_iter(); self.bytes.push(0x00); component_index.encode(&mut self.bytes); args.len().encode(&mut self.bytes); for (name, kind, index) in args { name.as_ref().encode(&mut self.bytes); kind.encode(&mut self.bytes); index.encode(&mut self.bytes); } self.num_added += 1; self } /// Define an instance by exporting items. pub fn export_items<'a, E>(&mut self, exports: E) -> &mut Self where E: IntoIterator, E::IntoIter: ExactSizeIterator, { let exports = exports.into_iter(); self.bytes.push(0x01); exports.len().encode(&mut self.bytes); for (name, kind, index) in exports { crate::encode_component_export_name(&mut self.bytes, name); kind.encode(&mut self.bytes); index.encode(&mut self.bytes); } self.num_added += 1; self } } impl Encode for ComponentInstanceSection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl ComponentSection for ComponentInstanceSection { fn id(&self) -> u8 { ComponentSectionId::Instance.into() } } wasm-encoder-0.239.0/src/component/modules.rs000064400000000000000000000013471046102023000171770ustar 00000000000000use crate::{ComponentSection, ComponentSectionId, Encode, Module}; use alloc::vec::Vec; /// An encoder for the module section of WebAssembly components. /// /// # Example /// /// ```rust /// use wasm_encoder::{Module, Component, ModuleSection}; /// /// let mut module = Module::new(); /// let mut component = Component::new(); /// component.section(&ModuleSection(&module)); /// /// let bytes = component.finish(); /// ``` #[derive(Clone, Debug)] pub struct ModuleSection<'a>(pub &'a Module); impl Encode for ModuleSection<'_> { fn encode(&self, sink: &mut Vec) { self.0.bytes.encode(sink); } } impl ComponentSection for ModuleSection<'_> { fn id(&self) -> u8 { ComponentSectionId::CoreModule.into() } } wasm-encoder-0.239.0/src/component/names.rs000064400000000000000000000116721046102023000166340ustar 00000000000000use alloc::borrow::Cow; use alloc::vec::Vec; use super::*; use crate::{ExportKind, NameMap, SectionId, encoding_size}; /// Encoding for the `component-name` custom section which assigns /// human-readable names to items within a component. #[derive(Clone, Debug, Default)] pub struct ComponentNameSection { bytes: Vec, } enum Subsection { Component, Decls, } impl ComponentNameSection { /// Creates a new blank `name` custom section. pub fn new() -> Self { Self::default() } /// Appends a component name subsection to this section. /// /// This will indicate that the name of the entire component should be the /// `name` specified. Note that this should be encoded first before other /// subsections. pub fn component(&mut self, name: &str) { let len = encoding_size(u32::try_from(name.len()).unwrap()); self.subsection_header(Subsection::Component, len + name.len()); name.encode(&mut self.bytes); } /// Appends a decls name subsection to name core functions within the /// component. pub fn core_funcs(&mut self, names: &NameMap) { self.core_decls(ExportKind::Func as u8, names) } /// Appends a decls name subsection to name core tables within the /// component. pub fn core_tables(&mut self, names: &NameMap) { self.core_decls(ExportKind::Table as u8, names) } /// Appends a decls name subsection to name core memories within the /// component. pub fn core_memories(&mut self, names: &NameMap) { self.core_decls(ExportKind::Memory as u8, names) } /// Appends a decls name subsection to name core globals within the /// component. pub fn core_globals(&mut self, names: &NameMap) { 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) { self.core_decls(CORE_TYPE_SORT, names) } /// Appends a decls name subsection to name core modules within the /// component. pub fn core_modules(&mut self, names: &NameMap) { self.core_decls(CORE_MODULE_SORT, names) } /// Appends a decls name subsection to name core instances within the /// component. pub fn core_instances(&mut self, names: &NameMap) { self.core_decls(CORE_INSTANCE_SORT, names) } /// Appends a decls name subsection to name component functions within the /// component. pub fn funcs(&mut self, names: &NameMap) { self.component_decls(FUNCTION_SORT, names) } /// Appends a decls name subsection to name component values within the /// component. pub fn values(&mut self, names: &NameMap) { self.component_decls(VALUE_SORT, names) } /// Appends a decls name subsection to name component type within the /// component. pub fn types(&mut self, names: &NameMap) { self.component_decls(TYPE_SORT, names) } /// Appends a decls name subsection to name components within the /// component. pub fn components(&mut self, names: &NameMap) { self.component_decls(COMPONENT_SORT, names) } /// Appends a decls name subsection to name component instances within the /// component. pub fn instances(&mut self, names: &NameMap) { self.component_decls(INSTANCE_SORT, names) } /// Appends a raw subsection with the given id and data. pub fn raw(&mut self, id: u8, data: &[u8]) { self.bytes.push(id); data.encode(&mut self.bytes); } fn component_decls(&mut self, kind: u8, names: &NameMap) { self.subsection_header(Subsection::Decls, 1 + names.size()); self.bytes.push(kind); names.encode(&mut self.bytes); } fn core_decls(&mut self, kind: u8, names: &NameMap) { self.subsection_header(Subsection::Decls, 2 + names.size()); self.bytes.push(CORE_SORT); self.bytes.push(kind); names.encode(&mut self.bytes); } fn subsection_header(&mut self, id: Subsection, len: usize) { self.bytes.push(id as u8); len.encode(&mut self.bytes); } /// Returns whether this section is empty, or nothing has been encoded. pub fn is_empty(&self) -> bool { self.bytes.is_empty() } /// View the encoded section as a CustomSection. pub fn as_custom<'a>(&'a self) -> CustomSection<'a> { CustomSection { name: "component-name".into(), data: Cow::Borrowed(&self.bytes), } } } impl Encode for ComponentNameSection { fn encode(&self, sink: &mut Vec) { self.as_custom().encode(sink); } } impl ComponentSection for ComponentNameSection { fn id(&self) -> u8 { SectionId::Custom.into() } } wasm-encoder-0.239.0/src/component/start.rs000064400000000000000000000025661046102023000166700ustar 00000000000000use crate::{ComponentSection, ComponentSectionId, Encode}; use alloc::vec::Vec; /// An encoder for the start section of WebAssembly components. /// /// # Example /// /// ``` /// use wasm_encoder::{Component, ComponentStartSection}; /// /// let start = ComponentStartSection { function_index: 0, args: [0, 1], results: 1 }; /// /// let mut component = Component::new(); /// component.section(&start); /// /// let bytes = component.finish(); /// ``` #[derive(Clone, Debug)] pub struct ComponentStartSection { /// The index to the start function. pub function_index: u32, /// The arguments to pass to the start function. /// /// An argument is an index to a value. pub args: A, /// The number of expected results for the start function. /// /// This should match the number of results for the type of /// the function referenced by `function_index`. pub results: u32, } impl Encode for ComponentStartSection where A: AsRef<[u32]>, { fn encode(&self, sink: &mut Vec) { let mut bytes = Vec::new(); self.function_index.encode(&mut bytes); self.args.as_ref().encode(&mut bytes); self.results.encode(&mut bytes); bytes.encode(sink); } } impl ComponentSection for ComponentStartSection where A: AsRef<[u32]>, { fn id(&self) -> u8 { ComponentSectionId::Start.into() } } wasm-encoder-0.239.0/src/component/types.rs000064400000000000000000000525671046102023000167050ustar 00000000000000use super::CORE_TYPE_SORT; use crate::{ Alias, ComponentExportKind, ComponentOuterAliasKind, ComponentSection, ComponentSectionId, ComponentTypeRef, CoreTypeEncoder, Encode, EntityType, ValType, encode_section, }; use alloc::vec::Vec; /// Represents the type of a core module. #[derive(Debug, Clone, Default)] pub struct ModuleType { bytes: Vec, num_added: u32, types_added: u32, } impl ModuleType { /// Creates a new core module type. pub fn new() -> Self { Self::default() } /// Defines an import in this module type. pub fn import(&mut self, module: &str, name: &str, ty: EntityType) -> &mut Self { self.bytes.push(0x00); module.encode(&mut self.bytes); name.encode(&mut self.bytes); ty.encode(&mut self.bytes); self.num_added += 1; self } /// Define a type in this module type. /// /// 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<'_> { self.bytes.push(0x01); self.num_added += 1; self.types_added += 1; CoreTypeEncoder { push_prefix_if_component_core_type: false, bytes: &mut self.bytes, } } /// Defines an outer core type alias in this module type. pub fn alias_outer_core_type(&mut self, count: u32, index: u32) -> &mut Self { self.bytes.push(0x02); self.bytes.push(CORE_TYPE_SORT); self.bytes.push(0x01); // outer count.encode(&mut self.bytes); index.encode(&mut self.bytes); self.num_added += 1; self.types_added += 1; self } /// Defines an export in this module type. pub fn export(&mut self, name: &str, ty: EntityType) -> &mut Self { self.bytes.push(0x03); name.encode(&mut self.bytes); ty.encode(&mut self.bytes); self.num_added += 1; self } /// Gets the number of types that have been added to this module type. pub fn type_count(&self) -> u32 { self.types_added } } impl Encode for ModuleType { fn encode(&self, sink: &mut Vec) { sink.push(0x50); self.num_added.encode(sink); sink.extend(&self.bytes); } } /// Used to encode core types. #[derive(Debug)] pub struct ComponentCoreTypeEncoder<'a>(pub(crate) &'a mut Vec); impl<'a> ComponentCoreTypeEncoder<'a> { /// Define a module type. pub fn module(self, ty: &ModuleType) { ty.encode(self.0); } /// Define any core type other than a module type. #[must_use = "the encoder must be used to encode the type"] pub fn core(self) -> CoreTypeEncoder<'a> { CoreTypeEncoder { bytes: self.0, push_prefix_if_component_core_type: true, } } } /// An encoder for the core type section of WebAssembly components. /// /// # Example /// /// ```rust /// use wasm_encoder::{Component, CoreTypeSection, ModuleType}; /// /// let mut types = CoreTypeSection::new(); /// /// types.ty().module(&ModuleType::new()); /// /// let mut component = Component::new(); /// component.section(&types); /// /// let bytes = component.finish(); /// ``` #[derive(Clone, Debug, Default)] pub struct CoreTypeSection { bytes: Vec, num_added: u32, } impl CoreTypeSection { /// Create a new core type section encoder. pub fn new() -> Self { Self::default() } /// The number of types in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Encode a type into this section. /// /// The returned encoder must be finished before adding another type. #[must_use = "the encoder must be used to encode the type"] pub fn ty(&mut self) -> ComponentCoreTypeEncoder<'_> { self.num_added += 1; ComponentCoreTypeEncoder(&mut self.bytes) } } impl Encode for CoreTypeSection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl ComponentSection for CoreTypeSection { fn id(&self) -> u8 { ComponentSectionId::CoreType.into() } } /// Represents a component type. #[derive(Debug, Clone, Default)] pub struct ComponentType { bytes: Vec, num_added: u32, core_types_added: u32, types_added: u32, instances_added: u32, } impl ComponentType { /// Creates a new component type. pub fn new() -> Self { Self::default() } /// Define a core type in this component type. /// /// 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<'_> { self.bytes.push(0x00); self.num_added += 1; self.core_types_added += 1; ComponentCoreTypeEncoder(&mut self.bytes) } /// Define a type in this component type. /// /// 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<'_> { self.bytes.push(0x01); self.num_added += 1; self.types_added += 1; ComponentTypeEncoder(&mut self.bytes) } /// Defines an alias for an exported item of a prior instance or an /// outer type. pub fn alias(&mut self, alias: Alias<'_>) -> &mut Self { self.bytes.push(0x02); alias.encode(&mut self.bytes); self.num_added += 1; match &alias { Alias::InstanceExport { kind: ComponentExportKind::Type, .. } | Alias::Outer { kind: ComponentOuterAliasKind::Type, .. } => self.types_added += 1, Alias::Outer { kind: ComponentOuterAliasKind::CoreType, .. } => self.core_types_added += 1, Alias::InstanceExport { kind: ComponentExportKind::Instance, .. } => self.instances_added += 1, _ => {} } self } /// Defines an import in this component type. pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { self.bytes.push(0x03); crate::encode_component_import_name(&mut self.bytes, name); ty.encode(&mut self.bytes); self.num_added += 1; match ty { ComponentTypeRef::Type(..) => self.types_added += 1, ComponentTypeRef::Instance(..) => self.instances_added += 1, _ => {} } self } /// Defines an export in this component type. pub fn export(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { self.bytes.push(0x04); crate::encode_component_export_name(&mut self.bytes, name); ty.encode(&mut self.bytes); self.num_added += 1; match ty { ComponentTypeRef::Type(..) => self.types_added += 1, ComponentTypeRef::Instance(..) => self.instances_added += 1, _ => {} } self } /// Gets the number of core types that have been added to this component type. pub fn core_type_count(&self) -> u32 { self.core_types_added } /// Gets the number of types that have been added or aliased in this component type. pub fn type_count(&self) -> u32 { self.types_added } /// Gets the number of instances that have been defined in this component /// type through imports, exports, or aliases. pub fn instance_count(&self) -> u32 { self.instances_added } } impl Encode for ComponentType { fn encode(&self, sink: &mut Vec) { sink.push(0x41); self.num_added.encode(sink); sink.extend(&self.bytes); } } /// Represents an instance type. #[derive(Debug, Clone, Default)] pub struct InstanceType(ComponentType); impl InstanceType { /// Creates a new instance type. pub fn new() -> Self { Self::default() } /// Define a core type in this instance type. /// /// 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<'_> { self.0.core_type() } /// Define a type in this instance type. /// /// 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<'_> { self.0.ty() } /// Defines an outer core type alias in this component type. pub fn alias(&mut self, alias: Alias<'_>) -> &mut Self { self.0.alias(alias); self } /// Defines an export in this instance type. pub fn export(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { self.0.export(name, ty); self } /// Gets the number of core types that have been added to this instance type. pub fn core_type_count(&self) -> u32 { self.0.core_types_added } /// Gets the number of types that have been added or aliased in this instance type. pub fn type_count(&self) -> u32 { self.0.types_added } /// Gets the number of instances that have been imported or exported or /// aliased in this instance type. pub fn instance_count(&self) -> u32 { self.0.instances_added } /// Returns whether or not this instance type is empty. pub fn is_empty(&self) -> bool { self.0.num_added == 0 } /// Returns the number of entries added to this instance types. pub fn len(&self) -> u32 { self.0.num_added } } impl Encode for InstanceType { fn encode(&self, sink: &mut Vec) { sink.push(0x42); self.0.num_added.encode(sink); sink.extend(&self.0.bytes); } } /// Used to encode component function types. #[derive(Debug)] pub struct ComponentFuncTypeEncoder<'a> { params_encoded: bool, results_encoded: bool, sink: &'a mut Vec, } impl<'a> ComponentFuncTypeEncoder<'a> { fn new(sink: &'a mut Vec) -> Self { sink.push(0x40); Self { params_encoded: false, results_encoded: false, sink, } } /// Defines named parameters. /// /// Parameters must be defined before defining results. /// /// # Panics /// /// This method will panic if the function is called twice since parameters /// can only be encoded once. pub fn params<'b, P, T>(&mut self, params: P) -> &mut Self where P: IntoIterator, P::IntoIter: ExactSizeIterator, T: Into, { assert!(!self.params_encoded); self.params_encoded = true; let params = params.into_iter(); params.len().encode(self.sink); for (name, ty) in params { name.encode(self.sink); ty.into().encode(self.sink); } self } /// Defines a single unnamed result. /// /// This method cannot be used with `results`. /// /// # Panics /// /// 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: Option) -> &mut Self { assert!(self.params_encoded); assert!(!self.results_encoded); self.results_encoded = true; encode_resultlist(self.sink, ty); self } } pub(crate) fn encode_resultlist(sink: &mut Vec, ty: Option) { match ty { Some(ty) => { sink.push(0x00); ty.encode(sink); } None => { sink.push(0x01); sink.push(0x00); } } } /// Used to encode component and instance types. #[derive(Debug)] pub struct ComponentTypeEncoder<'a>(&'a mut Vec); impl<'a> ComponentTypeEncoder<'a> { /// Define a component type. pub fn component(self, ty: &ComponentType) { ty.encode(self.0); } /// Define an instance type. pub fn instance(self, ty: &InstanceType) { ty.encode(self.0); } /// Define a function type. pub fn function(self) -> ComponentFuncTypeEncoder<'a> { ComponentFuncTypeEncoder::new(self.0) } /// Define a defined component type. /// /// The returned encoder must be used before adding another type. #[must_use = "the encoder must be used to encode the type"] pub fn defined_type(self) -> ComponentDefinedTypeEncoder<'a> { ComponentDefinedTypeEncoder(self.0) } /// Define a resource type. pub fn resource(self, rep: ValType, dtor: Option) { self.0.push(0x3f); rep.encode(self.0); match dtor { Some(i) => { self.0.push(0x01); i.encode(self.0); } None => self.0.push(0x00), } } } /// Represents a primitive component value type. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum PrimitiveValType { /// The type is a boolean. Bool, /// The type is a signed 8-bit integer. S8, /// The type is an unsigned 8-bit integer. U8, /// The type is a signed 16-bit integer. S16, /// The type is an unsigned 16-bit integer. U16, /// The type is a signed 32-bit integer. S32, /// The type is an unsigned 32-bit integer. U32, /// The type is a signed 64-bit integer. S64, /// The type is an unsigned 64-bit integer. U64, /// The type is a 32-bit floating point number with only one NaN. F32, /// The type is a 64-bit floating point number with only one NaN. F64, /// The type is a Unicode character. Char, /// The type is a string. String, /// Type for `error-context` added with async support in the component model. ErrorContext, } impl Encode for PrimitiveValType { fn encode(&self, sink: &mut Vec) { sink.push(match self { Self::Bool => 0x7f, Self::S8 => 0x7e, Self::U8 => 0x7d, Self::S16 => 0x7c, Self::U16 => 0x7b, Self::S32 => 0x7a, Self::U32 => 0x79, Self::S64 => 0x78, Self::U64 => 0x77, Self::F32 => 0x76, Self::F64 => 0x75, Self::Char => 0x74, Self::String => 0x73, Self::ErrorContext => 0x64, }); } } /// Represents a component value type. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ComponentValType { /// The value is a primitive type. Primitive(PrimitiveValType), /// The value is to a defined value type. /// /// The type index must be to a value type. Type(u32), } impl Encode for ComponentValType { fn encode(&self, sink: &mut Vec) { match self { Self::Primitive(ty) => ty.encode(sink), Self::Type(index) => (*index as i64).encode(sink), } } } impl From for ComponentValType { fn from(ty: PrimitiveValType) -> Self { Self::Primitive(ty) } } /// Used for encoding component defined types. #[derive(Debug)] pub struct ComponentDefinedTypeEncoder<'a>(&'a mut Vec); impl ComponentDefinedTypeEncoder<'_> { /// Define a primitive value type. pub fn primitive(self, ty: PrimitiveValType) { ty.encode(self.0); } /// Define a record type. pub fn record<'a, F, T>(self, fields: F) where F: IntoIterator, F::IntoIter: ExactSizeIterator, T: Into, { let fields = fields.into_iter(); self.0.push(0x72); fields.len().encode(self.0); for (name, ty) in fields { name.encode(self.0); ty.into().encode(self.0); } } /// Define a variant type. pub fn variant<'a, C>(self, cases: C) where C: IntoIterator, Option)>, C::IntoIter: ExactSizeIterator, { let cases = cases.into_iter(); self.0.push(0x71); cases.len().encode(self.0); for (name, ty, refines) in cases { name.encode(self.0); ty.encode(self.0); refines.encode(self.0); } } /// Define a list type. pub fn list(self, ty: impl Into) { self.0.push(0x70); ty.into().encode(self.0); } /// Define a fixed size list type. pub fn fixed_size_list(self, ty: impl Into, elements: u32) { self.0.push(0x67); ty.into().encode(self.0); elements.encode(self.0); } /// Define a tuple type. pub fn tuple(self, types: I) where I: IntoIterator, I::IntoIter: ExactSizeIterator, T: Into, { let types = types.into_iter(); self.0.push(0x6F); types.len().encode(self.0); for ty in types { ty.into().encode(self.0); } } /// Define a flags type. pub fn flags<'a, I>(self, names: I) where I: IntoIterator, I::IntoIter: ExactSizeIterator, { let names = names.into_iter(); self.0.push(0x6E); names.len().encode(self.0); for name in names { name.encode(self.0); } } /// Define an enum type. pub fn enum_type<'a, I>(self, tags: I) where I: IntoIterator, I::IntoIter: ExactSizeIterator, { let tags = tags.into_iter(); self.0.push(0x6D); tags.len().encode(self.0); for tag in tags { tag.encode(self.0); } } /// Define an option type. pub fn option(self, ty: impl Into) { self.0.push(0x6B); ty.into().encode(self.0); } /// Define a result type. pub fn result(self, ok: Option, err: Option) { self.0.push(0x6A); ok.encode(self.0); err.encode(self.0); } /// Define a `own` handle type pub fn own(self, idx: u32) { self.0.push(0x69); idx.encode(self.0); } /// Define a `borrow` handle type pub fn borrow(self, idx: u32) { self.0.push(0x68); idx.encode(self.0); } /// Define a `future` type with the specified payload. pub fn future(self, payload: Option) { self.0.push(0x65); payload.encode(self.0); } /// Define a `stream` type with the specified payload. pub fn stream(self, payload: Option) { self.0.push(0x66); payload.encode(self.0); } } /// An encoder for the type section of WebAssembly components. /// /// # Example /// /// ```rust /// use wasm_encoder::{Component, ComponentTypeSection, PrimitiveValType}; /// /// let mut types = ComponentTypeSection::new(); /// /// // Define a function type of `[string, string] -> string`. /// types /// .function() /// .params( /// [ /// ("a", PrimitiveValType::String), /// ("b", PrimitiveValType::String) /// ] /// ) /// .result(Some(PrimitiveValType::String.into())); /// /// let mut component = Component::new(); /// component.section(&types); /// /// let bytes = component.finish(); /// ``` #[derive(Clone, Debug, Default)] pub struct ComponentTypeSection { bytes: Vec, num_added: u32, } impl ComponentTypeSection { /// Create a new component type section encoder. pub fn new() -> Self { Self::default() } /// The number of types in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Encode a type into this section. /// /// The returned encoder must be finished before adding another type. #[must_use = "the encoder must be used to encode the type"] pub fn ty(&mut self) -> ComponentTypeEncoder<'_> { self.num_added += 1; ComponentTypeEncoder(&mut self.bytes) } /// Define a component type in this type section. pub fn component(&mut self, ty: &ComponentType) -> &mut Self { self.ty().component(ty); self } /// Define an instance type in this type section. pub fn instance(&mut self, ty: &InstanceType) -> &mut Self { self.ty().instance(ty); self } /// Define a function type in this type section. pub fn function(&mut self) -> ComponentFuncTypeEncoder<'_> { self.ty().function() } /// Add a component defined type to this type section. /// /// The returned encoder must be used before adding another type. #[must_use = "the encoder must be used to encode the type"] pub fn defined_type(&mut self) -> ComponentDefinedTypeEncoder<'_> { self.ty().defined_type() } /// Defines a new resource type. pub fn resource(&mut self, rep: ValType, dtor: Option) -> &mut Self { self.ty().resource(rep, dtor); self } } impl Encode for ComponentTypeSection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl ComponentSection for ComponentTypeSection { fn id(&self) -> u8 { ComponentSectionId::Type.into() } } wasm-encoder-0.239.0/src/component.rs000064400000000000000000000103051046102023000155210ustar 00000000000000mod aliases; mod builder; mod canonicals; mod components; mod exports; mod imports; mod instances; mod modules; mod names; mod start; mod types; pub use self::aliases::*; pub use self::builder::*; pub use self::canonicals::*; pub use self::components::*; pub use self::exports::*; pub use self::imports::*; pub use self::instances::*; pub use self::modules::*; pub use self::names::*; pub use self::start::*; pub use self::types::*; use crate::{CustomSection, Encode, ProducersSection, RawCustomSection}; use alloc::vec::Vec; // Core sorts extended by the component model const CORE_TYPE_SORT: u8 = 0x10; const CORE_MODULE_SORT: u8 = 0x11; const CORE_INSTANCE_SORT: u8 = 0x12; const CORE_SORT: u8 = 0x00; const FUNCTION_SORT: u8 = 0x01; const VALUE_SORT: u8 = 0x02; const TYPE_SORT: u8 = 0x03; const COMPONENT_SORT: u8 = 0x04; const INSTANCE_SORT: u8 = 0x05; /// A WebAssembly component section. /// /// Various builders defined in this crate already implement this trait, but you /// can also implement it yourself for your own custom section builders, or use /// `RawSection` to use a bunch of raw bytes as a section. pub trait ComponentSection: Encode { /// Gets the section identifier for this section. fn id(&self) -> u8; /// Appends this section to the specified destination list of bytes. fn append_to_component(&self, dst: &mut Vec) { dst.push(self.id()); self.encode(dst); } } /// Known section identifiers of WebAssembly components. /// /// These sections are supported by the component model proposal. #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] #[repr(u8)] pub enum ComponentSectionId { /// The section is a core custom section. CoreCustom = 0, /// The section is a core module section. CoreModule = 1, /// The section is a core instance section. CoreInstance = 2, /// The section is a core type section. CoreType = 3, /// The section is a component section. Component = 4, /// The section is an instance section. Instance = 5, /// The section is an alias section. Alias = 6, /// The section is a type section. Type = 7, /// The section is a canonical function section. CanonicalFunction = 8, /// The section is a start section. Start = 9, /// The section is an import section. Import = 10, /// The section is an export section. Export = 11, } impl From for u8 { #[inline] fn from(id: ComponentSectionId) -> u8 { id as u8 } } impl Encode for ComponentSectionId { fn encode(&self, sink: &mut Vec) { sink.push(*self as u8); } } /// Represents a WebAssembly component that is being encoded. /// /// Unlike core WebAssembly modules, the sections of a component /// may appear in any order and may be repeated. /// /// Components may also added as a section to other components. #[derive(Clone, Debug)] pub struct Component { bytes: Vec, } impl Component { /// The 8-byte header at the beginning of all components. #[rustfmt::skip] pub const HEADER: [u8; 8] = [ // Magic 0x00, 0x61, 0x73, 0x6D, // Version 0x0d, 0x00, 0x01, 0x00, ]; /// Begin writing a new `Component`. pub fn new() -> Self { Self { bytes: Self::HEADER.to_vec(), } } /// Finish writing this component and extract ownership of the encoded bytes. pub fn finish(self) -> Vec { self.bytes } /// Write a section to this component. pub fn section(&mut self, section: &impl ComponentSection) -> &mut Self { self.bytes.push(section.id()); section.encode(&mut self.bytes); self } /// View the encoded bytes. pub fn as_slice(&self) -> &[u8] { &self.bytes } } impl Default for Component { fn default() -> Self { Self::new() } } impl ComponentSection for CustomSection<'_> { fn id(&self) -> u8 { ComponentSectionId::CoreCustom.into() } } impl ComponentSection for RawCustomSection<'_> { fn id(&self) -> u8 { ComponentSectionId::CoreCustom.into() } } impl ComponentSection for ProducersSection { fn id(&self) -> u8 { ComponentSectionId::CoreCustom.into() } } wasm-encoder-0.239.0/src/core/branch_hints.rs000064400000000000000000000063751046102023000171250ustar 00000000000000use crate::{CustomSection, Encode, Section, SectionId}; use alloc::borrow::Cow; use alloc::vec::Vec; /// Helper structure to encode the `metadata.code.branch_hint` custom section. /// /// This section was defined in the branch-hinting proposal for WebAssembly: /// . /// /// # Example /// /// ``` /// use wasm_encoder::*; /// /// 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([]); /// /// body.instructions().i32_const(1); /// let if_offset = body.byte_len(); /// body.instructions() /// .if_(BlockType::Empty) /// .end() /// .end(); /// code.function(&body); /// /// let mut hints = BranchHints::new(); /// hints.function_hints(0, [BranchHint { /// branch_func_offset: if_offset as u32, /// branch_hint_value: 1, // taken /// }]); /// module.section(&hints); /// module.section(&code); /// /// let wasm = module.finish(); /// let wat = wasmprinter::print_bytes(&wasm).unwrap(); /// assert_eq!(wat, r#"(module /// (type (;0;) (func)) /// (func (;0;) (type 0) /// i32.const 1 /// (@metadata.code.branch_hint "\01") /// if ;; label = @1 /// end /// ) /// ) /// "#); /// /// ``` #[derive(Default, Debug)] pub struct BranchHints { bytes: Vec, num_hints: u32, } /// A single branch hint within a function. #[derive(Debug, Clone, Copy)] pub struct BranchHint { /// The offset, in bytes from the beginning of the function, to the `if` /// instruction that this is hinting. pub branch_func_offset: u32, /// The value of the hint, 0 for not taken and 1 for taken. pub branch_hint_value: u32, } impl BranchHints { /// Construct an empty encoder for the branch hints custom section. pub fn new() -> Self { Self::default() } /// Adds a new set of function hints for the `func` specified. pub fn function_hints(&mut self, func: u32, hints: I) where I: IntoIterator, I::IntoIter: ExactSizeIterator, { self.num_hints += 1; func.encode(&mut self.bytes); let hints = hints.into_iter(); hints.len().encode(&mut self.bytes); for hint in hints { hint.branch_func_offset.encode(&mut self.bytes); 1u32.encode(&mut self.bytes); hint.branch_hint_value.encode(&mut self.bytes); } } /// Returns if this is an empty section. pub fn is_empty(&self) -> bool { self.num_hints == 0 } /// Returns the number of functions that have hints registered in this /// sectino. pub fn len(&self) -> u32 { self.num_hints } } impl Encode for BranchHints { fn encode(&self, sink: &mut Vec) { let mut data = Vec::new(); self.num_hints.encode(&mut data); data.extend(&self.bytes); CustomSection { name: "metadata.code.branch_hint".into(), data: Cow::Borrowed(&data), } .encode(sink); } } impl Section for BranchHints { fn id(&self) -> u8 { SectionId::Custom.into() } } wasm-encoder-0.239.0/src/core/code.rs000064400000000000000000002527201046102023000153720ustar 00000000000000use crate::{ Encode, HeapType, InstructionSink, RefType, Section, SectionId, ValType, encode_section, }; use alloc::borrow::Cow; use alloc::vec; use alloc::vec::Vec; /// An encoder for the code section. /// /// Code sections are only supported for modules. /// /// # Example /// /// ``` /// use wasm_encoder::{ /// CodeSection, Function, FunctionSection, Module, /// TypeSection, ValType /// }; /// /// let mut types = TypeSection::new(); /// types.ty().function(vec![], vec![ValType::I32]); /// /// let mut functions = FunctionSection::new(); /// let type_index = 0; /// functions.function(type_index); /// /// let locals = vec![]; /// let mut func = Function::new(locals); /// func.instructions().i32_const(42); /// let mut code = CodeSection::new(); /// code.function(&func); /// /// let mut module = Module::new(); /// module /// .section(&types) /// .section(&functions) /// .section(&code); /// /// let wasm_bytes = module.finish(); /// ``` #[derive(Clone, Default, Debug)] pub struct CodeSection { bytes: Vec, num_added: u32, } impl CodeSection { /// Create a new code section encoder. pub fn new() -> Self { Self::default() } /// The number of functions in the section. pub fn len(&self) -> u32 { self.num_added } /// The number of bytes already added to this section. /// /// This number doesn't include the vector length that precedes the /// code entries, since it has a variable size that isn't known until all /// functions are added. pub fn byte_len(&self) -> usize { self.bytes.len() } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Write a function body into this code section. pub fn function(&mut self, func: &Function) -> &mut Self { func.encode(&mut self.bytes); self.num_added += 1; self } /// Add a raw byte slice into this code section as a function body. /// /// The length prefix of the function body will be automatically prepended, /// and should not be included in the raw byte slice. /// /// # Example /// /// You can use the `raw` method to copy an already-encoded function body /// into a new code section encoder: /// /// ``` /// # use wasmparser::{BinaryReader, CodeSectionReader}; /// // id, size, # entries, entry /// let code_section = [10, 6, 1, 4, 0, 65, 0, 11]; /// /// // Parse the code section. /// let reader = BinaryReader::new(&code_section, 0); /// let reader = CodeSectionReader::new(reader).unwrap(); /// let body = reader.into_iter().next().unwrap().unwrap(); /// let body_range = body.range(); /// /// // Add the body to a new code section encoder by copying bytes rather /// // than re-parsing and re-encoding it. /// let mut encoder = wasm_encoder::CodeSection::new(); /// encoder.raw(&code_section[body_range.start..body_range.end]); /// ``` pub fn raw(&mut self, data: &[u8]) -> &mut Self { data.encode(&mut self.bytes); self.num_added += 1; self } } impl Encode for CodeSection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl Section for CodeSection { fn id(&self) -> u8 { SectionId::Code.into() } } /// An encoder for a function body within the code section. /// /// # Example /// /// ``` /// use wasm_encoder::{CodeSection, Function}; /// /// // Define the function body for: /// // /// // (func (param i32 i32) (result i32) /// // local.get 0 /// // local.get 1 /// // i32.add) /// let locals = vec![]; /// let mut func = Function::new(locals); /// func.instructions() /// .local_get(0) /// .local_get(1) /// .i32_add(); /// /// // Add our function to the code section. /// let mut code = CodeSection::new(); /// code.function(&func); /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Function { bytes: Vec, } impl Function { /// Create a new function body with the given locals. /// /// The argument is an iterator over `(N, Ty)`, which defines /// that the next `N` locals will be of type `Ty`. /// /// For example, a function with locals 0 and 1 of type I32 and /// local 2 of type F32 would be created as: /// /// ``` /// # use wasm_encoder::{Function, ValType}; /// let f = Function::new([(2, ValType::I32), (1, ValType::F32)]); /// ``` /// /// For more information about the code section (and function definition) in the WASM binary format /// see the [WebAssembly spec](https://webassembly.github.io/spec/core/binary/modules.html#binary-func) pub fn new(locals: L) -> Self where L: IntoIterator, L::IntoIter: ExactSizeIterator, { let locals = locals.into_iter(); let mut bytes = vec![]; locals.len().encode(&mut bytes); for (count, ty) in locals { count.encode(&mut bytes); ty.encode(&mut bytes); } Function { bytes } } /// Create a function from a list of locals' types. /// /// Unlike [`Function::new`], this constructor simply takes a list of types /// which are in order associated with locals. /// /// For example: /// /// ``` /// # use wasm_encoder::{Function, ValType}; /// let f = Function::new([(2, ValType::I32), (1, ValType::F32)]); /// let g = Function::new_with_locals_types([ /// ValType::I32, ValType::I32, ValType::F32 /// ]); /// /// assert_eq!(f, g) /// ``` pub fn new_with_locals_types(locals: L) -> Self where L: IntoIterator, { let locals = locals.into_iter(); let mut locals_collected: Vec<(u32, ValType)> = vec![]; for l in locals { if let Some((last_count, last_type)) = locals_collected.last_mut() { if l == *last_type { // Increment the count of consecutive locals of this type *last_count += 1; continue; } } // If we didn't increment, a new type of local appeared locals_collected.push((1, l)); } 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); self } /// Add raw bytes to this function's body. pub fn raw(&mut self, bytes: B) -> &mut Self where B: IntoIterator, { self.bytes.extend(bytes); self } /// The number of bytes already added to this function. /// /// This number doesn't include the variable-width size field that `encode` /// will write before the added bytes, since the size of that field isn't /// known until all the instructions are added to this function. pub fn byte_len(&self) -> usize { self.bytes.len() } /// Unwraps and returns the raw byte encoding of this function. /// /// This encoding doesn't include the variable-width size field /// that `encode` will write before the added bytes. As such, its /// length will match the return value of [`Function::byte_len`]. /// /// # Use Case /// /// This raw byte form is suitable for later using with /// [`CodeSection::raw`]. Note that it *differs* from what results /// from [`Function::encode`] precisely due to the *lack* of the /// length prefix; [`CodeSection::raw`] will use this. Using /// [`Function::encode`] instead produces bytes that cannot be fed /// into other wasm-encoder types without stripping off the length /// prefix, which is awkward and error-prone. /// /// This method combined with [`CodeSection::raw`] may be useful /// together if one wants to save the result of function encoding /// and use it later: for example, caching the result of some code /// generation process. /// /// For example: /// /// ``` /// # use wasm_encoder::{CodeSection, Function}; /// let mut f = Function::new([]); /// f.instructions().end(); /// let bytes = f.into_raw_body(); /// // (save `bytes` somewhere for later use) /// let mut code = CodeSection::new(); /// code.raw(&bytes[..]); /// /// assert_eq!(2, bytes.len()); // Locals count, then `end` /// assert_eq!(3, code.byte_len()); // Function length byte, function body /// ``` pub fn into_raw_body(self) -> Vec { self.bytes } } impl Encode for Function { fn encode(&self, sink: &mut Vec) { self.bytes.encode(sink); } } /// 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 for Ieee32 { fn from(value: f32) -> Self { Ieee32(u32::from_le_bytes(value.to_le_bytes())) } } impl From for f32 { fn from(bits: Ieee32) -> f32 { f32::from_bits(bits.bits()) } } impl Encode for Ieee32 { fn encode(&self, sink: &mut Vec) { 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 for Ieee64 { fn from(value: f64) -> Self { Ieee64(u64::from_le_bytes(value.to_le_bytes())) } } impl From for f64 { fn from(bits: Ieee64) -> f64 { f64::from_bits(bits.bits()) } } impl Encode for Ieee64 { fn encode(&self, sink: &mut Vec) { let bits = self.bits(); sink.extend(bits.to_le_bytes()) } } /// The immediate for a memory instruction. #[derive(Clone, Copy, Debug)] pub struct MemArg { /// A static offset to add to the instruction's dynamic address operand. /// /// This is a `u64` field for the memory64 proposal, but 32-bit memories /// limit offsets to at most `u32::MAX` bytes. This will be encoded as a LEB /// but it won't generate a valid module if an offset is specified which is /// larger than the maximum size of the index space for the memory indicated /// by `memory_index`. pub offset: u64, /// The expected alignment of the instruction's dynamic address operand /// (expressed the exponent of a power of two). pub align: u32, /// The index of the memory this instruction is operating upon. pub memory_index: u32, } impl Encode for MemArg { fn encode(&self, sink: &mut Vec) { if self.memory_index == 0 { self.align.encode(sink); self.offset.encode(sink); } else { (self.align | (1 << 6)).encode(sink); self.memory_index.encode(sink); self.offset.encode(sink); } } } /// The memory ordering for atomic instructions. /// /// For an in-depth explanation of memory orderings, see the C++ documentation /// for [`memory_order`] or the Rust documentation for [`atomic::Ordering`]. /// /// [`memory_order`]: https://en.cppreference.com/w/cpp/atomic/memory_order /// [`atomic::Ordering`]: https://doc.rust-lang.org/std/sync/atomic/enum.Ordering.html #[derive(Clone, Copy, Debug)] pub enum Ordering { /// For a load, it acquires; this orders all operations before the last /// "releasing" store. For a store, it releases; this orders all operations /// before it at the next "acquiring" load. AcqRel, /// Like `AcqRel` but all threads see all sequentially consistent operations /// in the same order. SeqCst, } impl Encode for Ordering { fn encode(&self, sink: &mut Vec) { let flag: u8 = match self { Ordering::SeqCst => 0, Ordering::AcqRel => 1, }; sink.push(flag); } } /// Describe an unchecked SIMD lane index. pub type Lane = u8; /// The type for a `block`/`if`/`loop`. #[derive(Clone, Copy, Debug)] pub enum BlockType { /// `[] -> []` Empty, /// `[] -> [t]` Result(ValType), /// The `n`th function type. FunctionType(u32), } impl Encode for BlockType { fn encode(&self, sink: &mut Vec) { match *self { Self::Empty => sink.push(0x40), Self::Result(ty) => ty.encode(sink), Self::FunctionType(f) => (f as i64).encode(sink), } } } /// WebAssembly instructions. #[derive(Clone, Debug)] #[non_exhaustive] #[allow(missing_docs, non_camel_case_types)] pub enum Instruction<'a> { // Control instructions. Unreachable, Nop, Block(BlockType), Loop(BlockType), If(BlockType), Else, End, Br(u32), BrIf(u32), BrTable(Cow<'a, [u32]>, u32), BrOnNull(u32), BrOnNonNull(u32), Return, Call(u32), CallRef(u32), CallIndirect { type_index: u32, table_index: u32, }, ReturnCallRef(u32), ReturnCall(u32), ReturnCallIndirect { type_index: u32, table_index: u32, }, TryTable(BlockType, Cow<'a, [Catch]>), Throw(u32), ThrowRef, // Deprecated exception-handling instructions Try(BlockType), Delegate(u32), Catch(u32), CatchAll, Rethrow(u32), // Parametric instructions. Drop, Select, // Variable instructions. LocalGet(u32), LocalSet(u32), LocalTee(u32), GlobalGet(u32), GlobalSet(u32), // Memory instructions. I32Load(MemArg), I64Load(MemArg), F32Load(MemArg), F64Load(MemArg), I32Load8S(MemArg), I32Load8U(MemArg), I32Load16S(MemArg), I32Load16U(MemArg), I64Load8S(MemArg), I64Load8U(MemArg), I64Load16S(MemArg), I64Load16U(MemArg), I64Load32S(MemArg), I64Load32U(MemArg), I32Store(MemArg), I64Store(MemArg), F32Store(MemArg), F64Store(MemArg), I32Store8(MemArg), I32Store16(MemArg), I64Store8(MemArg), I64Store16(MemArg), I64Store32(MemArg), MemorySize(u32), MemoryGrow(u32), MemoryInit { mem: u32, data_index: u32, }, DataDrop(u32), MemoryCopy { src_mem: u32, dst_mem: u32, }, MemoryFill(u32), MemoryDiscard(u32), // Numeric instructions. I32Const(i32), I64Const(i64), F32Const(Ieee32), F64Const(Ieee64), I32Eqz, I32Eq, I32Ne, I32LtS, I32LtU, I32GtS, I32GtU, I32LeS, I32LeU, I32GeS, I32GeU, I64Eqz, I64Eq, I64Ne, I64LtS, I64LtU, I64GtS, I64GtU, I64LeS, I64LeU, I64GeS, I64GeU, F32Eq, F32Ne, F32Lt, F32Gt, F32Le, F32Ge, F64Eq, F64Ne, F64Lt, F64Gt, F64Le, F64Ge, I32Clz, I32Ctz, I32Popcnt, I32Add, I32Sub, I32Mul, I32DivS, I32DivU, I32RemS, I32RemU, I32And, I32Or, I32Xor, I32Shl, I32ShrS, I32ShrU, I32Rotl, I32Rotr, I64Clz, I64Ctz, I64Popcnt, I64Add, I64Sub, I64Mul, I64DivS, I64DivU, I64RemS, I64RemU, I64And, I64Or, I64Xor, I64Shl, I64ShrS, I64ShrU, I64Rotl, I64Rotr, F32Abs, F32Neg, F32Ceil, F32Floor, F32Trunc, F32Nearest, F32Sqrt, F32Add, F32Sub, F32Mul, F32Div, F32Min, F32Max, F32Copysign, F64Abs, F64Neg, F64Ceil, F64Floor, F64Trunc, F64Nearest, F64Sqrt, F64Add, F64Sub, F64Mul, F64Div, F64Min, F64Max, F64Copysign, I32WrapI64, I32TruncF32S, I32TruncF32U, I32TruncF64S, I32TruncF64U, I64ExtendI32S, I64ExtendI32U, I64TruncF32S, I64TruncF32U, I64TruncF64S, I64TruncF64U, F32ConvertI32S, F32ConvertI32U, F32ConvertI64S, F32ConvertI64U, F32DemoteF64, F64ConvertI32S, F64ConvertI32U, F64ConvertI64S, F64ConvertI64U, F64PromoteF32, I32ReinterpretF32, I64ReinterpretF64, F32ReinterpretI32, F64ReinterpretI64, I32Extend8S, I32Extend16S, I64Extend8S, I64Extend16S, I64Extend32S, I32TruncSatF32S, I32TruncSatF32U, I32TruncSatF64S, I32TruncSatF64U, I64TruncSatF32S, I64TruncSatF32U, I64TruncSatF64S, I64TruncSatF64U, // Reference types instructions. TypedSelect(ValType), TypedSelectMulti(Cow<'a, [ValType]>), RefNull(HeapType), RefIsNull, RefFunc(u32), RefEq, RefAsNonNull, // GC types instructions. StructNew(u32), StructNewDefault(u32), StructGet { struct_type_index: u32, field_index: u32, }, StructGetS { struct_type_index: u32, field_index: u32, }, StructGetU { struct_type_index: u32, field_index: u32, }, StructSet { struct_type_index: u32, field_index: u32, }, ArrayNew(u32), ArrayNewDefault(u32), ArrayNewFixed { array_type_index: u32, array_size: u32, }, ArrayNewData { array_type_index: u32, array_data_index: u32, }, ArrayNewElem { array_type_index: u32, array_elem_index: u32, }, ArrayGet(u32), ArrayGetS(u32), ArrayGetU(u32), ArraySet(u32), ArrayLen, ArrayFill(u32), ArrayCopy { array_type_index_dst: u32, array_type_index_src: u32, }, ArrayInitData { array_type_index: u32, array_data_index: u32, }, ArrayInitElem { array_type_index: u32, array_elem_index: u32, }, RefTestNonNull(HeapType), RefTestNullable(HeapType), RefCastNonNull(HeapType), RefCastNullable(HeapType), BrOnCast { relative_depth: u32, from_ref_type: RefType, to_ref_type: RefType, }, BrOnCastFail { relative_depth: u32, from_ref_type: RefType, to_ref_type: RefType, }, AnyConvertExtern, ExternConvertAny, RefI31, I31GetS, I31GetU, // Bulk memory instructions. TableInit { elem_index: u32, table: u32, }, ElemDrop(u32), TableFill(u32), TableSet(u32), TableGet(u32), TableGrow(u32), TableSize(u32), TableCopy { src_table: u32, dst_table: u32, }, // SIMD instructions. V128Load(MemArg), V128Load8x8S(MemArg), V128Load8x8U(MemArg), V128Load16x4S(MemArg), V128Load16x4U(MemArg), V128Load32x2S(MemArg), V128Load32x2U(MemArg), V128Load8Splat(MemArg), V128Load16Splat(MemArg), V128Load32Splat(MemArg), V128Load64Splat(MemArg), V128Load32Zero(MemArg), V128Load64Zero(MemArg), V128Store(MemArg), V128Load8Lane { memarg: MemArg, lane: Lane, }, V128Load16Lane { memarg: MemArg, lane: Lane, }, V128Load32Lane { memarg: MemArg, lane: Lane, }, V128Load64Lane { memarg: MemArg, lane: Lane, }, V128Store8Lane { memarg: MemArg, lane: Lane, }, V128Store16Lane { memarg: MemArg, lane: Lane, }, V128Store32Lane { memarg: MemArg, lane: Lane, }, V128Store64Lane { memarg: MemArg, lane: Lane, }, V128Const(i128), I8x16Shuffle([Lane; 16]), I8x16ExtractLaneS(Lane), I8x16ExtractLaneU(Lane), I8x16ReplaceLane(Lane), I16x8ExtractLaneS(Lane), I16x8ExtractLaneU(Lane), I16x8ReplaceLane(Lane), I32x4ExtractLane(Lane), I32x4ReplaceLane(Lane), I64x2ExtractLane(Lane), I64x2ReplaceLane(Lane), F32x4ExtractLane(Lane), F32x4ReplaceLane(Lane), F64x2ExtractLane(Lane), F64x2ReplaceLane(Lane), I8x16Swizzle, I8x16Splat, I16x8Splat, I32x4Splat, I64x2Splat, F32x4Splat, F64x2Splat, I8x16Eq, I8x16Ne, I8x16LtS, I8x16LtU, I8x16GtS, I8x16GtU, I8x16LeS, I8x16LeU, I8x16GeS, I8x16GeU, I16x8Eq, I16x8Ne, I16x8LtS, I16x8LtU, I16x8GtS, I16x8GtU, I16x8LeS, I16x8LeU, I16x8GeS, I16x8GeU, I32x4Eq, I32x4Ne, I32x4LtS, I32x4LtU, I32x4GtS, I32x4GtU, I32x4LeS, I32x4LeU, I32x4GeS, I32x4GeU, I64x2Eq, I64x2Ne, I64x2LtS, I64x2GtS, I64x2LeS, I64x2GeS, F32x4Eq, F32x4Ne, F32x4Lt, F32x4Gt, F32x4Le, F32x4Ge, F64x2Eq, F64x2Ne, F64x2Lt, F64x2Gt, F64x2Le, F64x2Ge, V128Not, V128And, V128AndNot, V128Or, V128Xor, V128Bitselect, V128AnyTrue, I8x16Abs, I8x16Neg, I8x16Popcnt, I8x16AllTrue, I8x16Bitmask, I8x16NarrowI16x8S, I8x16NarrowI16x8U, I8x16Shl, I8x16ShrS, I8x16ShrU, I8x16Add, I8x16AddSatS, I8x16AddSatU, I8x16Sub, I8x16SubSatS, I8x16SubSatU, I8x16MinS, I8x16MinU, I8x16MaxS, I8x16MaxU, I8x16AvgrU, I16x8ExtAddPairwiseI8x16S, I16x8ExtAddPairwiseI8x16U, I16x8Abs, I16x8Neg, I16x8Q15MulrSatS, I16x8AllTrue, I16x8Bitmask, I16x8NarrowI32x4S, I16x8NarrowI32x4U, I16x8ExtendLowI8x16S, I16x8ExtendHighI8x16S, I16x8ExtendLowI8x16U, I16x8ExtendHighI8x16U, I16x8Shl, I16x8ShrS, I16x8ShrU, I16x8Add, I16x8AddSatS, I16x8AddSatU, I16x8Sub, I16x8SubSatS, I16x8SubSatU, I16x8Mul, I16x8MinS, I16x8MinU, I16x8MaxS, I16x8MaxU, I16x8AvgrU, I16x8ExtMulLowI8x16S, I16x8ExtMulHighI8x16S, I16x8ExtMulLowI8x16U, I16x8ExtMulHighI8x16U, I32x4ExtAddPairwiseI16x8S, I32x4ExtAddPairwiseI16x8U, I32x4Abs, I32x4Neg, I32x4AllTrue, I32x4Bitmask, I32x4ExtendLowI16x8S, I32x4ExtendHighI16x8S, I32x4ExtendLowI16x8U, I32x4ExtendHighI16x8U, I32x4Shl, I32x4ShrS, I32x4ShrU, I32x4Add, I32x4Sub, I32x4Mul, I32x4MinS, I32x4MinU, I32x4MaxS, I32x4MaxU, I32x4DotI16x8S, I32x4ExtMulLowI16x8S, I32x4ExtMulHighI16x8S, I32x4ExtMulLowI16x8U, I32x4ExtMulHighI16x8U, I64x2Abs, I64x2Neg, I64x2AllTrue, I64x2Bitmask, I64x2ExtendLowI32x4S, I64x2ExtendHighI32x4S, I64x2ExtendLowI32x4U, I64x2ExtendHighI32x4U, I64x2Shl, I64x2ShrS, I64x2ShrU, I64x2Add, I64x2Sub, I64x2Mul, I64x2ExtMulLowI32x4S, I64x2ExtMulHighI32x4S, I64x2ExtMulLowI32x4U, I64x2ExtMulHighI32x4U, F32x4Ceil, F32x4Floor, F32x4Trunc, F32x4Nearest, F32x4Abs, F32x4Neg, F32x4Sqrt, F32x4Add, F32x4Sub, F32x4Mul, F32x4Div, F32x4Min, F32x4Max, F32x4PMin, F32x4PMax, F64x2Ceil, F64x2Floor, F64x2Trunc, F64x2Nearest, F64x2Abs, F64x2Neg, F64x2Sqrt, F64x2Add, F64x2Sub, F64x2Mul, F64x2Div, F64x2Min, F64x2Max, F64x2PMin, F64x2PMax, I32x4TruncSatF32x4S, I32x4TruncSatF32x4U, F32x4ConvertI32x4S, F32x4ConvertI32x4U, I32x4TruncSatF64x2SZero, I32x4TruncSatF64x2UZero, F64x2ConvertLowI32x4S, F64x2ConvertLowI32x4U, F32x4DemoteF64x2Zero, F64x2PromoteLowF32x4, // Relaxed simd proposal I8x16RelaxedSwizzle, I32x4RelaxedTruncF32x4S, I32x4RelaxedTruncF32x4U, I32x4RelaxedTruncF64x2SZero, I32x4RelaxedTruncF64x2UZero, F32x4RelaxedMadd, F32x4RelaxedNmadd, F64x2RelaxedMadd, F64x2RelaxedNmadd, I8x16RelaxedLaneselect, I16x8RelaxedLaneselect, I32x4RelaxedLaneselect, I64x2RelaxedLaneselect, F32x4RelaxedMin, F32x4RelaxedMax, F64x2RelaxedMin, F64x2RelaxedMax, I16x8RelaxedQ15mulrS, I16x8RelaxedDotI8x16I7x16S, I32x4RelaxedDotI8x16I7x16AddS, // Atomic instructions (the threads proposal) MemoryAtomicNotify(MemArg), MemoryAtomicWait32(MemArg), MemoryAtomicWait64(MemArg), AtomicFence, I32AtomicLoad(MemArg), I64AtomicLoad(MemArg), I32AtomicLoad8U(MemArg), I32AtomicLoad16U(MemArg), I64AtomicLoad8U(MemArg), I64AtomicLoad16U(MemArg), I64AtomicLoad32U(MemArg), I32AtomicStore(MemArg), I64AtomicStore(MemArg), I32AtomicStore8(MemArg), I32AtomicStore16(MemArg), I64AtomicStore8(MemArg), I64AtomicStore16(MemArg), I64AtomicStore32(MemArg), I32AtomicRmwAdd(MemArg), I64AtomicRmwAdd(MemArg), I32AtomicRmw8AddU(MemArg), I32AtomicRmw16AddU(MemArg), I64AtomicRmw8AddU(MemArg), I64AtomicRmw16AddU(MemArg), I64AtomicRmw32AddU(MemArg), I32AtomicRmwSub(MemArg), I64AtomicRmwSub(MemArg), I32AtomicRmw8SubU(MemArg), I32AtomicRmw16SubU(MemArg), I64AtomicRmw8SubU(MemArg), I64AtomicRmw16SubU(MemArg), I64AtomicRmw32SubU(MemArg), I32AtomicRmwAnd(MemArg), I64AtomicRmwAnd(MemArg), I32AtomicRmw8AndU(MemArg), I32AtomicRmw16AndU(MemArg), I64AtomicRmw8AndU(MemArg), I64AtomicRmw16AndU(MemArg), I64AtomicRmw32AndU(MemArg), I32AtomicRmwOr(MemArg), I64AtomicRmwOr(MemArg), I32AtomicRmw8OrU(MemArg), I32AtomicRmw16OrU(MemArg), I64AtomicRmw8OrU(MemArg), I64AtomicRmw16OrU(MemArg), I64AtomicRmw32OrU(MemArg), I32AtomicRmwXor(MemArg), I64AtomicRmwXor(MemArg), I32AtomicRmw8XorU(MemArg), I32AtomicRmw16XorU(MemArg), I64AtomicRmw8XorU(MemArg), I64AtomicRmw16XorU(MemArg), I64AtomicRmw32XorU(MemArg), I32AtomicRmwXchg(MemArg), I64AtomicRmwXchg(MemArg), I32AtomicRmw8XchgU(MemArg), I32AtomicRmw16XchgU(MemArg), I64AtomicRmw8XchgU(MemArg), I64AtomicRmw16XchgU(MemArg), I64AtomicRmw32XchgU(MemArg), I32AtomicRmwCmpxchg(MemArg), I64AtomicRmwCmpxchg(MemArg), I32AtomicRmw8CmpxchgU(MemArg), I32AtomicRmw16CmpxchgU(MemArg), I64AtomicRmw8CmpxchgU(MemArg), I64AtomicRmw16CmpxchgU(MemArg), I64AtomicRmw32CmpxchgU(MemArg), // More atomic instructions (the shared-everything-threads proposal) GlobalAtomicGet { ordering: Ordering, global_index: u32, }, GlobalAtomicSet { ordering: Ordering, global_index: u32, }, GlobalAtomicRmwAdd { ordering: Ordering, global_index: u32, }, GlobalAtomicRmwSub { ordering: Ordering, global_index: u32, }, GlobalAtomicRmwAnd { ordering: Ordering, global_index: u32, }, GlobalAtomicRmwOr { ordering: Ordering, global_index: u32, }, GlobalAtomicRmwXor { ordering: Ordering, global_index: u32, }, GlobalAtomicRmwXchg { ordering: Ordering, global_index: u32, }, GlobalAtomicRmwCmpxchg { ordering: Ordering, global_index: u32, }, TableAtomicGet { ordering: Ordering, table_index: u32, }, TableAtomicSet { ordering: Ordering, table_index: u32, }, TableAtomicRmwXchg { ordering: Ordering, table_index: u32, }, TableAtomicRmwCmpxchg { ordering: Ordering, table_index: u32, }, StructAtomicGet { ordering: Ordering, struct_type_index: u32, field_index: u32, }, StructAtomicGetS { ordering: Ordering, struct_type_index: u32, field_index: u32, }, StructAtomicGetU { ordering: Ordering, struct_type_index: u32, field_index: u32, }, StructAtomicSet { ordering: Ordering, struct_type_index: u32, field_index: u32, }, StructAtomicRmwAdd { ordering: Ordering, struct_type_index: u32, field_index: u32, }, StructAtomicRmwSub { ordering: Ordering, struct_type_index: u32, field_index: u32, }, StructAtomicRmwAnd { ordering: Ordering, struct_type_index: u32, field_index: u32, }, StructAtomicRmwOr { ordering: Ordering, struct_type_index: u32, field_index: u32, }, StructAtomicRmwXor { ordering: Ordering, struct_type_index: u32, field_index: u32, }, StructAtomicRmwXchg { ordering: Ordering, struct_type_index: u32, field_index: u32, }, StructAtomicRmwCmpxchg { ordering: Ordering, struct_type_index: u32, field_index: u32, }, ArrayAtomicGet { ordering: Ordering, array_type_index: u32, }, ArrayAtomicGetS { ordering: Ordering, array_type_index: u32, }, ArrayAtomicGetU { ordering: Ordering, array_type_index: u32, }, ArrayAtomicSet { ordering: Ordering, array_type_index: u32, }, ArrayAtomicRmwAdd { ordering: Ordering, array_type_index: u32, }, ArrayAtomicRmwSub { ordering: Ordering, array_type_index: u32, }, ArrayAtomicRmwAnd { ordering: Ordering, array_type_index: u32, }, ArrayAtomicRmwOr { ordering: Ordering, array_type_index: u32, }, ArrayAtomicRmwXor { ordering: Ordering, array_type_index: u32, }, ArrayAtomicRmwXchg { ordering: Ordering, array_type_index: u32, }, ArrayAtomicRmwCmpxchg { ordering: Ordering, array_type_index: u32, }, RefI31Shared, // Stack switching ContNew(u32), ContBind { argument_index: u32, result_index: u32, }, Suspend(u32), Resume { cont_type_index: u32, resume_table: Cow<'a, [Handle]>, }, ResumeThrow { cont_type_index: u32, tag_index: u32, resume_table: Cow<'a, [Handle]>, }, Switch { cont_type_index: u32, tag_index: u32, }, // Wide Arithmetic I64Add128, I64Sub128, I64MulWideS, I64MulWideU, } impl Encode for Instruction<'_> { fn encode(&self, bytes: &mut Vec) { let mut sink = InstructionSink::new(bytes); match *self { // Control instructions. 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.call_indirect(table_index, type_index), Instruction::ReturnCallRef(ty) => sink.return_call_ref(ty), Instruction::ReturnCall(f) => sink.return_call(f), Instruction::ReturnCallIndirect { type_index, table_index, } => sink.return_call_indirect(table_index, type_index), Instruction::Delegate(l) => sink.delegate(l), Instruction::CatchAll => sink.catch_all(), // Parametric instructions. 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.try_table(ty, catches.iter().cloned()), // Variable instructions. 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.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.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.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.struct_new(type_index), Instruction::StructNewDefault(type_index) => sink.struct_new_default(type_index), Instruction::StructGet { struct_type_index, field_index, } => sink.struct_get(struct_type_index, field_index), Instruction::StructGetS { struct_type_index, field_index, } => sink.struct_get_s(struct_type_index, field_index), Instruction::StructGetU { struct_type_index, field_index, } => sink.struct_get_u(struct_type_index, field_index), Instruction::StructSet { struct_type_index, field_index, } => sink.struct_set(struct_type_index, field_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.array_new_fixed(array_type_index, array_size), Instruction::ArrayNewData { array_type_index, array_data_index, } => sink.array_new_data(array_type_index, array_data_index), Instruction::ArrayNewElem { array_type_index, array_elem_index, } => 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.array_copy(array_type_index_dst, array_type_index_src), Instruction::ArrayInitData { array_type_index, array_data_index, } => sink.array_init_data(array_type_index, array_data_index), Instruction::ArrayInitElem { array_type_index, array_elem_index, } => 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.br_on_cast(relative_depth, from_ref_type, to_ref_type), Instruction::BrOnCastFail { relative_depth, from_ref_type, to_ref_type, } => 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.table_init(table, elem_index), Instruction::ElemDrop(segment) => sink.elem_drop(segment), Instruction::TableCopy { src_table, dst_table, } => 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.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.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.global_atomic_get(ordering, global_index), Instruction::GlobalAtomicSet { ordering, global_index, } => sink.global_atomic_set(ordering, global_index), Instruction::GlobalAtomicRmwAdd { ordering, global_index, } => sink.global_atomic_rmw_add(ordering, global_index), Instruction::GlobalAtomicRmwSub { ordering, global_index, } => sink.global_atomic_rmw_sub(ordering, global_index), Instruction::GlobalAtomicRmwAnd { ordering, global_index, } => sink.global_atomic_rmw_and(ordering, global_index), Instruction::GlobalAtomicRmwOr { ordering, global_index, } => sink.global_atomic_rmw_or(ordering, global_index), Instruction::GlobalAtomicRmwXor { ordering, global_index, } => sink.global_atomic_rmw_xor(ordering, global_index), Instruction::GlobalAtomicRmwXchg { ordering, global_index, } => sink.global_atomic_rmw_xchg(ordering, global_index), Instruction::GlobalAtomicRmwCmpxchg { ordering, global_index, } => sink.global_atomic_rmw_cmpxchg(ordering, global_index), Instruction::TableAtomicGet { ordering, table_index, } => sink.table_atomic_get(ordering, table_index), Instruction::TableAtomicSet { ordering, table_index, } => sink.table_atomic_set(ordering, table_index), Instruction::TableAtomicRmwXchg { ordering, table_index, } => sink.table_atomic_rmw_xchg(ordering, table_index), Instruction::TableAtomicRmwCmpxchg { ordering, table_index, } => sink.table_atomic_rmw_cmpxchg(ordering, table_index), Instruction::StructAtomicGet { ordering, struct_type_index, field_index, } => sink.struct_atomic_get(ordering, struct_type_index, field_index), Instruction::StructAtomicGetS { ordering, struct_type_index, field_index, } => sink.struct_atomic_get_s(ordering, struct_type_index, field_index), Instruction::StructAtomicGetU { ordering, struct_type_index, field_index, } => sink.struct_atomic_get_u(ordering, struct_type_index, field_index), Instruction::StructAtomicSet { ordering, struct_type_index, field_index, } => sink.struct_atomic_set(ordering, struct_type_index, field_index), Instruction::StructAtomicRmwAdd { ordering, struct_type_index, field_index, } => sink.struct_atomic_rmw_add(ordering, struct_type_index, field_index), Instruction::StructAtomicRmwSub { ordering, struct_type_index, field_index, } => sink.struct_atomic_rmw_sub(ordering, struct_type_index, field_index), Instruction::StructAtomicRmwAnd { ordering, struct_type_index, field_index, } => sink.struct_atomic_rmw_and(ordering, struct_type_index, field_index), Instruction::StructAtomicRmwOr { ordering, struct_type_index, field_index, } => sink.struct_atomic_rmw_or(ordering, struct_type_index, field_index), Instruction::StructAtomicRmwXor { ordering, struct_type_index, field_index, } => sink.struct_atomic_rmw_xor(ordering, struct_type_index, field_index), Instruction::StructAtomicRmwXchg { ordering, struct_type_index, field_index, } => sink.struct_atomic_rmw_xchg(ordering, struct_type_index, field_index), Instruction::StructAtomicRmwCmpxchg { ordering, struct_type_index, field_index, } => sink.struct_atomic_rmw_cmpxchg(ordering, struct_type_index, field_index), Instruction::ArrayAtomicGet { ordering, array_type_index, } => sink.array_atomic_get(ordering, array_type_index), Instruction::ArrayAtomicGetS { ordering, array_type_index, } => sink.array_atomic_get_s(ordering, array_type_index), Instruction::ArrayAtomicGetU { ordering, array_type_index, } => sink.array_atomic_get_u(ordering, array_type_index), Instruction::ArrayAtomicSet { ordering, array_type_index, } => sink.array_atomic_set(ordering, array_type_index), Instruction::ArrayAtomicRmwAdd { ordering, array_type_index, } => sink.array_atomic_rmw_add(ordering, array_type_index), Instruction::ArrayAtomicRmwSub { ordering, array_type_index, } => sink.array_atomic_rmw_sub(ordering, array_type_index), Instruction::ArrayAtomicRmwAnd { ordering, array_type_index, } => sink.array_atomic_rmw_and(ordering, array_type_index), Instruction::ArrayAtomicRmwOr { ordering, array_type_index, } => sink.array_atomic_rmw_or(ordering, array_type_index), Instruction::ArrayAtomicRmwXor { ordering, array_type_index, } => sink.array_atomic_rmw_xor(ordering, array_type_index), Instruction::ArrayAtomicRmwXchg { ordering, array_type_index, } => sink.array_atomic_rmw_xchg(ordering, array_type_index), Instruction::ArrayAtomicRmwCmpxchg { ordering, array_type_index, } => 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.cont_bind(argument_index, result_index), Instruction::Suspend(tag_index) => sink.suspend(tag_index), Instruction::Resume { cont_type_index, ref resume_table, } => sink.resume(cont_type_index, resume_table.iter().cloned()), Instruction::ResumeThrow { cont_type_index, tag_index, ref resume_table, } => sink.resume_throw(cont_type_index, tag_index, resume_table.iter().cloned()), Instruction::Switch { cont_type_index, tag_index, } => 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(), }; } } #[derive(Clone, Debug)] #[allow(missing_docs)] pub enum Catch { One { tag: u32, label: u32 }, OneRef { tag: u32, label: u32 }, All { label: u32 }, AllRef { label: u32 }, } impl Encode for Catch { fn encode(&self, sink: &mut Vec) { match self { Catch::One { tag, label } => { sink.push(0x00); tag.encode(sink); label.encode(sink); } Catch::OneRef { tag, label } => { sink.push(0x01); tag.encode(sink); label.encode(sink); } Catch::All { label } => { sink.push(0x02); label.encode(sink); } Catch::AllRef { label } => { sink.push(0x03); label.encode(sink); } } } } #[derive(Clone, Debug)] #[allow(missing_docs)] pub enum Handle { OnLabel { tag: u32, label: u32 }, OnSwitch { tag: u32 }, } impl Encode for Handle { fn encode(&self, sink: &mut Vec) { match self { Handle::OnLabel { tag, label } => { sink.push(0x00); tag.encode(sink); label.encode(sink); } Handle::OnSwitch { tag } => { sink.push(0x01); tag.encode(sink); } } } } /// A constant expression. /// /// Usable in contexts such as offsets or initializers. #[derive(Clone, Debug)] pub struct ConstExpr { bytes: Vec, } impl ConstExpr { /// Create a new empty constant expression builder. pub fn empty() -> Self { Self { bytes: Vec::new() } } /// Create a constant expression with the specified raw encoding of instructions. pub fn raw(bytes: impl IntoIterator) -> Self { Self { bytes: bytes.into_iter().collect(), } } /// Create a constant expression with the sequence of instructions pub fn extended<'a>(insns: impl IntoIterator>) -> Self { let mut bytes = vec![]; for insn in insns { insn.encode(&mut bytes); } Self { bytes } } fn new(f: F) -> Self where for<'a, 'b> F: FnOnce(&'a mut InstructionSink<'b>) -> &'a mut InstructionSink<'b>, { let mut bytes = vec![]; f(&mut InstructionSink::new(&mut bytes)); Self { bytes } } fn with(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| insn.global_get(index)) } /// Create a constant expression containing a single `ref.null` instruction. pub fn ref_null(ty: HeapType) -> Self { 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| insn.ref_func(func)) } /// Create a constant expression containing a single `i32.const` instruction. pub fn i32_const(value: i32) -> Self { 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| insn.i64_const(value)) } /// Create a constant expression containing a single `f32.const` instruction. 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: 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| 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| 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| 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| 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| 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| insn.i64_const(value)) } /// Add a `f32.const` instruction to this constant expression. 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: 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| insn.v128_const(value)) } /// Add an `i32.add` instruction to this constant expression. pub fn with_i32_add(self) -> Self { 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| insn.i32_sub()) } /// Add an `i32.mul` instruction to this constant expression. pub fn with_i32_mul(self) -> Self { 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| insn.i64_add()) } /// Add an `i64.sub` instruction to this constant expression. pub fn with_i64_sub(self) -> Self { 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| insn.i64_mul()) } /// Returns the function, if any, referenced by this global. pub fn get_ref_func(&self) -> Option { let prefix = *self.bytes.get(0)?; // 0xd2 == `ref.func` opcode, and if that's found then load the leb // corresponding to the function index. if prefix != 0xd2 { return None; } leb128fmt::decode_uint_slice::(&self.bytes[1..], &mut 0).ok() } } impl Encode for ConstExpr { fn encode(&self, sink: &mut Vec) { sink.extend(&self.bytes); InstructionSink::new(sink).end(); } } #[cfg(test)] mod tests { #[test] fn function_new_with_locals_test() { use super::*; // Test the algorithm for conversion is correct let f1 = Function::new_with_locals_types([ ValType::I32, ValType::I32, ValType::I64, ValType::F32, ValType::F32, ValType::F32, ValType::I32, ValType::I64, ValType::I64, ]); let f2 = Function::new([ (2, ValType::I32), (1, ValType::I64), (3, ValType::F32), (1, ValType::I32), (2, ValType::I64), ]); assert_eq!(f1.bytes, f2.bytes) } #[test] fn func_raw_bytes() { use super::*; let mut f = Function::new([(1, ValType::I32), (1, ValType::F32)]); f.instructions().end(); let mut code_from_func = CodeSection::new(); code_from_func.function(&f); let bytes = f.into_raw_body(); let mut code_from_raw = CodeSection::new(); code_from_raw.raw(&bytes[..]); let mut c1 = vec![]; code_from_func.encode(&mut c1); let mut c2 = vec![]; code_from_raw.encode(&mut c2); assert_eq!(c1, c2); } } wasm-encoder-0.239.0/src/core/custom.rs000064400000000000000000000034711046102023000157670ustar 00000000000000use crate::{Encode, Section, SectionId, encoding_size}; use alloc::borrow::Cow; use alloc::vec::Vec; /// A custom section holding arbitrary data. #[derive(Clone, Debug, PartialEq)] pub struct CustomSection<'a> { /// The name of this custom section. pub name: Cow<'a, str>, /// This custom section's data. pub data: Cow<'a, [u8]>, } impl Encode for CustomSection<'_> { fn encode(&self, sink: &mut Vec) { let encoded_name_len = encoding_size(u32::try_from(self.name.len()).unwrap()); (encoded_name_len + self.name.len() + self.data.len()).encode(sink); self.name.encode(sink); sink.extend(&*self.data); } } impl Section for CustomSection<'_> { fn id(&self) -> u8 { SectionId::Custom.into() } } /// A raw custom section where the bytes specified contain the leb-encoded /// length of the custom section, the custom section's name, and the custom /// section's data. #[derive(Clone, Debug)] pub struct RawCustomSection<'a>(pub &'a [u8]); impl Encode for RawCustomSection<'_> { fn encode(&self, sink: &mut Vec) { sink.extend(self.0); } } impl Section for RawCustomSection<'_> { fn id(&self) -> u8 { SectionId::Custom.into() } } #[cfg(test)] mod tests { use super::*; use alloc::vec; #[test] fn test_custom_section() { let custom = CustomSection { name: "test".into(), data: Cow::Borrowed(&[11, 22, 33, 44]), }; let mut encoded = vec![]; custom.encode(&mut encoded); #[rustfmt::skip] assert_eq!(encoded, vec![ // LEB128 length of section. 9, // LEB128 length of name. 4, // Name. b't', b'e', b's', b't', // Data. 11, 22, 33, 44, ]); } } wasm-encoder-0.239.0/src/core/data.rs000064400000000000000000000112001046102023000153530ustar 00000000000000use crate::{ConstExpr, Encode, Section, SectionId, encode_section, encoding_size}; use alloc::vec::Vec; /// An encoder for the data section. /// /// Data sections are only supported for modules. /// /// # Example /// /// ``` /// use wasm_encoder::{ /// ConstExpr, DataSection, Instruction, MemorySection, MemoryType, /// Module, /// }; /// /// let mut memory = MemorySection::new(); /// memory.memory(MemoryType { /// minimum: 1, /// maximum: None, /// memory64: false, /// shared: false, /// page_size_log2: None, /// }); /// /// let mut data = DataSection::new(); /// let memory_index = 0; /// let offset = ConstExpr::i32_const(42); /// let segment_data = b"hello"; /// data.active(memory_index, &offset, segment_data.iter().copied()); /// /// let mut module = Module::new(); /// module /// .section(&memory) /// .section(&data); /// /// let wasm_bytes = module.finish(); /// ``` #[derive(Clone, Default, Debug)] pub struct DataSection { bytes: Vec, num_added: u32, } /// A segment in the data section. #[derive(Clone, Debug)] pub struct DataSegment<'a, D> { /// This data segment's mode. pub mode: DataSegmentMode<'a>, /// This data segment's data. pub data: D, } /// A data segment's mode. #[derive(Clone, Debug)] pub enum DataSegmentMode<'a> { /// An active data segment. Active { /// The memory this segment applies to. memory_index: u32, /// The offset where this segment's data is initialized at. offset: &'a ConstExpr, }, /// A passive data segment. /// /// Passive data segments are part of the bulk memory proposal. Passive, } impl DataSection { /// Create a new data section encoder. pub fn new() -> Self { Self::default() } /// The number of data segments in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Define a data segment. pub fn segment(&mut self, segment: DataSegment) -> &mut Self where D: IntoIterator, D::IntoIter: ExactSizeIterator, { match segment.mode { DataSegmentMode::Passive => { self.bytes.push(0x01); } DataSegmentMode::Active { memory_index: 0, offset, } => { self.bytes.push(0x00); offset.encode(&mut self.bytes); } DataSegmentMode::Active { memory_index, offset, } => { self.bytes.push(0x02); memory_index.encode(&mut self.bytes); offset.encode(&mut self.bytes); } } let data = segment.data.into_iter(); data.len().encode(&mut self.bytes); self.bytes.extend(data); self.num_added += 1; self } /// Define an active data segment. pub fn active(&mut self, memory_index: u32, offset: &ConstExpr, data: D) -> &mut Self where D: IntoIterator, D::IntoIter: ExactSizeIterator, { self.segment(DataSegment { mode: DataSegmentMode::Active { memory_index, offset, }, data, }) } /// Define a passive data segment. /// /// Passive data segments are part of the bulk memory proposal. pub fn passive(&mut self, data: D) -> &mut Self where D: IntoIterator, D::IntoIter: ExactSizeIterator, { self.segment(DataSegment { mode: DataSegmentMode::Passive, data, }) } /// Copy an already-encoded data segment into this data section. pub fn raw(&mut self, already_encoded_data_segment: &[u8]) -> &mut Self { self.bytes.extend_from_slice(already_encoded_data_segment); self.num_added += 1; self } } impl Encode for DataSection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl Section for DataSection { fn id(&self) -> u8 { SectionId::Data.into() } } /// An encoder for the data count section. #[derive(Clone, Copy, Debug)] pub struct DataCountSection { /// The number of segments in the data section. pub count: u32, } impl Encode for DataCountSection { fn encode(&self, sink: &mut Vec) { encoding_size(self.count).encode(sink); self.count.encode(sink); } } impl Section for DataCountSection { fn id(&self) -> u8 { SectionId::DataCount.into() } } wasm-encoder-0.239.0/src/core/dump.rs000064400000000000000000000444141046102023000154240ustar 00000000000000use crate::{CustomSection, Encode, Ieee32, Ieee64, Section}; use alloc::borrow::Cow; use alloc::string::String; use alloc::vec; use alloc::vec::Vec; /// The "core" custom section for coredumps, as described in the /// [tool-conventions /// repository](https://github.com/WebAssembly/tool-conventions/blob/main/Coredump.md). /// /// There are four sections that comprise a core dump: /// - "core", which contains the name of the core dump /// - "coremodules", a listing of modules /// - "coreinstances", a listing of module instances /// - "corestack", a listing of frames for a specific thread /// /// # Example of how these could be constructed and encoded into a module: /// /// ``` /// use wasm_encoder::{ /// CoreDumpInstancesSection, CoreDumpModulesSection, CoreDumpSection, CoreDumpStackSection, /// CoreDumpValue, Module, /// }; /// let core = CoreDumpSection::new("MyModule.wasm"); /// /// let mut modules = CoreDumpModulesSection::new(); /// modules.module("my_module"); /// /// let mut instances = CoreDumpInstancesSection::new(); /// let module_idx = 0; /// let memories = vec![1]; /// let globals = vec![2]; /// instances.instance(module_idx, memories, globals); /// /// let mut thread = CoreDumpStackSection::new("main"); /// let instance_index = 0; /// let func_index = 42; /// let code_offset = 0x1234; /// let locals = vec![CoreDumpValue::I32(1)]; /// let stack = vec![CoreDumpValue::I32(2)]; /// thread.frame(instance_index, func_index, code_offset, locals, stack); /// /// let mut module = Module::new(); /// module.section(&core); /// module.section(&modules); /// module.section(&instances); /// module.section(&thread); /// ``` #[derive(Clone, Debug, Default)] pub struct CoreDumpSection { name: String, } impl CoreDumpSection { /// Create a new core dump section encoder pub fn new(name: impl Into) -> Self { let name = name.into(); CoreDumpSection { name } } /// View the encoded section as a CustomSection. fn as_custom<'a>(&'a self) -> CustomSection<'a> { let mut data = vec![0]; self.name.encode(&mut data); CustomSection { name: "core".into(), data: Cow::Owned(data), } } } impl Encode for CoreDumpSection { fn encode(&self, sink: &mut Vec) { self.as_custom().encode(sink); } } impl Section for CoreDumpSection { fn id(&self) -> u8 { crate::core::SectionId::Custom as u8 } } /// The "coremodules" custom section for coredumps which lists the names of the /// modules /// /// # Example /// /// ``` /// use wasm_encoder::{CoreDumpModulesSection, Module}; /// let mut modules_section = CoreDumpModulesSection::new(); /// modules_section.module("my_module"); /// let mut module = Module::new(); /// module.section(&modules_section); /// ``` #[derive(Debug)] pub struct CoreDumpModulesSection { num_added: u32, bytes: Vec, } impl CoreDumpModulesSection { /// Create a new core dump modules section encoder. pub fn new() -> Self { CoreDumpModulesSection { bytes: vec![], num_added: 0, } } /// View the encoded section as a CustomSection. pub fn as_custom(&self) -> CustomSection<'_> { let mut data = vec![]; self.num_added.encode(&mut data); data.extend(self.bytes.iter().copied()); CustomSection { name: "coremodules".into(), data: Cow::Owned(data), } } /// Encode a module name into the section's bytes. pub fn module(&mut self, module_name: impl AsRef) -> &mut Self { self.bytes.push(0x0); module_name.as_ref().encode(&mut self.bytes); self.num_added += 1; self } /// The number of modules that are encoded in the section. pub fn len(&self) -> u32 { self.num_added } } impl Encode for CoreDumpModulesSection { fn encode(&self, sink: &mut Vec) { self.as_custom().encode(sink); } } impl Section for CoreDumpModulesSection { fn id(&self) -> u8 { crate::core::SectionId::Custom as u8 } } /// The "coreinstances" section for the core dump #[derive(Debug)] pub struct CoreDumpInstancesSection { num_added: u32, bytes: Vec, } impl CoreDumpInstancesSection { /// Create a new core dump instances section encoder. pub fn new() -> Self { CoreDumpInstancesSection { bytes: vec![], num_added: 0, } } /// View the encoded section as a CustomSection. pub fn as_custom(&self) -> CustomSection<'_> { let mut data = vec![]; self.num_added.encode(&mut data); data.extend(self.bytes.iter().copied()); CustomSection { name: "coreinstances".into(), data: Cow::Owned(data), } } /// Encode an instance into the section's bytes. pub fn instance(&mut self, module_index: u32, memories: M, globals: G) -> &mut Self where M: IntoIterator, ::IntoIter: ExactSizeIterator, G: IntoIterator, ::IntoIter: ExactSizeIterator, { self.bytes.push(0x0); module_index.encode(&mut self.bytes); crate::encode_vec(memories, &mut self.bytes); crate::encode_vec(globals, &mut self.bytes); self.num_added += 1; self } /// The number of modules that are encoded in the section. pub fn len(&self) -> u32 { self.num_added } } impl Encode for CoreDumpInstancesSection { fn encode(&self, sink: &mut Vec) { self.as_custom().encode(sink); } } impl Section for CoreDumpInstancesSection { fn id(&self) -> u8 { crate::core::SectionId::Custom as u8 } } /// A "corestack" custom section as described in the [tool-conventions /// repository](https://github.com/WebAssembly/tool-conventions/blob/main/Coredump.md) /// /// # Example /// /// ``` /// use wasm_encoder::{CoreDumpStackSection, Module, CoreDumpValue}; /// let mut thread = CoreDumpStackSection::new("main"); /// /// let instance_index = 0; /// let func_index = 42; /// let code_offset = 0x1234; /// let locals = vec![CoreDumpValue::I32(1)]; /// let stack = vec![CoreDumpValue::I32(2)]; /// thread.frame(instance_index, func_index, code_offset, locals, stack); /// /// let mut module = Module::new(); /// module.section(&thread); /// ``` #[derive(Clone, Debug, Default)] pub struct CoreDumpStackSection { frame_bytes: Vec, count: u32, name: String, } impl CoreDumpStackSection { /// Create a new core dump stack section encoder. pub fn new(name: impl Into) -> Self { let name = name.into(); CoreDumpStackSection { frame_bytes: Vec::new(), count: 0, name, } } /// Add a stack frame to this coredump stack section. pub fn frame( &mut self, instanceidx: u32, funcidx: u32, codeoffset: u32, locals: L, stack: S, ) -> &mut Self where L: IntoIterator, ::IntoIter: ExactSizeIterator, S: IntoIterator, ::IntoIter: ExactSizeIterator, { self.count += 1; self.frame_bytes.push(0); instanceidx.encode(&mut self.frame_bytes); funcidx.encode(&mut self.frame_bytes); codeoffset.encode(&mut self.frame_bytes); crate::encode_vec(locals, &mut self.frame_bytes); crate::encode_vec(stack, &mut self.frame_bytes); self } /// View the encoded section as a CustomSection. pub fn as_custom<'a>(&'a self) -> CustomSection<'a> { let mut data = vec![0]; self.name.encode(&mut data); self.count.encode(&mut data); data.extend(&self.frame_bytes); CustomSection { name: "corestack".into(), data: Cow::Owned(data), } } } impl Encode for CoreDumpStackSection { fn encode(&self, sink: &mut Vec) { self.as_custom().encode(sink); } } impl Section for CoreDumpStackSection { fn id(&self) -> u8 { crate::core::SectionId::Custom as u8 } } /// Local and stack values are encoded using one byte for the type (similar to /// Wasm's Number Types) followed by bytes representing the actual value /// See the tool-conventions repo for more details. #[derive(Clone, Debug)] pub enum CoreDumpValue { /// a missing value (usually missing because it was optimized out) Missing, /// An i32 value I32(i32), /// An i64 value I64(i64), /// An f32 value F32(Ieee32), /// An f64 value F64(Ieee64), } impl Encode for CoreDumpValue { fn encode(&self, sink: &mut Vec) { match self { CoreDumpValue::Missing => sink.push(0x01), CoreDumpValue::I32(x) => { sink.push(0x7F); x.encode(sink); } CoreDumpValue::I64(x) => { sink.push(0x7E); x.encode(sink); } CoreDumpValue::F32(x) => { sink.push(0x7D); x.encode(sink); } CoreDumpValue::F64(x) => { sink.push(0x7C); x.encode(sink); } } } } #[cfg(test)] mod tests { use super::*; use crate::Module; use wasmparser::{KnownCustom, Parser, Payload}; // Create new core dump section and test whether it is properly encoded and // parsed back out by wasmparser #[test] fn test_roundtrip_core() { let core = CoreDumpSection::new("test.wasm"); let mut module = Module::new(); module.section(&core); let wasm_bytes = module.finish(); let mut parser = Parser::new(0).parse_all(&wasm_bytes); match parser.next() { Some(Ok(Payload::Version { .. })) => {} _ => panic!(""), } let payload = parser .next() .expect("parser is not empty") .expect("element is a payload"); match payload { Payload::CustomSection(section) => { assert_eq!(section.name(), "core"); let core = match section.as_known() { KnownCustom::CoreDump(s) => s, _ => panic!("not coredump"), }; assert_eq!(core.name, "test.wasm"); } _ => panic!("unexpected payload"), } } #[test] fn test_roundtrip_coremodules() { let mut coremodules = CoreDumpModulesSection::new(); coremodules.module("test_module"); let mut module = crate::Module::new(); module.section(&coremodules); let wasm_bytes = module.finish(); let mut parser = Parser::new(0).parse_all(&wasm_bytes); match parser.next() { Some(Ok(Payload::Version { .. })) => {} _ => panic!(""), } let payload = parser .next() .expect("parser is not empty") .expect("element is a payload"); match payload { Payload::CustomSection(section) => { assert_eq!(section.name(), "coremodules"); let modules = match section.as_known() { KnownCustom::CoreDumpModules(s) => s, _ => panic!("not coremodules"), }; assert_eq!(modules.modules[0], "test_module"); } _ => panic!("unexpected payload"), } } #[test] fn test_roundtrip_coreinstances() { let mut coreinstances = CoreDumpInstancesSection::new(); let module_index = 0; let memories = vec![42]; let globals = vec![17]; coreinstances.instance(module_index, memories, globals); let mut module = Module::new(); module.section(&coreinstances); let wasm_bytes = module.finish(); let mut parser = Parser::new(0).parse_all(&wasm_bytes); match parser.next() { Some(Ok(Payload::Version { .. })) => {} _ => panic!(""), } let payload = parser .next() .expect("parser is not empty") .expect("element is a payload"); match payload { Payload::CustomSection(section) => { assert_eq!(section.name(), "coreinstances"); let coreinstances = match section.as_known() { KnownCustom::CoreDumpInstances(s) => s, _ => panic!("not coreinstances"), }; assert_eq!(coreinstances.instances.len(), 1); let instance = coreinstances .instances .first() .expect("instance is encoded"); assert_eq!(instance.module_index, 0); assert_eq!(instance.memories.len(), 1); assert_eq!(instance.globals.len(), 1); } _ => panic!("unexpected payload"), } } // Create new corestack section and test whether it is properly encoded and // parsed back out by wasmparser #[test] fn test_roundtrip_corestack() { let mut corestack = CoreDumpStackSection::new("main"); corestack.frame( 0, 12, 0, vec![CoreDumpValue::I32(10)], vec![CoreDumpValue::I32(42)], ); let mut module = Module::new(); module.section(&corestack); let wasm_bytes = module.finish(); let mut parser = Parser::new(0).parse_all(&wasm_bytes); match parser.next() { Some(Ok(Payload::Version { .. })) => {} _ => panic!(""), } let payload = parser .next() .expect("parser is not empty") .expect("element is a payload"); match payload { Payload::CustomSection(section) => { assert_eq!(section.name(), "corestack"); let corestack = match section.as_known() { KnownCustom::CoreDumpStack(s) => s, _ => panic!("not a corestack section"), }; assert_eq!(corestack.name, "main"); assert_eq!(corestack.frames.len(), 1); let frame = corestack .frames .first() .expect("frame is encoded in corestack"); assert_eq!(frame.instanceidx, 0); assert_eq!(frame.funcidx, 12); assert_eq!(frame.codeoffset, 0); assert_eq!(frame.locals.len(), 1); match frame.locals.first().expect("frame contains a local") { &wasmparser::CoreDumpValue::I32(val) => assert_eq!(val, 10), _ => panic!("unexpected local value"), } assert_eq!(frame.stack.len(), 1); match frame.stack.first().expect("stack contains a value") { &wasmparser::CoreDumpValue::I32(val) => assert_eq!(val, 42), _ => panic!("unexpected stack value"), } } _ => panic!("unexpected payload"), } } #[test] fn test_encode_coredump_section() { let core = CoreDumpSection::new("test"); let mut encoded = vec![]; core.encode(&mut encoded); #[rustfmt::skip] assert_eq!(encoded, vec![ // section length 11, // name length 4, // section name (core) b'c',b'o',b'r',b'e', // process-info (0, data length, data) 0, 4, b't', b'e', b's', b't', ]); } #[test] fn test_encode_coremodules_section() { let mut modules = CoreDumpModulesSection::new(); modules.module("mod1"); modules.module("mod2"); let mut encoded = vec![]; modules.encode(&mut encoded); #[rustfmt::skip] assert_eq!(encoded, vec![ // section length 25, // name length 11, // section name (coremodules) b'c',b'o',b'r',b'e',b'm',b'o',b'd',b'u',b'l',b'e',b's', // module count 2, // 0x0, name-length, module name (mod1) 0x0, 4, b'm',b'o',b'd',b'1', // 0x0, name-length, module name (mod2) 0x0, 4, b'm',b'o',b'd',b'2' ]); } #[test] fn test_encode_coreinstances_section() { let mut instances = CoreDumpInstancesSection::new(); instances.instance(0, vec![42], vec![17]); let mut encoded = vec![]; instances.encode(&mut encoded); #[rustfmt::skip] assert_eq!(encoded, vec![ // section length 21, // name length 13, // section name (coreinstances) b'c',b'o',b'r',b'e',b'i',b'n',b's',b't',b'a',b'n',b'c',b'e',b's', // instance count 1, // 0x0, module_idx 0x0, 0, // memories count, memories 1, 42, // globals count, globals 1, 17 ]); } #[test] fn test_encode_corestack_section() { let mut thread = CoreDumpStackSection::new("main"); thread.frame( 0, 42, 51, vec![CoreDumpValue::I32(1)], vec![CoreDumpValue::I32(2)], ); let mut encoded = vec![]; thread.encode(&mut encoded); #[rustfmt::skip] assert_eq!( encoded, vec![ // section length 27, // length of name. 9, // section name (corestack) b'c',b'o',b'r',b'e',b's',b't',b'a',b'c',b'k', // 0x0, thread name length 0, 4, // thread name (main) b'm',b'a',b'i',b'n', // frame count 1, // 0x0, instanceidx, funcidx, codeoffset 0, 0, 42, 51, // local count 1, // local value type 0x7F, // local value 1, // stack count 1, // stack value type 0x7F, // stack value 2 ] ); } } wasm-encoder-0.239.0/src/core/elements.rs000064400000000000000000000155131046102023000162710ustar 00000000000000use crate::{ConstExpr, Encode, RefType, Section, SectionId, encode_section}; use alloc::borrow::Cow; use alloc::vec::Vec; /// An encoder for the element section. /// /// Element sections are only supported for modules. /// /// # Example /// /// ``` /// use std::borrow::Cow; /// use wasm_encoder::{ /// Elements, ElementSection, Module, TableSection, TableType, /// RefType, ConstExpr /// }; /// /// let mut tables = TableSection::new(); /// tables.table(TableType { /// element_type: RefType::FUNCREF, /// minimum: 128, /// maximum: None, /// table64: false, /// shared: false, /// }); /// /// let mut elements = ElementSection::new(); /// let table_index = 0; /// let offset = ConstExpr::i32_const(42); /// let functions = Elements::Functions(Cow::Borrowed(&[ /// // Function indices... /// ])); /// elements.active(Some(table_index), &offset, functions); /// /// let mut module = Module::new(); /// module /// .section(&tables) /// .section(&elements); /// /// let wasm_bytes = module.finish(); /// ``` #[derive(Clone, Default, Debug)] pub struct ElementSection { bytes: Vec, num_added: u32, } /// A sequence of elements in a segment in the element section. #[derive(Clone, Debug)] pub enum Elements<'a> { /// A sequences of references to functions by their indices. Functions(Cow<'a, [u32]>), /// A sequence of reference expressions. Expressions(RefType, Cow<'a, [ConstExpr]>), } /// An element segment's mode. #[derive(Clone, Debug)] pub enum ElementMode<'a> { /// A passive element segment. /// /// Passive segments are part of the bulk memory proposal. Passive, /// A declared element segment. /// /// Declared segments are part of the bulk memory proposal. Declared, /// An active element segment. Active { /// The table index. /// /// `Active` element specifying a `None` table forces the MVP encoding and refers to the /// 0th table holding `funcref`s. Non-`None` tables use the encoding introduced with the /// bulk memory proposal and can refer to tables with any valid reference type. table: Option, /// The offset within the table to place this segment. offset: &'a ConstExpr, }, } /// An element segment in the element section. #[derive(Clone, Debug)] pub struct ElementSegment<'a> { /// The element segment's mode. pub mode: ElementMode<'a>, /// This segment's elements. pub elements: Elements<'a>, } impl ElementSection { /// Create a new element section encoder. pub fn new() -> Self { Self::default() } /// The number of element segments in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Define an element segment. pub fn segment<'a>(&mut self, segment: ElementSegment<'a>) -> &mut Self { let expr_bit = match segment.elements { Elements::Expressions(..) => 0b100u32, Elements::Functions(_) => 0b000u32, }; let mut encode_type = false; match &segment.mode { ElementMode::Passive => { (0x01 | expr_bit).encode(&mut self.bytes); encode_type = true; } ElementMode::Active { table, offset } => { match (table, &segment.elements) { // If the `table` is not specified then the 0x00 encoding // can be used with either function indices or expressions // that have a `funcref` type. (None, Elements::Functions(_) | Elements::Expressions(RefType::FUNCREF, _)) => { (/* 0x00 | */expr_bit).encode(&mut self.bytes); } // ... otherwise fall through for all other expressions here // with table 0 or an explicitly specified table to the 0x02 // encoding. (None, Elements::Expressions(..)) | (Some(_), _) => { (0x02 | expr_bit).encode(&mut self.bytes); table.unwrap_or(0).encode(&mut self.bytes); encode_type = true; } } offset.encode(&mut self.bytes); } ElementMode::Declared => { (0x03 | expr_bit).encode(&mut self.bytes); encode_type = true; } } match segment.elements { Elements::Functions(fs) => { if encode_type { // elemkind == funcref self.bytes.push(0x00); } fs.encode(&mut self.bytes); } Elements::Expressions(ty, e) => { if encode_type { ty.encode(&mut self.bytes); } e.len().encode(&mut self.bytes); for expr in e.iter() { expr.encode(&mut self.bytes); } } } self.num_added += 1; self } /// Define an active element segment. /// /// `Active` element specifying a `None` table forces the MVP encoding and refers to the 0th /// table holding `funcref`s. Non-`None` tables use the encoding introduced with the bulk /// memory proposal and can refer to tables with any valid reference type. pub fn active( &mut self, table_index: Option, offset: &ConstExpr, elements: Elements<'_>, ) -> &mut Self { self.segment(ElementSegment { mode: ElementMode::Active { table: table_index, offset, }, elements, }) } /// Encode a passive element segment. /// /// Passive segments are part of the bulk memory proposal. pub fn passive<'a>(&mut self, elements: Elements<'a>) -> &mut Self { self.segment(ElementSegment { mode: ElementMode::Passive, elements, }) } /// Encode a declared element segment. /// /// Declared segments are part of the bulk memory proposal. pub fn declared<'a>(&mut self, elements: Elements<'a>) -> &mut Self { self.segment(ElementSegment { mode: ElementMode::Declared, elements, }) } /// Copy a raw, already-encoded element segment into this elements section. pub fn raw(&mut self, raw_bytes: &[u8]) -> &mut Self { self.bytes.extend_from_slice(raw_bytes); self.num_added += 1; self } } impl Encode for ElementSection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl Section for ElementSection { fn id(&self) -> u8 { SectionId::Element.into() } } wasm-encoder-0.239.0/src/core/exports.rs000064400000000000000000000041021046102023000161510ustar 00000000000000use super::{ CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT, CORE_TABLE_SORT, CORE_TAG_SORT, }; use crate::{Encode, Section, SectionId, encode_section}; use alloc::vec::Vec; /// Represents the kind of an export from a WebAssembly module. #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] #[repr(u8)] pub enum ExportKind { /// The export is a function. Func = CORE_FUNCTION_SORT, /// The export is a table. Table = CORE_TABLE_SORT, /// The export is a memory. Memory = CORE_MEMORY_SORT, /// The export is a global. Global = CORE_GLOBAL_SORT, /// The export is a tag. Tag = CORE_TAG_SORT, } impl Encode for ExportKind { fn encode(&self, sink: &mut Vec) { sink.push(*self as u8); } } /// An encoder for the export section of WebAssembly module. /// /// # Example /// /// ```rust /// use wasm_encoder::{Module, ExportSection, ExportKind}; /// /// let mut exports = ExportSection::new(); /// exports.export("foo", ExportKind::Func, 0); /// /// let mut module = Module::new(); /// module.section(&exports); /// /// let bytes = module.finish(); /// ``` #[derive(Clone, Debug, Default)] pub struct ExportSection { bytes: Vec, num_added: u32, } impl ExportSection { /// Create a new export section encoder. pub fn new() -> Self { Self::default() } /// The number of exports in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Define an export in the export section. pub fn export(&mut self, name: &str, kind: ExportKind, index: u32) -> &mut Self { name.encode(&mut self.bytes); kind.encode(&mut self.bytes); index.encode(&mut self.bytes); self.num_added += 1; self } } impl Encode for ExportSection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl Section for ExportSection { fn id(&self) -> u8 { SectionId::Export.into() } } wasm-encoder-0.239.0/src/core/functions.rs000064400000000000000000000030611046102023000164600ustar 00000000000000use crate::{Encode, Section, SectionId, encode_section}; use alloc::vec::Vec; /// An encoder for the function section of WebAssembly modules. /// /// # Example /// /// ``` /// use wasm_encoder::{Module, FunctionSection, ValType}; /// /// let mut functions = FunctionSection::new(); /// let type_index = 0; /// functions.function(type_index); /// /// let mut module = Module::new(); /// module.section(&functions); /// /// // Note: this will generate an invalid module because we didn't generate a /// // code section containing the function body. See the documentation for /// // `CodeSection` for details. /// /// let bytes = module.finish(); /// ``` #[derive(Clone, Debug, Default)] pub struct FunctionSection { bytes: Vec, num_added: u32, } impl FunctionSection { /// Construct a new module function section encoder. pub fn new() -> Self { Self::default() } /// The number of functions in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Define a function in a module's function section. pub fn function(&mut self, type_index: u32) -> &mut Self { type_index.encode(&mut self.bytes); self.num_added += 1; self } } impl Encode for FunctionSection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl Section for FunctionSection { fn id(&self) -> u8 { SectionId::Function.into() } } wasm-encoder-0.239.0/src/core/globals.rs000064400000000000000000000045471046102023000161050ustar 00000000000000use crate::{ConstExpr, Encode, Section, SectionId, ValType, encode_section}; use alloc::vec::Vec; /// An encoder for the global section. /// /// Global sections are only supported for modules. /// /// # Example /// /// ``` /// use wasm_encoder::{ConstExpr, Module, GlobalSection, GlobalType, Instruction, ValType}; /// /// let mut globals = GlobalSection::new(); /// globals.global( /// GlobalType { /// val_type: ValType::I32, /// mutable: false, /// shared: false, /// }, /// &ConstExpr::i32_const(42), /// ); /// /// let mut module = Module::new(); /// module.section(&globals); /// /// let wasm_bytes = module.finish(); /// ``` #[derive(Clone, Default, Debug)] pub struct GlobalSection { bytes: Vec, num_added: u32, } impl GlobalSection { /// Create a new global section encoder. pub fn new() -> Self { Self::default() } /// The number of globals in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Define a global. pub fn global(&mut self, global_type: GlobalType, init_expr: &ConstExpr) -> &mut Self { global_type.encode(&mut self.bytes); init_expr.encode(&mut self.bytes); self.num_added += 1; self } /// Add a raw byte slice into this code section as a global. pub fn raw(&mut self, data: &[u8]) -> &mut Self { self.bytes.extend(data); self.num_added += 1; self } } impl Encode for GlobalSection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl Section for GlobalSection { fn id(&self) -> u8 { SectionId::Global.into() } } /// A global's type. #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub struct GlobalType { /// This global's value type. pub val_type: ValType, /// Whether this global is mutable or not. pub mutable: bool, /// Whether this global is shared or not. pub shared: bool, } impl Encode for GlobalType { fn encode(&self, sink: &mut Vec) { self.val_type.encode(sink); let mut flag = 0; if self.mutable { flag |= 0b01; } if self.shared { flag |= 0b10; } sink.push(flag); } } wasm-encoder-0.239.0/src/core/imports.rs000064400000000000000000000064751046102023000161610ustar 00000000000000use crate::{ 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; /// The type of an entity. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum EntityType { /// A function type. /// /// The value is an index into the types section. Function(u32), /// A table type. Table(TableType), /// A memory type. Memory(MemoryType), /// A global type. Global(GlobalType), /// A tag type. /// /// This variant is used with the exception handling proposal. Tag(TagType), } impl Encode for EntityType { fn encode(&self, sink: &mut Vec) { match self { Self::Function(i) => { sink.push(CORE_FUNCTION_SORT); i.encode(sink); } Self::Table(t) => { sink.push(CORE_TABLE_SORT); t.encode(sink); } Self::Memory(t) => { sink.push(CORE_MEMORY_SORT); t.encode(sink); } Self::Global(t) => { sink.push(CORE_GLOBAL_SORT); t.encode(sink); } Self::Tag(t) => { sink.push(CORE_TAG_SORT); t.encode(sink); } } } } impl From for EntityType { fn from(t: TableType) -> Self { Self::Table(t) } } impl From for EntityType { fn from(t: MemoryType) -> Self { Self::Memory(t) } } impl From for EntityType { fn from(t: GlobalType) -> Self { Self::Global(t) } } impl From for EntityType { fn from(t: TagType) -> Self { Self::Tag(t) } } /// An encoder for the import section of WebAssembly modules. /// /// # Example /// /// ```rust /// use wasm_encoder::{MemoryType, Module, ImportSection}; /// /// let mut imports = ImportSection::new(); /// imports.import( /// "env", /// "memory", /// MemoryType { /// minimum: 1, /// maximum: None, /// memory64: false, /// shared: false, /// page_size_log2: None, /// } /// ); /// /// let mut module = Module::new(); /// module.section(&imports); /// /// let bytes = module.finish(); /// ``` #[derive(Clone, Debug, Default)] pub struct ImportSection { bytes: Vec, num_added: u32, } impl ImportSection { /// Create a new import section encoder. pub fn new() -> Self { Self::default() } /// The number of imports in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Define an import in the import section. pub fn import(&mut self, module: &str, field: &str, ty: impl Into) -> &mut Self { module.encode(&mut self.bytes); field.encode(&mut self.bytes); ty.into().encode(&mut self.bytes); self.num_added += 1; self } } impl Encode for ImportSection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl Section for ImportSection { fn id(&self) -> u8 { SectionId::Import.into() } } wasm-encoder-0.239.0/src/core/instructions.rs000064400000000000000000003623211046102023000172230ustar 00000000000000#[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, } impl<'a> InstructionSink<'a> { /// Create an instruction encoder pointing to the given byte sink. pub fn new(sink: &'a mut Vec) -> 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>(&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>( &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::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>( &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>( &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 } } wasm-encoder-0.239.0/src/core/linking.rs000064400000000000000000000203661046102023000161120ustar 00000000000000use crate::{CustomSection, Encode, Section, SectionId, encode_section}; use alloc::borrow::Cow; use alloc::vec; use alloc::vec::Vec; const VERSION: u32 = 2; /// An encoder for the [linking custom /// section](https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md#linking-metadata-section). /// /// This section is a non-standard convention that is supported by the LLVM /// toolchain. It, along with associated "reloc.*" custom sections, allows you /// to treat a Wasm module as a low-level object file that can be linked with /// other Wasm object files to produce a final, complete Wasm module. /// /// The linking section must come before the reloc sections. /// /// # Example /// /// ``` /// use wasm_encoder::{LinkingSection, Module, SymbolTable}; /// /// // Create a new linking section. /// let mut linking = LinkingSection::new(); /// /// // Define a symbol table. /// let mut sym_tab = SymbolTable::new(); /// /// // Define a function symbol in the symbol table. /// let flags = SymbolTable::WASM_SYM_BINDING_LOCAL | SymbolTable::WASM_SYM_EXPORTED; /// let func_index = 42; /// let sym_name = "my_exported_func"; /// sym_tab.function(flags, func_index, Some(sym_name)); /// /// // Add the symbol table to our linking section. /// linking.symbol_table(&sym_tab); /// /// // Add the linking section to a new Wasm module and get the encoded bytes. /// let mut module = Module::new(); /// module.section(&linking); /// let wasm_bytes = module.finish(); /// ``` #[derive(Clone, Debug)] pub struct LinkingSection { bytes: Vec, } impl LinkingSection { /// Construct a new encoder for the linking custom section. pub fn new() -> Self { Self::default() } // TODO: `fn segment_info` for the `WASM_SEGMENT_INFO` linking subsection. // TODO: `fn init_funcs` for the `WASM_INIT_FUNCS` linking subsection. // TODO: `fn comdat_info` for the `WASM_COMDAT_INFO` linking subsection. /// Add a symbol table subsection. pub fn symbol_table(&mut self, symbol_table: &SymbolTable) -> &mut Self { symbol_table.encode(&mut self.bytes); self } } impl Default for LinkingSection { fn default() -> Self { let mut bytes = Vec::new(); VERSION.encode(&mut bytes); Self { bytes } } } impl Encode for LinkingSection { fn encode(&self, sink: &mut Vec) { CustomSection { name: "linking".into(), data: Cow::Borrowed(&self.bytes), } .encode(sink); } } impl Section for LinkingSection { fn id(&self) -> u8 { SectionId::Custom.into() } } #[allow(unused)] const WASM_SEGMENT_INFO: u8 = 5; #[allow(unused)] const WASM_INIT_FUNCS: u8 = 6; #[allow(unused)] const WASM_COMDAT_INFO: u8 = 7; const WASM_SYMBOL_TABLE: u8 = 8; /// A subsection of the [linking custom section][crate::LinkingSection] that /// provides extra information about the symbols present in this Wasm object /// file. #[derive(Clone, Debug, Default)] pub struct SymbolTable { bytes: Vec, num_added: u32, } const SYMTAB_FUNCTION: u32 = 0; const SYMTAB_DATA: u32 = 1; const SYMTAB_GLOBAL: u32 = 2; #[allow(unused)] const SYMTAB_SECTION: u32 = 3; #[allow(unused)] const SYMTAB_TAG: u32 = 4; const SYMTAB_TABLE: u32 = 5; impl SymbolTable { /// Construct a new symbol table subsection encoder. pub fn new() -> Self { SymbolTable { bytes: vec![], num_added: 0, } } /// Define a function symbol in this symbol table. /// /// The `name` must be omitted if `index` references an imported table and /// the `WASM_SYM_EXPLICIT_NAME` flag is not set. pub fn function(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self { SYMTAB_FUNCTION.encode(&mut self.bytes); flags.encode(&mut self.bytes); index.encode(&mut self.bytes); if let Some(name) = name { name.encode(&mut self.bytes); } self.num_added += 1; self } /// Define a global symbol in this symbol table. /// /// The `name` must be omitted if `index` references an imported table and /// the `WASM_SYM_EXPLICIT_NAME` flag is not set. pub fn global(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self { SYMTAB_GLOBAL.encode(&mut self.bytes); flags.encode(&mut self.bytes); index.encode(&mut self.bytes); if let Some(name) = name { name.encode(&mut self.bytes); } self.num_added += 1; self } // TODO: tags /// Define a table symbol in this symbol table. /// /// The `name` must be omitted if `index` references an imported table and /// the `WASM_SYM_EXPLICIT_NAME` flag is not set. pub fn table(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self { SYMTAB_TABLE.encode(&mut self.bytes); flags.encode(&mut self.bytes); index.encode(&mut self.bytes); if let Some(name) = name { name.encode(&mut self.bytes); } self.num_added += 1; self } /// Add a data symbol to this symbol table. pub fn data( &mut self, flags: u32, name: &str, definition: Option, ) -> &mut Self { SYMTAB_DATA.encode(&mut self.bytes); flags.encode(&mut self.bytes); name.encode(&mut self.bytes); if let Some(def) = definition { def.index.encode(&mut self.bytes); def.offset.encode(&mut self.bytes); def.size.encode(&mut self.bytes); } self.num_added += 1; self } // TODO: sections /// This is a weak symbol. /// /// This flag is mutually exclusive with `WASM_SYM_BINDING_LOCAL`. /// /// When linking multiple modules defining the same symbol, all weak /// definitions are discarded if any strong definitions exist; then if /// multiple weak definitions exist all but one (unspecified) are discarded; /// and finally it is an error if more than one definition remains. pub const WASM_SYM_BINDING_WEAK: u32 = 0x1; /// This is a local symbol. /// /// This flag is mutually exclusive with `WASM_SYM_BINDING_WEAK`. /// /// Local symbols are not to be exported, or linked to other /// modules/sections. The names of all non-local symbols must be unique, but /// the names of local symbols are not considered for uniqueness. A local /// function or global symbol cannot reference an import. pub const WASM_SYM_BINDING_LOCAL: u32 = 0x02; /// This is a hidden symbol. /// /// Hidden symbols are not to be exported when performing the final link, /// but may be linked to other modules. pub const WASM_SYM_VISIBILITY_HIDDEN: u32 = 0x04; /// This symbol is not defined. /// /// For non-data symbols, this must match whether the symbol is an import or /// is defined; for data symbols, determines whether a segment is specified. pub const WASM_SYM_UNDEFINED: u32 = 0x10; /// This symbol is intended to be exported from the wasm module to the host /// environment. /// /// This differs from the visibility flags in that it effects the static /// linker. pub const WASM_SYM_EXPORTED: u32 = 0x20; /// This symbol uses an explicit symbol name, rather than reusing the name /// from a wasm import. /// /// This allows it to remap imports from foreign WebAssembly modules into /// local symbols with different names. pub const WASM_SYM_EXPLICIT_NAME: u32 = 0x40; /// This symbol is intended to be included in the linker output, regardless /// of whether it is used by the program. pub const WASM_SYM_NO_STRIP: u32 = 0x80; } impl Encode for SymbolTable { fn encode(&self, sink: &mut Vec) { sink.push(WASM_SYMBOL_TABLE); encode_section(sink, self.num_added, &self.bytes); } } /// The definition of a data symbol within a symbol table. #[derive(Clone, Debug)] pub struct DataSymbolDefinition { /// The index of the data segment that this symbol is in. pub index: u32, /// The offset of this symbol within its segment. pub offset: u32, /// The byte size (which can be zero) of this data symbol. /// /// Note that `offset + size` must be less than or equal to the segment's /// size. pub size: u32, } wasm-encoder-0.239.0/src/core/memories.rs000064400000000000000000000056571046102023000163050ustar 00000000000000use crate::{Encode, Section, SectionId, encode_section}; use alloc::vec::Vec; /// An encoder for the memory section. /// /// Memory sections are only supported for modules. /// /// # Example /// /// ``` /// use wasm_encoder::{Module, MemorySection, MemoryType}; /// /// let mut memories = MemorySection::new(); /// memories.memory(MemoryType { /// minimum: 1, /// maximum: None, /// memory64: false, /// shared: false, /// page_size_log2: None, /// }); /// /// let mut module = Module::new(); /// module.section(&memories); /// /// let wasm_bytes = module.finish(); /// ``` #[derive(Clone, Default, Debug)] pub struct MemorySection { bytes: Vec, num_added: u32, } impl MemorySection { /// Create a new memory section encoder. pub fn new() -> Self { Self::default() } /// The number of memories in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Define a memory. pub fn memory(&mut self, memory_type: MemoryType) -> &mut Self { memory_type.encode(&mut self.bytes); self.num_added += 1; self } } impl Encode for MemorySection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl Section for MemorySection { fn id(&self) -> u8 { SectionId::Memory.into() } } /// A memory's type. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct MemoryType { /// Minimum size, in pages, of this memory pub minimum: u64, /// Maximum size, in pages, of this memory pub maximum: Option, /// Whether or not this is a 64-bit memory. pub memory64: bool, /// Whether or not this memory is shared. pub shared: bool, /// The log base 2 of a custom page size for this memory. /// /// The default page size for Wasm memories is 64KiB, i.e. 216 or /// `65536`. /// /// After the introduction of [the custom-page-sizes /// proposal](https://github.com/WebAssembly/custom-page-sizes), Wasm can /// customize the page size. It must be a power of two that is less than or /// equal to 64KiB. Attempting to encode an invalid page size may panic. pub page_size_log2: Option, } impl Encode for MemoryType { fn encode(&self, sink: &mut Vec) { let mut flags = 0; if self.maximum.is_some() { flags |= 0b0001; } if self.shared { flags |= 0b0010; } if self.memory64 { flags |= 0b0100; } if self.page_size_log2.is_some() { flags |= 0b1000; } sink.push(flags); self.minimum.encode(sink); if let Some(max) = self.maximum { max.encode(sink); } if let Some(p) = self.page_size_log2 { p.encode(sink); } } } wasm-encoder-0.239.0/src/core/names.rs000064400000000000000000000233141046102023000155560ustar 00000000000000use crate::{CustomSection, Encode, Section, SectionId, encoding_size}; use alloc::borrow::Cow; use alloc::vec; use alloc::vec::Vec; /// An encoder for the custom `name` section. /// /// # Example /// /// ``` /// use wasm_encoder::{Module, NameSection, NameMap}; /// /// let mut names = NameSection::new(); /// names.module("the module name"); /// /// let mut function_names = NameMap::new(); /// function_names.append(0, "name of function 0"); /// function_names.append(1, "a better function"); /// function_names.append(3, "the best function"); /// names.functions(&function_names); /// /// let mut module = Module::new(); /// module.section(&names); /// /// let wasm_bytes = module.finish(); /// ``` #[derive(Clone, Debug, Default)] pub struct NameSection { bytes: Vec, } enum Subsection { // Currently specified in the wasm spec's appendix Module = 0, Function = 1, Local = 2, // specified as part of the extended name section proposal // // https://github.com/WebAssembly/extended-name-section/blob/main/proposals/extended-name-section/Overview.md Label = 3, Type = 4, Table = 5, Memory = 6, Global = 7, Element = 8, Data = 9, // https://github.com/WebAssembly/gc/issues/193 Field = 10, // https://github.com/WebAssembly/exception-handling/pull/213 Tag = 11, } impl NameSection { /// Creates a new blank `name` custom section. pub fn new() -> Self { Self::default() } /// Appends a module name subsection to this section. /// /// This will indicate that the name of the entire module should be the /// `name` specified. Note that this should be encoded first before other /// subsections. pub fn module(&mut self, name: &str) { let len = encoding_size(u32::try_from(name.len()).unwrap()); self.subsection_header(Subsection::Module, len + name.len()); name.encode(&mut self.bytes); } /// Appends a subsection for the names of all functions in this wasm module. /// /// Function names are declared in the `names` map provided where the index /// in the map corresponds to the wasm index of the function. This section /// should come after the module name subsection (if present) and before the /// locals subsection (if present). pub fn functions(&mut self, names: &NameMap) { self.subsection_header(Subsection::Function, names.size()); names.encode(&mut self.bytes); } /// Appends a subsection for the names of locals within functions in this /// wasm module. /// /// This section should come after the function name subsection (if present) /// and before the labels subsection (if present). pub fn locals(&mut self, names: &IndirectNameMap) { self.subsection_header(Subsection::Local, names.size()); names.encode(&mut self.bytes); } /// Appends a subsection for the names of labels within functions in this /// wasm module. /// /// This section should come after the local name subsection (if present) /// and before the type subsection (if present). pub fn labels(&mut self, names: &IndirectNameMap) { self.subsection_header(Subsection::Label, names.size()); names.encode(&mut self.bytes); } /// Appends a subsection for the names of all types in this wasm module. /// /// This section should come after the label name subsection (if present) /// and before the table subsection (if present). pub fn types(&mut self, names: &NameMap) { self.subsection_header(Subsection::Type, names.size()); names.encode(&mut self.bytes); } /// Appends a subsection for the names of all tables in this wasm module. /// /// This section should come after the type name subsection (if present) /// and before the memory subsection (if present). pub fn tables(&mut self, names: &NameMap) { self.subsection_header(Subsection::Table, names.size()); names.encode(&mut self.bytes); } /// Appends a subsection for the names of all memories in this wasm module. /// /// This section should come after the table name subsection (if present) /// and before the global subsection (if present). pub fn memories(&mut self, names: &NameMap) { self.subsection_header(Subsection::Memory, names.size()); names.encode(&mut self.bytes); } /// Appends a subsection for the names of all globals in this wasm module. /// /// This section should come after the memory name subsection (if present) /// and before the element subsection (if present). pub fn globals(&mut self, names: &NameMap) { self.subsection_header(Subsection::Global, names.size()); names.encode(&mut self.bytes); } /// Appends a subsection for the names of all elements in this wasm module. /// /// This section should come after the global name subsection (if present) /// and before the data subsection (if present). pub fn elements(&mut self, names: &NameMap) { self.subsection_header(Subsection::Element, names.size()); names.encode(&mut self.bytes); } /// Appends a subsection for the names of all data in this wasm module. /// /// This section should come after the element name subsection (if present) /// and before the field subsection (if present). pub fn data(&mut self, names: &NameMap) { self.subsection_header(Subsection::Data, names.size()); names.encode(&mut self.bytes); } /// Appends a subsection for the names of all tags in this wasm module. /// /// This section should come after the data name subsection (if present). pub fn tag(&mut self, names: &NameMap) { self.subsection_header(Subsection::Tag, names.size()); names.encode(&mut self.bytes); } /// Appends a subsection for the names of fields within types in this /// wasm module. /// /// This section should come after the data name subsection (if present) /// and before the tag subsection (if present). pub fn fields(&mut self, names: &IndirectNameMap) { self.subsection_header(Subsection::Field, names.size()); names.encode(&mut self.bytes); } /// Appends a subsection for the names of all tags in this wasm module. /// /// This section should come after the field name subsection (if present). pub fn tags(&mut self, names: &NameMap) { self.subsection_header(Subsection::Tag, names.size()); names.encode(&mut self.bytes); } /// Appends a raw subsection with the given id and data. pub fn raw(&mut self, id: u8, data: &[u8]) { self.bytes.push(id); data.encode(&mut self.bytes); } fn subsection_header(&mut self, id: Subsection, len: usize) { self.bytes.push(id as u8); len.encode(&mut self.bytes); } /// View the encoded section as a CustomSection. pub fn as_custom<'a>(&'a self) -> CustomSection<'a> { CustomSection { name: "name".into(), data: Cow::Borrowed(&self.bytes), } } } impl Encode for NameSection { fn encode(&self, sink: &mut Vec) { self.as_custom().encode(sink); } } impl Section for NameSection { fn id(&self) -> u8 { SectionId::Custom.into() } } /// A map used to name items in a wasm module, organized by naming each /// individual index. /// /// This is used in conjunction with [`NameSection::functions`] and simlar /// methods. #[derive(Clone, Debug, Default)] pub struct NameMap { bytes: Vec, count: u32, } impl NameMap { /// Creates a new empty `NameMap`. pub fn new() -> NameMap { NameMap { bytes: vec![], count: 0, } } /// Adds a an entry where the item at `idx` has the `name` specified. /// /// Note that indices should be appended in ascending order of the index /// value. Each index may only be named once, but not all indices must be /// named (e.g. `0 foo; 1 bar; 7 qux` is valid but `0 foo; 0 bar` is not). /// Names do not have to be unique (e.g. `0 foo; 1 foo; 2 foo` is valid). pub fn append(&mut self, idx: u32, name: &str) { idx.encode(&mut self.bytes); name.encode(&mut self.bytes); self.count += 1; } pub(crate) fn size(&self) -> usize { encoding_size(self.count) + self.bytes.len() } /// Returns whether no names have been added to this map. pub fn is_empty(&self) -> bool { self.count == 0 } } impl Encode for NameMap { fn encode(&self, sink: &mut Vec) { self.count.encode(sink); sink.extend(&self.bytes); } } /// A map used to describe names with two levels of indirection, as opposed to a /// [`NameMap`] which has one level of indirection. /// /// This naming map is used with [`NameSection::locals`], for example. #[derive(Clone, Debug, Default)] pub struct IndirectNameMap { bytes: Vec, count: u32, } impl IndirectNameMap { /// Creates a new empty name map. pub fn new() -> IndirectNameMap { IndirectNameMap { bytes: vec![], count: 0, } } /// Adds a new entry where the item at `idx` has sub-items named within /// `names` as specified. /// /// For example if this is describing local names then `idx` is a function /// index where the indexes within `names` are local indices. pub fn append(&mut self, idx: u32, names: &NameMap) { idx.encode(&mut self.bytes); names.encode(&mut self.bytes); self.count += 1; } fn size(&self) -> usize { encoding_size(self.count) + self.bytes.len() } } impl Encode for IndirectNameMap { fn encode(&self, sink: &mut Vec) { self.count.encode(sink); sink.extend(&self.bytes); } } wasm-encoder-0.239.0/src/core/producers.rs000064400000000000000000000125621046102023000164640ustar 00000000000000use crate::{CustomSection, Encode, Section, SectionId}; use alloc::borrow::Cow; use alloc::vec::Vec; /// An encoder for the [producers custom /// section](https://github.com/WebAssembly/tool-conventions/blob/main/ProducersSection.md). /// /// This section is a non-standard convention that is supported by many toolchains. /// /// # Example /// /// ``` /// use wasm_encoder::{ProducersSection, ProducersField, Module}; /// /// // Create a new producers section. /// let mut field = ProducersField::new(); /// field.value("clang", "14.0.4"); /// field.value("rustc", "1.66.1 (90743e729 2023-01-10)"); /// let mut producers = ProducersSection::new(); /// producers.field("processed-by", &field); /// /// // Add the producers section to a new Wasm module and get the encoded bytes. /// let mut module = Module::new(); /// module.section(&producers); /// let wasm_bytes = module.finish(); /// ``` #[derive(Clone, Debug)] pub struct ProducersSection { bytes: Vec, num_fields: u32, } impl ProducersSection { /// Construct an empty encoder for the producers custom section. pub fn new() -> Self { Self::default() } /// Add a field to the section. The spec recommends names for this section /// are "language", "processed-by", and "sdk". Each field in section must /// have a unique name. pub fn field(&mut self, name: &str, values: &ProducersField) -> &mut Self { name.encode(&mut self.bytes); values.encode(&mut self.bytes); self.num_fields += 1; self } } impl Default for ProducersSection { fn default() -> Self { Self { bytes: Vec::new(), num_fields: 0, } } } impl Encode for ProducersSection { fn encode(&self, sink: &mut Vec) { let mut data = Vec::new(); self.num_fields.encode(&mut data); data.extend(&self.bytes); CustomSection { name: "producers".into(), data: Cow::Borrowed(&data), } .encode(sink); } } impl Section for ProducersSection { fn id(&self) -> u8 { SectionId::Custom.into() } } /// The value of a field in the producers custom section #[derive(Clone, Debug)] pub struct ProducersField { bytes: Vec, num_values: u32, } impl ProducersField { /// Construct an empty encoder for a producers field value pub fn new() -> Self { ProducersField::default() } /// Add a value to the field encoder. Each value in a field must have a /// unique name. If there is no sensible value for `version`, use the /// empty string. pub fn value(&mut self, name: &str, version: &str) -> &mut Self { name.encode(&mut self.bytes); version.encode(&mut self.bytes); self.num_values += 1; self } } impl Default for ProducersField { fn default() -> Self { Self { bytes: Vec::new(), num_values: 0, } } } impl Encode for ProducersField { fn encode(&self, sink: &mut Vec) { self.num_values.encode(sink); sink.extend(&self.bytes); } } #[cfg(test)] mod test { #[test] fn roundtrip_example() { use crate::{Module, ProducersField, ProducersSection}; use wasmparser::{KnownCustom, Parser, Payload}; // Create a new producers section. let mut field = ProducersField::new(); field.value("clang", "14.0.4"); field.value("rustc", "1.66.1"); let mut producers = ProducersSection::new(); producers.field("processed-by", &field); // Add the producers section to a new Wasm module and get the encoded bytes. let mut module = Module::new(); module.section(&producers); let wasm_bytes = module.finish(); let mut parser = Parser::new(0).parse_all(&wasm_bytes); let payload = parser .next() .expect("parser is not empty") .expect("element is a payload"); match payload { Payload::Version { .. } => {} _ => panic!(""), } let payload = parser .next() .expect("parser is not empty") .expect("element is a payload"); match payload { Payload::CustomSection(c) => { assert_eq!(c.name(), "producers"); let mut section = match c.as_known() { KnownCustom::Producers(s) => s.into_iter(), _ => panic!("unknown custom section"), }; let field = section .next() .expect("section has an element") .expect("element is a producers field"); assert_eq!(field.name, "processed-by"); let mut values = field.values.into_iter(); let value = values .next() .expect("values has an element") .expect("element is a producers field value"); assert_eq!(value.name, "clang"); assert_eq!(value.version, "14.0.4"); let value = values .next() .expect("values has another element") .expect("element is a producers field value"); assert_eq!(value.name, "rustc"); assert_eq!(value.version, "1.66.1"); } _ => panic!("unexpected payload"), } } } wasm-encoder-0.239.0/src/core/start.rs000064400000000000000000000020341046102023000156040ustar 00000000000000use crate::{Encode, Section, SectionId, encoding_size}; use alloc::vec::Vec; /// An encoder for the start section of WebAssembly modules. /// /// # Example /// /// Note: this doesn't actually define the function at index 0, its type, or its /// code body, so the resulting Wasm module will be invalid. See `TypeSection`, /// `FunctionSection`, and `CodeSection` for details on how to generate those /// things. /// /// ``` /// use wasm_encoder::{Module, StartSection}; /// /// let start = StartSection { function_index: 0 }; /// /// let mut module = Module::new(); /// module.section(&start); /// /// let wasm_bytes = module.finish(); /// ``` #[derive(Clone, Copy, Debug)] pub struct StartSection { /// The index of the start function. pub function_index: u32, } impl Encode for StartSection { fn encode(&self, sink: &mut Vec) { encoding_size(self.function_index).encode(sink); self.function_index.encode(sink); } } impl Section for StartSection { fn id(&self) -> u8 { SectionId::Start.into() } } wasm-encoder-0.239.0/src/core/tables.rs000064400000000000000000000061431046102023000157260ustar 00000000000000use crate::{ConstExpr, Encode, RefType, Section, SectionId, ValType, encode_section}; use alloc::vec::Vec; /// An encoder for the table section. /// /// Table sections are only supported for modules. /// /// # Example /// /// ``` /// use wasm_encoder::{Module, TableSection, TableType, RefType}; /// /// let mut tables = TableSection::new(); /// tables.table(TableType { /// element_type: RefType::FUNCREF, /// minimum: 128, /// maximum: None, /// table64: false, /// shared: false, /// }); /// /// let mut module = Module::new(); /// module.section(&tables); /// /// let wasm_bytes = module.finish(); /// ``` #[derive(Clone, Default, Debug)] pub struct TableSection { bytes: Vec, num_added: u32, } impl TableSection { /// Construct a new table section encoder. pub fn new() -> Self { Self::default() } /// The number of tables in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Define a table. pub fn table(&mut self, table_type: TableType) -> &mut Self { table_type.encode(&mut self.bytes); self.num_added += 1; self } /// Define a table with an explicit initialization expression. /// /// Note that this is part of the function-references proposal. pub fn table_with_init(&mut self, table_type: TableType, init: &ConstExpr) -> &mut Self { self.bytes.push(0x40); self.bytes.push(0x00); table_type.encode(&mut self.bytes); init.encode(&mut self.bytes); self.num_added += 1; self } } impl Encode for TableSection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl Section for TableSection { fn id(&self) -> u8 { SectionId::Table.into() } } /// A table's type. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct TableType { /// The table's element type. pub element_type: RefType, /// Whether or not this is a 64-bit table. pub table64: bool, /// Minimum size, in elements, of this table pub minimum: u64, /// Maximum size, in elements, of this table pub maximum: Option, /// Whether this table is shared or not. /// /// This is included the shared-everything-threads proposal. pub shared: bool, } impl TableType { /// Returns the type used to index this table. pub fn index_type(&self) -> ValType { if self.table64 { ValType::I64 } else { ValType::I32 } } } impl Encode for TableType { fn encode(&self, sink: &mut Vec) { let mut flags = 0; if self.maximum.is_some() { flags |= 0b001; } if self.shared { flags |= 0b010; } if self.table64 { flags |= 0b100; } self.element_type.encode(sink); sink.push(flags); self.minimum.encode(sink); if let Some(max) = self.maximum { max.encode(sink); } } } wasm-encoder-0.239.0/src/core/tags.rs000064400000000000000000000034411046102023000154100ustar 00000000000000use crate::{Encode, Section, SectionId, encode_section}; use alloc::vec::Vec; /// An encoder for the tag section. /// /// # Example /// /// ``` /// use wasm_encoder::{Module, TagSection, TagType, TagKind}; /// /// let mut tags = TagSection::new(); /// tags.tag(TagType { /// kind: TagKind::Exception, /// func_type_idx: 0, /// }); /// /// let mut module = Module::new(); /// module.section(&tags); /// /// let wasm_bytes = module.finish(); /// ``` #[derive(Clone, Default, Debug)] pub struct TagSection { bytes: Vec, num_added: u32, } impl TagSection { /// Create a new tag section encoder. pub fn new() -> Self { Self::default() } /// The number of tags in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Define a tag. pub fn tag(&mut self, tag_type: TagType) -> &mut Self { tag_type.encode(&mut self.bytes); self.num_added += 1; self } } impl Encode for TagSection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl Section for TagSection { fn id(&self) -> u8 { SectionId::Tag.into() } } /// Represents a tag kind. #[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum TagKind { /// The tag is an exception type. Exception = 0x0, } /// A tag's type. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct TagType { /// The kind of tag pub kind: TagKind, /// The function type this tag uses pub func_type_idx: u32, } impl Encode for TagType { fn encode(&self, sink: &mut Vec) { sink.push(self.kind as u8); self.func_type_idx.encode(sink); } } wasm-encoder-0.239.0/src/core/types.rs000064400000000000000000000512511046102023000156200ustar 00000000000000use crate::{Encode, Section, SectionId, encode_section}; use alloc::boxed::Box; use alloc::vec::Vec; /// Represents a subtype of possible other types in a WebAssembly module. #[derive(Debug, Clone)] pub struct SubType { /// Is the subtype final. pub is_final: bool, /// The list of supertype indexes. As of GC MVP, there can be at most one /// supertype. pub supertype_idx: Option, /// The composite type of the subtype. pub composite_type: CompositeType, } /// Represents a composite type in a WebAssembly module. #[derive(Debug, Clone)] pub struct CompositeType { /// The type defined inside the composite type. pub inner: CompositeInnerType, /// Whether the type is shared. This is part of the /// shared-everything-threads proposal. pub shared: bool, } /// A [`CompositeType`] can contain one of these types. #[derive(Debug, Clone)] pub enum CompositeInnerType { /// The type is for a function. Func(FuncType), /// The type is for an array. Array(ArrayType), /// The type is for a struct. Struct(StructType), /// The type is for a continuation. Cont(ContType), } /// Represents a type of a function in a WebAssembly module. #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct FuncType { /// The combined parameters and result types. params_results: Box<[ValType]>, /// The number of parameter types. len_params: usize, } /// Represents a type of an array in a WebAssembly module. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub struct ArrayType(pub FieldType); /// Represents a type of a struct in a WebAssembly module. #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct StructType { /// Struct fields. pub fields: Box<[FieldType]>, } /// Field type in composite types (structs, arrays). #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct FieldType { /// Storage type of the field. pub element_type: StorageType, /// Is the field mutable. pub mutable: bool, } /// Storage type for composite type fields. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] pub enum StorageType { /// The `i8` type. I8, /// The `i16` type. I16, /// A value type. Val(ValType), } impl StorageType { /// Is this storage type defaultable? pub fn is_defaultable(&self) -> bool { self.unpack().is_defaultable() } /// Unpack this storage type into a value type. pub fn unpack(&self) -> ValType { match self { StorageType::I8 | StorageType::I16 => ValType::I32, StorageType::Val(v) => *v, } } } /// Represents a type of a continuation in a WebAssembly module. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub struct ContType(pub u32); /// The type of a core WebAssembly value. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] pub enum ValType { /// The `i32` type. I32, /// The `i64` type. I64, /// The `f32` type. F32, /// The `f64` type. F64, /// The `v128` type. /// /// Part of the SIMD proposal. V128, /// A reference type. /// /// The `funcref` and `externref` type fall into this category and the full /// generalization here is due to the implementation of the /// function-references proposal. Ref(RefType), } impl ValType { /// Is this a numeric value type? pub fn is_numeric(&self) -> bool { match self { ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => true, ValType::V128 | ValType::Ref(_) => false, } } /// Is this a vector type? pub fn is_vector(&self) -> bool { match self { ValType::V128 => true, ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::Ref(_) => false, } } /// Is this a reference type? pub fn is_reference(&self) -> bool { match self { ValType::Ref(_) => true, ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => false, } } } impl FuncType { /// Creates a new [`FuncType`] from the given `params` and `results`. pub fn new(params: P, results: R) -> Self where P: IntoIterator, R: IntoIterator, { let mut buffer = params.into_iter().collect::>(); let len_params = buffer.len(); buffer.extend(results); Self::from_parts(buffer.into(), len_params) } #[inline] pub(crate) fn from_parts(params_results: Box<[ValType]>, len_params: usize) -> Self { Self { params_results, len_params, } } /// Returns a shared slice to the parameter types of the [`FuncType`]. #[inline] pub fn params(&self) -> &[ValType] { &self.params_results[..self.len_params] } /// Returns a shared slice to the result types of the [`FuncType`]. #[inline] pub fn results(&self) -> &[ValType] { &self.params_results[self.len_params..] } } impl ValType { /// Alias for the `funcref` type in WebAssembly pub const FUNCREF: ValType = ValType::Ref(RefType::FUNCREF); /// Alias for the `externref` type in WebAssembly pub const EXTERNREF: ValType = ValType::Ref(RefType::EXTERNREF); /// Alias for the `exnref` type in WebAssembly pub const EXNREF: ValType = ValType::Ref(RefType::EXNREF); /// Is this value defaultable? pub fn is_defaultable(&self) -> bool { match self { ValType::Ref(r) => r.nullable, ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => true, } } } impl Encode for StorageType { fn encode(&self, sink: &mut Vec) { match self { StorageType::I8 => sink.push(0x78), StorageType::I16 => sink.push(0x77), StorageType::Val(vt) => vt.encode(sink), } } } impl Encode for ValType { fn encode(&self, sink: &mut Vec) { match self { ValType::I32 => sink.push(0x7F), ValType::I64 => sink.push(0x7E), ValType::F32 => sink.push(0x7D), ValType::F64 => sink.push(0x7C), ValType::V128 => sink.push(0x7B), ValType::Ref(rt) => rt.encode(sink), } } } /// A reference type. /// /// This is largely part of the function references proposal for WebAssembly but /// additionally is used by the `funcref` and `externref` types. The full /// generality of this type is only exercised with function-references. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] #[allow(missing_docs)] pub struct RefType { pub nullable: bool, pub heap_type: HeapType, } impl RefType { /// Alias for the `anyref` type in WebAssembly. pub const ANYREF: RefType = RefType { nullable: true, heap_type: HeapType::Abstract { shared: false, ty: AbstractHeapType::Any, }, }; /// Alias for the `anyref` type in WebAssembly. pub const EQREF: RefType = RefType { nullable: true, heap_type: HeapType::Abstract { shared: false, ty: AbstractHeapType::Eq, }, }; /// Alias for the `funcref` type in WebAssembly. pub const FUNCREF: RefType = RefType { nullable: true, heap_type: HeapType::Abstract { shared: false, ty: AbstractHeapType::Func, }, }; /// Alias for the `externref` type in WebAssembly. pub const EXTERNREF: RefType = RefType { nullable: true, heap_type: HeapType::Abstract { shared: false, ty: AbstractHeapType::Extern, }, }; /// Alias for the `i31ref` type in WebAssembly. pub const I31REF: RefType = RefType { nullable: true, heap_type: HeapType::Abstract { shared: false, ty: AbstractHeapType::I31, }, }; /// Alias for the `arrayref` type in WebAssembly. pub const ARRAYREF: RefType = RefType { nullable: true, heap_type: HeapType::Abstract { shared: false, ty: AbstractHeapType::Array, }, }; /// Alias for the `exnref` type in WebAssembly. pub const EXNREF: RefType = RefType { nullable: true, heap_type: HeapType::Abstract { shared: false, ty: AbstractHeapType::Exn, }, }; /// Create a new abstract reference type. pub fn new_abstract(ty: AbstractHeapType, nullable: bool, shared: bool) -> Self { Self { nullable, heap_type: HeapType::Abstract { shared, ty }, } } /// Set the nullability of this reference type. pub fn nullable(mut self, nullable: bool) -> Self { self.nullable = nullable; self } } impl Encode for RefType { fn encode(&self, sink: &mut Vec) { match self { // Binary abbreviations (i.e., short form), for when the ref is // nullable. RefType { nullable: true, heap_type: heap @ HeapType::Abstract { .. }, } => { heap.encode(sink); } // Generic 'ref null ' encoding (i.e., long form). RefType { nullable: true, heap_type, } => { sink.push(0x63); heap_type.encode(sink); } // Generic 'ref ' encoding. RefType { nullable: false, heap_type, } => { sink.push(0x64); heap_type.encode(sink); } } } } impl From for ValType { fn from(ty: RefType) -> ValType { ValType::Ref(ty) } } /// Part of the function references proposal. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] pub enum HeapType { /// An abstract heap type; e.g., `anyref`. Abstract { /// Whether the type is shared. shared: bool, /// The actual heap type. ty: AbstractHeapType, }, /// A concrete Wasm-defined type at the given index. Concrete(u32), } impl HeapType { /// Alias for the unshared `any` heap type. pub const ANY: Self = Self::Abstract { shared: false, ty: AbstractHeapType::Any, }; /// Alias for the unshared `func` heap type. pub const FUNC: Self = Self::Abstract { shared: false, ty: AbstractHeapType::Func, }; /// Alias for the unshared `extern` heap type. pub const EXTERN: Self = Self::Abstract { shared: false, ty: AbstractHeapType::Extern, }; /// Alias for the unshared `i31` heap type. pub const I31: Self = Self::Abstract { shared: false, ty: AbstractHeapType::I31, }; } impl Encode for HeapType { fn encode(&self, sink: &mut Vec) { match self { HeapType::Abstract { shared, ty } => { if *shared { sink.push(0x65); } ty.encode(sink); } // 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), } } } /// An abstract heap type. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] pub enum AbstractHeapType { /// Untyped (any) function. Func, /// The abstract external heap type. Extern, /// The abstract `any` heap type. /// /// The common supertype (a.k.a. top) of all internal types. Any, /// The abstract `none` heap type. /// /// The common subtype (a.k.a. bottom) of all internal types. None, /// The abstract `noextern` heap type. /// /// The common subtype (a.k.a. bottom) of all external types. NoExtern, /// The abstract `nofunc` heap type. /// /// The common subtype (a.k.a. bottom) of all function types. NoFunc, /// The abstract `eq` heap type. /// /// The common supertype of all referenceable types on which comparison /// (ref.eq) is allowed. Eq, /// The abstract `struct` heap type. /// /// The common supertype of all struct types. Struct, /// The abstract `array` heap type. /// /// The common supertype of all array types. Array, /// The unboxed `i31` heap type. I31, /// The abstract `exception` heap type. Exn, /// The abstract `noexn` heap type. NoExn, /// The abstract `cont` heap type. Cont, /// The abstract `nocont` heap type. NoCont, } impl Encode for AbstractHeapType { fn encode(&self, sink: &mut Vec) { use AbstractHeapType::*; match self { Func => sink.push(0x70), Extern => sink.push(0x6F), Any => sink.push(0x6E), None => sink.push(0x71), NoExtern => sink.push(0x72), NoFunc => sink.push(0x73), Eq => sink.push(0x6D), Struct => sink.push(0x6B), Array => sink.push(0x6A), I31 => sink.push(0x6C), Exn => sink.push(0x69), NoExn => sink.push(0x74), Cont => sink.push(0x68), NoCont => sink.push(0x75), } } } /// An encoder for the type section of WebAssembly modules. /// /// # Example /// /// ```rust /// use wasm_encoder::{Module, TypeSection, ValType}; /// /// let mut types = TypeSection::new(); /// /// types.ty().function([ValType::I32, ValType::I32], [ValType::I64]); /// /// let mut module = Module::new(); /// module.section(&types); /// /// let bytes = module.finish(); /// ``` #[derive(Clone, Debug, Default)] pub struct TypeSection { bytes: Vec, num_added: u32, } impl TypeSection { /// Create a new module type section encoder. pub fn new() -> Self { Self::default() } /// The number of types in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// 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<'_> { self.num_added += 1; CoreTypeEncoder { bytes: &mut self.bytes, push_prefix_if_component_core_type: false, } } } impl Encode for TypeSection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl Section for TypeSection { fn id(&self) -> u8 { SectionId::Type.into() } } /// A single-use encoder for encoding a type; this forces all encoding for a /// type to be done in a single shot. #[derive(Debug)] pub struct CoreTypeEncoder<'a> { pub(crate) bytes: &'a mut Vec, // For the time being, this flag handles an ambiguous encoding in the // component model: the `0x50` opcode represents both a core module type as // well as a GC non-final `sub` type. To avoid this, the component model // specification requires us to prefix a non-final `sub` type with `0x00` // when it is used as a top-level core type of a component. Eventually // (prior to the component model's v1.0 release), a module type will get a // new opcode and this special logic can go away. pub(crate) push_prefix_if_component_core_type: bool, } impl<'a> CoreTypeEncoder<'a> { /// Define a function type in this type section. pub fn function(mut self, params: P, results: R) where P: IntoIterator, P::IntoIter: ExactSizeIterator, R: IntoIterator, R::IntoIter: ExactSizeIterator, { self.encode_function(params, results); } /// Define a function type in this type section. pub fn func_type(mut self, ty: &FuncType) { self.encode_function(ty.params().iter().cloned(), ty.results().iter().cloned()); } fn encode_function(&mut self, params: P, results: R) where P: IntoIterator, P::IntoIter: ExactSizeIterator, R: IntoIterator, R::IntoIter: ExactSizeIterator, { let params = params.into_iter(); let results = results.into_iter(); self.bytes.push(0x60); params.len().encode(self.bytes); params.for_each(|p| p.encode(self.bytes)); results.len().encode(self.bytes); results.for_each(|p| p.encode(self.bytes)); } /// Define an array type in this type section. pub fn array(mut self, ty: &StorageType, mutable: bool) { self.encode_array(ty, mutable); } fn encode_array(&mut self, ty: &StorageType, mutable: bool) { self.bytes.push(0x5e); self.encode_field(ty, mutable); } fn encode_field(&mut self, ty: &StorageType, mutable: bool) { ty.encode(self.bytes); self.bytes.push(mutable as u8); } /// Define a struct type in this type section. pub fn struct_(mut self, fields: F) where F: IntoIterator, F::IntoIter: ExactSizeIterator, { self.encode_struct(fields); } fn encode_struct(&mut self, fields: F) where F: IntoIterator, F::IntoIter: ExactSizeIterator, { let fields = fields.into_iter(); self.bytes.push(0x5f); fields.len().encode(self.bytes); for f in fields { self.encode_field(&f.element_type, f.mutable); } } /// 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); } /// Define an explicit subtype in this type section. pub fn subtype(mut self, ty: &SubType) { self.encode_subtype(ty) } /// Define an explicit subtype in this type section. fn encode_subtype(&mut self, ty: &SubType) { // We only need to emit a prefix byte before the actual composite type // when either the `sub` type is not final or it has a declared super // type (see notes on `push_prefix_if_component_core_type`). if ty.supertype_idx.is_some() || !ty.is_final { if ty.is_final { self.bytes.push(0x4f); } else { if self.push_prefix_if_component_core_type { self.bytes.push(0x00); } self.bytes.push(0x50); } ty.supertype_idx.encode(self.bytes); } if ty.composite_type.shared { self.bytes.push(0x65); } match &ty.composite_type.inner { CompositeInnerType::Func(ty) => { self.encode_function(ty.params().iter().copied(), ty.results().iter().copied()) } CompositeInnerType::Array(ArrayType(ty)) => { self.encode_array(&ty.element_type, ty.mutable) } CompositeInnerType::Struct(ty) => self.encode_struct(ty.fields.iter().cloned()), CompositeInnerType::Cont(ty) => self.encode_cont(ty), } } /// Define an explicit recursion group in this type section. pub fn rec(mut self, types: T) where T: IntoIterator, T::IntoIter: ExactSizeIterator, { // When emitting a `rec` group, we will never emit `sub`'s special // `0x00` prefix; that is only necessary when `sub` is not wrapped by // `rec` (see notes on `push_prefix_if_component_core_type`). self.push_prefix_if_component_core_type = false; let types = types.into_iter(); self.bytes.push(0x4e); types.len().encode(self.bytes); types.for_each(|t| { self.encode_subtype(&t); }); } } #[cfg(test)] mod tests { use super::*; use crate::Module; use wasmparser::WasmFeatures; #[test] fn func_types_dont_require_wasm_gc() { let mut types = TypeSection::new(); types.ty().subtype(&SubType { is_final: true, supertype_idx: None, composite_type: CompositeType { inner: CompositeInnerType::Func(FuncType::new([], [])), shared: false, }, }); let mut module = Module::new(); module.section(&types); let wasm_bytes = module.finish(); let mut validator = wasmparser::Validator::new_with_features(WasmFeatures::default() & !WasmFeatures::GC); validator.validate_all(&wasm_bytes).expect( "Encoding pre Wasm GC type should not accidentally use Wasm GC specific encoding", ); } } wasm-encoder-0.239.0/src/core.rs000064400000000000000000000103171046102023000144520ustar 00000000000000mod branch_hints; mod code; mod custom; mod data; mod dump; mod elements; mod exports; mod functions; mod globals; mod imports; mod instructions; mod linking; mod memories; mod names; mod producers; mod start; mod tables; mod tags; mod types; pub use branch_hints::*; pub use code::*; pub use custom::*; pub use data::*; pub use dump::*; pub use elements::*; pub use exports::*; pub use functions::*; pub use globals::*; pub use imports::*; pub use instructions::*; pub use linking::*; pub use memories::*; pub use names::*; pub use producers::*; pub use start::*; pub use tables::*; pub use tags::*; pub use types::*; use crate::Encode; use alloc::vec::Vec; pub(crate) const CORE_FUNCTION_SORT: u8 = 0x00; 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; /// A WebAssembly module section. /// /// Various builders defined in this crate already implement this trait, but you /// can also implement it yourself for your own custom section builders, or use /// `RawSection` to use a bunch of raw bytes as a section. pub trait Section: Encode { /// Gets the section identifier for this section. fn id(&self) -> u8; /// Appends this section to the specified destination list of bytes. fn append_to(&self, dst: &mut Vec) { dst.push(self.id()); self.encode(dst); } } /// Known section identifiers of WebAssembly modules. #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] #[repr(u8)] pub enum SectionId { /// The custom section. Custom = 0, /// The type section. Type = 1, /// The import section. Import = 2, /// The function section. Function = 3, /// The table section. Table = 4, /// The memory section. Memory = 5, /// The global section. Global = 6, /// The export section. Export = 7, /// The start section. Start = 8, /// The element section. Element = 9, /// The code section. Code = 10, /// The data section. Data = 11, /// The data count section. DataCount = 12, /// The tag section. /// /// This section is supported by the exception handling proposal. Tag = 13, } impl From for u8 { #[inline] fn from(id: SectionId) -> u8 { id as u8 } } impl Encode for SectionId { fn encode(&self, sink: &mut Vec) { sink.push(*self as u8); } } /// Represents a WebAssembly component that is being encoded. /// /// Sections within a WebAssembly module are encoded in a specific order. /// /// Modules may also added as a section to a WebAssembly component. #[derive(Clone, Debug)] pub struct Module { pub(crate) bytes: Vec, } impl Module { /// The 8-byte header at the beginning of all core wasm modules. #[rustfmt::skip] pub const HEADER: [u8; 8] = [ // Magic 0x00, 0x61, 0x73, 0x6D, // Version 0x01, 0x00, 0x00, 0x00, ]; /// Begin writing a new `Module`. #[rustfmt::skip] pub fn new() -> Self { Module { bytes: Self::HEADER.to_vec(), } } /// Write a section into this module. /// /// It is your responsibility to define the sections in the [proper /// order](https://webassembly.github.io/spec/core/binary/modules.html#binary-module), /// and to ensure that each kind of section (other than custom sections) is /// only defined once. While this is a potential footgun, it also allows you /// to use this crate to easily construct test cases for bad Wasm module /// encodings. pub fn section(&mut self, section: &impl Section) -> &mut Self { self.bytes.push(section.id()); section.encode(&mut self.bytes); self } /// Get the encoded Wasm module as a slice. pub fn as_slice(&self) -> &[u8] { &self.bytes } /// Give the current size of the module in bytes. pub fn len(&self) -> usize { self.bytes.len() } /// Finish writing this Wasm module and extract ownership of the encoded /// bytes. pub fn finish(self) -> Vec { self.bytes } } impl Default for Module { fn default() -> Self { Self::new() } } wasm-encoder-0.239.0/src/lib.rs000064400000000000000000000126451046102023000142760ustar 00000000000000//! A WebAssembly encoder. //! //! The main builder is the [`Module`]. You can build a section with a //! section-specific builder, like [`TypeSection`] or [`ImportSection`], and //! then add it to the module with [`Module::section`]. When you are finished //! building the module, call either [`Module::as_slice`] or [`Module::finish`] //! to get the encoded bytes. The former gives a shared reference to the //! underlying bytes as a slice, while the latter gives you ownership of them as //! a vector. //! //! # Example //! //! If we wanted to build this module: //! //! ```wasm //! (module //! (type (func (param i32 i32) (result i32))) //! (func (type 0) //! local.get 0 //! local.get 1 //! i32.add) //! (export "f" (func 0))) //! ``` //! //! then we would do this: //! //! ``` //! use wasm_encoder::{ //! CodeSection, ExportKind, ExportSection, Function, FunctionSection, //! Module, TypeSection, ValType, //! }; //! //! let mut module = Module::new(); //! //! // Encode the type section. //! let mut types = TypeSection::new(); //! let params = vec![ValType::I32, ValType::I32]; //! let results = vec![ValType::I32]; //! types.ty().function(params, results); //! module.section(&types); //! //! // Encode the function section. //! let mut functions = FunctionSection::new(); //! let type_index = 0; //! functions.function(type_index); //! module.section(&functions); //! //! // Encode the export section. //! let mut exports = ExportSection::new(); //! exports.export("f", ExportKind::Func, 0); //! module.section(&exports); //! //! // Encode the code section. //! let mut codes = CodeSection::new(); //! let locals = vec![]; //! let mut f = Function::new(locals); //! f.instructions() //! .local_get(0) //! .local_get(1) //! .i32_add() //! .end(); //! codes.function(&f); //! module.section(&codes); //! //! // Extract the encoded Wasm bytes for this module. //! let wasm_bytes = module.finish(); //! //! // We generated a valid Wasm module! //! assert!(wasmparser::validate(&wasm_bytes).is_ok()); //! ``` #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![no_std] #![deny(missing_docs, missing_debug_implementations)] extern crate alloc; #[cfg(feature = "std")] #[macro_use] extern crate std; #[cfg(feature = "component-model")] mod component; mod core; mod raw; #[cfg(feature = "wasmparser")] pub mod reencode; #[cfg(feature = "component-model")] pub use self::component::*; pub use self::core::*; pub use self::raw::*; use alloc::vec::Vec; /// Implemented by types that can be encoded into a byte sink. pub trait Encode { /// Encode the type into the given byte sink. fn encode(&self, sink: &mut Vec); } impl Encode for &'_ T { fn encode(&self, sink: &mut Vec) { T::encode(self, sink) } } impl Encode for [T] { fn encode(&self, sink: &mut Vec) { self.len().encode(sink); for item in self { item.encode(sink); } } } impl Encode for [u8] { fn encode(&self, sink: &mut Vec) { self.len().encode(sink); sink.extend(self); } } impl Encode for str { fn encode(&self, sink: &mut Vec) { self.len().encode(sink); sink.extend_from_slice(self.as_bytes()); } } impl Encode for usize { fn encode(&self, sink: &mut Vec) { assert!(*self <= u32::max_value() as usize); (*self as u32).encode(sink) } } impl Encode for u32 { fn encode(&self, sink: &mut Vec) { let (value, pos) = leb128fmt::encode_u32(*self).unwrap(); sink.extend_from_slice(&value[..pos]); } } impl Encode for i32 { fn encode(&self, sink: &mut Vec) { let (value, pos) = leb128fmt::encode_s32(*self).unwrap(); sink.extend_from_slice(&value[..pos]); } } impl Encode for u64 { fn encode(&self, sink: &mut Vec) { let (value, pos) = leb128fmt::encode_u64(*self).unwrap(); sink.extend_from_slice(&value[..pos]); } } impl Encode for i64 { fn encode(&self, sink: &mut Vec) { let (value, pos) = leb128fmt::encode_s64(*self).unwrap(); sink.extend_from_slice(&value[..pos]); } } fn encode_vec(elements: V, sink: &mut Vec) where T: Encode, V: IntoIterator, V::IntoIter: ExactSizeIterator, { let elements = elements.into_iter(); u32::try_from(elements.len()).unwrap().encode(sink); for x in elements { x.encode(sink); } } impl Encode for Option where T: Encode, { fn encode(&self, sink: &mut Vec) { match self { Some(v) => { sink.push(0x01); v.encode(sink); } None => sink.push(0x00), } } } fn encoding_size(n: u32) -> usize { let (_value, pos) = leb128fmt::encode_u32(n).unwrap(); pos } fn encode_section(sink: &mut Vec, count: u32, bytes: &[u8]) { (encoding_size(count) + bytes.len()).encode(sink); count.encode(sink); sink.extend(bytes); } #[cfg(test)] mod test { use super::*; #[test] fn test_encoding_size() { assert_eq!(encoding_size(624485), 3); } #[test] fn it_encodes_an_empty_module() { let bytes = Module::new().finish(); assert_eq!(bytes, [0x00, b'a', b's', b'm', 0x01, 0x00, 0x00, 0x00]); } #[test] fn it_encodes_an_empty_component() { let bytes = Component::new().finish(); assert_eq!(bytes, [0x00, b'a', b's', b'm', 0x0d, 0x00, 0x01, 0x00]); } } wasm-encoder-0.239.0/src/raw.rs000064400000000000000000000012451046102023000143130ustar 00000000000000use crate::{Encode, Section}; use alloc::vec::Vec; /// A section made up of uninterpreted, raw bytes. /// /// Allows you to splat any data into a module or component. #[derive(Clone, Copy, Debug)] pub struct RawSection<'a> { /// The id for this section. pub id: u8, /// The raw data for this section. pub data: &'a [u8], } impl Encode for RawSection<'_> { fn encode(&self, sink: &mut Vec) { self.data.encode(sink); } } impl Section for RawSection<'_> { fn id(&self) -> u8 { self.id } } #[cfg(feature = "component-model")] impl crate::ComponentSection for RawSection<'_> { fn id(&self) -> u8 { self.id } } wasm-encoder-0.239.0/src/reencode/component.rs000064400000000000000000001663461046102023000173260ustar 00000000000000use crate::reencode::{Error, Reencode, RoundtripReencoder}; use alloc::boxed::Box; use core::convert::Infallible; #[allow(missing_docs)] // FIXME pub trait ReencodeComponent: Reencode { fn component_type_index(&mut self, ty: u32) -> u32 { ty } fn component_instance_index(&mut self, ty: u32) -> u32 { ty } fn component_func_index(&mut self, ty: u32) -> u32 { ty } fn component_index(&mut self, ty: u32) -> u32 { ty } fn module_index(&mut self, ty: u32) -> u32 { ty } fn instance_index(&mut self, ty: u32) -> u32 { ty } fn component_value_index(&mut self, ty: u32) -> u32 { ty } fn outer_type_index(&mut self, count: u32, ty: u32) -> Result> { let _ = count; self.type_index(ty) } fn outer_component_type_index(&mut self, count: u32, ty: u32) -> u32 { let _ = count; self.component_type_index(ty) } fn outer_component_index(&mut self, count: u32, component: u32) -> u32 { let _ = count; self.component_index(component) } fn outer_module_index(&mut self, count: u32, module: u32) -> u32 { let _ = count; self.module_index(module) } fn push_depth(&mut self) {} fn pop_depth(&mut self) {} fn component_external_index( &mut self, kind: wasmparser::ComponentExternalKind, index: u32, ) -> u32 { match kind { wasmparser::ComponentExternalKind::Func => self.component_func_index(index), wasmparser::ComponentExternalKind::Module => self.module_index(index), wasmparser::ComponentExternalKind::Component => self.component_index(index), wasmparser::ComponentExternalKind::Type => self.component_type_index(index), wasmparser::ComponentExternalKind::Instance => self.component_instance_index(index), wasmparser::ComponentExternalKind::Value => self.component_value_index(index), } } fn parse_component( &mut self, component: &mut crate::Component, parser: wasmparser::Parser, data: &[u8], ) -> Result<(), Error> { component_utils::parse_component(self, component, parser, data, data) } fn parse_component_payload( &mut self, component: &mut crate::Component, payload: wasmparser::Payload<'_>, whole_component: &[u8], ) -> Result<(), Error> { component_utils::parse_component_payload(self, component, payload, whole_component) } fn parse_component_submodule( &mut self, component: &mut crate::Component, parser: wasmparser::Parser, module: &[u8], ) -> Result<(), Error> { component_utils::parse_component_submodule(self, component, parser, module) } fn parse_component_subcomponent( &mut self, component: &mut crate::Component, parser: wasmparser::Parser, subcomponent: &[u8], whole_component: &[u8], ) -> Result<(), Error> { component_utils::parse_component_subcomponent( self, component, parser, subcomponent, whole_component, ) } fn parse_unknown_component_section( &mut self, component: &mut crate::Component, id: u8, contents: &[u8], ) -> Result<(), Error> { component_utils::parse_unknown_component_section(self, component, id, contents) } fn parse_component_custom_section( &mut self, component: &mut crate::Component, section: wasmparser::CustomSectionReader<'_>, ) -> Result<(), Error> { component_utils::parse_component_custom_section(self, component, section) } fn parse_component_type_section( &mut self, types: &mut crate::ComponentTypeSection, section: wasmparser::ComponentTypeSectionReader<'_>, ) -> Result<(), Error> { component_utils::parse_component_type_section(self, types, section) } fn parse_component_type( &mut self, dst: crate::ComponentTypeEncoder<'_>, ty: wasmparser::ComponentType<'_>, ) -> Result<(), Error> { component_utils::parse_component_type(self, dst, ty) } fn component_instance_type( &mut self, ty: Box<[wasmparser::InstanceTypeDeclaration<'_>]>, ) -> Result> { component_utils::component_instance_type(self, ty) } fn parse_component_instance_type_declaration( &mut self, ty: &mut crate::InstanceType, decl: wasmparser::InstanceTypeDeclaration<'_>, ) -> Result<(), Error> { component_utils::parse_component_instance_type_declaration(self, ty, decl) } fn parse_component_core_type( &mut self, ty: crate::ComponentCoreTypeEncoder<'_>, core: wasmparser::CoreType<'_>, ) -> Result<(), Error> { component_utils::parse_component_core_type(self, ty, core) } fn component_type( &mut self, ty: Box<[wasmparser::ComponentTypeDeclaration<'_>]>, ) -> Result> { component_utils::component_type(self, ty) } fn parse_component_type_declaration( &mut self, component: &mut crate::ComponentType, decl: wasmparser::ComponentTypeDeclaration<'_>, ) -> Result<(), Error> { component_utils::parse_component_type_declaration(self, component, decl) } fn parse_component_func_type( &mut self, func: crate::ComponentFuncTypeEncoder<'_>, ty: wasmparser::ComponentFuncType<'_>, ) -> Result<(), Error> { component_utils::parse_component_func_type(self, func, ty) } fn parse_component_defined_type( &mut self, defined: crate::ComponentDefinedTypeEncoder<'_>, ty: wasmparser::ComponentDefinedType<'_>, ) -> Result<(), Error> { component_utils::parse_component_defined_type(self, defined, ty) } fn component_module_type( &mut self, ty: Box<[wasmparser::ModuleTypeDeclaration<'_>]>, ) -> Result> { component_utils::component_module_type(self, ty) } fn parse_component_module_type_declaration( &mut self, module: &mut crate::ModuleType, decl: wasmparser::ModuleTypeDeclaration<'_>, ) -> Result<(), Error> { component_utils::parse_component_module_type_declaration(self, module, decl) } fn component_alias<'a>( &mut self, alias: wasmparser::ComponentAlias<'a>, ) -> Result, Error> { component_utils::component_alias(self, alias) } fn parse_component_import_section( &mut self, imports: &mut crate::ComponentImportSection, section: wasmparser::ComponentImportSectionReader<'_>, ) -> Result<(), Error> { component_utils::parse_component_import_section(self, imports, section) } fn parse_component_canonical_section( &mut self, canonical: &mut crate::CanonicalFunctionSection, section: wasmparser::ComponentCanonicalSectionReader<'_>, ) -> Result<(), Error> { component_utils::parse_component_canonical_section(self, canonical, section) } fn parse_component_canonical( &mut self, section: &mut crate::CanonicalFunctionSection, func: wasmparser::CanonicalFunction, ) -> Result<(), Error> { component_utils::parse_component_canonical(self, section, func) } fn parse_component_alias_section( &mut self, aliases: &mut crate::ComponentAliasSection, section: wasmparser::ComponentAliasSectionReader<'_>, ) -> Result<(), Error> { component_utils::parse_component_alias_section(self, aliases, section) } fn parse_component_instance_section( &mut self, instances: &mut crate::ComponentInstanceSection, section: wasmparser::ComponentInstanceSectionReader<'_>, ) -> Result<(), Error> { component_utils::parse_component_instance_section(self, instances, section) } fn parse_component_instance( &mut self, instances: &mut crate::ComponentInstanceSection, instance: wasmparser::ComponentInstance<'_>, ) -> Result<(), Error> { component_utils::parse_component_instance(self, instances, instance) } fn parse_instance_section( &mut self, instances: &mut crate::InstanceSection, section: wasmparser::InstanceSectionReader<'_>, ) -> Result<(), Error> { component_utils::parse_instance_section(self, instances, section) } fn parse_instance( &mut self, instances: &mut crate::InstanceSection, instance: wasmparser::Instance<'_>, ) -> Result<(), Error> { component_utils::parse_instance(self, instances, instance) } fn parse_core_type_section( &mut self, types: &mut crate::CoreTypeSection, section: wasmparser::CoreTypeSectionReader<'_>, ) -> Result<(), Error> { component_utils::parse_core_type_section(self, types, section) } fn parse_component_export_section( &mut self, exports: &mut crate::ComponentExportSection, section: wasmparser::ComponentExportSectionReader<'_>, ) -> Result<(), Error> { component_utils::parse_component_export_section(self, exports, section) } fn parse_component_export( &mut self, exports: &mut crate::ComponentExportSection, export: wasmparser::ComponentExport<'_>, ) -> Result<(), Error> { component_utils::parse_component_export(self, exports, export) } fn parse_component_start_section( &mut self, component: &mut crate::Component, func: wasmparser::ComponentStartFunction, ) -> Result<(), Error> { component_utils::parse_component_start_section(self, component, func) } fn component_type_ref( &mut self, ty: wasmparser::ComponentTypeRef, ) -> Result> { component_utils::component_type_ref(self, ty) } fn component_primitive_val_type( &mut self, ty: wasmparser::PrimitiveValType, ) -> crate::component::PrimitiveValType { component_utils::component_primitive_val_type(self, ty) } fn component_export_kind( &mut self, ty: wasmparser::ComponentExternalKind, ) -> crate::component::ComponentExportKind { component_utils::component_export_kind(self, ty) } fn component_outer_alias_kind( &mut self, kind: wasmparser::ComponentOuterAliasKind, ) -> crate::component::ComponentOuterAliasKind { component_utils::component_outer_alias_kind(self, kind) } fn component_val_type( &mut self, ty: wasmparser::ComponentValType, ) -> crate::component::ComponentValType { component_utils::component_val_type(self, ty) } fn type_bounds(&mut self, ty: wasmparser::TypeBounds) -> crate::component::TypeBounds { component_utils::type_bounds(self, ty) } fn canonical_option( &mut self, ty: wasmparser::CanonicalOption, ) -> Result> { component_utils::canonical_option(self, ty) } fn custom_component_name_section( &mut self, section: wasmparser::ComponentNameSectionReader<'_>, ) -> Result> { component_utils::custom_component_name_section(self, section) } fn parse_custom_component_name_subsection( &mut self, names: &mut crate::ComponentNameSection, section: wasmparser::ComponentName<'_>, ) -> Result<(), Error> { component_utils::parse_custom_component_name_subsection(self, names, section) } } impl ReencodeComponent for RoundtripReencoder {} #[allow(missing_docs)] // FIXME pub mod component_utils { use super::super::utils::name_map; use super::ReencodeComponent; use crate::reencode::Error; use alloc::boxed::Box; use alloc::vec::Vec; pub fn parse_component( reencoder: &mut T, component: &mut crate::Component, mut parser: wasmparser::Parser, data: &[u8], whole_component: &[u8], ) -> Result<(), Error> { let mut remaining = data; while !remaining.is_empty() { let section = match parser.parse(remaining, true)? { wasmparser::Chunk::Parsed { consumed, payload } => { remaining = &remaining[consumed..]; payload } wasmparser::Chunk::NeedMoreData(_) => unreachable!(), }; match §ion { wasmparser::Payload::ComponentSection { unchecked_range, .. } | wasmparser::Payload::ModuleSection { unchecked_range, .. } => { remaining = &remaining[unchecked_range.len()..]; } _ => {} } reencoder.parse_component_payload(component, section, whole_component)?; } Ok(()) } pub fn parse_component_payload( reencoder: &mut T, component: &mut crate::Component, payload: wasmparser::Payload<'_>, whole_component: &[u8], ) -> Result<(), Error> { match payload { wasmparser::Payload::Version { encoding: wasmparser::Encoding::Component, .. } => (), wasmparser::Payload::Version { .. } => { return Err(Error::UnexpectedNonComponentSection); } wasmparser::Payload::TypeSection(_) | wasmparser::Payload::ImportSection(_) | wasmparser::Payload::FunctionSection(_) | wasmparser::Payload::TableSection(_) | wasmparser::Payload::MemorySection(_) | wasmparser::Payload::TagSection(_) | wasmparser::Payload::GlobalSection(_) | wasmparser::Payload::ExportSection(_) | wasmparser::Payload::StartSection { .. } | wasmparser::Payload::ElementSection(_) | wasmparser::Payload::DataCountSection { .. } | wasmparser::Payload::DataSection(_) | wasmparser::Payload::CodeSectionStart { .. } | wasmparser::Payload::CodeSectionEntry(_) => { return Err(Error::UnexpectedNonComponentSection); } wasmparser::Payload::ComponentTypeSection(section) => { let mut types = crate::ComponentTypeSection::new(); reencoder.parse_component_type_section(&mut types, section)?; component.section(&types); } wasmparser::Payload::ComponentImportSection(section) => { let mut imports = crate::ComponentImportSection::new(); reencoder.parse_component_import_section(&mut imports, section)?; component.section(&imports); } wasmparser::Payload::ComponentCanonicalSection(section) => { let mut canonical = crate::CanonicalFunctionSection::new(); reencoder.parse_component_canonical_section(&mut canonical, section)?; component.section(&canonical); } wasmparser::Payload::ComponentAliasSection(section) => { let mut aliases = crate::ComponentAliasSection::new(); reencoder.parse_component_alias_section(&mut aliases, section)?; component.section(&aliases); } wasmparser::Payload::ComponentInstanceSection(section) => { let mut instances = crate::ComponentInstanceSection::new(); reencoder.parse_component_instance_section(&mut instances, section)?; component.section(&instances); } wasmparser::Payload::InstanceSection(section) => { let mut instances = crate::InstanceSection::new(); reencoder.parse_instance_section(&mut instances, section)?; component.section(&instances); } wasmparser::Payload::CoreTypeSection(section) => { let mut types = crate::CoreTypeSection::new(); reencoder.parse_core_type_section(&mut types, section)?; component.section(&types); } wasmparser::Payload::ComponentExportSection(section) => { let mut exports = crate::ComponentExportSection::new(); reencoder.parse_component_export_section(&mut exports, section)?; component.section(&exports); } wasmparser::Payload::CustomSection(section) => { reencoder.parse_component_custom_section(component, section)?; } wasmparser::Payload::ModuleSection { parser, unchecked_range, } => { reencoder.parse_component_submodule( component, parser, &whole_component[unchecked_range], )?; } wasmparser::Payload::ComponentSection { parser, unchecked_range, } => { reencoder.parse_component_subcomponent( component, parser, &whole_component[unchecked_range], whole_component, )?; } wasmparser::Payload::ComponentStartSection { start, range: _ } => { reencoder.parse_component_start_section(component, start)?; } wasmparser::Payload::End(_) => {} other => match other.as_section() { Some((id, range)) => { let section = &whole_component[range]; reencoder.parse_unknown_component_section(component, id, section)?; } None => unreachable!(), }, } Ok(()) } pub fn parse_component_submodule( reencoder: &mut T, component: &mut crate::Component, parser: wasmparser::Parser, submodule: &[u8], ) -> Result<(), Error> { reencoder.push_depth(); let mut module = crate::Module::new(); crate::reencode::utils::parse_core_module(reencoder, &mut module, parser, submodule)?; component.section(&crate::ModuleSection(&module)); reencoder.pop_depth(); Ok(()) } pub fn parse_component_subcomponent( reencoder: &mut T, component: &mut crate::Component, parser: wasmparser::Parser, data: &[u8], whole_component: &[u8], ) -> Result<(), Error> { reencoder.push_depth(); let mut subcomponent = crate::Component::new(); parse_component(reencoder, &mut subcomponent, parser, data, whole_component)?; component.section(&crate::NestedComponentSection(&subcomponent)); reencoder.pop_depth(); Ok(()) } pub fn parse_unknown_component_section( _reencoder: &mut T, component: &mut crate::Component, id: u8, contents: &[u8], ) -> Result<(), Error> { component.section(&crate::RawSection { id, data: contents }); Ok(()) } pub fn parse_component_custom_section( reencoder: &mut T, component: &mut crate::Component, section: wasmparser::CustomSectionReader<'_>, ) -> Result<(), Error> { match section.as_known() { wasmparser::KnownCustom::ComponentName(name) => { component.section(&reencoder.custom_component_name_section(name)?); } _ => { component.section(&reencoder.custom_section(section)?); } } Ok(()) } pub fn parse_component_type_section( reencoder: &mut T, types: &mut crate::ComponentTypeSection, section: wasmparser::ComponentTypeSectionReader<'_>, ) -> Result<(), Error> { for ty in section { reencoder.parse_component_type(types.ty(), ty?)?; } Ok(()) } pub fn parse_component_type( reencoder: &mut T, dst: crate::ComponentTypeEncoder, ty: wasmparser::ComponentType<'_>, ) -> Result<(), Error> { match ty { wasmparser::ComponentType::Defined(ty) => { reencoder.parse_component_defined_type(dst.defined_type(), ty)?; } wasmparser::ComponentType::Func(func) => { reencoder.parse_component_func_type(dst.function(), func)?; } wasmparser::ComponentType::Component(component) => { let ty = reencoder.component_type(component)?; dst.component(&ty); } wasmparser::ComponentType::Instance(instance) => { let ty = reencoder.component_instance_type(instance)?; dst.instance(&ty); } wasmparser::ComponentType::Resource { rep, dtor } => { let rep = reencoder.val_type(rep)?; let dtor = dtor.map(|i| reencoder.function_index(i)).transpose()?; dst.resource(rep, dtor); } } Ok(()) } pub fn component_instance_type( reencoder: &mut T, ty: Box<[wasmparser::InstanceTypeDeclaration<'_>]>, ) -> Result> { reencoder.push_depth(); let mut ret = crate::InstanceType::new(); for decl in Vec::from(ty) { reencoder.parse_component_instance_type_declaration(&mut ret, decl)?; } reencoder.pop_depth(); Ok(ret) } pub fn parse_component_instance_type_declaration( reencoder: &mut T, instance: &mut crate::InstanceType, decl: wasmparser::InstanceTypeDeclaration<'_>, ) -> Result<(), Error> { match decl { wasmparser::InstanceTypeDeclaration::CoreType(core) => { reencoder.parse_component_core_type(instance.core_type(), core) } wasmparser::InstanceTypeDeclaration::Type(t) => { reencoder.parse_component_type(instance.ty(), t) } wasmparser::InstanceTypeDeclaration::Alias(a) => { let a = reencoder.component_alias(a)?; instance.alias(a); Ok(()) } wasmparser::InstanceTypeDeclaration::Export { name, ty } => { let ty = reencoder.component_type_ref(ty)?; instance.export(name.0, ty); Ok(()) } } } pub fn parse_component_core_type( reencoder: &mut T, ty: crate::ComponentCoreTypeEncoder<'_>, decl: wasmparser::CoreType<'_>, ) -> Result<(), Error> { match decl { wasmparser::CoreType::Rec(rec) => { reencoder.parse_recursive_type_group(ty.core(), rec)?; } wasmparser::CoreType::Module(decls) => { ty.module(&reencoder.component_module_type(decls)?); } } Ok(()) } pub fn component_type( reencoder: &mut T, ty: Box<[wasmparser::ComponentTypeDeclaration<'_>]>, ) -> Result> { reencoder.push_depth(); let mut ret = crate::ComponentType::new(); for decl in Vec::from(ty) { reencoder.parse_component_type_declaration(&mut ret, decl)?; } reencoder.pop_depth(); Ok(ret) } pub fn parse_component_type_declaration( reencoder: &mut T, component: &mut crate::ComponentType, decl: wasmparser::ComponentTypeDeclaration<'_>, ) -> Result<(), Error> { match decl { wasmparser::ComponentTypeDeclaration::CoreType(ty) => { reencoder.parse_component_core_type(component.core_type(), ty) } wasmparser::ComponentTypeDeclaration::Type(ty) => { reencoder.parse_component_type(component.ty(), ty) } wasmparser::ComponentTypeDeclaration::Alias(a) => { let a = reencoder.component_alias(a)?; component.alias(a); Ok(()) } wasmparser::ComponentTypeDeclaration::Export { name, 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)?; component.import(import.name.0, ty); Ok(()) } } } pub fn parse_component_func_type( reencoder: &mut T, mut func: crate::ComponentFuncTypeEncoder<'_>, ty: wasmparser::ComponentFuncType<'_>, ) -> Result<(), Error> { func.params( Vec::from(ty.params) .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(()) } pub fn parse_component_defined_type( reencoder: &mut T, defined: crate::ComponentDefinedTypeEncoder<'_>, ty: wasmparser::ComponentDefinedType<'_>, ) -> Result<(), Error> { match ty { wasmparser::ComponentDefinedType::Primitive(p) => { defined.primitive(reencoder.component_primitive_val_type(p)); } wasmparser::ComponentDefinedType::Record(r) => { defined.record( r.iter() .map(|(name, ty)| (*name, reencoder.component_val_type(*ty))), ); } wasmparser::ComponentDefinedType::Variant(v) => { defined.variant(v.iter().map(|case| { ( case.name, case.ty.map(|t| reencoder.component_val_type(t)), case.refines, ) })); } 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))); } wasmparser::ComponentDefinedType::Flags(t) => { defined.flags(t.iter().copied()); } wasmparser::ComponentDefinedType::Enum(t) => { defined.enum_type(t.iter().copied()); } wasmparser::ComponentDefinedType::Option(t) => { defined.option(reencoder.component_val_type(t)); } wasmparser::ComponentDefinedType::Result { ok, err } => { let ok = ok.map(|t| reencoder.component_val_type(t)); let err = err.map(|t| reencoder.component_val_type(t)); defined.result(ok, err); } wasmparser::ComponentDefinedType::Own(i) => { defined.own(reencoder.component_type_index(i)); } wasmparser::ComponentDefinedType::Borrow(i) => { defined.borrow(reencoder.component_type_index(i)); } wasmparser::ComponentDefinedType::Future(t) => { defined.future(t.map(|t| reencoder.component_val_type(t))); } wasmparser::ComponentDefinedType::Stream(t) => { defined.stream(t.map(|t| reencoder.component_val_type(t))); } } Ok(()) } pub fn component_module_type( reencoder: &mut T, ty: Box<[wasmparser::ModuleTypeDeclaration<'_>]>, ) -> Result> { reencoder.push_depth(); let mut ret = crate::ModuleType::new(); for decl in Vec::from(ty) { reencoder.parse_component_module_type_declaration(&mut ret, decl)?; } reencoder.pop_depth(); Ok(ret) } pub fn parse_component_module_type_declaration( reencoder: &mut T, module: &mut crate::ModuleType, decl: wasmparser::ModuleTypeDeclaration<'_>, ) -> Result<(), Error> { match decl { wasmparser::ModuleTypeDeclaration::Type(rec) => { reencoder.parse_recursive_type_group(module.ty(), rec)?; } wasmparser::ModuleTypeDeclaration::Export { name, ty } => { module.export(name, reencoder.entity_type(ty)?); } wasmparser::ModuleTypeDeclaration::OuterAlias { kind: wasmparser::OuterAliasKind::Type, count, index, } => { let index = reencoder.outer_type_index(count, index)?; module.alias_outer_core_type(count, index); } wasmparser::ModuleTypeDeclaration::Import(import) => { module.import( import.module, import.name, reencoder.entity_type(import.ty)?, ); } } Ok(()) } pub fn component_alias<'a, T: ?Sized + ReencodeComponent>( reencoder: &mut T, alias: wasmparser::ComponentAlias<'a>, ) -> Result, Error> { match alias { wasmparser::ComponentAlias::InstanceExport { kind, instance_index, name, } => Ok(crate::Alias::InstanceExport { instance: reencoder.component_instance_index(instance_index), kind: kind.into(), name, }), wasmparser::ComponentAlias::CoreInstanceExport { kind, instance_index, name, } => Ok(crate::Alias::CoreInstanceExport { instance: reencoder.instance_index(instance_index), kind: kind.into(), name, }), wasmparser::ComponentAlias::Outer { kind, count, index } => Ok(crate::Alias::Outer { kind: kind.into(), count, index: match kind { wasmparser::ComponentOuterAliasKind::CoreModule => { reencoder.outer_module_index(count, index) } wasmparser::ComponentOuterAliasKind::CoreType => { reencoder.outer_type_index(count, index)? } wasmparser::ComponentOuterAliasKind::Type => { reencoder.outer_component_type_index(count, index) } wasmparser::ComponentOuterAliasKind::Component => { reencoder.outer_component_index(count, index) } }, }), } } pub fn parse_component_import_section( reencoder: &mut T, imports: &mut crate::ComponentImportSection, section: wasmparser::ComponentImportSectionReader<'_>, ) -> Result<(), Error> { for import in section { let import = import?; imports.import(import.name.0, reencoder.component_type_ref(import.ty)?); } Ok(()) } pub fn parse_component_canonical_section( reencoder: &mut T, canonical: &mut crate::CanonicalFunctionSection, section: wasmparser::ComponentCanonicalSectionReader<'_>, ) -> Result<(), Error> { for c in section { reencoder.parse_component_canonical(canonical, c?)?; } Ok(()) } pub fn parse_component_canonical( reencoder: &mut T, section: &mut crate::CanonicalFunctionSection, func: wasmparser::CanonicalFunction, ) -> Result<(), Error> { match func { wasmparser::CanonicalFunction::Lift { core_func_index, type_index, options, } => { let func = reencoder.function_index(core_func_index)?; let ty = reencoder.component_type_index(type_index); let options = options .iter() .map(|o| reencoder.canonical_option(*o)) .collect::, _>>()?; section.lift(func, ty, options); } wasmparser::CanonicalFunction::Lower { func_index, options, } => { let func = reencoder.component_func_index(func_index); let options = options .iter() .map(|o| reencoder.canonical_option(*o)) .collect::, _>>()?; section.lower(func, options); } wasmparser::CanonicalFunction::ResourceNew { resource } => { let resource = reencoder.component_type_index(resource); section.resource_new(resource); } wasmparser::CanonicalFunction::ResourceDrop { resource } => { 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::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::BackpressureInc => { section.backpressure_inc(); } wasmparser::CanonicalFunction::BackpressureDec => { section.backpressure_dec(); } wasmparser::CanonicalFunction::TaskReturn { result, options } => { let options = options .iter() .map(|o| reencoder.canonical_option(*o)) .collect::, _>>()?; section.task_return(result.map(|ty| reencoder.component_val_type(ty)), options); } wasmparser::CanonicalFunction::TaskCancel => { section.task_cancel(); } wasmparser::CanonicalFunction::ContextGet(i) => { section.context_get(i); } 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 } => { let options = options .iter() .map(|o| reencoder.canonical_option(*o)) .collect::, _>>()?; section.stream_read(reencoder.component_type_index(ty), options); } wasmparser::CanonicalFunction::StreamWrite { ty, options } => { let options = options .iter() .map(|o| reencoder.canonical_option(*o)) .collect::, _>>()?; section.stream_write(reencoder.component_type_index(ty), options); } wasmparser::CanonicalFunction::StreamCancelRead { ty, async_ } => { section.stream_cancel_read(ty, async_); } wasmparser::CanonicalFunction::StreamCancelWrite { ty, async_ } => { section.stream_cancel_write(ty, async_); } wasmparser::CanonicalFunction::StreamDropReadable { ty } => { section.stream_drop_readable(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 } => { let options = options .iter() .map(|o| reencoder.canonical_option(*o)) .collect::, _>>()?; section.future_read(reencoder.component_type_index(ty), options); } wasmparser::CanonicalFunction::FutureWrite { ty, options } => { let options = options .iter() .map(|o| reencoder.canonical_option(*o)) .collect::, _>>()?; section.future_write(reencoder.component_type_index(ty), options); } wasmparser::CanonicalFunction::FutureCancelRead { ty, async_ } => { section.future_cancel_read(ty, async_); } wasmparser::CanonicalFunction::FutureCancelWrite { ty, async_ } => { section.future_cancel_write(ty, async_); } wasmparser::CanonicalFunction::FutureDropReadable { ty } => { section.future_drop_readable(reencoder.component_type_index(ty)); } wasmparser::CanonicalFunction::FutureDropWritable { ty } => { section.future_drop_writable(reencoder.component_type_index(ty)); } wasmparser::CanonicalFunction::ErrorContextNew { options } => { let options = options .iter() .map(|o| reencoder.canonical_option(*o)) .collect::, _>>()?; section.error_context_new(options); } wasmparser::CanonicalFunction::ErrorContextDebugMessage { options } => { let options = options .iter() .map(|o| reencoder.canonical_option(*o)) .collect::, _>>()?; 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(()) } pub fn parse_component_alias_section( reencoder: &mut T, aliases: &mut crate::ComponentAliasSection, section: wasmparser::ComponentAliasSectionReader<'_>, ) -> Result<(), Error> { for a in section { aliases.alias(reencoder.component_alias(a?)?); } Ok(()) } pub fn parse_component_instance_section( reencoder: &mut T, instances: &mut crate::ComponentInstanceSection, section: wasmparser::ComponentInstanceSectionReader<'_>, ) -> Result<(), Error> { for i in section { reencoder.parse_component_instance(instances, i?)?; } Ok(()) } pub fn parse_component_instance( reencoder: &mut T, instances: &mut crate::ComponentInstanceSection, instance: wasmparser::ComponentInstance<'_>, ) -> Result<(), Error> { match instance { wasmparser::ComponentInstance::Instantiate { component_index, args, } => { instances.instantiate( reencoder.component_index(component_index), args.iter().map(|arg| { ( arg.name, arg.kind.into(), reencoder.component_external_index(arg.kind, arg.index), ) }), ); } wasmparser::ComponentInstance::FromExports(exports) => { instances.export_items(exports.iter().map(|export| { ( export.name.0, export.kind.into(), reencoder.component_external_index(export.kind, export.index), ) })); } } Ok(()) } pub fn parse_instance_section( reencoder: &mut T, instances: &mut crate::InstanceSection, section: wasmparser::InstanceSectionReader<'_>, ) -> Result<(), Error> { for i in section { reencoder.parse_instance(instances, i?)?; } Ok(()) } pub fn parse_instance( reencoder: &mut T, instances: &mut crate::InstanceSection, instance: wasmparser::Instance<'_>, ) -> Result<(), Error> { match instance { wasmparser::Instance::Instantiate { module_index, args } => { instances.instantiate( reencoder.module_index(module_index), args.iter().map(|arg| match arg.kind { wasmparser::InstantiationArgKind::Instance => ( arg.name, crate::ModuleArg::Instance(reencoder.instance_index(arg.index)), ), }), ); } wasmparser::Instance::FromExports(exports) => { let exports = exports .iter() .map(|export| { Ok(( export.name, reencoder.export_kind(export.kind)?, reencoder.external_index(export.kind, export.index)?, )) }) .collect::, Error>>()?; instances.export_items(exports); } } Ok(()) } pub fn parse_core_type_section( reencoder: &mut T, types: &mut crate::CoreTypeSection, section: wasmparser::CoreTypeSectionReader<'_>, ) -> Result<(), Error> { for t in section { reencoder.parse_component_core_type(types.ty(), t?)?; } Ok(()) } pub fn parse_component_export_section( reencoder: &mut T, exports: &mut crate::ComponentExportSection, section: wasmparser::ComponentExportSectionReader<'_>, ) -> Result<(), Error> { for e in section { reencoder.parse_component_export(exports, e?)?; } Ok(()) } pub fn parse_component_export( reencoder: &mut T, exports: &mut crate::ComponentExportSection, export: wasmparser::ComponentExport<'_>, ) -> Result<(), Error> { exports.export( export.name.0, export.kind.into(), reencoder.component_external_index(export.kind, export.index), export .ty .map(|t| reencoder.component_type_ref(t)) .transpose()?, ); Ok(()) } pub fn parse_component_start_section( reencoder: &mut T, component: &mut crate::Component, func: wasmparser::ComponentStartFunction, ) -> Result<(), Error> { component.section(&crate::ComponentStartSection { function_index: reencoder.component_func_index(func.func_index), args: func .arguments .iter() .map(|i| reencoder.component_value_index(*i)) .collect::>(), results: func.results, }); Ok(()) } pub fn component_type_ref( reencoder: &mut T, ty: wasmparser::ComponentTypeRef, ) -> Result> { Ok(match ty { wasmparser::ComponentTypeRef::Module(u) => { crate::component::ComponentTypeRef::Module(reencoder.type_index(u)?) } wasmparser::ComponentTypeRef::Func(u) => { crate::component::ComponentTypeRef::Func(reencoder.component_type_index(u)) } wasmparser::ComponentTypeRef::Value(valty) => { crate::component::ComponentTypeRef::Value(reencoder.component_val_type(valty)) } wasmparser::ComponentTypeRef::Type(bounds) => { crate::component::ComponentTypeRef::Type(reencoder.type_bounds(bounds)) } wasmparser::ComponentTypeRef::Instance(u) => { crate::component::ComponentTypeRef::Instance(reencoder.component_type_index(u)) } wasmparser::ComponentTypeRef::Component(u) => { crate::component::ComponentTypeRef::Component(reencoder.component_type_index(u)) } }) } pub fn component_primitive_val_type( _reencoder: &mut T, ty: wasmparser::PrimitiveValType, ) -> crate::component::PrimitiveValType { match ty { wasmparser::PrimitiveValType::Bool => crate::component::PrimitiveValType::Bool, wasmparser::PrimitiveValType::S8 => crate::component::PrimitiveValType::S8, wasmparser::PrimitiveValType::U8 => crate::component::PrimitiveValType::U8, wasmparser::PrimitiveValType::S16 => crate::component::PrimitiveValType::S16, wasmparser::PrimitiveValType::U16 => crate::component::PrimitiveValType::U16, wasmparser::PrimitiveValType::S32 => crate::component::PrimitiveValType::S32, wasmparser::PrimitiveValType::U32 => crate::component::PrimitiveValType::U32, wasmparser::PrimitiveValType::S64 => crate::component::PrimitiveValType::S64, wasmparser::PrimitiveValType::U64 => crate::component::PrimitiveValType::U64, wasmparser::PrimitiveValType::F32 => crate::component::PrimitiveValType::F32, 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 } } } pub fn component_export_kind( _reencoder: &mut T, ty: wasmparser::ComponentExternalKind, ) -> crate::component::ComponentExportKind { match ty { wasmparser::ComponentExternalKind::Module => crate::ComponentExportKind::Module, wasmparser::ComponentExternalKind::Func => crate::ComponentExportKind::Func, wasmparser::ComponentExternalKind::Value => crate::ComponentExportKind::Value, wasmparser::ComponentExternalKind::Type => crate::ComponentExportKind::Type, wasmparser::ComponentExternalKind::Instance => crate::ComponentExportKind::Instance, wasmparser::ComponentExternalKind::Component => crate::ComponentExportKind::Component, } } pub fn component_outer_alias_kind( _reencoder: &mut T, ty: wasmparser::ComponentOuterAliasKind, ) -> crate::component::ComponentOuterAliasKind { match ty { wasmparser::ComponentOuterAliasKind::CoreModule => { crate::component::ComponentOuterAliasKind::CoreModule } wasmparser::ComponentOuterAliasKind::CoreType => { crate::component::ComponentOuterAliasKind::CoreType } wasmparser::ComponentOuterAliasKind::Type => { crate::component::ComponentOuterAliasKind::Type } wasmparser::ComponentOuterAliasKind::Component => { crate::ComponentOuterAliasKind::Component } } } pub fn component_val_type( reencoder: &mut T, ty: wasmparser::ComponentValType, ) -> crate::component::ComponentValType { match ty { wasmparser::ComponentValType::Type(u) => { crate::component::ComponentValType::Type(reencoder.component_type_index(u)) } wasmparser::ComponentValType::Primitive(pty) => { crate::component::ComponentValType::Primitive( crate::component::PrimitiveValType::from(pty), ) } } } pub fn type_bounds( reencoder: &mut T, ty: wasmparser::TypeBounds, ) -> crate::component::TypeBounds { match ty { wasmparser::TypeBounds::Eq(u) => { crate::component::TypeBounds::Eq(reencoder.component_type_index(u)) } wasmparser::TypeBounds::SubResource => crate::component::TypeBounds::SubResource, } } pub fn canonical_option( reencoder: &mut T, ty: wasmparser::CanonicalOption, ) -> Result> { 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)?) } wasmparser::CanonicalOption::Realloc(u) => { crate::component::CanonicalOption::Realloc(reencoder.function_index(u)?) } wasmparser::CanonicalOption::PostReturn(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)?) } 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( reencoder: &mut T, section: wasmparser::ComponentNameSectionReader<'_>, ) -> Result> { let mut ret = crate::ComponentNameSection::new(); for subsection in section { reencoder.parse_custom_component_name_subsection(&mut ret, subsection?)?; } Ok(ret) } pub fn parse_custom_component_name_subsection( reencoder: &mut T, names: &mut crate::ComponentNameSection, section: wasmparser::ComponentName<'_>, ) -> Result<(), Error> { match section { wasmparser::ComponentName::Component { name, .. } => { names.component(name); } wasmparser::ComponentName::CoreFuncs(map) => { names.core_funcs(&name_map(map, |i| reencoder.function_index(i))?); } wasmparser::ComponentName::CoreGlobals(map) => { names.core_globals(&name_map(map, |i| reencoder.global_index(i))?); } wasmparser::ComponentName::CoreMemories(map) => { names.core_memories(&name_map(map, |i| reencoder.memory_index(i))?); } 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| Ok(reencoder.module_index(i)))?); } wasmparser::ComponentName::CoreInstances(map) => { 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| Ok(reencoder.component_type_index(i)))?); } wasmparser::ComponentName::Instances(map) => { names.instances(&name_map(map, |i| { Ok(reencoder.component_instance_index(i)) })?); } wasmparser::ComponentName::Components(map) => { names.components(&name_map(map, |i| Ok(reencoder.component_index(i)))?); } wasmparser::ComponentName::Funcs(map) => { names.funcs(&name_map(map, |i| Ok(reencoder.component_func_index(i)))?); } wasmparser::ComponentName::Values(map) => { names.values(&name_map(map, |i| Ok(reencoder.component_value_index(i)))?); } wasmparser::ComponentName::Unknown { ty, data, .. } => { names.raw(ty, data); } } Ok(()) } } impl From for crate::ComponentValType { fn from(ty: wasmparser::ComponentValType) -> Self { RoundtripReencoder.component_val_type(ty) } } impl From for crate::TypeBounds { fn from(ty: wasmparser::TypeBounds) -> Self { RoundtripReencoder.type_bounds(ty) } } impl From for crate::CanonicalOption { fn from(opt: wasmparser::CanonicalOption) -> Self { Result::<_, Error>::unwrap(RoundtripReencoder.canonical_option(opt)) } } impl From for crate::ComponentExportKind { fn from(kind: wasmparser::ComponentExternalKind) -> Self { RoundtripReencoder.component_export_kind(kind) } } impl From for crate::ComponentOuterAliasKind { fn from(kind: wasmparser::ComponentOuterAliasKind) -> Self { RoundtripReencoder.component_outer_alias_kind(kind) } } impl From for crate::ComponentTypeRef { fn from(ty: wasmparser::ComponentTypeRef) -> Self { Result::<_, Error>::unwrap(RoundtripReencoder.component_type_ref(ty)) } } impl From for crate::PrimitiveValType { fn from(ty: wasmparser::PrimitiveValType) -> Self { RoundtripReencoder.component_primitive_val_type(ty) } } wasm-encoder-0.239.0/src/reencode.rs000064400000000000000000002236021046102023000153110ustar 00000000000000//! Conversions from `wasmparser` to `wasm-encoder` to [`Reencode`] parsed wasm. //! //! The [`RoundtripReencoder`] allows encoding identical wasm to the parsed //! input. #[cfg(all(not(feature = "std"), core_error))] use core::error::Error as StdError; #[cfg(feature = "std")] use std::error::Error as StdError; use crate::CoreTypeEncoder; use core::convert::Infallible; #[cfg(feature = "component-model")] 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) -> Result> { Ok(utils::data_index(self, data)) } fn element_index(&mut self, element: u32) -> Result> { Ok(utils::element_index(self, element)) } fn function_index(&mut self, func: u32) -> Result> { Ok(utils::function_index(self, func)) } fn global_index(&mut self, global: u32) -> Result> { Ok(utils::global_index(self, global)) } fn memory_index(&mut self, memory: u32) -> Result> { Ok(utils::memory_index(self, memory)) } fn table_index(&mut self, table: u32) -> Result> { Ok(utils::table_index(self, table)) } fn tag_index(&mut self, tag: u32) -> Result> { Ok(utils::tag_index(self, tag)) } fn type_index(&mut self, ty: u32) -> Result> { Ok(utils::type_index(self, ty)) } fn type_index_unpacked( &mut self, ty: wasmparser::UnpackedIndex, ) -> Result> { utils::type_index_unpacked(self, ty) } fn external_index( &mut self, kind: wasmparser::ExternalKind, index: u32, ) -> Result> { match kind { wasmparser::ExternalKind::Func => 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), wasmparser::ExternalKind::Tag => self.tag_index(index), } } fn abstract_heap_type( &mut self, value: wasmparser::AbstractHeapType, ) -> Result> { Ok(utils::abstract_heap_type(self, value)) } fn array_type( &mut self, array_ty: wasmparser::ArrayType, ) -> Result> { utils::array_type(self, array_ty) } fn block_type( &mut self, arg: wasmparser::BlockType, ) -> Result> { utils::block_type(self, arg) } fn const_expr( &mut self, const_expr: wasmparser::ConstExpr, ) -> Result> { utils::const_expr(self, const_expr) } fn catch(&mut self, arg: wasmparser::Catch) -> Result> { utils::catch(self, arg) } fn composite_type( &mut self, composite_ty: wasmparser::CompositeType, ) -> Result> { utils::composite_type(self, composite_ty) } fn entity_type( &mut self, type_ref: wasmparser::TypeRef, ) -> Result> { utils::entity_type(self, type_ref) } fn export_kind( &mut self, external_kind: wasmparser::ExternalKind, ) -> Result> { Ok(utils::export_kind(self, external_kind)) } fn field_type( &mut self, field_ty: wasmparser::FieldType, ) -> Result> { utils::field_type(self, field_ty) } fn func_type( &mut self, func_ty: wasmparser::FuncType, ) -> Result> { utils::func_type(self, func_ty) } fn cont_type( &mut self, cont_ty: wasmparser::ContType, ) -> Result> { utils::cont_type(self, cont_ty) } fn global_type( &mut self, global_ty: wasmparser::GlobalType, ) -> Result> { utils::global_type(self, global_ty) } fn handle(&mut self, on: wasmparser::Handle) -> Result> { utils::handle(self, on) } fn heap_type( &mut self, heap_type: wasmparser::HeapType, ) -> Result> { utils::heap_type(self, heap_type) } fn instruction<'a>( &mut self, arg: wasmparser::Operator<'a>, ) -> Result, Error> { utils::instruction(self, arg) } fn memory_type( &mut self, memory_ty: wasmparser::MemoryType, ) -> Result> { Ok(utils::memory_type(self, memory_ty)) } fn ieee32_arg(&mut self, arg: wasmparser::Ieee32) -> Result> { Ok(utils::ieee32_arg(self, arg)) } fn ieee64_arg(&mut self, arg: wasmparser::Ieee64) -> Result> { Ok(utils::ieee64_arg(self, arg)) } fn mem_arg(&mut self, arg: wasmparser::MemArg) -> Result> { utils::mem_arg(self, arg) } fn ordering( &mut self, arg: wasmparser::Ordering, ) -> Result> { Ok(utils::ordering(self, arg)) } fn ref_type( &mut self, ref_type: wasmparser::RefType, ) -> Result> { utils::ref_type(self, ref_type) } fn storage_type( &mut self, storage_ty: wasmparser::StorageType, ) -> Result> { utils::storage_type(self, storage_ty) } fn struct_type( &mut self, struct_ty: wasmparser::StructType, ) -> Result> { utils::struct_type(self, struct_ty) } fn sub_type( &mut self, sub_ty: wasmparser::SubType, ) -> Result> { utils::sub_type(self, sub_ty) } fn table_type( &mut self, table_ty: wasmparser::TableType, ) -> Result> { utils::table_type(self, table_ty) } fn tag_kind( &mut self, kind: wasmparser::TagKind, ) -> Result> { Ok(utils::tag_kind(self, kind)) } fn tag_type( &mut self, tag_ty: wasmparser::TagType, ) -> Result> { utils::tag_type(self, tag_ty) } fn val_type( &mut self, val_ty: wasmparser::ValType, ) -> Result> { utils::val_type(self, val_ty) } fn val_types( &mut self, val_tys: Vec, ) -> Result, 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( &mut self, module: &mut crate::Module, section: wasmparser::CustomSectionReader<'_>, ) -> Result<(), Error> { utils::parse_custom_section(self, module, section) } /// Converts the input `section` given from the `wasmparser` crate into an /// encoded custom section. fn custom_section<'a>( &mut self, section: wasmparser::CustomSectionReader<'a>, ) -> Result, Error> { Ok(utils::custom_section(self, section)) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the code to the `code` section. fn parse_code_section( &mut self, code: &mut crate::CodeSection, section: wasmparser::CodeSectionReader<'_>, ) -> Result<(), Error> { utils::parse_code_section(self, code, section) } /// Parses a single [`wasmparser::FunctionBody`] and adds it to the `code` section. fn parse_function_body( &mut self, code: &mut crate::CodeSection, func: wasmparser::FunctionBody<'_>, ) -> Result<(), Error> { utils::parse_function_body(self, code, func) } /// Create a new [`crate::Function`] by parsing the locals declarations from the /// provided [`wasmparser::FunctionBody`]. fn new_function_with_parsed_locals( &mut self, func: &wasmparser::FunctionBody<'_>, ) -> Result> { utils::new_function_with_parsed_locals(self, func) } /// Parses a single instruction from `reader` and adds it to `function`. fn parse_instruction<'a>( &mut self, reader: &mut wasmparser::OperatorsReader<'a>, ) -> Result, Error> { utils::parse_instruction(self, reader) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the data to the `data` section. fn parse_data_section( &mut self, data: &mut crate::DataSection, section: wasmparser::DataSectionReader<'_>, ) -> Result<(), Error> { utils::parse_data_section(self, data, section) } /// Parses a single [`wasmparser::Data`] and adds it to the `data` section. fn parse_data( &mut self, data: &mut crate::DataSection, datum: wasmparser::Data<'_>, ) -> Result<(), Error> { utils::parse_data(self, data, datum) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the elements to the `element` section. fn parse_element_section( &mut self, elements: &mut crate::ElementSection, section: wasmparser::ElementSectionReader<'_>, ) -> Result<(), Error> { utils::parse_element_section(self, elements, section) } /// Parses the single [`wasmparser::Element`] provided and adds it to the /// `element` section. fn parse_element( &mut self, elements: &mut crate::ElementSection, element: wasmparser::Element<'_>, ) -> Result<(), Error> { utils::parse_element(self, elements, element) } fn element_items<'a>( &mut self, items: wasmparser::ElementItems<'a>, ) -> Result, Error> { utils::element_items(self, items) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the exports to the `exports` section. fn parse_export_section( &mut self, exports: &mut crate::ExportSection, section: wasmparser::ExportSectionReader<'_>, ) -> Result<(), Error> { utils::parse_export_section(self, exports, section) } /// 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<'_>, ) -> Result<(), Error> { utils::parse_export(self, exports, export) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the functions to the `functions` section. fn parse_function_section( &mut self, functions: &mut crate::FunctionSection, section: wasmparser::FunctionSectionReader<'_>, ) -> Result<(), Error> { utils::parse_function_section(self, functions, section) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the globals to the `globals` section. fn parse_global_section( &mut self, globals: &mut crate::GlobalSection, section: wasmparser::GlobalSectionReader<'_>, ) -> Result<(), Error> { utils::parse_global_section(self, globals, section) } /// Parses the single [`wasmparser::Global`] provided and adds it to the /// `globals` section. fn parse_global( &mut self, globals: &mut crate::GlobalSection, global: wasmparser::Global<'_>, ) -> Result<(), Error> { utils::parse_global(self, globals, global) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the imports to the `import` section. fn parse_import_section( &mut self, imports: &mut crate::ImportSection, section: wasmparser::ImportSectionReader<'_>, ) -> Result<(), Error> { utils::parse_import_section(self, imports, section) } /// Parses the single [`wasmparser::Import`] provided and adds it to the /// `import` section. fn parse_import( &mut self, imports: &mut crate::ImportSection, import: wasmparser::Import<'_>, ) -> Result<(), Error> { utils::parse_import(self, imports, import) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the memories to the `memories` section. fn parse_memory_section( &mut self, memories: &mut crate::MemorySection, section: wasmparser::MemorySectionReader<'_>, ) -> Result<(), Error> { utils::parse_memory_section(self, memories, section) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the tables to the `tables` section. fn parse_table_section( &mut self, tables: &mut crate::TableSection, section: wasmparser::TableSectionReader<'_>, ) -> Result<(), Error> { utils::parse_table_section(self, tables, section) } /// Parses a single [`wasmparser::Table`] and adds it to the `tables` section. fn parse_table( &mut self, tables: &mut crate::TableSection, table: wasmparser::Table<'_>, ) -> Result<(), Error> { utils::parse_table(self, tables, table) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the tags to the `tags` section. fn parse_tag_section( &mut self, tags: &mut crate::TagSection, section: wasmparser::TagSectionReader<'_>, ) -> Result<(), Error> { utils::parse_tag_section(self, tags, section) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the types to the `types` section. fn parse_type_section( &mut self, types: &mut crate::TypeSection, section: wasmparser::TypeSectionReader<'_>, ) -> Result<(), Error> { utils::parse_type_section(self, types, section) } /// Parses a single [`wasmparser::RecGroup`] and adds it to the `types` section. fn parse_recursive_type_group( &mut self, encoder: CoreTypeEncoder, rec_group: wasmparser::RecGroup, ) -> Result<(), Error> { utils::parse_recursive_type_group(self, encoder, rec_group) } fn parse_unknown_section( &mut self, module: &mut crate::Module, id: u8, contents: &[u8], ) -> Result<(), Error> { utils::parse_unknown_section(self, module, id, contents) } /// A hook method that is called inside [`Reencode::parse_core_module`] /// before and after every non-custom core wasm section. /// /// This method can be used to insert new custom sections in between those /// sections, or to detect when a non-custom section is missing and insert /// it in the [proper order]. /// /// The `after` parameter is `None` iff the hook is called before the first /// non-custom section, and `Some(s)` afterwards, where `s` is the /// [`SectionId`] of the previous non-custom section. /// /// The `before` parameter is `None` iff the hook is called after the last /// non-custom section, and `Some(s)` beforehand, where `s` is the /// [`SectionId`] of the following non-custom section. /// /// [proper order]: https://webassembly.github.io/spec/core/binary/modules.html#binary-module /// [`SectionId`]: crate::SectionId fn intersperse_section_hook( &mut self, module: &mut crate::Module, after: Option, before: Option, ) -> Result<(), Error> { utils::intersperse_section_hook(self, module, after, before) } fn parse_core_module( &mut self, module: &mut crate::Module, parser: wasmparser::Parser, data: &[u8], ) -> Result<(), Error> { utils::parse_core_module(self, module, parser, data) } fn custom_name_section( &mut self, section: wasmparser::NameSectionReader<'_>, ) -> Result> { utils::custom_name_section(self, section) } fn parse_custom_name_subsection( &mut self, names: &mut crate::NameSection, section: wasmparser::Name<'_>, ) -> Result<(), Error> { utils::parse_custom_name_subsection(self, names, section) } fn data_count(&mut self, count: u32) -> Result> { Ok(count) } fn start_section(&mut self, start: u32) -> Result> { self.function_index(start) } } /// An error when re-encoding from `wasmparser` to `wasm-encoder`. #[derive(Debug)] pub enum Error { /// There was a type reference that was canonicalized and no longer /// references an index into a module's types space, so we cannot encode it /// into a Wasm binary again. CanonicalizedHeapTypeReference, /// The const expression is invalid: not actually constant or something like /// that. InvalidConstExpr, /// The code section size listed was not valid for the wasm binary provided. InvalidCodeSectionSize, /// There was a section that does not belong in a core wasm module. UnexpectedNonCoreModuleSection, /// 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, /// There was an error when parsing. ParseError(wasmparser::BinaryReaderError), /// There was a user-defined error when re-encoding. UserError(E), } impl From for Error { fn from(err: wasmparser::BinaryReaderError) -> Self { Self::ParseError(err) } } impl core::fmt::Display for Error { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { match self { Self::ParseError(_e) => { write!(fmt, "There was an error when parsing") } Self::UserError(e) => write!(fmt, "{e}"), Self::InvalidConstExpr => write!(fmt, "The const expression was invalid"), Self::UnexpectedNonCoreModuleSection => write!( fmt, "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 in a component" ), Self::CanonicalizedHeapTypeReference => write!( fmt, "There was a canonicalized heap type reference without type index information" ), Self::UnsupportedCoreTypeInComponent => { fmt.write_str("unsupported core type in a component") } Self::InvalidCodeSectionSize => fmt.write_str("invalid code section size"), } } } #[cfg(any(feature = "std", core_error))] impl StdError for Error { fn source(&self) -> Option<&(dyn StdError + 'static)> { match self { Self::ParseError(e) => Some(e), Self::UserError(e) => Some(e), Self::InvalidConstExpr | Self::CanonicalizedHeapTypeReference | Self::UnexpectedNonCoreModuleSection | Self::UnexpectedNonComponentSection | Self::UnsupportedCoreTypeInComponent | Self::InvalidCodeSectionSize => None, } } } /// Reencodes `wasmparser` into `wasm-encoder` so that the encoded wasm is /// identical to the input and can be parsed and encoded again. #[derive(Debug)] pub struct RoundtripReencoder; impl Reencode for RoundtripReencoder { type Error = Infallible; } #[allow(missing_docs)] // FIXME pub mod utils { use super::{Error, Reencode}; use crate::{CoreTypeEncoder, Encode}; use alloc::vec::Vec; use core::ops::Range; pub fn parse_core_module( reencoder: &mut T, module: &mut crate::Module, parser: wasmparser::Parser, data: &[u8], ) -> Result<(), Error> { fn handle_intersperse_section_hook( reencoder: &mut T, module: &mut crate::Module, last_section: &mut Option, next_section: Option, ) -> Result<(), Error> { let after = core::mem::replace(last_section, next_section); let before = next_section; reencoder.intersperse_section_hook(module, after, before) } // Convert from `range` to a byte range within `data` while // 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 overriding `parse_code_section` always get that // function called. let orig_offset = parser.offset() as usize; let get_original_section = |range: Range| { data.get(range.start - orig_offset..range.end - orig_offset) .ok_or(Error::InvalidCodeSectionSize) }; let mut last_section = None; for section in parser.parse_all(data) { match section? { wasmparser::Payload::Version { encoding: wasmparser::Encoding::Module, .. } => (), wasmparser::Payload::Version { .. } => { return Err(Error::UnexpectedNonCoreModuleSection); } wasmparser::Payload::TypeSection(section) => { handle_intersperse_section_hook( reencoder, module, &mut last_section, Some(crate::SectionId::Type), )?; let mut types = crate::TypeSection::new(); reencoder.parse_type_section(&mut types, section)?; module.section(&types); } wasmparser::Payload::ImportSection(section) => { handle_intersperse_section_hook( reencoder, module, &mut last_section, Some(crate::SectionId::Import), )?; let mut imports = crate::ImportSection::new(); reencoder.parse_import_section(&mut imports, section)?; module.section(&imports); } wasmparser::Payload::FunctionSection(section) => { handle_intersperse_section_hook( reencoder, module, &mut last_section, Some(crate::SectionId::Function), )?; let mut functions = crate::FunctionSection::new(); reencoder.parse_function_section(&mut functions, section)?; module.section(&functions); } wasmparser::Payload::TableSection(section) => { handle_intersperse_section_hook( reencoder, module, &mut last_section, Some(crate::SectionId::Table), )?; let mut tables = crate::TableSection::new(); reencoder.parse_table_section(&mut tables, section)?; module.section(&tables); } wasmparser::Payload::MemorySection(section) => { handle_intersperse_section_hook( reencoder, module, &mut last_section, Some(crate::SectionId::Memory), )?; let mut memories = crate::MemorySection::new(); reencoder.parse_memory_section(&mut memories, section)?; module.section(&memories); } wasmparser::Payload::TagSection(section) => { handle_intersperse_section_hook( reencoder, module, &mut last_section, Some(crate::SectionId::Tag), )?; let mut tags = crate::TagSection::new(); reencoder.parse_tag_section(&mut tags, section)?; module.section(&tags); } wasmparser::Payload::GlobalSection(section) => { handle_intersperse_section_hook( reencoder, module, &mut last_section, Some(crate::SectionId::Global), )?; let mut globals = crate::GlobalSection::new(); reencoder.parse_global_section(&mut globals, section)?; module.section(&globals); } wasmparser::Payload::ExportSection(section) => { handle_intersperse_section_hook( reencoder, module, &mut last_section, Some(crate::SectionId::Export), )?; let mut exports = crate::ExportSection::new(); reencoder.parse_export_section(&mut exports, section)?; module.section(&exports); } wasmparser::Payload::StartSection { func, .. } => { handle_intersperse_section_hook( reencoder, module, &mut last_section, Some(crate::SectionId::Start), )?; module.section(&crate::StartSection { function_index: reencoder.start_section(func)?, }); } wasmparser::Payload::ElementSection(section) => { handle_intersperse_section_hook( reencoder, module, &mut last_section, Some(crate::SectionId::Element), )?; let mut elements = crate::ElementSection::new(); reencoder.parse_element_section(&mut elements, section)?; module.section(&elements); } wasmparser::Payload::DataCountSection { count, .. } => { handle_intersperse_section_hook( reencoder, module, &mut last_section, Some(crate::SectionId::DataCount), )?; let count = reencoder.data_count(count)?; module.section(&crate::DataCountSection { count }); } wasmparser::Payload::DataSection(section) => { handle_intersperse_section_hook( reencoder, module, &mut last_section, Some(crate::SectionId::Data), )?; let mut data = crate::DataSection::new(); reencoder.parse_data_section(&mut data, section)?; module.section(&data); } wasmparser::Payload::CodeSectionStart { range, .. } => { handle_intersperse_section_hook( reencoder, module, &mut last_section, Some(crate::SectionId::Code), )?; let mut codes = crate::CodeSection::new(); // Convert from `range` to a byte range within `data` while // 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 overriding `parse_code_section` always get that // function called. let section = get_original_section(range.clone())?; let reader = wasmparser::BinaryReader::new(section, range.start); let section = wasmparser::CodeSectionReader::new(reader)?; reencoder.parse_code_section(&mut codes, section)?; module.section(&codes); } // Parsing of code section entries (function bodies) happens // above during the handling of the code section. That means // that we just skip all these payloads. wasmparser::Payload::CodeSectionEntry(_) => {} #[cfg(feature = "component-model")] wasmparser::Payload::ModuleSection { .. } | wasmparser::Payload::InstanceSection(_) | wasmparser::Payload::CoreTypeSection(_) | wasmparser::Payload::ComponentSection { .. } | wasmparser::Payload::ComponentInstanceSection(_) | wasmparser::Payload::ComponentAliasSection(_) | wasmparser::Payload::ComponentTypeSection(_) | wasmparser::Payload::ComponentCanonicalSection(_) | wasmparser::Payload::ComponentStartSection { .. } | wasmparser::Payload::ComponentImportSection(_) | wasmparser::Payload::ComponentExportSection(_) => { return Err(Error::UnexpectedNonCoreModuleSection); } wasmparser::Payload::CustomSection(section) => { reencoder.parse_custom_section(module, section)?; } wasmparser::Payload::End(_) => { handle_intersperse_section_hook(reencoder, module, &mut last_section, None)?; } other => match other.as_section() { Some((id, range)) => { let section = get_original_section(range)?; reencoder.parse_unknown_section(module, id, section)?; } None => unreachable!(), }, } } Ok(()) } /// A hook method that is called inside [`Reencode::parse_core_module`] /// before and after every non-custom core wasm section. /// /// This method can be used to insert new custom sections in between those /// sections, or to detect when a non-custom section is missing and insert /// it in the [proper order]. /// /// The `after` parameter is `None` iff the hook is called before the first /// non-custom section, and `Some(s)` afterwards, where `s` is the /// [`SectionId`] of the previous non-custom section. /// /// The `before` parameter is `None` iff the hook is called after the last /// non-custom section, and `Some(s)` beforehand, where `s` is the /// [`SectionId`] of the following non-custom section. /// /// [proper order]: https://webassembly.github.io/spec/core/binary/modules.html#binary-module /// [`SectionId`]: crate::SectionId pub fn intersperse_section_hook( _reencoder: &mut T, _module: &mut crate::Module, _after: Option, _before: Option, ) -> Result<(), Error> { Ok(()) } pub fn memory_index(_reencoder: &mut T, memory: u32) -> u32 { memory } pub fn ieee32_arg( _reencoder: &mut T, arg: wasmparser::Ieee32, ) -> crate::Ieee32 { crate::Ieee32(arg.bits()) } pub fn ieee64_arg( _reencoder: &mut T, arg: wasmparser::Ieee64, ) -> crate::Ieee64 { crate::Ieee64(arg.bits()) } pub fn mem_arg( reencoder: &mut T, arg: wasmparser::MemArg, ) -> Result> { Ok(crate::MemArg { offset: arg.offset, align: arg.align.into(), memory_index: reencoder.memory_index(arg.memory)?, }) } pub fn ordering( _reencoder: &mut T, arg: wasmparser::Ordering, ) -> crate::Ordering { match arg { wasmparser::Ordering::SeqCst => crate::Ordering::SeqCst, wasmparser::Ordering::AcqRel => crate::Ordering::AcqRel, } } pub fn function_index(_reencoder: &mut T, func: u32) -> u32 { func } pub fn tag_index(_reencoder: &mut T, tag: u32) -> u32 { tag } pub fn catch( reencoder: &mut T, arg: wasmparser::Catch, ) -> Result> { Ok(match arg { wasmparser::Catch::One { tag, label } => crate::Catch::One { tag: reencoder.tag_index(tag)?, label, }, wasmparser::Catch::OneRef { tag, label } => crate::Catch::OneRef { 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( reencoder: &mut T, arg: wasmparser::Handle, ) -> Result> { Ok(match arg { wasmparser::Handle::OnLabel { tag, label } => crate::Handle::OnLabel { tag: reencoder.tag_index(tag)?, label, }, wasmparser::Handle::OnSwitch { tag } => crate::Handle::OnSwitch { tag: reencoder.tag_index(tag)?, }, }) } /// Parses the input `section` given from the `wasmparser` crate and /// adds the custom section to the `module`. pub fn parse_custom_section( reencoder: &mut T, module: &mut crate::Module, section: wasmparser::CustomSectionReader<'_>, ) -> Result<(), Error> { match section.as_known() { wasmparser::KnownCustom::Name(name) => { module.section(&reencoder.custom_name_section(name)?); } _ => { module.section(&reencoder.custom_section(section)?); } } Ok(()) } /// Converts the input `section` given from the `wasmparser` crate into an /// encoded custom section. pub fn custom_section<'a, T: ?Sized + Reencode>( _reencoder: &mut T, section: wasmparser::CustomSectionReader<'a>, ) -> crate::CustomSection<'a> { crate::CustomSection { data: section.data().into(), name: section.name().into(), } } pub fn export_kind( _reencoder: &mut T, external_kind: wasmparser::ExternalKind, ) -> crate::ExportKind { match external_kind { wasmparser::ExternalKind::Func => crate::ExportKind::Func, wasmparser::ExternalKind::Table => crate::ExportKind::Table, wasmparser::ExternalKind::Memory => crate::ExportKind::Memory, wasmparser::ExternalKind::Global => crate::ExportKind::Global, wasmparser::ExternalKind::Tag => crate::ExportKind::Tag, } } pub fn memory_type( _reencoder: &mut T, memory_ty: wasmparser::MemoryType, ) -> crate::MemoryType { crate::MemoryType { minimum: memory_ty.initial, maximum: memory_ty.maximum, memory64: memory_ty.memory64, shared: memory_ty.shared, page_size_log2: memory_ty.page_size_log2, } } pub fn tag_kind( _reencoder: &mut T, kind: wasmparser::TagKind, ) -> crate::TagKind { match kind { wasmparser::TagKind::Exception => crate::TagKind::Exception, } } pub fn type_index(_reencoder: &mut T, ty: u32) -> u32 { ty } pub fn type_index_unpacked( reencoder: &mut T, ty: wasmparser::UnpackedIndex, ) -> Result> { ty.as_module_index() .ok_or(Error::CanonicalizedHeapTypeReference) .and_then(|ty| reencoder.type_index(ty)) } pub fn tag_type( reencoder: &mut T, tag_ty: wasmparser::TagType, ) -> Result> { 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( _reencoder: &mut T, value: wasmparser::AbstractHeapType, ) -> crate::AbstractHeapType { use wasmparser::AbstractHeapType::*; match value { Func => crate::AbstractHeapType::Func, Extern => crate::AbstractHeapType::Extern, Any => crate::AbstractHeapType::Any, None => crate::AbstractHeapType::None, NoExtern => crate::AbstractHeapType::NoExtern, NoFunc => crate::AbstractHeapType::NoFunc, Eq => crate::AbstractHeapType::Eq, Struct => crate::AbstractHeapType::Struct, Array => crate::AbstractHeapType::Array, I31 => crate::AbstractHeapType::I31, Exn => crate::AbstractHeapType::Exn, NoExn => crate::AbstractHeapType::NoExn, Cont => crate::AbstractHeapType::Cont, NoCont => crate::AbstractHeapType::NoCont, } } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the types to the `types` section. pub fn parse_type_section( reencoder: &mut T, types: &mut crate::TypeSection, section: wasmparser::TypeSectionReader<'_>, ) -> Result<(), Error> { for rec_group in section { reencoder.parse_recursive_type_group(types.ty(), rec_group?)?; } Ok(()) } /// Parses a single [`wasmparser::RecGroup`] and adds it to the `types` section. pub fn parse_recursive_type_group( reencoder: &mut T, encoder: CoreTypeEncoder, rec_group: wasmparser::RecGroup, ) -> Result<(), Error> { if rec_group.is_explicit_rec_group() { let subtypes = rec_group .into_types() .map(|t| reencoder.sub_type(t)) .collect::, _>>()?; encoder.rec(subtypes); } else { let ty = rec_group.into_types().next().unwrap(); encoder.subtype(&reencoder.sub_type(ty)?); } Ok(()) } pub fn sub_type( reencoder: &mut T, sub_ty: wasmparser::SubType, ) -> Result> { Ok(crate::SubType { is_final: sub_ty.is_final, supertype_idx: sub_ty .supertype_idx .map(|i| reencoder.type_index_unpacked(i.unpack())) .transpose()?, composite_type: reencoder.composite_type(sub_ty.composite_type)?, }) } pub fn composite_type( reencoder: &mut T, composite_ty: wasmparser::CompositeType, ) -> Result> { let inner = match composite_ty.inner { wasmparser::CompositeInnerType::Func(f) => { crate::CompositeInnerType::Func(reencoder.func_type(f)?) } wasmparser::CompositeInnerType::Array(a) => { crate::CompositeInnerType::Array(reencoder.array_type(a)?) } wasmparser::CompositeInnerType::Struct(s) => { crate::CompositeInnerType::Struct(reencoder.struct_type(s)?) } wasmparser::CompositeInnerType::Cont(c) => { crate::CompositeInnerType::Cont(reencoder.cont_type(c)?) } }; Ok(crate::CompositeType { inner, shared: composite_ty.shared, }) } pub fn func_type( reencoder: &mut T, func_ty: wasmparser::FuncType, ) -> Result> { let mut buf = Vec::with_capacity(func_ty.params().len() + func_ty.results().len()); for ty in func_ty.params().iter().chain(func_ty.results()).copied() { buf.push(reencoder.val_type(ty)?); } Ok(crate::FuncType::from_parts( buf.into(), func_ty.params().len(), )) } pub fn array_type( reencoder: &mut T, array_ty: wasmparser::ArrayType, ) -> Result> { Ok(crate::ArrayType(reencoder.field_type(array_ty.0)?)) } pub fn struct_type( reencoder: &mut T, struct_ty: wasmparser::StructType, ) -> Result> { Ok(crate::StructType { fields: struct_ty .fields .iter() .map(|field_ty| reencoder.field_type(*field_ty)) .collect::>()?, }) } pub fn field_type( reencoder: &mut T, field_ty: wasmparser::FieldType, ) -> Result> { Ok(crate::FieldType { element_type: reencoder.storage_type(field_ty.element_type)?, mutable: field_ty.mutable, }) } pub fn storage_type( reencoder: &mut T, storage_ty: wasmparser::StorageType, ) -> Result> { Ok(match storage_ty { wasmparser::StorageType::I8 => crate::StorageType::I8, wasmparser::StorageType::I16 => crate::StorageType::I16, wasmparser::StorageType::Val(v) => crate::StorageType::Val(reencoder.val_type(v)?), }) } pub fn cont_type( reencoder: &mut T, cont_ty: wasmparser::ContType, ) -> Result> { Ok(crate::ContType( reencoder.type_index_unpacked(cont_ty.0.unpack())?, )) } pub fn val_type( reencoder: &mut T, val_ty: wasmparser::ValType, ) -> Result> { Ok(match val_ty { wasmparser::ValType::I32 => crate::ValType::I32, wasmparser::ValType::I64 => crate::ValType::I64, wasmparser::ValType::F32 => crate::ValType::F32, wasmparser::ValType::F64 => crate::ValType::F64, wasmparser::ValType::V128 => crate::ValType::V128, wasmparser::ValType::Ref(r) => crate::ValType::Ref(reencoder.ref_type(r)?), }) } pub fn ref_type( reencoder: &mut T, ref_type: wasmparser::RefType, ) -> Result> { Ok(crate::RefType { nullable: ref_type.is_nullable(), heap_type: reencoder.heap_type(ref_type.heap_type())?, }) } pub fn heap_type( reencoder: &mut T, heap_type: wasmparser::HeapType, ) -> Result> { Ok(match heap_type { wasmparser::HeapType::Concrete(i) => { crate::HeapType::Concrete(reencoder.type_index_unpacked(i)?) } wasmparser::HeapType::Abstract { shared, ty } => crate::HeapType::Abstract { shared, ty: reencoder.abstract_heap_type(ty)?, }, }) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the tables to the `tables` section. pub fn parse_table_section( reencoder: &mut T, tables: &mut crate::TableSection, section: wasmparser::TableSectionReader<'_>, ) -> Result<(), Error> { for table in section { reencoder.parse_table(tables, table?)?; } Ok(()) } /// Parses a single [`wasmparser::Table`] and adds it to the `tables` section. pub fn parse_table( reencoder: &mut T, tables: &mut crate::TableSection, table: wasmparser::Table<'_>, ) -> Result<(), Error> { let ty = reencoder.table_type(table.ty)?; match table.init { wasmparser::TableInit::RefNull => { tables.table(ty); } wasmparser::TableInit::Expr(e) => { tables.table_with_init(ty, &reencoder.const_expr(e)?); } } Ok(()) } pub fn table_type( reencoder: &mut T, table_ty: wasmparser::TableType, ) -> Result> { Ok(crate::TableType { element_type: reencoder.ref_type(table_ty.element_type)?, minimum: table_ty.initial, maximum: table_ty.maximum, table64: table_ty.table64, shared: table_ty.shared, }) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the tags to the `tags` section. pub fn parse_tag_section( reencoder: &mut T, tags: &mut crate::TagSection, section: wasmparser::TagSectionReader<'_>, ) -> Result<(), Error> { for tag in section { let tag = tag?; tags.tag(reencoder.tag_type(tag)?); } Ok(()) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the exports to the `exports` section. pub fn parse_export_section( reencoder: &mut T, exports: &mut crate::ExportSection, section: wasmparser::ExportSectionReader<'_>, ) -> Result<(), Error> { for export in section { reencoder.parse_export(exports, export?)?; } Ok(()) } /// Parses the single [`wasmparser::Export`] provided and adds it to the /// `exports` section. pub fn parse_export( reencoder: &mut T, exports: &mut crate::ExportSection, export: wasmparser::Export<'_>, ) -> Result<(), Error> { exports.export( export.name, reencoder.export_kind(export.kind)?, reencoder.external_index(export.kind, export.index)?, ); Ok(()) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the globals to the `globals` section. pub fn parse_global_section( reencoder: &mut T, globals: &mut crate::GlobalSection, section: wasmparser::GlobalSectionReader<'_>, ) -> Result<(), Error> { for global in section { reencoder.parse_global(globals, global?)?; } Ok(()) } /// Parses the single [`wasmparser::Global`] provided and adds it to the /// `globals` section. pub fn parse_global( reencoder: &mut T, globals: &mut crate::GlobalSection, global: wasmparser::Global<'_>, ) -> Result<(), Error> { globals.global( reencoder.global_type(global.ty)?, &reencoder.const_expr(global.init_expr)?, ); Ok(()) } pub fn global_type( reencoder: &mut T, global_ty: wasmparser::GlobalType, ) -> Result> { Ok(crate::GlobalType { val_type: reencoder.val_type(global_ty.content_type)?, mutable: global_ty.mutable, shared: global_ty.shared, }) } pub fn entity_type( reencoder: &mut T, type_ref: wasmparser::TypeRef, ) -> Result> { Ok(match type_ref { wasmparser::TypeRef::Func(i) => crate::EntityType::Function(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::Global(g) => crate::EntityType::Global(reencoder.global_type(g)?), wasmparser::TypeRef::Tag(t) => crate::EntityType::Tag(reencoder.tag_type(t)?), }) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the imports to the `import` section. pub fn parse_import_section( reencoder: &mut T, imports: &mut crate::ImportSection, section: wasmparser::ImportSectionReader<'_>, ) -> Result<(), Error> { for import in section { reencoder.parse_import(imports, import?)?; } Ok(()) } /// Parses the single [`wasmparser::Import`] provided and adds it to the /// `import` section. pub fn parse_import( reencoder: &mut T, imports: &mut crate::ImportSection, import: wasmparser::Import<'_>, ) -> Result<(), Error> { imports.import( import.module, import.name, reencoder.entity_type(import.ty)?, ); Ok(()) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the memories to the `memories` section. pub fn parse_memory_section( reencoder: &mut T, memories: &mut crate::MemorySection, section: wasmparser::MemorySectionReader<'_>, ) -> Result<(), Error> { for memory in section { let memory = memory?; memories.memory(reencoder.memory_type(memory)?); } Ok(()) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the functions to the `functions` section. pub fn parse_function_section( reencoder: &mut T, functions: &mut crate::FunctionSection, section: wasmparser::FunctionSectionReader<'_>, ) -> Result<(), Error> { for func in section { functions.function(reencoder.type_index(func?)?); } Ok(()) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the data to the `data` section. pub fn parse_data_section( reencoder: &mut T, data: &mut crate::DataSection, section: wasmparser::DataSectionReader<'_>, ) -> Result<(), Error> { for datum in section { reencoder.parse_data(data, datum?)?; } Ok(()) } /// Parses a single [`wasmparser::Data`] and adds it to the `data` section. pub fn parse_data( reencoder: &mut T, data: &mut crate::DataSection, datum: wasmparser::Data<'_>, ) -> Result<(), Error> { match datum.kind { wasmparser::DataKind::Active { memory_index, offset_expr, } => data.active( reencoder.memory_index(memory_index)?, &reencoder.const_expr(offset_expr)?, datum.data.iter().copied(), ), wasmparser::DataKind::Passive => data.passive(datum.data.iter().copied()), }; Ok(()) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the elements to the `element` section. pub fn parse_element_section( reencoder: &mut T, elements: &mut crate::ElementSection, section: wasmparser::ElementSectionReader<'_>, ) -> Result<(), Error> { for element in section { reencoder.parse_element(elements, element?)?; } Ok(()) } /// Parses the single [`wasmparser::Element`] provided and adds it to the /// `element` section. pub fn parse_element( reencoder: &mut T, elements: &mut crate::ElementSection, element: wasmparser::Element<'_>, ) -> Result<(), Error> { let elems = reencoder.element_items(element.items)?; match element.kind { wasmparser::ElementKind::Active { table_index, offset_expr, } => elements.active( // Inform the reencoder that a table index is being used even if // it's not actually present here. That helps wasm-mutate for // example which wants to track uses to know when it's ok to // remove a table. // // If the table index started at `None` and is still zero then // 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))?, ) { (None, 0) => None, (_, n) => Some(n), }, &reencoder.const_expr(offset_expr)?, elems, ), wasmparser::ElementKind::Passive => elements.passive(elems), wasmparser::ElementKind::Declared => elements.declared(elems), }; Ok(()) } pub fn element_items<'a, T: ?Sized + Reencode>( reencoder: &mut T, items: wasmparser::ElementItems<'a>, ) -> Result, Error> { Ok(match items { wasmparser::ElementItems::Functions(f) => { let mut funcs = Vec::new(); for func in f { funcs.push(reencoder.function_index(func?)?); } crate::Elements::Functions(funcs.into()) } wasmparser::ElementItems::Expressions(ty, e) => { let mut exprs = Vec::new(); for expr in e { exprs.push(reencoder.const_expr(expr?)?); } crate::Elements::Expressions(reencoder.ref_type(ty)?, exprs.into()) } }) } pub fn table_index(_reencoder: &mut T, table: u32) -> u32 { table } pub fn global_index(_reencoder: &mut T, global: u32) -> u32 { global } pub fn data_index(_reencoder: &mut T, data: u32) -> u32 { data } pub fn element_index(_reencoder: &mut T, element: u32) -> u32 { element } pub fn const_expr( reencoder: &mut T, const_expr: wasmparser::ConstExpr, ) -> Result> { let mut ops = const_expr.get_operators_reader(); let mut bytes = Vec::new(); while !ops.is_end_then_eof() { let insn = reencoder.parse_instruction(&mut ops)?; insn.encode(&mut bytes); } Ok(crate::ConstExpr::raw(bytes)) } pub fn block_type( reencoder: &mut T, arg: wasmparser::BlockType, ) -> Result> { match arg { wasmparser::BlockType::Empty => Ok(crate::BlockType::Empty), wasmparser::BlockType::FuncType(n) => { Ok(crate::BlockType::FunctionType(reencoder.type_index(n)?)) } wasmparser::BlockType::Type(t) => Ok(crate::BlockType::Result(reencoder.val_type(t)?)), } } pub fn instruction<'a, T: ?Sized + Reencode>( reencoder: &mut T, arg: wasmparser::Operator<'a>, ) -> Result, Error> { use crate::Instruction; use alloc::borrow::Cow; macro_rules! translate { ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => { Ok(match arg { $( wasmparser::Operator::$op $({ $($arg),* })? => { $( $(let $arg = translate!(map $arg $arg);)* )? translate!(build $op $($($arg)*)?) } )* unexpected => unreachable!("encountered unexpected Wasm operator: {unexpected:?}"), }) }; // 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 blockty) => (reencoder.block_type($arg)?); (map $arg:ident relative_depth) => ($arg); (map $arg:ident targets) => (( $arg .targets() .collect::, wasmparser::BinaryReaderError>>()? .into(), $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 local_index) => ($arg); (map $arg:ident value) => ($arg); (map $arg:ident lane) => ($arg); (map $arg:ident lanes) => ($arg); (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 resume_table) => (( $arg.handlers.into_iter() .map(|h| reencoder.handle(h)) .collect::, _>>()? .into() )); // This case takes the arguments of a wasmparser instruction and creates // a wasm-encoder instruction. There are a few special cases for where // the structure of a wasmparser instruction differs from that of // 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($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::, _>>()? .into() })); (build $op:ident $arg:ident) => (Instruction::$op($arg)); (build $op:ident $($arg:ident)*) => (Instruction::$op { $($arg),* }); } wasmparser::for_each_operator!(translate) } /// Parses the input `section` given from the `wasmparser` crate and adds /// all the code to the `code` section. pub fn parse_code_section( reencoder: &mut T, code: &mut crate::CodeSection, section: wasmparser::CodeSectionReader<'_>, ) -> Result<(), Error> { for func in section { reencoder.parse_function_body(code, func?)?; } Ok(()) } /// Parses a single [`wasmparser::FunctionBody`] and adds it to the `code` section. pub fn parse_function_body( reencoder: &mut T, code: &mut crate::CodeSection, func: wasmparser::FunctionBody<'_>, ) -> Result<(), Error> { let mut f = reencoder.new_function_with_parsed_locals(&func)?; let mut reader = func.get_operators_reader()?; while !reader.eof() { f.instruction(&reencoder.parse_instruction(&mut reader)?); } code.function(&f); Ok(()) } /// Create a new [`crate::Function`] by parsing the locals declarations from the /// provided [`wasmparser::FunctionBody`]. pub fn new_function_with_parsed_locals( reencoder: &mut T, func: &wasmparser::FunctionBody<'_>, ) -> Result> { let mut locals = Vec::new(); for pair in func.get_locals_reader()? { let (cnt, ty) = pair?; locals.push((cnt, reencoder.val_type(ty)?)); } Ok(crate::Function::new(locals)) } /// Parses a single instruction from `reader` and adds it to `function`. pub fn parse_instruction<'a, T: ?Sized + Reencode>( reencoder: &mut T, reader: &mut wasmparser::OperatorsReader<'a>, ) -> Result, Error> { let instruction = reencoder.instruction(reader.read()?)?; Ok(instruction) } pub fn parse_unknown_section( _reencoder: &mut T, module: &mut crate::Module, id: u8, contents: &[u8], ) -> Result<(), Error> { module.section(&crate::RawSection { id, data: contents }); Ok(()) } pub fn custom_name_section( reencoder: &mut T, section: wasmparser::NameSectionReader<'_>, ) -> Result> { let mut ret = crate::NameSection::new(); for subsection in section { reencoder.parse_custom_name_subsection(&mut ret, subsection?)?; } Ok(ret) } pub fn parse_custom_name_subsection( reencoder: &mut T, names: &mut crate::NameSection, section: wasmparser::Name<'_>, ) -> Result<(), Error> { match section { wasmparser::Name::Module { name, .. } => { names.module(name); } wasmparser::Name::Function(map) => { names.functions(&name_map(map, |i| reencoder.function_index(i))?); } wasmparser::Name::Type(map) => { names.types(&name_map(map, |i| reencoder.type_index(i))?); } wasmparser::Name::Local(map) => { names.locals(&indirect_name_map(map, |i| reencoder.function_index(i))?); } wasmparser::Name::Label(map) => { names.labels(&indirect_name_map(map, |i| reencoder.function_index(i))?); } wasmparser::Name::Table(map) => { names.tables(&name_map(map, |i| reencoder.table_index(i))?); } wasmparser::Name::Memory(map) => { names.memories(&name_map(map, |i| reencoder.memory_index(i))?); } wasmparser::Name::Global(map) => { names.globals(&name_map(map, |i| reencoder.global_index(i))?); } wasmparser::Name::Element(map) => { names.elements(&name_map(map, |i| reencoder.element_index(i))?); } wasmparser::Name::Data(map) => { names.data(&name_map(map, |i| reencoder.data_index(i))?); } wasmparser::Name::Tag(map) => { names.tags(&name_map(map, |i| reencoder.tag_index(i))?); } wasmparser::Name::Field(map) => { names.fields(&indirect_name_map(map, |i| reencoder.type_index(i))?); } wasmparser::Name::Unknown { ty, data, .. } => { names.raw(ty, data); } } Ok(()) } pub fn name_map( map: wasmparser::NameMap<'_>, mut map_index: impl FnMut(u32) -> Result>, ) -> Result> { let mut ret = crate::NameMap::new(); for naming in map { let naming = naming?; ret.append(map_index(naming.index)?, naming.name); } Ok(ret) } pub fn indirect_name_map( map: wasmparser::IndirectNameMap<'_>, mut map_index: impl FnMut(u32) -> Result>, ) -> Result> { let mut ret = crate::IndirectNameMap::new(); for naming in map { let naming = naming?; ret.append( map_index(naming.index)?, &name_map(naming.names, |i| Ok(i))?, ); } Ok(ret) } } impl From for crate::Ieee32 { fn from(arg: wasmparser::Ieee32) -> Self { utils::ieee32_arg(&mut RoundtripReencoder, arg) } } impl From for crate::Ieee64 { fn from(arg: wasmparser::Ieee64) -> Self { utils::ieee64_arg(&mut RoundtripReencoder, arg) } } impl TryFrom for crate::MemArg { type Error = Error; fn try_from(arg: wasmparser::MemArg) -> Result { RoundtripReencoder.mem_arg(arg) } } impl From for crate::Ordering { fn from(arg: wasmparser::Ordering) -> Self { utils::ordering(&mut RoundtripReencoder, arg) } } impl TryFrom for crate::BlockType { type Error = Error; fn try_from(arg: wasmparser::BlockType) -> Result { RoundtripReencoder.block_type(arg) } } impl<'a> TryFrom> for crate::Instruction<'a> { type Error = Error; fn try_from(arg: wasmparser::Operator<'a>) -> Result { RoundtripReencoder.instruction(arg) } } impl TryFrom for crate::Catch { type Error = Error; fn try_from(arg: wasmparser::Catch) -> Result { RoundtripReencoder.catch(arg) } } impl<'a> TryFrom> for crate::ConstExpr { type Error = Error; fn try_from(const_expr: wasmparser::ConstExpr) -> Result { RoundtripReencoder.const_expr(const_expr) } } impl<'a> From> for crate::CustomSection<'a> { fn from(section: wasmparser::CustomSectionReader<'a>) -> Self { utils::custom_section(&mut RoundtripReencoder, section) } } impl From for crate::ExportKind { fn from(external_kind: wasmparser::ExternalKind) -> Self { utils::export_kind(&mut RoundtripReencoder, external_kind) } } impl TryFrom for crate::GlobalType { type Error = Error; fn try_from(global_ty: wasmparser::GlobalType) -> Result { RoundtripReencoder.global_type(global_ty) } } impl TryFrom for crate::Handle { type Error = Error; fn try_from(arg: wasmparser::Handle) -> Result { RoundtripReencoder.handle(arg) } } impl TryFrom for crate::EntityType { type Error = Error; fn try_from(type_ref: wasmparser::TypeRef) -> Result { RoundtripReencoder.entity_type(type_ref) } } impl From for crate::MemoryType { fn from(memory_ty: wasmparser::MemoryType) -> Self { utils::memory_type(&mut RoundtripReencoder, memory_ty) } } impl TryFrom for crate::TableType { type Error = Error; fn try_from(table_ty: wasmparser::TableType) -> Result { RoundtripReencoder.table_type(table_ty) } } impl From for crate::TagKind { fn from(kind: wasmparser::TagKind) -> Self { utils::tag_kind(&mut RoundtripReencoder, kind) } } impl TryFrom for crate::TagType { type Error = Error; fn try_from(tag_ty: wasmparser::TagType) -> Result { RoundtripReencoder.tag_type(tag_ty) } } impl TryFrom for crate::SubType { type Error = Error; fn try_from(sub_ty: wasmparser::SubType) -> Result { RoundtripReencoder.sub_type(sub_ty) } } impl TryFrom for crate::CompositeType { type Error = Error; fn try_from(composite_ty: wasmparser::CompositeType) -> Result { RoundtripReencoder.composite_type(composite_ty) } } impl TryFrom for crate::FuncType { type Error = Error; fn try_from(func_ty: wasmparser::FuncType) -> Result { RoundtripReencoder.func_type(func_ty) } } impl TryFrom for crate::ArrayType { type Error = Error; fn try_from(array_ty: wasmparser::ArrayType) -> Result { RoundtripReencoder.array_type(array_ty) } } impl TryFrom for crate::StructType { type Error = Error; fn try_from(struct_ty: wasmparser::StructType) -> Result { RoundtripReencoder.struct_type(struct_ty) } } impl TryFrom for crate::FieldType { type Error = Error; fn try_from(field_ty: wasmparser::FieldType) -> Result { RoundtripReencoder.field_type(field_ty) } } impl TryFrom for crate::StorageType { type Error = Error; fn try_from(storage_ty: wasmparser::StorageType) -> Result { RoundtripReencoder.storage_type(storage_ty) } } impl TryFrom for crate::ValType { type Error = Error; fn try_from(val_ty: wasmparser::ValType) -> Result { RoundtripReencoder.val_type(val_ty) } } impl TryFrom for crate::RefType { type Error = Error; fn try_from(ref_type: wasmparser::RefType) -> Result { RoundtripReencoder.ref_type(ref_type) } } impl TryFrom for crate::HeapType { type Error = Error; fn try_from(heap_type: wasmparser::HeapType) -> Result { crate::reencode::utils::heap_type(&mut crate::reencode::RoundtripReencoder, heap_type) } } impl From for crate::AbstractHeapType { fn from(value: wasmparser::AbstractHeapType) -> Self { utils::abstract_heap_type(&mut RoundtripReencoder, value) } }