diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /third_party/rust/wasm-encoder/src | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/wasm-encoder/src')
32 files changed, 9567 insertions, 0 deletions
diff --git a/third_party/rust/wasm-encoder/src/component.rs b/third_party/rust/wasm-encoder/src/component.rs new file mode 100644 index 0000000000..e3f36a88a2 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component.rs @@ -0,0 +1,168 @@ +mod 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<u8>) { + 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<ComponentSectionId> for u8 { + #[inline] + fn from(id: ComponentSectionId) -> u8 { + id as u8 + } +} + +impl Encode for ComponentSectionId { + fn encode(&self, sink: &mut Vec<u8>) { + 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<u8>, +} + +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<u8> { + 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() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/aliases.rs b/third_party/rust/wasm-encoder/src/component/aliases.rs new file mode 100644 index 0000000000..1e317fb0e2 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/aliases.rs @@ -0,0 +1,160 @@ +use 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<u8>) { + 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<u8>, + 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<u8>) { + 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<u8>) { + 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); + } + } + } +} diff --git a/third_party/rust/wasm-encoder/src/component/builder.rs b/third_party/rust/wasm-encoder/src/component/builder.rs new file mode 100644 index 0000000000..27c39ac8a0 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/builder.rs @@ -0,0 +1,455 @@ +use 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<u8> { + 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<Item = (&'a str, ModuleArg)>, + 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<Item = (&'a str, ExportKind, u32)>, + 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, + }) + } + + 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<O>(&mut self, func_index: u32, options: O) -> u32 + where + O: IntoIterator<Item = CanonicalOption>, + O::IntoIter: ExactSizeIterator, + { + self.canonical_functions().lower(func_index, options); + inc(&mut self.core_funcs) + } + + /// Lifts the core wasm `core_func_index` function with the component + /// function type `type_index` and `options`. + /// + /// Returns the index of the component function created. + pub fn lift_func<O>(&mut self, core_func_index: u32, type_index: u32, options: O) -> u32 + where + O: IntoIterator<Item = CanonicalOption>, + 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<ComponentTypeRef>, + ) -> 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>) -> 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<A, S>(&mut self, component_index: u32, args: A) -> u32 + where + A: IntoIterator<Item = (S, ComponentExportKind, u32)>, + A::IntoIter: ExactSizeIterator, + S: AsRef<str>, + { + 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 +} diff --git a/third_party/rust/wasm-encoder/src/component/canonicals.rs b/third_party/rust/wasm-encoder/src/component/canonicals.rs new file mode 100644 index 0000000000..340d9ca621 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/canonicals.rs @@ -0,0 +1,159 @@ +use 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<u8>) { + 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<u8>, + 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<O>(&mut self, core_func_index: u32, type_index: u32, options: O) -> &mut Self + where + O: IntoIterator<Item = CanonicalOption>, + O::IntoIter: ExactSizeIterator, + { + let options = options.into_iter(); + self.bytes.push(0x00); + self.bytes.push(0x00); + core_func_index.encode(&mut self.bytes); + options.len().encode(&mut self.bytes); + for option in options { + option.encode(&mut self.bytes); + } + 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<O>(&mut self, func_index: u32, options: O) -> &mut Self + where + O: IntoIterator<Item = CanonicalOption>, + O::IntoIter: ExactSizeIterator, + { + let options = options.into_iter(); + self.bytes.push(0x01); + self.bytes.push(0x00); + func_index.encode(&mut self.bytes); + options.len().encode(&mut self.bytes); + for option in options { + option.encode(&mut self.bytes); + } + self.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<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl ComponentSection for CanonicalFunctionSection { + fn id(&self) -> u8 { + ComponentSectionId::CanonicalFunction.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/components.rs b/third_party/rust/wasm-encoder/src/component/components.rs new file mode 100644 index 0000000000..c08645e3b9 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/components.rs @@ -0,0 +1,29 @@ +use 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<u8>) { + self.0.bytes.encode(sink); + } +} + +impl ComponentSection for NestedComponentSection<'_> { + fn id(&self) -> u8 { + ComponentSectionId::Component.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/exports.rs b/third_party/rust/wasm-encoder/src/component/exports.rs new file mode 100644 index 0000000000..e4fcfee055 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/exports.rs @@ -0,0 +1,124 @@ +use super::{ + COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, FUNCTION_SORT, INSTANCE_SORT, TYPE_SORT, + VALUE_SORT, +}; +use crate::{encode_section, ComponentSection, ComponentSectionId, ComponentTypeRef, Encode}; + +/// 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<u8>) { + 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<u8>, + 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<ComponentTypeRef>, + ) -> &mut Self { + crate::component::imports::push_extern_name_byte(&mut self.bytes, name); + name.encode(&mut self.bytes); + 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<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl ComponentSection for ComponentExportSection { + fn id(&self) -> u8 { + ComponentSectionId::Export.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/imports.rs b/third_party/rust/wasm-encoder/src/component/imports.rs new file mode 100644 index 0000000000..6337a0625d --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/imports.rs @@ -0,0 +1,175 @@ +use 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<u8>) { + 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<u8>) { + 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<u8>, + 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 { + push_extern_name_byte(&mut self.bytes, name); + name.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + self + } +} + +impl Encode for ComponentImportSection { + fn encode(&self, sink: &mut Vec<u8>) { + 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. +/// +/// This function is a compatibility shim for the time being while this change +/// is being rolled out. That PR is technically a spec-breaking change relative +/// to prior but we want old tooling to continue to work with new modules. To +/// handle that names that look like IDs, `a:b/c`, get an 0x01 prefix instead of +/// the spec-defined 0x00 prefix. That makes components produced by current +/// versions of this crate compatible with older parsers. +/// +/// Note that wasmparser has a similar case where it parses either 0x01 or 0x00. +/// That means that the selection of a byte here doesn't actually matter for +/// wasmparser's own validation. Eventually this will go away and an 0x00 byte +/// will always be emitted to align with the spec. +pub(crate) fn push_extern_name_byte(bytes: &mut Vec<u8>, name: &str) { + if name.contains(':') { + bytes.push(0x01); + } else { + bytes.push(0x00); + } +} diff --git a/third_party/rust/wasm-encoder/src/component/instances.rs b/third_party/rust/wasm-encoder/src/component/instances.rs new file mode 100644 index 0000000000..e0877d1661 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/instances.rs @@ -0,0 +1,200 @@ +use 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<u8>) { + 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<u8>, + 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<A, S>(&mut self, module_index: u32, args: A) -> &mut Self + where + A: IntoIterator<Item = (S, ModuleArg)>, + A::IntoIter: ExactSizeIterator, + S: AsRef<str>, + { + 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<E, S>(&mut self, exports: E) -> &mut Self + where + E: IntoIterator<Item = (S, ExportKind, u32)>, + E::IntoIter: ExactSizeIterator, + S: AsRef<str>, + { + 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<u8>) { + 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<u8>, + 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<A, S>(&mut self, component_index: u32, args: A) -> &mut Self + where + A: IntoIterator<Item = (S, ComponentExportKind, u32)>, + A::IntoIter: ExactSizeIterator, + S: AsRef<str>, + { + 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<Item = (&'a str, ComponentExportKind, u32)>, + 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::push_extern_name_byte(&mut self.bytes, name); + name.encode(&mut self.bytes); + 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<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl ComponentSection for ComponentInstanceSection { + fn id(&self) -> u8 { + ComponentSectionId::Instance.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/modules.rs b/third_party/rust/wasm-encoder/src/component/modules.rs new file mode 100644 index 0000000000..437cd353af --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/modules.rs @@ -0,0 +1,29 @@ +use 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<u8>) { + self.0.bytes.encode(sink); + } +} + +impl ComponentSection for ModuleSection<'_> { + fn id(&self) -> u8 { + ComponentSectionId::CoreModule.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/names.rs b/third_party/rust/wasm-encoder/src/component/names.rs new file mode 100644 index 0000000000..99db10bda0 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/names.rs @@ -0,0 +1,149 @@ +use std::borrow::Cow; + +use super::*; +use crate::{encoding_size, CustomSection, Encode, 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<u8>, +} + +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) + } + + 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<u8>) { + self.as_custom().encode(sink); + } +} + +impl ComponentSection for ComponentNameSection { + fn id(&self) -> u8 { + SectionId::Custom.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/start.rs b/third_party/rust/wasm-encoder/src/component/start.rs new file mode 100644 index 0000000000..d4b60e1dfc --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/start.rs @@ -0,0 +1,52 @@ +use 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<A> { + /// 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<A> Encode for ComponentStartSection<A> +where + A: AsRef<[u32]>, +{ + fn encode(&self, sink: &mut Vec<u8>) { + 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<A> ComponentSection for ComponentStartSection<A> +where + A: AsRef<[u32]>, +{ + fn id(&self) -> u8 { + ComponentSectionId::Start.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/types.rs b/third_party/rust/wasm-encoder/src/component/types.rs new file mode 100644 index 0000000000..537e8c5a00 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/types.rs @@ -0,0 +1,792 @@ +use 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<u8>, + 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 { + crate::component::imports::push_extern_name_byte(&mut self.bytes, name); + 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<u8>) { + 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<u8>); + +impl<'a> CoreTypeEncoder<'a> { + /// Define a function type. + pub fn function<P, R>(self, params: P, results: R) + where + P: IntoIterator<Item = ValType>, + P::IntoIter: ExactSizeIterator, + R: IntoIterator<Item = ValType>, + 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<u8>, + 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<P, R>(&mut self, params: P, results: R) -> &mut Self + where + P: IntoIterator<Item = ValType>, + P::IntoIter: ExactSizeIterator, + R: IntoIterator<Item = ValType>, + 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<u8>) { + 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<u8>, + 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::component::imports::push_extern_name_byte(&mut self.bytes, name); + name.encode(&mut self.bytes); + 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::component::imports::push_extern_name_byte(&mut self.bytes, name); + name.encode(&mut self.bytes); + 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<u8>) { + 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<u8>) { + 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>(&'a mut Vec<u8>); + +impl<'a> ComponentFuncTypeEncoder<'a> { + fn new(sink: &'a mut Vec<u8>) -> Self { + sink.push(0x40); + Self(sink) + } + + /// Defines named parameters. + /// + /// Parameters must be defined before defining results. + pub fn params<'b, P, T>(&mut self, params: P) -> &mut Self + where + P: IntoIterator<Item = (&'b str, T)>, + P::IntoIter: ExactSizeIterator, + T: Into<ComponentValType>, + { + let params = params.into_iter(); + params.len().encode(self.0); + for (name, ty) in params { + name.encode(self.0); + ty.into().encode(self.0); + } + self + } + + /// Defines a single unnamed result. + /// + /// This method cannot be used with `results`. + pub fn result(&mut self, ty: impl Into<ComponentValType>) -> &mut Self { + self.0.push(0x00); + ty.into().encode(self.0); + self + } + + /// Defines named results. + /// + /// This method cannot be used with `result`. + pub fn results<'b, R, T>(&mut self, results: R) -> &mut Self + where + R: IntoIterator<Item = (&'b str, T)>, + R::IntoIter: ExactSizeIterator, + T: Into<ComponentValType>, + { + self.0.push(0x01); + let results = results.into_iter(); + results.len().encode(self.0); + for (name, ty) in results { + name.encode(self.0); + ty.into().encode(self.0); + } + self + } +} + +/// Used to encode component and instance types. +#[derive(Debug)] +pub struct ComponentTypeEncoder<'a>(&'a mut Vec<u8>); + +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<u32>) { + 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. + Float32, + /// The type is a 64-bit floating point number. + Float64, + /// The type is a Unicode character. + Char, + /// The type is a string. + String, +} + +impl Encode for PrimitiveValType { + fn encode(&self, sink: &mut Vec<u8>) { + 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::Float32 => 0x76, + Self::Float64 => 0x75, + Self::Char => 0x74, + Self::String => 0x73, + }); + } +} + +#[cfg(feature = "wasmparser")] +impl From<wasmparser::PrimitiveValType> for PrimitiveValType { + fn from(ty: wasmparser::PrimitiveValType) -> Self { + match ty { + wasmparser::PrimitiveValType::Bool => PrimitiveValType::Bool, + wasmparser::PrimitiveValType::S8 => PrimitiveValType::S8, + wasmparser::PrimitiveValType::U8 => PrimitiveValType::U8, + wasmparser::PrimitiveValType::S16 => PrimitiveValType::S16, + wasmparser::PrimitiveValType::U16 => PrimitiveValType::U16, + wasmparser::PrimitiveValType::S32 => PrimitiveValType::S32, + wasmparser::PrimitiveValType::U32 => PrimitiveValType::U32, + wasmparser::PrimitiveValType::S64 => PrimitiveValType::S64, + wasmparser::PrimitiveValType::U64 => PrimitiveValType::U64, + wasmparser::PrimitiveValType::Float32 => PrimitiveValType::Float32, + wasmparser::PrimitiveValType::Float64 => PrimitiveValType::Float64, + wasmparser::PrimitiveValType::Char => PrimitiveValType::Char, + wasmparser::PrimitiveValType::String => PrimitiveValType::String, + } + } +} + +/// 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<u8>) { + match self { + Self::Primitive(ty) => ty.encode(sink), + Self::Type(index) => (*index as i64).encode(sink), + } + } +} + +impl From<PrimitiveValType> 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<u8>); + +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<Item = (&'a str, T)>, + F::IntoIter: ExactSizeIterator, + T: Into<ComponentValType>, + { + 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<Item = (&'a str, Option<ComponentValType>, Option<u32>)>, + 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<ComponentValType>) { + self.0.push(0x70); + ty.into().encode(self.0); + } + + /// Define a tuple type. + pub fn tuple<I, T>(self, types: I) + where + I: IntoIterator<Item = T>, + I::IntoIter: ExactSizeIterator, + T: Into<ComponentValType>, + { + 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<Item = &'a str>, + 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<Item = &'a str>, + 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<ComponentValType>) { + self.0.push(0x6B); + ty.into().encode(self.0); + } + + /// Define a result type. + pub fn result(self, ok: Option<ComponentValType>, err: Option<ComponentValType>) { + 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<u8>, + 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<u32>) -> &mut Self { + self.ty().resource(rep, dtor); + self + } +} + +impl Encode for ComponentTypeSection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl ComponentSection for ComponentTypeSection { + fn id(&self) -> u8 { + ComponentSectionId::Type.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/core.rs b/third_party/rust/wasm-encoder/src/core.rs new file mode 100644 index 0000000000..feccfdefc1 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core.rs @@ -0,0 +1,168 @@ +mod 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<u8>) { + 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<SectionId> for u8 { + #[inline] + fn from(id: SectionId) -> u8 { + id as u8 + } +} + +impl Encode for SectionId { + fn encode(&self, sink: &mut Vec<u8>) { + 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<u8>, +} + +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<u8> { + self.bytes + } +} + +impl Default for Module { + fn default() -> Self { + Self::new() + } +} diff --git a/third_party/rust/wasm-encoder/src/core/code.rs b/third_party/rust/wasm-encoder/src/core/code.rs new file mode 100644 index 0000000000..cec2d4191e --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/code.rs @@ -0,0 +1,3355 @@ +use 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<u8>, + 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: + /// + /// ``` + /// // id, size, # entries, entry + /// let code_section = [10, 6, 1, 4, 0, 65, 0, 11]; + /// + /// // Parse the code section. + /// let reader = wasmparser::CodeSectionReader::new(&code_section, 0).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<u8>) { + 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<u8>, +} + +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<L>(locals: L) -> Self + where + L: IntoIterator<Item = (u32, ValType)>, + 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<L>(locals: L) -> Self + where + L: IntoIterator<Item = ValType>, + { + 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<B>(&mut self, bytes: B) -> &mut Self + where + B: IntoIterator<Item = u8>, + { + 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() + } +} + +impl Encode for Function { + fn encode(&self, sink: &mut Vec<u8>) { + 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<u8>) { + 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); + } + } +} + +/// 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<u8>) { + 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 { + ty: u32, + table: u32, + }, + ReturnCallRef(u32), + ReturnCall(u32), + ReturnCallIndirect { + ty: u32, + table: 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), +} + +impl Encode for Instruction<'_> { + fn encode(&self, sink: &mut Vec<u8>) { + 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 { ty, table } => { + sink.push(0x11); + ty.encode(sink); + table.encode(sink); + } + Instruction::ReturnCallRef(ty) => { + sink.push(0x15); + ty.encode(sink); + } + + Instruction::ReturnCall(f) => { + sink.push(0x12); + f.encode(sink); + } + Instruction::ReturnCallIndirect { ty, table } => { + sink.push(0x13); + ty.encode(sink); + table.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); + } + + // Atmoic 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); + } + } + } +} + +#[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<u8>) { + 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<u8>, +} + +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<Item = u8>) -> Self { + Self { + bytes: bytes.into_iter().collect(), + } + } + + fn new_insn(insn: Instruction) -> Self { + let mut bytes = vec![]; + insn.encode(&mut bytes); + Self { bytes } + } + + /// 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)) + } +} + +impl Encode for ConstExpr { + fn encode(&self, sink: &mut Vec<u8>) { + sink.extend(&self.bytes); + Instruction::End.encode(sink); + } +} + +/// An error when converting a `wasmparser::ConstExpr` into a +/// `wasm_encoder::ConstExpr`. +#[cfg(feature = "wasmparser")] +#[derive(Debug)] +pub enum ConstExprConversionError { + /// There was an error when parsing the const expression. + ParseError(wasmparser::BinaryReaderError), + + /// The const expression is invalid: not actually constant or something like + /// that. + Invalid, + + /// 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. + CanonicalizedTypeReference, +} + +#[cfg(feature = "wasmparser")] +impl std::fmt::Display for ConstExprConversionError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::ParseError(_e) => { + write!(f, "There was an error when parsing the const expression") + } + Self::Invalid => write!(f, "The const expression was invalid"), + Self::CanonicalizedTypeReference => write!( + f, + "There was a canonicalized type reference without type index information" + ), + } + } +} + +#[cfg(feature = "wasmparser")] +impl std::error::Error for ConstExprConversionError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::ParseError(e) => Some(e), + Self::Invalid | Self::CanonicalizedTypeReference => None, + } + } +} + +#[cfg(feature = "wasmparser")] +impl<'a> TryFrom<wasmparser::ConstExpr<'a>> for ConstExpr { + type Error = ConstExprConversionError; + + fn try_from(const_expr: wasmparser::ConstExpr) -> Result<Self, Self::Error> { + let mut ops = const_expr.get_operators_reader().into_iter(); + + let result = match ops.next() { + Some(Ok(wasmparser::Operator::I32Const { value })) => ConstExpr::i32_const(value), + Some(Ok(wasmparser::Operator::I64Const { value })) => ConstExpr::i64_const(value), + Some(Ok(wasmparser::Operator::F32Const { value })) => { + ConstExpr::f32_const(value.bits() as _) + } + Some(Ok(wasmparser::Operator::F64Const { value })) => { + ConstExpr::f64_const(value.bits() as _) + } + Some(Ok(wasmparser::Operator::V128Const { value })) => { + ConstExpr::v128_const(i128::from_le_bytes(*value.bytes())) + } + Some(Ok(wasmparser::Operator::RefNull { hty })) => ConstExpr::ref_null( + HeapType::try_from(hty) + .map_err(|_| ConstExprConversionError::CanonicalizedTypeReference)?, + ), + Some(Ok(wasmparser::Operator::RefFunc { function_index })) => { + ConstExpr::ref_func(function_index) + } + Some(Ok(wasmparser::Operator::GlobalGet { global_index })) => { + ConstExpr::global_get(global_index) + } + + // TODO: support the extended-const proposal. + Some(Ok(_op)) => return Err(ConstExprConversionError::Invalid), + + Some(Err(e)) => return Err(ConstExprConversionError::ParseError(e)), + None => return Err(ConstExprConversionError::Invalid), + }; + + match (ops.next(), ops.next()) { + (Some(Ok(wasmparser::Operator::End)), None) => Ok(result), + _ => Err(ConstExprConversionError::Invalid), + } + } +} + +#[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) + } +} diff --git a/third_party/rust/wasm-encoder/src/core/custom.rs b/third_party/rust/wasm-encoder/src/core/custom.rs new file mode 100644 index 0000000000..870ee62617 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/custom.rs @@ -0,0 +1,73 @@ +use 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<u8>) { + 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<u8>) { + 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, + ]); + } +} diff --git a/third_party/rust/wasm-encoder/src/core/data.rs b/third_party/rust/wasm-encoder/src/core/data.rs new file mode 100644 index 0000000000..6439b66e2e --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/data.rs @@ -0,0 +1,185 @@ +use 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, +/// }); +/// +/// 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<u8>, + 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<D>(&mut self, segment: DataSegment<D>) -> &mut Self + where + D: IntoIterator<Item = u8>, + D::IntoIter: ExactSizeIterator, + { + match segment.mode { + DataSegmentMode::Passive => { + self.bytes.push(0x01); + } + DataSegmentMode::Active { + memory_index: 0, + offset, + } => { + self.bytes.push(0x00); + offset.encode(&mut self.bytes); + } + 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<D>(&mut self, memory_index: u32, offset: &ConstExpr, data: D) -> &mut Self + where + D: IntoIterator<Item = u8>, + D::IntoIter: ExactSizeIterator, + { + self.segment(DataSegment { + mode: DataSegmentMode::Active { + memory_index, + offset, + }, + data, + }) + } + + /// Define a passive data segment. + /// + /// Passive data segments are part of the bulk memory proposal. + pub fn passive<D>(&mut self, data: D) -> &mut Self + where + D: IntoIterator<Item = u8>, + 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<u8>) { + 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<u8>) { + encoding_size(self.count).encode(sink); + self.count.encode(sink); + } +} + +impl Section for DataCountSection { + fn id(&self) -> u8 { + SectionId::DataCount.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/core/dump.rs b/third_party/rust/wasm-encoder/src/core/dump.rs new file mode 100644 index 0000000000..ee3d229909 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/dump.rs @@ -0,0 +1,627 @@ +use 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<String>) -> 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<u8>) { + 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<u8>, +} + +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<str>) -> &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<u8>) { + 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<u8>, +} + +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<M, G>(&mut self, module_index: u32, memories: M, globals: G) -> &mut Self + where + M: IntoIterator<Item = u32>, + <M as IntoIterator>::IntoIter: ExactSizeIterator, + G: IntoIterator<Item = u32>, + <G as 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<u8>) { + 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<u8>, + count: u32, + name: String, +} + +impl CoreDumpStackSection { + /// Create a new core dump stack section encoder. + pub fn new(name: impl Into<String>) -> 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<L, S>( + &mut self, + instanceidx: u32, + funcidx: u32, + codeoffset: u32, + locals: L, + stack: S, + ) -> &mut Self + where + L: IntoIterator<Item = CoreDumpValue>, + <L as IntoIterator>::IntoIter: ExactSizeIterator, + S: IntoIterator<Item = CoreDumpValue>, + <S as 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<u8>) { + 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<u8>) { + 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::{BinaryReader, FromReader, 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 = wasmparser::CoreDumpSection::from_reader(&mut BinaryReader::new( + section.data(), + )) + .expect("data is readable into a core dump section"); + 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 = wasmparser::CoreDumpModulesSection::from_reader( + &mut BinaryReader::new(section.data()), + ) + .expect("data is readable into a core dump modules section"); + 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 = wasmparser::CoreDumpInstancesSection::from_reader( + &mut BinaryReader::new(section.data()), + ) + .expect("data is readable into a core dump instances section"); + 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 = wasmparser::CoreDumpStackSection::from_reader( + &mut BinaryReader::new(section.data()), + ) + .expect("data is readable into a core dump stack 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 + + ] + ); + } +} diff --git a/third_party/rust/wasm-encoder/src/core/elements.rs b/third_party/rust/wasm-encoder/src/core/elements.rs new file mode 100644 index 0000000000..31b772186a --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/elements.rs @@ -0,0 +1,220 @@ +use 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, +/// }); +/// +/// 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<u8>, + num_added: u32, +} + +/// A sequence of elements in a segment in the element section. +#[derive(Clone, Copy, Debug)] +pub enum Elements<'a> { + /// A sequences of references to functions by their indices. + Functions(&'a [u32]), + /// A sequence of reference expressions. + Expressions(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<u32>, + /// 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<u32>, + 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<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl Section for ElementSection { + fn id(&self) -> u8 { + SectionId::Element.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/core/exports.rs b/third_party/rust/wasm-encoder/src/core/exports.rs new file mode 100644 index 0000000000..fc2dc9c392 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/exports.rs @@ -0,0 +1,98 @@ +use 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<u8>) { + sink.push(*self as u8); + } +} + +#[cfg(feature = "wasmparser")] +impl From<wasmparser::ExternalKind> for ExportKind { + fn from(external_kind: wasmparser::ExternalKind) -> Self { + match external_kind { + wasmparser::ExternalKind::Func => ExportKind::Func, + wasmparser::ExternalKind::Table => ExportKind::Table, + wasmparser::ExternalKind::Memory => ExportKind::Memory, + wasmparser::ExternalKind::Global => ExportKind::Global, + wasmparser::ExternalKind::Tag => ExportKind::Tag, + } + } +} + +/// 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<u8>, + 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<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl Section for ExportSection { + fn id(&self) -> u8 { + SectionId::Export.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/core/functions.rs b/third_party/rust/wasm-encoder/src/core/functions.rs new file mode 100644 index 0000000000..e21d8c10a7 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/functions.rs @@ -0,0 +1,63 @@ +use 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<u8>, + 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<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl Section for FunctionSection { + fn id(&self) -> u8 { + SectionId::Function.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/core/globals.rs b/third_party/rust/wasm-encoder/src/core/globals.rs new file mode 100644 index 0000000000..64fec982cd --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/globals.rs @@ -0,0 +1,101 @@ +use 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, +/// }, +/// &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<u8>, + 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<u8>) { + 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, +} + +impl Encode for GlobalType { + fn encode(&self, sink: &mut Vec<u8>) { + self.val_type.encode(sink); + sink.push(self.mutable as u8); + } +} + +#[cfg(feature = "wasmparser")] +impl TryFrom<wasmparser::GlobalType> for GlobalType { + type Error = (); + fn try_from(global_ty: wasmparser::GlobalType) -> Result<Self, Self::Error> { + Ok(GlobalType { + val_type: global_ty.content_type.try_into()?, + mutable: global_ty.mutable, + }) + } +} diff --git a/third_party/rust/wasm-encoder/src/core/imports.rs b/third_party/rust/wasm-encoder/src/core/imports.rs new file mode 100644 index 0000000000..0030d640e6 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/imports.rs @@ -0,0 +1,156 @@ +use crate::{ + encode_section, Encode, GlobalType, MemoryType, Section, SectionId, TableType, TagType, + CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT, CORE_TABLE_SORT, CORE_TAG_SORT, +}; + +/// 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<u8>) { + 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<TableType> for EntityType { + fn from(t: TableType) -> Self { + Self::Table(t) + } +} + +impl From<MemoryType> for EntityType { + fn from(t: MemoryType) -> Self { + Self::Memory(t) + } +} + +impl From<GlobalType> for EntityType { + fn from(t: GlobalType) -> Self { + Self::Global(t) + } +} + +impl From<TagType> for EntityType { + fn from(t: TagType) -> Self { + Self::Tag(t) + } +} + +#[cfg(feature = "wasmparser")] +impl TryFrom<wasmparser::TypeRef> for EntityType { + type Error = (); + fn try_from(type_ref: wasmparser::TypeRef) -> Result<Self, Self::Error> { + Ok(match type_ref { + wasmparser::TypeRef::Func(i) => EntityType::Function(i), + wasmparser::TypeRef::Table(t) => EntityType::Table(t.try_into()?), + wasmparser::TypeRef::Memory(m) => EntityType::Memory(m.into()), + wasmparser::TypeRef::Global(g) => EntityType::Global(g.try_into()?), + wasmparser::TypeRef::Tag(t) => EntityType::Tag(t.into()), + }) + } +} + +/// 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, +/// } +/// ); +/// +/// let mut module = Module::new(); +/// module.section(&imports); +/// +/// let bytes = module.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct ImportSection { + bytes: Vec<u8>, + 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<EntityType>) -> &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<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl Section for ImportSection { + fn id(&self) -> u8 { + SectionId::Import.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/core/linking.rs b/third_party/rust/wasm-encoder/src/core/linking.rs new file mode 100644 index 0000000000..9a2995721f --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/linking.rs @@ -0,0 +1,263 @@ +use 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<u8>, +} + +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<u8>) { + 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<u8>, + 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<DataSymbolDefinition>, + ) -> &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<u8>) { + 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, +} diff --git a/third_party/rust/wasm-encoder/src/core/memories.rs b/third_party/rust/wasm-encoder/src/core/memories.rs new file mode 100644 index 0000000000..892545eb98 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/memories.rs @@ -0,0 +1,111 @@ +use 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, +/// }); +/// +/// let mut module = Module::new(); +/// module.section(&memories); +/// +/// let wasm_bytes = module.finish(); +/// ``` +#[derive(Clone, Default, Debug)] +pub struct MemorySection { + bytes: Vec<u8>, + 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<u8>) { + 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<u64>, + /// Whether or not this is a 64-bit memory. + pub memory64: bool, + /// Whether or not this memory is shared. + pub shared: bool, +} + +impl Encode for MemoryType { + fn encode(&self, sink: &mut Vec<u8>) { + let mut flags = 0; + if self.maximum.is_some() { + flags |= 0b001; + } + if self.shared { + flags |= 0b010; + } + if self.memory64 { + flags |= 0b100; + } + + sink.push(flags); + self.minimum.encode(sink); + if let Some(max) = self.maximum { + max.encode(sink); + } + } +} + +#[cfg(feature = "wasmparser")] +impl From<wasmparser::MemoryType> for MemoryType { + fn from(memory_ty: wasmparser::MemoryType) -> Self { + MemoryType { + minimum: memory_ty.initial, + maximum: memory_ty.maximum, + memory64: memory_ty.memory64, + shared: memory_ty.shared, + } + } +} diff --git a/third_party/rust/wasm-encoder/src/core/names.rs b/third_party/rust/wasm-encoder/src/core/names.rs new file mode 100644 index 0000000000..587ae6a792 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/names.rs @@ -0,0 +1,298 @@ +use 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<u8>, +} + +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); + } + + 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<u8>) { + 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<u8>, + 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<u8>) { + 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<u8>, + 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<u8>) { + self.count.encode(sink); + sink.extend(&self.bytes); + } +} diff --git a/third_party/rust/wasm-encoder/src/core/producers.rs b/third_party/rust/wasm-encoder/src/core/producers.rs new file mode 100644 index 0000000000..af03ecbb8e --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/producers.rs @@ -0,0 +1,180 @@ +use 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<u8>, + 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<u8>) { + 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<u8>, + 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<u8>) { + self.num_values.encode(sink); + sink.extend(&self.bytes); + } +} + +#[cfg(test)] +mod test { + #[test] + fn roundtrip_example() { + use crate::{Module, ProducersField, ProducersSection}; + use wasmparser::{Parser, Payload, ProducersSectionReader}; + + // 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 = ProducersSectionReader::new(c.data(), c.data_offset()) + .expect("readable as a producers section") + .into_iter(); + 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"), + } + } +} diff --git a/third_party/rust/wasm-encoder/src/core/start.rs b/third_party/rust/wasm-encoder/src/core/start.rs new file mode 100644 index 0000000000..8f12c0d0ef --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/start.rs @@ -0,0 +1,39 @@ +use 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<u8>) { + encoding_size(self.function_index).encode(sink); + self.function_index.encode(sink); + } +} + +impl Section for StartSection { + fn id(&self) -> u8 { + SectionId::Start.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/core/tables.rs b/third_party/rust/wasm-encoder/src/core/tables.rs new file mode 100644 index 0000000000..cb224c1564 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/tables.rs @@ -0,0 +1,116 @@ +use crate::{encode_section, ConstExpr, Encode, RefType, Section, SectionId}; + +/// 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, +/// }); +/// +/// let mut module = Module::new(); +/// module.section(&tables); +/// +/// let wasm_bytes = module.finish(); +/// ``` +#[derive(Clone, Default, Debug)] +pub struct TableSection { + bytes: Vec<u8>, + 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<u8>) { + 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, + /// Minimum size, in elements, of this table + pub minimum: u32, + /// Maximum size, in elements, of this table + pub maximum: Option<u32>, +} + +impl Encode for TableType { + fn encode(&self, sink: &mut Vec<u8>) { + let mut flags = 0; + if self.maximum.is_some() { + flags |= 0b001; + } + + self.element_type.encode(sink); + sink.push(flags); + self.minimum.encode(sink); + + if let Some(max) = self.maximum { + max.encode(sink); + } + } +} + +#[cfg(feature = "wasmparser")] +impl TryFrom<wasmparser::TableType> for TableType { + type Error = (); + fn try_from(table_ty: wasmparser::TableType) -> Result<Self, Self::Error> { + Ok(TableType { + element_type: table_ty.element_type.try_into()?, + minimum: table_ty.initial, + maximum: table_ty.maximum, + }) + } +} diff --git a/third_party/rust/wasm-encoder/src/core/tags.rs b/third_party/rust/wasm-encoder/src/core/tags.rs new file mode 100644 index 0000000000..9b4c728a8c --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/tags.rs @@ -0,0 +1,104 @@ +use 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<u8>, + 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<u8>) { + 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, +} + +#[cfg(feature = "wasmparser")] +impl From<wasmparser::TagKind> for TagKind { + fn from(kind: wasmparser::TagKind) -> Self { + match kind { + wasmparser::TagKind::Exception => TagKind::Exception, + } + } +} + +/// 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<u8>) { + sink.push(self.kind as u8); + self.func_type_idx.encode(sink); + } +} + +#[cfg(feature = "wasmparser")] +impl From<wasmparser::TagType> for TagType { + fn from(tag_ty: wasmparser::TagType) -> Self { + TagType { + kind: tag_ty.kind.into(), + func_type_idx: tag_ty.func_type_idx, + } + } +} diff --git a/third_party/rust/wasm-encoder/src/core/types.rs b/third_party/rust/wasm-encoder/src/core/types.rs new file mode 100644 index 0000000000..bfc54ae1e3 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/types.rs @@ -0,0 +1,673 @@ +use 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<u32>, + /// The composite type of the subtype. + pub composite_type: CompositeType, +} + +impl Encode for SubType { + fn encode(&self, sink: &mut Vec<u8>) { + // 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); + } +} + +#[cfg(feature = "wasmparser")] +impl TryFrom<wasmparser::SubType> for SubType { + type Error = (); + + fn try_from(sub_ty: wasmparser::SubType) -> Result<Self, Self::Error> { + Ok(SubType { + is_final: sub_ty.is_final, + supertype_idx: sub_ty + .supertype_idx + .map(|i| i.as_module_index().ok_or(())) + .transpose()?, + composite_type: sub_ty.composite_type.try_into()?, + }) + } +} + +/// Represents a composite type in a WebAssembly module. +#[derive(Debug, Clone)] +pub enum CompositeType { + /// The type is for a function. + Func(FuncType), + /// The type is for an array. + Array(ArrayType), + /// The type is for a struct. + Struct(StructType), +} + +impl Encode for CompositeType { + fn encode(&self, sink: &mut Vec<u8>) { + match self { + CompositeType::Func(ty) => TypeSection::encode_function( + sink, + ty.params().iter().copied(), + ty.results().iter().copied(), + ), + CompositeType::Array(ArrayType(ty)) => { + TypeSection::encode_array(sink, &ty.element_type, ty.mutable) + } + CompositeType::Struct(ty) => { + TypeSection::encode_struct(sink, ty.fields.iter().cloned()) + } + } + } +} + +#[cfg(feature = "wasmparser")] +impl TryFrom<wasmparser::CompositeType> for CompositeType { + type Error = (); + fn try_from(composite_ty: wasmparser::CompositeType) -> Result<Self, Self::Error> { + Ok(match composite_ty { + wasmparser::CompositeType::Func(f) => CompositeType::Func(f.try_into()?), + wasmparser::CompositeType::Array(a) => CompositeType::Array(a.try_into()?), + wasmparser::CompositeType::Struct(s) => CompositeType::Struct(s.try_into()?), + }) + } +} + +/// 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, +} + +#[cfg(feature = "wasmparser")] +impl TryFrom<wasmparser::FuncType> for FuncType { + type Error = (); + fn try_from(func_ty: wasmparser::FuncType) -> Result<Self, Self::Error> { + 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(ty.try_into()?); + } + Ok(FuncType::from_parts(buf.into(), func_ty.params().len())) + } +} + +/// Represents a type of an array in a WebAssembly module. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub struct ArrayType(pub FieldType); + +#[cfg(feature = "wasmparser")] +impl TryFrom<wasmparser::ArrayType> for ArrayType { + type Error = (); + fn try_from(array_ty: wasmparser::ArrayType) -> Result<Self, Self::Error> { + Ok(ArrayType(array_ty.0.try_into()?)) + } +} + +/// 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]>, +} + +#[cfg(feature = "wasmparser")] +impl TryFrom<wasmparser::StructType> for StructType { + type Error = (); + fn try_from(struct_ty: wasmparser::StructType) -> Result<Self, Self::Error> { + Ok(StructType { + fields: struct_ty + .fields + .iter() + .cloned() + .map(TryInto::try_into) + .collect::<Result<_, _>>()?, + }) + } +} + +/// 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, +} + +#[cfg(feature = "wasmparser")] +impl TryFrom<wasmparser::FieldType> for FieldType { + type Error = (); + fn try_from(field_ty: wasmparser::FieldType) -> Result<Self, Self::Error> { + Ok(FieldType { + element_type: field_ty.element_type.try_into()?, + mutable: field_ty.mutable, + }) + } +} + +/// 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), +} + +#[cfg(feature = "wasmparser")] +impl TryFrom<wasmparser::StorageType> for StorageType { + type Error = (); + fn try_from(storage_ty: wasmparser::StorageType) -> Result<Self, Self::Error> { + Ok(match storage_ty { + wasmparser::StorageType::I8 => StorageType::I8, + wasmparser::StorageType::I16 => StorageType::I16, + wasmparser::StorageType::Val(v) => StorageType::Val(v.try_into()?), + }) + } +} + +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), +} + +#[cfg(feature = "wasmparser")] +impl TryFrom<wasmparser::ValType> for ValType { + type Error = (); + fn try_from(val_ty: wasmparser::ValType) -> Result<Self, Self::Error> { + Ok(match val_ty { + wasmparser::ValType::I32 => ValType::I32, + wasmparser::ValType::I64 => ValType::I64, + wasmparser::ValType::F32 => ValType::F32, + wasmparser::ValType::F64 => ValType::F64, + wasmparser::ValType::V128 => ValType::V128, + wasmparser::ValType::Ref(r) => ValType::Ref(r.try_into()?), + }) + } +} + +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<P, R>(params: P, results: R) -> Self + where + P: IntoIterator<Item = ValType>, + R: IntoIterator<Item = ValType>, + { + let mut buffer = params.into_iter().collect::<Vec<_>>(); + 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<u8>) { + 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<u8>) { + 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 `funcref` type in WebAssembly + pub const FUNCREF: RefType = RefType { + nullable: true, + heap_type: HeapType::Func, + }; + + /// Alias for the `externref` type in WebAssembly + pub const EXTERNREF: RefType = RefType { + nullable: true, + heap_type: HeapType::Extern, + }; + + /// Alias for the `exnref` type in WebAssembly + pub const EXNREF: RefType = RefType { + nullable: true, + heap_type: HeapType::Exn, + }; +} + +impl Encode for RefType { + fn encode(&self, sink: &mut Vec<u8>) { + if self.nullable { + // Favor the original encodings of `funcref` and `externref` where + // possible + match self.heap_type { + HeapType::Func => return sink.push(0x70), + HeapType::Extern => return sink.push(0x6f), + _ => {} + } + } + + if self.nullable { + sink.push(0x63); + } else { + sink.push(0x64); + } + self.heap_type.encode(sink); + } +} + +#[cfg(feature = "wasmparser")] +impl TryFrom<wasmparser::RefType> for RefType { + type Error = (); + + fn try_from(ref_type: wasmparser::RefType) -> Result<Self, Self::Error> { + Ok(RefType { + nullable: ref_type.is_nullable(), + heap_type: ref_type.heap_type().try_into()?, + }) + } +} + +impl From<RefType> 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 { + /// 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, + + /// A concrete Wasm-defined type at the given index. + Concrete(u32), +} + +impl Encode for HeapType { + fn encode(&self, sink: &mut Vec<u8>) { + match self { + HeapType::Func => sink.push(0x70), + HeapType::Extern => sink.push(0x6F), + HeapType::Any => sink.push(0x6E), + HeapType::None => sink.push(0x71), + HeapType::NoExtern => sink.push(0x72), + HeapType::NoFunc => sink.push(0x73), + HeapType::Eq => sink.push(0x6D), + HeapType::Struct => sink.push(0x6B), + HeapType::Array => sink.push(0x6A), + HeapType::I31 => sink.push(0x6C), + HeapType::Exn => sink.push(0x69), + // 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), + } + } +} + +#[cfg(feature = "wasmparser")] +impl TryFrom<wasmparser::HeapType> for HeapType { + type Error = (); + + fn try_from(heap_type: wasmparser::HeapType) -> Result<Self, Self::Error> { + Ok(match heap_type { + wasmparser::HeapType::Concrete(i) => HeapType::Concrete(i.as_module_index().ok_or(())?), + wasmparser::HeapType::Func => HeapType::Func, + wasmparser::HeapType::Extern => HeapType::Extern, + wasmparser::HeapType::Any => HeapType::Any, + wasmparser::HeapType::None => HeapType::None, + wasmparser::HeapType::NoExtern => HeapType::NoExtern, + wasmparser::HeapType::NoFunc => HeapType::NoFunc, + wasmparser::HeapType::Eq => HeapType::Eq, + wasmparser::HeapType::Struct => HeapType::Struct, + wasmparser::HeapType::Array => HeapType::Array, + wasmparser::HeapType::I31 => HeapType::I31, + wasmparser::HeapType::Exn => HeapType::Exn, + }) + } +} + +/// 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<u8>, + 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<P, R>(&mut self, params: P, results: R) -> &mut Self + where + P: IntoIterator<Item = ValType>, + P::IntoIter: ExactSizeIterator, + R: IntoIterator<Item = ValType>, + R::IntoIter: ExactSizeIterator, + { + Self::encode_function(&mut self.bytes, params, results); + self.num_added += 1; + self + } + + fn encode_function<P, R>(sink: &mut Vec<u8>, params: P, results: R) + where + P: IntoIterator<Item = ValType>, + P::IntoIter: ExactSizeIterator, + R: IntoIterator<Item = ValType>, + 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<u8>, ty: &StorageType, mutable: bool) { + sink.push(0x5e); + Self::encode_field(sink, ty, mutable); + } + + fn encode_field(sink: &mut Vec<u8>, ty: &StorageType, mutable: bool) { + ty.encode(sink); + sink.push(mutable as u8); + } + + /// Define a struct type in this type section. + pub fn struct_<F>(&mut self, fields: F) -> &mut Self + where + F: IntoIterator<Item = FieldType>, + F::IntoIter: ExactSizeIterator, + { + Self::encode_struct(&mut self.bytes, fields); + self.num_added += 1; + self + } + + fn encode_struct<F>(sink: &mut Vec<u8>, fields: F) + where + F: IntoIterator<Item = FieldType>, + 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<T>(&mut self, types: T) -> &mut Self + where + T: IntoIterator<Item = SubType>, + 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<u8>) { + 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; + + #[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::Func(FuncType::new([], [])), + }); + + let mut module = Module::new(); + module.section(&types); + let wasm_bytes = module.finish(); + + let mut validator = wasmparser::Validator::new_with_features(wasmparser::WasmFeatures { + gc: false, + ..Default::default() + }); + + validator.validate_all(&wasm_bytes).expect( + "Encoding pre Wasm GC type should not accidentally use Wasm GC specific encoding", + ); + } +} diff --git a/third_party/rust/wasm-encoder/src/lib.rs b/third_party/rust/wasm-encoder/src/lib.rs new file mode 100644 index 0000000000..930c63ec9d --- /dev/null +++ b/third_party/rust/wasm-encoder/src/lib.rs @@ -0,0 +1,215 @@ +//! 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()); +//! ``` + +#![deny(missing_docs, missing_debug_implementations)] + +mod component; +mod core; +mod raw; + +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<u8>); +} + +impl<T: Encode + ?Sized> Encode for &'_ T { + fn encode(&self, sink: &mut Vec<u8>) { + T::encode(self, sink) + } +} + +impl<T: Encode> Encode for [T] { + fn encode(&self, sink: &mut Vec<u8>) { + self.len().encode(sink); + for item in self { + item.encode(sink); + } + } +} + +impl Encode for [u8] { + fn encode(&self, sink: &mut Vec<u8>) { + self.len().encode(sink); + sink.extend(self); + } +} + +impl Encode for str { + fn encode(&self, sink: &mut Vec<u8>) { + self.len().encode(sink); + sink.extend_from_slice(self.as_bytes()); + } +} + +impl Encode for usize { + fn encode(&self, sink: &mut Vec<u8>) { + assert!(*self <= u32::max_value() as usize); + (*self as u32).encode(sink) + } +} + +impl Encode for u32 { + fn encode(&self, sink: &mut Vec<u8>) { + leb128::write::unsigned(sink, (*self).into()).unwrap(); + } +} + +impl Encode for i32 { + fn encode(&self, sink: &mut Vec<u8>) { + leb128::write::signed(sink, (*self).into()).unwrap(); + } +} + +impl Encode for u64 { + fn encode(&self, sink: &mut Vec<u8>) { + leb128::write::unsigned(sink, *self).unwrap(); + } +} + +impl Encode for i64 { + fn encode(&self, sink: &mut Vec<u8>) { + leb128::write::signed(sink, *self).unwrap(); + } +} + +impl Encode for f32 { + fn encode(&self, sink: &mut Vec<u8>) { + let bits = self.to_bits(); + sink.extend(bits.to_le_bytes()) + } +} + +impl Encode for f64 { + fn encode(&self, sink: &mut Vec<u8>) { + let bits = self.to_bits(); + sink.extend(bits.to_le_bytes()) + } +} + +fn encode_vec<T, V>(elements: V, sink: &mut Vec<u8>) +where + T: Encode, + V: IntoIterator<Item = T>, + V::IntoIter: ExactSizeIterator, +{ + let elements = elements.into_iter(); + u32::try_from(elements.len()).unwrap().encode(sink); + for x in elements { + x.encode(sink); + } +} + +impl<T> Encode for Option<T> +where + T: Encode, +{ + fn encode(&self, sink: &mut Vec<u8>) { + 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<u8>, 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]); + } +} diff --git a/third_party/rust/wasm-encoder/src/raw.rs b/third_party/rust/wasm-encoder/src/raw.rs new file mode 100644 index 0000000000..a1323ca88e --- /dev/null +++ b/third_party/rust/wasm-encoder/src/raw.rs @@ -0,0 +1,30 @@ +use 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<u8>) { + self.data.encode(sink); + } +} + +impl Section for RawSection<'_> { + fn id(&self) -> u8 { + self.id + } +} + +impl ComponentSection for RawSection<'_> { + fn id(&self) -> u8 { + self.id + } +} |