diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/wasm-encoder/src | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/wasm-encoder/src')
30 files changed, 7264 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..5f92a91f77 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component.rs @@ -0,0 +1,160 @@ +mod aliases; +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::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}; + +// 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 + 0x0c, 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 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/canonicals.rs b/third_party/rust/wasm-encoder/src/component/canonicals.rs new file mode 100644 index 0000000000..e81819c44e --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/canonicals.rs @@ -0,0 +1,133 @@ +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 + } +} + +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..9720d51b02 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/exports.rs @@ -0,0 +1,125 @@ +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, + url: &str, + kind: ComponentExportKind, + index: u32, + ty: Option<ComponentTypeRef>, + ) -> &mut Self { + name.encode(&mut self.bytes); + url.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..8d843407f3 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/imports.rs @@ -0,0 +1,151 @@ +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. + Eq, +} + +impl Encode for TypeBounds { + fn encode(&self, sink: &mut Vec<u8>) { + match self { + Self::Eq => sink.push(0x00), + } + } +} + +/// 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. + /// + /// The index is expected to be a type index. + Type(TypeBounds, u32), + /// 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, idx) => { + bounds.encode(sink); + idx.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, url: &str, ty: ComponentTypeRef) -> &mut Self { + name.encode(&mut self.bytes); + url.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() + } +} 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..5f2c97dec3 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/instances.rs @@ -0,0 +1,199 @@ +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 { + 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..0e3b02dc2e --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/names.rs @@ -0,0 +1,147 @@ +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", + data: &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..930467d57a --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/types.rs @@ -0,0 +1,736 @@ +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 { + self.bytes.push(0x00); + module.encode(&mut self.bytes); + name.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Define a type in this module type. + /// + /// The returned encoder must be used before adding another definition. + #[must_use = "the encoder must be used to encode the type"] + pub fn ty(&mut self) -> CoreTypeEncoder { + self.bytes.push(0x01); + self.num_added += 1; + self.types_added += 1; + CoreTypeEncoder(&mut self.bytes) + } + + /// Defines an outer core type alias in this module type. + pub fn alias_outer_core_type(&mut self, count: u32, index: u32) -> &mut Self { + self.bytes.push(0x02); + self.bytes.push(CORE_TYPE_SORT); + self.bytes.push(0x01); // outer + count.encode(&mut self.bytes); + index.encode(&mut self.bytes); + self.num_added += 1; + self.types_added += 1; + self + } + + /// Defines an export in this module type. + pub fn export(&mut self, name: &str, ty: EntityType) -> &mut Self { + self.bytes.push(0x03); + name.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Gets the number of types that have been added to this module type. + pub fn type_count(&self) -> u32 { + self.types_added + } +} + +impl Encode for ModuleType { + fn encode(&self, sink: &mut Vec<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, +} + +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, + _ => {} + } + self + } + + /// Defines an import in this component type. + pub fn import(&mut self, name: &str, url: &str, ty: ComponentTypeRef) -> &mut Self { + self.bytes.push(0x03); + name.encode(&mut self.bytes); + url.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + match ty { + ComponentTypeRef::Type(..) => self.types_added += 1, + _ => {} + } + self + } + + /// Defines an export in this component type. + pub fn export(&mut self, name: &str, url: &str, ty: ComponentTypeRef) -> &mut Self { + self.bytes.push(0x04); + name.encode(&mut self.bytes); + url.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + match ty { + ComponentTypeRef::Type(..) => self.types_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 + } +} + +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, url: &str, ty: ComponentTypeRef) -> &mut Self { + self.0.export(name, url, 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 + } + + /// 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) + } +} + +/// 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, + }); + } +} + +/// 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 a union type. + pub fn union<I, T>(self, types: I) + where + I: IntoIterator<Item = T>, + I::IntoIter: ExactSizeIterator, + T: Into<ComponentValType>, + { + let types = types.into_iter(); + self.0.push(0x6C); + types.len().encode(self.0); + for ty in types { + ty.into().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); + } +} + +/// 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() + } +} + +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..dcf4d6fb74 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core.rs @@ -0,0 +1,166 @@ +mod code; +mod custom; +mod data; +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 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..641231d04f --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/code.rs @@ -0,0 +1,2894 @@ +use crate::{encode_section, Encode, HeapType, 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, + Try(BlockType), + Delegate(u32), + Catch(u32), + CatchAll, + End, + Br(u32), + BrIf(u32), + BrTable(Cow<'a, [u32]>, u32), + BrOnNull(u32), + BrOnNonNull(u32), + Return, + Call(u32), + CallRef(HeapType), + CallIndirect { ty: u32, table: u32 }, + ReturnCallRef(HeapType), + ReturnCall(u32), + ReturnCallIndirect { ty: u32, table: u32 }, + Throw(u32), + 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), + RefAsNonNull, + + // 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::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(0xD4); + 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); + } + + // 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::RefAsNonNull => sink.push(0xD3), + + // 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); + } + } + } +} + +/// 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); + } +} + +#[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..47d78d458c --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/custom.rs @@ -0,0 +1,53 @@ +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: &'a str, + /// This custom section's data. + pub data: &'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() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_custom_section() { + let custom = CustomSection { + name: "test", + data: &[11, 22, 33, 44], + }; + + let mut encoded = vec![]; + custom.encode(&mut encoded); + + #[rustfmt::skip] + assert_eq!(encoded, vec![ + // LEB128 length of section. + 9, + // LEB128 length of name. + 4, + // Name. + b't', b'e', b's', b't', + // Data. + 11, 22, 33, 44, + ]); + } +} 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/elements.rs b/third_party/rust/wasm-encoder/src/core/elements.rs new file mode 100644 index 0000000000..3325c3d429 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/elements.rs @@ -0,0 +1,227 @@ +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 element_type = RefType::FUNCREF; +/// let functions = Elements::Functions(&[ +/// // Function indices... +/// ]); +/// elements.active(Some(table_index), &offset, element_type, functions); +/// +/// let mut module = Module::new(); +/// module +/// .section(&tables) +/// .section(&elements); +/// +/// let wasm_bytes = module.finish(); +/// ``` +#[derive(Clone, 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(&'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>, + /// The element segment's type. + pub element_type: RefType, + /// 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, + }; + match &segment.mode { + ElementMode::Active { + table: None, + offset, + } => { + (/* 0x00 | */expr_bit).encode(&mut self.bytes); + offset.encode(&mut self.bytes); + } + ElementMode::Passive => { + (0x01 | expr_bit).encode(&mut self.bytes); + if expr_bit == 0 { + self.bytes.push(0x00); // elemkind == funcref + } else { + segment.element_type.encode(&mut self.bytes); + } + } + ElementMode::Active { + table: Some(i), + offset, + } => { + (0x02 | expr_bit).encode(&mut self.bytes); + i.encode(&mut self.bytes); + offset.encode(&mut self.bytes); + if expr_bit == 0 { + self.bytes.push(0x00); // elemkind == funcref + } else { + segment.element_type.encode(&mut self.bytes); + } + } + ElementMode::Declared => { + (0x03 | expr_bit).encode(&mut self.bytes); + if expr_bit == 0 { + self.bytes.push(0x00); // elemkind == funcref + } else { + segment.element_type.encode(&mut self.bytes); + } + } + } + + match segment.elements { + Elements::Functions(fs) => { + fs.encode(&mut self.bytes); + } + Elements::Expressions(e) => { + 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, + element_type: RefType, + elements: Elements<'_>, + ) -> &mut Self { + self.segment(ElementSegment { + mode: ElementMode::Active { + table: table_index, + offset, + }, + element_type, + elements, + }) + } + + /// Encode a passive element segment. + /// + /// Passive segments are part of the bulk memory proposal. + pub fn passive<'a>(&mut self, element_type: RefType, elements: Elements<'a>) -> &mut Self { + self.segment(ElementSegment { + mode: ElementMode::Passive, + element_type, + elements, + }) + } + + /// Encode a declared element segment. + /// + /// Declared segments are part of the bulk memory proposal. + pub fn declared<'a>(&mut self, element_type: RefType, elements: Elements<'a>) -> &mut Self { + self.segment(ElementSegment { + mode: ElementMode::Declared, + element_type, + 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..36c7896362 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/exports.rs @@ -0,0 +1,85 @@ +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); + } +} + +/// 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..16f23c2891 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/globals.rs @@ -0,0 +1,90 @@ +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); + } +} 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..455170f227 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/imports.rs @@ -0,0 +1,142 @@ +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) + } +} + +/// 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..3309277be3 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/linking.rs @@ -0,0 +1,261 @@ +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", + data: &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..c651768bdc --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/memories.rs @@ -0,0 +1,99 @@ +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); + } + } +} 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..a1c31506fd --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/names.rs @@ -0,0 +1,263 @@ +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, +} + +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 the + /// 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 the + /// 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). + pub fn data(&mut self, names: &NameMap) { + self.subsection_header(Subsection::Data, 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", + data: &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..ace908a7bd --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/producers.rs @@ -0,0 +1,178 @@ +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", + data: &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..cbb2048a64 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/tables.rs @@ -0,0 +1,104 @@ +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); + } + } +} 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..413055f2af --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/tags.rs @@ -0,0 +1,85 @@ +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, +} + +/// 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); + } +} 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..d21dbbc960 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/types.rs @@ -0,0 +1,191 @@ +use crate::{encode_section, Encode, Section, SectionId}; + +/// The type of a core WebAssembly value. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] +pub enum ValType { + /// The `i32` type. + I32, + /// The `i64` type. + I64, + /// The `f32` type. + F32, + /// The `f64` type. + F64, + /// The `v128` type. + /// + /// Part of the SIMD proposal. + V128, + /// A reference type. + /// + /// The `funcref` and `externref` type fall into this category and the full + /// generalization here is due to the implementation of the + /// function-references proposal. + Ref(RefType), +} + +impl ValType { + /// 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); +} + +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, + }; +} + +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(0x6C); + } else { + sink.push(0x6B); + } + self.heap_type.encode(sink); + } +} + +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 { + /// A function reference. When nullable, equivalent to `funcref` + Func, + /// An extern reference. When nullable, equivalent to `externref` + Extern, + /// A reference to a particular index in a table. + TypedFunc(u32), +} + +impl Encode for HeapType { + fn encode(&self, sink: &mut Vec<u8>) { + match self { + HeapType::Func => sink.push(0x70), + HeapType::Extern => sink.push(0x6F), + // Note that this is encoded as a signed type rather than unsigned + // as it's decoded as an s33 + HeapType::TypedFunc(i) => i64::from(*i).encode(sink), + } + } +} + +/// 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, + { + let params = params.into_iter(); + let results = results.into_iter(); + + self.bytes.push(0x60); + params.len().encode(&mut self.bytes); + params.for_each(|p| p.encode(&mut self.bytes)); + results.len().encode(&mut self.bytes); + results.for_each(|p| p.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() + } +} 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..3f36562508 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/lib.rs @@ -0,0 +1,188 @@ +//! 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<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', 0x0c, 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 + } +} |