diff options
Diffstat (limited to 'third_party/rust/wasm-encoder')
32 files changed, 7075 insertions, 0 deletions
diff --git a/third_party/rust/wasm-encoder/.cargo-checksum.json b/third_party/rust/wasm-encoder/.cargo-checksum.json new file mode 100644 index 0000000000..2a13ada3be --- /dev/null +++ b/third_party/rust/wasm-encoder/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"9d800ed141917d12a9b0e13a292b6e9b45c74ad4afbc03876f5f43a838d85f9a","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"ac016c4843a7e1a5737255b39418732783592222dc518020730edf9dd46a1c13","src/component.rs":"8725965b2116922acaa9604f08ef5f89e1704d3fac03c2eefc6d453ca35db647","src/component/aliases.rs":"c5958acaedb9a6bcd2756f58c92f300a2acc5bf8be39b1a5265f307fb415b59b","src/component/canonicals.rs":"8b270caef4e0f1e2b62af5b27560ac370399d11ce411aae6b811dddeaedb7750","src/component/components.rs":"07b8cae3a400e1955cc39d142569910b4fef2136021053d0ddbd6404d810aa52","src/component/exports.rs":"3f297f57a1278940c06219581f2129b7608f965371101af3d6c5e1aaa1c22b4f","src/component/imports.rs":"a2d6ea0411537c76e617a5a22fb435ffebea962fb16bdda35a231f254b8c55ae","src/component/instances.rs":"c86f24e466aeb6889413f32d95e039a90a1e20d2e5a0505339aa81fc086a8c24","src/component/modules.rs":"9e80907e72360fae4d8057b6b0e7a6b58edd7ba6aba6e63ba17346518e169617","src/component/start.rs":"4055553d5c99c99abbc01bb8abb928ecb8b909d148b647a9977fbd444bb464a3","src/component/types.rs":"cb5b759ca2f9a001eef50f82306cf716105a441b1a3c78d4c0996c98c8f849ed","src/core.rs":"d52f366d84a931a1b994c1cf32da860ad0d7a456f82dfcdef32c6260fdc6999c","src/core/code.rs":"52a796b64175e4a6233e1be152043b5e3d5ae3fe731a2957d075f406a8185063","src/core/custom.rs":"df2d6a8c5a64603822301522e9df4344022226301df846941d95930f1f4d99c4","src/core/data.rs":"c9d59eab2ab811bd950da52e6766c7df2367986c7a3a0d94d7aeb47d86f203ac","src/core/elements.rs":"361eba770b0bd6129e5b96f3081b022c5fa74640730d1d0501a33d93fea7d707","src/core/exports.rs":"81a40d30b1ae6d8ae32a2ae20e398ccab9cf6b8ae66c985e6ab7f46e06bf2ed4","src/core/functions.rs":"c18b9872ac0c21048a3ce32e5e44e8e702f97a57fa1b3a07bdd98c7f6c820f09","src/core/globals.rs":"560d8e8c818d968cd8a101ab3c639f723b1c754716aa1178d1c4570efd84d010","src/core/imports.rs":"782bbc2e70b379831f85716c0f50c0221d1487c8cba26e8845028b2ae1962c0c","src/core/linking.rs":"5c7d5bce822fad92dc096ceafde878c6d25869004ca26dde1378e78ae37071c9","src/core/memories.rs":"840d15fcd9bd4a668298491c6a91455b145c5c7ff1adf8c769aaf49d6c664d3a","src/core/names.rs":"b12bcb3e0462d52849057467f6b80565cda6021f09c3c0f52c1f83341a5f482d","src/core/start.rs":"a01d4a91bcd93048977ccafc6af160357297450395bf598351f5a3e6d322e0de","src/core/tables.rs":"f87a9761002e93c8e04e646cdf19fb5d012b190a4dbba542e8bfe1cfc606b545","src/core/tags.rs":"26d58904871d92f395eed67d4c25f0914b337d213bab2288011abe3ad31fa12b","src/core/types.rs":"42125c08577c418237982980fd13eb9a21e63b52674c0820c2df2e61b5f454fc","src/lib.rs":"bbe5b54b0614128c94aa3adbc96420d813195949aaa5e9258d9ea1b55894f6fd","src/raw.rs":"a6a72cfe8f88ea6476eccee4acf362030ba2d2e5710215bc4f13cde7de6d71ae"},"package":"9424cdab516a16d4ea03c8f4a01b14e7b2d04a129dcc2bcdde5bcc5f68f06c41"}
\ No newline at end of file diff --git a/third_party/rust/wasm-encoder/Cargo.toml b/third_party/rust/wasm-encoder/Cargo.toml new file mode 100644 index 0000000000..dc890d74fa --- /dev/null +++ b/third_party/rust/wasm-encoder/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "wasm-encoder" +version = "0.19.1" +authors = ["Nick Fitzgerald <fitzgen@gmail.com>"] +description = """ +A low-level WebAssembly encoder. +""" +homepage = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder" +documentation = "https://docs.rs/wasm-encoder" +readme = "README.md" +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder" + +[dependencies.leb128] +version = "0.2.4" + +[dev-dependencies.anyhow] +version = "1.0.58" + +[dev-dependencies.tempfile] +version = "3.2.0" diff --git a/third_party/rust/wasm-encoder/LICENSE b/third_party/rust/wasm-encoder/LICENSE new file mode 100644 index 0000000000..f9d81955f4 --- /dev/null +++ b/third_party/rust/wasm-encoder/LICENSE @@ -0,0 +1,220 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/third_party/rust/wasm-encoder/README.md b/third_party/rust/wasm-encoder/README.md new file mode 100644 index 0000000000..5f2efbe210 --- /dev/null +++ b/third_party/rust/wasm-encoder/README.md @@ -0,0 +1,80 @@ +<div align="center"> + <h1><code>wasm-encoder</code></h1> + +<strong>A <a href="https://bytecodealliance.org/">Bytecode Alliance</a> project</strong> + + <p> + <strong>A WebAssembly encoder for Rust.</strong> + </p> + + <p> + <a href="https://crates.io/crates/wasm-encoder"><img src="https://img.shields.io/crates/v/wasm-encoder.svg?style=flat-square" alt="Crates.io version" /></a> + <a href="https://crates.io/crates/wasm-encoder"><img src="https://img.shields.io/crates/d/wasm-encoder.svg?style=flat-square" alt="Download" /></a> + <a href="https://docs.rs/wasm-encoder/"><img src="https://img.shields.io/static/v1?label=docs&message=wasm-encoder&color=blue&style=flat-square" alt="docs.rs docs" /></a> + </p> +</div> + +## Usage + +Add `wasm-encoder` to your `Cargo.toml` + +```sh +$ cargo add wasm-encoder +``` + +And then you can encode WebAssembly binaries via: + +```rust +use wasm_encoder::{ + CodeSection, ExportKind, ExportSection, Function, FunctionSection, Instruction, + Module, TypeSection, ValType, +}; + +let mut module = Module::new(); + +// Encode the type section. +let mut types = TypeSection::new(); +let params = vec![ValType::I32, ValType::I32]; +let results = vec![ValType::I32]; +types.function(params, results); +module.section(&types); + +// Encode the function section. +let mut functions = FunctionSection::new(); +let type_index = 0; +functions.function(type_index); +module.section(&functions); + +// Encode the export section. +let mut exports = ExportSection::new(); +exports.export("f", ExportKind::Func, 0); +module.section(&exports); + +// Encode the code section. +let mut codes = CodeSection::new(); +let locals = vec![]; +let mut f = Function::new(locals); +f.instruction(&Instruction::LocalGet(0)); +f.instruction(&Instruction::LocalGet(1)); +f.instruction(&Instruction::I32Add); +f.instruction(&Instruction::End); +codes.function(&f); +module.section(&codes); + +// Extract the encoded Wasm bytes for this module. +let wasm_bytes = module.finish(); + +// We generated a valid Wasm module! +assert!(wasmparser::validate(&wasm_bytes).is_ok()); +``` + +# License + +This project is licensed under the Apache 2.0 license with the LLVM exception. +See [LICENSE](LICENSE) for more details. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this project by you, as defined in the Apache-2.0 license, +shall be licensed as above, without any additional terms or conditions. 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..f3d53003ee --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component.rs @@ -0,0 +1,135 @@ +mod aliases; +mod canonicals; +mod components; +mod exports; +mod imports; +mod instances; +mod modules; +mod start; +mod types; + +pub use self::aliases::*; +pub use self::canonicals::*; +pub use self::components::*; +pub use self::exports::*; +pub use self::imports::*; +pub use self::instances::*; +pub use self::modules::*; +pub use self::start::*; +pub use self::types::*; + +use crate::{CustomSection, Encode}; + +// 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; +} + +/// 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 { + /// Begin writing a new `Component`. + pub fn new() -> Self { + Self { + bytes: vec![ + 0x00, 0x61, 0x73, 0x6D, // magic (`\0asm`) + 0x0a, 0x00, 0x01, 0x00, // version + ], + } + } + + /// 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 + } +} + +impl Default for Component { + fn default() -> Self { + Self::new() + } +} + +impl ComponentSection for CustomSection<'_> { + 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..a78d52643a --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/aliases.rs @@ -0,0 +1,129 @@ +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, ComponentAliasSection, ComponentExportKind, ComponentOuterAliasKind}; +/// +/// let mut aliases = ComponentAliasSection::new(); +/// aliases.instance_export(0, ComponentExportKind::Func, "f"); +/// aliases.outer(0, ComponentOuterAliasKind::Type, 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, +} + +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 instance_export( + &mut self, + instance_index: u32, + kind: ComponentExportKind, + name: &str, + ) -> &mut Self { + kind.encode(&mut self.bytes); + self.bytes.push(0x00); + instance_index.encode(&mut self.bytes); + name.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Define an alias to a core instance's export. + pub fn core_instance_export( + &mut self, + instance_index: u32, + kind: ExportKind, + name: &str, + ) -> &mut Self { + self.bytes.push(CORE_SORT); + kind.encode(&mut self.bytes); + self.bytes.push(0x01); + instance_index.encode(&mut self.bytes); + name.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Define an alias to an outer component item. + /// + /// The count starts at 0 to indicate the current component, 1 indicates the direct + /// parent, 2 the grandparent, etc. + pub fn outer(&mut self, count: u32, kind: ComponentOuterAliasKind, index: u32) -> &mut Self { + kind.encode(&mut self.bytes); + self.bytes.push(0x02); + count.encode(&mut self.bytes); + index.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() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/canonicals.rs b/third_party/rust/wasm-encoder/src/component/canonicals.rs new file mode 100644 index 0000000000..e81819c44e --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/canonicals.rs @@ -0,0 +1,133 @@ +use crate::{encode_section, ComponentSection, ComponentSectionId, Encode}; + +/// Represents options for canonical function definitions. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CanonicalOption { + /// The string types in the function signature are UTF-8 encoded. + UTF8, + /// The string types in the function signature are UTF-16 encoded. + UTF16, + /// The string types in the function signature are compact UTF-16 encoded. + CompactUTF16, + /// The memory to use if the lifting or lowering of a function requires memory access. + /// + /// The value is an index to a core memory. + Memory(u32), + /// The realloc function to use if the lifting or lowering of a function requires memory + /// allocation. + /// + /// The value is an index to a core function of type `(func (param i32 i32 i32 i32) (result i32))`. + Realloc(u32), + /// The post-return function to use if the lifting of a function requires + /// cleanup after the function returns. + PostReturn(u32), +} + +impl Encode for CanonicalOption { + fn encode(&self, sink: &mut Vec<u8>) { + match self { + Self::UTF8 => sink.push(0x00), + Self::UTF16 => sink.push(0x01), + Self::CompactUTF16 => sink.push(0x02), + Self::Memory(idx) => { + sink.push(0x03); + idx.encode(sink); + } + Self::Realloc(idx) => { + sink.push(0x04); + idx.encode(sink); + } + Self::PostReturn(idx) => { + sink.push(0x05); + idx.encode(sink); + } + } + } +} + +/// An encoder for the canonical function section of WebAssembly components. +/// +/// # Example +/// +/// ``` +/// use wasm_encoder::{Component, CanonicalFunctionSection, CanonicalOption}; +/// +/// let mut functions = CanonicalFunctionSection::new(); +/// functions.lift(0, 0, [CanonicalOption::UTF8]); +/// +/// let mut component = Component::new(); +/// component.section(&functions); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct CanonicalFunctionSection { + bytes: Vec<u8>, + num_added: u32, +} + +impl CanonicalFunctionSection { + /// Construct a new component function section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of functions in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Define a function that will lift a core WebAssembly function to the canonical ABI. + pub fn lift<O>(&mut self, core_func_index: u32, type_index: u32, options: O) -> &mut Self + where + O: IntoIterator<Item = CanonicalOption>, + O::IntoIter: ExactSizeIterator, + { + let options = options.into_iter(); + self.bytes.push(0x00); + self.bytes.push(0x00); + core_func_index.encode(&mut self.bytes); + options.len().encode(&mut self.bytes); + for option in options { + option.encode(&mut self.bytes); + } + type_index.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Define a function that will lower a canonical ABI function to a core WebAssembly function. + pub fn lower<O>(&mut self, func_index: u32, options: O) -> &mut Self + where + O: IntoIterator<Item = CanonicalOption>, + O::IntoIter: ExactSizeIterator, + { + let options = options.into_iter(); + self.bytes.push(0x01); + self.bytes.push(0x00); + func_index.encode(&mut self.bytes); + options.len().encode(&mut self.bytes); + for option in options { + option.encode(&mut self.bytes); + } + self.num_added += 1; + self + } +} + +impl Encode for CanonicalFunctionSection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl ComponentSection for CanonicalFunctionSection { + fn id(&self) -> u8 { + ComponentSectionId::CanonicalFunction.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/components.rs b/third_party/rust/wasm-encoder/src/component/components.rs new file mode 100644 index 0000000000..c08645e3b9 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/components.rs @@ -0,0 +1,29 @@ +use crate::{Component, ComponentSection, ComponentSectionId, Encode}; + +/// An encoder for the component section of WebAssembly components. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Component, NestedComponentSection}; +/// +/// let mut nested = Component::new(); +/// let mut component = Component::new(); +/// component.section(&NestedComponentSection(&nested)); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug)] +pub struct NestedComponentSection<'a>(pub &'a Component); + +impl Encode for NestedComponentSection<'_> { + fn encode(&self, sink: &mut Vec<u8>) { + self.0.bytes.encode(sink); + } +} + +impl ComponentSection for NestedComponentSection<'_> { + fn id(&self) -> u8 { + ComponentSectionId::Component.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/exports.rs b/third_party/rust/wasm-encoder/src/component/exports.rs new file mode 100644 index 0000000000..eefd3ca0ec --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/exports.rs @@ -0,0 +1,108 @@ +use super::{ + COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, FUNCTION_SORT, INSTANCE_SORT, TYPE_SORT, + VALUE_SORT, +}; +use crate::{encode_section, ComponentSection, ComponentSectionId, 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); +/// +/// 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) -> &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 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..641163f3f5 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/imports.rs @@ -0,0 +1,150 @@ +use crate::{ + encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, ComponentValType, + Encode, +}; + +/// Represents the possible type bounds for type references. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum TypeBounds { + /// The type is bounded by equality. + Eq, +} + +impl Encode for TypeBounds { + fn encode(&self, sink: &mut Vec<u8>) { + match self { + Self::Eq => sink.push(0x00), + } + } +} + +/// Represents a reference to a type. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum ComponentTypeRef { + /// The reference is to a core module type. + /// + /// The index is expected to be core type index to a core module type. + Module(u32), + /// The reference is to a function type. + /// + /// The index is expected to be a type index to a function type. + Func(u32), + /// The reference is to a value type. + Value(ComponentValType), + /// The reference is to a bounded type. + /// + /// The index is expected to be a type index. + Type(TypeBounds, u32), + /// The reference is to an instance type. + /// + /// The index is expected to be a type index to an instance type. + Instance(u32), + /// The reference is to a component type. + /// + /// The index is expected to be a type index to a component type. + Component(u32), +} + +impl ComponentTypeRef { + /// Gets the export kind of the reference. + pub fn kind(&self) -> ComponentExportKind { + match self { + Self::Module(_) => ComponentExportKind::Module, + Self::Func(_) => ComponentExportKind::Func, + Self::Value(_) => ComponentExportKind::Value, + Self::Type(..) => ComponentExportKind::Type, + Self::Instance(_) => ComponentExportKind::Instance, + Self::Component(_) => ComponentExportKind::Component, + } + } +} + +impl Encode for ComponentTypeRef { + fn encode(&self, sink: &mut Vec<u8>) { + self.kind().encode(sink); + + match self { + Self::Module(idx) | Self::Func(idx) | Self::Instance(idx) | Self::Component(idx) => { + idx.encode(sink); + } + Self::Value(ty) => ty.encode(sink), + Self::Type(bounds, idx) => { + bounds.encode(sink); + idx.encode(sink); + } + } + } +} + +/// An encoder for the import section of WebAssembly components. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Component, ComponentTypeSection, PrimitiveValType, ComponentImportSection, ComponentTypeRef}; +/// +/// let mut types = ComponentTypeSection::new(); +/// +/// // Define a function type of `[string, string] -> string`. +/// types +/// .function() +/// .params( +/// [ +/// ("a", PrimitiveValType::String), +/// ("b", PrimitiveValType::String) +/// ] +/// ) +/// .result(PrimitiveValType::String); +/// +/// // This imports a function named `f` with the type defined above +/// let mut imports = ComponentImportSection::new(); +/// imports.import("f", ComponentTypeRef::Func(0)); +/// +/// let mut component = Component::new(); +/// component.section(&types); +/// component.section(&imports); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct ComponentImportSection { + bytes: Vec<u8>, + num_added: u32, +} + +impl ComponentImportSection { + /// Create a new component import section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of imports in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Define an import in the component import section. + pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { + 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() + } +} 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..000a872d6b --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/instances.rs @@ -0,0 +1,196 @@ +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, A>(&mut self, module_index: u32, args: A) -> &mut Self + where + A: IntoIterator<Item = (&'a str, ModuleArg)>, + A::IntoIter: ExactSizeIterator, + { + 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.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<'a, E>(&mut self, exports: E) -> &mut Self + where + E: IntoIterator<Item = (&'a str, ExportKind, u32)>, + E::IntoIter: ExactSizeIterator, + { + let exports = exports.into_iter(); + self.bytes.push(0x01); + exports.len().encode(&mut self.bytes); + for (name, kind, index) in exports { + name.encode(&mut self.bytes); + kind.encode(&mut self.bytes); + index.encode(&mut self.bytes); + } + self.num_added += 1; + self + } +} + +impl Encode for 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, A>(&mut self, component_index: u32, args: A) -> &mut Self + where + A: IntoIterator<Item = (&'a str, ComponentExportKind, u32)>, + A::IntoIter: ExactSizeIterator, + { + 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.encode(&mut self.bytes); + kind.encode(&mut self.bytes); + index.encode(&mut self.bytes); + } + self.num_added += 1; + self + } + + /// Define an instance by exporting items. + pub fn export_items<'a, E>(&mut self, exports: E) -> &mut Self + where + E: IntoIterator<Item = (&'a str, ComponentExportKind, u32)>, + E::IntoIter: ExactSizeIterator, + { + let exports = exports.into_iter(); + self.bytes.push(0x01); + exports.len().encode(&mut self.bytes); + for (name, kind, index) in exports { + name.encode(&mut self.bytes); + kind.encode(&mut self.bytes); + index.encode(&mut self.bytes); + } + self.num_added += 1; + self + } +} + +impl Encode for ComponentInstanceSection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl ComponentSection for ComponentInstanceSection { + fn id(&self) -> u8 { + ComponentSectionId::Instance.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/modules.rs b/third_party/rust/wasm-encoder/src/component/modules.rs new file mode 100644 index 0000000000..437cd353af --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/modules.rs @@ -0,0 +1,29 @@ +use crate::{ComponentSection, ComponentSectionId, Encode, Module}; + +/// An encoder for the module section of WebAssembly components. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Module, Component, ModuleSection}; +/// +/// let mut module = Module::new(); +/// let mut component = Component::new(); +/// component.section(&ModuleSection(&module)); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug)] +pub struct ModuleSection<'a>(pub &'a Module); + +impl Encode for ModuleSection<'_> { + fn encode(&self, sink: &mut Vec<u8>) { + self.0.bytes.encode(sink); + } +} + +impl ComponentSection for ModuleSection<'_> { + fn id(&self) -> u8 { + ComponentSectionId::CoreModule.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/component/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..8b097c9834 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/component/types.rs @@ -0,0 +1,748 @@ +use super::CORE_TYPE_SORT; +use crate::{ + encode_section, ComponentOuterAliasKind, ComponentSection, ComponentSectionId, + ComponentTypeRef, Encode, EntityType, ValType, +}; + +/// Represents the type of a core module. +#[derive(Debug, Clone, Default)] +pub struct ModuleType { + bytes: Vec<u8>, + num_added: u32, + types_added: u32, +} + +impl ModuleType { + /// Creates a new core module type. + pub fn new() -> Self { + Self::default() + } + + /// Defines an import in this module type. + pub fn import(&mut self, module: &str, name: &str, ty: EntityType) -> &mut Self { + self.bytes.push(0x00); + module.encode(&mut self.bytes); + name.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Define a type in this module type. + /// + /// The returned encoder must be used before adding another definition. + #[must_use = "the encoder must be used to encode the type"] + pub fn ty(&mut self) -> CoreTypeEncoder { + self.bytes.push(0x01); + self.num_added += 1; + self.types_added += 1; + CoreTypeEncoder(&mut self.bytes) + } + + /// Defines an outer core type alias in this module type. + pub fn alias_outer_core_type(&mut self, count: u32, index: u32) -> &mut Self { + self.bytes.push(0x02); + self.bytes.push(CORE_TYPE_SORT); + self.bytes.push(0x01); // outer + count.encode(&mut self.bytes); + index.encode(&mut self.bytes); + self.num_added += 1; + self.types_added += 1; + self + } + + /// Defines an export in this module type. + pub fn export(&mut self, name: &str, ty: EntityType) -> &mut Self { + self.bytes.push(0x03); + name.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Gets the number of types that have been added to this module type. + pub fn type_count(&self) -> u32 { + self.types_added + } +} + +impl Encode for ModuleType { + fn encode(&self, sink: &mut Vec<u8>) { + sink.push(0x50); + self.num_added.encode(sink); + sink.extend(&self.bytes); + } +} + +/// Used to encode core types. +#[derive(Debug)] +pub struct CoreTypeEncoder<'a>(pub(crate) &'a mut Vec<u8>); + +impl<'a> CoreTypeEncoder<'a> { + /// Define a function type. + pub fn function<P, R>(self, params: P, results: R) + where + P: IntoIterator<Item = ValType>, + P::IntoIter: ExactSizeIterator, + R: IntoIterator<Item = ValType>, + R::IntoIter: ExactSizeIterator, + { + let params = params.into_iter(); + let results = results.into_iter(); + + self.0.push(0x60); + params.len().encode(self.0); + self.0.extend(params.map(u8::from)); + results.len().encode(self.0); + self.0.extend(results.map(u8::from)); + } + + /// Define a module type. + pub fn module(self, ty: &ModuleType) { + ty.encode(self.0); + } +} + +/// An encoder for the core type section of WebAssembly components. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Component, CoreTypeSection, ModuleType}; +/// +/// let mut types = CoreTypeSection::new(); +/// +/// types.module(&ModuleType::new()); +/// +/// let mut component = Component::new(); +/// component.section(&types); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct CoreTypeSection { + bytes: Vec<u8>, + num_added: u32, +} + +impl CoreTypeSection { + /// Create a new core type section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of types in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Encode a type into this section. + /// + /// The returned encoder must be finished before adding another type. + #[must_use = "the encoder must be used to encode the type"] + pub fn ty(&mut self) -> CoreTypeEncoder<'_> { + self.num_added += 1; + CoreTypeEncoder(&mut self.bytes) + } + + /// Define a function type in this type section. + pub fn function<P, R>(&mut self, params: P, results: R) -> &mut Self + where + P: IntoIterator<Item = ValType>, + P::IntoIter: ExactSizeIterator, + R: IntoIterator<Item = ValType>, + R::IntoIter: ExactSizeIterator, + { + self.ty().function(params, results); + self + } + + /// Define a module type in this type section. + /// + /// Currently this is only used for core type sections in components. + pub fn module(&mut self, ty: &ModuleType) -> &mut Self { + self.ty().module(ty); + self + } +} + +impl Encode for CoreTypeSection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl ComponentSection for CoreTypeSection { + fn id(&self) -> u8 { + ComponentSectionId::CoreType.into() + } +} + +/// Represents a component type. +#[derive(Debug, Clone, Default)] +pub struct ComponentType { + bytes: Vec<u8>, + num_added: u32, + core_types_added: u32, + types_added: u32, +} + +impl ComponentType { + /// Creates a new component type. + pub fn new() -> Self { + Self::default() + } + + /// Define a core type in this component type. + /// + /// The returned encoder must be used before adding another definition. + #[must_use = "the encoder must be used to encode the type"] + pub fn core_type(&mut self) -> CoreTypeEncoder { + self.bytes.push(0x00); + self.num_added += 1; + self.core_types_added += 1; + CoreTypeEncoder(&mut self.bytes) + } + + /// Define a type in this component type. + /// + /// The returned encoder must be used before adding another definition. + #[must_use = "the encoder must be used to encode the type"] + pub fn ty(&mut self) -> ComponentTypeEncoder { + self.bytes.push(0x01); + self.num_added += 1; + self.types_added += 1; + ComponentTypeEncoder(&mut self.bytes) + } + + /// Defines an outer core type alias in this component type. + pub fn alias_outer_core_type(&mut self, count: u32, index: u32) -> &mut Self { + self.bytes.push(0x02); + ComponentOuterAliasKind::CoreType.encode(&mut self.bytes); + self.bytes.push(0x02); + count.encode(&mut self.bytes); + index.encode(&mut self.bytes); + self.num_added += 1; + self.core_types_added += 1; + self + } + + /// Defines an outer type alias in this component type. + pub fn alias_outer_type(&mut self, count: u32, index: u32) -> &mut Self { + self.bytes.push(0x02); + ComponentOuterAliasKind::Type.encode(&mut self.bytes); + self.bytes.push(0x02); + count.encode(&mut self.bytes); + index.encode(&mut self.bytes); + self.num_added += 1; + self.types_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); + name.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_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); + name.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Gets the number of core types that have been added to this component type. + pub fn core_type_count(&self) -> u32 { + self.core_types_added + } + + /// Gets the number of types that have been added or aliased in this component type. + pub fn type_count(&self) -> u32 { + self.types_added + } +} + +impl Encode for ComponentType { + fn encode(&self, sink: &mut Vec<u8>) { + sink.push(0x41); + self.num_added.encode(sink); + sink.extend(&self.bytes); + } +} + +/// Represents an instance type. +#[derive(Debug, Clone, Default)] +pub struct InstanceType { + bytes: Vec<u8>, + num_added: u32, + core_types_added: u32, + types_added: u32, +} + +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.bytes.push(0x00); + self.num_added += 1; + self.core_types_added += 1; + CoreTypeEncoder(&mut self.bytes) + } + + /// 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.bytes.push(0x01); + self.num_added += 1; + self.types_added += 1; + ComponentTypeEncoder(&mut self.bytes) + } + + /// Defines an outer core type alias in this component type. + pub fn alias_outer_core_type(&mut self, count: u32, index: u32) -> &mut Self { + self.bytes.push(0x02); + ComponentOuterAliasKind::CoreType.encode(&mut self.bytes); + self.bytes.push(0x02); + count.encode(&mut self.bytes); + index.encode(&mut self.bytes); + self.num_added += 1; + self.core_types_added += 1; + self + } + + /// Defines an alias in this instance type. + pub fn alias_outer_type(&mut self, count: u32, index: u32) -> &mut Self { + self.bytes.push(0x02); + ComponentOuterAliasKind::Type.encode(&mut self.bytes); + self.bytes.push(0x02); + count.encode(&mut self.bytes); + index.encode(&mut self.bytes); + self.num_added += 1; + self.types_added += 1; + self + } + + /// Defines an export in this instance type. + pub fn export(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { + self.bytes.push(0x04); + name.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Gets the number of core types that have been added to this instance 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 instance type. + pub fn type_count(&self) -> u32 { + self.types_added + } +} + +impl Encode for InstanceType { + fn encode(&self, sink: &mut Vec<u8>) { + sink.push(0x42); + self.num_added.encode(sink); + sink.extend(&self.bytes); + } +} + +/// Used to encode component function types. +#[derive(Debug)] +pub struct ComponentFuncTypeEncoder<'a>(&'a mut Vec<u8>); + +impl<'a> ComponentFuncTypeEncoder<'a> { + fn new(sink: &'a mut Vec<u8>) -> Self { + sink.push(0x40); + Self(sink) + } + + /// Defines named parameters. + /// + /// Parameters must be defined before defining results. + pub fn params<'b, P, T>(&mut self, params: P) -> &mut Self + where + P: IntoIterator<Item = (&'b str, T)>, + P::IntoIter: ExactSizeIterator, + T: Into<ComponentValType>, + { + let params = params.into_iter(); + params.len().encode(self.0); + for (name, ty) in params { + name.encode(self.0); + ty.into().encode(self.0); + } + self + } + + /// Defines a single unnamed result. + /// + /// This method cannot be used with `results`. + pub fn result(&mut self, ty: impl Into<ComponentValType>) -> &mut Self { + self.0.push(0x00); + ty.into().encode(self.0); + self + } + + /// Defines named results. + /// + /// This method cannot be used with `result`. + pub fn results<'b, R, T>(&mut self, results: R) -> &mut Self + where + R: IntoIterator<Item = (&'b str, T)>, + R::IntoIter: ExactSizeIterator, + T: Into<ComponentValType>, + { + self.0.push(0x01); + let results = results.into_iter(); + results.len().encode(self.0); + for (name, ty) in results { + name.encode(self.0); + ty.into().encode(self.0); + } + self + } +} + +/// Used to encode component and instance types. +#[derive(Debug)] +pub struct ComponentTypeEncoder<'a>(&'a mut Vec<u8>); + +impl<'a> ComponentTypeEncoder<'a> { + /// Define a component type. + pub fn component(self, ty: &ComponentType) { + ty.encode(self.0); + } + + /// Define an instance type. + pub fn instance(self, ty: &InstanceType) { + ty.encode(self.0); + } + + /// Define a function type. + pub fn function(self) -> ComponentFuncTypeEncoder<'a> { + ComponentFuncTypeEncoder::new(self.0) + } + + /// Define a defined component type. + /// + /// The returned encoder must be used before adding another type. + #[must_use = "the encoder must be used to encode the type"] + pub fn defined_type(self) -> ComponentDefinedTypeEncoder<'a> { + ComponentDefinedTypeEncoder(self.0) + } +} + +/// Represents a primitive component value type. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum PrimitiveValType { + /// The type is a boolean. + Bool, + /// The type is a signed 8-bit integer. + S8, + /// The type is an unsigned 8-bit integer. + U8, + /// The type is a signed 16-bit integer. + S16, + /// The type is an unsigned 16-bit integer. + U16, + /// The type is a signed 32-bit integer. + S32, + /// The type is an unsigned 32-bit integer. + U32, + /// The type is a signed 64-bit integer. + S64, + /// The type is an unsigned 64-bit integer. + U64, + /// The type is a 32-bit floating point number. + Float32, + /// The type is a 64-bit floating point number. + Float64, + /// The type is a Unicode character. + Char, + /// The type is a string. + String, +} + +impl Encode for PrimitiveValType { + fn encode(&self, sink: &mut Vec<u8>) { + sink.push(match self { + Self::Bool => 0x7f, + Self::S8 => 0x7e, + Self::U8 => 0x7d, + Self::S16 => 0x7c, + Self::U16 => 0x7b, + Self::S32 => 0x7a, + Self::U32 => 0x79, + Self::S64 => 0x78, + Self::U64 => 0x77, + Self::Float32 => 0x76, + Self::Float64 => 0x75, + Self::Char => 0x74, + Self::String => 0x73, + }); + } +} + +/// Represents a component value type. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ComponentValType { + /// The value is a primitive type. + Primitive(PrimitiveValType), + /// The value is to a defined value type. + /// + /// The type index must be to a value type. + Type(u32), +} + +impl Encode for ComponentValType { + fn encode(&self, sink: &mut Vec<u8>) { + match self { + Self::Primitive(ty) => ty.encode(sink), + Self::Type(index) => (*index as i64).encode(sink), + } + } +} + +impl From<PrimitiveValType> for ComponentValType { + fn from(ty: PrimitiveValType) -> Self { + Self::Primitive(ty) + } +} + +/// Used for encoding component defined types. +#[derive(Debug)] +pub struct ComponentDefinedTypeEncoder<'a>(&'a mut Vec<u8>); + +impl ComponentDefinedTypeEncoder<'_> { + /// Define a primitive value type. + pub fn primitive(self, ty: PrimitiveValType) { + ty.encode(self.0); + } + + /// Define a record type. + pub fn record<'a, F, T>(self, fields: F) + where + F: IntoIterator<Item = (&'a str, T)>, + F::IntoIter: ExactSizeIterator, + T: Into<ComponentValType>, + { + let fields = fields.into_iter(); + self.0.push(0x72); + fields.len().encode(self.0); + for (name, ty) in fields { + name.encode(self.0); + ty.into().encode(self.0); + } + } + + /// Define a variant type. + pub fn variant<'a, C>(self, cases: C) + where + C: IntoIterator<Item = (&'a str, Option<ComponentValType>, Option<u32>)>, + C::IntoIter: ExactSizeIterator, + { + let cases = cases.into_iter(); + self.0.push(0x71); + cases.len().encode(self.0); + for (name, ty, refines) in cases { + name.encode(self.0); + ty.encode(self.0); + refines.encode(self.0); + } + } + + /// Define a list type. + pub fn list(self, ty: impl Into<ComponentValType>) { + self.0.push(0x70); + ty.into().encode(self.0); + } + + /// Define a tuple type. + pub fn tuple<I, T>(self, types: I) + where + I: IntoIterator<Item = T>, + I::IntoIter: ExactSizeIterator, + T: Into<ComponentValType>, + { + let types = types.into_iter(); + self.0.push(0x6F); + types.len().encode(self.0); + for ty in types { + ty.into().encode(self.0); + } + } + + /// Define a flags type. + pub fn flags<'a, I>(self, names: I) + where + I: IntoIterator<Item = &'a str>, + I::IntoIter: ExactSizeIterator, + { + let names = names.into_iter(); + self.0.push(0x6E); + names.len().encode(self.0); + for name in names { + name.encode(self.0); + } + } + + /// Define an enum type. + pub fn enum_type<'a, I>(self, tags: I) + where + I: IntoIterator<Item = &'a str>, + I::IntoIter: ExactSizeIterator, + { + let tags = tags.into_iter(); + self.0.push(0x6D); + tags.len().encode(self.0); + for tag in tags { + tag.encode(self.0); + } + } + + /// Define a union type. + pub fn union<I, T>(self, types: I) + where + I: IntoIterator<Item = T>, + I::IntoIter: ExactSizeIterator, + T: Into<ComponentValType>, + { + let types = types.into_iter(); + self.0.push(0x6C); + types.len().encode(self.0); + for ty in types { + ty.into().encode(self.0); + } + } + + /// Define an option type. + pub fn option(self, ty: impl Into<ComponentValType>) { + self.0.push(0x6B); + ty.into().encode(self.0); + } + + /// Define a result type. + pub fn result(self, ok: Option<ComponentValType>, err: Option<ComponentValType>) { + self.0.push(0x6A); + ok.encode(self.0); + err.encode(self.0); + } +} + +/// An encoder for the type section of WebAssembly components. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Component, ComponentTypeSection, PrimitiveValType}; +/// +/// let mut types = ComponentTypeSection::new(); +/// +/// // Define a function type of `[string, string] -> string`. +/// types +/// .function() +/// .params( +/// [ +/// ("a", PrimitiveValType::String), +/// ("b", PrimitiveValType::String) +/// ] +/// ) +/// .result(PrimitiveValType::String); +/// +/// let mut component = Component::new(); +/// component.section(&types); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct ComponentTypeSection { + bytes: Vec<u8>, + num_added: u32, +} + +impl ComponentTypeSection { + /// Create a new component type section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of types in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Encode a type into this section. + /// + /// The returned encoder must be finished before adding another type. + #[must_use = "the encoder must be used to encode the type"] + pub fn ty(&mut self) -> ComponentTypeEncoder<'_> { + self.num_added += 1; + ComponentTypeEncoder(&mut self.bytes) + } + + /// Define a component type in this type section. + pub fn component(&mut self, ty: &ComponentType) -> &mut Self { + self.ty().component(ty); + self + } + + /// Define an instance type in this type section. + pub fn instance(&mut self, ty: &InstanceType) -> &mut Self { + self.ty().instance(ty); + self + } + + /// Define a function type in this type section. + pub fn function(&mut self) -> ComponentFuncTypeEncoder<'_> { + self.ty().function() + } + + /// Add a component defined type to this type section. + /// + /// The returned encoder must be used before adding another type. + #[must_use = "the encoder must be used to encode the type"] + pub fn defined_type(&mut self) -> ComponentDefinedTypeEncoder<'_> { + self.ty().defined_type() + } +} + +impl Encode for ComponentTypeSection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl ComponentSection for ComponentTypeSection { + fn id(&self) -> u8 { + ComponentSectionId::Type.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/core.rs b/third_party/rust/wasm-encoder/src/core.rs new file mode 100644 index 0000000000..e03bd9363e --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core.rs @@ -0,0 +1,154 @@ +mod code; +mod custom; +mod data; +mod elements; +mod exports; +mod functions; +mod globals; +mod imports; +mod linking; +mod memories; +mod names; +mod start; +mod tables; +mod tags; +mod types; + +pub use code::*; +pub use custom::*; +pub use data::*; +pub use elements::*; +pub use exports::*; +pub use functions::*; +pub use globals::*; +pub use imports::*; +pub use linking::*; +pub use memories::*; +pub use names::*; +pub use 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; +} + +/// 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 { + /// Begin writing a new `Module`. + #[rustfmt::skip] + pub fn new() -> Self { + Module { + bytes: vec![ + // Magic + 0x00, 0x61, 0x73, 0x6D, + // Version + 0x01, 0x00, 0x00, 0x00, + ], + } + } + + /// 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..eb3f7c03e9 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/code.rs @@ -0,0 +1,2868 @@ +use crate::{encode_section, Encode, 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 mut reader = wasmparser::CodeSectionReader::new(&code_section, 0).unwrap(); + /// let body = reader.read().unwrap(); + /// let body_range = body.range(); + /// + /// // Add the body to a new code section encoder by copying bytes rather + /// // than re-parsing and re-encoding it. + /// let mut encoder = wasm_encoder::CodeSection::new(); + /// encoder.raw(&code_section[body_range.start..body_range.end]); + /// ``` + pub fn raw(&mut self, data: &[u8]) -> &mut Self { + data.encode(&mut self.bytes); + self.num_added += 1; + self + } +} + +impl Encode for CodeSection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl Section for CodeSection { + fn id(&self) -> u8 { + SectionId::Code.into() + } +} + +/// An encoder for a function body within the code section. +/// +/// # Example +/// +/// ``` +/// use wasm_encoder::{CodeSection, Function, Instruction}; +/// +/// // Define the function body for: +/// // +/// // (func (param i32 i32) (result i32) +/// // local.get 0 +/// // local.get 1 +/// // i32.add) +/// let locals = vec![]; +/// let mut func = Function::new(locals); +/// func.instruction(&Instruction::LocalGet(0)); +/// func.instruction(&Instruction::LocalGet(1)); +/// func.instruction(&Instruction::I32Add); +/// +/// // Add our function to the code section. +/// let mut code = CodeSection::new(); +/// code.function(&func); +/// ``` +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Function { + bytes: Vec<u8>, +} + +impl Function { + /// Create a new function body with the given locals. + /// + /// The argument is an iterator over `(N, Ty)`, which defines + /// that the next `N` locals will be of type `Ty`. + /// + /// For example, a function with locals 0 and 1 of type I32 and + /// local 2 of type F32 would be created as: + /// + /// ``` + /// # use wasm_encoder::{Function, ValType}; + /// let f = Function::new([(2, ValType::I32), (1, ValType::F32)]); + /// ``` + /// + /// For more information about the code section (and function definition) in the WASM binary format + /// see the [WebAssembly spec](https://webassembly.github.io/spec/core/binary/modules.html#binary-func) + pub fn new<L>(locals: L) -> Self + where + L: IntoIterator<Item = (u32, ValType)>, + L::IntoIter: ExactSizeIterator, + { + let locals = locals.into_iter(); + let mut bytes = vec![]; + locals.len().encode(&mut bytes); + for (count, ty) in locals { + count.encode(&mut bytes); + ty.encode(&mut bytes); + } + Function { bytes } + } + + /// Create a function from a list of locals' types. + /// + /// Unlike [`Function::new`], this constructor simply takes a list of types + /// which are in order associated with locals. + /// + /// For example: + /// + /// ``` + /// # use wasm_encoder::{Function, ValType}; + /// let f = Function::new([(2, ValType::I32), (1, ValType::F32)]); + /// let g = Function::new_with_locals_types([ + /// ValType::I32, ValType::I32, ValType::F32 + /// ]); + /// + /// assert_eq!(f, g) + /// ``` + pub fn new_with_locals_types<L>(locals: L) -> Self + where + L: IntoIterator<Item = ValType>, + { + let locals = locals.into_iter(); + + let mut locals_collected: Vec<(u32, ValType)> = vec![]; + for l in locals { + if let Some((last_count, last_type)) = locals_collected.last_mut() { + if l == *last_type { + // Increment the count of consecutive locals of this type + *last_count += 1; + continue; + } + } + // If we didn't increment, a new type of local appeared + locals_collected.push((1, l)); + } + + Function::new(locals_collected) + } + + /// Write an instruction into this function body. + pub fn instruction(&mut self, instruction: &Instruction) -> &mut Self { + instruction.encode(&mut self.bytes); + self + } + + /// Add raw bytes to this function's body. + pub fn raw<B>(&mut self, bytes: B) -> &mut Self + where + B: IntoIterator<Item = u8>, + { + self.bytes.extend(bytes); + self + } + + /// The number of bytes already added to this function. + /// + /// This number doesn't include the variable-width size field that `encode` + /// will write before the added bytes, since the size of that field isn't + /// known until all the instructions are added to this function. + pub fn byte_len(&self) -> usize { + self.bytes.len() + } +} + +impl Encode for Function { + fn encode(&self, sink: &mut Vec<u8>) { + self.bytes.encode(sink); + } +} + +/// The immediate for a memory instruction. +#[derive(Clone, Copy, Debug)] +pub struct MemArg { + /// A static offset to add to the instruction's dynamic address operand. + /// + /// This is a `u64` field for the memory64 proposal, but 32-bit memories + /// limit offsets to at most `u32::MAX` bytes. This will be encoded as a LEB + /// but it won't generate a valid module if an offset is specified which is + /// larger than the maximum size of the index space for the memory indicated + /// by `memory_index`. + pub offset: u64, + /// The expected alignment of the instruction's dynamic address operand + /// (expressed the exponent of a power of two). + pub align: u32, + /// The index of the memory this instruction is operating upon. + pub memory_index: u32, +} + +impl Encode for MemArg { + fn encode(&self, sink: &mut Vec<u8>) { + if self.memory_index == 0 { + self.align.encode(sink); + self.offset.encode(sink); + } else { + (self.align | (1 << 6)).encode(sink); + self.memory_index.encode(sink); + self.offset.encode(sink); + } + } +} + +/// Describe an unchecked SIMD lane index. +pub type Lane = u8; + +/// The type for a `block`/`if`/`loop`. +#[derive(Clone, Copy, Debug)] +pub enum BlockType { + /// `[] -> []` + Empty, + /// `[] -> [t]` + Result(ValType), + /// The `n`th function type. + FunctionType(u32), +} + +impl Encode for BlockType { + fn encode(&self, sink: &mut Vec<u8>) { + match *self { + Self::Empty => sink.push(0x40), + Self::Result(ty) => ty.encode(sink), + Self::FunctionType(f) => (f as i64).encode(sink), + } + } +} + +/// WebAssembly instructions. +#[derive(Clone, Debug)] +#[non_exhaustive] +#[allow(missing_docs, non_camel_case_types)] +pub enum Instruction<'a> { + // Control instructions. + Unreachable, + Nop, + Block(BlockType), + Loop(BlockType), + If(BlockType), + Else, + Try(BlockType), + Delegate(u32), + Catch(u32), + CatchAll, + End, + Br(u32), + BrIf(u32), + BrTable(Cow<'a, [u32]>, u32), + Return, + Call(u32), + CallIndirect { ty: u32, table: u32 }, + ReturnCall(u32), + ReturnCallIndirect { ty: u32, table: u32 }, + Throw(u32), + Rethrow(u32), + + // Parametric instructions. + Drop, + Select, + + // Variable instructions. + LocalGet(u32), + LocalSet(u32), + LocalTee(u32), + GlobalGet(u32), + GlobalSet(u32), + + // Memory instructions. + I32Load(MemArg), + I64Load(MemArg), + F32Load(MemArg), + F64Load(MemArg), + I32Load8S(MemArg), + I32Load8U(MemArg), + I32Load16S(MemArg), + I32Load16U(MemArg), + I64Load8S(MemArg), + I64Load8U(MemArg), + I64Load16S(MemArg), + I64Load16U(MemArg), + I64Load32S(MemArg), + I64Load32U(MemArg), + I32Store(MemArg), + I64Store(MemArg), + F32Store(MemArg), + F64Store(MemArg), + I32Store8(MemArg), + I32Store16(MemArg), + I64Store8(MemArg), + I64Store16(MemArg), + I64Store32(MemArg), + MemorySize(u32), + MemoryGrow(u32), + MemoryInit { mem: u32, data_index: u32 }, + DataDrop(u32), + MemoryCopy { src_mem: u32, dst_mem: u32 }, + MemoryFill(u32), + + // 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(ValType), + RefIsNull, + RefFunc(u32), + + // 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, + I8x16RelaxedSwizzle, + I32x4RelaxedTruncSatF32x4S, + I32x4RelaxedTruncSatF32x4U, + I32x4RelaxedTruncSatF64x2SZero, + I32x4RelaxedTruncSatF64x2UZero, + F32x4RelaxedFma, + F32x4RelaxedFnma, + F64x2RelaxedFma, + F64x2RelaxedFnma, + I8x16RelaxedLaneselect, + I16x8RelaxedLaneselect, + I32x4RelaxedLaneselect, + I64x2RelaxedLaneselect, + F32x4RelaxedMin, + F32x4RelaxedMax, + F64x2RelaxedMin, + F64x2RelaxedMax, + I16x8RelaxedQ15mulrS, + I16x8DotI8x16I7x16S, + I32x4DotI8x16I7x16AddS, + F32x4RelaxedDotBf16x8AddF32x4, + + // Atomic instructions (the threads proposal) + MemoryAtomicNotify(MemArg), + MemoryAtomicWait32(MemArg), + MemoryAtomicWait64(MemArg), + AtomicFence, + I32AtomicLoad(MemArg), + I64AtomicLoad(MemArg), + I32AtomicLoad8U(MemArg), + I32AtomicLoad16U(MemArg), + I64AtomicLoad8U(MemArg), + I64AtomicLoad16U(MemArg), + I64AtomicLoad32U(MemArg), + I32AtomicStore(MemArg), + I64AtomicStore(MemArg), + I32AtomicStore8(MemArg), + I32AtomicStore16(MemArg), + I64AtomicStore8(MemArg), + I64AtomicStore16(MemArg), + I64AtomicStore32(MemArg), + I32AtomicRmwAdd(MemArg), + I64AtomicRmwAdd(MemArg), + I32AtomicRmw8AddU(MemArg), + I32AtomicRmw16AddU(MemArg), + I64AtomicRmw8AddU(MemArg), + I64AtomicRmw16AddU(MemArg), + I64AtomicRmw32AddU(MemArg), + I32AtomicRmwSub(MemArg), + I64AtomicRmwSub(MemArg), + I32AtomicRmw8SubU(MemArg), + I32AtomicRmw16SubU(MemArg), + I64AtomicRmw8SubU(MemArg), + I64AtomicRmw16SubU(MemArg), + I64AtomicRmw32SubU(MemArg), + I32AtomicRmwAnd(MemArg), + I64AtomicRmwAnd(MemArg), + I32AtomicRmw8AndU(MemArg), + I32AtomicRmw16AndU(MemArg), + I64AtomicRmw8AndU(MemArg), + I64AtomicRmw16AndU(MemArg), + I64AtomicRmw32AndU(MemArg), + I32AtomicRmwOr(MemArg), + I64AtomicRmwOr(MemArg), + I32AtomicRmw8OrU(MemArg), + I32AtomicRmw16OrU(MemArg), + I64AtomicRmw8OrU(MemArg), + I64AtomicRmw16OrU(MemArg), + I64AtomicRmw32OrU(MemArg), + I32AtomicRmwXor(MemArg), + I64AtomicRmwXor(MemArg), + I32AtomicRmw8XorU(MemArg), + I32AtomicRmw16XorU(MemArg), + I64AtomicRmw8XorU(MemArg), + I64AtomicRmw16XorU(MemArg), + I64AtomicRmw32XorU(MemArg), + I32AtomicRmwXchg(MemArg), + I64AtomicRmwXchg(MemArg), + I32AtomicRmw8XchgU(MemArg), + I32AtomicRmw16XchgU(MemArg), + I64AtomicRmw8XchgU(MemArg), + I64AtomicRmw16XchgU(MemArg), + I64AtomicRmw32XchgU(MemArg), + I32AtomicRmwCmpxchg(MemArg), + I64AtomicRmwCmpxchg(MemArg), + I32AtomicRmw8CmpxchgU(MemArg), + I32AtomicRmw16CmpxchgU(MemArg), + I64AtomicRmw8CmpxchgU(MemArg), + I64AtomicRmw16CmpxchgU(MemArg), + I64AtomicRmw32CmpxchgU(MemArg), +} + +impl Encode for Instruction<'_> { + fn encode(&self, sink: &mut Vec<u8>) { + match *self { + // Control instructions. + Instruction::Unreachable => sink.push(0x00), + Instruction::Nop => sink.push(0x01), + Instruction::Block(bt) => { + sink.push(0x02); + bt.encode(sink); + } + Instruction::Loop(bt) => { + sink.push(0x03); + bt.encode(sink); + } + Instruction::If(bt) => { + sink.push(0x04); + bt.encode(sink); + } + Instruction::Else => sink.push(0x05), + Instruction::Try(bt) => { + sink.push(0x06); + bt.encode(sink); + } + Instruction::Catch(t) => { + sink.push(0x07); + t.encode(sink); + } + Instruction::Throw(t) => { + sink.push(0x08); + t.encode(sink); + } + Instruction::Rethrow(l) => { + sink.push(0x09); + l.encode(sink); + } + Instruction::End => sink.push(0x0B), + Instruction::Br(l) => { + sink.push(0x0C); + l.encode(sink); + } + Instruction::BrIf(l) => { + sink.push(0x0D); + l.encode(sink); + } + Instruction::BrTable(ref ls, l) => { + sink.push(0x0E); + ls.encode(sink); + l.encode(sink); + } + Instruction::Return => sink.push(0x0F), + Instruction::Call(f) => { + sink.push(0x10); + f.encode(sink); + } + Instruction::CallIndirect { ty, table } => { + sink.push(0x11); + ty.encode(sink); + table.encode(sink); + } + Instruction::ReturnCall(f) => { + sink.push(0x12); + f.encode(sink); + } + Instruction::ReturnCallIndirect { ty, table } => { + sink.push(0x13); + ty.encode(sink); + table.encode(sink); + } + Instruction::Delegate(l) => { + sink.push(0x18); + l.encode(sink); + } + Instruction::CatchAll => { + sink.push(0x19); + } + + // Parametric instructions. + Instruction::Drop => sink.push(0x1A), + Instruction::Select => sink.push(0x1B), + Instruction::TypedSelect(ty) => { + sink.push(0x1c); + [ty].encode(sink); + } + + // Variable instructions. + Instruction::LocalGet(l) => { + sink.push(0x20); + l.encode(sink); + } + Instruction::LocalSet(l) => { + sink.push(0x21); + l.encode(sink); + } + Instruction::LocalTee(l) => { + sink.push(0x22); + l.encode(sink); + } + Instruction::GlobalGet(g) => { + sink.push(0x23); + g.encode(sink); + } + Instruction::GlobalSet(g) => { + sink.push(0x24); + g.encode(sink); + } + Instruction::TableGet(table) => { + sink.push(0x25); + table.encode(sink); + } + Instruction::TableSet(table) => { + sink.push(0x26); + table.encode(sink); + } + + // Memory instructions. + Instruction::I32Load(m) => { + sink.push(0x28); + m.encode(sink); + } + Instruction::I64Load(m) => { + sink.push(0x29); + m.encode(sink); + } + Instruction::F32Load(m) => { + sink.push(0x2A); + m.encode(sink); + } + Instruction::F64Load(m) => { + sink.push(0x2B); + m.encode(sink); + } + Instruction::I32Load8S(m) => { + sink.push(0x2C); + m.encode(sink); + } + Instruction::I32Load8U(m) => { + sink.push(0x2D); + m.encode(sink); + } + Instruction::I32Load16S(m) => { + sink.push(0x2E); + m.encode(sink); + } + Instruction::I32Load16U(m) => { + sink.push(0x2F); + m.encode(sink); + } + Instruction::I64Load8S(m) => { + sink.push(0x30); + m.encode(sink); + } + Instruction::I64Load8U(m) => { + sink.push(0x31); + m.encode(sink); + } + Instruction::I64Load16S(m) => { + sink.push(0x32); + m.encode(sink); + } + Instruction::I64Load16U(m) => { + sink.push(0x33); + m.encode(sink); + } + Instruction::I64Load32S(m) => { + sink.push(0x34); + m.encode(sink); + } + Instruction::I64Load32U(m) => { + sink.push(0x35); + m.encode(sink); + } + Instruction::I32Store(m) => { + sink.push(0x36); + m.encode(sink); + } + Instruction::I64Store(m) => { + sink.push(0x37); + m.encode(sink); + } + Instruction::F32Store(m) => { + sink.push(0x38); + m.encode(sink); + } + Instruction::F64Store(m) => { + sink.push(0x39); + m.encode(sink); + } + Instruction::I32Store8(m) => { + sink.push(0x3A); + m.encode(sink); + } + Instruction::I32Store16(m) => { + sink.push(0x3B); + m.encode(sink); + } + Instruction::I64Store8(m) => { + sink.push(0x3C); + m.encode(sink); + } + Instruction::I64Store16(m) => { + sink.push(0x3D); + m.encode(sink); + } + Instruction::I64Store32(m) => { + sink.push(0x3E); + m.encode(sink); + } + Instruction::MemorySize(i) => { + sink.push(0x3F); + i.encode(sink); + } + Instruction::MemoryGrow(i) => { + sink.push(0x40); + i.encode(sink); + } + Instruction::MemoryInit { mem, data_index } => { + sink.push(0xfc); + sink.push(0x08); + data_index.encode(sink); + mem.encode(sink); + } + Instruction::DataDrop(data) => { + sink.push(0xfc); + sink.push(0x09); + data.encode(sink); + } + Instruction::MemoryCopy { src_mem, dst_mem } => { + sink.push(0xfc); + sink.push(0x0a); + dst_mem.encode(sink); + src_mem.encode(sink); + } + Instruction::MemoryFill(mem) => { + sink.push(0xfc); + sink.push(0x0b); + mem.encode(sink); + } + + // 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); + } + + // 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::I32x4RelaxedTruncSatF32x4S => { + sink.push(0xFD); + 0x101u32.encode(sink); + } + Instruction::I32x4RelaxedTruncSatF32x4U => { + sink.push(0xFD); + 0x102u32.encode(sink); + } + Instruction::I32x4RelaxedTruncSatF64x2SZero => { + sink.push(0xFD); + 0x103u32.encode(sink); + } + Instruction::I32x4RelaxedTruncSatF64x2UZero => { + sink.push(0xFD); + 0x104u32.encode(sink); + } + Instruction::F32x4RelaxedFma => { + sink.push(0xFD); + 0x105u32.encode(sink); + } + Instruction::F32x4RelaxedFnma => { + sink.push(0xFD); + 0x106u32.encode(sink); + } + Instruction::F64x2RelaxedFma => { + sink.push(0xFD); + 0x107u32.encode(sink); + } + Instruction::F64x2RelaxedFnma => { + 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::I16x8DotI8x16I7x16S => { + sink.push(0xFD); + 0x112u32.encode(sink); + } + Instruction::I32x4DotI8x16I7x16AddS => { + sink.push(0xFD); + 0x113u32.encode(sink); + } + Instruction::F32x4RelaxedDotBf16x8AddF32x4 => { + sink.push(0xFD); + 0x114u32.encode(sink); + } + + // Atmoic instructions from the thread proposal + Instruction::MemoryAtomicNotify(memarg) => { + sink.push(0xFE); + sink.push(0x00); + memarg.encode(sink); + } + Instruction::MemoryAtomicWait32(memarg) => { + sink.push(0xFE); + sink.push(0x01); + memarg.encode(sink); + } + Instruction::MemoryAtomicWait64(memarg) => { + sink.push(0xFE); + sink.push(0x02); + memarg.encode(sink); + } + Instruction::AtomicFence => { + sink.push(0xFE); + sink.push(0x03); + sink.push(0x00); + } + Instruction::I32AtomicLoad(memarg) => { + sink.push(0xFE); + sink.push(0x10); + memarg.encode(sink); + } + Instruction::I64AtomicLoad(memarg) => { + sink.push(0xFE); + sink.push(0x11); + memarg.encode(sink); + } + Instruction::I32AtomicLoad8U(memarg) => { + sink.push(0xFE); + sink.push(0x12); + memarg.encode(sink); + } + Instruction::I32AtomicLoad16U(memarg) => { + sink.push(0xFE); + sink.push(0x13); + memarg.encode(sink); + } + Instruction::I64AtomicLoad8U(memarg) => { + sink.push(0xFE); + sink.push(0x14); + memarg.encode(sink); + } + Instruction::I64AtomicLoad16U(memarg) => { + sink.push(0xFE); + sink.push(0x15); + memarg.encode(sink); + } + Instruction::I64AtomicLoad32U(memarg) => { + sink.push(0xFE); + sink.push(0x16); + memarg.encode(sink); + } + Instruction::I32AtomicStore(memarg) => { + sink.push(0xFE); + sink.push(0x17); + memarg.encode(sink); + } + Instruction::I64AtomicStore(memarg) => { + sink.push(0xFE); + sink.push(0x18); + memarg.encode(sink); + } + Instruction::I32AtomicStore8(memarg) => { + sink.push(0xFE); + sink.push(0x19); + memarg.encode(sink); + } + Instruction::I32AtomicStore16(memarg) => { + sink.push(0xFE); + sink.push(0x1A); + memarg.encode(sink); + } + Instruction::I64AtomicStore8(memarg) => { + sink.push(0xFE); + sink.push(0x1B); + memarg.encode(sink); + } + Instruction::I64AtomicStore16(memarg) => { + sink.push(0xFE); + sink.push(0x1C); + memarg.encode(sink); + } + Instruction::I64AtomicStore32(memarg) => { + sink.push(0xFE); + sink.push(0x1D); + memarg.encode(sink); + } + Instruction::I32AtomicRmwAdd(memarg) => { + sink.push(0xFE); + sink.push(0x1E); + memarg.encode(sink); + } + Instruction::I64AtomicRmwAdd(memarg) => { + sink.push(0xFE); + sink.push(0x1F); + memarg.encode(sink); + } + Instruction::I32AtomicRmw8AddU(memarg) => { + sink.push(0xFE); + sink.push(0x20); + memarg.encode(sink); + } + Instruction::I32AtomicRmw16AddU(memarg) => { + sink.push(0xFE); + sink.push(0x21); + memarg.encode(sink); + } + Instruction::I64AtomicRmw8AddU(memarg) => { + sink.push(0xFE); + sink.push(0x22); + memarg.encode(sink); + } + Instruction::I64AtomicRmw16AddU(memarg) => { + sink.push(0xFE); + sink.push(0x23); + memarg.encode(sink); + } + Instruction::I64AtomicRmw32AddU(memarg) => { + sink.push(0xFE); + sink.push(0x24); + memarg.encode(sink); + } + Instruction::I32AtomicRmwSub(memarg) => { + sink.push(0xFE); + sink.push(0x25); + memarg.encode(sink); + } + Instruction::I64AtomicRmwSub(memarg) => { + sink.push(0xFE); + sink.push(0x26); + memarg.encode(sink); + } + Instruction::I32AtomicRmw8SubU(memarg) => { + sink.push(0xFE); + sink.push(0x27); + memarg.encode(sink); + } + Instruction::I32AtomicRmw16SubU(memarg) => { + sink.push(0xFE); + sink.push(0x28); + memarg.encode(sink); + } + Instruction::I64AtomicRmw8SubU(memarg) => { + sink.push(0xFE); + sink.push(0x29); + memarg.encode(sink); + } + Instruction::I64AtomicRmw16SubU(memarg) => { + sink.push(0xFE); + sink.push(0x2A); + memarg.encode(sink); + } + Instruction::I64AtomicRmw32SubU(memarg) => { + sink.push(0xFE); + sink.push(0x2B); + memarg.encode(sink); + } + Instruction::I32AtomicRmwAnd(memarg) => { + sink.push(0xFE); + sink.push(0x2C); + memarg.encode(sink); + } + Instruction::I64AtomicRmwAnd(memarg) => { + sink.push(0xFE); + sink.push(0x2D); + memarg.encode(sink); + } + Instruction::I32AtomicRmw8AndU(memarg) => { + sink.push(0xFE); + sink.push(0x2E); + memarg.encode(sink); + } + Instruction::I32AtomicRmw16AndU(memarg) => { + sink.push(0xFE); + sink.push(0x2F); + memarg.encode(sink); + } + Instruction::I64AtomicRmw8AndU(memarg) => { + sink.push(0xFE); + sink.push(0x30); + memarg.encode(sink); + } + Instruction::I64AtomicRmw16AndU(memarg) => { + sink.push(0xFE); + sink.push(0x31); + memarg.encode(sink); + } + Instruction::I64AtomicRmw32AndU(memarg) => { + sink.push(0xFE); + sink.push(0x32); + memarg.encode(sink); + } + Instruction::I32AtomicRmwOr(memarg) => { + sink.push(0xFE); + sink.push(0x33); + memarg.encode(sink); + } + Instruction::I64AtomicRmwOr(memarg) => { + sink.push(0xFE); + sink.push(0x34); + memarg.encode(sink); + } + Instruction::I32AtomicRmw8OrU(memarg) => { + sink.push(0xFE); + sink.push(0x35); + memarg.encode(sink); + } + Instruction::I32AtomicRmw16OrU(memarg) => { + sink.push(0xFE); + sink.push(0x36); + memarg.encode(sink); + } + Instruction::I64AtomicRmw8OrU(memarg) => { + sink.push(0xFE); + sink.push(0x37); + memarg.encode(sink); + } + Instruction::I64AtomicRmw16OrU(memarg) => { + sink.push(0xFE); + sink.push(0x38); + memarg.encode(sink); + } + Instruction::I64AtomicRmw32OrU(memarg) => { + sink.push(0xFE); + sink.push(0x39); + memarg.encode(sink); + } + Instruction::I32AtomicRmwXor(memarg) => { + sink.push(0xFE); + sink.push(0x3A); + memarg.encode(sink); + } + Instruction::I64AtomicRmwXor(memarg) => { + sink.push(0xFE); + sink.push(0x3B); + memarg.encode(sink); + } + Instruction::I32AtomicRmw8XorU(memarg) => { + sink.push(0xFE); + sink.push(0x3C); + memarg.encode(sink); + } + Instruction::I32AtomicRmw16XorU(memarg) => { + sink.push(0xFE); + sink.push(0x3D); + memarg.encode(sink); + } + Instruction::I64AtomicRmw8XorU(memarg) => { + sink.push(0xFE); + sink.push(0x3E); + memarg.encode(sink); + } + Instruction::I64AtomicRmw16XorU(memarg) => { + sink.push(0xFE); + sink.push(0x3F); + memarg.encode(sink); + } + Instruction::I64AtomicRmw32XorU(memarg) => { + sink.push(0xFE); + sink.push(0x40); + memarg.encode(sink); + } + Instruction::I32AtomicRmwXchg(memarg) => { + sink.push(0xFE); + sink.push(0x41); + memarg.encode(sink); + } + Instruction::I64AtomicRmwXchg(memarg) => { + sink.push(0xFE); + sink.push(0x42); + memarg.encode(sink); + } + Instruction::I32AtomicRmw8XchgU(memarg) => { + sink.push(0xFE); + sink.push(0x43); + memarg.encode(sink); + } + Instruction::I32AtomicRmw16XchgU(memarg) => { + sink.push(0xFE); + sink.push(0x44); + memarg.encode(sink); + } + Instruction::I64AtomicRmw8XchgU(memarg) => { + sink.push(0xFE); + sink.push(0x45); + memarg.encode(sink); + } + Instruction::I64AtomicRmw16XchgU(memarg) => { + sink.push(0xFE); + sink.push(0x46); + memarg.encode(sink); + } + Instruction::I64AtomicRmw32XchgU(memarg) => { + sink.push(0xFE); + sink.push(0x47); + memarg.encode(sink); + } + Instruction::I32AtomicRmwCmpxchg(memarg) => { + sink.push(0xFE); + sink.push(0x48); + memarg.encode(sink); + } + Instruction::I64AtomicRmwCmpxchg(memarg) => { + sink.push(0xFE); + sink.push(0x49); + memarg.encode(sink); + } + Instruction::I32AtomicRmw8CmpxchgU(memarg) => { + sink.push(0xFE); + sink.push(0x4A); + memarg.encode(sink); + } + Instruction::I32AtomicRmw16CmpxchgU(memarg) => { + sink.push(0xFE); + sink.push(0x4B); + memarg.encode(sink); + } + Instruction::I64AtomicRmw8CmpxchgU(memarg) => { + sink.push(0xFE); + sink.push(0x4C); + memarg.encode(sink); + } + Instruction::I64AtomicRmw16CmpxchgU(memarg) => { + sink.push(0xFE); + sink.push(0x4D); + memarg.encode(sink); + } + Instruction::I64AtomicRmw32CmpxchgU(memarg) => { + sink.push(0xFE); + sink.push(0x4E); + memarg.encode(sink); + } + } + } +} + +/// A constant expression. +/// +/// Usable in contexts such as offsets or initializers. +#[derive(Debug)] +pub struct ConstExpr { + bytes: Vec<u8>, +} + +impl ConstExpr { + /// Create a new empty constant expression builder. + pub fn empty() -> Self { + Self { bytes: Vec::new() } + } + + /// Create a constant expression with the specified raw encoding of instructions. + pub fn raw(bytes: impl IntoIterator<Item = u8>) -> Self { + Self { + bytes: bytes.into_iter().collect(), + } + } + + fn new_insn(insn: Instruction) -> Self { + let mut bytes = vec![]; + insn.encode(&mut bytes); + Self { bytes } + } + + /// Create a constant expression containing a single `global.get` instruction. + pub fn global_get(index: u32) -> Self { + Self::new_insn(Instruction::GlobalGet(index)) + } + + /// Create a constant expression containing a single `ref.null` instruction. + pub fn ref_null(ty: ValType) -> Self { + Self::new_insn(Instruction::RefNull(ty)) + } + + /// Create a constant expression containing a single `ref.func` instruction. + pub fn ref_func(func: u32) -> Self { + Self::new_insn(Instruction::RefFunc(func)) + } + + /// Create a constant expression containing a single `i32.const` instruction. + pub fn i32_const(value: i32) -> Self { + Self::new_insn(Instruction::I32Const(value)) + } + + /// Create a constant expression containing a single `i64.const` instruction. + pub fn i64_const(value: i64) -> Self { + Self::new_insn(Instruction::I64Const(value)) + } + + /// Create a constant expression containing a single `f32.const` instruction. + pub fn f32_const(value: f32) -> Self { + Self::new_insn(Instruction::F32Const(value)) + } + + /// Create a constant expression containing a single `f64.const` instruction. + pub fn f64_const(value: f64) -> Self { + Self::new_insn(Instruction::F64Const(value)) + } + + /// Create a constant expression containing a single `v128.const` instruction. + pub fn v128_const(value: i128) -> Self { + Self::new_insn(Instruction::V128Const(value)) + } +} + +impl Encode for ConstExpr { + fn encode(&self, sink: &mut Vec<u8>) { + sink.extend(&self.bytes); + Instruction::End.encode(sink); + } +} + +#[cfg(test)] +mod tests { + #[test] + fn function_new_with_locals_test() { + use super::*; + + // Test the algorithm for conversion is correct + let f1 = Function::new_with_locals_types([ + ValType::I32, + ValType::I32, + ValType::I64, + ValType::F32, + ValType::F32, + ValType::F32, + ValType::I32, + ValType::I64, + ValType::I64, + ]); + let f2 = Function::new([ + (2, ValType::I32), + (1, ValType::I64), + (3, ValType::F32), + (1, ValType::I32), + (2, ValType::I64), + ]); + + assert_eq!(f1.bytes, f2.bytes) + } +} diff --git a/third_party/rust/wasm-encoder/src/core/custom.rs b/third_party/rust/wasm-encoder/src/core/custom.rs new file mode 100644 index 0000000000..47d78d458c --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/custom.rs @@ -0,0 +1,53 @@ +use crate::{encoding_size, Encode, Section, SectionId}; + +/// A custom section holding arbitrary data. +#[derive(Clone, Debug)] +pub struct CustomSection<'a> { + /// The name of this custom section. + pub name: &'a str, + /// This custom section's data. + pub data: &'a [u8], +} + +impl Encode for CustomSection<'_> { + fn encode(&self, sink: &mut Vec<u8>) { + let encoded_name_len = encoding_size(u32::try_from(self.name.len()).unwrap()); + (encoded_name_len + self.name.len() + self.data.len()).encode(sink); + self.name.encode(sink); + sink.extend(self.data); + } +} + +impl Section for CustomSection<'_> { + fn id(&self) -> u8 { + SectionId::Custom.into() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_custom_section() { + let custom = CustomSection { + name: "test", + data: &[11, 22, 33, 44], + }; + + let mut encoded = vec![]; + custom.encode(&mut encoded); + + #[rustfmt::skip] + assert_eq!(encoded, vec![ + // LEB128 length of section. + 9, + // LEB128 length of name. + 4, + // Name. + b't', b'e', b's', b't', + // Data. + 11, 22, 33, 44, + ]); + } +} diff --git a/third_party/rust/wasm-encoder/src/core/data.rs b/third_party/rust/wasm-encoder/src/core/data.rs new file mode 100644 index 0000000000..6439b66e2e --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/data.rs @@ -0,0 +1,185 @@ +use crate::{encode_section, encoding_size, ConstExpr, Encode, Section, SectionId}; + +/// An encoder for the data section. +/// +/// Data sections are only supported for modules. +/// +/// # Example +/// +/// ``` +/// use wasm_encoder::{ +/// ConstExpr, DataSection, Instruction, MemorySection, MemoryType, +/// Module, +/// }; +/// +/// let mut memory = MemorySection::new(); +/// memory.memory(MemoryType { +/// minimum: 1, +/// maximum: None, +/// memory64: false, +/// shared: false, +/// }); +/// +/// let mut data = DataSection::new(); +/// let memory_index = 0; +/// let offset = ConstExpr::i32_const(42); +/// let segment_data = b"hello"; +/// data.active(memory_index, &offset, segment_data.iter().copied()); +/// +/// let mut module = Module::new(); +/// module +/// .section(&memory) +/// .section(&data); +/// +/// let wasm_bytes = module.finish(); +/// ``` +#[derive(Clone, Default, Debug)] +pub struct DataSection { + bytes: Vec<u8>, + num_added: u32, +} + +/// A segment in the data section. +#[derive(Clone, Debug)] +pub struct DataSegment<'a, D> { + /// This data segment's mode. + pub mode: DataSegmentMode<'a>, + /// This data segment's data. + pub data: D, +} + +/// A data segment's mode. +#[derive(Clone, Debug)] +pub enum DataSegmentMode<'a> { + /// An active data segment. + Active { + /// The memory this segment applies to. + memory_index: u32, + /// The offset where this segment's data is initialized at. + offset: &'a ConstExpr, + }, + /// A passive data segment. + /// + /// Passive data segments are part of the bulk memory proposal. + Passive, +} + +impl DataSection { + /// Create a new data section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of data segments in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Define a data segment. + pub fn segment<D>(&mut self, segment: DataSegment<D>) -> &mut Self + where + D: IntoIterator<Item = u8>, + D::IntoIter: ExactSizeIterator, + { + match segment.mode { + DataSegmentMode::Passive => { + self.bytes.push(0x01); + } + DataSegmentMode::Active { + memory_index: 0, + offset, + } => { + self.bytes.push(0x00); + offset.encode(&mut self.bytes); + } + DataSegmentMode::Active { + memory_index, + offset, + } => { + self.bytes.push(0x02); + memory_index.encode(&mut self.bytes); + offset.encode(&mut self.bytes); + } + } + + let data = segment.data.into_iter(); + data.len().encode(&mut self.bytes); + self.bytes.extend(data); + + self.num_added += 1; + self + } + + /// Define an active data segment. + pub fn active<D>(&mut self, memory_index: u32, offset: &ConstExpr, data: D) -> &mut Self + where + D: IntoIterator<Item = u8>, + D::IntoIter: ExactSizeIterator, + { + self.segment(DataSegment { + mode: DataSegmentMode::Active { + memory_index, + offset, + }, + data, + }) + } + + /// Define a passive data segment. + /// + /// Passive data segments are part of the bulk memory proposal. + pub fn passive<D>(&mut self, data: D) -> &mut Self + where + D: IntoIterator<Item = u8>, + D::IntoIter: ExactSizeIterator, + { + self.segment(DataSegment { + mode: DataSegmentMode::Passive, + data, + }) + } + + /// Copy an already-encoded data segment into this data section. + pub fn raw(&mut self, already_encoded_data_segment: &[u8]) -> &mut Self { + self.bytes.extend_from_slice(already_encoded_data_segment); + self.num_added += 1; + self + } +} + +impl Encode for DataSection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl Section for DataSection { + fn id(&self) -> u8 { + SectionId::Data.into() + } +} + +/// An encoder for the data count section. +#[derive(Clone, Copy, Debug)] +pub struct DataCountSection { + /// The number of segments in the data section. + pub count: u32, +} + +impl Encode for DataCountSection { + fn encode(&self, sink: &mut Vec<u8>) { + encoding_size(self.count).encode(sink); + self.count.encode(sink); + } +} + +impl Section for DataCountSection { + fn id(&self) -> u8 { + SectionId::DataCount.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/core/elements.rs b/third_party/rust/wasm-encoder/src/core/elements.rs new file mode 100644 index 0000000000..5eb641247b --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/elements.rs @@ -0,0 +1,227 @@ +use crate::{encode_section, ConstExpr, Encode, Section, SectionId, ValType}; + +/// An encoder for the element section. +/// +/// Element sections are only supported for modules. +/// +/// # Example +/// +/// ``` +/// use wasm_encoder::{ +/// Elements, ElementSection, Module, TableSection, TableType, +/// ValType, ConstExpr +/// }; +/// +/// let mut tables = TableSection::new(); +/// tables.table(TableType { +/// element_type: ValType::FuncRef, +/// minimum: 128, +/// maximum: None, +/// }); +/// +/// let mut elements = ElementSection::new(); +/// let table_index = 0; +/// let offset = ConstExpr::i32_const(42); +/// let element_type = ValType::FuncRef; +/// let functions = Elements::Functions(&[ +/// // Function indices... +/// ]); +/// elements.active(Some(table_index), &offset, element_type, functions); +/// +/// let mut module = Module::new(); +/// module +/// .section(&tables) +/// .section(&elements); +/// +/// let wasm_bytes = module.finish(); +/// ``` +#[derive(Clone, Default, Debug)] +pub struct ElementSection { + bytes: Vec<u8>, + num_added: u32, +} + +/// A sequence of elements in a segment in the element section. +#[derive(Clone, Copy, Debug)] +pub enum Elements<'a> { + /// A sequences of references to functions by their indices. + Functions(&'a [u32]), + /// A sequence of reference expressions. + Expressions(&'a [ConstExpr]), +} + +/// An element segment's mode. +#[derive(Clone, Debug)] +pub enum ElementMode<'a> { + /// A passive element segment. + /// + /// Passive segments are part of the bulk memory proposal. + Passive, + /// A declared element segment. + /// + /// Declared segments are part of the bulk memory proposal. + Declared, + /// An active element segment. + Active { + /// The table index. + /// + /// `Active` element specifying a `None` table forces the MVP encoding and refers to the + /// 0th table holding `funcref`s. Non-`None` tables use the encoding introduced with the + /// bulk memory proposal and can refer to tables with any valid reference type. + table: Option<u32>, + /// The offset within the table to place this segment. + offset: &'a ConstExpr, + }, +} + +/// An element segment in the element section. +#[derive(Clone, Debug)] +pub struct ElementSegment<'a> { + /// The element segment's mode. + pub mode: ElementMode<'a>, + /// The element segment's type. + pub element_type: ValType, + /// This segment's elements. + pub elements: Elements<'a>, +} + +impl ElementSection { + /// Create a new element section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of element segments in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Define an element segment. + pub fn segment<'a>(&mut self, segment: ElementSegment<'a>) -> &mut Self { + let expr_bit = match segment.elements { + Elements::Expressions(_) => 0b100u32, + Elements::Functions(_) => 0b000u32, + }; + match &segment.mode { + ElementMode::Active { + table: None, + offset, + } => { + (/* 0x00 | */expr_bit).encode(&mut self.bytes); + offset.encode(&mut self.bytes); + } + ElementMode::Passive => { + (0x01 | expr_bit).encode(&mut self.bytes); + if expr_bit == 0 { + self.bytes.push(0x00); // elemkind == funcref + } else { + segment.element_type.encode(&mut self.bytes); + } + } + ElementMode::Active { + table: Some(i), + offset, + } => { + (0x02 | expr_bit).encode(&mut self.bytes); + i.encode(&mut self.bytes); + offset.encode(&mut self.bytes); + if expr_bit == 0 { + self.bytes.push(0x00); // elemkind == funcref + } else { + segment.element_type.encode(&mut self.bytes); + } + } + ElementMode::Declared => { + (0x03 | expr_bit).encode(&mut self.bytes); + if expr_bit == 0 { + self.bytes.push(0x00); // elemkind == funcref + } else { + segment.element_type.encode(&mut self.bytes); + } + } + } + + match segment.elements { + Elements::Functions(fs) => { + fs.encode(&mut self.bytes); + } + Elements::Expressions(e) => { + e.len().encode(&mut self.bytes); + for expr in e { + expr.encode(&mut self.bytes); + } + } + } + + self.num_added += 1; + self + } + + /// Define an active element segment. + /// + /// `Active` element specifying a `None` table forces the MVP encoding and refers to the 0th + /// table holding `funcref`s. Non-`None` tables use the encoding introduced with the bulk + /// memory proposal and can refer to tables with any valid reference type. + pub fn active( + &mut self, + table_index: Option<u32>, + offset: &ConstExpr, + element_type: ValType, + elements: Elements<'_>, + ) -> &mut Self { + self.segment(ElementSegment { + mode: ElementMode::Active { + table: table_index, + offset, + }, + element_type, + elements, + }) + } + + /// Encode a passive element segment. + /// + /// Passive segments are part of the bulk memory proposal. + pub fn passive<'a>(&mut self, element_type: ValType, elements: Elements<'a>) -> &mut Self { + self.segment(ElementSegment { + mode: ElementMode::Passive, + element_type, + elements, + }) + } + + /// Encode a declared element segment. + /// + /// Declared segments are part of the bulk memory proposal. + pub fn declared<'a>(&mut self, element_type: ValType, elements: Elements<'a>) -> &mut Self { + self.segment(ElementSegment { + mode: ElementMode::Declared, + element_type, + elements, + }) + } + + /// Copy a raw, already-encoded element segment into this elements section. + pub fn raw(&mut self, raw_bytes: &[u8]) -> &mut Self { + self.bytes.extend_from_slice(raw_bytes); + self.num_added += 1; + self + } +} + +impl Encode for ElementSection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl Section for ElementSection { + fn id(&self) -> u8 { + SectionId::Element.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/core/exports.rs b/third_party/rust/wasm-encoder/src/core/exports.rs new file mode 100644 index 0000000000..0b8006655f --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/exports.rs @@ -0,0 +1,90 @@ +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)] +pub enum ExportKind { + /// The export is a function. + Func, + /// The export is a table. + Table, + /// The export is a memory. + Memory, + /// The export is a global. + Global, + /// The export is a tag. + Tag, +} + +impl Encode for ExportKind { + fn encode(&self, sink: &mut Vec<u8>) { + sink.push(match self { + Self::Func => CORE_FUNCTION_SORT, + Self::Table => CORE_TABLE_SORT, + Self::Memory => CORE_MEMORY_SORT, + Self::Global => CORE_GLOBAL_SORT, + Self::Tag => CORE_TAG_SORT, + }); + } +} + +/// An encoder for the export section of WebAssembly module. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Module, ExportSection, ExportKind}; +/// +/// let mut exports = ExportSection::new(); +/// exports.export("foo", ExportKind::Func, 0); +/// +/// let mut module = Module::new(); +/// module.section(&exports); +/// +/// let bytes = module.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct ExportSection { + bytes: Vec<u8>, + num_added: u32, +} + +impl ExportSection { + /// Create a new export section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of exports in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Define an export in the export section. + pub fn export(&mut self, name: &str, kind: ExportKind, index: u32) -> &mut Self { + name.encode(&mut self.bytes); + kind.encode(&mut self.bytes); + index.encode(&mut self.bytes); + self.num_added += 1; + self + } +} + +impl Encode for ExportSection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl Section for ExportSection { + fn id(&self) -> u8 { + SectionId::Export.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/core/functions.rs b/third_party/rust/wasm-encoder/src/core/functions.rs new file mode 100644 index 0000000000..e21d8c10a7 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/functions.rs @@ -0,0 +1,63 @@ +use crate::{encode_section, Encode, Section, SectionId}; + +/// An encoder for the function section of WebAssembly modules. +/// +/// # Example +/// +/// ``` +/// use wasm_encoder::{Module, FunctionSection, ValType}; +/// +/// let mut functions = FunctionSection::new(); +/// let type_index = 0; +/// functions.function(type_index); +/// +/// let mut module = Module::new(); +/// module.section(&functions); +/// +/// // Note: this will generate an invalid module because we didn't generate a +/// // code section containing the function body. See the documentation for +/// // `CodeSection` for details. +/// +/// let bytes = module.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct FunctionSection { + bytes: Vec<u8>, + num_added: u32, +} + +impl FunctionSection { + /// Construct a new module function section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of functions in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Define a function in a module's function section. + pub fn function(&mut self, type_index: u32) -> &mut Self { + type_index.encode(&mut self.bytes); + self.num_added += 1; + self + } +} + +impl Encode for FunctionSection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl Section for FunctionSection { + fn id(&self) -> u8 { + SectionId::Function.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/core/globals.rs b/third_party/rust/wasm-encoder/src/core/globals.rs new file mode 100644 index 0000000000..16f23c2891 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/globals.rs @@ -0,0 +1,90 @@ +use crate::{encode_section, ConstExpr, Encode, Section, SectionId, ValType}; + +/// An encoder for the global section. +/// +/// Global sections are only supported for modules. +/// +/// # Example +/// +/// ``` +/// use wasm_encoder::{ConstExpr, Module, GlobalSection, GlobalType, Instruction, ValType}; +/// +/// let mut globals = GlobalSection::new(); +/// globals.global( +/// GlobalType { +/// val_type: ValType::I32, +/// mutable: false, +/// }, +/// &ConstExpr::i32_const(42), +/// ); +/// +/// let mut module = Module::new(); +/// module.section(&globals); +/// +/// let wasm_bytes = module.finish(); +/// ``` +#[derive(Clone, Default, Debug)] +pub struct GlobalSection { + bytes: Vec<u8>, + num_added: u32, +} + +impl GlobalSection { + /// Create a new global section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of globals in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Define a global. + pub fn global(&mut self, global_type: GlobalType, init_expr: &ConstExpr) -> &mut Self { + global_type.encode(&mut self.bytes); + init_expr.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Add a raw byte slice into this code section as a global. + pub fn raw(&mut self, data: &[u8]) -> &mut Self { + self.bytes.extend(data); + self.num_added += 1; + self + } +} + +impl Encode for GlobalSection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl Section for GlobalSection { + fn id(&self) -> u8 { + SectionId::Global.into() + } +} + +/// A global's type. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub struct GlobalType { + /// This global's value type. + pub val_type: ValType, + /// Whether this global is mutable or not. + pub mutable: bool, +} + +impl Encode for GlobalType { + fn encode(&self, sink: &mut Vec<u8>) { + self.val_type.encode(sink); + sink.push(self.mutable as u8); + } +} diff --git a/third_party/rust/wasm-encoder/src/core/imports.rs b/third_party/rust/wasm-encoder/src/core/imports.rs new file mode 100644 index 0000000000..455170f227 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/imports.rs @@ -0,0 +1,142 @@ +use crate::{ + encode_section, Encode, GlobalType, MemoryType, Section, SectionId, TableType, TagType, + CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT, CORE_TABLE_SORT, CORE_TAG_SORT, +}; + +/// The type of an entity. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum EntityType { + /// A function type. + /// + /// The value is an index into the types section. + Function(u32), + /// A table type. + Table(TableType), + /// A memory type. + Memory(MemoryType), + /// A global type. + Global(GlobalType), + /// A tag type. + /// + /// This variant is used with the exception handling proposal. + Tag(TagType), +} + +impl Encode for EntityType { + fn encode(&self, sink: &mut Vec<u8>) { + match self { + Self::Function(i) => { + sink.push(CORE_FUNCTION_SORT); + i.encode(sink); + } + Self::Table(t) => { + sink.push(CORE_TABLE_SORT); + t.encode(sink); + } + Self::Memory(t) => { + sink.push(CORE_MEMORY_SORT); + t.encode(sink); + } + Self::Global(t) => { + sink.push(CORE_GLOBAL_SORT); + t.encode(sink); + } + Self::Tag(t) => { + sink.push(CORE_TAG_SORT); + t.encode(sink); + } + } + } +} + +impl From<TableType> for EntityType { + fn from(t: TableType) -> Self { + Self::Table(t) + } +} + +impl From<MemoryType> for EntityType { + fn from(t: MemoryType) -> Self { + Self::Memory(t) + } +} + +impl From<GlobalType> for EntityType { + fn from(t: GlobalType) -> Self { + Self::Global(t) + } +} + +impl From<TagType> for EntityType { + fn from(t: TagType) -> Self { + Self::Tag(t) + } +} + +/// An encoder for the import section of WebAssembly modules. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{MemoryType, Module, ImportSection}; +/// +/// let mut imports = ImportSection::new(); +/// imports.import( +/// "env", +/// "memory", +/// MemoryType { +/// minimum: 1, +/// maximum: None, +/// memory64: false, +/// shared: false, +/// } +/// ); +/// +/// let mut module = Module::new(); +/// module.section(&imports); +/// +/// let bytes = module.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct ImportSection { + bytes: Vec<u8>, + num_added: u32, +} + +impl ImportSection { + /// Create a new import section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of imports in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Define an import in the import section. + pub fn import(&mut self, module: &str, field: &str, ty: impl Into<EntityType>) -> &mut Self { + module.encode(&mut self.bytes); + field.encode(&mut self.bytes); + ty.into().encode(&mut self.bytes); + self.num_added += 1; + self + } +} + +impl Encode for ImportSection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl Section for ImportSection { + fn id(&self) -> u8 { + SectionId::Import.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/core/linking.rs b/third_party/rust/wasm-encoder/src/core/linking.rs new file mode 100644 index 0000000000..3309277be3 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/linking.rs @@ -0,0 +1,261 @@ +use crate::{encode_section, CustomSection, Encode, Section, SectionId}; + +const VERSION: u32 = 2; + +/// An encoder for the [linking custom +/// section](https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md#linking-metadata-section). +/// +/// This section is a non-standard convention that is supported by the LLVM +/// toolchain. It, along with associated "reloc.*" custom sections, allows you +/// to treat a Wasm module as a low-level object file that can be linked with +/// other Wasm object files to produce a final, complete Wasm module. +/// +/// The linking section must come before the reloc sections. +/// +/// # Example +/// +/// ``` +/// use wasm_encoder::{LinkingSection, Module, SymbolTable}; +/// +/// // Create a new linking section. +/// let mut linking = LinkingSection::new(); +/// +/// // Define a symbol table. +/// let mut sym_tab = SymbolTable::new(); +/// +/// // Define a function symbol in the symbol table. +/// let flags = SymbolTable::WASM_SYM_BINDING_LOCAL | SymbolTable::WASM_SYM_EXPORTED; +/// let func_index = 42; +/// let sym_name = "my_exported_func"; +/// sym_tab.function(flags, func_index, Some(sym_name)); +/// +/// // Add the symbol table to our linking section. +/// linking.symbol_table(&sym_tab); +/// +/// // Add the linking section to a new Wasm module and get the encoded bytes. +/// let mut module = Module::new(); +/// module.section(&linking); +/// let wasm_bytes = module.finish(); +/// ``` +#[derive(Clone, Debug)] +pub struct LinkingSection { + bytes: Vec<u8>, +} + +impl LinkingSection { + /// Construct a new encoder for the linking custom section. + pub fn new() -> Self { + Self::default() + } + + // TODO: `fn segment_info` for the `WASM_SEGMENT_INFO` linking subsection. + + // TODO: `fn init_funcs` for the `WASM_INIT_FUNCS` linking subsection. + + // TODO: `fn comdat_info` for the `WASM_COMDAT_INFO` linking subsection. + + /// Add a symbol table subsection. + pub fn symbol_table(&mut self, symbol_table: &SymbolTable) -> &mut Self { + symbol_table.encode(&mut self.bytes); + self + } +} + +impl Default for LinkingSection { + fn default() -> Self { + let mut bytes = Vec::new(); + VERSION.encode(&mut bytes); + Self { bytes } + } +} + +impl Encode for LinkingSection { + fn encode(&self, sink: &mut Vec<u8>) { + CustomSection { + name: "linking", + data: &self.bytes, + } + .encode(sink); + } +} + +impl Section for LinkingSection { + fn id(&self) -> u8 { + SectionId::Custom.into() + } +} + +#[allow(unused)] +const WASM_SEGMENT_INFO: u8 = 5; +#[allow(unused)] +const WASM_INIT_FUNCS: u8 = 6; +#[allow(unused)] +const WASM_COMDAT_INFO: u8 = 7; +const WASM_SYMBOL_TABLE: u8 = 8; + +/// A subsection of the [linking custom section][crate::LinkingSection] that +/// provides extra information about the symbols present in this Wasm object +/// file. +#[derive(Clone, Debug, Default)] +pub struct SymbolTable { + bytes: Vec<u8>, + num_added: u32, +} + +const SYMTAB_FUNCTION: u32 = 0; +const SYMTAB_DATA: u32 = 1; +const SYMTAB_GLOBAL: u32 = 2; +#[allow(unused)] +const SYMTAB_SECTION: u32 = 3; +#[allow(unused)] +const SYMTAB_TAG: u32 = 4; +const SYMTAB_TABLE: u32 = 5; + +impl SymbolTable { + /// Construct a new symbol table subsection encoder. + pub fn new() -> Self { + SymbolTable { + bytes: vec![], + num_added: 0, + } + } + + /// Define a function symbol in this symbol table. + /// + /// The `name` must be omitted if `index` references an imported table and + /// the `WASM_SYM_EXPLICIT_NAME` flag is not set. + pub fn function(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self { + SYMTAB_FUNCTION.encode(&mut self.bytes); + flags.encode(&mut self.bytes); + index.encode(&mut self.bytes); + if let Some(name) = name { + name.encode(&mut self.bytes); + } + self.num_added += 1; + self + } + + /// Define a global symbol in this symbol table. + /// + /// The `name` must be omitted if `index` references an imported table and + /// the `WASM_SYM_EXPLICIT_NAME` flag is not set. + pub fn global(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self { + SYMTAB_GLOBAL.encode(&mut self.bytes); + flags.encode(&mut self.bytes); + index.encode(&mut self.bytes); + if let Some(name) = name { + name.encode(&mut self.bytes); + } + self.num_added += 1; + self + } + + // TODO: tags + + /// Define a table symbol in this symbol table. + /// + /// The `name` must be omitted if `index` references an imported table and + /// the `WASM_SYM_EXPLICIT_NAME` flag is not set. + pub fn table(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self { + SYMTAB_TABLE.encode(&mut self.bytes); + flags.encode(&mut self.bytes); + index.encode(&mut self.bytes); + if let Some(name) = name { + name.encode(&mut self.bytes); + } + self.num_added += 1; + self + } + + /// Add a data symbol to this symbol table. + pub fn data( + &mut self, + flags: u32, + name: &str, + definition: Option<DataSymbolDefinition>, + ) -> &mut Self { + SYMTAB_DATA.encode(&mut self.bytes); + flags.encode(&mut self.bytes); + name.encode(&mut self.bytes); + if let Some(def) = definition { + def.index.encode(&mut self.bytes); + def.offset.encode(&mut self.bytes); + def.size.encode(&mut self.bytes); + } + self.num_added += 1; + self + } + + // TODO: sections + + /// This is a weak symbol. + /// + /// This flag is mutually exclusive with `WASM_SYM_BINDING_LOCAL`. + /// + /// When linking multiple modules defining the same symbol, all weak + /// definitions are discarded if any strong definitions exist; then if + /// multiple weak definitions exist all but one (unspecified) are discarded; + /// and finally it is an error if more than one definition remains. + pub const WASM_SYM_BINDING_WEAK: u32 = 0x1; + + /// This is a local symbol. + /// + /// This flag is mutually exclusive with `WASM_SYM_BINDING_WEAK`. + /// + /// Local symbols are not to be exported, or linked to other + /// modules/sections. The names of all non-local symbols must be unique, but + /// the names of local symbols are not considered for uniqueness. A local + /// function or global symbol cannot reference an import. + pub const WASM_SYM_BINDING_LOCAL: u32 = 0x02; + + /// This is a hidden symbol. + /// + /// Hidden symbols are not to be exported when performing the final link, + /// but may be linked to other modules. + pub const WASM_SYM_VISIBILITY_HIDDEN: u32 = 0x04; + + /// This symbol is not defined. + /// + /// For non-data symbols, this must match whether the symbol is an import or + /// is defined; for data symbols, determines whether a segment is specified. + pub const WASM_SYM_UNDEFINED: u32 = 0x10; + + /// This symbol is intended to be exported from the wasm module to the host + /// environment. + /// + /// This differs from the visibility flags in that it effects the static + /// linker. + pub const WASM_SYM_EXPORTED: u32 = 0x20; + + /// This symbol uses an explicit symbol name, rather than reusing the name + /// from a wasm import. + /// + /// This allows it to remap imports from foreign WebAssembly modules into + /// local symbols with different names. + pub const WASM_SYM_EXPLICIT_NAME: u32 = 0x40; + + /// This symbol is intended to be included in the linker output, regardless + /// of whether it is used by the program. + pub const WASM_SYM_NO_STRIP: u32 = 0x80; +} + +impl Encode for SymbolTable { + fn encode(&self, sink: &mut Vec<u8>) { + sink.push(WASM_SYMBOL_TABLE); + encode_section(sink, self.num_added, &self.bytes); + } +} + +/// The definition of a data symbol within a symbol table. +#[derive(Clone, Debug)] +pub struct DataSymbolDefinition { + /// The index of the data segment that this symbol is in. + pub index: u32, + /// The offset of this symbol within its segment. + pub offset: u32, + /// The byte size (which can be zero) of this data symbol. + /// + /// Note that `offset + size` must be less than or equal to the segment's + /// size. + pub size: u32, +} diff --git a/third_party/rust/wasm-encoder/src/core/memories.rs b/third_party/rust/wasm-encoder/src/core/memories.rs new file mode 100644 index 0000000000..c651768bdc --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/memories.rs @@ -0,0 +1,99 @@ +use crate::{encode_section, Encode, Section, SectionId}; + +/// An encoder for the memory section. +/// +/// Memory sections are only supported for modules. +/// +/// # Example +/// +/// ``` +/// use wasm_encoder::{Module, MemorySection, MemoryType}; +/// +/// let mut memories = MemorySection::new(); +/// memories.memory(MemoryType { +/// minimum: 1, +/// maximum: None, +/// memory64: false, +/// shared: false, +/// }); +/// +/// let mut module = Module::new(); +/// module.section(&memories); +/// +/// let wasm_bytes = module.finish(); +/// ``` +#[derive(Clone, Default, Debug)] +pub struct MemorySection { + bytes: Vec<u8>, + num_added: u32, +} + +impl MemorySection { + /// Create a new memory section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of memories in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Define a memory. + pub fn memory(&mut self, memory_type: MemoryType) -> &mut Self { + memory_type.encode(&mut self.bytes); + self.num_added += 1; + self + } +} + +impl Encode for MemorySection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl Section for MemorySection { + fn id(&self) -> u8 { + SectionId::Memory.into() + } +} + +/// A memory's type. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct MemoryType { + /// Minimum size, in pages, of this memory + pub minimum: u64, + /// Maximum size, in pages, of this memory + pub maximum: Option<u64>, + /// Whether or not this is a 64-bit memory. + pub memory64: bool, + /// Whether or not this memory is shared. + pub shared: bool, +} + +impl Encode for MemoryType { + fn encode(&self, sink: &mut Vec<u8>) { + let mut flags = 0; + if self.maximum.is_some() { + flags |= 0b001; + } + if self.shared { + flags |= 0b010; + } + if self.memory64 { + flags |= 0b100; + } + + sink.push(flags); + self.minimum.encode(sink); + if let Some(max) = self.maximum { + max.encode(sink); + } + } +} diff --git a/third_party/rust/wasm-encoder/src/core/names.rs b/third_party/rust/wasm-encoder/src/core/names.rs new file mode 100644 index 0000000000..880925918e --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/names.rs @@ -0,0 +1,254 @@ +use crate::{encoding_size, CustomSection, Encode, Section, SectionId}; + +/// An encoder for the custom `name` section. +/// +/// # Example +/// +/// ``` +/// use wasm_encoder::{Module, NameSection, NameMap}; +/// +/// let mut names = NameSection::new(); +/// names.module("the module name"); +/// +/// let mut function_names = NameMap::new(); +/// function_names.append(0, "name of function 0"); +/// function_names.append(1, "a better function"); +/// function_names.append(3, "the best function"); +/// names.functions(&function_names); +/// +/// let mut module = Module::new(); +/// module.section(&names); +/// +/// let wasm_bytes = module.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct NameSection { + bytes: Vec<u8>, +} + +enum Subsection { + // Currently specified in the wasm spec's appendix + Module = 0, + Function = 1, + Local = 2, + + // specified as part of the extended name section proposal + // + // https://github.com/WebAssembly/extended-name-section/blob/main/proposals/extended-name-section/Overview.md + Label = 3, + Type = 4, + Table = 5, + Memory = 6, + Global = 7, + Element = 8, + Data = 9, +} + +impl NameSection { + /// Creates a new blank `name` custom section. + pub fn new() -> Self { + Self::default() + } + + /// Appends a module name subsection to this section. + /// + /// This will indicate that the name of the entire module should be the + /// `name` specified. Note that this should be encoded first before other + /// subsections. + pub fn module(&mut self, name: &str) { + let len = encoding_size(u32::try_from(name.len()).unwrap()); + self.subsection_header(Subsection::Module, len + name.len()); + name.encode(&mut self.bytes); + } + + /// Appends a subsection for the names of all functions in this wasm module. + /// + /// Function names are declared in the `names` map provided where the index + /// in the map corresponds to the wasm index of the function. This section + /// should come after the module name subsection (if present) and before the + /// locals subsection (if present). + pub fn functions(&mut self, names: &NameMap) { + self.subsection_header(Subsection::Function, names.size()); + names.encode(&mut self.bytes); + } + + /// Appends a subsection for the names of locals within functions in the + /// wasm module. + /// + /// This section should come after the function name subsection (if present) + /// and before the labels subsection (if present). + pub fn locals(&mut self, names: &IndirectNameMap) { + self.subsection_header(Subsection::Local, names.size()); + names.encode(&mut self.bytes); + } + + /// Appends a subsection for the names of labels within functions in the + /// wasm module. + /// + /// This section should come after the local name subsection (if present) + /// and before the type subsection (if present). + pub fn labels(&mut self, names: &IndirectNameMap) { + self.subsection_header(Subsection::Label, names.size()); + names.encode(&mut self.bytes); + } + + /// Appends a subsection for the names of all types in this wasm module. + /// + /// This section should come after the label name subsection (if present) + /// and before the table subsection (if present). + pub fn types(&mut self, names: &NameMap) { + self.subsection_header(Subsection::Type, names.size()); + names.encode(&mut self.bytes); + } + + /// Appends a subsection for the names of all tables in this wasm module. + /// + /// This section should come after the type name subsection (if present) + /// and before the memory subsection (if present). + pub fn tables(&mut self, names: &NameMap) { + self.subsection_header(Subsection::Table, names.size()); + names.encode(&mut self.bytes); + } + + /// Appends a subsection for the names of all memories in this wasm module. + /// + /// This section should come after the table name subsection (if present) + /// and before the global subsection (if present). + pub fn memories(&mut self, names: &NameMap) { + self.subsection_header(Subsection::Memory, names.size()); + names.encode(&mut self.bytes); + } + + /// Appends a subsection for the names of all globals in this wasm module. + /// + /// This section should come after the memory name subsection (if present) + /// and before the element subsection (if present). + pub fn globals(&mut self, names: &NameMap) { + self.subsection_header(Subsection::Global, names.size()); + names.encode(&mut self.bytes); + } + + /// Appends a subsection for the names of all elements in this wasm module. + /// + /// This section should come after the global name subsection (if present) + /// and before the data subsection (if present). + pub fn elements(&mut self, names: &NameMap) { + self.subsection_header(Subsection::Element, names.size()); + names.encode(&mut self.bytes); + } + + /// Appends a subsection for the names of all data in this wasm module. + /// + /// This section should come after the element name subsection (if present). + pub fn data(&mut self, names: &NameMap) { + self.subsection_header(Subsection::Data, names.size()); + names.encode(&mut self.bytes); + } + + fn subsection_header(&mut self, id: Subsection, len: usize) { + self.bytes.push(id as u8); + len.encode(&mut self.bytes); + } +} + +impl Encode for NameSection { + fn encode(&self, sink: &mut Vec<u8>) { + CustomSection { + name: "name", + data: &self.bytes, + } + .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; + } + + fn size(&self) -> usize { + encoding_size(self.count) + self.bytes.len() + } +} + +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/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..57a7628a5d --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/tables.rs @@ -0,0 +1,92 @@ +use crate::{encode_section, Encode, Section, SectionId, ValType}; + +/// An encoder for the table section. +/// +/// Table sections are only supported for modules. +/// +/// # Example +/// +/// ``` +/// use wasm_encoder::{Module, TableSection, TableType, ValType}; +/// +/// let mut tables = TableSection::new(); +/// tables.table(TableType { +/// element_type: ValType::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 + } +} + +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: ValType, + /// Minimum size, in elements, of this table + pub minimum: u32, + /// Maximum size, in elements, of this table + pub maximum: Option<u32>, +} + +impl Encode for TableType { + fn encode(&self, sink: &mut Vec<u8>) { + let mut flags = 0; + if self.maximum.is_some() { + flags |= 0b001; + } + + self.element_type.encode(sink); + sink.push(flags); + self.minimum.encode(sink); + + if let Some(max) = self.maximum { + max.encode(sink); + } + } +} diff --git a/third_party/rust/wasm-encoder/src/core/tags.rs b/third_party/rust/wasm-encoder/src/core/tags.rs new file mode 100644 index 0000000000..413055f2af --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/tags.rs @@ -0,0 +1,85 @@ +use crate::{encode_section, Encode, Section, SectionId}; + +/// An encoder for the tag section. +/// +/// # Example +/// +/// ``` +/// use wasm_encoder::{Module, TagSection, TagType, TagKind}; +/// +/// let mut tags = TagSection::new(); +/// tags.tag(TagType { +/// kind: TagKind::Exception, +/// func_type_idx: 0, +/// }); +/// +/// let mut module = Module::new(); +/// module.section(&tags); +/// +/// let wasm_bytes = module.finish(); +/// ``` +#[derive(Clone, Default, Debug)] +pub struct TagSection { + bytes: Vec<u8>, + num_added: u32, +} + +impl TagSection { + /// Create a new tag section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of tags in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Define a tag. + pub fn tag(&mut self, tag_type: TagType) -> &mut Self { + tag_type.encode(&mut self.bytes); + self.num_added += 1; + self + } +} + +impl Encode for TagSection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl Section for TagSection { + fn id(&self) -> u8 { + SectionId::Tag.into() + } +} + +/// Represents a tag kind. +#[repr(u8)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum TagKind { + /// The tag is an exception type. + Exception = 0x0, +} + +/// A tag's type. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct TagType { + /// The kind of tag + pub kind: TagKind, + /// The function type this tag uses + pub func_type_idx: u32, +} + +impl Encode for TagType { + fn encode(&self, sink: &mut Vec<u8>) { + sink.push(self.kind as u8); + self.func_type_idx.encode(sink); + } +} diff --git a/third_party/rust/wasm-encoder/src/core/types.rs b/third_party/rust/wasm-encoder/src/core/types.rs new file mode 100644 index 0000000000..d99e22ea94 --- /dev/null +++ b/third_party/rust/wasm-encoder/src/core/types.rs @@ -0,0 +1,112 @@ +use crate::{encode_section, Encode, Section, SectionId}; + +/// The type of a core WebAssembly value. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[repr(u8)] +pub enum ValType { + /// The `i32` type. + I32 = 0x7F, + /// The `i64` type. + I64 = 0x7E, + /// The `f32` type. + F32 = 0x7D, + /// The `f64` type. + F64 = 0x7C, + /// The `v128` type. + /// + /// Part of the SIMD proposal. + V128 = 0x7B, + /// The `funcref` type. + /// + /// Part of the reference types proposal when used anywhere other than a + /// table's element type. + FuncRef = 0x70, + /// The `externref` type. + /// + /// Part of the reference types proposal. + ExternRef = 0x6F, +} + +impl From<ValType> for u8 { + #[inline] + fn from(t: ValType) -> u8 { + t as u8 + } +} + +impl Encode for ValType { + fn encode(&self, sink: &mut Vec<u8>) { + sink.push(*self as u8); + } +} + +/// An encoder for the type section of WebAssembly modules. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Module, TypeSection, ValType}; +/// +/// let mut types = TypeSection::new(); +/// +/// types.function([ValType::I32, ValType::I32], [ValType::I64]); +/// +/// let mut module = Module::new(); +/// module.section(&types); +/// +/// let bytes = module.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct TypeSection { + bytes: Vec<u8>, + num_added: u32, +} + +impl TypeSection { + /// Create a new module type section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of types in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Define a function type in this type section. + pub fn function<P, R>(&mut self, params: P, results: R) -> &mut Self + where + P: IntoIterator<Item = ValType>, + P::IntoIter: ExactSizeIterator, + R: IntoIterator<Item = ValType>, + R::IntoIter: ExactSizeIterator, + { + let params = params.into_iter(); + let results = results.into_iter(); + + self.bytes.push(0x60); + params.len().encode(&mut self.bytes); + self.bytes.extend(params.map(u8::from)); + results.len().encode(&mut self.bytes); + self.bytes.extend(results.map(u8::from)); + self.num_added += 1; + self + } +} + +impl Encode for TypeSection { + fn encode(&self, sink: &mut Vec<u8>) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl Section for TypeSection { + fn id(&self) -> u8 { + SectionId::Type.into() + } +} diff --git a/third_party/rust/wasm-encoder/src/lib.rs b/third_party/rust/wasm-encoder/src/lib.rs new file mode 100644 index 0000000000..c84e20f81d --- /dev/null +++ b/third_party/rust/wasm-encoder/src/lib.rs @@ -0,0 +1,188 @@ +//! A WebAssembly encoder. +//! +//! The main builder is the [`Module`]. You can build a section with a +//! section-specific builder, like [`TypeSection`] or [`ImportSection`], and +//! then add it to the module with [`Module::section`]. When you are finished +//! building the module, call either [`Module::as_slice`] or [`Module::finish`] +//! to get the encoded bytes. The former gives a shared reference to the +//! underlying bytes as a slice, while the latter gives you ownership of them as +//! a vector. +//! +//! # Example +//! +//! If we wanted to build this module: +//! +//! ```wasm +//! (module +//! (type (func (param i32 i32) (result i32))) +//! (func (type 0) +//! local.get 0 +//! local.get 1 +//! i32.add) +//! (export "f" (func 0))) +//! ``` +//! +//! then we would do this: +//! +//! ``` +//! use wasm_encoder::{ +//! CodeSection, ExportKind, ExportSection, Function, FunctionSection, Instruction, +//! Module, TypeSection, ValType, +//! }; +//! +//! let mut module = Module::new(); +//! +//! // Encode the type section. +//! let mut types = TypeSection::new(); +//! let params = vec![ValType::I32, ValType::I32]; +//! let results = vec![ValType::I32]; +//! types.function(params, results); +//! module.section(&types); +//! +//! // Encode the function section. +//! let mut functions = FunctionSection::new(); +//! let type_index = 0; +//! functions.function(type_index); +//! module.section(&functions); +//! +//! // Encode the export section. +//! let mut exports = ExportSection::new(); +//! exports.export("f", ExportKind::Func, 0); +//! module.section(&exports); +//! +//! // Encode the code section. +//! let mut codes = CodeSection::new(); +//! let locals = vec![]; +//! let mut f = Function::new(locals); +//! f.instruction(&Instruction::LocalGet(0)); +//! f.instruction(&Instruction::LocalGet(1)); +//! f.instruction(&Instruction::I32Add); +//! f.instruction(&Instruction::End); +//! codes.function(&f); +//! module.section(&codes); +//! +//! // Extract the encoded Wasm bytes for this module. +//! let wasm_bytes = module.finish(); +//! +//! // We generated a valid Wasm module! +//! assert!(wasmparser::validate(&wasm_bytes).is_ok()); +//! ``` + +#![deny(missing_docs, missing_debug_implementations)] + +mod component; +mod core; +mod raw; + +pub use self::component::*; +pub use self::core::*; +pub use self::raw::*; + +/// Implemented by types that can be encoded into a byte sink. +pub trait Encode { + /// Encode the type into the given byte sink. + fn encode(&self, sink: &mut Vec<u8>); +} + +impl<T: Encode + ?Sized> Encode for &'_ T { + fn encode(&self, sink: &mut Vec<u8>) { + T::encode(self, sink) + } +} + +impl<T: Encode> Encode for [T] { + fn encode(&self, sink: &mut Vec<u8>) { + self.len().encode(sink); + for item in self { + item.encode(sink); + } + } +} + +impl Encode for [u8] { + fn encode(&self, sink: &mut Vec<u8>) { + self.len().encode(sink); + sink.extend(self); + } +} + +impl Encode for str { + fn encode(&self, sink: &mut Vec<u8>) { + self.len().encode(sink); + sink.extend_from_slice(self.as_bytes()); + } +} + +impl Encode for usize { + fn encode(&self, sink: &mut Vec<u8>) { + assert!(*self <= u32::max_value() as usize); + (*self as u32).encode(sink) + } +} + +impl Encode for u32 { + fn encode(&self, sink: &mut Vec<u8>) { + leb128::write::unsigned(sink, (*self).into()).unwrap(); + } +} + +impl Encode for i32 { + fn encode(&self, sink: &mut Vec<u8>) { + leb128::write::signed(sink, (*self).into()).unwrap(); + } +} + +impl Encode for u64 { + fn encode(&self, sink: &mut Vec<u8>) { + leb128::write::unsigned(sink, *self).unwrap(); + } +} + +impl Encode for i64 { + fn encode(&self, sink: &mut Vec<u8>) { + leb128::write::signed(sink, *self).unwrap(); + } +} + +impl<T> Encode for Option<T> +where + T: Encode, +{ + fn encode(&self, sink: &mut Vec<u8>) { + match self { + Some(v) => { + sink.push(0x01); + v.encode(sink); + } + None => sink.push(0x00), + } + } +} + +fn encoding_size(n: u32) -> usize { + let mut buf = [0u8; 5]; + leb128::write::unsigned(&mut &mut buf[..], n.into()).unwrap() +} + +fn encode_section(sink: &mut Vec<u8>, count: u32, bytes: &[u8]) { + (encoding_size(count) + bytes.len()).encode(sink); + count.encode(sink); + sink.extend(bytes); +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn it_encodes_an_empty_module() { + let bytes = Module::new().finish(); + assert_eq!(bytes, [0x00, b'a', b's', b'm', 0x01, 0x00, 0x00, 0x00]); + } + + #[test] + fn it_encodes_an_empty_component() { + let bytes = Component::new().finish(); + assert_eq!(bytes, [0x00, b'a', b's', b'm', 0x0a, 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 + } +} |