wasm-encoder-0.217.0/.cargo_vcs_info.json0000644000000001610000000000100135650ustar { "git": { "sha1": "46cb2e80abe9e57c422a3496032dd4c49bdefcd9" }, "path_in_vcs": "crates/wasm-encoder" }wasm-encoder-0.217.0/Cargo.toml0000644000000031020000000000100115610ustar # 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.217.0" authors = ["Nick Fitzgerald "] build = 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 [lib] name = "wasm_encoder" path = "src/lib.rs" [dependencies.leb128] version = "0.2.4" [dependencies.wasmparser] version = "0.217.0" features = ["std"] optional = true default-features = false [dev-dependencies.anyhow] version = "1.0.58" [dev-dependencies.tempfile] version = "3.2.0" [lints.clippy] clone_on_copy = "warn" manual_strip = "warn" map_clone = "warn" unnecessary_to_owned = "warn" [lints.clippy.all] level = "allow" priority = -1 [lints.rust] unsafe_code = "deny" wasm-encoder-0.217.0/Cargo.toml.orig000064400000000000000000000015471046102023000152550ustar 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] leb128 = { workspace = true } # Enable this dependency to get a bunch of `From for # wasm_encoder::Foo` impls. wasmparser = { optional = true, workspace = true } [dev-dependencies] anyhow = { workspace = true } tempfile = "3.2.0" wasmparser = { path = "../wasmparser" } wasm-encoder-0.217.0/README.md000064400000000000000000000045671046102023000136520ustar 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, Instruction, Module, TypeSection, ValType, }; let mut module = Module::new(); // Encode the type section. let mut types = TypeSection::new(); let params = vec![ValType::I32, ValType::I32]; let results = vec![ValType::I32]; types.function(params, results); module.section(&types); // Encode the function section. let mut functions = FunctionSection::new(); let type_index = 0; functions.function(type_index); module.section(&functions); // Encode the export section. let mut exports = ExportSection::new(); exports.export("f", 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.instruction(&Instruction::LocalGet(0)); f.instruction(&Instruction::LocalGet(1)); f.instruction(&Instruction::I32Add); f.instruction(&Instruction::End); codes.function(&f); module.section(&codes); // Extract the encoded Wasm bytes for this module. let wasm_bytes = module.finish(); // We generated a valid Wasm module! assert!(wasmparser::validate(&wasm_bytes).is_ok()); ``` # License This project is licensed under the Apache 2.0 license with the LLVM exception. See [LICENSE](LICENSE) for more details. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be licensed as above, without any additional terms or conditions. wasm-encoder-0.217.0/src/component/aliases.rs000064400000000000000000000111151046102023000171360ustar 00000000000000use super::{COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, CORE_TYPE_SORT, TYPE_SORT}; use crate::{ encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind, }; /// 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.217.0/src/component/builder.rs000064400000000000000000000365271046102023000171610ustar 00000000000000use crate::component::*; use crate::{ExportKind, Module, RawSection, ValType}; use std::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 crated. 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 crated. 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 crated. 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, }) } /// Creates an alias to a previous core 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_core_export(&mut self, instance: u32, name: &str, kind: ExportKind) -> u32 { self.alias(Alias::CoreInstanceExport { 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, CoreTypeEncoder<'_>) { (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 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.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) } /// 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.217.0/src/component/canonicals.rs000064400000000000000000000115441046102023000176350ustar 00000000000000use crate::{encode_section, ComponentSection, ComponentSectionId, Encode}; /// 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), } 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); } } } } /// 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, { let options = options.into_iter(); self.bytes.push(0x00); self.bytes.push(0x00); core_func_index.encode(&mut self.bytes); options.len().encode(&mut self.bytes); for option in options { option.encode(&mut self.bytes); } 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, { let options = options.into_iter(); self.bytes.push(0x01); self.bytes.push(0x00); func_index.encode(&mut self.bytes); options.len().encode(&mut self.bytes); for option in options { option.encode(&mut self.bytes); } self.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 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 } } 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.217.0/src/component/components.rs000064400000000000000000000014021046102023000177000ustar 00000000000000use crate::{Component, ComponentSection, ComponentSectionId, Encode}; /// 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.217.0/src/component/exports.rs000064400000000000000000000064531046102023000172320ustar 00000000000000use super::{ COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, FUNCTION_SORT, INSTANCE_SORT, TYPE_SORT, VALUE_SORT, }; use crate::{encode_section, ComponentSection, ComponentSectionId, ComponentTypeRef, Encode}; /// 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.217.0/src/component/imports.rs000064400000000000000000000120251046102023000172130ustar 00000000000000use crate::{ encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, ComponentValType, Encode, }; /// 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(PrimitiveValType::String); /// /// // 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.217.0/src/component/instances.rs000064400000000000000000000127501046102023000175120ustar 00000000000000use super::CORE_INSTANCE_SORT; use crate::{ encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind, }; /// 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.217.0/src/component/modules.rs000064400000000000000000000013221046102023000171640ustar 00000000000000use crate::{ComponentSection, ComponentSectionId, Encode, Module}; /// 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.217.0/src/component/names.rs000064400000000000000000000113331046102023000166220ustar 00000000000000use std::borrow::Cow; use super::*; use crate::{encoding_size, ExportKind, NameMap, SectionId}; /// 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 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.217.0/src/component/start.rs000064400000000000000000000025411046102023000166550ustar 00000000000000use crate::{ComponentSection, ComponentSectionId, Encode}; /// 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.217.0/src/component/types.rs000064400000000000000000000535651046102023000167000ustar 00000000000000use super::CORE_TYPE_SORT; use crate::{ encode_section, Alias, ComponentExportKind, ComponentOuterAliasKind, ComponentSection, ComponentSectionId, ComponentTypeRef, Encode, EntityType, ValType, }; /// 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(&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 CoreTypeEncoder<'a>(pub(crate) &'a mut Vec); impl<'a> CoreTypeEncoder<'a> { /// Define a function type. pub fn function(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.0.push(0x60); params.len().encode(self.0); params.for_each(|p| p.encode(self.0)); results.len().encode(self.0); results.for_each(|p| p.encode(self.0)); } /// Define a module type. pub fn module(self, ty: &ModuleType) { ty.encode(self.0); } } /// An encoder for the core type section of WebAssembly components. /// /// # Example /// /// ```rust /// use wasm_encoder::{Component, CoreTypeSection, ModuleType}; /// /// let mut types = CoreTypeSection::new(); /// /// types.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) -> CoreTypeEncoder<'_> { self.num_added += 1; CoreTypeEncoder(&mut self.bytes) } /// Define a function type in this type section. pub fn function(&mut self, params: P, results: R) -> &mut Self where P: IntoIterator, P::IntoIter: ExactSizeIterator, R: IntoIterator, R::IntoIter: ExactSizeIterator, { self.ty().function(params, results); self } /// Define a module type in this type section. /// /// Currently this is only used for core type sections in components. pub fn module(&mut self, ty: &ModuleType) -> &mut Self { self.ty().module(ty); self } } 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) -> CoreTypeEncoder { self.bytes.push(0x00); self.num_added += 1; self.core_types_added += 1; CoreTypeEncoder(&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) -> CoreTypeEncoder { 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: impl Into) -> &mut Self { assert!(self.params_encoded); assert!(!self.results_encoded); self.results_encoded = true; self.sink.push(0x00); ty.into().encode(self.sink); self } /// Defines named results. /// /// This method cannot be used with `result`. /// /// # Panics /// /// This method will panic if the function is called twice, called before /// the `params` method, or called in addition to the `result` method. pub fn results<'b, R, T>(&mut self, results: R) -> &mut Self where R: IntoIterator, R::IntoIter: ExactSizeIterator, T: Into, { assert!(self.params_encoded); assert!(!self.results_encoded); self.results_encoded = true; self.sink.push(0x01); let results = results.into_iter(); results.len().encode(self.sink); for (name, ty) in results { name.encode(self.sink); ty.into().encode(self.sink); } self } } /// 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, } 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, }); } } /// 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 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); } } /// 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(PrimitiveValType::String); /// /// 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.217.0/src/component.rs000064400000000000000000000102601046102023000155150ustar 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}; // 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.217.0/src/core/code.rs000064400000000000000000003525261046102023000153730ustar 00000000000000use crate::{encode_section, Encode, HeapType, RefType, Section, SectionId, ValType}; use std::borrow::Cow; /// An encoder for the code section. /// /// Code sections are only supported for modules. /// /// # Example /// /// ``` /// use wasm_encoder::{ /// CodeSection, Function, FunctionSection, Instruction, Module, /// TypeSection, ValType /// }; /// /// let mut types = TypeSection::new(); /// types.function(vec![], vec![ValType::I32]); /// /// let mut functions = FunctionSection::new(); /// let type_index = 0; /// functions.function(type_index); /// /// let locals = vec![]; /// let mut func = Function::new(locals); /// func.instruction(&Instruction::I32Const(42)); /// let mut code = CodeSection::new(); /// code.function(&func); /// /// let mut module = Module::new(); /// module /// .section(&types) /// .section(&functions) /// .section(&code); /// /// let wasm_bytes = module.finish(); /// ``` #[derive(Clone, 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, Instruction}; /// /// // Define the function body for: /// // /// // (func (param i32 i32) (result i32) /// // local.get 0 /// // local.get 1 /// // i32.add) /// let locals = vec![]; /// let mut func = Function::new(locals); /// func.instruction(&Instruction::LocalGet(0)); /// func.instruction(&Instruction::LocalGet(1)); /// func.instruction(&Instruction::I32Add); /// /// // Add our function to the code section. /// let mut code = CodeSection::new(); /// code.function(&func); /// ``` #[derive(Clone, Debug, 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) } /// 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 [`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, Instruction}; /// let mut f = Function::new([]); /// f.instruction(&Instruction::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); } } /// 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(f32), F64Const(f64), 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), 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, } impl Encode for Instruction<'_> { fn encode(&self, sink: &mut Vec) { match *self { // Control instructions. Instruction::Unreachable => sink.push(0x00), Instruction::Nop => sink.push(0x01), Instruction::Block(bt) => { sink.push(0x02); bt.encode(sink); } Instruction::Loop(bt) => { sink.push(0x03); bt.encode(sink); } Instruction::If(bt) => { sink.push(0x04); bt.encode(sink); } Instruction::Else => sink.push(0x05), Instruction::Try(bt) => { sink.push(0x06); bt.encode(sink); } Instruction::Catch(t) => { sink.push(0x07); t.encode(sink); } Instruction::Throw(t) => { sink.push(0x08); t.encode(sink); } Instruction::Rethrow(l) => { sink.push(0x09); l.encode(sink); } Instruction::ThrowRef => { sink.push(0x0A); } Instruction::End => sink.push(0x0B), Instruction::Br(l) => { sink.push(0x0C); l.encode(sink); } Instruction::BrIf(l) => { sink.push(0x0D); l.encode(sink); } Instruction::BrTable(ref ls, l) => { sink.push(0x0E); ls.encode(sink); l.encode(sink); } Instruction::BrOnNull(l) => { sink.push(0xD5); l.encode(sink); } Instruction::BrOnNonNull(l) => { sink.push(0xD6); l.encode(sink); } Instruction::Return => sink.push(0x0F), Instruction::Call(f) => { sink.push(0x10); f.encode(sink); } Instruction::CallRef(ty) => { sink.push(0x14); ty.encode(sink); } Instruction::CallIndirect { type_index, table_index, } => { sink.push(0x11); type_index.encode(sink); table_index.encode(sink); } Instruction::ReturnCallRef(ty) => { sink.push(0x15); ty.encode(sink); } Instruction::ReturnCall(f) => { sink.push(0x12); f.encode(sink); } Instruction::ReturnCallIndirect { type_index, table_index, } => { sink.push(0x13); type_index.encode(sink); table_index.encode(sink); } Instruction::Delegate(l) => { sink.push(0x18); l.encode(sink); } Instruction::CatchAll => { sink.push(0x19); } // Parametric instructions. Instruction::Drop => sink.push(0x1A), Instruction::Select => sink.push(0x1B), Instruction::TypedSelect(ty) => { sink.push(0x1c); [ty].encode(sink); } Instruction::TryTable(ty, ref catches) => { sink.push(0x1f); ty.encode(sink); catches.encode(sink); } // Variable instructions. Instruction::LocalGet(l) => { sink.push(0x20); l.encode(sink); } Instruction::LocalSet(l) => { sink.push(0x21); l.encode(sink); } Instruction::LocalTee(l) => { sink.push(0x22); l.encode(sink); } Instruction::GlobalGet(g) => { sink.push(0x23); g.encode(sink); } Instruction::GlobalSet(g) => { sink.push(0x24); g.encode(sink); } Instruction::TableGet(table) => { sink.push(0x25); table.encode(sink); } Instruction::TableSet(table) => { sink.push(0x26); table.encode(sink); } // Memory instructions. Instruction::I32Load(m) => { sink.push(0x28); m.encode(sink); } Instruction::I64Load(m) => { sink.push(0x29); m.encode(sink); } Instruction::F32Load(m) => { sink.push(0x2A); m.encode(sink); } Instruction::F64Load(m) => { sink.push(0x2B); m.encode(sink); } Instruction::I32Load8S(m) => { sink.push(0x2C); m.encode(sink); } Instruction::I32Load8U(m) => { sink.push(0x2D); m.encode(sink); } Instruction::I32Load16S(m) => { sink.push(0x2E); m.encode(sink); } Instruction::I32Load16U(m) => { sink.push(0x2F); m.encode(sink); } Instruction::I64Load8S(m) => { sink.push(0x30); m.encode(sink); } Instruction::I64Load8U(m) => { sink.push(0x31); m.encode(sink); } Instruction::I64Load16S(m) => { sink.push(0x32); m.encode(sink); } Instruction::I64Load16U(m) => { sink.push(0x33); m.encode(sink); } Instruction::I64Load32S(m) => { sink.push(0x34); m.encode(sink); } Instruction::I64Load32U(m) => { sink.push(0x35); m.encode(sink); } Instruction::I32Store(m) => { sink.push(0x36); m.encode(sink); } Instruction::I64Store(m) => { sink.push(0x37); m.encode(sink); } Instruction::F32Store(m) => { sink.push(0x38); m.encode(sink); } Instruction::F64Store(m) => { sink.push(0x39); m.encode(sink); } Instruction::I32Store8(m) => { sink.push(0x3A); m.encode(sink); } Instruction::I32Store16(m) => { sink.push(0x3B); m.encode(sink); } Instruction::I64Store8(m) => { sink.push(0x3C); m.encode(sink); } Instruction::I64Store16(m) => { sink.push(0x3D); m.encode(sink); } Instruction::I64Store32(m) => { sink.push(0x3E); m.encode(sink); } Instruction::MemorySize(i) => { sink.push(0x3F); i.encode(sink); } Instruction::MemoryGrow(i) => { sink.push(0x40); i.encode(sink); } Instruction::MemoryInit { mem, data_index } => { sink.push(0xfc); sink.push(0x08); data_index.encode(sink); mem.encode(sink); } Instruction::DataDrop(data) => { sink.push(0xfc); sink.push(0x09); data.encode(sink); } Instruction::MemoryCopy { src_mem, dst_mem } => { sink.push(0xfc); sink.push(0x0a); dst_mem.encode(sink); src_mem.encode(sink); } Instruction::MemoryFill(mem) => { sink.push(0xfc); sink.push(0x0b); mem.encode(sink); } Instruction::MemoryDiscard(mem) => { sink.push(0xfc); sink.push(0x12); mem.encode(sink); } // Numeric instructions. Instruction::I32Const(x) => { sink.push(0x41); x.encode(sink); } Instruction::I64Const(x) => { sink.push(0x42); x.encode(sink); } Instruction::F32Const(x) => { sink.push(0x43); let x = x.to_bits(); sink.extend(x.to_le_bytes().iter().copied()); } Instruction::F64Const(x) => { sink.push(0x44); let x = x.to_bits(); sink.extend(x.to_le_bytes().iter().copied()); } Instruction::I32Eqz => sink.push(0x45), Instruction::I32Eq => sink.push(0x46), Instruction::I32Ne => sink.push(0x47), Instruction::I32LtS => sink.push(0x48), Instruction::I32LtU => sink.push(0x49), Instruction::I32GtS => sink.push(0x4A), Instruction::I32GtU => sink.push(0x4B), Instruction::I32LeS => sink.push(0x4C), Instruction::I32LeU => sink.push(0x4D), Instruction::I32GeS => sink.push(0x4E), Instruction::I32GeU => sink.push(0x4F), Instruction::I64Eqz => sink.push(0x50), Instruction::I64Eq => sink.push(0x51), Instruction::I64Ne => sink.push(0x52), Instruction::I64LtS => sink.push(0x53), Instruction::I64LtU => sink.push(0x54), Instruction::I64GtS => sink.push(0x55), Instruction::I64GtU => sink.push(0x56), Instruction::I64LeS => sink.push(0x57), Instruction::I64LeU => sink.push(0x58), Instruction::I64GeS => sink.push(0x59), Instruction::I64GeU => sink.push(0x5A), Instruction::F32Eq => sink.push(0x5B), Instruction::F32Ne => sink.push(0x5C), Instruction::F32Lt => sink.push(0x5D), Instruction::F32Gt => sink.push(0x5E), Instruction::F32Le => sink.push(0x5F), Instruction::F32Ge => sink.push(0x60), Instruction::F64Eq => sink.push(0x61), Instruction::F64Ne => sink.push(0x62), Instruction::F64Lt => sink.push(0x63), Instruction::F64Gt => sink.push(0x64), Instruction::F64Le => sink.push(0x65), Instruction::F64Ge => sink.push(0x66), Instruction::I32Clz => sink.push(0x67), Instruction::I32Ctz => sink.push(0x68), Instruction::I32Popcnt => sink.push(0x69), Instruction::I32Add => sink.push(0x6A), Instruction::I32Sub => sink.push(0x6B), Instruction::I32Mul => sink.push(0x6C), Instruction::I32DivS => sink.push(0x6D), Instruction::I32DivU => sink.push(0x6E), Instruction::I32RemS => sink.push(0x6F), Instruction::I32RemU => sink.push(0x70), Instruction::I32And => sink.push(0x71), Instruction::I32Or => sink.push(0x72), Instruction::I32Xor => sink.push(0x73), Instruction::I32Shl => sink.push(0x74), Instruction::I32ShrS => sink.push(0x75), Instruction::I32ShrU => sink.push(0x76), Instruction::I32Rotl => sink.push(0x77), Instruction::I32Rotr => sink.push(0x78), Instruction::I64Clz => sink.push(0x79), Instruction::I64Ctz => sink.push(0x7A), Instruction::I64Popcnt => sink.push(0x7B), Instruction::I64Add => sink.push(0x7C), Instruction::I64Sub => sink.push(0x7D), Instruction::I64Mul => sink.push(0x7E), Instruction::I64DivS => sink.push(0x7F), Instruction::I64DivU => sink.push(0x80), Instruction::I64RemS => sink.push(0x81), Instruction::I64RemU => sink.push(0x82), Instruction::I64And => sink.push(0x83), Instruction::I64Or => sink.push(0x84), Instruction::I64Xor => sink.push(0x85), Instruction::I64Shl => sink.push(0x86), Instruction::I64ShrS => sink.push(0x87), Instruction::I64ShrU => sink.push(0x88), Instruction::I64Rotl => sink.push(0x89), Instruction::I64Rotr => sink.push(0x8A), Instruction::F32Abs => sink.push(0x8B), Instruction::F32Neg => sink.push(0x8C), Instruction::F32Ceil => sink.push(0x8D), Instruction::F32Floor => sink.push(0x8E), Instruction::F32Trunc => sink.push(0x8F), Instruction::F32Nearest => sink.push(0x90), Instruction::F32Sqrt => sink.push(0x91), Instruction::F32Add => sink.push(0x92), Instruction::F32Sub => sink.push(0x93), Instruction::F32Mul => sink.push(0x94), Instruction::F32Div => sink.push(0x95), Instruction::F32Min => sink.push(0x96), Instruction::F32Max => sink.push(0x97), Instruction::F32Copysign => sink.push(0x98), Instruction::F64Abs => sink.push(0x99), Instruction::F64Neg => sink.push(0x9A), Instruction::F64Ceil => sink.push(0x9B), Instruction::F64Floor => sink.push(0x9C), Instruction::F64Trunc => sink.push(0x9D), Instruction::F64Nearest => sink.push(0x9E), Instruction::F64Sqrt => sink.push(0x9F), Instruction::F64Add => sink.push(0xA0), Instruction::F64Sub => sink.push(0xA1), Instruction::F64Mul => sink.push(0xA2), Instruction::F64Div => sink.push(0xA3), Instruction::F64Min => sink.push(0xA4), Instruction::F64Max => sink.push(0xA5), Instruction::F64Copysign => sink.push(0xA6), Instruction::I32WrapI64 => sink.push(0xA7), Instruction::I32TruncF32S => sink.push(0xA8), Instruction::I32TruncF32U => sink.push(0xA9), Instruction::I32TruncF64S => sink.push(0xAA), Instruction::I32TruncF64U => sink.push(0xAB), Instruction::I64ExtendI32S => sink.push(0xAC), Instruction::I64ExtendI32U => sink.push(0xAD), Instruction::I64TruncF32S => sink.push(0xAE), Instruction::I64TruncF32U => sink.push(0xAF), Instruction::I64TruncF64S => sink.push(0xB0), Instruction::I64TruncF64U => sink.push(0xB1), Instruction::F32ConvertI32S => sink.push(0xB2), Instruction::F32ConvertI32U => sink.push(0xB3), Instruction::F32ConvertI64S => sink.push(0xB4), Instruction::F32ConvertI64U => sink.push(0xB5), Instruction::F32DemoteF64 => sink.push(0xB6), Instruction::F64ConvertI32S => sink.push(0xB7), Instruction::F64ConvertI32U => sink.push(0xB8), Instruction::F64ConvertI64S => sink.push(0xB9), Instruction::F64ConvertI64U => sink.push(0xBA), Instruction::F64PromoteF32 => sink.push(0xBB), Instruction::I32ReinterpretF32 => sink.push(0xBC), Instruction::I64ReinterpretF64 => sink.push(0xBD), Instruction::F32ReinterpretI32 => sink.push(0xBE), Instruction::F64ReinterpretI64 => sink.push(0xBF), Instruction::I32Extend8S => sink.push(0xC0), Instruction::I32Extend16S => sink.push(0xC1), Instruction::I64Extend8S => sink.push(0xC2), Instruction::I64Extend16S => sink.push(0xC3), Instruction::I64Extend32S => sink.push(0xC4), Instruction::I32TruncSatF32S => { sink.push(0xFC); sink.push(0x00); } Instruction::I32TruncSatF32U => { sink.push(0xFC); sink.push(0x01); } Instruction::I32TruncSatF64S => { sink.push(0xFC); sink.push(0x02); } Instruction::I32TruncSatF64U => { sink.push(0xFC); sink.push(0x03); } Instruction::I64TruncSatF32S => { sink.push(0xFC); sink.push(0x04); } Instruction::I64TruncSatF32U => { sink.push(0xFC); sink.push(0x05); } Instruction::I64TruncSatF64S => { sink.push(0xFC); sink.push(0x06); } Instruction::I64TruncSatF64U => { sink.push(0xFC); sink.push(0x07); } // Reference types instructions. Instruction::RefNull(ty) => { sink.push(0xd0); ty.encode(sink); } Instruction::RefIsNull => sink.push(0xd1), Instruction::RefFunc(f) => { sink.push(0xd2); f.encode(sink); } Instruction::RefEq => sink.push(0xd3), Instruction::RefAsNonNull => sink.push(0xd4), // GC instructions. Instruction::StructNew(type_index) => { sink.push(0xfb); sink.push(0x00); type_index.encode(sink); } Instruction::StructNewDefault(type_index) => { sink.push(0xfb); sink.push(0x01); type_index.encode(sink); } Instruction::StructGet { struct_type_index, field_index, } => { sink.push(0xfb); sink.push(0x02); struct_type_index.encode(sink); field_index.encode(sink); } Instruction::StructGetS { struct_type_index, field_index, } => { sink.push(0xfb); sink.push(0x03); struct_type_index.encode(sink); field_index.encode(sink); } Instruction::StructGetU { struct_type_index, field_index, } => { sink.push(0xfb); sink.push(0x04); struct_type_index.encode(sink); field_index.encode(sink); } Instruction::StructSet { struct_type_index, field_index, } => { sink.push(0xfb); sink.push(0x05); struct_type_index.encode(sink); field_index.encode(sink); } Instruction::ArrayNew(type_index) => { sink.push(0xfb); sink.push(0x06); type_index.encode(sink); } Instruction::ArrayNewDefault(type_index) => { sink.push(0xfb); sink.push(0x07); type_index.encode(sink); } Instruction::ArrayNewFixed { array_type_index, array_size, } => { sink.push(0xfb); sink.push(0x08); array_type_index.encode(sink); array_size.encode(sink); } Instruction::ArrayNewData { array_type_index, array_data_index, } => { sink.push(0xfb); sink.push(0x09); array_type_index.encode(sink); array_data_index.encode(sink); } Instruction::ArrayNewElem { array_type_index, array_elem_index, } => { sink.push(0xfb); sink.push(0x0a); array_type_index.encode(sink); array_elem_index.encode(sink); } Instruction::ArrayGet(type_index) => { sink.push(0xfb); sink.push(0x0b); type_index.encode(sink); } Instruction::ArrayGetS(type_index) => { sink.push(0xfb); sink.push(0x0c); type_index.encode(sink); } Instruction::ArrayGetU(type_index) => { sink.push(0xfb); sink.push(0x0d); type_index.encode(sink); } Instruction::ArraySet(type_index) => { sink.push(0xfb); sink.push(0x0e); type_index.encode(sink); } Instruction::ArrayLen => { sink.push(0xfb); sink.push(0x0f); } Instruction::ArrayFill(type_index) => { sink.push(0xfb); sink.push(0x10); type_index.encode(sink); } Instruction::ArrayCopy { array_type_index_dst, array_type_index_src, } => { sink.push(0xfb); sink.push(0x11); array_type_index_dst.encode(sink); array_type_index_src.encode(sink); } Instruction::ArrayInitData { array_type_index, array_data_index, } => { sink.push(0xfb); sink.push(0x12); array_type_index.encode(sink); array_data_index.encode(sink); } Instruction::ArrayInitElem { array_type_index, array_elem_index, } => { sink.push(0xfb); sink.push(0x13); array_type_index.encode(sink); array_elem_index.encode(sink); } Instruction::RefTestNonNull(heap_type) => { sink.push(0xfb); sink.push(0x14); heap_type.encode(sink); } Instruction::RefTestNullable(heap_type) => { sink.push(0xfb); sink.push(0x15); heap_type.encode(sink); } Instruction::RefCastNonNull(heap_type) => { sink.push(0xfb); sink.push(0x16); heap_type.encode(sink); } Instruction::RefCastNullable(heap_type) => { sink.push(0xfb); sink.push(0x17); heap_type.encode(sink); } Instruction::BrOnCast { relative_depth, from_ref_type, to_ref_type, } => { sink.push(0xfb); sink.push(0x18); let cast_flags = (from_ref_type.nullable as u8) | ((to_ref_type.nullable as u8) << 1); sink.push(cast_flags); relative_depth.encode(sink); from_ref_type.heap_type.encode(sink); to_ref_type.heap_type.encode(sink); } Instruction::BrOnCastFail { relative_depth, from_ref_type, to_ref_type, } => { sink.push(0xfb); sink.push(0x19); let cast_flags = (from_ref_type.nullable as u8) | ((to_ref_type.nullable as u8) << 1); sink.push(cast_flags); relative_depth.encode(sink); from_ref_type.heap_type.encode(sink); to_ref_type.heap_type.encode(sink); } Instruction::AnyConvertExtern => { sink.push(0xfb); sink.push(0x1a); } Instruction::ExternConvertAny => { sink.push(0xfb); sink.push(0x1b); } Instruction::RefI31 => { sink.push(0xfb); sink.push(0x1c); } Instruction::I31GetS => { sink.push(0xfb); sink.push(0x1d); } Instruction::I31GetU => { sink.push(0xfb); sink.push(0x1e); } // Bulk memory instructions. Instruction::TableInit { elem_index, table } => { sink.push(0xfc); sink.push(0x0c); elem_index.encode(sink); table.encode(sink); } Instruction::ElemDrop(segment) => { sink.push(0xfc); sink.push(0x0d); segment.encode(sink); } Instruction::TableCopy { src_table, dst_table, } => { sink.push(0xfc); sink.push(0x0e); dst_table.encode(sink); src_table.encode(sink); } Instruction::TableGrow(table) => { sink.push(0xfc); sink.push(0x0f); table.encode(sink); } Instruction::TableSize(table) => { sink.push(0xfc); sink.push(0x10); table.encode(sink); } Instruction::TableFill(table) => { sink.push(0xfc); sink.push(0x11); table.encode(sink); } // SIMD instructions. Instruction::V128Load(memarg) => { sink.push(0xFD); 0x00u32.encode(sink); memarg.encode(sink); } Instruction::V128Load8x8S(memarg) => { sink.push(0xFD); 0x01u32.encode(sink); memarg.encode(sink); } Instruction::V128Load8x8U(memarg) => { sink.push(0xFD); 0x02u32.encode(sink); memarg.encode(sink); } Instruction::V128Load16x4S(memarg) => { sink.push(0xFD); 0x03u32.encode(sink); memarg.encode(sink); } Instruction::V128Load16x4U(memarg) => { sink.push(0xFD); 0x04u32.encode(sink); memarg.encode(sink); } Instruction::V128Load32x2S(memarg) => { sink.push(0xFD); 0x05u32.encode(sink); memarg.encode(sink); } Instruction::V128Load32x2U(memarg) => { sink.push(0xFD); 0x06u32.encode(sink); memarg.encode(sink); } Instruction::V128Load8Splat(memarg) => { sink.push(0xFD); 0x07u32.encode(sink); memarg.encode(sink); } Instruction::V128Load16Splat(memarg) => { sink.push(0xFD); 0x08u32.encode(sink); memarg.encode(sink); } Instruction::V128Load32Splat(memarg) => { sink.push(0xFD); 0x09u32.encode(sink); memarg.encode(sink); } Instruction::V128Load64Splat(memarg) => { sink.push(0xFD); 0x0Au32.encode(sink); memarg.encode(sink); } Instruction::V128Store(memarg) => { sink.push(0xFD); 0x0Bu32.encode(sink); memarg.encode(sink); } Instruction::V128Const(x) => { sink.push(0xFD); 0x0Cu32.encode(sink); sink.extend(x.to_le_bytes().iter().copied()); } Instruction::I8x16Shuffle(lanes) => { sink.push(0xFD); 0x0Du32.encode(sink); assert!(lanes.iter().all(|l: &u8| *l < 32)); sink.extend(lanes.iter().copied()); } Instruction::I8x16Swizzle => { sink.push(0xFD); 0x0Eu32.encode(sink); } Instruction::I8x16Splat => { sink.push(0xFD); 0x0Fu32.encode(sink); } Instruction::I16x8Splat => { sink.push(0xFD); 0x10u32.encode(sink); } Instruction::I32x4Splat => { sink.push(0xFD); 0x11u32.encode(sink); } Instruction::I64x2Splat => { sink.push(0xFD); 0x12u32.encode(sink); } Instruction::F32x4Splat => { sink.push(0xFD); 0x13u32.encode(sink); } Instruction::F64x2Splat => { sink.push(0xFD); 0x14u32.encode(sink); } Instruction::I8x16ExtractLaneS(lane) => { sink.push(0xFD); 0x15u32.encode(sink); assert!(lane < 16); sink.push(lane); } Instruction::I8x16ExtractLaneU(lane) => { sink.push(0xFD); 0x16u32.encode(sink); assert!(lane < 16); sink.push(lane); } Instruction::I8x16ReplaceLane(lane) => { sink.push(0xFD); 0x17u32.encode(sink); assert!(lane < 16); sink.push(lane); } Instruction::I16x8ExtractLaneS(lane) => { sink.push(0xFD); 0x18u32.encode(sink); assert!(lane < 8); sink.push(lane); } Instruction::I16x8ExtractLaneU(lane) => { sink.push(0xFD); 0x19u32.encode(sink); assert!(lane < 8); sink.push(lane); } Instruction::I16x8ReplaceLane(lane) => { sink.push(0xFD); 0x1Au32.encode(sink); assert!(lane < 8); sink.push(lane); } Instruction::I32x4ExtractLane(lane) => { sink.push(0xFD); 0x1Bu32.encode(sink); assert!(lane < 4); sink.push(lane); } Instruction::I32x4ReplaceLane(lane) => { sink.push(0xFD); 0x1Cu32.encode(sink); assert!(lane < 4); sink.push(lane); } Instruction::I64x2ExtractLane(lane) => { sink.push(0xFD); 0x1Du32.encode(sink); assert!(lane < 2); sink.push(lane); } Instruction::I64x2ReplaceLane(lane) => { sink.push(0xFD); 0x1Eu32.encode(sink); assert!(lane < 2); sink.push(lane); } Instruction::F32x4ExtractLane(lane) => { sink.push(0xFD); 0x1Fu32.encode(sink); assert!(lane < 4); sink.push(lane); } Instruction::F32x4ReplaceLane(lane) => { sink.push(0xFD); 0x20u32.encode(sink); assert!(lane < 4); sink.push(lane); } Instruction::F64x2ExtractLane(lane) => { sink.push(0xFD); 0x21u32.encode(sink); assert!(lane < 2); sink.push(lane); } Instruction::F64x2ReplaceLane(lane) => { sink.push(0xFD); 0x22u32.encode(sink); assert!(lane < 2); sink.push(lane); } Instruction::I8x16Eq => { sink.push(0xFD); 0x23u32.encode(sink); } Instruction::I8x16Ne => { sink.push(0xFD); 0x24u32.encode(sink); } Instruction::I8x16LtS => { sink.push(0xFD); 0x25u32.encode(sink); } Instruction::I8x16LtU => { sink.push(0xFD); 0x26u32.encode(sink); } Instruction::I8x16GtS => { sink.push(0xFD); 0x27u32.encode(sink); } Instruction::I8x16GtU => { sink.push(0xFD); 0x28u32.encode(sink); } Instruction::I8x16LeS => { sink.push(0xFD); 0x29u32.encode(sink); } Instruction::I8x16LeU => { sink.push(0xFD); 0x2Au32.encode(sink); } Instruction::I8x16GeS => { sink.push(0xFD); 0x2Bu32.encode(sink); } Instruction::I8x16GeU => { sink.push(0xFD); 0x2Cu32.encode(sink); } Instruction::I16x8Eq => { sink.push(0xFD); 0x2Du32.encode(sink); } Instruction::I16x8Ne => { sink.push(0xFD); 0x2Eu32.encode(sink); } Instruction::I16x8LtS => { sink.push(0xFD); 0x2Fu32.encode(sink); } Instruction::I16x8LtU => { sink.push(0xFD); 0x30u32.encode(sink); } Instruction::I16x8GtS => { sink.push(0xFD); 0x31u32.encode(sink); } Instruction::I16x8GtU => { sink.push(0xFD); 0x32u32.encode(sink); } Instruction::I16x8LeS => { sink.push(0xFD); 0x33u32.encode(sink); } Instruction::I16x8LeU => { sink.push(0xFD); 0x34u32.encode(sink); } Instruction::I16x8GeS => { sink.push(0xFD); 0x35u32.encode(sink); } Instruction::I16x8GeU => { sink.push(0xFD); 0x36u32.encode(sink); } Instruction::I32x4Eq => { sink.push(0xFD); 0x37u32.encode(sink); } Instruction::I32x4Ne => { sink.push(0xFD); 0x38u32.encode(sink); } Instruction::I32x4LtS => { sink.push(0xFD); 0x39u32.encode(sink); } Instruction::I32x4LtU => { sink.push(0xFD); 0x3Au32.encode(sink); } Instruction::I32x4GtS => { sink.push(0xFD); 0x3Bu32.encode(sink); } Instruction::I32x4GtU => { sink.push(0xFD); 0x3Cu32.encode(sink); } Instruction::I32x4LeS => { sink.push(0xFD); 0x3Du32.encode(sink); } Instruction::I32x4LeU => { sink.push(0xFD); 0x3Eu32.encode(sink); } Instruction::I32x4GeS => { sink.push(0xFD); 0x3Fu32.encode(sink); } Instruction::I32x4GeU => { sink.push(0xFD); 0x40u32.encode(sink); } Instruction::F32x4Eq => { sink.push(0xFD); 0x41u32.encode(sink); } Instruction::F32x4Ne => { sink.push(0xFD); 0x42u32.encode(sink); } Instruction::F32x4Lt => { sink.push(0xFD); 0x43u32.encode(sink); } Instruction::F32x4Gt => { sink.push(0xFD); 0x44u32.encode(sink); } Instruction::F32x4Le => { sink.push(0xFD); 0x45u32.encode(sink); } Instruction::F32x4Ge => { sink.push(0xFD); 0x46u32.encode(sink); } Instruction::F64x2Eq => { sink.push(0xFD); 0x47u32.encode(sink); } Instruction::F64x2Ne => { sink.push(0xFD); 0x48u32.encode(sink); } Instruction::F64x2Lt => { sink.push(0xFD); 0x49u32.encode(sink); } Instruction::F64x2Gt => { sink.push(0xFD); 0x4Au32.encode(sink); } Instruction::F64x2Le => { sink.push(0xFD); 0x4Bu32.encode(sink); } Instruction::F64x2Ge => { sink.push(0xFD); 0x4Cu32.encode(sink); } Instruction::V128Not => { sink.push(0xFD); 0x4Du32.encode(sink); } Instruction::V128And => { sink.push(0xFD); 0x4Eu32.encode(sink); } Instruction::V128AndNot => { sink.push(0xFD); 0x4Fu32.encode(sink); } Instruction::V128Or => { sink.push(0xFD); 0x50u32.encode(sink); } Instruction::V128Xor => { sink.push(0xFD); 0x51u32.encode(sink); } Instruction::V128Bitselect => { sink.push(0xFD); 0x52u32.encode(sink); } Instruction::V128AnyTrue => { sink.push(0xFD); 0x53u32.encode(sink); } Instruction::I8x16Abs => { sink.push(0xFD); 0x60u32.encode(sink); } Instruction::I8x16Neg => { sink.push(0xFD); 0x61u32.encode(sink); } Instruction::I8x16Popcnt => { sink.push(0xFD); 0x62u32.encode(sink); } Instruction::I8x16AllTrue => { sink.push(0xFD); 0x63u32.encode(sink); } Instruction::I8x16Bitmask => { sink.push(0xFD); 0x64u32.encode(sink); } Instruction::I8x16NarrowI16x8S => { sink.push(0xFD); 0x65u32.encode(sink); } Instruction::I8x16NarrowI16x8U => { sink.push(0xFD); 0x66u32.encode(sink); } Instruction::I8x16Shl => { sink.push(0xFD); 0x6bu32.encode(sink); } Instruction::I8x16ShrS => { sink.push(0xFD); 0x6cu32.encode(sink); } Instruction::I8x16ShrU => { sink.push(0xFD); 0x6du32.encode(sink); } Instruction::I8x16Add => { sink.push(0xFD); 0x6eu32.encode(sink); } Instruction::I8x16AddSatS => { sink.push(0xFD); 0x6fu32.encode(sink); } Instruction::I8x16AddSatU => { sink.push(0xFD); 0x70u32.encode(sink); } Instruction::I8x16Sub => { sink.push(0xFD); 0x71u32.encode(sink); } Instruction::I8x16SubSatS => { sink.push(0xFD); 0x72u32.encode(sink); } Instruction::I8x16SubSatU => { sink.push(0xFD); 0x73u32.encode(sink); } Instruction::I8x16MinS => { sink.push(0xFD); 0x76u32.encode(sink); } Instruction::I8x16MinU => { sink.push(0xFD); 0x77u32.encode(sink); } Instruction::I8x16MaxS => { sink.push(0xFD); 0x78u32.encode(sink); } Instruction::I8x16MaxU => { sink.push(0xFD); 0x79u32.encode(sink); } Instruction::I8x16AvgrU => { sink.push(0xFD); 0x7Bu32.encode(sink); } Instruction::I16x8ExtAddPairwiseI8x16S => { sink.push(0xFD); 0x7Cu32.encode(sink); } Instruction::I16x8ExtAddPairwiseI8x16U => { sink.push(0xFD); 0x7Du32.encode(sink); } Instruction::I32x4ExtAddPairwiseI16x8S => { sink.push(0xFD); 0x7Eu32.encode(sink); } Instruction::I32x4ExtAddPairwiseI16x8U => { sink.push(0xFD); 0x7Fu32.encode(sink); } Instruction::I16x8Abs => { sink.push(0xFD); 0x80u32.encode(sink); } Instruction::I16x8Neg => { sink.push(0xFD); 0x81u32.encode(sink); } Instruction::I16x8Q15MulrSatS => { sink.push(0xFD); 0x82u32.encode(sink); } Instruction::I16x8AllTrue => { sink.push(0xFD); 0x83u32.encode(sink); } Instruction::I16x8Bitmask => { sink.push(0xFD); 0x84u32.encode(sink); } Instruction::I16x8NarrowI32x4S => { sink.push(0xFD); 0x85u32.encode(sink); } Instruction::I16x8NarrowI32x4U => { sink.push(0xFD); 0x86u32.encode(sink); } Instruction::I16x8ExtendLowI8x16S => { sink.push(0xFD); 0x87u32.encode(sink); } Instruction::I16x8ExtendHighI8x16S => { sink.push(0xFD); 0x88u32.encode(sink); } Instruction::I16x8ExtendLowI8x16U => { sink.push(0xFD); 0x89u32.encode(sink); } Instruction::I16x8ExtendHighI8x16U => { sink.push(0xFD); 0x8Au32.encode(sink); } Instruction::I16x8Shl => { sink.push(0xFD); 0x8Bu32.encode(sink); } Instruction::I16x8ShrS => { sink.push(0xFD); 0x8Cu32.encode(sink); } Instruction::I16x8ShrU => { sink.push(0xFD); 0x8Du32.encode(sink); } Instruction::I16x8Add => { sink.push(0xFD); 0x8Eu32.encode(sink); } Instruction::I16x8AddSatS => { sink.push(0xFD); 0x8Fu32.encode(sink); } Instruction::I16x8AddSatU => { sink.push(0xFD); 0x90u32.encode(sink); } Instruction::I16x8Sub => { sink.push(0xFD); 0x91u32.encode(sink); } Instruction::I16x8SubSatS => { sink.push(0xFD); 0x92u32.encode(sink); } Instruction::I16x8SubSatU => { sink.push(0xFD); 0x93u32.encode(sink); } Instruction::I16x8Mul => { sink.push(0xFD); 0x95u32.encode(sink); } Instruction::I16x8MinS => { sink.push(0xFD); 0x96u32.encode(sink); } Instruction::I16x8MinU => { sink.push(0xFD); 0x97u32.encode(sink); } Instruction::I16x8MaxS => { sink.push(0xFD); 0x98u32.encode(sink); } Instruction::I16x8MaxU => { sink.push(0xFD); 0x99u32.encode(sink); } Instruction::I16x8AvgrU => { sink.push(0xFD); 0x9Bu32.encode(sink); } Instruction::I16x8ExtMulLowI8x16S => { sink.push(0xFD); 0x9Cu32.encode(sink); } Instruction::I16x8ExtMulHighI8x16S => { sink.push(0xFD); 0x9Du32.encode(sink); } Instruction::I16x8ExtMulLowI8x16U => { sink.push(0xFD); 0x9Eu32.encode(sink); } Instruction::I16x8ExtMulHighI8x16U => { sink.push(0xFD); 0x9Fu32.encode(sink); } Instruction::I32x4Abs => { sink.push(0xFD); 0xA0u32.encode(sink); } Instruction::I32x4Neg => { sink.push(0xFD); 0xA1u32.encode(sink); } Instruction::I32x4AllTrue => { sink.push(0xFD); 0xA3u32.encode(sink); } Instruction::I32x4Bitmask => { sink.push(0xFD); 0xA4u32.encode(sink); } Instruction::I32x4ExtendLowI16x8S => { sink.push(0xFD); 0xA7u32.encode(sink); } Instruction::I32x4ExtendHighI16x8S => { sink.push(0xFD); 0xA8u32.encode(sink); } Instruction::I32x4ExtendLowI16x8U => { sink.push(0xFD); 0xA9u32.encode(sink); } Instruction::I32x4ExtendHighI16x8U => { sink.push(0xFD); 0xAAu32.encode(sink); } Instruction::I32x4Shl => { sink.push(0xFD); 0xABu32.encode(sink); } Instruction::I32x4ShrS => { sink.push(0xFD); 0xACu32.encode(sink); } Instruction::I32x4ShrU => { sink.push(0xFD); 0xADu32.encode(sink); } Instruction::I32x4Add => { sink.push(0xFD); 0xAEu32.encode(sink); } Instruction::I32x4Sub => { sink.push(0xFD); 0xB1u32.encode(sink); } Instruction::I32x4Mul => { sink.push(0xFD); 0xB5u32.encode(sink); } Instruction::I32x4MinS => { sink.push(0xFD); 0xB6u32.encode(sink); } Instruction::I32x4MinU => { sink.push(0xFD); 0xB7u32.encode(sink); } Instruction::I32x4MaxS => { sink.push(0xFD); 0xB8u32.encode(sink); } Instruction::I32x4MaxU => { sink.push(0xFD); 0xB9u32.encode(sink); } Instruction::I32x4DotI16x8S => { sink.push(0xFD); 0xBAu32.encode(sink); } Instruction::I32x4ExtMulLowI16x8S => { sink.push(0xFD); 0xBCu32.encode(sink); } Instruction::I32x4ExtMulHighI16x8S => { sink.push(0xFD); 0xBDu32.encode(sink); } Instruction::I32x4ExtMulLowI16x8U => { sink.push(0xFD); 0xBEu32.encode(sink); } Instruction::I32x4ExtMulHighI16x8U => { sink.push(0xFD); 0xBFu32.encode(sink); } Instruction::I64x2Abs => { sink.push(0xFD); 0xC0u32.encode(sink); } Instruction::I64x2Neg => { sink.push(0xFD); 0xC1u32.encode(sink); } Instruction::I64x2AllTrue => { sink.push(0xFD); 0xC3u32.encode(sink); } Instruction::I64x2Bitmask => { sink.push(0xFD); 0xC4u32.encode(sink); } Instruction::I64x2ExtendLowI32x4S => { sink.push(0xFD); 0xC7u32.encode(sink); } Instruction::I64x2ExtendHighI32x4S => { sink.push(0xFD); 0xC8u32.encode(sink); } Instruction::I64x2ExtendLowI32x4U => { sink.push(0xFD); 0xC9u32.encode(sink); } Instruction::I64x2ExtendHighI32x4U => { sink.push(0xFD); 0xCAu32.encode(sink); } Instruction::I64x2Shl => { sink.push(0xFD); 0xCBu32.encode(sink); } Instruction::I64x2ShrS => { sink.push(0xFD); 0xCCu32.encode(sink); } Instruction::I64x2ShrU => { sink.push(0xFD); 0xCDu32.encode(sink); } Instruction::I64x2Add => { sink.push(0xFD); 0xCEu32.encode(sink); } Instruction::I64x2Sub => { sink.push(0xFD); 0xD1u32.encode(sink); } Instruction::I64x2Mul => { sink.push(0xFD); 0xD5u32.encode(sink); } Instruction::I64x2ExtMulLowI32x4S => { sink.push(0xFD); 0xDCu32.encode(sink); } Instruction::I64x2ExtMulHighI32x4S => { sink.push(0xFD); 0xDDu32.encode(sink); } Instruction::I64x2ExtMulLowI32x4U => { sink.push(0xFD); 0xDEu32.encode(sink); } Instruction::I64x2ExtMulHighI32x4U => { sink.push(0xFD); 0xDFu32.encode(sink); } Instruction::F32x4Ceil => { sink.push(0xFD); 0x67u32.encode(sink); } Instruction::F32x4Floor => { sink.push(0xFD); 0x68u32.encode(sink); } Instruction::F32x4Trunc => { sink.push(0xFD); 0x69u32.encode(sink); } Instruction::F32x4Nearest => { sink.push(0xFD); 0x6Au32.encode(sink); } Instruction::F32x4Abs => { sink.push(0xFD); 0xE0u32.encode(sink); } Instruction::F32x4Neg => { sink.push(0xFD); 0xE1u32.encode(sink); } Instruction::F32x4Sqrt => { sink.push(0xFD); 0xE3u32.encode(sink); } Instruction::F32x4Add => { sink.push(0xFD); 0xE4u32.encode(sink); } Instruction::F32x4Sub => { sink.push(0xFD); 0xE5u32.encode(sink); } Instruction::F32x4Mul => { sink.push(0xFD); 0xE6u32.encode(sink); } Instruction::F32x4Div => { sink.push(0xFD); 0xE7u32.encode(sink); } Instruction::F32x4Min => { sink.push(0xFD); 0xE8u32.encode(sink); } Instruction::F32x4Max => { sink.push(0xFD); 0xE9u32.encode(sink); } Instruction::F32x4PMin => { sink.push(0xFD); 0xEAu32.encode(sink); } Instruction::F32x4PMax => { sink.push(0xFD); 0xEBu32.encode(sink); } Instruction::F64x2Ceil => { sink.push(0xFD); 0x74u32.encode(sink); } Instruction::F64x2Floor => { sink.push(0xFD); 0x75u32.encode(sink); } Instruction::F64x2Trunc => { sink.push(0xFD); 0x7Au32.encode(sink); } Instruction::F64x2Nearest => { sink.push(0xFD); 0x94u32.encode(sink); } Instruction::F64x2Abs => { sink.push(0xFD); 0xECu32.encode(sink); } Instruction::F64x2Neg => { sink.push(0xFD); 0xEDu32.encode(sink); } Instruction::F64x2Sqrt => { sink.push(0xFD); 0xEFu32.encode(sink); } Instruction::F64x2Add => { sink.push(0xFD); 0xF0u32.encode(sink); } Instruction::F64x2Sub => { sink.push(0xFD); 0xF1u32.encode(sink); } Instruction::F64x2Mul => { sink.push(0xFD); 0xF2u32.encode(sink); } Instruction::F64x2Div => { sink.push(0xFD); 0xF3u32.encode(sink); } Instruction::F64x2Min => { sink.push(0xFD); 0xF4u32.encode(sink); } Instruction::F64x2Max => { sink.push(0xFD); 0xF5u32.encode(sink); } Instruction::F64x2PMin => { sink.push(0xFD); 0xF6u32.encode(sink); } Instruction::F64x2PMax => { sink.push(0xFD); 0xF7u32.encode(sink); } Instruction::I32x4TruncSatF32x4S => { sink.push(0xFD); 0xF8u32.encode(sink); } Instruction::I32x4TruncSatF32x4U => { sink.push(0xFD); 0xF9u32.encode(sink); } Instruction::F32x4ConvertI32x4S => { sink.push(0xFD); 0xFAu32.encode(sink); } Instruction::F32x4ConvertI32x4U => { sink.push(0xFD); 0xFBu32.encode(sink); } Instruction::I32x4TruncSatF64x2SZero => { sink.push(0xFD); 0xFCu32.encode(sink); } Instruction::I32x4TruncSatF64x2UZero => { sink.push(0xFD); 0xFDu32.encode(sink); } Instruction::F64x2ConvertLowI32x4S => { sink.push(0xFD); 0xFEu32.encode(sink); } Instruction::F64x2ConvertLowI32x4U => { sink.push(0xFD); 0xFFu32.encode(sink); } Instruction::F32x4DemoteF64x2Zero => { sink.push(0xFD); 0x5Eu32.encode(sink); } Instruction::F64x2PromoteLowF32x4 => { sink.push(0xFD); 0x5Fu32.encode(sink); } Instruction::V128Load32Zero(memarg) => { sink.push(0xFD); 0x5Cu32.encode(sink); memarg.encode(sink); } Instruction::V128Load64Zero(memarg) => { sink.push(0xFD); 0x5Du32.encode(sink); memarg.encode(sink); } Instruction::V128Load8Lane { memarg, lane } => { sink.push(0xFD); 0x54u32.encode(sink); memarg.encode(sink); assert!(lane < 16); sink.push(lane); } Instruction::V128Load16Lane { memarg, lane } => { sink.push(0xFD); 0x55u32.encode(sink); memarg.encode(sink); assert!(lane < 8); sink.push(lane); } Instruction::V128Load32Lane { memarg, lane } => { sink.push(0xFD); 0x56u32.encode(sink); memarg.encode(sink); assert!(lane < 4); sink.push(lane); } Instruction::V128Load64Lane { memarg, lane } => { sink.push(0xFD); 0x57u32.encode(sink); memarg.encode(sink); assert!(lane < 2); sink.push(lane); } Instruction::V128Store8Lane { memarg, lane } => { sink.push(0xFD); 0x58u32.encode(sink); memarg.encode(sink); assert!(lane < 16); sink.push(lane); } Instruction::V128Store16Lane { memarg, lane } => { sink.push(0xFD); 0x59u32.encode(sink); memarg.encode(sink); assert!(lane < 8); sink.push(lane); } Instruction::V128Store32Lane { memarg, lane } => { sink.push(0xFD); 0x5Au32.encode(sink); memarg.encode(sink); assert!(lane < 4); sink.push(lane); } Instruction::V128Store64Lane { memarg, lane } => { sink.push(0xFD); 0x5Bu32.encode(sink); memarg.encode(sink); assert!(lane < 2); sink.push(lane); } Instruction::I64x2Eq => { sink.push(0xFD); 0xD6u32.encode(sink); } Instruction::I64x2Ne => { sink.push(0xFD); 0xD7u32.encode(sink); } Instruction::I64x2LtS => { sink.push(0xFD); 0xD8u32.encode(sink); } Instruction::I64x2GtS => { sink.push(0xFD); 0xD9u32.encode(sink); } Instruction::I64x2LeS => { sink.push(0xFD); 0xDAu32.encode(sink); } Instruction::I64x2GeS => { sink.push(0xFD); 0xDBu32.encode(sink); } Instruction::I8x16RelaxedSwizzle => { sink.push(0xFD); 0x100u32.encode(sink); } Instruction::I32x4RelaxedTruncF32x4S => { sink.push(0xFD); 0x101u32.encode(sink); } Instruction::I32x4RelaxedTruncF32x4U => { sink.push(0xFD); 0x102u32.encode(sink); } Instruction::I32x4RelaxedTruncF64x2SZero => { sink.push(0xFD); 0x103u32.encode(sink); } Instruction::I32x4RelaxedTruncF64x2UZero => { sink.push(0xFD); 0x104u32.encode(sink); } Instruction::F32x4RelaxedMadd => { sink.push(0xFD); 0x105u32.encode(sink); } Instruction::F32x4RelaxedNmadd => { sink.push(0xFD); 0x106u32.encode(sink); } Instruction::F64x2RelaxedMadd => { sink.push(0xFD); 0x107u32.encode(sink); } Instruction::F64x2RelaxedNmadd => { sink.push(0xFD); 0x108u32.encode(sink); } Instruction::I8x16RelaxedLaneselect => { sink.push(0xFD); 0x109u32.encode(sink); } Instruction::I16x8RelaxedLaneselect => { sink.push(0xFD); 0x10Au32.encode(sink); } Instruction::I32x4RelaxedLaneselect => { sink.push(0xFD); 0x10Bu32.encode(sink); } Instruction::I64x2RelaxedLaneselect => { sink.push(0xFD); 0x10Cu32.encode(sink); } Instruction::F32x4RelaxedMin => { sink.push(0xFD); 0x10Du32.encode(sink); } Instruction::F32x4RelaxedMax => { sink.push(0xFD); 0x10Eu32.encode(sink); } Instruction::F64x2RelaxedMin => { sink.push(0xFD); 0x10Fu32.encode(sink); } Instruction::F64x2RelaxedMax => { sink.push(0xFD); 0x110u32.encode(sink); } Instruction::I16x8RelaxedQ15mulrS => { sink.push(0xFD); 0x111u32.encode(sink); } Instruction::I16x8RelaxedDotI8x16I7x16S => { sink.push(0xFD); 0x112u32.encode(sink); } Instruction::I32x4RelaxedDotI8x16I7x16AddS => { sink.push(0xFD); 0x113u32.encode(sink); } // Atomic instructions from the thread proposal Instruction::MemoryAtomicNotify(memarg) => { sink.push(0xFE); sink.push(0x00); memarg.encode(sink); } Instruction::MemoryAtomicWait32(memarg) => { sink.push(0xFE); sink.push(0x01); memarg.encode(sink); } Instruction::MemoryAtomicWait64(memarg) => { sink.push(0xFE); sink.push(0x02); memarg.encode(sink); } Instruction::AtomicFence => { sink.push(0xFE); sink.push(0x03); sink.push(0x00); } Instruction::I32AtomicLoad(memarg) => { sink.push(0xFE); sink.push(0x10); memarg.encode(sink); } Instruction::I64AtomicLoad(memarg) => { sink.push(0xFE); sink.push(0x11); memarg.encode(sink); } Instruction::I32AtomicLoad8U(memarg) => { sink.push(0xFE); sink.push(0x12); memarg.encode(sink); } Instruction::I32AtomicLoad16U(memarg) => { sink.push(0xFE); sink.push(0x13); memarg.encode(sink); } Instruction::I64AtomicLoad8U(memarg) => { sink.push(0xFE); sink.push(0x14); memarg.encode(sink); } Instruction::I64AtomicLoad16U(memarg) => { sink.push(0xFE); sink.push(0x15); memarg.encode(sink); } Instruction::I64AtomicLoad32U(memarg) => { sink.push(0xFE); sink.push(0x16); memarg.encode(sink); } Instruction::I32AtomicStore(memarg) => { sink.push(0xFE); sink.push(0x17); memarg.encode(sink); } Instruction::I64AtomicStore(memarg) => { sink.push(0xFE); sink.push(0x18); memarg.encode(sink); } Instruction::I32AtomicStore8(memarg) => { sink.push(0xFE); sink.push(0x19); memarg.encode(sink); } Instruction::I32AtomicStore16(memarg) => { sink.push(0xFE); sink.push(0x1A); memarg.encode(sink); } Instruction::I64AtomicStore8(memarg) => { sink.push(0xFE); sink.push(0x1B); memarg.encode(sink); } Instruction::I64AtomicStore16(memarg) => { sink.push(0xFE); sink.push(0x1C); memarg.encode(sink); } Instruction::I64AtomicStore32(memarg) => { sink.push(0xFE); sink.push(0x1D); memarg.encode(sink); } Instruction::I32AtomicRmwAdd(memarg) => { sink.push(0xFE); sink.push(0x1E); memarg.encode(sink); } Instruction::I64AtomicRmwAdd(memarg) => { sink.push(0xFE); sink.push(0x1F); memarg.encode(sink); } Instruction::I32AtomicRmw8AddU(memarg) => { sink.push(0xFE); sink.push(0x20); memarg.encode(sink); } Instruction::I32AtomicRmw16AddU(memarg) => { sink.push(0xFE); sink.push(0x21); memarg.encode(sink); } Instruction::I64AtomicRmw8AddU(memarg) => { sink.push(0xFE); sink.push(0x22); memarg.encode(sink); } Instruction::I64AtomicRmw16AddU(memarg) => { sink.push(0xFE); sink.push(0x23); memarg.encode(sink); } Instruction::I64AtomicRmw32AddU(memarg) => { sink.push(0xFE); sink.push(0x24); memarg.encode(sink); } Instruction::I32AtomicRmwSub(memarg) => { sink.push(0xFE); sink.push(0x25); memarg.encode(sink); } Instruction::I64AtomicRmwSub(memarg) => { sink.push(0xFE); sink.push(0x26); memarg.encode(sink); } Instruction::I32AtomicRmw8SubU(memarg) => { sink.push(0xFE); sink.push(0x27); memarg.encode(sink); } Instruction::I32AtomicRmw16SubU(memarg) => { sink.push(0xFE); sink.push(0x28); memarg.encode(sink); } Instruction::I64AtomicRmw8SubU(memarg) => { sink.push(0xFE); sink.push(0x29); memarg.encode(sink); } Instruction::I64AtomicRmw16SubU(memarg) => { sink.push(0xFE); sink.push(0x2A); memarg.encode(sink); } Instruction::I64AtomicRmw32SubU(memarg) => { sink.push(0xFE); sink.push(0x2B); memarg.encode(sink); } Instruction::I32AtomicRmwAnd(memarg) => { sink.push(0xFE); sink.push(0x2C); memarg.encode(sink); } Instruction::I64AtomicRmwAnd(memarg) => { sink.push(0xFE); sink.push(0x2D); memarg.encode(sink); } Instruction::I32AtomicRmw8AndU(memarg) => { sink.push(0xFE); sink.push(0x2E); memarg.encode(sink); } Instruction::I32AtomicRmw16AndU(memarg) => { sink.push(0xFE); sink.push(0x2F); memarg.encode(sink); } Instruction::I64AtomicRmw8AndU(memarg) => { sink.push(0xFE); sink.push(0x30); memarg.encode(sink); } Instruction::I64AtomicRmw16AndU(memarg) => { sink.push(0xFE); sink.push(0x31); memarg.encode(sink); } Instruction::I64AtomicRmw32AndU(memarg) => { sink.push(0xFE); sink.push(0x32); memarg.encode(sink); } Instruction::I32AtomicRmwOr(memarg) => { sink.push(0xFE); sink.push(0x33); memarg.encode(sink); } Instruction::I64AtomicRmwOr(memarg) => { sink.push(0xFE); sink.push(0x34); memarg.encode(sink); } Instruction::I32AtomicRmw8OrU(memarg) => { sink.push(0xFE); sink.push(0x35); memarg.encode(sink); } Instruction::I32AtomicRmw16OrU(memarg) => { sink.push(0xFE); sink.push(0x36); memarg.encode(sink); } Instruction::I64AtomicRmw8OrU(memarg) => { sink.push(0xFE); sink.push(0x37); memarg.encode(sink); } Instruction::I64AtomicRmw16OrU(memarg) => { sink.push(0xFE); sink.push(0x38); memarg.encode(sink); } Instruction::I64AtomicRmw32OrU(memarg) => { sink.push(0xFE); sink.push(0x39); memarg.encode(sink); } Instruction::I32AtomicRmwXor(memarg) => { sink.push(0xFE); sink.push(0x3A); memarg.encode(sink); } Instruction::I64AtomicRmwXor(memarg) => { sink.push(0xFE); sink.push(0x3B); memarg.encode(sink); } Instruction::I32AtomicRmw8XorU(memarg) => { sink.push(0xFE); sink.push(0x3C); memarg.encode(sink); } Instruction::I32AtomicRmw16XorU(memarg) => { sink.push(0xFE); sink.push(0x3D); memarg.encode(sink); } Instruction::I64AtomicRmw8XorU(memarg) => { sink.push(0xFE); sink.push(0x3E); memarg.encode(sink); } Instruction::I64AtomicRmw16XorU(memarg) => { sink.push(0xFE); sink.push(0x3F); memarg.encode(sink); } Instruction::I64AtomicRmw32XorU(memarg) => { sink.push(0xFE); sink.push(0x40); memarg.encode(sink); } Instruction::I32AtomicRmwXchg(memarg) => { sink.push(0xFE); sink.push(0x41); memarg.encode(sink); } Instruction::I64AtomicRmwXchg(memarg) => { sink.push(0xFE); sink.push(0x42); memarg.encode(sink); } Instruction::I32AtomicRmw8XchgU(memarg) => { sink.push(0xFE); sink.push(0x43); memarg.encode(sink); } Instruction::I32AtomicRmw16XchgU(memarg) => { sink.push(0xFE); sink.push(0x44); memarg.encode(sink); } Instruction::I64AtomicRmw8XchgU(memarg) => { sink.push(0xFE); sink.push(0x45); memarg.encode(sink); } Instruction::I64AtomicRmw16XchgU(memarg) => { sink.push(0xFE); sink.push(0x46); memarg.encode(sink); } Instruction::I64AtomicRmw32XchgU(memarg) => { sink.push(0xFE); sink.push(0x47); memarg.encode(sink); } Instruction::I32AtomicRmwCmpxchg(memarg) => { sink.push(0xFE); sink.push(0x48); memarg.encode(sink); } Instruction::I64AtomicRmwCmpxchg(memarg) => { sink.push(0xFE); sink.push(0x49); memarg.encode(sink); } Instruction::I32AtomicRmw8CmpxchgU(memarg) => { sink.push(0xFE); sink.push(0x4A); memarg.encode(sink); } Instruction::I32AtomicRmw16CmpxchgU(memarg) => { sink.push(0xFE); sink.push(0x4B); memarg.encode(sink); } Instruction::I64AtomicRmw8CmpxchgU(memarg) => { sink.push(0xFE); sink.push(0x4C); memarg.encode(sink); } Instruction::I64AtomicRmw16CmpxchgU(memarg) => { sink.push(0xFE); sink.push(0x4D); memarg.encode(sink); } Instruction::I64AtomicRmw32CmpxchgU(memarg) => { sink.push(0xFE); sink.push(0x4E); memarg.encode(sink); } // Atomic instructions from the shared-everything-threads proposal Instruction::GlobalAtomicGet { ordering, global_index, } => { sink.push(0xFE); sink.push(0x4F); ordering.encode(sink); global_index.encode(sink); } Instruction::GlobalAtomicSet { ordering, global_index, } => { sink.push(0xFE); sink.push(0x50); ordering.encode(sink); global_index.encode(sink); } Instruction::GlobalAtomicRmwAdd { ordering, global_index, } => { sink.push(0xFE); sink.push(0x51); ordering.encode(sink); global_index.encode(sink); } Instruction::GlobalAtomicRmwSub { ordering, global_index, } => { sink.push(0xFE); sink.push(0x52); ordering.encode(sink); global_index.encode(sink); } Instruction::GlobalAtomicRmwAnd { ordering, global_index, } => { sink.push(0xFE); sink.push(0x53); ordering.encode(sink); global_index.encode(sink); } Instruction::GlobalAtomicRmwOr { ordering, global_index, } => { sink.push(0xFE); sink.push(0x54); ordering.encode(sink); global_index.encode(sink); } Instruction::GlobalAtomicRmwXor { ordering, global_index, } => { sink.push(0xFE); sink.push(0x55); ordering.encode(sink); global_index.encode(sink); } Instruction::GlobalAtomicRmwXchg { ordering, global_index, } => { sink.push(0xFE); sink.push(0x56); ordering.encode(sink); global_index.encode(sink); } Instruction::GlobalAtomicRmwCmpxchg { ordering, global_index, } => { sink.push(0xFE); sink.push(0x57); ordering.encode(sink); global_index.encode(sink); } Instruction::TableAtomicGet { ordering, table_index, } => { sink.push(0xFE); sink.push(0x58); ordering.encode(sink); table_index.encode(sink); } Instruction::TableAtomicSet { ordering, table_index, } => { sink.push(0xFE); sink.push(0x59); ordering.encode(sink); table_index.encode(sink); } Instruction::TableAtomicRmwXchg { ordering, table_index, } => { sink.push(0xFE); sink.push(0x5A); ordering.encode(sink); table_index.encode(sink); } Instruction::TableAtomicRmwCmpxchg { ordering, table_index, } => { sink.push(0xFE); sink.push(0x5B); ordering.encode(sink); table_index.encode(sink); } Instruction::StructAtomicGet { ordering, struct_type_index, field_index, } => { sink.push(0xFE); sink.push(0x5C); ordering.encode(sink); struct_type_index.encode(sink); field_index.encode(sink); } Instruction::StructAtomicGetS { ordering, struct_type_index, field_index, } => { sink.push(0xFE); sink.push(0x5D); ordering.encode(sink); struct_type_index.encode(sink); field_index.encode(sink); } Instruction::StructAtomicGetU { ordering, struct_type_index, field_index, } => { sink.push(0xFE); sink.push(0x5E); ordering.encode(sink); struct_type_index.encode(sink); field_index.encode(sink); } Instruction::StructAtomicSet { ordering, struct_type_index, field_index, } => { sink.push(0xFE); sink.push(0x5F); ordering.encode(sink); struct_type_index.encode(sink); field_index.encode(sink); } Instruction::StructAtomicRmwAdd { ordering, struct_type_index, field_index, } => { sink.push(0xFE); sink.push(0x60); ordering.encode(sink); struct_type_index.encode(sink); field_index.encode(sink); } Instruction::StructAtomicRmwSub { ordering, struct_type_index, field_index, } => { sink.push(0xFE); sink.push(0x61); ordering.encode(sink); struct_type_index.encode(sink); field_index.encode(sink); } Instruction::StructAtomicRmwAnd { ordering, struct_type_index, field_index, } => { sink.push(0xFE); sink.push(0x62); ordering.encode(sink); struct_type_index.encode(sink); field_index.encode(sink); } Instruction::StructAtomicRmwOr { ordering, struct_type_index, field_index, } => { sink.push(0xFE); sink.push(0x63); ordering.encode(sink); struct_type_index.encode(sink); field_index.encode(sink); } Instruction::StructAtomicRmwXor { ordering, struct_type_index, field_index, } => { sink.push(0xFE); sink.push(0x64); ordering.encode(sink); struct_type_index.encode(sink); field_index.encode(sink); } Instruction::StructAtomicRmwXchg { ordering, struct_type_index, field_index, } => { sink.push(0xFE); sink.push(0x65); ordering.encode(sink); struct_type_index.encode(sink); field_index.encode(sink); } Instruction::StructAtomicRmwCmpxchg { ordering, struct_type_index, field_index, } => { sink.push(0xFE); sink.push(0x66); ordering.encode(sink); struct_type_index.encode(sink); field_index.encode(sink); } Instruction::ArrayAtomicGet { ordering, array_type_index, } => { sink.push(0xFE); sink.push(0x67); ordering.encode(sink); array_type_index.encode(sink); } Instruction::ArrayAtomicGetS { ordering, array_type_index, } => { sink.push(0xFE); sink.push(0x68); ordering.encode(sink); array_type_index.encode(sink); } Instruction::ArrayAtomicGetU { ordering, array_type_index, } => { sink.push(0xFE); sink.push(0x69); ordering.encode(sink); array_type_index.encode(sink); } Instruction::ArrayAtomicSet { ordering, array_type_index, } => { sink.push(0xFE); sink.push(0x6A); ordering.encode(sink); array_type_index.encode(sink); } Instruction::ArrayAtomicRmwAdd { ordering, array_type_index, } => { sink.push(0xFE); sink.push(0x6B); ordering.encode(sink); array_type_index.encode(sink); } Instruction::ArrayAtomicRmwSub { ordering, array_type_index, } => { sink.push(0xFE); sink.push(0x6C); ordering.encode(sink); array_type_index.encode(sink); } Instruction::ArrayAtomicRmwAnd { ordering, array_type_index, } => { sink.push(0xFE); sink.push(0x6D); ordering.encode(sink); array_type_index.encode(sink); } Instruction::ArrayAtomicRmwOr { ordering, array_type_index, } => { sink.push(0xFE); sink.push(0x6E); ordering.encode(sink); array_type_index.encode(sink); } Instruction::ArrayAtomicRmwXor { ordering, array_type_index, } => { sink.push(0xFE); sink.push(0x6F); ordering.encode(sink); array_type_index.encode(sink); } Instruction::ArrayAtomicRmwXchg { ordering, array_type_index, } => { sink.push(0xFE); sink.push(0x70); ordering.encode(sink); array_type_index.encode(sink); } Instruction::ArrayAtomicRmwCmpxchg { ordering, array_type_index, } => { sink.push(0xFE); sink.push(0x71); ordering.encode(sink); array_type_index.encode(sink); } Instruction::RefI31Shared => { sink.push(0xFE); sink.push(0x72); } } } } #[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); } } } } /// A constant expression. /// /// Usable in contexts such as offsets or initializers. #[derive(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(), } } fn new_insn(insn: Instruction) -> Self { let mut bytes = vec![]; insn.encode(&mut bytes); Self { bytes } } fn with_insn(mut self, insn: Instruction) -> Self { insn.encode(&mut self.bytes); self } /// Create a constant expression containing a single `global.get` instruction. pub fn global_get(index: u32) -> Self { Self::new_insn(Instruction::GlobalGet(index)) } /// Create a constant expression containing a single `ref.null` instruction. pub fn ref_null(ty: HeapType) -> Self { Self::new_insn(Instruction::RefNull(ty)) } /// Create a constant expression containing a single `ref.func` instruction. pub fn ref_func(func: u32) -> Self { Self::new_insn(Instruction::RefFunc(func)) } /// Create a constant expression containing a single `i32.const` instruction. pub fn i32_const(value: i32) -> Self { Self::new_insn(Instruction::I32Const(value)) } /// Create a constant expression containing a single `i64.const` instruction. pub fn i64_const(value: i64) -> Self { Self::new_insn(Instruction::I64Const(value)) } /// Create a constant expression containing a single `f32.const` instruction. pub fn f32_const(value: f32) -> Self { Self::new_insn(Instruction::F32Const(value)) } /// Create a constant expression containing a single `f64.const` instruction. pub fn f64_const(value: f64) -> Self { Self::new_insn(Instruction::F64Const(value)) } /// Create a constant expression containing a single `v128.const` instruction. pub fn v128_const(value: i128) -> Self { Self::new_insn(Instruction::V128Const(value)) } /// Add a `global.get` instruction to this constant expression. pub fn with_global_get(self, index: u32) -> Self { self.with_insn(Instruction::GlobalGet(index)) } /// Add a `ref.null` instruction to this constant expression. pub fn with_ref_null(self, ty: HeapType) -> Self { self.with_insn(Instruction::RefNull(ty)) } /// Add a `ref.func` instruction to this constant expression. pub fn with_ref_func(self, func: u32) -> Self { self.with_insn(Instruction::RefFunc(func)) } /// Add an `i32.const` instruction to this constant expression. pub fn with_i32_const(self, value: i32) -> Self { self.with_insn(Instruction::I32Const(value)) } /// Add an `i64.const` instruction to this constant expression. pub fn with_i64_const(self, value: i64) -> Self { self.with_insn(Instruction::I64Const(value)) } /// Add a `f32.const` instruction to this constant expression. pub fn with_f32_const(self, value: f32) -> Self { self.with_insn(Instruction::F32Const(value)) } /// Add a `f64.const` instruction to this constant expression. pub fn with_f64_const(self, value: f64) -> Self { self.with_insn(Instruction::F64Const(value)) } /// Add a `v128.const` instruction to this constant expression. pub fn with_v128_const(self, value: i128) -> Self { self.with_insn(Instruction::V128Const(value)) } /// Add an `i32.add` instruction to this constant expression. pub fn with_i32_add(self) -> Self { self.with_insn(Instruction::I32Add) } /// Add an `i32.sub` instruction to this constant expression. pub fn with_i32_sub(self) -> Self { self.with_insn(Instruction::I32Sub) } /// Add an `i32.mul` instruction to this constant expression. pub fn with_i32_mul(self) -> Self { self.with_insn(Instruction::I32Mul) } /// Add an `i64.add` instruction to this constant expression. pub fn with_i64_add(self) -> Self { self.with_insn(Instruction::I64Add) } /// Add an `i64.sub` instruction to this constant expression. pub fn with_i64_sub(self) -> Self { self.with_insn(Instruction::I64Sub) } /// Add an `i64.mul` instruction to this constant expression. pub fn with_i64_mul(self) -> Self { self.with_insn(Instruction::I64Mul) } /// 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; } leb128::read::unsigned(&mut &self.bytes[1..]) .ok()? .try_into() .ok() } } impl Encode for ConstExpr { fn encode(&self, sink: &mut Vec) { sink.extend(&self.bytes); Instruction::End.encode(sink); } } #[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.instruction(&Instruction::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.217.0/src/core/custom.rs000064400000000000000000000034041046102023000157570ustar 00000000000000use std::borrow::Cow; use crate::{encoding_size, Encode, Section, SectionId}; /// A custom section holding arbitrary data. #[derive(Clone, Debug)] 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::*; #[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.217.0/src/core/data.rs000064400000000000000000000111531046102023000153560ustar 00000000000000use crate::{encode_section, encoding_size, ConstExpr, Encode, Section, SectionId}; /// 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.217.0/src/core/dump.rs000064400000000000000000000442651046102023000154240ustar 00000000000000use std::borrow::Cow; use crate::{CustomSection, Encode, Section}; /// 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(f32), /// An f64 value F64(f64), } 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.217.0/src/core/elements.rs000064400000000000000000000153521046102023000162660ustar 00000000000000use crate::{encode_section, ConstExpr, Encode, RefType, Section, SectionId}; /// An encoder for the element section. /// /// Element sections are only supported for modules. /// /// # Example /// /// ``` /// 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(&[ /// // 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, Copy, Debug)] pub enum Elements<'a> { /// A sequences of references to functions by their indices. Functions(&'a [u32]), /// A sequence of reference expressions. Expressions(RefType, &'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 { 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.217.0/src/core/exports.rs000064400000000000000000000040471046102023000161550ustar 00000000000000use super::{ CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT, CORE_TABLE_SORT, CORE_TAG_SORT, }; use crate::{encode_section, Encode, Section, SectionId}; /// Represents the kind of an export from a WebAssembly module. #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[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.217.0/src/core/functions.rs000064400000000000000000000030341046102023000164540ustar 00000000000000use crate::{encode_section, Encode, Section, SectionId}; /// 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.217.0/src/core/globals.rs000064400000000000000000000045221046102023000160720ustar 00000000000000use crate::{encode_section, ConstExpr, Encode, Section, SectionId, ValType}; /// 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.217.0/src/core/imports.rs000064400000000000000000000064501046102023000161460ustar 00000000000000use crate::{ encode_section, Encode, GlobalType, MemoryType, Section, SectionId, TableType, TagType, CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT, CORE_TABLE_SORT, CORE_TAG_SORT, }; /// 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.217.0/src/core/linking.rs000064400000000000000000000203201046102023000160740ustar 00000000000000use std::borrow::Cow; use crate::{encode_section, CustomSection, Encode, Section, SectionId}; 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.217.0/src/core/memories.rs000064400000000000000000000056321046102023000162720ustar 00000000000000use crate::{encode_section, Encode, Section, SectionId}; /// 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.217.0/src/core/names.rs000064400000000000000000000232461046102023000155560ustar 00000000000000use std::borrow::Cow; use crate::{encoding_size, CustomSection, Encode, Section, SectionId}; /// 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.217.0/src/core/producers.rs000064400000000000000000000125341046102023000164570ustar 00000000000000use std::borrow::Cow; use crate::{CustomSection, Encode, Section, SectionId}; /// 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.217.0/src/core/start.rs000064400000000000000000000020071046102023000156000ustar 00000000000000use crate::{encoding_size, Encode, Section, SectionId}; /// 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.217.0/src/core/tables.rs000064400000000000000000000061161046102023000157220ustar 00000000000000use crate::{encode_section, ConstExpr, Encode, RefType, Section, SectionId, ValType}; /// 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.217.0/src/core/tags.rs000064400000000000000000000034141046102023000154040ustar 00000000000000use crate::{encode_section, Encode, Section, SectionId}; /// 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.217.0/src/core/types.rs000064400000000000000000000451431046102023000156170ustar 00000000000000use crate::{encode_section, Encode, Section, SectionId}; /// 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, } impl Encode for SubType { fn encode(&self, sink: &mut Vec) { // We only need to emit a prefix byte before the actual composite type // when either the type is not final or it has a declared super type. if self.supertype_idx.is_some() || !self.is_final { sink.push(if self.is_final { 0x4f } else { 0x50 }); self.supertype_idx.encode(sink); } self.composite_type.encode(sink); } } /// 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, } impl Encode for CompositeType { fn encode(&self, sink: &mut Vec) { if self.shared { sink.push(0x65); } match &self.inner { CompositeInnerType::Func(ty) => TypeSection::encode_function( sink, ty.params().iter().copied(), ty.results().iter().copied(), ), CompositeInnerType::Array(ArrayType(ty)) => { TypeSection::encode_array(sink, &ty.element_type, ty.mutable) } CompositeInnerType::Struct(ty) => { TypeSection::encode_struct(sink, ty.fields.iter().cloned()) } } } } /// 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), } /// 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, } } } /// 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, }, }; /// 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, } 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), } } } /// An encoder for the type section of WebAssembly modules. /// /// # Example /// /// ```rust /// use wasm_encoder::{Module, TypeSection, ValType}; /// /// let mut types = TypeSection::new(); /// /// types.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 } /// Define a function type in this type section. pub fn function(&mut self, params: P, results: R) -> &mut Self where P: IntoIterator, P::IntoIter: ExactSizeIterator, R: IntoIterator, R::IntoIter: ExactSizeIterator, { Self::encode_function(&mut self.bytes, params, results); self.num_added += 1; self } /// Define a function type in this type section. pub fn func_type(&mut self, ty: &FuncType) -> &mut Self { Self::encode_function( &mut self.bytes, ty.params().iter().cloned(), ty.results().iter().cloned(), ); self.num_added += 1; self } fn encode_function(sink: &mut Vec, 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(); sink.push(0x60); params.len().encode(sink); params.for_each(|p| p.encode(sink)); results.len().encode(sink); results.for_each(|p| p.encode(sink)); } /// Define an array type in this type section. pub fn array(&mut self, ty: &StorageType, mutable: bool) -> &mut Self { Self::encode_array(&mut self.bytes, ty, mutable); self.num_added += 1; self } fn encode_array(sink: &mut Vec, ty: &StorageType, mutable: bool) { sink.push(0x5e); Self::encode_field(sink, ty, mutable); } fn encode_field(sink: &mut Vec, ty: &StorageType, mutable: bool) { ty.encode(sink); sink.push(mutable as u8); } /// Define a struct type in this type section. pub fn struct_(&mut self, fields: F) -> &mut Self where F: IntoIterator, F::IntoIter: ExactSizeIterator, { Self::encode_struct(&mut self.bytes, fields); self.num_added += 1; self } fn encode_struct(sink: &mut Vec, fields: F) where F: IntoIterator, F::IntoIter: ExactSizeIterator, { let fields = fields.into_iter(); sink.push(0x5f); fields.len().encode(sink); for f in fields { Self::encode_field(sink, &f.element_type, f.mutable); } } /// Define an explicit subtype in this type section. pub fn subtype(&mut self, ty: &SubType) -> &mut Self { ty.encode(&mut self.bytes); self.num_added += 1; self } /// Define an explicit recursion group in this type section. pub fn rec(&mut self, types: T) -> &mut Self where T: IntoIterator, T::IntoIter: ExactSizeIterator, { let types = types.into_iter(); self.bytes.push(0x4e); types.len().encode(&mut self.bytes); types.for_each(|t| t.encode(&mut self.bytes)); self.num_added += 1; self } } 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() } } #[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.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.217.0/src/core.rs000064400000000000000000000077551046102023000144620ustar 00000000000000mod code; mod custom; mod data; mod dump; mod elements; mod exports; mod functions; mod globals; mod imports; mod linking; mod memories; mod names; mod producers; mod start; mod tables; mod tags; mod types; 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 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; 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 } /// 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.217.0/src/lib.rs000064400000000000000000000125131046102023000142640ustar 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, Instruction, //! Module, TypeSection, ValType, //! }; //! //! let mut module = Module::new(); //! //! // Encode the type section. //! let mut types = TypeSection::new(); //! let params = vec![ValType::I32, ValType::I32]; //! let results = vec![ValType::I32]; //! types.function(params, results); //! module.section(&types); //! //! // Encode the function section. //! let mut functions = FunctionSection::new(); //! let type_index = 0; //! functions.function(type_index); //! module.section(&functions); //! //! // Encode the export section. //! let mut exports = ExportSection::new(); //! exports.export("f", 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.instruction(&Instruction::LocalGet(0)); //! f.instruction(&Instruction::LocalGet(1)); //! f.instruction(&Instruction::I32Add); //! f.instruction(&Instruction::End); //! codes.function(&f); //! module.section(&codes); //! //! // Extract the encoded Wasm bytes for this module. //! let wasm_bytes = module.finish(); //! //! // We generated a valid Wasm module! //! assert!(wasmparser::validate(&wasm_bytes).is_ok()); //! ``` #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![deny(missing_docs, missing_debug_implementations)] mod component; mod core; mod raw; #[cfg(feature = "wasmparser")] pub mod reencode; pub use self::component::*; pub use self::core::*; pub use self::raw::*; /// 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) { leb128::write::unsigned(sink, (*self).into()).unwrap(); } } impl Encode for i32 { fn encode(&self, sink: &mut Vec) { leb128::write::signed(sink, (*self).into()).unwrap(); } } impl Encode for u64 { fn encode(&self, sink: &mut Vec) { leb128::write::unsigned(sink, *self).unwrap(); } } impl Encode for i64 { fn encode(&self, sink: &mut Vec) { leb128::write::signed(sink, *self).unwrap(); } } impl Encode for f32 { fn encode(&self, sink: &mut Vec) { let bits = self.to_bits(); sink.extend(bits.to_le_bytes()) } } impl Encode for f64 { fn encode(&self, sink: &mut Vec) { let bits = self.to_bits(); sink.extend(bits.to_le_bytes()) } } 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 mut buf = [0u8; 5]; leb128::write::unsigned(&mut &mut buf[..], n.into()).unwrap() } 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 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.217.0/src/raw.rs000064400000000000000000000011671046102023000143120ustar 00000000000000use crate::{ComponentSection, Encode, Section}; /// 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 } } impl ComponentSection for RawSection<'_> { fn id(&self) -> u8 { self.id } } wasm-encoder-0.217.0/src/reencode/component.rs000064400000000000000000001450571046102023000173160ustar 00000000000000use crate::reencode::{Error, Reencode, RoundtripReencoder}; #[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) -> u32 { 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::CoreTypeEncoder<'_>, 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_sub_type( &mut self, ty: crate::CoreTypeEncoder<'_>, sub: wasmparser::SubType, ) -> Result<(), Error> { component_utils::parse_component_sub_type(self, ty, sub) } 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, ) -> crate::component::ComponentTypeRef { 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, ) -> crate::component::CanonicalOption { 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; 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::UnknownSection { id, contents, .. } => { reencoder.parse_unknown_component_section(component, id, contents)?; } 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(_) => {} } 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)); 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::CoreTypeEncoder<'_>, decl: wasmparser::CoreType<'_>, ) -> Result<(), Error> { match decl { wasmparser::CoreType::Sub(core) => reencoder.parse_component_sub_type(ty, core)?, 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))), ); match ty.results { wasmparser::ComponentFuncResult::Unnamed(ty) => { func.result(reencoder.component_val_type(ty)); } wasmparser::ComponentFuncResult::Named(list) => { func.results( Vec::from(list) .into_iter() .map(|(name, ty)| (name, reencoder.component_val_type(ty))), ); } } 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::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)); } } 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(ty) => { reencoder.parse_component_sub_type(module.ty(), ty)? } 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_sub_type( reencoder: &mut T, ty: crate::CoreTypeEncoder<'_>, sub: wasmparser::SubType, ) -> Result<(), Error> { if !sub.is_final || sub.supertype_idx.is_some() || sub.composite_type.shared { return Err(Error::UnsupportedCoreTypeInComponent); } let func = match sub.composite_type.inner { wasmparser::CompositeInnerType::Func(f) => f, _ => return Err(Error::UnsupportedCoreTypeInComponent), }; ty.function( func.params() .iter() .map(|t| reencoder.val_type(*t)) .collect::, _>>()?, func.results() .iter() .map(|t| reencoder.val_type(*t)) .collect::, _>>()?, ); Ok(()) } 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); section.lift( func, ty, options.iter().map(|o| reencoder.canonical_option(*o)), ); } wasmparser::CanonicalFunction::Lower { func_index, options, } => { let func = reencoder.component_func_index(func_index); section.lower(func, options.iter().map(|o| reencoder.canonical_option(*o))); } 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::ResourceRep { resource } => { let resource = reencoder.component_type_index(resource); section.resource_rep(resource); } } 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) => { instances.export_items(exports.iter().map(|export| { ( export.name, reencoder.export_kind(export.kind), reencoder.external_index(export.kind, export.index), ) })); } } 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)), ); 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, ) -> crate::component::ComponentTypeRef { 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, } } 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, ) -> crate::component::CanonicalOption { 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)) } } } 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::CoreModules(map) => { names.core_modules(&name_map(map, |i| reencoder.module_index(i))?); } wasmparser::ComponentName::CoreInstances(map) => { names.core_instances(&name_map(map, |i| reencoder.instance_index(i))?); } wasmparser::ComponentName::CoreTypes(map) => { names.core_types(&name_map(map, |i| reencoder.type_index(i))?); } wasmparser::ComponentName::Types(map) => { names.types(&name_map(map, |i| reencoder.component_type_index(i))?); } wasmparser::ComponentName::Instances(map) => { names.instances(&name_map(map, |i| reencoder.component_instance_index(i))?); } wasmparser::ComponentName::Components(map) => { names.components(&name_map(map, |i| reencoder.component_index(i))?); } wasmparser::ComponentName::Funcs(map) => { names.funcs(&name_map(map, |i| reencoder.component_func_index(i))?); } wasmparser::ComponentName::Values(map) => { names.values(&name_map(map, |i| 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 { 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 { 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.217.0/src/reencode.rs000064400000000000000000002057601046102023000153120ustar 00000000000000//! Conversions from `wasmparser` to `wasm-encoder` to [`Reencode`] parsed wasm. //! //! The [`RoundtripReencoder`] allows encoding identical wasm to the parsed //! input. use std::convert::Infallible; mod component; pub use self::component::*; #[allow(missing_docs)] // FIXME pub trait Reencode { type Error; fn data_index(&mut self, data: u32) -> u32 { utils::data_index(self, data) } fn element_index(&mut self, element: u32) -> u32 { utils::element_index(self, element) } fn function_index(&mut self, func: u32) -> u32 { utils::function_index(self, func) } fn global_index(&mut self, global: u32) -> u32 { utils::global_index(self, global) } fn memory_index(&mut self, memory: u32) -> u32 { utils::memory_index(self, memory) } fn table_index(&mut self, table: u32) -> u32 { utils::table_index(self, table) } fn tag_index(&mut self, tag: u32) -> u32 { utils::tag_index(self, tag) } fn type_index(&mut self, ty: u32) -> u32 { 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) -> u32 { 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, ) -> crate::AbstractHeapType { 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) -> crate::Catch { 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) -> crate::ExportKind { 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 global_type( &mut self, global_ty: wasmparser::GlobalType, ) -> Result> { utils::global_type(self, global_ty) } 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) -> crate::MemoryType { utils::memory_type(self, memory_ty) } fn mem_arg(&mut self, arg: wasmparser::MemArg) -> crate::MemArg { utils::mem_arg(self, arg) } fn ordering(&mut self, arg: wasmparser::Ordering) -> crate::Ordering { 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) -> crate::TagKind { utils::tag_kind(self, kind) } fn tag_type(&mut self, tag_ty: wasmparser::TagType) -> crate::TagType { utils::tag_type(self, tag_ty) } fn val_type( &mut self, val_ty: wasmparser::ValType, ) -> Result> { utils::val_type(self, val_ty) } /// 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>, ) -> crate::CustomSection<'a> { 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) } /// 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<'_>) { 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, types: &mut crate::TypeSection, rec_group: wasmparser::RecGroup, ) -> Result<(), Error> { utils::parse_recursive_type_group(self, types, 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) } } /// 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, /// There was a section that does not belong into a core wasm module. UnexpectedNonCoreModuleSection, /// There was a section that does not belong into a compoennt 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 std::fmt::Display for Error { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::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 into a core wasm module" ), Self::UnexpectedNonComponentSection => write!( fmt, "There was a section that does not belong into 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") } } } } impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { Self::ParseError(e) => Some(e), Self::UserError(e) => Some(e), Self::InvalidConstExpr | Self::CanonicalizedHeapTypeReference | Self::UnexpectedNonCoreModuleSection | Self::UnexpectedNonComponentSection | Self::UnsupportedCoreTypeInComponent => 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::Encode; 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 = std::mem::replace(last_section, next_section); let before = next_section; reencoder.intersperse_section_hook(module, after, before) } let mut sections = parser.parse_all(data); let mut next_section = sections.next(); let mut last_section = None; 'outer: while let Some(section) = next_section { 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.function_index(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), )?; 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 { count, .. } => { handle_intersperse_section_hook( reencoder, module, &mut last_section, Some(crate::SectionId::Code), )?; let mut codes = crate::CodeSection::new(); for _ in 0..count { if let Some(Ok(wasmparser::Payload::CodeSectionEntry(section))) = sections.next() { reencoder.parse_function_body(&mut codes, section)?; } else { return Err(Error::UnexpectedNonCoreModuleSection); } } module.section(&codes); } wasmparser::Payload::CodeSectionEntry(section) => { handle_intersperse_section_hook( reencoder, module, &mut last_section, Some(crate::SectionId::Code), )?; // we can't do better than start a new code section here let mut codes = crate::CodeSection::new(); reencoder.parse_function_body(&mut codes, section)?; while let Some(section) = sections.next() { let section = section?; if let wasmparser::Payload::CodeSectionEntry(section) = section { reencoder.parse_function_body(&mut codes, section)?; } else { module.section(&codes); next_section = Some(Ok(section)); continue 'outer; } } module.section(&codes); } 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::UnknownSection { id, contents, .. } => { reencoder.parse_unknown_section(module, id, contents)?; } wasmparser::Payload::End(_) => { handle_intersperse_section_hook(reencoder, module, &mut last_section, None)?; } } next_section = sections.next(); } 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 mem_arg( reencoder: &mut T, arg: wasmparser::MemArg, ) -> crate::MemArg { 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) -> crate::Catch { 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 }, } } /// 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() .map(|ty| reencoder.type_index(ty)) .ok_or(Error::CanonicalizedHeapTypeReference) } pub fn tag_type( reencoder: &mut T, tag_ty: wasmparser::TagType, ) -> crate::TagType { crate::TagType { kind: reencoder.tag_kind(tag_ty.kind), func_type_idx: reencoder.type_index(tag_ty.func_type_idx), } } 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, } } /// 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, rec_group?)?; } Ok(()) } /// Parses a single [`wasmparser::RecGroup`] and adds it to the `types` section. pub fn parse_recursive_type_group( reencoder: &mut T, types: &mut crate::TypeSection, 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::, _>>()?; types.rec(subtypes); } else { let ty = rec_group.into_types().next().unwrap(); types.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)?) } }; 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 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<'_>, ) { exports.export( export.name, reencoder.export_kind(export.kind), reencoder.external_index(export.kind, export.index), ); } /// 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 mut funcs; let mut exprs; let elems = match element.items { wasmparser::ElementItems::Functions(f) => { funcs = Vec::new(); for func in f { funcs.push(reencoder.function_index(func?)); } crate::Elements::Functions(&funcs) } wasmparser::ElementItems::Expressions(ty, e) => { exprs = Vec::new(); for expr in e { exprs.push(reencoder.const_expr(expr?)?); } crate::Elements::Expressions(reencoder.ref_type(ty)?, &exprs) } }; match element.kind { wasmparser::ElementKind::Active { table_index, offset_expr, } => elements.active( table_index.map(|t| reencoder.table_index(t)), &reencoder.const_expr(offset_expr)?, elems, ), wasmparser::ElementKind::Passive => elements.passive(elems), wasmparser::ElementKind::Declared => elements.declared(elems), }; Ok(()) } 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; macro_rules! translate { ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { Ok(match arg { $( wasmparser::Operator::$op $({ $($arg),* })? => { $( $(let $arg = translate!(map $arg $arg);)* )? translate!(build $op $($($arg)*)?) } )* }) }; // 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 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); // 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 I32Const $arg:ident) => (Instruction::I32Const($arg)); (build I64Const $arg:ident) => (Instruction::I64Const($arg)); (build F32Const $arg:ident) => (Instruction::F32Const(f32::from_bits($arg.bits()))); (build F64Const $arg:ident) => (Instruction::F64Const(f64::from_bits($arg.bits()))); (build 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) -> u32, ) -> wasmparser::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) -> u32, ) -> wasmparser::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| i)?); } Ok(ret) } } impl From for crate::MemArg { fn from(arg: wasmparser::MemArg) -> Self { RoundtripReencoder.mem_arg(arg) } } impl From for crate::Ordering { fn from(arg: wasmparser::Ordering) -> Self { RoundtripReencoder.ordering(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 From for crate::Catch { fn from(arg: wasmparser::Catch) -> Self { 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 { RoundtripReencoder.custom_section(section) } } impl From for crate::ExportKind { fn from(external_kind: wasmparser::ExternalKind) -> Self { RoundtripReencoder.export_kind(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::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 { RoundtripReencoder.memory_type(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 { RoundtripReencoder.tag_kind(kind) } } impl From for crate::TagType { fn from(tag_ty: wasmparser::TagType) -> Self { 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 { RoundtripReencoder.abstract_heap_type(value) } }