summaryrefslogtreecommitdiffstats
path: root/third_party/rust/wasm-encoder/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/wasm-encoder/src
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/wasm-encoder/src')
-rw-r--r--third_party/rust/wasm-encoder/src/component.rs168
-rw-r--r--third_party/rust/wasm-encoder/src/component/aliases.rs160
-rw-r--r--third_party/rust/wasm-encoder/src/component/builder.rs455
-rw-r--r--third_party/rust/wasm-encoder/src/component/canonicals.rs159
-rw-r--r--third_party/rust/wasm-encoder/src/component/components.rs29
-rw-r--r--third_party/rust/wasm-encoder/src/component/exports.rs124
-rw-r--r--third_party/rust/wasm-encoder/src/component/imports.rs175
-rw-r--r--third_party/rust/wasm-encoder/src/component/instances.rs200
-rw-r--r--third_party/rust/wasm-encoder/src/component/modules.rs29
-rw-r--r--third_party/rust/wasm-encoder/src/component/names.rs149
-rw-r--r--third_party/rust/wasm-encoder/src/component/start.rs52
-rw-r--r--third_party/rust/wasm-encoder/src/component/types.rs792
-rw-r--r--third_party/rust/wasm-encoder/src/core.rs168
-rw-r--r--third_party/rust/wasm-encoder/src/core/code.rs3355
-rw-r--r--third_party/rust/wasm-encoder/src/core/custom.rs73
-rw-r--r--third_party/rust/wasm-encoder/src/core/data.rs185
-rw-r--r--third_party/rust/wasm-encoder/src/core/dump.rs627
-rw-r--r--third_party/rust/wasm-encoder/src/core/elements.rs220
-rw-r--r--third_party/rust/wasm-encoder/src/core/exports.rs98
-rw-r--r--third_party/rust/wasm-encoder/src/core/functions.rs63
-rw-r--r--third_party/rust/wasm-encoder/src/core/globals.rs101
-rw-r--r--third_party/rust/wasm-encoder/src/core/imports.rs156
-rw-r--r--third_party/rust/wasm-encoder/src/core/linking.rs263
-rw-r--r--third_party/rust/wasm-encoder/src/core/memories.rs111
-rw-r--r--third_party/rust/wasm-encoder/src/core/names.rs298
-rw-r--r--third_party/rust/wasm-encoder/src/core/producers.rs180
-rw-r--r--third_party/rust/wasm-encoder/src/core/start.rs39
-rw-r--r--third_party/rust/wasm-encoder/src/core/tables.rs116
-rw-r--r--third_party/rust/wasm-encoder/src/core/tags.rs104
-rw-r--r--third_party/rust/wasm-encoder/src/core/types.rs673
-rw-r--r--third_party/rust/wasm-encoder/src/lib.rs215
-rw-r--r--third_party/rust/wasm-encoder/src/raw.rs30
32 files changed, 9567 insertions, 0 deletions
diff --git a/third_party/rust/wasm-encoder/src/component.rs b/third_party/rust/wasm-encoder/src/component.rs
new file mode 100644
index 0000000000..e3f36a88a2
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/component.rs
@@ -0,0 +1,168 @@
+mod aliases;
+mod builder;
+mod canonicals;
+mod components;
+mod exports;
+mod imports;
+mod instances;
+mod modules;
+mod names;
+mod start;
+mod types;
+
+pub use self::aliases::*;
+pub use self::builder::*;
+pub use self::canonicals::*;
+pub use self::components::*;
+pub use self::exports::*;
+pub use self::imports::*;
+pub use self::instances::*;
+pub use self::modules::*;
+pub use self::names::*;
+pub use self::start::*;
+pub use self::types::*;
+
+use crate::{CustomSection, Encode, ProducersSection, RawCustomSection};
+
+// Core sorts extended by the component model
+const CORE_TYPE_SORT: u8 = 0x10;
+const CORE_MODULE_SORT: u8 = 0x11;
+const CORE_INSTANCE_SORT: u8 = 0x12;
+
+const CORE_SORT: u8 = 0x00;
+const FUNCTION_SORT: u8 = 0x01;
+const VALUE_SORT: u8 = 0x02;
+const TYPE_SORT: u8 = 0x03;
+const COMPONENT_SORT: u8 = 0x04;
+const INSTANCE_SORT: u8 = 0x05;
+
+/// A WebAssembly component section.
+///
+/// Various builders defined in this crate already implement this trait, but you
+/// can also implement it yourself for your own custom section builders, or use
+/// `RawSection` to use a bunch of raw bytes as a section.
+pub trait ComponentSection: Encode {
+ /// Gets the section identifier for this section.
+ fn id(&self) -> u8;
+
+ /// Appends this section to the specified destination list of bytes.
+ fn append_to_component(&self, dst: &mut Vec<u8>) {
+ dst.push(self.id());
+ self.encode(dst);
+ }
+}
+
+/// Known section identifiers of WebAssembly components.
+///
+/// These sections are supported by the component model proposal.
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
+#[repr(u8)]
+pub enum ComponentSectionId {
+ /// The section is a core custom section.
+ CoreCustom = 0,
+ /// The section is a core module section.
+ CoreModule = 1,
+ /// The section is a core instance section.
+ CoreInstance = 2,
+ /// The section is a core type section.
+ CoreType = 3,
+ /// The section is a component section.
+ Component = 4,
+ /// The section is an instance section.
+ Instance = 5,
+ /// The section is an alias section.
+ Alias = 6,
+ /// The section is a type section.
+ Type = 7,
+ /// The section is a canonical function section.
+ CanonicalFunction = 8,
+ /// The section is a start section.
+ Start = 9,
+ /// The section is an import section.
+ Import = 10,
+ /// The section is an export section.
+ Export = 11,
+}
+
+impl From<ComponentSectionId> for u8 {
+ #[inline]
+ fn from(id: ComponentSectionId) -> u8 {
+ id as u8
+ }
+}
+
+impl Encode for ComponentSectionId {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ sink.push(*self as u8);
+ }
+}
+
+/// Represents a WebAssembly component that is being encoded.
+///
+/// Unlike core WebAssembly modules, the sections of a component
+/// may appear in any order and may be repeated.
+///
+/// Components may also added as a section to other components.
+#[derive(Clone, Debug)]
+pub struct Component {
+ bytes: Vec<u8>,
+}
+
+impl Component {
+ /// The 8-byte header at the beginning of all components.
+ #[rustfmt::skip]
+ pub const HEADER: [u8; 8] = [
+ // Magic
+ 0x00, 0x61, 0x73, 0x6D,
+ // Version
+ 0x0d, 0x00, 0x01, 0x00,
+ ];
+
+ /// Begin writing a new `Component`.
+ pub fn new() -> Self {
+ Self {
+ bytes: Self::HEADER.to_vec(),
+ }
+ }
+
+ /// Finish writing this component and extract ownership of the encoded bytes.
+ pub fn finish(self) -> Vec<u8> {
+ self.bytes
+ }
+
+ /// Write a section to this component.
+ pub fn section(&mut self, section: &impl ComponentSection) -> &mut Self {
+ self.bytes.push(section.id());
+ section.encode(&mut self.bytes);
+ self
+ }
+
+ /// View the encoded bytes.
+ pub fn as_slice(&self) -> &[u8] {
+ &self.bytes
+ }
+}
+
+impl Default for Component {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl ComponentSection for CustomSection<'_> {
+ fn id(&self) -> u8 {
+ ComponentSectionId::CoreCustom.into()
+ }
+}
+
+impl ComponentSection for RawCustomSection<'_> {
+ fn id(&self) -> u8 {
+ ComponentSectionId::CoreCustom.into()
+ }
+}
+
+impl ComponentSection for ProducersSection {
+ fn id(&self) -> u8 {
+ ComponentSectionId::CoreCustom.into()
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/component/aliases.rs b/third_party/rust/wasm-encoder/src/component/aliases.rs
new file mode 100644
index 0000000000..1e317fb0e2
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/component/aliases.rs
@@ -0,0 +1,160 @@
+use super::{COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, CORE_TYPE_SORT, TYPE_SORT};
+use crate::{
+ encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind,
+};
+
+/// Represents the kinds of outer aliasable items in a component.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum ComponentOuterAliasKind {
+ /// The alias is to a core module.
+ CoreModule,
+ /// The alias is to a core type.
+ CoreType,
+ /// The alias is to a type.
+ Type,
+ /// The alias is to a component.
+ Component,
+}
+
+impl Encode for ComponentOuterAliasKind {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ match self {
+ Self::CoreModule => {
+ sink.push(CORE_SORT);
+ sink.push(CORE_MODULE_SORT);
+ }
+ Self::CoreType => {
+ sink.push(CORE_SORT);
+ sink.push(CORE_TYPE_SORT);
+ }
+ Self::Type => sink.push(TYPE_SORT),
+ Self::Component => sink.push(COMPONENT_SORT),
+ }
+ }
+}
+
+/// An encoder for the alias section of WebAssembly component.
+///
+/// # Example
+///
+/// ```rust
+/// use wasm_encoder::{Component, Alias, ComponentAliasSection, ComponentExportKind, ComponentOuterAliasKind};
+///
+/// let mut aliases = ComponentAliasSection::new();
+/// aliases.alias(Alias::InstanceExport { instance: 0, kind: ComponentExportKind::Func, name: "f" });
+/// aliases.alias(Alias::Outer { count: 0, kind: ComponentOuterAliasKind::Type, index: 1 });
+///
+/// let mut component = Component::new();
+/// component.section(&aliases);
+///
+/// let bytes = component.finish();
+/// ```
+#[derive(Clone, Debug, Default)]
+pub struct ComponentAliasSection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+/// Different forms of aliases that can be inserted into a
+/// [`ComponentAliasSection`].
+#[derive(Copy, Clone, Debug)]
+pub enum Alias<'a> {
+ /// An alias of a component instance export.
+ InstanceExport {
+ /// The index of the component instance that's being aliased from.
+ instance: u32,
+ /// The kind of item that's being extracted from the component
+ /// instance.
+ kind: ComponentExportKind,
+ /// The name of the export that's being aliased.
+ name: &'a str,
+ },
+ /// Same as `InstanceExport`, but for core instances.
+ #[allow(missing_docs)]
+ CoreInstanceExport {
+ instance: u32,
+ kind: ExportKind,
+ name: &'a str,
+ },
+ /// Aliasing an item from an outer component.
+ Outer {
+ /// The kind of item being aliased, either a type or a component.
+ kind: ComponentOuterAliasKind,
+ /// Number of levels "up" to go to lookup the index within. Level 0 is
+ /// the current scope and level 1 is the enclosing scope, and so on.
+ count: u32,
+ /// The index of the item to alias within the scope referenced by
+ /// `count`.
+ index: u32,
+ },
+}
+
+impl ComponentAliasSection {
+ /// Create a new alias section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of aliases in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Define an alias to a component instance's export.
+ pub fn alias(&mut self, alias: Alias<'_>) -> &mut Self {
+ alias.encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+}
+
+impl Encode for ComponentAliasSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl ComponentSection for ComponentAliasSection {
+ fn id(&self) -> u8 {
+ ComponentSectionId::Alias.into()
+ }
+}
+
+impl Encode for Alias<'_> {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ match self {
+ Alias::InstanceExport {
+ instance,
+ kind,
+ name,
+ } => {
+ kind.encode(sink);
+ sink.push(0x00);
+ instance.encode(sink);
+ name.encode(sink);
+ }
+ Alias::CoreInstanceExport {
+ instance,
+ kind,
+ name,
+ } => {
+ sink.push(CORE_SORT);
+ kind.encode(sink);
+ sink.push(0x01);
+ instance.encode(sink);
+ name.encode(sink);
+ }
+ Alias::Outer { kind, count, index } => {
+ kind.encode(sink);
+ sink.push(0x02);
+ count.encode(sink);
+ index.encode(sink);
+ }
+ }
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/component/builder.rs b/third_party/rust/wasm-encoder/src/component/builder.rs
new file mode 100644
index 0000000000..27c39ac8a0
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/component/builder.rs
@@ -0,0 +1,455 @@
+use crate::component::*;
+use crate::{ExportKind, Module, RawSection, ValType};
+use std::mem;
+
+/// Convenience type to build a component incrementally and automatically keep
+/// track of index spaces.
+///
+/// This type is intended to be a wrapper around the [`Component`] encoding type
+/// which is useful for building it up incrementally over time. This type will
+/// automatically collect definitions into sections and reports the index of all
+/// items added by keeping track of indices internally.
+#[derive(Debug, Default)]
+pub struct ComponentBuilder {
+ /// The binary component that's being built.
+ component: Component,
+
+ /// The last section which was appended to during encoding. This type is
+ /// generated by the `section_accessors` macro below.
+ ///
+ /// When something is encoded this is used if it matches the kind of item
+ /// being encoded, otherwise it's "flushed" to the output component and a
+ /// new section is started.
+ last_section: LastSection,
+
+ // Core index spaces
+ core_modules: u32,
+ core_funcs: u32,
+ core_types: u32,
+ core_memories: u32,
+ core_tables: u32,
+ core_instances: u32,
+ core_tags: u32,
+ core_globals: u32,
+
+ // Component index spaces
+ funcs: u32,
+ instances: u32,
+ types: u32,
+ components: u32,
+ values: u32,
+}
+
+impl ComponentBuilder {
+ /// Returns the current number of core modules.
+ pub fn core_module_count(&self) -> u32 {
+ self.core_modules
+ }
+
+ /// Returns the current number of core funcs.
+ pub fn core_func_count(&self) -> u32 {
+ self.core_funcs
+ }
+
+ /// Returns the current number of core types.
+ pub fn core_type_count(&self) -> u32 {
+ self.core_types
+ }
+
+ /// Returns the current number of core memories.
+ pub fn core_memory_count(&self) -> u32 {
+ self.core_memories
+ }
+
+ /// Returns the current number of core tables.
+ pub fn core_table_count(&self) -> u32 {
+ self.core_tables
+ }
+
+ /// Returns the current number of core instances.
+ pub fn core_instance_count(&self) -> u32 {
+ self.core_instances
+ }
+
+ /// Returns the current number of core tags.
+ pub fn core_tag_count(&self) -> u32 {
+ self.core_tags
+ }
+
+ /// Returns the current number of core globals.
+ pub fn core_global_count(&self) -> u32 {
+ self.core_globals
+ }
+
+ /// Returns the current number of component funcs.
+ pub fn func_count(&self) -> u32 {
+ self.funcs
+ }
+
+ /// Returns the current number of component instances.
+ pub fn instance_count(&self) -> u32 {
+ self.instances
+ }
+
+ /// Returns the current number of component values.
+ pub fn value_count(&self) -> u32 {
+ self.values
+ }
+
+ /// Returns the current number of components.
+ pub fn component_count(&self) -> u32 {
+ self.components
+ }
+
+ /// Returns the current number of component types.
+ pub fn type_count(&self) -> u32 {
+ self.types
+ }
+
+ /// Completes this component and returns the binary encoding of the entire
+ /// component.
+ pub fn finish(mut self) -> Vec<u8> {
+ self.flush();
+ self.component.finish()
+ }
+
+ /// Encodes a core wasm `Module` into this component, returning its index.
+ pub fn core_module(&mut self, module: &Module) -> u32 {
+ self.flush();
+ self.component.section(&ModuleSection(module));
+ inc(&mut self.core_modules)
+ }
+
+ /// Encodes a core wasm `module` into this component, returning its index.
+ pub fn core_module_raw(&mut self, module: &[u8]) -> u32 {
+ self.flush();
+ self.component.section(&RawSection {
+ id: ComponentSectionId::CoreModule.into(),
+ data: module,
+ });
+ inc(&mut self.core_modules)
+ }
+
+ /// Instantiates a core wasm module at `module_index` with the `args`
+ /// provided.
+ ///
+ /// Returns the index of the core wasm instance crated.
+ pub fn core_instantiate<'a, A>(&mut self, module_index: u32, args: A) -> u32
+ where
+ A: IntoIterator<Item = (&'a str, ModuleArg)>,
+ A::IntoIter: ExactSizeIterator,
+ {
+ self.instances().instantiate(module_index, args);
+ inc(&mut self.core_instances)
+ }
+
+ /// Creates a new core wasm instance from the `exports` provided.
+ ///
+ /// Returns the index of the core wasm instance crated.
+ pub fn core_instantiate_exports<'a, E>(&mut self, exports: E) -> u32
+ where
+ E: IntoIterator<Item = (&'a str, ExportKind, u32)>,
+ E::IntoIter: ExactSizeIterator,
+ {
+ self.instances().export_items(exports);
+ inc(&mut self.core_instances)
+ }
+
+ /// Creates a new aliased item where the core `instance` specified has its
+ /// export `name` aliased out with the `kind` specified.
+ ///
+ /// Returns the index of the item crated.
+ pub fn core_alias_export(&mut self, instance: u32, name: &str, kind: ExportKind) -> u32 {
+ self.alias(Alias::CoreInstanceExport {
+ instance,
+ kind,
+ name,
+ })
+ }
+
+ /// Adds a new alias to this component
+ pub fn alias(&mut self, alias: Alias<'_>) -> u32 {
+ self.aliases().alias(alias);
+ match alias {
+ Alias::InstanceExport { kind, .. } => self.inc_kind(kind),
+ Alias::CoreInstanceExport { kind, .. } => self.inc_core_kind(kind),
+ Alias::Outer {
+ kind: ComponentOuterAliasKind::Type,
+ ..
+ } => inc(&mut self.types),
+ Alias::Outer {
+ kind: ComponentOuterAliasKind::CoreModule,
+ ..
+ } => inc(&mut self.core_modules),
+ Alias::Outer {
+ kind: ComponentOuterAliasKind::Component,
+ ..
+ } => inc(&mut self.components),
+ Alias::Outer {
+ kind: ComponentOuterAliasKind::CoreType,
+ ..
+ } => inc(&mut self.core_types),
+ }
+ }
+
+ /// Creates an alias to a previous component instance's exported item.
+ ///
+ /// The `instance` provided is the instance to access and the `name` is the
+ /// item to access.
+ ///
+ /// Returns the index of the new item defined.
+ pub fn alias_export(&mut self, instance: u32, name: &str, kind: ComponentExportKind) -> u32 {
+ self.alias(Alias::InstanceExport {
+ instance,
+ kind,
+ name,
+ })
+ }
+
+ fn inc_kind(&mut self, kind: ComponentExportKind) -> u32 {
+ match kind {
+ ComponentExportKind::Func => inc(&mut self.funcs),
+ ComponentExportKind::Module => inc(&mut self.core_modules),
+ ComponentExportKind::Type => inc(&mut self.types),
+ ComponentExportKind::Component => inc(&mut self.components),
+ ComponentExportKind::Instance => inc(&mut self.instances),
+ ComponentExportKind::Value => inc(&mut self.values),
+ }
+ }
+
+ fn inc_core_kind(&mut self, kind: ExportKind) -> u32 {
+ match kind {
+ ExportKind::Func => inc(&mut self.core_funcs),
+ ExportKind::Table => inc(&mut self.core_tables),
+ ExportKind::Memory => inc(&mut self.core_memories),
+ ExportKind::Global => inc(&mut self.core_globals),
+ ExportKind::Tag => inc(&mut self.core_tags),
+ }
+ }
+
+ /// Lowers the `func_index` component function into a core wasm function
+ /// using the `options` provided.
+ ///
+ /// Returns the index of the core wasm function created.
+ pub fn lower_func<O>(&mut self, func_index: u32, options: O) -> u32
+ where
+ O: IntoIterator<Item = CanonicalOption>,
+ O::IntoIter: ExactSizeIterator,
+ {
+ self.canonical_functions().lower(func_index, options);
+ inc(&mut self.core_funcs)
+ }
+
+ /// Lifts the core wasm `core_func_index` function with the component
+ /// function type `type_index` and `options`.
+ ///
+ /// Returns the index of the component function created.
+ pub fn lift_func<O>(&mut self, core_func_index: u32, type_index: u32, options: O) -> u32
+ where
+ O: IntoIterator<Item = CanonicalOption>,
+ O::IntoIter: ExactSizeIterator,
+ {
+ self.canonical_functions()
+ .lift(core_func_index, type_index, options);
+ inc(&mut self.funcs)
+ }
+
+ /// Imports a new item into this component with the `name` and `ty` specified.
+ pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> u32 {
+ let ret = match &ty {
+ ComponentTypeRef::Instance(_) => inc(&mut self.instances),
+ ComponentTypeRef::Func(_) => inc(&mut self.funcs),
+ ComponentTypeRef::Type(..) => inc(&mut self.types),
+ ComponentTypeRef::Component(_) => inc(&mut self.components),
+ ComponentTypeRef::Module(_) => inc(&mut self.core_modules),
+ ComponentTypeRef::Value(_) => inc(&mut self.values),
+ };
+ self.imports().import(name, ty);
+ ret
+ }
+
+ /// Exports a new item from this component with the `name` and `kind`
+ /// specified.
+ ///
+ /// The `idx` is the item to export and the `ty` is an optional type to
+ /// ascribe to the export.
+ pub fn export(
+ &mut self,
+ name: &str,
+ kind: ComponentExportKind,
+ idx: u32,
+ ty: Option<ComponentTypeRef>,
+ ) -> u32 {
+ self.exports().export(name, kind, idx, ty);
+ self.inc_kind(kind)
+ }
+
+ /// Creates a new encoder for the next core type in this component.
+ pub fn core_type(&mut self) -> (u32, CoreTypeEncoder<'_>) {
+ (inc(&mut self.core_types), self.core_types().ty())
+ }
+
+ /// Creates a new encoder for the next type in this component.
+ pub fn ty(&mut self) -> (u32, ComponentTypeEncoder<'_>) {
+ (inc(&mut self.types), self.types().ty())
+ }
+
+ /// Creates a new instance type within this component.
+ pub fn type_instance(&mut self, ty: &InstanceType) -> u32 {
+ self.types().instance(ty);
+ inc(&mut self.types)
+ }
+
+ /// Creates a new component type within this component.
+ pub fn type_component(&mut self, ty: &ComponentType) -> u32 {
+ self.types().component(ty);
+ inc(&mut self.types)
+ }
+
+ /// Creates a new defined component type within this component.
+ pub fn type_defined(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) {
+ (inc(&mut self.types), self.types().defined_type())
+ }
+
+ /// Creates a new component function type within this component.
+ pub fn type_function(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) {
+ (inc(&mut self.types), self.types().function())
+ }
+
+ /// Declares a
+ pub fn type_resource(&mut self, rep: ValType, dtor: Option<u32>) -> u32 {
+ self.types().resource(rep, dtor);
+ inc(&mut self.types)
+ }
+
+ /// Defines a new subcomponent of this component.
+ pub fn component(&mut self, mut builder: ComponentBuilder) -> u32 {
+ builder.flush();
+ self.flush();
+ self.component
+ .section(&NestedComponentSection(&builder.component));
+ inc(&mut self.components)
+ }
+
+ /// Defines a new subcomponent of this component.
+ pub fn component_raw(&mut self, data: &[u8]) -> u32 {
+ let raw_section = RawSection {
+ id: ComponentSectionId::Component.into(),
+ data,
+ };
+ self.flush();
+ self.component.section(&raw_section);
+ inc(&mut self.components)
+ }
+
+ /// Instantiates the `component_index` specified with the `args` specified.
+ pub fn instantiate<A, S>(&mut self, component_index: u32, args: A) -> u32
+ where
+ A: IntoIterator<Item = (S, ComponentExportKind, u32)>,
+ A::IntoIter: ExactSizeIterator,
+ S: AsRef<str>,
+ {
+ self.component_instances()
+ .instantiate(component_index, args);
+ inc(&mut self.instances)
+ }
+
+ /// Declares a new `resource.drop` intrinsic.
+ pub fn resource_drop(&mut self, ty: u32) -> u32 {
+ self.canonical_functions().resource_drop(ty);
+ inc(&mut self.core_funcs)
+ }
+
+ /// Declares a new `resource.new` intrinsic.
+ pub fn resource_new(&mut self, ty: u32) -> u32 {
+ self.canonical_functions().resource_new(ty);
+ inc(&mut self.core_funcs)
+ }
+
+ /// Declares a new `resource.rep` intrinsic.
+ pub fn resource_rep(&mut self, ty: u32) -> u32 {
+ self.canonical_functions().resource_rep(ty);
+ inc(&mut self.core_funcs)
+ }
+
+ /// Adds a new custom section to this component.
+ pub fn custom_section(&mut self, section: &CustomSection<'_>) {
+ self.flush();
+ self.component.section(section);
+ }
+
+ /// Adds a new custom section to this component.
+ pub fn raw_custom_section(&mut self, section: &[u8]) {
+ self.flush();
+ self.component.section(&RawCustomSection(section));
+ }
+}
+
+// Helper macro to generate methods on `ComponentBuilder` to get specific
+// section encoders that automatically flush and write out prior sections as
+// necessary.
+macro_rules! section_accessors {
+ ($($method:ident => $section:ident)*) => (
+ #[derive(Debug, Default)]
+ enum LastSection {
+ #[default]
+ None,
+ $($section($section),)*
+ }
+
+ impl ComponentBuilder {
+ $(
+ fn $method(&mut self) -> &mut $section {
+ match &self.last_section {
+ // The last encoded section matches the section that's
+ // being requested, so no change is necessary.
+ LastSection::$section(_) => {}
+
+ // Otherwise the last section didn't match this section,
+ // so flush any prior section if needed and start
+ // encoding the desired section of this method.
+ _ => {
+ self.flush();
+ self.last_section = LastSection::$section($section::new());
+ }
+ }
+ match &mut self.last_section {
+ LastSection::$section(ret) => ret,
+ _ => unreachable!()
+ }
+ }
+ )*
+
+ /// Writes out the last section into the final component binary if
+ /// there is a section specified, otherwise does nothing.
+ fn flush(&mut self) {
+ match mem::take(&mut self.last_section) {
+ LastSection::None => {}
+ $(
+ LastSection::$section(section) => {
+ self.component.section(&section);
+ }
+ )*
+ }
+ }
+
+ }
+ )
+}
+
+section_accessors! {
+ component_instances => ComponentInstanceSection
+ instances => InstanceSection
+ canonical_functions => CanonicalFunctionSection
+ aliases => ComponentAliasSection
+ exports => ComponentExportSection
+ imports => ComponentImportSection
+ types => ComponentTypeSection
+ core_types => CoreTypeSection
+}
+
+fn inc(idx: &mut u32) -> u32 {
+ let ret = *idx;
+ *idx += 1;
+ ret
+}
diff --git a/third_party/rust/wasm-encoder/src/component/canonicals.rs b/third_party/rust/wasm-encoder/src/component/canonicals.rs
new file mode 100644
index 0000000000..340d9ca621
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/component/canonicals.rs
@@ -0,0 +1,159 @@
+use crate::{encode_section, ComponentSection, ComponentSectionId, Encode};
+
+/// Represents options for canonical function definitions.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum CanonicalOption {
+ /// The string types in the function signature are UTF-8 encoded.
+ UTF8,
+ /// The string types in the function signature are UTF-16 encoded.
+ UTF16,
+ /// The string types in the function signature are compact UTF-16 encoded.
+ CompactUTF16,
+ /// The memory to use if the lifting or lowering of a function requires memory access.
+ ///
+ /// The value is an index to a core memory.
+ Memory(u32),
+ /// The realloc function to use if the lifting or lowering of a function requires memory
+ /// allocation.
+ ///
+ /// The value is an index to a core function of type `(func (param i32 i32 i32 i32) (result i32))`.
+ Realloc(u32),
+ /// The post-return function to use if the lifting of a function requires
+ /// cleanup after the function returns.
+ PostReturn(u32),
+}
+
+impl Encode for CanonicalOption {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ match self {
+ Self::UTF8 => sink.push(0x00),
+ Self::UTF16 => sink.push(0x01),
+ Self::CompactUTF16 => sink.push(0x02),
+ Self::Memory(idx) => {
+ sink.push(0x03);
+ idx.encode(sink);
+ }
+ Self::Realloc(idx) => {
+ sink.push(0x04);
+ idx.encode(sink);
+ }
+ Self::PostReturn(idx) => {
+ sink.push(0x05);
+ idx.encode(sink);
+ }
+ }
+ }
+}
+
+/// An encoder for the canonical function section of WebAssembly components.
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{Component, CanonicalFunctionSection, CanonicalOption};
+///
+/// let mut functions = CanonicalFunctionSection::new();
+/// functions.lift(0, 0, [CanonicalOption::UTF8]);
+///
+/// let mut component = Component::new();
+/// component.section(&functions);
+///
+/// let bytes = component.finish();
+/// ```
+#[derive(Clone, Debug, Default)]
+pub struct CanonicalFunctionSection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+impl CanonicalFunctionSection {
+ /// Construct a new component function section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of functions in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Define a function that will lift a core WebAssembly function to the canonical ABI.
+ pub fn lift<O>(&mut self, core_func_index: u32, type_index: u32, options: O) -> &mut Self
+ where
+ O: IntoIterator<Item = CanonicalOption>,
+ O::IntoIter: ExactSizeIterator,
+ {
+ let options = options.into_iter();
+ self.bytes.push(0x00);
+ self.bytes.push(0x00);
+ core_func_index.encode(&mut self.bytes);
+ options.len().encode(&mut self.bytes);
+ for option in options {
+ option.encode(&mut self.bytes);
+ }
+ type_index.encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+
+ /// Define a function that will lower a canonical ABI function to a core WebAssembly function.
+ pub fn lower<O>(&mut self, func_index: u32, options: O) -> &mut Self
+ where
+ O: IntoIterator<Item = CanonicalOption>,
+ O::IntoIter: ExactSizeIterator,
+ {
+ let options = options.into_iter();
+ self.bytes.push(0x01);
+ self.bytes.push(0x00);
+ func_index.encode(&mut self.bytes);
+ options.len().encode(&mut self.bytes);
+ for option in options {
+ option.encode(&mut self.bytes);
+ }
+ self.num_added += 1;
+ self
+ }
+
+ /// Defines a function which will create an owned handle to the resource
+ /// specified by `ty_index`.
+ pub fn resource_new(&mut self, ty_index: u32) -> &mut Self {
+ self.bytes.push(0x02);
+ ty_index.encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+
+ /// Defines a function which will drop the specified type of handle.
+ pub fn resource_drop(&mut self, ty_index: u32) -> &mut Self {
+ self.bytes.push(0x03);
+ ty_index.encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+
+ /// Defines a function which will return the representation of the specified
+ /// resource type.
+ pub fn resource_rep(&mut self, ty_index: u32) -> &mut Self {
+ self.bytes.push(0x04);
+ ty_index.encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+}
+
+impl Encode for CanonicalFunctionSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl ComponentSection for CanonicalFunctionSection {
+ fn id(&self) -> u8 {
+ ComponentSectionId::CanonicalFunction.into()
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/component/components.rs b/third_party/rust/wasm-encoder/src/component/components.rs
new file mode 100644
index 0000000000..c08645e3b9
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/component/components.rs
@@ -0,0 +1,29 @@
+use crate::{Component, ComponentSection, ComponentSectionId, Encode};
+
+/// An encoder for the component section of WebAssembly components.
+///
+/// # Example
+///
+/// ```rust
+/// use wasm_encoder::{Component, NestedComponentSection};
+///
+/// let mut nested = Component::new();
+/// let mut component = Component::new();
+/// component.section(&NestedComponentSection(&nested));
+///
+/// let bytes = component.finish();
+/// ```
+#[derive(Clone, Debug)]
+pub struct NestedComponentSection<'a>(pub &'a Component);
+
+impl Encode for NestedComponentSection<'_> {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ self.0.bytes.encode(sink);
+ }
+}
+
+impl ComponentSection for NestedComponentSection<'_> {
+ fn id(&self) -> u8 {
+ ComponentSectionId::Component.into()
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/component/exports.rs b/third_party/rust/wasm-encoder/src/component/exports.rs
new file mode 100644
index 0000000000..e4fcfee055
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/component/exports.rs
@@ -0,0 +1,124 @@
+use super::{
+ COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, FUNCTION_SORT, INSTANCE_SORT, TYPE_SORT,
+ VALUE_SORT,
+};
+use crate::{encode_section, ComponentSection, ComponentSectionId, ComponentTypeRef, Encode};
+
+/// Represents the kind of an export from a WebAssembly component.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum ComponentExportKind {
+ /// The export is a core module.
+ Module,
+ /// The export is a function.
+ Func,
+ /// The export is a value.
+ Value,
+ /// The export is a type.
+ Type,
+ /// The export is an instance.
+ Instance,
+ /// The export is a component.
+ Component,
+}
+
+impl Encode for ComponentExportKind {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ match self {
+ Self::Module => {
+ sink.push(CORE_SORT);
+ sink.push(CORE_MODULE_SORT);
+ }
+ Self::Func => {
+ sink.push(FUNCTION_SORT);
+ }
+ Self::Value => {
+ sink.push(VALUE_SORT);
+ }
+ Self::Type => {
+ sink.push(TYPE_SORT);
+ }
+ Self::Instance => {
+ sink.push(INSTANCE_SORT);
+ }
+ Self::Component => {
+ sink.push(COMPONENT_SORT);
+ }
+ }
+ }
+}
+
+/// An encoder for the export section of WebAssembly component.
+///
+/// # Example
+///
+/// ```rust
+/// use wasm_encoder::{Component, ComponentExportSection, ComponentExportKind};
+///
+/// // This exports a function named "foo"
+/// let mut exports = ComponentExportSection::new();
+/// exports.export("foo", ComponentExportKind::Func, 0, None);
+///
+/// let mut component = Component::new();
+/// component.section(&exports);
+///
+/// let bytes = component.finish();
+/// ```
+#[derive(Clone, Debug, Default)]
+pub struct ComponentExportSection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+impl ComponentExportSection {
+ /// Create a new component export section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of exports in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Define an export in the export section.
+ pub fn export(
+ &mut self,
+ name: &str,
+ kind: ComponentExportKind,
+ index: u32,
+ ty: Option<ComponentTypeRef>,
+ ) -> &mut Self {
+ crate::component::imports::push_extern_name_byte(&mut self.bytes, name);
+ name.encode(&mut self.bytes);
+ kind.encode(&mut self.bytes);
+ index.encode(&mut self.bytes);
+ match ty {
+ Some(ty) => {
+ self.bytes.push(0x01);
+ ty.encode(&mut self.bytes);
+ }
+ None => {
+ self.bytes.push(0x00);
+ }
+ }
+ self.num_added += 1;
+ self
+ }
+}
+
+impl Encode for ComponentExportSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl ComponentSection for ComponentExportSection {
+ fn id(&self) -> u8 {
+ ComponentSectionId::Export.into()
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/component/imports.rs b/third_party/rust/wasm-encoder/src/component/imports.rs
new file mode 100644
index 0000000000..6337a0625d
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/component/imports.rs
@@ -0,0 +1,175 @@
+use crate::{
+ encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, ComponentValType,
+ Encode,
+};
+
+/// Represents the possible type bounds for type references.
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
+pub enum TypeBounds {
+ /// The type is bounded by equality to the type index specified.
+ Eq(u32),
+ /// This type is a fresh resource type,
+ SubResource,
+}
+
+impl Encode for TypeBounds {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ match self {
+ Self::Eq(i) => {
+ sink.push(0x00);
+ i.encode(sink);
+ }
+ Self::SubResource => sink.push(0x01),
+ }
+ }
+}
+
+/// Represents a reference to a type.
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
+pub enum ComponentTypeRef {
+ /// The reference is to a core module type.
+ ///
+ /// The index is expected to be core type index to a core module type.
+ Module(u32),
+ /// The reference is to a function type.
+ ///
+ /// The index is expected to be a type index to a function type.
+ Func(u32),
+ /// The reference is to a value type.
+ Value(ComponentValType),
+ /// The reference is to a bounded type.
+ Type(TypeBounds),
+ /// The reference is to an instance type.
+ ///
+ /// The index is expected to be a type index to an instance type.
+ Instance(u32),
+ /// The reference is to a component type.
+ ///
+ /// The index is expected to be a type index to a component type.
+ Component(u32),
+}
+
+impl ComponentTypeRef {
+ /// Gets the export kind of the reference.
+ pub fn kind(&self) -> ComponentExportKind {
+ match self {
+ Self::Module(_) => ComponentExportKind::Module,
+ Self::Func(_) => ComponentExportKind::Func,
+ Self::Value(_) => ComponentExportKind::Value,
+ Self::Type(..) => ComponentExportKind::Type,
+ Self::Instance(_) => ComponentExportKind::Instance,
+ Self::Component(_) => ComponentExportKind::Component,
+ }
+ }
+}
+
+impl Encode for ComponentTypeRef {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ self.kind().encode(sink);
+
+ match self {
+ Self::Module(idx) | Self::Func(idx) | Self::Instance(idx) | Self::Component(idx) => {
+ idx.encode(sink);
+ }
+ Self::Value(ty) => ty.encode(sink),
+ Self::Type(bounds) => bounds.encode(sink),
+ }
+ }
+}
+
+/// An encoder for the import section of WebAssembly components.
+///
+/// # Example
+///
+/// ```rust
+/// use wasm_encoder::{Component, ComponentTypeSection, PrimitiveValType, ComponentImportSection, ComponentTypeRef};
+///
+/// let mut types = ComponentTypeSection::new();
+///
+/// // Define a function type of `[string, string] -> string`.
+/// types
+/// .function()
+/// .params(
+/// [
+/// ("a", PrimitiveValType::String),
+/// ("b", PrimitiveValType::String)
+/// ]
+/// )
+/// .result(PrimitiveValType::String);
+///
+/// // This imports a function named `f` with the type defined above
+/// let mut imports = ComponentImportSection::new();
+/// imports.import("f", ComponentTypeRef::Func(0));
+///
+/// let mut component = Component::new();
+/// component.section(&types);
+/// component.section(&imports);
+///
+/// let bytes = component.finish();
+/// ```
+#[derive(Clone, Debug, Default)]
+pub struct ComponentImportSection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+impl ComponentImportSection {
+ /// Create a new component import section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of imports in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Define an import in the component import section.
+ pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self {
+ push_extern_name_byte(&mut self.bytes, name);
+ name.encode(&mut self.bytes);
+ ty.encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+}
+
+impl Encode for ComponentImportSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl ComponentSection for ComponentImportSection {
+ fn id(&self) -> u8 {
+ ComponentSectionId::Import.into()
+ }
+}
+
+/// Prior to WebAssembly/component-model#263 import and export names were
+/// discriminated with a leading byte indicating what kind of import they are.
+/// After that PR though names are always prefixed with a 0x00 byte.
+///
+/// This function is a compatibility shim for the time being while this change
+/// is being rolled out. That PR is technically a spec-breaking change relative
+/// to prior but we want old tooling to continue to work with new modules. To
+/// handle that names that look like IDs, `a:b/c`, get an 0x01 prefix instead of
+/// the spec-defined 0x00 prefix. That makes components produced by current
+/// versions of this crate compatible with older parsers.
+///
+/// Note that wasmparser has a similar case where it parses either 0x01 or 0x00.
+/// That means that the selection of a byte here doesn't actually matter for
+/// wasmparser's own validation. Eventually this will go away and an 0x00 byte
+/// will always be emitted to align with the spec.
+pub(crate) fn push_extern_name_byte(bytes: &mut Vec<u8>, name: &str) {
+ if name.contains(':') {
+ bytes.push(0x01);
+ } else {
+ bytes.push(0x00);
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/component/instances.rs b/third_party/rust/wasm-encoder/src/component/instances.rs
new file mode 100644
index 0000000000..e0877d1661
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/component/instances.rs
@@ -0,0 +1,200 @@
+use super::CORE_INSTANCE_SORT;
+use crate::{
+ encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind,
+};
+
+/// Represents an argument to a module instantiation.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum ModuleArg {
+ /// The argument is an instance.
+ Instance(u32),
+}
+
+impl Encode for ModuleArg {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ let (sort, idx) = match self {
+ Self::Instance(idx) => (CORE_INSTANCE_SORT, *idx),
+ };
+ sink.push(sort);
+ idx.encode(sink);
+ }
+}
+
+/// An encoder for the core instance section of WebAssembly components.
+///
+/// # Example
+///
+/// ```rust
+/// use wasm_encoder::{Component, InstanceSection, ExportKind, ModuleArg};
+///
+/// let mut instances = InstanceSection::new();
+/// instances.export_items([("foo", ExportKind::Func, 0)]);
+/// instances.instantiate(1, [("foo", ModuleArg::Instance(0))]);
+///
+/// let mut component = Component::new();
+/// component.section(&instances);
+///
+/// let bytes = component.finish();
+/// ```
+#[derive(Clone, Debug, Default)]
+pub struct InstanceSection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+impl InstanceSection {
+ /// Create a new core instance section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of instances in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Define an instance by instantiating a core module.
+ pub fn instantiate<A, S>(&mut self, module_index: u32, args: A) -> &mut Self
+ where
+ A: IntoIterator<Item = (S, ModuleArg)>,
+ A::IntoIter: ExactSizeIterator,
+ S: AsRef<str>,
+ {
+ let args = args.into_iter();
+ self.bytes.push(0x00);
+ module_index.encode(&mut self.bytes);
+ args.len().encode(&mut self.bytes);
+ for (name, arg) in args {
+ name.as_ref().encode(&mut self.bytes);
+ arg.encode(&mut self.bytes);
+ }
+ self.num_added += 1;
+ self
+ }
+
+ /// Define an instance by exporting core WebAssembly items.
+ pub fn export_items<E, S>(&mut self, exports: E) -> &mut Self
+ where
+ E: IntoIterator<Item = (S, ExportKind, u32)>,
+ E::IntoIter: ExactSizeIterator,
+ S: AsRef<str>,
+ {
+ let exports = exports.into_iter();
+ self.bytes.push(0x01);
+ exports.len().encode(&mut self.bytes);
+ for (name, kind, index) in exports {
+ name.as_ref().encode(&mut self.bytes);
+ kind.encode(&mut self.bytes);
+ index.encode(&mut self.bytes);
+ }
+ self.num_added += 1;
+ self
+ }
+}
+
+impl Encode for InstanceSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl ComponentSection for InstanceSection {
+ fn id(&self) -> u8 {
+ ComponentSectionId::CoreInstance.into()
+ }
+}
+
+/// An encoder for the instance section of WebAssembly components.
+///
+/// # Example
+///
+/// ```rust
+/// use wasm_encoder::{Component, ComponentInstanceSection, ComponentExportKind};
+///
+/// let mut instances = ComponentInstanceSection::new();
+/// instances.export_items([("foo", ComponentExportKind::Func, 0)]);
+/// instances.instantiate(1, [("foo", ComponentExportKind::Instance, 0)]);
+///
+/// let mut component = Component::new();
+/// component.section(&instances);
+///
+/// let bytes = component.finish();
+/// ```
+#[derive(Clone, Debug, Default)]
+pub struct ComponentInstanceSection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+impl ComponentInstanceSection {
+ /// Create a new instance section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of instances in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Define an instance by instantiating a component.
+ pub fn instantiate<A, S>(&mut self, component_index: u32, args: A) -> &mut Self
+ where
+ A: IntoIterator<Item = (S, ComponentExportKind, u32)>,
+ A::IntoIter: ExactSizeIterator,
+ S: AsRef<str>,
+ {
+ let args = args.into_iter();
+ self.bytes.push(0x00);
+ component_index.encode(&mut self.bytes);
+ args.len().encode(&mut self.bytes);
+ for (name, kind, index) in args {
+ name.as_ref().encode(&mut self.bytes);
+ kind.encode(&mut self.bytes);
+ index.encode(&mut self.bytes);
+ }
+ self.num_added += 1;
+ self
+ }
+
+ /// Define an instance by exporting items.
+ pub fn export_items<'a, E>(&mut self, exports: E) -> &mut Self
+ where
+ E: IntoIterator<Item = (&'a str, ComponentExportKind, u32)>,
+ E::IntoIter: ExactSizeIterator,
+ {
+ let exports = exports.into_iter();
+ self.bytes.push(0x01);
+ exports.len().encode(&mut self.bytes);
+ for (name, kind, index) in exports {
+ crate::push_extern_name_byte(&mut self.bytes, name);
+ name.encode(&mut self.bytes);
+ kind.encode(&mut self.bytes);
+ index.encode(&mut self.bytes);
+ }
+ self.num_added += 1;
+ self
+ }
+}
+
+impl Encode for ComponentInstanceSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl ComponentSection for ComponentInstanceSection {
+ fn id(&self) -> u8 {
+ ComponentSectionId::Instance.into()
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/component/modules.rs b/third_party/rust/wasm-encoder/src/component/modules.rs
new file mode 100644
index 0000000000..437cd353af
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/component/modules.rs
@@ -0,0 +1,29 @@
+use crate::{ComponentSection, ComponentSectionId, Encode, Module};
+
+/// An encoder for the module section of WebAssembly components.
+///
+/// # Example
+///
+/// ```rust
+/// use wasm_encoder::{Module, Component, ModuleSection};
+///
+/// let mut module = Module::new();
+/// let mut component = Component::new();
+/// component.section(&ModuleSection(&module));
+///
+/// let bytes = component.finish();
+/// ```
+#[derive(Clone, Debug)]
+pub struct ModuleSection<'a>(pub &'a Module);
+
+impl Encode for ModuleSection<'_> {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ self.0.bytes.encode(sink);
+ }
+}
+
+impl ComponentSection for ModuleSection<'_> {
+ fn id(&self) -> u8 {
+ ComponentSectionId::CoreModule.into()
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/component/names.rs b/third_party/rust/wasm-encoder/src/component/names.rs
new file mode 100644
index 0000000000..99db10bda0
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/component/names.rs
@@ -0,0 +1,149 @@
+use std::borrow::Cow;
+
+use super::*;
+use crate::{encoding_size, CustomSection, Encode, ExportKind, NameMap, SectionId};
+
+/// Encoding for the `component-name` custom section which assigns
+/// human-readable names to items within a component.
+#[derive(Clone, Debug, Default)]
+pub struct ComponentNameSection {
+ bytes: Vec<u8>,
+}
+
+enum Subsection {
+ Component,
+ Decls,
+}
+
+impl ComponentNameSection {
+ /// Creates a new blank `name` custom section.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// Appends a component name subsection to this section.
+ ///
+ /// This will indicate that the name of the entire component should be the
+ /// `name` specified. Note that this should be encoded first before other
+ /// subsections.
+ pub fn component(&mut self, name: &str) {
+ let len = encoding_size(u32::try_from(name.len()).unwrap());
+ self.subsection_header(Subsection::Component, len + name.len());
+ name.encode(&mut self.bytes);
+ }
+
+ /// Appends a decls name subsection to name core functions within the
+ /// component.
+ pub fn core_funcs(&mut self, names: &NameMap) {
+ self.core_decls(ExportKind::Func as u8, names)
+ }
+
+ /// Appends a decls name subsection to name core tables within the
+ /// component.
+ pub fn core_tables(&mut self, names: &NameMap) {
+ self.core_decls(ExportKind::Table as u8, names)
+ }
+
+ /// Appends a decls name subsection to name core memories within the
+ /// component.
+ pub fn core_memories(&mut self, names: &NameMap) {
+ self.core_decls(ExportKind::Memory as u8, names)
+ }
+
+ /// Appends a decls name subsection to name core globals within the
+ /// component.
+ pub fn core_globals(&mut self, names: &NameMap) {
+ self.core_decls(ExportKind::Global as u8, names)
+ }
+
+ /// Appends a decls name subsection to name core types within the
+ /// component.
+ pub fn core_types(&mut self, names: &NameMap) {
+ self.core_decls(CORE_TYPE_SORT, names)
+ }
+
+ /// Appends a decls name subsection to name core modules within the
+ /// component.
+ pub fn core_modules(&mut self, names: &NameMap) {
+ self.core_decls(CORE_MODULE_SORT, names)
+ }
+
+ /// Appends a decls name subsection to name core instances within the
+ /// component.
+ pub fn core_instances(&mut self, names: &NameMap) {
+ self.core_decls(CORE_INSTANCE_SORT, names)
+ }
+
+ /// Appends a decls name subsection to name component functions within the
+ /// component.
+ pub fn funcs(&mut self, names: &NameMap) {
+ self.component_decls(FUNCTION_SORT, names)
+ }
+
+ /// Appends a decls name subsection to name component values within the
+ /// component.
+ pub fn values(&mut self, names: &NameMap) {
+ self.component_decls(VALUE_SORT, names)
+ }
+
+ /// Appends a decls name subsection to name component type within the
+ /// component.
+ pub fn types(&mut self, names: &NameMap) {
+ self.component_decls(TYPE_SORT, names)
+ }
+
+ /// Appends a decls name subsection to name components within the
+ /// component.
+ pub fn components(&mut self, names: &NameMap) {
+ self.component_decls(COMPONENT_SORT, names)
+ }
+
+ /// Appends a decls name subsection to name component instances within the
+ /// component.
+ pub fn instances(&mut self, names: &NameMap) {
+ self.component_decls(INSTANCE_SORT, names)
+ }
+
+ fn component_decls(&mut self, kind: u8, names: &NameMap) {
+ self.subsection_header(Subsection::Decls, 1 + names.size());
+ self.bytes.push(kind);
+ names.encode(&mut self.bytes);
+ }
+
+ fn core_decls(&mut self, kind: u8, names: &NameMap) {
+ self.subsection_header(Subsection::Decls, 2 + names.size());
+ self.bytes.push(CORE_SORT);
+ self.bytes.push(kind);
+ names.encode(&mut self.bytes);
+ }
+
+ fn subsection_header(&mut self, id: Subsection, len: usize) {
+ self.bytes.push(id as u8);
+ len.encode(&mut self.bytes);
+ }
+
+ /// Returns whether this section is empty, or nothing has been encoded.
+ pub fn is_empty(&self) -> bool {
+ self.bytes.is_empty()
+ }
+
+ /// View the encoded section as a CustomSection.
+ pub fn as_custom<'a>(&'a self) -> CustomSection<'a> {
+ CustomSection {
+ name: "component-name".into(),
+ data: Cow::Borrowed(&self.bytes),
+ }
+ }
+}
+
+impl Encode for ComponentNameSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ self.as_custom().encode(sink);
+ }
+}
+
+impl ComponentSection for ComponentNameSection {
+ fn id(&self) -> u8 {
+ SectionId::Custom.into()
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/component/start.rs b/third_party/rust/wasm-encoder/src/component/start.rs
new file mode 100644
index 0000000000..d4b60e1dfc
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/component/start.rs
@@ -0,0 +1,52 @@
+use crate::{ComponentSection, ComponentSectionId, Encode};
+
+/// An encoder for the start section of WebAssembly components.
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{Component, ComponentStartSection};
+///
+/// let start = ComponentStartSection { function_index: 0, args: [0, 1], results: 1 };
+///
+/// let mut component = Component::new();
+/// component.section(&start);
+///
+/// let bytes = component.finish();
+/// ```
+#[derive(Clone, Debug)]
+pub struct ComponentStartSection<A> {
+ /// The index to the start function.
+ pub function_index: u32,
+ /// The arguments to pass to the start function.
+ ///
+ /// An argument is an index to a value.
+ pub args: A,
+ /// The number of expected results for the start function.
+ ///
+ /// This should match the number of results for the type of
+ /// the function referenced by `function_index`.
+ pub results: u32,
+}
+
+impl<A> Encode for ComponentStartSection<A>
+where
+ A: AsRef<[u32]>,
+{
+ fn encode(&self, sink: &mut Vec<u8>) {
+ let mut bytes = Vec::new();
+ self.function_index.encode(&mut bytes);
+ self.args.as_ref().encode(&mut bytes);
+ self.results.encode(&mut bytes);
+ bytes.encode(sink);
+ }
+}
+
+impl<A> ComponentSection for ComponentStartSection<A>
+where
+ A: AsRef<[u32]>,
+{
+ fn id(&self) -> u8 {
+ ComponentSectionId::Start.into()
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/component/types.rs b/third_party/rust/wasm-encoder/src/component/types.rs
new file mode 100644
index 0000000000..537e8c5a00
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/component/types.rs
@@ -0,0 +1,792 @@
+use super::CORE_TYPE_SORT;
+use crate::{
+ encode_section, Alias, ComponentExportKind, ComponentOuterAliasKind, ComponentSection,
+ ComponentSectionId, ComponentTypeRef, Encode, EntityType, ValType,
+};
+
+/// Represents the type of a core module.
+#[derive(Debug, Clone, Default)]
+pub struct ModuleType {
+ bytes: Vec<u8>,
+ num_added: u32,
+ types_added: u32,
+}
+
+impl ModuleType {
+ /// Creates a new core module type.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// Defines an import in this module type.
+ pub fn import(&mut self, module: &str, name: &str, ty: EntityType) -> &mut Self {
+ crate::component::imports::push_extern_name_byte(&mut self.bytes, name);
+ module.encode(&mut self.bytes);
+ name.encode(&mut self.bytes);
+ ty.encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+
+ /// Define a type in this module type.
+ ///
+ /// The returned encoder must be used before adding another definition.
+ #[must_use = "the encoder must be used to encode the type"]
+ pub fn ty(&mut self) -> CoreTypeEncoder {
+ self.bytes.push(0x01);
+ self.num_added += 1;
+ self.types_added += 1;
+ CoreTypeEncoder(&mut self.bytes)
+ }
+
+ /// Defines an outer core type alias in this module type.
+ pub fn alias_outer_core_type(&mut self, count: u32, index: u32) -> &mut Self {
+ self.bytes.push(0x02);
+ self.bytes.push(CORE_TYPE_SORT);
+ self.bytes.push(0x01); // outer
+ count.encode(&mut self.bytes);
+ index.encode(&mut self.bytes);
+ self.num_added += 1;
+ self.types_added += 1;
+ self
+ }
+
+ /// Defines an export in this module type.
+ pub fn export(&mut self, name: &str, ty: EntityType) -> &mut Self {
+ self.bytes.push(0x03);
+ name.encode(&mut self.bytes);
+ ty.encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+
+ /// Gets the number of types that have been added to this module type.
+ pub fn type_count(&self) -> u32 {
+ self.types_added
+ }
+}
+
+impl Encode for ModuleType {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ sink.push(0x50);
+ self.num_added.encode(sink);
+ sink.extend(&self.bytes);
+ }
+}
+
+/// Used to encode core types.
+#[derive(Debug)]
+pub struct CoreTypeEncoder<'a>(pub(crate) &'a mut Vec<u8>);
+
+impl<'a> CoreTypeEncoder<'a> {
+ /// Define a function type.
+ pub fn function<P, R>(self, params: P, results: R)
+ where
+ P: IntoIterator<Item = ValType>,
+ P::IntoIter: ExactSizeIterator,
+ R: IntoIterator<Item = ValType>,
+ R::IntoIter: ExactSizeIterator,
+ {
+ let params = params.into_iter();
+ let results = results.into_iter();
+
+ self.0.push(0x60);
+ params.len().encode(self.0);
+ params.for_each(|p| p.encode(self.0));
+ results.len().encode(self.0);
+ results.for_each(|p| p.encode(self.0));
+ }
+
+ /// Define a module type.
+ pub fn module(self, ty: &ModuleType) {
+ ty.encode(self.0);
+ }
+}
+
+/// An encoder for the core type section of WebAssembly components.
+///
+/// # Example
+///
+/// ```rust
+/// use wasm_encoder::{Component, CoreTypeSection, ModuleType};
+///
+/// let mut types = CoreTypeSection::new();
+///
+/// types.module(&ModuleType::new());
+///
+/// let mut component = Component::new();
+/// component.section(&types);
+///
+/// let bytes = component.finish();
+/// ```
+#[derive(Clone, Debug, Default)]
+pub struct CoreTypeSection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+impl CoreTypeSection {
+ /// Create a new core type section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of types in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Encode a type into this section.
+ ///
+ /// The returned encoder must be finished before adding another type.
+ #[must_use = "the encoder must be used to encode the type"]
+ pub fn ty(&mut self) -> CoreTypeEncoder<'_> {
+ self.num_added += 1;
+ CoreTypeEncoder(&mut self.bytes)
+ }
+
+ /// Define a function type in this type section.
+ pub fn function<P, R>(&mut self, params: P, results: R) -> &mut Self
+ where
+ P: IntoIterator<Item = ValType>,
+ P::IntoIter: ExactSizeIterator,
+ R: IntoIterator<Item = ValType>,
+ R::IntoIter: ExactSizeIterator,
+ {
+ self.ty().function(params, results);
+ self
+ }
+
+ /// Define a module type in this type section.
+ ///
+ /// Currently this is only used for core type sections in components.
+ pub fn module(&mut self, ty: &ModuleType) -> &mut Self {
+ self.ty().module(ty);
+ self
+ }
+}
+
+impl Encode for CoreTypeSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl ComponentSection for CoreTypeSection {
+ fn id(&self) -> u8 {
+ ComponentSectionId::CoreType.into()
+ }
+}
+
+/// Represents a component type.
+#[derive(Debug, Clone, Default)]
+pub struct ComponentType {
+ bytes: Vec<u8>,
+ num_added: u32,
+ core_types_added: u32,
+ types_added: u32,
+ instances_added: u32,
+}
+
+impl ComponentType {
+ /// Creates a new component type.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// Define a core type in this component type.
+ ///
+ /// The returned encoder must be used before adding another definition.
+ #[must_use = "the encoder must be used to encode the type"]
+ pub fn core_type(&mut self) -> CoreTypeEncoder {
+ self.bytes.push(0x00);
+ self.num_added += 1;
+ self.core_types_added += 1;
+ CoreTypeEncoder(&mut self.bytes)
+ }
+
+ /// Define a type in this component type.
+ ///
+ /// The returned encoder must be used before adding another definition.
+ #[must_use = "the encoder must be used to encode the type"]
+ pub fn ty(&mut self) -> ComponentTypeEncoder {
+ self.bytes.push(0x01);
+ self.num_added += 1;
+ self.types_added += 1;
+ ComponentTypeEncoder(&mut self.bytes)
+ }
+
+ /// Defines an alias for an exported item of a prior instance or an
+ /// outer type.
+ pub fn alias(&mut self, alias: Alias<'_>) -> &mut Self {
+ self.bytes.push(0x02);
+ alias.encode(&mut self.bytes);
+ self.num_added += 1;
+ match &alias {
+ Alias::InstanceExport {
+ kind: ComponentExportKind::Type,
+ ..
+ }
+ | Alias::Outer {
+ kind: ComponentOuterAliasKind::Type,
+ ..
+ } => self.types_added += 1,
+ Alias::Outer {
+ kind: ComponentOuterAliasKind::CoreType,
+ ..
+ } => self.core_types_added += 1,
+ Alias::InstanceExport {
+ kind: ComponentExportKind::Instance,
+ ..
+ } => self.instances_added += 1,
+ _ => {}
+ }
+ self
+ }
+
+ /// Defines an import in this component type.
+ pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self {
+ self.bytes.push(0x03);
+ crate::component::imports::push_extern_name_byte(&mut self.bytes, name);
+ name.encode(&mut self.bytes);
+ ty.encode(&mut self.bytes);
+ self.num_added += 1;
+ match ty {
+ ComponentTypeRef::Type(..) => self.types_added += 1,
+ ComponentTypeRef::Instance(..) => self.instances_added += 1,
+ _ => {}
+ }
+ self
+ }
+
+ /// Defines an export in this component type.
+ pub fn export(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self {
+ self.bytes.push(0x04);
+ crate::component::imports::push_extern_name_byte(&mut self.bytes, name);
+ name.encode(&mut self.bytes);
+ ty.encode(&mut self.bytes);
+ self.num_added += 1;
+ match ty {
+ ComponentTypeRef::Type(..) => self.types_added += 1,
+ ComponentTypeRef::Instance(..) => self.instances_added += 1,
+ _ => {}
+ }
+ self
+ }
+
+ /// Gets the number of core types that have been added to this component type.
+ pub fn core_type_count(&self) -> u32 {
+ self.core_types_added
+ }
+
+ /// Gets the number of types that have been added or aliased in this component type.
+ pub fn type_count(&self) -> u32 {
+ self.types_added
+ }
+
+ /// Gets the number of instances that have been defined in this component
+ /// type through imports, exports, or aliases.
+ pub fn instance_count(&self) -> u32 {
+ self.instances_added
+ }
+}
+
+impl Encode for ComponentType {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ sink.push(0x41);
+ self.num_added.encode(sink);
+ sink.extend(&self.bytes);
+ }
+}
+
+/// Represents an instance type.
+#[derive(Debug, Clone, Default)]
+pub struct InstanceType(ComponentType);
+
+impl InstanceType {
+ /// Creates a new instance type.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// Define a core type in this instance type.
+ ///
+ /// The returned encoder must be used before adding another definition.
+ #[must_use = "the encoder must be used to encode the type"]
+ pub fn core_type(&mut self) -> CoreTypeEncoder {
+ self.0.core_type()
+ }
+
+ /// Define a type in this instance type.
+ ///
+ /// The returned encoder must be used before adding another definition.
+ #[must_use = "the encoder must be used to encode the type"]
+ pub fn ty(&mut self) -> ComponentTypeEncoder {
+ self.0.ty()
+ }
+
+ /// Defines an outer core type alias in this component type.
+ pub fn alias(&mut self, alias: Alias<'_>) -> &mut Self {
+ self.0.alias(alias);
+ self
+ }
+
+ /// Defines an export in this instance type.
+ pub fn export(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self {
+ self.0.export(name, ty);
+ self
+ }
+
+ /// Gets the number of core types that have been added to this instance type.
+ pub fn core_type_count(&self) -> u32 {
+ self.0.core_types_added
+ }
+
+ /// Gets the number of types that have been added or aliased in this instance type.
+ pub fn type_count(&self) -> u32 {
+ self.0.types_added
+ }
+
+ /// Gets the number of instances that have been imported or exported or
+ /// aliased in this instance type.
+ pub fn instance_count(&self) -> u32 {
+ self.0.instances_added
+ }
+
+ /// Returns whether or not this instance type is empty.
+ pub fn is_empty(&self) -> bool {
+ self.0.num_added == 0
+ }
+
+ /// Returns the number of entries added to this instance types.
+ pub fn len(&self) -> u32 {
+ self.0.num_added
+ }
+}
+
+impl Encode for InstanceType {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ sink.push(0x42);
+ self.0.num_added.encode(sink);
+ sink.extend(&self.0.bytes);
+ }
+}
+
+/// Used to encode component function types.
+#[derive(Debug)]
+pub struct ComponentFuncTypeEncoder<'a>(&'a mut Vec<u8>);
+
+impl<'a> ComponentFuncTypeEncoder<'a> {
+ fn new(sink: &'a mut Vec<u8>) -> Self {
+ sink.push(0x40);
+ Self(sink)
+ }
+
+ /// Defines named parameters.
+ ///
+ /// Parameters must be defined before defining results.
+ pub fn params<'b, P, T>(&mut self, params: P) -> &mut Self
+ where
+ P: IntoIterator<Item = (&'b str, T)>,
+ P::IntoIter: ExactSizeIterator,
+ T: Into<ComponentValType>,
+ {
+ let params = params.into_iter();
+ params.len().encode(self.0);
+ for (name, ty) in params {
+ name.encode(self.0);
+ ty.into().encode(self.0);
+ }
+ self
+ }
+
+ /// Defines a single unnamed result.
+ ///
+ /// This method cannot be used with `results`.
+ pub fn result(&mut self, ty: impl Into<ComponentValType>) -> &mut Self {
+ self.0.push(0x00);
+ ty.into().encode(self.0);
+ self
+ }
+
+ /// Defines named results.
+ ///
+ /// This method cannot be used with `result`.
+ pub fn results<'b, R, T>(&mut self, results: R) -> &mut Self
+ where
+ R: IntoIterator<Item = (&'b str, T)>,
+ R::IntoIter: ExactSizeIterator,
+ T: Into<ComponentValType>,
+ {
+ self.0.push(0x01);
+ let results = results.into_iter();
+ results.len().encode(self.0);
+ for (name, ty) in results {
+ name.encode(self.0);
+ ty.into().encode(self.0);
+ }
+ self
+ }
+}
+
+/// Used to encode component and instance types.
+#[derive(Debug)]
+pub struct ComponentTypeEncoder<'a>(&'a mut Vec<u8>);
+
+impl<'a> ComponentTypeEncoder<'a> {
+ /// Define a component type.
+ pub fn component(self, ty: &ComponentType) {
+ ty.encode(self.0);
+ }
+
+ /// Define an instance type.
+ pub fn instance(self, ty: &InstanceType) {
+ ty.encode(self.0);
+ }
+
+ /// Define a function type.
+ pub fn function(self) -> ComponentFuncTypeEncoder<'a> {
+ ComponentFuncTypeEncoder::new(self.0)
+ }
+
+ /// Define a defined component type.
+ ///
+ /// The returned encoder must be used before adding another type.
+ #[must_use = "the encoder must be used to encode the type"]
+ pub fn defined_type(self) -> ComponentDefinedTypeEncoder<'a> {
+ ComponentDefinedTypeEncoder(self.0)
+ }
+
+ /// Define a resource type.
+ pub fn resource(self, rep: ValType, dtor: Option<u32>) {
+ self.0.push(0x3f);
+ rep.encode(self.0);
+ match dtor {
+ Some(i) => {
+ self.0.push(0x01);
+ i.encode(self.0);
+ }
+ None => self.0.push(0x00),
+ }
+ }
+}
+
+/// Represents a primitive component value type.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum PrimitiveValType {
+ /// The type is a boolean.
+ Bool,
+ /// The type is a signed 8-bit integer.
+ S8,
+ /// The type is an unsigned 8-bit integer.
+ U8,
+ /// The type is a signed 16-bit integer.
+ S16,
+ /// The type is an unsigned 16-bit integer.
+ U16,
+ /// The type is a signed 32-bit integer.
+ S32,
+ /// The type is an unsigned 32-bit integer.
+ U32,
+ /// The type is a signed 64-bit integer.
+ S64,
+ /// The type is an unsigned 64-bit integer.
+ U64,
+ /// The type is a 32-bit floating point number.
+ Float32,
+ /// The type is a 64-bit floating point number.
+ Float64,
+ /// The type is a Unicode character.
+ Char,
+ /// The type is a string.
+ String,
+}
+
+impl Encode for PrimitiveValType {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ sink.push(match self {
+ Self::Bool => 0x7f,
+ Self::S8 => 0x7e,
+ Self::U8 => 0x7d,
+ Self::S16 => 0x7c,
+ Self::U16 => 0x7b,
+ Self::S32 => 0x7a,
+ Self::U32 => 0x79,
+ Self::S64 => 0x78,
+ Self::U64 => 0x77,
+ Self::Float32 => 0x76,
+ Self::Float64 => 0x75,
+ Self::Char => 0x74,
+ Self::String => 0x73,
+ });
+ }
+}
+
+#[cfg(feature = "wasmparser")]
+impl From<wasmparser::PrimitiveValType> for PrimitiveValType {
+ fn from(ty: wasmparser::PrimitiveValType) -> Self {
+ match ty {
+ wasmparser::PrimitiveValType::Bool => PrimitiveValType::Bool,
+ wasmparser::PrimitiveValType::S8 => PrimitiveValType::S8,
+ wasmparser::PrimitiveValType::U8 => PrimitiveValType::U8,
+ wasmparser::PrimitiveValType::S16 => PrimitiveValType::S16,
+ wasmparser::PrimitiveValType::U16 => PrimitiveValType::U16,
+ wasmparser::PrimitiveValType::S32 => PrimitiveValType::S32,
+ wasmparser::PrimitiveValType::U32 => PrimitiveValType::U32,
+ wasmparser::PrimitiveValType::S64 => PrimitiveValType::S64,
+ wasmparser::PrimitiveValType::U64 => PrimitiveValType::U64,
+ wasmparser::PrimitiveValType::Float32 => PrimitiveValType::Float32,
+ wasmparser::PrimitiveValType::Float64 => PrimitiveValType::Float64,
+ wasmparser::PrimitiveValType::Char => PrimitiveValType::Char,
+ wasmparser::PrimitiveValType::String => PrimitiveValType::String,
+ }
+ }
+}
+
+/// Represents a component value type.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum ComponentValType {
+ /// The value is a primitive type.
+ Primitive(PrimitiveValType),
+ /// The value is to a defined value type.
+ ///
+ /// The type index must be to a value type.
+ Type(u32),
+}
+
+impl Encode for ComponentValType {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ match self {
+ Self::Primitive(ty) => ty.encode(sink),
+ Self::Type(index) => (*index as i64).encode(sink),
+ }
+ }
+}
+
+impl From<PrimitiveValType> for ComponentValType {
+ fn from(ty: PrimitiveValType) -> Self {
+ Self::Primitive(ty)
+ }
+}
+
+/// Used for encoding component defined types.
+#[derive(Debug)]
+pub struct ComponentDefinedTypeEncoder<'a>(&'a mut Vec<u8>);
+
+impl ComponentDefinedTypeEncoder<'_> {
+ /// Define a primitive value type.
+ pub fn primitive(self, ty: PrimitiveValType) {
+ ty.encode(self.0);
+ }
+
+ /// Define a record type.
+ pub fn record<'a, F, T>(self, fields: F)
+ where
+ F: IntoIterator<Item = (&'a str, T)>,
+ F::IntoIter: ExactSizeIterator,
+ T: Into<ComponentValType>,
+ {
+ let fields = fields.into_iter();
+ self.0.push(0x72);
+ fields.len().encode(self.0);
+ for (name, ty) in fields {
+ name.encode(self.0);
+ ty.into().encode(self.0);
+ }
+ }
+
+ /// Define a variant type.
+ pub fn variant<'a, C>(self, cases: C)
+ where
+ C: IntoIterator<Item = (&'a str, Option<ComponentValType>, Option<u32>)>,
+ C::IntoIter: ExactSizeIterator,
+ {
+ let cases = cases.into_iter();
+ self.0.push(0x71);
+ cases.len().encode(self.0);
+ for (name, ty, refines) in cases {
+ name.encode(self.0);
+ ty.encode(self.0);
+ refines.encode(self.0);
+ }
+ }
+
+ /// Define a list type.
+ pub fn list(self, ty: impl Into<ComponentValType>) {
+ self.0.push(0x70);
+ ty.into().encode(self.0);
+ }
+
+ /// Define a tuple type.
+ pub fn tuple<I, T>(self, types: I)
+ where
+ I: IntoIterator<Item = T>,
+ I::IntoIter: ExactSizeIterator,
+ T: Into<ComponentValType>,
+ {
+ let types = types.into_iter();
+ self.0.push(0x6F);
+ types.len().encode(self.0);
+ for ty in types {
+ ty.into().encode(self.0);
+ }
+ }
+
+ /// Define a flags type.
+ pub fn flags<'a, I>(self, names: I)
+ where
+ I: IntoIterator<Item = &'a str>,
+ I::IntoIter: ExactSizeIterator,
+ {
+ let names = names.into_iter();
+ self.0.push(0x6E);
+ names.len().encode(self.0);
+ for name in names {
+ name.encode(self.0);
+ }
+ }
+
+ /// Define an enum type.
+ pub fn enum_type<'a, I>(self, tags: I)
+ where
+ I: IntoIterator<Item = &'a str>,
+ I::IntoIter: ExactSizeIterator,
+ {
+ let tags = tags.into_iter();
+ self.0.push(0x6D);
+ tags.len().encode(self.0);
+ for tag in tags {
+ tag.encode(self.0);
+ }
+ }
+
+ /// Define an option type.
+ pub fn option(self, ty: impl Into<ComponentValType>) {
+ self.0.push(0x6B);
+ ty.into().encode(self.0);
+ }
+
+ /// Define a result type.
+ pub fn result(self, ok: Option<ComponentValType>, err: Option<ComponentValType>) {
+ self.0.push(0x6A);
+ ok.encode(self.0);
+ err.encode(self.0);
+ }
+
+ /// Define a `own` handle type
+ pub fn own(self, idx: u32) {
+ self.0.push(0x69);
+ idx.encode(self.0);
+ }
+
+ /// Define a `borrow` handle type
+ pub fn borrow(self, idx: u32) {
+ self.0.push(0x68);
+ idx.encode(self.0);
+ }
+}
+
+/// An encoder for the type section of WebAssembly components.
+///
+/// # Example
+///
+/// ```rust
+/// use wasm_encoder::{Component, ComponentTypeSection, PrimitiveValType};
+///
+/// let mut types = ComponentTypeSection::new();
+///
+/// // Define a function type of `[string, string] -> string`.
+/// types
+/// .function()
+/// .params(
+/// [
+/// ("a", PrimitiveValType::String),
+/// ("b", PrimitiveValType::String)
+/// ]
+/// )
+/// .result(PrimitiveValType::String);
+///
+/// let mut component = Component::new();
+/// component.section(&types);
+///
+/// let bytes = component.finish();
+/// ```
+#[derive(Clone, Debug, Default)]
+pub struct ComponentTypeSection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+impl ComponentTypeSection {
+ /// Create a new component type section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of types in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Encode a type into this section.
+ ///
+ /// The returned encoder must be finished before adding another type.
+ #[must_use = "the encoder must be used to encode the type"]
+ pub fn ty(&mut self) -> ComponentTypeEncoder<'_> {
+ self.num_added += 1;
+ ComponentTypeEncoder(&mut self.bytes)
+ }
+
+ /// Define a component type in this type section.
+ pub fn component(&mut self, ty: &ComponentType) -> &mut Self {
+ self.ty().component(ty);
+ self
+ }
+
+ /// Define an instance type in this type section.
+ pub fn instance(&mut self, ty: &InstanceType) -> &mut Self {
+ self.ty().instance(ty);
+ self
+ }
+
+ /// Define a function type in this type section.
+ pub fn function(&mut self) -> ComponentFuncTypeEncoder<'_> {
+ self.ty().function()
+ }
+
+ /// Add a component defined type to this type section.
+ ///
+ /// The returned encoder must be used before adding another type.
+ #[must_use = "the encoder must be used to encode the type"]
+ pub fn defined_type(&mut self) -> ComponentDefinedTypeEncoder<'_> {
+ self.ty().defined_type()
+ }
+
+ /// Defines a new resource type.
+ pub fn resource(&mut self, rep: ValType, dtor: Option<u32>) -> &mut Self {
+ self.ty().resource(rep, dtor);
+ self
+ }
+}
+
+impl Encode for ComponentTypeSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl ComponentSection for ComponentTypeSection {
+ fn id(&self) -> u8 {
+ ComponentSectionId::Type.into()
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/core.rs b/third_party/rust/wasm-encoder/src/core.rs
new file mode 100644
index 0000000000..feccfdefc1
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/core.rs
@@ -0,0 +1,168 @@
+mod code;
+mod custom;
+mod data;
+mod dump;
+mod elements;
+mod exports;
+mod functions;
+mod globals;
+mod imports;
+mod linking;
+mod memories;
+mod names;
+mod producers;
+mod start;
+mod tables;
+mod tags;
+mod types;
+
+pub use code::*;
+pub use custom::*;
+pub use data::*;
+pub use dump::*;
+pub use elements::*;
+pub use exports::*;
+pub use functions::*;
+pub use globals::*;
+pub use imports::*;
+pub use linking::*;
+pub use memories::*;
+pub use names::*;
+pub use producers::*;
+pub use start::*;
+pub use tables::*;
+pub use tags::*;
+pub use types::*;
+
+use crate::Encode;
+
+pub(crate) const CORE_FUNCTION_SORT: u8 = 0x00;
+pub(crate) const CORE_TABLE_SORT: u8 = 0x01;
+pub(crate) const CORE_MEMORY_SORT: u8 = 0x02;
+pub(crate) const CORE_GLOBAL_SORT: u8 = 0x03;
+pub(crate) const CORE_TAG_SORT: u8 = 0x04;
+
+/// A WebAssembly module section.
+///
+/// Various builders defined in this crate already implement this trait, but you
+/// can also implement it yourself for your own custom section builders, or use
+/// `RawSection` to use a bunch of raw bytes as a section.
+pub trait Section: Encode {
+ /// Gets the section identifier for this section.
+ fn id(&self) -> u8;
+
+ /// Appends this section to the specified destination list of bytes.
+ fn append_to(&self, dst: &mut Vec<u8>) {
+ dst.push(self.id());
+ self.encode(dst);
+ }
+}
+
+/// Known section identifiers of WebAssembly modules.
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
+#[repr(u8)]
+pub enum SectionId {
+ /// The custom section.
+ Custom = 0,
+ /// The type section.
+ Type = 1,
+ /// The import section.
+ Import = 2,
+ /// The function section.
+ Function = 3,
+ /// The table section.
+ Table = 4,
+ /// The memory section.
+ Memory = 5,
+ /// The global section.
+ Global = 6,
+ /// The export section.
+ Export = 7,
+ /// The start section.
+ Start = 8,
+ /// The element section.
+ Element = 9,
+ /// The code section.
+ Code = 10,
+ /// The data section.
+ Data = 11,
+ /// The data count section.
+ DataCount = 12,
+ /// The tag section.
+ ///
+ /// This section is supported by the exception handling proposal.
+ Tag = 13,
+}
+
+impl From<SectionId> for u8 {
+ #[inline]
+ fn from(id: SectionId) -> u8 {
+ id as u8
+ }
+}
+
+impl Encode for SectionId {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ sink.push(*self as u8);
+ }
+}
+
+/// Represents a WebAssembly component that is being encoded.
+///
+/// Sections within a WebAssembly module are encoded in a specific order.
+///
+/// Modules may also added as a section to a WebAssembly component.
+#[derive(Clone, Debug)]
+pub struct Module {
+ pub(crate) bytes: Vec<u8>,
+}
+
+impl Module {
+ /// The 8-byte header at the beginning of all core wasm modules.
+ #[rustfmt::skip]
+ pub const HEADER: [u8; 8] = [
+ // Magic
+ 0x00, 0x61, 0x73, 0x6D,
+ // Version
+ 0x01, 0x00, 0x00, 0x00,
+ ];
+
+ /// Begin writing a new `Module`.
+ #[rustfmt::skip]
+ pub fn new() -> Self {
+ Module {
+ bytes: Self::HEADER.to_vec(),
+ }
+ }
+
+ /// Write a section into this module.
+ ///
+ /// It is your responsibility to define the sections in the [proper
+ /// order](https://webassembly.github.io/spec/core/binary/modules.html#binary-module),
+ /// and to ensure that each kind of section (other than custom sections) is
+ /// only defined once. While this is a potential footgun, it also allows you
+ /// to use this crate to easily construct test cases for bad Wasm module
+ /// encodings.
+ pub fn section(&mut self, section: &impl Section) -> &mut Self {
+ self.bytes.push(section.id());
+ section.encode(&mut self.bytes);
+ self
+ }
+
+ /// Get the encoded Wasm module as a slice.
+ pub fn as_slice(&self) -> &[u8] {
+ &self.bytes
+ }
+
+ /// Finish writing this Wasm module and extract ownership of the encoded
+ /// bytes.
+ pub fn finish(self) -> Vec<u8> {
+ self.bytes
+ }
+}
+
+impl Default for Module {
+ fn default() -> Self {
+ Self::new()
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/core/code.rs b/third_party/rust/wasm-encoder/src/core/code.rs
new file mode 100644
index 0000000000..cec2d4191e
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/core/code.rs
@@ -0,0 +1,3355 @@
+use crate::{encode_section, Encode, HeapType, RefType, Section, SectionId, ValType};
+use std::borrow::Cow;
+
+/// An encoder for the code section.
+///
+/// Code sections are only supported for modules.
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{
+/// CodeSection, Function, FunctionSection, Instruction, Module,
+/// TypeSection, ValType
+/// };
+///
+/// let mut types = TypeSection::new();
+/// types.function(vec![], vec![ValType::I32]);
+///
+/// let mut functions = FunctionSection::new();
+/// let type_index = 0;
+/// functions.function(type_index);
+///
+/// let locals = vec![];
+/// let mut func = Function::new(locals);
+/// func.instruction(&Instruction::I32Const(42));
+/// let mut code = CodeSection::new();
+/// code.function(&func);
+///
+/// let mut module = Module::new();
+/// module
+/// .section(&types)
+/// .section(&functions)
+/// .section(&code);
+///
+/// let wasm_bytes = module.finish();
+/// ```
+#[derive(Clone, Default, Debug)]
+pub struct CodeSection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+impl CodeSection {
+ /// Create a new code section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of functions in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// The number of bytes already added to this section.
+ ///
+ /// This number doesn't include the vector length that precedes the
+ /// code entries, since it has a variable size that isn't known until all
+ /// functions are added.
+ pub fn byte_len(&self) -> usize {
+ self.bytes.len()
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Write a function body into this code section.
+ pub fn function(&mut self, func: &Function) -> &mut Self {
+ func.encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+
+ /// Add a raw byte slice into this code section as a function body.
+ ///
+ /// The length prefix of the function body will be automatically prepended,
+ /// and should not be included in the raw byte slice.
+ ///
+ /// # Example
+ ///
+ /// You can use the `raw` method to copy an already-encoded function body
+ /// into a new code section encoder:
+ ///
+ /// ```
+ /// // id, size, # entries, entry
+ /// let code_section = [10, 6, 1, 4, 0, 65, 0, 11];
+ ///
+ /// // Parse the code section.
+ /// let reader = wasmparser::CodeSectionReader::new(&code_section, 0).unwrap();
+ /// let body = reader.into_iter().next().unwrap().unwrap();
+ /// let body_range = body.range();
+ ///
+ /// // Add the body to a new code section encoder by copying bytes rather
+ /// // than re-parsing and re-encoding it.
+ /// let mut encoder = wasm_encoder::CodeSection::new();
+ /// encoder.raw(&code_section[body_range.start..body_range.end]);
+ /// ```
+ pub fn raw(&mut self, data: &[u8]) -> &mut Self {
+ data.encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+}
+
+impl Encode for CodeSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl Section for CodeSection {
+ fn id(&self) -> u8 {
+ SectionId::Code.into()
+ }
+}
+
+/// An encoder for a function body within the code section.
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{CodeSection, Function, Instruction};
+///
+/// // Define the function body for:
+/// //
+/// // (func (param i32 i32) (result i32)
+/// // local.get 0
+/// // local.get 1
+/// // i32.add)
+/// let locals = vec![];
+/// let mut func = Function::new(locals);
+/// func.instruction(&Instruction::LocalGet(0));
+/// func.instruction(&Instruction::LocalGet(1));
+/// func.instruction(&Instruction::I32Add);
+///
+/// // Add our function to the code section.
+/// let mut code = CodeSection::new();
+/// code.function(&func);
+/// ```
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct Function {
+ bytes: Vec<u8>,
+}
+
+impl Function {
+ /// Create a new function body with the given locals.
+ ///
+ /// The argument is an iterator over `(N, Ty)`, which defines
+ /// that the next `N` locals will be of type `Ty`.
+ ///
+ /// For example, a function with locals 0 and 1 of type I32 and
+ /// local 2 of type F32 would be created as:
+ ///
+ /// ```
+ /// # use wasm_encoder::{Function, ValType};
+ /// let f = Function::new([(2, ValType::I32), (1, ValType::F32)]);
+ /// ```
+ ///
+ /// For more information about the code section (and function definition) in the WASM binary format
+ /// see the [WebAssembly spec](https://webassembly.github.io/spec/core/binary/modules.html#binary-func)
+ pub fn new<L>(locals: L) -> Self
+ where
+ L: IntoIterator<Item = (u32, ValType)>,
+ L::IntoIter: ExactSizeIterator,
+ {
+ let locals = locals.into_iter();
+ let mut bytes = vec![];
+ locals.len().encode(&mut bytes);
+ for (count, ty) in locals {
+ count.encode(&mut bytes);
+ ty.encode(&mut bytes);
+ }
+ Function { bytes }
+ }
+
+ /// Create a function from a list of locals' types.
+ ///
+ /// Unlike [`Function::new`], this constructor simply takes a list of types
+ /// which are in order associated with locals.
+ ///
+ /// For example:
+ ///
+ /// ```
+ /// # use wasm_encoder::{Function, ValType};
+ /// let f = Function::new([(2, ValType::I32), (1, ValType::F32)]);
+ /// let g = Function::new_with_locals_types([
+ /// ValType::I32, ValType::I32, ValType::F32
+ /// ]);
+ ///
+ /// assert_eq!(f, g)
+ /// ```
+ pub fn new_with_locals_types<L>(locals: L) -> Self
+ where
+ L: IntoIterator<Item = ValType>,
+ {
+ let locals = locals.into_iter();
+
+ let mut locals_collected: Vec<(u32, ValType)> = vec![];
+ for l in locals {
+ if let Some((last_count, last_type)) = locals_collected.last_mut() {
+ if l == *last_type {
+ // Increment the count of consecutive locals of this type
+ *last_count += 1;
+ continue;
+ }
+ }
+ // If we didn't increment, a new type of local appeared
+ locals_collected.push((1, l));
+ }
+
+ Function::new(locals_collected)
+ }
+
+ /// Write an instruction into this function body.
+ pub fn instruction(&mut self, instruction: &Instruction) -> &mut Self {
+ instruction.encode(&mut self.bytes);
+ self
+ }
+
+ /// Add raw bytes to this function's body.
+ pub fn raw<B>(&mut self, bytes: B) -> &mut Self
+ where
+ B: IntoIterator<Item = u8>,
+ {
+ self.bytes.extend(bytes);
+ self
+ }
+
+ /// The number of bytes already added to this function.
+ ///
+ /// This number doesn't include the variable-width size field that `encode`
+ /// will write before the added bytes, since the size of that field isn't
+ /// known until all the instructions are added to this function.
+ pub fn byte_len(&self) -> usize {
+ self.bytes.len()
+ }
+}
+
+impl Encode for Function {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ self.bytes.encode(sink);
+ }
+}
+
+/// The immediate for a memory instruction.
+#[derive(Clone, Copy, Debug)]
+pub struct MemArg {
+ /// A static offset to add to the instruction's dynamic address operand.
+ ///
+ /// This is a `u64` field for the memory64 proposal, but 32-bit memories
+ /// limit offsets to at most `u32::MAX` bytes. This will be encoded as a LEB
+ /// but it won't generate a valid module if an offset is specified which is
+ /// larger than the maximum size of the index space for the memory indicated
+ /// by `memory_index`.
+ pub offset: u64,
+ /// The expected alignment of the instruction's dynamic address operand
+ /// (expressed the exponent of a power of two).
+ pub align: u32,
+ /// The index of the memory this instruction is operating upon.
+ pub memory_index: u32,
+}
+
+impl Encode for MemArg {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ if self.memory_index == 0 {
+ self.align.encode(sink);
+ self.offset.encode(sink);
+ } else {
+ (self.align | (1 << 6)).encode(sink);
+ self.memory_index.encode(sink);
+ self.offset.encode(sink);
+ }
+ }
+}
+
+/// Describe an unchecked SIMD lane index.
+pub type Lane = u8;
+
+/// The type for a `block`/`if`/`loop`.
+#[derive(Clone, Copy, Debug)]
+pub enum BlockType {
+ /// `[] -> []`
+ Empty,
+ /// `[] -> [t]`
+ Result(ValType),
+ /// The `n`th function type.
+ FunctionType(u32),
+}
+
+impl Encode for BlockType {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ match *self {
+ Self::Empty => sink.push(0x40),
+ Self::Result(ty) => ty.encode(sink),
+ Self::FunctionType(f) => (f as i64).encode(sink),
+ }
+ }
+}
+
+/// WebAssembly instructions.
+#[derive(Clone, Debug)]
+#[non_exhaustive]
+#[allow(missing_docs, non_camel_case_types)]
+pub enum Instruction<'a> {
+ // Control instructions.
+ Unreachable,
+ Nop,
+ Block(BlockType),
+ Loop(BlockType),
+ If(BlockType),
+ Else,
+ End,
+ Br(u32),
+ BrIf(u32),
+ BrTable(Cow<'a, [u32]>, u32),
+ BrOnNull(u32),
+ BrOnNonNull(u32),
+ Return,
+ Call(u32),
+ CallRef(u32),
+ CallIndirect {
+ ty: u32,
+ table: u32,
+ },
+ ReturnCallRef(u32),
+ ReturnCall(u32),
+ ReturnCallIndirect {
+ ty: u32,
+ table: u32,
+ },
+ TryTable(BlockType, Cow<'a, [Catch]>),
+ Throw(u32),
+ ThrowRef,
+
+ // Deprecated exception-handling instructions
+ Try(BlockType),
+ Delegate(u32),
+ Catch(u32),
+ CatchAll,
+ Rethrow(u32),
+
+ // Parametric instructions.
+ Drop,
+ Select,
+
+ // Variable instructions.
+ LocalGet(u32),
+ LocalSet(u32),
+ LocalTee(u32),
+ GlobalGet(u32),
+ GlobalSet(u32),
+
+ // Memory instructions.
+ I32Load(MemArg),
+ I64Load(MemArg),
+ F32Load(MemArg),
+ F64Load(MemArg),
+ I32Load8S(MemArg),
+ I32Load8U(MemArg),
+ I32Load16S(MemArg),
+ I32Load16U(MemArg),
+ I64Load8S(MemArg),
+ I64Load8U(MemArg),
+ I64Load16S(MemArg),
+ I64Load16U(MemArg),
+ I64Load32S(MemArg),
+ I64Load32U(MemArg),
+ I32Store(MemArg),
+ I64Store(MemArg),
+ F32Store(MemArg),
+ F64Store(MemArg),
+ I32Store8(MemArg),
+ I32Store16(MemArg),
+ I64Store8(MemArg),
+ I64Store16(MemArg),
+ I64Store32(MemArg),
+ MemorySize(u32),
+ MemoryGrow(u32),
+ MemoryInit {
+ mem: u32,
+ data_index: u32,
+ },
+ DataDrop(u32),
+ MemoryCopy {
+ src_mem: u32,
+ dst_mem: u32,
+ },
+ MemoryFill(u32),
+ MemoryDiscard(u32),
+
+ // Numeric instructions.
+ I32Const(i32),
+ I64Const(i64),
+ F32Const(f32),
+ F64Const(f64),
+ I32Eqz,
+ I32Eq,
+ I32Ne,
+ I32LtS,
+ I32LtU,
+ I32GtS,
+ I32GtU,
+ I32LeS,
+ I32LeU,
+ I32GeS,
+ I32GeU,
+ I64Eqz,
+ I64Eq,
+ I64Ne,
+ I64LtS,
+ I64LtU,
+ I64GtS,
+ I64GtU,
+ I64LeS,
+ I64LeU,
+ I64GeS,
+ I64GeU,
+ F32Eq,
+ F32Ne,
+ F32Lt,
+ F32Gt,
+ F32Le,
+ F32Ge,
+ F64Eq,
+ F64Ne,
+ F64Lt,
+ F64Gt,
+ F64Le,
+ F64Ge,
+ I32Clz,
+ I32Ctz,
+ I32Popcnt,
+ I32Add,
+ I32Sub,
+ I32Mul,
+ I32DivS,
+ I32DivU,
+ I32RemS,
+ I32RemU,
+ I32And,
+ I32Or,
+ I32Xor,
+ I32Shl,
+ I32ShrS,
+ I32ShrU,
+ I32Rotl,
+ I32Rotr,
+ I64Clz,
+ I64Ctz,
+ I64Popcnt,
+ I64Add,
+ I64Sub,
+ I64Mul,
+ I64DivS,
+ I64DivU,
+ I64RemS,
+ I64RemU,
+ I64And,
+ I64Or,
+ I64Xor,
+ I64Shl,
+ I64ShrS,
+ I64ShrU,
+ I64Rotl,
+ I64Rotr,
+ F32Abs,
+ F32Neg,
+ F32Ceil,
+ F32Floor,
+ F32Trunc,
+ F32Nearest,
+ F32Sqrt,
+ F32Add,
+ F32Sub,
+ F32Mul,
+ F32Div,
+ F32Min,
+ F32Max,
+ F32Copysign,
+ F64Abs,
+ F64Neg,
+ F64Ceil,
+ F64Floor,
+ F64Trunc,
+ F64Nearest,
+ F64Sqrt,
+ F64Add,
+ F64Sub,
+ F64Mul,
+ F64Div,
+ F64Min,
+ F64Max,
+ F64Copysign,
+ I32WrapI64,
+ I32TruncF32S,
+ I32TruncF32U,
+ I32TruncF64S,
+ I32TruncF64U,
+ I64ExtendI32S,
+ I64ExtendI32U,
+ I64TruncF32S,
+ I64TruncF32U,
+ I64TruncF64S,
+ I64TruncF64U,
+ F32ConvertI32S,
+ F32ConvertI32U,
+ F32ConvertI64S,
+ F32ConvertI64U,
+ F32DemoteF64,
+ F64ConvertI32S,
+ F64ConvertI32U,
+ F64ConvertI64S,
+ F64ConvertI64U,
+ F64PromoteF32,
+ I32ReinterpretF32,
+ I64ReinterpretF64,
+ F32ReinterpretI32,
+ F64ReinterpretI64,
+ I32Extend8S,
+ I32Extend16S,
+ I64Extend8S,
+ I64Extend16S,
+ I64Extend32S,
+ I32TruncSatF32S,
+ I32TruncSatF32U,
+ I32TruncSatF64S,
+ I32TruncSatF64U,
+ I64TruncSatF32S,
+ I64TruncSatF32U,
+ I64TruncSatF64S,
+ I64TruncSatF64U,
+
+ // Reference types instructions.
+ TypedSelect(ValType),
+ RefNull(HeapType),
+ RefIsNull,
+ RefFunc(u32),
+ RefEq,
+ RefAsNonNull,
+
+ // GC types instructions.
+ StructNew(u32),
+ StructNewDefault(u32),
+ StructGet {
+ struct_type_index: u32,
+ field_index: u32,
+ },
+ StructGetS {
+ struct_type_index: u32,
+ field_index: u32,
+ },
+ StructGetU {
+ struct_type_index: u32,
+ field_index: u32,
+ },
+ StructSet {
+ struct_type_index: u32,
+ field_index: u32,
+ },
+
+ ArrayNew(u32),
+ ArrayNewDefault(u32),
+ ArrayNewFixed {
+ array_type_index: u32,
+ array_size: u32,
+ },
+ ArrayNewData {
+ array_type_index: u32,
+ array_data_index: u32,
+ },
+ ArrayNewElem {
+ array_type_index: u32,
+ array_elem_index: u32,
+ },
+ ArrayGet(u32),
+ ArrayGetS(u32),
+ ArrayGetU(u32),
+ ArraySet(u32),
+ ArrayLen,
+ ArrayFill(u32),
+ ArrayCopy {
+ array_type_index_dst: u32,
+ array_type_index_src: u32,
+ },
+ ArrayInitData {
+ array_type_index: u32,
+ array_data_index: u32,
+ },
+ ArrayInitElem {
+ array_type_index: u32,
+ array_elem_index: u32,
+ },
+ RefTestNonNull(HeapType),
+ RefTestNullable(HeapType),
+ RefCastNonNull(HeapType),
+ RefCastNullable(HeapType),
+ BrOnCast {
+ relative_depth: u32,
+ from_ref_type: RefType,
+ to_ref_type: RefType,
+ },
+ BrOnCastFail {
+ relative_depth: u32,
+ from_ref_type: RefType,
+ to_ref_type: RefType,
+ },
+ AnyConvertExtern,
+ ExternConvertAny,
+
+ RefI31,
+ I31GetS,
+ I31GetU,
+
+ // Bulk memory instructions.
+ TableInit {
+ elem_index: u32,
+ table: u32,
+ },
+ ElemDrop(u32),
+ TableFill(u32),
+ TableSet(u32),
+ TableGet(u32),
+ TableGrow(u32),
+ TableSize(u32),
+ TableCopy {
+ src_table: u32,
+ dst_table: u32,
+ },
+
+ // SIMD instructions.
+ V128Load(MemArg),
+ V128Load8x8S(MemArg),
+ V128Load8x8U(MemArg),
+ V128Load16x4S(MemArg),
+ V128Load16x4U(MemArg),
+ V128Load32x2S(MemArg),
+ V128Load32x2U(MemArg),
+ V128Load8Splat(MemArg),
+ V128Load16Splat(MemArg),
+ V128Load32Splat(MemArg),
+ V128Load64Splat(MemArg),
+ V128Load32Zero(MemArg),
+ V128Load64Zero(MemArg),
+ V128Store(MemArg),
+ V128Load8Lane {
+ memarg: MemArg,
+ lane: Lane,
+ },
+ V128Load16Lane {
+ memarg: MemArg,
+ lane: Lane,
+ },
+ V128Load32Lane {
+ memarg: MemArg,
+ lane: Lane,
+ },
+ V128Load64Lane {
+ memarg: MemArg,
+ lane: Lane,
+ },
+ V128Store8Lane {
+ memarg: MemArg,
+ lane: Lane,
+ },
+ V128Store16Lane {
+ memarg: MemArg,
+ lane: Lane,
+ },
+ V128Store32Lane {
+ memarg: MemArg,
+ lane: Lane,
+ },
+ V128Store64Lane {
+ memarg: MemArg,
+ lane: Lane,
+ },
+ V128Const(i128),
+ I8x16Shuffle([Lane; 16]),
+ I8x16ExtractLaneS(Lane),
+ I8x16ExtractLaneU(Lane),
+ I8x16ReplaceLane(Lane),
+ I16x8ExtractLaneS(Lane),
+ I16x8ExtractLaneU(Lane),
+ I16x8ReplaceLane(Lane),
+ I32x4ExtractLane(Lane),
+ I32x4ReplaceLane(Lane),
+ I64x2ExtractLane(Lane),
+ I64x2ReplaceLane(Lane),
+ F32x4ExtractLane(Lane),
+ F32x4ReplaceLane(Lane),
+ F64x2ExtractLane(Lane),
+ F64x2ReplaceLane(Lane),
+ I8x16Swizzle,
+ I8x16Splat,
+ I16x8Splat,
+ I32x4Splat,
+ I64x2Splat,
+ F32x4Splat,
+ F64x2Splat,
+ I8x16Eq,
+ I8x16Ne,
+ I8x16LtS,
+ I8x16LtU,
+ I8x16GtS,
+ I8x16GtU,
+ I8x16LeS,
+ I8x16LeU,
+ I8x16GeS,
+ I8x16GeU,
+ I16x8Eq,
+ I16x8Ne,
+ I16x8LtS,
+ I16x8LtU,
+ I16x8GtS,
+ I16x8GtU,
+ I16x8LeS,
+ I16x8LeU,
+ I16x8GeS,
+ I16x8GeU,
+ I32x4Eq,
+ I32x4Ne,
+ I32x4LtS,
+ I32x4LtU,
+ I32x4GtS,
+ I32x4GtU,
+ I32x4LeS,
+ I32x4LeU,
+ I32x4GeS,
+ I32x4GeU,
+ I64x2Eq,
+ I64x2Ne,
+ I64x2LtS,
+ I64x2GtS,
+ I64x2LeS,
+ I64x2GeS,
+ F32x4Eq,
+ F32x4Ne,
+ F32x4Lt,
+ F32x4Gt,
+ F32x4Le,
+ F32x4Ge,
+ F64x2Eq,
+ F64x2Ne,
+ F64x2Lt,
+ F64x2Gt,
+ F64x2Le,
+ F64x2Ge,
+ V128Not,
+ V128And,
+ V128AndNot,
+ V128Or,
+ V128Xor,
+ V128Bitselect,
+ V128AnyTrue,
+ I8x16Abs,
+ I8x16Neg,
+ I8x16Popcnt,
+ I8x16AllTrue,
+ I8x16Bitmask,
+ I8x16NarrowI16x8S,
+ I8x16NarrowI16x8U,
+ I8x16Shl,
+ I8x16ShrS,
+ I8x16ShrU,
+ I8x16Add,
+ I8x16AddSatS,
+ I8x16AddSatU,
+ I8x16Sub,
+ I8x16SubSatS,
+ I8x16SubSatU,
+ I8x16MinS,
+ I8x16MinU,
+ I8x16MaxS,
+ I8x16MaxU,
+ I8x16AvgrU,
+ I16x8ExtAddPairwiseI8x16S,
+ I16x8ExtAddPairwiseI8x16U,
+ I16x8Abs,
+ I16x8Neg,
+ I16x8Q15MulrSatS,
+ I16x8AllTrue,
+ I16x8Bitmask,
+ I16x8NarrowI32x4S,
+ I16x8NarrowI32x4U,
+ I16x8ExtendLowI8x16S,
+ I16x8ExtendHighI8x16S,
+ I16x8ExtendLowI8x16U,
+ I16x8ExtendHighI8x16U,
+ I16x8Shl,
+ I16x8ShrS,
+ I16x8ShrU,
+ I16x8Add,
+ I16x8AddSatS,
+ I16x8AddSatU,
+ I16x8Sub,
+ I16x8SubSatS,
+ I16x8SubSatU,
+ I16x8Mul,
+ I16x8MinS,
+ I16x8MinU,
+ I16x8MaxS,
+ I16x8MaxU,
+ I16x8AvgrU,
+ I16x8ExtMulLowI8x16S,
+ I16x8ExtMulHighI8x16S,
+ I16x8ExtMulLowI8x16U,
+ I16x8ExtMulHighI8x16U,
+ I32x4ExtAddPairwiseI16x8S,
+ I32x4ExtAddPairwiseI16x8U,
+ I32x4Abs,
+ I32x4Neg,
+ I32x4AllTrue,
+ I32x4Bitmask,
+ I32x4ExtendLowI16x8S,
+ I32x4ExtendHighI16x8S,
+ I32x4ExtendLowI16x8U,
+ I32x4ExtendHighI16x8U,
+ I32x4Shl,
+ I32x4ShrS,
+ I32x4ShrU,
+ I32x4Add,
+ I32x4Sub,
+ I32x4Mul,
+ I32x4MinS,
+ I32x4MinU,
+ I32x4MaxS,
+ I32x4MaxU,
+ I32x4DotI16x8S,
+ I32x4ExtMulLowI16x8S,
+ I32x4ExtMulHighI16x8S,
+ I32x4ExtMulLowI16x8U,
+ I32x4ExtMulHighI16x8U,
+ I64x2Abs,
+ I64x2Neg,
+ I64x2AllTrue,
+ I64x2Bitmask,
+ I64x2ExtendLowI32x4S,
+ I64x2ExtendHighI32x4S,
+ I64x2ExtendLowI32x4U,
+ I64x2ExtendHighI32x4U,
+ I64x2Shl,
+ I64x2ShrS,
+ I64x2ShrU,
+ I64x2Add,
+ I64x2Sub,
+ I64x2Mul,
+ I64x2ExtMulLowI32x4S,
+ I64x2ExtMulHighI32x4S,
+ I64x2ExtMulLowI32x4U,
+ I64x2ExtMulHighI32x4U,
+ F32x4Ceil,
+ F32x4Floor,
+ F32x4Trunc,
+ F32x4Nearest,
+ F32x4Abs,
+ F32x4Neg,
+ F32x4Sqrt,
+ F32x4Add,
+ F32x4Sub,
+ F32x4Mul,
+ F32x4Div,
+ F32x4Min,
+ F32x4Max,
+ F32x4PMin,
+ F32x4PMax,
+ F64x2Ceil,
+ F64x2Floor,
+ F64x2Trunc,
+ F64x2Nearest,
+ F64x2Abs,
+ F64x2Neg,
+ F64x2Sqrt,
+ F64x2Add,
+ F64x2Sub,
+ F64x2Mul,
+ F64x2Div,
+ F64x2Min,
+ F64x2Max,
+ F64x2PMin,
+ F64x2PMax,
+ I32x4TruncSatF32x4S,
+ I32x4TruncSatF32x4U,
+ F32x4ConvertI32x4S,
+ F32x4ConvertI32x4U,
+ I32x4TruncSatF64x2SZero,
+ I32x4TruncSatF64x2UZero,
+ F64x2ConvertLowI32x4S,
+ F64x2ConvertLowI32x4U,
+ F32x4DemoteF64x2Zero,
+ F64x2PromoteLowF32x4,
+
+ // Relaxed simd proposal
+ I8x16RelaxedSwizzle,
+ I32x4RelaxedTruncF32x4S,
+ I32x4RelaxedTruncF32x4U,
+ I32x4RelaxedTruncF64x2SZero,
+ I32x4RelaxedTruncF64x2UZero,
+ F32x4RelaxedMadd,
+ F32x4RelaxedNmadd,
+ F64x2RelaxedMadd,
+ F64x2RelaxedNmadd,
+ I8x16RelaxedLaneselect,
+ I16x8RelaxedLaneselect,
+ I32x4RelaxedLaneselect,
+ I64x2RelaxedLaneselect,
+ F32x4RelaxedMin,
+ F32x4RelaxedMax,
+ F64x2RelaxedMin,
+ F64x2RelaxedMax,
+ I16x8RelaxedQ15mulrS,
+ I16x8RelaxedDotI8x16I7x16S,
+ I32x4RelaxedDotI8x16I7x16AddS,
+
+ // Atomic instructions (the threads proposal)
+ MemoryAtomicNotify(MemArg),
+ MemoryAtomicWait32(MemArg),
+ MemoryAtomicWait64(MemArg),
+ AtomicFence,
+ I32AtomicLoad(MemArg),
+ I64AtomicLoad(MemArg),
+ I32AtomicLoad8U(MemArg),
+ I32AtomicLoad16U(MemArg),
+ I64AtomicLoad8U(MemArg),
+ I64AtomicLoad16U(MemArg),
+ I64AtomicLoad32U(MemArg),
+ I32AtomicStore(MemArg),
+ I64AtomicStore(MemArg),
+ I32AtomicStore8(MemArg),
+ I32AtomicStore16(MemArg),
+ I64AtomicStore8(MemArg),
+ I64AtomicStore16(MemArg),
+ I64AtomicStore32(MemArg),
+ I32AtomicRmwAdd(MemArg),
+ I64AtomicRmwAdd(MemArg),
+ I32AtomicRmw8AddU(MemArg),
+ I32AtomicRmw16AddU(MemArg),
+ I64AtomicRmw8AddU(MemArg),
+ I64AtomicRmw16AddU(MemArg),
+ I64AtomicRmw32AddU(MemArg),
+ I32AtomicRmwSub(MemArg),
+ I64AtomicRmwSub(MemArg),
+ I32AtomicRmw8SubU(MemArg),
+ I32AtomicRmw16SubU(MemArg),
+ I64AtomicRmw8SubU(MemArg),
+ I64AtomicRmw16SubU(MemArg),
+ I64AtomicRmw32SubU(MemArg),
+ I32AtomicRmwAnd(MemArg),
+ I64AtomicRmwAnd(MemArg),
+ I32AtomicRmw8AndU(MemArg),
+ I32AtomicRmw16AndU(MemArg),
+ I64AtomicRmw8AndU(MemArg),
+ I64AtomicRmw16AndU(MemArg),
+ I64AtomicRmw32AndU(MemArg),
+ I32AtomicRmwOr(MemArg),
+ I64AtomicRmwOr(MemArg),
+ I32AtomicRmw8OrU(MemArg),
+ I32AtomicRmw16OrU(MemArg),
+ I64AtomicRmw8OrU(MemArg),
+ I64AtomicRmw16OrU(MemArg),
+ I64AtomicRmw32OrU(MemArg),
+ I32AtomicRmwXor(MemArg),
+ I64AtomicRmwXor(MemArg),
+ I32AtomicRmw8XorU(MemArg),
+ I32AtomicRmw16XorU(MemArg),
+ I64AtomicRmw8XorU(MemArg),
+ I64AtomicRmw16XorU(MemArg),
+ I64AtomicRmw32XorU(MemArg),
+ I32AtomicRmwXchg(MemArg),
+ I64AtomicRmwXchg(MemArg),
+ I32AtomicRmw8XchgU(MemArg),
+ I32AtomicRmw16XchgU(MemArg),
+ I64AtomicRmw8XchgU(MemArg),
+ I64AtomicRmw16XchgU(MemArg),
+ I64AtomicRmw32XchgU(MemArg),
+ I32AtomicRmwCmpxchg(MemArg),
+ I64AtomicRmwCmpxchg(MemArg),
+ I32AtomicRmw8CmpxchgU(MemArg),
+ I32AtomicRmw16CmpxchgU(MemArg),
+ I64AtomicRmw8CmpxchgU(MemArg),
+ I64AtomicRmw16CmpxchgU(MemArg),
+ I64AtomicRmw32CmpxchgU(MemArg),
+}
+
+impl Encode for Instruction<'_> {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ match *self {
+ // Control instructions.
+ Instruction::Unreachable => sink.push(0x00),
+ Instruction::Nop => sink.push(0x01),
+ Instruction::Block(bt) => {
+ sink.push(0x02);
+ bt.encode(sink);
+ }
+ Instruction::Loop(bt) => {
+ sink.push(0x03);
+ bt.encode(sink);
+ }
+ Instruction::If(bt) => {
+ sink.push(0x04);
+ bt.encode(sink);
+ }
+ Instruction::Else => sink.push(0x05),
+ Instruction::Try(bt) => {
+ sink.push(0x06);
+ bt.encode(sink);
+ }
+ Instruction::Catch(t) => {
+ sink.push(0x07);
+ t.encode(sink);
+ }
+ Instruction::Throw(t) => {
+ sink.push(0x08);
+ t.encode(sink);
+ }
+ Instruction::Rethrow(l) => {
+ sink.push(0x09);
+ l.encode(sink);
+ }
+ Instruction::ThrowRef => {
+ sink.push(0x0A);
+ }
+ Instruction::End => sink.push(0x0B),
+ Instruction::Br(l) => {
+ sink.push(0x0C);
+ l.encode(sink);
+ }
+ Instruction::BrIf(l) => {
+ sink.push(0x0D);
+ l.encode(sink);
+ }
+ Instruction::BrTable(ref ls, l) => {
+ sink.push(0x0E);
+ ls.encode(sink);
+ l.encode(sink);
+ }
+ Instruction::BrOnNull(l) => {
+ sink.push(0xD5);
+ l.encode(sink);
+ }
+ Instruction::BrOnNonNull(l) => {
+ sink.push(0xD6);
+ l.encode(sink);
+ }
+ Instruction::Return => sink.push(0x0F),
+ Instruction::Call(f) => {
+ sink.push(0x10);
+ f.encode(sink);
+ }
+ Instruction::CallRef(ty) => {
+ sink.push(0x14);
+ ty.encode(sink);
+ }
+ Instruction::CallIndirect { ty, table } => {
+ sink.push(0x11);
+ ty.encode(sink);
+ table.encode(sink);
+ }
+ Instruction::ReturnCallRef(ty) => {
+ sink.push(0x15);
+ ty.encode(sink);
+ }
+
+ Instruction::ReturnCall(f) => {
+ sink.push(0x12);
+ f.encode(sink);
+ }
+ Instruction::ReturnCallIndirect { ty, table } => {
+ sink.push(0x13);
+ ty.encode(sink);
+ table.encode(sink);
+ }
+ Instruction::Delegate(l) => {
+ sink.push(0x18);
+ l.encode(sink);
+ }
+ Instruction::CatchAll => {
+ sink.push(0x19);
+ }
+
+ // Parametric instructions.
+ Instruction::Drop => sink.push(0x1A),
+ Instruction::Select => sink.push(0x1B),
+ Instruction::TypedSelect(ty) => {
+ sink.push(0x1c);
+ [ty].encode(sink);
+ }
+
+ Instruction::TryTable(ty, ref catches) => {
+ sink.push(0x1f);
+ ty.encode(sink);
+ catches.encode(sink);
+ }
+
+ // Variable instructions.
+ Instruction::LocalGet(l) => {
+ sink.push(0x20);
+ l.encode(sink);
+ }
+ Instruction::LocalSet(l) => {
+ sink.push(0x21);
+ l.encode(sink);
+ }
+ Instruction::LocalTee(l) => {
+ sink.push(0x22);
+ l.encode(sink);
+ }
+ Instruction::GlobalGet(g) => {
+ sink.push(0x23);
+ g.encode(sink);
+ }
+ Instruction::GlobalSet(g) => {
+ sink.push(0x24);
+ g.encode(sink);
+ }
+ Instruction::TableGet(table) => {
+ sink.push(0x25);
+ table.encode(sink);
+ }
+ Instruction::TableSet(table) => {
+ sink.push(0x26);
+ table.encode(sink);
+ }
+
+ // Memory instructions.
+ Instruction::I32Load(m) => {
+ sink.push(0x28);
+ m.encode(sink);
+ }
+ Instruction::I64Load(m) => {
+ sink.push(0x29);
+ m.encode(sink);
+ }
+ Instruction::F32Load(m) => {
+ sink.push(0x2A);
+ m.encode(sink);
+ }
+ Instruction::F64Load(m) => {
+ sink.push(0x2B);
+ m.encode(sink);
+ }
+ Instruction::I32Load8S(m) => {
+ sink.push(0x2C);
+ m.encode(sink);
+ }
+ Instruction::I32Load8U(m) => {
+ sink.push(0x2D);
+ m.encode(sink);
+ }
+ Instruction::I32Load16S(m) => {
+ sink.push(0x2E);
+ m.encode(sink);
+ }
+ Instruction::I32Load16U(m) => {
+ sink.push(0x2F);
+ m.encode(sink);
+ }
+ Instruction::I64Load8S(m) => {
+ sink.push(0x30);
+ m.encode(sink);
+ }
+ Instruction::I64Load8U(m) => {
+ sink.push(0x31);
+ m.encode(sink);
+ }
+ Instruction::I64Load16S(m) => {
+ sink.push(0x32);
+ m.encode(sink);
+ }
+ Instruction::I64Load16U(m) => {
+ sink.push(0x33);
+ m.encode(sink);
+ }
+ Instruction::I64Load32S(m) => {
+ sink.push(0x34);
+ m.encode(sink);
+ }
+ Instruction::I64Load32U(m) => {
+ sink.push(0x35);
+ m.encode(sink);
+ }
+ Instruction::I32Store(m) => {
+ sink.push(0x36);
+ m.encode(sink);
+ }
+ Instruction::I64Store(m) => {
+ sink.push(0x37);
+ m.encode(sink);
+ }
+ Instruction::F32Store(m) => {
+ sink.push(0x38);
+ m.encode(sink);
+ }
+ Instruction::F64Store(m) => {
+ sink.push(0x39);
+ m.encode(sink);
+ }
+ Instruction::I32Store8(m) => {
+ sink.push(0x3A);
+ m.encode(sink);
+ }
+ Instruction::I32Store16(m) => {
+ sink.push(0x3B);
+ m.encode(sink);
+ }
+ Instruction::I64Store8(m) => {
+ sink.push(0x3C);
+ m.encode(sink);
+ }
+ Instruction::I64Store16(m) => {
+ sink.push(0x3D);
+ m.encode(sink);
+ }
+ Instruction::I64Store32(m) => {
+ sink.push(0x3E);
+ m.encode(sink);
+ }
+ Instruction::MemorySize(i) => {
+ sink.push(0x3F);
+ i.encode(sink);
+ }
+ Instruction::MemoryGrow(i) => {
+ sink.push(0x40);
+ i.encode(sink);
+ }
+ Instruction::MemoryInit { mem, data_index } => {
+ sink.push(0xfc);
+ sink.push(0x08);
+ data_index.encode(sink);
+ mem.encode(sink);
+ }
+ Instruction::DataDrop(data) => {
+ sink.push(0xfc);
+ sink.push(0x09);
+ data.encode(sink);
+ }
+ Instruction::MemoryCopy { src_mem, dst_mem } => {
+ sink.push(0xfc);
+ sink.push(0x0a);
+ dst_mem.encode(sink);
+ src_mem.encode(sink);
+ }
+ Instruction::MemoryFill(mem) => {
+ sink.push(0xfc);
+ sink.push(0x0b);
+ mem.encode(sink);
+ }
+ Instruction::MemoryDiscard(mem) => {
+ sink.push(0xfc);
+ sink.push(0x12);
+ mem.encode(sink);
+ }
+
+ // Numeric instructions.
+ Instruction::I32Const(x) => {
+ sink.push(0x41);
+ x.encode(sink);
+ }
+ Instruction::I64Const(x) => {
+ sink.push(0x42);
+ x.encode(sink);
+ }
+ Instruction::F32Const(x) => {
+ sink.push(0x43);
+ let x = x.to_bits();
+ sink.extend(x.to_le_bytes().iter().copied());
+ }
+ Instruction::F64Const(x) => {
+ sink.push(0x44);
+ let x = x.to_bits();
+ sink.extend(x.to_le_bytes().iter().copied());
+ }
+ Instruction::I32Eqz => sink.push(0x45),
+ Instruction::I32Eq => sink.push(0x46),
+ Instruction::I32Ne => sink.push(0x47),
+ Instruction::I32LtS => sink.push(0x48),
+ Instruction::I32LtU => sink.push(0x49),
+ Instruction::I32GtS => sink.push(0x4A),
+ Instruction::I32GtU => sink.push(0x4B),
+ Instruction::I32LeS => sink.push(0x4C),
+ Instruction::I32LeU => sink.push(0x4D),
+ Instruction::I32GeS => sink.push(0x4E),
+ Instruction::I32GeU => sink.push(0x4F),
+ Instruction::I64Eqz => sink.push(0x50),
+ Instruction::I64Eq => sink.push(0x51),
+ Instruction::I64Ne => sink.push(0x52),
+ Instruction::I64LtS => sink.push(0x53),
+ Instruction::I64LtU => sink.push(0x54),
+ Instruction::I64GtS => sink.push(0x55),
+ Instruction::I64GtU => sink.push(0x56),
+ Instruction::I64LeS => sink.push(0x57),
+ Instruction::I64LeU => sink.push(0x58),
+ Instruction::I64GeS => sink.push(0x59),
+ Instruction::I64GeU => sink.push(0x5A),
+ Instruction::F32Eq => sink.push(0x5B),
+ Instruction::F32Ne => sink.push(0x5C),
+ Instruction::F32Lt => sink.push(0x5D),
+ Instruction::F32Gt => sink.push(0x5E),
+ Instruction::F32Le => sink.push(0x5F),
+ Instruction::F32Ge => sink.push(0x60),
+ Instruction::F64Eq => sink.push(0x61),
+ Instruction::F64Ne => sink.push(0x62),
+ Instruction::F64Lt => sink.push(0x63),
+ Instruction::F64Gt => sink.push(0x64),
+ Instruction::F64Le => sink.push(0x65),
+ Instruction::F64Ge => sink.push(0x66),
+ Instruction::I32Clz => sink.push(0x67),
+ Instruction::I32Ctz => sink.push(0x68),
+ Instruction::I32Popcnt => sink.push(0x69),
+ Instruction::I32Add => sink.push(0x6A),
+ Instruction::I32Sub => sink.push(0x6B),
+ Instruction::I32Mul => sink.push(0x6C),
+ Instruction::I32DivS => sink.push(0x6D),
+ Instruction::I32DivU => sink.push(0x6E),
+ Instruction::I32RemS => sink.push(0x6F),
+ Instruction::I32RemU => sink.push(0x70),
+ Instruction::I32And => sink.push(0x71),
+ Instruction::I32Or => sink.push(0x72),
+ Instruction::I32Xor => sink.push(0x73),
+ Instruction::I32Shl => sink.push(0x74),
+ Instruction::I32ShrS => sink.push(0x75),
+ Instruction::I32ShrU => sink.push(0x76),
+ Instruction::I32Rotl => sink.push(0x77),
+ Instruction::I32Rotr => sink.push(0x78),
+ Instruction::I64Clz => sink.push(0x79),
+ Instruction::I64Ctz => sink.push(0x7A),
+ Instruction::I64Popcnt => sink.push(0x7B),
+ Instruction::I64Add => sink.push(0x7C),
+ Instruction::I64Sub => sink.push(0x7D),
+ Instruction::I64Mul => sink.push(0x7E),
+ Instruction::I64DivS => sink.push(0x7F),
+ Instruction::I64DivU => sink.push(0x80),
+ Instruction::I64RemS => sink.push(0x81),
+ Instruction::I64RemU => sink.push(0x82),
+ Instruction::I64And => sink.push(0x83),
+ Instruction::I64Or => sink.push(0x84),
+ Instruction::I64Xor => sink.push(0x85),
+ Instruction::I64Shl => sink.push(0x86),
+ Instruction::I64ShrS => sink.push(0x87),
+ Instruction::I64ShrU => sink.push(0x88),
+ Instruction::I64Rotl => sink.push(0x89),
+ Instruction::I64Rotr => sink.push(0x8A),
+ Instruction::F32Abs => sink.push(0x8B),
+ Instruction::F32Neg => sink.push(0x8C),
+ Instruction::F32Ceil => sink.push(0x8D),
+ Instruction::F32Floor => sink.push(0x8E),
+ Instruction::F32Trunc => sink.push(0x8F),
+ Instruction::F32Nearest => sink.push(0x90),
+ Instruction::F32Sqrt => sink.push(0x91),
+ Instruction::F32Add => sink.push(0x92),
+ Instruction::F32Sub => sink.push(0x93),
+ Instruction::F32Mul => sink.push(0x94),
+ Instruction::F32Div => sink.push(0x95),
+ Instruction::F32Min => sink.push(0x96),
+ Instruction::F32Max => sink.push(0x97),
+ Instruction::F32Copysign => sink.push(0x98),
+ Instruction::F64Abs => sink.push(0x99),
+ Instruction::F64Neg => sink.push(0x9A),
+ Instruction::F64Ceil => sink.push(0x9B),
+ Instruction::F64Floor => sink.push(0x9C),
+ Instruction::F64Trunc => sink.push(0x9D),
+ Instruction::F64Nearest => sink.push(0x9E),
+ Instruction::F64Sqrt => sink.push(0x9F),
+ Instruction::F64Add => sink.push(0xA0),
+ Instruction::F64Sub => sink.push(0xA1),
+ Instruction::F64Mul => sink.push(0xA2),
+ Instruction::F64Div => sink.push(0xA3),
+ Instruction::F64Min => sink.push(0xA4),
+ Instruction::F64Max => sink.push(0xA5),
+ Instruction::F64Copysign => sink.push(0xA6),
+ Instruction::I32WrapI64 => sink.push(0xA7),
+ Instruction::I32TruncF32S => sink.push(0xA8),
+ Instruction::I32TruncF32U => sink.push(0xA9),
+ Instruction::I32TruncF64S => sink.push(0xAA),
+ Instruction::I32TruncF64U => sink.push(0xAB),
+ Instruction::I64ExtendI32S => sink.push(0xAC),
+ Instruction::I64ExtendI32U => sink.push(0xAD),
+ Instruction::I64TruncF32S => sink.push(0xAE),
+ Instruction::I64TruncF32U => sink.push(0xAF),
+ Instruction::I64TruncF64S => sink.push(0xB0),
+ Instruction::I64TruncF64U => sink.push(0xB1),
+ Instruction::F32ConvertI32S => sink.push(0xB2),
+ Instruction::F32ConvertI32U => sink.push(0xB3),
+ Instruction::F32ConvertI64S => sink.push(0xB4),
+ Instruction::F32ConvertI64U => sink.push(0xB5),
+ Instruction::F32DemoteF64 => sink.push(0xB6),
+ Instruction::F64ConvertI32S => sink.push(0xB7),
+ Instruction::F64ConvertI32U => sink.push(0xB8),
+ Instruction::F64ConvertI64S => sink.push(0xB9),
+ Instruction::F64ConvertI64U => sink.push(0xBA),
+ Instruction::F64PromoteF32 => sink.push(0xBB),
+ Instruction::I32ReinterpretF32 => sink.push(0xBC),
+ Instruction::I64ReinterpretF64 => sink.push(0xBD),
+ Instruction::F32ReinterpretI32 => sink.push(0xBE),
+ Instruction::F64ReinterpretI64 => sink.push(0xBF),
+ Instruction::I32Extend8S => sink.push(0xC0),
+ Instruction::I32Extend16S => sink.push(0xC1),
+ Instruction::I64Extend8S => sink.push(0xC2),
+ Instruction::I64Extend16S => sink.push(0xC3),
+ Instruction::I64Extend32S => sink.push(0xC4),
+
+ Instruction::I32TruncSatF32S => {
+ sink.push(0xFC);
+ sink.push(0x00);
+ }
+ Instruction::I32TruncSatF32U => {
+ sink.push(0xFC);
+ sink.push(0x01);
+ }
+ Instruction::I32TruncSatF64S => {
+ sink.push(0xFC);
+ sink.push(0x02);
+ }
+ Instruction::I32TruncSatF64U => {
+ sink.push(0xFC);
+ sink.push(0x03);
+ }
+ Instruction::I64TruncSatF32S => {
+ sink.push(0xFC);
+ sink.push(0x04);
+ }
+ Instruction::I64TruncSatF32U => {
+ sink.push(0xFC);
+ sink.push(0x05);
+ }
+ Instruction::I64TruncSatF64S => {
+ sink.push(0xFC);
+ sink.push(0x06);
+ }
+ Instruction::I64TruncSatF64U => {
+ sink.push(0xFC);
+ sink.push(0x07);
+ }
+
+ // Reference types instructions.
+ Instruction::RefNull(ty) => {
+ sink.push(0xd0);
+ ty.encode(sink);
+ }
+ Instruction::RefIsNull => sink.push(0xd1),
+ Instruction::RefFunc(f) => {
+ sink.push(0xd2);
+ f.encode(sink);
+ }
+ Instruction::RefEq => sink.push(0xd3),
+ Instruction::RefAsNonNull => sink.push(0xd4),
+
+ // GC instructions.
+ Instruction::StructNew(type_index) => {
+ sink.push(0xfb);
+ sink.push(0x00);
+ type_index.encode(sink);
+ }
+ Instruction::StructNewDefault(type_index) => {
+ sink.push(0xfb);
+ sink.push(0x01);
+ type_index.encode(sink);
+ }
+ Instruction::StructGet {
+ struct_type_index,
+ field_index,
+ } => {
+ sink.push(0xfb);
+ sink.push(0x02);
+ struct_type_index.encode(sink);
+ field_index.encode(sink);
+ }
+ Instruction::StructGetS {
+ struct_type_index,
+ field_index,
+ } => {
+ sink.push(0xfb);
+ sink.push(0x03);
+ struct_type_index.encode(sink);
+ field_index.encode(sink);
+ }
+ Instruction::StructGetU {
+ struct_type_index,
+ field_index,
+ } => {
+ sink.push(0xfb);
+ sink.push(0x04);
+ struct_type_index.encode(sink);
+ field_index.encode(sink);
+ }
+ Instruction::StructSet {
+ struct_type_index,
+ field_index,
+ } => {
+ sink.push(0xfb);
+ sink.push(0x05);
+ struct_type_index.encode(sink);
+ field_index.encode(sink);
+ }
+ Instruction::ArrayNew(type_index) => {
+ sink.push(0xfb);
+ sink.push(0x06);
+ type_index.encode(sink);
+ }
+ Instruction::ArrayNewDefault(type_index) => {
+ sink.push(0xfb);
+ sink.push(0x07);
+ type_index.encode(sink);
+ }
+ Instruction::ArrayNewFixed {
+ array_type_index,
+ array_size,
+ } => {
+ sink.push(0xfb);
+ sink.push(0x08);
+ array_type_index.encode(sink);
+ array_size.encode(sink);
+ }
+ Instruction::ArrayNewData {
+ array_type_index,
+ array_data_index,
+ } => {
+ sink.push(0xfb);
+ sink.push(0x09);
+ array_type_index.encode(sink);
+ array_data_index.encode(sink);
+ }
+ Instruction::ArrayNewElem {
+ array_type_index,
+ array_elem_index,
+ } => {
+ sink.push(0xfb);
+ sink.push(0x0a);
+ array_type_index.encode(sink);
+ array_elem_index.encode(sink);
+ }
+ Instruction::ArrayGet(type_index) => {
+ sink.push(0xfb);
+ sink.push(0x0b);
+ type_index.encode(sink);
+ }
+ Instruction::ArrayGetS(type_index) => {
+ sink.push(0xfb);
+ sink.push(0x0c);
+ type_index.encode(sink);
+ }
+ Instruction::ArrayGetU(type_index) => {
+ sink.push(0xfb);
+ sink.push(0x0d);
+ type_index.encode(sink);
+ }
+ Instruction::ArraySet(type_index) => {
+ sink.push(0xfb);
+ sink.push(0x0e);
+ type_index.encode(sink);
+ }
+ Instruction::ArrayLen => {
+ sink.push(0xfb);
+ sink.push(0x0f);
+ }
+ Instruction::ArrayFill(type_index) => {
+ sink.push(0xfb);
+ sink.push(0x10);
+ type_index.encode(sink);
+ }
+ Instruction::ArrayCopy {
+ array_type_index_dst,
+ array_type_index_src,
+ } => {
+ sink.push(0xfb);
+ sink.push(0x11);
+ array_type_index_dst.encode(sink);
+ array_type_index_src.encode(sink);
+ }
+ Instruction::ArrayInitData {
+ array_type_index,
+ array_data_index,
+ } => {
+ sink.push(0xfb);
+ sink.push(0x12);
+ array_type_index.encode(sink);
+ array_data_index.encode(sink);
+ }
+ Instruction::ArrayInitElem {
+ array_type_index,
+ array_elem_index,
+ } => {
+ sink.push(0xfb);
+ sink.push(0x13);
+ array_type_index.encode(sink);
+ array_elem_index.encode(sink);
+ }
+ Instruction::RefTestNonNull(heap_type) => {
+ sink.push(0xfb);
+ sink.push(0x14);
+ heap_type.encode(sink);
+ }
+ Instruction::RefTestNullable(heap_type) => {
+ sink.push(0xfb);
+ sink.push(0x15);
+ heap_type.encode(sink);
+ }
+ Instruction::RefCastNonNull(heap_type) => {
+ sink.push(0xfb);
+ sink.push(0x16);
+ heap_type.encode(sink);
+ }
+ Instruction::RefCastNullable(heap_type) => {
+ sink.push(0xfb);
+ sink.push(0x17);
+ heap_type.encode(sink);
+ }
+ Instruction::BrOnCast {
+ relative_depth,
+ from_ref_type,
+ to_ref_type,
+ } => {
+ sink.push(0xfb);
+ sink.push(0x18);
+ let cast_flags =
+ (from_ref_type.nullable as u8) | ((to_ref_type.nullable as u8) << 1);
+ sink.push(cast_flags);
+ relative_depth.encode(sink);
+ from_ref_type.heap_type.encode(sink);
+ to_ref_type.heap_type.encode(sink);
+ }
+ Instruction::BrOnCastFail {
+ relative_depth,
+ from_ref_type,
+ to_ref_type,
+ } => {
+ sink.push(0xfb);
+ sink.push(0x19);
+ let cast_flags =
+ (from_ref_type.nullable as u8) | ((to_ref_type.nullable as u8) << 1);
+ sink.push(cast_flags);
+ relative_depth.encode(sink);
+ from_ref_type.heap_type.encode(sink);
+ to_ref_type.heap_type.encode(sink);
+ }
+ Instruction::AnyConvertExtern => {
+ sink.push(0xfb);
+ sink.push(0x1a);
+ }
+ Instruction::ExternConvertAny => {
+ sink.push(0xfb);
+ sink.push(0x1b);
+ }
+ Instruction::RefI31 => {
+ sink.push(0xfb);
+ sink.push(0x1c);
+ }
+ Instruction::I31GetS => {
+ sink.push(0xfb);
+ sink.push(0x1d);
+ }
+ Instruction::I31GetU => {
+ sink.push(0xfb);
+ sink.push(0x1e);
+ }
+
+ // Bulk memory instructions.
+ Instruction::TableInit { elem_index, table } => {
+ sink.push(0xfc);
+ sink.push(0x0c);
+ elem_index.encode(sink);
+ table.encode(sink);
+ }
+ Instruction::ElemDrop(segment) => {
+ sink.push(0xfc);
+ sink.push(0x0d);
+ segment.encode(sink);
+ }
+ Instruction::TableCopy {
+ src_table,
+ dst_table,
+ } => {
+ sink.push(0xfc);
+ sink.push(0x0e);
+ dst_table.encode(sink);
+ src_table.encode(sink);
+ }
+ Instruction::TableGrow(table) => {
+ sink.push(0xfc);
+ sink.push(0x0f);
+ table.encode(sink);
+ }
+ Instruction::TableSize(table) => {
+ sink.push(0xfc);
+ sink.push(0x10);
+ table.encode(sink);
+ }
+ Instruction::TableFill(table) => {
+ sink.push(0xfc);
+ sink.push(0x11);
+ table.encode(sink);
+ }
+
+ // SIMD instructions.
+ Instruction::V128Load(memarg) => {
+ sink.push(0xFD);
+ 0x00u32.encode(sink);
+ memarg.encode(sink);
+ }
+ Instruction::V128Load8x8S(memarg) => {
+ sink.push(0xFD);
+ 0x01u32.encode(sink);
+ memarg.encode(sink);
+ }
+ Instruction::V128Load8x8U(memarg) => {
+ sink.push(0xFD);
+ 0x02u32.encode(sink);
+ memarg.encode(sink);
+ }
+ Instruction::V128Load16x4S(memarg) => {
+ sink.push(0xFD);
+ 0x03u32.encode(sink);
+ memarg.encode(sink);
+ }
+ Instruction::V128Load16x4U(memarg) => {
+ sink.push(0xFD);
+ 0x04u32.encode(sink);
+ memarg.encode(sink);
+ }
+ Instruction::V128Load32x2S(memarg) => {
+ sink.push(0xFD);
+ 0x05u32.encode(sink);
+ memarg.encode(sink);
+ }
+ Instruction::V128Load32x2U(memarg) => {
+ sink.push(0xFD);
+ 0x06u32.encode(sink);
+ memarg.encode(sink);
+ }
+ Instruction::V128Load8Splat(memarg) => {
+ sink.push(0xFD);
+ 0x07u32.encode(sink);
+ memarg.encode(sink);
+ }
+ Instruction::V128Load16Splat(memarg) => {
+ sink.push(0xFD);
+ 0x08u32.encode(sink);
+ memarg.encode(sink);
+ }
+ Instruction::V128Load32Splat(memarg) => {
+ sink.push(0xFD);
+ 0x09u32.encode(sink);
+ memarg.encode(sink);
+ }
+ Instruction::V128Load64Splat(memarg) => {
+ sink.push(0xFD);
+ 0x0Au32.encode(sink);
+ memarg.encode(sink);
+ }
+ Instruction::V128Store(memarg) => {
+ sink.push(0xFD);
+ 0x0Bu32.encode(sink);
+ memarg.encode(sink);
+ }
+ Instruction::V128Const(x) => {
+ sink.push(0xFD);
+ 0x0Cu32.encode(sink);
+ sink.extend(x.to_le_bytes().iter().copied());
+ }
+ Instruction::I8x16Shuffle(lanes) => {
+ sink.push(0xFD);
+ 0x0Du32.encode(sink);
+ assert!(lanes.iter().all(|l: &u8| *l < 32));
+ sink.extend(lanes.iter().copied());
+ }
+ Instruction::I8x16Swizzle => {
+ sink.push(0xFD);
+ 0x0Eu32.encode(sink);
+ }
+ Instruction::I8x16Splat => {
+ sink.push(0xFD);
+ 0x0Fu32.encode(sink);
+ }
+ Instruction::I16x8Splat => {
+ sink.push(0xFD);
+ 0x10u32.encode(sink);
+ }
+ Instruction::I32x4Splat => {
+ sink.push(0xFD);
+ 0x11u32.encode(sink);
+ }
+ Instruction::I64x2Splat => {
+ sink.push(0xFD);
+ 0x12u32.encode(sink);
+ }
+ Instruction::F32x4Splat => {
+ sink.push(0xFD);
+ 0x13u32.encode(sink);
+ }
+ Instruction::F64x2Splat => {
+ sink.push(0xFD);
+ 0x14u32.encode(sink);
+ }
+ Instruction::I8x16ExtractLaneS(lane) => {
+ sink.push(0xFD);
+ 0x15u32.encode(sink);
+ assert!(lane < 16);
+ sink.push(lane);
+ }
+ Instruction::I8x16ExtractLaneU(lane) => {
+ sink.push(0xFD);
+ 0x16u32.encode(sink);
+ assert!(lane < 16);
+ sink.push(lane);
+ }
+ Instruction::I8x16ReplaceLane(lane) => {
+ sink.push(0xFD);
+ 0x17u32.encode(sink);
+ assert!(lane < 16);
+ sink.push(lane);
+ }
+ Instruction::I16x8ExtractLaneS(lane) => {
+ sink.push(0xFD);
+ 0x18u32.encode(sink);
+ assert!(lane < 8);
+ sink.push(lane);
+ }
+ Instruction::I16x8ExtractLaneU(lane) => {
+ sink.push(0xFD);
+ 0x19u32.encode(sink);
+ assert!(lane < 8);
+ sink.push(lane);
+ }
+ Instruction::I16x8ReplaceLane(lane) => {
+ sink.push(0xFD);
+ 0x1Au32.encode(sink);
+ assert!(lane < 8);
+ sink.push(lane);
+ }
+ Instruction::I32x4ExtractLane(lane) => {
+ sink.push(0xFD);
+ 0x1Bu32.encode(sink);
+ assert!(lane < 4);
+ sink.push(lane);
+ }
+ Instruction::I32x4ReplaceLane(lane) => {
+ sink.push(0xFD);
+ 0x1Cu32.encode(sink);
+ assert!(lane < 4);
+ sink.push(lane);
+ }
+ Instruction::I64x2ExtractLane(lane) => {
+ sink.push(0xFD);
+ 0x1Du32.encode(sink);
+ assert!(lane < 2);
+ sink.push(lane);
+ }
+ Instruction::I64x2ReplaceLane(lane) => {
+ sink.push(0xFD);
+ 0x1Eu32.encode(sink);
+ assert!(lane < 2);
+ sink.push(lane);
+ }
+ Instruction::F32x4ExtractLane(lane) => {
+ sink.push(0xFD);
+ 0x1Fu32.encode(sink);
+ assert!(lane < 4);
+ sink.push(lane);
+ }
+ Instruction::F32x4ReplaceLane(lane) => {
+ sink.push(0xFD);
+ 0x20u32.encode(sink);
+ assert!(lane < 4);
+ sink.push(lane);
+ }
+ Instruction::F64x2ExtractLane(lane) => {
+ sink.push(0xFD);
+ 0x21u32.encode(sink);
+ assert!(lane < 2);
+ sink.push(lane);
+ }
+ Instruction::F64x2ReplaceLane(lane) => {
+ sink.push(0xFD);
+ 0x22u32.encode(sink);
+ assert!(lane < 2);
+ sink.push(lane);
+ }
+
+ Instruction::I8x16Eq => {
+ sink.push(0xFD);
+ 0x23u32.encode(sink);
+ }
+ Instruction::I8x16Ne => {
+ sink.push(0xFD);
+ 0x24u32.encode(sink);
+ }
+ Instruction::I8x16LtS => {
+ sink.push(0xFD);
+ 0x25u32.encode(sink);
+ }
+ Instruction::I8x16LtU => {
+ sink.push(0xFD);
+ 0x26u32.encode(sink);
+ }
+ Instruction::I8x16GtS => {
+ sink.push(0xFD);
+ 0x27u32.encode(sink);
+ }
+ Instruction::I8x16GtU => {
+ sink.push(0xFD);
+ 0x28u32.encode(sink);
+ }
+ Instruction::I8x16LeS => {
+ sink.push(0xFD);
+ 0x29u32.encode(sink);
+ }
+ Instruction::I8x16LeU => {
+ sink.push(0xFD);
+ 0x2Au32.encode(sink);
+ }
+ Instruction::I8x16GeS => {
+ sink.push(0xFD);
+ 0x2Bu32.encode(sink);
+ }
+ Instruction::I8x16GeU => {
+ sink.push(0xFD);
+ 0x2Cu32.encode(sink);
+ }
+ Instruction::I16x8Eq => {
+ sink.push(0xFD);
+ 0x2Du32.encode(sink);
+ }
+ Instruction::I16x8Ne => {
+ sink.push(0xFD);
+ 0x2Eu32.encode(sink);
+ }
+ Instruction::I16x8LtS => {
+ sink.push(0xFD);
+ 0x2Fu32.encode(sink);
+ }
+ Instruction::I16x8LtU => {
+ sink.push(0xFD);
+ 0x30u32.encode(sink);
+ }
+ Instruction::I16x8GtS => {
+ sink.push(0xFD);
+ 0x31u32.encode(sink);
+ }
+ Instruction::I16x8GtU => {
+ sink.push(0xFD);
+ 0x32u32.encode(sink);
+ }
+ Instruction::I16x8LeS => {
+ sink.push(0xFD);
+ 0x33u32.encode(sink);
+ }
+ Instruction::I16x8LeU => {
+ sink.push(0xFD);
+ 0x34u32.encode(sink);
+ }
+ Instruction::I16x8GeS => {
+ sink.push(0xFD);
+ 0x35u32.encode(sink);
+ }
+ Instruction::I16x8GeU => {
+ sink.push(0xFD);
+ 0x36u32.encode(sink);
+ }
+ Instruction::I32x4Eq => {
+ sink.push(0xFD);
+ 0x37u32.encode(sink);
+ }
+ Instruction::I32x4Ne => {
+ sink.push(0xFD);
+ 0x38u32.encode(sink);
+ }
+ Instruction::I32x4LtS => {
+ sink.push(0xFD);
+ 0x39u32.encode(sink);
+ }
+ Instruction::I32x4LtU => {
+ sink.push(0xFD);
+ 0x3Au32.encode(sink);
+ }
+ Instruction::I32x4GtS => {
+ sink.push(0xFD);
+ 0x3Bu32.encode(sink);
+ }
+ Instruction::I32x4GtU => {
+ sink.push(0xFD);
+ 0x3Cu32.encode(sink);
+ }
+ Instruction::I32x4LeS => {
+ sink.push(0xFD);
+ 0x3Du32.encode(sink);
+ }
+ Instruction::I32x4LeU => {
+ sink.push(0xFD);
+ 0x3Eu32.encode(sink);
+ }
+ Instruction::I32x4GeS => {
+ sink.push(0xFD);
+ 0x3Fu32.encode(sink);
+ }
+ Instruction::I32x4GeU => {
+ sink.push(0xFD);
+ 0x40u32.encode(sink);
+ }
+ Instruction::F32x4Eq => {
+ sink.push(0xFD);
+ 0x41u32.encode(sink);
+ }
+ Instruction::F32x4Ne => {
+ sink.push(0xFD);
+ 0x42u32.encode(sink);
+ }
+ Instruction::F32x4Lt => {
+ sink.push(0xFD);
+ 0x43u32.encode(sink);
+ }
+ Instruction::F32x4Gt => {
+ sink.push(0xFD);
+ 0x44u32.encode(sink);
+ }
+ Instruction::F32x4Le => {
+ sink.push(0xFD);
+ 0x45u32.encode(sink);
+ }
+ Instruction::F32x4Ge => {
+ sink.push(0xFD);
+ 0x46u32.encode(sink);
+ }
+ Instruction::F64x2Eq => {
+ sink.push(0xFD);
+ 0x47u32.encode(sink);
+ }
+ Instruction::F64x2Ne => {
+ sink.push(0xFD);
+ 0x48u32.encode(sink);
+ }
+ Instruction::F64x2Lt => {
+ sink.push(0xFD);
+ 0x49u32.encode(sink);
+ }
+ Instruction::F64x2Gt => {
+ sink.push(0xFD);
+ 0x4Au32.encode(sink);
+ }
+ Instruction::F64x2Le => {
+ sink.push(0xFD);
+ 0x4Bu32.encode(sink);
+ }
+ Instruction::F64x2Ge => {
+ sink.push(0xFD);
+ 0x4Cu32.encode(sink);
+ }
+ Instruction::V128Not => {
+ sink.push(0xFD);
+ 0x4Du32.encode(sink);
+ }
+ Instruction::V128And => {
+ sink.push(0xFD);
+ 0x4Eu32.encode(sink);
+ }
+ Instruction::V128AndNot => {
+ sink.push(0xFD);
+ 0x4Fu32.encode(sink);
+ }
+ Instruction::V128Or => {
+ sink.push(0xFD);
+ 0x50u32.encode(sink);
+ }
+ Instruction::V128Xor => {
+ sink.push(0xFD);
+ 0x51u32.encode(sink);
+ }
+ Instruction::V128Bitselect => {
+ sink.push(0xFD);
+ 0x52u32.encode(sink);
+ }
+ Instruction::V128AnyTrue => {
+ sink.push(0xFD);
+ 0x53u32.encode(sink);
+ }
+ Instruction::I8x16Abs => {
+ sink.push(0xFD);
+ 0x60u32.encode(sink);
+ }
+ Instruction::I8x16Neg => {
+ sink.push(0xFD);
+ 0x61u32.encode(sink);
+ }
+ Instruction::I8x16Popcnt => {
+ sink.push(0xFD);
+ 0x62u32.encode(sink);
+ }
+ Instruction::I8x16AllTrue => {
+ sink.push(0xFD);
+ 0x63u32.encode(sink);
+ }
+ Instruction::I8x16Bitmask => {
+ sink.push(0xFD);
+ 0x64u32.encode(sink);
+ }
+ Instruction::I8x16NarrowI16x8S => {
+ sink.push(0xFD);
+ 0x65u32.encode(sink);
+ }
+ Instruction::I8x16NarrowI16x8U => {
+ sink.push(0xFD);
+ 0x66u32.encode(sink);
+ }
+ Instruction::I8x16Shl => {
+ sink.push(0xFD);
+ 0x6bu32.encode(sink);
+ }
+ Instruction::I8x16ShrS => {
+ sink.push(0xFD);
+ 0x6cu32.encode(sink);
+ }
+ Instruction::I8x16ShrU => {
+ sink.push(0xFD);
+ 0x6du32.encode(sink);
+ }
+ Instruction::I8x16Add => {
+ sink.push(0xFD);
+ 0x6eu32.encode(sink);
+ }
+ Instruction::I8x16AddSatS => {
+ sink.push(0xFD);
+ 0x6fu32.encode(sink);
+ }
+ Instruction::I8x16AddSatU => {
+ sink.push(0xFD);
+ 0x70u32.encode(sink);
+ }
+ Instruction::I8x16Sub => {
+ sink.push(0xFD);
+ 0x71u32.encode(sink);
+ }
+ Instruction::I8x16SubSatS => {
+ sink.push(0xFD);
+ 0x72u32.encode(sink);
+ }
+ Instruction::I8x16SubSatU => {
+ sink.push(0xFD);
+ 0x73u32.encode(sink);
+ }
+ Instruction::I8x16MinS => {
+ sink.push(0xFD);
+ 0x76u32.encode(sink);
+ }
+ Instruction::I8x16MinU => {
+ sink.push(0xFD);
+ 0x77u32.encode(sink);
+ }
+ Instruction::I8x16MaxS => {
+ sink.push(0xFD);
+ 0x78u32.encode(sink);
+ }
+ Instruction::I8x16MaxU => {
+ sink.push(0xFD);
+ 0x79u32.encode(sink);
+ }
+ Instruction::I8x16AvgrU => {
+ sink.push(0xFD);
+ 0x7Bu32.encode(sink);
+ }
+ Instruction::I16x8ExtAddPairwiseI8x16S => {
+ sink.push(0xFD);
+ 0x7Cu32.encode(sink);
+ }
+ Instruction::I16x8ExtAddPairwiseI8x16U => {
+ sink.push(0xFD);
+ 0x7Du32.encode(sink);
+ }
+ Instruction::I32x4ExtAddPairwiseI16x8S => {
+ sink.push(0xFD);
+ 0x7Eu32.encode(sink);
+ }
+ Instruction::I32x4ExtAddPairwiseI16x8U => {
+ sink.push(0xFD);
+ 0x7Fu32.encode(sink);
+ }
+ Instruction::I16x8Abs => {
+ sink.push(0xFD);
+ 0x80u32.encode(sink);
+ }
+ Instruction::I16x8Neg => {
+ sink.push(0xFD);
+ 0x81u32.encode(sink);
+ }
+ Instruction::I16x8Q15MulrSatS => {
+ sink.push(0xFD);
+ 0x82u32.encode(sink);
+ }
+ Instruction::I16x8AllTrue => {
+ sink.push(0xFD);
+ 0x83u32.encode(sink);
+ }
+ Instruction::I16x8Bitmask => {
+ sink.push(0xFD);
+ 0x84u32.encode(sink);
+ }
+ Instruction::I16x8NarrowI32x4S => {
+ sink.push(0xFD);
+ 0x85u32.encode(sink);
+ }
+ Instruction::I16x8NarrowI32x4U => {
+ sink.push(0xFD);
+ 0x86u32.encode(sink);
+ }
+ Instruction::I16x8ExtendLowI8x16S => {
+ sink.push(0xFD);
+ 0x87u32.encode(sink);
+ }
+ Instruction::I16x8ExtendHighI8x16S => {
+ sink.push(0xFD);
+ 0x88u32.encode(sink);
+ }
+ Instruction::I16x8ExtendLowI8x16U => {
+ sink.push(0xFD);
+ 0x89u32.encode(sink);
+ }
+ Instruction::I16x8ExtendHighI8x16U => {
+ sink.push(0xFD);
+ 0x8Au32.encode(sink);
+ }
+ Instruction::I16x8Shl => {
+ sink.push(0xFD);
+ 0x8Bu32.encode(sink);
+ }
+ Instruction::I16x8ShrS => {
+ sink.push(0xFD);
+ 0x8Cu32.encode(sink);
+ }
+ Instruction::I16x8ShrU => {
+ sink.push(0xFD);
+ 0x8Du32.encode(sink);
+ }
+ Instruction::I16x8Add => {
+ sink.push(0xFD);
+ 0x8Eu32.encode(sink);
+ }
+ Instruction::I16x8AddSatS => {
+ sink.push(0xFD);
+ 0x8Fu32.encode(sink);
+ }
+ Instruction::I16x8AddSatU => {
+ sink.push(0xFD);
+ 0x90u32.encode(sink);
+ }
+ Instruction::I16x8Sub => {
+ sink.push(0xFD);
+ 0x91u32.encode(sink);
+ }
+ Instruction::I16x8SubSatS => {
+ sink.push(0xFD);
+ 0x92u32.encode(sink);
+ }
+ Instruction::I16x8SubSatU => {
+ sink.push(0xFD);
+ 0x93u32.encode(sink);
+ }
+ Instruction::I16x8Mul => {
+ sink.push(0xFD);
+ 0x95u32.encode(sink);
+ }
+ Instruction::I16x8MinS => {
+ sink.push(0xFD);
+ 0x96u32.encode(sink);
+ }
+ Instruction::I16x8MinU => {
+ sink.push(0xFD);
+ 0x97u32.encode(sink);
+ }
+ Instruction::I16x8MaxS => {
+ sink.push(0xFD);
+ 0x98u32.encode(sink);
+ }
+ Instruction::I16x8MaxU => {
+ sink.push(0xFD);
+ 0x99u32.encode(sink);
+ }
+ Instruction::I16x8AvgrU => {
+ sink.push(0xFD);
+ 0x9Bu32.encode(sink);
+ }
+ Instruction::I16x8ExtMulLowI8x16S => {
+ sink.push(0xFD);
+ 0x9Cu32.encode(sink);
+ }
+ Instruction::I16x8ExtMulHighI8x16S => {
+ sink.push(0xFD);
+ 0x9Du32.encode(sink);
+ }
+ Instruction::I16x8ExtMulLowI8x16U => {
+ sink.push(0xFD);
+ 0x9Eu32.encode(sink);
+ }
+ Instruction::I16x8ExtMulHighI8x16U => {
+ sink.push(0xFD);
+ 0x9Fu32.encode(sink);
+ }
+ Instruction::I32x4Abs => {
+ sink.push(0xFD);
+ 0xA0u32.encode(sink);
+ }
+ Instruction::I32x4Neg => {
+ sink.push(0xFD);
+ 0xA1u32.encode(sink);
+ }
+ Instruction::I32x4AllTrue => {
+ sink.push(0xFD);
+ 0xA3u32.encode(sink);
+ }
+ Instruction::I32x4Bitmask => {
+ sink.push(0xFD);
+ 0xA4u32.encode(sink);
+ }
+ Instruction::I32x4ExtendLowI16x8S => {
+ sink.push(0xFD);
+ 0xA7u32.encode(sink);
+ }
+ Instruction::I32x4ExtendHighI16x8S => {
+ sink.push(0xFD);
+ 0xA8u32.encode(sink);
+ }
+ Instruction::I32x4ExtendLowI16x8U => {
+ sink.push(0xFD);
+ 0xA9u32.encode(sink);
+ }
+ Instruction::I32x4ExtendHighI16x8U => {
+ sink.push(0xFD);
+ 0xAAu32.encode(sink);
+ }
+ Instruction::I32x4Shl => {
+ sink.push(0xFD);
+ 0xABu32.encode(sink);
+ }
+ Instruction::I32x4ShrS => {
+ sink.push(0xFD);
+ 0xACu32.encode(sink);
+ }
+ Instruction::I32x4ShrU => {
+ sink.push(0xFD);
+ 0xADu32.encode(sink);
+ }
+ Instruction::I32x4Add => {
+ sink.push(0xFD);
+ 0xAEu32.encode(sink);
+ }
+ Instruction::I32x4Sub => {
+ sink.push(0xFD);
+ 0xB1u32.encode(sink);
+ }
+ Instruction::I32x4Mul => {
+ sink.push(0xFD);
+ 0xB5u32.encode(sink);
+ }
+ Instruction::I32x4MinS => {
+ sink.push(0xFD);
+ 0xB6u32.encode(sink);
+ }
+ Instruction::I32x4MinU => {
+ sink.push(0xFD);
+ 0xB7u32.encode(sink);
+ }
+ Instruction::I32x4MaxS => {
+ sink.push(0xFD);
+ 0xB8u32.encode(sink);
+ }
+ Instruction::I32x4MaxU => {
+ sink.push(0xFD);
+ 0xB9u32.encode(sink);
+ }
+ Instruction::I32x4DotI16x8S => {
+ sink.push(0xFD);
+ 0xBAu32.encode(sink);
+ }
+ Instruction::I32x4ExtMulLowI16x8S => {
+ sink.push(0xFD);
+ 0xBCu32.encode(sink);
+ }
+ Instruction::I32x4ExtMulHighI16x8S => {
+ sink.push(0xFD);
+ 0xBDu32.encode(sink);
+ }
+ Instruction::I32x4ExtMulLowI16x8U => {
+ sink.push(0xFD);
+ 0xBEu32.encode(sink);
+ }
+ Instruction::I32x4ExtMulHighI16x8U => {
+ sink.push(0xFD);
+ 0xBFu32.encode(sink);
+ }
+ Instruction::I64x2Abs => {
+ sink.push(0xFD);
+ 0xC0u32.encode(sink);
+ }
+ Instruction::I64x2Neg => {
+ sink.push(0xFD);
+ 0xC1u32.encode(sink);
+ }
+ Instruction::I64x2AllTrue => {
+ sink.push(0xFD);
+ 0xC3u32.encode(sink);
+ }
+ Instruction::I64x2Bitmask => {
+ sink.push(0xFD);
+ 0xC4u32.encode(sink);
+ }
+ Instruction::I64x2ExtendLowI32x4S => {
+ sink.push(0xFD);
+ 0xC7u32.encode(sink);
+ }
+ Instruction::I64x2ExtendHighI32x4S => {
+ sink.push(0xFD);
+ 0xC8u32.encode(sink);
+ }
+ Instruction::I64x2ExtendLowI32x4U => {
+ sink.push(0xFD);
+ 0xC9u32.encode(sink);
+ }
+ Instruction::I64x2ExtendHighI32x4U => {
+ sink.push(0xFD);
+ 0xCAu32.encode(sink);
+ }
+ Instruction::I64x2Shl => {
+ sink.push(0xFD);
+ 0xCBu32.encode(sink);
+ }
+ Instruction::I64x2ShrS => {
+ sink.push(0xFD);
+ 0xCCu32.encode(sink);
+ }
+ Instruction::I64x2ShrU => {
+ sink.push(0xFD);
+ 0xCDu32.encode(sink);
+ }
+ Instruction::I64x2Add => {
+ sink.push(0xFD);
+ 0xCEu32.encode(sink);
+ }
+ Instruction::I64x2Sub => {
+ sink.push(0xFD);
+ 0xD1u32.encode(sink);
+ }
+ Instruction::I64x2Mul => {
+ sink.push(0xFD);
+ 0xD5u32.encode(sink);
+ }
+ Instruction::I64x2ExtMulLowI32x4S => {
+ sink.push(0xFD);
+ 0xDCu32.encode(sink);
+ }
+ Instruction::I64x2ExtMulHighI32x4S => {
+ sink.push(0xFD);
+ 0xDDu32.encode(sink);
+ }
+ Instruction::I64x2ExtMulLowI32x4U => {
+ sink.push(0xFD);
+ 0xDEu32.encode(sink);
+ }
+ Instruction::I64x2ExtMulHighI32x4U => {
+ sink.push(0xFD);
+ 0xDFu32.encode(sink);
+ }
+ Instruction::F32x4Ceil => {
+ sink.push(0xFD);
+ 0x67u32.encode(sink);
+ }
+ Instruction::F32x4Floor => {
+ sink.push(0xFD);
+ 0x68u32.encode(sink);
+ }
+ Instruction::F32x4Trunc => {
+ sink.push(0xFD);
+ 0x69u32.encode(sink);
+ }
+ Instruction::F32x4Nearest => {
+ sink.push(0xFD);
+ 0x6Au32.encode(sink);
+ }
+ Instruction::F32x4Abs => {
+ sink.push(0xFD);
+ 0xE0u32.encode(sink);
+ }
+ Instruction::F32x4Neg => {
+ sink.push(0xFD);
+ 0xE1u32.encode(sink);
+ }
+ Instruction::F32x4Sqrt => {
+ sink.push(0xFD);
+ 0xE3u32.encode(sink);
+ }
+ Instruction::F32x4Add => {
+ sink.push(0xFD);
+ 0xE4u32.encode(sink);
+ }
+ Instruction::F32x4Sub => {
+ sink.push(0xFD);
+ 0xE5u32.encode(sink);
+ }
+ Instruction::F32x4Mul => {
+ sink.push(0xFD);
+ 0xE6u32.encode(sink);
+ }
+ Instruction::F32x4Div => {
+ sink.push(0xFD);
+ 0xE7u32.encode(sink);
+ }
+ Instruction::F32x4Min => {
+ sink.push(0xFD);
+ 0xE8u32.encode(sink);
+ }
+ Instruction::F32x4Max => {
+ sink.push(0xFD);
+ 0xE9u32.encode(sink);
+ }
+ Instruction::F32x4PMin => {
+ sink.push(0xFD);
+ 0xEAu32.encode(sink);
+ }
+ Instruction::F32x4PMax => {
+ sink.push(0xFD);
+ 0xEBu32.encode(sink);
+ }
+ Instruction::F64x2Ceil => {
+ sink.push(0xFD);
+ 0x74u32.encode(sink);
+ }
+ Instruction::F64x2Floor => {
+ sink.push(0xFD);
+ 0x75u32.encode(sink);
+ }
+ Instruction::F64x2Trunc => {
+ sink.push(0xFD);
+ 0x7Au32.encode(sink);
+ }
+ Instruction::F64x2Nearest => {
+ sink.push(0xFD);
+ 0x94u32.encode(sink);
+ }
+ Instruction::F64x2Abs => {
+ sink.push(0xFD);
+ 0xECu32.encode(sink);
+ }
+ Instruction::F64x2Neg => {
+ sink.push(0xFD);
+ 0xEDu32.encode(sink);
+ }
+ Instruction::F64x2Sqrt => {
+ sink.push(0xFD);
+ 0xEFu32.encode(sink);
+ }
+ Instruction::F64x2Add => {
+ sink.push(0xFD);
+ 0xF0u32.encode(sink);
+ }
+ Instruction::F64x2Sub => {
+ sink.push(0xFD);
+ 0xF1u32.encode(sink);
+ }
+ Instruction::F64x2Mul => {
+ sink.push(0xFD);
+ 0xF2u32.encode(sink);
+ }
+ Instruction::F64x2Div => {
+ sink.push(0xFD);
+ 0xF3u32.encode(sink);
+ }
+ Instruction::F64x2Min => {
+ sink.push(0xFD);
+ 0xF4u32.encode(sink);
+ }
+ Instruction::F64x2Max => {
+ sink.push(0xFD);
+ 0xF5u32.encode(sink);
+ }
+ Instruction::F64x2PMin => {
+ sink.push(0xFD);
+ 0xF6u32.encode(sink);
+ }
+ Instruction::F64x2PMax => {
+ sink.push(0xFD);
+ 0xF7u32.encode(sink);
+ }
+ Instruction::I32x4TruncSatF32x4S => {
+ sink.push(0xFD);
+ 0xF8u32.encode(sink);
+ }
+ Instruction::I32x4TruncSatF32x4U => {
+ sink.push(0xFD);
+ 0xF9u32.encode(sink);
+ }
+ Instruction::F32x4ConvertI32x4S => {
+ sink.push(0xFD);
+ 0xFAu32.encode(sink);
+ }
+ Instruction::F32x4ConvertI32x4U => {
+ sink.push(0xFD);
+ 0xFBu32.encode(sink);
+ }
+ Instruction::I32x4TruncSatF64x2SZero => {
+ sink.push(0xFD);
+ 0xFCu32.encode(sink);
+ }
+ Instruction::I32x4TruncSatF64x2UZero => {
+ sink.push(0xFD);
+ 0xFDu32.encode(sink);
+ }
+ Instruction::F64x2ConvertLowI32x4S => {
+ sink.push(0xFD);
+ 0xFEu32.encode(sink);
+ }
+ Instruction::F64x2ConvertLowI32x4U => {
+ sink.push(0xFD);
+ 0xFFu32.encode(sink);
+ }
+ Instruction::F32x4DemoteF64x2Zero => {
+ sink.push(0xFD);
+ 0x5Eu32.encode(sink);
+ }
+ Instruction::F64x2PromoteLowF32x4 => {
+ sink.push(0xFD);
+ 0x5Fu32.encode(sink);
+ }
+ Instruction::V128Load32Zero(memarg) => {
+ sink.push(0xFD);
+ 0x5Cu32.encode(sink);
+ memarg.encode(sink);
+ }
+ Instruction::V128Load64Zero(memarg) => {
+ sink.push(0xFD);
+ 0x5Du32.encode(sink);
+ memarg.encode(sink);
+ }
+ Instruction::V128Load8Lane { memarg, lane } => {
+ sink.push(0xFD);
+ 0x54u32.encode(sink);
+ memarg.encode(sink);
+ assert!(lane < 16);
+ sink.push(lane);
+ }
+ Instruction::V128Load16Lane { memarg, lane } => {
+ sink.push(0xFD);
+ 0x55u32.encode(sink);
+ memarg.encode(sink);
+ assert!(lane < 8);
+ sink.push(lane);
+ }
+ Instruction::V128Load32Lane { memarg, lane } => {
+ sink.push(0xFD);
+ 0x56u32.encode(sink);
+ memarg.encode(sink);
+ assert!(lane < 4);
+ sink.push(lane);
+ }
+ Instruction::V128Load64Lane { memarg, lane } => {
+ sink.push(0xFD);
+ 0x57u32.encode(sink);
+ memarg.encode(sink);
+ assert!(lane < 2);
+ sink.push(lane);
+ }
+ Instruction::V128Store8Lane { memarg, lane } => {
+ sink.push(0xFD);
+ 0x58u32.encode(sink);
+ memarg.encode(sink);
+ assert!(lane < 16);
+ sink.push(lane);
+ }
+ Instruction::V128Store16Lane { memarg, lane } => {
+ sink.push(0xFD);
+ 0x59u32.encode(sink);
+ memarg.encode(sink);
+ assert!(lane < 8);
+ sink.push(lane);
+ }
+ Instruction::V128Store32Lane { memarg, lane } => {
+ sink.push(0xFD);
+ 0x5Au32.encode(sink);
+ memarg.encode(sink);
+ assert!(lane < 4);
+ sink.push(lane);
+ }
+ Instruction::V128Store64Lane { memarg, lane } => {
+ sink.push(0xFD);
+ 0x5Bu32.encode(sink);
+ memarg.encode(sink);
+ assert!(lane < 2);
+ sink.push(lane);
+ }
+ Instruction::I64x2Eq => {
+ sink.push(0xFD);
+ 0xD6u32.encode(sink);
+ }
+ Instruction::I64x2Ne => {
+ sink.push(0xFD);
+ 0xD7u32.encode(sink);
+ }
+ Instruction::I64x2LtS => {
+ sink.push(0xFD);
+ 0xD8u32.encode(sink);
+ }
+ Instruction::I64x2GtS => {
+ sink.push(0xFD);
+ 0xD9u32.encode(sink);
+ }
+ Instruction::I64x2LeS => {
+ sink.push(0xFD);
+ 0xDAu32.encode(sink);
+ }
+ Instruction::I64x2GeS => {
+ sink.push(0xFD);
+ 0xDBu32.encode(sink);
+ }
+ Instruction::I8x16RelaxedSwizzle => {
+ sink.push(0xFD);
+ 0x100u32.encode(sink);
+ }
+ Instruction::I32x4RelaxedTruncF32x4S => {
+ sink.push(0xFD);
+ 0x101u32.encode(sink);
+ }
+ Instruction::I32x4RelaxedTruncF32x4U => {
+ sink.push(0xFD);
+ 0x102u32.encode(sink);
+ }
+ Instruction::I32x4RelaxedTruncF64x2SZero => {
+ sink.push(0xFD);
+ 0x103u32.encode(sink);
+ }
+ Instruction::I32x4RelaxedTruncF64x2UZero => {
+ sink.push(0xFD);
+ 0x104u32.encode(sink);
+ }
+ Instruction::F32x4RelaxedMadd => {
+ sink.push(0xFD);
+ 0x105u32.encode(sink);
+ }
+ Instruction::F32x4RelaxedNmadd => {
+ sink.push(0xFD);
+ 0x106u32.encode(sink);
+ }
+ Instruction::F64x2RelaxedMadd => {
+ sink.push(0xFD);
+ 0x107u32.encode(sink);
+ }
+ Instruction::F64x2RelaxedNmadd => {
+ sink.push(0xFD);
+ 0x108u32.encode(sink);
+ }
+ Instruction::I8x16RelaxedLaneselect => {
+ sink.push(0xFD);
+ 0x109u32.encode(sink);
+ }
+ Instruction::I16x8RelaxedLaneselect => {
+ sink.push(0xFD);
+ 0x10Au32.encode(sink);
+ }
+ Instruction::I32x4RelaxedLaneselect => {
+ sink.push(0xFD);
+ 0x10Bu32.encode(sink);
+ }
+ Instruction::I64x2RelaxedLaneselect => {
+ sink.push(0xFD);
+ 0x10Cu32.encode(sink);
+ }
+ Instruction::F32x4RelaxedMin => {
+ sink.push(0xFD);
+ 0x10Du32.encode(sink);
+ }
+ Instruction::F32x4RelaxedMax => {
+ sink.push(0xFD);
+ 0x10Eu32.encode(sink);
+ }
+ Instruction::F64x2RelaxedMin => {
+ sink.push(0xFD);
+ 0x10Fu32.encode(sink);
+ }
+ Instruction::F64x2RelaxedMax => {
+ sink.push(0xFD);
+ 0x110u32.encode(sink);
+ }
+ Instruction::I16x8RelaxedQ15mulrS => {
+ sink.push(0xFD);
+ 0x111u32.encode(sink);
+ }
+ Instruction::I16x8RelaxedDotI8x16I7x16S => {
+ sink.push(0xFD);
+ 0x112u32.encode(sink);
+ }
+ Instruction::I32x4RelaxedDotI8x16I7x16AddS => {
+ sink.push(0xFD);
+ 0x113u32.encode(sink);
+ }
+
+ // Atmoic instructions from the thread proposal
+ Instruction::MemoryAtomicNotify(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x00);
+ memarg.encode(sink);
+ }
+ Instruction::MemoryAtomicWait32(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x01);
+ memarg.encode(sink);
+ }
+ Instruction::MemoryAtomicWait64(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x02);
+ memarg.encode(sink);
+ }
+ Instruction::AtomicFence => {
+ sink.push(0xFE);
+ sink.push(0x03);
+ sink.push(0x00);
+ }
+ Instruction::I32AtomicLoad(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x10);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicLoad(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x11);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicLoad8U(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x12);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicLoad16U(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x13);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicLoad8U(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x14);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicLoad16U(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x15);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicLoad32U(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x16);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicStore(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x17);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicStore(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x18);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicStore8(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x19);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicStore16(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x1A);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicStore8(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x1B);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicStore16(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x1C);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicStore32(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x1D);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmwAdd(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x1E);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmwAdd(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x1F);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmw8AddU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x20);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmw16AddU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x21);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw8AddU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x22);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw16AddU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x23);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw32AddU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x24);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmwSub(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x25);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmwSub(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x26);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmw8SubU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x27);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmw16SubU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x28);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw8SubU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x29);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw16SubU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x2A);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw32SubU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x2B);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmwAnd(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x2C);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmwAnd(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x2D);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmw8AndU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x2E);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmw16AndU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x2F);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw8AndU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x30);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw16AndU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x31);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw32AndU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x32);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmwOr(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x33);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmwOr(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x34);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmw8OrU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x35);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmw16OrU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x36);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw8OrU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x37);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw16OrU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x38);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw32OrU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x39);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmwXor(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x3A);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmwXor(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x3B);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmw8XorU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x3C);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmw16XorU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x3D);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw8XorU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x3E);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw16XorU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x3F);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw32XorU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x40);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmwXchg(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x41);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmwXchg(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x42);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmw8XchgU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x43);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmw16XchgU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x44);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw8XchgU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x45);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw16XchgU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x46);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw32XchgU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x47);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmwCmpxchg(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x48);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmwCmpxchg(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x49);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmw8CmpxchgU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x4A);
+ memarg.encode(sink);
+ }
+ Instruction::I32AtomicRmw16CmpxchgU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x4B);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw8CmpxchgU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x4C);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw16CmpxchgU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x4D);
+ memarg.encode(sink);
+ }
+ Instruction::I64AtomicRmw32CmpxchgU(memarg) => {
+ sink.push(0xFE);
+ sink.push(0x4E);
+ memarg.encode(sink);
+ }
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+#[allow(missing_docs)]
+pub enum Catch {
+ One { tag: u32, label: u32 },
+ OneRef { tag: u32, label: u32 },
+ All { label: u32 },
+ AllRef { label: u32 },
+}
+
+impl Encode for Catch {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ match self {
+ Catch::One { tag, label } => {
+ sink.push(0x00);
+ tag.encode(sink);
+ label.encode(sink);
+ }
+ Catch::OneRef { tag, label } => {
+ sink.push(0x01);
+ tag.encode(sink);
+ label.encode(sink);
+ }
+ Catch::All { label } => {
+ sink.push(0x02);
+ label.encode(sink);
+ }
+ Catch::AllRef { label } => {
+ sink.push(0x03);
+ label.encode(sink);
+ }
+ }
+ }
+}
+
+/// A constant expression.
+///
+/// Usable in contexts such as offsets or initializers.
+#[derive(Debug)]
+pub struct ConstExpr {
+ bytes: Vec<u8>,
+}
+
+impl ConstExpr {
+ /// Create a new empty constant expression builder.
+ pub fn empty() -> Self {
+ Self { bytes: Vec::new() }
+ }
+
+ /// Create a constant expression with the specified raw encoding of instructions.
+ pub fn raw(bytes: impl IntoIterator<Item = u8>) -> Self {
+ Self {
+ bytes: bytes.into_iter().collect(),
+ }
+ }
+
+ fn new_insn(insn: Instruction) -> Self {
+ let mut bytes = vec![];
+ insn.encode(&mut bytes);
+ Self { bytes }
+ }
+
+ /// Create a constant expression containing a single `global.get` instruction.
+ pub fn global_get(index: u32) -> Self {
+ Self::new_insn(Instruction::GlobalGet(index))
+ }
+
+ /// Create a constant expression containing a single `ref.null` instruction.
+ pub fn ref_null(ty: HeapType) -> Self {
+ Self::new_insn(Instruction::RefNull(ty))
+ }
+
+ /// Create a constant expression containing a single `ref.func` instruction.
+ pub fn ref_func(func: u32) -> Self {
+ Self::new_insn(Instruction::RefFunc(func))
+ }
+
+ /// Create a constant expression containing a single `i32.const` instruction.
+ pub fn i32_const(value: i32) -> Self {
+ Self::new_insn(Instruction::I32Const(value))
+ }
+
+ /// Create a constant expression containing a single `i64.const` instruction.
+ pub fn i64_const(value: i64) -> Self {
+ Self::new_insn(Instruction::I64Const(value))
+ }
+
+ /// Create a constant expression containing a single `f32.const` instruction.
+ pub fn f32_const(value: f32) -> Self {
+ Self::new_insn(Instruction::F32Const(value))
+ }
+
+ /// Create a constant expression containing a single `f64.const` instruction.
+ pub fn f64_const(value: f64) -> Self {
+ Self::new_insn(Instruction::F64Const(value))
+ }
+
+ /// Create a constant expression containing a single `v128.const` instruction.
+ pub fn v128_const(value: i128) -> Self {
+ Self::new_insn(Instruction::V128Const(value))
+ }
+}
+
+impl Encode for ConstExpr {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ sink.extend(&self.bytes);
+ Instruction::End.encode(sink);
+ }
+}
+
+/// An error when converting a `wasmparser::ConstExpr` into a
+/// `wasm_encoder::ConstExpr`.
+#[cfg(feature = "wasmparser")]
+#[derive(Debug)]
+pub enum ConstExprConversionError {
+ /// There was an error when parsing the const expression.
+ ParseError(wasmparser::BinaryReaderError),
+
+ /// The const expression is invalid: not actually constant or something like
+ /// that.
+ Invalid,
+
+ /// There was a type reference that was canonicalized and no longer
+ /// references an index into a module's types space, so we cannot encode it
+ /// into a Wasm binary again.
+ CanonicalizedTypeReference,
+}
+
+#[cfg(feature = "wasmparser")]
+impl std::fmt::Display for ConstExprConversionError {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Self::ParseError(_e) => {
+ write!(f, "There was an error when parsing the const expression")
+ }
+ Self::Invalid => write!(f, "The const expression was invalid"),
+ Self::CanonicalizedTypeReference => write!(
+ f,
+ "There was a canonicalized type reference without type index information"
+ ),
+ }
+ }
+}
+
+#[cfg(feature = "wasmparser")]
+impl std::error::Error for ConstExprConversionError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ Self::ParseError(e) => Some(e),
+ Self::Invalid | Self::CanonicalizedTypeReference => None,
+ }
+ }
+}
+
+#[cfg(feature = "wasmparser")]
+impl<'a> TryFrom<wasmparser::ConstExpr<'a>> for ConstExpr {
+ type Error = ConstExprConversionError;
+
+ fn try_from(const_expr: wasmparser::ConstExpr) -> Result<Self, Self::Error> {
+ let mut ops = const_expr.get_operators_reader().into_iter();
+
+ let result = match ops.next() {
+ Some(Ok(wasmparser::Operator::I32Const { value })) => ConstExpr::i32_const(value),
+ Some(Ok(wasmparser::Operator::I64Const { value })) => ConstExpr::i64_const(value),
+ Some(Ok(wasmparser::Operator::F32Const { value })) => {
+ ConstExpr::f32_const(value.bits() as _)
+ }
+ Some(Ok(wasmparser::Operator::F64Const { value })) => {
+ ConstExpr::f64_const(value.bits() as _)
+ }
+ Some(Ok(wasmparser::Operator::V128Const { value })) => {
+ ConstExpr::v128_const(i128::from_le_bytes(*value.bytes()))
+ }
+ Some(Ok(wasmparser::Operator::RefNull { hty })) => ConstExpr::ref_null(
+ HeapType::try_from(hty)
+ .map_err(|_| ConstExprConversionError::CanonicalizedTypeReference)?,
+ ),
+ Some(Ok(wasmparser::Operator::RefFunc { function_index })) => {
+ ConstExpr::ref_func(function_index)
+ }
+ Some(Ok(wasmparser::Operator::GlobalGet { global_index })) => {
+ ConstExpr::global_get(global_index)
+ }
+
+ // TODO: support the extended-const proposal.
+ Some(Ok(_op)) => return Err(ConstExprConversionError::Invalid),
+
+ Some(Err(e)) => return Err(ConstExprConversionError::ParseError(e)),
+ None => return Err(ConstExprConversionError::Invalid),
+ };
+
+ match (ops.next(), ops.next()) {
+ (Some(Ok(wasmparser::Operator::End)), None) => Ok(result),
+ _ => Err(ConstExprConversionError::Invalid),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn function_new_with_locals_test() {
+ use super::*;
+
+ // Test the algorithm for conversion is correct
+ let f1 = Function::new_with_locals_types([
+ ValType::I32,
+ ValType::I32,
+ ValType::I64,
+ ValType::F32,
+ ValType::F32,
+ ValType::F32,
+ ValType::I32,
+ ValType::I64,
+ ValType::I64,
+ ]);
+ let f2 = Function::new([
+ (2, ValType::I32),
+ (1, ValType::I64),
+ (3, ValType::F32),
+ (1, ValType::I32),
+ (2, ValType::I64),
+ ]);
+
+ assert_eq!(f1.bytes, f2.bytes)
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/core/custom.rs b/third_party/rust/wasm-encoder/src/core/custom.rs
new file mode 100644
index 0000000000..870ee62617
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/core/custom.rs
@@ -0,0 +1,73 @@
+use std::borrow::Cow;
+
+use crate::{encoding_size, Encode, Section, SectionId};
+
+/// A custom section holding arbitrary data.
+#[derive(Clone, Debug)]
+pub struct CustomSection<'a> {
+ /// The name of this custom section.
+ pub name: Cow<'a, str>,
+ /// This custom section's data.
+ pub data: Cow<'a, [u8]>,
+}
+
+impl Encode for CustomSection<'_> {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ let encoded_name_len = encoding_size(u32::try_from(self.name.len()).unwrap());
+ (encoded_name_len + self.name.len() + self.data.len()).encode(sink);
+ self.name.encode(sink);
+ sink.extend(&*self.data);
+ }
+}
+
+impl Section for CustomSection<'_> {
+ fn id(&self) -> u8 {
+ SectionId::Custom.into()
+ }
+}
+
+/// A raw custom section where the bytes specified contain the leb-encoded
+/// length of the custom section, the custom section's name, and the custom
+/// section's data.
+#[derive(Clone, Debug)]
+pub struct RawCustomSection<'a>(pub &'a [u8]);
+
+impl Encode for RawCustomSection<'_> {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ sink.extend(self.0);
+ }
+}
+
+impl Section for RawCustomSection<'_> {
+ fn id(&self) -> u8 {
+ SectionId::Custom.into()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_custom_section() {
+ let custom = CustomSection {
+ name: "test".into(),
+ data: Cow::Borrowed(&[11, 22, 33, 44]),
+ };
+
+ let mut encoded = vec![];
+ custom.encode(&mut encoded);
+
+ #[rustfmt::skip]
+ assert_eq!(encoded, vec![
+ // LEB128 length of section.
+ 9,
+ // LEB128 length of name.
+ 4,
+ // Name.
+ b't', b'e', b's', b't',
+ // Data.
+ 11, 22, 33, 44,
+ ]);
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/core/data.rs b/third_party/rust/wasm-encoder/src/core/data.rs
new file mode 100644
index 0000000000..6439b66e2e
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/core/data.rs
@@ -0,0 +1,185 @@
+use crate::{encode_section, encoding_size, ConstExpr, Encode, Section, SectionId};
+
+/// An encoder for the data section.
+///
+/// Data sections are only supported for modules.
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{
+/// ConstExpr, DataSection, Instruction, MemorySection, MemoryType,
+/// Module,
+/// };
+///
+/// let mut memory = MemorySection::new();
+/// memory.memory(MemoryType {
+/// minimum: 1,
+/// maximum: None,
+/// memory64: false,
+/// shared: false,
+/// });
+///
+/// let mut data = DataSection::new();
+/// let memory_index = 0;
+/// let offset = ConstExpr::i32_const(42);
+/// let segment_data = b"hello";
+/// data.active(memory_index, &offset, segment_data.iter().copied());
+///
+/// let mut module = Module::new();
+/// module
+/// .section(&memory)
+/// .section(&data);
+///
+/// let wasm_bytes = module.finish();
+/// ```
+#[derive(Clone, Default, Debug)]
+pub struct DataSection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+/// A segment in the data section.
+#[derive(Clone, Debug)]
+pub struct DataSegment<'a, D> {
+ /// This data segment's mode.
+ pub mode: DataSegmentMode<'a>,
+ /// This data segment's data.
+ pub data: D,
+}
+
+/// A data segment's mode.
+#[derive(Clone, Debug)]
+pub enum DataSegmentMode<'a> {
+ /// An active data segment.
+ Active {
+ /// The memory this segment applies to.
+ memory_index: u32,
+ /// The offset where this segment's data is initialized at.
+ offset: &'a ConstExpr,
+ },
+ /// A passive data segment.
+ ///
+ /// Passive data segments are part of the bulk memory proposal.
+ Passive,
+}
+
+impl DataSection {
+ /// Create a new data section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of data segments in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Define a data segment.
+ pub fn segment<D>(&mut self, segment: DataSegment<D>) -> &mut Self
+ where
+ D: IntoIterator<Item = u8>,
+ D::IntoIter: ExactSizeIterator,
+ {
+ match segment.mode {
+ DataSegmentMode::Passive => {
+ self.bytes.push(0x01);
+ }
+ DataSegmentMode::Active {
+ memory_index: 0,
+ offset,
+ } => {
+ self.bytes.push(0x00);
+ offset.encode(&mut self.bytes);
+ }
+ DataSegmentMode::Active {
+ memory_index,
+ offset,
+ } => {
+ self.bytes.push(0x02);
+ memory_index.encode(&mut self.bytes);
+ offset.encode(&mut self.bytes);
+ }
+ }
+
+ let data = segment.data.into_iter();
+ data.len().encode(&mut self.bytes);
+ self.bytes.extend(data);
+
+ self.num_added += 1;
+ self
+ }
+
+ /// Define an active data segment.
+ pub fn active<D>(&mut self, memory_index: u32, offset: &ConstExpr, data: D) -> &mut Self
+ where
+ D: IntoIterator<Item = u8>,
+ D::IntoIter: ExactSizeIterator,
+ {
+ self.segment(DataSegment {
+ mode: DataSegmentMode::Active {
+ memory_index,
+ offset,
+ },
+ data,
+ })
+ }
+
+ /// Define a passive data segment.
+ ///
+ /// Passive data segments are part of the bulk memory proposal.
+ pub fn passive<D>(&mut self, data: D) -> &mut Self
+ where
+ D: IntoIterator<Item = u8>,
+ D::IntoIter: ExactSizeIterator,
+ {
+ self.segment(DataSegment {
+ mode: DataSegmentMode::Passive,
+ data,
+ })
+ }
+
+ /// Copy an already-encoded data segment into this data section.
+ pub fn raw(&mut self, already_encoded_data_segment: &[u8]) -> &mut Self {
+ self.bytes.extend_from_slice(already_encoded_data_segment);
+ self.num_added += 1;
+ self
+ }
+}
+
+impl Encode for DataSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl Section for DataSection {
+ fn id(&self) -> u8 {
+ SectionId::Data.into()
+ }
+}
+
+/// An encoder for the data count section.
+#[derive(Clone, Copy, Debug)]
+pub struct DataCountSection {
+ /// The number of segments in the data section.
+ pub count: u32,
+}
+
+impl Encode for DataCountSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encoding_size(self.count).encode(sink);
+ self.count.encode(sink);
+ }
+}
+
+impl Section for DataCountSection {
+ fn id(&self) -> u8 {
+ SectionId::DataCount.into()
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/core/dump.rs b/third_party/rust/wasm-encoder/src/core/dump.rs
new file mode 100644
index 0000000000..ee3d229909
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/core/dump.rs
@@ -0,0 +1,627 @@
+use std::borrow::Cow;
+
+use crate::{CustomSection, Encode, Section};
+
+/// The "core" custom section for coredumps, as described in the
+/// [tool-conventions
+/// repository](https://github.com/WebAssembly/tool-conventions/blob/main/Coredump.md).
+///
+/// There are four sections that comprise a core dump:
+/// - "core", which contains the name of the core dump
+/// - "coremodules", a listing of modules
+/// - "coreinstances", a listing of module instances
+/// - "corestack", a listing of frames for a specific thread
+///
+/// # Example of how these could be constructed and encoded into a module:
+///
+/// ```
+/// use wasm_encoder::{
+/// CoreDumpInstancesSection, CoreDumpModulesSection, CoreDumpSection, CoreDumpStackSection,
+/// CoreDumpValue, Module,
+/// };
+/// let core = CoreDumpSection::new("MyModule.wasm");
+///
+/// let mut modules = CoreDumpModulesSection::new();
+/// modules.module("my_module");
+///
+/// let mut instances = CoreDumpInstancesSection::new();
+/// let module_idx = 0;
+/// let memories = vec![1];
+/// let globals = vec![2];
+/// instances.instance(module_idx, memories, globals);
+///
+/// let mut thread = CoreDumpStackSection::new("main");
+/// let instance_index = 0;
+/// let func_index = 42;
+/// let code_offset = 0x1234;
+/// let locals = vec![CoreDumpValue::I32(1)];
+/// let stack = vec![CoreDumpValue::I32(2)];
+/// thread.frame(instance_index, func_index, code_offset, locals, stack);
+///
+/// let mut module = Module::new();
+/// module.section(&core);
+/// module.section(&modules);
+/// module.section(&instances);
+/// module.section(&thread);
+/// ```
+#[derive(Clone, Debug, Default)]
+pub struct CoreDumpSection {
+ name: String,
+}
+
+impl CoreDumpSection {
+ /// Create a new core dump section encoder
+ pub fn new(name: impl Into<String>) -> Self {
+ let name = name.into();
+ CoreDumpSection { name }
+ }
+
+ /// View the encoded section as a CustomSection.
+ fn as_custom<'a>(&'a self) -> CustomSection<'a> {
+ let mut data = vec![0];
+ self.name.encode(&mut data);
+ CustomSection {
+ name: "core".into(),
+ data: Cow::Owned(data),
+ }
+ }
+}
+
+impl Encode for CoreDumpSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ self.as_custom().encode(sink);
+ }
+}
+
+impl Section for CoreDumpSection {
+ fn id(&self) -> u8 {
+ crate::core::SectionId::Custom as u8
+ }
+}
+
+/// The "coremodules" custom section for coredumps which lists the names of the
+/// modules
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{CoreDumpModulesSection, Module};
+/// let mut modules_section = CoreDumpModulesSection::new();
+/// modules_section.module("my_module");
+/// let mut module = Module::new();
+/// module.section(&modules_section);
+/// ```
+#[derive(Debug)]
+pub struct CoreDumpModulesSection {
+ num_added: u32,
+ bytes: Vec<u8>,
+}
+
+impl CoreDumpModulesSection {
+ /// Create a new core dump modules section encoder.
+ pub fn new() -> Self {
+ CoreDumpModulesSection {
+ bytes: vec![],
+ num_added: 0,
+ }
+ }
+
+ /// View the encoded section as a CustomSection.
+ pub fn as_custom(&self) -> CustomSection<'_> {
+ let mut data = vec![];
+ self.num_added.encode(&mut data);
+ data.extend(self.bytes.iter().copied());
+ CustomSection {
+ name: "coremodules".into(),
+ data: Cow::Owned(data),
+ }
+ }
+
+ /// Encode a module name into the section's bytes.
+ pub fn module(&mut self, module_name: impl AsRef<str>) -> &mut Self {
+ self.bytes.push(0x0);
+ module_name.as_ref().encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+
+ /// The number of modules that are encoded in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+}
+
+impl Encode for CoreDumpModulesSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ self.as_custom().encode(sink);
+ }
+}
+
+impl Section for CoreDumpModulesSection {
+ fn id(&self) -> u8 {
+ crate::core::SectionId::Custom as u8
+ }
+}
+
+/// The "coreinstances" section for the core dump
+#[derive(Debug)]
+pub struct CoreDumpInstancesSection {
+ num_added: u32,
+ bytes: Vec<u8>,
+}
+
+impl CoreDumpInstancesSection {
+ /// Create a new core dump instances section encoder.
+ pub fn new() -> Self {
+ CoreDumpInstancesSection {
+ bytes: vec![],
+ num_added: 0,
+ }
+ }
+
+ /// View the encoded section as a CustomSection.
+ pub fn as_custom(&self) -> CustomSection<'_> {
+ let mut data = vec![];
+ self.num_added.encode(&mut data);
+ data.extend(self.bytes.iter().copied());
+ CustomSection {
+ name: "coreinstances".into(),
+ data: Cow::Owned(data),
+ }
+ }
+
+ /// Encode an instance into the section's bytes.
+ pub fn instance<M, G>(&mut self, module_index: u32, memories: M, globals: G) -> &mut Self
+ where
+ M: IntoIterator<Item = u32>,
+ <M as IntoIterator>::IntoIter: ExactSizeIterator,
+ G: IntoIterator<Item = u32>,
+ <G as IntoIterator>::IntoIter: ExactSizeIterator,
+ {
+ self.bytes.push(0x0);
+ module_index.encode(&mut self.bytes);
+ crate::encode_vec(memories, &mut self.bytes);
+ crate::encode_vec(globals, &mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+
+ /// The number of modules that are encoded in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+}
+
+impl Encode for CoreDumpInstancesSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ self.as_custom().encode(sink);
+ }
+}
+
+impl Section for CoreDumpInstancesSection {
+ fn id(&self) -> u8 {
+ crate::core::SectionId::Custom as u8
+ }
+}
+
+/// A "corestack" custom section as described in the [tool-conventions
+/// repository](https://github.com/WebAssembly/tool-conventions/blob/main/Coredump.md)
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{CoreDumpStackSection, Module, CoreDumpValue};
+/// let mut thread = CoreDumpStackSection::new("main");
+///
+/// let instance_index = 0;
+/// let func_index = 42;
+/// let code_offset = 0x1234;
+/// let locals = vec![CoreDumpValue::I32(1)];
+/// let stack = vec![CoreDumpValue::I32(2)];
+/// thread.frame(instance_index, func_index, code_offset, locals, stack);
+///
+/// let mut module = Module::new();
+/// module.section(&thread);
+/// ```
+#[derive(Clone, Debug, Default)]
+pub struct CoreDumpStackSection {
+ frame_bytes: Vec<u8>,
+ count: u32,
+ name: String,
+}
+
+impl CoreDumpStackSection {
+ /// Create a new core dump stack section encoder.
+ pub fn new(name: impl Into<String>) -> Self {
+ let name = name.into();
+ CoreDumpStackSection {
+ frame_bytes: Vec::new(),
+ count: 0,
+ name,
+ }
+ }
+
+ /// Add a stack frame to this coredump stack section.
+ pub fn frame<L, S>(
+ &mut self,
+ instanceidx: u32,
+ funcidx: u32,
+ codeoffset: u32,
+ locals: L,
+ stack: S,
+ ) -> &mut Self
+ where
+ L: IntoIterator<Item = CoreDumpValue>,
+ <L as IntoIterator>::IntoIter: ExactSizeIterator,
+ S: IntoIterator<Item = CoreDumpValue>,
+ <S as IntoIterator>::IntoIter: ExactSizeIterator,
+ {
+ self.count += 1;
+ self.frame_bytes.push(0);
+ instanceidx.encode(&mut self.frame_bytes);
+ funcidx.encode(&mut self.frame_bytes);
+ codeoffset.encode(&mut self.frame_bytes);
+ crate::encode_vec(locals, &mut self.frame_bytes);
+ crate::encode_vec(stack, &mut self.frame_bytes);
+ self
+ }
+
+ /// View the encoded section as a CustomSection.
+ pub fn as_custom<'a>(&'a self) -> CustomSection<'a> {
+ let mut data = vec![0];
+ self.name.encode(&mut data);
+ self.count.encode(&mut data);
+ data.extend(&self.frame_bytes);
+ CustomSection {
+ name: "corestack".into(),
+ data: Cow::Owned(data),
+ }
+ }
+}
+
+impl Encode for CoreDumpStackSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ self.as_custom().encode(sink);
+ }
+}
+
+impl Section for CoreDumpStackSection {
+ fn id(&self) -> u8 {
+ crate::core::SectionId::Custom as u8
+ }
+}
+
+/// Local and stack values are encoded using one byte for the type (similar to
+/// Wasm's Number Types) followed by bytes representing the actual value
+/// See the tool-conventions repo for more details.
+#[derive(Clone, Debug)]
+pub enum CoreDumpValue {
+ /// a missing value (usually missing because it was optimized out)
+ Missing,
+ /// An i32 value
+ I32(i32),
+ /// An i64 value
+ I64(i64),
+ /// An f32 value
+ F32(f32),
+ /// An f64 value
+ F64(f64),
+}
+
+impl Encode for CoreDumpValue {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ match self {
+ CoreDumpValue::Missing => sink.push(0x01),
+ CoreDumpValue::I32(x) => {
+ sink.push(0x7F);
+ x.encode(sink);
+ }
+ CoreDumpValue::I64(x) => {
+ sink.push(0x7E);
+ x.encode(sink);
+ }
+ CoreDumpValue::F32(x) => {
+ sink.push(0x7D);
+ x.encode(sink);
+ }
+ CoreDumpValue::F64(x) => {
+ sink.push(0x7C);
+ x.encode(sink);
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::Module;
+ use wasmparser::{BinaryReader, FromReader, Parser, Payload};
+
+ // Create new core dump section and test whether it is properly encoded and
+ // parsed back out by wasmparser
+ #[test]
+ fn test_roundtrip_core() {
+ let core = CoreDumpSection::new("test.wasm");
+ let mut module = Module::new();
+ module.section(&core);
+
+ let wasm_bytes = module.finish();
+
+ let mut parser = Parser::new(0).parse_all(&wasm_bytes);
+ match parser.next() {
+ Some(Ok(Payload::Version { .. })) => {}
+ _ => panic!(""),
+ }
+
+ let payload = parser
+ .next()
+ .expect("parser is not empty")
+ .expect("element is a payload");
+ match payload {
+ Payload::CustomSection(section) => {
+ assert_eq!(section.name(), "core");
+ let core = wasmparser::CoreDumpSection::from_reader(&mut BinaryReader::new(
+ section.data(),
+ ))
+ .expect("data is readable into a core dump section");
+ assert_eq!(core.name, "test.wasm");
+ }
+ _ => panic!("unexpected payload"),
+ }
+ }
+
+ #[test]
+ fn test_roundtrip_coremodules() {
+ let mut coremodules = CoreDumpModulesSection::new();
+ coremodules.module("test_module");
+
+ let mut module = crate::Module::new();
+ module.section(&coremodules);
+
+ let wasm_bytes = module.finish();
+
+ let mut parser = Parser::new(0).parse_all(&wasm_bytes);
+ match parser.next() {
+ Some(Ok(Payload::Version { .. })) => {}
+ _ => panic!(""),
+ }
+
+ let payload = parser
+ .next()
+ .expect("parser is not empty")
+ .expect("element is a payload");
+ match payload {
+ Payload::CustomSection(section) => {
+ assert_eq!(section.name(), "coremodules");
+ let modules = wasmparser::CoreDumpModulesSection::from_reader(
+ &mut BinaryReader::new(section.data()),
+ )
+ .expect("data is readable into a core dump modules section");
+ assert_eq!(modules.modules[0], "test_module");
+ }
+ _ => panic!("unexpected payload"),
+ }
+ }
+
+ #[test]
+ fn test_roundtrip_coreinstances() {
+ let mut coreinstances = CoreDumpInstancesSection::new();
+ let module_index = 0;
+ let memories = vec![42];
+ let globals = vec![17];
+ coreinstances.instance(module_index, memories, globals);
+
+ let mut module = Module::new();
+ module.section(&coreinstances);
+ let wasm_bytes = module.finish();
+
+ let mut parser = Parser::new(0).parse_all(&wasm_bytes);
+ match parser.next() {
+ Some(Ok(Payload::Version { .. })) => {}
+ _ => panic!(""),
+ }
+
+ let payload = parser
+ .next()
+ .expect("parser is not empty")
+ .expect("element is a payload");
+ match payload {
+ Payload::CustomSection(section) => {
+ assert_eq!(section.name(), "coreinstances");
+ let coreinstances = wasmparser::CoreDumpInstancesSection::from_reader(
+ &mut BinaryReader::new(section.data()),
+ )
+ .expect("data is readable into a core dump instances section");
+ assert_eq!(coreinstances.instances.len(), 1);
+ let instance = coreinstances
+ .instances
+ .first()
+ .expect("instance is encoded");
+ assert_eq!(instance.module_index, 0);
+ assert_eq!(instance.memories.len(), 1);
+ assert_eq!(instance.globals.len(), 1);
+ }
+ _ => panic!("unexpected payload"),
+ }
+ }
+
+ // Create new corestack section and test whether it is properly encoded and
+ // parsed back out by wasmparser
+ #[test]
+ fn test_roundtrip_corestack() {
+ let mut corestack = CoreDumpStackSection::new("main");
+ corestack.frame(
+ 0,
+ 12,
+ 0,
+ vec![CoreDumpValue::I32(10)],
+ vec![CoreDumpValue::I32(42)],
+ );
+ let mut module = Module::new();
+ module.section(&corestack);
+ let wasm_bytes = module.finish();
+
+ let mut parser = Parser::new(0).parse_all(&wasm_bytes);
+ match parser.next() {
+ Some(Ok(Payload::Version { .. })) => {}
+ _ => panic!(""),
+ }
+
+ let payload = parser
+ .next()
+ .expect("parser is not empty")
+ .expect("element is a payload");
+ match payload {
+ Payload::CustomSection(section) => {
+ assert_eq!(section.name(), "corestack");
+ let corestack = wasmparser::CoreDumpStackSection::from_reader(
+ &mut BinaryReader::new(section.data()),
+ )
+ .expect("data is readable into a core dump stack section");
+ assert_eq!(corestack.name, "main");
+ assert_eq!(corestack.frames.len(), 1);
+ let frame = corestack
+ .frames
+ .first()
+ .expect("frame is encoded in corestack");
+ assert_eq!(frame.instanceidx, 0);
+ assert_eq!(frame.funcidx, 12);
+ assert_eq!(frame.codeoffset, 0);
+ assert_eq!(frame.locals.len(), 1);
+ match frame.locals.first().expect("frame contains a local") {
+ &wasmparser::CoreDumpValue::I32(val) => assert_eq!(val, 10),
+ _ => panic!("unexpected local value"),
+ }
+ assert_eq!(frame.stack.len(), 1);
+ match frame.stack.first().expect("stack contains a value") {
+ &wasmparser::CoreDumpValue::I32(val) => assert_eq!(val, 42),
+ _ => panic!("unexpected stack value"),
+ }
+ }
+ _ => panic!("unexpected payload"),
+ }
+ }
+
+ #[test]
+ fn test_encode_coredump_section() {
+ let core = CoreDumpSection::new("test");
+
+ let mut encoded = vec![];
+ core.encode(&mut encoded);
+
+ #[rustfmt::skip]
+ assert_eq!(encoded, vec![
+ // section length
+ 11,
+ // name length
+ 4,
+ // section name (core)
+ b'c',b'o',b'r',b'e',
+ // process-info (0, data length, data)
+ 0, 4, b't', b'e', b's', b't',
+ ]);
+ }
+
+ #[test]
+ fn test_encode_coremodules_section() {
+ let mut modules = CoreDumpModulesSection::new();
+ modules.module("mod1");
+ modules.module("mod2");
+
+ let mut encoded = vec![];
+ modules.encode(&mut encoded);
+
+ #[rustfmt::skip]
+ assert_eq!(encoded, vec![
+ // section length
+ 25,
+ // name length
+ 11,
+ // section name (coremodules)
+ b'c',b'o',b'r',b'e',b'm',b'o',b'd',b'u',b'l',b'e',b's',
+ // module count
+ 2,
+ // 0x0, name-length, module name (mod1)
+ 0x0, 4, b'm',b'o',b'd',b'1',
+ // 0x0, name-length, module name (mod2)
+ 0x0, 4, b'm',b'o',b'd',b'2'
+ ]);
+ }
+
+ #[test]
+ fn test_encode_coreinstances_section() {
+ let mut instances = CoreDumpInstancesSection::new();
+ instances.instance(0, vec![42], vec![17]);
+
+ let mut encoded = vec![];
+ instances.encode(&mut encoded);
+
+ #[rustfmt::skip]
+ assert_eq!(encoded, vec![
+ // section length
+ 21,
+ // name length
+ 13,
+ // section name (coreinstances)
+ b'c',b'o',b'r',b'e',b'i',b'n',b's',b't',b'a',b'n',b'c',b'e',b's',
+ // instance count
+ 1,
+ // 0x0, module_idx
+ 0x0, 0,
+ // memories count, memories
+ 1, 42,
+ // globals count, globals
+ 1, 17
+ ]);
+ }
+
+ #[test]
+ fn test_encode_corestack_section() {
+ let mut thread = CoreDumpStackSection::new("main");
+ thread.frame(
+ 0,
+ 42,
+ 51,
+ vec![CoreDumpValue::I32(1)],
+ vec![CoreDumpValue::I32(2)],
+ );
+
+ let mut encoded = vec![];
+ thread.encode(&mut encoded);
+
+ #[rustfmt::skip]
+ assert_eq!(
+ encoded,
+ vec![
+ // section length
+ 27,
+ // length of name.
+ 9,
+ // section name (corestack)
+ b'c',b'o',b'r',b'e',b's',b't',b'a',b'c',b'k',
+ // 0x0, thread name length
+ 0, 4,
+ // thread name (main)
+ b'm',b'a',b'i',b'n',
+ // frame count
+ 1,
+ // 0x0, instanceidx, funcidx, codeoffset
+ 0, 0, 42, 51,
+ // local count
+ 1,
+ // local value type
+ 0x7F,
+ // local value
+ 1,
+ // stack count
+ 1,
+ // stack value type
+ 0x7F,
+ // stack value
+ 2
+
+ ]
+ );
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/core/elements.rs b/third_party/rust/wasm-encoder/src/core/elements.rs
new file mode 100644
index 0000000000..31b772186a
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/core/elements.rs
@@ -0,0 +1,220 @@
+use crate::{encode_section, ConstExpr, Encode, RefType, Section, SectionId};
+
+/// An encoder for the element section.
+///
+/// Element sections are only supported for modules.
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{
+/// Elements, ElementSection, Module, TableSection, TableType,
+/// RefType, ConstExpr
+/// };
+///
+/// let mut tables = TableSection::new();
+/// tables.table(TableType {
+/// element_type: RefType::FUNCREF,
+/// minimum: 128,
+/// maximum: None,
+/// });
+///
+/// let mut elements = ElementSection::new();
+/// let table_index = 0;
+/// let offset = ConstExpr::i32_const(42);
+/// let functions = Elements::Functions(&[
+/// // Function indices...
+/// ]);
+/// elements.active(Some(table_index), &offset, functions);
+///
+/// let mut module = Module::new();
+/// module
+/// .section(&tables)
+/// .section(&elements);
+///
+/// let wasm_bytes = module.finish();
+/// ```
+#[derive(Clone, Default, Debug)]
+pub struct ElementSection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+/// A sequence of elements in a segment in the element section.
+#[derive(Clone, Copy, Debug)]
+pub enum Elements<'a> {
+ /// A sequences of references to functions by their indices.
+ Functions(&'a [u32]),
+ /// A sequence of reference expressions.
+ Expressions(RefType, &'a [ConstExpr]),
+}
+
+/// An element segment's mode.
+#[derive(Clone, Debug)]
+pub enum ElementMode<'a> {
+ /// A passive element segment.
+ ///
+ /// Passive segments are part of the bulk memory proposal.
+ Passive,
+ /// A declared element segment.
+ ///
+ /// Declared segments are part of the bulk memory proposal.
+ Declared,
+ /// An active element segment.
+ Active {
+ /// The table index.
+ ///
+ /// `Active` element specifying a `None` table forces the MVP encoding and refers to the
+ /// 0th table holding `funcref`s. Non-`None` tables use the encoding introduced with the
+ /// bulk memory proposal and can refer to tables with any valid reference type.
+ table: Option<u32>,
+ /// The offset within the table to place this segment.
+ offset: &'a ConstExpr,
+ },
+}
+
+/// An element segment in the element section.
+#[derive(Clone, Debug)]
+pub struct ElementSegment<'a> {
+ /// The element segment's mode.
+ pub mode: ElementMode<'a>,
+ /// This segment's elements.
+ pub elements: Elements<'a>,
+}
+
+impl ElementSection {
+ /// Create a new element section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of element segments in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Define an element segment.
+ pub fn segment<'a>(&mut self, segment: ElementSegment<'a>) -> &mut Self {
+ let expr_bit = match segment.elements {
+ Elements::Expressions(..) => 0b100u32,
+ Elements::Functions(_) => 0b000u32,
+ };
+ let mut encode_type = false;
+ match &segment.mode {
+ ElementMode::Passive => {
+ (0x01 | expr_bit).encode(&mut self.bytes);
+ encode_type = true;
+ }
+ ElementMode::Active { table, offset } => {
+ match (table, &segment.elements) {
+ // If the `table` is not specified then the 0x00 encoding
+ // can be used with either function indices or expressions
+ // that have a `funcref` type.
+ (None, Elements::Functions(_) | Elements::Expressions(RefType::FUNCREF, _)) => {
+ (/* 0x00 | */expr_bit).encode(&mut self.bytes);
+ }
+
+ // ... otherwise fall through for all other expressions here
+ // with table 0 or an explicitly specified table to the 0x02
+ // encoding.
+ (None, Elements::Expressions(..)) | (Some(_), _) => {
+ (0x02 | expr_bit).encode(&mut self.bytes);
+ table.unwrap_or(0).encode(&mut self.bytes);
+ encode_type = true;
+ }
+ }
+ offset.encode(&mut self.bytes);
+ }
+ ElementMode::Declared => {
+ (0x03 | expr_bit).encode(&mut self.bytes);
+ encode_type = true;
+ }
+ }
+
+ match segment.elements {
+ Elements::Functions(fs) => {
+ if encode_type {
+ // elemkind == funcref
+ self.bytes.push(0x00);
+ }
+ fs.encode(&mut self.bytes);
+ }
+ Elements::Expressions(ty, e) => {
+ if encode_type {
+ ty.encode(&mut self.bytes);
+ }
+ e.len().encode(&mut self.bytes);
+ for expr in e {
+ expr.encode(&mut self.bytes);
+ }
+ }
+ }
+
+ self.num_added += 1;
+ self
+ }
+
+ /// Define an active element segment.
+ ///
+ /// `Active` element specifying a `None` table forces the MVP encoding and refers to the 0th
+ /// table holding `funcref`s. Non-`None` tables use the encoding introduced with the bulk
+ /// memory proposal and can refer to tables with any valid reference type.
+ pub fn active(
+ &mut self,
+ table_index: Option<u32>,
+ offset: &ConstExpr,
+ elements: Elements<'_>,
+ ) -> &mut Self {
+ self.segment(ElementSegment {
+ mode: ElementMode::Active {
+ table: table_index,
+ offset,
+ },
+ elements,
+ })
+ }
+
+ /// Encode a passive element segment.
+ ///
+ /// Passive segments are part of the bulk memory proposal.
+ pub fn passive<'a>(&mut self, elements: Elements<'a>) -> &mut Self {
+ self.segment(ElementSegment {
+ mode: ElementMode::Passive,
+ elements,
+ })
+ }
+
+ /// Encode a declared element segment.
+ ///
+ /// Declared segments are part of the bulk memory proposal.
+ pub fn declared<'a>(&mut self, elements: Elements<'a>) -> &mut Self {
+ self.segment(ElementSegment {
+ mode: ElementMode::Declared,
+ elements,
+ })
+ }
+
+ /// Copy a raw, already-encoded element segment into this elements section.
+ pub fn raw(&mut self, raw_bytes: &[u8]) -> &mut Self {
+ self.bytes.extend_from_slice(raw_bytes);
+ self.num_added += 1;
+ self
+ }
+}
+
+impl Encode for ElementSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl Section for ElementSection {
+ fn id(&self) -> u8 {
+ SectionId::Element.into()
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/core/exports.rs b/third_party/rust/wasm-encoder/src/core/exports.rs
new file mode 100644
index 0000000000..fc2dc9c392
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/core/exports.rs
@@ -0,0 +1,98 @@
+use super::{
+ CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT, CORE_TABLE_SORT, CORE_TAG_SORT,
+};
+use crate::{encode_section, Encode, Section, SectionId};
+
+/// Represents the kind of an export from a WebAssembly module.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+#[repr(u8)]
+pub enum ExportKind {
+ /// The export is a function.
+ Func = CORE_FUNCTION_SORT,
+ /// The export is a table.
+ Table = CORE_TABLE_SORT,
+ /// The export is a memory.
+ Memory = CORE_MEMORY_SORT,
+ /// The export is a global.
+ Global = CORE_GLOBAL_SORT,
+ /// The export is a tag.
+ Tag = CORE_TAG_SORT,
+}
+
+impl Encode for ExportKind {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ sink.push(*self as u8);
+ }
+}
+
+#[cfg(feature = "wasmparser")]
+impl From<wasmparser::ExternalKind> for ExportKind {
+ fn from(external_kind: wasmparser::ExternalKind) -> Self {
+ match external_kind {
+ wasmparser::ExternalKind::Func => ExportKind::Func,
+ wasmparser::ExternalKind::Table => ExportKind::Table,
+ wasmparser::ExternalKind::Memory => ExportKind::Memory,
+ wasmparser::ExternalKind::Global => ExportKind::Global,
+ wasmparser::ExternalKind::Tag => ExportKind::Tag,
+ }
+ }
+}
+
+/// An encoder for the export section of WebAssembly module.
+///
+/// # Example
+///
+/// ```rust
+/// use wasm_encoder::{Module, ExportSection, ExportKind};
+///
+/// let mut exports = ExportSection::new();
+/// exports.export("foo", ExportKind::Func, 0);
+///
+/// let mut module = Module::new();
+/// module.section(&exports);
+///
+/// let bytes = module.finish();
+/// ```
+#[derive(Clone, Debug, Default)]
+pub struct ExportSection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+impl ExportSection {
+ /// Create a new export section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of exports in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Define an export in the export section.
+ pub fn export(&mut self, name: &str, kind: ExportKind, index: u32) -> &mut Self {
+ name.encode(&mut self.bytes);
+ kind.encode(&mut self.bytes);
+ index.encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+}
+
+impl Encode for ExportSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl Section for ExportSection {
+ fn id(&self) -> u8 {
+ SectionId::Export.into()
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/core/functions.rs b/third_party/rust/wasm-encoder/src/core/functions.rs
new file mode 100644
index 0000000000..e21d8c10a7
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/core/functions.rs
@@ -0,0 +1,63 @@
+use crate::{encode_section, Encode, Section, SectionId};
+
+/// An encoder for the function section of WebAssembly modules.
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{Module, FunctionSection, ValType};
+///
+/// let mut functions = FunctionSection::new();
+/// let type_index = 0;
+/// functions.function(type_index);
+///
+/// let mut module = Module::new();
+/// module.section(&functions);
+///
+/// // Note: this will generate an invalid module because we didn't generate a
+/// // code section containing the function body. See the documentation for
+/// // `CodeSection` for details.
+///
+/// let bytes = module.finish();
+/// ```
+#[derive(Clone, Debug, Default)]
+pub struct FunctionSection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+impl FunctionSection {
+ /// Construct a new module function section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of functions in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Define a function in a module's function section.
+ pub fn function(&mut self, type_index: u32) -> &mut Self {
+ type_index.encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+}
+
+impl Encode for FunctionSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl Section for FunctionSection {
+ fn id(&self) -> u8 {
+ SectionId::Function.into()
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/core/globals.rs b/third_party/rust/wasm-encoder/src/core/globals.rs
new file mode 100644
index 0000000000..64fec982cd
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/core/globals.rs
@@ -0,0 +1,101 @@
+use crate::{encode_section, ConstExpr, Encode, Section, SectionId, ValType};
+
+/// An encoder for the global section.
+///
+/// Global sections are only supported for modules.
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{ConstExpr, Module, GlobalSection, GlobalType, Instruction, ValType};
+///
+/// let mut globals = GlobalSection::new();
+/// globals.global(
+/// GlobalType {
+/// val_type: ValType::I32,
+/// mutable: false,
+/// },
+/// &ConstExpr::i32_const(42),
+/// );
+///
+/// let mut module = Module::new();
+/// module.section(&globals);
+///
+/// let wasm_bytes = module.finish();
+/// ```
+#[derive(Clone, Default, Debug)]
+pub struct GlobalSection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+impl GlobalSection {
+ /// Create a new global section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of globals in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Define a global.
+ pub fn global(&mut self, global_type: GlobalType, init_expr: &ConstExpr) -> &mut Self {
+ global_type.encode(&mut self.bytes);
+ init_expr.encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+
+ /// Add a raw byte slice into this code section as a global.
+ pub fn raw(&mut self, data: &[u8]) -> &mut Self {
+ self.bytes.extend(data);
+ self.num_added += 1;
+ self
+ }
+}
+
+impl Encode for GlobalSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl Section for GlobalSection {
+ fn id(&self) -> u8 {
+ SectionId::Global.into()
+ }
+}
+
+/// A global's type.
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
+pub struct GlobalType {
+ /// This global's value type.
+ pub val_type: ValType,
+ /// Whether this global is mutable or not.
+ pub mutable: bool,
+}
+
+impl Encode for GlobalType {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ self.val_type.encode(sink);
+ sink.push(self.mutable as u8);
+ }
+}
+
+#[cfg(feature = "wasmparser")]
+impl TryFrom<wasmparser::GlobalType> for GlobalType {
+ type Error = ();
+ fn try_from(global_ty: wasmparser::GlobalType) -> Result<Self, Self::Error> {
+ Ok(GlobalType {
+ val_type: global_ty.content_type.try_into()?,
+ mutable: global_ty.mutable,
+ })
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/core/imports.rs b/third_party/rust/wasm-encoder/src/core/imports.rs
new file mode 100644
index 0000000000..0030d640e6
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/core/imports.rs
@@ -0,0 +1,156 @@
+use crate::{
+ encode_section, Encode, GlobalType, MemoryType, Section, SectionId, TableType, TagType,
+ CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT, CORE_TABLE_SORT, CORE_TAG_SORT,
+};
+
+/// The type of an entity.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum EntityType {
+ /// A function type.
+ ///
+ /// The value is an index into the types section.
+ Function(u32),
+ /// A table type.
+ Table(TableType),
+ /// A memory type.
+ Memory(MemoryType),
+ /// A global type.
+ Global(GlobalType),
+ /// A tag type.
+ ///
+ /// This variant is used with the exception handling proposal.
+ Tag(TagType),
+}
+
+impl Encode for EntityType {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ match self {
+ Self::Function(i) => {
+ sink.push(CORE_FUNCTION_SORT);
+ i.encode(sink);
+ }
+ Self::Table(t) => {
+ sink.push(CORE_TABLE_SORT);
+ t.encode(sink);
+ }
+ Self::Memory(t) => {
+ sink.push(CORE_MEMORY_SORT);
+ t.encode(sink);
+ }
+ Self::Global(t) => {
+ sink.push(CORE_GLOBAL_SORT);
+ t.encode(sink);
+ }
+ Self::Tag(t) => {
+ sink.push(CORE_TAG_SORT);
+ t.encode(sink);
+ }
+ }
+ }
+}
+
+impl From<TableType> for EntityType {
+ fn from(t: TableType) -> Self {
+ Self::Table(t)
+ }
+}
+
+impl From<MemoryType> for EntityType {
+ fn from(t: MemoryType) -> Self {
+ Self::Memory(t)
+ }
+}
+
+impl From<GlobalType> for EntityType {
+ fn from(t: GlobalType) -> Self {
+ Self::Global(t)
+ }
+}
+
+impl From<TagType> for EntityType {
+ fn from(t: TagType) -> Self {
+ Self::Tag(t)
+ }
+}
+
+#[cfg(feature = "wasmparser")]
+impl TryFrom<wasmparser::TypeRef> for EntityType {
+ type Error = ();
+ fn try_from(type_ref: wasmparser::TypeRef) -> Result<Self, Self::Error> {
+ Ok(match type_ref {
+ wasmparser::TypeRef::Func(i) => EntityType::Function(i),
+ wasmparser::TypeRef::Table(t) => EntityType::Table(t.try_into()?),
+ wasmparser::TypeRef::Memory(m) => EntityType::Memory(m.into()),
+ wasmparser::TypeRef::Global(g) => EntityType::Global(g.try_into()?),
+ wasmparser::TypeRef::Tag(t) => EntityType::Tag(t.into()),
+ })
+ }
+}
+
+/// An encoder for the import section of WebAssembly modules.
+///
+/// # Example
+///
+/// ```rust
+/// use wasm_encoder::{MemoryType, Module, ImportSection};
+///
+/// let mut imports = ImportSection::new();
+/// imports.import(
+/// "env",
+/// "memory",
+/// MemoryType {
+/// minimum: 1,
+/// maximum: None,
+/// memory64: false,
+/// shared: false,
+/// }
+/// );
+///
+/// let mut module = Module::new();
+/// module.section(&imports);
+///
+/// let bytes = module.finish();
+/// ```
+#[derive(Clone, Debug, Default)]
+pub struct ImportSection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+impl ImportSection {
+ /// Create a new import section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of imports in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Define an import in the import section.
+ pub fn import(&mut self, module: &str, field: &str, ty: impl Into<EntityType>) -> &mut Self {
+ module.encode(&mut self.bytes);
+ field.encode(&mut self.bytes);
+ ty.into().encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+}
+
+impl Encode for ImportSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl Section for ImportSection {
+ fn id(&self) -> u8 {
+ SectionId::Import.into()
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/core/linking.rs b/third_party/rust/wasm-encoder/src/core/linking.rs
new file mode 100644
index 0000000000..9a2995721f
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/core/linking.rs
@@ -0,0 +1,263 @@
+use std::borrow::Cow;
+
+use crate::{encode_section, CustomSection, Encode, Section, SectionId};
+
+const VERSION: u32 = 2;
+
+/// An encoder for the [linking custom
+/// section](https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md#linking-metadata-section).
+///
+/// This section is a non-standard convention that is supported by the LLVM
+/// toolchain. It, along with associated "reloc.*" custom sections, allows you
+/// to treat a Wasm module as a low-level object file that can be linked with
+/// other Wasm object files to produce a final, complete Wasm module.
+///
+/// The linking section must come before the reloc sections.
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{LinkingSection, Module, SymbolTable};
+///
+/// // Create a new linking section.
+/// let mut linking = LinkingSection::new();
+///
+/// // Define a symbol table.
+/// let mut sym_tab = SymbolTable::new();
+///
+/// // Define a function symbol in the symbol table.
+/// let flags = SymbolTable::WASM_SYM_BINDING_LOCAL | SymbolTable::WASM_SYM_EXPORTED;
+/// let func_index = 42;
+/// let sym_name = "my_exported_func";
+/// sym_tab.function(flags, func_index, Some(sym_name));
+///
+/// // Add the symbol table to our linking section.
+/// linking.symbol_table(&sym_tab);
+///
+/// // Add the linking section to a new Wasm module and get the encoded bytes.
+/// let mut module = Module::new();
+/// module.section(&linking);
+/// let wasm_bytes = module.finish();
+/// ```
+#[derive(Clone, Debug)]
+pub struct LinkingSection {
+ bytes: Vec<u8>,
+}
+
+impl LinkingSection {
+ /// Construct a new encoder for the linking custom section.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ // TODO: `fn segment_info` for the `WASM_SEGMENT_INFO` linking subsection.
+
+ // TODO: `fn init_funcs` for the `WASM_INIT_FUNCS` linking subsection.
+
+ // TODO: `fn comdat_info` for the `WASM_COMDAT_INFO` linking subsection.
+
+ /// Add a symbol table subsection.
+ pub fn symbol_table(&mut self, symbol_table: &SymbolTable) -> &mut Self {
+ symbol_table.encode(&mut self.bytes);
+ self
+ }
+}
+
+impl Default for LinkingSection {
+ fn default() -> Self {
+ let mut bytes = Vec::new();
+ VERSION.encode(&mut bytes);
+ Self { bytes }
+ }
+}
+
+impl Encode for LinkingSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ CustomSection {
+ name: "linking".into(),
+ data: Cow::Borrowed(&self.bytes),
+ }
+ .encode(sink);
+ }
+}
+
+impl Section for LinkingSection {
+ fn id(&self) -> u8 {
+ SectionId::Custom.into()
+ }
+}
+
+#[allow(unused)]
+const WASM_SEGMENT_INFO: u8 = 5;
+#[allow(unused)]
+const WASM_INIT_FUNCS: u8 = 6;
+#[allow(unused)]
+const WASM_COMDAT_INFO: u8 = 7;
+const WASM_SYMBOL_TABLE: u8 = 8;
+
+/// A subsection of the [linking custom section][crate::LinkingSection] that
+/// provides extra information about the symbols present in this Wasm object
+/// file.
+#[derive(Clone, Debug, Default)]
+pub struct SymbolTable {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+const SYMTAB_FUNCTION: u32 = 0;
+const SYMTAB_DATA: u32 = 1;
+const SYMTAB_GLOBAL: u32 = 2;
+#[allow(unused)]
+const SYMTAB_SECTION: u32 = 3;
+#[allow(unused)]
+const SYMTAB_TAG: u32 = 4;
+const SYMTAB_TABLE: u32 = 5;
+
+impl SymbolTable {
+ /// Construct a new symbol table subsection encoder.
+ pub fn new() -> Self {
+ SymbolTable {
+ bytes: vec![],
+ num_added: 0,
+ }
+ }
+
+ /// Define a function symbol in this symbol table.
+ ///
+ /// The `name` must be omitted if `index` references an imported table and
+ /// the `WASM_SYM_EXPLICIT_NAME` flag is not set.
+ pub fn function(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self {
+ SYMTAB_FUNCTION.encode(&mut self.bytes);
+ flags.encode(&mut self.bytes);
+ index.encode(&mut self.bytes);
+ if let Some(name) = name {
+ name.encode(&mut self.bytes);
+ }
+ self.num_added += 1;
+ self
+ }
+
+ /// Define a global symbol in this symbol table.
+ ///
+ /// The `name` must be omitted if `index` references an imported table and
+ /// the `WASM_SYM_EXPLICIT_NAME` flag is not set.
+ pub fn global(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self {
+ SYMTAB_GLOBAL.encode(&mut self.bytes);
+ flags.encode(&mut self.bytes);
+ index.encode(&mut self.bytes);
+ if let Some(name) = name {
+ name.encode(&mut self.bytes);
+ }
+ self.num_added += 1;
+ self
+ }
+
+ // TODO: tags
+
+ /// Define a table symbol in this symbol table.
+ ///
+ /// The `name` must be omitted if `index` references an imported table and
+ /// the `WASM_SYM_EXPLICIT_NAME` flag is not set.
+ pub fn table(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self {
+ SYMTAB_TABLE.encode(&mut self.bytes);
+ flags.encode(&mut self.bytes);
+ index.encode(&mut self.bytes);
+ if let Some(name) = name {
+ name.encode(&mut self.bytes);
+ }
+ self.num_added += 1;
+ self
+ }
+
+ /// Add a data symbol to this symbol table.
+ pub fn data(
+ &mut self,
+ flags: u32,
+ name: &str,
+ definition: Option<DataSymbolDefinition>,
+ ) -> &mut Self {
+ SYMTAB_DATA.encode(&mut self.bytes);
+ flags.encode(&mut self.bytes);
+ name.encode(&mut self.bytes);
+ if let Some(def) = definition {
+ def.index.encode(&mut self.bytes);
+ def.offset.encode(&mut self.bytes);
+ def.size.encode(&mut self.bytes);
+ }
+ self.num_added += 1;
+ self
+ }
+
+ // TODO: sections
+
+ /// This is a weak symbol.
+ ///
+ /// This flag is mutually exclusive with `WASM_SYM_BINDING_LOCAL`.
+ ///
+ /// When linking multiple modules defining the same symbol, all weak
+ /// definitions are discarded if any strong definitions exist; then if
+ /// multiple weak definitions exist all but one (unspecified) are discarded;
+ /// and finally it is an error if more than one definition remains.
+ pub const WASM_SYM_BINDING_WEAK: u32 = 0x1;
+
+ /// This is a local symbol.
+ ///
+ /// This flag is mutually exclusive with `WASM_SYM_BINDING_WEAK`.
+ ///
+ /// Local symbols are not to be exported, or linked to other
+ /// modules/sections. The names of all non-local symbols must be unique, but
+ /// the names of local symbols are not considered for uniqueness. A local
+ /// function or global symbol cannot reference an import.
+ pub const WASM_SYM_BINDING_LOCAL: u32 = 0x02;
+
+ /// This is a hidden symbol.
+ ///
+ /// Hidden symbols are not to be exported when performing the final link,
+ /// but may be linked to other modules.
+ pub const WASM_SYM_VISIBILITY_HIDDEN: u32 = 0x04;
+
+ /// This symbol is not defined.
+ ///
+ /// For non-data symbols, this must match whether the symbol is an import or
+ /// is defined; for data symbols, determines whether a segment is specified.
+ pub const WASM_SYM_UNDEFINED: u32 = 0x10;
+
+ /// This symbol is intended to be exported from the wasm module to the host
+ /// environment.
+ ///
+ /// This differs from the visibility flags in that it effects the static
+ /// linker.
+ pub const WASM_SYM_EXPORTED: u32 = 0x20;
+
+ /// This symbol uses an explicit symbol name, rather than reusing the name
+ /// from a wasm import.
+ ///
+ /// This allows it to remap imports from foreign WebAssembly modules into
+ /// local symbols with different names.
+ pub const WASM_SYM_EXPLICIT_NAME: u32 = 0x40;
+
+ /// This symbol is intended to be included in the linker output, regardless
+ /// of whether it is used by the program.
+ pub const WASM_SYM_NO_STRIP: u32 = 0x80;
+}
+
+impl Encode for SymbolTable {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ sink.push(WASM_SYMBOL_TABLE);
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+/// The definition of a data symbol within a symbol table.
+#[derive(Clone, Debug)]
+pub struct DataSymbolDefinition {
+ /// The index of the data segment that this symbol is in.
+ pub index: u32,
+ /// The offset of this symbol within its segment.
+ pub offset: u32,
+ /// The byte size (which can be zero) of this data symbol.
+ ///
+ /// Note that `offset + size` must be less than or equal to the segment's
+ /// size.
+ pub size: u32,
+}
diff --git a/third_party/rust/wasm-encoder/src/core/memories.rs b/third_party/rust/wasm-encoder/src/core/memories.rs
new file mode 100644
index 0000000000..892545eb98
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/core/memories.rs
@@ -0,0 +1,111 @@
+use crate::{encode_section, Encode, Section, SectionId};
+
+/// An encoder for the memory section.
+///
+/// Memory sections are only supported for modules.
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{Module, MemorySection, MemoryType};
+///
+/// let mut memories = MemorySection::new();
+/// memories.memory(MemoryType {
+/// minimum: 1,
+/// maximum: None,
+/// memory64: false,
+/// shared: false,
+/// });
+///
+/// let mut module = Module::new();
+/// module.section(&memories);
+///
+/// let wasm_bytes = module.finish();
+/// ```
+#[derive(Clone, Default, Debug)]
+pub struct MemorySection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+impl MemorySection {
+ /// Create a new memory section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of memories in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Define a memory.
+ pub fn memory(&mut self, memory_type: MemoryType) -> &mut Self {
+ memory_type.encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+}
+
+impl Encode for MemorySection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl Section for MemorySection {
+ fn id(&self) -> u8 {
+ SectionId::Memory.into()
+ }
+}
+
+/// A memory's type.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct MemoryType {
+ /// Minimum size, in pages, of this memory
+ pub minimum: u64,
+ /// Maximum size, in pages, of this memory
+ pub maximum: Option<u64>,
+ /// Whether or not this is a 64-bit memory.
+ pub memory64: bool,
+ /// Whether or not this memory is shared.
+ pub shared: bool,
+}
+
+impl Encode for MemoryType {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ let mut flags = 0;
+ if self.maximum.is_some() {
+ flags |= 0b001;
+ }
+ if self.shared {
+ flags |= 0b010;
+ }
+ if self.memory64 {
+ flags |= 0b100;
+ }
+
+ sink.push(flags);
+ self.minimum.encode(sink);
+ if let Some(max) = self.maximum {
+ max.encode(sink);
+ }
+ }
+}
+
+#[cfg(feature = "wasmparser")]
+impl From<wasmparser::MemoryType> for MemoryType {
+ fn from(memory_ty: wasmparser::MemoryType) -> Self {
+ MemoryType {
+ minimum: memory_ty.initial,
+ maximum: memory_ty.maximum,
+ memory64: memory_ty.memory64,
+ shared: memory_ty.shared,
+ }
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/core/names.rs b/third_party/rust/wasm-encoder/src/core/names.rs
new file mode 100644
index 0000000000..587ae6a792
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/core/names.rs
@@ -0,0 +1,298 @@
+use std::borrow::Cow;
+
+use crate::{encoding_size, CustomSection, Encode, Section, SectionId};
+
+/// An encoder for the custom `name` section.
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{Module, NameSection, NameMap};
+///
+/// let mut names = NameSection::new();
+/// names.module("the module name");
+///
+/// let mut function_names = NameMap::new();
+/// function_names.append(0, "name of function 0");
+/// function_names.append(1, "a better function");
+/// function_names.append(3, "the best function");
+/// names.functions(&function_names);
+///
+/// let mut module = Module::new();
+/// module.section(&names);
+///
+/// let wasm_bytes = module.finish();
+/// ```
+#[derive(Clone, Debug, Default)]
+pub struct NameSection {
+ bytes: Vec<u8>,
+}
+
+enum Subsection {
+ // Currently specified in the wasm spec's appendix
+ Module = 0,
+ Function = 1,
+ Local = 2,
+
+ // specified as part of the extended name section proposal
+ //
+ // https://github.com/WebAssembly/extended-name-section/blob/main/proposals/extended-name-section/Overview.md
+ Label = 3,
+ Type = 4,
+ Table = 5,
+ Memory = 6,
+ Global = 7,
+ Element = 8,
+ Data = 9,
+
+ // https://github.com/WebAssembly/gc/issues/193
+ Field = 10,
+
+ // https://github.com/WebAssembly/exception-handling/pull/213
+ Tag = 11,
+}
+
+impl NameSection {
+ /// Creates a new blank `name` custom section.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// Appends a module name subsection to this section.
+ ///
+ /// This will indicate that the name of the entire module should be the
+ /// `name` specified. Note that this should be encoded first before other
+ /// subsections.
+ pub fn module(&mut self, name: &str) {
+ let len = encoding_size(u32::try_from(name.len()).unwrap());
+ self.subsection_header(Subsection::Module, len + name.len());
+ name.encode(&mut self.bytes);
+ }
+
+ /// Appends a subsection for the names of all functions in this wasm module.
+ ///
+ /// Function names are declared in the `names` map provided where the index
+ /// in the map corresponds to the wasm index of the function. This section
+ /// should come after the module name subsection (if present) and before the
+ /// locals subsection (if present).
+ pub fn functions(&mut self, names: &NameMap) {
+ self.subsection_header(Subsection::Function, names.size());
+ names.encode(&mut self.bytes);
+ }
+
+ /// Appends a subsection for the names of locals within functions in this
+ /// wasm module.
+ ///
+ /// This section should come after the function name subsection (if present)
+ /// and before the labels subsection (if present).
+ pub fn locals(&mut self, names: &IndirectNameMap) {
+ self.subsection_header(Subsection::Local, names.size());
+ names.encode(&mut self.bytes);
+ }
+
+ /// Appends a subsection for the names of labels within functions in this
+ /// wasm module.
+ ///
+ /// This section should come after the local name subsection (if present)
+ /// and before the type subsection (if present).
+ pub fn labels(&mut self, names: &IndirectNameMap) {
+ self.subsection_header(Subsection::Label, names.size());
+ names.encode(&mut self.bytes);
+ }
+
+ /// Appends a subsection for the names of all types in this wasm module.
+ ///
+ /// This section should come after the label name subsection (if present)
+ /// and before the table subsection (if present).
+ pub fn types(&mut self, names: &NameMap) {
+ self.subsection_header(Subsection::Type, names.size());
+ names.encode(&mut self.bytes);
+ }
+
+ /// Appends a subsection for the names of all tables in this wasm module.
+ ///
+ /// This section should come after the type name subsection (if present)
+ /// and before the memory subsection (if present).
+ pub fn tables(&mut self, names: &NameMap) {
+ self.subsection_header(Subsection::Table, names.size());
+ names.encode(&mut self.bytes);
+ }
+
+ /// Appends a subsection for the names of all memories in this wasm module.
+ ///
+ /// This section should come after the table name subsection (if present)
+ /// and before the global subsection (if present).
+ pub fn memories(&mut self, names: &NameMap) {
+ self.subsection_header(Subsection::Memory, names.size());
+ names.encode(&mut self.bytes);
+ }
+
+ /// Appends a subsection for the names of all globals in this wasm module.
+ ///
+ /// This section should come after the memory name subsection (if present)
+ /// and before the element subsection (if present).
+ pub fn globals(&mut self, names: &NameMap) {
+ self.subsection_header(Subsection::Global, names.size());
+ names.encode(&mut self.bytes);
+ }
+
+ /// Appends a subsection for the names of all elements in this wasm module.
+ ///
+ /// This section should come after the global name subsection (if present)
+ /// and before the data subsection (if present).
+ pub fn elements(&mut self, names: &NameMap) {
+ self.subsection_header(Subsection::Element, names.size());
+ names.encode(&mut self.bytes);
+ }
+
+ /// Appends a subsection for the names of all data in this wasm module.
+ ///
+ /// This section should come after the element name subsection (if present)
+ /// and before the field subsection (if present).
+ pub fn data(&mut self, names: &NameMap) {
+ self.subsection_header(Subsection::Data, names.size());
+ names.encode(&mut self.bytes);
+ }
+
+ /// Appends a subsection for the names of all tags in this wasm module.
+ ///
+ /// This section should come after the data name subsection (if present).
+ pub fn tag(&mut self, names: &NameMap) {
+ self.subsection_header(Subsection::Tag, names.size());
+ names.encode(&mut self.bytes);
+ }
+
+ /// Appends a subsection for the names of fields within types in this
+ /// wasm module.
+ ///
+ /// This section should come after the data name subsection (if present)
+ /// and before the tag subsection (if present).
+ pub fn fields(&mut self, names: &IndirectNameMap) {
+ self.subsection_header(Subsection::Field, names.size());
+ names.encode(&mut self.bytes);
+ }
+
+ /// Appends a subsection for the names of all tags in this wasm module.
+ ///
+ /// This section should come after the field name subsection (if present).
+ pub fn tags(&mut self, names: &NameMap) {
+ self.subsection_header(Subsection::Tag, names.size());
+ names.encode(&mut self.bytes);
+ }
+
+ fn subsection_header(&mut self, id: Subsection, len: usize) {
+ self.bytes.push(id as u8);
+ len.encode(&mut self.bytes);
+ }
+
+ /// View the encoded section as a CustomSection.
+ pub fn as_custom<'a>(&'a self) -> CustomSection<'a> {
+ CustomSection {
+ name: "name".into(),
+ data: Cow::Borrowed(&self.bytes),
+ }
+ }
+}
+
+impl Encode for NameSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ self.as_custom().encode(sink);
+ }
+}
+
+impl Section for NameSection {
+ fn id(&self) -> u8 {
+ SectionId::Custom.into()
+ }
+}
+
+/// A map used to name items in a wasm module, organized by naming each
+/// individual index.
+///
+/// This is used in conjunction with [`NameSection::functions`] and simlar
+/// methods.
+#[derive(Clone, Debug, Default)]
+pub struct NameMap {
+ bytes: Vec<u8>,
+ count: u32,
+}
+
+impl NameMap {
+ /// Creates a new empty `NameMap`.
+ pub fn new() -> NameMap {
+ NameMap {
+ bytes: vec![],
+ count: 0,
+ }
+ }
+
+ /// Adds a an entry where the item at `idx` has the `name` specified.
+ ///
+ /// Note that indices should be appended in ascending order of the index
+ /// value. Each index may only be named once, but not all indices must be
+ /// named (e.g. `0 foo; 1 bar; 7 qux` is valid but `0 foo; 0 bar` is not).
+ /// Names do not have to be unique (e.g. `0 foo; 1 foo; 2 foo` is valid).
+ pub fn append(&mut self, idx: u32, name: &str) {
+ idx.encode(&mut self.bytes);
+ name.encode(&mut self.bytes);
+ self.count += 1;
+ }
+
+ pub(crate) fn size(&self) -> usize {
+ encoding_size(self.count) + self.bytes.len()
+ }
+
+ /// Returns whether no names have been added to this map.
+ pub fn is_empty(&self) -> bool {
+ self.count == 0
+ }
+}
+
+impl Encode for NameMap {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ self.count.encode(sink);
+ sink.extend(&self.bytes);
+ }
+}
+
+/// A map used to describe names with two levels of indirection, as opposed to a
+/// [`NameMap`] which has one level of indirection.
+///
+/// This naming map is used with [`NameSection::locals`], for example.
+#[derive(Clone, Debug, Default)]
+pub struct IndirectNameMap {
+ bytes: Vec<u8>,
+ count: u32,
+}
+
+impl IndirectNameMap {
+ /// Creates a new empty name map.
+ pub fn new() -> IndirectNameMap {
+ IndirectNameMap {
+ bytes: vec![],
+ count: 0,
+ }
+ }
+
+ /// Adds a new entry where the item at `idx` has sub-items named within
+ /// `names` as specified.
+ ///
+ /// For example if this is describing local names then `idx` is a function
+ /// index where the indexes within `names` are local indices.
+ pub fn append(&mut self, idx: u32, names: &NameMap) {
+ idx.encode(&mut self.bytes);
+ names.encode(&mut self.bytes);
+ self.count += 1;
+ }
+
+ fn size(&self) -> usize {
+ encoding_size(self.count) + self.bytes.len()
+ }
+}
+
+impl Encode for IndirectNameMap {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ self.count.encode(sink);
+ sink.extend(&self.bytes);
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/core/producers.rs b/third_party/rust/wasm-encoder/src/core/producers.rs
new file mode 100644
index 0000000000..af03ecbb8e
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/core/producers.rs
@@ -0,0 +1,180 @@
+use std::borrow::Cow;
+
+use crate::{CustomSection, Encode, Section, SectionId};
+
+/// An encoder for the [producers custom
+/// section](https://github.com/WebAssembly/tool-conventions/blob/main/ProducersSection.md).
+///
+/// This section is a non-standard convention that is supported by many toolchains.
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{ProducersSection, ProducersField, Module};
+///
+/// // Create a new producers section.
+/// let mut field = ProducersField::new();
+/// field.value("clang", "14.0.4");
+/// field.value("rustc", "1.66.1 (90743e729 2023-01-10)");
+/// let mut producers = ProducersSection::new();
+/// producers.field("processed-by", &field);
+///
+/// // Add the producers section to a new Wasm module and get the encoded bytes.
+/// let mut module = Module::new();
+/// module.section(&producers);
+/// let wasm_bytes = module.finish();
+/// ```
+#[derive(Clone, Debug)]
+pub struct ProducersSection {
+ bytes: Vec<u8>,
+ num_fields: u32,
+}
+
+impl ProducersSection {
+ /// Construct an empty encoder for the producers custom section.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// Add a field to the section. The spec recommends names for this section
+ /// are "language", "processed-by", and "sdk". Each field in section must
+ /// have a unique name.
+ pub fn field(&mut self, name: &str, values: &ProducersField) -> &mut Self {
+ name.encode(&mut self.bytes);
+ values.encode(&mut self.bytes);
+ self.num_fields += 1;
+ self
+ }
+}
+
+impl Default for ProducersSection {
+ fn default() -> Self {
+ Self {
+ bytes: Vec::new(),
+ num_fields: 0,
+ }
+ }
+}
+
+impl Encode for ProducersSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ let mut data = Vec::new();
+ self.num_fields.encode(&mut data);
+ data.extend(&self.bytes);
+
+ CustomSection {
+ name: "producers".into(),
+ data: Cow::Borrowed(&data),
+ }
+ .encode(sink);
+ }
+}
+
+impl Section for ProducersSection {
+ fn id(&self) -> u8 {
+ SectionId::Custom.into()
+ }
+}
+
+/// The value of a field in the producers custom section
+#[derive(Clone, Debug)]
+pub struct ProducersField {
+ bytes: Vec<u8>,
+ num_values: u32,
+}
+
+impl ProducersField {
+ /// Construct an empty encoder for a producers field value
+ pub fn new() -> Self {
+ ProducersField::default()
+ }
+
+ /// Add a value to the field encoder. Each value in a field must have a
+ /// unique name. If there is no sensible value for `version`, use the
+ /// empty string.
+ pub fn value(&mut self, name: &str, version: &str) -> &mut Self {
+ name.encode(&mut self.bytes);
+ version.encode(&mut self.bytes);
+ self.num_values += 1;
+ self
+ }
+}
+
+impl Default for ProducersField {
+ fn default() -> Self {
+ Self {
+ bytes: Vec::new(),
+ num_values: 0,
+ }
+ }
+}
+
+impl Encode for ProducersField {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ self.num_values.encode(sink);
+ sink.extend(&self.bytes);
+ }
+}
+
+#[cfg(test)]
+mod test {
+ #[test]
+ fn roundtrip_example() {
+ use crate::{Module, ProducersField, ProducersSection};
+ use wasmparser::{Parser, Payload, ProducersSectionReader};
+
+ // Create a new producers section.
+ let mut field = ProducersField::new();
+ field.value("clang", "14.0.4");
+ field.value("rustc", "1.66.1");
+ let mut producers = ProducersSection::new();
+ producers.field("processed-by", &field);
+
+ // Add the producers section to a new Wasm module and get the encoded bytes.
+ let mut module = Module::new();
+ module.section(&producers);
+ let wasm_bytes = module.finish();
+
+ let mut parser = Parser::new(0).parse_all(&wasm_bytes);
+ let payload = parser
+ .next()
+ .expect("parser is not empty")
+ .expect("element is a payload");
+ match payload {
+ Payload::Version { .. } => {}
+ _ => panic!(""),
+ }
+ let payload = parser
+ .next()
+ .expect("parser is not empty")
+ .expect("element is a payload");
+ match payload {
+ Payload::CustomSection(c) => {
+ assert_eq!(c.name(), "producers");
+ let mut section = ProducersSectionReader::new(c.data(), c.data_offset())
+ .expect("readable as a producers section")
+ .into_iter();
+ let field = section
+ .next()
+ .expect("section has an element")
+ .expect("element is a producers field");
+ assert_eq!(field.name, "processed-by");
+ let mut values = field.values.into_iter();
+ let value = values
+ .next()
+ .expect("values has an element")
+ .expect("element is a producers field value");
+ assert_eq!(value.name, "clang");
+ assert_eq!(value.version, "14.0.4");
+
+ let value = values
+ .next()
+ .expect("values has another element")
+ .expect("element is a producers field value");
+ assert_eq!(value.name, "rustc");
+ assert_eq!(value.version, "1.66.1");
+ }
+ _ => panic!("unexpected payload"),
+ }
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/core/start.rs b/third_party/rust/wasm-encoder/src/core/start.rs
new file mode 100644
index 0000000000..8f12c0d0ef
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/core/start.rs
@@ -0,0 +1,39 @@
+use crate::{encoding_size, Encode, Section, SectionId};
+
+/// An encoder for the start section of WebAssembly modules.
+///
+/// # Example
+///
+/// Note: this doesn't actually define the function at index 0, its type, or its
+/// code body, so the resulting Wasm module will be invalid. See `TypeSection`,
+/// `FunctionSection`, and `CodeSection` for details on how to generate those
+/// things.
+///
+/// ```
+/// use wasm_encoder::{Module, StartSection};
+///
+/// let start = StartSection { function_index: 0 };
+///
+/// let mut module = Module::new();
+/// module.section(&start);
+///
+/// let wasm_bytes = module.finish();
+/// ```
+#[derive(Clone, Copy, Debug)]
+pub struct StartSection {
+ /// The index of the start function.
+ pub function_index: u32,
+}
+
+impl Encode for StartSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encoding_size(self.function_index).encode(sink);
+ self.function_index.encode(sink);
+ }
+}
+
+impl Section for StartSection {
+ fn id(&self) -> u8 {
+ SectionId::Start.into()
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/core/tables.rs b/third_party/rust/wasm-encoder/src/core/tables.rs
new file mode 100644
index 0000000000..cb224c1564
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/core/tables.rs
@@ -0,0 +1,116 @@
+use crate::{encode_section, ConstExpr, Encode, RefType, Section, SectionId};
+
+/// An encoder for the table section.
+///
+/// Table sections are only supported for modules.
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{Module, TableSection, TableType, RefType};
+///
+/// let mut tables = TableSection::new();
+/// tables.table(TableType {
+/// element_type: RefType::FUNCREF,
+/// minimum: 128,
+/// maximum: None,
+/// });
+///
+/// let mut module = Module::new();
+/// module.section(&tables);
+///
+/// let wasm_bytes = module.finish();
+/// ```
+#[derive(Clone, Default, Debug)]
+pub struct TableSection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+impl TableSection {
+ /// Construct a new table section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of tables in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Define a table.
+ pub fn table(&mut self, table_type: TableType) -> &mut Self {
+ table_type.encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+
+ /// Define a table with an explicit initialization expression.
+ ///
+ /// Note that this is part of the function-references proposal.
+ pub fn table_with_init(&mut self, table_type: TableType, init: &ConstExpr) -> &mut Self {
+ self.bytes.push(0x40);
+ self.bytes.push(0x00);
+ table_type.encode(&mut self.bytes);
+ init.encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+}
+
+impl Encode for TableSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl Section for TableSection {
+ fn id(&self) -> u8 {
+ SectionId::Table.into()
+ }
+}
+
+/// A table's type.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct TableType {
+ /// The table's element type.
+ pub element_type: RefType,
+ /// Minimum size, in elements, of this table
+ pub minimum: u32,
+ /// Maximum size, in elements, of this table
+ pub maximum: Option<u32>,
+}
+
+impl Encode for TableType {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ let mut flags = 0;
+ if self.maximum.is_some() {
+ flags |= 0b001;
+ }
+
+ self.element_type.encode(sink);
+ sink.push(flags);
+ self.minimum.encode(sink);
+
+ if let Some(max) = self.maximum {
+ max.encode(sink);
+ }
+ }
+}
+
+#[cfg(feature = "wasmparser")]
+impl TryFrom<wasmparser::TableType> for TableType {
+ type Error = ();
+ fn try_from(table_ty: wasmparser::TableType) -> Result<Self, Self::Error> {
+ Ok(TableType {
+ element_type: table_ty.element_type.try_into()?,
+ minimum: table_ty.initial,
+ maximum: table_ty.maximum,
+ })
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/core/tags.rs b/third_party/rust/wasm-encoder/src/core/tags.rs
new file mode 100644
index 0000000000..9b4c728a8c
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/core/tags.rs
@@ -0,0 +1,104 @@
+use crate::{encode_section, Encode, Section, SectionId};
+
+/// An encoder for the tag section.
+///
+/// # Example
+///
+/// ```
+/// use wasm_encoder::{Module, TagSection, TagType, TagKind};
+///
+/// let mut tags = TagSection::new();
+/// tags.tag(TagType {
+/// kind: TagKind::Exception,
+/// func_type_idx: 0,
+/// });
+///
+/// let mut module = Module::new();
+/// module.section(&tags);
+///
+/// let wasm_bytes = module.finish();
+/// ```
+#[derive(Clone, Default, Debug)]
+pub struct TagSection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+impl TagSection {
+ /// Create a new tag section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of tags in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Define a tag.
+ pub fn tag(&mut self, tag_type: TagType) -> &mut Self {
+ tag_type.encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+}
+
+impl Encode for TagSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl Section for TagSection {
+ fn id(&self) -> u8 {
+ SectionId::Tag.into()
+ }
+}
+
+/// Represents a tag kind.
+#[repr(u8)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum TagKind {
+ /// The tag is an exception type.
+ Exception = 0x0,
+}
+
+#[cfg(feature = "wasmparser")]
+impl From<wasmparser::TagKind> for TagKind {
+ fn from(kind: wasmparser::TagKind) -> Self {
+ match kind {
+ wasmparser::TagKind::Exception => TagKind::Exception,
+ }
+ }
+}
+
+/// A tag's type.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct TagType {
+ /// The kind of tag
+ pub kind: TagKind,
+ /// The function type this tag uses
+ pub func_type_idx: u32,
+}
+
+impl Encode for TagType {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ sink.push(self.kind as u8);
+ self.func_type_idx.encode(sink);
+ }
+}
+
+#[cfg(feature = "wasmparser")]
+impl From<wasmparser::TagType> for TagType {
+ fn from(tag_ty: wasmparser::TagType) -> Self {
+ TagType {
+ kind: tag_ty.kind.into(),
+ func_type_idx: tag_ty.func_type_idx,
+ }
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/core/types.rs b/third_party/rust/wasm-encoder/src/core/types.rs
new file mode 100644
index 0000000000..bfc54ae1e3
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/core/types.rs
@@ -0,0 +1,673 @@
+use crate::{encode_section, Encode, Section, SectionId};
+
+/// Represents a subtype of possible other types in a WebAssembly module.
+#[derive(Debug, Clone)]
+pub struct SubType {
+ /// Is the subtype final.
+ pub is_final: bool,
+ /// The list of supertype indexes. As of GC MVP, there can be at most one supertype.
+ pub supertype_idx: Option<u32>,
+ /// The composite type of the subtype.
+ pub composite_type: CompositeType,
+}
+
+impl Encode for SubType {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ // We only need to emit a prefix byte before the actual composite type
+ // when either the type is not final or it has a declared super type.
+ if self.supertype_idx.is_some() || !self.is_final {
+ sink.push(if self.is_final { 0x4f } else { 0x50 });
+ self.supertype_idx.encode(sink);
+ }
+ self.composite_type.encode(sink);
+ }
+}
+
+#[cfg(feature = "wasmparser")]
+impl TryFrom<wasmparser::SubType> for SubType {
+ type Error = ();
+
+ fn try_from(sub_ty: wasmparser::SubType) -> Result<Self, Self::Error> {
+ Ok(SubType {
+ is_final: sub_ty.is_final,
+ supertype_idx: sub_ty
+ .supertype_idx
+ .map(|i| i.as_module_index().ok_or(()))
+ .transpose()?,
+ composite_type: sub_ty.composite_type.try_into()?,
+ })
+ }
+}
+
+/// Represents a composite type in a WebAssembly module.
+#[derive(Debug, Clone)]
+pub enum CompositeType {
+ /// The type is for a function.
+ Func(FuncType),
+ /// The type is for an array.
+ Array(ArrayType),
+ /// The type is for a struct.
+ Struct(StructType),
+}
+
+impl Encode for CompositeType {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ match self {
+ CompositeType::Func(ty) => TypeSection::encode_function(
+ sink,
+ ty.params().iter().copied(),
+ ty.results().iter().copied(),
+ ),
+ CompositeType::Array(ArrayType(ty)) => {
+ TypeSection::encode_array(sink, &ty.element_type, ty.mutable)
+ }
+ CompositeType::Struct(ty) => {
+ TypeSection::encode_struct(sink, ty.fields.iter().cloned())
+ }
+ }
+ }
+}
+
+#[cfg(feature = "wasmparser")]
+impl TryFrom<wasmparser::CompositeType> for CompositeType {
+ type Error = ();
+ fn try_from(composite_ty: wasmparser::CompositeType) -> Result<Self, Self::Error> {
+ Ok(match composite_ty {
+ wasmparser::CompositeType::Func(f) => CompositeType::Func(f.try_into()?),
+ wasmparser::CompositeType::Array(a) => CompositeType::Array(a.try_into()?),
+ wasmparser::CompositeType::Struct(s) => CompositeType::Struct(s.try_into()?),
+ })
+ }
+}
+
+/// Represents a type of a function in a WebAssembly module.
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+pub struct FuncType {
+ /// The combined parameters and result types.
+ params_results: Box<[ValType]>,
+ /// The number of parameter types.
+ len_params: usize,
+}
+
+#[cfg(feature = "wasmparser")]
+impl TryFrom<wasmparser::FuncType> for FuncType {
+ type Error = ();
+ fn try_from(func_ty: wasmparser::FuncType) -> Result<Self, Self::Error> {
+ let mut buf = Vec::with_capacity(func_ty.params().len() + func_ty.results().len());
+ for ty in func_ty.params().iter().chain(func_ty.results()).copied() {
+ buf.push(ty.try_into()?);
+ }
+ Ok(FuncType::from_parts(buf.into(), func_ty.params().len()))
+ }
+}
+
+/// Represents a type of an array in a WebAssembly module.
+#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
+pub struct ArrayType(pub FieldType);
+
+#[cfg(feature = "wasmparser")]
+impl TryFrom<wasmparser::ArrayType> for ArrayType {
+ type Error = ();
+ fn try_from(array_ty: wasmparser::ArrayType) -> Result<Self, Self::Error> {
+ Ok(ArrayType(array_ty.0.try_into()?))
+ }
+}
+
+/// Represents a type of a struct in a WebAssembly module.
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+pub struct StructType {
+ /// Struct fields.
+ pub fields: Box<[FieldType]>,
+}
+
+#[cfg(feature = "wasmparser")]
+impl TryFrom<wasmparser::StructType> for StructType {
+ type Error = ();
+ fn try_from(struct_ty: wasmparser::StructType) -> Result<Self, Self::Error> {
+ Ok(StructType {
+ fields: struct_ty
+ .fields
+ .iter()
+ .cloned()
+ .map(TryInto::try_into)
+ .collect::<Result<_, _>>()?,
+ })
+ }
+}
+
+/// Field type in composite types (structs, arrays).
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
+pub struct FieldType {
+ /// Storage type of the field.
+ pub element_type: StorageType,
+ /// Is the field mutable.
+ pub mutable: bool,
+}
+
+#[cfg(feature = "wasmparser")]
+impl TryFrom<wasmparser::FieldType> for FieldType {
+ type Error = ();
+ fn try_from(field_ty: wasmparser::FieldType) -> Result<Self, Self::Error> {
+ Ok(FieldType {
+ element_type: field_ty.element_type.try_into()?,
+ mutable: field_ty.mutable,
+ })
+ }
+}
+
+/// Storage type for composite type fields.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
+pub enum StorageType {
+ /// The `i8` type.
+ I8,
+ /// The `i16` type.
+ I16,
+ /// A value type.
+ Val(ValType),
+}
+
+#[cfg(feature = "wasmparser")]
+impl TryFrom<wasmparser::StorageType> for StorageType {
+ type Error = ();
+ fn try_from(storage_ty: wasmparser::StorageType) -> Result<Self, Self::Error> {
+ Ok(match storage_ty {
+ wasmparser::StorageType::I8 => StorageType::I8,
+ wasmparser::StorageType::I16 => StorageType::I16,
+ wasmparser::StorageType::Val(v) => StorageType::Val(v.try_into()?),
+ })
+ }
+}
+
+impl StorageType {
+ /// Is this storage type defaultable?
+ pub fn is_defaultable(&self) -> bool {
+ self.unpack().is_defaultable()
+ }
+
+ /// Unpack this storage type into a value type.
+ pub fn unpack(&self) -> ValType {
+ match self {
+ StorageType::I8 | StorageType::I16 => ValType::I32,
+ StorageType::Val(v) => *v,
+ }
+ }
+}
+
+/// The type of a core WebAssembly value.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
+pub enum ValType {
+ /// The `i32` type.
+ I32,
+ /// The `i64` type.
+ I64,
+ /// The `f32` type.
+ F32,
+ /// The `f64` type.
+ F64,
+ /// The `v128` type.
+ ///
+ /// Part of the SIMD proposal.
+ V128,
+ /// A reference type.
+ ///
+ /// The `funcref` and `externref` type fall into this category and the full
+ /// generalization here is due to the implementation of the
+ /// function-references proposal.
+ Ref(RefType),
+}
+
+#[cfg(feature = "wasmparser")]
+impl TryFrom<wasmparser::ValType> for ValType {
+ type Error = ();
+ fn try_from(val_ty: wasmparser::ValType) -> Result<Self, Self::Error> {
+ Ok(match val_ty {
+ wasmparser::ValType::I32 => ValType::I32,
+ wasmparser::ValType::I64 => ValType::I64,
+ wasmparser::ValType::F32 => ValType::F32,
+ wasmparser::ValType::F64 => ValType::F64,
+ wasmparser::ValType::V128 => ValType::V128,
+ wasmparser::ValType::Ref(r) => ValType::Ref(r.try_into()?),
+ })
+ }
+}
+
+impl ValType {
+ /// Is this a numeric value type?
+ pub fn is_numeric(&self) -> bool {
+ match self {
+ ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => true,
+ ValType::V128 | ValType::Ref(_) => false,
+ }
+ }
+
+ /// Is this a vector type?
+ pub fn is_vector(&self) -> bool {
+ match self {
+ ValType::V128 => true,
+ ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::Ref(_) => false,
+ }
+ }
+
+ /// Is this a reference type?
+ pub fn is_reference(&self) -> bool {
+ match self {
+ ValType::Ref(_) => true,
+ ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => false,
+ }
+ }
+}
+
+impl FuncType {
+ /// Creates a new [`FuncType`] from the given `params` and `results`.
+ pub fn new<P, R>(params: P, results: R) -> Self
+ where
+ P: IntoIterator<Item = ValType>,
+ R: IntoIterator<Item = ValType>,
+ {
+ let mut buffer = params.into_iter().collect::<Vec<_>>();
+ let len_params = buffer.len();
+ buffer.extend(results);
+ Self::from_parts(buffer.into(), len_params)
+ }
+
+ #[inline]
+ pub(crate) fn from_parts(params_results: Box<[ValType]>, len_params: usize) -> Self {
+ Self {
+ params_results,
+ len_params,
+ }
+ }
+
+ /// Returns a shared slice to the parameter types of the [`FuncType`].
+ #[inline]
+ pub fn params(&self) -> &[ValType] {
+ &self.params_results[..self.len_params]
+ }
+
+ /// Returns a shared slice to the result types of the [`FuncType`].
+ #[inline]
+ pub fn results(&self) -> &[ValType] {
+ &self.params_results[self.len_params..]
+ }
+}
+
+impl ValType {
+ /// Alias for the `funcref` type in WebAssembly
+ pub const FUNCREF: ValType = ValType::Ref(RefType::FUNCREF);
+ /// Alias for the `externref` type in WebAssembly
+ pub const EXTERNREF: ValType = ValType::Ref(RefType::EXTERNREF);
+ /// Alias for the `exnref` type in WebAssembly
+ pub const EXNREF: ValType = ValType::Ref(RefType::EXNREF);
+
+ /// Is this value defaultable?
+ pub fn is_defaultable(&self) -> bool {
+ match self {
+ ValType::Ref(r) => r.nullable,
+ ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => true,
+ }
+ }
+}
+
+impl Encode for StorageType {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ match self {
+ StorageType::I8 => sink.push(0x78),
+ StorageType::I16 => sink.push(0x77),
+ StorageType::Val(vt) => vt.encode(sink),
+ }
+ }
+}
+
+impl Encode for ValType {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ match self {
+ ValType::I32 => sink.push(0x7F),
+ ValType::I64 => sink.push(0x7E),
+ ValType::F32 => sink.push(0x7D),
+ ValType::F64 => sink.push(0x7C),
+ ValType::V128 => sink.push(0x7B),
+ ValType::Ref(rt) => rt.encode(sink),
+ }
+ }
+}
+
+/// A reference type.
+///
+/// This is largely part of the function references proposal for WebAssembly but
+/// additionally is used by the `funcref` and `externref` types. The full
+/// generality of this type is only exercised with function-references.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
+#[allow(missing_docs)]
+pub struct RefType {
+ pub nullable: bool,
+ pub heap_type: HeapType,
+}
+
+impl RefType {
+ /// Alias for the `funcref` type in WebAssembly
+ pub const FUNCREF: RefType = RefType {
+ nullable: true,
+ heap_type: HeapType::Func,
+ };
+
+ /// Alias for the `externref` type in WebAssembly
+ pub const EXTERNREF: RefType = RefType {
+ nullable: true,
+ heap_type: HeapType::Extern,
+ };
+
+ /// Alias for the `exnref` type in WebAssembly
+ pub const EXNREF: RefType = RefType {
+ nullable: true,
+ heap_type: HeapType::Exn,
+ };
+}
+
+impl Encode for RefType {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ if self.nullable {
+ // Favor the original encodings of `funcref` and `externref` where
+ // possible
+ match self.heap_type {
+ HeapType::Func => return sink.push(0x70),
+ HeapType::Extern => return sink.push(0x6f),
+ _ => {}
+ }
+ }
+
+ if self.nullable {
+ sink.push(0x63);
+ } else {
+ sink.push(0x64);
+ }
+ self.heap_type.encode(sink);
+ }
+}
+
+#[cfg(feature = "wasmparser")]
+impl TryFrom<wasmparser::RefType> for RefType {
+ type Error = ();
+
+ fn try_from(ref_type: wasmparser::RefType) -> Result<Self, Self::Error> {
+ Ok(RefType {
+ nullable: ref_type.is_nullable(),
+ heap_type: ref_type.heap_type().try_into()?,
+ })
+ }
+}
+
+impl From<RefType> for ValType {
+ fn from(ty: RefType) -> ValType {
+ ValType::Ref(ty)
+ }
+}
+
+/// Part of the function references proposal.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
+pub enum HeapType {
+ /// Untyped (any) function.
+ Func,
+
+ /// The abstract external heap type.
+ Extern,
+
+ /// The abstract `any` heap type.
+ ///
+ /// The common supertype (a.k.a. top) of all internal types.
+ Any,
+
+ /// The abstract `none` heap type.
+ ///
+ /// The common subtype (a.k.a. bottom) of all internal types.
+ None,
+
+ /// The abstract `noextern` heap type.
+ ///
+ /// The common subtype (a.k.a. bottom) of all external types.
+ NoExtern,
+
+ /// The abstract `nofunc` heap type.
+ ///
+ /// The common subtype (a.k.a. bottom) of all function types.
+ NoFunc,
+
+ /// The abstract `eq` heap type.
+ ///
+ /// The common supertype of all referenceable types on which comparison
+ /// (ref.eq) is allowed.
+ Eq,
+
+ /// The abstract `struct` heap type.
+ ///
+ /// The common supertype of all struct types.
+ Struct,
+
+ /// The abstract `array` heap type.
+ ///
+ /// The common supertype of all array types.
+ Array,
+
+ /// The unboxed `i31` heap type.
+ I31,
+
+ /// The abstract` exception` heap type.
+ Exn,
+
+ /// A concrete Wasm-defined type at the given index.
+ Concrete(u32),
+}
+
+impl Encode for HeapType {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ match self {
+ HeapType::Func => sink.push(0x70),
+ HeapType::Extern => sink.push(0x6F),
+ HeapType::Any => sink.push(0x6E),
+ HeapType::None => sink.push(0x71),
+ HeapType::NoExtern => sink.push(0x72),
+ HeapType::NoFunc => sink.push(0x73),
+ HeapType::Eq => sink.push(0x6D),
+ HeapType::Struct => sink.push(0x6B),
+ HeapType::Array => sink.push(0x6A),
+ HeapType::I31 => sink.push(0x6C),
+ HeapType::Exn => sink.push(0x69),
+ // Note that this is encoded as a signed type rather than unsigned
+ // as it's decoded as an s33
+ HeapType::Concrete(i) => i64::from(*i).encode(sink),
+ }
+ }
+}
+
+#[cfg(feature = "wasmparser")]
+impl TryFrom<wasmparser::HeapType> for HeapType {
+ type Error = ();
+
+ fn try_from(heap_type: wasmparser::HeapType) -> Result<Self, Self::Error> {
+ Ok(match heap_type {
+ wasmparser::HeapType::Concrete(i) => HeapType::Concrete(i.as_module_index().ok_or(())?),
+ wasmparser::HeapType::Func => HeapType::Func,
+ wasmparser::HeapType::Extern => HeapType::Extern,
+ wasmparser::HeapType::Any => HeapType::Any,
+ wasmparser::HeapType::None => HeapType::None,
+ wasmparser::HeapType::NoExtern => HeapType::NoExtern,
+ wasmparser::HeapType::NoFunc => HeapType::NoFunc,
+ wasmparser::HeapType::Eq => HeapType::Eq,
+ wasmparser::HeapType::Struct => HeapType::Struct,
+ wasmparser::HeapType::Array => HeapType::Array,
+ wasmparser::HeapType::I31 => HeapType::I31,
+ wasmparser::HeapType::Exn => HeapType::Exn,
+ })
+ }
+}
+
+/// An encoder for the type section of WebAssembly modules.
+///
+/// # Example
+///
+/// ```rust
+/// use wasm_encoder::{Module, TypeSection, ValType};
+///
+/// let mut types = TypeSection::new();
+///
+/// types.function([ValType::I32, ValType::I32], [ValType::I64]);
+///
+/// let mut module = Module::new();
+/// module.section(&types);
+///
+/// let bytes = module.finish();
+/// ```
+#[derive(Clone, Debug, Default)]
+pub struct TypeSection {
+ bytes: Vec<u8>,
+ num_added: u32,
+}
+
+impl TypeSection {
+ /// Create a new module type section encoder.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// The number of types in the section.
+ pub fn len(&self) -> u32 {
+ self.num_added
+ }
+
+ /// Determines if the section is empty.
+ pub fn is_empty(&self) -> bool {
+ self.num_added == 0
+ }
+
+ /// Define a function type in this type section.
+ pub fn function<P, R>(&mut self, params: P, results: R) -> &mut Self
+ where
+ P: IntoIterator<Item = ValType>,
+ P::IntoIter: ExactSizeIterator,
+ R: IntoIterator<Item = ValType>,
+ R::IntoIter: ExactSizeIterator,
+ {
+ Self::encode_function(&mut self.bytes, params, results);
+ self.num_added += 1;
+ self
+ }
+
+ fn encode_function<P, R>(sink: &mut Vec<u8>, params: P, results: R)
+ where
+ P: IntoIterator<Item = ValType>,
+ P::IntoIter: ExactSizeIterator,
+ R: IntoIterator<Item = ValType>,
+ R::IntoIter: ExactSizeIterator,
+ {
+ let params = params.into_iter();
+ let results = results.into_iter();
+
+ sink.push(0x60);
+ params.len().encode(sink);
+ params.for_each(|p| p.encode(sink));
+ results.len().encode(sink);
+ results.for_each(|p| p.encode(sink));
+ }
+
+ /// Define an array type in this type section.
+ pub fn array(&mut self, ty: &StorageType, mutable: bool) -> &mut Self {
+ Self::encode_array(&mut self.bytes, ty, mutable);
+ self.num_added += 1;
+ self
+ }
+
+ fn encode_array(sink: &mut Vec<u8>, ty: &StorageType, mutable: bool) {
+ sink.push(0x5e);
+ Self::encode_field(sink, ty, mutable);
+ }
+
+ fn encode_field(sink: &mut Vec<u8>, ty: &StorageType, mutable: bool) {
+ ty.encode(sink);
+ sink.push(mutable as u8);
+ }
+
+ /// Define a struct type in this type section.
+ pub fn struct_<F>(&mut self, fields: F) -> &mut Self
+ where
+ F: IntoIterator<Item = FieldType>,
+ F::IntoIter: ExactSizeIterator,
+ {
+ Self::encode_struct(&mut self.bytes, fields);
+ self.num_added += 1;
+ self
+ }
+
+ fn encode_struct<F>(sink: &mut Vec<u8>, fields: F)
+ where
+ F: IntoIterator<Item = FieldType>,
+ F::IntoIter: ExactSizeIterator,
+ {
+ let fields = fields.into_iter();
+ sink.push(0x5f);
+ fields.len().encode(sink);
+ for f in fields {
+ Self::encode_field(sink, &f.element_type, f.mutable);
+ }
+ }
+
+ /// Define an explicit subtype in this type section.
+ pub fn subtype(&mut self, ty: &SubType) -> &mut Self {
+ ty.encode(&mut self.bytes);
+ self.num_added += 1;
+ self
+ }
+
+ /// Define an explicit recursion group in this type section.
+ pub fn rec<T>(&mut self, types: T) -> &mut Self
+ where
+ T: IntoIterator<Item = SubType>,
+ T::IntoIter: ExactSizeIterator,
+ {
+ let types = types.into_iter();
+ self.bytes.push(0x4e);
+ types.len().encode(&mut self.bytes);
+ types.for_each(|t| t.encode(&mut self.bytes));
+ self.num_added += 1;
+ self
+ }
+}
+
+impl Encode for TypeSection {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ encode_section(sink, self.num_added, &self.bytes);
+ }
+}
+
+impl Section for TypeSection {
+ fn id(&self) -> u8 {
+ SectionId::Type.into()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::Module;
+
+ #[test]
+ fn func_types_dont_require_wasm_gc() {
+ let mut types = TypeSection::new();
+ types.subtype(&SubType {
+ is_final: true,
+ supertype_idx: None,
+ composite_type: CompositeType::Func(FuncType::new([], [])),
+ });
+
+ let mut module = Module::new();
+ module.section(&types);
+ let wasm_bytes = module.finish();
+
+ let mut validator = wasmparser::Validator::new_with_features(wasmparser::WasmFeatures {
+ gc: false,
+ ..Default::default()
+ });
+
+ validator.validate_all(&wasm_bytes).expect(
+ "Encoding pre Wasm GC type should not accidentally use Wasm GC specific encoding",
+ );
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/lib.rs b/third_party/rust/wasm-encoder/src/lib.rs
new file mode 100644
index 0000000000..930c63ec9d
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/lib.rs
@@ -0,0 +1,215 @@
+//! A WebAssembly encoder.
+//!
+//! The main builder is the [`Module`]. You can build a section with a
+//! section-specific builder, like [`TypeSection`] or [`ImportSection`], and
+//! then add it to the module with [`Module::section`]. When you are finished
+//! building the module, call either [`Module::as_slice`] or [`Module::finish`]
+//! to get the encoded bytes. The former gives a shared reference to the
+//! underlying bytes as a slice, while the latter gives you ownership of them as
+//! a vector.
+//!
+//! # Example
+//!
+//! If we wanted to build this module:
+//!
+//! ```wasm
+//! (module
+//! (type (func (param i32 i32) (result i32)))
+//! (func (type 0)
+//! local.get 0
+//! local.get 1
+//! i32.add)
+//! (export "f" (func 0)))
+//! ```
+//!
+//! then we would do this:
+//!
+//! ```
+//! use wasm_encoder::{
+//! CodeSection, ExportKind, ExportSection, Function, FunctionSection, Instruction,
+//! Module, TypeSection, ValType,
+//! };
+//!
+//! let mut module = Module::new();
+//!
+//! // Encode the type section.
+//! let mut types = TypeSection::new();
+//! let params = vec![ValType::I32, ValType::I32];
+//! let results = vec![ValType::I32];
+//! types.function(params, results);
+//! module.section(&types);
+//!
+//! // Encode the function section.
+//! let mut functions = FunctionSection::new();
+//! let type_index = 0;
+//! functions.function(type_index);
+//! module.section(&functions);
+//!
+//! // Encode the export section.
+//! let mut exports = ExportSection::new();
+//! exports.export("f", ExportKind::Func, 0);
+//! module.section(&exports);
+//!
+//! // Encode the code section.
+//! let mut codes = CodeSection::new();
+//! let locals = vec![];
+//! let mut f = Function::new(locals);
+//! f.instruction(&Instruction::LocalGet(0));
+//! f.instruction(&Instruction::LocalGet(1));
+//! f.instruction(&Instruction::I32Add);
+//! f.instruction(&Instruction::End);
+//! codes.function(&f);
+//! module.section(&codes);
+//!
+//! // Extract the encoded Wasm bytes for this module.
+//! let wasm_bytes = module.finish();
+//!
+//! // We generated a valid Wasm module!
+//! assert!(wasmparser::validate(&wasm_bytes).is_ok());
+//! ```
+
+#![deny(missing_docs, missing_debug_implementations)]
+
+mod component;
+mod core;
+mod raw;
+
+pub use self::component::*;
+pub use self::core::*;
+pub use self::raw::*;
+
+/// Implemented by types that can be encoded into a byte sink.
+pub trait Encode {
+ /// Encode the type into the given byte sink.
+ fn encode(&self, sink: &mut Vec<u8>);
+}
+
+impl<T: Encode + ?Sized> Encode for &'_ T {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ T::encode(self, sink)
+ }
+}
+
+impl<T: Encode> Encode for [T] {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ self.len().encode(sink);
+ for item in self {
+ item.encode(sink);
+ }
+ }
+}
+
+impl Encode for [u8] {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ self.len().encode(sink);
+ sink.extend(self);
+ }
+}
+
+impl Encode for str {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ self.len().encode(sink);
+ sink.extend_from_slice(self.as_bytes());
+ }
+}
+
+impl Encode for usize {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ assert!(*self <= u32::max_value() as usize);
+ (*self as u32).encode(sink)
+ }
+}
+
+impl Encode for u32 {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ leb128::write::unsigned(sink, (*self).into()).unwrap();
+ }
+}
+
+impl Encode for i32 {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ leb128::write::signed(sink, (*self).into()).unwrap();
+ }
+}
+
+impl Encode for u64 {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ leb128::write::unsigned(sink, *self).unwrap();
+ }
+}
+
+impl Encode for i64 {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ leb128::write::signed(sink, *self).unwrap();
+ }
+}
+
+impl Encode for f32 {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ let bits = self.to_bits();
+ sink.extend(bits.to_le_bytes())
+ }
+}
+
+impl Encode for f64 {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ let bits = self.to_bits();
+ sink.extend(bits.to_le_bytes())
+ }
+}
+
+fn encode_vec<T, V>(elements: V, sink: &mut Vec<u8>)
+where
+ T: Encode,
+ V: IntoIterator<Item = T>,
+ V::IntoIter: ExactSizeIterator,
+{
+ let elements = elements.into_iter();
+ u32::try_from(elements.len()).unwrap().encode(sink);
+ for x in elements {
+ x.encode(sink);
+ }
+}
+
+impl<T> Encode for Option<T>
+where
+ T: Encode,
+{
+ fn encode(&self, sink: &mut Vec<u8>) {
+ match self {
+ Some(v) => {
+ sink.push(0x01);
+ v.encode(sink);
+ }
+ None => sink.push(0x00),
+ }
+ }
+}
+
+fn encoding_size(n: u32) -> usize {
+ let mut buf = [0u8; 5];
+ leb128::write::unsigned(&mut &mut buf[..], n.into()).unwrap()
+}
+
+fn encode_section(sink: &mut Vec<u8>, count: u32, bytes: &[u8]) {
+ (encoding_size(count) + bytes.len()).encode(sink);
+ count.encode(sink);
+ sink.extend(bytes);
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn it_encodes_an_empty_module() {
+ let bytes = Module::new().finish();
+ assert_eq!(bytes, [0x00, b'a', b's', b'm', 0x01, 0x00, 0x00, 0x00]);
+ }
+
+ #[test]
+ fn it_encodes_an_empty_component() {
+ let bytes = Component::new().finish();
+ assert_eq!(bytes, [0x00, b'a', b's', b'm', 0x0d, 0x00, 0x01, 0x00]);
+ }
+}
diff --git a/third_party/rust/wasm-encoder/src/raw.rs b/third_party/rust/wasm-encoder/src/raw.rs
new file mode 100644
index 0000000000..a1323ca88e
--- /dev/null
+++ b/third_party/rust/wasm-encoder/src/raw.rs
@@ -0,0 +1,30 @@
+use crate::{ComponentSection, Encode, Section};
+
+/// A section made up of uninterpreted, raw bytes.
+///
+/// Allows you to splat any data into a module or component.
+#[derive(Clone, Copy, Debug)]
+pub struct RawSection<'a> {
+ /// The id for this section.
+ pub id: u8,
+ /// The raw data for this section.
+ pub data: &'a [u8],
+}
+
+impl Encode for RawSection<'_> {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ self.data.encode(sink);
+ }
+}
+
+impl Section for RawSection<'_> {
+ fn id(&self) -> u8 {
+ self.id
+ }
+}
+
+impl ComponentSection for RawSection<'_> {
+ fn id(&self) -> u8 {
+ self.id
+ }
+}